whisper-secrets 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/README.md +110 -0
- package/bin/whisper-secrets +49 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# whisper-secrets
|
|
2
|
+
|
|
3
|
+
Zero-knowledge `.env` secret manager for teams. Encrypt, store, and share secrets — secrets are encrypted before leaving your machine. No signup, no accounts.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g whisper-secrets
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Client-side encryption**: AES-256-GCM encryption with PBKDF2 key derivation — your server never sees plaintext
|
|
14
|
+
- **Team sharing**: Initialize a project, share the passphrase link, and teammates can pull secrets instantly
|
|
15
|
+
- **Ephemeral secrets**: One-time share links with auto-expiration and optional self-destruct
|
|
16
|
+
- **`.env` workflow**: Push, pull, import, rotate, and remove secrets — works with your existing `.env` files
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Initialize a project (generates passphrase + .whisperrc config)
|
|
22
|
+
whisper-secrets init
|
|
23
|
+
|
|
24
|
+
# Share the generated link with your team
|
|
25
|
+
# Teammates clone the repo, then:
|
|
26
|
+
whisper-secrets pull
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Managed Secrets (`.env` workflow)
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Initialize a project
|
|
33
|
+
whisper-secrets init
|
|
34
|
+
whisper-secrets init --url https://your-server.com
|
|
35
|
+
|
|
36
|
+
# Import an existing .env file (encrypts & uploads every entry)
|
|
37
|
+
whisper-secrets import
|
|
38
|
+
|
|
39
|
+
# Push a single secret
|
|
40
|
+
whisper-secrets push DATABASE_URL
|
|
41
|
+
|
|
42
|
+
# Pull all secrets into .env
|
|
43
|
+
whisper-secrets pull
|
|
44
|
+
|
|
45
|
+
# Rotate a secret's value
|
|
46
|
+
whisper-secrets rotate DATABASE_URL
|
|
47
|
+
|
|
48
|
+
# Delete a secret
|
|
49
|
+
whisper-secrets remove DATABASE_URL
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Ephemeral Secrets (one-time sharing)
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Share a secret (default: 1h expiration, self-destruct on)
|
|
56
|
+
whisper-secrets share --expiration 1h
|
|
57
|
+
|
|
58
|
+
# Share without self-destruct
|
|
59
|
+
whisper-secrets share --expiration 24h --no-self-destruct
|
|
60
|
+
|
|
61
|
+
# Retrieve a secret by URL or ID
|
|
62
|
+
whisper-secrets get https://whisper.example.com/get_secret?shared_secret_id=UUID
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## How It Works
|
|
66
|
+
|
|
67
|
+
1. `whisper-secrets init` generates a random passphrase and creates `.whisperrc`
|
|
68
|
+
2. The passphrase derives an encryption key (PBKDF2-SHA256, 600k iterations) and an auth token
|
|
69
|
+
3. `push` / `import` encrypt secrets client-side, then upload the ciphertext to the server
|
|
70
|
+
4. `pull` downloads ciphertext and decrypts locally
|
|
71
|
+
5. The server only stores encrypted blobs — zero knowledge of your secrets
|
|
72
|
+
|
|
73
|
+
**Files created:**
|
|
74
|
+
- `.whisperrc` — project config (URL + passphrase). Add to `.gitignore`
|
|
75
|
+
- `.env.whisper` — mapping of secret names to server IDs. Commit this to git
|
|
76
|
+
- `.env` — plaintext secrets, generated by `pull`. Add to `.gitignore`
|
|
77
|
+
|
|
78
|
+
## Security
|
|
79
|
+
|
|
80
|
+
- **AES-256-GCM** authenticated encryption with unique nonce per secret
|
|
81
|
+
- **PBKDF2-SHA256** key derivation (600,000 iterations)
|
|
82
|
+
- **Bearer token** authentication derived from the same passphrase
|
|
83
|
+
- **No plaintext** ever leaves your machine or is stored on the server
|
|
84
|
+
|
|
85
|
+
## Supported Platforms
|
|
86
|
+
|
|
87
|
+
| Platform | Architecture |
|
|
88
|
+
|----------|-------------|
|
|
89
|
+
| Linux | x64, arm64 |
|
|
90
|
+
| macOS | arm64 (Apple Silicon) |
|
|
91
|
+
| Windows | x64 |
|
|
92
|
+
|
|
93
|
+
## Self-hosting
|
|
94
|
+
|
|
95
|
+
Whisper is open source. You can host your own server:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# See full setup instructions
|
|
99
|
+
git clone https://github.com/quentinved/Whisper
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Then point the CLI to your server:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
whisper-secrets init --url https://your-whisper-instance.com
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT — [github.com/quentinved/Whisper](https://github.com/quentinved/Whisper)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execFileSync } = require("child_process");
|
|
4
|
+
const os = require("os");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
|
|
7
|
+
const PLATFORMS = {
|
|
8
|
+
"darwin-arm64": "@whisper-secrets/darwin-arm64",
|
|
9
|
+
"linux-arm64": "@whisper-secrets/linux-arm64",
|
|
10
|
+
"linux-x64": "@whisper-secrets/linux-x64",
|
|
11
|
+
"win32-x64": "@whisper-secrets/win32-x64",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const platform = os.platform();
|
|
15
|
+
const arch = os.arch();
|
|
16
|
+
const key = `${platform}-${arch}`;
|
|
17
|
+
const pkg = PLATFORMS[key];
|
|
18
|
+
|
|
19
|
+
if (!pkg) {
|
|
20
|
+
console.error(
|
|
21
|
+
`Unsupported platform: ${platform}-${arch}. ` +
|
|
22
|
+
`Supported: ${Object.keys(PLATFORMS).join(", ")}`
|
|
23
|
+
);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let binPath;
|
|
28
|
+
try {
|
|
29
|
+
const pkgDir = path.dirname(require.resolve(`${pkg}/package.json`));
|
|
30
|
+
const ext = platform === "win32" ? ".exe" : "";
|
|
31
|
+
binPath = path.join(pkgDir, "bin", `whisper-secrets${ext}`);
|
|
32
|
+
} catch (e) {
|
|
33
|
+
console.error(
|
|
34
|
+
`Could not find package ${pkg}. ` +
|
|
35
|
+
`Make sure optional dependencies are installed (do not use --no-optional).`
|
|
36
|
+
);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const result = execFileSync(binPath, process.argv.slice(2), {
|
|
42
|
+
stdio: "inherit",
|
|
43
|
+
});
|
|
44
|
+
} catch (e) {
|
|
45
|
+
if (e.status !== null) {
|
|
46
|
+
process.exit(e.status);
|
|
47
|
+
}
|
|
48
|
+
throw e;
|
|
49
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "whisper-secrets",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Secure, encrypted secret management CLI for teams. Zero-knowledge .env manager with client-side AES-256-GCM encryption.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Quentin Vedrenne",
|
|
7
|
+
"homepage": "https://whisper.quentinvedrenne.com",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/quentinved/Whisper"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/quentinved/Whisper/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"secrets",
|
|
17
|
+
"env",
|
|
18
|
+
"dotenv",
|
|
19
|
+
"encryption",
|
|
20
|
+
"aes-256-gcm",
|
|
21
|
+
"secret-management",
|
|
22
|
+
"cli",
|
|
23
|
+
"zero-knowledge"
|
|
24
|
+
],
|
|
25
|
+
"bin": {
|
|
26
|
+
"whisper-secrets": "bin/whisper-secrets"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"bin/",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"optionalDependencies": {
|
|
33
|
+
"@whisper-secrets/linux-x64": "0.2.0",
|
|
34
|
+
"@whisper-secrets/linux-arm64": "0.2.0",
|
|
35
|
+
"@whisper-secrets/darwin-arm64": "0.2.0",
|
|
36
|
+
"@whisper-secrets/win32-x64": "0.2.0"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=16"
|
|
40
|
+
}
|
|
41
|
+
}
|