diff --git a/protos/UnidentifiedDelivery.proto b/protos/UnidentifiedDelivery.proto deleted file mode 100644 index 255ab6eeeba..00000000000 --- a/protos/UnidentifiedDelivery.proto +++ /dev/null @@ -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; -} diff --git a/ts/jobs/helpers/sendCallingMessage.ts b/ts/jobs/helpers/sendCallingMessage.ts index b8e640446c1..321aa12add6 100644 --- a/ts/jobs/helpers/sendCallingMessage.ts +++ b/ts/jobs/helpers/sendCallingMessage.ts @@ -1,6 +1,8 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import { ContentHint } from '@signalapp/libsignal-client'; + import { handleMessageSend } from '../../util/handleMessageSend'; import { getSendOptions } from '../../util/getSendOptions'; import { @@ -92,13 +94,11 @@ export async function sendCallingMessage( const callMessage = Proto.CallMessage.decode(Bytes.fromBase64(protoBase64)); - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - try { if (isGroup(conversation.attributes)) { await handleMessageSend( sendContentMessageToGroup({ - contentHint: ContentHint.DEFAULT, + contentHint: ContentHint.Default, contentMessage: new Proto.Content({ callMessage }), isPartialSend, messageId: undefined, diff --git a/ts/jobs/helpers/sendDeleteForEveryone.ts b/ts/jobs/helpers/sendDeleteForEveryone.ts index ce306f16649..6545cb36478 100644 --- a/ts/jobs/helpers/sendDeleteForEveryone.ts +++ b/ts/jobs/helpers/sendDeleteForEveryone.ts @@ -1,6 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import { ContentHint } from '@signalapp/libsignal-client'; import { isNumber } from 'lodash'; import * as Errors from '../../types/errors'; @@ -82,8 +83,7 @@ export async function sendDeleteForEveryone( } const sendType = 'deleteForEveryone'; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - const contentHint = ContentHint.RESENDABLE; + const contentHint = ContentHint.Resendable; const messageIds = [messageId]; const deletedForEveryoneSendStatus = message.get( diff --git a/ts/jobs/helpers/sendDeleteStoryForEveryone.ts b/ts/jobs/helpers/sendDeleteStoryForEveryone.ts index f9b186e71d9..2f6a2b4fc59 100644 --- a/ts/jobs/helpers/sendDeleteStoryForEveryone.ts +++ b/ts/jobs/helpers/sendDeleteStoryForEveryone.ts @@ -1,10 +1,11 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import { ContentHint } from '@signalapp/libsignal-client'; + import * as Errors from '../../types/errors'; import { getSendOptions } from '../../util/getSendOptions'; import { isDirectConversation, isMe } from '../../util/whatTypeOfConversation'; -import { SignalService as Proto } from '../../protobuf'; import { handleMultipleSendErrors, maybeExpandErrors, @@ -68,8 +69,7 @@ export async function sendDeleteStoryForEveryone( strictAssert(isStory(message.attributes), 'Story message must be a story'); const sendType = 'deleteForEveryone'; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - const contentHint = ContentHint.RESENDABLE; + const contentHint = ContentHint.Resendable; const deletedForEveryoneSendStatus = message.get( 'deletedForEveryoneSendStatus' diff --git a/ts/jobs/helpers/sendDirectExpirationTimerUpdate.ts b/ts/jobs/helpers/sendDirectExpirationTimerUpdate.ts index 806847e92d6..3cb558294ee 100644 --- a/ts/jobs/helpers/sendDirectExpirationTimerUpdate.ts +++ b/ts/jobs/helpers/sendDirectExpirationTimerUpdate.ts @@ -1,6 +1,8 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import { ContentHint } from '@signalapp/libsignal-client'; + import { getSendOptions } from '../../util/getSendOptions'; import { isDirectConversation, isMe } from '../../util/whatTypeOfConversation'; import { SignalService as Proto } from '../../protobuf'; @@ -70,8 +72,7 @@ export async function sendDirectExpirationTimerUpdate( profileKey = await ourProfileKeyService.get(); } - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - const contentHint = ContentHint.RESENDABLE; + const contentHint = ContentHint.Resendable; const sendType = 'expirationTimerUpdate'; const flags = Proto.DataMessage.Flags.EXPIRATION_TIMER_UPDATE; diff --git a/ts/jobs/helpers/sendGroupCallUpdate.ts b/ts/jobs/helpers/sendGroupCallUpdate.ts index d5b682e7733..06be00be494 100644 --- a/ts/jobs/helpers/sendGroupCallUpdate.ts +++ b/ts/jobs/helpers/sendGroupCallUpdate.ts @@ -1,9 +1,10 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import { ContentHint } from '@signalapp/libsignal-client'; + import { getSendOptions } from '../../util/getSendOptions'; import { isGroup } from '../../util/whatTypeOfConversation'; -import { SignalService as Proto } from '../../protobuf'; import { handleMultipleSendErrors, maybeExpandErrors, @@ -66,7 +67,6 @@ export async function sendGroupCallUpdate( } const sendType = 'callingMessage'; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; const groupV2 = conversation.getGroupV2Info(); const sendOptions = await getSendOptions(conversation.attributes); if (!groupV2) { @@ -82,7 +82,7 @@ export async function sendGroupCallUpdate( send: () => conversation.queueJob(logId, () => sendToGroup({ - contentHint: ContentHint.DEFAULT, + contentHint: ContentHint.Default, groupSendOptions: { groupCallUpdate: { eraId }, groupV2, diff --git a/ts/jobs/helpers/sendGroupUpdate.ts b/ts/jobs/helpers/sendGroupUpdate.ts index 57c12bcaa92..ae1c37133b0 100644 --- a/ts/jobs/helpers/sendGroupUpdate.ts +++ b/ts/jobs/helpers/sendGroupUpdate.ts @@ -1,9 +1,10 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import { ContentHint } from '@signalapp/libsignal-client'; + import { getSendOptionsForRecipients } from '../../util/getSendOptions'; import { isGroupV2 } from '../../util/whatTypeOfConversation'; -import { SignalService as Proto } from '../../protobuf'; import { handleMultipleSendErrors, maybeExpandErrors, @@ -70,8 +71,7 @@ export async function sendGroupUpdate( const sendOptions = await getSendOptionsForRecipients(recipients); - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - const contentHint = ContentHint.RESENDABLE; + const contentHint = ContentHint.Resendable; const sendType = 'groupChange'; const groupChange = groupChangeBase64 diff --git a/ts/jobs/helpers/sendNormalMessage.ts b/ts/jobs/helpers/sendNormalMessage.ts index ae5f5008e03..6cdfe56af49 100644 --- a/ts/jobs/helpers/sendNormalMessage.ts +++ b/ts/jobs/helpers/sendNormalMessage.ts @@ -3,6 +3,7 @@ import { isNumber } from 'lodash'; import PQueue from 'p-queue'; +import { ContentHint } from '@signalapp/libsignal-client'; import * as Errors from '../../types/errors'; import { strictAssert } from '../../util/assert'; @@ -11,7 +12,6 @@ import { getMessageById } from '../../messages/getMessageById'; import type { ConversationModel } from '../../models/conversations'; import { isGroup, isGroupV2, isMe } from '../../util/whatTypeOfConversation'; import { getSendOptions } from '../../util/getSendOptions'; -import { SignalService as Proto } from '../../protobuf'; import { handleMessageSend } from '../../util/handleMessageSend'; import { findAndFormatContact } from '../../util/findAndFormatContact'; import { uploadAttachment } from '../../util/uploadAttachment'; @@ -302,7 +302,6 @@ export async function sendNormalMessage( } else { const conversationType = conversation.get('type'); const sendOptions = await getSendOptions(conversation.attributes); - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; let innerPromise: Promise; if (conversationType === Message.GROUP) { @@ -324,7 +323,7 @@ export async function sendNormalMessage( abortSignal => sendToGroup({ abortSignal, - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, groupSendOptions: { attachments, bodyRanges, @@ -392,7 +391,7 @@ export async function sendNormalMessage( attachments, bodyRanges, contact, - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, deletedForEveryoneTimestamp, expireTimer, expireTimerVersion: conversation.getExpireTimerVersion(), diff --git a/ts/jobs/helpers/sendNullMessage.ts b/ts/jobs/helpers/sendNullMessage.ts index 657f412e336..c10cf79f520 100644 --- a/ts/jobs/helpers/sendNullMessage.ts +++ b/ts/jobs/helpers/sendNullMessage.ts @@ -1,10 +1,11 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import { ContentHint } from '@signalapp/libsignal-client'; + import { handleMessageSend } from '../../util/handleMessageSend'; import { getSendOptions } from '../../util/getSendOptions'; import { isDirectConversation } from '../../util/whatTypeOfConversation'; -import { SignalService as Proto } from '../../protobuf'; import { handleMultipleSendErrors, maybeExpandErrors, @@ -62,8 +63,7 @@ export async function sendNullMessage( ); const sendOptions = await getSendOptions(conversation.attributes); - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - const contentHint = ContentHint.RESENDABLE; + const contentHint = ContentHint.Resendable; const sendType = 'nullMessage'; // Note: we will send to blocked users, to those still in message request state, etc. @@ -109,7 +109,7 @@ export async function sendNullMessage( abortSignal => sendToGroup({ abortSignal, - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, groupSendOptions: { attachments: [], bodyRanges: [], diff --git a/ts/jobs/helpers/sendProfileKey.ts b/ts/jobs/helpers/sendProfileKey.ts index 71025920e87..a4dbba82404 100644 --- a/ts/jobs/helpers/sendProfileKey.ts +++ b/ts/jobs/helpers/sendProfileKey.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { isNumber } from 'lodash'; +import { ContentHint } from '@signalapp/libsignal-client'; import { handleMessageSend } from '../../util/handleMessageSend'; import { getSendOptions } from '../../util/getSendOptions'; @@ -95,8 +96,7 @@ export async function sendProfileKey( const { revision } = data; const sendOptions = await getSendOptions(conversation.attributes); - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - const contentHint = ContentHint.RESENDABLE; + const contentHint = ContentHint.Resendable; const sendType = 'profileKeyUpdate'; let sendPromise: Promise; diff --git a/ts/jobs/helpers/sendReaction.ts b/ts/jobs/helpers/sendReaction.ts index e0dbc15fe7d..2d0f915d01b 100644 --- a/ts/jobs/helpers/sendReaction.ts +++ b/ts/jobs/helpers/sendReaction.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { isNumber } from 'lodash'; +import { ContentHint } from '@signalapp/libsignal-client'; import * as Errors from '../../types/errors'; import { strictAssert } from '../../util/assert'; @@ -21,7 +22,6 @@ import { isGroupV2, } from '../../util/whatTypeOfConversation'; import { getSendOptions } from '../../util/getSendOptions'; -import { SignalService as Proto } from '../../protobuf'; import { handleMessageSend } from '../../util/handleMessageSend'; import { ourProfileKeyService } from '../../services/ourProfileKey'; import { canReact, isStory } from '../../state/selectors/message'; @@ -211,7 +211,6 @@ export async function sendReaction( successfulConversationIds.add(ourConversationId); } else { const sendOptions = await getSendOptions(conversation.attributes); - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; let promise: Promise; if (isDirectConversation(conversation.attributes)) { @@ -250,7 +249,7 @@ export async function sendReaction( timestamp: pendingReaction.timestamp, expireTimer, expireTimerVersion: conversation.getExpireTimerVersion(), - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, groupId: undefined, profileKey, options: sendOptions, @@ -276,7 +275,7 @@ export async function sendReaction( return sendToGroup({ abortSignal, - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, groupSendOptions: { groupV2: groupV2Info, reaction: reactionForSend, diff --git a/ts/jobs/helpers/sendResendRequest.ts b/ts/jobs/helpers/sendResendRequest.ts index a53d4bf2d8d..99990b5334f 100644 --- a/ts/jobs/helpers/sendResendRequest.ts +++ b/ts/jobs/helpers/sendResendRequest.ts @@ -1,12 +1,11 @@ // Copyright 2022 Signal Messenger, LLC // 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 { getSendOptions } from '../../util/getSendOptions'; import { isDirectConversation } from '../../util/whatTypeOfConversation'; -import { SignalService as Proto } from '../../protobuf'; import { handleMultipleSendErrors, maybeExpandErrors, @@ -98,7 +97,6 @@ export async function sendResendRequest( const plaintext = PlaintextContent.deserialize( 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 // 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, recipients: [senderAci], proto: plaintext, - contentHint: ContentHint.DEFAULT, + contentHint: ContentHint.Default, groupId, options, urgent: false, @@ -124,7 +122,7 @@ export async function sendResendRequest( // 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. - if (contentHint === ContentHint.RESENDABLE) { + if (contentHint === ContentHint.Resendable) { const { retryPlaceholders } = window.Signal.Services; 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 // reset their session. - if (contentHint === ContentHint.IMPLICIT) { + if (contentHint === ContentHint.Implicit) { log.info('contentHint is IMPLICIT, adding no timeline item.'); return; } diff --git a/ts/jobs/helpers/sendStory.ts b/ts/jobs/helpers/sendStory.ts index 98d049c2809..f26b77fe73a 100644 --- a/ts/jobs/helpers/sendStory.ts +++ b/ts/jobs/helpers/sendStory.ts @@ -2,6 +2,8 @@ // SPDX-License-Identifier: AGPL-3.0-only import { isEqual } from 'lodash'; +import { ContentHint } from '@signalapp/libsignal-client'; + import type { UploadedAttachmentType } from '../../types/Attachment'; import type { ConversationModel } from '../../models/conversations'; import type { @@ -324,8 +326,6 @@ export async function sendStory( return; } - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - const sendOptions = await getSendOptionsForRecipients( pendingSendRecipientServiceIds, { story: true } @@ -356,7 +356,7 @@ export async function sendStory( contentMessage.storyMessage = storyMessage; const innerPromise = sendContentMessageToGroup({ - contentHint: ContentHint.IMPLICIT, + contentHint: ContentHint.Implicit, contentMessage, isPartialSend: false, messageId: undefined, diff --git a/ts/models/conversations.ts b/ts/models/conversations.ts index 49e09d030f0..3bea5962f32 100644 --- a/ts/models/conversations.ts +++ b/ts/models/conversations.ts @@ -4,6 +4,7 @@ import { compact, isNumber, throttle, debounce } from 'lodash'; import { v4 as generateGuid } from 'uuid'; import PQueue from 'p-queue'; +import { ContentHint } from '@signalapp/libsignal-client'; import type { ReadonlyDeep } from 'type-fest'; import type { @@ -1377,8 +1378,6 @@ export class ConversationModel { const contentMessage = messaging.getTypingContentMessage(content); - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - const sendOptions = { ...(await getSendOptions(this.attributes)), online: true, @@ -1386,7 +1385,7 @@ export class ConversationModel { if (isDirectConversation(this.attributes)) { await handleMessageSend( messaging.sendMessageProtoAndWait({ - contentHint: ContentHint.IMPLICIT, + contentHint: ContentHint.Implicit, groupId: undefined, options: sendOptions, proto: contentMessage, @@ -1399,7 +1398,7 @@ export class ConversationModel { } else { await handleMessageSend( sendContentMessageToGroup({ - contentHint: ContentHint.IMPLICIT, + contentHint: ContentHint.Implicit, contentMessage, messageId: undefined, online: true, diff --git a/ts/services/senderCertificate.ts b/ts/services/senderCertificate.ts index 3e343cd07bd..e99289f2968 100644 --- a/ts/services/senderCertificate.ts +++ b/ts/services/senderCertificate.ts @@ -1,6 +1,8 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import { SenderCertificate } from '@signalapp/libsignal-client'; + import type { SerializedCertificateType } from '../textsecure/OutgoingMessage'; import { SenderCertificateMode, @@ -14,9 +16,6 @@ import { createLogger } from '../logging/log'; import type { StorageInterface } from '../types/Storage.d'; import * as Errors from '../types/errors'; import type { WebAPIType } from '../textsecure/WebAPI'; -import { SignalService as Proto } from '../protobuf'; - -import SenderCertificate = Proto.SenderCertificate; import { safeParseUnknown } from '../util/schemas'; const log = createLogger('senderCertificate'); @@ -176,11 +175,8 @@ export class SenderCertificateService { return undefined; } const certificate = Bytes.fromBase64(certificateString); - const decodedContainer = SenderCertificate.decode(certificate); - const decodedCert = decodedContainer.certificate - ? SenderCertificate.Certificate.decode(decodedContainer.certificate) - : undefined; - const expires = decodedCert?.expires?.toNumber(); + const decodedCert = SenderCertificate.deserialize(certificate); + const expires = decodedCert.expiration(); if (!isExpirationValid(expires)) { log.warn( @@ -240,8 +236,8 @@ function modeToLogString(mode: SenderCertificateMode): string { } } -function isExpirationValid(expiration: unknown): expiration is number { - return typeof expiration === 'number' && expiration > Date.now(); +function isExpirationValid(expiration: number): boolean { + return expiration > Date.now(); } export const senderCertificateService = new SenderCertificateService(); diff --git a/ts/test-electron/services/senderCertificate_test.ts b/ts/test-electron/services/senderCertificate_test.ts index 742b6a43a36..996fee4d67f 100644 --- a/ts/test-electron/services/senderCertificate_test.ts +++ b/ts/test-electron/services/senderCertificate_test.ts @@ -6,18 +6,20 @@ import { assert } from 'chai'; 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 { drop } from '../../util/drop'; import * as Bytes from '../../Bytes'; import { SenderCertificateMode } from '../../textsecure/OutgoingMessage'; -import { SignalService as Proto } from '../../protobuf'; import { SenderCertificateService } from '../../services/senderCertificate'; -import SenderCertificate = Proto.SenderCertificate; - describe('SenderCertificateService', () => { const FIFTEEN_MINUTES = 15 * durations.MINUTE; @@ -39,14 +41,26 @@ describe('SenderCertificateService', () => { } 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; - const certificate = new SenderCertificate.Certificate(); - certificate.expires = Long.fromNumber(fakeValidCertificateExpiry); - fakeValidCertificate.certificate = - SenderCertificate.Certificate.encode(certificate).finish(); - fakeValidEncodedCertificate = - SenderCertificate.encode(fakeValidCertificate).finish(); + fakeValidCertificate = SenderCertificate.new( + 'aaaaaaaa-7000-11eb-b32a-33b8a8a487a6', + null, + 2, + fakeSenderIdentityKey.publicKey, + fakeValidCertificateExpiry, + fakeServerCert, + fakeServerKey.privateKey + ); + fakeValidEncodedCertificate = fakeValidCertificate.serialize(); fakeServer = { isOnline: () => true, @@ -65,7 +79,9 @@ describe('SenderCertificateService', () => { put: 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'); }); @@ -199,15 +215,28 @@ describe('SenderCertificateService', () => { it('returns undefined if the server returns an already-expired certificate', async () => { const service = initializeTestService(); - const expiredCertificate = new SenderCertificate(); - const certificate = new SenderCertificate.Certificate(); - certificate.expires = Long.fromNumber(Date.now() - 1000); - expiredCertificate.certificate = - SenderCertificate.Certificate.encode(certificate).finish(); + const fakeTrustRoot = IdentityKeyPair.generate(); + const fakeServerKey = IdentityKeyPair.generate(); + const fakeSenderIdentityKey = IdentityKeyPair.generate(); + const fakeServerCert = ServerCertificate.new( + 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({ - certificate: Bytes.toBase64( - SenderCertificate.encode(expiredCertificate).finish() - ), + certificate: Bytes.toBase64(expiredCertificate.serialize()), }); assert.isUndefined(await service.get(SenderCertificateMode.WithE164)); diff --git a/ts/textsecure/MessageReceiver.ts b/ts/textsecure/MessageReceiver.ts index 9c3176ef1d7..578378af527 100644 --- a/ts/textsecure/MessageReceiver.ts +++ b/ts/textsecure/MessageReceiver.ts @@ -1699,12 +1699,7 @@ export default class MessageReceiver 'Missing sender certificate for sealed sender message' ); - const unidentifiedSenderTypeEnum = - Proto.UnidentifiedSenderMessage.Message.Type; - - if ( - messageContent.msgType() === unidentifiedSenderTypeEnum.PLAINTEXT_CONTENT - ) { + if (messageContent.msgType() === CiphertextMessageType.Plaintext) { log.info( `decryptSealedSender(${logId}): ` + 'unidentified message/plaintext contents' @@ -1719,9 +1714,7 @@ export default class MessageReceiver }; } - if ( - messageContent.msgType() === unidentifiedSenderTypeEnum.SENDERKEY_MESSAGE - ) { + if (messageContent.msgType() === CiphertextMessageType.SenderKey) { log.info( `decryptSealedSender(${logId}): ` + 'unidentified message/sender key contents' @@ -1777,7 +1770,7 @@ export default class MessageReceiver envelope.sourceDevice ); const message = - messageContent.msgType() === unidentifiedSenderTypeEnum.PREKEY_MESSAGE + messageContent.msgType() === CiphertextMessageType.PreKey ? PreKeySignalMessage.deserialize(messageContent.contents()) : SignalMessage.deserialize(messageContent.contents()); const plaintext = await this.#storage.protocol.enqueueSessionJob( diff --git a/ts/textsecure/SendMessage.ts b/ts/textsecure/SendMessage.ts index f8937fd2c68..390279080a8 100644 --- a/ts/textsecure/SendMessage.ts +++ b/ts/textsecure/SendMessage.ts @@ -10,6 +10,7 @@ import PQueue from 'p-queue'; import pMap from 'p-map'; import type { PlaintextContent } from '@signalapp/libsignal-client'; import { + ContentHint, ProtocolAddress, SenderKeyDistributionMessage, } from '@signalapp/libsignal-client'; @@ -1381,13 +1382,11 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return this.sendIndividualProto({ serviceId: myAci, proto: contentMessage, timestamp, - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, options, urgent, }); @@ -1403,10 +1402,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: myAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1427,10 +1424,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: myAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1451,10 +1446,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: myAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1476,10 +1469,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: myAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1501,10 +1492,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: myAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1526,10 +1515,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: myAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1624,10 +1611,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: myAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1653,10 +1638,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: myAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1684,10 +1667,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: ourAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1722,10 +1703,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: ourAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1759,13 +1738,11 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return this.sendIndividualProto({ serviceId: myAci, proto: contentMessage, timestamp: Date.now(), - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, options, urgent: true, }); @@ -1792,13 +1769,11 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return this.sendIndividualProto({ serviceId: myAci, proto: contentMessage, timestamp: Date.now(), - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, options, urgent: false, }); @@ -1839,13 +1814,11 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return this.sendIndividualProto({ serviceId: myAci, proto: contentMessage, timestamp: Date.now(), - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, options, urgent: false, }); @@ -1877,10 +1850,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: myAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1921,10 +1892,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: myAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1962,10 +1931,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: myAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -2009,10 +1976,8 @@ export default class MessageSender { const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return { - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: myAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -2045,13 +2010,11 @@ export default class MessageSender { reason: `sendCallingMessage(${timestamp})`, }); - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return this.sendMessageProtoAndWait({ timestamp, recipients, proto: contentMessage, - contentHint: ContentHint.DEFAULT, + contentHint: ContentHint.Default, groupId: undefined, options, urgent, @@ -2134,13 +2097,11 @@ export default class MessageSender { }); } - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - return this.sendIndividualProto({ serviceId: senderAci, proto: contentMessage, timestamp, - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, options, urgent: false, }); @@ -2389,7 +2350,6 @@ export default class MessageSender { options?: Readonly ): Promise { const timestamp = Date.now(); - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; const contentMessage = await this.getSenderKeyDistributionMessage( distributionId, { @@ -2401,7 +2361,7 @@ export default class MessageSender { const sendLogCallback = serviceIds.length > 1 ? this.makeSendLogCallback({ - contentHint: contentHint ?? ContentHint.IMPLICIT, + contentHint: contentHint ?? ContentHint.Implicit, proto: Proto.Content.encode(contentMessage).finish(), sendType: 'senderKeyDistributionMessage', timestamp, @@ -2411,7 +2371,7 @@ export default class MessageSender { : undefined; return this.sendGroupProto({ - contentHint: contentHint ?? ContentHint.IMPLICIT, + contentHint: contentHint ?? ContentHint.Implicit, groupId, options, proto: contentMessage, diff --git a/ts/util/callDisposition.ts b/ts/util/callDisposition.ts index e4b5ae83564..7d747991e9a 100644 --- a/ts/util/callDisposition.ts +++ b/ts/util/callDisposition.ts @@ -11,6 +11,7 @@ import { callIdFromRingId, RingUpdate, } from '@signalapp/ringrtc'; +import { ContentHint } from '@signalapp/libsignal-client'; import { isEqual } from 'lodash'; import { strictAssert } from './assert'; import { DataReader, DataWriter } from '../sql/Client'; @@ -1305,10 +1306,8 @@ async function updateRemoteCallHistory( const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - await singleProtoJobQueue.add({ - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: ourAci, isSyncMessage: true, protoBase64: Bytes.toBase64( @@ -1468,11 +1467,9 @@ export async function markAllCallHistoryReadAndSync( const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - log.info('markAllCallHistoryReadAndSync: Queueing sync message'); await singleProtoJobQueue.add({ - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: ourAci, isSyncMessage: true, protoBase64: Bytes.toBase64( diff --git a/ts/util/sendCallLinkUpdateSync.ts b/ts/util/sendCallLinkUpdateSync.ts index 23e142b6589..6e07e42ed53 100644 --- a/ts/util/sendCallLinkUpdateSync.ts +++ b/ts/util/sendCallLinkUpdateSync.ts @@ -1,5 +1,8 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only + +import { ContentHint } from '@signalapp/libsignal-client'; + import * as Bytes from '../Bytes'; import { CallLinkUpdateSyncType } from '../types/CallLink'; import { createLogger } from '../logging/log'; @@ -55,10 +58,8 @@ async function _sendCallLinkUpdateSync( const contentMessage = new Proto.Content(); contentMessage.syncMessage = syncMessage; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; - await singleProtoJobQueue.add({ - contentHint: ContentHint.RESENDABLE, + contentHint: ContentHint.Resendable, serviceId: ourAci, isSyncMessage: true, protoBase64: Bytes.toBase64( diff --git a/ts/util/sendToGroup.ts b/ts/util/sendToGroup.ts index 3e6090b953e..3803f1747fd 100644 --- a/ts/util/sendToGroup.ts +++ b/ts/util/sendToGroup.ts @@ -5,6 +5,7 @@ import { differenceWith, omit } from 'lodash'; import { v4 as generateUuid } from 'uuid'; import { + ContentHint, ErrorCode, LibSignalErrorBase, groupEncrypt, @@ -293,7 +294,6 @@ export async function sendToGroupViaSenderKey( timestamp, urgent, } = options; - const { ContentHint } = Proto.UnidentifiedSenderMessage.Message; const logId = `sendToGroupViaSenderKey/${sendTarget.idForLogging()}`; log.info( @@ -312,9 +312,9 @@ export async function sendToGroupViaSenderKey( } if ( - contentHint !== ContentHint.DEFAULT && - contentHint !== ContentHint.RESENDABLE && - contentHint !== ContentHint.IMPLICIT + contentHint !== ContentHint.Default && + contentHint !== ContentHint.Resendable && + contentHint !== ContentHint.Implicit ) { throw new Error(`${logId}: Invalid contentHint ${contentHint}`); }