omniauth-shopify-oauth2 2.0.0 → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3c2fdff942824597bca290d63c4d5f2e8ad3fea3
4
- data.tar.gz: 175291a1282389126084a7d32c2fd7c4965faa9c
2
+ SHA256:
3
+ metadata.gz: a323c0e91f3f9574a06a0510f3a68e3ac0d0fefd52a9202d1d7899005ed3fa33
4
+ data.tar.gz: 3fb6661fe5e570d77070bdac24f88577c53a36b5fd847955dbf9368491620d28
5
5
  SHA512:
6
- metadata.gz: f905cd84cc0df6a8b1ef9d61ae432e0aaeb2d88547b77e4ddf5ca09c991ef181d131690a5ec6022553ff31b1246875cc76fd7420911cb463d021f459a72b8b4b
7
- data.tar.gz: e909527c818473c35ae5e9caf4f3afaffe38e9fdf835fc7bff13fe41c1be8ab2e81f71f1fca02011013d78303d1baccb222fb9e2c6cd7be9704fd9645c668e31
6
+ metadata.gz: 8f4909d9271c0b50bade9ea456594275aee7ee4877c6d89c55c9cae824e6b63c9659fecf945cfa6cc44ac3bdc67c1ae8961289b6a84f4683f2874419846fbcfc
7
+ data.tar.gz: d4df88d5a00976d50b2137f213ac6f64ff9ea011538a835d7e63204a3b5cdafc9b2f000947652de0ad0407a8ef37a9710b94495a8a3fe7aa175aaff77a89679d
@@ -1,5 +1,5 @@
1
1
  module OmniAuth
2
2
  module Shopify
3
- VERSION = "2.0.0"
3
+ VERSION = "2.1.0"
4
4
  end
5
5
  end
@@ -17,6 +17,7 @@ module OmniAuth
17
17
 
18
18
  option :callback_url
19
19
  option :myshopify_domain, 'myshopify.com'
20
+ option :old_client_secret
20
21
 
21
22
  # When `true`, the user's permission level will apply (in addition to
22
23
  # the requested access scope) when making API requests to Shopify.
@@ -61,8 +62,10 @@ module OmniAuth
61
62
 
62
63
  return false unless timestamp.to_i > Time.now.to_i - CODE_EXPIRES_AFTER
63
64
 
64
- calculated_signature = self.class.hmac_sign(self.class.encoded_params_for_signature(params), options.client_secret)
65
- Rack::Utils.secure_compare(calculated_signature, signature)
65
+ new_secret = options.client_secret
66
+ old_secret = options.old_client_secret
67
+
68
+ validate_signature(new_secret) || (old_secret && validate_signature(old_secret))
66
69
  end
67
70
 
68
71
  def valid_scope?(token)
@@ -139,6 +142,14 @@ module OmniAuth
139
142
  def callback_url
140
143
  options[:callback_url] || full_host + script_name + callback_path
141
144
  end
145
+
146
+ private
147
+
148
+ def validate_signature(secret)
149
+ params = request.GET
150
+ calculated_signature = self.class.hmac_sign(self.class.encoded_params_for_signature(params), secret)
151
+ Rack::Utils.secure_compare(calculated_signature, params['hmac'])
152
+ end
142
153
  end
143
154
  end
144
155
  end
@@ -52,7 +52,7 @@ class IntegrationTest < Minitest::Test
52
52
  response = authorize(shop)
53
53
  assert_auth_failure(response, 'invalid_site')
54
54
 
55
- response = callback(sign_params(shop: shop, code: code))
55
+ response = callback(sign_with_new_secret(shop: shop, code: code))
56
56
  assert_auth_failure(response, 'invalid_site')
57
57
  end
58
58
  end
@@ -62,7 +62,7 @@ class IntegrationTest < Minitest::Test
62
62
  code = SecureRandom.hex(16)
63
63
  expect_access_token_request(access_token, OmniAuth::Strategies::Shopify::DEFAULT_SCOPE)
64
64
 
65
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
65
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
66
66
 
67
67
  assert_callback_success(response, access_token, code)
68
68
  end
@@ -73,7 +73,7 @@ class IntegrationTest < Minitest::Test
73
73
  code = SecureRandom.hex(16)
74
74
  expect_access_token_request(access_token, OmniAuth::Strategies::Shopify::DEFAULT_SCOPE)
75
75
 
76
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]).merge(signature: 'ignored'))
76
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]).merge(signature: 'ignored'))
77
77
 
78
78
  assert_callback_success(response, access_token, code)
79
79
  end
@@ -100,21 +100,21 @@ class IntegrationTest < Minitest::Test
100
100
  code = SecureRandom.hex(16)
101
101
  expect_access_token_request(access_token, 'read_orders,write_products')
102
102
 
103
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
103
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
104
104
 
105
105
  assert_callback_success(response, access_token, code)
106
106
  end
107
107
 
108
108
  def test_callback_rejects_invalid_hmac
109
109
  @secret = 'wrong_secret'
110
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: SecureRandom.hex(16)))
110
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: SecureRandom.hex(16)))
111
111
 
112
112
  assert_auth_failure(response, 'invalid_signature')
113
113
  end
114
114
 
115
115
  def test_callback_rejects_old_timestamps
116
116
  expired_timestamp = Time.now.to_i - OmniAuth::Strategies::Shopify::CODE_EXPIRES_AFTER - 1
117
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: SecureRandom.hex(16), timestamp: expired_timestamp))
117
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: SecureRandom.hex(16), timestamp: expired_timestamp))
118
118
 
119
119
  assert_auth_failure(response, 'invalid_signature')
120
120
  end
@@ -129,7 +129,7 @@ class IntegrationTest < Minitest::Test
129
129
 
130
130
  def test_callback_rejects_body_params
131
131
  code = SecureRandom.hex(16)
132
- params = sign_params(shop: 'snowdevil.myshopify.com', code: code)
132
+ params = sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code)
133
133
  body = Rack::Utils.build_nested_query(unsigned: 'value')
134
134
 
135
135
  response = request.get("https://app.example.com/auth/shopify/callback?#{Rack::Utils.build_query(params)}",
@@ -189,7 +189,7 @@ class IntegrationTest < Minitest::Test
189
189
  code = SecureRandom.hex(16)
190
190
  expect_access_token_request(access_token, OmniAuth::Strategies::Shopify::DEFAULT_SCOPE)
191
191
 
192
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: 'invalid'))
192
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: 'invalid'))
193
193
 
194
194
  assert_equal 302, response.status
195
195
  assert_equal '/auth/failure?message=csrf_detected&strategy=shopify', response.location
@@ -200,7 +200,7 @@ class IntegrationTest < Minitest::Test
200
200
  code = SecureRandom.hex(16)
201
201
  expect_access_token_request(access_token, 'some_invalid_scope', nil)
202
202
 
203
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
203
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
204
204
 
205
205
  assert_equal 302, response.status
206
206
  assert_equal '/auth/failure?message=invalid_scope&strategy=shopify', response.location
@@ -211,7 +211,7 @@ class IntegrationTest < Minitest::Test
211
211
  code = SecureRandom.hex(16)
212
212
  expect_access_token_request(access_token, nil)
213
213
 
214
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
214
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
215
215
 
216
216
  assert_equal 302, response.status
217
217
  assert_equal '/auth/failure?message=invalid_scope&strategy=shopify', response.location
@@ -224,7 +224,7 @@ class IntegrationTest < Minitest::Test
224
224
  code = SecureRandom.hex(16)
225
225
  expect_access_token_request(access_token, 'first_scope')
226
226
 
227
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
227
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
228
228
 
229
229
  assert_equal 302, response.status
230
230
  assert_equal '/auth/failure?message=invalid_scope&strategy=shopify', response.location
@@ -237,7 +237,7 @@ class IntegrationTest < Minitest::Test
237
237
  code = SecureRandom.hex(16)
238
238
  expect_access_token_request(access_token, 'second_scope,first_scope,third_scope')
239
239
 
240
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
240
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
241
241
 
242
242
  assert_equal 302, response.status
243
243
  assert_equal '/auth/failure?message=invalid_scope&strategy=shopify', response.location
@@ -250,7 +250,7 @@ class IntegrationTest < Minitest::Test
250
250
  code = SecureRandom.hex(16)
251
251
  expect_access_token_request(access_token, 'second_scope,first_scope')
252
252
 
253
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
253
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
254
254
 
255
255
  assert_callback_success(response, access_token, code)
256
256
  end
@@ -262,7 +262,7 @@ class IntegrationTest < Minitest::Test
262
262
  code = SecureRandom.hex(16)
263
263
  expect_access_token_request(access_token, 'read_content,write_products')
264
264
 
265
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
265
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
266
266
 
267
267
  assert_callback_success(response, access_token, code)
268
268
  end
@@ -274,7 +274,7 @@ class IntegrationTest < Minitest::Test
274
274
  code = SecureRandom.hex(16)
275
275
  expect_access_token_request(access_token, 'scope', { id: 1, email: 'bob@bobsen.com'})
276
276
 
277
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
277
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
278
278
 
279
279
  assert_equal 302, response.status
280
280
  assert_equal '/auth/failure?message=invalid_permissions&strategy=shopify', response.location
@@ -287,7 +287,7 @@ class IntegrationTest < Minitest::Test
287
287
  code = SecureRandom.hex(16)
288
288
  expect_access_token_request(access_token, 'scope', nil)
289
289
 
290
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
290
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
291
291
 
292
292
  assert_equal 302, response.status
293
293
  assert_equal '/auth/failure?message=invalid_permissions&strategy=shopify', response.location
@@ -300,18 +300,45 @@ class IntegrationTest < Minitest::Test
300
300
  code = SecureRandom.hex(16)
301
301
  expect_access_token_request(access_token, 'scope', { id: 1, email: 'bob@bobsen.com'})
302
302
 
303
- response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
303
+ response = callback(sign_with_new_secret(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
304
304
 
305
305
  assert_equal 200, response.status
306
306
  end
307
307
 
308
+ def test_callback_works_with_old_secret
309
+ build_app scope: OmniAuth::Strategies::Shopify::DEFAULT_SCOPE
310
+ access_token = SecureRandom.hex(16)
311
+ code = SecureRandom.hex(16)
312
+ expect_access_token_request(access_token, OmniAuth::Strategies::Shopify::DEFAULT_SCOPE)
313
+
314
+ signed_params = sign_with_old_secret(
315
+ shop: 'snowdevil.myshopify.com',
316
+ code: code,
317
+ state: opts["rack.session"]["omniauth.state"]
318
+ )
319
+
320
+ response = callback(signed_params)
321
+
322
+ assert_callback_success(response, access_token, code)
323
+ end
324
+
308
325
  private
309
326
 
310
- def sign_params(params)
311
- params = params.dup
327
+ def sign_with_old_secret(params)
328
+ params = add_time(params)
329
+ encoded_params = OmniAuth::Strategies::Shopify.encoded_params_for_signature(params)
330
+ params['hmac'] = OmniAuth::Strategies::Shopify.hmac_sign(encoded_params, @old_secret)
331
+ params
332
+ end
312
333
 
334
+ def add_time(params)
335
+ params = params.dup
313
336
  params[:timestamp] ||= Time.now.to_i
337
+ params
338
+ end
314
339
 
340
+ def sign_with_new_secret(params)
341
+ params = add_time(params)
315
342
  encoded_params = OmniAuth::Strategies::Shopify.encoded_params_for_signature(params)
316
343
  params['hmac'] = OmniAuth::Strategies::Shopify.hmac_sign(encoded_params, @secret)
317
344
  params
@@ -344,6 +371,9 @@ class IntegrationTest < Minitest::Test
344
371
  end
345
372
 
346
373
  def build_app(options={})
374
+ @old_secret = '12d34s1'
375
+ @secret = '53cr3tz'
376
+ options.merge!(old_client_secret: @old_secret)
347
377
  app = proc { |env|
348
378
  @omniauth_result = env['omniauth.auth']
349
379
  [200, {Rack::CONTENT_TYPE => "text/plain"}, "OK"]
@@ -351,9 +381,8 @@ class IntegrationTest < Minitest::Test
351
381
 
352
382
  opts["rack.session"]["omniauth.state"] = SecureRandom.hex(32)
353
383
  app = OmniAuth::Builder.new(app) do
354
- provider :shopify, '123', '53cr3tz', options
384
+ provider :shopify, '123', '53cr3tz' , options
355
385
  end
356
- @secret = '53cr3tz'
357
386
  @app = Rack::Session::Cookie.new(app, secret: SecureRandom.hex(64))
358
387
  end
359
388
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-shopify-oauth2
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Odorcic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-14 00:00:00.000000000 Z
11
+ date: 2019-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: omniauth-oauth2
@@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
124
  version: '0'
125
125
  requirements: []
126
126
  rubyforge_project:
127
- rubygems_version: 2.6.14
127
+ rubygems_version: 2.7.6
128
128
  signing_key:
129
129
  specification_version: 4
130
130
  summary: Shopify strategy for OmniAuth