// Simple JSON syntax highlighter document.addEventListener("DOMContentLoaded", function() { const claimsElement = document.getElementById("claims"); if (claimsElement) { try { const json = JSON.parse(claimsElement.textContent); claimsElement.innerHTML = syntaxHighlight(json); } catch (e) { console.error("Invalid JSON in claims:", e); } } }); function syntaxHighlight(json) { if (typeof json != 'string') { json = JSON.stringify(json, undefined, 2); } json = json.replace(/&/g, '&').replace(//g, '>'); return json.replace(/("(\\u[\da-fA-F]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|\b\d+\b)/g, function (match) { let cls = 'number'; if (/^"/.test(match)) { if (/:$/.test(match)) { cls = 'key'; } else { cls = 'string'; } } else if (/true|false/.test(match)) { cls = 'boolean'; } else if (/null/.test(match)) { cls = 'null'; } return '' + match + ''; }); } function copyPublicKey() { const publicKeyElement = document.getElementById("public-key"); if (!publicKeyElement) return; const text = publicKeyElement.textContent; // Use modern clipboard API if available if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text).then(() => { showCopyFeedback("Copied!"); }).catch(err => { console.error("Failed to copy:", err); fallbackCopy(text); }); } else { fallbackCopy(text); } } function fallbackCopy(text) { const textarea = document.createElement("textarea"); textarea.value = text; textarea.style.position = "fixed"; textarea.style.opacity = "0"; document.body.appendChild(textarea); textarea.select(); try { document.execCommand("copy"); showCopyFeedback("Copied!"); } catch (err) { console.error("Fallback copy failed:", err); showCopyFeedback("Failed to copy"); } document.body.removeChild(textarea); } function showCopyFeedback(message) { const btn = event.target; const originalText = btn.textContent; btn.textContent = message; btn.style.backgroundColor = "#28a745"; setTimeout(() => { btn.textContent = originalText; btn.style.backgroundColor = ""; }, 2000); } // UserInfo functionality document.addEventListener("DOMContentLoaded", function() { const form = document.getElementById("userinfo-form"); if (form) { form.addEventListener("submit", fetchUserInfo); } }); async function fetchUserInfo(event) { event.preventDefault(); const form = event.target; const loading = document.getElementById("userinfo-loading"); const error = document.getElementById("userinfo-error"); const claimsElement = document.getElementById("userinfo-claims"); const submitButton = form.querySelector('button[type="submit"]'); // Hide error and claims from previous attempts error.style.display = "none"; claimsElement.style.display = "none"; // Show loading, hide button submitButton.style.display = "none"; loading.style.display = "flex"; try { const formData = new FormData(form); // Convert FormData to URL-encoded string const urlEncodedData = new URLSearchParams(formData).toString(); const response = await fetch("/userinfo", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: urlEncodedData }); if (!response.ok) { const errorText = await response.text(); throw new Error(errorText || `HTTP ${response.status}`); } const userinfo = await response.json(); // Display the userinfo claims const code = claimsElement.querySelector("code"); const formattedJson = JSON.stringify(userinfo, null, 2); code.textContent = formattedJson; // Apply syntax highlighting try { code.innerHTML = syntaxHighlight(userinfo); } catch (e) { console.error("Failed to highlight JSON:", e); } claimsElement.style.display = "block"; } catch (err) { console.error("Failed to fetch userinfo:", err); error.textContent = "Failed to fetch UserInfo: " + err.message; error.style.display = "block"; submitButton.style.display = "inline-block"; } finally { loading.style.display = "none"; } }