@signalapp/mock-server
Version:
Mock Signal Server for writing tests
101 lines (100 loc) • 3.86 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.Router = void 0;
const debug_1 = __importDefault(require("debug"));
const url_1 = require("url");
const querystring_1 = require("querystring");
const url_pattern_1 = __importDefault(require("url-pattern"));
const util_1 = require("../../util");
const assert_1 = __importDefault(require("assert"));
const debug = (0, debug_1.default)('mock:ws:router');
class Router {
options;
routes = [];
isAuthenticated = false;
constructor(options) {
this.options = options;
}
register(method, pattern, handler) {
this.routes.push({
method,
pattern: new url_pattern_1.default(pattern, {
segmentValueCharset: ':a-zA-Z0-9-_~ %',
}),
handler,
});
}
get(pattern, handler) {
this.register('GET', pattern, handler);
}
patch(pattern, handler) {
this.register('PATCH', pattern, handler);
}
put(pattern, handler) {
this.register('PUT', pattern, handler);
}
post(pattern, handler) {
this.register('POST', pattern, handler);
}
del(pattern, handler) {
this.register('DELETE', pattern, handler);
}
async run(request) {
const headers = {};
for (const pair of request.headers ?? []) {
const [field, value = ''] = pair.split(/\s*:\s*/, 2);
(0, assert_1.default)(field != null, 'Missing field name for header');
headers[field.toLowerCase()] = value;
}
let response = [404, { error: 'Not found' }];
debug('got request %s %s %s', this.isAuthenticated ? '(auth)' : '(unauth)', request.verb, request.path);
// eslint-disable-next-line @typescript-eslint/no-deprecated
const { pathname, query } = (0, url_1.parse)(request.path ?? '');
await this.options.beforeRequest(request.verb ?? '', pathname ?? '', headers);
for (const { method, pattern, handler } of this.routes) {
if (method !== request.verb) {
continue;
}
const params = pattern.match(pathname ?? '');
if (params == null) {
continue;
}
const decodedParams = {};
for (const [key, value] of Object.entries(params)) {
decodedParams[key] = decodeURIComponent(String(value));
}
response = await handler(decodedParams, request.body ?? undefined, headers, query === null ? undefined : (0, querystring_1.parse)(query));
break;
}
const [status, json, responseHeaders = {}] = response;
debug('response %s %s status=%d', request.verb, request.path, status);
const timestampHeader = `X-Signal-Timestamp:${Date.now()}`;
const replyHeaders = [timestampHeader].concat(Object.entries(responseHeaders).map(([name, value]) => `${name}:${value}`));
if (json instanceof Uint8Array) {
return {
id: request.id,
status,
message: null,
headers: ['Content-Type:application/x-protobuf'].concat(replyHeaders),
body: Buffer.from(json),
};
}
(0, util_1.assertJsonValue)(json);
return {
id: request.id,
status,
message: null,
headers: replyHeaders.concat(['Content-Type:application/json']),
body: Buffer.from(JSON.stringify(json)),
};
}
setIsAuthenticated(value) {
this.isAuthenticated = value;
}
}
exports.Router = Router;