pepper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
File without changes
@@ -0,0 +1,61 @@
1
+ module Pepper
2
+ module Commands
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ # http://www.nominet.org.uk/registrars/systems/nominetepp/login/
9
+ def login
10
+ unless @logged_in
11
+ builder = Nokogiri::XML::Builder.new do |xml|
12
+ xml.epp("xmlns" => "urn:ietf:params:xml:ns:epp-1.0",
13
+ "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
14
+ "xsi:schemaLocation" => "urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd" ) {
15
+ xml.command {
16
+ xml.login {
17
+ xml.clID @tag
18
+ xml.pw @password
19
+ xml.options {
20
+ xml.version "1.0"
21
+ xml.lang "en"
22
+ }
23
+ xml.svcs {
24
+ xml.objURI "http://www.nominet.org.uk/epp/xml/nom-domain-2.0"
25
+ }
26
+ }
27
+ }
28
+ }
29
+ end
30
+ r = self.write( builder.to_xml )
31
+ end
32
+ @logged_in = true
33
+ end
34
+
35
+ def check(*domains)
36
+ login unless @logged_in
37
+ builder = Nokogiri::XML::Builder.new do |xml|
38
+ xml.epp("xmlns" => "urn:ietf:params:xml:ns:epp-1.0",
39
+ "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
40
+ "xsi:schemaLocation" => "urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd" ) {
41
+ xml.command {
42
+ xml.check {
43
+ xml.check("xmlns:domain" => "http://www.nominet.org.uk/epp/xml/nom-domain-2.0",
44
+ "xsi:schemaLocation" => "http://www.nominet.org.uk/epp/xml/nom-domain-2.0 nom-domain-2.0.xsd") {
45
+ xml.parent.namespace = xml.parent.namespace_definitions.first
46
+ domains.each {|d|
47
+ xml["domain"].name d
48
+ }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ end
54
+ r = self.write( builder.to_xml )
55
+ r.response.resdata.chkdata.domain_names.inject({}){|hash,domain|
56
+ hash.merge( domain => r.response.resdata.chkdata.domain_names_avail.shift == "1")
57
+ }
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,47 @@
1
+ require "socket"
2
+ require "openssl"
3
+ require "eventmachine"
4
+
5
+ module Pepper
6
+ module Connection
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+ attr_accessor :connection
13
+
14
+ def settings=(opts = {})
15
+ @server = opts[:server]
16
+ @tag = opts[:tag]
17
+ @password = opts[:password]
18
+ @port = opts[:port] || 700
19
+ @lang = opts[:lang] || "en"
20
+
21
+ @logged_in = false
22
+ @parser = nil
23
+ end
24
+
25
+ def connect
26
+ sock = TCPSocket.new( @server, @port )
27
+ ssl_context = OpenSSL::SSL::SSLContext.new
28
+ ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
29
+ self.connection = OpenSSL::SSL::SSLSocket.new( sock, ssl_context )
30
+
31
+ self.connection.sync_close
32
+ self.connection.connect
33
+
34
+ @parser = StreamParser.new self.connection
35
+ @parser.get_frame
36
+
37
+ self.connection
38
+ end
39
+
40
+ def write(xml)
41
+ (@parser && self.connection || self.connect).write(xml)
42
+ @parser.get_frame
43
+ end
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,12 @@
1
+ module Pepper
2
+ module Error
3
+ class ProtocolSyntax < StandardError; end
4
+ class ImplementationSpecificRules < StandardError; end
5
+ class Security < StandardError; end
6
+ class DataManagement < StandardError; end
7
+ class ServerSystem < StandardError; end
8
+ class ConnectionManagement < StandardError; end
9
+
10
+ class UnrecognisedResponse < StandardError; end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module Pepper
2
+ module Stanzas
3
+ class Chkdata
4
+ include SAXMachine
5
+
6
+ elements "domain:name", :as => :domain_names
7
+ elements "domain:name", :value => :avail, :as => :domain_names_avail
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ module Pepper
2
+ module Stanzas
3
+ class Epp
4
+ include SAXMachine
5
+
6
+ element :greeting
7
+ element :response, :class => Response
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Pepper
2
+ module Stanzas
3
+ class Resdata
4
+ include SAXMachine
5
+
6
+ element "domain:chkData", :as => :chkdata, :class => Chkdata
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Pepper
2
+ module Stanzas
3
+ class Response
4
+ include SAXMachine
5
+
6
+ element :result, :class => Result
7
+ element :result, :as => :result_code, :value => :code
8
+ element :resData, :as => :resdata, :class => Resdata
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module Pepper
2
+ module Stanzas
3
+ class Result
4
+ include SAXMachine
5
+
6
+ element :msg
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ require "sax-machine"
2
+ require "pepper/stanzas/chkdata"
3
+ require "pepper/stanzas/resdata"
4
+ require "pepper/stanzas/result"
5
+ require "pepper/stanzas/response"
6
+ require "pepper/stanzas/epp"
@@ -0,0 +1,59 @@
1
+ require "nokogiri"
2
+
3
+ module Pepper
4
+ class StreamParser < Nokogiri::XML::SAX::Document
5
+
6
+ def initialize(stream)
7
+ @stream = stream
8
+ end
9
+
10
+ def get_frame
11
+ @parser = Nokogiri::XML::SAX::PushParser.new self
12
+ @data = ""
13
+ @start, @end = nil
14
+ header = @stream.read(4)
15
+ begin
16
+ d = @stream.read(1)
17
+ @data << d # Nasty: Duplicates data to feed into sax machine, done because sax-machine does not use a push parser
18
+ @parser << d # This parser is used to find the end of the stanza in the stream
19
+ end until @end
20
+ @stanza = Pepper::Stanzas::Epp.parse @data
21
+ parse_response_code @stanza.response unless @stanza.greeting
22
+ @stanza
23
+ end
24
+
25
+ def start_element name, attrs = []
26
+ @start = name unless @start
27
+ end
28
+
29
+ def end_element name
30
+ @end = true if @start == name
31
+ end
32
+
33
+ private
34
+
35
+ def parse_response_code(response)
36
+ code = response.result_code
37
+ msg = response.result.msg.strip
38
+ case code[0].chr
39
+ when "1"
40
+ # Positive completion reply
41
+ when "2"
42
+ # Negative completion reply
43
+ case code[1].chr
44
+ when "0" : raise Error::ProtocolSyntax.new msg
45
+ when "1" : raise Error::ImplentationSpecificRules.new msg
46
+ when "2" : raise Error::Security.new msg
47
+ when "3" : raise Error::DataManagement.new msg
48
+ when "4" : raise Error::ServerSystem.new msg
49
+ when "5" : raise Error::ConnectionManagement.new msg
50
+ else
51
+ raise Error::UnrecognisedResponse.new msg
52
+ end
53
+ else
54
+ raise Error::UnrecognisedResponse.new msg
55
+ end
56
+ end
57
+
58
+ end
59
+ end
data/lib/pepper.rb ADDED
@@ -0,0 +1,13 @@
1
+ require "rubygems"
2
+ gem "sax-machine"
3
+
4
+ require "pepper/stanzas"
5
+ require "pepper/connection"
6
+ require "pepper/commands"
7
+ require "pepper/stream_parser"
8
+ require "pepper/error"
9
+
10
+ Pepper.class_eval do
11
+ include Pepper::Connection
12
+ include Pepper::Commands
13
+ end
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <epp xmlns="urn:ietf:params:xml:ns:epp-1.0"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
5
+ <response>
6
+ <result code="1000">
7
+ <msg>Command completed successfully</msg>
8
+ </result>
9
+ <trID>
10
+ <clTRID>ABC-12345</clTRID>
11
+ <svTRID>54321-XYZ</svTRID>
12
+ </trID>
13
+ </response>
14
+ </epp>
@@ -0,0 +1,51 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require "test_helper"
3
+
4
+ class LivePepperTest < Test::Unit::TestCase
5
+
6
+ context "logging in with correct credentials" do
7
+ setup do
8
+ Pepper.settings = YAML.load_file( File.join(File.dirname(__FILE__), "live_settings.yaml" ))
9
+ end
10
+
11
+ should "return true" do
12
+ assert_equal true, Pepper.login
13
+ end
14
+
15
+ context "twice" do
16
+ should "return true" do
17
+ assert_equal true, Pepper.login
18
+ assert_equal true, Pepper.login
19
+ end
20
+ end
21
+ end
22
+
23
+ context "logging in with incorrect credentials" do
24
+ should "raise error" do
25
+ Pepper.settings = YAML.load_file( File.join(File.dirname(__FILE__), "live_settings.yaml" )).merge( :tag => "FOO" )
26
+
27
+ assert_raises Pepper::Error::Security do
28
+ Pepper.login
29
+ end
30
+ end
31
+ end
32
+
33
+ context "command" do
34
+ setup do
35
+ @hash = YAML.load_file( File.join(File.dirname(__FILE__), "live_settings.yaml" ))
36
+ Pepper.settings = @hash
37
+ end
38
+
39
+ context "'check'" do
40
+ should "return available for 'foo.co.uk'" do
41
+ assert_equal( {"foo.co.uk" => true}, Pepper.check( 'foo.co.uk' ))
42
+ end
43
+
44
+ should "return correct hash for 'foo.co.uk', 'bar.co.uk' and 'macduff-TAG.co.uk'" do
45
+ domains = {"foo.co.uk" => true, "bar.co.uk" => true, "macduff-#{@hash[:tag]}.co.uk" => false}
46
+ assert_equal domains, Pepper.check( *domains.keys )
47
+ end
48
+ end
49
+ end
50
+
51
+ end
@@ -0,0 +1,4 @@
1
+ :server: testbed-epp.nominet.org.uk
2
+ :port: 700
3
+ :tag: FOO
4
+ :password: secret
@@ -0,0 +1,11 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require "test_helper"
3
+
4
+ class PepperTest < Test::Unit::TestCase
5
+ context "logging in" do
6
+ should "write login stanza" do
7
+ mock( Pepper ).write(anything) { response "login_success" }
8
+ Pepper.login
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ $:.unshift File.join( File.dirname(File.dirname(__FILE__)), "lib" )
2
+
3
+ require "pepper"
4
+
5
+ require "rubygems"
6
+
7
+ require "test/unit"
8
+ require "shoulda"
9
+ require "rr"
10
+ require 'stringio'
11
+
12
+ class Test::Unit::TestCase
13
+ include RR::Adapters::TestUnit
14
+
15
+ def response(name)
16
+ Pepper::Stanzas::Epp.parse File.read( File.join(File.dirname(__FILE__),"fixtures", "#{name}.xml") )
17
+ end
18
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pepper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Theo Cushion
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-16 00:00:00 +00:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: sax-machine
17
+ type: :runtime
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: nokogiri
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: rr
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: shoulda
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ description: Currently supports connecting to Nominet and running checks on domain names
56
+ email: theo@triplegeek.com
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files: []
62
+
63
+ files:
64
+ - README
65
+ - lib/pepper/commands.rb
66
+ - lib/pepper/connection.rb
67
+ - lib/pepper/error.rb
68
+ - lib/pepper/stanzas/chkdata.rb
69
+ - lib/pepper/stanzas/epp.rb
70
+ - lib/pepper/stanzas/resdata.rb
71
+ - lib/pepper/stanzas/response.rb
72
+ - lib/pepper/stanzas/result.rb
73
+ - lib/pepper/stanzas.rb
74
+ - lib/pepper/stream_parser.rb
75
+ - lib/pepper.rb
76
+ has_rdoc: true
77
+ homepage: http://github.com/theoooo/pepper
78
+ licenses: []
79
+
80
+ post_install_message:
81
+ rdoc_options: []
82
+
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ version:
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: "0"
96
+ version:
97
+ requirements: []
98
+
99
+ rubyforge_project:
100
+ rubygems_version: 1.3.5
101
+ signing_key:
102
+ specification_version: 3
103
+ summary: Provides a simple interface to Nominets EPP service
104
+ test_files:
105
+ - test/fixtures/login_success.xml
106
+ - test/live_pepper_test.rb
107
+ - test/pepper_test.rb
108
+ - test/test_helper.rb
109
+ - test/live_settings.yaml.example