epp-ruby 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/.simplecov +16 -0
- data/.travis.yml +11 -0
- data/.yardopts +4 -0
- data/CHANGELOG.md +31 -0
- data/Gemfile +20 -0
- data/Gemfile.lock +51 -0
- data/LICENSE +21 -0
- data/README.md +95 -0
- data/Rakefile +20 -0
- data/epp-ruby.gemspec +22 -0
- data/examples/contact_create.rb +28 -0
- data/examples/domain_check.rb +11 -0
- data/examples/domain_create.rb +19 -0
- data/examples/domain_info.rb +9 -0
- data/examples/host_create.rb +14 -0
- data/gemfiles/Gemfile.ruby18 +14 -0
- data/lib/epp-client/client.rb +172 -0
- data/lib/epp-client/commands/check.rb +11 -0
- data/lib/epp-client/commands/command.rb +24 -0
- data/lib/epp-client/commands/create.rb +11 -0
- data/lib/epp-client/commands/delete.rb +11 -0
- data/lib/epp-client/commands/info.rb +11 -0
- data/lib/epp-client/commands/login.rb +40 -0
- data/lib/epp-client/commands/logout.rb +11 -0
- data/lib/epp-client/commands/poll.rb +28 -0
- data/lib/epp-client/commands/read_write_command.rb +18 -0
- data/lib/epp-client/commands/renew.rb +11 -0
- data/lib/epp-client/commands/transfer.rb +25 -0
- data/lib/epp-client/commands/transfer_handshake.rb +43 -0
- data/lib/epp-client/commands/update.rb +11 -0
- data/lib/epp-client/contact/check.rb +23 -0
- data/lib/epp-client/contact/check_response.rb +41 -0
- data/lib/epp-client/contact/command.rb +106 -0
- data/lib/epp-client/contact/create.rb +34 -0
- data/lib/epp-client/contact/create_response.rb +14 -0
- data/lib/epp-client/contact/delete.rb +21 -0
- data/lib/epp-client/contact/delete_response.rb +9 -0
- data/lib/epp-client/contact/info.rb +21 -0
- data/lib/epp-client/contact/info_response.rb +74 -0
- data/lib/epp-client/contact/response.rb +34 -0
- data/lib/epp-client/contact/transfer.rb +21 -0
- data/lib/epp-client/contact/transfer_response.rb +26 -0
- data/lib/epp-client/contact/update.rb +80 -0
- data/lib/epp-client/contact/update_response.rb +9 -0
- data/lib/epp-client/domain/check.rb +23 -0
- data/lib/epp-client/domain/check_response.rb +41 -0
- data/lib/epp-client/domain/command.rb +92 -0
- data/lib/epp-client/domain/create.rb +75 -0
- data/lib/epp-client/domain/create_response.rb +29 -0
- data/lib/epp-client/domain/delete.rb +21 -0
- data/lib/epp-client/domain/delete_response.rb +9 -0
- data/lib/epp-client/domain/info.rb +21 -0
- data/lib/epp-client/domain/info_response.rb +72 -0
- data/lib/epp-client/domain/list.rb +36 -0
- data/lib/epp-client/domain/renew.rb +38 -0
- data/lib/epp-client/domain/renew_response.rb +14 -0
- data/lib/epp-client/domain/response.rb +34 -0
- data/lib/epp-client/domain/transfer.rb +37 -0
- data/lib/epp-client/domain/transfer_response.rb +29 -0
- data/lib/epp-client/domain/update.rb +81 -0
- data/lib/epp-client/domain/update_response.rb +9 -0
- data/lib/epp-client/host/check.rb +23 -0
- data/lib/epp-client/host/check_response.rb +41 -0
- data/lib/epp-client/host/command.rb +47 -0
- data/lib/epp-client/host/create.rb +24 -0
- data/lib/epp-client/host/create_response.rb +14 -0
- data/lib/epp-client/host/delete.rb +21 -0
- data/lib/epp-client/host/delete_response.rb +9 -0
- data/lib/epp-client/host/info.rb +21 -0
- data/lib/epp-client/host/info_response.rb +42 -0
- data/lib/epp-client/host/response.rb +34 -0
- data/lib/epp-client/host/update.rb +76 -0
- data/lib/epp-client/host/update_response.rb +9 -0
- data/lib/epp-client/old_server.rb +25 -0
- data/lib/epp-client/request.rb +51 -0
- data/lib/epp-client/requests/abstract.rb +30 -0
- data/lib/epp-client/requests/command.rb +28 -0
- data/lib/epp-client/requests/extension.rb +28 -0
- data/lib/epp-client/requests/hello.rb +12 -0
- data/lib/epp-client/response.rb +100 -0
- data/lib/epp-client/response_error.rb +15 -0
- data/lib/epp-client/response_helper.rb +25 -0
- data/lib/epp-client/server.rb +330 -0
- data/lib/epp-client/testing.rb +59 -0
- data/lib/epp-client/version.rb +3 -0
- data/lib/epp-client/xml_helper.rb +71 -0
- data/lib/epp-client.rb +103 -0
- data/lib/epp-ruby.rb +1 -0
- data/test/commands/test_check_command.rb +33 -0
- data/test/commands/test_create_command.rb +53 -0
- data/test/commands/test_delete_command.rb +28 -0
- data/test/commands/test_info_command.rb +28 -0
- data/test/commands/test_login_command.rb +56 -0
- data/test/commands/test_logout_command.rb +22 -0
- data/test/commands/test_poll_command.rb +54 -0
- data/test/commands/test_renew_command.rb +39 -0
- data/test/commands/test_transfer_command.rb +37 -0
- data/test/commands/test_update_command.rb +60 -0
- data/test/contact/test_contact_check.rb +33 -0
- data/test/contact/test_contact_check_response.rb +88 -0
- data/test/contact/test_contact_create.rb +71 -0
- data/test/contact/test_contact_create_response.rb +33 -0
- data/test/contact/test_contact_delete.rb +28 -0
- data/test/contact/test_contact_delete_response.rb +23 -0
- data/test/contact/test_contact_info.rb +28 -0
- data/test/contact/test_contact_info_response.rb +100 -0
- data/test/contact/test_contact_transfer.rb +28 -0
- data/test/contact/test_contact_transfer_response.rb +100 -0
- data/test/contact/test_contact_update.rb +84 -0
- data/test/contact/test_contact_update_response.rb +23 -0
- data/test/domain/test_domain_check.rb +33 -0
- data/test/domain/test_domain_check_response.rb +88 -0
- data/test/domain/test_domain_create.rb +108 -0
- data/test/domain/test_domain_create_response.rb +70 -0
- data/test/domain/test_domain_delete.rb +28 -0
- data/test/domain/test_domain_delete_response.rb +23 -0
- data/test/domain/test_domain_info.rb +28 -0
- data/test/domain/test_domain_info_response.rb +146 -0
- data/test/domain/test_domain_renew.rb +91 -0
- data/test/domain/test_domain_renew_response.rb +32 -0
- data/test/domain/test_domain_transfer.rb +89 -0
- data/test/domain/test_domain_transfer_response.rb +112 -0
- data/test/domain/test_domain_update.rb +73 -0
- data/test/domain/test_domain_update_response.rb +23 -0
- data/test/fixtures/responses/contact/check-single.xml +20 -0
- data/test/fixtures/responses/contact/check.xml +27 -0
- data/test/fixtures/responses/contact/create.xml +19 -0
- data/test/fixtures/responses/contact/delete.xml +12 -0
- data/test/fixtures/responses/contact/info.xml +49 -0
- data/test/fixtures/responses/contact/transfer-query.xml +23 -0
- data/test/fixtures/responses/contact/transfer-request.xml +23 -0
- data/test/fixtures/responses/contact/update.xml +12 -0
- data/test/fixtures/responses/domain/check-single.xml +20 -0
- data/test/fixtures/responses/domain/check.xml +27 -0
- data/test/fixtures/responses/domain/create-pending.xml +12 -0
- data/test/fixtures/responses/domain/create.xml +20 -0
- data/test/fixtures/responses/domain/delete.xml +12 -0
- data/test/fixtures/responses/domain/info-no-exDate.xml +38 -0
- data/test/fixtures/responses/domain/info-ns-hostAttr-name-only.xml +34 -0
- data/test/fixtures/responses/domain/info-ns-hostAttr.xml +38 -0
- data/test/fixtures/responses/domain/info.xml +40 -0
- data/test/fixtures/responses/domain/renew.xml +19 -0
- data/test/fixtures/responses/domain/transfer-query.xml +24 -0
- data/test/fixtures/responses/domain/transfer-request.xml +24 -0
- data/test/fixtures/responses/domain/update.xml +12 -0
- data/test/fixtures/responses/greeting.xml +25 -0
- data/test/fixtures/responses/host/check-single.xml +20 -0
- data/test/fixtures/responses/host/check.xml +27 -0
- data/test/fixtures/responses/host/create.xml +19 -0
- data/test/fixtures/responses/host/delete.xml +12 -0
- data/test/fixtures/responses/host/info.xml +30 -0
- data/test/fixtures/responses/host/update.xml +12 -0
- data/test/helper.rb +100 -0
- data/test/host/test_host_check.rb +33 -0
- data/test/host/test_host_check_response.rb +88 -0
- data/test/host/test_host_create.rb +37 -0
- data/test/host/test_host_create_response.rb +33 -0
- data/test/host/test_host_delete.rb +28 -0
- data/test/host/test_host_delete_response.rb +23 -0
- data/test/host/test_host_info.rb +28 -0
- data/test/host/test_host_info_response.rb +72 -0
- data/test/host/test_host_update.rb +68 -0
- data/test/host/test_host_update_response.rb +23 -0
- data/test/requests/test_command_request.rb +16 -0
- data/test/requests/test_extension_request.rb +55 -0
- data/test/requests/test_hello_request.rb +15 -0
- data/test/support/schemas/all.xsd +21 -0
- data/test/support/schemas/contact-1.0.xsd +387 -0
- data/test/support/schemas/domain-1.0.xsd +432 -0
- data/test/support/schemas/epp-1.0.xsd +403 -0
- data/test/support/schemas/eppcom-1.0.xsd +93 -0
- data/test/support/schemas/host-1.0.xsd +240 -0
- data/test/test_client.rb +64 -0
- data/test/test_request.rb +15 -0
- data/test/test_server.rb +67 -0
- metadata +322 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
module EPP
|
|
2
|
+
# An EPP XML Response
|
|
3
|
+
class Response
|
|
4
|
+
# Creates an instance of an EPP::Response
|
|
5
|
+
#
|
|
6
|
+
# @param [String] xml_string XML Response
|
|
7
|
+
def initialize(xml_string)
|
|
8
|
+
@xml = XML::Parser.string(xml_string).parse
|
|
9
|
+
@xml.root.namespaces.default_prefix = 'e'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Indicates if the response is successful.
|
|
13
|
+
# @return [Boolean] if the response is successful
|
|
14
|
+
def success?
|
|
15
|
+
code == 1000
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def pending?
|
|
19
|
+
code == 1001
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Response code
|
|
23
|
+
# @return [Integer] response code
|
|
24
|
+
def code
|
|
25
|
+
@code ||= result['code'].to_i
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Response message
|
|
29
|
+
# @return [String] response message
|
|
30
|
+
def message
|
|
31
|
+
@message ||= result.find('e:msg/text()').first.content.strip
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Descriptive Error Information
|
|
35
|
+
# @return [XML::Node] error information
|
|
36
|
+
def error_value
|
|
37
|
+
@error_value ||= result.find('e:extValue/e:value/node()').first
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Error reason
|
|
41
|
+
# @return [String] error reason
|
|
42
|
+
def error_reason
|
|
43
|
+
unless defined?(@error_reason)
|
|
44
|
+
reason = result.find('e:extValue/e:reason/text()').first
|
|
45
|
+
@error_reason = reason && reason.content.strip
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
@error_reason
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Response data
|
|
52
|
+
# @return [XML::Node, Array<XML::Node>] response data
|
|
53
|
+
def data
|
|
54
|
+
@data ||= begin
|
|
55
|
+
list = @xml.find('/e:epp/e:response/e:resData/node()').reject { |n| n.empty? }
|
|
56
|
+
list.size > 1 ? list : list[0]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Response Message Queue
|
|
61
|
+
# @return [XML::Node] message queue
|
|
62
|
+
def msgQ
|
|
63
|
+
@msgQ ||= @xml.find('/e:epp/e:response/e:msgQ').first
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Response extension block
|
|
67
|
+
# @return [XML::Node, Array<XML::Node>] extension
|
|
68
|
+
def extension
|
|
69
|
+
@extension ||= begin
|
|
70
|
+
list = @xml.find('/e:epp/e:response/e:extension/node()').reject { |n| n.empty? }
|
|
71
|
+
list.size > 1 ? list : list[0]
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @see Object#inspect
|
|
76
|
+
def inspect
|
|
77
|
+
@xml.inspect
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Returns the XML response document
|
|
81
|
+
# @return [XML::Document] XML response document
|
|
82
|
+
def to_xml
|
|
83
|
+
@xml
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Convert the receiver to a string
|
|
87
|
+
#
|
|
88
|
+
# @param [Hash] opts Formatting options, passed to the XML::Document
|
|
89
|
+
# @return [String] formatted XML response
|
|
90
|
+
def to_s(opts = {})
|
|
91
|
+
@xml.to_s({:indent => false}.merge(opts))
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
# @return [XML::Node] Result node
|
|
96
|
+
def result
|
|
97
|
+
@result ||= @xml.find('/e:epp/e:response/e:result').first
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module EPP
|
|
2
|
+
# Error response
|
|
3
|
+
class ResponseError < RuntimeError
|
|
4
|
+
attr_accessor :code, :xml
|
|
5
|
+
# Create new ResponseError
|
|
6
|
+
def initialize(code, msg, xml)
|
|
7
|
+
super(msg)
|
|
8
|
+
@code, @xml = code, xml
|
|
9
|
+
end
|
|
10
|
+
# @return [String] Formatted Response error
|
|
11
|
+
def message
|
|
12
|
+
"#{to_s} (code #{code})"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module EPP
|
|
2
|
+
module ResponseHelper
|
|
3
|
+
def value_for_xpath(xpath, base = nil, &block)
|
|
4
|
+
values_for_xpath(xpath, base, &block).first
|
|
5
|
+
end
|
|
6
|
+
def values_for_xpath(xpath, base = nil)
|
|
7
|
+
nodes_for_xpath(xpath, base).map do |node|
|
|
8
|
+
if block_given?
|
|
9
|
+
yield node
|
|
10
|
+
else
|
|
11
|
+
case node
|
|
12
|
+
when XML::Node
|
|
13
|
+
node.content.strip
|
|
14
|
+
when XML::Attr
|
|
15
|
+
node.value
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
def nodes_for_xpath(xpath, base = nil)
|
|
21
|
+
base ||= @response.data
|
|
22
|
+
base.find(xpath, namespaces)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
module EPP
|
|
2
|
+
# A server error
|
|
3
|
+
class ServerError < Error; end
|
|
4
|
+
|
|
5
|
+
# A connection error
|
|
6
|
+
class ConnectionError < Error
|
|
7
|
+
attr_reader :error, :addr, :peeraddr
|
|
8
|
+
def initialize(message, addr, peeraddr, error)
|
|
9
|
+
super(message)
|
|
10
|
+
@error = error
|
|
11
|
+
@addr = addr
|
|
12
|
+
@peeraddr = peeraddr
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Handles sending and receiving data to EPP servers.
|
|
17
|
+
# Supports new style EPP servers which include length of payloads in transmission.
|
|
18
|
+
class Server
|
|
19
|
+
# @!attribute DEFAULT_SERVICES
|
|
20
|
+
# Provided for legacy clients who might be using it.
|
|
21
|
+
# The constant has been moved into the EPP::Client class which
|
|
22
|
+
# is the primary client facing API.
|
|
23
|
+
#
|
|
24
|
+
# @deprecated please use EPP::Client::DEFAULT_SERVICES
|
|
25
|
+
# @see EPP::Client::DEFAULT_SERVICES
|
|
26
|
+
|
|
27
|
+
# Handles emitting warnings for deprecated constants.
|
|
28
|
+
#
|
|
29
|
+
# @private
|
|
30
|
+
# @param [Symbol] const_name Name of the missing constant
|
|
31
|
+
# @see Module.const_missing
|
|
32
|
+
def self.const_missing(const_name)
|
|
33
|
+
case const_name
|
|
34
|
+
when :DEFAULT_SERVICES
|
|
35
|
+
warn "EPP::Server::DEFAULT_SERVICES has been deprecated, please use EPP::Client::DEFAULT_SERVICES"
|
|
36
|
+
EPP::Client::DEFAULT_SERVICES
|
|
37
|
+
else
|
|
38
|
+
super
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Default connection options
|
|
43
|
+
DEFAULTS = { :port => 700, :compatibility => false, :lang => 'en', :version => '1.0',
|
|
44
|
+
:extensions => [], :services => EPP::Client::DEFAULT_SERVICES, :address_family => nil }
|
|
45
|
+
|
|
46
|
+
# Receive frame header length
|
|
47
|
+
# @private
|
|
48
|
+
HEADER_LEN = 4
|
|
49
|
+
|
|
50
|
+
# @param [String] tag EPP Tag
|
|
51
|
+
# @param [String] passwd EPP Tag password
|
|
52
|
+
# @param [String] host EPP Server address
|
|
53
|
+
# @param [Hash] options configuration options
|
|
54
|
+
# @option options [Integer] :port EPP Port number, default 700
|
|
55
|
+
# @option options [OpenSSL::SSL::SSLContext] :ssl_context For client certificate auth
|
|
56
|
+
# @option options [Boolean] :compatibility Compatibility mode, default false
|
|
57
|
+
# @option options [String] :lang EPP Language code, default 'en'
|
|
58
|
+
# @option options [String] :version EPP protocol version, default '1.0'
|
|
59
|
+
# @option options [Array<String>] :extensions EPP Extension URNs
|
|
60
|
+
# @option options [Array<String>] :services EPP Service URNs
|
|
61
|
+
# @option options [String] :address_family 'AF_INET' or 'AF_INET6' or either of the
|
|
62
|
+
# appropriate socket constants. Will cause connections to be
|
|
63
|
+
# limited to this address family. Default try all addresses.
|
|
64
|
+
|
|
65
|
+
def initialize(tag, passwd, host, options = {})
|
|
66
|
+
@tag, @passwd, @host = tag, passwd, host
|
|
67
|
+
@options = DEFAULTS.merge(options)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Sends a Hello Request to the server
|
|
71
|
+
# @return [Boolean] True if greeting was returned
|
|
72
|
+
def hello
|
|
73
|
+
hello = EPP::Requests::Hello.new
|
|
74
|
+
request = EPP::Request.new(hello)
|
|
75
|
+
send_frame(request)
|
|
76
|
+
return true if recv_frame =~ /<greeting>/
|
|
77
|
+
false
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Send request to server
|
|
81
|
+
#
|
|
82
|
+
# @overload request(command, payload)
|
|
83
|
+
# @param [String, #to_s] command EPP Command to call
|
|
84
|
+
# @param [XML::Node, XML::Document, String] payload EPP XML Payload
|
|
85
|
+
# @overload request(command)
|
|
86
|
+
# @param [String, #to_s] command EPP Command to call
|
|
87
|
+
# @yield [xml] block to construct payload
|
|
88
|
+
# @yieldparam [XML::Node] xml XML Node of the command
|
|
89
|
+
# for the payload to be added into
|
|
90
|
+
# @return [Response] EPP Response object
|
|
91
|
+
# def request(command, payload = nil, extension = nil, &block)
|
|
92
|
+
# @req = if payload.nil? && block_given?
|
|
93
|
+
# Request.new(command, req_tid, &block)
|
|
94
|
+
# else
|
|
95
|
+
# Request.new(command, payload, extension, req_tid)
|
|
96
|
+
# end
|
|
97
|
+
#
|
|
98
|
+
# @resp = send_recv_frame(@req)
|
|
99
|
+
# end
|
|
100
|
+
|
|
101
|
+
# @note Primarily an internal method, exposed to enable testing
|
|
102
|
+
# @param [] command
|
|
103
|
+
# @param [] extension
|
|
104
|
+
# @return [EPP::Request]
|
|
105
|
+
# @see request
|
|
106
|
+
def prepare_request(command, extension = nil)
|
|
107
|
+
cmd = EPP::Requests::Command.new(req_tid, command, extension)
|
|
108
|
+
EPP::Request.new(cmd)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def request(command, extension = nil)
|
|
112
|
+
@req = command.is_a?(EPP::Request) ? command :
|
|
113
|
+
prepare_request(command, extension)
|
|
114
|
+
|
|
115
|
+
@resp = send_recv_frame(@req)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Return the Request object created by the last call to #request
|
|
119
|
+
#
|
|
120
|
+
# @return [Request] Last created EPP Request object
|
|
121
|
+
def last_request
|
|
122
|
+
@req
|
|
123
|
+
end
|
|
124
|
+
# Return the Response object created by the last call to #request
|
|
125
|
+
#
|
|
126
|
+
# @return [Response] Last created EPP Response object
|
|
127
|
+
def last_response
|
|
128
|
+
@resp
|
|
129
|
+
end
|
|
130
|
+
# Return the error from the last login or logout request
|
|
131
|
+
#
|
|
132
|
+
# @return [ResponseError] last error from login or logout
|
|
133
|
+
def last_error
|
|
134
|
+
@error
|
|
135
|
+
end
|
|
136
|
+
# Return the options the receiver was initialized with
|
|
137
|
+
#
|
|
138
|
+
# @return [Hash] configuration options
|
|
139
|
+
def options
|
|
140
|
+
@options
|
|
141
|
+
end
|
|
142
|
+
# Return the greeting XML received during the last connection
|
|
143
|
+
#
|
|
144
|
+
# @return [String]
|
|
145
|
+
def greeting
|
|
146
|
+
@greeting
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Runs a block while logged into the receiver
|
|
150
|
+
#
|
|
151
|
+
# @yield logged in EPP server session
|
|
152
|
+
# @example typical usage
|
|
153
|
+
# connection do
|
|
154
|
+
# with_login do
|
|
155
|
+
# # .. do stuff with logged in session ..
|
|
156
|
+
# end
|
|
157
|
+
# end
|
|
158
|
+
def with_login
|
|
159
|
+
login!
|
|
160
|
+
|
|
161
|
+
begin
|
|
162
|
+
yield
|
|
163
|
+
ensure
|
|
164
|
+
logout!
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# EPP Server Connection
|
|
169
|
+
#
|
|
170
|
+
# @yield connected session
|
|
171
|
+
# @example typical usage
|
|
172
|
+
# connection do
|
|
173
|
+
# # .. do stuff with logged in session ..
|
|
174
|
+
# end
|
|
175
|
+
# @example usage with with_login
|
|
176
|
+
# connection do
|
|
177
|
+
# with_login do
|
|
178
|
+
# # .. do stuff with logged in session ..
|
|
179
|
+
# end
|
|
180
|
+
# end
|
|
181
|
+
def connection
|
|
182
|
+
@connection_errors = []
|
|
183
|
+
addrinfo.each do |_,port,_,addr,_,_,_|
|
|
184
|
+
retried = false
|
|
185
|
+
begin
|
|
186
|
+
@conn = TCPSocket.new(addr, port)
|
|
187
|
+
rescue Errno::EINVAL => e
|
|
188
|
+
if retried
|
|
189
|
+
message = e.message.split(" - ")[1]
|
|
190
|
+
@connection_errors << Errno::EINVAL.new(
|
|
191
|
+
"#{message}: TCPSocket.new(#{addr.inspect}, #{port.inspect})")
|
|
192
|
+
next
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
retried = true
|
|
196
|
+
retry
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
args = [@conn]
|
|
200
|
+
args << options[:ssl_context] if options[:ssl_context]
|
|
201
|
+
@sock = OpenSSL::SSL::SSLSocket.new(*args)
|
|
202
|
+
@sock.sync_close = true
|
|
203
|
+
|
|
204
|
+
begin
|
|
205
|
+
@sock.connect
|
|
206
|
+
@greeting = recv_frame # Perform initial recv
|
|
207
|
+
|
|
208
|
+
return yield
|
|
209
|
+
rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EHOSTUNREACH => e
|
|
210
|
+
@connection_errors << e
|
|
211
|
+
next # try the next address in the list
|
|
212
|
+
rescue OpenSSL::SSL::SSLError => e
|
|
213
|
+
# Connection error, most likely the IP isn't in the allow list
|
|
214
|
+
if e.message =~ /returned=5 errno=0/
|
|
215
|
+
@connection_errors << ConnectionError.new("SSL Connection error, IP may not be permitted to connect to #{@host}",
|
|
216
|
+
@conn.addr, @conn.peeraddr, e)
|
|
217
|
+
next
|
|
218
|
+
else
|
|
219
|
+
raise e
|
|
220
|
+
end
|
|
221
|
+
ensure
|
|
222
|
+
@sock.close # closes @conn
|
|
223
|
+
@conn = @sock = nil
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Should only get here if we didn't return from the block above
|
|
228
|
+
|
|
229
|
+
addrinfo(true) # Update our addrinfo in case the DNS has changed
|
|
230
|
+
raise @connection_errors.last unless @connection_errors.empty?
|
|
231
|
+
raise Errno::EHOSTUNREACH, "Failed to connect to host #{@host}"
|
|
232
|
+
end
|
|
233
|
+
private
|
|
234
|
+
def addrinfo(refresh = false)
|
|
235
|
+
@addrinfo = nil if refresh
|
|
236
|
+
@addrinfo ||= resolve_addrinfo
|
|
237
|
+
end
|
|
238
|
+
def resolve_addrinfo
|
|
239
|
+
family = case @options[:address_family]
|
|
240
|
+
when 'AF_INET', Socket::AF_INET then Socket::AF_INET
|
|
241
|
+
when 'AF_INET6', Socket::AF_INET6 then Socket::AF_INET6
|
|
242
|
+
else nil end
|
|
243
|
+
|
|
244
|
+
Socket.getaddrinfo(@host, @options[:port], family, Socket::SOCK_STREAM)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# @return [String] next transaction id
|
|
248
|
+
def req_tid
|
|
249
|
+
@req_tid ||= 0
|
|
250
|
+
@req_tid += 1
|
|
251
|
+
date = Time.now.strftime("%Y%m%d")
|
|
252
|
+
"%s-%s%06d" % [@tag, date, @req_tid]
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# @return [String] next auth transaction id
|
|
256
|
+
def auth_tid
|
|
257
|
+
@auth_tid ||= 0
|
|
258
|
+
@auth_tid += 1
|
|
259
|
+
date = Time.now.strftime("%Y%m%d")
|
|
260
|
+
"%s-AUTH-%s%06d" % [@tag, date, @auth_tid]
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# Perform login
|
|
264
|
+
#
|
|
265
|
+
# @return [true] login successful
|
|
266
|
+
# @raise [ResponseError] login failed
|
|
267
|
+
# @see login_request
|
|
268
|
+
def login!
|
|
269
|
+
@error = nil
|
|
270
|
+
login = EPP::Commands::Login.new(@tag, @passwd, @options)
|
|
271
|
+
command = EPP::Requests::Command.new(auth_tid, login)
|
|
272
|
+
request = EPP::Request.new(command)
|
|
273
|
+
response = send_recv_frame(request)
|
|
274
|
+
|
|
275
|
+
return true if response.code == 1000
|
|
276
|
+
raise @error = ResponseError.new(response.code, response.message, response.to_xml)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Perform logout
|
|
280
|
+
#
|
|
281
|
+
# @return [true] logout successful
|
|
282
|
+
# @raise [ResponseError] logout failed
|
|
283
|
+
# @see logout_request
|
|
284
|
+
def logout!
|
|
285
|
+
logout = EPP::Commands::Logout.new
|
|
286
|
+
command = EPP::Requests::Command.new(auth_tid, logout)
|
|
287
|
+
request = EPP::Request.new(command)
|
|
288
|
+
response = send_recv_frame(request)
|
|
289
|
+
|
|
290
|
+
return true if response.code == 1500
|
|
291
|
+
raise @error = ResponseError.new(response.code, response.message, response.to_xml)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Send a frame and receive its response
|
|
295
|
+
#
|
|
296
|
+
# @param [String] xml XML Payload to send
|
|
297
|
+
# @return [Response] EPP Response
|
|
298
|
+
# @see send_frame
|
|
299
|
+
# @see recv_frame
|
|
300
|
+
def send_recv_frame(xml)
|
|
301
|
+
send_frame(xml)
|
|
302
|
+
Response.new(recv_frame)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Send XML frame
|
|
306
|
+
# @param [String,Request] xml Payload to send
|
|
307
|
+
# @return [Integer] number of bytes written
|
|
308
|
+
def send_frame(xml)
|
|
309
|
+
xml = xml.to_s if xml.kind_of?(Request)
|
|
310
|
+
@sock.write([xml.size + HEADER_LEN].pack("N") + xml)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# Receive XML frame
|
|
314
|
+
# @return [String] XML response
|
|
315
|
+
def recv_frame
|
|
316
|
+
header = @sock.read(HEADER_LEN)
|
|
317
|
+
|
|
318
|
+
if header.nil? && @sock.eof?
|
|
319
|
+
raise ServerError, "Connection terminated by remote host"
|
|
320
|
+
elsif header.nil?
|
|
321
|
+
raise ServerError, "Failed to read header from remote host"
|
|
322
|
+
else
|
|
323
|
+
len = header.unpack('N')[0]
|
|
324
|
+
|
|
325
|
+
raise ServerError, "Bad frame header from server, should be greater than #{HEADER_LEN}" unless len > HEADER_LEN
|
|
326
|
+
@sock.read(len - HEADER_LEN)
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require 'epp-client'
|
|
2
|
+
|
|
3
|
+
module EPP
|
|
4
|
+
class Client
|
|
5
|
+
# Request Preparation Methods
|
|
6
|
+
def check_prepare(payload, extension = nil)
|
|
7
|
+
check = EPP::Commands::Check.new(payload)
|
|
8
|
+
prepare_request(check, extension)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def create_prepare(payload, extension = nil)
|
|
12
|
+
create = EPP::Commands::Create.new(payload)
|
|
13
|
+
prepare_request(create, extension)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def delete_prepare(payload, extension = nil)
|
|
17
|
+
delete = EPP::Commands::Delete.new(payload)
|
|
18
|
+
prepare_request(delete, extension)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def info_prepare(payload, extension = nil)
|
|
22
|
+
info = EPP::Commands::Info.new(payload)
|
|
23
|
+
prepare_request(info, extension)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def renew_prepare(payload, extension = nil)
|
|
27
|
+
renew = EPP::Commands::Renew.new(payload)
|
|
28
|
+
prepare_request(renew, extension)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def transfer_prepare(op, payload, extension = nil)
|
|
32
|
+
transfer = EPP::Commands::Transfer.new(op, payload)
|
|
33
|
+
prepare_request(transfer, extension)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def update_prepare(payload, extension = nil)
|
|
37
|
+
update = EPP::Commands::Update.new(payload)
|
|
38
|
+
prepare_request(update, extension)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def poll_prepare
|
|
42
|
+
poll = EPP::Commands::Poll.new
|
|
43
|
+
prepare_request(poll)
|
|
44
|
+
end
|
|
45
|
+
def ack_prepare(msgID)
|
|
46
|
+
ack = EPP::Commands::Poll.new(msgID)
|
|
47
|
+
prepare_request(ack)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def prepare_request(cmd, extension = nil)
|
|
51
|
+
@conn.prepare_request(cmd, extension)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Response Preparation Methods
|
|
55
|
+
def load_response(xml_data)
|
|
56
|
+
EPP::Response.new(xml_data)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module EPP
|
|
2
|
+
module XMLHelpers
|
|
3
|
+
# Creates and returns an instance of the EPP 1.0 namespace
|
|
4
|
+
#
|
|
5
|
+
# @param [XML::Node] node to create the namespace on
|
|
6
|
+
# @param [String, nil] Name to give the namespace
|
|
7
|
+
# @return [XML::Namespace] EPP 1.0 namespace
|
|
8
|
+
def epp_namespace(node, name = nil, namespaces = {})
|
|
9
|
+
return namespaces['epp'] if namespaces.has_key?('epp')
|
|
10
|
+
xml_namespace(node, name, 'urn:ietf:params:xml:ns:epp-1.0')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Creates and returns a new node in the EPP 1.0 namespace
|
|
14
|
+
#
|
|
15
|
+
# @param [String] name of the node to create
|
|
16
|
+
# @param [String,XML::Node,nil] value of the node
|
|
17
|
+
# @return [XML::Node]
|
|
18
|
+
def epp_node(name, value = nil, namespaces = {})
|
|
19
|
+
value, namespaces = nil, value if value.kind_of?(Hash)
|
|
20
|
+
|
|
21
|
+
node = xml_node(name, value)
|
|
22
|
+
node.namespaces.namespace = epp_namespace(node, nil, namespaces)
|
|
23
|
+
node
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Creates and returns a new XML node
|
|
27
|
+
#
|
|
28
|
+
# @param [String] name of the node to create
|
|
29
|
+
# @param [String,XML::Node,nil] value of the node
|
|
30
|
+
# @return [XML::Node]
|
|
31
|
+
def xml_node(name, value = nil)
|
|
32
|
+
XML::Node.new(name, value)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Creates and returns a new XML namespace
|
|
36
|
+
#
|
|
37
|
+
# @param [XML::Node] node XML node to add the namespace to
|
|
38
|
+
# @param [String] name Name of the namespace to create
|
|
39
|
+
# @param [String] uri URI of the namespace to create
|
|
40
|
+
# @return [XML::Namespace]
|
|
41
|
+
def xml_namespace(node, name, uri, namespaces = {})
|
|
42
|
+
XML::Namespace.new(node, name, uri)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Creates and returns a new XML document
|
|
46
|
+
#
|
|
47
|
+
# @param [XML::Document,String] obj Object to create the document with
|
|
48
|
+
# @return [XML::Document]
|
|
49
|
+
def xml_document(obj)
|
|
50
|
+
case obj
|
|
51
|
+
when XML::Document
|
|
52
|
+
XML::Document.document(obj)
|
|
53
|
+
else
|
|
54
|
+
XML::Document.new('1.0')
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def as_xml(obj)
|
|
59
|
+
return obj.to_xml if obj.respond_to?(:to_xml)
|
|
60
|
+
|
|
61
|
+
case obj
|
|
62
|
+
when String
|
|
63
|
+
XML::Document.string(obj).root
|
|
64
|
+
when XML::Node
|
|
65
|
+
obj
|
|
66
|
+
when XML::Document
|
|
67
|
+
obj.root
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|