Files
GDPR-Content-Blocker/license-backend/test/util.test.mjs
s4luorth ecb5e1bd22 chore: monorepo - plugin, backend und hilfsdaten in einem repo
- Eltern-Ordner ist jetzt EIN Git-Repo (statt getrennter Repos).
- root .gitignore haelt Secrets (.env), node_modules, DB und Build-Artefakte raus.
- release.ps1: manueller Release (ZIP bauen + ans Backend laden).
- root README mit Struktur und Release-Ablauf.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:41:38 +02:00

51 lines
2.5 KiB
JavaScript

import { generateKey, normalizeDomain, safeEqual, isExpired, compareVersions, signToken, verifyToken } from '../src/util.js';
let fail = 0;
const ok = (name, cond) => { console.log((cond ? '[PASS] ' : '[FAIL] ') + name); if (!cond) fail++; };
// Key format
const k = generateKey();
ok('key format XXXX-XXXX-XXXX-XXXX', /^[A-Z2-9]{4}-[A-Z2-9]{4}-[A-Z2-9]{4}-[A-Z2-9]{4}$/.test(k));
ok('no ambiguous chars (0OI1L)', !/[0OI1L]/.test(k));
const keys = new Set(Array.from({ length: 1000 }, () => generateKey()));
ok('1000 keys unique', keys.size === 1000);
// Domain normalization
ok('strip https + www', normalizeDomain('https://www.Example.com/') === 'example.com');
ok('strip path', normalizeDomain('http://example.com/foo/bar') === 'example.com');
ok('strip port', normalizeDomain('example.com:8080') === 'example.com');
ok('subdomain kept', normalizeDomain('https://shop.example.com/x') === 'shop.example.com');
ok('empty stays empty', normalizeDomain('') === '');
ok('null safe', normalizeDomain(null) === '');
// safeEqual
ok('safeEqual match', safeEqual('abc123', 'abc123') === true);
ok('safeEqual mismatch', safeEqual('abc', 'abd') === false);
ok('safeEqual length diff', safeEqual('abc', 'abcd') === false);
// isExpired
ok('no expiry = not expired', isExpired(null) === false);
ok('past = expired', isExpired('2000-01-01T00:00:00Z') === true);
ok('future = not expired', isExpired('2999-01-01T00:00:00Z') === false);
ok('garbage = not expired', isExpired('not-a-date') === false);
// compareVersions
ok('1.1.0 > 1.0.0', compareVersions('1.1.0', '1.0.0') === 1);
ok('1.0.0 < 1.0.1', compareVersions('1.0.0', '1.0.1') === -1);
ok('1.0 == 1.0.0', compareVersions('1.0', '1.0.0') === 0);
ok('2.0.0 > 1.9.9', compareVersions('2.0.0', '1.9.9') === 1);
ok('10.0 > 9.0 (numeric not lexical)', compareVersions('10.0', '9.0') === 1);
// signToken / verifyToken
const secret = 'top-secret';
const tok = signToken({ k: 'KEY', p: 'gdpr-content-blocker', v: '1.1.0', exp: Date.now() + 10000 }, secret);
const payload = verifyToken(tok, secret);
ok('token round-trips', payload && payload.k === 'KEY' && payload.v === '1.1.0');
ok('wrong secret → null', verifyToken(tok, 'other') === null);
ok('tampered body → null', verifyToken('x' + tok, secret) === null);
ok('expired token → null', verifyToken(signToken({ exp: Date.now() - 1 }, secret), secret) === null);
ok('garbage token → null', verifyToken('not-a-token', secret) === null);
console.log('\n' + (fail === 0 ? 'ALL PASSED' : fail + ' FAILED'));
process.exit(fail === 0 ? 0 : 1);