dotcrypt 0.0.0-stage → 1.0.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/CHANGELOG.md +22 -0
- package/LICENSE +21 -0
- package/README.md +346 -2
- package/bin/cli.js +489 -0
- package/package.json +59 -4
- package/src/config.js +167 -0
- package/src/crypto.js +259 -0
- package/src/server.js +321 -0
- package/src/utils.js +253 -0
- package/src/vault.js +391 -0
- package/ui/README.md +4 -0
- package/ui/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/ui/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/ui/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/ui/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/ui/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/ui/dist/assets/index-CmGxJebe.js +9 -0
- package/ui/dist/assets/index-DBqwUbdm.css +2 -0
- package/ui/dist/index.html +14 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project follows
|
|
5
|
+
[Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [1.0.0] - 2026-11-10
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `init`, `encrypt`, `decrypt`, `rotate-key` and `diff` commands for AES-256-GCM (scrypt) encrypted
|
|
14
|
+
`.env` files that are safe to commit to Git.
|
|
15
|
+
- `ui` command: a local, token-protected web dashboard bound to `127.0.0.1`.
|
|
16
|
+
- Overwrite protection with key-level diffs (values are never printed).
|
|
17
|
+
- `encrypt --replace` to deliberately discard a vault file that is unreadable, belongs to another
|
|
18
|
+
environment, or uses a different password.
|
|
19
|
+
- Passwords via interactive prompt, `DOTCRYPT_PASSWORD` / `DOTCRYPT_NEW_PASSWORD`, or flags.
|
|
20
|
+
|
|
21
|
+
[Unreleased]: https://github.com/zubayerhimel/dotcrypt/compare/v1.0.0...HEAD
|
|
22
|
+
[1.0.0]: https://github.com/zubayerhimel/dotcrypt/releases/tag/v1.0.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 zubayerhimel
|
|
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
CHANGED
|
@@ -1,3 +1,347 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dotcrypt
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Securely sync multiple `.env` environments across machines **through your existing Git repository**.
|
|
4
|
+
Plaintext env files stay local and git-ignored; only AES-256-GCM encrypted `.enc` files and a shared
|
|
5
|
+
`.dotcrypt.json` configuration are committed.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
.dotcrypt.json <- committed: environments + file mappings (no secrets)
|
|
9
|
+
.env.development <- local only (git-ignored)
|
|
10
|
+
.env.development.enc <- committed: encrypted with AES-256-GCM
|
|
11
|
+
.env.production <- local only (git-ignored)
|
|
12
|
+
.env.production.enc <- committed
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g dotcrypt
|
|
19
|
+
dotcrypt --help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### From source
|
|
23
|
+
|
|
24
|
+
Requires Node.js **20.19+** (needed to build the dashboard; the CLI alone runs on 18.17+).
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
git clone https://github.com/zubayerhimel/dotcrypt.git
|
|
28
|
+
cd dotcrypt
|
|
29
|
+
npm run setup # installs CLI + dashboard dependencies and builds the dashboard
|
|
30
|
+
npm link # exposes the `dotcrypt` command globally
|
|
31
|
+
dotcrypt --help
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`npm run setup` is the same as running these one by one:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install # CLI dependencies
|
|
38
|
+
npm --prefix ui install # dashboard dependencies
|
|
39
|
+
npm run build:ui # builds the dashboard into ui/dist
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Re-run `npm run build:ui` after pulling changes to the dashboard code.
|
|
43
|
+
|
|
44
|
+
> **Windows PowerShell:** if you get "running scripts is disabled on this system", use `npm.cmd`
|
|
45
|
+
> instead of `npm` (e.g. `npm.cmd run setup`, `npm.cmd link`), or run the commands from Command Prompt.
|
|
46
|
+
|
|
47
|
+
To uninstall the global link: `npm unlink -g dotcrypt`.
|
|
48
|
+
|
|
49
|
+
## Quick start
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cd path/to/your-project
|
|
53
|
+
dotcrypt init # creates .dotcrypt.json and updates .gitignore
|
|
54
|
+
dotcrypt ui # opens the dashboard in your browser
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Prefer the terminal? Everything in the dashboard is also available as a CLI command (see below).
|
|
58
|
+
|
|
59
|
+
## Commands
|
|
60
|
+
|
|
61
|
+
| Command | Description |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| `init [-n name] [--envs a,b,c] [-d env] [-y] [-f]` | Create `.dotcrypt.json` and add ignore rules for plaintext env files to `.gitignore`. |
|
|
64
|
+
| `encrypt [-e env] [-p password] [-f] [--replace]` | Encrypt the mapped local file (e.g. `.env.staging`) into its `.enc` file. |
|
|
65
|
+
| `decrypt [-e env] [-p password] [-f]` | Decrypt the `.enc` file into the mapped local file. |
|
|
66
|
+
| `rotate-key [-e env] [-o old] [-n new]` | Re-encrypt with a new password, a fresh salt and a fresh IV. |
|
|
67
|
+
| `diff [-e env] [-p password] [--exit-code]` | Show **key names** that were added / removed / changed. Values are never printed. |
|
|
68
|
+
| `ui [--port n] [--no-open]` | Open the local web dashboard (see below). |
|
|
69
|
+
|
|
70
|
+
If `-e` is omitted you are prompted to pick an environment (non-interactive runs fall back to
|
|
71
|
+
`defaultEnvironment`).
|
|
72
|
+
|
|
73
|
+
### Supplying passwords
|
|
74
|
+
|
|
75
|
+
Passwords are resolved in this order:
|
|
76
|
+
|
|
77
|
+
1. CLI flag (`-p`, `-o`, `-n`) — works, but prints a warning because flags leak into shell
|
|
78
|
+
history and process listings.
|
|
79
|
+
2. Environment variable — `DOTCRYPT_PASSWORD` (and `DOTCRYPT_NEW_PASSWORD` for the new
|
|
80
|
+
password in `rotate-key`). Recommended for CI.
|
|
81
|
+
3. Interactive masked prompt (recommended for humans). New passwords must be at least 12
|
|
82
|
+
characters and are asked twice.
|
|
83
|
+
|
|
84
|
+
### Overwrite protection
|
|
85
|
+
|
|
86
|
+
- `decrypt` never silently replaces a local file that differs from the vault: it shows which keys
|
|
87
|
+
would be lost/changed and asks for confirmation. Use `--force` to skip the prompt.
|
|
88
|
+
- `encrypt` shows a key-level summary of what will change in the vault and asks before
|
|
89
|
+
overwriting. If the files are identical, nothing is written (no Git churn).
|
|
90
|
+
- `encrypt` **verifies your password against the existing `.enc` file**. This prevents a
|
|
91
|
+
teammate from accidentally re-encrypting a shared vault with a different password. Change
|
|
92
|
+
passwords with `rotate-key`. To deliberately discard a vault file that is unreadable, belongs to
|
|
93
|
+
another environment, or uses a different password, pass `--replace` (`--force` alone never does
|
|
94
|
+
this). When the password was typed at a prompt, you must re-enter it before the vault is replaced.
|
|
95
|
+
- `init` refuses to overwrite an existing `.dotcrypt.json` without confirmation or `--force`.
|
|
96
|
+
- Non-interactive sessions (CI, pipes) never prompt; they fail safely unless `--force` is given.
|
|
97
|
+
|
|
98
|
+
### Exit codes
|
|
99
|
+
|
|
100
|
+
| Code | Meaning |
|
|
101
|
+
| --- | --- |
|
|
102
|
+
| `0` | Success |
|
|
103
|
+
| `1` | General error, aborted, or (`diff --exit-code`) differences found |
|
|
104
|
+
| `2` | Wrong password or corrupted / tampered encrypted file |
|
|
105
|
+
| `130` | Cancelled at a prompt (Ctrl+C) |
|
|
106
|
+
|
|
107
|
+
## `.dotcrypt.json`
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"version": 1,
|
|
112
|
+
"vault": {
|
|
113
|
+
"name": "my-app",
|
|
114
|
+
"createdAt": "2026-11-07T06:00:00.000Z",
|
|
115
|
+
"cipher": "aes-256-gcm",
|
|
116
|
+
"kdf": "scrypt"
|
|
117
|
+
},
|
|
118
|
+
"defaultEnvironment": "development",
|
|
119
|
+
"environments": {
|
|
120
|
+
"development": { "file": ".env.development", "encryptedFile": ".env.development.enc" },
|
|
121
|
+
"staging": { "file": ".env.staging", "encryptedFile": ".env.staging.enc" },
|
|
122
|
+
"production": { "file": ".env.production", "encryptedFile": ".env.production.enc" }
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
You may edit mappings by hand (e.g. `"file": "apps/api/.env"`). Validation rules:
|
|
128
|
+
|
|
129
|
+
- Environment names: 1–64 chars of letters, digits, `-`, `_`.
|
|
130
|
+
- Paths must be relative and stay inside the project (no absolute paths, no `..` escapes).
|
|
131
|
+
- `encryptedFile` must end in `.enc`; `file` must not.
|
|
132
|
+
- No two mappings may share a path (compared case-insensitively).
|
|
133
|
+
|
|
134
|
+
Custom plaintext paths that the default `.env` / `.env.*` rules don't cover are added to
|
|
135
|
+
`.gitignore` explicitly the next time you run `init`.
|
|
136
|
+
|
|
137
|
+
## Team workflow
|
|
138
|
+
|
|
139
|
+
**Project owner (once):**
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
dotcrypt init # creates .dotcrypt.json, updates .gitignore
|
|
143
|
+
# create .env.development, .env.staging, ...
|
|
144
|
+
dotcrypt encrypt -e development # choose a strong password
|
|
145
|
+
dotcrypt encrypt -e production # use a *different* password per environment
|
|
146
|
+
git add .dotcrypt.json .gitignore *.enc
|
|
147
|
+
git commit -m "Add encrypted environments"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Share each environment's password **out of band** (password manager, not chat or the repo).
|
|
151
|
+
|
|
152
|
+
**Teammate on a new machine:**
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
git pull
|
|
156
|
+
dotcrypt decrypt -e development
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Changing a secret:**
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
git pull # always start from the latest vault
|
|
163
|
+
dotcrypt diff -e development # see what differs before acting
|
|
164
|
+
# edit .env.development
|
|
165
|
+
dotcrypt encrypt -e development
|
|
166
|
+
git add .env.development.enc && git commit -m "Update dev env" && git push
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Someone leaves the team / password leaked:**
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
dotcrypt rotate-key -e production
|
|
173
|
+
git commit -am "Rotate production vault password" && git push
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
> ⚠️ Rotating the password does **not** revoke secrets. Anyone who had the old password can still
|
|
177
|
+
> decrypt old versions of the `.enc` file from Git history. After a departure or leak, rotate the
|
|
178
|
+
> **underlying secrets** (API keys, DB passwords) too, then re-encrypt.
|
|
179
|
+
|
|
180
|
+
**Merge conflicts in `.enc` files:** encrypted files can't be merged textually. Resolve by taking
|
|
181
|
+
one side (`git checkout --theirs .env.x.enc`), running `decrypt`, re-applying your changes to the
|
|
182
|
+
plaintext file, and running `encrypt` again.
|
|
183
|
+
|
|
184
|
+
**CI usage:**
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
DOTCRYPT_PASSWORD="$VAULT_PASSWORD_PRODUCTION" dotcrypt decrypt -e production --force
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Security architecture
|
|
191
|
+
|
|
192
|
+
### Encrypted file format
|
|
193
|
+
|
|
194
|
+
Each `.enc` file is a JSON envelope:
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"version": 1,
|
|
199
|
+
"algorithm": "aes-256-gcm",
|
|
200
|
+
"kdf": { "name": "scrypt", "N": 32768, "r": 8, "p": 1, "salt": "<base64, 32 bytes>" },
|
|
201
|
+
"iv": "<base64, 16 bytes>",
|
|
202
|
+
"metadata": {
|
|
203
|
+
"environment": "production",
|
|
204
|
+
"sourceFile": ".env.production",
|
|
205
|
+
"encryptedAt": "2026-11-07T06:00:00.000Z"
|
|
206
|
+
},
|
|
207
|
+
"authTag": "<base64, 16 bytes>",
|
|
208
|
+
"ciphertext": "<base64>"
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Cryptographic design
|
|
213
|
+
|
|
214
|
+
- **Cipher:** AES-256-GCM (authenticated encryption) via `node:crypto`, 128-bit auth tag
|
|
215
|
+
enforced with `authTagLength` on both encrypt and decrypt.
|
|
216
|
+
- **Key derivation:** `crypto.scryptSync` → 256-bit key. Default cost `N=2^15, r=8, p=1`
|
|
217
|
+
(~32 MiB, OWASP baseline). Passwords are Unicode NFC-normalized so the same password works on
|
|
218
|
+
every OS/keyboard.
|
|
219
|
+
- **Fresh randomness every run:** a new 32-byte salt and new 16-byte IV come from the CSPRNG
|
|
220
|
+
(`crypto.randomBytes`) on every `encrypt` and `rotate-key`. IVs are never fixed, reused, or
|
|
221
|
+
derived; because the key is also fresh per salt, (key, IV) reuse is cryptographically
|
|
222
|
+
negligible.
|
|
223
|
+
- **Authenticated header (AAD):** the format version, algorithm, all KDF parameters, salt, IV,
|
|
224
|
+
and metadata (environment, source file, timestamp) are bound to the ciphertext as GCM
|
|
225
|
+
Additional Authenticated Data. Any modification — including swapping `staging.enc` into
|
|
226
|
+
`production.enc` or editing the environment label — fails authentication.
|
|
227
|
+
- **Environment binding:** on decrypt, the authenticated `metadata.environment` must match the
|
|
228
|
+
requested environment.
|
|
229
|
+
- **Downgrade / DoS resistance:** KDF parameters read from files are bounds-checked (N must be a
|
|
230
|
+
power of two in `[2^14, 2^20]`, `r ∈ [8, 32]`, `p ∈ [1, 16]`, memory ≤ 256 MiB). Base64 fields,
|
|
231
|
+
salt/IV/tag lengths, and file sizes (5 MiB) are strictly validated before any crypto runs.
|
|
232
|
+
- **Uniform failure:** a wrong password and a tampered file produce the same error (GCM cannot and
|
|
233
|
+
should not distinguish them); no partial plaintext is ever written.
|
|
234
|
+
- **Key hygiene:** derived keys, password byte buffers and plaintext buffers are zeroed after use
|
|
235
|
+
(best-effort in a garbage-collected runtime).
|
|
236
|
+
|
|
237
|
+
### Filesystem safety
|
|
238
|
+
|
|
239
|
+
- **Atomic writes:** output is written to an exclusive (`wx`) temp file, `fsync`ed, then renamed
|
|
240
|
+
over the target, so crashes never leave truncated `.env` or `.enc` files.
|
|
241
|
+
- **Restrictive permissions:** decrypted plaintext files are created with mode `0600`.
|
|
242
|
+
- **Path confinement:** all paths from `.dotcrypt.json` must resolve inside the project root.
|
|
243
|
+
- **Symlink protection:** the tool refuses to read or write through symlinks, or through
|
|
244
|
+
symlinked directories that resolve outside the project. A malicious repository therefore can't
|
|
245
|
+
make `decrypt` overwrite e.g. `~/.bashrc`, or make `encrypt` pull `~/.ssh/id_rsa` into a
|
|
246
|
+
committed file.
|
|
247
|
+
- **Git hygiene:** `init` appends `.env`, `.env.*` and `!.env.*.enc` (plus explicit entries for
|
|
248
|
+
custom paths) to `.gitignore` without touching existing rules. `encrypt`/`decrypt` warn loudly if
|
|
249
|
+
a plaintext file is tracked by Git or not ignored.
|
|
250
|
+
- **No secret output:** `diff` and the overwrite summaries print key names only; key names are
|
|
251
|
+
sanitized of control characters to prevent terminal escape injection.
|
|
252
|
+
|
|
253
|
+
### Threat model & limitations
|
|
254
|
+
|
|
255
|
+
- Protects secrets **at rest in Git** (hosting provider, forks, leaked clones) against anyone
|
|
256
|
+
without the password.
|
|
257
|
+
- Does **not** protect against a compromised developer machine, or against someone who holds the
|
|
258
|
+
password. Old ciphertexts in Git history remain decryptable with old passwords.
|
|
259
|
+
- Security depends on password strength. Use long random passphrases from a password manager and a
|
|
260
|
+
separate password per environment.
|
|
261
|
+
- Not a replacement for a full secrets manager (per-user access control, audit logs, automatic
|
|
262
|
+
rotation). It is designed for small, trusted teams.
|
|
263
|
+
|
|
264
|
+
## Web dashboard
|
|
265
|
+
|
|
266
|
+
### Opening the dashboard
|
|
267
|
+
|
|
268
|
+
1. Make sure you ran `npm run setup` (or `npm run build:ui`) once in this repository.
|
|
269
|
+
2. In a terminal, go to the project whose env files you want to manage (the folder with
|
|
270
|
+
`.dotcrypt.json`, or any folder if you want to create one from the dashboard).
|
|
271
|
+
3. Run:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
dotcrypt ui # random free port, opens your browser
|
|
275
|
+
dotcrypt ui --port 4600 # fixed port
|
|
276
|
+
dotcrypt ui --no-open # just print the URL
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
4. The terminal prints a URL like `http://127.0.0.1:53412/?token=3f9c…`. Your browser opens it
|
|
280
|
+
automatically; if it does not, copy the **full** URL (including `?token=`) into your browser.
|
|
281
|
+
5. Leave the terminal open while you use the dashboard. Press **Ctrl+C** to stop it.
|
|
282
|
+
|
|
283
|
+
Each run creates a new token, so old URLs stop working after a restart. If the page says
|
|
284
|
+
"Session token missing or expired", open the URL from the current run again. If it says the
|
|
285
|
+
dashboard assets are not built, run `npm run build:ui` in this repository.
|
|
286
|
+
|
|
287
|
+
### What it does
|
|
288
|
+
|
|
289
|
+
A local dashboard built with React, [shadcn/ui](https://ui.shadcn.com) (Base UI primitives) and
|
|
290
|
+
Tailwind. It shows:
|
|
291
|
+
|
|
292
|
+
- every environment in `.dotcrypt.json`: local file and vault file status, sizes, last-modified /
|
|
293
|
+
last-encrypted times, and the default environment
|
|
294
|
+
- a health badge per environment (Synced, Local changed, Not encrypted, Not decrypted, Vault
|
|
295
|
+
unreadable, Plaintext tracked)
|
|
296
|
+
- Git safety: whether plaintext files are ignored or (dangerously) tracked, whether `.enc` files are
|
|
297
|
+
committed, and a one-click fix for missing `.gitignore` rules
|
|
298
|
+
- an activity log for the session
|
|
299
|
+
|
|
300
|
+
You can initialize a vault, add environments, set the default, and run encrypt, decrypt, diff and
|
|
301
|
+
rotate-key from the dashboard. Overwrites show the key-name diff and need confirmation, just like
|
|
302
|
+
the CLI. The dashboard refreshes every 5 seconds, so changes made in the terminal or by `git pull`
|
|
303
|
+
show up automatically.
|
|
304
|
+
|
|
305
|
+
### Dashboard security model
|
|
306
|
+
|
|
307
|
+
- **Loopback only.** The server binds to `127.0.0.1` and never to `0.0.0.0`.
|
|
308
|
+
- **Per-run secret token.** A random 256-bit token is generated on every start and required as a
|
|
309
|
+
bearer token on every API call, compared in constant time. The browser moves it from the URL into
|
|
310
|
+
`sessionStorage` and removes it from the address bar. Do not share the printed URL.
|
|
311
|
+
- **DNS-rebinding and CSRF protection.** Requests whose `Host` is not `127.0.0.1:<port>` or
|
|
312
|
+
`localhost:<port>` are rejected (421). Writes require `Content-Type: application/json`, a matching
|
|
313
|
+
`Origin`, and a same-origin `Sec-Fetch-Site`.
|
|
314
|
+
- **Strict headers.** A restrictive CSP (`script-src 'self'`, `frame-ancestors 'none'`, …),
|
|
315
|
+
`X-Frame-Options: DENY`, `nosniff`, `no-referrer`, and `Cache-Control: no-store` on API responses.
|
|
316
|
+
- **No secret values leave the server.** The API returns metadata and key names only. Passwords are
|
|
317
|
+
sent per request, held only in the tab's memory (the **Lock** button clears them), and never
|
|
318
|
+
stored in `localStorage` or on disk. Request bodies are capped at 64 KB.
|
|
319
|
+
|
|
320
|
+
### Developing the dashboard
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
# terminal 1, inside any project with a vault
|
|
324
|
+
dotcrypt ui --port 4600 --no-open # note the token it prints
|
|
325
|
+
# terminal 2, in this repository
|
|
326
|
+
VAULT_API_PORT=4600 npm run dev:ui # Vite on http://localhost:5173, /api is proxied
|
|
327
|
+
# open http://localhost:5173/?token=<token>
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
UI code lives in `ui/src` (`App.tsx`, `components/`, `lib/api.ts`). Add more shadcn components with
|
|
331
|
+
`npx shadcn@latest add <component>` from the `ui/` directory.
|
|
332
|
+
|
|
333
|
+
## Development
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
npm install
|
|
337
|
+
npm test
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Source layout: `src/crypto.js` (envelope format and AES-256-GCM/scrypt), `src/config.js`
|
|
341
|
+
(`.dotcrypt.json`), `src/utils.js` (filesystem and Git safety), `src/vault.js` (operations shared
|
|
342
|
+
by the CLI and dashboard), `src/server.js` (dashboard server), `bin/cli.js` (Commander CLI) and
|
|
343
|
+
`ui/` (dashboard).
|
|
344
|
+
|
|
345
|
+
## License
|
|
346
|
+
|
|
347
|
+
MIT
|