mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 02:20:39 +00:00
Store recipient unregistered state
This commit is contained in:
parent
6a5dcd00b2
commit
f92466f6be
5 changed files with 102 additions and 2 deletions
|
@ -24,6 +24,7 @@ public class ServiceConfig {
|
|||
public static final boolean AUTOMATIC_NETWORK_RETRY = true;
|
||||
public static final int GROUP_MAX_SIZE = 1001;
|
||||
public static final int MAXIMUM_ONE_OFF_REQUEST_SIZE = 3;
|
||||
public static final long UNREGISTERED_LIFESPAN = TimeUnit.DAYS.toMillis(30);
|
||||
|
||||
public static AccountAttributes.Capabilities getCapabilities(boolean isPrimaryDevice) {
|
||||
final var giftBadges = !isPrimaryDevice;
|
||||
|
|
|
@ -164,6 +164,10 @@ public class RecipientHelper {
|
|||
registeredUsers.forEach((number, u) -> account.getRecipientTrustedResolver()
|
||||
.resolveRecipientTrusted(u.aci, u.pni, Optional.of(number)));
|
||||
|
||||
final var unregisteredUsers = new HashSet<>(numbers);
|
||||
unregisteredUsers.removeAll(registeredUsers.keySet());
|
||||
account.getRecipientStore().markUnregistered(unregisteredUsers);
|
||||
|
||||
return registeredUsers;
|
||||
}
|
||||
|
||||
|
|
|
@ -149,6 +149,17 @@ public class StorageHelper {
|
|||
|
||||
logger.debug("Pre-Merge ID Difference :: " + idDifference);
|
||||
|
||||
if (!idDifference.localOnlyIds().isEmpty()) {
|
||||
final var updated = account.getRecipientStore()
|
||||
.removeStorageIdsFromLocalOnlyUnregisteredRecipients(connection, idDifference.localOnlyIds());
|
||||
|
||||
if (updated > 0) {
|
||||
logger.warn(
|
||||
"Found {} records that were deleted remotely but only marked unregistered locally. Removed those from local store. Recalculating diff.",
|
||||
updated);
|
||||
}
|
||||
}
|
||||
|
||||
if (!idDifference.isEmpty()) {
|
||||
final var remoteOnlyRecords = getSignalStorageRecords(storageKey, idDifference.remoteOnlyIds());
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import java.util.UUID;
|
|||
public class AccountDatabase extends Database {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AccountDatabase.class);
|
||||
private static final long DATABASE_VERSION = 20;
|
||||
private static final long DATABASE_VERSION = 21;
|
||||
|
||||
private AccountDatabase(final HikariDataSource dataSource) {
|
||||
super(logger, DATABASE_VERSION, dataSource);
|
||||
|
@ -558,5 +558,14 @@ public class AccountDatabase extends Database {
|
|||
""");
|
||||
}
|
||||
}
|
||||
if (oldVersion < 21) {
|
||||
logger.debug("Updating database: Create unregistered column");
|
||||
try (final var statement = connection.createStatement()) {
|
||||
statement.executeUpdate("""
|
||||
ALTER TABLE recipient ADD unregistered_timestamp INTEGER;
|
||||
UPDATE recipient SET pni = NULL WHERE uuid IS NOT NULL;
|
||||
""");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ import java.util.Set;
|
|||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.asamk.signal.manager.config.ServiceConfig.UNREGISTERED_LIFESPAN;
|
||||
|
||||
public class RecipientStore implements RecipientIdCreator, RecipientResolver, RecipientTrustedResolver, ContactsStore, ProfileStore {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RecipientStore.class);
|
||||
|
@ -65,6 +67,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
|||
username TEXT UNIQUE,
|
||||
uuid BLOB UNIQUE,
|
||||
pni BLOB UNIQUE,
|
||||
unregistered_timestamp INTEGER,
|
||||
profile_key BLOB,
|
||||
profile_key_credential BLOB,
|
||||
|
||||
|
@ -521,7 +524,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
|||
"""
|
||||
SELECT r._id
|
||||
FROM %s r
|
||||
WHERE r.storage_id IS NULL
|
||||
WHERE r.storage_id IS NULL AND (r.unregistered_timestamp IS NULL OR r.unregistered_timestamp > ?)
|
||||
"""
|
||||
).formatted(TABLE_RECIPIENT);
|
||||
final var updateSql = (
|
||||
|
@ -534,6 +537,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
|||
try (final var connection = database.getConnection()) {
|
||||
connection.setAutoCommit(false);
|
||||
try (final var selectStmt = connection.prepareStatement(selectSql)) {
|
||||
selectStmt.setLong(1, System.currentTimeMillis() - UNREGISTERED_LIFESPAN);
|
||||
final var recipientIds = Utils.executeQueryForStream(selectStmt, this::getRecipientIdFromResultSet)
|
||||
.toList();
|
||||
try (final var updateStmt = connection.prepareStatement(updateSql)) {
|
||||
|
@ -835,6 +839,76 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
|||
rotateStorageId(connection, recipientId);
|
||||
}
|
||||
|
||||
public int removeStorageIdsFromLocalOnlyUnregisteredRecipients(
|
||||
final Connection connection, final List<StorageId> storageIds
|
||||
) throws SQLException {
|
||||
final var sql = (
|
||||
"""
|
||||
UPDATE %s
|
||||
SET storage_id = NULL
|
||||
WHERE storage_id = ? AND storage_id IS NOT NULL AND unregistered_timestamp IS NOT NULL
|
||||
"""
|
||||
).formatted(TABLE_RECIPIENT);
|
||||
var count = 0;
|
||||
try (final var statement = connection.prepareStatement(sql)) {
|
||||
for (final var storageId : storageIds) {
|
||||
statement.setBytes(1, storageId.getRaw());
|
||||
count += statement.executeUpdate();
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public void markUnregistered(final Set<String> unregisteredUsers) {
|
||||
logger.debug("Marking {} numbers as unregistered", unregisteredUsers.size());
|
||||
try (final var connection = database.getConnection()) {
|
||||
connection.setAutoCommit(false);
|
||||
for (final var number : unregisteredUsers) {
|
||||
final var recipient = findByNumber(connection, number);
|
||||
if (recipient.isPresent()) {
|
||||
markUnregistered(connection, recipient.get().id());
|
||||
}
|
||||
}
|
||||
connection.commit();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Failed update recipient store", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void markRegistered(
|
||||
final Connection connection, final RecipientId recipientId
|
||||
) throws SQLException {
|
||||
final var sql = (
|
||||
"""
|
||||
UPDATE %s
|
||||
SET unregistered_timestamp = ?
|
||||
WHERE _id = ?
|
||||
"""
|
||||
).formatted(TABLE_RECIPIENT);
|
||||
try (final var statement = connection.prepareStatement(sql)) {
|
||||
statement.setNull(1, Types.INTEGER);
|
||||
statement.setLong(2, recipientId.id());
|
||||
statement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private void markUnregistered(
|
||||
final Connection connection, final RecipientId recipientId
|
||||
) throws SQLException {
|
||||
final var sql = (
|
||||
"""
|
||||
UPDATE %s
|
||||
SET unregistered_timestamp = ?
|
||||
WHERE _id = ? AND unregistered_timestamp IS NULL
|
||||
"""
|
||||
).formatted(TABLE_RECIPIENT);
|
||||
try (final var statement = connection.prepareStatement(sql)) {
|
||||
statement.setLong(1, System.currentTimeMillis());
|
||||
statement.setLong(2, recipientId.id());
|
||||
statement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private void storeExpiringProfileKeyCredential(
|
||||
final Connection connection,
|
||||
final RecipientId recipientId,
|
||||
|
@ -948,6 +1022,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
|||
return new Pair<>(resolveRecipientLocked(connection, address), List.of());
|
||||
} else {
|
||||
final var pair = MergeRecipientHelper.resolveRecipientTrustedLocked(new HelperStore(connection), address);
|
||||
markRegistered(connection, pair.first());
|
||||
|
||||
for (final var toBeMergedRecipientId : pair.second()) {
|
||||
mergeRecipientsLocked(connection, pair.first(), toBeMergedRecipientId);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue