shopify_app 12.0.0 → 13.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -0
- data/README.md +67 -20
- data/app/assets/javascripts/shopify_app/itp_helper.js +6 -6
- data/app/assets/javascripts/shopify_app/storage_access.js +35 -6
- data/app/controllers/concerns/shopify_app/authenticated.rb +1 -1
- data/app/controllers/shopify_app/callback_controller.rb +14 -10
- data/app/controllers/shopify_app/sessions_controller.rb +49 -13
- data/app/views/shopify_app/sessions/enable_cookies.html.erb +1 -1
- data/app/views/shopify_app/sessions/request_storage_access.html.erb +1 -1
- data/config/locales/pt-BR.yml +1 -1
- data/lib/generators/shopify_app/add_marketing_activity_extension/templates/marketing_activities_controller.rb +1 -5
- data/lib/generators/shopify_app/home_controller/templates/index.html.erb +1 -1
- data/lib/generators/shopify_app/install/templates/embedded_app.html.erb +1 -1
- data/lib/generators/shopify_app/install/templates/shopify_app.rb +1 -1
- data/lib/generators/shopify_app/install/templates/shopify_provider.rb +1 -1
- data/lib/generators/shopify_app/shop_model/shop_model_generator.rb +1 -1
- data/lib/generators/shopify_app/shop_model/templates/shop.rb +1 -1
- data/lib/generators/shopify_app/user_model/templates/user.rb +1 -1
- data/lib/generators/shopify_app/user_model/user_model_generator.rb +1 -1
- data/lib/shopify_app/configuration.rb +12 -9
- data/lib/shopify_app/controller_concerns/login_protection.rb +39 -22
- data/lib/shopify_app/engine.rb +1 -1
- data/lib/shopify_app/middleware/same_site_cookie_middleware.rb +18 -45
- data/lib/shopify_app/session/in_memory_shop_session_store.rb +4 -0
- data/lib/shopify_app/session/in_memory_user_session_store.rb +4 -0
- data/lib/shopify_app/session/session_repository.rb +38 -13
- data/lib/shopify_app/session/session_storage.rb +0 -10
- data/lib/shopify_app/session/{storage_strategies/shop_storage_strategy.rb → shop_session_storage.rb} +9 -2
- data/lib/shopify_app/session/{storage_strategies/user_storage_strategy.rb → user_session_storage.rb} +10 -3
- data/lib/shopify_app/version.rb +1 -1
- data/lib/shopify_app.rb +4 -2
- data/package-lock.json +1228 -1207
- data/package.json +2 -2
- data/shopify_app.gemspec +4 -4
- metadata +12 -10
@@ -32,7 +32,7 @@
|
|
32
32
|
myshopifyUrl: "https://#{current_shopify_domain}",
|
33
33
|
hasStorageAccessUrl: "#{has_storage_access_url}",
|
34
34
|
doesNotHaveStorageAccessUrl: "#{does_not_have_storage_access_url}",
|
35
|
-
|
35
|
+
appTargetUrl: "#{app_target_url}"
|
36
36
|
},
|
37
37
|
},
|
38
38
|
)
|
@@ -24,7 +24,7 @@
|
|
24
24
|
myshopifyUrl: "https://#{current_shopify_domain}",
|
25
25
|
hasStorageAccessUrl: "#{has_storage_access_url}",
|
26
26
|
doesNotHaveStorageAccessUrl: "#{does_not_have_storage_access_url}",
|
27
|
-
|
27
|
+
appTargetUrl: "#{app_target_url}"
|
28
28
|
},
|
29
29
|
},
|
30
30
|
)
|
data/config/locales/pt-BR.yml
CHANGED
@@ -4,7 +4,7 @@ pt-BR:
|
|
4
4
|
could_not_log_in: Não foi possível fazer login na Shopify store
|
5
5
|
invalid_shop_url: Domínio de loja inválido
|
6
6
|
enable_cookies_heading: Habilitar cookies de %{app}
|
7
|
-
enable_cookies_body: Você
|
7
|
+
enable_cookies_body: Você precisa habilitar manualmente os cookies neste navegador
|
8
8
|
para usar %{app} dentro da Shopify.
|
9
9
|
enable_cookies_footer: Os cookies permitem que o app o autentique armazenando temporariamente
|
10
10
|
suas preferências e dados pessoais. Eles expiram depois de 30 dias.
|
@@ -3,11 +3,7 @@
|
|
3
3
|
class MarketingActivitiesController < ShopifyApp::ExtensionVerificationController
|
4
4
|
def preload_form_data
|
5
5
|
preload_data = {
|
6
|
-
"form_data": {
|
7
|
-
"budget": {
|
8
|
-
"currency": "USD",
|
9
|
-
}
|
10
|
-
}
|
6
|
+
"form_data": {}
|
11
7
|
}
|
12
8
|
render(json: preload_data, status: :ok)
|
13
9
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
<ul>
|
4
4
|
<% @products.each do |product| %>
|
5
|
-
<li><%= link_to product.title, "https://#{@
|
5
|
+
<li><%= link_to product.title, "https://#{@current_shopify_session.domain}/admin/products/#{product.id}", target: "_top" %></li>
|
6
6
|
<% end %>
|
7
7
|
</ul>
|
8
8
|
|
@@ -28,7 +28,7 @@
|
|
28
28
|
|
29
29
|
<%= content_tag(:div, nil, id: 'shopify-app-init', data: {
|
30
30
|
api_key: ShopifyApp.configuration.api_key,
|
31
|
-
shop_origin: (@
|
31
|
+
shop_origin: (@current_shopify_session.domain if @current_shopify_session),
|
32
32
|
debug: Rails.env.development?
|
33
33
|
} ) %>
|
34
34
|
|
@@ -8,7 +8,7 @@ ShopifyApp.configure do |config|
|
|
8
8
|
config.embedded_app = <%= embedded_app? %>
|
9
9
|
config.after_authenticate_job = false
|
10
10
|
config.api_version = "<%= @api_version %>"
|
11
|
-
config.
|
11
|
+
config.shop_session_repository = 'ShopifyApp::InMemoryShopSessionStore'
|
12
12
|
end
|
13
13
|
|
14
14
|
# ShopifyApp::Utils.fetch_known_api_versions # Uncomment to fetch known api versions from shopify servers on boot
|
@@ -4,7 +4,6 @@ provider :shopify,
|
|
4
4
|
ShopifyApp.configuration.api_key,
|
5
5
|
ShopifyApp.configuration.secret,
|
6
6
|
scope: ShopifyApp.configuration.scope,
|
7
|
-
per_user_permissions: ShopifyApp.configuration.per_user_tokens,
|
8
7
|
setup: lambda { |env|
|
9
8
|
strategy = env['omniauth.strategy']
|
10
9
|
|
@@ -17,4 +16,5 @@ provider :shopify,
|
|
17
16
|
|
18
17
|
strategy.options[:client_options][:site] = shop
|
19
18
|
strategy.options[:old_client_secret] = ShopifyApp.configuration.old_secret
|
19
|
+
strategy.options[:per_user_permissions] = strategy.session[:user_tokens]
|
20
20
|
}
|
@@ -16,7 +16,7 @@ module ShopifyApp
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def update_shopify_app_initializer
|
19
|
-
gsub_file 'config/initializers/shopify_app.rb', 'ShopifyApp::
|
19
|
+
gsub_file 'config/initializers/shopify_app.rb', 'ShopifyApp::InMemoryShopSessionStore', 'Shop'
|
20
20
|
end
|
21
21
|
|
22
22
|
def create_shop_fixtures
|
@@ -16,7 +16,7 @@ module ShopifyApp
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def update_shopify_app_initializer
|
19
|
-
gsub_file 'config/initializers/shopify_app.rb', 'ShopifyApp::
|
19
|
+
gsub_file 'config/initializers/shopify_app.rb', 'ShopifyApp::InMemoryUserSessionStore', 'User'
|
20
20
|
end
|
21
21
|
|
22
22
|
def create_user_fixtures
|
@@ -5,7 +5,7 @@ module ShopifyApp
|
|
5
5
|
# for the app in your Shopify Partners page. Change your settings in
|
6
6
|
# `config/initializers/shopify_app.rb`
|
7
7
|
attr_accessor :application_name
|
8
|
-
attr_accessor
|
8
|
+
attr_accessor :api_key
|
9
9
|
attr_accessor :secret
|
10
10
|
attr_accessor :old_secret
|
11
11
|
attr_accessor :scope
|
@@ -14,9 +14,8 @@ module ShopifyApp
|
|
14
14
|
attr_accessor :webhooks
|
15
15
|
attr_accessor :scripttags
|
16
16
|
attr_accessor :after_authenticate_job
|
17
|
-
attr_reader :
|
18
|
-
|
19
|
-
alias_method :per_user_tokens?, :per_user_tokens
|
17
|
+
attr_reader :shop_session_repository
|
18
|
+
attr_reader :user_session_repository
|
20
19
|
attr_accessor :api_version
|
21
20
|
|
22
21
|
# customise urls
|
@@ -44,7 +43,6 @@ module ShopifyApp
|
|
44
43
|
@myshopify_domain = 'myshopify.com'
|
45
44
|
@scripttags_manager_queue_name = Rails.application.config.active_job.queue_name
|
46
45
|
@webhooks_manager_queue_name = Rails.application.config.active_job.queue_name
|
47
|
-
@per_user_tokens = false
|
48
46
|
@disable_webpacker = ENV['SHOPIFY_APP_DISABLE_WEBPACKER'].present?
|
49
47
|
end
|
50
48
|
|
@@ -52,9 +50,14 @@ module ShopifyApp
|
|
52
50
|
@login_url || File.join(@root_url, 'login')
|
53
51
|
end
|
54
52
|
|
55
|
-
def
|
56
|
-
@
|
57
|
-
ShopifyApp::SessionRepository.
|
53
|
+
def user_session_repository=(klass)
|
54
|
+
@user_session_repository = klass
|
55
|
+
ShopifyApp::SessionRepository.user_storage = klass
|
56
|
+
end
|
57
|
+
|
58
|
+
def shop_session_repository=(klass)
|
59
|
+
@shop_session_repository = klass
|
60
|
+
ShopifyApp::SessionRepository.shop_storage = klass
|
58
61
|
end
|
59
62
|
|
60
63
|
def has_webhooks?
|
@@ -66,7 +69,7 @@ module ShopifyApp
|
|
66
69
|
end
|
67
70
|
|
68
71
|
def enable_same_site_none
|
69
|
-
@enable_same_site_none.nil? ? embedded_app? : @enable_same_site_none
|
72
|
+
!Rails.env.test? && (@enable_same_site_none.nil? ? embedded_app? : @enable_same_site_none)
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
@@ -14,44 +14,48 @@ module ShopifyApp
|
|
14
14
|
rescue_from ActiveResource::UnauthorizedAccess, :with => :close_session
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
return redirect_to_login
|
17
|
+
def activate_shopify_session
|
18
|
+
return redirect_to_login if current_shopify_session.blank?
|
19
19
|
clear_top_level_oauth_cookie
|
20
20
|
|
21
21
|
begin
|
22
|
-
ShopifyAPI::Base.activate_session(
|
22
|
+
ShopifyAPI::Base.activate_session(current_shopify_session)
|
23
23
|
yield
|
24
24
|
ensure
|
25
25
|
ShopifyAPI::Base.clear_session
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
30
|
-
if
|
31
|
-
|
32
|
-
@shop_session ||= ShopifyApp::SessionRepository.retrieve(session[:shopify_user]['id'])
|
29
|
+
def current_shopify_session
|
30
|
+
if session[:user_id].present?
|
31
|
+
@current_shopify_session ||= user_session
|
33
32
|
else
|
34
|
-
|
35
|
-
@shop_session ||= ShopifyApp::SessionRepository.retrieve(session[:shopify])
|
33
|
+
@current_shopify_session ||= shop_session
|
36
34
|
end
|
37
35
|
end
|
38
36
|
|
37
|
+
def user_session
|
38
|
+
return if session[:user_id].blank?
|
39
|
+
ShopifyApp::SessionRepository.retrieve_user_session(session[:user_id])
|
40
|
+
end
|
41
|
+
|
42
|
+
def shop_session
|
43
|
+
return if session[:shop_id].blank?
|
44
|
+
ShopifyApp::SessionRepository.retrieve_shop_session(session[:shop_id])
|
45
|
+
end
|
46
|
+
|
39
47
|
def login_again_if_different_user_or_shop
|
40
|
-
if
|
41
|
-
|
42
|
-
sessions_do_not_match = session[:user_session] != params[:session] # current user is different from stored user
|
48
|
+
if session[:user_session].present? && params[:session].present? # session data was sent/stored correctly
|
49
|
+
clear_session = session[:user_session] != params[:session] # current user is different from stored user
|
43
50
|
|
44
|
-
if valid_session_data && sessions_do_not_match
|
45
|
-
clear_session = true
|
46
|
-
end
|
47
51
|
end
|
48
52
|
|
49
|
-
if
|
53
|
+
if current_shopify_session && params[:shop] && params[:shop].is_a?(String) && (current_shopify_session.domain != params[:shop])
|
50
54
|
clear_session = true
|
51
55
|
end
|
52
56
|
|
53
57
|
if clear_session
|
54
|
-
|
58
|
+
clear_shopify_session
|
55
59
|
redirect_to_login
|
56
60
|
end
|
57
61
|
end
|
@@ -76,12 +80,13 @@ module ShopifyApp
|
|
76
80
|
end
|
77
81
|
|
78
82
|
def close_session
|
79
|
-
|
83
|
+
clear_shopify_session
|
80
84
|
redirect_to(login_url_with_optional_shop)
|
81
85
|
end
|
82
86
|
|
83
|
-
def
|
84
|
-
session[:
|
87
|
+
def clear_shopify_session
|
88
|
+
session[:shop_id] = nil
|
89
|
+
session[:user_id] = nil
|
85
90
|
session[:shopify_domain] = nil
|
86
91
|
session[:shopify_user] = nil
|
87
92
|
session[:user_session] = nil
|
@@ -100,8 +105,10 @@ module ShopifyApp
|
|
100
105
|
query_params = {}
|
101
106
|
query_params[:shop] = sanitized_params[:shop] if params[:shop].present?
|
102
107
|
|
103
|
-
|
104
|
-
|
108
|
+
return_to = session[:return_to] || params[:return_to]
|
109
|
+
|
110
|
+
if return_to.present? && return_to_param_required?
|
111
|
+
query_params[:return_to] = return_to
|
105
112
|
end
|
106
113
|
|
107
114
|
has_referer_shop_name = referer_sanitized_shop_name.present?
|
@@ -165,5 +172,15 @@ module ShopifyApp
|
|
165
172
|
def return_address
|
166
173
|
session.delete(:return_to) || ShopifyApp.configuration.root_url
|
167
174
|
end
|
175
|
+
|
176
|
+
def return_address_with_params(params)
|
177
|
+
uri = URI(return_address)
|
178
|
+
uri.query = CGI.parse(uri.query.to_s)
|
179
|
+
.symbolize_keys
|
180
|
+
.transform_values { |v| v.one? ? v.first : v }
|
181
|
+
.merge(params)
|
182
|
+
.to_query
|
183
|
+
uri.to_s
|
184
|
+
end
|
168
185
|
end
|
169
186
|
end
|
data/lib/shopify_app/engine.rb
CHANGED
@@ -14,7 +14,7 @@ module ShopifyApp
|
|
14
14
|
end
|
15
15
|
|
16
16
|
initializer "shopify_app.middleware" do |app|
|
17
|
-
app.config.middleware.
|
17
|
+
app.config.middleware.insert_after(::Rack::Runtime, ShopifyApp::SameSiteCookieMiddleware)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -1,60 +1,33 @@
|
|
1
1
|
module ShopifyApp
|
2
2
|
class SameSiteCookieMiddleware
|
3
|
+
COOKIE_SEPARATOR = "\n"
|
4
|
+
|
3
5
|
def initialize(app)
|
4
6
|
@app = app
|
5
7
|
end
|
6
8
|
|
7
9
|
def call(env)
|
8
|
-
|
9
|
-
ensure
|
10
|
+
status, headers, body = @app.call(env)
|
10
11
|
user_agent = env['HTTP_USER_AGENT']
|
11
12
|
|
12
|
-
if headers && headers['Set-Cookie'] &&
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
if headers && headers['Set-Cookie'] &&
|
14
|
+
BrowserSniffer.new(user_agent).same_site_none_compatible? &&
|
15
|
+
ShopifyApp.configuration.enable_same_site_none &&
|
16
|
+
Rack::Request.new(env).ssl?
|
17
|
+
|
18
|
+
set_cookies = headers['Set-Cookie']
|
19
|
+
.split(COOKIE_SEPARATOR)
|
20
|
+
.compact
|
21
|
+
.map do |cookie|
|
22
|
+
cookie << '; Secure' if not cookie =~ /;\s*secure/i
|
23
|
+
cookie << '; SameSite=None' unless cookie =~ /;\s*samesite=/i
|
24
|
+
cookie
|
20
25
|
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
webkit_same_site_bug?(sniffer) || drops_unrecognized_same_site_cookies?(sniffer)
|
29
|
-
rescue
|
30
|
-
true
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.webkit_same_site_bug?(sniffer)
|
34
|
-
(sniffer.os == :ios && sniffer.os_version.match?(/^([0-9]|1[12])[\.\_]/)) ||
|
35
|
-
(sniffer.os == :mac && sniffer.browser == :safari && sniffer.os_version.match?(/^10[\.\_]14/))
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.drops_unrecognized_same_site_cookies?(sniffer)
|
39
|
-
(chromium_based?(sniffer) && sniffer.major_browser_version >= 51 && sniffer.major_browser_version <= 66) ||
|
40
|
-
(uc_browser?(sniffer) && !uc_browser_version_at_least?(sniffer: sniffer, major: 12, minor: 13, build: 2))
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.chromium_based?(sniffer)
|
44
|
-
sniffer.browser_name.downcase.match?(/chrom(e|ium)/)
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.uc_browser?(sniffer)
|
48
|
-
sniffer.user_agent.downcase.match?(/uc\s?browser/)
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.uc_browser_version_at_least?(sniffer:, major:, minor:, build:)
|
52
|
-
digits = sniffer.browser_version.split('.').map(&:to_i)
|
53
|
-
return false unless digits.count >= 3
|
27
|
+
headers['Set-Cookie'] = set_cookies.join(COOKIE_SEPARATOR)
|
28
|
+
end
|
54
29
|
|
55
|
-
|
56
|
-
return digits[1] > minor if digits[1] != minor
|
57
|
-
digits[2] >= build
|
30
|
+
[status, headers, body]
|
58
31
|
end
|
59
32
|
end
|
60
33
|
end
|
@@ -3,31 +3,56 @@ module ShopifyApp
|
|
3
3
|
class ConfigurationError < StandardError; end
|
4
4
|
|
5
5
|
class << self
|
6
|
-
def
|
7
|
-
@
|
6
|
+
def shop_storage=(storage)
|
7
|
+
@shop_storage = storage
|
8
8
|
|
9
|
-
unless storage.nil? || self.
|
10
|
-
raise ArgumentError, "storage must respond to :store and :retrieve"
|
9
|
+
unless storage.nil? || self.shop_storage.respond_to?(:store) && self.shop_storage.respond_to?(:retrieve)
|
10
|
+
raise ArgumentError, "shop storage must respond to :store and :retrieve"
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
storage
|
14
|
+
def user_storage=(storage)
|
15
|
+
@user_storage = storage
|
16
|
+
|
17
|
+
unless storage.nil? || self.user_storage.respond_to?(:store) && self.user_storage.respond_to?(:retrieve)
|
18
|
+
raise ArgumentError, "user storage must respond to :store and :retrieve"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def retrieve_shop_session(id)
|
23
|
+
shop_storage.retrieve(id)
|
24
|
+
end
|
25
|
+
|
26
|
+
def retrieve_user_session(id)
|
27
|
+
user_storage.retrieve(id)
|
16
28
|
end
|
17
29
|
|
18
|
-
def
|
19
|
-
|
30
|
+
def store_shop_session(session)
|
31
|
+
shop_storage.store(session)
|
20
32
|
end
|
21
33
|
|
22
|
-
def
|
23
|
-
|
34
|
+
def store_user_session(session, user)
|
35
|
+
user_storage.store(session, user)
|
36
|
+
end
|
37
|
+
|
38
|
+
def shop_storage
|
39
|
+
load_shop_storage || raise(ConfigurationError.new("ShopifySessionRepository.shop_storage is not configured!"))
|
40
|
+
end
|
41
|
+
|
42
|
+
def user_storage
|
43
|
+
load_user_storage
|
24
44
|
end
|
25
45
|
|
26
46
|
private
|
27
47
|
|
28
|
-
def
|
29
|
-
return unless @
|
30
|
-
@
|
48
|
+
def load_shop_storage
|
49
|
+
return unless @shop_storage
|
50
|
+
@shop_storage.respond_to?(:safe_constantize) ? @shop_storage.safe_constantize : @shop_storage
|
51
|
+
end
|
52
|
+
|
53
|
+
def load_user_storage
|
54
|
+
return unless @user_storage
|
55
|
+
@user_storage.respond_to?(:safe_constantize) ? @user_storage.safe_constantize : @user_storage
|
31
56
|
end
|
32
57
|
end
|
33
58
|
end
|