diff --git a/public/s/js/messages.js b/public/s/js/messages.js
index 6be376a..6dddd1c 100644
--- a/public/s/js/messages.js
+++ b/public/s/js/messages.js
@@ -2073,27 +2073,45 @@ if (window.__dmLoaded) {
// Recovery modal (shown when vault exists but no local key)
// ─────────────────────────────────────────────────────────────────────────
- function showRecoveryModal() {
+ function showRecoveryModal({ dismissible = false } = {}) {
return new Promise(resolve => {
const modal = document.createElement('div');
modal.id = 'dm-recovery-modal';
- modal.className = 'dm-modal-overlay dm-modal-blocking';
+ modal.className = 'dm-modal-overlay' + (dismissible ? '' : ' dm-modal-blocking');
modal.innerHTML = `
-
🔑 Restore your key
+ ${dismissible ? '
' : ''}
+
Restore your key
Enter your 12 recovery words to regain access to your messages.
-
+
Forgot your words? You can create a new key — all old messages will become unreadable.
-
+
`;
- modal.addEventListener('click', e => e.stopPropagation());
+ const dismiss = () => {
+ document.removeEventListener('keydown', trapEsc2, true);
+ modal.remove();
+ resolve();
+ };
+
+ if (dismissible) {
+ modal.querySelector('#dm-recovery-close').onclick = dismiss;
+ modal.addEventListener('click', e => { if (e.target === modal) dismiss(); });
+ } else {
+ modal.addEventListener('click', e => e.stopPropagation());
+ }
+
document.addEventListener('keydown', trapEsc2, true);
- function trapEsc2(e) { if (e.key === 'Escape') e.stopImmediatePropagation(); }
+ function trapEsc2(e) {
+ if (e.key === 'Escape') {
+ if (dismissible) { e.stopImmediatePropagation(); dismiss(); }
+ else e.stopImmediatePropagation();
+ }
+ }
const grid = modal.querySelector('#dm-recovery-inputs');
for (let i = 0; i < 12; i++) {
@@ -2212,24 +2230,19 @@ if (window.__dmLoaded) {
modal.innerHTML = `
-
🔑 Encryption Key
+
Encryption Key
Your private key is secured with your recovery phrase and stored encrypted on the server.
${hasKey() ? '✅ Key loaded and backed up.' : '❌ No key found.'}
-
🔓 Recover from phrase
+
Recover from phrase
Already have a recovery phrase? Enter it here to restore access to previous messages on this device.
-
-
Create new key
-
⚠️ Creates a new key pair. Old messages will become unreadable.
-
-
-
+
`;
@@ -2240,7 +2253,7 @@ if (window.__dmLoaded) {
// Recover from existing phrase
modal.querySelector('#dm-recover-phrase-btn').onclick = async () => {
modal.style.display = 'none';
- await showRecoveryModal();
+ await showRecoveryModal({ dismissible: true });
// REFRESH UI after recovery
if (typeof initMessagesPage === 'function') await initMessagesPage();
@@ -2250,25 +2263,7 @@ if (window.__dmLoaded) {
if (statusEl) statusEl.textContent = hasKey() ? '✅ Key loaded and backed up.' : '❌ No key found.';
};
- modal.querySelector('#dm-regen-btn').onclick = async () => {
- const msg = modal.querySelector('#dm-regen-msg');
- if (!confirm('Really create a new key? All old messages will become unreadable.')) return;
- try {
- await dmFetch('DELETE', '/api/dm/keyvault');
- localStorage.removeItem(DM_KEY_NAME);
- localStorage.removeItem(DM_PUBKEY_NAME);
- localStorage.removeItem(DM_KEY_VERSION);
- _privateKey = null; _publicKeyJwk = null; pubkeyCache.clear();
- modal.style.display = 'none';
- const status = await loadOrCreateKeyPair();
- uploadPublicKey().catch(() => {});
- if (status === 'new') await showSeedSetupModal();
- // REFRESH UI after regen/setup
- if (typeof initMessagesPage === 'function') await initMessagesPage();
- } catch (e) {
- setMsg(msg, '❌ Error: ' + e.message, 'err');
- }
- };
+
return modal;
}
diff --git a/views/messages-conversation.html b/views/messages-conversation.html
index 315f9d2..5a62a34 100644
--- a/views/messages-conversation.html
+++ b/views/messages-conversation.html
@@ -18,7 +18,6 @@
-