auth-sanitizer 0.1.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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +46 -0
- data/CITATION.cff +20 -0
- data/CODE_OF_CONDUCT.md +139 -0
- data/CONTRIBUTING.md +227 -0
- data/FUNDING.md +74 -0
- data/README.md +532 -0
- data/REEK +2 -0
- data/RUBOCOP.md +71 -0
- data/SECURITY.md +24 -0
- data/lib/auth/sanitizer/filtered_attributes.rb +109 -0
- data/lib/auth/sanitizer/sanitized_logger.rb +244 -0
- data/lib/auth/sanitizer/thing_filter.rb +58 -0
- data/lib/auth/sanitizer/version.rb +10 -0
- data/lib/auth/sanitizer.rb +77 -0
- data/sig/auth/sanitizer.rbs +6 -0
- data.tar.gz.sig +1 -0
- metadata +288 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Auth
|
|
4
|
+
module Sanitizer
|
|
5
|
+
# Mixin that redacts sensitive instance variables in `#inspect` output.
|
|
6
|
+
#
|
|
7
|
+
# Classes include this module and declare which attribute names should be
|
|
8
|
+
# filtered via {.filtered_attributes}. Matching and replacement behavior is
|
|
9
|
+
# delegated to {ThingFilter}, which is initialized once per object.
|
|
10
|
+
#
|
|
11
|
+
# This means existing objects keep the filter configuration that was present
|
|
12
|
+
# when they were initialized, even if global config or class-level filter
|
|
13
|
+
# declarations change later.
|
|
14
|
+
#
|
|
15
|
+
# The label used for redaction is resolved from {Auth::Sanitizer.filtered_label}
|
|
16
|
+
# at object initialization time. Host gems may customize this by installing a
|
|
17
|
+
# provider via {Auth::Sanitizer.filtered_label_provider=}.
|
|
18
|
+
module FilteredAttributes
|
|
19
|
+
class << self
|
|
20
|
+
# Hook invoked when the module is included. Extends the including class with
|
|
21
|
+
# class-level helpers and prepends the initializer hook.
|
|
22
|
+
#
|
|
23
|
+
# @param [Class] base The including class
|
|
24
|
+
# @return [void]
|
|
25
|
+
def included(base)
|
|
26
|
+
base.extend(ClassMethods)
|
|
27
|
+
base.prepend(InitializerMethods)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Initializer hook that snapshots the thing filter for this object.
|
|
32
|
+
#
|
|
33
|
+
# The snapshot captures both the class-level filtered attribute names and
|
|
34
|
+
# the current {Auth::Sanitizer.filtered_label} value.
|
|
35
|
+
module InitializerMethods
|
|
36
|
+
def initialize(*args, &block)
|
|
37
|
+
super(*args, &block)
|
|
38
|
+
@thing_filter = ThingFilter.new(
|
|
39
|
+
self.class.filtered_attribute_names,
|
|
40
|
+
label: Auth::Sanitizer.filtered_label,
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Class-level helpers for configuring filtered attributes.
|
|
46
|
+
module ClassMethods
|
|
47
|
+
class << self
|
|
48
|
+
# Declare attributes that should be redacted in inspect output.
|
|
49
|
+
#
|
|
50
|
+
# @param [Array<Symbol, String>] attributes One or more attribute names
|
|
51
|
+
# @return [void]
|
|
52
|
+
def filtered_attributes(base, *attributes)
|
|
53
|
+
base.instance_variable_set(:@filtered_attribute_names, attributes.map(&:to_sym))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# The configured attribute names to filter.
|
|
57
|
+
#
|
|
58
|
+
# @param [Class] base The class to get filtered attributes for
|
|
59
|
+
# @return [Array<Symbol>]
|
|
60
|
+
def filtered_attribute_names(base)
|
|
61
|
+
return [] unless base.instance_variable_defined?(:@filtered_attribute_names)
|
|
62
|
+
|
|
63
|
+
base.instance_variable_get(:@filtered_attribute_names) || []
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Declare attributes that should be redacted in inspect output.
|
|
68
|
+
#
|
|
69
|
+
# @param [Array<Symbol, String>] attributes One or more attribute names
|
|
70
|
+
# @return [void]
|
|
71
|
+
def filtered_attributes(*attributes)
|
|
72
|
+
ClassMethods.filtered_attributes(self, *attributes)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# The configured attribute names to filter.
|
|
76
|
+
#
|
|
77
|
+
# @return [Array<Symbol>]
|
|
78
|
+
def filtered_attribute_names
|
|
79
|
+
ClassMethods.filtered_attribute_names(self)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# The initialized thing filter used by this object.
|
|
84
|
+
#
|
|
85
|
+
# This is a per-instance snapshot created during initialization.
|
|
86
|
+
#
|
|
87
|
+
# @return [ThingFilter]
|
|
88
|
+
def thing_filter
|
|
89
|
+
@thing_filter
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Custom inspect that redacts configured attributes.
|
|
93
|
+
#
|
|
94
|
+
# @return [String]
|
|
95
|
+
def inspect
|
|
96
|
+
return super if thing_filter.things.empty?
|
|
97
|
+
|
|
98
|
+
inspected_vars = instance_variables.map do |var|
|
|
99
|
+
if thing_filter.filtered?(var)
|
|
100
|
+
"#{var}=#{thing_filter.label}"
|
|
101
|
+
else
|
|
102
|
+
"#{var}=#{instance_variable_get(var).inspect}"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
"#<#{self.class}:#{object_id} #{inspected_vars.join(", ")}>"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Auth
|
|
4
|
+
module Sanitizer
|
|
5
|
+
# Logger wrapper that redacts sensitive values from debug output before
|
|
6
|
+
# delegating to the underlying logger instance.
|
|
7
|
+
#
|
|
8
|
+
# This class is intentionally narrow in scope: it only sanitizes string
|
|
9
|
+
# messages emitted through the logging path and leaves request/response
|
|
10
|
+
# behavior unchanged.
|
|
11
|
+
#
|
|
12
|
+
# The underlying {ThingFilter} is initialized once when the logger wrapper is
|
|
13
|
+
# created, so later config changes do not alter the behavior of existing
|
|
14
|
+
# logger instances.
|
|
15
|
+
class SanitizedLogger
|
|
16
|
+
# Create a new sanitized logger wrapper.
|
|
17
|
+
#
|
|
18
|
+
# @param [#add, #debug, #info, #warn, #error, #fatal, #unknown] logger
|
|
19
|
+
# The underlying logger instance that will receive sanitized messages.
|
|
20
|
+
# @param [Array<String>] filtered_keys
|
|
21
|
+
# Key names whose values should be redacted in debug output.
|
|
22
|
+
# Defaults to {Auth::Sanitizer.default_filtered_keys}.
|
|
23
|
+
# @param [String] label
|
|
24
|
+
# Replacement label for redacted values.
|
|
25
|
+
# Defaults to {Auth::Sanitizer.filtered_label}.
|
|
26
|
+
def initialize(logger, filtered_keys: Auth::Sanitizer.default_filtered_keys, label: Auth::Sanitizer.filtered_label)
|
|
27
|
+
@logger = logger
|
|
28
|
+
@thing_filter = ThingFilter.new(filtered_keys, label: label)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Add a log entry after sanitizing any string payloads.
|
|
32
|
+
#
|
|
33
|
+
# @param [Integer, Symbol, String, nil] severity Logger severity
|
|
34
|
+
# @param [Object, nil] message Optional log message
|
|
35
|
+
# @param [Object, nil] progname Optional program name
|
|
36
|
+
# @yieldreturn [Object] Deferred log message
|
|
37
|
+
# @return [Object] The underlying logger result
|
|
38
|
+
def add(severity, message = nil, progname = nil)
|
|
39
|
+
if block_given?
|
|
40
|
+
@logger.add(severity, sanitize(message), sanitize(progname)) { sanitize(yield) }
|
|
41
|
+
else
|
|
42
|
+
@logger.add(severity, sanitize(message), sanitize(progname))
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Append a message to the underlying logger after sanitization.
|
|
47
|
+
#
|
|
48
|
+
# @param [String] message Message to append
|
|
49
|
+
# @return [Object] The underlying logger result
|
|
50
|
+
def <<(message)
|
|
51
|
+
@logger << sanitize(message)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Log a debug message after sanitization.
|
|
55
|
+
#
|
|
56
|
+
# @param [Object, nil] progname Optional program name
|
|
57
|
+
# @yieldreturn [Object] Deferred log message
|
|
58
|
+
# @return [Object] The underlying logger result
|
|
59
|
+
def debug(progname = nil, &block)
|
|
60
|
+
log(:debug, progname, &block)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Log an info message after sanitization.
|
|
64
|
+
#
|
|
65
|
+
# @param [Object, nil] progname Optional program name
|
|
66
|
+
# @yieldreturn [Object] Deferred log message
|
|
67
|
+
# @return [Object] The underlying logger result
|
|
68
|
+
def info(progname = nil, &block)
|
|
69
|
+
log(:info, progname, &block)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Log a warning message after sanitization.
|
|
73
|
+
#
|
|
74
|
+
# @param [Object, nil] progname Optional program name
|
|
75
|
+
# @yieldreturn [Object] Deferred log message
|
|
76
|
+
# @return [Object] The underlying logger result
|
|
77
|
+
def warn(progname = nil, &block)
|
|
78
|
+
log(:warn, progname, &block)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Log an error message after sanitization.
|
|
82
|
+
#
|
|
83
|
+
# @param [Object, nil] progname Optional program name
|
|
84
|
+
# @yieldreturn [Object] Deferred log message
|
|
85
|
+
# @return [Object] The underlying logger result
|
|
86
|
+
def error(progname = nil, &block)
|
|
87
|
+
log(:error, progname, &block)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Log a fatal message after sanitization.
|
|
91
|
+
#
|
|
92
|
+
# @param [Object, nil] progname Optional program name
|
|
93
|
+
# @yieldreturn [Object] Deferred log message
|
|
94
|
+
# @return [Object] The underlying logger result
|
|
95
|
+
def fatal(progname = nil, &block)
|
|
96
|
+
log(:fatal, progname, &block)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Log an unknown-severity message after sanitization.
|
|
100
|
+
#
|
|
101
|
+
# @param [Object, nil] progname Optional program name
|
|
102
|
+
# @yieldreturn [Object] Deferred log message
|
|
103
|
+
# @return [Object] The underlying logger result
|
|
104
|
+
def unknown(progname = nil, &block)
|
|
105
|
+
log(:unknown, progname, &block)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Close the underlying logger if supported.
|
|
109
|
+
#
|
|
110
|
+
# @return [void]
|
|
111
|
+
def close
|
|
112
|
+
@logger.close if @logger.respond_to?(:close)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Access the formatter of the underlying logger if supported.
|
|
116
|
+
#
|
|
117
|
+
# @return [Object, nil]
|
|
118
|
+
def formatter
|
|
119
|
+
@logger.formatter if @logger.respond_to?(:formatter)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Set the formatter of the underlying logger if supported.
|
|
123
|
+
#
|
|
124
|
+
# @param [Object] formatter Formatter object
|
|
125
|
+
# @return [void]
|
|
126
|
+
def formatter=(formatter)
|
|
127
|
+
@logger.formatter = formatter if @logger.respond_to?(:formatter=)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Access the logger level if supported.
|
|
131
|
+
#
|
|
132
|
+
# @return [Object, nil]
|
|
133
|
+
def level
|
|
134
|
+
@logger.level if @logger.respond_to?(:level)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Set the logger level if supported.
|
|
138
|
+
#
|
|
139
|
+
# @param [Object] level Logger level
|
|
140
|
+
# @return [void]
|
|
141
|
+
def level=(level)
|
|
142
|
+
@logger.level = level if @logger.respond_to?(:level=)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Access the logger progname if supported.
|
|
146
|
+
#
|
|
147
|
+
# @return [Object, nil]
|
|
148
|
+
def progname
|
|
149
|
+
@logger.progname if @logger.respond_to?(:progname)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Set the logger progname if supported.
|
|
153
|
+
#
|
|
154
|
+
# @param [Object] progname Logger progname
|
|
155
|
+
# @return [void]
|
|
156
|
+
def progname=(progname)
|
|
157
|
+
@logger.progname = progname if @logger.respond_to?(:progname=)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Report support for methods provided by the wrapped logger.
|
|
161
|
+
#
|
|
162
|
+
# @param [Symbol] method_name Method name to check
|
|
163
|
+
# @param [Boolean] include_private Whether private methods are considered
|
|
164
|
+
# @return [Boolean]
|
|
165
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
166
|
+
@logger.respond_to?(method_name, include_private) || super
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Delegate unsupported methods to the wrapped logger.
|
|
170
|
+
#
|
|
171
|
+
# @param [Symbol] method_name Method to invoke
|
|
172
|
+
# @param [Array<Object>] args Method arguments
|
|
173
|
+
# @yield Deferred block forwarded to the wrapped logger
|
|
174
|
+
# @return [Object] The delegated result
|
|
175
|
+
def method_missing(method_name, *args, &block)
|
|
176
|
+
return super unless @logger.respond_to?(method_name)
|
|
177
|
+
|
|
178
|
+
@logger.public_send(method_name, *args, &block)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
private
|
|
182
|
+
|
|
183
|
+
# Dispatch a severity-specific log call after sanitization.
|
|
184
|
+
#
|
|
185
|
+
# @param [Symbol] level Logger method name
|
|
186
|
+
# @param [Object, nil] progname Optional program name
|
|
187
|
+
# @yieldreturn [Object] Deferred log message
|
|
188
|
+
# @return [Object] The underlying logger result
|
|
189
|
+
def log(level, progname = nil)
|
|
190
|
+
if block_given?
|
|
191
|
+
@logger.public_send(level, sanitize(progname)) { sanitize(yield) }
|
|
192
|
+
else
|
|
193
|
+
@logger.public_send(level, sanitize(progname))
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Sanitize a logger message when it is a String.
|
|
198
|
+
#
|
|
199
|
+
# @param [Object] message Potential logger payload
|
|
200
|
+
# @return [Object] Unchanged non-String payloads, sanitized String payloads
|
|
201
|
+
def sanitize(message)
|
|
202
|
+
return message unless message.is_a?(String)
|
|
203
|
+
|
|
204
|
+
sanitized = message.dup
|
|
205
|
+
sanitized = sanitize_authorization_header(sanitized)
|
|
206
|
+
sanitized = sanitize_json_pairs(sanitized)
|
|
207
|
+
sanitize_form_and_query_pairs(sanitized)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# The initialized thing filter used by this logger.
|
|
211
|
+
#
|
|
212
|
+
# This is a per-logger snapshot created during initialization.
|
|
213
|
+
#
|
|
214
|
+
# @return [ThingFilter]
|
|
215
|
+
attr_reader :thing_filter
|
|
216
|
+
|
|
217
|
+
# Redact Authorization header values.
|
|
218
|
+
#
|
|
219
|
+
# @param [String] message Logger message
|
|
220
|
+
# @return [String] Sanitized logger message
|
|
221
|
+
def sanitize_authorization_header(message)
|
|
222
|
+
message.gsub(/(Authorization:\s*)(?:\"[^\"]*\"|[^\r\n]+)/i, "\\1\"#{thing_filter.label}\"")
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Redact JSON-style values for configured sensitive key names.
|
|
226
|
+
#
|
|
227
|
+
# @param [String] message Logger message
|
|
228
|
+
# @return [String] Sanitized logger message
|
|
229
|
+
def sanitize_json_pairs(message)
|
|
230
|
+
message.gsub(/([\"'])(#{thing_filter.pattern_source})\1(\s*:\s*)([\"'])(.*?)\4/i) do
|
|
231
|
+
%(#{$1}#{$2}#{$1}#{$3}#{$4}#{thing_filter.label}#{$4})
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Redact form-encoded and query-string values for configured sensitive key names.
|
|
236
|
+
#
|
|
237
|
+
# @param [String] message Logger message
|
|
238
|
+
# @return [String] Sanitized logger message
|
|
239
|
+
def sanitize_form_and_query_pairs(message)
|
|
240
|
+
message.gsub(/(\b(?:#{thing_filter.pattern_source})=)([^&\s\"]+)/i, "\\1#{thing_filter.label}")
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Auth
|
|
4
|
+
module Sanitizer
|
|
5
|
+
# Small value object for matching and filtering named things.
|
|
6
|
+
#
|
|
7
|
+
# Used by multiple filtering surfaces in the library, such as inspected
|
|
8
|
+
# object attributes and debug-log key filtering.
|
|
9
|
+
#
|
|
10
|
+
# `ThingFilter` snapshots and duplicates its inputs on initialization so later
|
|
11
|
+
# mutation of caller-owned arrays or strings does not affect existing filter
|
|
12
|
+
# instances.
|
|
13
|
+
class ThingFilter
|
|
14
|
+
# Create a new filter.
|
|
15
|
+
#
|
|
16
|
+
# @param [Enumerable<#to_s>] things Names that should be filtered
|
|
17
|
+
# @param [String] label Replacement label to use for filtered values
|
|
18
|
+
#
|
|
19
|
+
# The provided values are duplicated and frozen so the filter remains
|
|
20
|
+
# stable for the lifetime of the object.
|
|
21
|
+
def initialize(things, label:)
|
|
22
|
+
@things = Array(things).map { |thing| thing.to_s.dup.freeze }.freeze
|
|
23
|
+
@label = label.to_s.dup.freeze
|
|
24
|
+
@pattern_source = Regexp.union(@things).source.freeze
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# The configured names that should be filtered.
|
|
28
|
+
#
|
|
29
|
+
# @return [Array<String>]
|
|
30
|
+
attr_reader :things
|
|
31
|
+
|
|
32
|
+
# The configured replacement label.
|
|
33
|
+
#
|
|
34
|
+
# @return [String]
|
|
35
|
+
attr_reader :label
|
|
36
|
+
|
|
37
|
+
# True when the provided name matches any configured filter entry.
|
|
38
|
+
#
|
|
39
|
+
# Matching is substring-based so it works naturally with instance-variable
|
|
40
|
+
# names used by `#inspect`, such as `@secret` matching `secret`.
|
|
41
|
+
#
|
|
42
|
+
# @param [#to_s] thing_name Candidate thing name
|
|
43
|
+
# @return [Boolean]
|
|
44
|
+
def filtered?(thing_name)
|
|
45
|
+
thing_name_str = thing_name.to_s
|
|
46
|
+
things.any? { |thing| thing_name_str.include?(thing) }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Build a regular-expression source for the configured thing names.
|
|
50
|
+
#
|
|
51
|
+
# Useful when a filtering surface needs regex-based replacement rather than
|
|
52
|
+
# direct name checks.
|
|
53
|
+
#
|
|
54
|
+
# @return [String]
|
|
55
|
+
attr_reader :pattern_source
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "version_gem"
|
|
4
|
+
require_relative "sanitizer/version"
|
|
5
|
+
require_relative "sanitizer/thing_filter"
|
|
6
|
+
require_relative "sanitizer/filtered_attributes"
|
|
7
|
+
require_relative "sanitizer/sanitized_logger"
|
|
8
|
+
|
|
9
|
+
Auth::Sanitizer::Version.class_eval do
|
|
10
|
+
extend VersionGem::Basic
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module Auth
|
|
14
|
+
module Sanitizer
|
|
15
|
+
class Error < StandardError; end
|
|
16
|
+
|
|
17
|
+
# Default keys filtered from debug log output.
|
|
18
|
+
DEFAULT_FILTERED_KEYS = %w[
|
|
19
|
+
access_token
|
|
20
|
+
refresh_token
|
|
21
|
+
id_token
|
|
22
|
+
client_secret
|
|
23
|
+
assertion
|
|
24
|
+
code_verifier
|
|
25
|
+
token
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
28
|
+
# Default replacement label for redacted values.
|
|
29
|
+
DEFAULT_FILTERED_LABEL = "[FILTERED]"
|
|
30
|
+
|
|
31
|
+
# Default callable used to provide the filtered replacement label.
|
|
32
|
+
DEFAULT_FILTERED_LABEL_PROVIDER = -> { DEFAULT_FILTERED_LABEL }
|
|
33
|
+
|
|
34
|
+
filtered_label_provider = DEFAULT_FILTERED_LABEL_PROVIDER
|
|
35
|
+
filtered_label_provider_mutex = Mutex.new
|
|
36
|
+
|
|
37
|
+
# Returns the current filtered label by calling the installed provider.
|
|
38
|
+
#
|
|
39
|
+
# Host gems may install a provider that reads from their own config by
|
|
40
|
+
# calling {filtered_label_provider=}.
|
|
41
|
+
#
|
|
42
|
+
# @return [String]
|
|
43
|
+
define_singleton_method(:filtered_label) do
|
|
44
|
+
filtered_label_provider_mutex.synchronize { filtered_label_provider }.call
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Install a custom provider for the filtered label.
|
|
48
|
+
#
|
|
49
|
+
# The provider is called each time a new {FilteredAttributes}- or
|
|
50
|
+
# {SanitizedLogger}-bearing object is initialized, allowing the label to
|
|
51
|
+
# track a host gem's live configuration while still being snapshotted per
|
|
52
|
+
# object instance.
|
|
53
|
+
#
|
|
54
|
+
# @example Delegate to a host gem's config
|
|
55
|
+
# Auth::Sanitizer.filtered_label_provider = -> { MyGem.config[:filtered_label] }
|
|
56
|
+
#
|
|
57
|
+
# @param [#call] provider A callable that returns the label string
|
|
58
|
+
# @return [void]
|
|
59
|
+
define_singleton_method(:filtered_label_provider=) do |provider|
|
|
60
|
+
filtered_label_provider_mutex.synchronize do
|
|
61
|
+
filtered_label_provider = provider
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class << self
|
|
66
|
+
# Returns the default set of key names filtered from debug log output.
|
|
67
|
+
#
|
|
68
|
+
# Host gems may override this by passing `filtered_keys:` directly to
|
|
69
|
+
# {SanitizedLogger#initialize}.
|
|
70
|
+
#
|
|
71
|
+
# @return [Array<String>]
|
|
72
|
+
def default_filtered_keys
|
|
73
|
+
DEFAULT_FILTERED_KEYS
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
data.tar.gz.sig
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rlV�w����|�S6���[={ۿ��-Y��^�rv�ql�pT�ګ����k��b��%j�k�U�LY��NF�'��N(�my/�Z�����U�F�f7/*à�J����n�hH_���3#Н�Xf��� (��}���/f-d��FG�u<��L�&�M ��x2�&V[>6#��ǭf<�kG̲m�k�P�q�ڴtz&�|�1}@?<�&�ی�/iM�����+��7l�_���D:6��̄����B9�r�Xi+�~�Gl��7A̡^Cޢm[��{�o:J�.�x �|��ȟ��^�gq|]ܤ�E��'ا�0Nh1:#P#dBѨ�9�r���mٴ��l��g��:��L$�B���,AvU���G����"�A_�EGв�6
|