Files
bitvid/scripts/agent/fuzz-nostr-schemas.mjs
T
google-labs-jules[bot] 5c2e9cd7f8 feat: add fuzz testing harness and fix repost builder
- Created generic fuzzing library `scripts/agent/fuzz-lib.mjs`.
- Implemented fuzz targets for `nostrEventSchemas.js`, `dmDecryptor.js`, and `magnetUtils.js`.
- Fixed `buildRepostEvent` to allow missing relay URLs for robustness.
- Added crash reproducers to `examples/reproducers/`.
2026-01-20 16:42:46 +00:00

107 lines
3.4 KiB
JavaScript

import { Fuzzer } from "./fuzz-lib.mjs";
import * as schemas from "../../js/nostrEventSchemas.js";
// Mock global dependencies if needed
if (typeof global.window === "undefined") {
global.window = {};
}
const fuzzer = new Fuzzer("nostr-schemas");
// Builders take a params object.
const builders = [
"buildVideoPostEvent",
"buildVideoMirrorEvent",
"buildRepostEvent",
"buildRelayListEvent",
"buildDmRelayListEvent",
"buildProfileMetadataEvent",
"buildMuteListEvent",
"buildDmAttachmentEvent",
"buildDmReadReceiptEvent",
"buildDmTypingIndicatorEvent",
"buildViewEvent",
"buildZapRequestEvent",
"buildReactionEvent",
"buildCommentEvent",
"buildWatchHistoryEvent",
"buildSubscriptionListEvent",
"buildBlockListEvent",
"buildHashtagPreferenceEvent",
];
async function test(fuzzer, state) {
const action = fuzzer.randInt(0, 3);
let input = {};
if (action === 0) {
// Fuzz sanitizeAdditionalTags
const tags = fuzzer.randArray(() => {
if (fuzzer.randBool()) {
return fuzzer.randArray(() => fuzzer.randString(10), 0, 5);
} else {
return fuzzer.randJSON(); // Garbage
}
}, 0, 20);
input = { target: "sanitizeAdditionalTags", tags };
state.input = input;
schemas.sanitizeAdditionalTags(tags);
} else if (action === 1) {
// Fuzz validateEventAgainstSchema
const types = Object.keys(schemas.NOTE_TYPES);
const type = fuzzer.pick(types);
const event = {
kind: fuzzer.randInt(0, 40000),
content: fuzzer.randUnicodeString(100),
tags: fuzzer.randArray(() => fuzzer.randArray(() => fuzzer.randString(10), 0, 5), 0, 10),
pubkey: fuzzer.randString(64, "0123456789abcdef"),
created_at: Math.floor(Date.now() / 1000)
};
// Mutate event
if (fuzzer.randBool()) event.content = fuzzer.randJSON();
if (fuzzer.randBool()) event.tags = "not an array";
input = { target: "validateEventAgainstSchema", type, event };
state.input = input;
schemas.validateEventAgainstSchema(type, event);
} else if (action === 2) {
// Fuzz Builders
const builderName = fuzzer.pick(builders);
const builderFn = schemas[builderName];
// Generate random params
const params = fuzzer.randObject({
pubkey: () => fuzzer.randString(64, "0123456789abcdef"),
created_at: () => Math.floor(Date.now() / 1000),
content: () => fuzzer.randUnicodeString(50),
additionalTags: () => fuzzer.randArray(() => [fuzzer.randString(5), fuzzer.randString(10)], 0, 5),
dTagValue: () => fuzzer.randString(10),
eventId: () => fuzzer.randString(64, "0123456789abcdef"),
// Add more random keys that might be expected or unexpected
[fuzzer.randString(5)]: () => fuzzer.randJSON()
});
input = { target: builderName, params };
state.input = input;
if (typeof builderFn === "function") {
builderFn(params);
}
} else if (action === 3) {
// buildAdminListEvent special case
const listKey = fuzzer.pick(["moderation", "editors", "whitelist", "blacklist", fuzzer.randString(5)]);
const params = {
pubkey: fuzzer.randString(64, "0123456789abcdef"),
hexPubkeys: fuzzer.randArray(() => fuzzer.randString(64, "0123456789abcdef"), 0, 5)
};
input = { target: "buildAdminListEvent", listKey, params };
state.input = input;
schemas.buildAdminListEvent(listKey, params);
}
}
fuzzer.runFuzzLoop(2000, test);