@signalapp/mock-server
Version:
Mock Signal Server for writing tests
181 lines (180 loc) • 6.13 kB
JavaScript
"use strict";
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Device = void 0;
const debug_1 = __importDefault(require("debug"));
const libsignal_client_1 = require("@signalapp/libsignal-client");
const zkgroup_1 = require("@signalapp/libsignal-client/zkgroup");
const types_1 = require("../types");
const debug = (0, debug_1.default)('mock:device');
// Technically, it is infinite.
const PRE_KEY_ITERATOR_COUNT = 100;
class Device {
aci;
deviceId;
address;
capabilities;
backupLevel = zkgroup_1.BackupLevel.Paid;
accessKey;
profileKeyCommitment;
profileName;
keys = new Map();
privPni;
privNumber;
privPniAddress;
registrationId;
pniRegistrationId;
constructor(options) {
this.aci = options.aci;
this.deviceId = options.deviceId;
this.registrationId = options.registrationId;
this.privPni = options.pni;
this.privNumber = options.number;
this.pniRegistrationId = options.pniRegistrationId;
this.address = libsignal_client_1.ProtocolAddress.new(this.aci, this.deviceId);
this.privPniAddress = libsignal_client_1.ProtocolAddress.new(this.pni, this.deviceId);
this.capabilities = {
deleteSync: true,
versionedExpirationTimer: true,
ssre2: true,
};
}
get debugId() {
return `${this.aci}.${this.deviceId}`;
}
getRegistrationId(serviceIdKind) {
switch (serviceIdKind) {
case types_1.ServiceIdKind.ACI:
return this.registrationId;
case types_1.ServiceIdKind.PNI:
return this.pniRegistrationId;
}
}
get pni() {
return this.privPni;
}
get number() {
return this.privNumber;
}
get pniAddress() {
return this.privPniAddress;
}
async changeNumber({ number, pni, pniRegistrationId, }) {
this.privNumber = number;
this.privPni = pni;
this.pniRegistrationId = pniRegistrationId;
this.privPniAddress = libsignal_client_1.ProtocolAddress.new(this.pni, this.deviceId);
}
async setKeys(serviceIdKind, keys) {
debug('setting %s keys for %s', serviceIdKind, this.debugId);
const existingKeys = this.keys.get(serviceIdKind);
const { signedPreKey = existingKeys?.signedPreKey, lastResortKey = existingKeys?.lastResortKey, } = keys;
if (!signedPreKey) {
throw new Error('setKeys: Missing signedPreKey');
}
if (!lastResortKey) {
throw new Error('setKeys: Missing lastResortKey');
}
this.keys.set(serviceIdKind, {
identityKey: keys.identityKey,
signedPreKey,
preKeys: keys.preKeys?.slice() ?? [],
kyberPreKeys: keys.kyberPreKeys?.slice() ?? [],
lastResortKey,
preKeyIterator: keys.preKeyIterator,
kyberPreKeyIterator: keys.kyberPreKeyIterator,
});
}
async getIdentityKey(serviceIdKind = types_1.ServiceIdKind.ACI) {
const keys = this.keys.get(serviceIdKind);
if (!keys) {
throw new Error('No keys available for device');
}
return keys.identityKey;
}
async popSingleUseKey(serviceIdKind = types_1.ServiceIdKind.ACI) {
const keys = this.keys.get(serviceIdKind);
if (!keys) {
throw new Error('No keys available for device');
}
debug('popping single use key for %s', this.debugId);
let preKey;
if (keys.preKeyIterator) {
const { value } = await keys.preKeyIterator.next();
preKey = value;
}
if (!preKey) {
preKey = keys.preKeys.shift();
}
let pqPreKey;
if (keys.kyberPreKeyIterator) {
const { value } = await keys.kyberPreKeyIterator.next();
pqPreKey = value;
}
if (!pqPreKey) {
pqPreKey = keys.kyberPreKeys.shift();
}
if (!pqPreKey) {
pqPreKey = keys.lastResortKey;
}
if (!pqPreKey) {
throw new Error('popSingleUseKey: Missing pqPreKey; checked iterator/array/lastResort');
}
return {
identityKey: keys.identityKey,
signedPreKey: keys.signedPreKey,
preKey,
pqPreKey,
};
}
async getPreKeyCount(serviceIdKind = types_1.ServiceIdKind.ACI) {
const keys = this.keys.get(serviceIdKind);
if (!keys) {
throw new Error('No keys available for device');
}
if (keys.preKeyIterator) {
return PRE_KEY_ITERATOR_COUNT;
}
return keys.preKeys.length;
}
async getKyberPreKeyCount(serviceIdKind = types_1.ServiceIdKind.ACI) {
const keys = this.keys.get(serviceIdKind);
if (!keys) {
throw new Error('No keys available for device');
}
if (keys.kyberPreKeyIterator) {
return PRE_KEY_ITERATOR_COUNT;
}
return keys.kyberPreKeys.length;
}
getServiceIdByKind(serviceIdKind) {
switch (serviceIdKind) {
case types_1.ServiceIdKind.ACI:
return this.aci;
case types_1.ServiceIdKind.PNI:
return this.pni;
}
}
getServiceIdKind(serviceId) {
if (serviceId === this.aci) {
return types_1.ServiceIdKind.ACI;
}
if (serviceId === this.pni) {
return types_1.ServiceIdKind.PNI;
}
throw new Error(`Unknown serviceId: ${serviceId}`);
}
getAddressByKind(serviceIdKind) {
switch (serviceIdKind) {
case types_1.ServiceIdKind.ACI:
return this.address;
case types_1.ServiceIdKind.PNI:
return this.pniAddress;
}
}
}
exports.Device = Device;