universal_ruby_whois 1.2.9

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/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