]> nmode's Git Repositories - signal-cli/blobdiff - lib/src/main/java/org/asamk/signal/manager/helper/PinHelper.java
Add support for SVR2
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / helper / PinHelper.java
index c734323ff092c94a44a8313ff11956176bd96faa..2c56092eddb9640ae0ba50c304fcc934e8cc50fe 100644 (file)
@@ -1,37 +1,39 @@
 package org.asamk.signal.manager.helper;
 
 import org.asamk.signal.manager.api.IncorrectPinException;
-import org.asamk.signal.manager.api.Pair;
-import org.signal.libsignal.protocol.InvalidKeyException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.whispersystems.signalservice.api.KeyBackupService;
-import org.whispersystems.signalservice.api.KeyBackupServicePinException;
-import org.whispersystems.signalservice.api.SvrNoDataException;
-import org.whispersystems.signalservice.api.SvrPinData;
 import org.whispersystems.signalservice.api.kbs.MasterKey;
 import org.whispersystems.signalservice.api.kbs.PinHashUtil;
+import org.whispersystems.signalservice.api.svr.SecureValueRecovery;
+import org.whispersystems.signalservice.api.svr.SecureValueRecoveryV1;
+import org.whispersystems.signalservice.api.svr.SecureValueRecoveryV2;
 import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException;
-import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
 import org.whispersystems.signalservice.internal.push.AuthCredentials;
 import org.whispersystems.signalservice.internal.push.LockedException;
 
 import java.io.IOException;
 import java.util.Collection;
-import java.util.stream.Stream;
 
 public class PinHelper {
 
     private final static Logger logger = LoggerFactory.getLogger(PinHelper.class);
 
     private final KeyBackupService keyBackupService;
+    private final SecureValueRecoveryV1 secureValueRecoveryV1;
+    private final SecureValueRecoveryV2 secureValueRecoveryV2;
     private final Collection<KeyBackupService> fallbackKeyBackupServices;
 
     public PinHelper(
-            final KeyBackupService keyBackupService, final Collection<KeyBackupService> fallbackKeyBackupServices
+            final KeyBackupService keyBackupService,
+            final Collection<KeyBackupService> fallbackKeyBackupServices,
+            SecureValueRecoveryV2 secureValueRecoveryV2
     ) {
         this.keyBackupService = keyBackupService;
         this.fallbackKeyBackupServices = fallbackKeyBackupServices;
+        this.secureValueRecoveryV1 = new SecureValueRecoveryV1(keyBackupService);
+        this.secureValueRecoveryV2 = secureValueRecoveryV2;
     }
 
     public void setRegistrationLockPin(
@@ -46,6 +48,22 @@ public class PinHelper {
             throw new IOException(e);
         }
         pinChangeSession.enableRegistrationLock(masterKey);
+
+        final var backupResponse = secureValueRecoveryV2.setPin(pin, masterKey).execute();
+        if (backupResponse instanceof SecureValueRecovery.BackupResponse.Success) {
+        } else if (backupResponse instanceof SecureValueRecovery.BackupResponse.ServerRejected) {
+            logger.warn("Backup svr2 failed: ServerRejected");
+        } else if (backupResponse instanceof SecureValueRecovery.BackupResponse.EnclaveNotFound) {
+            logger.warn("Backup svr2 failed: EnclaveNotFound");
+        } else if (backupResponse instanceof SecureValueRecovery.BackupResponse.ExposeFailure) {
+            logger.warn("Backup svr2 failed: ExposeFailure");
+        } else if (backupResponse instanceof SecureValueRecovery.BackupResponse.ApplicationError error) {
+            throw new IOException(error.getException());
+        } else if (backupResponse instanceof SecureValueRecovery.BackupResponse.NetworkError error) {
+            throw error.getException();
+        } else {
+            throw new AssertionError("Unexpected response");
+        }
     }
 
     public void migrateRegistrationLockPin(String pin, MasterKey masterKey) throws IOException {
@@ -69,75 +87,53 @@ public class PinHelper {
         } catch (UnauthenticatedResponseException e) {
             throw new IOException(e);
         }
+
+        final var deleteResponse = secureValueRecoveryV2.deleteData();
+        if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.Success) {
+        } else if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.ServerRejected) {
+            logger.warn("Delete svr2 failed: ServerRejected");
+        } else if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.EnclaveNotFound) {
+            logger.warn("Delete svr2 failed: EnclaveNotFound");
+        } else if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.ApplicationError error) {
+            throw new IOException(error.getException());
+        } else if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.NetworkError error) {
+            throw error.getException();
+        } else {
+            throw new AssertionError("Unexpected response");
+        }
     }
 
-    public SvrPinData getRegistrationLockData(
+    public SecureValueRecovery.RestoreResponse.Success getRegistrationLockData(
             String pin, LockedException e
     ) throws IOException, IncorrectPinException {
-        var basicStorageCredentials = e.getSvr1Credentials();
-        if (basicStorageCredentials == null) {
-            return null;
-        }
-
-        try {
-            return getRegistrationLockData(pin, basicStorageCredentials);
-        } catch (SvrNoDataException ex) {
-            throw new IOException(e);
-        } catch (KeyBackupServicePinException ex) {
-            throw new IncorrectPinException(ex.getTriesRemaining());
+        var svr1Credentials = e.getSvr1Credentials();
+        if (svr1Credentials != null) {
+            return getRegistrationLockData(secureValueRecoveryV1, svr1Credentials, pin);
         }
-    }
 
-    private SvrPinData getRegistrationLockData(
-            String pin, AuthCredentials authCredentials
-    ) throws IOException, SvrNoDataException, KeyBackupServicePinException {
-        final var basicStorageCredentials = authCredentials.asBasic();
-        var tokenResponsePair = getTokenResponse(basicStorageCredentials);
-        final var tokenResponse = tokenResponsePair.first();
-        final var keyBackupService = tokenResponsePair.second();
-
-        var registrationLockData = restoreMasterKey(pin, basicStorageCredentials, tokenResponse, keyBackupService);
-        if (registrationLockData == null) {
-            throw new AssertionError("Failed to restore master key");
+        var svr2Credentials = e.getSvr2Credentials();
+        if (svr2Credentials != null) {
+            return getRegistrationLockData(secureValueRecoveryV2, svr2Credentials, pin);
         }
-        return registrationLockData;
-    }
 
-    private Pair<TokenResponse, KeyBackupService> getTokenResponse(String basicStorageCredentials) throws IOException {
-        final var keyBackupServices = Stream.concat(Stream.of(keyBackupService), fallbackKeyBackupServices.stream())
-                .toList();
-        for (final var keyBackupService : keyBackupServices) {
-            var tokenResponse = keyBackupService.getToken(basicStorageCredentials);
-            if (tokenResponse != null && tokenResponse.getTries() > 0) {
-                return new Pair<>(tokenResponse, keyBackupService);
-            }
-        }
-        throw new IOException("KBS Account locked, maximum pin attempts reached.");
+        return null;
     }
 
-    private SvrPinData restoreMasterKey(
-            String pin,
-            String basicStorageCredentials,
-            TokenResponse tokenResponse,
-            final KeyBackupService keyBackupService
-    ) throws IOException, SvrNoDataException, KeyBackupServicePinException {
-        if (pin == null) return null;
-
-        if (basicStorageCredentials == null) {
-            throw new AssertionError("Cannot restore KBS key, no storage credentials supplied");
-        }
-
-        var session = keyBackupService.newRegistrationSession(basicStorageCredentials, tokenResponse);
-
-        try {
-            var hashedPin = PinHashUtil.hashPin(pin, session.hashSalt());
-            var kbsData = session.restorePin(hashedPin);
-            if (kbsData == null) {
-                throw new AssertionError("Null not expected");
-            }
-            return kbsData;
-        } catch (UnauthenticatedResponseException | InvalidKeyException e) {
-            throw new IOException(e);
+    public SecureValueRecovery.RestoreResponse.Success getRegistrationLockData(
+            SecureValueRecovery secureValueRecovery, AuthCredentials authCredentials, String pin
+    ) throws IOException, IncorrectPinException {
+        final var restoreResponse = secureValueRecovery.restoreDataPreRegistration(authCredentials, pin);
+
+        if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.Success s) {
+            return s;
+        } else if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.PinMismatch pinMismatch) {
+            throw new IncorrectPinException(pinMismatch.getTriesRemaining());
+        } else if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.ApplicationError error) {
+            throw new IOException(error.getException());
+        } else if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.NetworkError error) {
+            throw error.getException();
+        } else {
+            throw new AssertionError("Unexpected response");
         }
     }
 }