shopify_app 9.0.0 → 12.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -2
  3. data/CHANGELOG.md +145 -0
  4. data/README.md +180 -126
  5. data/app/assets/javascripts/shopify_app/itp_helper.js +6 -6
  6. data/app/assets/javascripts/shopify_app/storage_access.js +36 -7
  7. data/app/controllers/concerns/shopify_app/authenticated.rb +1 -1
  8. data/app/controllers/shopify_app/callback_controller.rb +14 -5
  9. data/app/controllers/shopify_app/extension_verification_controller.rb +20 -0
  10. data/app/controllers/shopify_app/sessions_controller.rb +44 -18
  11. data/app/views/shopify_app/sessions/enable_cookies.html.erb +3 -1
  12. data/app/views/shopify_app/sessions/request_storage_access.html.erb +2 -1
  13. data/app/views/shopify_app/sessions/top_level_interaction.html.erb +1 -0
  14. data/app/views/shopify_app/shared/redirect.html.erb +1 -0
  15. data/config/locales/cs.yml +23 -0
  16. data/config/locales/da.yml +20 -0
  17. data/config/locales/de.yml +5 -5
  18. data/config/locales/en.yml +1 -1
  19. data/config/locales/es.yml +3 -3
  20. data/config/locales/fi.yml +20 -0
  21. data/config/locales/fr.yml +3 -3
  22. data/config/locales/hi.yml +23 -0
  23. data/config/locales/it.yml +2 -3
  24. data/config/locales/ja.yml +1 -1
  25. data/config/locales/ko.yml +19 -0
  26. data/config/locales/ms.yml +22 -0
  27. data/config/locales/nb.yml +21 -0
  28. data/config/locales/nl.yml +3 -3
  29. data/config/locales/pl.yml +21 -0
  30. data/config/locales/pt-BR.yml +9 -10
  31. data/config/locales/pt-PT.yml +22 -0
  32. data/config/locales/sv.yml +21 -0
  33. data/config/locales/th.yml +20 -0
  34. data/config/locales/tr.yml +22 -0
  35. data/config/locales/zh-CN.yml +3 -3
  36. data/config/locales/zh-TW.yml +1 -2
  37. data/docs/Quickstart.md +44 -16
  38. data/docs/Releasing.md +0 -1
  39. data/docs/install-on-dev-shop.png +0 -0
  40. data/docs/test-your-app.png +0 -0
  41. data/karma.conf.js +1 -0
  42. data/lib/generators/shopify_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb +2 -2
  43. data/lib/generators/shopify_app/add_marketing_activity_extension/add_marketing_activity_extension_generator.rb +39 -0
  44. data/lib/generators/shopify_app/add_marketing_activity_extension/templates/marketing_activities_controller.rb +62 -0
  45. data/lib/generators/shopify_app/home_controller/home_controller_generator.rb +0 -6
  46. data/lib/generators/shopify_app/install/install_generator.rb +27 -11
  47. data/lib/generators/shopify_app/install/templates/_flash_messages.html.erb +1 -17
  48. data/lib/generators/shopify_app/install/templates/embedded_app.html.erb +11 -10
  49. data/lib/generators/shopify_app/install/templates/flash_messages.js +26 -0
  50. data/lib/generators/shopify_app/install/templates/shopify_app.js +15 -0
  51. data/lib/generators/shopify_app/install/templates/shopify_app.rb +6 -3
  52. data/lib/generators/shopify_app/install/templates/shopify_app_index.js +2 -0
  53. data/lib/generators/shopify_app/install/templates/shopify_provider.rb +1 -0
  54. data/lib/generators/shopify_app/install/templates/user_agent.rb +5 -0
  55. data/lib/generators/shopify_app/user_model/templates/db/migrate/create_users.erb +16 -0
  56. data/lib/generators/shopify_app/user_model/templates/user.rb +7 -0
  57. data/lib/generators/shopify_app/user_model/templates/users.yml +4 -0
  58. data/lib/generators/shopify_app/user_model/user_model_generator.rb +38 -0
  59. data/lib/shopify_app.rb +46 -29
  60. data/lib/shopify_app/configuration.rb +24 -9
  61. data/lib/shopify_app/controller_concerns/login_protection.rb +53 -7
  62. data/lib/shopify_app/engine.rb +4 -0
  63. data/lib/shopify_app/managers/webhooks_manager.rb +1 -1
  64. data/lib/shopify_app/middleware/same_site_cookie_middleware.rb +33 -0
  65. data/lib/shopify_app/session/in_memory_session_store.rb +1 -1
  66. data/lib/shopify_app/session/session_repository.rb +2 -2
  67. data/lib/shopify_app/session/session_storage.rb +10 -22
  68. data/lib/shopify_app/session/storage_strategies/shop_storage_strategy.rb +23 -0
  69. data/lib/shopify_app/session/storage_strategies/user_storage_strategy.rb +24 -0
  70. data/lib/shopify_app/utils.rb +7 -0
  71. data/lib/shopify_app/version.rb +1 -1
  72. data/package-lock.json +7212 -11
  73. data/package.json +9 -9
  74. data/service.yml +1 -1
  75. data/shopify_app.gemspec +10 -5
  76. data/translation.yml +1 -1
  77. data/yarn.lock +2555 -1886
  78. metadata +115 -19
  79. data/lib/generators/shopify_app/home_controller/templates/shopify_app_ready_script.html.erb +0 -7
@@ -4,31 +4,31 @@
4
4
  this.itpAction = document.getElementById('TopLevelInteractionButton');
5
5
  this.redirectUrl = opts.redirectUrl;
6
6
  }
7
-
7
+
8
8
  ITPHelper.prototype.redirect = function() {
9
9
  sessionStorage.setItem('shopify.top_level_interaction', true);
10
10
  window.location.href = this.redirectUrl;
11
11
  }
12
-
12
+
13
13
  ITPHelper.prototype.userAgentIsAffected = function() {
14
14
  return Boolean(document.hasStorageAccess);
15
15
  }
16
-
16
+
17
17
  ITPHelper.prototype.canPartitionCookies = function() {
18
18
  var versionRegEx = /Version\/12\.0\.?\d? Safari/;
19
19
  return versionRegEx.test(navigator.userAgent);
20
20
  }
21
-
21
+
22
22
  ITPHelper.prototype.setUpContent = function(onClick) {
23
23
  this.itpContent.style.display = 'block';
24
24
  this.itpAction.addEventListener('click', this.redirect.bind(this));
25
25
  }
26
-
26
+
27
27
  ITPHelper.prototype.execute = function() {
28
28
  if (!this.itpContent) {
29
29
  return;
30
30
  }
31
-
31
+
32
32
  if (this.userAgentIsAffected()) {
33
33
  this.setUpContent();
34
34
  } else {
@@ -28,18 +28,47 @@
28
28
  window.parent.location.href = this.redirectData.myshopifyUrl + '/admin/apps';
29
29
  }
30
30
 
31
- StorageAccessHelper.prototype.redirectToAppHome = function() {
32
- window.location.href = this.redirectData.appHomeUrl;
31
+ StorageAccessHelper.prototype.redirectToAppTargetUrl = function() {
32
+ window.location.href = this.redirectData.appTargetUrl;
33
+ }
34
+
35
+ StorageAccessHelper.prototype.sameSiteNoneIncompatible = function(ua) {
36
+ return ua.includes("iPhone OS 12_") || ua.includes("iPad; CPU OS 12_") || //iOS 12
37
+ (ua.includes("UCBrowser/")
38
+ ? this.isOlderUcBrowser(ua) //UC Browser < 12.13.2
39
+ : (ua.includes("Chrome/5") || ua.includes("Chrome/6"))) ||
40
+ ua.includes("Chromium/5") || ua.includes("Chromium/6") ||
41
+ (ua.includes(" OS X 10_14_") &&
42
+ ((ua.includes("Version/") && ua.includes("Safari")) || //Safari on MacOS 10.14
43
+ ua.endsWith("(KHTML, like Gecko)"))); //Web view on MacOS 10.14
44
+ }
45
+
46
+ StorageAccessHelper.prototype.isOlderUcBrowser = function(ua) {
47
+ var match = ua.match(/UCBrowser\/(\d+)\.(\d+)\.(\d+)\./);
48
+ if (!match) return false;
49
+ var major = parseInt(match[1]);
50
+ var minor = parseInt(match[2]);
51
+ var build = parseInt(match[3]);
52
+ if (major != 12) return major < 12;
53
+ if (minor != 13) return minor < 13;
54
+ return build < 2;
55
+ }
56
+
57
+ StorageAccessHelper.prototype.setCookie = function(value) {
58
+ if(!this.sameSiteNoneIncompatible(navigator.userAgent)) {
59
+ value += '; secure; SameSite=None'
60
+ }
61
+ document.cookie = value;
33
62
  }
34
63
 
35
64
  StorageAccessHelper.prototype.grantedStorageAccess = function() {
36
65
  try {
37
66
  sessionStorage.setItem('shopify.granted_storage_access', true);
38
- document.cookie = 'shopify.granted_storage_access=true';
67
+ this.setCookie('shopify.granted_storage_access=true');
39
68
  if (!document.cookie) {
40
69
  throw 'Cannot set third-party cookie.'
41
70
  }
42
- this.redirectToAppHome();
71
+ this.redirectToAppTargetUrl();
43
72
  } catch (error) {
44
73
  console.warn('Third party cookies may be blocked.', error);
45
74
  this.redirectToAppTLD(ACCESS_DENIED_STATUS);
@@ -61,7 +90,7 @@
61
90
  StorageAccessHelper.prototype.handleHasStorageAccess = function() {
62
91
  if (sessionStorage.getItem('shopify.granted_storage_access')) {
63
92
  // If app was classified by ITP and used Storage Access API to acquire access
64
- this.redirectToAppHome();
93
+ this.redirectToAppTargetUrl();
65
94
  } else {
66
95
  // If app has not been classified by ITP and still has storage access
67
96
  this.redirectToAppTLD(ACCESS_GRANTED_STATUS);
@@ -103,11 +132,11 @@
103
132
 
104
133
  /* ITP 2.0 solution: handles cookie partitioning */
105
134
  StorageAccessHelper.prototype.setUpHelper = function() {
106
- return new ITPHelper({redirectUrl: window.shopOrigin + "/admin/apps/" + window.apiKey});
135
+ return new ITPHelper({redirectUrl: window.shopOrigin + "/admin/apps/" + window.apiKey + window.returnTo});
107
136
  }
108
137
 
109
138
  StorageAccessHelper.prototype.setCookieAndRedirect = function() {
110
- document.cookie = "shopify.cookies_persist=true";
139
+ this.setCookie('shopify.cookies_persist=true');
111
140
  var helper = this.setUpHelper();
112
141
  helper.redirect();
113
142
  }
@@ -8,7 +8,7 @@ module ShopifyApp
8
8
  include ShopifyApp::Localization
9
9
  include ShopifyApp::LoginProtection
10
10
  include ShopifyApp::EmbeddedApp
11
- before_action :login_again_if_different_shop
11
+ before_action :login_again_if_different_user_or_shop
12
12
  around_action :shopify_session
13
13
  end
14
14
  end
@@ -15,7 +15,7 @@ module ShopifyApp
15
15
  redirect_to return_address
16
16
  else
17
17
  flash[:error] = I18n.t('could_not_log_in')
18
- redirect_to login_url
18
+ redirect_to(login_url_with_optional_shop)
19
19
  end
20
20
  end
21
21
 
@@ -55,10 +55,16 @@ module ShopifyApp
55
55
  token: token,
56
56
  api_version: ShopifyApp.configuration.api_version
57
57
  )
58
-
59
- session[:shopify] = ShopifyApp::SessionRepository.store(session_store)
58
+ session[:shopify] = ShopifyApp::SessionRepository.store(session_store, user: associated_user)
60
59
  session[:shopify_domain] = shop_name
61
60
  session[:shopify_user] = associated_user
61
+
62
+ if ShopifyApp.configuration.per_user_tokens?
63
+ # Adds the user_session to the session to determine if the logged in user has changed
64
+ user_session = auth_hash&.extra&.session
65
+ raise IndexError, "Missing user session signature" if user_session.nil?
66
+ session[:user_session] = user_session
67
+ end
62
68
  end
63
69
 
64
70
  def install_webhooks
@@ -86,10 +92,13 @@ module ShopifyApp
86
92
 
87
93
  return unless config && config[:job].present?
88
94
 
95
+ job = config[:job]
96
+ job = job.constantize if job.is_a?(String)
97
+
89
98
  if config[:inline] == true
90
- config[:job].perform_now(shop_domain: session[:shopify_domain])
99
+ job.perform_now(shop_domain: session[:shopify_domain])
91
100
  else
92
- config[:job].perform_later(shop_domain: session[:shopify_domain])
101
+ job.perform_later(shop_domain: session[:shopify_domain])
93
102
  end
94
103
  end
95
104
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShopifyApp
4
+ class ExtensionVerificationController < ActionController::Base
5
+ protect_from_forgery with: :null_session
6
+ before_action :verify_request
7
+
8
+ private
9
+
10
+ def verify_request
11
+ hmac_header = request.headers['HTTP_X_SHOPIFY_HMAC_SHA256']
12
+ request_body = request.body.read
13
+ secret = ShopifyApp.configuration.secret
14
+ digest = OpenSSL::Digest.new('sha256')
15
+
16
+ expected_hmac = Base64.strict_encode64(OpenSSL::HMAC.digest(digest, secret, request_body))
17
+ head(:unauthorized) unless ActiveSupport::SecurityUtils.secure_compare(expected_hmac, hmac_header)
18
+ end
19
+ end
20
+ end
@@ -20,16 +20,20 @@ module ShopifyApp
20
20
 
21
21
  render(:enable_cookies, layout: false, locals: {
22
22
  does_not_have_storage_access_url: top_level_interaction_path(
23
- shop: sanitized_shop_name
23
+ shop: sanitized_shop_name,
24
+ return_to: params[:return_to]
24
25
  ),
25
- has_storage_access_url: login_url(top_level: true),
26
- app_home_url: granted_storage_access_path(shop: sanitized_shop_name),
27
- current_shopify_domain: current_shopify_domain,
26
+ has_storage_access_url: login_url_with_optional_shop(top_level: true),
27
+ app_target_url: granted_storage_access_path(
28
+ shop: sanitized_shop_name,
29
+ return_to: params[:return_to]
30
+ ),
31
+ current_shopify_domain: current_shopify_domain
28
32
  })
29
33
  end
30
34
 
31
35
  def top_level_interaction
32
- @url = login_url(top_level: true)
36
+ @url = login_url_with_optional_shop(top_level: true)
33
37
  validate_shop
34
38
  end
35
39
 
@@ -38,14 +42,15 @@ module ShopifyApp
38
42
 
39
43
  session['shopify.granted_storage_access'] = true
40
44
 
41
- params = { shop: @shop }
42
- redirect_to "#{ShopifyApp.configuration.root_url}?#{params.to_query}"
45
+ copy_return_to_param_to_session
46
+
47
+ redirect_to(return_address_with_params({ shop: @shop }))
43
48
  end
44
49
 
45
50
  def destroy
46
51
  reset_session
47
52
  flash[:notice] = I18n.t('.logged_out')
48
- redirect_to login_url
53
+ redirect_to(login_url_with_optional_shop)
49
54
  end
50
55
 
51
56
  private
@@ -54,6 +59,8 @@ module ShopifyApp
54
59
  return render_invalid_shop_error unless sanitized_shop_name.present?
55
60
  session['shopify.omniauth_params'] = { shop: sanitized_shop_name }
56
61
 
62
+ copy_return_to_param_to_session
63
+
57
64
  if user_agent_can_partition_cookies
58
65
  authenticate_with_partitioning
59
66
  else
@@ -77,7 +84,7 @@ module ShopifyApp
77
84
  authenticate_in_context
78
85
  else
79
86
  set_top_level_oauth_cookie
80
- fullpage_redirect_to enable_cookies_path(shop: sanitized_shop_name)
87
+ enable_cookie_access
81
88
  end
82
89
  end
83
90
 
@@ -91,17 +98,28 @@ module ShopifyApp
91
98
  true
92
99
  end
93
100
 
101
+ def copy_return_to_param_to_session
102
+ session[:return_to] = params[:return_to] if params[:return_to]
103
+ end
104
+
94
105
  def render_invalid_shop_error
95
106
  flash[:error] = I18n.t('invalid_shop_url')
96
107
  redirect_to return_address
97
108
  end
98
109
 
110
+ def enable_cookie_access
111
+ fullpage_redirect_to(enable_cookies_path(
112
+ shop: sanitized_shop_name,
113
+ return_to: session[:return_to]
114
+ ))
115
+ end
116
+
99
117
  def authenticate_in_context
100
118
  redirect_to "#{main_app.root_path}auth/shopify"
101
119
  end
102
120
 
103
121
  def authenticate_at_top_level
104
- fullpage_redirect_to login_url(top_level: true)
122
+ fullpage_redirect_to(login_url_with_optional_shop(top_level: true))
105
123
  end
106
124
 
107
125
  def authenticate_in_context?
@@ -119,14 +137,22 @@ module ShopifyApp
119
137
  end
120
138
 
121
139
  def redirect_to_request_storage_access
122
- render :request_storage_access, layout: false, locals: {
123
- does_not_have_storage_access_url: top_level_interaction_path(
124
- shop: sanitized_shop_name
125
- ),
126
- has_storage_access_url: login_url(top_level: true),
127
- app_home_url: granted_storage_access_path(shop: sanitized_shop_name),
128
- current_shopify_domain: current_shopify_domain
129
- }
140
+ render(
141
+ :request_storage_access,
142
+ layout: false,
143
+ locals: {
144
+ does_not_have_storage_access_url: top_level_interaction_path(
145
+ shop: sanitized_shop_name,
146
+ return_to: session[:return_to]
147
+ ),
148
+ has_storage_access_url: login_url_with_optional_shop(top_level: true),
149
+ app_target_url: granted_storage_access_path(
150
+ shop: sanitized_shop_name,
151
+ return_to: session[:return_to]
152
+ ),
153
+ current_shopify_domain: current_shopify_domain
154
+ }
155
+ )
130
156
  end
131
157
  end
132
158
  end
@@ -2,6 +2,7 @@
2
2
  <html lang="<%= I18n.locale %>">
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
5
6
  <base target="_top">
6
7
  <title>Redirecting…</title>
7
8
  <%= render 'shopify_app/partials/layout_styles' %>
@@ -16,6 +17,7 @@
16
17
  <script>
17
18
  window.apiKey = "<%= ShopifyApp.configuration.api_key %>";
18
19
  window.shopOrigin = "https://<%= @shop %>";
20
+ window.returnTo = "<%= params[:return_to] %>"
19
21
  </script>
20
22
 
21
23
  <%= javascript_include_tag('shopify_app/enable_cookies', crossorigin: 'anonymous', integrity: true) %>
@@ -30,7 +32,7 @@
30
32
  myshopifyUrl: "https://#{current_shopify_domain}",
31
33
  hasStorageAccessUrl: "#{has_storage_access_url}",
32
34
  doesNotHaveStorageAccessUrl: "#{does_not_have_storage_access_url}",
33
- appHomeUrl: "#{app_home_url}"
35
+ appTargetUrl: "#{app_target_url}"
34
36
  },
35
37
  },
36
38
  )
@@ -2,6 +2,7 @@
2
2
  <html lang="<%= I18n.locale %>">
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
5
6
  <base target="_top">
6
7
  <title>Redirecting…</title>
7
8
  <%= render 'shopify_app/partials/layout_styles' %>
@@ -23,7 +24,7 @@
23
24
  myshopifyUrl: "https://#{current_shopify_domain}",
24
25
  hasStorageAccessUrl: "#{has_storage_access_url}",
25
26
  doesNotHaveStorageAccessUrl: "#{does_not_have_storage_access_url}",
26
- appHomeUrl: "#{app_home_url}"
27
+ appTargetUrl: "#{app_target_url}"
27
28
  },
28
29
  },
29
30
  )
@@ -2,6 +2,7 @@
2
2
  <html lang="<%= I18n.locale %>">
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
5
6
  <base target="_top">
6
7
  <title>Redirecting…</title>
7
8
  <%= render 'shopify_app/partials/layout_styles' %>
@@ -2,6 +2,7 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
5
6
  <base target="_top">
6
7
  <title>Redirecting…</title>
7
8
  <%= javascript_include_tag('shopify_app/redirect', crossorigin: 'anonymous', integrity: true) %>
@@ -0,0 +1,23 @@
1
+ ---
2
+ cs:
3
+ logged_out: Odhlášení proběhlo úspěšně
4
+ could_not_log_in: Nelze se přihlásit do obchodu Shopify
5
+ invalid_shop_url: Neplatná doména obchodu
6
+ enable_cookies_heading: Zapnout soubory cookie z aplikace %{app}
7
+ enable_cookies_body: Pokud chcete v Shopify používat aplikaci %{app}, musíte soubory
8
+ cookie v tomto prohlížeči povolit ručně.
9
+ enable_cookies_footer: Soubory cookie umožňují, aby vás aplikace ověřila pomocí
10
+ dočasného uchování preferencí a osobních údajů. Jejich platnost vyprší po 30 dnech.
11
+ enable_cookies_action: Povolit soubory cookie
12
+ top_level_interaction_heading: Váš prohlížeč potřebuje ověřit aplikaci %{app}
13
+ top_level_interaction_body: Váš prohlížeč vyžaduje, aby si od vás aplikace, jako
14
+ je %{app}, nejdřív vyžádaly přístup k souborům cookie, než je pro vás Shopify
15
+ otevře.
16
+ top_level_interaction_action: Pokračovat
17
+ request_storage_access_heading: Aplikace %{app} potřebuje získat přístup k souborům
18
+ cookie
19
+ request_storage_access_body: Tato aplikace vám umožní ověření prostřednictvím dočasného
20
+ uchování vašich osobních údajů. Pokud chcete používat tuto aplikaci, klikněte
21
+ na tlačítko Pokračovat a povolte soubory cookie.
22
+ request_storage_access_footer: Platnost souborů cookie vyprší po 30 dnech.
23
+ request_storage_access_action: Pokračovat
@@ -0,0 +1,20 @@
1
+ ---
2
+ da:
3
+ logged_out: Logget ud
4
+ could_not_log_in: Kunne ikke logge ind på Shopify-butik
5
+ invalid_shop_url: Ugyldig butiksdomæne
6
+ enable_cookies_heading: Aktivér cookies fra %{app}
7
+ enable_cookies_body: Du skal manuelt aktivere cookies i denne browser for at kunne
8
+ bruge %{app} i Shopify.
9
+ enable_cookies_footer: Cookies lader appen godkende dig ved at gemme dine præferencer
10
+ og personlige oplysninger midlertidigt. De udløber efter 30 dage.
11
+ enable_cookies_action: Aktivér cookies
12
+ top_level_interaction_heading: Din browser skal godkende %{app}
13
+ top_level_interaction_body: Din browser kræver, at apps som f.eks. %{app} spørger
14
+ dig om adgang til cookies, inden Shopify kan åbne den for dig.
15
+ top_level_interaction_action: Fortsæt
16
+ request_storage_access_heading: "%{app} skal have adgang til cookies"
17
+ request_storage_access_body: Det lader appen godkende dig ved at gemme dine personlige
18
+ oplysninger midlertidigt. Klik på forsæt, og tillad cookies for at bruge appen.
19
+ request_storage_access_footer: Cookies udløber efter 30 dage.
20
+ request_storage_access_action: Fortsæt
@@ -7,16 +7,16 @@ de:
7
7
  enable_cookies_body: Sie müssen Cookies in diesem Browser manuell aktivieren, um
8
8
  %{app} in Shopify verwenden zu können.
9
9
  enable_cookies_footer: Mithilfe von Cookies kann die App Sie authentifizieren, indem
10
- Ihre Einstellungen und persönlichen Informationen vorübergehend gespeichert werden.
10
+ Ihre Einstellungen und personenbezogenen Daten vorübergehend gespeichert werden.
11
11
  Sie laufen nach 30 Tagen ab.
12
12
  enable_cookies_action: Cookies aktivieren
13
13
  top_level_interaction_heading: Ihr Browser muss %{app} authentifizieren
14
- top_level_interaction_body: Ihr Browser verlangt, dass Apps von Drittanbietern wie
15
- %{app} Sie um Zugriff auf Cookies bitten, bevor Shopify sie für Sie öffnen kann.
14
+ top_level_interaction_body: Ihr Browser verlangt, dass Apps wie %{app} Sie um Zugriff
15
+ auf Cookies bitten, bevor Shopify sie für Sie öffnen kann.
16
16
  top_level_interaction_action: Weiter
17
17
  request_storage_access_heading: "%{app} braucht Zugriff auf Cookies"
18
18
  request_storage_access_body: Damit kann die App Sie authentifizieren, indem Ihre
19
- Einstellungen und persönlichen Informationen vorübergehend gespeichert werden.
20
- Klicken Sie auf "Weiter" und erlauben Sie den Cookies, die App zu verwenden.
19
+ Einstellungen und personenbezogenen Daten vorübergehend gespeichert werden. Klicken
20
+ Sie auf "Weiter" und erlauben Sie den Cookies, die App zu verwenden.
21
21
  request_storage_access_footer: Cookies laufen nach 30 Tagen ab.
22
22
  request_storage_access_action: Weiter
@@ -7,7 +7,7 @@ en:
7
7
  enable_cookies_footer: 'Cookies let the app authenticate you by temporarily storing your preferences and personal information. They expire after 30 days.'
8
8
  enable_cookies_action: 'Enable cookies'
9
9
  top_level_interaction_heading: "Your browser needs to authenticate %{app}"
10
- top_level_interaction_body: "Your browser requires third-party apps like %{app} to ask you for access to cookies before Shopify can open it for you."
10
+ top_level_interaction_body: "Your browser requires apps like %{app} to ask you for access to cookies before Shopify can open it for you."
11
11
  top_level_interaction_action: 'Continue'
12
12
  request_storage_access_heading: "%{app} needs access to cookies"
13
13
  request_storage_access_body: "This lets the app authenticate you by temporarily storing your personal information. Click continue and allow cookies to use the app."