diff --git a/static/js/app.js b/static/js/app.js index 8b1821d..2af86d7 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -2198,14 +2198,22 @@ function bookFileSelected(input) { } function initBookDropZone() { - const zone = $('book-drop-zone'); - // Prevent Firefox from opening dragged files when dropped outside the zone document.addEventListener('dragover', e => e.preventDefault()); document.addEventListener('drop', e => { + const zone = $('book-drop-zone'); if (!zone || !zone.contains(e.target)) e.preventDefault(); }); + const storageKey = `diora_enc_key_${window.USER_ID || 'anon'}`; + const hasKey = !!localStorage.getItem(storageKey); + const prompt = $('enc-key-prompt'); + const uploadArea = $('book-upload-area'); + + if (prompt) prompt.style.display = hasKey ? 'none' : ''; + if (uploadArea) uploadArea.style.display = hasKey ? '' : 'none'; + + const zone = $('book-drop-zone'); if (!zone) return; zone.addEventListener('dragover', e => { @@ -2221,6 +2229,36 @@ function initBookDropZone() { }); } +async function deriveAndStoreKey() { + const pwInput = document.getElementById('enc-key-password'); + const statusEl = $('enc-key-status'); + const pw = pwInput ? pwInput.value : ''; + if (!pw) { if (statusEl) statusEl.textContent = 'Please enter your password.'; return; } + + if (statusEl) statusEl.textContent = 'Deriving key…'; + try { + const enc = new TextEncoder(); + const username = document.querySelector('meta[name="username"]')?.content || ''; + const mat = await crypto.subtle.importKey('raw', enc.encode(pw), 'PBKDF2', false, ['deriveKey']); + const key = await crypto.subtle.deriveKey( + {name: 'PBKDF2', salt: enc.encode('diora:' + username), iterations: 200000, hash: 'SHA-256'}, + mat, {name: 'AES-GCM', length: 256}, true, ['encrypt', 'decrypt'] + ); + const raw = await crypto.subtle.exportKey('raw', key); + const storageKey = `diora_enc_key_${window.USER_ID || 'anon'}`; + localStorage.setItem(storageKey, bytesToBase64(new Uint8Array(raw))); + _encKey = null; // reset cached key + if (statusEl) statusEl.textContent = '✓ Unlocked'; + const prompt = $('enc-key-prompt'); + const uploadArea = $('book-upload-area'); + if (prompt) prompt.style.display = 'none'; + if (uploadArea) uploadArea.style.display = ''; + loadBookList(); + } catch (err) { + if (statusEl) statusEl.textContent = 'Error: ' + err.message; + } +} + async function uploadEbook(file) { const statusEl = $('book-upload-status'); const isPdf = /\.pdf$/i.test(file.name); diff --git a/templates/base.html b/templates/base.html index 7c9dde8..3c93ae1 100644 --- a/templates/base.html +++ b/templates/base.html @@ -8,6 +8,7 @@ + {% if user.is_authenticated %}{% endif %} diff --git a/templates/radio/player.html b/templates/radio/player.html index 64c2926..c7184e1 100644 --- a/templates/radio/player.html +++ b/templates/radio/player.html @@ -278,10 +278,20 @@