@signalapp/mock-server
Version:
Mock Signal Server for writing tests
85 lines (84 loc) • 3.28 kB
JavaScript
"use strict";
// Copyright 2026 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
Object.defineProperty(exports, "__esModule", { value: true });
exports.SfuService = void 0;
const call_1 = require("./call");
const calling_1 = require("../calling");
const connection_1 = require("./connection");
const srtp_1 = require("./srtp");
const ice_1 = require("./ice");
const crypto_1 = require("./crypto");
/**
* Selective Forwarding Unit
*/
class SfuService {
#calls = new Map();
#connections = new Map();
async joinCall(request) {
let call = this.#calls.get(request.eraId);
if (call == null) {
call = new call_1.SfuCall({
creatorUserId: request.userId,
roomId: request.roomId,
eraId: request.eraId,
maxClients: 30,
newClientsRequireApproval: request.newClientsRequireApproval,
persistApprovalForAllUsersWhoJoin: true,
approvedUsers: request.approvedUsers,
});
this.#calls.set(call.eraId, call);
}
if (call.hasClient(request.demuxId)) {
throw new calling_1.CallingError(calling_1.CallingErrorCode.DuplicateDemuxIdDetected);
}
const { serverIceUsername, clientIceUsername } = (0, ice_1.getIceUsernames)({
serverIceUsernameFragment: request.serverIceUsernameFragment,
clientIceUsernameFragment: request.clientIceUsernameFragment,
});
const clientStatus = call.addClient({
userId: request.userId,
demuxId: request.demuxId,
isAdmin: request.isAdmin,
});
if (clientStatus === call_1.SfuClientStatus.Rejected) {
throw new calling_1.CallingError(calling_1.CallingErrorCode.TooManyClients);
}
const serverKeys = await crypto_1.CallingKeyPair.generate();
const serverSecret = serverKeys.privateKey;
const serverPublicKey = serverKeys.publicKey;
const sharedSecret = serverSecret.agree(request.clientPublicKey);
const strpKeyMaterial = (0, srtp_1.getStrpKeyMaterial)({
sharedSecret,
clientHkdfExtraInfo: request.clientHkdfExtraInfo,
});
const connectionId = (0, connection_1.getSfuConnectionId)({
eraId: call.eraId,
demuxId: request.demuxId,
});
const connection = new connection_1.SfuConnection({
connectionId,
demuxId: request.demuxId,
serverIceUsername,
clientIceUsername,
serverIcePassword: request.serverIcePassword,
clientIcePassword: request.clientIcePassword,
strpKeyMaterial,
});
this.#connections.set(connectionId, connection);
return {
serverPublicKey,
clientStatus,
};
}
async peekCall(request) {
const call = this.#calls.get(request.eraId);
if (call == null) {
throw new calling_1.CallingError(calling_1.CallingErrorCode.CallNotFound);
}
const includePendingUserIds = call.isAdmin(request.userId);
const info = call.getInfo(includePendingUserIds);
return { info };
}
}
exports.SfuService = SfuService;