Files
Veskslop-t/poc/src/tls.ts
T

76 lines
2.2 KiB
TypeScript

/*
* Veskslop daemon — self-signed TLS for the web UI.
*
* Browser media APIs need a secure context. The daemon generates one
* self-signed certificate (openssl) covering localhost and the host's LAN
* addresses, and serves the UI over HTTPS. WEBUI_TLS=0 disables this.
*/
import { execFileSync } from "node:child_process";
import { existsSync, mkdirSync } from "node:fs";
import { networkInterfaces } from "node:os";
import { join } from "node:path";
export interface TlsPaths {
key: string;
cert: string;
}
function localAddresses(): string[] {
const names = ["DNS:localhost", "IP:127.0.0.1"];
for (const list of Object.values(networkInterfaces())) {
for (const info of list ?? []) {
if (info.family === "IPv4" && !info.internal) names.push(`IP:${info.address}`);
}
}
return names;
}
export function ensureTls(storeDir: string): TlsPaths | undefined {
if (process.env.WEBUI_TLS === "0") return undefined;
const keyOverride = process.env.WEBUI_TLS_KEY;
const certOverride = process.env.WEBUI_TLS_CERT;
if (keyOverride && certOverride) {
return existsSync(keyOverride) && existsSync(certOverride)
? { key: keyOverride, cert: certOverride }
: undefined;
}
const dir = join(storeDir, "tls");
const key = join(dir, "key.pem");
const cert = join(dir, "cert.pem");
if (existsSync(key) && existsSync(cert)) return { key, cert };
try {
mkdirSync(dir, { recursive: true });
execFileSync(
"openssl",
[
"req",
"-x509",
"-newkey",
"rsa:2048",
"-nodes",
"-keyout",
key,
"-out",
cert,
"-days",
"825",
"-subj",
"/CN=veskslop",
"-addext",
`subjectAltName=${localAddresses().join(",")}`
],
{ stdio: "ignore" }
);
return { key, cert };
} catch (error) {
console.warn("[webui] self-signed certificate generation failed:", (error as Error).message);
return undefined;
}
}