frely-cli 0.4.1 → 0.5.0

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.
Files changed (82) hide show
  1. package/README.md +24 -32
  2. package/dist/auth.d.ts +3 -0
  3. package/dist/auth.js +43 -58
  4. package/dist/auth.js.map +1 -1
  5. package/dist/cli-launch.d.ts +2 -0
  6. package/dist/cli-launch.js +5 -0
  7. package/dist/cli-launch.js.map +1 -0
  8. package/dist/credential-basic.d.ts +5 -0
  9. package/dist/credential-basic.js +84 -0
  10. package/dist/credential-basic.js.map +1 -0
  11. package/dist/credential-command.d.ts +8 -0
  12. package/dist/credential-command.js +42 -0
  13. package/dist/credential-command.js.map +1 -0
  14. package/dist/credential-file.d.ts +6 -0
  15. package/dist/credential-file.js +212 -0
  16. package/dist/credential-file.js.map +1 -0
  17. package/dist/credential-native.d.ts +3 -0
  18. package/dist/credential-native.js +196 -0
  19. package/dist/credential-native.js.map +1 -0
  20. package/dist/credential-store.d.ts +11 -4
  21. package/dist/credential-store.js +48 -10
  22. package/dist/credential-store.js.map +1 -1
  23. package/dist/credential-system.d.ts +3 -0
  24. package/dist/credential-system.js +99 -0
  25. package/dist/credential-system.js.map +1 -0
  26. package/dist/device/control.d.ts +8 -1
  27. package/dist/device/control.js +7 -14
  28. package/dist/device/control.js.map +1 -1
  29. package/dist/device/identity.d.ts +1 -0
  30. package/dist/device/identity.js +4 -4
  31. package/dist/device/identity.js.map +1 -1
  32. package/dist/device/protocol.d.ts +7 -1
  33. package/dist/device/protocol.js +9 -1
  34. package/dist/device/protocol.js.map +1 -1
  35. package/dist/device/relay-client.js +55 -24
  36. package/dist/device/relay-client.js.map +1 -1
  37. package/dist/device/state.d.ts +1 -2
  38. package/dist/device/state.js +2 -2
  39. package/dist/device/state.js.map +1 -1
  40. package/dist/diagnostics.d.ts +13 -10
  41. package/dist/diagnostics.js +26 -45
  42. package/dist/diagnostics.js.map +1 -1
  43. package/dist/index.js +46 -53
  44. package/dist/index.js.map +1 -1
  45. package/dist/mcp-authorization.d.ts +35 -0
  46. package/dist/mcp-authorization.js +171 -0
  47. package/dist/mcp-authorization.js.map +1 -0
  48. package/dist/network-contract.d.ts +2 -3
  49. package/dist/network-contract.js +16 -13
  50. package/dist/network-contract.js.map +1 -1
  51. package/dist/network.js +3 -3
  52. package/dist/network.js.map +1 -1
  53. package/dist/runtime/mcp-lease.d.ts +14 -0
  54. package/dist/runtime/mcp-lease.js +38 -0
  55. package/dist/runtime/mcp-lease.js.map +1 -0
  56. package/dist/runtime/mcp.d.ts +6 -2
  57. package/dist/runtime/mcp.js +14 -7
  58. package/dist/runtime/mcp.js.map +1 -1
  59. package/dist/runtime/process-manager.d.ts +2 -0
  60. package/dist/runtime/process-manager.js +11 -8
  61. package/dist/runtime/process-manager.js.map +1 -1
  62. package/dist/runtime/process-tree.d.ts +6 -0
  63. package/dist/runtime/process-tree.js +54 -0
  64. package/dist/runtime/process-tree.js.map +1 -0
  65. package/dist/runtime/relay-mcp.d.ts +3 -1
  66. package/dist/runtime/relay-mcp.js +5 -2
  67. package/dist/runtime/relay-mcp.js.map +1 -1
  68. package/dist/runtime/scheduler.d.ts +2 -1
  69. package/dist/runtime/scheduler.js +5 -3
  70. package/dist/runtime/scheduler.js.map +1 -1
  71. package/dist/runtime/workspace.d.ts +1 -1
  72. package/dist/runtime/workspace.js +13 -12
  73. package/dist/runtime/workspace.js.map +1 -1
  74. package/dist/service-windows.d.ts +9 -0
  75. package/dist/service-windows.js +55 -0
  76. package/dist/service-windows.js.map +1 -0
  77. package/dist/service.d.ts +5 -0
  78. package/dist/service.js +81 -78
  79. package/dist/service.js.map +1 -1
  80. package/dist/version.js +8 -5
  81. package/dist/version.js.map +1 -1
  82. package/package.json +7 -6
@@ -0,0 +1,42 @@
1
+ import { spawn } from "node:child_process";
2
+ /** Secrets travel through pipes, never command arguments, a shell, or error messages. */
3
+ export const runCredentialCommand = (file, args, input) => new Promise((resolve, reject) => {
4
+ const child = spawn(file, args, { shell: false, windowsHide: true, stdio: ["pipe", "pipe", "pipe"] });
5
+ const stdout = [];
6
+ const stderr = [];
7
+ let bytes = 0;
8
+ let settled = false;
9
+ const finish = (error, result) => {
10
+ if (settled)
11
+ return;
12
+ settled = true;
13
+ clearTimeout(timer);
14
+ if (error)
15
+ reject(error);
16
+ else
17
+ resolve(result);
18
+ };
19
+ const timer = setTimeout(() => {
20
+ child.kill("SIGKILL");
21
+ finish(new Error("Credential service timed out. Unlock the OS credential store or configure FRELY_CREDENTIAL_STORE=encrypted-file with FRELY_CREDENTIAL_KEY."));
22
+ }, 15_000);
23
+ const collect = (stream, chunk) => {
24
+ bytes += chunk.length;
25
+ if (bytes > 2 * 1024 * 1024) {
26
+ child.kill("SIGKILL");
27
+ finish(new Error("Credential service response exceeded the size limit."));
28
+ return;
29
+ }
30
+ if (stream === "stdout")
31
+ stdout.push(chunk);
32
+ else
33
+ stderr.push(chunk);
34
+ };
35
+ child.stdout.on("data", (chunk) => collect("stdout", chunk));
36
+ child.stderr.on("data", (chunk) => collect("stderr", chunk));
37
+ child.once("error", () => finish(new Error("OS credential tool is unavailable. Linux requires secret-tool and an unlocked Secret Service; headless hosts can use FRELY_CREDENTIAL_STORE=encrypted-file with FRELY_CREDENTIAL_KEY.")));
38
+ child.stdin.on("error", () => { });
39
+ child.once("close", (code) => finish(undefined, { code, stdout: Buffer.concat(stdout).toString("utf8"), stderr: Buffer.concat(stderr).toString("utf8") }));
40
+ child.stdin.end(input ?? "");
41
+ });
42
+ //# sourceMappingURL=credential-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-command.js","sourceRoot":"","sources":["../src/credential-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAS3C,yFAAyF;AACzF,MAAM,CAAC,MAAM,oBAAoB,GAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC5G,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACtG,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,MAAsB,EAAQ,EAAE;QAC7D,IAAI,OAAO;YAAE,OAAO;QACpB,OAAO,GAAG,IAAI,CAAC;QACf,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,KAAK;YAAE,MAAM,CAAC,KAAK,CAAC,CAAC;;YACpB,OAAO,CAAC,MAAO,CAAC,CAAC;IACxB,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;QAC5B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtB,MAAM,CAAC,IAAI,KAAK,CAAC,4IAA4I,CAAC,CAAC,CAAC;IAClK,CAAC,EAAE,MAAM,CAAC,CAAC;IACX,MAAM,OAAO,GAAG,CAAC,MAA2B,EAAE,KAAa,EAAQ,EAAE;QACnE,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC;QACtB,IAAI,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,MAAM,CAAC,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC,CAAC;YAC1E,OAAO;QACT,CAAC;QACD,IAAI,MAAM,KAAK,QAAQ;YAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;;YACvC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC,CAAC;IACF,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;IACrE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;IACrE,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,uLAAuL,CAAC,CAAC,CAAC,CAAC;IACtO,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAqE,CAAC,CAAC,CAAC;IACrG,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3J,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { CredentialStore } from "./credential-store.js";
2
+ /** The encryption key is injected by the operator; this module never writes it to disk. */
3
+ export declare function createEncryptedCredentialStore(root: string, keyHex: string): CredentialStore;
4
+ export declare function ensureCredentialDirectory(path: string, create: boolean): Promise<boolean>;
5
+ export declare function readPrivateFile(path: string): Promise<string | null>;
6
+ export declare function writePrivateFile(path: string, content: string): Promise<void>;
@@ -0,0 +1,212 @@
1
+ import { createCipheriv, createDecipheriv, createHash, randomBytes, randomUUID } from "node:crypto";
2
+ import { constants } from "node:fs";
3
+ import { lstat, mkdir, open, readdir, rename, rmdir, unlink } from "node:fs/promises";
4
+ import { dirname, join } from "node:path";
5
+ const HEADER = "vault.json";
6
+ const CHECK = "frely credential vault v1";
7
+ const MAX_FILE_SIZE = 2 * 1024 * 1024;
8
+ const invalid = () => new Error("Encrypted credential authentication failed. Check FRELY_CREDENTIAL_KEY and vault integrity. Existing credentials were not replaced.");
9
+ /** The encryption key is injected by the operator; this module never writes it to disk. */
10
+ export function createEncryptedCredentialStore(root, keyHex) {
11
+ if (!/^[a-fA-F0-9]{64}$/u.test(keyHex))
12
+ throw new Error("FRELY_CREDENTIAL_KEY must be a 32-byte random key encoded as 64 hexadecimal characters. Provision it through a secret manager; do not store it next to the vault.");
13
+ const key = Buffer.from(keyHex, "hex");
14
+ const context = (service, account) => JSON.stringify(["frely.credentials.v1", service, account]);
15
+ const entryPath = (service, account) => join(root, `${createHash("sha256").update(context(service, account)).digest("hex")}.json`);
16
+ const headerContext = context("vault", "key-check");
17
+ function encrypt(value, aad) {
18
+ const iv = randomBytes(12);
19
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
20
+ cipher.setAAD(Buffer.from(aad));
21
+ const data = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
22
+ return JSON.stringify({ version: 1, algorithm: "aes-256-gcm", iv: iv.toString("base64"), tag: cipher.getAuthTag().toString("base64"), data: data.toString("base64") }) + "\n";
23
+ }
24
+ function decrypt(raw, aad) {
25
+ try {
26
+ const value = JSON.parse(raw);
27
+ if (value.version !== 1 || value.algorithm !== "aes-256-gcm")
28
+ throw invalid();
29
+ const decode = (input) => {
30
+ if (typeof input !== "string")
31
+ throw invalid();
32
+ const result = Buffer.from(input, "base64");
33
+ if (result.toString("base64") !== input)
34
+ throw invalid();
35
+ return result;
36
+ };
37
+ const iv = decode(value.iv), tag = decode(value.tag), data = decode(value.data);
38
+ if (iv.length !== 12 || tag.length !== 16)
39
+ throw invalid();
40
+ const cipher = createDecipheriv("aes-256-gcm", key, iv);
41
+ cipher.setAAD(Buffer.from(aad));
42
+ cipher.setAuthTag(tag);
43
+ return Buffer.concat([cipher.update(data), cipher.final()]).toString("utf8");
44
+ }
45
+ catch {
46
+ throw invalid();
47
+ }
48
+ }
49
+ async function checkHeader(create) {
50
+ if (!await ensureCredentialDirectory(root, create))
51
+ return false;
52
+ const path = join(root, HEADER);
53
+ const check = async () => {
54
+ const raw = await readPrivateFile(path);
55
+ if (raw === null)
56
+ return false;
57
+ if (decrypt(raw, headerContext) !== CHECK)
58
+ throw invalid();
59
+ return true;
60
+ };
61
+ if (await check())
62
+ return true;
63
+ if (!create) {
64
+ if ((await readdir(root)).some((name) => name.endsWith(".json")))
65
+ throw invalid();
66
+ return false;
67
+ }
68
+ // Serialize first-key initialization across processes. A stale lock fails closed.
69
+ const lock = join(root, ".init.lock");
70
+ let locked = false;
71
+ for (let attempt = 0; attempt < 100; attempt++) {
72
+ try {
73
+ await mkdir(lock, { mode: 0o700 });
74
+ locked = true;
75
+ break;
76
+ }
77
+ catch (error) {
78
+ if (!directoryLockBusy(error))
79
+ throw error;
80
+ await new Promise((resolve) => setTimeout(resolve, 50));
81
+ }
82
+ }
83
+ if (!locked)
84
+ throw new Error("Credential vault initialization is locked. Check for another Frely process or a stale .init.lock directory before retrying.");
85
+ try {
86
+ if (!await check()) {
87
+ if ((await readdir(root)).some((name) => name.endsWith(".json")))
88
+ throw invalid();
89
+ await writePrivateFile(path, encrypt(CHECK, headerContext));
90
+ }
91
+ }
92
+ finally {
93
+ await rmdir(lock);
94
+ }
95
+ return true;
96
+ }
97
+ return {
98
+ async getPassword(service, account) {
99
+ if (!await checkHeader(false))
100
+ return null;
101
+ const raw = await readPrivateFile(entryPath(service, account));
102
+ return raw === null ? null : decrypt(raw, context(service, account));
103
+ },
104
+ async setPassword(service, account, password) {
105
+ await checkHeader(true);
106
+ const path = entryPath(service, account);
107
+ const previous = await readPrivateFile(path);
108
+ if (previous !== null)
109
+ decrypt(previous, context(service, account));
110
+ await writePrivateFile(path, encrypt(password, context(service, account)));
111
+ },
112
+ async deletePassword(service, account) {
113
+ if (!await checkHeader(false))
114
+ return false;
115
+ const path = entryPath(service, account);
116
+ const raw = await readPrivateFile(path);
117
+ if (raw === null)
118
+ return false;
119
+ decrypt(raw, context(service, account));
120
+ try {
121
+ await unlink(path);
122
+ return true;
123
+ }
124
+ catch (error) {
125
+ if (hasCode(error, "ENOENT"))
126
+ return false;
127
+ throw error;
128
+ }
129
+ },
130
+ };
131
+ }
132
+ export async function ensureCredentialDirectory(path, create) {
133
+ let info;
134
+ try {
135
+ info = await lstat(path);
136
+ }
137
+ catch (error) {
138
+ if (!hasCode(error, "ENOENT"))
139
+ throw error;
140
+ if (!create)
141
+ return false;
142
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
143
+ const parent = await lstat(dirname(path));
144
+ assertPrivate(parent, true);
145
+ await mkdir(path, { mode: 0o700 }).catch((error) => { if (!hasCode(error, "EEXIST"))
146
+ throw error; });
147
+ info = await lstat(path);
148
+ }
149
+ assertPrivate(await lstat(dirname(path)), true);
150
+ assertPrivate(info, true);
151
+ return true;
152
+ }
153
+ function assertPrivate(info, directory) {
154
+ if (info.isSymbolicLink() || (directory ? !info.isDirectory() : !info.isFile()) || (!directory && info.nlink !== 1))
155
+ throw new Error("Credential vault paths must be regular owner-controlled files and directories, not links.");
156
+ if (process.platform !== "win32" && ((info.mode & 0o077) !== 0 || (process.getuid && info.uid !== process.getuid())))
157
+ throw new Error("Credential vault permissions are unsafe. Use owner-only directories (0700) and files (0600).");
158
+ }
159
+ export async function readPrivateFile(path) {
160
+ let before;
161
+ try {
162
+ before = await lstat(path);
163
+ }
164
+ catch (error) {
165
+ if (hasCode(error, "ENOENT"))
166
+ return null;
167
+ throw error;
168
+ }
169
+ assertPrivate(before, false);
170
+ const file = await open(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
171
+ try {
172
+ const info = await file.stat();
173
+ assertPrivate(info, false);
174
+ if (info.ino !== before.ino || info.dev !== before.dev || info.size > MAX_FILE_SIZE)
175
+ throw new Error("Credential vault file changed or exceeded the size limit.");
176
+ const raw = await file.readFile("utf8");
177
+ if (Buffer.byteLength(raw) > MAX_FILE_SIZE)
178
+ throw new Error("Credential vault file exceeded the size limit.");
179
+ return raw;
180
+ }
181
+ finally {
182
+ await file.close();
183
+ }
184
+ }
185
+ export async function writePrivateFile(path, content) {
186
+ if (Buffer.byteLength(content) > MAX_FILE_SIZE)
187
+ throw new Error("Credential exceeded the size limit.");
188
+ const temporary = join(dirname(path), `.${randomUUID()}.tmp`);
189
+ const file = await open(temporary, "wx", 0o600);
190
+ try {
191
+ await file.writeFile(content, "utf8");
192
+ await file.sync();
193
+ await file.close();
194
+ await rename(temporary, path);
195
+ }
196
+ finally {
197
+ await file.close().catch(() => undefined);
198
+ await unlink(temporary).catch((error) => { if (!hasCode(error, "ENOENT"))
199
+ throw error; });
200
+ }
201
+ }
202
+ function hasCode(error, code) {
203
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
204
+ }
205
+ function directoryLockBusy(error) {
206
+ if (hasCode(error, "EEXIST"))
207
+ return true;
208
+ // Windows can report transient sharing/access errors while another caller owns
209
+ // or removes the directory lock. Retry within the bounded lock window only.
210
+ return process.platform === "win32" && ["EPERM", "EBUSY", "ENOTEMPTY"].some((code) => hasCode(error, code));
211
+ }
212
+ //# sourceMappingURL=credential-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-file.js","sourceRoot":"","sources":["../src/credential-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { CredentialStore } from "./credential-store.js";
2
+ import { type CredentialCommand } from "./credential-command.js";
3
+ export declare function createNativeCredentialStore(platform?: NodeJS.Platform, run?: CredentialCommand): CredentialStore;
@@ -0,0 +1,196 @@
1
+ import { win32 } from "node:path";
2
+ import { runCredentialCommand } from "./credential-command.js";
3
+ const unavailable = () => new Error("OS credential store access failed. Unlock the store and run `frely doctor`; headless hosts can configure FRELY_CREDENTIAL_STORE=encrypted-file with FRELY_CREDENTIAL_KEY. No plaintext fallback was used.");
4
+ const stripNewline = (value) => value.replace(/\r?\n$/u, "");
5
+ export function createNativeCredentialStore(platform = process.platform, run = runCredentialCommand) {
6
+ if (platform === "darwin") {
7
+ const read = async (service, account) => {
8
+ const result = await run("/usr/bin/security", ["find-generic-password", "-s", service, "-a", account, "-g"]);
9
+ if (result.code === 44)
10
+ return null; // errSecItemNotFound; other failures must not become missing credentials.
11
+ if (result.code !== 0)
12
+ throw unavailable();
13
+ const output = stripNewline(result.stderr);
14
+ if (!output.startsWith("password: "))
15
+ throw unavailable();
16
+ const value = output.slice("password: ".length);
17
+ const hex = /^0x([a-fA-F0-9]+)(?:\s.*)?$/su.exec(value)?.[1];
18
+ if (hex && hex.length % 2 === 0)
19
+ return Buffer.from(hex, "hex").toString("utf8");
20
+ if (value.startsWith('"') && value.endsWith('"'))
21
+ return value.slice(1, -1);
22
+ if (value === "")
23
+ return "";
24
+ throw unavailable();
25
+ };
26
+ return {
27
+ getPassword: read,
28
+ async setPassword(service, account, password) {
29
+ // security's interactive parser is not a shell. Restrict its identifiers and send
30
+ // password bytes as hex over stdin; -A and shell/argv secrets are prohibited.
31
+ if ([service, account].some((value) => /[\x00-\x20\x7f"'\\]/u.test(value)))
32
+ throw new Error("Invalid macOS credential identifier.");
33
+ const line = `add-generic-password -U -s "${service}" -a "${account}" -X ${Buffer.from(password, "utf8").toString("hex")}\n`;
34
+ if (Buffer.byteLength(line, "utf8") >= 4096)
35
+ throw new Error("macOS credential command exceeds its input limit.");
36
+ const result = await run("/usr/bin/security", ["-i"], line);
37
+ // Interactive security can exit 0 after a command error; require readback.
38
+ if (result.code !== 0 || await read(service, account) !== password)
39
+ throw unavailable();
40
+ },
41
+ async deletePassword(service, account) {
42
+ const result = await run("/usr/bin/security", ["delete-generic-password", "-s", service, "-a", account]);
43
+ if (result.code === 44)
44
+ return false;
45
+ if (result.code !== 0)
46
+ throw unavailable();
47
+ return true;
48
+ },
49
+ };
50
+ }
51
+ if (platform === "linux") {
52
+ const missing = (result) => result.code === 1 && result.stdout.length === 0 && result.stderr.trim().length === 0;
53
+ const attributes = (service, account) => ["service", service, "account", account];
54
+ const read = async (service, account) => {
55
+ const result = await run("secret-tool", ["lookup", ...attributes(service, account)]);
56
+ if (missing(result))
57
+ return null;
58
+ if (result.code !== 0)
59
+ throw unavailable();
60
+ // secret-tool writes the stored value verbatim when stdout is a pipe.
61
+ // Removing a trailing newline would corrupt legitimate multiline secrets.
62
+ return result.stdout;
63
+ };
64
+ return {
65
+ getPassword: read,
66
+ async setPassword(service, account, password) {
67
+ const result = await run("secret-tool", ["store", "--label=Frely CLI", ...attributes(service, account)], password);
68
+ if (result.code !== 0 || await read(service, account) !== password)
69
+ throw unavailable();
70
+ },
71
+ async deletePassword(service, account) {
72
+ if (await read(service, account) === null)
73
+ return false;
74
+ const result = await run("secret-tool", ["clear", ...attributes(service, account)]);
75
+ if (result.code !== 0)
76
+ throw unavailable();
77
+ return true;
78
+ },
79
+ };
80
+ }
81
+ if (platform === "win32") {
82
+ const execute = async (operation, service, account, password) => {
83
+ const file = win32.join(process.env.SystemRoot || "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
84
+ const result = await run(file, ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", WINDOWS_SCRIPT], JSON.stringify({ operation, target: `${service}/${account}`, account, ...(password !== undefined ? { data: Buffer.from(password, "utf8").toString("base64") } : {}) }));
85
+ if (result.code !== 0)
86
+ throw unavailable();
87
+ try {
88
+ const value = JSON.parse(result.stdout.trim());
89
+ if (value.ok !== true)
90
+ throw unavailable();
91
+ if (operation === "get") {
92
+ if (value.data === null)
93
+ return null;
94
+ if (typeof value.data !== "string")
95
+ throw unavailable();
96
+ return Buffer.from(value.data, "base64").toString("utf8");
97
+ }
98
+ return value.deleted ?? true;
99
+ }
100
+ catch {
101
+ throw unavailable();
102
+ }
103
+ };
104
+ return {
105
+ async getPassword(service, account) { return await execute("get", service, account); },
106
+ async setPassword(service, account, password) {
107
+ if (Buffer.byteLength(password, "utf8") > 2560)
108
+ throw new Error("Windows Credential Manager limits a credential to 2560 bytes. Use FRELY_CREDENTIAL_STORE=encrypted-file with an injected FRELY_CREDENTIAL_KEY for larger credentials.");
109
+ await execute("set", service, account, password);
110
+ },
111
+ async deletePassword(service, account) { return await execute("delete", service, account); },
112
+ };
113
+ }
114
+ throw new Error("Unsupported OS credential store. Configure FRELY_CREDENTIAL_STORE=encrypted-file with FRELY_CREDENTIAL_KEY.");
115
+ }
116
+ // Static source only. Request values enter through stdin JSON, not PowerShell source.
117
+ // CredentialBlob is UTF-8 and TargetName is service/account, matching legacy keytar.
118
+ const WINDOWS_SCRIPT = String.raw `
119
+ $ErrorActionPreference = 'Stop'
120
+ [Console]::InputEncoding = New-Object System.Text.UTF8Encoding($false)
121
+ [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false)
122
+ try {
123
+ Add-Type -TypeDefinition @'
124
+ using System;
125
+ using System.ComponentModel;
126
+ using System.Runtime.InteropServices;
127
+ public static class FrelyCredentials {
128
+ [StructLayout(LayoutKind.Sequential)]
129
+ struct Credential {
130
+ public uint Flags, Type;
131
+ public IntPtr TargetName, Comment;
132
+ public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
133
+ public uint CredentialBlobSize;
134
+ public IntPtr CredentialBlob;
135
+ public uint Persist, AttributeCount;
136
+ public IntPtr Attributes, TargetAlias, UserName;
137
+ }
138
+ [DllImport("advapi32.dll", EntryPoint="CredReadW", CharSet=CharSet.Unicode, SetLastError=true)]
139
+ static extern bool Read(string target, uint type, uint flags, out IntPtr credential);
140
+ [DllImport("advapi32.dll", EntryPoint="CredWriteW", CharSet=CharSet.Unicode, SetLastError=true)]
141
+ static extern bool Write(ref Credential credential, uint flags);
142
+ [DllImport("advapi32.dll", EntryPoint="CredDeleteW", CharSet=CharSet.Unicode, SetLastError=true)]
143
+ static extern bool Delete(string target, uint type, uint flags);
144
+ [DllImport("advapi32.dll")] static extern void CredFree(IntPtr credential);
145
+ public static string Get(string target) {
146
+ IntPtr ptr;
147
+ if (!Read(target, 1, 0, out ptr)) {
148
+ int error = Marshal.GetLastWin32Error();
149
+ if (error == 1168) return null;
150
+ throw new Win32Exception(error);
151
+ }
152
+ try {
153
+ Credential value = (Credential)Marshal.PtrToStructure(ptr, typeof(Credential));
154
+ byte[] data = new byte[value.CredentialBlobSize];
155
+ if (data.Length > 0) Marshal.Copy(value.CredentialBlob, data, 0, data.Length);
156
+ return Convert.ToBase64String(data);
157
+ } finally { CredFree(ptr); }
158
+ }
159
+ public static void Set(string target, string account, string encoded) {
160
+ byte[] data = Convert.FromBase64String(encoded);
161
+ Credential value = new Credential();
162
+ value.Type = 1; value.Persist = 2;
163
+ try {
164
+ value.TargetName = Marshal.StringToCoTaskMemUni(target);
165
+ value.UserName = Marshal.StringToCoTaskMemUni(account);
166
+ value.CredentialBlobSize = (uint)data.Length;
167
+ value.CredentialBlob = Marshal.AllocCoTaskMem(data.Length);
168
+ if (data.Length > 0) Marshal.Copy(data, 0, value.CredentialBlob, data.Length);
169
+ if (!Write(ref value, 0)) throw new Win32Exception(Marshal.GetLastWin32Error());
170
+ } finally {
171
+ if (value.CredentialBlob != IntPtr.Zero) {
172
+ for (int i = 0; i < data.Length; i++) Marshal.WriteByte(value.CredentialBlob, i, 0);
173
+ Marshal.FreeCoTaskMem(value.CredentialBlob);
174
+ }
175
+ Marshal.FreeCoTaskMem(value.TargetName); Marshal.FreeCoTaskMem(value.UserName);
176
+ Array.Clear(data, 0, data.Length);
177
+ }
178
+ }
179
+ public static bool Remove(string target) {
180
+ if (Delete(target, 1, 0)) return true;
181
+ int error = Marshal.GetLastWin32Error();
182
+ if (error == 1168) return false;
183
+ throw new Win32Exception(error);
184
+ }
185
+ }
186
+ '@
187
+ $request = [Console]::In.ReadToEnd() | ConvertFrom-Json
188
+ switch ($request.operation) {
189
+ 'get' { $data = [FrelyCredentials]::Get($request.target); [Console]::Out.Write((@{ok=$true;data=$data} | ConvertTo-Json -Compress)) }
190
+ 'set' { [FrelyCredentials]::Set($request.target,$request.account,$request.data); [Console]::Out.Write('{"ok":true}') }
191
+ 'delete' { $deleted = [FrelyCredentials]::Remove($request.target); [Console]::Out.Write((@{ok=$true;deleted=$deleted} | ConvertTo-Json -Compress)) }
192
+ default { exit 1 }
193
+ }
194
+ } catch { [Console]::Error.Write('Windows credential operation failed.'); exit 1 }
195
+ `;
196
+ //# sourceMappingURL=credential-native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-native.js","sourceRoot":"","sources":["../src/credential-native.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,oBAAoB,EAA8C,MAAM,yBAAyB,CAAC;AAE3G,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,IAAI,KAAK,CAAC,2MAA2M,CAAC,CAAC;AACjP,MAAM,YAAY,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AAE7E,MAAM,UAAU,2BAA2B,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,MAAyB,oBAAoB;IACpH,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,KAAK,EAAE,OAAe,EAAE,OAAe,EAA0B,EAAE;YAC9E,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,mBAAmB,EAAE,CAAC,uBAAuB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;YAC7G,IAAI,MAAM,CAAC,IAAI,KAAK,EAAE;gBAAE,OAAO,IAAI,CAAC,CAAC,0EAA0E;YAC/G,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;gBAAE,MAAM,WAAW,EAAE,CAAC;YAC3C,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC;gBAAE,MAAM,WAAW,EAAE,CAAC;YAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,GAAG,GAAG,+BAA+B,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC7D,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC;gBAAE,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACjF,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC5E,IAAI,KAAK,KAAK,EAAE;gBAAE,OAAO,EAAE,CAAC;YAC5B,MAAM,WAAW,EAAE,CAAC;QACtB,CAAC,CAAC;QACF,OAAO;YACL,WAAW,EAAE,IAAI;YACjB,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ;gBAC1C,kFAAkF;gBAClF,8EAA8E;gBAC9E,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;gBACpI,MAAM,IAAI,GAAG,+BAA+B,OAAO,SAAS,OAAO,QAAQ,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;gBAC7H,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI;oBAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;gBAClH,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,mBAAmB,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;gBAC5D,2EAA2E;gBAC3E,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,MAAM,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,QAAQ;oBAAE,MAAM,WAAW,EAAE,CAAC;YAC1F,CAAC;YACD,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO;gBACnC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,mBAAmB,EAAE,CAAC,yBAAyB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;gBACzG,IAAI,MAAM,CAAC,IAAI,KAAK,EAAE;oBAAE,OAAO,KAAK,CAAC;gBACrC,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;oBAAE,MAAM,WAAW,EAAE,CAAC;gBAC3C,OAAO,IAAI,CAAC;YACd,CAAC;SACF,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,CAAC,MAAqB,EAAW,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC;QACzI,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,OAAe,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAClG,MAAM,IAAI,GAAG,KAAK,EAAE,OAAe,EAAE,OAAe,EAA0B,EAAE;YAC9E,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,aAAa,EAAE,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;YACrF,IAAI,OAAO,CAAC,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;YACjC,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;gBAAE,MAAM,WAAW,EAAE,CAAC;YAC3C,sEAAsE;YACtE,0EAA0E;YAC1E,OAAO,MAAM,CAAC,MAAM,CAAC;QACvB,CAAC,CAAC;QACF,OAAO;YACL,WAAW,EAAE,IAAI;YACjB,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ;gBAC1C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;gBACnH,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,MAAM,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,QAAQ;oBAAE,MAAM,WAAW,EAAE,CAAC;YAC1F,CAAC;YACD,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO;gBACnC,IAAI,MAAM,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,IAAI;oBAAE,OAAO,KAAK,CAAC;gBACxD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;gBACpF,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;oBAAE,MAAM,WAAW,EAAE,CAAC;gBAC3C,OAAO,IAAI,CAAC;YACd,CAAC;SACF,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,KAAK,EAAE,SAAiB,EAAE,OAAe,EAAE,OAAe,EAAE,QAAiB,EAAoC,EAAE;YACjI,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,aAAa,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC;YAC5H,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,IAAI,OAAO,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACjR,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;gBAAE,MAAM,WAAW,EAAE,CAAC;YAC3C,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAA8D,CAAC;gBAC5G,IAAI,KAAK,CAAC,EAAE,KAAK,IAAI;oBAAE,MAAM,WAAW,EAAE,CAAC;gBAC3C,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;oBACxB,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI;wBAAE,OAAO,IAAI,CAAC;oBACrC,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;wBAAE,MAAM,WAAW,EAAE,CAAC;oBACxD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBAC5D,CAAC;gBACD,OAAO,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC;YAC/B,CAAC;YAAC,MAAM,CAAC;gBAAC,MAAM,WAAW,EAAE,CAAC;YAAC,CAAC;QAClC,CAAC,CAAC;QACF,OAAO;YACL,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,IAAI,OAAO,MAAM,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAkB,CAAC,CAAC,CAAC;YACvG,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ;gBAC1C,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI;oBAAE,MAAM,IAAI,KAAK,CAAC,uKAAuK,CAAC,CAAC;gBACzO,MAAM,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;YACnD,CAAC;YACD,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,IAAI,OAAO,MAAM,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAY,CAAC,CAAC,CAAC;SACxG,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,6GAA6G,CAAC,CAAC;AACjI,CAAC;AAED,sFAAsF;AACtF,qFAAqF;AACrF,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6EhC,CAAC"}
@@ -1,10 +1,17 @@
1
+ import type { CredentialCommand } from "./credential-command.js";
1
2
  export interface CredentialStore {
2
3
  getPassword(service: string, account: string): Promise<string | null>;
3
4
  setPassword(service: string, account: string, password: string): Promise<void>;
4
5
  deletePassword(service: string, account: string): Promise<boolean>;
5
6
  }
6
- /**
7
- * Production credential storage backed by the operating system's secure store.
8
- * Tests replace the methods on this narrow adapter with an in-memory store.
9
- */
7
+ interface StoreOptions {
8
+ platform?: NodeJS.Platform;
9
+ env?: NodeJS.ProcessEnv;
10
+ run?: CredentialCommand;
11
+ }
12
+ export declare function credentialStoreBackend(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): string;
13
+ /** Backend selection and OS access happen at credential use, not module import. */
14
+ export declare function createCredentialStore(options?: StoreOptions): CredentialStore;
15
+ /** Tests replace this narrow adapter without contacting the user's credential store. */
10
16
  export declare const credentialStore: CredentialStore;
17
+ export {};
@@ -1,11 +1,49 @@
1
- import keytar from "keytar";
2
- /**
3
- * Production credential storage backed by the operating system's secure store.
4
- * Tests replace the methods on this narrow adapter with an in-memory store.
5
- */
6
- export const credentialStore = {
7
- getPassword: (service, account) => keytar.getPassword(service, account),
8
- setPassword: (service, account, password) => keytar.setPassword(service, account, password),
9
- deletePassword: (service, account) => keytar.deletePassword(service, account),
10
- };
1
+ import { homedir } from "node:os";
2
+ import { join, resolve } from "node:path";
3
+ import { createNativeCredentialStore } from "./credential-native.js";
4
+ import { createEncryptedCredentialStore } from "./credential-file.js";
5
+ import { createSystemCredentialStore } from "./credential-system.js";
6
+ export function credentialStoreBackend(env = process.env, platform = process.platform) {
7
+ const mode = env.FRELY_CREDENTIAL_STORE ?? "auto";
8
+ if (!["auto", "system", "encrypted-file"].includes(mode))
9
+ throw new Error("FRELY_CREDENTIAL_STORE must be auto, system, or encrypted-file. Plaintext storage is not supported.");
10
+ if (mode === "encrypted-file" || (mode === "auto" && env.FRELY_CREDENTIAL_KEY !== undefined))
11
+ return "encrypted-file";
12
+ if (platform === "darwin")
13
+ return "macOS Keychain";
14
+ if (platform === "win32")
15
+ return "Windows Credential Manager";
16
+ if (platform === "linux")
17
+ return "Linux Secret Service";
18
+ throw new Error("Unsupported OS credential store. Configure encrypted-file storage with an injected FRELY_CREDENTIAL_KEY.");
19
+ }
20
+ /** Backend selection and OS access happen at credential use, not module import. */
21
+ export function createCredentialStore(options = {}) {
22
+ const select = () => {
23
+ const env = options.env ?? process.env;
24
+ const platform = options.platform ?? process.platform;
25
+ if (credentialStoreBackend(env, platform) === "encrypted-file") {
26
+ const root = resolve(join(env.XDG_CONFIG_HOME || join(homedir(), ".config"), "frely", "credentials-v1"));
27
+ return createEncryptedCredentialStore(root, env.FRELY_CREDENTIAL_KEY ?? "");
28
+ }
29
+ const root = resolve(join(env.XDG_CONFIG_HOME || join(homedir(), ".config"), "frely", "system-credentials-v1"));
30
+ return createSystemCredentialStore(root, createNativeCredentialStore(platform, options.run));
31
+ };
32
+ const validate = (service, account) => {
33
+ if (!service || !account || /[\x00-\x1f\x7f]/u.test(service + account))
34
+ throw new Error("Credential service and account must be non-empty and contain no control characters.");
35
+ };
36
+ return {
37
+ async getPassword(service, account) { validate(service, account); return select().getPassword(service, account); },
38
+ async setPassword(service, account, password) {
39
+ validate(service, account);
40
+ if (!password || Buffer.byteLength(password, "utf8") > 1024 * 1024)
41
+ throw new Error("Credential must contain between 1 byte and 1 MiB.");
42
+ await select().setPassword(service, account, password);
43
+ },
44
+ async deletePassword(service, account) { validate(service, account); return select().deletePassword(service, account); },
45
+ };
46
+ }
47
+ /** Tests replace this narrow adapter without contacting the user's credential store. */
48
+ export const credentialStore = createCredentialStore();
11
49
  //# sourceMappingURL=credential-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../src/credential-store.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAQ5B;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAoB;IAC9C,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC;IACvE,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC;IAC3F,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC;CAC9E,CAAC"}
1
+ {"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../src/credential-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { CredentialStore } from "./credential-store.js";
2
+ /** The OS stores a 32-byte master key; authenticated files hold variable-size credentials. */
3
+ export declare function createSystemCredentialStore(root: string, native: CredentialStore): CredentialStore;