shopify_app 14.4.4 → 18.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +1 -0
- data/.github/ISSUE_TEMPLATE/bug-report.md +63 -0
- data/.github/ISSUE_TEMPLATE/config.yml +1 -0
- data/.github/ISSUE_TEMPLATE/feature-request.md +33 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +17 -1
- data/.github/workflows/build.yml +41 -0
- data/.github/workflows/release.yml +24 -0
- data/.github/workflows/rubocop.yml +1 -7
- data/.gitignore +0 -2
- data/CHANGELOG.md +75 -0
- data/CONTRIBUTING.md +76 -0
- data/Gemfile.lock +268 -0
- data/README.md +73 -572
- data/app/assets/images/storage_access.svg +1 -2
- data/app/assets/javascripts/shopify_app/post_redirect.js +9 -0
- data/app/controllers/concerns/shopify_app/ensure_authenticated_links.rb +26 -0
- data/app/controllers/concerns/shopify_app/shop_access_scopes_verification.rb +32 -0
- data/app/controllers/shopify_app/callback_controller.rb +34 -10
- data/app/controllers/shopify_app/sessions_controller.rb +19 -20
- data/app/views/shopify_app/partials/_button_styles.html.erb +41 -36
- data/app/views/shopify_app/partials/_card_styles.html.erb +3 -3
- data/app/views/shopify_app/partials/_empty_state_styles.html.erb +28 -59
- data/app/views/shopify_app/partials/_form_styles.html.erb +56 -0
- data/app/views/shopify_app/partials/_layout_styles.html.erb +16 -1
- data/app/views/shopify_app/partials/_typography_styles.html.erb +6 -6
- data/app/views/shopify_app/sessions/enable_cookies.html.erb +1 -1
- data/app/views/shopify_app/sessions/new.html.erb +38 -110
- data/app/views/shopify_app/sessions/request_storage_access.html.erb +1 -1
- data/app/views/shopify_app/sessions/top_level_interaction.html.erb +20 -15
- data/app/views/shopify_app/shared/post_redirect_to_auth_shopify.html.erb +13 -0
- data/config/locales/de.yml +11 -11
- data/config/locales/nl.yml +1 -1
- data/config/locales/vi.yml +22 -0
- data/config/locales/zh-CN.yml +1 -1
- data/docs/Quickstart.md +15 -77
- data/docs/Releasing.md +9 -6
- data/docs/Troubleshooting.md +147 -4
- data/docs/Upgrading.md +126 -0
- data/docs/shopify_app/authentication.md +124 -0
- data/docs/shopify_app/engine.md +82 -0
- data/docs/shopify_app/generators.md +127 -0
- data/docs/shopify_app/handling-access-scopes-changes.md +14 -0
- data/docs/shopify_app/script-tags.md +28 -0
- data/docs/shopify_app/session-repository.md +88 -0
- data/docs/shopify_app/testing.md +38 -0
- data/docs/shopify_app/webhooks.md +72 -0
- data/lib/generators/shopify_app/home_controller/home_controller_generator.rb +16 -7
- data/lib/generators/shopify_app/home_controller/templates/home_controller.rb +10 -0
- data/lib/generators/shopify_app/home_controller/templates/index.html.erb +11 -11
- data/lib/generators/shopify_app/home_controller/templates/unauthenticated_home_controller.rb +2 -0
- data/lib/generators/shopify_app/install/install_generator.rb +36 -2
- data/lib/generators/shopify_app/install/templates/embedded_app.html.erb +2 -1
- data/lib/generators/shopify_app/install/templates/omniauth.rb +1 -0
- data/lib/generators/shopify_app/install/templates/shopify_app.js +1 -1
- data/lib/generators/shopify_app/install/templates/shopify_app.rb.tt +13 -4
- data/lib/generators/shopify_app/install/templates/shopify_provider.rb.tt +8 -0
- data/lib/generators/shopify_app/shop_model/shop_model_generator.rb +27 -0
- data/lib/generators/shopify_app/shop_model/templates/db/migrate/add_shop_access_scopes_column.erb +5 -0
- data/lib/generators/shopify_app/shop_model/templates/shop.rb +1 -1
- data/lib/generators/shopify_app/shopify_app_generator.rb +1 -1
- data/lib/generators/shopify_app/user_model/templates/db/migrate/add_user_access_scopes_column.erb +5 -0
- data/lib/generators/shopify_app/user_model/templates/user.rb +1 -1
- data/lib/generators/shopify_app/user_model/user_model_generator.rb +27 -0
- data/lib/shopify_app/access_scopes/noop_strategy.rb +13 -0
- data/lib/shopify_app/access_scopes/shop_strategy.rb +24 -0
- data/lib/shopify_app/access_scopes/user_strategy.rb +41 -0
- data/lib/shopify_app/configuration.rb +25 -0
- data/lib/shopify_app/controller_concerns/itp.rb +0 -2
- data/lib/shopify_app/controller_concerns/login_protection.rb +14 -17
- data/lib/shopify_app/engine.rb +1 -0
- data/lib/shopify_app/middleware/same_site_cookie_middleware.rb +1 -1
- data/lib/shopify_app/omniauth/omniauth_configuration.rb +64 -0
- data/lib/shopify_app/session/in_memory_shop_session_store.rb +9 -7
- data/lib/shopify_app/session/in_memory_user_session_store.rb +9 -7
- data/lib/shopify_app/session/jwt.rb +3 -1
- data/lib/shopify_app/session/shop_session_storage_with_scopes.rb +58 -0
- data/lib/shopify_app/session/user_session_storage_with_scopes.rb +58 -0
- data/lib/shopify_app/utils.rb +12 -0
- data/lib/shopify_app/version.rb +1 -1
- data/lib/shopify_app.rb +11 -0
- data/package.json +1 -1
- data/service.yml +1 -4
- data/shopify_app.gemspec +5 -4
- data/translation.yml +1 -1
- data/yarn.lock +92 -123
- metadata +62 -16
- data/.github/ISSUE_TEMPLATE.md +0 -19
- data/.travis.yml +0 -27
- data/docs/install-on-dev-shop.png +0 -0
- data/docs/test-your-app.png +0 -0
- data/lib/generators/shopify_app/install/templates/shopify_provider.rb +0 -20
@@ -1,2 +1 @@
|
|
1
|
-
|
2
|
-
<svg enable-background="new 0 0 1920 1080" version="1.1" viewBox="0 0 1920 1080" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><polygon points="1345 330.75 1345 437.24 1224.7 437.24 1224.7 676.56 873.52 676.56 874.04 643.85 1203.2 330.23" fill="#fff"/><path d="m1095.7 677.54c-18.553 0.074-37.107 0.163-55.66 0.126-18.553 0.056-37.107-0.188-55.66-0.233l-13.915-0.063-13.915 0.044-27.83 0.094c-18.553 0.128-37.107-5e-3 -55.66-0.056l-1.266-3e-3 3e-3 -1.259 0.047-22.532-0.093-22.532-0.068-11.266 6e-3 -11.266 0.019-22.532h2.703l0.111 22.532c0.053 7.511 0.06 15.022 0.038 22.532l-0.094 45.065-1.407-1.407c18.553 7e-3 37.107-0.041 55.66 0.086l27.83 0.131 13.915 0.066 13.915-0.028c18.553-8e-3 37.107-0.151 55.66-0.019 18.553 0.099 37.107 0.049 55.66-0.181v2.701z" fill="#0C1238"/><path d="m1225 677.54c-9.24 0.123-18.48 0.187-27.72 0.077l-13.86-0.213c-2.31-0.051-4.62-0.023-6.93 1e-3l-6.93 0.062c-9.24 0.156-18.48 0.076-27.72-0.054-2.31-0.034-4.62 1e-3 -6.93 2e-3l-6.93 0.121c-4.62 0.062-9.24-2e-3 -13.86 3e-3v-2.703c4.62-0.048 9.24-0.165 13.86-0.157l6.93 0.025c2.31 0.027 4.62 0.088 6.93 0.076 9.24-0.024 18.48-0.031 27.72 0.145 4.62 0.038 9.24 0.163 13.86 0.126l13.86-0.081c4.62-0.04 9.24 0.088 13.86 0.101 2.31 0.047 4.62-0.048 6.93-0.065 2.31-0.026 4.62-0.07 6.93-0.169v2.703z" fill="#0C1238"/><path d="m871.68 561.78l-0.13-115.72 0.07-115.72 1e-3 -1.414 1.411 3e-3 117.9 0.228 117.9-0.138 58.951-0.061 58.951 0.072 117.9 0.09 1.218 1e-3 4e-3 1.221 0.156 53.426-0.026 53.426h-2.703l-0.154-53.426 0.04-53.426 1.466 1.466-235.8-0.148-117.9-0.193-117.9 0.087 1.212-1.212-0.084 115.72c-0.058 19.286 0.032 38.573 0.074 57.859l0.15 57.859h-2.705z" fill="#0C1238"/><g fill="#E6E8F0"><circle cx="891.37" cy="344.49" r="6.812"/><circle cx="912.86" cy="345.01" r="6.812"/><circle cx="934.34" cy="345.54" r="6.812"/><path d="m1202.7 352.87h-186.64c-0.552 0-1-0.448-1-1v-11.624c0-0.552 0.448-1 1-1h186.64c0.552 0 1 0.448 1 1v11.624c0 0.552-0.448 1-1 1z" stroke="#F0F3F5" stroke-miterlimit="10"/><rect x="1288.6" y="339.25" width="17.816" height="13.624"/><path d="m1327.4 352.87h-15.816c-0.552 0-1-0.448-1-1v-11.624c0-0.552 0.448-1 1-1h15.816c0.552 0 1 0.448 1 1v11.624c0 0.552-0.447 1-1 1z"/></g><g fill="none" stroke="#8891EA" stroke-miterlimit="10" stroke-width="8"><path d="m1098.3 576.8c-24.295 0-43.99-19.695-43.99-43.99v-29.485c0-2.209 1.791-4 4-4h79.98c2.209 0 4 1.791 4 4v29.485c0 24.295-19.695 43.99-43.99 43.99z"/><path d="m1066 499.33v-12.41c0-17.804 14.433-32.237 32.237-32.237s32.237 14.433 32.237 32.237v12.41"/></g><circle cx="1098.3" cy="529.08" r="8.966" fill="#8891EA"/><line x1="1098.3" x2="1098.3" y1="529.08" y2="546.68" fill="#fff" stroke="#8891EA" stroke-linecap="round" stroke-miterlimit="10" stroke-width="8"/><polygon points="1416.1 676.19 1358 748.57 1416.1 749.77 1225 749.77 1225 659.42 1416.1 437.19" fill="#fff"/><path d="m1415.2 497.07l-0.12-59.83 1.472 1.472-95.89-0.052-47.945-0.135c-15.982-0.023-31.963-0.14-47.945-0.085l1.2-1.2 0.139 78.077c0.086 26.026 4e-3 52.052-0.039 78.077l-0.076 78.077c0.056 26.026 0.201 52.052 0.145 78.077l-1.368-1.368 38.25 0.017v2.703l-38.251 0.1-1.444 4e-3 -6e-3 -1.454c-0.102-26.026-0.045-52.052-0.026-78.077l0.068-78.077 0.067-78.077 0.191-78.077 3e-3 -1.15h1.147l47.945-0.013 47.945-0.051 95.89 0.089 1.121 1e-3 4e-3 1.125 0.226 59.83h-2.703z" fill="#0C1238"/><path d="m1417.9 518.33c0.051 19.268 0.165 38.536 0.128 57.804l-0.022 28.902-0.134 28.902-0.134 28.902 0.061 28.902 0.087 28.902 0.046 14.451-0.034 14.451-3e-3 1.353-1.347-3e-3c-22.64-0.042-45.28-0.192-67.919-0.118l-33.96 0.144-33.96-0.025v-2.703l33.96-0.143 33.96 0.01c11.32 0.049 22.64 0.1 33.96 0.078l33.96-2e-3 -1.409 1.409c-0.03-19.268 0.125-38.536 0.178-57.804l0.103-28.902-0.051-28.902-0.051-28.902 0.081-28.902c0.128-19.268-0.116-38.536-0.204-57.804h2.704z" fill="#0C1238"/><path d="m1400.3 458.72h-160.44c-0.552 0-1-0.448-1-1v-11.624c0-0.552 0.448-1 1-1h160.44c0.552 0 1 0.448 1 1v11.624c0 0.552-0.448 1-1 1z" fill="#E6E8F0" stroke="#F0F3F5" stroke-miterlimit="10"/><path d="m1238.5 467.44c13.587-0.084 27.173-0.121 40.76-0.055l20.38 0.141c6.793 0.061 13.587-0.03 20.38-0.038 13.587-0.116 27.173-0.022 40.76 0.038 6.793 0.029 13.587-0.022 20.38-0.082 6.793-0.046 13.587 0 20.38-5e-3v1.802c-13.587 0.111-27.173 0.144-40.76 0.036-13.587 2e-3 -27.173 0.027-40.76-0.09-6.793-0.025-13.587-0.117-20.38-0.088l-20.38 0.054c-6.793 0.022-13.587-0.048-20.38-0.067-6.793-7e-3 -13.587 0.107-20.38 0.154v-1.8z" fill="#E6E8F0"/><path d="m891.69 362.56c36.392-0.084 72.784-0.121 109.18-0.055l54.588 0.141c18.196 0.062 36.392-0.034 54.588-0.043l218.35-0.043v1.802c-36.392 0.111-72.784 0.144-109.18 0.036l-109.18-0.09-54.588-0.088-54.588 0.054-54.588-0.067-54.588 0.154v-1.801z" fill="#E6E8F0"/><g fill="none" stroke="#8891EA" stroke-miterlimit="10" stroke-width="6"><path d="m1320.6 638.41c-17.878 0-32.371-14.493-32.371-32.371v-21.697c0-1.626 1.318-2.943 2.943-2.943h58.854c1.626 0 2.943 1.318 2.943 2.943v21.697c1e-3 17.878-14.491 32.371-32.369 32.371z"/><path d="m1296.9 581.4v-9.132c0-13.101 10.62-23.722 23.722-23.722 13.101 0 23.722 10.621 23.722 23.722v9.132"/></g><circle cx="1320.6" cy="604.5" r="5.88" fill="#8891EA"/><line x1="1320.6" x2="1320.6" y1="603.3" y2="616.25" fill="#fff" stroke="#8891EA" stroke-linecap="round" stroke-miterlimit="10" stroke-width="6"/><path d="m966.35 697.36l-0.029 13.745c-0.01 1.145 0.011 2.291-0.023 3.436l-0.124 3.436c-0.103 2.291 0.022 4.582 0.121 6.872l-1.912-1.912c10.168-0.857 20.337-0.478 30.505-0.36 5.084 0.104 10.168 0.133 15.252 0.178 5.084 6e-3 10.168 0.199 15.252 0.287l7.626 0.168 7.626 0.264c2.542 0.09 5.084 0.032 7.626 0.023 2.542-0.035 5.084 0.047 7.626 0.065 10.168 0.377 20.337-0.052 30.505 0.201l7.626 0.04c2.542 6e-3 5.084-0.283 7.626-0.394 5.084-0.14 10.168-0.184 15.252-0.268 5.084-0.072 10.168-0.071 15.252-0.204 2.542-0.07 5.084-0.088 7.626-0.118 2.542-0.019 5.084 0.1 7.626 0.143 10.168 0.462 20.337-0.303 30.505 0.192 2.542 0.145 5.084 0.163 7.626 0.139 2.542 0 5.084-0.038 7.626-0.099l15.252-0.314v3.936l-15.252 0.106c-5.084 0.024-10.168 0.012-15.252 0.3-10.168 0.483-20.337-0.281-30.505-0.213-20.337-1.165-40.673 0.704-61.01-0.137-2.542 0.117-5.084 0.33-7.626 0.382-2.542 0.092-5.084 0.173-7.626-0.018s-5.084-0.219-7.626-0.183c-2.542-2e-3 -5.084 0.099-7.626 0.081-2.542-0.027-5.084 0.026-7.626-0.066-1.271-0.039-2.542-0.079-3.813-0.09-1.271-0.022-2.542-0.05-3.813 0.018-2.542 0.097-5.084 0.355-7.626 0.327-1.271-0.037-2.542-0.06-3.813-0.12l-3.813-0.238c-2.542-0.162-5.084-0.324-7.626-0.268-2.542 0.109-5.084-0.092-7.626-0.222-2.542-0.112-5.084-0.326-7.626-0.371-2.542-0.094-5.084-0.061-7.626-0.038-5.084 0.101-10.168 0.266-15.252 0.414-2.542 0.071-5.084 0.122-7.626 0.123l-7.626-0.19-1.598-0.04 0.032-1.527c0.047-2.291 0.153-4.582 9e-3 -6.872l-0.162-3.436c-0.047-1.145-0.04-2.291-0.062-3.436l-0.186-13.745h3.934z" fill="#E6E8F0"/><path d="m1434.8 722.88l16.096 0.019 8.048 0.01c2.683 0.018 5.365-0.029 8.048 0.05l-1.89 1.89c0.07-3.44 0.218-6.88 0.086-10.32l-0.312-10.32c-0.261-6.88-0.364-13.76-0.339-20.639l0.314-41.279c0.052-6.88 0.033-13.76 0.144-20.639l0.275-20.639c0.057-6.88 0.274-13.76 0.375-20.639 0.058-6.88-0.069-13.76 0.033-20.639l0.226-20.639-0.071-10.32-0.046-5.16 0.032-5.16 0.11-20.639c0.012-3.44 0.045-6.88-0.068-10.32-0.149-3.44-0.261-6.88-0.361-10.32l-0.328-41.279c-0.074-6.88-0.188-13.76-0.211-20.639 0.028-6.88 0.177-13.76 0.261-20.639l1.77 1.77c-4.37-0.095-8.74 1e-3 -13.111 1e-3l-13.111 0.063c-4.37 1e-3 -8.74 0.084-13.111 0.016l-13.111-0.231c-4.37-0.118-8.74-0.058-13.111-0.055-4.37-4e-3 -8.74 0.077-13.111 0.113l-26.221 0.29v-3.936l26.221-0.107 13.111-0.052c4.37-0.026 8.74 2e-3 13.111-0.14l13.111-0.262c4.37-0.066 8.74 0.04 13.111 0.051l26.221 0.283 2.211 0.024-0.016 2.172c-0.049 6.88-0.045 13.76-0.139 20.639-0.152 6.88-0.325 13.76-0.304 20.639l0.499 41.279c-0.024 1.72-0.037 3.44-0.138 5.16l-0.297 5.16c-0.137 3.44-0.045 6.88 0.01 10.32 0.12 6.88 0.479 13.76 0.59 20.639 0.273 6.88-0.127 13.76-0.227 20.639-0.014 6.88 0.146 13.76 0.091 20.639 0.051 6.88-0.202 13.76-0.162 20.639 0.04 3.44 0.226 6.88 0.324 10.32 0.061 3.44 4e-3 6.88-0.082 10.32l-0.356 10.32c-0.047 1.72-0.141 3.44-0.149 5.16l2e-3 5.16c-0.012 1.72 0.032 3.44-0.026 5.16l-0.164 5.16-0.335 10.32c-0.306 13.76 0.065 27.519 0.289 41.279 0.074 3.44 0.091 6.88 0.13 10.32 0.059 3.44-0.071 6.88-0.098 10.32l-0.153 10.32c-0.053 1.72 0.021 3.44 0.049 5.16l0.139 5.16 0.044 1.627-1.73 0.06c-2.683 0.093-5.365 0.065-8.048 0.1l-8.048 0.061-16.096 0.121v-3.941z" fill="#E6E8F0"/></svg>
|
1
|
+
<svg width="140" height="140" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M79 55a9 9 0 00-18 0v8h18v-8zm6 8v-8a15 15 0 00-30 0v8h-5a2 2 0 00-2 2v20a15 15 0 0015 15h14a15 15 0 0015-15V65a2 2 0 00-2-2h-5zM70 90a3 3 0 01-3-3V75a3 3 0 116 0v12a3 3 0 01-3 3z" fill="#8C9196"/></svg>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShopifyApp
|
4
|
+
module EnsureAuthenticatedLinks
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
before_action :redirect_to_splash_page, if: :missing_expected_jwt?
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def redirect_to_splash_page
|
14
|
+
splash_page_path = root_path(return_to: request.fullpath, shop: current_shopify_domain)
|
15
|
+
redirect_to(splash_page_path)
|
16
|
+
rescue ShopifyApp::LoginProtection::ShopifyDomainNotFound => error
|
17
|
+
Rails.logger.warn("[ShopifyApp::EnsureAuthenticatedLinks] Redirecting to login: [#{error.class}] "\
|
18
|
+
"Could not determine current shop domain")
|
19
|
+
redirect_to(ShopifyApp.configuration.login_url)
|
20
|
+
end
|
21
|
+
|
22
|
+
def missing_expected_jwt?
|
23
|
+
jwt_shopify_domain.blank?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShopifyApp
|
4
|
+
module ShopAccessScopesVerification
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
before_action :login_on_scope_changes
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def login_on_scope_changes
|
14
|
+
redirect_to(shop_login) if scopes_mismatch?
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def scopes_mismatch?
|
20
|
+
ShopifyApp.configuration.shop_access_scopes_strategy.update_access_scopes?(current_shopify_domain)
|
21
|
+
end
|
22
|
+
|
23
|
+
def current_shopify_domain
|
24
|
+
return if params[:shop].blank?
|
25
|
+
ShopifyApp::Utils.sanitize_shop_domain(params[:shop])
|
26
|
+
end
|
27
|
+
|
28
|
+
def shop_login
|
29
|
+
ShopifyApp::Utils.shop_login_url(shop: params[:shop], return_to: request.fullpath)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -30,16 +30,12 @@ module ShopifyApp
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def respond_with_user_token_flow
|
33
|
-
Rails.logger.debug("[ShopifyApp::CallbackController] Redirecting for user token...")
|
34
33
|
redirect_to(login_url_with_optional_shop)
|
35
34
|
end
|
36
35
|
|
37
36
|
def store_access_token_and_build_session
|
38
37
|
if native_browser_request?
|
39
|
-
Rails.logger.debug("[ShopifyApp::CallbackController] Not a JWT request. Resetting session options...")
|
40
38
|
reset_session_options
|
41
|
-
else
|
42
|
-
Rails.logger.debug("[ShopifyApp::CallbackController] JWT request detected. Setting shopify session...")
|
43
39
|
end
|
44
40
|
set_shopify_session
|
45
41
|
end
|
@@ -62,23 +58,38 @@ module ShopifyApp
|
|
62
58
|
|
63
59
|
def respond_with_error
|
64
60
|
if jwt_request?
|
65
|
-
Rails.logger.debug("[ShopifyApp::CallbackController] Invalid JWT auth detected.")
|
66
61
|
head(:unauthorized)
|
67
62
|
else
|
68
|
-
Rails.logger.debug("[ShopifyApp::CallbackController] Invalid non JWT auth detected.")
|
69
63
|
flash[:error] = I18n.t('could_not_log_in')
|
70
64
|
redirect_to(login_url_with_optional_shop)
|
71
65
|
end
|
72
66
|
end
|
73
67
|
|
68
|
+
# Override user_session_by_cookie from LoginProtection to bypass allow_cookie_authentication
|
69
|
+
# setting check because session cookies are justified at top level
|
70
|
+
def user_session_by_cookie
|
71
|
+
return unless session[:user_id].present?
|
72
|
+
ShopifyApp::SessionRepository.retrieve_user_session(session[:user_id])
|
73
|
+
end
|
74
|
+
|
74
75
|
def start_user_token_flow?
|
75
76
|
if jwt_request?
|
76
77
|
false
|
77
78
|
else
|
78
|
-
ShopifyApp::SessionRepository.user_storage.present?
|
79
|
+
return false unless ShopifyApp::SessionRepository.user_storage.present?
|
80
|
+
update_user_access_scopes?
|
79
81
|
end
|
80
82
|
end
|
81
83
|
|
84
|
+
def update_user_access_scopes?
|
85
|
+
return true if user_session.blank?
|
86
|
+
user_access_scopes_strategy.update_access_scopes?(user_id: session[:user_id])
|
87
|
+
end
|
88
|
+
|
89
|
+
def user_access_scopes_strategy
|
90
|
+
ShopifyApp.configuration.user_access_scopes_strategy
|
91
|
+
end
|
92
|
+
|
82
93
|
def jwt_request?
|
83
94
|
jwt_shopify_domain || jwt_shopify_user_id
|
84
95
|
end
|
@@ -95,6 +106,14 @@ module ShopifyApp
|
|
95
106
|
auth_hash.uid
|
96
107
|
end
|
97
108
|
|
109
|
+
def offline_access_token
|
110
|
+
ShopifyApp::SessionRepository.retrieve_shop_session_by_shopify_domain(shop_name)&.token
|
111
|
+
end
|
112
|
+
|
113
|
+
def online_access_token
|
114
|
+
ShopifyApp::SessionRepository.retrieve_user_session_by_shopify_user_id(associated_user_id)&.token
|
115
|
+
end
|
116
|
+
|
98
117
|
def associated_user
|
99
118
|
return unless auth_hash.dig('extra', 'associated_user').present?
|
100
119
|
|
@@ -109,6 +128,10 @@ module ShopifyApp
|
|
109
128
|
auth_hash['credentials']['token']
|
110
129
|
end
|
111
130
|
|
131
|
+
def access_scopes
|
132
|
+
auth_hash.dig('extra', 'scope')
|
133
|
+
end
|
134
|
+
|
112
135
|
def reset_session_options
|
113
136
|
request.session_options[:renew] = true
|
114
137
|
session.delete(:_csrf_token)
|
@@ -118,7 +141,8 @@ module ShopifyApp
|
|
118
141
|
session_store = ShopifyAPI::Session.new(
|
119
142
|
domain: shop_name,
|
120
143
|
token: token,
|
121
|
-
api_version: ShopifyApp.configuration.api_version
|
144
|
+
api_version: ShopifyApp.configuration.api_version,
|
145
|
+
access_scopes: access_scopes
|
122
146
|
)
|
123
147
|
|
124
148
|
session[:shopify_user] = associated_user
|
@@ -138,7 +162,7 @@ module ShopifyApp
|
|
138
162
|
|
139
163
|
WebhooksManager.queue(
|
140
164
|
shop_name,
|
141
|
-
|
165
|
+
offline_access_token || online_access_token,
|
142
166
|
ShopifyApp.configuration.webhooks
|
143
167
|
)
|
144
168
|
end
|
@@ -148,7 +172,7 @@ module ShopifyApp
|
|
148
172
|
|
149
173
|
ScripttagsManager.queue(
|
150
174
|
shop_name,
|
151
|
-
|
175
|
+
offline_access_token || online_access_token,
|
152
176
|
ShopifyApp.configuration.scripttags
|
153
177
|
)
|
154
178
|
end
|
@@ -10,19 +10,14 @@ module ShopifyApp
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def new
|
13
|
-
if sanitized_shop_name.present?
|
14
|
-
Rails.logger.debug("[ShopifyApp::SessionsController] Sanitized shop name present. Authenticating...")
|
15
|
-
authenticate
|
16
|
-
end
|
13
|
+
authenticate if sanitized_shop_name.present?
|
17
14
|
end
|
18
15
|
|
19
16
|
def create
|
20
|
-
Rails.logger.debug("[ShopifyApp::SessionsController] Authenticating...")
|
21
17
|
authenticate
|
22
18
|
end
|
23
19
|
|
24
20
|
def enable_cookies
|
25
|
-
Rails.logger.debug("[ShopifyApp::SessionsController] Enabling cookies...")
|
26
21
|
return unless validate_shop_presence
|
27
22
|
|
28
23
|
render(:enable_cookies, layout: false, locals: {
|
@@ -45,7 +40,6 @@ module ShopifyApp
|
|
45
40
|
end
|
46
41
|
|
47
42
|
def granted_storage_access
|
48
|
-
Rails.logger.debug("[ShopifyApp::SessionsController] Granted storage access.")
|
49
43
|
return unless validate_shop_presence
|
50
44
|
|
51
45
|
session['shopify.granted_storage_access'] = true
|
@@ -56,7 +50,6 @@ module ShopifyApp
|
|
56
50
|
end
|
57
51
|
|
58
52
|
def destroy
|
59
|
-
Rails.logger.debug("[ShopifyApp::SessionsController] Resetting session.")
|
60
53
|
reset_session
|
61
54
|
flash[:notice] = I18n.t('.logged_out')
|
62
55
|
redirect_to(login_url_with_optional_shop)
|
@@ -73,23 +66,18 @@ module ShopifyApp
|
|
73
66
|
set_user_tokens_option
|
74
67
|
|
75
68
|
if user_agent_can_partition_cookies
|
76
|
-
Rails.logger.debug("[ShopifyApp::SessionsController] Authenticating with partitioning...")
|
77
69
|
authenticate_with_partitioning
|
78
70
|
else
|
79
|
-
Rails.logger.debug("[ShopifyApp::SessionsController] Authenticating normally...")
|
80
71
|
authenticate_normally
|
81
72
|
end
|
82
73
|
end
|
83
74
|
|
84
75
|
def authenticate_normally
|
85
76
|
if request_storage_access?
|
86
|
-
Rails.logger.debug("[ShopifyApp::SessionsController] Redirecting to request storage access...")
|
87
77
|
redirect_to_request_storage_access
|
88
78
|
elsif authenticate_in_context?
|
89
|
-
Rails.logger.debug("[ShopifyApp::SessionsController] Authenticating in context...")
|
90
79
|
authenticate_in_context
|
91
80
|
else
|
92
|
-
Rails.logger.debug("[ShopifyApp::SessionsController] Authenticating at top level...")
|
93
81
|
authenticate_at_top_level
|
94
82
|
end
|
95
83
|
end
|
@@ -104,10 +92,18 @@ module ShopifyApp
|
|
104
92
|
end
|
105
93
|
end
|
106
94
|
|
95
|
+
# Override shop_session_by_cookie from LoginProtection to bypass allow_cookie_authentication
|
96
|
+
# setting check because session cookies are justified at top level
|
97
|
+
def shop_session_by_cookie
|
98
|
+
return unless session[:shop_id].present?
|
99
|
+
ShopifyApp::SessionRepository.retrieve_shop_session(session[:shop_id])
|
100
|
+
end
|
101
|
+
|
107
102
|
# rubocop:disable Lint/SuppressedException
|
108
103
|
def set_user_tokens_option
|
109
|
-
|
110
|
-
|
104
|
+
current_shop_session = shop_session
|
105
|
+
|
106
|
+
if current_shop_session.blank?
|
111
107
|
session[:user_tokens] = false
|
112
108
|
return
|
113
109
|
end
|
@@ -115,9 +111,9 @@ module ShopifyApp
|
|
115
111
|
session[:user_tokens] = ShopifyApp::SessionRepository.user_storage.present?
|
116
112
|
|
117
113
|
ShopifyAPI::Session.temp(
|
118
|
-
domain:
|
119
|
-
token:
|
120
|
-
api_version:
|
114
|
+
domain: current_shop_session.domain,
|
115
|
+
token: current_shop_session.token,
|
116
|
+
api_version: current_shop_session.api_version
|
121
117
|
) do
|
122
118
|
ShopifyAPI::Metafield.find(:token_validity_bogus_check)
|
123
119
|
end
|
@@ -130,7 +126,6 @@ module ShopifyApp
|
|
130
126
|
def validate_shop_presence
|
131
127
|
@shop = sanitized_shop_name
|
132
128
|
unless @shop
|
133
|
-
Rails.logger.debug("[ShopifyApp::SessionsController] Invalid shop detected.")
|
134
129
|
render_invalid_shop_error
|
135
130
|
return false
|
136
131
|
end
|
@@ -155,7 +150,11 @@ module ShopifyApp
|
|
155
150
|
end
|
156
151
|
|
157
152
|
def authenticate_in_context
|
158
|
-
|
153
|
+
post_redirect_to_auth_shopify
|
154
|
+
end
|
155
|
+
|
156
|
+
def post_redirect_to_auth_shopify
|
157
|
+
render('shopify_app/shared/post_redirect_to_auth_shopify', layout: false)
|
159
158
|
end
|
160
159
|
|
161
160
|
def authenticate_at_top_level
|
@@ -1,6 +1,5 @@
|
|
1
1
|
<style>
|
2
2
|
.Polaris-Button {
|
3
|
-
fill:#637381;
|
4
3
|
position:relative;
|
5
4
|
display:-webkit-inline-box;
|
6
5
|
display:-ms-inline-flexbox;
|
@@ -15,12 +14,14 @@
|
|
15
14
|
min-width:3.6rem;
|
16
15
|
margin:0;
|
17
16
|
padding:0.7rem 1.6rem;
|
18
|
-
background
|
19
|
-
border:1px solid #
|
20
|
-
|
21
|
-
border-
|
17
|
+
background-color:#ffffff;
|
18
|
+
border:1px solid #babfc3;
|
19
|
+
border-top-color: #c9cccf;
|
20
|
+
border-bottom-color: #babfc4;
|
21
|
+
box-shadow:0 1px 0 0 rgba(0, 0, 0, 0.05);
|
22
|
+
border-radius:4px;
|
22
23
|
line-height:1;
|
23
|
-
color:#
|
24
|
+
color:#202223;
|
24
25
|
text-align:center;
|
25
26
|
cursor:pointer;
|
26
27
|
-webkit-user-select:none;
|
@@ -29,30 +30,44 @@
|
|
29
30
|
user-select:none;
|
30
31
|
text-decoration:none;
|
31
32
|
transition-property:background, border, box-shadow;
|
32
|
-
transition-duration:
|
33
|
+
transition-duration:100ms;
|
33
34
|
transition-timing-function:cubic-bezier(0.64, 0, 0.35, 1);
|
34
35
|
}
|
35
36
|
|
36
37
|
.Polaris-Button:hover {
|
37
|
-
background
|
38
|
-
border-color:#c4cdd5;
|
38
|
+
background-color:#f6f6f7;
|
39
39
|
}
|
40
40
|
|
41
41
|
.Polaris-Button:focus {
|
42
|
-
border-color:#5c6ac4;
|
43
42
|
outline:0;
|
44
|
-
|
43
|
+
}
|
44
|
+
|
45
|
+
.Polaris-Button:focus:after {
|
46
|
+
box-shadow:0 0 0 .2rem #448fff;
|
47
|
+
}
|
48
|
+
|
49
|
+
.Polaris-Button:after {
|
50
|
+
content:'';
|
51
|
+
position:absolute;
|
52
|
+
z-index:1;
|
53
|
+
top:-.2rem;
|
54
|
+
right:-.2rem;
|
55
|
+
bottom:-.2rem;
|
56
|
+
left:-.2rem;
|
57
|
+
display:block;
|
58
|
+
pointer-events:none;
|
59
|
+
box-shadow:0 0 0 -.2rem #448fff;
|
60
|
+
transition:box-shadow 100ms cubic-bezier(0.64, 0, 0.35, 1);
|
61
|
+
border-radius:5px;
|
45
62
|
}
|
46
63
|
|
47
64
|
.Polaris-Button:active {
|
48
|
-
background
|
49
|
-
border-color:#c4cdd5;
|
50
|
-
box-shadow:0 0 0 0 transparent, inset 0 1px 1px 0 rgba(99, 115, 129, 0.1), inset 0 1px 4px 0 rgba(99, 115, 129, 0.2);
|
65
|
+
background-color:#f1f2f3);
|
51
66
|
}
|
52
67
|
|
53
68
|
.Polaris-Button__Content {
|
54
|
-
font-size:1.
|
55
|
-
font-weight:
|
69
|
+
font-size:1.4rem;
|
70
|
+
font-weight:500;
|
56
71
|
line-height:1.6rem;
|
57
72
|
text-transform:initial;
|
58
73
|
letter-spacing:initial;
|
@@ -70,35 +85,25 @@
|
|
70
85
|
min-height:1px;
|
71
86
|
}
|
72
87
|
|
73
|
-
@media (min-width: 40em) {
|
74
|
-
.Polaris-Button__Content {
|
75
|
-
font-size:1.4rem;
|
76
|
-
}
|
77
|
-
}
|
78
|
-
|
79
88
|
.Polaris-Button--primary {
|
80
|
-
background
|
81
|
-
border-color
|
82
|
-
|
89
|
+
background-color:#008060;
|
90
|
+
border-color:transparent;
|
91
|
+
border-width:0;
|
83
92
|
color:white;
|
84
|
-
fill:white;
|
85
93
|
}
|
86
94
|
|
87
95
|
.Polaris-Button--primary:hover {
|
88
|
-
background
|
89
|
-
border-color
|
96
|
+
background-color:#006e52;
|
97
|
+
border-color:transparent;
|
90
98
|
color:white;
|
91
|
-
text-decoration:none;
|
92
99
|
}
|
93
100
|
|
94
|
-
.Polaris-Button--primary:
|
95
|
-
|
96
|
-
|
101
|
+
.Polaris-Button--primary:active {
|
102
|
+
background-color:#005e46;
|
103
|
+
border-color:transparent;
|
97
104
|
}
|
98
105
|
|
99
|
-
.Polaris-Button--
|
100
|
-
|
101
|
-
border-color:#38469b;
|
102
|
-
box-shadow:inset 0 0 0 0 transparent, 0 1px 0 0 rgba(22, 29, 37, 0.05), 0 0 1px 0 #38469b;
|
106
|
+
.Polaris-Button--sizeLarge {
|
107
|
+
padding:1.1rem 2.4rem;
|
103
108
|
}
|
104
109
|
</style>
|
@@ -11,7 +11,7 @@
|
|
11
11
|
|
12
12
|
@media (min-width: 30.625em) {
|
13
13
|
.Polaris-Card {
|
14
|
-
border-radius:
|
14
|
+
border-radius:8px;
|
15
15
|
}
|
16
16
|
}
|
17
17
|
|
@@ -24,10 +24,10 @@
|
|
24
24
|
}
|
25
25
|
|
26
26
|
.Polaris-Card__Section + .Polaris-Card__Section {
|
27
|
-
border-top
|
27
|
+
border-top:.1rem solid #e4e5e7;
|
28
28
|
}
|
29
29
|
|
30
30
|
.Polaris-Card__Section--subdued {
|
31
|
-
background-color:#
|
31
|
+
background-color:#fafbfb;
|
32
32
|
}
|
33
33
|
</style>
|
@@ -11,8 +11,8 @@
|
|
11
11
|
-ms-flex-align:center;
|
12
12
|
align-items:center;
|
13
13
|
width:100%;
|
14
|
-
margin:
|
15
|
-
padding:2rem 0;
|
14
|
+
margin:0 auto;
|
15
|
+
padding:2rem 0 6rem;
|
16
16
|
max-width:99.8rem;
|
17
17
|
}
|
18
18
|
|
@@ -24,33 +24,22 @@
|
|
24
24
|
}
|
25
25
|
|
26
26
|
.Polaris-EmptyState__Section {
|
27
|
-
position:relative;
|
28
27
|
display:-webkit-box;
|
29
28
|
display:-ms-flexbox;
|
30
29
|
display:flex;
|
31
30
|
-webkit-box-orient:vertical;
|
32
|
-
-webkit-box-direction:
|
33
|
-
-ms-flex-direction:column;
|
34
|
-
flex-direction:column;
|
31
|
+
-webkit-box-direction:reverse;
|
32
|
+
-ms-flex-direction:column-reverse;
|
33
|
+
flex-direction:column-reverse;
|
35
34
|
-webkit-box-flex:1;
|
36
35
|
-ms-flex:1 1 auto;
|
37
36
|
flex:1 1 auto;
|
37
|
+
-webkit-box-align:center;
|
38
|
+
-ms-flex-align:center;
|
39
|
+
align-items:center;
|
38
40
|
width:100%;
|
39
41
|
}
|
40
42
|
|
41
|
-
@media (min-width: 46.5em) {
|
42
|
-
.Polaris-EmptyState__Section {
|
43
|
-
left:2rem;
|
44
|
-
-webkit-box-orient:horizontal;
|
45
|
-
-webkit-box-direction:normal;
|
46
|
-
-ms-flex-direction:row;
|
47
|
-
flex-direction:row;
|
48
|
-
-webkit-box-align:center;
|
49
|
-
-ms-flex-align:center;
|
50
|
-
align-items:center;
|
51
|
-
}
|
52
|
-
}
|
53
|
-
|
54
43
|
.Polaris-EmptyState__ImageContainer,
|
55
44
|
.Polaris-EmptyState__DetailsContainer {
|
56
45
|
-webkit-box-flex:1;
|
@@ -58,6 +47,7 @@
|
|
58
47
|
flex:1 1 auto;
|
59
48
|
padding:0;
|
60
49
|
margin:0;
|
50
|
+
text-align:center;
|
61
51
|
}
|
62
52
|
|
63
53
|
@media (min-width: 46.5em) {
|
@@ -68,37 +58,32 @@
|
|
68
58
|
}
|
69
59
|
}
|
70
60
|
|
71
|
-
@media (max-width: 30.625em) {
|
72
|
-
.Polaris-EmptyState__ImageContainer,
|
73
|
-
.Polaris-EmptyState__DetailsContainer {
|
74
|
-
overflow-x:hidden;
|
75
|
-
}
|
76
|
-
}
|
77
|
-
|
78
61
|
.Polaris-EmptyState__Details {
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
62
|
+
max-width:40rem;
|
63
|
+
display:-webkit-box;
|
64
|
+
display:-ms-flexbox;
|
65
|
+
display: flex;
|
66
|
+
-webkit-box-orient:vertical;
|
67
|
+
-webkit-box-direction:normal;
|
68
|
+
-ms-flex-direction:column;
|
69
|
+
flex-direction: column;
|
70
|
+
-webkit-box-align:center;
|
71
|
+
-ms-flex-align:center;
|
72
|
+
align-items: center;
|
89
73
|
}
|
90
74
|
|
91
75
|
.Polaris-EmptyState__Content {
|
92
|
-
|
76
|
+
margin-top: 1.6rem;
|
77
|
+
font-size:1.5rem;
|
93
78
|
font-weight:400;
|
94
|
-
line-height:
|
95
|
-
color:#
|
79
|
+
line-height:2rem;
|
80
|
+
color:#6d7175;
|
81
|
+
padding-bottom: .8rem;
|
96
82
|
}
|
97
83
|
|
98
84
|
@media (min-width: 40em) {
|
99
85
|
.Polaris-EmptyState__Content {
|
100
|
-
font-size:
|
101
|
-
line-height:2.8rem;
|
86
|
+
font-size:1.4rem;
|
102
87
|
}
|
103
88
|
}
|
104
89
|
|
@@ -107,23 +92,7 @@
|
|
107
92
|
}
|
108
93
|
|
109
94
|
.Polaris-EmptyState__Image {
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
@media (min-width: 30.625em) {
|
114
|
-
.Polaris-EmptyState__Image {
|
115
|
-
display: block;
|
116
|
-
margin-left:-60%;
|
117
|
-
margin-top:-30%;
|
118
|
-
width:200%;
|
119
|
-
}
|
120
|
-
}
|
121
|
-
|
122
|
-
@media (min-width: 46.5em) {
|
123
|
-
.Polaris-EmptyState__Image {
|
124
|
-
margin-top:0;
|
125
|
-
margin-left:-90%;
|
126
|
-
width:200%;
|
127
|
-
}
|
95
|
+
margin: 0;
|
96
|
+
width: auto;
|
128
97
|
}
|
129
98
|
</style>
|
@@ -0,0 +1,56 @@
|
|
1
|
+
<style>
|
2
|
+
.Polaris-Label {
|
3
|
+
margin-bottom:.4rem;
|
4
|
+
}
|
5
|
+
|
6
|
+
.Polaris-Label__Text {
|
7
|
+
-webkit-tap-highlight-color:transparent;
|
8
|
+
}
|
9
|
+
|
10
|
+
.Polaris-TextField {
|
11
|
+
position:relative;
|
12
|
+
margin-bottom:1.6rem;
|
13
|
+
}
|
14
|
+
|
15
|
+
.Polaris-TextField--InlineError {
|
16
|
+
margin-bottom:.4rem;
|
17
|
+
}
|
18
|
+
|
19
|
+
.Polaris-TextField__Input {
|
20
|
+
width:100%;
|
21
|
+
padding:.5rem 1.2rem;
|
22
|
+
border:1px solid #c9cccf;
|
23
|
+
border-top-color:#aeb4b9;
|
24
|
+
border-radius:4px;
|
25
|
+
box-shadow:none;
|
26
|
+
line-height:2.4rem;
|
27
|
+
}
|
28
|
+
|
29
|
+
.Polaris-TextField__Input:focus {
|
30
|
+
outline:none;
|
31
|
+
}
|
32
|
+
|
33
|
+
.Polaris-TextField__Backdrop:after {
|
34
|
+
content:'';
|
35
|
+
position:absolute;
|
36
|
+
z-index:1;
|
37
|
+
top:-.2rem;
|
38
|
+
right:-.2rem;
|
39
|
+
bottom:-.2rem;
|
40
|
+
left:-.2rem;
|
41
|
+
display:block;
|
42
|
+
pointer-events:none;
|
43
|
+
box-shadow:0 0 0 -.2rem #448fff;
|
44
|
+
transition:box-shadow .1s cubic-bezier(0.64, 0, 0.35, 1);
|
45
|
+
border-radius:5px;
|
46
|
+
}
|
47
|
+
|
48
|
+
.Polaris-TextField__Input:focus~.Polaris-TextField__Backdrop:after {
|
49
|
+
box-shadow:0 0 0 .2rem #448fff;
|
50
|
+
}
|
51
|
+
|
52
|
+
.Polaris-InlineError {
|
53
|
+
color:#d72c0d;
|
54
|
+
margin-bottom:1.6rem;
|
55
|
+
}
|
56
|
+
</style>
|