This commit is contained in:
Keep Creating Online
2025-02-03 17:33:16 -05:00
parent 2f90f845a2
commit f5e3484cbc
12 changed files with 1425 additions and 810 deletions

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8" />
<title>bitvid Whitelist Application Form</title>
<!-- Link to your main stylesheet -->
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="../../css/style.css" />
<style>
/* Override for form page to match modal field styling */
@@ -42,7 +42,7 @@
display: block;
margin-top: 1em;
font-weight: bold;
color: #E5E7EB; /* Tailwind's text-gray-200 */
color: #e5e7eb; /* Tailwind's text-gray-200 */
}
/* Input, textarea, select mimic modal field styles */
@@ -51,8 +51,8 @@
select {
width: 100%;
margin-bottom: 0.75em;
background-color: #1F2937; /* Tailwind's bg-gray-800 */
color: #F3F4F6; /* Tailwind's text-gray-100 */
background-color: #1f2937; /* Tailwind's bg-gray-800 */
color: #f3f4f6; /* Tailwind's text-gray-100 */
border: 1px solid #374151; /* Tailwind's border-gray-700 */
padding: 0.5em;
border-radius: 0.375rem; /* rounded-md */
@@ -62,9 +62,9 @@
input:focus,
textarea:focus,
select:focus {
border-color: #3B82F6; /* blue-500 */
border-color: #3b82f6; /* blue-500 */
outline: none;
box-shadow: 0 0 0 1px #3B82F6;
box-shadow: 0 0 0 1px #3b82f6;
}
/* Style for checkboxes display inline with a label */
@@ -77,7 +77,7 @@
/* Button styled similarly to modal publish button */
button {
padding: 0.5em 1em;
background: #3B82F6; /* blue-500 */
background: #3b82f6; /* blue-500 */
color: #fff;
border: none;
border-radius: 0.375rem;
@@ -97,13 +97,13 @@
margin: 0.25em 0;
}
.error {
color: #F87171; /* a red tint */
color: #f87171; /* a red tint */
}
.success {
color: #3B82F6; /* blue-500 */
color: #3b82f6; /* blue-500 */
}
.warn {
color: #FACC15; /* a yellow tone */
color: #facc15; /* a yellow tone */
}
/* Custom Scrollbar styling for WebKit browsers */
@@ -115,13 +115,13 @@
background: transparent;
}
::-webkit-scrollbar-thumb {
background-color: #3B82F6;
background-color: #3b82f6;
border-radius: 4px;
}
/* Custom Scrollbar styling for Firefox */
* {
scrollbar-width: thin;
scrollbar-color: #3B82F6 transparent;
scrollbar-color: #3b82f6 transparent;
}
</style>
<!-- Load nostrtools v2.10.4 -->
@@ -131,72 +131,163 @@
<div class="container">
<div class="form-container">
<p>
bitvid is currently in early access. If you would like to request access, please fill out this application. Applications will be reviewed manually, and approvals will be based on alignment with bitvids community values.
bitvid is currently in early access. If you would like to request
access, please fill out this application. Applications will be
reviewed manually, and approvals will be based on alignment with
bitvids community values.
</p>
<form id="wl-form">
<!-- 1. Applicant Information -->
<h2>1. Applicant Information</h2>
<label for="applicantNpub">Nostr Public Key (npub):</label>
<input type="text" id="applicantNpub" placeholder="Enter your npub" required />
<input
type="text"
id="applicantNpub"
placeholder="Enter your npub"
required
/>
<label for="contactMethod">Preferred Contact Method (if applicable):</label>
<input type="text" id="contactMethod" placeholder="Nostr DM, email, or other" />
<label for="contactMethod"
>Preferred Contact Method (if applicable):</label
>
<input
type="text"
id="contactMethod"
placeholder="Nostr DM, email, or other"
/>
<label for="username">Username or Alias (if applicable):</label>
<input type="text" id="username" placeholder="Enter your preferred name" />
<input
type="text"
id="username"
placeholder="Enter your preferred name"
/>
<!-- 2. Content Intent -->
<h2>2. Content Intent</h2>
<p>What type of content do you plan to upload? (Check all that apply)</p>
<p>
What type of content do you plan to upload? (Check all that apply)
</p>
<div class="checkbox-group">
<label><input type="checkbox" name="contentType" value="Educational" /> Educational</label>
<label><input type="checkbox" name="contentType" value="Entertainment" /> Entertainment</label>
<label><input type="checkbox" name="contentType" value="News & Journalism" /> News & Journalism</label>
<label><input type="checkbox" name="contentType" value="Creative Works" /> Creative Works</label>
<label><input type="checkbox" name="contentType" value="Discussions & Opinions" /> Discussions & Opinions</label>
<label><input type="checkbox" name="contentType" value="Other" /> Other</label>
<label
><input type="checkbox" name="contentType" value="Educational" />
Educational</label
>
<label
><input
type="checkbox"
name="contentType"
value="Entertainment"
/>
Entertainment</label
>
<label
><input
type="checkbox"
name="contentType"
value="News & Journalism"
/>
News & Journalism</label
>
<label
><input
type="checkbox"
name="contentType"
value="Creative Works"
/>
Creative Works</label
>
<label
><input
type="checkbox"
name="contentType"
value="Discussions & Opinions"
/>
Discussions & Opinions</label
>
<label
><input type="checkbox" name="contentType" value="Other" />
Other</label
>
</div>
<label for="otherContent">Other (please specify):</label>
<input type="text" id="otherContent" placeholder="Describe if Other was selected" />
<input
type="text"
id="otherContent"
placeholder="Describe if Other was selected"
/>
<label for="whyJoin">Why do you want to join bitvid?</label>
<textarea id="whyJoin" rows="3" placeholder="Explain your motivation"></textarea>
<textarea
id="whyJoin"
rows="3"
placeholder="Explain your motivation"
></textarea>
<label for="priorExperience">Have you created content on other platforms before?</label>
<label for="priorExperience"
>Have you created content on other platforms before?</label
>
<select id="priorExperience">
<option value="">Select an option</option>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<label for="experienceLinks">If yes, provide links or references to your previous work:</label>
<textarea id="experienceLinks" rows="2" placeholder="Paste links or describe your work"></textarea>
<label for="experienceLinks"
>If yes, provide links or references to your previous work:</label
>
<textarea
id="experienceLinks"
rows="2"
placeholder="Paste links or describe your work"
></textarea>
<!-- 3. Community Engagement -->
<h2>3. Community Engagement</h2>
<label for="familiarGuidelines">Are you familiar with bitvids Community Guidelines?</label>
<label for="familiarGuidelines"
>Are you familiar with bitvids Community Guidelines?</label
>
<select id="familiarGuidelines">
<option value="">Select an option</option>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<label for="agreeGuidelines">Do you agree to follow the guidelines and respect decentralized moderation?</label>
<label for="agreeGuidelines"
>Do you agree to follow the guidelines and respect decentralized
moderation?</label
>
<select id="agreeGuidelines">
<option value="">Select an option</option>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<label for="communityContribution">How do you plan to contribute positively to the bitvid community?</label>
<textarea id="communityContribution" rows="3" placeholder="Explain your approach"></textarea>
<label for="communityContribution"
>How do you plan to contribute positively to the bitvid
community?</label
>
<textarea
id="communityContribution"
rows="3"
placeholder="Explain your approach"
></textarea>
<!-- 4. Additional Information -->
<h2>4. Additional Information</h2>
<label for="specialSkills">Do you have any special skills or interests that could help improve bitvid?</label>
<textarea id="specialSkills" rows="3" placeholder="e.g., software development, moderation, design, advocacy"></textarea>
<label for="specialSkills"
>Do you have any special skills or interests that could help improve
bitvid?</label
>
<textarea
id="specialSkills"
rows="3"
placeholder="e.g., software development, moderation, design, advocacy"
></textarea>
<label for="testFeatures">Would you be interested in helping test new features?</label>
<label for="testFeatures"
>Would you be interested in helping test new features?</label
>
<select id="testFeatures">
<option value="">Select an option</option>
<option value="Yes">Yes</option>
@@ -207,9 +298,10 @@
<h2>5. Declaration</h2>
<p>
By submitting this application, you confirm that:
<br />- The information provided is accurate.
<br />- You understand that approval is based on community alignment and available capacity.
<br />- You acknowledge that whitelist status may be revoked if guidelines are violated.
<br />- The information provided is accurate. <br />- You understand
that approval is based on community alignment and available
capacity. <br />- You acknowledge that whitelist status may be
revoked if guidelines are violated.
</p>
<label for="signature">Signature (Digital or Written):</label>
<input type="text" id="signature" placeholder="Your signature" />
@@ -242,53 +334,90 @@
log("NostrTools not loaded. Check console or ad-blockers.", "error");
return;
}
const { generateSecretKey, getPublicKey, finalizeEvent, nip04, nip19, SimplePool, Relay } = window.NostrTools;
const {
generateSecretKey,
getPublicKey,
finalizeEvent,
nip04,
nip19,
SimplePool,
Relay,
} = window.NostrTools;
// Set the recipient's NPUB (your personal NPUB) here.
const recipientNpub = "npub13yarr7j6vjqjjkahd63dmr27curypehx45ucue286ac7sft27y0srnpmpe";
const recipientNpub =
"npub13yarr7j6vjqjjkahd63dmr27curypehx45ucue286ac7sft27y0srnpmpe";
const RELAYS = [
"wss://relay.snort.social",
"wss://relay.damus.io",
"wss://relay.primal.net"
"wss://relay.primal.net",
];
const pool = new SimplePool();
document.getElementById("wl-form").addEventListener("submit", async (ev) => {
ev.preventDefault();
clear();
try {
// Retrieve applicant-provided input.
const applicantNpub = document.getElementById("applicantNpub").value.trim();
const contactMethod = document.getElementById("contactMethod").value.trim();
const username = document.getElementById("username").value.trim();
document
.getElementById("wl-form")
.addEventListener("submit", async (ev) => {
ev.preventDefault();
clear();
try {
// Retrieve applicant-provided input.
const applicantNpub = document
.getElementById("applicantNpub")
.value.trim();
const contactMethod = document
.getElementById("contactMethod")
.value.trim();
const username = document.getElementById("username").value.trim();
// Section 2: Content Intent
// Get all checked content types
const contentTypeNodes = document.querySelectorAll('input[name="contentType"]:checked');
let contentTypes = [];
contentTypeNodes.forEach((node) => {
contentTypes.push(node.value);
});
const otherContent = document.getElementById("otherContent").value.trim();
const whyJoin = document.getElementById("whyJoin").value.trim();
const priorExperience = document.getElementById("priorExperience").value.trim();
const experienceLinks = document.getElementById("experienceLinks").value.trim();
// Section 2: Content Intent
// Get all checked content types
const contentTypeNodes = document.querySelectorAll(
'input[name="contentType"]:checked'
);
let contentTypes = [];
contentTypeNodes.forEach((node) => {
contentTypes.push(node.value);
});
const otherContent = document
.getElementById("otherContent")
.value.trim();
const whyJoin = document.getElementById("whyJoin").value.trim();
const priorExperience = document
.getElementById("priorExperience")
.value.trim();
const experienceLinks = document
.getElementById("experienceLinks")
.value.trim();
// Section 3: Community Engagement
const familiarGuidelines = document.getElementById("familiarGuidelines").value.trim();
const agreeGuidelines = document.getElementById("agreeGuidelines").value.trim();
const communityContribution = document.getElementById("communityContribution").value.trim();
// Section 3: Community Engagement
const familiarGuidelines = document
.getElementById("familiarGuidelines")
.value.trim();
const agreeGuidelines = document
.getElementById("agreeGuidelines")
.value.trim();
const communityContribution = document
.getElementById("communityContribution")
.value.trim();
// Section 4: Additional Information
const specialSkills = document.getElementById("specialSkills").value.trim();
const testFeatures = document.getElementById("testFeatures").value.trim();
// Section 4: Additional Information
const specialSkills = document
.getElementById("specialSkills")
.value.trim();
const testFeatures = document
.getElementById("testFeatures")
.value.trim();
// Section 5: Declaration
const signature = document.getElementById("signature").value.trim();
const declarationDate = document.getElementById("declarationDate").value.trim();
// Section 5: Declaration
const signature = document
.getElementById("signature")
.value.trim();
const declarationDate = document
.getElementById("declarationDate")
.value.trim();
// Construct the whitelist application content.
const applicationContent = `
// Construct the whitelist application content.
const applicationContent = `
# **bitvid Whitelist Application Form**
**1. Applicant Information**
@@ -301,13 +430,19 @@
- **Other (if applicable):** ${otherContent || "N/A"}
- **Why do you want to join bitvid?**
${whyJoin || "N/A"}
- **Have you created content on other platforms before?** ${priorExperience || "N/A"}
- **Have you created content on other platforms before?** ${
priorExperience || "N/A"
}
- **Links or references to your previous work:**
${experienceLinks || "N/A"}
**3. Community Engagement**
- **Familiar with bitvids Community Guidelines?** ${familiarGuidelines || "N/A"}
- **Agree to follow guidelines and respect moderation?** ${agreeGuidelines || "N/A"}
- **Familiar with bitvids Community Guidelines?** ${
familiarGuidelines || "N/A"
}
- **Agree to follow guidelines and respect moderation?** ${
agreeGuidelines || "N/A"
}
- **How do you plan to contribute to the community?**
${communityContribution || "N/A"}
@@ -332,71 +467,90 @@ By submitting this application, you confirm that:
For further questions, contact us through bitvids Nostr support channels.
`.trim();
log("[DEBUG] Constructed application content:\n" + applicationContent);
log(
"[DEBUG] Constructed application content:\n" +
applicationContent
);
// 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.");
// 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) + "...");
// Encrypt the application content.
log("Encrypting application content (nip04)...");
const ciphertext = await nip04.encrypt(
ephemeralPriv,
targetPubHex,
applicationContent
);
log("[DEBUG] Ciphertext: " + ciphertext);
log("Encryption done.");
// Build the Nostr event template.
const now = Math.floor(Date.now() / 1000);
const eventTemplate = {
kind: 4,
created_at: now,
tags: [["p", targetPubHex]],
content: ciphertext,
};
log(
"[DEBUG] Event template before finalizing: " +
JSON.stringify(eventTemplate)
);
// Finalize the event (computing the id and signature).
const event = finalizeEvent(eventTemplate, ephemeralPriv);
log("[DEBUG] Final event: " + JSON.stringify(event));
// Publish the event to all relays.
log("Publishing the application to relays...");
await Promise.any(pool.publish(RELAYS, event));
log("At least one relay accepted the event.", "success");
// For each relay, subscribe to verify the event appears.
for (const url of RELAYS) {
log("Connecting to " + url + " for subscription...");
const relay = await Relay.connect(url);
relay.subscribe([{ authors: [ephemeralPubHex], kinds: [4] }], {
onEvent(foundEvent) {
if (foundEvent.id === event.id) {
log(
"[" +
url +
"] => Found our application 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 application was found in storage, a moderator will review your application within 7-14 days."
);
} catch (err) {
log("Error: " + err.message, "error");
console.error(err);
}
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) + "...");
// Encrypt the application content.
log("Encrypting application content (nip04)...");
const ciphertext = await nip04.encrypt(ephemeralPriv, targetPubHex, applicationContent);
log("[DEBUG] Ciphertext: " + ciphertext);
log("Encryption done.");
// Build the Nostr event template.
const now = Math.floor(Date.now() / 1000);
const eventTemplate = {
kind: 4,
created_at: now,
tags: [["p", targetPubHex]],
content: ciphertext,
};
log("[DEBUG] Event template before finalizing: " + JSON.stringify(eventTemplate));
// Finalize the event (computing the id and signature).
const event = finalizeEvent(eventTemplate, ephemeralPriv);
log("[DEBUG] Final event: " + JSON.stringify(event));
// Publish the event to all relays.
log("Publishing the application to relays...");
await Promise.any(pool.publish(RELAYS, event));
log("At least one relay accepted the event.", "success");
// For each relay, subscribe to verify the event appears.
for (const url of RELAYS) {
log("Connecting to " + url + " for subscription...");
const relay = await Relay.connect(url);
relay.subscribe([{ authors: [ephemeralPubHex], kinds: [4] }], {
onEvent(foundEvent) {
if (foundEvent.id === event.id) {
log("[" + url + "] => Found our application 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 application was found in storage, a moderator will review your application within 7-14 days.");
} catch (err) {
log("Error: " + err.message, "error");
console.error(err);
}
});
});
});
</script>
</body>