Serve HTTPS by default with a local CA
The installer generates a CA and a 397-day certificate into $COBBLE_HOME/certs (in the app image, with the host's addresses), mounts the certificate, key and CA into the container and serves TLS from Bun on the published port. --no-https opts out; --https-cert/--https-key use a real certificate, --https-host adds names and --https-regen replaces the CA. The installer and the image health check use curl -k when TLS is on. The CA is served at /ca.crt and as an iOS/macOS profile at /ca.mobileconfig for one-tap install. Development picks up certs/ automatically, `bun run dev:phone` generates and starts, and a plain-HTTP listener on PORT + 1 redirects to HTTPS. Port sharing is off, so a stale dev server fails instead of silently answering on the same port.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import net from "net";
|
||||
|
||||
type Params = {
|
||||
/**
|
||||
* The machine's own name, as `os.hostname()` gives it. Its short form
|
||||
* and `<short>.local` are added too, since that is how a LAN reaches
|
||||
* it.
|
||||
*/
|
||||
hostname?: string;
|
||||
/**
|
||||
* Addresses the app answers on.
|
||||
*/
|
||||
addresses?: string[];
|
||||
/**
|
||||
* Names or addresses given by the user, e.g. a VPN's DNS name.
|
||||
*/
|
||||
hosts?: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* The `subjectAltName` entries a certificate is issued for: `DNS:name` for
|
||||
* a name, `IP:address` for an address, deduplicated. `localhost` and both
|
||||
* loopback addresses are always there, so `https://localhost` (and a
|
||||
* forwarded port) keep working.
|
||||
*
|
||||
* A name is classified by `net.isIP`, so a user can pass an address
|
||||
* wherever a host is expected without it becoming a useless DNS entry.
|
||||
*/
|
||||
export default function buildSanList({
|
||||
hostname,
|
||||
addresses,
|
||||
hosts,
|
||||
}: Params): string[] {
|
||||
const entries: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
|
||||
const add = ({ type, value }: { type: "DNS" | "IP"; value: string }) => {
|
||||
const trimmed = value.trim();
|
||||
|
||||
if (!trimmed) return;
|
||||
|
||||
const entry = `${type}:${
|
||||
type == "DNS" ? trimmed.toLowerCase() : trimmed
|
||||
}`;
|
||||
const key = entry.toLowerCase();
|
||||
|
||||
if (seen.has(key)) return;
|
||||
|
||||
seen.add(key);
|
||||
entries.push(entry);
|
||||
};
|
||||
|
||||
const addHost = (value: string) => {
|
||||
const trimmed = value.trim();
|
||||
|
||||
if (!trimmed) return;
|
||||
|
||||
add({ type: net.isIP(trimmed) ? "IP" : "DNS", value: trimmed });
|
||||
};
|
||||
|
||||
add({ type: "DNS", value: "localhost" });
|
||||
add({ type: "IP", value: "127.0.0.1" });
|
||||
add({ type: "IP", value: "::1" });
|
||||
|
||||
const own = (hostname ?? "").trim();
|
||||
|
||||
if (own) {
|
||||
addHost(own);
|
||||
|
||||
const short = own.split(".")[0];
|
||||
|
||||
if (short && short != "localhost") {
|
||||
add({ type: "DNS", value: short });
|
||||
|
||||
if (short != own) add({ type: "DNS", value: `${short}.local` });
|
||||
}
|
||||
}
|
||||
|
||||
for (const address of addresses ?? []) addHost(address);
|
||||
for (const host of hosts ?? []) addHost(host);
|
||||
|
||||
return entries;
|
||||
}
|
||||
Reference in New Issue
Block a user