dnsimple 2.0.0.a → 2.0.0.alpha2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +1 -2
  5. data/CHANGELOG.markdown +26 -2
  6. data/Gemfile +2 -0
  7. data/README.markdown +56 -36
  8. data/Rakefile +0 -1
  9. data/{dnsimple-ruby.gemspec → dnsimple.gemspec} +6 -4
  10. data/lib/dnsimple.rb +1 -1
  11. data/lib/dnsimple/base.rb +1 -1
  12. data/lib/dnsimple/certificate.rb +49 -35
  13. data/lib/dnsimple/client.rb +25 -72
  14. data/lib/dnsimple/contact.rb +12 -9
  15. data/lib/dnsimple/domain.rb +117 -82
  16. data/lib/dnsimple/error.rb +13 -2
  17. data/lib/dnsimple/extended_attribute.rb +3 -3
  18. data/lib/dnsimple/record.rb +9 -9
  19. data/lib/dnsimple/service.rb +3 -3
  20. data/lib/dnsimple/template.rb +8 -6
  21. data/lib/dnsimple/template_record.rb +8 -8
  22. data/lib/dnsimple/transfer_order.rb +2 -2
  23. data/lib/dnsimple/user.rb +26 -2
  24. data/lib/dnsimple/version.rb +2 -2
  25. data/spec/dnsimple/certificate_spec.rb +8 -5
  26. data/spec/dnsimple/client_spec.rb +56 -9
  27. data/spec/dnsimple/contact_spec.rb +2 -2
  28. data/spec/dnsimple/domain_spec.rb +140 -32
  29. data/spec/dnsimple/extended_attributes_spec.rb +1 -1
  30. data/spec/dnsimple/record_spec.rb +2 -2
  31. data/spec/dnsimple/template_spec.rb +1 -1
  32. data/spec/dnsimple/user_spec.rb +40 -1
  33. data/spec/files/2fa/error-badtoken.http +22 -0
  34. data/spec/files/2fa/error-required.http +23 -0
  35. data/spec/files/2fa/exchange-token.http +25 -0
  36. data/spec/files/account/user/success.http +3 -3
  37. data/spec/files/certificates/index/success.http +2 -2
  38. data/spec/files/certificates/show/notfound.http +2 -2
  39. data/spec/files/certificates/show/success.http +2 -2
  40. data/spec/files/contacts/show/notfound.http +2 -2
  41. data/spec/files/contacts/show/success.http +3 -3
  42. data/spec/files/domains/auto_renewal_disable/notfound.http +1 -1
  43. data/spec/files/domains/auto_renewal_disable/success.http +1 -1
  44. data/spec/files/domains/auto_renewal_enable/notfound.http +1 -1
  45. data/spec/files/domains/auto_renewal_enable/success.http +1 -1
  46. data/spec/files/domains/create/success.http +19 -0
  47. data/spec/files/domains/delete/success-204.http +18 -0
  48. data/spec/files/domains/delete/success.http +19 -0
  49. data/spec/files/domains/index/success.http +19 -0
  50. data/spec/files/domains/{show/notfound.http → notfound.http} +2 -2
  51. data/spec/files/domains/show/success.http +2 -2
  52. data/spec/files/extended_attributes/ca.http +2 -2
  53. data/spec/files/extended_attributes/com.http +2 -2
  54. data/spec/files/extended_attributes/success.http +2 -2
  55. data/spec/files/records/index/success.http +2 -2
  56. data/spec/files/records/show/notfound.http +2 -2
  57. data/spec/files/records/show/success.http +2 -2
  58. data/spec/files/templates/show/notfound.http +2 -2
  59. data/spec/files/templates/show/success.http +2 -2
  60. data/spec/spec_helper.rb +9 -9
  61. metadata +45 -33
  62. data/lib/dnsimple-ruby.rb +0 -1
  63. data/spec/ci/.dnsimple.test +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0418d92096c1c920c5693162451754d9bb762958
4
- data.tar.gz: 21f57179e35c105fd91708c6e4144bc55c9deafc
3
+ metadata.gz: 0e16688144a4991e78dc2f86e78dbc558c011aa4
4
+ data.tar.gz: f7dc21999ebef6b8bfee73a6a9d0afefad8ca89e
5
5
  SHA512:
6
- metadata.gz: 49dcab64cf05445a94c9b61413935e4bc03b270adcf9c676a69f261bd895d7ae96b870d7a2a38e1d38720cc0cbced0026df8d01f6d0071c538d333aa4a3171d0
7
- data.tar.gz: 183e028e671edbd2eba42b19c4e7492ec51808365f6e3a74eebe4dfd3bb72ebeb7ef8c2f52cc66c1003c821cb8a2f36f8deec2d98e6f67c0b21e20a901d43c6b
6
+ metadata.gz: 461f978e357d7a1b6895253d8c1488f7d8b720fd00b1ef80008b83071ca6d4dc8b5aafcefe927b90aacc708deda5de9fbed6f491de67ef56d0bad4d44adc087c
7
+ data.tar.gz: aef1ebfd28622173d53fc183a5834f5b42390fc3c7d4aff75686456b9d578fe5059430aab72436c55df836284bde6bde638538d524572bde220fe14e706531ee
data/.gitignore CHANGED
@@ -6,3 +6,4 @@ Gemfile.lock
6
6
  # YARD
7
7
  .yardoc
8
8
  yardoc/
9
+ doc/
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-2.0
1
+ ruby-2.1
data/.travis.yml CHANGED
@@ -1,7 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.2
4
3
  - 1.9.3
5
4
  - 2.0.0
6
5
  - 2.1.0
7
- env: DNSIMPLE_TEST_CONFIG=spec/ci/.dnsimple.test
6
+ env: COVERALL=1
data/CHANGELOG.markdown CHANGED
@@ -1,8 +1,32 @@
1
1
  # Changelog
2
2
 
3
- #### Release 2.0.0
3
+ #### 2.0.0.alpha
4
4
 
5
- - NEW: Separated CLI from library. The CLI may be found at https://github.com/aetrion/dnsimple-cli
5
+ - CHANGED: Drop 1.8.7 support.
6
+
7
+ - CHANGED: This package no longer provides a CLI. The CLI has been extracted to [aetrion/dnsimple-ruby-cli](https://github.com/aetrion/dnsimple-ruby-cli)
8
+
9
+ - CHANGED: Renamed the Gem from "dnsimple-ruby" to "dnsimple". (GH-23)
10
+
11
+ - CHANGED: Renamed the namespace from DNSimple to Dnsimple.
12
+
13
+ - REMOVED: The library no longer provides built-in support for loading the credentials from a config file.
14
+
15
+ #### Release 1.7.1
16
+
17
+ - FIXED: Updated Certificate to match the serialized attributes (GH-53)
18
+
19
+ #### Release 1.7.0
20
+
21
+ - NEW: Add support for Domain-based authentication (GH-40, GH-46). Thanks @dwradcliffe and @samsonasu.
22
+
23
+ #### Release 1.6.0
24
+
25
+ - NEW: Add support for 2FA (GH-44)
26
+
27
+ #### Release 1.5.5
28
+
29
+ - NEW: Add notice about the CLI moving to a new location
6
30
 
7
31
  #### Release 1.5.4
8
32
 
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ gem 'coveralls', :require => false
data/README.markdown CHANGED
@@ -1,60 +1,80 @@
1
- # DNSimple Ruby API Wrapper
1
+ # DNSimple Ruby Client
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/aetrion/dnsimple-ruby.png)](http://travis-ci.org/aetrion/dnsimple-ruby)
3
+ A Ruby client for the [DNSimple API](http://developer.dnsimple.com/).
4
4
 
5
- A Ruby API wrapper for the [DNSimple API](http://developer.dnsimple.com/).
5
+ [![Build Status](https://travis-ci.org/aetrion/dnsimple-ruby.svg?branch=master)](https://travis-ci.org/aetrion/dnsimple-ruby)
6
+ [![Coverage Status](https://img.shields.io/coveralls/aetrion/dnsimple-ruby.svg)](https://coveralls.io/r/aetrion/dnsimple-ruby?branch=master)
6
7
 
7
- [DNSimple](https://dnsimple.com/) provides DNS hosting
8
- and domain registration that is simple and friendly.
8
+ [DNSimple](https://dnsimple.com/) provides DNS hosting and domain registration that is simple and friendly.
9
+ We provide a full API and an easy-to-use web interface so you can get your domain registered and set up with a minimal amount of effort.
9
10
 
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
11
 
13
12
  ## Installation
14
13
 
15
14
  $ gem install dnsimple
16
15
 
17
- ## Credentials
18
16
 
19
- Create a file in your home directory called `.dnsimple`.
17
+ ## DNSimple Client
20
18
 
21
- In this file add the following:
19
+ This library provides a Ruby DNSimple client you can use to interact with the [DNSimple API](http://developer.dnsimple.com/). Here's a short example.
22
20
 
23
- username: YOUR_USERNAME
24
- password: YOUR_PASSWORD
21
+ ```ruby
22
+ require 'dnsimple'
25
23
 
26
- Or if using an API token
24
+ DNSimple::Client.username = 'YOUR_USERNAME'
25
+ DNSimple::Client.password = 'YOUR_PASSWORD'
27
26
 
28
- username: YOUR_USERNAME
29
- api_token: YOUR_API_TOKEN
27
+ user = DNSimple::User.me
28
+ puts "#{user.domain_count} domains"
30
29
 
31
- ## Wrapper Classes
30
+ puts "Domains..."
31
+ DNSimple::Domain.all.each do |domain|
32
+ puts " #{domain.name}"
33
+ end
32
34
 
33
- In addition to the command line utility you may also use the included Ruby
34
- classes directly in your Ruby applications.
35
+ domain = DNSimple::Domain.find("example.com")
36
+ domain.apply("template") # applies a standard or custom template to the domain
35
37
 
36
- Here's a short example.
38
+ domain = DNSimple::Domain.create("newdomain.com")
39
+ puts "Added #{domain.name}"
40
+ domain.delete # removes from DNSimple
41
+ ```
37
42
 
38
- require 'rubygems'
39
- require 'dnsimple'
43
+ For the full API documentation visit http://rubydoc.info/gems/dnsimple
40
44
 
41
- DNSimple::Client.username = 'YOUR_USERNAME'
42
- DNSimple::Client.password = 'YOUR_PASSWORD'
43
- DNSimple::Client.http_proxy = {}
45
+ ### Authentication
44
46
 
45
- user = DNSimple::User.me
46
- puts "#{user.domain_count} domains"
47
+ This client supports both the HTTP Basic and API Token authentication mechanism.
47
48
 
48
- puts "Domains..."
49
- DNSimple::Domain.all.each do |domain|
50
- puts " #{domain.name}"
51
- end
49
+ #### HTTP Basic
52
50
 
53
- domain = DNSimple::Domain.find("example.com")
54
- domain.apply("template") # applies a standard or custom template to the domain
51
+ ```ruby
52
+ DNSimple::Client.username = 'YOUR_USERNAME'
53
+ DNSimple::Client.password = 'YOUR_PASSWORD'
55
54
 
56
- domain = DNSimple::Domain.create("newdomain.com")
57
- puts "Added #{domain.name}"
58
- domain.delete # removes from DNSimple
55
+ user = DNSimple::User.me
56
+ ```
59
57
 
60
- For the full API documentation visit http://rubydoc.info/gems/dnsimple-ruby
58
+ #### HTTP Basic with two-factor authentication enabled
59
+
60
+ See the [2FA API documentation](http://developer.dnsimple.com/authentication/#twofa).
61
+
62
+ ```ruby
63
+ # Request the 2FA exchange token
64
+ DNSimple::Client.username = 'YOUR_USERNAME'
65
+ DNSimple::Client.password = 'YOUR_PASSWORD'
66
+ token = DNSimple::User.two_factor_exchange_token('otp-token')
67
+
68
+ # Authenticate with the exchange token
69
+ DNSimple::Client.exchange_token = token
70
+ user = DNSimple::User.me
71
+ ```
72
+
73
+ #### API Token
74
+
75
+ ```ruby
76
+ DNSimple::Client.username = 'YOUR_USERNAME'
77
+ DNSimple::Client.api_token = 'API_TOKEN'
78
+
79
+ user = DNSimple::User.me
80
+ ```
data/Rakefile CHANGED
@@ -2,7 +2,6 @@ require 'bundler/gem_tasks'
2
2
 
3
3
  # Run test by default.
4
4
  task :default => :spec
5
- task :test => :spec
6
5
 
7
6
 
8
7
  require 'rspec/core/rake_task'
@@ -4,19 +4,21 @@ require 'dnsimple/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = 'dnsimple'
7
- s.version = DNSimple::VERSION
7
+ s.version = Dnsimple::VERSION
8
8
  s.authors = ['Anthony Eden', 'Simone Carletti']
9
9
  s.email = ['anthony.eden@dnsimple.com', 'simone.carletti@dnsimple.com']
10
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.'
11
+ s.summary = 'A Ruby client for the DNSimple API'
12
+ s.description = 'A Ruby client for the DNSimple API that also includes a command-line client.'
13
+
14
+ s.required_ruby_version = ">= 1.9.3"
13
15
 
14
16
  s.require_paths = ['lib']
15
17
  s.files = `git ls-files`.split("\n")
16
18
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
19
  s.extra_rdoc_files = %w( README.markdown CHANGELOG.markdown LICENSE )
18
20
 
19
- s.add_dependency 'httparty', RUBY_VERSION < "1.9.3" ? [">= 0.10", "< 0.12"] : "~> 0.12"
21
+ s.add_dependency 'httparty'
20
22
 
21
23
  s.add_development_dependency 'rake'
22
24
  s.add_development_dependency 'mocha'
data/lib/dnsimple.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'httparty'
2
2
 
3
- module DNSimple
3
+ module Dnsimple
4
4
 
5
5
  BLANK_REGEX = /\S+/
6
6
 
data/lib/dnsimple/base.rb CHANGED
@@ -1,4 +1,4 @@
1
- module DNSimple
1
+ module Dnsimple
2
2
  class Base
3
3
  def initialize(attributes = {})
4
4
  attributes.each do |key, value|
@@ -1,4 +1,4 @@
1
- module DNSimple
1
+ module Dnsimple
2
2
 
3
3
  # Represents an SSL certificate that has been purchased.
4
4
  #
@@ -6,57 +6,71 @@ module DNSimple
6
6
  # before the Certificate Authority will issue a signed certificate.
7
7
  class Certificate < Base
8
8
 
9
- # The certificate ID in DNSimple
9
+ # The Fixnum certificate ID in DNSimple.
10
10
  attr_accessor :id
11
11
 
12
- attr_accessor :domain
12
+ # The Fixnum associated domain ID.
13
+ attr_accessor :domain_id
14
+
15
+ # The Fixnum associated contact ID.
16
+ attr_accessor :contact_id
13
17
 
14
- # The subdomain on the certificate
18
+ # The String subdomain on the certificate.
15
19
  attr_accessor :name
16
20
 
17
- # The Certificate Signing Request
21
+ # The String state.
22
+ attr_accessor :state
23
+
24
+ # The String Certificate Signing Request.
18
25
  attr_accessor :csr
19
26
 
20
- # The SSL certificate, if it has been issued by the Certificate Authority
27
+ # The String SSL certificate.
28
+ # It is set only if the order issued by the Certificate Authority.
21
29
  attr_accessor :ssl_certificate
22
30
 
23
- # The private key, if DNSimple generated the Certificate Signing Request
31
+ # The String private key.
32
+ # It is set only if DNSimple generated the Certificate Signing Request.
24
33
  attr_accessor :private_key
25
34
 
26
- # The approver email address
35
+ # The String approver email address
36
+ # It is set only if the state is submitted.
27
37
  attr_accessor :approver_email
28
38
 
29
- # When the certificate was purchased
39
+ # The Array of all emails that can be used to approve the certificate.
40
+ # It is set only if the state is configured.
41
+ attr_accessor :approver_emails
42
+
43
+ # The Date the certificate was create in DNSimple.
30
44
  attr_accessor :created_at
31
45
 
32
- # When the certificate was last updated
46
+ # The Date the certificate was last updated in DNSimple.
33
47
  attr_accessor :updated_at
34
48
 
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
49
+ # The Date the certificate was configured.
50
+ attr_accessor :configured_at
40
51
 
41
- # The date the Certificate order was placed
42
- attr_accessor :order_date
52
+ # The Date the certificate will expire.
53
+ attr_accessor :expires_on
43
54
 
44
- # The date the Certificate will expire
45
- attr_accessor :expiration_date
55
+ # The associated Domain.
56
+ attr_accessor :domain
46
57
 
47
58
 
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.
59
+ # Purchases a certificate under the given domain with the given name.
51
60
  #
52
- # Example: DNSimple::Certificate.purchase(domain, 'www', contact)
61
+ # The name will be appended to the domain name, and thus should only be the subdomain part.
53
62
  #
54
- # Please note that by invoking this method DNSimple will immediately charge
63
+ # Invoking this method DNSimple will immediately charge
55
64
  # your credit card on file at DNSimple for the full certificate price.
56
65
  #
57
66
  # For wildcard certificates an asterisk must appear in the name.
58
67
  #
59
- # Example: DNSimple::Certificate.purchase(domain, '*', contact)
68
+ # @example Purchase a single-hostname certificate
69
+ # Dnsimple::Certificate.purchase(domain, 'www', contact)
70
+ #
71
+ # @example Purchase a wildcard certificate
72
+ # Dnsimple::Certificate.purchase(domain, '*', contact)
73
+ #
60
74
  def self.purchase(domain, name, contact, options={})
61
75
  certificate_hash = {
62
76
  :name => name,
@@ -65,7 +79,7 @@ module DNSimple
65
79
 
66
80
  options.merge!({:body => {:certificate => certificate_hash}})
67
81
 
68
- response = DNSimple::Client.post("/v1/domains/#{domain.name}/certificates", options)
82
+ response = Client.post("/v1/domains/#{domain.name}/certificates", options)
69
83
 
70
84
  case response.code
71
85
  when 201
@@ -79,7 +93,7 @@ module DNSimple
79
93
 
80
94
  # Get an array of all certificates for the given domain.
81
95
  def self.all(domain, options={})
82
- response = DNSimple::Client.get("/v1/domains/#{domain.name}/certificates", options)
96
+ response = Client.get("/v1/domains/#{domain.name}/certificates", options)
83
97
 
84
98
  case response.code
85
99
  when 200
@@ -91,7 +105,7 @@ module DNSimple
91
105
 
92
106
  # Find a specific certificate for the given domain.
93
107
  def self.find(domain, id, options = {})
94
- response = DNSimple::Client.get("/v1/domains/#{domain.name}/certificates/#{id}", options)
108
+ response = Client.get("/v1/domains/#{domain.name}/certificates/#{id}", options)
95
109
 
96
110
  case response.code
97
111
  when 200
@@ -107,21 +121,21 @@ module DNSimple
107
121
  # Get the fully-qualified domain name for the certificate. This is the
108
122
  # domain.name joined with the certificate name, separated by a period.
109
123
  def fqdn
110
- [name, domain.name].delete_if { |p| p !~ DNSimple::BLANK_REGEX }.join(".")
124
+ [name, domain.name].delete_if { |p| p !~ BLANK_REGEX }.join(".")
111
125
  end
112
126
 
113
127
  def submit(approver_email, options={})
114
- raise DNSimple::Error, "Approver email is required" unless approver_email
128
+ raise Error, "Approver email is required" unless approver_email
115
129
 
116
130
  options.merge!(:body => {:certificate => {:approver_email => approver_email}})
117
131
 
118
- response = DNSimple::Client.put("/v1/domains/#{domain.name}/certificates/#{id}/submit", options)
132
+ response = Client.put("/v1/domains/#{domain.name}/certificates/#{id}/submit", options)
119
133
 
120
134
  case response.code
121
- when 200
122
- Certificate.new({ :domain => domain }.merge(response["certificate"]))
123
- else
124
- raise RequestError.new("Error submitting certificate", response)
135
+ when 200
136
+ Certificate.new({ :domain => domain }.merge(response["certificate"]))
137
+ else
138
+ raise RequestError.new("Error submitting certificate", response)
125
139
  end
126
140
  end
127
141
 
@@ -1,42 +1,22 @@
1
1
  require 'dnsimple/version'
2
2
  require 'yaml'
3
3
 
4
- module DNSimple
4
+ module Dnsimple
5
5
  class Client
6
6
 
7
- DEFAULT_BASE_URI = "https://api.dnsimple.com/"
7
+ DEFAULT_BASE_URI = "https://api.dnsimple.com/"
8
+ HEADER_2FA_STRICT = "X-DNSimple-2FA-Strict"
9
+ HEADER_API_TOKEN = "X-DNSimple-Token"
10
+ HEADER_DOMAIN_API_TOKEN = "X-DNSimple-Domain-Token"
11
+ HEADER_OTP_TOKEN = "X-DNSimple-OTP"
12
+ HEADER_EXCHANGE_TOKEN = "X-DNSimple-OTP-Token"
8
13
 
14
+ class << self
15
+ # @return [Boolean] if the debug mode is enabled.
16
+ # Defaults to false.
17
+ attr_accessor :debug
9
18
 
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
19
+ attr_accessor :username, :password, :exchange_token, :api_token, :domain_api_token
40
20
  end
41
21
 
42
22
  # Gets the qualified API base uri.
@@ -57,56 +37,27 @@ module DNSimple
57
37
  @http_proxy
58
38
  end
59
39
 
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
40
  def self.base_options
94
41
  options = {
95
42
  :format => :json,
96
- :headers => { 'Accept' => 'application/json', 'User-Agent' => "dnsimple-ruby/#{DNSimple::VERSION}" },
43
+ :headers => { 'Accept' => 'application/json', 'User-Agent' => "dnsimple-ruby/#{VERSION}" },
97
44
  }
98
45
 
99
46
  if http_proxy
100
47
  options.merge!(
101
- :http_proxyaddr => self.http_proxy[:addr],
102
- :http_proxyport => self.http_proxy[:port]
48
+ :http_proxyaddr => http_proxy[:addr],
49
+ :http_proxyport => http_proxy[:port]
103
50
  )
104
51
  end
105
52
 
106
- if password
53
+ if exchange_token
54
+ options[:basic_auth] = { :username => exchange_token, :password => "x-2fa-basic" }
55
+ elsif password
107
56
  options[:basic_auth] = { :username => username, :password => password }
57
+ elsif domain_api_token
58
+ options[:headers][HEADER_DOMAIN_API_TOKEN] = domain_api_token
108
59
  elsif api_token
109
- options[:headers]['X-DNSimple-Token'] = "#{username}:#{api_token}"
60
+ options[:headers][HEADER_API_TOKEN] = "#{username}:#{api_token}"
110
61
  else
111
62
  raise Error, 'A password or API token is required for all API requests.'
112
63
  end
@@ -133,8 +84,10 @@ module DNSimple
133
84
  def self.request(method, path, options)
134
85
  response = HTTParty.send(method, "#{base_uri}#{path}", base_options.merge(options))
135
86
 
136
- if response.code == 401
137
- raise AuthenticationFailed
87
+ if response.code == 401 && response.headers[HEADER_OTP_TOKEN] == "required"
88
+ raise TwoFactorAuthenticationRequired, response["message"]
89
+ elsif response.code == 401
90
+ raise AuthenticationFailed, response["message"]
138
91
  end
139
92
 
140
93
  response