Repository files, collaboration, releases and project activity.
archforge-external-status / tests/domain-setup.test.jsmain
▤ tests/domain-setup.test.js3542 bytes
65 lines · Select a line number for a permalink
1
'use strict';2
const test=require('node:test');3
const assert=require('node:assert/strict');4
const fs=require('node:fs');5
const os=require('node:os');6
const path=require('node:path');7
const {spawnSync}=require('node:child_process');8
const LIB=path.resolve(__dirname,'../scripts/domain-lib.sh');9
function run(cmd,args=[]){10
return spawnSync('bash',['-c',`set -Eeuo pipefail; source "$1"; ${cmd}`,'bash',LIB,...args],{encoding:'utf8'});11
}12
test('valid DNS hostnames only (reject injection, wildcards, invalid labels)',()=>{13
for(const hostname of ['status.archforge.nl','sub-domain.example.org','a.b']){14
const out=run('af_valid_domain "$2"',[hostname]);15
assert.equal(out.status,0,`${hostname}: ${out.stderr}`);16
}17
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']){18
assert.notEqual(run('af_valid_domain "$2"',[hostname]).status,0,hostname);19
}20
});21
test('IPv4/IPv6 and ACME e-mail validation',()=>{22
assert.equal(run('af_valid_ipv4 "$2"',['203.0.113.42']).status,0);23
assert.notEqual(run('af_valid_ipv4 "$2"',['256.1.2.3']).status,0);24
assert.notEqual(run('af_valid_ipv4 "$2"',['01.2.3.4']).status,0);25
assert.equal(run('af_valid_ipv6 "$2"',['2001:db8::1']).status,0);26
assert.notEqual(run('af_valid_ipv6 "$2"',['anything']).status,0);27
assert.equal(run('af_valid_email "$2"',['ops@example.org']).status,0);28
assert.notEqual(run('af_valid_email "$2"',['ops@example.org\nmalicious']).status,0);29
});30
test('Caddy site snippet cannot inject directives',()=>{31
const valid=run('af_render_caddy "$2" "$3"',['status.archforge.nl','ops@example.org']);32
assert.equal(valid.status,0);33
assert.match(valid.stdout,/^status\.archforge\.nl \{/);34
assert.match(valid.stdout,/reverse_proxy 127\.0\.0\.1:3000/);35
assert.match(valid.stdout,/tls ops@example\.org/);36
assert.notEqual(run('af_render_caddy "$2" "$3"',['example.org\nfoo {','']).status,0);37
});38
test('domain change preserves all secrets, permissions and existing non-domain lines',()=>{39
const dir=fs.mkdtempSync(path.join(os.tmpdir(),'archforge-domain-'));40
try{41
const env=path.join(dir,'status.env');42
fs.writeFileSync(env,'NODE_ENV=production\nSTATUS_PUBLIC_URL=https://old.example.org\nSTATUS_ENCRYPTION_KEY=aabbcc\nSMTP_PASSWORD=very#private=secret\n');43
fs.chmodSync(env,0o640);44
const res=run('af_set_public_domain "$2" "$3"; af_read_public_domain "$2"',[env,'status.archforge.nl']);45
assert.equal(res.status,0,res.stderr);46
assert.equal(res.stdout,'status.archforge.nl');47
const body=fs.readFileSync(env,'utf8');48
assert.match(body,/STATUS_PUBLIC_URL=https:\/\/status\.archforge\.nl/);49
assert.match(body,/STATUS_ENCRYPTION_KEY=aabbcc/);50
assert.match(body,/SMTP_PASSWORD=very#private=secret/);51
assert.equal(fs.statSync(env).mode & 0o777,0o640);52
assert.equal(body.match(/^STATUS_PUBLIC_URL=/gm).length,1);53
} finally{fs.rmSync(dir,{recursive:true,force:true});}54
});55
test('SSL script cannot be run in wrong environment or as non-root',()=>{56
const script=path.resolve(__dirname,'../configure-domain.sh');57
const data=fs.readFileSync(script,'utf8');58
assert.match(data,/scripts\/configure-domain\.sh/);59
const source=fs.readFileSync(path.resolve(__dirname,'../scripts/configure-domain.sh'),'utf8');60
assert.match(source,/Debian 13 only/);61
assert.match(source,/Caddy validation failed/);62
assert.match(source,/TLS: NOT YET VERIFIED/);63
assert.match(source,/restore_previous/);64
});