dnsimple 2.0.0.a

Sign up to get free protection for your applications and to get access to all the features.
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