standard_id 0.5.0 → 0.5.2
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 514c8e8c18bb9bf6d8bd0268cca374d477b2c276a3caf69b0ef58222b5b14b33
|
|
4
|
+
data.tar.gz: 8e9f2307f6fd2d6a99e78df4604f838c319a61487e0d1549df1712eaf683b639
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 21fcdb6b8caaf652bdbe6cb86c52e7cf66480b5aae7bf9fab210dad86b9cb12626920190cd1743c138d8b3fc1608c2f921a3c18b79f0cdfe20407530fbcee596
|
|
7
|
+
data.tar.gz: 30dfa2dae9df664b4ff7bfdb972cbc3970bf8ac81fb185e8f6aca0676b4647903f20e60d0eaf5d531b3e3a1e4fcbaf923b1e05ee7f9f8fd6ca93461b0567e999
|
|
@@ -9,6 +9,19 @@ module StandardId
|
|
|
9
9
|
# Safe to include even when the Sentry gem is not installed -- the
|
|
10
10
|
# callback is a no-op if `Sentry` is not defined.
|
|
11
11
|
#
|
|
12
|
+
# Extra fields can be added via the `sentry_context` config option:
|
|
13
|
+
#
|
|
14
|
+
# StandardId.configure do |c|
|
|
15
|
+
# c.sentry_context = ->(account, session) {
|
|
16
|
+
# { email: account.email, username: account.try(:display_name) }
|
|
17
|
+
# }
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# The lambda must return a Hash (nil and non-Hash returns are ignored).
|
|
21
|
+
# Base keys (id, session_id) always take precedence and cannot be
|
|
22
|
+
# overridden by the lambda. Exceptions raised by the lambda are not
|
|
23
|
+
# caught — they will propagate to surface misconfiguration immediately.
|
|
24
|
+
#
|
|
12
25
|
# @example
|
|
13
26
|
# class ApplicationController < ActionController::Base
|
|
14
27
|
# include StandardId::WebAuthentication
|
|
@@ -27,10 +40,20 @@ module StandardId
|
|
|
27
40
|
return unless defined?(Sentry)
|
|
28
41
|
return unless respond_to?(:current_account, true) && current_account.present?
|
|
29
42
|
|
|
30
|
-
|
|
31
|
-
|
|
43
|
+
session_value = current_session.presence if respond_to?(:current_session, true)
|
|
44
|
+
|
|
45
|
+
base = { id: current_account.id }
|
|
46
|
+
base[:session_id] = session_value.id if session_value&.respond_to?(:id)
|
|
47
|
+
|
|
48
|
+
extra = StandardId.config.sentry_context
|
|
49
|
+
if extra.respond_to?(:call)
|
|
50
|
+
result = extra.call(current_account, session_value)
|
|
51
|
+
# Merge lambda result underneath base keys so id/session_id cannot
|
|
52
|
+
# be accidentally overridden by the host app's lambda.
|
|
53
|
+
base = result.merge(base) if result.is_a?(Hash)
|
|
54
|
+
end
|
|
32
55
|
|
|
33
|
-
Sentry.set_user(
|
|
56
|
+
Sentry.set_user(base)
|
|
34
57
|
end
|
|
35
58
|
end
|
|
36
59
|
end
|
|
@@ -6,6 +6,19 @@ module StandardId
|
|
|
6
6
|
cancancan: :check_authorization
|
|
7
7
|
}.freeze
|
|
8
8
|
|
|
9
|
+
# Frameworks where the skip falls through to skip_after_action.
|
|
10
|
+
# ActionPolicy is NOT listed here because it is handled first via
|
|
11
|
+
# CLASS_METHOD_SKIP. Only :pundit reaches this branch.
|
|
12
|
+
AFTER_ACTION_FRAMEWORKS = %i[pundit].freeze
|
|
13
|
+
|
|
14
|
+
# ActionPolicy provides a dedicated class method to undo
|
|
15
|
+
# verify_authorized. Using skip_before_action or skip_after_action
|
|
16
|
+
# would silently do nothing for ActionPolicy because it manages the
|
|
17
|
+
# callback through its own DSL.
|
|
18
|
+
CLASS_METHOD_SKIP = {
|
|
19
|
+
action_policy: :skip_verify_authorized
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
9
22
|
MUTEX = Mutex.new
|
|
10
23
|
private_constant :MUTEX
|
|
11
24
|
|
|
@@ -30,11 +43,12 @@ module StandardId
|
|
|
30
43
|
|
|
31
44
|
MUTEX.synchronize do
|
|
32
45
|
# Guard against duplicate to_prepare registrations if called more than
|
|
33
|
-
# once (e.g. in tests or misconfigured initializers).
|
|
34
|
-
#
|
|
46
|
+
# once (e.g. in tests or misconfigured initializers). The skip methods
|
|
47
|
+
# are idempotent so duplicates are harmless, but this keeps things tidy.
|
|
35
48
|
return if @callback_name
|
|
36
49
|
|
|
37
50
|
@callback_name = resolve_callback(framework, callback)
|
|
51
|
+
@framework = framework&.to_sym
|
|
38
52
|
# @prepared is intentionally NOT cleared by reset!. This ensures
|
|
39
53
|
# at most one to_prepare block is registered per process lifetime.
|
|
40
54
|
# Trade-off: after reset! + apply (e.g. in tests switching
|
|
@@ -64,7 +78,7 @@ module StandardId
|
|
|
64
78
|
end
|
|
65
79
|
|
|
66
80
|
# Whether apply has been called. Used by ControllerPolicy.register to
|
|
67
|
-
# decide if newly loaded controllers need immediate
|
|
81
|
+
# decide if newly loaded controllers need an immediate authorization skip.
|
|
68
82
|
def applied?
|
|
69
83
|
MUTEX.synchronize { !@callback_name.nil? }
|
|
70
84
|
end
|
|
@@ -72,10 +86,11 @@ module StandardId
|
|
|
72
86
|
# Apply skips to a single controller. Called by ControllerPolicy.register
|
|
73
87
|
# when a controller is lazily loaded after apply has already been called.
|
|
74
88
|
def apply_to_controller(controller, policy)
|
|
75
|
-
callback = MUTEX.synchronize { @callback_name }
|
|
89
|
+
callback, framework = MUTEX.synchronize { [@callback_name, @framework] }
|
|
76
90
|
return unless callback
|
|
77
91
|
|
|
78
|
-
controller
|
|
92
|
+
skip_authorization_callback(controller, callback, framework)
|
|
93
|
+
|
|
79
94
|
if policy == :public
|
|
80
95
|
# authenticate_account! is defined in WebAuthentication, not on API
|
|
81
96
|
# controllers. raise: false ensures this is a safe no-op for API
|
|
@@ -94,11 +109,15 @@ module StandardId
|
|
|
94
109
|
end
|
|
95
110
|
|
|
96
111
|
# @api private — intended for test isolation only.
|
|
97
|
-
# NOTE: This clears @callback_name (so applied? returns
|
|
98
|
-
# can be called again with a different framework) but
|
|
99
|
-
# NOT clear @prepared, so no additional to_prepare
|
|
112
|
+
# NOTE: This clears @callback_name and @framework (so applied? returns
|
|
113
|
+
# false and apply can be called again with a different framework) but
|
|
114
|
+
# intentionally does NOT clear @prepared, so no additional to_prepare
|
|
115
|
+
# block is registered.
|
|
100
116
|
def reset!
|
|
101
|
-
MUTEX.synchronize
|
|
117
|
+
MUTEX.synchronize do
|
|
118
|
+
@callback_name = nil
|
|
119
|
+
@framework = nil
|
|
120
|
+
end
|
|
102
121
|
end
|
|
103
122
|
|
|
104
123
|
private
|
|
@@ -116,6 +135,36 @@ module StandardId
|
|
|
116
135
|
raise ArgumentError, "Provide either framework: or callback:"
|
|
117
136
|
end
|
|
118
137
|
end
|
|
138
|
+
|
|
139
|
+
# Picks the right skip mechanism based on how the framework registers
|
|
140
|
+
# its authorization check:
|
|
141
|
+
#
|
|
142
|
+
# - ActionPolicy: provides `skip_verify_authorized` class method
|
|
143
|
+
# - Pundit: uses after_action, so `skip_after_action` is needed
|
|
144
|
+
# - CanCanCan: uses before_action, so `skip_before_action` works
|
|
145
|
+
# - Custom callback: assumed to be a before_action (caller can use
|
|
146
|
+
# framework: for known frameworks)
|
|
147
|
+
def skip_authorization_callback(controller, callback, framework)
|
|
148
|
+
if (class_method = CLASS_METHOD_SKIP[framework])
|
|
149
|
+
# Engine controllers may inherit the skip class method (e.g.
|
|
150
|
+
# skip_verify_authorized from ActionPolicy) via the host app's
|
|
151
|
+
# ApplicationController without having called verify_authorized
|
|
152
|
+
# themselves. Rails raises ArgumentError when trying to skip a
|
|
153
|
+
# callback that was never registered. We match on the message to
|
|
154
|
+
# avoid masking unrelated ArgumentErrors.
|
|
155
|
+
begin
|
|
156
|
+
controller.public_send(class_method) if controller.respond_to?(class_method)
|
|
157
|
+
rescue ArgumentError => e
|
|
158
|
+
raise unless e.message.include?(":#{callback} has not been defined")
|
|
159
|
+
|
|
160
|
+
Rails.logger.debug { "[StandardId] Skipped #{class_method} on #{controller.name}: #{e.message}" }
|
|
161
|
+
end
|
|
162
|
+
elsif AFTER_ACTION_FRAMEWORKS.include?(framework)
|
|
163
|
+
controller.skip_after_action callback, raise: false
|
|
164
|
+
else
|
|
165
|
+
controller.skip_before_action callback, raise: false
|
|
166
|
+
end
|
|
167
|
+
end
|
|
119
168
|
end
|
|
120
169
|
end
|
|
121
170
|
end
|
|
@@ -18,6 +18,9 @@ StandardConfig.schema.draw do
|
|
|
18
18
|
field :use_inertia, type: :boolean, default: false
|
|
19
19
|
field :inertia_component_namespace, type: :string, default: "standard_id"
|
|
20
20
|
field :alias_current_user, type: :boolean, default: false
|
|
21
|
+
# Callable (lambda/proc) that returns a Hash of extra Sentry user context fields.
|
|
22
|
+
# Receives (account, session) where session may be nil. Non-callable values are ignored.
|
|
23
|
+
field :sentry_context, type: :any, default: nil
|
|
21
24
|
end
|
|
22
25
|
|
|
23
26
|
scope :events do
|
data/lib/standard_id/version.rb
CHANGED