ryodo 0.0.2
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/.document +5 -0
- data/.rbenv-gemsets +1 -0
- data/.rbenv-version +1 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +16 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +46 -0
- data/LICENSE.txt +20 -0
- data/README.md +72 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/checks/matching.rb +89 -0
- data/data/suffix.dat +4317 -0
- data/lib/ryodo/convenience/.u.rb +19 -0
- data/lib/ryodo/convenience.rb +13 -0
- data/lib/ryodo/domain.rb +83 -0
- data/lib/ryodo/ext/string.rb +9 -0
- data/lib/ryodo/methods.rb +12 -0
- data/lib/ryodo/parser.rb +37 -0
- data/lib/ryodo/rule.rb +15 -0
- data/lib/ryodo/rule_set.rb +77 -0
- data/lib/ryodo/suffix_list.rb +57 -0
- data/lib/ryodo/suffix_list_fetcher.rb +54 -0
- data/lib/ryodo.rb +29 -0
- data/spec/_files/mozilla_effective_tld_names.dat +5229 -0
- data/spec/ryodo/suffix_list_fetcher_spec.rb +81 -0
- data/spec/ryodo/suffix_list_spec.rb +50 -0
- data/spec/ryodo_spec.rb +6 -0
- data/spec/spec_helper.rb +37 -0
- metadata +192 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Ryodo
|
4
|
+
module Convenience
|
5
|
+
module U
|
6
|
+
|
7
|
+
alias_method :ryodo, :Ryodo
|
8
|
+
|
9
|
+
# Unicode junkie? ;o)
|
10
|
+
alias_method :"ryōdo", :Ryodo
|
11
|
+
alias_method :"領土", :Ryodo
|
12
|
+
alias_method :"りょうど", :Ryodo
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
include Ryodo::Convenience::U
|
data/lib/ryodo/domain.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Ryodo
|
4
|
+
class Domain
|
5
|
+
|
6
|
+
# DomainString is a String with extended methods
|
7
|
+
class DomainString < String
|
8
|
+
|
9
|
+
def reverse
|
10
|
+
to_a(:r).join(".")
|
11
|
+
end
|
12
|
+
alias_method :r, :reverse
|
13
|
+
|
14
|
+
def to_a option = nil
|
15
|
+
case option
|
16
|
+
when :reverse, :r
|
17
|
+
dsplit.reverse
|
18
|
+
else
|
19
|
+
dsplit
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def dsplit
|
26
|
+
self.split(".",-1)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
# remove own class comparison (we will use String#== via method_missing)
|
32
|
+
undef_method :==
|
33
|
+
|
34
|
+
def initialize domainStr
|
35
|
+
raise TypeError, "Not a valid domain string!" unless domainStr.is_a?(String)
|
36
|
+
@domain_string = DomainString.new domainStr.downcase
|
37
|
+
|
38
|
+
parts = Ryodo::Parser.run(@domain_string)
|
39
|
+
|
40
|
+
@suffix = parts ? parts[0].reverse.join(".") : nil
|
41
|
+
@domain = parts && !parts[1].empty? ? (parts[0] + parts[1]).reverse.join(".") : nil
|
42
|
+
@subdomain = parts && !parts[2].empty? ? (parts[2]).reverse.join(".") : nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def suffix
|
46
|
+
DomainString.new @suffix if @suffix
|
47
|
+
end
|
48
|
+
alias_method :tld, :suffix
|
49
|
+
|
50
|
+
def domain
|
51
|
+
DomainString.new @domain if @domain
|
52
|
+
end
|
53
|
+
alias_method :registered_domain, :domain
|
54
|
+
alias_method :regdomain, :domain
|
55
|
+
|
56
|
+
def subdomain
|
57
|
+
DomainString.new @subdomain if @subdomain
|
58
|
+
end
|
59
|
+
|
60
|
+
def fqdn
|
61
|
+
DomainString.new "#{to_s}."
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_s
|
65
|
+
@domain_string
|
66
|
+
end
|
67
|
+
|
68
|
+
def inspect
|
69
|
+
@domain_string.inspect
|
70
|
+
end
|
71
|
+
|
72
|
+
# pass all missings to @domain_string (String class)
|
73
|
+
def method_missing(name, *args, &block)
|
74
|
+
@domain_string.send(name, *args, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
# explicit definition of class' send
|
78
|
+
def send(symbol, *args)
|
79
|
+
__send__(symbol, *args)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
data/lib/ryodo/parser.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Ryodo
|
4
|
+
class Parser
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@rules = Ryodo::RuleSet.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def build_query domain
|
11
|
+
if domain.to_s[0] == "."
|
12
|
+
# FQDN in reversed order
|
13
|
+
domain.downcase[1..-1].split(".")
|
14
|
+
else
|
15
|
+
domain.downcase.split(".").reverse
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse domain
|
20
|
+
@rules.match build_query(domain)
|
21
|
+
end
|
22
|
+
|
23
|
+
class << self
|
24
|
+
|
25
|
+
def run domain
|
26
|
+
instance.parse domain
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def instance
|
31
|
+
@@instance ||= new
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/lib/ryodo/rule.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Ryodo
|
4
|
+
class RuleSet
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@tree = {}
|
8
|
+
build!
|
9
|
+
end
|
10
|
+
|
11
|
+
def build!
|
12
|
+
|
13
|
+
Ryodo::SuffixList.list.each do |line|
|
14
|
+
|
15
|
+
line.each.with_index do |node_name, idx|
|
16
|
+
|
17
|
+
stopOK = node_name == line.last
|
18
|
+
exception = node_name[0] == "!"
|
19
|
+
node_name = node_name[1..-1] if exception
|
20
|
+
children = {}
|
21
|
+
|
22
|
+
node = Ryodo::Rule.new(exception, stopOK, children)
|
23
|
+
|
24
|
+
if idx > 0
|
25
|
+
end_idx = idx - 1
|
26
|
+
parent = select_rule(line[0..end_idx])
|
27
|
+
parent.children[node_name] = node unless parent.children[node_name]
|
28
|
+
|
29
|
+
else
|
30
|
+
@tree[node_name] = node unless @tree[node_name]
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def select_rule(rule_path)
|
40
|
+
|
41
|
+
path = rule_path.dup
|
42
|
+
|
43
|
+
if current = path.pop
|
44
|
+
|
45
|
+
if path.empty?
|
46
|
+
@tree[current]
|
47
|
+
|
48
|
+
else
|
49
|
+
rule = select_rule(path)
|
50
|
+
rule.children[current] if rule
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def match(path)
|
58
|
+
suffix, domain, match = [], [], nil
|
59
|
+
|
60
|
+
until match || path.empty?
|
61
|
+
match = select_rule(path) || select_rule(path.dup.fill("*",-1))
|
62
|
+
match = nil if match && !match.is_suffix?
|
63
|
+
domain.unshift path.pop
|
64
|
+
suffix = path
|
65
|
+
end
|
66
|
+
|
67
|
+
suffix.push(domain.shift) if match && !match.exception
|
68
|
+
|
69
|
+
# only if match has no children with domain and domain is present
|
70
|
+
if match && !match.children.keys.include?(domain[0]) && domain[0]
|
71
|
+
[ suffix, [domain.shift], domain ]
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Ryodo
|
4
|
+
|
5
|
+
class SuffixList
|
6
|
+
def initialize suffix_file = Ryodo::PUBLIC_SUFFIX_STORE
|
7
|
+
load_file(suffix_file)
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse_data
|
11
|
+
# loads and converts to array
|
12
|
+
# "baz.bar.foo" => ["baz", "bar", "foo"]
|
13
|
+
File.readlines(@suffix_file).map{ |line| line.strip.split(".") }
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_file suffix_file = Ryodo::PUBLIC_SUFFIX_STORE
|
17
|
+
@suffix_file = suffix_file
|
18
|
+
@suffix_data = parse_data
|
19
|
+
end
|
20
|
+
|
21
|
+
def list
|
22
|
+
@suffix_data
|
23
|
+
end
|
24
|
+
|
25
|
+
def inspect
|
26
|
+
"#<#{self.class} FILE:#{@suffix_file} ENTRIES:#{@suffix_data.size}>"
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
|
31
|
+
def SuffixList suffix_file = Ryodo::PUBLIC_SUFFIX_STORE
|
32
|
+
instance(suffix_file)
|
33
|
+
end
|
34
|
+
|
35
|
+
def reload suffix_file = Ryodo::PUBLIC_SUFFIX_STORE
|
36
|
+
instance.load_file(suffix_file) && true
|
37
|
+
end
|
38
|
+
|
39
|
+
def list
|
40
|
+
instance.list
|
41
|
+
end
|
42
|
+
|
43
|
+
def instance
|
44
|
+
@@instance ||= new
|
45
|
+
end
|
46
|
+
|
47
|
+
def inspect
|
48
|
+
instance.inspect
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
private_class_method :new
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
require "net/http"
|
5
|
+
|
6
|
+
module Ryodo
|
7
|
+
|
8
|
+
class FetchError < StandardError; end
|
9
|
+
|
10
|
+
class SuffixListFetcher
|
11
|
+
|
12
|
+
def initialize uri = Ryodo::PUBLIC_SUFFIX_DATA_URI, store = Ryodo::PUBLIC_SUFFIX_STORE
|
13
|
+
@uri = URI(uri)
|
14
|
+
@store = store
|
15
|
+
end
|
16
|
+
|
17
|
+
def fetch_data
|
18
|
+
res = Net::HTTP.get_response(@uri)
|
19
|
+
raise Ryodo::FetchError, "Could not fetch suffix data! (#{res})" unless res.is_a?(Net::HTTPSuccess)
|
20
|
+
@fetched_data = res.body.lines
|
21
|
+
end
|
22
|
+
|
23
|
+
def prepare_data
|
24
|
+
@prepared_data = @fetched_data.inject([]) do |acc, line|
|
25
|
+
next(acc) if line =~ /^\/\/|^\n/
|
26
|
+
dns_line = line.strip.
|
27
|
+
split(".").
|
28
|
+
reverse.
|
29
|
+
join(".") # "foo.bar.baz" => "baz.bar.foo"
|
30
|
+
acc << dns_line
|
31
|
+
end.sort
|
32
|
+
end
|
33
|
+
|
34
|
+
def save_data
|
35
|
+
File.open(Ryodo::PUBLIC_SUFFIX_STORE, "w") do |fh|
|
36
|
+
fh.write @prepared_data.join("\n")
|
37
|
+
end if @prepared_data
|
38
|
+
end
|
39
|
+
|
40
|
+
class << self
|
41
|
+
def fetch_and_save! uri = Ryodo::PUBLIC_SUFFIX_DATA_URI, store = Ryodo::PUBLIC_SUFFIX_STORE
|
42
|
+
fetcher = self.new uri, store
|
43
|
+
fetcher.fetch_data
|
44
|
+
fetcher.prepare_data
|
45
|
+
fetcher.save_data
|
46
|
+
true
|
47
|
+
rescue
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/ryodo.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Ryodo
|
4
|
+
|
5
|
+
VERSION_FILE = File.expand_path("../../VERSION", __FILE__)
|
6
|
+
VERSION = File.exist?(VERSION_FILE) ? File.read(VERSION_FILE) : "(could not find VERSION file)"
|
7
|
+
|
8
|
+
RYODO_ROOT = File.expand_path("../..", __FILE__)
|
9
|
+
|
10
|
+
PUBLIC_SUFFIX_DATA_URI = "http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1"
|
11
|
+
PUBLIC_SUFFIX_STORE = "#{RYODO_ROOT}/data/suffix.dat"
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
require "ryodo/domain"
|
16
|
+
require "ryodo/parser"
|
17
|
+
require "ryodo/rule"
|
18
|
+
require "ryodo/rule_set"
|
19
|
+
require "ryodo/suffix_list"
|
20
|
+
|
21
|
+
require "ryodo/methods"
|
22
|
+
require "ryodo/ext/string"
|
23
|
+
|
24
|
+
# Convenient shorthands
|
25
|
+
module Ryodo
|
26
|
+
extend Ryodo::Methods
|
27
|
+
require "ryodo/convenience"
|
28
|
+
require "ryodo/convenience/.u" unless Kernel.const_defined?("RYODO_NO_U") || ENV['RYODO_NO_U']
|
29
|
+
end
|