Send and receive PniSignatureMessage

This commit is contained in:
Fedor Indutny 2022-08-15 14:53:33 -07:00 committed by GitHub
parent 95be24e8f7
commit 00cfd92dd0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 1082 additions and 164 deletions

View file

@ -15,8 +15,9 @@ import {
} from '@signalapp/libsignal-client';
import type { QuotedMessageType } from '../model-types.d';
import type { ConversationModel } from '../models/conversations';
import { GLOBAL_ZONE } from '../SignalProtocolStore';
import { assert } from '../util/assert';
import { assert, strictAssert } from '../util/assert';
import { parseIntOrThrow } from '../util/parseIntOrThrow';
import { Address } from '../types/Address';
import { QualifiedAddress } from '../types/QualifiedAddress';
@ -65,6 +66,7 @@ import type {
import { concat, isEmpty, map } from '../util/iterables';
import type { SendTypesType } from '../util/handleMessageSend';
import { shouldSaveProto, sendTypesEnum } from '../util/handleMessageSend';
import { uuidToBytes } from '../util/uuidToBytes';
import { SignalService as Proto } from '../protobuf';
import * as log from '../logging/log';
import type { Avatar, EmbeddedContactType } from '../types/EmbeddedContact';
@ -574,11 +576,43 @@ class Message {
return proto;
}
encode() {
encode(): Uint8Array {
return Proto.DataMessage.encode(this.toProto()).finish();
}
}
type AddPniSignatureMessageToProtoOptionsType = Readonly<{
conversation?: ConversationModel;
proto: Proto.Content;
reason: string;
}>;
function addPniSignatureMessageToProto({
conversation,
proto,
reason,
}: AddPniSignatureMessageToProtoOptionsType): void {
if (!conversation) {
return;
}
const pniSignatureMessage = conversation?.getPniSignatureMessage();
if (!pniSignatureMessage) {
return;
}
log.info(
`addPniSignatureMessageToProto(${reason}): ` +
`adding pni signature for ${conversation.idForLogging()}`
);
// eslint-disable-next-line no-param-reassign
proto.pniSignatureMessage = {
pni: uuidToBytes(pniSignatureMessage.pni),
signature: pniSignatureMessage.signature,
};
}
export default class MessageSender {
pendingMessages: {
[id: string]: PQueue;
@ -944,7 +978,10 @@ export default class MessageSender {
}
async getContentMessage(
options: Readonly<MessageOptionsType>
options: Readonly<MessageOptionsType> &
Readonly<{
includePniSignatureMessage?: boolean;
}>
): Promise<Proto.Content> {
const message = await this.getHydratedMessage(options);
const dataMessage = message.toProto();
@ -952,6 +989,24 @@ export default class MessageSender {
const contentMessage = new Proto.Content();
contentMessage.dataMessage = dataMessage;
const { includePniSignatureMessage } = options;
if (includePniSignatureMessage) {
strictAssert(
message.recipients.length === 1,
'getContentMessage: includePniSignatureMessage is single recipient only'
);
const conversation = window.ConversationController.get(
message.recipients[0]
);
addPniSignatureMessageToProto({
conversation,
proto: contentMessage,
reason: `getContentMessage(${message.timestamp})`,
});
}
return contentMessage;
}
@ -1001,6 +1056,14 @@ export default class MessageSender {
const contentMessage = new Proto.Content();
contentMessage.typingMessage = typingMessage;
if (recipientId) {
addPniSignatureMessageToProto({
conversation: window.ConversationController.get(recipientId),
proto: contentMessage,
reason: `getTypingContentMessage(${finalTimestamp})`,
});
}
return contentMessage;
}
@ -1100,14 +1163,19 @@ export default class MessageSender {
groupId,
options,
urgent,
includePniSignatureMessage,
}: Readonly<{
messageOptions: MessageOptionsType;
contentHint: number;
groupId: string | undefined;
options?: SendOptionsType;
urgent: boolean;
includePniSignatureMessage?: boolean;
}>): Promise<CallbackResultType> {
const message = await this.getHydratedMessage(messageOptions);
const proto = await this.getContentMessage({
...messageOptions,
includePniSignatureMessage,
});
return new Promise((resolve, reject) => {
this.sendMessageProto({
@ -1121,9 +1189,9 @@ export default class MessageSender {
contentHint,
groupId,
options,
proto: message.toProto(),
recipients: message.recipients || [],
timestamp: message.timestamp,
proto,
recipients: messageOptions.recipients || [],
timestamp: messageOptions.timestamp,
urgent,
});
});
@ -1276,6 +1344,7 @@ export default class MessageSender {
storyContext,
timestamp,
urgent,
includePniSignatureMessage,
}: Readonly<{
attachments: ReadonlyArray<AttachmentType> | undefined;
contact?: Array<ContactWithHydratedAvatar>;
@ -1294,6 +1363,7 @@ export default class MessageSender {
storyContext?: StoryContextType;
timestamp: number;
urgent: boolean;
includePniSignatureMessage?: boolean;
}>): Promise<CallbackResultType> {
return this.sendMessage({
messageOptions: {
@ -1315,6 +1385,7 @@ export default class MessageSender {
groupId,
options,
urgent,
includePniSignatureMessage,
});
}
@ -1886,6 +1957,14 @@ export default class MessageSender {
const contentMessage = new Proto.Content();
contentMessage.callingMessage = callingMessage;
const conversation = window.ConversationController.get(recipientId);
addPniSignatureMessageToProto({
conversation,
proto: contentMessage,
reason: `sendCallingMessage(${finalTimestamp})`,
});
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return this.sendMessageProtoAndWait({
@ -1904,6 +1983,7 @@ export default class MessageSender {
senderE164?: string;
senderUuid?: string;
timestamps: Array<number>;
isDirectConversation: boolean;
options?: Readonly<SendOptionsType>;
}>
): Promise<CallbackResultType> {
@ -1918,6 +1998,7 @@ export default class MessageSender {
senderE164?: string;
senderUuid?: string;
timestamps: Array<number>;
isDirectConversation: boolean;
options?: Readonly<SendOptionsType>;
}>
): Promise<CallbackResultType> {
@ -1932,6 +2013,7 @@ export default class MessageSender {
senderE164?: string;
senderUuid?: string;
timestamps: Array<number>;
isDirectConversation: boolean;
options?: Readonly<SendOptionsType>;
}>
): Promise<CallbackResultType> {
@ -1946,12 +2028,14 @@ export default class MessageSender {
senderUuid,
timestamps,
type,
isDirectConversation,
options,
}: Readonly<{
senderE164?: string;
senderUuid?: string;
timestamps: Array<number>;
type: Proto.ReceiptMessage.Type;
isDirectConversation: boolean;
options?: Readonly<SendOptionsType>;
}>): Promise<CallbackResultType> {
if (!senderUuid && !senderE164) {
@ -1960,21 +2044,35 @@ export default class MessageSender {
);
}
const timestamp = Date.now();
const receiptMessage = new Proto.ReceiptMessage();
receiptMessage.type = type;
receiptMessage.timestamp = timestamps.map(timestamp =>
Long.fromNumber(timestamp)
receiptMessage.timestamp = timestamps.map(receiptTimestamp =>
Long.fromNumber(receiptTimestamp)
);
const contentMessage = new Proto.Content();
contentMessage.receiptMessage = receiptMessage;
if (isDirectConversation) {
const conversation = window.ConversationController.get(
senderUuid || senderE164
);
addPniSignatureMessageToProto({
conversation,
proto: contentMessage,
reason: `sendReceiptMessage(${type}, ${timestamp})`,
});
}
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return this.sendIndividualProto({
identifier: senderUuid || senderE164,
proto: contentMessage,
timestamp: Date.now(),
timestamp,
contentHint: ContentHint.RESENDABLE,
options,
urgent: false,
@ -2052,6 +2150,7 @@ export default class MessageSender {
sendType,
timestamp,
urgent,
hasPniSignatureMessage,
}: Readonly<{
contentHint: number;
messageId?: string;
@ -2059,6 +2158,7 @@ export default class MessageSender {
sendType: SendTypesType;
timestamp: number;
urgent: boolean;
hasPniSignatureMessage: boolean;
}>): SendLogCallbackType {
let initialSavePromise: Promise<number>;
@ -2095,6 +2195,7 @@ export default class MessageSender {
proto,
timestamp,
urgent,
hasPniSignatureMessage,
},
{
recipients: { [recipientUuid]: deviceIds },
@ -2270,6 +2371,7 @@ export default class MessageSender {
sendType: 'senderKeyDistributionMessage',
timestamp,
urgent,
hasPniSignatureMessage: false,
})
: undefined;
@ -2313,6 +2415,7 @@ export default class MessageSender {
sendType: 'legacyGroupChange',
timestamp,
urgent: false,
hasPniSignatureMessage: false,
})
: undefined;