wilcocrypt 2.1.0 → 2.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/.github/ISSUE_TEMPLATE/bug.md +78 -0
- package/.github/ISSUE_TEMPLATE/config.yml +6 -0
- package/.github/ISSUE_TEMPLATE/feature.yml +38 -0
- package/.github/dependabot.yml +11 -0
- package/CHANGELOG.md +62 -0
- package/DOCS.md +335 -0
- package/README.md +69 -59
- package/SECURITY.md +48 -0
- package/package.json +17 -10
- package/src/cli.js +141 -0
- package/src/wilcocrypt.js +422 -0
- package/types/wilcocrypt.d.ts +186 -0
- package/dist/cli.js +0 -4441
- package/dist/cli.min.cjs +0 -2
- package/dist/cli.min.js +0 -2
- package/dist/wilcocrypt.js +0 -987
- package/dist/wilcocrypt.min.js +0 -1
- package/rollup.config.js +0 -54
- package/sea/sea-config.json +0 -5
package/README.md
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
# WilcoCrypt
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
It offers both a clean programmatic API and a practical command-line interface (CLI) for everyday use.
|
|
3
|
+
[](https://github.com/standard/semistandard)
|
|
5
4
|
|
|
6
|
-
The
|
|
7
|
-
|
|
5
|
+
> **The `master` branch may be unstable during active development.**
|
|
6
|
+
> For production use, always install from [npm](https://www.npmjs.com/package/wilcocrypt) or use a tagged [GitHub Release](https://github.com/computer-wilco/wilcocrypt/releases).
|
|
7
|
+
|
|
8
|
+
A simple, modern Node.js encryption library and CLI tool. AES-256-GCM, password-based key derivation via scrypt, optional gzip compression, and a streaming API for large files.
|
|
8
9
|
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
## Features
|
|
12
13
|
|
|
13
14
|
- AES-256-GCM authenticated encryption
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
15
|
+
- scrypt key derivation with a random salt per encryption
|
|
16
|
+
- Optional gzip compression before encryption
|
|
17
|
+
- Streaming API for large files (`encryptFileStream` / `decryptFileStream`)
|
|
18
|
+
- CLI with interactive password prompt
|
|
19
|
+
- TypeScript types included
|
|
20
|
+
- semistandard code style
|
|
20
21
|
|
|
21
22
|
---
|
|
22
23
|
|
|
@@ -26,86 +27,95 @@ The library focuses on strong defaults, portability, and predictable behavior ac
|
|
|
26
27
|
npm install wilcocrypt
|
|
27
28
|
```
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npm install -g wilcocrypt
|
|
33
|
-
```
|
|
30
|
+
Requires Node.js 18 or later.
|
|
34
31
|
|
|
35
32
|
---
|
|
36
33
|
|
|
37
|
-
##
|
|
34
|
+
## Quick Start
|
|
38
35
|
|
|
39
36
|
```js
|
|
40
37
|
import wilcocrypt from 'wilcocrypt';
|
|
41
38
|
|
|
42
|
-
// Encrypt a
|
|
43
|
-
wilcocrypt.
|
|
39
|
+
// Encrypt / decrypt a Buffer
|
|
40
|
+
const encrypted = wilcocrypt.encryptData(Buffer.from('Hello!'), 'my-password');
|
|
41
|
+
const decrypted = wilcocrypt.decryptData(encrypted, 'my-password');
|
|
42
|
+
|
|
43
|
+
// Encrypt a file → writes file.txt.enc
|
|
44
|
+
wilcocrypt.encryptFile('file.txt', 'my-password');
|
|
45
|
+
|
|
46
|
+
// Decrypt to Buffer
|
|
47
|
+
const buf = wilcocrypt.decryptFile('file.txt.enc', 'my-password');
|
|
44
48
|
|
|
45
|
-
// Decrypt
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
// Decrypt directly to disk
|
|
50
|
+
wilcocrypt.decryptFile('file.txt.enc', 'my-password', 'output.txt');
|
|
51
|
+
|
|
52
|
+
// Stream API (memory-efficient for large files)
|
|
53
|
+
await wilcocrypt.encryptFileStream('big.zip', 'big.zip.enc', 'my-password');
|
|
54
|
+
await wilcocrypt.decryptFileStream('big.zip.enc', 'big.zip', 'my-password');
|
|
48
55
|
```
|
|
49
56
|
|
|
50
57
|
---
|
|
51
58
|
|
|
52
|
-
##
|
|
59
|
+
## CLI
|
|
53
60
|
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
```bash
|
|
62
|
+
# Encrypt
|
|
63
|
+
wilcocrypt -e secret.txt
|
|
64
|
+
# → prompts for password, writes secret.txt.enc
|
|
56
65
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
# Decrypt to stdout
|
|
67
|
+
wilcocrypt -d secret.txt.enc
|
|
68
|
+
|
|
69
|
+
# Decrypt to a file
|
|
70
|
+
wilcocrypt -d secret.txt.enc -o secret.txt
|
|
61
71
|
```
|
|
62
72
|
|
|
73
|
+
See `wilcocrypt --help` for all options.
|
|
74
|
+
|
|
63
75
|
---
|
|
64
76
|
|
|
65
|
-
##
|
|
77
|
+
## Binary Payload Format
|
|
66
78
|
|
|
67
|
-
|
|
79
|
+
```
|
|
80
|
+
[ HEADER (10) ] [ VERSION (dynamic) ] [ salt (16) ] [ iv (12) ] [ ciphertext ] [ authTag (16) ]
|
|
81
|
+
```
|
|
68
82
|
|
|
69
|
-
|
|
70
|
-
# Encrypt a file
|
|
71
|
-
wilcocrypt -e document.txt
|
|
72
|
-
wilcocrypt --encrypt document.txt
|
|
83
|
+
The auth tag is appended at the end for streaming compatibility. See [DOCS.md](./DOCS.md#binary-payload-format) for the full layout.
|
|
73
84
|
|
|
74
|
-
|
|
75
|
-
wilcocrypt -d document.txt.enc
|
|
76
|
-
wilcocrypt --decrypt document.txt.enc
|
|
85
|
+
> **Note:** The format changed in v2.2.0. Payloads from v2.1.x are not compatible.
|
|
77
86
|
|
|
78
|
-
|
|
79
|
-
wilcocrypt --unpack document.txt.enc
|
|
80
|
-
```
|
|
87
|
+
---
|
|
81
88
|
|
|
82
|
-
|
|
89
|
+
## Error Handling
|
|
83
90
|
|
|
84
|
-
|
|
91
|
+
All errors are instances of `WilcoCryptError` with a machine-readable `code` property.
|
|
85
92
|
|
|
86
|
-
|
|
93
|
+
```js
|
|
94
|
+
import wilcocrypt from 'wilcocrypt';
|
|
95
|
+
const { WilcoCryptError } = wilcocrypt._;
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
wilcocrypt.decryptData(payload, 'wrong');
|
|
99
|
+
} catch (err) {
|
|
100
|
+
if (err instanceof WilcoCryptError) {
|
|
101
|
+
console.error(err.code); // e.g. DECRYPTION_FAILED
|
|
102
|
+
console.error(err.message);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
87
106
|
|
|
88
|
-
|
|
89
|
-
- Version 1.x is deprecated and should not be used
|
|
107
|
+
Common codes: `WEAK_PASSWORD`, `INVALID_HEADER`, `VERSION_MISMATCH`, `DECRYPTION_FAILED`, `INVALID_FILE_EXTENSION`.
|
|
90
108
|
|
|
91
109
|
---
|
|
92
110
|
|
|
93
|
-
##
|
|
111
|
+
## Documentation
|
|
94
112
|
|
|
95
|
-
|
|
113
|
+
Full API reference, CLI docs, payload format, TypeScript usage, and security notes: **[DOCS.md](./DOCS.md)**
|
|
96
114
|
|
|
97
|
-
|
|
98
|
-
- Use the software for any purpose
|
|
99
|
-
- Study how it works and modify it
|
|
100
|
-
- Redistribute the software
|
|
101
|
-
- Distribute modified versions
|
|
115
|
+
Changelog: **[CHANGELOG.md](./CHANGELOG.md)**
|
|
102
116
|
|
|
103
|
-
|
|
104
|
-
- Any distributed derivative work is also licensed under GPL-3.0-only
|
|
105
|
-
- The source code remains available to users
|
|
117
|
+
---
|
|
106
118
|
|
|
107
|
-
|
|
108
|
-
Use it at your own risk.
|
|
119
|
+
## License
|
|
109
120
|
|
|
110
|
-
|
|
111
|
-
https://www.gnu.org/licenses/gpl-3.0.html
|
|
121
|
+
Licensed under **GPL-3.0-only**.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
The following versions of WilcoCrypt are currently supported with security updates:
|
|
6
|
+
|
|
7
|
+
| Version | Supported |
|
|
8
|
+
| ------- | ------------------ |
|
|
9
|
+
| 2.1.x | :white_check_mark: |
|
|
10
|
+
| 2.0.x | :x: |
|
|
11
|
+
| 1.x | :x: |
|
|
12
|
+
|
|
13
|
+
Only the latest minor version in the 2.x range receives security updates. All the versions below that are not supported.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Reporting a Vulnerability
|
|
18
|
+
|
|
19
|
+
If you discover a security vulnerability in WilcoCrypt, please report it responsibly.
|
|
20
|
+
|
|
21
|
+
### How to report
|
|
22
|
+
|
|
23
|
+
- Open a **private security advisory** via the GitHub repository
|
|
24
|
+
|
|
25
|
+
Please include:
|
|
26
|
+
|
|
27
|
+
* A clear description of the issue
|
|
28
|
+
* Steps to reproduce (if possible)
|
|
29
|
+
* Impact assessment (what can go wrong)
|
|
30
|
+
|
|
31
|
+
### What to expect
|
|
32
|
+
|
|
33
|
+
* You will receive a response within **48 hours**
|
|
34
|
+
* I will investigate and confirm the issue
|
|
35
|
+
* If accepted, a fix will be developed as soon as possible
|
|
36
|
+
* A patched version will be released and documented
|
|
37
|
+
|
|
38
|
+
### Responsible disclosure
|
|
39
|
+
|
|
40
|
+
Please do **not** publicly disclose the vulnerability until a fix has been released.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Notes
|
|
45
|
+
|
|
46
|
+
* WilcoCrypt is designed with strong cryptographic defaults, but misuse (e.g. weak passwords) can still lead to insecure outcomes
|
|
47
|
+
* Always use strong, unique passwords
|
|
48
|
+
* Security is a shared responsibility between the library and its users
|
package/package.json
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wilcocrypt",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "A encrypting tool",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"encrypting"
|
|
6
|
+
"encrypting",
|
|
7
|
+
"crypto"
|
|
7
8
|
],
|
|
8
9
|
"license": "GPL-3.0-only",
|
|
9
|
-
"author": "
|
|
10
|
+
"author": "computerwilco",
|
|
10
11
|
"type": "module",
|
|
11
|
-
"main": "
|
|
12
|
-
"bin": "
|
|
12
|
+
"main": "src/wilcocrypt.js",
|
|
13
|
+
"bin": "src/cli.js",
|
|
14
|
+
"types": "types/wilcocrypt.d.ts",
|
|
13
15
|
"scripts": {
|
|
14
|
-
"test": "
|
|
16
|
+
"test": "node src/cli.js",
|
|
17
|
+
"lint": "npx semistandard",
|
|
18
|
+
"lint:fix": "npx semistandard --fix",
|
|
15
19
|
"update": "npx -y Jelmerro/nus",
|
|
16
|
-
"rollup": "rollup -c && node src/scripts/fix-cli-min-import.js && node src/scripts/chmod.js",
|
|
20
|
+
"rollup": "node src/scripts/shebang-fix.js pre && rollup -c && node src/scripts/shebang-fix.js post && node src/scripts/fix-cli-min-import.js && node src/scripts/chmod.js",
|
|
17
21
|
"sea:blob": "node src/scripts/sea-blob.js",
|
|
18
22
|
"sea:linux-x64": "cp node-binaries/linux-x64/node release/wilcocrypt-linux-x64 && npx postject release/wilcocrypt-linux-x64 NODE_SEA_BLOB sea/wilcocrypt.sea --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 && chmod +x release/wilcocrypt-linux-x64",
|
|
19
23
|
"sea:linux-arm64": "cp node-binaries/linux-arm64/node release/wilcocrypt-linux-arm64 && npx postject release/wilcocrypt-linux-arm64 NODE_SEA_BLOB sea/wilcocrypt.sea --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 && chmod +x release/wilcocrypt-linux-arm64",
|
|
@@ -23,13 +27,16 @@
|
|
|
23
27
|
"build": "npm run rollup && npm run sea:blob && npm run sea:linux-x64 && npm run sea:linux-arm64 && npm run sea:windows-x64 && npm run sea:macos-x64 && npm run sea:macos-arm64",
|
|
24
28
|
"clean": "rm -rf dist && rm -rf sea/*.sea && rm -rf release/*"
|
|
25
29
|
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"commander": "14.0.3"
|
|
32
|
+
},
|
|
26
33
|
"devDependencies": {
|
|
27
34
|
"@rollup/plugin-commonjs": "29.0.2",
|
|
28
35
|
"@rollup/plugin-node-resolve": "16.0.3",
|
|
29
36
|
"@rollup/plugin-replace": "6.0.3",
|
|
30
37
|
"@rollup/plugin-terser": "1.0.0",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
38
|
+
"@types/node": "25.6.0",
|
|
39
|
+
"rollup": "4.60.2",
|
|
40
|
+
"semistandard": "17.0.0"
|
|
34
41
|
}
|
|
35
42
|
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import wilcocrypt from './wilcocrypt.js';
|
|
4
|
+
|
|
5
|
+
/* =========================
|
|
6
|
+
Helpers
|
|
7
|
+
========================= */
|
|
8
|
+
|
|
9
|
+
function promptPassword (promptText = 'Password: ') {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
const stdin = process.stdin;
|
|
12
|
+
const stdout = process.stdout;
|
|
13
|
+
|
|
14
|
+
if (!stdin.isTTY) {
|
|
15
|
+
throw new wilcocrypt._.WilcoCryptError(
|
|
16
|
+
'Password prompt requires a TTY',
|
|
17
|
+
'NO_TTY'
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
stdout.write(promptText);
|
|
22
|
+
|
|
23
|
+
let password = '';
|
|
24
|
+
|
|
25
|
+
stdin.setRawMode(true);
|
|
26
|
+
stdin.resume();
|
|
27
|
+
stdin.setEncoding('utf8');
|
|
28
|
+
|
|
29
|
+
function onData (char) {
|
|
30
|
+
if (char === '\r' || char === '\n') {
|
|
31
|
+
stdout.write('\n');
|
|
32
|
+
stdin.setRawMode(false);
|
|
33
|
+
stdin.pause();
|
|
34
|
+
stdin.removeListener('data', onData);
|
|
35
|
+
resolve(password);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (char === '\u0003') {
|
|
40
|
+
stdout.write('\n');
|
|
41
|
+
stdin.setRawMode(false);
|
|
42
|
+
stdin.pause();
|
|
43
|
+
stdin.removeListener('data', onData);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (char === '\u007f' || char === '\b') {
|
|
48
|
+
if (password.length > 0) {
|
|
49
|
+
password = password.slice(0, -1);
|
|
50
|
+
stdout.write('\b \b');
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
password += char;
|
|
56
|
+
stdout.write('*');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
stdin.on('data', onData);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* =========================
|
|
64
|
+
CLI setup
|
|
65
|
+
========================= */
|
|
66
|
+
|
|
67
|
+
const program = new Command();
|
|
68
|
+
|
|
69
|
+
program
|
|
70
|
+
.name('wilcocrypt')
|
|
71
|
+
.description('File encryption tool')
|
|
72
|
+
.version(wilcocrypt._.VERSION, '--version', 'Show version')
|
|
73
|
+
|
|
74
|
+
.option('-e, --encrypt <file>', 'Encrypt file')
|
|
75
|
+
.option('-d, --decrypt <file>', 'Decrypt file')
|
|
76
|
+
.option('-o, --output <file>', 'Write output to file instead of stdout (decrypt only)')
|
|
77
|
+
.option('--stdout', 'Write decrypted output to stdout (default behavior, explicit flag)')
|
|
78
|
+
|
|
79
|
+
.helpOption('-h, --help', 'Display help');
|
|
80
|
+
|
|
81
|
+
program.parse(process.argv);
|
|
82
|
+
|
|
83
|
+
const options = program.opts();
|
|
84
|
+
|
|
85
|
+
/* =========================
|
|
86
|
+
Validation
|
|
87
|
+
========================= */
|
|
88
|
+
|
|
89
|
+
const actions = [
|
|
90
|
+
options.encrypt,
|
|
91
|
+
options.decrypt
|
|
92
|
+
].filter(Boolean);
|
|
93
|
+
|
|
94
|
+
if (actions.length === 0) {
|
|
95
|
+
program.help();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (actions.length > 1) {
|
|
99
|
+
console.error('error: please specify only one action (-e or -d)');
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (options.output && options.stdout) {
|
|
104
|
+
console.error('error: --output and --stdout are mutually exclusive');
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (options.output && options.encrypt) {
|
|
109
|
+
console.error('error: --output is only supported for decryption');
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* =========================
|
|
114
|
+
Actions
|
|
115
|
+
========================= */
|
|
116
|
+
|
|
117
|
+
(async () => {
|
|
118
|
+
try {
|
|
119
|
+
if (options.encrypt) {
|
|
120
|
+
const password = await promptPassword('Encryption password: ');
|
|
121
|
+
wilcocrypt.encryptFile(options.encrypt, password);
|
|
122
|
+
console.log(`Encrypted: ${options.encrypt}.enc`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (options.decrypt) {
|
|
127
|
+
const password = await promptPassword('Decryption password: ');
|
|
128
|
+
|
|
129
|
+
if (options.output) {
|
|
130
|
+
wilcocrypt.decryptFile(options.decrypt, password, options.output);
|
|
131
|
+
console.log(`Decrypted: ${options.output}`);
|
|
132
|
+
} else {
|
|
133
|
+
const result = wilcocrypt.decryptFile(options.decrypt, password);
|
|
134
|
+
process.stdout.write(result);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} catch (err) {
|
|
138
|
+
console.error(`error: ${err.message}`);
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
})();
|