mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-09-12 13:48:58 +02:00
48 lines
2.7 KiB
JavaScript
48 lines
2.7 KiB
JavaScript
const { expect } = require("chai");
|
|
require("ts-node/register/transpile-only");
|
|
const { createTokenCipher } = require("../src/core/credential-crypto");
|
|
const { redactSecrets } = require("../src/core/redact-secrets");
|
|
const keys = JSON.stringify({ old: Buffer.alloc(32, 1).toString("base64"), next: Buffer.alloc(32, 2).toString("base64") });
|
|
|
|
describe("credential encryption", () => {
|
|
const cipher = createTokenCipher(keys, "old");
|
|
it("round trips with independent nonces and no plaintext in the envelope", () => {
|
|
const a = cipher.encrypt("secret-token", "owner", "github");
|
|
const b = cipher.encrypt("secret-token", "owner", "github");
|
|
expect(a.nonce).not.to.equal(b.nonce);
|
|
expect(JSON.stringify(a)).not.to.include("secret-token");
|
|
expect(cipher.decrypt(a, "owner", "github")).to.equal("secret-token");
|
|
});
|
|
it("rejects altered envelopes and a different owner/provider", () => {
|
|
const a = cipher.encrypt("secret-token", "owner", "github");
|
|
for (const field of ["nonce", "tag", "ciphertext"]) {
|
|
const bytes = Buffer.from(a[field], "base64"); bytes[0] ^= 1;
|
|
expect(() => cipher.decrypt({ ...a, [field]: bytes.toString("base64") }, "owner", "github")).to.throw("Credential decryption failed");
|
|
}
|
|
for (const patch of [{ version: 2 }, { keyId: "missing" }, { tag: "YQ==" }, { nonce: "!!!!" }]) {
|
|
expect(() => cipher.decrypt({ ...a, ...patch }, "owner", "github")).to.throw();
|
|
}
|
|
expect(() => cipher.decrypt(a, "someone-else", "github")).to.throw();
|
|
expect(() => cipher.decrypt(a, "owner", "other")).to.throw();
|
|
const wrong = createTokenCipher(JSON.stringify({ old: Buffer.alloc(32, 3).toString("base64") }), "old");
|
|
expect(() => wrong.decrypt(a, "owner", "github")).to.throw();
|
|
});
|
|
it("supports key rotation while retaining reads of old credentials", () => {
|
|
const rotated = createTokenCipher(keys, "next");
|
|
expect(rotated.decrypt(cipher.encrypt("secret", "owner", "github"), "owner", "github")).to.equal("secret");
|
|
expect(rotated.encrypt("secret", "owner", "github").keyId).to.equal("next");
|
|
});
|
|
it("refuses missing, malformed, and short keys", () => {
|
|
for (const raw of ["", "null", "[]", "{}", '{"old":"YQ=="}']) {
|
|
expect(() => createTokenCipher(raw, "old")).to.throw();
|
|
}
|
|
});
|
|
it("redacts nested credentials, authorization and tokens in URLs/errors", () => {
|
|
const input = { accessTokens: { github: "plain" }, nested: { authorization: "Bearer plain", encryptedToken: { ciphertext: "abc" } }, message: "failed ghp_abcdef https://example.test/?token=plain" };
|
|
const result = JSON.stringify(redactSecrets(input));
|
|
expect(result).not.to.include("plain");
|
|
expect(result).not.to.include("ghp_abcdef");
|
|
expect(result).not.to.include("abc");
|
|
});
|
|
});
|