Skip to content

Repository files, collaboration, releases and project activity.

archforge-external-status / tests/http.test.jsmain
▤ tests/http.test.js3888 bytes
19 lines · Select a line number for a permalink
1'use strict';
2const test=require('node:test'),assert=require('node:assert/strict'),crypto=require('node:crypto');
3const {openDatabase,one,run,now}=require('../src/database'),{makeApp}=require('../src/server'),{base32Encode,totp,passwordHash,encrypt}=require('../src/security');
4const key=crypto.randomBytes(32).toString('hex');
5const 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};
6let app,base;
7test.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}`;});
8test.after(async()=>{await app.close();});
9test('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/);});
10test('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/);});
11test('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'));});
12test('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);});
13test('admin requires valid password and time-based one-time password',async()=>{
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));
15 const r=await fetch(base+'/admin/login');const cookie=r.headers.get('set-cookie').split(';')[0],csrf=cookie.split('=')[1];
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);
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/);
18});