Send alternate numbers to CDSI
Co-authored-by: yash-signal <yash@signal.org>
This commit is contained in:
parent
cbeb51a68b
commit
8edb054874
7 changed files with 116 additions and 28 deletions
8
package-lock.json
generated
8
package-lock.json
generated
|
@ -49,7 +49,7 @@
|
|||
"form-data": "4.0.1",
|
||||
"fs-extra": "11.2.0",
|
||||
"fuse.js": "6.5.3",
|
||||
"google-libphonenumber": "3.2.38",
|
||||
"google-libphonenumber": "^3.2.39",
|
||||
"got": "11.8.5",
|
||||
"heic-convert": "2.1.0",
|
||||
"humanize-duration": "3.27.1",
|
||||
|
@ -17417,9 +17417,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/google-libphonenumber": {
|
||||
"version": "3.2.38",
|
||||
"resolved": "https://registry.npmjs.org/google-libphonenumber/-/google-libphonenumber-3.2.38.tgz",
|
||||
"integrity": "sha512-t/K0dsVmA0gMMVLJgcMeB9g1Ar4ANVWfkY+AJGSdfyJ2Ay7Bu8ceLYpUlC6FZSilZgaF1qbkM9tZydGBEBHqAg==",
|
||||
"version": "3.2.39",
|
||||
"resolved": "https://registry.npmjs.org/google-libphonenumber/-/google-libphonenumber-3.2.39.tgz",
|
||||
"integrity": "sha512-dpCbkY6ZxHXIHEFDwSir/gPBWkn22e2EixBv47guVs/NE8+qd35f1yu+fxQ8awRnHEXC60uhcPM9mbqmrD6nmw==",
|
||||
"license": "(MIT AND Apache-2.0)",
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
|
|
|
@ -133,7 +133,7 @@
|
|||
"form-data": "4.0.1",
|
||||
"fs-extra": "11.2.0",
|
||||
"fuse.js": "6.5.3",
|
||||
"google-libphonenumber": "3.2.38",
|
||||
"google-libphonenumber": "3.2.39",
|
||||
"got": "11.8.5",
|
||||
"heic-convert": "2.1.0",
|
||||
"humanize-duration": "3.27.1",
|
||||
|
|
|
@ -1402,15 +1402,15 @@ export class ConversationController {
|
|||
async _forgetE164(e164: string): Promise<void> {
|
||||
const { server } = window.textsecure;
|
||||
strictAssert(server, 'Server must be initialized');
|
||||
const { entries: serviceIdMap } = await getServiceIdsForE164s(server, [
|
||||
e164,
|
||||
]);
|
||||
const { entries: serviceIdMap, transformedE164s } =
|
||||
await getServiceIdsForE164s(server, [e164]);
|
||||
|
||||
const pni = serviceIdMap.get(e164)?.pni;
|
||||
const e164ToUse = transformedE164s.get(e164) ?? e164;
|
||||
const pni = serviceIdMap.get(e164ToUse)?.pni;
|
||||
|
||||
log.info(`ConversationController: forgetting e164=${e164} pni=${pni}`);
|
||||
log.info(`ConversationController: forgetting e164=${e164ToUse} pni=${pni}`);
|
||||
|
||||
const convos = [this.get(e164), this.get(pni)];
|
||||
const convos = [this.get(e164ToUse), this.get(pni)];
|
||||
|
||||
for (const convo of convos) {
|
||||
if (!convo) {
|
||||
|
|
|
@ -93,17 +93,17 @@ function checkForAccount(
|
|||
|
||||
log.info(`checkForAccount: looking ${phoneNumber} up on server`);
|
||||
try {
|
||||
const { entries: serviceIdLookup } = await getServiceIdsForE164s(server, [
|
||||
phoneNumber,
|
||||
]);
|
||||
const maybePair = serviceIdLookup.get(phoneNumber);
|
||||
const { entries: serviceIdLookup, transformedE164s } =
|
||||
await getServiceIdsForE164s(server, [phoneNumber]);
|
||||
const phoneNumberToUse = transformedE164s.get(phoneNumber) ?? phoneNumber;
|
||||
const maybePair = serviceIdLookup.get(phoneNumberToUse);
|
||||
|
||||
if (maybePair) {
|
||||
const { conversation: maybeMerged } =
|
||||
window.ConversationController.maybeMergeContacts({
|
||||
aci: maybePair.aci,
|
||||
pni: maybePair.pni,
|
||||
e164: phoneNumber,
|
||||
e164: phoneNumberToUse,
|
||||
reason: 'checkForAccount',
|
||||
});
|
||||
serviceId = maybeMerged.getServiceId();
|
||||
|
|
|
@ -27,7 +27,8 @@ export async function updateConversationsWithUuidLookup({
|
|||
return;
|
||||
}
|
||||
|
||||
const { entries: serverLookup } = await getServiceIdsForE164s(server, e164s);
|
||||
const { entries: serverLookup, transformedE164s } =
|
||||
await getServiceIdsForE164s(server, e164s);
|
||||
|
||||
await Promise.all(
|
||||
conversations.map(async conversation => {
|
||||
|
@ -38,13 +39,14 @@ export async function updateConversationsWithUuidLookup({
|
|||
|
||||
let finalConversation: ConversationModel;
|
||||
|
||||
const pairFromServer = serverLookup.get(e164);
|
||||
const e164ToUse = transformedE164s.get(e164) ?? e164;
|
||||
const pairFromServer = serverLookup.get(e164ToUse);
|
||||
if (pairFromServer) {
|
||||
const { conversation: maybeFinalConversation } =
|
||||
conversationController.maybeMergeContacts({
|
||||
aci: pairFromServer.aci,
|
||||
pni: pairFromServer.pni,
|
||||
e164,
|
||||
e164: e164ToUse,
|
||||
reason: 'updateConversationsWithUuidLookup',
|
||||
});
|
||||
assertDev(
|
||||
|
|
|
@ -6,11 +6,73 @@ import type { WebAPIType } from '../textsecure/WebAPI';
|
|||
import type { AciString } from '../types/ServiceId';
|
||||
import * as log from '../logging/log';
|
||||
import { isDirectConversation, isMe } from './whatTypeOfConversation';
|
||||
import { parseNumber } from './libphonenumberUtil';
|
||||
|
||||
type PhoneNumberTransformation = {
|
||||
oldPattern: RegExp;
|
||||
newPattern: RegExp;
|
||||
oldToNew: (e164: string) => string;
|
||||
newToOld: (e164: string) => string;
|
||||
};
|
||||
|
||||
const PHONE_TRANSFORMATIONS: Record<string, PhoneNumberTransformation> = {
|
||||
'229': {
|
||||
// Benin
|
||||
oldPattern: /^\+229\d{8}$/,
|
||||
newPattern: /^\+22901\d{8}$/,
|
||||
oldToNew: (e164: string) => e164.replace(/^\+229(\d{8})$/, '+22901$1'),
|
||||
newToOld: (e164: string) => e164.replace(/^\+22901(\d{8})$/, '+229$1'),
|
||||
},
|
||||
'52': {
|
||||
// Mexico
|
||||
oldPattern: /^\+521\d{10}$/,
|
||||
newPattern: /^\+52\d{10}$/,
|
||||
oldToNew: (e164: string) => e164.replace(/^\+521(\d{10})$/, '+52$1'),
|
||||
newToOld: (e164: string) => e164.replace(/^\+52(\d{10})$/, '+521$1'),
|
||||
},
|
||||
'54': {
|
||||
// Argentina
|
||||
oldPattern: /^\+54\d{10}$/,
|
||||
newPattern: /^\+549\d{10}$/,
|
||||
oldToNew: (e164: string) => e164.replace(/^\+54(\d{10})$/, '+549$1'),
|
||||
newToOld: (e164: string) => e164.replace(/^\+549(\d{10})$/, '+54$1'),
|
||||
},
|
||||
};
|
||||
|
||||
type ReturnType = CDSResponseType & {
|
||||
// Maps from provided E164 phone numbers to their alternate representations
|
||||
// found in CDSI. If a E164 appears as a key in this map, you should use the
|
||||
// corresponding E164 value for any subsequent operations, as that's
|
||||
// the format stored in CDSI's database.
|
||||
transformedE164s: Map<string, string>;
|
||||
};
|
||||
|
||||
export async function getServiceIdsForE164s(
|
||||
server: Pick<WebAPIType, 'cdsLookup'>,
|
||||
e164s: ReadonlyArray<string>
|
||||
): Promise<CDSResponseType> {
|
||||
): Promise<ReturnType> {
|
||||
const expandedE164s = new Set(e164s);
|
||||
|
||||
const transformationMap = new Map<string, string>();
|
||||
|
||||
for (const e164 of e164s) {
|
||||
const parsedNumber = parseNumber(e164);
|
||||
|
||||
if (parsedNumber.isValidNumber && parsedNumber.countryCode) {
|
||||
const transform = PHONE_TRANSFORMATIONS[parsedNumber.countryCode];
|
||||
if (transform) {
|
||||
if (transform.oldPattern.test(e164)) {
|
||||
const newFormat = transform.oldToNew(e164);
|
||||
expandedE164s.add(newFormat);
|
||||
transformationMap.set(e164, newFormat);
|
||||
} else if (transform.newPattern.test(e164)) {
|
||||
const oldFormat = transform.newToOld(e164);
|
||||
expandedE164s.add(oldFormat);
|
||||
transformationMap.set(e164, oldFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
|
@ -35,16 +97,40 @@ export async function getServiceIdsForE164s(
|
|||
acisAndAccessKeys.push({ aci, accessKey });
|
||||
}
|
||||
|
||||
const expandedE164sArray = Array.from(expandedE164s);
|
||||
|
||||
log.info(
|
||||
`getServiceIdsForE164s(${e164s}): acis=${acisAndAccessKeys.length} ` +
|
||||
`getServiceIdsForE164s(${expandedE164sArray}): acis=${acisAndAccessKeys.length} ` +
|
||||
`accessKeys=${acisAndAccessKeys.length}`
|
||||
);
|
||||
return server.cdsLookup({
|
||||
e164s,
|
||||
const response = await server.cdsLookup({
|
||||
e164s: expandedE164sArray,
|
||||
acisAndAccessKeys,
|
||||
returnAcisWithoutUaks: false,
|
||||
useLibsignal: window.Signal.RemoteConfig.isEnabled(
|
||||
'desktop.cdsiViaLibsignal'
|
||||
),
|
||||
});
|
||||
|
||||
const e164sWithVariantsInCdsi = new Map(
|
||||
Array.from(transformationMap).filter(([providedE164, alternateE164]) => {
|
||||
if (
|
||||
response.entries.has(providedE164) &&
|
||||
response.entries.has(alternateE164)
|
||||
) {
|
||||
log.warn(`both ${providedE164} and ${alternateE164} are in CDSI`);
|
||||
return false;
|
||||
}
|
||||
if (response.entries.has(alternateE164)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
...response,
|
||||
transformedE164s: e164sWithVariantsInCdsi,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -71,18 +71,18 @@ export async function lookupConversationWithoutServiceId(
|
|||
try {
|
||||
let conversationId: string | undefined;
|
||||
if (options.type === 'e164') {
|
||||
const { entries: serverLookup } = await getServiceIdsForE164s(server, [
|
||||
options.e164,
|
||||
]);
|
||||
const { entries: serverLookup, transformedE164s } =
|
||||
await getServiceIdsForE164s(server, [options.e164]);
|
||||
const e164ToUse = transformedE164s.get(options.e164) ?? options.e164;
|
||||
|
||||
const maybePair = serverLookup.get(options.e164);
|
||||
const maybePair = serverLookup.get(e164ToUse);
|
||||
|
||||
if (maybePair) {
|
||||
const { conversation } =
|
||||
window.ConversationController.maybeMergeContacts({
|
||||
aci: maybePair.aci,
|
||||
pni: maybePair.pni,
|
||||
e164: options.e164,
|
||||
e164: e164ToUse,
|
||||
reason: 'startNewConversationWithoutUuid(e164)',
|
||||
});
|
||||
conversationId = conversation?.id;
|
||||
|
|
Loading…
Reference in a new issue