mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
The embed submission forms accepted any free-text identifier and published it, so they were an easy spam vector. Add a shared, testable NIP-19 validator and require a well-formed npub before a submission is sent. - js/utils/validateNpub.js: validateNpubHex() decodes via nostr-tools nip19 and returns the 64-char hex pubkey, or null for anything that isn't a real npub (free text, wrong prefix, bad checksum, wrong NIP-19 entity). Also exposed as window.validateNpubHex for the classic iframe form scripts. - Application form (required npub): submit is blocked unless valid; the decoded hex is written into the application body for canonical storage/matching. - Feature-request / bug-fix / feedback (optional npub): stays optional, but a non-empty value must be a valid npub or submit is blocked with an inline error. - Tests: tests/validate-npub.test.mjs (real nostr-tools, no implementation mirror). Co-Authored-By: Claude Opus 4.8 <[email protected]>
61 lines
2.0 KiB
JavaScript
61 lines
2.0 KiB
JavaScript
// Shared, anti-spam npub (NIP-19) validation for the embed submission forms
|
|
// (application / feature-request / bug-fix / feedback). A submission identifier
|
|
// is only accepted if it decodes to a canonical 64-char hex pubkey, so the forms
|
|
// stop publishing free-text garbage.
|
|
//
|
|
// Usable two ways:
|
|
// - import { validateNpubHex } from "../utils/validateNpub.js" (tests / app)
|
|
// - as a classic global in the iframe forms: window.validateNpubHex(value)
|
|
// (the module assigns the global below and resolves nostr-tools at call time
|
|
// from window.NostrTools, which the forms already load).
|
|
|
|
/**
|
|
* Decode a user-entered npub and return its hex pubkey, or null if it isn't a
|
|
* well-formed npub.
|
|
*
|
|
* @param {string} value Raw input (may include surrounding whitespace).
|
|
* @param {{ nip19?: { decode: Function } }} [deps] Inject a nip19 implementation
|
|
* (defaults to the global NostrTools bundle the embed forms load).
|
|
* @returns {string|null} 64-char lowercase hex pubkey, or null when invalid.
|
|
*/
|
|
export function validateNpubHex(value, { nip19 } = {}) {
|
|
const decoder =
|
|
nip19 ||
|
|
(typeof globalThis !== "undefined" ? globalThis.NostrTools?.nip19 : null);
|
|
|
|
if (typeof value !== "string") {
|
|
return null;
|
|
}
|
|
const trimmed = value.trim();
|
|
if (!trimmed.startsWith("npub1")) {
|
|
return null;
|
|
}
|
|
if (!decoder || typeof decoder.decode !== "function") {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
const decoded = decoder.decode(trimmed);
|
|
if (
|
|
decoded &&
|
|
decoded.type === "npub" &&
|
|
typeof decoded.data === "string" &&
|
|
/^[0-9a-f]{64}$/.test(decoded.data)
|
|
) {
|
|
return decoded.data;
|
|
}
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
if (typeof globalThis !== "undefined") {
|
|
// Expose to the iframe forms' classic inline scripts. Resolves NostrTools at
|
|
// call time, so load order relative to the nostr-tools bundle doesn't matter.
|
|
globalThis.validateNpubHex = (value) => validateNpubHex(value);
|
|
}
|
|
|
|
export default validateNpubHex;
|