#!/usr/bin/env node import crypto from 'node:crypto' import fs from 'node:fs' import http from 'node:http' import path from 'node:path' import { fileURLToPath } from 'node:url' const MAX_CONTROL_BYTES = 1024 * 1024 const VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/ const SHA256_PATTERN = /^[a-f0-9]{64}$/ const fail = (code) => { throw new Error(code) } const sha256 = (bytes) => crypto.createHash('sha256').update(bytes).digest('hex') const requireText = (value, code) => { if (typeof value !== 'string' || value.trim() === '') fail(code) return value.trim() } function trustedRegularFile(file, { enforceRootOwner, maxBytes = null }) { const info = fs.lstatSync(file) if (!info.isFile() || info.isSymbolicLink()) fail('HOLOLAKE_RELEASE_FILE_NOT_REGULAR') if ((info.mode & 0o022) !== 0) fail('HOLOLAKE_RELEASE_FILE_WRITABLE_BY_NON_OWNER') if (enforceRootOwner && info.uid !== 0) fail('HOLOLAKE_RELEASE_FILE_NOT_ROOT_OWNED') if (maxBytes !== null && info.size > maxBytes) fail('HOLOLAKE_RELEASE_CONTROL_FILE_TOO_LARGE') return info } function safeRelative(root, value, code) { const relative = requireText(value, code) if (path.isAbsolute(relative) || relative.includes('\0')) fail(code) const resolved = path.resolve(root, relative) if (!resolved.startsWith(`${root}${path.sep}`)) fail(code) return resolved } function readTrustedJson(file, options) { trustedRegularFile(file, { ...options, maxBytes: MAX_CONTROL_BYTES }) return { bytes: fs.readFileSync(file), value: JSON.parse(fs.readFileSync(file, 'utf8')) } } function validatePlatform(platform, releaseDirectory, enforceRootOwner) { const url = new URL(requireText(platform?.url, 'HOLOLAKE_RELEASE_PACKAGE_URL_REQUIRED')) if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash) { fail('HOLOLAKE_RELEASE_PACKAGE_URL_INVALID') } const packageName = decodeURIComponent(path.posix.basename(url.pathname)) if (!packageName || packageName === '.' || packageName === '..') fail('HOLOLAKE_RELEASE_PACKAGE_NAME_INVALID') const packagePath = safeRelative(releaseDirectory, packageName, 'HOLOLAKE_RELEASE_PACKAGE_PATH_INVALID') const packageInfo = trustedRegularFile(packagePath, { enforceRootOwner }) if (!Number.isSafeInteger(platform.size) || platform.size <= 0 || platform.size !== packageInfo.size) { fail('HOLOLAKE_RELEASE_PACKAGE_SIZE_MISMATCH') } if (!SHA256_PATTERN.test(platform.sha256 || '') || sha256(fs.readFileSync(packagePath)) !== platform.sha256) { fail('HOLOLAKE_RELEASE_PACKAGE_SHA256_MISMATCH') } requireText(platform.signature, 'HOLOLAKE_RELEASE_PACKAGE_SIGNATURE_REQUIRED') const codeReceiptId = requireText(platform.platformCodeSignatureReceipt, 'HOLOLAKE_RELEASE_CODESIGN_RECEIPT_REQUIRED') const notarizationReceiptId = requireText(platform.notarizationReceipt, 'HOLOLAKE_RELEASE_NOTARIZATION_RECEIPT_REQUIRED') const codeReceipt = readTrustedJson( safeRelative(releaseDirectory, `${codeReceiptId}.json`, 'HOLOLAKE_RELEASE_CODESIGN_RECEIPT_PATH_INVALID'), { enforceRootOwner }, ).value const notarizationReceipt = readTrustedJson( safeRelative(releaseDirectory, `${notarizationReceiptId}.json`, 'HOLOLAKE_RELEASE_NOTARIZATION_RECEIPT_PATH_INVALID'), { enforceRootOwner }, ).value if ( codeReceipt?.schema !== 'hololake.platform-code-signature-receipt/v1' || codeReceipt?.state !== 'DEVELOPER_ID_SIGNATURE_STRICT_AND_GATEKEEPER_ACCEPTED' ) fail('HOLOLAKE_RELEASE_CODESIGN_RECEIPT_INVALID') if ( notarizationReceipt?.schema !== 'hololake.apple-notarization-receipt/v1' || notarizationReceipt?.state !== 'APPLE_NOTARIZATION_ACCEPTED_AND_STAPLED' ) fail('HOLOLAKE_RELEASE_NOTARIZATION_RECEIPT_INVALID') return { pathname: url.pathname, file: packagePath, size: packageInfo.size } } function loadActiveRelease(stateRoot, enforceRootOwner) { const activationPath = path.join(stateRoot, 'ACTIVE.json') if (!fs.existsSync(activationPath)) { return { state: 'EMPTY_FAIL_CLOSED', release: null, reasonCode: null } } const activation = readTrustedJson(activationPath, { enforceRootOwner }).value if ( activation?.schema !== 'hololake.release-broadcast-activation/v1' || activation?.state !== 'HUMAN_APPROVED_SIGNED_NOTARIZED_RELEASE_ACTIVE' ) fail('HOLOLAKE_RELEASE_ACTIVATION_INVALID') const releaseId = requireText(activation.releaseId, 'HOLOLAKE_RELEASE_ID_REQUIRED') const version = requireText(activation.version, 'HOLOLAKE_RELEASE_VERSION_REQUIRED') if (!VERSION_PATTERN.test(version)) fail('HOLOLAKE_RELEASE_VERSION_INVALID') if (!SHA256_PATTERN.test(activation.broadcastSha256 || '')) fail('HOLOLAKE_RELEASE_BROADCAST_SHA256_INVALID') requireText(activation.humanApprovalReceipt, 'HOLOLAKE_RELEASE_HUMAN_APPROVAL_REQUIRED') const broadcastPath = safeRelative(stateRoot, activation.broadcastRelativePath, 'HOLOLAKE_RELEASE_BROADCAST_PATH_INVALID') const pipelinePath = safeRelative(stateRoot, activation.pipelineReceiptRelativePath, 'HOLOLAKE_RELEASE_PIPELINE_PATH_INVALID') const broadcastDocument = readTrustedJson(broadcastPath, { enforceRootOwner }) const pipelineReceipt = readTrustedJson(pipelinePath, { enforceRootOwner }).value if (sha256(broadcastDocument.bytes) !== activation.broadcastSha256) fail('HOLOLAKE_RELEASE_BROADCAST_SHA256_MISMATCH') if ( pipelineReceipt?.schema !== 'hololake.signed-release-pipeline-receipt/v1' || pipelineReceipt?.state !== 'SIGNED_NOTARIZED_RELEASE_BROADCAST_READY_FOR_JD_CONTROLLER_UPLOAD' || pipelineReceipt?.broadcastSha256 !== activation.broadcastSha256 || pipelineReceipt?.automaticUpload !== false || pipelineReceipt?.automaticActivation !== false ) fail('HOLOLAKE_RELEASE_PIPELINE_RECEIPT_INVALID') const broadcast = broadcastDocument.value if ( broadcast?.schema !== 'hololake.release-broadcast/v1' || broadcast?.releaseId !== releaseId || broadcast?.version !== version || broadcast?.hololake?.restart?.required !== true || broadcast?.hololake?.restart?.automaticAllowed !== false || broadcast?.hololake?.rollback?.supported !== true || broadcast?.hololake?.rollback?.healthReceiptRequired !== true || !broadcast.platforms || typeof broadcast.platforms !== 'object' || Array.isArray(broadcast.platforms) || Object.keys(broadcast.platforms).length === 0 ) fail('HOLOLAKE_RELEASE_BROADCAST_INVALID') const releaseDirectory = path.dirname(broadcastPath) const packages = new Map() for (const platform of Object.values(broadcast.platforms)) { const accepted = validatePlatform(platform, releaseDirectory, enforceRootOwner) if (packages.has(accepted.pathname)) fail('HOLOLAKE_RELEASE_PACKAGE_ROUTE_COLLISION') packages.set(accepted.pathname, accepted) } return { state: 'READY_SIGNED_NOTARIZED_BROADCAST', release: { releaseId, version, broadcastBytes: broadcastDocument.bytes, packages }, reasonCode: null, } } export function loadRuntimeState(stateRoot, { enforceRootOwner = false } = {}) { const resolvedRoot = path.resolve(stateRoot) try { return loadActiveRelease(resolvedRoot, enforceRootOwner) } catch (error) { return { state: 'LOCKED_INVALID_RELEASE_EVIDENCE', release: null, reasonCode: error instanceof Error ? error.message : 'HOLOLAKE_RELEASE_UNKNOWN_FAILURE', } } } function jsonResponse(response, status, value) { const body = Buffer.from(`${JSON.stringify(value)}\n`) response.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': body.length, 'Cache-Control': 'no-store', 'X-Content-Type-Options': 'nosniff', }) response.end(body) } export function createReleaseServer(runtimeState) { return http.createServer((request, response) => { response.setHeader('X-Content-Type-Options', 'nosniff') if (!['GET', 'HEAD'].includes(request.method || '')) { response.writeHead(405, { Allow: 'GET, HEAD', 'Cache-Control': 'no-store' }) return response.end() } const pathname = new URL(request.url || '/', 'http://127.0.0.1').pathname if (pathname === '/health') { const status = runtimeState.state === 'LOCKED_INVALID_RELEASE_EVIDENCE' ? 503 : 200 return jsonResponse(response, status, { schema: 'hololake.release-broadcast-health/v1', state: runtimeState.state, updateAvailable: runtimeState.release !== null, automaticUpload: false, automaticActivation: false, upstreamUpdateSources: [], ...(runtimeState.release ? { releaseId: runtimeState.release.releaseId, version: runtimeState.release.version } : {}), ...(runtimeState.reasonCode ? { reasonCode: runtimeState.reasonCode } : {}), }) } if (pathname === '/latest.json') { if (runtimeState.state === 'EMPTY_FAIL_CLOSED') { response.writeHead(204, { 'Cache-Control': 'no-store' }) return response.end() } if (!runtimeState.release) { response.writeHead(503, { 'Cache-Control': 'no-store' }) return response.end() } response.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': runtimeState.release.broadcastBytes.length, 'Cache-Control': 'no-store', 'X-Content-Type-Options': 'nosniff', }) return response.end(request.method === 'HEAD' ? undefined : runtimeState.release.broadcastBytes) } const packageFile = runtimeState.release?.packages.get(pathname) if (packageFile) { response.writeHead(200, { 'Content-Type': 'application/octet-stream', 'Content-Length': packageFile.size, 'Cache-Control': 'public, max-age=31536000, immutable', 'X-Content-Type-Options': 'nosniff', }) if (request.method === 'HEAD') return response.end() return fs.createReadStream(packageFile.file).on('error', () => response.destroy()).pipe(response) } response.writeHead(404, { 'Cache-Control': 'no-store' }) response.end() }) } export function main(env = process.env) { const host = env.HOLOLAKE_RELEASE_HOST || '127.0.0.1' if (host !== '127.0.0.1') fail('HOLOLAKE_RELEASE_LOOPBACK_BIND_REQUIRED') const port = Number(env.HOLOLAKE_RELEASE_PORT || 3940) if (!Number.isInteger(port) || port < 1024 || port > 65535) fail('HOLOLAKE_RELEASE_PORT_INVALID') const stateRoot = path.resolve(env.HOLOLAKE_RELEASE_STATE_ROOT || '/var/lib/guanghu/hololake-release-broadcast') const runtimeState = loadRuntimeState(stateRoot, { enforceRootOwner: env.HOLOLAKE_RELEASE_ENFORCE_ROOT_OWNER === '1' }) const server = createReleaseServer(runtimeState) server.on('clientError', (_error, socket) => socket.end('HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n')) server.listen(port, host, () => { process.stdout.write(`${JSON.stringify({ schema: 'hololake.release-broadcast-startup/v1', host, port, state: runtimeState.state })}\n`) }) return server } if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { try { main() } catch (error) { process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`) process.exitCode = 1 } }