keebox 0.9.0 → 0.9.2
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 +66 -41
- package/{index.js → bin/index.js} +10 -5
- package/package.json +10 -5
- package/utils/config.js +7 -4
- package/utils/index.js +15 -3
- package/utils/prompt.js +2 -2
package/README.md
CHANGED
|
@@ -10,9 +10,17 @@
|
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
13
|
-
<a href="https://
|
|
13
|
+
<a href="https://www.npmjs.com/package/keebox"><img src="https://img.shields.io/npm/v/keebox?color=f5a524&label=npm" alt="npm version"></a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/keebox"><img src="https://img.shields.io/npm/dm/keebox?color=f5a524" alt="npm downloads"></a>
|
|
15
|
+
<a href="https://opensource.org/license/mit"><img src="https://img.shields.io/badge/license-MIT-f5a524" alt="MIT license"></a>
|
|
16
|
+
<img src="https://img.shields.io/badge/node-%3E%3D18-f5a524?logo=nodedotjs&logoColor=white" alt="node >= 18">
|
|
17
|
+
<img src="https://img.shields.io/badge/dependencies-0-7ccf8a" alt="zero dependencies">
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
<a href="https://keebox.eissa.top">Website</a> ·
|
|
14
22
|
<a href="#get-started">Get started</a> ·
|
|
15
|
-
<a href="#commands
|
|
23
|
+
<a href="#commands">Commands</a> ·
|
|
16
24
|
<a href="#encryption">Security</a>
|
|
17
25
|
</p>
|
|
18
26
|
|
|
@@ -27,7 +35,7 @@ Most password managers ask you to trust them with everything: your passwords sit
|
|
|
27
35
|
- **Nothing in the cloud.** KeeBox never touches the network: no sync server to breach, no telemetry, no account to phish. Your encrypted vault only exists where you put it.
|
|
28
36
|
- **Strong, standard encryption.** Every password, login and note is encrypted with AES-256-GCM. The key is locked behind your master password with scrypt, which makes guessing slow and expensive. Tampered or damaged entries are detected and refused, never silently decrypted into garbage.
|
|
29
37
|
- **A recovery phrase, like a crypto wallet.** Lost your credentials file or forgot your master password? A 12-word recovery phrase gets you back in. Without the phrase or the password, nobody can open the vault, not even the author of KeeBox.
|
|
30
|
-
- **Zero dependencies.** No
|
|
38
|
+
- **Zero dependencies.** No third-party packages, so there's no supply chain to compromise. The whole tool is about 1,300 lines of plain Node.js that you can read and audit in an afternoon.
|
|
31
39
|
- **Portable.** Copy the folder plus a Node.js binary to a USB drive and it runs on Linux, macOS, Windows and Android (Termux), no installation needed.
|
|
32
40
|
- **Fast from the terminal.** Generate strong passwords, find accounts by any field, and copy a password to the clipboard. It's wiped automatically after 20 seconds.
|
|
33
41
|
- **Yours to keep.** Export everything to CSV whenever you want, import accounts from CSV, and check your vault for damage. Open source and MIT licensed.
|
|
@@ -39,9 +47,22 @@ Most password managers ask you to trust them with everything: your passwords sit
|
|
|
39
47
|
Requires Node.js 18+.
|
|
40
48
|
|
|
41
49
|
```
|
|
42
|
-
|
|
50
|
+
npm install -g keebox
|
|
51
|
+
keebox -h
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Your vault (`db.json` + `credentials.json`) is kept in `~/.keebox/`, outside the npm folder, so updating or uninstalling KeeBox never touches it. To keep it somewhere else (an encrypted drive, a backed-up folder...), set `KEEBOX_HOME`:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
export KEEBOX_HOME=/path/to/vault-folder # in your .bashrc / .zshrc
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Or run it from source, without installing (the vault then lives in the project folder):
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
git clone https://github.com/eissapk/keebox.git
|
|
43
64
|
cd keebox # no npm install needed, there are no dependencies
|
|
44
|
-
node index.js -h
|
|
65
|
+
node bin/index.js -h
|
|
45
66
|
```
|
|
46
67
|
|
|
47
68
|
Clipboard: macOS and Windows/WSL work as is, Linux needs `xclip` (X11) or `wl-clipboard` (Wayland). On Android (Termux) passwords are printed instead of copied.
|
|
@@ -51,9 +72,10 @@ Clipboard: macOS and Windows/WSL work as is, Linux needs `xclip` (X11) or `wl-cl
|
|
|
51
72
|
```
|
|
52
73
|
├── assets
|
|
53
74
|
│ └── logo.svg
|
|
75
|
+
├── bin
|
|
76
|
+
│ └── index.js # CLI entry (the `keebox` command): commands + master password prompt
|
|
54
77
|
├── credentials.json # created on first run (master password lock), not in git
|
|
55
78
|
├── db.json # created on first run (accounts + recovery lock), not in git
|
|
56
|
-
├── index.js # CLI entry: commands + master password prompt
|
|
57
79
|
├── node # optional, for a portable copy (see below), not in git
|
|
58
80
|
│ ├── linux/node
|
|
59
81
|
│ ├── mac/node
|
|
@@ -86,9 +108,11 @@ Clipboard: macOS and Windows/WSL work as is, Linux needs `xclip` (X11) or `wl-cl
|
|
|
86
108
|
└── wordlist.js # BIP39 English wordlist
|
|
87
109
|
```
|
|
88
110
|
|
|
111
|
+
`db.json` / `credentials.json` sit in the project folder when run from source or a portable copy, in `~/.keebox/` when installed with npm, or in `$KEEBOX_HOME` when it's set.
|
|
112
|
+
|
|
89
113
|
##### Make it portable (USB flash)
|
|
90
114
|
|
|
91
|
-
Copy the project with a Node.js binary per OS, so it runs on machines without Node installed:
|
|
115
|
+
Copy the project with a Node.js binary per OS, so it runs on machines without Node installed. The vault is kept next to it, on the flash drive:
|
|
92
116
|
|
|
93
117
|
```
|
|
94
118
|
cp -r /path/to/project /path/to/usb-flash
|
|
@@ -98,46 +122,47 @@ cp "$(command -v node)" /path/to/usb-flash/node/linux/node # repeat for mac/node
|
|
|
98
122
|
Run it from the flash drive:
|
|
99
123
|
|
|
100
124
|
```
|
|
101
|
-
/path/to/usb-flash/node/linux/node /path/to/usb-flash/index.js -h
|
|
125
|
+
/path/to/usb-flash/node/linux/node /path/to/usb-flash/bin/index.js -h
|
|
102
126
|
```
|
|
103
127
|
|
|
104
128
|
Or add an alias in your `.bashrc` / `.zshrc`, and use it anywhere:
|
|
105
129
|
|
|
106
130
|
```
|
|
107
|
-
alias
|
|
108
|
-
|
|
109
|
-
|
|
131
|
+
alias keebox='node /path/to/usb-flash/bin/index.js'
|
|
132
|
+
keebox --help
|
|
133
|
+
keebox --version
|
|
110
134
|
```
|
|
111
135
|
|
|
112
|
-
##### Commands
|
|
136
|
+
##### Commands
|
|
113
137
|
|
|
114
138
|
```
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
139
|
+
keebox get # list all accounts
|
|
140
|
+
keebox get --id 2 # show account with id 2
|
|
141
|
+
keebox get --name google # show accounts whose name contains "google"
|
|
142
|
+
keebox get --id 2 --cp # copy its password to the clipboard (auto-cleared after 20s)
|
|
143
|
+
keebox get --id 2 --show # show its login/notes
|
|
144
|
+
keebox get --id 2 --edit # update it (Enter = keep a value, '-' = clear it)
|
|
145
|
+
keebox get --id 2 --rm # delete it
|
|
146
|
+
keebox add --name google --username foo@gmail.com --url www.google.com # add an account (asks for its password)
|
|
147
|
+
keebox add --name github --username foo --url github.com --login foo@mail.com --notes "2FA via phone" # with login/notes (encrypted)
|
|
148
|
+
keebox make --size 20 # generate a random strong password of 20 chars
|
|
149
|
+
keebox export # export all accounts, decrypted, to keebox-export-<date>.csv
|
|
150
|
+
keebox export --name google --out google.csv # export matching accounts to google.csv
|
|
151
|
+
keebox import --file accounts.csv # add accounts from a csv (same columns as export; id is ignored, duplicates skipped)
|
|
152
|
+
keebox check # damage check: lists accounts that are broken or can't be decrypted (read-only, exit code 1 if any)
|
|
153
|
+
keebox recovery # create (or replace) the 12-word recovery phrase
|
|
154
|
+
keebox recover # lost credentials.json / forgot the master password: unlock with the recovery phrase, set a new master password
|
|
155
|
+
keebox master # create or change the master password
|
|
131
156
|
```
|
|
132
157
|
|
|
133
158
|
Exported CSV files are **not encrypted**, delete them when you're done.
|
|
134
159
|
|
|
135
160
|
##### Create / change master password
|
|
136
161
|
|
|
137
|
-
On a new (empty) vault, the first `
|
|
162
|
+
On a new (empty) vault, the first `keebox add` / `keebox get` asks you to create one. To create it yourself, or change it later (asks the current one first; `db.json` stays as is, and the recovery phrase keeps working):
|
|
138
163
|
|
|
139
164
|
```
|
|
140
|
-
|
|
165
|
+
keebox master
|
|
141
166
|
```
|
|
142
167
|
|
|
143
168
|
##### Encryption
|
|
@@ -147,14 +172,14 @@ Each password, login and notes is encrypted (AES-256-GCM) with one random 256-bi
|
|
|
147
172
|
| Where | Locked with | Opened by |
|
|
148
173
|
|---|---|---|
|
|
149
174
|
| `credentials.json` → `{ salt, n, key }` | scrypt(master password, salt) + AES-256-GCM | the master password |
|
|
150
|
-
| `db.json` → `recovery: { salt, n, key }` | scrypt(12-word phrase, salt) + AES-256-GCM | the recovery phrase (`
|
|
175
|
+
| `db.json` → `recovery: { salt, n, key }` | scrypt(12-word phrase, salt) + AES-256-GCM | the recovery phrase (`keebox recover`) |
|
|
151
176
|
|
|
152
177
|
What gets you into the accounts:
|
|
153
178
|
|
|
154
179
|
| You have | Access? |
|
|
155
180
|
|---|---|
|
|
156
181
|
| `db.json` + `credentials.json` + master password | yes (normal use) |
|
|
157
|
-
| `db.json` + recovery phrase | yes: `
|
|
182
|
+
| `db.json` + recovery phrase | yes: `keebox recover` sets a new master password and writes a new `credentials.json` |
|
|
158
183
|
| `db.json` + master password, but no `credentials.json` | **no**: the master password only opens `credentials.json` (restore `credentials.json.bak` or a backup) |
|
|
159
184
|
| `db.json` alone | **no**, for anyone: it would mean guessing a 128-bit phrase or a 256-bit key |
|
|
160
185
|
|
|
@@ -162,15 +187,15 @@ So keep `db.json` and `credentials.json` together and backed up, choose a strong
|
|
|
162
187
|
|
|
163
188
|
##### Recovery phrase (emergency key)
|
|
164
189
|
|
|
165
|
-
`
|
|
190
|
+
`keebox recovery` makes a 12-word phrase (BIP39 English words, like a crypto wallet seed: 128 random bits + checksum) and locks the same vault key with it into `db.json`. The phrase itself is never saved, it's shown once: write it down, then type it back to confirm.
|
|
166
191
|
|
|
167
|
-
If `credentials.json` is deleted or you forget the master password, `
|
|
192
|
+
If `credentials.json` is deleted or you forget the master password, `keebox recover` asks for the 12 words (any case/spacing; typos and swapped words are caught by the checksum), unlocks the vault key and lets you set a new master password. Only `credentials.json` is written, `db.json` isn't changed, and the same phrase keeps working afterwards. Running `keebox recovery` again replaces the phrase (the old one stops working, except against an older `db.json.bak`).
|
|
168
193
|
|
|
169
194
|
Anyone with the phrase + `db.json` can read every account, so guard it like the master password.
|
|
170
195
|
|
|
171
196
|
##### Files
|
|
172
197
|
|
|
173
|
-
`db.json` (`recovery` is `null` until you run `
|
|
198
|
+
`db.json` (`recovery` is `null` until you run `keebox recovery`):
|
|
174
199
|
|
|
175
200
|
```json
|
|
176
201
|
{
|
|
@@ -197,12 +222,12 @@ Anyone with the phrase + `db.json` can read every account, so guard it like the
|
|
|
197
222
|
{ "salt": "...", "n": 32768, "key": "iv.tag.data" }
|
|
198
223
|
```
|
|
199
224
|
|
|
200
|
-
Both are created automatically if missing, and every save keeps the previous version as `db.json.bak` / `credentials.json.bak`. If `credentials.json` is missing but `db.json` has data, KeeBox won't create a new master password (that would make a new vault key and lock out the existing accounts); it asks you to run `
|
|
225
|
+
Both are created automatically if missing, and every save keeps the previous version as `db.json.bak` / `credentials.json.bak`. If `credentials.json` is missing but `db.json` has data, KeeBox won't create a new master password (that would make a new vault key and lock out the existing accounts); it asks you to run `keebox recover` or restore `credentials.json.bak` instead.
|
|
201
226
|
|
|
202
227
|
##### Decryption flow
|
|
203
228
|
|
|
204
229
|
```
|
|
205
|
-
|
|
230
|
+
keebox get --id 11 --cp
|
|
206
231
|
│
|
|
207
232
|
▼
|
|
208
233
|
┌───────────────────────────────┐
|
|
@@ -269,7 +294,7 @@ Both are created automatically if missing, and every save keeps the previous ver
|
|
|
269
294
|
##### Recovery flow
|
|
270
295
|
|
|
271
296
|
```
|
|
272
|
-
|
|
297
|
+
keebox recover
|
|
273
298
|
│
|
|
274
299
|
▼
|
|
275
300
|
┌───────────────────────────────┐
|
|
@@ -296,10 +321,10 @@ Both are created automatically if missing, and every save keeps the previous ver
|
|
|
296
321
|
|
|
297
322
|
| Step | File | Uses |
|
|
298
323
|
|---|---|---|
|
|
299
|
-
| Ask for or create the master password | `index.js` → `askMaster`, `utils/config.js` → `createMaster` | master password |
|
|
324
|
+
| Ask for or create the master password | `bin/index.js` → `askMaster`, `utils/config.js` → `createMaster` | master password |
|
|
300
325
|
| Master password → vault key | `utils/vault.js` → `unlock` | `credentials.json` `salt`, `n`, `key` |
|
|
301
|
-
| Create the recovery phrase (`
|
|
302
|
-
| Recovery phrase → vault key (`
|
|
326
|
+
| Create the recovery phrase (`keebox recovery`) | `options/recovery.js` → `createRecovery`, `utils/vault.js` → `makeRecovery`, `utils/mnemonic.js` | `db.json` `recovery` |
|
|
327
|
+
| Recovery phrase → vault key (`keebox recover`) | `options/recovery.js` → `recoverVault`, `utils/vault.js` → `recover` | `db.json` `recovery` |
|
|
303
328
|
| Vault key → account password | `utils/index.js` → `decrypt` (called from `options/get.js` → `copyEntry`) | `iv`, `tag`, `data` |
|
|
304
329
|
|
|
305
330
|
##### Tests
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { mkPass, askPassword, loadData, copyOrPrint, run, FIELDS, SECRET_FIELDS, log, hasMaster, unlock, createMaster, changeMaster, parseArgs } = require("../utils");
|
|
2
3
|
const crypto = require("crypto");
|
|
3
|
-
const pkgJSON = require("
|
|
4
|
-
const { getEntry, addEntry, exportEntries, importEntries, checkDb, createRecovery, recoverVault } = require("
|
|
4
|
+
const pkgJSON = require("../package.json");
|
|
5
|
+
const { getEntry, addEntry, exportEntries, importEntries, checkDb, createRecovery, recoverVault } = require("../options");
|
|
5
6
|
|
|
6
7
|
run(main);
|
|
7
8
|
|
|
@@ -29,9 +30,9 @@ async function main() {
|
|
|
29
30
|
["--out <file>", "CSV file to write (default: keebox-export-<date>.csv) - use it with 'export' command"],
|
|
30
31
|
["--file <file>", "CSV file to read (columns: name,password + optional url,username,login,notes,created,updated) - use it with 'import' command"],
|
|
31
32
|
],
|
|
32
|
-
commands: { add: "Add account", get: "display account(s)", make: "Generate a password", export: "Export account(s) as decrypted CSV (filter with --id/--name/...)", import: "Import account(s) from a CSV file (e.g. one made by 'export')", check: "Damage check: find accounts that are broken or can't be decrypted (changes nothing)", recovery: "Create (or replace) the 12-word recovery phrase", recover: "Lost credentials.json / forgot the master password: unlock with the recovery phrase and set a new master password" },
|
|
33
|
+
commands: { add: "Add account", get: "display account(s)", make: "Generate a password", export: "Export account(s) as decrypted CSV (filter with --id/--name/...)", import: "Import account(s) from a CSV file (e.g. one made by 'export')", check: "Damage check: find accounts that are broken or can't be decrypted (changes nothing)", recovery: "Create (or replace) the 12-word recovery phrase", recover: "Lost credentials.json / forgot the master password: unlock with the recovery phrase and set a new master password", master: "Create or change the master password (accounts and recovery phrase keep working)" },
|
|
33
34
|
});
|
|
34
|
-
if (parsed) await { add, get, make, export: exportCsv, import: importCsv, check, recovery, recover }[parsed.command](parsed.opts, db, cred);
|
|
35
|
+
if (parsed) await { add, get, make, export: exportCsv, import: importCsv, check, recovery, recover, master }[parsed.command](parsed.opts, db, cred);
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
// ask master password -> vault key, or null
|
|
@@ -106,3 +107,7 @@ async function recovery(opts, db, cred) {
|
|
|
106
107
|
async function recover(opts, db, cred) {
|
|
107
108
|
await recoverVault(db, cred);
|
|
108
109
|
}
|
|
110
|
+
|
|
111
|
+
async function master(opts, db, cred) {
|
|
112
|
+
await changeMaster(db, cred);
|
|
113
|
+
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keebox",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "KeeBox is an offline password manager that lives in your terminal",
|
|
5
|
-
"
|
|
5
|
+
"bin": {
|
|
6
|
+
"keebox": "./bin/index.js"
|
|
7
|
+
},
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=18"
|
|
10
|
+
},
|
|
6
11
|
"scripts": {
|
|
7
12
|
"test": "node --test"
|
|
8
13
|
},
|
|
9
14
|
"repository": {
|
|
10
15
|
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/eissapk/
|
|
16
|
+
"url": "git+https://github.com/eissapk/keebox.git"
|
|
12
17
|
},
|
|
13
18
|
"keywords": [],
|
|
14
19
|
"author": "Eissa Saber",
|
|
15
20
|
"license": "MIT",
|
|
16
21
|
"bugs": {
|
|
17
|
-
"url": "https://github.com/eissapk/
|
|
22
|
+
"url": "https://github.com/eissapk/keebox/issues"
|
|
18
23
|
},
|
|
19
|
-
"homepage": "https://github.com/eissapk/
|
|
24
|
+
"homepage": "https://github.com/eissapk/keebox#readme"
|
|
20
25
|
}
|
package/utils/config.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
const { askPassword, loadData, saveOrReport, run, credPath, log, lockVault, hasMaster, unlock } = require("./index");
|
|
2
2
|
const crypto = require("crypto");
|
|
3
3
|
|
|
4
|
-
// usage: node utils/config.js -> create the master password, or change it
|
|
4
|
+
// usage: keebox master (or node utils/config.js) -> create the master password, or change it
|
|
5
5
|
if (require.main === module) run(main);
|
|
6
|
-
module.exports = { createMaster };
|
|
6
|
+
module.exports = { createMaster, changeMaster };
|
|
7
7
|
|
|
8
8
|
async function main() {
|
|
9
9
|
const data = loadData();
|
|
10
|
-
if (
|
|
11
|
-
|
|
10
|
+
if (data) await changeMaster(data.db, data.cred);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// create the master password, or change it (asks the current one first)
|
|
14
|
+
async function changeMaster(db, cred) {
|
|
12
15
|
if (!hasMaster(cred)) {
|
|
13
16
|
// a new vault key would make the existing accounts unreadable
|
|
14
17
|
if (db.accounts.length || db.recovery) return log.error("credentials.json is missing, but db.json has data. Run 'recover' with your recovery phrase, or restore credentials.json.bak");
|
package/utils/index.js
CHANGED
|
@@ -12,8 +12,19 @@ const prompt = require("./prompt");
|
|
|
12
12
|
const drawTable = require("./table");
|
|
13
13
|
const parseArgs = require("./cli");
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
// where db.json + credentials.json live:
|
|
16
|
+
// - $KEEBOX_HOME when set
|
|
17
|
+
// - ~/.keebox when installed with npm (inside node_modules, which npm wipes on update/uninstall)
|
|
18
|
+
// - the project folder otherwise (git clone / portable USB copy)
|
|
19
|
+
function dataDir() {
|
|
20
|
+
if (process.env.KEEBOX_HOME) return path.resolve(process.env.KEEBOX_HOME);
|
|
21
|
+
const appDir = path.resolve(__dirname, "..");
|
|
22
|
+
if (appDir.split(path.sep).includes("node_modules")) return path.join(require("os").homedir(), ".keebox");
|
|
23
|
+
return appDir;
|
|
24
|
+
}
|
|
25
|
+
const dir = dataDir();
|
|
26
|
+
const dbPath = path.join(dir, "db.json");
|
|
27
|
+
const credPath = path.join(dir, "credentials.json");
|
|
17
28
|
|
|
18
29
|
// cryptographically secure, exact length, at least one char of each class (length >= 4)
|
|
19
30
|
function mkPass(length) {
|
|
@@ -67,7 +78,8 @@ function decryptField(entry, field, key) {
|
|
|
67
78
|
function saveJson(file, data) {
|
|
68
79
|
const fs = require("fs");
|
|
69
80
|
const tmp = file + ".tmp";
|
|
70
|
-
|
|
81
|
+
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
82
|
+
const fd = fs.openSync(tmp, "w", 0o600);
|
|
71
83
|
try {
|
|
72
84
|
fs.writeFileSync(fd, JSON.stringify(data, null, 2));
|
|
73
85
|
fs.fsyncSync(fd);
|
package/utils/prompt.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// minimal inquirer replacement, public Node APIs only
|
|
2
2
|
// await prompt([{ type: "input" | "password" | "confirm", name, message, default }]) -> answers
|
|
3
3
|
// - interactive (stdin is a terminal): readline for input/confirm, raw-mode reader for passwords (masked with "•")
|
|
4
|
-
// - piped stdin: one shared line queue, so answers can be scripted: printf 'pw\ny\n' |
|
|
4
|
+
// - piped stdin: one shared line queue, so answers can be scripted: printf 'pw\ny\n' | keebox get --id 1 --rm
|
|
5
5
|
// - Ctrl+C exits 130; Ctrl+D / end of input cancels with exit 1 (never auto-answers, e.g. "delete? (Y/n)")
|
|
6
6
|
const readline = require("readline");
|
|
7
7
|
const readlinePromises = require("readline/promises");
|
|
8
8
|
|
|
9
|
-
// prompts go to the terminal even when stdout is redirected (
|
|
9
|
+
// prompts go to the terminal even when stdout is redirected (keebox get > list.txt)
|
|
10
10
|
function promptOut() {
|
|
11
11
|
return process.stdout.isTTY || !process.stderr.isTTY ? process.stdout : process.stderr;
|
|
12
12
|
}
|