mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
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/`.
This commit is contained in:
1 parent
5726997475
commit
5c2e9cd7f8
26 files changed
+1041
-3
No files matched your search
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"hash": "18c960c07a1b14b0",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "211f1794817bb9666b6c4efa29c91560f72ceab6cb4b64088d08d14f470996b6",
|
||||
"content": "젴㨁ၱ괚æ\udb40麗ሉ傯\uda90뷉呉\udae4戩廈\udfd1갓賏\uda06굦ꪉ璔믡」십쑴떣笓˸\udc5a\udae2烜\ud950䧾䍂땃挠줁鐼屎\uddc3튏锄\udd4e\ude2c傏",
|
||||
"additionalTags": [
|
||||
[
|
||||
"q77wm",
|
||||
"fSO71LLMPq"
|
||||
]
|
||||
],
|
||||
"dTagValue": "hSAuaQM2FZ",
|
||||
"eventId": "7261d7919e592b16974bc6d0c043eb6321c83d78844ea4c30357ade246032aa2",
|
||||
"cxosb": 8411.55359292702
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.506Z"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"hash": "227e8db93b7456c9",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "cc401e3196abdc664a40862d3cd9025af82aa2ac55bbee7e69c7faefbd81cb74",
|
||||
"created_at": 1768926859,
|
||||
"content": "ꔳ幰\udbc7岽\udef9\udea2㦉땮\udeee䏓ᄁ⡏ﱳ䋯䓙\udaed굘ӹ旎⎪\udee6紌\udd16瑩Ꟈ\udf75鎍⑩ᭌ瘫ǻ刧敃摢穃翂櫵ᙾ拷젙\uddb3\udeb7씰\udc28␋\udfa4軤",
|
||||
"additionalTags": [
|
||||
[
|
||||
"OGAEp",
|
||||
"sCThZka3DJ"
|
||||
],
|
||||
[
|
||||
"elm64",
|
||||
"uN1X33bJV2"
|
||||
]
|
||||
],
|
||||
"dTagValue": "OAOTVCvayE",
|
||||
"eventId": "c5c0e46d9c509a99eaa7b237dd7e9741e07bf9fe424d83aaaab1f5c68ca810e3"
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.531Z"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"hash": "2388d33b32f5dd1f",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "576173493bdf93c35219b1a1e842fd06493d6ca8a7e652f37e3e9e1dfdc03a74",
|
||||
"created_at": 1768926859,
|
||||
"content": "薁睶\ude68㩻﵆\udd0e菕
挠\ude84tℋ䂖騺鍱\udb31ᜧά갛\udc08\udcd4㐟䗝㲳忠\uda44⯒狙뻡㩼餵睊琻塘\udfbe\udb02鱫瀭鄉\udde3삭鲢䤫圢\udb48ᗷ\ude96",
|
||||
"dTagValue": "NVe9A407cH",
|
||||
"eventId": "7f6cf3739e77207b2d5f9f2aacb90fac8545125e372775e551716e184e2c63f9",
|
||||
"cpmtW": null
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.543Z"
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"hash": "2d038dd6ff3603e4",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "d33cbc19b939f4c690253ba9586c0762968fb9cfcffcd085f1251441a51c737a",
|
||||
"created_at": 1768926859,
|
||||
"additionalTags": [
|
||||
[
|
||||
"EEL1e",
|
||||
"Zr5ZuL4HR8"
|
||||
],
|
||||
[
|
||||
"Q2rEl",
|
||||
"tTrkEYP54t"
|
||||
],
|
||||
[
|
||||
"upLL8",
|
||||
"AoPmhLHLNv"
|
||||
]
|
||||
],
|
||||
"dTagValue": "VR73sR2X8M",
|
||||
"eventId": "87e7c3605c9a88ef9d9e3984e7e6b49d3a790e746a35bbcb3157695828615e6a"
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.549Z"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"hash": "7d28c8f4e78c2a83",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "d1f3b06f1f9ab423b6bbcb9b9b8ae956e21893bdb09feba59cc01f451e92ae95",
|
||||
"content": "졹즮ﮕ냿㦫斮냲Ѻ㝫翗\udee3瑌⡚㢴\udb99刭繐시둥睧襼ﹶꃛꃿ哉狏騣隚䰰₤\udacf☯刴\udcc2搧\udce8㚲䜼傫ꦖ勃뱭",
|
||||
"additionalTags": [
|
||||
[
|
||||
"iVEpY",
|
||||
"Sm5vcAEAuR"
|
||||
],
|
||||
[
|
||||
"Ui2Kv",
|
||||
"C3lqEHkIIf"
|
||||
]
|
||||
],
|
||||
"dTagValue": "5M3K7s1CZ3",
|
||||
"eventId": "1428c4a55f48084251e0c8899f90f045b1346abfd938897aa424227d2d16ad4c",
|
||||
"fJXSq": false
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.508Z"
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"hash": "85fde36936a9aa86",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "415eaf447da61c89b247562016620bb385c07e8b870d92c7d3d799eb300a720e",
|
||||
"created_at": 1768926859,
|
||||
"content": "锅瘜퇍\udbf7ヨ茸\udad9ꔶ궍Ⓒ\udfdc⣶ﹰ쿃咖\uda15\ud910ྀ餂뚲\udd7d蔪冷宷拉蟒綹𮭶錅死쭽뷟掴᳓ԯ縱ꏫ㺅㨼괾鯏",
|
||||
"additionalTags": [
|
||||
[
|
||||
"zGn0s",
|
||||
"YkXLolqsxO"
|
||||
]
|
||||
],
|
||||
"dTagValue": "OvQLBvFwWi",
|
||||
"eventId": "843ae1e4b92b44b37c439ebadcf3c62444dd544e266e51c45bee1535782ca20b",
|
||||
"cfiJH": {
|
||||
"obfx4": {
|
||||
"tRVaR": "倂\udaf8\udaf2ᜑ\udf10榦\ude58Ю쫪᳑礅ꈑᛖ竣皰遐伹狍致ㅧ䙠\ud97b颢萕酂侕秀㍓〧ퟮ탛\ud951Խ繶㩎",
|
||||
"oIPt2": 2116.4722459860054,
|
||||
"nYQ7a": {
|
||||
"tKuK2": "⏤췟蠚꛲昄팍朱Ừ㦄㲟킪塅\udb7b養ﭪੀꙋ珎儠罼꿇鬇ᡞ\udbde穎꣫蝿敐\udfb4⼺囱浊僵ڨ\uda97\ud8c7\ud949\ud90aᆿ\udc50\uddd6큪ꪷꁬꌉ⊢㇑\udb2c鶬槳ᐉ룧\ud862쥰ꐞ耔륥\ude7f\udf91廢阬룾\ud9ea遼祘펰涊Ꝓᆽ\udc6f𗗖狋ਸᅜ\ude1d魫碦炲붻",
|
||||
"BU1mk": "㺡ฑӢ쳁ﵑ䟫됯䠝鳚\ude01◜\udfa2蹒⋶柵\ud8d5鱍뒮᱈䝒\ud8a0섧Ọ㊓⺉횢邗玹\udf9e碊\udbda\ud8ec涁\ude12힛别걍堥㢯끂ꘀ︓\udddc孭걎셽则揽林傸독\ud934䴊蔵䉡䏐뱲椠ѕ\ude01頣꼱꼿맅謹\udae2\ud808콛玵長嘦봓暆哶죕鷱",
|
||||
"4oh3t": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.543Z"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"hash": "8d1d49645b90d7ce",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "897ba807670635e9028915f0d2a5d8dccfc3cef45dc00537013bed46915e0e2b",
|
||||
"created_at": 1768926859,
|
||||
"content": "寱嫤\udf71ᆲ褥齼㝃੨\ud839✈\udc53貂ꭣﵘᲬ잸⚩ڛ矈䛋ᵻ햙睡缳㙙\udd85䵇森즶┅䧊⌝လ㍼\udebfҩ뒮孴憅襖\ud987큜",
|
||||
"additionalTags": [
|
||||
[
|
||||
"WX2IY",
|
||||
"mpSajY2xeL"
|
||||
],
|
||||
[
|
||||
"nsM2D",
|
||||
"SdgpCEcGjK"
|
||||
],
|
||||
[
|
||||
"3Kfhr",
|
||||
"08NTDSgrSs"
|
||||
],
|
||||
[
|
||||
"0QMFV",
|
||||
"gNv4TRO4nD"
|
||||
],
|
||||
[
|
||||
"lDdW5",
|
||||
"XRC6qfbLWJ"
|
||||
]
|
||||
],
|
||||
"eventId": "8afbfbd0712f801f8dbcb769e04334ebc644b5098d9811db5e64f0b079833ffd",
|
||||
"9TAlG": null
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.517Z"
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"hash": "91f935834c393ec6",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "407827d56783cf92690806e83584f140ac020f77863bde94b98b1be645dc754b",
|
||||
"created_at": 1768926859,
|
||||
"content": "괾趞劵呆쨱ꌓ⸢\uda4a艦Ꜻ瓸ʲ㴭\ud826䵌ꆪ즜뼙䝁껊맒ꉳ裟\udc48춾讄閅㛡\uddb5䲲ᴡ䥾\ude96飽ⅻ奈턍䁑鲉骆浀워\ud983멍쇳\ud9f5폘廨\udde9",
|
||||
"additionalTags": [
|
||||
[
|
||||
"Hex9u",
|
||||
"xuTpbZTCJZ"
|
||||
],
|
||||
[
|
||||
"0Pj8H",
|
||||
"xGRidktuGx"
|
||||
],
|
||||
[
|
||||
"50YMk",
|
||||
"L6x6dP7NuV"
|
||||
],
|
||||
[
|
||||
"G6Y7w",
|
||||
"rL5ziZzTJP"
|
||||
]
|
||||
],
|
||||
"dTagValue": "698DG6ofzq",
|
||||
"eventId": "c293397373b188cd1739673a53b3441d8366e97eec0b49ce42220d7dd52ea18d"
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.532Z"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"hash": "9542c7dff1386872",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "a1f6dc0c6ed04eb5a7c445d75b235503fab159dfe2a6c81908e18de21b276629",
|
||||
"created_at": 1768926859,
|
||||
"content": "띬띔횎\ud92eⵡ濐椻绍笜\udbe0\ud9e4꒝꒕\udf63\ud829\uddde羠珠䤑ꎺ郔\uda35願쐝剨鲨妆璐녮\udac2夆㍬㒔\udc19䚝\ud9df轛㹻䛊梨骪䬼",
|
||||
"additionalTags": [
|
||||
[
|
||||
"vamZy",
|
||||
"GSc8LqPhma"
|
||||
],
|
||||
[
|
||||
"kTMoy",
|
||||
"CVvoRUIw7e"
|
||||
],
|
||||
[
|
||||
"Xhqdf",
|
||||
"A6DC90idgK"
|
||||
]
|
||||
],
|
||||
"dTagValue": "ceP4ztRvZA",
|
||||
"eventId": "6223d12f986cfb6023dec140c80720bb96457cc5847a088b02e53b606ab70e88",
|
||||
"s3KNd": false
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.566Z"
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"hash": "97b4273a8fe15fbe",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "7c3724fd1df9c80af92bbdf94217cac149df0f4d5624da9d55b9be030ef1c476",
|
||||
"created_at": 1768926859,
|
||||
"content": "䁟面\ude5b뷌ﺃ蛿\ud973\ud87a潟\ud9a3狱癉뢓䁞⺵敊睚蟬탯䒌ﳕ\udfd5䟜\udcc7\ud82d윷\ud926ྖ惻\ude45馍ﱩ龵魯莺ᴚ洨⣐\ude4a߸덻",
|
||||
"additionalTags": [
|
||||
[
|
||||
"s1OI3",
|
||||
"gdsJFyYpaq"
|
||||
],
|
||||
[
|
||||
"ZQ69f",
|
||||
"oyglX4Gl01"
|
||||
],
|
||||
[
|
||||
"NlTNs",
|
||||
"O1U4EsfdJB"
|
||||
],
|
||||
[
|
||||
"1BSQP",
|
||||
"QlFRMWP1Aw"
|
||||
],
|
||||
[
|
||||
"yM5dw",
|
||||
"x7MC08UOCO"
|
||||
]
|
||||
],
|
||||
"eventId": "145f4a20c49b9e6eb5a5da9d080a49e346db18ef87311823bfb208ddaf99337c",
|
||||
"Kta5T": {
|
||||
"sjSQd": null,
|
||||
"EAIXe": "\udccc踞㈧\udb24⧪幖⥼븛\udf03\uded1\udc6d쫙㬵﹥檛ꗧ榗퉳\udea8⢑緿汅묰宮\ud985夂䩃ᴣ殄䡎\uda14琽寮硫ᵪ꺀곭ᒕྨ䯁Ⴐ螥䱰ﴟ\uddf6\udd6aZ汼獴攳䬎䣋\udc4b堠\udf46\udb55皒\uded7ֹ硓繌칪汴䡁\uda12Თ徝벹ꉓ㩥㙰敚\udfa3",
|
||||
"shQ9t": 9712.102376936997,
|
||||
"XQ27X": {
|
||||
"JGJTu": {
|
||||
"HkOET": [
|
||||
[
|
||||
[
|
||||
true,
|
||||
null,
|
||||
true
|
||||
],
|
||||
{
|
||||
"fO3Pp": 265.33605545970175,
|
||||
"PdIMd": {
|
||||
"o4z7g": 5652.840913340699,
|
||||
"ViLwB": {
|
||||
"T7DVJ": null,
|
||||
"hEVDx": null,
|
||||
"KSJNy": {},
|
||||
"Lg5pm": "듈輳\udf16ťᰭ份毽園맋乷⏥ᡙ\udb94뵺\udd79篱랁\ud8d3ᔠ菝⊍샺헡뷾㲐澴蛊⟖\udf95̭\uddca\ud8e4碄\ud828"
|
||||
}
|
||||
},
|
||||
"ddTzu": "",
|
||||
"hAmUf": [
|
||||
{
|
||||
"AxxMA": 5577.908593874583,
|
||||
"kMpqu": {
|
||||
"9tIb0": [
|
||||
9373.082458292405,
|
||||
910.9792573057307,
|
||||
null
|
||||
],
|
||||
"KLf1v": [
|
||||
[
|
||||
true,
|
||||
[
|
||||
null
|
||||
],
|
||||
null
|
||||
]
|
||||
],
|
||||
"7lfoe": "Ⲙ榵鐶\udf22\udeeb淽\udf41\udef7㙏\udaff\udaf8猔얒\ud8ad愽귿\udad3꤭倛ꢓ禈؟䵶\uda48跓鹒గ欺ﰩ䐆Ⴟ磶\ude2e킲\ud96d퇳ѱ⡘\udfe1㒖\udf8a"
|
||||
}
|
||||
}
|
||||
],
|
||||
"kwKRg": {
|
||||
"tIRii": [],
|
||||
"ED8W0": "鋻뺕哓鈍彚簎먇\udd4eⰱꙫꂓ䏏\udc39\uda1aう\udd3e뻺\udef3욞믊\ud9b6㶶윺槠㍱㖌ᄬ틭\ude1c죲칇绌䉎ﲃ\ude5aㄸᶪ棨䂍鱌納⻇淰⢦佾뜃ﲣ嘵㈥녏蝧ﭯ\udeaa馩㪚\udde2ॄ㑉㱋盆ⶌ"
|
||||
}
|
||||
},
|
||||
{
|
||||
"zu4Uv": 8618.712144946234,
|
||||
"gMudq": true,
|
||||
"xwA25": false
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"x99oQ": null,
|
||||
"OVXDu": 6984.617523492656,
|
||||
"GxxAh": [
|
||||
{},
|
||||
null
|
||||
],
|
||||
"Mbljc": [
|
||||
false,
|
||||
[]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.482Z"
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"hash": "9a68a21eb821d150",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "eead25bac11265dbf5d5dc85e2a4e13475799a942db587944066a33d994dd535",
|
||||
"created_at": 1768926859,
|
||||
"content": "\udaa1Ĝ䗷ܬ\udf57荮\udd34࠶짽တ呦瘁埽\udec6ﳅ\ud869\udb63ẜȚ䒜냛谅ꛉ\udf64濧陋\udb95㕍ɔ炩抻⩄䬄쐕潝먔獽ꪟ쓶阻ꑫ嬀⡉ᳶ",
|
||||
"additionalTags": [
|
||||
[
|
||||
"707fp",
|
||||
"1loFnMJca4"
|
||||
],
|
||||
[
|
||||
"HhEan",
|
||||
"yciSPB5wlB"
|
||||
],
|
||||
[
|
||||
"0p6W5",
|
||||
"5IMUKnIeic"
|
||||
],
|
||||
[
|
||||
"cB5SQ",
|
||||
"BXCZ7JxWkl"
|
||||
],
|
||||
[
|
||||
"pt11s",
|
||||
"w2TOjbcwXl"
|
||||
]
|
||||
],
|
||||
"dTagValue": "exrKZf3lsj",
|
||||
"eventId": "be8ee7354cbabac4647130b09d4e050f81b61e8f3182dc9357ec29fed575cac4",
|
||||
"iJzUL": "삻翘㝃暞\ud977茇殸⪼닝峎땟˽蓽ᬇ\ud947智\udcffƐ䑳\udea7玖\udcafុ刯\udb8d廬ꯨ왙돕邢\udda3꠴ᢙ拘Ꜭ䁋\ud84e鱆\udd91ᷗ謷\ud980\udd70來ﱀ酐\udc0f끸噶翤ᘭ㚩ꉁ瞡䆇\ud811詔極孬팿\udb36渎䭢᪂푝ⓤ䄊\udd0a\udb03䔹雲ψ\uddce껵덹㟷鋯\uda3d낉軓\udb55\ud8a8ꦬ\udd67ߥ"
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.551Z"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"hash": "9e2b76583d4b46cf",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "eb2c35eeab443722897ed1add9c97202797ac45a0a58f9950de20460f30c8bad",
|
||||
"created_at": 1768926859,
|
||||
"content": "\udfe3죸⨘\udd6b힖䢍\udf04觚卵瀞佭\ude9aẕ䳽\ud9cd評롘잤桭貒暃뛀턻뢛閕慏ᘂﮔ괵ԫ\uda4e뙤岱\ud95d雉ߒ\ud9ab悜荙怟\udc34뙦\udfda㒬㈅",
|
||||
"additionalTags": [
|
||||
[
|
||||
"DuYKZ",
|
||||
"PfHnMIr5Bk"
|
||||
]
|
||||
],
|
||||
"dTagValue": "973aEhQQcO",
|
||||
"eventId": "e1e45c178921b470bc7018c909df5c14a08907cc4468a124ac80056182bbd4db"
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.541Z"
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"hash": "a58dd9ee08c19eca",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "29f5fc4f9ed239aa66179a85a767352536e9e0eef3f7d3e7cfa15443bd66f4b4",
|
||||
"created_at": 1768926859,
|
||||
"content": "壳䨘둈貍䢹ӌꙈ鱨䲗\ud949粏窞\udb56㷧跿茶\uda13ᰜ騿貸싵\udb12۩꧅鞊꾾趹\udf6bꮆ㿅\udd87报㝒䢱啨\ude90⮅ึ✑記먙⦂砲문鯻瞗",
|
||||
"additionalTags": [
|
||||
[
|
||||
"4kSJm",
|
||||
"8PGGWlUJk7"
|
||||
],
|
||||
[
|
||||
"PoqmU",
|
||||
"yi5kUCLwTa"
|
||||
],
|
||||
[
|
||||
"VuPQD",
|
||||
"pWCxsp8Zgy"
|
||||
],
|
||||
[
|
||||
"A42dG",
|
||||
"aS26J6nAsP"
|
||||
]
|
||||
],
|
||||
"dTagValue": "9jQxiKeSIo",
|
||||
"eventId": "9b4eb0132046934e6f2507ad51e3d799038ea9b4d0610b6059bf5c33b1235115",
|
||||
"CON5u": [
|
||||
8867.612802646758
|
||||
]
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.540Z"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"hash": "c1a8c5dbd064fa0b",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "468deb5661f468407499e44c1a73b551625f052d35bf79f88829b0c95a288eb4",
|
||||
"content": "춁俳㌻鸂\udaea꠲\udb11\udd57\uddeaፋ菅酫鳾㋅䥴\udefb驩ᕦ熞䤺䐐\udd21뭌츔㵻\ud885㘪㭴埳躇৬쥢軎\udcbc᪹鵓럢쓶䋸铇ꦈ\ud851",
|
||||
"additionalTags": [
|
||||
[
|
||||
"tYyDa",
|
||||
"KspWQJHOod"
|
||||
]
|
||||
],
|
||||
"dTagValue": "vQbH1Ux6oW",
|
||||
"eventId": "c2fc8377e82146d86a87d0b738e910c29ca0ba3645b82dfe807e71532c8f902b",
|
||||
"9AH9x": []
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.554Z"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"hash": "c446637259d72e96",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "46f6cca0676ceb29c7e448929842451213b103a3bc11ee591646bc9e55b28d7f",
|
||||
"content": "린\udd2a䵿鳷k곊廚峡\udb2b缝睐\ude22ꀔ짧忀\ud8f4떰ꗰ\udc50풬ႆ蟶\udade兞\ud9e8떏楚儷䜼쐥鼶ᒜ䄗ꙫ皲莜\ud9c4⻛ギ␊",
|
||||
"additionalTags": [
|
||||
[
|
||||
"NpumS",
|
||||
"ufHBSpG49L"
|
||||
],
|
||||
[
|
||||
"t4p5f",
|
||||
"WnzWK88bUH"
|
||||
]
|
||||
],
|
||||
"dTagValue": "I0SdpsWAAn",
|
||||
"eventId": "d905ec3d877e235ec34b5292b7240c4501953be24fdb017b8105402c91da7157",
|
||||
"aS4ID": 1532.0835797977606
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.535Z"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"hash": "ca5e0379db09a508",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "61137f8c918da5e6a3efae6174d31b8870ec06b1e41ba6395fe593491106d7ec",
|
||||
"created_at": 1768926859,
|
||||
"content": "\ude91酭蓈\uddba鯳㶈\udd57뢫재\uda14俳皂ꥒ\udd28\udb2a㬛쬨\ud8db橥\ude01蹍隕뾣\ud81e㈖\udcd2竺\udfbb읩얏䛟읮本ᓰノ\udbe2\udff9뙰꧷퇷䶫焞\udce1\udec2\udb40",
|
||||
"additionalTags": [],
|
||||
"dTagValue": "YZMwTXBnF0",
|
||||
"eventId": "160f8475a536a8af8140239d59fb0e9b130b8428d1aaf99abb48ca6aada188f9",
|
||||
"DsDHJ": null
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.555Z"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"hash": "d770efd177e76757",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"created_at": 1768926859,
|
||||
"content": "\ude79ꉋ詟\ud929\ud94d\udc4b⤘倳ꖨ萊䉕з忠쨌⦯ധ⊐神羈\udebc\uda86ᡵ쑰檨\ud8ee\ud875ꊛຒ敛\udd1f肿蠢둼襛✆荏",
|
||||
"additionalTags": [],
|
||||
"eventId": "798a916303e40319bdd0e7afcc95fdd448b4dc84501fdb8604e23d31f18a8fe4",
|
||||
"pzxvb": 9780.324581105677
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.561Z"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"hash": "e4db9b78fcd4b2a5",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:23)",
|
||||
"timestamp": "2026-01-20T16:32:00.400Z"
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"hash": "e5ac4b49024a9315",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "63a10c52b6909024935c9e0b2a2c68e3db1ea1115f2434b50a797fb559b58bca",
|
||||
"created_at": 1768926859,
|
||||
"additionalTags": [
|
||||
[
|
||||
"Elx3b",
|
||||
"MmFA1VNdgc"
|
||||
],
|
||||
[
|
||||
"I3ybr",
|
||||
"XJDkDHqKnS"
|
||||
],
|
||||
[
|
||||
"ktZT5",
|
||||
"YVcLFQ1tgg"
|
||||
],
|
||||
[
|
||||
"rViGm",
|
||||
"Y58vBKHbbM"
|
||||
],
|
||||
[
|
||||
"HjDaJ",
|
||||
"ZY4F4o1jts"
|
||||
]
|
||||
],
|
||||
"dTagValue": "CU7mmWlnIL",
|
||||
"eventId": "728ee10a08594bde492cccd82af025639361b8ff608da37e5110d4bc4b98d785",
|
||||
"XP1x6": [
|
||||
{
|
||||
"PsmRN": [
|
||||
true
|
||||
],
|
||||
"EHNwp": 872.9927942691252,
|
||||
"oHHhu": "ⲉ㿙㘅磳쓿ֆ垜\ud8c7嘮ᭀᣵ\udd8d㨔\uda9d\ud933≄뎡\ude03\udaed旍菜㉉厕\udd94\udc2e쏞笒뚏\udb05ℛ鼇憑샄\udff4",
|
||||
"iT9Mb": 7962.070659919705
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.546Z"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"hash": "f5565f667ef0bd28",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "7e8b1efc8fef112e00addea54f4ff10ca29ab88ca2ab5e36a7fb0822627f2a3b",
|
||||
"created_at": 1768926859,
|
||||
"content": "ፂ킆ⅷ隰\ude47\udc98烥낷쪾⸛꒻ᕬ㦑屔\udef5㷣\ud8e7鄬䀟࠭ᩝ\udd6c䥶村\udffe\ud878嶁\udf84㩓䂹\ud81b㑤쇼᷒抪燉䷓\udaf5哐冡\udbfa\uda10",
|
||||
"additionalTags": [],
|
||||
"dTagValue": "Go7SKAG4O3",
|
||||
"eventId": "5374e07583039dbf7be03119c6d5e0c7ea8545ce55050620e1021b5ce7fc6924",
|
||||
"M5lVs": {}
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.526Z"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"hash": "f5dd74590c3975b4",
|
||||
"message": "missing-event-relay",
|
||||
"stack": "Error: missing-event-relay\n at buildRepostEvent (file:///app/js/nostrEventSchemas.js:869:13)\n at test (file:///app/scripts/agent/fuzz-nostr-schemas.mjs:91:9)\n at Fuzzer.runFuzzLoop (file:///app/scripts/agent/fuzz-lib.mjs:142:15)",
|
||||
"input": {
|
||||
"target": "buildRepostEvent",
|
||||
"params": {
|
||||
"pubkey": "817aa90feff264c4dd1b9eb9281aea0f683364befe1c4f19504c67730688a033",
|
||||
"created_at": 1768926859,
|
||||
"content": "鋈፟돞\ud857苜퀯锬\ud99f嫴䝺嵵⤓\uddce葔埤↤\ude82߁㨡䓶㶻\udad6렃腫諧䑠數䐇它ꁦ㾝紵垥ᒸ듿⡗嗸ⶹ杮\udbe6\ud828ꏮ쮡낛鿻存",
|
||||
"dTagValue": "aYFKrxoRwN",
|
||||
"eventId": "1b7081e18c97001a19a5777da2d877331830f925db75f72161e504d01e889a4c",
|
||||
"FRqDH": {}
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-01-20T16:34:19.529Z"
|
||||
}
|
||||
@@ -865,10 +865,11 @@ export function buildRepostEvent(params) {
|
||||
typeof eventRelay === "string" ? eventRelay.trim() : "";
|
||||
|
||||
if (normalizedEventId) {
|
||||
if (!normalizedEventRelay) {
|
||||
throw new Error("missing-event-relay");
|
||||
if (normalizedEventRelay) {
|
||||
tags.push(["e", normalizedEventId, normalizedEventRelay]);
|
||||
} else {
|
||||
tags.push(["e", normalizedEventId]);
|
||||
}
|
||||
tags.push(["e", normalizedEventId, normalizedEventRelay]);
|
||||
}
|
||||
|
||||
const normalizedAddress = typeof address === "string" ? address.trim() : "";
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { Fuzzer } from "./fuzz-lib.mjs";
|
||||
import { decryptDM } from "../../js/dmDecryptor.js";
|
||||
|
||||
// Mock global dependencies
|
||||
if (typeof global.window === "undefined") {
|
||||
global.window = {
|
||||
location: { protocol: "https:" },
|
||||
crypto: {
|
||||
getRandomValues: (arr) => crypto.randomFillSync(arr),
|
||||
subtle: {
|
||||
digest: async (algo, data) => {
|
||||
const hash = crypto.createHash("sha256").update(data).digest();
|
||||
return hash.buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
if (typeof global.localStorage === "undefined") {
|
||||
global.localStorage = {
|
||||
getItem: () => null,
|
||||
setItem: () => {},
|
||||
removeItem: () => {}
|
||||
};
|
||||
}
|
||||
|
||||
const fuzzer = new Fuzzer("dm-decryptor");
|
||||
|
||||
async function test(fuzzer, state) {
|
||||
// Generate random event
|
||||
const event = {
|
||||
kind: fuzzer.randBool() ? fuzzer.pick([4, 1059]) : fuzzer.randInt(0, 20000), // 4=DM, 1059=GiftWrap
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
tags: fuzzer.randArray(() => {
|
||||
const tagType = fuzzer.pick(["p", "e", "encrypted"]);
|
||||
if (tagType === "p") return ["p", fuzzer.randString(64, "0123456789abcdef")];
|
||||
if (tagType === "encrypted") return ["encrypted", fuzzer.pick(["nip04", "nip44", "nip44_v2"])];
|
||||
return [fuzzer.randString(5), fuzzer.randString(10)];
|
||||
}, 0, 5),
|
||||
content: fuzzer.randUnicodeString(fuzzer.randInt(0, 200)),
|
||||
pubkey: fuzzer.randString(64, "0123456789abcdef"),
|
||||
id: fuzzer.randString(64, "0123456789abcdef")
|
||||
};
|
||||
|
||||
if (fuzzer.randBool()) event.content = fuzzer.randJSON(); // Garbage content
|
||||
|
||||
// Mock decryptors
|
||||
const decryptors = fuzzer.randArray(() => {
|
||||
return {
|
||||
decrypt: async (pubkey, ciphertext) => {
|
||||
if (fuzzer.randBool()) throw new Error("Decrypt failed");
|
||||
// Return random valid JSON or garbage
|
||||
if (fuzzer.randBool()) return JSON.stringify(fuzzer.randJSON());
|
||||
return fuzzer.randUnicodeString(50);
|
||||
},
|
||||
scheme: fuzzer.pick(["nip04", "nip44", "nip44_v2", "unknown"]),
|
||||
priority: fuzzer.randInt(0, 10),
|
||||
supportsGiftWrap: fuzzer.randBool()
|
||||
};
|
||||
}, 0, 3);
|
||||
|
||||
const context = {
|
||||
actorPubkey: fuzzer.randString(64, "0123456789abcdef"),
|
||||
decryptors: decryptors
|
||||
};
|
||||
|
||||
state.input = { event, context };
|
||||
|
||||
await decryptDM(event, context);
|
||||
}
|
||||
|
||||
fuzzer.runFuzzLoop(2000, test);
|
||||
@@ -0,0 +1,190 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import crypto from "crypto";
|
||||
|
||||
export class Fuzzer {
|
||||
constructor(targetName) {
|
||||
this.targetName = targetName;
|
||||
this.artifactsDir = path.join(process.cwd(), "artifacts");
|
||||
this.reproducersDir = path.join(process.cwd(), "examples", "reproducers", targetName);
|
||||
this.reportPath = path.join(this.artifactsDir, `fuzz-report-${targetName}.json`);
|
||||
this.issues = [];
|
||||
|
||||
if (!fs.existsSync(this.artifactsDir)) {
|
||||
fs.mkdirSync(this.artifactsDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(this.reproducersDir)) {
|
||||
fs.mkdirSync(this.reproducersDir, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
// Random Primitives
|
||||
|
||||
randInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
randBool() {
|
||||
return Math.random() < 0.5;
|
||||
}
|
||||
|
||||
randByte() {
|
||||
return this.randInt(0, 255);
|
||||
}
|
||||
|
||||
randBytes(length) {
|
||||
return crypto.randomBytes(length);
|
||||
}
|
||||
|
||||
randString(length, charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
|
||||
let result = "";
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += charset.charAt(this.randInt(0, charset.length - 1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
randUnicodeString(length) {
|
||||
let result = "";
|
||||
for (let i = 0; i < length; i++) {
|
||||
// Basic multilingual plane + some surrogate pairs
|
||||
if (Math.random() < 0.1) {
|
||||
// High surrogate
|
||||
result += String.fromCharCode(this.randInt(0xD800, 0xDBFF));
|
||||
} else if (Math.random() < 0.1) {
|
||||
// Low surrogate
|
||||
result += String.fromCharCode(this.randInt(0xDC00, 0xDFFF));
|
||||
} else {
|
||||
result += String.fromCharCode(this.randInt(0, 0xFFFF));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
randBuffer(length) {
|
||||
return this.randBytes(length);
|
||||
}
|
||||
|
||||
// Structured Data
|
||||
|
||||
randArray(generator, minLen = 0, maxLen = 10) {
|
||||
const len = this.randInt(minLen, maxLen);
|
||||
const arr = [];
|
||||
for (let i = 0; i < len; i++) {
|
||||
arr.push(generator());
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
randObject(schema) {
|
||||
const obj = {};
|
||||
for (const [key, generator] of Object.entries(schema)) {
|
||||
if (Math.random() > 0.1) { // 10% chance to miss field
|
||||
obj[key] = generator();
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
randJSON() {
|
||||
const types = ["string", "number", "object", "array", "boolean", "null"];
|
||||
const type = types[this.randInt(0, types.length - 1)];
|
||||
|
||||
switch (type) {
|
||||
case "string": return this.randUnicodeString(this.randInt(0, 100));
|
||||
case "number": return Math.random() * 10000;
|
||||
case "boolean": return this.randBool();
|
||||
case "null": return null;
|
||||
case "array": return this.randArray(() => this.randJSON(), 0, 3); // keep depth low
|
||||
case "object": {
|
||||
const obj = {};
|
||||
const keys = this.randInt(0, 5);
|
||||
for(let i=0; i<keys; i++) {
|
||||
obj[this.randString(5)] = this.randJSON();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generateMalformedJSON() {
|
||||
const json = JSON.stringify(this.randJSON());
|
||||
// Mutate
|
||||
const mutationType = this.randInt(0, 2);
|
||||
if (mutationType === 0) {
|
||||
// Truncate
|
||||
return json.slice(0, this.randInt(0, json.length));
|
||||
} else if (mutationType === 1) {
|
||||
// Insert garbage
|
||||
const pos = this.randInt(0, json.length);
|
||||
return json.slice(0, pos) + this.randString(5) + json.slice(pos);
|
||||
} else {
|
||||
// Delete chunk
|
||||
const start = this.randInt(0, json.length);
|
||||
const end = this.randInt(start, json.length);
|
||||
return json.slice(0, start) + json.slice(end);
|
||||
}
|
||||
}
|
||||
|
||||
pick(arr) {
|
||||
if (arr.length === 0) return undefined;
|
||||
return arr[this.randInt(0, arr.length - 1)];
|
||||
}
|
||||
|
||||
// Execution
|
||||
|
||||
async runFuzzLoop(iterations, testFn) {
|
||||
console.log(`Starting fuzzing for ${this.targetName} with ${iterations} iterations...`);
|
||||
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const state = {};
|
||||
try {
|
||||
await testFn(this, state);
|
||||
} catch (err) {
|
||||
this.reportIssue(err, state.input);
|
||||
}
|
||||
|
||||
if ((i + 1) % 100 === 0) {
|
||||
process.stdout.write(".");
|
||||
}
|
||||
}
|
||||
console.log("\nFuzzing complete.");
|
||||
this.writeReport();
|
||||
}
|
||||
|
||||
reportIssue(error, input) {
|
||||
const hash = crypto.createHash("sha256").update(JSON.stringify(input) + error.stack).digest("hex").slice(0, 16);
|
||||
const issue = {
|
||||
hash,
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
input: input,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
// Check for duplicate
|
||||
if (this.issues.some(i => i.hash === hash)) return;
|
||||
|
||||
this.issues.push(issue);
|
||||
console.error(`\n[Found Issue] ${error.message} (Hash: ${hash})`);
|
||||
|
||||
// Write reproducer
|
||||
const reproPath = path.join(this.reproducersDir, `${hash}.json`);
|
||||
fs.writeFileSync(reproPath, JSON.stringify(issue, null, 2));
|
||||
}
|
||||
|
||||
writeReport() {
|
||||
const report = {
|
||||
target: this.targetName,
|
||||
timestamp: new Date().toISOString(),
|
||||
issues: this.issues
|
||||
};
|
||||
fs.writeFileSync(this.reportPath, JSON.stringify(report, null, 2));
|
||||
console.log(`Report written to ${this.reportPath}`);
|
||||
if (this.issues.length > 0) {
|
||||
console.log(`Found ${this.issues.length} unique issues.`);
|
||||
} else {
|
||||
console.log("No issues found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Fuzzer } from "./fuzz-lib.mjs";
|
||||
import { normalizeAndAugmentMagnet } from "../../js/magnetUtils.js";
|
||||
|
||||
// Mock global dependencies if needed
|
||||
if (typeof global.window === "undefined") {
|
||||
global.window = {
|
||||
location: { protocol: "https:" }
|
||||
};
|
||||
}
|
||||
|
||||
const fuzzer = new Fuzzer("magnet-utils");
|
||||
|
||||
async function test(fuzzer, state) {
|
||||
const rawValue = fuzzer.randBool() ?
|
||||
`magnet:?xt=urn:btih:${fuzzer.randString(40, "0123456789abcdef")}&dn=${fuzzer.randString(10)}` :
|
||||
fuzzer.randUnicodeString(100);
|
||||
|
||||
const options = {
|
||||
webSeed: fuzzer.randBool() ? fuzzer.randString(50) : fuzzer.randArray(() => fuzzer.randString(50), 0, 3),
|
||||
torrentUrl: fuzzer.randBool() ? fuzzer.randString(50) : undefined,
|
||||
xs: fuzzer.randBool() ? fuzzer.randString(50) : undefined,
|
||||
extraTrackers: fuzzer.randArray(() => fuzzer.randString(30), 0, 5),
|
||||
appProtocol: fuzzer.pick(["http:", "https:", "magnet:", "unknown:"]),
|
||||
logger: () => {} // No-op logger
|
||||
};
|
||||
|
||||
// Sometimes pass garbage options
|
||||
if (fuzzer.randBool()) {
|
||||
options.webSeed = fuzzer.randJSON();
|
||||
}
|
||||
|
||||
state.input = { rawValue, options };
|
||||
normalizeAndAugmentMagnet(rawValue, options);
|
||||
}
|
||||
|
||||
fuzzer.runFuzzLoop(5000, test);
|
||||
@@ -0,0 +1,106 @@
|
||||
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);
|
||||
Reference in new issue
Block a user