import { EndpointType } from "$lib/server/enums/endpoints" import { httpVersion, proxyProtocol, secureProtocol, type NginxProtocol } from "$lib/server/enums/protocols" import { validatePort } from "$lib/server/utils/ports-utils" import type { Stats } from "fs" import type { FSHeader, IEndpointFS } from "./endpoints" import { createHeader } from "../utils" import { hashUtil } from "$lib/server/utils/filesystem-utils" // TODO: add broker implementation export class SSLTerminationFS implements IEndpointFS { private static __type = EndpointType.SSL_TERMINATION public get type() { return SSLTerminationFS.__type } public name: string public stats: Stats public path: string public hash: string public sslPort: number public clearPort: number public servicePort: number public serviceEndpoint: string public protocol: NginxProtocol public certificateURI: string public privateKeyURI: string constructor( name: string, stats: Stats, path: string, hash: string, sslPort: number, clearPort: number, servicePort: number, serviceEndpoint: string, protocol: NginxProtocol, certificateURI: string, privateKeyURI: string ) { this.name = name this.stats = stats this.path = path this.hash = hash this.sslPort = sslPort this.clearPort = clearPort this.servicePort = servicePort this.serviceEndpoint = serviceEndpoint this.protocol = protocol this.certificateURI = certificateURI this.privateKeyURI = privateKeyURI } headerHash(): string { return hashUtil( this.createHeader() ) } toConf(): string { const HEADER = this.createHeader() const SSL_SERVER = this.createSSLServer() const CLEAR_SERVER = this.createClearServer() const CONF = HEADER + SSL_SERVER + CLEAR_SERVER return CONF } ports(): number[]{ return [ this.sslPort, this.clearPort ] } public static parseConf(fsHeader: FSHeader, conf: string) : SSLTerminationFS { // TODO: parse header } private createHeader() { return createHeader( this, [ { key: "NAME", value: this.name }, { key: "PROTOCOL", value: this.protocol }, { key: "SSL_PORT", value: this.sslPort }, { key: "CLEAR_PORT", value: this.clearPort }, { key: "SERVICE_PORT", value: this.servicePort }, { key: "SERVICE_ENDPOINT", value: this.serviceEndpoint }, { key: "CERTIFICATE_PATH", value: this.certificateURI }, { key: "KEY_PATH", value: this.privateKeyURI } ] ) } // UGLY: refactor into a flexible method private createSSLServer() { const CLEAR_PROTOCOL = `${this.protocol}` const HTTP_VERSION = httpVersion(this.protocol) const PROXY_OPTION = proxyProtocol(this.protocol) // UGLY: put to constants let conf = [ "server {\n", "\tmore_clear_headers Server;\n", `\tlisten ${this.sslPort};` ] if (HTTP_VERSION !== 1) { conf.push( `\thttp${HTTP_VERSION} on;` ) } // TODO: check if we should support less protocols conf.push( "\n", "\tlocation / {", `\t\t${PROXY_OPTION} ${CLEAR_PROTOCOL}://127.0.0.1:${this.clearPort};`, "\t}", "\n", `ssl_certificate ${this.certificateURI};`, `ssl_certificate_key ${this.privateKeyURI};`, "\tssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;", "\n", "}" ) return conf.join("\n") } private createClearServer() { const SSL_PROTOCOL = secureProtocol(this.protocol) const HTTP_VERSION = httpVersion(this.protocol) const PROXY_OPTION = proxyProtocol(this.protocol) // UGLY: put to constants let conf = [ "server {\n", "\tmore_clear_headers Server;\n", `\tlisten ${this.clearPort};` ] if (HTTP_VERSION !== 1) { conf.push( `\thttp${HTTP_VERSION} on;` ) } // TODO: check if we should support less protocols conf.push( "\n", "\tlocation / {", `\t\t${PROXY_OPTION} ${SSL_PROTOCOL}://${this.serviceEndpoint}:${this.servicePort};`, "\t}", "\n", "}" ) return conf.join("\n") } }