import { resolve } from 'node:path'; import { createApp } from './app.mjs'; import { openStore } from './store.mjs'; import { startTelemetry } from './telemetry.mjs'; import { startSIEM } from './siem.mjs'; import {startAuditRetention} from './audit-retention.mjs'; const env=process.env; const publicUrl=(env.PUBLIC_URL||'http://127.0.0.1:4310').replace(/\/$/,''); const u=new URL(publicUrl); if(u.protocol!=='https:' && !['127.0.0.1','localhost','[::1]'].includes(u.hostname))throw Error('Remote management requires HTTPS'); if(u.protocol==='http:'&&(!env.ADMIN_TOKEN||env.ADMIN_TOKEN.length<32))throw Error('Local development requires ADMIN_TOKEN of at least 32 characters'); if(u.protocol==='http:'&&env.HOST&&!['127.0.0.1','localhost','::1'].includes(env.HOST))throw Error('Development HTTP management must bind only to loopback'); if(u.protocol==='https:'&&(!env.OIDC_ISSUER||!env.OIDC_CLIENT_ID))throw Error('HTTPS management requires enterprise OIDC configuration; shared bootstrap administrator tokens are disabled'); const config={publicUrl,secure:u.protocol==='https:',adminToken:env.ADMIN_TOKEN,oidcIssuer:env.OIDC_ISSUER,oidcClientId:env.OIDC_CLIENT_ID,oidcClientSecret:env.OIDC_CLIENT_SECRET,oidcAdminGroup:env.OIDC_ADMIN_GROUP||'safetynet-admins',oidcGroupsClaim:env.OIDC_GROUPS_CLAIM||'groups',aiBaseUrl:env.AI_BASE_URL,aiKey:env.AI_API_KEY,aiModel:env.AI_MODEL,inspectorUrl:env.INSPECTOR_URL,inspectorToken:env.INSPECTOR_TOKEN}; config.companyNewsAllowedHosts=(env.COMPANY_NEWS_ALLOWED_HOSTS||'').split(',').map(v=>v.trim().toLowerCase()).filter(Boolean); const store=openStore(resolve(env.DATA_DIR||'data'),{auditSigningKeyFile:env.AUDIT_SIGNING_KEY_FILE}); config.evidenceKeyFile=env.EVIDENCE_KEY_FILE; config.evidenceRetentionDays=Number(env.EVIDENCE_RETENTION_DAYS||30); config.oidcDeviceGroup=env.OIDC_DEVICE_GROUP; config.oidcOperatorGroup=env.OIDC_OPERATOR_GROUP; config.oidcAuditorGroup=env.OIDC_AUDITOR_GROUP; config.oidcAnalystGroup=env.OIDC_ANALYST_GROUP; config.requireIndependentPolicyApproval=env.REQUIRE_INDEPENDENT_POLICY_APPROVAL==='true'; config.requirePQManagement=env.REQUIRE_PQ_MANAGEMENT_CHANNEL!=='false'; if(u.protocol==='https:'&&!config.requirePQManagement)throw Error('Remote deployment requires the protected management channel'); config.aiEndpointId=env.AI_ENDPOINT_ID||'default'; const telemetry=startTelemetry(); const siem=startSIEM(store,resolve(env.DATA_DIR||'data')); config.siemStatus=()=>siem.status(); config.siemControl=siem; const retention=startAuditRetention(store,siem,{days:Number(env.AUDIT_RETENTION_DAYS||0)}); config.auditRetentionStatus=()=>retention.status(); const server=createApp(store,config).listen(Number(env.PORT||4310),env.HOST||'127.0.0.1',()=>console.log(`SafetyNet management: ${publicUrl}`)); const timer=setInterval(()=>{ for(const table of ['sessions','logins','tickets','enrollments'])store.db.prepare(`DELETE FROM ${table} WHERE expires{store.db.close();await telemetry?.shutdown();process.exit(0);});} process.on('SIGINT',stop);process.on('SIGTERM',stop);