Skip to content

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-111 'use strict';
e59b7f7cc6archadmin2026-10-112 const test=require('node:test'),assert=require('node:assert/strict'),crypto=require('node:crypto');
e59b7f7cc6archadmin2026-10-113 const {openDatabase,one,run,now}=require('../src/database'),{makeApp}=require('../src/server'),{base32Encode,totp,passwordHash,encrypt}=require('../src/security');
e59b7f7cc6archadmin2026-10-114 const key=crypto.randomBytes(32).toString('hex');
e59b7f7cc6archadmin2026-10-115 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-116 let app,base;
e59b7f7cc6archadmin2026-10-117 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-118 test.after(async()=>{await app.close();});
e59b7f7cc6archadmin2026-10-119 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-1110 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-1111 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-1112 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-1113 test('admin requires valid password and time-based one-time password',async()=>{
e59b7f7cc6archadmin2026-10-1114  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-1115  const r=await fetch(base+'/admin/login');const cookie=r.headers.get('set-cookie').split(';')[0],csrf=cookie.split('=')[1];
e59b7f7cc6archadmin2026-10-1116  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-1117  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-1118 });