diff --git a/test/setup-test-node.js b/test/setup-test-node.js index 20c5bca861..3baf460c96 100644 --- a/test/setup-test-node.js +++ b/test/setup-test-node.js @@ -18,6 +18,7 @@ global.window = { Date, performance, SignalContext: { + getPath: () => '/tmp', getVersion: () => package.version, config: { serverUrl: 'https://127.0.0.1:9', diff --git a/ts/CI.ts b/ts/CI.ts index 89b4ff029c..2608702e14 100644 --- a/ts/CI.ts +++ b/ts/CI.ts @@ -11,6 +11,7 @@ import { explodePromise } from './util/explodePromise.js'; import { AccessType, ipcInvoke } from './sql/channels.js'; import { backupsService } from './services/backups/index.js'; import { notificationService } from './services/notifications.js'; +import { challengeHandler } from './services/challengeHandler.js'; import { AttachmentBackupManager } from './jobs/AttachmentBackupManager.js'; import { migrateAllMessages } from './messages/migrateMessageData.js'; import { SECOND } from './util/durations/index.js'; @@ -154,7 +155,7 @@ export function getCI({ } function solveChallenge(response: ChallengeResponseType): void { - window.Signal.challengeHandler?.onResponse(response); + challengeHandler.onResponse(response); } async function getMessagesBySentAt(sentAt: number) { diff --git a/ts/CI/benchmarkConversationOpen.ts b/ts/CI/benchmarkConversationOpen.ts index f56cf17ecc..c465066007 100644 --- a/ts/CI/benchmarkConversationOpen.ts +++ b/ts/CI/benchmarkConversationOpen.ts @@ -8,6 +8,7 @@ import { ReadStatus } from '../messages/MessageReadStatus.js'; import { SendStatus } from '../messages/MessageSendState.js'; import { DataWriter } from '../sql/Client.js'; import { BodyRange } from '../types/BodyRange.js'; +import { CURRENT_SCHEMA_VERSION } from '../types/Message2.js'; import { strictAssert } from '../util/assert.js'; import { MINUTE } from '../util/durations/index.js'; import { isOlderThan } from '../util/timestamp.js'; @@ -72,7 +73,7 @@ export async function populateConversationWithMessages({ type: isIncoming ? 'incoming' : 'outgoing', timestamp, sent_at: timestamp, - schemaVersion: window.Signal.Types.Message.CURRENT_SCHEMA_VERSION, + schemaVersion: CURRENT_SCHEMA_VERSION, received_at: incrementMessageCounter(), readStatus: isUnread ? ReadStatus.Unread : ReadStatus.Read, sourceServiceId: isIncoming diff --git a/ts/SignalProtocolStore.ts b/ts/SignalProtocolStore.ts index 89fc6053f3..1f378cfaa4 100644 --- a/ts/SignalProtocolStore.ts +++ b/ts/SignalProtocolStore.ts @@ -61,7 +61,6 @@ import { QualifiedAddress } from './types/QualifiedAddress.js'; import { createLogger } from './logging/log.js'; import * as Errors from './types/errors.js'; import { MINUTE } from './util/durations/index.js'; -import { conversationJobQueue } from './jobs/conversationJobQueue.js'; import { KYBER_KEY_ID_KEY, SIGNED_PRE_KEY_ID_KEY, @@ -1846,8 +1845,7 @@ export class SignalProtocolStore extends EventEmitter { await this.archiveSession(qualifiedAddress); // Enqueue a null message with newly-created session - await conversationJobQueue.add({ - type: 'NullMessage', + this.emit('nullMessage', { conversationId: conversation.id, idForTracking: id, }); @@ -2811,6 +2809,14 @@ export class SignalProtocolStore extends EventEmitter { public override on(name: 'removeAllData', handler: () => unknown): this; + public override on( + name: 'nullMessage', + handler: (options: { + conversationId: string; + idForTracking: string; + }) => unknown + ): this; + public override on( eventName: string | symbol, // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -2829,6 +2835,14 @@ export class SignalProtocolStore extends EventEmitter { public override emit(name: 'removeAllData'): boolean; + public override emit( + name: 'nullMessage', + options: { + conversationId: string; + idForTracking: string; + } + ): boolean; + public override emit( eventName: string | symbol, // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/ts/background.ts b/ts/background.ts index 46e1d74d0f..1fa54251ea 100644 --- a/ts/background.ts +++ b/ts/background.ts @@ -28,8 +28,6 @@ import type { MenuOptionsType } from './types/menu.js'; import { SocketStatus } from './types/SocketStatus.js'; import { DEFAULT_CONVERSATION_COLOR } from './types/Colors.js'; import { ThemeType } from './types/Util.js'; -import { ToastType } from './types/Toast.js'; -import { ChallengeHandler } from './challenge.js'; import * as durations from './util/durations/index.js'; import { drop } from './util/drop.js'; import { explodePromise } from './util/explodePromise.js'; @@ -42,6 +40,7 @@ import { areRemoteBackupsTurnedOn } from './util/isBackupEnabled.js'; import { lightSessionResetQueue } from './util/lightSessionResetQueue.js'; import { setAppLoadingScreenMessage } from './setAppLoadingScreenMessage.js'; import { IdleDetector } from './IdleDetector.js'; +import { challengeHandler } from './services/challengeHandler.js'; import { initialize as initializeExpiringMessageService, update as updateExpiringMessagesService, @@ -85,6 +84,7 @@ import { shutdownAllJobQueues, } from './jobs/initializeAllJobQueues.js'; import { removeStorageKeyJobQueue } from './jobs/removeStorageKeyJobQueue.js'; +import { conversationJobQueue } from './jobs/conversationJobQueue.js'; import { ourProfileKeyService } from './services/ourProfileKey.js'; import { notificationService } from './services/notifications.js'; import { areWeASubscriberService } from './services/areWeASubscriber.js'; @@ -146,7 +146,6 @@ import { registerCapabilities as doRegisterCapabilities, registerRequestHandler, reportMessage, - sendChallengeResponse, unregisterRequestHandler, } from './textsecure/WebAPI.js'; import AccountManager from './textsecure/AccountManager.js'; @@ -204,7 +203,6 @@ import { startInteractionMode } from './services/InteractionMode.js'; import { calling } from './services/calling.js'; import { ReactionSource } from './reactions/ReactionSource.js'; import { singleProtoJobQueue } from './jobs/singleProtoJobQueue.js'; -import { conversationJobQueue } from './jobs/conversationJobQueue.js'; import { SeenStatus } from './MessageSeenStatus.js'; import { MessageSender } from './textsecure/SendMessage.js'; import { onStoryRecipientUpdate } from './util/onStoryRecipientUpdate.js'; @@ -272,6 +270,7 @@ import { isLocalBackupsEnabled } from './util/isLocalBackupsEnabled.js'; import { NavTab, SettingsPage, ProfileEditorPage } from './types/Nav.js'; import { initialize as initializeDonationService } from './services/donations.js'; import { MessageRequestResponseSource } from './types/MessageRequestResponseEvent.js'; +import { CURRENT_SCHEMA_VERSION, PRIVATE, GROUP } from './types/Message2.js'; import { JobCancelReason } from './jobs/types.js'; import { itemStorage } from './textsecure/Storage.js'; @@ -322,7 +321,6 @@ export async function startApp(): Promise { // Initialize WebAPI as early as possible let messageReceiver: MessageReceiver | undefined; - let challengeHandler: ChallengeHandler | undefined; let routineProfileRefresher: RoutineProfileRefresher | undefined; ourProfileKeyService.initialize(itemStorage); @@ -399,8 +397,6 @@ export async function startApp(): Promise { // of preload.js processing window.setImmediate = window.nodeSetImmediate; - const { Message } = window.Signal.Types; - log.info('page reloaded'); log.info('environment:', getEnvironment()); @@ -436,6 +432,16 @@ export async function startApp(): Promise { window.reduxActions.stories.removeAllStories(); }); + signalProtocolStore.on('nullMessage', ({ conversationId, idForTracking }) => { + drop( + conversationJobQueue.add({ + type: 'NullMessage', + conversationId, + idForTracking, + }) + ); + }); + window.getSocketStatus = () => { return getSocketStatus(); }; @@ -559,54 +565,10 @@ export async function startApp(): Promise { drop(onExpiration('build')); }); - challengeHandler = new ChallengeHandler({ - storage: itemStorage, - - startQueue(conversationId: string) { - conversationJobQueue.resolveVerificationWaiter(conversationId); - }, - - requestChallenge(request) { - if (window.SignalCI) { - window.SignalCI.handleEvent('challenge', request); - return; - } - window.sendChallengeRequest(request); - }, - - async sendChallengeResponse(data) { - await sendChallengeResponse(data); - }, - - onChallengeFailed() { - // TODO: DESKTOP-1530 - // Display humanized `retryAfter` - window.reduxActions.toast.showToast({ - toastType: ToastType.CaptchaFailed, - }); - }, - - onChallengeSolved() { - window.reduxActions.toast.showToast({ - toastType: ToastType.CaptchaSolved, - }); - }, - - setChallengeStatus(challengeStatus) { - window.reduxActions.network.setChallengeStatus(challengeStatus); - }, - }); - window.Whisper.events.on('challengeResponse', response => { - if (!challengeHandler) { - throw new Error('Expected challenge handler to be there'); - } - challengeHandler.onResponse(response); }); - window.Signal.challengeHandler = challengeHandler; - log.info('Initializing MessageReceiver'); messageReceiver = new MessageReceiver({ storage: itemStorage, @@ -1074,7 +1036,7 @@ export async function startApp(): Promise { let isMigrationWithIndexComplete = false; let isIdleTaskProcessing = false; log.info( - `Starting background data migration. Target version: ${Message.CURRENT_SCHEMA_VERSION}` + `Starting background data migration. Target version: ${CURRENT_SCHEMA_VERSION}` ); idleDetector.on('idle', async () => { const NUM_MESSAGES_PER_BATCH = 250; @@ -1592,7 +1554,7 @@ export async function startApp(): Promise { hasAppEverBeenRegistered, }); - drop(challengeHandler?.onOffline()); + drop(challengeHandler.onOffline()); drop(AttachmentDownloadManager.stop()); drop(AttachmentBackupManager.stop()); @@ -1923,7 +1885,6 @@ export async function startApp(): Promise { drop(handleServerAlerts(getServerAlerts())); - strictAssert(challengeHandler, 'afterEveryAuthConnect: challengeHandler'); drop(challengeHandler.onOnline()); reconnectBackOff.reset(); @@ -2885,7 +2846,7 @@ export async function startApp(): Promise { const groupV2 = window.ConversationController.get(id); if (groupV2) { return { - type: Message.GROUP, + type: GROUP, id: groupV2.id, }; } @@ -2894,7 +2855,7 @@ export async function startApp(): Promise { const groupV1 = window.ConversationController.getByDerivedGroupV2Id(id); if (groupV1) { return { - type: Message.GROUP, + type: GROUP, id: groupV1.id, }; } @@ -2908,7 +2869,7 @@ export async function startApp(): Promise { }); return { - type: Message.GROUP, + type: GROUP, id: conversationId, }; } @@ -2924,7 +2885,7 @@ export async function startApp(): Promise { ); return { - type: Message.PRIVATE, + type: PRIVATE, id: conversation.id, }; }; @@ -3204,7 +3165,7 @@ export async function startApp(): Promise { messageDescriptor: MessageDescriptor ): boolean { if (message.groupCallUpdate) { - if (message.groupV2 && messageDescriptor.type === Message.GROUP) { + if (message.groupV2 && messageDescriptor.type === GROUP) { const conversationId = messageDescriptor.id; const callId = message.groupCallUpdate?.eraId != null diff --git a/ts/groups.ts b/ts/groups.ts index e9a81effb6..09132ddd56 100644 --- a/ts/groups.ts +++ b/ts/groups.ts @@ -10,7 +10,6 @@ import { getCheckedGroupCredentialsForToday, maybeFetchNewCredentials, } from './services/groupCredentialFetcher.js'; -import { storageServiceUploadJob } from './services/storage.js'; import { DataReader, DataWriter } from './sql/Client.js'; import { toWebSafeBase64, fromWebSafeBase64 } from './util/webSafeBase64.js'; import { assertDev, strictAssert } from './util/assert.js'; @@ -1854,9 +1853,7 @@ export async function createGroupV2( } ); - await conversation.queueJob('storageServiceUploadJob', async () => { - await storageServiceUploadJob({ reason: 'createGroupV2' }); - }); + conversation.captureChange('createGroupV2'); const timestamp = Date.now(); const groupV2Info = conversation.getGroupV2Info({ diff --git a/ts/jobs/conversationJobQueue.ts b/ts/jobs/conversationJobQueue.ts index 6e415440ef..931813996b 100644 --- a/ts/jobs/conversationJobQueue.ts +++ b/ts/jobs/conversationJobQueue.ts @@ -54,6 +54,7 @@ import { isInPast } from '../util/timestamp.js'; import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary.js'; import { FIBONACCI } from '../util/BackOff.js'; import { parseUnknown } from '../util/schemas.js'; +import { challengeHandler } from '../services/challengeHandler.js'; const globalLogger = createLogger('conversationJobQueue'); @@ -418,11 +419,7 @@ export class ConversationJobQueue extends JobQueue { const { conversationId, type } = data; if (shouldSendShowCaptcha(data.type)) { - strictAssert( - window.Signal.challengeHandler, - 'conversationJobQueue.add: Missing challengeHandler!' - ); - window.Signal.challengeHandler.maybeSolve({ + challengeHandler.maybeSolve({ conversationId, reason: `conversationJobQueue.add(${conversationId}, ${type})`, }); @@ -747,7 +744,7 @@ export class ConversationJobQueue extends JobQueue { ); // We're starting to retry jobs; remove the challenge handler - drop(window.Signal.challengeHandler?.unregister(conversationId, logId)); + drop(challengeHandler.unregister(conversationId, logId)); this.#perConversationData.set(conversationId, { status: RETRY_STATUS.RUNNING, @@ -824,7 +821,7 @@ export class ConversationJobQueue extends JobQueue { } const isChallengeRegistered = - window.Signal.challengeHandler?.isRegistered(conversationId); + challengeHandler.isRegistered(conversationId); if (!isChallengeRegistered) { this.#unblockConversationRetries(conversationId); } @@ -834,7 +831,7 @@ export class ConversationJobQueue extends JobQueue { throw new Error("Shutting down, can't wait for captcha challenge."); } - window.Signal.challengeHandler?.maybeSolve({ + challengeHandler.maybeSolve({ conversationId, reason: 'conversationJobQueue.run/addWaiter(' + @@ -1013,7 +1010,7 @@ export class ConversationJobQueue extends JobQueue { const silent = !shouldSendShowCaptcha(type); drop( - window.Signal.challengeHandler?.register( + challengeHandler.register( { conversationId, createdAt: Date.now(), diff --git a/ts/jobs/helpers/sendNormalMessage.ts b/ts/jobs/helpers/sendNormalMessage.ts index 8f0cf4b13b..2cf85ea4e7 100644 --- a/ts/jobs/helpers/sendNormalMessage.ts +++ b/ts/jobs/helpers/sendNormalMessage.ts @@ -34,6 +34,7 @@ import type { RawBodyRange } from '../../types/BodyRange.js'; import type { EmbeddedContactWithUploadedAvatar } from '../../types/EmbeddedContact.js'; import type { StoryContextType } from '../../types/Util.js'; import type { LoggerType } from '../../types/Logging.js'; +import { GROUP } from '../../types/Message2.js'; import type { ConversationQueueJobBundle, NormalMessageSendJobData, @@ -82,8 +83,6 @@ export async function sendNormalMessage( }: ConversationQueueJobBundle, data: NormalMessageSendJobData ): Promise { - const { Message } = window.Signal.Types; - const { messageId, revision, editedMessageTimestamp } = data; const message = await getMessageById(messageId); if (!message) { @@ -306,7 +305,7 @@ export async function sendNormalMessage( const sendOptions = await getSendOptions(conversation.attributes); let innerPromise: Promise; - if (conversationType === Message.GROUP) { + if (conversationType === GROUP) { // Note: this will happen for all old jobs queued beore 5.32.x if (isGroupV2(conversation.attributes) && !isNumber(revision)) { log.error('No revision provided, but conversation is GroupV2'); diff --git a/ts/jobs/helpers/sendStory.ts b/ts/jobs/helpers/sendStory.ts index 0dc69a18b1..3974c518da 100644 --- a/ts/jobs/helpers/sendStory.ts +++ b/ts/jobs/helpers/sendStory.ts @@ -36,6 +36,7 @@ import { handleMessageSend } from '../../util/handleMessageSend.js'; import { handleMultipleSendErrors } from './handleMultipleSendErrors.js'; import { isGroupV2, isMe } from '../../util/whatTypeOfConversation.js'; import { ourProfileKeyService } from '../../services/ourProfileKey.js'; +import { challengeHandler } from '../../services/challengeHandler.js'; import { sendContentMessageToGroup } from '../../util/sendToGroup.js'; import { distributionListToSendTarget } from '../../util/distributionListToSendTarget.js'; import { uploadAttachment } from '../../util/uploadAttachment.js'; @@ -446,7 +447,7 @@ export async function sendStory( // conversationJobQueue. errors.forEach(error => { if (error instanceof SendMessageChallengeError) { - void window.Signal.challengeHandler?.register( + void challengeHandler.register( { conversationId: conversation.id, createdAt: Date.now(), diff --git a/ts/messages/copyQuote.ts b/ts/messages/copyQuote.ts index e6ad57ff23..80476d84c4 100644 --- a/ts/messages/copyQuote.ts +++ b/ts/messages/copyQuote.ts @@ -9,6 +9,7 @@ import { SignalService } from '../protobuf/index.js'; import { isGiftBadge, isTapToView } from '../state/selectors/message.js'; import type { ProcessedQuote } from '../textsecure/Types.js'; import { IMAGE_JPEG } from '../types/MIME.js'; +import { VERSION_NEEDED_FOR_DISPLAY } from '../types/Message2.js'; import { strictAssert } from '../util/assert.js'; import { getQuoteBodyText } from '../util/getQuoteBodyText.js'; import { isQuoteAMatch } from './quotes.js'; @@ -135,10 +136,7 @@ export const copyQuoteContentFromOriginal = async ( } try { - await messageCache.upgradeSchema( - message, - window.Signal.Types.Message.VERSION_NEEDED_FOR_DISPLAY - ); + await messageCache.upgradeSchema(message, VERSION_NEEDED_FOR_DISPLAY); } catch (error) { log.error( 'Problem upgrading message quoted message from database', diff --git a/ts/models/conversations.ts b/ts/models/conversations.ts index 91d7982a7c..e8d9adf837 100644 --- a/ts/models/conversations.ts +++ b/ts/models/conversations.ts @@ -108,6 +108,7 @@ import { isNotNil } from '../util/isNotNil.js'; import { signalProtocolStore } from '../SignalProtocolStore.js'; import { shouldSaveNotificationAvatarToDisk } from '../services/notifications.js'; import { storageServiceUploadJob } from '../services/storage.js'; +import { challengeHandler } from '../services/challengeHandler.js'; import { getSendOptions } from '../util/getSendOptions.js'; import type { IsConversationAcceptedOptionsType } from '../util/isConversationAccepted.js'; import { isConversationAccepted } from '../util/isConversationAccepted.js'; @@ -1372,10 +1373,7 @@ export class ConversationModel { // If captchas are active, then we should drop typing messages because // they're less important and could overwhelm the queue. - if ( - window.Signal.challengeHandler?.areAnyRegistered() && - this.isSealedSenderDisabled() - ) { + if (challengeHandler.areAnyRegistered() && this.isSealedSenderDisabled()) { log.info( `sendTypingMessage(${this.idForLogging()}): Challenge is registered and can't send sealed, ignoring` ); diff --git a/ts/models/messages.ts b/ts/models/messages.ts index 361afe07f0..ffb1cd5fa6 100644 --- a/ts/models/messages.ts +++ b/ts/models/messages.ts @@ -3,6 +3,7 @@ import type { MessageAttributesType } from '../model-types.d.ts'; import type { CallbackResultType } from '../textsecure/Types.d.ts'; +import { initializeSchemaVersion } from '../types/Message2.js'; import { createLogger } from '../logging/log.js'; const log = createLogger('messages'); @@ -44,7 +45,7 @@ export class MessageModel { this.#_attributes = attributes; this.set( - window.Signal.Types.Message.initializeSchemaVersion({ + initializeSchemaVersion({ message: attributes, logger: log, }), diff --git a/ts/services/backups/index.ts b/ts/services/backups/index.ts index 50f263251a..93b9d0d231 100644 --- a/ts/services/backups/index.ts +++ b/ts/services/backups/index.ts @@ -21,6 +21,7 @@ import { createLogger } from '../../logging/log.js'; import * as Bytes from '../../Bytes.js'; import { strictAssert } from '../../util/assert.js'; import { drop } from '../../util/drop.js'; +import { TEMP_PATH } from '../../util/basePaths.js'; import { waitForAllBatchers } from '../../util/batcher.js'; import { flushAllWaitBatchers } from '../../util/waitBatcher.js'; import { DelimitedStream } from '../../util/DelimitedStream.js'; @@ -307,7 +308,7 @@ export class BackupsService { await this.#waitForEmptyQueues('backups.upload'); const fileName = `backup-${randomBytes(32).toString('hex')}`; - const filePath = join(window.BasePaths.temp, fileName); + const filePath = join(TEMP_PATH, fileName); const backupLevel = await this.credentials.getBackupLevel( BackupCredentialType.Media diff --git a/ts/services/challengeHandler.ts b/ts/services/challengeHandler.ts new file mode 100644 index 0000000000..f41308a7f0 --- /dev/null +++ b/ts/services/challengeHandler.ts @@ -0,0 +1,46 @@ +// Copyright 2025 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { ChallengeHandler } from '../challenge.js'; +import { itemStorage } from '../textsecure/Storage.js'; +import { sendChallengeResponse as doSendChallengeResponse } from '../textsecure/WebAPI.js'; +import { conversationJobQueue } from '../jobs/conversationJobQueue.js'; +import { ToastType } from '../types/Toast.js'; + +export const challengeHandler = new ChallengeHandler({ + storage: itemStorage, + + startQueue(conversationId: string) { + conversationJobQueue.resolveVerificationWaiter(conversationId); + }, + + requestChallenge(request) { + if (window.SignalCI) { + window.SignalCI.handleEvent('challenge', request); + return; + } + window.sendChallengeRequest(request); + }, + + async sendChallengeResponse(data) { + await doSendChallengeResponse(data); + }, + + onChallengeFailed() { + // TODO: DESKTOP-1530 + // Display humanized `retryAfter` + window.reduxActions.toast.showToast({ + toastType: ToastType.CaptchaFailed, + }); + }, + + onChallengeSolved() { + window.reduxActions.toast.showToast({ + toastType: ToastType.CaptchaSolved, + }); + }, + + setChallengeStatus(challengeStatus) { + window.reduxActions.network.setChallengeStatus(challengeStatus); + }, +}); diff --git a/ts/signal.ts b/ts/signal.ts index fc4e1cf63d..7b1f82f66a 100644 --- a/ts/signal.ts +++ b/ts/signal.ts @@ -13,8 +13,6 @@ import { DataReader, DataWriter } from './sql/Client.js'; import * as TypesAttachment from './util/Attachment.js'; import * as VisualAttachment from './types/VisualAttachment.js'; import * as MessageType from './types/Message2.js'; -import { Address } from './types/Address.js'; -import { QualifiedAddress } from './types/QualifiedAddress.js'; // Processes / Services import { calling } from './services/calling.js'; @@ -453,23 +451,15 @@ export const setup = (options: { backups: backupsService, }; - const Types = { - Message: MessageType, - - // Mostly for debugging - Address, - QualifiedAddress, - }; - return { Migrations, OS, - Services, - Types, ...(isProduction(window.getVersion()) ? {} : { + Services, + DataReader, DataWriter, }), diff --git a/ts/state/ducks/installer.ts b/ts/state/ducks/installer.ts index b94711a870..640ede3235 100644 --- a/ts/state/ducks/installer.ts +++ b/ts/state/ducks/installer.ts @@ -282,14 +282,12 @@ type FinishInstallOptionsType = ReadonlyDeep<{ isLinkAndSync: boolean; deviceName: string; envelope?: ProvisionEnvelopeType; - backupFile?: Uint8Array; }>; function finishInstall({ isLinkAndSync, envelope: providedEnvelope, deviceName, - backupFile, }: FinishInstallOptionsType): ThunkAction< void, RootStateType, @@ -336,7 +334,6 @@ function finishInstall({ Provisioner.prepareLinkData({ envelope, deviceName, - backupFile, }) ); window.IPC.removeSetupMenuItems(); diff --git a/ts/state/getInitialState.ts b/ts/state/getInitialState.ts index affcc227d7..7f6c21ec8f 100644 --- a/ts/state/getInitialState.ts +++ b/ts/state/getInitialState.ts @@ -40,6 +40,11 @@ import { getEmptyState as usernameEmptyState } from './ducks/username.js'; import OS from '../util/os/osMain.js'; import { getInteractionMode } from '../services/InteractionMode.js'; import { makeLookup } from '../util/makeLookup.js'; +import { + ATTACHMENTS_PATH, + STICKERS_PATH, + TEMP_PATH, +} from '../util/basePaths.js'; import { toCurrentChatFolders } from '../types/ChatFolder.js'; import type { StateType } from './reducer.js'; @@ -216,7 +221,7 @@ export function generateUserState({ return { ...userEmptyState(), - attachmentsPath: window.BasePaths.attachments, + attachmentsPath: ATTACHMENTS_PATH, i18n: window.i18n, interactionMode: getInteractionMode(), isMainWindowFullScreen: mainWindowStats.isFullScreen, @@ -231,8 +236,8 @@ export function generateUserState({ ourPni, platform: window.platform, regionCode: itemStorage.get('regionCode'), - stickersPath: window.BasePaths.stickers, - tempPath: window.BasePaths.temp, + stickersPath: STICKERS_PATH, + tempPath: TEMP_PATH, theme, version: window.getVersion(), }; diff --git a/ts/state/smart/App.tsx b/ts/state/smart/App.tsx index 6009496d44..a3e963224e 100644 --- a/ts/state/smart/App.tsx +++ b/ts/state/smart/App.tsx @@ -10,6 +10,7 @@ import OS from '../../util/os/osMain.js'; import { getConversation } from '../../util/getConversation.js'; import { getChallengeURL } from '../../challenge.js'; import { writeProfile } from '../../services/writeProfile.js'; +import { challengeHandler } from '../../services/challengeHandler.js'; import { SmartCallManager } from './CallManager.js'; import { SmartGlobalModalContainer } from './GlobalModalContainer.js'; import { SmartLightbox } from './Lightbox.js'; @@ -60,10 +61,7 @@ function renderStoryViewer(closeView: () => unknown): JSX.Element { async function getCaptchaToken(): Promise { const url = getChallengeURL('registration'); document.location.href = url; - if (!window.Signal.challengeHandler) { - throw new Error('Captcha handler is not ready!'); - } - return window.Signal.challengeHandler.requestCaptcha({ + return challengeHandler.requestCaptcha({ reason: 'standalone registration', }); } diff --git a/ts/textsecure/AccountManager.ts b/ts/textsecure/AccountManager.ts index 9d30fe1ef9..2e3c41f757 100644 --- a/ts/textsecure/AccountManager.ts +++ b/ts/textsecure/AccountManager.ts @@ -8,7 +8,6 @@ import { AccountEntropyPool, BackupKey, } from '@signalapp/libsignal-client/dist/AccountKeys.js'; -import { Readable } from 'node:stream'; import EventTarget from './EventTarget.js'; import { @@ -37,7 +36,6 @@ import * as Bytes from '../Bytes.js'; import * as Errors from '../types/errors.js'; import { isMockEnvironment } from '../environment.js'; import { senderCertificateService } from '../services/senderCertificate.js'; -import { backupsService } from '../services/backups/index.js'; import { decryptDeviceName, deriveAccessKey, @@ -150,9 +148,6 @@ type CreateAccountSharedOptionsType = Readonly<{ profileKey: Uint8Array; masterKey: Uint8Array | undefined; accountEntropyPool: string | undefined; - - // Test-only - backupFile?: Uint8Array; }>; type CreatePrimaryDeviceOptionsType = Readonly<{ @@ -936,7 +931,6 @@ export default class AccountManager extends EventTarget { mediaRootBackupKey, readReceipts, userAgent, - backupFile, accountEntropyPool, } = options; @@ -974,7 +968,7 @@ export default class AccountManager extends EventTarget { !previousACI && previousNumber && previousNumber !== number; let cleanStart = !previousACI && !previousPNI && !previousNumber; - if (uuidChanged || numberChanged || backupFile !== undefined) { + if (uuidChanged || numberChanged) { if (uuidChanged) { log.warn( 'createAccount: New uuid is different from old uuid; deleting all previous data' @@ -985,12 +979,6 @@ export default class AccountManager extends EventTarget { 'createAccount: New number is different from old number; deleting all previous data' ); } - if (backupFile !== undefined) { - log.warn( - 'createAccount: Restoring from backup; ' + - 'deleting all previous data' - ); - } try { await signalProtocolStore.removeAllData(); @@ -1289,10 +1277,6 @@ export default class AccountManager extends EventTarget { uploadKeys(ServiceIdKind.ACI), uploadKeys(ServiceIdKind.PNI), ]); - - if (backupFile !== undefined) { - await backupsService.importBackup(() => Readable.from([backupFile])); - } } // Exposed only for testing diff --git a/ts/textsecure/Provisioner.ts b/ts/textsecure/Provisioner.ts index c8a8419704..023a84d523 100644 --- a/ts/textsecure/Provisioner.ts +++ b/ts/textsecure/Provisioner.ts @@ -88,7 +88,6 @@ export type SubscriberType = Readonly<{ export type PrepareLinkDataOptionsType = Readonly<{ envelope: EnvelopeType; deviceName: string; - backupFile?: Uint8Array; }>; enum SocketState { @@ -143,7 +142,6 @@ export class Provisioner { public static prepareLinkData({ envelope, deviceName, - backupFile, }: PrepareLinkDataOptionsType): CreateLinkedDeviceOptionsType { const { number, @@ -185,7 +183,6 @@ export class Provisioner { 0, MAX_DEVICE_NAME_LENGTH ), - backupFile, userAgent, ourAci, ourPni, diff --git a/ts/util/basePaths.ts b/ts/util/basePaths.ts new file mode 100644 index 0000000000..342b276982 --- /dev/null +++ b/ts/util/basePaths.ts @@ -0,0 +1,16 @@ +// Copyright 2025 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { + getPath, + getDraftPath, + getStickersPath, + getTempPath, +} from '../../app/attachments.js'; + +const userDataPath = window.SignalContext.getPath('userData'); + +export const ATTACHMENTS_PATH = getPath(userDataPath); +export const DRAFT_PATH = getDraftPath(userDataPath); +export const STICKERS_PATH = getStickersPath(userDataPath); +export const TEMP_PATH = getTempPath(userDataPath); diff --git a/ts/window.d.ts b/ts/window.d.ts index 052e4dfaf6..484319cb0b 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -10,10 +10,7 @@ import type PQueue from 'p-queue/dist.js'; import type { assert } from 'chai'; import type { MochaOptions } from 'mocha'; -import type { - ChallengeHandler, - IPCRequest as IPCChallengeRequest, -} from './challenge.js'; +import type { IPCRequest as IPCChallengeRequest } from './challenge.js'; import type AccountManager from './textsecure/AccountManager.js'; import type { OSType } from './util/os/shared.js'; import type { @@ -28,12 +25,9 @@ import type { BatcherType } from './util/batcher.js'; import type { ScreenShareStatus } from './types/Calling.js'; import type { MessageCache } from './services/MessageCache.js'; import type { StateType } from './state/reducer.js'; -import type { Address } from './types/Address.js'; -import type { QualifiedAddress } from './types/QualifiedAddress.js'; import type { CIType } from './CI.js'; import type { IPCEventsType } from './util/createIPCEvents.js'; import type { SignalContextType } from './windows/context.js'; -import type * as Message2 from './types/Message2.js'; import type { initializeMigrations } from './signal.js'; import type { PropsPreloadType as PreferencesPropsType } from './components/Preferences.js'; import type { WindowsNotificationData } from './services/notifications.js'; @@ -132,24 +126,18 @@ export type SignalCoreType = { DebugLogWindowProps?: DebugLogWindowPropsType; PermissionsWindowProps?: PermissionsWindowPropsType; ScreenShareWindowProps?: ScreenShareWindowPropsType; - // Only for development - Services: { + SettingsWindowProps?: SettingsWindowPropsType; + + OS: OSType; + Migrations: ReturnType; + + // Only for debugging in Dev Tools + Services?: { storage: unknown; backups: unknown; calling: unknown; donations: unknown; }; - SettingsWindowProps?: SettingsWindowPropsType; - Migrations: ReturnType; - Types: { - Message: typeof Message2; - Address: typeof Address; - QualifiedAddress: typeof QualifiedAddress; - }; - OS: OSType; - challengeHandler?: ChallengeHandler; - - // Only for debugging in Dev Tools DataReader?: unknown; DataWriter?: unknown; }; @@ -212,14 +200,6 @@ declare global { // Feature Flags Flags: FeatureFlagType; - // Paths - BasePaths: { - attachments: string; - draft: string; - stickers: string; - temp: string; - }; - // Test only SignalCI?: CIType; diff --git a/ts/windows/main/phase2-dependencies.ts b/ts/windows/main/phase2-dependencies.ts index 13319d00b8..70c689baf8 100644 --- a/ts/windows/main/phase2-dependencies.ts +++ b/ts/windows/main/phase2-dependencies.ts @@ -9,6 +9,11 @@ import { initialize as initializeLogging } from '../../logging/set_up_renderer_l import { setup } from '../../signal.js'; import { addSensitivePath } from '../../util/privacy.js'; import * as dns from '../../util/dns.js'; +import { + ATTACHMENTS_PATH, + STICKERS_PATH, + DRAFT_PATH, +} from '../../util/basePaths.js'; import { createLogger } from '../../logging/log.js'; import { SignalContext } from '../context.js'; import * as Attachments from './attachments.js'; @@ -36,15 +41,9 @@ moment.locale( localeOverride != null ? [localeOverride] : preferredSystemLocales ); -const userDataPath = SignalContext.getPath('userData'); -window.BasePaths = { - attachments: Attachments.getPath(userDataPath), - draft: Attachments.getDraftPath(userDataPath), - stickers: Attachments.getStickersPath(userDataPath), - temp: Attachments.getTempPath(userDataPath), -}; - -addSensitivePath(window.BasePaths.attachments); +addSensitivePath(ATTACHMENTS_PATH); +addSensitivePath(STICKERS_PATH); +addSensitivePath(DRAFT_PATH); if (config.crashDumpsPath) { addSensitivePath(config.crashDumpsPath); } @@ -58,5 +57,5 @@ window.Signal = setup({ Attachments, getRegionCode: () => itemStorage.get('regionCode'), logger: log, - userDataPath, + userDataPath: window.SignalContext.getPath('userData'), });