From 1649eb27a08c6fdf675f6c17f913c7bd07443122 Mon Sep 17 00:00:00 2001 From: Marwin Schulz Date: Fri, 20 Mar 2026 09:45:39 +0100 Subject: [PATCH] Fix ebooks: show wrong-key warning, close overlay on open failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - renderBookList now shows a ⚠️ warning and disables the Open button for books that couldn't be decrypted (keyOk: false), telling the user to import the correct encryption key - openBook catch block now hides the reader overlay and shows an alert instead of leaving the overlay open with a cryptic error message Co-Authored-By: Claude Sonnet 4.6 --- static/js/app.js | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/static/js/app.js b/static/js/app.js index 23dbcf1..b3a76ac 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -2611,13 +2611,15 @@ async function loadBookList() { listEl.innerHTML = '

Loading…

'; try { - const res = await fetch('/books/'); + const res = await fetch('/books/', {cache: 'no-store'}); if (!res.ok) { + console.error('loadBookList: server returned', res.status); listEl.innerHTML = `

Server error ${res.status} loading books.

`; return; } const books = await res.json(); if (!Array.isArray(books)) { + console.error('loadBookList: unexpected response', books); listEl.innerHTML = `

Unexpected response from server.

`; return; } @@ -2626,22 +2628,32 @@ async function loadBookList() { return; } - const key = await getOrCreateEncKey(); + let key; + try { + key = await getOrCreateEncKey(); + } catch (e) { + console.error('loadBookList: getOrCreateEncKey failed', e); + listEl.innerHTML = `

Encryption not available: ${e.message}. Make sure you are on HTTPS.

`; + return; + } + const decrypted = []; for (const b of books) { try { const metaBuf = await decryptBytes(key, b.meta_iv, b.meta_ct); const meta = JSON.parse(new TextDecoder().decode(metaBuf)); bookMetaCache[b.id] = {title: meta.title || '?', author: meta.author || '', type: meta.type || 'epub'}; - decrypted.push({id: b.id, title: meta.title || '?', author: meta.author || '', type: meta.type || 'epub', scroll_fraction: b.scroll_fraction, uploaded_at: b.uploaded_at}); + decrypted.push({id: b.id, title: meta.title || '?', author: meta.author || '', type: meta.type || 'epub', scroll_fraction: b.scroll_fraction, uploaded_at: b.uploaded_at, keyOk: true}); } catch (e) { + console.warn(`loadBookList: could not decrypt book #${b.id}:`, e.message); bookMetaCache[b.id] = {title: `Book #${b.id}`, author: '', type: 'epub'}; - decrypted.push({id: b.id, title: `Book #${b.id}`, author: '', type: 'epub', scroll_fraction: b.scroll_fraction, uploaded_at: b.uploaded_at}); + decrypted.push({id: b.id, title: `Book #${b.id}`, author: '', type: 'epub', scroll_fraction: b.scroll_fraction, uploaded_at: b.uploaded_at, keyOk: false}); } } renderBookList(decrypted); } catch (e) { - if (listEl) listEl.innerHTML = `

Error: ${e.message}

`; + console.error('loadBookList error:', e); + if (listEl) listEl.innerHTML = `

Error loading books: ${e.message}

`; } } @@ -2651,14 +2663,15 @@ function renderBookList(books) { let html = ''; for (const b of books) { const pct = Math.round((b.scroll_fraction || 0) * 100); + const keyWarning = b.keyOk === false ? '⚠️ wrong key' : ''; html += `
- ${escapeHtml(b.title)} + ${escapeHtml(b.title)}${keyWarning} ${escapeHtml(b.author)} ${pct > 0 ? `${pct}% read` : ''}
- +
`; @@ -3076,7 +3089,8 @@ async function openBook(bookId) { } } catch (e) { - contentEl.innerHTML = `

Failed to open book: ${escapeHtml(e.message)}

`; + overlay.style.display = 'none'; + alert(`Failed to open book: ${e.message}`); } }