Skip to content

Repository files, collaboration, releases and project activity.

archforge-external-status / src/config.jsmain
▤ src/config.js2723 bytes
46 lines · Select a line number for a permalink
1'use strict';
2const fs=require('node:fs');
3const {URL}=require('node:url');
4function loadEnv(file=process.env.STATUS_ENV_FILE || '/etc/archforge-status/status.env') {
5 if (!fs.existsSync(file)) return;
6 for(const row of fs.readFileSync(file,'utf8').split(/\r?\n/)){
7 const line=row.trim(); if(!line||line.startsWith('#'))continue;
8 const match=line.match(/^([A-Z][A-Z0-9_]*)=(.*)$/); if(!match)continue;
9 if(process.env[match[1]]===undefined) {
10 let v=match[2].trim(); if(/^".*"$/.test(v))v=v.slice(1,-1).replace(/\\n/g,'\n');
11 process.env[match[1]]=v;
12 }
13 }
15function boundedInt(val,def,min,max){let n=Number(val);return Number.isInteger(n)&&n>=min&&n<=max?n:def;}
16function urlValue(value,def){try{const u=new URL(value||def);if(u.protocol!=='https:'||u.username||u.password||u.hash)throw Error('invalid');return u.toString();}catch{throw new Error('URL must use HTTPS: '+(value||def));}}
17function readConfig(){
18 loadEnv();
19 const website=urlValue(process.env.TARGET_WEBSITE,'https://archforge.nl');
20 const status=urlValue(process.env.STATUS_PUBLIC_URL,'https://status.archforge.nl');
21 const websiteHost=new URL(website).hostname;
22 const api=process.env.TARGET_API_URL?urlValue(process.env.TARGET_API_URL):'';
23 const gitHttp=process.env.TARGET_GIT_HTTP_URL?urlValue(process.env.TARGET_GIT_HTTP_URL):'';
24 // Disallow off-site targets; prevents DNS rebinding and arbitrary probe destinations via env changes.
25 for(const u of [api,gitHttp].filter(Boolean))if(new URL(u).hostname!==websiteHost)throw Error('Probe hostname must equal TARGET_WEBSITE host');
26 const key=process.env.STATUS_ENCRYPTION_KEY||'';
27 if(!/^[a-f0-9]{64}$/i.test(key) && process.env.NODE_ENV==='production')throw Error('STATUS_ENCRYPTION_KEY must be 32 random bytes in hex');
28 return {
29 port:boundedInt(process.env.PORT,3000,1,65535),
30 host:process.env.STATUS_LISTEN_HOST||'127.0.0.1',
31 publicUrl:status,website,websiteHost,api,gitHttp,
32 gitHost:process.env.TARGET_GIT_SSH_HOST||websiteHost,
33 gitPort:boundedInt(process.env.TARGET_GIT_SSH_PORT,22,1,65535),
34 interval:boundedInt(process.env.MONITOR_INTERVAL_SECONDS,60,30,3600)*1000,
35 failures:boundedInt(process.env.MONITOR_FAILURE_THRESHOLD,3,2,20),
36 recoveries:boundedInt(process.env.MONITOR_RECOVERY_THRESHOLD,2,1,20),
37 timeout:boundedInt(process.env.MONITOR_TIMEOUT_MS,8000,1000,25000),
38 discord:process.env.STATUS_DISCORD_WEBHOOK_URL||'',
39 smtpFrom:process.env.SMTP_FROM||'',
40 smtpAvailable:!!(process.env.SMTP_HOST&&process.env.SMTP_FROM),
41 key, dbPath:process.env.STATUS_DB_PATH||'/var/lib/archforge-status/status.db',
42 test:process.env.NODE_ENV==='test'
43 };
45module.exports={loadEnv,readConfig,boundedInt,urlValue};