X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/55dde93811ac137741b49d3fab2483e689592038..a754eb6fafb568ef8904bf8b9276856e3dfd36e2:/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 ebafe24b..0e3c9af0 100644 --- a/lib/src/main/java/org/asamk/signal/manager/RegistrationManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/RegistrationManagerImpl.java @@ -18,13 +18,18 @@ 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.signal.libsignal.usernames.BaseUsernameException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.signalservice.api.SignalServiceAccountManager; @@ -33,15 +38,14 @@ 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.api.push.exceptions.DeprecatedVersionException; 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); @@ -90,29 +94,51 @@ 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; - } + try { + 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); + } catch (DeprecatedVersionException e) { + logger.debug("Signal-Server returned deprecated version exception", e); + throw e; + } } @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); @@ -139,11 +165,17 @@ 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()); } + try { + m.refreshCurrentUsername(); + } catch (IOException | BaseUsernameException e) { + logger.warn("Failed to refresh current username", e); + } + if (newManagerListener != null) { newManagerListener.accept(m); m = null; @@ -155,6 +187,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(), @@ -162,16 +206,7 @@ class RegistrationManagerImpl implements RegistrationManager { userAgent, null, ServiceConfig.AUTOMATIC_NETWORK_RETRY); - accountManager.setAccountAttributes(null, - account.getLocalRegistrationId(), - true, - null, - account.getPinMasterKey() == null ? null : account.getPinMasterKey().deriveRegistrationLock(), - account.getSelfUnidentifiedAccessKey(), - account.isUnrestrictedUnidentifiedAccess(), - capabilities, - account.isDiscoverableByPhoneNumber(), - account.getEncryptedDeviceName()); + accountManager.setAccountAttributes(account.getAccountAttributes(null)); account.setRegistered(true); logger.info("Reactivated existing account, verify is not necessary."); if (newManagerListener != null) { @@ -190,27 +225,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