Store serviceId in protocol stores as TEXT
ServiceIds are no longer just UUIDs, they can now have prefixes like "PNI:"
This commit is contained in:
		
							parent
							
								
									a7744e837c
								
							
						
					
					
						commit
						b2a32666e9
					
				@ -2,6 +2,7 @@ package org.asamk.signal.manager.storage;
 | 
			
		||||
 | 
			
		||||
import com.zaxxer.hikari.HikariDataSource;
 | 
			
		||||
 | 
			
		||||
import org.asamk.signal.manager.api.Pair;
 | 
			
		||||
import org.asamk.signal.manager.storage.groups.GroupStore;
 | 
			
		||||
import org.asamk.signal.manager.storage.identities.IdentityKeyStore;
 | 
			
		||||
import org.asamk.signal.manager.storage.prekeys.KyberPreKeyStore;
 | 
			
		||||
@ -15,16 +16,21 @@ import org.asamk.signal.manager.storage.sessions.SessionStore;
 | 
			
		||||
import org.asamk.signal.manager.storage.stickers.StickerStore;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.whispersystems.signalservice.api.push.ServiceId;
 | 
			
		||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
 | 
			
		||||
import org.whispersystems.signalservice.api.util.UuidUtil;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.sql.Connection;
 | 
			
		||||
import java.sql.SQLException;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
public class AccountDatabase extends Database {
 | 
			
		||||
 | 
			
		||||
    private final static Logger logger = LoggerFactory.getLogger(AccountDatabase.class);
 | 
			
		||||
    private static final long DATABASE_VERSION = 14;
 | 
			
		||||
    private static final long DATABASE_VERSION = 15;
 | 
			
		||||
 | 
			
		||||
    private AccountDatabase(final HikariDataSource dataSource) {
 | 
			
		||||
        super(logger, DATABASE_VERSION, dataSource);
 | 
			
		||||
@ -346,7 +352,146 @@ public class AccountDatabase extends Database {
 | 
			
		||||
                                            """);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (oldVersion < 15) {
 | 
			
		||||
            logger.debug("Updating database: Store serviceId as TEXT");
 | 
			
		||||
            try (final var statement = connection.createStatement()) {
 | 
			
		||||
                statement.executeUpdate("""
 | 
			
		||||
                                        CREATE TABLE tmp_mapping_table (
 | 
			
		||||
                                          uuid BLOB NOT NULL,
 | 
			
		||||
                                          address TEXT NOT NULL
 | 
			
		||||
                                        ) STRICT;
 | 
			
		||||
                                        """);
 | 
			
		||||
 | 
			
		||||
                final var sql = (
 | 
			
		||||
                        """
 | 
			
		||||
                        SELECT r.uuid, r.pni
 | 
			
		||||
                        FROM recipient r
 | 
			
		||||
                        """
 | 
			
		||||
                );
 | 
			
		||||
                final var uuidAddressMapping = new HashMap<UUID, ServiceId>();
 | 
			
		||||
                try (final var preparedStatement = connection.prepareStatement(sql)) {
 | 
			
		||||
                    try (var result = Utils.executeQueryForStream(preparedStatement, (resultSet) -> {
 | 
			
		||||
                        final var pni = Optional.ofNullable(resultSet.getBytes("pni"))
 | 
			
		||||
                                .map(UuidUtil::parseOrNull)
 | 
			
		||||
                                .map(ServiceId.PNI::from);
 | 
			
		||||
                        final var serviceIdUuid = Optional.ofNullable(resultSet.getBytes("uuid"))
 | 
			
		||||
                                .map(UuidUtil::parseOrNull);
 | 
			
		||||
                        final var serviceId = serviceIdUuid.isPresent() && pni.isPresent() && serviceIdUuid.get()
 | 
			
		||||
                                .equals(pni.get().getRawUuid())
 | 
			
		||||
                                ? pni.<ServiceId>map(p -> p)
 | 
			
		||||
                                : serviceIdUuid.<ServiceId>map(ACI::from);
 | 
			
		||||
 | 
			
		||||
                        return new Pair<>(serviceId, pni);
 | 
			
		||||
                    })) {
 | 
			
		||||
                        result.forEach(p -> {
 | 
			
		||||
                            final var serviceId = p.first();
 | 
			
		||||
                            final var pni = p.second();
 | 
			
		||||
                            if (serviceId.isPresent()) {
 | 
			
		||||
                                uuidAddressMapping.put(serviceId.get().getRawUuid(), serviceId.get());
 | 
			
		||||
                            }
 | 
			
		||||
                            if (pni.isPresent()) {
 | 
			
		||||
                                uuidAddressMapping.put(pni.get().getRawUuid(), pni.get());
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                final var insertSql = """
 | 
			
		||||
                                      INSERT INTO tmp_mapping_table (uuid, address)
 | 
			
		||||
                                      VALUES (?,?)
 | 
			
		||||
                                      """;
 | 
			
		||||
                try (final var insertStatement = connection.prepareStatement(insertSql)) {
 | 
			
		||||
                    for (final var entry : uuidAddressMapping.entrySet()) {
 | 
			
		||||
                        final var uuid = entry.getKey();
 | 
			
		||||
                        final var serviceId = entry.getValue();
 | 
			
		||||
                        insertStatement.setBytes(1, UuidUtil.toByteArray(uuid));
 | 
			
		||||
                        insertStatement.setString(2, serviceId.toString());
 | 
			
		||||
                        insertStatement.execute();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                statement.executeUpdate("""
 | 
			
		||||
                                        CREATE TABLE identity2 (
 | 
			
		||||
                                          _id INTEGER PRIMARY KEY,
 | 
			
		||||
                                          address TEXT UNIQUE NOT NULL,
 | 
			
		||||
                                          identity_key BLOB NOT NULL,
 | 
			
		||||
                                          added_timestamp INTEGER NOT NULL,
 | 
			
		||||
                                          trust_level INTEGER NOT NULL
 | 
			
		||||
                                        ) STRICT;
 | 
			
		||||
                                        INSERT INTO identity2 (_id, address, identity_key, added_timestamp, trust_level)
 | 
			
		||||
                                          SELECT i._id, (SELECT t.address FROM tmp_mapping_table t WHERE t.uuid = i.uuid) address, i.identity_key, i.added_timestamp, i.trust_level
 | 
			
		||||
                                          FROM identity i
 | 
			
		||||
                                          WHERE address IS NOT NULL;
 | 
			
		||||
                                        DROP TABLE identity;
 | 
			
		||||
                                        ALTER TABLE identity2 RENAME TO identity;
 | 
			
		||||
 | 
			
		||||
                                        CREATE TABLE message_send_log2 (
 | 
			
		||||
                                          _id INTEGER PRIMARY KEY,
 | 
			
		||||
                                          content_id INTEGER NOT NULL REFERENCES message_send_log_content (_id) ON DELETE CASCADE,
 | 
			
		||||
                                          address TEXT NOT NULL,
 | 
			
		||||
                                          device_id INTEGER NOT NULL
 | 
			
		||||
                                        ) STRICT;
 | 
			
		||||
                                        INSERT INTO message_send_log2 (_id, content_id, address, device_id)
 | 
			
		||||
                                          SELECT m._id, m.content_id, (SELECT t.address FROM tmp_mapping_table t WHERE t.uuid = m.uuid) address, m.device_id
 | 
			
		||||
                                          FROM message_send_log m
 | 
			
		||||
                                          WHERE address IS NOT NULL;
 | 
			
		||||
                                        DROP INDEX msl_recipient_index;
 | 
			
		||||
                                        DROP INDEX msl_content_index;
 | 
			
		||||
                                        DROP TABLE message_send_log;
 | 
			
		||||
                                        ALTER TABLE message_send_log2 RENAME TO message_send_log;
 | 
			
		||||
                                        CREATE INDEX msl_recipient_index ON message_send_log (address, device_id, content_id);
 | 
			
		||||
                                        CREATE INDEX msl_content_index ON message_send_log (content_id);
 | 
			
		||||
 | 
			
		||||
                                        CREATE TABLE sender_key2 (
 | 
			
		||||
                                          _id INTEGER PRIMARY KEY,
 | 
			
		||||
                                          address TEXT NOT NULL,
 | 
			
		||||
                                          device_id INTEGER NOT NULL,
 | 
			
		||||
                                          distribution_id BLOB NOT NULL,
 | 
			
		||||
                                          record BLOB NOT NULL,
 | 
			
		||||
                                          created_timestamp INTEGER NOT NULL,
 | 
			
		||||
                                          UNIQUE(address, device_id, distribution_id)
 | 
			
		||||
                                        ) STRICT;
 | 
			
		||||
                                        INSERT INTO sender_key2 (_id, address, device_id, distribution_id, record, created_timestamp)
 | 
			
		||||
                                          SELECT s._id, (SELECT t.address FROM tmp_mapping_table t WHERE t.uuid = s.uuid) address, s.device_id, s.distribution_id, s.record, s.created_timestamp
 | 
			
		||||
                                          FROM sender_key s
 | 
			
		||||
                                          WHERE address IS NOT NULL;
 | 
			
		||||
                                        DROP TABLE sender_key;
 | 
			
		||||
                                        ALTER TABLE sender_key2 RENAME TO sender_key;
 | 
			
		||||
 | 
			
		||||
                                        CREATE TABLE sender_key_shared2 (
 | 
			
		||||
                                          _id INTEGER PRIMARY KEY,
 | 
			
		||||
                                          address TEXT NOT NULL,
 | 
			
		||||
                                          device_id INTEGER NOT NULL,
 | 
			
		||||
                                          distribution_id BLOB NOT NULL,
 | 
			
		||||
                                          timestamp INTEGER NOT NULL,
 | 
			
		||||
                                          UNIQUE(address, device_id, distribution_id)
 | 
			
		||||
                                        ) STRICT;
 | 
			
		||||
                                        INSERT INTO sender_key_shared2 (_id, address, device_id, distribution_id, timestamp)
 | 
			
		||||
                                          SELECT s._id, (SELECT t.address FROM tmp_mapping_table t WHERE t.uuid = s.uuid) address, s.device_id, s.distribution_id, s.timestamp
 | 
			
		||||
                                          FROM sender_key_shared s
 | 
			
		||||
                                          WHERE address IS NOT NULL;
 | 
			
		||||
                                        DROP TABLE sender_key_shared;
 | 
			
		||||
                                        ALTER TABLE sender_key_shared2 RENAME TO sender_key_shared;
 | 
			
		||||
 | 
			
		||||
                                        CREATE TABLE session2 (
 | 
			
		||||
                                          _id INTEGER PRIMARY KEY,
 | 
			
		||||
                                          account_id_type INTEGER NOT NULL,
 | 
			
		||||
                                          address TEXT NOT NULL,
 | 
			
		||||
                                          device_id INTEGER NOT NULL,
 | 
			
		||||
                                          record BLOB NOT NULL,
 | 
			
		||||
                                          UNIQUE(account_id_type, address, device_id)
 | 
			
		||||
                                        ) STRICT;
 | 
			
		||||
                                        INSERT INTO session2 (_id, account_id_type, address, device_id, record)
 | 
			
		||||
                                          SELECT s._id, s.account_id_type, (SELECT t.address FROM tmp_mapping_table t WHERE t.uuid = s.uuid) address, s.device_id, s.record
 | 
			
		||||
                                          FROM session s
 | 
			
		||||
                                          WHERE address IS NOT NULL;
 | 
			
		||||
                                        DROP TABLE session;
 | 
			
		||||
                                        ALTER TABLE session2 RENAME TO session;
 | 
			
		||||
 | 
			
		||||
                                        DROP TABLE tmp_mapping_table;
 | 
			
		||||
                                        """);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1841,8 +1841,7 @@ public class SignalAccount implements Closeable {
 | 
			
		||||
 | 
			
		||||
        public SignalIdentityKeyStore getIdentityKeyStore() {
 | 
			
		||||
            return getOrCreate(() -> identityKeyStore,
 | 
			
		||||
                    () -> identityKeyStore = new SignalIdentityKeyStore(getRecipientResolver(),
 | 
			
		||||
                            () -> identityKeyPair,
 | 
			
		||||
                    () -> identityKeyStore = new SignalIdentityKeyStore(() -> identityKeyPair,
 | 
			
		||||
                            localRegistrationId,
 | 
			
		||||
                            SignalAccount.this.getIdentityKeyStore()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -56,7 +56,7 @@ public class Utils {
 | 
			
		||||
        return node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static RecipientAddress getRecipientAddressFromIdentifier(final String identifier) {
 | 
			
		||||
    public static RecipientAddress getRecipientAddressFromLegacyIdentifier(final String identifier) {
 | 
			
		||||
        if (UuidUtil.isUuid(identifier)) {
 | 
			
		||||
            return new RecipientAddress(ServiceId.parseOrThrow(identifier));
 | 
			
		||||
        } else {
 | 
			
		||||
 | 
			
		||||
@ -6,26 +6,26 @@ import org.whispersystems.signalservice.api.push.ServiceId;
 | 
			
		||||
 | 
			
		||||
public class IdentityInfo {
 | 
			
		||||
 | 
			
		||||
    private final String name;
 | 
			
		||||
    private final String address;
 | 
			
		||||
    private final IdentityKey identityKey;
 | 
			
		||||
    private final TrustLevel trustLevel;
 | 
			
		||||
    private final long addedTimestamp;
 | 
			
		||||
 | 
			
		||||
    IdentityInfo(
 | 
			
		||||
            final String name, IdentityKey identityKey, TrustLevel trustLevel, long addedTimestamp
 | 
			
		||||
            final String address, IdentityKey identityKey, TrustLevel trustLevel, long addedTimestamp
 | 
			
		||||
    ) {
 | 
			
		||||
        this.name = name;
 | 
			
		||||
        this.address = address;
 | 
			
		||||
        this.identityKey = identityKey;
 | 
			
		||||
        this.trustLevel = trustLevel;
 | 
			
		||||
        this.addedTimestamp = addedTimestamp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ServiceId getServiceId() {
 | 
			
		||||
        return ServiceId.parseOrThrow(name);
 | 
			
		||||
        return ServiceId.parseOrThrow(address);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        return name;
 | 
			
		||||
    public String getAddress() {
 | 
			
		||||
        return address;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public IdentityKey getIdentityKey() {
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ public class IdentityKeyStore {
 | 
			
		||||
            statement.executeUpdate("""
 | 
			
		||||
                                    CREATE TABLE identity (
 | 
			
		||||
                                      _id INTEGER PRIMARY KEY,
 | 
			
		||||
                                      uuid BLOB UNIQUE NOT NULL,
 | 
			
		||||
                                      address TEXT UNIQUE NOT NULL,
 | 
			
		||||
                                      identity_key BLOB NOT NULL,
 | 
			
		||||
                                      added_timestamp INTEGER NOT NULL,
 | 
			
		||||
                                      trust_level INTEGER NOT NULL
 | 
			
		||||
@ -56,18 +56,22 @@ public class IdentityKeyStore {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean saveIdentity(final ServiceId serviceId, final IdentityKey identityKey) {
 | 
			
		||||
        return saveIdentity(serviceId.toString(), identityKey);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boolean saveIdentity(final String address, final IdentityKey identityKey) {
 | 
			
		||||
        if (isRetryingDecryption) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            final var identityInfo = loadIdentity(connection, serviceId);
 | 
			
		||||
            final var identityInfo = loadIdentity(connection, address);
 | 
			
		||||
            if (identityInfo != null && identityInfo.getIdentityKey().equals(identityKey)) {
 | 
			
		||||
                // Identity already exists, not updating the trust level
 | 
			
		||||
                logger.trace("Not storing new identity for recipient {}, identity already stored", serviceId);
 | 
			
		||||
                logger.trace("Not storing new identity for recipient {}, identity already stored", address);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            saveNewIdentity(connection, serviceId, identityKey, identityInfo == null);
 | 
			
		||||
            saveNewIdentity(connection, address, identityKey, identityInfo == null);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
            throw new RuntimeException("Failed update identity store", e);
 | 
			
		||||
@ -80,7 +84,8 @@ public class IdentityKeyStore {
 | 
			
		||||
 | 
			
		||||
    public boolean setIdentityTrustLevel(ServiceId serviceId, IdentityKey identityKey, TrustLevel trustLevel) {
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            final var identityInfo = loadIdentity(connection, serviceId);
 | 
			
		||||
            final var address = serviceId.toString();
 | 
			
		||||
            final var identityInfo = loadIdentity(connection, address);
 | 
			
		||||
            if (identityInfo == null) {
 | 
			
		||||
                logger.debug("Not updating trust level for recipient {}, identity not found", serviceId);
 | 
			
		||||
                return false;
 | 
			
		||||
@ -95,7 +100,7 @@ public class IdentityKeyStore {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            logger.debug("Updating trust level for recipient {} with trust {}", serviceId, trustLevel);
 | 
			
		||||
            final var newIdentityInfo = new IdentityInfo(serviceId,
 | 
			
		||||
            final var newIdentityInfo = new IdentityInfo(address,
 | 
			
		||||
                    identityKey,
 | 
			
		||||
                    trustLevel,
 | 
			
		||||
                    identityInfo.getDateAddedTimestamp());
 | 
			
		||||
@ -107,31 +112,35 @@ public class IdentityKeyStore {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isTrustedIdentity(ServiceId serviceId, IdentityKey identityKey, Direction direction) {
 | 
			
		||||
        return isTrustedIdentity(serviceId.toString(), identityKey, direction);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isTrustedIdentity(String address, IdentityKey identityKey, Direction direction) {
 | 
			
		||||
        if (trustNewIdentity == TrustNewIdentity.ALWAYS) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            // TODO implement possibility for different handling of incoming/outgoing trust decisions
 | 
			
		||||
            var identityInfo = loadIdentity(connection, serviceId);
 | 
			
		||||
            var identityInfo = loadIdentity(connection, address);
 | 
			
		||||
            if (identityInfo == null) {
 | 
			
		||||
                logger.debug("Initial identity found for {}, saving.", serviceId);
 | 
			
		||||
                saveNewIdentity(connection, serviceId, identityKey, true);
 | 
			
		||||
                identityInfo = loadIdentity(connection, serviceId);
 | 
			
		||||
                logger.debug("Initial identity found for {}, saving.", address);
 | 
			
		||||
                saveNewIdentity(connection, address, identityKey, true);
 | 
			
		||||
                identityInfo = loadIdentity(connection, address);
 | 
			
		||||
            } else if (!identityInfo.getIdentityKey().equals(identityKey)) {
 | 
			
		||||
                // Identity found, but different
 | 
			
		||||
                if (direction == Direction.SENDING) {
 | 
			
		||||
                    logger.debug("Changed identity found for {}, saving.", serviceId);
 | 
			
		||||
                    saveNewIdentity(connection, serviceId, identityKey, false);
 | 
			
		||||
                    identityInfo = loadIdentity(connection, serviceId);
 | 
			
		||||
                    logger.debug("Changed identity found for {}, saving.", address);
 | 
			
		||||
                    saveNewIdentity(connection, address, identityKey, false);
 | 
			
		||||
                    identityInfo = loadIdentity(connection, address);
 | 
			
		||||
                } else {
 | 
			
		||||
                    logger.trace("Trusting identity for {} for {}: {}", serviceId, direction, false);
 | 
			
		||||
                    logger.trace("Trusting identity for {} for {}: {}", address, direction, false);
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            final var isTrusted = identityInfo != null && identityInfo.isTrusted();
 | 
			
		||||
            logger.trace("Trusting identity for {} for {}: {}", serviceId, direction, isTrusted);
 | 
			
		||||
            logger.trace("Trusting identity for {} for {}: {}", address, direction, isTrusted);
 | 
			
		||||
            return isTrusted;
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
            throw new RuntimeException("Failed read from identity store", e);
 | 
			
		||||
@ -139,8 +148,12 @@ public class IdentityKeyStore {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public IdentityInfo getIdentityInfo(ServiceId serviceId) {
 | 
			
		||||
        return getIdentityInfo(serviceId.toString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public IdentityInfo getIdentityInfo(String address) {
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            return loadIdentity(connection, serviceId);
 | 
			
		||||
            return loadIdentity(connection, address);
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
            throw new RuntimeException("Failed read from identity store", e);
 | 
			
		||||
        }
 | 
			
		||||
@ -150,7 +163,7 @@ public class IdentityKeyStore {
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            final var sql = (
 | 
			
		||||
                    """
 | 
			
		||||
                    SELECT i.uuid, i.identity_key, i.added_timestamp, i.trust_level
 | 
			
		||||
                    SELECT i.address, i.identity_key, i.added_timestamp, i.trust_level
 | 
			
		||||
                    FROM %s AS i
 | 
			
		||||
                    """
 | 
			
		||||
            ).formatted(TABLE_IDENTITY);
 | 
			
		||||
@ -166,7 +179,7 @@ public class IdentityKeyStore {
 | 
			
		||||
 | 
			
		||||
    public void deleteIdentity(final ServiceId serviceId) {
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            deleteIdentity(connection, serviceId);
 | 
			
		||||
            deleteIdentity(connection, serviceId.toString());
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
            throw new RuntimeException("Failed update identity store", e);
 | 
			
		||||
        }
 | 
			
		||||
@ -188,34 +201,37 @@ public class IdentityKeyStore {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private IdentityInfo loadIdentity(
 | 
			
		||||
            final Connection connection, final ServiceId serviceId
 | 
			
		||||
            final Connection connection, final String address
 | 
			
		||||
    ) throws SQLException {
 | 
			
		||||
        final var sql = (
 | 
			
		||||
                """
 | 
			
		||||
                SELECT i.uuid, i.identity_key, i.added_timestamp, i.trust_level
 | 
			
		||||
                SELECT i.address, i.identity_key, i.added_timestamp, i.trust_level
 | 
			
		||||
                FROM %s AS i
 | 
			
		||||
                WHERE i.uuid = ?
 | 
			
		||||
                WHERE i.address = ?
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_IDENTITY);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
            statement.setBytes(1, serviceId.toByteArray());
 | 
			
		||||
            statement.setString(1, address);
 | 
			
		||||
            return Utils.executeQueryForOptional(statement, this::getIdentityInfoFromResultSet).orElse(null);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void saveNewIdentity(
 | 
			
		||||
            final Connection connection,
 | 
			
		||||
            final ServiceId serviceId,
 | 
			
		||||
            final String address,
 | 
			
		||||
            final IdentityKey identityKey,
 | 
			
		||||
            final boolean firstIdentity
 | 
			
		||||
    ) throws SQLException {
 | 
			
		||||
        final var trustLevel = trustNewIdentity == TrustNewIdentity.ALWAYS || (
 | 
			
		||||
                trustNewIdentity == TrustNewIdentity.ON_FIRST_USE && firstIdentity
 | 
			
		||||
        ) ? TrustLevel.TRUSTED_UNVERIFIED : TrustLevel.UNTRUSTED;
 | 
			
		||||
        logger.debug("Storing new identity for recipient {} with trust {}", serviceId, trustLevel);
 | 
			
		||||
        final var newIdentityInfo = new IdentityInfo(serviceId, identityKey, trustLevel, System.currentTimeMillis());
 | 
			
		||||
        logger.debug("Storing new identity for recipient {} with trust {}", address, trustLevel);
 | 
			
		||||
        final var newIdentityInfo = new IdentityInfo(address, identityKey, trustLevel, System.currentTimeMillis());
 | 
			
		||||
        storeIdentity(connection, newIdentityInfo);
 | 
			
		||||
        identityChanges.onNext(serviceId);
 | 
			
		||||
        final var serviceId = ServiceId.parseOrNull(address);
 | 
			
		||||
        if (serviceId != null) {
 | 
			
		||||
            identityChanges.onNext(serviceId);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void storeIdentity(final Connection connection, final IdentityInfo identityInfo) throws SQLException {
 | 
			
		||||
@ -225,12 +241,12 @@ public class IdentityKeyStore {
 | 
			
		||||
                identityInfo.getDateAddedTimestamp());
 | 
			
		||||
        final var sql = (
 | 
			
		||||
                """
 | 
			
		||||
                INSERT OR REPLACE INTO %s (uuid, identity_key, added_timestamp, trust_level)
 | 
			
		||||
                INSERT OR REPLACE INTO %s (address, identity_key, added_timestamp, trust_level)
 | 
			
		||||
                VALUES (?, ?, ?, ?)
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_IDENTITY);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
            statement.setBytes(1, identityInfo.getServiceId().toByteArray());
 | 
			
		||||
            statement.setString(1, identityInfo.getAddress());
 | 
			
		||||
            statement.setBytes(2, identityInfo.getIdentityKey().serialize());
 | 
			
		||||
            statement.setLong(3, identityInfo.getDateAddedTimestamp());
 | 
			
		||||
            statement.setInt(4, identityInfo.getTrustLevel().ordinal());
 | 
			
		||||
@ -238,27 +254,27 @@ public class IdentityKeyStore {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void deleteIdentity(final Connection connection, final ServiceId serviceId) throws SQLException {
 | 
			
		||||
    private void deleteIdentity(final Connection connection, final String address) throws SQLException {
 | 
			
		||||
        final var sql = (
 | 
			
		||||
                """
 | 
			
		||||
                DELETE FROM %s AS i
 | 
			
		||||
                WHERE i.uuid = ?
 | 
			
		||||
                WHERE i.address = ?
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_IDENTITY);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
            statement.setBytes(1, serviceId.toByteArray());
 | 
			
		||||
            statement.setString(1, address);
 | 
			
		||||
            statement.executeUpdate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private IdentityInfo getIdentityInfoFromResultSet(ResultSet resultSet) throws SQLException {
 | 
			
		||||
        try {
 | 
			
		||||
            final var serviceId = ServiceId.parseOrThrow(resultSet.getBytes("uuid"));
 | 
			
		||||
            final var address = resultSet.getString("address");
 | 
			
		||||
            final var id = new IdentityKey(resultSet.getBytes("identity_key"));
 | 
			
		||||
            final var trustLevel = TrustLevel.fromInt(resultSet.getInt("trust_level"));
 | 
			
		||||
            final var added = resultSet.getLong("added_timestamp");
 | 
			
		||||
 | 
			
		||||
            return new IdentityInfo(serviceId, id, trustLevel, added);
 | 
			
		||||
            return new IdentityInfo(address, id, trustLevel, added);
 | 
			
		||||
        } catch (InvalidKeyException e) {
 | 
			
		||||
            logger.warn("Failed to load identity key, resetting: {}", e.getMessage());
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
@ -84,7 +84,7 @@ public class LegacyIdentityKeyStore {
 | 
			
		||||
            var added = storage.addedTimestamp();
 | 
			
		||||
 | 
			
		||||
            final var serviceId = address.serviceId().get();
 | 
			
		||||
            return new IdentityInfo(serviceId, id, trustLevel, added);
 | 
			
		||||
            return new IdentityInfo(serviceId.toString(), id, trustLevel, added);
 | 
			
		||||
        } catch (IOException | InvalidKeyException e) {
 | 
			
		||||
            logger.warn("Failed to load identity key: {}", e.getMessage());
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,8 @@
 | 
			
		||||
package org.asamk.signal.manager.storage.identities;
 | 
			
		||||
 | 
			
		||||
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
 | 
			
		||||
import org.signal.libsignal.protocol.IdentityKey;
 | 
			
		||||
import org.signal.libsignal.protocol.IdentityKeyPair;
 | 
			
		||||
import org.signal.libsignal.protocol.SignalProtocolAddress;
 | 
			
		||||
import org.whispersystems.signalservice.api.push.ServiceId;
 | 
			
		||||
 | 
			
		||||
import java.util.function.Supplier;
 | 
			
		||||
 | 
			
		||||
@ -15,7 +13,6 @@ public class SignalIdentityKeyStore implements org.signal.libsignal.protocol.sta
 | 
			
		||||
    private final IdentityKeyStore identityKeyStore;
 | 
			
		||||
 | 
			
		||||
    public SignalIdentityKeyStore(
 | 
			
		||||
            final RecipientResolver resolver,
 | 
			
		||||
            final Supplier<IdentityKeyPair> identityKeyPairSupplier,
 | 
			
		||||
            final int localRegistrationId,
 | 
			
		||||
            final IdentityKeyStore identityKeyStore
 | 
			
		||||
@ -37,22 +34,17 @@ public class SignalIdentityKeyStore implements org.signal.libsignal.protocol.sta
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey) {
 | 
			
		||||
        final var serviceId = ServiceId.parseOrThrow(address.getName());
 | 
			
		||||
 | 
			
		||||
        return identityKeyStore.saveIdentity(serviceId, identityKey);
 | 
			
		||||
        return identityKeyStore.saveIdentity(address.getName(), identityKey);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) {
 | 
			
		||||
        final var serviceId = ServiceId.parseOrThrow(address.getName());
 | 
			
		||||
 | 
			
		||||
        return identityKeyStore.isTrustedIdentity(serviceId, identityKey, direction);
 | 
			
		||||
        return identityKeyStore.isTrustedIdentity(address.getName(), identityKey, direction);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public IdentityKey getIdentity(SignalProtocolAddress address) {
 | 
			
		||||
        final var serviceId = ServiceId.parseOrThrow(address.getName());
 | 
			
		||||
        final var identityInfo = identityKeyStore.getIdentityInfo(serviceId);
 | 
			
		||||
        final var identityInfo = identityKeyStore.getIdentityInfo(address.getName());
 | 
			
		||||
        return identityInfo == null ? null : identityInfo.getIdentityKey();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -100,7 +100,7 @@ public class LegacyJsonIdentityKeyStore {
 | 
			
		||||
                            ? UuidUtil.parseOrNull(trustedKey.get("uuid").asText())
 | 
			
		||||
                            : null;
 | 
			
		||||
                    final var address = uuid == null
 | 
			
		||||
                            ? Utils.getRecipientAddressFromIdentifier(trustedKeyName)
 | 
			
		||||
                            ? Utils.getRecipientAddressFromLegacyIdentifier(trustedKeyName)
 | 
			
		||||
                            : new RecipientAddress(ACI.from(uuid), trustedKeyName);
 | 
			
		||||
                    try {
 | 
			
		||||
                        var id = new IdentityKey(Base64.getDecoder().decode(trustedKey.get("identityKey").asText()), 0);
 | 
			
		||||
 | 
			
		||||
@ -47,7 +47,7 @@ public class LegacyJsonSessionStore {
 | 
			
		||||
 | 
			
		||||
                    var uuid = session.hasNonNull("uuid") ? UuidUtil.parseOrNull(session.get("uuid").asText()) : null;
 | 
			
		||||
                    final var address = uuid == null
 | 
			
		||||
                            ? Utils.getRecipientAddressFromIdentifier(sessionName)
 | 
			
		||||
                            ? Utils.getRecipientAddressFromLegacyIdentifier(sessionName)
 | 
			
		||||
                            : new RecipientAddress(ACI.from(uuid), sessionName);
 | 
			
		||||
                    final var deviceId = session.get("deviceId").asInt();
 | 
			
		||||
                    final var record = Base64.getDecoder().decode(session.get("record").asText());
 | 
			
		||||
 | 
			
		||||
@ -151,8 +151,9 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public RecipientId resolveRecipient(final String identifier) {
 | 
			
		||||
        if (UuidUtil.isUuid(identifier)) {
 | 
			
		||||
            return resolveRecipient(ServiceId.parseOrThrow(identifier));
 | 
			
		||||
        final var serviceId = ServiceId.parseOrNull(identifier);
 | 
			
		||||
        if (serviceId != null) {
 | 
			
		||||
            return resolveRecipient(serviceId);
 | 
			
		||||
        } else {
 | 
			
		||||
            return resolveRecipientByNumber(identifier);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -67,7 +67,7 @@ public class MessageSendLogStore implements AutoCloseable {
 | 
			
		||||
                                    CREATE TABLE message_send_log (
 | 
			
		||||
                                      _id INTEGER PRIMARY KEY,
 | 
			
		||||
                                      content_id INTEGER NOT NULL REFERENCES message_send_log_content (_id) ON DELETE CASCADE,
 | 
			
		||||
                                      uuid BLOB NOT NULL,
 | 
			
		||||
                                      address TEXT NOT NULL,
 | 
			
		||||
                                      device_id INTEGER NOT NULL
 | 
			
		||||
                                    ) STRICT;
 | 
			
		||||
                                    CREATE TABLE message_send_log_content (
 | 
			
		||||
@ -79,7 +79,7 @@ public class MessageSendLogStore implements AutoCloseable {
 | 
			
		||||
                                      urgent INTEGER NOT NULL
 | 
			
		||||
                                    ) STRICT;
 | 
			
		||||
                                    CREATE INDEX mslc_timestamp_index ON message_send_log_content (timestamp);
 | 
			
		||||
                                    CREATE INDEX msl_recipient_index ON message_send_log (uuid, device_id, content_id);
 | 
			
		||||
                                    CREATE INDEX msl_recipient_index ON message_send_log (address, device_id, content_id);
 | 
			
		||||
                                    CREATE INDEX msl_content_index ON message_send_log (content_id);
 | 
			
		||||
                                    """);
 | 
			
		||||
        }
 | 
			
		||||
@ -92,13 +92,13 @@ public class MessageSendLogStore implements AutoCloseable {
 | 
			
		||||
                        SELECT group_id, content, content_hint, urgent
 | 
			
		||||
                        FROM %s l
 | 
			
		||||
                             INNER JOIN %s lc ON l.content_id = lc._id
 | 
			
		||||
                        WHERE l.uuid = ? AND l.device_id = ? AND lc.timestamp = ?
 | 
			
		||||
                        WHERE l.address = ? AND l.device_id = ? AND lc.timestamp = ?
 | 
			
		||||
                        """.formatted(TABLE_MESSAGE_SEND_LOG, TABLE_MESSAGE_SEND_LOG_CONTENT);
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            deleteOutdatedEntries(connection);
 | 
			
		||||
 | 
			
		||||
            try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
                statement.setBytes(1, serviceId.toByteArray());
 | 
			
		||||
                statement.setString(1, serviceId.toString());
 | 
			
		||||
                statement.setInt(2, deviceId);
 | 
			
		||||
                statement.setLong(3, timestamp);
 | 
			
		||||
                try (var result = Utils.executeQueryForStream(statement, this::getMessageSendLogEntryFromResultSet)) {
 | 
			
		||||
@ -202,13 +202,13 @@ public class MessageSendLogStore implements AutoCloseable {
 | 
			
		||||
    public void deleteEntryForRecipientNonGroup(long sentTimestamp, ServiceId serviceId) {
 | 
			
		||||
        final var sql = """
 | 
			
		||||
                        DELETE FROM %s AS lc
 | 
			
		||||
                        WHERE lc.timestamp = ? AND lc.group_id IS NULL AND lc._id IN (SELECT content_id FROM %s l WHERE l.uuid = ?)
 | 
			
		||||
                        WHERE lc.timestamp = ? AND lc.group_id IS NULL AND lc._id IN (SELECT content_id FROM %s l WHERE l.address = ?)
 | 
			
		||||
                        """.formatted(TABLE_MESSAGE_SEND_LOG_CONTENT, TABLE_MESSAGE_SEND_LOG);
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            connection.setAutoCommit(false);
 | 
			
		||||
            try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
                statement.setLong(1, sentTimestamp);
 | 
			
		||||
                statement.setBytes(2, serviceId.toByteArray());
 | 
			
		||||
                statement.setString(2, serviceId.toString());
 | 
			
		||||
                statement.executeUpdate();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -226,14 +226,14 @@ public class MessageSendLogStore implements AutoCloseable {
 | 
			
		||||
    public void deleteEntriesForRecipient(List<Long> sentTimestamps, ServiceId serviceId, int deviceId) {
 | 
			
		||||
        final var sql = """
 | 
			
		||||
                        DELETE FROM %s AS l
 | 
			
		||||
                        WHERE l.content_id IN (SELECT _id FROM %s lc WHERE lc.timestamp = ?) AND l.uuid = ? AND l.device_id = ?
 | 
			
		||||
                        WHERE l.content_id IN (SELECT _id FROM %s lc WHERE lc.timestamp = ?) AND l.address = ? AND l.device_id = ?
 | 
			
		||||
                        """.formatted(TABLE_MESSAGE_SEND_LOG, TABLE_MESSAGE_SEND_LOG_CONTENT);
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            connection.setAutoCommit(false);
 | 
			
		||||
            try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
                for (final var sentTimestamp : sentTimestamps) {
 | 
			
		||||
                    statement.setLong(1, sentTimestamp);
 | 
			
		||||
                    statement.setBytes(2, serviceId.toByteArray());
 | 
			
		||||
                    statement.setString(2, serviceId.toString());
 | 
			
		||||
                    statement.setInt(3, deviceId);
 | 
			
		||||
                    statement.executeUpdate();
 | 
			
		||||
                }
 | 
			
		||||
@ -342,13 +342,13 @@ public class MessageSendLogStore implements AutoCloseable {
 | 
			
		||||
            final long contentId, final List<RecipientDevices> recipientDevices, final Connection connection
 | 
			
		||||
    ) throws SQLException {
 | 
			
		||||
        final var sql = """
 | 
			
		||||
                        INSERT INTO %s (uuid, device_id, content_id)
 | 
			
		||||
                        INSERT INTO %s (address, device_id, content_id)
 | 
			
		||||
                        VALUES (?,?,?)
 | 
			
		||||
                        """.formatted(TABLE_MESSAGE_SEND_LOG);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
            for (final var recipientDevice : recipientDevices) {
 | 
			
		||||
                for (final var deviceId : recipientDevice.deviceIds()) {
 | 
			
		||||
                    statement.setBytes(1, recipientDevice.serviceId().toByteArray());
 | 
			
		||||
                    statement.setString(1, recipientDevice.serviceId().toString());
 | 
			
		||||
                    statement.setInt(2, deviceId);
 | 
			
		||||
                    statement.setLong(3, contentId);
 | 
			
		||||
                    statement.executeUpdate();
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,9 @@ public class LegacySenderKeyRecordStore {
 | 
			
		||||
            if (record == null || serviceId.isEmpty()) {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
            return new Pair<>(new SenderKeyRecordStore.Key(serviceId.get(), key.deviceId, key.distributionId), record);
 | 
			
		||||
            return new Pair<>(new SenderKeyRecordStore.Key(serviceId.get().toString(),
 | 
			
		||||
                    key.deviceId,
 | 
			
		||||
                    key.distributionId), record);
 | 
			
		||||
        }).filter(Objects::nonNull).toList();
 | 
			
		||||
 | 
			
		||||
        senderKeyStore.addLegacySenderKeys(senderKeys);
 | 
			
		||||
 | 
			
		||||
@ -40,7 +40,7 @@ public class LegacySenderKeySharedStore {
 | 
			
		||||
                if (serviceId.isEmpty()) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                final var entry = new SenderKeySharedEntry(serviceId.get(), senderKey.deviceId);
 | 
			
		||||
                final var entry = new SenderKeySharedEntry(serviceId.get().toString(), senderKey.deviceId);
 | 
			
		||||
                final var distributionId = DistributionId.from(senderKey.distributionId);
 | 
			
		||||
                var entries = sharedSenderKeys.get(distributionId);
 | 
			
		||||
                if (entries == null) {
 | 
			
		||||
 | 
			
		||||
@ -31,12 +31,12 @@ public class SenderKeyRecordStore implements SenderKeyStore {
 | 
			
		||||
            statement.executeUpdate("""
 | 
			
		||||
                                    CREATE TABLE sender_key (
 | 
			
		||||
                                      _id INTEGER PRIMARY KEY,
 | 
			
		||||
                                      uuid BLOB NOT NULL,
 | 
			
		||||
                                      address TEXT NOT NULL,
 | 
			
		||||
                                      device_id INTEGER NOT NULL,
 | 
			
		||||
                                      distribution_id BLOB NOT NULL,
 | 
			
		||||
                                      record BLOB NOT NULL,
 | 
			
		||||
                                      created_timestamp INTEGER NOT NULL,
 | 
			
		||||
                                      UNIQUE(uuid, device_id, distribution_id)
 | 
			
		||||
                                      UNIQUE(address, device_id, distribution_id)
 | 
			
		||||
                                    ) STRICT;
 | 
			
		||||
                                    """);
 | 
			
		||||
        }
 | 
			
		||||
@ -75,12 +75,12 @@ public class SenderKeyRecordStore implements SenderKeyStore {
 | 
			
		||||
                """
 | 
			
		||||
                SELECT s.created_timestamp
 | 
			
		||||
                FROM %s AS s
 | 
			
		||||
                WHERE s.uuid = ? AND s.device_id = ? AND s.distribution_id = ?
 | 
			
		||||
                WHERE s.address = ? AND s.device_id = ? AND s.distribution_id = ?
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_SENDER_KEY);
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
                statement.setBytes(1, selfServiceId.toByteArray());
 | 
			
		||||
                statement.setString(1, selfServiceId.toString());
 | 
			
		||||
                statement.setInt(2, selfDeviceId);
 | 
			
		||||
                statement.setBytes(3, UuidUtil.toByteArray(distributionId));
 | 
			
		||||
                return Utils.executeQueryForOptional(statement, res -> res.getLong("created_timestamp")).orElse(-1L);
 | 
			
		||||
@ -94,12 +94,12 @@ public class SenderKeyRecordStore implements SenderKeyStore {
 | 
			
		||||
        final var sql = (
 | 
			
		||||
                """
 | 
			
		||||
                DELETE FROM %s AS s
 | 
			
		||||
                WHERE s.uuid = ? AND s.distribution_id = ?
 | 
			
		||||
                WHERE s.address = ? AND s.distribution_id = ?
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_SENDER_KEY);
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
                statement.setBytes(1, serviceId.toByteArray());
 | 
			
		||||
                statement.setString(1, serviceId.toString());
 | 
			
		||||
                statement.setBytes(2, UuidUtil.toByteArray(distributionId));
 | 
			
		||||
                statement.executeUpdate();
 | 
			
		||||
            }
 | 
			
		||||
@ -145,8 +145,7 @@ public class SenderKeyRecordStore implements SenderKeyStore {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Key getKey(final SignalProtocolAddress address, final UUID distributionId) {
 | 
			
		||||
        final var serviceId = ServiceId.parseOrThrow(address.getName());
 | 
			
		||||
        return new Key(serviceId, address.getDeviceId(), distributionId);
 | 
			
		||||
        return new Key(address.getName(), address.getDeviceId(), distributionId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private SenderKeyRecord loadSenderKey(final Connection connection, final Key key) throws SQLException {
 | 
			
		||||
@ -154,11 +153,11 @@ public class SenderKeyRecordStore implements SenderKeyStore {
 | 
			
		||||
                """
 | 
			
		||||
                SELECT s.record
 | 
			
		||||
                FROM %s AS s
 | 
			
		||||
                WHERE s.uuid = ? AND s.device_id = ? AND s.distribution_id = ?
 | 
			
		||||
                WHERE s.address = ? AND s.device_id = ? AND s.distribution_id = ?
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_SENDER_KEY);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
            statement.setBytes(1, key.serviceId().toByteArray());
 | 
			
		||||
            statement.setString(1, key.address());
 | 
			
		||||
            statement.setInt(2, key.deviceId());
 | 
			
		||||
            statement.setBytes(3, UuidUtil.toByteArray(key.distributionId()));
 | 
			
		||||
            return Utils.executeQueryForOptional(statement, this::getSenderKeyRecordFromResultSet).orElse(null);
 | 
			
		||||
@ -171,11 +170,11 @@ public class SenderKeyRecordStore implements SenderKeyStore {
 | 
			
		||||
        final var sqlUpdate = """
 | 
			
		||||
                              UPDATE %s
 | 
			
		||||
                              SET record = ?
 | 
			
		||||
                              WHERE uuid = ? AND device_id = ? and distribution_id = ?
 | 
			
		||||
                              WHERE address = ? AND device_id = ? and distribution_id = ?
 | 
			
		||||
                              """.formatted(TABLE_SENDER_KEY);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sqlUpdate)) {
 | 
			
		||||
            statement.setBytes(1, senderKeyRecord.serialize());
 | 
			
		||||
            statement.setBytes(2, key.serviceId().toByteArray());
 | 
			
		||||
            statement.setString(2, key.address());
 | 
			
		||||
            statement.setLong(3, key.deviceId());
 | 
			
		||||
            statement.setBytes(4, UuidUtil.toByteArray(key.distributionId()));
 | 
			
		||||
            final var rows = statement.executeUpdate();
 | 
			
		||||
@ -187,12 +186,12 @@ public class SenderKeyRecordStore implements SenderKeyStore {
 | 
			
		||||
        // Record doesn't exist yet, creating a new one
 | 
			
		||||
        final var sqlInsert = (
 | 
			
		||||
                """
 | 
			
		||||
                INSERT OR REPLACE INTO %s (uuid, device_id, distribution_id, record, created_timestamp)
 | 
			
		||||
                INSERT OR REPLACE INTO %s (address, device_id, distribution_id, record, created_timestamp)
 | 
			
		||||
                VALUES (?, ?, ?, ?, ?)
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_SENDER_KEY);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sqlInsert)) {
 | 
			
		||||
            statement.setBytes(1, key.serviceId().toByteArray());
 | 
			
		||||
            statement.setString(1, key.address());
 | 
			
		||||
            statement.setInt(2, key.deviceId());
 | 
			
		||||
            statement.setBytes(3, UuidUtil.toByteArray(key.distributionId()));
 | 
			
		||||
            statement.setBytes(4, senderKeyRecord.serialize());
 | 
			
		||||
@ -205,11 +204,11 @@ public class SenderKeyRecordStore implements SenderKeyStore {
 | 
			
		||||
        final var sql = (
 | 
			
		||||
                """
 | 
			
		||||
                DELETE FROM %s AS s
 | 
			
		||||
                WHERE s.uuid = ?
 | 
			
		||||
                WHERE s.address = ?
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_SENDER_KEY);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
            statement.setBytes(1, serviceId.toByteArray());
 | 
			
		||||
            statement.setString(1, serviceId.toString());
 | 
			
		||||
            statement.executeUpdate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -225,5 +224,5 @@ public class SenderKeyRecordStore implements SenderKeyStore {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    record Key(ServiceId serviceId, int deviceId, UUID distributionId) {}
 | 
			
		||||
    record Key(String address, int deviceId, UUID distributionId) {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -30,11 +30,11 @@ public class SenderKeySharedStore {
 | 
			
		||||
            statement.executeUpdate("""
 | 
			
		||||
                                    CREATE TABLE sender_key_shared (
 | 
			
		||||
                                      _id INTEGER PRIMARY KEY,
 | 
			
		||||
                                      uuid BLOB NOT NULL,
 | 
			
		||||
                                      address TEXT NOT NULL,
 | 
			
		||||
                                      device_id INTEGER NOT NULL,
 | 
			
		||||
                                      distribution_id BLOB NOT NULL,
 | 
			
		||||
                                      timestamp INTEGER NOT NULL,
 | 
			
		||||
                                      UNIQUE(uuid, device_id, distribution_id)
 | 
			
		||||
                                      UNIQUE(address, device_id, distribution_id)
 | 
			
		||||
                                    ) STRICT;
 | 
			
		||||
                                    """);
 | 
			
		||||
        }
 | 
			
		||||
@ -48,7 +48,7 @@ public class SenderKeySharedStore {
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            final var sql = (
 | 
			
		||||
                    """
 | 
			
		||||
                    SELECT s.uuid, s.device_id
 | 
			
		||||
                    SELECT s.address, s.device_id
 | 
			
		||||
                    FROM %s AS s
 | 
			
		||||
                    WHERE s.distribution_id = ?
 | 
			
		||||
                    """
 | 
			
		||||
@ -56,7 +56,7 @@ public class SenderKeySharedStore {
 | 
			
		||||
            try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
                statement.setBytes(1, UuidUtil.toByteArray(distributionId.asUuid()));
 | 
			
		||||
                return Utils.executeQueryForStream(statement, this::getSenderKeySharedEntryFromResultSet)
 | 
			
		||||
                        .map(k -> k.serviceId.toProtocolAddress(k.deviceId()))
 | 
			
		||||
                        .map(k -> new SignalProtocolAddress(k.address, k.deviceId()))
 | 
			
		||||
                        .collect(Collectors.toSet());
 | 
			
		||||
            }
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
@ -68,7 +68,7 @@ public class SenderKeySharedStore {
 | 
			
		||||
            final DistributionId distributionId, final Collection<SignalProtocolAddress> addresses
 | 
			
		||||
    ) {
 | 
			
		||||
        final var newEntries = addresses.stream()
 | 
			
		||||
                .map(a -> new SenderKeySharedEntry(ServiceId.parseOrThrow(a.getName()), a.getDeviceId()))
 | 
			
		||||
                .map(a -> new SenderKeySharedEntry(a.getName(), a.getDeviceId()))
 | 
			
		||||
                .collect(Collectors.toSet());
 | 
			
		||||
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
@ -82,8 +82,7 @@ public class SenderKeySharedStore {
 | 
			
		||||
 | 
			
		||||
    public void clearSenderKeySharedWith(final Collection<SignalProtocolAddress> addresses) {
 | 
			
		||||
        final var entriesToDelete = addresses.stream()
 | 
			
		||||
                .filter(a -> UuidUtil.isUuid(a.getName()))
 | 
			
		||||
                .map(a -> new SenderKeySharedEntry(ServiceId.parseOrThrow(a.getName()), a.getDeviceId()))
 | 
			
		||||
                .map(a -> new SenderKeySharedEntry(a.getName(), a.getDeviceId()))
 | 
			
		||||
                .collect(Collectors.toSet());
 | 
			
		||||
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
@ -91,12 +90,12 @@ public class SenderKeySharedStore {
 | 
			
		||||
            final var sql = (
 | 
			
		||||
                    """
 | 
			
		||||
                    DELETE FROM %s AS s
 | 
			
		||||
                    WHERE uuid = ? AND device_id = ?
 | 
			
		||||
                    WHERE address = ? AND device_id = ?
 | 
			
		||||
                    """
 | 
			
		||||
            ).formatted(TABLE_SENDER_KEY_SHARED);
 | 
			
		||||
            try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
                for (final var entry : entriesToDelete) {
 | 
			
		||||
                    statement.setBytes(1, entry.serviceId().toByteArray());
 | 
			
		||||
                    statement.setString(1, entry.address());
 | 
			
		||||
                    statement.setInt(2, entry.deviceId());
 | 
			
		||||
                    statement.executeUpdate();
 | 
			
		||||
                }
 | 
			
		||||
@ -127,11 +126,11 @@ public class SenderKeySharedStore {
 | 
			
		||||
            final var sql = (
 | 
			
		||||
                    """
 | 
			
		||||
                    DELETE FROM %s AS s
 | 
			
		||||
                    WHERE uuid = ?
 | 
			
		||||
                    WHERE address = ?
 | 
			
		||||
                    """
 | 
			
		||||
            ).formatted(TABLE_SENDER_KEY_SHARED);
 | 
			
		||||
            try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
                statement.setBytes(1, serviceId.toByteArray());
 | 
			
		||||
                statement.setString(1, serviceId.toString());
 | 
			
		||||
                statement.executeUpdate();
 | 
			
		||||
            }
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
@ -146,11 +145,11 @@ public class SenderKeySharedStore {
 | 
			
		||||
            final var sql = (
 | 
			
		||||
                    """
 | 
			
		||||
                    DELETE FROM %s AS s
 | 
			
		||||
                    WHERE uuid = ? AND device_id = ? AND distribution_id = ?
 | 
			
		||||
                    WHERE address = ? AND device_id = ? AND distribution_id = ?
 | 
			
		||||
                    """
 | 
			
		||||
            ).formatted(TABLE_SENDER_KEY_SHARED);
 | 
			
		||||
            try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
                statement.setBytes(1, serviceId.toByteArray());
 | 
			
		||||
                statement.setString(1, serviceId.toString());
 | 
			
		||||
                statement.setInt(2, deviceId);
 | 
			
		||||
                statement.setBytes(3, UuidUtil.toByteArray(distributionId.asUuid()));
 | 
			
		||||
                statement.executeUpdate();
 | 
			
		||||
@ -197,13 +196,13 @@ public class SenderKeySharedStore {
 | 
			
		||||
    ) throws SQLException {
 | 
			
		||||
        final var sql = (
 | 
			
		||||
                """
 | 
			
		||||
                INSERT OR REPLACE INTO %s (uuid, device_id, distribution_id, timestamp)
 | 
			
		||||
                INSERT OR REPLACE INTO %s (address, device_id, distribution_id, timestamp)
 | 
			
		||||
                VALUES (?, ?, ?, ?)
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_SENDER_KEY_SHARED);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
            for (final var entry : newEntries) {
 | 
			
		||||
                statement.setBytes(1, entry.serviceId().toByteArray());
 | 
			
		||||
                statement.setString(1, entry.toString());
 | 
			
		||||
                statement.setInt(2, entry.deviceId());
 | 
			
		||||
                statement.setBytes(3, UuidUtil.toByteArray(distributionId.asUuid()));
 | 
			
		||||
                statement.setLong(4, System.currentTimeMillis());
 | 
			
		||||
@ -213,10 +212,10 @@ public class SenderKeySharedStore {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private SenderKeySharedEntry getSenderKeySharedEntryFromResultSet(ResultSet resultSet) throws SQLException {
 | 
			
		||||
        final var serviceId = ServiceId.parseOrThrow(resultSet.getBytes("uuid"));
 | 
			
		||||
        final var address = resultSet.getString("address");
 | 
			
		||||
        final var deviceId = resultSet.getInt("device_id");
 | 
			
		||||
        return new SenderKeySharedEntry(serviceId, deviceId);
 | 
			
		||||
        return new SenderKeySharedEntry(address, deviceId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    record SenderKeySharedEntry(ServiceId serviceId, int deviceId) {}
 | 
			
		||||
    record SenderKeySharedEntry(String address, int deviceId) {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ public class LegacySessionStore {
 | 
			
		||||
            if (record == null || serviceId.isEmpty()) {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
            return new Pair<>(new SessionStore.Key(serviceId.get(), key.deviceId()), record);
 | 
			
		||||
            return new Pair<>(new SessionStore.Key(serviceId.get().toString(), key.deviceId()), record);
 | 
			
		||||
        }).filter(Objects::nonNull).toList();
 | 
			
		||||
        sessionStore.addLegacySessions(sessions);
 | 
			
		||||
        deleteAllSessions(sessionsPath);
 | 
			
		||||
 | 
			
		||||
@ -6,15 +6,12 @@ import org.asamk.signal.manager.storage.Utils;
 | 
			
		||||
import org.signal.libsignal.protocol.NoSessionException;
 | 
			
		||||
import org.signal.libsignal.protocol.SignalProtocolAddress;
 | 
			
		||||
import org.signal.libsignal.protocol.ecc.ECPublicKey;
 | 
			
		||||
import org.signal.libsignal.protocol.message.CiphertextMessage;
 | 
			
		||||
import org.signal.libsignal.protocol.state.SessionRecord;
 | 
			
		||||
import org.signal.libsignal.protocol.util.Hex;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.whispersystems.signalservice.api.SignalServiceSessionStore;
 | 
			
		||||
import org.whispersystems.signalservice.api.push.ServiceId;
 | 
			
		||||
import org.whispersystems.signalservice.api.push.ServiceIdType;
 | 
			
		||||
import org.whispersystems.signalservice.api.util.UuidUtil;
 | 
			
		||||
 | 
			
		||||
import java.sql.Connection;
 | 
			
		||||
import java.sql.ResultSet;
 | 
			
		||||
@ -45,10 +42,10 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
                                    CREATE TABLE session (
 | 
			
		||||
                                      _id INTEGER PRIMARY KEY,
 | 
			
		||||
                                      account_id_type INTEGER NOT NULL,
 | 
			
		||||
                                      uuid BLOB NOT NULL,
 | 
			
		||||
                                      address TEXT NOT NULL,
 | 
			
		||||
                                      device_id INTEGER NOT NULL,
 | 
			
		||||
                                      record BLOB NOT NULL,
 | 
			
		||||
                                      UNIQUE(account_id_type, uuid, device_id)
 | 
			
		||||
                                      UNIQUE(account_id_type, address, device_id)
 | 
			
		||||
                                    ) STRICT;
 | 
			
		||||
                                    """);
 | 
			
		||||
        }
 | 
			
		||||
@ -107,13 +104,13 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
                """
 | 
			
		||||
                SELECT s.device_id
 | 
			
		||||
                FROM %s AS s
 | 
			
		||||
                WHERE s.account_id_type = ? AND s.uuid = ? AND s.device_id != 1
 | 
			
		||||
                WHERE s.account_id_type = ? AND s.address = ? AND s.device_id != 1
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_SESSION);
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
                statement.setInt(1, accountIdType);
 | 
			
		||||
                statement.setBytes(2, serviceId.toByteArray());
 | 
			
		||||
                statement.setString(2, serviceId.toString());
 | 
			
		||||
                return Utils.executeQueryForStream(statement, res -> res.getInt("device_id")).toList();
 | 
			
		||||
            }
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
@ -122,7 +119,7 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isCurrentRatchetKey(ServiceId serviceId, int deviceId, ECPublicKey ratchetKey) {
 | 
			
		||||
        final var key = new Key(serviceId, deviceId);
 | 
			
		||||
        final var key = new Key(serviceId.toString(), deviceId);
 | 
			
		||||
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            final var session = loadSession(connection, key);
 | 
			
		||||
@ -177,7 +174,7 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
 | 
			
		||||
    public void deleteAllSessions(ServiceId serviceId) {
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
            deleteAllSessions(connection, serviceId);
 | 
			
		||||
            deleteAllSessions(connection, serviceId.toString());
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
            throw new RuntimeException("Failed update session store", e);
 | 
			
		||||
        }
 | 
			
		||||
@ -185,10 +182,6 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void archiveSession(final SignalProtocolAddress address) {
 | 
			
		||||
        if (!UuidUtil.isUuid(address.getName())) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        final var key = getKey(address);
 | 
			
		||||
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
@ -207,15 +200,13 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<SignalProtocolAddress> getAllAddressesWithActiveSessions(final List<String> addressNames) {
 | 
			
		||||
        final var serviceIdsCommaSeparated = addressNames.stream()
 | 
			
		||||
                .map(ServiceId::parseOrThrow)
 | 
			
		||||
                .map(ServiceId::toByteArray)
 | 
			
		||||
                .map(uuid -> "x'" + Hex.toStringCondensed(uuid) + "'")
 | 
			
		||||
                .map(address -> "'" + address.replaceAll("'", "''") + "'")
 | 
			
		||||
                .collect(Collectors.joining(","));
 | 
			
		||||
        final var sql = (
 | 
			
		||||
                """
 | 
			
		||||
                SELECT s.uuid, s.device_id, s.record
 | 
			
		||||
                SELECT s.address, s.device_id, s.record
 | 
			
		||||
                FROM %s AS s
 | 
			
		||||
                WHERE s.account_id_type = ? AND s.uuid IN (%s)
 | 
			
		||||
                WHERE s.account_id_type = ? AND s.address IN (%s)
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_SESSION, serviceIdsCommaSeparated);
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
@ -225,7 +216,7 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
                                res -> new Pair<>(getKeyFromResultSet(res), getSessionRecordFromResultSet(res)))
 | 
			
		||||
                        .filter(pair -> isActive(pair.second()))
 | 
			
		||||
                        .map(Pair::first)
 | 
			
		||||
                        .map(key -> key.serviceId().toProtocolAddress(key.deviceId()))
 | 
			
		||||
                        .map(key -> new SignalProtocolAddress(key.address(), key.deviceId()))
 | 
			
		||||
                        .collect(Collectors.toSet());
 | 
			
		||||
            }
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
@ -236,7 +227,7 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
    public void archiveAllSessions() {
 | 
			
		||||
        final var sql = (
 | 
			
		||||
                """
 | 
			
		||||
                SELECT s.uuid, s.device_id, s.record
 | 
			
		||||
                SELECT s.address, s.device_id, s.record
 | 
			
		||||
                FROM %s AS s
 | 
			
		||||
                WHERE s.account_id_type = ?
 | 
			
		||||
                """
 | 
			
		||||
@ -264,9 +255,9 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
    public void archiveSessions(final ServiceId serviceId) {
 | 
			
		||||
        final var sql = (
 | 
			
		||||
                """
 | 
			
		||||
                SELECT s.uuid, s.device_id, s.record
 | 
			
		||||
                SELECT s.address, s.device_id, s.record
 | 
			
		||||
                FROM %s AS s
 | 
			
		||||
                WHERE s.account_id_type = ? AND s.uuid = ?
 | 
			
		||||
                WHERE s.account_id_type = ? AND s.address = ?
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_SESSION);
 | 
			
		||||
        try (final var connection = database.getConnection()) {
 | 
			
		||||
@ -274,7 +265,7 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
            final List<Pair<Key, SessionRecord>> records;
 | 
			
		||||
            try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
                statement.setInt(1, accountIdType);
 | 
			
		||||
                statement.setBytes(2, serviceId.toByteArray());
 | 
			
		||||
                statement.setString(2, serviceId.toString());
 | 
			
		||||
                records = Utils.executeQueryForStream(statement,
 | 
			
		||||
                                res -> new Pair<>(getKeyFromResultSet(res), getSessionRecordFromResultSet(res)))
 | 
			
		||||
                        .filter(Objects::nonNull)
 | 
			
		||||
@ -306,8 +297,7 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Key getKey(final SignalProtocolAddress address) {
 | 
			
		||||
        final var serviceId = ServiceId.parseOrThrow(address.getName());
 | 
			
		||||
        return new Key(serviceId, address.getDeviceId());
 | 
			
		||||
        return new Key(address.getName(), address.getDeviceId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private SessionRecord loadSession(Connection connection, final Key key) throws SQLException {
 | 
			
		||||
@ -321,21 +311,21 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
                """
 | 
			
		||||
                SELECT s.record
 | 
			
		||||
                FROM %s AS s
 | 
			
		||||
                WHERE s.account_id_type = ? AND s.uuid = ? AND s.device_id = ?
 | 
			
		||||
                WHERE s.account_id_type = ? AND s.address = ? AND s.device_id = ?
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_SESSION);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
            statement.setInt(1, accountIdType);
 | 
			
		||||
            statement.setBytes(2, key.serviceId().toByteArray());
 | 
			
		||||
            statement.setString(2, key.address());
 | 
			
		||||
            statement.setInt(3, key.deviceId());
 | 
			
		||||
            return Utils.executeQueryForOptional(statement, this::getSessionRecordFromResultSet).orElse(null);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Key getKeyFromResultSet(ResultSet resultSet) throws SQLException {
 | 
			
		||||
        final var serviceId = ServiceId.parseOrThrow(resultSet.getBytes("uuid"));
 | 
			
		||||
        final var address = resultSet.getString("address");
 | 
			
		||||
        final var deviceId = resultSet.getInt("device_id");
 | 
			
		||||
        return new Key(serviceId, deviceId);
 | 
			
		||||
        return new Key(address, deviceId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private SessionRecord getSessionRecordFromResultSet(ResultSet resultSet) throws SQLException {
 | 
			
		||||
@ -356,19 +346,19 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        final var sql = """
 | 
			
		||||
                        INSERT OR REPLACE INTO %s (account_id_type, uuid, device_id, record)
 | 
			
		||||
                        INSERT OR REPLACE INTO %s (account_id_type, address, device_id, record)
 | 
			
		||||
                        VALUES (?, ?, ?, ?)
 | 
			
		||||
                        """.formatted(TABLE_SESSION);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
            statement.setInt(1, accountIdType);
 | 
			
		||||
            statement.setBytes(2, key.serviceId().toByteArray());
 | 
			
		||||
            statement.setString(2, key.address());
 | 
			
		||||
            statement.setInt(3, key.deviceId());
 | 
			
		||||
            statement.setBytes(4, session.serialize());
 | 
			
		||||
            statement.executeUpdate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void deleteAllSessions(final Connection connection, final ServiceId serviceId) throws SQLException {
 | 
			
		||||
    private void deleteAllSessions(final Connection connection, final String address) throws SQLException {
 | 
			
		||||
        synchronized (cachedSessions) {
 | 
			
		||||
            cachedSessions.clear();
 | 
			
		||||
        }
 | 
			
		||||
@ -376,12 +366,12 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
        final var sql = (
 | 
			
		||||
                """
 | 
			
		||||
                DELETE FROM %s AS s
 | 
			
		||||
                WHERE s.account_id_type = ? AND s.uuid = ?
 | 
			
		||||
                WHERE s.account_id_type = ? AND s.address = ?
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_SESSION);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
            statement.setInt(1, accountIdType);
 | 
			
		||||
            statement.setBytes(2, serviceId.toByteArray());
 | 
			
		||||
            statement.setString(2, address);
 | 
			
		||||
            statement.executeUpdate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -394,12 +384,12 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
        final var sql = (
 | 
			
		||||
                """
 | 
			
		||||
                DELETE FROM %s AS s
 | 
			
		||||
                WHERE s.account_id_type = ? AND s.uuid = ? AND s.device_id = ?
 | 
			
		||||
                WHERE s.account_id_type = ? AND s.address = ? AND s.device_id = ?
 | 
			
		||||
                """
 | 
			
		||||
        ).formatted(TABLE_SESSION);
 | 
			
		||||
        try (final var statement = connection.prepareStatement(sql)) {
 | 
			
		||||
            statement.setInt(1, accountIdType);
 | 
			
		||||
            statement.setBytes(2, key.serviceId().toByteArray());
 | 
			
		||||
            statement.setString(2, key.address());
 | 
			
		||||
            statement.setInt(3, key.deviceId());
 | 
			
		||||
            statement.executeUpdate();
 | 
			
		||||
        }
 | 
			
		||||
@ -409,5 +399,5 @@ public class SessionStore implements SignalServiceSessionStore {
 | 
			
		||||
        return record != null && record.hasSenderChain();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    record Key(ServiceId serviceId, int deviceId) {}
 | 
			
		||||
    record Key(String address, int deviceId) {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user