/* * Copyright (C) Sapphirecode - All Rights Reserved * This file is part of Auth-Server-Helper which is released under MIT. * See file 'LICENSE' for full license details. * Created by Timo Hocker , December 2020 */ import { IncomingMessage, ServerResponse } from 'http'; import { run_regex } from '@sapphirecode/utilities'; import authority from './Authority'; type AnyFunc = (...args: unknown[]) => unknown; type Gateway = ( req: IncomingMessage, res: ServerResponse, next: AnyFunc ) => unknown; interface GatewayOptions { redirect_url: string; cookie_name?: string; } class GatewayClass { private _options: GatewayOptions; public constructor (options: GatewayOptions) { this._options = options; } private redirect (res: ServerResponse): void { res.statusCode = 302; res.setHeader ('Location', this._options.redirect_url); res.end (); } private get_header_auth (req: IncomingMessage): string | null { const auth_header = req.headers.authorization; const auth = (/(?\w+) (?.*)/u).exec (auth_header || ''); if (auth === null) return null; if (auth.groups?.type !== 'Bearer') return null; return auth.groups?.data; } private get_cookie_auth (req: IncomingMessage): string | null { if (typeof this._options.cookie_name === 'undefined') return null; let auth = null; run_regex ( /(?:^|;)\s*(?[^;=]+)=(?[^;]+)/gu, req.headers.cookie, (res: RegExpMatchArray) => { if (res.groups?.name === this._options.cookie_name) auth = res.groups?.value; } ); return auth; } private authenticate (req: IncomingMessage): boolean { let auth = this.get_header_auth (req); if (auth === null) auth = this.get_cookie_auth (req); if (auth === null) return false; const ver = authority.verify (auth); const con = req.connection as unknown as Record; con.auth = { token_id: ver.id, token_data: ver.data }; return ver.authorized; } public process_request ( req: IncomingMessage, res: ServerResponse, next: AnyFunc ): unknown { if (this.authenticate (req)) return next (); return this.redirect (res); } } export default function create_gateway (options: GatewayOptions): Gateway { const g = new GatewayClass (options); return g.process_request.bind (g); } export { AnyFunc, Gateway, GatewayOptions, GatewayClass };