otto 2.0.0.pre2 → 2.0.0.pre7
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/.github/workflows/ci.yml +1 -3
- data/.github/workflows/claude-code-review.yml +29 -13
- data/.github/workflows/code-smells.yml +146 -0
- data/.gitignore +4 -0
- data/.pre-commit-config.yaml +2 -2
- data/.reek.yml +99 -0
- data/CHANGELOG.rst +90 -0
- data/CLAUDE.md +116 -45
- data/Gemfile +5 -2
- data/Gemfile.lock +70 -24
- data/README.md +49 -1
- data/changelog.d/20251103_235431_delano_86_improve_error_logging.rst +15 -0
- data/changelog.d/20251109_025012_claude_fix_backtrace_sanitization.rst +37 -0
- data/docs/.gitignore +1 -0
- data/docs/ipaddr-encoding-quirk.md +34 -0
- data/docs/migrating/v2.0.0-pre2.md +11 -18
- data/examples/advanced_routes/README.md +137 -20
- data/examples/authentication_strategies/README.md +212 -19
- data/examples/authentication_strategies/config.ru +0 -1
- data/examples/backtrace_sanitization_demo.rb +86 -0
- data/examples/basic/README.md +61 -10
- data/examples/error_handler_registration.rb +136 -0
- data/examples/logging_improvements.rb +76 -0
- data/examples/mcp_demo/README.md +187 -27
- data/examples/security_features/README.md +249 -30
- data/examples/simple_geo_resolver.rb +107 -0
- data/lib/otto/core/configuration.rb +90 -45
- data/lib/otto/core/error_handler.rb +138 -8
- data/lib/otto/core/file_safety.rb +2 -2
- data/lib/otto/core/freezable.rb +93 -0
- data/lib/otto/core/middleware_stack.rb +25 -18
- data/lib/otto/core/router.rb +62 -9
- data/lib/otto/core/uri_generator.rb +2 -2
- data/lib/otto/core.rb +10 -0
- data/lib/otto/design_system.rb +2 -2
- data/lib/otto/env_keys.rb +65 -12
- data/lib/otto/helpers/base.rb +2 -2
- data/lib/otto/helpers/request.rb +85 -2
- data/lib/otto/helpers/response.rb +5 -5
- data/lib/otto/helpers/validation.rb +2 -2
- data/lib/otto/helpers.rb +6 -0
- data/lib/otto/locale/config.rb +56 -0
- data/lib/otto/locale/middleware.rb +160 -0
- data/lib/otto/locale.rb +10 -0
- data/lib/otto/logging_helpers.rb +273 -0
- data/lib/otto/mcp/auth/token.rb +2 -2
- data/lib/otto/mcp/protocol.rb +2 -2
- data/lib/otto/mcp/rate_limiting.rb +2 -2
- data/lib/otto/mcp/registry.rb +2 -2
- data/lib/otto/mcp/route_parser.rb +2 -2
- data/lib/otto/mcp/schema_validation.rb +2 -2
- data/lib/otto/mcp/server.rb +2 -2
- data/lib/otto/mcp.rb +5 -0
- data/lib/otto/privacy/config.rb +201 -0
- data/lib/otto/privacy/geo_resolver.rb +285 -0
- data/lib/otto/privacy/ip_privacy.rb +177 -0
- data/lib/otto/privacy/redacted_fingerprint.rb +146 -0
- data/lib/otto/privacy.rb +31 -0
- data/lib/otto/response_handlers/auto.rb +2 -0
- data/lib/otto/response_handlers/base.rb +2 -0
- data/lib/otto/response_handlers/default.rb +2 -0
- data/lib/otto/response_handlers/factory.rb +2 -0
- data/lib/otto/response_handlers/json.rb +2 -0
- data/lib/otto/response_handlers/redirect.rb +2 -0
- data/lib/otto/response_handlers/view.rb +2 -0
- data/lib/otto/response_handlers.rb +2 -2
- data/lib/otto/route.rb +4 -4
- data/lib/otto/route_definition.rb +42 -15
- data/lib/otto/route_handlers/base.rb +2 -1
- data/lib/otto/route_handlers/class_method.rb +18 -25
- data/lib/otto/route_handlers/factory.rb +18 -16
- data/lib/otto/route_handlers/instance_method.rb +8 -5
- data/lib/otto/route_handlers/lambda.rb +8 -20
- data/lib/otto/route_handlers/logic_class.rb +25 -8
- data/lib/otto/route_handlers.rb +2 -2
- data/lib/otto/security/authentication/{failure_result.rb → auth_failure.rb} +5 -5
- data/lib/otto/security/authentication/auth_strategy.rb +13 -6
- data/lib/otto/security/authentication/route_auth_wrapper.rb +304 -41
- data/lib/otto/security/authentication/strategies/api_key_strategy.rb +2 -0
- data/lib/otto/security/authentication/strategies/noauth_strategy.rb +7 -1
- data/lib/otto/security/authentication/strategies/permission_strategy.rb +2 -0
- data/lib/otto/security/authentication/strategies/role_strategy.rb +2 -0
- data/lib/otto/security/authentication/strategies/session_strategy.rb +2 -0
- data/lib/otto/security/authentication/strategy_result.rb +6 -5
- data/lib/otto/security/authentication.rb +5 -6
- data/lib/otto/security/authorization_error.rb +73 -0
- data/lib/otto/security/config.rb +53 -9
- data/lib/otto/security/configurator.rb +17 -15
- data/lib/otto/security/csrf.rb +2 -2
- data/lib/otto/security/middleware/csrf_middleware.rb +11 -1
- data/lib/otto/security/middleware/ip_privacy_middleware.rb +231 -0
- data/lib/otto/security/middleware/rate_limit_middleware.rb +2 -0
- data/lib/otto/security/middleware/validation_middleware.rb +15 -0
- data/lib/otto/security/rate_limiter.rb +2 -2
- data/lib/otto/security/rate_limiting.rb +2 -2
- data/lib/otto/security/validator.rb +2 -2
- data/lib/otto/security.rb +12 -0
- data/lib/otto/static.rb +2 -2
- data/lib/otto/utils.rb +27 -2
- data/lib/otto/version.rb +3 -3
- data/lib/otto.rb +344 -89
- data/otto.gemspec +9 -2
- metadata +72 -8
- data/lib/otto/security/authentication/authentication_middleware.rb +0 -140
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: otto
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.0.
|
|
4
|
+
version: 2.0.0.pre7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Delano Mandelbaum
|
|
@@ -9,6 +9,46 @@ bindir: bin
|
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: concurrent-ruby
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.3'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '2.0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - "~>"
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '1.3'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '2.0'
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: ipaddr
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - "~>"
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '1'
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '2.0'
|
|
42
|
+
type: :runtime
|
|
43
|
+
prerelease: false
|
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - "~>"
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '1'
|
|
49
|
+
- - "<"
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '2.0'
|
|
12
52
|
- !ruby/object:Gem::Dependency
|
|
13
53
|
name: logger
|
|
14
54
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -67,16 +107,16 @@ dependencies:
|
|
|
67
107
|
name: rexml
|
|
68
108
|
requirement: !ruby/object:Gem::Requirement
|
|
69
109
|
requirements:
|
|
70
|
-
- - "
|
|
110
|
+
- - "~>"
|
|
71
111
|
- !ruby/object:Gem::Version
|
|
72
|
-
version: 3.
|
|
112
|
+
version: '3.4'
|
|
73
113
|
type: :runtime
|
|
74
114
|
prerelease: false
|
|
75
115
|
version_requirements: !ruby/object:Gem::Requirement
|
|
76
116
|
requirements:
|
|
77
|
-
- - "
|
|
117
|
+
- - "~>"
|
|
78
118
|
- !ruby/object:Gem::Version
|
|
79
|
-
version: 3.
|
|
119
|
+
version: '3.4'
|
|
80
120
|
- !ruby/object:Gem::Dependency
|
|
81
121
|
name: facets
|
|
82
122
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -115,9 +155,11 @@ files:
|
|
|
115
155
|
- ".github/workflows/ci.yml"
|
|
116
156
|
- ".github/workflows/claude-code-review.yml"
|
|
117
157
|
- ".github/workflows/claude.yml"
|
|
158
|
+
- ".github/workflows/code-smells.yml"
|
|
118
159
|
- ".gitignore"
|
|
119
160
|
- ".pre-commit-config.yaml"
|
|
120
161
|
- ".pre-push-config.yaml"
|
|
162
|
+
- ".reek.yml"
|
|
121
163
|
- ".rspec"
|
|
122
164
|
- ".rubocop.yml"
|
|
123
165
|
- CHANGELOG.rst
|
|
@@ -127,9 +169,12 @@ files:
|
|
|
127
169
|
- LICENSE.txt
|
|
128
170
|
- README.md
|
|
129
171
|
- bin/rspec
|
|
172
|
+
- changelog.d/20251103_235431_delano_86_improve_error_logging.rst
|
|
173
|
+
- changelog.d/20251109_025012_claude_fix_backtrace_sanitization.rst
|
|
130
174
|
- changelog.d/README.md
|
|
131
175
|
- changelog.d/scriv.ini
|
|
132
176
|
- docs/.gitignore
|
|
177
|
+
- docs/ipaddr-encoding-quirk.md
|
|
133
178
|
- docs/migrating/v2.0.0-pre1.md
|
|
134
179
|
- docs/migrating/v2.0.0-pre2.md
|
|
135
180
|
- examples/.gitignore
|
|
@@ -173,10 +218,13 @@ files:
|
|
|
173
218
|
- examples/authentication_strategies/app/controllers/main_controller.rb
|
|
174
219
|
- examples/authentication_strategies/config.ru
|
|
175
220
|
- examples/authentication_strategies/routes
|
|
221
|
+
- examples/backtrace_sanitization_demo.rb
|
|
176
222
|
- examples/basic/README.md
|
|
177
223
|
- examples/basic/app.rb
|
|
178
224
|
- examples/basic/config.ru
|
|
179
225
|
- examples/basic/routes
|
|
226
|
+
- examples/error_handler_registration.rb
|
|
227
|
+
- examples/logging_improvements.rb
|
|
180
228
|
- examples/mcp_demo/README.md
|
|
181
229
|
- examples/mcp_demo/app.rb
|
|
182
230
|
- examples/mcp_demo/config.ru
|
|
@@ -185,19 +233,28 @@ files:
|
|
|
185
233
|
- examples/security_features/app.rb
|
|
186
234
|
- examples/security_features/config.ru
|
|
187
235
|
- examples/security_features/routes
|
|
236
|
+
- examples/simple_geo_resolver.rb
|
|
188
237
|
- lib/otto.rb
|
|
238
|
+
- lib/otto/core.rb
|
|
189
239
|
- lib/otto/core/configuration.rb
|
|
190
240
|
- lib/otto/core/error_handler.rb
|
|
191
241
|
- lib/otto/core/file_safety.rb
|
|
242
|
+
- lib/otto/core/freezable.rb
|
|
192
243
|
- lib/otto/core/middleware_stack.rb
|
|
193
244
|
- lib/otto/core/router.rb
|
|
194
245
|
- lib/otto/core/uri_generator.rb
|
|
195
246
|
- lib/otto/design_system.rb
|
|
196
247
|
- lib/otto/env_keys.rb
|
|
248
|
+
- lib/otto/helpers.rb
|
|
197
249
|
- lib/otto/helpers/base.rb
|
|
198
250
|
- lib/otto/helpers/request.rb
|
|
199
251
|
- lib/otto/helpers/response.rb
|
|
200
252
|
- lib/otto/helpers/validation.rb
|
|
253
|
+
- lib/otto/locale.rb
|
|
254
|
+
- lib/otto/locale/config.rb
|
|
255
|
+
- lib/otto/locale/middleware.rb
|
|
256
|
+
- lib/otto/logging_helpers.rb
|
|
257
|
+
- lib/otto/mcp.rb
|
|
201
258
|
- lib/otto/mcp/auth/token.rb
|
|
202
259
|
- lib/otto/mcp/protocol.rb
|
|
203
260
|
- lib/otto/mcp/rate_limiting.rb
|
|
@@ -205,6 +262,11 @@ files:
|
|
|
205
262
|
- lib/otto/mcp/route_parser.rb
|
|
206
263
|
- lib/otto/mcp/schema_validation.rb
|
|
207
264
|
- lib/otto/mcp/server.rb
|
|
265
|
+
- lib/otto/privacy.rb
|
|
266
|
+
- lib/otto/privacy/config.rb
|
|
267
|
+
- lib/otto/privacy/geo_resolver.rb
|
|
268
|
+
- lib/otto/privacy/ip_privacy.rb
|
|
269
|
+
- lib/otto/privacy/redacted_fingerprint.rb
|
|
208
270
|
- lib/otto/response_handlers.rb
|
|
209
271
|
- lib/otto/response_handlers/auto.rb
|
|
210
272
|
- lib/otto/response_handlers/base.rb
|
|
@@ -222,10 +284,10 @@ files:
|
|
|
222
284
|
- lib/otto/route_handlers/instance_method.rb
|
|
223
285
|
- lib/otto/route_handlers/lambda.rb
|
|
224
286
|
- lib/otto/route_handlers/logic_class.rb
|
|
287
|
+
- lib/otto/security.rb
|
|
225
288
|
- lib/otto/security/authentication.rb
|
|
289
|
+
- lib/otto/security/authentication/auth_failure.rb
|
|
226
290
|
- lib/otto/security/authentication/auth_strategy.rb
|
|
227
|
-
- lib/otto/security/authentication/authentication_middleware.rb
|
|
228
|
-
- lib/otto/security/authentication/failure_result.rb
|
|
229
291
|
- lib/otto/security/authentication/route_auth_wrapper.rb
|
|
230
292
|
- lib/otto/security/authentication/strategies/api_key_strategy.rb
|
|
231
293
|
- lib/otto/security/authentication/strategies/noauth_strategy.rb
|
|
@@ -233,10 +295,12 @@ files:
|
|
|
233
295
|
- lib/otto/security/authentication/strategies/role_strategy.rb
|
|
234
296
|
- lib/otto/security/authentication/strategies/session_strategy.rb
|
|
235
297
|
- lib/otto/security/authentication/strategy_result.rb
|
|
298
|
+
- lib/otto/security/authorization_error.rb
|
|
236
299
|
- lib/otto/security/config.rb
|
|
237
300
|
- lib/otto/security/configurator.rb
|
|
238
301
|
- lib/otto/security/csrf.rb
|
|
239
302
|
- lib/otto/security/middleware/csrf_middleware.rb
|
|
303
|
+
- lib/otto/security/middleware/ip_privacy_middleware.rb
|
|
240
304
|
- lib/otto/security/middleware/rate_limit_middleware.rb
|
|
241
305
|
- lib/otto/security/middleware/validation_middleware.rb
|
|
242
306
|
- lib/otto/security/rate_limiter.rb
|
|
@@ -270,7 +334,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
270
334
|
- !ruby/object:Gem::Version
|
|
271
335
|
version: '0'
|
|
272
336
|
requirements: []
|
|
273
|
-
rubygems_version: 3.
|
|
337
|
+
rubygems_version: 3.7.2
|
|
274
338
|
specification_version: 4
|
|
275
339
|
summary: Auto-define your rack-apps in plaintext.
|
|
276
340
|
test_files: []
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'strategy_result'
|
|
4
|
-
require_relative 'failure_result'
|
|
5
|
-
require_relative 'route_auth_wrapper'
|
|
6
|
-
require_relative 'strategies/noauth_strategy'
|
|
7
|
-
require_relative 'strategies/role_strategy'
|
|
8
|
-
require_relative 'strategies/permission_strategy'
|
|
9
|
-
|
|
10
|
-
class Otto
|
|
11
|
-
module Security
|
|
12
|
-
module Authentication
|
|
13
|
-
# Authentication middleware that enforces route-level auth requirements
|
|
14
|
-
class AuthenticationMiddleware
|
|
15
|
-
def initialize(app, security_config = {}, config = {})
|
|
16
|
-
@app = app
|
|
17
|
-
@security_config = security_config
|
|
18
|
-
@config = config
|
|
19
|
-
@strategies = config[:auth_strategies] || {}
|
|
20
|
-
@default_strategy = config[:default_auth_strategy] || 'noauth'
|
|
21
|
-
|
|
22
|
-
# Add default noauth strategy if not provided
|
|
23
|
-
@strategies['noauth'] ||= Strategies::NoAuthStrategy.new
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def call(env)
|
|
27
|
-
# Check if this route has auth requirements
|
|
28
|
-
route_definition = env['otto.route_definition']
|
|
29
|
-
|
|
30
|
-
# If no route definition, create anonymous result and continue
|
|
31
|
-
unless route_definition
|
|
32
|
-
env['otto.strategy_result'] = Otto::Security::Authentication::StrategyResult.anonymous(
|
|
33
|
-
metadata: { ip: env['REMOTE_ADDR'] }
|
|
34
|
-
)
|
|
35
|
-
return @app.call(env)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
auth_requirement = route_definition.auth_requirement
|
|
39
|
-
|
|
40
|
-
# If no auth requirement, create anonymous result and continue
|
|
41
|
-
unless auth_requirement
|
|
42
|
-
env['otto.strategy_result'] = Otto::Security::Authentication::StrategyResult.anonymous(
|
|
43
|
-
metadata: { ip: env['REMOTE_ADDR'] }
|
|
44
|
-
)
|
|
45
|
-
return @app.call(env)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Find appropriate strategy
|
|
49
|
-
strategy = find_strategy(auth_requirement)
|
|
50
|
-
return auth_error_response("Unknown authentication strategy: #{auth_requirement}") unless strategy
|
|
51
|
-
|
|
52
|
-
# Perform authentication
|
|
53
|
-
strategy_result = strategy.authenticate(env, auth_requirement)
|
|
54
|
-
|
|
55
|
-
# Check result type: FailureResult indicates auth failure, StrategyResult indicates success
|
|
56
|
-
if strategy_result.is_a?(Otto::Security::Authentication::FailureResult)
|
|
57
|
-
# Failure - create anonymous result with failure info
|
|
58
|
-
failure_reason = strategy_result.failure_reason || 'Authentication failed'
|
|
59
|
-
env['otto.strategy_result'] = Otto::Security::Authentication::StrategyResult.anonymous(
|
|
60
|
-
metadata: {
|
|
61
|
-
ip: env['REMOTE_ADDR'],
|
|
62
|
-
auth_failure: failure_reason,
|
|
63
|
-
attempted_strategy: auth_requirement,
|
|
64
|
-
}
|
|
65
|
-
)
|
|
66
|
-
auth_error_response(failure_reason)
|
|
67
|
-
else
|
|
68
|
-
# Success - store the strategy result directly
|
|
69
|
-
env['otto.strategy_result'] = strategy_result
|
|
70
|
-
|
|
71
|
-
# SESSION PERSISTENCE: This assignment is INTENTIONAL, not a merge operation.
|
|
72
|
-
# We must ensure env['rack.session'] and strategy_result.session reference
|
|
73
|
-
# the SAME object so that:
|
|
74
|
-
# 1. Logic classes write to strategy_result.session
|
|
75
|
-
# 2. Rack's session middleware persists env['rack.session']
|
|
76
|
-
# 3. Changes from (1) are included in (2)
|
|
77
|
-
#
|
|
78
|
-
# Using merge! instead would break this - the objects must be identical.
|
|
79
|
-
# See commit ed7fa0d for the bug this fixes.
|
|
80
|
-
env['rack.session'] = strategy_result.session if strategy_result.session
|
|
81
|
-
env['otto.user'] = strategy_result.user # For convenience
|
|
82
|
-
env['otto.user_context'] = strategy_result.user_context # For convenience
|
|
83
|
-
@app.call(env)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
private
|
|
88
|
-
|
|
89
|
-
def find_strategy(requirement)
|
|
90
|
-
# Try exact match first - this has highest priority
|
|
91
|
-
return @strategies[requirement] if @strategies[requirement]
|
|
92
|
-
|
|
93
|
-
# For colon-separated requirements like "role:admin", try prefix match
|
|
94
|
-
if requirement.include?(':')
|
|
95
|
-
prefix = requirement.split(':', 2).first
|
|
96
|
-
|
|
97
|
-
# Check if we have a strategy registered for the prefix
|
|
98
|
-
prefix_strategy = @strategies[prefix]
|
|
99
|
-
return prefix_strategy if prefix_strategy
|
|
100
|
-
|
|
101
|
-
# Try fallback patterns for role: and permission: requirements
|
|
102
|
-
if requirement.start_with?('role:')
|
|
103
|
-
return @strategies['role'] || Strategies::RoleStrategy.new([])
|
|
104
|
-
elsif requirement.start_with?('permission:')
|
|
105
|
-
return @strategies['permission'] || Strategies::PermissionStrategy.new([])
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
nil
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def auth_error_response(message)
|
|
113
|
-
body = JSON.generate({
|
|
114
|
-
error: 'Authentication Required',
|
|
115
|
-
message: message,
|
|
116
|
-
timestamp: Time.now.to_i,
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
headers = {
|
|
120
|
-
'Content-Type' => 'application/json',
|
|
121
|
-
'Content-Length' => body.bytesize.to_s,
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
# Add security headers if available from config hash or Otto instance
|
|
125
|
-
# NOTE: Extracting this to a method was considered but rejected.
|
|
126
|
-
# This logic appears only once and is clear in context. Extraction would
|
|
127
|
-
# add ~10 lines (method def + docs) for a 5-line single-use block without
|
|
128
|
-
# improving readability. Consider extracting if this pattern is duplicated.
|
|
129
|
-
if @config.is_a?(Hash) && @config[:security_headers]
|
|
130
|
-
headers.merge!(@config[:security_headers])
|
|
131
|
-
elsif @config.respond_to?(:security_config) && @config.security_config
|
|
132
|
-
headers.merge!(@config.security_config.security_headers)
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
[401, headers, [body]]
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|