wilcocrypt 2.1.1 → 2.2.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 CHANGED
@@ -1,21 +1,24 @@
1
1
  # WilcoCrypt
2
2
 
3
- **WilcoCrypt** is a small, secure, and predictable encryption library for Node.js.
3
+ [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
4
4
 
5
- It is designed around strong defaults, minimal dependencies, and consistent behavior across environments — from servers to low-end devices like Raspberry Pi.
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.
6
9
 
7
10
  ---
8
11
 
9
12
  ## Features
10
13
 
11
14
  - AES-256-GCM authenticated encryption
12
- - Password-based key derivation using scrypt
15
+ - scrypt key derivation with a random salt per encryption
13
16
  - Optional gzip compression before encryption
14
- - Compact binary format using MessagePack
15
- - Built-in versioning and compatibility checks
16
- - Clear and consistent error handling
17
- - Simple, dependency-light design
18
- - CLI for quick file encryption and decryption
17
+ - Synchronous and asynchronous APIs
18
+ - Streaming API for large files (`encryptFileStream` / `decryptFileStream`)
19
+ - CLI with interactive password prompt
20
+ - Comprehensive TypeScript definitions with full JSDoc support
21
+ - Prettier code formatting
19
22
 
20
23
  ---
21
24
 
@@ -25,99 +28,92 @@ It is designed around strong defaults, minimal dependencies, and consistent beha
25
28
  npm install wilcocrypt
26
29
  ```
27
30
 
28
- ### CLI (global)
29
-
30
- ```bash
31
- npm install -g wilcocrypt
32
- ```
31
+ Requires Node.js 18 or later.
33
32
 
34
33
  ---
35
34
 
36
- ## Usage (Node.js)
35
+ ## Quick Start
37
36
 
38
37
  ```js
39
- import wilcocrypt from 'wilcocrypt';
38
+ import wilcocrypt from "wilcocrypt";
40
39
 
41
- // Encrypt a file
42
- wilcocrypt.encryptFile('document.txt', 'myStrongPassword');
40
+ // Encrypt / decrypt a Buffer
41
+ const encrypted = wilcocrypt.encryptData(Buffer.from("Hello!"), "my-password");
42
+ const decrypted = wilcocrypt.decryptData(encrypted, "my-password");
43
43
 
44
- // Decrypt a file
45
- const content = wilcocrypt.decryptFile('document.txt.enc', 'myStrongPassword');
44
+ // Encrypt a file → writes file.txt.enc
45
+ wilcocrypt.encryptFile("file.txt", "my-password");
46
46
 
47
- console.log(content);
48
- ```
47
+ // Decrypt to Buffer
48
+ const buf = wilcocrypt.decryptFile("file.txt.enc", "my-password");
49
49
 
50
- ### Working with Buffers
50
+ // Decrypt directly to disk
51
+ wilcocrypt.decryptFile("file.txt.enc", "my-password", "output.txt");
51
52
 
52
- ```js
53
- import wilcocrypt from 'wilcocrypt';
54
-
55
- const data = Buffer.from('Hello world');
56
-
57
- // Encrypt
58
- const encrypted = wilcocrypt.encryptData(data, 'password');
59
-
60
- // Decrypt
61
- const decrypted = wilcocrypt.decryptData(encrypted, 'password');
62
-
63
- console.log(decrypted.toString());
53
+ // Stream API (memory-efficient for large files)
54
+ await wilcocrypt.encryptFileStream("big.zip", "big.zip.enc", "my-password");
55
+ await wilcocrypt.decryptFileStream("big.zip.enc", "big.zip", "my-password");
64
56
  ```
65
57
 
66
58
  ---
67
59
 
68
- ## CLI Usage
60
+ ## CLI
69
61
 
70
62
  ```bash
71
63
  # Encrypt
72
- wilcocrypt -e file.txt
73
- wilcocrypt --encrypt file.txt
64
+ wilcocrypt -e secret.txt
65
+ # prompts for password, writes secret.txt.enc
66
+
67
+ # Decrypt to stdout
68
+ wilcocrypt -d secret.txt.enc
74
69
 
75
- # Decrypt
76
- wilcocrypt -d file.txt.enc
77
- wilcocrypt --decrypt file.txt.enc
70
+ # Decrypt to a file
71
+ wilcocrypt -d secret.txt.enc -o secret.txt
78
72
  ```
79
73
 
80
- The CLI will securely prompt for a password (input is masked).
74
+ See `wilcocrypt --help` for all options.
81
75
 
82
76
  ---
83
77
 
84
- ## Internal API
78
+ ## Binary Payload Format
85
79
 
86
- Advanced users can access internal helpers via:
87
-
88
- ```js
89
- wilcocrypt._
80
+ ```
81
+ [ HEADER (10) ] [ VERSION (dynamic) ] [ salt (16) ] [ iv (12) ] [ ciphertext ] [ authTag (16) ]
90
82
  ```
91
83
 
92
- These APIs are **not stable** and may change between versions.
93
-
94
- ---
84
+ The auth tag is appended at the end for streaming compatibility. See [DOCS.md](./DOCS.md#binary-payload-format) for the full layout.
95
85
 
96
- ## Format Overview
86
+ > **Note:** The format changed in v2.2.0. Payloads from v2.1.x are not compatible.
97
87
 
98
- Encrypted output is stored as a MessagePack-encoded object containing:
88
+ ---
99
89
 
100
- - payload (ciphertext, hex)
101
- - authTag (hex)
102
- - salt (hex)
103
- - iv (hex)
104
- - version
90
+ ## Error Handling
105
91
 
106
- ---
92
+ All errors are instances of `WilcoCryptError` with a machine-readable `code` property.
107
93
 
108
- ## Version
94
+ ```js
95
+ import wilcocrypt from "wilcocrypt";
96
+ const { WilcoCryptError } = wilcocrypt._;
97
+
98
+ try {
99
+ wilcocrypt.decryptData(payload, "wrong");
100
+ } catch (err) {
101
+ if (err instanceof WilcoCryptError) {
102
+ console.error(err.code); // e.g. DECRYPTION_FAILED
103
+ console.error(err.message);
104
+ }
105
+ }
106
+ ```
109
107
 
110
- - Current version: **2.1.1**
111
- - Encrypted data must match the exact version
108
+ Common codes: `WEAK_PASSWORD`, `INVALID_HEADER`, `VERSION_MISMATCH`, `DECRYPTION_FAILED`, `INVALID_FILE_EXTENSION`.
112
109
 
113
110
  ---
114
111
 
115
- ## Security Notes
112
+ ## Documentation
113
+
114
+ Full API reference, CLI docs, payload format, TypeScript usage, and security notes: **[DOCS.md](./DOCS.md)**
116
115
 
117
- - Always use strong, unique passwords
118
- - Losing the password means permanent data loss
119
- - Do not modify encrypted files manually
120
- - Compression can be disabled if not needed
116
+ Changelog: **[CHANGELOG.md](./CHANGELOG.md)**
121
117
 
122
118
  ---
123
119
 
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.2.x | :white_check_mark: |
10
+ | 2.1.x | :x: |
11
+ | 2.0.x | :x: |
12
+ | 1.x | :x: |
13
+
14
+ Only the latest minor version in the 2.x range receives updates. All the versions below that are not supported.
15
+
16
+ ---
17
+
18
+ ## Reporting a Vulnerability
19
+
20
+ If you discover a security vulnerability in WilcoCrypt, please report it responsibly.
21
+
22
+ ### How to report
23
+
24
+ - Open a **private security advisory** via the GitHub repository
25
+
26
+ Please include:
27
+
28
+ - A clear description of the issue
29
+ - Steps to reproduce (if possible)
30
+ - Impact assessment (what can go wrong)
31
+
32
+ ### What to expect
33
+
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,6 +1,6 @@
1
1
  {
2
2
  "name": "wilcocrypt",
3
- "version": "2.1.1",
3
+ "version": "2.2.1",
4
4
  "description": "A encrypting tool",
5
5
  "keywords": [
6
6
  "encrypting",
@@ -10,12 +10,16 @@
10
10
  "author": "computerwilco",
11
11
  "type": "module",
12
12
  "main": "src/wilcocrypt.js",
13
- "bin": "src/cli.js",
13
+ "bin": {
14
+ "wilcocrypt": "src/cli.js"
15
+ },
14
16
  "types": "types/wilcocrypt.d.ts",
15
17
  "scripts": {
16
- "test": "echo \"Error: no test specified\" && exit 1",
18
+ "test": "node src/cli.js",
19
+ "semistandard": "npx semistandard",
20
+ "lint": "npx semistandard --fix; npx prettier --write .",
17
21
  "update": "npx -y Jelmerro/nus",
18
- "rollup": "rollup -c && node src/scripts/fix-cli-min-import.js && node src/scripts/chmod.js",
22
+ "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",
19
23
  "sea:blob": "node src/scripts/sea-blob.js",
20
24
  "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",
21
25
  "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",
@@ -26,14 +30,16 @@
26
30
  "clean": "rm -rf dist && rm -rf sea/*.sea && rm -rf release/*"
27
31
  },
28
32
  "dependencies": {
29
- "commander": "14.0.3",
30
- "notepack.io": "3.0.1"
33
+ "commander": "15.0.0"
31
34
  },
32
35
  "devDependencies": {
33
- "@rollup/plugin-commonjs": "29.0.2",
36
+ "@rollup/plugin-commonjs": "29.0.3",
34
37
  "@rollup/plugin-node-resolve": "16.0.3",
35
38
  "@rollup/plugin-replace": "6.0.3",
36
39
  "@rollup/plugin-terser": "1.0.0",
37
- "rollup": "4.60.2"
40
+ "@types/node": "25.9.2",
41
+ "prettier": "3.8.3",
42
+ "rollup": "4.61.1",
43
+ "semistandard": "17.0.0"
38
44
  }
39
45
  }
package/src/cli.js CHANGED
@@ -1,61 +1,62 @@
1
- import { Command } from 'commander';
2
- import wilcocrypt from './wilcocrypt.js';
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import wilcocrypt from "./wilcocrypt.js";
3
4
 
4
5
  /* =========================
5
6
  Helpers
6
7
  ========================= */
7
8
 
8
- function promptPassword(promptText = 'Password: ') {
9
+ function promptPassword(promptText = "Password: ") {
9
10
  return new Promise((resolve) => {
10
11
  const stdin = process.stdin;
11
12
  const stdout = process.stdout;
12
13
 
13
14
  if (!stdin.isTTY) {
14
15
  throw new wilcocrypt._.WilcoCryptError(
15
- 'Password prompt requires a TTY',
16
- 'NO_TTY'
16
+ "Password prompt requires a TTY",
17
+ "NO_TTY",
17
18
  );
18
19
  }
19
-
20
+
20
21
  stdout.write(promptText);
21
22
 
22
- let password = '';
23
+ let password = "";
23
24
 
24
25
  stdin.setRawMode(true);
25
26
  stdin.resume();
26
- stdin.setEncoding('utf8');
27
+ stdin.setEncoding("utf8");
27
28
 
28
29
  function onData(char) {
29
- if (char === '\r' || char === '\n') {
30
- stdout.write('\n');
30
+ if (char === "\r" || char === "\n") {
31
+ stdout.write("\n");
31
32
  stdin.setRawMode(false);
32
33
  stdin.pause();
33
- stdin.removeListener('data', onData);
34
+ stdin.removeListener("data", onData);
34
35
  resolve(password);
35
36
  return;
36
37
  }
37
38
 
38
- if (char === '\u0003') {
39
- stdout.write('\n');
39
+ if (char === "\u0003") {
40
+ stdout.write("\n");
40
41
  stdin.setRawMode(false);
41
42
  stdin.pause();
42
- stdin.removeListener('data', onData);
43
+ stdin.removeListener("data", onData);
43
44
  process.exit(1);
44
45
  }
45
46
 
46
- if (char === '\u007f' || char === '\b') {
47
+ if (char === "\u007f" || char === "\b") {
47
48
  if (password.length > 0) {
48
49
  password = password.slice(0, -1);
49
- stdout.write('\b \b');
50
+ stdout.write("\b \b");
50
51
  }
51
52
  return;
52
53
  }
53
54
 
54
55
  password += char;
55
- stdout.write('*');
56
+ stdout.write("*");
56
57
  }
57
58
 
58
- stdin.on('data', onData);
59
+ stdin.on("data", onData);
59
60
  });
60
61
  }
61
62
 
@@ -66,14 +67,22 @@ function promptPassword(promptText = 'Password: ') {
66
67
  const program = new Command();
67
68
 
68
69
  program
69
- .name('wilcocrypt')
70
- .description('File encryption tool')
71
- .version(wilcocrypt._.VERSION, '--version', 'Show version')
72
-
73
- .option('-e, --encrypt <file>', 'Encrypt file')
74
- .option('-d, --decrypt <file>', 'Decrypt file')
75
-
76
- .helpOption('-h, --help', 'Display help');
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(
77
+ "-o, --output <file>",
78
+ "Write output to file instead of stdout (decrypt only)",
79
+ )
80
+ .option(
81
+ "--stdout",
82
+ "Write decrypted output to stdout (default behavior, explicit flag)",
83
+ )
84
+
85
+ .helpOption("-h, --help", "Display help");
77
86
 
78
87
  program.parse(process.argv);
79
88
 
@@ -83,18 +92,24 @@ const options = program.opts();
83
92
  Validation
84
93
  ========================= */
85
94
 
86
- const actions = [
87
- options.encrypt,
88
- options.decrypt,
89
- options.unpack
90
- ].filter(Boolean);
95
+ const actions = [options.encrypt, options.decrypt].filter(Boolean);
91
96
 
92
97
  if (actions.length === 0) {
93
98
  program.help();
94
99
  }
95
100
 
96
101
  if (actions.length > 1) {
97
- console.error('error: please specify only one action (-e, -d or --unpack)');
102
+ console.error("error: please specify only one action (-e or -d)");
103
+ process.exit(1);
104
+ }
105
+
106
+ if (options.output && options.stdout) {
107
+ console.error("error: --output and --stdout are mutually exclusive");
108
+ process.exit(1);
109
+ }
110
+
111
+ if (options.output && options.encrypt) {
112
+ console.error("error: --output is only supported for decryption");
98
113
  process.exit(1);
99
114
  }
100
115
 
@@ -105,17 +120,22 @@ if (actions.length > 1) {
105
120
  (async () => {
106
121
  try {
107
122
  if (options.encrypt) {
108
- const password = await promptPassword('Encryption password: ');
123
+ const password = await promptPassword("Encryption password: ");
109
124
  wilcocrypt.encryptFile(options.encrypt, password);
110
125
  console.log(`Encrypted: ${options.encrypt}.enc`);
111
126
  return;
112
127
  }
113
128
 
114
129
  if (options.decrypt) {
115
- const password = await promptPassword('Decryption password: ');
116
- const result = wilcocrypt.decryptFile(options.decrypt, password);
117
- process.stdout.write(result);
118
- return;
130
+ const password = await promptPassword("Decryption password: ");
131
+
132
+ if (options.output) {
133
+ wilcocrypt.decryptFile(options.decrypt, password, options.output);
134
+ console.log(`Decrypted: ${options.output}`);
135
+ } else {
136
+ const result = wilcocrypt.decryptFile(options.decrypt, password);
137
+ process.stdout.write(result);
138
+ }
119
139
  }
120
140
  } catch (err) {
121
141
  console.error(`error: ${err.message}`);