duodealer_app 1.0.0 → 1.0.1
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/README.md +2 -2
- data/app/controllers/duodealer_app/callback_controller.rb +10 -10
- data/app/controllers/duodealer_app/sessions_controller.rb +23 -23
- data/app/controllers/duodealer_app/webhooks_controller.rb +1 -1
- data/lib/duodealer_app/controller_concerns/login_protection.rb +29 -29
- data/lib/duodealer_app/controller_concerns/webhook_verification.rb +2 -2
- data/lib/duodealer_app/jobs/scripttags_manager_job.rb +3 -3
- data/lib/duodealer_app/jobs/webhooks_manager_job.rb +2 -2
- data/lib/duodealer_app/version.rb +1 -1
- data/lib/generators/duodealer_app/install/templates/duodealer_provider.rb +0 -2
- data/lib/generators/duodealer_app/rotate_duodealer_token_job/templates/rotate_duodealer_token_job.rb +7 -7
- metadata +2 -18
- data/app/controllers/concerns/duodealer_app/authenticated.rb-e +0 -15
- data/app/controllers/duodealer_app/authenticated_controller.rb-e +0 -9
- data/app/controllers/duodealer_app/callback_controller.rb-e +0 -104
- data/app/controllers/duodealer_app/extension_verification_controller.rb-e +0 -19
- data/app/controllers/duodealer_app/sessions_controller.rb-e +0 -159
- data/app/controllers/duodealer_app/webhooks_controller.rb-e +0 -37
- data/app/views/duodealer_app/partials/_button_styles.html.erb-e +0 -104
- data/app/views/duodealer_app/partials/_card_styles.html.erb-e +0 -33
- data/app/views/duodealer_app/partials/_empty_state_styles.html.erb-e +0 -129
- data/app/views/duodealer_app/partials/_layout_styles.html.erb-e +0 -167
- data/app/views/duodealer_app/partials/_typography_styles.html.erb-e +0 -35
- data/app/views/duodealer_app/sessions/enable_cookies.html.erb-e +0 -75
- data/app/views/duodealer_app/sessions/new.html.erb-e +0 -123
- data/app/views/duodealer_app/sessions/request_storage_access.html.erb-e +0 -68
- data/app/views/duodealer_app/sessions/top_level_interaction.html.erb-e +0 -64
- data/app/views/duodealer_app/shared/redirect.html.erb-e +0 -23
data/lib/generators/duodealer_app/rotate_duodealer_token_job/templates/rotate_duodealer_token_job.rb
CHANGED
@@ -3,16 +3,16 @@
|
|
3
3
|
module Duodealer
|
4
4
|
class RotateDuodealerTokenJob < ActiveJob::Base
|
5
5
|
def perform(params)
|
6
|
-
@
|
7
|
-
return unless @
|
6
|
+
@account = Account.find_by(duodealer_domain: params[:account_domain])
|
7
|
+
return unless @account
|
8
8
|
|
9
9
|
config = DuodealerApp.configuration
|
10
|
-
uri = URI("https://#{@
|
10
|
+
uri = URI("https://#{@account.duodealer_domain}/admin/oauth/access_token")
|
11
11
|
post_data = {
|
12
12
|
client_id: config.api_key,
|
13
13
|
client_secret: config.secret,
|
14
14
|
refresh_token: params[:refresh_token],
|
15
|
-
access_token: @
|
15
|
+
access_token: @account.duodealer_token,
|
16
16
|
}
|
17
17
|
|
18
18
|
@response = Net::HTTP.post_form(uri, post_data)
|
@@ -21,7 +21,7 @@ module Duodealer
|
|
21
21
|
access_token = JSON.parse(@response.body)['access_token']
|
22
22
|
return log_error(no_access_token_error_message) unless access_token
|
23
23
|
|
24
|
-
@
|
24
|
+
@account.update(duodealer_token: access_token)
|
25
25
|
end
|
26
26
|
|
27
27
|
private
|
@@ -31,11 +31,11 @@ module Duodealer
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def no_access_token_error_message
|
34
|
-
"RotateDuodealerTokenJob response returned no access token for
|
34
|
+
"RotateDuodealerTokenJob response returned no access token for account: #{@account.duodealer_domain}"
|
35
35
|
end
|
36
36
|
|
37
37
|
def response_exception_error_message
|
38
|
-
"RotateDuodealerTokenJob failed for
|
38
|
+
"RotateDuodealerTokenJob failed for account: #{@account.duodealer_domain}." \
|
39
39
|
"Response returned status: #{@response.code}. Error message: #{@response.message}. "
|
40
40
|
end
|
41
41
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duodealer_app
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Raio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: browser_sniffer
|
@@ -234,37 +234,21 @@ files:
|
|
234
234
|
- app/assets/javascripts/duodealer_app/top_level.js
|
235
235
|
- app/assets/javascripts/duodealer_app/top_level_interaction.js
|
236
236
|
- app/controllers/concerns/duodealer_app/authenticated.rb
|
237
|
-
- app/controllers/concerns/duodealer_app/authenticated.rb-e
|
238
237
|
- app/controllers/duodealer_app/authenticated_controller.rb
|
239
|
-
- app/controllers/duodealer_app/authenticated_controller.rb-e
|
240
238
|
- app/controllers/duodealer_app/callback_controller.rb
|
241
|
-
- app/controllers/duodealer_app/callback_controller.rb-e
|
242
239
|
- app/controllers/duodealer_app/extension_verification_controller.rb
|
243
|
-
- app/controllers/duodealer_app/extension_verification_controller.rb-e
|
244
240
|
- app/controllers/duodealer_app/sessions_controller.rb
|
245
|
-
- app/controllers/duodealer_app/sessions_controller.rb-e
|
246
241
|
- app/controllers/duodealer_app/webhooks_controller.rb
|
247
|
-
- app/controllers/duodealer_app/webhooks_controller.rb-e
|
248
242
|
- app/views/duodealer_app/partials/_button_styles.html.erb
|
249
|
-
- app/views/duodealer_app/partials/_button_styles.html.erb-e
|
250
243
|
- app/views/duodealer_app/partials/_card_styles.html.erb
|
251
|
-
- app/views/duodealer_app/partials/_card_styles.html.erb-e
|
252
244
|
- app/views/duodealer_app/partials/_empty_state_styles.html.erb
|
253
|
-
- app/views/duodealer_app/partials/_empty_state_styles.html.erb-e
|
254
245
|
- app/views/duodealer_app/partials/_layout_styles.html.erb
|
255
|
-
- app/views/duodealer_app/partials/_layout_styles.html.erb-e
|
256
246
|
- app/views/duodealer_app/partials/_typography_styles.html.erb
|
257
|
-
- app/views/duodealer_app/partials/_typography_styles.html.erb-e
|
258
247
|
- app/views/duodealer_app/sessions/enable_cookies.html.erb
|
259
|
-
- app/views/duodealer_app/sessions/enable_cookies.html.erb-e
|
260
248
|
- app/views/duodealer_app/sessions/new.html.erb
|
261
|
-
- app/views/duodealer_app/sessions/new.html.erb-e
|
262
249
|
- app/views/duodealer_app/sessions/request_storage_access.html.erb
|
263
|
-
- app/views/duodealer_app/sessions/request_storage_access.html.erb-e
|
264
250
|
- app/views/duodealer_app/sessions/top_level_interaction.html.erb
|
265
|
-
- app/views/duodealer_app/sessions/top_level_interaction.html.erb-e
|
266
251
|
- app/views/duodealer_app/shared/redirect.html.erb
|
267
|
-
- app/views/duodealer_app/shared/redirect.html.erb-e
|
268
252
|
- config/locales/cs.yml
|
269
253
|
- config/locales/da.yml
|
270
254
|
- config/locales/de.yml
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DuodealerApp
|
4
|
-
module Authenticated
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
included do
|
8
|
-
include DuodealerApp::Localization
|
9
|
-
include DuodealerApp::LoginProtection
|
10
|
-
include DuodealerApp::EmbeddedApp
|
11
|
-
before_action :login_again_if_different_user_or_shop
|
12
|
-
around_action :duodealer_session
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,104 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DuodealerApp
|
4
|
-
# Performs login after OAuth completes
|
5
|
-
class CallbackController < ApplicationController
|
6
|
-
include DuodealerApp::LoginProtection
|
7
|
-
|
8
|
-
def callback
|
9
|
-
if auth_hash
|
10
|
-
login_shop
|
11
|
-
install_webhooks
|
12
|
-
install_scripttags
|
13
|
-
perform_after_authenticate_job
|
14
|
-
|
15
|
-
redirect_to return_address
|
16
|
-
else
|
17
|
-
flash[:error] = I18n.t("could_not_log_in")
|
18
|
-
redirect_to(login_url_with_optional_shop)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
def login_shop
|
24
|
-
reset_session_options
|
25
|
-
set_duodealer_session
|
26
|
-
end
|
27
|
-
|
28
|
-
def auth_hash
|
29
|
-
request.env["omniauth.auth"]
|
30
|
-
end
|
31
|
-
|
32
|
-
def shop_name
|
33
|
-
auth_hash.uid
|
34
|
-
end
|
35
|
-
|
36
|
-
def associated_user
|
37
|
-
return if auth_hash["extra"].blank?
|
38
|
-
|
39
|
-
auth_hash["extra"]["associated_user"]
|
40
|
-
end
|
41
|
-
|
42
|
-
def token
|
43
|
-
auth_hash["credentials"]["token"]
|
44
|
-
end
|
45
|
-
|
46
|
-
def reset_session_options
|
47
|
-
request.session_options[:renew] = true
|
48
|
-
session.delete(:_csrf_token)
|
49
|
-
end
|
50
|
-
|
51
|
-
def set_duodealer_session
|
52
|
-
session_store = DuodealerAPI::Session.new(
|
53
|
-
domain: shop_name,
|
54
|
-
token: token,
|
55
|
-
api_version: DuodealerApp.configuration.api_version
|
56
|
-
)
|
57
|
-
session[:duodealer] = DuodealerApp::SessionRepository.store(session_store, user: associated_user)
|
58
|
-
session[:duodealer_domain] = shop_name
|
59
|
-
session[:duodealer_user] = associated_user
|
60
|
-
|
61
|
-
if DuodealerApp.configuration.per_user_tokens?
|
62
|
-
# Adds the user_session to the session to determine if the logged in user has changed
|
63
|
-
user_session = auth_hash&.extra&.session
|
64
|
-
raise IndexError, "Missing user session signature" if user_session.nil?
|
65
|
-
session[:user_session] = user_session
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def install_webhooks
|
70
|
-
return unless DuodealerApp.configuration.has_webhooks?
|
71
|
-
|
72
|
-
WebhooksManager.queue(
|
73
|
-
shop_name,
|
74
|
-
token,
|
75
|
-
DuodealerApp.configuration.webhooks
|
76
|
-
)
|
77
|
-
end
|
78
|
-
|
79
|
-
def install_scripttags
|
80
|
-
return unless DuodealerApp.configuration.has_scripttags?
|
81
|
-
|
82
|
-
ScripttagsManager.queue(
|
83
|
-
shop_name,
|
84
|
-
token,
|
85
|
-
DuodealerApp.configuration.scripttags
|
86
|
-
)
|
87
|
-
end
|
88
|
-
|
89
|
-
def perform_after_authenticate_job
|
90
|
-
config = DuodealerApp.configuration.after_authenticate_job
|
91
|
-
|
92
|
-
return unless config && config[:job].present?
|
93
|
-
|
94
|
-
job = config[:job]
|
95
|
-
job = job.constantize if job.is_a?(String)
|
96
|
-
|
97
|
-
if config[:inline] == true
|
98
|
-
job.perform_now(shop_domain: session[:duodealer_domain])
|
99
|
-
else
|
100
|
-
job.perform_later(shop_domain: session[:duodealer_domain])
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DuodealerApp
|
4
|
-
class ExtensionVerificationController < ApplicationController
|
5
|
-
protect_from_forgery with: :null_session
|
6
|
-
before_action :verify_request
|
7
|
-
|
8
|
-
private
|
9
|
-
def verify_request
|
10
|
-
hmac_header = request.headers["HTTP_X_DUODEALER_HMAC_SHA256"]
|
11
|
-
request_body = request.body.read
|
12
|
-
secret = DuodealerApp.configuration.secret
|
13
|
-
digest = OpenSSL::Digest.new("sha256")
|
14
|
-
|
15
|
-
expected_hmac = Base64.strict_encode64(OpenSSL::HMAC.digest(digest, secret, request_body))
|
16
|
-
head(:unauthorized) unless ActiveSupport::SecurityUtils.secure_compare(expected_hmac, hmac_header)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,159 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DuodealerApp
|
4
|
-
class SessionsController < ApplicationController # rubocop:disable Metrics/ClassLength
|
5
|
-
include DuodealerApp::LoginProtection
|
6
|
-
|
7
|
-
layout false, only: :new
|
8
|
-
after_action only: [:new, :create] do |controller|
|
9
|
-
controller.response.headers.except!("X-Frame-Options")
|
10
|
-
end
|
11
|
-
|
12
|
-
def new
|
13
|
-
authenticate if sanitized_shop_name.present?
|
14
|
-
end
|
15
|
-
|
16
|
-
def create
|
17
|
-
authenticate
|
18
|
-
end
|
19
|
-
|
20
|
-
def enable_cookies
|
21
|
-
return unless validate_shop
|
22
|
-
|
23
|
-
render(:enable_cookies, layout: false, locals: {
|
24
|
-
does_not_have_storage_access_url: top_level_interaction_path(
|
25
|
-
shop: sanitized_shop_name,
|
26
|
-
return_to: params[:return_to]
|
27
|
-
),
|
28
|
-
has_storage_access_url: login_url_with_optional_shop(top_level: true),
|
29
|
-
app_target_url: granted_storage_access_path(
|
30
|
-
shop: sanitized_shop_name,
|
31
|
-
return_to: params[:return_to]
|
32
|
-
),
|
33
|
-
current_duodealer_domain: current_duodealer_domain
|
34
|
-
})
|
35
|
-
end
|
36
|
-
|
37
|
-
def top_level_interaction
|
38
|
-
@url = login_url_with_optional_shop(top_level: true)
|
39
|
-
validate_shop
|
40
|
-
end
|
41
|
-
|
42
|
-
def granted_storage_access
|
43
|
-
return unless validate_shop
|
44
|
-
|
45
|
-
session["duodealer.granted_storage_access"] = true
|
46
|
-
|
47
|
-
copy_return_to_param_to_session
|
48
|
-
|
49
|
-
redirect_to(return_address_with_params({ shop: @shop }))
|
50
|
-
end
|
51
|
-
|
52
|
-
def destroy
|
53
|
-
reset_session
|
54
|
-
flash[:notice] = I18n.t(".logged_out")
|
55
|
-
redirect_to(login_url_with_optional_shop)
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
def authenticate
|
60
|
-
return render_invalid_shop_error if sanitized_shop_name.blank?
|
61
|
-
session["duodealer.omniauth_params"] = { shop: sanitized_shop_name }
|
62
|
-
|
63
|
-
copy_return_to_param_to_session
|
64
|
-
|
65
|
-
if user_agent_can_partition_cookies
|
66
|
-
authenticate_with_partitioning
|
67
|
-
else
|
68
|
-
authenticate_normally
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def authenticate_normally
|
73
|
-
if request_storage_access?
|
74
|
-
redirect_to_request_storage_access
|
75
|
-
elsif authenticate_in_context?
|
76
|
-
authenticate_in_context
|
77
|
-
else
|
78
|
-
authenticate_at_top_level
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def authenticate_with_partitioning
|
83
|
-
if session["duodealer.cookies_persist"]
|
84
|
-
clear_top_level_oauth_cookie
|
85
|
-
authenticate_in_context
|
86
|
-
else
|
87
|
-
set_top_level_oauth_cookie
|
88
|
-
enable_cookie_access
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def validate_shop
|
93
|
-
@shop = sanitized_shop_name
|
94
|
-
unless @shop
|
95
|
-
render_invalid_shop_error
|
96
|
-
return false
|
97
|
-
end
|
98
|
-
|
99
|
-
true
|
100
|
-
end
|
101
|
-
|
102
|
-
def copy_return_to_param_to_session
|
103
|
-
session[:return_to] = params[:return_to] if params[:return_to]
|
104
|
-
end
|
105
|
-
|
106
|
-
def render_invalid_shop_error
|
107
|
-
flash[:error] = I18n.t("invalid_shop_url")
|
108
|
-
redirect_to return_address
|
109
|
-
end
|
110
|
-
|
111
|
-
def enable_cookie_access
|
112
|
-
fullpage_redirect_to(enable_cookies_path(
|
113
|
-
shop: sanitized_shop_name,
|
114
|
-
return_to: session[:return_to]
|
115
|
-
))
|
116
|
-
end
|
117
|
-
|
118
|
-
def authenticate_in_context
|
119
|
-
redirect_to "#{main_app.root_path}auth/duodealer"
|
120
|
-
end
|
121
|
-
|
122
|
-
def authenticate_at_top_level
|
123
|
-
fullpage_redirect_to(login_url_with_optional_shop(top_level: true))
|
124
|
-
end
|
125
|
-
|
126
|
-
def authenticate_in_context?
|
127
|
-
return true unless DuodealerApp.configuration.embedded_app?
|
128
|
-
params[:top_level]
|
129
|
-
end
|
130
|
-
|
131
|
-
def request_storage_access?
|
132
|
-
return false unless DuodealerApp.configuration.embedded_app?
|
133
|
-
return false if params[:top_level]
|
134
|
-
return false if user_agent_is_mobile
|
135
|
-
return false if user_agent_is_pos
|
136
|
-
|
137
|
-
!session["duodealer.granted_storage_access"]
|
138
|
-
end
|
139
|
-
|
140
|
-
def redirect_to_request_storage_access
|
141
|
-
render(
|
142
|
-
:request_storage_access,
|
143
|
-
layout: false,
|
144
|
-
locals: {
|
145
|
-
does_not_have_storage_access_url: top_level_interaction_path(
|
146
|
-
shop: sanitized_shop_name,
|
147
|
-
return_to: session[:return_to]
|
148
|
-
),
|
149
|
-
has_storage_access_url: login_url_with_optional_shop(top_level: true),
|
150
|
-
app_target_url: granted_storage_access_path(
|
151
|
-
shop: sanitized_shop_name,
|
152
|
-
return_to: session[:return_to]
|
153
|
-
),
|
154
|
-
current_duodealer_domain: current_duodealer_domain
|
155
|
-
}
|
156
|
-
)
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DuodealerApp
|
4
|
-
class WebhooksController < ApplicationController
|
5
|
-
include DuodealerApp::WebhookVerification
|
6
|
-
|
7
|
-
class DuodealerApp::MissingWebhookJobError < StandardError; end
|
8
|
-
|
9
|
-
def receive
|
10
|
-
params.permit!
|
11
|
-
job_args = { shop_domain: shop_domain, webhook: webhook_params.to_h }
|
12
|
-
webhook_job_klass.perform_later(job_args)
|
13
|
-
head :no_content
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
def webhook_params
|
18
|
-
params.except(:controller, :action, :type)
|
19
|
-
end
|
20
|
-
|
21
|
-
def webhook_job_klass
|
22
|
-
webhook_job_klass_name.safe_constantize || raise(DuodealerApp::MissingWebhookJobError)
|
23
|
-
end
|
24
|
-
|
25
|
-
def webhook_job_klass_name(type = webhook_type)
|
26
|
-
[webhook_namespace, "#{type}_job"].compact.join("/").classify
|
27
|
-
end
|
28
|
-
|
29
|
-
def webhook_type
|
30
|
-
params[:type]
|
31
|
-
end
|
32
|
-
|
33
|
-
def webhook_namespace
|
34
|
-
DuodealerApp.configuration.webhook_jobs_namespace
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|