dnsimple 2.0.0.a

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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +1 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +7 -0
  7. data/CHANGELOG.markdown +50 -0
  8. data/Gemfile +3 -0
  9. data/LICENSE +22 -0
  10. data/README.markdown +60 -0
  11. data/Rakefile +33 -0
  12. data/dnsimple-ruby.gemspec +26 -0
  13. data/lib/dnsimple-ruby.rb +1 -0
  14. data/lib/dnsimple.rb +33 -0
  15. data/lib/dnsimple/base.rb +10 -0
  16. data/lib/dnsimple/certificate.rb +129 -0
  17. data/lib/dnsimple/client.rb +144 -0
  18. data/lib/dnsimple/contact.rb +154 -0
  19. data/lib/dnsimple/domain.rb +217 -0
  20. data/lib/dnsimple/error.rb +21 -0
  21. data/lib/dnsimple/extended_attribute.rb +52 -0
  22. data/lib/dnsimple/record.rb +94 -0
  23. data/lib/dnsimple/service.rb +42 -0
  24. data/lib/dnsimple/template.rb +63 -0
  25. data/lib/dnsimple/template_record.rb +80 -0
  26. data/lib/dnsimple/transfer_order.rb +34 -0
  27. data/lib/dnsimple/user.rb +26 -0
  28. data/lib/dnsimple/version.rb +3 -0
  29. data/spec/ci/.dnsimple.test +3 -0
  30. data/spec/dnsimple/certificate_spec.rb +56 -0
  31. data/spec/dnsimple/client_spec.rb +107 -0
  32. data/spec/dnsimple/contact_spec.rb +45 -0
  33. data/spec/dnsimple/domain_spec.rb +133 -0
  34. data/spec/dnsimple/extended_attributes_spec.rb +54 -0
  35. data/spec/dnsimple/record_spec.rb +51 -0
  36. data/spec/dnsimple/template_spec.rb +31 -0
  37. data/spec/dnsimple/user_spec.rb +31 -0
  38. data/spec/files/account/user/success.http +19 -0
  39. data/spec/files/certificates/index/success.http +19 -0
  40. data/spec/files/certificates/show/notfound.http +17 -0
  41. data/spec/files/certificates/show/success.http +19 -0
  42. data/spec/files/contacts/show/notfound.http +17 -0
  43. data/spec/files/contacts/show/success.http +19 -0
  44. data/spec/files/domains/auto_renewal_disable/notfound.http +21 -0
  45. data/spec/files/domains/auto_renewal_disable/success.http +23 -0
  46. data/spec/files/domains/auto_renewal_enable/notfound.http +21 -0
  47. data/spec/files/domains/auto_renewal_enable/success.http +23 -0
  48. data/spec/files/domains/show/notfound.http +17 -0
  49. data/spec/files/domains/show/success.http +19 -0
  50. data/spec/files/extended_attributes/ca.http +19 -0
  51. data/spec/files/extended_attributes/com.http +19 -0
  52. data/spec/files/extended_attributes/success.http +19 -0
  53. data/spec/files/records/index/success.http +19 -0
  54. data/spec/files/records/show/notfound.http +17 -0
  55. data/spec/files/records/show/success.http +19 -0
  56. data/spec/files/templates/show/notfound.http +17 -0
  57. data/spec/files/templates/show/success.http +19 -0
  58. data/spec/spec_helper.rb +34 -0
  59. data/spec/support/helpers.rb +15 -0
  60. data/spec/support/webmock.rb +11 -0
  61. metadata +224 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0418d92096c1c920c5693162451754d9bb762958
4
+ data.tar.gz: 21f57179e35c105fd91708c6e4144bc55c9deafc
5
+ SHA512:
6
+ metadata.gz: 49dcab64cf05445a94c9b61413935e4bc03b270adcf9c676a69f261bd895d7ae96b870d7a2a38e1d38720cc0cbced0026df8d01f6d0071c538d333aa4a3171d0
7
+ data.tar.gz: 183e028e671edbd2eba42b19c4e7492ec51808365f6e3a74eebe4dfd3bb72ebeb7ef8c2f52cc66c1003c821cb8a2f36f8deec2d98e6f67c0b21e20a901d43c6b
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ # Bundler
2
+ .bundle
3
+ pkg/*
4
+ Gemfile.lock
5
+
6
+ # YARD
7
+ .yardoc
8
+ yardoc/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ dnsimple-ruby
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.0
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.0
7
+ env: DNSIMPLE_TEST_CONFIG=spec/ci/.dnsimple.test
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ #### Release 2.0.0
4
+
5
+ - NEW: Separated CLI from library. The CLI may be found at https://github.com/aetrion/dnsimple-cli
6
+
7
+ #### Release 1.5.4
8
+
9
+ - NEW: Added domain#expires_on attribute (GH-34). Thanks @alkema
10
+
11
+ - NEW: Add various missing domain attributes (GH-38). Thanks @nickhammond
12
+
13
+ - NEW: Added support for auto-renewal (GH-36). Thanks @mzuneska
14
+
15
+ - CHANGED: User.me now uses the correct patch for API v1.
16
+
17
+ #### Release 1.5.3
18
+
19
+ - FIXED: In some cases the client crashed with NoMethodError VERSION (GH-35).
20
+
21
+ #### Release 1.5.2
22
+
23
+ - NEW: Provide a meaningful user-agent.
24
+
25
+ #### Release 1.5.1
26
+
27
+ - FIXED: Invalid base URI.
28
+
29
+ #### Release 1.5.0
30
+
31
+ - CHANGED: Added support for versioned API (GH-33)
32
+
33
+ #### Release 1.4.0
34
+
35
+ - CHANGED: Normalized exception handling. No more RuntimeError.
36
+ In case of request error, the client raises RequestError, RecordExists or RecodNotFound
37
+ depending on the called method.
38
+
39
+ - CHANGED: Use Accept header to determine the request type instead of the .json suffix in the URL.
40
+
41
+ - CHANGED: Renamed commands to the ObjectAction scheme (e.g. CreateDomain became DomainCreate).
42
+
43
+ - CHANGED: Removed DomainError, UserNotFound, CertificateNotFound, CertificateExists error classes.
44
+ See Error and RequestError.
45
+
46
+ - CHANGED: Removed DNSimple::Command base class.
47
+
48
+ - FIXED: Cucumber was trying to execute steps on dnsimple.com main website instead of given site.
49
+
50
+ - FIXED: We're no longer accepting route format. Use the correct header.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2010-2014 Aetrion LLC
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+
data/README.markdown ADDED
@@ -0,0 +1,60 @@
1
+ # DNSimple Ruby API Wrapper
2
+
3
+ [![Build Status](https://secure.travis-ci.org/aetrion/dnsimple-ruby.png)](http://travis-ci.org/aetrion/dnsimple-ruby)
4
+
5
+ A Ruby API wrapper for the [DNSimple API](http://developer.dnsimple.com/).
6
+
7
+ [DNSimple](https://dnsimple.com/) provides DNS hosting
8
+ and domain registration that is simple and friendly.
9
+
10
+ We provide a full API and an easy-to-use web interface so you can get
11
+ your domain registered and set up with a minimal amount of effort.
12
+
13
+ ## Installation
14
+
15
+ $ gem install dnsimple
16
+
17
+ ## Credentials
18
+
19
+ Create a file in your home directory called `.dnsimple`.
20
+
21
+ In this file add the following:
22
+
23
+ username: YOUR_USERNAME
24
+ password: YOUR_PASSWORD
25
+
26
+ Or if using an API token
27
+
28
+ username: YOUR_USERNAME
29
+ api_token: YOUR_API_TOKEN
30
+
31
+ ## Wrapper Classes
32
+
33
+ In addition to the command line utility you may also use the included Ruby
34
+ classes directly in your Ruby applications.
35
+
36
+ Here's a short example.
37
+
38
+ require 'rubygems'
39
+ require 'dnsimple'
40
+
41
+ DNSimple::Client.username = 'YOUR_USERNAME'
42
+ DNSimple::Client.password = 'YOUR_PASSWORD'
43
+ DNSimple::Client.http_proxy = {}
44
+
45
+ user = DNSimple::User.me
46
+ puts "#{user.domain_count} domains"
47
+
48
+ puts "Domains..."
49
+ DNSimple::Domain.all.each do |domain|
50
+ puts " #{domain.name}"
51
+ end
52
+
53
+ domain = DNSimple::Domain.find("example.com")
54
+ domain.apply("template") # applies a standard or custom template to the domain
55
+
56
+ domain = DNSimple::Domain.create("newdomain.com")
57
+ puts "Added #{domain.name}"
58
+ domain.delete # removes from DNSimple
59
+
60
+ For the full API documentation visit http://rubydoc.info/gems/dnsimple-ruby
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ # Run test by default.
4
+ task :default => :spec
5
+ task :test => :spec
6
+
7
+
8
+ require 'rspec/core/rake_task'
9
+
10
+ RSpec::Core::RakeTask.new do |t|
11
+ t.verbose = !!ENV["VERBOSE"]
12
+ end
13
+
14
+
15
+ require 'yard'
16
+
17
+ YARD::Rake::YardocTask.new(:yardoc) do |y|
18
+ y.options = ["--output-dir", "yardoc"]
19
+ end
20
+
21
+ namespace :yardoc do
22
+ task :clobber do
23
+ rm_r "yardoc" rescue nil
24
+ end
25
+ end
26
+
27
+ task :clobber => "yardoc:clobber"
28
+
29
+
30
+ desc "Open an irb session preloaded with this library"
31
+ task :console do
32
+ sh "irb -rubygems -I lib -r dnsimple.rb"
33
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'dnsimple/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'dnsimple'
7
+ s.version = DNSimple::VERSION
8
+ s.authors = ['Anthony Eden', 'Simone Carletti']
9
+ s.email = ['anthony.eden@dnsimple.com', 'simone.carletti@dnsimple.com']
10
+ s.homepage = 'http://github.com/aetrion/dnsimple-ruby'
11
+ s.summary = 'A ruby wrapper for the DNSimple API'
12
+ s.description = 'A ruby wrapper for the DNSimple API.'
13
+
14
+ s.require_paths = ['lib']
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.extra_rdoc_files = %w( README.markdown CHANGELOG.markdown LICENSE )
18
+
19
+ s.add_dependency 'httparty', RUBY_VERSION < "1.9.3" ? [">= 0.10", "< 0.12"] : "~> 0.12"
20
+
21
+ s.add_development_dependency 'rake'
22
+ s.add_development_dependency 'mocha'
23
+ s.add_development_dependency 'rspec'
24
+ s.add_development_dependency 'yard'
25
+ s.add_development_dependency 'webmock'
26
+ end
@@ -0,0 +1 @@
1
+ require 'dnsimple'
data/lib/dnsimple.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'httparty'
2
+
3
+ module DNSimple
4
+
5
+ BLANK_REGEX = /\S+/
6
+
7
+ # Echoes a deprecation warning message.
8
+ #
9
+ # @param [String] message The message to display.
10
+ # @return [void]
11
+ #
12
+ # @api internal
13
+ # @private
14
+ def self.deprecate(message = nil)
15
+ message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
16
+ warn("DEPRECATION WARNING: #{message}")
17
+ end
18
+
19
+ end
20
+
21
+ require 'dnsimple/base'
22
+ require 'dnsimple/client'
23
+ require 'dnsimple/error'
24
+ require 'dnsimple/user'
25
+ require 'dnsimple/contact'
26
+ require 'dnsimple/domain'
27
+ require 'dnsimple/record'
28
+ require 'dnsimple/template'
29
+ require 'dnsimple/template_record'
30
+ require 'dnsimple/transfer_order'
31
+ require 'dnsimple/extended_attribute'
32
+ require 'dnsimple/service'
33
+ require 'dnsimple/certificate'
@@ -0,0 +1,10 @@
1
+ module DNSimple
2
+ class Base
3
+ def initialize(attributes = {})
4
+ attributes.each do |key, value|
5
+ m = "#{key}=".to_sym
6
+ self.send(m, value) if self.respond_to?(m)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,129 @@
1
+ module DNSimple
2
+
3
+ # Represents an SSL certificate that has been purchased.
4
+ #
5
+ # The certificate must also be submitted using the #submit method
6
+ # before the Certificate Authority will issue a signed certificate.
7
+ class Certificate < Base
8
+
9
+ # The certificate ID in DNSimple
10
+ attr_accessor :id
11
+
12
+ attr_accessor :domain
13
+
14
+ # The subdomain on the certificate
15
+ attr_accessor :name
16
+
17
+ # The Certificate Signing Request
18
+ attr_accessor :csr
19
+
20
+ # The SSL certificate, if it has been issued by the Certificate Authority
21
+ attr_accessor :ssl_certificate
22
+
23
+ # The private key, if DNSimple generated the Certificate Signing Request
24
+ attr_accessor :private_key
25
+
26
+ # The approver email address
27
+ attr_accessor :approver_email
28
+
29
+ # When the certificate was purchased
30
+ attr_accessor :created_at
31
+
32
+ # When the certificate was last updated
33
+ attr_accessor :updated_at
34
+
35
+ # An array of all emails that can be used to approve the certificate
36
+ attr_accessor :available_approver_emails
37
+
38
+ # The Certificate status
39
+ attr_accessor :certificate_status
40
+
41
+ # The date the Certificate order was placed
42
+ attr_accessor :order_date
43
+
44
+ # The date the Certificate will expire
45
+ attr_accessor :expiration_date
46
+
47
+
48
+ # Purchase a certificate under the given domain with the given name. The
49
+ # name will be appended to the domain name, and thus should only be the
50
+ # subdomain part.
51
+ #
52
+ # Example: DNSimple::Certificate.purchase(domain, 'www', contact)
53
+ #
54
+ # Please note that by invoking this method DNSimple will immediately charge
55
+ # your credit card on file at DNSimple for the full certificate price.
56
+ #
57
+ # For wildcard certificates an asterisk must appear in the name.
58
+ #
59
+ # Example: DNSimple::Certificate.purchase(domain, '*', contact)
60
+ def self.purchase(domain, name, contact, options={})
61
+ certificate_hash = {
62
+ :name => name,
63
+ :contact_id => contact.id
64
+ }
65
+
66
+ options.merge!({:body => {:certificate => certificate_hash}})
67
+
68
+ response = DNSimple::Client.post("/v1/domains/#{domain.name}/certificates", options)
69
+
70
+ case response.code
71
+ when 201
72
+ new({ :domain => domain }.merge(response["certificate"]))
73
+ when 406
74
+ raise RecordExists, "Certificate for #{domain.name} already exists"
75
+ else
76
+ raise RequestError.new("Error purchasing certificate", response)
77
+ end
78
+ end
79
+
80
+ # Get an array of all certificates for the given domain.
81
+ def self.all(domain, options={})
82
+ response = DNSimple::Client.get("/v1/domains/#{domain.name}/certificates", options)
83
+
84
+ case response.code
85
+ when 200
86
+ response.map { |r| new({:domain => domain}.merge(r["certificate"])) }
87
+ else
88
+ raise RequestError.new("Error listing certificates", response)
89
+ end
90
+ end
91
+
92
+ # Find a specific certificate for the given domain.
93
+ def self.find(domain, id, options = {})
94
+ response = DNSimple::Client.get("/v1/domains/#{domain.name}/certificates/#{id}", options)
95
+
96
+ case response.code
97
+ when 200
98
+ new({:domain => domain}.merge(response["certificate"]))
99
+ when 404
100
+ raise RecordNotFound, "Could not find certificate #{id} for domain #{domain.name}"
101
+ else
102
+ raise RequestError.new("Error finding certificate", response)
103
+ end
104
+ end
105
+
106
+
107
+ # Get the fully-qualified domain name for the certificate. This is the
108
+ # domain.name joined with the certificate name, separated by a period.
109
+ def fqdn
110
+ [name, domain.name].delete_if { |p| p !~ DNSimple::BLANK_REGEX }.join(".")
111
+ end
112
+
113
+ def submit(approver_email, options={})
114
+ raise DNSimple::Error, "Approver email is required" unless approver_email
115
+
116
+ options.merge!(:body => {:certificate => {:approver_email => approver_email}})
117
+
118
+ response = DNSimple::Client.put("/v1/domains/#{domain.name}/certificates/#{id}/submit", options)
119
+
120
+ case response.code
121
+ when 200
122
+ Certificate.new({ :domain => domain }.merge(response["certificate"]))
123
+ else
124
+ raise RequestError.new("Error submitting certificate", response)
125
+ end
126
+ end
127
+
128
+ end
129
+ end
@@ -0,0 +1,144 @@
1
+ require 'dnsimple/version'
2
+ require 'yaml'
3
+
4
+ module DNSimple
5
+ class Client
6
+
7
+ DEFAULT_BASE_URI = "https://api.dnsimple.com/"
8
+
9
+
10
+ def self.debug?
11
+ @debug
12
+ end
13
+
14
+ def self.debug=(debug)
15
+ @debug = debug
16
+ end
17
+
18
+ def self.username
19
+ @username
20
+ end
21
+
22
+ def self.username=(username)
23
+ @username = username
24
+ end
25
+
26
+ def self.password
27
+ @password
28
+ end
29
+
30
+ def self.password=(password)
31
+ @password = password
32
+ end
33
+
34
+ def self.api_token
35
+ @api_token
36
+ end
37
+
38
+ def self.api_token=(api_token)
39
+ @api_token = api_token
40
+ end
41
+
42
+ # Gets the qualified API base uri.
43
+ #
44
+ # @return [String] The qualified API base uri.
45
+ def self.base_uri
46
+ @base_uri ||= DEFAULT_BASE_URI.chomp("/")
47
+ end
48
+
49
+ # Sets the qualified API base uri.
50
+ #
51
+ # @param [String] value The qualified API base uri.
52
+ def self.base_uri=(value)
53
+ @base_uri = value.to_s.chomp("/")
54
+ end
55
+
56
+ def self.http_proxy
57
+ @http_proxy
58
+ end
59
+
60
+ def self.http_proxy=(http_proxy)
61
+ @http_proxy = http_proxy
62
+ end
63
+
64
+ def self.load_credentials_if_necessary
65
+ load_credentials unless credentials_loaded?
66
+ end
67
+
68
+ def self.config_path
69
+ ENV['DNSIMPLE_CONFIG'] || '~/.dnsimple'
70
+ end
71
+
72
+ def self.load_credentials(path = config_path)
73
+ begin
74
+ credentials = YAML.load_file(File.expand_path(path))
75
+ self.username ||= credentials['username']
76
+ self.password ||= credentials['password']
77
+ self.api_token ||= credentials['api_token']
78
+ self.base_uri = credentials['site'] if credentials['site']
79
+ self.base_uri = credentials['base_uri'] if credentials['base_uri']
80
+ self.http_proxy = { :addr => credentials['proxy_addr'], :port => credentials['proxy_port'] } if credentials['proxy_addr'] || credentials['proxy_port']
81
+ @credentials_loaded = true
82
+ puts "Credentials loaded from #{path}"
83
+ rescue => error
84
+ puts "Error loading your credentials: #{error.message}"
85
+ exit 1
86
+ end
87
+ end
88
+
89
+ def self.credentials_loaded?
90
+ (@credentials_loaded ||= false) or (username and (password or api_token))
91
+ end
92
+
93
+ def self.base_options
94
+ options = {
95
+ :format => :json,
96
+ :headers => { 'Accept' => 'application/json', 'User-Agent' => "dnsimple-ruby/#{DNSimple::VERSION}" },
97
+ }
98
+
99
+ if http_proxy
100
+ options.merge!(
101
+ :http_proxyaddr => self.http_proxy[:addr],
102
+ :http_proxyport => self.http_proxy[:port]
103
+ )
104
+ end
105
+
106
+ if password
107
+ options[:basic_auth] = { :username => username, :password => password }
108
+ elsif api_token
109
+ options[:headers]['X-DNSimple-Token'] = "#{username}:#{api_token}"
110
+ else
111
+ raise Error, 'A password or API token is required for all API requests.'
112
+ end
113
+
114
+ options
115
+ end
116
+
117
+ def self.get(path, options = {})
118
+ request :get, path, options
119
+ end
120
+
121
+ def self.post(path, options = {})
122
+ request :post, path, options
123
+ end
124
+
125
+ def self.put(path, options = {})
126
+ request :put, path, options
127
+ end
128
+
129
+ def self.delete(path, options = {})
130
+ request :delete, path, options
131
+ end
132
+
133
+ def self.request(method, path, options)
134
+ response = HTTParty.send(method, "#{base_uri}#{path}", base_options.merge(options))
135
+
136
+ if response.code == 401
137
+ raise AuthenticationFailed
138
+ end
139
+
140
+ response
141
+ end
142
+
143
+ end
144
+ end