getmyenv 0.7.0 → 0.8.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/README.md +18 -16
- package/dist/bin.d.ts +0 -1
- package/dist/bin.js +2 -2
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +13 -17
- package/dist/commands/backup.d.ts +1 -2
- package/dist/commands/backup.js +11 -7
- package/dist/commands/claim.d.ts +1 -2
- package/dist/commands/claim.js +84 -40
- package/dist/commands/context.d.ts +0 -1
- package/dist/commands/context.js +23 -7
- package/dist/commands/export.d.ts +0 -2
- package/dist/commands/export.js +12 -15
- package/dist/commands/guest.d.ts +2 -3
- package/dist/commands/guest.js +10 -11
- package/dist/commands/import.d.ts +2 -2
- package/dist/commands/import.js +6 -4
- package/dist/commands/lock.d.ts +1 -2
- package/dist/commands/lock.js +5 -9
- package/dist/commands/ls.d.ts +0 -1
- package/dist/commands/ls.js +0 -1
- package/dist/commands/restore.d.ts +3 -4
- package/dist/commands/restore.js +52 -28
- package/dist/commands/run.d.ts +0 -2
- package/dist/commands/run.js +7 -16
- package/dist/commands/set.d.ts +0 -2
- package/dist/commands/set.js +4 -17
- package/dist/commands/start.d.ts +8 -3
- package/dist/commands/start.js +49 -11
- package/dist/commands/status.d.ts +0 -1
- package/dist/commands/status.js +3 -2
- package/dist/commands/template.d.ts +13 -0
- package/dist/commands/template.js +75 -0
- package/dist/commands/unlink.d.ts +0 -1
- package/dist/commands/unlink.js +4 -8
- package/dist/lib/api-url.d.ts +0 -1
- package/dist/lib/api-url.js +0 -1
- package/dist/lib/api.d.ts +13 -8
- package/dist/lib/api.js +10 -5
- package/dist/lib/authorize.d.ts +0 -1
- package/dist/lib/authorize.js +2 -3
- package/dist/lib/bootstrap.d.ts +0 -1
- package/dist/lib/bootstrap.js +5 -3
- package/dist/lib/confirm.d.ts +0 -1
- package/dist/lib/confirm.js +0 -1
- package/dist/lib/context.d.ts +3 -2
- package/dist/lib/context.js +4 -2
- package/dist/lib/credentials.d.ts +4 -1
- package/dist/lib/credentials.js +28 -2
- package/dist/lib/fs.d.ts +10 -7
- package/dist/lib/fs.js +37 -22
- package/dist/lib/guest-key.d.ts +7 -4
- package/dist/lib/guest-key.js +22 -30
- package/dist/lib/identity.d.ts +1 -2
- package/dist/lib/identity.js +1 -2
- package/dist/lib/keychain.d.ts +19 -6
- package/dist/lib/keychain.js +69 -19
- package/dist/lib/known-keys.d.ts +3 -0
- package/dist/lib/known-keys.js +17 -0
- package/dist/lib/run-env.d.ts +2 -4
- package/dist/lib/run-env.js +9 -1
- package/dist/lib/update-check.d.ts +0 -1
- package/dist/lib/update-check.js +4 -2
- package/dist/lib/upload.d.ts +0 -2
- package/dist/lib/upload.js +11 -20
- package/dist/lib/vault.d.ts +54 -0
- package/dist/lib/vault.js +174 -0
- package/package.json +4 -5
- package/dist/bin.d.ts.map +0 -1
- package/dist/bin.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/backup.d.ts.map +0 -1
- package/dist/commands/backup.js.map +0 -1
- package/dist/commands/claim.d.ts.map +0 -1
- package/dist/commands/claim.js.map +0 -1
- package/dist/commands/context.d.ts.map +0 -1
- package/dist/commands/context.js.map +0 -1
- package/dist/commands/export.d.ts.map +0 -1
- package/dist/commands/export.js.map +0 -1
- package/dist/commands/guest.d.ts.map +0 -1
- package/dist/commands/guest.js.map +0 -1
- package/dist/commands/import.d.ts.map +0 -1
- package/dist/commands/import.js.map +0 -1
- package/dist/commands/lock.d.ts.map +0 -1
- package/dist/commands/lock.js.map +0 -1
- package/dist/commands/ls.d.ts.map +0 -1
- package/dist/commands/ls.js.map +0 -1
- package/dist/commands/restore.d.ts.map +0 -1
- package/dist/commands/restore.js.map +0 -1
- package/dist/commands/run.d.ts.map +0 -1
- package/dist/commands/run.js.map +0 -1
- package/dist/commands/set.d.ts.map +0 -1
- package/dist/commands/set.js.map +0 -1
- package/dist/commands/start.d.ts.map +0 -1
- package/dist/commands/start.js.map +0 -1
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unlink.d.ts.map +0 -1
- package/dist/commands/unlink.js.map +0 -1
- package/dist/lib/api-url.d.ts.map +0 -1
- package/dist/lib/api-url.js.map +0 -1
- package/dist/lib/api.d.ts.map +0 -1
- package/dist/lib/api.js.map +0 -1
- package/dist/lib/authorize.d.ts.map +0 -1
- package/dist/lib/authorize.js.map +0 -1
- package/dist/lib/bootstrap.d.ts.map +0 -1
- package/dist/lib/bootstrap.js.map +0 -1
- package/dist/lib/confirm.d.ts.map +0 -1
- package/dist/lib/confirm.js.map +0 -1
- package/dist/lib/context.d.ts.map +0 -1
- package/dist/lib/context.js.map +0 -1
- package/dist/lib/credentials.d.ts.map +0 -1
- package/dist/lib/credentials.js.map +0 -1
- package/dist/lib/fs.d.ts.map +0 -1
- package/dist/lib/fs.js.map +0 -1
- package/dist/lib/guest-key.d.ts.map +0 -1
- package/dist/lib/guest-key.js.map +0 -1
- package/dist/lib/identity.d.ts.map +0 -1
- package/dist/lib/identity.js.map +0 -1
- package/dist/lib/keychain.d.ts.map +0 -1
- package/dist/lib/keychain.js.map +0 -1
- package/dist/lib/pek.d.ts +0 -27
- package/dist/lib/pek.d.ts.map +0 -1
- package/dist/lib/pek.js +0 -60
- package/dist/lib/pek.js.map +0 -1
- package/dist/lib/run-env.d.ts.map +0 -1
- package/dist/lib/run-env.js.map +0 -1
- package/dist/lib/unlock.d.ts +0 -24
- package/dist/lib/unlock.d.ts.map +0 -1
- package/dist/lib/unlock.js +0 -83
- package/dist/lib/unlock.js.map +0 -1
- package/dist/lib/update-check.d.ts.map +0 -1
- package/dist/lib/update-check.js.map +0 -1
- package/dist/lib/upload.d.ts.map +0 -1
- package/dist/lib/upload.js.map +0 -1
package/dist/lib/identity.d.ts
CHANGED
|
@@ -2,9 +2,8 @@ import { type MachineKeypair } from "@getmyenv/crypto";
|
|
|
2
2
|
import { type MachineProof } from "@getmyenv/shared";
|
|
3
3
|
/**
|
|
4
4
|
* Machine identity per project, stored in the OS user config (never the repo).
|
|
5
|
-
* It identifies this machine for
|
|
5
|
+
* It identifies this machine for read-only contexts. It does not decrypt values.
|
|
6
6
|
*/
|
|
7
7
|
export declare function loadOrCreateIdentity(projectId: string): MachineKeypair;
|
|
8
8
|
export declare function machineLabel(): string;
|
|
9
9
|
export declare function signMachineProof(projectId: string, contextSlug: string): MachineProof;
|
|
10
|
-
//# sourceMappingURL=identity.d.ts.map
|
package/dist/lib/identity.js
CHANGED
|
@@ -6,7 +6,7 @@ import { machineProofMessage } from "@getmyenv/shared";
|
|
|
6
6
|
import { getConfigDir } from "./fs.js";
|
|
7
7
|
/**
|
|
8
8
|
* Machine identity per project, stored in the OS user config (never the repo).
|
|
9
|
-
* It identifies this machine for
|
|
9
|
+
* It identifies this machine for read-only contexts. It does not decrypt values.
|
|
10
10
|
*/
|
|
11
11
|
export function loadOrCreateIdentity(projectId) {
|
|
12
12
|
const dir = path.join(getConfigDir(), "machines");
|
|
@@ -45,4 +45,3 @@ export function signMachineProof(projectId, contextSlug) {
|
|
|
45
45
|
timestamp,
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
-
//# sourceMappingURL=identity.js.map
|
package/dist/lib/keychain.d.ts
CHANGED
|
@@ -5,17 +5,30 @@ type KeyringEntry = {
|
|
|
5
5
|
deletePassword(): boolean;
|
|
6
6
|
};
|
|
7
7
|
export type KeyringFactory = (service: string, account: string) => KeyringEntry;
|
|
8
|
+
export type KeyringAccounts = (service: string) => string[];
|
|
8
9
|
/** Tests swap in an in-memory keyring. `null` means no keyring available. */
|
|
9
|
-
export declare function setKeyringForTests(factory: KeyringFactory | null | undefined): void;
|
|
10
|
+
export declare function setKeyringForTests(factory: KeyringFactory | null | undefined, accounts?: KeyringAccounts): void;
|
|
10
11
|
/** Off with `GETMYENV_KEYCHAIN=0` or in CI (`CI` set to anything but `false` or `0`). */
|
|
11
12
|
export declare function keychainEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
12
13
|
/** One keychain entry per server origin and project, so staging and production keys never mix. */
|
|
13
14
|
export declare function keychainAccount(apiUrl: string, projectId: string): string;
|
|
14
|
-
/**
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* The cached key of one context, only if it has not expired and matches the
|
|
17
|
+
* sealed key the server holds now. A new sealed key (rotation) misses.
|
|
18
|
+
*/
|
|
19
|
+
export declare function readCachedContextKey(account: string, contextId: number, sealedRaw: string, now?: number): Promise<Uint8Array | null>;
|
|
16
20
|
/** Returns false when no keychain is available; the CLI then keeps asking. */
|
|
17
|
-
export declare function
|
|
21
|
+
export declare function storeCachedContextKeys(account: string, entries: Array<{
|
|
22
|
+
contextId: number;
|
|
23
|
+
sealedRaw: string;
|
|
24
|
+
key: Uint8Array;
|
|
25
|
+
}>, now?: number): Promise<boolean>;
|
|
18
26
|
/** True when an entry was removed. False when there was none or no keychain is available. */
|
|
19
|
-
export declare function
|
|
27
|
+
export declare function clearCachedKeys(account: string): Promise<boolean>;
|
|
28
|
+
/**
|
|
29
|
+
* Removes every getmyenv entry on this machine, for all servers and projects.
|
|
30
|
+
* `fallback` accounts are cleared too, for keychains that cannot list entries.
|
|
31
|
+
* Returns how many entries were removed.
|
|
32
|
+
*/
|
|
33
|
+
export declare function clearAllCachedKeys(fallback?: string[]): Promise<number>;
|
|
20
34
|
export {};
|
|
21
|
-
//# sourceMappingURL=keychain.d.ts.map
|
package/dist/lib/keychain.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Unlocked open context keys, remembered in the OS keychain (macOS Keychain,
|
|
4
4
|
* Windows Credential Manager, Linux Secret Service) for a few hours so `run`
|
|
5
5
|
* on an open context does not ask for the Vault password every time.
|
|
6
|
-
* Never the Vault password
|
|
6
|
+
* Never the Vault password or the private key.
|
|
7
7
|
*/
|
|
8
8
|
const SERVICE = "getmyenv";
|
|
9
9
|
export const KEYCHAIN_TTL_MS = 8 * 60 * 60 * 1000;
|
|
10
10
|
let factoryOverride;
|
|
11
|
+
let accountsOverride;
|
|
11
12
|
/** Tests swap in an in-memory keyring. `null` means no keyring available. */
|
|
12
|
-
export function setKeyringForTests(factory) {
|
|
13
|
+
export function setKeyringForTests(factory, accounts) {
|
|
13
14
|
factoryOverride = factory;
|
|
15
|
+
accountsOverride = accounts;
|
|
14
16
|
}
|
|
15
17
|
async function loadFactory() {
|
|
16
18
|
if (factoryOverride !== undefined)
|
|
@@ -23,6 +25,17 @@ async function loadFactory() {
|
|
|
23
25
|
return null;
|
|
24
26
|
}
|
|
25
27
|
}
|
|
28
|
+
async function loadAccounts() {
|
|
29
|
+
if (factoryOverride !== undefined)
|
|
30
|
+
return accountsOverride ?? null;
|
|
31
|
+
try {
|
|
32
|
+
const { findCredentials } = await import("@napi-rs/keyring");
|
|
33
|
+
return (service) => findCredentials(service).map((c) => c.account);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
26
39
|
/** Off with `GETMYENV_KEYCHAIN=0` or in CI (`CI` set to anything but `false` or `0`). */
|
|
27
40
|
export function keychainEnabled(env = process.env) {
|
|
28
41
|
if (env.GETMYENV_KEYCHAIN === "0")
|
|
@@ -43,8 +56,8 @@ export function keychainAccount(apiUrl, projectId) {
|
|
|
43
56
|
}
|
|
44
57
|
return `${origin}|project:${projectId}`;
|
|
45
58
|
}
|
|
46
|
-
function
|
|
47
|
-
return createHash("sha256").update(
|
|
59
|
+
function hashSealed(sealedRaw) {
|
|
60
|
+
return createHash("sha256").update(sealedRaw).digest("hex");
|
|
48
61
|
}
|
|
49
62
|
async function entryFor(account) {
|
|
50
63
|
const factory = await loadFactory();
|
|
@@ -57,11 +70,7 @@ async function entryFor(account) {
|
|
|
57
70
|
return null;
|
|
58
71
|
}
|
|
59
72
|
}
|
|
60
|
-
|
|
61
|
-
export async function readCachedPek(account, wrappedRaw, now = Date.now()) {
|
|
62
|
-
const entry = await entryFor(account);
|
|
63
|
-
if (!entry)
|
|
64
|
-
return null;
|
|
73
|
+
function readStored(entry, now) {
|
|
65
74
|
let raw;
|
|
66
75
|
try {
|
|
67
76
|
raw = entry.getPassword();
|
|
@@ -79,24 +88,43 @@ export async function readCachedPek(account, wrappedRaw, now = Date.now()) {
|
|
|
79
88
|
safeDelete(entry);
|
|
80
89
|
return null;
|
|
81
90
|
}
|
|
82
|
-
if (
|
|
83
|
-
stored.wrappedHash !== hashWrapped(wrappedRaw) ||
|
|
91
|
+
if (stored.version !== 2 ||
|
|
84
92
|
typeof stored.expiresAt !== "number" ||
|
|
85
|
-
stored.expiresAt <= now
|
|
93
|
+
stored.expiresAt <= now ||
|
|
94
|
+
!stored.keys ||
|
|
95
|
+
typeof stored.keys !== "object") {
|
|
86
96
|
safeDelete(entry);
|
|
87
97
|
return null;
|
|
88
98
|
}
|
|
89
|
-
return
|
|
99
|
+
return stored;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The cached key of one context, only if it has not expired and matches the
|
|
103
|
+
* sealed key the server holds now. A new sealed key (rotation) misses.
|
|
104
|
+
*/
|
|
105
|
+
export async function readCachedContextKey(account, contextId, sealedRaw, now = Date.now()) {
|
|
106
|
+
const entry = await entryFor(account);
|
|
107
|
+
if (!entry)
|
|
108
|
+
return null;
|
|
109
|
+
const stored = readStored(entry, now);
|
|
110
|
+
const hit = stored?.keys[String(contextId)];
|
|
111
|
+
if (!hit || typeof hit.key !== "string" || hit.sealedHash !== hashSealed(sealedRaw))
|
|
112
|
+
return null;
|
|
113
|
+
const key = new Uint8Array(Buffer.from(hit.key, "base64"));
|
|
114
|
+
return key.length === 32 ? key : null;
|
|
90
115
|
}
|
|
91
116
|
/** Returns false when no keychain is available; the CLI then keeps asking. */
|
|
92
|
-
export async function
|
|
117
|
+
export async function storeCachedContextKeys(account, entries, now = Date.now()) {
|
|
93
118
|
const entry = await entryFor(account);
|
|
94
119
|
if (!entry)
|
|
95
120
|
return false;
|
|
96
121
|
const stored = {
|
|
97
|
-
|
|
98
|
-
wrappedHash: hashWrapped(wrappedRaw),
|
|
122
|
+
version: 2,
|
|
99
123
|
expiresAt: now + KEYCHAIN_TTL_MS,
|
|
124
|
+
keys: Object.fromEntries(entries.map((e) => [
|
|
125
|
+
String(e.contextId),
|
|
126
|
+
{ key: Buffer.from(e.key).toString("base64"), sealedHash: hashSealed(e.sealedRaw) },
|
|
127
|
+
])),
|
|
100
128
|
};
|
|
101
129
|
try {
|
|
102
130
|
entry.setPassword(JSON.stringify(stored));
|
|
@@ -107,12 +135,35 @@ export async function storeCachedPek(account, wrappedRaw, pek, now = Date.now())
|
|
|
107
135
|
}
|
|
108
136
|
}
|
|
109
137
|
/** True when an entry was removed. False when there was none or no keychain is available. */
|
|
110
|
-
export async function
|
|
138
|
+
export async function clearCachedKeys(account) {
|
|
111
139
|
const entry = await entryFor(account);
|
|
112
140
|
if (!entry)
|
|
113
141
|
return false;
|
|
114
142
|
return safeDelete(entry);
|
|
115
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Removes every getmyenv entry on this machine, for all servers and projects.
|
|
146
|
+
* `fallback` accounts are cleared too, for keychains that cannot list entries.
|
|
147
|
+
* Returns how many entries were removed.
|
|
148
|
+
*/
|
|
149
|
+
export async function clearAllCachedKeys(fallback = []) {
|
|
150
|
+
let accounts = [];
|
|
151
|
+
const list = await loadAccounts();
|
|
152
|
+
if (list) {
|
|
153
|
+
try {
|
|
154
|
+
accounts = list(SERVICE);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
accounts = [];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
let removed = 0;
|
|
161
|
+
for (const account of new Set([...accounts, ...fallback])) {
|
|
162
|
+
if (await clearCachedKeys(account))
|
|
163
|
+
removed++;
|
|
164
|
+
}
|
|
165
|
+
return removed;
|
|
166
|
+
}
|
|
116
167
|
function safeDelete(entry) {
|
|
117
168
|
try {
|
|
118
169
|
return entry.deletePassword();
|
|
@@ -121,4 +172,3 @@ function safeDelete(entry) {
|
|
|
121
172
|
return false;
|
|
122
173
|
}
|
|
123
174
|
}
|
|
124
|
-
//# sourceMappingURL=keychain.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
import { nearMissKnownKey } from "@getmyenv/shared";
|
|
3
|
+
/** "Did you mean OPENAI_API_KEY?" for names close to a known one. Nothing is renamed. */
|
|
4
|
+
export function didYouMean(name) {
|
|
5
|
+
const near = nearMissKnownKey(name);
|
|
6
|
+
if (!near)
|
|
7
|
+
return null;
|
|
8
|
+
const why = near.source === "sdk" ? `${near.provider} SDKs read that name.` : "That is the common name.";
|
|
9
|
+
return `Did you mean ${near.name}? ${why}`;
|
|
10
|
+
}
|
|
11
|
+
export function printDidYouMean(names, indent = "") {
|
|
12
|
+
for (const name of names) {
|
|
13
|
+
const hint = didYouMean(name);
|
|
14
|
+
if (hint)
|
|
15
|
+
console.error(pc.yellow(`${indent}${name}: ${hint}`));
|
|
16
|
+
}
|
|
17
|
+
}
|
package/dist/lib/run-env.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
*/
|
|
1
|
+
/** Names from the server go into an environment or a file. Refuse any that are not variable names. */
|
|
2
|
+
export declare function assertVariableNames(names: Iterable<string>): void;
|
|
4
3
|
export type MissingKey = {
|
|
5
4
|
name: string;
|
|
6
5
|
reason: "missing" | "expired";
|
|
@@ -47,4 +46,3 @@ export declare function windowsCommandLine(args: string[]): string;
|
|
|
47
46
|
export declare function signalExitCode(signal: NodeJS.Signals, numbers: Record<string, number>): number;
|
|
48
47
|
/** `--explain` output. Names and origins only, never values. */
|
|
49
48
|
export declare function explainLines(result: MergeResult, contextSlug: string): string[];
|
|
50
|
-
//# sourceMappingURL=run-env.d.ts.map
|
package/dist/lib/run-env.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pure pieces of `getmyenv run`: validate and merge. Names only in any output.
|
|
3
3
|
*/
|
|
4
|
+
import { isValidVariableName } from "@getmyenv/shared";
|
|
5
|
+
/** Names from the server go into an environment or a file. Refuse any that are not variable names. */
|
|
6
|
+
export function assertVariableNames(names) {
|
|
7
|
+
for (const name of names) {
|
|
8
|
+
if (!isValidVariableName(name)) {
|
|
9
|
+
throw new Error("The server sent a name that is not a valid variable name. Nothing was run or written.");
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
4
13
|
/** The child never sees the CLI's own settings (token, API URL, config dir). */
|
|
5
14
|
export function withoutOwnEnv(parent) {
|
|
6
15
|
const env = {};
|
|
@@ -111,4 +120,3 @@ export function explainLines(result, contextSlug) {
|
|
|
111
120
|
lines.push(` ${result.applied.length} from getmyenv, ${result.overridden.length} replaced, ${result.kept.length} kept, ${result.filledByParent.length} from parent env, ${result.unresolved.length} not set`);
|
|
112
121
|
return lines;
|
|
113
122
|
}
|
|
114
|
-
//# sourceMappingURL=run-env.js.map
|
|
@@ -11,4 +11,3 @@ export declare function updateLine(current: string, latest: string | null): stri
|
|
|
11
11
|
* cached npm version, refreshed in the background once a day. Skipped in CI.
|
|
12
12
|
*/
|
|
13
13
|
export declare function maybeSuggestUpdate(): Promise<void>;
|
|
14
|
-
//# sourceMappingURL=update-check.d.ts.map
|
package/dist/lib/update-check.js
CHANGED
|
@@ -90,7 +90,10 @@ async function fetchAndCache(file, timeoutMs) {
|
|
|
90
90
|
const ctrl = new AbortController();
|
|
91
91
|
setTimeout(() => ctrl.abort(), timeoutMs).unref();
|
|
92
92
|
try {
|
|
93
|
-
const res = await fetch("https://registry.npmjs.org/getmyenv/latest", {
|
|
93
|
+
const res = await fetch("https://registry.npmjs.org/getmyenv/latest", {
|
|
94
|
+
signal: ctrl.signal,
|
|
95
|
+
redirect: "error",
|
|
96
|
+
});
|
|
94
97
|
if (!res.ok)
|
|
95
98
|
return;
|
|
96
99
|
const data = (await res.json());
|
|
@@ -132,4 +135,3 @@ export async function maybeSuggestUpdate() {
|
|
|
132
135
|
if (line)
|
|
133
136
|
console.error(pc.yellow(line));
|
|
134
137
|
}
|
|
135
|
-
//# sourceMappingURL=update-check.js.map
|
package/dist/lib/upload.d.ts
CHANGED
|
@@ -12,10 +12,8 @@ export declare function uploadValues(input: {
|
|
|
12
12
|
pairs: Record<string, string>;
|
|
13
13
|
prune?: boolean;
|
|
14
14
|
expiresAt?: string | null;
|
|
15
|
-
vaultPasswordStdin?: boolean;
|
|
16
15
|
}): Promise<{
|
|
17
16
|
set: string[];
|
|
18
17
|
pruned: string[];
|
|
19
18
|
declared: string[];
|
|
20
19
|
}>;
|
|
21
|
-
//# sourceMappingURL=upload.d.ts.map
|
package/dist/lib/upload.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { encryptSecret, serializePayload } from "@getmyenv/crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { contextKey } from "./vault.js";
|
|
3
3
|
/** Fail fast before prompting or encrypting. Mirrors the server's `checkWrite`, which still enforces it. */
|
|
4
4
|
export function assertWritable(linked, ctx) {
|
|
5
5
|
if (linked.who.token.kind === "server") {
|
|
@@ -21,33 +21,24 @@ export async function uploadValues(input) {
|
|
|
21
21
|
.filter(([, v]) => v === "")
|
|
22
22
|
.map(([k]) => k);
|
|
23
23
|
let values = [];
|
|
24
|
-
let wrappedProjectKey;
|
|
25
24
|
if (filled.length > 0) {
|
|
26
|
-
const
|
|
27
|
-
const { pek, wrappedRaw, created } = await unlockProjectKey({
|
|
28
|
-
isGuest: linked.who.isGuest,
|
|
29
|
-
projectId: linked.who.project.id,
|
|
30
|
-
wrapped: serverWrapped,
|
|
31
|
-
cache: true,
|
|
32
|
-
allowCreate: true,
|
|
33
|
-
vaultPasswordStdin: input.vaultPasswordStdin,
|
|
34
|
-
apiUrl: linked.apiUrl,
|
|
35
|
-
});
|
|
36
|
-
if (serverWrapped == null || created) {
|
|
37
|
-
wrappedProjectKey = JSON.parse(wrappedRaw);
|
|
38
|
-
}
|
|
25
|
+
const key = await contextKey(linked, context, { create: true });
|
|
39
26
|
values = filled.map(([name, value]) => ({
|
|
40
27
|
name,
|
|
41
|
-
ciphertext: serializePayload(encryptSecret(
|
|
28
|
+
ciphertext: serializePayload(encryptSecret(key, name, value)),
|
|
42
29
|
...(input.expiresAt !== undefined ? { expiresAt: input.expiresAt } : {}),
|
|
43
30
|
}));
|
|
44
31
|
}
|
|
45
|
-
|
|
32
|
+
const body = {
|
|
46
33
|
context: context.slug,
|
|
47
|
-
...(wrappedProjectKey ? { wrappedProjectKey } : {}),
|
|
48
34
|
values,
|
|
49
35
|
...(input.prune ? { prune: true } : {}),
|
|
50
36
|
...(declare.length > 0 ? { declare } : {}),
|
|
51
|
-
}
|
|
37
|
+
};
|
|
38
|
+
if (Buffer.byteLength(JSON.stringify(body)) > UPLOAD_MAX_BYTES) {
|
|
39
|
+
throw new Error("Too much to upload at once (max 1 MB encrypted). Split the file and import each part.");
|
|
40
|
+
}
|
|
41
|
+
return linked.client.request("POST", "/api/cli/values", body);
|
|
52
42
|
}
|
|
53
|
-
|
|
43
|
+
/** Matches the server limit on `/api/cli/values`. */
|
|
44
|
+
const UPLOAD_MAX_BYTES = 1024 * 1024;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type SealedKey, type WrappedPrivateKey } from "@getmyenv/crypto";
|
|
2
|
+
import { type Protection } from "./api.js";
|
|
3
|
+
import type { Linked } from "./bootstrap.js";
|
|
4
|
+
/**
|
|
5
|
+
* Context keys for the CLI.
|
|
6
|
+
*
|
|
7
|
+
* Folder and guest tokens: the account (or guest) private key is wrapped with
|
|
8
|
+
* the Vault password (or the guest passphrase in claim.json). It is unwrapped
|
|
9
|
+
* here, opens the sealed context keys, and is wiped. Open context keys may
|
|
10
|
+
* stay in the OS keychain for 8 hours. The private key is never stored.
|
|
11
|
+
*
|
|
12
|
+
* Server tokens: GETMYENV_TOKEN holds the token's own private key. It opens
|
|
13
|
+
* the one context key sealed to that token. No Vault password.
|
|
14
|
+
*/
|
|
15
|
+
export type VaultContext = {
|
|
16
|
+
id: number;
|
|
17
|
+
slug: string;
|
|
18
|
+
protection: Protection;
|
|
19
|
+
hasKey: boolean;
|
|
20
|
+
sealedKey: SealedKey | null;
|
|
21
|
+
};
|
|
22
|
+
export type VaultInfo = {
|
|
23
|
+
holder: "user" | "guest" | "token";
|
|
24
|
+
publicKey: string | null;
|
|
25
|
+
wrappedPrivateKey: WrappedPrivateKey | null;
|
|
26
|
+
contexts: VaultContext[];
|
|
27
|
+
claim: {
|
|
28
|
+
publicKey: string;
|
|
29
|
+
wrappedPrivateKey: WrappedPrivateKey;
|
|
30
|
+
shares: Array<{
|
|
31
|
+
contextId: number;
|
|
32
|
+
sealedKey: SealedKey;
|
|
33
|
+
}>;
|
|
34
|
+
} | null;
|
|
35
|
+
};
|
|
36
|
+
export type KeyTarget = {
|
|
37
|
+
id: number;
|
|
38
|
+
slug: string;
|
|
39
|
+
protection: Protection;
|
|
40
|
+
/** Sealed key already sent by the server, so no extra request is needed. */
|
|
41
|
+
sealedKey?: SealedKey | null;
|
|
42
|
+
};
|
|
43
|
+
export type KeyOpts = {
|
|
44
|
+
/** Make the Vault password and the context key when they do not exist yet. */
|
|
45
|
+
create?: boolean;
|
|
46
|
+
};
|
|
47
|
+
export declare function fetchVault(linked: Linked): Promise<VaultInfo>;
|
|
48
|
+
/** The context key, unlocking with the Vault password when needed. */
|
|
49
|
+
export declare function contextKey(linked: Linked, target: KeyTarget, opts?: KeyOpts): Promise<Uint8Array>;
|
|
50
|
+
/** Unlock with the Vault password and return the private key. Caller wipes it. */
|
|
51
|
+
export declare function unlockPrivateKey(linked: Linked, opts?: KeyOpts): Promise<{
|
|
52
|
+
vault: VaultInfo;
|
|
53
|
+
privateKey: Uint8Array;
|
|
54
|
+
}>;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
import { createUserKeys, generateContextKey, openSealedKey, sealContextKey, splitServerToken, unwrapPrivateKey, wipe, } from "@getmyenv/crypto";
|
|
3
|
+
import { ApiError } from "./api.js";
|
|
4
|
+
import { resolveVaultPassword } from "./guest-key.js";
|
|
5
|
+
import { KEYCHAIN_TTL_MS, keychainAccount, keychainEnabled, readCachedContextKey, storeCachedContextKeys, } from "./keychain.js";
|
|
6
|
+
/** One unlock per process: several contexts in one command prompt once. */
|
|
7
|
+
const memo = new Map();
|
|
8
|
+
export function fetchVault(linked) {
|
|
9
|
+
return linked.client.request("GET", "/api/cli/vault");
|
|
10
|
+
}
|
|
11
|
+
/** The context key, unlocking with the Vault password when needed. */
|
|
12
|
+
export async function contextKey(linked, target, opts = {}) {
|
|
13
|
+
const cached = memo.get(target.id);
|
|
14
|
+
if (cached)
|
|
15
|
+
return cached;
|
|
16
|
+
if (linked.who.token.kind === "server")
|
|
17
|
+
return serverContextKey(linked, target);
|
|
18
|
+
const account = keychainFor(linked);
|
|
19
|
+
if (account && target.protection === "open" && target.sealedKey) {
|
|
20
|
+
const key = await readCachedContextKey(account, target.id, JSON.stringify(target.sealedKey));
|
|
21
|
+
if (key) {
|
|
22
|
+
memo.set(target.id, key);
|
|
23
|
+
return key;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
let vault = await fetchVault(linked);
|
|
27
|
+
const privateKey = await holderPrivateKey(linked, vault, opts);
|
|
28
|
+
try {
|
|
29
|
+
let ctx = vault.contexts.find((c) => c.id === target.id);
|
|
30
|
+
if (!ctx)
|
|
31
|
+
throw new Error(`This token cannot read ${target.slug}.`);
|
|
32
|
+
const member = linked.who.token.member === true;
|
|
33
|
+
if (!ctx.hasKey) {
|
|
34
|
+
if (member)
|
|
35
|
+
throw new Error(`${target.slug} has no values yet. The project owner sets the first one.`);
|
|
36
|
+
if (!opts.create || ctx.protection !== "open") {
|
|
37
|
+
throw new Error(`${target.slug} has no values yet.`);
|
|
38
|
+
}
|
|
39
|
+
vault = await initContextKey(linked, vault, ctx);
|
|
40
|
+
ctx = vault.contexts.find((c) => c.id === target.id);
|
|
41
|
+
}
|
|
42
|
+
const opened = openAll(vault, privateKey);
|
|
43
|
+
const key = opened.get(target.id);
|
|
44
|
+
if (!key) {
|
|
45
|
+
throw new Error(member
|
|
46
|
+
? `The owner has not sent you the key for ${target.slug} yet. Ask them to open Members in the dashboard.`
|
|
47
|
+
: `No key for ${target.slug} on this account. Open the project in the dashboard once.`);
|
|
48
|
+
}
|
|
49
|
+
for (const [id, k] of opened)
|
|
50
|
+
memo.set(id, k);
|
|
51
|
+
if (account)
|
|
52
|
+
await remember(account, vault, opened);
|
|
53
|
+
return key;
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
wipe(privateKey);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function serverContextKey(linked, target) {
|
|
60
|
+
const { privateKey } = splitServerToken(process.env.GETMYENV_TOKEN?.trim() ?? "");
|
|
61
|
+
if (!privateKey) {
|
|
62
|
+
throw new Error("This server token has no key. Create a new server token on the CLI page.");
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
let sealed = target.sealedKey;
|
|
66
|
+
if (sealed === undefined) {
|
|
67
|
+
sealed = (await fetchVault(linked)).contexts.find((c) => c.id === target.id)?.sealedKey ?? null;
|
|
68
|
+
}
|
|
69
|
+
if (!sealed) {
|
|
70
|
+
throw new Error(`This server token has no key for ${target.slug}. Create a new server token on the CLI page.`);
|
|
71
|
+
}
|
|
72
|
+
const key = openSealedKey(sealed, privateKey, target.id);
|
|
73
|
+
memo.set(target.id, key);
|
|
74
|
+
return key;
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
wipe(privateKey);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Open contexts on a signed-in account, with a password typed at a terminal. */
|
|
81
|
+
function keychainFor(linked) {
|
|
82
|
+
if (linked.who.isGuest || !keychainEnabled())
|
|
83
|
+
return null;
|
|
84
|
+
return keychainAccount(linked.apiUrl, linked.who.project.id);
|
|
85
|
+
}
|
|
86
|
+
async function remember(account, vault, opened) {
|
|
87
|
+
if (process.stdin.isTTY !== true)
|
|
88
|
+
return;
|
|
89
|
+
const entries = vault.contexts
|
|
90
|
+
.filter((c) => c.protection === "open" && c.sealedKey && opened.has(c.id))
|
|
91
|
+
.map((c) => ({ contextId: c.id, sealedRaw: JSON.stringify(c.sealedKey), key: opened.get(c.id) }));
|
|
92
|
+
if (entries.length === 0)
|
|
93
|
+
return;
|
|
94
|
+
if (await storeCachedContextKeys(account, entries)) {
|
|
95
|
+
console.error(pc.dim(`Unlocked on this machine for ${KEYCHAIN_TTL_MS / 3_600_000} hours (OS keychain). Forget it with: npx getmyenv lock\n`));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function openAll(vault, privateKey) {
|
|
99
|
+
const out = new Map();
|
|
100
|
+
for (const c of vault.contexts) {
|
|
101
|
+
if (c.sealedKey)
|
|
102
|
+
out.set(c.id, openSealedKey(c.sealedKey, privateKey, c.id));
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
/** First key of an open context. Another client may win the race: then use theirs. */
|
|
107
|
+
async function initContextKey(linked, vault, ctx) {
|
|
108
|
+
const key = generateContextKey();
|
|
109
|
+
try {
|
|
110
|
+
await linked.client.request("POST", "/api/cli/vault", {
|
|
111
|
+
shares: [{ contextId: ctx.id, sealedKey: sealContextKey(key, vault.publicKey, ctx.id) }],
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
if (!(err instanceof ApiError && err.status === 409))
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
wipe(key);
|
|
120
|
+
}
|
|
121
|
+
return fetchVault(linked);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The holder's private key. Creates the keys on first use when allowed:
|
|
125
|
+
* a new Vault password for an account, the claim.json passphrase for a guest.
|
|
126
|
+
*/
|
|
127
|
+
async function holderPrivateKey(linked, vault, opts) {
|
|
128
|
+
const isGuest = vault.holder === "guest";
|
|
129
|
+
if (!vault.publicKey || !vault.wrappedPrivateKey) {
|
|
130
|
+
if (!opts.create) {
|
|
131
|
+
throw new Error("No Vault password yet. Set a value first: npx getmyenv set KEY");
|
|
132
|
+
}
|
|
133
|
+
if (!isGuest) {
|
|
134
|
+
console.error(pc.dim("Choose a Vault password. It stays on this machine. We store an encrypted key blob only.\n"));
|
|
135
|
+
}
|
|
136
|
+
const password = await resolveVaultPassword({ isGuest, create: true });
|
|
137
|
+
const created = await createUserKeys(password);
|
|
138
|
+
try {
|
|
139
|
+
await linked.client.request("POST", "/api/cli/vault", {
|
|
140
|
+
keys: { publicKey: created.publicKey, wrappedPrivateKey: created.wrapped },
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
wipe(created.privateKey);
|
|
145
|
+
throw err;
|
|
146
|
+
}
|
|
147
|
+
vault.publicKey = created.publicKey;
|
|
148
|
+
vault.wrappedPrivateKey = created.wrapped;
|
|
149
|
+
return created.privateKey;
|
|
150
|
+
}
|
|
151
|
+
const interactive = process.stdin.isTTY && !isGuest;
|
|
152
|
+
const maxAttempts = interactive ? 3 : 1;
|
|
153
|
+
for (let attempt = 1;; attempt++) {
|
|
154
|
+
const password = await resolveVaultPassword({ isGuest });
|
|
155
|
+
try {
|
|
156
|
+
return await unwrapPrivateKey(password, vault.wrappedPrivateKey);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
if (isGuest) {
|
|
160
|
+
throw new Error("Could not unlock with the claim.json passphrase. Check .getmyenv/claim.json against the passphrase shown at creation.");
|
|
161
|
+
}
|
|
162
|
+
if (attempt < maxAttempts) {
|
|
163
|
+
console.error(pc.red("Wrong Vault password. Try again.\n"));
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
throw new Error("Could not unlock. Check your Vault password.");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/** Unlock with the Vault password and return the private key. Caller wipes it. */
|
|
171
|
+
export async function unlockPrivateKey(linked, opts = {}) {
|
|
172
|
+
const vault = await fetchVault(linked);
|
|
173
|
+
return { vault, privateKey: await holderPrivateKey(linked, vault, opts) };
|
|
174
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "getmyenv",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "CLI for getmyenv
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"description": "CLI for getmyenv, an encrypted store for environment variables and secrets. We store ciphertext only.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"getmyenv": "./dist/bin.js"
|
|
@@ -33,12 +33,11 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@getmyenv/crypto": "0.
|
|
37
|
-
"@getmyenv/shared": "0.
|
|
36
|
+
"@getmyenv/crypto": "0.4.0",
|
|
37
|
+
"@getmyenv/shared": "0.5.0",
|
|
38
38
|
"@napi-rs/keyring": "^2.1.0",
|
|
39
39
|
"commander": "^13.1.0",
|
|
40
40
|
"dotenv": "^16.4.7",
|
|
41
|
-
"ora": "^8.2.0",
|
|
42
41
|
"picocolors": "^1.1.1"
|
|
43
42
|
},
|
|
44
43
|
"devDependencies": {
|
package/dist/bin.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
|
package/dist/bin.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,KAAK,UAAU,IAAI;IACjB,MAAM,kBAAkB,EAAE,CAAC;IAC3B,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC;IACxE,uDAAuD;IACvD,OAAO,CAAC,KAAK,CAAC,aAAa,OAAO,EAAE,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC,CAAC,CAAC"}
|
package/dist/cli.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AA+BA;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,OAAO,GACf;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CASzC;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA8L1D"}
|
package/dist/cli.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../../src/commands/backup.ts"],"names":[],"mappings":"AAaA,KAAK,UAAU,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD,mFAAmF;AACnF,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCnE"}
|