google-safe-browsing-plugin 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.
Files changed (44) hide show
  1. data/LICENSE.txt +20 -0
  2. data/README.md +88 -0
  3. data/lib/faraday/response/safe_browsing_update_parser.rb +119 -0
  4. data/lib/google/safe_browsing_client.rb +211 -0
  5. data/lib/google/safe_browsing_parser.rb +214 -0
  6. data/lib/google/safe_browsing_update_helper.rb +171 -0
  7. data/lib/google/sha_util.rb +22 -0
  8. data/lib/google/url_canonicalizer.rb +36 -0
  9. data/lib/google/url_scramble.rb +54 -0
  10. data/lib/google_safe_browsing_plugin.rb +29 -0
  11. data/lib/rails/generators/google/config/config_generator.rb +16 -0
  12. data/lib/rails/generators/google/config/templates/google_safe_browsing.yml +16 -0
  13. data/lib/rails/generators/google/helper/helper_generator.rb +16 -0
  14. data/lib/rails/generators/google/helper/templates/safe_browsing_helper.rb +168 -0
  15. data/lib/rails/generators/google/install_generator.rb +20 -0
  16. data/lib/rails/generators/google/model/model_generator.rb +47 -0
  17. data/lib/rails/generators/google/model/templates/create_google_functions.rb +18 -0
  18. data/lib/rails/generators/google/model/templates/create_google_safe_browsing_full_hash_requests.rb +22 -0
  19. data/lib/rails/generators/google/model/templates/create_google_safe_browsing_full_hashes.rb +20 -0
  20. data/lib/rails/generators/google/model/templates/create_google_safe_browsing_list.rb +15 -0
  21. data/lib/rails/generators/google/model/templates/create_google_safe_browsing_redirect_urls.rb +26 -0
  22. data/lib/rails/generators/google/model/templates/create_google_safe_browsing_shavar.rb +27 -0
  23. data/lib/rails/generators/google/model/templates/google.rb +2 -0
  24. data/lib/rails/generators/google/model/templates/google/error.rb +11 -0
  25. data/lib/rails/generators/google/model/templates/google/function.rb +6 -0
  26. data/lib/rails/generators/google/model/templates/google/safe_browsing_full_hash.rb +7 -0
  27. data/lib/rails/generators/google/model/templates/google/safe_browsing_full_hash_request.rb +19 -0
  28. data/lib/rails/generators/google/model/templates/google/safe_browsing_list.rb +41 -0
  29. data/lib/rails/generators/google/model/templates/google/safe_browsing_redirect_url.rb +36 -0
  30. data/lib/rails/generators/google/model/templates/google/safe_browsing_shavar.rb +38 -0
  31. data/lib/rails/generators/google/model/templates/google/safe_browsing_update.rb +77 -0
  32. data/lib/rails/generators/google/rspec/rspec_generator.rb +28 -0
  33. data/lib/rails/generators/google/rspec/templates/bin_sample_1.data +0 -0
  34. data/lib/rails/generators/google/rspec/templates/bin_sample_2.data +0 -0
  35. data/lib/rails/generators/google/rspec/templates/full_hash_parse_spec.rb +58 -0
  36. data/lib/rails/generators/google/rspec/templates/full_hash_response_0.data +0 -0
  37. data/lib/rails/generators/google/rspec/templates/full_hash_response_1.data +0 -0
  38. data/lib/rails/generators/google/rspec/templates/full_hash_response_2.data +3 -0
  39. data/lib/rails/generators/google/rspec/templates/full_hash_response_3.data +3 -0
  40. data/lib/rails/generators/google/rspec/templates/shavar_encode_data_parse_spec.rb +56 -0
  41. data/lib/rails/generators/google/rspec/templates/shavar_list_info_parse_spec.rb +48 -0
  42. data/lib/safe_browsing_task.rb +5 -0
  43. data/lib/tasks/google.rake +122 -0
  44. metadata +222 -0
@@ -0,0 +1,20 @@
1
+ module Google
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+
5
+ GENERATORS = %w(google:config google:helper google:model google:rspec)
6
+ def run_all_generators
7
+ if behavior == :invoke
8
+ GENERATORS.each do |g|
9
+ generate g
10
+ end
11
+ elsif behavior == :revoke
12
+ GENERATORS.reverse.each do |g|
13
+ Rails::Generators.invoke g, [], :behavior => :revoke
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,47 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+ require 'rails/generators/active_record'
4
+
5
+ module Google
6
+ module Generators
7
+ class ModelGenerator < Rails::Generators::Base
8
+ include Rails::Generators::Migration
9
+
10
+ source_root File.expand_path('../templates', __FILE__)
11
+
12
+ def self.next_migration_number path
13
+ ActiveRecord::Generators::Base.next_migration_number(path)
14
+ end
15
+
16
+ def creaet_migrations
17
+
18
+ %w(create_google_functions.rb
19
+ create_google_safe_browsing_full_hash_requests.rb
20
+ create_google_safe_browsing_list.rb
21
+ create_google_safe_browsing_shavar.rb
22
+ create_google_safe_browsing_full_hashes.rb
23
+ create_google_safe_browsing_redirect_urls.rb).each do |f|
24
+
25
+ migration_template "#{f}", "db/migrate/#{f}"
26
+ end
27
+
28
+ end
29
+
30
+ def create_models
31
+ %w(google.rb
32
+ google/function.rb
33
+ google/error.rb
34
+ google/safe_browsing_full_hash.rb
35
+ google/safe_browsing_full_hash_request.rb
36
+ google/safe_browsing_list.rb
37
+ google/safe_browsing_redirect_url.rb
38
+ google/safe_browsing_shavar.rb
39
+ google/safe_browsing_update.rb
40
+ ).each do |f|
41
+ template "#{f}", "app/models/#{f}"
42
+ end
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,18 @@
1
+ class CreateGoogleFunctions < ActiveRecord::Migration
2
+
3
+ class << self
4
+ def up
5
+ create_table :google_functions do |t|
6
+ t.string :name, :limit => 255
7
+ t.integer :version
8
+ t.timestamp :next_updated_at
9
+ t.timestamps
10
+ end
11
+ end
12
+
13
+ def down
14
+ drop_table :google_functions
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ class CreateGoogleSafeBrowsingFullHashRequests < ActiveRecord::Migration
2
+
3
+ class << self
4
+ def up
5
+ create_table :google_safe_browsing_full_hash_requests do |t|
6
+ t.string :prefix
7
+ t.string :state
8
+ t.integer :attempts
9
+ t.datetime :created_at
10
+ t.datetime :requested_at
11
+ end
12
+
13
+ add_index :google_safe_browsing_full_hash_requests, :prefix, :name => 'index_hash_prefix'
14
+
15
+ end
16
+
17
+ def down
18
+ drop_table :google_safe_browsing_full_hash_requests
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ class CreateGoogleSafeBrowsingFullHashes < ActiveRecord::Migration
2
+
3
+ class << self
4
+ def up
5
+ create_table :google_safe_browsing_full_hashes do |t|
6
+ t.string :value # 32 Bytes
7
+ t.integer :add_chunk_num
8
+ t.integer :google_safe_browsing_list_id
9
+ t.timestamps
10
+ end
11
+
12
+ add_index :google_safe_browsing_full_hashes, :value, :name => 'index_full_hashes'
13
+
14
+ end
15
+
16
+ def down
17
+ drop_table :google_safe_browsing_full_hashes
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ class CreateGoogleSafeBrowsingList < ActiveRecord::Migration
2
+
3
+ class << self
4
+ def up
5
+ create_table :google_safe_browsing_lists do |t|
6
+ t.string :name
7
+ end
8
+ end
9
+
10
+ def down
11
+ drop_table :google_safe_browsing_lists
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,26 @@
1
+ class CreateGoogleSafeBrowsingRedirectUrls < ActiveRecord::Migration
2
+
3
+ class << self
4
+ def up
5
+ create_table :google_safe_browsing_redirect_urls do |t|
6
+ t.string :url, :limit => 2047
7
+ t.string :url_hash
8
+ t.integer :order
9
+ t.integer :google_safe_browsing_list_id
10
+ t.string :download_state
11
+ t.integer :download_attempts
12
+ t.datetime :last_download_at
13
+ t.timestamps
14
+ end
15
+
16
+ add_index :google_safe_browsing_redirect_urls, :url_hash, :name => 'index_redirect_url_hashes'
17
+ add_index :google_safe_browsing_redirect_urls, :order, :name => 'index_redirect_urls_order'
18
+
19
+ end
20
+
21
+ def down
22
+ drop_table :google_safe_browsing_redirect_urls
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ class CreateGoogleSafeBrowsingShavar < ActiveRecord::Migration
2
+
3
+ class << self
4
+ def up
5
+ create_table :google_safe_browsing_shavars do |t|
6
+ t.integer :chunk_num
7
+ t.string :chunk_type, :limit => 1 # "a" or "s"
8
+ t.string :host_key
9
+ t.integer :add_chunk_num # Only for sub shavar data, add shavar data will have it as NULL
10
+ t.string :prefix
11
+ t.integer :google_safe_browsing_list_id # malware or phishing
12
+ end
13
+
14
+ add_index :google_safe_browsing_shavars, [:chunk_type, :host_key], :name => 'index_chunk_type_host'
15
+ add_index :google_safe_browsing_shavars, [:chunk_type, :host_key, :prefix], :name => 'index_chunk_type_host_prefix'
16
+ add_index :google_safe_browsing_shavars, [:chunk_type, :add_chunk_num, :host_key, :prefix], :name => 'index_add_chunk_host_prefix'
17
+
18
+ add_index :google_safe_browsing_shavars, \
19
+ [:google_safe_browsing_list_id, :chunk_type, :chunk_num, :host_key, :add_chunk_num, :prefix], :unique => true, :name => 'index_chunk_host_prefix'
20
+ end
21
+
22
+ def down
23
+ drop_table :google_safe_browsing_shavars
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,2 @@
1
+ module Google
2
+ end
@@ -0,0 +1,11 @@
1
+ module Google
2
+ module Error
3
+
4
+ class ParserError < StandardError; end
5
+ class InvalidRequest < StandardError; end
6
+ class ServiceUnavailable < StandardError; end
7
+ class NoContent < StandardError; end
8
+
9
+ class UnknownError < StandardError; end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ module Google
2
+ class Function < ActiveRecord::Base
3
+ GoogleSafeBrowsing ||= 'GoogleSafeBrowsing'
4
+ attr_accessible :name, :version, :next_updated_at
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ module Google
2
+ class SafeBrowsingFullHash < ActiveRecord::Base
3
+ belongs_to :list, :class_name => "Google::SafeBrowsingList", :foreign_key => "google_safe_browsing_list_id"
4
+
5
+ attr_accessible :add_chunk_num, :value, :google_safe_browsing_list_id
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ module Google
2
+ class SafeBrowsingFullHashRequest < ActiveRecord::Base
3
+ before_save :set_other_attrs
4
+
5
+ attr_accessible :prefix, :state, :attempts, :requested_at
6
+
7
+ COMPLETED ||= 'completed'
8
+
9
+ def set_other_attrs
10
+ if !self.state.blank? && self.state != COMPLETED
11
+ self.attempts ||= 0
12
+ self.attempts += 1
13
+ else
14
+ self.attempts = nil
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ module Google
2
+ class SafeBrowsingList < ActiveRecord::Base
3
+
4
+ MalwareList ||= 'goog-malware-shavar'
5
+ PhishList ||= 'googpub-phish-shavar'
6
+
7
+ attr_accessible :prefix
8
+
9
+ has_many :shavars, :class_name => "Google::SafeBrowsingShavar", :foreign_key => "google_safe_browsing_list_id", :dependent => :destroy
10
+ has_many :redirect_urls, :class_name => "Google::SafeBrowsingRedirectUrl", :foreign_key => "google_safe_browsing_list_id", :dependent => :destroy
11
+ has_many :full_hashes, :class_name => "Google::SafeBrowsingFullHash", :foreign_key => "google_safe_browsing_list_id", :dependent => :destroy
12
+
13
+ class << self
14
+
15
+ def valid_list? list_name
16
+ [MalwareList, PhishList].include?(list_name.to_s)
17
+ end
18
+
19
+ def malware_list
20
+ @malware_list_obj ||= find_by_name MalwareList
21
+ end
22
+
23
+ def phishing_list
24
+ @phishing_list_obj ||= find_by_name PhishList
25
+ end
26
+
27
+ def list_by_name name
28
+ if valid_list?(name.to_s)
29
+ if malware_list.name == name.to_s
30
+ malware_list
31
+ elsif phishing_list.name == name.to_s
32
+ phishing_list
33
+ end
34
+ else
35
+ nil
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,36 @@
1
+ module Google
2
+ class SafeBrowsingRedirectUrl < ActiveRecord::Base
3
+
4
+ belongs_to :list, :class_name => "Google::SafeBrowsingList", :foreign_key => "google_safe_browsing_list_id"
5
+ attr_accessible :url, :order, :download_state, :last_download_at, :google_safe_browsing_list_id
6
+ before_create :set_other_attrs
7
+ before_update :set_download_attr
8
+
9
+ COMPLETED ||= 'completed'
10
+
11
+ scope :for_url_and_list_id, lambda { |url, list_id|
12
+ where(url_hash: SafeBrowsingRedirectUrl.url_hash_key(url), google_safe_browsing_list_id: list_id)
13
+ }
14
+
15
+ def set_other_attrs
16
+ ord = Google::SafeBrowsingRedirectUrl.maximum(:order)
17
+ self.order = ord.nil?? 1 : ord + 1
18
+ self.url_hash = SafeBrowsingRedirectUrl.url_hash_key(self.url)
19
+ set_download_attr
20
+ end
21
+
22
+ def set_download_attr
23
+ if !self.download_state.blank? && self.download_state != COMPLETED
24
+ self.download_attempts ||= 0
25
+ self.download_attempts += 1
26
+ end
27
+ end
28
+
29
+ class << self
30
+ def url_hash_key url_str
31
+ Digest::MD5.hexdigest(url_str)
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ module Google
2
+ class SafeBrowsingShavar < ActiveRecord::Base
3
+
4
+ CHUNK_TYPE_ADD ||= 'a'
5
+ CHUNK_TYPE_SUB ||= 's'
6
+
7
+ belongs_to :list, :class_name => "Google::SafeBrowsingList", :foreign_key => "google_safe_browsing_list_id"
8
+
9
+ scope :add_chunk_nums_for_list, lambda {|list_name|
10
+ joins("join google_safe_browsing_lists as lists on lists.id = google_safe_browsing_shavars.google_safe_browsing_list_id")
11
+ .where("lists.name = ?", list_name)
12
+ .where('google_safe_browsing_shavars.chunk_type = ?', CHUNK_TYPE_ADD)
13
+ .group("google_safe_browsing_shavars.chunk_num")
14
+ .order('google_safe_browsing_shavars.chunk_num')
15
+ }
16
+
17
+ scope :sub_chunk_nums_for_list, lambda {|list_name|
18
+ joins("join google_safe_browsing_lists as lists on lists.id = google_safe_browsing_shavars.google_safe_browsing_list_id")
19
+ .where("lists.name = ?", list_name)
20
+ .where('google_safe_browsing_shavars.chunk_type = ?', CHUNK_TYPE_SUB)
21
+ .group("google_safe_browsing_shavars.chunk_num")
22
+ .order('google_safe_browsing_shavars.chunk_num')
23
+ }
24
+
25
+ scope :add_host_keys, lambda { |hashes|
26
+ where(chunk_type: CHUNK_TYPE_ADD, host_key: hashes)
27
+ }
28
+
29
+ scope :add_host_prefixes, lambda { |hosts, prefixes|
30
+ where(chunk_type: CHUNK_TYPE_ADD, host_key: hosts, prefix: prefixes)
31
+ }
32
+
33
+ def self.find_subs_for_add add_chunk_num, host_key, prefix
34
+ where(chunk_type: CHUNK_TYPE_SUB, add_chunk_num: add_chunk_num, host_key: host_key, prefix: prefix)
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,77 @@
1
+ # To capture the GSB Update payload
2
+ module Google
3
+ class SafeBrowsingUpdate
4
+
5
+ #
6
+ # BODY = [(REKEY | MAC) LF] NEXT LF (RESET | (LIST LF)+) EOF
7
+ # NEXT = "n:" DIGIT+ # Minimum delay before polling again in seconds
8
+ # REKEY = "e:pleaserekey"
9
+ # RESET = "r:pleasereset"
10
+ # LIST = "i:" LISTNAME [MAC] (LF LISTDATA)+
11
+ # LISTNAME = (LOALPHA | DIGIT | "-")+ # e.g. "goog-phish-sha128"
12
+ # MAC = "," (LOALPHA | DIGIT)+
13
+ # LISTDATA = ((REDIRECT_URL | ADDDEL-HEAD | SUBDEL-HEAD) LF)+
14
+ # REDIRECT_URL = "u:" URL [MAC]
15
+ # URL = Defined in RFC 1738
16
+ # ADDDEL-HEAD = "ad:" CHUNKLIST
17
+ # SUBDEL-HEAD = "sd:" CHUNKLIST
18
+ # CHUNKLIST = (RANGE | NUMBER) ["," CHUNKLIST]
19
+ # NUMBER = DIGIT+ # Chunk number >= 1
20
+ # RANGE = NUMBER "-" NUMBER
21
+ #
22
+
23
+ attr_accessor :next, :rekey, :reset
24
+ attr_reader :lists
25
+ attr_accessor :current_list
26
+
27
+ def set_current_list list_name
28
+ @current_list = list_name.to_s.to_sym
29
+ @lists ||= {}
30
+ # :u is download urls
31
+ # :sd is sub del
32
+ # :ad is add del
33
+ @lists[current_list] ||= { :u => [], :sd => [], :ad => [] }
34
+ end
35
+
36
+ def has_lists?
37
+ @lists != nil
38
+ end
39
+
40
+ def get_list list_name
41
+ @lists[list_name.to_s.to_sym]
42
+ end
43
+
44
+ def get_current_list
45
+ @lists[current_list]
46
+ end
47
+
48
+ def get_redirect_urls list_name
49
+ name = list_name.to_s.to_sym
50
+ if @lists && @lists[name] && !@lists[name][:u].blank?
51
+ @lists[name][:u]
52
+ else
53
+ []
54
+ end
55
+ end
56
+
57
+ def get_ad_chunk_ids list_name
58
+ name = list_name.to_s.to_sym
59
+ if @lists && @lists[name] && !@lists[name][:ad].blank?
60
+ @lists[name][:ad]
61
+ else
62
+ []
63
+ end
64
+ end
65
+
66
+ def get_sd_chunk_ids list_name
67
+ name = list_name.to_s.to_sym
68
+ if @lists && @lists[name] && !@lists[name][:sd].blank?
69
+ @lists[name][:sd]
70
+ else
71
+ []
72
+ end
73
+ end
74
+
75
+
76
+ end
77
+ end