@envsave/cli 1.0.37

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jose C Sancho
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,223 @@
1
+ # EnvSave
2
+
3
+ A local encrypted vault for secrets (API keys, tokens, passwords) designed to be safe for use with LLM agents. Secrets are accessed via opaque keys (`es_...`) — agents can read values but can't discover or enumerate other secrets.
4
+
5
+ ## The problem EnvSave solves
6
+
7
+ API keys, access tokens, database URLs, webhook secrets — **these must never be visible to AI assistants or coding agents you run on your codebase.** If an LLM can read a real secret, so can anyone watching the LLM:
8
+
9
+ - **Exfiltration.** An agent with tool access (shell, file read, HTTP) can quietly send keys to an external endpoint, log them into a transcript cached by a third party, or commit them to a public repo. You won't notice until the bill arrives.
10
+ - **Abuse by strangers.** A leaked OpenAI / Anthropic / Stripe / AWS key is an open tab on your credit card. Attackers scrape keys out of GitHub, npm tarballs, Discord pastes, and LLM transcripts within minutes of exposure.
11
+ - **Prompt injection.** A malicious webpage, PR description, or document pulled into the agent's context can instruct it to read `.env`, list environment variables, or print secrets as "debug output." If the secret is in your code or your environment, a compromised agent will surface it.
12
+ - **Context-window leakage.** Once a key is in the LLM's context it can be logged, embedded, cached, and potentially used to train future models — you've lost control of it.
13
+ - **Painful rotation.** Rotating a leaked production key means downtime, redeploys, and hunting down every place it was pasted.
14
+
15
+ **EnvSave is how you stop giving LLMs your real secrets.** Instead of exposing `sk-proj-...` or reading `.env` in your code, you hand the LLM an *opaque key* — a deterministic HMAC hash like `es_7a3f2b1e9c8d4f6b2a1c3d5f` — that only resolves to the real value through the encrypted vault on your machine. The agent can read your code, your `.env`, even the session cache, and still learn nothing: opaque keys can't be reversed, enumerated, or brute-forced without the master password.
16
+
17
+ ```ts
18
+ // ❌ Bad — the LLM sees the real key in your code
19
+ const openai = new OpenAI({ apiKey: "sk-proj-abc123..." });
20
+
21
+ // ❌ Also bad — .env still contains the plaintext key, and agents read .env
22
+ const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
23
+
24
+ // ✅ EnvSave — the agent only ever sees "es_7a3f...", useless outside your vault
25
+ import { get } from "@envsave/cli";
26
+ const openai = new OpenAI({ apiKey: get("es_7a3f2b1e9c8d4f6b2a1c3d5f") });
27
+ ```
28
+
29
+ This is the single problem this project is built around. Everything else — the CLI, the license server, the Python bridge, the cloud backup — exists to make opaque-key-based secrets practical to use day to day.
30
+
31
+ ## Free tier
32
+
33
+ Up to **5 secrets** with no license. Beyond that you'll need to activate a license (`envsave activate <token>`) — get yours at https://envsave.com.
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ # Global CLI (binary will be available as `envsave`)
39
+ npm install -g @envsave/cli
40
+
41
+ # Or use it as a library
42
+ npm install @envsave/cli
43
+ ```
44
+
45
+ Python users:
46
+
47
+ ```bash
48
+ pip install envsave
49
+ ```
50
+
51
+ ## Activation
52
+
53
+ ### Online (production)
54
+
55
+ Requires the license server running at `https://api.envsave.com`.
56
+
57
+ ```bash
58
+ # 1. Register on the webapp to get a token
59
+ # 2. Activate
60
+ envsave activate <token>
61
+ ```
62
+
63
+ The CLI calls `/api/license/validate` to verify the token's HMAC signature, expiry, and DB status.
64
+
65
+ ### Offline (dev/testing)
66
+
67
+ Skips server validation. Only allowed for a small set of whitelisted emails maintained in `src/license.ts`.
68
+
69
+ ```bash
70
+ envsave activate <token> --offline
71
+ ```
72
+
73
+ This parses the signed token locally, checks the embedded email is in the allowed list, verifies expiry, and writes `~/.envsave/license.json`.
74
+
75
+ ## Setup
76
+
77
+ ```bash
78
+ # Initialize vault (creates ~/.envsave/vault.enc)
79
+ envsave init
80
+
81
+ # Optional: initialize with an existing .env file
82
+ envsave init --env .env
83
+
84
+ # Optional: add SSH key as second factor
85
+ envsave init --ssh-key ~/.ssh/id_ed25519
86
+ ```
87
+
88
+ You'll be prompted to set and confirm a master password.
89
+
90
+ ## Storing Secrets
91
+
92
+ ```bash
93
+ envsave set OPENAI_API_KEY sk-abc123
94
+ # Output:
95
+ # OPENAI_API_KEY → es_7a3f2b1e9c8d4f6b
96
+ # Use this in your code to access OPENAI_API_KEY:
97
+ # envsave.get("es_7a3f2b1e9c8d4f6b")
98
+ ```
99
+
100
+ The opaque key (`es_...`) is an HMAC-SHA256 hash — no trace of the original key name.
101
+
102
+ ## Retrieving Secrets
103
+
104
+ ### CLI
105
+
106
+ ```bash
107
+ # By opaque key (tries session cache first, then prompts for password)
108
+ envsave get es_7a3f2b1e9c8d4f6b
109
+ ```
110
+
111
+ ### Node.js / Bun
112
+
113
+ ```ts
114
+ import { get, has } from "@envsave/cli";
115
+
116
+ const apiKey = get("es_7a3f2b1e9c8d4f6b");
117
+
118
+ if (has("es_7a3f2b1e9c8d4f6b")) {
119
+ // secret exists
120
+ }
121
+ ```
122
+
123
+ ### Python
124
+
125
+ ```python
126
+ from envsave import get
127
+
128
+ api_key = get("es_7a3f2b1e9c8d4f6b")
129
+ ```
130
+
131
+ ## Other Commands
132
+
133
+ ```bash
134
+ # Show opaque key for a named secret (requires password)
135
+ envsave reveal OPENAI_API_KEY
136
+
137
+ # Reveal multiple keys at once
138
+ envsave reveal OPENAI_API_KEY DATABASE_URL STRIPE_KEY
139
+
140
+ # List all stored key names (requires password)
141
+ envsave list
142
+
143
+ # Delete a secret (requires password)
144
+ envsave delete OPENAI_API_KEY
145
+
146
+ # Bulk import from .env file (requires password)
147
+ envsave import .env
148
+
149
+ # Export all secrets as .env format (requires password)
150
+ envsave export
151
+ ```
152
+
153
+ ## Cloud Backup & Sync
154
+
155
+ The encrypted vault can be backed up to the EnvSave cloud server for disaster recovery or syncing across machines. The server only stores the encrypted bytes — it never sees plaintext secrets.
156
+
157
+ ```bash
158
+ # Upload encrypted vault to cloud
159
+ envsave backup
160
+
161
+ # Download vault backup from cloud (prompts before overwriting)
162
+ envsave restore
163
+
164
+ # Smart sync — auto-detects which direction to sync
165
+ envsave sync
166
+ ```
167
+
168
+ ### Sync behavior
169
+
170
+ | Scenario | Action |
171
+ |---|---|
172
+ | Both match (same checksum) | "Already in sync" |
173
+ | Local only, no cloud backup | Auto-pushes to cloud |
174
+ | Cloud only, no local vault | Auto-pulls from cloud |
175
+ | Both exist but differ | Asks: pull (p), push (l), or cancel (c) |
176
+ | Neither exists | Tells user to run `envsave init` |
177
+
178
+ ### Setting up on a new machine or remote server
179
+
180
+ ```bash
181
+ # 1. Install envsave
182
+ bun install @envsave/cli
183
+
184
+ # 2. Activate with same license token
185
+ envsave activate <token>
186
+
187
+ # 3. Pull vault from cloud
188
+ envsave sync
189
+ # or: envsave restore
190
+
191
+ # 4. Verify
192
+ envsave list
193
+ ```
194
+
195
+ ## Security Model
196
+
197
+ 1. Vault is encrypted with AES-256-GCM + PBKDF2 key derivation
198
+ 2. Stored at `~/.envsave/vault.enc` (binary: salt + iv + encrypted data + auth tag)
199
+ 3. Key names are HMAC-SHA256 hashes — fully opaque, no trace of original name
200
+ 4. Session cache stores decrypted secrets in memory — no password needed for repeated reads
201
+ 5. Optional SSH key adds a "something you have" hardware factor
202
+ 6. LLM agents only see opaque keys — they can read values but can't discover or enumerate secrets
203
+
204
+ ## License Tokens
205
+
206
+ Tokens are self-contained signed strings: `es_<base64url(email|created_ts|expires_ts|hmac)>`
207
+
208
+ - Dates are embedded inside the token (opaque to users)
209
+ - HMAC signature prevents tampering (verified server-side)
210
+ - Server also checks DB for revocation support
211
+ - Offline mode reads expiry from the token directly without server call
212
+
213
+ ### Auto-Renewal
214
+
215
+ When a license token expires, the CLI automatically contacts the server to renew it — no user action needed. The renewal succeeds if the user's subscription is still active (user exists in DB and hasn't been revoked). The new token is saved locally and the command proceeds normally.
216
+
217
+ ## File Locations
218
+
219
+ | File | Purpose |
220
+ |------|---------|
221
+ | `~/.envsave/vault.enc` | Encrypted vault |
222
+ | `~/.envsave/license.json` | Activated license |
223
+ | `~/.envsave/session.json` | Session cache (decrypted secrets) |