bytifi 0.2.1 → 0.2.3
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 +1 -28
- package/bin/bytifi.js +4 -1
- package/lib/crypto.js +22 -5
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ bytifi upload ./logs.txt --concurrency 8 --json > upload.json
|
|
|
59
59
|
bytifi upload ./photo.png -q
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
Files up to **10 MB** are gzip-compressed per chunk before encryption. Larger files use multipart upload with fixed-size encrypted parts (no compression — gzip can expand ISO/zip data past the server part limit).
|
|
63
63
|
|
|
64
64
|
Upload accepts **one file at a time**. Quote paths that contain spaces. Avoid shell globs like `**` — your shell may expand them into dozens of paths.
|
|
65
65
|
|
|
@@ -155,33 +155,6 @@ JSON output for decrypt includes `outputPath`, `originalName`, `size`, `mimeType
|
|
|
155
155
|
|
|
156
156
|
Files over ~100 MB encrypted use multipart upload automatically. Progress prints to stderr unless `--json` or `--quiet` is set.
|
|
157
157
|
|
|
158
|
-
## How it works
|
|
159
|
-
|
|
160
|
-
**Upload**
|
|
161
|
-
|
|
162
|
-
1. Gzip-compresses each chunk, then encrypts locally with AES-GCM (meta `version: 2`)
|
|
163
|
-
2. Uploads encrypted bytes via multipart pipeline for files >10 MB
|
|
164
|
-
3. Prints a share URL including `#token=...`
|
|
165
|
-
|
|
166
|
-
## Compatibility
|
|
167
|
-
|
|
168
|
-
| Scenario | Works? |
|
|
169
|
-
|----------|--------|
|
|
170
|
-
| Old links (no compression) | Yes — everywhere |
|
|
171
|
-
| New CLI upload + new CLI decrypt | Yes |
|
|
172
|
-
| New CLI upload + **updated website** decrypt | Yes — **deploy Bytifi-Website** after upgrading CLI |
|
|
173
|
-
| New CLI upload + old website (not deployed) | **Broken in browser** — garbled download |
|
|
174
|
-
| New CLI upload + old CLI (≤0.1.5) decrypt | **Broken** — upgrade CLI |
|
|
175
|
-
| Website upload (no compression) | Yes — unchanged |
|
|
176
|
-
|
|
177
|
-
Compressed files larger than one chunk use **part-based storage**; decrypt via share link or CLI part download.
|
|
178
|
-
|
|
179
|
-
**Decrypt**
|
|
180
|
-
|
|
181
|
-
1. Reads link metadata from `/api/link/:token`, from `--upload-json`, or from `--meta`
|
|
182
|
-
2. Downloads the encrypted file (unless you pass a local encrypted file)
|
|
183
|
-
3. Decrypts locally and writes the original file to disk
|
|
184
|
-
|
|
185
158
|
## Development
|
|
186
159
|
|
|
187
160
|
```bash
|
package/bin/bytifi.js
CHANGED
|
@@ -8,7 +8,10 @@ import { decryptFile } from '../lib/decrypt.js'
|
|
|
8
8
|
import { BytifiApiError, BytifiNetworkError, uploadFile } from '../lib/upload.js'
|
|
9
9
|
|
|
10
10
|
const require = createRequire(import.meta.url)
|
|
11
|
-
const
|
|
11
|
+
const version =
|
|
12
|
+
typeof __BYTIFI_VERSION__ !== 'undefined'
|
|
13
|
+
? __BYTIFI_VERSION__
|
|
14
|
+
: require('../package.json').version
|
|
12
15
|
|
|
13
16
|
function printHelp() {
|
|
14
17
|
process.stdout.write(`Bytifi CLI v${version} — encrypt, upload, and decrypt files
|
package/lib/crypto.js
CHANGED
|
@@ -20,7 +20,14 @@ export function buildChunkIv(noncePrefix, chunkIndex) {
|
|
|
20
20
|
return iv
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export function resolveCompressionMode() {
|
|
23
|
+
export function resolveCompressionMode(originalSize = 0) {
|
|
24
|
+
// Multipart uploads use fixed 32 MB encrypted parts on the server. Gzip can
|
|
25
|
+
// expand incompressible data (ISO, zip, etc.) past that limit and fail part
|
|
26
|
+
// validation, so only gzip-compress direct uploads.
|
|
27
|
+
if (originalSize > MULTIPART_THRESHOLD_BYTES) {
|
|
28
|
+
return 'none'
|
|
29
|
+
}
|
|
30
|
+
|
|
24
31
|
return 'gzip'
|
|
25
32
|
}
|
|
26
33
|
|
|
@@ -63,11 +70,16 @@ export function buildClientEncryptionMeta({
|
|
|
63
70
|
noncePrefix,
|
|
64
71
|
originalSize,
|
|
65
72
|
mimeType,
|
|
73
|
+
compression = 'gzip',
|
|
66
74
|
}) {
|
|
75
|
+
const compressionMeta = compression === 'gzip'
|
|
76
|
+
? { algorithm: 'gzip', scope: 'chunk' }
|
|
77
|
+
: { algorithm: 'none', scope: 'chunk' }
|
|
78
|
+
|
|
67
79
|
return {
|
|
68
|
-
version: 2,
|
|
80
|
+
version: compression === 'gzip' ? 2 : 1,
|
|
69
81
|
algorithm: 'AES-GCM',
|
|
70
|
-
compression:
|
|
82
|
+
compression: compressionMeta,
|
|
71
83
|
chunkSize: plainChunkSize,
|
|
72
84
|
chunkCount,
|
|
73
85
|
noncePrefix: toBase64Url(noncePrefix),
|
|
@@ -100,6 +112,7 @@ export function createEncryptionContext({
|
|
|
100
112
|
if (tokenBytes.length !== 32) throw new Error('Encryption token must be 32 bytes.')
|
|
101
113
|
if (noncePrefix.length !== 8) throw new Error('Nonce prefix must be 8 bytes.')
|
|
102
114
|
|
|
115
|
+
const compression = resolveCompressionMode(originalSize)
|
|
103
116
|
const { chunkCount, encryptedSize } = calculateEncryptedSize(originalSize, plainChunkSize)
|
|
104
117
|
const meta = buildClientEncryptionMeta({
|
|
105
118
|
plainChunkSize,
|
|
@@ -107,6 +120,7 @@ export function createEncryptionContext({
|
|
|
107
120
|
noncePrefix,
|
|
108
121
|
originalSize,
|
|
109
122
|
mimeType,
|
|
123
|
+
compression,
|
|
110
124
|
})
|
|
111
125
|
|
|
112
126
|
return {
|
|
@@ -120,7 +134,7 @@ export function createEncryptionContext({
|
|
|
120
134
|
mimeType,
|
|
121
135
|
originalSize,
|
|
122
136
|
plainChunkSize,
|
|
123
|
-
compression
|
|
137
|
+
compression,
|
|
124
138
|
}
|
|
125
139
|
}
|
|
126
140
|
|
|
@@ -166,7 +180,10 @@ export async function encryptChunkFromFile(fileHandle, chunkIndex, context) {
|
|
|
166
180
|
context.plainChunkSize,
|
|
167
181
|
)
|
|
168
182
|
|
|
169
|
-
let payload =
|
|
183
|
+
let payload = plainChunk
|
|
184
|
+
if (context.compression === 'gzip') {
|
|
185
|
+
payload = await compressPlainChunk(plainChunk)
|
|
186
|
+
}
|
|
170
187
|
|
|
171
188
|
return encryptChunk(payload, context.tokenBytes, context.noncePrefix, chunkIndex)
|
|
172
189
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bytifi",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Official Bytifi CLI — encrypt, upload, and decrypt files from the terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"upload": "node bin/bytifi.js upload",
|
|
18
18
|
"decrypt": "node bin/bytifi.js decrypt",
|
|
19
|
-
"build:bundle": "
|
|
20
|
-
"build:win": "npm run build:bundle && pkg dist/bytifi-bundle.cjs --targets node22-win-x64 --output dist/bytifi.exe --compress GZip"
|
|
19
|
+
"build:bundle": "node scripts/build-bundle.mjs",
|
|
20
|
+
"build:win": "npm run build:bundle && pkg dist/bytifi-bundle.cjs --targets node22-win-x64 --output dist/bytifi.exe --compress GZip --public --public-packages \"*\""
|
|
21
21
|
},
|
|
22
22
|
"repository": {
|
|
23
23
|
"type": "git",
|