moriarty-project 0.1.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (416) hide show
  1. moriarty/__init__.py +5 -0
  2. moriarty/adapters/__init__.py +0 -0
  3. moriarty/agent/__init__.py +0 -0
  4. moriarty/assets/modules/.gitkeep +0 -0
  5. moriarty/assets/modules/asia/douban.yaml +19 -0
  6. moriarty/assets/modules/asia/kakao.yaml +19 -0
  7. moriarty/assets/modules/asia/line.yaml +19 -0
  8. moriarty/assets/modules/asia/mixi.yaml +19 -0
  9. moriarty/assets/modules/asia/naver.yaml +19 -0
  10. moriarty/assets/modules/asia/qq.yaml +19 -0
  11. moriarty/assets/modules/asia/vk.yaml +19 -0
  12. moriarty/assets/modules/asia/wechat.yaml +19 -0
  13. moriarty/assets/modules/asia/weibo.yaml +19 -0
  14. moriarty/assets/modules/asia/xiaohongshu.yaml +19 -0
  15. moriarty/assets/modules/behance.yaml +47 -0
  16. moriarty/assets/modules/business/crunchbase.yaml +27 -0
  17. moriarty/assets/modules/business/fiverr.yaml +32 -0
  18. moriarty/assets/modules/business/freelancer.yaml +27 -0
  19. moriarty/assets/modules/business/glassdoor.yaml +27 -0
  20. moriarty/assets/modules/business/guru.yaml +26 -0
  21. moriarty/assets/modules/business/indeed.yaml +25 -0
  22. moriarty/assets/modules/business/monster.yaml +25 -0
  23. moriarty/assets/modules/business/peopleperhour.yaml +26 -0
  24. moriarty/assets/modules/business/toptal.yaml +28 -0
  25. moriarty/assets/modules/business/upwork.yaml +27 -0
  26. moriarty/assets/modules/business/ziprecruiter.yaml +25 -0
  27. moriarty/assets/modules/content/buymeacoffee.yaml +27 -0
  28. moriarty/assets/modules/content/gumroad.yaml +27 -0
  29. moriarty/assets/modules/content/ko-fi.yaml +32 -0
  30. moriarty/assets/modules/content/onlyfans.yaml +27 -0
  31. moriarty/assets/modules/content/patreon.yaml +33 -0
  32. moriarty/assets/modules/content/substack.yaml +32 -0
  33. moriarty/assets/modules/creative/500px.yaml +31 -0
  34. moriarty/assets/modules/creative/artstation.yaml +33 -0
  35. moriarty/assets/modules/creative/deviantart.yaml +32 -0
  36. moriarty/assets/modules/creative/flickr.yaml +31 -0
  37. moriarty/assets/modules/creative/pexels.yaml +26 -0
  38. moriarty/assets/modules/creative/unsplash.yaml +26 -0
  39. moriarty/assets/modules/creative/vimeo.yaml +31 -0
  40. moriarty/assets/modules/crypto/binance.yaml +27 -0
  41. moriarty/assets/modules/crypto/bitcointalk.yaml +33 -0
  42. moriarty/assets/modules/crypto/coinbase.yaml +26 -0
  43. moriarty/assets/modules/crypto/etherscan.yaml +32 -0
  44. moriarty/assets/modules/crypto/foundation.yaml +28 -0
  45. moriarty/assets/modules/crypto/kraken.yaml +27 -0
  46. moriarty/assets/modules/crypto/mirror.yaml +27 -0
  47. moriarty/assets/modules/crypto/niftygateway.yaml +26 -0
  48. moriarty/assets/modules/crypto/opensea.yaml +32 -0
  49. moriarty/assets/modules/crypto/rarible.yaml +27 -0
  50. moriarty/assets/modules/crypto/superrare.yaml +29 -0
  51. moriarty/assets/modules/dating/bumble.yaml +25 -0
  52. moriarty/assets/modules/dating/grindr.yaml +27 -0
  53. moriarty/assets/modules/dating/happn.yaml +25 -0
  54. moriarty/assets/modules/dating/her.yaml +27 -0
  55. moriarty/assets/modules/dating/hinge.yaml +25 -0
  56. moriarty/assets/modules/dating/match.yaml +25 -0
  57. moriarty/assets/modules/dating/meetme.yaml +27 -0
  58. moriarty/assets/modules/dating/okcupid.yaml +25 -0
  59. moriarty/assets/modules/dating/pof.yaml +25 -0
  60. moriarty/assets/modules/dating/tinder.yaml +25 -0
  61. moriarty/assets/modules/dating-nsfw/adultfriendfinder.yaml +28 -0
  62. moriarty/assets/modules/dating-nsfw/ashley-madison.yaml +26 -0
  63. moriarty/assets/modules/design/adobe-portfolio.yaml +27 -0
  64. moriarty/assets/modules/design/carbonmade.yaml +27 -0
  65. moriarty/assets/modules/design/cgsociety.yaml +27 -0
  66. moriarty/assets/modules/design/coroflot.yaml +27 -0
  67. moriarty/assets/modules/design/figma.yaml +27 -0
  68. moriarty/assets/modules/design/sketch.yaml +26 -0
  69. moriarty/assets/modules/dev/bitbucket.yaml +35 -0
  70. moriarty/assets/modules/dev/codeforces.yaml +32 -0
  71. moriarty/assets/modules/dev/codepen.yaml +34 -0
  72. moriarty/assets/modules/dev/hackerone.yaml +32 -0
  73. moriarty/assets/modules/dev/hackthebox.yaml +27 -0
  74. moriarty/assets/modules/dev/huggingface.yaml +27 -0
  75. moriarty/assets/modules/dev/kaggle.yaml +32 -0
  76. moriarty/assets/modules/dev/leetcode.yaml +32 -0
  77. moriarty/assets/modules/dev/replit.yaml +31 -0
  78. moriarty/assets/modules/dribbble.yaml +53 -0
  79. moriarty/assets/modules/ecommerce/etsy.yaml +32 -0
  80. moriarty/assets/modules/education/duolingo.yaml +32 -0
  81. moriarty/assets/modules/education/edx.yaml +26 -0
  82. moriarty/assets/modules/education/khanacademy.yaml +26 -0
  83. moriarty/assets/modules/education/lynda.yaml +27 -0
  84. moriarty/assets/modules/education/memrise.yaml +27 -0
  85. moriarty/assets/modules/education/pluralsight.yaml +27 -0
  86. moriarty/assets/modules/education/skillshare.yaml +27 -0
  87. moriarty/assets/modules/education/udacity.yaml +27 -0
  88. moriarty/assets/modules/email/github_email.yaml +40 -0
  89. moriarty/assets/modules/email/gravatar.yaml +23 -0
  90. moriarty/assets/modules/europe/badoo.yaml +19 -0
  91. moriarty/assets/modules/europe/lovoo.yaml +19 -0
  92. moriarty/assets/modules/europe/myspace.yaml +19 -0
  93. moriarty/assets/modules/europe/netlog.yaml +19 -0
  94. moriarty/assets/modules/europe/ok.yaml +19 -0
  95. moriarty/assets/modules/europe/skyrock.yaml +19 -0
  96. moriarty/assets/modules/europe/studivz.yaml +19 -0
  97. moriarty/assets/modules/europe/tuenti.yaml +19 -0
  98. moriarty/assets/modules/europe/viadeo.yaml +19 -0
  99. moriarty/assets/modules/europe/xing.yaml +19 -0
  100. moriarty/assets/modules/fitness/fitbit.yaml +27 -0
  101. moriarty/assets/modules/fitness/garmin.yaml +27 -0
  102. moriarty/assets/modules/fitness/myfitnesspal.yaml +27 -0
  103. moriarty/assets/modules/fitness/strava.yaml +33 -0
  104. moriarty/assets/modules/fitness/zwift.yaml +28 -0
  105. moriarty/assets/modules/food/allrecipes.yaml +27 -0
  106. moriarty/assets/modules/food/tasty.yaml +27 -0
  107. moriarty/assets/modules/food/yelp.yaml +32 -0
  108. moriarty/assets/modules/food/zomato.yaml +28 -0
  109. moriarty/assets/modules/forums/4chan.yaml +26 -0
  110. moriarty/assets/modules/forums/8kun.yaml +26 -0
  111. moriarty/assets/modules/forums/9gag.yaml +26 -0
  112. moriarty/assets/modules/forums/discourse.yaml +26 -0
  113. moriarty/assets/modules/forums/disqus.yaml +31 -0
  114. moriarty/assets/modules/forums/hackernews.yaml +32 -0
  115. moriarty/assets/modules/forums/launchpad.yaml +27 -0
  116. moriarty/assets/modules/forums/phpbb.yaml +25 -0
  117. moriarty/assets/modules/forums/quora.yaml +32 -0
  118. moriarty/assets/modules/forums/serverfault.yaml +27 -0
  119. moriarty/assets/modules/forums/slashdot.yaml +28 -0
  120. moriarty/assets/modules/forums/stackexchange.yaml +32 -0
  121. moriarty/assets/modules/forums/superuser.yaml +27 -0
  122. moriarty/assets/modules/forums/vbulletin.yaml +25 -0
  123. moriarty/assets/modules/forums/xenforo.yaml +25 -0
  124. moriarty/assets/modules/forums-nsfw/kiwifarms.yaml +25 -0
  125. moriarty/assets/modules/forums-nsfw/lolcow.yaml +26 -0
  126. moriarty/assets/modules/gaming/apextracker.yaml +27 -0
  127. moriarty/assets/modules/gaming/battlenet.yaml +26 -0
  128. moriarty/assets/modules/gaming/chess.yaml +30 -0
  129. moriarty/assets/modules/gaming/discord-public.yaml +27 -0
  130. moriarty/assets/modules/gaming/dotabuff.yaml +32 -0
  131. moriarty/assets/modules/gaming/epicgames.yaml +25 -0
  132. moriarty/assets/modules/gaming/faceit.yaml +33 -0
  133. moriarty/assets/modules/gaming/fortnitetracker.yaml +32 -0
  134. moriarty/assets/modules/gaming/gog.yaml +26 -0
  135. moriarty/assets/modules/gaming/itch.yaml +32 -0
  136. moriarty/assets/modules/gaming/kongregate.yaml +25 -0
  137. moriarty/assets/modules/gaming/minecraft.yaml +31 -0
  138. moriarty/assets/modules/gaming/opgg.yaml +32 -0
  139. moriarty/assets/modules/gaming/origin.yaml +26 -0
  140. moriarty/assets/modules/gaming/playstation.yaml +30 -0
  141. moriarty/assets/modules/gaming/roblox.yaml +31 -0
  142. moriarty/assets/modules/gaming/xbox.yaml +25 -0
  143. moriarty/assets/modules/github.yaml +68 -0
  144. moriarty/assets/modules/gitlab.yaml +60 -0
  145. moriarty/assets/modules/instagram.yaml +48 -0
  146. moriarty/assets/modules/latam/fotolog.yaml +27 -0
  147. moriarty/assets/modules/latam/orkut.yaml +26 -0
  148. moriarty/assets/modules/latam/taringa.yaml +27 -0
  149. moriarty/assets/modules/learning/coursera.yaml +26 -0
  150. moriarty/assets/modules/learning/udemy.yaml +26 -0
  151. moriarty/assets/modules/linkedin.yaml +40 -0
  152. moriarty/assets/modules/marketplaces/depop.yaml +28 -0
  153. moriarty/assets/modules/marketplaces/ebay.yaml +32 -0
  154. moriarty/assets/modules/marketplaces/grailed.yaml +27 -0
  155. moriarty/assets/modules/marketplaces/mercari.yaml +26 -0
  156. moriarty/assets/modules/marketplaces/poshmark.yaml +27 -0
  157. moriarty/assets/modules/marketplaces/reverb.yaml +27 -0
  158. moriarty/assets/modules/marketplaces/vinted.yaml +28 -0
  159. moriarty/assets/modules/medium.yaml +44 -0
  160. moriarty/assets/modules/music/audiomack.yaml +26 -0
  161. moriarty/assets/modules/music/bandcamp.yaml +30 -0
  162. moriarty/assets/modules/music/beatport.yaml +28 -0
  163. moriarty/assets/modules/music/deezer.yaml +26 -0
  164. moriarty/assets/modules/music/discogs.yaml +32 -0
  165. moriarty/assets/modules/music/genius.yaml +26 -0
  166. moriarty/assets/modules/music/lastfm.yaml +30 -0
  167. moriarty/assets/modules/music/mixcloud.yaml +26 -0
  168. moriarty/assets/modules/music/reverbnation.yaml +31 -0
  169. moriarty/assets/modules/music/soundcloud.yaml +31 -0
  170. moriarty/assets/modules/music/spotify.yaml +26 -0
  171. moriarty/assets/modules/music/tidal.yaml +26 -0
  172. moriarty/assets/modules/nsfw/adultwork.yaml +27 -0
  173. moriarty/assets/modules/nsfw/bongacams.yaml +28 -0
  174. moriarty/assets/modules/nsfw/cam4.yaml +28 -0
  175. moriarty/assets/modules/nsfw/chaturbate.yaml +28 -0
  176. moriarty/assets/modules/nsfw/clips4sale.yaml +27 -0
  177. moriarty/assets/modules/nsfw/extralunchmoney.yaml +27 -0
  178. moriarty/assets/modules/nsfw/fansly.yaml +28 -0
  179. moriarty/assets/modules/nsfw/fetlife.yaml +28 -0
  180. moriarty/assets/modules/nsfw/iwantclips.yaml +27 -0
  181. moriarty/assets/modules/nsfw/justforfans.yaml +28 -0
  182. moriarty/assets/modules/nsfw/loyalfans.yaml +28 -0
  183. moriarty/assets/modules/nsfw/manyvids.yaml +27 -0
  184. moriarty/assets/modules/nsfw/myfreecams.yaml +28 -0
  185. moriarty/assets/modules/nsfw/niteflirt.yaml +26 -0
  186. moriarty/assets/modules/nsfw/pornhub.yaml +32 -0
  187. moriarty/assets/modules/nsfw/redtube.yaml +27 -0
  188. moriarty/assets/modules/nsfw/stripchat.yaml +28 -0
  189. moriarty/assets/modules/nsfw/xhamster.yaml +27 -0
  190. moriarty/assets/modules/nsfw/xvideos.yaml +27 -0
  191. moriarty/assets/modules/nsfw/youporn.yaml +27 -0
  192. moriarty/assets/modules/photography/eyeem.yaml +25 -0
  193. moriarty/assets/modules/photography/fotki.yaml +25 -0
  194. moriarty/assets/modules/photography/photobucket.yaml +26 -0
  195. moriarty/assets/modules/photography/smugmug.yaml +25 -0
  196. moriarty/assets/modules/photography/vsco.yaml +27 -0
  197. moriarty/assets/modules/pinterest.yaml +40 -0
  198. moriarty/assets/modules/podcasts/anchor.yaml +26 -0
  199. moriarty/assets/modules/podcasts/castbox.yaml +26 -0
  200. moriarty/assets/modules/podcasts/podbean.yaml +26 -0
  201. moriarty/assets/modules/professional/about.yaml +31 -0
  202. moriarty/assets/modules/professional/academia.yaml +27 -0
  203. moriarty/assets/modules/professional/angellist.yaml +27 -0
  204. moriarty/assets/modules/professional/calendly.yaml +26 -0
  205. moriarty/assets/modules/professional/issuu.yaml +27 -0
  206. moriarty/assets/modules/professional/mendeley.yaml +27 -0
  207. moriarty/assets/modules/professional/notion.yaml +27 -0
  208. moriarty/assets/modules/professional/orcid.yaml +27 -0
  209. moriarty/assets/modules/professional/producthunt.yaml +31 -0
  210. moriarty/assets/modules/professional/researchgate.yaml +32 -0
  211. moriarty/assets/modules/professional/scribd.yaml +27 -0
  212. moriarty/assets/modules/professional/slideshare.yaml +31 -0
  213. moriarty/assets/modules/professional/trello.yaml +26 -0
  214. moriarty/assets/modules/professional/typeform.yaml +27 -0
  215. moriarty/assets/modules/reddit.yaml +46 -0
  216. moriarty/assets/modules/regional/amino.yaml +27 -0
  217. moriarty/assets/modules/regional/ask-fm.yaml +32 -0
  218. moriarty/assets/modules/regional/babycenter.yaml +26 -0
  219. moriarty/assets/modules/regional/cafemom.yaml +27 -0
  220. moriarty/assets/modules/regional/care2.yaml +27 -0
  221. moriarty/assets/modules/regional/diaspora.yaml +26 -0
  222. moriarty/assets/modules/regional/ello.yaml +27 -0
  223. moriarty/assets/modules/regional/gaia.yaml +27 -0
  224. moriarty/assets/modules/regional/habbo.yaml +27 -0
  225. moriarty/assets/modules/regional/imvu.yaml +27 -0
  226. moriarty/assets/modules/regional/lemmy.yaml +27 -0
  227. moriarty/assets/modules/regional/peertube.yaml +26 -0
  228. moriarty/assets/modules/regional/pixelfed.yaml +27 -0
  229. moriarty/assets/modules/regional/plurk.yaml +26 -0
  230. moriarty/assets/modules/regional/recroom.yaml +27 -0
  231. moriarty/assets/modules/regional/secondlife.yaml +26 -0
  232. moriarty/assets/modules/regional/vine-archive.yaml +27 -0
  233. moriarty/assets/modules/regional/vrchat.yaml +27 -0
  234. moriarty/assets/modules/regional/weheartit.yaml +27 -0
  235. moriarty/assets/modules/social/anilist.yaml +27 -0
  236. moriarty/assets/modules/social/beacons.yaml +26 -0
  237. moriarty/assets/modules/social/blogger.yaml +27 -0
  238. moriarty/assets/modules/social/crunchyroll.yaml +27 -0
  239. moriarty/assets/modules/social/discord.yaml +27 -0
  240. moriarty/assets/modules/social/dreamwidth.yaml +26 -0
  241. moriarty/assets/modules/social/facebook.yaml +34 -0
  242. moriarty/assets/modules/social/goodreads.yaml +32 -0
  243. moriarty/assets/modules/social/imdb.yaml +27 -0
  244. moriarty/assets/modules/social/kitsu.yaml +27 -0
  245. moriarty/assets/modules/social/letterboxd.yaml +32 -0
  246. moriarty/assets/modules/social/linktree.yaml +26 -0
  247. moriarty/assets/modules/social/livejournal.yaml +27 -0
  248. moriarty/assets/modules/social/mastodon.yaml +30 -0
  249. moriarty/assets/modules/social/minds.yaml +25 -0
  250. moriarty/assets/modules/social/myanimelist.yaml +32 -0
  251. moriarty/assets/modules/social/ravelry.yaml +27 -0
  252. moriarty/assets/modules/social/snapchat.yaml +25 -0
  253. moriarty/assets/modules/social/telegram.yaml +35 -0
  254. moriarty/assets/modules/social/tiktok.yaml +35 -0
  255. moriarty/assets/modules/social/trakt.yaml +28 -0
  256. moriarty/assets/modules/social/wattpad.yaml +32 -0
  257. moriarty/assets/modules/social/wordpress-com.yaml +26 -0
  258. moriarty/assets/modules/sports/espn.yaml +26 -0
  259. moriarty/assets/modules/sports/untappd.yaml +32 -0
  260. moriarty/assets/modules/stackoverflow.yaml +47 -0
  261. moriarty/assets/modules/steam.yaml +47 -0
  262. moriarty/assets/modules/streaming/caffeine.yaml +25 -0
  263. moriarty/assets/modules/streaming/dlive.yaml +27 -0
  264. moriarty/assets/modules/streaming/trovo.yaml +25 -0
  265. moriarty/assets/modules/travel/airbnb.yaml +26 -0
  266. moriarty/assets/modules/travel/booking.yaml +26 -0
  267. moriarty/assets/modules/travel/couchsurfing.yaml +27 -0
  268. moriarty/assets/modules/travel/tripadvisor.yaml +32 -0
  269. moriarty/assets/modules/tumblr.yaml +40 -0
  270. moriarty/assets/modules/twitch.yaml +48 -0
  271. moriarty/assets/modules/twitter.yaml +39 -0
  272. moriarty/assets/modules/youtube.yaml +42 -0
  273. moriarty/assets/templates/cves/CVE-2017-5638.yaml +27 -0
  274. moriarty/assets/templates/cves/CVE-2018-7600.yaml +30 -0
  275. moriarty/assets/templates/cves/CVE-2019-11510.yaml +27 -0
  276. moriarty/assets/templates/cves/CVE-2019-19781.yaml +28 -0
  277. moriarty/assets/templates/cves/CVE-2020-14882.yaml +28 -0
  278. moriarty/assets/templates/cves/CVE-2020-14883.yaml +29 -0
  279. moriarty/assets/templates/cves/CVE-2020-3452.yaml +28 -0
  280. moriarty/assets/templates/cves/CVE-2020-5902.yaml +28 -0
  281. moriarty/assets/templates/cves/CVE-2021-21972.yaml +31 -0
  282. moriarty/assets/templates/cves/CVE-2021-21985.yaml +28 -0
  283. moriarty/assets/templates/cves/CVE-2021-26084.yaml +30 -0
  284. moriarty/assets/templates/cves/CVE-2021-41773.yaml +25 -0
  285. moriarty/assets/templates/cves/CVE-2021-42013.yaml +28 -0
  286. moriarty/assets/templates/cves/CVE-2021-44228.yaml +27 -0
  287. moriarty/assets/templates/cves/CVE-2022-0185.yaml +21 -0
  288. moriarty/assets/templates/cves/CVE-2022-1388.yaml +36 -0
  289. moriarty/assets/templates/cves/CVE-2022-22954.yaml +28 -0
  290. moriarty/assets/templates/cves/CVE-2022-22965.yaml +31 -0
  291. moriarty/assets/templates/cves/CVE-2022-26134.yaml +27 -0
  292. moriarty/assets/templates/cves/CVE-2023-22515.yaml +27 -0
  293. moriarty/assets/templates/cves/CVE-2023-22527.yaml +29 -0
  294. moriarty/assets/templates/cves/CVE-2023-23752.yaml +33 -0
  295. moriarty/assets/templates/cves/CVE-2023-27350.yaml +27 -0
  296. moriarty/assets/templates/cves/CVE-2023-2868.yaml +27 -0
  297. moriarty/assets/templates/cves/CVE-2023-34362.yaml +27 -0
  298. moriarty/assets/templates/cves/CVE-2023-3519.yaml +28 -0
  299. moriarty/assets/templates/cves/CVE-2023-4966.yaml +27 -0
  300. moriarty/assets/templates/default-logins/admin-weak.yaml +40 -0
  301. moriarty/assets/templates/default-logins/wordpress-default.yaml +38 -0
  302. moriarty/assets/templates/exposures/aws-credentials.yaml +35 -0
  303. moriarty/assets/templates/exposures/backup-files.yaml +36 -0
  304. moriarty/assets/templates/exposures/database-files.yaml +34 -0
  305. moriarty/assets/templates/exposures/docker-exposed.yaml +31 -0
  306. moriarty/assets/templates/exposures/env-exposed.yaml +41 -0
  307. moriarty/assets/templates/exposures/git-exposed.yaml +41 -0
  308. moriarty/assets/templates/exposures/phpinfo.yaml +36 -0
  309. moriarty/assets/templates/exposures/svn-exposed.yaml +28 -0
  310. moriarty/assets/templates/fuzzing/api-endpoints.yaml +39 -0
  311. moriarty/assets/templates/fuzzing/common-files.yaml +37 -0
  312. moriarty/assets/templates/fuzzing/open-redirect-fuzz.yaml +35 -0
  313. moriarty/assets/templates/fuzzing/xss-search-fuzz.yaml +29 -0
  314. moriarty/assets/templates/git-config.yaml +18 -0
  315. moriarty/assets/templates/misconfigurations/cors-misconfiguration.yaml +30 -0
  316. moriarty/assets/templates/misconfigurations/debug-enabled.yaml +29 -0
  317. moriarty/assets/templates/misconfigurations/directory-listing.yaml +33 -0
  318. moriarty/assets/templates/misconfigurations/jwt-none-algo.yaml +30 -0
  319. moriarty/assets/templates/misconfigurations/ssl-tls-weak.yaml +23 -0
  320. moriarty/assets/templates/vulnerabilities/lfi-basic.yaml +31 -0
  321. moriarty/assets/templates/vulnerabilities/open-redirect.yaml +31 -0
  322. moriarty/assets/templates/vulnerabilities/rce-basic.yaml +34 -0
  323. moriarty/assets/templates/vulnerabilities/sqli-error.yaml +39 -0
  324. moriarty/assets/templates/vulnerabilities/ssrf-basic.yaml +31 -0
  325. moriarty/assets/templates/vulnerabilities/xss-reflected.yaml +38 -0
  326. moriarty/assets/templates/vulnerabilities/xxe-basic.yaml +30 -0
  327. moriarty/assets/wordlists/subdomains-1000.txt +1063 -0
  328. moriarty/cli/__init__.py +3 -0
  329. moriarty/cli/app.py +120 -0
  330. moriarty/cli/async_utils.py +19 -0
  331. moriarty/cli/dns.py +83 -0
  332. moriarty/cli/domain_cmd.py +572 -0
  333. moriarty/cli/email.py +383 -0
  334. moriarty/cli/email_investigate.py +224 -0
  335. moriarty/cli/intelligence.py +329 -0
  336. moriarty/cli/output.py +62 -0
  337. moriarty/cli/rdap.py +94 -0
  338. moriarty/cli/state.py +38 -0
  339. moriarty/cli/tls.py +91 -0
  340. moriarty/cli/user.py +227 -0
  341. moriarty/core/cache_backend.py +223 -0
  342. moriarty/core/config_manager.py +303 -0
  343. moriarty/correlator/__init__.py +0 -0
  344. moriarty/data/__init__.py +81 -0
  345. moriarty/data/ioc/__init__.py +142 -0
  346. moriarty/data/ioc/matcher.py +254 -0
  347. moriarty/data/ioc/types.py +267 -0
  348. moriarty/data/local_intelligence.py +507 -0
  349. moriarty/data/signature_loaders/__init__.py +103 -0
  350. moriarty/data/signature_loaders/base.py +54 -0
  351. moriarty/data/signature_loaders/ioc_feed.py +356 -0
  352. moriarty/data/signature_loaders/wappalyzer.py +112 -0
  353. moriarty/dsl/__init__.py +0 -0
  354. moriarty/dsl/loader.py +99 -0
  355. moriarty/dsl/schema.py +47 -0
  356. moriarty/export/__init__.py +0 -0
  357. moriarty/intelligence/__init__.py +27 -0
  358. moriarty/intelligence/__main__.py +150 -0
  359. moriarty/intelligence/config.py +395 -0
  360. moriarty/intelligence/ioc.py +267 -0
  361. moriarty/intelligence/signatures.py +550 -0
  362. moriarty/intelligence/storage.py +501 -0
  363. moriarty/interop/__init__.py +0 -0
  364. moriarty/logging/__init__.py +0 -0
  365. moriarty/logging/config.py +47 -0
  366. moriarty/models/__init__.py +16 -0
  367. moriarty/models/assertion.py +24 -0
  368. moriarty/models/entity.py +22 -0
  369. moriarty/models/evidence.py +37 -0
  370. moriarty/models/relation.py +24 -0
  371. moriarty/models/types.py +28 -0
  372. moriarty/modules/__init__.py +0 -0
  373. moriarty/modules/avatar_hash.py +184 -0
  374. moriarty/modules/directory_fuzzer.py +322 -0
  375. moriarty/modules/dns_scan.py +40 -0
  376. moriarty/modules/domain_scanner.py +620 -0
  377. moriarty/modules/email_check.py +98 -0
  378. moriarty/modules/email_investigate.py +267 -0
  379. moriarty/modules/email_security.py +274 -0
  380. moriarty/modules/googlemaps_lookup.py +106 -0
  381. moriarty/modules/headless_executor.py +201 -0
  382. moriarty/modules/orchestrator.py +60 -0
  383. moriarty/modules/passive_recon.py +444 -0
  384. moriarty/modules/phone_extractor.py +151 -0
  385. moriarty/modules/pipeline_orchestrator.py +726 -0
  386. moriarty/modules/port_scanner.py +129 -0
  387. moriarty/modules/rdap.py +61 -0
  388. moriarty/modules/rdap_extended.py +188 -0
  389. moriarty/modules/stealth_mode.py +610 -0
  390. moriarty/modules/subdomain_discovery.py +595 -0
  391. moriarty/modules/technology_profiler.py +361 -0
  392. moriarty/modules/template_executor.py +239 -0
  393. moriarty/modules/template_scanner.py +1048 -0
  394. moriarty/modules/tls_scan.py +46 -0
  395. moriarty/modules/tls_validator.py +188 -0
  396. moriarty/modules/vuln_scanner.py +483 -0
  397. moriarty/modules/waf_detector.py +585 -0
  398. moriarty/modules/wayback_discovery.py +234 -0
  399. moriarty/modules/web_crawler.py +163 -0
  400. moriarty/net/__init__.py +0 -0
  401. moriarty/net/dns_cache.py +175 -0
  402. moriarty/net/dns_client.py +188 -0
  403. moriarty/net/rdap_client.py +52 -0
  404. moriarty/net/smtp_client.py +114 -0
  405. moriarty/net/tls_client.py +111 -0
  406. moriarty/parsers/__init__.py +0 -0
  407. moriarty/parsers/html_parser.py +136 -0
  408. moriarty/tests/__init__.py +0 -0
  409. moriarty/tests/test_email_service.py +17 -0
  410. moriarty/tests/test_models.py +46 -0
  411. moriarty/tests/test_orchestrator.py +30 -0
  412. moriarty/tests/test_tls_client.py +18 -0
  413. moriarty_project-0.1.6.dist-info/METADATA +388 -0
  414. moriarty_project-0.1.6.dist-info/RECORD +418 -0
  415. moriarty_project-0.1.6.dist-info/WHEEL +4 -0
  416. moriarty_project-0.1.6.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,188 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from dataclasses import dataclass
5
+ from time import perf_counter
6
+ from typing import Any, Dict, List, Optional
7
+
8
+ import aiodns
9
+ import httpx
10
+ import structlog
11
+
12
+ from .dns_cache import DNSCache, get_global_cache
13
+
14
+
15
+ @dataclass(slots=True)
16
+ class MXRecord:
17
+ priority: int
18
+ exchange: str
19
+
20
+
21
+ @dataclass(slots=True)
22
+ class TXTRecord:
23
+ text: str
24
+
25
+
26
+ @dataclass(slots=True)
27
+ class DNSLookupResult:
28
+ a: List[str]
29
+ aaaa: List[str]
30
+ mx: List[MXRecord]
31
+ txt: List[TXTRecord]
32
+ spf: List[str]
33
+ dmarc: List[str]
34
+
35
+
36
+ class DNSClient:
37
+ def __init__(
38
+ self,
39
+ timeout: float = 8.0,
40
+ use_cache: bool = True,
41
+ doh_endpoint: Optional[str] = None,
42
+ dot_server: Optional[str] = None,
43
+ ) -> None:
44
+ self._resolver = aiodns.DNSResolver(timeout=timeout)
45
+ self._timeout = timeout
46
+ self._logger = structlog.get_logger(__name__)
47
+ self._use_cache = use_cache
48
+ self._cache = get_global_cache() if use_cache else None
49
+ self._doh_endpoint = doh_endpoint # Ex: https://cloudflare-dns.com/dns-query
50
+ self._dot_server = dot_server # Ex: 1.1.1.1:853
51
+
52
+ if doh_endpoint:
53
+ self._logger.info("dns.doh.enabled", endpoint=doh_endpoint)
54
+ if dot_server:
55
+ self._logger.info("dns.dot.enabled", server=dot_server)
56
+
57
+ async def lookup_domain(self, domain: str) -> DNSLookupResult:
58
+ start = perf_counter()
59
+ self._logger.info("dns.lookup.start", domain=domain, timeout_s=self._timeout)
60
+ a_task = asyncio.create_task(self._query(domain, "A"))
61
+ aaaa_task = asyncio.create_task(self._query(domain, "AAAA"))
62
+ mx_task = asyncio.create_task(self._query(domain, "MX"))
63
+ txt_task = asyncio.create_task(self._query(domain, "TXT"))
64
+ dmarc_task = asyncio.create_task(self._query(f"_dmarc.{domain}", "TXT"))
65
+
66
+ a_records = await a_task
67
+ aaaa_records = await aaaa_task
68
+ mx_records = await mx_task
69
+ txt_records = await txt_task
70
+ dmarc_records = await dmarc_task
71
+
72
+ mx_structured = [
73
+ MXRecord(priority=int(entry.get("priority", 0)), exchange=str(entry.get("host")))
74
+ for entry in mx_records
75
+ if "host" in entry
76
+ ]
77
+
78
+ txt_structured = [
79
+ TXTRecord(text=str(entry.get("text", "")))
80
+ for entry in txt_records
81
+ if entry.get("text")
82
+ ]
83
+
84
+ spf_records = [record.text for record in txt_structured if record.text.lower().startswith("v=spf1")]
85
+ dmarc_structured = [
86
+ TXTRecord(text=str(entry.get("text", "")))
87
+ for entry in dmarc_records
88
+ if entry.get("text")
89
+ ]
90
+
91
+ result = DNSLookupResult(
92
+ a=[entry.get("host") for entry in a_records if entry.get("host")],
93
+ aaaa=[entry.get("host") for entry in aaaa_records if entry.get("host")],
94
+ mx=sorted(mx_structured, key=lambda mx: (mx.priority, mx.exchange)),
95
+ txt=txt_structured,
96
+ spf=spf_records,
97
+ dmarc=[record.text for record in dmarc_structured],
98
+ )
99
+ latency_ms = (perf_counter() - start) * 1000
100
+ self._logger.info(
101
+ "dns.lookup.success",
102
+ domain=domain,
103
+ latency_ms=round(latency_ms, 2),
104
+ a=len(result.a),
105
+ aaaa=len(result.aaaa),
106
+ mx=len(result.mx),
107
+ )
108
+ return result
109
+
110
+ async def _query(self, domain: str, record_type: str) -> List[Dict[str, Any]]:
111
+ # Verifica cache primeiro
112
+ if self._cache:
113
+ cached = await self._cache.get(domain, record_type)
114
+ if cached is not None:
115
+ return cached
116
+
117
+ # DoH (DNS-over-HTTPS)
118
+ if self._doh_endpoint:
119
+ try:
120
+ result = await self._query_doh(domain, record_type)
121
+ if result and self._cache:
122
+ await self._cache.set(domain, record_type, result, ttl=300)
123
+ return result
124
+ except Exception as e:
125
+ self._logger.warning("dns.doh.error", error=str(e), domain=domain)
126
+ # Fallback para DNS tradicional
127
+
128
+ # DNS tradicional
129
+ try:
130
+ result = await self._resolver.query(domain, record_type)
131
+ except aiodns.error.DNSError:
132
+ self._logger.warning("dns.lookup.miss", domain=domain, record_type=record_type)
133
+ return []
134
+
135
+ if isinstance(result, list):
136
+ records = [self._record_to_dict(entry) for entry in result]
137
+
138
+ # Salva no cache com TTL
139
+ if self._cache and records:
140
+ ttl = getattr(result[0], 'ttl', 300) if result else 300
141
+ await self._cache.set(domain, record_type, records, ttl=ttl)
142
+
143
+ return records
144
+
145
+ return []
146
+
147
+ async def _query_doh(self, domain: str, record_type: str) -> List[Dict[str, Any]]:
148
+ """Consulta DNS via HTTPS (DoH)."""
149
+ async with httpx.AsyncClient(timeout=self._timeout) as client:
150
+ response = await client.get(
151
+ self._doh_endpoint,
152
+ params={
153
+ "name": domain,
154
+ "type": record_type,
155
+ },
156
+ headers={"Accept": "application/dns-json"},
157
+ )
158
+ response.raise_for_status()
159
+ data = response.json()
160
+
161
+ # Converte resposta DoH para formato compatível
162
+ answers = data.get("Answer", [])
163
+ if not answers:
164
+ return []
165
+
166
+ records = []
167
+ for answer in answers:
168
+ if record_type == "A" or record_type == "AAAA":
169
+ records.append({"host": answer.get("data"), "ttl": answer.get("TTL", 300)})
170
+ elif record_type == "MX":
171
+ parts = answer.get("data", "").split()
172
+ if len(parts) == 2:
173
+ records.append({"priority": int(parts[0]), "host": parts[1], "ttl": answer.get("TTL", 300)})
174
+ elif record_type == "TXT":
175
+ records.append({"text": answer.get("data", ""), "ttl": answer.get("TTL", 300)})
176
+
177
+ return records
178
+
179
+ @staticmethod
180
+ def _record_to_dict(record: Any) -> Dict[str, Any]:
181
+ return {
182
+ key: getattr(record, key)
183
+ for key in dir(record)
184
+ if not key.startswith("_") and not callable(getattr(record, key))
185
+ }
186
+
187
+
188
+ __all__ = ["DNSClient", "DNSLookupResult", "MXRecord", "TXTRecord"]
@@ -0,0 +1,52 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from time import perf_counter
5
+ from typing import Any, Dict
6
+
7
+ import httpx
8
+ import structlog
9
+
10
+ logger = structlog.get_logger(__name__)
11
+
12
+
13
+ @dataclass(slots=True)
14
+ class RDAPResponse:
15
+ url: str
16
+ payload: Dict[str, Any]
17
+ status: int
18
+ latency_ms: float
19
+
20
+
21
+ class RDAPClient:
22
+ def __init__(self, base_url: str = "https://rdap.org", timeout: float = 8.0, http2: bool = True) -> None:
23
+ self._base_url = base_url.rstrip("/")
24
+ self._timeout = timeout
25
+ self._http2 = http2
26
+
27
+ async def fetch(self, path: str) -> RDAPResponse:
28
+ url = f"{self._base_url}/{path.lstrip('/')}"
29
+ logger.info("rdap.request.start", url=url)
30
+ start = perf_counter()
31
+ async with httpx.AsyncClient(timeout=self._timeout, http2=self._http2) as client:
32
+ response = await client.get(url, headers={"Accept": "application/rdap+json, application/json"})
33
+ latency_ms = (perf_counter() - start) * 1000
34
+ if response.status_code >= 400:
35
+ logger.warning(
36
+ "rdap.request.error",
37
+ url=url,
38
+ status=response.status_code,
39
+ latency_ms=round(latency_ms, 2),
40
+ )
41
+ response.raise_for_status()
42
+ payload = response.json()
43
+ logger.info(
44
+ "rdap.request.success",
45
+ url=url,
46
+ status=response.status_code,
47
+ latency_ms=round(latency_ms, 2),
48
+ )
49
+ return RDAPResponse(url=url, payload=payload, status=response.status_code, latency_ms=latency_ms)
50
+
51
+
52
+ __all__ = ["RDAPClient", "RDAPResponse"]
@@ -0,0 +1,114 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import contextlib
5
+ from dataclasses import dataclass
6
+ from time import perf_counter
7
+ from typing import Iterable, List, Optional
8
+
9
+ import aiosmtplib
10
+ import structlog
11
+
12
+
13
+ @dataclass(slots=True)
14
+ class SMTPAttempt:
15
+ host: str
16
+ port: int
17
+ result_code: Optional[int]
18
+ result_message: Optional[str]
19
+ success: bool
20
+ error: Optional[str]
21
+
22
+
23
+ @dataclass(slots=True)
24
+ class SMTPProbeResult:
25
+ deliverable: bool
26
+ attempts: List[SMTPAttempt]
27
+
28
+
29
+ class SMTPClient:
30
+ def __init__(self, timeout: float = 8.0, wait: float = 1.0, retries: int = 1) -> None:
31
+ self._timeout = timeout
32
+ self._wait = wait
33
+ self._retries = retries
34
+ self._logger = structlog.get_logger(__name__)
35
+
36
+ async def probe(self, email: str, from_address: str, hosts: Iterable[str]) -> SMTPProbeResult:
37
+ attempts: List[SMTPAttempt] = []
38
+ deliverable = False
39
+
40
+ for host in hosts:
41
+ start = perf_counter()
42
+ self._logger.info(
43
+ "smtp.probe.start",
44
+ host=host,
45
+ retries=self._retries,
46
+ timeout_s=self._timeout,
47
+ )
48
+ for attempt in range(self._retries + 1):
49
+ smtp: Optional[aiosmtplib.SMTP] = None
50
+ try:
51
+ smtp = aiosmtplib.SMTP(hostname=host, port=25, timeout=self._timeout)
52
+ await smtp.connect()
53
+ await smtp.ehlo()
54
+ await smtp.mail(from_address)
55
+ rcpt_code, rcpt_message = await smtp.rcpt(email)
56
+ message_text = rcpt_message.decode("utf-8", errors="replace") if isinstance(rcpt_message, bytes) else str(rcpt_message)
57
+ success = 200 <= rcpt_code < 300
58
+ attempts.append(
59
+ SMTPAttempt(
60
+ host=host,
61
+ port=25,
62
+ result_code=rcpt_code,
63
+ result_message=message_text,
64
+ success=success,
65
+ error=None,
66
+ )
67
+ )
68
+ if success:
69
+ deliverable = True
70
+ await smtp.quit()
71
+ return SMTPProbeResult(deliverable=deliverable, attempts=attempts)
72
+ except aiosmtplib.errors.SMTPException as exc:
73
+ attempts.append(
74
+ SMTPAttempt(
75
+ host=host,
76
+ port=25,
77
+ result_code=None,
78
+ result_message=None,
79
+ success=False,
80
+ error=str(exc),
81
+ )
82
+ )
83
+ except Exception as exc: # noqa: BLE001
84
+ attempts.append(
85
+ SMTPAttempt(
86
+ host=host,
87
+ port=25,
88
+ result_code=None,
89
+ result_message=None,
90
+ success=False,
91
+ error=str(exc),
92
+ )
93
+ )
94
+ finally:
95
+ if smtp is not None:
96
+ with contextlib.suppress(Exception):
97
+ await smtp.quit()
98
+
99
+ if attempt < self._retries:
100
+ await asyncio.sleep(self._wait)
101
+
102
+ latency_ms = (perf_counter() - start) * 1000
103
+ self._logger.info(
104
+ "smtp.probe.complete",
105
+ host=host,
106
+ attempts=len(attempts),
107
+ latency_ms=round(latency_ms, 2),
108
+ deliverable=deliverable,
109
+ )
110
+
111
+ return SMTPProbeResult(deliverable=deliverable, attempts=attempts)
112
+
113
+
114
+ __all__ = ["SMTPClient", "SMTPProbeResult", "SMTPAttempt"]
@@ -0,0 +1,111 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import hashlib
5
+ import socket
6
+ import ssl
7
+ from dataclasses import dataclass
8
+ from datetime import datetime
9
+ from time import perf_counter
10
+ from typing import List, Optional
11
+
12
+ import structlog
13
+
14
+ logger = structlog.get_logger(__name__)
15
+
16
+
17
+ @dataclass(slots=True)
18
+ class TLSCertificate:
19
+ subject: str
20
+ issuer: str
21
+ not_before: datetime
22
+ not_after: datetime
23
+ fingerprint_sha256: str
24
+ subject_alt_names: List[str]
25
+
26
+
27
+ @dataclass(slots=True)
28
+ class TLSInspection:
29
+ host: str
30
+ port: int
31
+ protocol: Optional[str]
32
+ cipher: Optional[str]
33
+ certificates: List[TLSCertificate]
34
+ latency_ms: float
35
+
36
+
37
+ class TLSClient:
38
+ def __init__(self, timeout: float = 8.0, verify: bool = False) -> None:
39
+ self._timeout = timeout
40
+ self._verify = verify
41
+
42
+ async def inspect(self, host: str, port: int = 443) -> TLSInspection:
43
+ logger.info("tls.inspect.start", host=host, port=port)
44
+ start = perf_counter()
45
+ try:
46
+ protocol, cipher, certificates = await asyncio.wait_for(
47
+ asyncio.to_thread(self._inspect_sync, host, port),
48
+ timeout=self._timeout,
49
+ )
50
+ except Exception:
51
+ logger.exception("tls.inspect.error", host=host, port=port)
52
+ raise
53
+ latency_ms = (perf_counter() - start) * 1000
54
+ logger.info(
55
+ "tls.inspect.success",
56
+ host=host,
57
+ port=port,
58
+ latency_ms=round(latency_ms, 2),
59
+ certificates=len(certificates),
60
+ )
61
+ return TLSInspection(
62
+ host=host,
63
+ port=port,
64
+ protocol=protocol,
65
+ cipher=cipher,
66
+ certificates=certificates,
67
+ latency_ms=latency_ms,
68
+ )
69
+
70
+ def _inspect_sync(self, host: str, port: int) -> tuple[Optional[str], Optional[str], List[TLSCertificate]]:
71
+ context = ssl.create_default_context()
72
+ if not self._verify:
73
+ context.check_hostname = False
74
+ context.verify_mode = ssl.CERT_NONE
75
+
76
+ with socket.create_connection((host, port), timeout=self._timeout) as sock:
77
+ with context.wrap_socket(sock, server_hostname=host) as tls_sock:
78
+ cipher_info = tls_sock.cipher()
79
+ protocol = tls_sock.version()
80
+ der_cert = tls_sock.getpeercert(binary_form=True)
81
+ cert_dict = tls_sock.getpeercert()
82
+
83
+ certificate = self._parse_cert(der_cert, cert_dict)
84
+ return protocol, cipher_info[0] if cipher_info else None, [certificate]
85
+
86
+ def _parse_cert(self, der_bytes: bytes, cert_dict: dict[str, object]) -> TLSCertificate:
87
+ fingerprint = hashlib.sha256(der_bytes).hexdigest()
88
+ subject_components = cert_dict.get("subject", [])
89
+ subject = ", ".join("=".join(component) for rdn in subject_components for component in rdn)
90
+ issuer_components = cert_dict.get("issuer", [])
91
+ issuer = ", ".join("=".join(component) for rdn in issuer_components for component in rdn)
92
+ not_before = self._parse_time(cert_dict.get("notBefore"))
93
+ not_after = self._parse_time(cert_dict.get("notAfter"))
94
+ sans = [value for key, value in cert_dict.get("subjectAltName", []) if value]
95
+ return TLSCertificate(
96
+ subject=subject,
97
+ issuer=issuer,
98
+ not_before=not_before,
99
+ not_after=not_after,
100
+ fingerprint_sha256=fingerprint,
101
+ subject_alt_names=sans,
102
+ )
103
+
104
+ @staticmethod
105
+ def _parse_time(value: Optional[object]) -> datetime:
106
+ if isinstance(value, str):
107
+ return datetime.strptime(value, "%b %d %H:%M:%S %Y %Z")
108
+ return datetime.fromtimestamp(0)
109
+
110
+
111
+ __all__ = ["TLSClient", "TLSInspection", "TLSCertificate"]
File without changes
@@ -0,0 +1,136 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from typing import Any, List, Optional
5
+
6
+ from selectolax.parser import HTMLParser
7
+
8
+ from ..dsl.schema import SelectorSpec
9
+
10
+
11
+ class ParserError(Exception):
12
+ """Erro ao fazer parsing."""
13
+
14
+
15
+ class HTMLExtractor:
16
+ """Extrai dados de HTML usando selectores."""
17
+
18
+ def __init__(self, html: str) -> None:
19
+ self._parser = HTMLParser(html)
20
+ self._raw_html = html
21
+
22
+ def extract(self, selector: SelectorSpec) -> Optional[str]:
23
+ """Extrai um único valor usando um seletor."""
24
+ if selector.type == "css":
25
+ return self._extract_css(selector)
26
+ elif selector.type == "xpath":
27
+ # selectolax não suporta XPath nativamente, fallback para lxml se necessário
28
+ return self._extract_xpath(selector)
29
+ elif selector.type == "regex":
30
+ return self._extract_regex(selector)
31
+ elif selector.type == "json":
32
+ # JSON path sobre o HTML bruto
33
+ return None
34
+ return None
35
+
36
+ def extract_all(self, selector: SelectorSpec) -> List[str]:
37
+ """Extrai múltiplos valores."""
38
+ if selector.type == "css":
39
+ return self._extract_css_all(selector)
40
+ elif selector.type == "regex":
41
+ return self._extract_regex_all(selector)
42
+ return []
43
+
44
+ def exists(self, selector: SelectorSpec) -> bool:
45
+ """Verifica se um seletor encontra algo."""
46
+ result = self.extract(selector)
47
+ return result is not None and len(result) > 0
48
+
49
+ def _extract_css(self, selector: SelectorSpec) -> Optional[str]:
50
+ """Extrai usando CSS selector."""
51
+ node = self._parser.css_first(selector.query)
52
+ if node is None:
53
+ return None
54
+
55
+ if selector.attribute:
56
+ return node.attributes.get(selector.attribute)
57
+
58
+ return node.text(strip=True)
59
+
60
+ def _extract_css_all(self, selector: SelectorSpec) -> List[str]:
61
+ """Extrai todos os matches de um CSS selector."""
62
+ nodes = self._parser.css(selector.query)
63
+ results: List[str] = []
64
+
65
+ for node in nodes:
66
+ if selector.attribute:
67
+ value = node.attributes.get(selector.attribute)
68
+ if value:
69
+ results.append(value)
70
+ else:
71
+ text = node.text(strip=True)
72
+ if text:
73
+ results.append(text)
74
+
75
+ return results
76
+
77
+ def _extract_xpath(self, selector: SelectorSpec) -> Optional[str]:
78
+ """Extrai usando XPath (requer lxml)."""
79
+ try:
80
+ from lxml import etree, html
81
+ except ImportError:
82
+ raise ParserError("lxml required for XPath selectors")
83
+
84
+ try:
85
+ tree = html.fromstring(self._raw_html)
86
+ result = tree.xpath(selector.query)
87
+
88
+ if not result:
89
+ return None
90
+
91
+ if isinstance(result, list) and len(result) > 0:
92
+ element = result[0]
93
+ if selector.attribute and hasattr(element, "get"):
94
+ return element.get(selector.attribute)
95
+ if hasattr(element, "text"):
96
+ return element.text
97
+ return str(element)
98
+
99
+ return str(result)
100
+ except Exception:
101
+ return None
102
+
103
+ def _extract_regex(self, selector: SelectorSpec) -> Optional[str]:
104
+ """Extrai usando regex."""
105
+ pattern = re.compile(selector.query, re.IGNORECASE | re.DOTALL)
106
+ match = pattern.search(self._raw_html)
107
+
108
+ if match:
109
+ group = selector.group if selector.group is not None else 0
110
+ try:
111
+ return match.group(group)
112
+ except IndexError:
113
+ return None
114
+
115
+ return None
116
+
117
+ def _extract_regex_all(self, selector: SelectorSpec) -> List[str]:
118
+ """Extrai todos os matches de regex."""
119
+ pattern = re.compile(selector.query, re.IGNORECASE | re.DOTALL)
120
+ matches = pattern.finditer(self._raw_html)
121
+
122
+ results: List[str] = []
123
+ group = selector.group if selector.group is not None else 0
124
+
125
+ for match in matches:
126
+ try:
127
+ value = match.group(group)
128
+ if value:
129
+ results.append(value)
130
+ except IndexError:
131
+ continue
132
+
133
+ return results
134
+
135
+
136
+ __all__ = ["HTMLExtractor", "ParserError"]
File without changes
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+
5
+ from moriarty.modules.email_check import EmailCheckOptions, EmailCheckService
6
+
7
+
8
+ def test_email_normalization_only() -> None:
9
+ service = EmailCheckService(
10
+ email="Alice@Example.COM",
11
+ options=EmailCheckOptions(check_dns=False, check_smtp=False),
12
+ timeout=0.1,
13
+ )
14
+ result = asyncio.run(service.run())
15
+ assert result.normalized_email == "alice@example.com"
16
+ assert result.dns is None
17
+ assert result.smtp is None
@@ -0,0 +1,46 @@
1
+ from __future__ import annotations
2
+
3
+ from moriarty.models import (
4
+ Assertion,
5
+ ConfidenceBand,
6
+ CustodyEvent,
7
+ Entity,
8
+ EntityKind,
9
+ Evidence,
10
+ EvidenceKind,
11
+ Relation,
12
+ )
13
+
14
+
15
+ def test_entity_creation() -> None:
16
+ entity = Entity(kind=EntityKind.EMAIL, value="alice@example.com")
17
+ assert entity.value == "alice@example.com"
18
+ assert entity.kind is EntityKind.EMAIL
19
+
20
+
21
+ def test_evidence_chain() -> None:
22
+ evidence = Evidence(
23
+ kind=EvidenceKind.NETWORK,
24
+ sha256="deadbeef",
25
+ source="dns",
26
+ custody=[CustodyEvent(actor="tester", action="collected")],
27
+ )
28
+ assert evidence.custody[0].actor == "tester"
29
+
30
+
31
+ def test_assertion_defaults() -> None:
32
+ entity = Entity(kind=EntityKind.DOMAIN, value="example.com")
33
+ assertion = Assertion(
34
+ subject_id=entity.id,
35
+ predicate="resolves_to",
36
+ object="93.184.216.34",
37
+ )
38
+ assert assertion.band == ConfidenceBand.INDICATIVE
39
+
40
+
41
+ def test_relation_attributes() -> None:
42
+ src = Entity(kind=EntityKind.EMAIL, value="alice@example.com")
43
+ dst = Entity(kind=EntityKind.USERNAME, value="alice")
44
+ relation = Relation(source_id=src.id, target_id=dst.id, relation_type="aka")
45
+ assert relation.source_id == src.id
46
+ assert relation.relation_type == "aka"