epp-client-base 0.11.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.
- data/ChangeLog +5 -0
- data/Gemfile +6 -0
- data/MIT-LICENSE +19 -0
- data/README +5 -0
- data/Rakefile +37 -0
- data/epp-client-base.gemspec +54 -0
- data/lib/epp-client/base.rb +113 -0
- data/lib/epp-client/connection.rb +78 -0
- data/lib/epp-client/contact.rb +398 -0
- data/lib/epp-client/domain.rb +394 -0
- data/lib/epp-client/exceptions.rb +21 -0
- data/lib/epp-client/poll.rb +69 -0
- data/lib/epp-client/session.rb +56 -0
- data/lib/epp-client/ssl.rb +46 -0
- data/lib/epp-client/version.rb +3 -0
- data/lib/epp-client/xml.rb +150 -0
- data/vendor/ietf/contact-1.0.xsd +388 -0
- data/vendor/ietf/domain-1.0.xsd +430 -0
- data/vendor/ietf/epp-1.0.xsd +444 -0
- data/vendor/ietf/eppcom-1.0.xsd +105 -0
- data/vendor/ietf/host-1.0.xsd +240 -0
- data/vendor/ietf/rfc4310.txt +1235 -0
- data/vendor/ietf/rfc5730.txt +3755 -0
- data/vendor/ietf/rfc5731.txt +2467 -0
- data/vendor/ietf/rfc5732.txt +1627 -0
- data/vendor/ietf/rfc5733.txt +2299 -0
- data/vendor/ietf/rfc5734.txt +731 -0
- data/vendor/ietf/rfc5910.txt +2019 -0
- metadata +143 -0
@@ -0,0 +1,394 @@
|
|
1
|
+
module EPPClient
|
2
|
+
module Domain
|
3
|
+
EPPClient::Poll::PARSERS['domain:panData'] = :domain_pending_action_process
|
4
|
+
|
5
|
+
def domain_check_xml(*domains) # :nodoc:
|
6
|
+
command do |xml|
|
7
|
+
xml.check do
|
8
|
+
xml.check('xmlns' => EPPClient::SCHEMAS_URL['domain-1.0']) do
|
9
|
+
domains.each do |dom|
|
10
|
+
xml.name(dom)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Check the availability of domains
|
18
|
+
#
|
19
|
+
# takes a list of domains as arguments
|
20
|
+
#
|
21
|
+
# returns an array of hashes containing three fields :
|
22
|
+
# [<tt>:name</tt>] The domain name
|
23
|
+
# [<tt>:avail</tt>] Wether the domain is available or not.
|
24
|
+
# [<tt>:reason</tt>] The reason for non availability, if given.
|
25
|
+
def domain_check(*domains)
|
26
|
+
domains.flatten!
|
27
|
+
response = send_request(domain_check_xml(*domains))
|
28
|
+
|
29
|
+
get_result(:xml => response, :callback => :domain_check_process)
|
30
|
+
end
|
31
|
+
|
32
|
+
def domain_check_process(xml) # :nodoc:
|
33
|
+
xml.xpath('epp:resData/domain:chkData/domain:cd', EPPClient::SCHEMAS_URL).map do |dom|
|
34
|
+
ret = {
|
35
|
+
:name => dom.xpath('domain:name', EPPClient::SCHEMAS_URL).text,
|
36
|
+
:avail => dom.xpath('domain:name', EPPClient::SCHEMAS_URL).attr('avail').value == '1',
|
37
|
+
}
|
38
|
+
unless (reason = dom.xpath('domain:reason', EPPClient::SCHEMAS_URL).text).empty?
|
39
|
+
ret[:reason] = reason
|
40
|
+
end
|
41
|
+
ret
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def domain_info_xml(args) # :nodoc:
|
46
|
+
command do |xml|
|
47
|
+
xml.info do
|
48
|
+
xml.info('xmlns' => EPPClient::SCHEMAS_URL['domain-1.0']) do
|
49
|
+
xml.name(args[:name])
|
50
|
+
if args.key?(:authInfo)
|
51
|
+
xml.authInfo do
|
52
|
+
if args.key?(:roid)
|
53
|
+
xml.pw({:roid => args[:roid]}, args[:authInfo])
|
54
|
+
else
|
55
|
+
xml.pw(args[:authInfo])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns the informations about a domain
|
65
|
+
#
|
66
|
+
# Takes either a unique argument, a string, representing the domain, or a
|
67
|
+
# hash with : <tt>:name</tt> the domain name, and optionnaly
|
68
|
+
# <tt>:authInfo</tt> the authentication information and possibly
|
69
|
+
# <tt>:roid</tt> the contact the authInfo is about.
|
70
|
+
#
|
71
|
+
# Returned is a hash mapping as closely as possible the result expected
|
72
|
+
# from the command as per Section 3.1.2 of RFC 5731 :
|
73
|
+
# [<tt>:name</tt>] The fully qualified name of the domain object.
|
74
|
+
# [<tt>:roid</tt>]
|
75
|
+
# The Repository Object IDentifier assigned to the domain object when
|
76
|
+
# the object was created.
|
77
|
+
# [<tt>:status</tt>]
|
78
|
+
# an optionnal array of elements that contain the current status
|
79
|
+
# descriptors associated with the domain.
|
80
|
+
# [<tt>:registrant</tt>] one optionnal registrant nic handle.
|
81
|
+
# [<tt>:contacts</tt>]
|
82
|
+
# an optionnal hash which keys are choosen between +admin+, +billing+ and
|
83
|
+
# +tech+ and which values are arrays of nic handles for the corresponding
|
84
|
+
# contact types.
|
85
|
+
# [<tt>:ns</tt>]
|
86
|
+
# an optional array containing nameservers informations, which can either
|
87
|
+
# be an array of strings containing the the fully qualified name of a
|
88
|
+
# host, or an array of hashes containing the following keys :
|
89
|
+
# [<tt>:hostName</tt>] the fully qualified name of a host.
|
90
|
+
# [<tt>:hostAddrv4</tt>]
|
91
|
+
# an optionnal array of ipv4 addresses to be associated with the host.
|
92
|
+
# [<tt>:hostAddrv6</tt>]
|
93
|
+
# an optionnal array of ipv6 addresses to be associated with the host.
|
94
|
+
# [<tt>:host</tt>]
|
95
|
+
# an optionnal array of fully qualified names of the subordinate host
|
96
|
+
# objects that exist under this superordinate domain object.
|
97
|
+
# [<tt>:clID</tt>] the identifier of the sponsoring client.
|
98
|
+
# [<tt>:crID</tt>]
|
99
|
+
# an optional identifier of the client that created the domain object.
|
100
|
+
# [<tt>:crDate</tt>] an optional date and time of domain object creation.
|
101
|
+
# [<tt>:exDate</tt>]
|
102
|
+
# the date and time identifying the end of the domain object's
|
103
|
+
# registration period.
|
104
|
+
# [<tt>:upID</tt>]
|
105
|
+
# the identifier of the client that last updated the domain object.
|
106
|
+
# [<tt>:upDate</tt>]
|
107
|
+
# the date and time of the most recent domain-object modification.
|
108
|
+
# [<tt>:trDate</tt>]
|
109
|
+
# the date and time of the most recent successful domain-object transfer.
|
110
|
+
# [<tt>:authInfo</tt>]
|
111
|
+
# authorization information associated with the domain object.
|
112
|
+
def domain_info(args)
|
113
|
+
if String === args
|
114
|
+
args = {:name => args}
|
115
|
+
end
|
116
|
+
response = send_request(domain_info_xml(args))
|
117
|
+
|
118
|
+
get_result(:xml => response, :callback => :domain_info_process)
|
119
|
+
end
|
120
|
+
|
121
|
+
def domain_info_process(xml) # :nodoc:
|
122
|
+
dom = xml.xpath('epp:resData/domain:infData', EPPClient::SCHEMAS_URL)
|
123
|
+
ret = {
|
124
|
+
:name => dom.xpath('domain:name', EPPClient::SCHEMAS_URL).text,
|
125
|
+
:roid => dom.xpath('domain:roid', EPPClient::SCHEMAS_URL).text,
|
126
|
+
}
|
127
|
+
if (status = dom.xpath('domain:status', EPPClient::SCHEMAS_URL)).size > 0
|
128
|
+
ret[:status] = status.map {|s| s.attr('s')}
|
129
|
+
end
|
130
|
+
if (registrant = dom.xpath('domain:registrant', EPPClient::SCHEMAS_URL)).size > 0
|
131
|
+
ret[:registrant] = registrant.text
|
132
|
+
end
|
133
|
+
if (contact = dom.xpath('domain:contact', EPPClient::SCHEMAS_URL)).size > 0
|
134
|
+
ret[:contacts] = contact.inject({}) do |a,c|
|
135
|
+
s = c.attr('type').to_sym
|
136
|
+
a[s] ||= []
|
137
|
+
a[s] << c.text
|
138
|
+
a
|
139
|
+
end
|
140
|
+
end
|
141
|
+
if (ns = dom.xpath('domain:ns', EPPClient::SCHEMAS_URL)).size > 0
|
142
|
+
if (hostObj = ns.xpath('domain:hostObj', EPPClient::SCHEMAS_URL)).size > 0
|
143
|
+
ret[:ns] = hostObj.map {|h| h.text}
|
144
|
+
elsif (hostAttr = ns.xpath('domain:hostAttr', EPPClient::SCHEMAS_URL)).size > 0
|
145
|
+
ret[:ns] = hostAttr.map do |h|
|
146
|
+
r = { :hostName => h.xpath('domain:hostName', EPPClient::SCHEMAS_URL).text }
|
147
|
+
if (v4 = h.xpath('domain:hostAddr[@ip="v4"]', EPPClient::SCHEMAS_URL)).size > 0
|
148
|
+
r[:hostAddrv4] = v4.map {|v| v.text}
|
149
|
+
end
|
150
|
+
if (v6 = h.xpath('domain:hostAddr[@ip="v6"]', EPPClient::SCHEMAS_URL)).size > 0
|
151
|
+
r[:hostAddrv6] = v6.map {|v| v.text}
|
152
|
+
end
|
153
|
+
r
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
if (host = dom.xpath('domain:host', EPPClient::SCHEMAS_URL)).size > 0
|
158
|
+
ret[:host] = host.map {|h| h.text}
|
159
|
+
end
|
160
|
+
%w(clID upID).each do |val|
|
161
|
+
if (r = dom.xpath("domain:#{val}", EPPClient::SCHEMAS_URL)).size > 0
|
162
|
+
ret[val.to_sym] = r.text
|
163
|
+
end
|
164
|
+
end
|
165
|
+
%w(crDate exDate upDate trDate).each do |val|
|
166
|
+
if (r = dom.xpath("domain:#{val}", EPPClient::SCHEMAS_URL)).size > 0
|
167
|
+
ret[val.to_sym] = DateTime.parse(r.text)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
if (authInfo = dom.xpath('domain:authInfo', EPPClient::SCHEMAS_URL)).size > 0
|
171
|
+
ret[:authInfo] = authInfo.xpath('domain:pw', EPPClient::SCHEMAS_URL).text
|
172
|
+
end
|
173
|
+
return ret
|
174
|
+
end
|
175
|
+
|
176
|
+
def domain_nss_xml(xml, nss)
|
177
|
+
xml.ns do
|
178
|
+
if nss.first.is_a?(Hash)
|
179
|
+
nss.each do |ns|
|
180
|
+
xml.hostAttr do
|
181
|
+
xml.hostName ns[:hostName]
|
182
|
+
if ns.key?(:hostAddrv4)
|
183
|
+
ns[:hostAddrv4].each do |v4|
|
184
|
+
xml.hostAddr({:ip => :v4}, v4)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
if ns.key?(:hostAddrv6)
|
188
|
+
ns[:hostAddrv6].each do |v6|
|
189
|
+
xml.hostAddr({:ip => :v6}, v6)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
else
|
195
|
+
nss.each do |ns|
|
196
|
+
xml.hostObj ns
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def domain_contacts_xml(xml, args)
|
203
|
+
args.each do |type,contacts|
|
204
|
+
contacts.each do |c|
|
205
|
+
xml.contact({:type => type}, c)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def domain_create_xml(args) #:nodoc:
|
211
|
+
command do |xml|
|
212
|
+
xml.create do
|
213
|
+
xml.create('xmlns' => EPPClient::SCHEMAS_URL['domain-1.0']) do
|
214
|
+
xml.name args[:name]
|
215
|
+
|
216
|
+
if args.key?(:period)
|
217
|
+
xml.period({:unit => args[:period][:unit]}, args[:period][:number])
|
218
|
+
end
|
219
|
+
|
220
|
+
if args.key?(:ns)
|
221
|
+
domain_nss_xml(xml, args[:ns])
|
222
|
+
end
|
223
|
+
|
224
|
+
xml.registrant args[:registrant] if args.key?(:registrant)
|
225
|
+
|
226
|
+
if args.key?(:contacts)
|
227
|
+
domain_contacts_xml(xml, args[:contacts])
|
228
|
+
end
|
229
|
+
|
230
|
+
xml.authInfo do
|
231
|
+
xml.pw args[:authInfo]
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Creates a domain
|
239
|
+
#
|
240
|
+
# Takes a hash as an argument, containing the following keys :
|
241
|
+
#
|
242
|
+
# [<tt>:name</tt>] the domain name
|
243
|
+
# [<tt>:period</tt>]
|
244
|
+
# an optionnal hash containing the period for withch the domain is
|
245
|
+
# registered with the following keys :
|
246
|
+
# [<tt>:unit</tt>] the unit of time, either "m"onth or "y"ear.
|
247
|
+
# [<tt>:number</tt>] the number of unit of time.
|
248
|
+
# [<tt>:ns</tt>]
|
249
|
+
# an optional array containing nameservers informations, which can either
|
250
|
+
# be an array of strings containing the nameserver's hostname, or an
|
251
|
+
# array of hashes containing the following keys :
|
252
|
+
# [<tt>:hostName</tt>] the hostname of the nameserver.
|
253
|
+
# [<tt>:hostAddrv4</tt>] an optionnal array of ipv4 addresses.
|
254
|
+
# [<tt>:hostAddrv6</tt>] an optionnal array of ipv6 addresses.
|
255
|
+
# [<tt>:registrant</tt>] an optionnal registrant nic handle.
|
256
|
+
# [<tt>:contacts</tt>]
|
257
|
+
# an optionnal hash which keys are choosen between +admin+, +billing+ and
|
258
|
+
# +tech+ and which values are arrays of nic handles for the corresponding
|
259
|
+
# contact types.
|
260
|
+
# [<tt>:authInfo</tt>] the password associated with the domain.
|
261
|
+
#
|
262
|
+
# Returns a hash with the following keys :
|
263
|
+
#
|
264
|
+
# [<tt>:name</tt>] the fully qualified name of the domain object.
|
265
|
+
# [<tt>:crDate</tt>] the date and time of domain object creation.
|
266
|
+
# [<tt>:exDate</tt>]
|
267
|
+
# the date and time identifying the end of the domain object's
|
268
|
+
# registration period.
|
269
|
+
def domain_create(args)
|
270
|
+
response = send_request(domain_create_xml(args))
|
271
|
+
|
272
|
+
get_result(:xml => response, :callback => :domain_create_process)
|
273
|
+
end
|
274
|
+
|
275
|
+
def domain_create_process(xml) #:nodoc:
|
276
|
+
dom = xml.xpath('epp:resData/domain:creData', EPPClient::SCHEMAS_URL)
|
277
|
+
ret = {
|
278
|
+
:name => dom.xpath('domain:name', EPPClient::SCHEMAS_URL).text,
|
279
|
+
:crDate => DateTime.parse(dom.xpath('domain:crDate', EPPClient::SCHEMAS_URL).text),
|
280
|
+
:upDate => DateTime.parse(dom.xpath('domain:crDate', EPPClient::SCHEMAS_URL).text),
|
281
|
+
}
|
282
|
+
end
|
283
|
+
|
284
|
+
def domain_delete_xml(domain) #:nodoc:
|
285
|
+
command do |xml|
|
286
|
+
xml.delete do
|
287
|
+
xml.delete('xmlns' => EPPClient::SCHEMAS_URL['domain-1.0']) do
|
288
|
+
xml.name domain
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# Deletes a domain
|
295
|
+
#
|
296
|
+
# Takes a single fully qualified domain name for argument.
|
297
|
+
#
|
298
|
+
# Returns true on success, or raises an exception.
|
299
|
+
def domain_delete(domain)
|
300
|
+
response = send_request(domain_delete_xml(domain))
|
301
|
+
|
302
|
+
get_result(response)
|
303
|
+
end
|
304
|
+
|
305
|
+
def domain_update_xml(args) #:nodoc:
|
306
|
+
command do |xml|
|
307
|
+
xml.update do
|
308
|
+
xml.update('xmlns' => EPPClient::SCHEMAS_URL['domain-1.0']) do
|
309
|
+
xml.name args[:name]
|
310
|
+
[:add, :rem].each do |ar|
|
311
|
+
if args.key?(ar) && (args[ar].key?(:ns) || args[ar].key?(:contacts) || args[ar].key?(:status))
|
312
|
+
xml.__send__(ar) do
|
313
|
+
if args[ar].key?(:ns)
|
314
|
+
domain_nss_xml(xml, args[ar][:ns])
|
315
|
+
end
|
316
|
+
if args[ar].key?(:contacts)
|
317
|
+
domain_contacts_xml(xml, args[ar][:contacts])
|
318
|
+
end
|
319
|
+
if args[ar].key?(:status)
|
320
|
+
args[ar][:status].each do |st,text|
|
321
|
+
if text.nil?
|
322
|
+
xml.status(:s => st)
|
323
|
+
else
|
324
|
+
xml.status({:s => st}, text)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
if args.key?(:chg) && (args[:chg].key?(:registrant) || args[:chg].key?(:authInfo))
|
332
|
+
xml.chg do
|
333
|
+
if args[:chg].key?(:registrant)
|
334
|
+
xml.registrant args[:chg][:registrant]
|
335
|
+
end
|
336
|
+
if args[:chg].key?(:authInfo)
|
337
|
+
xml.authInfo do
|
338
|
+
xml.pw args[:chg][:authInfo]
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
# Updates a domain
|
349
|
+
#
|
350
|
+
# Takes a hash with the name, and at least one of the following keys :
|
351
|
+
# [<tt>:name</tt>]
|
352
|
+
# the fully qualified name of the domain object to be updated.
|
353
|
+
# [<tt>:add</tt>/<tt>:rem</tt>]
|
354
|
+
# adds / removes the following data to/from the domain object :
|
355
|
+
# [<tt>:ns</tt>]
|
356
|
+
# an optional array containing nameservers informations, which can either
|
357
|
+
# be an array of strings containing the nameserver's hostname, or an
|
358
|
+
# array of hashes containing the following keys :
|
359
|
+
# [<tt>:hostName</tt>] the hostname of the nameserver.
|
360
|
+
# [<tt>:hostAddrv4</tt>] an optionnal array of ipv4 addresses.
|
361
|
+
# [<tt>:hostAddrv6</tt>] an optionnal array of ipv6 addresses.
|
362
|
+
# [<tt>:contacts</tt>]
|
363
|
+
# an optionnal hash which keys are choosen between +admin+, +billing+ and
|
364
|
+
# +tech+ and which values are arrays of nic handles for the corresponding
|
365
|
+
# contact types.
|
366
|
+
# [<tt>:status</tt>]
|
367
|
+
# an optional hash with status values to be applied to or removed from
|
368
|
+
# the object. When specifying a value to be removed, only the attribute
|
369
|
+
# value is significant; element text is not required to match a value
|
370
|
+
# for removal.
|
371
|
+
# [<tt>:chg</tt>]
|
372
|
+
# changes the following in the domain object.
|
373
|
+
# [<tt>:registrant</tt>] an optionnal registrant nic handle.
|
374
|
+
# [<tt>:authInfo</tt>] an optional password associated with the domain.
|
375
|
+
#
|
376
|
+
# Returns true on success, or raises an exception.
|
377
|
+
def domain_update(args)
|
378
|
+
response = send_request(domain_update_xml(args))
|
379
|
+
|
380
|
+
get_result(response)
|
381
|
+
end
|
382
|
+
|
383
|
+
|
384
|
+
def domain_pending_action_process(xml) #:nodoc:
|
385
|
+
dom = xml.xpath('epp:resData/domain:panData', EPPClient::SCHEMAS_URL)
|
386
|
+
ret = {
|
387
|
+
:name => dom.xpath('domain:name', EPPClient::SCHEMAS_URL).text,
|
388
|
+
:paResult => dom.xpath('domain:name', EPPClient::SCHEMAS_URL).attribute('paResult').value,
|
389
|
+
:paTRID => get_trid(dom.xpath('domain:paTRID', EPPClient::SCHEMAS_URL)),
|
390
|
+
:paDate => DateTime.parse(dom.xpath('domain:paDate', EPPClient::SCHEMAS_URL).text),
|
391
|
+
}
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module EPPClient
|
2
|
+
class EPPErrorResponse < StandardError
|
3
|
+
attr_accessor :response_xml, :response_code, :message
|
4
|
+
|
5
|
+
# An exception with an added field so that it can store the xml response
|
6
|
+
# that generated it.
|
7
|
+
def initialize(attrs = {})
|
8
|
+
@response_xml = attrs[:xml]
|
9
|
+
@response_code = attrs[:code]
|
10
|
+
@message = attrs[:message]
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s #:nodoc:
|
14
|
+
"#{@message} (code #{@response_code})"
|
15
|
+
end
|
16
|
+
|
17
|
+
def inspect #:nodoc:
|
18
|
+
"#<#{self.class}: code: #{@response_code}, message: #{@message.inspect}, xml: #{@response_xml}>"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module EPPClient
|
2
|
+
module Poll
|
3
|
+
def poll_req_xml #:nodoc:
|
4
|
+
command do |xml|
|
5
|
+
xml.poll(:op => :req)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
# sends a <tt><epp:poll op="req"></tt> command to the server.
|
10
|
+
#
|
11
|
+
# if there is a message in the queue, returns a hash with the following keys :
|
12
|
+
# [<tt>:qDate</tt>] the date and time that the message was enqueued.
|
13
|
+
# [<tt>:msg</tt>, <tt>:msg_xml</tt>]
|
14
|
+
# a human readble message, the <tt>:msg</tt> version has all the possible
|
15
|
+
# xml stripped, whereas the <tt>:msg_xml</tt> contains the original
|
16
|
+
# message.
|
17
|
+
# [<tt>:obj</tt>, <tt>:obj_xml</tt>]
|
18
|
+
# contains a possible <tt><epp:resData></tt> object, the original one in
|
19
|
+
# <tt>:obj_xml</tt>, and if a parser is available, the parsed one in
|
20
|
+
# <tt>:obj</tt>.
|
21
|
+
def poll_req
|
22
|
+
response = send_request(poll_req_xml)
|
23
|
+
|
24
|
+
get_result(:xml => response, :callback => :poll_req_process)
|
25
|
+
end
|
26
|
+
|
27
|
+
PARSERS = {}
|
28
|
+
|
29
|
+
def poll_req_process(xml) #:nodoc:
|
30
|
+
ret = {}
|
31
|
+
if (date = xml.xpath("epp:msgQ/epp:qDate", EPPClient::SCHEMAS_URL)).size > 0
|
32
|
+
ret[:qDate] = DateTime.parse(date.text)
|
33
|
+
end
|
34
|
+
if (msg = xml.xpath("epp:msgQ/epp:msg", EPPClient::SCHEMAS_URL)).size > 0
|
35
|
+
ret[:msg] = msg.text
|
36
|
+
ret[:msg_xml] = msg.to_s
|
37
|
+
end
|
38
|
+
if (obj = xml.xpath('epp:resData', EPPClient::SCHEMAS_URL)).size > 0
|
39
|
+
ret[:obj_xml] = obj.to_s
|
40
|
+
PARSERS.each do |xpath,parser|
|
41
|
+
if obj.xpath(xpath, EPPClient::SCHEMAS_URL).size > 0
|
42
|
+
ret[:obj] = case parser
|
43
|
+
when Symbol
|
44
|
+
send(parser, xml)
|
45
|
+
else
|
46
|
+
raise NotImplementedError
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
ret
|
52
|
+
end
|
53
|
+
|
54
|
+
def poll_ack_xml(mid) #:nodoc:
|
55
|
+
command do |xml|
|
56
|
+
xml.poll(:op => :ack, :msgID => mid)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# sends a <tt><epp:poll op="ack" msgID="<mid>"></tt> command to the server.
|
61
|
+
# Most of the time, you should not pass any argument, as it will "do the
|
62
|
+
# right thing".
|
63
|
+
def poll_ack(mid = @msgQ_id)
|
64
|
+
response = send_request(poll_ack_xml(mid))
|
65
|
+
|
66
|
+
get_result(response)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module EPPClient
|
2
|
+
module Session
|
3
|
+
|
4
|
+
# Sends an hello epp command.
|
5
|
+
def hello
|
6
|
+
send_request(command do |xml|
|
7
|
+
xml.hello
|
8
|
+
end)
|
9
|
+
end
|
10
|
+
|
11
|
+
def login_xml(new_pw = nil) #:nodoc:
|
12
|
+
command do |xml|
|
13
|
+
xml.login do
|
14
|
+
xml.clID(@client_id)
|
15
|
+
xml.pw(@password)
|
16
|
+
xml.newPW(new_pw) unless new_pw.nil?
|
17
|
+
xml.options do
|
18
|
+
xml.version(@version)
|
19
|
+
xml.lang(@lang)
|
20
|
+
end
|
21
|
+
xml.svcs do
|
22
|
+
services.each do |s|
|
23
|
+
xml.objURI(s)
|
24
|
+
end
|
25
|
+
unless extensions.empty?
|
26
|
+
xml.svcExtension do
|
27
|
+
extensions.each do |e|
|
28
|
+
xml.extURI(e)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
private :login_xml
|
37
|
+
|
38
|
+
# Perform the login command on the server. Takes an optionnal argument, the
|
39
|
+
# new password for the account.
|
40
|
+
def login(new_pw = nil)
|
41
|
+
response = send_request(login_xml(new_pw))
|
42
|
+
|
43
|
+
get_result(response)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Performs the logout command, after it, the server terminates the
|
47
|
+
# connection.
|
48
|
+
def logout
|
49
|
+
response = send_request(command do |xml|
|
50
|
+
xml.logout
|
51
|
+
end)
|
52
|
+
|
53
|
+
get_result(response)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module EPPClient
|
2
|
+
module SSL
|
3
|
+
def self.included(base) # :nodoc:
|
4
|
+
base.class_eval do
|
5
|
+
alias_method :open_connection_without_ssl, :open_connection
|
6
|
+
alias_method :open_connection, :open_connection_with_ssl
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :ssl_cert, :ssl_key
|
11
|
+
|
12
|
+
def ssl_key=(key) #:nodoc:
|
13
|
+
case key
|
14
|
+
when OpenSSL::PKey::RSA
|
15
|
+
@ssl_key = key
|
16
|
+
when String
|
17
|
+
unless key =~ /-----BEGIN RSA PRIVATE KEY-----/
|
18
|
+
key = File.read(key)
|
19
|
+
end
|
20
|
+
@ssl_key = OpenSSL::PKey::RSA.new(key)
|
21
|
+
else
|
22
|
+
raise ArgumentError, "Must either be an OpenSSL::PKey::RSA object, a filename or a key"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def ssl_cert=(cert) #:nodoc:
|
27
|
+
case cert
|
28
|
+
when OpenSSL::X509::Certificate
|
29
|
+
@ssl_cert = cert
|
30
|
+
when String
|
31
|
+
unless cert =~ /-----BEGIN CERTIFICATE-----/
|
32
|
+
cert = File.read(cert)
|
33
|
+
end
|
34
|
+
@ssl_cert = OpenSSL::X509::Certificate.new(cert)
|
35
|
+
else
|
36
|
+
raise ArgumentError, "Must either be an OpenSSL::X509::Certificate object, a filename or a certificate"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def open_connection_with_ssl # :nodoc:
|
41
|
+
@context.cert ||= ssl_cert if ssl_cert.is_a?(OpenSSL::X509::Certificate)
|
42
|
+
@context.key ||= ssl_key if ssl_key.is_a?(OpenSSL::PKey::RSA)
|
43
|
+
open_connection_without_ssl
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|