Browse Source

fix: fallback on biometric key failures and retry creating key, fix up notification issues

pull/919/head 1.13.6
jubb 2 months ago
parent
commit
ba60e8a8ee
  1. 4
      app/build.gradle
  2. 38
      app/src/main/java/org/thoughtcrime/securesms/PassphrasePromptActivity.java
  3. 18
      app/src/main/java/org/thoughtcrime/securesms/crypto/BiometricSecretProvider.kt
  4. 4
      app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java
  5. 5
      app/src/main/java/org/thoughtcrime/securesms/notifications/PushNotificationService.kt
  6. 4
      libsession/src/main/java/org/session/libsession/messaging/jobs/BatchMessageReceiveJob.kt

4
app/build.gradle

@ -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,

38
app/src/main/java/org/thoughtcrime/securesms/PassphrasePromptActivity.java

@ -46,6 +46,7 @@ import org.thoughtcrime.securesms.crypto.BiometricSecretProvider;
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;
@ -68,6 +69,7 @@ public class PassphrasePromptActivity extends BaseActionBarActivity {
private boolean authenticated;
private boolean failure;
private boolean hasSignatureObject = true;
private KeyCachingService keyCachingService;
@ -205,7 +207,23 @@ public class PassphrasePromptActivity extends BaseActionBarActivity {
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", "");
@ -230,8 +248,22 @@ public class PassphrasePromptActivity extends BaseActionBarActivity {
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

18
app/src/main/java/org/thoughtcrime/securesms/crypto/BiometricSecretProvider.kt

@ -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
@ -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
}

4
app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java

@ -278,10 +278,10 @@ public class DefaultMessageNotifier implements MessageNotifier {
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 {
@ -305,7 +305,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
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;
}

5
app/src/main/java/org/thoughtcrime/securesms/notifications/PushNotificationService.kt

@ -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
@ -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.")

4
libsession/src/main/java/org/session/libsession/messaging/jobs/BatchMessageReceiveJob.kt

@ -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 {

Loading…
Cancel
Save