let currentUser = null; let currentChallenge = null; let authMethod = null; function escapeHtml(str) { const div = document.createElement('div'); div.textContent = str; return div.innerHTML; } // --- Matrix auth --- function goToMatrixLogin() { const slug = window.location.pathname.split('/').filter(Boolean)[0]; window.location.href = '/' + slug + '/matrix-login'; } function signOut() { sessionStorage.removeItem('matrix_session_token'); currentUser = null; authMethod = null; window.location.reload(); } function showNostrAuth() { document.getElementById('auth_method_select').style.display = 'none'; document.getElementById('nostr_auth_section').style.display = 'block'; } async function checkMatrixSession() { const sessionToken = sessionStorage.getItem('matrix_session_token'); if (!sessionToken) return false; try { const slug = window.location.pathname.split('/').filter(Boolean)[0]; const resp = await fetch('/' + slug + '/matrixVerify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_token: sessionToken }) }); if (resp.ok) { const data = await resp.json(); currentUser = { displayName: data.display_name, sessionToken: sessionToken }; authMethod = 'matrix'; document.getElementById('auth_section').style.display = 'none'; document.getElementById('vote_section').style.display = 'block'; document.getElementById('logged_in_as').textContent = 'Signed in as: ' + data.display_name; loadSubmissions(); return true; } else { sessionStorage.removeItem('matrix_session_token'); } } catch (e) { sessionStorage.removeItem('matrix_session_token'); } return false; } // --- Nostr auth --- function hasNip07() { return typeof window.nostr !== 'undefined' && window.nostr !== null; } async function connectNip07() { if (!hasNip07()) { setAuthStatus('No Nostr browser extension detected. Enter your npub manually.', true); return; } try { const hexKey = await window.nostr.getPublicKey(); const resp = await fetch('encode_npub', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ hex: hexKey }) }); if (resp.ok) { const data = await resp.json(); document.getElementById('npub_input').value = data.npub; document.getElementById('nip07_badge').style.display = 'block'; setAuthStatus('Connected! Click "Sign In to Vote" to continue.'); } else { document.getElementById('npub_input').value = hexKey; setAuthStatus('Connected (using hex key). Click "Sign In to Vote".'); } } catch (err) { setAuthStatus('Error: ' + err.message, true); } } async function authenticate() { const npub = document.getElementById('npub_input').value.trim(); if (!npub) { setAuthStatus('Enter your npub or connect AlbyHub first.', true); return; } setAuthStatus('Requesting challenge...'); try { const resp = await fetch('challenge', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ npub: npub }) }); if (resp.status === 404) { setAuthStatus('Npub not linked. Please link your identity first.', true); return; } if (!resp.ok) { const text = await resp.text(); setAuthStatus('Error: ' + text, true); return; } const data = await resp.json(); currentChallenge = data.challenge; if (!hasNip07()) { setAuthStatus('No Nostr extension. Please install AlbyHub to sign.', true); return; } setAuthStatus('Please sign the challenge in your extension...'); const signedEvent = await window.nostr.signEvent({ created_at: Math.floor(Date.now() / 1000), kind: 1, tags: [], content: currentChallenge }); currentUser = { npub: npub, displayName: data.display_name, signedEvent: signedEvent }; authMethod = 'nostr'; document.getElementById('auth_section').style.display = 'none'; document.getElementById('vote_section').style.display = 'block'; document.getElementById('logged_in_as').textContent = 'Signed in as: ' + data.display_name; loadSubmissions(); } catch (err) { if (err.message && err.message.includes('denied')) { setAuthStatus('Signature request denied.', true); } else { setAuthStatus('Error: ' + err.message, true); } } } function setAuthStatus(msg, isError) { const el = document.getElementById('auth_status'); el.innerHTML = msg; el.className = isError ? 'error' : 'success'; } // --- Submissions --- async function loadSubmissions() { try { const response = await fetch('submissions'); const data = await response.json(); const submissionList = document.getElementById('suggestion_list'); submissionList.innerHTML = ''; if (data.Submissions && data.Submissions.length > 0) { data.Submissions.forEach((sub) => { const li = document.createElement('li'); li.innerHTML = ` ${escapeHtml(sub.submitter)} SUGGESTED : ${escapeHtml(sub.submission)} `; submissionList.appendChild(li); }); } else { submissionList.innerHTML = '