lapsoss 0.1.0 → 0.2.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/lib/lapsoss/adapters/appsignal_adapter.rb +25 -26
- data/lib/lapsoss/adapters/base.rb +2 -2
- data/lib/lapsoss/adapters/bugsnag_adapter.rb +12 -0
- data/lib/lapsoss/adapters/insight_hub_adapter.rb +29 -32
- data/lib/lapsoss/adapters/logger_adapter.rb +8 -8
- data/lib/lapsoss/adapters/rollbar_adapter.rb +27 -28
- data/lib/lapsoss/adapters/sentry_adapter.rb +23 -29
- data/lib/lapsoss/backtrace_frame.rb +21 -31
- data/lib/lapsoss/backtrace_processor.rb +28 -31
- data/lib/lapsoss/client.rb +4 -6
- data/lib/lapsoss/configuration.rb +48 -41
- data/lib/lapsoss/current.rb +1 -1
- data/lib/lapsoss/event.rb +6 -5
- data/lib/lapsoss/{exclusions.rb → exclusion_filter.rb} +56 -56
- data/lib/lapsoss/fingerprinter.rb +33 -37
- data/lib/lapsoss/http_client.rb +45 -11
- data/lib/lapsoss/middleware.rb +35 -43
- data/lib/lapsoss/pipeline.rb +6 -10
- data/lib/lapsoss/railtie.rb +9 -9
- data/lib/lapsoss/registry.rb +23 -22
- data/lib/lapsoss/release_tracker.rb +160 -182
- data/lib/lapsoss/router.rb +3 -5
- data/lib/lapsoss/sampling.rb +49 -53
- data/lib/lapsoss/scope.rb +6 -10
- data/lib/lapsoss/scrubber.rb +22 -24
- data/lib/lapsoss/user_context.rb +78 -85
- data/lib/lapsoss/validators.rb +13 -26
- data/lib/lapsoss/version.rb +1 -1
- data/lib/lapsoss.rb +12 -25
- metadata +59 -23
data/lib/lapsoss/sampling.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'digest'
|
4
4
|
|
5
5
|
module Lapsoss
|
6
6
|
module Sampling
|
7
7
|
class Base
|
8
|
-
def sample?(
|
8
|
+
def sample?(_event, _hint = {})
|
9
9
|
true
|
10
10
|
end
|
11
11
|
end
|
@@ -15,7 +15,7 @@ module Lapsoss
|
|
15
15
|
@rate = rate
|
16
16
|
end
|
17
17
|
|
18
|
-
def sample?(
|
18
|
+
def sample?(_event, _hint = {})
|
19
19
|
rand < @rate
|
20
20
|
end
|
21
21
|
end
|
@@ -24,13 +24,13 @@ module Lapsoss
|
|
24
24
|
def initialize(max_events_per_second: 10)
|
25
25
|
@max_events_per_second = max_events_per_second
|
26
26
|
@tokens = max_events_per_second
|
27
|
-
@last_refill = Time.now
|
27
|
+
@last_refill = Time.zone.now
|
28
28
|
@mutex = Mutex.new
|
29
29
|
end
|
30
30
|
|
31
|
-
def sample?(
|
31
|
+
def sample?(_event, _hint = {})
|
32
32
|
@mutex.synchronize do
|
33
|
-
now = Time.now
|
33
|
+
now = Time.zone.now
|
34
34
|
time_passed = now - @last_refill
|
35
35
|
|
36
36
|
# Refill tokens based on time passed
|
@@ -53,7 +53,7 @@ module Lapsoss
|
|
53
53
|
@default_rate = rates.fetch(:default, 1.0)
|
54
54
|
end
|
55
55
|
|
56
|
-
def sample?(event,
|
56
|
+
def sample?(event, _hint = {})
|
57
57
|
return @default_rate > rand unless event.exception
|
58
58
|
|
59
59
|
exception_class = event.exception.class
|
@@ -92,7 +92,7 @@ module Lapsoss
|
|
92
92
|
@default_rate = rates.fetch(:default, 1.0)
|
93
93
|
end
|
94
94
|
|
95
|
-
def sample?(event,
|
95
|
+
def sample?(event, _hint = {})
|
96
96
|
user = event.context[:user]
|
97
97
|
return @default_rate > rand unless user
|
98
98
|
|
@@ -104,18 +104,18 @@ module Lapsoss
|
|
104
104
|
|
105
105
|
def find_rate_for_user(user)
|
106
106
|
# Check specific user ID
|
107
|
-
user_id = user[:id] || user[
|
107
|
+
user_id = user[:id] || user['id']
|
108
108
|
return @rates[user_id] if user_id && @rates.key?(user_id)
|
109
109
|
|
110
110
|
# Check user segments
|
111
111
|
@rates.each do |segment, rate|
|
112
112
|
case segment
|
113
|
-
when :internal,
|
114
|
-
return rate if user[:internal] || user[
|
115
|
-
when :premium,
|
116
|
-
return rate if user[:premium] || user[
|
117
|
-
when :beta,
|
118
|
-
return rate if user[:beta] || user[
|
113
|
+
when :internal, 'internal'
|
114
|
+
return rate if user[:internal] || user['internal']
|
115
|
+
when :premium, 'premium'
|
116
|
+
return rate if user[:premium] || user['premium']
|
117
|
+
when :beta, 'beta'
|
118
|
+
return rate if user[:beta] || user['beta']
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
@@ -140,7 +140,7 @@ module Lapsoss
|
|
140
140
|
|
141
141
|
private
|
142
142
|
|
143
|
-
def default_key_extractor(event,
|
143
|
+
def default_key_extractor(event, _hint)
|
144
144
|
# Use fingerprint for consistent sampling
|
145
145
|
event.fingerprint
|
146
146
|
end
|
@@ -152,8 +152,8 @@ module Lapsoss
|
|
152
152
|
@default_rate = schedule.fetch(:default, 1.0)
|
153
153
|
end
|
154
154
|
|
155
|
-
def sample?(
|
156
|
-
now = Time.now
|
155
|
+
def sample?(_event, _hint = {})
|
156
|
+
now = Time.zone.now
|
157
157
|
rate = find_rate_for_time(now)
|
158
158
|
rate > rand
|
159
159
|
end
|
@@ -165,11 +165,11 @@ module Lapsoss
|
|
165
165
|
day_of_week = time.wday # 0 = Sunday
|
166
166
|
|
167
167
|
# Check specific hour
|
168
|
-
hour_key = "hour_#{hour}"
|
168
|
+
hour_key = :"hour_#{hour}"
|
169
169
|
return @schedule[hour_key] if @schedule.key?(hour_key)
|
170
170
|
|
171
171
|
# Check day of week
|
172
|
-
day_names = [
|
172
|
+
day_names = %i[sunday monday tuesday wednesday thursday friday saturday]
|
173
173
|
day_key = day_names[day_of_week]
|
174
174
|
return @schedule[day_key] if @schedule.key?(day_key)
|
175
175
|
|
@@ -179,9 +179,7 @@ module Lapsoss
|
|
179
179
|
end
|
180
180
|
|
181
181
|
# Check weekends
|
182
|
-
if @schedule.key?(:weekends) && [0, 6].include?(day_of_week)
|
183
|
-
return @schedule[:weekends]
|
184
|
-
end
|
182
|
+
return @schedule[:weekends] if @schedule.key?(:weekends) && [0, 6].include?(day_of_week)
|
185
183
|
|
186
184
|
@default_rate
|
187
185
|
end
|
@@ -214,16 +212,16 @@ module Lapsoss
|
|
214
212
|
@adjustment_period = adjustment_period
|
215
213
|
@current_rate = target_rate
|
216
214
|
@events_count = 0
|
217
|
-
@last_adjustment = Time.now
|
215
|
+
@last_adjustment = Time.zone.now
|
218
216
|
@mutex = Mutex.new
|
219
217
|
end
|
220
218
|
|
221
|
-
def sample?(
|
219
|
+
def sample?(_event, _hint = {})
|
222
220
|
@mutex.synchronize do
|
223
221
|
@events_count += 1
|
224
222
|
|
225
223
|
# Adjust rate periodically
|
226
|
-
now = Time.now
|
224
|
+
now = Time.zone.now
|
227
225
|
if now - @last_adjustment > @adjustment_period
|
228
226
|
adjust_rate
|
229
227
|
@last_adjustment = now
|
@@ -234,9 +232,7 @@ module Lapsoss
|
|
234
232
|
@current_rate > rand
|
235
233
|
end
|
236
234
|
|
237
|
-
|
238
|
-
@current_rate
|
239
|
-
end
|
235
|
+
attr_reader :current_rate
|
240
236
|
|
241
237
|
private
|
242
238
|
|
@@ -258,7 +254,7 @@ module Lapsoss
|
|
258
254
|
@low_rate = low_rate
|
259
255
|
end
|
260
256
|
|
261
|
-
def sample?(
|
257
|
+
def sample?(_event, _hint = {})
|
262
258
|
healthy = @health_check.call
|
263
259
|
rate = healthy ? @high_rate : @low_rate
|
264
260
|
rate > rand
|
@@ -275,29 +271,29 @@ module Lapsoss
|
|
275
271
|
|
276
272
|
# Different rates for different exception types
|
277
273
|
ExceptionTypeSampler.new(rates: {
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
274
|
+
# Critical errors - always sample
|
275
|
+
SecurityError => 1.0,
|
276
|
+
SystemStackError => 1.0,
|
277
|
+
NoMemoryError => 1.0,
|
282
278
|
|
283
|
-
|
284
|
-
|
285
|
-
|
279
|
+
# Common errors - sample less
|
280
|
+
ArgumentError => 0.1,
|
281
|
+
TypeError => 0.1,
|
286
282
|
|
287
|
-
|
288
|
-
|
289
|
-
|
283
|
+
# Network errors - medium sampling
|
284
|
+
/timeout/i => 0.3,
|
285
|
+
/connection/i => 0.3,
|
290
286
|
|
291
|
-
|
292
|
-
|
293
|
-
|
287
|
+
# Default for unknown errors
|
288
|
+
default: 0.5
|
289
|
+
}),
|
294
290
|
|
295
291
|
# Lower sampling during business hours
|
296
292
|
TimeBasedSampler.new(schedule: {
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
293
|
+
business_hours: 0.3,
|
294
|
+
weekends: 0.8,
|
295
|
+
default: 0.5
|
296
|
+
})
|
301
297
|
],
|
302
298
|
strategy: :all
|
303
299
|
)
|
@@ -312,16 +308,16 @@ module Lapsoss
|
|
312
308
|
samplers: [
|
313
309
|
# Higher sampling for internal users
|
314
310
|
UserBasedSampler.new(rates: {
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
311
|
+
internal: 1.0,
|
312
|
+
premium: 0.8,
|
313
|
+
beta: 0.9,
|
314
|
+
default: 0.1
|
315
|
+
}),
|
320
316
|
|
321
317
|
# Consistent sampling based on user ID
|
322
318
|
ConsistentHashSampler.new(
|
323
319
|
rate: 0.1,
|
324
|
-
key_extractor: ->(event,
|
320
|
+
key_extractor: ->(event, _hint) { event.context.dig(:user, :id) }
|
325
321
|
)
|
326
322
|
],
|
327
323
|
strategy: :any
|
data/lib/lapsoss/scope.rb
CHANGED
@@ -29,13 +29,11 @@ module Lapsoss
|
|
29
29
|
@extra.merge!(context[:extra] || {})
|
30
30
|
|
31
31
|
# Handle breadcrumbs if provided
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
end
|
32
|
+
return unless context[:breadcrumbs]
|
33
|
+
|
34
|
+
@breadcrumbs.concat(context[:breadcrumbs])
|
35
|
+
# Keep breadcrumbs to a reasonable limit
|
36
|
+
@breadcrumbs.shift while @breadcrumbs.length > 20
|
39
37
|
end
|
40
38
|
|
41
39
|
def clear
|
@@ -97,9 +95,7 @@ module Lapsoss
|
|
97
95
|
def merge_breadcrumbs
|
98
96
|
result = @base_scope.breadcrumbs.dup
|
99
97
|
@scope_stack.each do |context|
|
100
|
-
if context[:breadcrumbs]
|
101
|
-
result.concat(context[:breadcrumbs])
|
102
|
-
end
|
98
|
+
result.concat(context[:breadcrumbs]) if context[:breadcrumbs]
|
103
99
|
end
|
104
100
|
# Add our own breadcrumbs
|
105
101
|
result.concat(@own_breadcrumbs)
|
data/lib/lapsoss/scrubber.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'active_support/parameter_filter'
|
4
4
|
|
5
5
|
module Lapsoss
|
6
6
|
class Scrubber
|
@@ -25,22 +25,20 @@ module Lapsoss
|
|
25
25
|
@rails_parameter_filter = rails_parameter_filter
|
26
26
|
|
27
27
|
# Only use custom scrubbing if Rails parameter filter is not available
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
28
|
+
return if @rails_parameter_filter
|
29
|
+
|
30
|
+
@scrub_fields = Array(config[:scrub_fields] || DEFAULT_SCRUB_FIELDS)
|
31
|
+
@scrub_all = config[:scrub_all] || false
|
32
|
+
@whitelist_fields = Array(config[:whitelist_fields] || [])
|
33
|
+
@randomize_scrub_length = config[:randomize_scrub_length] || false
|
34
|
+
@scrub_value = config[:scrub_value] || '**SCRUBBED**'
|
35
35
|
end
|
36
36
|
|
37
37
|
def scrub(data)
|
38
38
|
return data if data.nil?
|
39
39
|
|
40
40
|
# If Rails parameter filter is available, use it exclusively
|
41
|
-
if @rails_parameter_filter
|
42
|
-
return @rails_parameter_filter.filter(data)
|
43
|
-
end
|
41
|
+
return @rails_parameter_filter.filter(data) if @rails_parameter_filter
|
44
42
|
|
45
43
|
# Fallback to custom scrubbing logic only if Rails filter is not available
|
46
44
|
@scrubbed_objects = {}.compare_by_identity
|
@@ -68,15 +66,15 @@ module Lapsoss
|
|
68
66
|
hash.each_with_object({}) do |(key, value), result|
|
69
67
|
key_string = key.to_s.downcase
|
70
68
|
|
71
|
-
if should_scrub_field?(key_string)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
69
|
+
result[key] = if should_scrub_field?(key_string)
|
70
|
+
generate_scrub_value(value)
|
71
|
+
elsif value.is_a?(Hash)
|
72
|
+
scrub_recursive(value)
|
73
|
+
elsif value.is_a?(Array)
|
74
|
+
scrub_array(value)
|
75
|
+
else
|
76
|
+
scrub_value(value)
|
77
|
+
end
|
80
78
|
end
|
81
79
|
end
|
82
80
|
|
@@ -118,7 +116,7 @@ module Lapsoss
|
|
118
116
|
PROTECTED_EVENT_FIELDS.include?(field_name.to_s)
|
119
117
|
end
|
120
118
|
|
121
|
-
def whitelisted_value?(
|
119
|
+
def whitelisted_value?(_value)
|
122
120
|
# Basic implementation - could be extended
|
123
121
|
false
|
124
122
|
end
|
@@ -136,7 +134,7 @@ module Lapsoss
|
|
136
134
|
original_filename: safe_call(attachment, :original_filename),
|
137
135
|
size: safe_call(attachment, :size) || safe_call(attachment, :tempfile, :size)
|
138
136
|
}
|
139
|
-
rescue => e
|
137
|
+
rescue StandardError => e
|
140
138
|
{ __attachment__: true, error: "Failed to extract attachment info: #{e.message}" }
|
141
139
|
end
|
142
140
|
|
@@ -146,9 +144,9 @@ module Lapsoss
|
|
146
144
|
end
|
147
145
|
end
|
148
146
|
|
149
|
-
def generate_scrub_value(
|
147
|
+
def generate_scrub_value(_original_value)
|
150
148
|
if @randomize_scrub_length
|
151
|
-
|
149
|
+
'*' * rand(6..12)
|
152
150
|
else
|
153
151
|
@scrub_value
|
154
152
|
end
|
data/lib/lapsoss/user_context.rb
CHANGED
@@ -30,16 +30,14 @@ module Lapsoss
|
|
30
30
|
key_sym = key.to_sym
|
31
31
|
|
32
32
|
# Skip if not in allowed fields list (when specified)
|
33
|
-
if @allowed_fields
|
34
|
-
next
|
35
|
-
end
|
33
|
+
next if @allowed_fields&.exclude?(key_sym)
|
36
34
|
|
37
35
|
# Apply privacy filtering
|
38
|
-
if @privacy_mode && sensitive_field?(key_sym)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
36
|
+
processed[key] = if @privacy_mode && sensitive_field?(key_sym)
|
37
|
+
apply_privacy_filter(key_sym, value)
|
38
|
+
else
|
39
|
+
transform_field(key_sym, value)
|
40
|
+
end
|
43
41
|
end
|
44
42
|
|
45
43
|
processed
|
@@ -70,18 +68,18 @@ module Lapsoss
|
|
70
68
|
segments = {}
|
71
69
|
|
72
70
|
# Check for common user segments
|
73
|
-
segments[:internal] =
|
74
|
-
segments[:premium] =
|
75
|
-
segments[:beta] =
|
76
|
-
segments[:admin] =
|
71
|
+
segments[:internal] = !(user_data[:internal] || user_data['internal']).nil?
|
72
|
+
segments[:premium] = !(user_data[:premium] || user_data['premium']).nil?
|
73
|
+
segments[:beta] = !(user_data[:beta] || user_data['beta']).nil?
|
74
|
+
segments[:admin] = !(user_data[:admin] || user_data['admin']).nil?
|
77
75
|
|
78
76
|
# Check role-based segments
|
79
|
-
if role =
|
77
|
+
if role = user_data[:role] || user_data['role']
|
80
78
|
segments[:role] = role.to_s.downcase
|
81
79
|
end
|
82
80
|
|
83
81
|
# Check plan-based segments
|
84
|
-
if plan =
|
82
|
+
if plan = user_data[:plan] || user_data['plan']
|
85
83
|
segments[:plan] = plan.to_s.downcase
|
86
84
|
end
|
87
85
|
|
@@ -96,15 +94,15 @@ module Lapsoss
|
|
96
94
|
user_data.each do |key, value|
|
97
95
|
key_sym = key.to_sym
|
98
96
|
|
99
|
-
if sensitive_field?(key_sym)
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
97
|
+
sanitized[key] = if sensitive_field?(key_sym)
|
98
|
+
'[REDACTED]'
|
99
|
+
elsif value.is_a?(Hash)
|
100
|
+
sanitize_for_logging(value)
|
101
|
+
elsif value.is_a?(Array)
|
102
|
+
value.map { |v| v.is_a?(Hash) ? sanitize_for_logging(v) : v }
|
103
|
+
else
|
104
|
+
value
|
105
|
+
end
|
108
106
|
end
|
109
107
|
|
110
108
|
sanitized
|
@@ -125,7 +123,7 @@ module Lapsoss
|
|
125
123
|
when :ip_address, :last_login_ip
|
126
124
|
mask_ip(value)
|
127
125
|
else
|
128
|
-
|
126
|
+
'[FILTERED]'
|
129
127
|
end
|
130
128
|
end
|
131
129
|
|
@@ -138,38 +136,39 @@ module Lapsoss
|
|
138
136
|
end
|
139
137
|
|
140
138
|
def mask_email(email)
|
141
|
-
return
|
139
|
+
return '[INVALID_EMAIL]' unless email.is_a?(String) && email.include?('@')
|
142
140
|
|
143
|
-
local, domain = email.split(
|
144
|
-
masked_local = local.length > 2 ? "#{local[0]}***#{local[-1]}" :
|
141
|
+
local, domain = email.split('@', 2)
|
142
|
+
masked_local = local.length > 2 ? "#{local[0]}***#{local[-1]}" : '***'
|
145
143
|
"#{masked_local}@#{domain}"
|
146
144
|
end
|
147
145
|
|
148
146
|
def mask_phone(phone)
|
149
|
-
return
|
147
|
+
return '[INVALID_PHONE]' unless phone.is_a?(String)
|
150
148
|
|
151
149
|
# Remove all non-digits
|
152
|
-
digits = phone.gsub(/\D/,
|
153
|
-
return
|
150
|
+
digits = phone.gsub(/\D/, '')
|
151
|
+
return '[INVALID_PHONE]' if digits.length < 4
|
154
152
|
|
155
153
|
# Show last 4 digits
|
156
|
-
|
154
|
+
('*' * (digits.length - 4)) + digits[-4..]
|
157
155
|
end
|
158
156
|
|
159
157
|
def mask_ip(ip)
|
160
|
-
return
|
158
|
+
return '[INVALID_IP]' unless ip.is_a?(String)
|
161
159
|
|
162
|
-
if ip.include?(
|
160
|
+
if ip.include?(':')
|
163
161
|
# IPv6 - mask last 4 groups
|
164
|
-
parts = ip.split(
|
165
|
-
parts[-4..-1] = [
|
166
|
-
parts.join(
|
162
|
+
parts = ip.split(':')
|
163
|
+
parts[-4..-1] = ['****'] * 4 if parts.length >= 4
|
164
|
+
parts.join(':')
|
167
165
|
else
|
168
166
|
# IPv4 - mask last octet
|
169
|
-
parts = ip.split(
|
170
|
-
return
|
171
|
-
|
172
|
-
parts
|
167
|
+
parts = ip.split('.')
|
168
|
+
return '[INVALID_IP]' if parts.length != 4
|
169
|
+
|
170
|
+
parts[-1] = '***'
|
171
|
+
parts.join('.')
|
173
172
|
end
|
174
173
|
end
|
175
174
|
end
|
@@ -185,14 +184,12 @@ module Lapsoss
|
|
185
184
|
|
186
185
|
# Try each provider in order
|
187
186
|
@providers.each do |name, provider|
|
188
|
-
|
189
|
-
|
190
|
-
context.merge!(provider_context)
|
191
|
-
end
|
192
|
-
rescue StandardError => e
|
193
|
-
# Log provider error but don't fail
|
194
|
-
warn "User context provider #{name} failed: #{e.message}"
|
187
|
+
if provider_context = provider.call(event, hint)
|
188
|
+
context.merge!(provider_context)
|
195
189
|
end
|
190
|
+
rescue StandardError => e
|
191
|
+
# Log provider error but don't fail
|
192
|
+
warn "User context provider #{name} failed: #{e.message}"
|
196
193
|
end
|
197
194
|
|
198
195
|
context
|
@@ -200,12 +197,12 @@ module Lapsoss
|
|
200
197
|
|
201
198
|
# Built-in providers for common authentication systems
|
202
199
|
def self.devise_provider
|
203
|
-
lambda do |
|
200
|
+
lambda do |_event, hint|
|
204
201
|
return {} unless defined?(Devise) && defined?(Warden)
|
205
202
|
|
206
203
|
# Try to get user from Warden (used by Devise)
|
207
204
|
if request = hint[:request]
|
208
|
-
user = request.env[
|
205
|
+
user = request.env['warden']&.user
|
209
206
|
return {} unless user
|
210
207
|
|
211
208
|
{
|
@@ -222,19 +219,17 @@ module Lapsoss
|
|
222
219
|
end
|
223
220
|
|
224
221
|
def self.omniauth_provider
|
225
|
-
lambda do |
|
222
|
+
lambda do |_event, hint|
|
226
223
|
return {} unless defined?(OmniAuth)
|
227
224
|
|
228
|
-
if request = hint[:request]
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
}.compact
|
237
|
-
end
|
225
|
+
if (request = hint[:request]) && (auth_info = request.env['omniauth.auth'])
|
226
|
+
{
|
227
|
+
provider: auth_info['provider'],
|
228
|
+
uid: auth_info['uid'],
|
229
|
+
name: auth_info.dig('info', 'name'),
|
230
|
+
email: auth_info.dig('info', 'email'),
|
231
|
+
username: auth_info.dig('info', 'nickname')
|
232
|
+
}.compact
|
238
233
|
end
|
239
234
|
|
240
235
|
{}
|
@@ -242,22 +237,26 @@ module Lapsoss
|
|
242
237
|
end
|
243
238
|
|
244
239
|
def self.session_provider
|
245
|
-
lambda do |
|
240
|
+
lambda do |_event, hint|
|
246
241
|
return {} unless hint[:request]
|
247
242
|
|
248
243
|
request = hint[:request]
|
249
|
-
session =
|
244
|
+
session = begin
|
245
|
+
request.session
|
246
|
+
rescue StandardError
|
247
|
+
{}
|
248
|
+
end
|
250
249
|
|
251
250
|
{
|
252
|
-
session_id: session[:session_id] || session[
|
253
|
-
user_id: session[:user_id] || session[
|
254
|
-
csrf_token: session[:_csrf_token] || session[
|
251
|
+
session_id: session[:session_id] || session['session_id'],
|
252
|
+
user_id: session[:user_id] || session['user_id'],
|
253
|
+
csrf_token: session[:_csrf_token] || session['_csrf_token']
|
255
254
|
}.compact
|
256
255
|
end
|
257
256
|
end
|
258
257
|
|
259
258
|
def self.thread_local_provider
|
260
|
-
lambda do |
|
259
|
+
lambda do |_event, _hint|
|
261
260
|
# Get user from thread-local storage
|
262
261
|
Thread.current[:current_user] || {}
|
263
262
|
end
|
@@ -270,20 +269,18 @@ module Lapsoss
|
|
270
269
|
return unless defined?(Devise)
|
271
270
|
|
272
271
|
# Add middleware to capture user context
|
273
|
-
if defined?(Rails)
|
274
|
-
Rails.application.config.middleware.use(UserContextMiddleware)
|
275
|
-
end
|
272
|
+
Rails.application.config.middleware.use(UserContextMiddleware) if defined?(Rails)
|
276
273
|
end
|
277
274
|
|
278
275
|
def self.setup_clearance_integration
|
279
276
|
return unless defined?(Clearance)
|
280
277
|
|
281
278
|
# Clearance integration
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
279
|
+
return unless defined?(Rails)
|
280
|
+
|
281
|
+
Rails.application.config.middleware.use(UserContextMiddleware) do |middleware|
|
282
|
+
middleware.user_provider = lambda do |request|
|
283
|
+
request.env[:clearance].current_user if request.env[:clearance]
|
287
284
|
end
|
288
285
|
end
|
289
286
|
end
|
@@ -292,11 +289,11 @@ module Lapsoss
|
|
292
289
|
return unless defined?(Authlogic)
|
293
290
|
|
294
291
|
# Authlogic integration
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
292
|
+
return unless defined?(Rails)
|
293
|
+
|
294
|
+
Rails.application.config.middleware.use(UserContextMiddleware) do |middleware|
|
295
|
+
middleware.user_provider = lambda do |_request|
|
296
|
+
UserSession.find&.user if defined?(UserSession)
|
300
297
|
end
|
301
298
|
end
|
302
299
|
end
|
@@ -337,14 +334,10 @@ module Lapsoss
|
|
337
334
|
}
|
338
335
|
|
339
336
|
# Add role information if available
|
340
|
-
if user.respond_to?(:role)
|
341
|
-
context[:role] = user.role
|
342
|
-
end
|
337
|
+
context[:role] = user.role if user.respond_to?(:role)
|
343
338
|
|
344
339
|
# Add plan information if available
|
345
|
-
if user.respond_to?(:plan)
|
346
|
-
context[:plan] = user.plan
|
347
|
-
end
|
340
|
+
context[:plan] = user.plan if user.respond_to?(:plan)
|
348
341
|
|
349
342
|
context.compact
|
350
343
|
else
|