mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-05-15 22:42:51 +00:00
Switch to a more flexible intro library
This commit is contained in:
parent
1528aa5eaf
commit
302c4802b7
15 changed files with 263 additions and 385 deletions
|
@ -2,12 +2,17 @@ package me.impy.aegis;
|
|||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.github.paolorotolo.appintro.ISlidePolicy;
|
||||
import com.github.paolorotolo.appintro.ISlideSelectionListener;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
@ -17,80 +22,29 @@ import javax.crypto.Cipher;
|
|||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import agency.tango.materialintroscreen.SlideFragment;
|
||||
import me.impy.aegis.crypto.CryptoUtils;
|
||||
import me.impy.aegis.crypto.slots.PasswordSlot;
|
||||
import me.impy.aegis.crypto.slots.Slot;
|
||||
|
||||
public class CustomAuthenticatedSlide extends SlideFragment {
|
||||
public class CustomAuthenticatedSlide extends Fragment implements ISlidePolicy, ISlideSelectionListener {
|
||||
private int cryptType;
|
||||
private EditText textPassword;
|
||||
private EditText textPasswordConfirm;
|
||||
private int bgColor;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_authenticated_slide, container, false);
|
||||
final View view = inflater.inflate(R.layout.fragment_authenticated_slide, container, false);
|
||||
textPassword = (EditText) view.findViewById(R.id.text_password);
|
||||
textPasswordConfirm = (EditText) view.findViewById(R.id.text_password_confirm);
|
||||
view.findViewById(R.id.main).setBackgroundColor(bgColor);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
|
||||
if (!isVisibleToUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = getActivity().getIntent();
|
||||
cryptType = intent.getIntExtra("cryptType", 1337);
|
||||
|
||||
switch(cryptType) {
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
|
||||
break;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
|
||||
break;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int backgroundColor() {
|
||||
return R.color.colorHeaderSuccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
/*@Override
|
||||
public int buttonsColor() {
|
||||
return R.color.colorAccent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMoveFurther() {
|
||||
switch(cryptType) {
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
|
||||
return true;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
|
||||
char[] password = getEditTextChars(textPassword);
|
||||
char[] passwordConfirm = getEditTextChars(textPasswordConfirm);
|
||||
boolean equal = password.length != 0 && Arrays.equals(password, passwordConfirm);
|
||||
CryptoUtils.zero(password);
|
||||
CryptoUtils.zero(passwordConfirm);
|
||||
return equal;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
|
||||
return false;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cantMoveFurtherErrorMessage() {
|
||||
return "Passwords should be equal and non-empty";
|
||||
}
|
||||
}*/
|
||||
|
||||
public int getCryptType() {
|
||||
return cryptType;
|
||||
|
@ -121,4 +75,57 @@ public class CustomAuthenticatedSlide extends SlideFragment {
|
|||
editable.getChars(0, editable.length(), chars, 0);
|
||||
return chars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlideSelected() {
|
||||
Intent intent = getActivity().getIntent();
|
||||
cryptType = intent.getIntExtra("cryptType", 1337);
|
||||
|
||||
switch(cryptType) {
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
|
||||
break;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
|
||||
break;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public void setBgColor(int color) {
|
||||
bgColor = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlideDeselected() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPolicyRespected() {
|
||||
switch(cryptType) {
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
|
||||
return true;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
|
||||
char[] password = getEditTextChars(textPassword);
|
||||
char[] passwordConfirm = getEditTextChars(textPasswordConfirm);
|
||||
boolean equal = password.length != 0 && Arrays.equals(password, passwordConfirm);
|
||||
CryptoUtils.zero(password);
|
||||
CryptoUtils.zero(passwordConfirm);
|
||||
return equal;
|
||||
case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
|
||||
return false;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserIllegallyRequestedNextPage() {
|
||||
View view = getView();
|
||||
if (view != null) {
|
||||
Snackbar snackbar = Snackbar.make(getView(), "Passwords should be equal and non-empty", Snackbar.LENGTH_LONG);
|
||||
snackbar.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,24 +7,28 @@ import android.content.pm.PackageManager;
|
|||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import agency.tango.materialintroscreen.SlideFragment;
|
||||
import com.github.paolorotolo.appintro.ISlidePolicy;
|
||||
|
||||
public class CustomAuthenticationSlide extends SlideFragment {
|
||||
public static final int CRYPT_TYPE_NONE = 0;
|
||||
public static final int CRYPT_TYPE_PASS = 1;
|
||||
public static final int CRYPT_TYPE_FINGER = 2;
|
||||
public class CustomAuthenticationSlide extends Fragment implements ISlidePolicy {
|
||||
public static final int CRYPT_TYPE_INVALID = 0;
|
||||
public static final int CRYPT_TYPE_NONE = 1;
|
||||
public static final int CRYPT_TYPE_PASS = 2;
|
||||
public static final int CRYPT_TYPE_FINGER = 3;
|
||||
|
||||
private RadioGroup buttonGroup;
|
||||
private int bgColor;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
|
@ -34,7 +38,7 @@ public class CustomAuthenticationSlide extends SlideFragment {
|
|||
buttonGroup = (RadioGroup) view.findViewById(R.id.rg_authenticationMethod);
|
||||
buttonGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
|
||||
public void onCheckedChanged(RadioGroup group, int checkedId) {
|
||||
if (checkedId == -1) {
|
||||
return;
|
||||
}
|
||||
|
@ -72,26 +76,27 @@ public class CustomAuthenticationSlide extends SlideFragment {
|
|||
}
|
||||
}
|
||||
|
||||
view.findViewById(R.id.main).setBackgroundColor(bgColor);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int backgroundColor() {
|
||||
return R.color.colorHeaderSuccess;
|
||||
public void setBgColor(int color) {
|
||||
bgColor = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int buttonsColor() {
|
||||
return R.color.colorAccent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMoveFurther() {
|
||||
public boolean isPolicyRespected() {
|
||||
return buttonGroup.getCheckedRadioButtonId() != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String cantMoveFurtherErrorMessage() {
|
||||
return "Please select an authentication method";
|
||||
public void onUserIllegallyRequestedNextPage() {
|
||||
Snackbar snackbar = Snackbar.make(getView(), "Please select an authentication method", Snackbar.LENGTH_LONG);
|
||||
snackbar.show();
|
||||
}
|
||||
|
||||
/*@Override
|
||||
public int buttonsColor() {
|
||||
return R.color.colorAccent;
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
package me.impy.aegis;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.BottomSheetDialogFragment;
|
||||
|
@ -11,7 +7,6 @@ import android.view.LayoutInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class EditProfileBottomSheetdialog extends BottomSheetDialogFragment {
|
||||
LinearLayout copyLayout;
|
||||
|
|
|
@ -5,17 +5,14 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.support.v4.app.Fragment;
|
||||
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import com.github.paolorotolo.appintro.AppIntro;
|
||||
import com.github.paolorotolo.appintro.AppIntroFragment;
|
||||
import com.github.paolorotolo.appintro.model.SliderPage;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
import agency.tango.materialintroscreen.MaterialIntroActivity;
|
||||
import agency.tango.materialintroscreen.MessageButtonBehaviour;
|
||||
import agency.tango.materialintroscreen.SlideFragmentBuilder;
|
||||
import me.impy.aegis.crypto.CryptResult;
|
||||
import me.impy.aegis.crypto.MasterKey;
|
||||
import me.impy.aegis.crypto.slots.PasswordSlot;
|
||||
|
@ -23,63 +20,77 @@ import me.impy.aegis.crypto.slots.SlotCollection;
|
|||
import me.impy.aegis.db.Database;
|
||||
import me.impy.aegis.db.DatabaseFile;
|
||||
|
||||
public class IntroActivity extends MaterialIntroActivity {
|
||||
public class IntroActivity extends AppIntro {
|
||||
public static final int RESULT_OK = 0;
|
||||
public static final int RESULT_EXCEPTION = 1;
|
||||
|
||||
private CustomAuthenticatedSlide authenticatedSlide;
|
||||
private CustomAuthenticationSlide authenticationSlide;
|
||||
private Fragment endSlide;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
hideBackButton();
|
||||
showSkipButton(false);
|
||||
//showPagerIndicator(false);
|
||||
setGoBackLock(true);
|
||||
// TODO: remove this once github.com/apl-devs/AppIntro/issues/347 is fixed
|
||||
setSwipeLock(true);
|
||||
|
||||
addSlide(new SlideFragmentBuilder()
|
||||
.backgroundColor(R.color.colorPrimary)
|
||||
.buttonsColor(R.color.colorAccent)
|
||||
.image(R.drawable.intro_shield)
|
||||
.title("Welcome")
|
||||
.description("Aegis is a brand new open source(!) authenticator app which generates tokens for your accounts.")
|
||||
.build());
|
||||
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));
|
||||
|
||||
addSlide(new SlideFragmentBuilder()
|
||||
.backgroundColor(R.color.colorAccent)
|
||||
.buttonsColor(R.color.colorPrimary)
|
||||
.neededPermissions(new String[]{Manifest.permission.CAMERA})
|
||||
.image(R.drawable.intro_scanner)
|
||||
.title("Permissions")
|
||||
.description("Aegis needs permission to your camera in order to function properly. This is needed to scan QR codes.")
|
||||
.build(),
|
||||
new MessageButtonBehaviour(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
}
|
||||
}, "Permission granted"));
|
||||
|
||||
addSlide(new CustomAuthenticationSlide());
|
||||
SliderPage permSliderPage = new SliderPage();
|
||||
permSliderPage.setTitle("Permissions");
|
||||
permSliderPage.setDescription("Aegis needs permission to use your camera in order to scan QR codes.");
|
||||
permSliderPage.setImageDrawable(R.drawable.intro_scanner);
|
||||
permSliderPage.setBgColor(getResources().getColor(R.color.colorAccent));
|
||||
addSlide(AppIntroFragment.newInstance(permSliderPage));
|
||||
askForPermissions(new String[]{Manifest.permission.CAMERA}, 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);
|
||||
|
||||
addSlide(new SlideFragmentBuilder()
|
||||
.backgroundColor(R.color.colorPrimary)
|
||||
.buttonsColor(R.color.colorAccent)
|
||||
.image(R.drawable.intro_shield)
|
||||
.title("All done!")
|
||||
.description("Aegis has been set up and is ready to go.")
|
||||
.build());
|
||||
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);
|
||||
}
|
||||
|
||||
private void setException(Exception e) {
|
||||
Intent result = new Intent();
|
||||
result.putExtra("exception", e);
|
||||
setResult(RESULT_EXCEPTION, result);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
super.onFinish();
|
||||
public void onSlideChanged(Fragment oldFragment, Fragment newFragment) {
|
||||
// skip to the last slide if no encryption will be used
|
||||
if (oldFragment == authenticationSlide && newFragment != endSlide) {
|
||||
Intent intent = getIntent();
|
||||
int cryptType = intent.getIntExtra("cryptType", CustomAuthenticationSlide.CRYPT_TYPE_INVALID);
|
||||
if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
||||
// TODO: no magic indices
|
||||
getPager().setCurrentItem(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDonePressed(Fragment currentFragment) {
|
||||
super.onDonePressed(currentFragment);
|
||||
|
||||
// create the database and database file
|
||||
Database database = new Database();
|
||||
|
@ -142,5 +153,6 @@ public class IntroActivity extends MaterialIntroActivity {
|
|||
// TODO: show the intro if we can't find any database files
|
||||
SharedPreferences prefs = this.getSharedPreferences("me.impy.aegis", Context.MODE_PRIVATE);
|
||||
prefs.edit().putBoolean("passedIntro", true).apply();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -409,9 +409,4 @@ public class MainActivity extends AppCompatActivity {
|
|||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean causeIsKeyUserNotAuthenticated(Exception e) {
|
||||
// TODO: is there a way to catch "Key user not authenticated" specifically aside from checking the exception message?
|
||||
return e.getCause().getMessage().equals("Key user not authenticated");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package me.impy.aegis;
|
||||
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class SetPasswordActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_set_password);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue