Notifications for a few merge-related scenarios
This commit is contained in:
parent
78ce34b9d3
commit
a49a6f2057
40 changed files with 2764 additions and 553 deletions
|
@ -1523,7 +1523,11 @@ export class SignalProtocolStore extends EventEmitter {
|
|||
|
||||
switch (direction) {
|
||||
case Direction.Sending:
|
||||
return this.isTrustedForSending(publicKey, identityRecord);
|
||||
return this.isTrustedForSending(
|
||||
encodedAddress.uuid,
|
||||
publicKey,
|
||||
identityRecord
|
||||
);
|
||||
case Direction.Receiving:
|
||||
return true;
|
||||
default:
|
||||
|
@ -1533,11 +1537,31 @@ export class SignalProtocolStore extends EventEmitter {
|
|||
|
||||
// https://github.com/signalapp/Signal-Android/blob/fc3db538bcaa38dc149712a483d3032c9c1f3998/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStore.java#L233
|
||||
isTrustedForSending(
|
||||
uuid: UUID,
|
||||
publicKey: Uint8Array,
|
||||
identityRecord?: IdentityKeyType
|
||||
): boolean {
|
||||
if (!identityRecord) {
|
||||
log.info('isTrustedForSending: No previous record, returning true...');
|
||||
// To track key changes across session switches, we save an old identity key on the
|
||||
// conversation.
|
||||
const conversation = window.ConversationController.get(uuid.toString());
|
||||
const previousIdentityKeyBase64 = conversation?.get(
|
||||
'previousIdentityKey'
|
||||
);
|
||||
if (conversation && previousIdentityKeyBase64) {
|
||||
const previousIdentityKey = Bytes.fromBase64(previousIdentityKeyBase64);
|
||||
|
||||
if (!constantTimeEqual(previousIdentityKey, publicKey)) {
|
||||
log.info(
|
||||
'isTrustedForSending: previousIdentityKey does not match, returning false'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
log.info(
|
||||
'isTrustedForSending: No previous record or previousIdentityKey, returning true'
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1552,7 +1576,7 @@ export class SignalProtocolStore extends EventEmitter {
|
|||
return false;
|
||||
}
|
||||
if (identityRecord.verified === VerifiedStatus.UNVERIFIED) {
|
||||
log.error('isTrustedIdentity: Needs unverified approval!');
|
||||
log.error('isTrustedForSending: Needs unverified approval!');
|
||||
return false;
|
||||
}
|
||||
if (this.isNonBlockingApprovalRequired(identityRecord)) {
|
||||
|
@ -1648,6 +1672,8 @@ export class SignalProtocolStore extends EventEmitter {
|
|||
nonblockingApproval,
|
||||
});
|
||||
|
||||
this.checkPreviousKey(encodedAddress.uuid, publicKey, 'saveIdentity');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1690,7 +1716,7 @@ export class SignalProtocolStore extends EventEmitter {
|
|||
// See `addKeyChange` in `ts/models/conversations.ts` for sender key info
|
||||
// update caused by this.
|
||||
try {
|
||||
this.emit('keychange', encodedAddress.uuid);
|
||||
this.emit('keychange', encodedAddress.uuid, 'saveIdentity - change');
|
||||
} catch (error) {
|
||||
log.error(
|
||||
'saveIdentity: error triggering keychange:',
|
||||
|
@ -1822,6 +1848,37 @@ export class SignalProtocolStore extends EventEmitter {
|
|||
return VerifiedStatus.DEFAULT;
|
||||
}
|
||||
|
||||
// To track key changes across session switches, we save an old identity key on the
|
||||
// conversation. Whenever we get a new identity key for that contact, we need to
|
||||
// check it against that saved key - no need to pop a key change warning if it is
|
||||
// the same!
|
||||
checkPreviousKey(uuid: UUID, publicKey: Uint8Array, context: string): void {
|
||||
const conversation = window.ConversationController.get(uuid.toString());
|
||||
const previousIdentityKeyBase64 = conversation?.get('previousIdentityKey');
|
||||
if (conversation && previousIdentityKeyBase64) {
|
||||
const previousIdentityKey = Bytes.fromBase64(previousIdentityKeyBase64);
|
||||
|
||||
try {
|
||||
if (!constantTimeEqual(previousIdentityKey, publicKey)) {
|
||||
this.emit(
|
||||
'keychange',
|
||||
uuid,
|
||||
`${context} - previousIdentityKey check`
|
||||
);
|
||||
}
|
||||
|
||||
// We only want to clear previousIdentityKey on a match, or on successfully emit.
|
||||
conversation.set({ previousIdentityKey: undefined });
|
||||
window.Signal.Data.updateConversation(conversation.attributes);
|
||||
} catch (error) {
|
||||
log.error(
|
||||
'saveIdentity: error triggering keychange:',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See https://github.com/signalapp/Signal-Android/blob/fc3db538bcaa38dc149712a483d3032c9c1f3998/app/src/main/java/org/thoughtcrime/securesms/database/IdentityDatabase.java#L184
|
||||
async updateIdentityAfterSync(
|
||||
uuid: UUID,
|
||||
|
@ -1851,10 +1908,11 @@ export class SignalProtocolStore extends EventEmitter {
|
|||
nonblockingApproval: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (hadEntry && !keyMatches) {
|
||||
if (!hadEntry) {
|
||||
this.checkPreviousKey(uuid, publicKey, 'updateIdentityAfterSync');
|
||||
} else if (hadEntry && !keyMatches) {
|
||||
try {
|
||||
this.emit('keychange', uuid);
|
||||
this.emit('keychange', uuid, 'updateIdentityAfterSync - change');
|
||||
} catch (error) {
|
||||
log.error(
|
||||
'updateIdentityAfterSync: error triggering keychange:',
|
||||
|
@ -1903,7 +1961,10 @@ export class SignalProtocolStore extends EventEmitter {
|
|||
return false;
|
||||
}
|
||||
|
||||
async removeIdentityKey(uuid: UUID): Promise<void> {
|
||||
async removeIdentityKey(
|
||||
uuid: UUID,
|
||||
options?: { disableSessionDeletion: boolean }
|
||||
): Promise<void> {
|
||||
if (!this.identityKeys) {
|
||||
throw new Error('removeIdentityKey: this.identityKeys not yet cached!');
|
||||
}
|
||||
|
@ -1911,7 +1972,9 @@ export class SignalProtocolStore extends EventEmitter {
|
|||
const id = uuid.toString();
|
||||
this.identityKeys.delete(id);
|
||||
await window.Signal.Data.removeIdentityKeyById(id);
|
||||
await this.removeAllSessions(id);
|
||||
if (!options?.disableSessionDeletion) {
|
||||
await this.removeAllSessions(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Not yet processed messages - for resiliency
|
||||
|
@ -2197,7 +2260,7 @@ export class SignalProtocolStore extends EventEmitter {
|
|||
|
||||
public override on(
|
||||
name: 'keychange',
|
||||
handler: (theirUuid: UUID) => unknown
|
||||
handler: (theirUuid: UUID, reason: string) => unknown
|
||||
): this;
|
||||
|
||||
public override on(name: 'removeAllData', handler: () => unknown): this;
|
||||
|
@ -2212,7 +2275,11 @@ export class SignalProtocolStore extends EventEmitter {
|
|||
|
||||
public override emit(name: 'removePreKey', ourUuid: UUID): boolean;
|
||||
|
||||
public override emit(name: 'keychange', theirUuid: UUID): boolean;
|
||||
public override emit(
|
||||
name: 'keychange',
|
||||
theirUuid: UUID,
|
||||
reason: string
|
||||
): boolean;
|
||||
|
||||
public override emit(name: 'removeAllData'): boolean;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue