registrar-client 0.1.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/LICENSE +19 -0
- data/Readme.md +70 -0
- data/Spec.md +55 -0
- data/examples/enom.example.yml +4 -0
- data/examples/purchase_com.rb +7 -0
- data/lib/registrar-client.rb +1 -0
- data/lib/registrar.rb +14 -0
- data/lib/registrar/client.rb +224 -0
- data/lib/registrar/contact.rb +31 -0
- data/lib/registrar/domain.rb +26 -0
- data/lib/registrar/extended_attribute.rb +12 -0
- data/lib/registrar/extended_attribute_descriptor.rb +31 -0
- data/lib/registrar/extended_attribute_option_descriptor.rb +7 -0
- data/lib/registrar/name_server.rb +16 -0
- data/lib/registrar/order.rb +43 -0
- data/lib/registrar/provider/enom.rb +430 -0
- data/lib/registrar/provider/enom/contact.rb +68 -0
- data/lib/registrar/provider/enom/extended_attribute.rb +64 -0
- data/lib/registrar/provider/enom/extended_attribute_be.rb +0 -0
- data/lib/registrar/provider/enom/extended_attribute_ca.rb +40 -0
- data/lib/registrar/provider/enom/extended_attribute_io.rb +18 -0
- data/lib/registrar/provider/enom/extended_attribute_us.rb +29 -0
- data/lib/registrar/provider/enom/order.rb +41 -0
- data/lib/registrar/provider/opensrs.rb +133 -0
- data/lib/registrar/provider/opensrs/contact.rb +30 -0
- data/lib/registrar/provider/opensrs/contact_set.rb +24 -0
- data/lib/registrar/provider/opensrs/name_server_list.rb +26 -0
- data/lib/registrar/provider/opensrs/operation.rb +42 -0
- data/lib/registrar/provider/opensrs/order.rb +59 -0
- data/lib/registrar/provider/opensrs/tld_data.rb +29 -0
- data/lib/registrar/provider/opensrs/tld_data_us.rb +48 -0
- data/lib/registrar/purchase_options.rb +29 -0
- data/lib/registrar/renewal_options.rb +8 -0
- metadata +177 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
module Registrar
|
2
|
+
module Provider
|
3
|
+
# :nodoc:
|
4
|
+
class Enom
|
5
|
+
# Contact object that wraps a generic contact and can be used to produce and parse
|
6
|
+
# wire-level representations of Enom contacts.
|
7
|
+
class Contact
|
8
|
+
attr_reader :contact
|
9
|
+
|
10
|
+
def initialize(contact)
|
11
|
+
raise ArgumentError, "Contact is required" unless contact
|
12
|
+
@contact = contact
|
13
|
+
end
|
14
|
+
|
15
|
+
def identifier
|
16
|
+
contact.identifier
|
17
|
+
end
|
18
|
+
|
19
|
+
def identifier=(identifier)
|
20
|
+
contact.identifier = identifier
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns a Hash that can be merged into a query.
|
24
|
+
# Type should be one of the following: Registrant, AuxBilling, Tech, Admin
|
25
|
+
def to_query(type)
|
26
|
+
{
|
27
|
+
"#{type}Address1" => contact.address_1,
|
28
|
+
"#{type}Address2" => contact.address_2,
|
29
|
+
"#{type}City" => contact.city,
|
30
|
+
"#{type}Country" => contact.country,
|
31
|
+
"#{type}EmailAddress" => contact.email,
|
32
|
+
"#{type}Fax" => contact.fax,
|
33
|
+
"#{type}FirstName" => contact.first_name,
|
34
|
+
"#{type}LastName" => contact.last_name,
|
35
|
+
"#{type}JobTitle" => contact.job_title,
|
36
|
+
"#{type}OrganizationName" => contact.organization_name,
|
37
|
+
"#{type}Phone" => contact.phone,
|
38
|
+
"#{type}PhoneExt" => contact.phone_ext,
|
39
|
+
"#{type}PostalCode" => contact.postal_code,
|
40
|
+
"#{type}StateProvince" => contact.state_province,
|
41
|
+
"#{type}StateProvinceChoice" => contact.state_province_choice
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.from_response(type, attributes)
|
46
|
+
contact = Registrar::Contact.new
|
47
|
+
contact.identifier = attributes["#{type}PartyID"]
|
48
|
+
contact.address_1 = attributes["#{type}Address1"]
|
49
|
+
contact.address_2 = attributes["#{type}Address2"]
|
50
|
+
contact.city = attributes["#{type}City"]
|
51
|
+
contact.country = attributes["#{type}Country"]
|
52
|
+
contact.email = attributes["#{type}EmailAddress"]
|
53
|
+
contact.fax = attributes["#{type}Fax"]
|
54
|
+
contact.first_name = attributes["#{type}FirstName"]
|
55
|
+
contact.last_name = attributes["#{type}LastName"]
|
56
|
+
contact.job_title = attributes["#{type}JobTitle"]
|
57
|
+
contact.organization_name = attributes["#{type}OrganizationName"]
|
58
|
+
contact.phone = attributes["#{type}Phone"]
|
59
|
+
contact.phone_ext = attributes["#{type}PhoneExt"]
|
60
|
+
contact.postal_code = attributes["#{type}PostalCode"]
|
61
|
+
contact.state_province = attributes["#{type}StateProvince"]
|
62
|
+
contact.state_province_choice = attributes["#{type}StateProvinceChoice"]
|
63
|
+
self.new(contact)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'registrar/provider/enom/extended_attribute_us'
|
2
|
+
require 'registrar/provider/enom/extended_attribute_ca'
|
3
|
+
require 'registrar/provider/enom/extended_attribute_io'
|
4
|
+
|
5
|
+
module Registrar
|
6
|
+
module Provider
|
7
|
+
class Enom
|
8
|
+
# Wrapper around the generic extended attribute that resolves symbolic values
|
9
|
+
# to their Enom-specific values.
|
10
|
+
class ExtendedAttribute
|
11
|
+
include ExtendedAttributeUS
|
12
|
+
include ExtendedAttributeCA
|
13
|
+
include ExtendedAttributeIO
|
14
|
+
|
15
|
+
attr_reader :extended_attribute
|
16
|
+
def initialize(extended_attribute)
|
17
|
+
@extended_attribute = extended_attribute
|
18
|
+
end
|
19
|
+
|
20
|
+
def name
|
21
|
+
resolve_name(extended_attribute.tld, extended_attribute.name)
|
22
|
+
end
|
23
|
+
def value
|
24
|
+
resolve_value(extended_attribute.tld, extended_attribute.value)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def resolve_name(tld, name)
|
29
|
+
case name
|
30
|
+
when Symbol then
|
31
|
+
names(tld)[name]
|
32
|
+
else
|
33
|
+
name
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def names(tld)
|
38
|
+
{
|
39
|
+
'us' => us_names,
|
40
|
+
'ca' => ca_names,
|
41
|
+
'io' => io_names,
|
42
|
+
}[tld]
|
43
|
+
end
|
44
|
+
|
45
|
+
def resolve_value(tld, value)
|
46
|
+
case value
|
47
|
+
when Symbol then
|
48
|
+
values(tld)[value]
|
49
|
+
else
|
50
|
+
value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def values(tld)
|
55
|
+
{
|
56
|
+
'us' => us_values,
|
57
|
+
'ca' => ca_values,
|
58
|
+
'io' => io_values,
|
59
|
+
}[tld]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
File without changes
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Registrar
|
2
|
+
module Provider
|
3
|
+
class Enom
|
4
|
+
module ExtendedAttributeCA
|
5
|
+
protected
|
6
|
+
def ca_names
|
7
|
+
{
|
8
|
+
:"Legal Type" => 'cira_legal_type',
|
9
|
+
:"Agreement Version" => 'cira_agreement_version',
|
10
|
+
:"Agreement Value" => 'cira_agreement_value',
|
11
|
+
}
|
12
|
+
end
|
13
|
+
def ca_values
|
14
|
+
{
|
15
|
+
:"Aboriginal Peoples" => "ABO",
|
16
|
+
:"Canadian Citizen" => "CCT",
|
17
|
+
:"Canadian Resident" => "RES",
|
18
|
+
:"Corporation" => "CCO",
|
19
|
+
:"Educational" => "EDU",
|
20
|
+
:"Government Entity" => "GOV",
|
21
|
+
:"Hospital" => "HOP",
|
22
|
+
:"Indian Band" => "INB",
|
23
|
+
:"Legal Representative" => "LGR",
|
24
|
+
:"Library, Archive or Museum" => "LAM",
|
25
|
+
:"Official Mark" => "OMK",
|
26
|
+
:"Partnership" => "PRT",
|
27
|
+
:"Political Party" => "PLT",
|
28
|
+
:"The Queen" => "MAJ",
|
29
|
+
:"Trade Union" => "TRD",
|
30
|
+
:"Trade-mark" => "TDM",
|
31
|
+
:"Trust" => "TRS",
|
32
|
+
:"Unincorporated Association" => "ASS",
|
33
|
+
:"Yes" => "Y",
|
34
|
+
:"No" => "N",
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Registrar
|
2
|
+
module Provider
|
3
|
+
class Enom
|
4
|
+
module ExtendedAttributeUS
|
5
|
+
def us_names
|
6
|
+
{
|
7
|
+
:Nexus => 'us_nexus',
|
8
|
+
:Purpose => 'us_purpose',
|
9
|
+
:Country => 'global_cc_us'
|
10
|
+
}
|
11
|
+
end
|
12
|
+
def us_values
|
13
|
+
{
|
14
|
+
:"US Citizen" => 'C11',
|
15
|
+
:"Business Entity" => 'C21',
|
16
|
+
:"Foreign Entity" => 'C31',
|
17
|
+
:"Permanent Resident" => 'C12',
|
18
|
+
:"US Based Office" => 'C22',
|
19
|
+
:"For Profit" => 'P1',
|
20
|
+
:"Non Profit" => 'P2',
|
21
|
+
:Personal => 'P3',
|
22
|
+
:Educational => 'P4',
|
23
|
+
:Government => 'P5',
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Registrar
|
2
|
+
module Provider
|
3
|
+
class Enom
|
4
|
+
# An Enom order.
|
5
|
+
class Order
|
6
|
+
attr_accessor :id
|
7
|
+
attr_accessor :order_status
|
8
|
+
attr_accessor :order_date
|
9
|
+
attr_accessor :status
|
10
|
+
|
11
|
+
def initialize(id)
|
12
|
+
@id = id
|
13
|
+
end
|
14
|
+
|
15
|
+
def status
|
16
|
+
@status || 'unknown'
|
17
|
+
end
|
18
|
+
|
19
|
+
def order_status
|
20
|
+
@order_status || 'unknown'
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get a generic Registrar::Order object to use.
|
24
|
+
def to_order
|
25
|
+
order = Registrar::Order.new(id)
|
26
|
+
order.successful = status.downcase == "successful"
|
27
|
+
|
28
|
+
order.status = case order_status.downcase
|
29
|
+
when 'open' then :open
|
30
|
+
when 'closed' then :closed
|
31
|
+
else
|
32
|
+
order_status.downcase.to_sym
|
33
|
+
end
|
34
|
+
|
35
|
+
order.date = order_date
|
36
|
+
order
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'builder'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'registrar/provider/opensrs/order'
|
5
|
+
require 'registrar/provider/opensrs/operation'
|
6
|
+
require 'registrar/provider/opensrs/contact'
|
7
|
+
require 'registrar/provider/opensrs/contact_set'
|
8
|
+
|
9
|
+
module Registrar
|
10
|
+
module Provider
|
11
|
+
# Implementation of a registrar provider for OpenSRS (http://www.opensrs.com/).
|
12
|
+
class OpenSRS
|
13
|
+
include HTTParty
|
14
|
+
format :xml
|
15
|
+
debug_output $stderr
|
16
|
+
|
17
|
+
attr_accessor :url, :username, :private_key
|
18
|
+
|
19
|
+
def initialize(url, username, private_key)
|
20
|
+
@url = url
|
21
|
+
@username = username
|
22
|
+
@private_key = private_key
|
23
|
+
end
|
24
|
+
|
25
|
+
def available?(name)
|
26
|
+
response = execute(lookup_operation(name).to_xml)
|
27
|
+
|
28
|
+
items = response['OPS_envelope']['body']['data_block']['dt_assoc']['item']
|
29
|
+
items = items.find { |item| item['dt_assoc'] }['dt_assoc']
|
30
|
+
items['item'][0] == 'available'
|
31
|
+
end
|
32
|
+
|
33
|
+
def purchase(name, registrant, purchase_options=nil)
|
34
|
+
purchase_options ||= Registrar::PurchaseOptions.new
|
35
|
+
response = execute(registration_operation(name, registrant,
|
36
|
+
purchase_options).to_xml)
|
37
|
+
order = check_order(response.body)
|
38
|
+
order.add_domain(name, registrant)
|
39
|
+
order.to_order
|
40
|
+
end
|
41
|
+
|
42
|
+
def renew(name, renewal_options)
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def name_servers(name)
|
47
|
+
operation = Operation.new(:get, {
|
48
|
+
:domain => name,
|
49
|
+
:type => "nameservers"
|
50
|
+
})
|
51
|
+
nameserver_list_from(execute(operation.to_xml).body)
|
52
|
+
end
|
53
|
+
alias :nameservers :name_servers
|
54
|
+
|
55
|
+
private
|
56
|
+
def nameserver_list_from(xml)
|
57
|
+
Nokogiri::XML(xml).xpath('//dt_array/item/dt_assoc/item[@key="name"]').map do |item|
|
58
|
+
Registrar::NameServer.new(item.content)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def check_order(xml)
|
63
|
+
order_info = execute(order_info_operation(order_id_from(xml)).to_xml)
|
64
|
+
Registrar::Provider::OpenSRS::Order.new(order_info.to_s)
|
65
|
+
end
|
66
|
+
|
67
|
+
def order_id_from(xml)
|
68
|
+
Nokogiri::XML(xml).xpath(
|
69
|
+
"//dt_assoc/item[@key='attributes']/dt_assoc/item[@key='id']").inner_text
|
70
|
+
end
|
71
|
+
|
72
|
+
def order_info_operation(id)
|
73
|
+
operation = Operation.new(:get_order_info, {
|
74
|
+
:order_id => id})
|
75
|
+
end
|
76
|
+
|
77
|
+
def lookup_operation(name)
|
78
|
+
operation = Operation.new(:lookup, {
|
79
|
+
:domain => name,
|
80
|
+
:no_cache => "1"
|
81
|
+
})
|
82
|
+
end
|
83
|
+
|
84
|
+
def registration_operation(name, registrant, purchase_options)
|
85
|
+
operation = Operation.new(:sw_register, {
|
86
|
+
:domain => name,
|
87
|
+
:period => purchase_options.number_of_years,
|
88
|
+
:reg_type => "new",
|
89
|
+
:handle => 'process',
|
90
|
+
:reg_username => 'dnsimple',
|
91
|
+
:reg_password => 'password',
|
92
|
+
:custom_tech_contact => '1',
|
93
|
+
:custom_nameservers => '1',
|
94
|
+
:nameserver_list => nameserver_list(purchase_options),
|
95
|
+
:contact_set => contact_set(registrant),
|
96
|
+
:tld_data => tld_data(purchase_options)
|
97
|
+
})
|
98
|
+
end
|
99
|
+
|
100
|
+
def nameserver_list(purchase_options)
|
101
|
+
NameServerList.new(purchase_options) if purchase_options
|
102
|
+
end
|
103
|
+
|
104
|
+
def tld_data(purchase_options)
|
105
|
+
TldData.build_with(purchase_options) if purchase_options && purchase_options.extended_attributes != []
|
106
|
+
end
|
107
|
+
|
108
|
+
def contact_set(registrant)
|
109
|
+
ContactSet.new({
|
110
|
+
'owner' => OpenSRS::Contact.new(registrant),
|
111
|
+
'admin' => OpenSRS::Contact.new(registrant),
|
112
|
+
'billing' => OpenSRS::Contact.new(registrant),
|
113
|
+
'tech' => OpenSRS::Contact.new(registrant)
|
114
|
+
})
|
115
|
+
end
|
116
|
+
|
117
|
+
def execute(body)
|
118
|
+
self.class.headers(
|
119
|
+
"Content-Type" => "text/xml",
|
120
|
+
"X-Username" => username,
|
121
|
+
"X-Signature" => signature(body),
|
122
|
+
"Content-Length" => body.length.to_s
|
123
|
+
)
|
124
|
+
self.class.post(url, {:body => body})
|
125
|
+
end
|
126
|
+
|
127
|
+
def signature(body)
|
128
|
+
step1 = Digest::MD5.hexdigest("#{body}#{private_key}")
|
129
|
+
Digest::MD5.hexdigest("#{step1}#{private_key}")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Registrar
|
2
|
+
module Provider
|
3
|
+
# :nodoc:
|
4
|
+
class OpenSRS
|
5
|
+
class Contact
|
6
|
+
attr_reader :contact
|
7
|
+
|
8
|
+
def initialize(contact)
|
9
|
+
raise ArgumentError, "Contact is required" unless contact
|
10
|
+
@contact = contact
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_xml(builder)
|
14
|
+
builder.item(contact.first_name, :key => "first_name")
|
15
|
+
builder.item(contact.last_name, :key => "last_name")
|
16
|
+
builder.item(contact.phone, :key => "phone")
|
17
|
+
builder.item(contact.fax, :key => "fax")
|
18
|
+
builder.item(contact.email, :key => "email")
|
19
|
+
builder.item(contact.organization_name, :key => "org_name")
|
20
|
+
builder.item(contact.address_1, :key => "address1")
|
21
|
+
builder.item(contact.address_2, :key => "address2")
|
22
|
+
builder.item(contact.city, :key => "city")
|
23
|
+
builder.item(contact.state_province, :key => "state")
|
24
|
+
builder.item(contact.country, :key => "country")
|
25
|
+
builder.item(contact.postal_code, :key => "postal_code")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Registrar
|
2
|
+
module Provider
|
3
|
+
class OpenSRS
|
4
|
+
class ContactSet
|
5
|
+
attr_reader :contacts
|
6
|
+
def initialize(contacts)
|
7
|
+
@contacts = contacts
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_xml(builder)
|
11
|
+
builder.dt_assoc { |b|
|
12
|
+
contacts.each do |key, contact|
|
13
|
+
b.item(:key => key.to_s) { |b|
|
14
|
+
b.dt_assoc { |b|
|
15
|
+
contact.to_xml(b)
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|