oauth 0.5.14 → 0.6.2
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/CHANGELOG.md +33 -3
- data/README.md +56 -46
- data/SECURITY.md +0 -2
- data/bin/oauth +8 -4
- data/lib/oauth/cli/authorize_command.rb +58 -54
- data/lib/oauth/cli/base_command.rb +163 -159
- data/lib/oauth/cli/help_command.rb +9 -5
- data/lib/oauth/cli/query_command.rb +26 -17
- data/lib/oauth/cli/sign_command.rb +58 -52
- data/lib/oauth/cli/version_command.rb +8 -4
- data/lib/oauth/cli.rb +2 -0
- data/lib/oauth/client/action_controller_request.rb +4 -1
- data/lib/oauth/client/em_http.rb +3 -1
- data/lib/oauth/client/helper.rb +76 -72
- data/lib/oauth/client/net_http.rb +111 -104
- data/lib/oauth/client.rb +2 -0
- data/lib/oauth/consumer.rb +89 -68
- data/lib/oauth/errors/error.rb +2 -0
- data/lib/oauth/errors/problem.rb +3 -0
- data/lib/oauth/errors/unauthorized.rb +4 -0
- data/lib/oauth/errors.rb +2 -0
- data/lib/oauth/helper.rb +9 -5
- data/lib/oauth/oauth.rb +4 -2
- data/lib/oauth/oauth_test_helper.rb +2 -0
- data/lib/oauth/request_proxy/base.rb +4 -4
- data/lib/oauth/request_proxy/mock_request.rb +1 -1
- data/lib/oauth/request_proxy/net_http.rb +8 -8
- data/lib/oauth/request_proxy/rest_client_request.rb +4 -3
- data/lib/oauth/request_proxy.rb +4 -1
- data/lib/oauth/server.rb +8 -4
- data/lib/oauth/signature/base.rb +73 -65
- data/lib/oauth/signature/hmac/sha1.rb +15 -9
- data/lib/oauth/signature/hmac/sha256.rb +15 -9
- data/lib/oauth/signature/plaintext.rb +18 -20
- data/lib/oauth/signature/rsa/sha1.rb +46 -38
- data/lib/oauth/signature.rb +3 -0
- data/lib/oauth/token.rb +2 -0
- data/lib/oauth/tokens/access_token.rb +2 -0
- data/lib/oauth/tokens/consumer_token.rb +2 -0
- data/lib/oauth/tokens/request_token.rb +5 -2
- data/lib/oauth/tokens/server_token.rb +2 -0
- data/lib/oauth/tokens/token.rb +2 -0
- data/lib/oauth/version.rb +5 -1
- data/lib/oauth.rb +9 -2
- metadata +43 -32
data/lib/oauth/consumer.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "net/http"
|
2
4
|
require "net/https"
|
3
5
|
require "oauth/oauth"
|
@@ -17,7 +19,8 @@ module OAuth
|
|
17
19
|
end
|
18
20
|
|
19
21
|
unless defined?(CA_FILE)
|
20
|
-
CA_FILES = %w[/etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt
|
22
|
+
CA_FILES = %w[/etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt
|
23
|
+
/usr/share/curl/curl-ca-bundle.crt].freeze
|
21
24
|
CA_FILES.each do |ca_file|
|
22
25
|
if File.exist?(ca_file)
|
23
26
|
CA_FILE = ca_file
|
@@ -27,42 +30,49 @@ module OAuth
|
|
27
30
|
end
|
28
31
|
CA_FILE = nil unless defined?(CA_FILE)
|
29
32
|
|
30
|
-
@@default_options =
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
33
|
+
@@default_options = SnakyHash::SymbolKeyed.new(
|
34
|
+
{
|
35
|
+
# Signature method used by server. Defaults to HMAC-SHA1
|
36
|
+
signature_method: "HMAC-SHA1",
|
37
|
+
|
38
|
+
# default paths on site. These are the same as the defaults set up by the generators
|
39
|
+
request_token_path: "/oauth/request_token",
|
40
|
+
authenticate_path: "/oauth/authenticate",
|
41
|
+
authorize_path: "/oauth/authorize",
|
42
|
+
access_token_path: "/oauth/access_token",
|
43
|
+
|
44
|
+
proxy: nil,
|
45
|
+
# How do we send the oauth values to the server see
|
46
|
+
# https://oauth.net/core/1.0/#consumer_req_param for more info
|
47
|
+
#
|
48
|
+
# Possible values:
|
49
|
+
#
|
50
|
+
# :header - via the Authorize header (Default) ( option 1. in spec)
|
51
|
+
# :body - url form encoded in body of POST request ( option 2. in spec)
|
52
|
+
# :query_string - via the query part of the url ( option 3. in spec)
|
53
|
+
scheme: :header,
|
54
|
+
|
55
|
+
# Default http method used for OAuth Token Requests (defaults to :post)
|
56
|
+
http_method: :post,
|
57
|
+
|
58
|
+
# Add a custom ca_file for consumer
|
59
|
+
# :ca_file => '/etc/certs.pem'
|
60
|
+
|
61
|
+
# Possible values:
|
62
|
+
#
|
63
|
+
# nil, false - no debug output
|
64
|
+
# true - uses $stdout
|
65
|
+
# some_value - uses some_value
|
66
|
+
debug_output: nil,
|
67
|
+
|
68
|
+
# Defaults to producing a body_hash as part of the signature but
|
69
|
+
# can be disabled since it's not officially part of the OAuth 1.0
|
70
|
+
# spec. Possible values are true and false
|
71
|
+
body_hash_enabled: true,
|
72
|
+
|
73
|
+
oauth_version: "1.0"
|
74
|
+
}
|
75
|
+
)
|
66
76
|
|
67
77
|
attr_accessor :options, :key, :secret
|
68
78
|
attr_writer :site, :http
|
@@ -75,7 +85,8 @@ module OAuth
|
|
75
85
|
# :http_method => :post,
|
76
86
|
# :request_token_path => "/oauth/example/request_token.php",
|
77
87
|
# :access_token_path => "/oauth/example/access_token.php",
|
78
|
-
# :authorize_path => "/oauth/example/authorize.php"
|
88
|
+
# :authorize_path => "/oauth/example/authorize.php",
|
89
|
+
# :body_hash_enabled => false
|
79
90
|
# })
|
80
91
|
#
|
81
92
|
# Start the process by requesting a token
|
@@ -94,9 +105,8 @@ module OAuth
|
|
94
105
|
@secret = consumer_secret
|
95
106
|
|
96
107
|
# ensure that keys are symbols
|
97
|
-
|
98
|
-
|
99
|
-
end)
|
108
|
+
snaky_options = SnakyHash::SymbolKeyed.new(options)
|
109
|
+
@options = @@default_options.merge(snaky_options)
|
100
110
|
end
|
101
111
|
|
102
112
|
# The default http method
|
@@ -105,15 +115,13 @@ module OAuth
|
|
105
115
|
end
|
106
116
|
|
107
117
|
def debug_output
|
108
|
-
@debug_output ||=
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
end
|
116
|
-
end
|
118
|
+
@debug_output ||= case @options[:debug_output]
|
119
|
+
when nil, false
|
120
|
+
when true
|
121
|
+
$stdout
|
122
|
+
else
|
123
|
+
@options[:debug_output]
|
124
|
+
end
|
117
125
|
end
|
118
126
|
|
119
127
|
# The HTTP object for the site. The HTTP Object is what you get when you do Net::HTTP.new
|
@@ -132,7 +140,8 @@ module OAuth
|
|
132
140
|
end
|
133
141
|
|
134
142
|
def get_access_token(request_token, request_options = {}, *arguments, &block)
|
135
|
-
response = token_request(http_method, (access_token_url? ? access_token_url : access_token_path), request_token,
|
143
|
+
response = token_request(http_method, (access_token_url? ? access_token_url : access_token_path), request_token,
|
144
|
+
request_options, *arguments, &block)
|
136
145
|
OAuth::AccessToken.from_hash(self, response)
|
137
146
|
end
|
138
147
|
|
@@ -153,9 +162,11 @@ module OAuth
|
|
153
162
|
def get_request_token(request_options = {}, *arguments, &block)
|
154
163
|
# if oauth_callback wasn't provided, it is assumed that oauth_verifiers
|
155
164
|
# will be exchanged out of band
|
156
|
-
|
165
|
+
unless request_options[:exclude_callback]
|
166
|
+
request_options[:oauth_callback] ||= OAuth::OUT_OF_BAND
|
167
|
+
end
|
157
168
|
|
158
|
-
response = if
|
169
|
+
response = if block
|
159
170
|
token_request(
|
160
171
|
http_method,
|
161
172
|
(request_token_url? ? request_token_url : request_token_path),
|
@@ -165,7 +176,8 @@ module OAuth
|
|
165
176
|
&block
|
166
177
|
)
|
167
178
|
else
|
168
|
-
token_request(http_method, (request_token_url? ? request_token_url : request_token_path), nil,
|
179
|
+
token_request(http_method, (request_token_url? ? request_token_url : request_token_path), nil,
|
180
|
+
request_options, *arguments)
|
169
181
|
end
|
170
182
|
OAuth::RequestToken.from_hash(self, response)
|
171
183
|
end
|
@@ -181,7 +193,7 @@ module OAuth
|
|
181
193
|
# @consumer.request(:post, '/people', @token, {}, @person.to_xml, { 'Content-Type' => 'application/xml' })
|
182
194
|
#
|
183
195
|
def request(http_method, path, token = nil, request_options = {}, *arguments)
|
184
|
-
|
196
|
+
unless %r{^/}.match?(path)
|
185
197
|
@http = create_http(path)
|
186
198
|
_uri = URI.parse(path)
|
187
199
|
path = "#{_uri.path}#{_uri.query ? "?#{_uri.query}" : ""}"
|
@@ -190,13 +202,14 @@ module OAuth
|
|
190
202
|
# override the request with your own, this is useful for file uploads which Net::HTTP does not do
|
191
203
|
req = create_signed_request(http_method, path, token, request_options, *arguments)
|
192
204
|
return nil if block_given? && (yield(req) == :done)
|
205
|
+
|
193
206
|
rsp = http.request(req)
|
194
207
|
# check for an error reported by the Problem Reporting extension
|
195
208
|
# (https://wiki.oauth.net/ProblemReporting)
|
196
209
|
# note: a 200 may actually be an error; check for an oauth_problem key to be sure
|
197
210
|
if !(headers = rsp.to_hash["www-authenticate"]).nil? &&
|
198
|
-
(h = headers.
|
199
|
-
h.first
|
211
|
+
(h = headers.grep(/^OAuth /)).any? &&
|
212
|
+
h.first.include?("oauth_problem")
|
200
213
|
|
201
214
|
# puts "Header: #{h.first}"
|
202
215
|
|
@@ -276,6 +289,7 @@ module OAuth
|
|
276
289
|
|
277
290
|
def request_endpoint
|
278
291
|
return nil if @options[:request_endpoint].nil?
|
292
|
+
|
279
293
|
@options[:request_endpoint].to_s
|
280
294
|
end
|
281
295
|
|
@@ -301,7 +315,7 @@ module OAuth
|
|
301
315
|
|
302
316
|
# TODO: this is ugly, rewrite
|
303
317
|
def request_token_url
|
304
|
-
@options[:request_token_url] || site + request_token_path
|
318
|
+
@options[:request_token_url] || (site + request_token_path)
|
305
319
|
end
|
306
320
|
|
307
321
|
def request_token_url?
|
@@ -309,7 +323,7 @@ module OAuth
|
|
309
323
|
end
|
310
324
|
|
311
325
|
def authenticate_url
|
312
|
-
@options[:authenticate_url] || site + authenticate_path
|
326
|
+
@options[:authenticate_url] || (site + authenticate_path)
|
313
327
|
end
|
314
328
|
|
315
329
|
def authenticate_url?
|
@@ -317,7 +331,7 @@ module OAuth
|
|
317
331
|
end
|
318
332
|
|
319
333
|
def authorize_url
|
320
|
-
@options[:authorize_url] || site + authorize_path
|
334
|
+
@options[:authorize_url] || (site + authorize_path)
|
321
335
|
end
|
322
336
|
|
323
337
|
def authorize_url?
|
@@ -325,7 +339,7 @@ module OAuth
|
|
325
339
|
end
|
326
340
|
|
327
341
|
def access_token_url
|
328
|
-
@options[:access_token_url] || site + access_token_path
|
342
|
+
@options[:access_token_url] || (site + access_token_path)
|
329
343
|
end
|
330
344
|
|
331
345
|
def access_token_url?
|
@@ -342,7 +356,7 @@ module OAuth
|
|
342
356
|
def create_http(_url = nil)
|
343
357
|
_url = request_endpoint unless request_endpoint.nil?
|
344
358
|
|
345
|
-
our_uri = if _url.nil? || _url[0] =~
|
359
|
+
our_uri = if _url.nil? || _url[0] =~ %r{^/}
|
346
360
|
URI.parse(site)
|
347
361
|
else
|
348
362
|
your_uri = URI.parse(_url)
|
@@ -359,7 +373,8 @@ module OAuth
|
|
359
373
|
http_object = Net::HTTP.new(our_uri.host, our_uri.port)
|
360
374
|
else
|
361
375
|
proxy_uri = proxy.is_a?(URI) ? proxy : URI.parse(proxy)
|
362
|
-
http_object = Net::HTTP.new(our_uri.host, our_uri.port, proxy_uri.host, proxy_uri.port, proxy_uri.user,
|
376
|
+
http_object = Net::HTTP.new(our_uri.host, our_uri.port, proxy_uri.host, proxy_uri.port, proxy_uri.user,
|
377
|
+
proxy_uri.password)
|
363
378
|
end
|
364
379
|
|
365
380
|
http_object.use_ssl = (our_uri.scheme == "https")
|
@@ -374,10 +389,14 @@ module OAuth
|
|
374
389
|
end
|
375
390
|
|
376
391
|
http_object.read_timeout = http_object.open_timeout = @options[:timeout] || 60
|
377
|
-
|
392
|
+
if @options[:open_timeout]
|
393
|
+
http_object.open_timeout = @options[:open_timeout]
|
394
|
+
end
|
378
395
|
http_object.ssl_version = @options[:ssl_version] if @options[:ssl_version]
|
379
|
-
|
380
|
-
|
396
|
+
if @options[:ssl_client_cert]
|
397
|
+
http_object.cert = @options[:ssl_client_cert]
|
398
|
+
end
|
399
|
+
http_object.key = @options[:ssl_client_key] if @options[:ssl_client_key]
|
381
400
|
http_object.set_debug_output(debug_output) if debug_output
|
382
401
|
|
383
402
|
http_object
|
@@ -392,8 +411,10 @@ module OAuth
|
|
392
411
|
# if the base site contains a path, add it now
|
393
412
|
# only add if the site host matches the current http object's host
|
394
413
|
# (in case we've specified a full url for token requests)
|
395
|
-
uri
|
396
|
-
|
414
|
+
uri = URI.parse(site)
|
415
|
+
if uri.path && uri.path != "/" && uri.host == http.address
|
416
|
+
path = uri.path + path
|
417
|
+
end
|
397
418
|
|
398
419
|
headers = arguments.first.is_a?(Hash) ? arguments.shift : {}
|
399
420
|
|
data/lib/oauth/errors/error.rb
CHANGED
data/lib/oauth/errors/problem.rb
CHANGED
data/lib/oauth/errors.rb
CHANGED
data/lib/oauth/helper.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "time"
|
1
4
|
require "openssl"
|
2
5
|
require "base64"
|
3
6
|
|
4
7
|
module OAuth
|
5
8
|
module Helper
|
6
|
-
|
9
|
+
module_function
|
7
10
|
|
8
11
|
# Escape +value+ by URL encoding all non-reserved character.
|
9
12
|
#
|
@@ -30,7 +33,7 @@ module OAuth
|
|
30
33
|
|
31
34
|
alias generate_nonce generate_key
|
32
35
|
|
33
|
-
def generate_timestamp
|
36
|
+
def generate_timestamp # :nodoc:
|
34
37
|
Time.now.to_i.to_s
|
35
38
|
end
|
36
39
|
|
@@ -43,7 +46,8 @@ module OAuth
|
|
43
46
|
# See Also: {OAuth core spec version 1.0, section 9.1.1}[http://oauth.net/core/1.0#rfc.section.9.1.1]
|
44
47
|
def normalize(params)
|
45
48
|
params.sort.map do |k, values|
|
46
|
-
|
49
|
+
case values
|
50
|
+
when Array
|
47
51
|
# make sure the array has an element so we don't lose the key
|
48
52
|
values << nil if values.empty?
|
49
53
|
# multiple values were provided for a single key
|
@@ -54,7 +58,7 @@ module OAuth
|
|
54
58
|
[escape(k), escape(v)].join("=")
|
55
59
|
end
|
56
60
|
end
|
57
|
-
|
61
|
+
when Hash
|
58
62
|
normalize_nested_query(values, k)
|
59
63
|
else
|
60
64
|
[escape(k), escape(values)].join("=")
|
@@ -99,7 +103,7 @@ module OAuth
|
|
99
103
|
# strip and unescape
|
100
104
|
val = unescape(v.strip)
|
101
105
|
# strip quotes
|
102
|
-
val.sub(
|
106
|
+
val.sub(/^"(.*)"$/, '\1')
|
103
107
|
end
|
104
108
|
|
105
109
|
# convert into a Hash
|
data/lib/oauth/oauth.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OAuth
|
2
4
|
# request tokens are passed between the consumer and the provider out of
|
3
5
|
# band (i.e. callbacks cannot be used), per section 6.1.1
|
4
|
-
OUT_OF_BAND = "oob"
|
6
|
+
OUT_OF_BAND = "oob"
|
5
7
|
|
6
8
|
# required parameters, per sections 6.1.1, 6.3.1, and 7
|
7
9
|
PARAMETERS = %w[oauth_callback oauth_consumer_key oauth_token
|
@@ -9,5 +11,5 @@ module OAuth
|
|
9
11
|
oauth_version oauth_signature oauth_body_hash].freeze
|
10
12
|
|
11
13
|
# reserved character regexp, per section 5.1
|
12
|
-
RESERVED_CHARACTERS = /[^a-zA-Z0-9
|
14
|
+
RESERVED_CHARACTERS = /[^a-zA-Z0-9\-._~]/.freeze
|
13
15
|
end
|
@@ -79,15 +79,15 @@ module OAuth
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def parameters_for_signature
|
82
|
-
parameters.
|
82
|
+
parameters.select { |k, _v| !signature_and_unsigned_parameters.include?(k) }
|
83
83
|
end
|
84
84
|
|
85
85
|
def oauth_parameters
|
86
|
-
parameters.select { |k,
|
86
|
+
parameters.select { |k, v| OAuth::PARAMETERS.include?(k) && !v.nil? && v != "" }
|
87
87
|
end
|
88
88
|
|
89
89
|
def non_oauth_parameters
|
90
|
-
parameters.
|
90
|
+
parameters.select { |k, _v| !OAuth::PARAMETERS.include?(k) }
|
91
91
|
end
|
92
92
|
|
93
93
|
def signature_and_unsigned_parameters
|
@@ -127,7 +127,7 @@ module OAuth
|
|
127
127
|
end
|
128
128
|
|
129
129
|
# URI, including OAuth parameters
|
130
|
-
def signed_uri(with_oauth
|
130
|
+
def signed_uri(with_oauth: true)
|
131
131
|
if signed?
|
132
132
|
params = if with_oauth
|
133
133
|
parameters
|
@@ -38,13 +38,11 @@ module OAuth
|
|
38
38
|
request_params = CGI.parse(query_string)
|
39
39
|
# request_params.each{|k,v| request_params[k] = [nil] if v == []}
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
request_params[k] = [v]
|
47
|
-
end
|
41
|
+
options[:parameters]&.each do |k, v|
|
42
|
+
if request_params.key?(k) && v
|
43
|
+
request_params[k] << v
|
44
|
+
else
|
45
|
+
request_params[k] = [v]
|
48
46
|
end
|
49
47
|
end
|
50
48
|
request_params
|
@@ -71,7 +69,9 @@ module OAuth
|
|
71
69
|
end
|
72
70
|
|
73
71
|
def auth_header_params
|
74
|
-
|
72
|
+
unless request["Authorization"] && request["Authorization"][0, 5] == "OAuth"
|
73
|
+
return nil
|
74
|
+
end
|
75
75
|
|
76
76
|
request["Authorization"]
|
77
77
|
end
|
@@ -38,7 +38,8 @@ module OAuth
|
|
38
38
|
|
39
39
|
def post_parameters
|
40
40
|
# Post params are only used if posting form data
|
41
|
-
|
41
|
+
is_form_data = request.payload && request.payload.headers["Content-Type"] == "application/x-www-form-urlencoded"
|
42
|
+
if is_form_data && (method == "POST" || method == "PUT")
|
42
43
|
OAuth::Helper.stringify_keys(query_string_to_hash(request.payload.to_s) || {})
|
43
44
|
else
|
44
45
|
{}
|
@@ -51,9 +52,9 @@ module OAuth
|
|
51
52
|
query.split("&").inject({}) do |result, q|
|
52
53
|
k, v = q.split("=")
|
53
54
|
if !v.nil?
|
54
|
-
result.merge(k => v)
|
55
|
+
result.merge({ k => v })
|
55
56
|
elsif !result.key?(k)
|
56
|
-
result.merge(k => true)
|
57
|
+
result.merge({ k => true })
|
57
58
|
else
|
58
59
|
result
|
59
60
|
end
|
data/lib/oauth/request_proxy.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OAuth
|
2
4
|
module RequestProxy
|
3
|
-
def self.available_proxies
|
5
|
+
def self.available_proxies # :nodoc:
|
4
6
|
@available_proxies ||= {}
|
5
7
|
end
|
6
8
|
|
@@ -16,6 +18,7 @@ module OAuth
|
|
16
18
|
end
|
17
19
|
|
18
20
|
raise UnknownRequestType, request.class.to_s unless klass
|
21
|
+
|
19
22
|
klass.new(request, options)
|
20
23
|
end
|
21
24
|
|
data/lib/oauth/server.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "oauth/helper"
|
2
4
|
require "oauth/consumer"
|
3
5
|
|
@@ -31,10 +33,12 @@ module OAuth
|
|
31
33
|
def create_consumer
|
32
34
|
creds = generate_credentials
|
33
35
|
Consumer.new(creds[0], creds[1],
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
{
|
37
|
+
site: base_url,
|
38
|
+
request_token_path: request_token_path,
|
39
|
+
authorize_path: authorize_path,
|
40
|
+
access_token_path: access_token_path
|
41
|
+
})
|
38
42
|
end
|
39
43
|
|
40
44
|
def request_token_path
|