diff --git a/test/test.js b/test/test.js index cf5b2414c4..32cc50cdc8 100644 --- a/test/test.js +++ b/test/test.js @@ -21,7 +21,6 @@ before(async () => { window.testUtilities.prepareTests(); delete window.testUtilities.prepareTests; -window.textsecure.storage.protocol = window.getSignalProtocolStore(); !(function () { class Reporter extends Mocha.reporters.HTML { diff --git a/ts/ConversationController.ts b/ts/ConversationController.ts index 971503b61a..e9c4fcb71c 100644 --- a/ts/ConversationController.ts +++ b/ts/ConversationController.ts @@ -42,6 +42,7 @@ import { validateConversation } from './util/validateConversation.js'; import { ConversationModel } from './models/conversations.js'; import { INITIAL_EXPIRE_TIMER_VERSION } from './util/expirationTimer.js'; import { missingCaseError } from './util/missingCaseError.js'; +import { signalProtocolStore } from './SignalProtocolStore.js'; import type { ConversationAttributesType, @@ -490,7 +491,7 @@ export class ConversationController { version: 2, expireTimerVersion: INITIAL_EXPIRE_TIMER_VERSION, unreadCount: 0, - verified: window.textsecure.storage.protocol.VerifiedStatus.DEFAULT, + verified: signalProtocolStore.VerifiedStatus.DEFAULT, messageCount: 0, sentMessageCount: 0, ...additionalInitialProps, @@ -506,7 +507,7 @@ export class ConversationController { version: 2, expireTimerVersion: INITIAL_EXPIRE_TIMER_VERSION, unreadCount: 0, - verified: window.textsecure.storage.protocol.VerifiedStatus.DEFAULT, + verified: signalProtocolStore.VerifiedStatus.DEFAULT, messageCount: 0, sentMessageCount: 0, ...additionalInitialProps, @@ -522,7 +523,7 @@ export class ConversationController { version: 2, expireTimerVersion: INITIAL_EXPIRE_TIMER_VERSION, unreadCount: 0, - verified: window.textsecure.storage.protocol.VerifiedStatus.DEFAULT, + verified: signalProtocolStore.VerifiedStatus.DEFAULT, messageCount: 0, sentMessageCount: 0, ...additionalInitialProps, @@ -1366,17 +1367,13 @@ export class ConversationController { log.warn(`${logId}: Delete all sessions tied to old conversationId`); // Note: we use the conversationId here in case we've already lost our service id. - await window.textsecure.storage.protocol.removeSessionsByConversation( - obsoleteId - ); + await signalProtocolStore.removeSessionsByConversation(obsoleteId); log.warn( `${logId}: Delete all identity information tied to old conversationId` ); if (obsoleteServiceId) { - await window.textsecure.storage.protocol.removeIdentityKey( - obsoleteServiceId - ); + await signalProtocolStore.removeIdentityKey(obsoleteServiceId); } log.warn( @@ -1814,9 +1811,7 @@ export class ConversationController { recipients.forEach(serviceId => { drop( queue.add(async () => { - await window.textsecure.storage.protocol.archiveAllSessions( - serviceId - ); + await signalProtocolStore.archiveAllSessions(serviceId); }) ); }); diff --git a/ts/LibSignalStores.ts b/ts/LibSignalStores.ts index dc1fce1404..9c3b9be9cf 100644 --- a/ts/LibSignalStores.ts +++ b/ts/LibSignalStores.ts @@ -30,6 +30,7 @@ import { Address } from './types/Address.js'; import { QualifiedAddress } from './types/QualifiedAddress.js'; import type { ServiceIdString } from './types/ServiceId.js'; import { normalizeServiceId } from './types/ServiceId.js'; +import { signalProtocolStore } from './SignalProtocolStore.js'; import type { Zone } from './util/Zone.js'; @@ -68,7 +69,7 @@ export class Sessions extends SessionStore { address: ProtocolAddress, record: SessionRecord ): Promise { - await window.textsecure.storage.protocol.storeSession( + await signalProtocolStore.storeSession( toQualifiedAddress(this.#ourServiceId, address), record, { zone: this.#zone } @@ -77,10 +78,9 @@ export class Sessions extends SessionStore { async getSession(name: ProtocolAddress): Promise { const encodedAddress = toQualifiedAddress(this.#ourServiceId, name); - const record = await window.textsecure.storage.protocol.loadSession( - encodedAddress, - { zone: this.#zone } - ); + const record = await signalProtocolStore.loadSession(encodedAddress, { + zone: this.#zone, + }); return record || null; } @@ -91,7 +91,7 @@ export class Sessions extends SessionStore { const encodedAddresses = addresses.map(addr => toQualifiedAddress(this.#ourServiceId, addr) ); - return window.textsecure.storage.protocol.loadSessions(encodedAddresses, { + return signalProtocolStore.loadSessions(encodedAddresses, { zone: this.#zone, }); } @@ -114,9 +114,7 @@ export class IdentityKeys extends IdentityKeyStore { } async getIdentityKey(): Promise { - const keyPair = window.textsecure.storage.protocol.getIdentityKeyPair( - this.#ourServiceId - ); + const keyPair = signalProtocolStore.getIdentityKeyPair(this.#ourServiceId); if (!keyPair) { throw new Error('IdentityKeyStore/getIdentityKey: No identity key!'); } @@ -124,7 +122,7 @@ export class IdentityKeys extends IdentityKeyStore { } async getLocalRegistrationId(): Promise { - const id = await window.textsecure.storage.protocol.getLocalRegistrationId( + const id = await signalProtocolStore.getLocalRegistrationId( this.#ourServiceId ); if (!isNumber(id)) { @@ -137,7 +135,7 @@ export class IdentityKeys extends IdentityKeyStore { async getIdentity(address: ProtocolAddress): Promise { const encodedAddress = encodeAddress(address); - const key = await window.textsecure.storage.protocol.loadIdentityKey( + const key = await signalProtocolStore.loadIdentityKey( encodedAddress.serviceId ); @@ -157,12 +155,9 @@ export class IdentityKeys extends IdentityKeyStore { // Pass `zone` to let `saveIdentity` archive sibling sessions when identity // key changes. - return window.textsecure.storage.protocol.saveIdentity( - encodedAddress, - publicKey, - false, - { zone: this.#zone } - ); + return signalProtocolStore.saveIdentity(encodedAddress, publicKey, false, { + zone: this.#zone, + }); } async isTrustedIdentity( @@ -173,7 +168,7 @@ export class IdentityKeys extends IdentityKeyStore { const encodedAddress = encodeAddress(name); const publicKey = key.serialize(); - return window.textsecure.storage.protocol.isTrustedIdentity( + return signalProtocolStore.isTrustedIdentity( encodedAddress, publicKey, direction @@ -201,10 +196,7 @@ export class PreKeys extends PreKeyStore { } async getPreKey(id: number): Promise { - const preKey = await window.textsecure.storage.protocol.loadPreKey( - this.#ourServiceId, - id - ); + const preKey = await signalProtocolStore.loadPreKey(this.#ourServiceId, id); if (preKey === undefined) { throw new Error(`getPreKey: PreKey ${id} not found`); @@ -214,11 +206,9 @@ export class PreKeys extends PreKeyStore { } async removePreKey(id: number): Promise { - await window.textsecure.storage.protocol.removePreKeys( - this.#ourServiceId, - [id], - { zone: this.#zone } - ); + await signalProtocolStore.removePreKeys(this.#ourServiceId, [id], { + zone: this.#zone, + }); } } @@ -237,11 +227,10 @@ export class KyberPreKeys extends KyberPreKeyStore { } async getKyberPreKey(id: number): Promise { - const kyberPreKey = - await window.textsecure.storage.protocol.loadKyberPreKey( - this.#ourServiceId, - id - ); + const kyberPreKey = await signalProtocolStore.loadKyberPreKey( + this.#ourServiceId, + id + ); if (kyberPreKey === undefined) { throw new Error(`getKyberPreKey: KyberPreKey ${id} not found`); @@ -255,7 +244,7 @@ export class KyberPreKeys extends KyberPreKeyStore { signedPreKeyId: number, baseKey: PublicKey ): Promise { - await window.textsecure.storage.protocol.maybeRemoveKyberPreKey( + await signalProtocolStore.maybeRemoveKyberPreKey( this.#ourServiceId, { keyId, signedPreKeyId, baseKey }, { zone: this.#zone } @@ -285,7 +274,7 @@ export class SenderKeys extends SenderKeyStore { ): Promise { const encodedAddress = toQualifiedAddress(this.#ourServiceId, sender); - await window.textsecure.storage.protocol.saveSenderKey( + await signalProtocolStore.saveSenderKey( encodedAddress, distributionId, record, @@ -299,7 +288,7 @@ export class SenderKeys extends SenderKeyStore { ): Promise { const encodedAddress = toQualifiedAddress(this.#ourServiceId, sender); - const senderKey = await window.textsecure.storage.protocol.getSenderKey( + const senderKey = await signalProtocolStore.getSenderKey( encodedAddress, distributionId, { zone: this.zone } @@ -327,11 +316,10 @@ export class SignedPreKeys extends SignedPreKeyStore { } async getSignedPreKey(id: number): Promise { - const signedPreKey = - await window.textsecure.storage.protocol.loadSignedPreKey( - this.#ourServiceId, - id - ); + const signedPreKey = await signalProtocolStore.loadSignedPreKey( + this.#ourServiceId, + id + ); if (!signedPreKey) { throw new Error(`getSignedPreKey: SignedPreKey ${id} not found`); diff --git a/ts/SignalProtocolStore.ts b/ts/SignalProtocolStore.ts index b432f50daf..b275055ed3 100644 --- a/ts/SignalProtocolStore.ts +++ b/ts/SignalProtocolStore.ts @@ -2838,8 +2838,4 @@ export class SignalProtocolStore extends EventEmitter { } } -export function getSignalProtocolStore(): SignalProtocolStore { - return new SignalProtocolStore(); -} - -window.SignalProtocolStore = SignalProtocolStore; +export const signalProtocolStore = new SignalProtocolStore(); diff --git a/ts/background.ts b/ts/background.ts index cdbd37c3e4..3dbf1cc3da 100644 --- a/ts/background.ts +++ b/ts/background.ts @@ -9,6 +9,7 @@ import { v7 as generateUuid } from 'uuid'; import * as Registration from './util/registration.js'; import MessageReceiver from './textsecure/MessageReceiver.js'; +import { signalProtocolStore } from './SignalProtocolStore.js'; import type { SessionResetsType, ProcessedDataMessage, @@ -269,8 +270,6 @@ export async function cleanupSessionResets(): Promise { } export async function startApp(): Promise { - window.textsecure.storage.protocol = new window.SignalProtocolStore(); - if (window.initialTheme === ThemeType.light) { document.body.classList.add('light-theme'); } @@ -390,8 +389,8 @@ export async function startApp(): Promise { window.SignalContext.getResolvedMessagesLocaleDirection() ); - KeyChangeListener.init(window.textsecure.storage.protocol); - window.textsecure.storage.protocol.on( + KeyChangeListener.init(signalProtocolStore); + signalProtocolStore.on( 'lowKeys', throttle( async () => { @@ -403,7 +402,7 @@ export async function startApp(): Promise { ) ); - window.textsecure.storage.protocol.on('removeAllData', () => { + signalProtocolStore.on('removeAllData', () => { window.reduxActions.stories.removeAllStories(); }); @@ -525,7 +524,27 @@ export async function startApp(): Promise { const buildExpirationService = new BuildExpirationService(); - server = window.WebAPI.connect({ + const { config } = window.SignalContext; + + const WebAPI = window.textsecure.WebAPI.initialize({ + chatServiceUrl: config.serverUrl, + storageUrl: config.storageUrl, + updatesUrl: config.updatesUrl, + resourcesUrl: config.resourcesUrl, + cdnUrlObject: { + 0: config.cdnUrl0, + 2: config.cdnUrl2, + 3: config.cdnUrl3, + }, + certificateAuthority: config.certificateAuthority, + contentProxyUrl: config.contentProxyUrl, + proxyUrl: config.proxyUrl, + version: config.version, + disableIPv6: config.disableIPv6, + stripePublishableKey: config.stripePublishableKey, + }); + + server = WebAPI.connect({ ...window.textsecure.storage.user.getWebAPICredentials(), hasBuildExpired: buildExpirationService.hasBuildExpired(), hasStoriesDisabled: window.storage.get('hasStoriesDisabled', false), @@ -1181,7 +1200,7 @@ export async function startApp(): Promise { await Promise.all([ window.ConversationController.getOrCreateSignalConversation(), - window.textsecure.storage.protocol.hydrateCaches(), + signalProtocolStore.hydrateCaches(), loadAll(), ]); await window.ConversationController.checkForConflicts(); @@ -3292,7 +3311,7 @@ export async function startApp(): Promise { await DataReader.getItemById('manifestVersion'); // Finally, conversations in the database, and delete all config tables - await window.textsecure.storage.protocol.removeAllConfiguration(); + await signalProtocolStore.removeAllConfiguration(); // These three bits of data are important to ensure that the app loads up // the conversation list, instead of showing just the QR code screen. diff --git a/ts/model-types.d.ts b/ts/model-types.d.ts index eaca52ca8c..8723994b92 100644 --- a/ts/model-types.d.ts +++ b/ts/model-types.d.ts @@ -8,7 +8,7 @@ import type { DraftBodyRanges, RawBodyRange } from './types/BodyRange.js'; import type { CustomColorType, ConversationColorType } from './types/Colors.js'; import type { SendMessageChallengeData } from './textsecure/Errors.js'; import type { ProfileNameChangeType } from './util/getStringForProfileChange.js'; -import type { CapabilitiesType } from './textsecure/WebAPI.js'; +import type { CapabilitiesType } from './types/Capabilities.d.ts'; import type { ReadStatus } from './messages/MessageReadStatus.js'; import type { SendStateByConversationId } from './messages/MessageSendState.js'; import type { GroupNameCollisionsWithIdsByTitle } from './util/groupMemberNameCollisions.js'; diff --git a/ts/models/conversations.ts b/ts/models/conversations.ts index 3e698e221b..cc56af6e99 100644 --- a/ts/models/conversations.ts +++ b/ts/models/conversations.ts @@ -97,6 +97,7 @@ import * as Bytes from '../Bytes.js'; import type { DraftBodyRanges } from '../types/BodyRange.js'; import { migrateColor } from '../util/migrateColor.js'; import { isNotNil } from '../util/isNotNil.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; import { shouldSaveNotificationAvatarToDisk } from '../services/notifications.js'; import { storageServiceUploadJob } from '../services/storage.js'; import { getSendOptions } from '../util/getSendOptions.js'; @@ -321,7 +322,7 @@ export class ConversationModel { #lastIsTyping?: boolean; #muteTimer?: NodeJS.Timeout; - #privVerifiedEnum?: typeof window.textsecure.storage.protocol.VerifiedStatus; + #privVerifiedEnum?: typeof signalProtocolStore.VerifiedStatus; #isShuttingDown = false; #savePromises = new Set>(); @@ -418,7 +419,7 @@ export class ConversationModel { this.storeName = 'conversations'; - this.#privVerifiedEnum = window.textsecure.storage.protocol.VerifiedStatus; + this.#privVerifiedEnum = signalProtocolStore.VerifiedStatus; // This may be overridden by window.ConversationController.getOrCreate, and signify // our first save to the database. Or first fetch from the database. @@ -522,7 +523,7 @@ export class ConversationModel { }; } - get #verifiedEnum(): typeof window.textsecure.storage.protocol.VerifiedStatus { + get #verifiedEnum(): typeof signalProtocolStore.VerifiedStatus { strictAssert(this.#privVerifiedEnum, 'ConversationModel not initialize'); return this.#privVerifiedEnum; } @@ -2116,7 +2117,7 @@ export class ConversationModel { // for the case where we need to do old and new PNI comparisons. We'll wait // for the PNI update to do that. if (oldValue && oldValue !== this.getPni()) { - drop(window.textsecure.storage.protocol.removeIdentityKey(oldValue)); + drop(signalProtocolStore.removeIdentityKey(oldValue)); } this.captureChange('updateServiceId'); @@ -2176,9 +2177,8 @@ export class ConversationModel { // We're going from an old PNI to a new PNI if (pni) { const oldIdentityRecord = - window.textsecure.storage.protocol.getIdentityRecord(oldValue); - const newIdentityRecord = - window.textsecure.storage.protocol.getIdentityRecord(pni); + signalProtocolStore.getIdentityRecord(oldValue); + const newIdentityRecord = signalProtocolStore.getIdentityRecord(pni); if ( newIdentityRecord && @@ -2197,7 +2197,7 @@ export class ConversationModel { // We're just dropping the PNI if (!pni) { const oldIdentityRecord = - window.textsecure.storage.protocol.getIdentityRecord(oldValue); + signalProtocolStore.getIdentityRecord(oldValue); if (oldIdentityRecord) { this.trackPreviousIdentityKey(oldIdentityRecord.publicKey); @@ -2207,7 +2207,7 @@ export class ConversationModel { // If this PNI is going away or going to someone else, we'll delete all its sessions if (oldValue) { - drop(window.textsecure.storage.protocol.removeIdentityKey(oldValue)); + drop(signalProtocolStore.removeIdentityKey(oldValue)); } if (pni && !this.getServiceId()) { @@ -2877,7 +2877,7 @@ export class ConversationModel { } try { - return await window.textsecure.storage.protocol.getVerified(serviceId); + return await signalProtocolStore.getVerified(serviceId); } catch { return this.#verifiedEnum.DEFAULT; } @@ -2942,9 +2942,9 @@ export class ConversationModel { const keyChange = false; if (aci) { if (verified === this.#verifiedEnum.DEFAULT) { - await window.textsecure.storage.protocol.setVerified(aci, verified); + await signalProtocolStore.setVerified(aci, verified); } else { - await window.textsecure.storage.protocol.setVerified(aci, verified, { + await signalProtocolStore.setVerified(aci, verified, { firstUse: false, nonblockingApproval: true, }); @@ -2997,7 +2997,7 @@ export class ConversationModel { return; } - const key = await window.textsecure.storage.protocol.loadIdentityKey(aci); + const key = await signalProtocolStore.loadIdentityKey(aci); if (!key) { throw new Error( `sendVerifySyncMessage: No identity key found for aci ${aci}` @@ -3089,7 +3089,7 @@ export class ConversationModel { } return this.queueJob('setApproved', async () => { - return window.textsecure.storage.protocol.setApproval(serviceId, true); + return signalProtocolStore.setApproval(serviceId, true); }); } @@ -3097,10 +3097,7 @@ export class ConversationModel { try { const serviceId = this.getServiceId(); strictAssert(serviceId, `No serviceId for conversation: ${this.id}`); - return window.textsecure.storage.protocol.isUntrusted( - serviceId, - timestampThreshold - ); + return signalProtocolStore.isUntrusted(serviceId, timestampThreshold); } catch (err) { return false; } @@ -3357,8 +3354,7 @@ export class ConversationModel { return; } - const hadSession = - await window.textsecure.storage.protocol.hasSessionWith(originalPni); + const hadSession = await signalProtocolStore.hasSessionWith(originalPni); if (!hadSession) { log.info(`${logId}: not adding, no PNI session`); @@ -5776,7 +5772,7 @@ export class ConversationModel { if (!this.get('shareMyPhoneNumber')) { return undefined; } - return window.textsecure.storage.protocol.signAlternateIdentity(); + return signalProtocolStore.signAlternateIdentity(); } /** @return only undefined if not a group */ diff --git a/ts/services/backups/import.ts b/ts/services/backups/import.ts index 7f15e04cf0..20cb17e18b 100644 --- a/ts/services/backups/import.ts +++ b/ts/services/backups/import.ts @@ -86,6 +86,7 @@ import { SendStatus } from '../../messages/MessageSendState.js'; import type { SendStateByConversationId } from '../../messages/MessageSendState.js'; import { SeenStatus } from '../../MessageSeenStatus.js'; import { constantTimeEqual, deriveAccessKey } from '../../Crypto.js'; +import { signalProtocolStore } from '../../SignalProtocolStore.js'; import * as Bytes from '../../Bytes.js'; import { BACKUP_VERSION, WALLPAPER_TO_BUBBLE_COLOR } from './constants.js'; import { UnsupportedBackupVersion } from './errors.js'; @@ -386,7 +387,7 @@ export class BackupImportStream extends Writable { await window.storage.fetch(); // Load identity keys we just saved. - await window.storage.protocol.hydrateCaches(); + await signalProtocolStore.hydrateCaches(); // Load all data into redux (need to do this before updating a // conversation's last message, which uses redux selectors) diff --git a/ts/services/backups/index.ts b/ts/services/backups/index.ts index 0a91af1d59..c984671ac9 100644 --- a/ts/services/backups/index.ts +++ b/ts/services/backups/index.ts @@ -45,6 +45,7 @@ import { import { HTTPError } from '../../types/HTTPError.js'; import { constantTimeEqual } from '../../Crypto.js'; import { measureSize } from '../../AttachmentCrypto.js'; +import { signalProtocolStore } from '../../SignalProtocolStore.js'; import { isTestOrMockEnvironment } from '../../environment.js'; import { runStorageServiceSyncJob } from '../storage.js'; import { BackupExportStream, type StatsType } from './export.js'; @@ -1014,7 +1015,7 @@ export class BackupsService { try { log.info('backups.unlinkAndDeleteAllData: deleting all data'); - await window.textsecure.storage.protocol.removeAllData(); + await signalProtocolStore.removeAllData(); log.info('backups.unlinkAndDeleteAllData: all data deleted successfully'); } catch (e) { log.error( diff --git a/ts/services/calling.ts b/ts/services/calling.ts index eb9a241cf4..7d6188cc77 100644 --- a/ts/services/calling.ts +++ b/ts/services/calling.ts @@ -165,6 +165,7 @@ import { createIdenticon } from '../util/createIdenticon.js'; import { getColorForCallLink } from '../util/getColorForCallLink.js'; import OS from '../util/os/osMain.js'; import { sleep } from '../util/sleep.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; const { uniqBy, noop, compact } = lodash; @@ -2885,7 +2886,7 @@ export class CallingClass { const { storage } = window.textsecure; const senderIdentityRecord = - await storage.protocol.getOrMigrateIdentityRecord(remoteUserId); + await signalProtocolStore.getOrMigrateIdentityRecord(remoteUserId); if (!senderIdentityRecord) { log.error( `${logId}: Missing sender identity record; ignoring call message.` @@ -2896,7 +2897,8 @@ export class CallingClass { const ourAci = storage.user.getCheckedAci(); - const receiverIdentityRecord = storage.protocol.getIdentityRecord(ourAci); + const receiverIdentityRecord = + signalProtocolStore.getIdentityRecord(ourAci); if (!receiverIdentityRecord) { log.error( `${logId}: Missing receiver identity record; ignoring call message.` @@ -3324,10 +3326,7 @@ export class CallingClass { // This is mostly the safety number check, unverified meaning that they were // verified before but now they are not. const verifiedEnum = await conversation.safeGetVerified(); - if ( - verifiedEnum === - window.textsecure.storage.protocol.VerifiedStatus.UNVERIFIED - ) { + if (verifiedEnum === signalProtocolStore.VerifiedStatus.UNVERIFIED) { log.info(`${logId}: Peer is not trusted, ignoring incoming call`); const localCallEvent = LocalCallEvent.Missed; diff --git a/ts/services/profiles.ts b/ts/services/profiles.ts index 7a8f736674..e3b325112e 100644 --- a/ts/services/profiles.ts +++ b/ts/services/profiles.ts @@ -10,7 +10,8 @@ import { IdentityChange } from '@signalapp/libsignal-client'; import type { ReadonlyDeep } from 'type-fest'; import type { ConversationModel } from '../models/conversations.js'; -import type { CapabilitiesType, ProfileType } from '../textsecure/WebAPI.js'; +import type { CapabilitiesType } from '../types/Capabilities.d.ts'; +import type { ProfileType } from '../textsecure/WebAPI.js'; import MessageSender from '../textsecure/SendMessage.js'; import type { ServiceIdString } from '../types/ServiceId.js'; import { DataWriter } from '../sql/Client.js'; @@ -44,6 +45,7 @@ import { onFailedToSendWithEndorsements, } from '../util/groupSendEndorsements.js'; import { ProfileDecryptError } from '../types/errors.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; const log = createLogger('profiles'); @@ -852,7 +854,7 @@ export async function updateIdentityKey( return false; } - const saveOutcome = await window.textsecure.storage.protocol.saveIdentity( + const saveOutcome = await signalProtocolStore.saveIdentity( new Address(serviceId, 1), identityKey, false, @@ -864,7 +866,7 @@ export async function updateIdentityKey( // save identity will close all sessions except for .1, so we // must close that one manually. const ourAci = window.textsecure.storage.user.getCheckedAci(); - await window.textsecure.storage.protocol.archiveSession( + await signalProtocolStore.archiveSession( new QualifiedAddress(ourAci, new Address(serviceId, 1)) ); } diff --git a/ts/services/storageRecordOps.ts b/ts/services/storageRecordOps.ts index 2290d97c16..9f575fa0b1 100644 --- a/ts/services/storageRecordOps.ts +++ b/ts/services/storageRecordOps.ts @@ -111,6 +111,7 @@ import { } from '../types/ChatFolder.js'; import { deriveGroupID, deriveGroupSecretParams } from '../util/zkgroup.js'; import { chatFolderCleanupService } from './expiring/chatFolderCleanupService.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; const { isEqual } = lodash; @@ -135,7 +136,7 @@ export type MergeResultType = Readonly<{ }>; function toRecordVerified(verified: number): Proto.ContactRecord.IdentityState { - const VERIFIED_ENUM = window.textsecure.storage.protocol.VerifiedStatus; + const VERIFIED_ENUM = signalProtocolStore.VerifiedStatus; const STATE_ENUM = Proto.ContactRecord.IdentityState; switch (verified) { @@ -151,7 +152,7 @@ function toRecordVerified(verified: number): Proto.ContactRecord.IdentityState { function fromRecordVerified( verified: Proto.ContactRecord.IdentityState ): number { - const VERIFIED_ENUM = window.textsecure.storage.protocol.VerifiedStatus; + const VERIFIED_ENUM = signalProtocolStore.VerifiedStatus; const STATE_ENUM = Proto.ContactRecord.IdentityState; switch (verified) { @@ -283,7 +284,7 @@ export async function toContactRecord( const serviceId = aci ?? pni; const identityKey = serviceId - ? await window.textsecure.storage.protocol.loadIdentityKey(serviceId) + ? await signalProtocolStore.loadIdentityKey(serviceId) : undefined; if (identityKey) { contactRecord.identityKey = identityKey; @@ -1376,12 +1377,11 @@ export async function mergeContactRecord( } const newVerified = fromRecordVerified(identityState); - const needsNotification = - await window.textsecure.storage.protocol.updateIdentityAfterSync( - serviceId, - newVerified, - contactRecord.identityKey - ); + const needsNotification = await signalProtocolStore.updateIdentityAfterSync( + serviceId, + newVerified, + contactRecord.identityKey + ); if (verified !== newVerified) { details.push( @@ -1392,7 +1392,7 @@ export async function mergeContactRecord( conversation.set({ verified: newVerified }); } - const VERIFIED_ENUM = window.textsecure.storage.protocol.VerifiedStatus; + const VERIFIED_ENUM = signalProtocolStore.VerifiedStatus; if (needsNotification) { details.push('adding a verified notification'); await conversation.addVerifiedChange( diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index 897cb9f050..c9c01c5739 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -200,7 +200,7 @@ import { } from '../../util/syncIdentifiers.js'; import { MAX_MESSAGE_COUNT } from '../../util/deleteForMe.types.js'; import { markCallHistoryReadInConversation } from './callHistory.js'; -import type { CapabilitiesType } from '../../textsecure/WebAPI.js'; +import type { CapabilitiesType } from '../../types/Capabilities.d.ts'; import { actions as searchActions } from './search.js'; import type { SearchActionType } from './search.js'; import { getNotificationTextForMessage } from '../../util/getNotificationTextForMessage.js'; diff --git a/ts/state/ducks/installer.ts b/ts/state/ducks/installer.ts index 813d214e04..9af9703b10 100644 --- a/ts/state/ducks/installer.ts +++ b/ts/state/ducks/installer.ts @@ -29,6 +29,7 @@ import { useBoundActions } from '../../hooks/useBoundActions.js'; import { createLogger } from '../../logging/log.js'; import { backupsService } from '../../services/backups/index.js'; import OS from '../../util/os/osMain.js'; +import { signalProtocolStore } from '../../SignalProtocolStore.js'; const log = createLogger('installer'); @@ -370,7 +371,7 @@ function finishInstall({ const shouldRetainData = Registration.everDone(); if (!shouldRetainData) { try { - await window.textsecure.storage.protocol.removeAllData(); + await signalProtocolStore.removeAllData(); } catch (error) { log.error( 'finishInstall: error clearing database', diff --git a/ts/test-electron/ConversationController_test.ts b/ts/test-electron/ConversationController_test.ts index 97688cd976..22c76ef4f3 100644 --- a/ts/test-electron/ConversationController_test.ts +++ b/ts/test-electron/ConversationController_test.ts @@ -14,6 +14,7 @@ import type { } from '../types/ServiceId.js'; import { generateAci, generatePni } from '../types/ServiceId.js'; import type { SafeCombineConversationsParams } from '../ConversationController.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; const ACI_1 = generateAci(); const ACI_2 = generateAci(); @@ -41,7 +42,7 @@ describe('ConversationController', () => { window.ConversationController.reset(); await window.ConversationController.load(); - await window.textsecure.storage.protocol.hydrateCaches(); + await signalProtocolStore.hydrateCaches(); mergeOldAndNew = () => { throw new Error('mergeOldAndNew: Should not be called!'); diff --git a/ts/test-electron/MessageReceiver_test.ts b/ts/test-electron/MessageReceiver_test.ts index 61c5d72e5d..20612d2d36 100644 --- a/ts/test-electron/MessageReceiver_test.ts +++ b/ts/test-electron/MessageReceiver_test.ts @@ -15,6 +15,7 @@ import { toAciObject } from '../util/ServiceId.js'; import { SignalService as Proto } from '../protobuf/index.js'; import * as Crypto from '../Crypto.js'; import { toBase64 } from '../Bytes.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; describe('MessageReceiver', () => { const someAci = generateAci(); @@ -27,14 +28,14 @@ describe('MessageReceiver', () => { oldAci = window.storage.user.getAci(); oldDeviceId = window.storage.user.getDeviceId(); await window.storage.user.setAciAndDeviceId(generateAci(), 2); - await window.storage.protocol.hydrateCaches(); + await signalProtocolStore.hydrateCaches(); }); afterEach(async () => { if (oldAci !== undefined && oldDeviceId !== undefined) { await window.storage.user.setAciAndDeviceId(oldAci, oldDeviceId); } - await window.storage.protocol.removeAllUnprocessed(); + await signalProtocolStore.removeAllUnprocessed(); }); describe('connecting', () => { diff --git a/ts/test-electron/SignalProtocolStore_test.ts b/ts/test-electron/SignalProtocolStore_test.ts index 3a28b2b8c9..b7208c7f60 100644 --- a/ts/test-electron/SignalProtocolStore_test.ts +++ b/ts/test-electron/SignalProtocolStore_test.ts @@ -30,7 +30,7 @@ import { generateKyberPreKey, } from '../Curve.js'; import type { SignalProtocolStore } from '../SignalProtocolStore.js'; -import { GLOBAL_ZONE } from '../SignalProtocolStore.js'; +import { GLOBAL_ZONE, signalProtocolStore } from '../SignalProtocolStore.js'; import { Address } from '../types/Address.js'; import { QualifiedAddress } from '../types/QualifiedAddress.js'; import { generateAci, generatePni } from '../types/ServiceId.js'; @@ -152,7 +152,7 @@ describe('SignalProtocolStore', () => { } before(async () => { - store = window.textsecure.storage.protocol; + store = signalProtocolStore; await store.hydrateCaches(); identityKey = IdentityKeyPair.generate(); testKey = IdentityKeyPair.generate(); diff --git a/ts/test-electron/textsecure/AccountManager_test.ts b/ts/test-electron/textsecure/AccountManager_test.ts index d006667060..4cf18ae179 100644 --- a/ts/test-electron/textsecure/AccountManager_test.ts +++ b/ts/test-electron/textsecure/AccountManager_test.ts @@ -19,6 +19,7 @@ import { generatePni, } from '../../types/ServiceId.js'; import { DAY } from '../../util/durations/index.js'; +import { signalProtocolStore } from '../../SignalProtocolStore.js'; const { range } = lodash; @@ -40,9 +41,10 @@ describe('AccountManager', () => { const server: any = {}; accountManager = new AccountManager(server); - const { storage } = window.textsecure; - sandbox.stub(storage.protocol, 'getIdentityKeyPair').returns(identityKey); - const { user } = storage; + sandbox + .stub(signalProtocolStore, 'getIdentityKeyPair') + .returns(identityKey); + const { user } = window.textsecure.storage; sandbox.stub(user, 'getAci').returns(ourAci); sandbox.stub(user, 'getPni').returns(ourPni); sandbox.stub(user, 'getServiceId').returns(ourAci); @@ -83,20 +85,15 @@ describe('AccountManager', () => { let signedPreKeys: Array; beforeEach(async () => { - originalLoadSignedPreKeys = - window.textsecure.storage.protocol.loadSignedPreKeys; - originalRemoveSignedPreKey = - window.textsecure.storage.protocol.removeSignedPreKeys; + originalLoadSignedPreKeys = signalProtocolStore.loadSignedPreKeys; + originalRemoveSignedPreKey = signalProtocolStore.removeSignedPreKeys; - window.textsecure.storage.protocol.loadSignedPreKeys = () => - signedPreKeys; + signalProtocolStore.loadSignedPreKeys = () => signedPreKeys; // removeSignedPreKeys is updated per-test, below }); afterEach(() => { - window.textsecure.storage.protocol.loadSignedPreKeys = - originalLoadSignedPreKeys; - window.textsecure.storage.protocol.removeSignedPreKeys = - originalRemoveSignedPreKey; + signalProtocolStore.loadSignedPreKeys = originalLoadSignedPreKeys; + signalProtocolStore.removeSignedPreKeys = originalRemoveSignedPreKey; }); it('keeps no keys if five or less, even if over a month old', () => { @@ -192,10 +189,7 @@ describe('AccountManager', () => { ]; let removedKeys: Array = []; - window.textsecure.storage.protocol.removeSignedPreKeys = async ( - _, - keyIds - ) => { + signalProtocolStore.removeSignedPreKeys = async (_, keyIds) => { removedKeys = removedKeys.concat(keyIds); }; @@ -210,19 +204,15 @@ describe('AccountManager', () => { let kyberPreKeys: Array; beforeEach(async () => { - originalLoadKyberPreKeys = - window.textsecure.storage.protocol.loadKyberPreKeys; - originalRemoveKyberPreKey = - window.textsecure.storage.protocol.removeKyberPreKeys; + originalLoadKyberPreKeys = signalProtocolStore.loadKyberPreKeys; + originalRemoveKyberPreKey = signalProtocolStore.removeKyberPreKeys; - window.textsecure.storage.protocol.loadKyberPreKeys = () => kyberPreKeys; + signalProtocolStore.loadKyberPreKeys = () => kyberPreKeys; // removeKyberPreKeys is updated per-test, below }); afterEach(() => { - window.textsecure.storage.protocol.loadKyberPreKeys = - originalLoadKyberPreKeys; - window.textsecure.storage.protocol.removeKyberPreKeys = - originalRemoveKyberPreKey; + signalProtocolStore.loadKyberPreKeys = originalLoadKyberPreKeys; + signalProtocolStore.removeKyberPreKeys = originalRemoveKyberPreKey; }); it('keeps five keys even if over a month old', () => { @@ -351,10 +341,7 @@ describe('AccountManager', () => { ]; let removedKeys: Array = []; - window.textsecure.storage.protocol.removeKyberPreKeys = async ( - _, - keyIds - ) => { + signalProtocolStore.removeKyberPreKeys = async (_, keyIds) => { removedKeys = removedKeys.concat(keyIds); }; @@ -369,15 +356,15 @@ describe('AccountManager', () => { let preKeys: Array; beforeEach(async () => { - originalLoadPreKeys = window.textsecure.storage.protocol.loadPreKeys; - originalRemovePreKeys = window.textsecure.storage.protocol.removePreKeys; + originalLoadPreKeys = signalProtocolStore.loadPreKeys; + originalRemovePreKeys = signalProtocolStore.removePreKeys; - window.textsecure.storage.protocol.loadPreKeys = () => preKeys; + signalProtocolStore.loadPreKeys = () => preKeys; // removePreKeys is updated per-test, below }); afterEach(() => { - window.textsecure.storage.protocol.loadPreKeys = originalLoadPreKeys; - window.textsecure.storage.protocol.removePreKeys = originalRemovePreKeys; + signalProtocolStore.loadPreKeys = originalLoadPreKeys; + signalProtocolStore.removePreKeys = originalRemovePreKeys; }); it('keeps five keys even if over 90 days old, but all latest batch', () => { @@ -474,7 +461,7 @@ describe('AccountManager', () => { ]; let removedKeys: Array = []; - window.textsecure.storage.protocol.removePreKeys = async (_, keyIds) => { + signalProtocolStore.removePreKeys = async (_, keyIds) => { removedKeys = removedKeys.concat(keyIds); }; @@ -489,19 +476,15 @@ describe('AccountManager', () => { let kyberPreKeys: Array; beforeEach(async () => { - originalLoadKyberPreKeys = - window.textsecure.storage.protocol.loadKyberPreKeys; - originalRemoveKyberPreKeys = - window.textsecure.storage.protocol.removeKyberPreKeys; + originalLoadKyberPreKeys = signalProtocolStore.loadKyberPreKeys; + originalRemoveKyberPreKeys = signalProtocolStore.removeKyberPreKeys; - window.textsecure.storage.protocol.loadKyberPreKeys = () => kyberPreKeys; + signalProtocolStore.loadKyberPreKeys = () => kyberPreKeys; // removeKyberPreKeys is updated per-test, below }); afterEach(() => { - window.textsecure.storage.protocol.loadKyberPreKeys = - originalLoadKyberPreKeys; - window.textsecure.storage.protocol.removeKyberPreKeys = - originalRemoveKyberPreKeys; + signalProtocolStore.loadKyberPreKeys = originalLoadKyberPreKeys; + signalProtocolStore.removeKyberPreKeys = originalRemoveKyberPreKeys; }); it('keeps five keys even if over 90 days old', () => { @@ -606,10 +589,7 @@ describe('AccountManager', () => { ]; let removedKeys: Array = []; - window.textsecure.storage.protocol.removeKyberPreKeys = async ( - _, - keyIds - ) => { + signalProtocolStore.removeKyberPreKeys = async (_, keyIds) => { removedKeys = removedKeys.concat(keyIds); }; diff --git a/ts/test-electron/textsecure/generate_keys_test.ts b/ts/test-electron/textsecure/generate_keys_test.ts index 474aa106e7..7b2c682954 100644 --- a/ts/test-electron/textsecure/generate_keys_test.ts +++ b/ts/test-electron/textsecure/generate_keys_test.ts @@ -13,6 +13,7 @@ import AccountManager from '../../textsecure/AccountManager.js'; import { ServiceIdKind } from '../../types/ServiceId.js'; import { normalizeAci } from '../../util/normalizeAci.js'; import { DataWriter } from '../../sql/Client.js'; +import { signalProtocolStore } from '../../SignalProtocolStore.js'; const { textsecure } = window; @@ -31,16 +32,13 @@ describe('Key generation', function (this: Mocha.Suite) { function itStoresPreKey(keyId: number): void { it(`prekey ${keyId} is valid`, async () => { - const keyPair = await textsecure.storage.protocol.loadPreKey( - ourServiceId, - keyId - ); + const keyPair = await signalProtocolStore.loadPreKey(ourServiceId, keyId); assert(keyPair, `PreKey ${keyId} not found`); }); } function itStoresKyberPreKey(keyId: number): void { it(`kyber pre key ${keyId} is valid`, async () => { - const key = await textsecure.storage.protocol.loadKyberPreKey( + const key = await signalProtocolStore.loadKyberPreKey( ourServiceId, keyId ); @@ -51,7 +49,7 @@ describe('Key generation', function (this: Mocha.Suite) { async function validateResultPreKey( resultKey: UploadPreKeyType ): Promise { - const keyPair = await textsecure.storage.protocol.loadPreKey( + const keyPair = await signalProtocolStore.loadPreKey( ourServiceId, resultKey.keyId ); @@ -65,9 +63,9 @@ describe('Key generation', function (this: Mocha.Suite) { } before(async () => { - await textsecure.storage.protocol.clearPreKeyStore(); - await textsecure.storage.protocol.clearKyberPreKeyStore(); - await textsecure.storage.protocol.clearSignedPreKeysStore(); + await signalProtocolStore.clearPreKeyStore(); + await signalProtocolStore.clearKyberPreKeyStore(); + await signalProtocolStore.clearSignedPreKeysStore(); const keyPair = generateKeyPair(); await textsecure.storage.put('identityKeyMap', { @@ -78,13 +76,13 @@ describe('Key generation', function (this: Mocha.Suite) { }); await textsecure.storage.user.setAciAndDeviceId(ourServiceId, 1); - await textsecure.storage.protocol.hydrateCaches(); + await signalProtocolStore.hydrateCaches(); }); after(async () => { - await textsecure.storage.protocol.clearPreKeyStore(); - await textsecure.storage.protocol.clearKyberPreKeyStore(); - await textsecure.storage.protocol.clearSignedPreKeysStore(); + await signalProtocolStore.clearPreKeyStore(); + await signalProtocolStore.clearKyberPreKeyStore(); + await signalProtocolStore.clearSignedPreKeysStore(); await DataWriter.removeAll(); await window.storage.fetch(); @@ -209,7 +207,7 @@ describe('Key generation', function (this: Mocha.Suite) { }); it('does not generate a third last resort prekey', async () => { const keyId = 3 * count + 3; - const key = await textsecure.storage.protocol.loadKyberPreKey( + const key = await signalProtocolStore.loadKyberPreKey( ourServiceId, keyId ); @@ -217,7 +215,7 @@ describe('Key generation', function (this: Mocha.Suite) { }); it('does not generate a third signed prekey', async () => { const keyId = 3; - const keyPair = await textsecure.storage.protocol.loadSignedPreKey( + const keyPair = await signalProtocolStore.loadSignedPreKey( ourServiceId, keyId ); diff --git a/ts/textsecure/AccountManager.ts b/ts/textsecure/AccountManager.ts index 460c006217..1fef40e817 100644 --- a/ts/textsecure/AccountManager.ts +++ b/ts/textsecure/AccountManager.ts @@ -72,6 +72,7 @@ import { getRelativePath, createName } from '../util/attachmentPath.js'; import { isLinkAndSyncEnabled } from '../util/isLinkAndSyncEnabled.js'; import { getMessageQueueTime } from '../util/getMessageQueueTime.js'; import { canAttemptRemoteBackupDownload } from '../util/isBackupEnabled.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; const { isNumber, omit, orderBy } = lodash; @@ -281,8 +282,7 @@ export default class AccountManager extends EventTarget { async decryptDeviceName(base64: string): Promise { const ourAci = window.textsecure.storage.user.getCheckedAci(); - const identityKey = - window.textsecure.storage.protocol.getIdentityKeyPair(ourAci); + const identityKey = signalProtocolStore.getIdentityKeyPair(ourAci); if (!identityKey) { throw new Error('decryptDeviceName: No identity key pair!'); } @@ -316,7 +316,7 @@ export default class AccountManager extends EventTarget { } const { storage } = window.textsecure; const deviceName = storage.user.getDeviceName(); - const identityKeyPair = storage.protocol.getIdentityKeyPair( + const identityKeyPair = signalProtocolStore.getIdentityKeyPair( storage.user.getCheckedAci() ); strictAssert( @@ -376,11 +376,9 @@ export default class AccountManager extends EventTarget { } #getIdentityKeyOrThrow(ourServiceId: ServiceIdString): KeyPairType { - const { storage } = window.textsecure; - const store = storage.protocol; let identityKey: KeyPairType | undefined; try { - identityKey = store.getIdentityKeyPair(ourServiceId); + identityKey = signalProtocolStore.getIdentityKeyPair(ourServiceId); } catch (error) { const errorText = Errors.toLogFormat(error); throw new Error( @@ -403,7 +401,6 @@ export default class AccountManager extends EventTarget { window.textsecure.storage.user.getCheckedServiceId(serviceIdKind); const logId = `AccountManager.generateNewPreKeys(${serviceIdKind})`; const { storage } = window.textsecure; - const store = storage.protocol; const startId = getNextKeyId(serviceIdKind, PRE_KEY_ID_KEY); log.info(`${logId}: Generating ${count} new keys starting at ${startId}`); @@ -420,7 +417,7 @@ export default class AccountManager extends EventTarget { } await Promise.all([ - store.storePreKeys(ourServiceId, toSave), + signalProtocolStore.storePreKeys(ourServiceId, toSave), storage.put(PRE_KEY_ID_KEY[serviceIdKind], startId + count), ]); @@ -435,8 +432,6 @@ export default class AccountManager extends EventTarget { count = PRE_KEY_GEN_BATCH_SIZE ): Promise> { const logId = `AccountManager.generateNewKyberPreKeys(${serviceIdKind})`; - const { storage } = window.textsecure; - const store = storage.protocol; const startId = getNextKeyId(serviceIdKind, KYBER_KEY_ID_KEY); log.info(`${logId}: Generating ${count} new keys starting at ${startId}`); @@ -447,6 +442,8 @@ export default class AccountManager extends EventTarget { ); } + const { storage } = window.textsecure; + const ourServiceId = storage.user.getCheckedServiceId(serviceIdKind); const identityKey = this.#getIdentityKeyOrThrow(ourServiceId); @@ -471,7 +468,7 @@ export default class AccountManager extends EventTarget { } await Promise.all([ - store.storeKyberPreKeys(ourServiceId, toSave), + signalProtocolStore.storeKyberPreKeys(ourServiceId, toSave), storage.put(KYBER_KEY_ID_KEY[serviceIdKind], startId + count), ]); @@ -645,9 +642,8 @@ export default class AccountManager extends EventTarget { window.textsecure.storage.user.getCheckedServiceId(serviceIdKind); const identityKey = this.#getIdentityKeyOrThrow(ourServiceId); const logId = `AccountManager.maybeUpdateSignedPreKey(${serviceIdKind}, ${ourServiceId})`; - const store = window.textsecure.storage.protocol; - const keys = await store.loadSignedPreKeys(ourServiceId); + const keys = await signalProtocolStore.loadSignedPreKeys(ourServiceId); const sortedKeys = orderBy(keys, ['created_at'], ['desc']); const confirmedKeys = sortedKeys.filter(key => key.confirmed); const mostRecent = confirmedKeys[0]; @@ -677,7 +673,11 @@ export default class AccountManager extends EventTarget { const key = await this.#generateSignedPreKey(serviceIdKind, identityKey); log.info(`${logId}: Saving new signed prekey`, key.keyId); - await store.storeSignedPreKey(ourServiceId, key.keyId, key.keyPair); + await signalProtocolStore.storeSignedPreKey( + ourServiceId, + key.keyId, + key.keyPair + ); return signedPreKeyToUploadSignedPreKey(key); } @@ -715,9 +715,10 @@ export default class AccountManager extends EventTarget { window.textsecure.storage.user.getCheckedServiceId(serviceIdKind); const identityKey = this.#getIdentityKeyOrThrow(ourServiceId); const logId = `maybeUpdateLastResortKyberKey(${serviceIdKind}, ${ourServiceId})`; - const store = window.textsecure.storage.protocol; - const keys = store.loadKyberPreKeys(ourServiceId, { isLastResort: true }); + const keys = signalProtocolStore.loadKyberPreKeys(ourServiceId, { + isLastResort: true, + }); const sortedKeys = orderBy(keys, ['createdAt'], ['desc']); const confirmedKeys = sortedKeys.filter(key => key.isConfirmed); const mostRecent = confirmedKeys[0]; @@ -751,7 +752,7 @@ export default class AccountManager extends EventTarget { log.info(`${logId}: Saving new last resort prekey`, record.id()); const key = kyberPreKeyToStoredSignedPreKey(record, ourServiceId); - await store.storeKyberPreKeys(ourServiceId, [key]); + await signalProtocolStore.storeKyberPreKeys(ourServiceId, [key]); return kyberPreKeyToUploadSignedPreKey(record); } @@ -760,10 +761,9 @@ export default class AccountManager extends EventTarget { async _cleanSignedPreKeys(serviceIdKind: ServiceIdKind): Promise { const ourServiceId = window.textsecure.storage.user.getCheckedServiceId(serviceIdKind); - const store = window.textsecure.storage.protocol; const logId = `AccountManager.cleanSignedPreKeys(${serviceIdKind})`; - const allKeys = store.loadSignedPreKeys(ourServiceId); + const allKeys = signalProtocolStore.loadSignedPreKeys(ourServiceId); const sortedKeys = orderBy(allKeys, ['created_at'], ['desc']); const confirmed = sortedKeys.filter(key => key.confirmed); const unconfirmed = sortedKeys.filter(key => !key.confirmed); @@ -805,7 +805,7 @@ export default class AccountManager extends EventTarget { }); if (toDelete.length > 0) { log.info(`${logId}: Removing ${toDelete.length} signed prekeys`); - await store.removeSignedPreKeys(ourServiceId, toDelete); + await signalProtocolStore.removeSignedPreKeys(ourServiceId, toDelete); } } @@ -813,10 +813,9 @@ export default class AccountManager extends EventTarget { async _cleanLastResortKeys(serviceIdKind: ServiceIdKind): Promise { const ourServiceId = window.textsecure.storage.user.getCheckedServiceId(serviceIdKind); - const store = window.textsecure.storage.protocol; const logId = `AccountManager.cleanLastResortKeys(${serviceIdKind})`; - const allKeys = store.loadKyberPreKeys(ourServiceId, { + const allKeys = signalProtocolStore.loadKyberPreKeys(ourServiceId, { isLastResort: true, }); const sortedKeys = orderBy(allKeys, ['createdAt'], ['desc']); @@ -862,17 +861,16 @@ export default class AccountManager extends EventTarget { }); if (toDelete.length > 0) { log.info(`${logId}: Removing ${toDelete.length} last resort keys`); - await store.removeKyberPreKeys(ourServiceId, toDelete); + await signalProtocolStore.removeKyberPreKeys(ourServiceId, toDelete); } } async _cleanPreKeys(serviceIdKind: ServiceIdKind): Promise { - const store = window.textsecure.storage.protocol; const logId = `AccountManager.cleanPreKeys(${serviceIdKind})`; const ourServiceId = window.textsecure.storage.user.getCheckedServiceId(serviceIdKind); - const preKeys = store.loadPreKeys(ourServiceId); + const preKeys = signalProtocolStore.loadPreKeys(ourServiceId); const toDelete: Array = []; const sortedKeys = orderBy(preKeys, ['createdAt'], ['desc']); @@ -890,17 +888,16 @@ export default class AccountManager extends EventTarget { log.info(`${logId}: ${sortedKeys.length} total prekeys`); if (toDelete.length > 0) { log.info(`${logId}: Removing ${toDelete.length} obsolete prekeys`); - await store.removePreKeys(ourServiceId, toDelete); + await signalProtocolStore.removePreKeys(ourServiceId, toDelete); } } async _cleanKyberPreKeys(serviceIdKind: ServiceIdKind): Promise { - const store = window.textsecure.storage.protocol; const logId = `AccountManager.cleanKyberPreKeys(${serviceIdKind})`; const ourServiceId = window.textsecure.storage.user.getCheckedServiceId(serviceIdKind); - const preKeys = store.loadKyberPreKeys(ourServiceId, { + const preKeys = signalProtocolStore.loadKyberPreKeys(ourServiceId, { isLastResort: false, }); const toDelete: Array = []; @@ -920,7 +917,7 @@ export default class AccountManager extends EventTarget { log.info(`${logId}: ${sortedKeys.length} total prekeys`); if (toDelete.length > 0) { log.info(`${logId}: Removing ${toDelete.length} kyber keys`); - await store.removeKyberPreKeys(ourServiceId, toDelete); + await signalProtocolStore.removeKyberPreKeys(ourServiceId, toDelete); } } @@ -1004,7 +1001,7 @@ export default class AccountManager extends EventTarget { } try { - await storage.protocol.removeAllData(); + await signalProtocolStore.removeAllData(); log.info('createAccount: Successfully deleted previous data'); cleanStart = true; @@ -1016,7 +1013,7 @@ export default class AccountManager extends EventTarget { } } else { log.info('createAccount: Erasing configuration'); - await storage.protocol.removeAllConfiguration(); + await signalProtocolStore.removeAllConfiguration(); } await senderCertificateService.clear(); @@ -1174,18 +1171,18 @@ export default class AccountManager extends EventTarget { const identityAttrs = { firstUse: true, timestamp: Date.now(), - verified: storage.protocol.VerifiedStatus.VERIFIED, + verified: signalProtocolStore.VerifiedStatus.VERIFIED, nonblockingApproval: true, }; // update our own identity key, which may have changed // if we're relinking after a reinstall on the master device await Promise.all([ - storage.protocol.saveIdentityWithAttributes(ourAci, { + signalProtocolStore.saveIdentityWithAttributes(ourAci, { ...identityAttrs, publicKey: aciKeyPair.publicKey.serialize(), }), - storage.protocol.saveIdentityWithAttributes(ourPni, { + signalProtocolStore.saveIdentityWithAttributes(ourPni, { ...identityAttrs, publicKey: pniKeyPair.publicKey.serialize(), }), @@ -1242,24 +1239,22 @@ export default class AccountManager extends EventTarget { const regionCode = getRegionCodeForNumber(number); await storage.put('regionCode', regionCode); - await storage.protocol.hydrateCaches(); + await signalProtocolStore.hydrateCaches(); - const store = storage.protocol; - - await store.storeSignedPreKey( + await signalProtocolStore.storeSignedPreKey( ourAci, aciSignedPreKey.keyId, aciSignedPreKey.keyPair ); - await store.storeSignedPreKey( + await signalProtocolStore.storeSignedPreKey( ourPni, pniSignedPreKey.keyId, pniSignedPreKey.keyPair ); - await store.storeKyberPreKeys(ourAci, [ + await signalProtocolStore.storeKyberPreKeys(ourAci, [ kyberPreKeyToStoredSignedPreKey(aciPqLastResortPreKey, ourAci), ]); - await store.storeKyberPreKeys(ourPni, [ + await signalProtocolStore.storeKyberPreKeys(ourPni, [ kyberPreKeyToStoredSignedPreKey(pniPqLastResortPreKey, ourPni), ]); @@ -1319,13 +1314,14 @@ export default class AccountManager extends EventTarget { const ourServiceId = window.textsecure.storage.user.getCheckedServiceId(serviceIdKind); const logId = `AccountManager.confirmKeys(${serviceIdKind})`; - const { storage } = window.textsecure; - const store = storage.protocol; const updatedAt = Date.now(); if (signedPreKey) { log.info(`${logId}: confirming signed prekey key`, signedPreKey.keyId); - await store.confirmSignedPreKey(ourServiceId, signedPreKey.keyId); + await signalProtocolStore.confirmSignedPreKey( + ourServiceId, + signedPreKey.keyId + ); await window.storage.put( SIGNED_PRE_KEY_UPDATE_TIME_KEY[serviceIdKind], updatedAt @@ -1339,7 +1335,10 @@ export default class AccountManager extends EventTarget { `${logId}: confirming last resort key`, pqLastResortPreKey.keyId ); - await store.confirmKyberPreKey(ourServiceId, pqLastResortPreKey.keyId); + await signalProtocolStore.confirmKyberPreKey( + ourServiceId, + pqLastResortPreKey.keyId + ); await window.storage.put( LAST_RESORT_KEY_UPDATE_TIME_KEY[serviceIdKind], updatedAt @@ -1398,14 +1397,14 @@ export default class AccountManager extends EventTarget { log.info(`${logId}: updating from ${oldPni}`); if (oldPni) { - await storage.protocol.removeOurOldPni(oldPni); + await signalProtocolStore.removeOurOldPni(oldPni); await window.ConversationController.clearShareMyPhoneNumber(); } await storage.user.setPni(pni); if (keyMaterial) { - await storage.protocol.updateOurPniKeyMaterial(pni, keyMaterial); + await signalProtocolStore.updateOurPniKeyMaterial(pni, keyMaterial); // Intentionally not awaiting since this is processed on encrypted queue // of MessageReceiver. Note that `maybeUpdateKeys` runs on the queue so diff --git a/ts/textsecure/MessageReceiver.ts b/ts/textsecure/MessageReceiver.ts index df64fdd9fb..5e7e72a020 100644 --- a/ts/textsecure/MessageReceiver.ts +++ b/ts/textsecure/MessageReceiver.ts @@ -69,6 +69,7 @@ import { isAciString } from '../util/isAciString.js'; import { calling } from '../services/calling.js'; import { retryPlaceholders } from '../services/retryPlaceholders.js'; import * as Errors from '../types/errors.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; import { SignalService as Proto } from '../protobuf/index.js'; import { deriveGroupFields, MASTER_KEY_LENGTH } from '../groups.js'; @@ -936,7 +937,7 @@ export default class MessageReceiver try { const { id } = item; - await this.#storage.protocol.removeUnprocessed(id); + await signalProtocolStore.removeUnprocessed(id); } catch (deleteError) { log.error( 'queueCached error deleting item', @@ -973,15 +974,13 @@ export default class MessageReceiver async *#getAllFromCache(): AsyncIterable> { log.info('getAllFromCache'); - const ids = await this.#storage.protocol.getAllUnprocessedIds(); + const ids = await signalProtocolStore.getAllUnprocessedIds(); log.info(`getAllFromCache - ${ids.length} unprocessed`); for (const batch of chunk(ids, 1000)) { log.info(`getAllFromCache - yielding batch of ${batch.length}`); - yield this.#storage.protocol.getUnprocessedByIdsAndIncrementAttempts( - batch - ); + yield signalProtocolStore.getUnprocessedByIdsAndIncrementAttempts(batch); } log.info(`getAllFromCache - done retrieving ${ids.length} unprocessed`); } @@ -997,7 +996,7 @@ export default class MessageReceiver }> > = []; - const storageProtocol = this.#storage.protocol; + const storageProtocol = signalProtocolStore; try { const zone = new Zone('decryptAndCacheBatch', { @@ -1189,7 +1188,7 @@ export default class MessageReceiver } async #cacheRemoveBatch(items: Array): Promise { - await this.#storage.protocol.removeUnprocessed(items); + await signalProtocolStore.removeUnprocessed(items); } #removeFromCache(envelope: ProcessedEnvelope): void { @@ -1750,7 +1749,7 @@ export default class MessageReceiver Address.create(sealedSenderIdentifier, sealedSenderSourceDevice) ); - const plaintext = await this.#storage.protocol.enqueueSenderKeyJob( + const plaintext = await signalProtocolStore.enqueueSenderKeyJob( address, () => groupDecrypt( @@ -1792,7 +1791,7 @@ export default class MessageReceiver messageContent.msgType() === CiphertextMessageType.PreKey ? PreKeySignalMessage.deserialize(messageContent.contents()) : SignalMessage.deserialize(messageContent.contents()); - const plaintext = await this.#storage.protocol.enqueueSessionJob( + const plaintext = await signalProtocolStore.enqueueSessionJob( address, () => { if (message instanceof PreKeySignalMessage) { @@ -1887,7 +1886,7 @@ export default class MessageReceiver } const signalMessage = SignalMessage.deserialize(ciphertext); - const plaintext = await this.#storage.protocol.enqueueSessionJob( + const plaintext = await signalProtocolStore.enqueueSessionJob( address, async () => this.#unpad( @@ -1916,7 +1915,7 @@ export default class MessageReceiver } const preKeySignalMessage = PreKeySignalMessage.deserialize(ciphertext); - const plaintext = await this.#storage.protocol.enqueueSessionJob( + const plaintext = await signalProtocolStore.enqueueSessionJob( address, async () => this.#unpad( @@ -2689,7 +2688,7 @@ export default class MessageReceiver Address.create(sourceServiceId, sourceDevice) ); - await this.#storage.protocol.enqueueSenderKeyJob( + await signalProtocolStore.enqueueSenderKeyJob( address, () => processSenderKeyDistributionMessage( @@ -2722,7 +2721,7 @@ export default class MessageReceiver strictAssert(isAciString(aci), `${logId}: invalid ACI`); strictAssert(isPniString(pni), `${logId}: invalid PNI`); - const isValid = await this.#storage.protocol.verifyAlternateIdentity({ + const isValid = await signalProtocolStore.verifyAlternateIdentity({ aci, pni, signature, @@ -4034,7 +4033,7 @@ export default class MessageReceiver logUnexpectedUrgentValue(envelope, 'resetSession'); - await this.#storage.protocol.archiveAllSessions(theirServiceId); + await signalProtocolStore.archiveAllSessions(theirServiceId); } #processDecrypted( diff --git a/ts/textsecure/OutgoingMessage.ts b/ts/textsecure/OutgoingMessage.ts index fc823aade7..a3f21d9d50 100644 --- a/ts/textsecure/OutgoingMessage.ts +++ b/ts/textsecure/OutgoingMessage.ts @@ -45,6 +45,7 @@ import { createLogger } from '../logging/log.js'; import type { GroupSendToken } from '../types/GroupSendEndorsements.js'; import { isSignalServiceId } from '../util/isSignalConversation.js'; import * as Bytes from '../Bytes.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; const { reject } = lodash; @@ -274,7 +275,7 @@ export default class OutgoingMessage { ): () => Promise { return async () => { const ourAci = window.textsecure.storage.user.getCheckedAci(); - const deviceIds = await window.textsecure.storage.protocol.getDeviceIds({ + const deviceIds = await signalProtocolStore.getDeviceIds({ ourServiceId: ourAci, serviceId, }); @@ -452,7 +453,7 @@ export default class OutgoingMessage { new Address(serviceId, destinationDeviceId) ); - return window.textsecure.storage.protocol.enqueueSessionJob( + return signalProtocolStore.enqueueSessionJob( address, async () => { const protocolAddress = ProtocolAddress.new( @@ -622,7 +623,7 @@ export default class OutgoingMessage { } else { p = Promise.all( (response.staleDevices || []).map(async (deviceId: number) => { - await window.textsecure.storage.protocol.archiveSession( + await signalProtocolStore.archiveSession( new QualifiedAddress(ourAci, new Address(serviceId, deviceId)) ); }) @@ -655,7 +656,7 @@ export default class OutgoingMessage { ); log.info('closing all sessions for', serviceId); - window.textsecure.storage.protocol.archiveAllSessions(serviceId).then( + signalProtocolStore.archiveAllSessions(serviceId).then( () => { throw error; }, @@ -687,7 +688,7 @@ export default class OutgoingMessage { await Promise.all( deviceIdsToRemove.map(async deviceId => { - await window.textsecure.storage.protocol.archiveSession( + await signalProtocolStore.archiveSession( new QualifiedAddress(ourAci, new Address(serviceId, deviceId)) ); }) @@ -706,7 +707,7 @@ export default class OutgoingMessage { try { const ourAci = window.textsecure.storage.user.getCheckedAci(); - const deviceIds = await window.textsecure.storage.protocol.getDeviceIds({ + const deviceIds = await signalProtocolStore.getDeviceIds({ ourServiceId: ourAci, serviceId, }); diff --git a/ts/textsecure/SendMessage.ts b/ts/textsecure/SendMessage.ts index 1d1dbae40c..e890a006b6 100644 --- a/ts/textsecure/SendMessage.ts +++ b/ts/textsecure/SendMessage.ts @@ -15,9 +15,9 @@ import { SenderKeyDistributionMessage, } from '@signalapp/libsignal-client'; +import { GLOBAL_ZONE, signalProtocolStore } from '../SignalProtocolStore.js'; import { DataWriter } from '../sql/Client.js'; import type { ConversationModel } from '../models/conversations.js'; -import { GLOBAL_ZONE } from '../SignalProtocolStore.js'; import { assertDev, strictAssert } from '../util/assert.js'; import { parseIntOrThrow } from '../util/parseIntOrThrow.js'; import { Address } from '../types/Address.js'; @@ -1368,9 +1368,7 @@ export default class MessageSender { } if (isPniString(serviceId)) { const pniIdentityKey = - await window.textsecure.storage.protocol.loadIdentityKey( - serviceId - ); + await signalProtocolStore.loadIdentityKey(serviceId); if (pniIdentityKey) { status.destinationPniIdentityKey = pniIdentityKey; } @@ -2297,33 +2295,30 @@ export default class MessageSender { ); const senderKeyDistributionMessage = - await window.textsecure.storage.protocol.enqueueSenderKeyJob( - address, - async () => { - const senderKeyStore = new SenderKeys({ - ourServiceId: ourAci, - zone: GLOBAL_ZONE, - }); + await signalProtocolStore.enqueueSenderKeyJob(address, async () => { + const senderKeyStore = new SenderKeys({ + ourServiceId: ourAci, + zone: GLOBAL_ZONE, + }); - if (throwIfNotInDatabase) { - const key = await senderKeyStore.getSenderKey( - protocolAddress, - distributionId - ); - if (!key) { - throw new NoSenderKeyError( - `getSenderKeyDistributionMessage: Distribution ${distributionId} was not in database as expected` - ); - } - } - - return SenderKeyDistributionMessage.create( + if (throwIfNotInDatabase) { + const key = await senderKeyStore.getSenderKey( protocolAddress, - distributionId, - senderKeyStore + distributionId ); + if (!key) { + throw new NoSenderKeyError( + `getSenderKeyDistributionMessage: Distribution ${distributionId} was not in database as expected` + ); + } } - ); + + return SenderKeyDistributionMessage.create( + protocolAddress, + distributionId, + senderKeyStore + ); + }); log.info( `getSenderKeyDistributionMessage: Building ${distributionId} with timestamp ${timestamp}` diff --git a/ts/textsecure/Storage.ts b/ts/textsecure/Storage.ts index ab2e7de68e..44ed1506c2 100644 --- a/ts/textsecure/Storage.ts +++ b/ts/textsecure/Storage.ts @@ -8,9 +8,7 @@ import type { import { User } from './storage/User.js'; import { Blocked } from './storage/Blocked.js'; -import { assertDev } from '../util/assert.js'; import { DataReader, DataWriter } from '../sql/Client.js'; -import type { SignalProtocolStore } from '../SignalProtocolStore.js'; import { createLogger } from '../logging/log.js'; const log = createLogger('Storage'); @@ -30,7 +28,6 @@ export class Storage implements StorageInterface { #ready = false; #readyCallbacks: Array<() => void> = []; #items: Partial = Object.create(null); - #privProtocol: SignalProtocolStore | undefined; constructor() { this.user = new User(this); @@ -39,18 +36,6 @@ export class Storage implements StorageInterface { window.storage = this; } - get protocol(): SignalProtocolStore { - assertDev( - this.#privProtocol !== undefined, - 'SignalProtocolStore not initialized' - ); - return this.#privProtocol; - } - - set protocol(value: SignalProtocolStore) { - this.#privProtocol = value; - } - // `StorageInterface` implementation public get( diff --git a/ts/textsecure/WebAPI.ts b/ts/textsecure/WebAPI.ts index 780d5b3ad0..31639f798f 100644 --- a/ts/textsecure/WebAPI.ts +++ b/ts/textsecure/WebAPI.ts @@ -36,6 +36,10 @@ import { createProxyAgent } from '../util/createProxyAgent.js'; import type { ProxyAgent } from '../util/createProxyAgent.js'; import type { FetchFunctionType } from '../util/uploads/tusProtocol.js'; import { VerificationTransport } from '../types/VerificationTransport.js'; +import type { + CapabilitiesType, + CapabilitiesUploadType, +} from '../types/Capabilities.d.ts'; import type { HeaderListType } from '../types/WebAPI.d.ts'; import { ZERO_ACCESS_KEY } from '../types/SealedSender.js'; import { toLogFormat } from '../types/errors.js'; @@ -851,16 +855,6 @@ export type WebAPIConnectType = { connect: (options: WebAPIConnectOptionsType) => WebAPIType; }; -// When updating this make sure to update `observedCapabilities` type in -// ts/types/Storage.d.ts -export type CapabilitiesType = { - attachmentBackfill: boolean; -}; -export type CapabilitiesUploadType = { - attachmentBackfill: true; - spqr: true; -}; - type StickerPackManifestType = Uint8Array; export type GroupCredentialType = { diff --git a/ts/textsecure/getKeysForServiceId.ts b/ts/textsecure/getKeysForServiceId.ts index 0c6bb057ae..59042b46cb 100644 --- a/ts/textsecure/getKeysForServiceId.ts +++ b/ts/textsecure/getKeysForServiceId.ts @@ -22,6 +22,7 @@ import { isRecord } from '../util/isRecord.js'; import type { GroupSendToken } from '../types/GroupSendEndorsements.js'; import { HTTPError } from '../types/HTTPError.js'; import { onFailedToSendWithEndorsements } from '../util/groupSendEndorsements.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; const log = createLogger('getKeysForServiceId'); @@ -47,7 +48,7 @@ export async function getKeysForServiceId( }; } catch (error) { if (error instanceof HTTPError && error.code === 404) { - await window.textsecure.storage.protocol.archiveAllSessions(serviceId); + await signalProtocolStore.archiveAllSessions(serviceId); throw new UnregisteredUserError(serviceId, error); } @@ -176,15 +177,13 @@ async function handleServerKeys( ); try { - await window.textsecure.storage.protocol.enqueueSessionJob( - address, - () => - processPreKeyBundle( - preKeyBundle, - protocolAddress, - sessionStore, - identityKeyStore - ) + await signalProtocolStore.enqueueSessionJob(address, () => + processPreKeyBundle( + preKeyBundle, + protocolAddress, + sessionStore, + identityKeyStore + ) ); } catch (error) { if ( diff --git a/ts/types/Capabilities.d.ts b/ts/types/Capabilities.d.ts new file mode 100644 index 0000000000..a31c0c62a8 --- /dev/null +++ b/ts/types/Capabilities.d.ts @@ -0,0 +1,12 @@ +// Copyright 2020 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +// When updating this make sure to update `observedCapabilities` type in +// ts/types/Storage.d.ts +export type CapabilitiesType = { + attachmentBackfill: boolean; +}; +export type CapabilitiesUploadType = { + attachmentBackfill: true; + spqr: true; +}; diff --git a/ts/util/checkOurPniIdentityKey.ts b/ts/util/checkOurPniIdentityKey.ts index 142894d8cf..2c351a2511 100644 --- a/ts/util/checkOurPniIdentityKey.ts +++ b/ts/util/checkOurPniIdentityKey.ts @@ -3,6 +3,7 @@ import { createLogger } from '../logging/log.js'; import { constantTimeEqual } from '../Crypto.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; import { strictAssert } from './assert.js'; const log = createLogger('checkOurPniIdentityKey'); @@ -19,7 +20,7 @@ export async function checkOurPniIdentityKey(): Promise { return; } - const localKeyPair = await window.storage.protocol.getIdentityKeyPair(ourPni); + const localKeyPair = await signalProtocolStore.getIdentityKeyPair(ourPni); if (!localKeyPair) { log.warn(`no local key pair for ${ourPni}, unlinking`); window.Whisper.events.emit('unlinkAndDisconnect'); diff --git a/ts/util/getTitle.ts b/ts/util/getTitle.ts index bfe6e2f696..56cd40011b 100644 --- a/ts/util/getTitle.ts +++ b/ts/util/getTitle.ts @@ -7,6 +7,7 @@ import type { } from '../model-types.d.ts'; import { combineNames } from './combineNames.js'; import { getRegionCodeForNumber } from './libphonenumberUtil.js'; +import { instance, PhoneNumberFormat } from './libphonenumberInstance.js'; import { isDirectConversation } from './whatTypeOfConversation.js'; import { getE164 } from './getE164.js'; @@ -158,18 +159,12 @@ export function getNumber( export function renderNumber(e164: string): string | undefined { try { - const parsedNumber = window.libphonenumberInstance.parse(e164); + const parsedNumber = instance.parse(e164); const regionCode = getRegionCodeForNumber(e164); if (regionCode === window.storage.get('regionCode')) { - return window.libphonenumberInstance.format( - parsedNumber, - window.libphonenumberFormat.NATIONAL - ); + return instance.format(parsedNumber, PhoneNumberFormat.NATIONAL); } - return window.libphonenumberInstance.format( - parsedNumber, - window.libphonenumberFormat.INTERNATIONAL - ); + return instance.format(parsedNumber, PhoneNumberFormat.INTERNATIONAL); } catch (e) { return undefined; } diff --git a/ts/util/handleRetry.ts b/ts/util/handleRetry.ts index 8aaed03850..5e26cb8e3b 100644 --- a/ts/util/handleRetry.ts +++ b/ts/util/handleRetry.ts @@ -9,6 +9,7 @@ import lodash from 'lodash'; import type PQueue from 'p-queue'; import * as Bytes from '../Bytes.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; import { DataReader, DataWriter } from '../sql/Client.js'; import { isProduction } from './version.js'; import { strictAssert } from './assert.js'; @@ -360,13 +361,13 @@ async function archiveSessionOnMatch({ ourAci, Address.create(requesterAci, requesterDevice) ); - const session = await window.textsecure.storage.protocol.loadSession(address); + const session = await signalProtocolStore.loadSession(address); if (session && session.currentRatchetKeyMatches(ratchetKey)) { log.info( 'archiveSessionOnMatch: Matching device and ratchetKey, archiving session' ); - await window.textsecure.storage.protocol.archiveSession(address); + await signalProtocolStore.archiveSession(address); return true; } @@ -720,7 +721,7 @@ function scheduleSessionReset(senderAci: AciString, senderDevice: number) { lightSessionResetQueue.add(async () => { const ourAci = window.textsecure.storage.user.getCheckedAci(); - await window.textsecure.storage.protocol.lightSessionReset( + await signalProtocolStore.lightSessionReset( new QualifiedAddress(ourAci, Address.create(senderAci, senderDevice)) ); }) diff --git a/ts/util/safetyNumber.ts b/ts/util/safetyNumber.ts index d635b036ca..2839c3f884 100644 --- a/ts/util/safetyNumber.ts +++ b/ts/util/safetyNumber.ts @@ -8,6 +8,7 @@ import { assertDev } from './assert.js'; import { uuidToBytes } from './uuidToBytes.js'; import { createLogger } from '../logging/log.js'; import type { SafetyNumberType } from '../types/safetyNumber.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; import { isAciString } from './isAciString.js'; const log = createLogger('safetyNumber'); @@ -27,14 +28,14 @@ export async function generateSafetyNumber( const { storage } = window.textsecure; const ourAci = storage.user.getCheckedAci(); - const us = storage.protocol.getIdentityRecord(ourAci); + const us = signalProtocolStore.getIdentityRecord(ourAci); const ourKeyBuffer = us ? us.publicKey : null; const theirAci = isAciString(contact.serviceId) ? contact.serviceId : undefined; const them = theirAci - ? await storage.protocol.getOrMigrateIdentityRecord(theirAci) + ? await signalProtocolStore.getOrMigrateIdentityRecord(theirAci) : undefined; const theirKeyBuffer = them?.publicKey; diff --git a/ts/util/sendToGroup.ts b/ts/util/sendToGroup.ts index 633ae0c059..46f7c45582 100644 --- a/ts/util/sendToGroup.ts +++ b/ts/util/sendToGroup.ts @@ -14,6 +14,7 @@ import { SenderCertificate, UnidentifiedSenderMessageContent, } from '@signalapp/libsignal-client'; +import { signalProtocolStore, GLOBAL_ZONE } from '../SignalProtocolStore.js'; import { senderCertificateService } from '../services/senderCertificate.js'; import type { SendLogCallbackType } from '../textsecure/OutgoingMessage.js'; import { @@ -65,7 +66,6 @@ import { SignalService as Proto } from '../protobuf/index.js'; import { strictAssert } from './assert.js'; import { createLogger } from '../logging/log.js'; -import { GLOBAL_ZONE } from '../SignalProtocolStore.js'; import { waitForAll } from './waitForAll.js'; import type { GroupSendEndorsementState } from './groupSendEndorsements.js'; import { @@ -355,7 +355,7 @@ export async function sendToGroupViaSenderKey( // 2. Fetch all devices we believe we'll be sending to const ourAci = window.textsecure.storage.user.getCheckedAci(); const { devices: currentDevices, emptyServiceIds } = - await window.textsecure.storage.protocol.getOpenDevices(ourAci, recipients); + await signalProtocolStore.getOpenDevices(ourAci, recipients); let groupSendEndorsementState: GroupSendEndorsementState | null = null; if (groupId != null && !story) { @@ -770,7 +770,7 @@ export async function resetSenderKey( }); const ourAci = window.storage.user.getCheckedAci(); - await window.textsecure.storage.protocol.removeSenderKey( + await signalProtocolStore.removeSenderKey( new QualifiedAddress(ourAci, ourAddress), distributionId ); @@ -950,7 +950,7 @@ async function markServiceIdUnregistered(serviceId: ServiceIdString) { conversation.setUnregistered(); await DataWriter.updateConversation(conversation.attributes); - await window.textsecure.storage.protocol.archiveAllSessions(serviceId); + await signalProtocolStore.archiveAllSessions(serviceId); } function isServiceIdRegistered(serviceId: ServiceIdString) { @@ -992,7 +992,7 @@ async function handle409Response( await waitForAll({ tasks: devices.extraDevices.map(deviceId => async () => { - await window.textsecure.storage.protocol.archiveSession( + await signalProtocolStore.archiveSession( new QualifiedAddress(ourAci, Address.create(uuid, deviceId)) ); }), @@ -1032,7 +1032,7 @@ async function handle410Response( // First, archive our existing sessions with these devices await waitForAll({ tasks: devices.staleDevices.map(deviceId => async () => { - await window.textsecure.storage.protocol.archiveSession( + await signalProtocolStore.archiveSession( new QualifiedAddress(ourAci, Address.create(uuid, deviceId)) ); }), @@ -1151,11 +1151,10 @@ async function encryptForSenderKey({ }); const message = padMessage(contentMessage); - const ciphertextMessage = - await window.textsecure.storage.protocol.enqueueSenderKeyJob( - new QualifiedAddress(ourAci, ourAddress), - () => groupEncrypt(sender, distributionId, senderKeyStore, message) - ); + const ciphertextMessage = await signalProtocolStore.enqueueSenderKeyJob( + new QualifiedAddress(ourAci, ourAddress), + () => groupEncrypt(sender, distributionId, senderKeyStore, message) + ); const groupIdBuffer = groupId ? Bytes.fromBase64(groupId) : null; const senderCertificateObject = await senderCertificateService.get( diff --git a/ts/util/verifyStoryListMembers.ts b/ts/util/verifyStoryListMembers.ts index 053412af2f..fd990f30ee 100644 --- a/ts/util/verifyStoryListMembers.ts +++ b/ts/util/verifyStoryListMembers.ts @@ -5,6 +5,7 @@ import { createLogger } from '../logging/log.js'; import { isNotNil } from './isNotNil.js'; import { updateIdentityKey } from '../services/profiles.js'; import type { ServiceIdString } from '../types/ServiceId.js'; +import { signalProtocolStore } from '../SignalProtocolStore.js'; import * as Bytes from '../Bytes.js'; const log = createLogger('verifyStoryListMembers'); @@ -25,8 +26,7 @@ export async function verifyStoryListMembers( const elements = await Promise.all( serviceIds.map(async serviceId => { - const fingerprint = - await window.textsecure.storage.protocol.getFingerprint(serviceId); + const fingerprint = await signalProtocolStore.getFingerprint(serviceId); if (!fingerprint) { log.warn('no fingerprint found for serviceId=', serviceId); diff --git a/ts/window.d.ts b/ts/window.d.ts index 34151e3208..c48b9173a9 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -8,7 +8,6 @@ import type { Store } from 'redux'; import type { SystemPreferences } from 'electron'; import type PQueue from 'p-queue/dist.js'; import type { assert } from 'chai'; -import googleLibphonenumber from 'google-libphonenumber'; import type { MochaOptions } from 'mocha'; import type { textsecure } from './textsecure/index.js'; @@ -18,7 +17,6 @@ import type { IPCRequest as IPCChallengeRequest, } from './challenge.js'; import type AccountManager from './textsecure/AccountManager.js'; -import type { WebAPIConnectType } from './textsecure/WebAPI.js'; import type { OSType } from './util/os/shared.js'; import type { LocalizerType, @@ -29,7 +27,6 @@ import type { Receipt } from './types/Receipt.js'; import type { ConversationController } from './ConversationController.js'; import type { ReduxActions } from './state/types.js'; import type { BatcherType } from './util/batcher.js'; -import type { SignalProtocolStore } from './SignalProtocolStore.js'; import type { ScreenShareStatus } from './types/Calling.js'; import type { MessageCache } from './services/MessageCache.js'; import type { StateType } from './state/reducer.js'; @@ -45,8 +42,6 @@ import type { WindowsNotificationData } from './services/notifications.js'; import type { QueryStatsOptions } from './sql/main.js'; import type { SocketStatuses } from './textsecure/SocketManager.js'; -const { PhoneNumber, PhoneNumberFormat } = googleLibphonenumber; - export { Long } from 'long'; export type IPCType = { @@ -164,13 +159,6 @@ declare global { // We want to extend various globals, so we need to use interfaces. /* eslint-disable no-restricted-syntax */ interface Window { - // Used in Sticker Creator to create proper paths to emoji images - ROOT_PATH?: string; - // Used for sticker creator localization - localeMessages: { [key: string]: { message: string } }; - - openArtCreator: (opts: { username: string; password: string }) => void; - enterKeyboardMode: () => void; enterMouseMode: () => void; getAccountManager: () => AccountManager; @@ -191,18 +179,11 @@ declare global { isAfterVersion: (version: string, anotherVersion: string) => boolean; isBeforeVersion: (version: string, anotherVersion: string) => boolean; initialTheme?: ThemeType; - libphonenumberInstance: { - parse: (number: string) => PhoneNumber; - getRegionCodeForNumber: (number: PhoneNumber) => string | undefined; - format: (number: PhoneNumber, format: PhoneNumberFormat) => string; - }; - libphonenumberFormat: typeof PhoneNumberFormat; nodeSetImmediate: typeof setImmediate; platform: string; preloadedImages: Array; setImmediate: typeof setImmediate; sendChallengeRequest: (request: IPCChallengeRequest) => void; - showKeyboardShortcuts: () => void; storage: Storage; systemTheme: SystemThemeType; @@ -217,12 +198,8 @@ declare global { ConversationController: ConversationController; Events: IPCEventsType; - FontFace: typeof FontFace; MessageCache: MessageCache; - SignalProtocolStore: typeof SignalProtocolStore; - WebAPI: WebAPIConnectType; Whisper: WhisperType; - getSignalProtocolStore: () => SignalProtocolStore; i18n: LocalizerType; // Note: used in background.html, and not type-checked startApp: () => void; @@ -287,12 +264,6 @@ declare global { interface SharedArrayBuffer { __arrayBuffer: never; } - - interface Set { - // Needed until TS upgrade - difference(other: ReadonlySet): Set; - symmetricDifference(other: ReadonlySet): Set; - } } export type WhisperType = { diff --git a/ts/windows/main/phase2-dependencies.ts b/ts/windows/main/phase2-dependencies.ts index 65d68e75bf..069c5bfd32 100644 --- a/ts/windows/main/phase2-dependencies.ts +++ b/ts/windows/main/phase2-dependencies.ts @@ -1,7 +1,6 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import googleLibphonenumber from 'google-libphonenumber'; import * as moment from 'moment'; // @ts-expect-error -- no types import 'moment/min/locales.min.js'; @@ -15,8 +14,6 @@ import { createLogger } from '../../logging/log.js'; import { SignalContext } from '../context.js'; import * as Attachments from './attachments.js'; -const { PhoneNumberUtil, PhoneNumberFormat } = googleLibphonenumber; - const log = createLogger('phase2-dependencies'); initializeLogging(); @@ -26,27 +23,6 @@ window.textsecure = textsecure; const { config } = window.SignalContext; -window.WebAPI = window.textsecure.WebAPI.initialize({ - chatServiceUrl: config.serverUrl, - storageUrl: config.storageUrl, - updatesUrl: config.updatesUrl, - resourcesUrl: config.resourcesUrl, - cdnUrlObject: { - 0: config.cdnUrl0, - 2: config.cdnUrl2, - 3: config.cdnUrl3, - }, - certificateAuthority: config.certificateAuthority, - contentProxyUrl: config.contentProxyUrl, - proxyUrl: config.proxyUrl, - version: config.version, - disableIPv6: config.disableIPv6, - stripePublishableKey: config.stripePublishableKey, -}); - -window.libphonenumberInstance = PhoneNumberUtil.getInstance(); -window.libphonenumberFormat = PhoneNumberFormat; - const { resolvedTranslationsLocale, preferredSystemLocales, localeOverride } = config; diff --git a/ts/windows/main/preload_test.ts b/ts/windows/main/preload_test.ts index d68d415f29..90bb835c52 100644 --- a/ts/windows/main/preload_test.ts +++ b/ts/windows/main/preload_test.ts @@ -14,7 +14,6 @@ import chaiAsPromised from 'chai-as-promised'; // eslint-disable-next-line import/no-extraneous-dependencies import { reporters, type MochaOptions } from 'mocha'; -import { getSignalProtocolStore } from '../../SignalProtocolStore.js'; import { initMessageCleanup } from '../../services/messageStateCleanup.js'; import { initializeMessageCounter } from '../../util/incrementMessageCounter.js'; import { initializeRedux } from '../../state/initializeRedux.js'; @@ -165,5 +164,3 @@ window.testUtilities = { } }, }; - -window.getSignalProtocolStore = getSignalProtocolStore;