2020-10-30 15:34:04 -05:00
|
|
|
// Copyright 2020 Signal Messenger, LLC
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
2022-03-24 14:47:21 -07:00
|
|
|
import { PublicKey, Fingerprint } from '@signalapp/libsignal-client';
|
2025-09-16 17:39:03 -07:00
|
|
|
import type { ConversationType } from '../state/ducks/conversations.js';
|
2020-06-25 20:08:58 -04:00
|
|
|
|
2025-09-16 17:39:03 -07:00
|
|
|
import { assertDev } from './assert.js';
|
|
|
|
import { uuidToBytes } from './uuidToBytes.js';
|
|
|
|
import { createLogger } from '../logging/log.js';
|
|
|
|
import type { SafetyNumberType } from '../types/safetyNumber.js';
|
|
|
|
import { isAciString } from './isAciString.js';
|
2021-06-14 17:09:37 -07:00
|
|
|
|
2025-06-16 11:59:31 -07:00
|
|
|
const log = createLogger('safetyNumber');
|
|
|
|
|
2023-07-13 21:06:42 +02:00
|
|
|
const ITERATION_COUNT = 5200;
|
2023-08-16 22:54:39 +02:00
|
|
|
const SERVICE_ID_VERSION = 2;
|
2023-04-07 10:46:00 -07:00
|
|
|
|
2023-07-13 21:06:42 +02:00
|
|
|
// Number of digits in a safety number block
|
|
|
|
const BLOCK_SIZE = 5;
|
2020-06-25 20:08:58 -04:00
|
|
|
|
2023-11-01 23:55:30 +01:00
|
|
|
export async function generateSafetyNumber(
|
2023-11-01 21:35:55 +01:00
|
|
|
contact: ConversationType
|
2023-11-01 23:55:30 +01:00
|
|
|
): Promise<SafetyNumberType> {
|
2023-11-01 21:35:55 +01:00
|
|
|
const logId = `generateSafetyNumbers(${contact.id})`;
|
2023-04-07 10:46:00 -07:00
|
|
|
log.info(`${logId}: starting`);
|
|
|
|
|
2021-09-09 19:38:11 -07:00
|
|
|
const { storage } = window.textsecure;
|
2023-08-10 18:43:33 +02:00
|
|
|
const ourAci = storage.user.getCheckedAci();
|
2020-06-25 20:08:58 -04:00
|
|
|
|
2023-07-13 21:06:42 +02:00
|
|
|
const us = storage.protocol.getIdentityRecord(ourAci);
|
|
|
|
const ourKeyBuffer = us ? us.publicKey : null;
|
2020-06-25 20:08:58 -04:00
|
|
|
|
2023-08-30 05:15:28 +02:00
|
|
|
const theirAci = isAciString(contact.serviceId)
|
|
|
|
? contact.serviceId
|
|
|
|
: undefined;
|
2023-07-13 21:06:42 +02:00
|
|
|
const them = theirAci
|
2023-08-10 18:43:33 +02:00
|
|
|
? await storage.protocol.getOrMigrateIdentityRecord(theirAci)
|
2021-09-09 19:38:11 -07:00
|
|
|
: undefined;
|
2023-07-13 21:06:42 +02:00
|
|
|
const theirKeyBuffer = them?.publicKey;
|
2020-06-25 20:08:58 -04:00
|
|
|
|
2023-07-13 21:06:42 +02:00
|
|
|
if (!ourKeyBuffer) {
|
2020-06-25 20:08:58 -04:00
|
|
|
throw new Error('Could not load our key');
|
|
|
|
}
|
|
|
|
|
2023-07-13 21:06:42 +02:00
|
|
|
if (!theirKeyBuffer) {
|
2020-06-25 20:08:58 -04:00
|
|
|
throw new Error('Could not load their key');
|
|
|
|
}
|
|
|
|
|
2025-06-30 11:43:41 -07:00
|
|
|
const ourKey = PublicKey.deserialize(ourKeyBuffer);
|
|
|
|
const theirKey = PublicKey.deserialize(theirKeyBuffer);
|
2023-07-13 21:06:42 +02:00
|
|
|
|
2023-11-01 23:55:30 +01:00
|
|
|
assertDev(theirAci, 'Should have their serviceId');
|
|
|
|
const fingerprint = Fingerprint.new(
|
|
|
|
ITERATION_COUNT,
|
|
|
|
SERVICE_ID_VERSION,
|
2025-06-30 11:43:41 -07:00
|
|
|
uuidToBytes(ourAci),
|
2023-11-01 23:55:30 +01:00
|
|
|
ourKey,
|
2025-06-30 11:43:41 -07:00
|
|
|
uuidToBytes(theirAci),
|
2023-11-01 23:55:30 +01:00
|
|
|
theirKey
|
|
|
|
);
|
|
|
|
|
|
|
|
const securityNumber = fingerprint.displayableFingerprint().toString();
|
|
|
|
|
|
|
|
const numberBlocks = [];
|
|
|
|
for (let i = 0; i < securityNumber.length; i += BLOCK_SIZE) {
|
|
|
|
numberBlocks.push(securityNumber.substring(i, i + BLOCK_SIZE));
|
|
|
|
}
|
|
|
|
|
|
|
|
const qrData = fingerprint.scannableFingerprint().toBuffer();
|
|
|
|
|
|
|
|
return { numberBlocks, qrData };
|
2020-06-25 20:08:58 -04:00
|
|
|
}
|