shopify_app 13.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/.babelrc +5 -0
  3. data/.github/CODEOWNERS +1 -0
  4. data/.github/ISSUE_TEMPLATE.md +14 -0
  5. data/.github/PULL_REQUEST_TEMPLATE.md +6 -0
  6. data/.github/probots.yml +2 -0
  7. data/.github/workflows/rubocop.yml +28 -0
  8. data/.gitignore +16 -0
  9. data/.nvmrc +1 -0
  10. data/.rubocop.yml +17 -0
  11. data/.ruby-version +1 -0
  12. data/.travis.yml +28 -0
  13. data/CHANGELOG.md +505 -0
  14. data/Gemfile +11 -0
  15. data/LICENSE +19 -0
  16. data/README.md +620 -0
  17. data/Rakefile +7 -0
  18. data/SECURITY.md +59 -0
  19. data/app/assets/images/storage_access.svg +2 -0
  20. data/app/assets/javascripts/shopify_app/enable_cookies.js +3 -0
  21. data/app/assets/javascripts/shopify_app/itp_helper.js +40 -0
  22. data/app/assets/javascripts/shopify_app/partition_cookies.js +8 -0
  23. data/app/assets/javascripts/shopify_app/redirect.js +33 -0
  24. data/app/assets/javascripts/shopify_app/request_storage_access.js +3 -0
  25. data/app/assets/javascripts/shopify_app/storage_access.js +153 -0
  26. data/app/assets/javascripts/shopify_app/storage_access_redirect.js +17 -0
  27. data/app/assets/javascripts/shopify_app/top_level.js +2 -0
  28. data/app/assets/javascripts/shopify_app/top_level_interaction.js +11 -0
  29. data/app/controllers/concerns/shopify_app/authenticated.rb +16 -0
  30. data/app/controllers/concerns/shopify_app/require_known_shop.rb +39 -0
  31. data/app/controllers/shopify_app/authenticated_controller.rb +8 -0
  32. data/app/controllers/shopify_app/callback_controller.rb +140 -0
  33. data/app/controllers/shopify_app/extension_verification_controller.rb +15 -0
  34. data/app/controllers/shopify_app/sessions_controller.rb +184 -0
  35. data/app/controllers/shopify_app/webhooks_controller.rb +37 -0
  36. data/app/views/shopify_app/partials/_button_styles.html.erb +104 -0
  37. data/app/views/shopify_app/partials/_card_styles.html.erb +33 -0
  38. data/app/views/shopify_app/partials/_empty_state_styles.html.erb +129 -0
  39. data/app/views/shopify_app/partials/_layout_styles.html.erb +167 -0
  40. data/app/views/shopify_app/partials/_typography_styles.html.erb +35 -0
  41. data/app/views/shopify_app/sessions/enable_cookies.html.erb +75 -0
  42. data/app/views/shopify_app/sessions/new.html.erb +123 -0
  43. data/app/views/shopify_app/sessions/request_storage_access.html.erb +68 -0
  44. data/app/views/shopify_app/sessions/top_level_interaction.html.erb +64 -0
  45. data/app/views/shopify_app/shared/redirect.html.erb +23 -0
  46. data/config/locales/cs.yml +23 -0
  47. data/config/locales/da.yml +20 -0
  48. data/config/locales/de.yml +22 -0
  49. data/config/locales/en.yml +15 -0
  50. data/config/locales/es.yml +22 -0
  51. data/config/locales/fi.yml +20 -0
  52. data/config/locales/fr.yml +23 -0
  53. data/config/locales/hi.yml +23 -0
  54. data/config/locales/it.yml +21 -0
  55. data/config/locales/ja.yml +17 -0
  56. data/config/locales/ko.yml +19 -0
  57. data/config/locales/ms.yml +22 -0
  58. data/config/locales/nb.yml +21 -0
  59. data/config/locales/nl.yml +21 -0
  60. data/config/locales/pl.yml +21 -0
  61. data/config/locales/pt-BR.yml +21 -0
  62. data/config/locales/pt-PT.yml +22 -0
  63. data/config/locales/sv.yml +21 -0
  64. data/config/locales/th.yml +20 -0
  65. data/config/locales/tr.yml +22 -0
  66. data/config/locales/zh-CN.yml +16 -0
  67. data/config/locales/zh-TW.yml +16 -0
  68. data/config/routes.rb +23 -0
  69. data/docs/Quickstart.md +93 -0
  70. data/docs/Releasing.md +18 -0
  71. data/docs/Troubleshooting.md +16 -0
  72. data/docs/install-on-dev-shop.png +0 -0
  73. data/docs/test-your-app.png +0 -0
  74. data/images/app-proxy-screenshot.png +0 -0
  75. data/karma.conf.js +44 -0
  76. data/lib/generators/shopify_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb +47 -0
  77. data/lib/generators/shopify_app/add_after_authenticate_job/templates/after_authenticate_job.rb +11 -0
  78. data/lib/generators/shopify_app/add_marketing_activity_extension/add_marketing_activity_extension_generator.rb +40 -0
  79. data/lib/generators/shopify_app/add_marketing_activity_extension/templates/marketing_activities_controller.rb +62 -0
  80. data/lib/generators/shopify_app/add_webhook/add_webhook_generator.rb +69 -0
  81. data/lib/generators/shopify_app/add_webhook/templates/webhook_job.rb.tt +13 -0
  82. data/lib/generators/shopify_app/app_proxy_controller/app_proxy_controller_generator.rb +26 -0
  83. data/lib/generators/shopify_app/app_proxy_controller/templates/app_proxy_controller.rb +8 -0
  84. data/lib/generators/shopify_app/app_proxy_controller/templates/app_proxy_route.rb +11 -0
  85. data/lib/generators/shopify_app/app_proxy_controller/templates/index.html.erb +19 -0
  86. data/lib/generators/shopify_app/authenticated_controller/authenticated_controller_generator.rb +15 -0
  87. data/lib/generators/shopify_app/authenticated_controller/templates/authenticated_controller.rb +5 -0
  88. data/lib/generators/shopify_app/controllers/controllers_generator.rb +30 -0
  89. data/lib/generators/shopify_app/home_controller/home_controller_generator.rb +26 -0
  90. data/lib/generators/shopify_app/home_controller/templates/home_controller.rb +8 -0
  91. data/lib/generators/shopify_app/home_controller/templates/index.html.erb +21 -0
  92. data/lib/generators/shopify_app/install/install_generator.rb +83 -0
  93. data/lib/generators/shopify_app/install/templates/_flash_messages.html.erb +3 -0
  94. data/lib/generators/shopify_app/install/templates/embedded_app.html.erb +41 -0
  95. data/lib/generators/shopify_app/install/templates/flash_messages.js +24 -0
  96. data/lib/generators/shopify_app/install/templates/omniauth.rb +3 -0
  97. data/lib/generators/shopify_app/install/templates/session_store.rb +4 -0
  98. data/lib/generators/shopify_app/install/templates/shopify_app.js +15 -0
  99. data/lib/generators/shopify_app/install/templates/shopify_app.rb.tt +15 -0
  100. data/lib/generators/shopify_app/install/templates/shopify_app_index.js +2 -0
  101. data/lib/generators/shopify_app/install/templates/shopify_provider.rb +20 -0
  102. data/lib/generators/shopify_app/install/templates/user_agent.rb +6 -0
  103. data/lib/generators/shopify_app/rotate_shopify_token_job/rotate_shopify_token_job_generator.rb +16 -0
  104. data/lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token.rake +17 -0
  105. data/lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token_job.rb +42 -0
  106. data/lib/generators/shopify_app/routes/routes_generator.rb +32 -0
  107. data/lib/generators/shopify_app/routes/templates/routes.rb +12 -0
  108. data/lib/generators/shopify_app/shop_model/shop_model_generator.rb +43 -0
  109. data/lib/generators/shopify_app/shop_model/templates/db/migrate/create_shops.erb +15 -0
  110. data/lib/generators/shopify_app/shop_model/templates/shop.rb +8 -0
  111. data/lib/generators/shopify_app/shop_model/templates/shops.yml +3 -0
  112. data/lib/generators/shopify_app/shopify_app_generator.rb +18 -0
  113. data/lib/generators/shopify_app/user_model/templates/db/migrate/create_users.erb +16 -0
  114. data/lib/generators/shopify_app/user_model/templates/user.rb +8 -0
  115. data/lib/generators/shopify_app/user_model/templates/users.yml +4 -0
  116. data/lib/generators/shopify_app/user_model/user_model_generator.rb +43 -0
  117. data/lib/generators/shopify_app/views/views_generator.rb +30 -0
  118. data/lib/shopify_app.rb +61 -0
  119. data/lib/shopify_app/configuration.rb +94 -0
  120. data/lib/shopify_app/controller_concerns/app_proxy_verification.rb +38 -0
  121. data/lib/shopify_app/controller_concerns/csrf_protection.rb +15 -0
  122. data/lib/shopify_app/controller_concerns/embedded_app.rb +20 -0
  123. data/lib/shopify_app/controller_concerns/itp.rb +45 -0
  124. data/lib/shopify_app/controller_concerns/localization.rb +23 -0
  125. data/lib/shopify_app/controller_concerns/login_protection.rb +231 -0
  126. data/lib/shopify_app/controller_concerns/payload_verification.rb +24 -0
  127. data/lib/shopify_app/controller_concerns/webhook_verification.rb +23 -0
  128. data/lib/shopify_app/engine.rb +25 -0
  129. data/lib/shopify_app/jobs/scripttags_manager_job.rb +16 -0
  130. data/lib/shopify_app/jobs/webhooks_manager_job.rb +16 -0
  131. data/lib/shopify_app/managers/scripttags_manager.rb +78 -0
  132. data/lib/shopify_app/managers/webhooks_manager.rb +62 -0
  133. data/lib/shopify_app/middleware/jwt_middleware.rb +42 -0
  134. data/lib/shopify_app/middleware/same_site_cookie_middleware.rb +34 -0
  135. data/lib/shopify_app/session/in_memory_session_store.rb +31 -0
  136. data/lib/shopify_app/session/in_memory_shop_session_store.rb +14 -0
  137. data/lib/shopify_app/session/in_memory_user_session_store.rb +14 -0
  138. data/lib/shopify_app/session/jwt.rb +61 -0
  139. data/lib/shopify_app/session/null_user_session_store.rb +22 -0
  140. data/lib/shopify_app/session/session_repository.rb +56 -0
  141. data/lib/shopify_app/session/session_storage.rb +20 -0
  142. data/lib/shopify_app/session/shop_session_storage.rb +42 -0
  143. data/lib/shopify_app/session/user_session_storage.rb +42 -0
  144. data/lib/shopify_app/test_helpers/all.rb +2 -0
  145. data/lib/shopify_app/test_helpers/webhook_verification_helper.rb +17 -0
  146. data/lib/shopify_app/utils.rb +24 -0
  147. data/lib/shopify_app/version.rb +4 -0
  148. data/package-lock.json +7177 -0
  149. data/package.json +28 -0
  150. data/service.yml +7 -0
  151. data/shipit.rubygems.yml +4 -0
  152. data/shopify_app.gemspec +37 -0
  153. data/translation.yml +7 -0
  154. data/webpack.config.js +24 -0
  155. data/yarn.lock +5263 -0
  156. metadata +420 -0
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+ module ShopifyApp
3
+ module AppProxyVerification
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ skip_before_action :verify_authenticity_token, raise: false
7
+ before_action :verify_proxy_request
8
+ end
9
+
10
+ def verify_proxy_request
11
+ return head(:forbidden) unless query_string_valid?(request.query_string)
12
+ end
13
+
14
+ private
15
+
16
+ def query_string_valid?(query_string)
17
+ query_hash = Rack::Utils.parse_query(query_string)
18
+
19
+ signature = query_hash.delete('signature')
20
+ return false if signature.nil?
21
+
22
+ ActiveSupport::SecurityUtils.secure_compare(
23
+ calculated_signature(query_hash),
24
+ signature
25
+ )
26
+ end
27
+
28
+ def calculated_signature(query_hash_without_signature)
29
+ sorted_params = query_hash_without_signature.collect { |k, v| "#{k}=#{Array(v).join(',')}" }.sort.join
30
+
31
+ OpenSSL::HMAC.hexdigest(
32
+ OpenSSL::Digest.new('sha256'),
33
+ ShopifyApp.configuration.secret,
34
+ sorted_params
35
+ )
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module ShopifyApp
3
+ module CsrfProtection
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ protect_from_forgery with: :exception, unless: :valid_session_token?
7
+ end
8
+
9
+ private
10
+
11
+ def valid_session_token?
12
+ request.env['jwt.shopify_domain']
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ module ShopifyApp
3
+ module EmbeddedApp
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ if ShopifyApp.configuration.embedded_app?
8
+ after_action(:set_esdk_headers)
9
+ layout('embedded_app')
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def set_esdk_headers
16
+ response.set_header('P3P', 'CP="Not used"')
17
+ response.headers.except!('X-Frame-Options')
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShopifyApp
4
+ # Cookie management helpers required for ITP implementation
5
+ module Itp
6
+ private
7
+
8
+ def set_test_cookie
9
+ return unless ShopifyApp.configuration.embedded_app?
10
+ return unless user_agent_can_partition_cookies
11
+
12
+ session['shopify.cookies_persist'] = true
13
+ end
14
+
15
+ def set_top_level_oauth_cookie
16
+ session['shopify.top_level_oauth'] = true
17
+ end
18
+
19
+ def clear_top_level_oauth_cookie
20
+ session.delete('shopify.top_level_oauth')
21
+ end
22
+
23
+ def user_agent_is_mobile
24
+ user_agent = BrowserSniffer.new(request.user_agent).browser_info
25
+
26
+ user_agent[:name].to_s.match(/Shopify\sMobile/)
27
+ end
28
+
29
+ def user_agent_is_pos
30
+ user_agent = BrowserSniffer.new(request.user_agent).browser_info
31
+
32
+ user_agent[:name].to_s.match(/Shopify\sPOS/)
33
+ end
34
+
35
+ def user_agent_can_partition_cookies
36
+ user_agent = BrowserSniffer.new(request.user_agent).browser_info
37
+
38
+ is_safari = user_agent[:name].to_s.match(/Safari/)
39
+
40
+ return false unless is_safari
41
+
42
+ user_agent[:version].to_s.match(/12\.0/)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ module ShopifyApp
3
+ module Localization
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before_action :set_locale
8
+ end
9
+
10
+ private
11
+
12
+ def set_locale
13
+ if params[:locale]
14
+ session[:locale] = params[:locale]
15
+ else
16
+ session[:locale] ||= I18n.default_locale
17
+ end
18
+ I18n.locale = session[:locale]
19
+ rescue I18n::InvalidLocale
20
+ I18n.locale = I18n.default_locale
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,231 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'browser_sniffer'
4
+
5
+ module ShopifyApp
6
+ module LoginProtection
7
+ extend ActiveSupport::Concern
8
+ include ShopifyApp::Itp
9
+
10
+ class ShopifyDomainNotFound < StandardError; end
11
+
12
+ included do
13
+ after_action :set_test_cookie
14
+ rescue_from ActiveResource::UnauthorizedAccess, with: :close_session
15
+ end
16
+
17
+ ACCESS_TOKEN_REQUIRED_HEADER = 'X-Shopify-API-Request-Failure-Unauthorized'
18
+
19
+ def activate_shopify_session
20
+ return redirect_to_login if current_shopify_session.blank?
21
+ clear_top_level_oauth_cookie
22
+
23
+ begin
24
+ ShopifyAPI::Base.activate_session(current_shopify_session)
25
+ yield
26
+ ensure
27
+ ShopifyAPI::Base.clear_session
28
+ end
29
+ end
30
+
31
+ def current_shopify_session
32
+ @current_shopify_session ||= begin
33
+ user_session || shop_session
34
+ end
35
+ end
36
+
37
+ def user_session
38
+ user_session_by_jwt || user_session_by_cookie
39
+ end
40
+
41
+ def user_session_by_jwt
42
+ return unless ShopifyApp.configuration.allow_jwt_authentication
43
+ return unless jwt_shopify_user_id
44
+ ShopifyApp::SessionRepository.retrieve_user_session_by_shopify_user_id(jwt_shopify_user_id)
45
+ end
46
+
47
+ def user_session_by_cookie
48
+ return unless session[:user_id].present?
49
+ ShopifyApp::SessionRepository.retrieve_user_session(session[:user_id])
50
+ end
51
+
52
+ def shop_session
53
+ shop_session_by_jwt || shop_session_by_cookie
54
+ end
55
+
56
+ def shop_session_by_jwt
57
+ return unless ShopifyApp.configuration.allow_jwt_authentication
58
+ return unless jwt_shopify_domain
59
+ ShopifyApp::SessionRepository.retrieve_shop_session_by_shopify_domain(jwt_shopify_domain)
60
+ end
61
+
62
+ def shop_session_by_cookie
63
+ return unless session[:shop_id].present?
64
+ ShopifyApp::SessionRepository.retrieve_shop_session(session[:shop_id])
65
+ end
66
+
67
+ def login_again_if_different_user_or_shop
68
+ if session[:user_session].present? && params[:session].present? # session data was sent/stored correctly
69
+ clear_session = session[:user_session] != params[:session] # current user is different from stored user
70
+
71
+ end
72
+
73
+ if current_shopify_session &&
74
+ params[:shop] && params[:shop].is_a?(String) &&
75
+ (current_shopify_session.domain != params[:shop])
76
+ clear_session = true
77
+ end
78
+
79
+ if clear_session
80
+ clear_shopify_session
81
+ redirect_to_login
82
+ end
83
+ end
84
+
85
+ def signal_access_token_required
86
+ response.set_header(ACCESS_TOKEN_REQUIRED_HEADER, true)
87
+ end
88
+
89
+ protected
90
+
91
+ def jwt_shopify_domain
92
+ request.env['jwt.shopify_domain']
93
+ end
94
+
95
+ def jwt_shopify_user_id
96
+ request.env['jwt.shopify_user_id']
97
+ end
98
+
99
+ def redirect_to_login
100
+ if request.xhr?
101
+ head(:unauthorized)
102
+ else
103
+ if request.get?
104
+ path = request.path
105
+ query = sanitized_params.to_query
106
+ else
107
+ referer = URI(request.referer || "/")
108
+ path = referer.path
109
+ query = "#{referer.query}&#{sanitized_params.to_query}"
110
+ end
111
+ session[:return_to] = query.blank? ? path.to_s : "#{path}?#{query}"
112
+ redirect_to(login_url_with_optional_shop)
113
+ end
114
+ end
115
+
116
+ def close_session
117
+ clear_shopify_session
118
+ redirect_to(login_url_with_optional_shop)
119
+ end
120
+
121
+ def clear_shopify_session
122
+ session[:shop_id] = nil
123
+ session[:user_id] = nil
124
+ session[:shopify_domain] = nil
125
+ session[:shopify_user] = nil
126
+ session[:user_session] = nil
127
+ end
128
+
129
+ def login_url_with_optional_shop(top_level: false)
130
+ url = ShopifyApp.configuration.login_url
131
+
132
+ query_params = login_url_params(top_level: top_level)
133
+
134
+ url = "#{url}?#{query_params.to_query}" if query_params.present?
135
+ url
136
+ end
137
+
138
+ def login_url_params(top_level:)
139
+ query_params = {}
140
+ query_params[:shop] = sanitized_params[:shop] if params[:shop].present?
141
+
142
+ return_to = RedirectSafely.make_safe(session[:return_to] || params[:return_to], nil)
143
+
144
+ if return_to.present? && return_to_param_required?
145
+ query_params[:return_to] = return_to
146
+ end
147
+
148
+ has_referer_shop_name = referer_sanitized_shop_name.present?
149
+
150
+ if has_referer_shop_name
151
+ query_params[:shop] ||= referer_sanitized_shop_name
152
+ end
153
+
154
+ query_params[:top_level] = true if top_level
155
+ query_params
156
+ end
157
+
158
+ def return_to_param_required?
159
+ native_params = %i[shop hmac timestamp locale protocol return_to]
160
+ request.path != '/' || sanitized_params.except(*native_params).any?
161
+ end
162
+
163
+ def fullpage_redirect_to(url)
164
+ if ShopifyApp.configuration.embedded_app?
165
+ render('shopify_app/shared/redirect', layout: false,
166
+ locals: { url: url, current_shopify_domain: current_shopify_domain })
167
+ else
168
+ redirect_to(url)
169
+ end
170
+ end
171
+
172
+ def current_shopify_domain
173
+ shopify_domain = sanitized_shop_name ||
174
+ jwt_shopify_domain ||
175
+ session[:shopify_domain]
176
+
177
+ return shopify_domain if shopify_domain.present?
178
+
179
+ raise ShopifyDomainNotFound
180
+ end
181
+
182
+ def sanitized_shop_name
183
+ @sanitized_shop_name ||= sanitize_shop_param(params)
184
+ end
185
+
186
+ def referer_sanitized_shop_name
187
+ return unless request.referer.present?
188
+
189
+ @referer_sanitized_shop_name ||= begin
190
+ referer_uri = URI(request.referer)
191
+ query_params = Rack::Utils.parse_query(referer_uri.query)
192
+
193
+ sanitize_shop_param(query_params.with_indifferent_access)
194
+ end
195
+ end
196
+
197
+ def sanitize_shop_param(params)
198
+ return unless params[:shop].present?
199
+ ShopifyApp::Utils.sanitize_shop_domain(params[:shop])
200
+ end
201
+
202
+ def sanitized_params
203
+ request.query_parameters.clone.tap do |query_params|
204
+ if params[:shop].is_a?(String)
205
+ query_params[:shop] = sanitize_shop_param(params)
206
+ end
207
+ end
208
+ end
209
+
210
+ def return_address
211
+ return base_return_address unless ShopifyApp.configuration.allow_jwt_authentication
212
+ return_address_with_params(shop: current_shopify_domain)
213
+ rescue ShopifyDomainNotFound
214
+ base_return_address
215
+ end
216
+
217
+ def base_return_address
218
+ session.delete(:return_to) || ShopifyApp.configuration.root_url
219
+ end
220
+
221
+ def return_address_with_params(params)
222
+ uri = URI(base_return_address)
223
+ uri.query = CGI.parse(uri.query.to_s)
224
+ .symbolize_keys
225
+ .transform_values { |v| v.one? ? v.first : v }
226
+ .merge(params)
227
+ .to_query
228
+ uri.to_s
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ module ShopifyApp
3
+ module PayloadVerification
4
+ extend ActiveSupport::Concern
5
+
6
+ private
7
+
8
+ def shopify_hmac
9
+ request.headers['HTTP_X_SHOPIFY_HMAC_SHA256']
10
+ end
11
+
12
+ def hmac_valid?(data)
13
+ secrets = [ShopifyApp.configuration.secret, ShopifyApp.configuration.old_secret].reject(&:blank?)
14
+
15
+ secrets.any? do |secret|
16
+ digest = OpenSSL::Digest.new('sha256')
17
+ ActiveSupport::SecurityUtils.secure_compare(
18
+ shopify_hmac,
19
+ Base64.strict_encode64(OpenSSL::HMAC.digest(digest, secret, data))
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ module ShopifyApp
3
+ module WebhookVerification
4
+ extend ActiveSupport::Concern
5
+ include ShopifyApp::PayloadVerification
6
+
7
+ included do
8
+ skip_before_action :verify_authenticity_token, raise: false
9
+ before_action :verify_request
10
+ end
11
+
12
+ private
13
+
14
+ def verify_request
15
+ data = request.raw_post
16
+ return head(:unauthorized) unless hmac_valid?(data)
17
+ end
18
+
19
+ def shop_domain
20
+ request.headers['HTTP_X_SHOPIFY_SHOP_DOMAIN']
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ module ShopifyApp
3
+ class Engine < Rails::Engine
4
+ engine_name 'shopify_app'
5
+ isolate_namespace ShopifyApp
6
+
7
+ initializer "shopify_app.assets.precompile" do |app|
8
+ app.config.assets.precompile += %w[
9
+ shopify_app/redirect.js
10
+ shopify_app/top_level.js
11
+ shopify_app/enable_cookies.js
12
+ shopify_app/request_storage_access.js
13
+ storage_access.svg
14
+ ]
15
+ end
16
+
17
+ initializer "shopify_app.middleware" do |app|
18
+ app.config.middleware.insert_after(::Rack::Runtime, ShopifyApp::SameSiteCookieMiddleware)
19
+
20
+ if ShopifyApp.configuration.allow_jwt_authentication
21
+ app.config.middleware.insert_after(ShopifyApp::SameSiteCookieMiddleware, ShopifyApp::JWTMiddleware)
22
+ end
23
+ end
24
+ end
25
+ end