shopify_app 12.0.2 → 12.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +23 -1
- data/app/assets/javascripts/shopify_app/storage_access.js +4 -4
- data/app/controllers/shopify_app/sessions_controller.rb +22 -9
- data/app/views/shopify_app/sessions/enable_cookies.html.erb +1 -1
- data/app/views/shopify_app/sessions/request_storage_access.html.erb +1 -1
- data/lib/shopify_app/configuration.rb +1 -1
- data/lib/shopify_app/controller_concerns/login_protection.rb +14 -2
- data/lib/shopify_app/engine.rb +1 -1
- data/lib/shopify_app/middleware/same_site_cookie_middleware.rb +18 -45
- data/lib/shopify_app/version.rb +1 -1
- data/package.json +1 -1
- data/shopify_app.gemspec +3 -3
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5acb9f9fb1606515013edfda25f981c36cf5ab4323572764ba9715018056532
|
4
|
+
data.tar.gz: e5499e7186fa12f37e01f975d7b67ed6a846d67679b580846a7191b53d81b3d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9e736b65bf5091c6ebdca30073653dde86abc131cd77747f872c0d42972bc35abdd406301e5a5eb0dd4f9273c66264c75b28e119d05d203e440038bb19250d3
|
7
|
+
data.tar.gz: 264ed359e7e07cf7b0947cbafad738cabf220e470872c663f18c2507c17c7d994316af275f1d28820d5624df03fabadf6f213475fb793b4fd024de514b636cf0
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
12.0.7
|
2
|
+
------
|
3
|
+
* Remove check for API_KEY in config that was throwing errors during install #919
|
4
|
+
|
5
|
+
12.0.6
|
6
|
+
------
|
7
|
+
* Adds changelog information and README updates for 8.4.0 #916
|
8
|
+
|
9
|
+
12.0.5
|
10
|
+
------
|
11
|
+
* Updating shopify_api gem to 9.0.1
|
12
|
+
|
13
|
+
12.0.4
|
14
|
+
------
|
15
|
+
* Reverts reverted PR (#895) #897
|
16
|
+
|
17
|
+
12.0.3
|
18
|
+
------
|
19
|
+
* Moves samesite middleware higher in the stack #898
|
20
|
+
* Fix issue where not redirecting user to granted storage page casues infinite loop #900
|
21
|
+
|
1
22
|
12.0.2
|
2
23
|
------
|
3
24
|
* Reverts "Fix for return_to in safari after enable_cookies/granted_storage_access" introduced in 12.0.1
|
@@ -178,6 +199,7 @@ Added support for rotating Shopify access tokens:
|
|
178
199
|
8.4.0
|
179
200
|
----
|
180
201
|
* Fix embedded app session management in Safari 12.1
|
202
|
+
* Note that with this change we have extracted the callback action in its own controller. If you are relying on it, see the README for more details: https://github.com/Shopify/shopify_app#callback
|
181
203
|
* Shop names passed to OAuth are no longer case sensitive
|
182
204
|
|
183
205
|
8.3.2
|
data/README.md
CHANGED
@@ -91,7 +91,9 @@ 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]. 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.
|
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
|
+
|
96
|
+
**You will need to load the ENV variables into your enviroment, you can do this with the [dot-env](https://github.com/bkeepers/dotenv) gem or any other method you wish to.**
|
95
97
|
|
96
98
|
### Install Generator
|
97
99
|
|
@@ -211,6 +213,17 @@ end
|
|
211
213
|
Authentication
|
212
214
|
--------------
|
213
215
|
|
216
|
+
### Callback
|
217
|
+
|
218
|
+
Upon completing the authentication flow Shopify calls the app at the `callback_path` mentioned before. If the app needs to do some extra work it can define and configure the route to a custom callback controller, inheriting from `ShopifyApp::CallbackController` and hook into or override any of the defined helper methods. The default callback controller already provides the following behaviour:
|
219
|
+
* Logging into the shop and resetting the session
|
220
|
+
* [Installing Webhooks](https://github.com/Shopify/shopify_app#webhooksmanager)
|
221
|
+
* [Setting Scripttags](https://github.com/Shopify/shopify_app#scripttagsmanager)
|
222
|
+
* [Performing the AfterAuthenticate Job](https://github.com/Shopify/shopify_app#afterauthenticatejob)
|
223
|
+
* Redirecting to the return address
|
224
|
+
|
225
|
+
**Note that starting with version 8.4.0, we have extracted the callback logic in its own controller. If you are upgrading from a version older than 8.4.0 the callback action and related helper methods were defined in `ShopifyApp::SessionsController` ==> you will have to extend `ShopifyApp::CallbackController` instead and port your logic to the new controller.**
|
226
|
+
|
214
227
|
### ShopifyApp::SessionRepository
|
215
228
|
|
216
229
|
`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.
|
@@ -287,6 +300,14 @@ bin/rails g shopify_app:add_after_authenticate_job
|
|
287
300
|
|
288
301
|
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.
|
289
302
|
|
303
|
+
API Versioning
|
304
|
+
--------------
|
305
|
+
|
306
|
+
Shopify's API is versioned, and you can [read about that process in the Shopify Developers documentation page](https://shopify.dev/concepts/about-apis/versioning).
|
307
|
+
|
308
|
+
Since shopify_app gem version 1.11.0, the included shopify_api gem has also been updated to allow you to easily set and switch what version of the Shopify API you want your app or service to use, as well as surface warnings to Rails apps about [deprecated endpoints, GraphQL fields and more](https://shopify.dev/concepts/about-apis/versioning#deprecation-practices).
|
309
|
+
|
310
|
+
See the [shopify_api gem README](https://github.com/Shopify/shopify_api/) for more details.
|
290
311
|
|
291
312
|
WebhooksManager
|
292
313
|
---------------
|
@@ -463,6 +484,7 @@ Questions or problems?
|
|
463
484
|
|
464
485
|
- [Ask questions!](https://ecommerce.shopify.com/c/shopify-apis-and-technology)
|
465
486
|
- [Read the docs!](https://help.shopify.com/api/guides)
|
487
|
+
- And don't forget to check the [Changelog](https://github.com/Shopify/shopify_app/blob/master/CHANGELOG.md) too!
|
466
488
|
|
467
489
|
Upgrading to 11.7.0
|
468
490
|
---------------------------
|
@@ -28,8 +28,8 @@
|
|
28
28
|
window.parent.location.href = this.redirectData.myshopifyUrl + '/admin/apps';
|
29
29
|
}
|
30
30
|
|
31
|
-
StorageAccessHelper.prototype.
|
32
|
-
window.location.href = this.redirectData.
|
31
|
+
StorageAccessHelper.prototype.redirectToAppTargetUrl = function() {
|
32
|
+
window.location.href = this.redirectData.appTargetUrl;
|
33
33
|
}
|
34
34
|
|
35
35
|
StorageAccessHelper.prototype.sameSiteNoneIncompatible = function(ua) {
|
@@ -68,7 +68,7 @@
|
|
68
68
|
if (!document.cookie) {
|
69
69
|
throw 'Cannot set third-party cookie.'
|
70
70
|
}
|
71
|
-
this.
|
71
|
+
this.redirectToAppTargetUrl();
|
72
72
|
} catch (error) {
|
73
73
|
console.warn('Third party cookies may be blocked.', error);
|
74
74
|
this.redirectToAppTLD(ACCESS_DENIED_STATUS);
|
@@ -90,7 +90,7 @@
|
|
90
90
|
StorageAccessHelper.prototype.handleHasStorageAccess = function() {
|
91
91
|
if (sessionStorage.getItem('shopify.granted_storage_access')) {
|
92
92
|
// If app was classified by ITP and used Storage Access API to acquire access
|
93
|
-
this.
|
93
|
+
this.redirectToAppTargetUrl();
|
94
94
|
} else {
|
95
95
|
// If app has not been classified by ITP and still has storage access
|
96
96
|
this.redirectToAppTLD(ACCESS_GRANTED_STATUS);
|
@@ -20,11 +20,15 @@ module ShopifyApp
|
|
20
20
|
|
21
21
|
render(:enable_cookies, layout: false, locals: {
|
22
22
|
does_not_have_storage_access_url: top_level_interaction_path(
|
23
|
-
shop: sanitized_shop_name
|
23
|
+
shop: sanitized_shop_name,
|
24
|
+
return_to: params[:return_to]
|
24
25
|
),
|
25
26
|
has_storage_access_url: login_url_with_optional_shop(top_level: true),
|
26
|
-
|
27
|
-
|
27
|
+
app_target_url: granted_storage_access_path(
|
28
|
+
shop: sanitized_shop_name,
|
29
|
+
return_to: params[:return_to]
|
30
|
+
),
|
31
|
+
current_shopify_domain: current_shopify_domain
|
28
32
|
})
|
29
33
|
end
|
30
34
|
|
@@ -38,8 +42,9 @@ module ShopifyApp
|
|
38
42
|
|
39
43
|
session['shopify.granted_storage_access'] = true
|
40
44
|
|
41
|
-
|
42
|
-
|
45
|
+
copy_return_to_param_to_session
|
46
|
+
|
47
|
+
redirect_to(return_address_with_params({ shop: @shop }))
|
43
48
|
end
|
44
49
|
|
45
50
|
def destroy
|
@@ -54,7 +59,7 @@ module ShopifyApp
|
|
54
59
|
return render_invalid_shop_error unless sanitized_shop_name.present?
|
55
60
|
session['shopify.omniauth_params'] = { shop: sanitized_shop_name }
|
56
61
|
|
57
|
-
|
62
|
+
copy_return_to_param_to_session
|
58
63
|
|
59
64
|
if user_agent_can_partition_cookies
|
60
65
|
authenticate_with_partitioning
|
@@ -93,6 +98,10 @@ module ShopifyApp
|
|
93
98
|
true
|
94
99
|
end
|
95
100
|
|
101
|
+
def copy_return_to_param_to_session
|
102
|
+
session[:return_to] = params[:return_to] if params[:return_to]
|
103
|
+
end
|
104
|
+
|
96
105
|
def render_invalid_shop_error
|
97
106
|
flash[:error] = I18n.t('invalid_shop_url')
|
98
107
|
redirect_to return_address
|
@@ -133,11 +142,15 @@ module ShopifyApp
|
|
133
142
|
layout: false,
|
134
143
|
locals: {
|
135
144
|
does_not_have_storage_access_url: top_level_interaction_path(
|
136
|
-
shop: sanitized_shop_name
|
145
|
+
shop: sanitized_shop_name,
|
146
|
+
return_to: session[:return_to]
|
137
147
|
),
|
138
148
|
has_storage_access_url: login_url_with_optional_shop(top_level: true),
|
139
|
-
|
140
|
-
|
149
|
+
app_target_url: granted_storage_access_path(
|
150
|
+
shop: sanitized_shop_name,
|
151
|
+
return_to: session[:return_to]
|
152
|
+
),
|
153
|
+
current_shopify_domain: current_shopify_domain
|
141
154
|
}
|
142
155
|
)
|
143
156
|
end
|
@@ -32,7 +32,7 @@
|
|
32
32
|
myshopifyUrl: "https://#{current_shopify_domain}",
|
33
33
|
hasStorageAccessUrl: "#{has_storage_access_url}",
|
34
34
|
doesNotHaveStorageAccessUrl: "#{does_not_have_storage_access_url}",
|
35
|
-
|
35
|
+
appTargetUrl: "#{app_target_url}"
|
36
36
|
},
|
37
37
|
},
|
38
38
|
)
|
@@ -24,7 +24,7 @@
|
|
24
24
|
myshopifyUrl: "https://#{current_shopify_domain}",
|
25
25
|
hasStorageAccessUrl: "#{has_storage_access_url}",
|
26
26
|
doesNotHaveStorageAccessUrl: "#{does_not_have_storage_access_url}",
|
27
|
-
|
27
|
+
appTargetUrl: "#{app_target_url}"
|
28
28
|
},
|
29
29
|
},
|
30
30
|
)
|
@@ -5,7 +5,7 @@ module ShopifyApp
|
|
5
5
|
# for the app in your Shopify Partners page. Change your settings in
|
6
6
|
# `config/initializers/shopify_app.rb`
|
7
7
|
attr_accessor :application_name
|
8
|
-
attr_accessor
|
8
|
+
attr_accessor :api_key
|
9
9
|
attr_accessor :secret
|
10
10
|
attr_accessor :old_secret
|
11
11
|
attr_accessor :scope
|
@@ -100,8 +100,10 @@ module ShopifyApp
|
|
100
100
|
query_params = {}
|
101
101
|
query_params[:shop] = sanitized_params[:shop] if params[:shop].present?
|
102
102
|
|
103
|
-
|
104
|
-
|
103
|
+
return_to = session[:return_to] || params[:return_to]
|
104
|
+
|
105
|
+
if return_to.present? && return_to_param_required?
|
106
|
+
query_params[:return_to] = return_to
|
105
107
|
end
|
106
108
|
|
107
109
|
has_referer_shop_name = referer_sanitized_shop_name.present?
|
@@ -165,5 +167,15 @@ module ShopifyApp
|
|
165
167
|
def return_address
|
166
168
|
session.delete(:return_to) || ShopifyApp.configuration.root_url
|
167
169
|
end
|
170
|
+
|
171
|
+
def return_address_with_params(params)
|
172
|
+
uri = URI(return_address)
|
173
|
+
uri.query = CGI.parse(uri.query.to_s)
|
174
|
+
.symbolize_keys
|
175
|
+
.transform_values { |v| v.one? ? v.first : v }
|
176
|
+
.merge(params)
|
177
|
+
.to_query
|
178
|
+
uri.to_s
|
179
|
+
end
|
168
180
|
end
|
169
181
|
end
|
data/lib/shopify_app/engine.rb
CHANGED
@@ -14,7 +14,7 @@ module ShopifyApp
|
|
14
14
|
end
|
15
15
|
|
16
16
|
initializer "shopify_app.middleware" do |app|
|
17
|
-
app.config.middleware.
|
17
|
+
app.config.middleware.insert_after(::Rack::Runtime, ShopifyApp::SameSiteCookieMiddleware)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -1,60 +1,33 @@
|
|
1
1
|
module ShopifyApp
|
2
2
|
class SameSiteCookieMiddleware
|
3
|
+
COOKIE_SEPARATOR = "\n"
|
4
|
+
|
3
5
|
def initialize(app)
|
4
6
|
@app = app
|
5
7
|
end
|
6
8
|
|
7
9
|
def call(env)
|
8
|
-
|
9
|
-
ensure
|
10
|
+
status, headers, body = @app.call(env)
|
10
11
|
user_agent = env['HTTP_USER_AGENT']
|
11
12
|
|
12
|
-
if headers && headers['Set-Cookie'] &&
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
if headers && headers['Set-Cookie'] &&
|
14
|
+
BrowserSniffer.new(user_agent).same_site_none_compatible? &&
|
15
|
+
ShopifyApp.configuration.enable_same_site_none &&
|
16
|
+
Rack::Request.new(env).ssl?
|
17
|
+
|
18
|
+
set_cookies = headers['Set-Cookie']
|
19
|
+
.split(COOKIE_SEPARATOR)
|
20
|
+
.compact
|
21
|
+
.map do |cookie|
|
22
|
+
cookie << '; Secure' if not cookie =~ /;\s*secure/i
|
23
|
+
cookie << '; SameSite=None' unless cookie =~ /;\s*samesite=/i
|
24
|
+
cookie
|
20
25
|
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
26
|
|
25
|
-
|
26
|
-
|
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
|
27
|
+
headers['Set-Cookie'] = set_cookies.join(COOKIE_SEPARATOR)
|
28
|
+
end
|
54
29
|
|
55
|
-
|
56
|
-
return digits[1] > minor if digits[1] != minor
|
57
|
-
digits[2] >= build
|
30
|
+
[status, headers, body]
|
58
31
|
end
|
59
32
|
end
|
60
33
|
end
|
data/lib/shopify_app/version.rb
CHANGED
data/package.json
CHANGED
data/shopify_app.gemspec
CHANGED
@@ -10,9 +10,9 @@ Gem::Specification.new do |s|
|
|
10
10
|
|
11
11
|
s.required_ruby_version = ">= 2.3.1"
|
12
12
|
|
13
|
-
s.add_runtime_dependency('browser_sniffer', '~> 1.
|
13
|
+
s.add_runtime_dependency('browser_sniffer', '~> 1.2.0')
|
14
14
|
s.add_runtime_dependency('rails', '> 5.2.1')
|
15
|
-
s.add_runtime_dependency('shopify_api', '~> 9.0')
|
15
|
+
s.add_runtime_dependency('shopify_api', '~> 9.0.1')
|
16
16
|
s.add_runtime_dependency('omniauth-shopify-oauth2', '~> 2.2.0')
|
17
17
|
|
18
18
|
s.add_development_dependency('rake')
|
@@ -29,4 +29,4 @@ Gem::Specification.new do |s|
|
|
29
29
|
s.files = `git ls-files`.split("\n").reject { |f| f.match(%r{^(test|example)/}) }
|
30
30
|
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
31
31
|
s.require_paths = ["lib"]
|
32
|
-
end
|
32
|
+
end
|
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: 12.0.
|
4
|
+
version: 12.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: browser_sniffer
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: 1.2.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: 1.2.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rails
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 9.0.1
|
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:
|
54
|
+
version: 9.0.1
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: omniauth-shopify-oauth2
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|