shopify_app 20.0.0 → 20.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/cla.yml +22 -0
  3. data/CHANGELOG.md +22 -4
  4. data/Gemfile.lock +5 -5
  5. data/README.md +18 -4
  6. data/app/controllers/concerns/shopify_app/require_known_shop.rb +9 -1
  7. data/app/controllers/concerns/shopify_app/shop_access_scopes_verification.rb +9 -1
  8. data/app/controllers/shopify_app/callback_controller.rb +8 -1
  9. data/app/controllers/shopify_app/sessions_controller.rb +9 -1
  10. data/config/locales/ja.yml +4 -4
  11. data/docs/Quickstart.md +5 -4
  12. data/docs/Upgrading.md +15 -3
  13. data/lib/generators/shopify_app/home_controller/templates/unauthenticated_home_controller.rb +6 -2
  14. data/lib/generators/shopify_app/install/install_generator.rb +26 -3
  15. data/lib/shopify_app/access_scopes/user_strategy.rb +1 -0
  16. data/lib/shopify_app/configuration.rb +3 -0
  17. data/lib/shopify_app/controller_concerns/embedded_app.rb +2 -0
  18. data/lib/shopify_app/controller_concerns/frame_ancestors.rb +16 -0
  19. data/lib/shopify_app/controller_concerns/login_protection.rb +4 -28
  20. data/lib/shopify_app/controller_concerns/redirect_for_embedded.rb +35 -0
  21. data/lib/shopify_app/controller_concerns/sanitized_params.rb +35 -0
  22. data/lib/shopify_app/engine.rb +1 -0
  23. data/lib/shopify_app/jobs/webhooks_manager_job.rb +1 -1
  24. data/lib/shopify_app/managers/scripttags_manager.rb +1 -0
  25. data/lib/shopify_app/managers/webhooks_manager.rb +2 -0
  26. data/lib/shopify_app/session/session_repository.rb +2 -0
  27. data/lib/shopify_app/utils.rb +1 -0
  28. data/lib/shopify_app/version.rb +1 -1
  29. data/lib/shopify_app.rb +3 -0
  30. data/package.json +1 -1
  31. data/service.yml +0 -1
  32. data/shopify_app.gemspec +1 -1
  33. metadata +8 -5
  34. data/.github/probots.yml +0 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90ae6248163ec5df43b7859362604cd54d3c3402a13c34d47b81db36427262b9
4
- data.tar.gz: f07b53d9d4d27e1c71531df33ac0ac2e1bc3d5c66244eda39a263eaaefa69fcf
3
+ metadata.gz: bd02305de4da4e2ffd996e7404103f9aa007d0f96dc7a8677e64bb358c27cd5c
4
+ data.tar.gz: 5519b4ee6fbb5c38de4e7e7c93a815dfe0a2722bc5e5280b834db8845f5341d3
5
5
  SHA512:
6
- metadata.gz: 3e37d67ae0d3449af0b9027345f66a3783bf8bc11323977b400b1af0de0c77dd56751453047271bb30ce66e7a840a6c65f56e574590697ca71a4c4267be174a3
7
- data.tar.gz: 3662b90bd2de575ba86a799ffb4c547d11132ba93e9655e8d53ae14c078b9e412fbc965404b65cf5665f4f7ee6d2cc3f12dd87de9ee0a92ce6b36ad4cad07fb1
6
+ metadata.gz: cc566b8087de98a2b75454611371bb2fe78d56e6e6fdf257f492fee8babe4fd96442309422be84fce66472e6780ce4cf59e9a20ee1343c73b322b5fff0c6683a
7
+ data.tar.gz: c760c3a573a3617adddcb0cb60b2517f8f27df2100781c172f88c7b8991bb728d4f2d03d0b86b3102b5342044580795bad02e3681bb4b7685de5fd640817e9c6
@@ -0,0 +1,22 @@
1
+ name: Contributor License Agreement (CLA)
2
+
3
+ on:
4
+ pull_request_target:
5
+ types: [opened, synchronize]
6
+ issue_comment:
7
+ types: [created]
8
+
9
+ jobs:
10
+ cla:
11
+ runs-on: ubuntu-latest
12
+ if: |
13
+ (github.event.issue.pull_request
14
+ && !github.event.issue.pull_request.merged_at
15
+ && contains(github.event.comment.body, 'signed')
16
+ )
17
+ || (github.event.pull_request && !github.event.pull_request.merged)
18
+ steps:
19
+ - uses: Shopify/shopify-cla-action@v1
20
+ with:
21
+ github-token: ${{ secrets.GITHUB_TOKEN }}
22
+ cla-token: ${{ secrets.CLA_TOKEN }}
data/CHANGELOG.md CHANGED
@@ -1,10 +1,28 @@
1
1
  Unreleased
2
2
  ----------
3
3
 
4
+ 20.1.0 (August 22, 2022)
5
+ ----------
6
+
7
+ * Set the appropriate CSP `frame-ancestor` directive in controllers using the `EmbeddedApp` concern. [#1474](https://github.com/Shopify/shopify_app/pull/1474)
8
+ * Allow [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/trycloudflare/) hosts in `config/environments/development.rb`.
9
+ * Use [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/trycloudflare/) as example tunnel in readme/docs.
10
+ * Change to optimize OAuth redirects to happen on the server side when possible. Also, add an optional `.embedded_redirect_url` configuration parameter to enable customized App Bridge-supported redirect. [1483](https://github.com/Shopify/shopify_app/pull/1483)
11
+
12
+ 20.0.2 (July 7, 2022)
13
+ ----------
14
+
15
+ * Bump [Shopify API](https://github.com/Shopify/shopify-api-ruby) to version 11.0.1. It includes [these updates](https://github.com/Shopify/shopify-api-ruby/blob/main/CHANGELOG.md#version-1101). Fix an issue where HMAC signature verification would fail in OAuth flows during API key rotation.
16
+
17
+ 20.0.1 (July 6, 2022)
18
+ ----------
19
+
20
+ * Accept extra keyword arguments to WebhooksManagerJob to ease upgrade path from v18 or older (https://github.com/Shopify/shopify_app/pull/1466)
21
+
4
22
  20.0.0 (July 4, 2022)
5
23
  ----------
6
24
 
7
- * Bump [Shopify API](https://github.com/Shopify/shopify-api-ruby) to version 11.0.0. It includes [these updates](https://github.com/Shopify/shopify-api-ruby/blob/main/CHANGELOG.md#version-1100). The breaking change relates to the removal of API version `2021-07` support.
25
+ * Bump [Shopify API](https://github.com/Shopify/shopify-api-ruby) to version 11.0.0. It includes [these updates](https://github.com/Shopify/shopify-api-ruby/blob/main/CHANGELOG.md#version-1100). The breaking change relates to the removal of API version `2021-07` support.
8
26
  * Internal update, adding App Bridge 3 for redirect (only). [#1458](https://github.com/Shopify/shopify_app/pull/1458)
9
27
 
10
28
  19.1.0 (June 20, 2022)
@@ -18,15 +36,15 @@ Unreleased
18
36
  ----------
19
37
 
20
38
  * Fix regression in apps using online tokens. [#1413](https://github.com/Shopify/shopify_app/pull/1413)
21
- * Bump [Shopify API](https://github.com/Shopify/shopify_api) to version 10.0.3. It includes [these fixes](https://github.com/Shopify/shopify_api/blob/main/CHANGELOG.md#version-1003).
39
+ * Bump [Shopify API](https://github.com/Shopify/shopify-api-ruby) to version 10.0.3. It includes [these fixes](https://github.com/Shopify/shopify-api-ruby/blob/main/CHANGELOG.md#version-1003).
22
40
 
23
41
  19.0.1 (April 11, 2022)
24
42
  ----------
25
- * Bump Shopify API (https://github.com/Shopify/shopify_api) to version 10.0.2. This update includes patch fixes since the initial v10 release.
43
+ * Bump Shopify API (https://github.com/Shopify/shopify-api-ruby) to version 10.0.2. This update includes patch fixes since the initial v10 release.
26
44
 
27
45
  19.0.0 (April 6, 2022)
28
46
  ----------
29
- * Use v10 of the Shopify API (https://github.com/Shopify/shopify_api). This update requires changes to an app - please refer to the [migration guide](https://github.com/Shopify/shopify_app/blob/main/docs/Upgrading.md) for details.
47
+ * Use v10 of the Shopify API (https://github.com/Shopify/shopify-api-ruby). This update requires changes to an app - please refer to the [migration guide](https://github.com/Shopify/shopify_app/blob/main/docs/Upgrading.md) for details.
30
48
  BREAKING, please see migration notes.
31
49
 
32
50
  18.1.2 (Mar 3, 2022)
data/Gemfile.lock CHANGED
@@ -1,13 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shopify_app (20.0.0)
4
+ shopify_app (20.1.0)
5
5
  activeresource
6
6
  browser_sniffer (~> 2.0)
7
7
  jwt (>= 2.2.3)
8
8
  rails (> 5.2.1)
9
9
  redirect_safely (~> 1.0)
10
- shopify_api (~> 11.0)
10
+ shopify_api (~> 11.1)
11
11
  sprockets-rails (>= 2.0.0)
12
12
 
13
13
  GEM
@@ -124,7 +124,7 @@ GEM
124
124
  nokogiri (1.13.4)
125
125
  mini_portile2 (~> 2.8.0)
126
126
  racc (~> 1.4)
127
- oj (3.13.15)
127
+ oj (3.13.21)
128
128
  openssl (3.0.0)
129
129
  parallel (1.21.0)
130
130
  parser (3.1.0.0)
@@ -194,7 +194,7 @@ GEM
194
194
  rubocop (~> 1.24)
195
195
  ruby-progressbar (1.11.0)
196
196
  securerandom (0.2.0)
197
- shopify_api (11.0.0)
197
+ shopify_api (11.1.0)
198
198
  concurrent-ruby
199
199
  hash_diff
200
200
  httparty
@@ -204,7 +204,7 @@ GEM
204
204
  securerandom
205
205
  sorbet-runtime
206
206
  zeitwerk (~> 2.5)
207
- sorbet-runtime (0.5.10139)
207
+ sorbet-runtime (0.5.10354)
208
208
  sprockets (4.1.1)
209
209
  concurrent-ruby (~> 1.0)
210
210
  rack (> 1, < 3)
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Shopify App
2
2
 
3
- **Shopify is doubling our engineering staff in 2021! [Join our team and work on libraries like this one.](https://smrtr.io/5GGrK)**
4
-
5
- [![Version][gem]][gem_url] [![Build Status](https://github.com/Shopify/shopify_app/workflows/CI/badge.svg)](https://github.com/Shopify/shopify_app/actions?query=workflow%3ACI) ![Supported Rails version][supported_rails_version]
3
+ [![Version][gem]][gem_url] [![Build Status](https://github.com/Shopify/shopify_app/workflows/CI/badge.svg)](https://github.com/Shopify/shopify_app/actions?query=workflow%3ACI)
6
4
 
7
5
  [gem]: https://img.shields.io/gem/v/shopify_app.svg
8
6
  [gem_url]: https://rubygems.org/gems/shopify_app
@@ -34,6 +32,21 @@ This gem requires that you have the following credentials:
34
32
  - **Shopify API key:** The API key app credential specified in your [Shopify Partners dashboard](https://partners.shopify.com/organizations).
35
33
  - **Shopify API secret:** The API secret key app credential specified in your [Shopify Partners dashboard](https://partners.shopify.com/organizations).
36
34
 
35
+ ### OAuth Tunnel in Development
36
+
37
+ In order to redirect OAuth requests securely to localhost, you'll need to setup a tunnel to redirect from the internet to localhost.
38
+
39
+ We've validated that [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/trycloudflare/) works with this template.
40
+
41
+ To do that, you can [install the `cloudflared` CLI tool](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/), and run:
42
+
43
+ ```shell
44
+ # Note that you can also use a different port
45
+ cloudflared tunnel --url http://localhost:3000
46
+ ```
47
+
48
+ You will need to keep this window running to maintain the tunnel during development.
49
+
37
50
  ## Usage
38
51
 
39
52
  1. To get started, create a new Rails app:
@@ -53,6 +66,7 @@ $ bundle add shopify_app
53
66
  ```
54
67
  SHOPIFY_API_KEY=<Your Shopify API key>
55
68
  SHOPIFY_API_SECRET=<Your Shopify API secret>
69
+ HOST=<Your SSH tunnel host>
56
70
  ```
57
71
 
58
72
  > In a development environment, you can use a gem like `dotenv-rails` to manage environment variables.
@@ -128,4 +142,4 @@ To learn more about how this gem authenticates with Shopify, see [*Authenticatio
128
142
 
129
143
  [Shopify's API is versioned](https://shopify.dev/concepts/about-apis/versioning). With Shopify App `v1.11.0`, the included Shopify API gem allows developers to specify and update the Shopify API version they want their app or service to use. The Shopify API gem also surfaces warnings to Rails apps about [deprecated endpoints, GraphQL fields and more](https://shopify.dev/concepts/about-apis/versioning#deprecation-practices).
130
144
 
131
- See the [Shopify API gem README](https://github.com/Shopify/shopify_api/) for more information.
145
+ See the [Shopify API gem README](https://github.com/Shopify/shopify-api-ruby/) for more information.
@@ -3,6 +3,7 @@
3
3
  module ShopifyApp
4
4
  module RequireKnownShop
5
5
  extend ActiveSupport::Concern
6
+ include ShopifyApp::RedirectForEmbedded
6
7
 
7
8
  included do
8
9
  before_action :check_shop_domain
@@ -11,6 +12,7 @@ module ShopifyApp
11
12
 
12
13
  def current_shopify_domain
13
14
  return if params[:shop].blank?
15
+
14
16
  @shopify_domain ||= ShopifyApp::Utils.sanitize_shop_domain(params[:shop])
15
17
  end
16
18
 
@@ -22,7 +24,13 @@ module ShopifyApp
22
24
 
23
25
  def check_shop_known
24
26
  @shop = SessionRepository.retrieve_shop_session_by_shopify_domain(current_shopify_domain)
25
- redirect_to(shop_login) unless @shop
27
+ unless @shop
28
+ if embedded_param?
29
+ redirect_for_embedded
30
+ else
31
+ redirect_to(shop_login)
32
+ end
33
+ end
26
34
  end
27
35
 
28
36
  def shop_login
@@ -3,6 +3,7 @@
3
3
  module ShopifyApp
4
4
  module ShopAccessScopesVerification
5
5
  extend ActiveSupport::Concern
6
+ include ShopifyApp::RedirectForEmbedded
6
7
 
7
8
  included do
8
9
  before_action :login_on_scope_changes
@@ -11,7 +12,13 @@ module ShopifyApp
11
12
  protected
12
13
 
13
14
  def login_on_scope_changes
14
- redirect_to(shop_login) if scopes_mismatch?
15
+ if scopes_mismatch?
16
+ if embedded_param?
17
+ redirect_for_embedded
18
+ else
19
+ redirect_to(shop_login)
20
+ end
21
+ end
15
22
  end
16
23
 
17
24
  private
@@ -22,6 +29,7 @@ module ShopifyApp
22
29
 
23
30
  def current_shopify_domain
24
31
  return if params[:shop].blank?
32
+
25
33
  ShopifyApp::Utils.sanitize_shop_domain(params[:shop])
26
34
  end
27
35
 
@@ -43,7 +43,12 @@ module ShopifyApp
43
43
  private
44
44
 
45
45
  def respond_successfully
46
- redirect_to(return_address)
46
+ if ShopifyAPI::Context.embedded?
47
+ return_to = session.delete(:return_to) || ""
48
+ redirect_to(ShopifyAPI::Auth.embedded_app_url(params[:host]) + return_to, allow_other_host: true)
49
+ else
50
+ redirect_to(return_address)
51
+ end
47
52
  end
48
53
 
49
54
  def respond_with_error
@@ -58,11 +63,13 @@ module ShopifyApp
58
63
  def start_user_token_flow?(shopify_session)
59
64
  return false unless ShopifyApp::SessionRepository.user_storage.present?
60
65
  return false if shopify_session.online?
66
+
61
67
  update_user_access_scopes?
62
68
  end
63
69
 
64
70
  def update_user_access_scopes?
65
71
  return true if session[:shopify_user_id].nil?
72
+
66
73
  user_access_scopes_strategy.update_access_scopes?(shopify_user_id: session[:shopify_user_id])
67
74
  end
68
75
 
@@ -3,6 +3,7 @@
3
3
  module ShopifyApp
4
4
  class SessionsController < ActionController::Base
5
5
  include ShopifyApp::LoginProtection
6
+ include ShopifyApp::RedirectForEmbedded
6
7
 
7
8
  layout false, only: :new
8
9
 
@@ -36,7 +37,13 @@ module ShopifyApp
36
37
 
37
38
  copy_return_to_param_to_session
38
39
 
39
- if top_level?
40
+ if embedded_redirect_url?
41
+ if embedded_param?
42
+ redirect_for_embedded
43
+ else
44
+ start_oauth
45
+ end
46
+ elsif top_level?
40
47
  start_oauth
41
48
  else
42
49
  redirect_auth_to_top_level
@@ -82,6 +89,7 @@ module ShopifyApp
82
89
 
83
90
  def top_level?
84
91
  return true unless ShopifyApp.configuration.embedded_app?
92
+
85
93
  !params[:top_level].nil?
86
94
  end
87
95
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  ja:
3
- logged_out: ログインに成功しました
3
+ logged_out: ログアウトに成功しました
4
4
  could_not_log_in: Shopifyストアにログインできませんでした
5
5
  invalid_shop_url: ショップのドメインが無効です
6
6
  enable_cookies_heading: "%{app}からのCookieを有効にする"
@@ -10,8 +10,8 @@ ja:
10
10
  top_level_interaction_heading: お使いのブラウザを更新する必要があります%{app}
11
11
  top_level_interaction_body: Shopifyがアプリを開けるように、ブラウザーはCookieにアクセスするための%{app}のようなアプリが必要です。
12
12
  top_level_interaction_action: 続ける
13
- request_storage_access_heading: "%{app}クッキーにアクセスする必要がある"
14
- request_storage_access_body: Cookieを使用すると、個人情報を一時的に保存することで、アプリ認証を受けることができます。[続行]
15
- をクリックして、Cookieでアプリを使用できるようにします。
13
+ request_storage_access_heading: "%{app}はCookieへのアクセス許可が必要です"
14
+ request_storage_access_body: Cookieを使用すると、個人情報を一時的に保存することで、アプリ認証を受けることができます。[続ける]
15
+ をクリックすると、アプリはCookieを利用します。
16
16
  request_storage_access_footer: Cookieは30日後に有効期限が切れます。
17
17
  request_storage_access_action: 続ける
data/docs/Quickstart.md CHANGED
@@ -12,12 +12,13 @@ This guide assumes you have completed the steps to create a new Rails app using
12
12
 
13
13
  Your local app needs to be accessible from the public Internet in order to install it on a Shopify store, to use the [App Proxy Controller](/lib/generators/shopify_app/app_proxy_controller/templates/app_proxy_controller.rb) or receive [webhooks](/docs/shopify_app/webhooks.md).
14
14
 
15
- Use a tunneling service like [ngrok](https://ngrok.com/), [Beeceptor](https://beeceptor.com/), [Mockbin](http://mockbin.org/), or [Hookbin](https://hookbin.com/) to make your development environment accessible to the internet.
15
+ Use a tunneling service like [Cloudflare](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/trycloudflare/) to make your development environment accessible to the internet.
16
16
 
17
- For example with [ngrok](https://ngrok.com/), run this command to set up a tunnel proxy to Rails' default port:
17
+ To use Cloudflare, [install the `cloudflared` CLI tool](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/), and run:
18
18
 
19
- ```sh
20
- ngrok http 3000
19
+ ```shell
20
+ # Note that you can also use a different port
21
+ cloudflared tunnel --url http://localhost:3000
21
22
  ```
22
23
 
23
24
  See the [*Embed the app in Shopify*](https://shopify.dev/tutorials/build-rails-react-app-that-uses-app-bridge-authentication#embed-the-app-in-shopify) section of [*Build a Shopify app with Rails, React, and App Bridge*](https://shopify.dev/tutorials/build-rails-react-app-that-uses-app-bridge-authentication) to learn more.
data/docs/Upgrading.md CHANGED
@@ -4,6 +4,8 @@ This file documents important changes needed to upgrade your app's Shopify App v
4
4
 
5
5
  #### Table of contents
6
6
 
7
+ [Upgrading to `v20.1.0`](#upgrading-to-v2010)
8
+
7
9
  [Upgrading to `v19.0.0`](#upgrading-to-v1900)
8
10
 
9
11
  [Upgrading to `v18.1.2`](#upgrading-to-v1812)
@@ -16,9 +18,18 @@ This file documents important changes needed to upgrade your app's Shopify App v
16
18
 
17
19
  [Upgrading from `v8.6` to `v9.0.0`](#upgrading-from-v86-to-v900)
18
20
 
21
+ ## Upgrading to `v20.1.0`
22
+
23
+ Note that the following steps are *optional* and only apply to **embedded** applications. However, they can improve the loading time of your embedded app at installation and re-auth.
24
+
25
+ - For embedded applications, update any controller that renders a full page reload (e.g: your home controller) to redirect using `Shopify::Auth.embedded_app_url`, if the `embedded` query argument is not present or does not equal `1`. Example [here](https://github.com/Shopify/shopify-app-template-ruby/pull/35/files#)
26
+ - If your app already has a frontend that uses App Bridge, this gem now supports using that to redirect out of the iframe before OAuth. Example [here](https://github.com/Shopify/shopify-frontend-template-react/blob/main/pages/ExitIframe.jsx)
27
+ - In your `shopify_app.rb` initializer, configure `.embedded_redirect_url` to the path of the route you added above.
28
+ - If you don't set this route, then the `shopify_app` gem will automatically load its own copy of App Bridge and perform this redirection without any additional configuration.
29
+
19
30
  ## Upgrading to `v19.0.0`
20
31
 
21
- This update moves API authentication logic from this gem to the [`shopify_api`](https://github.com/Shopify/shopify_api)
32
+ This update moves API authentication logic from this gem to the [`shopify_api`](https://github.com/Shopify/shopify-api-ruby)
22
33
  gem.
23
34
 
24
35
  ### High-level process
@@ -31,7 +42,7 @@ gem.
31
42
  `config/initializers/shopify_app.rb` as the decision logic for which authentication method to use is now handled
32
43
  internally by the `shopify_api` gem, using the `ShopifyAPI::Context.embedded_app` setting.
33
44
  - `v19.0.0` updates the `shopify_api` dependency to `10.0.0`. This version of `shopify_api` has breaking changes. See
34
- the documentation for addressing these breaking changes on GitHub [here](https://github.com/Shopify/shopify_api#breaking-change-notice-for-version-1000).
45
+ the documentation for addressing these breaking changes on GitHub [here](https://github.com/Shopify/shopify-api-ruby#breaking-change-notice-for-version-1000).
35
46
 
36
47
  ### Specific cases
37
48
 
@@ -87,6 +98,7 @@ Rails.application.config.after_initialize do
87
98
  ShopifyAPI::Context.setup(
88
99
  api_key: ShopifyApp.configuration.api_key,
89
100
  api_secret_key: ShopifyApp.configuration.secret,
101
+ old_api_secret_key: ShopifyApp.configuration.old_secret,
90
102
  api_version: ShopifyApp.configuration.api_version,
91
103
  host_name: URI(ENV.fetch('HOST', '')).host || '',
92
104
  scope: ShopifyApp.configuration.scope,
@@ -222,7 +234,7 @@ is changed to
222
234
 
223
235
  ### ShopifyAPI changes
224
236
 
225
- You will need to also follow the ShopifyAPI [upgrade guide](https://github.com/Shopify/shopify_api/blob/master/README.md#-breaking-change-notice-for-version-700-) to ensure your app is ready to work with API versioning.
237
+ You will need to also follow the ShopifyAPI [upgrade guide](https://github.com/Shopify/shopify-api-ruby/blob/master/README.md#-breaking-change-notice-for-version-700-) to ensure your app is ready to work with API versioning.
226
238
 
227
239
  [dashboard]: https://partners.shopify.com
228
240
  [app-bridge]: https://shopify.dev/apps/tools/app-bridge
@@ -6,7 +6,11 @@ class HomeController < ApplicationController
6
6
  include ShopifyApp::ShopAccessScopesVerification
7
7
 
8
8
  def index
9
- @shop_origin = current_shopify_domain
10
- @host = params[:host]
9
+ if ShopifyAPI::Context.embedded? && (!params[:embedded].present? || params[:embedded] != "1")
10
+ redirect_to(ShopifyAPI::Auth.embedded_app_url(params[:host]) + request.path, allow_other_host: true)
11
+ else
12
+ @shop_origin = current_shopify_domain
13
+ @host = params[:host]
14
+ end
11
15
  end
12
16
  end
@@ -13,6 +13,9 @@ module ShopifyApp
13
13
  class_option :embedded, type: :string, default: "true"
14
14
  class_option :api_version, type: :string, default: nil
15
15
 
16
+ NGROK_HOST = "/\[-\\w]+\\.ngrok\\.io/"
17
+ CLOUDFLARE_HOST = "/\[-\\w]+\\.trycloudflare\\.com/"
18
+
16
19
  def create_shopify_app_initializer
17
20
  @application_name = format_array_argument(options["application_name"])
18
21
  @scope = format_array_argument(options["scope"])
@@ -51,14 +54,34 @@ module ShopifyApp
51
54
  end
52
55
 
53
56
  def insert_hosts_into_development_config
57
+ "Rails.application.configure do\n"
58
+ .then { insert_tunnel_host_rules("ngrok", _1, NGROK_HOST + "\n") }
59
+ .then { insert_tunnel_host_rules("Cloudflare", _1, CLOUDFLARE_HOST + "\n") }
60
+ end
61
+
62
+ private
63
+
64
+ def add_comment_explaining_tunnel_host(provider_name, insert_after_line)
65
+ comment = " # Allow #{provider_name} tunnels for secure Shopify OAuth redirects\n"
54
66
  inject_into_file(
55
67
  "config/environments/development.rb",
56
- " config.hosts = (config.hosts rescue []) << /\[-\\w]+\\.ngrok\\.io/\n",
57
- after: "Rails.application.configure do\n"
68
+ comment,
69
+ after: insert_after_line
58
70
  )
71
+ comment
59
72
  end
60
73
 
61
- private
74
+ def insert_tunnel_host_rules(provider_name, insert_after_line, provider_host_domain)
75
+ explaination_comment = add_comment_explaining_tunnel_host(provider_name, insert_after_line)
76
+ host_line = " config.hosts = (config.hosts rescue []) << #{provider_host_domain}"
77
+
78
+ inject_into_file(
79
+ "config/environments/development.rb",
80
+ host_line,
81
+ after: explaination_comment
82
+ )
83
+ host_line
84
+ end
62
85
 
63
86
  def embedded_app?
64
87
  options["embedded"] == "true"
@@ -9,6 +9,7 @@ module ShopifyApp
9
9
  def update_access_scopes?(user_id: nil, shopify_user_id: nil)
10
10
  return update_access_scopes_for_user_id?(user_id) if user_id
11
11
  return update_access_scopes_for_shopify_user_id?(shopify_user_id) if shopify_user_id
12
+
12
13
  raise(InvalidInput, "#update_access_scopes? requires user_id or shopify_user_id parameter inputs")
13
14
  end
14
15
 
@@ -25,6 +25,7 @@ module ShopifyApp
25
25
  attr_accessor :root_url
26
26
  attr_writer :login_url
27
27
  attr_writer :login_callback_url
28
+ attr_accessor :embedded_redirect_url
28
29
 
29
30
  # customise ActiveJob queue names
30
31
  attr_accessor :scripttags_manager_queue_name
@@ -77,11 +78,13 @@ module ShopifyApp
77
78
 
78
79
  def shop_access_scopes_strategy
79
80
  return ShopifyApp::AccessScopes::NoopStrategy unless reauth_on_access_scope_changes
81
+
80
82
  ShopifyApp::AccessScopes::ShopStrategy
81
83
  end
82
84
 
83
85
  def user_access_scopes_strategy
84
86
  return ShopifyApp::AccessScopes::NoopStrategy unless reauth_on_access_scope_changes
87
+
85
88
  ShopifyApp::AccessScopes::UserStrategy
86
89
  end
87
90
 
@@ -4,6 +4,8 @@ module ShopifyApp
4
4
  module EmbeddedApp
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ include ShopifyApp::FrameAncestors
8
+
7
9
  included do
8
10
  if ShopifyApp.configuration.embedded_app?
9
11
  after_action(:set_esdk_headers)
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShopifyApp
4
+ module FrameAncestors
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ content_security_policy do |policy|
9
+ policy.frame_ancestors(-> do
10
+ domain_host = current_shopify_domain || "*.myshopify.com"
11
+ "https://#{domain_host} https://admin.shopify.com;"
12
+ end)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -6,6 +6,7 @@ module ShopifyApp
6
6
  module LoginProtection
7
7
  extend ActiveSupport::Concern
8
8
  include ShopifyApp::Itp
9
+ include ShopifyApp::SanitizedParams
9
10
 
10
11
  class ShopifyDomainNotFound < StandardError; end
11
12
 
@@ -56,6 +57,7 @@ module ShopifyApp
56
57
 
57
58
  def login_again_if_different_user_or_shop
58
59
  return unless session_id_conflicts_with_params || session_shop_conflicts_with_params
60
+
59
61
  clear_shopify_session
60
62
  redirect_to_login
61
63
  end
@@ -67,6 +69,7 @@ module ShopifyApp
67
69
  def jwt_expire_at
68
70
  expire_at = request.env["jwt.expire_at"]
69
71
  return unless expire_at
72
+
70
73
  expire_at - 5.seconds # 5s gap to start fetching new token in advance
71
74
  end
72
75
 
@@ -193,34 +196,6 @@ module ShopifyApp
193
196
  raise ShopifyDomainNotFound
194
197
  end
195
198
 
196
- def sanitized_shop_name
197
- @sanitized_shop_name ||= sanitize_shop_param(params)
198
- end
199
-
200
- def referer_sanitized_shop_name
201
- return unless request.referer.present?
202
-
203
- @referer_sanitized_shop_name ||= begin
204
- referer_uri = URI(request.referer)
205
- query_params = Rack::Utils.parse_query(referer_uri.query)
206
-
207
- sanitize_shop_param(query_params.with_indifferent_access)
208
- end
209
- end
210
-
211
- def sanitize_shop_param(params)
212
- return unless params[:shop].present?
213
- ShopifyApp::Utils.sanitize_shop_domain(params[:shop])
214
- end
215
-
216
- def sanitized_params
217
- request.query_parameters.clone.tap do |query_params|
218
- if params[:shop].is_a?(String)
219
- query_params[:shop] = sanitize_shop_param(params)
220
- end
221
- end
222
- end
223
-
224
199
  def return_address
225
200
  return_address_with_params(shop: current_shopify_domain, host: host)
226
201
  rescue ShopifyDomainNotFound, ShopifyHostNotFound
@@ -259,6 +234,7 @@ module ShopifyApp
259
234
  def user_session_expected?
260
235
  return false if shop_session.nil?
261
236
  return false if ShopifyApp.configuration.shop_access_scopes_strategy.update_access_scopes?(shop_session.shop)
237
+
262
238
  !ShopifyApp.configuration.user_session_repository.blank? && ShopifyApp::SessionRepository.user_storage.present?
263
239
  end
264
240
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShopifyApp
4
+ module RedirectForEmbedded
5
+ include ShopifyApp::SanitizedParams
6
+
7
+ private
8
+
9
+ def embedded_redirect_url?
10
+ ShopifyApp.configuration.embedded_redirect_url.present?
11
+ end
12
+
13
+ def embedded_param?
14
+ embedded_redirect_url? && params[:embedded].present? && params[:embedded] == "1"
15
+ end
16
+
17
+ def redirect_for_embedded
18
+ redirect_to(redirect_uri_for_embedded)
19
+ end
20
+
21
+ def redirect_uri_for_embedded
22
+ redirect_query_params = {}
23
+ redirect_uri = "https://#{ShopifyAPI::Context.host_name}#{ShopifyApp.configuration.login_url}"
24
+ redirect_query_params[:shop] = sanitized_shop_name
25
+ redirect_query_params[:shop] ||= referer_sanitized_shop_name if referer_sanitized_shop_name.present?
26
+ redirect_query_params[:host] ||= params[:host] if params[:host].present?
27
+ redirect_uri = "#{redirect_uri}?#{redirect_query_params.to_query}" if redirect_query_params.present?
28
+
29
+ query_params = sanitized_params.except(:redirect_uri, :embedded)
30
+ query_params[:redirectUri] = redirect_uri
31
+
32
+ "#{ShopifyApp.configuration.embedded_redirect_url}?#{query_params.to_query}"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShopifyApp
4
+ module SanitizedParams
5
+ protected
6
+
7
+ def sanitized_shop_name
8
+ @sanitized_shop_name ||= sanitize_shop_param(params)
9
+ end
10
+
11
+ def referer_sanitized_shop_name
12
+ return unless request.referer.present?
13
+
14
+ @referer_sanitized_shop_name ||= begin
15
+ referer_uri = URI(request.referer)
16
+ query_params = Rack::Utils.parse_query(referer_uri.query)
17
+
18
+ sanitize_shop_param(query_params.with_indifferent_access)
19
+ end
20
+ end
21
+
22
+ def sanitize_shop_param(params)
23
+ return unless params[:shop].present?
24
+ ShopifyApp::Utils.sanitize_shop_domain(params[:shop])
25
+ end
26
+
27
+ def sanitized_params
28
+ request.query_parameters.clone.tap do |query_params|
29
+ if params[:shop].is_a?(String)
30
+ query_params[:shop] = sanitize_shop_param(params)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -7,6 +7,7 @@ module ShopifyApp
7
7
  def args_info(job)
8
8
  log_disabled_classes = ["ShopifyApp::ScripttagsManagerJob", "ShopifyApp::WebhooksManagerJob"]
9
9
  return "" if log_disabled_classes.include?(job.class.name)
10
+
10
11
  super
11
12
  end
12
13
  end
@@ -6,7 +6,7 @@ module ShopifyApp
6
6
  ShopifyApp.configuration.webhooks_manager_queue_name
7
7
  end
8
8
 
9
- def perform(shop_domain:, shop_token:)
9
+ def perform(shop_domain:, shop_token:, **)
10
10
  ShopifyAPI::Auth::Session.temp(shop: shop_domain, access_token: shop_token) do |session|
11
11
  WebhooksManager.create_webhooks(session: session)
12
12
  end
@@ -16,6 +16,7 @@ module ShopifyApp
16
16
  def self.build_src(scripttags, domain)
17
17
  scripttags.map do |tag|
18
18
  next tag unless tag[:src].respond_to?(:call)
19
+
19
20
  tag = tag.dup
20
21
  tag[:src] = tag[:src].call(domain)
21
22
  tag
@@ -14,12 +14,14 @@ module ShopifyApp
14
14
 
15
15
  def create_webhooks(session:)
16
16
  return unless ShopifyApp.configuration.has_webhooks?
17
+
17
18
  ShopifyAPI::Webhooks::Registry.register_all(session: session)
18
19
  end
19
20
 
20
21
  def recreate_webhooks!(session:)
21
22
  destroy_webhooks
22
23
  return unless ShopifyApp.configuration.has_webhooks?
24
+
23
25
  add_registrations
24
26
  ShopifyAPI::Webhooks::Registry.register_all(session: session)
25
27
  end
@@ -81,11 +81,13 @@ module ShopifyApp
81
81
 
82
82
  def load_shop_storage
83
83
  return unless @shop_storage
84
+
84
85
  @shop_storage.respond_to?(:safe_constantize) ? @shop_storage.safe_constantize : @shop_storage
85
86
  end
86
87
 
87
88
  def load_user_storage
88
89
  return NullUserSessionStore unless @user_storage
90
+
89
91
  @user_storage.respond_to?(:safe_constantize) ? @user_storage.safe_constantize : @user_storage
90
92
  end
91
93
  end
@@ -16,6 +16,7 @@ module ShopifyApp
16
16
 
17
17
  def self.shop_login_url(shop:, host:, return_to:)
18
18
  return ShopifyApp.configuration.login_url unless shop
19
+
19
20
  url = URI(ShopifyApp.configuration.login_url)
20
21
 
21
22
  url.query = URI.encode_www_form(
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ShopifyApp
4
- VERSION = "20.0.0"
4
+ VERSION = "20.1.0"
5
5
  end
data/lib/shopify_app.rb CHANGED
@@ -37,7 +37,10 @@ module ShopifyApp
37
37
  # controller concerns
38
38
  require "shopify_app/controller_concerns/csrf_protection"
39
39
  require "shopify_app/controller_concerns/localization"
40
+ require "shopify_app/controller_concerns/frame_ancestors"
40
41
  require "shopify_app/controller_concerns/itp"
42
+ require "shopify_app/controller_concerns/sanitized_params"
43
+ require "shopify_app/controller_concerns/redirect_for_embedded"
41
44
  require "shopify_app/controller_concerns/login_protection"
42
45
  require "shopify_app/controller_concerns/ensure_billing"
43
46
  require "shopify_app/controller_concerns/embedded_app"
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shopify_app",
3
- "version": "20.0.0",
3
+ "version": "20.1.0",
4
4
  "repository": "git@github.com:Shopify/shopify_app.git",
5
5
  "author": "Shopify",
6
6
  "license": "MIT",
data/service.yml CHANGED
@@ -1,4 +1,3 @@
1
1
  audience: partner
2
- classification: library
3
2
  slack_channels:
4
3
  - shopify_app_gem
data/shopify_app.gemspec CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.add_runtime_dependency("jwt", ">= 2.2.3")
20
20
  s.add_runtime_dependency("rails", "> 5.2.1")
21
21
  s.add_runtime_dependency("redirect_safely", "~> 1.0")
22
- s.add_runtime_dependency("shopify_api", "~> 11.0")
22
+ s.add_runtime_dependency("shopify_api", "~> 11.1")
23
23
  s.add_runtime_dependency("sprockets-rails", ">= 2.0.0")
24
24
 
25
25
  s.add_development_dependency("byebug")
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: 20.0.0
4
+ version: 20.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-04 00:00:00.000000000 Z
11
+ date: 2022-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activeresource
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '11.0'
89
+ version: '11.1'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '11.0'
96
+ version: '11.1'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: sprockets-rails
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -260,8 +260,8 @@ files:
260
260
  - ".github/ISSUE_TEMPLATE/config.yml"
261
261
  - ".github/ISSUE_TEMPLATE/feature-request.md"
262
262
  - ".github/PULL_REQUEST_TEMPLATE.md"
263
- - ".github/probots.yml"
264
263
  - ".github/workflows/build.yml"
264
+ - ".github/workflows/cla.yml"
265
265
  - ".github/workflows/release.yml"
266
266
  - ".github/workflows/rubocop.yml"
267
267
  - ".gitignore"
@@ -401,10 +401,13 @@ files:
401
401
  - lib/shopify_app/controller_concerns/csrf_protection.rb
402
402
  - lib/shopify_app/controller_concerns/embedded_app.rb
403
403
  - lib/shopify_app/controller_concerns/ensure_billing.rb
404
+ - lib/shopify_app/controller_concerns/frame_ancestors.rb
404
405
  - lib/shopify_app/controller_concerns/itp.rb
405
406
  - lib/shopify_app/controller_concerns/localization.rb
406
407
  - lib/shopify_app/controller_concerns/login_protection.rb
407
408
  - lib/shopify_app/controller_concerns/payload_verification.rb
409
+ - lib/shopify_app/controller_concerns/redirect_for_embedded.rb
410
+ - lib/shopify_app/controller_concerns/sanitized_params.rb
408
411
  - lib/shopify_app/controller_concerns/webhook_verification.rb
409
412
  - lib/shopify_app/engine.rb
410
413
  - lib/shopify_app/jobs/scripttags_manager_job.rb
data/.github/probots.yml DELETED
@@ -1,2 +0,0 @@
1
- enabled:
2
- - cla