More protobufjs migration

This commit is contained in:
Fedor Indutny
2021-07-09 12:36:10 -07:00
committed by GitHub
parent cf06e6638e
commit ddbbe3a6b1
70 changed files with 3967 additions and 3369 deletions

View File

@@ -1,7 +1,7 @@
// Copyright 2020-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { isNumber } from 'lodash';
import { isNumber, noop } from 'lodash';
import { bindActionCreators } from 'redux';
import { render } from 'react-dom';
import {
@@ -9,16 +9,23 @@ import {
PlaintextContent,
} from '@signalapp/signal-client';
import { DataMessageClass, SyncMessageClass } from './textsecure.d';
import { SessionResetsType } from './textsecure/Types.d';
import { MessageAttributesType } from './model-types.d';
import MessageReceiver from './textsecure/MessageReceiver';
import { SessionResetsType, ProcessedDataMessage } from './textsecure/Types.d';
import {
MessageAttributesType,
ConversationAttributesType,
} from './model-types.d';
import * as Bytes from './Bytes';
import { typedArrayToArrayBuffer } from './Crypto';
import { WhatIsThis } from './window.d';
import { getTitleBarVisibility, TitleBarVisibility } from './types/Settings';
import { SocketStatus } from './types/SocketStatus';
import { DEFAULT_CONVERSATION_COLOR } from './types/Colors';
import { ChallengeHandler } from './challenge';
import { isWindowDragElement } from './util/isWindowDragElement';
import { assert } from './util/assert';
import { assert, strictAssert } from './util/assert';
import { dropNull } from './util/dropNull';
import { normalizeUuid } from './util/normalizeUuid';
import { filter } from './util/iterables';
import { isNotNil } from './util/isNotNil';
import { senderCertificateService } from './services/senderCertificate';
@@ -36,9 +43,30 @@ import { shouldRespondWithProfileKey } from './util/shouldRespondWithProfileKey'
import { LatestQueue } from './util/LatestQueue';
import { parseIntOrThrow } from './util/parseIntOrThrow';
import {
DecryptionErrorType,
RetryRequestType,
} from './textsecure/MessageReceiver';
TypingEvent,
ErrorEvent,
DeliveryEvent,
DecryptionErrorEvent,
DecryptionErrorEventData,
SentEvent,
SentEventData,
ProfileKeyUpdateEvent,
MessageEvent,
MessageEventData,
RetryRequestEvent,
RetryRequestEventData,
ReadEvent,
ConfigurationEvent,
ViewSyncEvent,
MessageRequestResponseEvent,
FetchLatestEvent,
KeysEvent,
StickerPackEvent,
VerifiedEvent,
ReadSyncEvent,
ContactEvent,
GroupEvent,
} from './textsecure/messageReceiverEvents';
import { connectToServerWithStoredCredentials } from './util/connectToServerWithStoredCredentials';
import * as universalExpireTimer from './util/universalExpireTimer';
import { isDirectConversation, isGroupV2 } from './util/whatTypeOfConversation';
@@ -59,6 +87,7 @@ import {
SystemTraySetting,
parseSystemTraySetting,
} from './types/SystemTraySetting';
import * as Stickers from './types/Stickers';
import { SignalService as Proto } from './protobuf';
const MAX_ATTACHMENT_DOWNLOAD_AGE = 3600 * 72 * 1000;
@@ -149,7 +178,7 @@ export async function startApp(): Promise<void> {
name: 'Whisper.deliveryReceiptBatcher',
wait: 500,
maxSize: 500,
processBatch: async (items: WhatIsThis) => {
processBatch: async items => {
const byConversationId = window._.groupBy(items, item =>
window.ConversationController.ensureContactIds({
e164: item.source,
@@ -320,7 +349,7 @@ export async function startApp(): Promise<void> {
window.getAccountManager()!.refreshPreKeys();
});
let messageReceiver: WhatIsThis;
let messageReceiver: MessageReceiver | undefined;
let preMessageReceiverStatus: SocketStatus | undefined;
window.getSocketStatus = () => {
if (messageReceiver) {
@@ -589,7 +618,7 @@ export async function startApp(): Promise<void> {
if (messageReceiver) {
messageReceiver.unregisterBatchers();
messageReceiver = null;
messageReceiver = undefined;
}
// A number of still-to-queue database queries might be waiting inside batchers.
@@ -619,14 +648,14 @@ export async function startApp(): Promise<void> {
window.isShowingModal = true;
// Kick off the download
window.Signal.Stickers.downloadEphemeralPack(packId, key);
Stickers.downloadEphemeralPack(packId, key);
const props = {
packId,
onClose: async () => {
window.isShowingModal = false;
stickerPreviewModalView.remove();
await window.Signal.Stickers.removeEphemeralPack(packId);
await Stickers.removeEphemeralPack(packId);
},
};
@@ -703,7 +732,7 @@ export async function startApp(): Promise<void> {
},
installStickerPack: async (packId: string, key: string) => {
window.Signal.Stickers.downloadStickerPack(packId, key, {
Stickers.downloadStickerPack(packId, key, {
finalStatus: 'installed',
});
},
@@ -894,7 +923,7 @@ export async function startApp(): Promise<void> {
try {
await Promise.all([
window.ConversationController.load(),
window.Signal.Stickers.load(),
Stickers.load(),
window.Signal.Emojis.load(),
window.textsecure.storage.protocol.hydrateCaches(),
]);
@@ -963,7 +992,7 @@ export async function startApp(): Promise<void> {
},
emojis: window.Signal.Emojis.getInitialState(),
items: window.storage.getItemsState(),
stickers: window.Signal.Stickers.getInitialState(),
stickers: Stickers.getInitialState(),
user: {
attachmentsPath: window.baseAttachmentsPath,
stickersPath: window.baseStickersPath,
@@ -1850,6 +1879,8 @@ export async function startApp(): Promise<void> {
}
window.getSyncRequest = (timeoutMillis?: number) => {
strictAssert(messageReceiver, 'MessageReceiver not initialized');
const syncRequest = new window.textsecure.SyncRequest(
window.textsecure.messaging,
messageReceiver,
@@ -1859,8 +1890,8 @@ export async function startApp(): Promise<void> {
return syncRequest;
};
let disconnectTimer: WhatIsThis | null = null;
let reconnectTimer: WhatIsThis | null = null;
let disconnectTimer: NodeJS.Timeout | undefined;
let reconnectTimer: number | undefined;
function onOffline() {
window.log.info('offline');
@@ -1886,12 +1917,12 @@ export async function startApp(): Promise<void> {
if (disconnectTimer && isSocketOnline()) {
window.log.warn('Already online. Had a blip in online/offline status.');
clearTimeout(disconnectTimer);
disconnectTimer = null;
disconnectTimer = undefined;
return;
}
if (disconnectTimer) {
clearTimeout(disconnectTimer);
disconnectTimer = null;
disconnectTimer = undefined;
}
connect();
@@ -1909,7 +1940,7 @@ export async function startApp(): Promise<void> {
window.log.info('disconnect');
// Clear timer, since we're only called when the timer is expired
disconnectTimer = null;
disconnectTimer = undefined;
AttachmentDownloads.stop();
if (messageReceiver) {
@@ -1934,7 +1965,7 @@ export async function startApp(): Promise<void> {
if (reconnectTimer) {
clearTimeout(reconnectTimer);
reconnectTimer = null;
reconnectTimer = undefined;
}
// Bootstrap our online/offline detection, only the first time we connect
@@ -1964,7 +1995,7 @@ export async function startApp(): Promise<void> {
if (messageReceiver) {
messageReceiver.unregisterBatchers();
messageReceiver = null;
messageReceiver = undefined;
}
const OLD_USERNAME = window.storage.get('number_id', '');
@@ -2043,8 +2074,11 @@ export async function startApp(): Promise<void> {
preMessageReceiverStatus = undefined;
// eslint-disable-next-line no-inner-declarations
function addQueuedEventListener(name: string, handler: WhatIsThis) {
messageReceiver.addEventListener(name, (...args: Array<WhatIsThis>) =>
function queuedEventListener<Args extends Array<unknown>>(
handler: (...args: Args) => Promise<void> | void,
track = true
): (...args: Args) => void {
return (...args: Args): void => {
eventHandlerQueue.add(async () => {
try {
await handler(...args);
@@ -2052,40 +2086,97 @@ export async function startApp(): Promise<void> {
// message/sent: Message.handleDataMessage has its own queue and will
// trigger this event itself when complete.
// error: Error processing (below) also has its own queue and self-trigger.
if (name !== 'message' && name !== 'sent' && name !== 'error') {
if (track) {
window.Whisper.events.trigger('incrementProgress');
}
}
})
);
});
};
}
addQueuedEventListener('message', onMessageReceived);
addQueuedEventListener('delivery', onDeliveryReceipt);
addQueuedEventListener('contact', onContactReceived);
addQueuedEventListener('contactsync', onContactSyncComplete);
addQueuedEventListener('group', onGroupReceived);
addQueuedEventListener('groupsync', onGroupSyncComplete);
addQueuedEventListener('sent', onSentMessage);
addQueuedEventListener('readSync', onReadSync);
addQueuedEventListener('read', onReadReceipt);
addQueuedEventListener('verified', onVerified);
addQueuedEventListener('error', onError);
addQueuedEventListener('decryption-error', onDecryptionError);
addQueuedEventListener('retry-request', onRetryRequest);
addQueuedEventListener('empty', onEmpty);
addQueuedEventListener('reconnect', onReconnect);
addQueuedEventListener('configuration', onConfiguration);
addQueuedEventListener('typing', onTyping);
addQueuedEventListener('sticker-pack', onStickerPack);
addQueuedEventListener('viewSync', onViewSync);
addQueuedEventListener(
'messageRequestResponse',
onMessageRequestResponse
messageReceiver.addEventListener(
'message',
queuedEventListener(onMessageReceived, false)
);
addQueuedEventListener('profileKeyUpdate', onProfileKeyUpdate);
addQueuedEventListener('fetchLatest', onFetchLatestSync);
addQueuedEventListener('keys', onKeysSync);
messageReceiver.addEventListener(
'delivery',
queuedEventListener(onDeliveryReceipt)
);
messageReceiver.addEventListener(
'contact',
queuedEventListener(onContactReceived)
);
messageReceiver.addEventListener(
'contactSync',
queuedEventListener(onContactSyncComplete)
);
messageReceiver.addEventListener(
'group',
queuedEventListener(onGroupReceived)
);
messageReceiver.addEventListener(
'groupSync',
queuedEventListener(onGroupSyncComplete)
);
messageReceiver.addEventListener(
'sent',
queuedEventListener(onSentMessage, false)
);
messageReceiver.addEventListener(
'readSync',
queuedEventListener(onReadSync)
);
messageReceiver.addEventListener(
'read',
queuedEventListener(onReadReceipt)
);
messageReceiver.addEventListener(
'verified',
queuedEventListener(onVerified)
);
messageReceiver.addEventListener(
'error',
queuedEventListener(onError, false)
);
messageReceiver.addEventListener(
'decryption-error',
queuedEventListener(onDecryptionError)
);
messageReceiver.addEventListener(
'retry-request',
queuedEventListener(onRetryRequest)
);
messageReceiver.addEventListener('empty', queuedEventListener(onEmpty));
messageReceiver.addEventListener(
'reconnect',
queuedEventListener(onReconnect)
);
messageReceiver.addEventListener(
'configuration',
queuedEventListener(onConfiguration)
);
messageReceiver.addEventListener('typing', queuedEventListener(onTyping));
messageReceiver.addEventListener(
'sticker-pack',
queuedEventListener(onStickerPack)
);
messageReceiver.addEventListener(
'viewSync',
queuedEventListener(onViewSync)
);
messageReceiver.addEventListener(
'messageRequestResponse',
queuedEventListener(onMessageRequestResponse)
);
messageReceiver.addEventListener(
'profileKeyUpdate',
queuedEventListener(onProfileKeyUpdate)
);
messageReceiver.addEventListener(
'fetchLatest',
queuedEventListener(onFetchLatestSync)
);
messageReceiver.addEventListener('keys', queuedEventListener(onKeysSync));
AttachmentDownloads.start({
getMessageReceiver: () => messageReceiver,
@@ -2093,7 +2184,7 @@ export async function startApp(): Promise<void> {
});
if (connectCount === 1) {
window.Signal.Stickers.downloadQueuedPacks();
Stickers.downloadQueuedPacks();
if (!newVersion) {
runStorageService();
}
@@ -2229,9 +2320,9 @@ export async function startApp(): Promise<void> {
syncMessage: true,
});
const installedStickerPacks = window.Signal.Stickers.getInstalledStickerPacks();
const installedStickerPacks = Stickers.getInstalledStickerPacks();
if (installedStickerPacks.length) {
const operations = installedStickerPacks.map((pack: WhatIsThis) => ({
const operations = installedStickerPacks.map(pack => ({
packId: pack.id,
packKey: pack.key,
installed: true,
@@ -2313,18 +2404,22 @@ export async function startApp(): Promise<void> {
window.log.info(
'waitForEmptyEventQueue: Waiting for MessageReceiver empty event...'
);
let resolve: WhatIsThis;
let reject: WhatIsThis;
const promise = new Promise((innerResolve, innerReject) => {
let resolve: undefined | (() => void);
let reject: undefined | ((error: Error) => void);
const promise = new Promise<void>((innerResolve, innerReject) => {
resolve = innerResolve;
reject = innerReject;
});
const timeout = setTimeout(reject, FIVE_MINUTES);
const timeout = reject && setTimeout(reject, FIVE_MINUTES);
const onEmptyOnce = () => {
messageReceiver.removeEventListener('empty', onEmptyOnce);
if (messageReceiver) {
messageReceiver.removeEventListener('empty', onEmptyOnce);
}
clearTimeout(timeout);
resolve();
if (resolve) {
resolve();
}
};
messageReceiver.addEventListener('empty', onEmptyOnce);
@@ -2459,7 +2554,7 @@ export async function startApp(): Promise<void> {
connect();
}
function onConfiguration(ev: WhatIsThis) {
function onConfiguration(ev: ConfigurationEvent) {
ev.confirm();
const { configuration } = ev;
@@ -2470,7 +2565,7 @@ export async function startApp(): Promise<void> {
linkPreviews,
} = configuration;
window.storage.put('read-receipt-setting', readReceipts);
window.storage.put('read-receipt-setting', Boolean(readReceipts));
if (
unidentifiedDeliveryIndicators === true ||
@@ -2491,7 +2586,7 @@ export async function startApp(): Promise<void> {
}
}
function onTyping(ev: WhatIsThis) {
function onTyping(ev: TypingEvent) {
// Note: this type of message is automatically removed from cache in MessageReceiver
const { typing, sender, senderUuid, senderDevice } = ev;
@@ -2557,12 +2652,12 @@ export async function startApp(): Promise<void> {
});
}
async function onStickerPack(ev: WhatIsThis) {
async function onStickerPack(ev: StickerPackEvent) {
ev.confirm();
const packs = ev.stickerPacks || [];
const packs = ev.stickerPacks;
packs.forEach((pack: WhatIsThis) => {
packs.forEach(pack => {
const { id, key, isInstall, isRemove } = pack || {};
if (!id || !key || (!isInstall && !isRemove)) {
@@ -2572,7 +2667,7 @@ export async function startApp(): Promise<void> {
return;
}
const status = window.Signal.Stickers.getStickerPackStatus(id);
const status = Stickers.getStickerPackStatus(id);
if (status === 'installed' && isRemove) {
window.reduxActions.stickers.uninstallStickerPack(id, key, {
@@ -2584,7 +2679,7 @@ export async function startApp(): Promise<void> {
fromSync: true,
});
} else {
window.Signal.Stickers.downloadStickerPack(id, key, {
Stickers.downloadStickerPack(id, key, {
finalStatus: 'installed',
fromSync: true,
});
@@ -2598,7 +2693,7 @@ export async function startApp(): Promise<void> {
await window.storage.put('synced_at', Date.now());
}
async function onContactReceived(ev: WhatIsThis) {
async function onContactReceived(ev: ContactEvent) {
const details = ev.contactDetails;
if (
@@ -2610,20 +2705,20 @@ export async function startApp(): Promise<void> {
// special case for syncing details about ourselves
if (details.profileKey) {
window.log.info('Got sync message with our own profile key');
ourProfileKeyService.set(details.profileKey);
ourProfileKeyService.set(typedArrayToArrayBuffer(details.profileKey));
}
}
const c = new window.Whisper.Conversation({
const c = new window.Whisper.Conversation(({
e164: details.number,
uuid: details.uuid,
type: 'private',
} as WhatIsThis);
} as Partial<ConversationAttributesType>) as WhatIsThis);
const validationError = c.validate();
if (validationError) {
window.log.error(
'Invalid contact received:',
Errors.toLogFormat(validationError as WhatIsThis)
Errors.toLogFormat(validationError)
);
return;
}
@@ -2638,9 +2733,7 @@ export async function startApp(): Promise<void> {
const conversation = window.ConversationController.get(detailsId)!;
if (details.profileKey) {
const profileKey = window.Signal.Crypto.arrayBufferToBase64(
details.profileKey
);
const profileKey = Bytes.toBase64(details.profileKey);
conversation.setProfileKey(profileKey);
}
@@ -2698,14 +2791,18 @@ export async function startApp(): Promise<void> {
if (details.verified) {
const { verified } = details;
const verifiedEvent = new Event('verified');
verifiedEvent.verified = {
state: verified.state,
destination: verified.destination,
destinationUuid: verified.destinationUuid,
identityKey: verified.identityKey.toArrayBuffer(),
};
(verifiedEvent as WhatIsThis).viaContactSync = true;
const verifiedEvent = new VerifiedEvent(
{
state: dropNull(verified.state),
destination: dropNull(verified.destination),
destinationUuid: dropNull(verified.destinationUuid),
identityKey: verified.identityKey
? typedArrayToArrayBuffer(verified.identityKey)
: undefined,
viaContactSync: true,
},
noop
);
await onVerified(verifiedEvent);
}
@@ -2726,11 +2823,11 @@ export async function startApp(): Promise<void> {
}
// Note: this handler is only for v1 groups received via 'group sync' messages
async function onGroupReceived(ev: WhatIsThis) {
async function onGroupReceived(ev: GroupEvent) {
const details = ev.groupDetails;
const { id } = details;
const idBuffer = window.Signal.Crypto.fromEncodedBinaryToArrayBuffer(id);
const idBuffer = id;
const idBytes = idBuffer.byteLength;
if (idBytes !== 16) {
window.log.error(
@@ -2740,7 +2837,7 @@ export async function startApp(): Promise<void> {
}
const conversation = await window.ConversationController.getOrCreateAndWait(
id,
Bytes.toBinary(id),
'group'
);
if (isGroupV2(conversation.attributes)) {
@@ -2751,18 +2848,18 @@ export async function startApp(): Promise<void> {
return;
}
const memberConversations = details.membersE164.map((e164: WhatIsThis) =>
const memberConversations = details.membersE164.map(e164 =>
window.ConversationController.getOrCreate(e164, 'private')
);
const members = memberConversations.map((c: WhatIsThis) => c.get('id'));
const members = memberConversations.map(c => c.get('id'));
const updates = {
const updates: Partial<ConversationAttributesType> = {
name: details.name,
members,
type: 'group',
inbox_position: details.inboxPosition,
} as WhatIsThis;
};
if (details.active) {
updates.left = false;
@@ -2823,8 +2920,16 @@ export async function startApp(): Promise<void> {
data,
confirm,
messageDescriptor,
}: WhatIsThis) {
const profileKey = data.message.profileKey.toString('base64');
}: {
data: MessageEventData;
confirm: () => void;
messageDescriptor: MessageDescriptor;
}) {
const { profileKey } = data.message;
strictAssert(
profileKey !== undefined,
'handleMessageReceivedProfileUpdate: missing profileKey'
);
const sender = window.ConversationController.get(messageDescriptor.id);
if (sender) {
@@ -2864,7 +2969,7 @@ export async function startApp(): Promise<void> {
// Note: We do very little in this function, since everything in handleDataMessage is
// inside a conversation-specific queue(). Any code here might run before an earlier
// message is processed in handleDataMessage().
function onMessageReceived(event: WhatIsThis) {
function onMessageReceived(event: MessageEvent) {
const { data, confirm } = event;
const messageDescriptor = getMessageDescriptor({
@@ -2903,10 +3008,13 @@ export async function startApp(): Promise<void> {
}
if (data.message.reaction) {
window.normalizeUuids(
data.message.reaction,
['targetAuthorUuid'],
'background::onMessageReceived'
strictAssert(
data.message.reaction.targetAuthorUuid,
'Reaction without targetAuthorUuid'
);
const targetAuthorUuid = normalizeUuid(
data.message.reaction.targetAuthorUuid,
'DataMessage.Reaction.targetAuthorUuid'
);
const { reaction } = data.message;
@@ -2924,7 +3032,7 @@ export async function startApp(): Promise<void> {
const reactionModel = Reactions.getSingleton().add({
emoji: reaction.emoji,
remove: reaction.remove,
targetAuthorUuid: reaction.targetAuthorUuid,
targetAuthorUuid,
targetTimestamp: reaction.targetTimestamp,
timestamp: Date.now(),
fromId: window.ConversationController.ensureContactIds({
@@ -2965,7 +3073,7 @@ export async function startApp(): Promise<void> {
return Promise.resolve();
}
async function onProfileKeyUpdate({ data, confirm }: WhatIsThis) {
async function onProfileKeyUpdate({ data, confirm }: ProfileKeyUpdateEvent) {
const conversationId = window.ConversationController.ensureContactIds({
e164: data.source,
uuid: data.sourceUuid,
@@ -3007,7 +3115,11 @@ export async function startApp(): Promise<void> {
data,
confirm,
messageDescriptor,
}: WhatIsThis) {
}: {
data: SentEventData;
confirm: () => void;
messageDescriptor: MessageDescriptor;
}) {
// First set profileSharing = true for the conversation we sent to
const { id } = messageDescriptor;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -3020,7 +3132,11 @@ export async function startApp(): Promise<void> {
const ourId = window.ConversationController.getOurConversationId();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const me = window.ConversationController.get(ourId)!;
const profileKey = data.message.profileKey.toString('base64');
const { profileKey } = data.message;
strictAssert(
profileKey !== undefined,
'handleMessageSentProfileUpdate: missing profileKey'
);
// Will do the save for us if needed
await me.setProfileKey(profileKey);
@@ -3028,18 +3144,17 @@ export async function startApp(): Promise<void> {
return confirm();
}
function createSentMessage(data: WhatIsThis, descriptor: MessageDescriptor) {
function createSentMessage(
data: SentEventData,
descriptor: MessageDescriptor
) {
const now = Date.now();
const timestamp = data.timestamp || now;
const unidentifiedStatus: Array<SyncMessageClass.Sent.UnidentifiedDeliveryStatus> = Array.isArray(
data.unidentifiedStatus
)
? data.unidentifiedStatus
: [];
const { unidentifiedStatus = [] } = data;
let sentTo: Array<string> = [];
let unidentifiedDeliveries: Array<string> = [];
if (unidentifiedStatus.length) {
sentTo = unidentifiedStatus
.map(item => item.destinationUuid || item.destination)
@@ -3048,13 +3163,12 @@ export async function startApp(): Promise<void> {
const unidentified = window._.filter(data.unidentifiedStatus, item =>
Boolean(item.unidentified)
);
// eslint-disable-next-line no-param-reassign
data.unidentifiedDeliveries = unidentified.map(
item => item.destinationUuid || item.destination
);
unidentifiedDeliveries = unidentified
.map(item => item.destinationUuid || item.destination)
.filter(isNotNil);
}
return new window.Whisper.Message({
return new window.Whisper.Message(({
source: window.textsecure.storage.user.getNumber(),
sourceUuid: window.textsecure.storage.user.getUuid(),
sourceDevice: data.device,
@@ -3067,12 +3181,12 @@ export async function startApp(): Promise<void> {
timestamp,
type: 'outgoing',
sent: true,
unidentifiedDeliveries: data.unidentifiedDeliveries || [],
unidentifiedDeliveries,
expirationStartTimestamp: Math.min(
data.expirationStartTimestamp || timestamp,
now
),
} as WhatIsThis);
} as Partial<MessageAttributesType>) as WhatIsThis);
}
// Works with 'sent' and 'message' data sent from MessageReceiver, with a little massage
@@ -3084,11 +3198,11 @@ export async function startApp(): Promise<void> {
destination,
destinationUuid,
}: {
message: DataMessageClass;
source: string;
sourceUuid: string;
destination: string;
destinationUuid: string;
message: ProcessedDataMessage;
source?: string;
sourceUuid?: string;
destination?: string;
destinationUuid?: string;
}): MessageDescriptor => {
if (message.groupV2) {
const { id } = message.groupV2;
@@ -3186,14 +3300,19 @@ export async function startApp(): Promise<void> {
// Note: We do very little in this function, since everything in handleDataMessage is
// inside a conversation-specific queue(). Any code here might run before an earlier
// message is processed in handleDataMessage().
function onSentMessage(event: WhatIsThis) {
function onSentMessage(event: SentEvent) {
const { data, confirm } = event;
const source = window.textsecure.storage.user.getNumber();
const sourceUuid = window.textsecure.storage.user.getUuid();
strictAssert(source && sourceUuid, 'Missing user number and uuid');
const messageDescriptor = getMessageDescriptor({
...data,
// 'sent' event: the sender is always us!
source: window.textsecure.storage.user.getNumber(),
sourceUuid: window.textsecure.storage.user.getUuid(),
source,
sourceUuid,
});
const { PROFILE_KEY_UPDATE } = Proto.DataMessage.Flags;
@@ -3210,10 +3329,13 @@ export async function startApp(): Promise<void> {
const message = createSentMessage(data, messageDescriptor);
if (data.message.reaction) {
window.normalizeUuids(
data.message.reaction,
['targetAuthorUuid'],
'background::onSentMessage'
strictAssert(
data.message.reaction.targetAuthorUuid,
'Reaction without targetAuthorUuid'
);
const targetAuthorUuid = normalizeUuid(
data.message.reaction.targetAuthorUuid,
'DataMessage.Reaction.targetAuthorUuid'
);
const { reaction } = data.message;
@@ -3228,7 +3350,7 @@ export async function startApp(): Promise<void> {
const reactionModel = Reactions.getSingleton().add({
emoji: reaction.emoji,
remove: reaction.remove,
targetAuthorUuid: reaction.targetAuthorUuid,
targetAuthorUuid,
targetTimestamp: reaction.targetTimestamp,
timestamp: Date.now(),
fromId: window.ConversationController.getOurConversationId(),
@@ -3246,7 +3368,7 @@ export async function startApp(): Promise<void> {
window.log.info('Queuing sent DOE for', del.targetSentTimestamp);
const deleteModel = Deletes.getSingleton().add({
targetSentTimestamp: del.targetSentTimestamp,
serverTimestamp: del.serverTimestamp,
serverTimestamp: data.serverTimestamp,
fromId: window.ConversationController.getOurConversationId(),
});
// Note: We do not wait for completion here
@@ -3274,14 +3396,14 @@ export async function startApp(): Promise<void> {
};
function initIncomingMessage(
data: WhatIsThis,
data: MessageEventData,
descriptor: MessageDescriptor
) {
assert(
Boolean(data.receivedAtCounter),
`Did not receive receivedAtCounter for message: ${data.timestamp}`
);
return new window.Whisper.Message({
return new window.Whisper.Message(({
source: data.source,
sourceUuid: data.sourceUuid,
sourceDevice: data.sourceDevice,
@@ -3293,13 +3415,14 @@ export async function startApp(): Promise<void> {
conversationId: descriptor.id,
unidentifiedDeliveryReceived: data.unidentifiedDeliveryReceived,
type: 'incoming',
unread: 1,
} as WhatIsThis);
unread: true,
timestamp: data.timestamp,
} as Partial<MessageAttributesType>) as WhatIsThis);
}
// Returns `false` if this message isn't a group call message.
function handleGroupCallUpdateMessage(
message: DataMessageClass,
message: ProcessedDataMessage,
messageDescriptor: MessageDescriptor
): boolean {
if (message.groupCallUpdate) {
@@ -3329,7 +3452,7 @@ export async function startApp(): Promise<void> {
if (messageReceiver) {
messageReceiver.unregisterBatchers();
messageReceiver = null;
messageReceiver = undefined;
}
onEmpty();
@@ -3399,7 +3522,7 @@ export async function startApp(): Promise<void> {
}
}
function onError(ev: WhatIsThis) {
function onError(ev: ErrorEvent) {
const { error } = ev;
window.log.error('background onError:', Errors.toLogFormat(error));
@@ -3436,10 +3559,6 @@ export async function startApp(): Promise<void> {
window.log.warn('background onError: Doing nothing with incoming error');
}
type RetryRequestEventType = Event & {
retryRequest: RetryRequestType;
};
function isInList(
conversation: ConversationModel,
list: Array<string | undefined | null> | undefined
@@ -3471,7 +3590,7 @@ export async function startApp(): Promise<void> {
requesterUuid,
requesterDevice,
senderDevice,
}: RetryRequestType): Promise<void> {
}: RetryRequestEventData): Promise<void> {
const ourDeviceId = parseIntOrThrow(
window.textsecure.storage.user.getDeviceId(),
'archiveSessionOnMatch/getDeviceId'
@@ -3486,7 +3605,7 @@ export async function startApp(): Promise<void> {
}
async function sendDistributionMessageOrNullMessage(
options: RetryRequestType
options: RetryRequestEventData
): Promise<void> {
const { groupId, requesterUuid } = options;
let sentDistributionMessage = false;
@@ -3558,7 +3677,7 @@ export async function startApp(): Promise<void> {
}
}
async function onRetryRequest(event: RetryRequestEventType) {
async function onRetryRequest(event: RetryRequestEvent) {
const { retryRequest } = event;
const {
requesterDevice,
@@ -3637,11 +3756,7 @@ export async function startApp(): Promise<void> {
await targetMessage.resend(requesterUuid);
}
type DecryptionErrorEventType = Event & {
decryptionError: DecryptionErrorType;
};
async function onDecryptionError(event: DecryptionErrorEventType) {
async function onDecryptionError(event: DecryptionErrorEvent) {
const { decryptionError } = event;
const { senderUuid, senderDevice, timestamp } = decryptionError;
const logId = `${senderUuid}.${senderDevice} ${timestamp}`;
@@ -3666,7 +3781,7 @@ export async function startApp(): Promise<void> {
window.log.info(`onDecryptionError/${logId}: ...complete`);
}
async function requestResend(decryptionError: DecryptionErrorType) {
async function requestResend(decryptionError: DecryptionErrorEventData) {
const {
cipherTextBytes,
cipherTextType,
@@ -3784,7 +3899,9 @@ export async function startApp(): Promise<void> {
});
}
function startAutomaticSessionReset(decryptionError: DecryptionErrorType) {
function startAutomaticSessionReset(
decryptionError: DecryptionErrorEventData
) {
const { senderUuid, senderDevice, timestamp } = decryptionError;
const logId = `${senderUuid}.${senderDevice} ${timestamp}`;
@@ -3818,7 +3935,7 @@ export async function startApp(): Promise<void> {
});
}
async function onViewSync(ev: WhatIsThis) {
async function onViewSync(ev: ViewSyncEvent) {
ev.confirm();
const { source, sourceUuid, timestamp } = ev;
@@ -3833,7 +3950,7 @@ export async function startApp(): Promise<void> {
ViewSyncs.getSingleton().onSync(sync);
}
async function onFetchLatestSync(ev: WhatIsThis) {
async function onFetchLatestSync(ev: FetchLatestEvent) {
ev.confirm();
const { eventType } = ev;
@@ -3856,7 +3973,7 @@ export async function startApp(): Promise<void> {
}
}
async function onKeysSync(ev: WhatIsThis) {
async function onKeysSync(ev: KeysEvent) {
ev.confirm();
const { storageServiceKey } = ev;
@@ -3877,7 +3994,7 @@ export async function startApp(): Promise<void> {
}
}
async function onMessageRequestResponse(ev: WhatIsThis) {
async function onMessageRequestResponse(ev: MessageRequestResponseEvent) {
ev.confirm();
const {
@@ -3907,9 +4024,9 @@ export async function startApp(): Promise<void> {
MessageRequests.getSingleton().onResponse(sync);
}
function onReadReceipt(ev: WhatIsThis) {
const readAt = ev.timestamp;
function onReadReceipt(ev: ReadEvent) {
const { envelopeTimestamp, timestamp, source, sourceUuid } = ev.read;
const readAt = envelopeTimestamp;
const reader = window.ConversationController.ensureContactIds({
e164: source,
uuid: sourceUuid,
@@ -3941,9 +4058,9 @@ export async function startApp(): Promise<void> {
ReadReceipts.getSingleton().onReceipt(receipt);
}
function onReadSync(ev: WhatIsThis) {
const readAt = ev.timestamp;
function onReadSync(ev: ReadSyncEvent) {
const { envelopeTimestamp, sender, senderUuid, timestamp } = ev.read;
const readAt = envelopeTimestamp;
const senderId = window.ConversationController.ensureContactIds({
e164: sender,
uuid: senderUuid,
@@ -3974,7 +4091,7 @@ export async function startApp(): Promise<void> {
return ReadSyncs.getSingleton().onReceipt(receipt);
}
async function onVerified(ev: WhatIsThis) {
async function onVerified(ev: VerifiedEvent) {
const e164 = ev.verified.destination;
const uuid = ev.verified.destinationUuid;
const key = ev.verified.identityKey;
@@ -3984,18 +4101,18 @@ export async function startApp(): Promise<void> {
ev.confirm();
}
const c = new window.Whisper.Conversation({
const c = new window.Whisper.Conversation(({
e164,
uuid,
type: 'private',
} as WhatIsThis);
} as Partial<ConversationAttributesType>) as WhatIsThis);
const error = c.validate();
if (error) {
window.log.error(
'Invalid verified sync received:',
e164,
uuid,
Errors.toLogFormat(error as WhatIsThis)
Errors.toLogFormat(error)
);
return;
}
@@ -4019,7 +4136,7 @@ export async function startApp(): Promise<void> {
e164,
uuid,
state,
ev.viaContactSync ? 'via contact sync' : ''
ev.verified.viaContactSync ? 'via contact sync' : ''
);
const verifiedId = window.ConversationController.ensureContactIds({
@@ -4031,7 +4148,7 @@ export async function startApp(): Promise<void> {
const contact = window.ConversationController.get(verifiedId)!;
const options = {
viaSyncMessage: true,
viaContactSync: ev.viaContactSync,
viaContactSync: ev.verified.viaContactSync,
key,
};
@@ -4044,7 +4161,7 @@ export async function startApp(): Promise<void> {
}
}
function onDeliveryReceipt(ev: WhatIsThis) {
function onDeliveryReceipt(ev: DeliveryEvent) {
const { deliveryReceipt } = ev;
const {
envelopeTimestamp,