Files
AriWeb-Suite/hal/config.mjs

42 lines
2.7 KiB
JavaScript

/**
* hal/config.mjs — HAL 실행 설정.
*
* 배포 때 정해지는 값(포트·데이터 디렉터리)은 환경 변수로, 운영 중 바꾸는 값(공개 주소·포털 주소·허용 네트워크·메트릭 보존 일수)은
* data/config.json 에 둔다. 비밀값(서비스 키·Agent 비밀)은 설정이 아니라 보관소(lib/vault)에만 둔다.
*/
import { readFileSync, existsSync, writeFileSync, mkdirSync, renameSync } from 'node:fs';
import { join } from 'node:path';
export function loadConfig() {
const dataDir = process.env.ARIWEB_HAL_DATA || process.env.DATA_DIR || join(process.cwd(), 'data');
mkdirSync(dataDir, { recursive: true, mode: 0o700 });
const file = join(dataDir, 'config.json');
let values = {}; try { values = existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')).values || {} : {}; } catch (_) { values = {}; }
const cfg = {
dataDir, file,
port: Number(process.env.PORT || 8900), host: process.env.HOST || '127.0.0.1',
/** HAL 공개 주소(Agent 가 접속하는 주소) */
publicUrl: values.publicUrl || process.env.HAL_PUBLIC_URL || 'https://hal.ariweb.net',
/** 포털 내부 주소(작업 이벤트를 미는 곳) */
portalUrl: values.portalUrl || process.env.PORTAL_URL || 'http://127.0.0.1:8910',
/** 운영자 콘솔 접근 허용 네트워크(CIDR 목록, §25). 비어 있으면 접근권(grant) 쿠키만 허용 */
opsAllowCidrs: values.opsAllowCidrs || (process.env.OPS_ALLOW_CIDRS ? process.env.OPS_ALLOW_CIDRS.split(',').map((s) => s.trim()).filter(Boolean) : ['127.0.0.1/32', '::1/128', '10.0.0.0/8', '192.168.0.0/16']),
/** 메트릭 보존 일수(최소 90, §28.1) */
metricsRetentionDays: Math.max(90, Number(values.metricsRetentionDays || 90)),
/** heartbeat 가 이만큼 없으면 서버를 offline 으로 본다 */
offlineAfterMs: Number(values.offlineAfterMs || 90 * 1000),
/** 전송(transfer) 파일 보관 시간 */
transferTtlMs: Number(values.transferTtlMs || 24 * 3600 * 1000),
/** 긴급 자격 최대 유효 시간(분) */
emergencyTtlMinutes: Math.min(60, Number(values.emergencyTtlMinutes || 30)),
values,
/** 설정 저장(운영자 화면·CLI). 비밀값은 거부한다. */
set(patch, by = 'ops') {
for (const k of Object.keys(patch)) if (/key|secret|token|pass/i.test(k)) throw new Error(`비밀값(${k})은 설정 파일에 둘 수 없습니다 — 보관소를 쓰세요`);
Object.assign(values, patch); const tmp = file + '.tmp';
writeFileSync(tmp, JSON.stringify({ version: 1, updatedAt: new Date().toISOString(), updatedBy: by, values }, null, 1), { mode: 0o600 }); renameSync(tmp, file); Object.assign(cfg, patch);
},
};
return cfg;
}