varcrypt 0.0.1 → 0.1.1
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 +89 -0
- package/index.mjs +101 -0
- package/package.json +17 -13
- package/index.js +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# varcrypt
|
|
2
|
+
|
|
3
|
+
CLI for [VarCrypt](https://varcrypt.vercel.app) — pull AES-256-GCM encrypted environment variables from the cloud directly into your terminal.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
Node.js 18 or later.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g varcrypt
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
**1. Generate an API token**
|
|
18
|
+
|
|
19
|
+
Go to **VarCrypt → Settings → API Tokens** and create a new token. Copy the `vc_…` value — it's only shown once.
|
|
20
|
+
|
|
21
|
+
**2. Save the token locally**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
varcrypt login
|
|
25
|
+
# Paste your API token:
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The token is stored in `~/.varcrypt/config.json`.
|
|
29
|
+
|
|
30
|
+
**3. Pull secrets**
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
varcrypt pull <project-slug> <environment>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Example:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
varcrypt pull my-app production
|
|
40
|
+
# DATABASE_URL=postgres://...
|
|
41
|
+
# API_KEY=sk-...
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Pipe directly into a process:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
env $(varcrypt pull my-app production) node server.js
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or source as shell exports:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
source <(varcrypt pull my-app production --output export)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Commands
|
|
57
|
+
|
|
58
|
+
### `varcrypt login`
|
|
59
|
+
|
|
60
|
+
Prompts for an API token and saves it to `~/.varcrypt/config.json`.
|
|
61
|
+
|
|
62
|
+
### `varcrypt pull <project> <env> [options]`
|
|
63
|
+
|
|
64
|
+
Prints secrets for the given project and environment as `KEY=value` lines.
|
|
65
|
+
|
|
66
|
+
| Option | Description |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `--output export` | Print as `export KEY="value"` instead of `KEY=value` |
|
|
69
|
+
| `--host <url>` | Override the API host (default: `http://localhost:3000`) |
|
|
70
|
+
|
|
71
|
+
The `--host` flag is useful for self-hosted deployments:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
varcrypt pull my-app staging --host https://varcrypt.example.com
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## How it works
|
|
78
|
+
|
|
79
|
+
Secrets are encrypted with AES-256-GCM at rest. The CLI sends your API token in the `Authorization` header; the server decrypts and returns the plaintext values over HTTPS. Your token is scoped to a single organization — it cannot read secrets from other organizations.
|
|
80
|
+
|
|
81
|
+
## Security
|
|
82
|
+
|
|
83
|
+
- Tokens are stored in `~/.varcrypt/config.json` with default file permissions. Protect this file like you would an SSH key.
|
|
84
|
+
- Always pull over HTTPS in production. The default `localhost:3000` host is intended for local development only.
|
|
85
|
+
- Rotate tokens in the VarCrypt dashboard if one is compromised.
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
MIT
|
package/index.mjs
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import * as readline from "readline/promises";
|
|
6
|
+
|
|
7
|
+
const CONFIG_DIR = join(homedir(), ".varcrypt");
|
|
8
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
9
|
+
const DEFAULT_HOST = "http://localhost:3000";
|
|
10
|
+
|
|
11
|
+
function loadConfig() {
|
|
12
|
+
try {
|
|
13
|
+
return JSON.parse(readFileSync(CONFIG_FILE, "utf8"));
|
|
14
|
+
} catch {
|
|
15
|
+
return {};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function saveConfig(config) {
|
|
20
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
21
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function login() {
|
|
25
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
26
|
+
const token = await rl.question("Paste your API token: ");
|
|
27
|
+
rl.close();
|
|
28
|
+
|
|
29
|
+
const trimmed = token.trim();
|
|
30
|
+
if (!trimmed.startsWith("vc_")) {
|
|
31
|
+
console.error("Invalid token — must start with vc_");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const config = loadConfig();
|
|
36
|
+
config.token = trimmed;
|
|
37
|
+
saveConfig(config);
|
|
38
|
+
console.log("Token saved to ~/.varcrypt/config.json");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function pull(project, env, opts) {
|
|
42
|
+
const config = loadConfig();
|
|
43
|
+
if (!config.token) {
|
|
44
|
+
console.error("Not logged in. Run: varcrypt login");
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const host = opts.host ?? config.host ?? DEFAULT_HOST;
|
|
49
|
+
const url = `${host}/api/secrets?project=${encodeURIComponent(project)}&env=${encodeURIComponent(env)}`;
|
|
50
|
+
|
|
51
|
+
const res = await fetch(url, {
|
|
52
|
+
headers: { Authorization: `Bearer ${config.token}` },
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
if (!res.ok) {
|
|
56
|
+
const body = await res.json().catch(() => ({}));
|
|
57
|
+
console.error(`Error ${res.status}: ${body.error ?? res.statusText}`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { secrets } = await res.json();
|
|
62
|
+
|
|
63
|
+
if (opts.output === "export") {
|
|
64
|
+
for (const [k, v] of Object.entries(secrets)) {
|
|
65
|
+
console.log(`export ${k}="${v}"`);
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
for (const [k, v] of Object.entries(secrets)) {
|
|
69
|
+
console.log(`${k}=${v}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function usage() {
|
|
75
|
+
console.log(`
|
|
76
|
+
varcrypt <command> [options]
|
|
77
|
+
|
|
78
|
+
Commands:
|
|
79
|
+
login Save your API token
|
|
80
|
+
pull <project> <env> Print secrets as KEY=value
|
|
81
|
+
--output export Print as export KEY="value" instead
|
|
82
|
+
--host <url> Override API host (default: http://localhost:3000)
|
|
83
|
+
`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const [,, cmd, ...args] = process.argv;
|
|
87
|
+
|
|
88
|
+
if (cmd === "login") {
|
|
89
|
+
await login();
|
|
90
|
+
} else if (cmd === "pull") {
|
|
91
|
+
const [project, env, ...rest] = args;
|
|
92
|
+
if (!project || !env) { usage(); process.exit(1); }
|
|
93
|
+
const opts = {};
|
|
94
|
+
for (let i = 0; i < rest.length; i++) {
|
|
95
|
+
if (rest[i] === "--output") opts.output = rest[++i];
|
|
96
|
+
if (rest[i] === "--host") opts.host = rest[++i];
|
|
97
|
+
}
|
|
98
|
+
await pull(project, env, opts);
|
|
99
|
+
} else {
|
|
100
|
+
usage();
|
|
101
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "varcrypt",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "varcrypt",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "CLI for VarCrypt — pull encrypted secrets from the cloud",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"varcrypt": "./index.mjs"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=18"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"index.mjs",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"license": "MIT"
|
|
17
|
+
}
|
package/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// VarCrypt - coming soon
|