authy 2.7.5 → 3.0.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/build.yml +21 -0
- data/.gitignore +1 -0
- data/CHANGELOG.md +18 -0
- data/Gemfile +1 -11
- data/README.md +39 -195
- data/authy.gemspec +0 -2
- data/examples/Gemfile +6 -0
- data/examples/README.md +48 -0
- data/examples/demo.rb +23 -19
- data/lib/authy.rb +0 -2
- data/lib/authy/api.rb +64 -58
- data/lib/authy/onetouch.rb +1 -1
- data/lib/authy/phone_verification.rb +5 -2
- data/lib/authy/url_helpers.rb +0 -4
- data/lib/authy/version.rb +1 -1
- data/spec/authy/api_spec.rb +384 -91
- data/spec/authy/onetouch_spec.rb +86 -30
- data/spec/authy/phone_verification_spec.rb +185 -54
- data/spec/authy/url_helpers_spec.rb +0 -12
- data/spec/spec_helper.rb +1 -2
- data/verify-legacy-v1.md +35 -0
- metadata +8 -11
- data/.travis.yml +0 -12
- data/Gemfile.lock +0 -118
- data/examples/pv-check.rb +0 -9
- data/examples/pv.rb +0 -12
- data/lib/authy/core_ext.rb +0 -26
- data/lib/authy/phone_intelligence.rb +0 -23
- data/spec/authy/phone_intelligence_spec.rb +0 -94
data/lib/authy.rb
CHANGED
@@ -6,11 +6,9 @@ require 'json'
|
|
6
6
|
|
7
7
|
require 'authy/version'
|
8
8
|
require 'authy/url_helpers'
|
9
|
-
require 'authy/core_ext'
|
10
9
|
require 'authy/response'
|
11
10
|
require 'authy/models/user'
|
12
11
|
require 'authy/config'
|
13
12
|
require 'authy/api'
|
14
|
-
require 'authy/phone_intelligence'
|
15
13
|
require 'authy/phone_verification'
|
16
14
|
require 'authy/onetouch'
|
data/lib/authy/api.rb
CHANGED
@@ -1,12 +1,6 @@
|
|
1
|
-
require
|
1
|
+
require "logger"
|
2
2
|
|
3
3
|
module Authy
|
4
|
-
|
5
|
-
AUTHY_LOGGER = Logger.new(STDOUT)
|
6
|
-
#
|
7
|
-
# Authy.api_key = 'foo'
|
8
|
-
# Authy.api_uri = 'http://test-authy-api.heroku.com/'
|
9
|
-
#
|
10
4
|
class API
|
11
5
|
MIN_TOKEN_SIZE = 6
|
12
6
|
MAX_TOKEN_SIZE = 12
|
@@ -25,7 +19,7 @@ module Authy
|
|
25
19
|
}
|
26
20
|
|
27
21
|
url = "#{Authy.api_uri}/protected/json/users/new"
|
28
|
-
response = http_client.post(url, :body => escape_query(params), :header => default_header(api_key: api_key))
|
22
|
+
response = http_client.post(url, :body => escape_query(params), :header => default_header(params: { api_key: api_key }))
|
29
23
|
|
30
24
|
Authy::User.new(response)
|
31
25
|
end
|
@@ -36,19 +30,18 @@ module Authy
|
|
36
30
|
# :force (true|false) force to check even if the cellphone is not confirmed
|
37
31
|
#
|
38
32
|
def self.verify(params)
|
39
|
-
token = params.delete(:token) || params.delete(
|
40
|
-
user_id = params.delete(:id) || params.delete(
|
33
|
+
token = params.delete(:token) || params.delete("token")
|
34
|
+
user_id = params.delete(:id) || params.delete("id")
|
41
35
|
|
42
|
-
return invalid_response(
|
43
|
-
return invalid_response(
|
36
|
+
return invalid_response("Token format is invalid") unless token_is_safe?(token)
|
37
|
+
return invalid_response("User id is invalid") unless is_digit?(user_id)
|
44
38
|
|
45
|
-
params[:force] = true if params[:force].nil? && params[
|
39
|
+
params[:force] = true if params[:force].nil? && params["force"].nil?
|
46
40
|
|
47
41
|
response = get_request("protected/json/verify/:token/:user_id", params.merge({
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
)
|
42
|
+
"token" => token,
|
43
|
+
"user_id" => user_id
|
44
|
+
}))
|
52
45
|
|
53
46
|
return verify_response(response) if response.ok?
|
54
47
|
return response
|
@@ -58,7 +51,7 @@ module Authy
|
|
58
51
|
# :id user id
|
59
52
|
# :force force sms
|
60
53
|
def self.request_sms(params)
|
61
|
-
user_id = params.delete(:id) || params.delete(
|
54
|
+
user_id = params.delete(:id) || params.delete("id")
|
62
55
|
|
63
56
|
get_request("protected/json/sms/:user_id", params.merge({"user_id" => user_id}))
|
64
57
|
end
|
@@ -68,14 +61,14 @@ module Authy
|
|
68
61
|
# :qr_size qr size
|
69
62
|
# :qr_label context for qr code
|
70
63
|
def self.request_qr_code(params)
|
71
|
-
user_id = params.delete(:id) || params.delete(
|
72
|
-
qr_size = params.delete(:qr_size) || params.delete(
|
73
|
-
qr_label = params.delete(:qr_label) || params.delete(
|
64
|
+
user_id = params.delete(:id) || params.delete("id")
|
65
|
+
qr_size = params.delete(:qr_size) || params.delete("qr_size") || 300
|
66
|
+
qr_label = params.delete(:qr_label) || params.delete("qr_label") || ""
|
74
67
|
|
75
|
-
return invalid_response(
|
76
|
-
return invalid_response(
|
68
|
+
return invalid_response("User id is invalid") unless is_digit?(user_id)
|
69
|
+
return invalid_response("Qr image size is invalid") unless is_digit?(qr_size)
|
77
70
|
|
78
|
-
response = post_request("protected/json/users/:user_id/secret"
|
71
|
+
response = post_request("protected/json/users/:user_id/secret", params.merge({
|
79
72
|
"user_id" => user_id,
|
80
73
|
"qr_size" => qr_size,
|
81
74
|
"label" => qr_label
|
@@ -86,19 +79,38 @@ module Authy
|
|
86
79
|
# :id user id
|
87
80
|
# :force force phone_call
|
88
81
|
def self.request_phone_call(params)
|
89
|
-
user_id = params.delete(:id) || params.delete(
|
82
|
+
user_id = params.delete(:id) || params.delete("id")
|
90
83
|
|
91
84
|
get_request("protected/json/call/:user_id", params.merge({"user_id" => user_id}))
|
92
85
|
end
|
93
86
|
|
94
87
|
# options:
|
95
88
|
# :id user id
|
96
|
-
def self.
|
89
|
+
def self.request_email(params)
|
90
|
+
user_id = params.delete(:id) || params.delete('id')
|
91
|
+
|
92
|
+
post_request("protected/json/email/:user_id", params.merge({"user_id" => user_id}))
|
93
|
+
end
|
94
|
+
|
95
|
+
# options:
|
96
|
+
# :id user id
|
97
|
+
# :email user's new email
|
98
|
+
def self.update_user(params)
|
97
99
|
user_id = params.delete(:id) || params.delete('id')
|
98
100
|
|
99
|
-
post_request("protected/json/users
|
101
|
+
post_request("protected/json/users/:user_id/update", params.merge({"user_id" => user_id}))
|
100
102
|
end
|
101
103
|
|
104
|
+
# options:
|
105
|
+
# :id user id
|
106
|
+
def self.delete_user(params)
|
107
|
+
user_id = params.delete(:id) || params.delete("id")
|
108
|
+
|
109
|
+
post_request("protected/json/users/delete/:user_id", params.merge({"user_id" => user_id}))
|
110
|
+
end
|
111
|
+
|
112
|
+
# options:
|
113
|
+
# :id user id
|
102
114
|
def self.user_status(params)
|
103
115
|
user_id = params.delete(:id) || params.delete("id")
|
104
116
|
get_request("protected/json/users/:user_id/status", params.merge({"user_id" => user_id}))
|
@@ -113,12 +125,12 @@ module Authy
|
|
113
125
|
state, error = validate_for_url(uri_params, params)
|
114
126
|
|
115
127
|
response = if state
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
128
|
+
url = "#{Authy.api_uri}/#{eval_uri(uri, params)}"
|
129
|
+
params = clean_uri_params(uri_params, params)
|
130
|
+
http_client.post(url, :body => escape_query(params), header: header_)
|
131
|
+
else
|
132
|
+
build_error_response(error)
|
133
|
+
end
|
122
134
|
Authy::Response.new(response)
|
123
135
|
end
|
124
136
|
|
@@ -128,24 +140,24 @@ module Authy
|
|
128
140
|
uri_params = keys_to_verify(uri, params)
|
129
141
|
state, error = validate_for_url(uri_params, params)
|
130
142
|
response = if state
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
143
|
+
url = "#{Authy.api_uri}/#{eval_uri(uri, params)}"
|
144
|
+
params = clean_uri_params(uri_params, params)
|
145
|
+
http_client.get(url, params, header_)
|
146
|
+
else
|
147
|
+
build_error_response(error)
|
148
|
+
end
|
137
149
|
Authy::Response.new(response)
|
138
150
|
end
|
139
151
|
|
140
152
|
def self.build_error_response(error = "blank uri param found")
|
141
153
|
OpenStruct.new({
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
}
|
154
|
+
"status" => 400,
|
155
|
+
"body" => {
|
156
|
+
"success" => false,
|
157
|
+
"message" => error,
|
158
|
+
"errors" => {
|
159
|
+
"message" => error,
|
160
|
+
},
|
149
161
|
}.to_json
|
150
162
|
})
|
151
163
|
end
|
@@ -158,32 +170,26 @@ module Authy
|
|
158
170
|
!!(/^\d+$/.match str.to_s)
|
159
171
|
end
|
160
172
|
|
161
|
-
def self.invalid_response(str="Invalid resonse")
|
173
|
+
def self.invalid_response(str = "Invalid resonse")
|
162
174
|
response = build_error_response(str)
|
163
175
|
return Authy::Response.new(response)
|
164
176
|
end
|
165
177
|
|
166
178
|
def self.verify_response(response)
|
167
|
-
return response if response[
|
168
|
-
response = build_error_response(
|
179
|
+
return response if response["token"] == "is valid"
|
180
|
+
response = build_error_response("Token is invalid")
|
169
181
|
return Authy::Response.new(response)
|
170
182
|
end
|
171
183
|
|
172
|
-
def self.default_header(
|
184
|
+
def self.default_header(params: {})
|
185
|
+
api_key = params.delete(:api_key) || params.delete("api_key")
|
186
|
+
|
173
187
|
header = {
|
174
188
|
"X-Authy-API-Key" => api_key || Authy.api_key,
|
175
189
|
"User-Agent" => Authy.user_agent
|
176
190
|
}
|
177
191
|
|
178
|
-
api_key_ = params.delete(:api_key) || params.delete("api_key")
|
179
|
-
|
180
|
-
if api_key_ && api_key_.strip != ""
|
181
|
-
AUTHY_LOGGER.warn("[DEPRECATED]: The Authy API key should not be sent as a parameter. Please send the HTTP header 'X-Authy-API-Key' instead.")
|
182
|
-
header["X-Authy-API-Key"] = api_key_
|
183
|
-
end
|
184
|
-
|
185
192
|
return header
|
186
193
|
end
|
187
|
-
|
188
194
|
end
|
189
195
|
end
|
data/lib/authy/onetouch.rb
CHANGED
@@ -6,8 +6,11 @@ module Authy
|
|
6
6
|
# :phone_number The persons phone number.
|
7
7
|
# :custom_code Pass along any generated custom code.
|
8
8
|
# :custom_message Custom Message.
|
9
|
+
# :code_length Length of code to be sent(4-10).
|
10
|
+
# :locale The language of the message received by user.
|
9
11
|
def self.start(params)
|
10
|
-
|
12
|
+
warn "Authy Phone Verification has been superseded by the Twilio Verify API. Check https://twil.io/verify-start-ruby to see how to start a verification with the Twilio Verify API."
|
13
|
+
params[:via] = "sms" unless %w(sms call).include?(params[:via])
|
11
14
|
|
12
15
|
post_request("protected/json/phones/verification/start", params)
|
13
16
|
end
|
@@ -17,8 +20,8 @@ module Authy
|
|
17
20
|
# :phone_number The persons phone number.
|
18
21
|
# :verification_code The verification code entered by the user.
|
19
22
|
def self.check(params)
|
23
|
+
warn "Authy Phone Verification has been superseded by the Twilio Verify API. Check https://twil.io/verify-check-ruby to see how to check a verification the Twilio Verify API."
|
20
24
|
get_request("protected/json/phones/verification/check", params)
|
21
25
|
end
|
22
|
-
|
23
26
|
end
|
24
27
|
end
|
data/lib/authy/url_helpers.rb
CHANGED
@@ -30,10 +30,6 @@ module Authy
|
|
30
30
|
[ true, ""]
|
31
31
|
end
|
32
32
|
|
33
|
-
def escape_for_url(field)
|
34
|
-
URI.escape(field.to_s.strip, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
35
|
-
end
|
36
|
-
|
37
33
|
def to_param(left, right)
|
38
34
|
HTTP::Message.escape(left) + '=' + HTTP::Message.escape(right.to_s)
|
39
35
|
end
|
data/lib/authy/version.rb
CHANGED
data/spec/authy/api_spec.rb
CHANGED
@@ -1,9 +1,17 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class Utils
|
4
|
+
include Authy::URL
|
5
|
+
end
|
2
6
|
|
3
7
|
describe "Authy::API" do
|
8
|
+
let(:headers) { { "X-Authy-API-Key" => Authy.api_key, "User-Agent" => "AuthyRuby/#{Authy::VERSION} (#{RUBY_PLATFORM}, Ruby #{RUBY_VERSION})" } }
|
9
|
+
let(:user_id) { 81547 }
|
10
|
+
let(:invalid_api_key) { "invalid_api_key" }
|
11
|
+
|
4
12
|
describe "request headers" do
|
5
13
|
it "contains api key and user agent in header" do
|
6
|
-
expect_any_instance_of(HTTPClient).to receive(:request).twice.with(any_args, hash_including(header:
|
14
|
+
expect_any_instance_of(HTTPClient).to receive(:request).twice.with(any_args, hash_including(header: headers)) { double(ok?: true, body: "", status: 200) }
|
7
15
|
|
8
16
|
url = "protected/json/foo/2"
|
9
17
|
Authy::API.get_request(url, {})
|
@@ -12,50 +20,130 @@ describe "Authy::API" do
|
|
12
20
|
end
|
13
21
|
|
14
22
|
describe "Registering users" do
|
15
|
-
|
16
|
-
|
23
|
+
let(:register_user_url) { "#{Authy.api_uri}/protected/json/users/new" }
|
24
|
+
|
25
|
+
it "should register a user successfully" do
|
26
|
+
user_attributes = {
|
17
27
|
email: generate_email,
|
18
28
|
cellphone: generate_cellphone,
|
19
29
|
country_code: 1
|
20
|
-
|
30
|
+
}
|
31
|
+
response_json = {
|
32
|
+
"message" => "User created successfully.",
|
33
|
+
"user" => { "id" => user_id },
|
34
|
+
"success" => true
|
35
|
+
}.to_json
|
36
|
+
expect(Authy::API.http_client).to receive(:request)
|
37
|
+
.once
|
38
|
+
.with(:post, register_user_url, {
|
39
|
+
:body => Utils.escape_query(
|
40
|
+
:user => user_attributes,
|
41
|
+
:send_install_link_via_sms => true
|
42
|
+
),
|
43
|
+
:header => headers
|
44
|
+
})
|
45
|
+
.and_return(double(:status => 200, :body => response_json))
|
46
|
+
|
47
|
+
user = Authy::API.register_user(user_attributes)
|
21
48
|
|
22
49
|
expect(user).to be_kind_of(Authy::Response)
|
23
50
|
expect(user).to be_kind_of(Authy::User)
|
24
51
|
expect(user).to_not be_nil
|
25
52
|
expect(user.id).to_not be_nil
|
26
|
-
expect(user.id).to
|
53
|
+
expect(user.id).to be(user_id)
|
27
54
|
end
|
28
55
|
|
29
56
|
it "should return the error messages as a hash" do
|
30
|
-
|
57
|
+
user_attributes = {
|
31
58
|
email: generate_email,
|
32
59
|
cellphone: "abc-1234",
|
33
60
|
country_code: 1
|
34
|
-
|
61
|
+
}
|
62
|
+
response_json = {
|
63
|
+
"cellphone" => "is invalid",
|
64
|
+
"message" => "User was not valid",
|
65
|
+
"success" => false,
|
66
|
+
"errors" => {
|
67
|
+
"cellphone" => "is invalid",
|
68
|
+
"message" => "User was not valid"
|
69
|
+
},
|
70
|
+
"error_code" => "60027"
|
71
|
+
}.to_json
|
72
|
+
|
73
|
+
expect(Authy::API.http_client).to receive(:request)
|
74
|
+
.once
|
75
|
+
.with(:post, register_user_url, {
|
76
|
+
:body => Utils.escape_query(
|
77
|
+
:user => user_attributes,
|
78
|
+
:send_install_link_via_sms => true
|
79
|
+
),
|
80
|
+
:header => headers
|
81
|
+
})
|
82
|
+
.and_return(double(:status => 400, :body => response_json))
|
83
|
+
|
84
|
+
user = Authy::API.register_user(user_attributes)
|
35
85
|
|
36
86
|
expect(user.errors).to be_kind_of(Hash)
|
37
|
-
expect(user.errors[
|
87
|
+
expect(user.errors["cellphone"]).to include "is invalid"
|
38
88
|
end
|
39
89
|
|
40
90
|
it "should allow to override the API key" do
|
41
|
-
|
91
|
+
response_json = {
|
92
|
+
"error_code" => "60001",
|
93
|
+
"message" => "Invalid API key",
|
94
|
+
"errors" => {"message" => "Invalid API key"},
|
95
|
+
"success" => false
|
96
|
+
}.to_json
|
97
|
+
user_attributes = {
|
42
98
|
email: generate_email,
|
43
99
|
cellphone: generate_cellphone,
|
44
100
|
country_code: 1,
|
45
|
-
api_key:
|
46
|
-
|
101
|
+
api_key: invalid_api_key
|
102
|
+
}
|
103
|
+
|
104
|
+
headers["X-Authy-API-Key"] = invalid_api_key
|
105
|
+
|
106
|
+
expect(Authy::API.http_client).to receive(:request)
|
107
|
+
.once
|
108
|
+
.with(:post, register_user_url, {
|
109
|
+
:body => Utils.escape_query(
|
110
|
+
:user => user_attributes.reject { |k,v| k === :api_key },
|
111
|
+
:send_install_link_via_sms => true
|
112
|
+
),
|
113
|
+
:header => headers
|
114
|
+
})
|
115
|
+
.and_return(double(:status => 401, :body => response_json))
|
116
|
+
|
117
|
+
user = Authy::API.register_user(user_attributes)
|
47
118
|
|
48
119
|
expect(user).to_not be_ok
|
49
|
-
expect(user.errors[
|
120
|
+
expect(user.errors["message"]).to match(/invalid api key/i)
|
50
121
|
end
|
51
122
|
|
52
123
|
it "should allow overriding send_install_link_via_sms default" do
|
53
|
-
|
124
|
+
response_json = {
|
125
|
+
"message" => "User created successfully.",
|
126
|
+
"user" => { "id" => user_id },
|
127
|
+
"success" => true
|
128
|
+
}.to_json
|
129
|
+
user_attributes = {
|
54
130
|
email: generate_email,
|
55
131
|
cellphone: generate_cellphone,
|
56
132
|
country_code: 1,
|
57
|
-
send_install_link_via_sms: false
|
58
|
-
|
133
|
+
send_install_link_via_sms: false
|
134
|
+
}
|
135
|
+
expect(Authy::API.http_client).to receive(:request)
|
136
|
+
.once
|
137
|
+
.with(:post, register_user_url, {
|
138
|
+
:body => Utils.escape_query(
|
139
|
+
:user => user_attributes.reject { |k,v| k === :send_install_link_via_sms },
|
140
|
+
:send_install_link_via_sms => false
|
141
|
+
),
|
142
|
+
:header => headers
|
143
|
+
})
|
144
|
+
.and_return(double(:status => 200, :body => response_json))
|
145
|
+
|
146
|
+
user = Authy::API.register_user(user_attributes)
|
59
147
|
|
60
148
|
expect(user).to be_kind_of(Authy::Response)
|
61
149
|
expect(user).to be_kind_of(Authy::User)
|
@@ -63,90 +151,98 @@ describe "Authy::API" do
|
|
63
151
|
expect(user.id).to_not be_nil
|
64
152
|
expect(user.id).to be_kind_of(Integer)
|
65
153
|
end
|
66
|
-
|
67
154
|
end
|
68
155
|
|
69
|
-
describe "
|
70
|
-
|
71
|
-
|
72
|
-
@cellphone = generate_cellphone
|
73
|
-
@user = Authy::API.register_user(
|
74
|
-
email: @email,
|
75
|
-
cellphone: @cellphone,
|
76
|
-
country_code: 1
|
77
|
-
)
|
78
|
-
expect(@user).to be_ok
|
79
|
-
end
|
156
|
+
describe "verifying tokens" do
|
157
|
+
let(:token) { "123456" }
|
158
|
+
let(:verify_url) { "#{Authy.api_uri}/protected/json/verify/#{token}/#{user_id}" }
|
80
159
|
|
81
|
-
it "should fail to validate a given token if the
|
82
|
-
|
160
|
+
it "should fail to validate a given token if the token is the wrong format" do
|
161
|
+
expect(Authy::API.http_client).to receive(:request).never
|
162
|
+
response = Authy::API.verify(token: "invalid_token", id: user_id)
|
83
163
|
|
84
164
|
expect(response).to be_kind_of(Authy::Response)
|
85
165
|
expect(response.ok?).to be_falsey
|
86
|
-
expect(response.errors[
|
166
|
+
expect(response.errors["message"]).to include "Token format is invalid"
|
87
167
|
end
|
88
168
|
|
89
169
|
it "should allow to override the API key" do
|
90
|
-
|
170
|
+
response_json = {
|
171
|
+
"error_code" => "60001",
|
172
|
+
"message" => "Invalid API key",
|
173
|
+
"errors" => {"message" => "Invalid API key"},
|
174
|
+
"success" => false
|
175
|
+
}.to_json
|
176
|
+
headers["X-Authy-API-Key"] = invalid_api_key
|
177
|
+
expect(Authy::API.http_client).to receive(:request)
|
178
|
+
.once
|
179
|
+
.with(:get, verify_url, {
|
180
|
+
:query => { :force => true },
|
181
|
+
:header => headers,
|
182
|
+
:follow_redirect => nil
|
183
|
+
})
|
184
|
+
.and_return(double(:status => 401, :body => response_json))
|
185
|
+
|
186
|
+
response = Authy::API.verify(token: "123456", id: user_id, api_key: invalid_api_key)
|
91
187
|
|
92
188
|
expect(response).to_not be_ok
|
93
|
-
expect(response.errors[
|
189
|
+
expect(response.errors["message"]).to match(/invalid api key/i)
|
94
190
|
end
|
95
191
|
|
96
192
|
it "should escape the params" do
|
193
|
+
expect(Authy::API.http_client).to receive(:request).never
|
97
194
|
expect do
|
98
|
-
Authy::API.verify(token:
|
195
|
+
Authy::API.verify(token: "[=#%@$&#(!@);.,", id: user_id)
|
99
196
|
end.to_not raise_error
|
100
197
|
end
|
101
198
|
|
102
199
|
it "should escape the params if have white spaces" do
|
200
|
+
expect(Authy::API.http_client).to receive(:request).never
|
103
201
|
expect do
|
104
|
-
Authy::API.verify(token: "token with space", id:
|
202
|
+
Authy::API.verify(token: "token with space", id: user_id)
|
105
203
|
end.to_not raise_error
|
106
204
|
end
|
107
205
|
|
108
206
|
it "should fail if a param is missing" do
|
109
|
-
|
207
|
+
expect(Authy::API.http_client).to receive(:request).never
|
208
|
+
response = Authy::API.verify(id: user_id)
|
110
209
|
expect(response).to be_kind_of(Authy::Response)
|
111
210
|
expect(response).to_not be_ok
|
112
|
-
expect(response["message"]).to include(
|
211
|
+
expect(response["message"]).to include("Token format is invalid")
|
113
212
|
end
|
114
213
|
|
115
|
-
it
|
116
|
-
|
214
|
+
it "fails when token format is invalid" do
|
215
|
+
expect(Authy::API.http_client).to receive(:request).never
|
216
|
+
response = Authy::API.verify(token: "0000", id: user_id)
|
117
217
|
|
118
218
|
expect(response.ok?).to be_falsey
|
119
219
|
expect(response).to be_kind_of(Authy::Response)
|
120
|
-
expect(response.errors[
|
220
|
+
expect(response.errors["message"]).to eq "Token format is invalid"
|
121
221
|
end
|
122
222
|
end
|
123
223
|
|
124
224
|
describe "requesting qr code for other authenticator apps" do
|
125
|
-
before do
|
126
|
-
@user = Authy::API.register_user(email: generate_email, cellphone: generate_cellphone, country_code: 1)
|
127
|
-
expect(@user).to be_ok
|
128
|
-
end
|
129
|
-
|
130
225
|
it "should request qrcode" do
|
131
|
-
url = "#{Authy.api_uri}/protected/json/users/#{
|
132
|
-
expect_any_instance_of(HTTPClient).to receive(:request).with(:post, url, body: "qr_size=300&label=example+app+name", header: {"X-Authy-API-Key" => Authy.api_key, "User-Agent" => "AuthyRuby/#{Authy::VERSION} (#{RUBY_PLATFORM}, Ruby #{RUBY_VERSION})"}) { double(ok?: true, body: "", status: 200) }
|
133
|
-
response = Authy::API.send("request_qr_code", id:
|
226
|
+
url = "#{Authy.api_uri}/protected/json/users/#{user_id}/secret"
|
227
|
+
expect_any_instance_of(HTTPClient).to receive(:request).with(:post, url, body: "qr_size=300&label=example+app+name", header: { "X-Authy-API-Key" => Authy.api_key, "User-Agent" => "AuthyRuby/#{Authy::VERSION} (#{RUBY_PLATFORM}, Ruby #{RUBY_VERSION})" }) { double(ok?: true, body: "", status: 200) }
|
228
|
+
response = Authy::API.send("request_qr_code", id: user_id, qr_size: 300, qr_label: "example app name")
|
134
229
|
expect(response).to be_ok
|
135
230
|
end
|
136
231
|
|
137
|
-
|
138
232
|
context "user id is not a number" do
|
139
233
|
it "should not be ok" do
|
234
|
+
expect(Authy::API.http_client).to receive(:request).never
|
140
235
|
response = Authy::API.send("request_qr_code", id: "tony")
|
141
|
-
expect(response.errors[
|
236
|
+
expect(response.errors["message"]).to eq "User id is invalid"
|
142
237
|
expect(response).to_not be_ok
|
143
238
|
end
|
144
239
|
end
|
145
240
|
|
146
241
|
context "qr size is not a number" do
|
147
242
|
it "should return the right error" do
|
148
|
-
|
149
|
-
|
243
|
+
expect(Authy::API.http_client).to receive(:request).never
|
244
|
+
response = Authy::API.send("request_qr_code", id: user_id, qr_size: "notanumber")
|
245
|
+
expect(response.errors["message"]).to eq "Qr image size is invalid"
|
150
246
|
expect(response).to_not be_ok
|
151
247
|
end
|
152
248
|
end
|
@@ -155,58 +251,212 @@ describe "Authy::API" do
|
|
155
251
|
["sms", "phone_call"].each do |kind|
|
156
252
|
title = kind.upcase
|
157
253
|
describe "Requesting #{title}" do
|
158
|
-
|
159
|
-
|
160
|
-
expect(@user).to be_ok
|
161
|
-
end
|
254
|
+
let(:uri_param) { kind == "phone_call" ? "call" : kind }
|
255
|
+
let(:url) { "#{Authy.api_uri}/protected/json/#{uri_param}/#{user_id}" }
|
162
256
|
|
163
257
|
it "should request a #{title} token" do
|
164
|
-
|
165
|
-
|
166
|
-
expect_any_instance_of(HTTPClient).to receive(:request).with(:get, url, {query:{}, header:{ "X-Authy-API-Key" => Authy.api_key, "User-Agent" => "AuthyRuby/#{Authy::VERSION} (#{RUBY_PLATFORM}, Ruby #{RUBY_VERSION})" }, follow_redirect:nil}) { double(ok?: true, body: "", status: 200) }
|
167
|
-
response = Authy::API.send("request_#{kind}", id: @user.id)
|
258
|
+
expect_any_instance_of(HTTPClient).to receive(:request).with(:get, url, { query: {}, header: { "X-Authy-API-Key" => Authy.api_key, "User-Agent" => "AuthyRuby/#{Authy::VERSION} (#{RUBY_PLATFORM}, Ruby #{RUBY_VERSION})" }, follow_redirect: nil }) { double(ok?: true, body: "", status: 200) }
|
259
|
+
response = Authy::API.send("request_#{kind}", id: user_id)
|
168
260
|
expect(response).to be_ok
|
169
261
|
end
|
170
262
|
|
171
263
|
it "should allow to override the API key" do
|
172
|
-
|
264
|
+
response_json = {
|
265
|
+
"error_code" => "60001",
|
266
|
+
"message" => "Invalid API key",
|
267
|
+
"errors" => {"message" => "Invalid API key"},
|
268
|
+
"success" => false
|
269
|
+
}.to_json
|
270
|
+
headers["X-Authy-API-Key"] = invalid_api_key
|
271
|
+
expect(Authy::API.http_client).to receive(:request)
|
272
|
+
.once
|
273
|
+
.with(:get, url, {
|
274
|
+
:header => headers,
|
275
|
+
:query => {},
|
276
|
+
:follow_redirect => nil
|
277
|
+
})
|
278
|
+
.and_return(double(:status => 401, :body => response_json))
|
279
|
+
response = Authy::API.send("request_#{kind}", id: user_id, api_key: invalid_api_key)
|
173
280
|
expect(response).to_not be_ok
|
174
|
-
expect(response.errors[
|
281
|
+
expect(response.errors["message"]).to match(/invalid api key/i)
|
175
282
|
end
|
176
283
|
|
177
284
|
it "should request a #{title} token using custom actions" do
|
178
|
-
|
285
|
+
response_json = {
|
286
|
+
:success => true
|
287
|
+
}.to_json
|
288
|
+
expect(Authy::API.http_client).to receive(:request)
|
289
|
+
.once
|
290
|
+
.with(:get, url, {
|
291
|
+
:header => headers,
|
292
|
+
:query => {
|
293
|
+
:action => "custom action?",
|
294
|
+
:action_message => "Action message $%^?@#"
|
295
|
+
},
|
296
|
+
:follow_redirect => nil
|
297
|
+
})
|
298
|
+
.and_return(double(:status => 200, :body => response_json))
|
299
|
+
response = Authy::API.send("request_#{kind}", id: user_id, action: "custom action?", action_message: "Action message $%^?@#")
|
179
300
|
expect(response).to be_ok
|
180
301
|
end
|
181
302
|
|
182
303
|
context "user doesn't exist" do
|
183
304
|
it "should not be ok" do
|
305
|
+
url = "#{Authy.api_uri}/protected/json/#{uri_param}/tony"
|
306
|
+
response_json = {
|
307
|
+
"message" => "User not found.",
|
308
|
+
"success" => false,
|
309
|
+
"errors" => { "message" => "User not found." },
|
310
|
+
"error_code" => "60026"
|
311
|
+
}.to_json
|
312
|
+
expect(Authy::API.http_client).to receive(:request)
|
313
|
+
.once
|
314
|
+
.with(:get, url, {
|
315
|
+
:header => headers,
|
316
|
+
:query => { },
|
317
|
+
:follow_redirect => nil
|
318
|
+
})
|
319
|
+
.and_return(double(:status => 404, :body => response_json))
|
184
320
|
response = Authy::API.send("request_#{kind}", id: "tony")
|
185
|
-
expect(response.errors[
|
321
|
+
expect(response.errors["message"]).to eq "User not found."
|
186
322
|
expect(response).to_not be_ok
|
187
323
|
end
|
188
324
|
end
|
189
325
|
end
|
190
326
|
end
|
191
327
|
|
192
|
-
describe "
|
328
|
+
describe "Requesting email" do
|
329
|
+
it "should request an email token" do
|
330
|
+
response_json = {
|
331
|
+
"success" => true,
|
332
|
+
"message" => "Email token was sent",
|
333
|
+
"email" => "recipient@foo.com",
|
334
|
+
"email_id" => "EMa364aa751cc280d8c22772307e2c5760"
|
335
|
+
}.to_json
|
336
|
+
url = "#{Authy.api_uri}/protected/json/email/#{user_id}"
|
337
|
+
|
338
|
+
expect(Authy::API.http_client).to receive(:request)
|
339
|
+
.once
|
340
|
+
.with(:post, url, body: "", header: headers)
|
341
|
+
.and_return(double(ok?: true, body: response_json, status: 200))
|
342
|
+
response = Authy::API.request_email(id: user_id)
|
343
|
+
expect(response).to be_ok
|
344
|
+
end
|
345
|
+
|
193
346
|
context "user doesn't exist" do
|
194
347
|
it "should not be ok" do
|
195
|
-
|
348
|
+
url = "#{Authy.api_uri}/protected/json/email/tony"
|
349
|
+
response_json = {
|
350
|
+
"message" => "User not found.",
|
351
|
+
"success" => false,
|
352
|
+
"errors" => {
|
353
|
+
"message" => "User not found."
|
354
|
+
},
|
355
|
+
"error_code" => "60026"
|
356
|
+
}.to_json
|
357
|
+
expect(Authy::API.http_client).to receive(:request)
|
358
|
+
.once
|
359
|
+
.with(:post, url, {
|
360
|
+
:header => headers,
|
361
|
+
:body => ""
|
362
|
+
})
|
363
|
+
.and_return(double(:status => 404, :body => response_json))
|
364
|
+
response = Authy::API.request_email(id: "tony")
|
365
|
+
expect(response.errors['message']).to eq "User not found."
|
366
|
+
expect(response).to_not be_ok
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
describe "update user email" do
|
372
|
+
context "user doesn't exist" do
|
373
|
+
it "should not be ok" do
|
374
|
+
url = "#{Authy.api_uri}/protected/json/users/tony/update"
|
375
|
+
response_json = {
|
376
|
+
"message" => "User not found.",
|
377
|
+
"success" => false,
|
378
|
+
"errors" => {
|
379
|
+
"message" => "User not found."
|
380
|
+
},
|
381
|
+
"error_code" => "60026"
|
382
|
+
}.to_json
|
383
|
+
new_email = generate_email
|
384
|
+
expect(Authy::API.http_client).to receive(:request)
|
385
|
+
.once
|
386
|
+
.with(:post, url, {
|
387
|
+
:header => headers,
|
388
|
+
:body => Utils.escape_query(:email => new_email)
|
389
|
+
})
|
390
|
+
.and_return(double(:status => 404, :body => response_json))
|
391
|
+
|
392
|
+
response = Authy::API.update_user(id: "tony", email: new_email)
|
196
393
|
expect(response.errors['message']).to eq "User not found."
|
197
394
|
expect(response).to_not be_ok
|
198
395
|
end
|
199
396
|
end
|
200
397
|
|
201
398
|
context "user exists" do
|
202
|
-
|
203
|
-
|
204
|
-
|
399
|
+
it "should be ok" do
|
400
|
+
response_json = {
|
401
|
+
"message" => "User was updated successfully",
|
402
|
+
"success" => true
|
403
|
+
}.to_json
|
404
|
+
url = "#{Authy.api_uri}/protected/json/users/#{user_id}/update"
|
405
|
+
new_email = generate_email
|
406
|
+
expect(Authy::API.http_client).to receive(:request)
|
407
|
+
.once
|
408
|
+
.with(:post, url, body: Utils.escape_query({
|
409
|
+
email: new_email
|
410
|
+
}), header: headers)
|
411
|
+
.and_return(double(ok?: true, body: response_json, status: 200))
|
412
|
+
response = Authy::API.update_user(id: user_id, email: new_email)
|
413
|
+
expect(response.message).to eq "User was updated successfully"
|
414
|
+
expect(response).to be_ok
|
205
415
|
end
|
416
|
+
end
|
417
|
+
end
|
206
418
|
|
419
|
+
describe "delete users" do
|
420
|
+
context "user doesn't exist" do
|
421
|
+
it "should not be ok" do
|
422
|
+
url = "#{Authy.api_uri}/protected/json/users/delete/tony"
|
423
|
+
response_json = {
|
424
|
+
"message" => "User not found.",
|
425
|
+
"success" => false,
|
426
|
+
"errors" => {
|
427
|
+
"message" => "User not found."
|
428
|
+
},
|
429
|
+
"error_code" => "60026"
|
430
|
+
}.to_json
|
431
|
+
expect(Authy::API.http_client).to receive(:request)
|
432
|
+
.once
|
433
|
+
.with(:post, url, {
|
434
|
+
:header => headers,
|
435
|
+
:body => ""
|
436
|
+
})
|
437
|
+
.and_return(double(:status => 404, :body => response_json))
|
438
|
+
response = Authy::API.delete_user(id: "tony")
|
439
|
+
expect(response.errors["message"]).to eq "User not found."
|
440
|
+
expect(response).to_not be_ok
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
context "user exists" do
|
445
|
+
let(:url) { "#{Authy.api_uri}/protected/json/users/delete/31567" }
|
207
446
|
it "should be ok" do
|
208
|
-
|
209
|
-
|
447
|
+
response_json = {
|
448
|
+
"message" => "User removed from application",
|
449
|
+
"success" => false
|
450
|
+
}.to_json
|
451
|
+
expect(Authy::API.http_client).to receive(:request)
|
452
|
+
.once
|
453
|
+
.with(:post, url, {
|
454
|
+
:header => headers,
|
455
|
+
:body => ""
|
456
|
+
})
|
457
|
+
.and_return(double(:status => 200, :body => response_json))
|
458
|
+
response = Authy::API.delete_user(id: 31567)
|
459
|
+
expect(response.message).to eq "User removed from application"
|
210
460
|
expect(response).to be_ok
|
211
461
|
end
|
212
462
|
end
|
@@ -215,6 +465,23 @@ describe "Authy::API" do
|
|
215
465
|
describe "user status" do
|
216
466
|
context "user doesn't exist" do
|
217
467
|
it "should not be ok" do
|
468
|
+
url = "#{Authy.api_uri}/protected/json/users/tony/status"
|
469
|
+
response_json = {
|
470
|
+
"message" => "User not found.",
|
471
|
+
"success" => false,
|
472
|
+
"errors" => {
|
473
|
+
"message" => "User not found."
|
474
|
+
},
|
475
|
+
"error_code" => "60026"
|
476
|
+
}.to_json
|
477
|
+
expect(Authy::API.http_client).to receive(:request)
|
478
|
+
.once
|
479
|
+
.with(:get, url, {
|
480
|
+
:header => headers,
|
481
|
+
:query => {},
|
482
|
+
:follow_redirect => nil
|
483
|
+
})
|
484
|
+
.and_return(double(:status => 404, :body => response_json))
|
218
485
|
response = Authy::API.user_status(id: "tony")
|
219
486
|
expect(response.errors["message"]).to eq "User not found."
|
220
487
|
expect(response).to_not be_ok
|
@@ -222,13 +489,42 @@ describe "Authy::API" do
|
|
222
489
|
end
|
223
490
|
|
224
491
|
context "user exists" do
|
225
|
-
before do
|
226
|
-
@user = Authy::API.register_user(email: generate_email, cellphone: generate_cellphone, country_code: 1)
|
227
|
-
expect(@user).to be_ok
|
228
|
-
end
|
229
|
-
|
230
492
|
it "should be ok" do
|
231
|
-
|
493
|
+
url = "#{Authy.api_uri}/protected/json/users/290907/status"
|
494
|
+
response_json = {
|
495
|
+
"status" => {
|
496
|
+
"authy_id" => 290907,
|
497
|
+
"confirmed" => true,
|
498
|
+
"registered" => false,
|
499
|
+
"country_code" => 1,
|
500
|
+
"phone_number" => "XXX-XXX-1118",
|
501
|
+
"email" => "alfvawmu@authy.com",
|
502
|
+
"devices" => [],
|
503
|
+
"has_hard_token" => false,
|
504
|
+
"account_disabled" => false,
|
505
|
+
"detailed_devices" => [{
|
506
|
+
"device_type" => "authy",
|
507
|
+
"os_type" => "unknown",
|
508
|
+
"registration_device_id" => nil,
|
509
|
+
"registration_method" => nil,
|
510
|
+
"device_id" => 290908,
|
511
|
+
"last_sync_date" => 0,
|
512
|
+
"creation_date" => 1433868212
|
513
|
+
}],
|
514
|
+
"deleted_devices" => []
|
515
|
+
},
|
516
|
+
"message" => "User status.",
|
517
|
+
"success" => true
|
518
|
+
}.to_json
|
519
|
+
expect(Authy::API.http_client).to receive(:request)
|
520
|
+
.once
|
521
|
+
.with(:get, url, {
|
522
|
+
:header => headers,
|
523
|
+
:query => {},
|
524
|
+
:follow_redirect => nil
|
525
|
+
})
|
526
|
+
.and_return(double(:status => 200, :body => response_json))
|
527
|
+
response = Authy::API.user_status(id: 290907)
|
232
528
|
expect(response.status).to be_kind_of(Hash)
|
233
529
|
expect(response).to be_ok
|
234
530
|
end
|
@@ -236,13 +532,9 @@ describe "Authy::API" do
|
|
236
532
|
end
|
237
533
|
|
238
534
|
describe "blank params" do
|
239
|
-
before do
|
240
|
-
@user = Authy::API.register_user(email: generate_email, cellphone: generate_cellphone, country_code: 1)
|
241
|
-
expect(@user).to be_ok
|
242
|
-
end
|
243
|
-
|
244
535
|
[:request_sms, :request_phone_call, :delete_user].each do |method|
|
245
536
|
it "should return a proper response with the errors for #{method}" do
|
537
|
+
expect(Authy::API.http_client).to receive(:request).never
|
246
538
|
response = Authy::API.send(method, id: nil)
|
247
539
|
expect(response).to_not be_ok
|
248
540
|
expect(response.message).to eq "user_id is blank."
|
@@ -250,25 +542,26 @@ describe "Authy::API" do
|
|
250
542
|
end
|
251
543
|
|
252
544
|
it "should return a prope response with the errors for verify" do
|
545
|
+
expect(Authy::API.http_client).to receive(:request).never
|
253
546
|
response = Authy::API.verify({})
|
254
547
|
expect(response).to_not be_ok
|
255
548
|
expect(response.message).to eq "Token format is invalid"
|
256
549
|
end
|
257
550
|
end
|
258
551
|
|
259
|
-
describe
|
260
|
-
it
|
261
|
-
expect(Authy::API.send(:token_is_safe?,
|
552
|
+
describe ".token_is_safe?" do
|
553
|
+
it "checks minimum token size" do
|
554
|
+
expect(Authy::API.send(:token_is_safe?, "1")).to be false
|
262
555
|
end
|
263
556
|
|
264
|
-
it
|
265
|
-
expect(Authy::API.send(:token_is_safe?,
|
266
|
-
expect(Authy::API.send(:token_is_safe?,
|
557
|
+
it "checks valid characters" do
|
558
|
+
expect(Authy::API.send(:token_is_safe?, "123456")).to be true
|
559
|
+
expect(Authy::API.send(:token_is_safe?, "123456a")).to be false
|
267
560
|
end
|
268
561
|
|
269
|
-
it
|
270
|
-
expect(Authy::API.send(:token_is_safe?,
|
271
|
-
expect(Authy::API.send(:token_is_safe?,
|
562
|
+
it "checks maximum token size" do
|
563
|
+
expect(Authy::API.send(:token_is_safe?, "123456789098")).to be true
|
564
|
+
expect(Authy::API.send(:token_is_safe?, "1234567890987")).to be false
|
272
565
|
end
|
273
566
|
end
|
274
567
|
end
|