mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
- Add fuzz testing scripts for `nostrEventSchemas.js`, `dmDecryptor.js`, and `magnetUtils.js` in `scripts/agent/`. - Fix `build...` functions in `nostrEventSchemas.js` to handle `null`/`undefined` inputs. - Fix `buildVideoPostEvent` to gracefully handle circular references in content serialization. - Fix `normalizeAndAugmentMagnet` in `magnetUtils.js` to handle non-iterable `extraTrackers`. - Include minimal reproducers for discovered crashes in `examples/reproducers/`.
241 lines
7.9 KiB
JavaScript
241 lines
7.9 KiB
JavaScript
|
|
import {
|
|
buildVideoPostEvent,
|
|
buildVideoMirrorEvent,
|
|
buildRepostEvent,
|
|
buildRelayListEvent,
|
|
buildViewEvent,
|
|
buildReactionEvent,
|
|
buildCommentEvent,
|
|
buildWatchHistoryEvent,
|
|
buildSubscriptionListEvent,
|
|
buildBlockListEvent,
|
|
buildHashtagPreferenceEvent,
|
|
buildAdminListEvent,
|
|
buildStorageChallengeEvent,
|
|
sanitizeAdditionalTags,
|
|
getNostrEventSchema
|
|
} from '../../js/nostrEventSchemas.js';
|
|
import { getRandomFuzzInput, randomString, randomHex } from './fuzz-utils.mjs';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
|
|
const REPRODUCERS_DIR = 'examples/reproducers/nostrEventSchemas';
|
|
fs.mkdirSync(REPRODUCERS_DIR, { recursive: true });
|
|
|
|
const failures = [];
|
|
|
|
function recordFailure(target, input, error) {
|
|
const id = Date.now() + Math.random().toString(36).substring(7);
|
|
const filename = path.join(REPRODUCERS_DIR, `${target}-${id}.json`);
|
|
|
|
// Handle circular input for logging
|
|
let safeInput = input;
|
|
try {
|
|
JSON.stringify(input);
|
|
} catch {
|
|
safeInput = "[Circular or non-serializable input]";
|
|
}
|
|
|
|
const report = {
|
|
target,
|
|
input: safeInput,
|
|
error: {
|
|
message: error.message,
|
|
stack: error.stack
|
|
}
|
|
};
|
|
|
|
fs.writeFileSync(filename, JSON.stringify(report, null, 2));
|
|
failures.push(report);
|
|
console.error(`[FAIL] ${target}: ${error.message} (Report saved to ${filename})`);
|
|
}
|
|
|
|
function runFuzz(name, fn, inputGenerator, iterations = 1000) {
|
|
console.log(`Fuzzing ${name} for ${iterations} iterations...`);
|
|
for (let i = 0; i < iterations; i++) {
|
|
const input = inputGenerator();
|
|
try {
|
|
fn(input);
|
|
} catch (error) {
|
|
recordFailure(name, input, error);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Wrap functions that take multiple arguments or objects
|
|
const wrappers = {
|
|
buildVideoPostEvent: (input) => {
|
|
// Input is expected to be an object, but we fuzz it with anything.
|
|
// If it is an object, we fuzz its properties too.
|
|
if (typeof input === 'object' && input !== null && !Array.isArray(input)) {
|
|
buildVideoPostEvent({
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput(),
|
|
dTagValue: input.dTagValue || getRandomFuzzInput(),
|
|
content: input.content || getRandomFuzzInput(),
|
|
additionalTags: input.additionalTags || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildVideoPostEvent(input);
|
|
}
|
|
},
|
|
buildVideoMirrorEvent: (input) => {
|
|
if (typeof input === 'object' && input !== null) {
|
|
buildVideoMirrorEvent({
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput(),
|
|
tags: input.tags || getRandomFuzzInput(),
|
|
content: input.content || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildVideoMirrorEvent(input);
|
|
}
|
|
},
|
|
buildRepostEvent: (input) => {
|
|
if (typeof input === 'object' && input !== null) {
|
|
buildRepostEvent({
|
|
...input,
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildRepostEvent(input);
|
|
}
|
|
},
|
|
buildRelayListEvent: (input) => {
|
|
if (typeof input === 'object' && input !== null) {
|
|
buildRelayListEvent({
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput(),
|
|
relays: input.relays || getRandomFuzzInput(),
|
|
additionalTags: input.additionalTags || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildRelayListEvent(input);
|
|
}
|
|
},
|
|
buildViewEvent: (input) => {
|
|
if (typeof input === 'object' && input !== null) {
|
|
buildViewEvent({
|
|
...input,
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildViewEvent(input);
|
|
}
|
|
},
|
|
buildReactionEvent: (input) => {
|
|
if (typeof input === 'object' && input !== null) {
|
|
buildReactionEvent({
|
|
...input,
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildReactionEvent(input);
|
|
}
|
|
},
|
|
buildCommentEvent: (input) => {
|
|
if (typeof input === 'object' && input !== null) {
|
|
buildCommentEvent({
|
|
...input,
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildCommentEvent(input);
|
|
}
|
|
},
|
|
buildWatchHistoryEvent: (input) => {
|
|
if (typeof input === 'object' && input !== null) {
|
|
buildWatchHistoryEvent({
|
|
...input,
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildWatchHistoryEvent(input);
|
|
}
|
|
},
|
|
buildSubscriptionListEvent: (input) => {
|
|
if (typeof input === 'object' && input !== null) {
|
|
buildSubscriptionListEvent({
|
|
...input,
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildSubscriptionListEvent(input);
|
|
}
|
|
},
|
|
buildBlockListEvent: (input) => {
|
|
if (typeof input === 'object' && input !== null) {
|
|
buildBlockListEvent({
|
|
...input,
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildBlockListEvent(input);
|
|
}
|
|
},
|
|
buildHashtagPreferenceEvent: (input) => {
|
|
if (typeof input === 'object' && input !== null) {
|
|
buildHashtagPreferenceEvent({
|
|
...input,
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildHashtagPreferenceEvent(input);
|
|
}
|
|
},
|
|
buildAdminListEvent: (input) => {
|
|
// expects listKey and params
|
|
const key = getRandomFuzzInput();
|
|
if (typeof input === 'object' && input !== null) {
|
|
buildAdminListEvent(key, {
|
|
...input,
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildAdminListEvent(key, input);
|
|
}
|
|
},
|
|
buildStorageChallengeEvent: (input) => {
|
|
if (typeof input === 'object' && input !== null) {
|
|
buildStorageChallengeEvent({
|
|
...input,
|
|
pubkey: input.pubkey || getRandomFuzzInput(),
|
|
created_at: input.created_at || getRandomFuzzInput()
|
|
});
|
|
} else {
|
|
buildStorageChallengeEvent(input);
|
|
}
|
|
},
|
|
sanitizeAdditionalTags: (input) => {
|
|
sanitizeAdditionalTags(input);
|
|
},
|
|
getNostrEventSchema: (input) => {
|
|
getNostrEventSchema(input);
|
|
}
|
|
};
|
|
|
|
// Main execution
|
|
Object.entries(wrappers).forEach(([name, fn]) => {
|
|
runFuzz(name, fn, getRandomFuzzInput);
|
|
});
|
|
|
|
// Write summary
|
|
fs.writeFileSync('artifacts/fuzz-report-nostrEventSchemas.json', JSON.stringify(failures, null, 2));
|
|
if (failures.length > 0) {
|
|
console.log(`\nFuzzing finished with ${failures.length} failures.`);
|
|
process.exit(1);
|
|
} else {
|
|
console.log("\nFuzzing finished with 0 failures.");
|
|
process.exit(0);
|
|
}
|