shopify_app 11.5.1 → 12.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -0
  3. data/README.md +122 -115
  4. data/app/assets/javascripts/shopify_app/itp_helper.js +6 -6
  5. data/app/assets/javascripts/shopify_app/storage_access.js +35 -6
  6. data/app/controllers/concerns/shopify_app/authenticated.rb +1 -1
  7. data/app/controllers/shopify_app/callback_controller.rb +8 -2
  8. data/app/controllers/shopify_app/extension_verification_controller.rb +20 -0
  9. data/app/controllers/shopify_app/sessions_controller.rb +8 -6
  10. data/app/views/shopify_app/sessions/enable_cookies.html.erb +1 -1
  11. data/app/views/shopify_app/sessions/request_storage_access.html.erb +1 -1
  12. data/config/locales/pt-BR.yml +1 -1
  13. data/docs/Quickstart.md +44 -16
  14. data/docs/install-on-dev-shop.png +0 -0
  15. data/docs/test-your-app.png +0 -0
  16. data/lib/generators/shopify_app/add_marketing_activity_extension/templates/marketing_activities_controller.rb +2 -6
  17. data/lib/generators/shopify_app/home_controller/home_controller_generator.rb +0 -6
  18. data/lib/generators/shopify_app/install/templates/embedded_app.html.erb +2 -2
  19. data/lib/generators/shopify_app/install/templates/flash_messages.js +11 -2
  20. data/lib/generators/shopify_app/install/templates/shopify_app.js +9 -3
  21. data/lib/generators/shopify_app/install/templates/shopify_provider.rb +1 -0
  22. data/lib/generators/shopify_app/user_model/templates/db/migrate/create_users.erb +16 -0
  23. data/lib/generators/shopify_app/user_model/templates/user.rb +7 -0
  24. data/lib/generators/shopify_app/user_model/templates/users.yml +4 -0
  25. data/lib/generators/shopify_app/user_model/user_model_generator.rb +38 -0
  26. data/lib/shopify_app.rb +5 -3
  27. data/lib/shopify_app/configuration.rb +10 -0
  28. data/lib/shopify_app/controller_concerns/login_protection.rb +33 -6
  29. data/lib/shopify_app/engine.rb +4 -0
  30. data/lib/shopify_app/middleware/same_site_cookie_middleware.rb +60 -0
  31. data/lib/shopify_app/session/in_memory_session_store.rb +1 -1
  32. data/lib/shopify_app/session/session_repository.rb +2 -2
  33. data/lib/shopify_app/session/session_storage.rb +10 -22
  34. data/lib/shopify_app/session/storage_strategies/shop_storage_strategy.rb +23 -0
  35. data/lib/shopify_app/session/storage_strategies/user_storage_strategy.rb +24 -0
  36. data/lib/shopify_app/version.rb +1 -1
  37. data/package.json +1 -0
  38. data/service.yml +1 -1
  39. data/shopify_app.gemspec +5 -2
  40. metadata +56 -6
  41. data/lib/generators/shopify_app/home_controller/templates/shopify_app_ready_script.html.erb +0 -7
  42. data/lib/shopify_app/controllers/extension_verification_controller.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f2c7003fc52f7cdca6ab2ecd68fd087aee28e63e8bfbdc59ea7ca82886f28b8
4
- data.tar.gz: b967b29d2122d732af04ef1aeb3fcf814fe53fd5103b124009bfad0daf2d298b
3
+ metadata.gz: e21696bedf0e9066e0363ffa54535563d57b04990c4fd8c39f61b24c9e7dd5a5
4
+ data.tar.gz: 0557a4eb040fe7dcc68b576ab90237902c4ec2a7e60f5352607a1753a2dc4d7b
5
5
  SHA512:
6
- metadata.gz: 325bc337b2be96e0cd91250ee19ddbed0ac34baf2c0bcea995f4b78048738e9a3d638e95334b55bb28e3350eb20365d1f9f2fcfe698356d338e2551797a7877c
7
- data.tar.gz: 7781e846d38666203e63eb6d17f182cea70a9011a5c5dec6b3b0dc540ae5473a21ae8f13fb82719435691b87e14c4981135d4f4e984e09a34cbd81316e89996a
6
+ metadata.gz: 4adc7c54f7662d8c4427012de16b9aa2bafd3c984ea4bf13d77c36722035f32ed3fe9a00b7d45c4dacad24a4d99d2b3939defcc7a0eeaea99efeed3be2f771a2
7
+ data.tar.gz: 2ae0baab7a365863bfc0530a4264b6397f59d447db24ba59fda93f455b44582fd432c2525fc064285b7c314f5bcbd6883568e2cd28460922911d14f340834228
@@ -1,3 +1,31 @@
1
+ 12.0.1
2
+ ------
3
+ * disable samesite cookie middleware in tests
4
+ * middleware compatibility for ruby 2.3
5
+ * samesite cookie fixes for javascript libraries
6
+ * change generators to add AppBridge instead of EASDK
7
+ * Fix for return_to in safari after enable_cookies/granted_storage_access
8
+
9
+ 12.0.0
10
+ -----
11
+ * Updating shopify_api gem to 9.0.0
12
+
13
+ 11.7.1
14
+ -----
15
+ * Fix to allow SessionStorage to be flexible on what model names that the are used for storing shop and user data
16
+
17
+ 11.7.0
18
+ -----
19
+ * Move ExtensionVerificationController from engine to app controllers, as being in the engine makes ActionController::Base get loaded before app initiates [#855](https://github.com/Shopify/shopify_app/pull/855)
20
+ * Add back per-user token support (added in 11.5.0, reverted in 11.5.1)
21
+ * If you have an override on the `self.store(auth_session)` method on your `SessionRepository` model, the method signature must be changed as according to this [change](https://github.com/Shopify/shopify_app/pull/856/files#diff-deaed2b262ec885f4e36de05621e41eaR18)
22
+
23
+ 11.6.0
24
+ -----
25
+ * Enable SameSite=None; Secure by default on all cookies for embedded apps [#851](https://github.com/Shopify/shopify_app/pull/851)
26
+ * Ensures compatibility of embedded apps with upcoming Chrome version 80 changes to cookie behaviour
27
+ * Configurable via `ShopifyApp.configuration.enable_same_site_none` (default true for embedded apps)
28
+
1
29
  11.5.1
2
30
  -----
3
31
  * Revert per-user token support temporarily
data/README.md CHANGED
@@ -12,70 +12,44 @@ Shopify Application Rails engine and generator
12
12
 
13
13
  Table of Contents
14
14
  -----------------
15
- * [**Description**](#description)
16
- * [**Quickstart**](#quickstart)
17
- * [**Becoming a Shopify App Developer**](#becoming-a-shopify-app-developer)
18
- * [**App Tunneling**](#app-tunneling)
19
- * [**Installation**](#installation)
20
- * [Rails Compatibility](#rails-compatibility)
21
- * [**Generators**](#generators)
22
- * [Default Generator](#default-generator)
23
- * [Install Generator](#install-generator)
24
- * [Shop Model Generator](#shop-model-generator)
25
- * [Home Controller Generator](#home-controller-generator)
26
- * [App Proxy Controller Generator](#app-proxy-controller-generator)
27
- * [Controllers, Routes and Views](#controllers-routes-and-views)
28
- * [**Mounting the Engine**](#mounting-the-engine)
29
- * [**WebhooksManager**](#webhooksmanager)
30
- * [**ScripttagsManager**](#scripttagsmanager)
31
- * [**AfterAuthenticate Job**](#afterauthenticate-job)
32
- * [**ShopifyApp::SessionRepository**](#shopifyappsessionrepository)
33
- * [**Authenticated**](#authenticated)
34
- * [**AppProxyVerification**](#appproxyverification)
35
- * [Recommended Usage](#recommended-usage)
36
- * [**Upgrading from 8.6 to 9.0.0**](#upgrading-from-86-to-900)
37
- * [**Troubleshooting**](#troubleshooting)
38
- * [Generator shopify_app:install hangs](#generator-shopify_appinstall-hangs)
39
- * [**Testing an embedded app outside the Shopify admin**](#testing-an-embedded-app-outside-the-shopify-admin)
40
- * [**Questions or problems?**](#questions-or-problems)
41
-
42
-
43
- Description
15
+ - [Introduction](#introduction)
16
+ - [Become a Shopify App Developer](#become-a-shopify-app-developer)
17
+ - [Installation](#installation)
18
+ - [Generators](#generators)
19
+ - [Mounting the Engine](#mounting-the-engine)
20
+ - [Authentication](#authentication)
21
+ - [WebhooksManager](#webhooksmanager)
22
+ - [ScripttagsManager](#scripttagsmanager)
23
+ - [RotateShopifyTokenJob](#rotateshopifytokenjob)
24
+ - [App Tunneling](#app-tunneling)
25
+ - [AppProxyVerification](#appproxyverification)
26
+ - [Troubleshooting](#troubleshooting)
27
+ - [Testing an embedded app outside the Shopify admin](#testing-an-embedded-app-outside-the-shopify-admin)
28
+ - [Questions or problems?](#questions-or-problems-)
29
+ - [Rails 6 Compatibility](#rails-6-compatibility)
30
+ - [Upgrading from 8.6 to 9.0.0](#upgrading-from-86-to-900)
31
+
32
+ Introduction
44
33
  -----------
45
- This gem includes a Rails Engine and generators for writing Rails applications using the Shopify API. The Engine provides a SessionsController and all the required code for authenticating with a shop via Oauth (other authentication methods are not supported).
34
+ Get started with the [Shopify Admin API](https://help.shopify.com/en/api/getting-started) faster; This gem includes a Rails Engine and generators for writing Rails applications using the Shopify API. The Engine provides a SessionsController and all the required code for authenticating with a shop via Oauth (other authentication methods are not supported).
46
35
 
47
- *Note: It's recommended to use this on a new Rails project, so that the generator won't overwrite/delete some of your files.*
36
+ *Note: It's recommended to use this on a new Rails project, so that the generator won't overwrite/delete your files.*
48
37
 
49
-
50
- Quickstart
51
- ----------
52
-
53
- Check out this screencast on how to create and deploy a new Shopify App to Heroku in 5 minutes:
38
+ Learn how to create and deploy a new Shopify App to Heroku with our [quickstart guide](https://github.com/Shopify/shopify_app/blob/master/docs/Quickstart.md), or dive in in less than 5 minutes with this quickstart video:
54
39
 
55
40
  [https://www.youtube.com/watch?v=yGxeoAHlQOg](https://www.youtube.com/watch?v=yGxeoAHlQOg)
56
41
 
57
- Or if you prefer text instructions the steps in the video are written out [here](https://github.com/Shopify/shopify_app/blob/master/docs/Quickstart.md)
58
-
59
- App Tunneling
60
- -------------
61
-
62
- Your local app needs to be accessible from the public Internet in order to install it on a shop, use the [App Proxy Controller](#app-proxy-controller-generator) or receive Webhooks. Use a tunneling service like [ngrok](https://ngrok.com/), [Forward](https://forwardhq.com/), [Beeceptor](https://beeceptor.com/), [Mockbin](http://mockbin.org/), [Hookbin](https://hookbin.com/), etc.
63
-
64
- For example with [ngrok](https://ngrok.com/), run this command to set up proxying to Rails' default port:
65
-
66
- ```sh
67
- ngrok http 3000
68
- ```
69
-
70
- Becoming a Shopify App Developer
42
+ Become a Shopify App Developer
71
43
  --------------------------------
72
- If you don't have a Shopify Partner account yet head over to http://shopify.com/partners to create one, you'll need it before you can start developing apps.
44
+ To become a Shopify App Developer you'll need a [Shopify Partner account.](http://shopify.com/partners) If you don't have a Shopify Partner account, head to http://shopify.com/partners to create one before you start.
45
+
46
+ Once you have a Partner account, [create a new application in the Partner Dashboard](https://help.shopify.com/en/api/tools/partner-dashboard/your-apps) to get an API key and other API credentials.
73
47
 
74
- Once you have a Partner account create a new application to get an API key and other API credentials. To create a development application set the `App URL` to the URL provided by [your tunnel](#app-tunneling) or `http://localhost:3000/` if you are not embeddeding your app inside the admin or receiving webhooks and the `Whitelisted redirection URL(s)` to contain `<App URL>/auth/shopify/callback`. Ensure you are using `https://` URLs if you are using tunneling.
48
+ To create an application for development set your new app's `App URL` to the URL provided by [your tunnel](#app-tunneling), ensuring that you use `https://`. If you are not planning to embed your app inside the Shopify admin or receive webhooks, set your redirect URL to `http://localhost:3000/` and the `Whitelisted redirection URL(s)` to contain `<App URL>/auth/shopify/callback`.
75
49
 
76
50
  Installation
77
51
  ------------
78
- To get started add shopify_app to your Gemfile and bundle install
52
+ To get started add `shopify_app` to your Gemfile and run `bundle install`:
79
53
 
80
54
  ``` sh
81
55
  # Create a new rails app
@@ -87,7 +61,7 @@ $ echo "gem 'shopify_app'" >> Gemfile
87
61
  $ bundle install
88
62
  ```
89
63
 
90
- Now we are ready to run any of the shopify_app generators. The following section explains the generators and what they can do.
64
+ Now we are ready to run any of the [generators](#generators) included with `shopify_app`. The following section explains the generators and what you can do with them.
91
65
 
92
66
 
93
67
  #### Rails Compatibility
@@ -100,24 +74,24 @@ Generators
100
74
 
101
75
  ### Default Generator
102
76
 
103
- The default generator will run the `install`, `shop`, and `home_controller` generators. This is the recommended way to start your app.
77
+ The default generator will run the `install`, `shop`, and `home_controller` generators. This is the recommended way to start a new app from scratch:
104
78
 
105
79
  ```sh
106
80
  $ rails generate shopify_app
107
81
  ```
108
82
 
109
- After running the generator, you will need to run `rake db:migrate` to add tables to your database. You can start your app with `bundle exec rails server` and install your app by visiting localhost.
83
+ After running the generator, you will need to run `rails db:migrate` to add new tables to your database. You can start your app with `bundle exec rails server` and install your app by visiting `http://localhost` in your web browser.
110
84
 
111
85
  ### API Keys
112
86
 
113
- The default and install generators have been updated to source Shopify API key and secret from a `.env` file, which you will need to create with the following format:
87
+ The default and install generators have been updated to source Shopify API key and secret from an Environment (`.env`) variables file, which you will need to create with the following format:
114
88
 
115
89
  ```
116
90
  SHOPIFY_API_KEY=your api key
117
91
  SHOPIFY_API_SECRET=your api secret
118
92
  ```
119
93
 
120
- These values can be found on the "App Setup" page in the [Shopify Partners Dashboard][dashboard].
94
+ These values can be found on the "App Setup" page in the [Shopify Partners Dashboard][dashboard]. If you are checking your code into a code repository, ensure your `.gitignore` prevents your `.env` file from being checked into any publicly accessible code.
121
95
 
122
96
  ### Install Generator
123
97
 
@@ -143,24 +117,13 @@ The generator adds ShopifyApp and the required initializers to the host Rails ap
143
117
  After running the `install` generator, you can start your app with `bundle exec rails server` and install your app by visiting localhost.
144
118
 
145
119
 
146
- ### Shop Model Generator
147
-
148
- ```sh
149
- $ rails generate shopify_app:shop_model
150
- ```
151
-
152
- The `install` generator doesn't create any database tables or models for you. If you are starting a new app its quite likely that you will want a shops table and model to store the tokens when your app is installed (most of our internally developed apps do!). This generator creates a shop model and a migration. This model includes the `ShopifyApp::SessionStorage` concern which adds two methods to make it compatible as a `SessionRepository`. After running this generator you'll notice the `session_repository` in your `config/initializers/shopify_app.rb` will be set to the `Shop` model. This means that internally ShopifyApp will try and load tokens from this model.
153
-
154
- *Note that you will need to run rake db:migrate after this generator*
155
-
156
-
157
120
  ### Home Controller Generator
158
121
 
159
122
  ```sh
160
123
  $ rails generate shopify_app:home_controller
161
124
  ```
162
125
 
163
- This generator creates an example home controller and view which fetches and displays products using the ShopifyAPI
126
+ This generator creates an example home controller and view which fetches and displays products using the Shopify API
164
127
 
165
128
 
166
129
  ### App Proxy Controller Generator
@@ -245,21 +208,84 @@ ShopifyApp.configure do |config|
245
208
  end
246
209
  ```
247
210
 
248
- Per User Authentication
249
- -----------------------
250
- To enable per user authentication you need to update the `omniauth.rb` initializer:
211
+ Authentication
212
+ --------------
213
+
214
+ ### ShopifyApp::SessionRepository
215
+
216
+ `ShopifyApp::SessionRepository` allows you as a developer to define how your sessions are stored and retrieved for shops. The `SessionRepository` is configured in the `config/initializers/shopify_app.rb` file and can be set to any object that implements `self.store(auth_session, *args)` which stores the session and returns a unique identifier and `self.retrieve(id)` which returns a `ShopifyAPI::Session` for the passed id. These methods are already implemented as part of the `ShopifyApp::SessionStorage` concern, but can be overridden for custom implementation.
217
+
218
+ If you only run the install generator then by default you will have an in memory store but it **won't work** on multi-server environments including Heroku. For multi-server environments, implement one of the following token-storage strategies.
219
+
220
+ #### Shop-based token storage
221
+ Storing tokens on the store model means that any user login associated to the store will have equal access levels to whatever the original user granted the app.
222
+ ```sh
223
+ $ rails generate shopify_app:shop_model
224
+ ```
225
+ This will generate a shop model which will be the storage for the tokens necessary for authentication.
226
+
227
+ #### User-based token storage
228
+ A more granular control over level of access per user on an app might be necessary, to which the shop-based token strategy is not sufficient. Shopify supports a user-based token storage strategy where a unique token to each user can be managed.
229
+ ```sh
230
+ $ rails generate shopify_app:user_model
231
+ ```
232
+ This will generate a user model which will be the storage for the tokens necessary for authentication.
233
+
234
+ The current Shopify user will be stored in the rails session at `session[:shopify_user]`
235
+
236
+ In this mode, The `self.store(auth_session, *args)` will be invoked with a Shopify User object hash, which is then used to store the token as part of a user record, rather than a store record.
237
+
238
+ This will change the type of token that Shopify returns and it will only be valid for a short time. Read more about `Online access` [here](https://help.shopify.com/api/getting-started/authentication/oauth). Note that this means you won't be able to use this token to respond to Webhooks.
239
+
240
+ #### Migrating from shop-based to user-based token strategy
241
+ After running the generator, ensure that configuration settings are successfully changed:
251
242
 
252
243
  ```ruby
244
+ # In the `omniauth.rb` initializer:
253
245
  provider :shopify,
254
246
  ShopifyApp.configuration.api_key,
255
247
  ShopifyApp.configuration.secret,
256
248
  scope: ShopifyApp.configuration.scope,
257
249
  per_user_permissions: true
250
+
251
+ # In the `shopify_app.rb` initializer:
252
+ config.session_repository = 'User'
253
+ config.per_user_tokens = true
258
254
  ```
259
255
 
260
- The current Shopify user will be stored in the rails session at `session[:shopify_user]`
256
+ ### Authenticated
261
257
 
262
- This will change the type of token that Shopify returns and it will only be valid for a short time. Read more about `Online access` [here](https://help.shopify.com/api/getting-started/authentication/oauth). Note that this means you won't be able to use this token to respond to Webhooks.
258
+ The engine provides a `ShopifyApp::Authenticated` concern which should be included in any controller that is intended to be behind Shopify OAuth. It adds `before_action`s to ensure that the user is authenticated and will redirect to the Shopify login page if not. It is best practice to include this concern in a base controller inheriting from your `ApplicationController`, from which all controllers that require Shopify authentication inherit.
259
+
260
+ For backwards compatibility, the engine still provides a controller called `ShopifyApp::AuthenticatedController` which includes the `ShopifyApp::Authenticated` concern. Note that it inherits directly from `ActionController::Base`, so you will not be able to share functionality between it and your application's `ApplicationController`.
261
+
262
+ ### AfterAuthenticate Job
263
+
264
+ If your app needs to perform specific actions after the user is authenticated successfully (i.e. every time a new session is created), ShopifyApp can queue or run a job of your choosing (note that we already provide support for automatically creating Webhooks and Scripttags). To configure the after authenticate job update your initializer as follows:
265
+
266
+ ```ruby
267
+ ShopifyApp.configure do |config|
268
+ config.after_authenticate_job = { job: "Shopify::AfterAuthenticateJob" }
269
+ end
270
+ ```
271
+
272
+ The job can be configured as either a class or a class name string.
273
+
274
+ If you need the job to run synchronously add the `inline` flag:
275
+
276
+ ```ruby
277
+ ShopifyApp.configure do |config|
278
+ config.after_authenticate_job = { job: Shopify::AfterAuthenticateJob, inline: true }
279
+ end
280
+ ```
281
+
282
+ We've also provided a generator which creates a skeleton job and updates the initializer for you:
283
+
284
+ ```
285
+ bin/rails g shopify_app:add_after_authenticate_job
286
+ ```
287
+
288
+ If you want to perform that action only once, e.g. send a welcome email to the user when they install the app, you should make sure that this action is idempotent, meaning that it won't have an impact if run multiple times.
263
289
 
264
290
 
265
291
  WebhooksManager
@@ -353,36 +379,6 @@ Scripttags are created in the same way as the Webhooks, with a background job wh
353
379
 
354
380
  If `src` responds to `call` its return value will be used as the scripttag's source. It will be called on scripttag creation and deletion.
355
381
 
356
- AfterAuthenticate Job
357
- ---------------------
358
-
359
- If your app needs to perform specific actions after the user is authenticated successfully (i.e. every time a new session is created), ShopifyApp can queue or run a job of your choosing (note that we already provide support for automatically creating Webhooks and Scripttags). To configure the after authenticate job update your initializer as follows:
360
-
361
- ```ruby
362
- ShopifyApp.configure do |config|
363
- config.after_authenticate_job = { job: "Shopify::AfterAuthenticateJob" }
364
- end
365
- ```
366
-
367
- The job can be configured as either a class or a class name string.
368
-
369
- If you need the job to run synchronously add the `inline` flag:
370
-
371
- ```ruby
372
- ShopifyApp.configure do |config|
373
- config.after_authenticate_job = { job: Shopify::AfterAuthenticateJob, inline: true }
374
- end
375
- ```
376
-
377
- We've also provided a generator which creates a skeleton job and updates the initializer for you:
378
-
379
- ```
380
- bin/rails g shopify_app:add_after_authenticate_job
381
- ```
382
-
383
- If you want to perform that action only once, e.g. send a welcome email to the user when they install the app, you should make sure that this action is idempotent, meaning that it won't have an impact if run multiple times.
384
-
385
-
386
382
  RotateShopifyTokenJob
387
383
  ---------------------
388
384
 
@@ -409,19 +405,18 @@ The generated rake task will be found at `lib/tasks/shopify/rotate_shopify_token
409
405
  strategy.options[:old_client_secret] = ShopifyApp.configuration.old_secret
410
406
  ```
411
407
 
412
- ShopifyApp::SessionRepository
413
- -----------------------------
414
-
415
- `ShopifyApp::SessionRepository` allows you as a developer to define how your sessions are retrieved and stored for shops. The `SessionRepository` is configured in the `config/initializers/shopify_app.rb` file and can be set to any object that implements `self.store(shopify_session)` which stores the session and returns a unique identifier and `self.retrieve(id)` which returns a `ShopifyAPI::Session` for the passed id. See either the `ShopifyApp::InMemorySessionStore` class or the `ShopifyApp::SessionStorage` concern for examples.
408
+ App Tunneling
409
+ -------------
416
410
 
417
- If you only run the install generator then by default you will have an in memory store but it **won't work** on multi-server environments including Heroku. If you ran all the generators including the shop_model generator then the `Shop` model itself will be the `SessionRepository`. If you look at the implementation of the generated shop model you'll see that this gem provides a concern for the `SessionRepository`. You can use this concern on any model that responds to `shopify_domain`, `shopify_token` and `api_version`.
411
+ 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](#app-proxy-controller-generator) or receive Webhooks.
418
412
 
419
- Authenticated
420
- -------------
413
+ Use a tunneling service like [ngrok](https://ngrok.com/), [Forward](https://forwardhq.com/), [Beeceptor](https://beeceptor.com/), [Mockbin](http://mockbin.org/), or [Hookbin](https://hookbin.com/) to make your development environment accessible to the internet.
421
414
 
422
- The engine provides a `ShopifyApp::Authenticated` concern which should be included in any controller that is intended to be behind Shopify OAuth. It adds `before_action`s to ensure that the user is authenticated and will redirect to the Shopify login page if not. It is best practice to include this concern in a base controller inheriting from your `ApplicationController`, from which all controllers that require Shopify authentication inherit.
415
+ For example with [ngrok](https://ngrok.com/), run this command to set up a tunnel proxy to Rails' default port:
423
416
 
424
- For backwards compatibility, the engine still provides a controller called `ShopifyApp::AuthenticatedController` which includes the `ShopifyApp::Authenticated` concern. Note that it inherits directly from `ActionController::Base`, so you will not be able to share functionality between it and your application's `ApplicationController`.
417
+ ```sh
418
+ ngrok http 3000
419
+ ```
425
420
 
426
421
  AppProxyVerification
427
422
  --------------------
@@ -444,6 +439,11 @@ end
444
439
  Create your app proxy url in the [Shopify Partners' Dashboard][dashboard], making sure to point it to `https://your_app_website.com/app_proxy`.
445
440
  ![Creating an App Proxy](/images/app-proxy-screenshot.png)
446
441
 
442
+ App Bridge
443
+ ---
444
+
445
+ A basic example of using [App Bridge][app-bridge] is included in the install generator. An app instance is automatically initialized in [shopify_app.js](https://github.com/Shopify/shopify_app/blob/master/lib/generators/shopify_app/install/templates/shopify_app.js) and [flash_messages.js](https://github.com/Shopify/shopify_app/blob/master/lib/generators/shopify_app/install/templates/flash_messages.js) converts Rails [flash messages](https://api.rubyonrails.org/classes/ActionDispatch/Flash.html) to App Bridge Toast actions automatically. By default, this library is included via [unpkg in the embedded_app layout](https://github.com/Shopify/shopify_app/blob/master/lib/generators/shopify_app/install/templates/embedded_app.html.erb#L27). For more advanced uses it is recommended to [install App Bridge via npm or yarn](https://help.shopify.com/en/api/embedded-apps/app-bridge/getting-started#set-up-shopify-app-bridge-in-your-app).
446
+
447
447
  Troubleshooting
448
448
  ---------------
449
449
 
@@ -464,9 +464,15 @@ Questions or problems?
464
464
  - [Ask questions!](https://ecommerce.shopify.com/c/shopify-apis-and-technology)
465
465
  - [Read the docs!](https://help.shopify.com/api/guides)
466
466
 
467
- Rails 6 Compatibility
467
+ Upgrading to 11.7.0
468
468
  ---------------------------
469
469
 
470
+ ### Session storage method signature breaking change
471
+ If you override `def self.store(auth_session)` method in your session storage model (e.g. Shop), the method signature has changed to `def self.store(auth_session, *args)` in order to support user-based token storage. Please update your method signature to include the second argument.
472
+
473
+ Rails 6 Compatibility
474
+ ---------------------
475
+
470
476
  ### Disable Webpacker
471
477
  If you are using sprockets in rails 6 or want to generate a shopify_app without webpacker run the install task by running
472
478
 
@@ -536,3 +542,4 @@ is changed to
536
542
  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.
537
543
 
538
544
  [dashboard]:https://partners.shopify.com
545
+ [app-bridge]:https://help.shopify.com/en/api/embedded-apps/app-bridge
@@ -4,31 +4,31 @@
4
4
  this.itpAction = document.getElementById('TopLevelInteractionButton');
5
5
  this.redirectUrl = opts.redirectUrl;
6
6
  }
7
-
7
+
8
8
  ITPHelper.prototype.redirect = function() {
9
9
  sessionStorage.setItem('shopify.top_level_interaction', true);
10
10
  window.location.href = this.redirectUrl;
11
11
  }
12
-
12
+
13
13
  ITPHelper.prototype.userAgentIsAffected = function() {
14
14
  return Boolean(document.hasStorageAccess);
15
15
  }
16
-
16
+
17
17
  ITPHelper.prototype.canPartitionCookies = function() {
18
18
  var versionRegEx = /Version\/12\.0\.?\d? Safari/;
19
19
  return versionRegEx.test(navigator.userAgent);
20
20
  }
21
-
21
+
22
22
  ITPHelper.prototype.setUpContent = function(onClick) {
23
23
  this.itpContent.style.display = 'block';
24
24
  this.itpAction.addEventListener('click', this.redirect.bind(this));
25
25
  }
26
-
26
+
27
27
  ITPHelper.prototype.execute = function() {
28
28
  if (!this.itpContent) {
29
29
  return;
30
30
  }
31
-
31
+
32
32
  if (this.userAgentIsAffected()) {
33
33
  this.setUpContent();
34
34
  } else {
@@ -28,18 +28,47 @@
28
28
  window.parent.location.href = this.redirectData.myshopifyUrl + '/admin/apps';
29
29
  }
30
30
 
31
- StorageAccessHelper.prototype.redirectToAppHome = function() {
32
- window.location.href = this.redirectData.appHomeUrl;
31
+ StorageAccessHelper.prototype.redirectToAppTargetUrl = function() {
32
+ window.location.href = this.redirectData.appTargetUrl;
33
+ }
34
+
35
+ StorageAccessHelper.prototype.sameSiteNoneIncompatible = function(ua) {
36
+ return ua.includes("iPhone OS 12_") || ua.includes("iPad; CPU OS 12_") || //iOS 12
37
+ (ua.includes("UCBrowser/")
38
+ ? this.isOlderUcBrowser(ua) //UC Browser < 12.13.2
39
+ : (ua.includes("Chrome/5") || ua.includes("Chrome/6"))) ||
40
+ ua.includes("Chromium/5") || ua.includes("Chromium/6") ||
41
+ (ua.includes(" OS X 10_14_") &&
42
+ ((ua.includes("Version/") && ua.includes("Safari")) || //Safari on MacOS 10.14
43
+ ua.endsWith("(KHTML, like Gecko)"))); //Web view on MacOS 10.14
44
+ }
45
+
46
+ StorageAccessHelper.prototype.isOlderUcBrowser = function(ua) {
47
+ var match = ua.match(/UCBrowser\/(\d+)\.(\d+)\.(\d+)\./);
48
+ if (!match) return false;
49
+ var major = parseInt(match[1]);
50
+ var minor = parseInt(match[2]);
51
+ var build = parseInt(match[3]);
52
+ if (major != 12) return major < 12;
53
+ if (minor != 13) return minor < 13;
54
+ return build < 2;
55
+ }
56
+
57
+ StorageAccessHelper.prototype.setCookie = function(value) {
58
+ if(!this.sameSiteNoneIncompatible(navigator.userAgent)) {
59
+ value += '; secure; SameSite=None'
60
+ }
61
+ document.cookie = value;
33
62
  }
34
63
 
35
64
  StorageAccessHelper.prototype.grantedStorageAccess = function() {
36
65
  try {
37
66
  sessionStorage.setItem('shopify.granted_storage_access', true);
38
- document.cookie = 'shopify.granted_storage_access=true';
67
+ this.setCookie('shopify.granted_storage_access=true');
39
68
  if (!document.cookie) {
40
69
  throw 'Cannot set third-party cookie.'
41
70
  }
42
- this.redirectToAppHome();
71
+ this.redirectToAppTargetUrl();
43
72
  } catch (error) {
44
73
  console.warn('Third party cookies may be blocked.', error);
45
74
  this.redirectToAppTLD(ACCESS_DENIED_STATUS);
@@ -61,7 +90,7 @@
61
90
  StorageAccessHelper.prototype.handleHasStorageAccess = function() {
62
91
  if (sessionStorage.getItem('shopify.granted_storage_access')) {
63
92
  // If app was classified by ITP and used Storage Access API to acquire access
64
- this.redirectToAppHome();
93
+ this.redirectToAppTargetUrl();
65
94
  } else {
66
95
  // If app has not been classified by ITP and still has storage access
67
96
  this.redirectToAppTLD(ACCESS_GRANTED_STATUS);
@@ -107,7 +136,7 @@
107
136
  }
108
137
 
109
138
  StorageAccessHelper.prototype.setCookieAndRedirect = function() {
110
- document.cookie = "shopify.cookies_persist=true";
139
+ this.setCookie('shopify.cookies_persist=true');
111
140
  var helper = this.setUpHelper();
112
141
  helper.redirect();
113
142
  }