diff --git a/ts/textsecure/WebAPI.ts b/ts/textsecure/WebAPI.ts index 535ac68f62..cc8c260e08 100644 --- a/ts/textsecure/WebAPI.ts +++ b/ts/textsecure/WebAPI.ts @@ -766,6 +766,7 @@ export type CdsLookupOptionsType = Readonly<{ e164s: ReadonlyArray; acisAndAccessKeys?: ReadonlyArray<{ aci: AciString; accessKey: string }>; returnAcisWithoutUaks?: boolean; + useLibsignal?: boolean; }>; type GetProfileCommonOptionsType = Readonly< @@ -3485,11 +3486,13 @@ export function initialize({ e164s, acisAndAccessKeys = [], returnAcisWithoutUaks, + useLibsignal, }: CdsLookupOptionsType): Promise { return cds.request({ e164s, acisAndAccessKeys, returnAcisWithoutUaks, + useLibsignal, }); } diff --git a/ts/textsecure/cds/CDSSocketManagerBase.ts b/ts/textsecure/cds/CDSSocketManagerBase.ts index 0fbf369cd9..4d506247d4 100644 --- a/ts/textsecure/cds/CDSSocketManagerBase.ts +++ b/ts/textsecure/cds/CDSSocketManagerBase.ts @@ -1,6 +1,12 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import type { RateLimitedError as NetRateLimitedError } from '@signalapp/libsignal-client'; +import { + Net, + ErrorCode as LibSignalErrorCode, + LibSignalErrorBase, +} from '@signalapp/libsignal-client'; import type { connection as WebSocket } from 'websocket'; import pTimeout from 'p-timeout'; @@ -19,6 +25,7 @@ import type { } from './Types.d'; import { RateLimitedError } from './RateLimitedError'; import { connect as connectWebSocket } from '../WebSocket'; +import { Environment, getEnvironment } from '../../environment'; const REQUEST_TIMEOUT = 10 * SECOND; @@ -47,6 +54,16 @@ export abstract class CDSSocketManagerBase< await sleep(delay); } + if (options.useLibsignal) { + return this.requestViaLibsignal(options); + } + return this.requestViaNativeSocket(options); + } + + private async requestViaNativeSocket( + options: CDSRequestOptionsType + ): Promise { + const log = this.logger; const auth = await this.getAuth(); log.info('CDSSocketManager: connecting socket'); @@ -85,6 +102,59 @@ export abstract class CDSSocketManagerBase< } } + private async requestViaLibsignal( + options: CDSRequestOptionsType + ): Promise { + const log = this.logger; + const { + acisAndAccessKeys, + e164s, + timeout = REQUEST_TIMEOUT, + returnAcisWithoutUaks = false, + } = options; + const auth = await this.getAuth(); + + log.info('CDSSocketManager: making request via libsignal'); + const net = new Net.Net(this.libsignalNetEnvironment()); + try { + log.info('CDSSocketManager: starting lookup request'); + const response = await net.cdsiLookup(auth, { + acisAndAccessKeys, + e164s, + timeout, + returnAcisWithoutUaks, + }); + + log.info('CDSSocketManager: lookup request finished'); + return response as CDSResponseType; + } catch (error) { + if ( + error instanceof LibSignalErrorBase && + error.code === LibSignalErrorCode.RateLimitedError + ) { + const retryError = error as NetRateLimitedError; + this.retryAfter = Math.max( + this.retryAfter ?? Date.now(), + Date.now() + retryError.retryAfterSecs * durations.SECOND + ); + } + throw error; + } + } + + private libsignalNetEnvironment(): Net.Environment { + const env = getEnvironment(); + switch (env) { + case Environment.Production: + return Net.Environment.Production; + case Environment.Development: + case Environment.Test: + case Environment.Staging: + default: + return Net.Environment.Staging; + } + } + private connect(auth: CDSAuthType): AbortableProcess { return connectWebSocket({ name: 'CDSSocket', diff --git a/ts/textsecure/cds/Types.d.ts b/ts/textsecure/cds/Types.d.ts index b21c1b6b7e..a0fb32bbee 100644 --- a/ts/textsecure/cds/Types.d.ts +++ b/ts/textsecure/cds/Types.d.ts @@ -1,23 +1,20 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import type { Net } from '@signalapp/libsignal-client'; import type { AciString, PniString } from '../../types/ServiceId'; -export type CDSAuthType = Readonly<{ - username: string; - password: string; -}>; - -export type CDSResponseEntryType = Readonly<{ - aci: AciString | undefined; - pni: PniString | undefined; -}>; - -export type CDSResponseType = ReadonlyMap; +export type CDSAuthType = Net.CDSAuthType; +export type CDSResponseEntryType = Net.CDSResponseEntryType< + AciString, + PniString +>; +export type CDSResponseType = Net.CDSResponseType; export type CDSRequestOptionsType = Readonly<{ e164s: ReadonlyArray; acisAndAccessKeys: ReadonlyArray<{ aci: AciString; accessKey: string }>; returnAcisWithoutUaks?: boolean; timeout?: number; + useLibsignal?: boolean; }>;