@signalapp/mock-server
Version:
Mock Signal Server for writing tests
120 lines (119 loc) • 4.72 kB
JavaScript
;
// 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.Group = void 0;
const assert_1 = __importDefault(require("assert"));
const zkgroup_1 = require("@signalapp/libsignal-client/zkgroup");
const libsignal_client_1 = require("@signalapp/libsignal-client");
const compiled_1 = require("../../protos/compiled");
const group_1 = require("../data/group");
const AccessRequired = compiled_1.signalservice.AccessControl.AccessRequired;
function encryptBlob(cipher, proto) {
const plaintext = compiled_1.signalservice.GroupAttributeBlob.encode(proto);
return Buffer.from(cipher.encryptBlob(plaintext));
}
function decryptBlob(cipher, ciphertext) {
const plaintext = cipher.decryptBlob(Buffer.from(ciphertext));
return compiled_1.signalservice.GroupAttributeBlob.decode(plaintext);
}
class Group extends group_1.Group {
secretParams;
title;
constructor({ secretParams, groupState }) {
super();
assert_1.default.ok(groupState.title, 'Group must have a title blob');
this.secretParams = secretParams;
const cipher = new zkgroup_1.ClientZkGroupCipher(secretParams);
const decrypted = decryptBlob(cipher, groupState.title);
(0, assert_1.default)(decrypted.content?.title != null, 'expected title');
this.title = decrypted.content.title;
this.privPublicParams = this.secretParams.getPublicParams();
// Build group log
this.privChanges = {
groupChanges: [
{
groupState,
groupChange: null,
},
],
groupSendEndorsementsResponse: null,
};
}
static fromConfig({ secretParams, title, members, }) {
const cipher = new zkgroup_1.ClientZkGroupCipher(secretParams);
const groupState = {
publicKey: secretParams.getPublicParams().serialize(),
version: 0,
title: encryptBlob(cipher, { content: { title } }),
// TODO(indutny): make it configurable
accessControl: {
attributes: AccessRequired.MEMBER,
members: AccessRequired.MEMBER,
addFromInviteLink: AccessRequired.UNSATISFIABLE,
memberLabel: AccessRequired.MEMBER,
},
members: members.map(({ presentation }) => {
return {
role: compiled_1.signalservice.Member.Role.ADMINISTRATOR,
presentation: presentation.serialize(),
userId: null,
profileKey: null,
joinedAtVersion: null,
labelEmoji: null,
labelString: null,
};
}),
avatarUrl: null,
disappearingMessagesTimer: null,
membersPendingProfileKey: null,
membersPendingAdminApproval: null,
inviteLinkPassword: null,
description: null,
announcementsOnly: null,
membersBanned: null,
terminated: null,
};
return new Group({
secretParams,
groupState,
});
}
get masterKey() {
return Buffer.from(this.secretParams.getMasterKey().serialize());
}
toContext() {
const masterKey = this.masterKey;
return {
masterKey,
revision: this.revision,
groupChange: null,
};
}
encryptServiceId(serviceId) {
const cipher = new zkgroup_1.ClientZkGroupCipher(this.secretParams);
return Buffer.from(cipher
.encryptServiceId(libsignal_client_1.ServiceId.parseFromServiceIdString(serviceId))
.serialize());
}
decryptServiceId(ciphertext) {
const cipher = new zkgroup_1.ClientZkGroupCipher(this.secretParams);
const uuidCiphertext = new zkgroup_1.UuidCiphertext(Buffer.from(ciphertext));
return cipher
.decryptServiceId(uuidCiphertext)
.getServiceIdString();
}
getMemberByServiceId(serviceId) {
return this.getMember(new zkgroup_1.UuidCiphertext(this.encryptServiceId(serviceId)));
}
getPendingMemberByServiceId(serviceId) {
return this.getPendingMember(new zkgroup_1.UuidCiphertext(this.encryptServiceId(serviceId)));
}
encryptBlob(proto) {
return encryptBlob(new zkgroup_1.ClientZkGroupCipher(this.secretParams), proto);
}
}
exports.Group = Group;