Skip to content

Commit

Permalink
Merge pull request #24 from infinum/dev
Browse files Browse the repository at this point in the history
Release v1.0.0
  • Loading branch information
domagojkorman authored Feb 13, 2018
2 parents d45d93f + 2f6bc81 commit 18d6f90
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 121 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#### Add dependency

```gradle
implementation 'co.infinum:goldfinger:1.0.0-rc1'
implementation 'co.infinum:goldfinger:1.0.0'
```

#### Initialize
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ buildscript {
]

ext.versions = [
goldfinger: '1.0.0-rc1',
goldfinger: '1.0.0',
buildTools: '26.0.2',
google : '27.0.2'
]
Expand Down
6 changes: 6 additions & 0 deletions example/src/main/java/co/infinum/example/ExampleActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ protected void onStart() {
}
}

@Override
protected void onStop() {
super.onStop();
goldfinger.cancel();
}

private void onSuccessResult(String value) {
onResult("onSuccess", value);
statusView.setTextColor(ContextCompat.getColor(this, R.color.ok));
Expand Down
2 changes: 0 additions & 2 deletions example/src/main/res/layout/activity_example.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
Expand Down Expand Up @@ -50,5 +49,4 @@
android:padding="16dp"
android:textColor="@color/textRegular"
android:textSize="16sp"/>

</LinearLayout>
39 changes: 39 additions & 0 deletions lib/src/main/java/co/infinum/goldfinger/AsyncCryptoFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package co.infinum.goldfinger;

import android.support.annotation.Nullable;
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

class AsyncCryptoFactory {

private final CryptoFactory cryptoFactory;
private final ExecutorService executor;
private Future task;

AsyncCryptoFactory(CryptoFactory cryptoFactory) {
this.cryptoFactory = cryptoFactory;
this.executor = Executors.newSingleThreadExecutor();
}

void createCryptoObject(String keyName, Mode mode, AsyncCryptoFactory.Callback callback) {
if (task != null && !task.isDone()) {
task.cancel(true);
}

this.task = executor.submit(new CryptoObjectInitRunnable(cryptoFactory, keyName, mode, callback));
}

static abstract class Callback {

boolean canceled = false;

abstract void onCryptoObjectCreated(@Nullable FingerprintManagerCompat.CryptoObject cryptoObject);

void cancel() {
canceled = true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,41 @@

class CancellableAuthenticationCallback extends FingerprintManagerCompat.AuthenticationCallback {

private static final long IGNORE_CANCEL_MS = 100;

private final Crypto crypto;
private final Logger logger;
private final Mode mode;
private final String value;
private final Goldfinger.Callback callback;
final CancellationSignal cancellationSignal = new CancellationSignal();
private final long initializationTime;
private final Clock clock;
final CancellationSignal cancellationSignal;

CancellableAuthenticationCallback(Crypto crypto, Logger logger, Mode mode, String value, Goldfinger.Callback callback) {
CancellableAuthenticationCallback(Crypto crypto, Logger logger, Clock clock, Mode mode, String value, Goldfinger.Callback callback) {
this.crypto = crypto;
this.logger = logger;
this.mode = mode;
this.value = value;
this.callback = callback;
this.clock = clock;
this.initializationTime = clock.currentTimeMs();
this.cancellationSignal = new CancellationSignal();
}

@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
if (!cancellationSignal.isCanceled()) {
Error error = Error.fromId(errMsgId);
Error error = Error.fromId(errMsgId);
if (shouldReactToError(error)) {
logger.log("Error [%s]", error);
callback.onError(error);
}
}

@Override
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
Warning warning = Warning.fromId(helpMsgId);
if (!cancellationSignal.isCanceled()) {
Warning warning = Warning.fromId(helpMsgId);
logger.log("Warning [%s]", warning);
callback.onWarning(warning);
}
Expand Down Expand Up @@ -84,4 +91,9 @@ void cancel() {
cancellationSignal.cancel();
}
}

private boolean shouldReactToError(Error error) {
return !cancellationSignal.isCanceled()
&& (error != Error.CANCELED || clock.isBeforeNow(initializationTime + IGNORE_CANCEL_MS));
}
}
28 changes: 28 additions & 0 deletions lib/src/main/java/co/infinum/goldfinger/Clock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package co.infinum.goldfinger;

/**
* Singleton class that wraps time functions.
* It is mainly needed for tests.
*/
class Clock {

private static Clock INSTANCE;

private Clock() {
}

static Clock instance() {
if (INSTANCE == null) {
INSTANCE = new Clock();
}
return INSTANCE;
}

long currentTimeMs() {
return System.currentTimeMillis();
}

boolean isBeforeNow(long timeMs) {
return timeMs < currentTimeMs();
}
}
6 changes: 2 additions & 4 deletions lib/src/main/java/co/infinum/goldfinger/Crypto.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ class Default implements Crypto {
public String encrypt(FingerprintManagerCompat.CryptoObject cryptoObject, String value) {
try {
byte[] encryptedBytes = cryptoObject.getCipher().doFinal(value.getBytes());
String encryptedValue = Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
return encryptedValue;
return Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
} catch (Exception e) {
logger.log(e);
return null;
Expand All @@ -44,8 +43,7 @@ public String encrypt(FingerprintManagerCompat.CryptoObject cryptoObject, String
public String decrypt(FingerprintManagerCompat.CryptoObject cryptoObject, String value) {
try {
byte[] decodedBytes = Base64.decode(value, Base64.DEFAULT);
String decryptedValue = new String(cryptoObject.getCipher().doFinal(decodedBytes));
return decryptedValue;
return new String(cryptoObject.getCipher().doFinal(decodedBytes));
} catch (Exception e) {
logger.log(e);
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package co.infinum.goldfinger;

import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;

class CryptoObjectInitRunnable implements Runnable {

private final CryptoFactory cryptoFactory;
private final String keyName;
private final Mode mode;
private final AsyncCryptoFactory.Callback callback;

CryptoObjectInitRunnable(CryptoFactory cryptoFactory, String keyName, Mode mode, AsyncCryptoFactory.Callback callback) {
this.cryptoFactory = cryptoFactory;
this.keyName = keyName;
this.mode = mode;
this.callback = callback;
}

@Override
public void run() {
FingerprintManagerCompat.CryptoObject cryptoObject = null;
switch (mode) {
case AUTHENTICATION:
cryptoObject = cryptoFactory.createAuthenticationCryptoObject(keyName);
break;
case DECRYPTION:
cryptoObject = cryptoFactory.createDecryptionCryptoObject(keyName);
break;
case ENCRYPTION:
cryptoObject = cryptoFactory.createEncryptionCryptoObject(keyName);
break;
}

if (!callback.canceled) {
callback.onCryptoObjectCreated(cryptoObject);
}
}
}
3 changes: 2 additions & 1 deletion lib/src/main/java/co/infinum/goldfinger/Goldfinger.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ private Goldfinger buildMarshmallowInstance() {
Crypto finalCrypto = crypto != null ? crypto : new Crypto.Default(logger);
CryptoFactory finalCryptoFactory =
cryptoFactory != null ? cryptoFactory : new CryptoFactory.Default(context, logger);
return new MarshmallowGoldfinger(context, finalCryptoFactory, finalCrypto, logger);
AsyncCryptoFactory asyncCryptoFactory = new AsyncCryptoFactory(finalCryptoFactory);
return new MarshmallowGoldfinger(context, asyncCryptoFactory, finalCrypto, logger);
}
}
}
2 changes: 1 addition & 1 deletion lib/src/main/java/co/infinum/goldfinger/Logger.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ void log(String message, Object... args) {

void log(Throwable t) {
if (enabled) {
Log.e(TAG, t.getMessage());
Log.e(TAG, t.toString());
}
}
}
55 changes: 32 additions & 23 deletions lib/src/main/java/co/infinum/goldfinger/MarshmallowGoldfinger.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;

Expand All @@ -13,14 +14,16 @@ class MarshmallowGoldfinger implements Goldfinger {
private static final String KEY_AUTH_MODE = "<Goldfinger authentication mode>";

private final Handler mainHandler = new Handler(Looper.getMainLooper());
private final CryptoFactory cryptoFactory;
private final Crypto crypto;
private final FingerprintManagerCompat fingerprintManagerCompat;
private final Logger logger;
private final AsyncCryptoFactory asyncCryptoFactory;

private AsyncCryptoFactory.Callback asyncCryptoFactoryCallback;
private CancellableAuthenticationCallback cancellableAuthenticationCallback;

MarshmallowGoldfinger(Context context, CryptoFactory cryptoFactory, Crypto crypto, Logger logger) {
this.cryptoFactory = cryptoFactory;
MarshmallowGoldfinger(Context context, AsyncCryptoFactory asyncCryptoFactory, Crypto crypto, Logger logger) {
this.asyncCryptoFactory = asyncCryptoFactory;
this.crypto = crypto;
this.fingerprintManagerCompat = FingerprintManagerCompat.from(context);
this.logger = logger;
Expand Down Expand Up @@ -51,31 +54,33 @@ public void encrypt(String keyName, String value, Callback callback) {
startFingerprintAuthentication(keyName, value, Mode.ENCRYPTION, callback);
}

private void startFingerprintAuthentication(String keyName, String value, Mode mode, Callback callback) {
private void startFingerprintAuthentication(final String keyName, final String value, final Mode mode, final Callback callback) {
cancel();

logger.log("Creating CryptoObject");
FingerprintManagerCompat.CryptoObject cryptoObject = null;
switch (mode) {
case AUTHENTICATION:
cryptoObject = cryptoFactory.createAuthenticationCryptoObject(keyName);
break;
case DECRYPTION:
cryptoObject = cryptoFactory.createDecryptionCryptoObject(keyName);
break;
case ENCRYPTION:
cryptoObject = cryptoFactory.createEncryptionCryptoObject(keyName);
break;
}
asyncCryptoFactoryCallback = new AsyncCryptoFactory.Callback() {
@Override
void onCryptoObjectCreated(@Nullable FingerprintManagerCompat.CryptoObject cryptoObject) {
if (cryptoObject != null) {
startNativeFingerprintAuthentication(cryptoObject, keyName, value, mode, callback);
} else {
notifyCryptoObjectInitError(callback);
}
}
};
asyncCryptoFactory.createCryptoObject(keyName, mode, asyncCryptoFactoryCallback);
}

if (cryptoObject == null) {
logger.log("Failed to create CryptoObject");
callback.onError(Error.CRYPTO_OBJECT_INIT);
return;
}
private void notifyCryptoObjectInitError(Callback callback) {
logger.log("Failed to create CryptoObject");
callback.onError(Error.CRYPTO_OBJECT_INIT);
}

private void startNativeFingerprintAuthentication(@Nullable FingerprintManagerCompat.CryptoObject cryptoObject, String keyName,
String value, Mode mode, Callback callback) {

logger.log("Starting authentication [keyName=%s; value=%s]", keyName, value);
cancellableAuthenticationCallback = new CancellableAuthenticationCallback(crypto, logger, mode, value, callback);
cancellableAuthenticationCallback = new CancellableAuthenticationCallback(crypto, logger, Clock.instance(), mode, value, callback);
fingerprintManagerCompat.authenticate(cryptoObject,
0,
cancellableAuthenticationCallback.cancellationSignal,
Expand All @@ -86,9 +91,13 @@ private void startFingerprintAuthentication(String keyName, String value, Mode m
@Override
public void cancel() {
if (cancellableAuthenticationCallback != null) {
mainHandler.removeCallbacksAndMessages(null);
cancellableAuthenticationCallback.cancel();
cancellableAuthenticationCallback = null;
}

if (asyncCryptoFactoryCallback != null) {
asyncCryptoFactoryCallback.cancel();
asyncCryptoFactoryCallback = null;
}
}
}
Loading

0 comments on commit 18d6f90

Please sign in to comment.