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.
@@ -0,0 +1,78 @@
1
+ name: Bug report
2
+ about: Report a bug or unexpected behavior in WilcoCrypt
3
+ title: "[BUG] "
4
+ labels: ["bug"]
5
+
6
+ body:
7
+ - type: markdown
8
+ attributes:
9
+ value: "## Bug report"
10
+
11
+ - type: textarea
12
+ id: description
13
+ attributes:
14
+ label: Description
15
+ description: Describe what went wrong
16
+ placeholder: Clearly explain the issue
17
+ validations:
18
+ required: true
19
+
20
+ - type: textarea
21
+ id: steps
22
+ attributes:
23
+ label: Steps to reproduce
24
+ description: How can this issue be reproduced?
25
+ value: |
26
+ 1.
27
+ 2.
28
+ 3.
29
+ validations:
30
+ required: true
31
+
32
+ - type: textarea
33
+ id: expected
34
+ attributes:
35
+ label: Expected behavior
36
+ description: What did you expect to happen?
37
+ validations:
38
+ required: true
39
+
40
+ - type: textarea
41
+ id: actual
42
+ attributes:
43
+ label: Actual behavior
44
+ description: What actually happened?
45
+ validations:
46
+ required: true
47
+
48
+ - type: input
49
+ id: version
50
+ attributes:
51
+ label: WilcoCrypt version
52
+ placeholder: e.g. 2.1.1
53
+ validations:
54
+ required: true
55
+
56
+ - type: input
57
+ id: node
58
+ attributes:
59
+ label: Node.js version
60
+ placeholder: e.g. 22.x
61
+
62
+ - type: dropdown
63
+ id: environment
64
+ attributes:
65
+ label: Environment
66
+ options:
67
+ - Linux
68
+ - Windows
69
+ - macOS
70
+ - Other
71
+ validations:
72
+ required: true
73
+
74
+ - type: textarea
75
+ id: additional
76
+ attributes:
77
+ label: Additional context
78
+ description: Logs, errors, or anything else
@@ -0,0 +1,6 @@
1
+ blank_issues_enabled: false
2
+
3
+ contact_links:
4
+ - name: Security vulnerability
5
+ url: https://github.com/computer-wilco/wilcocrypt/security/advisories
6
+ about: Report security vulnerabilities privately via GitHub Security Advisories
@@ -0,0 +1,38 @@
1
+ name: Feature request
2
+ about: Suggest an idea or improvement for WilcoCrypt
3
+ title: "[FEATURE] "
4
+ labels: ["enhancement"]
5
+
6
+ body:
7
+ - type: markdown
8
+ attributes:
9
+ value: "## Feature request"
10
+
11
+ - type: textarea
12
+ id: problem
13
+ attributes:
14
+ label: Problem
15
+ description: What problem does this solve?
16
+ placeholder: Describe the issue you're facing
17
+ validations:
18
+ required: true
19
+
20
+ - type: textarea
21
+ id: solution
22
+ attributes:
23
+ label: Proposed solution
24
+ description: What would you like to see?
25
+ validations:
26
+ required: true
27
+
28
+ - type: textarea
29
+ id: alternatives
30
+ attributes:
31
+ label: Alternatives considered
32
+ description: Any alternative solutions you've thought about?
33
+
34
+ - type: textarea
35
+ id: context
36
+ attributes:
37
+ label: Additional context
38
+ description: Extra details, use cases, or examples
@@ -0,0 +1,11 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "npm" # See documentation for possible values
9
+ directory: "/" # Location of package manifests
10
+ schedule:
11
+ interval: "weekly"
package/CHANGELOG.md ADDED
@@ -0,0 +1,62 @@
1
+ # Changelog
2
+
3
+ All notable changes to WilcoCrypt are documented here.
4
+
5
+ ---
6
+
7
+ ## [2.2.0] - 2026-05-01
8
+
9
+ ### Added
10
+
11
+ - **Streaming API** — `encryptFileStream(inputPath, outputPath, password, gzip?)` and `decryptFileStream(inputPath, outputPath, password, gzip?)` for memory-efficient encryption and decryption of large files using Node.js streams.
12
+ - **`decryptFile` output path** — `decryptFile` now accepts an optional `outputPath` argument. When provided, decrypted data is written directly to that file instead of being returned as a Buffer. Fully backward compatible.
13
+ - Internal `HEADER` constant (`[23, 9, 12, 3, 15, 3, 18, 25, 16, 20]`) for payload identification.
14
+ - **CLI `-o` / `--output` flag** — Decrypted output can now be written to a file via `-o <file>` instead of always piping to stdout.
15
+ - **CLI `--stdout` flag** — Explicit flag to write decrypted output to stdout (this remains the default when `-o` is omitted).
16
+ - **Version check on decryption** — The version string is now embedded in the encrypted payload and validated during decryption. Payloads from a different version are rejected with a `VERSION_MISMATCH` error.
17
+ - **GitHub issue templates** (bug report, feature request) and `issue_config.yml`.
18
+ - **`dependabot.yml`** for automated dependency updates.
19
+ - **`SECURITY.md`** with responsible disclosure policy.
20
+ - **`DOCS.md`** — full API reference, CLI docs, payload format, TypeScript usage, and security notes.
21
+
22
+ ### Changed
23
+
24
+ - **Binary payload format** — The encrypted payload format has been updated. The version string is now included between the header and salt, and the auth tag has moved to the **end** of the payload (after the ciphertext) to support streaming. The new layout is:
25
+ `[HEADER (10)] + [VERSION (dynamic)] + [salt (16)] + [iv (12)] + [ciphertext] + [authTag (16)]`
26
+ > Payloads encrypted with v2.1.1 are not compatible with v2.2.0 and vice versa.
27
+ - **Removed `notepack.io`** — The MessagePack dependency has been dropped entirely. The custom binary format replaces the previous envelope-based approach.
28
+ - **VERSION** bumped from `2.1.1` to `2.2.0`.
29
+ - **Linting** — Codebase now enforces [semistandard](https://github.com/standard/semistandard) style (Standard JS + semicolons).
30
+ - **TypeScript types** updated with overloads for the new `decryptFile` signature and the two new stream methods.
31
+ - **README** updated with stability warning, new features, and links to `DOCS.md` and `CHANGELOG.md`.
32
+
33
+ ### Internal
34
+
35
+ - Stream decryption performs early header and version validation before opening the output stream, and automatically cleans up the output file on failure.
36
+ - `_.decryptData` internal helper now accepts raw `Buffer` arguments (previously hex strings).
37
+
38
+ ### Fixed Bugs
39
+
40
+ - Fixed the bug where the CLI tool would not work when running with npx or global
41
+
42
+ ---
43
+
44
+ ## [2.1.1] - 2026-04-26
45
+
46
+ First official GitHub release of WilcoCrypt.
47
+
48
+ ### Added
49
+
50
+ - Full TypeScript support (`wilcocrypt.d.ts`).
51
+ - Pre-built binaries for Linux x64/arm64, macOS x64/arm64, and Windows x64.
52
+ - `WilcoCryptError` custom error class with machine-readable `code` property.
53
+ - Internal helpers: `assertKeyAndIv`, `assertPassword`, `constantTimeEqual`.
54
+
55
+ ### Changed
56
+
57
+ - Removed Rollup bundle from the npm package (Rollup is still used for building binaries).
58
+ - README improvements and consistency fixes.
59
+
60
+ ### Notes
61
+
62
+ - The CLI `wilcocrypt` command does not work when installed globally via npm in this release. Use the provided binaries as a workaround. This is fixed in v2.2.0.
package/DOCS.md ADDED
@@ -0,0 +1,335 @@
1
+ # WilcoCrypt Documentation
2
+
3
+ Complete reference for the WilcoCrypt API, CLI, and binary format.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ - [Installation](#installation)
10
+ - [Quick Start](#quick-start)
11
+ - [API Reference](#api-reference)
12
+ - [encryptData](#encryptdata)
13
+ - [decryptData](#decryptdata)
14
+ - [encryptFile](#encryptfile)
15
+ - [decryptFile](#decryptfile)
16
+ - [encryptFileStream](#encryptfilestream)
17
+ - [decryptFileStream](#decryptfilestream)
18
+ - [Internal Namespace (`_`)](#internal-namespace-_)
19
+ - [CLI Reference](#cli-reference)
20
+ - [Binary Payload Format](#binary-payload-format)
21
+ - [Error Handling](#error-handling)
22
+ - [TypeScript](#typescript)
23
+ - [Security Notes](#security-notes)
24
+
25
+ ---
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ npm install wilcocrypt
31
+ ```
32
+
33
+ Requires Node.js 18 or later (uses `stream/promises` and `fs/promises`).
34
+
35
+ ---
36
+
37
+ ## Quick Start
38
+
39
+ ```js
40
+ import wilcocrypt from 'wilcocrypt';
41
+
42
+ // Encrypt a Buffer
43
+ const data = Buffer.from('Hello, world!');
44
+ const encrypted = wilcocrypt.encryptData(data, 'my-password');
45
+
46
+ // Decrypt it back
47
+ const decrypted = wilcocrypt.decryptData(encrypted, 'my-password');
48
+ console.log(decrypted.toString()); // Hello, world!
49
+
50
+ // Encrypt a file (writes file.txt.enc)
51
+ wilcocrypt.encryptFile('file.txt', 'my-password');
52
+
53
+ // Decrypt a file (returns Buffer)
54
+ const contents = wilcocrypt.decryptFile('file.txt.enc', 'my-password');
55
+
56
+ // Decrypt a file directly to disk
57
+ wilcocrypt.decryptFile('file.txt.enc', 'my-password', 'output.txt');
58
+ ```
59
+
60
+ ---
61
+
62
+ ## API Reference
63
+
64
+ ### `encryptData(plaindata, password, gzip?)`
65
+
66
+ Encrypts a Buffer using password-based AES-256-GCM. The password is never stored; a random salt is generated for every encryption call.
67
+
68
+ | Parameter | Type | Default | Description |
69
+ |------------|-----------|---------|--------------------------------------|
70
+ | `plaindata`| `Buffer` | — | Raw data to encrypt |
71
+ | `password` | `string` | — | Password for key derivation (min. 6 chars) |
72
+ | `gzip` | `boolean` | `true` | Compress data before encryption |
73
+
74
+ **Returns:** `Buffer` — the encrypted payload in the [binary format](#binary-payload-format).
75
+
76
+ **Throws:** `WilcoCryptError` with code `WEAK_PASSWORD` if the password is too short.
77
+
78
+ ```js
79
+ const encrypted = wilcocrypt.encryptData(Buffer.from('secret'), 'passw0rd');
80
+ ```
81
+
82
+ ---
83
+
84
+ ### `decryptData(encryptedBuffer, password, gzip?)`
85
+
86
+ Decrypts a payload produced by `encryptData`. Validates the header and version before attempting decryption.
87
+
88
+ | Parameter | Type | Default | Description |
89
+ |-------------------|-----------|---------|-------------------------------------|
90
+ | `encryptedBuffer` | `Buffer` | — | Payload from `encryptData` |
91
+ | `password` | `string` | — | Password used during encryption |
92
+ | `gzip` | `boolean` | `true` | Decompress after decryption |
93
+
94
+ **Returns:** `Buffer` — the original plaintext data.
95
+
96
+ **Throws:**
97
+
98
+ | Code | Reason |
99
+ |---------------------|-------------------------------------------|
100
+ | `WEAK_PASSWORD` | Password shorter than 6 characters |
101
+ | `INVALID_HEADER` | Not a valid WilcoCrypt payload |
102
+ | `VERSION_MISMATCH` | Payload was encrypted with a different version |
103
+ | `DECRYPTION_FAILED` | Wrong password, tampered or corrupt data |
104
+
105
+ ```js
106
+ const plain = wilcocrypt.decryptData(encrypted, 'passw0rd');
107
+ ```
108
+
109
+ ---
110
+
111
+ ### `encryptFile(filePath, password, gzip?)`
112
+
113
+ Reads a file, encrypts it, and writes the result to `<filePath>.enc`. Uses `encryptData` internally, so the entire file is loaded into memory. For large files, use [`encryptFileStream`](#encryptfilestream) instead.
114
+
115
+ | Parameter | Type | Default | Description |
116
+ |------------|-----------|---------|---------------------------------|
117
+ | `filePath` | `string` | — | Path to the source file |
118
+ | `password` | `string` | — | Password for key derivation |
119
+ | `gzip` | `boolean` | `true` | Compress before encryption |
120
+
121
+ **Returns:** `void`
122
+
123
+ ```js
124
+ wilcocrypt.encryptFile('document.pdf', 'passw0rd');
125
+ // Creates document.pdf.enc
126
+ ```
127
+
128
+ ---
129
+
130
+ ### `decryptFile(filePath, password, outputPath?, gzip?)`
131
+
132
+ Decrypts a `.enc` file. If `outputPath` is provided, the result is written to disk and `undefined` is returned. Otherwise the decrypted `Buffer` is returned.
133
+
134
+ | Parameter | Type | Default | Description |
135
+ |--------------|-----------|-------------|-------------------------------------------------------|
136
+ | `filePath` | `string` | — | Path to the `.enc` file |
137
+ | `password` | `string` | — | Password used during encryption |
138
+ | `outputPath` | `string` | `undefined` | Optional path to write decrypted output to |
139
+ | `gzip` | `boolean` | `true` | Decompress after decryption |
140
+
141
+ > The legacy 3-argument form `decryptFile(filePath, password, gzip)` is still fully supported, but will be deprecated in the next release.
142
+
143
+ **Returns:** `Buffer` when no `outputPath` is given, `undefined` otherwise.
144
+
145
+ **Throws:** `WilcoCryptError` with code `INVALID_FILE_EXTENSION` if `filePath` does not end in `.enc`.
146
+
147
+ ```js
148
+ // Return as Buffer
149
+ const buf = wilcocrypt.decryptFile('document.pdf.enc', 'passw0rd');
150
+
151
+ // Write directly to disk
152
+ wilcocrypt.decryptFile('document.pdf.enc', 'passw0rd', 'document.pdf');
153
+ ```
154
+
155
+ ---
156
+
157
+ ### `encryptFileStream(inputPath, outputPath, password, gzip?)`
158
+
159
+ Streaming equivalent of `encryptFile`. Reads from `inputPath` and writes to `outputPath` chunk by chunk — suitable for large files where loading everything into memory is impractical.
160
+
161
+ | Parameter | Type | Default | Description |
162
+ |--------------|-----------|---------|--------------------------------------|
163
+ | `inputPath` | `string` | — | Path to the source file |
164
+ | `outputPath` | `string` | — | Path for the encrypted output |
165
+ | `password` | `string` | — | Password for key derivation |
166
+ | `gzip` | `boolean` | `true` | Compress before encryption |
167
+
168
+ **Returns:** `Promise<void>`
169
+
170
+ ```js
171
+ await wilcocrypt.encryptFileStream('bigfile.zip', 'bigfile.zip.enc', 'passw0rd');
172
+ ```
173
+
174
+ ---
175
+
176
+ ### `decryptFileStream(inputPath, outputPath, password, gzip?)`
177
+
178
+ Streaming equivalent of `decryptFile`. Header and version are validated before the stream starts. If decryption fails at any point, the partially written output file is deleted automatically.
179
+
180
+ | Parameter | Type | Default | Description |
181
+ |--------------|-----------|---------|---------------------------------------|
182
+ | `inputPath` | `string` | — | Path to the `.enc` file |
183
+ | `outputPath` | `string` | — | Path to write decrypted output to |
184
+ | `password` | `string` | — | Password used during encryption |
185
+ | `gzip` | `boolean` | `true` | Decompress after decryption |
186
+
187
+ **Returns:** `Promise<void>`
188
+
189
+ **Throws:** Same error codes as `decryptData`, plus automatic cleanup of `outputPath` on failure.
190
+
191
+ ```js
192
+ await wilcocrypt.decryptFileStream('bigfile.zip.enc', 'bigfile.zip', 'passw0rd');
193
+ ```
194
+
195
+ ---
196
+
197
+ ### Internal Namespace (`_`)
198
+
199
+ The `wilcocrypt._` namespace exposes internal helpers. These are not intended for normal use but are part of the public surface for advanced use cases and testing.
200
+
201
+ | Member | Type | Description |
202
+ |-------------------------|------------|----------------------------------------------------------|
203
+ | `_.VERSION` | `string` | Current version string, embedded in every payload |
204
+ | `_.MIN_PASSWORD_LENGTH` | `number` | Minimum accepted password length (6) |
205
+ | `_.HEADER` | `Buffer` | 10-byte magic bytes identifying a WilcoCrypt payload |
206
+ | `_.WilcoCryptError` | `class` | The error class (also importable from TypeScript types) |
207
+ | `_.assertKeyAndIv(key, iv)` | `function` | Throws if key or IV are not valid Buffers of the right length |
208
+ | `_.assertPassword(password)` | `function` | Throws `WEAK_PASSWORD` if password is too short |
209
+ | `_.constantTimeEqual(a, b)` | `function` | Constant-time Buffer comparison, returns `boolean` |
210
+ | `_.encryptData(plainData, key, iv)` | `function` | Raw AES-256-GCM encryption, returns `{ ciphertext, authTag }` |
211
+ | `_.decryptData(cipherBuffer, authTagBuffer, key, iv)` | `function` | Raw AES-256-GCM decryption, returns `Buffer` |
212
+
213
+ ---
214
+
215
+ ## CLI Reference
216
+
217
+ Install globally or use via `npx`:
218
+
219
+ ```bash
220
+ npm install -g wilcocrypt
221
+ wilcocrypt --help
222
+ ```
223
+
224
+ ### Options
225
+
226
+ | Flag | Description |
227
+ |--------------------------|-----------------------------------------------------|
228
+ | `-e, --encrypt <file>` | Encrypt the given file, writes `<file>.enc` |
229
+ | `-d, --decrypt <file>` | Decrypt the given `.enc` file |
230
+ | `-o, --output <file>` | Write decrypted output to `<file>` instead of stdout |
231
+ | `--stdout` | Explicitly write decrypted output to stdout (default) |
232
+ | `--version` | Show WilcoCrypt version |
233
+ | `-h, --help` | Show help |
234
+
235
+ Only one of `-e` or `-d` may be used at a time. The `--output` and `--stdout` flags are mutually exclusive. `--output` is only valid with `-d`.
236
+
237
+ ### Examples
238
+
239
+ ```bash
240
+ # Encrypt a file
241
+ wilcocrypt -e secret.txt
242
+ # → prompts for password, writes secret.txt.enc
243
+
244
+ # Decrypt to stdout (pipe-friendly)
245
+ wilcocrypt -d secret.txt.enc
246
+ # → prompts for password, writes to stdout
247
+
248
+ # Decrypt to a file
249
+ wilcocrypt -d secret.txt.enc -o secret.txt
250
+ # → prompts for password, writes to secret.txt
251
+ ```
252
+
253
+ Passwords are entered interactively with character masking (`*`). The CLI requires a TTY; piping passwords in is intentionally not supported.
254
+
255
+ ---
256
+
257
+ ## Binary Payload Format
258
+
259
+ Every payload produced by WilcoCrypt v2.2.0 has the following binary layout:
260
+
261
+ ```
262
+ [ HEADER ] 10 bytes — magic bytes: 23 9 12 3 15 3 18 25 16 20
263
+ [ VERSION ] dynamic — UTF-8 version string (e.g. "2.2.0"), 5 bytes for current version
264
+ [ salt ] 16 bytes — random salt for scrypt key derivation
265
+ [ iv ] 12 bytes — random IV for AES-256-GCM
266
+ [ ciphertext] variable — AES-256-GCM encrypted (and optionally gzip-compressed) data
267
+ [ authTag ] 16 bytes — GCM authentication tag
268
+ ```
269
+
270
+ The auth tag is placed at the end to allow the streaming API to append it after the pipeline finishes, without needing to seek backwards in the output stream.
271
+
272
+ > **Compatibility note:** The format changed between v2.1.x and v2.2.0. Files encrypted with v2.1.x cannot be decrypted with v2.2.0 and will throw a `VERSION_MISMATCH` or `INVALID_HEADER` error.
273
+
274
+ ---
275
+
276
+ ## Error Handling
277
+
278
+ All errors thrown by WilcoCrypt are instances of `WilcoCryptError`, which extends `Error` with a `code` property.
279
+
280
+ ```js
281
+ import wilcocrypt from 'wilcocrypt';
282
+ const { WilcoCryptError } = wilcocrypt._;
283
+
284
+ try {
285
+ wilcocrypt.decryptData(payload, 'wrong-password');
286
+ } catch (err) {
287
+ if (err instanceof WilcoCryptError) {
288
+ console.error(err.code); // e.g. DECRYPTION_FAILED
289
+ console.error(err.message); // human-readable
290
+ }
291
+ }
292
+ ```
293
+
294
+ ### Error Codes
295
+
296
+ | Code | Thrown by | Cause |
297
+ |-------------------------|----------------------------------|----------------------------------------------------|
298
+ | `WEAK_PASSWORD` | All public methods | Password shorter than 6 characters |
299
+ | `INVALID_HEADER` | `decryptData`, `decryptFile`, stream variants | Payload does not start with the WilcoCrypt magic bytes |
300
+ | `VERSION_MISMATCH` | `decryptData`, `decryptFile`, stream variants | Payload version does not match current version |
301
+ | `DECRYPTION_FAILED` | `decryptData`, `decryptFile`, stream variants | Wrong password, tampered data, or corruption |
302
+ | `INVALID_FILE_EXTENSION`| `decryptFile` | File path does not end with `.enc` |
303
+ | `INVALID_KEY` | `_.assertKeyAndIv` | Key is not a 32-byte Buffer |
304
+ | `INVALID_IV` | `_.assertKeyAndIv` | IV is not a 12-byte Buffer |
305
+ | `NO_TTY` | CLI password prompt | stdin is not a TTY |
306
+
307
+ ---
308
+
309
+ ## TypeScript
310
+
311
+ WilcoCrypt ships with `wilcocrypt.d.ts`. No `@types` package needed.
312
+
313
+ ```ts
314
+ import wilcocrypt, { WilcoCryptError } from 'wilcocrypt';
315
+
316
+ const encrypted: Buffer = wilcocrypt.encryptData(Buffer.from('hi'), 'passw0rd');
317
+
318
+ // decryptFile overloads
319
+ const buf: Buffer = wilcocrypt.decryptFile('file.enc', 'passw0rd');
320
+ wilcocrypt.decryptFile('file.enc', 'passw0rd', 'output.txt'); // returns undefined
321
+
322
+ // Streams
323
+ await wilcocrypt.encryptFileStream('in.txt', 'in.txt.enc', 'passw0rd');
324
+ await wilcocrypt.decryptFileStream('in.txt.enc', 'out.txt', 'passw0rd');
325
+ ```
326
+
327
+ ---
328
+
329
+ ## Security Notes
330
+
331
+ - **Key derivation** uses [scrypt](https://nodejs.org/api/crypto.html#cryptoscryptsyncpassword-salt-keylen-options) with a 16-byte random salt generated fresh for every encryption. The same password will produce a different key each time.
332
+ - **Authenticated encryption** via AES-256-GCM means any tampering with the ciphertext or auth tag will cause decryption to fail with `DECRYPTION_FAILED`.
333
+ - **No password is stored** anywhere in the payload. There is no way to recover a lost password.
334
+ - **The `gzip` flag must match** between encryption and decryption. If data was encrypted without compression (`gzip: false`), decryption must also use `gzip: false`.
335
+ - See [SECURITY.md](./SECURITY.md) for the responsible disclosure policy.