shopify_app 11.5.0 → 12.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/README.md +36 -20
  4. data/app/controllers/shopify_app/extension_verification_controller.rb +20 -0
  5. data/docs/Quickstart.md +44 -16
  6. data/docs/install-on-dev-shop.png +0 -0
  7. data/docs/test-your-app.png +0 -0
  8. data/lib/generators/shopify_app/add_marketing_activity_extension/templates/marketing_activities_controller.rb +1 -1
  9. data/lib/generators/shopify_app/home_controller/home_controller_generator.rb +0 -6
  10. data/lib/generators/shopify_app/install/templates/embedded_app.html.erb +2 -2
  11. data/lib/generators/shopify_app/install/templates/flash_messages.js +11 -2
  12. data/lib/generators/shopify_app/install/templates/shopify_app.js +9 -3
  13. data/lib/generators/shopify_app/install/templates/shopify_app.rb +1 -1
  14. data/lib/shopify_app.rb +3 -3
  15. data/lib/shopify_app/configuration.rb +9 -8
  16. data/lib/shopify_app/controller_concerns/login_protection.rb +7 -1
  17. data/lib/shopify_app/engine.rb +4 -0
  18. data/lib/shopify_app/middleware/same_site_cookie_middleware.rb +60 -0
  19. data/lib/shopify_app/session/session_storage.rb +6 -17
  20. data/lib/shopify_app/session/storage_strategies/shop_storage_strategy.rb +5 -6
  21. data/lib/shopify_app/session/storage_strategies/user_storage_strategy.rb +5 -7
  22. data/lib/shopify_app/version.rb +1 -1
  23. data/package.json +2 -1
  24. data/shopify_app.gemspec +1 -1
  25. metadata +8 -6
  26. data/lib/generators/shopify_app/home_controller/templates/shopify_app_ready_script.html.erb +0 -7
  27. 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: 0ba7612b4db7acb35c0fa91209e7b4421f90cefa6b95d52b433218e9be5a8703
4
- data.tar.gz: 9db8d74d1f2bebd2b4fe8856bb8c2d0a3e7108cfb5a940521a70ca67b1f6e1fe
3
+ metadata.gz: d7f75f25ebd3015036f89240acd78fb1d38bd85c6c61c361df564e0eaa1e2195
4
+ data.tar.gz: 5b91f6dd61dd686a9cce74123a3b6de0498f683488204768542aa128e312f90f
5
5
  SHA512:
6
- metadata.gz: 5b73cda40e6980ab59c5f5d40bcb09c93cfeb7e0fcfd8ff8cd953509e1d43eb45073f80e987aea8e7f585c28f50328613e5956d4d1de9e264908e3fc0265d670
7
- data.tar.gz: 349bbdfea89e30efd696f50572d09af4e421caa8a3ce89f539e5b1a05b956c0b35af1651482fc20bfdfc7d451874ffebecf15ed4ee86bb9bb885cab358a1d707
6
+ metadata.gz: 9119cf0bf9b9ad3a9f03c89877a7fc2337b99a98b36ec5ec01446b9a9ef15841e0bf7ba05631d15d827b5b32c535c1176f5b4b46227846ace43d27c9d55155cb
7
+ data.tar.gz: c084b5f9fd03727c865621a6615e2837179f262941b2ef3c5b083515d4e23b075e0d904f9cccee29140c78d117c2624fad4ef73c883aaa0ba087d0bc816a9685
@@ -1,3 +1,27 @@
1
+ 12.0.0
2
+ -----
3
+ * Updating shopify_api gem to 9.0.0
4
+
5
+ 11.7.1
6
+ -----
7
+ * Fix to allow SessionStorage to be flexible on what model names that the are used for storing shop and user data
8
+
9
+ 11.7.0
10
+ -----
11
+ * 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)
12
+ * Add back per-user token support (added in 11.5.0, reverted in 11.5.1)
13
+ * 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)
14
+
15
+ 11.6.0
16
+ -----
17
+ * Enable SameSite=None; Secure by default on all cookies for embedded apps [#851](https://github.com/Shopify/shopify_app/pull/851)
18
+ * Ensures compatibility of embedded apps with upcoming Chrome version 80 changes to cookie behaviour
19
+ * Configurable via `ShopifyApp.configuration.enable_same_site_none` (default true for embedded apps)
20
+
21
+ 11.5.1
22
+ -----
23
+ * Revert per-user token support temporarily
24
+
1
25
  11.5.0
2
26
  -----
3
27
  * Modularizes durable session storage
data/README.md CHANGED
@@ -13,7 +13,7 @@ Shopify Application Rails engine and generator
13
13
  Table of Contents
14
14
  -----------------
15
15
  - [Introduction](#introduction)
16
- - [Becoming a Shopify App Developer](#becoming-a-shopify-app-developer)
16
+ - [Become a Shopify App Developer](#become-a-shopify-app-developer)
17
17
  - [Installation](#installation)
18
18
  - [Generators](#generators)
19
19
  - [Mounting the Engine](#mounting-the-engine)
@@ -31,25 +31,25 @@ Table of Contents
31
31
 
32
32
  Introduction
33
33
  -----------
34
- 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).
35
35
 
36
- *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.*
37
37
 
38
- 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:
39
39
 
40
40
  [https://www.youtube.com/watch?v=yGxeoAHlQOg](https://www.youtube.com/watch?v=yGxeoAHlQOg)
41
41
 
42
- 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)
43
-
44
- Becoming a Shopify App Developer
42
+ Become a Shopify App Developer
45
43
  --------------------------------
46
- 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.
47
47
 
48
- 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`.
49
49
 
50
50
  Installation
51
51
  ------------
52
- 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`:
53
53
 
54
54
  ``` sh
55
55
  # Create a new rails app
@@ -61,7 +61,7 @@ $ echo "gem 'shopify_app'" >> Gemfile
61
61
  $ bundle install
62
62
  ```
63
63
 
64
- 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.
65
65
 
66
66
 
67
67
  #### Rails Compatibility
@@ -74,24 +74,24 @@ Generators
74
74
 
75
75
  ### Default Generator
76
76
 
77
- 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:
78
78
 
79
79
  ```sh
80
80
  $ rails generate shopify_app
81
81
  ```
82
82
 
83
- After running the generator, you will need to run `rails 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.
84
84
 
85
85
  ### API Keys
86
86
 
87
- 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:
88
88
 
89
89
  ```
90
90
  SHOPIFY_API_KEY=your api key
91
91
  SHOPIFY_API_SECRET=your api secret
92
92
  ```
93
93
 
94
- 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.
95
95
 
96
96
  ### Install Generator
97
97
 
@@ -123,7 +123,7 @@ After running the `install` generator, you can start your app with `bundle exec
123
123
  $ rails generate shopify_app:home_controller
124
124
  ```
125
125
 
126
- 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
127
127
 
128
128
 
129
129
  ### App Proxy Controller Generator
@@ -213,7 +213,7 @@ Authentication
213
213
 
214
214
  ### ShopifyApp::SessionRepository
215
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)` 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 details.
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
217
 
218
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
219
 
@@ -233,6 +233,8 @@ This will generate a user model which will be the storage for the tokens necessa
233
233
 
234
234
  The current Shopify user will be stored in the rails session at `session[:shopify_user]`
235
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
+
236
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.
237
239
 
238
240
  #### Migrating from shop-based to user-based token strategy
@@ -247,7 +249,7 @@ provider :shopify,
247
249
  per_user_permissions: true
248
250
 
249
251
  # In the `shopify_app.rb` initializer:
250
- config.session_repository = User
252
+ config.session_repository = 'User'
251
253
  config.per_user_tokens = true
252
254
  ```
253
255
 
@@ -406,9 +408,11 @@ strategy.options[:old_client_secret] = ShopifyApp.configuration.old_secret
406
408
  App Tunneling
407
409
  -------------
408
410
 
409
- 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.
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.
410
412
 
411
- For example with [ngrok](https://ngrok.com/), run this command to set up proxying to Rails' default port:
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.
414
+
415
+ For example with [ngrok](https://ngrok.com/), run this command to set up a tunnel proxy to Rails' default port:
412
416
 
413
417
  ```sh
414
418
  ngrok http 3000
@@ -435,6 +439,11 @@ end
435
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`.
436
440
  ![Creating an App Proxy](/images/app-proxy-screenshot.png)
437
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
+
438
447
  Troubleshooting
439
448
  ---------------
440
449
 
@@ -455,6 +464,12 @@ Questions or problems?
455
464
  - [Ask questions!](https://ecommerce.shopify.com/c/shopify-apis-and-technology)
456
465
  - [Read the docs!](https://help.shopify.com/api/guides)
457
466
 
467
+ Upgrading to 11.7.0
468
+ ---------------------------
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
+
458
473
  Rails 6 Compatibility
459
474
  ---------------------
460
475
 
@@ -527,3 +542,4 @@ is changed to
527
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.
528
543
 
529
544
  [dashboard]:https://partners.shopify.com
545
+ [app-bridge]:https://help.shopify.com/en/api/embedded-apps/app-bridge
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShopifyApp
4
+ class ExtensionVerificationController < ActionController::Base
5
+ protect_from_forgery with: :null_session
6
+ before_action :verify_request
7
+
8
+ private
9
+
10
+ def verify_request
11
+ hmac_header = request.headers['HTTP_X_SHOPIFY_HMAC_SHA256']
12
+ request_body = request.body.read
13
+ secret = ShopifyApp.configuration.secret
14
+ digest = OpenSSL::Digest.new('sha256')
15
+
16
+ expected_hmac = Base64.strict_encode64(OpenSSL::HMAC.digest(digest, secret, request_body))
17
+ head(:unauthorized) unless ActiveSupport::SecurityUtils.secure_compare(expected_hmac, hmac_header)
18
+ end
19
+ end
20
+ end
@@ -1,11 +1,13 @@
1
1
  Quickstart
2
2
  ==========
3
3
 
4
- Build and deploy a new Shopify App to Heroku in minutes
4
+ Get started building and deploying a new Shopify App to Heroku in just a few minutes. This guide assumes you have Ruby/Rails installed on your computer already; if you haven't done that already start with [this guide.](https://guides.rubyonrails.org/v5.0/getting_started.html#installing-rails)
5
5
 
6
6
  1. New Rails App (with postgres)
7
7
  --------------------------------
8
8
 
9
+ To create a new Rails app and use this generator, open your terminal and run the following commands:
10
+
9
11
  ```sh
10
12
  $ rails new test-app --database=postgresql
11
13
  $ cd test-app
@@ -17,43 +19,51 @@ $ git commit -m 'new rails app'
17
19
  2. Create a new Heroku app
18
20
  --------------------------
19
21
 
20
- The next step is to create a new heroku app. Pull up your heroku dashboard and make a new app!
22
+ The next step is to create a new Heroku app to host your application. If you haven't got a Heroku account yet, create a free account [here](https://www.heroku.com/).
23
+
24
+ Head to the Heroku dashboard and create a new app, or run the following commands with the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli#download-and-install) installed, substituting `name` for the name of your own app:
21
25
 
22
- cli:
26
+ CLI:
23
27
  ```sh
24
28
  $ heroku create name
25
29
  $ heroku git:remote -a name
26
30
  ```
27
31
 
28
- now we need to let git know where the remote server is so we'll be able to deploy later
32
+ Once you have created an app on Heroku, we need to let Git know where the Heroku server is so we can deploy to it later. Copy the app's name from your Heroku dashboard and substitute `appname.git` with the name you chose earlier:
29
33
 
30
34
  web:
31
35
  ```sh
32
36
  # https://dashboard.heroku.com/new
33
- $ git remote add heroku git@heroku.com:appinfive.git
37
+ $ git remote add heroku git@heroku.com:appname.git
34
38
  ```
35
39
 
36
- 3. Create a new App in the partners area
40
+ 3. Create a new App in the Shopify Partner dashboard
37
41
  -----------------------------------------
42
+ * Create a Shopify app in the [Partners dashboard](https://partner.shopify.com). For this tutorial, you can choose either a public or custom app, but you can [learn about App Types here.](https://help.shopify.com/en/manual/apps/app-types)
38
43
  [https://app.shopify.com/services/partners/api_clients](https://app.shopify.com/services/partners/api_clients)
39
- * set the callback url to `https://<name>.herokuapp.com/`
40
- * choose an embedded app
41
- * set the redirect_uri to `https://<name>.herokuapp.com/auth/shopify/callback`
42
-
44
+ * Set the callback url to `https://<appname>.herokuapp.com/`
45
+ * Choose an embedded app
46
+ * Set the app's `redirect_uri` to `https://<appname>.herokuapp.com/auth/shopify/callback`
43
47
 
44
- 4. Add ShopifyApp to gemfile
48
+ 4. Add ShopifyApp to Gemfile
45
49
  ----------------------------
50
+
51
+ Run these commands to add the `shopify_app` Gem to your app:
52
+
46
53
  ```sh
47
54
  $ echo "gem 'shopify_app'" >> Gemfile
48
55
  $ bundle install
49
56
  ```
50
57
 
51
- Note - its recommended to use the latest released version. Check the git tags to see the latest release and then add it to your Gemfile e.g `gem 'shopify_app', '~> 7.0.0'`
58
+ **Note:** we recommend using the latest version of Shopify Gem. Check the [Git tags](https://github.com/Shopify/shopify_app/tags) to see the latest release version and then add it to your Gemfile e.g `gem 'shopify_app', '~> 7.0.0'`
52
59
 
53
60
  5. Run the ShopifyApp generator
54
61
  -------------------------------
62
+
63
+ Generate the code for your app by running these commands:
64
+
55
65
  ```sh
56
- # use the keys from your app in the partners area
66
+ # Use the keys from your app you created in the partners area
57
67
  $ rails generate shopify_app --api_key <shopify_api_key> --secret <shopify_api_secret>
58
68
  $ git add .
59
69
  $ git commit -m 'generated shopify app'
@@ -61,10 +71,12 @@ $ git commit -m 'generated shopify app'
61
71
 
62
72
  If you forget to set your keys or redirect uri above, you will find them in the shopify_app initializer at: `/config/initializers/shopify_app.rb`.
63
73
 
64
- We recommend adding a gem or utilizing ENV variables to handle your keys before releasing your app.
74
+ We recommend adding a gem or utilizing environment variables (`.env`) to handle your keys before releasing your app. [Learn more about using environment variables.](https://www.honeybadger.io/blog/ruby-guide-environment-variables/)
65
75
 
66
- 6. Deploy
76
+ 6. Deploy your app
67
77
  ---------
78
+
79
+ Once you've generated your app, push it into your Heroku environment to see it up and running:
68
80
  ```sh
69
81
  $ git push heroku
70
82
  $ heroku run rake db:migrate
@@ -72,4 +84,20 @@ $ heroku run rake db:migrate
72
84
 
73
85
  7. Install the App!
74
86
  -------------------
75
- `https://<name>.herokuapp.com/`
87
+
88
+ Ensure you have created a [development store](https://help.shopify.com/en/api/getting-started/making-your-first-request#create-a-development-store) using the Shopify Partner Dashboard. If you don't already have one, [create one by following these instructions](https://help.shopify.com/en/api/getting-started/making-your-first-request#create-a-development-store).
89
+
90
+ ##### Note: The following step will cause your store to become `transfer-disabled.` Read more about store transfer and why it's important [here](https://help.shopify.com/en/api/guides/store-transfers#transfer-disabled-stores). This is an irreversible change, so be sure you don't plan to transfer this store to a merchant.
91
+
92
+ Install the app onto your new development store using the Partner Dashboard. Log in to your account, visit the apps page, click the app you created earlier, and looking for the `Test your app` instructions where you can select a store to install your app on.
93
+
94
+ ![Installing an app on the partners dashboard dropdown](/docs/install-on-dev-shop.png)
95
+
96
+ ### OR
97
+
98
+ ![Installing an app on the partners dashboard card](/docs/test-your-app.png)
99
+
100
+ 8. Great work!
101
+ -------------------
102
+
103
+ You're done creating your first app on Shopify. Keep going and learn more by [diving into our full documentation](https://help.shopify.com/en/api/getting-started), or join our [community of developers.](https://community.shopify.com/c/Shopify-Apps/bd-p/shopify-apps)
Binary file
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class MarketingActivitiesController < ExtensionVerificationController
3
+ class MarketingActivitiesController < ShopifyApp::ExtensionVerificationController
4
4
  def preload_form_data
5
5
  preload_data = {
6
6
  "form_data": {
@@ -11,12 +11,6 @@ module ShopifyApp
11
11
 
12
12
  def create_home_index_view
13
13
  copy_file 'index.html.erb', 'app/views/home/index.html.erb'
14
- if embedded_app?
15
- prepend_to_file(
16
- 'app/views/home/index.html.erb',
17
- File.read(File.expand_path(find_in_source_paths('shopify_app_ready_script.html.erb')))
18
- )
19
- end
20
14
  end
21
15
 
22
16
  def add_home_index_route
@@ -24,11 +24,11 @@
24
24
 
25
25
  <%= render 'layouts/flash_messages' %>
26
26
 
27
- <script src="https://cdn.shopify.com/s/assets/external/app.js?<%= Time.now.strftime('%Y%m%d%H') %>"></script>
27
+ <script src="https://unpkg.com/@shopify/app-bridge"></script>
28
28
 
29
29
  <%= content_tag(:div, nil, id: 'shopify-app-init', data: {
30
30
  api_key: ShopifyApp.configuration.api_key,
31
- shop_origin: ("https://#{ @shop_session.url }" if @shop_session),
31
+ shop_origin: (@shop_session.domain if @shop_session),
32
32
  debug: Rails.env.development?
33
33
  } ) %>
34
34
 
@@ -4,12 +4,21 @@ if (!document.documentElement.hasAttribute("data-turbolinks-preview")) {
4
4
  document.addEventListener(eventName, function flash() {
5
5
  var flashData = JSON.parse(document.getElementById('shopify-app-flash').dataset.flash);
6
6
 
7
+ var Toast = window['app-bridge'].actions.Toast;
8
+
7
9
  if (flashData.notice) {
8
- ShopifyApp.flashNotice(flashData.notice);
10
+ Toast.create(app, {
11
+ message: flashData.notice,
12
+ duration: 5000,
13
+ }).dispatch(Toast.Action.SHOW);
9
14
  }
10
15
 
11
16
  if (flashData.error) {
12
- ShopifyApp.flashError(flashData.error);
17
+ Toast.create(app, {
18
+ message: flashData.error,
19
+ duration: 5000,
20
+ isError: true,
21
+ }).dispatch(Toast.Action.SHOW);
13
22
  }
14
23
 
15
24
  document.removeEventListener(eventName, flash)
@@ -1,9 +1,15 @@
1
1
  document.addEventListener('DOMContentLoaded', () => {
2
2
  var data = document.getElementById('shopify-app-init').dataset;
3
- ShopifyApp.init({
3
+ var AppBridge = window['app-bridge'];
4
+ var createApp = AppBridge.default;
5
+ window.app = createApp({
4
6
  apiKey: data.apiKey,
5
7
  shopOrigin: data.shopOrigin,
6
- debug: data.debug === 'true',
7
- forceRedirect: true
8
+ });
9
+
10
+ var actions = AppBridge.actions;
11
+ var TitleBar = actions.TitleBar;
12
+ TitleBar.create(app, {
13
+ title: data.page,
8
14
  });
9
15
  });
@@ -8,7 +8,7 @@ ShopifyApp.configure do |config|
8
8
  config.embedded_app = <%= embedded_app? %>
9
9
  config.after_authenticate_job = false
10
10
  config.api_version = "<%= @api_version %>"
11
- config.session_repository = ShopifyApp::InMemorySessionStore
11
+ config.session_repository = 'ShopifyApp::InMemorySessionStore'
12
12
  end
13
13
 
14
14
  # ShopifyApp::Utils.fetch_known_api_versions # Uncomment to fetch known api versions from shopify servers on boot
@@ -24,9 +24,6 @@ module ShopifyApp
24
24
  # utils
25
25
  require 'shopify_app/utils'
26
26
 
27
- # controllers
28
- require 'shopify_app/controllers/extension_verification_controller'
29
-
30
27
  # controller concerns
31
28
  require 'shopify_app/controller_concerns/localization'
32
29
  require 'shopify_app/controller_concerns/itp'
@@ -43,6 +40,9 @@ module ShopifyApp
43
40
  require 'shopify_app/managers/webhooks_manager'
44
41
  require 'shopify_app/managers/scripttags_manager'
45
42
 
43
+ # middleware
44
+ require 'shopify_app/middleware/same_site_cookie_middleware'
45
+
46
46
  # session
47
47
  require 'shopify_app/session/storage_strategies/shop_storage_strategy'
48
48
  require 'shopify_app/session/storage_strategies/user_storage_strategy'
@@ -14,7 +14,7 @@ module ShopifyApp
14
14
  attr_accessor :webhooks
15
15
  attr_accessor :scripttags
16
16
  attr_accessor :after_authenticate_job
17
- attr_accessor :session_repository
17
+ attr_reader :session_repository
18
18
  attr_accessor :per_user_tokens
19
19
  alias_method :per_user_tokens?, :per_user_tokens
20
20
  attr_accessor :api_version
@@ -36,6 +36,9 @@ module ShopifyApp
36
36
  # allow namespacing webhook jobs
37
37
  attr_accessor :webhook_jobs_namespace
38
38
 
39
+ # allow enabling of same site none on cookies
40
+ attr_accessor :enable_same_site_none
41
+
39
42
  def initialize
40
43
  @root_url = '/'
41
44
  @myshopify_domain = 'myshopify.com'
@@ -50,13 +53,8 @@ module ShopifyApp
50
53
  end
51
54
 
52
55
  def session_repository=(klass)
53
- if Rails.configuration.cache_classes
54
- ShopifyApp::SessionRepository.storage = klass
55
- else
56
- ActiveSupport::Reloader.to_prepare do
57
- ShopifyApp::SessionRepository.storage = klass
58
- end
59
- end
56
+ @session_repository = klass
57
+ ShopifyApp::SessionRepository.storage = klass
60
58
  end
61
59
 
62
60
  def has_webhooks?
@@ -67,6 +65,9 @@ module ShopifyApp
67
65
  scripttags.present?
68
66
  end
69
67
 
68
+ def enable_same_site_none
69
+ @enable_same_site_none.nil? ? embedded_app? : @enable_same_site_none
70
+ end
70
71
  end
71
72
 
72
73
  def self.configuration
@@ -63,8 +63,14 @@ module ShopifyApp
63
63
  head :unauthorized
64
64
  else
65
65
  if request.get?
66
- session[:return_to] = "#{request.path}?#{sanitized_params.to_query}"
66
+ path = request.path
67
+ query = sanitized_params.to_query
68
+ else
69
+ referer = URI(request.referer || "/")
70
+ path = referer.path
71
+ query = "#{referer.query}&#{sanitized_params.to_query}"
67
72
  end
73
+ session[:return_to] = "#{path}?#{query}"
68
74
  redirect_to(login_url_with_optional_shop)
69
75
  end
70
76
  end
@@ -12,5 +12,9 @@ module ShopifyApp
12
12
  storage_access.svg
13
13
  ]
14
14
  end
15
+
16
+ initializer "shopify_app.middleware" do |app|
17
+ app.config.middleware.insert_before(ActionDispatch::Cookies, ShopifyApp::SameSiteCookieMiddleware)
18
+ end
15
19
  end
16
20
  end
@@ -0,0 +1,60 @@
1
+ module ShopifyApp
2
+ class SameSiteCookieMiddleware
3
+ def initialize(app)
4
+ @app = app
5
+ end
6
+
7
+ def call(env)
8
+ _status, headers, _body = @app.call(env)
9
+ ensure
10
+ user_agent = env['HTTP_USER_AGENT']
11
+
12
+ if headers && headers['Set-Cookie'] && !SameSiteCookieMiddleware.same_site_none_incompatible?(user_agent) &&
13
+ ShopifyApp.configuration.enable_same_site_none
14
+
15
+ cookies = headers['Set-Cookie'].split("\n").compact
16
+
17
+ cookies.each do |cookie|
18
+ unless cookie.include?("; SameSite")
19
+ headers['Set-Cookie'] = headers['Set-Cookie'].gsub("#{cookie}", "#{cookie}; secure; SameSite=None")
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ def self.same_site_none_incompatible?(user_agent)
26
+ sniffer = BrowserSniffer.new(user_agent)
27
+
28
+ webkit_same_site_bug?(sniffer) || drops_unrecognized_same_site_cookies?(sniffer)
29
+ rescue
30
+ true
31
+ end
32
+
33
+ def self.webkit_same_site_bug?(sniffer)
34
+ (sniffer.os == :ios && sniffer.os_version.match?(/^([0-9]|1[12])[\.\_]/)) ||
35
+ (sniffer.os == :mac && sniffer.browser == :safari && sniffer.os_version.match?(/^10[\.\_]14/))
36
+ end
37
+
38
+ def self.drops_unrecognized_same_site_cookies?(sniffer)
39
+ (chromium_based?(sniffer) && sniffer.major_browser_version >= 51 && sniffer.major_browser_version <= 66) ||
40
+ (uc_browser?(sniffer) && !uc_browser_version_at_least?(sniffer: sniffer, major: 12, minor: 13, build: 2))
41
+ end
42
+
43
+ def self.chromium_based?(sniffer)
44
+ sniffer.browser_name.downcase.match?(/chrom(e|ium)/)
45
+ end
46
+
47
+ def self.uc_browser?(sniffer)
48
+ sniffer.user_agent.downcase.match?(/uc\s?browser/)
49
+ end
50
+
51
+ def self.uc_browser_version_at_least?(sniffer:, major:, minor:, build:)
52
+ digits = sniffer.browser_version.split('.').map(&:to_i)
53
+ return false unless digits.count >= 3
54
+
55
+ return digits[0] > major if digits[0] != major
56
+ return digits[1] > minor if digits[1] != minor
57
+ digits[2] >= build
58
+ end
59
+ end
60
+ end
@@ -3,6 +3,12 @@ module ShopifyApp
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
+ if ShopifyApp.configuration.per_user_tokens?
7
+ extend ShopifyApp::SessionStorage::UserStorageStrategy
8
+ else
9
+ extend ShopifyApp::SessionStorage::ShopStorageStrategy
10
+ end
11
+
6
12
  validates :shopify_token, presence: true
7
13
  validates :api_version, presence: true
8
14
  validates :shopify_domain, presence: true,
@@ -19,22 +25,5 @@ module ShopifyApp
19
25
  &block
20
26
  )
21
27
  end
22
-
23
- class_methods do
24
-
25
- def strategy_klass
26
- ShopifyApp.configuration.per_user_tokens? ?
27
- ShopifyApp::SessionStorage::UserStorageStrategy :
28
- ShopifyApp::SessionStorage::ShopStorageStrategy
29
- end
30
-
31
- def store(auth_session, user: nil)
32
- strategy_klass.store(auth_session, user)
33
- end
34
-
35
- def retrieve(id)
36
- strategy_klass.retrieve(id)
37
- end
38
- end
39
28
  end
40
29
  end
@@ -1,17 +1,16 @@
1
1
  module ShopifyApp
2
2
  module SessionStorage
3
- class ShopStorageStrategy
4
-
5
- def self.store(auth_session, *args)
6
- shop = Shop.find_or_initialize_by(shopify_domain: auth_session.domain)
3
+ module ShopStorageStrategy
4
+ def store(auth_session, *args)
5
+ shop = find_or_initialize_by(shopify_domain: auth_session.domain)
7
6
  shop.shopify_token = auth_session.token
8
7
  shop.save!
9
8
  shop.id
10
9
  end
11
10
 
12
- def self.retrieve(id)
11
+ def retrieve(id)
13
12
  return unless id
14
- if shop = Shop.find_by(id: id)
13
+ if shop = self.find_by(id: id)
15
14
  ShopifyAPI::Session.new(
16
15
  domain: shop.shopify_domain,
17
16
  token: shop.shopify_token,
@@ -1,18 +1,17 @@
1
1
  module ShopifyApp
2
2
  module SessionStorage
3
- class UserStorageStrategy
4
-
5
- def self.store(auth_session, user)
6
- user = User.find_or_initialize_by(shopify_user_id: user[:id])
3
+ module UserStorageStrategy
4
+ def store(auth_session, user)
5
+ user = find_or_initialize_by(shopify_user_id: user[:id])
7
6
  user.shopify_token = auth_session.token
8
7
  user.shopify_domain = auth_session.domain
9
8
  user.save!
10
9
  user.id
11
10
  end
12
11
 
13
- def self.retrieve(id)
12
+ def retrieve(id)
14
13
  return unless id
15
- if user = User.find_by(shopify_user_id: id)
14
+ if user = self.find_by(shopify_user_id: id)
16
15
  ShopifyAPI::Session.new(
17
16
  domain: user.shopify_domain,
18
17
  token: user.shopify_token,
@@ -20,7 +19,6 @@ module ShopifyApp
20
19
  )
21
20
  end
22
21
  end
23
-
24
22
  end
25
23
  end
26
24
  end
@@ -1,3 +1,3 @@
1
1
  module ShopifyApp
2
- VERSION = '11.5.0'.freeze
2
+ VERSION = '12.0.0'.freeze
3
3
  end
@@ -23,5 +23,6 @@
23
23
  },
24
24
  "scripts": {
25
25
  "test": "./node_modules/.bin/karma start --browsers ChromeHeadless --single-run"
26
- }
26
+ },
27
+ "version": "12.0.0"
27
28
  }
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
12
12
 
13
13
  s.add_runtime_dependency('browser_sniffer', '~> 1.1.3')
14
14
  s.add_runtime_dependency('rails', '> 5.2.1')
15
- s.add_runtime_dependency('shopify_api', '~> 8.0')
15
+ s.add_runtime_dependency('shopify_api', '~> 9.0')
16
16
  s.add_runtime_dependency('omniauth-shopify-oauth2', '~> 2.2.0')
17
17
 
18
18
  s.add_development_dependency('rake')
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: 11.5.0
4
+ version: 12.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-07 00:00:00.000000000 Z
11
+ date: 2020-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: browser_sniffer
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '8.0'
47
+ version: '9.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '8.0'
54
+ version: '9.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: omniauth-shopify-oauth2
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -239,6 +239,7 @@ files:
239
239
  - app/controllers/concerns/shopify_app/authenticated.rb
240
240
  - app/controllers/shopify_app/authenticated_controller.rb
241
241
  - app/controllers/shopify_app/callback_controller.rb
242
+ - app/controllers/shopify_app/extension_verification_controller.rb
242
243
  - app/controllers/shopify_app/sessions_controller.rb
243
244
  - app/controllers/shopify_app/webhooks_controller.rb
244
245
  - app/views/shopify_app/partials/_button_styles.html.erb
@@ -277,6 +278,8 @@ files:
277
278
  - docs/Quickstart.md
278
279
  - docs/Releasing.md
279
280
  - docs/Troubleshooting.md
281
+ - docs/install-on-dev-shop.png
282
+ - docs/test-your-app.png
280
283
  - images/app-proxy-screenshot.png
281
284
  - karma.conf.js
282
285
  - lib/generators/shopify_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb
@@ -295,7 +298,6 @@ files:
295
298
  - lib/generators/shopify_app/home_controller/home_controller_generator.rb
296
299
  - lib/generators/shopify_app/home_controller/templates/home_controller.rb
297
300
  - lib/generators/shopify_app/home_controller/templates/index.html.erb
298
- - lib/generators/shopify_app/home_controller/templates/shopify_app_ready_script.html.erb
299
301
  - lib/generators/shopify_app/install/install_generator.rb
300
302
  - lib/generators/shopify_app/install/templates/_flash_messages.html.erb
301
303
  - lib/generators/shopify_app/install/templates/embedded_app.html.erb
@@ -330,12 +332,12 @@ files:
330
332
  - lib/shopify_app/controller_concerns/localization.rb
331
333
  - lib/shopify_app/controller_concerns/login_protection.rb
332
334
  - lib/shopify_app/controller_concerns/webhook_verification.rb
333
- - lib/shopify_app/controllers/extension_verification_controller.rb
334
335
  - lib/shopify_app/engine.rb
335
336
  - lib/shopify_app/jobs/scripttags_manager_job.rb
336
337
  - lib/shopify_app/jobs/webhooks_manager_job.rb
337
338
  - lib/shopify_app/managers/scripttags_manager.rb
338
339
  - lib/shopify_app/managers/webhooks_manager.rb
340
+ - lib/shopify_app/middleware/same_site_cookie_middleware.rb
339
341
  - lib/shopify_app/session/in_memory_session_store.rb
340
342
  - lib/shopify_app/session/session_repository.rb
341
343
  - lib/shopify_app/session/session_storage.rb
@@ -1,7 +0,0 @@
1
- <% content_for :javascript do %>
2
- <script type="text/javascript">
3
- ShopifyApp.ready(function(){
4
- ShopifyApp.Bar.initialize({ title: "Home" });
5
- });
6
- </script>
7
- <% end %>
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class ExtensionVerificationController < ActionController::Base
4
- protect_from_forgery with: :null_session
5
- before_action :verify_request
6
-
7
- private
8
-
9
- def verify_request
10
- hmac_header = request.headers['HTTP_X_SHOPIFY_HMAC_SHA256']
11
- request_body = request.body.read
12
- secret = ShopifyApp.configuration.secret
13
- digest = OpenSSL::Digest.new('sha256')
14
-
15
- expected_hmac = Base64.strict_encode64(OpenSSL::HMAC.digest(digest, secret, request_body))
16
- head(:unauthorized) unless ActiveSupport::SecurityUtils.secure_compare(expected_hmac, hmac_header)
17
- end
18
- end