Remove fallback CDSI implementation
This commit is contained in:
parent
ffb7ae772d
commit
514509e2c7
6 changed files with 69 additions and 219 deletions
|
@ -42,7 +42,6 @@ import {
|
||||||
aciSchema,
|
aciSchema,
|
||||||
untaggedPniSchema,
|
untaggedPniSchema,
|
||||||
} from '../types/ServiceId';
|
} from '../types/ServiceId';
|
||||||
import type { DirectoryConfigType } from '../types/RendererConfig';
|
|
||||||
import type { BackupPresentationHeadersType } from '../types/backups';
|
import type { BackupPresentationHeadersType } from '../types/backups';
|
||||||
import * as Bytes from '../Bytes';
|
import * as Bytes from '../Bytes';
|
||||||
import { randomInt } from '../Crypto';
|
import { randomInt } from '../Crypto';
|
||||||
|
@ -718,7 +717,6 @@ type InitializeOptionsType = {
|
||||||
contentProxyUrl: string;
|
contentProxyUrl: string;
|
||||||
proxyUrl: string | undefined;
|
proxyUrl: string | undefined;
|
||||||
version: string;
|
version: string;
|
||||||
directoryConfig: DirectoryConfigType;
|
|
||||||
disableIPv6: boolean;
|
disableIPv6: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -933,7 +931,6 @@ export type CdsLookupOptionsType = Readonly<{
|
||||||
e164s: ReadonlyArray<string>;
|
e164s: ReadonlyArray<string>;
|
||||||
acisAndAccessKeys?: ReadonlyArray<{ aci: AciString; accessKey: string }>;
|
acisAndAccessKeys?: ReadonlyArray<{ aci: AciString; accessKey: string }>;
|
||||||
returnAcisWithoutUaks?: boolean;
|
returnAcisWithoutUaks?: boolean;
|
||||||
useLibsignal?: boolean;
|
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type GetGroupCredentialsOptionsType = Readonly<{
|
export type GetGroupCredentialsOptionsType = Readonly<{
|
||||||
|
@ -1727,7 +1724,6 @@ export function initialize({
|
||||||
storageUrl,
|
storageUrl,
|
||||||
updatesUrl,
|
updatesUrl,
|
||||||
resourcesUrl,
|
resourcesUrl,
|
||||||
directoryConfig,
|
|
||||||
cdnUrlObject,
|
cdnUrlObject,
|
||||||
certificateAuthority,
|
certificateAuthority,
|
||||||
contentProxyUrl,
|
contentProxyUrl,
|
||||||
|
@ -1835,17 +1831,10 @@ export function initialize({
|
||||||
void socketManager.authenticate({ username, password });
|
void socketManager.authenticate({ username, password });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { directoryUrl, directoryMRENCLAVE } = directoryConfig;
|
|
||||||
|
|
||||||
const cds = new CDSI(libsignalNet, {
|
const cds = new CDSI(libsignalNet, {
|
||||||
logger: log,
|
logger: log,
|
||||||
proxyUrl,
|
proxyUrl,
|
||||||
|
|
||||||
url: directoryUrl,
|
|
||||||
mrenclave: directoryMRENCLAVE,
|
|
||||||
certificateAuthority,
|
|
||||||
version,
|
|
||||||
|
|
||||||
async getAuth() {
|
async getAuth() {
|
||||||
return (await _ajax({
|
return (await _ajax({
|
||||||
call: 'directoryAuthV2',
|
call: 'directoryAuthV2',
|
||||||
|
@ -4727,13 +4716,11 @@ export function initialize({
|
||||||
e164s,
|
e164s,
|
||||||
acisAndAccessKeys = [],
|
acisAndAccessKeys = [],
|
||||||
returnAcisWithoutUaks,
|
returnAcisWithoutUaks,
|
||||||
useLibsignal,
|
|
||||||
}: CdsLookupOptionsType): Promise<CDSResponseType> {
|
}: CdsLookupOptionsType): Promise<CDSResponseType> {
|
||||||
return cds.request({
|
return cds.request({
|
||||||
e164s,
|
e164s,
|
||||||
acisAndAccessKeys,
|
acisAndAccessKeys,
|
||||||
returnAcisWithoutUaks,
|
returnAcisWithoutUaks,
|
||||||
useLibsignal,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +1,82 @@
|
||||||
// Copyright 2022 Signal Messenger, LLC
|
// Copyright 2022 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import type { Net } from '@signalapp/libsignal-client';
|
import type {
|
||||||
import type { connection as WebSocket } from 'websocket';
|
RateLimitedError as NetRateLimitedError,
|
||||||
|
Net,
|
||||||
|
} from '@signalapp/libsignal-client';
|
||||||
|
import {
|
||||||
|
ErrorCode as LibSignalErrorCode,
|
||||||
|
LibSignalErrorBase,
|
||||||
|
} from '@signalapp/libsignal-client';
|
||||||
|
import pTimeout from 'p-timeout';
|
||||||
|
import type { CDSBaseOptionsType } from './CDSBase';
|
||||||
|
import { CDSBase } from './CDSBase';
|
||||||
|
import type { CDSRequestOptionsType, CDSResponseType } from './Types';
|
||||||
|
import { sleep } from '../../util/sleep';
|
||||||
|
import * as durations from '../../util/durations';
|
||||||
|
|
||||||
import * as Bytes from '../../Bytes';
|
export type CDSIOptionsType = CDSBaseOptionsType;
|
||||||
import { CDSISocket } from './CDSISocket';
|
|
||||||
import type { CDSSocketManagerBaseOptionsType } from './CDSSocketManagerBase';
|
|
||||||
import { CDSSocketManagerBase } from './CDSSocketManagerBase';
|
|
||||||
|
|
||||||
export type CDSIOptionsType = Readonly<{
|
const REQUEST_TIMEOUT = 10 * durations.SECOND;
|
||||||
mrenclave: string;
|
|
||||||
}> &
|
|
||||||
CDSSocketManagerBaseOptionsType;
|
|
||||||
|
|
||||||
export class CDSI extends CDSSocketManagerBase<CDSISocket, CDSIOptionsType> {
|
export class CDSI extends CDSBase<CDSIOptionsType> {
|
||||||
readonly #mrenclave: Buffer;
|
#retryAfter?: number;
|
||||||
|
|
||||||
constructor(libsignalNet: Net.Net, options: CDSIOptionsType) {
|
constructor(
|
||||||
super(libsignalNet, options);
|
private readonly libsignalNet: Net.Net,
|
||||||
|
options: CDSIOptionsType
|
||||||
this.#mrenclave = Buffer.from(Bytes.fromHex(options.mrenclave));
|
) {
|
||||||
|
super(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override getSocketUrl(): string {
|
public async request(
|
||||||
const { mrenclave } = this.options;
|
options: CDSRequestOptionsType
|
||||||
|
): Promise<CDSResponseType> {
|
||||||
|
const log = this.logger;
|
||||||
|
|
||||||
return `${this.options.url}/v1/${mrenclave}/discovery`;
|
if (this.#retryAfter !== undefined) {
|
||||||
}
|
const delay = Math.max(0, this.#retryAfter - Date.now());
|
||||||
|
|
||||||
protected override createSocket(socket: WebSocket): CDSISocket {
|
log.info(`CDSSocketManager: waiting ${delay}ms before retrying`);
|
||||||
return new CDSISocket({
|
await sleep(delay);
|
||||||
logger: this.logger,
|
}
|
||||||
socket,
|
|
||||||
mrenclave: this.#mrenclave,
|
const { acisAndAccessKeys, e164s, returnAcisWithoutUaks = false } = options;
|
||||||
});
|
const auth = await this.getAuth();
|
||||||
|
|
||||||
|
log.info('CDSSocketManager: making request via libsignal');
|
||||||
|
try {
|
||||||
|
log.info('CDSSocketManager: starting lookup request');
|
||||||
|
|
||||||
|
const useNewConnectLogic = !window.Signal.RemoteConfig.isEnabled(
|
||||||
|
'desktop.cdsiViaLibsignal.disableNewConnectionLogic'
|
||||||
|
);
|
||||||
|
const { timeout = REQUEST_TIMEOUT } = options;
|
||||||
|
const response = await pTimeout(
|
||||||
|
this.libsignalNet.cdsiLookup(auth, {
|
||||||
|
acisAndAccessKeys,
|
||||||
|
e164s,
|
||||||
|
returnAcisWithoutUaks,
|
||||||
|
useNewConnectLogic,
|
||||||
|
}),
|
||||||
|
timeout
|
||||||
|
);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,175 +0,0 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import type {
|
|
||||||
RateLimitedError as NetRateLimitedError,
|
|
||||||
Net,
|
|
||||||
} from '@signalapp/libsignal-client';
|
|
||||||
import {
|
|
||||||
ErrorCode as LibSignalErrorCode,
|
|
||||||
LibSignalErrorBase,
|
|
||||||
} from '@signalapp/libsignal-client';
|
|
||||||
import type { connection as WebSocket } from 'websocket';
|
|
||||||
import pTimeout from 'p-timeout';
|
|
||||||
|
|
||||||
import type { AbortableProcess } from '../../util/AbortableProcess';
|
|
||||||
import * as durations from '../../util/durations';
|
|
||||||
import { getBasicAuth } from '../../util/getBasicAuth';
|
|
||||||
import { sleep } from '../../util/sleep';
|
|
||||||
import { SECOND } from '../../util/durations';
|
|
||||||
import type { CDSBaseOptionsType } from './CDSBase';
|
|
||||||
import { CDSBase } from './CDSBase';
|
|
||||||
import type { CDSSocketBase } from './CDSSocketBase';
|
|
||||||
import type {
|
|
||||||
CDSRequestOptionsType,
|
|
||||||
CDSResponseType,
|
|
||||||
CDSAuthType,
|
|
||||||
} from './Types.d';
|
|
||||||
import { RateLimitedError } from './RateLimitedError';
|
|
||||||
import { connect as connectWebSocket } from '../WebSocket';
|
|
||||||
|
|
||||||
const REQUEST_TIMEOUT = 10 * SECOND;
|
|
||||||
|
|
||||||
export type CDSSocketManagerBaseOptionsType = Readonly<{
|
|
||||||
url: string;
|
|
||||||
certificateAuthority: string;
|
|
||||||
version: string;
|
|
||||||
}> &
|
|
||||||
CDSBaseOptionsType;
|
|
||||||
|
|
||||||
export abstract class CDSSocketManagerBase<
|
|
||||||
Socket extends CDSSocketBase,
|
|
||||||
Options extends CDSSocketManagerBaseOptionsType,
|
|
||||||
> extends CDSBase<Options> {
|
|
||||||
#retryAfter?: number;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private readonly libsignalNet: Net.Net,
|
|
||||||
options: Options
|
|
||||||
) {
|
|
||||||
super(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async request(
|
|
||||||
options: CDSRequestOptionsType
|
|
||||||
): Promise<CDSResponseType> {
|
|
||||||
const log = this.logger;
|
|
||||||
|
|
||||||
if (this.#retryAfter !== undefined) {
|
|
||||||
const delay = Math.max(0, this.#retryAfter - Date.now());
|
|
||||||
|
|
||||||
log.info(`CDSSocketManager: waiting ${delay}ms before retrying`);
|
|
||||||
await sleep(delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.useLibsignal) {
|
|
||||||
return this.#requestViaLibsignal(options);
|
|
||||||
}
|
|
||||||
return this.#requestViaNativeSocket(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
async #requestViaNativeSocket(
|
|
||||||
options: CDSRequestOptionsType
|
|
||||||
): Promise<CDSResponseType> {
|
|
||||||
const log = this.logger;
|
|
||||||
const auth = await this.getAuth();
|
|
||||||
|
|
||||||
log.info('CDSSocketManager: connecting socket');
|
|
||||||
const socket = await this.#connect(auth).getResult();
|
|
||||||
log.info('CDSSocketManager: connected socket');
|
|
||||||
|
|
||||||
try {
|
|
||||||
let { timeout = REQUEST_TIMEOUT } = options;
|
|
||||||
|
|
||||||
// Handshake
|
|
||||||
{
|
|
||||||
const start = Date.now();
|
|
||||||
await pTimeout(socket.handshake(), timeout);
|
|
||||||
const duration = Date.now() - start;
|
|
||||||
|
|
||||||
timeout = Math.max(timeout - duration, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send request
|
|
||||||
const response = await pTimeout(socket.request(options), timeout);
|
|
||||||
|
|
||||||
return response;
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof RateLimitedError) {
|
|
||||||
if (error.retryAfterSecs > 0) {
|
|
||||||
this.#retryAfter = Math.max(
|
|
||||||
this.#retryAfter ?? Date.now(),
|
|
||||||
Date.now() + error.retryAfterSecs * durations.SECOND
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
log.info('CDSSocketManager: closing socket');
|
|
||||||
void socket.close(3000, 'Normal');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async #requestViaLibsignal(
|
|
||||||
options: CDSRequestOptionsType
|
|
||||||
): Promise<CDSResponseType> {
|
|
||||||
const log = this.logger;
|
|
||||||
const { acisAndAccessKeys, e164s, returnAcisWithoutUaks = false } = options;
|
|
||||||
const auth = await this.getAuth();
|
|
||||||
|
|
||||||
log.info('CDSSocketManager: making request via libsignal');
|
|
||||||
try {
|
|
||||||
log.info('CDSSocketManager: starting lookup request');
|
|
||||||
|
|
||||||
const useNewConnectLogic = !window.Signal.RemoteConfig.isEnabled(
|
|
||||||
'desktop.cdsiViaLibsignal.disableNewConnectionLogic'
|
|
||||||
);
|
|
||||||
const { timeout = REQUEST_TIMEOUT } = options;
|
|
||||||
const response = await pTimeout(
|
|
||||||
this.libsignalNet.cdsiLookup(auth, {
|
|
||||||
acisAndAccessKeys,
|
|
||||||
e164s,
|
|
||||||
returnAcisWithoutUaks,
|
|
||||||
useNewConnectLogic,
|
|
||||||
}),
|
|
||||||
timeout
|
|
||||||
);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#connect(auth: CDSAuthType): AbortableProcess<Socket> {
|
|
||||||
return connectWebSocket<Socket>({
|
|
||||||
name: 'CDSSocket',
|
|
||||||
url: this.getSocketUrl(),
|
|
||||||
version: this.options.version,
|
|
||||||
proxyAgent: this.proxyAgent,
|
|
||||||
certificateAuthority: this.options.certificateAuthority,
|
|
||||||
extraHeaders: {
|
|
||||||
authorization: getBasicAuth(auth),
|
|
||||||
},
|
|
||||||
|
|
||||||
createResource: (socket: WebSocket): Socket => {
|
|
||||||
return this.createSocket(socket);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract getSocketUrl(): string;
|
|
||||||
|
|
||||||
protected abstract createSocket(socket: WebSocket): Socket;
|
|
||||||
}
|
|
1
ts/textsecure/cds/Types.d.ts
vendored
1
ts/textsecure/cds/Types.d.ts
vendored
|
@ -16,5 +16,4 @@ export type CDSRequestOptionsType = Readonly<{
|
||||||
acisAndAccessKeys: ReadonlyArray<{ aci: AciString; accessKey: string }>;
|
acisAndAccessKeys: ReadonlyArray<{ aci: AciString; accessKey: string }>;
|
||||||
returnAcisWithoutUaks?: boolean;
|
returnAcisWithoutUaks?: boolean;
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
useLibsignal?: boolean;
|
|
||||||
}>;
|
}>;
|
||||||
|
|
|
@ -107,9 +107,6 @@ export async function getServiceIdsForE164s(
|
||||||
e164s: expandedE164sArray,
|
e164s: expandedE164sArray,
|
||||||
acisAndAccessKeys,
|
acisAndAccessKeys,
|
||||||
returnAcisWithoutUaks: false,
|
returnAcisWithoutUaks: false,
|
||||||
useLibsignal: window.Signal.RemoteConfig.isEnabled(
|
|
||||||
'desktop.cdsiViaLibsignal'
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const e164sWithVariantsInCdsi = new Map(
|
const e164sWithVariantsInCdsi = new Map(
|
||||||
|
|
|
@ -28,7 +28,6 @@ window.WebAPI = window.textsecure.WebAPI.initialize({
|
||||||
storageUrl: config.storageUrl,
|
storageUrl: config.storageUrl,
|
||||||
updatesUrl: config.updatesUrl,
|
updatesUrl: config.updatesUrl,
|
||||||
resourcesUrl: config.resourcesUrl,
|
resourcesUrl: config.resourcesUrl,
|
||||||
directoryConfig: config.directoryConfig,
|
|
||||||
cdnUrlObject: {
|
cdnUrlObject: {
|
||||||
0: config.cdnUrl0,
|
0: config.cdnUrl0,
|
||||||
2: config.cdnUrl2,
|
2: config.cdnUrl2,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue