diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
index 468e16ac..8932a8ed 100644
Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ
diff --git a/app/build.gradle b/app/build.gradle
index f5a09e53..5b419e61 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -153,7 +153,7 @@ dependencies {
implementation 'com.android.support:cardview-v7:28.0.0'
implementation 'com.theartofdev.edmodo:android-image-cropper:2.7.0'
implementation 'com.scottyab:rootbeer-lib:0.0.7'
- implementation 'com.github.heasley:RxFingerprint:1.0.1'
+ implementation 'com.mtramin:rxfingerprint:2.2.1'
implementation project(':securitykeypad')
implementation project(':SpinnerDatePickerLib-release')
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4c5e19c3..821ac9d4 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,6 +11,9 @@
+
+
+
showProgressBar(true,getString(R.string.processing_request_text)))
+ .doFinally(()->showProgressBar(false,""))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Observer() {
+ @Override
+ public void onSubscribe(Disposable d) {
+
+ }
+
+ @Override
+ public void onNext(FingerprintEncryptionResult fingerprintEncryptionResult) {
+ if(fingerprintEncryptionResult.isSuccess()) {
+ showPopUpMessage("Now you can use your fingerprint to perform transactions",CustomAlertDialog.AlertType.SUCCESS,action->GmeApplication.getStorage().edit().putString(PrefKeys.APP_USER_SECRET_KEY, fingerprintEncryptionResult.getEncrypted()).apply());
+ }
+ else
+ showPopUpMessage(fingerprintEncryptionResult.getMessage(),CustomAlertDialog.AlertType.FAILED,null);
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ showPopUpMessage(e.getMessage(),CustomAlertDialog.AlertType.FAILED,null);
+ }
+
+ @Override
+ public void onComplete() {
+
+ }
+ });
+ }
+
+
private void promptLanguageSelectionDialog() {
LanguageSelectionListingDialog languageSelectionDialog = new LanguageSelectionListingDialog();
diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/gateway/TransactionPasswordPromptV2Gateway.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/gateway/TransactionPasswordPromptV2Gateway.java
index 1b81ef72..23a12e47 100644
--- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/gateway/TransactionPasswordPromptV2Gateway.java
+++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/gateway/TransactionPasswordPromptV2Gateway.java
@@ -1,5 +1,6 @@
package com.gmeremit.online.gmeremittance_native.transactionpasspromt.gateway;
+import com.gmeremit.online.gmeremittance_native.GmeApplication;
import com.gmeremit.online.gmeremittance_native.base.PrivilegedGateway;
import com.gmeremit.online.gmeremittance_native.transactionpasspromt.presenter.TransactionPasswordPromptV2InteractorInterface;
import com.gmeremit.online.gmeremittance_native.utils.https.HttpClientV2;
@@ -8,6 +9,9 @@ import com.google.gson.JsonObject;
import io.reactivex.Observable;
import okhttp3.ResponseBody;
+import static com.gmeremit.online.gmeremittance_native.base.PrefKeys.APP_FINGER_PRINT_ENABLED;
+import static com.gmeremit.online.gmeremittance_native.base.PrefKeys.APP_USER_SECRET_KEY;
+
public class TransactionPasswordPromptV2Gateway extends PrivilegedGateway implements TransactionPasswordPromptV2InteractorInterface.TransactionPasswordPromptV2GatewayInterface {
private final TransactionPasswordPromptV2InteractorInterface interactor;
@@ -25,4 +29,14 @@ public class TransactionPasswordPromptV2Gateway extends PrivilegedGateway implem
return HttpClientV2.getInstance().requestOTPForSendMoney(auth,jsonObject);
}
+
+ @Override
+ public boolean isFingerPrintEnabled() {
+ return GmeApplication.getStorage().getBoolean(APP_FINGER_PRINT_ENABLED,false);
+ }
+
+ @Override
+ public String getStoredSecretKey() {
+ return GmeApplication.getStorage().getString(APP_USER_SECRET_KEY,"");
+ }
}
diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2InteractorInterface.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2InteractorInterface.java
index c1b4d4c9..87d6307e 100644
--- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2InteractorInterface.java
+++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2InteractorInterface.java
@@ -11,5 +11,9 @@ public interface TransactionPasswordPromptV2InteractorInterface extends BaseInte
interface TransactionPasswordPromptV2GatewayInterface extends PrivilegedGatewayInterface
{
Observable requestOtp(String auth, String Uid,String amount,String kftc);
+
+ boolean isFingerPrintEnabled();
+
+ String getStoredSecretKey();
}
}
diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2Presenter.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2Presenter.java
index 67836a4c..d06dc02a 100644
--- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2Presenter.java
+++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2Presenter.java
@@ -8,6 +8,7 @@ import com.gmeremit.online.gmeremittance_native.utils.Constants;
import com.gmeremit.online.gmeremittance_native.utils.https.GenericApiObserverResponseV2;
import com.gmeremit.online.gmeremittance_native.utils.https.GenericResponseDataModel;
import com.gmeremit.online.gmeremittance_native.utils.https.MessageResponseDataModel;
+import com.gmeremit.online.gmeremittance_native.utils.security.SecurityUtils;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
@@ -16,7 +17,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
-public class TransactionPasswordPromptV2Presenter extends BasePresenter implements TransactionPasswordPromptV2PresenterInterface,TransactionPasswordPromptV2InteractorInterface {
+public class TransactionPasswordPromptV2Presenter extends BasePresenter implements TransactionPasswordPromptV2PresenterInterface, TransactionPasswordPromptV2InteractorInterface {
private final TransactionPasswordPromptV2PresenterInterface.TransactionPasswordPromptV2ContractInterface view;
private final TransactionPasswordPromptV2InteractorInterface.TransactionPasswordPromptV2GatewayInterface gateway;
@@ -26,29 +27,27 @@ public class TransactionPasswordPromptV2Presenter extends BasePresenter implemen
private String selectedKftcId;
public TransactionPasswordPromptV2Presenter(TransactionPasswordPromptV2PresenterInterface.TransactionPasswordPromptV2ContractInterface view) {
- this.view=view;
- this.gateway=new TransactionPasswordPromptV2Gateway(this);
+ this.view = view;
+ this.gateway = new TransactionPasswordPromptV2Gateway(this);
this.compositeDisposable = new CompositeDisposable();
- this.updateCountdownValue =-1;
- this.selectedKftcId="";
- this.selectedAmount="";
+ this.updateCountdownValue = -1;
+ this.selectedKftcId = "";
+ this.selectedAmount = "";
}
@Override
public void getOtp() {
- if(updateCountdownValue==-1) {
+ if (updateCountdownValue == -1) {
this.compositeDisposable.add(
- this.gateway.requestOtp(this.gateway.getAuth(), this.gateway.getUserID(),selectedAmount,selectedKftcId)
+ this.gateway.requestOtp(this.gateway.getAuth(), this.gateway.getUserID(), selectedAmount, selectedKftcId)
.doOnSubscribe(disposable -> view.showProgressBar(true, getStringfromStringId(R.string.requesting_otp_text)))
.doFinally(() -> view.showProgressBar(false, ""))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new ResendRequestObserver())
);
- }
- else
- {
+ } else {
view.showResendRequestView(false);
view.startCountdownView(updateCountdownValue);
}
@@ -57,7 +56,7 @@ public class TransactionPasswordPromptV2Presenter extends BasePresenter implemen
@Override
public void updateCountdown(long millisUntilFinished) {
- this.updateCountdownValue =millisUntilFinished;
+ this.updateCountdownValue = millisUntilFinished;
}
@Override
@@ -67,26 +66,33 @@ public class TransactionPasswordPromptV2Presenter extends BasePresenter implemen
@Override
public void updateSelectedAmount(String selectedAmount) {
- if(selectedAmount==null)
- selectedAmount="";
- this.selectedAmount=selectedAmount;
+ if (selectedAmount == null)
+ selectedAmount = "";
+ this.selectedAmount = selectedAmount;
}
@Override
public void updateSelectedKftcId(String selectedKftcId) {
- if(selectedKftcId==null)
- selectedKftcId="";
- this.selectedKftcId=selectedKftcId;
+ if (selectedKftcId == null)
+ selectedKftcId = "";
+ this.selectedKftcId = selectedKftcId;
}
@Override
public boolean checkIfUserHasEnabledBiometricAuth() {
return true;
+// return gateway.isFingerPrintEnabled()&&SecurityUtils.doesAppHasBiometricFeature(view.getContext());
}
+ @Override
+ public String getSecretKey() {
+ return gateway.getStoredSecretKey();
+
- class ResendRequestObserver extends GenericApiObserverResponseV2
- {
+ }
+
+
+ class ResendRequestObserver extends GenericApiObserverResponseV2 {
@Override
protected Type setType() {
@@ -100,8 +106,7 @@ public class TransactionPasswordPromptV2Presenter extends BasePresenter implemen
view.showResendRequestView(false);
view.startCountdownView(120000);
});
- }
- else {
+ } else {
view.showPopUpMessage(response.getMsg(), CustomAlertDialog.AlertType.FAILED, alertType -> {
view.showResendRequestView(true);
});
diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2PresenterInterface.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2PresenterInterface.java
index 9dea1e78..adc2aa86 100644
--- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2PresenterInterface.java
+++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2PresenterInterface.java
@@ -1,5 +1,7 @@
package com.gmeremit.online.gmeremittance_native.transactionpasspromt.presenter;
+import android.content.Context;
+
import com.gmeremit.online.gmeremittance_native.base.BaseContractInterface;
import com.gmeremit.online.gmeremittance_native.base.BasePresenterInterface;
@@ -16,10 +18,17 @@ public interface TransactionPasswordPromptV2PresenterInterface extends BasePrese
boolean checkIfUserHasEnabledBiometricAuth();
+ String getSecretKey();
+
+
interface TransactionPasswordPromptV2ContractInterface extends BaseContractInterface {
void startCountdownView(long durationMillisecond);
void showResendRequestView(boolean action);
+ Context getContext();
+
+
+
}
}
diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/view/TransactionPasswordPromptActivity.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/view/TransactionPasswordPromptActivity.java
index c0912ac9..4aaf5de4 100644
--- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/view/TransactionPasswordPromptActivity.java
+++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/view/TransactionPasswordPromptActivity.java
@@ -2,11 +2,11 @@ package com.gmeremit.online.gmeremittance_native.transactionpasspromt.view;
import android.annotation.SuppressLint;
import android.app.Activity;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.graphics.drawable.AnimatedVectorDrawable;
-import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.CountDownTimer;
@@ -29,6 +29,7 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import com.gmeremit.online.gmeremittance_native.GmeApplication;
import com.gmeremit.online.gmeremittance_native.R;
import com.gmeremit.online.gmeremittance_native.base.BaseActivity;
import com.gmeremit.online.gmeremittance_native.customwidgets.GmeErrorTextView;
@@ -38,12 +39,21 @@ import com.gmeremit.online.gmeremittance_native.utils.security.SecurityUtils;
import com.gmeremit.online.gmeremittance_native.utils.security.securitykeypad.SecurityKeyboardManager;
import com.gmeremit.online.gmeremittance_native.utils.security.securitykeypad.SecurityKeyboardView;
import com.gmeremit.online.gmeremittance_native.utils.security.securitykeypad.SecurityKeypadRequestParamBuilder;
+import com.mtramin.rxfingerprint.RxFingerprint;
+import com.mtramin.rxfingerprint.data.FingerprintDecryptionResult;
+import com.mtramin.rxfingerprint.data.FingerprintEncryptionResult;
import com.softsecurity.transkey.TransKeyActivity;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
+import io.reactivex.Observable;
+import io.reactivex.ObservableSource;
+import io.reactivex.Observer;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.functions.Function;
+import io.reactivex.observers.DisposableObserver;
public class TransactionPasswordPromptActivity extends BaseActivity implements SecurityKeyboardView.SecurityKeyboardFocusStateListener, TransactionPasswordPromptV2PresenterInterface.TransactionPasswordPromptV2ContractInterface, View.OnClickListener {
@@ -91,6 +101,9 @@ public class TransactionPasswordPromptActivity extends BaseActivity implements S
private CountDownTimer countDownTimer;
private AnimatedVectorDrawable fingerPrintAVD;
private AnimatedVectorDrawableCompat fingerPrintAVDCompat;
+ private Disposable fingerPrintReaderSubs;
+
+ String TAG = "FingerPrintObserver";
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -169,14 +182,14 @@ public class TransactionPasswordPromptActivity extends BaseActivity implements S
}
private void setupFingerPrintIconIfRequired() {
- //TODO if biometric is on
- if (SecurityUtils.doesAppHasBiometricFeature(this) && presenter.checkIfUserHasEnabledBiometricAuth()) {
+ if (presenter.checkIfUserHasEnabledBiometricAuth()) {
orTextView.setVisibility(View.VISIBLE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
fingerPrintAVD = (AnimatedVectorDrawable) ContextCompat.getDrawable(this, R.drawable.avd_fingerprint_off_to_on);
} else {
fingerPrintAVDCompat = (AnimatedVectorDrawableCompat) ContextCompat.getDrawable(this, R.drawable.avd_fingerprint_off_to_on);
}
+
} else {
passwordPromptImageView.setBackgroundResource(R.drawable.ic_penny_test_pending);
}
@@ -222,6 +235,8 @@ public class TransactionPasswordPromptActivity extends BaseActivity implements S
securityKeyboardView.setSecurityKeyboardFocusStateListener(this);
if (checkIfRequiredOTPScreen())
resendRequest.setOnClickListener(this);
+ else if (presenter.checkIfUserHasEnabledBiometricAuth())
+ fingerPrintReaderSubs = startObservingFingerPrintScanner();
}
@Override
@@ -230,35 +245,63 @@ public class TransactionPasswordPromptActivity extends BaseActivity implements S
securityKeyboardView.setSecurityKeyboardFocusStateListener(null);
if (checkIfRequiredOTPScreen())
resendRequest.setOnClickListener(null);
+ if (fingerPrintReaderSubs != null && !fingerPrintReaderSubs.isDisposed())
+ fingerPrintReaderSubs.dispose();
}
@Override
protected void onResume() {
super.onResume();
- new Handler().postDelayed(this::animateFingerPrintAppearAnimationIfRequired, 400);
+ animateFingerPrintAppearAnimationIfRequired(true);
}
@Override
protected void onPause() {
super.onPause();
- if (!checkIfRequiredOTPScreen() && SecurityUtils.doesAppHasBiometricFeature(this) && presenter.checkIfUserHasEnabledBiometricAuth())
- new Handler().postDelayed(() -> passwordPromptImageView.setImageDrawable(null), 200);
+ animateFingerPrintAppearAnimationIfRequired(false);
+
}
@SuppressLint("NewApi")
- private void animateFingerPrintAppearAnimationIfRequired() {
- if (!checkIfRequiredOTPScreen()) {
- if (fingerPrintAVD != null && !fingerPrintAVD.isRunning()) {
- passwordPromptImageView.setImageDrawable(fingerPrintAVD);
- fingerPrintAVD.start();
- } else if (fingerPrintAVDCompat != null && !fingerPrintAVDCompat.isRunning()) {
- passwordPromptImageView.setImageDrawable(fingerPrintAVDCompat);
- fingerPrintAVDCompat.start();
- }
+ private void animateFingerPrintAppearAnimationIfRequired(boolean action) {
+ if (!checkIfRequiredOTPScreen() && presenter.checkIfUserHasEnabledBiometricAuth() && action) {
+ new Handler().postDelayed(() -> {
+ if (fingerPrintAVD != null && !fingerPrintAVD.isRunning()) {
+ passwordPromptImageView.setImageDrawable(fingerPrintAVD);
+ fingerPrintAVD.start();
+ } else if (fingerPrintAVDCompat != null && !fingerPrintAVDCompat.isRunning()) {
+ passwordPromptImageView.setImageDrawable(fingerPrintAVDCompat);
+ fingerPrintAVDCompat.start();
+ }
+
+ }, 400);
+ } else {
+ new Handler().postDelayed(() -> {
+ passwordPromptImageView.setImageDrawable(null);
+ }, 200);
}
}
+ private Disposable startObservingFingerPrintScanner() {
+ return SecurityUtils.decryptSecret(this, presenter.getSecretKey())
+ .flatMap(authentication -> {
+ Log.d(TAG, authentication.getResult().toString());
+ switch (authentication.getResult()) {
+ case FAILED:
+ return io.reactivex.Observable.error(new SecurityUtils.FailedFingerPrintException(authentication.getMessage()));
+ case HELP:
+ return io.reactivex.Observable.error(new SecurityUtils.SensorNotReadyException(authentication.getMessage()));
+ case AUTHENTICATED:
+ return Observable.just(authentication);
+ default:
+ return io.reactivex.Observable.error(new Throwable(authentication.getMessage()));
+ }
+
+ })
+ .subscribeWith(new FingerPrintScannerObserver());
+ }
+
@Override
public void onSecurityViewRecievedFocus() {
if (securityKeyboardManager != null && !securityKeyboardManager.isKeyboardVisible())
@@ -338,6 +381,13 @@ public class TransactionPasswordPromptActivity extends BaseActivity implements S
}
}
+ @Override
+ public Context getContext() {
+ return this;
+ }
+
+
+
@Override
public void onBackPressed() {
@@ -416,4 +466,26 @@ public class TransactionPasswordPromptActivity extends BaseActivity implements S
}
+
+ class FingerPrintScannerObserver extends DisposableObserver {
+
+
+ @Override
+ public void onNext(FingerprintDecryptionResult fingerprintAuthenticationResult) {
+ Intent returnIntent = new Intent();
+ returnIntent.putExtra(TRANSACTION_PWD_ENC_DATA, fingerprintAuthenticationResult.getDecrypted());
+ setResult(Activity.RESULT_OK, returnIntent);
+ finish();
+ }
+
+ @Override
+ public void onError(Throwable e) {
+
+ }
+
+ @Override
+ public void onComplete() {
+
+ }
+ }
}
diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/SecurityUtils.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/SecurityUtils.java
index ceb31f27..cd4f87a1 100644
--- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/SecurityUtils.java
+++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/SecurityUtils.java
@@ -2,13 +2,53 @@ package com.gmeremit.online.gmeremittance_native.utils.security;
import android.content.Context;
+import com.mtramin.rxfingerprint.EncryptionMethod;
import com.mtramin.rxfingerprint.RxFingerprint;
+import com.mtramin.rxfingerprint.data.FingerprintAuthenticationResult;
+import com.mtramin.rxfingerprint.data.FingerprintDecryptionResult;
+import com.mtramin.rxfingerprint.data.FingerprintEncryptionResult;
+
+import io.reactivex.Observable;
+
public class SecurityUtils {
+ private static final String KEY_STORE_SECRET_ALIAS="gmeSecret321";
+
public static boolean doesAppHasBiometricFeature(Context context)
{
-// return RxFingerprint.isAvailable(context);
- return true;
+ return RxFingerprint.isAvailable(context);
+ }
+
+ public static Observable encryptSecret(Context context, String secret)
+ {
+ return RxFingerprint.encrypt(EncryptionMethod.RSA,context,KEY_STORE_SECRET_ALIAS,secret);
}
+
+ public static Observable decryptSecret(Context context, String secret)
+ {
+ return RxFingerprint.decrypt(EncryptionMethod.RSA,context,KEY_STORE_SECRET_ALIAS,secret);
+ }
+
+ public static Observable authenticateFingerPrint(Context context)
+ {
+ return RxFingerprint.authenticate(context);
+ }
+
+
+ public static class SensorNotReadyException extends Exception
+ {
+ public SensorNotReadyException(String message) {
+ super(message);
+ }
+ }
+
+ public static class FailedFingerPrintException extends Exception
+ {
+
+ public FailedFingerPrintException(String message) {
+ super(message);
+ }
+ }
+
}
diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml
index 11aa6dc2..45c6699e 100644
--- a/app/src/main/res/layout/activity_settings.xml
+++ b/app/src/main/res/layout/activity_settings.xml
@@ -135,6 +135,12 @@
android:textColor="@color/darkgray"
android:textSize="14sp" />
+
+