mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-02 19:02:28 +00:00
feat(forms): validate submitter npub on submission forms (#22)
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]>
This commit is contained in:
1 parent
fdcf034464
commit
e4e5c552c7
7 files changed
+203
-5
No files matched your search
@@ -0,0 +1,60 @@
|
||||
// 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;
|
||||
Reference in new issue
Block a user