Added Sign In tab to verify.html for nostr-login-lite authentication

This commit is contained in:
Laan Tungir
2026-07-27 13:03:36 -04:00
parent 200eb41f39
commit 94f03f2999
4 changed files with 161 additions and 12 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "nostr_quantum_preparation",
"version": "0.0.34",
"version": "0.0.35",
"description": "A migration strategy for bringing post-quantum security to Nostr without breaking the social graph, without requiring consensus on a single post-quantum algorithm, and without forcing existing users to abandon their identities.",
"main": "index.js",
"scripts": {
+145 -8
View File
@@ -22,19 +22,26 @@
================================================================ */
const tabRelay = document.getElementById('pqTabRelay');
const tabPaste = document.getElementById('pqTabPaste');
const tabSignIn = document.getElementById('pqTabSignIn');
const panelRelay = document.getElementById('pqPanelRelay');
const panelPaste = document.getElementById('pqPanelPaste');
const panelSignIn = document.getElementById('pqPanelSignIn');
function switchTab(which) {
const isRelay = which === 'relay';
const isPaste = which === 'paste';
const isSignIn = which === 'signin';
tabRelay.classList.toggle('pq-tab-active', isRelay);
tabPaste.classList.toggle('pq-tab-active', !isRelay);
tabPaste.classList.toggle('pq-tab-active', isPaste);
tabSignIn.classList.toggle('pq-tab-active', isSignIn);
panelRelay.classList.toggle('pq-tab-panel-active', isRelay);
panelPaste.classList.toggle('pq-tab-panel-active', !isRelay);
panelPaste.classList.toggle('pq-tab-panel-active', isPaste);
panelSignIn.classList.toggle('pq-tab-panel-active', isSignIn);
}
tabRelay.addEventListener('click', () => switchTab('relay'));
tabPaste.addEventListener('click', () => switchTab('paste'));
tabSignIn.addEventListener('click', () => switchTab('signin'));
/* ================================================================
SHARED DOM + STATE
@@ -607,6 +614,141 @@
}
});
/* ================================================================
AUTHENTICATION (nostr-login-lite / NIP-07)
================================================================ */
async function initNostrLoginLite() {
if (!window.NOSTR_LOGIN_LITE) return false;
if (!window.NOSTR_LOGIN_LITE._initialized) {
await window.NOSTR_LOGIN_LITE.init({
methods: { extension: true, local: true, nip46: true, seedphrase: true, nsigner: true }
});
}
return true;
}
// Fill the pubkey field and auto-query relays for the signed-in user's
// kind 9999 event. Switches to the Query Relay tab so the user sees the
// results. Returns the pubkey hex on success, null otherwise.
async function queryAsSignedInUser() {
if (!window.nostr || !window.nostr.getPublicKey) {
throw new Error('No Nostr signer available. Install a NIP-07 browser extension (nos2x, Alby) or use nostr-login-lite.');
}
const pubkeyHex = await window.nostr.getPublicKey();
if (!pubkeyHex) throw new Error('No pubkey returned by signer.');
console.log('[verify] Signed-in pubkey:', pubkeyHex);
const pubkeyInput = document.getElementById('pqPubkeyInput');
const npub = hexToNpub(pubkeyHex);
pubkeyInput.value = npub || pubkeyHex;
// Show the query tab so the user sees the results
switchTab('relay');
queryBtn.click();
return pubkeyHex;
}
/* ================================================================
TAB 3: SIGN IN
================================================================ */
const signInBtn = document.getElementById('pqSignInBtn');
const signInError = document.getElementById('pqSignInError');
const signInStatus = document.getElementById('pqSignInStatus');
signInBtn.addEventListener('click', async () => {
signInBtn.disabled = true;
signInError.innerHTML = '';
setStatus(signInStatus, 'info', 'Signing in...');
try {
if (window.NOSTR_LOGIN_LITE) {
await initNostrLoginLite();
// Try a restored session first
if (window.nostr) {
try {
const pk = await window.nostr.getPublicKey();
if (pk) {
await queryAsSignedInUser();
setStatus(signInStatus, 'success', 'Signed in. Querying your event...');
return;
}
} catch (e) {
console.log('[verify] Not yet authenticated, launching login modal...');
}
}
// Launch the login modal and wait for auth events
const pubkeyHex = await new Promise((resolve, reject) => {
let settled = false;
const timeout = setTimeout(() => {
if (!settled) { settled = true; cleanup(); reject(new Error('Login timed out')); }
}, 120000);
async function tryGetPubkey() {
if (settled) return;
if (window.nostr) {
try {
const pk = await window.nostr.getPublicKey();
if (pk && !settled) { settled = true; cleanup(); resolve(pk); }
} catch (e) { console.log('[verify] getPublicKey not ready:', e.message); }
}
}
function authHandler(e) {
if (e.type === 'nlMethodSelected' && e.detail && e.detail.pubkey) {
if (!settled) { settled = true; cleanup(); resolve(e.detail.pubkey); }
return;
}
tryGetPubkey();
setTimeout(tryGetPubkey, 200);
setTimeout(tryGetPubkey, 500);
setTimeout(tryGetPubkey, 1000);
setTimeout(tryGetPubkey, 2000);
}
function cleanup() {
window.removeEventListener('nlAuth', authHandler);
window.removeEventListener('nlAuthRestored', authHandler);
window.removeEventListener('nlMethodSelected', authHandler);
window.removeEventListener('nlAuthComplete', authHandler);
clearTimeout(timeout);
}
window.addEventListener('nlAuth', authHandler);
window.addEventListener('nlAuthRestored', authHandler);
window.addEventListener('nlMethodSelected', authHandler);
window.addEventListener('nlAuthComplete', authHandler);
try {
const result = window.NOSTR_LOGIN_LITE.launch();
if (result && typeof result.then === 'function') {
result.then(() => {
tryGetPubkey(); setTimeout(tryGetPubkey, 200); setTimeout(tryGetPubkey, 500);
}).catch(e => { if (!settled) { settled = true; cleanup(); reject(e); } });
}
} catch (e) {
if (!settled) { settled = true; cleanup(); reject(e); }
}
});
// Fill the pubkey field with the launched-session pubkey and query
const pubkeyInput = document.getElementById('pqPubkeyInput');
const npub = hexToNpub(pubkeyHex);
pubkeyInput.value = npub || pubkeyHex;
switchTab('relay');
queryBtn.click();
setStatus(signInStatus, 'success', 'Signed in. Querying your event...');
} else {
// No nostr-login-lite — fall back to a plain NIP-07 extension
await queryAsSignedInUser();
setStatus(signInStatus, 'success', 'Signed in. Querying your event...');
}
} catch (error) {
console.error('[verify] Sign-in failed:', error);
setStatus(signInError, 'error', error.message);
setStatus(signInStatus, 'error', 'Sign-in failed.');
} finally {
signInBtn.disabled = false;
}
});
/* ================================================================
AUTO-DETECT SIGNED-IN USER
On page load, check for a NIP-07 signer / nostr-login-lite. If the
@@ -614,14 +756,9 @@
relays for their kind 9999 event.
================================================================ */
async function initAutoDetect() {
// Initialize nostr-login-lite if available (shares session with main page)
if (window.NOSTR_LOGIN_LITE) {
try {
if (!window.NOSTR_LOGIN_LITE._initialized) {
await window.NOSTR_LOGIN_LITE.init({
methods: { extension: true, local: true, nip46: true, seedphrase: true, nsigner: true }
});
}
await initNostrLoginLite();
} catch (e) {
console.log('[verify] nostr-login-lite init failed:', e.message);
}
+3 -3
View File
@@ -1,5 +1,5 @@
{
"VERSION": "v0.0.34",
"VERSION_NUMBER": "0.0.34",
"BUILD_DATE": "2026-07-27T16:53:32.439Z"
"VERSION": "v0.0.35",
"VERSION_NUMBER": "0.0.35",
"BUILD_DATE": "2026-07-27T17:03:35.968Z"
}
+12
View File
@@ -258,6 +258,7 @@
<div class="pq-tabs">
<div class="pq-tab pq-tab-active" id="pqTabRelay">Query Relay</div>
<div class="pq-tab" id="pqTabPaste">Paste Event JSON</div>
<div class="pq-tab" id="pqTabSignIn">Sign In</div>
</div>
<!-- TAB 1: Query Relay -->
@@ -302,6 +303,17 @@
<input type="file" id="pqArchiveFileInput" accept="application/json,.json" style="margin-top: 6px; font-size: 13px;" />
</div>
<!-- TAB 3: SIGN IN -->
<div class="pq-tab-panel" id="pqPanelSignIn">
<div class="pq-info-text">
Sign in with your Nostr identity (NIP-07 extension or nostr-login-lite) to look up your
own kind 9999 event automatically.
</div>
<div id="pqSignInError"></div>
<button class="pq-button" id="pqSignInBtn">Sign In</button>
<div id="pqSignInStatus"></div>
</div>
<!-- Shared results area -->
<div id="pqResultsWrap" style="display: none;">
<div class="pq-info-text" style="margin-top: 15px; margin-bottom: 5px;">