snoopit 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +39 -0
  4. data/.idea/.name +1 -0
  5. data/.idea/.rakeTasks +7 -0
  6. data/.idea/dictionaries/rbirch.xml +9 -0
  7. data/.idea/encodings.xml +5 -0
  8. data/.idea/misc.xml +5 -0
  9. data/.idea/modules.xml +9 -0
  10. data/.idea/scopes/scope_settings.xml +5 -0
  11. data/.idea/snoopit.iml +233 -0
  12. data/.idea/vcs.xml +7 -0
  13. data/.rspec +2 -0
  14. data/.travis.yml +7 -0
  15. data/Gemfile +15 -0
  16. data/LICENSE.txt +22 -0
  17. data/README.md +411 -0
  18. data/Rakefile +1 -0
  19. data/bin/snoopit +173 -0
  20. data/lib/snoopit.rb +22 -0
  21. data/lib/snoopit/detected.rb +50 -0
  22. data/lib/snoopit/file_info.rb +104 -0
  23. data/lib/snoopit/file_tracker.rb +83 -0
  24. data/lib/snoopit/logger.rb +30 -0
  25. data/lib/snoopit/notification_manager.rb +123 -0
  26. data/lib/snoopit/notifier.rb +25 -0
  27. data/lib/snoopit/notifiers/email.rb +61 -0
  28. data/lib/snoopit/notifiers/http.rb +85 -0
  29. data/lib/snoopit/notifiers/https.rb +21 -0
  30. data/lib/snoopit/notifiers/stomp.rb +59 -0
  31. data/lib/snoopit/register.rb +69 -0
  32. data/lib/snoopit/sniffer.rb +51 -0
  33. data/lib/snoopit/snooper.rb +149 -0
  34. data/lib/snoopit/snoopy.rb +67 -0
  35. data/lib/snoopit/version.rb +3 -0
  36. data/snoopit.gemspec +27 -0
  37. data/spec/bin/snoopit_spec.rb +258 -0
  38. data/spec/file_info_spec.rb +131 -0
  39. data/spec/file_tracker_spec.rb +172 -0
  40. data/spec/notification_manager_spec.rb +103 -0
  41. data/spec/notifiers/email_spec.rb +36 -0
  42. data/spec/notifiers/http_spec.rb +37 -0
  43. data/spec/notifiers/https_spec.rb +38 -0
  44. data/spec/notifiers/stomp_spec.rb +34 -0
  45. data/spec/register_spec.rb +105 -0
  46. data/spec/snooper_spec.rb +538 -0
  47. data/spec/spec_helper.rb +24 -0
  48. data/spec/support/log/snoop_log.test +593 -0
  49. data/spec/support/log/snoop_log_2.test +593 -0
  50. data/spec/support/multiple_snoopies.json +82 -0
  51. data/spec/support/regexp_tester.rb +10 -0
  52. data/spec/support/snoopies.json +93 -0
  53. data/spec/support/snoopies_notifiers.json +66 -0
  54. data/spec/support/test_notifier.rb +18 -0
  55. data/spec/support/test_notifier_load.rb +18 -0
  56. data/support/snoopies.json +110 -0
  57. metadata +190 -0
@@ -0,0 +1,123 @@
1
+ module Snoopit
2
+
3
+ class NotificationManager
4
+
5
+ attr :active, :config
6
+
7
+ def initialize(config=nil)
8
+ @active = {}
9
+ @config = config
10
+ load_default_notifiers unless @config.nil?
11
+ end
12
+
13
+ def load_notifier_config(config)
14
+ @config = config
15
+ load_default_notifiers
16
+ load = @config['load']
17
+ load_files(load) unless load.nil?
18
+ end
19
+
20
+ def register(notifier)
21
+ raise NameError.new "Notifier missing valid name: #{notifier.inspect}" if notifier.name.nil?
22
+ Snoopit.logger.debug "Registering notifier #{notifier.name}"
23
+ @active[notifier.name] = notifier
24
+ end
25
+
26
+ def unregister(notifier)
27
+ self.unregister_by_name notifier.name
28
+ end
29
+
30
+ def unregister_by_name(notifier_name)
31
+ @active.delete notifier_name
32
+ end
33
+
34
+ def get_notifier(name)
35
+ @active[name]
36
+ end
37
+
38
+ def notify(snoopies)
39
+ snoopies.each do |snoopy|
40
+ snoopy.sniffers.each do |sniffer|
41
+ sniffer_notify(sniffer)
42
+ end
43
+ end
44
+ end
45
+
46
+ def sniffer_notify(sniffer)
47
+ messages = get_sniffed_messages sniffer
48
+ sniffer.notifiers.each do |key, value|
49
+ n = @active[key]
50
+ next if n.nil?
51
+ messages.each do |message|
52
+ n.notify(message, value)
53
+ end
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def load_default_notifiers
60
+ path = File.expand_path('../notifiers', __FILE__)
61
+ Dir.entries(path).each do |file|
62
+ next if File.directory? file
63
+ file_require "#{path}/#{file}"
64
+ end
65
+ create_default_notifiers
66
+ end
67
+
68
+ def create_default_notifiers
69
+ Snoopit::Notifiers.constants.select do |c|
70
+ if Class === Snoopit::Notifiers.const_get(c)
71
+ config = @config[c.to_s.downcase]
72
+ unless config.nil?
73
+ o = Snoopit::Notifiers.const_get(c).new config
74
+ @active[o.name] = o
75
+ else
76
+ Snoopit.logger.debug "Notifier #{c.to_s.downcase} not loaded due to no configuration specified"
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ def file_require(file)
83
+ Snoopit.logger.debug "Requiring notifier file: #{file}"
84
+ require file
85
+ end
86
+
87
+ def load_files(load)
88
+ load.keys.each do |key|
89
+ entry = load[key]
90
+ next if entry['file'].nil?
91
+ next if entry['class'].nil?
92
+ file_require entry['file']
93
+ create_notifier entry['class'], entry['config']
94
+ end
95
+ end
96
+
97
+ def create_notifier(klass, notifier_config=nil)
98
+ o = Object.const_get(klass).new notifier_config
99
+ @active[o.name] = o
100
+ end
101
+
102
+ def get_sniffed_messages(sniffer)
103
+ messages = []
104
+ sniffer.sniffed.each do |sniffed|
105
+ messages << build_message(sniffed)
106
+ end
107
+ messages
108
+ end
109
+
110
+ def build_message(sniffed)
111
+ {
112
+ comment: sniffed.comment,
113
+ file: sniffed.file,
114
+ before: sniffed.before.register.reverse,
115
+ match: sniffed.match,
116
+ match_line_no: sniffed.line_no,
117
+ after: sniffed.after.register.reverse
118
+ }
119
+ end
120
+
121
+ end
122
+
123
+ end
@@ -0,0 +1,25 @@
1
+ module Snoopit
2
+
3
+ # @abstract Subclass
4
+ # Override {#notify} method
5
+ class Notifier
6
+
7
+ attr_accessor :name, :configuration, :klass
8
+
9
+ # The name is used by the Snooper to identify type of notifier to create
10
+ # @param name [String] name of notifier if the name is nil the class name is used
11
+ # The empty constructor is used to initialize the class when loaded dynamically
12
+ # After loaded dynamically the method set_config is called to set the configuration
13
+ def initialize(config=nil, name=nil, klass=nil)
14
+ @name = name.nil? ? self.class.name : name
15
+ @klass = klass.nil? ? self.class.name : klass
16
+ @config = config
17
+ end
18
+
19
+ def notify(found, notify_params)
20
+ raise NotImplementedError.new 'Notifier#notify'
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,61 @@
1
+ require 'net/smtp'
2
+ require 'date'
3
+
4
+ module Snoopit
5
+ module Notifiers
6
+
7
+ class Email < Snoopit::Notifier
8
+
9
+ attr :smtp_server, :port, :tls
10
+ # The name 'email' is used by the Snooper to identify type of notifier to create
11
+ # The empty constructor is used to initialize the class when loaded dynamically
12
+ # After loaded dynamically the method set_config is called by the base class to set the configuration
13
+ def initialize(config=nil)
14
+ super config, 'email'
15
+ @smtp_server = @config['smtp-server']
16
+ @port = @config['port']
17
+ @tls = @config['tls']
18
+ @user = @config['user']
19
+ @password = @config['password']
20
+ end
21
+
22
+ def notify(found, notifier_params)
23
+ send found, notifier_params
24
+ end
25
+
26
+ def send(msg, notifier_params)
27
+ begin
28
+ auth = notifier_params['authentication'].nil? ? :login : notifier_params['authentication'].to_sym
29
+ from = notifier_params['from'].nil? ? 'snoopit@snooper.notifier.com' : notifier_params['from']
30
+ formatted = build_msg from, notifier_params['to'], msg
31
+ smtp = Net::SMTP.new @smtp_server, @port
32
+ helo = @user.split('@')[1] || 'localhost'
33
+ smtp.enable_starttls_auto
34
+ smtp.start helo, @user, @password, auth do |smtp|
35
+ smtp.send_message(formatted, from, notifier_params['to'])
36
+ end
37
+ rescue => e
38
+ Snoopit.logger.warn e.message
39
+ Snoopit.logger.warn e.backtrace
40
+ end
41
+ end
42
+
43
+ def build_msg(from, to, msg)
44
+ msg = <<-MSG
45
+ From: #{from}
46
+ To: #{to.kind_of?(Array) ? to.join(', ') : to }
47
+ Content-Type: text/plain
48
+ Subject: #{msg[:comment]}
49
+ Date: #{DateTime.now.rfc822}
50
+
51
+ Snooper event on line: #{msg[:match_line_no]} in file: #{msg[:file]}
52
+
53
+ #{msg[:before].join('')}#{msg[:match]}#{msg[:after].join('')}
54
+ MSG
55
+ msg
56
+ end
57
+
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,85 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'uri'
4
+ require 'awesome_print'
5
+
6
+ module Snoopit
7
+ module Notifiers
8
+
9
+ class Http < Snoopit::Notifier
10
+
11
+ # The name 'http' is used by the Snooper to identify type of notifier to create
12
+ # The empty constructor is used to initialize the class when loaded dynamically
13
+ # After loaded dynamically the method set_config is called by the base class to set the configuration
14
+ def initialize(config=nil)
15
+ super config, 'http'
16
+ @api_key = config['api-key']
17
+ end
18
+
19
+ def notify(found, notify_params)
20
+ raise ArgumentError.new 'URL parameter must be set' if notify_params['url'].nil?
21
+ post_it found, notify_params, URI(notify_params['url'])
22
+ end
23
+
24
+ def post_it(found, notify_params, uri)
25
+ conn = get_conn uri
26
+ request = build_request uri, found, notify_params
27
+ post conn, request
28
+ end
29
+
30
+ def post(conn, request)
31
+ response = conn.request(request)
32
+ case response.code
33
+ when 200..299, 300..399
34
+ logger.debug 'Posted notification to: ' + response.uri.to_s
35
+ logger.debug.ap found
36
+ when 400..599
37
+ logger.warn 'Failed to send notification to uri: ' + response.uri.to_s
38
+ logger.warn 'Failed to send notification to uri: ' + response.message
39
+ end
40
+ rescue => e
41
+ Snoopit.logger.warn 'Failed to send notification to uri: ' + response.uri.to_s unless response.nil?
42
+ Snoopit.logger.warn 'Failed to send notification to uri: ' + e.message
43
+ Snoopit.logger.warn 'Failed to send notification to uri: ' + e.backtrace.join("\n")
44
+ ensure
45
+ conn.finish if conn.started?
46
+ end
47
+
48
+ def build_request(uri, found, notify_params)
49
+ request = Net::HTTP::Post.new(uri.path)
50
+ request.basic_auth notify_params['user'], notify_params['password'] unless notify_params['user'].nil?
51
+ request.body = found.to_json
52
+ set_headers request
53
+ request
54
+ end
55
+
56
+ def get_conn(uri)
57
+ case uri.scheme
58
+ when 'http'
59
+ set_http(uri)
60
+ when 'https'
61
+ set_https(uri)
62
+ end
63
+ end
64
+
65
+ def set_http(uri)
66
+ Net::HTTP.new uri.host, uri.port
67
+ end
68
+
69
+ def set_https(uri)
70
+ conn = Net::HTTP.new uri.host, uri.port
71
+ conn.use_ssl = true
72
+ conn.verify_mode = OpenSSL::SSL::VERIFY_PEER
73
+ conn
74
+ end
75
+
76
+ def set_headers(request)
77
+ request['Content-Type'] = 'application/json'
78
+ request['Authorization'] = 'Token token=' + @api_key unless @api_key.nil?
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+ end
@@ -0,0 +1,21 @@
1
+
2
+ module Snoopit
3
+ module Notifiers
4
+
5
+ class Https < Snoopit::Notifier
6
+
7
+ # The name 'https' is used by the Snooper to identify type of notifier to create
8
+ # The empty constructor is used to initialize the class when loaded dynamically
9
+ # After loaded dynamically the method set_config is called by the base class to set the configuration
10
+ def initialize(config=nil)
11
+ super config, 'https'
12
+ @http = Snoopit::Notifiers::Http.new config
13
+ end
14
+
15
+ def notify(found, notify_params)
16
+ @http.notify(found, notify_params)
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,59 @@
1
+ require 'stomp'
2
+ require 'awesome_print'
3
+
4
+ module Snoopit
5
+ module Notifiers
6
+
7
+ class Stomp < Snoopit::Notifier
8
+
9
+ # The name 'stomp' is used by the Snooper to identify type of notifier to create
10
+ # The empty constructor is used to initialize the class when loaded dynamically
11
+ # After loaded dynamically the method set_config is called by the base class to set the configuration
12
+ def initialize(config=nil)
13
+ super config, 'stomp'
14
+ @host = config['host'] || 'localhost'
15
+ @port = config['port'] || 61613
16
+ @login = config['login']
17
+ @passcode = config['passcode']
18
+ @headers = config['headers']
19
+ end
20
+
21
+ def get_connection
22
+ params = { hosts: [ get_connect_params ] }
23
+ set_connect_headers params
24
+ ::Stomp::Connection.new params
25
+ rescue => e
26
+ Snoopit.logger.warn 'Stomp failed to connect: ' + params.to_json
27
+ Snoopit.logger.warn 'Stomp failed to connect: ' + e.message
28
+ Snoopit.logger.warn 'Stomp failed to connect: ' + e.backtrace.join('\n')
29
+ nil
30
+ end
31
+
32
+ def get_connect_params
33
+ params = { host: @host, port: @port }
34
+ params[:login] = @login unless @login.nil?
35
+ params[:passcode] = @passcode unless @passcode.nil?
36
+ params
37
+ end
38
+
39
+ def set_connect_headers(params)
40
+ params[:connect_headers] = @headers unless @headers.nil?
41
+ end
42
+
43
+ def notify(found, notify_params)
44
+ conn = get_connection
45
+ send_message(conn, found, notify_params) unless conn.nil?
46
+ rescue => e
47
+ Snoopit.logger.warn e.message
48
+ Snoopit.logger.warn e.backtrace.join('\n')
49
+ ensure
50
+ conn.disconnect unless conn.nil?
51
+ end
52
+
53
+ def send_message(conn, found, notify_params)
54
+ conn.publish notify_params['queue'], found.to_json, notify_params['headers']
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,69 @@
1
+ module Snoopit
2
+
3
+ # Behaves a bit like a CPU register
4
+ class Register
5
+
6
+ include Enumerable
7
+
8
+ attr :size, :register
9
+
10
+ # index always points to where the next element will be added
11
+ def initialize(size=10, data=nil)
12
+ if data.nil?
13
+ @register = Array.new size
14
+ else
15
+ @register = Array.new size
16
+ cloned = data.clone
17
+ [0...size].each { |i| @register[i] = cloned[i] }
18
+ end
19
+ end
20
+
21
+ # pushes one object to the front of the array and pops one off the end and returns is
22
+ def unshift(object)
23
+ return if @register.size == 0
24
+ @register.unshift object
25
+ @register.pop unless @register.size == 1
26
+ end
27
+
28
+ # pushes one object on to the end of the array and pops one off the front and returns is
29
+ def shift(object)
30
+ return if @register.size == 0
31
+ @register.push object
32
+ @register.slice! 0 unless @register.size == 1
33
+ end
34
+
35
+ alias_method :push_front, :unshift
36
+ alias_method :push_back, :shift
37
+
38
+ def [](index)
39
+ @register[index]
40
+ end
41
+
42
+ def []=(index, value)
43
+ @register[index] = value
44
+ end
45
+
46
+ def size
47
+ @register.size
48
+ end
49
+
50
+ def length
51
+ @register.length
52
+ end
53
+
54
+ def as_json(options=nil)
55
+ @register
56
+ end
57
+
58
+ def to_json(*a)
59
+ as_json.to_json(*a)
60
+ end
61
+
62
+ def each
63
+ @register.each { |r| yield r }
64
+ end
65
+
66
+ end
67
+
68
+
69
+ end