epp-client-hostmaster 0.2.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/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +144 -0
- data/Rakefile +1 -0
- data/epp-client-hostmaster.gemspec +23 -0
- data/lib/epp-client/hostmaster-connection.rb +9 -0
- data/lib/epp-client/hostmaster-contact.rb +149 -0
- data/lib/epp-client/hostmaster-domain.rb +183 -0
- data/lib/epp-client/hostmaster-host.rb +223 -0
- data/lib/epp-client/hostmaster-rgp.rb +27 -0
- data/lib/epp-client/hostmaster-transfer.rb +42 -0
- data/lib/epp-client/hostmaster-xml.rb +7 -0
- data/lib/epp-client/hostmaster.rb +41 -0
- data/lib/epp-client.rb +1 -0
- metadata +108 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Yuriy Kolodovskyy
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
# Hostmaster.UA EPP client library
|
2
|
+
|
3
|
+
EPP (Extensible Provisioning Protocol) client library based on [epp-client-base](https://rubygems.org/gems/epp-client-base) gem.
|
4
|
+
Full specification see at [Hostmaster.UA EPP Project](https://epp.hostmaster.ua).
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'epp-client-hostmaster'
|
11
|
+
|
12
|
+
or this line:
|
13
|
+
|
14
|
+
gem 'epp-client-hostmaster', git: 'https://github.com/kolodovskyy/epp-client-hostmaster.git'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install epp-client-hostmaster
|
23
|
+
|
24
|
+
## Usage (example)
|
25
|
+
|
26
|
+
require "epp-client/hostmaster"
|
27
|
+
|
28
|
+
#ENV['EPP_CLIENT_DEBUG'] = 'yes'
|
29
|
+
|
30
|
+
c = EPPClient::Hostmaster.new(
|
31
|
+
client_id: 'LOGIN',
|
32
|
+
password: 'PASSWORD',
|
33
|
+
ssl_cert: 'epp.crt',
|
34
|
+
ssl_key: 'epp.key'
|
35
|
+
)
|
36
|
+
|
37
|
+
begin
|
38
|
+
c.open_connection
|
39
|
+
c.login
|
40
|
+
c.hello
|
41
|
+
|
42
|
+
c.contact_check 'test1', 'test2'
|
43
|
+
puts c.contact_info 'test1'
|
44
|
+
|
45
|
+
c.contact_create(
|
46
|
+
id: 'test2',
|
47
|
+
postalInfo: {
|
48
|
+
loc: {
|
49
|
+
name: 'Test name',
|
50
|
+
org: 'Test organization',
|
51
|
+
addr: {
|
52
|
+
street: [ 'Test street' ],
|
53
|
+
city: 'Kiev',
|
54
|
+
pc: '00000',
|
55
|
+
cc: 'UA'
|
56
|
+
}
|
57
|
+
}
|
58
|
+
},
|
59
|
+
voice: '+380.441234567',
|
60
|
+
fax: '+380.441234567',
|
61
|
+
email: 'test@test.com',
|
62
|
+
authInfo: 'testpassword'
|
63
|
+
)
|
64
|
+
|
65
|
+
c.contact_update(
|
66
|
+
id: 'test',
|
67
|
+
chg: {
|
68
|
+
fax: '+380.447654321'
|
69
|
+
}
|
70
|
+
)
|
71
|
+
|
72
|
+
c.contact_delete 'test2'
|
73
|
+
|
74
|
+
c.host_check 'ns1.test.epp.ua', 'ns2.test.epp.ua'
|
75
|
+
c.host_info 'ns1.test.epp.ua'
|
76
|
+
c.host_create name: 'ns2.test.epp.ua', addrv4: [ '8.8.8.8' ]
|
77
|
+
c.host_update(
|
78
|
+
name: 'ns2.test.epp.ua',
|
79
|
+
rem: {
|
80
|
+
addrv4: '8.8.8.8'
|
81
|
+
},
|
82
|
+
add: {
|
83
|
+
addrv4: '8.8.8.8'
|
84
|
+
}
|
85
|
+
)
|
86
|
+
c.host_delete 'ns2.test.epp.ua'
|
87
|
+
|
88
|
+
puts c.domain_check 'test1.epp.ua', 'test2.epp.ua'
|
89
|
+
puts c.domain_info 'test1.epp.ua'
|
90
|
+
c.domain_create(
|
91
|
+
name: 'test3.epp.ua',
|
92
|
+
period: {
|
93
|
+
unit: 'y',
|
94
|
+
number: '1'
|
95
|
+
},
|
96
|
+
ns: [ 'ns1.test.epp.ua' ],
|
97
|
+
registrant: 'test',
|
98
|
+
contacts: {
|
99
|
+
admin: [ 'test' ],
|
100
|
+
tech: [ 'test' ]
|
101
|
+
}
|
102
|
+
)
|
103
|
+
|
104
|
+
puts c.domain_renew(
|
105
|
+
name: 'test.epp.ua',
|
106
|
+
curExpDate: '2013-11-19',
|
107
|
+
period: {
|
108
|
+
unit: 'y',
|
109
|
+
number: '1'
|
110
|
+
}
|
111
|
+
)
|
112
|
+
|
113
|
+
c.domain_delete('test.epp.ua')
|
114
|
+
c.domain_restore('test.epp.ua')
|
115
|
+
|
116
|
+
c.domain_update(
|
117
|
+
name: 'test.epp.ua',
|
118
|
+
chg: {
|
119
|
+
registrant: 'test1'
|
120
|
+
}
|
121
|
+
)
|
122
|
+
|
123
|
+
puts c.poll_req
|
124
|
+
puts c.poll_ack
|
125
|
+
|
126
|
+
puts c.transfer_request name: 'test-transfer.epp.ua', authInfo: '111'
|
127
|
+
puts c.transfer_cancel 'test-transfer.epp.ua'
|
128
|
+
puts c.transfer_query 'test-transfer.epp.ua'
|
129
|
+
|
130
|
+
c.logout
|
131
|
+
rescue => error
|
132
|
+
puts error.to_s
|
133
|
+
puts error.backtrace
|
134
|
+
ensure
|
135
|
+
c.close_connection
|
136
|
+
end
|
137
|
+
|
138
|
+
## Maintainers and Authors
|
139
|
+
|
140
|
+
Yuriy Kolodovskyy (https://github.com/kolodovskyy)
|
141
|
+
|
142
|
+
## License
|
143
|
+
|
144
|
+
MIT License. Copyright 2012 [Yuriy Kolodovskyy](http://twitter.com/kolodovskyy)
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'epp-client'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "epp-client-hostmaster"
|
8
|
+
gem.version = EPPClient::Hostmaster::VERSION
|
9
|
+
gem.authors = ["Yuriy Kolodovskyy"]
|
10
|
+
gem.email = %w{kolodovskyy@ukrindex.com}
|
11
|
+
gem.description = %q{Hostmaster.UA EPP client library}
|
12
|
+
gem.summary = %q{Hostmaster.UA EPP client library}
|
13
|
+
gem.homepage = "https://github.com/kolodovskyy/epp-client-hostmaster"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = %w{lib}
|
19
|
+
|
20
|
+
gem.add_development_dependency "bundler"
|
21
|
+
gem.add_dependency('epp-client-base', '~> 0.11.0')
|
22
|
+
gem.add_dependency('builder', '~> 3.1.4')
|
23
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module EPPClient
|
2
|
+
module HostmasterContact
|
3
|
+
def contact_check_xml(*contacts)
|
4
|
+
command do |xml|
|
5
|
+
xml.check do
|
6
|
+
xml.contact :check, 'xmlns:contact' => EPPClient::SCHEMAS_URL['contact-1.1'] do
|
7
|
+
contacts.each { |c| xml.contact :id, c }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def contact_info_xml(args)
|
14
|
+
command do |xml|
|
15
|
+
xml.info do
|
16
|
+
xml.contact :info, 'xmlns:contact' => EPPClient::SCHEMAS_URL['contact-1.1'] do
|
17
|
+
xml.contact :id, args[:id]
|
18
|
+
if args.key? :authInfo
|
19
|
+
xml.contact :authInfo do
|
20
|
+
xml.contact :pw, args[:authInfo]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def contact_create_xml(contact)
|
29
|
+
command do |xml|
|
30
|
+
xml.create do
|
31
|
+
xml.contact :create, 'xmlns:contact' => EPPClient::SCHEMAS_URL['contact-1.1'] do
|
32
|
+
if contact.key?(:id)
|
33
|
+
xml.contact :id, contact[:id]
|
34
|
+
else
|
35
|
+
xml.contact :id, 'autonic'
|
36
|
+
end
|
37
|
+
contact[:postalInfo].each do |type,infos|
|
38
|
+
xml.contact :postalInfo, type: type do
|
39
|
+
xml.contact :name, infos[:name]
|
40
|
+
xml.contact :org, infos[:org] if infos.key?(:org)
|
41
|
+
xml.contact :addr do
|
42
|
+
infos[:addr][:street].each do |street|
|
43
|
+
xml.contact :street, street
|
44
|
+
end
|
45
|
+
xml.contact :city, infos[:addr][:city]
|
46
|
+
xml.contact :sp, infos[:addr][:sp] if infos[:addr].key? :sp
|
47
|
+
xml.contact :pc, infos[:addr][:pc] if infos[:addr].key? :pc
|
48
|
+
xml.contact :cc, infos[:addr][:cc]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
xml.contact :voice, contact[:voice] if contact.key? :voice
|
53
|
+
xml.contact :fax, contact[:fax] if contact.key? :fax
|
54
|
+
xml.contact :email, contact[:email]
|
55
|
+
xml.contact :authInfo do
|
56
|
+
xml.contact :pw, contact[:authInfo]
|
57
|
+
end
|
58
|
+
if contact.key?(:disclose)
|
59
|
+
xml.contact :disclose, flag: '1' do # TODO: parameter for flag need
|
60
|
+
contact[:disclose].each do |disc|
|
61
|
+
if disc.key?(:type)
|
62
|
+
xml.contact disc[:name], type: disc[:type]
|
63
|
+
else
|
64
|
+
xml.contact disc[:name]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def contact_delete_xml(contact)
|
75
|
+
command do |xml|
|
76
|
+
xml.delete do
|
77
|
+
xml.contact :delete, 'xmlns:contact' => EPPClient::SCHEMAS_URL['contact-1.1'] do
|
78
|
+
xml.contact :id, contact
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def contact_update_xml(args)
|
85
|
+
command do |xml|
|
86
|
+
xml.update do
|
87
|
+
xml.contact :update, 'xmlns:contact' => EPPClient::SCHEMAS_URL['contact-1.1'] do
|
88
|
+
xml.contact :id, args[:id]
|
89
|
+
if args.key?(:add) && args[:add].key?(:status)
|
90
|
+
xml.contact :add do
|
91
|
+
args[:add][:status].each do |s|
|
92
|
+
xml.contact :status, s: s
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
if args.key?(:rem) && args[:rem].key?(:status)
|
97
|
+
xml.contact :rem do
|
98
|
+
args[:rem][:status].each do |s|
|
99
|
+
xml.contact :status, s: s
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
if args.key?(:chg)
|
104
|
+
contact = args[:chg]
|
105
|
+
xml.contact :chg do
|
106
|
+
if contact.key?(:postalInfo)
|
107
|
+
contact[:postalInfo].each do |type,infos|
|
108
|
+
xml.contact :postalInfo, type: type do
|
109
|
+
xml.contact :name, infos[:name]
|
110
|
+
xml.contact :org, infos[:org] if infos.key? :org
|
111
|
+
xml.contact :addr do
|
112
|
+
infos[:addr][:street].each do |street|
|
113
|
+
xml.contact :street, street
|
114
|
+
end
|
115
|
+
xml.contact :city, infos[:addr][:city]
|
116
|
+
xml.contact :sp, infos[:addr][:sp] if infos[:addr].key? :sp
|
117
|
+
xml.contact :pc, infos[:addr][:pc] if infos[:addr].key? :pc
|
118
|
+
xml.contact :cc, infos[:addr][:cc]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
[:voice, :fax, :email].each do |val|
|
124
|
+
xml.contact val, contact[val] if contact.key? val
|
125
|
+
end
|
126
|
+
if contact.key?(:authInfo)
|
127
|
+
xml.contact :authInfo do
|
128
|
+
xml.contact :pw, contact[:authInfo]
|
129
|
+
end
|
130
|
+
end
|
131
|
+
if contact.key?(:disclose)
|
132
|
+
xml.contact :disclose, flag: '1' do # TODO: parameter for flag need
|
133
|
+
contact[:disclose].each do |disc|
|
134
|
+
if disc.key?(:type)
|
135
|
+
xml.contact disc[:name], type: disc[:type]
|
136
|
+
else
|
137
|
+
xml.contact disc[:name]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
module EPPClient
|
2
|
+
module HostmasterDomain
|
3
|
+
def domain_check_xml(*domains) # :nodoc:
|
4
|
+
command do |xml|
|
5
|
+
xml.check do
|
6
|
+
xml.domain :check, 'xmlns:domain' => EPPClient::SCHEMAS_URL['domain-1.1'] do
|
7
|
+
domains.each {|domain| xml.domain :name, domain}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def domain_info_xml(args)
|
14
|
+
command do |xml|
|
15
|
+
xml.info do
|
16
|
+
xml.domain :info, 'xmlns:domain' => EPPClient::SCHEMAS_URL['domain-1.1'] do
|
17
|
+
xml.domain :name, args[:name]
|
18
|
+
if args.key? :authInfo
|
19
|
+
xml.domain :authInfo do
|
20
|
+
xml.domain :pw, args[:authInfo]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def domain_nss_xml(xml, nss)
|
29
|
+
xml.domain :ns do
|
30
|
+
if nss.first.is_a? Hash
|
31
|
+
nss.each do |ns|
|
32
|
+
xml.domain :hostAttr do
|
33
|
+
xml.domain :hostName, ns[:hostName]
|
34
|
+
if ns.key?(:hostAddrv4)
|
35
|
+
ns[:hostAddrv4].each do |v4|
|
36
|
+
xml.domain :hostAddr, {:ip => :v4}, v4
|
37
|
+
end
|
38
|
+
end
|
39
|
+
if ns.key?(:hostAddrv6)
|
40
|
+
ns[:hostAddrv6].each do |v6|
|
41
|
+
xml.domain :hostAddr, {:ip => :v6}, v6
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
else
|
47
|
+
nss.each do |ns|
|
48
|
+
xml.domain :hostObj, ns
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def domain_contacts_xml(xml, args)
|
55
|
+
args.each do |type,contacts|
|
56
|
+
contacts.each do |c|
|
57
|
+
xml.domain :contact, { type: type }, c
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def domain_period_xml(xml, period)
|
63
|
+
xml.domain :period, { unit: period[:unit] }, period[:number]
|
64
|
+
end
|
65
|
+
|
66
|
+
def domain_create_xml(args) #:nodoc:
|
67
|
+
command do |xml|
|
68
|
+
xml.create do
|
69
|
+
xml.domain :create, 'xmlns:domain' => EPPClient::SCHEMAS_URL['domain-1.1'] do
|
70
|
+
xml.domain :name, args[:name]
|
71
|
+
domain_period_xml(xml, args[:period]) if args.key?(:period)
|
72
|
+
domain_nss_xml(xml, args[:ns]) if args.key? :ns
|
73
|
+
xml.domain :registrant, args[:registrant]
|
74
|
+
domain_contacts_xml(xml, args[:contacts])
|
75
|
+
xml.domain :license, args[:license] if args.key? :license
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def domain_create_process(xml) #:nodoc:
|
82
|
+
dom = xml.xpath('epp:resData/domain:creData', EPPClient::SCHEMAS_URL)
|
83
|
+
ret = {
|
84
|
+
name: dom.xpath('domain:name', EPPClient::SCHEMAS_URL).text,
|
85
|
+
crDate: DateTime.parse(dom.xpath('domain:crDate', EPPClient::SCHEMAS_URL).text),
|
86
|
+
exDate: DateTime.parse(dom.xpath('domain:exDate', EPPClient::SCHEMAS_URL).text),
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
def domain_delete_xml(domain) #:nodoc:
|
92
|
+
command do |xml|
|
93
|
+
xml.delete do
|
94
|
+
xml.domain :delete, 'xmlns:domain' => EPPClient::SCHEMAS_URL['domain-1.1'] do
|
95
|
+
xml.domain :name, domain
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def domain_renew_xml(domain)
|
102
|
+
command do |xml|
|
103
|
+
xml.renew do
|
104
|
+
xml.domain :renew, 'xmlns:domain' => EPPClient::SCHEMAS_URL['domain-1.1'] do
|
105
|
+
xml.domain :name, domain[:name]
|
106
|
+
xml.domain :curExpDate, domain[:curExpDate].strftime('%Y-%m-%d')
|
107
|
+
domain_period_xml(xml, domain[:period])
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Renew a domain
|
114
|
+
#
|
115
|
+
# Takes a hash as an argument, containing the following keys :
|
116
|
+
#
|
117
|
+
# [<tt>:name</tt>] the domain name
|
118
|
+
# [<tt>:period</tt>]
|
119
|
+
# an optionnal hash containing the period for withch the domain is
|
120
|
+
# registered with the following keys :
|
121
|
+
# [<tt>:unit</tt>] the unit of time, either "m"onth or "y"ear.
|
122
|
+
# [<tt>:number</tt>] the number of unit of time.
|
123
|
+
# [<tt>:curExpDate</tt>]
|
124
|
+
# the date identifying the current end of the domain object
|
125
|
+
# registration period.
|
126
|
+
# Returns a hash with the following keys :
|
127
|
+
#
|
128
|
+
# [<tt>:name</tt>] the fully qualified name of the domain object.
|
129
|
+
# [<tt>:exDate</tt>]
|
130
|
+
# the date and time identifying the end of the domain object's
|
131
|
+
# registration period.
|
132
|
+
def domain_renew(domain)
|
133
|
+
domain[:curExpDate] = DateTime.parse(domain[:curExpDate]) unless domain[:curExpDate].is_a? DateTime
|
134
|
+
response = send_request(domain_renew_xml(domain))
|
135
|
+
get_result(:xml => response, :callback => :domain_renew_process)
|
136
|
+
end
|
137
|
+
|
138
|
+
def domain_renew_process(xml) #:nodoc:
|
139
|
+
dom = xml.xpath('epp:resData/domain:renData', EPPClient::SCHEMAS_URL)
|
140
|
+
ret = {
|
141
|
+
name: dom.xpath('domain:name', EPPClient::SCHEMAS_URL).text,
|
142
|
+
exDate: DateTime.parse(dom.xpath('domain:exDate', EPPClient::SCHEMAS_URL).text)
|
143
|
+
}
|
144
|
+
end
|
145
|
+
|
146
|
+
def domain_update_xml(args) #:nodoc:
|
147
|
+
command do |xml|
|
148
|
+
xml.update do
|
149
|
+
xml.domain :update, 'xmlns:domain' => EPPClient::SCHEMAS_URL['domain-1.1'] do
|
150
|
+
xml.domain :name, args[:name]
|
151
|
+
[:add, :rem].each do |ar|
|
152
|
+
next unless args.key?(ar) && (args[ar].key?(:ns) || args[ar].key?(:contacts) || args[ar].key?(:status))
|
153
|
+
xml.domain ar do
|
154
|
+
domain_nss_xml(xml, args[ar][:ns]) if args[ar].key? :ns
|
155
|
+
domain_contacts_xml(xml, args[ar][:contacts]) if args[ar].key? :contacts
|
156
|
+
if args[ar].key? :status
|
157
|
+
args[ar][:status].each do |st,text|
|
158
|
+
if text.nil?
|
159
|
+
xml.domain :status, s: st
|
160
|
+
else
|
161
|
+
xml.domain :status, { s: st }, text
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
if args.key?(:chg) && (args[:chg].key?(:registrant) || args[:chg].key?(:authInfo))
|
168
|
+
xml.domain :chg do
|
169
|
+
xml.domain :registrant, args[:chg][:registrant] if args[:chg].key? :registrant
|
170
|
+
if args[:chg].key? :authInfo
|
171
|
+
xml.domain :authInfo do
|
172
|
+
xml.domain :pw, args[:chg][:authInfo]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
require "ipaddr"
|
2
|
+
|
3
|
+
module EPPClient
|
4
|
+
module HostmasterHost
|
5
|
+
def host_check_xml(*hosts) #:nodoc:
|
6
|
+
command do |xml|
|
7
|
+
xml.check do
|
8
|
+
xml.host :check, 'xmlns:host' => EPPClient::SCHEMAS_URL['host-1.1'] do
|
9
|
+
hosts.each { |host| xml.host :name, host }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Check the availability of hosts
|
16
|
+
#
|
17
|
+
# takes list of hosts as arguments
|
18
|
+
#
|
19
|
+
# returns an array of hashes containing three fields :
|
20
|
+
# [<tt>:name</tt>] the host name
|
21
|
+
# [<tt>:avail</tt>] availability
|
22
|
+
# [<tt>:reason</tt>]
|
23
|
+
# the server-specific text to help explain why the object cannot be
|
24
|
+
# provisioned.
|
25
|
+
#
|
26
|
+
def host_check(*hosts)
|
27
|
+
hosts.flatten!
|
28
|
+
|
29
|
+
response = send_request(host_check_xml(*hosts))
|
30
|
+
get_result(:xml => response, :callback => :host_check_process)
|
31
|
+
end
|
32
|
+
|
33
|
+
def host_check_process(xml) #:nodoc:
|
34
|
+
xml.xpath('epp:resData/host:chkData/host:cd', EPPClient::SCHEMAS_URL).map do |dom|
|
35
|
+
ret = {
|
36
|
+
name: dom.xpath('host:name', EPPClient::SCHEMAS_URL).text,
|
37
|
+
avail: dom.xpath('host:name', EPPClient::SCHEMAS_URL).attr('avail').value == '1',
|
38
|
+
}
|
39
|
+
unless (reason = dom.xpath('host:reason', EPPClient::SCHEMAS_URL).text).empty?
|
40
|
+
ret[:reason] = reason
|
41
|
+
end
|
42
|
+
ret
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def host_info_xml(args) #:nodoc:
|
47
|
+
command do |xml|
|
48
|
+
xml.info do
|
49
|
+
xml.host :info, 'xmlns:host' => EPPClient::SCHEMAS_URL['host-1.1'] do
|
50
|
+
xml.host :name, args[:name]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the informations about a host
|
57
|
+
#
|
58
|
+
# Takes either a unique argument, either
|
59
|
+
# a string, representing the host name
|
60
|
+
# or a hash with the following keys :
|
61
|
+
# [<tt>:name</tt>] the host name
|
62
|
+
#
|
63
|
+
# Returned is a hash mapping:
|
64
|
+
# [<tt>:name</tt>] host name.
|
65
|
+
# [<tt>:roid</tt>]
|
66
|
+
# the Repository Object IDentifier assigned to the host object when
|
67
|
+
# the object was created.
|
68
|
+
# [<tt>:status</tt>] the status or array of statuses of the host object.
|
69
|
+
# [<tt>:addrv4</tt>] array with IPv4 addresses.
|
70
|
+
# [<tt>:addrv6</tt>] array with IPv6 addresses.
|
71
|
+
# [<tt>:clID</tt>] the identifier of the sponsoring client.
|
72
|
+
# [<tt>:crID</tt>]
|
73
|
+
# the identifier of the client that created the host object.
|
74
|
+
# [<tt>:crDate</tt>] the date and time of host object creation.
|
75
|
+
# [<tt>:upID</tt>]
|
76
|
+
# the optional identifier of the client that last updated the host
|
77
|
+
# object.
|
78
|
+
# [<tt>:upDate</tt>]
|
79
|
+
# the optional date and time of the most recent host object
|
80
|
+
# modification.
|
81
|
+
# [<tt>:trDate</tt>]
|
82
|
+
# the optional date and time of the most recent successful host object
|
83
|
+
# transfer.
|
84
|
+
def host_info(args)
|
85
|
+
args = { name: args } if args.is_a? String
|
86
|
+
response = send_request(host_info_xml(args))
|
87
|
+
get_result(:xml => response, :callback => :host_info_process)
|
88
|
+
end
|
89
|
+
|
90
|
+
def host_info_process(xml) #:nodoc:
|
91
|
+
host = xml.xpath('epp:resData/host:infData', EPPClient::SCHEMAS_URL)
|
92
|
+
ret = {
|
93
|
+
name: host.xpath('host:name', EPPClient::SCHEMAS_URL).text,
|
94
|
+
roid: host.xpath('host:roid', EPPClient::SCHEMAS_URL).text,
|
95
|
+
}
|
96
|
+
if (status = host.xpath('host:status', EPPClient::SCHEMAS_URL)).size > 0
|
97
|
+
ret[:status] = status.map {|s| s.attr('s')}
|
98
|
+
end
|
99
|
+
|
100
|
+
if (value = host.xpath('host:addr', EPPClient::SCHEMAS_URL, ip: 'v4')).size > 0
|
101
|
+
ret[:addrv4] = value.map {|ip| IPAddr.new(ip.text)}
|
102
|
+
end
|
103
|
+
if (value = host.xpath('host:addr', EPPClient::SCHEMAS_URL, ip: 'v6')).size > 0
|
104
|
+
ret[:addrv6] = value.map {|ip| IPAddr.new(ip.text)}
|
105
|
+
end
|
106
|
+
|
107
|
+
%w(clID crID upID).each do |val|
|
108
|
+
if (value = host.xpath("host:#{val}", EPPClient::SCHEMAS_URL)).size > 0
|
109
|
+
ret[val.to_sym] = value.text
|
110
|
+
end
|
111
|
+
end
|
112
|
+
%w(crDate upDate trDate).each do |val|
|
113
|
+
if (date = host.xpath("host:#{val}", EPPClient::SCHEMAS_URL)).size > 0
|
114
|
+
ret[val.to_sym] = DateTime.parse(date.text)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
ret
|
118
|
+
end
|
119
|
+
|
120
|
+
def host_create_xml(host) #:nodoc:
|
121
|
+
command do |xml|
|
122
|
+
xml.create do
|
123
|
+
xml.host :create, 'xmlns:host' => EPPClient::SCHEMAS_URL['host-1.1'] do
|
124
|
+
xml.host :name, host[:name]
|
125
|
+
%w(addrv4 addrv6).each do |type|
|
126
|
+
next unless host.key? type
|
127
|
+
host[type].each {|ip| xml.host :addr, ip}
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Creates a host
|
135
|
+
#
|
136
|
+
# Takes a hash as an argument containing the following keys :
|
137
|
+
# [<tt>:name</tt>] host name.
|
138
|
+
# [<tt>:addrv4</tt>] array with IPv4 addresses.
|
139
|
+
# [<tt>:addrv6</tt>] array with IPv6 addresses.
|
140
|
+
def host_create(host)
|
141
|
+
%w(addrv4 addrv6).each do |type|
|
142
|
+
next unless host.key? type
|
143
|
+
host[type] = [ host[type] ] unless host[type].is_a? Array
|
144
|
+
end
|
145
|
+
response = send_request(host_create_xml(host))
|
146
|
+
get_result(:xml => response, :callback => :host_create_process)
|
147
|
+
end
|
148
|
+
|
149
|
+
def host_create_process(xml) #:nodoc:
|
150
|
+
host = xml.xpath('epp:resData/host:creData', EPPClient::SCHEMAS_URL)
|
151
|
+
{
|
152
|
+
name: host.xpath('host:name', EPPClient::SCHEMAS_URL).text,
|
153
|
+
crDate: DateTime.parse(host.xpath('host:crDate', EPPClient::SCHEMAS_URL).text)
|
154
|
+
}
|
155
|
+
end
|
156
|
+
|
157
|
+
def host_delete_xml(host) #:nodoc:
|
158
|
+
command do |xml|
|
159
|
+
xml.delete do
|
160
|
+
xml.host :delete, 'xmlns:host' => EPPClient::SCHEMAS_URL['host-1.1'] do
|
161
|
+
xml.host :name, host
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# Deletes a host
|
168
|
+
#
|
169
|
+
# Takes a single host for argument.
|
170
|
+
#
|
171
|
+
# Returns true on success, or raises an exception.
|
172
|
+
def host_delete(host)
|
173
|
+
response = send_request(host_delete_xml(host))
|
174
|
+
get_result(response)
|
175
|
+
end
|
176
|
+
|
177
|
+
def host_update_xml(args) #:nodoc:
|
178
|
+
command do |xml|
|
179
|
+
xml.update do
|
180
|
+
xml.host :update, 'xmlns:host' => EPPClient::SCHEMAS_URL['host-1.1'] do
|
181
|
+
xml.host :name, args[:name]
|
182
|
+
[:add, :rem].each do |operation|
|
183
|
+
if args.key? operation
|
184
|
+
xml.host operation do
|
185
|
+
args[operation][:status].each {|s| xml.host :status, s: s} if args[operation].key? :status
|
186
|
+
%w(addrv4 addrv6).each do |type|
|
187
|
+
next unless args[operation].key? type
|
188
|
+
args[operation][type].each {|a| xml.host type, a}
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Updates a host
|
199
|
+
#
|
200
|
+
# Takes a hash with the name, and at least one of the following keys :
|
201
|
+
# [<tt>:name</tt>]
|
202
|
+
# the server-unique identifier of the host object to be updated.
|
203
|
+
# [<tt>:add</tt>/<tt>:rem</tt>]
|
204
|
+
# adds or removes the following data from the host object :
|
205
|
+
# [<tt>:addrv4</tt>] an array of IPv4 addresses.
|
206
|
+
# [<tt>:addrv6</tt>] an array of IPv6 addresses.
|
207
|
+
# [<tt>:status</tt>] an array of status to add to/remove from the object.
|
208
|
+
#
|
209
|
+
# Returns true on success, or raises an exception.
|
210
|
+
def host_update(args)
|
211
|
+
[:add, :rem].each do |operation|
|
212
|
+
next unless args.key?(operation)
|
213
|
+
%w(addrv4 addrv6).each do |type|
|
214
|
+
next unless args[operation].key? type
|
215
|
+
args[operation][type] = [ args[operation[type]] ] unless args[operation][type].is_a? Array
|
216
|
+
end
|
217
|
+
end
|
218
|
+
response = send_request(host_update_xml(args))
|
219
|
+
get_result(response)
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module EPPClient
|
2
|
+
module HostmasterRGP
|
3
|
+
def domain_restore_xml(domain)
|
4
|
+
command do |xml|
|
5
|
+
xml.update do
|
6
|
+
xml.domain :update, 'xmlns:domain' => EPPClient::SCHEMAS_URL['domain-1.1'] do
|
7
|
+
xml.domain :name, domain
|
8
|
+
end
|
9
|
+
end
|
10
|
+
xml.extension do
|
11
|
+
xml.rgp :update, 'xmlns:rgp' => EPPClient::SCHEMAS_URL['rgp-1.1'] do
|
12
|
+
xml.rgp :restore, op: 'request'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Restore a domain
|
19
|
+
# Takes a single fully qualified domain name for argument.:
|
20
|
+
#
|
21
|
+
# Returns an array of rgpStatus.
|
22
|
+
def domain_restore(domain)
|
23
|
+
response = send_request(domain_restore_xml(domain))
|
24
|
+
get_result(:xml => response)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module EPPClient
|
2
|
+
module HostmasterTransfer
|
3
|
+
def transfer_xml(domain, op)
|
4
|
+
command do |xml|
|
5
|
+
xml.transfer op: op do
|
6
|
+
xml.domain :transfer, 'xmlns:domain' => EPPClient::SCHEMAS_URL['domain-1.1'] do
|
7
|
+
xml.domain :name, domain[:name]
|
8
|
+
domain_period_xml(xml, domain[:period]) if domain.key? :period
|
9
|
+
if domain.key? :authInfo
|
10
|
+
xml.domain :authInfo do
|
11
|
+
xml.domain :pw, domain[:authInfo]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def transfer(domain, op)
|
20
|
+
domain = { name: domain } if domain.is_a? String
|
21
|
+
response = send_request(transfer_xml(domain, op))
|
22
|
+
get_result(:xml => response, :callback => :transfer_process)
|
23
|
+
end
|
24
|
+
|
25
|
+
%w(request cancel approve reject query).each do |op|
|
26
|
+
define_method("transfer_#{op}") { |domain| transfer(domain, op.to_sym) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def transfer_process(xml)
|
30
|
+
trn = xml.xpath('epp:resData/domain:trnData', EPPClient::SCHEMAS_URL)
|
31
|
+
{
|
32
|
+
name: trn.xpath('domain:name', EPPClient::SCHEMAS_URL).text,
|
33
|
+
trStatus: trn.xpath('domain:trStatus', EPPClient::SCHEMAS_URL).text,
|
34
|
+
reID: trn.xpath('domain:reID', EPPClient::SCHEMAS_URL).text,
|
35
|
+
reDate: DateTime.parse(trn.xpath('domain:reDate', EPPClient::SCHEMAS_URL).text),
|
36
|
+
acID: trn.xpath('domain:acID', EPPClient::SCHEMAS_URL).text,
|
37
|
+
acDate: DateTime.parse(trn.xpath('domain:acDate', EPPClient::SCHEMAS_URL).text),
|
38
|
+
exDate: DateTime.parse(trn.xpath('domain:exDate', EPPClient::SCHEMAS_URL).text)
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "epp-client/base"
|
2
|
+
require "epp-client/hostmaster-xml"
|
3
|
+
require "epp-client/hostmaster-connection"
|
4
|
+
require "epp-client/hostmaster-domain"
|
5
|
+
require "epp-client/hostmaster-contact"
|
6
|
+
require "epp-client/hostmaster-host"
|
7
|
+
require "epp-client/hostmaster-rgp"
|
8
|
+
require "epp-client/hostmaster-transfer"
|
9
|
+
|
10
|
+
module EPPClient
|
11
|
+
class Hostmaster < Base
|
12
|
+
VERSION = '0.2.0'
|
13
|
+
|
14
|
+
SCHEMAS = %w(domain-1.1 host-1.1 contact-1.1 rgp-1.1)
|
15
|
+
|
16
|
+
EPPClient::SCHEMAS_URL.merge!(SCHEMAS.inject({}) do |a,s|
|
17
|
+
a[s.sub(/-1\.1$/, '')] = "http://hostmaster.ua/epp/#{s}" if s =~ /-1\.1$/
|
18
|
+
a[s] = "http://hostmaster.ua/epp/#{s}"
|
19
|
+
a
|
20
|
+
end)
|
21
|
+
|
22
|
+
include EPPClient::HostmasterXML
|
23
|
+
include EPPClient::HostmasterConnection
|
24
|
+
include EPPClient::HostmasterDomain
|
25
|
+
include EPPClient::HostmasterContact
|
26
|
+
include EPPClient::HostmasterHost
|
27
|
+
include EPPClient::HostmasterRGP
|
28
|
+
include EPPClient::HostmasterTransfer
|
29
|
+
|
30
|
+
def initialize(attrs)
|
31
|
+
unless attrs.key?(:client_id) && attrs.key?(:password) && attrs.key?(:ssl_cert) && attrs.key?(:ssl_key)
|
32
|
+
raise ArgumentError, "client_id, password, ssl_cert and ssl_key are required"
|
33
|
+
end
|
34
|
+
attrs[:server] ||= 'epp.hostmaster.ua'
|
35
|
+
attrs[:port] ||= 700
|
36
|
+
attrs[:version] ||= '1.0'
|
37
|
+
@services = EPPClient::SCHEMAS_URL.values_at('domain', 'host', 'contact')
|
38
|
+
super(attrs)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/epp-client.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "epp-client/hostmaster"
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: epp-client-hostmaster
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Yuriy Kolodovskyy
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: epp-client-base
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.11.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.11.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: builder
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 3.1.4
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.1.4
|
62
|
+
description: Hostmaster.UA EPP client library
|
63
|
+
email:
|
64
|
+
- kolodovskyy@ukrindex.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- Gemfile
|
71
|
+
- LICENSE.txt
|
72
|
+
- README.md
|
73
|
+
- Rakefile
|
74
|
+
- epp-client-hostmaster.gemspec
|
75
|
+
- lib/epp-client.rb
|
76
|
+
- lib/epp-client/hostmaster-connection.rb
|
77
|
+
- lib/epp-client/hostmaster-contact.rb
|
78
|
+
- lib/epp-client/hostmaster-domain.rb
|
79
|
+
- lib/epp-client/hostmaster-host.rb
|
80
|
+
- lib/epp-client/hostmaster-rgp.rb
|
81
|
+
- lib/epp-client/hostmaster-transfer.rb
|
82
|
+
- lib/epp-client/hostmaster-xml.rb
|
83
|
+
- lib/epp-client/hostmaster.rb
|
84
|
+
homepage: https://github.com/kolodovskyy/epp-client-hostmaster
|
85
|
+
licenses: []
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 1.8.24
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: Hostmaster.UA EPP client library
|
108
|
+
test_files: []
|