2023-03-14 20:25:05 +00:00
|
|
|
// Copyright 2022 Signal Messenger, LLC
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
|
|
|
import { handleMessageSend } from '../../util/handleMessageSend';
|
|
|
|
import { getSendOptions } from '../../util/getSendOptions';
|
|
|
|
import { isDirectConversation } from '../../util/whatTypeOfConversation';
|
|
|
|
import { SignalService as Proto } from '../../protobuf';
|
|
|
|
import {
|
|
|
|
handleMultipleSendErrors,
|
|
|
|
maybeExpandErrors,
|
|
|
|
} from './handleMultipleSendErrors';
|
|
|
|
|
|
|
|
import type { ConversationModel } from '../../models/conversations';
|
|
|
|
import type {
|
|
|
|
ConversationQueueJobBundle,
|
|
|
|
SavedProtoJobData,
|
|
|
|
} from '../conversationJobQueue';
|
|
|
|
import { isConversationUnregistered } from '../../util/isConversationUnregistered';
|
|
|
|
import {
|
|
|
|
OutgoingIdentityKeyError,
|
|
|
|
UnregisteredUserError,
|
|
|
|
} from '../../textsecure/Errors';
|
|
|
|
|
|
|
|
export async function sendSavedProto(
|
|
|
|
conversation: ConversationModel,
|
|
|
|
{
|
|
|
|
isFinalAttempt,
|
|
|
|
messaging,
|
|
|
|
shouldContinue,
|
|
|
|
timestamp,
|
|
|
|
timeRemaining,
|
|
|
|
log,
|
|
|
|
}: ConversationQueueJobBundle,
|
|
|
|
data: SavedProtoJobData
|
|
|
|
): Promise<void> {
|
|
|
|
if (!shouldContinue) {
|
|
|
|
log.info('Ran out of time. Giving up on sending null message');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
log.info(
|
|
|
|
`starting saved proto send to ${conversation.idForLogging()} with timestamp ${timestamp}`
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!isDirectConversation(conversation.attributes)) {
|
|
|
|
log.info('Failing attempt to send null message to group');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: we will send to blocked users, to those still in message request state, etc.
|
|
|
|
// Any needed blocking should still apply once the decryption error is fixed.
|
|
|
|
|
|
|
|
if (isConversationUnregistered(conversation.attributes)) {
|
|
|
|
log.info(
|
|
|
|
`conversation ${conversation.idForLogging()} is unregistered; refusing to send null message`
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-16 20:54:39 +00:00
|
|
|
const serviceId = conversation.getServiceId();
|
|
|
|
if (!serviceId) {
|
2023-03-14 20:25:05 +00:00
|
|
|
log.info(
|
2023-08-16 20:54:39 +00:00
|
|
|
`conversation ${conversation.idForLogging()} was missing serviceId, cancelling job.`
|
2023-03-14 20:25:05 +00:00
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const {
|
|
|
|
protoBase64,
|
|
|
|
groupId,
|
|
|
|
contentHint,
|
|
|
|
story,
|
|
|
|
timestamp: originalTimestamp,
|
|
|
|
urgent,
|
|
|
|
} = data;
|
|
|
|
const sendOptions = await getSendOptions(conversation.attributes, { story });
|
|
|
|
const sendType = 'resendFromLog';
|
|
|
|
|
|
|
|
try {
|
|
|
|
const proto = Proto.Content.decode(Buffer.from(protoBase64, 'base64'));
|
|
|
|
await handleMessageSend(
|
|
|
|
messaging.sendMessageProtoAndWait({
|
|
|
|
contentHint,
|
|
|
|
groupId,
|
|
|
|
options: sendOptions,
|
|
|
|
proto,
|
2023-08-16 20:54:39 +00:00
|
|
|
recipients: [serviceId],
|
2023-03-14 20:25:05 +00:00
|
|
|
timestamp: originalTimestamp,
|
|
|
|
urgent,
|
|
|
|
story,
|
|
|
|
}),
|
|
|
|
{
|
|
|
|
messageIds: [],
|
|
|
|
sendType,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
} catch (error: unknown) {
|
|
|
|
if (
|
|
|
|
error instanceof OutgoingIdentityKeyError ||
|
|
|
|
error instanceof UnregisteredUserError
|
|
|
|
) {
|
|
|
|
log.info(
|
|
|
|
'Send failure was OutgoingIdentityKeyError or UnregisteredUserError. Cancelling job.'
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
await handleMultipleSendErrors({
|
|
|
|
errors: maybeExpandErrors(error),
|
|
|
|
isFinalAttempt,
|
|
|
|
log,
|
|
|
|
timeRemaining,
|
|
|
|
toThrow: error,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|