2021-05-07 01:15:25 +00:00
|
|
|
// Copyright 2021 Signal Messenger, LLC
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
2021-07-15 23:48:09 +00:00
|
|
|
import { isNumber } from 'lodash';
|
2021-10-26 19:15:33 +00:00
|
|
|
import type { CallbackResultType } from '../textsecure/Types.d';
|
2021-07-15 23:48:09 +00:00
|
|
|
import dataInterface from '../sql/Client';
|
2021-09-17 18:27:53 +00:00
|
|
|
import * as log from '../logging/log';
|
2021-07-15 23:48:09 +00:00
|
|
|
|
|
|
|
const { insertSentProto } = dataInterface;
|
2021-05-07 01:15:25 +00:00
|
|
|
|
2021-05-25 22:40:04 +00:00
|
|
|
export const SEALED_SENDER = {
|
2021-05-07 01:15:25 +00:00
|
|
|
UNKNOWN: 0,
|
|
|
|
ENABLED: 1,
|
|
|
|
DISABLED: 2,
|
|
|
|
UNRESTRICTED: 3,
|
|
|
|
};
|
|
|
|
|
2021-07-15 23:48:09 +00:00
|
|
|
export type SendTypesType =
|
|
|
|
| 'callingMessage' // excluded from send log
|
|
|
|
| 'deleteForEveryone'
|
|
|
|
| 'deliveryReceipt'
|
|
|
|
| 'expirationTimerUpdate'
|
|
|
|
| 'groupChange'
|
|
|
|
| 'legacyGroupChange'
|
|
|
|
| 'message'
|
|
|
|
| 'nullMessage' // excluded from send log
|
|
|
|
| 'otherSync'
|
|
|
|
| 'profileKeyUpdate'
|
|
|
|
| 'reaction'
|
|
|
|
| 'readReceipt'
|
|
|
|
| 'readSync'
|
|
|
|
| 'resendFromLog' // excluded from send log
|
|
|
|
| 'resetSession'
|
|
|
|
| 'retryRequest' // excluded from send log
|
|
|
|
| 'senderKeyDistributionMessage'
|
|
|
|
| 'sentSync'
|
|
|
|
| 'typing' // excluded from send log
|
|
|
|
| 'verificationSync'
|
2021-08-12 18:15:55 +00:00
|
|
|
| 'viewOnceSync'
|
2021-08-17 15:43:26 +00:00
|
|
|
| 'viewSync'
|
|
|
|
| 'viewedReceipt';
|
2021-07-15 23:48:09 +00:00
|
|
|
|
|
|
|
export function shouldSaveProto(sendType: SendTypesType): boolean {
|
|
|
|
if (sendType === 'callingMessage') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sendType === 'nullMessage') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sendType === 'resendFromLog') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sendType === 'retryRequest') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sendType === 'typing') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-05-07 01:15:25 +00:00
|
|
|
export async function handleMessageSend(
|
2021-07-15 23:48:09 +00:00
|
|
|
promise: Promise<CallbackResultType>,
|
|
|
|
options: {
|
|
|
|
messageIds: Array<string>;
|
|
|
|
sendType: SendTypesType;
|
|
|
|
}
|
|
|
|
): Promise<CallbackResultType> {
|
2021-05-07 01:15:25 +00:00
|
|
|
try {
|
|
|
|
const result = await promise;
|
2021-07-15 23:48:09 +00:00
|
|
|
|
|
|
|
await maybeSaveToSendLog(result, options);
|
|
|
|
|
|
|
|
await handleMessageSendResult(
|
|
|
|
result.failoverIdentifiers,
|
|
|
|
result.unidentifiedDeliveries
|
|
|
|
);
|
|
|
|
|
2021-05-07 01:15:25 +00:00
|
|
|
return result;
|
|
|
|
} catch (err) {
|
|
|
|
if (err) {
|
|
|
|
await handleMessageSendResult(
|
|
|
|
err.failoverIdentifiers,
|
|
|
|
err.unidentifiedDeliveries
|
|
|
|
);
|
|
|
|
}
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function handleMessageSendResult(
|
|
|
|
failoverIdentifiers: Array<string> | undefined,
|
|
|
|
unidentifiedDeliveries: Array<string> | undefined
|
|
|
|
): Promise<void> {
|
|
|
|
await Promise.all(
|
|
|
|
(failoverIdentifiers || []).map(async identifier => {
|
|
|
|
const conversation = window.ConversationController.get(identifier);
|
|
|
|
|
|
|
|
if (
|
|
|
|
conversation &&
|
|
|
|
conversation.get('sealedSender') !== SEALED_SENDER.DISABLED
|
|
|
|
) {
|
2021-09-17 18:27:53 +00:00
|
|
|
log.info(
|
2021-05-07 01:15:25 +00:00
|
|
|
`Setting sealedSender to DISABLED for conversation ${conversation.idForLogging()}`
|
|
|
|
);
|
|
|
|
conversation.set({
|
|
|
|
sealedSender: SEALED_SENDER.DISABLED,
|
|
|
|
});
|
|
|
|
window.Signal.Data.updateConversation(conversation.attributes);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
await Promise.all(
|
|
|
|
(unidentifiedDeliveries || []).map(async identifier => {
|
|
|
|
const conversation = window.ConversationController.get(identifier);
|
|
|
|
|
|
|
|
if (
|
|
|
|
conversation &&
|
|
|
|
conversation.get('sealedSender') === SEALED_SENDER.UNKNOWN
|
|
|
|
) {
|
|
|
|
if (conversation.get('accessKey')) {
|
2021-09-17 18:27:53 +00:00
|
|
|
log.info(
|
2021-05-07 01:15:25 +00:00
|
|
|
`Setting sealedSender to ENABLED for conversation ${conversation.idForLogging()}`
|
|
|
|
);
|
|
|
|
conversation.set({
|
|
|
|
sealedSender: SEALED_SENDER.ENABLED,
|
|
|
|
});
|
|
|
|
} else {
|
2021-09-17 18:27:53 +00:00
|
|
|
log.info(
|
2021-05-07 01:15:25 +00:00
|
|
|
`Setting sealedSender to UNRESTRICTED for conversation ${conversation.idForLogging()}`
|
|
|
|
);
|
|
|
|
conversation.set({
|
|
|
|
sealedSender: SEALED_SENDER.UNRESTRICTED,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
window.Signal.Data.updateConversation(conversation.attributes);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
2021-07-15 23:48:09 +00:00
|
|
|
|
|
|
|
async function maybeSaveToSendLog(
|
|
|
|
result: CallbackResultType,
|
|
|
|
{
|
|
|
|
messageIds,
|
|
|
|
sendType,
|
|
|
|
}: {
|
|
|
|
messageIds: Array<string>;
|
|
|
|
sendType: SendTypesType;
|
|
|
|
}
|
|
|
|
): Promise<void> {
|
|
|
|
const { contentHint, contentProto, recipients, timestamp } = result;
|
|
|
|
|
|
|
|
if (!shouldSaveProto(sendType)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isNumber(contentHint) || !contentProto || !recipients || !timestamp) {
|
2021-09-17 18:27:53 +00:00
|
|
|
log.warn(
|
2021-07-15 23:48:09 +00:00
|
|
|
`handleMessageSend: Missing necessary information to save to log for ${sendType} message ${timestamp}`
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const identifiers = Object.keys(recipients);
|
|
|
|
if (identifiers.length === 0) {
|
2021-09-17 18:27:53 +00:00
|
|
|
log.warn(
|
2021-07-15 23:48:09 +00:00
|
|
|
`handleMessageSend: ${sendType} message ${timestamp} had no recipients`
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the identifier count is greater than one, we've done the save elsewhere
|
|
|
|
if (identifiers.length > 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
await insertSentProto(
|
|
|
|
{
|
|
|
|
timestamp,
|
|
|
|
proto: Buffer.from(contentProto),
|
|
|
|
contentHint,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
messageIds,
|
|
|
|
recipients,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|