import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Files;
-import java.security.SecureRandom;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Base64;
private StorageKey storageKey;
private long storageManifestVersion = -1;
private ProfileKey profileKey;
- private int aciPreKeyIdOffset = 1;
- private int aciNextSignedPreKeyId = 1;
- private int pniPreKeyIdOffset = 1;
- private int pniNextSignedPreKeyId = 1;
- private int aciKyberPreKeyIdOffset = 1;
- private int aciActiveLastResortKyberPreKeyId = -1;
- private int pniKyberPreKeyIdOffset = 1;
- private int pniActiveLastResortKyberPreKeyId = -1;
- private IdentityKeyPair aciIdentityKeyPair;
- private IdentityKeyPair pniIdentityKeyPair;
- private int localRegistrationId;
- private int localPniRegistrationId;
private Settings settings;
private long lastReceiveTimestamp = 0;
private boolean registered = false;
- private SignalProtocolStore aciSignalProtocolStore;
- private SignalProtocolStore pniSignalProtocolStore;
- private PreKeyStore aciPreKeyStore;
- private SignedPreKeyStore aciSignedPreKeyStore;
- private KyberPreKeyStore aciKyberPreKeyStore;
- private PreKeyStore pniPreKeyStore;
- private SignedPreKeyStore pniSignedPreKeyStore;
- private KyberPreKeyStore pniKyberPreKeyStore;
- private SessionStore aciSessionStore;
- private SessionStore pniSessionStore;
+ private final AccountData aciAccountData = new AccountData(ServiceIdType.ACI);
+ private final AccountData pniAccountData = new AccountData(ServiceIdType.PNI);
private IdentityKeyStore identityKeyStore;
- private SignalIdentityKeyStore aciIdentityKeyStore;
- private SignalIdentityKeyStore pniIdentityKeyStore;
private SenderKeyStore senderKeyStore;
private GroupStore groupStore;
private RecipientStore recipientStore;
signalAccount.profileKey = profileKey;
signalAccount.dataPath = dataPath;
- signalAccount.aciIdentityKeyPair = aciIdentityKey;
- signalAccount.pniIdentityKeyPair = pniIdentityKey;
- signalAccount.localRegistrationId = registrationId;
- signalAccount.localPniRegistrationId = pniRegistrationId;
+ signalAccount.aciAccountData.setIdentityKeyPair(aciIdentityKey);
+ signalAccount.pniAccountData.setIdentityKeyPair(pniIdentityKey);
+ signalAccount.aciAccountData.setLocalRegistrationId(registrationId);
+ signalAccount.pniAccountData.setLocalRegistrationId(pniRegistrationId);
signalAccount.settings = settings;
signalAccount.configurationStore = new ConfigurationStore(signalAccount::saveConfigurationStore);
profileKey);
signalAccount.getRecipientTrustedResolver()
.resolveSelfRecipientTrusted(signalAccount.getSelfRecipientAddress());
- signalAccount.getAciSessionStore().archiveAllSessions();
- signalAccount.getPniSessionStore().archiveAllSessions();
+ signalAccount.aciAccountData.getSessionStore().archiveAllSessions();
+ signalAccount.pniAccountData.getSessionStore().archiveAllSessions();
signalAccount.getSenderKeyStore().deleteAll();
signalAccount.clearAllPreKeys();
return signalAccount;
}
private void clearAllPreKeys() {
- resetPreKeyOffsets(ServiceIdType.ACI);
- resetPreKeyOffsets(ServiceIdType.PNI);
- resetKyberPreKeyOffsets(ServiceIdType.ACI);
- resetKyberPreKeyOffsets(ServiceIdType.PNI);
- this.getAciPreKeyStore().removeAllPreKeys();
- this.getAciSignedPreKeyStore().removeAllSignedPreKeys();
- this.getAciKyberPreKeyStore().removeAllKyberPreKeys();
- this.getPniPreKeyStore().removeAllPreKeys();
- this.getPniSignedPreKeyStore().removeAllSignedPreKeys();
- this.getPniKyberPreKeyStore().removeAllKyberPreKeys();
+ clearAllPreKeys(ServiceIdType.ACI);
+ clearAllPreKeys(ServiceIdType.PNI);
+ }
+
+ private void clearAllPreKeys(ServiceIdType serviceIdType) {
+ final var accountData = getAccountData(serviceIdType);
+ resetPreKeyOffsets(serviceIdType);
+ resetKyberPreKeyOffsets(serviceIdType);
+ accountData.getPreKeyStore().removeAllPreKeys();
+ accountData.getSignedPreKeyStore().removeAllSignedPreKeys();
+ accountData.getKyberPreKeyStore().removeAllKyberPreKeys();
save();
}
signalAccount.dataPath = dataPath;
signalAccount.accountPath = accountPath;
signalAccount.serviceEnvironment = serviceEnvironment;
- signalAccount.localRegistrationId = registrationId;
- signalAccount.localPniRegistrationId = pniRegistrationId;
+ signalAccount.aciAccountData.setLocalRegistrationId(registrationId);
+ signalAccount.pniAccountData.setLocalRegistrationId(pniRegistrationId);
signalAccount.settings = settings;
signalAccount.setProvisioningData(number,
aci,
getProfileStore().storeSelfProfileKey(getSelfRecipientId(), getProfileKey());
this.encryptedDeviceName = encryptedDeviceName;
this.deviceId = deviceId;
- this.aciIdentityKeyPair = aciIdentity;
- this.pniIdentityKeyPair = pniIdentity;
+ this.aciAccountData.setIdentityKeyPair(aciIdentity);
+ this.pniAccountData.setIdentityKeyPair(pniIdentity);
this.registered = true;
this.isMultiDevice = true;
this.lastReceiveTimestamp = 0;
this.storageManifestVersion = -1;
this.setStorageManifest(null);
this.storageKey = null;
- final var aciPublicKey = getAciIdentityKeyPair().getPublicKey();
- getIdentityKeyStore().saveIdentity(getAci(), aciPublicKey);
- getIdentityKeyStore().setIdentityTrustLevel(getAci(), aciPublicKey, TrustLevel.TRUSTED_VERIFIED);
+ trustSelfIdentity(ServiceIdType.ACI);
if (getPniIdentityKeyPair() != null) {
- final var pniPublicKey = getPniIdentityKeyPair().getPublicKey();
- getIdentityKeyStore().saveIdentity(getPni(), pniPublicKey);
- getIdentityKeyStore().setIdentityTrustLevel(getPni(), pniPublicKey, TrustLevel.TRUSTED_VERIFIED);
+ trustSelfIdentity(ServiceIdType.PNI);
}
}
getMessageCache().deleteMessages(recipientId);
if (recipientAddress.serviceId().isPresent()) {
final var serviceId = recipientAddress.serviceId().get();
- getAciSessionStore().deleteAllSessions(serviceId);
- getPniSessionStore().deleteAllSessions(serviceId);
+ aciAccountData.getSessionStore().deleteAllSessions(serviceId);
+ pniAccountData.getSessionStore().deleteAllSessions(serviceId);
getIdentityKeyStore().deleteIdentity(serviceId);
getSenderKeyStore().deleteAll(serviceId);
}
registrationId = rootNode.get("registrationId").asInt();
}
if (rootNode.hasNonNull("pniRegistrationId")) {
- localPniRegistrationId = rootNode.get("pniRegistrationId").asInt();
+ pniAccountData.setLocalRegistrationId(rootNode.get("pniRegistrationId").asInt());
} else {
- localPniRegistrationId = KeyHelper.generateRegistrationId(false);
+ pniAccountData.setLocalRegistrationId(KeyHelper.generateRegistrationId(false));
}
IdentityKeyPair aciIdentityKeyPair = null;
if (rootNode.hasNonNull("identityPrivateKey") && rootNode.hasNonNull("identityKey")) {
if (rootNode.hasNonNull("pniIdentityPrivateKey") && rootNode.hasNonNull("pniIdentityKey")) {
final var publicKeyBytes = Base64.getDecoder().decode(rootNode.get("pniIdentityKey").asText());
final var privateKeyBytes = Base64.getDecoder().decode(rootNode.get("pniIdentityPrivateKey").asText());
- pniIdentityKeyPair = KeyUtils.getIdentityKeyPair(publicKeyBytes, privateKeyBytes);
+ pniAccountData.setIdentityKeyPair(KeyUtils.getIdentityKeyPair(publicKeyBytes, privateKeyBytes));
}
if (rootNode.hasNonNull("registrationLockPin")) {
storageManifestVersion = rootNode.get("storageManifestVersion").asLong();
}
if (rootNode.hasNonNull("preKeyIdOffset")) {
- aciPreKeyIdOffset = rootNode.get("preKeyIdOffset").asInt(1);
+ aciAccountData.preKeyMetadata.preKeyIdOffset = rootNode.get("preKeyIdOffset").asInt(1);
} else {
- aciPreKeyIdOffset = getRandomPreKeyIdOffset();
+ aciAccountData.preKeyMetadata.preKeyIdOffset = getRandomPreKeyIdOffset();
}
if (rootNode.hasNonNull("nextSignedPreKeyId")) {
- aciNextSignedPreKeyId = rootNode.get("nextSignedPreKeyId").asInt(1);
+ aciAccountData.preKeyMetadata.nextSignedPreKeyId = rootNode.get("nextSignedPreKeyId").asInt(1);
} else {
- aciNextSignedPreKeyId = getRandomPreKeyIdOffset();
+ aciAccountData.preKeyMetadata.nextSignedPreKeyId = getRandomPreKeyIdOffset();
}
if (rootNode.hasNonNull("pniPreKeyIdOffset")) {
- pniPreKeyIdOffset = rootNode.get("pniPreKeyIdOffset").asInt(1);
+ pniAccountData.preKeyMetadata.preKeyIdOffset = rootNode.get("pniPreKeyIdOffset").asInt(1);
} else {
- pniPreKeyIdOffset = getRandomPreKeyIdOffset();
+ pniAccountData.preKeyMetadata.preKeyIdOffset = getRandomPreKeyIdOffset();
}
if (rootNode.hasNonNull("pniNextSignedPreKeyId")) {
- pniNextSignedPreKeyId = rootNode.get("pniNextSignedPreKeyId").asInt(1);
+ pniAccountData.preKeyMetadata.nextSignedPreKeyId = rootNode.get("pniNextSignedPreKeyId").asInt(1);
} else {
- pniNextSignedPreKeyId = getRandomPreKeyIdOffset();
+ pniAccountData.preKeyMetadata.nextSignedPreKeyId = getRandomPreKeyIdOffset();
}
if (rootNode.hasNonNull("kyberPreKeyIdOffset")) {
- aciKyberPreKeyIdOffset = rootNode.get("kyberPreKeyIdOffset").asInt(1);
+ aciAccountData.preKeyMetadata.kyberPreKeyIdOffset = rootNode.get("kyberPreKeyIdOffset").asInt(1);
} else {
- aciKyberPreKeyIdOffset = getRandomPreKeyIdOffset();
+ aciAccountData.preKeyMetadata.kyberPreKeyIdOffset = getRandomPreKeyIdOffset();
}
if (rootNode.hasNonNull("activeLastResortKyberPreKeyId")) {
- aciActiveLastResortKyberPreKeyId = rootNode.get("activeLastResortKyberPreKeyId").asInt(-1);
+ aciAccountData.preKeyMetadata.activeLastResortKyberPreKeyId = rootNode.get("activeLastResortKyberPreKeyId")
+ .asInt(-1);
} else {
- aciActiveLastResortKyberPreKeyId = -1;
+ aciAccountData.preKeyMetadata.activeLastResortKyberPreKeyId = -1;
}
if (rootNode.hasNonNull("pniKyberPreKeyIdOffset")) {
- pniKyberPreKeyIdOffset = rootNode.get("pniKyberPreKeyIdOffset").asInt(1);
+ pniAccountData.preKeyMetadata.kyberPreKeyIdOffset = rootNode.get("pniKyberPreKeyIdOffset").asInt(1);
} else {
- pniKyberPreKeyIdOffset = getRandomPreKeyIdOffset();
+ pniAccountData.preKeyMetadata.kyberPreKeyIdOffset = getRandomPreKeyIdOffset();
}
if (rootNode.hasNonNull("pniActiveLastResortKyberPreKeyId")) {
- pniActiveLastResortKyberPreKeyId = rootNode.get("pniActiveLastResortKyberPreKeyId").asInt(-1);
+ pniAccountData.preKeyMetadata.activeLastResortKyberPreKeyId = rootNode.get(
+ "pniActiveLastResortKyberPreKeyId").asInt(-1);
} else {
- pniActiveLastResortKyberPreKeyId = -1;
+ pniAccountData.preKeyMetadata.activeLastResortKyberPreKeyId = -1;
}
if (rootNode.hasNonNull("profileKey")) {
try {
}
final var legacyAciPreKeysPath = getAciPreKeysPath(dataPath, accountPath);
if (legacyAciPreKeysPath.exists()) {
- LegacyPreKeyStore.migrate(legacyAciPreKeysPath, getAciPreKeyStore());
+ LegacyPreKeyStore.migrate(legacyAciPreKeysPath, aciAccountData.getPreKeyStore());
migratedLegacyConfig = true;
}
final var legacyPniPreKeysPath = getPniPreKeysPath(dataPath, accountPath);
if (legacyPniPreKeysPath.exists()) {
- LegacyPreKeyStore.migrate(legacyPniPreKeysPath, getPniPreKeyStore());
+ LegacyPreKeyStore.migrate(legacyPniPreKeysPath, pniAccountData.getPreKeyStore());
migratedLegacyConfig = true;
}
final var legacyAciSignedPreKeysPath = getAciSignedPreKeysPath(dataPath, accountPath);
if (legacyAciSignedPreKeysPath.exists()) {
- LegacySignedPreKeyStore.migrate(legacyAciSignedPreKeysPath, getAciSignedPreKeyStore());
+ LegacySignedPreKeyStore.migrate(legacyAciSignedPreKeysPath, aciAccountData.getSignedPreKeyStore());
migratedLegacyConfig = true;
}
final var legacyPniSignedPreKeysPath = getPniSignedPreKeysPath(dataPath, accountPath);
if (legacyPniSignedPreKeysPath.exists()) {
- LegacySignedPreKeyStore.migrate(legacyPniSignedPreKeysPath, getPniSignedPreKeyStore());
+ LegacySignedPreKeyStore.migrate(legacyPniSignedPreKeysPath, pniAccountData.getSignedPreKeyStore());
migratedLegacyConfig = true;
}
final var legacySessionsPath = getSessionsPath(dataPath, accountPath);
LegacySessionStore.migrate(legacySessionsPath,
getRecipientResolver(),
getRecipientAddressResolver(),
- getAciSessionStore());
+ aciAccountData.getSessionStore());
migratedLegacyConfig = true;
}
final var legacyIdentitiesPath = getIdentitiesPath(dataPath, accountPath);
migratedLegacyConfig = true;
}
- this.aciIdentityKeyPair = aciIdentityKeyPair;
- this.localRegistrationId = registrationId;
+ this.aciAccountData.setIdentityKeyPair(aciIdentityKeyPair);
+ this.aciAccountData.setLocalRegistrationId(registrationId);
migratedLegacyConfig = loadLegacyStores(rootNode, legacySignalProtocolStore) || migratedLegacyConfig;
logger.debug("Migrating legacy pre key store.");
for (var entry : legacySignalProtocolStore.getLegacyPreKeyStore().getPreKeys().entrySet()) {
try {
- getAciPreKeyStore().storePreKey(entry.getKey(), new PreKeyRecord(entry.getValue()));
+ aciAccountData.getPreKeyStore().storePreKey(entry.getKey(), new PreKeyRecord(entry.getValue()));
} catch (InvalidMessageException e) {
logger.warn("Failed to migrate pre key, ignoring", e);
}
logger.debug("Migrating legacy signed pre key store.");
for (var entry : legacySignalProtocolStore.getLegacySignedPreKeyStore().getSignedPreKeys().entrySet()) {
try {
- getAciSignedPreKeyStore().storeSignedPreKey(entry.getKey(),
- new SignedPreKeyRecord(entry.getValue()));
+ aciAccountData.getSignedPreKeyStore()
+ .storeSignedPreKey(entry.getKey(), new SignedPreKeyRecord(entry.getValue()));
} catch (InvalidMessageException e) {
logger.warn("Failed to migrate signed pre key, ignoring", e);
}
logger.debug("Migrating legacy session store.");
for (var session : legacySignalProtocolStore.getLegacySessionStore().getSessions()) {
try {
- getAciSessionStore().storeSession(new SignalProtocolAddress(session.address.getIdentifier(),
- session.deviceId), new SessionRecord(session.sessionRecord));
+ aciAccountData.getSessionStore()
+ .storeSession(new SignalProtocolAddress(session.address.getIdentifier(), session.deviceId),
+ new SessionRecord(session.sessionRecord));
} catch (Exception e) {
logger.warn("Failed to migrate session, ignoring", e);
}
.put("isMultiDevice", isMultiDevice)
.put("lastReceiveTimestamp", lastReceiveTimestamp)
.put("password", password)
- .put("registrationId", localRegistrationId)
- .put("pniRegistrationId", localPniRegistrationId)
+ .put("registrationId", aciAccountData.getLocalRegistrationId())
+ .put("pniRegistrationId", pniAccountData.getLocalRegistrationId())
.put("identityPrivateKey",
- Base64.getEncoder().encodeToString(aciIdentityKeyPair.getPrivateKey().serialize()))
+ Base64.getEncoder()
+ .encodeToString(aciAccountData.getIdentityKeyPair().getPrivateKey().serialize()))
.put("identityKey",
- Base64.getEncoder().encodeToString(aciIdentityKeyPair.getPublicKey().serialize()))
+ Base64.getEncoder()
+ .encodeToString(aciAccountData.getIdentityKeyPair().getPublicKey().serialize()))
.put("pniIdentityPrivateKey",
- pniIdentityKeyPair == null
+ pniAccountData.getIdentityKeyPair() == null
? null
: Base64.getEncoder()
- .encodeToString(pniIdentityKeyPair.getPrivateKey().serialize()))
+ .encodeToString(pniAccountData.getIdentityKeyPair()
+ .getPrivateKey()
+ .serialize()))
.put("pniIdentityKey",
- pniIdentityKeyPair == null
+ pniAccountData.getIdentityKeyPair() == null
? null
- : Base64.getEncoder().encodeToString(pniIdentityKeyPair.getPublicKey().serialize()))
+ : Base64.getEncoder()
+ .encodeToString(pniAccountData.getIdentityKeyPair()
+ .getPublicKey()
+ .serialize()))
.put("registrationLockPin", registrationLockPin)
.put("pinMasterKey",
pinMasterKey == null ? null : Base64.getEncoder().encodeToString(pinMasterKey.serialize()))
.put("storageKey",
storageKey == null ? null : Base64.getEncoder().encodeToString(storageKey.serialize()))
.put("storageManifestVersion", storageManifestVersion == -1 ? null : storageManifestVersion)
- .put("preKeyIdOffset", aciPreKeyIdOffset)
- .put("nextSignedPreKeyId", aciNextSignedPreKeyId)
- .put("pniPreKeyIdOffset", pniPreKeyIdOffset)
- .put("pniNextSignedPreKeyId", pniNextSignedPreKeyId)
- .put("kyberPreKeyIdOffset", aciKyberPreKeyIdOffset)
- .put("activeLastResortKyberPreKeyId", aciActiveLastResortKyberPreKeyId)
- .put("pniKyberPreKeyIdOffset", pniKyberPreKeyIdOffset)
- .put("pniActiveLastResortKyberPreKeyId", pniActiveLastResortKyberPreKeyId)
+ .put("preKeyIdOffset", aciAccountData.getPreKeyMetadata().preKeyIdOffset)
+ .put("nextSignedPreKeyId", aciAccountData.getPreKeyMetadata().nextSignedPreKeyId)
+ .put("pniPreKeyIdOffset", pniAccountData.getPreKeyMetadata().preKeyIdOffset)
+ .put("pniNextSignedPreKeyId", pniAccountData.getPreKeyMetadata().nextSignedPreKeyId)
+ .put("kyberPreKeyIdOffset", aciAccountData.getPreKeyMetadata().kyberPreKeyIdOffset)
+ .put("activeLastResortKyberPreKeyId",
+ aciAccountData.getPreKeyMetadata().activeLastResortKyberPreKeyId)
+ .put("pniKyberPreKeyIdOffset", pniAccountData.getPreKeyMetadata().kyberPreKeyIdOffset)
+ .put("pniActiveLastResortKyberPreKeyId",
+ pniAccountData.getPreKeyMetadata().activeLastResortKyberPreKeyId)
.put("profileKey",
profileKey == null ? null : Base64.getEncoder().encodeToString(profileKey.serialize()))
.put("registered", registered)
}
public void resetPreKeyOffsets(final ServiceIdType serviceIdType) {
- if (serviceIdType.equals(ServiceIdType.ACI)) {
- this.aciPreKeyIdOffset = getRandomPreKeyIdOffset();
- this.aciNextSignedPreKeyId = getRandomPreKeyIdOffset();
- } else {
- this.pniPreKeyIdOffset = getRandomPreKeyIdOffset();
- this.pniNextSignedPreKeyId = getRandomPreKeyIdOffset();
- }
+ final var preKeyMetadata = getAccountData(serviceIdType).getPreKeyMetadata();
+ preKeyMetadata.preKeyIdOffset = getRandomPreKeyIdOffset();
+ preKeyMetadata.nextSignedPreKeyId = getRandomPreKeyIdOffset();
save();
}
private static int getRandomPreKeyIdOffset() {
- return new SecureRandom().nextInt(PREKEY_MAXIMUM_ID);
+ return KeyUtils.getRandomInt(PREKEY_MAXIMUM_ID);
}
public void addPreKeys(ServiceIdType serviceIdType, List<PreKeyRecord> records) {
- if (serviceIdType.equals(ServiceIdType.ACI)) {
- addAciPreKeys(records);
- } else {
- addPniPreKeys(records);
- }
- }
-
- private void addAciPreKeys(List<PreKeyRecord> records) {
+ final var accountData = getAccountData(serviceIdType);
+ final var preKeyMetadata = accountData.getPreKeyMetadata();
for (var record : records) {
- if (aciPreKeyIdOffset != record.getId()) {
- logger.error("Invalid pre key id {}, expected {}", record.getId(), aciPreKeyIdOffset);
+ if (preKeyMetadata.preKeyIdOffset != record.getId()) {
+ logger.error("Invalid pre key id {}, expected {}", record.getId(), preKeyMetadata.preKeyIdOffset);
throw new AssertionError("Invalid pre key id");
}
- getAciPreKeyStore().storePreKey(record.getId(), record);
- aciPreKeyIdOffset = (aciPreKeyIdOffset + 1) % PREKEY_MAXIMUM_ID;
- }
- save();
- }
-
- private void addPniPreKeys(List<PreKeyRecord> records) {
- for (var record : records) {
- if (pniPreKeyIdOffset != record.getId()) {
- logger.error("Invalid pre key id {}, expected {}", record.getId(), pniPreKeyIdOffset);
- throw new AssertionError("Invalid pre key id");
- }
- getPniPreKeyStore().storePreKey(record.getId(), record);
- pniPreKeyIdOffset = (pniPreKeyIdOffset + 1) % PREKEY_MAXIMUM_ID;
+ accountData.getPreKeyStore().storePreKey(record.getId(), record);
+ preKeyMetadata.preKeyIdOffset = (preKeyMetadata.preKeyIdOffset + 1) % PREKEY_MAXIMUM_ID;
}
save();
}
public void addSignedPreKey(ServiceIdType serviceIdType, SignedPreKeyRecord record) {
- if (serviceIdType.equals(ServiceIdType.ACI)) {
- addAciSignedPreKey(record);
- } else {
- addPniSignedPreKey(record);
- }
- }
-
- public void addAciSignedPreKey(SignedPreKeyRecord record) {
- if (aciNextSignedPreKeyId != record.getId()) {
- logger.error("Invalid signed pre key id {}, expected {}", record.getId(), aciNextSignedPreKeyId);
- throw new AssertionError("Invalid signed pre key id");
- }
- getAciSignedPreKeyStore().storeSignedPreKey(record.getId(), record);
- aciNextSignedPreKeyId = (aciNextSignedPreKeyId + 1) % PREKEY_MAXIMUM_ID;
- save();
- }
-
- public void addPniSignedPreKey(SignedPreKeyRecord record) {
- if (pniNextSignedPreKeyId != record.getId()) {
- logger.error("Invalid signed pre key id {}, expected {}", record.getId(), pniNextSignedPreKeyId);
+ final var accountData = getAccountData(serviceIdType);
+ final var preKeyMetadata = accountData.getPreKeyMetadata();
+ if (preKeyMetadata.nextSignedPreKeyId != record.getId()) {
+ logger.error("Invalid signed pre key id {}, expected {}",
+ record.getId(),
+ preKeyMetadata.nextSignedPreKeyId);
throw new AssertionError("Invalid signed pre key id");
}
- getPniSignedPreKeyStore().storeSignedPreKey(record.getId(), record);
- pniNextSignedPreKeyId = (pniNextSignedPreKeyId + 1) % PREKEY_MAXIMUM_ID;
+ accountData.getSignedPreKeyStore().storeSignedPreKey(record.getId(), record);
+ preKeyMetadata.nextSignedPreKeyId = (preKeyMetadata.nextSignedPreKeyId + 1) % PREKEY_MAXIMUM_ID;
save();
}
public void resetKyberPreKeyOffsets(final ServiceIdType serviceIdType) {
- if (serviceIdType.equals(ServiceIdType.ACI)) {
- this.aciKyberPreKeyIdOffset = getRandomPreKeyIdOffset();
- this.aciActiveLastResortKyberPreKeyId = -1;
- } else {
- this.pniKyberPreKeyIdOffset = getRandomPreKeyIdOffset();
- this.pniActiveLastResortKyberPreKeyId = -1;
- }
+ final var preKeyMetadata = getAccountData(serviceIdType).getPreKeyMetadata();
+ preKeyMetadata.kyberPreKeyIdOffset = getRandomPreKeyIdOffset();
+ preKeyMetadata.activeLastResortKyberPreKeyId = -1;
save();
}
public void addKyberPreKeys(ServiceIdType serviceIdType, List<KyberPreKeyRecord> records) {
- if (serviceIdType.equals(ServiceIdType.ACI)) {
- addAciKyberPreKeys(records);
- } else {
- addPniKyberPreKeys(records);
- }
- }
-
- private void addAciKyberPreKeys(List<KyberPreKeyRecord> records) {
+ final var accountData = getAccountData(serviceIdType);
+ final var preKeyMetadata = accountData.getPreKeyMetadata();
for (var record : records) {
- if (aciKyberPreKeyIdOffset != record.getId()) {
- logger.error("Invalid kyber pre key id {}, expected {}", record.getId(), aciKyberPreKeyIdOffset);
+ if (preKeyMetadata.kyberPreKeyIdOffset != record.getId()) {
+ logger.error("Invalid kyber pre key id {}, expected {}",
+ record.getId(),
+ preKeyMetadata.kyberPreKeyIdOffset);
throw new AssertionError("Invalid kyber pre key id");
}
- getAciKyberPreKeyStore().storeKyberPreKey(record.getId(), record);
- aciKyberPreKeyIdOffset = (aciKyberPreKeyIdOffset + 1) % PREKEY_MAXIMUM_ID;
- }
- save();
- }
-
- private void addPniKyberPreKeys(List<KyberPreKeyRecord> records) {
- for (var record : records) {
- if (pniKyberPreKeyIdOffset != record.getId()) {
- logger.error("Invalid kyber pre key id {}, expected {}", record.getId(), pniKyberPreKeyIdOffset);
- throw new AssertionError("Invalid kyber pre key id");
- }
- getPniKyberPreKeyStore().storeKyberPreKey(record.getId(), record);
- pniKyberPreKeyIdOffset = (pniKyberPreKeyIdOffset + 1) % PREKEY_MAXIMUM_ID;
+ accountData.getKyberPreKeyStore().storeKyberPreKey(record.getId(), record);
+ preKeyMetadata.kyberPreKeyIdOffset = (preKeyMetadata.kyberPreKeyIdOffset + 1) % PREKEY_MAXIMUM_ID;
}
save();
}
public void addLastResortKyberPreKey(ServiceIdType serviceIdType, KyberPreKeyRecord record) {
- if (serviceIdType.equals(ServiceIdType.ACI)) {
- addAciLastResortKyberPreKey(record);
- } else {
- addPniLastResortKyberPreKey(record);
- }
- }
-
- public void addAciLastResortKyberPreKey(KyberPreKeyRecord record) {
- if (aciKyberPreKeyIdOffset != record.getId()) {
+ final var accountData = getAccountData(serviceIdType);
+ final var preKeyMetadata = accountData.getPreKeyMetadata();
+ if (preKeyMetadata.kyberPreKeyIdOffset != record.getId()) {
logger.error("Invalid last resort kyber pre key id {}, expected {}",
record.getId(),
- aciKyberPreKeyIdOffset);
+ preKeyMetadata.kyberPreKeyIdOffset);
throw new AssertionError("Invalid last resort kyber pre key id");
}
- getAciKyberPreKeyStore().storeLastResortKyberPreKey(record.getId(), record);
- aciActiveLastResortKyberPreKeyId = record.getId();
- aciKyberPreKeyIdOffset = (aciKyberPreKeyIdOffset + 1) % PREKEY_MAXIMUM_ID;
- save();
- }
-
- public void addPniLastResortKyberPreKey(KyberPreKeyRecord record) {
- if (pniKyberPreKeyIdOffset != record.getId()) {
- logger.error("Invalid last resort kyber pre key id {}, expected {}",
- record.getId(),
- pniKyberPreKeyIdOffset);
- throw new AssertionError("Invalid last resort kyber pre key id");
- }
- getPniKyberPreKeyStore().storeLastResortKyberPreKey(record.getId(), record);
- pniActiveLastResortKyberPreKeyId = record.getId();
- pniKyberPreKeyIdOffset = (pniKyberPreKeyIdOffset + 1) % PREKEY_MAXIMUM_ID;
+ accountData.getKyberPreKeyStore().storeLastResortKyberPreKey(record.getId(), record);
+ preKeyMetadata.activeLastResortKyberPreKeyId = record.getId();
+ preKeyMetadata.kyberPreKeyIdOffset = (preKeyMetadata.kyberPreKeyIdOffset + 1) % PREKEY_MAXIMUM_ID;
save();
}
return previousStorageVersion;
}
+ public AccountData getAccountData(ServiceIdType serviceIdType) {
+ return switch (serviceIdType) {
+ case ACI -> aciAccountData;
+ case PNI -> pniAccountData;
+ };
+ }
+
+ public AccountData getAccountData(ServiceId accountIdentifier) {
+ if (accountIdentifier.equals(aci)) {
+ return aciAccountData;
+ } else if (accountIdentifier.equals(pni)) {
+ return pniAccountData;
+ } else {
+ throw new IllegalArgumentException("No matching account data found for " + accountIdentifier);
+ }
+ }
+
public SignalServiceDataStore getSignalServiceDataStore() {
return new SignalServiceDataStore() {
@Override
@Override
public SignalServiceAccountDataStore aci() {
- return getAciSignalServiceAccountDataStore();
+ return aciAccountData.getSignalServiceAccountDataStore();
}
@Override
public SignalServiceAccountDataStore pni() {
- return getPniSignalServiceAccountDataStore();
+ return pniAccountData.getSignalServiceAccountDataStore();
}
@Override
};
}
- private SignalServiceAccountDataStore getAciSignalServiceAccountDataStore() {
- return getOrCreate(() -> aciSignalProtocolStore,
- () -> aciSignalProtocolStore = new SignalProtocolStore(getAciPreKeyStore(),
- getAciSignedPreKeyStore(),
- getAciKyberPreKeyStore(),
- getAciSessionStore(),
- getAciIdentityKeyStore(),
- getSenderKeyStore(),
- this::isMultiDevice));
- }
-
- private SignalServiceAccountDataStore getPniSignalServiceAccountDataStore() {
- return getOrCreate(() -> pniSignalProtocolStore,
- () -> pniSignalProtocolStore = new SignalProtocolStore(getPniPreKeyStore(),
- getPniSignedPreKeyStore(),
- getPniKyberPreKeyStore(),
- getPniSessionStore(),
- getPniIdentityKeyStore(),
- getSenderKeyStore(),
- this::isMultiDevice));
- }
-
- private PreKeyStore getAciPreKeyStore() {
- return getOrCreate(() -> aciPreKeyStore,
- () -> aciPreKeyStore = new PreKeyStore(getAccountDatabase(), ServiceIdType.ACI));
- }
-
- private SignedPreKeyStore getAciSignedPreKeyStore() {
- return getOrCreate(() -> aciSignedPreKeyStore,
- () -> aciSignedPreKeyStore = new SignedPreKeyStore(getAccountDatabase(), ServiceIdType.ACI));
- }
-
- private KyberPreKeyStore getAciKyberPreKeyStore() {
- return getOrCreate(() -> aciKyberPreKeyStore,
- () -> aciKyberPreKeyStore = new KyberPreKeyStore(getAccountDatabase(), ServiceIdType.ACI));
- }
-
- private PreKeyStore getPniPreKeyStore() {
- return getOrCreate(() -> pniPreKeyStore,
- () -> pniPreKeyStore = new PreKeyStore(getAccountDatabase(), ServiceIdType.PNI));
- }
-
- private SignedPreKeyStore getPniSignedPreKeyStore() {
- return getOrCreate(() -> pniSignedPreKeyStore,
- () -> pniSignedPreKeyStore = new SignedPreKeyStore(getAccountDatabase(), ServiceIdType.PNI));
- }
-
- private KyberPreKeyStore getPniKyberPreKeyStore() {
- return getOrCreate(() -> pniKyberPreKeyStore,
- () -> pniKyberPreKeyStore = new KyberPreKeyStore(getAccountDatabase(), ServiceIdType.PNI));
- }
-
- public SessionStore getAciSessionStore() {
- return getOrCreate(() -> aciSessionStore,
- () -> aciSessionStore = new SessionStore(getAccountDatabase(), ServiceIdType.ACI));
- }
-
- public SessionStore getPniSessionStore() {
- return getOrCreate(() -> pniSessionStore,
- () -> pniSessionStore = new SessionStore(getAccountDatabase(), ServiceIdType.PNI));
- }
-
public IdentityKeyStore getIdentityKeyStore() {
return getOrCreate(() -> identityKeyStore,
() -> identityKeyStore = new IdentityKeyStore(getAccountDatabase(), settings.trustNewIdentity()));
}
- public SignalIdentityKeyStore getAciIdentityKeyStore() {
- return getOrCreate(() -> aciIdentityKeyStore,
- () -> aciIdentityKeyStore = new SignalIdentityKeyStore(getRecipientResolver(),
- () -> aciIdentityKeyPair,
- localRegistrationId,
- getIdentityKeyStore()));
- }
-
- public SignalIdentityKeyStore getPniIdentityKeyStore() {
- return getOrCreate(() -> pniIdentityKeyStore,
- () -> pniIdentityKeyStore = new SignalIdentityKeyStore(getRecipientResolver(),
- () -> pniIdentityKeyPair,
- localRegistrationId,
- getIdentityKeyStore()));
- }
-
public GroupStore getGroupStore() {
return getOrCreate(() -> groupStore,
() -> groupStore = new GroupStore(getAccountDatabase(),
if (this.pni != null && !this.pni.equals(updatedPni)) {
// Clear data for old PNI
identityKeyStore.deleteIdentity(this.pni);
- getPniPreKeyStore().removeAllPreKeys();
- getPniSignedPreKeyStore().removeAllSignedPreKeys();
- getPniKyberPreKeyStore().removeAllKyberPreKeys();
- aciActiveLastResortKyberPreKeyId = -1;
- pniActiveLastResortKyberPreKeyId = -1;
+ clearAllPreKeys(ServiceIdType.PNI);
}
this.pni = updatedPni;
setPni(updatedPni);
setPniIdentityKeyPair(pniIdentityKeyPair);
- addPniSignedPreKey(pniSignedPreKey);
+ addSignedPreKey(ServiceIdType.PNI, pniSignedPreKey);
setLocalPniRegistrationId(localPniRegistrationId);
}
}
public IdentityKeyPair getIdentityKeyPair(ServiceIdType serviceIdType) {
- return serviceIdType.equals(ServiceIdType.ACI) ? aciIdentityKeyPair : pniIdentityKeyPair;
+ return getAccountData(serviceIdType).getIdentityKeyPair();
}
public IdentityKeyPair getAciIdentityKeyPair() {
- return aciIdentityKeyPair;
+ return aciAccountData.getIdentityKeyPair();
}
public IdentityKeyPair getPniIdentityKeyPair() {
- return pniIdentityKeyPair;
+ return pniAccountData.getIdentityKeyPair();
}
public void setPniIdentityKeyPair(final IdentityKeyPair identityKeyPair) {
- pniIdentityKeyPair = identityKeyPair;
- final var pniPublicKey = identityKeyPair.getPublicKey();
- getIdentityKeyStore().saveIdentity(getPni(), pniPublicKey);
- getIdentityKeyStore().setIdentityTrustLevel(getPni(), pniPublicKey, TrustLevel.TRUSTED_VERIFIED);
+ pniAccountData.setIdentityKeyPair(identityKeyPair);
+ trustSelfIdentity(ServiceIdType.PNI);
save();
}
public int getLocalRegistrationId() {
- return localRegistrationId;
+ return aciAccountData.getLocalRegistrationId();
}
public int getLocalPniRegistrationId() {
- return localPniRegistrationId;
+ return pniAccountData.getLocalRegistrationId();
}
public void setLocalPniRegistrationId(final int localPniRegistrationId) {
- this.localPniRegistrationId = localPniRegistrationId;
+ pniAccountData.setLocalRegistrationId(localPniRegistrationId);
save();
}
}
public int getPreKeyIdOffset(ServiceIdType serviceIdType) {
- return serviceIdType.equals(ServiceIdType.ACI) ? aciPreKeyIdOffset : pniPreKeyIdOffset;
+ return getAccountData(serviceIdType).getPreKeyMetadata().preKeyIdOffset;
}
public int getNextSignedPreKeyId(ServiceIdType serviceIdType) {
- return serviceIdType.equals(ServiceIdType.ACI) ? aciNextSignedPreKeyId : pniNextSignedPreKeyId;
+ return getAccountData(serviceIdType).getPreKeyMetadata().nextSignedPreKeyId;
}
public int getKyberPreKeyIdOffset(ServiceIdType serviceIdType) {
- return serviceIdType.equals(ServiceIdType.ACI) ? aciKyberPreKeyIdOffset : pniKyberPreKeyIdOffset;
+ return getAccountData(serviceIdType).getPreKeyMetadata().kyberPreKeyIdOffset;
}
public boolean isRegistered() {
save();
clearAllPreKeys();
- getAciSessionStore().archiveAllSessions();
- getPniSessionStore().archiveAllSessions();
+ aciAccountData.getSessionStore().archiveAllSessions();
+ pniAccountData.getSessionStore().archiveAllSessions();
getSenderKeyStore().deleteAll();
getRecipientTrustedResolver().resolveSelfRecipientTrusted(getSelfRecipientAddress());
- final var aciPublicKey = getAciIdentityKeyPair().getPublicKey();
- getIdentityKeyStore().saveIdentity(getAci(), aciPublicKey);
- getIdentityKeyStore().setIdentityTrustLevel(getAci(), aciPublicKey, TrustLevel.TRUSTED_VERIFIED);
+ trustSelfIdentity(ServiceIdType.ACI);
if (getPniIdentityKeyPair() == null) {
setPniIdentityKeyPair(KeyUtils.generateIdentityKeyPair());
} else {
- final var pniPublicKey = getPniIdentityKeyPair().getPublicKey();
- getIdentityKeyStore().saveIdentity(getPni(), pniPublicKey);
- getIdentityKeyStore().setIdentityTrustLevel(getPni(), pniPublicKey, TrustLevel.TRUSTED_VERIFIED);
+ trustSelfIdentity(ServiceIdType.PNI);
}
}
+ private void trustSelfIdentity(ServiceIdType serviceIdType) {
+ final var accountData = getAccountData(serviceIdType);
+ final var serviceId = accountData.getServiceId();
+ final var publicKey = accountData.getIdentityKeyPair().getPublicKey();
+ getIdentityKeyStore().saveIdentity(serviceId, publicKey);
+ getIdentityKeyStore().setIdentityTrustLevel(serviceId, publicKey, TrustLevel.TRUSTED_VERIFIED);
+ }
+
public void deleteAccountData() throws IOException {
close();
try (final var files = Files.walk(getUserPath(dataPath, accountPath).toPath())
void call();
}
+
+ private static class PreKeyMetadata {
+
+ private int preKeyIdOffset = 1;
+ private int nextSignedPreKeyId = 1;
+ private int kyberPreKeyIdOffset = 1;
+ private int activeLastResortKyberPreKeyId = -1;
+ }
+
+ public class AccountData {
+
+ private final ServiceIdType serviceIdType;
+ private IdentityKeyPair identityKeyPair;
+ private int localRegistrationId;
+ private final PreKeyMetadata preKeyMetadata = new PreKeyMetadata();
+
+ private SignalProtocolStore signalProtocolStore;
+ private PreKeyStore preKeyStore;
+ private SignedPreKeyStore signedPreKeyStore;
+ private KyberPreKeyStore kyberPreKeyStore;
+ private SessionStore sessionStore;
+ private SignalIdentityKeyStore identityKeyStore;
+
+ public AccountData(final ServiceIdType serviceIdType) {
+ this.serviceIdType = serviceIdType;
+ }
+
+ public ServiceId getServiceId() {
+ return getAccountId(serviceIdType);
+ }
+
+ public IdentityKeyPair getIdentityKeyPair() {
+ return identityKeyPair;
+ }
+
+ private void setIdentityKeyPair(final IdentityKeyPair identityKeyPair) {
+ this.identityKeyPair = identityKeyPair;
+ }
+
+ public int getLocalRegistrationId() {
+ return localRegistrationId;
+ }
+
+ private void setLocalRegistrationId(final int localRegistrationId) {
+ this.localRegistrationId = localRegistrationId;
+ this.identityKeyStore = null;
+ }
+
+ public PreKeyMetadata getPreKeyMetadata() {
+ return preKeyMetadata;
+ }
+
+ private SignalServiceAccountDataStore getSignalServiceAccountDataStore() {
+ return getOrCreate(() -> signalProtocolStore,
+ () -> signalProtocolStore = new SignalProtocolStore(getPreKeyStore(),
+ getSignedPreKeyStore(),
+ getKyberPreKeyStore(),
+ getSessionStore(),
+ getIdentityKeyStore(),
+ getSenderKeyStore(),
+ SignalAccount.this::isMultiDevice));
+ }
+
+ private PreKeyStore getPreKeyStore() {
+ return getOrCreate(() -> preKeyStore,
+ () -> preKeyStore = new PreKeyStore(getAccountDatabase(), serviceIdType));
+ }
+
+ private SignedPreKeyStore getSignedPreKeyStore() {
+ return getOrCreate(() -> signedPreKeyStore,
+ () -> signedPreKeyStore = new SignedPreKeyStore(getAccountDatabase(), serviceIdType));
+ }
+
+ private KyberPreKeyStore getKyberPreKeyStore() {
+ return getOrCreate(() -> kyberPreKeyStore,
+ () -> kyberPreKeyStore = new KyberPreKeyStore(getAccountDatabase(), serviceIdType));
+ }
+
+ public SessionStore getSessionStore() {
+ return getOrCreate(() -> sessionStore,
+ () -> sessionStore = new SessionStore(getAccountDatabase(), serviceIdType));
+ }
+
+ public SignalIdentityKeyStore getIdentityKeyStore() {
+ return getOrCreate(() -> identityKeyStore,
+ () -> identityKeyStore = new SignalIdentityKeyStore(getRecipientResolver(),
+ () -> identityKeyPair,
+ localRegistrationId,
+ SignalAccount.this.getIdentityKeyStore()));
+ }
+ }
}