Repository files, collaboration, releases and project activity.
ARCHFORGE HISTORY
Blame · tests/http.test.js
Branch main · the Commit author is not necessarily a verified ArchForge account.
e59b7f7cc6archadmin2026-10-11
1 'use strict';e59b7f7cc6archadmin2026-10-11
2 const test=require('node:test'),assert=require('node:assert/strict'),crypto=require('node:crypto');e59b7f7cc6archadmin2026-10-11
3 const {openDatabase,one,run,now}=require('../src/database'),{makeApp}=require('../src/server'),{base32Encode,totp,passwordHash,encrypt}=require('../src/security');e59b7f7cc6archadmin2026-10-11
4 const key=crypto.randomBytes(32).toString('hex');e59b7f7cc6archadmin2026-10-11
5 const cfg={key,dbPath:':memory:',publicUrl:'https://status.archforge.nl/',website:'https://archforge.nl/',websiteHost:'archforge.nl',api:'',gitHttp:'',gitHost:'archforge.nl',gitPort:22,discord:'',smtpAvailable:false,smtpFrom:'',failures:3,recoveries:2,timeout:2000,interval:60000,host:'127.0.0.1',port:0,test:true};e59b7f7cc6archadmin2026-10-11
6 let app,base;e59b7f7cc6archadmin2026-10-11
7 test.before(async()=>{const db=openDatabase(':memory:');app=makeApp({db,cfg,disableMonitor:true});await new Promise(r=>app.server.listen(0,'127.0.0.1',r));base=`http://127.0.0.1:${app.server.address().port}`;});e59b7f7cc6archadmin2026-10-11
8 test.after(async()=>{await app.close();});e59b7f7cc6archadmin2026-10-11
9 test('public overview uses unknown when there are no checks',async()=>{const r=await fetch(base+'/');const text=await r.text();assert.equal(r.status,200);assert.match(text,/Monitoring in progress/);assert.match(text,/Unknown days are not counted as healthy/);assert.match(text,/status\/style.css|style.css/);});e59b7f7cc6archadmin2026-10-11
10 test('90-day page renders without status badge and bars sharing a row',async()=>{const r=await fetch(base+'/?days=90');const html=await r.text();assert.equal(r.status,200);assert.match(html,/history-bars/);assert.match(html,/month-label/);assert.doesNotMatch(html,/style="--days/);assert.match(html,/90 days/);});e59b7f7cc6archadmin2026-10-11
11 test('public API does not depend on main server',async()=>{const j=await (await fetch(base+'/api/status')).json();assert.equal(j.source,'independent-external-monitor');assert.ok(j.services.find(s=>s.id==='website'));});e59b7f7cc6archadmin2026-10-11
12 test('form requires CSRF and stores no subscription without SMTP',async()=>{const r=await fetch(base+'/subscribe');assert.equal(r.status,200);const cookie=r.headers.get('set-cookie').split(';')[0];const csrf=cookie.split('=')[1];let bad=await fetch(base+'/subscribe',{method:'POST',headers:{'cookie':cookie,'content-type':'application/x-www-form-urlencoded','origin':'https://status.archforge.nl'},body:new URLSearchParams({email:'test@example.com',csrf:'bad'})});assert.equal(bad.status,403);let good=await fetch(base+'/subscribe',{method:'POST',headers:{'cookie':cookie,'content-type':'application/x-www-form-urlencoded','origin':'https://status.archforge.nl'},body:new URLSearchParams({email:'test@example.com',csrf})});assert.equal(good.status,503);assert.equal(one(app.db,'SELECT COUNT(*) c FROM subscriptions').c,0);});e59b7f7cc6archadmin2026-10-11
13 test('admin requires valid password and time-based one-time password',async()=>{e59b7f7cc6archadmin2026-10-11
14 const secret=base32Encode(crypto.randomBytes(20));run(app.db,'INSERT INTO admin(id,username,password_hash,totp_encrypted) VALUES(1,?,?,?)','admin',passwordHash('this-is-a-strong-password'),encrypt(key,secret));e59b7f7cc6archadmin2026-10-11
15 const r=await fetch(base+'/admin/login');const cookie=r.headers.get('set-cookie').split(';')[0],csrf=cookie.split('=')[1];e59b7f7cc6archadmin2026-10-11
16 let bad=await fetch(base+'/admin/login',{method:'POST',redirect:'manual',headers:{'cookie':cookie,'content-type':'application/x-www-form-urlencoded','origin':'https://status.archforge.nl'},body:new URLSearchParams({username:'admin',password:'wrong',totp:totp(secret),csrf})});assert.equal(bad.status,401);e59b7f7cc6archadmin2026-10-11
17 const ok=await fetch(base+'/admin/login',{method:'POST',redirect:'manual',headers:{'cookie':cookie,'content-type':'application/x-www-form-urlencoded','origin':'https://status.archforge.nl'},body:new URLSearchParams({username:'admin',password:'this-is-a-strong-password',totp:totp(secret),csrf})});assert.equal(ok.status,303);assert.equal(ok.headers.get('location'),'/admin');const session=ok.headers.get('set-cookie').split(';')[0];const res=await fetch(base+'/admin',{headers:{cookie:session}});assert.equal(res.status,200);assert.match(await res.text(),/Control center/);e59b7f7cc6archadmin2026-10-11
18 });