syncova-policies/tests/unit/security.test.ts
Weapie 265ca8ac38
All checks were successful
Container-Image bauen und veröffentlichen / build-and-push (push) Successful in 5m15s
Improve accessibility and access controls; verify production and database recovery
2026-09-14 11:44:41 +02:00

43 lines
2.6 KiB
TypeScript

import { test } from 'node:test'
import assert from 'node:assert/strict'
import { canUseSession } from '../../lib/session-access'
import { EMPTY_SITE_PAGES, isSafeMediaUrl, isAllowedEmbedUrl, validateSitePages } from '../../lib/site-pages'
import { validateUserInput } from '../../lib/user-validation'
test('sessions fail closed after account changes, deletion or suspension', () => {
const user = { role: 'ADMIN', isActive: true, updatedAt: new Date(1000) }
assert.equal(canUseSession(user, 1001), true)
for (const candidate of [null, {...user,isActive:false}, {...user,role:'USER'}, {...user,updatedAt:new Date(2000)}])
assert.equal(canUseSession(candidate, 1001), false)
assert.equal(canUseSession(user, undefined), false)
})
test('media allowlist rejects normalized foreign origins and credentials', () => {
for (const url of ['//evil.example/a', '/'+String.fromCharCode(92)+'evil.example/a','javascript:alert(1)','https://evil.example/a','https://signlanguage.alangu.de.evil.example/a','https://user:pass@signlanguage.alangu.de/player/'])
assert.equal(isSafeMediaUrl(url), false, url)
assert.equal(isSafeMediaUrl('/videos/dgs.mp4'), true)
assert.equal(isAllowedEmbedUrl('https://signlanguage.alangu.de/player/?subtitle=true'), true)
})
test('partial updates, placeholder publication and unpublishing are rejected', () => {
const previous = {...EMPTY_SITE_PAGES, accessibility:'Veröffentlichte Erklärung'}
assert.ok(validateSitePages({}, previous).length)
assert.ok(validateSitePages({...EMPTY_SITE_PAGES}, previous).length)
assert.ok(validateSitePages({...previous,accessibility:'{{STATUS}}'},previous).length)
assert.deepEqual(validateSitePages({...previous,accessibility:'Neue Erklärung'},previous),[])
})
test('user input rejects unexpected roles, invalid types and bcrypt truncation', () => {
const valid={email:'admin@example.org',role:'ADMIN',password:'A-safe-test-password'}
assert.equal(validateUserInput(valid,true),null)
for (const data of [{...valid,role:'ROOT'},{...valid,password:123},{...valid,password:'ü'.repeat(40)},{...valid,isActive:'false'}])
assert.ok(validateUserInput(data,true))
})
test('policy inputs reject objects and booleans in text fields without throwing', async () => {
const {parsePolicyInput}=await import('../../lib/policy-input')
for(const value of [null,[],{title:123},{recipients:{}},{isPublic:'false'},{legalBasis:['text']}])
assert.equal(parsePolicyInput(value),null)
const data=parsePolicyInput({title:' Beispiel ',processingDescription:'Verarbeitung',recipients:'Amt',isPublic:false})
assert.equal(data?.title,'Beispiel')
assert.equal(data?.isPublic,false)
assert.equal(data?.responsible,null)
})