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') })