universal_ruby_whois 1.2.9

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ == 1/17/13
2
+ * Update TLD output parsing rules by Vasily Shmelev
3
+ * Know issue: creation date won't return for some TLDs
4
+
5
+ == 7/24/09
6
+ * Added support for .br domain names by Ruy Rocha
7
+
8
+ == 2/17/09
9
+ * Included enhancements for .co.nz domains as provided by Matt Thompson
10
+
11
+ == 12/1/08
12
+ * Included atourino's fix for .mobi domains.
13
+ * Updated Rakefile to publish to RubyForge.
14
+
15
+ == 11/10/08
16
+ * Support for expiration date parsing added as requested by Jorge Yau.
17
+ * Renamed "created_date" to "creation_date" for consistency.
18
+ * Moved supporting libraries into a support folder.
19
+ * Added support for .jp and .co.jp etc. domain names.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2008 Matt Lightner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+
data/README.rdoc ADDED
@@ -0,0 +1,91 @@
1
+
2
+ === Rest In Peace Matt Lightner
3
+
4
+
5
+
6
+ = Universal Whois Server
7
+
8
+ *Author*: Matt Lightner <mailto:mlightner@gmail.com>
9
+
10
+ *License*: MIT[link:files/LICENSE.html]
11
+
12
+ *RDoc*: http://universalwhois.rubyforge.org
13
+
14
+ *RubyForge URL*: http://rubyforge.org/projects/universalwhois
15
+
16
+ *GitHub URL*: http://github.com/mlightner/universal_ruby_whois/tree/master
17
+
18
+
19
+ This library attempts to interpret WHOIS output from a variety of different registrars.
20
+ The ultimate goal is to have a complete "dictionary" of all of the TLD registrars (including
21
+ double domain TLDs such as .co.uk) on the Internet, and corresponding regular expressions
22
+ to parse the unique output format for each one.
23
+
24
+ This package requires a command line whois utility to retrieve output. It will then attempt
25
+ to interpret that output based on a series of regular expressions.
26
+
27
+
28
+ === DEFINING WHOIS SERVERS
29
+
30
+ Whois servers can be defined on a per-TLD basis, so each registrar can have a unique set
31
+ of regular expressions to match its particular output format. Whois servers are defined in the
32
+ file server_list.rb.
33
+
34
+ If you're using this module and come across a TLD that isn't yet supported or isn't working
35
+ quite right, I highly encourage you to fork the project and commit your updates. The more
36
+ people we have working on the list, the more comprehensive and effective it becomes!
37
+
38
+
39
+ === TLD SEARCH PRIORITY
40
+
41
+ When deciding which whois server to use, the script will always choose the most specific
42
+ server entry it can find. For instance, if you have defined a server for .uk domains,
43
+ but also a server for .co.uk domains, the domain name "test.co.uk" will always use the
44
+ latter whois server.
45
+
46
+
47
+ === EXAMPLE USAGE
48
+
49
+ Here is the output from a sample IRB session using this library:
50
+
51
+ require 'universal_ruby_whois'
52
+ => true
53
+ domain = Whois.find("mattlightner.com")
54
+ => #<Whois::Domain:0xb7a3b014 @domain="mattlightner.com", @server_tld_key="com">
55
+ domain.status
56
+ => :registered
57
+ domain.available?
58
+ => false
59
+ domain.registered?
60
+ => true
61
+ domain.creation_date
62
+ => Mon Aug 28 00:00:00 EDT 2006
63
+ domain.expiration_date
64
+ => Fri Aug 28 00:00:00 EDT 2009
65
+ domain = Whois.find("9384jf398ejf9832ej.com")
66
+ => #<Whois::Domain:0xb7a1ab34 @domain="9384jf398ejf9832ej.com", @server_tld_key="com">
67
+ domain.status
68
+ => :free
69
+
70
+
71
+ === NOTES
72
+
73
+ Some registrars are relatively unreliable or may add a server to a blacklist after a certain number of
74
+ queries. In particular, the registrars for these domains:
75
+
76
+ - es and related TLDs: They only provide an HTTP whois access interface, which is unreliable at
77
+ best (although this module supports HTTP lookups quite well).
78
+ - asn.au com.au id.au net.au org.au: 'whois.aunic.net', seems as though they will blacklist a server
79
+ making too many queries. Not sure about their blacklist removal policy.
80
+
81
+
82
+ === TODO
83
+
84
+ - Add better support for creation date parsing for major registrars.
85
+ - Find a more reliable way to look up domains from registrars not providing a whois server.
86
+
87
+
88
+ === CONTRIBUTIONS
89
+
90
+ Contribution is encouraged! Grab the source from: git://github.com/mlightner/universal_ruby_whois.git
91
+
@@ -0,0 +1,94 @@
1
+ module Whois
2
+
3
+ module ExtendedRegexp #:nodoc:
4
+
5
+ def self.included(base) #:nodoc:
6
+ base.send(:include, Whois::ExtendedRegexp::InstanceMethods)
7
+ end
8
+
9
+ # Extensions for Ruby's core Regexp class.
10
+ module InstanceMethods
11
+
12
+ # Find and replace literal values in a regular expression source string. You pass it a Hash
13
+ # where the keys are either strings or regular expressions to search for, and their values are
14
+ # the replacement values. A completely new Regexp object is returned and options are preserved.
15
+ #
16
+ # /a __REPLACE___ day/i.interpolate("__REPLACE__" => "fun") => /a fun day/i
17
+ #
18
+ def interpolate(*args)
19
+ if args.length > 1
20
+ replacements = Hash[*args]
21
+ elsif args.first.kind_of?(Hash)
22
+ replacements = args.first
23
+ else
24
+ raise ArgumentError, "Must pass hash to interpolate."
25
+ end
26
+
27
+ string = self.source
28
+
29
+ replacements.each do |key, value|
30
+ if key.kind_of?(Regexp)
31
+ string.gsub!(key, value.to_s)
32
+ else
33
+ string.gsub!(/#{self.class.escape(key)}/im, value.to_s)
34
+ end
35
+ end
36
+
37
+ string = (self.source.to_s).interpolate(*args)
38
+ self.class.new(string, self.options)
39
+ end
40
+
41
+ # Make a copy of the current regular expression object but with new options. Options are given
42
+ # as a string, like so:
43
+ #
44
+ # /testing/i.new_options('im') => /testing/im
45
+ def new_options(option_string)
46
+ options_list = []
47
+ { :i => Regexp::IGNORECASE,
48
+ :x => Regexp::EXTENDED,
49
+ :m => Regexp::MULTILINE }.each_pair do |charcode, constant|
50
+ options_list.push(constant) if option_string =~ /#{charcode.to_s}/i
51
+ end
52
+
53
+ self.class.new(self.source, options_list)
54
+ end
55
+
56
+
57
+ # === Inverted Regular Expressions
58
+ #
59
+ # Gives the ability to invert a regular expression so that running a match against it
60
+ # will yield a true result when it does NOT match the target string.
61
+ #
62
+ # Invert this regular expression.
63
+ def invert!
64
+ @inverted = true
65
+ self
66
+ end
67
+
68
+ # Uninvert this regular expression.
69
+ def uninvert!
70
+ @inverted = false
71
+ self
72
+ end
73
+
74
+ def set_inverted(value = true)
75
+ @inverted = (value) ? true : false
76
+ end
77
+
78
+ # Is this an inverted regular expression?
79
+ def inverted?
80
+ @inverted rescue false
81
+ end
82
+
83
+ # Run an inversion-aware match using this Regexp.
84
+ def match_with_inversion(*args, &block)
85
+ result = self.match(*args, &block)
86
+ if @inverted
87
+ result.nil? ? true : false
88
+ else
89
+ result
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,22 @@
1
+ class String #:nodoc:
2
+ def interpolate(*args)
3
+ if args.length > 1
4
+ replacements = Hash[*args]
5
+ elsif args.first.kind_of?(Hash)
6
+ replacements = args.first
7
+ else
8
+ raise ArgumentError, "Must pass hash to interpolate."
9
+ end
10
+
11
+ string = self.dup
12
+ replacements.each do |key, value|
13
+ if key.kind_of?(Regexp)
14
+ string.gsub!(key, value.to_s)
15
+ else
16
+ string.gsub!(/#{key}/i, value.to_s)
17
+ end
18
+ end
19
+
20
+ string
21
+ end
22
+ end
@@ -0,0 +1,145 @@
1
+ require File.dirname(__FILE__) + '/server'
2
+ require 'time'
3
+
4
+ module Whois
5
+
6
+ class Domain
7
+
8
+ # The domain name, lower case, no spaces.
9
+ attr_reader :domain
10
+
11
+ # The TLD server being used for this domain.
12
+ attr_reader :server_tld_key
13
+
14
+ # The cached output from a whois request for this domain.
15
+ attr_reader :whois_output
16
+
17
+ # Look up a domain name. If a proper whois server can not be found for this domain name's extension,
18
+ # it will return nil. Otherwise it returns a Whois::Domain object.
19
+ #
20
+ # Note: the preferred way to call this method is through the wrapper:
21
+ #
22
+ # Whois.find(domain)
23
+ def self.find(domain)
24
+ ::Whois::Server.find(domain)
25
+ end
26
+
27
+ def initialize(domain, server_tld_key = nil) #:nodoc:
28
+ @domain, @server_tld_key = domain.to_s.strip.downcase, server_tld_key
29
+ end
30
+
31
+ # Returns the Whois::Server object for this domain name.
32
+ def server
33
+ Whois::Server.list[@server_tld_key] rescue nil
34
+ end
35
+
36
+ # The set of regular expressions that will be used in matching this domain's whois output.
37
+ def regexes
38
+ server.regexes rescue {}
39
+ end
40
+
41
+ # Does this object have a domain name set?
42
+ def has_domain?
43
+ return false if domain.nil?
44
+ (domain.to_s =~ /\w/) ? true : false
45
+ end
46
+
47
+ # Does this domain have a server which is available?
48
+ def has_available_server?
49
+ server && !(server.unavailable? rescue true)
50
+ end
51
+
52
+ # Does this domain have sufficient info to perform a lookup?
53
+ def has_domain_and_server?
54
+ has_domain? && has_available_server?
55
+ end
56
+ alias_method :valid?, :has_domain_and_server?
57
+
58
+ # The raw whois server output obtained when looking up this domain.
59
+ def whois_output
60
+ return @whois_output if !@whois_output.blank?
61
+ @whois_output = has_domain_and_server? ? server.raw_response!(domain) : ''
62
+ end
63
+
64
+ # The domain name's current registration status:
65
+ # <tt>:registered</tt> The domain name is registered.
66
+ # <tt>:free</tt> The domain name is not registered (available).
67
+ # <tt>:error</tt> There was an error looking up the domain name.
68
+ # <tt>:unknown</tt> The domain name status could not be determined.
69
+ def status
70
+ return :unknown unless has_domain_and_server?
71
+ return @status unless @status.blank?
72
+ [ :registered, :free, :error ].each do |status|
73
+ #return status if Regexp.new(regexes[status].source, 5).match(res)
74
+ return(@status = status) if regexes[status].match_with_inversion(whois_output)
75
+ end
76
+ return @status = :unknown
77
+ end
78
+
79
+ # Is this domain available? Returns true/false.
80
+ def available?
81
+ return nil unless has_domain_and_server?
82
+ status == :free
83
+ end
84
+
85
+ # Is this domain name registered? Returns true/false.
86
+ def registered?
87
+ return nil unless has_domain_and_server?
88
+ status == :registered
89
+ end
90
+
91
+ # Returns a Time object representing the date this domain name was created.
92
+ def creation_date
93
+ return nil unless has_domain_and_server?
94
+ return @creation_date unless @creation_date.blank?
95
+ if regexes[:creation_date] && (regexes[:creation_date] =~ whois_output)
96
+ @creation_date = (Time.local(*ParseDate.parsedate($2)) rescue nil)
97
+ end
98
+ @creation_date
99
+ end
100
+
101
+ # Depreciated. Use creation_date instead.
102
+ alias_method :created_date, :creation_date
103
+
104
+ # Do we know the creation date for this domain?
105
+ def creation_date_known?
106
+ creation_date.kind_of?(Time)
107
+ end
108
+
109
+
110
+ # Returns a Time object representing the date this domain name is set to expire.
111
+ def expiration_date
112
+ return nil unless has_domain_and_server?
113
+ return @expiration_date unless @expiration_date.blank?
114
+ if regexes[:expiration_date] && (regexes[:expiration_date] =~ whois_output)
115
+ @expiration_date = (Time.local(*ParseDate.parsedate($2)) rescue nil)
116
+ end
117
+ @expiration_date
118
+ end
119
+
120
+ # Do we know the expiration date for this domain?
121
+ def expiration_date_known?
122
+ expiration_date.kind_of?(Time)
123
+ end
124
+
125
+ def to_s
126
+ domain.to_s rescue nil
127
+ end
128
+ def to_hash
129
+ {
130
+ :status => self.status,
131
+ :creation_date => self.creation_date,
132
+ :expiration_date => self.expiration_date,
133
+ :output => self.whois_output
134
+ }
135
+ end
136
+ def to_json
137
+ self.to_hash.to_json
138
+ end
139
+ def to_xml
140
+ self.to_hash.to_xml
141
+ end
142
+ end
143
+
144
+ end
145
+
@@ -0,0 +1,245 @@
1
+ module Whois
2
+
3
+ # = Whois::Server
4
+ #
5
+ # A Whois server object represents a single TLD mapped to a whois server hostname, and a set of regular expressions
6
+ # that are used to match against the raw whois output and determine various information about the domain name (currently
7
+ # registration status is supported on most domain TLDs, and creation date on a good number).
8
+ class Server
9
+
10
+ # Exception class thrown when a WHOIS server is down or unavailable.
11
+ class Unavailable < StandardError
12
+ end
13
+
14
+ # The default regular expressions used when defining a new server if none are supplied.
15
+ DEFAULT_WHOIS_REGULAR_EXPRESSIONS = {
16
+ :free => /(avail|free|no match|no entr|not taken|Available|Status\:\sNot\sRegistered|not registered|not found|No match for domain)/im,
17
+ :registered => /(registered|Domain ID|domain name\s*\:|is active|Status\:\sActive|Not available|is not available|exists|\bregistrant\b|Created on|created\:)/im,
18
+ :creation_date => /(Creation date|created on|created at|Commencement Date|Registration Date|domain_dateregistered|created\:)\s*[\:\.\]]*\s*([\w\-\:\ \/]+)[^\n\r]*[\n\r]/im,
19
+ :expiration_date => /(expiration date|expires on|registered through|Renewal date|domain_datebilleduntil|expires\:)\s*[\:\.\]]*\s*([\w\-\:\ \/]+)[^\n\r]*[\n\r]/im,
20
+ :error => /(error)/im,
21
+ :server_unavailable => /(Sorry\. Server busy\.|too many requests|been blocked)/im
22
+ }
23
+
24
+ # The location of the 'whois' binary utility.
25
+ WHOIS_BIN = '/usr/bin/env whois'
26
+
27
+ attr_reader :tld, :nic_server, :regexes, :port, :server_unavailable, :unavailable_response
28
+
29
+ # === Whois Server Definition
30
+ #
31
+ # Define a whois server for one or more TLDs. TLDs can be given as a single string or an array of strings representing
32
+ # TLDs that are handled by this server. The second argument should be a whois server hostname. If none is given,
33
+ # the generic output from the command line whois program is used (with any available redirection). An optional third
34
+ # argument is an array of regular expressions used to parse output from this particular server. A set of relatively
35
+ # liberal defaults is used if none (or only some) are given. Supported regex keys are :free, :registered, :creation_date
36
+ # and :error.
37
+ #
38
+ # ==== Regex Options
39
+ # * <tt>:registered</tt> -- If this regular expression matches the whois output, this domain is considered registered.
40
+ # * <tt>:free</tt> -- If this regular expression matches the whois output, the domain is considered available.
41
+ # * <tt>:error</tt> -- If this regular expression matches, an error is said to have occurred.
42
+ # * <tt>:creation_date</tt> -- If this regular expression matches, the value of the second set of parentheses is parsed
43
+ # using ParseDate and used as the creation date for this domain.
44
+ #
45
+ # Note, the preferred location for Whois::Server definitions is the server_list.rb file. Definitions should go from
46
+ # least specific to most specific, as subsequent definitions for a TLD will override previous ones.
47
+ def self.define(tlds, server = nil, regexes = nil, &block)
48
+ tlds = tlds.kind_of?(Array) ? tlds : [tlds]
49
+ tlds.each do |tld|
50
+ define_single(tld, server, regexes, &block)
51
+ end
52
+ tlds
53
+ end
54
+
55
+ def initialize(tld, nic_server = nil, options = nil) #:nodoc:
56
+ @tld = tld.gsub(/^\.+/, '')
57
+ options ||= Hash.new
58
+ @response_cache = Hash.new("")
59
+ @nic_server = nic_server
60
+ @port = options.delete(:port)
61
+ @regexes = options.reverse_merge(DEFAULT_WHOIS_REGULAR_EXPRESSIONS)
62
+ @regexes.each do |key, rx|
63
+ next unless rx.kind_of?(Array)
64
+ rx2 = Regexp.new(Regexp.escape(rx.first).gsub(/\s+/, '\s*'))
65
+ rx2 = rx2.new_options(rx[1])
66
+ rx2 = rx2.interpolate(/\s+/, '\s+')
67
+ rx2.invert! if ((rx[2] == true) rescue false)
68
+ @regexes[key] = rx2
69
+ end
70
+ end
71
+
72
+ # A hash of all of the known whois servers indexed by TLD
73
+ def self.list
74
+ @@list ||= Hash.new
75
+ end
76
+
77
+ def self.list=(value)
78
+ @@list = value
79
+ end
80
+
81
+ def self.domain_object_cache #:nodoc:
82
+ @@domain_object_cache ||= Hash.new
83
+ end
84
+
85
+ def self.domain_object_cache=(value) #:nodoc:
86
+ @@domain_object_cache = value
87
+ end
88
+
89
+ # A list of strings representing all supported TLDs.
90
+ def self.defined_tlds
91
+ self.list.collect {|tld,server| tld.gsub(/^\./, '') }
92
+ end
93
+
94
+ # Find a TLD from a full domain name. There is special care to check for two part TLDs
95
+ # (such as .co.uk, .kids.us, etc) first and then to look for the last part alone.
96
+ def self.find_server_from_domain(domain)
97
+ # valid domain?
98
+ return nil unless domain =~ /^((?:[-a-zA-Z0-9]+\.)+[a-zA-Z]{2,})$/
99
+
100
+ # start the searching.
101
+ tld = nil
102
+ parts = domain.split('.')
103
+
104
+ # if the passed domain is more than two parts (. separated strings)
105
+ # try to find the TLD from the last two parts (ie, .co.uk)
106
+ if parts.size > 2
107
+ tld_string = parts[-2,2].join('.')
108
+ tld = self.list[tld_string]
109
+ end
110
+
111
+ # if nothing was found, check for a match on the last part only.
112
+ if tld.blank?
113
+ tld_string = parts.last
114
+ tld = self.list[tld_string]
115
+ end
116
+
117
+ return nil if !tld.kind_of?(Whois::Server)
118
+ return tld
119
+ end
120
+
121
+ # Look up a domain name. If a proper whois server can not be found for this domain name's extension,
122
+ # it will return nil. Otherwise it returns a Whois::Domain object.
123
+ #
124
+ # Note: the preferred way to call this method is through the wrapper:
125
+ #
126
+ # Whois.find(domain)
127
+ def self.find(domain)
128
+ domain = domain.to_s.strip.downcase
129
+ return domain_object_cache[domain] unless domain_object_cache[domain].blank?
130
+ return nil unless server = server_for_domain(domain)
131
+ domain_object_cache[domain] = Whois::Domain.new(domain, server.tld)
132
+ end
133
+
134
+ # Determine the appropriate whois server object for a domain name.
135
+ def self.server_for_domain(domain)
136
+ server = self.find_server_from_domain(domain)
137
+ # This will only work on single extension domains
138
+ if server.blank? # && domain.scan(/(\.)/).length == 1
139
+ domain =~ /\.([\w\-]+)$/
140
+ tld = $1
141
+ self.define_from_iana(tld)
142
+ return false unless server = self.find_server_from_domain(domain)
143
+ end
144
+ server
145
+ end
146
+
147
+ def unavailable?
148
+ @server_unavailable ? true : false
149
+ end
150
+
151
+ # Retrieve the raw WHOIS server output for a domain.
152
+ def raw_response(domain)
153
+ return nil if unavailable?
154
+ return @response_cache[domain] if !@response_cache[domain].blank?
155
+ @response_cache[domain] = ""
156
+ if nic_server.kind_of?(Array)
157
+ interpolate_vars = {
158
+ '%DOMAIN%' => domain,
159
+ '%DOMAIN_NO_TLD%' => domain.gsub(/\.#{tld.to_s}$/i, ''),
160
+ '%TLD%' => tld
161
+ }
162
+
163
+ url = URI.parse(nic_server.first.dup.interpolate(interpolate_vars))
164
+ method = nic_server[1] || :post
165
+ req = "Net::HTTP::#{method.to_s.capitalize}".constantize.new(url.path)
166
+ form_data = nic_server[2].dup || {}
167
+ form_data.each { |k,v| form_data[k] = v.interpolate(interpolate_vars) }
168
+ req.set_form_data(form_data)
169
+ res = begin
170
+ Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
171
+ rescue Net::HTTPBadResponse
172
+ nil # Ignore these for now...
173
+ end
174
+ @response_cache[domain] = case res
175
+ when Net::HTTPSuccess, Net::HTTPRedirection
176
+ res.body
177
+ else
178
+ ''
179
+ end
180
+ elsif nic_server.to_s =~ /^http/
181
+ url = nic_server.gsub(/\%DOMAIN\%/, domain)
182
+ @response_cache[domain] = Net::HTTP.get_response(URI.parse(url)).body
183
+ else
184
+ command = "#{WHOIS_BIN} #{('-h ' + @nic_server) unless @nic_server.blank?} #{self.class.shell_escape(domain)} 2>&1"
185
+ @response_cache[domain] = Whois::Server.run_command_with_timeout(command, 10, true)
186
+ end
187
+ if match = regexes[:server_unavailable].match_with_inversion(@response_cache[domain])
188
+ @server_unavailable = true
189
+ @unavailable_response = match[1]
190
+ nil
191
+ else
192
+ @response_cache[domain]
193
+ end
194
+ end
195
+
196
+ def raw_response!(domain)
197
+ res = raw_response(domain)
198
+ if !res || !res.respond_to?(:to_s) || res.blank?
199
+ raise Whois::Server::Unavailable, "The WHOIS server for TLD #{tld.to_s} is currently unavailable. (response: #{unavailable_response})"
200
+ end
201
+ res
202
+ end
203
+
204
+ # Used as a fallback in case no specific WHOIS server is defined for a given TLD. An attempt will be made to search
205
+ # the IANA global registrar database to find a suitable whois server.
206
+ def self.define_from_iana(tld)
207
+ iana_out = run_command_with_timeout("#{WHOIS_BIN} -h whois.iana.org #{shell_escape(tld.to_s)} 2>&1", 10, false)
208
+ return false if iana_out.blank?
209
+ return false unless iana_out =~ /Whois\s+Server\s+\(port ([\d]+)\)\: ([\w\-\.\_]+)/im
210
+ port = $1
211
+ server = $2
212
+ define_single(tld.to_s, server, :port => port)
213
+ end
214
+
215
+ def self.define_single(*args, &block) #:nodoc:
216
+ new_server = allocate
217
+ new_server.send(:initialize, *args, &block)
218
+ list[args.first.to_s] = new_server
219
+ new_server
220
+ end
221
+
222
+ def self.run_command_with_timeout(command, timeout = 10, do_raise = false) #:nodoc:
223
+ @output = ""
224
+ begin
225
+ status = Timeout::timeout(10) do
226
+ IO.popen(command, "r") do |io|
227
+ @output << "#{io.read.to_s}"
228
+ end
229
+ end
230
+ rescue Exception => e
231
+ if do_raise
232
+ raise "Running command \"#{command}\" timed out."
233
+ end
234
+ end
235
+ @output.strip!
236
+ @output
237
+ end
238
+
239
+ def self.shell_escape(word) #:nodoc:
240
+ word.to_s.gsub(/[^\w\-\_\.]+/, '') rescue ''
241
+ end
242
+
243
+ end
244
+
245
+ end
@@ -0,0 +1,327 @@
1
+ # Define whois servers and their corresponding output format in this file.
2
+ # If no regular expressions are given to match states, some reasonable
3
+ # defaults will be used, but more specific is always better :)
4
+
5
+ # More generic definitions should appear first, as the more specific definitions
6
+ # will overwrite them in the extension dictionary if they appear later in the file.
7
+
8
+ Whois::Server.define('ae', 'whois.uaenic.ae')
9
+ Whois::Server.define('ai', 'whois.ainic.ai')
10
+ Whois::Server.define('as', 'whois.nic.as')
11
+ Whois::Server.define('at', 'whois.nic.at')
12
+ Whois::Server.define('bg', 'whois.digsys.bg')
13
+ Whois::Server.define('bi', 'whois.nic.bi')
14
+ Whois::Server.define('bj', 'www.nic.bj')
15
+ Whois::Server.define('br', 'whois.nic.br')
16
+ Whois::Server.define('bz', 'whois.belizenic.bz')
17
+ Whois::Server.define('cc', 'whois.nic.cc')
18
+ Whois::Server.define('cd', 'whois.nic.cd')
19
+ Whois::Server.define('ck', 'whois.nic.ckcn')
20
+ Whois::Server.define('de', 'whois.denic.de')
21
+ Whois::Server.define('fo', 'whois.ripe.net')
22
+ Whois::Server.define('gg', 'whois.isles.net')
23
+ Whois::Server.define('gl', 'whois.ripe.net')
24
+ Whois::Server.define('gm', 'whois.ripe.net')
25
+ Whois::Server.define('gr', 'whois.grnet.gr')
26
+ Whois::Server.define('gs', 'whois.gs')
27
+ Whois::Server.define('hm', 'webhst1.capital.hm')
28
+ Whois::Server.define('hu', 'whois.nic.hu')
29
+ Whois::Server.define('id', 'whois.idnic.net.id')
30
+ Whois::Server.define('in', 'whois.inregistry.net')
31
+ Whois::Server.define('io', 'whois.nic.io')
32
+ Whois::Server.define('ir', 'whois.nic.ir')
33
+ Whois::Server.define('kz', 'whois.nic.kz')
34
+ Whois::Server.define('la', 'whois2.afilias-grs.net')
35
+ Whois::Server.define('ly', 'whois.lydomains.com')
36
+ Whois::Server.define('mc', 'whois.ripe.net')
37
+ Whois::Server.define('ms', 'whois.nic.ms')
38
+ Whois::Server.define('mx', 'whois.nic.mx')
39
+ Whois::Server.define('my', 'whois.mynic.net.my')
40
+ Whois::Server.define('pl', 'whois.dns.pl')
41
+ Whois::Server.define('pm', 'whois.nic.pm')
42
+ Whois::Server.define('pro', 'whois.registrypro.pro')
43
+ Whois::Server.define('pt', 'whois.nic.pt')
44
+ Whois::Server.define('sa', 'saudinic.net.sa')
45
+ Whois::Server.define('sb', 'whois.nic.net.sb')
46
+ Whois::Server.define('sh', 'whois.nic.sh')
47
+ Whois::Server.define('si', 'whois.arnes.si')
48
+ Whois::Server.define('sk', 'whois.sk-nic.sk')
49
+ Whois::Server.define('sm', 'whois.ripe.net')
50
+ Whois::Server.define('st', 'whois.nic.st')
51
+ Whois::Server.define('su', 'whois.ripn.net')
52
+ Whois::Server.define('th', 'whois.thnic.net')
53
+ Whois::Server.define('to', 'whois.tonic.to')
54
+ Whois::Server.define('uy', 'www.nic.org.uy')
55
+ Whois::Server.define('uz', 'whois.cctld.uz')
56
+ Whois::Server.define('va', 'whois.ripe.net')
57
+ Whois::Server.define('ve', 'whois.nic.ve')
58
+ Whois::Server.define('vg', 'whois.vg')
59
+ Whois::Server.define('wf', 'whois.nic.wf')
60
+ Whois::Server.define('ws', 'whois.tld.ws')
61
+ Whois::Server.define('yt', 'whois.nic.yt')
62
+ Whois::Server.define('us', 'whois.nic.us')
63
+ Whois::Server.define('at', 'whois.nic.at')
64
+ Whois::Server.define('ca', 'whois.cira.ca')
65
+ Whois::Server.define('cc', 'whois.nic.cc')
66
+ Whois::Server.define('ch', 'whois.nic.ch')
67
+ Whois::Server.define('cn', 'whois.cnnic.net.cn')
68
+ Whois::Server.define('cz', 'whois.nic.cz')
69
+ Whois::Server.define('ee', 'whois.eenet.ee')
70
+ Whois::Server.define('gr', 'https://grweb.ics.forth.gr/')
71
+ Whois::Server.define('it', 'whois.nic.it')
72
+ Whois::Server.define('li', 'whois.nic.li')
73
+ Whois::Server.define('lt', 'whois.domreg.lt')
74
+ Whois::Server.define('lu', 'whois.dns.lu')
75
+ Whois::Server.define('lv', 'whois.ripe.net')
76
+ Whois::Server.define('co.nz', 'whois.domainz.net.nz')
77
+ Whois::Server.define('nu', 'whois.nic.nu')
78
+ Whois::Server.define('pl', 'whois.dns.pl')
79
+ Whois::Server.define('ro', 'whois.rotld.ro')
80
+ Whois::Server.define('ru', 'whois.ripn.net')
81
+ Whois::Server.define('se', 'whois.iis.se')
82
+ Whois::Server.define('sk', 'whois.ripe.net')
83
+ Whois::Server.define('ws', 'whois.worldsite.ws')
84
+
85
+ #Whois::Server.define('es',"https://www.nic.es/esnic/servlet/BuscarDomSolAlta?dominio=%DOMAIN%")
86
+ #Whois::Server.define('com.es',"https://www.nic.es/esnic/servlet/BuscarDomSolAlta?dominio=%DOMAIN%")
87
+
88
+ Whois::Server.define(
89
+ 'tv',
90
+ 'tvwhois.verisign-grs.com',
91
+ :registered => /Domain ID/im,
92
+ :free => /No match for/im,
93
+ :creation_date => /Creation Date/im,
94
+ :expiration_date => /Expiration Date/im
95
+ )
96
+
97
+
98
+ Whois::Server.define(
99
+ %w(gd tc vg ms),
100
+ 'whois.adamsnames.tc',
101
+ :registered => /domain name\:/im,
102
+ :free => /not found/im
103
+ )
104
+
105
+ Whois::Server.define(
106
+ %w(jp co.jp or.jp ne.jp ac.jp ad.jp ed.jp go.jp gr.jp lg.jp),
107
+ 'whois.jprs.jp',
108
+ # ['http://whois.jprs.jp/en/', :post, { :submit => 'query', :key => '%DOMAIN%', :type => 'DOM'}],
109
+ :registered => /Domain Information\:/im,
110
+ :free => /No match\!\!/im
111
+ )
112
+
113
+ Whois::Server.define(
114
+ %w(es com.es nom.es org.es gob.es edu.es),
115
+ ['https://www.nic.es/esnic/servlet/BuscarDomSolAlta', :post, { :Submit => 'Buscar', :domino => '%DOMAIN_NO_TLD%',
116
+ :sufijo => '%TLD%', :tipo => 'dominio'}],
117
+ :registered => [%q{%DOMAIN% </a> </th> <td class="disp"> <img src="../images/icon_disp_no.gif" alt="no" />}, 'im'],
118
+ :free => [%q{%DOMAIN% </a> </th> <td class="disp"> <img src="../images/icon_disp_yes.gif" alt="si" />}, 'im']
119
+ )
120
+
121
+ # By leaving out the whois server, we force it to follow the internic redirection.
122
+ Whois::Server.define(
123
+ %w(com net edu),
124
+ 'whois.verisign-grs.com',
125
+ :registered => /No match for/im.invert!,
126
+ :free => /No match for/im
127
+ )
128
+
129
+ Whois::Server.define(
130
+ 'gov', 'whois.nic.gov',
131
+ :registered => /Status:\s*Active/im,
132
+ :free => /Status:\s*Active/im.invert!
133
+ )
134
+
135
+ Whois::Server.define(
136
+ %w(asn.au com.au id.au net.au org.au),
137
+ 'whois.ausregistry.net.au',
138
+ :free => /No Data Found/im,
139
+ :registered => /Last Modified/im,
140
+ :error => /BLACKLISTED/m
141
+ )
142
+
143
+ Whois::Server.define(
144
+ %w(hk com.hk net.hk edu.hk org.hk gov.hk idv.hk),
145
+ 'whois.hkdnr.net.hk',
146
+ :free => /Domain Not Found/,
147
+ :registered => /Domain Name\:/im
148
+ )
149
+ Whois::Server.define(
150
+ %w(co.nz net.nz org.nz geek.nz school.nz gen.nz govt.nz maori.nz ac.nz iwi.nz cri.nz mil.nz parliament.nz),
151
+ 'whois.srs.net.nz',
152
+ :free => /220 available/im,
153
+ :registered => /220 available/im.invert!
154
+ )
155
+
156
+ Whois::Server.define(
157
+ 'eu.com',
158
+ 'whois.centralnic.net',
159
+ :free => /DOMAIN NOT FOUND/im,
160
+ :registered => /Domain Name\:/im
161
+ )
162
+
163
+ Whois::Server.define(
164
+ %w(uk.com uk.net us.com la cn.com de.com jpn.com kr.com no.com za.com br.com ar.com ru.com sa.com se.com
165
+ se.net hu.com gb.com gb.net qc.com uy.com ae.org no.com se.com),
166
+ 'whois.centralnic.net',
167
+ :free => /available for registration/im,
168
+ :registered => /Domain Name\:/im
169
+ )
170
+
171
+ Whois::Server.define(
172
+ 'be',
173
+ 'whois.dns.be',
174
+ :free => /Status:\s+FREE/im,
175
+ :registered => /Status:\s+REGISTERED/im
176
+ )
177
+ Whois::Server.define(
178
+ 'biz',
179
+ 'whois.neulevel.biz',
180
+ :free => /Not found:/im,
181
+ :registered => /Domain Name:/im
182
+ )
183
+ Whois::Server.define(
184
+ %w(co.uk org.uk me.uk ltd.uk plc.uk net.uk sch.uk),
185
+ 'whois.nic.uk',
186
+ :registered => /Domain name:/im,
187
+ :free => /No match for/im,
188
+ :error => /Error for/im
189
+ )
190
+ Whois::Server.define(
191
+ 'de',
192
+ 'whois.denic.de',
193
+ :error => /Status:\s+invalid/im,
194
+ :registered => /Status:\s+connect/im,
195
+ :free => /Status:\s+free/im
196
+ )
197
+ Whois::Server.define(
198
+ 'dk',
199
+ 'whois.dk-hostmaster.dk',
200
+ :registered => /Registered:/im,
201
+ :error => /Your request is not valid./im,
202
+ :free => /No entries found for the selected source./im
203
+ )
204
+ Whois::Server.define(
205
+ 'eu',
206
+ 'whois.eu',
207
+ :free => /AVAILABLE/im,
208
+ :registered => /Name servers\:/im,
209
+ :pending => /APPLICATION PENDING/im,
210
+ :error => /NOT ALLOWED/im
211
+ )
212
+ Whois::Server.define(
213
+ 'info',
214
+ 'whois.afilias.info',
215
+ :error => /Not a valid domain search pattern/im,
216
+ :registered => /Domain Name:/im,
217
+ :free => /NOT FOUND/im
218
+ )
219
+ Whois::Server.define(
220
+ 'name',
221
+ 'whois.nic.name',
222
+ :registered => /Not available for second level registration./im,
223
+ :preserved => /Not available for second level registration./im,
224
+ :free => /No match./im
225
+ )
226
+
227
+ # Whois::Server.define(
228
+ # 'net',
229
+ # 'whois.verisign-grs.com',
230
+ # :registered => /Domain Name:/im,
231
+ # :free => /No match for/im
232
+ # )
233
+ Whois::Server.define(
234
+ 'nl',
235
+ 'whois.domain-registry.nl',
236
+ :registered => /active/im,
237
+ :free => /free/im,
238
+ :error => /invalid domain/im,
239
+ :preserved => /excluded/im
240
+ )
241
+ Whois::Server.define(
242
+ 'org',
243
+ 'whois.publicinterestregistry.net',
244
+ :registered => /Domain Name:/im,
245
+ :free => /NOT FOUND/im,
246
+ :error => /Not a valid domain search pattern/im
247
+ )
248
+ Whois::Server.define(
249
+ 'cc',
250
+ 'whois.nic.cc',
251
+ :registered => /Domain Name:/im,
252
+ :free => /No match for/im
253
+
254
+ )
255
+ Whois::Server.define(
256
+ 'ru',
257
+ 'whois.ripn.net',
258
+ :registered => /domain:/im,
259
+ :free => /No entries found/im
260
+
261
+ )
262
+ Whois::Server.define(
263
+ 'cat',
264
+ 'whois.cat',
265
+ :registered => /Domain Name: /im,
266
+ :free => /NOT FOUND/im
267
+
268
+ )
269
+ Whois::Server.define(
270
+ %w(travel jobs aero pw tw),
271
+ 'whois.encirca.com',
272
+ :registered => /Domain Registrar Status:/im,
273
+ :free => /Not found:/im
274
+ )
275
+ Whois::Server.define(
276
+ 'mobi',
277
+ # 'whois.corenic.net',
278
+ 'whois.dotmobiregistry.net',
279
+ :registered => /is not registered/im.invert!,
280
+ :free => /is not registered/im
281
+ )
282
+ Whois::Server.define(
283
+ 'ca',
284
+ 'whois.cira.ca',
285
+ :registered => /EXIST/im,
286
+ :free => /AVAIL/im
287
+ )
288
+ Whois::Server.define(
289
+ 'asia',
290
+ 'whois.nic.asia',
291
+ :registered => /Domain ID/im,
292
+ :free => /NOT FOUND/im
293
+ )
294
+ Whois::Server.define(
295
+ 'co.il',
296
+ 'whois.isoc.org.il',
297
+ :registered => /validity:/im,
298
+ :free => /No data was found to match the request criteria./im
299
+ )
300
+ Whois::Server.define(
301
+ 'ac.uk',
302
+ 'whois.ja.net',
303
+ :registered => /Domain:/im,
304
+ :free => /No such domain/im
305
+ )
306
+ Whois::Server.define(
307
+ %w(cx cm ht ki mu nf sb tl),
308
+ 'whois.nic.cx',
309
+ :registered => /Expires:/im,
310
+ :free => /(Not Registered|No Applications Pending)/im
311
+ )
312
+
313
+ Whois::Server.define(
314
+ 'nu',
315
+ 'whois.nic.nu',
316
+ :free => /NO MATCH.*/,
317
+ :registered => /Domain Name/
318
+ )
319
+
320
+ Whois::Server.define(
321
+ 'no',
322
+ 'whois.norid.no',
323
+ :registered => /Domain Information/im,
324
+ :free => /% No match/im,
325
+ :creation_date => /(Created:)\s*([\w\-]+)[^\n\r]*[\n\r]/im
326
+ )
327
+
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'activesupport'
3
+ require 'net/http'
4
+ require 'uri'
5
+ require 'time'
6
+ require 'timeout'
7
+
8
+ require File.dirname(__FILE__) + '/support/string'
9
+ require File.dirname(__FILE__) + '/support/extended_regexp'
10
+ Regexp.class_eval do
11
+ include Whois::ExtendedRegexp
12
+ end
13
+
14
+ require File.dirname(__FILE__) + '/universal_ruby_whois/domain'
15
+ require File.dirname(__FILE__) + '/universal_ruby_whois/server'
16
+ require File.dirname(__FILE__) + '/universal_ruby_whois/server_list'
17
+
18
+ module Whois
19
+
20
+ # This is a wrapper around the main domain lookup function. It allows you to simply call:
21
+ # Whois.find("somedomain.com")
22
+ #
23
+ # It returns a Whois::Domain object if found, or nil if an appropriate whois server can't be found.
24
+ def find(domain)
25
+ ::Whois::Domain.find(domain)
26
+ end
27
+
28
+ module_function :find #:nodoc:
29
+
30
+ end
data/test/regexp.rb ADDED
@@ -0,0 +1,22 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/universal_ruby_whois'
3
+
4
+ class RegexpTest < Test::Unit::TestCase
5
+
6
+ def test_inversion
7
+ r = /hi there/.invert!
8
+ assert !r.match_with_inversion("hi there")
9
+ r.uninvert!
10
+ assert r.match_with_inversion("hi there")
11
+ end
12
+
13
+ def test_interpolation
14
+ r = /hello __REPLACEME__ end/
15
+ assert_equal "hello __REPLACEME__ end", r.source
16
+ old_options = r.options
17
+ r2 = r.interpolate("__REPLACEME__" => "a value")
18
+ assert_equal old_options, r2.options
19
+ assert_equal "hello a value end", r2.source
20
+ end
21
+
22
+ end
data/test/string.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/universal_ruby_whois'
3
+
4
+ class StringTest < Test::Unit::TestCase
5
+
6
+ def test_interpolation
7
+ s = "hello __REPLACEME__ end"
8
+ assert_equal "hello __REPLACEME__ end", s
9
+ s2 = s.interpolate("__REPLACEME__" => "a value")
10
+ assert_equal "hello a value end", s2
11
+ end
12
+
13
+ end
data/test/whois.rb ADDED
@@ -0,0 +1,72 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/universal_ruby_whois'
3
+
4
+ class WhoisTest < Test::Unit::TestCase
5
+
6
+ TEST_TLDS = %w(com org co.uk eu.com ru info jp eu tc nu co.nz no)
7
+ REGISTERED_DOMAIN = "google"
8
+ AVAILABLE_DOMAIN = "asdfasdfasdfcvr3rwsdc2e"
9
+
10
+ def test_invalid_tld
11
+ domain = Whois.find("hello.blahblah")
12
+ assert_nil domain
13
+ end
14
+
15
+ def test_unavailable
16
+ TEST_TLDS.each do |tld|
17
+ domain = find_and_assert_domain("#{REGISTERED_DOMAIN}.#{tld}")
18
+ assert !domain.available?, "The domain name #{domain} shows as available but should not."
19
+ assert domain.registered?, "The domain name #{domain} does not show as registered but should."
20
+ end
21
+ end
22
+
23
+ def test_available
24
+ TEST_TLDS.each do |tld|
25
+ domain = find_and_assert_domain("#{AVAILABLE_DOMAIN}.#{tld}")
26
+ assert domain.available?, "The domain name #{domain} does not show as available but should."
27
+ assert !domain.registered?, "The domain name #{domain} shows as registered but should not."
28
+ end
29
+ end
30
+
31
+ def test_creation_date
32
+ domain = find_and_assert_domain("google.com")
33
+ assert_equal Time.local(*ParseDate.parsedate("1997-09-15")), domain.creation_date
34
+
35
+ TEST_TLDS.each do |tld|
36
+ domain = find_and_assert_domain("#{REGISTERED_DOMAIN}.#{tld}")
37
+ next unless domain.creation_date_known?
38
+ assert_kind_of Time, domain.creation_date, "Can't find creation date for domain: #{domain}"
39
+ end
40
+ end
41
+
42
+ def test_expiration_date
43
+ domain = find_and_assert_domain("google.com")
44
+ assert_equal Time.local(*ParseDate.parsedate("2011-09-14")), domain.expiration_date
45
+
46
+ TEST_TLDS.each do |tld|
47
+ domain = find_and_assert_domain("#{REGISTERED_DOMAIN}.#{tld}")
48
+ next unless domain.expiration_date_known?
49
+ assert_kind_of Time, domain.expiration_date, "Can't find expiration date for domain: #{domain}"
50
+ end
51
+ end
52
+
53
+ def test_mobi_domain
54
+ domain = find_and_assert_domain("google.mobi")
55
+ assert domain.expiration_date_known?
56
+ end
57
+
58
+ def test_no_domain
59
+ domain = find_and_assert_domain("norge.no")
60
+ assert_equal Time.local(*ParseDate.parsedate("1999-11-15")), domain.creation_date
61
+ end
62
+
63
+ protected
64
+
65
+ def find_and_assert_domain(domain)
66
+ domain_object = ::Whois.find(domain)
67
+ assert_kind_of Whois::Domain, domain_object, "Unable to look up info for domain name: #{domain}"
68
+ assert domain_object.valid?, "The domain name object for #{domain} is not valid (perhaps the whois server is down or busy?)"
69
+ domain_object
70
+ end
71
+
72
+ end
@@ -0,0 +1,40 @@
1
+ PKG_NAME = 'universal_ruby_whois'
2
+ PKG_VERSION = '1.2.9'
3
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
4
+ # RUBY_FORGE_PROJECT = 'universalwhois'
5
+ # RUBY_FORGE_USER = 'mlightner'
6
+
7
+ GEM_SPEC = spec = Gem::Specification.new do |s|
8
+ s.name = PKG_NAME
9
+ s.version = PKG_VERSION
10
+ s.author = "Vasily Shmelev"
11
+ s.email = "sleephunter@gmail.com"
12
+ s.homepage = "https://github.com/vs-adm/universal_ruby_whois/tree/master"
13
+ s.platform = Gem::Platform::RUBY
14
+ s.summary = "A module that attempts to act as a universal WHOIS output interpreter allowing you to get information about most domain name extensions."
15
+ s.files = %w(
16
+ README.rdoc
17
+ CHANGELOG.rdoc
18
+ LICENSE
19
+ universal_ruby_whois.gemspec
20
+ lib/universal_ruby_whois.rb
21
+ lib/universal_ruby_whois/server.rb
22
+ lib/universal_ruby_whois/server_list.rb
23
+ lib/universal_ruby_whois/domain.rb
24
+ lib/support/extended_regexp.rb
25
+ lib/support/string.rb
26
+ test/whois.rb
27
+ test/string.rb
28
+ test/regexp.rb
29
+ )
30
+ s.require_path = "lib"
31
+ s.autorequire = "name"
32
+ s.add_dependency('activesupport', '>= 1.4.4')
33
+ s.test_files = %w(
34
+ test/whois.rb
35
+ test/string.rb
36
+ test/regexp.rb
37
+ )
38
+ s.has_rdoc = true
39
+ #s.extra_rdoc_files = ["README", "LICENSE"]
40
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: universal_ruby_whois
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.9
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vasily Shmelev
9
+ autorequire: name
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.4.4
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.4
30
+ description:
31
+ email: sleephunter@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - README.rdoc
37
+ - CHANGELOG.rdoc
38
+ - LICENSE
39
+ - universal_ruby_whois.gemspec
40
+ - lib/universal_ruby_whois.rb
41
+ - lib/universal_ruby_whois/server.rb
42
+ - lib/universal_ruby_whois/server_list.rb
43
+ - lib/universal_ruby_whois/domain.rb
44
+ - lib/support/extended_regexp.rb
45
+ - lib/support/string.rb
46
+ - test/whois.rb
47
+ - test/string.rb
48
+ - test/regexp.rb
49
+ homepage: https://github.com/vs-adm/universal_ruby_whois/tree/master
50
+ licenses: []
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 1.8.24
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: A module that attempts to act as a universal WHOIS output interpreter allowing
73
+ you to get information about most domain name extensions.
74
+ test_files:
75
+ - test/whois.rb
76
+ - test/string.rb
77
+ - test/regexp.rb