enclave-link 0.1.0 → 0.2.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.
package/dist/enclave.js CHANGED
@@ -1,66 +1,90 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ signRequest,
3
4
  vault
4
- } from "./chunk-LUHJCCBX.js";
5
- import "./chunk-U67V476Y.js";
5
+ } from "./chunk-RHLID3KU.js";
6
+ import "./chunk-7QIF4PCL.js";
6
7
 
7
8
  // src/cli.ts
8
- var usage = `enclave: ask a person for a secret through a one-time link, without ever seeing it
9
+ import { text } from "node:stream/consumers";
10
+ var usage = `enclave: a vault for your agent. Ask a person for a secret through a one-time link, and use it without seeing it
9
11
 
10
12
  enclave ask <name> [field...] print a link asking for <name> (fields default to password)
11
13
  enclave wait <name> wait for the answer and save it to the vault
12
14
  enclave run VAR=<name>/<field>... cmd run cmd with secrets in its environment, hidden in its output
13
- enclave get <name> <field> print a saved value, only ever into a pipe or $(...)
15
+ enclave get <name> <field> print a saved value, for a pipe or $(...)
16
+ enclave save <name> <field> save a value piped in, like a token you just made
14
17
  enclave passkey <name> [field] let the browser sign in with a saved passkey, once, in the next 5 minutes
15
18
  enclave sign sign a passkey request from the browser extension (JSON on stdin)
16
- enclave import proton <vault> copy a Proton Pass vault in, through pass-cli
17
- enclave list saved names and their fields
19
+ enclave import proton [vault...] copy Proton Pass in through pass-cli: every vault, or the ones named
20
+ enclave list [search] saved names and their fields, or the ones matching a name or site
18
21
  enclave rm <name> delete a saved item
19
22
  enclave mcp serve all of this to an agent over MCP (stdio)
20
23
 
21
24
  A field named totp holds a 2FA setup key, and get gives its current code. A field named passkey
22
- holds a passkey: enclave signs with it and never hands out its key.
25
+ holds a passkey: enclave signs with it and keeps its key.
23
26
  ENCLAVE_FROM names who's asking on the page, ENCLAVE_HOME holds the vault (~/.enclave),
24
27
  and ENCLAVE_RELAY points at a self-hosted relay.`;
28
+ var help = ["help", "--help", "-h"];
25
29
  var [command, name, ...rest] = process.argv.slice(2);
26
30
  try {
27
- if (command === "ask" && name) {
31
+ if (!command || help.includes(command) || help.includes(name ?? "")) {
32
+ console.log(usage);
33
+ } else if (name?.startsWith("-")) {
34
+ throw new Error(`there's no ${name} option; enclave --help lists what there is`);
35
+ } else if (command === "ask" && name) {
28
36
  console.log((await vault.ask(name, rest.length ? rest : void 0)).url);
29
- console.error(`Send this link to the person, then run \`enclave wait ${name}\` in the background.`);
37
+ console.error(`Send this link to the person, then run \`enclave wait ${quote(name)}\` in the background.`);
30
38
  } else if (command === "wait" && name) {
31
39
  console.log(`saved ${name}: ${(await vault.wait(name)).join(", ")}`);
32
40
  } else if (command === "run" && name) {
33
41
  const args = [name, ...rest];
34
42
  const split = args.findIndex((arg) => !/^[A-Za-z_]\w*=/.test(arg));
35
43
  if (split < 1) throw new Error("usage: enclave run VAR=<name>/<field>... <command...>");
36
- const secrets = Object.fromEntries(args.slice(0, split).map((arg) => [arg.slice(0, arg.indexOf("=")), arg.slice(arg.indexOf("=") + 1)]));
44
+ const secrets = Object.fromEntries(
45
+ args.slice(0, split).map((arg) => [arg.slice(0, arg.indexOf("=")), arg.slice(arg.indexOf("=") + 1)])
46
+ );
37
47
  process.exitCode = await vault.run(args.slice(split), secrets);
38
48
  } else if (command === "get" && name && rest[0]) {
39
49
  process.stdout.write(await vault.get(name, rest[0]));
50
+ } else if (command === "save" && name && rest[0]) {
51
+ await vault.save(name, rest[0], (await text(process.stdin)).replace(/\r?\n$/, ""));
52
+ console.log(`saved ${name}: ${rest[0]}`);
40
53
  } else if (command === "passkey" && name) {
41
- const { signedIn } = await vault.passkey(name, rest[0]);
42
- console.log(`${name}'s passkey is ready for 5 minutes: sign in with a passkey in the browser now`);
43
- await signedIn;
44
- console.log(`signed in with ${name}'s passkey`);
54
+ await vault.passkey(name, rest[0]);
55
+ console.log(
56
+ `${name}'s passkey is ready for one sign-in in the next 5 minutes: click the site's passkey sign-in now`
57
+ );
45
58
  } else if (command === "sign") {
46
- const request = JSON.parse(await new Response(process.stdin).text());
47
- process.stdout.write(JSON.stringify(await vault.sign(request)));
48
- } else if (command === "import" && name === "proton" && rest[0]) {
49
- const items = [...(await vault.importProton(rest[0])).values()];
50
- const count = (field) => items.filter((item) => Object.keys(item).some((key) => key.split(" ")[0] === field)).length;
51
- console.log(`imported ${items.length} items: ${count("password")} with a password, ${count("totp")} with 2FA, ${count("passkey")} with a passkey`);
59
+ process.stdout.write(JSON.stringify(await vault.sign(parseSignRequest(await text(process.stdin)))));
60
+ } else if (command === "import" && name === "proton") {
61
+ const { items, removed } = await vault.importProton(rest);
62
+ const count = (field) => items.filter((item) => item.fields.some((key) => key.split(" ")[0] === field)).length;
63
+ console.log(
64
+ `imported ${items.length} items: ${count("password")} with a password, ${count("totp")} with 2FA, ${count("passkey")} with a passkey`
65
+ );
66
+ if (removed.length) console.log(`removed ${removed.length} deleted from Proton: ${removed.join(", ")}`);
52
67
  } else if (command === "list") {
53
- for (const item of await vault.list()) console.log(`${item.name}: ${item.fields.join(", ")}`);
68
+ for (const item of await vault.list([name, ...rest].join(" ").trim() || void 0))
69
+ console.log(`${item.name}: ${item.fields.join(", ")}`);
54
70
  } else if (command === "rm" && name) {
55
71
  await vault.remove(name);
56
72
  } else if (command === "mcp") {
57
- const { serve } = await import("./mcp-WPCCWEA2.js");
73
+ const { serve } = await import("./mcp-GVB6A3NA.js");
58
74
  await serve(vault);
59
75
  } else {
60
- console.log(usage);
61
- process.exitCode = command && command !== "help" ? 1 : 0;
76
+ console.error(usage);
77
+ process.exitCode = 1;
62
78
  }
63
79
  } catch (error) {
64
80
  console.error(`enclave: ${error instanceof Error ? error.message : error}`);
65
81
  process.exitCode = 1;
66
82
  }
83
+ function quote(text2) {
84
+ return /^[\w@%+=:,./-]+$/.test(text2) ? text2 : `'${text2.replaceAll("'", `'\\''`)}'`;
85
+ }
86
+ function parseSignRequest(input) {
87
+ const request = signRequest.safeParse(JSON.parse(input));
88
+ if (!request.success) throw new Error("that isn't a passkey request from enclave's extension");
89
+ return request.data;
90
+ }
package/dist/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import {
2
+ Store,
2
3
  openVault,
3
4
  vault
4
- } from "./chunk-LUHJCCBX.js";
5
- import "./chunk-U67V476Y.js";
5
+ } from "./chunk-RHLID3KU.js";
6
+ import "./chunk-7QIF4PCL.js";
6
7
  export {
8
+ Store,
7
9
  openVault,
8
10
  vault
9
11
  };