feat: encrypted credential vault
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
5f8746cfae
commit
dd6b880f49
@@ -0,0 +1,24 @@
|
||||
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "node:crypto";
|
||||
|
||||
function key() {
|
||||
const s = process.env.APP_SECRET;
|
||||
if (!s || s.length < 16) throw new Error("APP_SECRET is missing or shorter than 16 chars — set it in .env");
|
||||
return scryptSync(s, "qai-vault-v1", 32);
|
||||
}
|
||||
export function seal(plain: string): string {
|
||||
if (!plain) return "";
|
||||
const iv = randomBytes(12);
|
||||
const c = createCipheriv("aes-256-gcm", key(), iv);
|
||||
const ct = Buffer.concat([c.update(plain, "utf8"), c.final()]);
|
||||
return `${iv.toString("hex")}.${c.getAuthTag().toString("hex")}.${ct.toString("hex")}`;
|
||||
}
|
||||
export function open(sealed: string): string {
|
||||
if (!sealed) return "";
|
||||
try {
|
||||
const [iv, tag, ct] = sealed.split(".");
|
||||
const d = createDecipheriv("aes-256-gcm", key(), Buffer.from(iv, "hex"), { authTagLength: 16 });
|
||||
d.setAuthTag(Buffer.from(tag, "hex"));
|
||||
return Buffer.concat([d.update(Buffer.from(ct, "hex")), d.final()]).toString("utf8");
|
||||
} catch { return ""; }
|
||||
}
|
||||
export const mask = (v: string) => (v ? `••••${v.slice(-4)}` : "");
|
||||
Reference in New Issue
Block a user