bytifi 0.2.2 → 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 -1
- package/lib/crypto.js +22 -5
- package/package.json +1 -1
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
|
|
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
|
}
|