UNPKG

helene

Version:
182 lines 7.48 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.HttpTransport = exports.HttpTransportEvents = void 0; const utils_1 = require("../../utils"); const cors_1 = __importDefault(require("cors")); const express_1 = __importDefault(require("express")); const http_1 = __importDefault(require("http")); const client_node_1 = require("../client-node"); const ejson_1 = require("../../ejson"); const express_rate_limit_1 = __importDefault(require("express-rate-limit")); const isString_1 = __importDefault(require("lodash/isString")); var HttpTransportEvents; (function (HttpTransportEvents) { HttpTransportEvents["HTTP_LISTENING"] = "http:listening"; HttpTransportEvents["HTTP_SERVER_ERROR"] = "http:server:error"; HttpTransportEvents["HTTP_SERVER_CLOSED"] = "http:server:closed"; })(HttpTransportEvents || (exports.HttpTransportEvents = HttpTransportEvents = {})); class HttpTransport { server; http; express; constructor(server, origins, limit) { this.server = server; this.express = (0, express_1.default)(); this.http = http_1.default.createServer(this.express); this.express.use('/__h', express_1.default.urlencoded({ extended: true })); this.express.use('/__h', express_1.default.text({ type: 'text/plain' })); if (limit) { const limiter = (0, express_rate_limit_1.default)({ ...(limit === true ? { windowMs: 60 * 1000, max: 120 } : { windowMs: limit.interval, max: limit.max }), standardHeaders: true, legacyHeaders: false, }); this.express.use('/__h', limiter); } if (origins) this.setCORS(origins); if (this.server.requestListener) { this.http.on(utils_1.ServerEvents.REQUEST, this.server.requestListener); } this.express.post('/__h', this.requestHandler); this.authMiddleware = this.authMiddleware.bind(this); this.contextMiddleware = this.contextMiddleware.bind(this); } setCORS(origins) { this.express.use((0, cors_1.default)({ credentials: true, origin: function (origin, callback) { if (!origin || origins.includes(origin)) return callback(null, true); callback(new Error('Not allowed by CORS')); }, })); } async getServerContext(clientNode, context = {}) { const token = clientNode.req.headers[utils_1.TOKEN_HEADER_KEY]; if ((0, isString_1.default)(token) && token.length && token !== 'undefined') { context.token = token.replace('Bearer ', ''); } if (this.server.auth instanceof Function) { let result = this.server.auth.call(clientNode, context ?? {}); result = result instanceof Promise ? await result : result; return result; } return false; } requestHandler = async (req, res) => { let uuid; let payload; try { const transport = req.body && (0, isString_1.default)(req.body) ? ejson_1.EJSON.parse(req.body) : {}; if (!transport.payload) { return res.send(utils_1.Presentation.encode({ type: utils_1.PayloadType.ERROR, message: utils_1.Errors.INVALID_REQUEST, })); } payload = transport.payload; const method = this.server.getMethod(payload.method); const clientId = req.headers[utils_1.CLIENT_ID_HEADER_KEY]; const clientNode = new client_node_1.ClientNode(this.server, null, req, res); clientNode.uuid = clientId; if (!method) { return res.send(utils_1.Presentation.encode({ type: utils_1.PayloadType.ERROR, message: utils_1.Errors.METHOD_NOT_FOUND, method: payload.method, })); } const serverContext = await this.getServerContext(clientNode, transport.context); clientNode.authenticated = Boolean(serverContext); clientNode.setContext(serverContext); if (method.isProtected && !clientNode.authenticated) { return res.send(utils_1.Presentation.encode({ type: utils_1.PayloadType.ERROR, message: utils_1.Errors.METHOD_FORBIDDEN, method: payload.method, })); } uuid = payload?.uuid ? { uuid: payload.uuid } : null; const result = await method.exec(payload.params, clientNode); res.send(utils_1.Presentation.encode({ type: utils_1.PayloadType.RESULT, uuid: payload.uuid, method: payload.method, result, })); } catch (error) { console.error(error); if (payload?.void) return; if (error instanceof utils_1.PublicError) { return res.send(utils_1.Presentation.encode({ type: utils_1.PayloadType.ERROR, message: error.message, ...uuid, })); } if (error instanceof utils_1.SchemaValidationError) { return res.send(utils_1.Presentation.encode({ type: utils_1.PayloadType.ERROR, message: error.message, errors: error.errors, ...uuid, })); } return res.send(utils_1.Presentation.encode({ type: utils_1.PayloadType.ERROR, message: utils_1.Errors.INTERNAL_ERROR, ...uuid, })); } }; async contextMiddleware(req, res, next) { const clientNode = new client_node_1.ClientNode(this.server, null, req, res); req.context = await this.getServerContext(clientNode); next(); } async authMiddleware(req, res, next) { const clientNode = new client_node_1.ClientNode(this.server, null, req, res); const serverContext = await this.getServerContext(clientNode); if (serverContext === false) { res.status(403); return res.end('403 Forbidden'); } req.context = serverContext; next(); } static(path, catchAll) { const middleware = express_1.default.static(path); this.express.use('/', middleware); if (catchAll) { this.express.use(/(.*)/, middleware); } } /** * Need to close WebSocket server first. */ close() { return new Promise(resolve => { if (!this.http) { this.server.emit(HttpTransportEvents.HTTP_SERVER_CLOSED); return resolve(); } this.http.closeAllConnections(); this.http.close(() => { this.http.unref(); this.http = undefined; this.server.emit(HttpTransportEvents.HTTP_SERVER_CLOSED); resolve(); }); }); } } exports.HttpTransport = HttpTransport; //# sourceMappingURL=http-transport.js.map