google-safe-browsing-plugin 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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