shopify_app 21.9.0 → 21.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0235c0e9ef88bf1ffa1b0fde1d62f2af79c3d2bd2a0e45dfd454f9d26dc30b53
4
- data.tar.gz: 1f00756ed0f26034b996b24db4cc2297e56afeffd0b3f28b6d22ecdc7f78dbe9
3
+ metadata.gz: 927f0886c6d7be713738a4c38d2a1c5319593d2d8e4d200d854957abae73ac09
4
+ data.tar.gz: cca13c50d4cc99853ef10e119d4cb10cf96ba786ee9e146c2acacc12758d741f
5
5
  SHA512:
6
- metadata.gz: a8c1116442619ef12195cf15ef38307f720640eb6993d2bfa174fb842878ff9af890a663271bf03aa556ee1fa86a7311956d6d29a8188e26276993c0d5e83057
7
- data.tar.gz: c6d78960aeba7353bea99a234adf87d772bf371f43d027dfcd32bb8e89d38aef00879b5a31aa655fcabe3f348a8d50c3553d87b845f8ac4b1e8f12eab8bb0385
6
+ metadata.gz: db9c6d4fdee1744d974fcde46f54d4246c2886dafb4d31f3423d9c903566f730c06a0b3187a21cdd534d7ee63be95c1fa318e85c007b53f682cbf7a6d3184df2
7
+ data.tar.gz: eb437382bf4fba13da3d3780fd05e29360807c8d999239d129dd4ff5e92fc63de33dea382deb9ab9f0e9552d208a1405acb5aa68cb85c20a7310afd81681bcb0
@@ -11,7 +11,7 @@ jobs:
11
11
  steps:
12
12
  - name: Extract tag name
13
13
  id: tag
14
- run: echo "::set-output name=value::${GITHUB_REF##*/}"
14
+ run: echo "value=${GITHUB_REF##*/}" >> "$GITHUB_OUTPUT"
15
15
  - uses: actions/checkout@v3
16
16
 
17
17
  - name: Create Release
data/CHANGELOG.md CHANGED
@@ -1,7 +1,12 @@
1
1
  Unreleased
2
2
  ----------
3
3
 
4
- 21.9.0 (January 16, 2023)
4
+ 21.10.0 (January 24, 2024)
5
+ ----------
6
+ * Fix session deletion for users with customized session storage[#1773](https://github.com/Shopify/shopify_app/pull/1773)
7
+ * Add configuration flag `check_session_expiry_date` to trigger a re-auth when the (user) session is expired. The session expiry date must be stored and retrieved for this flag to be effective. When the `UserSessionStorageWithScopes` concern is used, a DB migration can be generated with `rails generate shopify_app:user_model --skip` and should be applied before enabling that flag[#1757](https://github.com/Shopify/shopify_app/pull/1757)
8
+
9
+ 21.9.0 (January 16, 2024)
5
10
  ----------
6
11
  * Fix `add_webhook` generator to create the webhook jobs under the correct directory[#1748](https://github.com/Shopify/shopify_app/pull/1748)
7
12
  * Add support for metafield_namespaces in webhook registration [#1745](https://github.com/Shopify/shopify_app/pull/1745)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shopify_app (21.9.0)
4
+ shopify_app (21.10.0)
5
5
  activeresource
6
6
  addressable (~> 2.7)
7
7
  browser_sniffer (~> 2.0)
@@ -4,23 +4,27 @@ Sessions are used to make contextual API calls for either a shop (offline sessio
4
4
 
5
5
  #### Table of contents
6
6
 
7
- - [Sessions](#sessions-1)
8
- - [Types of session tokens](#types-of-session-tokens) - Shop (offline) v.s. User (online)
9
- - [Session token storage](#session-token-storage)
10
- - [Shop (offline) token storage](#shop-offline-token-storage)
11
- - [User (online) token storage](#user-online-token-storage)
12
- - [In-Memory Session Storage for Testing](#in-memory-session-storage-for-testing)
13
- - [Customizing Session Storage with `ShopifyApp::SessionRepository`](#customizing-session-storage-with-shopifyappsessionrepository)
14
- - [Loading Sessions](#loading-sessions)
7
+ - [Sessions](#sessions)
8
+ - [Table of contents](#table-of-contents)
9
+ - [Sessions](#sessions-1)
10
+ - [Types of session tokens](#types-of-session-tokens)
11
+ - [Session token storage](#session-token-storage)
12
+ - [Shop (offline) token storage](#shop-offline-token-storage)
13
+ - [User (online) token storage](#user-online-token-storage)
14
+ - [In-memory Session Storage for testing](#in-memory-session-storage-for-testing)
15
+ - [Customizing Session Storage with `ShopifyApp::SessionRepository`](#customizing-session-storage-with-shopifyappsessionrepository)
16
+ - [⚠️ Custom Session Storage Requirements](#️--custom-session-storage-requirements)
17
+ - [Available `ActiveSupport::Concerns` that contains implementation of the above methods](#available-activesupportconcerns-that-contains-implementation-of-the-above-methods)
18
+ - [Loading Sessions](#loading-sessions)
15
19
  - [Getting Sessions with Controller Concerns](#getting-sessions-with-controller-concerns)
16
- - [Shop session - "EnsureInstalled" ](#shop-sessions---ensureinstalled)
17
- - [User session - "EnsureHasSession" ](#user-sessions---ensurehassession)
18
- - [Getting Sessions from a Shop or User model record - "with_shopify_session"](#getting-sessions-from-a-shop-or-user-model-record---with_shopify_session)
19
- - [Access scopes](#access-scopes)
20
- - [`ShopifyApp::ShopSessionStorageWithScopes`](#shopifyappshopsessionstoragewithscopes)
21
- - [``ShopifyApp::UserSessionStorageWithScopes``](#shopifyappusersessionstoragewithscopes)
22
- - [Migrating from shop-based to user-based token strategy](#migrating-from-shop-based-to-user-based-token-strategy)
23
- - [Migrating from ShopifyApi::Auth::SessionStorage to ShopifyApp::SessionStorage](#migrating-from-shopifyapiauthsessionstorage-to-shopifyappsessionstorage)
20
+ - [**Shop Sessions - `EnsureInstalled`**](#shop-sessions---ensureinstalled)
21
+ - [User Sessions - `EnsureHasSession`](#user-sessions---ensurehassession)
22
+ - [Getting sessions from a Shop or User model record - 'with\_shopify\_session'](#getting-sessions-from-a-shop-or-user-model-record---with_shopify_session)
23
+ - [Access scopes](#access-scopes)
24
+ - [`ShopifyApp::ShopSessionStorageWithScopes`](#shopifyappshopsessionstoragewithscopes)
25
+ - [`ShopifyApp::UserSessionStorageWithScopes`](#shopifyappusersessionstoragewithscopes)
26
+ - [Migrating from shop-based to user-based token strategy](#migrating-from-shop-based-to-user-based-token-strategy)
27
+ - [Migrating from `ShopifyApi::Auth::SessionStorage` to `ShopifyApp::SessionStorage`](#migrating-from-shopifyapiauthsessionstorage-to-shopifyappsessionstorage)
24
28
 
25
29
  ## Sessions
26
30
  #### Types of session tokens
@@ -103,6 +107,7 @@ The custom **Shop** repository must implement the following methods:
103
107
  | `self.store(auth_session)` | `auth_session` (ShopifyAPI::Auth::Session) | - |
104
108
  | `self.retrieve(id)` | `id` (String) | ShopifyAPI::Auth::Session |
105
109
  | `self.retrieve_by_shopify_domain(shopify_domain)` | `shopify_domain` (String) | ShopifyAPI::Auth::Session |
110
+ | `self.destroy_by_shopify_domain(shopify_domain)` | `shopify_domain` (String) | - |
106
111
 
107
112
  The custom **User** repository must implement the following methods:
108
113
  | Method | Parameters | Return Type |
@@ -110,6 +115,7 @@ The custom **User** repository must implement the following methods:
110
115
  | `self.store(auth_session, user)` | <li>`auth_session` (ShopifyAPI::Auth::Session)<br><li>`user` (ShopifyAPI::Auth::AssociatedUser) | - |
111
116
  | `self.retrieve(id)` | `id` (String) | `ShopifyAPI::Auth::Session` |
112
117
  | `self.retrieve_by_shopify_user_id(user_id)` | `user_id` (String) | `ShopifyAPI::Auth::Session` |
118
+ | `self.destroy_by_shopify_user_id(user_id)` | `user_id` (String) | - |
113
119
 
114
120
 
115
121
  These methods are already implemented as a part of the `User` and `Shop` models generated from this gem's generator.
@@ -153,7 +159,7 @@ end
153
159
  ```
154
160
 
155
161
  ##### User Sessions - `EnsureHasSession`
156
- - [EnsureHasSession](https://github.com/Shopify/shopify_app/blob/main/app/controllers/concerns/shopify_app/ensure_has_session.rb) controller concern will load a user session via `current_shopify_session`. As part of loading this session, this concern will also ensure that the user session has the appropriate scopes needed for the application. If the user isn't found or has fewer permitted scopes than are required, they will be prompted to authorize the application.
162
+ - [EnsureHasSession](https://github.com/Shopify/shopify_app/blob/main/app/controllers/concerns/shopify_app/ensure_has_session.rb) controller concern will load a user session via `current_shopify_session`. As part of loading this session, this concern will also ensure that the user session has the appropriate scopes needed for the application and that it is not expired (when `check_session_expiry_date` is enabled). If the user isn't found or has fewer permitted scopes than are required, they will be prompted to authorize the application.
157
163
  - This controller concern should be used if you don't need your app to make calls on behalf of a user. With that in mind, there are a few other embedded concerns that are mixed in to ensure that embedding, CSRF, localization, and billing allow the action for the user.
158
164
  - Example
159
165
  ```ruby
@@ -228,6 +234,9 @@ class User < ActiveRecord::Base
228
234
  end
229
235
  ```
230
236
 
237
+ ## Expiry date
238
+ When the configuration flag `check_session_expiry_date` is set to true, the user session expiry date will be checked to trigger a re-auth and get a fresh user token when it is expired. This requires the `ShopifyAPI::Auth::Session` `expires` attribute to be stored. When the `User` model includes the `UserSessionStorageWithScopes` concern, a DB migration can be generated with `rails generate shopify_app:user_model --skip` to add the `expires_at` attribute to the model.
239
+
231
240
  ## Migrating from shop-based to user-based token strategy
232
241
 
233
242
  1. Run the `user_model` generator as [mentioned above](#user-online-token-storage).
@@ -0,0 +1,5 @@
1
+ class AddUserExpiresAtColumn < ActiveRecord::Migration[<%= rails_migration_version %>]
2
+ def change
3
+ add_column :users, :expires_at, :datetime
4
+ end
5
+ end
@@ -40,6 +40,26 @@ module ShopifyApp
40
40
  end
41
41
  end
42
42
 
43
+ def create_expires_at_storage_in_user_model
44
+ expires_at_column_prompt = <<~PROMPT
45
+ It is highly recommended that apps record the User session expiry date. \
46
+ This will allow to check if the session has expired and re-authenticate \
47
+ without a first call to Shopify.
48
+
49
+ After running the migration, the `check_session_expiry_date` configuration can be enabled.
50
+
51
+ The following migration will add an `expires_at` column to the User model. \
52
+ Do you want to include this migration? [y/n]
53
+ PROMPT
54
+
55
+ if new_shopify_cli_app? || Rails.env.test? || yes?(expires_at_column_prompt)
56
+ migration_template(
57
+ "db/migrate/add_user_expires_at_column.erb",
58
+ "db/migrate/add_user_expires_at_column.rb",
59
+ )
60
+ end
61
+ end
62
+
43
63
  def update_shopify_app_initializer
44
64
  gsub_file("config/initializers/shopify_app.rb", "ShopifyApp::InMemoryUserSessionStore", "User")
45
65
  end
@@ -20,6 +20,7 @@ module ShopifyApp
20
20
  attr_accessor :api_version
21
21
 
22
22
  attr_accessor :reauth_on_access_scope_changes
23
+ attr_accessor :check_session_expiry_date
23
24
  attr_accessor :log_level
24
25
 
25
26
  # customise urls
@@ -44,6 +45,9 @@ module ShopifyApp
44
45
  # takes a ShopifyApp::BillingConfiguration object
45
46
  attr_accessor :billing
46
47
 
48
+ # Work in Progress: enables token exchange authentication flow
49
+ attr_accessor :wip_new_embedded_auth_strategy
50
+
47
51
  def initialize
48
52
  @root_url = "/"
49
53
  @myshopify_domain = "myshopify.com"
@@ -118,6 +122,10 @@ module ShopifyApp
118
122
  def user_access_scopes
119
123
  @user_access_scopes || scope
120
124
  end
125
+
126
+ def use_new_embedded_auth_strategy?
127
+ wip_new_embedded_auth_strategy && embedded_app?
128
+ end
121
129
  end
122
130
 
123
131
  class BillingConfiguration
@@ -30,6 +30,12 @@ module ShopifyApp
30
30
  return redirect_to_login
31
31
  end
32
32
 
33
+ if ShopifyApp.configuration.check_session_expiry_date && current_shopify_session.expired?
34
+ ShopifyApp::Logger.debug("Session expired, redirecting to login")
35
+ clear_shopify_session
36
+ return redirect_to_login
37
+ end
38
+
33
39
  if ShopifyApp.configuration.reauth_on_access_scope_changes &&
34
40
  !ShopifyApp.configuration.user_access_scopes_strategy.covers_scopes?(current_shopify_session)
35
41
  clear_shopify_session
@@ -23,6 +23,14 @@ module ShopifyApp
23
23
  user_storage.retrieve_by_shopify_user_id(user_id)
24
24
  end
25
25
 
26
+ def destroy_shop_session_by_domain(shopify_domain)
27
+ shop_storage.destroy_by_shopify_domain(shopify_domain)
28
+ end
29
+
30
+ def destroy_user_session_by_shopify_user_id(user_id)
31
+ user_storage.destroy_by_shopify_user_id(user_id)
32
+ end
33
+
26
34
  def store_shop_session(session)
27
35
  shop_storage.store(session)
28
36
  end
@@ -73,18 +81,17 @@ module ShopifyApp
73
81
  def delete_session(id)
74
82
  match = id.match(/^offline_(.*)/)
75
83
 
76
- record = if match
84
+ if match
77
85
  domain = match[1]
78
86
  ShopifyApp::Logger.debug("Destroying session by domain - domain: #{domain}")
79
- Shop.find_by(shopify_domain: match[1])
87
+ destroy_shop_session_by_domain(domain)
88
+
80
89
  else
81
90
  shopify_user_id = id.split("_").last
82
91
  ShopifyApp::Logger.debug("Destroying session by user - user_id: #{shopify_user_id}")
83
- User.find_by(shopify_user_id: shopify_user_id)
92
+ destroy_user_session_by_shopify_user_id(shopify_user_id)
84
93
  end
85
94
 
86
- record.destroy
87
-
88
95
  true
89
96
  end
90
97
 
@@ -27,6 +27,10 @@ module ShopifyApp
27
27
  construct_session(shop)
28
28
  end
29
29
 
30
+ def destroy_by_shopify_domain(domain)
31
+ destroy_by(shopify_domain: domain)
32
+ end
33
+
30
34
  private
31
35
 
32
36
  def construct_session(shop)
@@ -29,6 +29,10 @@ module ShopifyApp
29
29
  construct_session(shop)
30
30
  end
31
31
 
32
+ def destroy_by_shopify_domain(domain)
33
+ destroy_by(shopify_domain: domain)
34
+ end
35
+
32
36
  private
33
37
 
34
38
  def construct_session(shop)
@@ -28,6 +28,10 @@ module ShopifyApp
28
28
  construct_session(user)
29
29
  end
30
30
 
31
+ def destroy_by_shopify_user_id(user_id)
32
+ destroy_by(shopify_user_id: user_id)
33
+ end
34
+
31
35
  private
32
36
 
33
37
  def construct_session(user)
@@ -15,6 +15,7 @@ module ShopifyApp
15
15
  user.shopify_token = auth_session.access_token
16
16
  user.shopify_domain = auth_session.shop
17
17
  user.access_scopes = auth_session.scope.to_s
18
+ user.expires_at = auth_session.expires
18
19
 
19
20
  user.save!
20
21
  user.id
@@ -30,6 +31,10 @@ module ShopifyApp
30
31
  construct_session(user)
31
32
  end
32
33
 
34
+ def destroy_by_shopify_user_id(user_id)
35
+ destroy_by(shopify_user_id: user_id)
36
+ end
37
+
33
38
  private
34
39
 
35
40
  def construct_session(user)
@@ -52,6 +57,7 @@ module ShopifyApp
52
57
  scope: user.access_scopes,
53
58
  associated_user_scope: user.access_scopes,
54
59
  associated_user: associated_user,
60
+ expires: user.expires_at,
55
61
  )
56
62
  end
57
63
  end
@@ -67,5 +73,24 @@ module ShopifyApp
67
73
  rescue NotImplementedError, NoMethodError
68
74
  raise NotImplementedError, "#access_scopes= must be defined to hook into stored access scopes"
69
75
  end
76
+
77
+ def expires_at=(expires_at)
78
+ super
79
+ rescue NotImplementedError, NoMethodError
80
+ if ShopifyApp.configuration.check_session_expiry_date
81
+ raise NotImplementedError,
82
+ "#expires_at= must be defined to handle storing the session expiry date"
83
+ end
84
+ end
85
+
86
+ def expires_at
87
+ super
88
+ rescue NotImplementedError, NoMethodError
89
+ if ShopifyApp.configuration.check_session_expiry_date
90
+ raise NotImplementedError, "#expires_at must be defined to check the session expiry date"
91
+ end
92
+
93
+ nil
94
+ end
70
95
  end
71
96
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ShopifyApp
4
- VERSION = "21.9.0"
4
+ VERSION = "21.10.0"
5
5
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shopify_app",
3
- "version": "21.9.0",
3
+ "version": "21.10.0",
4
4
  "repository": "git@github.com:Shopify/shopify_app.git",
5
5
  "author": "Shopify",
6
6
  "license": "MIT",
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: 21.9.0
4
+ version: 21.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-16 00:00:00.000000000 Z
11
+ date: 2024-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activeresource
@@ -416,6 +416,7 @@ files:
416
416
  - lib/generators/shopify_app/shop_model/templates/shops.yml
417
417
  - lib/generators/shopify_app/shopify_app_generator.rb
418
418
  - lib/generators/shopify_app/user_model/templates/db/migrate/add_user_access_scopes_column.erb
419
+ - lib/generators/shopify_app/user_model/templates/db/migrate/add_user_expires_at_column.erb
419
420
  - lib/generators/shopify_app/user_model/templates/db/migrate/create_users.erb
420
421
  - lib/generators/shopify_app/user_model/templates/user.rb
421
422
  - lib/generators/shopify_app/user_model/templates/users.yml