threatinator 0.1.1
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 +23 -0
- data/CONTRIBUTING.md +119 -0
- data/Gemfile +28 -0
- data/LICENSE +165 -0
- data/README.md +45 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/bin/threatinator +5 -0
- data/lib/threatinator.rb +3 -0
- data/lib/threatinator/action.rb +14 -0
- data/lib/threatinator/actions/list.rb +2 -0
- data/lib/threatinator/actions/list/action.rb +53 -0
- data/lib/threatinator/actions/list/config.rb +10 -0
- data/lib/threatinator/actions/run.rb +2 -0
- data/lib/threatinator/actions/run/action.rb +45 -0
- data/lib/threatinator/actions/run/config.rb +32 -0
- data/lib/threatinator/actions/run/coverage_observer.rb +54 -0
- data/lib/threatinator/actions/run/output_config.rb +59 -0
- data/lib/threatinator/cli.rb +13 -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 +113 -0
- data/lib/threatinator/cli/run_action_builder.rb +41 -0
- data/lib/threatinator/config.rb +6 -0
- data/lib/threatinator/config/base.rb +35 -0
- data/lib/threatinator/config/feed_search.rb +25 -0
- data/lib/threatinator/decoder.rb +24 -0
- data/lib/threatinator/decoders/gzip.rb +30 -0
- data/lib/threatinator/event.rb +27 -0
- data/lib/threatinator/event_builder.rb +41 -0
- data/lib/threatinator/exceptions.rb +61 -0
- data/lib/threatinator/feed.rb +82 -0
- data/lib/threatinator/feed_builder.rb +156 -0
- data/lib/threatinator/feed_registry.rb +47 -0
- data/lib/threatinator/feed_runner.rb +118 -0
- data/lib/threatinator/fetcher.rb +22 -0
- data/lib/threatinator/fetchers/http.rb +46 -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/output.rb +50 -0
- data/lib/threatinator/parser.rb +23 -0
- data/lib/threatinator/parsers/csv.rb +7 -0
- data/lib/threatinator/parsers/csv/parser.rb +77 -0
- data/lib/threatinator/parsers/getline.rb +8 -0
- data/lib/threatinator/parsers/getline/parser.rb +45 -0
- data/lib/threatinator/parsers/json.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/xml.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/plugin_loader.rb +115 -0
- data/lib/threatinator/plugins/output/csv.rb +47 -0
- data/lib/threatinator/plugins/output/null.rb +17 -0
- data/lib/threatinator/plugins/output/rubydebug.rb +16 -0
- data/lib/threatinator/property_definer.rb +101 -0
- data/lib/threatinator/record.rb +22 -0
- data/lib/threatinator/registry.rb +53 -0
- data/lib/threatinator/util.rb +15 -0
- data/spec/feeds/ET_compromised-ip_reputation_spec.rb +50 -0
- data/spec/feeds/alienvault-ip_reputation_spec.rb +50 -0
- data/spec/feeds/arbor_fastflux-domain_reputation_spec.rb +50 -0
- data/spec/feeds/arbor_ssh-ip_reputation_spec.rb +50 -0
- data/spec/feeds/autoshun_shunlist_spec.rb +42 -0
- data/spec/feeds/blocklist_de_apache-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_bots-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_ftp-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_imap-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_pop3-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_proftpd-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_sip-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_ssh-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_strongips-ip_reputation_spec.rb +50 -0
- data/spec/feeds/ciarmy-ip_reputation_spec.rb +50 -0
- data/spec/feeds/cruzit-ip_reputation_spec.rb +50 -0
- data/spec/feeds/dan_me_uk_torlist-ip_reputation_spec.rb +50 -0
- data/spec/feeds/data/ET_compromised-ip_reputation.txt +11 -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/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/ciarmy-ip-reputation.txt +11 -0
- data/spec/feeds/data/cruzit-ip-reputation.txt +14 -0
- data/spec/feeds/data/dan_me_uk_torlist-ip-reputation.txt +11 -0
- data/spec/feeds/data/dshield_topattackers.xml +4 -0
- data/spec/feeds/data/feodo_domainlist.txt +18 -0
- data/spec/feeds/data/feodo_iplist.txt +20 -0
- data/spec/feeds/data/infiltrated_iplist.txt +16 -0
- data/spec/feeds/data/malc0de_domainlist.txt +18 -0
- data/spec/feeds/data/malc0de_iplist.txt +14 -0
- data/spec/feeds/data/mirc_domainlist.txt +31 -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/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/spyeye_domainlist.txt +16 -0
- data/spec/feeds/data/spyeye_iplist.txt +19 -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/yourcmc_ssh-ip_reputation.txt +27 -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 +43 -0
- data/spec/feeds/feodo-domain_reputation_spec.rb +50 -0
- data/spec/feeds/feodo-ip_reputation_spec.rb +50 -0
- data/spec/feeds/infiltrated-ip_reputation_spec.rb +50 -0
- data/spec/feeds/malc0de-domain_reputation_spec.rb +50 -0
- data/spec/feeds/malc0de-ip_reputation_spec.rb +50 -0
- data/spec/feeds/mirc-domain_reputation_spec.rb +50 -0
- data/spec/feeds/nothink_irc-ip_reputation_spec.rb +50 -0
- data/spec/feeds/nothink_ssh-ip_reputation_spec.rb +50 -0
- data/spec/feeds/openbl-ip_reputation_spec.rb +50 -0
- data/spec/feeds/palevo-domain_reputation_spec.rb +50 -0
- data/spec/feeds/palevo-ip_reputation_spec.rb +50 -0
- data/spec/feeds/phishtank_spec.rb +45 -0
- data/spec/feeds/spyeye-domain_reputation_spec.rb +50 -0
- data/spec/feeds/spyeye-ip_reputation_spec.rb +50 -0
- data/spec/feeds/t-arend-de_ssh-ip_reputation_spec.rb +50 -0
- data/spec/feeds/the_haleys_ssh-ip_reputation_spec.rb +50 -0
- data/spec/feeds/yourcmc_ssh-ip_reputation_spec.rb +50 -0
- data/spec/feeds/zeus-domain_reputation_spec.rb +50 -0
- data/spec/feeds/zeus-ip_reputation_spec.rb +50 -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 +52 -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 +27 -0
- data/spec/support/factories/feed.rb +32 -0
- data/spec/support/factories/feed_builder.rb +65 -0
- data/spec/support/factories/feed_registry.rb +8 -0
- data/spec/support/factories/output.rb +11 -0
- data/spec/support/factories/record.rb +17 -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/feeds.rb +218 -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/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 +93 -0
- data/spec/threatinator/actions/run/action_spec.rb +89 -0
- data/spec/threatinator/actions/run/config_spec.rb +39 -0
- data/spec/threatinator/actions/run/coverage_observer_spec.rb +116 -0
- data/spec/threatinator/actions/run/output_config_spec.rb +89 -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 +33 -0
- data/spec/threatinator/event_spec.rb +30 -0
- data/spec/threatinator/feed_builder_spec.rb +636 -0
- data/spec/threatinator/feed_registry_spec.rb +198 -0
- data/spec/threatinator/feed_runner_spec.rb +155 -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/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 +46 -0
- data/spec/threatinator/plugins/output/null_spec.rb +17 -0
- data/spec/threatinator/plugins/output/rubydebug_spec.rb +37 -0
- data/spec/threatinator/property_definer_spec.rb +155 -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 +376 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'threatinator/parsers/xml/path'
|
|
2
|
+
|
|
3
|
+
module Threatinator
|
|
4
|
+
module Parsers
|
|
5
|
+
module XML
|
|
6
|
+
# Implements path matching behavior for use with the XML parser. Aims to support
|
|
7
|
+
# a small subset of XPath behaviors, specifically for matching elements.
|
|
8
|
+
class Pattern
|
|
9
|
+
# @param [String] pathspec A specification of a path match.
|
|
10
|
+
def initialize(pathspec)
|
|
11
|
+
parts = pathspec.split('/')
|
|
12
|
+
leader_count = 0
|
|
13
|
+
while parts[0] == ''
|
|
14
|
+
leader_count += 1
|
|
15
|
+
parts.shift
|
|
16
|
+
end
|
|
17
|
+
@path = Threatinator::Parsers::XML::Path.new(parts)
|
|
18
|
+
@anchored = true
|
|
19
|
+
|
|
20
|
+
if leader_count == 1
|
|
21
|
+
@anchored = true
|
|
22
|
+
elsif leader_count == 2
|
|
23
|
+
@anchored = false
|
|
24
|
+
else
|
|
25
|
+
raise ArgumentError.new('pathspec must begin with "/" or "//"')
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def max_depth
|
|
30
|
+
@anchored == true ? @path.length : Float::INFINITY
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @param [Threatinator::Parsers::XML::Path] path
|
|
34
|
+
# @return [Boolean] true if the pattern matches, false otherwise.
|
|
35
|
+
def match?(path)
|
|
36
|
+
if @anchored == true
|
|
37
|
+
@path == path
|
|
38
|
+
else
|
|
39
|
+
path.end_with?(@path)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def _internal_data
|
|
44
|
+
[@path, @anchored]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def ==(other)
|
|
48
|
+
_internal_data == other._internal_data
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require 'threatinator/parsers/xml/node_builder'
|
|
2
|
+
require 'threatinator/parsers/xml/path'
|
|
3
|
+
require 'nokogiri'
|
|
4
|
+
|
|
5
|
+
module Threatinator
|
|
6
|
+
module Parsers
|
|
7
|
+
module XML
|
|
8
|
+
class SAXDocument < Nokogiri::XML::SAX::Document
|
|
9
|
+
def initialize(pattern, cb)
|
|
10
|
+
@pattern = pattern
|
|
11
|
+
@max_depth = @pattern.max_depth
|
|
12
|
+
@cb = cb
|
|
13
|
+
@element_stack = Threatinator::Parsers::XML::Path.new
|
|
14
|
+
@parsing_stack = []
|
|
15
|
+
@current_node = nil
|
|
16
|
+
super()
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def start_parsing(name, attributes)
|
|
20
|
+
@current_node = Threatinator::Parsers::XML::NodeBuilder.new(name, attributes)
|
|
21
|
+
@parsing_stack.push(@current_node)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def characters(str)
|
|
25
|
+
return if @current_node.nil?
|
|
26
|
+
@current_node.append_text(str)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
alias_method :cdata_block, :characters
|
|
30
|
+
|
|
31
|
+
def start_element_namespace(name, attrs = [], prefix = nil, uri = nil, ns = [])
|
|
32
|
+
@element_stack.push(name)
|
|
33
|
+
|
|
34
|
+
if @parsing_stack.empty?
|
|
35
|
+
if @element_stack.length > @max_depth
|
|
36
|
+
return
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if @pattern.match?(@element_stack)
|
|
40
|
+
start_parsing(name, attrs)
|
|
41
|
+
end
|
|
42
|
+
else
|
|
43
|
+
start_parsing(name, attrs)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def end_element_namespace(name, prefix = nil, uri = nil)
|
|
48
|
+
name_sym = name.to_sym
|
|
49
|
+
@element_stack.pop
|
|
50
|
+
return if @parsing_stack.empty?
|
|
51
|
+
@parsing_stack.pop
|
|
52
|
+
|
|
53
|
+
if parent = @parsing_stack.last
|
|
54
|
+
parent.add_child(@current_node.build)
|
|
55
|
+
@current_node = parent
|
|
56
|
+
else
|
|
57
|
+
@cb.call(@current_node.build)
|
|
58
|
+
@current_node = nil
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'threatinator/util'
|
|
3
|
+
require 'threatinator/registry'
|
|
4
|
+
|
|
5
|
+
module Threatinator
|
|
6
|
+
class PluginLoader
|
|
7
|
+
def initialize()
|
|
8
|
+
@plugin_types_registry = Threatinator::Registry.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Loads all plugins
|
|
12
|
+
# @return [Threatinator::PluginLoader] self
|
|
13
|
+
def load_all_plugins()
|
|
14
|
+
load_plugins(:*)
|
|
15
|
+
return self
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Loads all plugins of the specified type
|
|
19
|
+
# @param [#to_sym] type
|
|
20
|
+
# @return [Threatinator::PluginLoader] self
|
|
21
|
+
def load_plugins(type)
|
|
22
|
+
load_files(find_plugin_files(type.to_sym))
|
|
23
|
+
return self
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Retrieves a loaded plugin by type and name.
|
|
27
|
+
# @param [#to_sym] type
|
|
28
|
+
# @param [#to_sym] name
|
|
29
|
+
# @return [Object] plugin
|
|
30
|
+
def get(type, name)
|
|
31
|
+
type_registry = @plugin_types_registry.get(type.to_sym)
|
|
32
|
+
return nil if type_registry.nil?
|
|
33
|
+
return type_registry.get(name.to_sym)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Enumerates through all plugins, optionally filtered by type.
|
|
37
|
+
# @yield [type, name, plugin]
|
|
38
|
+
# @yieldparam [Symbol] type
|
|
39
|
+
# @yieldparam [Symbol] name
|
|
40
|
+
# @yieldparam [Object] plugin
|
|
41
|
+
def each(type = nil)
|
|
42
|
+
return enum_for(:each, type) unless block_given?
|
|
43
|
+
@plugin_types_registry.each do |t, type_registry|
|
|
44
|
+
unless type.nil?
|
|
45
|
+
next unless type.to_sym == t
|
|
46
|
+
end
|
|
47
|
+
type_registry.each do |name, plugin|
|
|
48
|
+
yield(t, name, plugin)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns an array of all the types of plugins that are loaded.
|
|
54
|
+
# @return [Array<Symbol>]
|
|
55
|
+
def types
|
|
56
|
+
@plugin_types_registry.keys
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Registers a plugin with the provided type and name.
|
|
60
|
+
# @param [#to_sym] type
|
|
61
|
+
# @param [#to_sym] name
|
|
62
|
+
# @param [Object] plugin
|
|
63
|
+
# @raise [Threatinator::Exceptions::AlreadyRegisteredError
|
|
64
|
+
def register_plugin(type, name, plugin)
|
|
65
|
+
type = type.to_sym
|
|
66
|
+
unless type_registry = @plugin_types_registry.get(type)
|
|
67
|
+
type_registry = @plugin_types_registry.register(type, Threatinator::Registry.new)
|
|
68
|
+
end
|
|
69
|
+
type_registry.register(name.to_sym, plugin)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def find_plugin_files(type)
|
|
75
|
+
Gem.find_files("threatinator/plugins/#{type}/*.rb")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def register_plugin_by_name(type, name)
|
|
79
|
+
plugin_name = "Threatinator::Plugins::#{Threatinator::Util.underscore2cc(type)}::#{Threatinator::Util.underscore2cc(name)}"
|
|
80
|
+
begin
|
|
81
|
+
type_obj = Threatinator::Plugins.const_get(Threatinator::Util.underscore2cc(type))
|
|
82
|
+
plugin = type_obj.const_get(Threatinator::Util.underscore2cc(name))
|
|
83
|
+
register_plugin(type, name, plugin)
|
|
84
|
+
rescue ::NameError => e
|
|
85
|
+
raise Threatinator::Exceptions::PluginLoadError.new("Failed to load plugin '#{plugin_name}'", e)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def load_files(file_names)
|
|
90
|
+
file_names.each do |file_name|
|
|
91
|
+
path, type, name = split_file_name(file_name)
|
|
92
|
+
next if path.nil?
|
|
93
|
+
# Don't try to load unit tests as plugins :)
|
|
94
|
+
next if name.end_with?("_spec")
|
|
95
|
+
begin
|
|
96
|
+
require path
|
|
97
|
+
rescue ::LoadError
|
|
98
|
+
# TODO: Handle plugins inside of gems a bit better. We should try
|
|
99
|
+
# using only the latest version of a given Gem.
|
|
100
|
+
next
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
register_plugin_by_name(type, name)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @return [Array, nil] an array containing the path, type, and name of the
|
|
108
|
+
# plugin
|
|
109
|
+
def split_file_name(file_name)
|
|
110
|
+
m = file_name.match(/(?<=(\A|\/))(?<path>threatinator\/plugins\/(?<type>[^\/]+)\/(?<name>[^\/\.]+))\.rb$/)
|
|
111
|
+
return nil if m.nil?
|
|
112
|
+
[m[:path], m[:type], m[:name]]
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'threatinator/output'
|
|
2
|
+
require 'csv'
|
|
3
|
+
module Threatinator
|
|
4
|
+
module Plugins
|
|
5
|
+
module Output
|
|
6
|
+
class Csv < Threatinator::FileBasedOutput
|
|
7
|
+
class Config < superclass::Config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(config)
|
|
11
|
+
super(config)
|
|
12
|
+
@csv = ::CSV.new(self.output_io,
|
|
13
|
+
:write_headers => true,
|
|
14
|
+
:headers => [
|
|
15
|
+
:provider,
|
|
16
|
+
:feed_name,
|
|
17
|
+
:type,
|
|
18
|
+
:ipv4_1,
|
|
19
|
+
:ipv4_2,
|
|
20
|
+
:ipv4_3,
|
|
21
|
+
:ipv4_4,
|
|
22
|
+
:fqdn_1,
|
|
23
|
+
:fqdn_2,
|
|
24
|
+
:fqdn_3,
|
|
25
|
+
:fqdn_4
|
|
26
|
+
])
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def handle_event(event)
|
|
30
|
+
@csv.add_row([
|
|
31
|
+
event.feed_provider,
|
|
32
|
+
event.feed_name,
|
|
33
|
+
event.type,
|
|
34
|
+
event.ipv4s[0],
|
|
35
|
+
event.ipv4s[1],
|
|
36
|
+
event.ipv4s[2],
|
|
37
|
+
event.ipv4s[3],
|
|
38
|
+
event.fqdns[0],
|
|
39
|
+
event.fqdns[1],
|
|
40
|
+
event.fqdns[2],
|
|
41
|
+
event.fqdns[3]
|
|
42
|
+
])
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'threatinator/output'
|
|
2
|
+
module Threatinator
|
|
3
|
+
module Plugins
|
|
4
|
+
module Output
|
|
5
|
+
class Null < Threatinator::Output
|
|
6
|
+
class Config < superclass::Config
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def handle_event(event)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def finish
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'threatinator/output'
|
|
2
|
+
require 'pp'
|
|
3
|
+
module Threatinator
|
|
4
|
+
module Plugins
|
|
5
|
+
module Output
|
|
6
|
+
class Rubydebug < Threatinator::FileBasedOutput
|
|
7
|
+
class Config < superclass::Config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def handle_event(event)
|
|
11
|
+
::PP.pp(event, self.output_io); nil
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
|
|
2
|
+
module Threatinator
|
|
3
|
+
# A helper that lets us easily define properties within an object and
|
|
4
|
+
# validate them.
|
|
5
|
+
module PropertyDefiner
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.extend(Threatinator::PropertyDefiner::ClassMethods)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def _properties
|
|
11
|
+
@_properties ||= Hash.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def _prop(name)
|
|
15
|
+
self.class._properties[name]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def _get(name)
|
|
19
|
+
if _properties.has_key?(name)
|
|
20
|
+
return _properties[name]
|
|
21
|
+
end
|
|
22
|
+
prop = _prop(name)
|
|
23
|
+
return nil if prop.nil?
|
|
24
|
+
val = prop.default_value
|
|
25
|
+
_set(name, val)
|
|
26
|
+
val
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def _set(name, val)
|
|
30
|
+
prop = _prop(name)
|
|
31
|
+
return if prop.nil?
|
|
32
|
+
prop.validate!(self, val)
|
|
33
|
+
_properties[name] = val
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def _parse_properties(opts = {})
|
|
37
|
+
opts.each { |k, v| _set(k, v) }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class Property
|
|
41
|
+
attr_reader :name, :opts
|
|
42
|
+
def initialize(name, opts = {})
|
|
43
|
+
@name = name.to_sym
|
|
44
|
+
@type = opts.delete(:type) || Object
|
|
45
|
+
if @validator = opts.delete(:validate)
|
|
46
|
+
unless @validator.kind_of?(Proc)
|
|
47
|
+
raise ArgumentError.new(":validate must be a proc")
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
@default_value = opts.delete(:default)
|
|
51
|
+
@opts = opts
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def default_value
|
|
55
|
+
case @default_value
|
|
56
|
+
when Proc
|
|
57
|
+
return @default_value.call()
|
|
58
|
+
when nil
|
|
59
|
+
return nil
|
|
60
|
+
else
|
|
61
|
+
return @default_value
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def valid?(obj, val)
|
|
66
|
+
return false unless val.kind_of?(@type)
|
|
67
|
+
unless @validator.nil?
|
|
68
|
+
return false unless @validator.call(obj, val)
|
|
69
|
+
end
|
|
70
|
+
true
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def validate!(obj, val)
|
|
74
|
+
unless valid?(obj, val)
|
|
75
|
+
raise Threatinator::Exceptions::InvalidAttributeError.new(self.name, val)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
module ClassMethods
|
|
81
|
+
def _properties
|
|
82
|
+
@@properties ||= {}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def _define_property(prop)
|
|
86
|
+
name = prop.name
|
|
87
|
+
_properties[name] = prop
|
|
88
|
+
define_method("#{prop.name}=".to_sym) do |newval|
|
|
89
|
+
_set(name, newval)
|
|
90
|
+
end
|
|
91
|
+
define_method(name) do
|
|
92
|
+
_get(name)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def property(name, opts = {})
|
|
97
|
+
_define_property(Property.new(name, opts))
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Threatinator
|
|
2
|
+
class Record
|
|
3
|
+
attr_reader :data, :line_number, :pos_start, :pos_end
|
|
4
|
+
def initialize(data, opts = {})
|
|
5
|
+
@data = data
|
|
6
|
+
@line_number = opts[:line_number]
|
|
7
|
+
@pos_start = opts[:pos_start]
|
|
8
|
+
@pos_end = opts[:pos_end]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def ==(other)
|
|
12
|
+
@data == other.data &&
|
|
13
|
+
@line_number == other.line_number &&
|
|
14
|
+
@pos_start == other.pos_start &&
|
|
15
|
+
@pos_end == other.pos_end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def eql?(other)
|
|
19
|
+
other.kind_of?(self.class) && self == other
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|