shopify_app 21.3.0 → 21.4.0
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/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 +3 -1
- 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 -20
- 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: f8bffcbbd9262af14d8b5d0c0333b2a17f4de563ad4c40134dec7b838eaf789b
|
4
|
+
data.tar.gz: 0ba89c4f9ff64b366c3d368b70abcfdf2e02f1e0f66c796f5b16a6a5fafdcd07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc4dc9ccd6267a2eb7ff1d22e54f1527c0ab32cb61b83841bc71cc4bb79b14a33aa4021e13494e3167d0a7d20aeea86f9af9dd478ebff8400ec4b33ac1426417
|
7
|
+
data.tar.gz: c2154db900a3fb4321be1d224c8d44987fdce714984b3004b87b4dd5301717832fa11b907fe88b261020da82b4c3255256d4e4ba4dd5800262a8e3daa4778f91
|
@@ -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.0 (Jan 5, 2023)
|
5
|
+
----------
|
6
|
+
* Updated shopify_api to 12.4.0 [#1633](https://github.com/Shopify/shopify_app/pull/1633)
|
7
|
+
* Removed Logged output for rescued JWT exceptions [#1610](https://github.com/Shopify/shopify_app/pull/1610)
|
8
|
+
* 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)
|
9
|
+
* Validates shop's offline session token is still valid when using `EnsureInstalled`[#1612](https://github.com/Shopify/shopify_app/pull/1612)
|
10
|
+
* Allows use of multiple subdomains with myshopify_domain [#1620](https://github.com/Shopify/shopify_app/pull/1620)
|
11
|
+
* Added a `setup_shopify_session` test helper to stub a valid session
|
12
|
+
|
13
|
+
21.3.1 (Dec 12, 2022)
|
14
|
+
----------
|
15
|
+
* 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)
|
16
|
+
|
4
17
|
21.3.0 (Dec 9, 2022)
|
5
18
|
----------
|
6
19
|
* Move covered scopes check into user access strategy [#1600](https://github.com/Shopify/shopify_app/pull/1600)
|
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.0)
|
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.
|
@@ -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,30 +2,69 @@
|
|
2
2
|
|
3
3
|
module ShopifyApp
|
4
4
|
module Utils
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
16
47
|
|
17
|
-
|
18
|
-
|
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
|
19
53
|
|
20
|
-
|
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)
|
21
58
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
)
|
59
|
+
if uri.scheme.nil?
|
60
|
+
name = "https://" + name
|
61
|
+
uri = Addressable::URI.parse(name)
|
62
|
+
end
|
27
63
|
|
28
|
-
|
64
|
+
uri
|
65
|
+
rescue Addressable::URI::InvalidURIError
|
66
|
+
nil
|
67
|
+
end
|
29
68
|
end
|
30
69
|
end
|
31
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.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: 2023-01-05 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>
|