mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-04-22 23:09:13 +00:00
* Move global state to a new class that overrides Application * Make sure all preferences are stored in the same place and follow the same naming convention
210 lines
7.9 KiB
Java
210 lines
7.9 KiB
Java
package me.impy.aegis;
|
|
|
|
import android.Manifest;
|
|
import android.content.Intent;
|
|
import android.os.Bundle;
|
|
import android.support.v4.app.Fragment;
|
|
|
|
import com.github.paolorotolo.appintro.AppIntro;
|
|
import com.github.paolorotolo.appintro.AppIntroFragment;
|
|
import com.github.paolorotolo.appintro.model.SliderPage;
|
|
|
|
import javax.crypto.Cipher;
|
|
import javax.crypto.SecretKey;
|
|
|
|
import me.impy.aegis.crypto.CryptResult;
|
|
import me.impy.aegis.crypto.MasterKey;
|
|
import me.impy.aegis.crypto.slots.FingerprintSlot;
|
|
import me.impy.aegis.crypto.slots.PasswordSlot;
|
|
import me.impy.aegis.crypto.slots.Slot;
|
|
import me.impy.aegis.crypto.slots.SlotCollection;
|
|
import me.impy.aegis.db.Database;
|
|
import me.impy.aegis.db.DatabaseFile;
|
|
import me.impy.aegis.db.DatabaseManager;
|
|
|
|
public class IntroActivity extends AppIntro implements DerivationTask.Callback {
|
|
public static final int RESULT_OK = 0;
|
|
public static final int RESULT_EXCEPTION = 1;
|
|
|
|
private CustomAuthenticatedSlide _authenticatedSlide;
|
|
private CustomAuthenticationSlide _authenticationSlide;
|
|
private Fragment _endSlide;
|
|
|
|
private Database _database;
|
|
private DatabaseFile _databaseFile;
|
|
private PasswordSlot _passwordSlot;
|
|
private Cipher _passwordCipher;
|
|
|
|
private AegisApplication _app;
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
_app = (AegisApplication) getApplication();
|
|
|
|
showSkipButton(false);
|
|
//showPagerIndicator(false);
|
|
setGoBackLock(true);
|
|
|
|
SliderPage homeSliderPage = new SliderPage();
|
|
homeSliderPage.setTitle("Welcome");
|
|
homeSliderPage.setDescription("Aegis is a secure, free and open source 2FA app");
|
|
homeSliderPage.setImageDrawable(R.drawable.intro_shield);
|
|
homeSliderPage.setBgColor(getResources().getColor(R.color.colorPrimary));
|
|
addSlide(AppIntroFragment.newInstance(homeSliderPage));
|
|
|
|
SliderPage permSliderPage = new SliderPage();
|
|
permSliderPage.setTitle("Permissions");
|
|
permSliderPage.setDescription("Aegis needs permission to use your camera in order to scan QR codes. " +
|
|
"It also needs access to external storage to able to export the database.");
|
|
permSliderPage.setImageDrawable(R.drawable.intro_scanner);
|
|
permSliderPage.setBgColor(getResources().getColor(R.color.colorAccent));
|
|
addSlide(AppIntroFragment.newInstance(permSliderPage));
|
|
askForPermissions(new String[]{
|
|
Manifest.permission.CAMERA,
|
|
Manifest.permission.READ_EXTERNAL_STORAGE,
|
|
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
}, 2);
|
|
|
|
_authenticationSlide = new CustomAuthenticationSlide();
|
|
_authenticationSlide.setBgColor(getResources().getColor(R.color.colorHeaderSuccess));
|
|
addSlide(_authenticationSlide);
|
|
_authenticatedSlide = new CustomAuthenticatedSlide();
|
|
_authenticatedSlide.setBgColor(getResources().getColor(R.color.colorPrimary));
|
|
addSlide(_authenticatedSlide);
|
|
|
|
SliderPage endSliderPage = new SliderPage();
|
|
endSliderPage.setTitle("All done!");
|
|
endSliderPage.setDescription("Aegis has been set up and is ready to go.");
|
|
endSliderPage.setImageDrawable(R.drawable.intro_shield);
|
|
endSliderPage.setBgColor(getResources().getColor(R.color.colorPrimary));
|
|
_endSlide = AppIntroFragment.newInstance(endSliderPage);
|
|
addSlide(_endSlide);
|
|
|
|
// create the database and database file
|
|
_database = new Database();
|
|
_databaseFile = new DatabaseFile();
|
|
}
|
|
|
|
private void setException(Exception e) {
|
|
Intent result = new Intent();
|
|
result.putExtra("exception", e);
|
|
setResult(RESULT_EXCEPTION, result);
|
|
finish();
|
|
}
|
|
|
|
@Override
|
|
public void onSlideChanged(Fragment oldFragment, Fragment newFragment) {
|
|
Intent intent = getIntent();
|
|
int cryptType = intent.getIntExtra("cryptType", CustomAuthenticationSlide.CRYPT_TYPE_INVALID);
|
|
|
|
if (newFragment == _endSlide && cryptType != CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
|
_passwordSlot = new PasswordSlot();
|
|
new DerivationTask(this, this).execute(new DerivationTask.Params() {{
|
|
Slot = _passwordSlot;
|
|
Password = _authenticatedSlide.getPassword();
|
|
}});
|
|
} else if (oldFragment == _authenticationSlide && newFragment != _endSlide) {
|
|
// skip to the last slide if no encryption will be used
|
|
if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
|
// TODO: no magic indices
|
|
getPager().setCurrentItem(5);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onDonePressed(Fragment currentFragment) {
|
|
super.onDonePressed(currentFragment);
|
|
|
|
int cryptType = _authenticatedSlide.getCryptType();
|
|
// wait for the key derivation background task
|
|
if (cryptType != CustomAuthenticationSlide.CRYPT_TYPE_NONE &&
|
|
(_passwordSlot == null || _passwordCipher == null)) {
|
|
return;
|
|
}
|
|
|
|
// generate the master key
|
|
MasterKey masterKey = null;
|
|
if (cryptType != CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
|
try {
|
|
masterKey = MasterKey.generate();
|
|
} catch (Exception e) {
|
|
setException(e);
|
|
return;
|
|
}
|
|
}
|
|
|
|
SlotCollection slots = _databaseFile.getSlots();
|
|
if (cryptType != CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
|
try {
|
|
// encrypt the master key with a key derived from the user's password
|
|
// and add it to the list of slots
|
|
if (_passwordSlot == null || _passwordCipher == null) {
|
|
throw new RuntimeException();
|
|
}
|
|
try {
|
|
slots.encrypt(_passwordSlot, masterKey, _passwordCipher);
|
|
slots.add(_passwordSlot);
|
|
} catch (Exception e) {
|
|
setException(e);
|
|
}
|
|
} catch (Exception e) {
|
|
setException(e);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_FINGER) {
|
|
try {
|
|
// encrypt the master key with the fingerprint key
|
|
// and add it to the list of slots
|
|
FingerprintSlot slot = new FingerprintSlot();
|
|
Cipher cipher = _authenticatedSlide.getFingerCipher();
|
|
slots.encrypt(slot, masterKey, cipher);
|
|
slots.add(slot);
|
|
} catch (Exception e) {
|
|
setException(e);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// finally, save the database
|
|
try {
|
|
byte[] bytes = _database.serialize();
|
|
if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
|
_databaseFile.setContent(bytes);
|
|
} else {
|
|
CryptResult result = masterKey.encrypt(bytes);
|
|
_databaseFile.setContent(result.Data);
|
|
_databaseFile.setCryptParameters(result.Parameters);
|
|
}
|
|
DatabaseManager.save(getApplicationContext(), _databaseFile);
|
|
} catch (Exception e) {
|
|
setException(e);
|
|
return;
|
|
}
|
|
|
|
// send the master key back to the main activity
|
|
Intent result = new Intent();
|
|
result.putExtra("key", masterKey);
|
|
setResult(RESULT_OK, result);
|
|
|
|
// skip the intro from now on
|
|
_app.getPreferences().edit().putBoolean("pref_intro", true).apply();
|
|
finish();
|
|
}
|
|
|
|
@Override
|
|
public void onTaskFinished(SecretKey key) {
|
|
if (key != null) {
|
|
try {
|
|
_passwordCipher = Slot.createCipher(key, Cipher.ENCRYPT_MODE);
|
|
} catch (Exception e) {
|
|
setException(e);
|
|
}
|
|
} else {
|
|
setException(new NullPointerException());
|
|
}
|
|
}
|
|
}
|