Files
titlebot-ng-ng/voteServer/htm/link.html
T

155 lines
5.8 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Link Nostr Identity</title>
<link rel="stylesheet" href="css.css">
</head>
<body>
<h1>Link Your Nostr Identity</h1>
<p>Connect your npub to your Matrix display name so you can vote.</p>
<div id="auth_section">
<div id="nip07_status" class="info-box" style="display:none;">
Nostr browser extension detected.
</div>
<label for="display_name">Matrix Display Name:</label>
<input type="text" id="display_name" placeholder="Enter your Matrix display name exactly">
<label for="npub_input">Nostr Public Key (npub):</label>
<input type="text" id="npub_input" placeholder="npub1...">
<button id="connect_btn" onclick="connectNip07()">Connect AlbyHub</button>
<button id="link_btn" onclick="linkNpub()">Link & Sign</button>
<div id="status"></div>
</div>
<script>
let currentNpub = null;
async function connectNip07() {
if (!window.nostr) {
setStatus('No Nostr browser extension detected. Please enter your npub manually.', true);
return;
}
try {
const pubkey = await window.nostr.getPublicKey();
// Convert hex to npub bech32
const resp = await fetch('encode_npub', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({hex: pubkey})
});
if (resp.ok) {
const data = await resp.json();
document.getElementById('npub_input').value = data.npub;
currentNpub = data.npub;
setStatus('Connected! Npub loaded from extension.');
} else {
// Fallback: just use hex
document.getElementById('npub_input').value = pubkey;
currentNpub = pubkey;
setStatus('Connected! Paste this as npub if needed: ' + pubkey);
}
} catch (err) {
setStatus('Error connecting to extension: ' + err.message, true);
}
}
async function linkNpub() {
const displayName = document.getElementById('display_name').value.trim();
const npub = document.getElementById('npub_input').value.trim();
if (!displayName) {
setStatus('Please enter your Matrix display name.', true);
return;
}
if (!npub) {
setStatus('Please enter your npub or connect AlbyHub.', true);
return;
}
setStatus('Requesting signature...');
try {
// Build the linking message
// We need to get the hex pubkey first
let npubHex = npub;
// If it looks like a bech32 npub, we need to decode it client-side
// For simplicity, we'll send the npub and let the server decode it
// But we need the hex to build the message for signing
// Try to get hex from npub via server
const decodeResp = await fetch('decode_npub', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({npub: npub})
});
if (!decodeResp.ok) {
if (!window.nostr) {
setStatus('Could not decode npub. Please install a Nostr extension.', true);
return;
}
setStatus('Could not decode npub via server.', true);
return;
}
const decodeData = await decodeResp.json();
npubHex = decodeData.hex;
// Build the expected linking message
const slug = window.location.pathname.split('/')[1];
const linkMsg = `Link npub ${npubHex} to Matrix user ${displayName} for room ${slug}`;
let signedEvent;
if (window.nostr) {
// Sign via NIP-07 extension
signedEvent = await window.nostr.signEvent({
created_at: Math.floor(Date.now() / 1000),
kind: 1,
tags: [],
content: linkMsg
});
} else {
setStatus('No Nostr extension available. Please install AlbyHub or another NIP-07 signer.', true);
return;
}
setStatus('Sending link request...');
const resp = await fetch('linkNpub', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
display_name: displayName,
npub: npub,
signed_event: signedEvent
})
});
if (resp.ok) {
setStatus('Successfully linked! You can now <a href="/">go vote</a>.');
document.getElementById('link_btn').disabled = true;
} else {
const text = await resp.text();
setStatus('Error: ' + text, true);
}
} catch (err) {
setStatus('Error: ' + err.message, true);
}
}
function setStatus(msg, isError) {
const el = document.getElementById('status');
el.innerHTML = msg;
el.className = isError ? 'error' : 'success';
}
</script>
</body>
</html>