@brftech/filex-core 0.6.0 → 0.7.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/dist/{ArchiveViewer-EGgNqLPE.js → ArchiveViewer-Qi4L2jj9.js} +2 -2
- package/dist/{ArchiveViewer-EGgNqLPE.js.map → ArchiveViewer-Qi4L2jj9.js.map} +1 -1
- package/dist/{CsvViewer-BvriJ42M.js → CsvViewer-IOIrJDsJ.js} +2 -2
- package/dist/{CsvViewer-BvriJ42M.js.map → CsvViewer-IOIrJDsJ.js.map} +1 -1
- package/dist/{DrawioViewer-B_bSPsWX.js → DrawioViewer-D0KtUQBO.js} +2 -2
- package/dist/{DrawioViewer-B_bSPsWX.js.map → DrawioViewer-D0KtUQBO.js.map} +1 -1
- package/dist/{EpubViewer-hl68h4gG.js → EpubViewer-DJOXiOi4.js} +2 -2
- package/dist/{EpubViewer-hl68h4gG.js.map → EpubViewer-DJOXiOi4.js.map} +1 -1
- package/dist/{IpynbViewer-lhwOjXK7.js → IpynbViewer-D16jXVJc.js} +2 -2
- package/dist/{IpynbViewer-lhwOjXK7.js.map → IpynbViewer-D16jXVJc.js.map} +1 -1
- package/dist/{MermaidViewer-H2Z6AYXg.js → MermaidViewer-BnSaVg1L.js} +2 -2
- package/dist/{MermaidViewer-H2Z6AYXg.js.map → MermaidViewer-BnSaVg1L.js.map} +1 -1
- package/dist/{PsdViewer-Bsk-11yH.js → PsdViewer-BUerXaQA.js} +2 -2
- package/dist/{PsdViewer-Bsk-11yH.js.map → PsdViewer-BUerXaQA.js.map} +1 -1
- package/dist/{TiffViewer-D-j9vycG.js → TiffViewer-D0Qn3IV-.js} +2 -2
- package/dist/{TiffViewer-D-j9vycG.js.map → TiffViewer-D0Qn3IV-.js.map} +1 -1
- package/dist/{Viewer3D-Bcr70rTe.js → Viewer3D-BtRK-k1B.js} +2 -2
- package/dist/{Viewer3D-Bcr70rTe.js.map → Viewer3D-BtRK-k1B.js.map} +1 -1
- package/dist/filex-core.js +66 -50
- package/dist/filex-core.umd.cjs +35 -35
- package/dist/filex-core.umd.cjs.map +1 -1
- package/dist/index-CGNE1bSv.js +11802 -0
- package/dist/index-CGNE1bSv.js.map +1 -0
- package/dist/index.d.ts +184 -0
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/FileExplorer.vue +416 -15
- package/src/components/EncryptedFolderModal.vue +125 -0
- package/src/components/GalleryView.vue +1 -0
- package/src/components/GridView.vue +1 -0
- package/src/components/ListView.vue +1 -0
- package/src/components/SecondaryPane.vue +72 -78
- package/src/components/Toolbar.vue +112 -3
- package/src/composables/useFileApi.ts +7 -0
- package/src/composables/useKeyboardShortcuts.ts +6 -0
- package/src/composables/useTabs.ts +11 -2
- package/src/index.ts +21 -0
- package/src/lib/e2ecrypto.ts +299 -0
- package/src/locales/en.ts +34 -0
- package/src/locales/tr.ts +34 -0
- package/src/modals/NewFolderModal.vue +18 -0
- package/src/modals/PreviewModal.vue +7 -2
- package/src/styles/base.css +126 -1
- package/src/styles/variables.css +2 -2
- package/src/types/FileNode.ts +3 -0
- package/dist/index-C_ZSnk_I.js +0 -11109
- package/dist/index-C_ZSnk_I.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -43,6 +43,18 @@ declare type __VLS_Props_11 = {
|
|
|
43
43
|
virtualRows?: () => FileNode[];
|
|
44
44
|
/** Active-panel highlight (keyboard target). */
|
|
45
45
|
active?: boolean;
|
|
46
|
+
/** ui-fix — the pane renders the SAME view components as the main
|
|
47
|
+
* panel (list/grid/gallery) instead of its own flat list. */
|
|
48
|
+
viewMode?: ViewMode;
|
|
49
|
+
/** ui-fix — authenticated thumb resolver, forwarded to grid/gallery. */
|
|
50
|
+
thumbSrc?: (n: FileNode) => string | null;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
declare type __VLS_Props_12 = {
|
|
54
|
+
open: boolean;
|
|
55
|
+
locale: LocaleCode;
|
|
56
|
+
/** True while the parent is creating the folder + uploading the marker. */
|
|
57
|
+
busy?: boolean;
|
|
46
58
|
};
|
|
47
59
|
|
|
48
60
|
declare type __VLS_Props_2 = {
|
|
@@ -63,6 +75,7 @@ declare type __VLS_Props_2 = {
|
|
|
63
75
|
pdfSaveUrl?: string | null;
|
|
64
76
|
/** Standalone full-screen viewer route — `?path=…&storage=…&type=…`. */
|
|
65
77
|
viewerBaseUrl?: string | null;
|
|
78
|
+
newTabEnabled?: boolean;
|
|
66
79
|
/** Drop the dialog chrome (backdrop tint, header bar, footer actions)
|
|
67
80
|
* so the viewer fills the full viewport. Used by the standalone
|
|
68
81
|
* /files/edit route where the browser tab IS the container — a
|
|
@@ -249,16 +262,122 @@ declare interface ContextAction {
|
|
|
249
262
|
divider?: boolean;
|
|
250
263
|
}
|
|
251
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Tiny per-explorer key ring: encrypted-folder root (wire path) → KEK.
|
|
267
|
+
* Lives ONLY in memory — "Kilitle" drops the entry, a reload drops all.
|
|
268
|
+
*/
|
|
269
|
+
export declare function createKeyRing(): {
|
|
270
|
+
get(root: string): CryptoKey | undefined;
|
|
271
|
+
set(root: string, kek: CryptoKey): void;
|
|
272
|
+
/** Drop one folder's key ("Kilitle"). */
|
|
273
|
+
lock(root: string): void;
|
|
274
|
+
has(root: string): boolean;
|
|
275
|
+
clear(): void;
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
/** Create a fresh folder marker for `password` (also returns the derived KEK). */
|
|
279
|
+
export declare function createMarker(password: string, iterations?: number): Promise<{
|
|
280
|
+
marker: E2eMarker;
|
|
281
|
+
kek: CryptoKey;
|
|
282
|
+
}>;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Decrypt a 'filexe2e' blob with the folder KEK. Throws E2eDecryptError on
|
|
286
|
+
* a wrong key / tampered data, and a plain Error when the header is not an
|
|
287
|
+
* e2e file at all.
|
|
288
|
+
*/
|
|
289
|
+
export declare function decryptFile(kek: CryptoKey, data: ArrayBuffer): Promise<ArrayBuffer>;
|
|
290
|
+
|
|
252
291
|
export declare const DEFAULT_THEME_ID = "default";
|
|
253
292
|
|
|
254
293
|
declare type Density = 'comfortable' | 'compact';
|
|
255
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Derive the folder KEK from a password. Returns a NON-extractable
|
|
297
|
+
* AES-256-GCM CryptoKey — it can encrypt/decrypt but never be exported,
|
|
298
|
+
* so even a same-origin script can't read the raw key material back.
|
|
299
|
+
*/
|
|
300
|
+
export declare function deriveKek(password: string, salt: Uint8Array, iterations: number): Promise<CryptoKey>;
|
|
301
|
+
|
|
302
|
+
export declare const E2E_DEFAULT_ITERATIONS = 600000;
|
|
303
|
+
|
|
304
|
+
export declare const E2E_MAGIC = "filexe2e";
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* e2ecrypto — client-side crypto for E2E-encrypted folders (wiring:e2).
|
|
308
|
+
*
|
|
309
|
+
* WebCrypto ONLY — zero dependencies. Design doc: docs/E2E-ENCRYPTION.md.
|
|
310
|
+
*
|
|
311
|
+
* Scheme (v1):
|
|
312
|
+
* folder password ─PBKDF2-SHA256(600k iter, per-folder 16B salt)─▶ KEK (AES-256-GCM)
|
|
313
|
+
* per-file random 32B DEK (AES-256-GCM) encrypts the content one-shot;
|
|
314
|
+
* the DEK is wrapped with the KEK and stored in the file's own header.
|
|
315
|
+
*
|
|
316
|
+
* File layout ('filexe2e' magic, fixed 97-byte header):
|
|
317
|
+
* [0..8) magic "filexe2e"
|
|
318
|
+
* [8] version 0x01
|
|
319
|
+
* [9..21) wrapIV (12B) — GCM IV of the DEK wrap
|
|
320
|
+
* [21..69) wrappedDEK (48B = 32B DEK + 16B GCM tag)
|
|
321
|
+
* [69..81) dataIV (12B) — GCM IV of the content
|
|
322
|
+
* [81..97) reserved (zeros; v2 chunking/metadata)
|
|
323
|
+
* [97..) ciphertext (content + 16B GCM tag)
|
|
324
|
+
*
|
|
325
|
+
* Folder marker `.filex-e2e.json` at the encrypted-folder root:
|
|
326
|
+
* { v:1, salt:<b64 16B>, iter:600000, verify:<b64 12B IV || GCM('filex-e2e-verify-v1')> }
|
|
327
|
+
*
|
|
328
|
+
* The KEK NEVER leaves memory — no storage of any kind. Password loss is
|
|
329
|
+
* data loss by design (no recovery path exists anywhere).
|
|
330
|
+
*/
|
|
331
|
+
export declare const E2E_MARKER_NAME = ".filex-e2e.json";
|
|
332
|
+
|
|
333
|
+
/** MVP single-shot in-memory ceiling — larger uploads are refused with a warning. */
|
|
334
|
+
export declare const E2E_MAX_FILE_BYTES: number;
|
|
335
|
+
|
|
336
|
+
export declare const E2E_MIN_PASSWORD_LEN = 8;
|
|
337
|
+
|
|
338
|
+
export declare const E2E_VERSION = 1;
|
|
339
|
+
|
|
340
|
+
/** Thrown on wrong password / corrupted ciphertext (GCM tag mismatch). */
|
|
341
|
+
export declare class E2eDecryptError extends Error {
|
|
342
|
+
constructor(msg?: string);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export declare type E2eKeyRing = ReturnType<typeof createKeyRing>;
|
|
346
|
+
|
|
347
|
+
export declare interface E2eMarker {
|
|
348
|
+
v: number;
|
|
349
|
+
salt: string;
|
|
350
|
+
iter: number;
|
|
351
|
+
verify: string;
|
|
352
|
+
}
|
|
353
|
+
|
|
256
354
|
/** Current combo for an action ('' = unbound). */
|
|
257
355
|
export declare function effectiveCombo(id: string): string;
|
|
258
356
|
|
|
259
357
|
/** English UI strings. */
|
|
260
358
|
export declare const en: Record<string, string>;
|
|
261
359
|
|
|
360
|
+
export declare const EncryptedFolderModal: DefineComponent<__VLS_Props_12, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {} & {
|
|
361
|
+
close: () => any;
|
|
362
|
+
submit: (payload: {
|
|
363
|
+
name: string;
|
|
364
|
+
password: string;
|
|
365
|
+
}) => any;
|
|
366
|
+
}, string, PublicProps, Readonly<__VLS_Props_12> & Readonly<{
|
|
367
|
+
onClose?: (() => any) | undefined;
|
|
368
|
+
onSubmit?: ((payload: {
|
|
369
|
+
name: string;
|
|
370
|
+
password: string;
|
|
371
|
+
}) => any) | undefined;
|
|
372
|
+
}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {}, any>;
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Encrypt `content` under the folder KEK: mints a fresh DEK, encrypts the
|
|
376
|
+
* content one-shot, wraps the DEK with the KEK and prepends the fixed
|
|
377
|
+
* 'filexe2e' header. Throws when content exceeds E2E_MAX_FILE_BYTES.
|
|
378
|
+
*/
|
|
379
|
+
export declare function encryptFile(kek: CryptoKey, content: ArrayBuffer): Promise<ArrayBuffer>;
|
|
380
|
+
|
|
262
381
|
/**
|
|
263
382
|
* Resolved endpoint map. `useFileApi` derives this once on construction
|
|
264
383
|
* — components never need to think about config/apiBase precedence.
|
|
@@ -602,6 +721,9 @@ refresh: () => any;
|
|
|
602
721
|
"open-theme": () => any;
|
|
603
722
|
"open-shortcut-settings": () => any;
|
|
604
723
|
}, PublicProps, {}, false, {}, {}, GlobalComponents, GlobalDirectives, string, {
|
|
724
|
+
primaryEl: HTMLDivElement;
|
|
725
|
+
wideMoreBtnEl: HTMLButtonElement;
|
|
726
|
+
measureEl: HTMLDivElement;
|
|
605
727
|
searchEl: HTMLInputElement;
|
|
606
728
|
moreBtnEl: HTMLButtonElement;
|
|
607
729
|
moreRef: CreateComponentPublicInstanceWithMixins<Readonly<{
|
|
@@ -643,6 +765,45 @@ clientY: number;
|
|
|
643
765
|
}, nodes: FileNode[]) => Promise<void>;
|
|
644
766
|
hide: () => void;
|
|
645
767
|
}, {}, {}, {}, {}> | null;
|
|
768
|
+
wideMoreRef: CreateComponentPublicInstanceWithMixins<Readonly<{
|
|
769
|
+
locale: LocaleCode;
|
|
770
|
+
actions: ContextAction[];
|
|
771
|
+
theme?: ThemeMode;
|
|
772
|
+
sheet?: boolean;
|
|
773
|
+
}> & Readonly<{
|
|
774
|
+
onSelect?: ((action: ContextAction, target: FileNode[]) => any) | undefined;
|
|
775
|
+
}>, {
|
|
776
|
+
show: (ev: {
|
|
777
|
+
clientX: number;
|
|
778
|
+
clientY: number;
|
|
779
|
+
}, nodes: FileNode[]) => Promise<void>;
|
|
780
|
+
hide: () => void;
|
|
781
|
+
}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {} & {
|
|
782
|
+
select: (action: ContextAction, target: FileNode[]) => any;
|
|
783
|
+
}, PublicProps, {}, false, {}, {}, GlobalComponents, GlobalDirectives, string, {
|
|
784
|
+
sheetEl: HTMLDivElement;
|
|
785
|
+
menuEl: HTMLDivElement;
|
|
786
|
+
}, any, ComponentProvideOptions, {
|
|
787
|
+
P: {};
|
|
788
|
+
B: {};
|
|
789
|
+
D: {};
|
|
790
|
+
C: {};
|
|
791
|
+
M: {};
|
|
792
|
+
Defaults: {};
|
|
793
|
+
}, Readonly<{
|
|
794
|
+
locale: LocaleCode;
|
|
795
|
+
actions: ContextAction[];
|
|
796
|
+
theme?: ThemeMode;
|
|
797
|
+
sheet?: boolean;
|
|
798
|
+
}> & Readonly<{
|
|
799
|
+
onSelect?: ((action: ContextAction, target: FileNode[]) => any) | undefined;
|
|
800
|
+
}>, {
|
|
801
|
+
show: (ev: {
|
|
802
|
+
clientX: number;
|
|
803
|
+
clientY: number;
|
|
804
|
+
}, nodes: FileNode[]) => Promise<void>;
|
|
805
|
+
hide: () => void;
|
|
806
|
+
}, {}, {}, {}, {}> | null;
|
|
646
807
|
}, HTMLDivElement, ComponentProvideOptions, {
|
|
647
808
|
P: {};
|
|
648
809
|
B: {};
|
|
@@ -693,6 +854,8 @@ floor?: string;
|
|
|
693
854
|
multiRoot?: boolean;
|
|
694
855
|
virtualRows?: () => FileNode[];
|
|
695
856
|
active?: boolean;
|
|
857
|
+
viewMode?: ViewMode;
|
|
858
|
+
thumbSrc?: (n: FileNode) => string | null;
|
|
696
859
|
}> & Readonly<{
|
|
697
860
|
onClose?: (() => any) | undefined;
|
|
698
861
|
onNavigate?: ((path: string) => any) | undefined;
|
|
@@ -739,6 +902,8 @@ floor?: string;
|
|
|
739
902
|
multiRoot?: boolean;
|
|
740
903
|
virtualRows?: () => FileNode[];
|
|
741
904
|
active?: boolean;
|
|
905
|
+
viewMode?: ViewMode;
|
|
906
|
+
thumbSrc?: (n: FileNode) => string | null;
|
|
742
907
|
}> & Readonly<{
|
|
743
908
|
onClose?: (() => any) | undefined;
|
|
744
909
|
onNavigate?: ((path: string) => any) | undefined;
|
|
@@ -843,6 +1008,7 @@ export declare interface FileNode {
|
|
|
843
1008
|
* projectFileNodes emits it when a storage has RBAC on). '' / undefined =
|
|
844
1009
|
* ACL not enforced. Used to gate edit/manage affordances client-side. */
|
|
845
1010
|
perm?: 'none' | 'viewer' | 'editor' | 'owner';
|
|
1011
|
+
e2e?: boolean;
|
|
846
1012
|
/** Generic — any additional fields the backend wants to inline. */
|
|
847
1013
|
[k: string]: unknown;
|
|
848
1014
|
}
|
|
@@ -910,6 +1076,9 @@ declare interface Grant {
|
|
|
910
1076
|
inherited?: boolean;
|
|
911
1077
|
}
|
|
912
1078
|
|
|
1079
|
+
/** True when the buffer starts with the 'filexe2e' magic. */
|
|
1080
|
+
export declare function hasMagic(buf: ArrayBuffer | Uint8Array): boolean;
|
|
1081
|
+
|
|
913
1082
|
declare interface InviteResponse {
|
|
914
1083
|
mode: 'granted' | 'user_created' | 'shared';
|
|
915
1084
|
user_id?: number;
|
|
@@ -935,6 +1104,8 @@ export declare interface ManagerResponse {
|
|
|
935
1104
|
/** RBAC effective level for the current user on this directory ('' when ACL
|
|
936
1105
|
* is not enforced on the storage). Gates the folder-level write actions. */
|
|
937
1106
|
perm?: 'none' | 'viewer' | 'editor' | 'owner';
|
|
1107
|
+
e2e?: boolean;
|
|
1108
|
+
e2e_root?: string;
|
|
938
1109
|
files: FileNode[];
|
|
939
1110
|
}
|
|
940
1111
|
|
|
@@ -1053,6 +1224,9 @@ export declare type OperationsStore = ReturnType<typeof useOperations>;
|
|
|
1053
1224
|
|
|
1054
1225
|
export declare type OperationStatus = 'running' | 'done' | 'error' | 'aborted';
|
|
1055
1226
|
|
|
1227
|
+
/** Parse marker JSON text; returns null when the shape is not a v1 marker. */
|
|
1228
|
+
export declare function parseMarker(text: string): E2eMarker | null;
|
|
1229
|
+
|
|
1056
1230
|
export declare interface PendingOp {
|
|
1057
1231
|
id: number;
|
|
1058
1232
|
op_type: 'copy' | 'move' | 'delete';
|
|
@@ -1372,6 +1546,9 @@ export declare type TabsApi = ReturnType<typeof useTabs>;
|
|
|
1372
1546
|
/** Per-tab split state — the secondary pane's own location. */
|
|
1373
1547
|
export declare interface TabSplit {
|
|
1374
1548
|
path: string;
|
|
1549
|
+
/** ui-fix — the pane's OWN view mode (list/grid/gallery); undefined
|
|
1550
|
+
* inherits the main panel's mode at split time. */
|
|
1551
|
+
viewMode?: ViewMode;
|
|
1375
1552
|
}
|
|
1376
1553
|
|
|
1377
1554
|
export declare interface TabState {
|
|
@@ -1823,6 +2000,13 @@ export declare function useUploadChunked(config: ExplorerConfig, api: FileApi):
|
|
|
1823
2000
|
uploadFile: (opts: UploadOptions) => Promise<UploadFinalizeResponse>;
|
|
1824
2001
|
};
|
|
1825
2002
|
|
|
2003
|
+
/**
|
|
2004
|
+
* Check `password` against a folder marker. Resolves to the derived KEK on
|
|
2005
|
+
* success, or `null` on a wrong password (GCM tag mismatch on the verify
|
|
2006
|
+
* blob). Never talks to any server.
|
|
2007
|
+
*/
|
|
2008
|
+
export declare function verifyPassword(marker: E2eMarker, password: string): Promise<CryptoKey | null>;
|
|
2009
|
+
|
|
1826
2010
|
export declare type ViewMode = 'list' | 'grid' | 'gallery';
|
|
1827
2011
|
|
|
1828
2012
|
export { }
|