shadowbq-threatinator 0.5.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +66 -0
- data/CONTRIBUTING.md +119 -0
- data/Gemfile +38 -0
- data/LICENSE +165 -0
- data/README.md +101 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/bin/threatinator +5 -0
- data/bin/threatinator_loader +21 -0
- data/feeds/ET_block-ip_reputation.feed +27 -0
- data/feeds/ET_compromised-ip_reputation.feed +20 -0
- data/feeds/ET_openbadlist-ip_reputation.feed +36 -0
- data/feeds/alienvault-ip_reputation.feed +39 -0
- data/feeds/arbor_fastflux-domain_reputation.feed +19 -0
- data/feeds/arbor_ssh-ip_reputation.feed +24 -0
- data/feeds/autoshun_shunlist.feed +17 -0
- data/feeds/bambenek_c2_masterlist-domain_reputation.feed +16 -0
- data/feeds/bambenek_c2_masterlist-ip_reputation.feed +16 -0
- data/feeds/bambenek_dga_feed-domain_reputation.feed +16 -0
- data/feeds/berkeley-ip_reputation.feed +25 -0
- data/feeds/bitcash_cz_blacklist.feed +22 -0
- data/feeds/blocklist_de_apache-ip_reputation.feed +26 -0
- data/feeds/blocklist_de_bots-ip_reputation.feed +26 -0
- data/feeds/blocklist_de_ftp-ip_reputation.feed +25 -0
- data/feeds/blocklist_de_imap-ip_reputation.feed +25 -0
- data/feeds/blocklist_de_pop3-ip_reputation.feed +26 -0
- data/feeds/blocklist_de_proftpd-ip_reputation.feed +26 -0
- data/feeds/blocklist_de_sip-ip_reputation.feed +25 -0
- data/feeds/blocklist_de_ssh-ip_reputation.feed +25 -0
- data/feeds/blocklist_de_strongips-ip_reputation.feed +25 -0
- data/feeds/botscout-ip_reputation.feed +25 -0
- data/feeds/cert_mxpoison-ip_reputation.feed +22 -0
- data/feeds/chaosreigns-ip_reputation.feed +37 -0
- data/feeds/ciarmy-ip_reputation.feed +20 -0
- data/feeds/cruzit-ip_reputation.feed +30 -0
- data/feeds/cydef_torexit-ip_reputation.feed +25 -0
- data/feeds/dan_me_uk_torlist-ip_reputation.feed +25 -0
- data/feeds/danger_bruteforce-ip_reputation.feed +24 -0
- data/feeds/dshield_attackers-top1000.feed +34 -0
- data/feeds/falconcrest-ip_reputation.feed +19 -0
- data/feeds/feodo-domain_reputation.feed +19 -0
- data/feeds/feodo-ip_reputation.feed +20 -0
- data/feeds/h3x_asprox.feed +18 -0
- data/feeds/hosts-file_hphostspartial-domain_reputation.feed +19 -0
- data/feeds/infiltrated-ip_reputation.feed +26 -0
- data/feeds/infiltrated_vabl-ip_reputation.feed +30 -0
- data/feeds/isc_suspicious_high-domain_reputation.feed +26 -0
- data/feeds/isc_suspicious_low-domain_reputation.feed +26 -0
- data/feeds/isc_suspicious_medium-domain_reputation.feed +26 -0
- data/feeds/malc0de-domain_reputation.feed +24 -0
- data/feeds/malc0de-ip_reputation.feed +26 -0
- data/feeds/malwaredomainlist-url_reputation.feed +18 -0
- data/feeds/malwaredomains-domain_reputation.feed +29 -0
- data/feeds/malwaredomains_dyndns-domain_reputation.feed +29 -0
- data/feeds/malwaredomains_justdomains-domain_reputation.feed +20 -0
- data/feeds/mirc-domain_reputation.feed +30 -0
- data/feeds/multiproxy-ip_reputation.feed +22 -0
- data/feeds/nothink_irc-ip_reputation.feed +23 -0
- data/feeds/nothink_ssh-ip_reputation.feed +21 -0
- data/feeds/openbl-ip_reputation.feed +21 -0
- data/feeds/openphish-url_reputation.feed +24 -0
- data/feeds/packetmail_perimeterbad-ip_reputation.feed +28 -0
- data/feeds/palevo-domain_reputation.feed +22 -0
- data/feeds/palevo-ip_reputation.feed +23 -0
- data/feeds/phishtank.feed +22 -0
- data/feeds/sigmaproject_atma.feed +27 -0
- data/feeds/sigmaproject_spyware.feed +28 -0
- data/feeds/sigmaproject_webexploit.feed +26 -0
- data/feeds/snort_bpf-ip_reputation.feed +19 -0
- data/feeds/spyeye-domain_reputation.feed +18 -0
- data/feeds/spyeye-ip_reputation.feed +19 -0
- data/feeds/steeman-ip_reputation.feed +20 -0
- data/feeds/t-arend-de_ssh-ip_reputation.feed +20 -0
- data/feeds/the_haleys_ssh-ip_reputation.feed +20 -0
- data/feeds/trustedsec-ip_reputation.feed +18 -0
- data/feeds/virbl-ip_reputation.feed +25 -0
- data/feeds/vxvault-url_reputation.feed +23 -0
- data/feeds/yourcmc_ssh-ip_reputation.feed +20 -0
- data/feeds/yoyo_adservers-domain_reputation.feed +17 -0
- data/feeds/zeus-domain_reputation.feed +19 -0
- data/feeds/zeus-ip_reputation.feed +21 -0
- data/lib/threatinator/action.rb +14 -0
- data/lib/threatinator/actions/list/action.rb +97 -0
- data/lib/threatinator/actions/list/config.rb +12 -0
- data/lib/threatinator/actions/list.rb +2 -0
- data/lib/threatinator/actions/run/action.rb +57 -0
- data/lib/threatinator/actions/run/config.rb +32 -0
- data/lib/threatinator/actions/run/coverage_observer.rb +59 -0
- data/lib/threatinator/actions/run/output_config.rb +59 -0
- data/lib/threatinator/actions/run/status_observer.rb +37 -0
- data/lib/threatinator/actions/run.rb +2 -0
- data/lib/threatinator/cli/action_builder.rb +33 -0
- data/lib/threatinator/cli/list_action_builder.rb +19 -0
- data/lib/threatinator/cli/parser.rb +123 -0
- data/lib/threatinator/cli/run_action_builder.rb +41 -0
- data/lib/threatinator/cli.rb +19 -0
- data/lib/threatinator/config/base.rb +35 -0
- data/lib/threatinator/config/feed_search.rb +25 -0
- data/lib/threatinator/config/logger.rb +14 -0
- data/lib/threatinator/config.rb +7 -0
- data/lib/threatinator/decoder.rb +24 -0
- data/lib/threatinator/decoders/gzip.rb +30 -0
- data/lib/threatinator/event.rb +63 -0
- data/lib/threatinator/event_builder.rb +70 -0
- data/lib/threatinator/exceptions.rb +58 -0
- data/lib/threatinator/feed.rb +88 -0
- data/lib/threatinator/feed_builder.rb +161 -0
- data/lib/threatinator/feed_registry.rb +47 -0
- data/lib/threatinator/feed_runner.rb +177 -0
- data/lib/threatinator/fetcher.rb +22 -0
- data/lib/threatinator/fetchers/http.rb +50 -0
- data/lib/threatinator/filter.rb +12 -0
- data/lib/threatinator/filters/block.rb +18 -0
- data/lib/threatinator/filters/comments.rb +16 -0
- data/lib/threatinator/filters/whitespace.rb +19 -0
- data/lib/threatinator/logger.rb +66 -0
- data/lib/threatinator/logging.rb +20 -0
- data/lib/threatinator/model/base.rb +23 -0
- data/lib/threatinator/model/collection.rb +89 -0
- data/lib/threatinator/model/observables/fqdn_collection.rb +15 -0
- data/lib/threatinator/model/observables/ipv4.rb +33 -0
- data/lib/threatinator/model/observables/ipv4_collection.rb +14 -0
- data/lib/threatinator/model/observables/url_collection.rb +16 -0
- data/lib/threatinator/model/validations/type.rb +21 -0
- data/lib/threatinator/model/validations.rb +1 -0
- data/lib/threatinator/output.rb +50 -0
- data/lib/threatinator/parser.rb +23 -0
- data/lib/threatinator/parsers/csv/parser.rb +77 -0
- data/lib/threatinator/parsers/csv.rb +7 -0
- data/lib/threatinator/parsers/getline/parser.rb +45 -0
- data/lib/threatinator/parsers/getline.rb +8 -0
- data/lib/threatinator/parsers/json/adapters/oj.rb +65 -0
- data/lib/threatinator/parsers/json/parser.rb +45 -0
- data/lib/threatinator/parsers/json/record.rb +20 -0
- data/lib/threatinator/parsers/json.rb +8 -0
- data/lib/threatinator/parsers/xml/node.rb +79 -0
- data/lib/threatinator/parsers/xml/node_builder.rb +39 -0
- data/lib/threatinator/parsers/xml/parser.rb +44 -0
- data/lib/threatinator/parsers/xml/path.rb +70 -0
- data/lib/threatinator/parsers/xml/pattern.rb +53 -0
- data/lib/threatinator/parsers/xml/record.rb +14 -0
- data/lib/threatinator/parsers/xml/sax_document.rb +64 -0
- data/lib/threatinator/parsers/xml.rb +8 -0
- data/lib/threatinator/plugin_loader.rb +115 -0
- data/lib/threatinator/plugins/output/amqp/config.rb +18 -0
- data/lib/threatinator/plugins/output/amqp.rb +41 -0
- data/lib/threatinator/plugins/output/csv.rb +58 -0
- data/lib/threatinator/plugins/output/json/config.rb +14 -0
- data/lib/threatinator/plugins/output/json.rb +53 -0
- data/lib/threatinator/plugins/output/null.rb +17 -0
- data/lib/threatinator/plugins/output/rubydebug.rb +16 -0
- data/lib/threatinator/record.rb +22 -0
- data/lib/threatinator/registry.rb +53 -0
- data/lib/threatinator/util.rb +15 -0
- data/lib/threatinator.rb +3 -0
- data/spec/feeds/ET_block-ip_reputation_spec.rb +50 -0
- data/spec/feeds/ET_compromised-ip_reputation_spec.rb +47 -0
- data/spec/feeds/ET_openbadlist-ip_reputation_spec.rb +56 -0
- data/spec/feeds/alienvault-ip_reputation_spec.rb +46 -0
- data/spec/feeds/arbor_fastflux-domain_reputation_spec.rb +46 -0
- data/spec/feeds/arbor_ssh-ip_reputation_spec.rb +46 -0
- data/spec/feeds/autoshun_shunlist_spec.rb +38 -0
- data/spec/feeds/bambenek_c2_masterlist-domain_reputation_spec.rb +38 -0
- data/spec/feeds/bambenek_c2_masterlist-ip_reputation_spec.rb +39 -0
- data/spec/feeds/bambenek_dga_feed-domain_reputation_spec.rb +39 -0
- data/spec/feeds/berkeley-ip_reputation_spec.rb +47 -0
- data/spec/feeds/bitcash_cz_blacklist-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_apache-ip_reputation_spec.rb +47 -0
- data/spec/feeds/blocklist_de_bots-ip_reputation_spec.rb +47 -0
- data/spec/feeds/blocklist_de_ftp-ip_reputation_spec.rb +47 -0
- data/spec/feeds/blocklist_de_imap-ip_reputation_spec.rb +47 -0
- data/spec/feeds/blocklist_de_pop3-ip_reputation_spec.rb +47 -0
- data/spec/feeds/blocklist_de_proftpd-ip_reputation_spec.rb +47 -0
- data/spec/feeds/blocklist_de_sip-ip_reputation_spec.rb +47 -0
- data/spec/feeds/blocklist_de_ssh-ip_reputation_spec.rb +47 -0
- data/spec/feeds/blocklist_de_strongips-ip_reputation_spec.rb +47 -0
- data/spec/feeds/botscout-ip_reputation_spec.rb +50 -0
- data/spec/feeds/cert_mxpoison-ip_reputation_spec.rb +47 -0
- data/spec/feeds/chaosreigns-ip_reputation_spec.rb +50 -0
- data/spec/feeds/ciarmy-ip_reputation_spec.rb +47 -0
- data/spec/feeds/cruzit-ip_reputation_spec.rb +47 -0
- data/spec/feeds/cydef_torexit-ip_reputation_spec.rb +47 -0
- data/spec/feeds/dan_me_uk_torlist-ip_reputation_spec.rb +47 -0
- data/spec/feeds/danger_bruteforce-ip_reputation_spec.rb +47 -0
- data/spec/feeds/data/ET_block-ip_reputation.txt +80 -0
- data/spec/feeds/data/ET_compromised-ip_reputation.txt +11 -0
- data/spec/feeds/data/ET_openbadlist-ip_reputation.txt +62 -0
- data/spec/feeds/data/alienvault-ip_reputation.txt +18 -0
- data/spec/feeds/data/arbor_domainlist.txt +11 -0
- data/spec/feeds/data/arbor_ssh.txt +16 -0
- data/spec/feeds/data/autoshun_shunlist.csv +20 -0
- data/spec/feeds/data/bambenek_c2-dommasterlist.csv +30 -0
- data/spec/feeds/data/bambenek_c2-ipmasterlist.csv +27 -0
- data/spec/feeds/data/bambenek_dga_feed.csv +42 -0
- data/spec/feeds/data/berkeley.txt +29 -0
- data/spec/feeds/data/bitcash_cz_blacklist.txt +7 -0
- data/spec/feeds/data/blocklist_de_apache-ip-reputation.txt +17 -0
- data/spec/feeds/data/blocklist_de_bots-ip-reputation.txt +15 -0
- data/spec/feeds/data/blocklist_de_ftp-ip-reputation.txt +7 -0
- data/spec/feeds/data/blocklist_de_imap-ip-reputation.txt +8 -0
- data/spec/feeds/data/blocklist_de_pop3-ip-reputation.txt +11 -0
- data/spec/feeds/data/blocklist_de_proftpd-ip-reputation.txt +12 -0
- data/spec/feeds/data/blocklist_de_sip-ip-reputation.txt +9 -0
- data/spec/feeds/data/blocklist_de_ssh-ip-reputation.txt +10 -0
- data/spec/feeds/data/blocklist_de_strongips-ip-reputation.txt +11 -0
- data/spec/feeds/data/botscout-ip-reputation.txt +713 -0
- data/spec/feeds/data/cert_mxpoison-ip_reputation.txt +17 -0
- data/spec/feeds/data/chaosreigns-ip-reputation.txt +26 -0
- data/spec/feeds/data/ciarmy-ip-reputation.txt +11 -0
- data/spec/feeds/data/cruzit-ip-reputation.txt +14 -0
- data/spec/feeds/data/cydef_torexit-ip_reputation.txt +27 -0
- data/spec/feeds/data/dan_me_uk_torlist-ip-reputation.txt +11 -0
- data/spec/feeds/data/danger_bruteforce-ip_reputation.txt +12 -0
- data/spec/feeds/data/dshield_topattackers.xml +4 -0
- data/spec/feeds/data/falconcrest_iplist.txt +345 -0
- data/spec/feeds/data/feodo_domainlist.txt +18 -0
- data/spec/feeds/data/feodo_iplist.txt +20 -0
- data/spec/feeds/data/h3x_asprox.txt +20 -0
- data/spec/feeds/data/hosts-file_hphostspartial_domainlist.txt +24 -0
- data/spec/feeds/data/infiltrated_iplist.txt +16 -0
- data/spec/feeds/data/infiltrated_vabl_iplist.txt +33 -0
- data/spec/feeds/data/isc_suspicious_high_domainlist.txt +26 -0
- data/spec/feeds/data/isc_suspicious_low_domainlist.txt +34 -0
- data/spec/feeds/data/isc_suspicious_medium_domainlist.txt +32 -0
- data/spec/feeds/data/malc0de_domainlist.txt +18 -0
- data/spec/feeds/data/malc0de_iplist.txt +14 -0
- data/spec/feeds/data/malwaredomainlist-url-reputation.txt +8 -0
- data/spec/feeds/data/malwaredomains_domainlist.txt +24 -0
- data/spec/feeds/data/malwaredomains_dyndns_domainlist.txt +34 -0
- data/spec/feeds/data/malwaredomains_justdomains_domainlist.txt +18 -0
- data/spec/feeds/data/mirc_domainlist.txt +31 -0
- data/spec/feeds/data/multiproxy_iplist.txt +15 -0
- data/spec/feeds/data/nothink_irc_iplist.txt +14 -0
- data/spec/feeds/data/nothink_ssh_iplist.txt +10 -0
- data/spec/feeds/data/openbl_iplist.txt +12 -0
- data/spec/feeds/data/openphish-url-reputation.txt +16 -0
- data/spec/feeds/data/packetmail_perimeterbad-ip_reputation.txt +44 -0
- data/spec/feeds/data/palevo_domainlist.txt +25 -0
- data/spec/feeds/data/palevo_iplist.txt +24 -0
- data/spec/feeds/data/phishtank-sample.json.gz +0 -0
- data/spec/feeds/data/sigmaproject_atma.return.gz +0 -0
- data/spec/feeds/data/sigmaproject_spyware.return.gz +0 -0
- data/spec/feeds/data/sigmaproject_webexploit.return.gz +0 -0
- data/spec/feeds/data/snort_bpf-ip_reputation.txt +16 -0
- data/spec/feeds/data/spyeye_domainlist.txt +16 -0
- data/spec/feeds/data/spyeye_iplist.txt +19 -0
- data/spec/feeds/data/steeman-ip-reputation.txt +13 -0
- data/spec/feeds/data/t-arend-de_ssh_iplist.txt +17 -0
- data/spec/feeds/data/the_haleys_ssh_iplist.txt +12 -0
- data/spec/feeds/data/trustedsec-ip-reputation.txt +12 -0
- data/spec/feeds/data/valid.json +2908 -0
- data/spec/feeds/data/virbl-ip_reputation.txt +14 -0
- data/spec/feeds/data/vxvault-url-reputation.txt +15 -0
- data/spec/feeds/data/yourcmc_ssh-ip_reputation.txt +27 -0
- data/spec/feeds/data/yoyo_adservers.txt +25 -0
- data/spec/feeds/data/zeus-ip_reputation.txt +285 -0
- data/spec/feeds/data/zeus_domainlist.txt +27 -0
- data/spec/feeds/dshield_attackers-top1000_spec.rb +39 -0
- data/spec/feeds/falconcrest-ip_reputation_spec.rb +39 -0
- data/spec/feeds/feodo-domain_reputation_spec.rb +47 -0
- data/spec/feeds/feodo-ip_reputation_spec.rb +47 -0
- data/spec/feeds/h3x_asprox-ip_reputation_spec.rb +50 -0
- data/spec/feeds/hosts-file_hphostspartial-domain_reputation_spec.rb +47 -0
- data/spec/feeds/infiltrated-ip_reputation_spec.rb +47 -0
- data/spec/feeds/infiltrated_vabl-ip_reputation_spec.rb +47 -0
- data/spec/feeds/isc_suspicious_high-domain_reputation_spec.rb +47 -0
- data/spec/feeds/isc_suspicious_low-domain_reputation_spec.rb +47 -0
- data/spec/feeds/isc_suspicious_medium-domain_reputation_spec.rb +47 -0
- data/spec/feeds/malc0de-domain_reputation_spec.rb +47 -0
- data/spec/feeds/malc0de-ip_reputation_spec.rb +47 -0
- data/spec/feeds/malwaredomainlist_url_reputation_spec.rb +50 -0
- data/spec/feeds/malwaredomains-domain_reputation_spec.rb +47 -0
- data/spec/feeds/malwaredomains_dyndns-domain_reputation_spec.rb +47 -0
- data/spec/feeds/malwaredomains_justdomains-domain_reputation_spec.rb +47 -0
- data/spec/feeds/mirc-domain_reputation_spec.rb +47 -0
- data/spec/feeds/multiproxy-ip_reputation_spec.rb +47 -0
- data/spec/feeds/nothink_irc-ip_reputation_spec.rb +47 -0
- data/spec/feeds/nothink_ssh-ip_reputation_spec.rb +47 -0
- data/spec/feeds/openbl-ip_reputation_spec.rb +47 -0
- data/spec/feeds/openphish_url_reputation_spec.rb +50 -0
- data/spec/feeds/packetmail_perimeterbad-ip_reputation_spec.rb +47 -0
- data/spec/feeds/palevo-domain_reputation_spec.rb +47 -0
- data/spec/feeds/palevo-ip_reputation_spec.rb +47 -0
- data/spec/feeds/phishtank_spec.rb +41 -0
- data/spec/feeds/sigmaproject_atma_spec.rb +62 -0
- data/spec/feeds/sigmaproject_spyware_spec.rb +63 -0
- data/spec/feeds/sigmaproject_webexploit_spec.rb +62 -0
- data/spec/feeds/snort_bpf-ip_reputation_spec.rb +47 -0
- data/spec/feeds/spyeye-domain_reputation_spec.rb +47 -0
- data/spec/feeds/spyeye-ip_reputation_spec.rb +47 -0
- data/spec/feeds/steeman-ip_reputation_spec.rb +50 -0
- data/spec/feeds/t-arend-de_ssh-ip_reputation_spec.rb +47 -0
- data/spec/feeds/the_haleys_ssh-ip_reputation_spec.rb +47 -0
- data/spec/feeds/trustedsec-ip_reputation_spec.rb +47 -0
- data/spec/feeds/virbl-ip_reputation_spec.rb +47 -0
- data/spec/feeds/vxvault_url_reputation_spec.rb +50 -0
- data/spec/feeds/yourcmc_ssh-ip_reputation_spec.rb +47 -0
- data/spec/feeds/yoyo_adservers_spec.rb +47 -0
- data/spec/feeds/zeus-domain_reputation_spec.rb +47 -0
- data/spec/feeds/zeus-ip_reputation_spec.rb +47 -0
- data/spec/fixtures/feed/provider1/feed1.feed +6 -0
- data/spec/fixtures/parsers/test.xml +13 -0
- data/spec/fixtures/parsers/test_self_closing.xml +20 -0
- data/spec/fixtures/plugins/bad/threatinator/plugins/test_error1/plugin.rb +1 -0
- data/spec/fixtures/plugins/bad/threatinator/plugins/test_missing1/plugin.rb +0 -0
- data/spec/fixtures/plugins/fake.rb +19 -0
- data/spec/fixtures/plugins/good/threatinator/plugins/test_type1/plugin_a.rb +8 -0
- data/spec/fixtures/plugins/good/threatinator/plugins/test_type1/plugin_b.rb +8 -0
- data/spec/fixtures/plugins/good/threatinator/plugins/test_type2/plugin_c.rb +8 -0
- data/spec/fixtures/plugins/good/threatinator/plugins/test_type2/plugin_d.rb +8 -0
- data/spec/fixtures/plugins/good/threatinator/plugins/test_type3/plugin_e.rb +8 -0
- data/spec/fixtures/plugins/good/threatinator/plugins/test_type3/plugin_f.rb +8 -0
- data/spec/spec_helper.rb +54 -0
- data/spec/support/bad_feeds/missing_fetcher.feed +7 -0
- data/spec/support/bad_feeds/missing_name.feed +6 -0
- data/spec/support/bad_feeds/missing_parser.feed +3 -0
- data/spec/support/bad_feeds/missing_provider.feed +5 -0
- data/spec/support/factories/event.rb +31 -0
- data/spec/support/factories/feed.rb +59 -0
- data/spec/support/factories/feed_builder.rb +65 -0
- data/spec/support/factories/feed_registry.rb +8 -0
- data/spec/support/factories/ipv4.rb +36 -0
- data/spec/support/factories/output.rb +11 -0
- data/spec/support/factories/record.rb +17 -0
- data/spec/support/factories/url.rb +34 -0
- data/spec/support/factories/xml_node.rb +33 -0
- data/spec/support/helpers/io.rb +11 -0
- data/spec/support/helpers/models.rb +13 -0
- data/spec/support/shared/action_builder.rb +47 -0
- data/spec/support/shared/decoder.rb +70 -0
- data/spec/support/shared/feed_runner_observer.rb +136 -0
- data/spec/support/shared/feeds.rb +233 -0
- data/spec/support/shared/fetcher.rb +48 -0
- data/spec/support/shared/filter.rb +14 -0
- data/spec/support/shared/io-like.rb +7 -0
- data/spec/support/shared/model/collection.rb +164 -0
- data/spec/support/shared/output.rb +120 -0
- data/spec/support/shared/parsers.rb +51 -0
- data/spec/support/shared/record.rb +111 -0
- data/spec/threatinator/actions/list/action_spec.rb +148 -0
- data/spec/threatinator/actions/run/action_spec.rb +106 -0
- data/spec/threatinator/actions/run/config_spec.rb +39 -0
- data/spec/threatinator/actions/run/coverage_observer_spec.rb +151 -0
- data/spec/threatinator/actions/run/output_config_spec.rb +89 -0
- data/spec/threatinator/actions/run/status_observer_spec.rb +86 -0
- data/spec/threatinator/cli/list_action_builder_spec.rb +57 -0
- data/spec/threatinator/cli/run_action_builder_spec.rb +133 -0
- data/spec/threatinator/cli_spec.rb +175 -0
- data/spec/threatinator/config/base_spec.rb +39 -0
- data/spec/threatinator/config/feed_search_spec.rb +76 -0
- data/spec/threatinator/decoders/gzip_spec.rb +75 -0
- data/spec/threatinator/event_builder_spec.rb +123 -0
- data/spec/threatinator/event_spec.rb +254 -0
- data/spec/threatinator/event_spec.rb.new +319 -0
- data/spec/threatinator/feed_builder_spec.rb +633 -0
- data/spec/threatinator/feed_registry_spec.rb +198 -0
- data/spec/threatinator/feed_runner_spec.rb +372 -0
- data/spec/threatinator/feed_spec.rb +169 -0
- data/spec/threatinator/fetcher_spec.rb +12 -0
- data/spec/threatinator/fetchers/http_spec.rb +32 -0
- data/spec/threatinator/filter_spec.rb +13 -0
- data/spec/threatinator/filters/block_spec.rb +16 -0
- data/spec/threatinator/filters/comments_spec.rb +13 -0
- data/spec/threatinator/filters/whitespace_spec.rb +12 -0
- data/spec/threatinator/logger_spec.rb +29 -0
- data/spec/threatinator/model/observables/fqdn_collection_spec.rb +41 -0
- data/spec/threatinator/model/observables/ipv4_collection_spec.rb +36 -0
- data/spec/threatinator/model/observables/ipv4_spec.rb +75 -0
- data/spec/threatinator/model/observables/url_collection_spec.rb +45 -0
- data/spec/threatinator/model/validations/type_spec.rb +37 -0
- data/spec/threatinator/parser_spec.rb +13 -0
- data/spec/threatinator/parsers/csv/parser_spec.rb +202 -0
- data/spec/threatinator/parsers/getline/parser_spec.rb +83 -0
- data/spec/threatinator/parsers/json/parser_spec.rb +106 -0
- data/spec/threatinator/parsers/json/record_spec.rb +30 -0
- data/spec/threatinator/parsers/xml/node_spec.rb +335 -0
- data/spec/threatinator/parsers/xml/parser_spec.rb +263 -0
- data/spec/threatinator/parsers/xml/path_spec.rb +209 -0
- data/spec/threatinator/parsers/xml/pattern_spec.rb +72 -0
- data/spec/threatinator/parsers/xml/record_spec.rb +27 -0
- data/spec/threatinator/plugin_loader_spec.rb +238 -0
- data/spec/threatinator/plugins/output/csv_spec.rb +47 -0
- data/spec/threatinator/plugins/output/null_spec.rb +17 -0
- data/spec/threatinator/plugins/output/rubydebug_spec.rb +37 -0
- data/spec/threatinator/record_spec.rb +19 -0
- data/spec/threatinator/registry_spec.rb +97 -0
- data/spec/threatinator/runner_spec.rb +273 -0
- metadata +674 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'active_model'
|
|
2
|
+
require 'active_model/validations'
|
|
3
|
+
require 'threatinator/model/validations'
|
|
4
|
+
require 'threatinator/exceptions'
|
|
5
|
+
|
|
6
|
+
module Threatinator
|
|
7
|
+
module Model
|
|
8
|
+
class Base
|
|
9
|
+
include ActiveModel::Validations
|
|
10
|
+
include Threatinator::Model::Validations
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
validate!
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def validate!
|
|
17
|
+
unless valid?
|
|
18
|
+
raise Threatinator::Exceptions::InvalidAttributeError, errors.full_messages.join("\n")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require 'threatinator/exceptions'
|
|
2
|
+
require 'set'
|
|
3
|
+
|
|
4
|
+
module Threatinator
|
|
5
|
+
module Model
|
|
6
|
+
class Collection
|
|
7
|
+
def initialize(values = [])
|
|
8
|
+
@collection = Set.new
|
|
9
|
+
values.each do |v|
|
|
10
|
+
self << v
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def valid_member?(v)
|
|
15
|
+
#:nocov:
|
|
16
|
+
raise NotImplementedError, "#valid_member? not implemented"
|
|
17
|
+
#:nocov:
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def <<(v)
|
|
21
|
+
unless valid_member?(v)
|
|
22
|
+
raise Threatinator::Exceptions::InvalidAttributeError, "Invalid member: #{v.class} '#{v.inspect}'"
|
|
23
|
+
end
|
|
24
|
+
@collection << v
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def include?(member)
|
|
28
|
+
@collection.include?(member)
|
|
29
|
+
end
|
|
30
|
+
alias_method :member?, :include?
|
|
31
|
+
|
|
32
|
+
# @return [Boolean] true if empty, false otherwise
|
|
33
|
+
def empty?
|
|
34
|
+
@collection.empty?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def collect!
|
|
38
|
+
block_given? or return enum_for(__method__)
|
|
39
|
+
@collection.replace(@collection.class.new(@collection) { |o| yield(o) })
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def delete(o)
|
|
43
|
+
@collection.delete(o)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def delete?(o)
|
|
47
|
+
@collection.delete?(o)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @return [Integer] the number of members in the collection
|
|
51
|
+
def count
|
|
52
|
+
@collection.count
|
|
53
|
+
end
|
|
54
|
+
alias_method :size, :count
|
|
55
|
+
alias_method :length, :count
|
|
56
|
+
|
|
57
|
+
def to_ary
|
|
58
|
+
@collection.to_a
|
|
59
|
+
end
|
|
60
|
+
alias_method :to_a, :to_ary
|
|
61
|
+
|
|
62
|
+
# [31] pry(#<Threatinator::Plugins::Output::Json>)> event.urls.each{ |uri| p uri.to_s }
|
|
63
|
+
# "http://teamadrenaline.com/js/t1.exe"
|
|
64
|
+
# => [#<Addressable::URI:0x114c6ec URI:http://teamadrenaline.com/js/t1.exe>]
|
|
65
|
+
def each
|
|
66
|
+
return to_enum(:each) unless block_given?
|
|
67
|
+
@collection.each { |v| yield v }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def list
|
|
71
|
+
@collection.to_a.collect {|item|
|
|
72
|
+
item.to_s
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def ==(other)
|
|
77
|
+
if self.equal?(other)
|
|
78
|
+
return true
|
|
79
|
+
elsif other.instance_of?(self.class)
|
|
80
|
+
@collection == other.instance_variable_get(:@collection)
|
|
81
|
+
else
|
|
82
|
+
false
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'threatinator/model/collection'
|
|
2
|
+
require 'domain_name_validator'
|
|
3
|
+
|
|
4
|
+
module Threatinator
|
|
5
|
+
module Model
|
|
6
|
+
module Observables
|
|
7
|
+
class FqdnCollection < Threatinator::Model::Collection
|
|
8
|
+
def valid_member?(v)
|
|
9
|
+
#v.is_a?(::String)
|
|
10
|
+
::DomainNameValidator.new.validate(v.to_s)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'threatinator/model/base'
|
|
2
|
+
require 'ip'
|
|
3
|
+
require 'equalizer'
|
|
4
|
+
|
|
5
|
+
module Threatinator
|
|
6
|
+
module Model
|
|
7
|
+
module Observables
|
|
8
|
+
class Ipv4 < Threatinator::Model::Base
|
|
9
|
+
include Equalizer.new(:ipv4)
|
|
10
|
+
attr_reader :ipv4
|
|
11
|
+
|
|
12
|
+
validates_each :ipv4 do |record, attr, value|
|
|
13
|
+
if value.is_a?(::IP::V4)
|
|
14
|
+
record.errors.add(attr, 'prefix length is not 32 bits') unless value.pfxlen == 32
|
|
15
|
+
else
|
|
16
|
+
record.errors.add(attr, 'not an IP::V4 object')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @param [Hash] opts
|
|
21
|
+
# @option opts [IP::V4] :ipv4 An ipv4 object
|
|
22
|
+
def initialize(opts = {})
|
|
23
|
+
@ipv4 = opts.delete(:ipv4)
|
|
24
|
+
super()
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_s
|
|
28
|
+
return ipv4.to_s
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'threatinator/model/collection'
|
|
2
|
+
require 'threatinator/model/observables/ipv4'
|
|
3
|
+
|
|
4
|
+
module Threatinator
|
|
5
|
+
module Model
|
|
6
|
+
module Observables
|
|
7
|
+
class Ipv4Collection < Threatinator::Model::Collection
|
|
8
|
+
def valid_member?(v)
|
|
9
|
+
v.kind_of?(Threatinator::Model::Observables::Ipv4)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'threatinator/model/collection'
|
|
2
|
+
require 'addressable/uri'
|
|
3
|
+
|
|
4
|
+
module Threatinator
|
|
5
|
+
module Model
|
|
6
|
+
module Observables
|
|
7
|
+
class UrlCollection < Threatinator::Model::Collection
|
|
8
|
+
def valid_member?(v)
|
|
9
|
+
v.is_a?(::Addressable::URI) &&
|
|
10
|
+
v.absolute?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'active_model'
|
|
2
|
+
require 'active_model/validations'
|
|
3
|
+
|
|
4
|
+
module Threatinator
|
|
5
|
+
module Model
|
|
6
|
+
module Validations
|
|
7
|
+
class TypeValidator < ActiveModel::EachValidator
|
|
8
|
+
def initialize(options)
|
|
9
|
+
@type = options.delete(:with)
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def validate_each(record, name, value)
|
|
14
|
+
unless value.is_a?(@type)
|
|
15
|
+
record.errors.add name, "Expected to be #{@type}, got #{value.class} #{value.inspect}"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'threatinator/model/validations/type'
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'threatinator/config/base'
|
|
2
|
+
|
|
3
|
+
module Threatinator
|
|
4
|
+
class Output
|
|
5
|
+
def initialize(config)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def handle_event(event)
|
|
9
|
+
#:nocov:
|
|
10
|
+
raise NotImplementedError.new("#{self.class}#handle_event is not implemented")
|
|
11
|
+
#:nocov:
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def finish
|
|
15
|
+
#:nocov:
|
|
16
|
+
raise NotImplementedError.new("#{self.class}#finish is not implemented")
|
|
17
|
+
#:nocov:
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Config < Threatinator::Config::Base
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class FileBasedOutput < Output
|
|
25
|
+
attr_reader :output_io
|
|
26
|
+
protected :output_io
|
|
27
|
+
|
|
28
|
+
def initialize(config)
|
|
29
|
+
super(config)
|
|
30
|
+
if io = config.io
|
|
31
|
+
@output_io = io
|
|
32
|
+
elsif filename = config.filename
|
|
33
|
+
@output_io = File.open(filename, 'w:UTF-8')
|
|
34
|
+
else
|
|
35
|
+
@output_io = $stdout.dup
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def finish
|
|
40
|
+
@output_io.close
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class Config < superclass::Config
|
|
44
|
+
attribute :filename, String,
|
|
45
|
+
description: "Path to the file where output will be written"
|
|
46
|
+
|
|
47
|
+
attribute :io
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Threatinator
|
|
2
|
+
class Parser
|
|
3
|
+
# @param [Hash] opts An options hash. See subclasses for details.
|
|
4
|
+
def initialize(opts = {})
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Runs the parser against the provided io, yielding records.
|
|
8
|
+
# @param [IO] io The IO to be parsed.
|
|
9
|
+
def run(io)
|
|
10
|
+
raise NotImplementedError.new("#{self.class}#run not implemented!")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def ==(other)
|
|
14
|
+
true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def eql?(other)
|
|
18
|
+
self.class == other.class &&
|
|
19
|
+
self == other
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require 'threatinator/record'
|
|
2
|
+
require 'threatinator/parser'
|
|
3
|
+
require 'csv'
|
|
4
|
+
|
|
5
|
+
module Threatinator
|
|
6
|
+
module Parsers
|
|
7
|
+
module CSV
|
|
8
|
+
# Parses an IO, yielding a record with a CSV::Row.
|
|
9
|
+
class Parser < Threatinator::Parser
|
|
10
|
+
attr_reader :csv_opts, :row_separator, :col_separator, :headers
|
|
11
|
+
|
|
12
|
+
# @param [Hash] opts
|
|
13
|
+
# @option opts [String, :auto] :row_separator A string that represent the row
|
|
14
|
+
# separator. Identical to ::CSV.new's :row_sep.
|
|
15
|
+
# @option opts [String] :col_separator A string that represents the column
|
|
16
|
+
# separator. Identical to ::CSV.new's :col_sep.
|
|
17
|
+
# @option opts [Array<String>, :first_row, true, false] :headers The header
|
|
18
|
+
# configuration. Identical to ::CSV.new's :headers.
|
|
19
|
+
# @option opts [Hash] :csv_opts A hash of options that will be passed to
|
|
20
|
+
# Ruby's CSV.new.
|
|
21
|
+
# @see ::CSV
|
|
22
|
+
def initialize(opts = {})
|
|
23
|
+
@csv_opts = {}.merge(opts.delete(:csv_opts) || {})
|
|
24
|
+
@row_separator = opts.delete(:row_separator)
|
|
25
|
+
@col_separator = opts.delete(:col_separator)
|
|
26
|
+
@headers = opts.delete(:headers)
|
|
27
|
+
|
|
28
|
+
super(opts)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def ==(other)
|
|
32
|
+
@csv_opts == other.csv_opts &&
|
|
33
|
+
@row_separator == other.row_separator &&
|
|
34
|
+
@col_separator == other.col_separator &&
|
|
35
|
+
@headers == other.headers &&
|
|
36
|
+
super(other)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def _build_csv_opts
|
|
40
|
+
opts = {}.merge(@csv_opts)
|
|
41
|
+
opts[:return_headers] = true
|
|
42
|
+
opts[:row_sep] = @row_separator unless @row_separator.nil?
|
|
43
|
+
opts[:col_sep] = @col_separator unless @col_separator.nil?
|
|
44
|
+
opts[:headers] = @headers unless @headers.nil?
|
|
45
|
+
opts
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @param [IO] io
|
|
49
|
+
# @yield [record] Gives one line to the block
|
|
50
|
+
# @yieldparam record [Record] a record
|
|
51
|
+
def run(io)
|
|
52
|
+
lineno = 1
|
|
53
|
+
previous_pos = io.pos
|
|
54
|
+
csv = ::CSV.new(io, _build_csv_opts())
|
|
55
|
+
csv.each do |row|
|
|
56
|
+
begin
|
|
57
|
+
if row.kind_of?(::CSV::Row)
|
|
58
|
+
next if row.header_row?
|
|
59
|
+
row = row.to_hash
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
yield Record.new(row,
|
|
63
|
+
line_number: lineno,
|
|
64
|
+
pos_start: previous_pos,
|
|
65
|
+
pos_end: io.pos)
|
|
66
|
+
|
|
67
|
+
ensure
|
|
68
|
+
previous_pos = io.pos
|
|
69
|
+
lineno += 1
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
nil
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'threatinator/record'
|
|
2
|
+
require 'threatinator/parser'
|
|
3
|
+
|
|
4
|
+
module Threatinator
|
|
5
|
+
module Parsers
|
|
6
|
+
module Getline
|
|
7
|
+
# Parses an IO, yielding each 'line' of data as deliniated by :separator.
|
|
8
|
+
# The text matching :separator will be included.
|
|
9
|
+
class Parser < Threatinator::Parser
|
|
10
|
+
attr_reader :separator
|
|
11
|
+
|
|
12
|
+
# @param [Hash] opts
|
|
13
|
+
# @option opts [String] :separator ("\n") A character that will be used
|
|
14
|
+
# to detect the end of a line.
|
|
15
|
+
def initialize(opts = {})
|
|
16
|
+
@separator = opts.delete(:separator) || "\n"
|
|
17
|
+
unless @separator.length == 1
|
|
18
|
+
raise ArgumentError.new(":separator must be exactly one character long")
|
|
19
|
+
end
|
|
20
|
+
super(opts)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def ==(other)
|
|
24
|
+
@separator == other.separator &&
|
|
25
|
+
super(other)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @param [IO] io The IO to be parsed
|
|
29
|
+
# @yield [line] Gives one line to the block
|
|
30
|
+
# @yieldparam line [String] a line from the IO stream.
|
|
31
|
+
def run(io)
|
|
32
|
+
return enum_for(:each) unless block_given?
|
|
33
|
+
lineno = 1
|
|
34
|
+
while str = io.gets(@separator)
|
|
35
|
+
return if str.nil?
|
|
36
|
+
pos_start = io.pos - str.length
|
|
37
|
+
yield Record.new(str, line_number: lineno, pos_start: pos_start, pos_end: io.pos)
|
|
38
|
+
lineno += 1
|
|
39
|
+
end
|
|
40
|
+
nil
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require 'threatinator/parsers/json'
|
|
2
|
+
require 'threatinator/exceptions'
|
|
3
|
+
require 'oj'
|
|
4
|
+
|
|
5
|
+
module Threatinator::Parsers::JSON::Adapters
|
|
6
|
+
class Oj < ::Oj::ScHandler
|
|
7
|
+
def initialize
|
|
8
|
+
@root = nil
|
|
9
|
+
@depth = 0
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def run(io, &callback)
|
|
13
|
+
@callback = callback
|
|
14
|
+
begin
|
|
15
|
+
::Oj.sc_parse(self, io)
|
|
16
|
+
rescue ::Oj::ParseError => e
|
|
17
|
+
raise Threatinator::Exceptions::ParseError.new(e)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def do_callback(data, key = nil)
|
|
22
|
+
@callback.call(data, key: key)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def hash_start
|
|
26
|
+
ret = {}
|
|
27
|
+
@depth += 1
|
|
28
|
+
@root = ret if @root.nil?
|
|
29
|
+
ret
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def hash_set(h,k,v)
|
|
33
|
+
if @depth == 1
|
|
34
|
+
do_callback(v, k)
|
|
35
|
+
else
|
|
36
|
+
h[k] = v
|
|
37
|
+
end
|
|
38
|
+
v
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def hash_end
|
|
42
|
+
@depth -= 1
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def array_start
|
|
46
|
+
ret = []
|
|
47
|
+
@depth += 1
|
|
48
|
+
@root = ret if @root.nil?
|
|
49
|
+
ret
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def array_append(a,v)
|
|
53
|
+
if @depth == 1
|
|
54
|
+
do_callback(v)
|
|
55
|
+
else
|
|
56
|
+
a << v
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def array_end
|
|
61
|
+
@depth -= 1
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'threatinator/parser'
|
|
2
|
+
require 'threatinator/parsers/json/record'
|
|
3
|
+
|
|
4
|
+
module Threatinator
|
|
5
|
+
module Parsers
|
|
6
|
+
module JSON
|
|
7
|
+
class Parser < Threatinator::Parser
|
|
8
|
+
def initialize(opts = {})
|
|
9
|
+
@adapter_class = self.class.adapter_class
|
|
10
|
+
super(opts)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Detects the platform, loads the JSON adapter, and returns the
|
|
14
|
+
# adapter's class.
|
|
15
|
+
def self.adapter_class
|
|
16
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
|
17
|
+
#:nocov:
|
|
18
|
+
raise "JSON parsing not supported for JRuby"
|
|
19
|
+
#:nocov:
|
|
20
|
+
else
|
|
21
|
+
require 'threatinator/parsers/json/adapters/oj'
|
|
22
|
+
return Threatinator::Parsers::JSON::Adapters::Oj
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ==(other)
|
|
27
|
+
super(other)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @param [IO] io
|
|
31
|
+
# @yield [record] Gives one line to the block
|
|
32
|
+
# @yieldparam record [Threatinator::Parsers::JSON::Record] a record
|
|
33
|
+
def run(io)
|
|
34
|
+
adapter = @adapter_class.new
|
|
35
|
+
callback = lambda do |object, opts = {}|
|
|
36
|
+
yield Threatinator::Parsers::JSON::Record.new(object, opts)
|
|
37
|
+
end
|
|
38
|
+
adapter.run(io, &callback)
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'threatinator/record'
|
|
2
|
+
|
|
3
|
+
module Threatinator
|
|
4
|
+
module Parsers
|
|
5
|
+
module JSON
|
|
6
|
+
class Record < Threatinator::Record
|
|
7
|
+
attr_reader :key
|
|
8
|
+
def initialize(object, opts = {})
|
|
9
|
+
@key = opts.delete(:key)
|
|
10
|
+
super(object, opts)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def ==(other)
|
|
14
|
+
@key == other.key &&
|
|
15
|
+
super(other)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
module Threatinator
|
|
2
|
+
module Parsers
|
|
3
|
+
module XML
|
|
4
|
+
class Node
|
|
5
|
+
attr_accessor :text
|
|
6
|
+
attr_reader :name
|
|
7
|
+
attr_reader :attrs
|
|
8
|
+
attr_reader :children
|
|
9
|
+
|
|
10
|
+
# @param [String, Symbol] name
|
|
11
|
+
# @param [Hash] opts
|
|
12
|
+
# @option opts [String] :text The text
|
|
13
|
+
# @option opts [Hash] :attrs The attributes
|
|
14
|
+
# @option opts [Array<Threatinator::Parsers::XML::Node>] :children An array
|
|
15
|
+
# of child child nodes that belong to this node.
|
|
16
|
+
def initialize(name, opts = {})
|
|
17
|
+
unless name.kind_of?(::Symbol) or name.kind_of?(::String)
|
|
18
|
+
raise TypeError.new("name must be a String or a Symbol")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
@name = name.to_sym
|
|
22
|
+
@text = opts.delete(:text) || ""
|
|
23
|
+
unless @text.kind_of?(::String)
|
|
24
|
+
raise TypeError.new(":text must be a String")
|
|
25
|
+
end
|
|
26
|
+
@attrs = opts.delete(:attrs) || {}
|
|
27
|
+
unless @attrs.kind_of?(::Hash)
|
|
28
|
+
raise TypeError.new(":text must be a Hash")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
@children = {}
|
|
32
|
+
if _children = opts.delete(:children)
|
|
33
|
+
_children.each do |child|
|
|
34
|
+
add_child(child)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def ==(other)
|
|
40
|
+
@name == other.name &&
|
|
41
|
+
@attrs == other.attrs &&
|
|
42
|
+
@text == other.text &&
|
|
43
|
+
@children == other.children
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def eql?(other)
|
|
47
|
+
other.kind_of?(self.class) &&
|
|
48
|
+
self == other
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @return [Integer] the number of children
|
|
52
|
+
def num_children
|
|
53
|
+
@children.values.inject(0) {|total, child_set| total + child_set.count}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @param [String, Symbol] name The name of the child element
|
|
57
|
+
# @return [Array<Node>] An array containing all the child nodes for the given
|
|
58
|
+
# name. The array will be empty if there are no children by the given name.
|
|
59
|
+
def [](name)
|
|
60
|
+
@children[name.to_sym] || []
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @return [Array<Symbol>] an array containing all the names of child elements
|
|
64
|
+
def child_names
|
|
65
|
+
@children.keys
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
def add_child(child)
|
|
70
|
+
name = child.name
|
|
71
|
+
unless child_set = @children[name]
|
|
72
|
+
child_set = @children[name] = []
|
|
73
|
+
end
|
|
74
|
+
child_set << child
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|