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