@majikah/majik-file 0.0.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/LICENSE +67 -0
- package/README.md +310 -0
- package/dist/core/compressor/majik-compressor.d.ts +43 -0
- package/dist/core/compressor/majik-compressor.js +84 -0
- package/dist/core/crypto/constants.d.ts +93 -0
- package/dist/core/crypto/constants.js +507 -0
- package/dist/core/crypto/crypto-provider.d.ts +72 -0
- package/dist/core/crypto/crypto-provider.js +115 -0
- package/dist/core/error.d.ts +16 -0
- package/dist/core/error.js +43 -0
- package/dist/core/types.d.ts +223 -0
- package/dist/core/types.js +7 -0
- package/dist/core/utils.d.ts +162 -0
- package/dist/core/utils.js +413 -0
- package/dist/majik-file.d.ts +280 -0
- package/dist/majik-file.js +819 -0
- package/package.json +64 -0
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
// ─── .mjkb Format Constants ───────────────────────────────────────────────────
|
|
2
|
+
/** Current .mjkb binary format version. */
|
|
3
|
+
export const MJKB_VERSION = 1;
|
|
4
|
+
/**
|
|
5
|
+
* .mjkb magic bytes: ASCII "MJKB" (0x4D 0x4A 0x4B 0x42).
|
|
6
|
+
* Present at the very start of every .mjkb file for format identification.
|
|
7
|
+
*/
|
|
8
|
+
export const MJKB_MAGIC = new Uint8Array([0x4d, 0x4a, 0x4b, 0x42]);
|
|
9
|
+
/**
|
|
10
|
+
* Fixed header size before the variable-length payload JSON section:
|
|
11
|
+
* 4 magic "MJKB"
|
|
12
|
+
* 1 version
|
|
13
|
+
* 12 AES-GCM IV
|
|
14
|
+
* 4 payload JSON length (big-endian uint32)
|
|
15
|
+
* = 21 bytes
|
|
16
|
+
*
|
|
17
|
+
* @deprecated Use MJKB_FIXED_HEADER in utils.ts — this constant is kept only
|
|
18
|
+
* for backwards-compatibility with any external code that referenced it.
|
|
19
|
+
*/
|
|
20
|
+
export const MJKB_HEADER_SIZE = 4 + 1 + 12 + 4; // 21 (new variable-payload format)
|
|
21
|
+
// ─── ML-KEM-768 Key Sizes ─────────────────────────────────────────────────────
|
|
22
|
+
/** ML-KEM-768 public key length in bytes. */
|
|
23
|
+
export const ML_KEM_PK_LEN = 1184;
|
|
24
|
+
/** ML-KEM-768 secret key length in bytes. */
|
|
25
|
+
export const ML_KEM_SK_LEN = 2400;
|
|
26
|
+
/** ML-KEM-768 ciphertext length in bytes. */
|
|
27
|
+
export const ML_KEM_CT_LEN = 1088;
|
|
28
|
+
// ─── AES-GCM ─────────────────────────────────────────────────────────────────
|
|
29
|
+
/** AES-256-GCM key length in bytes. */
|
|
30
|
+
export const AES_KEY_LEN = 32;
|
|
31
|
+
/** AES-GCM IV length in bytes. */
|
|
32
|
+
export const IV_LENGTH = 12;
|
|
33
|
+
// ─── Compression ─────────────────────────────────────────────────────────────
|
|
34
|
+
/** Maximum Zstd compression level (highest ratio, slowest). */
|
|
35
|
+
export const ZSTD_MAX_LEVEL = 22;
|
|
36
|
+
// ─── File Size Limits ─────────────────────────────────────────────────────────
|
|
37
|
+
/** Default maximum file size: 100 MB in bytes. Bypassable via CreateOptions. */
|
|
38
|
+
export const MAX_FILE_SIZE_BYTES = 100 * 1024 * 1024;
|
|
39
|
+
// ─── R2 Storage Prefixes ─────────────────────────────────────────────────────
|
|
40
|
+
/**
|
|
41
|
+
* R2 bucket key prefixes.
|
|
42
|
+
*
|
|
43
|
+
* PERMANENT → files/user/<userId>/<fileHash>.mjkb
|
|
44
|
+
* Retained indefinitely. Scoped to the user's sub-directory.
|
|
45
|
+
*
|
|
46
|
+
* TEMPORARY → files/public/<userId>_<fileHash>.mjkb
|
|
47
|
+
* Auto-deleted after ~15 days by the bucket lifecycle policy
|
|
48
|
+
* targeting all objects under the `files/public/` prefix.
|
|
49
|
+
*/
|
|
50
|
+
export const R2_PREFIX = {
|
|
51
|
+
PERMANENT: "files/user",
|
|
52
|
+
TEMPORARY: "files/public",
|
|
53
|
+
/**
|
|
54
|
+
* Encrypted WebP chat images.
|
|
55
|
+
* Structure: images/chats/<conversationId>/<userId>_<fileHash>.mjkb
|
|
56
|
+
*
|
|
57
|
+
* Scoped per conversation so all images in a conversation can be
|
|
58
|
+
* batch-deleted (e.g. when a conversation is removed).
|
|
59
|
+
* These files use temporary storage by default with the standard
|
|
60
|
+
* 15-day R2 lifecycle policy, but can be made permanent if needed.
|
|
61
|
+
*/
|
|
62
|
+
CHAT_IMAGE: "images/chats",
|
|
63
|
+
};
|
|
64
|
+
// ─── MIME Type Sets ───────────────────────────────────────────────────────────
|
|
65
|
+
/**
|
|
66
|
+
* MIME types that can be rendered inline in a modern browser without
|
|
67
|
+
* requiring a download. Used by MajikFile.isInlineViewable.
|
|
68
|
+
*/
|
|
69
|
+
export const INLINE_VIEWABLE_MIME_TYPES = new Set([
|
|
70
|
+
// Images
|
|
71
|
+
"image/png",
|
|
72
|
+
"image/jpeg",
|
|
73
|
+
"image/gif",
|
|
74
|
+
"image/webp",
|
|
75
|
+
"image/avif",
|
|
76
|
+
"image/svg+xml",
|
|
77
|
+
"image/bmp",
|
|
78
|
+
"image/tiff",
|
|
79
|
+
"image/x-icon",
|
|
80
|
+
// Documents
|
|
81
|
+
"application/pdf",
|
|
82
|
+
// Text
|
|
83
|
+
"text/plain",
|
|
84
|
+
"text/html",
|
|
85
|
+
"text/css",
|
|
86
|
+
"text/csv",
|
|
87
|
+
"text/xml",
|
|
88
|
+
"text/markdown",
|
|
89
|
+
// Video
|
|
90
|
+
"video/mp4",
|
|
91
|
+
"video/webm",
|
|
92
|
+
"video/ogg",
|
|
93
|
+
"video/quicktime",
|
|
94
|
+
// Audio
|
|
95
|
+
"audio/mpeg",
|
|
96
|
+
"audio/ogg",
|
|
97
|
+
"audio/wav",
|
|
98
|
+
"audio/webm",
|
|
99
|
+
"audio/aac",
|
|
100
|
+
"audio/flac",
|
|
101
|
+
]);
|
|
102
|
+
/**
|
|
103
|
+
* Comprehensive MIME type registry for popular file formats.
|
|
104
|
+
* Used for validation, labelling, and icon selection in the UI.
|
|
105
|
+
* Organised by category.
|
|
106
|
+
*/
|
|
107
|
+
export const KNOWN_MIME_TYPES = new Set([
|
|
108
|
+
// ── Images ─────────────────────────────────────────────────────────────
|
|
109
|
+
"image/png",
|
|
110
|
+
"image/jpeg",
|
|
111
|
+
"image/gif",
|
|
112
|
+
"image/webp",
|
|
113
|
+
"image/avif",
|
|
114
|
+
"image/svg+xml",
|
|
115
|
+
"image/bmp",
|
|
116
|
+
"image/tiff",
|
|
117
|
+
"image/x-icon",
|
|
118
|
+
"image/heic",
|
|
119
|
+
"image/heif",
|
|
120
|
+
"image/jxl",
|
|
121
|
+
"image/vnd.adobe.photoshop", // .psd
|
|
122
|
+
"image/x-xcf", // GIMP .xcf
|
|
123
|
+
"image/x-raw", // Camera RAW generic
|
|
124
|
+
"image/x-canon-cr2", // Canon RAW
|
|
125
|
+
"image/x-nikon-nef", // Nikon RAW
|
|
126
|
+
"image/x-sony-arw", // Sony RAW
|
|
127
|
+
// ── Video ───────────────────────────────────────────────────────────────
|
|
128
|
+
"video/mp4",
|
|
129
|
+
"video/webm",
|
|
130
|
+
"video/ogg",
|
|
131
|
+
"video/quicktime", // .mov
|
|
132
|
+
"video/x-msvideo", // .avi
|
|
133
|
+
"video/x-matroska", // .mkv
|
|
134
|
+
"video/x-flv", // .flv
|
|
135
|
+
"video/3gpp", // .3gp
|
|
136
|
+
"video/3gpp2", // .3g2
|
|
137
|
+
"video/mpeg", // .mpeg .mpg
|
|
138
|
+
"video/x-ms-wmv", // .wmv
|
|
139
|
+
"video/mp2t", // .ts (MPEG transport stream)
|
|
140
|
+
"video/x-m4v", // .m4v
|
|
141
|
+
// ── Audio ───────────────────────────────────────────────────────────────
|
|
142
|
+
"audio/mpeg", // .mp3
|
|
143
|
+
"audio/ogg", // .ogg
|
|
144
|
+
"audio/wav", // .wav
|
|
145
|
+
"audio/webm",
|
|
146
|
+
"audio/aac", // .aac
|
|
147
|
+
"audio/flac", // .flac
|
|
148
|
+
"audio/x-m4a", // .m4a
|
|
149
|
+
"audio/midi", // .mid .midi
|
|
150
|
+
"audio/x-midi",
|
|
151
|
+
"audio/aiff", // .aiff .aif
|
|
152
|
+
"audio/x-aiff",
|
|
153
|
+
"audio/opus", // .opus
|
|
154
|
+
"audio/amr", // .amr
|
|
155
|
+
"audio/mp4", // .m4a (alternate)
|
|
156
|
+
// ── Documents ───────────────────────────────────────────────────────────
|
|
157
|
+
"application/pdf", // .pdf
|
|
158
|
+
"application/msword", // .doc
|
|
159
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", // .docx
|
|
160
|
+
"application/vnd.ms-excel", // .xls
|
|
161
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // .xlsx
|
|
162
|
+
"application/vnd.ms-powerpoint", // .ppt
|
|
163
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation", // .pptx
|
|
164
|
+
"application/vnd.oasis.opendocument.text", // .odt
|
|
165
|
+
"application/vnd.oasis.opendocument.spreadsheet", // .ods
|
|
166
|
+
"application/vnd.oasis.opendocument.presentation", // .odp
|
|
167
|
+
"application/rtf", // .rtf
|
|
168
|
+
"text/rtf",
|
|
169
|
+
// ── Text / Code ──────────────────────────────────────────────────────────
|
|
170
|
+
"text/plain", // .txt
|
|
171
|
+
"text/html", // .html .htm
|
|
172
|
+
"text/css", // .css
|
|
173
|
+
"text/csv", // .csv
|
|
174
|
+
"text/xml", // .xml
|
|
175
|
+
"text/markdown", // .md .markdown
|
|
176
|
+
"text/javascript", // .js .mjs
|
|
177
|
+
"application/javascript",
|
|
178
|
+
"application/typescript", // .ts
|
|
179
|
+
"application/json", // .json
|
|
180
|
+
"application/xml", // .xml (alternate)
|
|
181
|
+
"application/yaml", // .yaml .yml
|
|
182
|
+
"text/yaml",
|
|
183
|
+
"application/toml", // .toml
|
|
184
|
+
"application/graphql", // .graphql
|
|
185
|
+
"text/x-python", // .py
|
|
186
|
+
"text/x-java-source", // .java
|
|
187
|
+
"text/x-c", // .c
|
|
188
|
+
"text/x-c++", // .cpp .cxx
|
|
189
|
+
"text/x-csharp", // .cs
|
|
190
|
+
"text/x-go", // .go
|
|
191
|
+
"text/x-rust", // .rs
|
|
192
|
+
"text/x-swift", // .swift
|
|
193
|
+
"text/x-kotlin", // .kt
|
|
194
|
+
"text/x-ruby", // .rb
|
|
195
|
+
"text/x-php", // .php
|
|
196
|
+
"text/x-sh", // .sh .bash
|
|
197
|
+
"text/x-powershell", // .ps1
|
|
198
|
+
"application/x-httpd-php", // .php (alternate)
|
|
199
|
+
"application/x-sql", // .sql
|
|
200
|
+
"text/x-lua", // .lua
|
|
201
|
+
// ── Archives & Compressed ────────────────────────────────────────────────
|
|
202
|
+
"application/zip", // .zip
|
|
203
|
+
"application/x-rar-compressed", // .rar
|
|
204
|
+
"application/x-rar",
|
|
205
|
+
"application/x-7z-compressed", // .7z
|
|
206
|
+
"application/x-tar", // .tar
|
|
207
|
+
"application/gzip", // .gz
|
|
208
|
+
"application/x-gzip",
|
|
209
|
+
"application/x-bzip2", // .bz2
|
|
210
|
+
"application/x-xz", // .xz
|
|
211
|
+
"application/x-lzip", // .lz
|
|
212
|
+
"application/x-zstd", // .zst
|
|
213
|
+
"application/vnd.rar",
|
|
214
|
+
// ── Executables & Installers ─────────────────────────────────────────────
|
|
215
|
+
"application/x-msdownload", // .exe .dll
|
|
216
|
+
"application/vnd.microsoft.portable-executable", // .exe (alternate)
|
|
217
|
+
"application/x-msi", // .msi
|
|
218
|
+
"application/x-apple-diskimage", // .dmg
|
|
219
|
+
"application/x-debian-package", // .deb
|
|
220
|
+
"application/x-rpm", // .rpm
|
|
221
|
+
"application/x-sh", // .sh
|
|
222
|
+
"application/x-executable",
|
|
223
|
+
"application/octet-stream", // generic binary / unknown
|
|
224
|
+
// ── Fonts ────────────────────────────────────────────────────────────────
|
|
225
|
+
"font/ttf", // .ttf
|
|
226
|
+
"font/otf", // .otf
|
|
227
|
+
"font/woff", // .woff
|
|
228
|
+
"font/woff2", // .woff2
|
|
229
|
+
"application/font-woff",
|
|
230
|
+
"application/vnd.ms-fontobject", // .eot
|
|
231
|
+
// ── 3D & Design ──────────────────────────────────────────────────────────
|
|
232
|
+
"model/gltf+json", // .gltf
|
|
233
|
+
"model/gltf-binary", // .glb
|
|
234
|
+
"model/obj", // .obj
|
|
235
|
+
"model/stl", // .stl
|
|
236
|
+
"application/x-blender", // .blend (Blender)
|
|
237
|
+
"application/vnd.ms-3mfdocument", // .3mf (3D printing)
|
|
238
|
+
"application/x-fbx", // .fbx (Autodesk)
|
|
239
|
+
// ── Adobe Creative Suite ─────────────────────────────────────────────────
|
|
240
|
+
"image/vnd.adobe.photoshop", // .psd (Photoshop)
|
|
241
|
+
"application/postscript", // .ai (Illustrator) .eps .ps
|
|
242
|
+
"application/x-indesign", // .indd (InDesign)
|
|
243
|
+
"video/x-adobe-premiere", // .prproj (Premiere)
|
|
244
|
+
"application/x-adobe-after-effects", // .aep (After Effects)
|
|
245
|
+
"application/x-xd", // .xd (Adobe XD)
|
|
246
|
+
// ── Figma / Sketch / Design Tools ────────────────────────────────────────
|
|
247
|
+
"application/x-figma", // .fig
|
|
248
|
+
"application/x-sketch", // .sketch
|
|
249
|
+
"application/x-affinity-designer", // Affinity Designer
|
|
250
|
+
"application/x-affinity-photo", // Affinity Photo
|
|
251
|
+
// ── VS Code / IDEs / Config ──────────────────────────────────────────────
|
|
252
|
+
"application/json", // .json (settings, package.json, tsconfig)
|
|
253
|
+
"application/x-vsix", // .vsix (VS Code extension)
|
|
254
|
+
"application/x-ipynb+json", // .ipynb (Jupyter notebook)
|
|
255
|
+
"text/x-dockerfile", // Dockerfile
|
|
256
|
+
"application/x-env", // .env
|
|
257
|
+
// ── Database ─────────────────────────────────────────────────────────────
|
|
258
|
+
"application/x-sqlite3", // .sqlite .db
|
|
259
|
+
"application/vnd.sqlite3",
|
|
260
|
+
// ── eBook ────────────────────────────────────────────────────────────────
|
|
261
|
+
"application/epub+zip", // .epub
|
|
262
|
+
"application/x-mobipocket-ebook", // .mobi
|
|
263
|
+
"application/vnd.amazon.ebook", // .azw
|
|
264
|
+
// ── Productivity / Other ─────────────────────────────────────────────────
|
|
265
|
+
"application/x-abiword", // .abw (AbiWord)
|
|
266
|
+
"application/vnd.visio", // .vsd (Visio)
|
|
267
|
+
"application/x-iwork-pages-sffpages", // .pages (Apple Pages)
|
|
268
|
+
"application/x-iwork-numbers-sffnumbers", // .numbers (Apple Numbers)
|
|
269
|
+
"application/x-iwork-keynote-sffkey", // .key (Apple Keynote)
|
|
270
|
+
// ── Cryptographic / Certificates ─────────────────────────────────────────
|
|
271
|
+
"application/x-pem-file", // .pem
|
|
272
|
+
"application/x-pkcs12", // .pfx .p12
|
|
273
|
+
"application/pkix-cert", // .cer .crt
|
|
274
|
+
"application/x-x509-ca-cert",
|
|
275
|
+
]);
|
|
276
|
+
/**
|
|
277
|
+
* Map from common file extension → canonical MIME type.
|
|
278
|
+
* Use this when a file is uploaded without a MIME type and you need to infer
|
|
279
|
+
* one from the filename extension.
|
|
280
|
+
*/
|
|
281
|
+
export const EXTENSION_TO_MIME = {
|
|
282
|
+
// Images
|
|
283
|
+
png: "image/png",
|
|
284
|
+
jpg: "image/jpeg",
|
|
285
|
+
jpeg: "image/jpeg",
|
|
286
|
+
gif: "image/gif",
|
|
287
|
+
webp: "image/webp",
|
|
288
|
+
avif: "image/avif",
|
|
289
|
+
svg: "image/svg+xml",
|
|
290
|
+
bmp: "image/bmp",
|
|
291
|
+
tiff: "image/tiff",
|
|
292
|
+
tif: "image/tiff",
|
|
293
|
+
ico: "image/x-icon",
|
|
294
|
+
heic: "image/heic",
|
|
295
|
+
heif: "image/heif",
|
|
296
|
+
jxl: "image/jxl",
|
|
297
|
+
psd: "image/vnd.adobe.photoshop",
|
|
298
|
+
xcf: "image/x-xcf",
|
|
299
|
+
cr2: "image/x-canon-cr2",
|
|
300
|
+
nef: "image/x-nikon-nef",
|
|
301
|
+
arw: "image/x-sony-arw",
|
|
302
|
+
// Video
|
|
303
|
+
mp4: "video/mp4",
|
|
304
|
+
webm: "video/webm",
|
|
305
|
+
ogg: "video/ogg",
|
|
306
|
+
mov: "video/quicktime",
|
|
307
|
+
avi: "video/x-msvideo",
|
|
308
|
+
mkv: "video/x-matroska",
|
|
309
|
+
flv: "video/x-flv",
|
|
310
|
+
"3gp": "video/3gpp",
|
|
311
|
+
mpeg: "video/mpeg",
|
|
312
|
+
mpg: "video/mpeg",
|
|
313
|
+
wmv: "video/x-ms-wmv",
|
|
314
|
+
m4v: "video/x-m4v",
|
|
315
|
+
// Audio
|
|
316
|
+
mp3: "audio/mpeg",
|
|
317
|
+
wav: "audio/wav",
|
|
318
|
+
aac: "audio/aac",
|
|
319
|
+
flac: "audio/flac",
|
|
320
|
+
m4a: "audio/x-m4a",
|
|
321
|
+
mid: "audio/midi",
|
|
322
|
+
midi: "audio/midi",
|
|
323
|
+
aiff: "audio/aiff",
|
|
324
|
+
aif: "audio/aiff",
|
|
325
|
+
opus: "audio/opus",
|
|
326
|
+
amr: "audio/amr",
|
|
327
|
+
// Documents
|
|
328
|
+
pdf: "application/pdf",
|
|
329
|
+
doc: "application/msword",
|
|
330
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
331
|
+
xls: "application/vnd.ms-excel",
|
|
332
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
333
|
+
ppt: "application/vnd.ms-powerpoint",
|
|
334
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
335
|
+
odt: "application/vnd.oasis.opendocument.text",
|
|
336
|
+
ods: "application/vnd.oasis.opendocument.spreadsheet",
|
|
337
|
+
odp: "application/vnd.oasis.opendocument.presentation",
|
|
338
|
+
rtf: "application/rtf",
|
|
339
|
+
// Text / Code
|
|
340
|
+
txt: "text/plain",
|
|
341
|
+
html: "text/html",
|
|
342
|
+
htm: "text/html",
|
|
343
|
+
css: "text/css",
|
|
344
|
+
csv: "text/csv",
|
|
345
|
+
xml: "text/xml",
|
|
346
|
+
md: "text/markdown",
|
|
347
|
+
markdown: "text/markdown",
|
|
348
|
+
js: "text/javascript",
|
|
349
|
+
mjs: "text/javascript",
|
|
350
|
+
ts: "application/typescript",
|
|
351
|
+
json: "application/json",
|
|
352
|
+
yaml: "text/yaml",
|
|
353
|
+
yml: "text/yaml",
|
|
354
|
+
toml: "application/toml",
|
|
355
|
+
graphql: "application/graphql",
|
|
356
|
+
gql: "application/graphql",
|
|
357
|
+
py: "text/x-python",
|
|
358
|
+
java: "text/x-java-source",
|
|
359
|
+
c: "text/x-c",
|
|
360
|
+
cpp: "text/x-c++",
|
|
361
|
+
cxx: "text/x-c++",
|
|
362
|
+
cs: "text/x-csharp",
|
|
363
|
+
go: "text/x-go",
|
|
364
|
+
rs: "text/x-rust",
|
|
365
|
+
swift: "text/x-swift",
|
|
366
|
+
kt: "text/x-kotlin",
|
|
367
|
+
rb: "text/x-ruby",
|
|
368
|
+
php: "text/x-php",
|
|
369
|
+
sh: "text/x-sh",
|
|
370
|
+
bash: "text/x-sh",
|
|
371
|
+
ps1: "text/x-powershell",
|
|
372
|
+
sql: "application/x-sql",
|
|
373
|
+
lua: "text/x-lua",
|
|
374
|
+
// Archives
|
|
375
|
+
zip: "application/zip",
|
|
376
|
+
rar: "application/x-rar-compressed",
|
|
377
|
+
"7z": "application/x-7z-compressed",
|
|
378
|
+
tar: "application/x-tar",
|
|
379
|
+
gz: "application/gzip",
|
|
380
|
+
bz2: "application/x-bzip2",
|
|
381
|
+
xz: "application/x-xz",
|
|
382
|
+
zst: "application/x-zstd",
|
|
383
|
+
// Executables
|
|
384
|
+
exe: "application/x-msdownload",
|
|
385
|
+
dll: "application/x-msdownload",
|
|
386
|
+
msi: "application/x-msi",
|
|
387
|
+
dmg: "application/x-apple-diskimage",
|
|
388
|
+
deb: "application/x-debian-package",
|
|
389
|
+
rpm: "application/x-rpm",
|
|
390
|
+
// Fonts
|
|
391
|
+
ttf: "font/ttf",
|
|
392
|
+
otf: "font/otf",
|
|
393
|
+
woff: "font/woff",
|
|
394
|
+
woff2: "font/woff2",
|
|
395
|
+
eot: "application/vnd.ms-fontobject",
|
|
396
|
+
// 3D & Design
|
|
397
|
+
gltf: "model/gltf+json",
|
|
398
|
+
glb: "model/gltf-binary",
|
|
399
|
+
obj: "model/obj",
|
|
400
|
+
stl: "model/stl",
|
|
401
|
+
blend: "application/x-blender",
|
|
402
|
+
fbx: "application/x-fbx",
|
|
403
|
+
// Adobe
|
|
404
|
+
ai: "application/postscript",
|
|
405
|
+
eps: "application/postscript",
|
|
406
|
+
indd: "application/x-indesign",
|
|
407
|
+
xd: "application/x-xd",
|
|
408
|
+
// Design tools
|
|
409
|
+
fig: "application/x-figma",
|
|
410
|
+
sketch: "application/x-sketch",
|
|
411
|
+
// VS Code / IDE
|
|
412
|
+
vsix: "application/x-vsix",
|
|
413
|
+
ipynb: "application/x-ipynb+json",
|
|
414
|
+
// Database
|
|
415
|
+
sqlite: "application/x-sqlite3",
|
|
416
|
+
db: "application/x-sqlite3",
|
|
417
|
+
// eBook
|
|
418
|
+
epub: "application/epub+zip",
|
|
419
|
+
mobi: "application/x-mobipocket-ebook",
|
|
420
|
+
// Apple productivity
|
|
421
|
+
pages: "application/x-iwork-pages-sffpages",
|
|
422
|
+
numbers: "application/x-iwork-numbers-sffnumbers",
|
|
423
|
+
key: "application/x-iwork-keynote-sffkey",
|
|
424
|
+
// Crypto / Certs
|
|
425
|
+
pem: "application/x-pem-file",
|
|
426
|
+
pfx: "application/x-pkcs12",
|
|
427
|
+
p12: "application/x-pkcs12",
|
|
428
|
+
cer: "application/pkix-cert",
|
|
429
|
+
crt: "application/pkix-cert",
|
|
430
|
+
};
|
|
431
|
+
// ─── File-level Constants ────────────────────────────────────────────────────
|
|
432
|
+
/**
|
|
433
|
+
* Maximum number of recipients for a group-encrypted file.
|
|
434
|
+
* Prevents pathological payload sizes (each recipient adds ~1.5 KB to the
|
|
435
|
+
* .mjkb binary: 1088-byte ML-KEM CT + 32-byte encrypted AES key in base64).
|
|
436
|
+
*/
|
|
437
|
+
export const MAX_RECIPIENTS = 100;
|
|
438
|
+
/**
|
|
439
|
+
* MIME type prefixes and exact types that are already compressed at the
|
|
440
|
+
* codec level. Applying Zstd to these yields negligible savings and
|
|
441
|
+
* measurable CPU/memory overhead — especially on mobile.
|
|
442
|
+
*/
|
|
443
|
+
export const INCOMPRESSIBLE_MIME_TYPES = new Set([
|
|
444
|
+
// Pre-compressed image codecs
|
|
445
|
+
"image/jpeg",
|
|
446
|
+
"image/jpg",
|
|
447
|
+
"image/webp",
|
|
448
|
+
"image/avif",
|
|
449
|
+
"image/heic",
|
|
450
|
+
"image/heif",
|
|
451
|
+
"image/jxl",
|
|
452
|
+
// All video (codec-level compression throughout)
|
|
453
|
+
"video/mp4",
|
|
454
|
+
"video/webm",
|
|
455
|
+
"video/ogg",
|
|
456
|
+
"video/quicktime",
|
|
457
|
+
"video/x-msvideo",
|
|
458
|
+
"video/x-matroska",
|
|
459
|
+
"video/x-flv",
|
|
460
|
+
"video/3gpp",
|
|
461
|
+
"video/3gpp2",
|
|
462
|
+
"video/mpeg",
|
|
463
|
+
"video/x-ms-wmv",
|
|
464
|
+
"video/mp2t",
|
|
465
|
+
"video/x-m4v",
|
|
466
|
+
// Lossy/pre-compressed audio
|
|
467
|
+
"audio/mpeg", // mp3
|
|
468
|
+
"audio/aac",
|
|
469
|
+
"audio/ogg",
|
|
470
|
+
"audio/opus",
|
|
471
|
+
"audio/webm",
|
|
472
|
+
"audio/x-m4a",
|
|
473
|
+
"audio/mp4",
|
|
474
|
+
"audio/amr",
|
|
475
|
+
// Archives (already compressed)
|
|
476
|
+
"application/zip",
|
|
477
|
+
"application/gzip",
|
|
478
|
+
"application/x-gzip",
|
|
479
|
+
"application/x-rar-compressed",
|
|
480
|
+
"application/x-rar",
|
|
481
|
+
"application/vnd.rar",
|
|
482
|
+
"application/x-7z-compressed",
|
|
483
|
+
"application/x-bzip2",
|
|
484
|
+
"application/x-xz",
|
|
485
|
+
"application/x-lzip",
|
|
486
|
+
"application/x-zstd",
|
|
487
|
+
// Pre-compressed document formats
|
|
488
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", // .docx
|
|
489
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // .xlsx
|
|
490
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation", // .pptx
|
|
491
|
+
"application/epub+zip",
|
|
492
|
+
]);
|
|
493
|
+
/**
|
|
494
|
+
* Image MIME types that can be re-encoded to WebP in the browser.
|
|
495
|
+
* Used by the chat attachment path to normalise all images to WebP before
|
|
496
|
+
* encryption, reducing payload size for non-WebP sources.
|
|
497
|
+
*/
|
|
498
|
+
export const WEBP_CONVERTIBLE_IMAGE_TYPES = new Set([
|
|
499
|
+
"image/png",
|
|
500
|
+
"image/jpeg",
|
|
501
|
+
"image/jpg",
|
|
502
|
+
"image/gif",
|
|
503
|
+
"image/bmp",
|
|
504
|
+
"image/tiff",
|
|
505
|
+
"image/x-icon",
|
|
506
|
+
"image/svg+xml",
|
|
507
|
+
]);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* crypto-provider.ts
|
|
3
|
+
*
|
|
4
|
+
* Encryption engine for MajikFile.
|
|
5
|
+
* Provides AES-256-GCM and ML-KEM-768 (FIPS-203) primitives.
|
|
6
|
+
*
|
|
7
|
+
* All operations are synchronous except where noted.
|
|
8
|
+
* Random bytes are sourced from crypto.getRandomValues().
|
|
9
|
+
*/
|
|
10
|
+
import { IV_LENGTH, AES_KEY_LEN } from "./constants";
|
|
11
|
+
export { IV_LENGTH, AES_KEY_LEN };
|
|
12
|
+
/**
|
|
13
|
+
* Generate cryptographically random bytes using the Web Crypto API.
|
|
14
|
+
* @param len Number of bytes to generate.
|
|
15
|
+
*/
|
|
16
|
+
export declare function generateRandomBytes(len: number): Uint8Array;
|
|
17
|
+
/**
|
|
18
|
+
* Encrypt plaintext bytes with AES-256-GCM.
|
|
19
|
+
*
|
|
20
|
+
* @param keyBytes 32-byte AES key.
|
|
21
|
+
* @param iv 12-byte IV / nonce.
|
|
22
|
+
* @param plaintext Arbitrary-length plaintext.
|
|
23
|
+
* @returns Ciphertext with 16-byte GCM authentication tag appended.
|
|
24
|
+
*/
|
|
25
|
+
export declare function aesGcmEncrypt(keyBytes: Uint8Array, iv: Uint8Array, plaintext: Uint8Array): Uint8Array;
|
|
26
|
+
/**
|
|
27
|
+
* Decrypt AES-256-GCM ciphertext.
|
|
28
|
+
*
|
|
29
|
+
* @param keyBytes 32-byte AES key.
|
|
30
|
+
* @param iv 12-byte IV / nonce.
|
|
31
|
+
* @param ciphertext Ciphertext with 16-byte GCM authentication tag.
|
|
32
|
+
* @returns Decrypted plaintext, or null if authentication fails.
|
|
33
|
+
*/
|
|
34
|
+
export declare function aesGcmDecrypt(keyBytes: Uint8Array, iv: Uint8Array, ciphertext: Uint8Array): Uint8Array | null;
|
|
35
|
+
/**
|
|
36
|
+
* ML-KEM-768 key encapsulation.
|
|
37
|
+
*
|
|
38
|
+
* The sender calls this with the recipient's public key.
|
|
39
|
+
* Returns a 32-byte shared secret (used as the AES-256-GCM key)
|
|
40
|
+
* and a 1088-byte ciphertext that is stored in the .mjkb binary.
|
|
41
|
+
*
|
|
42
|
+
* Only the holder of the corresponding secret key can recover the
|
|
43
|
+
* shared secret via mlKemDecapsulate().
|
|
44
|
+
*
|
|
45
|
+
* @param recipientPublicKey ML-KEM-768 public key (1184 bytes).
|
|
46
|
+
* @returns { sharedSecret: 32 bytes, cipherText: 1088 bytes }
|
|
47
|
+
*/
|
|
48
|
+
export declare function mlKemEncapsulate(recipientPublicKey: Uint8Array): {
|
|
49
|
+
sharedSecret: Uint8Array;
|
|
50
|
+
cipherText: Uint8Array;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* ML-KEM-768 key decapsulation.
|
|
54
|
+
*
|
|
55
|
+
* IMPORTANT: ML-KEM decapsulation NEVER throws on a wrong key — it returns
|
|
56
|
+
* a different (useless) shared secret. The AES-GCM authentication tag will
|
|
57
|
+
* catch this, causing aesGcmDecrypt() to return null.
|
|
58
|
+
*
|
|
59
|
+
* @param cipherText ML-KEM-768 ciphertext from encapsulation (1088 bytes).
|
|
60
|
+
* @param recipientSecretKey ML-KEM-768 secret key (2400 bytes).
|
|
61
|
+
* @returns 32-byte shared secret.
|
|
62
|
+
*/
|
|
63
|
+
export declare function mlKemDecapsulate(cipherText: Uint8Array, recipientSecretKey: Uint8Array): Uint8Array;
|
|
64
|
+
/**
|
|
65
|
+
* Generate a random ML-KEM-768 keypair.
|
|
66
|
+
* Intended for testing only.
|
|
67
|
+
* Production identities must use deriveMlKemKeypairFromSeed() from a BIP-39 mnemonic.
|
|
68
|
+
*/
|
|
69
|
+
export declare function generateMlKemKeypair(): {
|
|
70
|
+
publicKey: Uint8Array;
|
|
71
|
+
secretKey: Uint8Array;
|
|
72
|
+
};
|