kopia lustrzana https://github.com/ryukoposting/Signal-Android
Add a write-through cache to the identity store.
rodzic
28d86886bd
commit
0a67731830
|
@ -469,7 +469,7 @@ public class DirectoryHelper {
|
||||||
|
|
||||||
for (RecipientId newUser: newUsers) {
|
for (RecipientId newUser: newUsers) {
|
||||||
Recipient recipient = Recipient.resolved(newUser);
|
Recipient recipient = Recipient.resolved(newUser);
|
||||||
if (!SessionUtil.hasSession(context, recipient.getId()) &&
|
if (!SessionUtil.hasSession(recipient.getId()) &&
|
||||||
!recipient.isSelf() &&
|
!recipient.isSelf() &&
|
||||||
recipient.hasAUserSetDisplayName(context))
|
recipient.hasAUserSetDisplayName(context))
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.database.MessageDatabase;
|
||||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||||
|
@ -126,14 +127,15 @@ final class SafetyNumberChangeRepository {
|
||||||
try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
||||||
for (ChangedRecipient changedRecipient : changedRecipients) {
|
for (ChangedRecipient changedRecipient : changedRecipients) {
|
||||||
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(changedRecipient.getRecipient().requireServiceId(), SignalServiceAddress.DEFAULT_DEVICE_ID);
|
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(changedRecipient.getRecipient().requireServiceId(), SignalServiceAddress.DEFAULT_DEVICE_ID);
|
||||||
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(context);
|
|
||||||
Log.d(TAG, "Saving identity for: " + changedRecipient.getRecipient().getId() + " " + changedRecipient.getIdentityRecord().getIdentityKey().hashCode());
|
Log.d(TAG, "Saving identity for: " + changedRecipient.getRecipient().getId() + " " + changedRecipient.getIdentityRecord().getIdentityKey().hashCode());
|
||||||
TextSecureIdentityKeyStore.SaveResult result = identityKeyStore.saveIdentity(mismatchAddress, changedRecipient.getIdentityRecord().getIdentityKey(), true);
|
TextSecureIdentityKeyStore.SaveResult result = ApplicationDependencies.getIdentityStore().saveIdentity(mismatchAddress, changedRecipient.getIdentityRecord().getIdentityKey(), true);
|
||||||
|
|
||||||
Log.d(TAG, "Saving identity result: " + result);
|
Log.d(TAG, "Saving identity result: " + result);
|
||||||
if (result == TextSecureIdentityKeyStore.SaveResult.NO_CHANGE) {
|
if (result == TextSecureIdentityKeyStore.SaveResult.NO_CHANGE) {
|
||||||
Log.i(TAG, "Archiving sessions explicitly as they appear to be out of sync.");
|
Log.i(TAG, "Archiving sessions explicitly as they appear to be out of sync.");
|
||||||
SessionUtil.archiveSession(context, changedRecipient.getRecipient().getId(), SignalServiceAddress.DEFAULT_DEVICE_ID);
|
SessionUtil.archiveSession(changedRecipient.getRecipient().getId(), SignalServiceAddress.DEFAULT_DEVICE_ID);
|
||||||
SessionUtil.archiveSiblingSessions(context, mismatchAddress);
|
SessionUtil.archiveSiblingSessions(mismatchAddress);
|
||||||
DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(changedRecipient.getRecipient().getId());
|
DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(changedRecipient.getRecipient().getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import android.content.Context;
|
||||||
|
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecurePreKeyStore;
|
import org.thoughtcrime.securesms.crypto.storage.TextSecurePreKeyStore;
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||||
import org.whispersystems.libsignal.InvalidKeyException;
|
import org.whispersystems.libsignal.InvalidKeyException;
|
||||||
|
@ -43,7 +44,7 @@ public class PreKeyUtil {
|
||||||
private static final int BATCH_SIZE = 100;
|
private static final int BATCH_SIZE = 100;
|
||||||
|
|
||||||
public synchronized static List<PreKeyRecord> generatePreKeys(Context context) {
|
public synchronized static List<PreKeyRecord> generatePreKeys(Context context) {
|
||||||
PreKeyStore preKeyStore = new TextSecurePreKeyStore(context);
|
PreKeyStore preKeyStore = ApplicationDependencies.getPreKeyStore();
|
||||||
List<PreKeyRecord> records = new LinkedList<>();
|
List<PreKeyRecord> records = new LinkedList<>();
|
||||||
int preKeyIdOffset = TextSecurePreferences.getNextPreKeyId(context);
|
int preKeyIdOffset = TextSecurePreferences.getNextPreKeyId(context);
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ public class PreKeyUtil {
|
||||||
|
|
||||||
public synchronized static SignedPreKeyRecord generateSignedPreKey(Context context, IdentityKeyPair identityKeyPair, boolean active) {
|
public synchronized static SignedPreKeyRecord generateSignedPreKey(Context context, IdentityKeyPair identityKeyPair, boolean active) {
|
||||||
try {
|
try {
|
||||||
SignedPreKeyStore signedPreKeyStore = new TextSecurePreKeyStore(context);
|
SignedPreKeyStore signedPreKeyStore = ApplicationDependencies.getPreKeyStore();
|
||||||
int signedPreKeyId = TextSecurePreferences.getNextSignedPreKeyId(context);
|
int signedPreKeyId = TextSecurePreferences.getNextSignedPreKeyId(context);
|
||||||
ECKeyPair keyPair = Curve.generateKeyPair();
|
ECKeyPair keyPair = Curve.generateKeyPair();
|
||||||
byte[] signature = Curve.calculateSignature(identityKeyPair.getPrivateKey(), keyPair.getPublicKey().serialize());
|
byte[] signature = Curve.calculateSignature(identityKeyPair.getPrivateKey(), keyPair.getPublicKey().serialize());
|
||||||
|
|
|
@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.storage.SignalSenderKeyStore;
|
import org.thoughtcrime.securesms.crypto.storage.SignalSenderKeyStore;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.whispersystems.signalservice.api.SignalSessionLock;
|
import org.whispersystems.signalservice.api.SignalSessionLock;
|
||||||
import org.whispersystems.signalservice.api.push.DistributionId;
|
import org.whispersystems.signalservice.api.push.DistributionId;
|
||||||
|
@ -19,7 +20,7 @@ public final class SenderKeyUtil {
|
||||||
*/
|
*/
|
||||||
public static void rotateOurKey(@NonNull Context context, @NonNull DistributionId distributionId) {
|
public static void rotateOurKey(@NonNull Context context, @NonNull DistributionId distributionId) {
|
||||||
try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
||||||
new SignalSenderKeyStore(context).deleteAllFor(Recipient.self().getId(), distributionId);
|
ApplicationDependencies.getSenderKeyStore().deleteAllFor(Recipient.self().getId(), distributionId);
|
||||||
DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(distributionId);
|
DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(distributionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +37,7 @@ public final class SenderKeyUtil {
|
||||||
*/
|
*/
|
||||||
public static void clearAllState(@NonNull Context context) {
|
public static void clearAllState(@NonNull Context context) {
|
||||||
try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
||||||
new SignalSenderKeyStore(context).deleteAll();
|
ApplicationDependencies.getSenderKeyStore().deleteAll();
|
||||||
DatabaseFactory.getSenderKeySharedDatabase(context).deleteAll();
|
DatabaseFactory.getSenderKeySharedDatabase(context).deleteAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +1,38 @@
|
||||||
package org.thoughtcrime.securesms.crypto;
|
package org.thoughtcrime.securesms.crypto;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||||
import org.whispersystems.libsignal.ecc.ECPublicKey;
|
import org.whispersystems.libsignal.ecc.ECPublicKey;
|
||||||
import org.whispersystems.libsignal.state.SessionRecord;
|
import org.whispersystems.libsignal.state.SessionRecord;
|
||||||
import org.whispersystems.libsignal.state.SessionStore;
|
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
|
|
||||||
public class SessionUtil {
|
public class SessionUtil {
|
||||||
|
|
||||||
public static boolean hasSession(@NonNull Context context, @NonNull RecipientId id) {
|
public static boolean hasSession(@NonNull RecipientId id) {
|
||||||
SessionStore sessionStore = new TextSecureSessionStore(context);
|
|
||||||
SignalProtocolAddress axolotlAddress = new SignalProtocolAddress(Recipient.resolved(id).requireServiceId(), SignalServiceAddress.DEFAULT_DEVICE_ID);
|
SignalProtocolAddress axolotlAddress = new SignalProtocolAddress(Recipient.resolved(id).requireServiceId(), SignalServiceAddress.DEFAULT_DEVICE_ID);
|
||||||
|
|
||||||
return sessionStore.containsSession(axolotlAddress);
|
return ApplicationDependencies.getSessionStore().containsSession(axolotlAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void archiveSiblingSessions(Context context, SignalProtocolAddress address) {
|
public static void archiveSiblingSessions(SignalProtocolAddress address) {
|
||||||
TextSecureSessionStore sessionStore = new TextSecureSessionStore(context);
|
ApplicationDependencies.getSessionStore().archiveSiblingSessions(address);
|
||||||
sessionStore.archiveSiblingSessions(address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void archiveAllSessions(Context context) {
|
public static void archiveAllSessions() {
|
||||||
new TextSecureSessionStore(context).archiveAllSessions();
|
ApplicationDependencies.getSessionStore().archiveAllSessions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void archiveSession(Context context, RecipientId recipientId, int deviceId) {
|
public static void archiveSession(RecipientId recipientId, int deviceId) {
|
||||||
new TextSecureSessionStore(context).archiveSession(recipientId, deviceId);
|
ApplicationDependencies.getSessionStore().archiveSession(recipientId, deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean ratchetKeyMatches(@NonNull Context context, @NonNull Recipient recipient, int deviceId, @NonNull ECPublicKey ratchetKey) {
|
public static boolean ratchetKeyMatches(@NonNull Recipient recipient, int deviceId, @NonNull ECPublicKey ratchetKey) {
|
||||||
TextSecureSessionStore sessionStore = new TextSecureSessionStore(context);
|
|
||||||
SignalProtocolAddress address = new SignalProtocolAddress(recipient.resolve().requireServiceId(), deviceId);
|
SignalProtocolAddress address = new SignalProtocolAddress(recipient.resolve().requireServiceId(), deviceId);
|
||||||
SessionRecord session = sessionStore.loadSession(address);
|
SessionRecord session = ApplicationDependencies.getSessionStore().loadSession(address);
|
||||||
|
|
||||||
return session.currentRatchetKeyMatches(ratchetKey);
|
return session.currentRatchetKeyMatches(ratchetKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.crypto.storage;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||||
|
@ -36,11 +37,11 @@ public class SignalProtocolStoreImpl implements SignalServiceDataStore {
|
||||||
|
|
||||||
public SignalProtocolStoreImpl(Context context) {
|
public SignalProtocolStoreImpl(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.preKeyStore = new TextSecurePreKeyStore(context);
|
this.preKeyStore = ApplicationDependencies.getPreKeyStore();
|
||||||
this.signedPreKeyStore = new TextSecurePreKeyStore(context);
|
this.signedPreKeyStore = ApplicationDependencies.getPreKeyStore();
|
||||||
this.identityKeyStore = new TextSecureIdentityKeyStore(context);
|
this.identityKeyStore = ApplicationDependencies.getIdentityStore();
|
||||||
this.sessionStore = new TextSecureSessionStore(context);
|
this.sessionStore = ApplicationDependencies.getSessionStore();
|
||||||
this.senderKeyStore = new SignalSenderKeyStore(context);
|
this.senderKeyStore = ApplicationDependencies.getSenderKeyStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -10,32 +10,33 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||||
import org.thoughtcrime.securesms.crypto.SessionUtil;
|
import org.thoughtcrime.securesms.crypto.SessionUtil;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||||
import org.thoughtcrime.securesms.database.model.IdentityStoreRecord;
|
import org.thoughtcrime.securesms.database.model.IdentityStoreRecord;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.LRUCache;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||||
import org.whispersystems.libsignal.state.IdentityKeyStore;
|
import org.whispersystems.libsignal.state.IdentityKeyStore;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
||||||
|
|
||||||
|
private static final String TAG = Log.tag(TextSecureIdentityKeyStore.class);
|
||||||
|
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
private static final int TIMESTAMP_THRESHOLD_SECONDS = 5;
|
private static final int TIMESTAMP_THRESHOLD_SECONDS = 5;
|
||||||
|
|
||||||
private static final String TAG = Log.tag(TextSecureIdentityKeyStore.class);
|
|
||||||
private static final Object LOCK = new Object();
|
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
private final Cache cache;
|
||||||
|
|
||||||
public TextSecureIdentityKeyStore(Context context) {
|
public TextSecureIdentityKeyStore(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.cache = new Cache(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -48,41 +49,44 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
||||||
return TextSecurePreferences.getLocalRegistrationId(context);
|
return TextSecurePreferences.getLocalRegistrationId(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey) {
|
||||||
|
return saveIdentity(address, identityKey, false) == SaveResult.UPDATE;
|
||||||
|
}
|
||||||
|
|
||||||
public @NonNull SaveResult saveIdentity(SignalProtocolAddress address, IdentityKey identityKey, boolean nonBlockingApproval) {
|
public @NonNull SaveResult saveIdentity(SignalProtocolAddress address, IdentityKey identityKey, boolean nonBlockingApproval) {
|
||||||
synchronized (LOCK) {
|
synchronized (LOCK) {
|
||||||
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
|
IdentityStoreRecord identityRecord = cache.get(address.getName());
|
||||||
Optional<IdentityRecord> identityRecord = identityDatabase.getIdentity(address.getName());
|
|
||||||
RecipientId recipientId = RecipientId.fromExternalPush(address.getName());
|
RecipientId recipientId = RecipientId.fromExternalPush(address.getName());
|
||||||
|
|
||||||
if (!identityRecord.isPresent()) {
|
if (identityRecord == null) {
|
||||||
Log.i(TAG, "Saving new identity...");
|
Log.i(TAG, "Saving new identity...");
|
||||||
identityDatabase.saveIdentity(address.getName(), recipientId, identityKey, VerifiedStatus.DEFAULT, true, System.currentTimeMillis(), nonBlockingApproval);
|
cache.save(address.getName(), recipientId, identityKey, VerifiedStatus.DEFAULT, true, System.currentTimeMillis(), nonBlockingApproval);
|
||||||
return SaveResult.NEW;
|
return SaveResult.NEW;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!identityRecord.get().getIdentityKey().equals(identityKey)) {
|
if (!identityRecord.getIdentityKey().equals(identityKey)) {
|
||||||
Log.i(TAG, "Replacing existing identity... Existing: " + identityRecord.get().getIdentityKey().hashCode() + " New: " + identityKey.hashCode());
|
Log.i(TAG, "Replacing existing identity... Existing: " + identityRecord.getIdentityKey().hashCode() + " New: " + identityKey.hashCode());
|
||||||
VerifiedStatus verifiedStatus;
|
VerifiedStatus verifiedStatus;
|
||||||
|
|
||||||
if (identityRecord.get().getVerifiedStatus() == VerifiedStatus.VERIFIED ||
|
if (identityRecord.getVerifiedStatus() == VerifiedStatus.VERIFIED ||
|
||||||
identityRecord.get().getVerifiedStatus() == VerifiedStatus.UNVERIFIED)
|
identityRecord.getVerifiedStatus() == VerifiedStatus.UNVERIFIED)
|
||||||
{
|
{
|
||||||
verifiedStatus = VerifiedStatus.UNVERIFIED;
|
verifiedStatus = VerifiedStatus.UNVERIFIED;
|
||||||
} else {
|
} else {
|
||||||
verifiedStatus = VerifiedStatus.DEFAULT;
|
verifiedStatus = VerifiedStatus.DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cache.save(address.getName(), recipientId, identityKey, verifiedStatus, false, System.currentTimeMillis(), nonBlockingApproval);
|
||||||
identityDatabase.saveIdentity(address.getName(), recipientId, identityKey, verifiedStatus, false, System.currentTimeMillis(), nonBlockingApproval);
|
|
||||||
IdentityUtil.markIdentityUpdate(context, recipientId);
|
IdentityUtil.markIdentityUpdate(context, recipientId);
|
||||||
SessionUtil.archiveSiblingSessions(context, address);
|
SessionUtil.archiveSiblingSessions(address);
|
||||||
DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(recipientId);
|
DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(recipientId);
|
||||||
return SaveResult.UPDATE;
|
return SaveResult.UPDATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNonBlockingApprovalRequired(identityRecord.get())) {
|
if (isNonBlockingApprovalRequired(identityRecord)) {
|
||||||
Log.i(TAG, "Setting approval status...");
|
Log.i(TAG, "Setting approval status...");
|
||||||
identityDatabase.setApproval(recipientId, nonBlockingApproval);
|
cache.setApproval(identityRecord, recipientId, nonBlockingApproval);
|
||||||
return SaveResult.NON_BLOCKING_APPROVAL_REQUIRED;
|
return SaveResult.NON_BLOCKING_APPROVAL_REQUIRED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,14 +94,8 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey) {
|
|
||||||
return saveIdentity(address, identityKey, false) == SaveResult.UPDATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) {
|
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) {
|
||||||
synchronized (LOCK) {
|
|
||||||
boolean isSelf = address.getName().equals(TextSecurePreferences.getLocalUuid(context).toString()) ||
|
boolean isSelf = address.getName().equals(TextSecurePreferences.getLocalUuid(context).toString()) ||
|
||||||
address.getName().equals(TextSecurePreferences.getLocalNumber(context));
|
address.getName().equals(TextSecurePreferences.getLocalNumber(context));
|
||||||
|
|
||||||
|
@ -105,7 +103,7 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
||||||
return identityKey.equals(IdentityKeyUtil.getIdentityKey(context));
|
return identityKey.equals(IdentityKeyUtil.getIdentityKey(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentityStoreRecord record = DatabaseFactory.getIdentityDatabase(context).getIdentityStoreRecord(address.getName());
|
IdentityStoreRecord record = cache.get(address.getName());
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case SENDING:
|
case SENDING:
|
||||||
|
@ -116,11 +114,10 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
||||||
throw new AssertionError("Unknown direction: " + direction);
|
throw new AssertionError("Unknown direction: " + direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IdentityKey getIdentity(SignalProtocolAddress address) {
|
public IdentityKey getIdentity(SignalProtocolAddress address) {
|
||||||
IdentityStoreRecord record = DatabaseFactory.getIdentityDatabase(context).getIdentityStoreRecord(address.getName());
|
IdentityStoreRecord record = cache.get(address.getName());
|
||||||
return record != null ? record.getIdentityKey() : null;
|
return record != null ? record.getIdentityKey() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,18 +145,47 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNonBlockingApprovalRequired(IdentityRecord identityRecord) {
|
private boolean isNonBlockingApprovalRequired(IdentityStoreRecord record) {
|
||||||
return isNonBlockingApprovalRequired(identityRecord.isFirstUse(), identityRecord.getTimestamp(), identityRecord.isApprovedNonBlocking());
|
return !record.getFirstUse() &&
|
||||||
|
!record.getNonblockingApproval() &&
|
||||||
|
System.currentTimeMillis() - record.getTimestamp() < TimeUnit.SECONDS.toMillis(TIMESTAMP_THRESHOLD_SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNonBlockingApprovalRequired(IdentityStoreRecord identityRecord) {
|
private static final class Cache {
|
||||||
return isNonBlockingApprovalRequired(identityRecord.getFirstUse(), identityRecord.getTimestamp(), identityRecord.getNonblockingApproval());
|
|
||||||
|
private final Context context;
|
||||||
|
private final Map<String, IdentityStoreRecord> cache;
|
||||||
|
|
||||||
|
Cache(@NonNull Context context) {
|
||||||
|
this.context = context;
|
||||||
|
this.cache = new LRUCache<>(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNonBlockingApprovalRequired(boolean firstUse, long timestamp, boolean nonblockingApproval) {
|
public synchronized @Nullable IdentityStoreRecord get(@NonNull String addressName) {
|
||||||
return !firstUse &&
|
if (cache.containsKey(addressName)) {
|
||||||
!nonblockingApproval &&
|
return cache.get(addressName);
|
||||||
System.currentTimeMillis() - timestamp < TimeUnit.SECONDS.toMillis(TIMESTAMP_THRESHOLD_SECONDS);
|
} else {
|
||||||
|
IdentityStoreRecord record = DatabaseFactory.getIdentityDatabase(context).getIdentityStoreRecord(addressName);
|
||||||
|
cache.put(addressName, record);
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void save(@NonNull String addressName, @NonNull RecipientId recipientId, @NonNull IdentityKey identityKey, @NonNull VerifiedStatus verifiedStatus, boolean firstUse, long timestamp, boolean nonBlockingApproval) {
|
||||||
|
DatabaseFactory.getIdentityDatabase(context).saveIdentity(addressName, recipientId, identityKey, verifiedStatus, firstUse, timestamp, nonBlockingApproval);
|
||||||
|
cache.put(addressName, new IdentityStoreRecord(addressName, identityKey, verifiedStatus, firstUse, timestamp, nonBlockingApproval));
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void setApproval(@NonNull IdentityStoreRecord record, @NonNull RecipientId recipientId, boolean nonblockingApproval) {
|
||||||
|
DatabaseFactory.getIdentityDatabase(context).setApproval(record.getAddressName(), recipientId, nonblockingApproval);
|
||||||
|
cache.put(record.getAddressName(),
|
||||||
|
new IdentityStoreRecord(record.getAddressName(),
|
||||||
|
record.getIdentityKey(),
|
||||||
|
record.getVerifiedStatus(),
|
||||||
|
record.getFirstUse(),
|
||||||
|
record.getTimestamp(),
|
||||||
|
nonblockingApproval));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SaveResult {
|
public enum SaveResult {
|
||||||
|
|
|
@ -222,12 +222,16 @@ public class IdentityDatabase extends Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setApproval(@NonNull RecipientId recipientId, boolean nonBlockingApproval) {
|
public void setApproval(@NonNull RecipientId recipientId, boolean nonBlockingApproval) {
|
||||||
|
setApproval(Recipient.resolved(recipientId).requireServiceId(), recipientId, nonBlockingApproval);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApproval(@NonNull String addressName, @NonNull RecipientId recipientId, boolean nonBlockingApproval) {
|
||||||
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
|
||||||
|
|
||||||
ContentValues contentValues = new ContentValues(2);
|
ContentValues contentValues = new ContentValues(2);
|
||||||
contentValues.put(NONBLOCKING_APPROVAL, nonBlockingApproval);
|
contentValues.put(NONBLOCKING_APPROVAL, nonBlockingApproval);
|
||||||
|
|
||||||
database.update(TABLE_NAME, contentValues, ADDRESS + " = ?", SqlUtil.buildArgs(Recipient.resolved(recipientId).requireServiceId()));
|
database.update(TABLE_NAME, contentValues, ADDRESS + " = ?", SqlUtil.buildArgs(addressName));
|
||||||
|
|
||||||
DatabaseFactory.getRecipientDatabase(context).markNeedsSync(recipientId);
|
DatabaseFactory.getRecipientDatabase(context).markNeedsSync(recipientId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,10 @@ import androidx.annotation.NonNull;
|
||||||
import org.thoughtcrime.securesms.KbsEnclave;
|
import org.thoughtcrime.securesms.KbsEnclave;
|
||||||
import org.thoughtcrime.securesms.components.TypingStatusRepository;
|
import org.thoughtcrime.securesms.components.TypingStatusRepository;
|
||||||
import org.thoughtcrime.securesms.components.TypingStatusSender;
|
import org.thoughtcrime.securesms.components.TypingStatusSender;
|
||||||
|
import org.thoughtcrime.securesms.crypto.storage.SignalSenderKeyStore;
|
||||||
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
|
||||||
|
import org.thoughtcrime.securesms.crypto.storage.TextSecurePreKeyStore;
|
||||||
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseObserver;
|
import org.thoughtcrime.securesms.database.DatabaseObserver;
|
||||||
import org.thoughtcrime.securesms.database.PendingRetryReceiptCache;
|
import org.thoughtcrime.securesms.database.PendingRetryReceiptCache;
|
||||||
import org.thoughtcrime.securesms.groups.GroupsV2Authorization;
|
import org.thoughtcrime.securesms.groups.GroupsV2Authorization;
|
||||||
|
@ -90,6 +94,10 @@ public class ApplicationDependencies {
|
||||||
private static volatile PendingRetryReceiptCache pendingRetryReceiptCache;
|
private static volatile PendingRetryReceiptCache pendingRetryReceiptCache;
|
||||||
private static volatile SignalWebSocket signalWebSocket;
|
private static volatile SignalWebSocket signalWebSocket;
|
||||||
private static volatile MessageNotifier messageNotifier;
|
private static volatile MessageNotifier messageNotifier;
|
||||||
|
private static volatile TextSecureIdentityKeyStore identityStore;
|
||||||
|
private static volatile TextSecureSessionStore sessionStore;
|
||||||
|
private static volatile TextSecurePreKeyStore preKeyStore;
|
||||||
|
private static volatile SignalSenderKeyStore senderKeyStore;
|
||||||
|
|
||||||
@MainThread
|
@MainThread
|
||||||
public static void init(@NonNull Application application, @NonNull Provider provider) {
|
public static void init(@NonNull Application application, @NonNull Provider provider) {
|
||||||
|
@ -499,6 +507,50 @@ public class ApplicationDependencies {
|
||||||
return signalWebSocket;
|
return signalWebSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static @NonNull TextSecureIdentityKeyStore getIdentityStore() {
|
||||||
|
if (identityStore == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (identityStore == null) {
|
||||||
|
identityStore = provider.provideIdentityStore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return identityStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NonNull TextSecureSessionStore getSessionStore() {
|
||||||
|
if (sessionStore == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (sessionStore == null) {
|
||||||
|
sessionStore = provider.provideSessionStore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sessionStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NonNull TextSecurePreKeyStore getPreKeyStore() {
|
||||||
|
if (preKeyStore == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (preKeyStore == null) {
|
||||||
|
preKeyStore = provider.providePreKeyStore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return preKeyStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NonNull SignalSenderKeyStore getSenderKeyStore() {
|
||||||
|
if (senderKeyStore == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (senderKeyStore == null) {
|
||||||
|
senderKeyStore = provider.provideSenderKeyStore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return senderKeyStore;
|
||||||
|
}
|
||||||
|
|
||||||
public interface Provider {
|
public interface Provider {
|
||||||
@NonNull GroupsV2Operations provideGroupsV2Operations();
|
@NonNull GroupsV2Operations provideGroupsV2Operations();
|
||||||
@NonNull SignalServiceAccountManager provideSignalServiceAccountManager();
|
@NonNull SignalServiceAccountManager provideSignalServiceAccountManager();
|
||||||
|
@ -527,5 +579,9 @@ public class ApplicationDependencies {
|
||||||
@NonNull PendingRetryReceiptManager providePendingRetryReceiptManager();
|
@NonNull PendingRetryReceiptManager providePendingRetryReceiptManager();
|
||||||
@NonNull PendingRetryReceiptCache providePendingRetryReceiptCache();
|
@NonNull PendingRetryReceiptCache providePendingRetryReceiptCache();
|
||||||
@NonNull SignalWebSocket provideSignalWebSocket();
|
@NonNull SignalWebSocket provideSignalWebSocket();
|
||||||
|
@NonNull TextSecureIdentityKeyStore provideIdentityStore();
|
||||||
|
@NonNull TextSecureSessionStore provideSessionStore();
|
||||||
|
@NonNull TextSecurePreKeyStore providePreKeyStore();
|
||||||
|
@NonNull SignalSenderKeyStore provideSenderKeyStore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,10 @@ import org.thoughtcrime.securesms.components.TypingStatusRepository;
|
||||||
import org.thoughtcrime.securesms.components.TypingStatusSender;
|
import org.thoughtcrime.securesms.components.TypingStatusSender;
|
||||||
import org.thoughtcrime.securesms.crypto.ReentrantSessionLock;
|
import org.thoughtcrime.securesms.crypto.ReentrantSessionLock;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
|
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
|
||||||
|
import org.thoughtcrime.securesms.crypto.storage.SignalSenderKeyStore;
|
||||||
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
|
||||||
|
import org.thoughtcrime.securesms.crypto.storage.TextSecurePreKeyStore;
|
||||||
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseObserver;
|
import org.thoughtcrime.securesms.database.DatabaseObserver;
|
||||||
import org.thoughtcrime.securesms.database.JobDatabase;
|
import org.thoughtcrime.securesms.database.JobDatabase;
|
||||||
import org.thoughtcrime.securesms.database.PendingRetryReceiptCache;
|
import org.thoughtcrime.securesms.database.PendingRetryReceiptCache;
|
||||||
|
@ -54,6 +58,7 @@ import org.thoughtcrime.securesms.util.EarlyMessageCache;
|
||||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.FrameRateTracker;
|
import org.thoughtcrime.securesms.util.FrameRateTracker;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
import org.whispersystems.libsignal.state.SignalProtocolStore;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
||||||
|
@ -259,6 +264,26 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr
|
||||||
return signalWebSocket;
|
return signalWebSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull TextSecureIdentityKeyStore provideIdentityStore() {
|
||||||
|
return new TextSecureIdentityKeyStore(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull TextSecureSessionStore provideSessionStore() {
|
||||||
|
return new TextSecureSessionStore(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull TextSecurePreKeyStore providePreKeyStore() {
|
||||||
|
return new TextSecurePreKeyStore(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull SignalSenderKeyStore provideSenderKeyStore() {
|
||||||
|
return new SignalSenderKeyStore(context);
|
||||||
|
}
|
||||||
|
|
||||||
private @NonNull WebSocketFactory provideWebSocketFactory(@NonNull SignalWebSocketHealthMonitor healthMonitor) {
|
private @NonNull WebSocketFactory provideWebSocketFactory(@NonNull SignalWebSocketHealthMonitor healthMonitor) {
|
||||||
return new WebSocketFactory() {
|
return new WebSocketFactory() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -84,7 +84,7 @@ public class AutomaticSessionResetJob extends BaseJob {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRun() throws Exception {
|
protected void onRun() throws Exception {
|
||||||
SessionUtil.archiveSession(context, recipientId, deviceId);
|
SessionUtil.archiveSession(recipientId, deviceId);
|
||||||
DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(recipientId);
|
DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(recipientId);
|
||||||
insertLocalMessage();
|
insertLocalMessage();
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,7 @@ public class ResendMessageJob extends BaseJob {
|
||||||
.map(device -> new SignalProtocolAddress(recipient.requireServiceId(), device))
|
.map(device -> new SignalProtocolAddress(recipient.requireServiceId(), device))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
new SignalSenderKeyStore(context).markSenderKeySharedWith(distributionId, addresses);
|
ApplicationDependencies.getSenderKeyStore().markSenderKeySharedWith(distributionId, addresses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -373,7 +373,7 @@ public class RetrieveProfileJob extends BaseJob {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentityUtil.saveIdentity(context, recipient.requireServiceId(), identityKey);
|
IdentityUtil.saveIdentity(recipient.requireServiceId(), identityKey);
|
||||||
} catch (InvalidKeyException | IOException e) {
|
} catch (InvalidKeyException | IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,7 @@ public final class SenderKeyDistributionSendJob extends BaseJob {
|
||||||
.map(device -> new SignalProtocolAddress(recipient.requireServiceId(), device))
|
.map(device -> new SignalProtocolAddress(recipient.requireServiceId(), device))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
new SignalSenderKeyStore(context).markSenderKeySharedWith(distributionId, addresses);
|
ApplicationDependencies.getSenderKeyStore().markSenderKeySharedWith(distributionId, addresses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -694,8 +694,7 @@ public final class MessageContentProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (insertResult.isPresent()) {
|
if (insertResult.isPresent()) {
|
||||||
SessionStore sessionStore = new TextSecureSessionStore(context);
|
ApplicationDependencies.getSessionStore().deleteAllSessions(content.getSender().getIdentifier());
|
||||||
sessionStore.deleteAllSessions(content.getSender().getIdentifier());
|
|
||||||
|
|
||||||
SecurityEvent.broadcastSecurityUpdateEvent(context);
|
SecurityEvent.broadcastSecurityUpdateEvent(context);
|
||||||
ApplicationDependencies.getMessageNotifier().updateNotification(context, insertResult.get().getThreadId());
|
ApplicationDependencies.getMessageNotifier().updateNotification(context, insertResult.get().getThreadId());
|
||||||
|
@ -717,8 +716,7 @@ public final class MessageContentProcessor {
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
|
|
||||||
if (!recipient.isGroup()) {
|
if (!recipient.isGroup()) {
|
||||||
SessionStore sessionStore = new TextSecureSessionStore(context);
|
ApplicationDependencies.getSessionStore().deleteAllSessions(recipient.requireServiceId());
|
||||||
sessionStore.deleteAllSessions(recipient.requireServiceId());
|
|
||||||
|
|
||||||
SecurityEvent.broadcastSecurityUpdateEvent(context);
|
SecurityEvent.broadcastSecurityUpdateEvent(context);
|
||||||
|
|
||||||
|
@ -1884,10 +1882,10 @@ public final class MessageContentProcessor {
|
||||||
|
|
||||||
if (decryptionErrorMessage.getDeviceId() == SignalServiceAddress.DEFAULT_DEVICE_ID &&
|
if (decryptionErrorMessage.getDeviceId() == SignalServiceAddress.DEFAULT_DEVICE_ID &&
|
||||||
decryptionErrorMessage.getRatchetKey().isPresent() &&
|
decryptionErrorMessage.getRatchetKey().isPresent() &&
|
||||||
SessionUtil.ratchetKeyMatches(context, requester, content.getSenderDevice(), decryptionErrorMessage.getRatchetKey().get()))
|
SessionUtil.ratchetKeyMatches(requester, content.getSenderDevice(), decryptionErrorMessage.getRatchetKey().get()))
|
||||||
{
|
{
|
||||||
warn(content.getTimestamp(), "[RetryReceipt-I] Ratchet key matches. Archiving the session.");
|
warn(content.getTimestamp(), "[RetryReceipt-I] Ratchet key matches. Archiving the session.");
|
||||||
SessionUtil.archiveSession(context, requester.getId(), content.getSenderDevice());
|
SessionUtil.archiveSession(requester.getId(), content.getSenderDevice());
|
||||||
archivedSession = true;
|
archivedSession = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -203,7 +203,7 @@ public final class CodeVerificationRequest {
|
||||||
byte[] unidentifiedAccessKey = UnidentifiedAccess.deriveAccessKeyFrom(profileKey);
|
byte[] unidentifiedAccessKey = UnidentifiedAccess.deriveAccessKeyFrom(profileKey);
|
||||||
|
|
||||||
TextSecurePreferences.setLocalRegistrationId(context, registrationId);
|
TextSecurePreferences.setLocalRegistrationId(context, registrationId);
|
||||||
SessionUtil.archiveAllSessions(context);
|
SessionUtil.archiveAllSessions();
|
||||||
SenderKeyUtil.clearAllState(context);
|
SenderKeyUtil.clearAllState(context);
|
||||||
|
|
||||||
SignalServiceAccountManager accountManager = AccountManagerFactory.createUnauthenticated(context, credentials.getE164number(), credentials.getPassword());
|
SignalServiceAccountManager accountManager = AccountManagerFactory.createUnauthenticated(context, credentials.getE164number(), credentials.getPassword());
|
||||||
|
|
|
@ -10,7 +10,6 @@ import org.signal.core.util.concurrent.SignalExecutors;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.crypto.ReentrantSessionLock;
|
import org.thoughtcrime.securesms.crypto.ReentrantSessionLock;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
|
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
|
@ -34,7 +33,6 @@ import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||||
import org.whispersystems.libsignal.state.IdentityKeyStore;
|
|
||||||
import org.whispersystems.libsignal.state.SessionRecord;
|
import org.whispersystems.libsignal.state.SessionRecord;
|
||||||
import org.whispersystems.libsignal.state.SessionStore;
|
import org.whispersystems.libsignal.state.SessionStore;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
@ -145,13 +143,12 @@ public final class IdentityUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveIdentity(Context context, String user, IdentityKey identityKey) {
|
public static void saveIdentity(String user, IdentityKey identityKey) {
|
||||||
try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
||||||
IdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(context);
|
SessionStore sessionStore = ApplicationDependencies.getSessionStore();
|
||||||
SessionStore sessionStore = new TextSecureSessionStore(context);
|
|
||||||
SignalProtocolAddress address = new SignalProtocolAddress(user, 1);
|
SignalProtocolAddress address = new SignalProtocolAddress(user, 1);
|
||||||
|
|
||||||
if (identityKeyStore.saveIdentity(address, identityKey)) {
|
if (ApplicationDependencies.getIdentityStore().saveIdentity(address, identityKey)) {
|
||||||
if (sessionStore.containsSession(address)) {
|
if (sessionStore.containsSession(address)) {
|
||||||
SessionRecord sessionRecord = sessionStore.loadSession(address);
|
SessionRecord sessionRecord = sessionStore.loadSession(address);
|
||||||
sessionRecord.archiveCurrentState();
|
sessionRecord.archiveCurrentState();
|
||||||
|
@ -187,7 +184,7 @@ public final class IdentityUtil {
|
||||||
(identityRecord.isPresent() && !identityRecord.get().getIdentityKey().equals(verifiedMessage.getIdentityKey())) ||
|
(identityRecord.isPresent() && !identityRecord.get().getIdentityKey().equals(verifiedMessage.getIdentityKey())) ||
|
||||||
(identityRecord.isPresent() && identityRecord.get().getVerifiedStatus() != IdentityDatabase.VerifiedStatus.VERIFIED)))
|
(identityRecord.isPresent() && identityRecord.get().getVerifiedStatus() != IdentityDatabase.VerifiedStatus.VERIFIED)))
|
||||||
{
|
{
|
||||||
saveIdentity(context, verifiedMessage.getDestination().getIdentifier(), verifiedMessage.getIdentityKey());
|
saveIdentity(verifiedMessage.getDestination().getIdentifier(), verifiedMessage.getIdentityKey());
|
||||||
identityDatabase.setVerified(recipient.getId(), verifiedMessage.getIdentityKey(), IdentityDatabase.VerifiedStatus.VERIFIED);
|
identityDatabase.setVerified(recipient.getId(), verifiedMessage.getIdentityKey(), IdentityDatabase.VerifiedStatus.VERIFIED);
|
||||||
markIdentityVerified(context, recipient, true, true);
|
markIdentityVerified(context, recipient, true, true);
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue