Files
bitvid/components/iframe_forms/iframe-bug-fix-form.html
T
thePR0M3TH3ANandClaude Opus 4.8 5eb7545a3f Submissions persistence: publish to nos.lol + admin re-broadcast mirror
Submissions are signed by throwaway ephemeral keys and public relays prune
events from pubkeys with no social graph, so the queue quietly evaporated.

- Forms: also publish to nos.lol (better retention, already in the app's
  query set) alongside snort/damus/primal.
- submissionFacade: on each fetch, re-broadcast the still-pending signed
  events back to our relays (publishEventToRelays) so pruning doesn't drop
  them. Best-effort, fire-and-forget — never blocks or fails the fetch;
  no-ops when no relay pool is available.
- test: fetch still returns the pending queue when a pool is present.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-07 15:48:48 -04:00

497 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>bitvid Bug Report Form</title>
<script type="module" src="./theme-sync.js"></script>
<!-- Link to your main stylesheet -->
<link rel="stylesheet" href="../../css/tailwind.generated.css" />
<!-- Load nostr‑tools v2.17.0 -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js"></script>
<!-- Shared anti-spam npub validation (sets window.validateNpubHex) -->
<script type="module" src="../../js/utils/validateNpub.js"></script>
</head>
<body class="iframe-form" data-ds="new">
<div class="container">
<div class="form-container">
<p>
If you have encountered a bug or technical issue on bitvid, please
fill out this form to help us diagnose and resolve the problem.
Providing detailed information will assist us in troubleshooting more
efficiently.
</p>
<form id="bug-form">
<!-- Section 1: User Information -->
<h2>1. User Information</h2>
<label for="userNpub">Nostr Public Key (npub) (optional):</label>
<input
class="form-control"
type="text"
id="userNpub"
placeholder="Enter your npub (optional)"
/>
<p>Are you a (check all that apply):</p>
<div class="checkbox-group">
<label
><input
class="checkbox"
type="checkbox"
name="userRole"
value="Viewer"
/>
Viewer</label
>
<label
><input
class="checkbox"
type="checkbox"
name="userRole"
value="Content Creator"
/>
Content Creator</label
>
<label
><input
class="checkbox"
type="checkbox"
name="userRole"
value="Developer/Contributor"
/>
Developer / Contributor</label
>
</div>
<!-- Section 2: Bug Details -->
<h2>2. Bug Details</h2>
<label for="issueDescription">Describe the issue:</label>
<textarea
class="textarea"
id="issueDescription"
rows="3"
placeholder="Provide a clear and concise description of the problem"
></textarea>
<label for="stepsToReproduce">Steps to reproduce the bug:</label>
<textarea
class="textarea"
id="stepsToReproduce"
rows="3"
placeholder="List the actions taken before encountering the issue"
></textarea>
<label for="expectedBehavior">Expected behavior:</label>
<textarea
class="textarea"
id="expectedBehavior"
rows="2"
placeholder="What should have happened instead?"
></textarea>
<label for="actualBehavior">Actual behavior:</label>
<textarea
class="textarea"
id="actualBehavior"
rows="2"
placeholder="What actually happened?"
></textarea>
<!-- Section 3: Device & Environment -->
<h2>3. Device &amp; Environment</h2>
<p>What device were you using? (check all that apply):</p>
<div class="checkbox-group">
<label
><input
class="checkbox"
type="checkbox"
name="deviceUsed"
value="Desktop"
/>
Desktop</label
>
<label
><input
class="checkbox"
type="checkbox"
name="deviceUsed"
value="Mobile"
/>
Mobile</label
>
<label
><input
class="checkbox"
type="checkbox"
name="deviceUsed"
value="Tablet"
/>
Tablet</label
>
</div>
<label for="operatingSystem">Operating System:</label>
<input
class="form-control"
type="text"
id="operatingSystem"
placeholder="e.g., Windows, macOS, Linux, iOS, Android"
/>
<label for="browserInfo">Browser (if applicable):</label>
<input
class="form-control"
type="text"
id="browserInfo"
placeholder="e.g., Chrome, Firefox, Safari"
/>
<label for="usingVPN"
>Are you using a VPN or privacy-focused browser settings?</label
>
<select class="select" id="usingVPN">
<option value="">Select an option</option>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<!-- Section 4: Screenshots or Logs -->
<h2>4. Screenshots or Logs (If Available)</h2>
<label for="screenshotInfo"
>Can you provide a screenshot or screen recording?</label
>
<textarea
class="textarea"
id="screenshotInfo"
rows="2"
placeholder="Attach if possible (e.g., URL to screenshot)"
></textarea>
<label for="errorMessages"
>Did the issue generate any error messages?</label
>
<textarea
class="textarea"
id="errorMessages"
rows="2"
placeholder="Include the exact error messages, if any"
></textarea>
<label for="consoleLogs">Any relevant console logs?</label>
<textarea
class="textarea"
id="consoleLogs"
rows="2"
placeholder="Paste any browser console logs if available"
></textarea>
<!-- Section 5: Additional Information -->
<h2>5. Additional Information</h2>
<label for="bugFrequency">How frequently does this bug occur?</label>
<select class="select" id="bugFrequency">
<option value="">Select an option</option>
<option value="Every time">Every time</option>
<option value="Occasionally">Occasionally</option>
<option value="Rarely">Rarely</option>
</select>
<label for="impactCore"
>Does this bug impact core functionality (e.g., video playback,
uploads, etc.)?</label
>
<select class="select" id="impactCore">
<option value="">Select an option</option>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<label for="additionalNotes"
>Any additional notes or suggestions?</label
>
<textarea
class="textarea"
id="additionalNotes"
rows="3"
placeholder="Describe any other relevant details"
></textarea>
<button class="btn" type="submit">Submit Bug Report</button>
</form>
<div id="status"></div>
</div>
</div>
<script>
// Provide no-op fallback loggers so embeds stay functional if bitvidLogger is unavailable.
const noopLogger = {
log: () => {},
info: () => {},
warn: () => {},
error: () => {},
};
const dev = window.bitvidLogger?.dev || noopLogger;
const user = window.bitvidLogger?.user || noopLogger;
document.addEventListener("DOMContentLoaded", () => {
// Logging functions for both on-page and console output.
function log(msg, type = "info") {
const div = document.createElement("div");
div.classList.add("status-line");
if (type === "error") div.classList.add("error");
if (type === "success") div.classList.add("success");
if (type === "warn") div.classList.add("warn");
div.textContent = msg;
document.getElementById("status").appendChild(div);
const formatted = `[${type.toUpperCase()}] ${msg}`;
if (type === "error") {
user.error(formatted);
} else if (type === "warn") {
user.warn(formatted);
} else if (type === "success") {
user.log(formatted);
} else if (type === "info") {
dev.info(formatted);
} else {
dev.log(formatted);
}
}
function clear() {
document.getElementById("status").innerHTML = "";
}
if (!window.NostrTools) {
log("NostrTools not loaded. Check console or ad-blockers.", "error");
return;
}
const {
generateSecretKey,
getPublicKey,
finalizeEvent,
nip04,
nip19,
SimplePool,
Relay,
} = window.NostrTools;
// Set the recipient's NPUB (your personal NPUB)
const recipientNpub =
"npub15jnttpymeytm80hatjqcvhhqhzrhx6gxp8pq0wn93rhnu8s9h9dsha32lx";
const RELAYS = [
"wss://relay.snort.social",
"wss://relay.damus.io",
"wss://relay.primal.net",
"wss://nos.lol",
];
const pool = new SimplePool();
document
.getElementById("bug-form")
.addEventListener("submit", async (ev) => {
ev.preventDefault();
clear();
try {
// Section 1: User Information
const userNpub = document.getElementById("userNpub").value.trim();
// Anti-spam: npub is optional here, but if provided it must be a
// valid npub so the submission can't carry free-text garbage.
if (
userNpub &&
(typeof window.validateNpubHex !== "function" ||
!window.validateNpubHex(userNpub))
) {
log(
"That Nostr public key isn't valid. Enter a valid npub1… or leave it blank. Your submission was not sent.",
"error"
);
document.getElementById("userNpub")?.focus();
return;
}
const roleNodes = document.querySelectorAll(
'input[name="userRole"]:checked'
);
let userRoles = [];
roleNodes.forEach((node) => {
userRoles.push(node.value);
});
// Section 2: Bug Details
const issueDescription = document
.getElementById("issueDescription")
.value.trim();
const stepsToReproduce = document
.getElementById("stepsToReproduce")
.value.trim();
const expectedBehavior = document
.getElementById("expectedBehavior")
.value.trim();
const actualBehavior = document
.getElementById("actualBehavior")
.value.trim();
// Section 3: Device & Environment
const deviceNodes = document.querySelectorAll(
'input[name="deviceUsed"]:checked'
);
let devicesUsed = [];
deviceNodes.forEach((node) => {
devicesUsed.push(node.value);
});
const operatingSystem = document
.getElementById("operatingSystem")
.value.trim();
const browserInfo = document
.getElementById("browserInfo")
.value.trim();
const usingVPN = document.getElementById("usingVPN").value.trim();
// Section 4: Screenshots or Logs
const screenshotInfo = document
.getElementById("screenshotInfo")
.value.trim();
const errorMessages = document
.getElementById("errorMessages")
.value.trim();
const consoleLogs = document
.getElementById("consoleLogs")
.value.trim();
// Section 5: Additional Information
const bugFrequency = document
.getElementById("bugFrequency")
.value.trim();
const impactCore = document
.getElementById("impactCore")
.value.trim();
const additionalNotes = document
.getElementById("additionalNotes")
.value.trim();
// Construct the bug report content as Markdown.
const bugReportContent = `
# **bitvid Bug Report Form**
If you have encountered a bug or technical issue on bitvid, please fill out this form to help us diagnose and resolve the problem. Providing detailed information will assist us in troubleshooting more efficiently.
## **1. User Information**
- **Nostr Public Key (npub) (optional):** ${userNpub || "N/A"}
- **Roles:** ${userRoles.length > 0 ? userRoles.join(", ") : "N/A"}
## **2. Bug Details**
- **Describe the issue:**
${issueDescription || "N/A"}
- **Steps to reproduce the bug:**
${stepsToReproduce || "N/A"}
- **Expected behavior:**
${expectedBehavior || "N/A"}
- **Actual behavior:**
${actualBehavior || "N/A"}
## **3. Device & Environment**
- **Devices used:** ${devicesUsed.length > 0 ? devicesUsed.join(", ") : "N/A"}
- **Operating System:** ${operatingSystem || "N/A"}
- **Browser:** ${browserInfo || "N/A"}
- **Using VPN/Privacy Settings:** ${usingVPN || "N/A"}
## **4. Screenshots or Logs**
- **Screenshot/Recording:** ${screenshotInfo || "N/A"}
- **Error Messages:** ${errorMessages || "N/A"}
- **Console Logs:** ${consoleLogs || "N/A"}
## **5. Additional Information**
- **Bug Frequency:** ${bugFrequency || "N/A"}
- **Impact on Core Functionality:** ${impactCore || "N/A"}
- **Additional Notes:** ${additionalNotes || "N/A"}
---
**Processing & Resolution:**
Our team reviews bug reports regularly. While we aim to fix critical issues as soon as possible, some bugs may take longer to resolve. We appreciate your patience and help in improving bitvid!
For urgent issues, contact us through bitvid’s Nostr support channels.
`.trim();
log(
"[DEBUG] Constructed bug report content:\n" + bugReportContent
);
// Decode the recipient NPUB to get the public key.
log("Decoding recipient npub...");
const decoded = nip19.decode(recipientNpub);
log("[DEBUG] Decoded npub: " + JSON.stringify(decoded));
if (decoded.type !== "npub") {
throw new Error("Decoded type is not npub.");
}
const targetPubHex = decoded.data;
log("Recipient pubkey: " + targetPubHex.slice(0, 16) + "...");
// Generate an ephemeral key pair.
log("Generating ephemeral key...");
const ephemeralPriv = generateSecretKey();
const ephemeralPubHex = getPublicKey(ephemeralPriv);
log("Ephemeral pubkey: " + ephemeralPubHex.slice(0, 16) + "...");
// Build a structured bitvid submission (kind 30083, PUBLIC — no
// encryption). Published from the ephemeral key.
const now = Math.floor(Date.now() / 1000);
const submissionId =
"sub-" +
now.toString(36) +
"-" +
Math.random().toString(36).slice(2, 10);
const tags = [
["d", submissionId],
["k", "bug"],
];
if (userNpub) {
tags.push(["applicant", userNpub]);
}
tags.push(
["p", targetPubHex],
["t", "bitvid-submission"],
["client", "bitvid"]
);
const eventTemplate = {
kind: 30083,
created_at: now,
tags,
content: bugReportContent,
};
log(
"[DEBUG] Event template before finalizing: " +
JSON.stringify(eventTemplate)
);
// Finalize the event.
const event = finalizeEvent(eventTemplate, ephemeralPriv);
log("[DEBUG] Final event: " + JSON.stringify(event));
// Publish the event to all relays.
log("Publishing the bug report to relays...");
await Promise.any(pool.publish(RELAYS, event));
log("At least one relay accepted the event.", "success");
// Subscribe to each relay.
for (const url of RELAYS) {
log("Connecting to " + url + " for subscription...");
const relay = await Relay.connect(url);
relay.subscribe([{ authors: [ephemeralPubHex], kinds: [30083] }], {
onEvent(foundEvent) {
if (foundEvent.id === event.id) {
log(
"[" +
url +
"] => Found our bug report in storage! ID: " +
foundEvent.id.slice(0, 8) +
"...",
"success"
);
}
},
onEose() {
relay.close();
},
});
}
log(
"Done. If the logs show that at least one relay accepted the event and the bug report was found in storage, our team will review your report within 7-14 days."
);
} catch (err) {
log("Error: " + err.message, "error");
user.error(err);
}
});
});
</script>
<div id="uiOverlay" data-overlay-root aria-hidden="true"></div>
</body>
</html>