shopify_app 21.3.1 → 21.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/ENHANCEMENT.md +9 -0
- data/.github/ISSUE_TEMPLATE/bug-report.md +24 -46
- data/.github/ISSUE_TEMPLATE/feature-request.md +5 -29
- data/CHANGELOG.md +13 -0
- data/CONTRIBUTING.md +17 -2
- data/Gemfile.lock +11 -13
- data/app/controllers/concerns/shopify_app/ensure_installed.rb +18 -2
- data/app/controllers/shopify_app/callback_controller.rb +4 -0
- data/docs/shopify_app/engine.md +2 -11
- data/docs/shopify_app/session-repository.md +1 -10
- data/docs/shopify_app/testing.md +32 -10
- data/lib/shopify_app/controller_concerns/login_protection.rb +5 -2
- data/lib/shopify_app/controller_concerns/redirect_for_embedded.rb +5 -1
- data/lib/shopify_app/managers/webhooks_manager.rb +3 -3
- data/lib/shopify_app/session/jwt.rb +1 -2
- data/lib/shopify_app/test_helpers/all.rb +1 -0
- data/lib/shopify_app/test_helpers/shopify_session_helper.rb +15 -0
- data/lib/shopify_app/utils.rb +59 -28
- data/lib/shopify_app/version.rb +1 -1
- data/lib/shopify_app.rb +1 -0
- data/package.json +1 -1
- data/shopify_app.gemspec +2 -1
- metadata +20 -17
- data/app/assets/javascripts/shopify_app/enable_cookies.js +0 -3
- data/app/assets/javascripts/shopify_app/itp_helper.js +0 -40
- data/app/assets/javascripts/shopify_app/partition_cookies.js +0 -8
- data/app/assets/javascripts/shopify_app/post_redirect.js +0 -9
- data/app/assets/javascripts/shopify_app/request_storage_access.js +0 -3
- data/app/assets/javascripts/shopify_app/storage_access.js +0 -148
- data/app/assets/javascripts/shopify_app/storage_access_redirect.js +0 -17
- data/app/assets/javascripts/shopify_app/top_level.js +0 -2
- data/app/assets/javascripts/shopify_app/top_level_interaction.js +0 -11
- data/app/views/shopify_app/sessions/enable_cookies.html.erb +0 -70
- data/app/views/shopify_app/sessions/request_storage_access.html.erb +0 -68
- data/app/views/shopify_app/sessions/top_level_interaction.html.erb +0 -63
- data/app/views/shopify_app/shared/post_redirect_to_auth_shopify.html.erb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e65d60a59d8ea51db704069c1d982e4c527339768f7c4e759e50a23ebe4fdb09
|
4
|
+
data.tar.gz: b5aff8a08f5c91093d3114ff7bc88b43894b5be2e6011a3cdc28a7dc3ab670c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 157fd8fe0c4ec1cb541cbbd1816ce4f950d4bde8cb5f71e37400fcf251de1928cc0954b28cfe2e9bf67d403b0746b0570a47b3891566df2eb2188c82ccf9de9f
|
7
|
+
data.tar.gz: 7025fa973e9e89e0b1ef93713fa6e831a33e401043b6627745617f51a6fe007673307911e5b72cabedd82a6cfc5cbbcdfdc00525b560728d6aff1fac7064147c
|
@@ -1,63 +1,41 @@
|
|
1
1
|
---
|
2
|
-
name: Bug
|
3
|
-
about:
|
4
|
-
labels:
|
2
|
+
name: "🐛 Bug Report"
|
3
|
+
about: Something isn't working
|
4
|
+
labels: "Type: Bug 🐛"
|
5
5
|
---
|
6
6
|
|
7
|
-
|
7
|
+
# Issue summary
|
8
8
|
|
9
|
-
|
9
|
+
<!--
|
10
10
|
|
11
|
-
|
11
|
+
Write a short description of the issue here. Please provide any details or logs that
|
12
|
+
can help us debug it.
|
12
13
|
|
13
|
-
|
14
|
+
Increase the logs as described in the README by setting log_level to :debug, and paste the relevant portion here.
|
14
15
|
|
15
|
-
|
16
|
+
Learn more: https://github.com/Shopify/shopify-api-ruby#setup-shopify-context
|
16
17
|
|
17
18
|
-->
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
### Steps to Reproduce
|
24
|
-
|
25
|
-
1. <!-- First Step -->
|
26
|
-
2. <!-- Second Step -->
|
27
|
-
3. <!-- and so on… -->
|
28
|
-
|
29
|
-
**Expected behavior:**
|
30
|
-
|
31
|
-
<!-- What you expect to happen -->
|
32
|
-
|
33
|
-
**Actual behavior:**
|
34
|
-
|
35
|
-
<!-- What actually happens -->
|
36
|
-
|
37
|
-
**Reproduces how often:**
|
38
|
-
|
39
|
-
<!-- What percentage of the time does it reproduce? -->
|
40
|
-
|
41
|
-
### Browsers
|
42
|
-
|
43
|
-
<!-- Please specify the browser(s) you have tested that exhibit this behaviour. -->
|
44
|
-
|
45
|
-
### Gem versions
|
46
|
-
|
47
|
-
<!-- Please specify which version(s) of the gem exhibit this behaviour. -->
|
48
|
-
|
49
|
-
### Additional Information
|
20
|
+
- `shopify_api` version:
|
21
|
+
- `shopify_app` version:
|
22
|
+
- Ruby version:
|
23
|
+
- Operating system:
|
50
24
|
|
51
|
-
|
25
|
+
```
|
26
|
+
// Paste any relevant logs here
|
27
|
+
```
|
52
28
|
|
53
|
-
|
54
|
-
<!-- - [x] My app is intended to be a non-embedded app -->
|
55
|
-
<!-- - [x] My app uses session tokens -->
|
29
|
+
## Expected behavior
|
56
30
|
|
31
|
+
<!-- What do you think should happen? -->
|
57
32
|
|
58
|
-
|
33
|
+
## Actual behavior
|
59
34
|
|
60
|
-
<!--
|
35
|
+
<!-- What actually happens? -->
|
61
36
|
|
62
|
-
|
37
|
+
## Steps to reproduce the problem
|
63
38
|
|
39
|
+
1.
|
40
|
+
1.
|
41
|
+
1.
|
@@ -1,33 +1,9 @@
|
|
1
1
|
---
|
2
|
-
name: Feature
|
3
|
-
about:
|
4
|
-
labels:
|
2
|
+
name: "🙌 Feature Request"
|
3
|
+
about: Suggest a new feature, or changes to an existing one
|
4
|
+
labels: "Type: Feature Request :raised_hands:"
|
5
5
|
---
|
6
6
|
|
7
|
-
|
7
|
+
## Overview
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
You can also join the Partners Slack Community group: https://www.shopify.com/partners/community#conversation
|
12
|
-
|
13
|
-
---
|
14
|
-
|
15
|
-
Please note that the team that maintains this gem has finite resources so it's unlikely that we'll work on feature requests. If we're interested in a particular feature however, we'll follow up and ask for more detail.
|
16
|
-
|
17
|
-
-->
|
18
|
-
|
19
|
-
### Summary
|
20
|
-
|
21
|
-
<!-- One paragraph explanation of the feature or suggestions. -->
|
22
|
-
|
23
|
-
### Motivation
|
24
|
-
|
25
|
-
<!-- Why is this feature or suggestion needed? What is the expected outcome? -->
|
26
|
-
|
27
|
-
### Describe alternatives you've considered
|
28
|
-
|
29
|
-
<!-- A clear and concise description of the alternative solutions you've considered. -->
|
30
|
-
|
31
|
-
### Additional context
|
32
|
-
|
33
|
-
<!-- Add any other context or screenshots about the feature request here. -->
|
9
|
+
<!-- Write a short description of the request here ↓ -->
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
Unreleased
|
2
2
|
----------
|
3
3
|
|
4
|
+
21.4.1 (Feb 21, 2023)
|
5
|
+
----------
|
6
|
+
* Fixed bug where authentication redirect could still happen even though `reauth_on_access_scope_changes` is set to `false` [#1639](https://github.com/Shopify/shopify_app/pull/1639)
|
7
|
+
|
8
|
+
21.4.0 (Jan 5, 2023)
|
9
|
+
----------
|
10
|
+
* Updated shopify_api to 12.4.0 [#1633](https://github.com/Shopify/shopify_app/pull/1633)
|
11
|
+
* Removed Logged output for rescued JWT exceptions [#1610](https://github.com/Shopify/shopify_app/pull/1610)
|
12
|
+
* Fixes a bug with `ShopifyApp::WebhooksManager.destroy_webhooks` causing not passing session arguments to [unregister](https://github.com/Shopify/shopify-api-ruby/blob/main/lib/shopify_api/webhooks/registry.rb#L99) method [#1569](https://github.com/Shopify/shopify_app/pull/1569)
|
13
|
+
* Validates shop's offline session token is still valid when using `EnsureInstalled`[#1612](https://github.com/Shopify/shopify_app/pull/1612)
|
14
|
+
* Allows use of multiple subdomains with myshopify_domain [#1620](https://github.com/Shopify/shopify_app/pull/1620)
|
15
|
+
* Added a `setup_shopify_session` test helper to stub a valid session
|
16
|
+
|
4
17
|
21.3.1 (Dec 12, 2022)
|
5
18
|
----------
|
6
19
|
* Fix bug with stores using the new unified admin that were falsely being flagged as phishing attempts [#1608](https://github.com/Shopify/shopify_app/pull/1608)
|
data/CONTRIBUTING.md
CHANGED
@@ -61,7 +61,7 @@ If you have a suggestion for the Shopify App gem or a feature request, provide t
|
|
61
61
|
|
62
62
|
The process described here has several goals:
|
63
63
|
|
64
|
-
* Maintain the Shopify App gem's quality
|
64
|
+
* Maintain the Shopify App gem's quality (does the change you're making have a test?)
|
65
65
|
* Fix problems that are important to app developers
|
66
66
|
* Enable a sustainable system for the Shopify App gem's maintainers to review contributions
|
67
67
|
|
@@ -74,7 +74,22 @@ Please follow these steps to have your contribution considered by the maintainer
|
|
74
74
|
|
75
75
|
While the prerequisites above must be satisfied prior to having your pull request reviewed, the reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted.
|
76
76
|
</details>
|
77
|
-
|
77
|
+
|
78
|
+
### Running tests
|
79
|
+
|
80
|
+
#### Test Environment Requirements
|
81
|
+
|
82
|
+
To run tests, you'll need to make sure that your development environment is setup correctly. You'll need:
|
83
|
+
|
84
|
+
* Ruby 3+ is installed on your system
|
85
|
+
* Install dependencies with `bundle install`
|
86
|
+
|
87
|
+
#### Executing Tests
|
88
|
+
|
89
|
+
* To run all tests: `bundle exec rake test`
|
90
|
+
* To run a specific test file: `bundle exec rake test TEST=test/controllers/callback_controller_test.rb`
|
91
|
+
* To run a single test: `bundle exec rake test TEST=test/controllers/callback_controller_test.rb:50` where `50` is the line number on or inside the test case.
|
92
|
+
|
78
93
|
### App Bridge client
|
79
94
|
|
80
95
|
This gem ships with a UMD version of the App Bridge client. It lives inside the assets folder: `app/assets/javascripts/shopify_app/`. To update the client, simply download the UMD build from [unpkg.com](https://unpkg.com/@shopify/app-bridge) and save it into the folder.
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
shopify_app (21.
|
4
|
+
shopify_app (21.4.1)
|
5
5
|
activeresource
|
6
|
+
addressable (~> 2.7)
|
6
7
|
browser_sniffer (~> 2.0)
|
7
8
|
jwt (>= 2.2.3)
|
8
9
|
rails (> 5.2.1)
|
9
10
|
redirect_safely (~> 1.0)
|
10
|
-
shopify_api (~> 12.
|
11
|
+
shopify_api (~> 12.4)
|
11
12
|
sprockets-rails (>= 2.0.0)
|
12
13
|
|
13
14
|
GEM
|
@@ -99,13 +100,13 @@ GEM
|
|
99
100
|
activesupport (>= 5.0)
|
100
101
|
hash_diff (1.1.1)
|
101
102
|
hashdiff (1.0.1)
|
102
|
-
httparty (0.
|
103
|
-
|
103
|
+
httparty (0.21.0)
|
104
|
+
mini_mime (>= 1.0.0)
|
104
105
|
multi_xml (>= 0.5.2)
|
105
106
|
i18n (1.12.0)
|
106
107
|
concurrent-ruby (~> 1.0)
|
107
108
|
json (2.6.3)
|
108
|
-
jwt (2.
|
109
|
+
jwt (2.6.0)
|
109
110
|
language_server-protocol (3.17.0.2)
|
110
111
|
loofah (2.19.0)
|
111
112
|
crass (~> 1.0.2)
|
@@ -117,11 +118,8 @@ GEM
|
|
117
118
|
net-smtp
|
118
119
|
marcel (1.0.2)
|
119
120
|
method_source (1.0.0)
|
120
|
-
mime-types (3.4.1)
|
121
|
-
mime-types-data (~> 3.2015)
|
122
|
-
mime-types-data (3.2022.0105)
|
123
121
|
mini_mime (1.1.2)
|
124
|
-
minitest (5.
|
122
|
+
minitest (5.17.0)
|
125
123
|
mocha (2.0.2)
|
126
124
|
ruby2_keywords (>= 0.0.5)
|
127
125
|
multi_xml (0.6.0)
|
@@ -141,7 +139,7 @@ GEM
|
|
141
139
|
nokogiri (1.13.9-x86_64-linux)
|
142
140
|
racc (~> 1.4)
|
143
141
|
oj (3.13.23)
|
144
|
-
openssl (3.0
|
142
|
+
openssl (3.1.0)
|
145
143
|
parallel (1.22.1)
|
146
144
|
parser (3.1.3.0)
|
147
145
|
ast (~> 2.4.1)
|
@@ -216,8 +214,8 @@ GEM
|
|
216
214
|
syntax_tree (>= 4.0.2, < 5.0.0)
|
217
215
|
ruby-progressbar (1.11.0)
|
218
216
|
ruby2_keywords (0.0.5)
|
219
|
-
securerandom (0.2.
|
220
|
-
shopify_api (12.
|
217
|
+
securerandom (0.2.2)
|
218
|
+
shopify_api (12.4.0)
|
221
219
|
activesupport
|
222
220
|
concurrent-ruby
|
223
221
|
hash_diff
|
@@ -228,7 +226,7 @@ GEM
|
|
228
226
|
securerandom
|
229
227
|
sorbet-runtime
|
230
228
|
zeitwerk (~> 2.5, < 2.6.5)
|
231
|
-
sorbet-runtime (0.5.
|
229
|
+
sorbet-runtime (0.5.10601)
|
232
230
|
sprockets (4.1.1)
|
233
231
|
concurrent-ruby (~> 1.0)
|
234
232
|
rack (> 1, < 3)
|
@@ -6,7 +6,7 @@ module ShopifyApp
|
|
6
6
|
include ShopifyApp::RedirectForEmbedded
|
7
7
|
|
8
8
|
included do
|
9
|
-
if ancestors.include?(ShopifyApp::LoginProtection)
|
9
|
+
if defined?(ShopifyApp::LoginProtection) && ancestors.include?(ShopifyApp::LoginProtection)
|
10
10
|
message = <<~EOS
|
11
11
|
We detected the use of incompatible concerns (EnsureInstalled and LoginProtection) in #{name},
|
12
12
|
which may lead to unpredictable behavior. In a future release of this library this will raise an error.
|
@@ -17,6 +17,7 @@ module ShopifyApp
|
|
17
17
|
|
18
18
|
before_action :check_shop_domain
|
19
19
|
before_action :check_shop_known
|
20
|
+
before_action :validate_non_embedded_session
|
20
21
|
end
|
21
22
|
|
22
23
|
def current_shopify_domain
|
@@ -30,6 +31,10 @@ module ShopifyApp
|
|
30
31
|
@shopify_domain
|
31
32
|
end
|
32
33
|
|
34
|
+
def installed_shop_session
|
35
|
+
@installed_shop_session ||= SessionRepository.retrieve_shop_session_by_shopify_domain(current_shopify_domain)
|
36
|
+
end
|
37
|
+
|
33
38
|
private
|
34
39
|
|
35
40
|
def check_shop_domain
|
@@ -37,7 +42,7 @@ module ShopifyApp
|
|
37
42
|
end
|
38
43
|
|
39
44
|
def check_shop_known
|
40
|
-
@shop =
|
45
|
+
@shop = installed_shop_session
|
41
46
|
unless @shop
|
42
47
|
if embedded_param?
|
43
48
|
redirect_for_embedded
|
@@ -58,5 +63,16 @@ module ShopifyApp
|
|
58
63
|
|
59
64
|
url.to_s
|
60
65
|
end
|
66
|
+
|
67
|
+
def validate_non_embedded_session
|
68
|
+
return if loaded_directly_from_admin?
|
69
|
+
|
70
|
+
client = ShopifyAPI::Clients::Rest::Admin.new(session: installed_shop_session)
|
71
|
+
client.get(path: "shop")
|
72
|
+
rescue ShopifyAPI::Errors::HttpResponseError => error
|
73
|
+
ShopifyApp::Logger.info("Shop offline session no longer valid. Redirecting to OAuth install")
|
74
|
+
redirect_to(shop_login) if error.code == 401
|
75
|
+
raise error if error.code != 401
|
76
|
+
end
|
61
77
|
end
|
62
78
|
end
|
@@ -85,6 +85,10 @@ module ShopifyApp
|
|
85
85
|
# host param doesn't match the configured myshopify_domain
|
86
86
|
def deduced_phishing_attack?
|
87
87
|
sanitized_host = ShopifyApp::Utils.sanitize_shop_domain(URI(decoded_host).host)
|
88
|
+
if sanitized_host.nil?
|
89
|
+
ShopifyApp::Logger.info("host param from callback is not from a trusted domain")
|
90
|
+
ShopifyApp::Logger.info("redirecting to root as this is likely a phishing attack")
|
91
|
+
end
|
88
92
|
sanitized_host.nil?
|
89
93
|
end
|
90
94
|
|
data/docs/shopify_app/engine.md
CHANGED
@@ -27,24 +27,15 @@ The engine may also be mounted at a nested route, for example:
|
|
27
27
|
mount ShopifyApp::Engine, at: '/nested'
|
28
28
|
```
|
29
29
|
|
30
|
-
This will create the Shopify engine routes under the specified subpath. You'll also need to make some updates to your `shopify_app.rb
|
30
|
+
This will create the Shopify engine routes under the specified subpath. You'll also need to make some updates to your `shopify_app.rb`. Update the shopify_app initializer to include a custom `root_url` and `login_callback_url` e.g.:
|
31
31
|
|
32
32
|
```ruby
|
33
33
|
ShopifyApp.configure do |config|
|
34
34
|
config.root_url = '/nested'
|
35
|
+
config.login_callback_url = '/nested/auth/shopify/callback'
|
35
36
|
end
|
36
37
|
```
|
37
38
|
|
38
|
-
then update the omniauth initializer to include a custom `callback_path` e.g.:
|
39
|
-
|
40
|
-
```ruby
|
41
|
-
provider :shopify,
|
42
|
-
ShopifyApp.configuration.api_key,
|
43
|
-
ShopifyApp.configuration.secret,
|
44
|
-
scope: ShopifyApp.configuration.scope,
|
45
|
-
callback_path: '/nested/auth/shopify/callback'
|
46
|
-
```
|
47
|
-
|
48
39
|
You may also need to change your `config/routes.rb` to render a view for `/nested`, since this is what will be rendered in the Shopify Admin of any shops that have installed your app. The engine itself doesn't have a view for this, so you'll need something like this:
|
49
40
|
|
50
41
|
```ruby
|
@@ -72,17 +72,8 @@ end
|
|
72
72
|
|
73
73
|
1. Run the `user_model` generator as mentioned above.
|
74
74
|
2. Ensure that both your `Shop` model and `User` model includes the necessary concerns `ShopifyApp::ShopSessionStorage` and `ShopifyApp::UserSessionStorage`.
|
75
|
-
3. Make changes to
|
75
|
+
3. Make changes to the `shopify_app.rb` initializer file as shown below:
|
76
76
|
```ruby
|
77
|
-
# In the `omniauth.rb` initializer:
|
78
|
-
provider :shopify,
|
79
|
-
...
|
80
|
-
setup: lambda { |env|
|
81
|
-
configuration = ShopifyApp::OmniAuthConfiguration.new(env['omniauth.strategy'], Rack::Request.new(env))
|
82
|
-
configuration.build_options
|
83
|
-
}
|
84
|
-
|
85
|
-
# In the `shopify_app.rb` initializer:
|
86
77
|
config.shop_session_repository = {YOUR_SHOP_MODEL_CLASS}
|
87
78
|
config.user_session_repository = {YOUR_USER_MODEL_CLASS}
|
88
79
|
```
|
data/docs/shopify_app/testing.md
CHANGED
@@ -11,20 +11,42 @@
|
|
11
11
|
A test helper that will allow you to test `ShopifyApp::WebhookVerification` in the controller from your app, to use this test, you need to `require` it directly inside your app `test/controllers/webhook_verification_test.rb`.
|
12
12
|
|
13
13
|
```ruby
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
require 'test_helper'
|
15
|
+
require 'action_controller'
|
16
|
+
require 'action_controller/base'
|
17
|
+
require 'shopify_app/test_helpers/webhook_verification_helper'
|
18
18
|
```
|
19
19
|
|
20
|
-
|
20
|
+
A test helper that allows you to stub out a shopify_app session in controllers that include `ShopifyApp::LoginProtection`, to use this helper, you need to `require` it directly.
|
21
|
+
|
22
|
+
Example Usage:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
require 'shopify_app/test_helpers/shopify_session_helper'
|
26
|
+
|
27
|
+
class MyAuthenticatedControllerTest < ActionController::TestCase
|
28
|
+
include ShopifyApp::TestHelpers::ShopifySessionHelper
|
29
|
+
|
30
|
+
test "does not redirect when there is a valid shopify session" do
|
31
|
+
# note shop_domain should be the same as your shopify domain
|
32
|
+
shop_domain = "my-shop.myshopify.com"
|
33
|
+
setup_shopify_session(session_id: "1", shop_domain: shop_domain)
|
34
|
+
|
35
|
+
get :index
|
36
|
+
|
37
|
+
assert_response :ok
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
Or you can require all shopify_app test helpers in your `test/test_helper.rb`.
|
21
43
|
|
22
44
|
```ruby
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
45
|
+
ENV['RAILS_ENV'] ||= 'test'
|
46
|
+
require_relative '../config/environment'
|
47
|
+
require 'rails/test_help'
|
48
|
+
require 'byebug'
|
49
|
+
require 'shopify_app/test_helpers/all'
|
28
50
|
```
|
29
51
|
|
30
52
|
With `lib/shopify_app/test_helpers/all'` more tests can be added and will only need to be required in once in your library.
|
@@ -8,7 +8,9 @@ module ShopifyApp
|
|
8
8
|
include ShopifyApp::SanitizedParams
|
9
9
|
|
10
10
|
included do
|
11
|
-
if
|
11
|
+
if defined?(ShopifyApp::RequireKnownShop) &&
|
12
|
+
defined?(ShopifyApp::EnsureInstalled) &&
|
13
|
+
ancestors.include?(ShopifyApp::RequireKnownShop || ShopifyApp::EnsureInstalled)
|
12
14
|
message = <<~EOS
|
13
15
|
We detected the use of incompatible concerns (RequireKnownShop/EnsureInstalled and LoginProtection) in #{name},
|
14
16
|
which may lead to unpredictable behavior. In a future release of this library this will raise an error.
|
@@ -28,7 +30,8 @@ module ShopifyApp
|
|
28
30
|
return redirect_to_login
|
29
31
|
end
|
30
32
|
|
31
|
-
|
33
|
+
if ShopifyApp.configuration.reauth_on_access_scope_changes &&
|
34
|
+
!ShopifyApp.configuration.user_access_scopes_strategy.covers_scopes?(current_shopify_session)
|
32
35
|
clear_shopify_session
|
33
36
|
return redirect_to_login
|
34
37
|
end
|
@@ -11,7 +11,11 @@ module ShopifyApp
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def embedded_param?
|
14
|
-
embedded_redirect_url? && params[:embedded].present? &&
|
14
|
+
embedded_redirect_url? && params[:embedded].present? && loaded_directly_from_admin?
|
15
|
+
end
|
16
|
+
|
17
|
+
def loaded_directly_from_admin?
|
18
|
+
ShopifyApp.configuration.embedded_app? && params[:embedded] == "1"
|
15
19
|
end
|
16
20
|
|
17
21
|
def redirect_for_embedded
|
@@ -21,7 +21,7 @@ module ShopifyApp
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def recreate_webhooks!(session:)
|
24
|
-
destroy_webhooks
|
24
|
+
destroy_webhooks(session: session)
|
25
25
|
return unless ShopifyApp.configuration.has_webhooks?
|
26
26
|
|
27
27
|
add_registrations
|
@@ -30,12 +30,12 @@ module ShopifyApp
|
|
30
30
|
ShopifyAPI::Webhooks::Registry.register_all(session: session)
|
31
31
|
end
|
32
32
|
|
33
|
-
def destroy_webhooks
|
33
|
+
def destroy_webhooks(session:)
|
34
34
|
return unless ShopifyApp.configuration.has_webhooks?
|
35
35
|
|
36
36
|
ShopifyApp::Logger.debug("Destroying webhooks")
|
37
37
|
ShopifyApp.configuration.webhooks.each do |attributes|
|
38
|
-
ShopifyAPI::Webhooks::Registry.unregister(topic: attributes[:topic])
|
38
|
+
ShopifyAPI::Webhooks::Registry.unregister(topic: attributes[:topic], session: session)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -34,8 +34,7 @@ module ShopifyApp
|
|
34
34
|
def set_payload
|
35
35
|
payload, _ = parse_token_data(ShopifyApp.configuration&.secret, ShopifyApp.configuration&.old_secret)
|
36
36
|
@payload = validate_payload(payload)
|
37
|
-
rescue *WARN_EXCEPTIONS
|
38
|
-
ShopifyApp::Logger.warn("Failed to validate JWT: [#{error.class}] #{error}")
|
37
|
+
rescue *WARN_EXCEPTIONS
|
39
38
|
nil
|
40
39
|
end
|
41
40
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShopifyApp
|
4
|
+
module TestHelpers
|
5
|
+
module ShopifySessionHelper
|
6
|
+
def setup_shopify_session(session_id:, shop_domain:)
|
7
|
+
ShopifyAPI::Auth::Session.new(id: session_id, shop: shop_domain).tap do |session|
|
8
|
+
ShopifyApp::SessionRepository.stubs(:load_session).returns(session)
|
9
|
+
ShopifyAPI::Utils::SessionUtils.stubs(:current_session_id).returns(session.id)
|
10
|
+
ShopifyAPI::Context.activate_session(session)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/shopify_app/utils.rb
CHANGED
@@ -2,38 +2,69 @@
|
|
2
2
|
|
3
3
|
module ShopifyApp
|
4
4
|
module Utils
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
5
|
+
class << self
|
6
|
+
TRUSTED_SHOPIFY_DOMAINS = [
|
7
|
+
"shopify.com",
|
8
|
+
"myshopify.io",
|
9
|
+
"myshopify.com",
|
10
|
+
"spin.dev",
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
def sanitize_shop_domain(shop_domain)
|
14
|
+
uri = uri_from_shop_domain(shop_domain)
|
15
|
+
return nil if uri.nil?
|
16
|
+
|
17
|
+
trusted_domains.each do |trusted_domain|
|
18
|
+
no_shop_name_in_subdomain = uri.host == trusted_domain
|
19
|
+
from_trusted_domain = trusted_domain == uri.domain
|
20
|
+
|
21
|
+
return nil if no_shop_name_in_subdomain || uri.host&.empty?
|
22
|
+
return uri.host if from_trusted_domain
|
23
|
+
end
|
24
|
+
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def shop_login_url(shop:, host:, return_to:)
|
29
|
+
return ShopifyApp.configuration.login_url unless shop
|
30
|
+
|
31
|
+
url = URI(ShopifyApp.configuration.login_url)
|
32
|
+
|
33
|
+
url.query = URI.encode_www_form(
|
34
|
+
shop: shop,
|
35
|
+
host: host,
|
36
|
+
return_to: return_to,
|
37
|
+
)
|
38
|
+
|
39
|
+
url.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def myshopify_domain
|
45
|
+
ShopifyApp.configuration.myshopify_domain
|
46
|
+
end
|
24
47
|
|
25
|
-
|
26
|
-
|
48
|
+
def trusted_domains
|
49
|
+
trusted_domains = TRUSTED_SHOPIFY_DOMAINS.dup
|
50
|
+
trusted_domains.append(myshopify_domain).uniq! if myshopify_domain
|
51
|
+
trusted_domains
|
52
|
+
end
|
27
53
|
|
28
|
-
|
54
|
+
def uri_from_shop_domain(shop_domain)
|
55
|
+
name = shop_domain.to_s.downcase.strip
|
56
|
+
name += ".#{myshopify_domain}" if !name.include?(myshopify_domain.to_s) && !name.include?(".")
|
57
|
+
uri = Addressable::URI.parse(name)
|
29
58
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
)
|
59
|
+
if uri.scheme.nil?
|
60
|
+
name = "https://" + name
|
61
|
+
uri = Addressable::URI.parse(name)
|
62
|
+
end
|
35
63
|
|
36
|
-
|
64
|
+
uri
|
65
|
+
rescue Addressable::URI::InvalidURIError
|
66
|
+
nil
|
67
|
+
end
|
37
68
|
end
|
38
69
|
end
|
39
70
|
end
|
data/lib/shopify_app/version.rb
CHANGED
data/lib/shopify_app.rb
CHANGED
data/package.json
CHANGED
data/shopify_app.gemspec
CHANGED
@@ -15,11 +15,12 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.metadata["allowed_push_host"] = "https://rubygems.org"
|
16
16
|
|
17
17
|
s.add_runtime_dependency("activeresource") # TODO: Remove this once all active resource dependencies are removed
|
18
|
+
s.add_runtime_dependency("addressable", "~> 2.7")
|
18
19
|
s.add_runtime_dependency("browser_sniffer", "~> 2.0")
|
19
20
|
s.add_runtime_dependency("jwt", ">= 2.2.3")
|
20
21
|
s.add_runtime_dependency("rails", "> 5.2.1")
|
21
22
|
s.add_runtime_dependency("redirect_safely", "~> 1.0")
|
22
|
-
s.add_runtime_dependency("shopify_api", "~> 12.
|
23
|
+
s.add_runtime_dependency("shopify_api", "~> 12.4")
|
23
24
|
s.add_runtime_dependency("sprockets-rails", ">= 2.0.0")
|
24
25
|
|
25
26
|
s.add_development_dependency("byebug")
|
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.
|
4
|
+
version: 21.4.1
|
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: 2023-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activeresource
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: addressable
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.7'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.7'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: browser_sniffer
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,14 +100,14 @@ dependencies:
|
|
86
100
|
requirements:
|
87
101
|
- - "~>"
|
88
102
|
- !ruby/object:Gem::Version
|
89
|
-
version: '12.
|
103
|
+
version: '12.4'
|
90
104
|
type: :runtime
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
108
|
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
|
-
version: '12.
|
110
|
+
version: '12.4'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: sprockets-rails
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -270,6 +284,7 @@ extra_rdoc_files: []
|
|
270
284
|
files:
|
271
285
|
- ".babelrc"
|
272
286
|
- ".github/CODEOWNERS"
|
287
|
+
- ".github/ISSUE_TEMPLATE/ENHANCEMENT.md"
|
273
288
|
- ".github/ISSUE_TEMPLATE/bug-report.md"
|
274
289
|
- ".github/ISSUE_TEMPLATE/config.yml"
|
275
290
|
- ".github/ISSUE_TEMPLATE/feature-request.md"
|
@@ -298,16 +313,7 @@ files:
|
|
298
313
|
- app/assets/javascripts/shopify_app/app_bridge_3.1.1.js
|
299
314
|
- app/assets/javascripts/shopify_app/app_bridge_redirect.js
|
300
315
|
- app/assets/javascripts/shopify_app/app_bridge_utils_3.1.1.js
|
301
|
-
- app/assets/javascripts/shopify_app/enable_cookies.js
|
302
|
-
- app/assets/javascripts/shopify_app/itp_helper.js
|
303
|
-
- app/assets/javascripts/shopify_app/partition_cookies.js
|
304
|
-
- app/assets/javascripts/shopify_app/post_redirect.js
|
305
316
|
- app/assets/javascripts/shopify_app/redirect.js
|
306
|
-
- app/assets/javascripts/shopify_app/request_storage_access.js
|
307
|
-
- app/assets/javascripts/shopify_app/storage_access.js
|
308
|
-
- app/assets/javascripts/shopify_app/storage_access_redirect.js
|
309
|
-
- app/assets/javascripts/shopify_app/top_level.js
|
310
|
-
- app/assets/javascripts/shopify_app/top_level_interaction.js
|
311
317
|
- app/controllers/concerns/shopify_app/authenticated.rb
|
312
318
|
- app/controllers/concerns/shopify_app/ensure_authenticated_links.rb
|
313
319
|
- app/controllers/concerns/shopify_app/ensure_has_session.rb
|
@@ -325,11 +331,7 @@ files:
|
|
325
331
|
- app/views/shopify_app/partials/_form_styles.html.erb
|
326
332
|
- app/views/shopify_app/partials/_layout_styles.html.erb
|
327
333
|
- app/views/shopify_app/partials/_typography_styles.html.erb
|
328
|
-
- app/views/shopify_app/sessions/enable_cookies.html.erb
|
329
334
|
- app/views/shopify_app/sessions/new.html.erb
|
330
|
-
- app/views/shopify_app/sessions/request_storage_access.html.erb
|
331
|
-
- app/views/shopify_app/sessions/top_level_interaction.html.erb
|
332
|
-
- app/views/shopify_app/shared/post_redirect_to_auth_shopify.html.erb
|
333
335
|
- app/views/shopify_app/shared/redirect.html.erb
|
334
336
|
- config/locales/cs.yml
|
335
337
|
- config/locales/da.yml
|
@@ -458,6 +460,7 @@ files:
|
|
458
460
|
- lib/shopify_app/session/user_session_storage.rb
|
459
461
|
- lib/shopify_app/session/user_session_storage_with_scopes.rb
|
460
462
|
- lib/shopify_app/test_helpers/all.rb
|
463
|
+
- lib/shopify_app/test_helpers/shopify_session_helper.rb
|
461
464
|
- lib/shopify_app/test_helpers/webhook_verification_helper.rb
|
462
465
|
- lib/shopify_app/utils.rb
|
463
466
|
- lib/shopify_app/version.rb
|
@@ -1,40 +0,0 @@
|
|
1
|
-
(function() {
|
2
|
-
function ITPHelper(opts) {
|
3
|
-
this.itpContent = document.getElementById('TopLevelInteractionContent');
|
4
|
-
this.itpAction = document.getElementById('TopLevelInteractionButton');
|
5
|
-
this.redirectUrl = opts.redirectUrl;
|
6
|
-
}
|
7
|
-
|
8
|
-
ITPHelper.prototype.redirect = function() {
|
9
|
-
sessionStorage.setItem('shopify.top_level_interaction', true);
|
10
|
-
window.location.href = this.redirectUrl;
|
11
|
-
}
|
12
|
-
|
13
|
-
ITPHelper.prototype.userAgentIsAffected = function() {
|
14
|
-
return Boolean(document.hasStorageAccess);
|
15
|
-
}
|
16
|
-
|
17
|
-
ITPHelper.prototype.canPartitionCookies = function() {
|
18
|
-
var versionRegEx = /Version\/12\.0\.?\d? Safari/;
|
19
|
-
return versionRegEx.test(navigator.userAgent);
|
20
|
-
}
|
21
|
-
|
22
|
-
ITPHelper.prototype.setUpContent = function(onClick) {
|
23
|
-
this.itpContent.style.display = 'block';
|
24
|
-
this.itpAction.addEventListener('click', this.redirect.bind(this));
|
25
|
-
}
|
26
|
-
|
27
|
-
ITPHelper.prototype.execute = function() {
|
28
|
-
if (!this.itpContent) {
|
29
|
-
return;
|
30
|
-
}
|
31
|
-
|
32
|
-
if (this.userAgentIsAffected()) {
|
33
|
-
this.setUpContent();
|
34
|
-
} else {
|
35
|
-
this.redirect();
|
36
|
-
}
|
37
|
-
}
|
38
|
-
|
39
|
-
this.ITPHelper = ITPHelper;
|
40
|
-
})(window);
|
@@ -1,8 +0,0 @@
|
|
1
|
-
(function() {
|
2
|
-
document.addEventListener("DOMContentLoaded", function() {
|
3
|
-
var redirectTargetElement = document.getElementById("redirection-target");
|
4
|
-
var targetInfo = JSON.parse(redirectTargetElement.dataset.target)
|
5
|
-
var storageAccessHelper = new StorageAccessHelper(targetInfo);
|
6
|
-
storageAccessHelper.execute();
|
7
|
-
});
|
8
|
-
})();
|
@@ -1,148 +0,0 @@
|
|
1
|
-
//= require ./app_bridge_redirect.js
|
2
|
-
|
3
|
-
(function() {
|
4
|
-
var ACCESS_GRANTED_STATUS = 'storage_access_granted';
|
5
|
-
var ACCESS_DENIED_STATUS = 'storage_access_denied';
|
6
|
-
|
7
|
-
function StorageAccessHelper(redirectData) {
|
8
|
-
this.redirectData = redirectData;
|
9
|
-
}
|
10
|
-
|
11
|
-
StorageAccessHelper.prototype.setNormalizedLink = function(storageAccessStatus) {
|
12
|
-
return storageAccessStatus === ACCESS_GRANTED_STATUS ? this.redirectData.hasStorageAccessUrl : this.redirectData.doesNotHaveStorageAccessUrl;
|
13
|
-
}
|
14
|
-
|
15
|
-
StorageAccessHelper.prototype.redirectToAppTLD = function(storageAccessStatus) {
|
16
|
-
var normalizedLink = document.createElement('a');
|
17
|
-
|
18
|
-
window.appBridgeRedirect(this.setNormalizedLink(storageAccessStatus));
|
19
|
-
}
|
20
|
-
|
21
|
-
StorageAccessHelper.prototype.redirectToAppsIndex = function() {
|
22
|
-
window.parent.location.href = this.redirectData.myshopifyUrl + '/admin/apps';
|
23
|
-
}
|
24
|
-
|
25
|
-
StorageAccessHelper.prototype.redirectToAppTargetUrl = function() {
|
26
|
-
window.location.href = this.redirectData.appTargetUrl;
|
27
|
-
}
|
28
|
-
|
29
|
-
StorageAccessHelper.prototype.sameSiteNoneIncompatible = function(ua) {
|
30
|
-
return ua.includes("iPhone OS 12_") || ua.includes("iPad; CPU OS 12_") || //iOS 12
|
31
|
-
(ua.includes("UCBrowser/")
|
32
|
-
? this.isOlderUcBrowser(ua) //UC Browser < 12.13.2
|
33
|
-
: (ua.includes("Chrome/5") || ua.includes("Chrome/6"))) ||
|
34
|
-
ua.includes("Chromium/5") || ua.includes("Chromium/6") ||
|
35
|
-
(ua.includes(" OS X 10_14_") &&
|
36
|
-
((ua.includes("Version/") && ua.includes("Safari")) || //Safari on MacOS 10.14
|
37
|
-
ua.endsWith("(KHTML, like Gecko)"))); //Web view on MacOS 10.14
|
38
|
-
}
|
39
|
-
|
40
|
-
StorageAccessHelper.prototype.isOlderUcBrowser = function(ua) {
|
41
|
-
var match = ua.match(/UCBrowser\/(\d+)\.(\d+)\.(\d+)\./);
|
42
|
-
if (!match) return false;
|
43
|
-
var major = parseInt(match[1]);
|
44
|
-
var minor = parseInt(match[2]);
|
45
|
-
var build = parseInt(match[3]);
|
46
|
-
if (major != 12) return major < 12;
|
47
|
-
if (minor != 13) return minor < 13;
|
48
|
-
return build < 2;
|
49
|
-
}
|
50
|
-
|
51
|
-
StorageAccessHelper.prototype.setCookie = function(value) {
|
52
|
-
if(!this.sameSiteNoneIncompatible(navigator.userAgent)) {
|
53
|
-
value += '; secure; SameSite=None'
|
54
|
-
}
|
55
|
-
document.cookie = value;
|
56
|
-
}
|
57
|
-
|
58
|
-
StorageAccessHelper.prototype.grantedStorageAccess = function() {
|
59
|
-
try {
|
60
|
-
sessionStorage.setItem('shopify.granted_storage_access', true);
|
61
|
-
this.setCookie('shopify.granted_storage_access=true');
|
62
|
-
if (!document.cookie) {
|
63
|
-
throw 'Cannot set third-party cookie.'
|
64
|
-
}
|
65
|
-
this.redirectToAppTargetUrl();
|
66
|
-
} catch (error) {
|
67
|
-
console.warn('Third party cookies may be blocked.', error);
|
68
|
-
this.redirectToAppTLD(ACCESS_DENIED_STATUS);
|
69
|
-
}
|
70
|
-
}
|
71
|
-
|
72
|
-
StorageAccessHelper.prototype.handleRequestStorageAccess = function() {
|
73
|
-
return document.requestStorageAccess().then(this.grantedStorageAccess.bind(this), this.redirectToAppsIndex.bind(this, ACCESS_DENIED_STATUS));
|
74
|
-
}
|
75
|
-
|
76
|
-
StorageAccessHelper.prototype.setupRequestStorageAccess = function() {
|
77
|
-
var requestContent = document.getElementById('RequestStorageAccess');
|
78
|
-
var requestButton = document.getElementById('TriggerAllowCookiesPrompt');
|
79
|
-
|
80
|
-
requestButton.addEventListener('click', this.handleRequestStorageAccess.bind(this));
|
81
|
-
requestContent.style.display = 'block';
|
82
|
-
}
|
83
|
-
|
84
|
-
StorageAccessHelper.prototype.handleHasStorageAccess = function() {
|
85
|
-
if (sessionStorage.getItem('shopify.granted_storage_access')) {
|
86
|
-
// If app was classified by ITP and used Storage Access API to acquire access
|
87
|
-
this.redirectToAppTargetUrl();
|
88
|
-
} else {
|
89
|
-
// If app has not been classified by ITP and still has storage access
|
90
|
-
this.redirectToAppTLD(ACCESS_GRANTED_STATUS);
|
91
|
-
}
|
92
|
-
}
|
93
|
-
|
94
|
-
StorageAccessHelper.prototype.handleGetStorageAccess = function() {
|
95
|
-
if (sessionStorage.getItem('shopify.top_level_interaction')) {
|
96
|
-
// If merchant has been redirected to interact with TLD (requirement for prompting request to gain storage access)
|
97
|
-
this.setupRequestStorageAccess();
|
98
|
-
} else {
|
99
|
-
// If merchant has not been redirected to interact with TLD (requirement for prompting request to gain storage access)
|
100
|
-
this.redirectToAppTLD(ACCESS_DENIED_STATUS);
|
101
|
-
}
|
102
|
-
}
|
103
|
-
|
104
|
-
StorageAccessHelper.prototype.manageStorageAccess = function() {
|
105
|
-
return document.hasStorageAccess().then(function(hasAccess) {
|
106
|
-
if (hasAccess) {
|
107
|
-
this.handleHasStorageAccess();
|
108
|
-
} else {
|
109
|
-
this.handleGetStorageAccess();
|
110
|
-
}
|
111
|
-
}.bind(this));
|
112
|
-
}
|
113
|
-
|
114
|
-
StorageAccessHelper.prototype.execute = function() {
|
115
|
-
if (ITPHelper.prototype.canPartitionCookies()) {
|
116
|
-
this.setUpCookiePartitioning();
|
117
|
-
return;
|
118
|
-
}
|
119
|
-
|
120
|
-
if (ITPHelper.prototype.userAgentIsAffected()) {
|
121
|
-
this.manageStorageAccess();
|
122
|
-
} else {
|
123
|
-
this.grantedStorageAccess();
|
124
|
-
}
|
125
|
-
}
|
126
|
-
|
127
|
-
/* ITP 2.0 solution: handles cookie partitioning */
|
128
|
-
StorageAccessHelper.prototype.setUpHelper = function() {
|
129
|
-
var shopifyData = document.body.dataset;
|
130
|
-
return new ITPHelper({redirectUrl: "https://" + shopifyData.shopOrigin + "/admin/apps/" + shopifyData.apiKey + shopifyData.returnTo});
|
131
|
-
}
|
132
|
-
|
133
|
-
StorageAccessHelper.prototype.setCookieAndRedirect = function() {
|
134
|
-
this.setCookie('shopify.cookies_persist=true');
|
135
|
-
var helper = this.setUpHelper();
|
136
|
-
helper.redirect();
|
137
|
-
}
|
138
|
-
|
139
|
-
StorageAccessHelper.prototype.setUpCookiePartitioning = function() {
|
140
|
-
var itpContent = document.getElementById('CookiePartitionPrompt');
|
141
|
-
itpContent.style.display = 'block';
|
142
|
-
|
143
|
-
var button = document.getElementById('AcceptCookies');
|
144
|
-
button.addEventListener('click', this.setCookieAndRedirect.bind(this));
|
145
|
-
}
|
146
|
-
|
147
|
-
this.StorageAccessHelper = StorageAccessHelper;
|
148
|
-
})(window);
|
@@ -1,17 +0,0 @@
|
|
1
|
-
(function() {
|
2
|
-
function redirect() {
|
3
|
-
var redirectTargetElement = document.getElementById("redirection-target");
|
4
|
-
|
5
|
-
var targetInfo = JSON.parse(redirectTargetElement.dataset.target)
|
6
|
-
|
7
|
-
if (window.top == window.self) {
|
8
|
-
// If the current window is the 'parent', change the URL by setting location.href
|
9
|
-
window.top.location.href = targetInfo.hasStorageAccessUrl;
|
10
|
-
} else {
|
11
|
-
var storageAccessHelper = new StorageAccessHelper(targetInfo);
|
12
|
-
storageAccessHelper.execute();
|
13
|
-
}
|
14
|
-
}
|
15
|
-
|
16
|
-
document.addEventListener("DOMContentLoaded", redirect);
|
17
|
-
})();
|
@@ -1,11 +0,0 @@
|
|
1
|
-
(function() {
|
2
|
-
function setUpTopLevelInteraction() {
|
3
|
-
var TopLevelInteraction = new ITPHelper({
|
4
|
-
redirectUrl: document.body.dataset.redirectUrl,
|
5
|
-
});
|
6
|
-
|
7
|
-
TopLevelInteraction.execute();
|
8
|
-
}
|
9
|
-
|
10
|
-
document.addEventListener("DOMContentLoaded", setUpTopLevelInteraction);
|
11
|
-
})();
|
@@ -1,70 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html lang="<%= I18n.locale %>">
|
3
|
-
<head>
|
4
|
-
<meta charset="utf-8" />
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
6
|
-
<base target="_top">
|
7
|
-
<title>Redirecting…</title>
|
8
|
-
<%= render 'shopify_app/partials/layout_styles' %>
|
9
|
-
<%= render 'shopify_app/partials/typography_styles' %>
|
10
|
-
<%= render 'shopify_app/partials/card_styles' %>
|
11
|
-
<%= render 'shopify_app/partials/button_styles' %>
|
12
|
-
<style>
|
13
|
-
#CookiePartitionPrompt {
|
14
|
-
display: none;
|
15
|
-
}
|
16
|
-
</style>
|
17
|
-
|
18
|
-
<%= javascript_include_tag('shopify_app/enable_cookies', crossorigin: 'anonymous', integrity: true) %>
|
19
|
-
</head>
|
20
|
-
<body data-api-key="<%= ShopifyApp.configuration.api_key %>" data-shop-origin="<%= @shop %>" data-redirect-url="<%= @url %>" data-host="<%= params[:host] %>" data-return-to="<%= params[:return_to] %>">
|
21
|
-
<%=
|
22
|
-
content_tag(
|
23
|
-
:div, nil,
|
24
|
-
id: 'redirection-target',
|
25
|
-
data: {
|
26
|
-
target: {
|
27
|
-
myshopifyUrl: "https://#{current_shopify_domain}",
|
28
|
-
hasStorageAccessUrl: "#{has_storage_access_url}",
|
29
|
-
doesNotHaveStorageAccessUrl: "#{does_not_have_storage_access_url}",
|
30
|
-
appTargetUrl: "#{app_target_url}"
|
31
|
-
},
|
32
|
-
},
|
33
|
-
)
|
34
|
-
%>
|
35
|
-
<main id="CookiePartitionPrompt">
|
36
|
-
<div class="Polaris-Page">
|
37
|
-
<div class="Polaris-Page__Content">
|
38
|
-
<div class="Polaris-Layout">
|
39
|
-
<div class="Polaris-Layout__Section">
|
40
|
-
<div class="Polaris-Stack Polaris-Stack--vertical">
|
41
|
-
<div class="Polaris-Stack__Item">
|
42
|
-
<div class="Polaris-Card">
|
43
|
-
<div class="Polaris-Card__Header">
|
44
|
-
<h1 class="Polaris-Heading"><%= I18n.t('enable_cookies_heading', app: ShopifyApp.configuration.application_name) %></h1>
|
45
|
-
</div>
|
46
|
-
<div class="Polaris-Card__Section">
|
47
|
-
<p><%= I18n.t('enable_cookies_body', app: ShopifyApp.configuration.application_name) %></p>
|
48
|
-
</div>
|
49
|
-
<div class="Polaris-Card__Section Polaris-Card__Section--subdued">
|
50
|
-
<p><%= I18n.t('enable_cookies_footer') %></p>
|
51
|
-
</div>
|
52
|
-
</div>
|
53
|
-
</div>
|
54
|
-
<div class="Polaris-Stack__Item">
|
55
|
-
<div class="Polaris-Stack Polaris-Stack--distributionTrailing Polaris-Stack--distributionTrailingCustomSpacing">
|
56
|
-
<div class="Polaris-Stack__Item">
|
57
|
-
<button type="button" class="Polaris-Button Polaris-Button--primary" id="AcceptCookies">
|
58
|
-
<span class="Polaris-Button__Content"><span><%= I18n.t('enable_cookies_action') %></span></span>
|
59
|
-
</button>
|
60
|
-
</div>
|
61
|
-
</div>
|
62
|
-
</div>
|
63
|
-
</div>
|
64
|
-
</div>
|
65
|
-
</div>
|
66
|
-
</div>
|
67
|
-
</div>
|
68
|
-
</main>
|
69
|
-
</body>
|
70
|
-
</html>
|
@@ -1,68 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html lang="<%= I18n.locale %>">
|
3
|
-
<head>
|
4
|
-
<meta charset="utf-8" />
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
6
|
-
<base target="_top">
|
7
|
-
<title>Redirecting…</title>
|
8
|
-
<%= render 'shopify_app/partials/layout_styles' %>
|
9
|
-
<%= render 'shopify_app/partials/typography_styles' %>
|
10
|
-
<%= render 'shopify_app/partials/card_styles' %>
|
11
|
-
<%= render 'shopify_app/partials/button_styles' %>
|
12
|
-
<style>
|
13
|
-
#RequestStorageAccess {
|
14
|
-
display: none;
|
15
|
-
}
|
16
|
-
</style>
|
17
|
-
</head>
|
18
|
-
<body data-api-key="<%= ShopifyApp.configuration.api_key %>" data-shop-origin="<%= current_shopify_domain %>" data-host="<%= params[:host] %>" data-return-to="<%= params[:return_to] %>">
|
19
|
-
<%=
|
20
|
-
content_tag(:div, nil,
|
21
|
-
id: 'redirection-target',
|
22
|
-
data: {
|
23
|
-
target: {
|
24
|
-
myshopifyUrl: "https://#{current_shopify_domain}",
|
25
|
-
hasStorageAccessUrl: "#{has_storage_access_url}",
|
26
|
-
doesNotHaveStorageAccessUrl: "#{does_not_have_storage_access_url}",
|
27
|
-
appTargetUrl: "#{app_target_url}"
|
28
|
-
},
|
29
|
-
},
|
30
|
-
)
|
31
|
-
%>
|
32
|
-
<main id="RequestStorageAccess">
|
33
|
-
<div class="Polaris-Page">
|
34
|
-
<div class="Polaris-Page__Content">
|
35
|
-
<div class="Polaris-Layout">
|
36
|
-
<div class="Polaris-Layout__Section">
|
37
|
-
<div class="Polaris-Stack Polaris-Stack--vertical">
|
38
|
-
<div class="Polaris-Stack__Item">
|
39
|
-
<div class="Polaris-Card">
|
40
|
-
<div class="Polaris-Card__Header">
|
41
|
-
<h1 class="Polaris-Heading"><%= I18n.t('request_storage_access_heading', app: ShopifyApp.configuration.application_name) %></h1>
|
42
|
-
</div>
|
43
|
-
<div class="Polaris-Card__Section">
|
44
|
-
<p><%= I18n.t('request_storage_access_body', app: ShopifyApp.configuration.application_name) %></p>
|
45
|
-
</div>
|
46
|
-
<div class="Polaris-Card__Section Polaris-Card__Section--subdued">
|
47
|
-
<p><%= I18n.t('request_storage_access_footer') %></p>
|
48
|
-
</div>
|
49
|
-
</div>
|
50
|
-
</div>
|
51
|
-
<div class="Polaris-Stack__Item">
|
52
|
-
<div class="Polaris-Stack Polaris-Stack--distributionTrailing Polaris-Stack--distributionTrailingCustomSpacing">
|
53
|
-
<div class="Polaris-Stack__Item">
|
54
|
-
<button type="button" class="Polaris-Button Polaris-Button--primary" id="TriggerAllowCookiesPrompt">
|
55
|
-
<span class="Polaris-Button__Content"><span><%= I18n.t('request_storage_access_action') %></span></span>
|
56
|
-
</button>
|
57
|
-
</div>
|
58
|
-
</div>
|
59
|
-
</div>
|
60
|
-
</div>
|
61
|
-
</div>
|
62
|
-
</div>
|
63
|
-
</div>
|
64
|
-
</div>
|
65
|
-
</main>
|
66
|
-
<%= javascript_include_tag('shopify_app/request_storage_access', crossorigin: 'anonymous', integrity: true) %>
|
67
|
-
</body>
|
68
|
-
</html>
|
@@ -1,63 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html lang="<%= I18n.locale %>">
|
3
|
-
<head>
|
4
|
-
<meta charset="utf-8" />
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
6
|
-
<base target="_top">
|
7
|
-
<title>Redirecting…</title>
|
8
|
-
<%= render 'shopify_app/partials/card_styles' %>
|
9
|
-
<%= render 'shopify_app/partials/layout_styles' %>
|
10
|
-
<%= render 'shopify_app/partials/typography_styles' %>
|
11
|
-
<%= render 'shopify_app/partials/button_styles' %>
|
12
|
-
<%= render 'shopify_app/partials/empty_state_styles' %>
|
13
|
-
<style>
|
14
|
-
#TopLevelInteractionContent {
|
15
|
-
display: none;
|
16
|
-
}
|
17
|
-
</style>
|
18
|
-
|
19
|
-
<%= javascript_include_tag('shopify_app/top_level', crossorigin: 'anonymous', integrity: true) %>
|
20
|
-
</head>
|
21
|
-
<body data-api-key="<%= ShopifyApp.configuration.api_key %>" data-shop-origin="https://<%= @shop %>" data-host="<%= @host %>" data-redirect-url="<%= @url %>">
|
22
|
-
<main id="TopLevelInteractionContent">
|
23
|
-
<div class="Polaris-Page">
|
24
|
-
<div class="Polaris-Page__Content">
|
25
|
-
<div class="Polaris-Layout">
|
26
|
-
<div class="Polaris-Layout__Section">
|
27
|
-
<div class="Polaris-Stack Polaris-Stack--vertical">
|
28
|
-
<div class="Polaris-Stack__Item">
|
29
|
-
<div class="Polaris-Card">
|
30
|
-
<div class="Polaris-Card__Section">
|
31
|
-
<div class="Polaris-EmptyState">
|
32
|
-
<div class="Polaris-EmptyState__Section">
|
33
|
-
<div class="Polaris-EmptyState__DetailsContainer">
|
34
|
-
<div class="Polaris-EmptyState__Details">
|
35
|
-
<div class="Polaris-TextContainer">
|
36
|
-
<h1 class="Polaris-DisplayText Polaris-DisplayText--sizeSmall"><%= I18n.t('top_level_interaction_heading', app: ShopifyApp.configuration.application_name) %></h1>
|
37
|
-
<div class="Polaris-EmptyState__Content">
|
38
|
-
<p><%= I18n.t('top_level_interaction_body', app: ShopifyApp.configuration.application_name) %></p>
|
39
|
-
</div>
|
40
|
-
</div>
|
41
|
-
<div class="Polaris-EmptyState__Actions">
|
42
|
-
<div class="Polaris-Stack Polaris-Stack--alignmentCenter">
|
43
|
-
<div class="Polaris-Stack__Item"><button type="button" id="TopLevelInteractionButton" class="Polaris-Button Polaris-Button--primary Polaris-Button--sizeLarge"><span class="Polaris-Button__Content"><span class="Polaris-Button__Icon"></span><span><%= I18n.t('top_level_interaction_action') %></span></span></button></div>
|
44
|
-
</div>
|
45
|
-
</div>
|
46
|
-
</div>
|
47
|
-
</div>
|
48
|
-
<div class="Polaris-EmptyState__ImageContainer">
|
49
|
-
<%= image_tag 'storage_access.svg', role: "presentation", alt: "", class: "Polaris-EmptyState__Image" %>
|
50
|
-
</div>
|
51
|
-
</div>
|
52
|
-
</div>
|
53
|
-
</div>
|
54
|
-
</div>
|
55
|
-
</div>
|
56
|
-
</div>
|
57
|
-
</div>
|
58
|
-
</div>
|
59
|
-
</div>
|
60
|
-
</div>
|
61
|
-
</main>
|
62
|
-
</body>
|
63
|
-
</html>
|
@@ -1,13 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html lang="en">
|
3
|
-
<head>
|
4
|
-
<meta charset="utf-8" />
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
6
|
-
<base target="_top">
|
7
|
-
<title>Redirecting…</title>
|
8
|
-
<%= javascript_include_tag('shopify_app/post_redirect', crossorigin: 'anonymous', integrity: true) %>
|
9
|
-
</head>
|
10
|
-
<body>
|
11
|
-
<%= form_tag '/auth/shopify', id: 'redirect-form' %>
|
12
|
-
</body>
|
13
|
-
</html>
|