shopify_app 8.4.2 → 8.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +9 -0
- data/README.md +26 -0
- data/config/locales/nl.yml +21 -0
- data/config/locales/zh-CN.yml +16 -0
- data/config/locales/zh-TW.yml +17 -0
- data/lib/generators/shopify_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb +3 -1
- data/lib/generators/shopify_app/install/install_generator.rb +2 -0
- data/lib/generators/shopify_app/install/templates/shopify_app.rb +1 -0
- data/lib/generators/shopify_app/install/templates/shopify_provider.rb +17 -14
- data/lib/generators/shopify_app/rotate_shopify_token_job/rotate_shopify_token_job_generator.rb +16 -0
- data/lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token.rake +17 -0
- data/lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token_job.rb +42 -0
- data/lib/shopify_app/configuration.rb +1 -0
- data/lib/shopify_app/controller_concerns/webhook_verification.rb +10 -6
- data/lib/shopify_app/version.rb +1 -1
- data/shopify_app.gemspec +1 -1
- data/translation.yml +1 -1
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8fe2949f5e38db4532dbcab3c05f96e228e6285fdbb4b729ffefecd8e40b2aad
|
4
|
+
data.tar.gz: 2fefc3ce45bc58cd82c874d5217f6abfce0a70ba56cb9105084dbec011f033cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a435b2541e5198fad47a247a97b2a68ce6e741b2b29a4b0b7f2cc29d256fc382a7fd8a56801e982744258e9efdfd3879a13dd4dffc033c88d432ce44d525e44
|
7
|
+
data.tar.gz: 1df140b61ca82e090eba2fcabac5f079cc5d87e7cb64bab657cbc725ff1063360fbd88822d4ed76c9224d2fd4e9429ba197dd3c7f6a6312b3c8dbdb060c35f26
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
8.5.0
|
2
|
+
-----
|
3
|
+
Added support for rotating Shopify access tokens:
|
4
|
+
|
5
|
+
* Added a generator shopify_app:rotate_shopify_token_job for generating the job to perform token rotation
|
6
|
+
* Extend Shopify app configuration to support a new and old secret token
|
7
|
+
* Extended webhook validation code to support validating against new and old secret tokens
|
8
|
+
* See the README for more details: https://github.com/Shopify/shopify_app#rotateshopifytokenjob
|
9
|
+
|
1
10
|
8.4.2
|
2
11
|
-----
|
3
12
|
* Clear stale user session during auth callback
|
data/README.md
CHANGED
@@ -364,6 +364,32 @@ We've also provided a generator which creates a skeleton job and updates the ini
|
|
364
364
|
bin/rails g shopify_app:add_after_authenticate_job
|
365
365
|
```
|
366
366
|
|
367
|
+
RotateShopifyTokenJob
|
368
|
+
---------------------
|
369
|
+
|
370
|
+
If your Shopify secret key is leaked, you can use the RotateShopifyTokenJob to perform [API Credential Rotation](https://help.shopify.com/en/api/getting-started/authentication/oauth/api-credential-rotation).
|
371
|
+
|
372
|
+
Before running the job, you'll need to generate a new secret key from your Shopify Partner dashboard, and update the `/config/initializers/shopify_app.rb` to hold your new and old secret keys:
|
373
|
+
|
374
|
+
```ruby
|
375
|
+
config.secret = Rails.application.secrets.shopify_secret
|
376
|
+
config.old_secret = Rails.application.secrets.old_shopify_secret
|
377
|
+
```
|
378
|
+
|
379
|
+
We've provided a generator which creates the job and an example rake task:
|
380
|
+
|
381
|
+
```sh
|
382
|
+
bin/rails g shopify_app:rotate_shopify_token_job
|
383
|
+
```
|
384
|
+
|
385
|
+
The generated rake task will be found at `lib/tasks/shopify/rotate_shopify_token.rake` and is provided strictly for example purposes. It might not work with your application out of the box without some configuration.
|
386
|
+
|
387
|
+
⚠️ Note: if you are updating `shopify_app` from a version prior to 8.4.2 (and do not wish to run the default/install generator again), you will need to add [the following line](https://github.com/Shopify/shopify_app/blob/4f7e6cca2a472d8f7af44b938bd0fcafe4d8e88a/lib/generators/shopify_app/install/templates/shopify_provider.rb#L18) to `config/intializers/omniauth.rb`:
|
388
|
+
|
389
|
+
```ruby
|
390
|
+
strategy.options[:old_client_secret] = ShopifyApp.configuration.old_secret
|
391
|
+
```
|
392
|
+
|
367
393
|
ShopifyApp::SessionRepository
|
368
394
|
-----------------------------
|
369
395
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
---
|
2
|
+
nl:
|
3
|
+
logged_out: U bent afgemeld
|
4
|
+
could_not_log_in: Kon niet aanmelden bij Shopify-winkel
|
5
|
+
invalid_shop_url: Ongeldig winkeldomein
|
6
|
+
enable_cookies_heading: Schakel cookies in van %{app}
|
7
|
+
enable_cookies_body: U moet cookies in deze browser handmatig inschakelen om %{app}
|
8
|
+
binnen Shopify te gebruiken.
|
9
|
+
enable_cookies_footer: Met cookies kan de app u verifiëren door uw voorkeuren en
|
10
|
+
persoonlijke informatie tijdelijk op te slaan. Ze vervallen na 30 dagen.
|
11
|
+
enable_cookies_action: Schakel cookies in
|
12
|
+
top_level_interaction_heading: Uw browser moet %{app} verifiëren
|
13
|
+
top_level_interaction_body: Uw browser heeft apps van derden nodig zoals %{app}
|
14
|
+
om u toegang te vragen tot cookies voordat Shopify het voor u kan openen.
|
15
|
+
top_level_interaction_action: Doorgaan
|
16
|
+
request_storage_access_heading: "%{app} heeft toegang tot cookies nodig"
|
17
|
+
request_storage_access_body: Hiermee kan de app u verifiëren door uw persoonlijke
|
18
|
+
gegevens tijdelijk op te slaan. Klik op Doorgaan en sta cookies toe om de app
|
19
|
+
te gebruiken.
|
20
|
+
request_storage_access_footer: Cookies verlopen na 30 dagen.
|
21
|
+
request_storage_access_action: Doorgaan
|
@@ -0,0 +1,16 @@
|
|
1
|
+
---
|
2
|
+
zh-CN:
|
3
|
+
logged_out: 已成功注销
|
4
|
+
could_not_log_in: 无法登录到 Shopify 店铺
|
5
|
+
invalid_shop_url: 商店域无效
|
6
|
+
enable_cookies_heading: 从 %{app} 启用 Cookie
|
7
|
+
enable_cookies_body: 您必须在此浏览器中手动启用 Cookie 才能在 Shopify 中使用 %{app}。
|
8
|
+
enable_cookies_footer: Cookie 使此应用能够通过暂时存储您的首选项和个人信息来验证您的身份。这些信息将在 30 天后过期。
|
9
|
+
enable_cookies_action: 启用 Cookie
|
10
|
+
top_level_interaction_heading: 您的浏览器需要对 %{app} 进行验证
|
11
|
+
top_level_interaction_body: 您的浏览器要求类似 %{app} 的第三方应用向您请求访问 Cookie,之后 Shopify 才能为您打开它。
|
12
|
+
top_level_interaction_action: 继续
|
13
|
+
request_storage_access_heading: "%{app} 需要访问 Cookie"
|
14
|
+
request_storage_access_body: 这使此应用能够通过暂时存储您的个人信息来验证您的身份。单击继续并启用 Cookie 以使用此应用。
|
15
|
+
request_storage_access_footer: Cookie 将在 30 天后过期。
|
16
|
+
request_storage_access_action: 继续
|
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
zh-TW:
|
3
|
+
logged_out: 登出成功
|
4
|
+
could_not_log_in: 無法登入 Shopify 商店
|
5
|
+
invalid_shop_url: 商店網域無效
|
6
|
+
enable_cookies_heading: 啟用 %{app} 的 Cookie
|
7
|
+
enable_cookies_body: 您必須在此瀏覽器中手動啟用 Cookie,才能夠在 Shopify 使用 %{app}。
|
8
|
+
enable_cookies_footer: Cookie 可讓應用程式暫時儲存您的偏好設定和個人資訊,藉此驗證您的身分,這些資料會在 30 天後失效。
|
9
|
+
enable_cookies_action: 啟用 Cookie
|
10
|
+
top_level_interaction_heading: 您的瀏覽器需要驗證 %{app}
|
11
|
+
top_level_interaction_body: 您的瀏覽器會要求第三方應用程式 (例如:%{app}) 向您請求 Cookie 的存取權限,然後才讓 Shopify
|
12
|
+
為您開啟此應用程式。
|
13
|
+
top_level_interaction_action: 繼續
|
14
|
+
request_storage_access_heading: "%{app} 需要 Cookie 存取權限"
|
15
|
+
request_storage_access_body: Cookie 可讓應用程式暫時儲存您的個人資訊,藉此驗證您的身分。按一下繼續並允許 Cookie 使用此應用程式。
|
16
|
+
request_storage_access_footer: Cookie 將於 30 天後失效。
|
17
|
+
request_storage_access_action: 繼續
|
data/lib/generators/shopify_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb
CHANGED
@@ -12,7 +12,9 @@ module ShopifyApp
|
|
12
12
|
def init_after_authenticate_config
|
13
13
|
initializer = load_initializer
|
14
14
|
|
15
|
-
|
15
|
+
after_authenticate_job_config =
|
16
|
+
" config.after_authenticate_job = "\
|
17
|
+
"{ job: Shopify::AfterAuthenticateJob, inline: false }\n"
|
16
18
|
|
17
19
|
inject_into_file(
|
18
20
|
'config/initializers/shopify_app.rb',
|
@@ -9,6 +9,7 @@ module ShopifyApp
|
|
9
9
|
class_option :application_name, type: :array, default: ['My', 'Shopify', 'App']
|
10
10
|
class_option :api_key, type: :string, default: '<api_key>'
|
11
11
|
class_option :secret, type: :string, default: '<secret>'
|
12
|
+
class_option :old_secret, type: :string, default: '<old_secret>'
|
12
13
|
class_option :scope, type: :array, default: ['read_products']
|
13
14
|
class_option :embedded, type: :string, default: 'true'
|
14
15
|
|
@@ -16,6 +17,7 @@ module ShopifyApp
|
|
16
17
|
@application_name = format_array_argument(options['application_name'])
|
17
18
|
@api_key = options['api_key']
|
18
19
|
@secret = options['secret']
|
20
|
+
@old_secret = options['old_secret']
|
19
21
|
@scope = format_array_argument(options['scope'])
|
20
22
|
|
21
23
|
template 'shopify_app.rb', 'config/initializers/shopify_app.rb'
|
@@ -2,6 +2,7 @@ ShopifyApp.configure do |config|
|
|
2
2
|
config.application_name = "<%= @application_name %>"
|
3
3
|
config.api_key = "<%= @api_key %>"
|
4
4
|
config.secret = "<%= @secret %>"
|
5
|
+
config.old_secret = "<%= @old_secret %>"
|
5
6
|
config.scope = "<%= @scope %>" # Consult this page for more scope options:
|
6
7
|
# https://help.shopify.com/en/api/getting-started/authentication/oauth/scopes
|
7
8
|
config.embedded_app = <%= embedded_app? %>
|
@@ -1,16 +1,19 @@
|
|
1
|
-
|
2
|
-
ShopifyApp.configuration.api_key,
|
3
|
-
ShopifyApp.configuration.secret,
|
4
|
-
scope: ShopifyApp.configuration.scope,
|
5
|
-
setup: lambda { |env|
|
6
|
-
strategy = env['omniauth.strategy']
|
1
|
+
# frozen_string_literal: true
|
7
2
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
3
|
+
provider :shopify,
|
4
|
+
ShopifyApp.configuration.api_key,
|
5
|
+
ShopifyApp.configuration.secret,
|
6
|
+
scope: ShopifyApp.configuration.scope,
|
7
|
+
setup: lambda { |env|
|
8
|
+
strategy = env['omniauth.strategy']
|
14
9
|
|
15
|
-
|
16
|
-
|
10
|
+
shopify_auth_params = strategy.session['shopify.omniauth_params']&.with_indifferent_access
|
11
|
+
shop = if shopify_auth_params.present?
|
12
|
+
"https://#{shopify_auth_params[:shop]}"
|
13
|
+
else
|
14
|
+
''
|
15
|
+
end
|
16
|
+
|
17
|
+
strategy.options[:client_options][:site] = shop
|
18
|
+
strategy.options[:old_client_secret] = ShopifyApp.configuration.old_secret
|
19
|
+
}
|
data/lib/generators/shopify_app/rotate_shopify_token_job/rotate_shopify_token_job_generator.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators/base'
|
4
|
+
|
5
|
+
module ShopifyApp
|
6
|
+
module Generators
|
7
|
+
class RotateShopifyTokenJobGenerator < Rails::Generators::Base
|
8
|
+
source_root File.expand_path('../templates', __FILE__)
|
9
|
+
|
10
|
+
def add_rotate_shopify_token_job
|
11
|
+
copy_file('rotate_shopify_token_job.rb', "app/jobs/shopify/rotate_shopify_token_job.rb")
|
12
|
+
copy_file('rotate_shopify_token.rake', "lib/tasks/shopify/rotate_shopify_token.rake")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
namespace :shopify do
|
3
|
+
desc "Rotate shopify tokens for all active shops"
|
4
|
+
task :rotate_shopify_tokens, [:refresh_token] => :environment do |_t, args|
|
5
|
+
all_active_shops.find_each do |shop|
|
6
|
+
Shopify::RotateShopifyTokenJob.perform_later(
|
7
|
+
shop_domain: shop.shopify_domain,
|
8
|
+
refresh_token: args[:refresh_token]
|
9
|
+
)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Its implementation will depend on the app configuration. Change accordingly.
|
14
|
+
def all_active_shops
|
15
|
+
Shop.all
|
16
|
+
end
|
17
|
+
end
|
data/lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token_job.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shopify
|
4
|
+
class RotateShopifyTokenJob < ActiveJob::Base
|
5
|
+
def perform(params)
|
6
|
+
@shop = Shop.find_by(shopify_domain: params[:shop_domain])
|
7
|
+
return unless @shop
|
8
|
+
|
9
|
+
config = ShopifyApp.configuration
|
10
|
+
uri = URI("https://#{@shop.shopify_domain}/admin/oauth/access_token")
|
11
|
+
post_data = {
|
12
|
+
client_id: config.api_key,
|
13
|
+
client_secret: config.secret,
|
14
|
+
refresh_token: params[:refresh_token],
|
15
|
+
access_token: @shop.shopify_token,
|
16
|
+
}
|
17
|
+
|
18
|
+
@response = Net::HTTP.post_form(uri, post_data)
|
19
|
+
return log_error(response_expcetion_error_message) unless @response.is_a?(Net::HTTPSuccess)
|
20
|
+
|
21
|
+
access_token = JSON.parse(@response.body)['access_token']
|
22
|
+
return log_error(no_access_token_error_message) unless access_token
|
23
|
+
|
24
|
+
@shop.update(shopify_token: access_token)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def log_error(message)
|
30
|
+
Rails.logger.error(message)
|
31
|
+
end
|
32
|
+
|
33
|
+
def no_access_token_error_message
|
34
|
+
"RotateShopifyTokenJob response returned no access token for shop: #{@shop.shopify_domain}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def response_exception_error_message
|
38
|
+
"RotateShopifyTokenJob failed for shop: #{@shop.shopify_domain}." \
|
39
|
+
"Response returned status: #{@response.code}. Error message: #{@response.message}. "
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -15,12 +15,16 @@ module ShopifyApp
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def hmac_valid?(data)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
secrets = [ShopifyApp.configuration.secret, ShopifyApp.configuration.old_secret].reject(&:blank?)
|
19
|
+
|
20
|
+
secrets.any? do |secret|
|
21
|
+
digest = OpenSSL::Digest.new('sha256')
|
22
|
+
|
23
|
+
ActiveSupport::SecurityUtils.secure_compare(
|
24
|
+
shopify_hmac,
|
25
|
+
Base64.strict_encode64(OpenSSL::HMAC.digest(digest, secret, data))
|
26
|
+
)
|
27
|
+
end
|
24
28
|
end
|
25
29
|
|
26
30
|
def shop_domain
|
data/lib/shopify_app/version.rb
CHANGED
data/shopify_app.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.add_runtime_dependency('browser_sniffer', '~> 1.1.0')
|
14
14
|
s.add_runtime_dependency('rails', '>= 5.0.0')
|
15
15
|
s.add_runtime_dependency('shopify_api', '>= 4.3.5')
|
16
|
-
s.add_runtime_dependency('omniauth-shopify-oauth2', '~> 2.
|
16
|
+
s.add_runtime_dependency('omniauth-shopify-oauth2', '~> 2.1.0')
|
17
17
|
|
18
18
|
s.add_development_dependency('rake')
|
19
19
|
s.add_development_dependency('byebug')
|
data/translation.yml
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shopify_app
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.
|
4
|
+
version: 8.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-02-
|
11
|
+
date: 2019-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: browser_sniffer
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 2.
|
61
|
+
version: 2.1.0
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 2.
|
68
|
+
version: 2.1.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -186,7 +186,10 @@ files:
|
|
186
186
|
- config/locales/fr.yml
|
187
187
|
- config/locales/it.yml
|
188
188
|
- config/locales/ja.yml
|
189
|
+
- config/locales/nl.yml
|
189
190
|
- config/locales/pt-BR.yml
|
191
|
+
- config/locales/zh-CN.yml
|
192
|
+
- config/locales/zh-TW.yml
|
190
193
|
- config/routes.rb
|
191
194
|
- docs/Quickstart.md
|
192
195
|
- docs/Releasing.md
|
@@ -212,6 +215,9 @@ files:
|
|
212
215
|
- lib/generators/shopify_app/install/templates/omniauth.rb
|
213
216
|
- lib/generators/shopify_app/install/templates/shopify_app.rb
|
214
217
|
- lib/generators/shopify_app/install/templates/shopify_provider.rb
|
218
|
+
- lib/generators/shopify_app/rotate_shopify_token_job/rotate_shopify_token_job_generator.rb
|
219
|
+
- lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token.rake
|
220
|
+
- lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token_job.rb
|
215
221
|
- lib/generators/shopify_app/routes/routes_generator.rb
|
216
222
|
- lib/generators/shopify_app/routes/templates/routes.rb
|
217
223
|
- lib/generators/shopify_app/shop_model/shop_model_generator.rb
|