]> nmode's Git Repositories - signal-cli/blobdiff - lib/src/main/java/org/asamk/signal/manager/RegistrationManagerImpl.java
Update libsignal-service-java
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / RegistrationManagerImpl.java
index c48a2e9915d3a4fbb363467f52a8d89dcf7379bc..337aa348ae3811449d83b7d43843dcd4a7d7de37 100644 (file)
@@ -18,27 +18,24 @@ package org.asamk.signal.manager;
 
 import org.asamk.signal.manager.api.CaptchaRequiredException;
 import org.asamk.signal.manager.api.IncorrectPinException;
+import org.asamk.signal.manager.api.NonNormalizedPhoneNumberException;
 import org.asamk.signal.manager.api.PinLockedException;
+import org.asamk.signal.manager.api.UpdateProfile;
 import org.asamk.signal.manager.config.ServiceConfig;
 import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
+import org.asamk.signal.manager.helper.AccountFileUpdater;
 import org.asamk.signal.manager.helper.PinHelper;
 import org.asamk.signal.manager.storage.SignalAccount;
-import org.asamk.signal.manager.util.Utils;
+import org.asamk.signal.manager.util.NumberVerificationUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.whispersystems.libsignal.util.guava.Optional;
-import org.whispersystems.signalservice.api.KbsPinData;
-import org.whispersystems.signalservice.api.KeyBackupServicePinException;
-import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException;
 import org.whispersystems.signalservice.api.SignalServiceAccountManager;
 import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
 import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
-import org.whispersystems.signalservice.api.kbs.MasterKey;
 import org.whispersystems.signalservice.api.push.ACI;
+import org.whispersystems.signalservice.api.push.PNI;
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 import org.whispersystems.signalservice.internal.ServiceResponse;
-import org.whispersystems.signalservice.internal.push.LockedException;
-import org.whispersystems.signalservice.internal.push.RequestVerificationCodeResponse;
 import org.whispersystems.signalservice.internal.push.VerifyAccountResponse;
 import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider;
 
@@ -59,30 +56,34 @@ class RegistrationManagerImpl implements RegistrationManager {
 
     private final SignalServiceAccountManager accountManager;
     private final PinHelper pinHelper;
+    private final AccountFileUpdater accountFileUpdater;
 
     RegistrationManagerImpl(
             SignalAccount account,
             PathConfig pathConfig,
             ServiceEnvironmentConfig serviceEnvironmentConfig,
             String userAgent,
-            Consumer<Manager> newManagerListener
+            Consumer<Manager> newManagerListener,
+            AccountFileUpdater accountFileUpdater
     ) {
         this.account = account;
         this.pathConfig = pathConfig;
+        this.accountFileUpdater = accountFileUpdater;
         this.serviceEnvironmentConfig = serviceEnvironmentConfig;
         this.userAgent = userAgent;
         this.newManagerListener = newManagerListener;
 
         GroupsV2Operations groupsV2Operations;
         try {
-            groupsV2Operations = new GroupsV2Operations(ClientZkOperations.create(serviceEnvironmentConfig.getSignalServiceConfiguration()));
+            groupsV2Operations = new GroupsV2Operations(ClientZkOperations.create(serviceEnvironmentConfig.getSignalServiceConfiguration()),
+                    ServiceConfig.GROUP_MAX_SIZE);
         } catch (Throwable ignored) {
             groupsV2Operations = null;
         }
         this.accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(),
                 new DynamicCredentialsProvider(
                         // Using empty UUID, because registering doesn't work otherwise
-                        null, account.getAccount(), account.getPassword(), SignalServiceAddress.DEFAULT_DEVICE_ID),
+                        null, null, account.getNumber(), account.getPassword(), SignalServiceAddress.DEFAULT_DEVICE_ID),
                 userAgent,
                 groupsV2Operations,
                 ServiceConfig.AUTOMATIC_NETWORK_RETRY);
@@ -95,103 +96,45 @@ class RegistrationManagerImpl implements RegistrationManager {
     }
 
     @Override
-    public void register(boolean voiceVerification, String captcha) throws IOException, CaptchaRequiredException {
-        captcha = captcha == null ? null : captcha.replace("signalcaptcha://", "");
-        if (account.getAci() != null) {
-            try {
-                final var accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(),
-                        new DynamicCredentialsProvider(account.getAci(),
-                                account.getAccount(),
-                                account.getPassword(),
-                                account.getDeviceId()),
-                        userAgent,
-                        null,
-                        ServiceConfig.AUTOMATIC_NETWORK_RETRY);
-                accountManager.setAccountAttributes(account.getEncryptedDeviceName(),
-                        null,
-                        account.getLocalRegistrationId(),
-                        true,
-                        null,
-                        account.getPinMasterKey() == null ? null : account.getPinMasterKey().deriveRegistrationLock(),
-                        account.getSelfUnidentifiedAccessKey(),
-                        account.isUnrestrictedUnidentifiedAccess(),
-                        capabilities,
-                        account.isDiscoverableByPhoneNumber());
-                account.setRegistered(true);
-                logger.info("Reactivated existing account, verify is not necessary.");
-                if (newManagerListener != null) {
-                    final var m = new ManagerImpl(account, pathConfig, serviceEnvironmentConfig, userAgent);
-                    account = null;
-                    newManagerListener.accept(m);
-                }
-                return;
-            } catch (IOException e) {
-                logger.debug("Failed to reactivate account");
-            }
+    public void register(
+            boolean voiceVerification, String captcha
+    ) throws IOException, CaptchaRequiredException, NonNormalizedPhoneNumberException {
+        if (account.isRegistered()
+                && account.getServiceEnvironment() != null
+                && account.getServiceEnvironment() != serviceEnvironmentConfig.getType()) {
+            throw new IOException("Account is registered in another environment: " + account.getServiceEnvironment());
         }
-        final ServiceResponse<RequestVerificationCodeResponse> response;
-        if (voiceVerification) {
-            response = accountManager.requestVoiceVerificationCode(Utils.getDefaultLocale(null),
-                    Optional.fromNullable(captcha),
-                    Optional.absent(),
-                    Optional.absent());
-        } else {
-            response = accountManager.requestSmsVerificationCode(false,
-                    Optional.fromNullable(captcha),
-                    Optional.absent(),
-                    Optional.absent());
-        }
-        try {
-            handleResponseException(response);
-        } catch (org.whispersystems.signalservice.api.push.exceptions.CaptchaRequiredException e) {
-            throw new CaptchaRequiredException(e.getMessage(), e);
+
+        if (account.getAci() != null && attemptReactivateAccount()) {
+            return;
         }
+
+        NumberVerificationUtils.requestVerificationCode(accountManager, captcha, voiceVerification);
     }
 
     @Override
     public void verifyAccount(
             String verificationCode, String pin
     ) throws IOException, PinLockedException, IncorrectPinException {
-        verificationCode = verificationCode.replace("-", "");
-        VerifyAccountResponse response;
-        MasterKey masterKey;
-        try {
-            response = verifyAccountWithCode(verificationCode, null);
-
-            masterKey = null;
+        final var result = NumberVerificationUtils.verifyNumber(verificationCode,
+                pin,
+                pinHelper,
+                this::verifyAccountWithCode);
+        final var response = result.first();
+        final var masterKey = result.second();
+        if (masterKey == null) {
             pin = null;
-        } catch (LockedException e) {
-            if (pin == null) {
-                throw new PinLockedException(e.getTimeRemaining());
-            }
-
-            KbsPinData registrationLockData;
-            try {
-                registrationLockData = pinHelper.getRegistrationLockData(pin, e);
-            } catch (KeyBackupSystemNoDataException ex) {
-                throw new IOException(e);
-            } catch (KeyBackupServicePinException ex) {
-                throw new IncorrectPinException(ex.getTriesRemaining());
-            }
-            if (registrationLockData == null) {
-                throw e;
-            }
-
-            var registrationLock = registrationLockData.getMasterKey().deriveRegistrationLock();
-            try {
-                response = verifyAccountWithCode(verificationCode, registrationLock);
-            } catch (LockedException _e) {
-                throw new AssertionError("KBS Pin appeared to matched but reg lock still failed!");
-            }
-            masterKey = registrationLockData.getMasterKey();
         }
 
         //accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID)));
-        account.finishRegistration(ACI.parseOrNull(response.getUuid()), masterKey, pin);
+        final var aci = ACI.parseOrNull(response.getUuid());
+        final var pni = PNI.parseOrNull(response.getPni());
+        account.finishRegistration(aci, pni, masterKey, pin);
+        accountFileUpdater.updateAccountIdentifiers(account.getNumber(), aci);
 
         ManagerImpl m = null;
         try {
-            m = new ManagerImpl(account, pathConfig, serviceEnvironmentConfig, userAgent);
+            m = new ManagerImpl(account, pathConfig, accountFileUpdater, serviceEnvironmentConfig, userAgent);
             account = null;
 
             m.refreshPreKeys();
@@ -200,7 +143,7 @@ class RegistrationManagerImpl implements RegistrationManager {
             }
             // Set an initial empty profile so user can be added to groups
             try {
-                m.setProfile(null, null, null, null, null);
+                m.updateProfile(UpdateProfile.newBuilder().build());
             } catch (NoClassDefFoundError e) {
                 logger.warn("Failed to set default profile: {}", e.getMessage());
             }
@@ -216,30 +159,77 @@ class RegistrationManagerImpl implements RegistrationManager {
         }
     }
 
-    private VerifyAccountResponse verifyAccountWithCode(
+    @Override
+    public void deleteLocalAccountData() throws IOException {
+        account.deleteAccountData();
+        accountFileUpdater.removeAccount();
+        account = null;
+    }
+
+    @Override
+    public boolean isRegistered() {
+        return account.isRegistered();
+    }
+
+    private boolean attemptReactivateAccount() {
+        try {
+            final var accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(),
+                    account.getCredentialsProvider(),
+                    userAgent,
+                    null,
+                    ServiceConfig.AUTOMATIC_NETWORK_RETRY);
+            accountManager.setAccountAttributes(null,
+                    account.getLocalRegistrationId(),
+                    true,
+                    null,
+                    account.getRegistrationLock(),
+                    account.getSelfUnidentifiedAccessKey(),
+                    account.isUnrestrictedUnidentifiedAccess(),
+                    capabilities,
+                    account.isDiscoverableByPhoneNumber(),
+                    account.getEncryptedDeviceName(),
+                    account.getLocalPniRegistrationId());
+            account.setRegistered(true);
+            logger.info("Reactivated existing account, verify is not necessary.");
+            if (newManagerListener != null) {
+                final var m = new ManagerImpl(account,
+                        pathConfig,
+                        accountFileUpdater,
+                        serviceEnvironmentConfig,
+                        userAgent);
+                account = null;
+                newManagerListener.accept(m);
+            }
+            return true;
+        } catch (IOException e) {
+            logger.debug("Failed to reactivate account");
+        }
+        return false;
+    }
+
+    private ServiceResponse<VerifyAccountResponse> verifyAccountWithCode(
             final String verificationCode, final String registrationLock
-    ) throws IOException {
-        final ServiceResponse<VerifyAccountResponse> response;
+    ) {
         if (registrationLock == null) {
-            response = accountManager.verifyAccount(verificationCode,
+            return accountManager.verifyAccount(verificationCode,
                     account.getLocalRegistrationId(),
                     true,
                     account.getSelfUnidentifiedAccessKey(),
                     account.isUnrestrictedUnidentifiedAccess(),
                     ServiceConfig.capabilities,
-                    account.isDiscoverableByPhoneNumber());
+                    account.isDiscoverableByPhoneNumber(),
+                    account.getLocalPniRegistrationId());
         } else {
-            response = accountManager.verifyAccountWithRegistrationLockPin(verificationCode,
+            return accountManager.verifyAccountWithRegistrationLockPin(verificationCode,
                     account.getLocalRegistrationId(),
                     true,
                     registrationLock,
                     account.getSelfUnidentifiedAccessKey(),
                     account.isUnrestrictedUnidentifiedAccess(),
                     ServiceConfig.capabilities,
-                    account.isDiscoverableByPhoneNumber());
+                    account.isDiscoverableByPhoneNumber(),
+                    account.getLocalPniRegistrationId());
         }
-        handleResponseException(response);
-        return response.getResult().get();
     }
 
     @Override
@@ -249,15 +239,4 @@ class RegistrationManagerImpl implements RegistrationManager {
             account = null;
         }
     }
-
-    private void handleResponseException(final ServiceResponse<?> response) throws IOException {
-        final var throwableOptional = response.getExecutionError().or(response.getApplicationError());
-        if (throwableOptional.isPresent()) {
-            if (throwableOptional.get() instanceof IOException) {
-                throw (IOException) throwableOptional.get();
-            } else {
-                throw new IOException(throwableOptional.get());
-            }
-        }
-    }
 }