epp 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2009 Josh Delsman (Ultraspeed)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,88 @@
1
+ = EPP (by {Ultraspeed}[http://ultraspeed.co.uk])
2
+
3
+ The EPP gem provides basic functionality for connecting and making requests on EPP (Extensible Provisioning Protocol) servers. Currently, major providers Centralnic and Nominet have been tested.
4
+
5
+ * {Nominet Standard EPP Documentation}[http://www.nominet.org.uk/registrars/systems/standardepp/]
6
+ * {Centralnic Labs EPP Documentation}[http://labs.centralnic.com/epp/]
7
+
8
+ == Installation
9
+
10
+ You can install this gem with:
11
+
12
+ $ sudo gem sources -a http://gems.github.com
13
+ $ sudo gem install ultraspeed-epp
14
+
15
+ Then, you can require it in your Ruby app:
16
+
17
+ require "epp"
18
+
19
+ If you're using Rails, add the following line to your Rails <tt>config/environment.rb</tt>:
20
+
21
+ config.gem "ultraspeed-epp", :lib => "epp", :source => "http://gems.github.com"
22
+
23
+ Once you do that, you can install the gem by typing <tt>sudo rake gems:install</tt>.
24
+
25
+ == Example Usage
26
+
27
+ First, you must initialize an Epp::Server object to use. This requires the EPP server address, tag/username and password:
28
+
29
+ server = Epp::Server.new(
30
+ :server => "testbed-epp.nominet.org.uk",
31
+ :tag => "TESTING",
32
+ :password => "testing"
33
+ )
34
+
35
+ If no port is specified, it will be assumed that you will be using port 700.
36
+
37
+ You would then make an XML request to the server.
38
+
39
+ xml = "<?xml ... </epp>"
40
+ response = server.request(xml)
41
+
42
+ You can build this however you'd like. The process is as follows:
43
+
44
+ * Connect to EPP server, get the <greeting> frame
45
+ * Send a standard <login> request
46
+ * Send your request
47
+ * Send a standard <logout> request
48
+ * Disconnect the socket from the server
49
+
50
+ The EPP server would then return the XML response as a string. In this example, the response XML would be set equal to <tt>response</tt> for your usage.
51
+
52
+ Once the request is complete, it will automatically close the connection. For simplicity purposes, this plug-in will *not* use a persistent connection to the EPP server.
53
+
54
+ == Bugs/Issues
55
+
56
+ Please report all issues using the GitHub issue tracker at:
57
+
58
+ http://github.com/ultraspeed/epp/issues
59
+
60
+ == Credit
61
+
62
+ Author:: Josh Delsman at Ultraspeed (http://twitter.com/voxxit)
63
+ Inspired from:: http://labs.centralnic.com/Net_EPP_Client.php
64
+
65
+ == License
66
+
67
+ The MIT License
68
+
69
+ Copyright (c) 2009 Josh Delsman (Ultraspeed)
70
+
71
+ Permission is hereby granted, free of charge, to any person obtaining
72
+ a copy of this software and associated documentation files (the
73
+ 'Software'), to deal in the Software without restriction, including
74
+ without limitation the rights to use, copy, modify, merge, publish,
75
+ distribute, sublicense, and/or sell copies of the Software, and to
76
+ permit persons to whom the Software is furnished to do so, subject to
77
+ the following conditions:
78
+
79
+ The above copyright notice and this permission notice shall be
80
+ included in all copies or substantial portions of the Software.
81
+
82
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
83
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
84
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
85
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
86
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
87
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
88
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,59 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = "epp"
9
+ gem.summary = "EPP (Extensible Provisioning Protocol) for Ruby"
10
+ gem.description = "Basic functionality for connecting and making requests on EPP (Extensible Provisioning Protocol) servers"
11
+ gem.email = "jdelsman@ultraspeed.com"
12
+ gem.homepage = "http://github.com/ultraspeed/epp"
13
+ gem.authors = ["Josh Delsman"]
14
+
15
+ # Dependencies
16
+ gem.add_development_dependency "thoughtbot-shoulda"
17
+ gem.add_dependency "activesupport"
18
+ gem.add_dependency "hpricot"
19
+ end
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
22
+ end
23
+
24
+ require 'rake/testtask'
25
+ Rake::TestTask.new(:test) do |test|
26
+ test.libs << 'lib' << 'test'
27
+ test.pattern = 'test/**/*_test.rb'
28
+ test.verbose = true
29
+ end
30
+
31
+ begin
32
+ require 'rcov/rcovtask'
33
+
34
+ Rcov::RcovTask.new do |test|
35
+ test.libs << 'test'
36
+ test.pattern = 'test/**/*_test.rb'
37
+ test.verbose = true
38
+ end
39
+ rescue LoadError
40
+ task :rcov do
41
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
42
+ end
43
+ end
44
+
45
+ task :test => :check_dependencies
46
+ task :default => :test
47
+
48
+ require 'sdoc'
49
+ require 'rake/rdoctask'
50
+ Rake::RDocTask.new do |rdoc|
51
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
52
+
53
+ rdoc.rdoc_dir = 'doc/rdoc'
54
+ rdoc.options << '--fmt' << 'shtml'
55
+ rdoc.template = 'direct'
56
+
57
+ rdoc.rdoc_files.include('README*')
58
+ rdoc.rdoc_files.include('lib/**/*.rb')
59
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.9
@@ -0,0 +1,16 @@
1
+ # Gem and other dependencies
2
+ require 'rubygems'
3
+ require 'openssl'
4
+ require 'socket'
5
+ require 'activesupport'
6
+ require 'rexml/document'
7
+ require 'hpricot'
8
+
9
+ # Package files
10
+ require File.dirname(__FILE__) + '/require_parameters.rb'
11
+ require File.dirname(__FILE__) + '/epp/server.rb'
12
+ require File.dirname(__FILE__) + '/epp/exceptions.rb'
13
+
14
+ module Epp #:nodoc:
15
+ VERSION = '1.0.8'
16
+ end
@@ -0,0 +1,14 @@
1
+ class EppErrorResponse < StandardError #:nodoc:
2
+ attr_accessor :response_xml, :response_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[:code]
8
+ @message = attributes[:message]
9
+ end
10
+
11
+ def to_s
12
+ "#{@message} (code #{@response_code})"
13
+ end
14
+ end
@@ -0,0 +1,206 @@
1
+ module Epp #:nodoc:
2
+ class Server
3
+ include RequiresParameters
4
+
5
+ attr_accessor :tag, :password, :server, :port, :clTRID, :old_server
6
+
7
+ # ==== Required Attrbiutes
8
+ #
9
+ # * <tt>:server</tt> - The EPP server to connect to
10
+ # * <tt>:tag</tt> - The tag or username used with <tt><login></tt> requests.
11
+ # * <tt>:password</tt> - The password used with <tt><login></tt> requests.
12
+ #
13
+ # ==== Optional Attributes
14
+ #
15
+ # * <tt>:port</tt> - The EPP standard port is 700. However, you can choose a different port to use.
16
+ # * <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"
17
+ # * <tt>:old_server</tt> - Set to true to read and write frames in a way that is compatible with old EPP servers. Default is false.
18
+ # * <tt>:lang</tt> - Set custom language attribute. Default is 'en'.
19
+ def initialize(attributes = {})
20
+ requires!(attributes, :tag, :password, :server)
21
+
22
+ @tag = attributes[:tag]
23
+ @password = attributes[:password]
24
+ @server = attributes[:server]
25
+ @port = attributes[:port] || 700
26
+ @clTRID = attributes[:clTRID] || "ABC-12345"
27
+ @old_server = attributes[:old_server] || false
28
+ @lang = attributes[:lang] || 'en'
29
+ end
30
+
31
+ # Sends an XML request to the EPP server, and receives an XML response.
32
+ # <tt><login></tt> and <tt><logout></tt> requests are also wrapped
33
+ # around the request, so we can close the socket immediately after
34
+ # the request is made.
35
+ def request(xml)
36
+ open_connection
37
+
38
+ begin
39
+ login
40
+ @response = send_request(xml)
41
+ ensure
42
+ logout unless @old_server
43
+ close_connection
44
+ end
45
+
46
+ return @response
47
+ end
48
+
49
+ # private
50
+
51
+ # Wrapper which sends an XML frame to the server, and receives
52
+ # the response frame in return.
53
+ def send_request(xml)
54
+ send_frame(xml)
55
+ response = get_frame
56
+ end
57
+
58
+ def login
59
+ xml = REXML::Document.new
60
+ xml << REXML::XMLDecl.new("1.0", "UTF-8", "no")
61
+
62
+ xml.add_element("epp", {
63
+ "xmlns" => "urn:ietf:params:xml:ns:epp-1.0",
64
+ "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
65
+ "xsi:schemaLocation" => "urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd"
66
+ })
67
+
68
+ command = xml.root.add_element("command")
69
+ login = command.add_element("login")
70
+
71
+ login.add_element("clID").text = @tag
72
+ login.add_element("pw").text = @password
73
+
74
+ options = login.add_element("options")
75
+ options.add_element("version").text = "1.0"
76
+ options.add_element("lang").text = @lang
77
+
78
+ services = login.add_element("svcs")
79
+ services.add_element("objURI").text = "urn:ietf:params:xml:ns:domain-1.0"
80
+ services.add_element("objURI").text = "urn:ietf:params:xml:ns:contact-1.0"
81
+ services.add_element("objURI").text = "urn:ietf:params:xml:ns:host-1.0"
82
+
83
+ command.add_element("clTRID").text = @clTRID
84
+
85
+ # Receive the login response
86
+ response = Hpricot.XML(send_request(xml.to_s))
87
+
88
+ result_message = (response/"epp"/"response"/"result"/"msg").text.strip
89
+ result_code = (response/"epp"/"response"/"result").attr("code").to_i
90
+
91
+ if result_code == 1000
92
+ return true
93
+ else
94
+ raise EppErrorResponse.new(:xml => response, :code => result_code, :message => result_message)
95
+ end
96
+ end
97
+
98
+ def logout
99
+ xml = REXML::Document.new
100
+ xml << REXML::XMLDecl.new("1.0", "UTF-8", "no")
101
+
102
+ xml.add_element('epp', {
103
+ 'xmlns' => "urn:ietf:params:xml:ns:epp-1.0",
104
+ 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
105
+ 'xsi:schemaLocation' => "urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd"
106
+ })
107
+
108
+ command = xml.root.add_element("command")
109
+ login = command.add_element("logout")
110
+
111
+ # Receive the logout response
112
+ response = Hpricot.XML(send_request(xml.to_s))
113
+
114
+ result_message = (response/"epp"/"response"/"result"/"msg").text.strip
115
+ result_code = (response/"epp"/"response"/"result").attr("code").to_i
116
+
117
+ if result_code == 1500
118
+ return true
119
+ else
120
+ raise EppErrorResponse.new(:xml => response, :code => result_code, :message => result_message)
121
+ end
122
+ end
123
+
124
+ # Establishes the connection to the server. If the connection is
125
+ # established, then this method will call get_frame and return
126
+ # the EPP <tt><greeting></tt> frame which is sent by the
127
+ # server upon connection.
128
+ def open_connection
129
+ @connection = TCPSocket.new(@server, @port)
130
+ @socket = OpenSSL::SSL::SSLSocket.new(@connection)
131
+
132
+ # Synchronously close the connection & socket
133
+ @socket.sync_close
134
+
135
+ # Connect
136
+ @socket.connect
137
+
138
+ # Get the initial frame
139
+ get_frame
140
+ end
141
+
142
+ # Closes the connection to the EPP server.
143
+ def close_connection
144
+ if defined?(@socket) and @socket.is_a?(OpenSSL::SSL::SSLSocket)
145
+ @socket.close
146
+ @socket = nil
147
+ end
148
+
149
+ if defined?(@connection) and @connection.is_a?(TCPSocket)
150
+ @connection.close
151
+ @connection = nil
152
+ end
153
+
154
+ return true if @connection.nil? and @socket.nil?
155
+ end
156
+
157
+ # Receive an EPP frame from the server. Since the connection is blocking,
158
+ # this method will wait until the connection becomes available for use. If
159
+ # the connection is broken, a SocketError will be raised. Otherwise,
160
+ # it will return a string containing the XML from the server.
161
+ def get_frame
162
+ if @old_server
163
+ data = ""
164
+ first_char = @socket.read(1)
165
+
166
+ if first_char.nil? and @socket.eof?
167
+ raise SocketError.new("Connection closed by remote server")
168
+ elsif first_char.nil?
169
+ raise SocketError.new("Error reading frame from remote server")
170
+ else
171
+ data << first_char
172
+
173
+ while char = @socket.read(1)
174
+ data << char
175
+
176
+ return data if data =~ %r|<\/epp>\n$|mi # at end
177
+ end
178
+ end
179
+ else
180
+ header = @socket.read(4)
181
+
182
+ if header.nil? and @socket.eof?
183
+ raise SocketError.new("Connection closed by remote server")
184
+ elsif header.nil?
185
+ raise SocketError.new("Error reading frame from remote server")
186
+ else
187
+ unpacked_header = header.unpack("N")
188
+ length = unpacked_header[0]
189
+
190
+ if length < 5
191
+ raise SocketError.new("Got bad frame header length of #{length} bytes from the server")
192
+ else
193
+ response = @socket.read(length - 4)
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ # Send an XML frame to the server. Should return the total byte
200
+ # size of the frame sent to the server. If the socket returns EOF,
201
+ # the connection has closed and a SocketError is raised.
202
+ def send_frame(xml)
203
+ @socket.write( @old_server ? (xml + "\r\n") : ([xml.size + 4].pack("N") + xml) )
204
+ end
205
+ end
206
+ 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
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class EppTest < Test::Unit::TestCase
4
+ should "create tests" do
5
+ flunk "Tests have not been written yet. Coming soon"
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'epp'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: epp
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.9
5
+ platform: ruby
6
+ authors:
7
+ - Josh Delsman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-18 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: thoughtbot-shoulda
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: hpricot
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ description: Basic functionality for connecting and making requests on EPP (Extensible Provisioning Protocol) servers
46
+ email: jdelsman@ultraspeed.com
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - LICENSE
53
+ - README.rdoc
54
+ files:
55
+ - LICENSE
56
+ - README.rdoc
57
+ - Rakefile
58
+ - VERSION
59
+ - lib/epp.rb
60
+ - lib/epp/exceptions.rb
61
+ - lib/epp/server.rb
62
+ - lib/require_parameters.rb
63
+ - test/epp_test.rb
64
+ - test/test_helper.rb
65
+ has_rdoc: true
66
+ homepage: http://github.com/ultraspeed/epp
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options:
71
+ - --charset=UTF-8
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ requirements: []
87
+
88
+ rubyforge_project:
89
+ rubygems_version: 1.3.5
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: EPP (Extensible Provisioning Protocol) for Ruby
93
+ test_files:
94
+ - test/epp_test.rb
95
+ - test/test_helper.rb