Use UUID-only sender certificate when applicable
This commit is contained in:
parent
cfd77bf968
commit
18ccda83ba
3 changed files with 70 additions and 25 deletions
|
@ -17,7 +17,12 @@ import {
|
||||||
} from '../components/conversation/conversation-details/PendingInvites';
|
} from '../components/conversation/conversation-details/PendingInvites';
|
||||||
import { GroupV2Membership } from '../components/conversation/conversation-details/ConversationDetailsMembershipList';
|
import { GroupV2Membership } from '../components/conversation/conversation-details/ConversationDetailsMembershipList';
|
||||||
import { CallMode, CallHistoryDetailsType } from '../types/Calling';
|
import { CallMode, CallHistoryDetailsType } from '../types/Calling';
|
||||||
import { CallbackResultType, GroupV2InfoType } from '../textsecure/SendMessage';
|
import {
|
||||||
|
CallbackResultType,
|
||||||
|
GroupV2InfoType,
|
||||||
|
SendMetadataType,
|
||||||
|
SendOptionsType,
|
||||||
|
} from '../textsecure/SendMessage';
|
||||||
import {
|
import {
|
||||||
ConversationType,
|
ConversationType,
|
||||||
ConversationTypeType,
|
ConversationTypeType,
|
||||||
|
@ -26,6 +31,7 @@ import { ColorType } from '../types/Colors';
|
||||||
import { MessageModel } from './messages';
|
import { MessageModel } from './messages';
|
||||||
import { isMuted } from '../util/isMuted';
|
import { isMuted } from '../util/isMuted';
|
||||||
import { isConversationUnregistered } from '../util/isConversationUnregistered';
|
import { isConversationUnregistered } from '../util/isConversationUnregistered';
|
||||||
|
import { assert } from '../util/assert';
|
||||||
import { missingCaseError } from '../util/missingCaseError';
|
import { missingCaseError } from '../util/missingCaseError';
|
||||||
import { sniffImageMimeType } from '../util/sniffImageMimeType';
|
import { sniffImageMimeType } from '../util/sniffImageMimeType';
|
||||||
import { MIMEType, IMAGE_WEBP } from '../types/MIME';
|
import { MIMEType, IMAGE_WEBP } from '../types/MIME';
|
||||||
|
@ -44,6 +50,11 @@ import { BodyRangesType } from '../types/Util';
|
||||||
import { getTextWithMentions } from '../util';
|
import { getTextWithMentions } from '../util';
|
||||||
import { migrateColor } from '../util/migrateColor';
|
import { migrateColor } from '../util/migrateColor';
|
||||||
import { isNotNil } from '../util/isNotNil';
|
import { isNotNil } from '../util/isNotNil';
|
||||||
|
import {
|
||||||
|
PhoneNumberSharingMode,
|
||||||
|
parsePhoneNumberSharingMode,
|
||||||
|
} from '../util/phoneNumberSharingMode';
|
||||||
|
import { SerializedCertificateType } from '../metadata/SecretSessionCipher';
|
||||||
|
|
||||||
/* eslint-disable more/no-then */
|
/* eslint-disable more/no-then */
|
||||||
window.Whisper = window.Whisper || {};
|
window.Whisper = window.Whisper || {};
|
||||||
|
@ -3544,19 +3555,17 @@ export class ConversationModel extends window.Backbone.Model<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSendOptions(options = {}): WhatIsThis {
|
getSendOptions(options = {}): SendOptionsType {
|
||||||
const senderCertificate = window.storage.get('senderCertificate');
|
|
||||||
const sendMetadata = this.getSendMetadata(options);
|
const sendMetadata = this.getSendMetadata(options);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
senderCertificate,
|
|
||||||
sendMetadata,
|
sendMetadata,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getSendMetadata(
|
getSendMetadata(
|
||||||
options: { syncMessage?: string; disableMeCheck?: boolean } = {}
|
options: { syncMessage?: string; disableMeCheck?: boolean } = {}
|
||||||
): WhatIsThis | null {
|
): SendMetadataType | undefined {
|
||||||
const { syncMessage, disableMeCheck } = options;
|
const { syncMessage, disableMeCheck } = options;
|
||||||
|
|
||||||
// START: this code has an Expiration date of ~2018/11/21
|
// START: this code has an Expiration date of ~2018/11/21
|
||||||
|
@ -3566,7 +3575,7 @@ export class ConversationModel extends window.Backbone.Model<
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
const me = window.ConversationController.get(myId)!;
|
const me = window.ConversationController.get(myId)!;
|
||||||
if (!disableMeCheck && me.get('sealedSender') === SEALED_SENDER.DISABLED) {
|
if (!disableMeCheck && me.get('sealedSender') === SEALED_SENDER.DISABLED) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
// END
|
// END
|
||||||
|
|
||||||
|
@ -3583,16 +3592,19 @@ export class ConversationModel extends window.Backbone.Model<
|
||||||
|
|
||||||
// We never send sync messages as sealed sender
|
// We never send sync messages as sealed sender
|
||||||
if (syncMessage && this.isMe()) {
|
if (syncMessage && this.isMe()) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const e164 = this.get('e164');
|
const e164 = this.get('e164');
|
||||||
const uuid = this.get('uuid');
|
const uuid = this.get('uuid');
|
||||||
|
|
||||||
|
const senderCertificate = this.getSenderCertificateForDirectConversation();
|
||||||
|
|
||||||
// If we've never fetched user's profile, we default to what we have
|
// If we've never fetched user's profile, we default to what we have
|
||||||
if (sealedSender === SEALED_SENDER.UNKNOWN) {
|
if (sealedSender === SEALED_SENDER.UNKNOWN) {
|
||||||
const info = {
|
const info = {
|
||||||
accessKey: accessKey || arrayBufferToBase64(getRandomBytes(16)),
|
accessKey: accessKey || arrayBufferToBase64(getRandomBytes(16)),
|
||||||
|
senderCertificate,
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
...(e164 ? { [e164]: info } : {}),
|
...(e164 ? { [e164]: info } : {}),
|
||||||
|
@ -3601,7 +3613,7 @@ export class ConversationModel extends window.Backbone.Model<
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sealedSender === SEALED_SENDER.DISABLED) {
|
if (sealedSender === SEALED_SENDER.DISABLED) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const info = {
|
const info = {
|
||||||
|
@ -3609,6 +3621,7 @@ export class ConversationModel extends window.Backbone.Model<
|
||||||
accessKey && sealedSender === SEALED_SENDER.ENABLED
|
accessKey && sealedSender === SEALED_SENDER.ENABLED
|
||||||
? accessKey
|
? accessKey
|
||||||
: arrayBufferToBase64(getRandomBytes(16)),
|
: arrayBufferToBase64(getRandomBytes(16)),
|
||||||
|
senderCertificate,
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -3617,6 +3630,48 @@ export class ConversationModel extends window.Backbone.Model<
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getSenderCertificateForDirectConversation():
|
||||||
|
| undefined
|
||||||
|
| SerializedCertificateType {
|
||||||
|
if (!this.isPrivate()) {
|
||||||
|
throw new Error(
|
||||||
|
'getSenderCertificateForDirectConversation should only be called for direct conversations'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const phoneNumberSharingMode = parsePhoneNumberSharingMode(
|
||||||
|
window.storage.get('phoneNumberSharingMode')
|
||||||
|
);
|
||||||
|
|
||||||
|
let storageKey: 'senderCertificate' | 'senderCertificateNoE164';
|
||||||
|
switch (phoneNumberSharingMode) {
|
||||||
|
case PhoneNumberSharingMode.Everybody:
|
||||||
|
storageKey = 'senderCertificate';
|
||||||
|
break;
|
||||||
|
case PhoneNumberSharingMode.ContactsOnly: {
|
||||||
|
const isInSystemContacts = Boolean(this.get('name'));
|
||||||
|
storageKey = isInSystemContacts
|
||||||
|
? 'senderCertificate'
|
||||||
|
: 'senderCertificateNoE164';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PhoneNumberSharingMode.Nobody:
|
||||||
|
storageKey = 'senderCertificateNoE164';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw missingCaseError(phoneNumberSharingMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = window.storage.get<SerializedCertificateType>(storageKey);
|
||||||
|
assert(
|
||||||
|
result,
|
||||||
|
`getSenderCertificateForDirectConversation: couldn't find a certificate stored in ${JSON.stringify(
|
||||||
|
storageKey
|
||||||
|
)}. Returning undefined`
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Is this someone who is a contact, or are we sharing our profile with them?
|
// Is this someone who is a contact, or are we sharing our profile with them?
|
||||||
// Or is the person who added us to this group a contact or are we sharing profile
|
// Or is the person who added us to this group a contact or are we sharing profile
|
||||||
// with them?
|
// with them?
|
||||||
|
|
|
@ -26,10 +26,7 @@ import {
|
||||||
UnregisteredUserError,
|
UnregisteredUserError,
|
||||||
} from './Errors';
|
} from './Errors';
|
||||||
import { isValidNumber } from '../types/PhoneNumber';
|
import { isValidNumber } from '../types/PhoneNumber';
|
||||||
import {
|
import { SecretSessionCipher } from '../metadata/SecretSessionCipher';
|
||||||
SecretSessionCipher,
|
|
||||||
SerializedCertificateType,
|
|
||||||
} from '../metadata/SecretSessionCipher';
|
|
||||||
|
|
||||||
type OutgoingMessageOptionsType = SendOptionsType & {
|
type OutgoingMessageOptionsType = SendOptionsType & {
|
||||||
online?: boolean;
|
online?: boolean;
|
||||||
|
@ -62,8 +59,6 @@ export default class OutgoingMessage {
|
||||||
|
|
||||||
sendMetadata?: SendMetadataType;
|
sendMetadata?: SendMetadataType;
|
||||||
|
|
||||||
senderCertificate?: SerializedCertificateType;
|
|
||||||
|
|
||||||
online?: boolean;
|
online?: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -96,9 +91,8 @@ export default class OutgoingMessage {
|
||||||
this.failoverIdentifiers = [];
|
this.failoverIdentifiers = [];
|
||||||
this.unidentifiedDeliveries = [];
|
this.unidentifiedDeliveries = [];
|
||||||
|
|
||||||
const { sendMetadata, senderCertificate, online } = options;
|
const { sendMetadata, online } = options;
|
||||||
this.sendMetadata = sendMetadata;
|
this.sendMetadata = sendMetadata;
|
||||||
this.senderCertificate = senderCertificate;
|
|
||||||
this.online = online;
|
this.online = online;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,12 +338,8 @@ export default class OutgoingMessage {
|
||||||
} = {};
|
} = {};
|
||||||
const plaintext = this.getPlaintext();
|
const plaintext = this.getPlaintext();
|
||||||
|
|
||||||
const { sendMetadata, senderCertificate } = this;
|
const { sendMetadata } = this;
|
||||||
const info =
|
const { accessKey, senderCertificate } = sendMetadata?.[identifier] || {};
|
||||||
sendMetadata && sendMetadata[identifier]
|
|
||||||
? sendMetadata[identifier]
|
|
||||||
: { accessKey: undefined };
|
|
||||||
const { accessKey } = info;
|
|
||||||
|
|
||||||
if (accessKey && !senderCertificate) {
|
if (accessKey && !senderCertificate) {
|
||||||
window.log.warn(
|
window.log.warn(
|
||||||
|
@ -442,8 +432,8 @@ export default class OutgoingMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This ensures that we don't hit this codepath the next time through
|
// This ensures that we don't hit this codepath the next time through
|
||||||
if (info) {
|
if (sendMetadata) {
|
||||||
info.accessKey = undefined;
|
delete sendMetadata[identifier];
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.doSendMessage(identifier, deviceIds, recurse);
|
return this.doSendMessage(identifier, deviceIds, recurse);
|
||||||
|
|
|
@ -63,11 +63,11 @@ function stringToArrayBuffer(str: string): ArrayBuffer {
|
||||||
export type SendMetadataType = {
|
export type SendMetadataType = {
|
||||||
[identifier: string]: {
|
[identifier: string]: {
|
||||||
accessKey: string;
|
accessKey: string;
|
||||||
|
senderCertificate?: SerializedCertificateType;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SendOptionsType = {
|
export type SendOptionsType = {
|
||||||
senderCertificate?: SerializedCertificateType;
|
|
||||||
sendMetadata?: SendMetadataType;
|
sendMetadata?: SendMetadataType;
|
||||||
online?: boolean;
|
online?: boolean;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue