surbl_client 0.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.
- checksums.yaml +7 -0
- data/lib/surbl_client.rb +236 -0
- data/test/tc_surbl_client.rb +26 -0
- metadata +45 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 979f763eb53d72f16d63ae605fe1c3dc25b3ee88
|
|
4
|
+
data.tar.gz: 49583ef0e17874f74b932e7c4d406ceb6ab1a650
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 864f33bf0b726ede4bd3e4593a93aa9ed9bbfb8cb954e691d99481669890e06861e1b6f4aa0a4964c81835b9cbee7cc863f32daa08016a03a0b4c7e262486979
|
|
7
|
+
data.tar.gz: dfd9223bb297bdd49b0e95ddc7167815a03a0580eb0f22ea2987429b9a223939b695504fba735c940b282925db286a3b1a16920b3d1b59a95d2d8a786e365efe
|
data/lib/surbl_client.rb
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# SURBL checker (http://www.surbl.org/)
|
|
2
|
+
#
|
|
3
|
+
# Example usage:
|
|
4
|
+
# 0> require "surbl_client"
|
|
5
|
+
# => true
|
|
6
|
+
# 0> surbl = SurblClient.new()
|
|
7
|
+
# => #<SurblClient:0x007fb6181216c0 @cache=[nil, nil]>
|
|
8
|
+
# 0> domain = "foo.bar.test.surbl.org"
|
|
9
|
+
# => "foo.bar.test.surbl.org"
|
|
10
|
+
# 0> surbl.include? domain
|
|
11
|
+
# => true
|
|
12
|
+
# 0> surbl.lookup(domain)
|
|
13
|
+
# => ["test.surbl.org", ["sc", "ws", "ph", "ob", "ab", "jp"]]
|
|
14
|
+
# 0> if surbl.include? domain then
|
|
15
|
+
# 1* results = surbl.lookup(domain)
|
|
16
|
+
# 1> puts "#{results[0]} blacklisted in #{results[1]}"
|
|
17
|
+
# 1> end
|
|
18
|
+
# test.surbl.org blacklisted in ["sc", "ws", "ph", "ob", "ab", "jp"]
|
|
19
|
+
# => nil
|
|
20
|
+
#
|
|
21
|
+
# This is a ruby port of https://github.com/byfilip/surblclient.
|
|
22
|
+
#
|
|
23
|
+
# Author:: George Perry (mailto:perrygeorget.public@gmail.com)
|
|
24
|
+
# License:: MIT
|
|
25
|
+
|
|
26
|
+
require 'resolv'
|
|
27
|
+
|
|
28
|
+
class SurblClient
|
|
29
|
+
@@flags = [[2, "sc"], [4, "ws"], [8, "ph"], [16, "ob"], [32, "ab"], [64, "jp"]]
|
|
30
|
+
@@two_level_tlds = %r{(?:^|\.)
|
|
31
|
+
(?:(?:com|edu|gov|net|mil|org)\.ac
|
|
32
|
+
|(?:com|net|org|gov|ac|co|sch|pro)\.ae
|
|
33
|
+
|(?:com|org|edu|gov)\.ai
|
|
34
|
+
|(?:com|net|org|gov|mil|edu|int)\.ar
|
|
35
|
+
|(?:co|ac|or|gv|priv)\.at
|
|
36
|
+
|(?:com|gov|org|edu|id|oz|info|net|asn|csiro|telememo|conf|otc|id)\.au
|
|
37
|
+
|(?:com|net|org)\.az
|
|
38
|
+
|(?:com|net|org)\.bb
|
|
39
|
+
|(?:ac|belgie|dns|fgov)\.be
|
|
40
|
+
|(?:com|gov|net|edu|org)\.bh
|
|
41
|
+
|(?:com|edu|gov|org|net)\.bm
|
|
42
|
+
|(?:adm|adv|agr|am|arq|art|ato|bio|bmd|cim|cng|cnt|com|coop|ecn|edu|eng|esp|etc|eti|far|fm|fnd|fot|fst|g12|ggf|gov|imb|ind|inf|jor|lel|mat|med|mil|mus|net|nom|not|ntr|odo|org|ppg|pro|psc|psi|qsl|rec|slg|srv|tmp|trd|tur|tv|vet|zlg)\.br
|
|
43
|
+
|(?:com|net|org)\.bs
|
|
44
|
+
|(?:com|net|org)\.bz
|
|
45
|
+
|(?:ab|bc|mb|nb|nf|nl|ns|nt|nu|on|pe|qc|sk|yk|gc)\.ca
|
|
46
|
+
|(?:co|net|org|edu|gov)\.ck
|
|
47
|
+
|(?:com|edu|gov|net|org|ac|ah|bj|cq|gd|gs|gx|gz|hb|he|hi|hk|hl|hn|jl|js|ln|mo|nm|nx|qh|sc|sn|sh|sx|tj|tw|xj|xz|yn|zj)\.cn
|
|
48
|
+
|(?:arts|com|edu|firm|gov|info|int|nom|mil|org|rec|store|web)\.co
|
|
49
|
+
|(?:ac|co|ed|fi|go|or|sa)\.cr
|
|
50
|
+
|(?:com|net|org)\.cu
|
|
51
|
+
|(?:ac|com|gov|net|org)\.cy
|
|
52
|
+
|(?:co)\.dk
|
|
53
|
+
|(?:art|com|edu|gov|gob|org|mil|net|sld|web)\.do
|
|
54
|
+
|(?:com|org|net|gov|edu|ass|pol|art)\.dz
|
|
55
|
+
|(?:com|k12|edu|fin|med|gov|mil|org|net)\.ec
|
|
56
|
+
|(?:com|pri|fie|org|med)\.ee
|
|
57
|
+
|(?:com|edu|eun|gov|net|org|sci)\.eg
|
|
58
|
+
|(?:com|net|org|edu|mil|gov|ind)\.er
|
|
59
|
+
|(?:com|org|gob|edu|nom)\.es
|
|
60
|
+
|(?:com|gov|org|edu|net|biz|name|info)\.et
|
|
61
|
+
|(?:ac|com|gov|id|org|school)\.fj
|
|
62
|
+
|(?:com|ac|gov|net|nom|org)\.fk
|
|
63
|
+
|(?:asso|nom|barreau|com|prd|presse|tm|aeroport|assedic|avocat|avoues|cci|chambagri|chirurgiens-dentistes|experts-comptables|geometre-expert|gouv|greta|huissier-justice|medecin|notaires|pharmacien|port|veterinaire)\.fr
|
|
64
|
+
|(?:com|edu|gov|mil|net|org|pvt)\.ge
|
|
65
|
+
|(?:co|org|sch|ac|gov|ltd|ind|net|alderney|guernsey|sark)\.gg
|
|
66
|
+
|(?:com|edu|gov|net|org)\.gr
|
|
67
|
+
|(?:com|edu|net|gob|org|mil|ind)\.gt
|
|
68
|
+
|(?:com|edu|net|org|gov|mil)\.gu
|
|
69
|
+
|(?:com|net|org|idv|gov|edu)\.hk
|
|
70
|
+
|(?:co|2000|erotika|jogasz|sex|video|info|agrar|film|konyvelo|shop|org|bolt|forum|lakas|suli|priv|casino|games|media|szex|sport|city|hotel|news|tozsde|tm|erotica|ingatlan|reklam|utazas)\.hu
|
|
71
|
+
|(?:ac|co|go|mil|net|or)\.id
|
|
72
|
+
|(?:co|net|org|ac|gov|k12|muni|idf)\.il
|
|
73
|
+
|(?:co|net|org|ac|lkd\.co|gov|nic|plc\.co)\.im
|
|
74
|
+
|(?:co|net|ac|ernet|gov|nic|res|gen|firm|mil|org|ind)\.in
|
|
75
|
+
|(?:ac|co|gov|id|net|org|sch)\.ir
|
|
76
|
+
|(?:ac|co|net|org|gov|ind|jersey|ltd|sch)\.je
|
|
77
|
+
|(?:com|org|net|gov|edu|mil)\.jo
|
|
78
|
+
|(?:ad|ac|co|go|or|ne|gr|ed|lg|net|org|gov|hokkaido|aomori|iwate|miyagi|akita|yamagata|fukushima|ibaraki|tochigi|gunma|saitama|chiba|tokyo|kanagawa|niigata|toyama|ishikawa|fukui|yamanashi|nagano|gifu|shizuoka|aichi|mie|shiga|kyoto|osaka|hyogo|nara|wakayama|tottori|shimane|okayama|hiroshima|yamaguchi|tokushima|kagawa|ehime|kochi|fukuoka|saga|nagasaki|kumamoto|oita|miyazaki|kagoshima|okinawa|sapporo|sendai|yokohama|kawasaki|nagoya|kobe|kitakyushu|utsunomiya|kanazawa|takamatsu|matsuyama)\.jp
|
|
79
|
+
|(?:com|net|org|edu|gov|mil)\.kg
|
|
80
|
+
|(?:com|net|org|per|edu|gov|mil)\.kh
|
|
81
|
+
|(?:ac|co|go|ne|or|pe|re|seoul|kyonggi)\.kr
|
|
82
|
+
|(?:com|net|org|edu|gov)\.kw
|
|
83
|
+
|(?:com|net|org)\.la
|
|
84
|
+
|(?:com|org|net|edu|gov|mil)\.lb
|
|
85
|
+
|(?:com|edu|gov|net|org)\.lc
|
|
86
|
+
|(?:com|net|org|edu|gov|mil|id|asn|conf)\.lv
|
|
87
|
+
|(?:com|net|org)\.ly
|
|
88
|
+
|(?:co|net|org|press|ac)\.ma
|
|
89
|
+
|(?:com)\.mk
|
|
90
|
+
|(?:com|net|org|edu|gov)\.mm
|
|
91
|
+
|(?:com|org|edu|gov|museum)\.mn
|
|
92
|
+
|(?:com|net|org|edu|gov)\.mo
|
|
93
|
+
|(?:com|net|org|edu|tm|uu)\.mt
|
|
94
|
+
|(?:com|net|org|gob|edu)\.mx
|
|
95
|
+
|(?:com|org|gov|edu|net)\.my
|
|
96
|
+
|(?:com|org|net|alt|edu|cul|unam|telecom)\.na
|
|
97
|
+
|(?:com|net|org)\.nc
|
|
98
|
+
|(?:ac|edu|sch|com|gov|org|net)\.ng
|
|
99
|
+
|(?:gob|com|net|edu|nom|org)\.ni
|
|
100
|
+
|(?:com|net|org|gov|edu)\.np
|
|
101
|
+
|(?:ac|co|cri|gen|geek|govt|iwi|maori|mil|net|org|school)\.nz
|
|
102
|
+
|(?:com|co|edu|ac|gov|net|org|mod|museum|biz|pro|med)\.om
|
|
103
|
+
|(?:com|net|org|edu|ac|gob|sld)\.pa
|
|
104
|
+
|(?:edu|gob|nom|mil|org|com|net)\.pe
|
|
105
|
+
|(?:com|net|ac)\.pg
|
|
106
|
+
|(?:com|net|org|mil|ngo)\.ph
|
|
107
|
+
|(?:aid|agro|atm|auto|biz|com|edu|gmina|gsm|info|mail|miasta|media|mil|net|nieruchomosci|nom|org|pc|powiat|priv|realestate|rel|sex|shop|sklep|sos|szkola|targi|tm|tourism|travel|turystyka)\.pl
|
|
108
|
+
|(?:com|net|edu|org|fam|biz|web|gov|gob|gok|gon|gop|gos)\.pk
|
|
109
|
+
|(?:edu|gov|plo|sec)\.ps
|
|
110
|
+
|(?:com|edu|gov|int|net|nome|org|publ)\.pt
|
|
111
|
+
|(?:com|net|org|edu)\.py
|
|
112
|
+
|(?:com|net|org|edu|gov)\.qa
|
|
113
|
+
|(?:asso|com|nom)\.re
|
|
114
|
+
|(?:com|org|tm|nt|nom|info|rec|arts|firm|store|www)\.ro
|
|
115
|
+
|(?:ac|adygeya|altai|amur|amursk|arkhangelsk|astrakhan|baikal|bashkiria|belgorod|bir|bryansk|buryatia|cbg|chel|chelyabinsk|chita|chukotka|chuvashia|cmw|com|dagestan|dudinka|e-burg|edu|fareast|gov|grozny|int|irkutsk|ivanovo|izhevsk|jamal|jar|joshkar-ola|k-uralsk|kalmykia|kaluga|kamchatka|karelia|kazan|kchr|kemerovo|khabarovsk|khakassia|khv|kirov|kms|koenig|komi|kostroma|krasnoyarsk|kuban|kurgan|kursk|kustanai|kuzbass|lipetsk|magadan|magnitka|mari-el|mari|marine|mil|mordovia|mosreg|msk|murmansk|mytis|nakhodka|nalchik|net|nkz|nnov|norilsk|nov|novosibirsk|nsk|omsk|orenburg|org|oryol|oskol|palana|penza|perm|pp|pskov|ptz|pyatigorsk|rnd|rubtsovsk|ryazan|sakhalin|samara|saratov|simbirsk|smolensk|snz|spb|stavropol|stv|surgut|syzran|tambov|tatarstan|test|tom|tomsk|tsaritsyn|tsk|tula|tuva|tver|tyumen|udm|udmurtia|ulan-ude|vdonsk|vladikavkaz|vladimir|vladivostok|volgograd|vologda|voronezh|vrn|vyatka|yakutia|yamal|yaroslavl|yekaterinburg|yuzhno-sakhalinsk|zgrad)\.ru
|
|
116
|
+
|(?:com|edu|sch|med|gov|net|org|pub)\.sa
|
|
117
|
+
|(?:com|net|org|edu|gov)\.sb
|
|
118
|
+
|(?:com|net|org|edu|sch|med|gov)\.sd
|
|
119
|
+
|(?:tm|press|parti|brand|fh|fhsk|fhv|komforb|kommunalforbund|komvux|lanarb|lanbib|naturbruksgymn|sshn|org|pp)\.se
|
|
120
|
+
|(?:com|net|org|edu|gov|per)\.sg
|
|
121
|
+
|(?:com|net|org|edu|gov|mil)\.sh
|
|
122
|
+
|(?:gov|saotome|principe|consulado|embaixada|org|edu|net|com|store|mil|co)\.st
|
|
123
|
+
|(?:com|org|edu|gob|red)\.sv
|
|
124
|
+
|(?:com|net|org|gov)\.sy
|
|
125
|
+
|(?:ac|co|go|net|or)\.th
|
|
126
|
+
|(?:com|net|org|edunet|gov|ens|fin|nat|ind|info|intl|rnrt|rnu|rns|tourism)\.tn
|
|
127
|
+
|(?:com|net|org|edu|gov|mil|bbs|k12|gen)\.tr
|
|
128
|
+
|(?:co|com|org|net|biz|info|pro|int|coop|jobs|mobi|travel|museum|aero|name|gov|edu|nic|us|uk|ca|eu|es|fr|it|se|dk|be|de|at|au)\.tt
|
|
129
|
+
|(?:co)\.tv
|
|
130
|
+
|(?:com|net|org|edu|idv|gov)\.tw
|
|
131
|
+
|(?:com|gov|net|edu|org|in|cherkassy|ck|chernigov|cn|chernovtsy|cv|crimea|dnepropetrovsk|dp|donetsk|dn|ivano-frankivsk|if|kharkov|kh|kherson|ks|khmelnitskiy|km|kiev|kv|kirovograd|kr|lugansk|lg|lutsk|lviv|nikolaev|mk|odessa|od|poltava|pl|rovno|rv|sebastopol|sumy|ternopil|te|uzhgorod|vinnica|vn|zaporizhzhe|zp|zhitomir|zt)\.ua
|
|
132
|
+
|(?:ac|co|or|go)\.ug
|
|
133
|
+
|(?:co|me|org|edu|ltd|plc|net|sch|nic|ac|gov|nhs|police|mod)\.uk
|
|
134
|
+
|(?:dni|fed)\.us
|
|
135
|
+
|(?:com|edu|net|org|gub|mil)\.uy
|
|
136
|
+
|(?:com|net|org|co|edu|gov|mil|arts|bib|firm|info|int|nom|rec|store|tec|web)\.ve
|
|
137
|
+
|(?:co|net|org)\.vi
|
|
138
|
+
|(?:com|biz|edu|gov|net|org|int|ac|pro|info|health|name)\.vn
|
|
139
|
+
|(?:com|edu|net|org|de|ch|fr)\.vu
|
|
140
|
+
|(?:com|net|org|gov|edu)\.ws
|
|
141
|
+
|(?:ac|co|edu|org)\.yu
|
|
142
|
+
|(?:com|net|org|gov|edu|mil)\.ye
|
|
143
|
+
|(?:ac|alt|bourse|city|co|edu|gov|law|mil|net|ngo|nom|org|school|tm|web)\.za
|
|
144
|
+
|(?:co|ac|org|gov)\.zw
|
|
145
|
+
|(?:eu)\.org
|
|
146
|
+
|(?:au|br|cn|de)\.com
|
|
147
|
+
|(?:de)\.net
|
|
148
|
+
|(?:eu|gb)\.com
|
|
149
|
+
|(?:gb)\.net
|
|
150
|
+
|(?:hu|no|qc|ru|sa|se|uk)\.com
|
|
151
|
+
|(?:uk)\.net
|
|
152
|
+
|(?:us|uy|za)\.com
|
|
153
|
+
|(?:dk)\.org
|
|
154
|
+
|(?:tel)\.no
|
|
155
|
+
|(?:fax|mob|mobil|mobile|tel|tlf)\.nr
|
|
156
|
+
|(?:e164)\.arpa)$
|
|
157
|
+
|(?:surbl)\.org}ix
|
|
158
|
+
|
|
159
|
+
def initialize
|
|
160
|
+
@cache = [nil, nil]
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
private
|
|
164
|
+
def _get_base_domain(domain)
|
|
165
|
+
# Remove userinfo
|
|
166
|
+
if domain.include? "@" then
|
|
167
|
+
domain = domain[domain.index("@") + 1, domain.length]
|
|
168
|
+
end
|
|
169
|
+
# Remove port
|
|
170
|
+
if domain.include? ":" then
|
|
171
|
+
domain = domain[0, domain.index(":")]
|
|
172
|
+
end
|
|
173
|
+
# Choose the right "depth"...
|
|
174
|
+
if @@two_level_tlds =~ domain then
|
|
175
|
+
n = 3
|
|
176
|
+
else
|
|
177
|
+
n = 2
|
|
178
|
+
end
|
|
179
|
+
split_domain = domain.split(".")
|
|
180
|
+
return split_domain[-n, split_domain.length].join(".")
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Like 'lookup', but checks the exact domain name given.
|
|
184
|
+
# Not for direct use.
|
|
185
|
+
def _lookup_exact(domain)
|
|
186
|
+
cached_domain = nil
|
|
187
|
+
flags = @cache
|
|
188
|
+
if cached_domain != domain then
|
|
189
|
+
begin
|
|
190
|
+
ip = Resolv.getaddress(domain + ".multi.surbl.org")
|
|
191
|
+
flags = ip.split(".")[-1].to_i
|
|
192
|
+
rescue Resolv::ResolvError => e
|
|
193
|
+
if e.message == "no address for #{domain}" then
|
|
194
|
+
# No record found
|
|
195
|
+
flags = nil
|
|
196
|
+
@cache = [domain, flags]
|
|
197
|
+
return False
|
|
198
|
+
else
|
|
199
|
+
# Unhandled error, pass test for now
|
|
200
|
+
return nil
|
|
201
|
+
end
|
|
202
|
+
rescue
|
|
203
|
+
# Not sure if this can happen. Timeouts?
|
|
204
|
+
return nil
|
|
205
|
+
end
|
|
206
|
+
@cache = [domain, flags]
|
|
207
|
+
end
|
|
208
|
+
if flags then
|
|
209
|
+
matches = []
|
|
210
|
+
@@flags.each do |n,s|
|
|
211
|
+
matches.push(s) if flags & n != 0
|
|
212
|
+
end
|
|
213
|
+
return [domain, matches]
|
|
214
|
+
else
|
|
215
|
+
return False
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
public
|
|
220
|
+
# Extract base domain and check it against SURBL.
|
|
221
|
+
# Return [basedomain, lists] array, where basedomain is the
|
|
222
|
+
# base domain and lists is a list of strings indicating which
|
|
223
|
+
# blacklists the domain was found in.
|
|
224
|
+
# If there was no match, return false.
|
|
225
|
+
# If unsure (temporary error), return nil.
|
|
226
|
+
def lookup(domain)
|
|
227
|
+
domain = _get_base_domain(domain)
|
|
228
|
+
return _lookup_exact(domain)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Return true if base domain is listed in SURBL.
|
|
232
|
+
# Returns false otherwise.
|
|
233
|
+
def include?(domain)
|
|
234
|
+
return lookup(domain) != nil
|
|
235
|
+
end
|
|
236
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require_relative "../lib/surbl_client"
|
|
2
|
+
require "test/unit"
|
|
3
|
+
|
|
4
|
+
class TestSurblClient < Test::Unit::TestCase
|
|
5
|
+
def testPass
|
|
6
|
+
surbl = SurblClient.new()
|
|
7
|
+
domains = ["google.com", "yahoo.com", "apple.com"]
|
|
8
|
+
domains.each do |domain|
|
|
9
|
+
assert_equal(false, surbl.include?(domain))
|
|
10
|
+
assert_nil(surbl.lookup(domain))
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def testSurblTestPoints
|
|
15
|
+
surbl = SurblClient.new()
|
|
16
|
+
domains = ["test.surbl.org", "surbl-org-permanent-test-point.com"]
|
|
17
|
+
all = ['sc', 'ws', 'ph', 'ob', 'ab', 'jp']
|
|
18
|
+
domains.each do |domain|
|
|
19
|
+
subdomain = "foo.bar.baz.#{domain}"
|
|
20
|
+
assert_equal(true, surbl.include?(domain))
|
|
21
|
+
assert_equal(surbl.lookup(domain), [domain, all])
|
|
22
|
+
assert_equal(true, surbl.include?(subdomain))
|
|
23
|
+
assert_equal(surbl.lookup(subdomain), [domain, all])
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: surbl_client
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: '0.1'
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- George Perry
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-09-21 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: A gem to check whether or not a domain has been blacklisted by SURBL
|
|
14
|
+
email: perrygeorget.public@gmail.com
|
|
15
|
+
executables: []
|
|
16
|
+
extensions: []
|
|
17
|
+
extra_rdoc_files: []
|
|
18
|
+
files:
|
|
19
|
+
- lib/surbl_client.rb
|
|
20
|
+
- test/tc_surbl_client.rb
|
|
21
|
+
homepage: https://github.com/perrygeorget/surbl_client
|
|
22
|
+
licenses:
|
|
23
|
+
- MIT
|
|
24
|
+
metadata: {}
|
|
25
|
+
post_install_message:
|
|
26
|
+
rdoc_options: []
|
|
27
|
+
require_paths:
|
|
28
|
+
- lib
|
|
29
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '0'
|
|
39
|
+
requirements: []
|
|
40
|
+
rubyforge_project:
|
|
41
|
+
rubygems_version: 2.5.1
|
|
42
|
+
signing_key:
|
|
43
|
+
specification_version: 4
|
|
44
|
+
summary: SURBL checker (http://www.surbl.org/)
|
|
45
|
+
test_files: []
|