Migrate textsecure to eslint

Co-authored-by: Chris Svenningsen <chris@carbonfive.com>
This commit is contained in:
Sidney Keese 2020-09-24 14:53:21 -07:00 committed by Josh Perez
parent b5df9b4067
commit 7b6d8f55d6
24 changed files with 706 additions and 299 deletions

View file

@ -1,19 +1,25 @@
// tslint:disable no-bitwise no-default-export
/* eslint-disable @typescript-eslint/ban-types */
/* eslint-disable no-bitwise */
/* eslint-disable class-methods-use-this */
/* eslint-disable more/no-then */
/* eslint-disable camelcase */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable max-classes-per-file */
import { isNumber, map, omit } from 'lodash';
import { w3cwebsocket as WebSocket } from 'websocket';
import PQueue from 'p-queue';
import { v4 as getGuid } from 'uuid';
import { SessionCipherClass, SignalProtocolAddressClass } from '../libsignal.d';
import { BatcherType, createBatcher } from '../util/batcher';
import EventTarget from './EventTarget';
import { WebAPIType } from './WebAPI';
import { BatcherType, createBatcher } from '../util/batcher';
import utils from './Helpers';
import WebSocketResource, {
IncomingWebSocketRequest,
} from './WebsocketResources';
import Crypto from './Crypto';
import { SessionCipherClass, SignalProtocolAddressClass } from '../libsignal.d';
import { ContactBuffer, GroupBuffer } from './ContactsParser';
import { IncomingIdentityKeyError } from './Errors';
@ -30,6 +36,8 @@ import {
VerifiedClass,
} from '../textsecure.d';
import { WebSocket } from './WebSocket';
import { deriveGroupFields, MASTER_KEY_LENGTH } from '../groups';
const RETRY_TIMEOUT = 2 * 60 * 1000;
@ -84,30 +92,51 @@ type CacheUpdateItemType = {
class MessageReceiverInner extends EventTarget {
_onClose?: (ev: any) => Promise<void>;
appQueue: PQueue;
cacheAddBatcher: BatcherType<CacheAddItemType>;
cacheRemoveBatcher: BatcherType<string>;
cacheUpdateBatcher: BatcherType<CacheUpdateItemType>;
calledClose?: boolean;
count: number;
deviceId: number;
hasConnected?: boolean;
incomingQueue: PQueue;
isEmptied?: boolean;
// tslint:disable-next-line variable-name
number_id: string | null;
password: string;
pendingQueue: PQueue;
retryCachedTimeout: any;
server: WebAPIType;
serverTrustRoot: ArrayBuffer;
signalingKey: ArrayBuffer;
socket?: WebSocket;
stoppingProcessing?: boolean;
username: string;
uuid: string;
// tslint:disable-next-line variable-name
uuid_id: string | null;
wsr?: WebSocketResource;
constructor(
@ -175,10 +204,13 @@ class MessageReceiverInner extends EventTarget {
static stringToArrayBuffer = (string: string): ArrayBuffer =>
window.dcodeIO.ByteBuffer.wrap(string, 'binary').toArrayBuffer();
static arrayBufferToString = (arrayBuffer: ArrayBuffer): string =>
window.dcodeIO.ByteBuffer.wrap(arrayBuffer).toString('binary');
static stringToArrayBufferBase64 = (string: string): ArrayBuffer =>
window.dcodeIO.ByteBuffer.wrap(string, 'base64').toArrayBuffer();
static arrayBufferToStringBase64 = (arrayBuffer: ArrayBuffer): string =>
window.dcodeIO.ByteBuffer.wrap(arrayBuffer).toString('base64');
@ -237,12 +269,9 @@ class MessageReceiverInner extends EventTarget {
shutdown() {
if (this.socket) {
// @ts-ignore
this.socket.onclose = null;
// @ts-ignore
this.socket.onerror = null;
// @ts-ignore
this.socket.onopen = null;
delete this.socket.onclose;
delete this.socket.onerror;
delete this.socket.onopen;
this.socket = undefined;
}
@ -253,6 +282,7 @@ class MessageReceiverInner extends EventTarget {
this.wsr = undefined;
}
}
async close() {
window.log.info('MessageReceiver.close()');
this.calledClose = true;
@ -267,18 +297,22 @@ class MessageReceiverInner extends EventTarget {
return this.drain();
}
onopen() {
window.log.info('websocket open');
}
onerror() {
window.log.error('websocket error');
}
async dispatchAndWait(event: Event) {
// tslint:disable-next-line no-floating-promises
this.appQueue.add(async () => Promise.all(this.dispatchEvent(event)));
return Promise.resolve();
}
async onclose(ev: any) {
window.log.info(
'websocket closed',
@ -309,6 +343,7 @@ class MessageReceiverInner extends EventTarget {
return this.dispatchAndWait(event);
});
}
handleRequest(request: IncomingWebSocketRequest) {
// We do the message decryption here, instead of in the ordered pending queue,
// to avoid exposing the time it took us to process messages through the time-to-ack.
@ -395,6 +430,7 @@ class MessageReceiverInner extends EventTarget {
// tslint:disable-next-line no-floating-promises
this.incomingQueue.add(job);
}
calculateMessageAge(
headers: Array<string>,
serverTimestamp?: number
@ -404,6 +440,7 @@ class MessageReceiverInner extends EventTarget {
if (serverTimestamp) {
// The 'X-Signal-Timestamp' is usually the last item, so start there.
let it = headers.length;
// eslint-disable-next-line no-plusplus
while (--it >= 0) {
const match = headers[it].match(/^X-Signal-Timestamp:\s*(\d+)\s*$/);
if (match && match.length === 2) {
@ -422,6 +459,7 @@ class MessageReceiverInner extends EventTarget {
return messageAgeSec;
}
async addToQueue(task: () => Promise<void>) {
this.count += 1;
@ -437,9 +475,11 @@ class MessageReceiverInner extends EventTarget {
return promise;
}
hasEmptied(): boolean {
return Boolean(this.isEmptied);
}
onEmpty() {
const emitEmpty = () => {
window.log.info("MessageReceiver: emitting 'empty' event");
@ -478,6 +518,7 @@ class MessageReceiverInner extends EventTarget {
// tslint:disable-next-line no-floating-promises
waitForCacheAddBatcher();
}
async drain() {
const waitForIncomingQueue = async () =>
this.addToQueue(async () => {
@ -486,6 +527,7 @@ class MessageReceiverInner extends EventTarget {
return this.incomingQueue.add(waitForIncomingQueue);
}
updateProgress(count: number) {
// count by 10s
if (count % 10 !== 0) {
@ -495,6 +537,7 @@ class MessageReceiverInner extends EventTarget {
ev.count = count;
this.dispatchEvent(ev);
}
async queueAllCached() {
const items = await this.getAllFromCache();
const max = items.length;
@ -503,6 +546,7 @@ class MessageReceiverInner extends EventTarget {
await this.queueCached(items[i]);
}
}
async queueCached(item: UnprocessedType) {
try {
let envelopePlaintext: ArrayBuffer;
@ -573,6 +617,7 @@ class MessageReceiverInner extends EventTarget {
}
}
}
getEnvelopeId(envelope: EnvelopeClass) {
if (envelope.sourceUuid || envelope.source) {
return `${envelope.sourceUuid || envelope.source}.${
@ -582,12 +627,14 @@ class MessageReceiverInner extends EventTarget {
return envelope.id;
}
clearRetryTimeout() {
if (this.retryCachedTimeout) {
clearInterval(this.retryCachedTimeout);
this.retryCachedTimeout = null;
}
}
maybeScheduleRetryTimeout() {
if (this.isEmptied) {
this.clearRetryTimeout();
@ -597,6 +644,7 @@ class MessageReceiverInner extends EventTarget {
}, RETRY_TIMEOUT);
}
}
async getAllFromCache() {
window.log.info('getAllFromCache');
const count = await window.textsecure.storage.unprocessed.getCount();
@ -640,6 +688,7 @@ class MessageReceiverInner extends EventTarget {
})
);
}
async cacheAndQueueBatch(items: Array<CacheAddItemType>) {
const dataArray = items.map(item => item.data);
try {
@ -661,6 +710,7 @@ class MessageReceiverInner extends EventTarget {
);
}
}
cacheAndQueue(
envelope: EnvelopeClass,
plaintext: ArrayBuffer,
@ -680,9 +730,11 @@ class MessageReceiverInner extends EventTarget {
data,
});
}
async cacheUpdateBatch(items: Array<Partial<UnprocessedType>>) {
await window.textsecure.storage.unprocessed.addDecryptedDataToList(items);
}
updateCache(envelope: EnvelopeClass, plaintext: ArrayBuffer) {
const { id } = envelope;
const data = {
@ -694,13 +746,16 @@ class MessageReceiverInner extends EventTarget {
};
this.cacheUpdateBatcher.add({ id, data });
}
async cacheRemoveBatch(items: Array<string>) {
await window.textsecure.storage.unprocessed.remove(items);
}
removeFromCache(envelope: EnvelopeClass) {
const { id } = envelope;
this.cacheRemoveBatcher.add(id);
}
async queueDecryptedEnvelope(
envelope: EnvelopeClass,
plaintext: ArrayBuffer
@ -722,6 +777,7 @@ class MessageReceiverInner extends EventTarget {
);
});
}
async queueEnvelope(envelope: EnvelopeClass) {
const id = this.getEnvelopeId(envelope);
window.log.info('queueing envelope', id);
@ -747,6 +803,7 @@ class MessageReceiverInner extends EventTarget {
}
});
}
// Same as handleEnvelope, just without the decryption step. Necessary for handling
// messages which were successfully decrypted, but application logic didn't finish
// processing.
@ -764,7 +821,8 @@ class MessageReceiverInner extends EventTarget {
await this.innerHandleContentMessage(envelope, plaintext);
return;
} else if (envelope.legacyMessage) {
}
if (envelope.legacyMessage) {
await this.innerHandleLegacyMessage(envelope, plaintext);
return;
@ -773,6 +831,7 @@ class MessageReceiverInner extends EventTarget {
this.removeFromCache(envelope);
throw new Error('Received message with no content and no legacyMessage');
}
async handleEnvelope(envelope: EnvelopeClass) {
if (this.stoppingProcessing) {
return Promise.resolve();
@ -784,20 +843,24 @@ class MessageReceiverInner extends EventTarget {
if (envelope.content) {
return this.handleContentMessage(envelope);
} else if (envelope.legacyMessage) {
}
if (envelope.legacyMessage) {
return this.handleLegacyMessage(envelope);
}
this.removeFromCache(envelope);
throw new Error('Received message with no content and no legacyMessage');
}
getStatus() {
if (this.socket) {
return this.socket.readyState;
} else if (this.hasConnected) {
}
if (this.hasConnected) {
return WebSocket.CLOSED;
}
return -1;
}
async onDeliveryReceipt(envelope: EnvelopeClass) {
// tslint:disable-next-line promise-must-complete
return new Promise((resolve, reject) => {
@ -812,6 +875,7 @@ class MessageReceiverInner extends EventTarget {
this.dispatchAndWait(ev).then(resolve as any, reject as any);
});
}
unpad(paddedData: ArrayBuffer) {
const paddedPlaintext = new Uint8Array(paddedData);
let plaintext;
@ -837,11 +901,10 @@ class MessageReceiverInner extends EventTarget {
): Promise<ArrayBuffer> {
const { serverTrustRoot } = this;
let address: SignalProtocolAddressClass;
let promise;
const identifier = envelope.sourceUuid || envelope.source;
address = new window.libsignal.SignalProtocolAddress(
const address = new window.libsignal.SignalProtocolAddress(
// Using source as opposed to sourceUuid allows us to get the existing
// session if we haven't yet harvested the incoming uuid
identifier as any,
@ -1034,6 +1097,7 @@ class MessageReceiverInner extends EventTarget {
return this.dispatchAndWait(ev).then(returnError, returnError);
});
}
async decryptPreKeyWhisperMessage(
ciphertext: ArrayBuffer,
sessionCipher: SessionCipherClass,
@ -1057,6 +1121,7 @@ class MessageReceiverInner extends EventTarget {
throw e;
}
}
async handleSentMessage(
envelope: EnvelopeClass,
sentContainer: SyncMessageClass.Sent
@ -1114,7 +1179,7 @@ class MessageReceiverInner extends EventTarget {
)} ignored; destined for blocked group`
);
this.removeFromCache(envelope);
return;
return undefined;
}
const ev = new Event('sent');
@ -1136,6 +1201,7 @@ class MessageReceiverInner extends EventTarget {
})
);
}
async handleDataMessage(envelope: EnvelopeClass, msg: DataMessageClass) {
window.log.info('data message from', this.getEnvelopeId(envelope));
let p: Promise<any> = Promise.resolve();
@ -1152,7 +1218,7 @@ class MessageReceiverInner extends EventTarget {
window.log.info(
'MessageReceiver.handleDataMessage: dropping GroupV2 message'
);
return;
return undefined;
}
this.deriveGroupsV2Data(msg);
@ -1204,7 +1270,7 @@ class MessageReceiverInner extends EventTarget {
)} ignored; destined for blocked group`
);
this.removeFromCache(envelope);
return;
return undefined;
}
const ev = new Event('message');
@ -1222,6 +1288,7 @@ class MessageReceiverInner extends EventTarget {
})
);
}
async handleLegacyMessage(envelope: EnvelopeClass) {
return this.decrypt(envelope, envelope.legacyMessage).then(plaintext => {
if (!plaintext) {
@ -1231,6 +1298,7 @@ class MessageReceiverInner extends EventTarget {
return this.innerHandleLegacyMessage(envelope, plaintext);
});
}
async innerHandleLegacyMessage(
envelope: EnvelopeClass,
plaintext: ArrayBuffer
@ -1238,6 +1306,7 @@ class MessageReceiverInner extends EventTarget {
const message = window.textsecure.protobuf.DataMessage.decode(plaintext);
return this.handleDataMessage(envelope, message);
}
async handleContentMessage(envelope: EnvelopeClass) {
return this.decrypt(envelope, envelope.content).then(plaintext => {
if (!plaintext) {
@ -1247,6 +1316,7 @@ class MessageReceiverInner extends EventTarget {
return this.innerHandleContentMessage(envelope, plaintext);
});
}
async innerHandleContentMessage(
envelope: EnvelopeClass,
plaintext: ArrayBuffer
@ -1254,21 +1324,27 @@ class MessageReceiverInner extends EventTarget {
const content = window.textsecure.protobuf.Content.decode(plaintext);
if (content.syncMessage) {
return this.handleSyncMessage(envelope, content.syncMessage);
} else if (content.dataMessage) {
}
if (content.dataMessage) {
return this.handleDataMessage(envelope, content.dataMessage);
} else if (content.nullMessage) {
}
if (content.nullMessage) {
this.handleNullMessage(envelope);
return;
} else if (content.callingMessage) {
return undefined;
}
if (content.callingMessage) {
return this.handleCallingMessage(envelope, content.callingMessage);
} else if (content.receiptMessage) {
}
if (content.receiptMessage) {
return this.handleReceiptMessage(envelope, content.receiptMessage);
} else if (content.typingMessage) {
}
if (content.typingMessage) {
return this.handleTypingMessage(envelope, content.typingMessage);
}
this.removeFromCache(envelope);
throw new Error('Unsupported content message');
}
async handleCallingMessage(
envelope: EnvelopeClass,
callingMessage: CallingMessageClass
@ -1279,6 +1355,7 @@ class MessageReceiverInner extends EventTarget {
callingMessage
);
}
async handleReceiptMessage(
envelope: EnvelopeClass,
receiptMessage: ReceiptMessageClass
@ -1319,6 +1396,7 @@ class MessageReceiverInner extends EventTarget {
}
return Promise.all(results);
}
handleTypingMessage(
envelope: EnvelopeClass,
typingMessage: TypingMessageClass
@ -1366,6 +1444,7 @@ class MessageReceiverInner extends EventTarget {
return this.dispatchEvent(ev);
}
handleNullMessage(envelope: EnvelopeClass) {
window.log.info('null message from', this.getEnvelopeId(envelope));
this.removeFromCache(envelope);
@ -1404,6 +1483,7 @@ class MessageReceiverInner extends EventTarget {
groupV2.groupChange = groupV2.groupChange.toString('base64');
}
}
getGroupId(message: DataMessageClass) {
if (message.groupV2) {
return message.groupV2.id;
@ -1418,11 +1498,11 @@ class MessageReceiverInner extends EventTarget {
getDestination(sentMessage: SyncMessageClass.Sent) {
if (sentMessage.message && sentMessage.message.groupV2) {
return `groupv2(${sentMessage.message.groupV2.id})`;
} else if (sentMessage.message && sentMessage.message.group) {
return `group(${sentMessage.message.group.id.toBinary()})`;
} else {
return sentMessage.destination || sentMessage.destinationUuid;
}
if (sentMessage.message && sentMessage.message.group) {
return `group(${sentMessage.message.group.id.toBinary()})`;
}
return sentMessage.destination || sentMessage.destinationUuid;
}
// tslint:disable-next-line cyclomatic-complexity
@ -1450,7 +1530,7 @@ class MessageReceiverInner extends EventTarget {
if (!fromSelfSource && !fromSelfSourceUuid) {
throw new Error('Received sync message from another number');
}
// tslint:disable-next-line triple-equals
// eslint-disable-next-line eqeqeq
if (envelope.sourceDevice == this.deviceId) {
throw new Error('Received sync message from our own device');
}
@ -1468,7 +1548,7 @@ class MessageReceiverInner extends EventTarget {
window.log.info(
'MessageReceiver.handleSyncMessage: dropping GroupV2 message'
);
return;
return undefined;
}
this.deriveGroupsV2Data(sentMessage.message);
@ -1481,26 +1561,34 @@ class MessageReceiverInner extends EventTarget {
this.getEnvelopeId(envelope)
);
return this.handleSentMessage(envelope, sentMessage);
} else if (syncMessage.contacts) {
}
if (syncMessage.contacts) {
this.handleContacts(envelope, syncMessage.contacts);
return;
} else if (syncMessage.groups) {
return undefined;
}
if (syncMessage.groups) {
this.handleGroups(envelope, syncMessage.groups);
return;
} else if (syncMessage.blocked) {
return undefined;
}
if (syncMessage.blocked) {
return this.handleBlocked(envelope, syncMessage.blocked);
} else if (syncMessage.request) {
}
if (syncMessage.request) {
window.log.info('Got SyncMessage Request');
this.removeFromCache(envelope);
return;
} else if (syncMessage.read && syncMessage.read.length) {
return undefined;
}
if (syncMessage.read && syncMessage.read.length) {
window.log.info('read messages from', this.getEnvelopeId(envelope));
return this.handleRead(envelope, syncMessage.read);
} else if (syncMessage.verified) {
}
if (syncMessage.verified) {
return this.handleVerified(envelope, syncMessage.verified);
} else if (syncMessage.configuration) {
}
if (syncMessage.configuration) {
return this.handleConfiguration(envelope, syncMessage.configuration);
} else if (
}
if (
syncMessage.stickerPackOperation &&
syncMessage.stickerPackOperation.length > 0
) {
@ -1508,22 +1596,27 @@ class MessageReceiverInner extends EventTarget {
envelope,
syncMessage.stickerPackOperation
);
} else if (syncMessage.viewOnceOpen) {
}
if (syncMessage.viewOnceOpen) {
return this.handleViewOnceOpen(envelope, syncMessage.viewOnceOpen);
} else if (syncMessage.messageRequestResponse) {
}
if (syncMessage.messageRequestResponse) {
return this.handleMessageRequestResponse(
envelope,
syncMessage.messageRequestResponse
);
} else if (syncMessage.fetchLatest) {
}
if (syncMessage.fetchLatest) {
return this.handleFetchLatest(envelope, syncMessage.fetchLatest);
} else if (syncMessage.keys) {
}
if (syncMessage.keys) {
return this.handleKeys(envelope, syncMessage.keys);
}
this.removeFromCache(envelope);
throw new Error('Got empty SyncMessage');
}
async handleConfiguration(
envelope: EnvelopeClass,
configuration: SyncMessageClass.Configuration
@ -1534,6 +1627,7 @@ class MessageReceiverInner extends EventTarget {
ev.configuration = configuration;
return this.dispatchAndWait(ev);
}
async handleViewOnceOpen(
envelope: EnvelopeClass,
sync: SyncMessageClass.ViewOnceOpen
@ -1554,6 +1648,7 @@ class MessageReceiverInner extends EventTarget {
return this.dispatchAndWait(ev);
}
async handleMessageRequestResponse(
envelope: EnvelopeClass,
sync: SyncMessageClass.MessageRequestResponse
@ -1573,6 +1668,7 @@ class MessageReceiverInner extends EventTarget {
'MessageReceiver::handleMessageRequestResponse'
);
}
async handleFetchLatest(
envelope: EnvelopeClass,
sync: SyncMessageClass.FetchLatest
@ -1585,11 +1681,12 @@ class MessageReceiverInner extends EventTarget {
return this.dispatchAndWait(ev);
}
async handleKeys(envelope: EnvelopeClass, sync: SyncMessageClass.Keys) {
window.log.info('got keys sync message');
if (!sync.storageService) {
return;
return undefined;
}
const ev = new Event('keys');
@ -1598,6 +1695,7 @@ class MessageReceiverInner extends EventTarget {
return this.dispatchAndWait(ev);
}
async handleStickerPackOperation(
envelope: EnvelopeClass,
operations: Array<SyncMessageClass.StickerPackOperation>
@ -1615,6 +1713,7 @@ class MessageReceiverInner extends EventTarget {
}));
return this.dispatchAndWait(ev);
}
async handleVerified(envelope: EnvelopeClass, verified: VerifiedClass) {
const ev = new Event('verified');
ev.confirm = this.removeFromCache.bind(this, envelope);
@ -1631,6 +1730,7 @@ class MessageReceiverInner extends EventTarget {
);
return this.dispatchAndWait(ev);
}
async handleRead(
envelope: EnvelopeClass,
read: Array<SyncMessageClass.Read>
@ -1655,6 +1755,7 @@ class MessageReceiverInner extends EventTarget {
}
return Promise.all(results);
}
handleContacts(envelope: EnvelopeClass, contacts: SyncMessageClass.Contacts) {
window.log.info('contact sync');
const { blob } = contacts;
@ -1692,6 +1793,7 @@ class MessageReceiverInner extends EventTarget {
});
});
}
handleGroups(envelope: EnvelopeClass, groups: SyncMessageClass.Groups) {
window.log.info('group sync');
const { blob } = groups;
@ -1726,6 +1828,7 @@ class MessageReceiverInner extends EventTarget {
});
});
}
async handleBlocked(
envelope: EnvelopeClass,
blocked: SyncMessageClass.Blocked
@ -1750,19 +1853,22 @@ class MessageReceiverInner extends EventTarget {
await window.textsecure.storage.put('blocked-groups', groupIds);
this.removeFromCache(envelope);
return;
}
isBlocked(number: string) {
return window.textsecure.storage.get('blocked', []).includes(number);
}
isUuidBlocked(uuid: string) {
return window.textsecure.storage.get('blocked-uuids', []).includes(uuid);
}
isGroupBlocked(groupId: string) {
return window.textsecure.storage
.get('blocked-groups', [])
.includes(groupId);
}
cleanAttachment(attachment: AttachmentPointerClass) {
return {
...omit(attachment, 'thumbnail'),
@ -1771,6 +1877,7 @@ class MessageReceiverInner extends EventTarget {
digest: attachment.digest ? attachment.digest.toString('base64') : null,
};
}
private isLinkPreviewDateValid(value: unknown): value is number {
return (
typeof value === 'number' &&
@ -1779,6 +1886,7 @@ class MessageReceiverInner extends EventTarget {
value > 0
);
}
private cleanLinkPreviewDate(value: unknown): number | null {
if (this.isLinkPreviewDateValid(value)) {
return value;
@ -1794,6 +1902,7 @@ class MessageReceiverInner extends EventTarget {
}
return this.isLinkPreviewDateValid(result) ? result : null;
}
async downloadAttachment(
attachment: AttachmentPointerClass
): Promise<DownloadAttachmentType> {
@ -1826,12 +1935,14 @@ class MessageReceiverInner extends EventTarget {
data,
};
}
async handleAttachment(
attachment: AttachmentPointerClass
): Promise<DownloadAttachmentType> {
const cleaned = this.cleanAttachment(attachment);
return this.downloadAttachment(cleaned);
}
async handleEndSession(identifier: string) {
window.log.info('got end session');
const deviceIds = await window.textsecure.storage.protocol.getDeviceIds(
@ -1890,7 +2001,8 @@ class MessageReceiverInner extends EventTarget {
decrypted.attachments = [];
decrypted.group = null;
return Promise.resolve(decrypted);
} else if (decrypted.flags & FLAGS.EXPIRATION_TIMER_UPDATE) {
}
if (decrypted.flags & FLAGS.EXPIRATION_TIMER_UPDATE) {
decrypted.body = null;
decrypted.attachments = [];
} else if (decrypted.flags & FLAGS.PROFILE_KEY_UPDATE) {
@ -2053,20 +2165,30 @@ export default class MessageReceiver {
}
addEventListener: (name: string, handler: Function) => void;
close: () => Promise<void>;
downloadAttachment: (
attachment: AttachmentPointerClass
) => Promise<DownloadAttachmentType>;
getStatus: () => number;
hasEmptied: () => boolean;
removeEventListener: (name: string, handler: Function) => void;
stopProcessing: () => Promise<void>;
unregisterBatchers: () => void;
static stringToArrayBuffer = MessageReceiverInner.stringToArrayBuffer;
static arrayBufferToString = MessageReceiverInner.arrayBufferToString;
static stringToArrayBufferBase64 =
MessageReceiverInner.stringToArrayBufferBase64;
static arrayBufferToStringBase64 =
MessageReceiverInner.arrayBufferToStringBase64;
}