Include ACI+Access Keys pairs with CDSI requests
This commit is contained in:
parent
13046dc020
commit
757af2cbbe
|
@ -9,7 +9,7 @@
|
|||
"directoryV2PublicKey": null,
|
||||
"directoryV2CodeHashes": null,
|
||||
"directoryV3Url": "https://cdsi.staging.signal.org",
|
||||
"directoryV3MRENCLAVE": "7b75dd6e862decef9b37132d54be082441917a7790e82fe44f9cf653de03a75f",
|
||||
"directoryV3MRENCLAVE": "ddc7b9b1cbcc932e24b9905e26c4ecbea3f9b7effd033f9e96488c2e8449f64e",
|
||||
"cdn": {
|
||||
"0": "https://cdn-staging.signal.org",
|
||||
"2": "https://cdn2-staging.signal.org"
|
||||
|
|
|
@ -27,6 +27,7 @@ import { QualifiedAddress } from './types/QualifiedAddress';
|
|||
import { sleep } from './util/sleep';
|
||||
import { isNotNil } from './util/isNotNil';
|
||||
import { MINUTE, SECOND } from './util/durations';
|
||||
import { getUuidsForE164s } from './util/getUuidsForE164s';
|
||||
|
||||
type ConvoMatchType =
|
||||
| {
|
||||
|
@ -1104,7 +1105,9 @@ export class ConversationController {
|
|||
async _forgetE164(e164: string): Promise<void> {
|
||||
const { server } = window.textsecure;
|
||||
strictAssert(server, 'Server must be initialized');
|
||||
const { [e164]: pni } = await server.getUuidsForE164s([e164]);
|
||||
const uuidMap = await getUuidsForE164s(server, [e164]);
|
||||
|
||||
const pni = uuidMap.get(e164)?.pni;
|
||||
|
||||
log.info(`ConversationController: forgetting e164=${e164} pni=${pni}`);
|
||||
|
||||
|
|
|
@ -2128,15 +2128,16 @@ export async function startApp(): Promise<void> {
|
|||
!c.isEverUnregistered()
|
||||
)
|
||||
);
|
||||
strictAssert(window.textsecure.server, 'server must be initialized');
|
||||
await updateConversationsWithUuidLookup({
|
||||
conversationController: window.ConversationController,
|
||||
conversations: lonelyE164Conversations,
|
||||
messaging: window.textsecure.messaging,
|
||||
server: window.textsecure.server,
|
||||
});
|
||||
} catch (error) {
|
||||
log.error(
|
||||
'connect: Error fetching UUIDs for lonely e164s:',
|
||||
error && error.stack ? error.stack : error
|
||||
Errors.toLogFormat(error)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1033,8 +1033,8 @@ export class ConversationModel extends window.Backbone
|
|||
}
|
||||
|
||||
async fetchSMSOnlyUUID(): Promise<void> {
|
||||
const { messaging } = window.textsecure;
|
||||
if (!messaging) {
|
||||
const { server } = window.textsecure;
|
||||
if (!server) {
|
||||
return;
|
||||
}
|
||||
if (!this.isSMSOnly()) {
|
||||
|
@ -1053,7 +1053,7 @@ export class ConversationModel extends window.Backbone
|
|||
await updateConversationsWithUuidLookup({
|
||||
conversationController: window.ConversationController,
|
||||
conversations: [this],
|
||||
messaging,
|
||||
server,
|
||||
});
|
||||
} finally {
|
||||
// No redux update here
|
||||
|
|
|
@ -837,10 +837,6 @@ async function removeAllSignedPreKeys(): Promise<void> {
|
|||
// Items
|
||||
|
||||
const ITEM_SPECS: Partial<Record<ItemKeyType, ObjectMappingSpecType>> = {
|
||||
senderCertificate: ['value.serialized'],
|
||||
senderCertificateNoE164: ['value.serialized'],
|
||||
subscriberId: ['value'],
|
||||
profileKey: ['value'],
|
||||
identityKeyMap: {
|
||||
key: 'value',
|
||||
valueSpec: {
|
||||
|
@ -848,6 +844,10 @@ const ITEM_SPECS: Partial<Record<ItemKeyType, ObjectMappingSpecType>> = {
|
|||
valueSpec: ['privKey', 'pubKey'],
|
||||
},
|
||||
},
|
||||
profileKey: ['value'],
|
||||
senderCertificate: ['value.serialized'],
|
||||
senderCertificateNoE164: ['value.serialized'],
|
||||
subscriberId: ['value'],
|
||||
};
|
||||
async function createOrUpdateItem<K extends ItemKeyType>(
|
||||
data: ItemType<K>
|
||||
|
|
|
@ -8,6 +8,7 @@ import * as log from '../../logging/log';
|
|||
|
||||
import type { StateType as RootStateType } from '../reducer';
|
||||
import type { UUIDStringType } from '../../types/UUID';
|
||||
import { getUuidsForE164s } from '../../util/getUuidsForE164s';
|
||||
|
||||
import type { NoopActionType } from './noop';
|
||||
|
||||
|
@ -44,7 +45,8 @@ function checkForAccount(
|
|||
AccountUpdateActionType | NoopActionType
|
||||
> {
|
||||
return async (dispatch, getState) => {
|
||||
if (!window.textsecure.messaging) {
|
||||
const { server } = window.textsecure;
|
||||
if (!server) {
|
||||
dispatch({
|
||||
type: 'NOOP',
|
||||
payload: null,
|
||||
|
@ -77,16 +79,24 @@ function checkForAccount(
|
|||
type: 'NOOP',
|
||||
payload: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let uuid: UUIDStringType | undefined;
|
||||
|
||||
log.info(`checkForAccount: looking ${phoneNumber} up on server`);
|
||||
try {
|
||||
const uuidLookup = await window.textsecure.messaging.getUuidsForE164s([
|
||||
phoneNumber,
|
||||
]);
|
||||
uuid = uuidLookup[phoneNumber] || undefined;
|
||||
const uuidLookup = await getUuidsForE164s(server, [phoneNumber]);
|
||||
const maybePair = uuidLookup.get(phoneNumber);
|
||||
|
||||
if (maybePair) {
|
||||
uuid = window.ConversationController.maybeMergeContacts({
|
||||
aci: maybePair.aci,
|
||||
pni: maybePair.pni,
|
||||
e164: phoneNumber,
|
||||
reason: 'checkForAccount',
|
||||
})?.get('uuid');
|
||||
}
|
||||
} catch (error) {
|
||||
log.error('checkForAccount:', Errors.toLogFormat(error));
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import { assert } from 'chai';
|
|||
import sinon from 'sinon';
|
||||
import { ConversationModel } from '../models/conversations';
|
||||
import type { ConversationAttributesType } from '../model-types.d';
|
||||
import type SendMessage from '../textsecure/SendMessage';
|
||||
import type { WebAPIType } from '../textsecure/WebAPI';
|
||||
import { UUID } from '../types/UUID';
|
||||
|
||||
import { updateConversationsWithUuidLookup } from '../updateConversationsWithUuidLookup';
|
||||
|
@ -137,22 +137,19 @@ describe('updateConversationsWithUuidLookup', () => {
|
|||
|
||||
let sinonSandbox: sinon.SinonSandbox;
|
||||
|
||||
let fakeGetUuidsForE164s: sinon.SinonStub;
|
||||
let fakeCdsLookup: sinon.SinonStub;
|
||||
let fakeCheckAccountExistence: sinon.SinonStub;
|
||||
let fakeMessaging: Pick<
|
||||
SendMessage,
|
||||
'getUuidsForE164s' | 'checkAccountExistence'
|
||||
>;
|
||||
let fakeServer: Pick<WebAPIType, 'cdsLookup' | 'checkAccountExistence'>;
|
||||
|
||||
beforeEach(() => {
|
||||
sinonSandbox = sinon.createSandbox();
|
||||
|
||||
sinonSandbox.stub(window.Signal.Data, 'updateConversation');
|
||||
|
||||
fakeGetUuidsForE164s = sinonSandbox.stub().resolves({});
|
||||
fakeCdsLookup = sinonSandbox.stub().resolves(new Map());
|
||||
fakeCheckAccountExistence = sinonSandbox.stub().resolves(false);
|
||||
fakeMessaging = {
|
||||
getUuidsForE164s: fakeGetUuidsForE164s,
|
||||
fakeServer = {
|
||||
cdsLookup: fakeCdsLookup,
|
||||
checkAccountExistence: fakeCheckAccountExistence,
|
||||
};
|
||||
});
|
||||
|
@ -165,10 +162,10 @@ describe('updateConversationsWithUuidLookup', () => {
|
|||
await updateConversationsWithUuidLookup({
|
||||
conversationController: new FakeConversationController(),
|
||||
conversations: [],
|
||||
messaging: fakeMessaging,
|
||||
server: fakeServer,
|
||||
});
|
||||
|
||||
sinon.assert.notCalled(fakeMessaging.getUuidsForE164s as sinon.SinonStub);
|
||||
sinon.assert.notCalled(fakeServer.cdsLookup as sinon.SinonStub);
|
||||
});
|
||||
|
||||
it('does nothing when called with an array of conversations that lack E164s', async () => {
|
||||
|
@ -178,10 +175,10 @@ describe('updateConversationsWithUuidLookup', () => {
|
|||
createConversation(),
|
||||
createConversation({ uuid: UUID.generate().toString() }),
|
||||
],
|
||||
messaging: fakeMessaging,
|
||||
server: fakeServer,
|
||||
});
|
||||
|
||||
sinon.assert.notCalled(fakeMessaging.getUuidsForE164s as sinon.SinonStub);
|
||||
sinon.assert.notCalled(fakeServer.cdsLookup as sinon.SinonStub);
|
||||
});
|
||||
|
||||
it('updates conversations with their UUID', async () => {
|
||||
|
@ -194,10 +191,12 @@ describe('updateConversationsWithUuidLookup', () => {
|
|||
const uuid1 = UUID.generate().toString();
|
||||
const uuid2 = UUID.generate().toString();
|
||||
|
||||
fakeGetUuidsForE164s.resolves({
|
||||
'+13215559876': uuid1,
|
||||
'+16545559876': uuid2,
|
||||
});
|
||||
fakeCdsLookup.resolves(
|
||||
new Map([
|
||||
['+13215559876', { aci: uuid1, pni: undefined }],
|
||||
['+16545559876', { aci: uuid2, pni: undefined }],
|
||||
])
|
||||
);
|
||||
|
||||
await updateConversationsWithUuidLookup({
|
||||
conversationController: new FakeConversationController([
|
||||
|
@ -205,7 +204,7 @@ describe('updateConversationsWithUuidLookup', () => {
|
|||
conversation2,
|
||||
]),
|
||||
conversations: [conversation1, conversation2],
|
||||
messaging: fakeMessaging,
|
||||
server: fakeServer,
|
||||
});
|
||||
|
||||
assert.strictEqual(conversation1.get('uuid'), uuid1);
|
||||
|
@ -219,12 +218,10 @@ describe('updateConversationsWithUuidLookup', () => {
|
|||
'Test was not set up correctly'
|
||||
);
|
||||
|
||||
fakeGetUuidsForE164s.resolves({ '+13215559876': null });
|
||||
|
||||
await updateConversationsWithUuidLookup({
|
||||
conversationController: new FakeConversationController([conversation]),
|
||||
conversations: [conversation],
|
||||
messaging: fakeMessaging,
|
||||
server: fakeServer,
|
||||
});
|
||||
|
||||
assert.approximately(
|
||||
|
@ -245,13 +242,12 @@ describe('updateConversationsWithUuidLookup', () => {
|
|||
'Test was not set up correctly'
|
||||
);
|
||||
|
||||
fakeGetUuidsForE164s.resolves({ '+13215559876': null });
|
||||
fakeCheckAccountExistence.resolves(true);
|
||||
|
||||
await updateConversationsWithUuidLookup({
|
||||
conversationController: new FakeConversationController([conversation]),
|
||||
conversations: [conversation],
|
||||
messaging: fakeMessaging,
|
||||
server: fakeServer,
|
||||
});
|
||||
|
||||
assert.strictEqual(conversation.get('uuid'), existingUuid);
|
||||
|
@ -269,13 +265,12 @@ describe('updateConversationsWithUuidLookup', () => {
|
|||
'Test was not set up correctly'
|
||||
);
|
||||
|
||||
fakeGetUuidsForE164s.resolves({ '+13215559876': null });
|
||||
fakeCheckAccountExistence.resolves(false);
|
||||
|
||||
await updateConversationsWithUuidLookup({
|
||||
conversationController: new FakeConversationController([conversation]),
|
||||
conversations: [conversation],
|
||||
messaging: fakeMessaging,
|
||||
server: fakeServer,
|
||||
});
|
||||
|
||||
assert.isUndefined(conversation.get('uuid'));
|
||||
|
|
|
@ -671,9 +671,9 @@ export default class OutgoingMessage {
|
|||
if (isValidUuid(identifier)) {
|
||||
// We're good!
|
||||
} else if (isValidNumber(identifier)) {
|
||||
if (!window.textsecure.messaging) {
|
||||
if (!window.textsecure.server) {
|
||||
throw new Error(
|
||||
'sendToIdentifier: window.textsecure.messaging is not available!'
|
||||
'sendToIdentifier: window.textsecure.server is not available!'
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -683,7 +683,7 @@ export default class OutgoingMessage {
|
|||
conversations: [
|
||||
window.ConversationController.getOrCreate(identifier, 'private'),
|
||||
],
|
||||
messaging: window.textsecure.messaging,
|
||||
server: window.textsecure.server,
|
||||
});
|
||||
|
||||
const uuid =
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
/* eslint-disable max-classes-per-file */
|
||||
|
||||
import { z } from 'zod';
|
||||
import type { Dictionary } from 'lodash';
|
||||
import Long from 'long';
|
||||
import PQueue from 'p-queue';
|
||||
import type { PlaintextContent } from '@signalapp/libsignal-client';
|
||||
|
@ -25,7 +24,7 @@ import { SenderKeys } from '../LibSignalStores';
|
|||
import type { LinkPreviewType } from '../types/message/LinkPreviews';
|
||||
import { MIMETypeToString } from '../types/MIME';
|
||||
import type * as Attachment from '../types/Attachment';
|
||||
import type { UUID, UUIDStringType } from '../types/UUID';
|
||||
import type { UUID } from '../types/UUID';
|
||||
import type {
|
||||
ChallengeType,
|
||||
GetGroupLogOptionsType,
|
||||
|
@ -49,7 +48,6 @@ import type {
|
|||
SendLogCallbackType,
|
||||
} from './OutgoingMessage';
|
||||
import OutgoingMessage from './OutgoingMessage';
|
||||
import type { CDSResponseType } from './cds/Types.d';
|
||||
import * as Bytes from '../Bytes';
|
||||
import { getRandomBytes, getZeroes, encryptAttachment } from '../Crypto';
|
||||
import {
|
||||
|
@ -2447,34 +2445,12 @@ export default class MessageSender {
|
|||
return this.server.getProfile(uuid.toString(), options);
|
||||
}
|
||||
|
||||
async checkAccountExistence(uuid: UUID): Promise<boolean> {
|
||||
return this.server.checkAccountExistence(uuid);
|
||||
}
|
||||
|
||||
async getProfileForUsername(
|
||||
username: string
|
||||
): ReturnType<WebAPIType['getProfileForUsername']> {
|
||||
return this.server.getProfileForUsername(username);
|
||||
}
|
||||
|
||||
async getUuidsForE164s(
|
||||
numbers: ReadonlyArray<string>
|
||||
): Promise<Dictionary<UUIDStringType | null>> {
|
||||
return this.server.getUuidsForE164s(numbers);
|
||||
}
|
||||
|
||||
async getUuidsForE164sV2(
|
||||
e164s: ReadonlyArray<string>,
|
||||
acis: ReadonlyArray<UUIDStringType>,
|
||||
accessKeys: ReadonlyArray<string>
|
||||
): Promise<CDSResponseType> {
|
||||
return this.server.getUuidsForE164sV2({
|
||||
e164s,
|
||||
acis,
|
||||
accessKeys,
|
||||
});
|
||||
}
|
||||
|
||||
async getAvatar(path: string): Promise<ReturnType<WebAPIType['getAvatar']>> {
|
||||
return this.server.getAvatar(path);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import type { Response } from 'node-fetch';
|
|||
import fetch from 'node-fetch';
|
||||
import ProxyAgent from 'proxy-agent';
|
||||
import { Agent } from 'https';
|
||||
import type { Dictionary } from 'lodash';
|
||||
import { escapeRegExp, isNumber } from 'lodash';
|
||||
import is from '@sindresorhus/is';
|
||||
import PQueue from 'p-queue';
|
||||
|
@ -767,10 +766,10 @@ export type ConfirmCodeResultType = Readonly<{
|
|||
deviceId?: number;
|
||||
}>;
|
||||
|
||||
export type GetUuidsForE164sV2OptionsType = Readonly<{
|
||||
export type CdsLookupOptionsType = Readonly<{
|
||||
e164s: ReadonlyArray<string>;
|
||||
acis: ReadonlyArray<UUIDStringType>;
|
||||
accessKeys: ReadonlyArray<string>;
|
||||
acis?: ReadonlyArray<UUIDStringType>;
|
||||
accessKeys?: ReadonlyArray<string>;
|
||||
}>;
|
||||
|
||||
type GetProfileCommonOptionsType = Readonly<
|
||||
|
@ -812,6 +811,7 @@ export type GetGroupCredentialsResultType = Readonly<{
|
|||
export type WebAPIType = {
|
||||
startRegistration(): unknown;
|
||||
finishRegistration(baton: unknown): void;
|
||||
cdsLookup: (options: CdsLookupOptionsType) => Promise<CDSResponseType>;
|
||||
confirmCode: (
|
||||
number: string,
|
||||
code: string,
|
||||
|
@ -880,12 +880,6 @@ export type WebAPIType = {
|
|||
getStorageCredentials: MessageSender['getStorageCredentials'];
|
||||
getStorageManifest: MessageSender['getStorageManifest'];
|
||||
getStorageRecords: MessageSender['getStorageRecords'];
|
||||
getUuidsForE164s: (
|
||||
e164s: ReadonlyArray<string>
|
||||
) => Promise<Dictionary<UUIDStringType | null>>;
|
||||
getUuidsForE164sV2: (
|
||||
options: GetUuidsForE164sV2OptionsType
|
||||
) => Promise<CDSResponseType>;
|
||||
fetchLinkPreviewMetadata: (
|
||||
href: string,
|
||||
abortSignal: AbortSignal
|
||||
|
@ -1251,6 +1245,7 @@ export function initialize({
|
|||
unregisterRequestHandler,
|
||||
authenticate,
|
||||
logout,
|
||||
cdsLookup,
|
||||
checkAccountExistence,
|
||||
confirmCode,
|
||||
createGroup,
|
||||
|
@ -1285,8 +1280,6 @@ export function initialize({
|
|||
getStorageCredentials,
|
||||
getStorageManifest,
|
||||
getStorageRecords,
|
||||
getUuidsForE164s,
|
||||
getUuidsForE164sV2,
|
||||
makeProxiedRequest,
|
||||
makeSfuRequest,
|
||||
modifyGroup,
|
||||
|
@ -2858,25 +2851,11 @@ export function initialize({
|
|||
return socketManager.getProvisioningResource(handler);
|
||||
}
|
||||
|
||||
async function getUuidsForE164s(
|
||||
e164s: ReadonlyArray<string>
|
||||
): Promise<Dictionary<UUIDStringType | null>> {
|
||||
const map = await cds.request({
|
||||
e164s,
|
||||
});
|
||||
|
||||
const result: Dictionary<UUIDStringType | null> = {};
|
||||
for (const [key, value] of map) {
|
||||
result[key] = value.pni ?? value.aci ?? null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function getUuidsForE164sV2({
|
||||
async function cdsLookup({
|
||||
e164s,
|
||||
acis,
|
||||
accessKeys,
|
||||
}: GetUuidsForE164sV2OptionsType): Promise<CDSResponseType> {
|
||||
acis = [],
|
||||
accessKeys = [],
|
||||
}: CdsLookupOptionsType): Promise<CDSResponseType> {
|
||||
return cds.request({
|
||||
e164s,
|
||||
acis,
|
||||
|
|
|
@ -85,28 +85,20 @@ export abstract class CDSSocketBase<
|
|||
|
||||
const aciUakPairs = new Array<Uint8Array>();
|
||||
|
||||
let version: 1 | 2;
|
||||
if (acis) {
|
||||
strictAssert(accessKeys, 'accessKeys are required when acis are present');
|
||||
const version = 2;
|
||||
strictAssert(
|
||||
acis.length === accessKeys.length,
|
||||
`Number of ACIs ${acis.length} is different ` +
|
||||
`from number of access keys ${accessKeys.length}`
|
||||
);
|
||||
|
||||
strictAssert(
|
||||
acis.length === accessKeys.length,
|
||||
`Number of ACIs ${acis.length} is different ` +
|
||||
`from number of access keys ${accessKeys.length}`
|
||||
for (let i = 0; i < acis.length; i += 1) {
|
||||
aciUakPairs.push(
|
||||
Bytes.concatenate([
|
||||
uuidToBytes(acis[i]),
|
||||
Bytes.fromBase64(accessKeys[i]),
|
||||
])
|
||||
);
|
||||
|
||||
version = 2;
|
||||
|
||||
for (let i = 0; i < acis.length; i += 1) {
|
||||
aciUakPairs.push(
|
||||
Bytes.concatenate([
|
||||
uuidToBytes(acis[i]),
|
||||
Bytes.fromBase64(accessKeys[i]),
|
||||
])
|
||||
);
|
||||
}
|
||||
} else {
|
||||
version = 1;
|
||||
}
|
||||
|
||||
const request = Proto.CDSClientRequest.encode({
|
||||
|
|
|
@ -17,7 +17,6 @@ import {
|
|||
} from '../../Crypto';
|
||||
import { calculateAgreement, generateKeyPair } from '../../Curve';
|
||||
import * as Bytes from '../../Bytes';
|
||||
import { strictAssert } from '../../util/assert';
|
||||
import { UUID } from '../../types/UUID';
|
||||
import type { CDSBaseOptionsType } from './CDSBase';
|
||||
import { CDSBase } from './CDSBase';
|
||||
|
@ -125,11 +124,7 @@ function getSgxConstants() {
|
|||
export class LegacyCDS extends CDSBase<LegacyCDSOptionsType> {
|
||||
public override async request({
|
||||
e164s,
|
||||
acis,
|
||||
accessKeys,
|
||||
}: CDSRequestOptionsType): Promise<CDSResponseType> {
|
||||
strictAssert(!acis && !accessKeys, 'LegacyCDS does not support PNP');
|
||||
|
||||
const directoryAuth = await this.getAuth();
|
||||
const attestationResult = await this.putAttestation(directoryAuth);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ export type CDSResponseType = ReadonlyMap<string, CDSResponseEntryType>;
|
|||
|
||||
export type CDSRequestOptionsType = Readonly<{
|
||||
e164s: ReadonlyArray<string>;
|
||||
acis?: ReadonlyArray<UUIDStringType>;
|
||||
accessKeys?: ReadonlyArray<string>;
|
||||
acis: ReadonlyArray<UUIDStringType>;
|
||||
accessKeys: ReadonlyArray<string>;
|
||||
timeout?: number;
|
||||
}>;
|
||||
|
|
|
@ -3,22 +3,22 @@
|
|||
|
||||
import type { ConversationController } from './ConversationController';
|
||||
import type { ConversationModel } from './models/conversations';
|
||||
import type SendMessage from './textsecure/SendMessage';
|
||||
import type { WebAPIType } from './textsecure/WebAPI';
|
||||
import { assert } from './util/assert';
|
||||
import { getOwn } from './util/getOwn';
|
||||
import { isNotNil } from './util/isNotNil';
|
||||
import { getUuidsForE164s } from './util/getUuidsForE164s';
|
||||
|
||||
export async function updateConversationsWithUuidLookup({
|
||||
conversationController,
|
||||
conversations,
|
||||
messaging,
|
||||
server,
|
||||
}: Readonly<{
|
||||
conversationController: Pick<
|
||||
ConversationController,
|
||||
'maybeMergeContacts' | 'get'
|
||||
>;
|
||||
conversations: ReadonlyArray<ConversationModel>;
|
||||
messaging: Pick<SendMessage, 'getUuidsForE164s' | 'checkAccountExistence'>;
|
||||
server: Pick<WebAPIType, 'cdsLookup' | 'checkAccountExistence'>;
|
||||
}>): Promise<void> {
|
||||
const e164s = conversations
|
||||
.map(conversation => conversation.get('e164'))
|
||||
|
@ -27,7 +27,7 @@ export async function updateConversationsWithUuidLookup({
|
|||
return;
|
||||
}
|
||||
|
||||
const serverLookup = await messaging.getUuidsForE164s(e164s);
|
||||
const serverLookup = await getUuidsForE164s(server, e164s);
|
||||
|
||||
await Promise.all(
|
||||
conversations.map(async conversation => {
|
||||
|
@ -38,11 +38,12 @@ export async function updateConversationsWithUuidLookup({
|
|||
|
||||
let finalConversation: ConversationModel;
|
||||
|
||||
const uuidFromServer = getOwn(serverLookup, e164);
|
||||
if (uuidFromServer) {
|
||||
const pairFromServer = serverLookup.get(e164);
|
||||
if (pairFromServer) {
|
||||
const maybeFinalConversation =
|
||||
conversationController.maybeMergeContacts({
|
||||
aci: uuidFromServer,
|
||||
aci: pairFromServer.aci,
|
||||
pni: pairFromServer.pni,
|
||||
e164,
|
||||
reason: 'updateConversationsWithUuidLookup',
|
||||
});
|
||||
|
@ -59,10 +60,8 @@ export async function updateConversationsWithUuidLookup({
|
|||
// they can't be looked up by a phone number. Check that uuid still exists,
|
||||
// and if not - drop it.
|
||||
let finalUuid = finalConversation.getUuid();
|
||||
if (!uuidFromServer && finalUuid) {
|
||||
const doesAccountExist = await messaging.checkAccountExistence(
|
||||
finalUuid
|
||||
);
|
||||
if (!pairFromServer && finalUuid) {
|
||||
const doesAccountExist = await server.checkAccountExistence(finalUuid);
|
||||
if (!doesAccountExist) {
|
||||
finalConversation.updateUuid(undefined);
|
||||
finalUuid = undefined;
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2022 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
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 { isDirectConversation, isMe } from './whatTypeOfConversation';
|
||||
|
||||
export async function getUuidsForE164s(
|
||||
server: Pick<WebAPIType, 'cdsLookup'>,
|
||||
e164s: ReadonlyArray<string>
|
||||
): Promise<CDSResponseType> {
|
||||
// Note: these have no relationship to supplied e164s. We just provide
|
||||
// all available information to the server so that it could return as many
|
||||
// ACI+PNI+E164 matches as possible.
|
||||
const acis = new Array<UUIDStringType>();
|
||||
const accessKeys = new Array<string>();
|
||||
|
||||
for (const convo of window.ConversationController.getAll()) {
|
||||
if (!isDirectConversation(convo.attributes) || isMe(convo.attributes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const aci = convo.getUuid();
|
||||
if (!aci) {
|
||||
continue;
|
||||
}
|
||||
|
||||
convo.deriveAccessKeyIfNeeded();
|
||||
const accessKey = convo.get('accessKey');
|
||||
if (!accessKey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
acis.push(aci.toString());
|
||||
accessKeys.push(accessKey);
|
||||
}
|
||||
|
||||
log.info(
|
||||
`getUuidsForE164s(${e164s}): acis=${acis.length} ` +
|
||||
`accessKeys=${accessKeys.length}`
|
||||
);
|
||||
return server.cdsLookup({ e164s, acis, accessKeys });
|
||||
}
|
|
@ -12,6 +12,7 @@ import { downloadAttachment } from './downloadAttachment';
|
|||
import { generateSecurityNumber } from './safetyNumber';
|
||||
import { getStringForProfileChange } from './getStringForProfileChange';
|
||||
import { getTextWithMentions } from './getTextWithMentions';
|
||||
import { getUuidsForE164s } from './getUuidsForE164s';
|
||||
import { getUserAgent } from './getUserAgent';
|
||||
import { hasExpired } from './hasExpired';
|
||||
import {
|
||||
|
@ -81,4 +82,5 @@ export {
|
|||
toWebSafeBase64,
|
||||
zkgroup,
|
||||
expirationTimer,
|
||||
getUuidsForE164s,
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@ import { HTTPError } from '../textsecure/Errors';
|
|||
import { showToast } from './showToast';
|
||||
import { strictAssert } from './assert';
|
||||
import type { UUIDFetchStateKeyType } from './uuidFetchState';
|
||||
import { getUuidsForE164s } from './getUuidsForE164s';
|
||||
|
||||
export type LookupConversationWithoutUuidActionsType = Readonly<{
|
||||
lookupConversationWithoutUuid: typeof lookupConversationWithoutUuid;
|
||||
|
@ -62,19 +63,22 @@ export async function lookupConversationWithoutUuid(
|
|||
const { showUserNotFoundModal, setIsFetchingUUID } = options;
|
||||
setIsFetchingUUID(identifier, true);
|
||||
|
||||
const { messaging } = window.textsecure;
|
||||
if (!messaging) {
|
||||
throw new Error('messaging is not available!');
|
||||
const { server } = window.textsecure;
|
||||
if (!server) {
|
||||
throw new Error('server is not available!');
|
||||
}
|
||||
|
||||
try {
|
||||
let conversationId: string | undefined;
|
||||
if (options.type === 'e164') {
|
||||
const serverLookup = await messaging.getUuidsForE164s([options.e164]);
|
||||
const serverLookup = await getUuidsForE164s(server, [options.e164]);
|
||||
|
||||
if (serverLookup[options.e164]) {
|
||||
const maybePair = serverLookup.get(options.e164);
|
||||
|
||||
if (maybePair) {
|
||||
const convo = window.ConversationController.maybeMergeContacts({
|
||||
aci: serverLookup[options.e164] || undefined,
|
||||
aci: maybePair.aci,
|
||||
pni: maybePair.pni,
|
||||
e164: options.e164,
|
||||
reason: 'startNewConversationWithoutUuid(e164)',
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue