aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/files-app.js
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/files-app.js')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/files-app.js20
1 files changed, 19 insertions, 1 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/files-app.js b/packages/meshbay-hub/src/meshbay_hub/static/files-app.js
index 4947f8c..36c5af3 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/files-app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/files-app.js
@@ -6,7 +6,7 @@ import { Icon } from './icon.js';
import { entriesUnder } from './zipstream.js';
import { transfers } from './transfers.js';
import {
- FILE_ICONS, formatSize, formatDate, canPreview, CHUNK_SIZE,
+ FILE_ICONS, formatSize, formatDate, canPreview, CHUNK_SIZE, MEMORY_CEILING,
pipelinedDownload, downloadEntry, downloadDirectory as sharedDownloadDirectory,
} from './file-utils.js';
@@ -598,6 +598,24 @@ function FilePreview({ entry, transportRef, gekRef, onClose, onDownload }) {
useEffect(() => {
let cancelled = false;
const load = async () => {
+ // Nothing here streams: a preview is decrypted whole, held as an array of
+ // chunks, and turned into a blob. That is right for a page of text and a
+ // photograph, and it is a dead tab for the things that also reach here —
+ // a scanned PDF, a multi-gigabyte .csv or .log. There was no size test at
+ // all, and the text branch is the sharpest illustration: it decoded the
+ // entire file and then kept 500 000 characters of it.
+ //
+ // Films and music never arrive (group-page.js's onPreview routes video to
+ // the MSE player and audio to the music queue), so this guard is only ever
+ // met by a document somebody clicked without knowing how big it was. It
+ // offers the download instead, which does stream.
+ if (entry.size > MEMORY_CEILING) {
+ setError(t('preview.too_large', {
+ size: formatSize(entry.size), limit: formatSize(MEMORY_CEILING),
+ }));
+ setPhase('error');
+ return;
+ }
const transport = transportRef.current;
if (!transport || !transport.connected) {
setError(t('video.err_transport'));