Mirror CDS requests
This commit is contained in:
parent
de84dc06c8
commit
d036803df9
12 changed files with 173 additions and 97 deletions
|
@ -9,6 +9,9 @@ import * as log from './logging/log';
|
|||
export type ConfigKeyType =
|
||||
| 'desktop.announcementGroup'
|
||||
| 'desktop.calling.audioLevelForSpeaking'
|
||||
| 'desktop.cdsi'
|
||||
| 'desktop.cdsi.returnAcisWithoutUaks'
|
||||
| 'desktop.cdsi.mirroring'
|
||||
| 'desktop.clientExpiration'
|
||||
| 'desktop.groupCallOutboundRing'
|
||||
| 'desktop.internalUser'
|
||||
|
|
|
@ -326,9 +326,9 @@ export class Bootstrap {
|
|||
},
|
||||
updatesEnabled: false,
|
||||
|
||||
directoryVersion: 3,
|
||||
directoryV3Url: url,
|
||||
directoryV3MRENCLAVE:
|
||||
directoreType: 'cdsi',
|
||||
directoryCDSIUrl: url,
|
||||
directoryCDSIMRENCLAVE:
|
||||
'51133fecb3fa18aaf0c8f64cb763656d3272d9faaacdb26ae7df082e414fb142',
|
||||
|
||||
...this.options.extraConfig,
|
||||
|
|
|
@ -33,13 +33,18 @@ import { toLogFormat } from '../types/errors';
|
|||
import { isPackIdValid, redactPackId } from '../types/Stickers';
|
||||
import type { UUID, UUIDStringType } from '../types/UUID';
|
||||
import { UUIDKind } from '../types/UUID';
|
||||
import type { DirectoryConfigType } from '../types/RendererConfig';
|
||||
import * as Bytes from '../Bytes';
|
||||
import { getRandomValue } from '../Crypto';
|
||||
import * as linkPreviewFetch from '../linkPreviews/linkPreviewFetch';
|
||||
import { isBadgeImageFileUrlValid } from '../badges/isBadgeImageFileUrlValid';
|
||||
|
||||
import { SocketManager } from './SocketManager';
|
||||
import type { CDSAuthType, CDSResponseType } from './cds/Types.d';
|
||||
import type {
|
||||
CDSAuthType,
|
||||
CDSRequestOptionsType,
|
||||
CDSResponseType,
|
||||
} from './cds/Types.d';
|
||||
import type { CDSBase } from './cds/CDSBase';
|
||||
import { LegacyCDS } from './cds/LegacyCDS';
|
||||
import type { LegacyCDSPutAttestationResponseType } from './cds/LegacyCDS';
|
||||
|
@ -548,40 +553,6 @@ const WEBSOCKET_CALLS = new Set<keyof typeof URL_CALLS>([
|
|||
'storageToken',
|
||||
]);
|
||||
|
||||
type DirectoryV1OptionsType = Readonly<{
|
||||
directoryVersion: 1;
|
||||
directoryUrl: string;
|
||||
directoryEnclaveId: string;
|
||||
directoryTrustAnchor: string;
|
||||
}>;
|
||||
|
||||
type DirectoryV2OptionsType = Readonly<{
|
||||
directoryVersion: 2;
|
||||
directoryV2Url: string;
|
||||
directoryV2PublicKey: string;
|
||||
directoryV2CodeHashes: ReadonlyArray<string>;
|
||||
}>;
|
||||
|
||||
type DirectoryV3OptionsType = Readonly<{
|
||||
directoryVersion: 3;
|
||||
directoryV3Url: string;
|
||||
directoryV3MRENCLAVE: string;
|
||||
}>;
|
||||
|
||||
type OptionalDirectoryFieldsType = {
|
||||
directoryUrl?: unknown;
|
||||
directoryEnclaveId?: unknown;
|
||||
directoryTrustAnchor?: unknown;
|
||||
directoryV2Url?: unknown;
|
||||
directoryV2PublicKey?: unknown;
|
||||
directoryV2CodeHashes?: unknown;
|
||||
directoryV3Url?: unknown;
|
||||
directoryV3MRENCLAVE?: unknown;
|
||||
};
|
||||
|
||||
type DirectoryOptionsType = OptionalDirectoryFieldsType &
|
||||
(DirectoryV1OptionsType | DirectoryV2OptionsType | DirectoryV3OptionsType);
|
||||
|
||||
type InitializeOptionsType = {
|
||||
url: string;
|
||||
storageUrl: string;
|
||||
|
@ -594,7 +565,7 @@ type InitializeOptionsType = {
|
|||
contentProxyUrl: string;
|
||||
proxyUrl: string | undefined;
|
||||
version: string;
|
||||
directoryConfig: DirectoryOptionsType;
|
||||
directoryConfig: DirectoryConfigType;
|
||||
};
|
||||
|
||||
export type MessageType = Readonly<{
|
||||
|
@ -770,6 +741,9 @@ export type CdsLookupOptionsType = Readonly<{
|
|||
e164s: ReadonlyArray<string>;
|
||||
acis?: ReadonlyArray<UUIDStringType>;
|
||||
accessKeys?: ReadonlyArray<string>;
|
||||
returnAcisWithoutUaks?: boolean;
|
||||
isLegacy: boolean;
|
||||
isMirroring: boolean;
|
||||
}>;
|
||||
|
||||
type GetProfileCommonOptionsType = Readonly<
|
||||
|
@ -1105,12 +1079,17 @@ export function initialize({
|
|||
socketManager.authenticate({ username, password });
|
||||
}
|
||||
|
||||
let cds: CDSBase;
|
||||
if (directoryConfig.directoryVersion === 1) {
|
||||
const { directoryUrl, directoryEnclaveId, directoryTrustAnchor } =
|
||||
directoryConfig;
|
||||
const {
|
||||
directoryType,
|
||||
directoryUrl,
|
||||
directoryEnclaveId,
|
||||
directoryTrustAnchor,
|
||||
} = directoryConfig;
|
||||
|
||||
cds = new LegacyCDS({
|
||||
let legacyCDS: LegacyCDS | undefined;
|
||||
let cds: CDSBase;
|
||||
if (directoryType === 'legacy' || directoryType === 'mirrored-cdsi') {
|
||||
legacyCDS = new LegacyCDS({
|
||||
logger: log,
|
||||
directoryEnclaveId,
|
||||
directoryTrustAnchor,
|
||||
|
@ -1183,17 +1162,20 @@ export function initialize({
|
|||
})) as CDSAuthType;
|
||||
},
|
||||
});
|
||||
} else if (directoryConfig.directoryVersion === 2) {
|
||||
const { directoryV2Url, directoryV2PublicKey, directoryV2CodeHashes } =
|
||||
directoryConfig;
|
||||
|
||||
cds = new CDSH({
|
||||
if (directoryType === 'legacy') {
|
||||
cds = legacyCDS;
|
||||
}
|
||||
}
|
||||
if (directoryType === 'cdsi' || directoryType === 'mirrored-cdsi') {
|
||||
const { directoryCDSIUrl, directoryCDSIMRENCLAVE } = directoryConfig;
|
||||
|
||||
cds = new CDSI({
|
||||
logger: log,
|
||||
proxyUrl,
|
||||
|
||||
url: directoryV2Url,
|
||||
publicKey: directoryV2PublicKey,
|
||||
codeHashes: directoryV2CodeHashes,
|
||||
url: directoryCDSIUrl,
|
||||
mrenclave: directoryCDSIMRENCLAVE,
|
||||
certificateAuthority,
|
||||
version,
|
||||
|
||||
|
@ -1205,15 +1187,21 @@ export function initialize({
|
|||
})) as CDSAuthType;
|
||||
},
|
||||
});
|
||||
} else if (directoryConfig.directoryVersion === 3) {
|
||||
const { directoryV3Url, directoryV3MRENCLAVE } = directoryConfig;
|
||||
}
|
||||
if (directoryType === 'cdsh') {
|
||||
const {
|
||||
directoryCDSHUrl,
|
||||
directoryCDSHPublicKey,
|
||||
directoryCDSHCodeHashes,
|
||||
} = directoryConfig;
|
||||
|
||||
cds = new CDSI({
|
||||
cds = new CDSH({
|
||||
logger: log,
|
||||
proxyUrl,
|
||||
|
||||
url: directoryV3Url,
|
||||
mrenclave: directoryV3MRENCLAVE,
|
||||
url: directoryCDSHUrl,
|
||||
publicKey: directoryCDSHPublicKey,
|
||||
codeHashes: directoryCDSHCodeHashes,
|
||||
certificateAuthority,
|
||||
version,
|
||||
|
||||
|
@ -2851,16 +2839,64 @@ export function initialize({
|
|||
return socketManager.getProvisioningResource(handler);
|
||||
}
|
||||
|
||||
async function mirroredCdsLookup(
|
||||
requestOptions: CDSRequestOptionsType,
|
||||
expectedMapPromise: Promise<CDSResponseType>
|
||||
): Promise<void> {
|
||||
try {
|
||||
log.info('cdsLookup: sending mirrored request');
|
||||
const actualMap = await cds.request(requestOptions);
|
||||
|
||||
const expectedMap = await expectedMapPromise;
|
||||
let matched = 0;
|
||||
for (const [e164, { aci }] of actualMap) {
|
||||
if (!aci) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const expectedACI = expectedMap.get(e164)?.aci;
|
||||
if (expectedACI === aci) {
|
||||
matched += 1;
|
||||
} else {
|
||||
log.warn(
|
||||
`cdsLookup: mirrored request has aci=${aci} for ${e164}, while ` +
|
||||
`expected aci=${expectedACI}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
log.info(`cdsLookup: mirrored request success, matched=${matched}`);
|
||||
} catch (error) {
|
||||
log.error('cdsLookup: mirrored request error', toLogFormat(error));
|
||||
}
|
||||
}
|
||||
|
||||
async function cdsLookup({
|
||||
e164s,
|
||||
acis = [],
|
||||
accessKeys = [],
|
||||
returnAcisWithoutUaks,
|
||||
isLegacy,
|
||||
isMirroring,
|
||||
}: CdsLookupOptionsType): Promise<CDSResponseType> {
|
||||
return cds.request({
|
||||
const requestOptions = {
|
||||
e164s,
|
||||
acis,
|
||||
accessKeys,
|
||||
});
|
||||
returnAcisWithoutUaks,
|
||||
};
|
||||
if (!isLegacy || !legacyCDS) {
|
||||
return cds.request(requestOptions);
|
||||
}
|
||||
|
||||
const legacyRequest = legacyCDS.request(requestOptions);
|
||||
|
||||
if (legacyCDS !== cds && isMirroring) {
|
||||
// Intentionally not awaiting
|
||||
mirroredCdsLookup(requestOptions, legacyRequest);
|
||||
}
|
||||
|
||||
return legacyRequest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@ export abstract class CDSSocketBase<
|
|||
e164s,
|
||||
acis,
|
||||
accessKeys,
|
||||
returnAcisWithoutUaks = false,
|
||||
}: CDSRequestOptionsType): Promise<CDSSocketResponseType> {
|
||||
const log = this.logger;
|
||||
|
||||
|
@ -109,6 +110,7 @@ export abstract class CDSSocketBase<
|
|||
})
|
||||
),
|
||||
aciUakPairs: Buffer.concat(aciUakPairs),
|
||||
returnAcisWithoutUaks,
|
||||
}).finish();
|
||||
|
||||
log.info(`CDSSocket.request(): sending version=${version} request`);
|
||||
|
|
|
@ -170,8 +170,8 @@ export class LegacyCDS extends CDSBase<LegacyCDSOptionsType> {
|
|||
for (const [i, e164] of e164s.entries()) {
|
||||
const uuid = uuids[i];
|
||||
result.set(e164, {
|
||||
aci: undefined,
|
||||
pni: uuid ? UUID.cast(uuid) : undefined,
|
||||
aci: uuid ? UUID.cast(uuid) : undefined,
|
||||
pni: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
1
ts/textsecure/cds/Types.d.ts
vendored
1
ts/textsecure/cds/Types.d.ts
vendored
|
@ -19,5 +19,6 @@ export type CDSRequestOptionsType = Readonly<{
|
|||
e164s: ReadonlyArray<string>;
|
||||
acis: ReadonlyArray<UUIDStringType>;
|
||||
accessKeys: ReadonlyArray<string>;
|
||||
returnAcisWithoutUaks?: boolean;
|
||||
timeout?: number;
|
||||
}>;
|
||||
|
|
|
@ -18,24 +18,35 @@ export type configOptionalStringType = z.infer<
|
|||
typeof configOptionalStringSchema
|
||||
>;
|
||||
|
||||
const directoryV1ConfigSchema = z.object({
|
||||
directoryVersion: z.literal(1),
|
||||
const directoryLegacyConfigSchema = z.object({
|
||||
directoryType: z.literal('legacy'),
|
||||
directoryEnclaveId: configRequiredStringSchema,
|
||||
directoryTrustAnchor: configRequiredStringSchema,
|
||||
directoryUrl: configRequiredStringSchema,
|
||||
});
|
||||
|
||||
const directoryV2ConfigSchema = z.object({
|
||||
directoryVersion: z.literal(2),
|
||||
directoryV2CodeHashes: z.array(z.string().nonempty()),
|
||||
directoryV2PublicKey: configRequiredStringSchema,
|
||||
directoryV2Url: configRequiredStringSchema,
|
||||
const directoryCDSIConfigSchema = z.object({
|
||||
directoryType: z.literal('cdsi'),
|
||||
directoryCDSIUrl: configRequiredStringSchema,
|
||||
directoryCDSIMRENCLAVE: configRequiredStringSchema,
|
||||
});
|
||||
|
||||
const directoryV3ConfigSchema = z.object({
|
||||
directoryVersion: z.literal(3),
|
||||
directoryV3Url: configRequiredStringSchema,
|
||||
directoryV3MRENCLAVE: configRequiredStringSchema,
|
||||
const directoryMirroredCDSIConfigSchema = z.object({
|
||||
directoryType: z.literal('mirrored-cdsi'),
|
||||
|
||||
directoryEnclaveId: configRequiredStringSchema,
|
||||
directoryTrustAnchor: configRequiredStringSchema,
|
||||
directoryUrl: configRequiredStringSchema,
|
||||
|
||||
directoryCDSIUrl: configRequiredStringSchema,
|
||||
directoryCDSIMRENCLAVE: configRequiredStringSchema,
|
||||
});
|
||||
|
||||
const directoryCDSHConfigSchema = z.object({
|
||||
directoryType: z.literal('cdsh'),
|
||||
directoryCDSHCodeHashes: z.array(z.string().nonempty()),
|
||||
directoryCDSHPublicKey: configRequiredStringSchema,
|
||||
directoryCDSHUrl: configRequiredStringSchema,
|
||||
});
|
||||
|
||||
export const directoryConfigSchema = z
|
||||
|
@ -44,16 +55,19 @@ export const directoryConfigSchema = z
|
|||
directoryEnclaveId: configOptionalUnknownSchema,
|
||||
directoryTrustAnchor: configOptionalUnknownSchema,
|
||||
directoryUrl: configOptionalUnknownSchema,
|
||||
directoryV2CodeHashes: configOptionalUnknownSchema,
|
||||
directoryV2PublicKey: configOptionalUnknownSchema,
|
||||
directoryV2Url: configOptionalUnknownSchema,
|
||||
directoryV3Url: configOptionalUnknownSchema,
|
||||
directoryV3MRENCLAVE: configOptionalUnknownSchema,
|
||||
|
||||
directoryCDSIUrl: configOptionalUnknownSchema,
|
||||
directoryCDSIMRENCLAVE: configOptionalUnknownSchema,
|
||||
|
||||
directoryCDSHCodeHashes: configOptionalUnknownSchema,
|
||||
directoryCDSHPublicKey: configOptionalUnknownSchema,
|
||||
directoryCDSHUrl: configOptionalUnknownSchema,
|
||||
})
|
||||
.and(
|
||||
directoryV1ConfigSchema
|
||||
.or(directoryV2ConfigSchema)
|
||||
.or(directoryV3ConfigSchema)
|
||||
directoryLegacyConfigSchema
|
||||
.or(directoryMirroredCDSIConfigSchema)
|
||||
.or(directoryCDSIConfigSchema)
|
||||
.or(directoryCDSHConfigSchema)
|
||||
);
|
||||
|
||||
export type DirectoryConfigType = z.infer<typeof directoryConfigSchema>;
|
||||
|
|
|
@ -5,6 +5,7 @@ import type { CDSResponseType } from '../textsecure/cds/Types.d';
|
|||
import type { WebAPIType } from '../textsecure/WebAPI';
|
||||
import type { UUIDStringType } from '../types/UUID';
|
||||
import * as log from '../logging/log';
|
||||
import { isEnabled } from '../RemoteConfig';
|
||||
import { isDirectConversation, isMe } from './whatTypeOfConversation';
|
||||
|
||||
export async function getUuidsForE164s(
|
||||
|
@ -37,9 +38,20 @@ export async function getUuidsForE164s(
|
|||
accessKeys.push(accessKey);
|
||||
}
|
||||
|
||||
const returnAcisWithoutUaks = isEnabled('desktop.cdsi.returnAcisWithoutUaks');
|
||||
const isCDSI = isEnabled('desktop.cdsi');
|
||||
const isMirroring = isEnabled('desktop.cdsi.mirroring');
|
||||
|
||||
log.info(
|
||||
`getUuidsForE164s(${e164s}): acis=${acis.length} ` +
|
||||
`accessKeys=${accessKeys.length}`
|
||||
);
|
||||
return server.cdsLookup({ e164s, acis, accessKeys });
|
||||
return server.cdsLookup({
|
||||
e164s,
|
||||
acis,
|
||||
accessKeys,
|
||||
returnAcisWithoutUaks,
|
||||
isLegacy: !isCDSI,
|
||||
isMirroring,
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue