mlightner-universal_ruby_whois 1.0.0 → 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.
data/CHANGELOG.rdoc ADDED
@@ -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/README.rdoc ADDED
@@ -0,0 +1,76 @@
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.created_date
50
+ => Mon Aug 28 00:00:00 EDT 2006
51
+ domain = Whois.find("9384jf398ejf9832ej.com")
52
+ => #<Whois::Domain:0xb7a1ab34 @domain="9384jf398ejf9832ej.com", @server_tld_key="com">
53
+ domain.status
54
+ => :free
55
+
56
+
57
+ === NOTES
58
+
59
+ Some registrars are relatively unreliable or may add a server to a blacklist after a certain number of
60
+ queries. In particular, the registrars for these domains:
61
+
62
+ - es and related TLDs: They only provide an HTTP whois access interface, which is unreliable at
63
+ best (although this module supports HTTP lookups quite well).
64
+ - asn.au com.au id.au net.au org.au: 'whois.aunic.net', seems as though they will blacklist a server
65
+ making too many queries. Not sure about their blacklist removal policy.
66
+
67
+
68
+ === TODO
69
+
70
+ - Add better support for creation date parsing for major registrars.
71
+ - Find a more reliable way to look up domains from registrars not providing a whois server.
72
+
73
+
74
+ === CONTRIBUTIONS
75
+
76
+ 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
@@ -1,17 +1,30 @@
1
1
  require 'rubygems'
2
2
  require 'activesupport'
3
-
4
3
  require 'net/http'
5
4
  require 'uri'
6
5
  require 'time'
7
6
  require 'timeout'
8
7
 
9
- require File.dirname(__FILE__) + '/universal_ruby_whois/inverted_regexp'
8
+ require File.dirname(__FILE__) + '/support/string'
9
+ require File.dirname(__FILE__) + '/support/extended_regexp'
10
10
  Regexp.class_eval do
11
- include MattLightner::InvertedRegexp
11
+ include Whois::ExtendedRegexp
12
12
  end
13
13
 
14
14
  require File.dirname(__FILE__) + '/universal_ruby_whois/domain'
15
15
  require File.dirname(__FILE__) + '/universal_ruby_whois/server'
16
16
  require File.dirname(__FILE__) + '/universal_ruby_whois/server_list'
17
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
@@ -1,29 +1,73 @@
1
+ require File.dirname(__FILE__) + '/server'
1
2
  require 'time'
2
3
 
3
4
  module Whois
4
5
 
5
6
  class Domain
6
7
 
7
- attr_accessor :domain, :server_tld_key, :whois_output
8
+ # The domain name, lower case, no spaces.
9
+ attr_reader :domain
8
10
 
9
- def initialize(domain, server_tld_key = nil)
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:
10
28
  @domain, @server_tld_key = domain.to_s.strip.downcase, server_tld_key
11
29
  end
12
30
 
31
+ # Returns the Whois::Server object for this domain name.
13
32
  def server
14
- Whois::Server.list[@server_tld_key]
33
+ Whois::Server.list[@server_tld_key] rescue nil
15
34
  end
16
35
 
36
+ # The set of regular expressions that will be used in matching this domain's whois output.
17
37
  def regexes
18
- server.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
19
45
  end
20
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.
21
59
  def whois_output
22
60
  return @whois_output if !@whois_output.blank?
23
- @whois_output = server.raw_response(domain) || ""
61
+ @whois_output = has_domain_and_server? ? server.raw_response!(domain) : ''
24
62
  end
25
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.
26
69
  def status
70
+ return :unknown unless has_domain_and_server?
27
71
  return @status unless @status.blank?
28
72
  [ :registered, :free, :error ].each do |status|
29
73
  #return status if Regexp.new(regexes[status].source, 5).match(res)
@@ -32,20 +76,54 @@ module Whois
32
76
  return @status = :unknown
33
77
  end
34
78
 
79
+ # Is this domain available? Returns true/false.
35
80
  def available?
81
+ return nil unless has_domain_and_server?
36
82
  status == :free
37
83
  end
38
84
 
85
+ # Is this domain name registered? Returns true/false.
39
86
  def registered?
87
+ return nil unless has_domain_and_server?
40
88
  status == :registered
41
89
  end
42
90
 
43
- def created_date
44
- return @created_date unless @created_date.blank?
45
- if regexes[:created_date] && (regexes[:created_date] =~ whois_output)
46
- @created_date = (Time.local(*ParseDate.parsedate($2)) rescue nil)
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)
47
97
  end
48
- @created_date
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
49
127
  end
50
128
  end
51
129
 
@@ -1,24 +1,75 @@
1
1
  module Whois
2
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).
3
8
  class Server
4
- @@whois_bin = `which whois`.gsub(/\s/, '')
5
9
 
6
- attr_accessor :tld, :nic_server, :regexes, :port
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 = `which whois`.gsub(/\s/, '')
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
7
54
 
8
- def initialize(tld, nic_server = nil, options = {})
9
- @tld = tld
55
+ def initialize(tld, nic_server = nil, options = nil) #:nodoc:
56
+ @tld = tld.gsub(/^\.+/, '')
57
+ options ||= Hash.new
10
58
  @response_cache = Hash.new("")
11
59
  @nic_server = nic_server
12
60
  @port = options.delete(:port)
13
- @regexes = options.reverse_merge(
14
- :free => /(avail|free|no match|no entr|not taken|not registered|not found)/im,
15
- :registered => /(registered|Domain ID|domain name\s*\:|is active|is not available|exists|\bregistrant\b|Created on)/im,
16
- :created_date => /(Creation date|created on|created at|Commencement Date|Registration Date)\s*[\:\.]*\s*([\w\-\:\ ]+)[^\n\r]*[\n\r]/im,
17
- :error => /(error)/im
18
- )
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
19
70
  end
20
71
 
21
- # Class variable accessors
72
+ # A hash of all of the known whois servers indexed by TLD
22
73
  def self.list
23
74
  @@list ||= Hash.new
24
75
  end
@@ -27,21 +78,21 @@ module Whois
27
78
  @@list = value
28
79
  end
29
80
 
30
- def self.domain_object_cache
81
+ def self.domain_object_cache #:nodoc:
31
82
  @@domain_object_cache ||= Hash.new
32
83
  end
33
84
 
34
- def self.domain_object_cache=(value)
85
+ def self.domain_object_cache=(value) #:nodoc:
35
86
  @@domain_object_cache = value
36
87
  end
37
88
 
89
+ # A list of strings representing all supported TLDs.
38
90
  def self.defined_tlds
39
91
  self.list.collect {|tld,server| tld.gsub(/^\./, '') }
40
92
  end
41
93
 
42
- # Find a TLD from a full domain name. There is special care to check for
43
- # two part TLD's (such as .co.uk, .kids.us, etc) first and then to look for
44
- # the last part alone.
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.
45
96
  def self.find_server_from_domain(domain)
46
97
  # valid domain?
47
98
  return nil unless domain =~ /^((?:[-a-zA-Z0-9]+\.)+[a-zA-Z]{2,})$/
@@ -67,6 +118,12 @@ module Whois
67
118
  return tld
68
119
  end
69
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)
70
127
  def self.find(domain)
71
128
  domain = domain.to_s.strip.downcase
72
129
  return domain_object_cache[domain] unless domain_object_cache[domain].blank?
@@ -74,6 +131,7 @@ module Whois
74
131
  domain_object_cache[domain] = Whois::Domain.new(domain, server.tld)
75
132
  end
76
133
 
134
+ # Determine the appropriate whois server object for a domain name.
77
135
  def self.server_for_domain(domain)
78
136
  server = self.find_server_from_domain(domain)
79
137
  # This will only work on single extension domains
@@ -86,21 +144,67 @@ module Whois
86
144
  server
87
145
  end
88
146
 
147
+ def unavailable?
148
+ @unavailable ? true : false
149
+ end
150
+
151
+ # Retrieve the raw WHOIS server output for a domain.
89
152
  def raw_response(domain)
153
+ return nil if unavailable?
90
154
  return @response_cache[domain] if !@response_cache[domain].blank?
91
155
  @response_cache[domain] = ""
92
- if nic_server =~ /^http/
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/
93
181
  url = nic_server.gsub(/\%DOMAIN\%/, domain)
94
182
  @response_cache[domain] = Net::HTTP.get_response(URI.parse(url)).body
95
183
  else
96
- command = "#{@@whois_bin} #{('-h ' + @nic_server) unless @nic_server.blank?} #{self.class.shell_escape(domain)} 2>&1"
184
+ command = "#{WHOIS_BIN} #{('-h ' + @nic_server) unless @nic_server.blank?} #{self.class.shell_escape(domain)} 2>&1"
97
185
  @response_cache[domain] = Whois::Server.run_command_with_timeout(command, 10, true)
98
186
  end
99
- @response_cache[domain]
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
100
202
  end
101
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.
102
206
  def self.define_from_iana(tld)
103
- iana_out = run_command_with_timeout("#{@@whois_bin} -h whois.iana.org #{shell_escape(tld.to_s)} 2>&1", 10, false)
207
+ iana_out = run_command_with_timeout("#{WHOIS_BIN} -h whois.iana.org #{shell_escape(tld.to_s)} 2>&1", 10, false)
104
208
  return false if iana_out.blank?
105
209
  return false unless iana_out =~ /Whois\s+Server\s+\(port ([\d]+)\)\: ([\w\-\.\_]+)/im
106
210
  port = $1
@@ -108,23 +212,14 @@ module Whois
108
212
  define_single(tld.to_s, server, :port => port)
109
213
  end
110
214
 
111
- def self.define_single(*args, &block)
215
+ def self.define_single(*args, &block) #:nodoc:
112
216
  new_server = allocate
113
217
  new_server.send(:initialize, *args, &block)
114
218
  list[args.first.to_s] = new_server
115
219
  new_server
116
220
  end
117
221
 
118
- def self.define(*args, &block)
119
- tld_list = args.shift
120
- tld_list = tld_list.kind_of?(Array) ? tld_list : [tld_list]
121
- tld_list.each do |tld|
122
- define_single(*args.clone.unshift(tld.to_s), &block)
123
- end
124
- tld_list
125
- end
126
-
127
- def self.run_command_with_timeout(command, timeout = 10, do_raise = false)
222
+ def self.run_command_with_timeout(command, timeout = 10, do_raise = false) #:nodoc:
128
223
  @output = ""
129
224
  begin
130
225
  status = Timeout::timeout(10) do
@@ -137,14 +232,15 @@ module Whois
137
232
  raise "Running command \"#{command}\" timed out."
138
233
  end
139
234
  end
235
+ @output.strip!
140
236
  @output
141
237
  end
142
238
 
143
- def self.shell_escape(word)
144
- word.to_s.gsub(/[^\w\-\_\.]+/, '')
239
+ def self.shell_escape(word) #:nodoc:
240
+ word.to_s.gsub(/[^\w\-\_\.]+/, '') rescue ''
145
241
  end
146
242
 
147
- end # class Server
243
+ end
148
244
 
149
245
  end
150
246
 
@@ -68,8 +68,6 @@ Whois::Server.define('ch',"whois.nic.ch")
68
68
  Whois::Server.define('cn',"whois.cnnic.net.cn")
69
69
  Whois::Server.define('cz',"whois.nic.cz")
70
70
  Whois::Server.define('ee',"whois.eenet.ee")
71
- Whois::Server.define('es',"https://www.nic.es/esnic/servlet/BuscarDomSolAlta?dominio=%DOMAIN%")
72
- Whois::Server.define('com.es',"https://www.nic.es/esnic/servlet/BuscarDomSolAlta?dominio=%DOMAIN%")
73
71
  Whois::Server.define('gr',"https://grweb.ics.forth.gr/")
74
72
  Whois::Server.define('it',"whois.nic.it")
75
73
  Whois::Server.define('li',"whois.nic.li")
@@ -88,6 +86,24 @@ Whois::Server.define('tc',"whois.adamsnames.tc")
88
86
  Whois::Server.define('vg',"whois.adamsnames.tc")
89
87
  Whois::Server.define('ws',"whois.worldsite.ws")
90
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
+
91
107
 
92
108
  # By leaving out the whois server, we force it to follow the internic redirection.
93
109
  Whois::Server.define(
@@ -104,7 +120,8 @@ Whois::Server.define(
104
120
 
105
121
  Whois::Server.define(%w(asn.au com.au id.au net.au org.au), 'whois.aunic.net',
106
122
  :free => /No Data Found/im,
107
- :registered => /No Data Found/im.invert! )
123
+ :registered => /No Data Found/im.invert!,
124
+ :error => /BLACKLISTED/m )
108
125
 
109
126
  Whois::Server.define(
110
127
  %w(hk com.hk net.hk edu.hk org.hk gov.hk idv.hk),
@@ -238,3 +255,9 @@ Whois::Server.define('asia', 'whois.nic.asia',
238
255
  :registered => /Domain ID/im,
239
256
  :free => /NOT FOUND/im
240
257
  )
258
+ Whois::Server.define(
259
+ '.co.il',
260
+ 'whois.isoc.org.il',
261
+ :registered => /validity:/im,
262
+ :free => /No data was found to match the request criteria./im
263
+ )
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 CHANGED
@@ -3,21 +3,60 @@ require File.dirname(__FILE__) + '/../lib/universal_ruby_whois'
3
3
 
4
4
  class WhoisTest < Test::Unit::TestCase
5
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
+
6
15
  def test_unavailable
7
- domain = Whois::Server.find("google.com")
8
- assert !domain.available?
9
- assert domain.registered?
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
10
21
  end
11
22
 
12
23
  def test_available
13
- domain = Whois::Server.find("j983jf89ej2e09d2jd.com")
14
- assert domain.available?
15
- assert !domain.registered?
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
16
29
  end
17
30
 
18
31
  def test_creation_date
19
- domain = Whois::Server.find("google.com")
20
- domain.created_date == Time.local(*ParseDate.parsedate("1997-09-15"))
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
21
60
  end
22
61
 
23
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 = 'mlightner'
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/mlightner/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 CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mlightner-universal_ruby_whois
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Lightner
@@ -9,7 +9,7 @@ autorequire: name
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-10-09 00:00:00 -07:00
12
+ date: 2008-10-27 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -27,16 +27,22 @@ executables: []
27
27
 
28
28
  extensions: []
29
29
 
30
- extra_rdoc_files:
31
- - README
32
- - LICENSE
30
+ extra_rdoc_files: []
31
+
33
32
  files:
34
- - README
33
+ - README.rdoc
34
+ - CHANGELOG.rdoc
35
35
  - LICENSE
36
+ - universal_ruby_whois.gemspec
36
37
  - lib/universal_ruby_whois.rb
37
- - lib/universal_ruby_whois/domain.rb
38
38
  - lib/universal_ruby_whois/server.rb
39
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
40
46
  has_rdoc: true
41
47
  homepage: http://github.com/mlightner/universal_ruby_whois/tree/master
42
48
  post_install_message:
@@ -65,3 +71,5 @@ specification_version: 2
65
71
  summary: A module that attempts to act as a universal WHOIS output interpreter allowing you to get information about most domain name extensions.
66
72
  test_files:
67
73
  - test/whois.rb
74
+ - test/string.rb
75
+ - test/regexp.rb
data/README DELETED
File without changes