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.
- data/LICENSE.txt +20 -0
- data/README.md +88 -0
- data/lib/faraday/response/safe_browsing_update_parser.rb +119 -0
- data/lib/google/safe_browsing_client.rb +211 -0
- data/lib/google/safe_browsing_parser.rb +214 -0
- data/lib/google/safe_browsing_update_helper.rb +171 -0
- data/lib/google/sha_util.rb +22 -0
- data/lib/google/url_canonicalizer.rb +36 -0
- data/lib/google/url_scramble.rb +54 -0
- data/lib/google_safe_browsing_plugin.rb +29 -0
- data/lib/rails/generators/google/config/config_generator.rb +16 -0
- data/lib/rails/generators/google/config/templates/google_safe_browsing.yml +16 -0
- data/lib/rails/generators/google/helper/helper_generator.rb +16 -0
- data/lib/rails/generators/google/helper/templates/safe_browsing_helper.rb +168 -0
- data/lib/rails/generators/google/install_generator.rb +20 -0
- data/lib/rails/generators/google/model/model_generator.rb +47 -0
- data/lib/rails/generators/google/model/templates/create_google_functions.rb +18 -0
- data/lib/rails/generators/google/model/templates/create_google_safe_browsing_full_hash_requests.rb +22 -0
- data/lib/rails/generators/google/model/templates/create_google_safe_browsing_full_hashes.rb +20 -0
- data/lib/rails/generators/google/model/templates/create_google_safe_browsing_list.rb +15 -0
- data/lib/rails/generators/google/model/templates/create_google_safe_browsing_redirect_urls.rb +26 -0
- data/lib/rails/generators/google/model/templates/create_google_safe_browsing_shavar.rb +27 -0
- data/lib/rails/generators/google/model/templates/google.rb +2 -0
- data/lib/rails/generators/google/model/templates/google/error.rb +11 -0
- data/lib/rails/generators/google/model/templates/google/function.rb +6 -0
- data/lib/rails/generators/google/model/templates/google/safe_browsing_full_hash.rb +7 -0
- data/lib/rails/generators/google/model/templates/google/safe_browsing_full_hash_request.rb +19 -0
- data/lib/rails/generators/google/model/templates/google/safe_browsing_list.rb +41 -0
- data/lib/rails/generators/google/model/templates/google/safe_browsing_redirect_url.rb +36 -0
- data/lib/rails/generators/google/model/templates/google/safe_browsing_shavar.rb +38 -0
- data/lib/rails/generators/google/model/templates/google/safe_browsing_update.rb +77 -0
- data/lib/rails/generators/google/rspec/rspec_generator.rb +28 -0
- data/lib/rails/generators/google/rspec/templates/bin_sample_1.data +0 -0
- data/lib/rails/generators/google/rspec/templates/bin_sample_2.data +0 -0
- data/lib/rails/generators/google/rspec/templates/full_hash_parse_spec.rb +58 -0
- data/lib/rails/generators/google/rspec/templates/full_hash_response_0.data +0 -0
- data/lib/rails/generators/google/rspec/templates/full_hash_response_1.data +0 -0
- data/lib/rails/generators/google/rspec/templates/full_hash_response_2.data +3 -0
- data/lib/rails/generators/google/rspec/templates/full_hash_response_3.data +3 -0
- data/lib/rails/generators/google/rspec/templates/shavar_encode_data_parse_spec.rb +56 -0
- data/lib/rails/generators/google/rspec/templates/shavar_list_info_parse_spec.rb +48 -0
- data/lib/safe_browsing_task.rb +5 -0
- data/lib/tasks/google.rake +122 -0
- 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
|
data/lib/rails/generators/google/model/templates/create_google_safe_browsing_full_hash_requests.rb
ADDED
@@ -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,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,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,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
|