@de-otio/chaoskb-client 0.3.6 → 0.3.7
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/cli/bootstrap.d.ts +11 -3
- package/dist/cli/bootstrap.d.ts.map +1 -1
- package/dist/cli/bootstrap.js +181 -126
- package/dist/cli/bootstrap.js.map +1 -1
- package/dist/cli/commands/config.d.ts +7 -4
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/config.js +161 -134
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/devices.d.ts.map +1 -1
- package/dist/cli/commands/devices.js +58 -33
- package/dist/cli/commands/devices.js.map +1 -1
- package/dist/cli/commands/export.d.ts.map +1 -1
- package/dist/cli/commands/export.js +6 -9
- package/dist/cli/commands/export.js.map +1 -1
- package/dist/cli/commands/import.js +1 -1
- package/dist/cli/commands/import.js.map +1 -1
- package/dist/cli/commands/projects.d.ts.map +1 -1
- package/dist/cli/commands/projects.js +33 -10
- package/dist/cli/commands/projects.js.map +1 -1
- package/dist/cli/commands/rotate-key.d.ts +3 -3
- package/dist/cli/commands/rotate-key.d.ts.map +1 -1
- package/dist/cli/commands/rotate-key.js +88 -35
- package/dist/cli/commands/rotate-key.js.map +1 -1
- package/dist/cli/commands/setup-sync.d.ts.map +1 -1
- package/dist/cli/commands/setup-sync.js +22 -4
- package/dist/cli/commands/setup-sync.js.map +1 -1
- package/dist/cli/mcp-server.d.ts.map +1 -1
- package/dist/cli/mcp-server.js +90 -42
- package/dist/cli/mcp-server.js.map +1 -1
- package/dist/crypto/aad.d.ts +2 -5
- package/dist/crypto/aad.d.ts.map +1 -1
- package/dist/crypto/aad.js +2 -8
- package/dist/crypto/aad.js.map +1 -1
- package/dist/crypto/aead.d.ts +8 -16
- package/dist/crypto/aead.d.ts.map +1 -1
- package/dist/crypto/aead.js +10 -36
- package/dist/crypto/aead.js.map +1 -1
- package/dist/crypto/blob-id.d.ts +2 -3
- package/dist/crypto/blob-id.d.ts.map +1 -1
- package/dist/crypto/blob-id.js +2 -30
- package/dist/crypto/blob-id.js.map +1 -1
- package/dist/crypto/canonical-json.d.ts +5 -3
- package/dist/crypto/canonical-json.d.ts.map +1 -1
- package/dist/crypto/canonical-json.js +5 -85
- package/dist/crypto/canonical-json.js.map +1 -1
- package/dist/crypto/commitment.d.ts +3 -9
- package/dist/crypto/commitment.d.ts.map +1 -1
- package/dist/crypto/commitment.js +3 -27
- package/dist/crypto/commitment.js.map +1 -1
- package/dist/crypto/encryption-service.d.ts +3 -0
- package/dist/crypto/encryption-service.d.ts.map +1 -1
- package/dist/crypto/encryption-service.js +10 -6
- package/dist/crypto/encryption-service.js.map +1 -1
- package/dist/crypto/envelope-cbor.d.ts +4 -34
- package/dist/crypto/envelope-cbor.d.ts.map +1 -1
- package/dist/crypto/envelope-cbor.js +4 -121
- package/dist/crypto/envelope-cbor.js.map +1 -1
- package/dist/crypto/envelope.d.ts +1 -31
- package/dist/crypto/envelope.d.ts.map +1 -1
- package/dist/crypto/envelope.js +31 -137
- package/dist/crypto/envelope.js.map +1 -1
- package/dist/crypto/hkdf.d.ts +7 -11
- package/dist/crypto/hkdf.d.ts.map +1 -1
- package/dist/crypto/hkdf.js +9 -18
- package/dist/crypto/hkdf.js.map +1 -1
- package/dist/crypto/index.d.ts +9 -4
- package/dist/crypto/index.d.ts.map +1 -1
- package/dist/crypto/index.js +9 -4
- package/dist/crypto/index.js.map +1 -1
- package/dist/crypto/ssh-keys.d.ts +17 -10
- package/dist/crypto/ssh-keys.d.ts.map +1 -1
- package/dist/crypto/ssh-keys.js +28 -108
- package/dist/crypto/ssh-keys.js.map +1 -1
- package/dist/crypto/types.d.ts +18 -88
- package/dist/crypto/types.d.ts.map +1 -1
- package/dist/crypto/types.js +3 -0
- package/dist/crypto/types.js.map +1 -1
- package/dist/pipeline/content-pipeline.d.ts.map +1 -1
- package/dist/pipeline/content-pipeline.js +19 -3
- package/dist/pipeline/content-pipeline.js.map +1 -1
- package/dist/pipeline/extract.d.ts +8 -0
- package/dist/pipeline/extract.d.ts.map +1 -1
- package/dist/pipeline/extract.js +15 -4
- package/dist/pipeline/extract.js.map +1 -1
- package/dist/pipeline/fetch-browser.d.ts +29 -0
- package/dist/pipeline/fetch-browser.d.ts.map +1 -0
- package/dist/pipeline/fetch-browser.js +98 -0
- package/dist/pipeline/fetch-browser.js.map +1 -0
- package/package.json +4 -1
- package/dist/crypto/argon2.d.ts +0 -11
- package/dist/crypto/argon2.d.ts.map +0 -1
- package/dist/crypto/argon2.js +0 -33
- package/dist/crypto/argon2.js.map +0 -1
- package/dist/crypto/invite.d.ts +0 -31
- package/dist/crypto/invite.d.ts.map +0 -1
- package/dist/crypto/invite.js +0 -139
- package/dist/crypto/invite.js.map +0 -1
- package/dist/crypto/keyring.d.ts +0 -37
- package/dist/crypto/keyring.d.ts.map +0 -1
- package/dist/crypto/keyring.js +0 -219
- package/dist/crypto/keyring.js.map +0 -1
- package/dist/crypto/known-keys.d.ts +0 -34
- package/dist/crypto/known-keys.d.ts.map +0 -1
- package/dist/crypto/known-keys.js +0 -114
- package/dist/crypto/known-keys.js.map +0 -1
- package/dist/crypto/project-keys.d.ts +0 -26
- package/dist/crypto/project-keys.d.ts.map +0 -1
- package/dist/crypto/project-keys.js +0 -69
- package/dist/crypto/project-keys.js.map +0 -1
- package/dist/crypto/secure-buffer.d.ts +0 -31
- package/dist/crypto/secure-buffer.d.ts.map +0 -1
- package/dist/crypto/secure-buffer.js +0 -61
- package/dist/crypto/secure-buffer.js.map +0 -1
- package/dist/crypto/tiers/enhanced.d.ts +0 -25
- package/dist/crypto/tiers/enhanced.d.ts.map +0 -1
- package/dist/crypto/tiers/enhanced.js +0 -56
- package/dist/crypto/tiers/enhanced.js.map +0 -1
- package/dist/crypto/tiers/maximum.d.ts +0 -19
- package/dist/crypto/tiers/maximum.d.ts.map +0 -1
- package/dist/crypto/tiers/maximum.js +0 -25
- package/dist/crypto/tiers/maximum.js.map +0 -1
- package/dist/crypto/tiers/standard.d.ts +0 -27
- package/dist/crypto/tiers/standard.d.ts.map +0 -1
- package/dist/crypto/tiers/standard.js +0 -155
- package/dist/crypto/tiers/standard.js.map +0 -1
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless-browser fallback for JavaScript-rendered pages.
|
|
3
|
+
*
|
|
4
|
+
* When `extractContent` throws `JsRenderRequiredError`, the content pipeline
|
|
5
|
+
* calls `fetchUrlWithBrowser` to re-fetch the URL through a Chromium instance
|
|
6
|
+
* that executes the page's JavaScript, then feeds the rendered HTML back into
|
|
7
|
+
* the normal extraction path.
|
|
8
|
+
*
|
|
9
|
+
* A module-level singleton Browser is launched lazily on first use and
|
|
10
|
+
* self-closes after `IDLE_SHUTDOWN_MS` of inactivity, amortizing the 2–5 s
|
|
11
|
+
* cold start across sequential ingestions while releasing the Chromium
|
|
12
|
+
* subprocess (~200 MB resident) when the fallback isn't active.
|
|
13
|
+
*/
|
|
14
|
+
import { chromium } from 'playwright';
|
|
15
|
+
import { MAX_RESPONSE_BYTES, validateUrl } from './fetch.js';
|
|
16
|
+
const IDLE_SHUTDOWN_MS = 60_000;
|
|
17
|
+
const NAV_TIMEOUT_MS = 15_000;
|
|
18
|
+
let browserPromise = null;
|
|
19
|
+
let idleTimer = null;
|
|
20
|
+
async function getBrowser() {
|
|
21
|
+
if (!browserPromise) {
|
|
22
|
+
browserPromise = chromium.launch({ headless: true });
|
|
23
|
+
}
|
|
24
|
+
return browserPromise;
|
|
25
|
+
}
|
|
26
|
+
function scheduleIdleShutdown() {
|
|
27
|
+
if (idleTimer)
|
|
28
|
+
clearTimeout(idleTimer);
|
|
29
|
+
idleTimer = setTimeout(async () => {
|
|
30
|
+
const p = browserPromise;
|
|
31
|
+
browserPromise = null;
|
|
32
|
+
idleTimer = null;
|
|
33
|
+
try {
|
|
34
|
+
const browser = await p;
|
|
35
|
+
await browser?.close();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Best-effort shutdown; swallow errors from a browser that already exited.
|
|
39
|
+
}
|
|
40
|
+
}, IDLE_SHUTDOWN_MS);
|
|
41
|
+
idleTimer.unref();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Fetch a URL through a headless Chromium instance, executing JavaScript and
|
|
45
|
+
* returning the post-render HTML.
|
|
46
|
+
*
|
|
47
|
+
* @param url - The URL to render. SSRF-validated before the browser launch.
|
|
48
|
+
* @returns The fully rendered HTML as a string.
|
|
49
|
+
* @throws If SSRF validation fails, navigation times out, or the rendered
|
|
50
|
+
* HTML exceeds `MAX_RESPONSE_BYTES`.
|
|
51
|
+
*/
|
|
52
|
+
export async function fetchUrlWithBrowser(url) {
|
|
53
|
+
// SSRF: validateUrl covers scheme, blocked hostnames, IP-literal private-IP
|
|
54
|
+
// check, DNS resolution, and per-resolved-address private-IP rejection.
|
|
55
|
+
await validateUrl(url);
|
|
56
|
+
const browser = await getBrowser();
|
|
57
|
+
const context = await browser.newContext();
|
|
58
|
+
try {
|
|
59
|
+
const page = await context.newPage();
|
|
60
|
+
try {
|
|
61
|
+
await page.goto(url, { waitUntil: 'networkidle', timeout: NAV_TIMEOUT_MS });
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Some sites never go fully idle (long-polling, analytics beacons).
|
|
65
|
+
// Fall back to domcontentloaded so we still capture the rendered DOM.
|
|
66
|
+
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: NAV_TIMEOUT_MS });
|
|
67
|
+
}
|
|
68
|
+
const html = await page.content();
|
|
69
|
+
if (html.length > MAX_RESPONSE_BYTES) {
|
|
70
|
+
throw new Error(`Rendered page exceeds ${MAX_RESPONSE_BYTES / 1024 / 1024} MB limit.`);
|
|
71
|
+
}
|
|
72
|
+
return html;
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
await context.close();
|
|
76
|
+
scheduleIdleShutdown();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Testing hook: tear down the singleton browser and cancel any pending idle
|
|
81
|
+
* shutdown. Not called from production code.
|
|
82
|
+
*/
|
|
83
|
+
export async function _resetBrowserSingletonForTests() {
|
|
84
|
+
if (idleTimer) {
|
|
85
|
+
clearTimeout(idleTimer);
|
|
86
|
+
idleTimer = null;
|
|
87
|
+
}
|
|
88
|
+
const p = browserPromise;
|
|
89
|
+
browserPromise = null;
|
|
90
|
+
try {
|
|
91
|
+
const browser = await p;
|
|
92
|
+
await browser?.close();
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// ignore
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=fetch-browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-browser.js","sourceRoot":"","sources":["../../pipeline/fetch-browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAgB,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAChC,MAAM,cAAc,GAAG,MAAM,CAAC;AAE9B,IAAI,cAAc,GAA4B,IAAI,CAAC;AACnD,IAAI,SAAS,GAA0B,IAAI,CAAC;AAE5C,KAAK,UAAU,UAAU;IACvB,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,SAAS,oBAAoB;IAC3B,IAAI,SAAS;QAAE,YAAY,CAAC,SAAS,CAAC,CAAC;IACvC,SAAS,GAAG,UAAU,CAAC,KAAK,IAAI,EAAE;QAChC,MAAM,CAAC,GAAG,cAAc,CAAC;QACzB,cAAc,GAAG,IAAI,CAAC;QACtB,SAAS,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC;YACxB,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,2EAA2E;QAC7E,CAAC;IACH,CAAC,EAAE,gBAAgB,CAAC,CAAC;IACrB,SAAS,CAAC,KAAK,EAAE,CAAC;AACpB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAAW;IACnD,4EAA4E;IAC5E,wEAAwE;IACxE,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;IAEvB,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;QAC9E,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;YACpE,sEAAsE;YACtE,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;QACnF,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CACb,yBAAyB,kBAAkB,GAAG,IAAI,GAAG,IAAI,YAAY,CACtE,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,oBAAoB,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B;IAClD,IAAI,SAAS,EAAE,CAAC;QACd,YAAY,CAAC,SAAS,CAAC,CAAC;QACxB,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;IACD,MAAM,CAAC,GAAG,cAAc,CAAC;IACzB,cAAc,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC;QACxB,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@de-otio/chaoskb-client",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "ChaosKB - E2E encrypted personal knowledge base with MCP integration",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@de-otio/agent-safety-pack": "^0.1.1",
|
|
49
|
+
"@de-otio/crypto-envelope": "^0.2.0-alpha.1",
|
|
50
|
+
"@de-otio/keyring": "^0.1.0-alpha.1",
|
|
49
51
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
50
52
|
"@mozilla/readability": "^0.6.0",
|
|
51
53
|
"@noble/ciphers": "^2.1.1",
|
|
@@ -60,6 +62,7 @@
|
|
|
60
62
|
"mammoth": "^1.12.0",
|
|
61
63
|
"onnxruntime-node": "^1.24.3",
|
|
62
64
|
"pdf-parse": "^2.4.5",
|
|
65
|
+
"playwright": "^1.48.0",
|
|
63
66
|
"sodium-native": "^5.1.0",
|
|
64
67
|
"sshpk": "^1.18.0"
|
|
65
68
|
},
|
package/dist/crypto/argon2.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { ISecureBuffer } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Derive a master key from a passphrase using Argon2id.
|
|
4
|
-
* The passphrase is held in a SecureBuffer and zeroed after derivation.
|
|
5
|
-
*
|
|
6
|
-
* @param passphrase - User passphrase
|
|
7
|
-
* @param salt - 16-byte salt (CSPRNG-generated, stored on server)
|
|
8
|
-
* @returns SecureBuffer containing the 32-byte derived key
|
|
9
|
-
*/
|
|
10
|
-
export declare function deriveFromPassphrase(passphrase: string, salt: Uint8Array): ISecureBuffer;
|
|
11
|
-
//# sourceMappingURL=argon2.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"argon2.d.ts","sourceRoot":"","sources":["../../crypto/argon2.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAQhD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,aAAa,CAiBxF"}
|
package/dist/crypto/argon2.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { argon2id } from '@noble/hashes/argon2.js';
|
|
2
|
-
import { SecureBuffer } from './secure-buffer.js';
|
|
3
|
-
// Argon2id parameters per spec: t=3, m=65536 (64MB), p=1, output 32 bytes
|
|
4
|
-
const ARGON2_TIME_COST = 3;
|
|
5
|
-
const ARGON2_MEMORY_COST = 65536; // in KiB = 64 MB
|
|
6
|
-
const ARGON2_PARALLELISM = 1;
|
|
7
|
-
const ARGON2_OUTPUT_LENGTH = 32;
|
|
8
|
-
/**
|
|
9
|
-
* Derive a master key from a passphrase using Argon2id.
|
|
10
|
-
* The passphrase is held in a SecureBuffer and zeroed after derivation.
|
|
11
|
-
*
|
|
12
|
-
* @param passphrase - User passphrase
|
|
13
|
-
* @param salt - 16-byte salt (CSPRNG-generated, stored on server)
|
|
14
|
-
* @returns SecureBuffer containing the 32-byte derived key
|
|
15
|
-
*/
|
|
16
|
-
export function deriveFromPassphrase(passphrase, salt) {
|
|
17
|
-
// Convert passphrase to bytes and hold in a buffer we can zero
|
|
18
|
-
const passphraseBytes = Buffer.from(passphrase, 'utf-8');
|
|
19
|
-
try {
|
|
20
|
-
const derived = argon2id(passphraseBytes, salt, {
|
|
21
|
-
t: ARGON2_TIME_COST,
|
|
22
|
-
m: ARGON2_MEMORY_COST,
|
|
23
|
-
p: ARGON2_PARALLELISM,
|
|
24
|
-
dkLen: ARGON2_OUTPUT_LENGTH,
|
|
25
|
-
});
|
|
26
|
-
return SecureBuffer.from(Buffer.from(derived));
|
|
27
|
-
}
|
|
28
|
-
finally {
|
|
29
|
-
// Zero passphrase memory immediately
|
|
30
|
-
passphraseBytes.fill(0);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
//# sourceMappingURL=argon2.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"argon2.js","sourceRoot":"","sources":["../../crypto/argon2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,0EAA0E;AAC1E,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,kBAAkB,GAAG,KAAK,CAAC,CAAC,iBAAiB;AACnD,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAC7B,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEhC;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAAkB,EAAE,IAAgB;IACvE,+DAA+D;IAC/D,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAEzD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,QAAQ,CAAC,eAAe,EAAE,IAAI,EAAE;YAC9C,CAAC,EAAE,gBAAgB;YACnB,CAAC,EAAE,kBAAkB;YACrB,CAAC,EAAE,kBAAkB;YACrB,KAAK,EAAE,oBAAoB;SAC5B,CAAC,CAAC;QAEH,OAAO,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC;YAAS,CAAC;QACT,qCAAqC;QACrC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC"}
|
package/dist/crypto/invite.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { SSHKeyInfo } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Create an encrypted invite blob for sharing a project key.
|
|
4
|
-
*
|
|
5
|
-
* Uses ephemeral X25519 ECDH + HKDF (with domain separation) + XChaCha20-Poly1305.
|
|
6
|
-
* The sender's and recipient's fingerprints and the project ID are bound into the
|
|
7
|
-
* HKDF info string to prevent cross-context key confusion.
|
|
8
|
-
*
|
|
9
|
-
* Output format: ephemeral_public_key(32) || nonce(24) || ciphertext || tag(16)
|
|
10
|
-
*/
|
|
11
|
-
export declare function createInviteBlob(projectKey: Uint8Array, projectId: string, senderKeyInfo: SSHKeyInfo, recipientKeyInfo: SSHKeyInfo): Uint8Array;
|
|
12
|
-
/**
|
|
13
|
-
* Open an encrypted invite blob to recover the project key.
|
|
14
|
-
*
|
|
15
|
-
* @param blob - The full invite blob (ephemeral_pk || nonce || ciphertext || tag)
|
|
16
|
-
* @param recipientEd25519Sk - The recipient's 64-byte Ed25519 secret key
|
|
17
|
-
* @param recipientKeyInfo - The recipient's SSH key info (for fingerprint)
|
|
18
|
-
* @param senderKeyInfo - The sender's SSH key info (for fingerprint)
|
|
19
|
-
* @param projectId - The project ID (for HKDF domain separation)
|
|
20
|
-
* @returns The raw project key bytes
|
|
21
|
-
*/
|
|
22
|
-
export declare function openInviteBlob(blob: Uint8Array, recipientEd25519Sk: Uint8Array, recipientKeyInfo: SSHKeyInfo, senderKeyInfo: SSHKeyInfo, projectId: string): Uint8Array;
|
|
23
|
-
/**
|
|
24
|
-
* Pad payload to a fixed size to prevent metadata leakage from blob sizes.
|
|
25
|
-
*/
|
|
26
|
-
export declare function padPayload(payload: Uint8Array, targetSize: number): Uint8Array;
|
|
27
|
-
/**
|
|
28
|
-
* Remove padding to recover the original payload.
|
|
29
|
-
*/
|
|
30
|
-
export declare function unpadPayload(padded: Uint8Array): Uint8Array;
|
|
31
|
-
//# sourceMappingURL=invite.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"invite.d.ts","sourceRoot":"","sources":["../../crypto/invite.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,UAAU,EACzB,gBAAgB,EAAE,UAAU,GAC3B,UAAU,CA4CZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,UAAU,EAChB,kBAAkB,EAAE,UAAU,EAC9B,gBAAgB,EAAE,UAAU,EAC5B,aAAa,EAAE,UAAU,EACzB,SAAS,EAAE,MAAM,GAChB,UAAU,CAkCZ;AAeD;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,CAgB9E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAS3D"}
|
package/dist/crypto/invite.js
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
-
import sodium from 'sodium-native';
|
|
3
|
-
// sodium-native types are incomplete — these functions exist at runtime
|
|
4
|
-
const sodiumAny = sodium;
|
|
5
|
-
import { aeadEncrypt, aeadDecrypt } from './aead.js';
|
|
6
|
-
import { deriveKey } from './hkdf.js';
|
|
7
|
-
import { ed25519ToX25519PublicKey, ed25519ToX25519SecretKey } from './ssh-keys.js';
|
|
8
|
-
const PADDED_PAYLOAD_SIZE = 512;
|
|
9
|
-
/**
|
|
10
|
-
* Create an encrypted invite blob for sharing a project key.
|
|
11
|
-
*
|
|
12
|
-
* Uses ephemeral X25519 ECDH + HKDF (with domain separation) + XChaCha20-Poly1305.
|
|
13
|
-
* The sender's and recipient's fingerprints and the project ID are bound into the
|
|
14
|
-
* HKDF info string to prevent cross-context key confusion.
|
|
15
|
-
*
|
|
16
|
-
* Output format: ephemeral_public_key(32) || nonce(24) || ciphertext || tag(16)
|
|
17
|
-
*/
|
|
18
|
-
export function createInviteBlob(projectKey, projectId, senderKeyInfo, recipientKeyInfo) {
|
|
19
|
-
if (recipientKeyInfo.type !== 'ed25519') {
|
|
20
|
-
throw new Error('Invite crypto currently supports Ed25519 recipients only');
|
|
21
|
-
}
|
|
22
|
-
// Generate ephemeral X25519 key pair
|
|
23
|
-
const ephPk = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES);
|
|
24
|
-
const ephSk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES);
|
|
25
|
-
sodiumAny.crypto_box_keypair(ephPk, ephSk);
|
|
26
|
-
// Convert recipient Ed25519 public key to X25519
|
|
27
|
-
const recipientX25519Pk = ed25519ToX25519PublicKey(recipientKeyInfo.publicKeyBytes);
|
|
28
|
-
// ECDH: shared_secret = X25519(ephemeral_secret, recipient_x25519_public)
|
|
29
|
-
const sharedSecret = Buffer.alloc(sodiumAny.crypto_scalarmult_BYTES);
|
|
30
|
-
sodiumAny.crypto_scalarmult(sharedSecret, ephSk, Buffer.from(recipientX25519Pk));
|
|
31
|
-
// Derive encryption key with domain separation
|
|
32
|
-
const info = buildInviteHkdfInfo(senderKeyInfo.fingerprint, recipientKeyInfo.fingerprint, projectId);
|
|
33
|
-
const encryptionKey = deriveKey(new Uint8Array(sharedSecret), info);
|
|
34
|
-
// Pad and encrypt payload
|
|
35
|
-
const payload = JSON.stringify({
|
|
36
|
-
projectKey: Buffer.from(projectKey).toString('base64'),
|
|
37
|
-
projectId,
|
|
38
|
-
});
|
|
39
|
-
const padded = padPayload(new TextEncoder().encode(payload), PADDED_PAYLOAD_SIZE);
|
|
40
|
-
const emptyAAD = new Uint8Array(0);
|
|
41
|
-
const { nonce, ciphertext, tag } = aeadEncrypt(encryptionKey, padded, emptyAAD);
|
|
42
|
-
// Zero sensitive buffers
|
|
43
|
-
ephSk.fill(0);
|
|
44
|
-
sharedSecret.fill(0);
|
|
45
|
-
encryptionKey.fill(0);
|
|
46
|
-
// Output: ephemeral_pk(32) || nonce(24) || ciphertext || tag(16)
|
|
47
|
-
const result = new Uint8Array(ephPk.length + nonce.length + ciphertext.length + tag.length);
|
|
48
|
-
let offset = 0;
|
|
49
|
-
result.set(ephPk, offset);
|
|
50
|
-
offset += ephPk.length;
|
|
51
|
-
result.set(nonce, offset);
|
|
52
|
-
offset += nonce.length;
|
|
53
|
-
result.set(ciphertext, offset);
|
|
54
|
-
offset += ciphertext.length;
|
|
55
|
-
result.set(tag, offset);
|
|
56
|
-
return result;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Open an encrypted invite blob to recover the project key.
|
|
60
|
-
*
|
|
61
|
-
* @param blob - The full invite blob (ephemeral_pk || nonce || ciphertext || tag)
|
|
62
|
-
* @param recipientEd25519Sk - The recipient's 64-byte Ed25519 secret key
|
|
63
|
-
* @param recipientKeyInfo - The recipient's SSH key info (for fingerprint)
|
|
64
|
-
* @param senderKeyInfo - The sender's SSH key info (for fingerprint)
|
|
65
|
-
* @param projectId - The project ID (for HKDF domain separation)
|
|
66
|
-
* @returns The raw project key bytes
|
|
67
|
-
*/
|
|
68
|
-
export function openInviteBlob(blob, recipientEd25519Sk, recipientKeyInfo, senderKeyInfo, projectId) {
|
|
69
|
-
// Parse the blob
|
|
70
|
-
let offset = 0;
|
|
71
|
-
const ephPk = blob.slice(offset, offset + 32);
|
|
72
|
-
offset += 32;
|
|
73
|
-
const nonce = blob.slice(offset, offset + 24);
|
|
74
|
-
offset += 24;
|
|
75
|
-
const tagStart = blob.length - 16;
|
|
76
|
-
const ciphertext = blob.slice(offset, tagStart);
|
|
77
|
-
const tag = blob.slice(tagStart);
|
|
78
|
-
// Convert recipient Ed25519 secret key to X25519
|
|
79
|
-
const recipientX25519Sk = ed25519ToX25519SecretKey(recipientEd25519Sk);
|
|
80
|
-
// ECDH: shared_secret = X25519(recipient_x25519_secret, ephemeral_public)
|
|
81
|
-
const sharedSecret = Buffer.alloc(sodiumAny.crypto_scalarmult_BYTES);
|
|
82
|
-
sodiumAny.crypto_scalarmult(sharedSecret, Buffer.from(recipientX25519Sk), Buffer.from(ephPk));
|
|
83
|
-
// Derive same encryption key
|
|
84
|
-
const info = buildInviteHkdfInfo(senderKeyInfo.fingerprint, recipientKeyInfo.fingerprint, projectId);
|
|
85
|
-
const encryptionKey = deriveKey(new Uint8Array(sharedSecret), info);
|
|
86
|
-
// Decrypt
|
|
87
|
-
const emptyAAD = new Uint8Array(0);
|
|
88
|
-
const padded = aeadDecrypt(encryptionKey, nonce, ciphertext, tag, emptyAAD);
|
|
89
|
-
// Zero sensitive buffers
|
|
90
|
-
const skBuf = Buffer.from(recipientX25519Sk);
|
|
91
|
-
skBuf.fill(0);
|
|
92
|
-
sharedSecret.fill(0);
|
|
93
|
-
encryptionKey.fill(0);
|
|
94
|
-
// Unpad and extract project key
|
|
95
|
-
const payload = unpadPayload(padded);
|
|
96
|
-
const parsed = JSON.parse(new TextDecoder().decode(payload));
|
|
97
|
-
return Buffer.from(parsed.projectKey, 'base64');
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Build the HKDF info string with domain separation.
|
|
101
|
-
*
|
|
102
|
-
* Format: "chaoskb-invite-v1" || SHA256(senderFingerprint)(32) || SHA256(recipientFingerprint)(32) || SHA256(projectId)(32)
|
|
103
|
-
* Fixed-width encoding prevents ambiguity from variable-length fields.
|
|
104
|
-
*/
|
|
105
|
-
function buildInviteHkdfInfo(senderFingerprint, recipientFingerprint, projectId) {
|
|
106
|
-
const senderHash = createHash('sha256').update(senderFingerprint).digest('hex').slice(0, 64);
|
|
107
|
-
const recipientHash = createHash('sha256').update(recipientFingerprint).digest('hex').slice(0, 64);
|
|
108
|
-
const projectHash = createHash('sha256').update(projectId).digest('hex').slice(0, 64);
|
|
109
|
-
return `chaoskb-invite-v1${senderHash}${recipientHash}${projectHash}`;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Pad payload to a fixed size to prevent metadata leakage from blob sizes.
|
|
113
|
-
*/
|
|
114
|
-
export function padPayload(payload, targetSize) {
|
|
115
|
-
if (payload.length > targetSize - 4) {
|
|
116
|
-
throw new Error(`Payload too large to pad: ${payload.length} bytes (max ${targetSize - 4})`);
|
|
117
|
-
}
|
|
118
|
-
const padded = new Uint8Array(targetSize);
|
|
119
|
-
// First 4 bytes: big-endian payload length
|
|
120
|
-
const view = new DataView(padded.buffer);
|
|
121
|
-
view.setUint32(0, payload.length, false);
|
|
122
|
-
padded.set(payload, 4);
|
|
123
|
-
// Fill remainder with random bytes
|
|
124
|
-
const randomPadding = randomBytes(targetSize - 4 - payload.length);
|
|
125
|
-
padded.set(randomPadding, 4 + payload.length);
|
|
126
|
-
return padded;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Remove padding to recover the original payload.
|
|
130
|
-
*/
|
|
131
|
-
export function unpadPayload(padded) {
|
|
132
|
-
const view = new DataView(padded.buffer, padded.byteOffset, padded.byteLength);
|
|
133
|
-
const length = view.getUint32(0, false);
|
|
134
|
-
if (length > padded.length - 4) {
|
|
135
|
-
throw new Error('Invalid padding: declared length exceeds buffer');
|
|
136
|
-
}
|
|
137
|
-
return padded.slice(4, 4 + length);
|
|
138
|
-
}
|
|
139
|
-
//# sourceMappingURL=invite.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"invite.js","sourceRoot":"","sources":["../../crypto/invite.ts"],"names":[],"mappings":"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"}
|
package/dist/crypto/keyring.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { IKeyringService, ISecureBuffer } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* OS keyring integration via shell commands.
|
|
4
|
-
* Uses execFile (not exec) to prevent shell injection.
|
|
5
|
-
*
|
|
6
|
-
* macOS: security add-generic-password / find-generic-password / delete-generic-password
|
|
7
|
-
* Linux: secret-tool store / lookup / clear
|
|
8
|
-
* Windows: cmdkey /add: / /list: / /delete:
|
|
9
|
-
*/
|
|
10
|
-
export declare class KeyringService implements IKeyringService {
|
|
11
|
-
private readonly platform;
|
|
12
|
-
constructor(platform?: NodeJS.Platform);
|
|
13
|
-
/**
|
|
14
|
-
* Store a secret in the OS keyring.
|
|
15
|
-
*/
|
|
16
|
-
store(service: string, account: string, secret: ISecureBuffer): Promise<void>;
|
|
17
|
-
/**
|
|
18
|
-
* Retrieve a secret from the OS keyring.
|
|
19
|
-
* Returns null if not found.
|
|
20
|
-
*/
|
|
21
|
-
retrieve(service: string, account: string): Promise<ISecureBuffer | null>;
|
|
22
|
-
/**
|
|
23
|
-
* Delete a secret from the OS keyring.
|
|
24
|
-
* Returns true if deleted, false if not found.
|
|
25
|
-
*/
|
|
26
|
-
delete(service: string, account: string): Promise<boolean>;
|
|
27
|
-
private storeMacOS;
|
|
28
|
-
private retrieveMacOS;
|
|
29
|
-
private deleteMacOS;
|
|
30
|
-
private storeLinux;
|
|
31
|
-
private retrieveLinux;
|
|
32
|
-
private deleteLinux;
|
|
33
|
-
private storeWindows;
|
|
34
|
-
private retrieveWindows;
|
|
35
|
-
private deleteWindows;
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=keyring.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"keyring.d.ts","sourceRoot":"","sources":["../../crypto/keyring.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIjE;;;;;;;GAOG;AACH,qBAAa,cAAe,YAAW,eAAe;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;gBAE/B,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ;IAItC;;OAEG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBnF;;;OAGG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAyB/E;;;OAGG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;YAuBlD,UAAU;YAqBV,aAAa;YAUb,WAAW;YAUX,UAAU;YAkBV,aAAa;YASb,WAAW;YAUX,YAAY;YAWZ,eAAe;YA4Cf,aAAa;CAI5B"}
|
package/dist/crypto/keyring.js
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
import { execFile } from 'node:child_process';
|
|
2
|
-
import { promisify } from 'node:util';
|
|
3
|
-
import { SecureBuffer } from './secure-buffer.js';
|
|
4
|
-
const execFileAsync = promisify(execFile);
|
|
5
|
-
/**
|
|
6
|
-
* OS keyring integration via shell commands.
|
|
7
|
-
* Uses execFile (not exec) to prevent shell injection.
|
|
8
|
-
*
|
|
9
|
-
* macOS: security add-generic-password / find-generic-password / delete-generic-password
|
|
10
|
-
* Linux: secret-tool store / lookup / clear
|
|
11
|
-
* Windows: cmdkey /add: / /list: / /delete:
|
|
12
|
-
*/
|
|
13
|
-
export class KeyringService {
|
|
14
|
-
platform;
|
|
15
|
-
constructor(platform) {
|
|
16
|
-
this.platform = platform ?? process.platform;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Store a secret in the OS keyring.
|
|
20
|
-
*/
|
|
21
|
-
async store(service, account, secret) {
|
|
22
|
-
const secretHex = secret.buffer.toString('hex');
|
|
23
|
-
try {
|
|
24
|
-
switch (this.platform) {
|
|
25
|
-
case 'darwin':
|
|
26
|
-
await this.storeMacOS(service, account, secretHex);
|
|
27
|
-
break;
|
|
28
|
-
case 'linux':
|
|
29
|
-
await this.storeLinux(service, account, secretHex);
|
|
30
|
-
break;
|
|
31
|
-
case 'win32':
|
|
32
|
-
await this.storeWindows(service, account, secretHex);
|
|
33
|
-
break;
|
|
34
|
-
default:
|
|
35
|
-
throw new Error(`Unsupported platform: ${this.platform}`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
finally {
|
|
39
|
-
// We can't zero the hex string (JS strings are immutable),
|
|
40
|
-
// but we at least don't hold onto it.
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Retrieve a secret from the OS keyring.
|
|
45
|
-
* Returns null if not found.
|
|
46
|
-
*/
|
|
47
|
-
async retrieve(service, account) {
|
|
48
|
-
try {
|
|
49
|
-
let secretHex;
|
|
50
|
-
switch (this.platform) {
|
|
51
|
-
case 'darwin':
|
|
52
|
-
secretHex = await this.retrieveMacOS(service, account);
|
|
53
|
-
break;
|
|
54
|
-
case 'linux':
|
|
55
|
-
secretHex = await this.retrieveLinux(service, account);
|
|
56
|
-
break;
|
|
57
|
-
case 'win32':
|
|
58
|
-
secretHex = await this.retrieveWindows(service, account);
|
|
59
|
-
break;
|
|
60
|
-
default:
|
|
61
|
-
throw new Error(`Unsupported platform: ${this.platform}`);
|
|
62
|
-
}
|
|
63
|
-
const bytes = Buffer.from(secretHex.trim(), 'hex');
|
|
64
|
-
return SecureBuffer.from(bytes);
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Delete a secret from the OS keyring.
|
|
72
|
-
* Returns true if deleted, false if not found.
|
|
73
|
-
*/
|
|
74
|
-
async delete(service, account) {
|
|
75
|
-
try {
|
|
76
|
-
switch (this.platform) {
|
|
77
|
-
case 'darwin':
|
|
78
|
-
await this.deleteMacOS(service, account);
|
|
79
|
-
break;
|
|
80
|
-
case 'linux':
|
|
81
|
-
await this.deleteLinux(service, account);
|
|
82
|
-
break;
|
|
83
|
-
case 'win32':
|
|
84
|
-
await this.deleteWindows(service, account);
|
|
85
|
-
break;
|
|
86
|
-
default:
|
|
87
|
-
throw new Error(`Unsupported platform: ${this.platform}`);
|
|
88
|
-
}
|
|
89
|
-
return true;
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
// --- macOS ---
|
|
96
|
-
async storeMacOS(service, account, secret) {
|
|
97
|
-
// Delete existing entry first (update = delete + add)
|
|
98
|
-
try {
|
|
99
|
-
await execFileAsync('security', [
|
|
100
|
-
'delete-generic-password',
|
|
101
|
-
'-s', service,
|
|
102
|
-
'-a', account,
|
|
103
|
-
]);
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
// Ignore if not found
|
|
107
|
-
}
|
|
108
|
-
await execFileAsync('security', [
|
|
109
|
-
'add-generic-password',
|
|
110
|
-
'-s', service,
|
|
111
|
-
'-a', account,
|
|
112
|
-
'-w', secret,
|
|
113
|
-
'-U', // update if exists
|
|
114
|
-
]);
|
|
115
|
-
}
|
|
116
|
-
async retrieveMacOS(service, account) {
|
|
117
|
-
const { stdout } = await execFileAsync('security', [
|
|
118
|
-
'find-generic-password',
|
|
119
|
-
'-s', service,
|
|
120
|
-
'-a', account,
|
|
121
|
-
'-w', // output password only
|
|
122
|
-
]);
|
|
123
|
-
return stdout.trim();
|
|
124
|
-
}
|
|
125
|
-
async deleteMacOS(service, account) {
|
|
126
|
-
await execFileAsync('security', [
|
|
127
|
-
'delete-generic-password',
|
|
128
|
-
'-s', service,
|
|
129
|
-
'-a', account,
|
|
130
|
-
]);
|
|
131
|
-
}
|
|
132
|
-
// --- Linux ---
|
|
133
|
-
async storeLinux(service, account, secret) {
|
|
134
|
-
// secret-tool reads from stdin
|
|
135
|
-
const child = execFileAsync('secret-tool', [
|
|
136
|
-
'store',
|
|
137
|
-
'--label', `${service}/${account}`,
|
|
138
|
-
'service', service,
|
|
139
|
-
'account', account,
|
|
140
|
-
]);
|
|
141
|
-
// Write secret to stdin
|
|
142
|
-
if (child.child.stdin) {
|
|
143
|
-
child.child.stdin.write(secret);
|
|
144
|
-
child.child.stdin.end();
|
|
145
|
-
}
|
|
146
|
-
await child;
|
|
147
|
-
}
|
|
148
|
-
async retrieveLinux(service, account) {
|
|
149
|
-
const { stdout } = await execFileAsync('secret-tool', [
|
|
150
|
-
'lookup',
|
|
151
|
-
'service', service,
|
|
152
|
-
'account', account,
|
|
153
|
-
]);
|
|
154
|
-
return stdout;
|
|
155
|
-
}
|
|
156
|
-
async deleteLinux(service, account) {
|
|
157
|
-
await execFileAsync('secret-tool', [
|
|
158
|
-
'clear',
|
|
159
|
-
'service', service,
|
|
160
|
-
'account', account,
|
|
161
|
-
]);
|
|
162
|
-
}
|
|
163
|
-
// --- Windows ---
|
|
164
|
-
async storeWindows(service, account, secret) {
|
|
165
|
-
const target = `${service}/${account}`;
|
|
166
|
-
// Use PowerShell with .NET CredentialManager API (no external modules required)
|
|
167
|
-
const script = `
|
|
168
|
-
Add-Type -AssemblyName System.Runtime.InteropServices
|
|
169
|
-
$cred = New-Object System.Management.Automation.PSCredential('${account.replace(/'/g, "''")}', (ConvertTo-SecureString '${secret.replace(/'/g, "''")}' -AsPlainText -Force))
|
|
170
|
-
cmdkey /add:${target} /user:${account} /pass:${secret}
|
|
171
|
-
`.trim();
|
|
172
|
-
await execFileAsync('powershell', ['-NoProfile', '-Command', script]);
|
|
173
|
-
}
|
|
174
|
-
async retrieveWindows(service, account) {
|
|
175
|
-
const target = `${service}/${account}`;
|
|
176
|
-
// Use PowerShell with native .NET Credential API (no external modules needed)
|
|
177
|
-
const script = `
|
|
178
|
-
Add-Type @"
|
|
179
|
-
using System;
|
|
180
|
-
using System.Runtime.InteropServices;
|
|
181
|
-
public class CredentialHelper {
|
|
182
|
-
[DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
|
|
183
|
-
public static extern bool CredReadW(string target, int type, int flags, out IntPtr credential);
|
|
184
|
-
[DllImport("advapi32.dll")]
|
|
185
|
-
public static extern void CredFree(IntPtr credential);
|
|
186
|
-
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
|
|
187
|
-
public struct CREDENTIAL {
|
|
188
|
-
public int Flags; public int Type;
|
|
189
|
-
public string TargetName; public string Comment;
|
|
190
|
-
public long LastWritten; public int CredentialBlobSize;
|
|
191
|
-
public IntPtr CredentialBlob; public int Persist;
|
|
192
|
-
public int AttributeCount; public IntPtr Attributes;
|
|
193
|
-
public string TargetAlias; public string UserName;
|
|
194
|
-
}
|
|
195
|
-
public static string Read(string target) {
|
|
196
|
-
IntPtr ptr;
|
|
197
|
-
if (!CredReadW(target, 1, 0, out ptr)) return "";
|
|
198
|
-
var cred = (CREDENTIAL)Marshal.PtrToStructure(ptr, typeof(CREDENTIAL));
|
|
199
|
-
var secret = Marshal.PtrToStringUni(cred.CredentialBlob, cred.CredentialBlobSize / 2);
|
|
200
|
-
CredFree(ptr);
|
|
201
|
-
return secret;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
"@
|
|
205
|
-
[CredentialHelper]::Read('${target.replace(/'/g, "''")}')
|
|
206
|
-
`.trim();
|
|
207
|
-
const { stdout } = await execFileAsync('powershell', ['-NoProfile', '-Command', script]);
|
|
208
|
-
const result = stdout.trim();
|
|
209
|
-
if (!result) {
|
|
210
|
-
throw new Error(`Credential not found: ${target}`);
|
|
211
|
-
}
|
|
212
|
-
return result;
|
|
213
|
-
}
|
|
214
|
-
async deleteWindows(service, account) {
|
|
215
|
-
const target = `${service}/${account}`;
|
|
216
|
-
await execFileAsync('cmdkey', ['/delete:' + target]);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
//# sourceMappingURL=keyring.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"keyring.js","sourceRoot":"","sources":["../../crypto/keyring.ts"],"names":[],"mappings":"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"}
|