Remove sealed sender proto file in favor of libsignal types

This commit is contained in:
Jordan Rose 2025-08-29 14:07:28 -07:00 committed by GitHub
commit a0633efece
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 132 additions and 230 deletions

View file

@ -1,70 +0,0 @@
// Copyright 2018 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
package signalservice;
option java_package = "org.whispersystems.libsignal.protocol";
option java_outer_classname = "WhisperProtos";
message ServerCertificate {
message Certificate {
optional uint32 id = 1;
optional bytes key = 2;
}
optional bytes certificate = 1;
optional bytes signature = 2;
}
message SenderCertificate {
message Certificate {
optional string senderE164 = 1;
optional string senderUuid = 6;
optional uint32 senderDevice = 2;
optional fixed64 expires = 3;
optional bytes identityKey = 4;
optional ServerCertificate signer = 5;
}
optional bytes certificate = 1;
optional bytes signature = 2;
}
message UnidentifiedSenderMessage {
message Message {
enum Type {
// Our parser does not handle reserved in enums: DESKTOP-1569
// reserved 1;
MESSAGE = 2;
PREKEY_MESSAGE = 3;
// Further cases should line up with Envelope.Type, even though old cases don't.
// reserved 3 to 6;
SENDERKEY_MESSAGE = 7;
PLAINTEXT_CONTENT = 8;
}
enum ContentHint {
// Show an error immediately; it was important but we can't retry.
DEFAULT = 0;
// Sender will try to resend; delay any error UI if possible
RESENDABLE = 1;
// Don't show any error UI at all; this is something sent implicitly like a typing message or a receipt
IMPLICIT = 2;
}
optional Type type = 1;
optional SenderCertificate senderCertificate = 2;
optional bytes content = 3;
optional ContentHint contentHint = 4;
optional bytes groupId = 5;
}
optional bytes ephemeralPublic = 1;
optional bytes encryptedStatic = 2;
optional bytes encryptedMessage = 3;
}

View file

@ -1,6 +1,8 @@
// Copyright 2022 Signal Messenger, LLC // Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { ContentHint } from '@signalapp/libsignal-client';
import { handleMessageSend } from '../../util/handleMessageSend'; import { handleMessageSend } from '../../util/handleMessageSend';
import { getSendOptions } from '../../util/getSendOptions'; import { getSendOptions } from '../../util/getSendOptions';
import { import {
@ -92,13 +94,11 @@ export async function sendCallingMessage(
const callMessage = Proto.CallMessage.decode(Bytes.fromBase64(protoBase64)); const callMessage = Proto.CallMessage.decode(Bytes.fromBase64(protoBase64));
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
try { try {
if (isGroup(conversation.attributes)) { if (isGroup(conversation.attributes)) {
await handleMessageSend( await handleMessageSend(
sendContentMessageToGroup({ sendContentMessageToGroup({
contentHint: ContentHint.DEFAULT, contentHint: ContentHint.Default,
contentMessage: new Proto.Content({ callMessage }), contentMessage: new Proto.Content({ callMessage }),
isPartialSend, isPartialSend,
messageId: undefined, messageId: undefined,

View file

@ -1,6 +1,7 @@
// Copyright 2022 Signal Messenger, LLC // Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { ContentHint } from '@signalapp/libsignal-client';
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import * as Errors from '../../types/errors'; import * as Errors from '../../types/errors';
@ -82,8 +83,7 @@ export async function sendDeleteForEveryone(
} }
const sendType = 'deleteForEveryone'; const sendType = 'deleteForEveryone';
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; const contentHint = ContentHint.Resendable;
const contentHint = ContentHint.RESENDABLE;
const messageIds = [messageId]; const messageIds = [messageId];
const deletedForEveryoneSendStatus = message.get( const deletedForEveryoneSendStatus = message.get(

View file

@ -1,10 +1,11 @@
// Copyright 2022 Signal Messenger, LLC // Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { ContentHint } from '@signalapp/libsignal-client';
import * as Errors from '../../types/errors'; import * as Errors from '../../types/errors';
import { getSendOptions } from '../../util/getSendOptions'; import { getSendOptions } from '../../util/getSendOptions';
import { isDirectConversation, isMe } from '../../util/whatTypeOfConversation'; import { isDirectConversation, isMe } from '../../util/whatTypeOfConversation';
import { SignalService as Proto } from '../../protobuf';
import { import {
handleMultipleSendErrors, handleMultipleSendErrors,
maybeExpandErrors, maybeExpandErrors,
@ -68,8 +69,7 @@ export async function sendDeleteStoryForEveryone(
strictAssert(isStory(message.attributes), 'Story message must be a story'); strictAssert(isStory(message.attributes), 'Story message must be a story');
const sendType = 'deleteForEveryone'; const sendType = 'deleteForEveryone';
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; const contentHint = ContentHint.Resendable;
const contentHint = ContentHint.RESENDABLE;
const deletedForEveryoneSendStatus = message.get( const deletedForEveryoneSendStatus = message.get(
'deletedForEveryoneSendStatus' 'deletedForEveryoneSendStatus'

View file

@ -1,6 +1,8 @@
// Copyright 2022 Signal Messenger, LLC // Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { ContentHint } from '@signalapp/libsignal-client';
import { getSendOptions } from '../../util/getSendOptions'; import { getSendOptions } from '../../util/getSendOptions';
import { isDirectConversation, isMe } from '../../util/whatTypeOfConversation'; import { isDirectConversation, isMe } from '../../util/whatTypeOfConversation';
import { SignalService as Proto } from '../../protobuf'; import { SignalService as Proto } from '../../protobuf';
@ -70,8 +72,7 @@ export async function sendDirectExpirationTimerUpdate(
profileKey = await ourProfileKeyService.get(); profileKey = await ourProfileKeyService.get();
} }
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; const contentHint = ContentHint.Resendable;
const contentHint = ContentHint.RESENDABLE;
const sendType = 'expirationTimerUpdate'; const sendType = 'expirationTimerUpdate';
const flags = Proto.DataMessage.Flags.EXPIRATION_TIMER_UPDATE; const flags = Proto.DataMessage.Flags.EXPIRATION_TIMER_UPDATE;

View file

@ -1,9 +1,10 @@
// Copyright 2022 Signal Messenger, LLC // Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { ContentHint } from '@signalapp/libsignal-client';
import { getSendOptions } from '../../util/getSendOptions'; import { getSendOptions } from '../../util/getSendOptions';
import { isGroup } from '../../util/whatTypeOfConversation'; import { isGroup } from '../../util/whatTypeOfConversation';
import { SignalService as Proto } from '../../protobuf';
import { import {
handleMultipleSendErrors, handleMultipleSendErrors,
maybeExpandErrors, maybeExpandErrors,
@ -66,7 +67,6 @@ export async function sendGroupCallUpdate(
} }
const sendType = 'callingMessage'; const sendType = 'callingMessage';
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
const groupV2 = conversation.getGroupV2Info(); const groupV2 = conversation.getGroupV2Info();
const sendOptions = await getSendOptions(conversation.attributes); const sendOptions = await getSendOptions(conversation.attributes);
if (!groupV2) { if (!groupV2) {
@ -82,7 +82,7 @@ export async function sendGroupCallUpdate(
send: () => send: () =>
conversation.queueJob(logId, () => conversation.queueJob(logId, () =>
sendToGroup({ sendToGroup({
contentHint: ContentHint.DEFAULT, contentHint: ContentHint.Default,
groupSendOptions: { groupSendOptions: {
groupCallUpdate: { eraId }, groupCallUpdate: { eraId },
groupV2, groupV2,

View file

@ -1,9 +1,10 @@
// Copyright 2022 Signal Messenger, LLC // Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { ContentHint } from '@signalapp/libsignal-client';
import { getSendOptionsForRecipients } from '../../util/getSendOptions'; import { getSendOptionsForRecipients } from '../../util/getSendOptions';
import { isGroupV2 } from '../../util/whatTypeOfConversation'; import { isGroupV2 } from '../../util/whatTypeOfConversation';
import { SignalService as Proto } from '../../protobuf';
import { import {
handleMultipleSendErrors, handleMultipleSendErrors,
maybeExpandErrors, maybeExpandErrors,
@ -70,8 +71,7 @@ export async function sendGroupUpdate(
const sendOptions = await getSendOptionsForRecipients(recipients); const sendOptions = await getSendOptionsForRecipients(recipients);
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; const contentHint = ContentHint.Resendable;
const contentHint = ContentHint.RESENDABLE;
const sendType = 'groupChange'; const sendType = 'groupChange';
const groupChange = groupChangeBase64 const groupChange = groupChangeBase64

View file

@ -3,6 +3,7 @@
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import PQueue from 'p-queue'; import PQueue from 'p-queue';
import { ContentHint } from '@signalapp/libsignal-client';
import * as Errors from '../../types/errors'; import * as Errors from '../../types/errors';
import { strictAssert } from '../../util/assert'; import { strictAssert } from '../../util/assert';
@ -11,7 +12,6 @@ import { getMessageById } from '../../messages/getMessageById';
import type { ConversationModel } from '../../models/conversations'; import type { ConversationModel } from '../../models/conversations';
import { isGroup, isGroupV2, isMe } from '../../util/whatTypeOfConversation'; import { isGroup, isGroupV2, isMe } from '../../util/whatTypeOfConversation';
import { getSendOptions } from '../../util/getSendOptions'; import { getSendOptions } from '../../util/getSendOptions';
import { SignalService as Proto } from '../../protobuf';
import { handleMessageSend } from '../../util/handleMessageSend'; import { handleMessageSend } from '../../util/handleMessageSend';
import { findAndFormatContact } from '../../util/findAndFormatContact'; import { findAndFormatContact } from '../../util/findAndFormatContact';
import { uploadAttachment } from '../../util/uploadAttachment'; import { uploadAttachment } from '../../util/uploadAttachment';
@ -302,7 +302,6 @@ export async function sendNormalMessage(
} else { } else {
const conversationType = conversation.get('type'); const conversationType = conversation.get('type');
const sendOptions = await getSendOptions(conversation.attributes); const sendOptions = await getSendOptions(conversation.attributes);
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
let innerPromise: Promise<CallbackResultType>; let innerPromise: Promise<CallbackResultType>;
if (conversationType === Message.GROUP) { if (conversationType === Message.GROUP) {
@ -324,7 +323,7 @@ export async function sendNormalMessage(
abortSignal => abortSignal =>
sendToGroup({ sendToGroup({
abortSignal, abortSignal,
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
groupSendOptions: { groupSendOptions: {
attachments, attachments,
bodyRanges, bodyRanges,
@ -392,7 +391,7 @@ export async function sendNormalMessage(
attachments, attachments,
bodyRanges, bodyRanges,
contact, contact,
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
deletedForEveryoneTimestamp, deletedForEveryoneTimestamp,
expireTimer, expireTimer,
expireTimerVersion: conversation.getExpireTimerVersion(), expireTimerVersion: conversation.getExpireTimerVersion(),

View file

@ -1,10 +1,11 @@
// Copyright 2022 Signal Messenger, LLC // Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { ContentHint } from '@signalapp/libsignal-client';
import { handleMessageSend } from '../../util/handleMessageSend'; import { handleMessageSend } from '../../util/handleMessageSend';
import { getSendOptions } from '../../util/getSendOptions'; import { getSendOptions } from '../../util/getSendOptions';
import { isDirectConversation } from '../../util/whatTypeOfConversation'; import { isDirectConversation } from '../../util/whatTypeOfConversation';
import { SignalService as Proto } from '../../protobuf';
import { import {
handleMultipleSendErrors, handleMultipleSendErrors,
maybeExpandErrors, maybeExpandErrors,
@ -62,8 +63,7 @@ export async function sendNullMessage(
); );
const sendOptions = await getSendOptions(conversation.attributes); const sendOptions = await getSendOptions(conversation.attributes);
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; const contentHint = ContentHint.Resendable;
const contentHint = ContentHint.RESENDABLE;
const sendType = 'nullMessage'; const sendType = 'nullMessage';
// Note: we will send to blocked users, to those still in message request state, etc. // Note: we will send to blocked users, to those still in message request state, etc.
@ -109,7 +109,7 @@ export async function sendNullMessage(
abortSignal => abortSignal =>
sendToGroup({ sendToGroup({
abortSignal, abortSignal,
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
groupSendOptions: { groupSendOptions: {
attachments: [], attachments: [],
bodyRanges: [], bodyRanges: [],

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import { ContentHint } from '@signalapp/libsignal-client';
import { handleMessageSend } from '../../util/handleMessageSend'; import { handleMessageSend } from '../../util/handleMessageSend';
import { getSendOptions } from '../../util/getSendOptions'; import { getSendOptions } from '../../util/getSendOptions';
@ -95,8 +96,7 @@ export async function sendProfileKey(
const { revision } = data; const { revision } = data;
const sendOptions = await getSendOptions(conversation.attributes); const sendOptions = await getSendOptions(conversation.attributes);
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; const contentHint = ContentHint.Resendable;
const contentHint = ContentHint.RESENDABLE;
const sendType = 'profileKeyUpdate'; const sendType = 'profileKeyUpdate';
let sendPromise: Promise<CallbackResultType>; let sendPromise: Promise<CallbackResultType>;

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import { ContentHint } from '@signalapp/libsignal-client';
import * as Errors from '../../types/errors'; import * as Errors from '../../types/errors';
import { strictAssert } from '../../util/assert'; import { strictAssert } from '../../util/assert';
@ -21,7 +22,6 @@ import {
isGroupV2, isGroupV2,
} from '../../util/whatTypeOfConversation'; } from '../../util/whatTypeOfConversation';
import { getSendOptions } from '../../util/getSendOptions'; import { getSendOptions } from '../../util/getSendOptions';
import { SignalService as Proto } from '../../protobuf';
import { handleMessageSend } from '../../util/handleMessageSend'; import { handleMessageSend } from '../../util/handleMessageSend';
import { ourProfileKeyService } from '../../services/ourProfileKey'; import { ourProfileKeyService } from '../../services/ourProfileKey';
import { canReact, isStory } from '../../state/selectors/message'; import { canReact, isStory } from '../../state/selectors/message';
@ -211,7 +211,6 @@ export async function sendReaction(
successfulConversationIds.add(ourConversationId); successfulConversationIds.add(ourConversationId);
} else { } else {
const sendOptions = await getSendOptions(conversation.attributes); const sendOptions = await getSendOptions(conversation.attributes);
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
let promise: Promise<CallbackResultType>; let promise: Promise<CallbackResultType>;
if (isDirectConversation(conversation.attributes)) { if (isDirectConversation(conversation.attributes)) {
@ -250,7 +249,7 @@ export async function sendReaction(
timestamp: pendingReaction.timestamp, timestamp: pendingReaction.timestamp,
expireTimer, expireTimer,
expireTimerVersion: conversation.getExpireTimerVersion(), expireTimerVersion: conversation.getExpireTimerVersion(),
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
groupId: undefined, groupId: undefined,
profileKey, profileKey,
options: sendOptions, options: sendOptions,
@ -276,7 +275,7 @@ export async function sendReaction(
return sendToGroup({ return sendToGroup({
abortSignal, abortSignal,
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
groupSendOptions: { groupSendOptions: {
groupV2: groupV2Info, groupV2: groupV2Info,
reaction: reactionForSend, reaction: reactionForSend,

View file

@ -1,12 +1,11 @@
// Copyright 2022 Signal Messenger, LLC // Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { PlaintextContent } from '@signalapp/libsignal-client'; import { ContentHint, PlaintextContent } from '@signalapp/libsignal-client';
import { handleMessageSend } from '../../util/handleMessageSend'; import { handleMessageSend } from '../../util/handleMessageSend';
import { getSendOptions } from '../../util/getSendOptions'; import { getSendOptions } from '../../util/getSendOptions';
import { isDirectConversation } from '../../util/whatTypeOfConversation'; import { isDirectConversation } from '../../util/whatTypeOfConversation';
import { SignalService as Proto } from '../../protobuf';
import { import {
handleMultipleSendErrors, handleMultipleSendErrors,
maybeExpandErrors, maybeExpandErrors,
@ -98,7 +97,6 @@ export async function sendResendRequest(
const plaintext = PlaintextContent.deserialize( const plaintext = PlaintextContent.deserialize(
Bytes.fromBase64(plaintextBase64) Bytes.fromBase64(plaintextBase64)
); );
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
// We run this job on the queue for the individual sender we want the resend from, but // We run this job on the queue for the individual sender we want the resend from, but
// the original message might have been sent in a group - and that's where we'll put // the original message might have been sent in a group - and that's where we'll put
@ -113,7 +111,7 @@ export async function sendResendRequest(
timestamp, timestamp,
recipients: [senderAci], recipients: [senderAci],
proto: plaintext, proto: plaintext,
contentHint: ContentHint.DEFAULT, contentHint: ContentHint.Default,
groupId, groupId,
options, options,
urgent: false, urgent: false,
@ -124,7 +122,7 @@ export async function sendResendRequest(
// Now that we've successfully sent, represent this to the user. Three options: // Now that we've successfully sent, represent this to the user. Three options:
// 1. We believe that it could be successfully re-sent, so we'll add a placeholder. // 1. We believe that it could be successfully re-sent, so we'll add a placeholder.
if (contentHint === ContentHint.RESENDABLE) { if (contentHint === ContentHint.Resendable) {
const { retryPlaceholders } = window.Signal.Services; const { retryPlaceholders } = window.Signal.Services;
strictAssert(retryPlaceholders, 'sendResendRequest: adding placeholder'); strictAssert(retryPlaceholders, 'sendResendRequest: adding placeholder');
@ -148,7 +146,7 @@ export async function sendResendRequest(
// 2. This message cannot be resent. We'll show no error and trust the other side to // 2. This message cannot be resent. We'll show no error and trust the other side to
// reset their session. // reset their session.
if (contentHint === ContentHint.IMPLICIT) { if (contentHint === ContentHint.Implicit) {
log.info('contentHint is IMPLICIT, adding no timeline item.'); log.info('contentHint is IMPLICIT, adding no timeline item.');
return; return;
} }

View file

@ -2,6 +2,8 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { isEqual } from 'lodash'; import { isEqual } from 'lodash';
import { ContentHint } from '@signalapp/libsignal-client';
import type { UploadedAttachmentType } from '../../types/Attachment'; import type { UploadedAttachmentType } from '../../types/Attachment';
import type { ConversationModel } from '../../models/conversations'; import type { ConversationModel } from '../../models/conversations';
import type { import type {
@ -324,8 +326,6 @@ export async function sendStory(
return; return;
} }
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
const sendOptions = await getSendOptionsForRecipients( const sendOptions = await getSendOptionsForRecipients(
pendingSendRecipientServiceIds, pendingSendRecipientServiceIds,
{ story: true } { story: true }
@ -356,7 +356,7 @@ export async function sendStory(
contentMessage.storyMessage = storyMessage; contentMessage.storyMessage = storyMessage;
const innerPromise = sendContentMessageToGroup({ const innerPromise = sendContentMessageToGroup({
contentHint: ContentHint.IMPLICIT, contentHint: ContentHint.Implicit,
contentMessage, contentMessage,
isPartialSend: false, isPartialSend: false,
messageId: undefined, messageId: undefined,

View file

@ -4,6 +4,7 @@
import { compact, isNumber, throttle, debounce } from 'lodash'; import { compact, isNumber, throttle, debounce } from 'lodash';
import { v4 as generateGuid } from 'uuid'; import { v4 as generateGuid } from 'uuid';
import PQueue from 'p-queue'; import PQueue from 'p-queue';
import { ContentHint } from '@signalapp/libsignal-client';
import type { ReadonlyDeep } from 'type-fest'; import type { ReadonlyDeep } from 'type-fest';
import type { import type {
@ -1377,8 +1378,6 @@ export class ConversationModel {
const contentMessage = messaging.getTypingContentMessage(content); const contentMessage = messaging.getTypingContentMessage(content);
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
const sendOptions = { const sendOptions = {
...(await getSendOptions(this.attributes)), ...(await getSendOptions(this.attributes)),
online: true, online: true,
@ -1386,7 +1385,7 @@ export class ConversationModel {
if (isDirectConversation(this.attributes)) { if (isDirectConversation(this.attributes)) {
await handleMessageSend( await handleMessageSend(
messaging.sendMessageProtoAndWait({ messaging.sendMessageProtoAndWait({
contentHint: ContentHint.IMPLICIT, contentHint: ContentHint.Implicit,
groupId: undefined, groupId: undefined,
options: sendOptions, options: sendOptions,
proto: contentMessage, proto: contentMessage,
@ -1399,7 +1398,7 @@ export class ConversationModel {
} else { } else {
await handleMessageSend( await handleMessageSend(
sendContentMessageToGroup({ sendContentMessageToGroup({
contentHint: ContentHint.IMPLICIT, contentHint: ContentHint.Implicit,
contentMessage, contentMessage,
messageId: undefined, messageId: undefined,
online: true, online: true,

View file

@ -1,6 +1,8 @@
// Copyright 2021 Signal Messenger, LLC // Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { SenderCertificate } from '@signalapp/libsignal-client';
import type { SerializedCertificateType } from '../textsecure/OutgoingMessage'; import type { SerializedCertificateType } from '../textsecure/OutgoingMessage';
import { import {
SenderCertificateMode, SenderCertificateMode,
@ -14,9 +16,6 @@ import { createLogger } from '../logging/log';
import type { StorageInterface } from '../types/Storage.d'; import type { StorageInterface } from '../types/Storage.d';
import * as Errors from '../types/errors'; import * as Errors from '../types/errors';
import type { WebAPIType } from '../textsecure/WebAPI'; import type { WebAPIType } from '../textsecure/WebAPI';
import { SignalService as Proto } from '../protobuf';
import SenderCertificate = Proto.SenderCertificate;
import { safeParseUnknown } from '../util/schemas'; import { safeParseUnknown } from '../util/schemas';
const log = createLogger('senderCertificate'); const log = createLogger('senderCertificate');
@ -176,11 +175,8 @@ export class SenderCertificateService {
return undefined; return undefined;
} }
const certificate = Bytes.fromBase64(certificateString); const certificate = Bytes.fromBase64(certificateString);
const decodedContainer = SenderCertificate.decode(certificate); const decodedCert = SenderCertificate.deserialize(certificate);
const decodedCert = decodedContainer.certificate const expires = decodedCert.expiration();
? SenderCertificate.Certificate.decode(decodedContainer.certificate)
: undefined;
const expires = decodedCert?.expires?.toNumber();
if (!isExpirationValid(expires)) { if (!isExpirationValid(expires)) {
log.warn( log.warn(
@ -240,8 +236,8 @@ function modeToLogString(mode: SenderCertificateMode): string {
} }
} }
function isExpirationValid(expiration: unknown): expiration is number { function isExpirationValid(expiration: number): boolean {
return typeof expiration === 'number' && expiration > Date.now(); return expiration > Date.now();
} }
export const senderCertificateService = new SenderCertificateService(); export const senderCertificateService = new SenderCertificateService();

View file

@ -6,18 +6,20 @@
import { assert } from 'chai'; import { assert } from 'chai';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
import { v4 as uuid } from 'uuid';
import Long from 'long'; import {
IdentityKeyPair,
SenderCertificate,
ServerCertificate,
} from '@signalapp/libsignal-client';
import * as durations from '../../util/durations'; import * as durations from '../../util/durations';
import { drop } from '../../util/drop'; import { drop } from '../../util/drop';
import * as Bytes from '../../Bytes'; import * as Bytes from '../../Bytes';
import { SenderCertificateMode } from '../../textsecure/OutgoingMessage'; import { SenderCertificateMode } from '../../textsecure/OutgoingMessage';
import { SignalService as Proto } from '../../protobuf';
import { SenderCertificateService } from '../../services/senderCertificate'; import { SenderCertificateService } from '../../services/senderCertificate';
import SenderCertificate = Proto.SenderCertificate;
describe('SenderCertificateService', () => { describe('SenderCertificateService', () => {
const FIFTEEN_MINUTES = 15 * durations.MINUTE; const FIFTEEN_MINUTES = 15 * durations.MINUTE;
@ -39,14 +41,26 @@ describe('SenderCertificateService', () => {
} }
beforeEach(() => { beforeEach(() => {
fakeValidCertificate = new SenderCertificate(); const fakeTrustRoot = IdentityKeyPair.generate();
const fakeServerKey = IdentityKeyPair.generate();
const fakeSenderIdentityKey = IdentityKeyPair.generate();
const fakeServerCert = ServerCertificate.new(
1,
fakeServerKey.publicKey,
fakeTrustRoot.privateKey
);
fakeValidCertificateExpiry = Date.now() + 604800000; fakeValidCertificateExpiry = Date.now() + 604800000;
const certificate = new SenderCertificate.Certificate(); fakeValidCertificate = SenderCertificate.new(
certificate.expires = Long.fromNumber(fakeValidCertificateExpiry); 'aaaaaaaa-7000-11eb-b32a-33b8a8a487a6',
fakeValidCertificate.certificate = null,
SenderCertificate.Certificate.encode(certificate).finish(); 2,
fakeValidEncodedCertificate = fakeSenderIdentityKey.publicKey,
SenderCertificate.encode(fakeValidCertificate).finish(); fakeValidCertificateExpiry,
fakeServerCert,
fakeServerKey.privateKey
);
fakeValidEncodedCertificate = fakeValidCertificate.serialize();
fakeServer = { fakeServer = {
isOnline: () => true, isOnline: () => true,
@ -65,7 +79,9 @@ describe('SenderCertificateService', () => {
put: sinon.stub().resolves(), put: sinon.stub().resolves(),
remove: sinon.stub().resolves(), remove: sinon.stub().resolves(),
}; };
fakeStorage.get.withArgs('uuid_id').returns(`${uuid()}.2`); fakeStorage.get
.withArgs('uuid_id')
.returns('aaaaaaaa-7000-11eb-b32a-33b8a8a487a6.2');
fakeStorage.get.withArgs('password').returns('abc123'); fakeStorage.get.withArgs('password').returns('abc123');
}); });
@ -199,15 +215,28 @@ describe('SenderCertificateService', () => {
it('returns undefined if the server returns an already-expired certificate', async () => { it('returns undefined if the server returns an already-expired certificate', async () => {
const service = initializeTestService(); const service = initializeTestService();
const expiredCertificate = new SenderCertificate(); const fakeTrustRoot = IdentityKeyPair.generate();
const certificate = new SenderCertificate.Certificate(); const fakeServerKey = IdentityKeyPair.generate();
certificate.expires = Long.fromNumber(Date.now() - 1000); const fakeSenderIdentityKey = IdentityKeyPair.generate();
expiredCertificate.certificate = const fakeServerCert = ServerCertificate.new(
SenderCertificate.Certificate.encode(certificate).finish(); 1,
fakeServerKey.publicKey,
fakeTrustRoot.privateKey
);
const expiry = Date.now() - 1000;
const expiredCertificate = SenderCertificate.new(
'aaaaaaaa-7000-11eb-b32a-33b8a8a487a6',
null,
1,
fakeSenderIdentityKey.publicKey,
expiry,
fakeServerCert,
fakeServerKey.privateKey
);
fakeServer.getSenderCertificate.resolves({ fakeServer.getSenderCertificate.resolves({
certificate: Bytes.toBase64( certificate: Bytes.toBase64(expiredCertificate.serialize()),
SenderCertificate.encode(expiredCertificate).finish()
),
}); });
assert.isUndefined(await service.get(SenderCertificateMode.WithE164)); assert.isUndefined(await service.get(SenderCertificateMode.WithE164));

View file

@ -1699,12 +1699,7 @@ export default class MessageReceiver
'Missing sender certificate for sealed sender message' 'Missing sender certificate for sealed sender message'
); );
const unidentifiedSenderTypeEnum = if (messageContent.msgType() === CiphertextMessageType.Plaintext) {
Proto.UnidentifiedSenderMessage.Message.Type;
if (
messageContent.msgType() === unidentifiedSenderTypeEnum.PLAINTEXT_CONTENT
) {
log.info( log.info(
`decryptSealedSender(${logId}): ` + `decryptSealedSender(${logId}): ` +
'unidentified message/plaintext contents' 'unidentified message/plaintext contents'
@ -1719,9 +1714,7 @@ export default class MessageReceiver
}; };
} }
if ( if (messageContent.msgType() === CiphertextMessageType.SenderKey) {
messageContent.msgType() === unidentifiedSenderTypeEnum.SENDERKEY_MESSAGE
) {
log.info( log.info(
`decryptSealedSender(${logId}): ` + `decryptSealedSender(${logId}): ` +
'unidentified message/sender key contents' 'unidentified message/sender key contents'
@ -1777,7 +1770,7 @@ export default class MessageReceiver
envelope.sourceDevice envelope.sourceDevice
); );
const message = const message =
messageContent.msgType() === unidentifiedSenderTypeEnum.PREKEY_MESSAGE messageContent.msgType() === CiphertextMessageType.PreKey
? PreKeySignalMessage.deserialize(messageContent.contents()) ? PreKeySignalMessage.deserialize(messageContent.contents())
: SignalMessage.deserialize(messageContent.contents()); : SignalMessage.deserialize(messageContent.contents());
const plaintext = await this.#storage.protocol.enqueueSessionJob( const plaintext = await this.#storage.protocol.enqueueSessionJob(

View file

@ -10,6 +10,7 @@ import PQueue from 'p-queue';
import pMap from 'p-map'; import pMap from 'p-map';
import type { PlaintextContent } from '@signalapp/libsignal-client'; import type { PlaintextContent } from '@signalapp/libsignal-client';
import { import {
ContentHint,
ProtocolAddress, ProtocolAddress,
SenderKeyDistributionMessage, SenderKeyDistributionMessage,
} from '@signalapp/libsignal-client'; } from '@signalapp/libsignal-client';
@ -1381,13 +1382,11 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return this.sendIndividualProto({ return this.sendIndividualProto({
serviceId: myAci, serviceId: myAci,
proto: contentMessage, proto: contentMessage,
timestamp, timestamp,
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
options, options,
urgent, urgent,
}); });
@ -1403,10 +1402,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: myAci, serviceId: myAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1427,10 +1424,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: myAci, serviceId: myAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1451,10 +1446,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: myAci, serviceId: myAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1476,10 +1469,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: myAci, serviceId: myAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1501,10 +1492,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: myAci, serviceId: myAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1526,10 +1515,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: myAci, serviceId: myAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1624,10 +1611,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: myAci, serviceId: myAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1653,10 +1638,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: myAci, serviceId: myAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1684,10 +1667,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: ourAci, serviceId: ourAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1722,10 +1703,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: ourAci, serviceId: ourAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1759,13 +1738,11 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return this.sendIndividualProto({ return this.sendIndividualProto({
serviceId: myAci, serviceId: myAci,
proto: contentMessage, proto: contentMessage,
timestamp: Date.now(), timestamp: Date.now(),
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
options, options,
urgent: true, urgent: true,
}); });
@ -1792,13 +1769,11 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return this.sendIndividualProto({ return this.sendIndividualProto({
serviceId: myAci, serviceId: myAci,
proto: contentMessage, proto: contentMessage,
timestamp: Date.now(), timestamp: Date.now(),
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
options, options,
urgent: false, urgent: false,
}); });
@ -1839,13 +1814,11 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return this.sendIndividualProto({ return this.sendIndividualProto({
serviceId: myAci, serviceId: myAci,
proto: contentMessage, proto: contentMessage,
timestamp: Date.now(), timestamp: Date.now(),
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
options, options,
urgent: false, urgent: false,
}); });
@ -1877,10 +1850,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: myAci, serviceId: myAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1921,10 +1892,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: myAci, serviceId: myAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1962,10 +1931,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: myAci, serviceId: myAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -2009,10 +1976,8 @@ export default class MessageSender {
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return { return {
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: myAci, serviceId: myAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -2045,13 +2010,11 @@ export default class MessageSender {
reason: `sendCallingMessage(${timestamp})`, reason: `sendCallingMessage(${timestamp})`,
}); });
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return this.sendMessageProtoAndWait({ return this.sendMessageProtoAndWait({
timestamp, timestamp,
recipients, recipients,
proto: contentMessage, proto: contentMessage,
contentHint: ContentHint.DEFAULT, contentHint: ContentHint.Default,
groupId: undefined, groupId: undefined,
options, options,
urgent, urgent,
@ -2134,13 +2097,11 @@ export default class MessageSender {
}); });
} }
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
return this.sendIndividualProto({ return this.sendIndividualProto({
serviceId: senderAci, serviceId: senderAci,
proto: contentMessage, proto: contentMessage,
timestamp, timestamp,
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
options, options,
urgent: false, urgent: false,
}); });
@ -2389,7 +2350,6 @@ export default class MessageSender {
options?: Readonly<SendOptionsType> options?: Readonly<SendOptionsType>
): Promise<CallbackResultType> { ): Promise<CallbackResultType> {
const timestamp = Date.now(); const timestamp = Date.now();
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
const contentMessage = await this.getSenderKeyDistributionMessage( const contentMessage = await this.getSenderKeyDistributionMessage(
distributionId, distributionId,
{ {
@ -2401,7 +2361,7 @@ export default class MessageSender {
const sendLogCallback = const sendLogCallback =
serviceIds.length > 1 serviceIds.length > 1
? this.makeSendLogCallback({ ? this.makeSendLogCallback({
contentHint: contentHint ?? ContentHint.IMPLICIT, contentHint: contentHint ?? ContentHint.Implicit,
proto: Proto.Content.encode(contentMessage).finish(), proto: Proto.Content.encode(contentMessage).finish(),
sendType: 'senderKeyDistributionMessage', sendType: 'senderKeyDistributionMessage',
timestamp, timestamp,
@ -2411,7 +2371,7 @@ export default class MessageSender {
: undefined; : undefined;
return this.sendGroupProto({ return this.sendGroupProto({
contentHint: contentHint ?? ContentHint.IMPLICIT, contentHint: contentHint ?? ContentHint.Implicit,
groupId, groupId,
options, options,
proto: contentMessage, proto: contentMessage,

View file

@ -11,6 +11,7 @@ import {
callIdFromRingId, callIdFromRingId,
RingUpdate, RingUpdate,
} from '@signalapp/ringrtc'; } from '@signalapp/ringrtc';
import { ContentHint } from '@signalapp/libsignal-client';
import { isEqual } from 'lodash'; import { isEqual } from 'lodash';
import { strictAssert } from './assert'; import { strictAssert } from './assert';
import { DataReader, DataWriter } from '../sql/Client'; import { DataReader, DataWriter } from '../sql/Client';
@ -1305,10 +1306,8 @@ async function updateRemoteCallHistory(
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
await singleProtoJobQueue.add({ await singleProtoJobQueue.add({
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: ourAci, serviceId: ourAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(
@ -1468,11 +1467,9 @@ export async function markAllCallHistoryReadAndSync(
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
log.info('markAllCallHistoryReadAndSync: Queueing sync message'); log.info('markAllCallHistoryReadAndSync: Queueing sync message');
await singleProtoJobQueue.add({ await singleProtoJobQueue.add({
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: ourAci, serviceId: ourAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(

View file

@ -1,5 +1,8 @@
// Copyright 2024 Signal Messenger, LLC // Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { ContentHint } from '@signalapp/libsignal-client';
import * as Bytes from '../Bytes'; import * as Bytes from '../Bytes';
import { CallLinkUpdateSyncType } from '../types/CallLink'; import { CallLinkUpdateSyncType } from '../types/CallLink';
import { createLogger } from '../logging/log'; import { createLogger } from '../logging/log';
@ -55,10 +58,8 @@ async function _sendCallLinkUpdateSync(
const contentMessage = new Proto.Content(); const contentMessage = new Proto.Content();
contentMessage.syncMessage = syncMessage; contentMessage.syncMessage = syncMessage;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
await singleProtoJobQueue.add({ await singleProtoJobQueue.add({
contentHint: ContentHint.RESENDABLE, contentHint: ContentHint.Resendable,
serviceId: ourAci, serviceId: ourAci,
isSyncMessage: true, isSyncMessage: true,
protoBase64: Bytes.toBase64( protoBase64: Bytes.toBase64(

View file

@ -5,6 +5,7 @@ import { differenceWith, omit } from 'lodash';
import { v4 as generateUuid } from 'uuid'; import { v4 as generateUuid } from 'uuid';
import { import {
ContentHint,
ErrorCode, ErrorCode,
LibSignalErrorBase, LibSignalErrorBase,
groupEncrypt, groupEncrypt,
@ -293,7 +294,6 @@ export async function sendToGroupViaSenderKey(
timestamp, timestamp,
urgent, urgent,
} = options; } = options;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
const logId = `sendToGroupViaSenderKey/${sendTarget.idForLogging()}`; const logId = `sendToGroupViaSenderKey/${sendTarget.idForLogging()}`;
log.info( log.info(
@ -312,9 +312,9 @@ export async function sendToGroupViaSenderKey(
} }
if ( if (
contentHint !== ContentHint.DEFAULT && contentHint !== ContentHint.Default &&
contentHint !== ContentHint.RESENDABLE && contentHint !== ContentHint.Resendable &&
contentHint !== ContentHint.IMPLICIT contentHint !== ContentHint.Implicit
) { ) {
throw new Error(`${logId}: Invalid contentHint ${contentHint}`); throw new Error(`${logId}: Invalid contentHint ${contentHint}`);
} }