coreymartella-universal_ruby_whois 1.2.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.
@@ -0,0 +1,5 @@
1
+ == 11/10/08
2
+ * Support for expiration date parsing added as requested by Jorge Yau.
3
+ * Renamed "created_date" to "creation_date" for consistency.
4
+ * Moved supporting libraries into a support folder.
5
+ * 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
+
@@ -0,0 +1,78 @@
1
+ = Universal Whois Server
2
+
3
+ *Author*: Matt Lightner <mailto:mlightner@gmail.com>
4
+
5
+ *License*: MIT[link:files/LICENSE.html]
6
+
7
+ This library attempts to interpret WHOIS output from a variety of different registrars.
8
+ The ultimate goal is to have a complete "dictionary" of all of the TLD registrars (including
9
+ double domain TLDs such as .co.uk) on the Internet, and corresponding regular expressions
10
+ to parse the unique output format for each one.
11
+
12
+ This package requires a command line whois utility to retrieve output. It will then attempt
13
+ to interpret that output based on a series of regular expressions.
14
+
15
+
16
+ === DEFINING WHOIS SERVERS
17
+
18
+ Whois servers can be defined on a per-TLD basis, so each registrar can have a unique set
19
+ of regular expressions to match its particular output format. Whois servers are defined in the
20
+ file server_list.rb.
21
+
22
+ If you're using this module and come across a TLD that isn't yet supported or isn't working
23
+ quite right, I highly encourage you to fork the project and commit your updates. The more
24
+ people we have working on the list, the more comprehensive and effective it becomes!
25
+
26
+
27
+ === TLD SEARCH PRIORITY
28
+
29
+ When deciding which whois server to use, the script will always choose the most specific
30
+ server entry it can find. For instance, if you have defined a server for .uk domains,
31
+ but also a server for .co.uk domains, the domain name "test.co.uk" will always use the
32
+ latter whois server.
33
+
34
+
35
+ === EXAMPLE USAGE
36
+
37
+ Here is the output from a sample IRB session using this library:
38
+
39
+ require 'universal_ruby_whois'
40
+ => true
41
+ domain = Whois.find("mattlightner.com")
42
+ => #<Whois::Domain:0xb7a3b014 @domain="mattlightner.com", @server_tld_key="com">
43
+ domain.status
44
+ => :registered
45
+ domain.available?
46
+ => false
47
+ domain.registered?
48
+ => true
49
+ domain.creation_date
50
+ => Mon Aug 28 00:00:00 EDT 2006
51
+ domain.expiration_date
52
+ => Fri Aug 28 00:00:00 EDT 2009
53
+ domain = Whois.find("9384jf398ejf9832ej.com")
54
+ => #<Whois::Domain:0xb7a1ab34 @domain="9384jf398ejf9832ej.com", @server_tld_key="com">
55
+ domain.status
56
+ => :free
57
+
58
+
59
+ === NOTES
60
+
61
+ Some registrars are relatively unreliable or may add a server to a blacklist after a certain number of
62
+ queries. In particular, the registrars for these domains:
63
+
64
+ - es and related TLDs: They only provide an HTTP whois access interface, which is unreliable at
65
+ best (although this module supports HTTP lookups quite well).
66
+ - asn.au com.au id.au net.au org.au: 'whois.aunic.net', seems as though they will blacklist a server
67
+ making too many queries. Not sure about their blacklist removal policy.
68
+
69
+
70
+ === TODO
71
+
72
+ - Add better support for creation date parsing for major registrars.
73
+ - Find a more reliable way to look up domains from registrars not providing a whois server.
74
+
75
+
76
+ === CONTRIBUTIONS
77
+
78
+ Contribution is encouraged! Grab the source from: git://github.com/mlightner/universal_ruby_whois.git
@@ -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,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
@@ -0,0 +1,131 @@
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
+ end
129
+
130
+ end
131
+
@@ -0,0 +1,246 @@
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|not registered|not found)/im,
17
+ :registered => /(registered|Domain ID|domain name\s*\:|is active|is not available|exists|\bregistrant\b|Created on)/im,
18
+ :creation_date => /(Creation date|created on|created at|Commencement Date|Registration Date)\s*[\:\.\]]*\s*([\w\-\:\ \/]+)[^\n\r]*[\n\r]/im,
19
+ :expiration_date => /(expiration date|expires on|registered through|Renewal date)\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, :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
+ @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
246
+
@@ -0,0 +1,269 @@
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('bz', 'whois.belizenic.bz')
16
+ Whois::Server.define('cc', 'whois.nic.cc')
17
+ Whois::Server.define('cd', 'whois.nic.cd')
18
+ Whois::Server.define('ck', 'whois.nic.ckcn')
19
+ Whois::Server.define('de', 'whois.denic.de')
20
+ Whois::Server.define('fo', 'whois.ripe.net')
21
+ Whois::Server.define('gg', 'whois.isles.net')
22
+ Whois::Server.define('gl', 'whois.ripe.net')
23
+ Whois::Server.define('gm', 'whois.ripe.net')
24
+ Whois::Server.define('gr', 'whois.grnet.gr')
25
+ Whois::Server.define('gs', 'whois.gs')
26
+ Whois::Server.define('hm', 'webhst1.capital.hm')
27
+ Whois::Server.define('hu', 'whois.nic.hu')
28
+ Whois::Server.define('id', 'whois.idnic.net.id')
29
+ Whois::Server.define('in', 'whois.inregistry.net')
30
+ Whois::Server.define('ir', 'whois.nic.ir')
31
+ Whois::Server.define('kz', 'whois.nic.kz')
32
+ Whois::Server.define('la', 'whois2.afilias-grs.net')
33
+ Whois::Server.define('ly', 'whois.lydomains.com')
34
+ Whois::Server.define('mc', 'whois.ripe.net')
35
+ Whois::Server.define('ms', 'whois.ms')
36
+ Whois::Server.define('mx', 'whois.nic.mx')
37
+ Whois::Server.define('my', 'whois.mynic.net.my')
38
+ Whois::Server.define('nu', 'whois.nic.nu')
39
+ Whois::Server.define('pl', 'whois.dns.pl')
40
+ Whois::Server.define('pm', 'whois.nic.pm')
41
+ Whois::Server.define('pro', 'whois.registrypro.pro')
42
+ Whois::Server.define('pt', 'whois.nic.pt')
43
+ Whois::Server.define('sa', 'saudinic.net.sa')
44
+ Whois::Server.define('sb', 'whois.nic.net.sb')
45
+ Whois::Server.define('se', 'whois.nic-se.se')
46
+ Whois::Server.define('si', 'whois.arnes.si')
47
+ Whois::Server.define('sk', 'whois.sk-nic.sk')
48
+ Whois::Server.define('sm', 'whois.ripe.net')
49
+ Whois::Server.define('st', 'whois.nic.st')
50
+ Whois::Server.define('su', 'whois.ripn.net')
51
+ Whois::Server.define('tc', 'whois.tc')
52
+ Whois::Server.define('th', 'whois.thnic.net')
53
+ Whois::Server.define('to', 'whois.tonic.to')
54
+ Whois::Server.define('tv', 'tvwhois.verisign-grs.com')
55
+ Whois::Server.define('uy', 'www.nic.org.uy')
56
+ Whois::Server.define('uz', 'whois.cctld.uz')
57
+ Whois::Server.define('va', 'whois.ripe.net')
58
+ Whois::Server.define('ve', 'whois.nic.ve')
59
+ Whois::Server.define('vg', 'whois.vg')
60
+ Whois::Server.define('wf', 'whois.nic.wf')
61
+ Whois::Server.define('ws', 'whois.tld.ws')
62
+ Whois::Server.define('yt', 'whois.nic.yt')
63
+ Whois::Server.define('us', 'whois.nic.us')
64
+ Whois::Server.define('at',"whois.nic.at")
65
+ Whois::Server.define('ca',"whois.cira.ca")
66
+ Whois::Server.define('cc',"whois.nic.cc")
67
+ Whois::Server.define('ch',"whois.nic.ch")
68
+ Whois::Server.define('cn',"whois.cnnic.net.cn")
69
+ Whois::Server.define('cz',"whois.nic.cz")
70
+ Whois::Server.define('ee',"whois.eenet.ee")
71
+ Whois::Server.define('gr',"https://grweb.ics.forth.gr/")
72
+ Whois::Server.define('it',"whois.nic.it")
73
+ Whois::Server.define('li',"whois.nic.li")
74
+ Whois::Server.define('lt',"whois.domreg.lt")
75
+ Whois::Server.define('lu',"whois.dns.lu")
76
+ Whois::Server.define('lv',"whois.ripe.net")
77
+ Whois::Server.define('ms',"whois.adamsnames.tc")
78
+ Whois::Server.define('co.nz',"whois.domainz.net.nz")
79
+ Whois::Server.define('nu',"whois.nic.nu")
80
+ Whois::Server.define('pl',"whois.dns.pl")
81
+ Whois::Server.define('ro',"whois.rotld.ro")
82
+ Whois::Server.define('ru',"whois.ripn.net")
83
+ Whois::Server.define('se',"whois.nic-se.se")
84
+ Whois::Server.define('sk',"whois.ripe.net")
85
+ Whois::Server.define('tc',"whois.adamsnames.tc")
86
+ Whois::Server.define('vg',"whois.adamsnames.tc")
87
+ Whois::Server.define('ws',"whois.worldsite.ws")
88
+
89
+ #Whois::Server.define('es',"https://www.nic.es/esnic/servlet/BuscarDomSolAlta?dominio=%DOMAIN%")
90
+ #Whois::Server.define('com.es',"https://www.nic.es/esnic/servlet/BuscarDomSolAlta?dominio=%DOMAIN%")
91
+
92
+ Whois::Server.define(
93
+ %w(jp co.jp or.jp ne.jp ac.jp ad.jp ed.jp go.jp gr.jp lg.jp),
94
+ ['http://whois.jprs.jp/en/', :post, { :submit => 'query', :key => '%DOMAIN%', :type => 'DOM'}],
95
+ :registered => /Domain Information\:/im,
96
+ :free => /No match\!\!/im
97
+ )
98
+
99
+ Whois::Server.define(
100
+ %w(es com.es nom.es org.es gob.es edu.es),
101
+ ['https://www.nic.es/esnic/servlet/BuscarDomSolAlta', :post, { :Submit => 'Buscar', :domino => '%DOMAIN_NO_TLD%',
102
+ :sufijo => '%TLD%', :tipo => 'dominio'}],
103
+ :registered => [%q{%DOMAIN% </a> </th> <td class="disp"> <img src="../images/icon_disp_no.gif" alt="no" />}, 'im'],
104
+ :free => [%q{%DOMAIN% </a> </th> <td class="disp"> <img src="../images/icon_disp_yes.gif" alt="si" />}, 'im']
105
+ )
106
+
107
+
108
+ # By leaving out the whois server, we force it to follow the internic redirection.
109
+ Whois::Server.define(
110
+ [ 'com', 'net', 'edu' ], nil,
111
+ :registered => /No match for/im.invert!,
112
+ :free => /No match for/im
113
+ )
114
+
115
+ Whois::Server.define(
116
+ 'gov', 'whois.nic.gov',
117
+ :registered => /Status:\s*Active/im,
118
+ :free => /Status:\s*Active/im.invert!
119
+ )
120
+
121
+ Whois::Server.define(%w(asn.au com.au id.au net.au org.au), 'whois.aunic.net',
122
+ :free => /No Data Found/im,
123
+ :registered => /No Data Found/im.invert!,
124
+ :error => /BLACKLISTED/m )
125
+
126
+ Whois::Server.define(
127
+ %w(hk com.hk net.hk edu.hk org.hk gov.hk idv.hk),
128
+ 'whois.hkdnr.net.hk',
129
+ :free => /Domain Not Found/,
130
+ :registered => /Domain Name\:/im
131
+ )
132
+ Whois::Server.define(
133
+ %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),
134
+ 'whois.srs.net.nz',
135
+ :free => /220 available/im,
136
+ :registered => /220 available/im.invert!
137
+ )
138
+ Whois::Server.define(
139
+ %w(eu.com 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
140
+ se.net hu.com gb.com gb.net qc.com uy.com ae.org no.com se.com),
141
+ 'whois.centralnic.net',
142
+ :free => /available for registration/im,
143
+ :registered => /Domain Name\:/im
144
+ )
145
+ Whois::Server.define(
146
+ 'be',
147
+ 'whois.dns.be',
148
+ :free => /Status:\s+FREE/im,
149
+ :registered => /Status:\s+REGISTERED/im
150
+ )
151
+ Whois::Server.define(
152
+ 'biz',
153
+ 'whois.neulevel.biz',
154
+ :free => /Not found:/im,
155
+ :registered => /Domain Name:/im
156
+ )
157
+ Whois::Server.define(
158
+ %w(co.uk org.uk me.uk ltd.uk plc.uk net.uk sch.uk),
159
+ 'whois.nic.uk',
160
+ :registered => /Domain name:/im,
161
+ :free => /No match for/im,
162
+ :error => /Error for/im
163
+ )
164
+ Whois::Server.define(
165
+ 'de',
166
+ 'whois.denic.de',
167
+ :error => /Status:\s+invalid/im,
168
+ :registered => /Status:\s+connect/im,
169
+ :free => /Status:\s+free/im
170
+ )
171
+ Whois::Server.define(
172
+ 'dk',
173
+ 'whois.dk-hostmaster.dk',
174
+ :registered => /Registered:/im,
175
+ :error => /Your request is not valid./im,
176
+ :free => /No entries found for the selected source./im
177
+ )
178
+ Whois::Server.define(
179
+ 'eu',
180
+ 'http://www.whois.eu/whois/GetDomainStatus.htm?domainName=%DOMAIN%',
181
+ :free => /AVAILABLE/im,
182
+ :registered => /REGISTERED/im,
183
+ :pending => /APPLICATION PENDING/im,
184
+ :error => /NOT ALLOWED/im
185
+ )
186
+ Whois::Server.define(
187
+ 'info',
188
+ 'whois.afilias.info',
189
+ :error => /Not a valid domain search pattern/im,
190
+ :registered => /Domain Name:/im,
191
+ :free => /NOT FOUND/im
192
+ )
193
+ Whois::Server.define(
194
+ 'name',
195
+ 'whois.nic.name',
196
+ :registered => /Not available for registration./im,
197
+ :preserved => /Not available for second level registration./im,
198
+ :free => /No match./im
199
+ )
200
+ # Whois::Server.define(
201
+ # 'net',
202
+ # 'whois.verisign-grs.com',
203
+ # :registered => /Domain Name:/im,
204
+ # :free => /No match for/im
205
+ # )
206
+ Whois::Server.define(
207
+ 'nl',
208
+ 'whois.domain-registry.nl',
209
+ :registered => /ims active/im,
210
+ :free => /ims free/im,
211
+ :error => /imnvalid name/im,
212
+ :preserved => /ims excluded/im
213
+ )
214
+ Whois::Server.define(
215
+ 'org',
216
+ 'whois.publicinterestregistry.net',
217
+ :registered => /Domain Name:/im,
218
+ :free => /NOT FOUND/im,
219
+ :error => /Not a valid domain search pattern/im
220
+ )
221
+ Whois::Server.define(
222
+ 'cc',
223
+ 'whois.nic.cc',
224
+ :registered => /Domain Name:/im,
225
+ :free => /No match for/im
226
+
227
+ )
228
+ Whois::Server.define(
229
+ 'ru',
230
+ 'whois.ripn.net',
231
+ :registered => /domain:/im,
232
+ :free => /No entries found/im
233
+
234
+ )
235
+ Whois::Server.define(
236
+ 'cat',
237
+ 'whois.cat',
238
+ :registered => /Domain Name: /im,
239
+ :free => /NOT FOUND/im
240
+
241
+ )
242
+ Whois::Server.define(
243
+ %w(travel jobs aero pw tw),
244
+ 'whois.encirca.com',
245
+ :registered => /Domain Registrar Status:/im,
246
+ :free => /Not found:/im
247
+ )
248
+ Whois::Server.define(
249
+ 'mobi',
250
+ 'whois.corenic.net',
251
+ :registered => /Domain ID:/im,
252
+ :free => /NOT FOUND/m
253
+ )
254
+ Whois::Server.define(
255
+ 'ca',
256
+ 'whois.cira.ca',
257
+ :registered => /EXIST/im,
258
+ :free => /AVAIL/im
259
+ )
260
+ Whois::Server.define('asia', 'whois.nic.asia',
261
+ :registered => /Domain ID/im,
262
+ :free => /NOT FOUND/im
263
+ )
264
+ Whois::Server.define(
265
+ '.co.il',
266
+ 'whois.isoc.org.il',
267
+ :registered => /validity:/im,
268
+ :free => /No data was found to match the request criteria./im
269
+ )
@@ -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
@@ -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
@@ -0,0 +1,62 @@
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)
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-13")), 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
+ protected
54
+
55
+ def find_and_assert_domain(domain)
56
+ domain_object = ::Whois.find(domain)
57
+ assert_kind_of Whois::Domain, domain_object, "Unable to look up info for domain name: #{domain}"
58
+ assert domain_object.valid?, "The domain name object for #{domain} is not valid (perhaps the whois server is down or busy?)"
59
+ domain_object
60
+ end
61
+
62
+ end
@@ -0,0 +1,40 @@
1
+ PKG_NAME = 'universal_ruby_whois'
2
+ PKG_VERSION = '1.2.1'
3
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
4
+ RUBY_FORGE_PROJECT = 'universalwhois'
5
+ RUBY_FORGE_USER = 'coreymartella'
6
+
7
+ GEM_SPEC = spec = Gem::Specification.new do |s|
8
+ s.name = PKG_NAME
9
+ s.version = PKG_VERSION
10
+ s.author = "Matt Lightner"
11
+ s.email = "mlightner@gmail.com"
12
+ s.homepage = "http://github.com/coreymartella/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,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: coreymartella-universal_ruby_whois
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Matt Lightner
8
+ autorequire: name
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-11 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.4.4
23
+ version:
24
+ description:
25
+ email: mlightner@gmail.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - README.rdoc
34
+ - CHANGELOG.rdoc
35
+ - LICENSE
36
+ - universal_ruby_whois.gemspec
37
+ - lib/universal_ruby_whois.rb
38
+ - lib/universal_ruby_whois/server.rb
39
+ - lib/universal_ruby_whois/server_list.rb
40
+ - lib/universal_ruby_whois/domain.rb
41
+ - lib/support/extended_regexp.rb
42
+ - lib/support/string.rb
43
+ - test/whois.rb
44
+ - test/string.rb
45
+ - test/regexp.rb
46
+ has_rdoc: true
47
+ homepage: http://github.com/coreymartella/universal_ruby_whois/tree/master
48
+ post_install_message:
49
+ rdoc_options: []
50
+
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.2.0
69
+ signing_key:
70
+ specification_version: 2
71
+ summary: A module that attempts to act as a universal WHOIS output interpreter allowing you to get information about most domain name extensions.
72
+ test_files:
73
+ - test/whois.rb
74
+ - test/string.rb
75
+ - test/regexp.rb