baudy/src/server/local-tls.ts

68 lines
1.6 KiB
TypeScript

import { mkdirSync } from 'node:fs'
import { getNetworkTargets } from './network'
const CERT_PATH = './certs/cert.pem'
const KEY_PATH = './certs/key.pem'
export interface LocalServerUrls {
primaryUrl: string
urls: string[]
}
export function getLocalServerUrls(port: number): LocalServerUrls {
const scheme = isLocalTlsEnabled() ? 'https' : 'http'
const { primaryHost, urls } = getNetworkTargets(port, scheme)
return {
primaryUrl: `${scheme}://${primaryHost}:${port}`,
urls,
}
}
export async function getLocalTlsOptions(_port: number) {
if (!isLocalTlsEnabled()) return
await ensureLocalTlsFiles()
return {
cert: Bun.file(CERT_PATH),
key: Bun.file(KEY_PATH),
}
}
export function isLocalTlsEnabled() {
return process.platform === 'darwin'
}
async function ensureLocalTlsFiles() {
const certExists = await Bun.file(CERT_PATH).exists()
const keyExists = await Bun.file(KEY_PATH).exists()
if (certExists && keyExists) return
const opensslCheck = Bun.spawnSync(['which', 'openssl'], {
stdout: 'ignore',
stderr: 'ignore',
})
if (opensslCheck.exitCode !== 0) {
throw new Error('openssl is required for local macOS HTTPS mode')
}
mkdirSync('./certs', { recursive: true })
const proc = Bun.spawnSync([
'openssl', 'req', '-x509', '-newkey', 'rsa:2048',
'-keyout', KEY_PATH,
'-out', CERT_PATH,
'-days', '365',
'-nodes',
'-subj', '/CN=localhost',
], {
stdout: 'ignore',
stderr: 'pipe',
})
if (proc.exitCode !== 0) {
throw new Error(`failed to generate local TLS certificate: ${proc.stderr.toString().trim()}`)
}
}