Add a crawler to assign PNIs to existing accounts

This commit is contained in:
Jon Chambers
2021-10-27 18:09:03 -04:00
committed by Jon Chambers
parent 5c4855cca6
commit f0a6be32fc
3 changed files with 139 additions and 0 deletions

View File

@@ -170,6 +170,7 @@ import org.whispersystems.textsecuregcm.storage.AccountDatabaseCrawlerCache;
import org.whispersystems.textsecuregcm.storage.AccountDatabaseCrawlerListener;
import org.whispersystems.textsecuregcm.storage.Accounts;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.AssignPhoneNumberIdentifierCrawlerListener;
import org.whispersystems.textsecuregcm.storage.ContactDiscoveryWriter;
import org.whispersystems.textsecuregcm.storage.DeletedAccounts;
import org.whispersystems.textsecuregcm.storage.DeletedAccountsDirectoryReconciler;
@@ -545,6 +546,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
}
accountDatabaseCrawlerListeners.add(new NonNormalizedAccountCrawlerListener(accountsManager, metricsCluster));
accountDatabaseCrawlerListeners.add(new ContactDiscoveryWriter(accountsManager));
accountDatabaseCrawlerListeners.add(new AssignPhoneNumberIdentifierCrawlerListener(accountsManager, phoneNumberIdentifiers));
// PushFeedbackProcessor may update device properties
accountDatabaseCrawlerListeners.add(new PushFeedbackProcessor(accountsManager));
// delete accounts last

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2013-2021 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.storage;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Metrics;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import static org.whispersystems.textsecuregcm.metrics.MetricsUtil.name;
// TODO Remove this crawler when PNIs have been assigned to all existing accounts
public class AssignPhoneNumberIdentifierCrawlerListener extends AccountDatabaseCrawlerListener {
private final AccountsManager accountsManager;
private final PhoneNumberIdentifiers phoneNumberIdentifiers;
private static final Counter ASSIGNED_PNI_COUNTER =
Metrics.counter(name(AssignPhoneNumberIdentifierCrawlerListener.class, "assignPni"));
public AssignPhoneNumberIdentifierCrawlerListener(final AccountsManager accountsManager,
final PhoneNumberIdentifiers phoneNumberIdentifiers) {
this.accountsManager = accountsManager;
this.phoneNumberIdentifiers = phoneNumberIdentifiers;
}
@Override
public void onCrawlStart() {
}
@Override
public void onCrawlEnd(final Optional<UUID> fromUuid) {
}
@Override
protected void onCrawlChunk(final Optional<UUID> fromUuid, final List<Account> chunkAccounts) {
// There are exactly two ways an account can get a phone number identifier (PNI):
//
// 1. It's assigned at construction time for accounts created after the introduction of PNIs
// 2. It's assigned by this crawler
//
// That means that we don't need to worry about accidentally overwriting a PNI assigned by another source; if an
// account doesn't have a PNI when it winds up in a crawled chunk, there's no danger that it will have one after a
// refresh, and so we can blindly assign a random PNI.
chunkAccounts.stream()
.filter(account -> account.getPhoneNumberIdentifier().isEmpty())
.map(Account::getUuid)
.forEach(accountIdentifier -> {
// We must not update the accounts in the chunk directly; instead, we need to get a fresh copy we're free to
// update as needed.
accountsManager.getByAccountIdentifier(accountIdentifier).ifPresent(accountWithoutPni -> {
final String number = accountWithoutPni.getNumber();
final UUID phoneNumberIdentifier = phoneNumberIdentifiers.getPhoneNumberIdentifier(number);
accountsManager.update(accountWithoutPni, a -> a.setNumber(number, phoneNumberIdentifier));
});
ASSIGNED_PNI_COUNTER.increment();
});
}
}