Only delete profile avatars during explicit delete actions

This preserves the avatar during re-registration, when PIN recovery might occur.
This commit is contained in:
Chris Eager
2025-07-14 16:09:36 -05:00
committed by ravi-signal
parent 58b9fa100d
commit ca9f29f984
10 changed files with 43 additions and 24 deletions

View File

@@ -193,7 +193,7 @@ public class ProfileController {
request.commitment().serialize()));
if (request.getAvatarChange() != CreateProfileRequest.AvatarChange.UNCHANGED) {
currentAvatar.ifPresent(s -> profilesManager.deleteAvatar(s).join());
currentAvatar.ifPresent(profilesManager::deleteAvatar);
}
accountsManager.update(account, a -> {

View File

@@ -374,7 +374,7 @@ public class AccountsManager extends RedisPubSubAdapter<String, String> implemen
keysManager.deleteSingleUsePreKeys(aci),
keysManager.deleteSingleUsePreKeys(pni),
messagesManager.clear(aci),
profilesManager.deleteAll(aci))
profilesManager.deleteAll(aci, false))
.thenCompose(ignored -> disconnectionRequestManager.requestDisconnection(aci))
.thenCompose(ignored -> accounts.reclaimAccount(e.getExistingAccount(), account, additionalWriteItems))
.thenCompose(ignored -> {
@@ -388,7 +388,7 @@ public class AccountsManager extends RedisPubSubAdapter<String, String> implemen
return CompletableFuture.allOf(keysManager.deleteSingleUsePreKeys(aci),
keysManager.deleteSingleUsePreKeys(pni),
messagesManager.clear(aci),
profilesManager.deleteAll(aci));
profilesManager.deleteAll(aci, false));
})
.join();
}
@@ -1299,7 +1299,7 @@ public class AccountsManager extends RedisPubSubAdapter<String, String> implemen
keysManager.deleteSingleUsePreKeys(account.getUuid()),
keysManager.deleteSingleUsePreKeys(account.getPhoneNumberIdentifier()),
messagesManager.clear(account.getUuid()),
profilesManager.deleteAll(account.getUuid()),
profilesManager.deleteAll(account.getUuid(), true),
registrationRecoveryPasswordsManager.remove(account.getIdentifier(IdentityType.PNI)))
.thenCompose(ignored -> accounts.delete(account.getUuid(), additionalWriteItems))
.thenCompose(ignored -> redisDeleteAsync(account))

View File

@@ -264,7 +264,7 @@ public class Profiles {
/**
* Deletes all profile versions for the given UUID
*
* @return a list of avatar URLs to be deleted
* @return a list of avatar URLs that may be deleted
*/
public CompletableFuture<List<String>> deleteAll(final UUID uuid) {
final Timer.Sample sample = Timer.start();

View File

@@ -60,12 +60,18 @@ public class ProfilesManager {
.thenCompose(ignored -> redisSetAsync(uuid, versionedProfile));
}
public CompletableFuture<Void> deleteAll(UUID uuid) {
/**
* Delete all profiles for the given uuid.
* <p>
* Avatars should be included for explicit delete actions, such as API calls and expired accounts. Implicit
* deletions, such as registration, should preserve them, so that PIN recovery includes the avatar.
*/
public CompletableFuture<Void> deleteAll(UUID uuid, final boolean includeAvatar) {
final CompletableFuture<Void> profilesAndAvatars = Mono.fromFuture(profiles.deleteAll(uuid))
.flatMapIterable(Function.identity())
.flatMap(avatar ->
Mono.fromFuture(deleteAvatar(avatar))
Mono.fromFuture(includeAvatar ? deleteAvatar(avatar) : CompletableFuture.completedFuture(null))
// this is best-effort
.retry(3)
.onErrorComplete())