dnsimple-ruby 1.5.5 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +65 -31
- data/bin/dnsimple.rb +1 -1
- data/lib/dnsimple/client.rb +27 -47
- data/lib/dnsimple/error.rb +12 -1
- data/lib/dnsimple/user.rb +25 -0
- data/lib/dnsimple/version.rb +1 -1
- data/spec/dnsimple/client_spec.rb +41 -5
- data/spec/dnsimple/domain_spec.rb +6 -6
- data/spec/dnsimple/user_spec.rb +39 -0
- data/spec/files/2fa/error-badtoken.http +22 -0
- data/spec/files/2fa/error-required.http +23 -0
- data/spec/files/2fa/exchange-token.http +25 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c40f147d4747a607ca8ae3cfb8bb1f99830513d9
|
4
|
+
data.tar.gz: 5d72dcfc3d7332887eec729b7d9122b51cc3fafb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 268b16e76b613c51ba2da2f51c5955d54f3ca4437acfef0232a5b4718d69b805420a5dc9851ca4d72fff1e594c3c3c4d91abab15aea138ffbbafdab9c37e34be
|
7
|
+
data.tar.gz: eb197c1b3b13de5a44075bba53585a2ed2c9cfb884cb63ba916b0cb7f52e14ed41aec1d1022b28a0c8c565ff5ff0178760fbe2102ab71934bbc39315c3e09538
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -11,6 +11,71 @@ your domain registered and set up with a minimal amount of effort.
|
|
11
11
|
|
12
12
|
$ gem install dnsimple-ruby
|
13
13
|
|
14
|
+
## DNSimple Client
|
15
|
+
|
16
|
+
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.
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
require 'dnsimple'
|
20
|
+
|
21
|
+
DNSimple::Client.username = 'YOUR_USERNAME'
|
22
|
+
DNSimple::Client.password = 'YOUR_PASSWORD'
|
23
|
+
|
24
|
+
user = DNSimple::User.me
|
25
|
+
puts "#{user.domain_count} domains"
|
26
|
+
|
27
|
+
puts "Domains..."
|
28
|
+
DNSimple::Domain.all.each do |domain|
|
29
|
+
puts " #{domain.name}"
|
30
|
+
end
|
31
|
+
|
32
|
+
domain = DNSimple::Domain.find("example.com")
|
33
|
+
domain.apply("template") # applies a standard or custom template to the domain
|
34
|
+
|
35
|
+
domain = DNSimple::Domain.create("newdomain.com")
|
36
|
+
puts "Added #{domain.name}"
|
37
|
+
domain.delete # removes from DNSimple
|
38
|
+
```
|
39
|
+
|
40
|
+
For the full API documentation visit http://rubydoc.info/gems/dnsimple-ruby
|
41
|
+
|
42
|
+
### Authentication
|
43
|
+
|
44
|
+
This client supports both the HTTP Basic and API Token authentication mechanism.
|
45
|
+
|
46
|
+
#### HTTP Basic
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
DNSimple::Client.username = 'YOUR_USERNAME'
|
50
|
+
DNSimple::Client.password = 'YOUR_PASSWORD'
|
51
|
+
|
52
|
+
user = DNSimple::User.me
|
53
|
+
```
|
54
|
+
|
55
|
+
#### HTTP Basic with two-factor authentication enabled
|
56
|
+
|
57
|
+
See the [2FA API documentation](http://developer.dnsimple.com/authentication/#twofa).
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# Request the 2FA exchange token
|
61
|
+
DNSimple::Client.username = 'YOUR_USERNAME'
|
62
|
+
DNSimple::Client.password = 'YOUR_PASSWORD'
|
63
|
+
token = DNSimple::User.two_factor_exchange_token('otp-token')
|
64
|
+
|
65
|
+
# Authenticate with the exchange token
|
66
|
+
DNSimple::Client.exchange_token = token
|
67
|
+
user = DNSimple::User.me
|
68
|
+
```
|
69
|
+
|
70
|
+
#### API Token
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
DNSimple::Client.api_token = 'the-token'
|
74
|
+
|
75
|
+
user = DNSimple::User.me
|
76
|
+
```
|
77
|
+
|
78
|
+
|
14
79
|
## Credentials
|
15
80
|
|
16
81
|
Create a file in your home directory called `.dnsimple`.
|
@@ -91,34 +156,3 @@ The contact name/value pairs are:
|
|
91
156
|
- phone
|
92
157
|
- phone_ext (optional)
|
93
158
|
- fax (optional)
|
94
|
-
|
95
|
-
## Wrapper Classes
|
96
|
-
|
97
|
-
In addition to the command line utility you may also use the included Ruby
|
98
|
-
classes directly in your Ruby applications.
|
99
|
-
|
100
|
-
Here's a short example.
|
101
|
-
|
102
|
-
require 'rubygems'
|
103
|
-
require 'dnsimple'
|
104
|
-
|
105
|
-
DNSimple::Client.username = 'YOUR_USERNAME'
|
106
|
-
DNSimple::Client.password = 'YOUR_PASSWORD'
|
107
|
-
DNSimple::Client.http_proxy = {}
|
108
|
-
|
109
|
-
user = DNSimple::User.me
|
110
|
-
puts "#{user.domain_count} domains"
|
111
|
-
|
112
|
-
puts "Domains..."
|
113
|
-
DNSimple::Domain.all.each do |domain|
|
114
|
-
puts " #{domain.name}"
|
115
|
-
end
|
116
|
-
|
117
|
-
domain = DNSimple::Domain.find("example.com")
|
118
|
-
domain.apply("template") # applies a standard or custom template to the domain
|
119
|
-
|
120
|
-
domain = DNSimple::Domain.create("newdomain.com")
|
121
|
-
puts "Added #{domain.name}"
|
122
|
-
domain.delete # removes from DNSimple
|
123
|
-
|
124
|
-
For the full API documentation visit http://rubydoc.info/gems/dnsimple-ruby
|
data/bin/dnsimple.rb
CHANGED
@@ -12,7 +12,7 @@ def usage
|
|
12
12
|
$stderr.puts <<EOF
|
13
13
|
|
14
14
|
NOTICE: The CLI is moving out into its own repository and its own gem! Visit
|
15
|
-
https://
|
15
|
+
https://github.com/aetrion/dnsimple-cli
|
16
16
|
|
17
17
|
This is a command line tool for DNSimple. More information about DNSimple can
|
18
18
|
be found at http://dnsimple.com/
|
data/lib/dnsimple/client.rb
CHANGED
@@ -4,39 +4,18 @@ require 'yaml'
|
|
4
4
|
module DNSimple
|
5
5
|
class Client
|
6
6
|
|
7
|
-
DEFAULT_BASE_URI
|
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_OTP_TOKEN = "X-DNSimple-OTP"
|
11
|
+
HEADER_EXCHANGE_TOKEN = "X-DNSimple-OTP-Token"
|
8
12
|
|
13
|
+
class << self
|
14
|
+
# @return [Boolean] if the debug mode is enabled.
|
15
|
+
# Defaults to false.
|
16
|
+
attr_accessor :debug
|
9
17
|
|
10
|
-
|
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
|
18
|
+
attr_accessor :username, :password, :exchange_token, :api_token
|
40
19
|
end
|
41
20
|
|
42
21
|
# Gets the qualified API base uri.
|
@@ -57,10 +36,6 @@ module DNSimple
|
|
57
36
|
@http_proxy
|
58
37
|
end
|
59
38
|
|
60
|
-
def self.http_proxy=(http_proxy)
|
61
|
-
@http_proxy = http_proxy
|
62
|
-
end
|
63
|
-
|
64
39
|
def self.load_credentials_if_necessary
|
65
40
|
load_credentials unless credentials_loaded?
|
66
41
|
end
|
@@ -72,12 +47,13 @@ module DNSimple
|
|
72
47
|
def self.load_credentials(path = config_path)
|
73
48
|
begin
|
74
49
|
credentials = YAML.load_file(File.expand_path(path))
|
75
|
-
self.username
|
76
|
-
self.password
|
77
|
-
self.
|
78
|
-
self.
|
79
|
-
self.base_uri
|
80
|
-
self.
|
50
|
+
self.username = credentials['username']
|
51
|
+
self.password = credentials['password']
|
52
|
+
self.exchange_token = credentials['exchange_token']
|
53
|
+
self.api_token = credentials['api_token']
|
54
|
+
self.base_uri = credentials['site'] if credentials['site']
|
55
|
+
self.base_uri = credentials['base_uri'] if credentials['base_uri']
|
56
|
+
@http_proxy = { :addr => credentials['proxy_addr'], :port => credentials['proxy_port'] } if credentials['proxy_addr'] || credentials['proxy_port']
|
81
57
|
@credentials_loaded = true
|
82
58
|
puts "Credentials loaded from #{path}"
|
83
59
|
rescue => error
|
@@ -98,15 +74,17 @@ module DNSimple
|
|
98
74
|
|
99
75
|
if http_proxy
|
100
76
|
options.merge!(
|
101
|
-
:http_proxyaddr =>
|
102
|
-
:http_proxyport =>
|
77
|
+
:http_proxyaddr => http_proxy[:addr],
|
78
|
+
:http_proxyport => http_proxy[:port]
|
103
79
|
)
|
104
80
|
end
|
105
81
|
|
106
|
-
if
|
82
|
+
if exchange_token
|
83
|
+
options[:basic_auth] = { :username => exchange_token, :password => "x-2fa-basic" }
|
84
|
+
elsif password
|
107
85
|
options[:basic_auth] = { :username => username, :password => password }
|
108
86
|
elsif api_token
|
109
|
-
options[:headers][
|
87
|
+
options[:headers][HEADER_API_TOKEN] = "#{username}:#{api_token}"
|
110
88
|
else
|
111
89
|
raise Error, 'A password or API token is required for all API requests.'
|
112
90
|
end
|
@@ -133,8 +111,10 @@ module DNSimple
|
|
133
111
|
def self.request(method, path, options)
|
134
112
|
response = HTTParty.send(method, "#{base_uri}#{path}", base_options.merge(options))
|
135
113
|
|
136
|
-
if response.code == 401
|
137
|
-
raise
|
114
|
+
if response.code == 401 && response.headers[HEADER_OTP_TOKEN] == "required"
|
115
|
+
raise TwoFactorAuthenticationRequired, response["message"]
|
116
|
+
elsif response.code == 401
|
117
|
+
raise AuthenticationFailed, response["message"]
|
138
118
|
end
|
139
119
|
|
140
120
|
response
|
data/lib/dnsimple/error.rb
CHANGED
@@ -9,13 +9,24 @@ module DNSimple
|
|
9
9
|
class RecordNotFound < Error
|
10
10
|
end
|
11
11
|
|
12
|
+
# An exception that is raised if a method is called with missing or invalid parameter values.
|
13
|
+
class ValidationError < Error
|
14
|
+
end
|
15
|
+
|
12
16
|
class RequestError < Error
|
13
17
|
def initialize(description, response)
|
14
18
|
super("#{description}: #{response["error"]}")
|
15
19
|
end
|
16
20
|
end
|
17
21
|
|
18
|
-
class
|
22
|
+
class AuthenticationError < Error
|
23
|
+
end
|
24
|
+
|
25
|
+
class AuthenticationFailed < AuthenticationError
|
26
|
+
end
|
27
|
+
|
28
|
+
# An exception that is raised if a request is executed for an account that requires two-factor authentication.
|
29
|
+
class TwoFactorAuthenticationRequired < AuthenticationError
|
19
30
|
end
|
20
31
|
|
21
32
|
end
|
data/lib/dnsimple/user.rb
CHANGED
@@ -11,6 +11,10 @@ module DNSimple
|
|
11
11
|
attr_accessor :updated_at
|
12
12
|
|
13
13
|
|
14
|
+
# Gets the information about the authenticated user.
|
15
|
+
#
|
16
|
+
# @return [User] the authenticated user
|
17
|
+
# @raise [RequestError] if the user doesn't exist
|
14
18
|
def self.me
|
15
19
|
response = DNSimple::Client.get("/v1/user")
|
16
20
|
|
@@ -22,5 +26,26 @@ module DNSimple
|
|
22
26
|
end
|
23
27
|
end
|
24
28
|
|
29
|
+
# Requests a new two-factor authentication exchange token.
|
30
|
+
#
|
31
|
+
# The exchange-token is required to validate API requests
|
32
|
+
# using HTTP Basic Authentication when the account has two-factor authentication enabled.
|
33
|
+
#
|
34
|
+
# @see http://developer.dnsimple.com/authentication/#twofa
|
35
|
+
#
|
36
|
+
# @example Request an Exchange Token
|
37
|
+
#
|
38
|
+
# DNSimple::User.two_factor_exchange_token('0000000')
|
39
|
+
# # => "cda038832591e34f5df642ce2b61dc78"
|
40
|
+
#
|
41
|
+
# @param [String] otp_token the two-factor one time (OTP) token
|
42
|
+
#
|
43
|
+
# @return [String] the two-factor API exchange token
|
44
|
+
# @raise [AuthenticationFailed] if the provided OTP token is invalid
|
45
|
+
def self.two_factor_exchange_token(otp_token)
|
46
|
+
response = DNSimple::Client.get("/v1/user", :headers => { DNSimple::Client::HEADER_2FA_STRICT => "1", DNSimple::Client::HEADER_OTP_TOKEN => otp_token })
|
47
|
+
response.headers[DNSimple::Client::HEADER_EXCHANGE_TOKEN]
|
48
|
+
end
|
49
|
+
|
25
50
|
end
|
26
51
|
end
|
data/lib/dnsimple/version.rb
CHANGED
@@ -29,10 +29,15 @@ describe DNSimple::Client do
|
|
29
29
|
end
|
30
30
|
|
31
31
|
describe ".request" do
|
32
|
+
before do
|
33
|
+
[:username, :password, :exchange_token, :api_token].each do |attribute|
|
34
|
+
described_class.send("#{attribute}=", nil)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
32
38
|
it "uses HTTP authentication if there's a password provided" do
|
33
39
|
described_class.username = 'user'
|
34
40
|
described_class.password = 'pass'
|
35
|
-
described_class.api_token = nil
|
36
41
|
described_class.base_uri = 'https://api.example.com/'
|
37
42
|
|
38
43
|
HTTParty.expects(:get).
|
@@ -44,7 +49,6 @@ describe DNSimple::Client do
|
|
44
49
|
|
45
50
|
it "uses header authentication if there's an api token provided" do
|
46
51
|
described_class.username = 'user'
|
47
|
-
described_class.password = nil
|
48
52
|
described_class.api_token = 'token'
|
49
53
|
described_class.base_uri = 'https://api.example.com/'
|
50
54
|
|
@@ -55,10 +59,21 @@ describe DNSimple::Client do
|
|
55
59
|
described_class.request(:get, '/domains', {})
|
56
60
|
end
|
57
61
|
|
62
|
+
it "uses HTTP authentication via exchange token if there's an exchange token provided" do
|
63
|
+
described_class.username = 'user'
|
64
|
+
described_class.password = 'pass'
|
65
|
+
described_class.exchange_token = 'exchange-token'
|
66
|
+
described_class.base_uri = 'https://api.example.com/'
|
67
|
+
|
68
|
+
HTTParty.expects(:get).
|
69
|
+
with('https://api.example.com/domains', has_entries(:basic_auth => { :username => 'exchange-token', :password => 'x-2fa-basic' })).
|
70
|
+
returns(response)
|
71
|
+
|
72
|
+
described_class.request(:get, '/domains', {})
|
73
|
+
end
|
74
|
+
|
58
75
|
it "raises an error if there's no password or api token provided" do
|
59
76
|
described_class.username = 'user'
|
60
|
-
described_class.password = nil
|
61
|
-
described_class.api_token = nil
|
62
77
|
described_class.base_uri = 'https://api.example.com/'
|
63
78
|
|
64
79
|
expect {
|
@@ -67,6 +82,8 @@ describe DNSimple::Client do
|
|
67
82
|
end
|
68
83
|
|
69
84
|
it "adds a custom user-agent" do
|
85
|
+
described_class.api_token = 'token'
|
86
|
+
|
70
87
|
HTTParty.expects(:get).
|
71
88
|
with(is_a(String), has_entries(:headers => has_entries({ 'User-Agent' => "dnsimple-ruby/#{DNSimple::VERSION}" }))).
|
72
89
|
returns(response)
|
@@ -75,12 +92,15 @@ describe DNSimple::Client do
|
|
75
92
|
end
|
76
93
|
|
77
94
|
it "performs a request" do
|
95
|
+
described_class.username = 'user'
|
96
|
+
described_class.password = 'pass'
|
97
|
+
|
78
98
|
HTTParty.expects(:get).
|
79
99
|
with("#{described_class.base_uri}/foo",
|
80
100
|
:format => :json,
|
81
101
|
:basic_auth => { :username => described_class.username, :password => described_class.password },
|
82
102
|
:headers => { 'Accept' => 'application/json', 'User-Agent' => "dnsimple-ruby/#{DNSimple::VERSION}" }
|
83
|
-
|
103
|
+
).
|
84
104
|
returns(response)
|
85
105
|
|
86
106
|
described_class.request(:get, '/foo', {})
|
@@ -104,4 +124,20 @@ describe DNSimple::Client do
|
|
104
124
|
end
|
105
125
|
end
|
106
126
|
|
127
|
+
|
128
|
+
describe "authentication" do
|
129
|
+
context "when 2FA is required" do
|
130
|
+
before do
|
131
|
+
stub_request(:get, %r[/foo]).
|
132
|
+
to_return(read_fixture("2fa/error-required.http"))
|
133
|
+
end
|
134
|
+
|
135
|
+
it "raises a TwoFactorAuthenticationRequired error" do
|
136
|
+
expect {
|
137
|
+
described_class.get('/foo', {})
|
138
|
+
}.to raise_error(DNSimple::TwoFactorAuthenticationRequired)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
107
143
|
end
|
@@ -40,7 +40,7 @@ describe DNSimple::Domain do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
describe "#enable_auto_renew" do
|
43
|
-
let(:domain) { described_class.new(name
|
43
|
+
let(:domain) { described_class.new(:name => 'example.com', :auto_renew => false) }
|
44
44
|
|
45
45
|
context "when response is not 200" do
|
46
46
|
before do
|
@@ -54,7 +54,7 @@ describe DNSimple::Domain do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
context "when auto_renew is true" do
|
57
|
-
let(:domain) { described_class.new(name
|
57
|
+
let(:domain) { described_class.new(:name => 'example.com', :auto_renew => true) }
|
58
58
|
|
59
59
|
it "does not send a web request" do
|
60
60
|
domain.enable_auto_renew
|
@@ -63,7 +63,7 @@ describe DNSimple::Domain do
|
|
63
63
|
end
|
64
64
|
|
65
65
|
context "when auto_renew is false" do
|
66
|
-
let(:domain) { described_class.new(name
|
66
|
+
let(:domain) { described_class.new(:name => 'example.com', :auto_renew => false) }
|
67
67
|
|
68
68
|
before do
|
69
69
|
stub_request(:post, %r[/v1/domains/example.com/auto_renewal]).
|
@@ -86,7 +86,7 @@ describe DNSimple::Domain do
|
|
86
86
|
end
|
87
87
|
|
88
88
|
describe "#disable_auto_renew" do
|
89
|
-
let(:domain) { described_class.new(name
|
89
|
+
let(:domain) { described_class.new(:name => 'example.com', :auto_renew => true) }
|
90
90
|
|
91
91
|
context "when response is not 200" do
|
92
92
|
before do
|
@@ -100,7 +100,7 @@ describe DNSimple::Domain do
|
|
100
100
|
end
|
101
101
|
|
102
102
|
context "when auto_renew is false" do
|
103
|
-
let(:domain) { described_class.new(name
|
103
|
+
let(:domain) { described_class.new(:name => 'example.com', :auto_renew => false) }
|
104
104
|
|
105
105
|
it "does not send a web request" do
|
106
106
|
domain.disable_auto_renew
|
@@ -109,7 +109,7 @@ describe DNSimple::Domain do
|
|
109
109
|
end
|
110
110
|
|
111
111
|
context "when auto_renew is true" do
|
112
|
-
let(:domain) { described_class.new(name
|
112
|
+
let(:domain) { described_class.new(:name => 'example.com', :auto_renew => true) }
|
113
113
|
|
114
114
|
before do
|
115
115
|
stub_request(:delete, %r[/v1/domains/example.com/auto_renewal]).
|
data/spec/dnsimple/user_spec.rb
CHANGED
@@ -28,4 +28,43 @@ describe DNSimple::User do
|
|
28
28
|
expect(result.updated_at).to be_a(String)
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
32
|
+
describe ".two_factor_exchange_token" do
|
33
|
+
before do
|
34
|
+
stub_request(:get, %r[/v1/user]).
|
35
|
+
to_return(read_fixture("2fa/exchange-token.http"))
|
36
|
+
end
|
37
|
+
|
38
|
+
let(:otp_token) { '1234567' }
|
39
|
+
|
40
|
+
it "builds the correct request" do
|
41
|
+
described_class.two_factor_exchange_token(otp_token)
|
42
|
+
|
43
|
+
expect(WebMock).to have_requested(:get, "https://#{CONFIG['username']}:#{CONFIG['password']}@#{CONFIG['host']}/v1/user").
|
44
|
+
# workaround for https://github.com/bblimke/webmock/issues/276
|
45
|
+
with do |req|
|
46
|
+
req.headers['Accept'] == 'application/json' &&
|
47
|
+
req.headers[DNSimple::CLient::HEADER_OTP_TOKEN] == otp_token
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "returns the exchange_token" do
|
52
|
+
result = described_class.two_factor_exchange_token(otp_token)
|
53
|
+
|
54
|
+
expect(result).to eq("0c622716aaa64124219963075bc1c870")
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when the OTP token is invalid" do
|
58
|
+
before do
|
59
|
+
stub_request(:get, %r[/v1/user]).
|
60
|
+
to_return(read_fixture("2fa/error-badtoken.http"))
|
61
|
+
end
|
62
|
+
|
63
|
+
it "raises an AuthenticationFailed" do
|
64
|
+
expect {
|
65
|
+
described_class.two_factor_exchange_token("invalid-token")
|
66
|
+
}.to raise_error(DNSimple::AuthenticationFailed, "Bad OTP token")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
31
70
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
HTTP/1.1 401 Unauthorized
|
2
|
+
Server: nginx
|
3
|
+
Date: Fri, 19 Sep 2014 10:20:23 GMT
|
4
|
+
Content-Type: application/json; charset=utf-8
|
5
|
+
Transfer-Encoding: chunked
|
6
|
+
Connection: close
|
7
|
+
Status: 401 Unauthorized
|
8
|
+
Strict-Transport-Security: max-age=631138519
|
9
|
+
X-Frame-Options: SAMEORIGIN
|
10
|
+
X-XSS-Protection: 1
|
11
|
+
X-Content-Type-Options: nosniff
|
12
|
+
X-UA-Compatible: chrome=1
|
13
|
+
Access-Control-Allow-Origin: *
|
14
|
+
Access-Control-Allow-Headers: Authorization,Accepts,Content-Type,X-DNSimple-Token,X-DNSimple-Domain-Token,X-CSRF-Token,x-requested-with
|
15
|
+
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
|
16
|
+
Cache-Control: no-cache
|
17
|
+
Set-Cookie: user_credentials=f53d51039d1ac35e3398b604cb8eb8b8ecc085b69e76e6a8b41bf9b758380b97be2c65ba3124b1d5f8fc9dbeef9690386bdc5ccd775f0494a1a5a1edb5d98521; path=/; expires=Sat, 19 Sep 2015 10:20:23 -0000; secure
|
18
|
+
Set-Cookie: _dnsimple_session=MEM4ak83V0lDeVV6YnA1L2JPbG90cDExelZ6REF6dTNMR0NLejN1VG85WkphdU9FUDBvRmxUSnhlTGxGdmhOOXhiamtBQW1SYU9NSU9KUlV5SG5lTzlDS2N0dCtuay9mem5vL2ZxUzdFL2VpVDNMS0dwOVQxdWc3QmtYcWpLQXQ1NDE3UmpUeEZiMmwwTVlxdmJZQVU3UDYrbmJ3RnhDODBnZE5MWVJKekY5MFdoN2h0UVFQUmZzY204N1pTS1VpV2FZNWdZVlNENDJ3cThyZUx3U2l2NFN2eWx1UEZSVkNtTXdTUitxZG04VDBmZzErTmtvN1BPMmlRVGdiTW5mTXdVR0Jlb2V1RWxaS0xlU3NpNFlrUzdERDRCNzRRTnFLZ2Q1bS95WXM4M3M9LS1FdGpHYWlKRUlyVmhHYXZic3JIM3lnPT0%3D--8081ac131a8acf29688505a8b2a8224d0fd76ce5; path=/; HttpOnly; secure
|
19
|
+
X-Request-Id: 0567a347-9ea0-46cf-a73b-eb5b60bbe8bb
|
20
|
+
X-Runtime: 0.214109
|
21
|
+
|
22
|
+
{"message":"Bad OTP token"}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
HTTP/1.1 401 Unauthorized
|
2
|
+
Server: nginx
|
3
|
+
Date: Fri, 19 Sep 2014 10:33:42 GMT
|
4
|
+
Content-Type: application/json; charset=utf-8
|
5
|
+
Transfer-Encoding: chunked
|
6
|
+
Connection: close
|
7
|
+
Status: 401 Unauthorized
|
8
|
+
Strict-Transport-Security: max-age=631138519
|
9
|
+
X-Frame-Options: SAMEORIGIN
|
10
|
+
X-XSS-Protection: 1
|
11
|
+
X-Content-Type-Options: nosniff
|
12
|
+
X-UA-Compatible: chrome=1
|
13
|
+
Access-Control-Allow-Origin: *
|
14
|
+
Access-Control-Allow-Headers: Authorization,Accepts,Content-Type,X-DNSimple-Token,X-DNSimple-Domain-Token,X-CSRF-Token,x-requested-with
|
15
|
+
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
|
16
|
+
X-DNSimple-OTP: required
|
17
|
+
Cache-Control: no-cache
|
18
|
+
Set-Cookie: user_credentials=4ef7ff0d7228ea953f77be4044941c0f7e9c5e308e3b2c778dd175b0dd0d95eb032cef4334c6c3a7023e0e4754e2aea3133f44aa663d760f78997d97bde9336f; path=/; expires=Sat, 19 Sep 2015 10:33:42 -0000; secure
|
19
|
+
Set-Cookie: _dnsimple_session=TXFabkRHZlZyaWQvOEVMc09PU3RCckR4cVBDeXZrczRwOStMbkJiZnRjMWIzV3R1NzdubktHdU1pNlEyVVJ4SDNlODBNcUo0VzN5VmhsdWxTU1dwUUhXbXJhNk1tOUNpWUNUdlZ3NFVJd2cydVFWdFJGT0s4OExZd1NNS0lEeVdYSW0venA1WFpjVnhYN0NzNUlEdFJBS2NnSmY0ZHFJaG5UTitST2prTXBrVmpBYUlFNEkzZVUxeU1kVGN4aXlMMHhRMFI1MlRVNSs2SXpLd0Uyb3VleG5KODh1TEJvdG5rN2tXWGtjeEIxM3AzWmRrc052TmRsdEcvLzdwZ1hvK014OXpKM1N2YkNmaVppbDdMWWRNOXE4cERuU2l4c3lwWmNOYjgxVXlOOUE9LS15aXY1ekg4WTZlMDRtTGIyZ0JFanJRPT0%3D--8c7111719b56998a6343d0b8dc68d5607d6c05bf; path=/; HttpOnly; secure
|
20
|
+
X-Request-Id: 58e56818-4804-4452-b255-0650552a24cc
|
21
|
+
X-Runtime: 0.212325
|
22
|
+
|
23
|
+
{"message":"2FA Authentication failed"}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Server: nginx
|
3
|
+
Date: Fri, 19 Sep 2014 10:59:16 GMT
|
4
|
+
Content-Type: application/json; charset=utf-8
|
5
|
+
Transfer-Encoding: chunked
|
6
|
+
Connection: close
|
7
|
+
Status: 200 OK
|
8
|
+
Strict-Transport-Security: max-age=631138519
|
9
|
+
X-Frame-Options: SAMEORIGIN
|
10
|
+
X-XSS-Protection: 1
|
11
|
+
X-Content-Type-Options: nosniff
|
12
|
+
X-UA-Compatible: chrome=1
|
13
|
+
Access-Control-Allow-Origin: *
|
14
|
+
Access-Control-Allow-Headers: Authorization,Accepts,Content-Type,X-DNSimple-Token,X-DNSimple-Domain-Token,X-CSRF-Token,x-requested-with
|
15
|
+
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
|
16
|
+
X-DNSimple-OTP-Token: 0c622716aaa64124219963075bc1c870
|
17
|
+
ETag: "8f991ac7debfbe00277cb74b6d41c9a4"
|
18
|
+
Cache-Control: max-age=0, private, must-revalidate
|
19
|
+
Set-Cookie: user_credentials=5a9961782864b9d0601fedf748aaafaa009a8468d6864b5e648b65b0a4c05547d17a07bf162c9610efb422824633563a74e2e2bf58a0d4627bb5ddcb7fe07014; path=/; expires=Sat, 19 Sep 2015 10:59:16 -0000; secure
|
20
|
+
Set-Cookie: _dnsimple_session=OG0rMmJZSHVZWDNuMXd5Rjk4SGxPMU8zRjlrbWkydW44ek00bXRDSkhpUTA3ZkZzUWVsenlXMjcyWk93ZFhCRjZXejdpSTNrZWxqdE9DUFVqckg0YU13cTNFcVJVTnU1VTVTYjRZNHRWdGV3QmpXYlFEUlhRVDRrZHFPZXovMU9pUmhYTG16UXBTbjRoeWtBUVJudytUVmpaU2NFdDFDQlE2QTRFRXBwSEI2V1lCRnJ3Zmx3RUVYWVM0THN1WlIySkJtTkYwRG5CcC9CK2RzeXpMU2hxcWpMTld5OThPSWxmSHpWNXdEUFRFWnFHRktZSktlZkRGNEdIS2llN25aZkhxWTh4Q0w2UUREemNYTDNIMm1yLzQvTU5WUk1RSTgwTE1la3A2Vk1jeXc9LS03dml0dCtLWUx5MFRLa3phRWxNRmt3PT0%3D--6cbcdf7e930eb4343b632553396dfb6ee0ee04e6; path=/; HttpOnly; secure
|
21
|
+
X-Request-Id: 7e658b27-a46f-42bc-acb7-56fc94a5a623
|
22
|
+
X-Runtime: 0.437686
|
23
|
+
Strict-Transport-Security: max-age=315360000
|
24
|
+
|
25
|
+
{"user":{"id":19,"email":"example@example.com","referral_token":"ad932ffb60c295","single_access_token":"hZ1P7jz1V0u6g0MMv0pL","domain_count":2,"domain_limit":10,"login_count":1,"failed_login_count":0,"created_at":"2014-01-15T21:59:04.104Z","updated_at":"2014-09-19T10:59:16.231Z","first_name":null,"last_name":null,"default_contact_id":null}}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dnsimple-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anthony Eden
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -233,6 +233,9 @@ files:
|
|
233
233
|
- spec/dnsimple/record_spec.rb
|
234
234
|
- spec/dnsimple/template_spec.rb
|
235
235
|
- spec/dnsimple/user_spec.rb
|
236
|
+
- spec/files/2fa/error-badtoken.http
|
237
|
+
- spec/files/2fa/error-required.http
|
238
|
+
- spec/files/2fa/exchange-token.http
|
236
239
|
- spec/files/account/user/success.http
|
237
240
|
- spec/files/certificates/index/success.http
|
238
241
|
- spec/files/certificates/show/notfound.http
|
@@ -311,6 +314,9 @@ test_files:
|
|
311
314
|
- spec/dnsimple/record_spec.rb
|
312
315
|
- spec/dnsimple/template_spec.rb
|
313
316
|
- spec/dnsimple/user_spec.rb
|
317
|
+
- spec/files/2fa/error-badtoken.http
|
318
|
+
- spec/files/2fa/error-required.http
|
319
|
+
- spec/files/2fa/exchange-token.http
|
314
320
|
- spec/files/account/user/success.http
|
315
321
|
- spec/files/certificates/index/success.http
|
316
322
|
- spec/files/certificates/show/notfound.http
|