use data: URI for image preview: CSP img-src only allows self+data, blob: would be blocked (#171)
This commit is contained in:
+20
-12
@@ -252,40 +252,48 @@ function extOf(name) {
|
|||||||
// content into the editor. Title auto-fills only if still blank (house
|
// content into the editor. Title auto-fills only if still blank (house
|
||||||
// rule: never overwrite a typed title).
|
// rule: never overwrite a typed title).
|
||||||
const IMAGE_RE = /^image\//;
|
const IMAGE_RE = /^image\//;
|
||||||
let previewURL = null;
|
let previewReader = null; // in-flight FileReader, aborted when the file changes
|
||||||
|
|
||||||
async function showFileInEditor(file) {
|
// #171: images preview via a data: URI — the CSP is img-src 'self' data:
|
||||||
|
// and blob: object URLs would be blocked at render time.
|
||||||
|
function showFileInEditor(file) {
|
||||||
const wrap = document.querySelector('.editor-wrap');
|
const wrap = document.querySelector('.editor-wrap');
|
||||||
const img = $('file-preview');
|
const img = $('file-preview');
|
||||||
if (IMAGE_RE.test(file.type)) {
|
if (IMAGE_RE.test(file.type)) {
|
||||||
if (previewURL) URL.revokeObjectURL(previewURL);
|
if (previewReader) { try { previewReader.abort(); } catch(e) {} previewReader = null; }
|
||||||
previewURL = URL.createObjectURL(file);
|
previewReader = new FileReader();
|
||||||
img.src = previewURL;
|
previewReader.onload = () => {
|
||||||
img.alt = file.name;
|
if (attachedFile !== file) return; // a different file was attached meanwhile
|
||||||
wrap.classList.add('previewing');
|
img.src = previewReader.result; // data: URI, allowed by img-src 'self' data:
|
||||||
img.classList.remove('hidden');
|
img.alt = file.name;
|
||||||
|
wrap.classList.add('previewing');
|
||||||
|
img.classList.remove('hidden');
|
||||||
|
previewReader = null;
|
||||||
|
};
|
||||||
|
previewReader.onerror = () => { previewReader = null; };
|
||||||
|
previewReader.readAsDataURL(file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wrap.classList.remove('previewing');
|
wrap.classList.remove('previewing');
|
||||||
img.classList.add('hidden');
|
img.classList.add('hidden');
|
||||||
if (!TEXT_EXTS.has(extOf(file.name))) return; // unknown binary: leave editor alone
|
if (!TEXT_EXTS.has(extOf(file.name))) return; // unknown binary: leave editor alone
|
||||||
try {
|
file.text().then(text => {
|
||||||
const text = await file.text();
|
if (attachedFile !== file) return;
|
||||||
if (!content.value.trim()) {
|
if (!content.value.trim()) {
|
||||||
content.value = text;
|
content.value = text;
|
||||||
updateGutter();
|
updateGutter();
|
||||||
guessLang();
|
guessLang();
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
}).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearPreview() {
|
function clearPreview() {
|
||||||
|
if (previewReader) { try { previewReader.abort(); } catch(e) {} previewReader = null; }
|
||||||
const wrap = document.querySelector('.editor-wrap');
|
const wrap = document.querySelector('.editor-wrap');
|
||||||
const img = $('file-preview');
|
const img = $('file-preview');
|
||||||
wrap.classList.remove('previewing');
|
wrap.classList.remove('previewing');
|
||||||
img.classList.add('hidden');
|
img.classList.add('hidden');
|
||||||
img.removeAttribute('src');
|
img.removeAttribute('src');
|
||||||
if (previewURL) { URL.revokeObjectURL(previewURL); previewURL = null; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setAttachedFile(file) {
|
function setAttachedFile(file) {
|
||||||
|
|||||||
Reference in New Issue
Block a user