X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/7a06d3959ee425253afa67a3891ea8bf8ee6ab3c..276ecef3009baecb740f23d53ddaa81f487d57a2:/lib/src/main/java/org/asamk/signal/manager/RegistrationManagerImpl.java diff --git a/lib/src/main/java/org/asamk/signal/manager/RegistrationManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/RegistrationManagerImpl.java index 97c0adf2..f5bff4d2 100644 --- a/lib/src/main/java/org/asamk/signal/manager/RegistrationManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/RegistrationManagerImpl.java @@ -18,29 +18,32 @@ 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.RateLimitException; +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.NumberVerificationUtils; +import org.asamk.signal.manager.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.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.api.push.exceptions.AlreadyVerifiedException; import org.whispersystems.signalservice.internal.push.VerifyAccountResponse; import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider; import java.io.IOException; import java.util.function.Consumer; -import static org.asamk.signal.manager.config.ServiceConfig.capabilities; - class RegistrationManagerImpl implements RegistrationManager { private final static Logger logger = LoggerFactory.getLogger(RegistrationManagerImpl.class); @@ -72,14 +75,15 @@ class RegistrationManagerImpl implements RegistrationManager { 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.getNumber(), account.getPassword(), SignalServiceAddress.DEFAULT_DEVICE_ID), + null, null, account.getNumber(), account.getPassword(), SignalServiceAddress.DEFAULT_DEVICE_ID), userAgent, groupsV2Operations, ServiceConfig.AUTOMATIC_NETWORK_RETRY); @@ -88,23 +92,46 @@ class RegistrationManagerImpl implements RegistrationManager { serviceEnvironmentConfig.getKeyBackupConfig().getServiceId(), serviceEnvironmentConfig.getKeyBackupConfig().getMrenclave(), 10); - this.pinHelper = new PinHelper(keyBackupService); + final var fallbackKeyBackupServices = serviceEnvironmentConfig.getFallbackKeyBackupConfigs() + .stream() + .map(config -> accountManager.getKeyBackupService(ServiceConfig.getIasKeyStore(), + config.getEnclaveName(), + config.getServiceId(), + config.getMrenclave(), + 10)) + .toList(); + this.pinHelper = new PinHelper(keyBackupService, fallbackKeyBackupServices); } @Override - public void register(boolean voiceVerification, String captcha) throws IOException, CaptchaRequiredException { + public void register( + boolean voiceVerification, String captcha + ) throws IOException, CaptchaRequiredException, NonNormalizedPhoneNumberException, RateLimitException { + if (account.isRegistered() + && account.getServiceEnvironment() != null + && account.getServiceEnvironment() != serviceEnvironmentConfig.getType()) { + throw new IOException("Account is registered in another environment: " + account.getServiceEnvironment()); + } + if (account.getAci() != null && attemptReactivateAccount()) { return; } - NumberVerificationUtils.requestVerificationCode(accountManager, captcha, voiceVerification); + String sessionId = NumberVerificationUtils.handleVerificationSession(accountManager, + account.getSessionId(account.getNumber()), + id -> account.setSessionId(account.getNumber(), id), + voiceVerification, + captcha); + NumberVerificationUtils.requestVerificationCode(accountManager, sessionId, voiceVerification); } @Override public void verifyAccount( String verificationCode, String pin ) throws IOException, PinLockedException, IncorrectPinException { - final var result = NumberVerificationUtils.verifyNumber(verificationCode, + var sessionId = account.getSessionId(account.getNumber()); + final var result = NumberVerificationUtils.verifyNumber(sessionId, + verificationCode, pin, pinHelper, this::verifyAccountWithCode); @@ -116,7 +143,8 @@ class RegistrationManagerImpl implements RegistrationManager { //accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID))); final var aci = ACI.parseOrNull(response.getUuid()); - account.finishRegistration(aci, masterKey, pin); + final var pni = PNI.parseOrNull(response.getPni()); + account.finishRegistration(aci, pni, masterKey, pin); accountFileUpdater.updateAccountIdentifiers(account.getNumber(), aci); ManagerImpl m = null; @@ -130,7 +158,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()); } @@ -146,6 +174,18 @@ class RegistrationManagerImpl implements RegistrationManager { } } + @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(), @@ -153,16 +193,7 @@ class RegistrationManagerImpl implements RegistrationManager { 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()); + accountManager.setAccountAttributes(account.getAccountAttributes(null)); account.setRegistered(true); logger.info("Reactivated existing account, verify is not necessary."); if (newManagerListener != null) { @@ -181,27 +212,18 @@ class RegistrationManagerImpl implements RegistrationManager { return false; } - private ServiceResponse verifyAccountWithCode( - final String verificationCode, final String registrationLock - ) { - if (registrationLock == null) { - return accountManager.verifyAccount(verificationCode, - account.getLocalRegistrationId(), - true, - account.getSelfUnidentifiedAccessKey(), - account.isUnrestrictedUnidentifiedAccess(), - ServiceConfig.capabilities, - account.isDiscoverableByPhoneNumber()); - } else { - return accountManager.verifyAccountWithRegistrationLockPin(verificationCode, - account.getLocalRegistrationId(), - true, - registrationLock, - account.getSelfUnidentifiedAccessKey(), - account.isUnrestrictedUnidentifiedAccess(), - ServiceConfig.capabilities, - account.isDiscoverableByPhoneNumber()); + private VerifyAccountResponse verifyAccountWithCode( + final String sessionId, final String verificationCode, final String registrationLock + ) throws IOException { + try { + Utils.handleResponseException(accountManager.verifyAccount(verificationCode, sessionId)); + } catch (AlreadyVerifiedException e) { + // Already verified so can continue registering } + return Utils.handleResponseException(accountManager.registerAccount(sessionId, + null, + account.getAccountAttributes(registrationLock), + true)); } @Override