shopify_app 11.4.0 → 11.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +0 -2
- data/CHANGELOG.md +5 -0
- data/README.md +100 -102
- data/app/controllers/concerns/shopify_app/authenticated.rb +1 -1
- data/app/controllers/shopify_app/callback_controller.rb +8 -2
- data/config/locales/nl.yml +1 -1
- data/lib/generators/shopify_app/install/install_generator.rb +0 -4
- data/lib/generators/shopify_app/install/templates/shopify_provider.rb +1 -0
- data/lib/generators/shopify_app/user_model/templates/db/migrate/create_users.erb +16 -0
- data/lib/generators/shopify_app/user_model/templates/user.rb +7 -0
- data/lib/generators/shopify_app/user_model/templates/users.yml +4 -0
- data/lib/generators/shopify_app/user_model/user_model_generator.rb +38 -0
- data/lib/shopify_app.rb +2 -0
- data/lib/shopify_app/configuration.rb +4 -0
- data/lib/shopify_app/controller_concerns/login_protection.rb +22 -3
- data/lib/shopify_app/controllers/extension_verification_controller.rb +1 -0
- data/lib/shopify_app/session/in_memory_session_store.rb +1 -1
- data/lib/shopify_app/session/session_repository.rb +2 -2
- data/lib/shopify_app/session/session_storage.rb +14 -15
- data/lib/shopify_app/session/storage_strategies/shop_storage_strategy.rb +24 -0
- data/lib/shopify_app/session/storage_strategies/user_storage_strategy.rb +26 -0
- data/lib/shopify_app/version.rb +1 -1
- data/package-lock.json +33 -35
- data/package.json +1 -1
- data/service.yml +1 -1
- data/shopify_app.gemspec +4 -1
- data/yarn.lock +14 -14
- metadata +50 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ba7612b4db7acb35c0fa91209e7b4421f90cefa6b95d52b433218e9be5a8703
|
4
|
+
data.tar.gz: 9db8d74d1f2bebd2b4fe8856bb8c2d0a3e7108cfb5a940521a70ca67b1f6e1fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b73cda40e6980ab59c5f5d40bcb09c93cfeb7e0fcfd8ff8cd953509e1d43eb45073f80e987aea8e7f585c28f50328613e5956d4d1de9e264908e3fc0265d670
|
7
|
+
data.tar.gz: 349bbdfea89e30efd696f50572d09af4e421caa8a3ce89f539e5b1a05b956c0b35af1651482fc20bfdfc7d451874ffebecf15ed4ee86bb9bb885cab358a1d707
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -12,61 +12,35 @@ Shopify Application Rails engine and generator
|
|
12
12
|
|
13
13
|
Table of Contents
|
14
14
|
-----------------
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
+
- [Becoming a Shopify App Developer](#becoming-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
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).
|
46
35
|
|
47
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.*
|
48
37
|
|
49
|
-
|
50
|
-
Quickstart
|
51
|
-
----------
|
52
|
-
|
53
38
|
Check out this screencast on how to create and deploy a new Shopify App to Heroku in 5 minutes:
|
54
39
|
|
55
40
|
[https://www.youtube.com/watch?v=yGxeoAHlQOg](https://www.youtube.com/watch?v=yGxeoAHlQOg)
|
56
41
|
|
57
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)
|
58
43
|
|
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
44
|
Becoming a Shopify App Developer
|
71
45
|
--------------------------------
|
72
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.
|
@@ -106,7 +80,7 @@ The default generator will run the `install`, `shop`, and `home_controller` gene
|
|
106
80
|
$ rails generate shopify_app
|
107
81
|
```
|
108
82
|
|
109
|
-
After running the generator, you will need to run `
|
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.
|
110
84
|
|
111
85
|
### API Keys
|
112
86
|
|
@@ -143,17 +117,6 @@ 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
|
@@ -171,6 +134,13 @@ $ rails generate shopify_app:app_proxy_controller
|
|
171
134
|
|
172
135
|
This optional generator, not included with the default generator, creates the app proxy controller to handle proxy requests to the app from your shop storefront, modifies 'config/routes.rb' with a namespace route, and an example view which displays current shop information using the LiquidAPI
|
173
136
|
|
137
|
+
### Marketing Extension Generator
|
138
|
+
|
139
|
+
```sh
|
140
|
+
$ rails generate shopify_app:add_marketing_activity_extension
|
141
|
+
```
|
142
|
+
|
143
|
+
This will create a controller with the endpoints required to build a [marketing activities extension](https://help.shopify.com/en/api/embedded-apps/app-extensions/shopify-admin/marketing-activities). The extension will be generated with a base url at `/marketing_activities`, which should also be configured in partners.
|
174
144
|
|
175
145
|
### Controllers, Routes and Views
|
176
146
|
|
@@ -238,21 +208,82 @@ ShopifyApp.configure do |config|
|
|
238
208
|
end
|
239
209
|
```
|
240
210
|
|
241
|
-
|
242
|
-
|
243
|
-
|
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)` 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.
|
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
|
+
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
|
+
|
238
|
+
#### Migrating from shop-based to user-based token strategy
|
239
|
+
After running the generator, ensure that configuration settings are successfully changed:
|
244
240
|
|
245
241
|
```ruby
|
242
|
+
# In the `omniauth.rb` initializer:
|
246
243
|
provider :shopify,
|
247
244
|
ShopifyApp.configuration.api_key,
|
248
245
|
ShopifyApp.configuration.secret,
|
249
246
|
scope: ShopifyApp.configuration.scope,
|
250
247
|
per_user_permissions: true
|
248
|
+
|
249
|
+
# In the `shopify_app.rb` initializer:
|
250
|
+
config.session_repository = User
|
251
|
+
config.per_user_tokens = true
|
251
252
|
```
|
252
253
|
|
253
|
-
|
254
|
+
### Authenticated
|
254
255
|
|
255
|
-
|
256
|
+
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.
|
257
|
+
|
258
|
+
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`.
|
259
|
+
|
260
|
+
### AfterAuthenticate Job
|
261
|
+
|
262
|
+
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:
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
ShopifyApp.configure do |config|
|
266
|
+
config.after_authenticate_job = { job: "Shopify::AfterAuthenticateJob" }
|
267
|
+
end
|
268
|
+
```
|
269
|
+
|
270
|
+
The job can be configured as either a class or a class name string.
|
271
|
+
|
272
|
+
If you need the job to run synchronously add the `inline` flag:
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
ShopifyApp.configure do |config|
|
276
|
+
config.after_authenticate_job = { job: Shopify::AfterAuthenticateJob, inline: true }
|
277
|
+
end
|
278
|
+
```
|
279
|
+
|
280
|
+
We've also provided a generator which creates a skeleton job and updates the initializer for you:
|
281
|
+
|
282
|
+
```
|
283
|
+
bin/rails g shopify_app:add_after_authenticate_job
|
284
|
+
```
|
285
|
+
|
286
|
+
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.
|
256
287
|
|
257
288
|
|
258
289
|
WebhooksManager
|
@@ -346,36 +377,6 @@ Scripttags are created in the same way as the Webhooks, with a background job wh
|
|
346
377
|
|
347
378
|
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.
|
348
379
|
|
349
|
-
AfterAuthenticate Job
|
350
|
-
---------------------
|
351
|
-
|
352
|
-
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:
|
353
|
-
|
354
|
-
```ruby
|
355
|
-
ShopifyApp.configure do |config|
|
356
|
-
config.after_authenticate_job = { job: "Shopify::AfterAuthenticateJob" }
|
357
|
-
end
|
358
|
-
```
|
359
|
-
|
360
|
-
The job can be configured as either a class or a class name string.
|
361
|
-
|
362
|
-
If you need the job to run synchronously add the `inline` flag:
|
363
|
-
|
364
|
-
```ruby
|
365
|
-
ShopifyApp.configure do |config|
|
366
|
-
config.after_authenticate_job = { job: Shopify::AfterAuthenticateJob, inline: true }
|
367
|
-
end
|
368
|
-
```
|
369
|
-
|
370
|
-
We've also provided a generator which creates a skeleton job and updates the initializer for you:
|
371
|
-
|
372
|
-
```
|
373
|
-
bin/rails g shopify_app:add_after_authenticate_job
|
374
|
-
```
|
375
|
-
|
376
|
-
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.
|
377
|
-
|
378
|
-
|
379
380
|
RotateShopifyTokenJob
|
380
381
|
---------------------
|
381
382
|
|
@@ -402,19 +403,16 @@ The generated rake task will be found at `lib/tasks/shopify/rotate_shopify_token
|
|
402
403
|
strategy.options[:old_client_secret] = ShopifyApp.configuration.old_secret
|
403
404
|
```
|
404
405
|
|
405
|
-
|
406
|
-
-----------------------------
|
407
|
-
|
408
|
-
`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.
|
409
|
-
|
410
|
-
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
|
-
|
412
|
-
Authenticated
|
406
|
+
App Tunneling
|
413
407
|
-------------
|
414
408
|
|
415
|
-
|
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.
|
416
410
|
|
417
|
-
For
|
411
|
+
For example with [ngrok](https://ngrok.com/), run this command to set up proxying to Rails' default port:
|
412
|
+
|
413
|
+
```sh
|
414
|
+
ngrok http 3000
|
415
|
+
```
|
418
416
|
|
419
417
|
AppProxyVerification
|
420
418
|
--------------------
|
@@ -458,7 +456,7 @@ Questions or problems?
|
|
458
456
|
- [Read the docs!](https://help.shopify.com/api/guides)
|
459
457
|
|
460
458
|
Rails 6 Compatibility
|
461
|
-
|
459
|
+
---------------------
|
462
460
|
|
463
461
|
### Disable Webpacker
|
464
462
|
If you are using sprockets in rails 6 or want to generate a shopify_app without webpacker run the install task by running
|
@@ -8,7 +8,7 @@ module ShopifyApp
|
|
8
8
|
include ShopifyApp::Localization
|
9
9
|
include ShopifyApp::LoginProtection
|
10
10
|
include ShopifyApp::EmbeddedApp
|
11
|
-
before_action :
|
11
|
+
before_action :login_again_if_different_user_or_shop
|
12
12
|
around_action :shopify_session
|
13
13
|
end
|
14
14
|
end
|
@@ -55,10 +55,16 @@ module ShopifyApp
|
|
55
55
|
token: token,
|
56
56
|
api_version: ShopifyApp.configuration.api_version
|
57
57
|
)
|
58
|
-
|
59
|
-
session[:shopify] = ShopifyApp::SessionRepository.store(session_store)
|
58
|
+
session[:shopify] = ShopifyApp::SessionRepository.store(session_store, user: associated_user)
|
60
59
|
session[:shopify_domain] = shop_name
|
61
60
|
session[:shopify_user] = associated_user
|
61
|
+
|
62
|
+
if ShopifyApp.configuration.per_user_tokens?
|
63
|
+
# Adds the user_session to the session to determine if the logged in user has changed
|
64
|
+
user_session = auth_hash&.extra&.session
|
65
|
+
raise IndexError, "Missing user session signature" if user_session.nil?
|
66
|
+
session[:user_session] = user_session
|
67
|
+
end
|
62
68
|
end
|
63
69
|
|
64
70
|
def install_webhooks
|
data/config/locales/nl.yml
CHANGED
@@ -11,10 +11,6 @@ module ShopifyApp
|
|
11
11
|
class_option :embedded, type: :string, default: 'true'
|
12
12
|
class_option :api_version, type: :string, default: nil
|
13
13
|
|
14
|
-
def add_dotenv_gem
|
15
|
-
gem('dotenv-rails', group: [:test, :development])
|
16
|
-
end
|
17
|
-
|
18
14
|
def create_shopify_app_initializer
|
19
15
|
@application_name = format_array_argument(options['application_name'])
|
20
16
|
@scope = format_array_argument(options['scope'])
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateUsers < ActiveRecord::Migration[<%= rails_migration_version %>]
|
2
|
+
def self.up
|
3
|
+
create_table :users do |t|
|
4
|
+
t.bigint :shopify_user_id, null: false
|
5
|
+
t.string :shopify_domain, null: false
|
6
|
+
t.string :shopify_token, null: false
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
add_index :users, :shopify_user_id, unique: true
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :users
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
require 'rails/generators/active_record'
|
3
|
+
|
4
|
+
module ShopifyApp
|
5
|
+
module Generators
|
6
|
+
class UserModelGenerator < Rails::Generators::Base
|
7
|
+
include Rails::Generators::Migration
|
8
|
+
source_root File.expand_path('../templates', __FILE__)
|
9
|
+
|
10
|
+
def create_user_model
|
11
|
+
copy_file 'user.rb', 'app/models/user.rb'
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_user_migration
|
15
|
+
migration_template 'db/migrate/create_users.erb', 'db/migrate/create_users.rb'
|
16
|
+
end
|
17
|
+
|
18
|
+
def update_shopify_app_initializer
|
19
|
+
gsub_file 'config/initializers/shopify_app.rb', 'ShopifyApp::InMemorySessionStore', 'User'
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_user_fixtures
|
23
|
+
copy_file 'users.yml', 'test/fixtures/users.yml'
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def rails_migration_version
|
29
|
+
Rails.version.match(/\d\.\d/)[0]
|
30
|
+
end
|
31
|
+
|
32
|
+
# for generating a timestamp when using `create_migration`
|
33
|
+
def self.next_migration_number(dir)
|
34
|
+
ActiveRecord::Generators::Base.next_migration_number(dir)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/shopify_app.rb
CHANGED
@@ -44,6 +44,8 @@ module ShopifyApp
|
|
44
44
|
require 'shopify_app/managers/scripttags_manager'
|
45
45
|
|
46
46
|
# session
|
47
|
+
require 'shopify_app/session/storage_strategies/shop_storage_strategy'
|
48
|
+
require 'shopify_app/session/storage_strategies/user_storage_strategy'
|
47
49
|
require 'shopify_app/session/session_storage'
|
48
50
|
require 'shopify_app/session/session_repository'
|
49
51
|
require 'shopify_app/session/in_memory_session_store'
|
@@ -15,6 +15,8 @@ module ShopifyApp
|
|
15
15
|
attr_accessor :scripttags
|
16
16
|
attr_accessor :after_authenticate_job
|
17
17
|
attr_accessor :session_repository
|
18
|
+
attr_accessor :per_user_tokens
|
19
|
+
alias_method :per_user_tokens?, :per_user_tokens
|
18
20
|
attr_accessor :api_version
|
19
21
|
|
20
22
|
# customise urls
|
@@ -39,6 +41,7 @@ module ShopifyApp
|
|
39
41
|
@myshopify_domain = 'myshopify.com'
|
40
42
|
@scripttags_manager_queue_name = Rails.application.config.active_job.queue_name
|
41
43
|
@webhooks_manager_queue_name = Rails.application.config.active_job.queue_name
|
44
|
+
@per_user_tokens = false
|
42
45
|
@disable_webpacker = ENV['SHOPIFY_APP_DISABLE_WEBPACKER'].present?
|
43
46
|
end
|
44
47
|
|
@@ -63,6 +66,7 @@ module ShopifyApp
|
|
63
66
|
def has_scripttags?
|
64
67
|
scripttags.present?
|
65
68
|
end
|
69
|
+
|
66
70
|
end
|
67
71
|
|
68
72
|
def self.configuration
|
@@ -27,12 +27,30 @@ module ShopifyApp
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def shop_session
|
30
|
-
|
31
|
-
|
30
|
+
if ShopifyApp.configuration.per_user_tokens?
|
31
|
+
return unless session[:shopify_user]
|
32
|
+
@shop_session ||= ShopifyApp::SessionRepository.retrieve(session[:shopify_user]['id'])
|
33
|
+
else
|
34
|
+
return unless session[:shopify]
|
35
|
+
@shop_session ||= ShopifyApp::SessionRepository.retrieve(session[:shopify])
|
36
|
+
end
|
32
37
|
end
|
33
38
|
|
34
|
-
def
|
39
|
+
def login_again_if_different_user_or_shop
|
40
|
+
if ShopifyApp.configuration.per_user_tokens?
|
41
|
+
valid_session_data = session[:user_session].present? && params[:session].present? # session data was sent/stored correctly
|
42
|
+
sessions_do_not_match = session[:user_session] != params[:session] # current user is different from stored user
|
43
|
+
|
44
|
+
if valid_session_data && sessions_do_not_match
|
45
|
+
clear_session = true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
35
49
|
if shop_session && params[:shop] && params[:shop].is_a?(String) && (shop_session.domain != params[:shop])
|
50
|
+
clear_session = true
|
51
|
+
end
|
52
|
+
|
53
|
+
if clear_session
|
36
54
|
clear_shop_session
|
37
55
|
redirect_to_login
|
38
56
|
end
|
@@ -60,6 +78,7 @@ module ShopifyApp
|
|
60
78
|
session[:shopify] = nil
|
61
79
|
session[:shopify_domain] = nil
|
62
80
|
session[:shopify_user] = nil
|
81
|
+
session[:user_session] = nil
|
63
82
|
end
|
64
83
|
|
65
84
|
def login_url_with_optional_shop(top_level: false)
|
@@ -3,9 +3,12 @@ module ShopifyApp
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
validates :shopify_domain, presence: true, uniqueness: { case_sensitive: false }
|
7
6
|
validates :shopify_token, presence: true
|
8
7
|
validates :api_version, presence: true
|
8
|
+
validates :shopify_domain, presence: true,
|
9
|
+
if: Proc.new {|_| ShopifyApp.configuration.per_user_tokens? }
|
10
|
+
validates :shopify_domain, presence: true, uniqueness: { case_sensitive: false },
|
11
|
+
if: Proc.new {|_| !ShopifyApp.configuration.per_user_tokens? }
|
9
12
|
end
|
10
13
|
|
11
14
|
def with_shopify_session(&block)
|
@@ -18,23 +21,19 @@ module ShopifyApp
|
|
18
21
|
end
|
19
22
|
|
20
23
|
class_methods do
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
|
25
|
+
def strategy_klass
|
26
|
+
ShopifyApp.configuration.per_user_tokens? ?
|
27
|
+
ShopifyApp::SessionStorage::UserStorageStrategy :
|
28
|
+
ShopifyApp::SessionStorage::ShopStorageStrategy
|
26
29
|
end
|
27
30
|
|
28
|
-
def
|
29
|
-
|
31
|
+
def store(auth_session, user: nil)
|
32
|
+
strategy_klass.store(auth_session, user)
|
33
|
+
end
|
30
34
|
|
31
|
-
|
32
|
-
|
33
|
-
domain: shop.shopify_domain,
|
34
|
-
token: shop.shopify_token,
|
35
|
-
api_version: shop.api_version
|
36
|
-
)
|
37
|
-
end
|
35
|
+
def retrieve(id)
|
36
|
+
strategy_klass.retrieve(id)
|
38
37
|
end
|
39
38
|
end
|
40
39
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ShopifyApp
|
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)
|
7
|
+
shop.shopify_token = auth_session.token
|
8
|
+
shop.save!
|
9
|
+
shop.id
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.retrieve(id)
|
13
|
+
return unless id
|
14
|
+
if shop = Shop.find_by(id: id)
|
15
|
+
ShopifyAPI::Session.new(
|
16
|
+
domain: shop.shopify_domain,
|
17
|
+
token: shop.shopify_token,
|
18
|
+
api_version: shop.api_version
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ShopifyApp
|
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])
|
7
|
+
user.shopify_token = auth_session.token
|
8
|
+
user.shopify_domain = auth_session.domain
|
9
|
+
user.save!
|
10
|
+
user.id
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.retrieve(id)
|
14
|
+
return unless id
|
15
|
+
if user = User.find_by(shopify_user_id: id)
|
16
|
+
ShopifyAPI::Session.new(
|
17
|
+
domain: user.shopify_domain,
|
18
|
+
token: user.shopify_token,
|
19
|
+
api_version: user.api_version
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/shopify_app/version.rb
CHANGED
data/package-lock.json
CHANGED
@@ -5909,12 +5909,6 @@
|
|
5909
5909
|
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
5910
5910
|
"dev": true
|
5911
5911
|
},
|
5912
|
-
"serialize-javascript": {
|
5913
|
-
"version": "1.9.1",
|
5914
|
-
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz",
|
5915
|
-
"integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==",
|
5916
|
-
"dev": true
|
5917
|
-
},
|
5918
5912
|
"set-blocking": {
|
5919
5913
|
"version": "2.0.0",
|
5920
5914
|
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
@@ -6497,31 +6491,6 @@
|
|
6497
6491
|
}
|
6498
6492
|
}
|
6499
6493
|
},
|
6500
|
-
"terser-webpack-plugin": {
|
6501
|
-
"version": "1.4.1",
|
6502
|
-
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz",
|
6503
|
-
"integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==",
|
6504
|
-
"dev": true,
|
6505
|
-
"requires": {
|
6506
|
-
"cacache": "12.0.3",
|
6507
|
-
"find-cache-dir": "2.1.0",
|
6508
|
-
"is-wsl": "1.1.0",
|
6509
|
-
"schema-utils": "1.0.0",
|
6510
|
-
"serialize-javascript": "1.9.1",
|
6511
|
-
"source-map": "0.6.1",
|
6512
|
-
"terser": "4.3.1",
|
6513
|
-
"webpack-sources": "1.4.3",
|
6514
|
-
"worker-farm": "1.7.0"
|
6515
|
-
},
|
6516
|
-
"dependencies": {
|
6517
|
-
"source-map": {
|
6518
|
-
"version": "0.6.1",
|
6519
|
-
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
6520
|
-
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
6521
|
-
"dev": true
|
6522
|
-
}
|
6523
|
-
}
|
6524
|
-
},
|
6525
6494
|
"through2": {
|
6526
6495
|
"version": "2.0.5",
|
6527
6496
|
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
|
@@ -6878,9 +6847,9 @@
|
|
6878
6847
|
}
|
6879
6848
|
},
|
6880
6849
|
"webpack": {
|
6881
|
-
"version": "4.
|
6882
|
-
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.
|
6883
|
-
"integrity": "sha512-
|
6850
|
+
"version": "4.41.3",
|
6851
|
+
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.3.tgz",
|
6852
|
+
"integrity": "sha512-EcNzP9jGoxpQAXq1VOoTet0ik7/VVU1MovIfcUSAjLowc7GhcQku/sOXALvq5nPpSei2HF6VRhibeJSC3i/Law==",
|
6884
6853
|
"dev": true,
|
6885
6854
|
"requires": {
|
6886
6855
|
"@webassemblyjs/ast": "1.8.5",
|
@@ -6903,7 +6872,7 @@
|
|
6903
6872
|
"node-libs-browser": "2.2.1",
|
6904
6873
|
"schema-utils": "1.0.0",
|
6905
6874
|
"tapable": "1.1.3",
|
6906
|
-
"terser-webpack-plugin": "1.4.
|
6875
|
+
"terser-webpack-plugin": "1.4.3",
|
6907
6876
|
"watchpack": "1.6.0",
|
6908
6877
|
"webpack-sources": "1.4.3"
|
6909
6878
|
},
|
@@ -6925,6 +6894,35 @@
|
|
6925
6894
|
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz",
|
6926
6895
|
"integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==",
|
6927
6896
|
"dev": true
|
6897
|
+
},
|
6898
|
+
"serialize-javascript": {
|
6899
|
+
"version": "2.1.2",
|
6900
|
+
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
|
6901
|
+
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
|
6902
|
+
"dev": true
|
6903
|
+
},
|
6904
|
+
"source-map": {
|
6905
|
+
"version": "0.6.1",
|
6906
|
+
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
6907
|
+
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
6908
|
+
"dev": true
|
6909
|
+
},
|
6910
|
+
"terser-webpack-plugin": {
|
6911
|
+
"version": "1.4.3",
|
6912
|
+
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz",
|
6913
|
+
"integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==",
|
6914
|
+
"dev": true,
|
6915
|
+
"requires": {
|
6916
|
+
"cacache": "12.0.3",
|
6917
|
+
"find-cache-dir": "2.1.0",
|
6918
|
+
"is-wsl": "1.1.0",
|
6919
|
+
"schema-utils": "1.0.0",
|
6920
|
+
"serialize-javascript": "2.1.2",
|
6921
|
+
"source-map": "0.6.1",
|
6922
|
+
"terser": "4.3.1",
|
6923
|
+
"webpack-sources": "1.4.3",
|
6924
|
+
"worker-farm": "1.7.0"
|
6925
|
+
}
|
6928
6926
|
}
|
6929
6927
|
}
|
6930
6928
|
},
|
data/package.json
CHANGED
data/service.yml
CHANGED
data/shopify_app.gemspec
CHANGED
@@ -18,6 +18,9 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.add_development_dependency('rake')
|
19
19
|
s.add_development_dependency('byebug')
|
20
20
|
s.add_development_dependency('pry')
|
21
|
+
s.add_development_dependency('pry-nav')
|
22
|
+
s.add_development_dependency('pry-stack_explorer')
|
23
|
+
s.add_development_dependency('rb-readline')
|
21
24
|
s.add_development_dependency('sqlite3', '~> 1.4')
|
22
25
|
s.add_development_dependency('minitest')
|
23
26
|
s.add_development_dependency('mocha')
|
@@ -26,4 +29,4 @@ Gem::Specification.new do |s|
|
|
26
29
|
s.files = `git ls-files`.split("\n").reject { |f| f.match(%r{^(test|example)/}) }
|
27
30
|
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
28
31
|
s.require_paths = ["lib"]
|
29
|
-
end
|
32
|
+
end
|
data/yarn.lock
CHANGED
@@ -4360,10 +4360,10 @@ semver@^6.3.0:
|
|
4360
4360
|
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
4361
4361
|
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
4362
4362
|
|
4363
|
-
serialize-javascript@^1.
|
4364
|
-
version "1.
|
4365
|
-
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.
|
4366
|
-
integrity sha512-
|
4363
|
+
serialize-javascript@^2.1.2:
|
4364
|
+
version "2.1.2"
|
4365
|
+
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
|
4366
|
+
integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==
|
4367
4367
|
|
4368
4368
|
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
4369
4369
|
version "2.0.0"
|
@@ -4769,16 +4769,16 @@ tar@^4:
|
|
4769
4769
|
safe-buffer "^5.1.2"
|
4770
4770
|
yallist "^3.0.3"
|
4771
4771
|
|
4772
|
-
terser-webpack-plugin@^1.4.
|
4773
|
-
version "1.4.
|
4774
|
-
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.
|
4775
|
-
integrity sha512-
|
4772
|
+
terser-webpack-plugin@^1.4.3:
|
4773
|
+
version "1.4.3"
|
4774
|
+
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c"
|
4775
|
+
integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==
|
4776
4776
|
dependencies:
|
4777
4777
|
cacache "^12.0.2"
|
4778
4778
|
find-cache-dir "^2.1.0"
|
4779
4779
|
is-wsl "^1.1.0"
|
4780
4780
|
schema-utils "^1.0.0"
|
4781
|
-
serialize-javascript "^1.
|
4781
|
+
serialize-javascript "^2.1.2"
|
4782
4782
|
source-map "^0.6.1"
|
4783
4783
|
terser "^4.1.2"
|
4784
4784
|
webpack-sources "^1.4.0"
|
@@ -5083,10 +5083,10 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1:
|
|
5083
5083
|
source-list-map "^2.0.0"
|
5084
5084
|
source-map "~0.6.1"
|
5085
5085
|
|
5086
|
-
webpack@^4.
|
5087
|
-
version "4.
|
5088
|
-
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.
|
5089
|
-
integrity sha512-
|
5086
|
+
webpack@^4.41.3:
|
5087
|
+
version "4.41.3"
|
5088
|
+
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.3.tgz#cb7592c43080337dbc9be9e98fc6478eb3981026"
|
5089
|
+
integrity sha512-EcNzP9jGoxpQAXq1VOoTet0ik7/VVU1MovIfcUSAjLowc7GhcQku/sOXALvq5nPpSei2HF6VRhibeJSC3i/Law==
|
5090
5090
|
dependencies:
|
5091
5091
|
"@webassemblyjs/ast" "1.8.5"
|
5092
5092
|
"@webassemblyjs/helper-module-context" "1.8.5"
|
@@ -5108,7 +5108,7 @@ webpack@^4.40.2:
|
|
5108
5108
|
node-libs-browser "^2.2.1"
|
5109
5109
|
schema-utils "^1.0.0"
|
5110
5110
|
tapable "^1.1.3"
|
5111
|
-
terser-webpack-plugin "^1.4.
|
5111
|
+
terser-webpack-plugin "^1.4.3"
|
5112
5112
|
watchpack "^1.6.0"
|
5113
5113
|
webpack-sources "^1.4.1"
|
5114
5114
|
|
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.
|
4
|
+
version: 11.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: browser_sniffer
|
@@ -108,6 +108,48 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry-nav
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: pry-stack_explorer
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rb-readline
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
111
153
|
- !ruby/object:Gem::Dependency
|
112
154
|
name: sqlite3
|
113
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -275,6 +317,10 @@ files:
|
|
275
317
|
- lib/generators/shopify_app/shop_model/templates/shop.rb
|
276
318
|
- lib/generators/shopify_app/shop_model/templates/shops.yml
|
277
319
|
- lib/generators/shopify_app/shopify_app_generator.rb
|
320
|
+
- lib/generators/shopify_app/user_model/templates/db/migrate/create_users.erb
|
321
|
+
- lib/generators/shopify_app/user_model/templates/user.rb
|
322
|
+
- lib/generators/shopify_app/user_model/templates/users.yml
|
323
|
+
- lib/generators/shopify_app/user_model/user_model_generator.rb
|
278
324
|
- lib/generators/shopify_app/views/views_generator.rb
|
279
325
|
- lib/shopify_app.rb
|
280
326
|
- lib/shopify_app/configuration.rb
|
@@ -293,6 +339,8 @@ files:
|
|
293
339
|
- lib/shopify_app/session/in_memory_session_store.rb
|
294
340
|
- lib/shopify_app/session/session_repository.rb
|
295
341
|
- lib/shopify_app/session/session_storage.rb
|
342
|
+
- lib/shopify_app/session/storage_strategies/shop_storage_strategy.rb
|
343
|
+
- lib/shopify_app/session/storage_strategies/user_storage_strategy.rb
|
296
344
|
- lib/shopify_app/utils.rb
|
297
345
|
- lib/shopify_app/version.rb
|
298
346
|
- package-lock.json
|