Skip to content

Commit

Permalink
fix: fallback on biometric key failures and retry creating key, fix u…
Browse files Browse the repository at this point in the history
…p notification issues
  • Loading branch information
hjubb committed Jun 21, 2022
1 parent 58dfd3b commit ba60e8a
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 15 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ dependencies {
testImplementation 'org.robolectric:shadows-multidex:4.4'
}

def canonicalVersionCode = 286
def canonicalVersionName = "1.13.5"
def canonicalVersionCode = 287
def canonicalVersionName = "1.13.6"

def postFixSize = 10
def abiPostFix = ['armeabi-v7a' : 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.AnimationCompleteListener;

import java.security.InvalidKeyException;
import java.security.Signature;

import network.loki.messenger.R;
Expand All @@ -68,6 +69,7 @@ public class PassphrasePromptActivity extends BaseActionBarActivity {

private boolean authenticated;
private boolean failure;
private boolean hasSignatureObject = true;

private KeyCachingService keyCachingService;

Expand Down Expand Up @@ -205,7 +207,23 @@ private void resumeScreenLock() {
if (fingerprintManager.isHardwareDetected() && fingerprintManager.hasEnrolledFingerprints()) {
Log.i(TAG, "Listening for fingerprints...");
fingerprintCancellationSignal = new CancellationSignal();
fingerprintManager.authenticate(new FingerprintManagerCompat.CryptoObject(biometricSecretProvider.getOrCreateBiometricSignature(this)), 0, fingerprintCancellationSignal, fingerprintListener, null);
Signature signature;
try {
signature = biometricSecretProvider.getOrCreateBiometricSignature(this);
hasSignatureObject = true;
throw new InvalidKeyException("e");
} catch (InvalidKeyException e) {
signature = null;
hasSignatureObject = false;
Log.e(TAG, "Error getting / creating signature", e);
}
fingerprintManager.authenticate(
signature == null ? null : new FingerprintManagerCompat.CryptoObject(signature),
0,
fingerprintCancellationSignal,
fingerprintListener,
null
);
} else {
Log.i(TAG, "firing intent...");
Intent intent = keyguardManager.createConfirmDeviceCredentialIntent("Unlock Session", "");
Expand All @@ -230,8 +248,22 @@ public void onAuthenticationError(int errMsgId, CharSequence errString) {
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
Log.i(TAG, "onAuthenticationSucceeded");
if (result.getCryptoObject() == null || result.getCryptoObject().getSignature() == null) {
// authentication failed
onAuthenticationFailed();
if (hasSignatureObject) {
// authentication failed
onAuthenticationFailed();
} else {
fingerprintPrompt.setImageResource(R.drawable.ic_check_white_48dp);
fingerprintPrompt.getBackground().setColorFilter(getResources().getColor(R.color.green_500), PorterDuff.Mode.SRC_IN);
fingerprintPrompt.animate().setInterpolator(new BounceInterpolator()).scaleX(1.1f).scaleY(1.1f).setDuration(500).setListener(new AnimationCompleteListener() {
@Override
public void onAnimationEnd(Animator animation) {
handleAuthenticated();

fingerprintPrompt.setImageResource(R.drawable.ic_fingerprint_white_48dp);
fingerprintPrompt.getBackground().setColorFilter(getResources().getColor(R.color.signal_primary), PorterDuff.Mode.SRC_IN);
}
}).start();
}
return;
}
// Signature object now successfully unlocked
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.Util
import java.security.InvalidKeyException
import java.security.KeyPairGenerator
import java.security.KeyStore
import java.security.PrivateKey
Expand Down Expand Up @@ -58,9 +59,20 @@ class BiometricSecretProvider {
createAsymmetricKey(context)
TextSecurePreferences.setFingerprintKeyGenerated(context)
}
val key = ks.getKey(BIOMETRIC_ASYM_KEY_ALIAS, null) as PrivateKey
val signature = Signature.getInstance(SIGNATURE_ALGORITHM)
signature.initSign(key)
val signature = try {
val key = ks.getKey(BIOMETRIC_ASYM_KEY_ALIAS, null) as PrivateKey
val signature = Signature.getInstance(SIGNATURE_ALGORITHM)
signature.initSign(key)
signature
} catch (e: InvalidKeyException) {
ks.deleteEntry(BIOMETRIC_ASYM_KEY_ALIAS)
createAsymmetricKey(context)
TextSecurePreferences.setFingerprintKeyGenerated(context)
val key = ks.getKey(BIOMETRIC_ASYM_KEY_ALIAS, null) as PrivateKey
val signature = Signature.getInstance(SIGNATURE_ALGORITHM)
signature.initSign(key)
signature
}
return signature
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,10 +278,10 @@ public void updateNotification(@NonNull Context context, boolean signal, int rem

try {
if (notificationState.hasMultipleThreads()) {
sendMultipleThreadNotification(context, notificationState, signal);
for (long threadId : notificationState.getThreads()) {
sendSingleThreadNotification(context, new NotificationState(notificationState.getNotificationsForThread(threadId)), false, true);
}
sendMultipleThreadNotification(context, notificationState, signal);
} else if (notificationState.getMessageCount() > 0){
sendSingleThreadNotification(context, notificationState, signal, false);
} else {
Expand All @@ -305,7 +305,7 @@ private String getTrimmedText(CharSequence text) {
String trimmedText = "";
if (text != null) {
int trimEnd = Math.min(text.length(), 50);
trimmedText = text.subSequence(0,trimEnd) + (text.length() > 50 ? "..." : "");
trimmedText = text.subSequence(0,trimEnd) + (text.length() >= 50 ? "..." : "");
}
return trimmedText;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import org.session.libsession.messaging.jobs.BatchMessageReceiveJob
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.jobs.MessageReceiveJob
import org.session.libsession.messaging.jobs.MessageReceiveParameters
import org.session.libsession.messaging.utilities.MessageWrapper
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.utilities.Base64
Expand All @@ -27,7 +28,7 @@ class PushNotificationService : FirebaseMessagingService() {
if (data != null) {
try {
val envelopeAsData = MessageWrapper.unwrap(data).toByteArray()
val job = MessageReceiveJob(envelopeAsData)
val job = BatchMessageReceiveJob(listOf(MessageReceiveParameters(envelopeAsData)), null)
JobQueue.shared.add(job)
} catch (e: Exception) {
Log.d("Loki", "Failed to unwrap data for message due to error: $e.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,12 @@ class BatchMessageReceiveJob(
}
storage.incrementUnread(threadId, trueUnreadCount)
storage.updateThread(threadId, true)
SSKEnvironment.shared.notificationManager.updateNotification(context, threadId)
}
}

// await all thread processing
deferredThreadMap.awaitAll()
}

SSKEnvironment.shared.notificationManager.updateNotification(context)
if (failures.isEmpty()) {
handleSuccess()
} else {
Expand Down

0 comments on commit ba60e8a

Please sign in to comment.