Skip to content

Repository files, collaboration, releases and project activity.

ARCHFORGE HISTORY

Blame · tests/domain-setup.test.js

Branch main · the Commit author is not necessarily a verified ArchForge account.

b8619f148earchadmin2026-10-111 'use strict';
b8619f148earchadmin2026-10-112 const test=require('node:test');
b8619f148earchadmin2026-10-113 const assert=require('node:assert/strict');
b8619f148earchadmin2026-10-114 const fs=require('node:fs');
b8619f148earchadmin2026-10-115 const os=require('node:os');
b8619f148earchadmin2026-10-116 const path=require('node:path');
b8619f148earchadmin2026-10-117 const {spawnSync}=require('node:child_process');
b8619f148earchadmin2026-10-118 const LIB=path.resolve(__dirname,'../scripts/domain-lib.sh');
b8619f148earchadmin2026-10-119 function run(cmd,args=[]){
b8619f148earchadmin2026-10-1110  return spawnSync('bash',['-c',`set -Eeuo pipefail; source "$1"; ${cmd}`,'bash',LIB,...args],{encoding:'utf8'});
b8619f148earchadmin2026-10-1111 }
b8619f148earchadmin2026-10-1112 test('valid DNS hostnames only (reject injection, wildcards, invalid labels)',()=>{
b8619f148earchadmin2026-10-1113  for(const hostname of ['status.archforge.nl','sub-domain.example.org','a.b']){
b8619f148earchadmin2026-10-1114  const out=run('af_valid_domain "$2"',[hostname]);
b8619f148earchadmin2026-10-1115  assert.equal(out.status,0,`${hostname}: ${out.stderr}`);
b8619f148earchadmin2026-10-1116  }
b8619f148earchadmin2026-10-1117  for(const hostname of ['localhost','-bad.example','bad-.example','bad..example','a.b;rm -rf /','*.example.com','a_underscore.com','a'.repeat(64)+'.com','example.com\nimport /etc/passwd']){
b8619f148earchadmin2026-10-1118  assert.notEqual(run('af_valid_domain "$2"',[hostname]).status,0,hostname);
b8619f148earchadmin2026-10-1119  }
b8619f148earchadmin2026-10-1120 });
b8619f148earchadmin2026-10-1121 test('IPv4/IPv6 and ACME e-mail validation',()=>{
b8619f148earchadmin2026-10-1122  assert.equal(run('af_valid_ipv4 "$2"',['203.0.113.42']).status,0);
b8619f148earchadmin2026-10-1123  assert.notEqual(run('af_valid_ipv4 "$2"',['256.1.2.3']).status,0);
b8619f148earchadmin2026-10-1124  assert.notEqual(run('af_valid_ipv4 "$2"',['01.2.3.4']).status,0);
b8619f148earchadmin2026-10-1125  assert.equal(run('af_valid_ipv6 "$2"',['2001:db8::1']).status,0);
b8619f148earchadmin2026-10-1126  assert.notEqual(run('af_valid_ipv6 "$2"',['anything']).status,0);
b8619f148earchadmin2026-10-1127  assert.equal(run('af_valid_email "$2"',['ops@example.org']).status,0);
b8619f148earchadmin2026-10-1128  assert.notEqual(run('af_valid_email "$2"',['ops@example.org\nmalicious']).status,0);
b8619f148earchadmin2026-10-1129 });
b8619f148earchadmin2026-10-1130 test('Caddy site snippet cannot inject directives',()=>{
b8619f148earchadmin2026-10-1131  const valid=run('af_render_caddy "$2" "$3"',['status.archforge.nl','ops@example.org']);
b8619f148earchadmin2026-10-1132  assert.equal(valid.status,0);
b8619f148earchadmin2026-10-1133  assert.match(valid.stdout,/^status\.archforge\.nl \{/);
b8619f148earchadmin2026-10-1134  assert.match(valid.stdout,/reverse_proxy 127\.0\.0\.1:3000/);
b8619f148earchadmin2026-10-1135  assert.match(valid.stdout,/tls ops@example\.org/);
b8619f148earchadmin2026-10-1136  assert.notEqual(run('af_render_caddy "$2" "$3"',['example.org\nfoo {','']).status,0);
b8619f148earchadmin2026-10-1137 });
b8619f148earchadmin2026-10-1138 test('domain change preserves all secrets, permissions and existing non-domain lines',()=>{
b8619f148earchadmin2026-10-1139  const dir=fs.mkdtempSync(path.join(os.tmpdir(),'archforge-domain-'));
b8619f148earchadmin2026-10-1140  try{
b8619f148earchadmin2026-10-1141  const env=path.join(dir,'status.env');
b8619f148earchadmin2026-10-1142  fs.writeFileSync(env,'NODE_ENV=production\nSTATUS_PUBLIC_URL=https://old.example.org\nSTATUS_ENCRYPTION_KEY=aabbcc\nSMTP_PASSWORD=very#private=secret\n');
b8619f148earchadmin2026-10-1143  fs.chmodSync(env,0o640);
b8619f148earchadmin2026-10-1144  const res=run('af_set_public_domain "$2" "$3"; af_read_public_domain "$2"',[env,'status.archforge.nl']);
b8619f148earchadmin2026-10-1145  assert.equal(res.status,0,res.stderr);
b8619f148earchadmin2026-10-1146  assert.equal(res.stdout,'status.archforge.nl');
b8619f148earchadmin2026-10-1147  const body=fs.readFileSync(env,'utf8');
b8619f148earchadmin2026-10-1148  assert.match(body,/STATUS_PUBLIC_URL=https:\/\/status\.archforge\.nl/);
b8619f148earchadmin2026-10-1149  assert.match(body,/STATUS_ENCRYPTION_KEY=aabbcc/);
b8619f148earchadmin2026-10-1150  assert.match(body,/SMTP_PASSWORD=very#private=secret/);
b8619f148earchadmin2026-10-1151  assert.equal(fs.statSync(env).mode & 0o777,0o640);
b8619f148earchadmin2026-10-1152  assert.equal(body.match(/^STATUS_PUBLIC_URL=/gm).length,1);
b8619f148earchadmin2026-10-1153  } finally{fs.rmSync(dir,{recursive:true,force:true});}
b8619f148earchadmin2026-10-1154 });
b8619f148earchadmin2026-10-1155 test('SSL script cannot be run in wrong environment or as non-root',()=>{
b8619f148earchadmin2026-10-1156  const script=path.resolve(__dirname,'../configure-domain.sh');
b8619f148earchadmin2026-10-1157  const data=fs.readFileSync(script,'utf8');
b8619f148earchadmin2026-10-1158  assert.match(data,/scripts\/configure-domain\.sh/);
b8619f148earchadmin2026-10-1159  const source=fs.readFileSync(path.resolve(__dirname,'../scripts/configure-domain.sh'),'utf8');
b8619f148earchadmin2026-10-1160  assert.match(source,/Debian 13 only/);
b8619f148earchadmin2026-10-1161  assert.match(source,/Caddy validation failed/);
b8619f148earchadmin2026-10-1162  assert.match(source,/TLS: NOT YET VERIFIED/);
b8619f148earchadmin2026-10-1163  assert.match(source,/restore_previous/);
b8619f148earchadmin2026-10-1164 });