Files
dockhand-upstream/tests/encryption-prefix-bypass.test.ts
T

42 lines
1.7 KiB
TypeScript

/**
* Regression test for audit LOW #1/#40: a secret that literally starts with the
* reserved "enc:v1:" prefix was passed through encrypt() unchanged and stored as
* PLAINTEXT. encrypt() now only skips re-encrypting values that are genuinely our
* ciphertext (valid prefix AND a decodable, long-enough payload).
*/
import assert from 'node:assert/strict';
import { describe, it, before } from 'node:test';
import { encrypt, decrypt, looksLikeCiphertext } from '../src/lib/server/encryption';
before(() => {
// Deterministic key so encrypt/decrypt round-trip in the test env.
process.env.ENCRYPTION_KEY ||= Buffer.alloc(32, 7).toString('base64');
});
describe('encryption reserved-prefix bypass (audit #1/#40)', () => {
it('encrypts a password that starts with the reserved prefix (no plaintext leak)', () => {
const pw = 'enc:v1:hunter2';
const enc = encrypt(pw)!;
assert.notEqual(enc, pw, 'must not store the prefixed password verbatim');
assert.equal(decrypt(enc), pw, 'must round-trip back to the original');
});
it('looksLikeCiphertext is false for a plaintext that merely starts with the prefix', () => {
assert.equal(looksLikeCiphertext('enc:v1:hunter2'), false);
assert.equal(looksLikeCiphertext('enc:v1:'), false);
assert.equal(looksLikeCiphertext('enc:v1:!!!not-base64!!!'), false);
});
it('looksLikeCiphertext is true for a real encrypted blob, and it is not double-encrypted', () => {
const enc = encrypt('some-secret')!;
assert.equal(looksLikeCiphertext(enc), true);
assert.equal(encrypt(enc), enc, 'genuine ciphertext must not be re-encrypted');
});
it('normal passwords still round-trip', () => {
const n = 'S3cr3t-P@ss';
assert.equal(decrypt(encrypt(n)!), n);
});
});