nominet-epp 0.0.2

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.
@@ -0,0 +1,20 @@
1
+ module NominetEPP
2
+ module Operations
3
+ # EPP Delete Operation
4
+ module Delete
5
+ # Delete a domain from the registry
6
+ #
7
+ # @param [String] name Domain name
8
+ # @return [Boolean] success status
9
+ def delete(name)
10
+ resp = @client.delete do
11
+ domain('delete') do |node, ns|
12
+ node << XML::Node.new('name', name, ns)
13
+ end
14
+ end
15
+
16
+ resp.success?
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,53 @@
1
+ module NominetEPP
2
+ module Operations
3
+ # EPP Fork Operation
4
+ module Fork
5
+ # Splits a selection of domains from one account into another.
6
+ #
7
+ # The returned hash contains the following keys
8
+ # - (String) +:roid+ -- New account ID
9
+ # - (String) +:name+ -- New account name
10
+ # - (String) +:crDate+ -- Date the account was created
11
+ # - (Hash) +:contact+ -- Contact details
12
+ #
13
+ # The +:contact+ hash contains the following keys
14
+ # - (String) +:roid+ -- Contact ID
15
+ # - (String) +:name+ -- Contact Name
16
+ # - (String) +:type+ -- Contact Type
17
+ # - (Integer) +:order+ -- Contact Order
18
+ #
19
+ # @param [String] account_num Account Number
20
+ # @param [String, ...] *names Domain names to fork from the account
21
+ # @return [false] fork failed
22
+ # @return [Hash] new account details
23
+ def fork(account_num, *names)
24
+ resp = @client.update do
25
+ account('fork') do |node, ns|
26
+ node << XML::Node.new('roid', account_num, ns)
27
+ names.each do |name|
28
+ node << XML::Node.new('domain-name', name, ns)
29
+ end
30
+ end
31
+ end
32
+
33
+ return false unless resp.success?
34
+
35
+ hash = {
36
+ :roid => node_value(resp.data, '//account:creData/account:roid'),
37
+ :name => node_value(resp.data, '//account:creData/account:name'),
38
+ :crDate => node_value(resp.data, '//account:creData/account:crDate'),
39
+ :contact => {
40
+ :roid => node_value(resp.data, '//account:creData/account:contact/contact:creData/contact:roid'),
41
+ :name => node_value(resp.data, '//account:creData/account:contact/contact:creData/contact:name')
42
+ }
43
+ }
44
+
45
+ contact = resp.data.find('//account:creData/account:contact', namespaces).first
46
+ hash[:contact][:type] = contact['type']
47
+ hash[:contact][:order] = contact['order']
48
+
49
+ hash
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,11 @@
1
+ module NominetEPP
2
+ module Operations
3
+ # EPP Hello Operation
4
+ module Hello
5
+ # @return [Boolean] hello greeting returned
6
+ def hello
7
+ @client.hello # This should be a epp-client method
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,93 @@
1
+ module NominetEPP
2
+ module Operations
3
+ # EPP Info Operation
4
+ module Info
5
+ # @param [Symbol] entity Type of entity to get information about
6
+ # @param [String] id Identifier of the entity
7
+ # @return [false] failed
8
+ # @return [Hash]
9
+ def info(entity, id)
10
+ raise ArgumentError, "entity must be :domain, :contact or :account" unless [:domain, :contact, :account].include?(entity)
11
+
12
+ resp = @client.info do
13
+ case entity
14
+ when :domain
15
+ domain('info') { |node, ns| node << XML::Node.new('name', id, ns) }
16
+ when :account
17
+ account('info') { |node, ns| node << XML::Node.new('roid', id, ns) }
18
+ when :contact
19
+ contact('info') { |node, ns| node << XML::Node.new('roid', id, ns) }
20
+ end
21
+ end
22
+
23
+ return false unless resp.success?
24
+ self.send(:"info_#{entity}", resp.data)
25
+ end
26
+
27
+ private
28
+ # @param [XML::Node] data Domain data
29
+ # @return [Hash]
30
+ def info_domain(data)
31
+ hash = {}
32
+ data.find('//domain:infData', namespaces).first.children.reject{|n| n.empty?}.each do |node|
33
+ key = node.name.gsub('-', '_').to_sym
34
+ case node.name
35
+ when 'account'
36
+ hash[:account] = info_account(node)
37
+ when 'ns'
38
+ hash[:ns] = node.find('domain:host', namespaces).map do |hostnode|
39
+ { :name => node_value(hostnode, 'domain:hostName'),
40
+ :v4 => node_value(hostnode, 'domain:hostAddr[@ip="v4"]'),
41
+ :v6 => node_value(hostnode, 'domain:hostAddr[@ip="v6"]') }.reject{|k,v| v.nil?}
42
+ end
43
+ when /date/i
44
+ hash[key] = Time.parse(node.content.strip)
45
+ else
46
+ hash[key] = node.content.strip
47
+ end
48
+ end
49
+ hash
50
+ end
51
+
52
+ # @param [XML::Node] data Account data
53
+ # @return [Hash]
54
+ def info_account(data)
55
+ hash = {}
56
+ data.find('//account:infData', namespaces).first.children.reject{|n| n.empty?}.each do |node|
57
+ key = node.name.gsub('-', '_').to_sym
58
+ case node.name
59
+ when 'addr'
60
+ hash[:addr] = {}
61
+ node.children.reject{|n| n.empty?}.each do |n|
62
+ hash[:addr][n.name.to_sym] = n.content.strip
63
+ end
64
+ when 'contact'
65
+ hash[:contacts] ||= Array.new
66
+ hash[:contacts] << info_contact(node)
67
+ hash[:contacts].last[:type] = node['type']
68
+ hash[:contacts].last[:order] = node['order']
69
+ when /date/i
70
+ hash[key] = Time.parse(node.content.strip)
71
+ else
72
+ hash[key] = node.content.strip
73
+ end
74
+ end
75
+ hash
76
+ end
77
+
78
+ # @param [XML::Node] data Contact data
79
+ # @return [Hash]
80
+ def info_contact(data)
81
+ hash = {}
82
+ data.find('//contact:infData', namespaces).first.children.reject{|n| n.empty?}.each do |node|
83
+ if node.name =~ /date/i
84
+ hash[node.name.to_sym] = Time.parse(node.content.strip)
85
+ else
86
+ hash[node.name.to_sym] = node.content.strip
87
+ end
88
+ end
89
+ hash
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,83 @@
1
+ module NominetEPP
2
+ module Operations
3
+ # EPP List Operatons
4
+ module List
5
+ # Obtain a list of domains, and optionally their details, which either
6
+ # expire or were registered in the month given.
7
+ #
8
+ # @param [Symbol] type Listing type, either +:expiry+ or +:month+
9
+ # @param [String, #strftime] date Date of either expiry or registration to list
10
+ # @param [String] fields Verbosity of the response, either 'none' or 'all'
11
+ # @raise [ArgumentError] type must be +:expiry+ or +:month+
12
+ # @return [nil] list failed
13
+ # @return [Array<String>] list of domains
14
+ # @return [Array<Hash>] list of domains with details
15
+ def list(type, date, fields = 'none')
16
+ raise ArgumentError, "type must be :expiry or :month" unless [:expiry, :month].include?(type)
17
+
18
+ date = date.strftime("%Y-%m") if date.respond_to?(:strftime)
19
+ resp = @client.info do
20
+ domain('list') do |node, ns|
21
+ node << XML::Node.new(type, date, ns)
22
+ node << XML::Node.new('fields', fields, ns)
23
+ end
24
+ end
25
+
26
+ return nil unless resp.success?
27
+
28
+ if fields == 'none'
29
+ resp.data.find('//domain:name', namespaces).map do |node|
30
+ node.content.strip
31
+ end
32
+ else
33
+ resp.data.find('//domain:infData', namespaces).map do |infData|
34
+ hash = {}
35
+ infData.children.reject{|n| n.empty?}.each do |node|
36
+ key = node.name.gsub('-', '_').to_sym
37
+ case node.name
38
+ when 'account'
39
+ hash[:account] = info_account(node)
40
+ when 'ns'
41
+ hash[:ns] = node.find('domain:host', namespaces).map do |hostnode|
42
+ { :name => node_value(hostnode, 'domain:hostName'),
43
+ :v4 => node_value(hostnode, 'domain:hostAddr[@ip="v4"]'),
44
+ :v6 => node_value(hostnode, 'domain:hostAddr[@ip="v6"]') }.reject{|k,v| v.nil?}
45
+ end
46
+ when /date/i
47
+ hash[key] = Time.parse(node.content.strip)
48
+ else
49
+ hash[key] = node.content.strip
50
+ end
51
+ end
52
+ hash
53
+ end
54
+ end
55
+ end
56
+
57
+ # list of all tags that accept tag changes along with their handshake settings
58
+ #
59
+ # The returned array of hashes contain the following keys
60
+ # - (String) +:registrar_tag+ -- TAG name
61
+ # - (String) +:name+ -- Name of the TAG owner
62
+ # - (String) +:trad_name+ -- TAG trading name
63
+ # - (BOOL) +:handshake+ -- Whether the TAG accepts handshakes
64
+ #
65
+ # @return [false] failure
66
+ # @return [Array<Hash>] tag details
67
+ def tag_list
68
+ resp = @client.info do
69
+ tag('list')
70
+ end
71
+
72
+ return false unless resp.success?
73
+
74
+ resp.data.find('//tag:infData', namespaces).map do |node|
75
+ { :registrar_tag => node_value(node, 'tag:registrar-tag'),
76
+ :name => node_value(node, 'tag:name'),
77
+ :trad_name => node_value(node, 'tag:trad-name'),
78
+ :handshake => node_value(node, 'tag:handshake') == 'Y' }
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,56 @@
1
+ module NominetEPP
2
+ module Operations
3
+ # EPP Lock Operation
4
+ module Lock
5
+ # Lock domain or account 'investigation' or 'opt-out'
6
+ #
7
+ # @param [Symbol] entity Entity to lock
8
+ # @param [String] type Type of lock to set
9
+ # @param [String] id Domain name or account ID
10
+ # @raise [ArgumentError] entity is not +:domain+ or +:account+
11
+ # @raise [ArgumentError] type is not 'investigation' or 'opt-out'
12
+ # @return [Boolean] locking successful
13
+ def lock(entity, type, id)
14
+ raise ArgumentError, "entity must be :domain or :account" unless [:domain, :account].include?(entity)
15
+ raise ArgumentError, "type must be 'investigation' or 'opt-out'" unless %w(investigation opt-out).include?(type)
16
+
17
+ resp = @client.update do
18
+ case type
19
+ when 'investigation'
20
+ lock_investigation(entity, id)
21
+ when 'opt-out'
22
+ lock_opt_out(entity, id)
23
+ end
24
+ end
25
+
26
+ return resp.success?
27
+ end
28
+ private
29
+ # Create +account:lock+ XML element for opt-out lock
30
+ # @param [Symbol] entity Entity to set opt out lock on
31
+ # @param [String] id Domain name or Account ID to lock
32
+ # @return [XML::Node] +account:lock+ element
33
+ def lock_opt_out(entity, id)
34
+ account('lock') do |node, ns|
35
+ node['type'] = 'opt-out'
36
+ node << XML::Node.new((entity == :domain ? 'domain-name' : 'roid'), id, ns)
37
+ end
38
+ end
39
+
40
+ # Create +lock+ XML element for investigation lock
41
+ #
42
+ # We don't support 'investigation' on account:domain-name as this ability
43
+ # is already provided via domain:name
44
+ #
45
+ # @param [Symbol] entity Entity to set investigation lock on
46
+ # @param [String] id Domain name or account ID to set lock on
47
+ # @return [XML::Node] +lock+ element
48
+ def lock_investigation(entity, id)
49
+ self.send(entity, 'lock') do |node, ns|
50
+ node['type'] = 'investigation'
51
+ node << XML::Node.new((entity == :domain ? 'name' : 'roid'), id, ns)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,41 @@
1
+ module NominetEPP
2
+ module Operations
3
+ # EPP Merge Operation
4
+ module Merge
5
+ # Merge accounts or domains into an Account
6
+ #
7
+ # @param [String] target Account ID to merge into
8
+ # @param [Hash] sources Account IDs to merge into the target
9
+ # @option sources [Array] :accounts Account numbers to merge
10
+ # @option sources [Array] :names Account names to merge
11
+ # @option sources [Array] :domains Domain names to merge
12
+ # @return [false] merge failed
13
+ # @return [Response] merge succeded
14
+ def merge(target, sources = {})
15
+ resp = @client.update do
16
+ account('merge') do |node, ns|
17
+ node << XML::Node.new('roid', target, ns)
18
+
19
+ (sources[:accounts] || []).each do |acct|
20
+ n = XML::Node.new('roid', acct, ns)
21
+ n['source'] = 'y'
22
+ node << n
23
+ end
24
+
25
+ (sources[:names] || []).each do |name|
26
+ node << XML::Node.new('name', name, ns)
27
+ end
28
+
29
+ (sources[:domains] || []).each do |domain|
30
+ node << XML::Node.new('domain-name', domain, ns)
31
+ end
32
+ end
33
+ end
34
+
35
+ return false unless resp.success?
36
+
37
+ resp # Need to test this to see what gets returned
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,38 @@
1
+ module NominetEPP
2
+ module Operations
3
+ # EPP Poll Operation
4
+ module Poll
5
+ # Poll the EPP server for events
6
+ #
7
+ # @yield [data] process data if messages to poll
8
+ # @yieldparam [XML::Node] data Response data
9
+ # @return [nil] no messages to handle
10
+ # @return [Boolean] ack successful
11
+ # @see ack
12
+ def poll
13
+ resp = @client.poll do |poll|
14
+ poll['op'] = 'req'
15
+ end
16
+
17
+ return if resp.code != 1301 || resp.msgQ['count'] == '0'
18
+
19
+ yield resp.data
20
+
21
+ ack(resp.msgQ['id'])
22
+ end
23
+
24
+ # Acknowledges a polled message ID
25
+ #
26
+ # @param [String] msgID Message ID to acknowledge
27
+ # @return [Boolean] ack successful
28
+ def ack(msgID)
29
+ resp = @client.poll do |poll|
30
+ poll['op'] = 'ack'
31
+ poll['msgID'] = msgID
32
+ end
33
+
34
+ return resp.success?
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,40 @@
1
+ module NominetEPP
2
+ module Operations
3
+ # EPP Renew Operation
4
+ module Renew
5
+ # Renew a domain name
6
+ #
7
+ # @param [String] name Domain name to renew
8
+ # @param [String] period Length of time to renew for. Currently has to be '2y'.
9
+ # @raise [ArgumentError] invalid period specified
10
+ # @raise [RuntimeError] renewed domain name does not match +name+
11
+ # @return [false] renewal failed
12
+ # @return [Time] domain expiration date
13
+ def renew(name, period = '2y')
14
+ period = '2y' # reset period to 2 years as nominet don't currently support other options
15
+
16
+ unit = period[-1..1]
17
+ num = period.to_i.to_s
18
+
19
+ raise ArgumentError, "period suffix must either be 'm' or 'y'" unless %w(m y).include?(unit)
20
+
21
+ resp = @client.renew do
22
+ domain('renew') do |node, ns|
23
+ node << XML::Node.new('name', name, ns)
24
+ p = XML::Node.new('period', num, ns);
25
+ p['unit'] = unit
26
+ node << p
27
+ end
28
+ end
29
+
30
+ return false unless resp.success?
31
+
32
+ renName = node_value(resp.data, '//domain:renData/domain:name')
33
+ renExp = node_value(resp.data, '//domain:renData/domain:exDate')
34
+
35
+ raise "Renewed name #{renName} does not match #{name}" if renName != name
36
+ return Time.parse(renExp)
37
+ end
38
+ end
39
+ end
40
+ end