gman 8.0.0 → 8.1.0
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.
- checksums.yaml +4 -4
- data/lib/gman/domain_list.rb +60 -7
- data/lib/gman/identifier.rb +2 -6
- data/lib/gman/importer.rb +13 -13
- data/lib/gman/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 29b30e2a1e50e8e0f8f7d5ca50a6c2a8671b1e69a1d8213415bd6d6a70a35af9
|
|
4
|
+
data.tar.gz: 07b8f53008e8699d2f67ef162460540196cd90c3e89e1ed3a4054a185b0a325f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 25c6626204645cfbc03b7875ddb5a7eb51d18d56b5f70af1f993def0ece5841a36b27e151c2e517eee4060059627f648f1883c45216d50b68ee1f749ea4999de
|
|
7
|
+
data.tar.gz: 5ca3b6cba72c5bf9238abaa014c61f9caaeaa10bcc4a0f147b27f92fb5fa96a2fff835fbd2b479764429d6ce6e0e1bd15937b8f371c8483dbb63724ebbafb032
|
data/lib/gman/domain_list.rb
CHANGED
|
@@ -4,7 +4,7 @@ class Gman
|
|
|
4
4
|
class DomainList
|
|
5
5
|
COMMENT_REGEX = %r{//[/\s]*(.*)$}i
|
|
6
6
|
|
|
7
|
-
attr_writer :
|
|
7
|
+
attr_writer :path, :contents
|
|
8
8
|
|
|
9
9
|
class << self
|
|
10
10
|
# The current, government domain list
|
|
@@ -41,6 +41,12 @@ class Gman
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
# Replaces the list data, a hash of group => domains
|
|
45
|
+
def data=(data)
|
|
46
|
+
@data = data
|
|
47
|
+
clear_cache
|
|
48
|
+
end
|
|
49
|
+
|
|
44
50
|
# Returns the parsed contents of the domain list as a hash
|
|
45
51
|
# in the form for group => domains
|
|
46
52
|
def data
|
|
@@ -73,7 +79,7 @@ class Gman
|
|
|
73
79
|
|
|
74
80
|
# Return an array of strings representing all domains on the list
|
|
75
81
|
def domains
|
|
76
|
-
data.values.flatten.compact.sort.uniq
|
|
82
|
+
@domains ||= data.values.flatten.compact.sort.uniq.freeze
|
|
77
83
|
end
|
|
78
84
|
|
|
79
85
|
# Return the total number of domains in the list
|
|
@@ -84,11 +90,12 @@ class Gman
|
|
|
84
90
|
# Alphabetize groups and domains within each group
|
|
85
91
|
# We need to ensure exceptions appear after their coresponding rules
|
|
86
92
|
def alphabetize
|
|
87
|
-
|
|
88
|
-
@data.
|
|
93
|
+
self.data = data.sort_by { |k, _v| k.downcase }.to_h
|
|
94
|
+
@data.each_value do |domains|
|
|
89
95
|
domains.sort! { |a, b| sort_with_exceptions(a, b) }
|
|
90
96
|
domains.uniq!
|
|
91
97
|
end
|
|
98
|
+
clear_cache
|
|
92
99
|
end
|
|
93
100
|
|
|
94
101
|
# Write the domain list to disk
|
|
@@ -112,14 +119,60 @@ class Gman
|
|
|
112
119
|
end
|
|
113
120
|
alias to_public_suffix to_s
|
|
114
121
|
|
|
115
|
-
#
|
|
116
|
-
#
|
|
122
|
+
# Returns the group a list entry belongs to, e.g., "US Federal" for "fcc.gov"
|
|
123
|
+
# The entry must match the list verbatim. If an entry appears in more than
|
|
124
|
+
# one group, the first group wins.
|
|
125
|
+
def group_for(entry)
|
|
126
|
+
group_index[entry]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Given a domain, find the list entry that covers it, using public suffix
|
|
130
|
+
# rules. E.g., `fcc.gov` would be the parent of `data.fcc.gov`, and
|
|
131
|
+
# `*.foo.gov` the parent of `bar.foo.gov`.
|
|
132
|
+
#
|
|
133
|
+
# If more than one entry matches, the longest wins. A domain under an
|
|
134
|
+
# exception rule (e.g., `!mail.gov.ua`) has no parent. A domain that is
|
|
135
|
+
# itself on the list returns the entry that covers its parent, if any.
|
|
136
|
+
#
|
|
137
|
+
# Returns the list entry as written (e.g., `*.foo.gov`), or nil
|
|
117
138
|
def parent_domain(domain)
|
|
118
|
-
|
|
139
|
+
rule = parent_list.find(domain, default: nil)
|
|
140
|
+
if rule && !rule.is_a?(PublicSuffix::Rule::Exception) && rule.value == domain
|
|
141
|
+
ancestor = domain.split('.', 2)[1]
|
|
142
|
+
rule = ancestor && parent_list.find(ancestor, default: nil)
|
|
143
|
+
end
|
|
144
|
+
return if rule.nil? || rule.is_a?(PublicSuffix::Rule::Exception)
|
|
145
|
+
|
|
146
|
+
rule.rule
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Returns the exception rule (e.g., `!mail.gov.ua`) that excludes the given
|
|
150
|
+
# domain from the list, or nil if none does
|
|
151
|
+
def exception_for(domain)
|
|
152
|
+
rule = parent_list.find(domain, default: nil)
|
|
153
|
+
rule.rule if rule.is_a?(PublicSuffix::Rule::Exception)
|
|
119
154
|
end
|
|
120
155
|
|
|
121
156
|
private
|
|
122
157
|
|
|
158
|
+
# Clear values derived from data. Call after mutating data in place.
|
|
159
|
+
def clear_cache
|
|
160
|
+
@domains = @parent_list = @group_index = nil
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# PublicSuffix::List of the current data, for parent lookups. Unlike
|
|
164
|
+
# #public_suffix_list, it is rebuilt when the data changes.
|
|
165
|
+
def parent_list
|
|
166
|
+
@parent_list ||= PublicSuffix::List.parse(domains.join("\n"))
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Hash of list entry => group, for constant-time group lookups
|
|
170
|
+
def group_index
|
|
171
|
+
@group_index ||= data.each_with_object({}) do |(group, domains), index|
|
|
172
|
+
domains.each { |domain| index[domain] ||= group }
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
123
176
|
# Parse a public-suffix formatted string into a hash of groups => [domains]
|
|
124
177
|
def string_to_hash(string)
|
|
125
178
|
return unless string
|
data/lib/gman/identifier.rb
CHANGED
|
@@ -110,12 +110,8 @@ class Gman
|
|
|
110
110
|
def list_category
|
|
111
111
|
return @list_category if defined?(@list_category)
|
|
112
112
|
|
|
113
|
-
match = Gman.list.public_suffix_list.find(domain.to_s)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
regex = %r{// ([^\n]+)\n?[^/]*\n#{Regexp.escape(match.value)}\n}im
|
|
117
|
-
matches = Gman.list.contents.match(regex)
|
|
118
|
-
@list_category = matches ? matches[1] : nil
|
|
113
|
+
match = Gman.list.public_suffix_list.find(domain.to_s, default: nil)
|
|
114
|
+
@list_category = match && Gman.list.group_for(match.value)
|
|
119
115
|
end
|
|
120
116
|
|
|
121
117
|
def matches
|
data/lib/gman/importer.rb
CHANGED
|
@@ -6,6 +6,7 @@ require 'yaml'
|
|
|
6
6
|
require 'open-uri'
|
|
7
7
|
require 'resolv'
|
|
8
8
|
require 'logger'
|
|
9
|
+
require 'addressable/uri'
|
|
9
10
|
require 'swot'
|
|
10
11
|
require_relative '../gman'
|
|
11
12
|
require_relative 'domain_list'
|
|
@@ -71,7 +72,7 @@ class Gman
|
|
|
71
72
|
|
|
72
73
|
def normalize_domain(domain)
|
|
73
74
|
domain = Gman.new(domain).to_s
|
|
74
|
-
domain.to_s.downcase.strip.
|
|
75
|
+
domain.to_s.downcase.strip.delete_prefix('www.').delete_suffix('/')
|
|
75
76
|
end
|
|
76
77
|
|
|
77
78
|
def valid_domain?(domain, options = {})
|
|
@@ -152,34 +153,33 @@ class Gman
|
|
|
152
153
|
|
|
153
154
|
if current.domains.include?(domain)
|
|
154
155
|
reject(domain, 'duplicate')
|
|
155
|
-
|
|
156
|
-
parent = current.parent_domain(domain)
|
|
156
|
+
elsif (parent = current.parent_domain(domain))
|
|
157
157
|
reject(domain, "subdomain of #{parent}")
|
|
158
|
+
else
|
|
159
|
+
reject(domain, "excluded by #{current.exception_for(domain)}")
|
|
158
160
|
end
|
|
159
161
|
end
|
|
160
162
|
|
|
163
|
+
# A domain is a dupe if it's on the list, covered by a list entry, or
|
|
164
|
+
# excluded by an exception rule
|
|
161
165
|
def dupe?(domain)
|
|
162
|
-
current.domains.include?(domain) || current.parent_domain(domain)
|
|
166
|
+
current.domains.include?(domain) || current.parent_domain(domain) || current.exception_for(domain)
|
|
163
167
|
end
|
|
164
168
|
|
|
165
169
|
def normalize_domains!
|
|
166
|
-
domain_list.
|
|
167
|
-
domains.map
|
|
168
|
-
domains.uniq!
|
|
170
|
+
domain_list.data = domain_list.data.transform_values do |domains|
|
|
171
|
+
domains.map { |domain| normalize_domain(domain) }.uniq
|
|
169
172
|
end
|
|
170
173
|
end
|
|
171
174
|
|
|
172
175
|
def ensure_validity!(options = {})
|
|
173
|
-
domain_list.data.
|
|
174
|
-
domains.select
|
|
176
|
+
domain_list.data = domain_list.data.transform_values do |domains|
|
|
177
|
+
domains.select { |domain| valid_domain?(domain, options) }
|
|
175
178
|
end
|
|
176
179
|
end
|
|
177
180
|
|
|
178
181
|
def add_to_current
|
|
179
|
-
domain_list.data
|
|
180
|
-
current.data[group] ||= []
|
|
181
|
-
current.data[group].concat domains
|
|
182
|
-
end
|
|
182
|
+
current.data = current.data.merge(domain_list.data) { |_group, existing, added| existing + added }
|
|
183
183
|
current.write
|
|
184
184
|
end
|
|
185
185
|
|
data/lib/gman/version.rb
CHANGED