Cleanup incomplete account data after unsuccessful link

Fixes #2080
This commit is contained in:
AsamK 2026-07-31 08:56:54 +02:00
parent ecc76ec52b
commit de5daf0ad4
2 changed files with 39 additions and 1 deletions

View File

@ -191,14 +191,18 @@ public class ProvisioningManagerImpl implements ProvisioningManager, Closeable {
: new MediaRootBackupKey(msg.mediaRootBackupKey.toByteArray());
SignalAccount account = null;
var cleanUpPartialAccountOnFailure = false;
var linkingFinished = false;
try {
if (!accountExists) {
account = SignalAccount.createLinkedAccount(pathConfig.dataPath(),
accountPath,
serviceEnvironmentConfig.type(),
Settings.DEFAULT);
cleanUpPartialAccountOnFailure = true;
} else {
account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, Settings.DEFAULT);
cleanUpPartialAccountOnFailure = false;
}
account.setProvisioningData(number,
@ -241,6 +245,7 @@ public class ProvisioningManagerImpl implements ProvisioningManager, Closeable {
final var deviceId = Integer.parseInt(registerResponse.getDeviceId());
account.finishLinking(deviceId, aciPreKeys, pniPreKeys);
linkingFinished = true;
ManagerImpl m = null;
try {
@ -277,6 +282,12 @@ public class ProvisioningManagerImpl implements ProvisioningManager, Closeable {
m.close();
}
}
} catch (Exception e) {
if (!linkingFinished && cleanUpPartialAccountOnFailure && account != null) {
cleanupPartialAccount(account, accountPath, e);
account = null;
}
throw e;
} finally {
if (account != null) {
account.close();
@ -289,6 +300,28 @@ public class ProvisioningManagerImpl implements ProvisioningManager, Closeable {
socketHandle.close();
}
private void cleanupPartialAccount(final SignalAccount account, final String accountPath, final Exception cause) {
logger.warn("Link attempt failed before registration completed, removing partial account state for {}.",
accountPath,
cause);
try {
account.deleteAccountData();
} catch (IOException cleanupError) {
logger.warn("Failed to delete partial account data for {}: {}",
accountPath,
cleanupError.getMessage(),
cleanupError);
}
try {
accountsStore.removeAccount(accountPath);
} catch (RuntimeException cleanupError) {
logger.warn("Failed to remove partial account entry for {}: {}",
accountPath,
cleanupError.getMessage(),
cleanupError);
}
}
private boolean canRelinkExistingAccount(final String accountPath) throws IOException {
final SignalAccount signalAccount;
try {
@ -302,6 +335,11 @@ public class ProvisioningManagerImpl implements ProvisioningManager, Closeable {
}
try (signalAccount) {
if (signalAccount.getDeviceId() <= 0) {
logger.debug("Account has invalid deviceId {}, allowing relink.",
signalAccount.getDeviceId());
return true;
}
if (signalAccount.isPrimaryDevice()) {
logger.debug("Account is a primary device.");
return false;

View File

@ -1731,7 +1731,7 @@ public class SignalAccount implements Closeable {
}
public boolean isRegistered() {
return registered;
return registered && deviceId > 0;
}
public void setRegistered(final boolean registered) {