Auth-herding: roller, kontoadmin, token-revokering + søkbar planliste + neon
Auth (app-modus):
- Roller admin/standard. Admin oppretter/sletter kontoer, resetter passord,
endrer roller (konto-modal). Eksisterende brukere → admin ved migrering;
bootstrap-bruker via proxy-bypass → admin. Siste admin vernet.
- Tilbakekalling via per-bruker epoke i tokenet: passordbytte, admin-reset,
«Logg ut alle enheter» og sletting dreper alle aktive sesjoner. Token-format
endret (3- → 4-delt) — alle logges ut én gang ved oppgradering.
Dagsplan: søkbar/velgbar planliste («📋 Planer») avledet fra planIndex —
finn plan på navn/dato/person uten å gjette dato.
GUI: login-neon trukket inn i hovedappen (header/knapper/KPI-kanter), og
login-siden fikk mer tech (HUD-hjørner, glitch-tittel, scanlines).
40 integrasjonstester (6 nye), alle grønne. README + CLAUDE.md oppdatert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
f6268440d9
commit
3f69cd4248
9 changed files with 518 additions and 36 deletions
|
|
@ -508,3 +508,72 @@ test('proxy-modus (default): ingen guard, alt åpent', async () => {
|
|||
assert.equal(res.status, 200);
|
||||
assert.equal((await res.json()).auth.mode, 'proxy');
|
||||
});
|
||||
|
||||
// ---------- Roller, admin og tilbakekalling ----------
|
||||
// jon fikk admin via bootstrap (proxy-bypass) i en tidligere test; passord = 'hemmelig123'.
|
||||
|
||||
test('app-auth: bootstrap-bruker ble admin', async () => {
|
||||
const res = await aReq('GET', '/api/auth/users', undefined, { 'X-Remote-User': 'jon' });
|
||||
assert.equal(res.status, 200);
|
||||
const { users } = await res.json();
|
||||
const jon = users.find(u => u.user === 'jon');
|
||||
assert.equal(jon.role, 'admin');
|
||||
});
|
||||
|
||||
test('app-auth: admin oppretter standard-bruker; standard er ikke admin', async () => {
|
||||
let res = await aReq('POST', '/api/auth/users', { user: 'kari', password: 'karipass1', role: 'standard' }, { 'X-Remote-User': 'jon' });
|
||||
assert.equal(res.status, 201);
|
||||
|
||||
// kari (via proxy-bypass, men finnes som standard) får ikke admin-endepunkt
|
||||
res = await aReq('GET', '/api/auth/users', undefined, { 'X-Remote-User': 'kari' });
|
||||
assert.equal(res.status, 403);
|
||||
});
|
||||
|
||||
test('app-auth: passordbytte tilbakekaller gamle tokens', async () => {
|
||||
let res = await aReq('POST', '/api/auth/login', { user: 'jon', password: 'hemmelig123' });
|
||||
const oldCookie = cookieFrom(res);
|
||||
assert.ok(oldCookie);
|
||||
|
||||
res = await aReq('POST', '/api/auth/password', { current: 'hemmelig123', password: 'jonpass2' }, { Cookie: oldCookie });
|
||||
assert.equal(res.status, 200);
|
||||
const newCookie = cookieFrom(res);
|
||||
|
||||
// Gammel cookie er nå ugyldig (epoke bumpet), ny virker
|
||||
res = await aReq('GET', '/api/state', undefined, { Cookie: oldCookie });
|
||||
assert.equal(res.status, 401);
|
||||
res = await aReq('GET', '/api/state', undefined, { Cookie: newCookie });
|
||||
assert.equal(res.status, 200);
|
||||
});
|
||||
|
||||
test('app-auth: logg ut alle enheter dreper andre økter, beholder denne', async () => {
|
||||
const a = cookieFrom(await aReq('POST', '/api/auth/login', { user: 'jon', password: 'jonpass2' }));
|
||||
const b = cookieFrom(await aReq('POST', '/api/auth/login', { user: 'jon', password: 'jonpass2' }));
|
||||
const res = await aReq('POST', '/api/auth/logout-all', undefined, { Cookie: a });
|
||||
const aNew = cookieFrom(res);
|
||||
// b (eldre epoke) er død, a fornyet virker
|
||||
assert.equal((await aReq('GET', '/api/state', undefined, { Cookie: b })).status, 401);
|
||||
assert.equal((await aReq('GET', '/api/state', undefined, { Cookie: aNew })).status, 200);
|
||||
});
|
||||
|
||||
test('app-auth: kan ikke slette egen konto eller demote siste admin', async () => {
|
||||
let res = await aReq('DELETE', '/api/auth/users/jon', undefined, { 'X-Remote-User': 'jon' });
|
||||
assert.equal(res.status, 400);
|
||||
res = await aReq('PUT', '/api/auth/users/jon/role', { role: 'standard' }, { 'X-Remote-User': 'jon' });
|
||||
assert.equal(res.status, 400); // siste admin
|
||||
});
|
||||
|
||||
test('app-auth: admin endrer rolle og resetter passord (logger ut brukeren)', async () => {
|
||||
// kari logger inn
|
||||
const kariCookie = cookieFrom(await aReq('POST', '/api/auth/login', { user: 'kari', password: 'karipass1' }));
|
||||
assert.ok(kariCookie);
|
||||
|
||||
// jon (admin) resetter karis passord → karis token dør
|
||||
let res = await aReq('POST', '/api/auth/users/kari/password', { password: 'nyttkari1' }, { 'X-Remote-User': 'jon' });
|
||||
assert.equal(res.status, 200);
|
||||
assert.equal((await aReq('GET', '/api/state', undefined, { Cookie: kariCookie })).status, 401);
|
||||
|
||||
// jon gjør kari til admin
|
||||
res = await aReq('PUT', '/api/auth/users/kari/role', { role: 'admin' }, { 'X-Remote-User': 'jon' });
|
||||
assert.equal(res.status, 200);
|
||||
assert.equal((await res.json()).role, 'admin');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue