Files
Webklar-Kundenbereich/test/previewEnv.test.js
T
2026-09-30 21:53:41 +00:00

104 lines
4.4 KiB
JavaScript

import { test } from 'node:test'
import assert from 'node:assert/strict'
import crypto from 'node:crypto'
import {
encryptEnv, decryptEnv, validateEnvChange, envNames, maskLog, envKey,
} from '../server/services/previewEnv.js'
const key = crypto.randomBytes(32)
test('Round-Trip und Format', () => {
const s = encryptEnv({ A: 'x', B: 'ü' }, key)
assert.match(s, /^v1:[^:]+:[^:]+:[^:]+$/)
assert.deepEqual(decryptEnv(s, key), { A: 'x', B: 'ü' })
assert.notEqual(encryptEnv({ A: 'x' }, key), encryptEnv({ A: 'x' }, key))
})
test('leer', () => {
assert.deepEqual(decryptEnv(encryptEnv({}, key), key), {})
assert.deepEqual(decryptEnv('', key), {})
assert.deepEqual(decryptEnv(null, key), {})
})
test('falscher Schluessel und manipulierter Tag => Fehler', () => {
const s = encryptEnv({ A: 'geheim' }, key)
assert.throws(() => decryptEnv(s, crypto.randomBytes(32)))
const p = s.split(':')
const tag = Buffer.from(p[2], 'base64')
tag[0] ^= 1
p[2] = tag.toString('base64')
assert.throws(() => decryptEnv(p.join(':'), key))
assert.throws(() => decryptEnv('v2:a:b:c', key))
})
test('envNames sortiert', () => {
assert.deepEqual(envNames(encryptEnv({ B: '1', A: '2' }, key), key), ['A', 'B'])
assert.deepEqual(envNames('', key), [])
})
test('envKey', () => {
const old = process.env.PREVIEW_ENV_KEY
try {
delete process.env.PREVIEW_ENV_KEY
assert.equal(envKey(), null)
process.env.PREVIEW_ENV_KEY = Buffer.alloc(16).toString('base64')
assert.equal(envKey(), null)
process.env.PREVIEW_ENV_KEY = key.toString('base64')
assert.ok(envKey().equals(key))
} finally {
if (old === undefined) delete process.env.PREVIEW_ENV_KEY
else process.env.PREVIEW_ENV_KEY = old
}
})
test('validateEnvChange', () => {
let r = validateEnvChange({ A: '1' }, { set: { B: '2' }, remove: ['A', 'NIX'] })
assert.deepEqual(r, { ok: true, env: { B: '2' } })
assert.equal(validateEnvChange({}, { set: { abc: '1' } }).ok, false)
assert.equal(validateEnvChange({}, { set: { '1A': '1' } }).ok, false)
assert.equal(validateEnvChange({}, { set: { A: 'x'.repeat(4097) } }).ok, false)
assert.equal(validateEnvChange({}, { set: { A: 'x'.repeat(4096) } }).ok, true)
assert.equal(validateEnvChange({}, { set: { A: 'ü'.repeat(2049) } }).ok, false)
assert.equal(validateEnvChange({}, { set: { A: 1 } }).ok, false)
assert.equal(validateEnvChange({}, { set: { A: 'a\nb' } }).ok, false)
assert.equal(validateEnvChange({}, { set: { A: 'a\0b' } }).ok, false)
const many = Object.fromEntries(Array.from({ length: 31 }, (_, i) => [`V${i}`, '1']))
r = validateEnvChange({}, { set: many })
assert.equal(r.ok, false)
assert.match(r.error, /30/)
const thirty = Object.fromEntries(Array.from({ length: 30 }, (_, i) => [`V${i}`, '1']))
assert.equal(validateEnvChange(thirty, { set: { V0: '2' } }).ok, true)
assert.equal(validateEnvChange(thirty, { set: { NEU: '2' }, remove: ['V1'] }).ok, true)
assert.equal(validateEnvChange(thirty, { set: { NEU: '2' } }).ok, false)
assert.equal(validateEnvChange({}, {}).ok, true)
})
test('maskLog', () => {
const env = { A: 'geheim', B: 'abc', C: 'geheimer' , D: 'a.b+'}
assert.equal(maskLog('x geheimer y geheim z abc a.b+ axbb', env), 'x ••• y ••• z abc ••• axbb')
assert.equal(maskLog('', env), '')
assert.equal(maskLog('text', {}), 'text')
})
test('gekuerzter Tag, falsche IV-Laenge, manipulierter Ciphertext => Fehler', () => {
const p = encryptEnv({ A: 'geheim' }, key).split(':')
const b = (i) => Buffer.from(p[i], 'base64')
const join = (x) => x.join(':')
const short = [...p]; short[2] = b(2).subarray(0, 8).toString('base64')
assert.throws(() => decryptEnv(join(short), key))
const iv = [...p]; iv[1] = b(1).subarray(0, 8).toString('base64')
assert.throws(() => decryptEnv(join(iv), key))
const ct = [...p]; const c = b(3); c[0] ^= 1; ct[3] = c.toString('base64')
assert.throws(() => decryptEnv(join(ct), key))
})
test('entschluesselter Inhalt muss Objekt mit String-Werten sein', () => {
for (const bad of [['x'], 'text', { A: 1 }, null]) {
const iv = crypto.randomBytes(12)
const c = crypto.createCipheriv('aes-256-gcm', key, iv, { authTagLength: 16 })
const ct = Buffer.concat([c.update(JSON.stringify(bad), 'utf8'), c.final()])
const s = ['v1', iv, c.getAuthTag(), ct].map((x) => (typeof x === 'string' ? x : x.toString('base64'))).join(':')
assert.throws(() => decryptEnv(s, key))
}
})