beercan 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat/providers/websocket.d.ts +7 -1
- package/dist/chat/providers/websocket.d.ts.map +1 -1
- package/dist/chat/providers/websocket.js +27 -3
- package/dist/chat/providers/websocket.js.map +1 -1
- package/dist/cli.js +134 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +20 -0
- package/dist/config.js.map +1 -1
- package/dist/core/logger.d.ts +7 -0
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +57 -2
- package/dist/core/logger.js.map +1 -1
- package/dist/crypto/index.d.ts +66 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +142 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/key-manager.d.ts +62 -0
- package/dist/crypto/key-manager.d.ts.map +1 -0
- package/dist/crypto/key-manager.js +198 -0
- package/dist/crypto/key-manager.js.map +1 -0
- package/dist/crypto/migration.d.ts +23 -0
- package/dist/crypto/migration.d.ts.map +1 -0
- package/dist/crypto/migration.js +183 -0
- package/dist/crypto/migration.js.map +1 -0
- package/dist/crypto/primitives.d.ts +53 -0
- package/dist/crypto/primitives.d.ts.map +1 -0
- package/dist/crypto/primitives.js +99 -0
- package/dist/crypto/primitives.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -1
- package/dist/index.js.map +1 -1
- package/dist/storage/database.d.ts +15 -1
- package/dist/storage/database.d.ts.map +1 -1
- package/dist/storage/database.js +102 -34
- package/dist/storage/database.js.map +1 -1
- package/package.json +1 -1
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,qEAAqE;AACrE,wDAAwD;AACxD,6BAA6B;AAC7B,cAAc;AACd,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AACpF,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AAE9C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAClD,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AAElD,OAAO,EAAE,CAAC,CAAC,WAAW;AAEtB,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACvC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;IAChE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC;IACrD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,iBAAiB,CAAC;IACjD,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,2BAA2B,CAAC;IAChE,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1C,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAC3C,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACpC,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAC/C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACpE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACxC,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;IACjD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,gBAAgB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3C,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC7C,gCAAgC;IAChC,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1C,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACpC,kCAAkC;IAClC,sBAAsB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC9C,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC7C,sBAAsB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7C,qBAAqB;IACrB,wBAAwB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAChD,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;IACvD,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3C,sBAAsB;IACtB,iBAAiB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC7C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACtC,aAAa;IACb,iBAAiB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC7C,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;IACvE,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACxC,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAG,8CAA8C;IAC5F,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAY,gCAAgC;IAC/E,gBAAgB;IAChB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAIH,IAAI,OAAO,GAAkB,IAAI,CAAC;AAElC,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC;YAC3B,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;YAC9C,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB;YACrC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB;YAC/C,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB;YAC3C,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB;YACrD,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB;gBACpD,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;gBAC9C,CAAC,CAAC,SAAS;YACb,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB;gBAClD,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;gBAChD,CAAC,CAAC,SAAS;YACb,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB;gBAC/C,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;gBAC9C,CAAC,CAAC,SAAS;YACb,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;gBAClD,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;gBAC5C,CAAC,CAAC,SAAS;YACb,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;YACvC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB;YACrC,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B;gBACtD,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;gBAClD,CAAC,CAAC,SAAS;YACb,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,6BAA6B;gBAC3D,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC;gBACrD,CAAC,CAAC,SAAS;YACb,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe;YACnC,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B;gBACtD,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,OAAO;gBACpD,CAAC,CAAC,SAAS;YACb,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B;YACxD,mBAAmB,EAAE,OAAO,CAAC,GAAG,CAAC,8BAA8B;gBAC7D,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC;gBACtD,CAAC,CAAC,SAAS;YACb,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB;gBAChD,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;gBAC/C,CAAC,CAAC,SAAS;YACb,sBAAsB,EAAE,OAAO,CAAC,GAAG,CAAC,iCAAiC;gBACnE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC;gBACzD,CAAC,CAAC,SAAS;YACb,qBAAqB,EAAE,OAAO,CAAC,GAAG,CAAC,gCAAgC;gBACjE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC;gBACxD,CAAC,CAAC,SAAS;YACb,sBAAsB,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB;gBAC3D,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;gBACjD,CAAC,CAAC,SAAS;YACb,wBAAwB,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B;gBAC9D,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;gBAClD,CAAC,CAAC,SAAS;YACb,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB;YACzD,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,8BAA8B;gBAC9D,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC;gBACtD,CAAC,CAAC,SAAS;YACb,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B;gBACvD,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,MAAM;gBACnD,CAAC,CAAC,SAAS;YACb,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB;YACrD,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B;gBACvD,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,MAAM;gBACnD,CAAC,CAAC,SAAS;YACb,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB;YACnD,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B;YACzD,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,6BAA6B;YAC/D,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;gBAC3C,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,MAAM;gBAC7C,CAAC,CAAC,SAAS;YACb,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB;YAC1C,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;SACzC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,WAAW;IACzB,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;AACjE,CAAC"}
|
package/dist/core/logger.d.ts
CHANGED
|
@@ -10,7 +10,10 @@ export declare class Logger {
|
|
|
10
10
|
private level;
|
|
11
11
|
private fileStream;
|
|
12
12
|
private quiet;
|
|
13
|
+
private sanitizeEnabled;
|
|
13
14
|
constructor(level?: LogLevel, logFilePath?: string);
|
|
15
|
+
/** Enable or disable log sanitization (redacts sensitive fields). */
|
|
16
|
+
setSanitize(enabled: boolean): void;
|
|
14
17
|
/** Suppress console output (file-only). Used in chat mode. */
|
|
15
18
|
setQuiet(quiet: boolean): void;
|
|
16
19
|
private write;
|
|
@@ -19,6 +22,10 @@ export declare class Logger {
|
|
|
19
22
|
warn(component: string, message: string, data?: Record<string, unknown>): void;
|
|
20
23
|
error(component: string, message: string, data?: Record<string, unknown>): void;
|
|
21
24
|
close(): void;
|
|
25
|
+
/** Deep-walk a data object and redact sensitive fields. */
|
|
26
|
+
static sanitize(data: Record<string, unknown>): Record<string, unknown>;
|
|
27
|
+
/** Scrub known secret patterns from a string. */
|
|
28
|
+
static sanitizeString(str: string): string;
|
|
22
29
|
}
|
|
23
30
|
export declare function setGlobalLogger(logger: Logger): void;
|
|
24
31
|
export declare function getLogger(): Logger;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAI3D,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAI3D,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAoBD,qBAAa,MAAM;IACjB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,eAAe,CAAS;gBAEpB,KAAK,GAAE,QAAiB,EAAE,WAAW,CAAC,EAAE,MAAM;IAU1D,qEAAqE;IACrE,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAInC,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI9B,OAAO,CAAC,KAAK;IA6Bb,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI/E,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI9E,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI9E,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI/E,KAAK,IAAI,IAAI;IAKb,2DAA2D;IAC3D,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAsBvE,iDAAiD;IACjD,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;CAO3C;AAKD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED,wBAAgB,SAAS,IAAI,MAAM,CAKlC"}
|
package/dist/core/logger.js
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
const LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
4
|
+
// ── Sensitive Field Patterns ─────────────────────────────────
|
|
5
|
+
// Fields whose values should be redacted when log sanitization is active.
|
|
6
|
+
const SENSITIVE_FIELDS = new Set([
|
|
7
|
+
"goal", "result", "content", "messages", "systemPrompt", "system_prompt",
|
|
8
|
+
"toolCalls", "tool_calls", "extraContext", "extra_context",
|
|
9
|
+
"eventData", "event_data", "goalTemplate", "goal_template",
|
|
10
|
+
"filterData", "filter_data", "passphrase", "password",
|
|
11
|
+
]);
|
|
12
|
+
// Regex patterns for API keys/tokens that should always be redacted.
|
|
13
|
+
const SECRET_PATTERNS = [
|
|
14
|
+
/sk-ant-[a-zA-Z0-9_-]+/g, // Anthropic API keys
|
|
15
|
+
/sk-[a-zA-Z0-9]{20,}/g, // OpenAI-style keys
|
|
16
|
+
/xoxb-[a-zA-Z0-9-]+/g, // Slack bot tokens
|
|
17
|
+
/xoxp-[a-zA-Z0-9-]+/g, // Slack user tokens
|
|
18
|
+
/Bearer\s+[a-zA-Z0-9._~+/-]+=*/g, // Bearer tokens
|
|
19
|
+
];
|
|
4
20
|
export class Logger {
|
|
5
21
|
level;
|
|
6
22
|
fileStream = null;
|
|
7
23
|
quiet = false;
|
|
24
|
+
sanitizeEnabled = false;
|
|
8
25
|
constructor(level = "info", logFilePath) {
|
|
9
26
|
this.level = LEVELS[level];
|
|
10
27
|
if (logFilePath) {
|
|
@@ -14,6 +31,10 @@ export class Logger {
|
|
|
14
31
|
this.fileStream = fs.createWriteStream(logFilePath, { flags: "a" });
|
|
15
32
|
}
|
|
16
33
|
}
|
|
34
|
+
/** Enable or disable log sanitization (redacts sensitive fields). */
|
|
35
|
+
setSanitize(enabled) {
|
|
36
|
+
this.sanitizeEnabled = enabled;
|
|
37
|
+
}
|
|
17
38
|
/** Suppress console output (file-only). Used in chat mode. */
|
|
18
39
|
setQuiet(quiet) {
|
|
19
40
|
this.quiet = quiet;
|
|
@@ -21,12 +42,14 @@ export class Logger {
|
|
|
21
42
|
write(level, component, message, data) {
|
|
22
43
|
if (LEVELS[level] < this.level)
|
|
23
44
|
return;
|
|
45
|
+
const sanitizedData = this.sanitizeEnabled && data ? Logger.sanitize(data) : data;
|
|
46
|
+
const sanitizedMessage = this.sanitizeEnabled ? Logger.sanitizeString(message) : message;
|
|
24
47
|
const entry = {
|
|
25
48
|
timestamp: new Date().toISOString(),
|
|
26
49
|
level,
|
|
27
50
|
component,
|
|
28
|
-
message,
|
|
29
|
-
...(
|
|
51
|
+
message: sanitizedMessage,
|
|
52
|
+
...(sanitizedData && Object.keys(sanitizedData).length > 0 ? { data: sanitizedData } : {}),
|
|
30
53
|
};
|
|
31
54
|
const line = JSON.stringify(entry);
|
|
32
55
|
// Always write to file if available
|
|
@@ -57,6 +80,38 @@ export class Logger {
|
|
|
57
80
|
this.fileStream?.end();
|
|
58
81
|
this.fileStream = null;
|
|
59
82
|
}
|
|
83
|
+
/** Deep-walk a data object and redact sensitive fields. */
|
|
84
|
+
static sanitize(data) {
|
|
85
|
+
const result = {};
|
|
86
|
+
for (const [key, value] of Object.entries(data)) {
|
|
87
|
+
if (SENSITIVE_FIELDS.has(key)) {
|
|
88
|
+
result[key] = "[REDACTED]";
|
|
89
|
+
}
|
|
90
|
+
else if (typeof value === "string") {
|
|
91
|
+
result[key] = Logger.sanitizeString(value);
|
|
92
|
+
}
|
|
93
|
+
else if (Array.isArray(value)) {
|
|
94
|
+
result[key] = value.map((item) => typeof item === "object" && item !== null
|
|
95
|
+
? Logger.sanitize(item)
|
|
96
|
+
: typeof item === "string" ? Logger.sanitizeString(item) : item);
|
|
97
|
+
}
|
|
98
|
+
else if (typeof value === "object" && value !== null) {
|
|
99
|
+
result[key] = Logger.sanitize(value);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
result[key] = value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
/** Scrub known secret patterns from a string. */
|
|
108
|
+
static sanitizeString(str) {
|
|
109
|
+
let result = str;
|
|
110
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
111
|
+
result = result.replace(pattern, "[REDACTED:key]");
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
60
115
|
}
|
|
61
116
|
/** Global logger instance — set once in BeerCanEngine */
|
|
62
117
|
let _logger = null;
|
package/dist/core/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAOxB,MAAM,MAAM,GAA6B,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAUlF,MAAM,OAAO,MAAM;IACT,KAAK,CAAS;IACd,UAAU,GAA0B,IAAI,CAAC;IACzC,KAAK,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export type EncryptionScope = {
|
|
2
|
+
type: "global";
|
|
3
|
+
} | {
|
|
4
|
+
type: "project";
|
|
5
|
+
projectId: string;
|
|
6
|
+
} | {
|
|
7
|
+
type: "bloop";
|
|
8
|
+
projectId: string;
|
|
9
|
+
bloopId: string;
|
|
10
|
+
} | {
|
|
11
|
+
type: "memory";
|
|
12
|
+
projectId: string;
|
|
13
|
+
};
|
|
14
|
+
export declare class CryptoManager {
|
|
15
|
+
private keyManager;
|
|
16
|
+
private constructor();
|
|
17
|
+
/** Create a CryptoManager from a passphrase. */
|
|
18
|
+
static fromPassphrase(passphrase: string, configDir: string): CryptoManager;
|
|
19
|
+
/** Create a CryptoManager from a keyfile. */
|
|
20
|
+
static fromKeyfile(keyfilePath: string): CryptoManager;
|
|
21
|
+
/** Create a disabled CryptoManager (no-op passthrough). */
|
|
22
|
+
static disabled(): CryptoManager;
|
|
23
|
+
/** Returns true if encryption is active. */
|
|
24
|
+
isEnabled(): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Encrypt a plaintext string with scope-based key derivation.
|
|
27
|
+
* Returns an "enc:v1:<base64>" formatted string.
|
|
28
|
+
* If encryption is disabled, returns the plaintext unchanged.
|
|
29
|
+
*/
|
|
30
|
+
encrypt(plaintext: string, scope: EncryptionScope): string;
|
|
31
|
+
/**
|
|
32
|
+
* Decrypt an "enc:v1:<base64>" string back to plaintext.
|
|
33
|
+
* Throws if the data is tampered or the wrong key is used.
|
|
34
|
+
* If encryption is disabled, returns the input unchanged.
|
|
35
|
+
*/
|
|
36
|
+
decrypt(ciphertext: string, scope: EncryptionScope): string;
|
|
37
|
+
/**
|
|
38
|
+
* Decrypt if encrypted, return as-is if plaintext.
|
|
39
|
+
* Use during migration period when data may be mixed.
|
|
40
|
+
*/
|
|
41
|
+
maybeDecrypt(value: string | null | undefined, scope: EncryptionScope): string | null | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Encrypt a JSON-serializable value.
|
|
44
|
+
* Serializes to JSON string, then encrypts.
|
|
45
|
+
*/
|
|
46
|
+
encryptJSON(obj: unknown, scope: EncryptionScope): string;
|
|
47
|
+
/**
|
|
48
|
+
* Decrypt a value and parse as JSON.
|
|
49
|
+
*/
|
|
50
|
+
decryptJSON(ciphertext: string, scope: EncryptionScope): unknown;
|
|
51
|
+
/**
|
|
52
|
+
* Conditionally decrypt a JSON field. If the value is already plaintext JSON, parse directly.
|
|
53
|
+
*/
|
|
54
|
+
maybeDecryptJSON(value: string | null | undefined, scope: EncryptionScope): unknown;
|
|
55
|
+
/**
|
|
56
|
+
* Securely destroy all key material. Call on shutdown.
|
|
57
|
+
* After calling, encrypt/decrypt will act as disabled (passthrough).
|
|
58
|
+
*/
|
|
59
|
+
destroy(): void;
|
|
60
|
+
private resolveKey;
|
|
61
|
+
}
|
|
62
|
+
/** Check if a value is in encrypted format. */
|
|
63
|
+
export declare function isEncrypted(value: string): boolean;
|
|
64
|
+
export { KeyManager } from "./key-manager.js";
|
|
65
|
+
export { generateRandomKey, zeroBuffer } from "./primitives.js";
|
|
66
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAa1C,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAoB;IAEtC,OAAO;IAMP,gDAAgD;IAChD,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa;IAK3E,6CAA6C;IAC7C,MAAM,CAAC,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa;IAKtD,2DAA2D;IAC3D,MAAM,CAAC,QAAQ,IAAI,aAAa;IAMhC,4CAA4C;IAC5C,SAAS,IAAI,OAAO;IAMpB;;;;OAIG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM;IAS1D;;;;OAIG;IACH,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM;IAc3D;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS;IAOjG;;;OAGG;IACH,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM;IAIzD;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO;IAKhE;;OAEG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO;IAUnF;;;OAGG;IACH,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,UAAU;CAkBnB;AAID,+CAA+C;AAC/C,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAElD;AAGD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { aesGcmEncrypt, aesGcmDecrypt, packAesGcm, unpackAesGcm, } from "./primitives.js";
|
|
2
|
+
import { KeyManager } from "./key-manager.js";
|
|
3
|
+
// ── Encrypted Value Format ───────────────────────────────────
|
|
4
|
+
// Encrypted values are stored as: "enc:v1:<base64(iv + ciphertext + tag)>"
|
|
5
|
+
// The prefix allows detection of encrypted vs plaintext data.
|
|
6
|
+
const ENC_PREFIX = "enc:v1:";
|
|
7
|
+
// ── CryptoManager ────────────────────────────────────────────
|
|
8
|
+
// High-level facade for all encryption operations in BeerCan.
|
|
9
|
+
// Thread-safe (single-threaded Node.js), handles key derivation
|
|
10
|
+
// and provides encrypt/decrypt with scope-based key selection.
|
|
11
|
+
export class CryptoManager {
|
|
12
|
+
keyManager;
|
|
13
|
+
constructor(keyManager) {
|
|
14
|
+
this.keyManager = keyManager;
|
|
15
|
+
}
|
|
16
|
+
// ── Factory Methods ──────────────────────────────────────
|
|
17
|
+
/** Create a CryptoManager from a passphrase. */
|
|
18
|
+
static fromPassphrase(passphrase, configDir) {
|
|
19
|
+
const km = KeyManager.fromPassphrase(passphrase, configDir);
|
|
20
|
+
return new CryptoManager(km);
|
|
21
|
+
}
|
|
22
|
+
/** Create a CryptoManager from a keyfile. */
|
|
23
|
+
static fromKeyfile(keyfilePath) {
|
|
24
|
+
const km = KeyManager.fromKeyfile(keyfilePath);
|
|
25
|
+
return new CryptoManager(km);
|
|
26
|
+
}
|
|
27
|
+
/** Create a disabled CryptoManager (no-op passthrough). */
|
|
28
|
+
static disabled() {
|
|
29
|
+
return new CryptoManager(null);
|
|
30
|
+
}
|
|
31
|
+
// ── Status ───────────────────────────────────────────────
|
|
32
|
+
/** Returns true if encryption is active. */
|
|
33
|
+
isEnabled() {
|
|
34
|
+
return this.keyManager !== null && !this.keyManager.isDestroyed();
|
|
35
|
+
}
|
|
36
|
+
// ── Encrypt / Decrypt ────────────────────────────────────
|
|
37
|
+
/**
|
|
38
|
+
* Encrypt a plaintext string with scope-based key derivation.
|
|
39
|
+
* Returns an "enc:v1:<base64>" formatted string.
|
|
40
|
+
* If encryption is disabled, returns the plaintext unchanged.
|
|
41
|
+
*/
|
|
42
|
+
encrypt(plaintext, scope) {
|
|
43
|
+
if (!this.isEnabled())
|
|
44
|
+
return plaintext;
|
|
45
|
+
const key = this.resolveKey(scope);
|
|
46
|
+
const result = aesGcmEncrypt(key, Buffer.from(plaintext, "utf-8"));
|
|
47
|
+
const packed = packAesGcm(result);
|
|
48
|
+
return ENC_PREFIX + packed.toString("base64");
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Decrypt an "enc:v1:<base64>" string back to plaintext.
|
|
52
|
+
* Throws if the data is tampered or the wrong key is used.
|
|
53
|
+
* If encryption is disabled, returns the input unchanged.
|
|
54
|
+
*/
|
|
55
|
+
decrypt(ciphertext, scope) {
|
|
56
|
+
if (!this.isEnabled())
|
|
57
|
+
return ciphertext;
|
|
58
|
+
if (!ciphertext.startsWith(ENC_PREFIX)) {
|
|
59
|
+
throw new Error("Cannot decrypt: value is not in encrypted format");
|
|
60
|
+
}
|
|
61
|
+
const packed = Buffer.from(ciphertext.slice(ENC_PREFIX.length), "base64");
|
|
62
|
+
const { iv, ciphertext: ct, tag } = unpackAesGcm(packed);
|
|
63
|
+
const key = this.resolveKey(scope);
|
|
64
|
+
const plaintext = aesGcmDecrypt(key, iv, ct, tag);
|
|
65
|
+
return plaintext.toString("utf-8");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Decrypt if encrypted, return as-is if plaintext.
|
|
69
|
+
* Use during migration period when data may be mixed.
|
|
70
|
+
*/
|
|
71
|
+
maybeDecrypt(value, scope) {
|
|
72
|
+
if (value == null)
|
|
73
|
+
return value;
|
|
74
|
+
if (!this.isEnabled())
|
|
75
|
+
return value;
|
|
76
|
+
if (!isEncrypted(value))
|
|
77
|
+
return value;
|
|
78
|
+
return this.decrypt(value, scope);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Encrypt a JSON-serializable value.
|
|
82
|
+
* Serializes to JSON string, then encrypts.
|
|
83
|
+
*/
|
|
84
|
+
encryptJSON(obj, scope) {
|
|
85
|
+
return this.encrypt(JSON.stringify(obj), scope);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Decrypt a value and parse as JSON.
|
|
89
|
+
*/
|
|
90
|
+
decryptJSON(ciphertext, scope) {
|
|
91
|
+
const plaintext = this.decrypt(ciphertext, scope);
|
|
92
|
+
return JSON.parse(plaintext);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Conditionally decrypt a JSON field. If the value is already plaintext JSON, parse directly.
|
|
96
|
+
*/
|
|
97
|
+
maybeDecryptJSON(value, scope) {
|
|
98
|
+
if (value == null)
|
|
99
|
+
return value;
|
|
100
|
+
if (!this.isEnabled() || !isEncrypted(value)) {
|
|
101
|
+
return JSON.parse(value);
|
|
102
|
+
}
|
|
103
|
+
return this.decryptJSON(value, scope);
|
|
104
|
+
}
|
|
105
|
+
// ── Lifecycle ────────────────────────────────────────────
|
|
106
|
+
/**
|
|
107
|
+
* Securely destroy all key material. Call on shutdown.
|
|
108
|
+
* After calling, encrypt/decrypt will act as disabled (passthrough).
|
|
109
|
+
*/
|
|
110
|
+
destroy() {
|
|
111
|
+
if (this.keyManager) {
|
|
112
|
+
this.keyManager.destroy();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// ── Internal ─────────────────────────────────────────────
|
|
116
|
+
resolveKey(scope) {
|
|
117
|
+
if (!this.keyManager) {
|
|
118
|
+
throw new Error("CryptoManager is disabled — cannot resolve key");
|
|
119
|
+
}
|
|
120
|
+
switch (scope.type) {
|
|
121
|
+
case "global":
|
|
122
|
+
return this.keyManager.deriveGlobalKey();
|
|
123
|
+
case "project":
|
|
124
|
+
return this.keyManager.deriveProjectKey(scope.projectId);
|
|
125
|
+
case "bloop":
|
|
126
|
+
return this.keyManager.deriveBloopKey(scope.projectId, scope.bloopId);
|
|
127
|
+
case "memory":
|
|
128
|
+
return this.keyManager.deriveMemoryKey(scope.projectId);
|
|
129
|
+
default:
|
|
130
|
+
throw new Error(`Unknown encryption scope type: ${scope.type}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// ── Utility ──────────────────────────────────────────────────
|
|
135
|
+
/** Check if a value is in encrypted format. */
|
|
136
|
+
export function isEncrypted(value) {
|
|
137
|
+
return value.startsWith(ENC_PREFIX);
|
|
138
|
+
}
|
|
139
|
+
// Re-export key types for consumers
|
|
140
|
+
export { KeyManager } from "./key-manager.js";
|
|
141
|
+
export { generateRandomKey, zeroBuffer } from "./primitives.js";
|
|
142
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export interface CryptoConfig {
|
|
2
|
+
version: number;
|
|
3
|
+
mode: "passphrase" | "keyfile";
|
|
4
|
+
scrypt?: {
|
|
5
|
+
salt: string;
|
|
6
|
+
N: number;
|
|
7
|
+
r: number;
|
|
8
|
+
p: number;
|
|
9
|
+
keyLength: number;
|
|
10
|
+
};
|
|
11
|
+
verifier: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class KeyManager {
|
|
14
|
+
private masterKey;
|
|
15
|
+
private hkdfSalt;
|
|
16
|
+
private subKeyCache;
|
|
17
|
+
private destroyed;
|
|
18
|
+
private constructor();
|
|
19
|
+
/**
|
|
20
|
+
* Initialize from a passphrase. If crypto.json exists at configDir, uses stored salt.
|
|
21
|
+
* Otherwise creates a new config with fresh salt.
|
|
22
|
+
*/
|
|
23
|
+
static fromPassphrase(passphrase: string, configDir: string): KeyManager;
|
|
24
|
+
/**
|
|
25
|
+
* Initialize from a keyfile. If the file doesn't exist, throws.
|
|
26
|
+
*/
|
|
27
|
+
static fromKeyfile(keyfilePath: string): KeyManager;
|
|
28
|
+
/**
|
|
29
|
+
* Generate a new keyfile at the given path.
|
|
30
|
+
*/
|
|
31
|
+
static generateKeyfile(keyfilePath: string, configDir: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* Derive a sub-key for a given context string.
|
|
34
|
+
* Uses LRU cache to avoid repeated HKDF calls.
|
|
35
|
+
*/
|
|
36
|
+
deriveKey(context: string): Buffer;
|
|
37
|
+
/** Derive a project-scoped key. */
|
|
38
|
+
deriveProjectKey(projectId: string): Buffer;
|
|
39
|
+
/** Derive a bloop-scoped key. */
|
|
40
|
+
deriveBloopKey(projectId: string, bloopId: string): Buffer;
|
|
41
|
+
/** Derive a memory-scoped key. */
|
|
42
|
+
deriveMemoryKey(projectId: string): Buffer;
|
|
43
|
+
/** Derive the global key (for cross-project data like job queue). */
|
|
44
|
+
deriveGlobalKey(): Buffer;
|
|
45
|
+
/**
|
|
46
|
+
* Securely destroy all key material. Call on shutdown.
|
|
47
|
+
* After calling, all encrypt/decrypt operations will throw.
|
|
48
|
+
*/
|
|
49
|
+
destroy(): void;
|
|
50
|
+
isDestroyed(): boolean;
|
|
51
|
+
private ensureNotDestroyed;
|
|
52
|
+
/**
|
|
53
|
+
* Create a verifier string by encrypting a known plaintext with the key.
|
|
54
|
+
* Used to check if a passphrase is correct without storing the key.
|
|
55
|
+
*/
|
|
56
|
+
private static createVerifier;
|
|
57
|
+
/**
|
|
58
|
+
* Verify that a key can decrypt the stored verifier.
|
|
59
|
+
*/
|
|
60
|
+
private static verifyKey;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=key-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-manager.d.ts","sourceRoot":"","sources":["../../src/crypto/key-manager.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,YAAY,GAAG,SAAS,CAAC;IAC/B,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;CAClB;AAOD,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAA0D;IAC7E,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO;IAQP;;;OAGG;IACH,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU;IAkDxE;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU;IAenD;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAyBpE;;;OAGG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAgClC,mCAAmC;IACnC,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAI3C,iCAAiC;IACjC,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAI1D,kCAAkC;IAClC,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAI1C,qEAAqE;IACrE,eAAe,IAAI,MAAM;IAMzB;;;OAGG;IACH,OAAO,IAAI,IAAI;IAaf,WAAW,IAAI,OAAO;IAMtB,OAAO,CAAC,kBAAkB;IAM1B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAK7B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;CAUzB"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { aesGcmEncrypt, aesGcmDecrypt, packAesGcm, unpackAesGcm, hkdfDerive, scryptDerive, generateRandomKey, zeroBuffer, } from "./primitives.js";
|
|
4
|
+
const VERIFIER_PLAINTEXT = "beercan-key-verification-v1";
|
|
5
|
+
const CONFIG_FILENAME = "crypto.json";
|
|
6
|
+
const KEYFILE_FILENAME = "master.key";
|
|
7
|
+
const MAX_LRU_SIZE = 200;
|
|
8
|
+
export class KeyManager {
|
|
9
|
+
masterKey;
|
|
10
|
+
hkdfSalt;
|
|
11
|
+
subKeyCache = new Map();
|
|
12
|
+
destroyed = false;
|
|
13
|
+
constructor(masterKey, hkdfSalt) {
|
|
14
|
+
this.masterKey = masterKey;
|
|
15
|
+
// Use a fixed HKDF salt derived from the master key for deterministic sub-key derivation
|
|
16
|
+
this.hkdfSalt = hkdfSalt;
|
|
17
|
+
}
|
|
18
|
+
// ── Factory Methods ──────────────────────────────────────
|
|
19
|
+
/**
|
|
20
|
+
* Initialize from a passphrase. If crypto.json exists at configDir, uses stored salt.
|
|
21
|
+
* Otherwise creates a new config with fresh salt.
|
|
22
|
+
*/
|
|
23
|
+
static fromPassphrase(passphrase, configDir) {
|
|
24
|
+
const configPath = path.join(configDir, CONFIG_FILENAME);
|
|
25
|
+
let config = null;
|
|
26
|
+
if (fs.existsSync(configPath)) {
|
|
27
|
+
config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
28
|
+
if (config.mode !== "passphrase") {
|
|
29
|
+
throw new Error(`crypto.json specifies mode "${config.mode}", but passphrase was provided`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
let key;
|
|
33
|
+
if (config?.scrypt) {
|
|
34
|
+
// Re-derive with stored params
|
|
35
|
+
const salt = Buffer.from(config.scrypt.salt, "base64");
|
|
36
|
+
const result = scryptDerive(passphrase, salt);
|
|
37
|
+
key = result.key;
|
|
38
|
+
// Verify the passphrase is correct
|
|
39
|
+
if (!KeyManager.verifyKey(key, config.verifier)) {
|
|
40
|
+
zeroBuffer(key);
|
|
41
|
+
throw new Error("Invalid passphrase — key verification failed");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
// First-time setup: derive key and save config
|
|
46
|
+
const result = scryptDerive(passphrase);
|
|
47
|
+
key = result.key;
|
|
48
|
+
const verifier = KeyManager.createVerifier(key);
|
|
49
|
+
const newConfig = {
|
|
50
|
+
version: 1,
|
|
51
|
+
mode: "passphrase",
|
|
52
|
+
scrypt: {
|
|
53
|
+
salt: result.params.salt.toString("base64"),
|
|
54
|
+
N: result.params.N,
|
|
55
|
+
r: result.params.r,
|
|
56
|
+
p: result.params.p,
|
|
57
|
+
keyLength: result.params.keyLength,
|
|
58
|
+
},
|
|
59
|
+
verifier,
|
|
60
|
+
};
|
|
61
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
62
|
+
fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 2), { mode: 0o600 });
|
|
63
|
+
}
|
|
64
|
+
const hkdfSalt = hkdfDerive(key, Buffer.alloc(0), "beercan-hkdf-salt", 32);
|
|
65
|
+
return new KeyManager(key, hkdfSalt);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Initialize from a keyfile. If the file doesn't exist, throws.
|
|
69
|
+
*/
|
|
70
|
+
static fromKeyfile(keyfilePath) {
|
|
71
|
+
if (!fs.existsSync(keyfilePath)) {
|
|
72
|
+
throw new Error(`Keyfile not found: ${keyfilePath}`);
|
|
73
|
+
}
|
|
74
|
+
const raw = fs.readFileSync(keyfilePath);
|
|
75
|
+
if (raw.length !== 32) {
|
|
76
|
+
throw new Error(`Keyfile must be exactly 32 bytes (256 bits), got ${raw.length}`);
|
|
77
|
+
}
|
|
78
|
+
const key = Buffer.from(raw);
|
|
79
|
+
const hkdfSalt = hkdfDerive(key, Buffer.alloc(0), "beercan-hkdf-salt", 32);
|
|
80
|
+
return new KeyManager(key, hkdfSalt);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Generate a new keyfile at the given path.
|
|
84
|
+
*/
|
|
85
|
+
static generateKeyfile(keyfilePath, configDir) {
|
|
86
|
+
const key = generateRandomKey();
|
|
87
|
+
const dir = path.dirname(keyfilePath);
|
|
88
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
89
|
+
fs.writeFileSync(keyfilePath, key, { mode: 0o600 });
|
|
90
|
+
// Also write crypto.json in keyfile mode
|
|
91
|
+
const verifier = KeyManager.createVerifier(key);
|
|
92
|
+
const config = {
|
|
93
|
+
version: 1,
|
|
94
|
+
mode: "keyfile",
|
|
95
|
+
verifier,
|
|
96
|
+
};
|
|
97
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
98
|
+
fs.writeFileSync(path.join(configDir, CONFIG_FILENAME), JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
99
|
+
zeroBuffer(key);
|
|
100
|
+
}
|
|
101
|
+
// ── Key Derivation ───────────────────────────────────────
|
|
102
|
+
/**
|
|
103
|
+
* Derive a sub-key for a given context string.
|
|
104
|
+
* Uses LRU cache to avoid repeated HKDF calls.
|
|
105
|
+
*/
|
|
106
|
+
deriveKey(context) {
|
|
107
|
+
this.ensureNotDestroyed();
|
|
108
|
+
const cached = this.subKeyCache.get(context);
|
|
109
|
+
if (cached) {
|
|
110
|
+
cached.accessedAt = Date.now();
|
|
111
|
+
return cached.key;
|
|
112
|
+
}
|
|
113
|
+
const derived = hkdfDerive(this.masterKey, this.hkdfSalt, context);
|
|
114
|
+
// Evict oldest entry if cache is full
|
|
115
|
+
if (this.subKeyCache.size >= MAX_LRU_SIZE) {
|
|
116
|
+
let oldestKey = "";
|
|
117
|
+
let oldestTime = Infinity;
|
|
118
|
+
for (const [k, v] of this.subKeyCache) {
|
|
119
|
+
if (v.accessedAt < oldestTime) {
|
|
120
|
+
oldestTime = v.accessedAt;
|
|
121
|
+
oldestKey = k;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (oldestKey) {
|
|
125
|
+
const evicted = this.subKeyCache.get(oldestKey);
|
|
126
|
+
if (evicted)
|
|
127
|
+
zeroBuffer(evicted.key);
|
|
128
|
+
this.subKeyCache.delete(oldestKey);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
this.subKeyCache.set(context, { key: derived, accessedAt: Date.now() });
|
|
132
|
+
return derived;
|
|
133
|
+
}
|
|
134
|
+
/** Derive a project-scoped key. */
|
|
135
|
+
deriveProjectKey(projectId) {
|
|
136
|
+
return this.deriveKey(`beercan-project-${projectId}`);
|
|
137
|
+
}
|
|
138
|
+
/** Derive a bloop-scoped key. */
|
|
139
|
+
deriveBloopKey(projectId, bloopId) {
|
|
140
|
+
return this.deriveKey(`beercan-bloop-${projectId}-${bloopId}`);
|
|
141
|
+
}
|
|
142
|
+
/** Derive a memory-scoped key. */
|
|
143
|
+
deriveMemoryKey(projectId) {
|
|
144
|
+
return this.deriveKey(`beercan-memory-${projectId}`);
|
|
145
|
+
}
|
|
146
|
+
/** Derive the global key (for cross-project data like job queue). */
|
|
147
|
+
deriveGlobalKey() {
|
|
148
|
+
return this.deriveKey("beercan-global");
|
|
149
|
+
}
|
|
150
|
+
// ── Lifecycle ────────────────────────────────────────────
|
|
151
|
+
/**
|
|
152
|
+
* Securely destroy all key material. Call on shutdown.
|
|
153
|
+
* After calling, all encrypt/decrypt operations will throw.
|
|
154
|
+
*/
|
|
155
|
+
destroy() {
|
|
156
|
+
if (this.destroyed)
|
|
157
|
+
return;
|
|
158
|
+
zeroBuffer(this.masterKey);
|
|
159
|
+
zeroBuffer(this.hkdfSalt);
|
|
160
|
+
for (const [, entry] of this.subKeyCache) {
|
|
161
|
+
zeroBuffer(entry.key);
|
|
162
|
+
}
|
|
163
|
+
this.subKeyCache.clear();
|
|
164
|
+
this.destroyed = true;
|
|
165
|
+
}
|
|
166
|
+
isDestroyed() {
|
|
167
|
+
return this.destroyed;
|
|
168
|
+
}
|
|
169
|
+
// ── Internal ─────────────────────────────────────────────
|
|
170
|
+
ensureNotDestroyed() {
|
|
171
|
+
if (this.destroyed) {
|
|
172
|
+
throw new Error("KeyManager has been destroyed — cannot derive keys");
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Create a verifier string by encrypting a known plaintext with the key.
|
|
177
|
+
* Used to check if a passphrase is correct without storing the key.
|
|
178
|
+
*/
|
|
179
|
+
static createVerifier(key) {
|
|
180
|
+
const result = aesGcmEncrypt(key, Buffer.from(VERIFIER_PLAINTEXT, "utf-8"));
|
|
181
|
+
return packAesGcm(result).toString("base64");
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Verify that a key can decrypt the stored verifier.
|
|
185
|
+
*/
|
|
186
|
+
static verifyKey(key, verifierBase64) {
|
|
187
|
+
try {
|
|
188
|
+
const packed = Buffer.from(verifierBase64, "base64");
|
|
189
|
+
const { iv, ciphertext, tag } = unpackAesGcm(packed);
|
|
190
|
+
const plaintext = aesGcmDecrypt(key, iv, ciphertext, tag);
|
|
191
|
+
return plaintext.toString("utf-8") === VERIFIER_PLAINTEXT;
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=key-manager.js.map
|