kono_epp_client 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/lib/epp/epp_command.rb +15 -0
- data/lib/epp/epp_command/create_contact.rb +87 -0
- data/lib/epp/epp_command/create_domain.rb +42 -0
- data/lib/epp/epp_command/delete_contact.rb +15 -0
- data/lib/epp/epp_command/delete_domain.rb +14 -0
- data/lib/epp/epp_command/hello.rb +13 -0
- data/lib/epp/epp_command/info_contact.rb +15 -0
- data/lib/epp/epp_command/info_domain.rb +14 -0
- data/lib/epp/epp_command/login.rb +79 -0
- data/lib/epp/epp_command/logout.rb +10 -0
- data/lib/epp/epp_command/poll.rb +16 -0
- data/lib/epp/epp_command/transfer_domain.rb +19 -0
- data/lib/epp/epp_command/update_contact.rb +115 -0
- data/lib/epp/epp_command/update_domain.rb +88 -0
- data/lib/epp/exceptions.rb +18 -0
- data/lib/epp/server.rb +271 -0
- data/lib/epp/transport.rb +13 -0
- data/lib/epp/transport/http.rb +66 -0
- data/lib/epp/transport/tcp.rb +93 -0
- data/lib/require_parameters.rb +14 -0
- metadata +22 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80640a05d680c3d25c1371495913b4816266e4c2
|
4
|
+
data.tar.gz: 1e2fa73d4c1e1d51ef7a487c275a9a8a08226acb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3bdcb5660089b22ec5ec0f026a35517d04c4c75006b863154db2a04cc0c8809348f0eda14496cd3ed105941c195666ee7a78b8b0eace40db8f44b22efeb1b418
|
7
|
+
data.tar.gz: 4f1eca44ce49bee99b1ededec75b3e30c058de3ffd1a5cf186e3579355767bbbb25b9f7d83930595b8a7e721bc7b271ca295c23c5642f1353d870fdd7a6fd90b
|
data/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
include REXML
|
2
|
+
|
3
|
+
class KonoEppCommand < REXML::Document
|
4
|
+
def initialize( source = nil, context = nil )
|
5
|
+
super( source, context )
|
6
|
+
|
7
|
+
add( XMLDecl.new( "1.0", "UTF-8", "no" ) )
|
8
|
+
|
9
|
+
epp = add_element( "epp", { "xmlns" => "urn:ietf:params:xml:ns:epp-1.0",
|
10
|
+
"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
|
11
|
+
"xsi:schemaLocation" => "urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd" } )
|
12
|
+
|
13
|
+
epp.add_element( "command" )
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
class KonoEppCreateContact < KonoEppCommand
|
2
|
+
def initialize( options )
|
3
|
+
super( nil, nil )
|
4
|
+
|
5
|
+
command = root.elements['command']
|
6
|
+
|
7
|
+
create = command.add_element "create"
|
8
|
+
|
9
|
+
contact_create = create.add_element( "contact:create", { "xmlns:contact" => "urn:ietf:params:xml:ns:contact-1.0",
|
10
|
+
"xsi:schemaLocation" => "urn:ietf:params:xml:ns:contact-1.0 contact-1.0.xsd" } )
|
11
|
+
|
12
|
+
puts options
|
13
|
+
id = contact_create.add_element "contact:id"
|
14
|
+
id.text = options[:id]
|
15
|
+
|
16
|
+
postal_info = contact_create.add_element "contact:postalInfo", { "type" => "loc" }
|
17
|
+
|
18
|
+
name = postal_info.add_element "contact:name"
|
19
|
+
name.text = options[:name]
|
20
|
+
|
21
|
+
unless options[:organization].blank?
|
22
|
+
organization = postal_info.add_element "contact:org"
|
23
|
+
organization.text = options[:organization]
|
24
|
+
end
|
25
|
+
|
26
|
+
addr = postal_info.add_element "contact:addr"
|
27
|
+
|
28
|
+
unless options[:street].blank?
|
29
|
+
street = addr.add_element "contact:street"
|
30
|
+
street.text = options[:street]
|
31
|
+
end
|
32
|
+
|
33
|
+
city = addr.add_element "contact:city"
|
34
|
+
city.text = options[:city]
|
35
|
+
|
36
|
+
unless options[:state].blank?
|
37
|
+
state = addr.add_element "contact:sp"
|
38
|
+
state.text = options[:state]
|
39
|
+
end
|
40
|
+
|
41
|
+
unless options[:postal_code].blank?
|
42
|
+
postal_code = addr.add_element "contact:pc"
|
43
|
+
postal_code.text = options[:postal_code]
|
44
|
+
end
|
45
|
+
|
46
|
+
country_code = addr.add_element "contact:cc"
|
47
|
+
country_code.text = options[:country_code]
|
48
|
+
|
49
|
+
if options[:voice]
|
50
|
+
voice = contact_create.add_element "contact:voice"
|
51
|
+
voice.text = options[:voice]
|
52
|
+
end
|
53
|
+
|
54
|
+
if options[:fax]
|
55
|
+
fax = contact_create.add_element "contact:fax"
|
56
|
+
fax.text = options[:fax]
|
57
|
+
end
|
58
|
+
|
59
|
+
email = contact_create.add_element "contact:email"
|
60
|
+
email.text = options[:email]
|
61
|
+
|
62
|
+
auth_info = contact_create.add_element "contact:authInfo"
|
63
|
+
pw = auth_info.add_element "contact:pw"
|
64
|
+
pw.text = options[:auth_info]
|
65
|
+
|
66
|
+
# FIXME
|
67
|
+
extension = command.add_element "extension"
|
68
|
+
extension_create = extension.add_element "extcon:create", { "xmlns:extcon" => 'http://www.nic.it/ITNIC-EPP/extcon-1.0',
|
69
|
+
"xsi:schemaLocation" => 'http://www.nic.it/ITNIC-EPP/extcon-1.0 extcon-1.0.xsd' }
|
70
|
+
|
71
|
+
publish = extension_create.add_element "extcon:consentForPublishing"
|
72
|
+
publish.text = options[:publish] == "1" ? "true" : "false"
|
73
|
+
|
74
|
+
if options[:is_registrant]
|
75
|
+
extcon_registrant = extension_create.add_element "extcon:registrant"
|
76
|
+
|
77
|
+
extcon_nationality = extcon_registrant.add_element "extcon:nationalityCode"
|
78
|
+
extcon_nationality.text = options[:nationality]
|
79
|
+
|
80
|
+
extcon_entity = extcon_registrant.add_element "extcon:entityType"
|
81
|
+
extcon_entity.text = options[:entity_type]
|
82
|
+
|
83
|
+
extcon_regcode = extcon_registrant.add_element "extcon:regCode"
|
84
|
+
extcon_regcode.text = options[:reg_code]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class KonoEppCreateDomain < KonoEppCommand
|
2
|
+
def initialize( options )
|
3
|
+
super( nil, nil )
|
4
|
+
|
5
|
+
command = root.elements['command']
|
6
|
+
create = command.add_element( "create" )
|
7
|
+
|
8
|
+
|
9
|
+
domain_create = create.add_element( "domain:create", { "xmlns:domain" => "urn:ietf:params:xml:ns:domain-1.0",
|
10
|
+
"xsi:schemaLocation" => "urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd" } )
|
11
|
+
|
12
|
+
name = domain_create.add_element "domain:name"
|
13
|
+
name.text = options[:name]
|
14
|
+
|
15
|
+
domain_ns = domain_create.add_element "domain:ns"
|
16
|
+
|
17
|
+
options[:nameservers].each do |ns|
|
18
|
+
host_attr = domain_ns.add_element "domain:hostAttr"
|
19
|
+
host_name = host_attr.add_element "domain:hostName"
|
20
|
+
|
21
|
+
host_name.text = ns[0]
|
22
|
+
|
23
|
+
# FIXME IPv6
|
24
|
+
host_addr = host_attr.add_element "domain:hostAddr", { "ip" => "v4" }
|
25
|
+
host_addr.text = ns[1]
|
26
|
+
end
|
27
|
+
|
28
|
+
domain_registrant = domain_create.add_element "domain:registrant"
|
29
|
+
domain_registrant.text = options[:registrant]
|
30
|
+
|
31
|
+
domain_contact = domain_create.add_element "domain:contact", { "type" => "admin" }
|
32
|
+
domain_contact.text = options[:admin]
|
33
|
+
|
34
|
+
domain_contact = domain_create.add_element "domain:contact", { "type" => "tech" }
|
35
|
+
domain_contact.text = options[:tech]
|
36
|
+
|
37
|
+
domain_authinfo = domain_create.add_element "domain:authInfo"
|
38
|
+
|
39
|
+
domain_pw = domain_authinfo.add_element "domain:pw"
|
40
|
+
domain_pw.text = options[:authinfo]
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class KonoEppDeleteContact < KonoEppCommand
|
2
|
+
def initialize( id )
|
3
|
+
super( nil, nil )
|
4
|
+
|
5
|
+
command = root.elements['command']
|
6
|
+
|
7
|
+
delete = command.add_element "delete"
|
8
|
+
|
9
|
+
contact_delete = delete.add_element( "contact:delete", { "xmlns:contact" => "urn:ietf:params:xml:ns:contact-1.0",
|
10
|
+
"xsi:schemaLocation" => "urn:ietf:params:xml:ns:contact-1.0 contact-1.0.xsd" } )
|
11
|
+
|
12
|
+
contact_id = contact_delete.add_element "contact:id"
|
13
|
+
contact_id.text = id
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class KonoEppDeleteDomain < KonoEppCommand
|
2
|
+
def initialize( name )
|
3
|
+
super( nil, nil )
|
4
|
+
|
5
|
+
command = root.elements['command']
|
6
|
+
delete = command.add_element( "delete" )
|
7
|
+
|
8
|
+
domain_delete = delete.add_element( "domain:delete", { "xmlns:domain" => "urn:ietf:params:xml:ns:domain-1.0",
|
9
|
+
"xsi:schemaLocation" => "urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd" } )
|
10
|
+
|
11
|
+
domain_name = domain_delete.add_element "domain:name"
|
12
|
+
domain_name.text = name
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class KonoEppHello < REXML::Document
|
2
|
+
def initialize
|
3
|
+
super
|
4
|
+
|
5
|
+
add( XMLDecl.new( "1.0", "UTF-8", "no" ) )
|
6
|
+
|
7
|
+
epp = add_element( "epp", { "xmlns" => "urn:ietf:params:xml:ns:epp-1.0",
|
8
|
+
"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
|
9
|
+
"xsi:schemaLocation" => "urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd" } )
|
10
|
+
|
11
|
+
epp.add_element( "hello" )
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class KonoEppInfoContact < KonoEppCommand
|
2
|
+
def initialize( id )
|
3
|
+
super( nil, nil )
|
4
|
+
|
5
|
+
command = root.elements['command']
|
6
|
+
|
7
|
+
info = command.add_element "info"
|
8
|
+
|
9
|
+
contact_info = info.add_element( "contact:info", { "xmlns:contact" => "urn:ietf:params:xml:ns:contact-1.0",
|
10
|
+
"xsi:schemaLocation" => "urn:ietf:params:xml:ns:contact-1.0 contact-1.0.xsd" } )
|
11
|
+
|
12
|
+
contact_id = contact_info.add_element "contact:id"
|
13
|
+
contact_id.text = id
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class KonoEppInfoDomain < KonoEppCommand
|
2
|
+
def initialize( name )
|
3
|
+
super( nil, nil )
|
4
|
+
|
5
|
+
command = root.elements['command']
|
6
|
+
info = command.add_element( "info" )
|
7
|
+
|
8
|
+
domain_info = info.add_element( "domain:info", { "xmlns:domain" => "urn:ietf:params:xml:ns:domain-1.0",
|
9
|
+
"xsi:schemaLocation" => "urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd" } )
|
10
|
+
|
11
|
+
domain_name = domain_info.add_element "domain:name", { "hosts" => "all" }
|
12
|
+
domain_name.text = name
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class KonoEppLogin < KonoEppCommand
|
2
|
+
def initialize( id = nil, password = nil )
|
3
|
+
super( nil, nil )
|
4
|
+
|
5
|
+
@command = root.elements['command']
|
6
|
+
@login = @command.add_element( "login" )
|
7
|
+
|
8
|
+
@login.add_element( "clID" ).text = id if id
|
9
|
+
@login.add_element( "pw" ).text = password if password
|
10
|
+
|
11
|
+
@command.add_element( "clTRID" ).text = "ABC-12345"
|
12
|
+
end
|
13
|
+
|
14
|
+
def version=( value )
|
15
|
+
@options = @login.add_element( "options" ) unless @options
|
16
|
+
@options.add_element( "version") unless @options.elements['version']
|
17
|
+
|
18
|
+
@options.elements['version'].text = value
|
19
|
+
end
|
20
|
+
|
21
|
+
def version
|
22
|
+
version = @options.elements['version']
|
23
|
+
|
24
|
+
version.text if version
|
25
|
+
end
|
26
|
+
|
27
|
+
def lang=( value )
|
28
|
+
@options = @login.add_element( "options" ) unless @options
|
29
|
+
@options.add_element( "lang") unless @options.elements['lang']
|
30
|
+
|
31
|
+
@options.elements['lang'].text = value
|
32
|
+
end
|
33
|
+
|
34
|
+
def lang
|
35
|
+
lang = @options.elements['lang']
|
36
|
+
|
37
|
+
lang.text if version
|
38
|
+
end
|
39
|
+
|
40
|
+
def new_password=( value )
|
41
|
+
newpw = @login.add_element( "newPW" )
|
42
|
+
newpw.text = value
|
43
|
+
end
|
44
|
+
|
45
|
+
def services=( services )
|
46
|
+
svcs = @login.add_element( "svcs" ) unless @login.elements['svcs']
|
47
|
+
services.each {|service| svcs.add_element("objURI").text = service }
|
48
|
+
end
|
49
|
+
|
50
|
+
def services
|
51
|
+
svcs = @login.elements['svcs']
|
52
|
+
|
53
|
+
res = []
|
54
|
+
svcs.elements.each( "objURI" ) { |obj| res << obj.text } if svcs
|
55
|
+
|
56
|
+
return res
|
57
|
+
end
|
58
|
+
|
59
|
+
def extensions=( extensions )
|
60
|
+
svcs = @login.elements['svcs']
|
61
|
+
|
62
|
+
svcs = @login.add_element( "svcs" ) unless svcs
|
63
|
+
|
64
|
+
# Include schema extensions for registrars which require it
|
65
|
+
extensions_container = svcs.add_element("svcExtension") unless extensions.empty?
|
66
|
+
|
67
|
+
for uri in extensions
|
68
|
+
extensions_container.add_element("extURI").text = uri
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def extensions
|
73
|
+
svc_extension = @login.elements['svcs/svcExtension']
|
74
|
+
|
75
|
+
svc_extension.elements.each( "extURI" ) { |obj| res << obj.text } if svcs_extension
|
76
|
+
|
77
|
+
return res
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class KonoEppPoll < KonoEppCommand
|
2
|
+
def initialize( op = :req )
|
3
|
+
super( nil, nil )
|
4
|
+
|
5
|
+
command = root.elements['command']
|
6
|
+
poll = command.add_element( "poll" )
|
7
|
+
|
8
|
+
poll.add_attribute( "op", op.to_s )
|
9
|
+
end
|
10
|
+
|
11
|
+
def ack_id=( id )
|
12
|
+
poll = root.elements['command/poll']
|
13
|
+
|
14
|
+
poll.add_attribute( "msgID", id )
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class KonoEppTransferDomain < KonoEppCommand
|
2
|
+
def initialize( name, authinfo, op )
|
3
|
+
super( nil, nil )
|
4
|
+
|
5
|
+
command = root.elements['command']
|
6
|
+
transfer = command.add_element( "transfer", { "op" => op } )
|
7
|
+
|
8
|
+
domain_transfer = transfer.add_element( "domain:transfer", { "xmlns:domain" => "urn:ietf:params:xml:ns:domain-1.0",
|
9
|
+
"xsi:schemaLocation" => "urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd" } )
|
10
|
+
|
11
|
+
domain_name = domain_transfer.add_element "domain:name"
|
12
|
+
domain_name.text = name
|
13
|
+
|
14
|
+
domain_authinfo = domain_transfer.add_element "domain:authInfo"
|
15
|
+
domain_pw = domain_authinfo.add_element "domain:pw"
|
16
|
+
|
17
|
+
domain_pw.text = authinfo
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
class KonoEppUpdateContact < KonoEppCommand
|
2
|
+
|
3
|
+
# TODO: Add and remove fields
|
4
|
+
def initialize( options )
|
5
|
+
super( nil, nil )
|
6
|
+
|
7
|
+
command = root.elements['command']
|
8
|
+
|
9
|
+
update = command.add_element "update"
|
10
|
+
|
11
|
+
contact_update = update.add_element( "contact:update", { "xmlns:contact" => "urn:ietf:params:xml:ns:contact-1.0",
|
12
|
+
"xsi:schemaLocation" => "urn:ietf:params:xml:ns:contact-1.0 contact-1.0.xsd" } )
|
13
|
+
|
14
|
+
id = contact_update.add_element "contact:id"
|
15
|
+
id.text = options[:id]
|
16
|
+
|
17
|
+
contact_chg = contact_update.add_element "contact:chg"
|
18
|
+
|
19
|
+
unless options[:name].blank? \
|
20
|
+
and options[:organization].blank? \
|
21
|
+
and options[:address].blank? \
|
22
|
+
and options[:city].blank? \
|
23
|
+
and options[:state].blank? \
|
24
|
+
and options[:postal_code].blank? \
|
25
|
+
and options[:country].blank?
|
26
|
+
|
27
|
+
postal_info = contact_chg.add_element "contact:postalInfo", { "type" => "loc" }
|
28
|
+
|
29
|
+
unless options[:name].blank?
|
30
|
+
name = postal_info.add_element "contact:name"
|
31
|
+
name.text = options[:name]
|
32
|
+
end
|
33
|
+
|
34
|
+
unless options[:organization].blank?
|
35
|
+
organization = postal_info.add_element "contact:org"
|
36
|
+
organization.text = options[:organization]
|
37
|
+
end
|
38
|
+
|
39
|
+
# NOTE: city and country are REQUIRED
|
40
|
+
unless options[:address].blank? \
|
41
|
+
and options[:city].blank? \
|
42
|
+
and options[:state].blank? \
|
43
|
+
and options[:postal_code].blank? \
|
44
|
+
and options[:country].blank?
|
45
|
+
|
46
|
+
addr = postal_info.add_element "contact:addr"
|
47
|
+
|
48
|
+
unless options[:address].blank?
|
49
|
+
street = addr.add_element "contact:street"
|
50
|
+
street.text = options[:address]
|
51
|
+
end
|
52
|
+
|
53
|
+
city = addr.add_element "contact:city"
|
54
|
+
city.text = options[:city]
|
55
|
+
|
56
|
+
unless options[:state].blank?
|
57
|
+
state = addr.add_element "contact:sp"
|
58
|
+
state.text = options[:state]
|
59
|
+
end
|
60
|
+
|
61
|
+
unless options[:postal_code].blank?
|
62
|
+
postal_code = addr.add_element "contact:pc"
|
63
|
+
postal_code.text = options[:postal_code]
|
64
|
+
end
|
65
|
+
|
66
|
+
country_code = addr.add_element "contact:cc"
|
67
|
+
country_code.text = options[:country]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if options[:voice]
|
72
|
+
voice = contact_chg.add_element "contact:voice"
|
73
|
+
voice.text = options[:voice]
|
74
|
+
end
|
75
|
+
|
76
|
+
if options[:fax]
|
77
|
+
fax = contact_chg.add_element "contact:fax"
|
78
|
+
fax.text = options[:fax]
|
79
|
+
end
|
80
|
+
|
81
|
+
if options[:email]
|
82
|
+
email = contact_chg.add_element "contact:email"
|
83
|
+
email.text = options[:email]
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
unless not options.has_key?( :publish ) \
|
88
|
+
and options[:nationality].blank? \
|
89
|
+
and options[:entity_type].blank? \
|
90
|
+
and options[:reg_code].blank?
|
91
|
+
|
92
|
+
# FIXME
|
93
|
+
extension = command.add_element "extension"
|
94
|
+
extension_update = extension.add_element "extcon:update", { "xmlns:extcon" => 'http://www.nic.it/ITNIC-EPP/extcon-1.0',
|
95
|
+
"xsi:schemaLocation" => 'http://www.nic.it/ITNIC-EPP/extcon-1.0 extcon-1.0.xsd' }
|
96
|
+
if options.has_key?( :publish )
|
97
|
+
publish = extension_update.add_element "extcon:consentForPublishing"
|
98
|
+
publish.text = options[:publish]
|
99
|
+
end
|
100
|
+
|
101
|
+
if options[:becomes_registrant]
|
102
|
+
extcon_registrant = extension_update.add_element "extcon:registrant"
|
103
|
+
|
104
|
+
extcon_nationality = extcon_registrant.add_element "extcon:nationalityCode"
|
105
|
+
extcon_nationality.text = options[:nationality]
|
106
|
+
|
107
|
+
extcon_entity = extcon_registrant.add_element "extcon:entityType"
|
108
|
+
extcon_entity.text = options[:entity_type]
|
109
|
+
|
110
|
+
extcon_regcode = extcon_registrant.add_element "extcon:regCode"
|
111
|
+
extcon_regcode.text = options[:reg_code]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
class KonoEppUpdateDomain < KonoEppCommand
|
2
|
+
def initialize( options )
|
3
|
+
super( nil, nil )
|
4
|
+
|
5
|
+
command = root.elements['command']
|
6
|
+
update = command.add_element( "update" )
|
7
|
+
|
8
|
+
|
9
|
+
domain_update = update.add_element( "domain:update", { "xmlns:domain" => "urn:ietf:params:xml:ns:domain-1.0",
|
10
|
+
"xsi:schemaLocation" => "urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd" } )
|
11
|
+
|
12
|
+
name = domain_update.add_element "domain:name"
|
13
|
+
name.text = options[:name]
|
14
|
+
|
15
|
+
if not options[:add_nameservers].blank? or options[:add_admin] or options[:add_tech]
|
16
|
+
domain_add = domain_update.add_element "domain:add"
|
17
|
+
end
|
18
|
+
|
19
|
+
if not options[:remove_nameservers].blank? or options[:remove_admin] or options[:remove_tech]
|
20
|
+
domain_remove = domain_update.add_element "domain:rem"
|
21
|
+
end
|
22
|
+
|
23
|
+
# <domain:add>
|
24
|
+
unless options[:add_nameservers].blank?
|
25
|
+
domain_add_ns = domain_add.add_element "domain:ns"
|
26
|
+
|
27
|
+
options[:add_nameservers].each do |ns|
|
28
|
+
host_attr = domain_add_ns.add_element "domain:hostAttr"
|
29
|
+
host_name = host_attr.add_element "domain:hostName"
|
30
|
+
|
31
|
+
host_name.text = ns[0]
|
32
|
+
|
33
|
+
# FIXME IPv6
|
34
|
+
host_addr = host_attr.add_element "domain:hostAddr", { "ip" => "v4" }
|
35
|
+
host_addr.text = ns[1]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
if options[:add_admin]
|
40
|
+
domain_contact = domain_add.add_element "domain:contact", { "type" => "admin" }
|
41
|
+
domain_contact.text = options[:add_admin]
|
42
|
+
end
|
43
|
+
|
44
|
+
if options[:add_tech]
|
45
|
+
domain_contact = domain_add.add_element "domain:contact", { "type" => "tech" }
|
46
|
+
domain_contact.text = options[:add_tech]
|
47
|
+
end
|
48
|
+
|
49
|
+
# <domain:rem>
|
50
|
+
unless options[:remove_nameservers].blank?
|
51
|
+
domain_remove_ns = domain_remove.add_element "domain:ns"
|
52
|
+
|
53
|
+
options[:remove_nameservers].each do |name|
|
54
|
+
host_attr = domain_remove_ns.add_element "domain:hostAttr"
|
55
|
+
host_name = host_attr.add_element "domain:hostName"
|
56
|
+
|
57
|
+
host_name.text = name
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
if options[:remove_admin]
|
62
|
+
domain_contact = domain_remove.add_element "domain:contact", { "type" => "admin" }
|
63
|
+
domain_contact.text = options[:remove_admin]
|
64
|
+
end
|
65
|
+
|
66
|
+
if options[:remove_tech]
|
67
|
+
domain_contact = domain_remove.add_element "domain:contact", { "type" => "tech" }
|
68
|
+
domain_contact.text = options[:remove_tech]
|
69
|
+
end
|
70
|
+
|
71
|
+
# <domain:chg>
|
72
|
+
if options[:auth_info]
|
73
|
+
domain_change = domain_update.add_element "domain:chg"
|
74
|
+
|
75
|
+
if options[:registrant]
|
76
|
+
domain_registrant = domain_change.add_element "domain:registrant"
|
77
|
+
domain_registrant.text = options[:registrant]
|
78
|
+
end
|
79
|
+
|
80
|
+
domain_authinfo = domain_change.add_element "domain:authInfo"
|
81
|
+
|
82
|
+
domain_pw = domain_authinfo.add_element "domain:pw"
|
83
|
+
domain_pw.text = options[:auth_info]
|
84
|
+
end
|
85
|
+
|
86
|
+
# TODO: Registrant
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class KonoEppErrorResponse < StandardError #:nodoc:
|
2
|
+
attr_accessor :response_xml, :response_code, :reason_code, :message
|
3
|
+
|
4
|
+
# Generic EPP exception. Accepts a response code and a message
|
5
|
+
def initialize(attributes = {})
|
6
|
+
@response_xml = attributes[:xml]
|
7
|
+
@response_code = attributes[:response_code]
|
8
|
+
@reason_code = attributes[:reason_code]
|
9
|
+
@message = attributes[:message]
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"#{@message} (reason: #{@reason_code} code: #{@response_code})"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class KonoEppAuthenticationPasswordExpired < KonoEppErrorResponse ; end
|
18
|
+
class KonoEppLoginNeeded < KonoEppErrorResponse ; end
|
data/lib/epp/server.rb
ADDED
@@ -0,0 +1,271 @@
|
|
1
|
+
module KonoEppClient #:nodoc:
|
2
|
+
class Server
|
3
|
+
include REXML
|
4
|
+
include RequiresParameters
|
5
|
+
|
6
|
+
require 'nokogiri'
|
7
|
+
|
8
|
+
attr_accessor :tag, :password, :server, :port, :old_server, :services, :lang, :extensions, :version, :credit, :timeout
|
9
|
+
|
10
|
+
# ==== Required Attrbiutes
|
11
|
+
#
|
12
|
+
# * <tt>:server</tt> - The EPP server to connect to
|
13
|
+
# * <tt>:tag</tt> - The tag or username used with <tt><login></tt> requests.
|
14
|
+
# * <tt>:password</tt> - The password used with <tt><login></tt> requests.
|
15
|
+
#
|
16
|
+
# ==== Optional Attributes
|
17
|
+
#
|
18
|
+
# * <tt>:port</tt> - The EPP standard port is 700. However, you can choose a different port to use.
|
19
|
+
# * <tt>:clTRID</tt> - The client transaction identifier is an element that EPP specifies MAY be used to uniquely identify the command to the server. You are responsible for maintaining your own transaction identifier space to ensure uniqueness. Defaults to "ABC-12345"
|
20
|
+
# * <tt>:old_server</tt> - Set to true to read and write frames in a way that is compatible with older EPP servers. Default is false.
|
21
|
+
# * <tt>:lang</tt> - Set custom language attribute. Default is 'en'.
|
22
|
+
# * <tt>:services</tt> - Use custom EPP services in the <login> frame. The defaults use the EPP standard domain, contact and host 1.0 services.
|
23
|
+
# * <tt>:extensions</tt> - URLs to custom extensions to standard EPP. Use these to extend the standard EPP (e.g., Nominet uses extensions). Defaults to none.
|
24
|
+
# * <tt>:version</tt> - Set the EPP version. Defaults to "1.0".
|
25
|
+
def initialize(attributes = {})
|
26
|
+
requires!(attributes, :tag, :password, :server)
|
27
|
+
|
28
|
+
@tag = attributes[:tag]
|
29
|
+
@password = attributes[:password]
|
30
|
+
@server = attributes[:server]
|
31
|
+
@port = attributes[:port] || 700
|
32
|
+
@old_server = attributes[:old_server] || false
|
33
|
+
@lang = attributes[:lang] || "en"
|
34
|
+
@services = attributes[:services] || ["urn:ietf:params:xml:ns:domain-1.0", "urn:ietf:params:xml:ns:contact-1.0", "urn:ietf:params:xml:ns:host-1.0"]
|
35
|
+
@extensions = attributes[:extensions] || []
|
36
|
+
@version = attributes[:version] || "1.0"
|
37
|
+
@transport = attributes[:transport] || :tcp
|
38
|
+
@timeout = attributes[:timeout] || 30
|
39
|
+
|
40
|
+
@logged_in = false
|
41
|
+
end
|
42
|
+
|
43
|
+
def connect_and_hello
|
44
|
+
open_connection
|
45
|
+
|
46
|
+
hello
|
47
|
+
end
|
48
|
+
|
49
|
+
# Closes the connection to the EPP server.
|
50
|
+
def close_connection
|
51
|
+
@connection.close
|
52
|
+
end
|
53
|
+
|
54
|
+
# Sends an XML request to the EPP server, and receives an XML response.
|
55
|
+
# <tt><login></tt> and <tt><logout></tt> requests are also wrapped
|
56
|
+
# around the request, so we can close the socket immediately after
|
57
|
+
# the request is made.
|
58
|
+
def request( xml )
|
59
|
+
# open_connection
|
60
|
+
|
61
|
+
# @logged_in = true if login
|
62
|
+
|
63
|
+
begin
|
64
|
+
@response = send_request( xml )
|
65
|
+
ensure
|
66
|
+
if @logged_in && !old_server
|
67
|
+
@logged_in = false if logout
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
return @response
|
72
|
+
end
|
73
|
+
|
74
|
+
# Sends a standard login request to the EPP server.
|
75
|
+
def login
|
76
|
+
login = KonoEppLogin.new( tag, password )
|
77
|
+
|
78
|
+
# FIXME: Order matters
|
79
|
+
login.version = version
|
80
|
+
login.lang = lang
|
81
|
+
|
82
|
+
login.services = services
|
83
|
+
login.extensions = extensions
|
84
|
+
|
85
|
+
send_command( login )
|
86
|
+
end
|
87
|
+
|
88
|
+
def change_password( new_password )
|
89
|
+
login = KonoEppLogin.new( tag, password )
|
90
|
+
|
91
|
+
# FIXME: Order matters
|
92
|
+
login.new_password = new_password
|
93
|
+
|
94
|
+
login.version = version
|
95
|
+
login.lang = lang
|
96
|
+
|
97
|
+
login.services = services
|
98
|
+
login.extensions = extensions
|
99
|
+
|
100
|
+
send_command( login )
|
101
|
+
end
|
102
|
+
|
103
|
+
def logged_in?
|
104
|
+
begin
|
105
|
+
poll
|
106
|
+
rescue
|
107
|
+
return false
|
108
|
+
end
|
109
|
+
|
110
|
+
return true
|
111
|
+
end
|
112
|
+
|
113
|
+
# FIXME: Remove command wrappers?
|
114
|
+
def hello
|
115
|
+
response = Hpricot.XML( send_request( KonoEppHello.new.to_s ) )
|
116
|
+
end
|
117
|
+
|
118
|
+
def poll( id = nil )
|
119
|
+
poll = KonoEppPoll.new( id ? :ack : :req )
|
120
|
+
|
121
|
+
poll.ack_id = id if id
|
122
|
+
|
123
|
+
send_command( poll )
|
124
|
+
end
|
125
|
+
|
126
|
+
def create_contact( options )
|
127
|
+
contact = KonoEppCreateContact.new options
|
128
|
+
send_command( contact )
|
129
|
+
end
|
130
|
+
|
131
|
+
def delete_contact( id )
|
132
|
+
contact = KonoEppDeleteContact.new id
|
133
|
+
send_command( contact )
|
134
|
+
end
|
135
|
+
|
136
|
+
def update_contact( options )
|
137
|
+
contact = KonoEppUpdateContact.new options
|
138
|
+
send_command( contact )
|
139
|
+
end
|
140
|
+
|
141
|
+
def create_domain( options )
|
142
|
+
domain = KonoEppCreateDomain.new options
|
143
|
+
send_command( domain )
|
144
|
+
end
|
145
|
+
|
146
|
+
def update_domain( options )
|
147
|
+
domain = KonoEppUpdateDomain.new options
|
148
|
+
send_command( domain )
|
149
|
+
end
|
150
|
+
|
151
|
+
def delete_domain( name )
|
152
|
+
domain = KonoEppDeleteDomain.new name
|
153
|
+
send_command( domain )
|
154
|
+
end
|
155
|
+
|
156
|
+
def info_contact( id )
|
157
|
+
contact = KonoEppInfoContact.new id
|
158
|
+
send_command( contact )
|
159
|
+
end
|
160
|
+
|
161
|
+
def info_domain( name )
|
162
|
+
info = KonoEppInfoDomain.new name
|
163
|
+
send_command( info )
|
164
|
+
end
|
165
|
+
|
166
|
+
def transfer_domain( name, authinfo, op )
|
167
|
+
transfer = KonoEppTransferDomain.new name, authinfo, op
|
168
|
+
send_command( transfer )
|
169
|
+
end
|
170
|
+
|
171
|
+
# Sends a standard logout request to the EPP server.
|
172
|
+
def logout
|
173
|
+
send_command( KonoEppLogout.new, 1500 )
|
174
|
+
end
|
175
|
+
|
176
|
+
# private
|
177
|
+
# Wrapper which sends XML to the server, and receives
|
178
|
+
# the response in return.
|
179
|
+
def send_request( xml )
|
180
|
+
write( xml )
|
181
|
+
read
|
182
|
+
end
|
183
|
+
|
184
|
+
def send_command( command, expected_result = 1000..1999 )
|
185
|
+
namespaces = { 'extepp' => 'http://www.nic.it/ITNIC-EPP/extepp-2.0',
|
186
|
+
'xmlns' => "urn:ietf:params:xml:ns:epp-1.0" }
|
187
|
+
|
188
|
+
xml = Nokogiri.XML( send_request( command.to_s ) )
|
189
|
+
|
190
|
+
# TODO: multiple <response> RFC 3730 §2.6
|
191
|
+
result = xml.at_xpath( "/xmlns:epp/xmlns:response[1]/xmlns:result",
|
192
|
+
namespaces )
|
193
|
+
raise KonoEppErrorResponse.new( :message => 'Malformed response' ) if result.nil?
|
194
|
+
|
195
|
+
xmlns_code = result.at_xpath( "@code" )
|
196
|
+
raise KonoEppErrorResponse.new( :message => 'Malformed response' ) if xmlns_code.nil?
|
197
|
+
|
198
|
+
response_code = xmlns_code.value.to_i
|
199
|
+
|
200
|
+
xmlns_msg = result.xpath( "xmlns:msg/text ()",
|
201
|
+
namespaces )
|
202
|
+
raise KonoEppErrorResponse.new( :message => 'Malformed response' ) if xmlns_msg.empty?
|
203
|
+
|
204
|
+
result_message = xmlns_msg.text.strip
|
205
|
+
|
206
|
+
# TODO: value
|
207
|
+
|
208
|
+
xmlns_ext_reason = result.xpath( "xmlns:extValue/xmlns:reason",
|
209
|
+
namespaces)
|
210
|
+
result_message += ": #{xmlns_ext_reason.text.strip}" unless xmlns_ext_reason.empty?
|
211
|
+
|
212
|
+
xmlns_reason_code = result.xpath( "xmlns:extValue/xmlns:value/extepp:reasonCode",
|
213
|
+
namespaces )
|
214
|
+
reason_code = xmlns_reason_code.text.strip.to_i unless xmlns_reason_code.empty?
|
215
|
+
|
216
|
+
credit_msg = xml.xpath( "//extepp:credit/text ()",
|
217
|
+
namespaces )
|
218
|
+
@credit = credit_msg.text.to_f unless credit_msg.empty?
|
219
|
+
|
220
|
+
if expected_result === response_code
|
221
|
+
return xml
|
222
|
+
end
|
223
|
+
|
224
|
+
args = { :xml => xml,
|
225
|
+
:response_code => response_code,
|
226
|
+
:reason_code => reason_code,
|
227
|
+
:message => result_message }
|
228
|
+
|
229
|
+
case [ response_code, reason_code ]
|
230
|
+
when [2200, 6004]
|
231
|
+
raise KonoEppAuthenticationPasswordExpired.new( args )
|
232
|
+
when [2002, 4015]
|
233
|
+
raise KonoEppLoginNeeded.new( args )
|
234
|
+
else
|
235
|
+
raise KonoEppErrorResponse.new( args )
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# Establishes the connection to the server. If the connection is
|
240
|
+
# established, then this method will call read and return
|
241
|
+
# the EPP <tt><greeting></tt> which is sent by the
|
242
|
+
# server upon connection.
|
243
|
+
def open_connection
|
244
|
+
Timeout.timeout @timeout do
|
245
|
+
@connection = case @transport
|
246
|
+
when :tcp then KonoEppClient::Transport::TcpTransport.new( server, port )
|
247
|
+
when :http then KonoEppClient::Transport::HttpTransport.new( server, port )
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
|
253
|
+
# Receive an EPP response from the server. Since the connection is blocking,
|
254
|
+
# this method will wait until the connection becomes available for use. If
|
255
|
+
# the connection is broken, a SocketError will be raised. Otherwise,
|
256
|
+
# it will return a string containing the XML from the server.
|
257
|
+
def read
|
258
|
+
Timeout.timeout @timeout do
|
259
|
+
@connection.read
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
# Send XML to the server. If the socket returns EOF,
|
264
|
+
# the connection has closed and a SocketError is raised.
|
265
|
+
def write( xml )
|
266
|
+
Timeout.timeout @timeout do
|
267
|
+
@connection.write( xml )
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module KonoEppClient::Transport
|
4
|
+
class HttpTransport
|
5
|
+
include KonoEppClient::Transport
|
6
|
+
|
7
|
+
require 'pstore'
|
8
|
+
|
9
|
+
def initialize( server, port )
|
10
|
+
@net_http = Net::HTTP.new( server, port )
|
11
|
+
|
12
|
+
@net_http.use_ssl = true
|
13
|
+
@net_http.ssl_version = :TLSv1
|
14
|
+
@net_http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
15
|
+
|
16
|
+
#FIXME: Commented because not work on MacOS (dev machine), is necessary for Linux machine?
|
17
|
+
#@net_http.ca_path = '/etc/ssl/certs'
|
18
|
+
|
19
|
+
# @net_http.set_debug_output $stderr
|
20
|
+
#@net_http.set_debug_output File.open( "/tmp/net.log", "a")
|
21
|
+
|
22
|
+
@store = PStore.new( "cookies.pstore" )
|
23
|
+
end
|
24
|
+
|
25
|
+
def read
|
26
|
+
#puts @response.body
|
27
|
+
@response.body
|
28
|
+
end
|
29
|
+
|
30
|
+
def write( xml )
|
31
|
+
@store.transaction do
|
32
|
+
cookie_str = '$Version="1"'
|
33
|
+
@store[:cookies].each do |c|
|
34
|
+
cookie_str += "; #{c[:name]}=#{c[:value]}"
|
35
|
+
end if @store[:cookies]
|
36
|
+
|
37
|
+
header = { "Cookie" => cookie_str }
|
38
|
+
|
39
|
+
@response = @net_http.post( "/", xml, header )
|
40
|
+
|
41
|
+
@store[:cookies] = parse_set_cookie( @response["Set-Cookie"] ) if @response["Set-Cookie"]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def close
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def parse_set_cookie( string )
|
50
|
+
cookies = []
|
51
|
+
|
52
|
+
string.split( "," ).each do |cookie|
|
53
|
+
tokens = cookie.split ";"
|
54
|
+
|
55
|
+
name, value = tokens[0].split( "=", 2 )
|
56
|
+
# TODO: complete parsing. Maybe encapsulate the cookie as well.
|
57
|
+
cookies << { :name => name, :value => value }
|
58
|
+
end
|
59
|
+
|
60
|
+
return cookies
|
61
|
+
end
|
62
|
+
|
63
|
+
def http_post
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module KonoEppClient::Transport
|
2
|
+
class TcpTransport
|
3
|
+
include KonoEppClient::Transport
|
4
|
+
|
5
|
+
def initialize( server, port )
|
6
|
+
@connection = TCPSocket.new( server, port )
|
7
|
+
@socket = OpenSSL::SSL::SSLSocket.new( @connection )
|
8
|
+
|
9
|
+
# Synchronously close the connection & socket
|
10
|
+
@socket.sync_close
|
11
|
+
|
12
|
+
# Connect
|
13
|
+
@socket.connect
|
14
|
+
|
15
|
+
# Get the initial frame
|
16
|
+
read
|
17
|
+
end
|
18
|
+
|
19
|
+
def read
|
20
|
+
if old_server
|
21
|
+
data = ""
|
22
|
+
first_char = @socket.read(1)
|
23
|
+
|
24
|
+
if first_char.nil? and @socket.eof?
|
25
|
+
raise SocketError.new("Connection closed by remote server")
|
26
|
+
elsif first_char.nil?
|
27
|
+
raise SocketError.new("Error reading frame from remote server")
|
28
|
+
else
|
29
|
+
data << first_char
|
30
|
+
|
31
|
+
while char = @socket.read(1)
|
32
|
+
data << char
|
33
|
+
|
34
|
+
return data if data =~ %r|<\/epp>\n$|mi # at end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
else
|
38
|
+
header = @socket.read(4)
|
39
|
+
|
40
|
+
if header.nil? and @socket.eof?
|
41
|
+
raise SocketError.new("Connection closed by remote server")
|
42
|
+
elsif header.nil?
|
43
|
+
raise SocketError.new("Error reading frame from remote server")
|
44
|
+
else
|
45
|
+
unpacked_header = header.unpack("N")
|
46
|
+
length = unpacked_header[0]
|
47
|
+
|
48
|
+
if length < 5
|
49
|
+
raise SocketError.new("Got bad frame header length of #{length} bytes from the server")
|
50
|
+
else
|
51
|
+
response = @socket.read(length - 4)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def write
|
58
|
+
if defined?( @socket ) and @socket.is_a?( OpenSSL::SSL::SSLSocket )
|
59
|
+
@socket.close
|
60
|
+
@socket = nil
|
61
|
+
end
|
62
|
+
|
63
|
+
if defined?( @connection ) and @connection.is_a?( TCPSocket )
|
64
|
+
@connection.close
|
65
|
+
@connection = nil
|
66
|
+
end
|
67
|
+
|
68
|
+
return true if @connection.nil? and @socket.nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
def close
|
72
|
+
if defined?( @socket ) and @socket.is_a?( OpenSSL::SSL::SSLSocket )
|
73
|
+
@socket.close
|
74
|
+
@socket = nil
|
75
|
+
end
|
76
|
+
|
77
|
+
if defined?( @connection ) and @connection.is_a?( TCPSocket )
|
78
|
+
@connection.close
|
79
|
+
@connection = nil
|
80
|
+
end
|
81
|
+
|
82
|
+
return true if @connection.nil? and @socket.nil?
|
83
|
+
end
|
84
|
+
private
|
85
|
+
# Receive an EPP frame from the server. Since the connection is blocking,
|
86
|
+
# this method will wait until the connection becomes available for use. If
|
87
|
+
# the connection is broken, a SocketError will be raised. Otherwise,
|
88
|
+
# it will return a string containing the XML from the server.
|
89
|
+
def get_frame
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module RequiresParameters #:nodoc:
|
2
|
+
def requires!(hash, *params)
|
3
|
+
params.each do |param|
|
4
|
+
if param.is_a?(Array)
|
5
|
+
raise ArgumentError.new("Missing required parameter: #{param.first}") unless hash.has_key?(param.first)
|
6
|
+
|
7
|
+
valid_options = param[1..-1]
|
8
|
+
raise ArgumentError.new("Parameter: #{param.first} must be one of #{valid_options.to_sentence(:connector => 'or')}") unless valid_options.include?(hash[param.first])
|
9
|
+
else
|
10
|
+
raise ArgumentError.new("Missing required parameter: #{param}") unless hash.has_key?(param)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kono_epp_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fabio Bonelli
|
@@ -17,7 +17,28 @@ executables: []
|
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
+
- README.md
|
21
|
+
- lib/epp/epp_command.rb
|
22
|
+
- lib/epp/epp_command/create_contact.rb
|
23
|
+
- lib/epp/epp_command/create_domain.rb
|
24
|
+
- lib/epp/epp_command/delete_contact.rb
|
25
|
+
- lib/epp/epp_command/delete_domain.rb
|
26
|
+
- lib/epp/epp_command/hello.rb
|
27
|
+
- lib/epp/epp_command/info_contact.rb
|
28
|
+
- lib/epp/epp_command/info_domain.rb
|
29
|
+
- lib/epp/epp_command/login.rb
|
30
|
+
- lib/epp/epp_command/logout.rb
|
31
|
+
- lib/epp/epp_command/poll.rb
|
32
|
+
- lib/epp/epp_command/transfer_domain.rb
|
33
|
+
- lib/epp/epp_command/update_contact.rb
|
34
|
+
- lib/epp/epp_command/update_domain.rb
|
35
|
+
- lib/epp/exceptions.rb
|
36
|
+
- lib/epp/server.rb
|
37
|
+
- lib/epp/transport.rb
|
38
|
+
- lib/epp/transport/http.rb
|
39
|
+
- lib/epp/transport/tcp.rb
|
20
40
|
- lib/kono_epp_client.rb
|
41
|
+
- lib/require_parameters.rb
|
21
42
|
homepage: https://github.com/ArchimediaZerogroup/kono_epp_client
|
22
43
|
licenses:
|
23
44
|
- MIT
|