Implement account reregistration with recovery password

This commit is contained in:
AsamK 2024-02-10 11:54:06 +01:00
parent fb85e1a068
commit 9f6b6cb657
2 changed files with 90 additions and 38 deletions

View file

@ -39,6 +39,7 @@ import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.account.PreKeyCollection;
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.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
@ -111,6 +112,11 @@ public class RegistrationManagerImpl implements RegistrationManager {
}
try {
final var recoveryPassword = account.getRecoveryPassword();
if (recoveryPassword != null && account.isPrimaryDevice() && attemptReregisterAccount(recoveryPassword)) {
return;
}
if (account.getAci() != null && attemptReactivateAccount()) {
return;
}
@ -156,43 +162,7 @@ public class RegistrationManagerImpl implements RegistrationManager {
pin = null;
}
//accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID)));
final var aci = ACI.parseOrThrow(response.getUuid());
final var pni = PNI.parseOrThrow(response.getPni());
account.finishRegistration(aci, pni, masterKey, pin, aciPreKeys, pniPreKeys);
accountFileUpdater.updateAccountIdentifiers(account.getNumber(), aci);
ManagerImpl m = null;
try {
m = new ManagerImpl(account, pathConfig, accountFileUpdater, serviceEnvironmentConfig, userAgent);
account = null;
m.refreshPreKeys();
if (response.isStorageCapable()) {
m.syncRemoteStorage();
}
// Set an initial empty profile so user can be added to groups
try {
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;
}
} finally {
if (m != null) {
m.close();
}
}
finishAccountRegistration(response, pin, masterKey, aciPreKeys, pniPreKeys);
}
@Override
@ -207,6 +177,34 @@ public class RegistrationManagerImpl implements RegistrationManager {
return account.isRegistered();
}
private boolean attemptReregisterAccount(final String recoveryPassword) {
try {
if (account.getPniIdentityKeyPair() == null) {
account.setPniIdentityKeyPair(KeyUtils.generateIdentityKeyPair());
}
final var aciPreKeys = generatePreKeysForType(account.getAccountData(ServiceIdType.ACI));
final var pniPreKeys = generatePreKeysForType(account.getAccountData(ServiceIdType.PNI));
final var response = Utils.handleResponseException(accountManager.registerAccount(null,
recoveryPassword,
account.getAccountAttributes(null),
aciPreKeys,
pniPreKeys,
null,
true));
finishAccountRegistration(response,
account.getRegistrationLockPin(),
account.getPinBackedMasterKey(),
aciPreKeys,
pniPreKeys);
logger.info("Reregistered existing account, verify is not necessary.");
return true;
} catch (IOException e) {
logger.debug("Failed to reregister account with recovery password", e);
}
return false;
}
private boolean attemptReactivateAccount() {
try {
final var accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.signalServiceConfiguration(),
@ -254,6 +252,52 @@ public class RegistrationManagerImpl implements RegistrationManager {
true));
}
private void finishAccountRegistration(
final VerifyAccountResponse response,
final String pin,
final MasterKey masterKey,
final PreKeyCollection aciPreKeys,
final PreKeyCollection pniPreKeys
) throws IOException {
//accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID)));
final var aci = ACI.parseOrThrow(response.getUuid());
final var pni = PNI.parseOrThrow(response.getPni());
account.finishRegistration(aci, pni, masterKey, pin, aciPreKeys, pniPreKeys);
accountFileUpdater.updateAccountIdentifiers(account.getNumber(), aci);
ManagerImpl m = null;
try {
m = new ManagerImpl(account, pathConfig, accountFileUpdater, serviceEnvironmentConfig, userAgent);
account = null;
m.refreshPreKeys();
if (response.isStorageCapable()) {
m.syncRemoteStorage();
}
// Set an initial empty profile so user can be added to groups
try {
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;
}
} finally {
if (m != null) {
m.close();
}
}
}
@Override
public void close() {
if (account != null) {

View file

@ -1351,7 +1351,7 @@ public class SignalAccount implements Closeable {
getAccountCapabilities(),
encryptedDeviceName,
pniAccountData.getLocalRegistrationId(),
null); // TODO recoveryPassword?
getRecoveryPassword());
}
public AccountAttributes.Capabilities getAccountCapabilities() {
@ -1533,6 +1533,14 @@ public class SignalAccount implements Closeable {
save();
}
public String getRecoveryPassword() {
final var masterKey = getPinBackedMasterKey();
if (masterKey == null) {
return null;
}
return masterKey.deriveRegistrationRecoveryPassword();
}
public long getStorageManifestVersion() {
return getKeyValueStore().getEntry(storageManifestVersion);
}