Class: Otto::CaddyTLS::Server
- Inherits:
-
Object
- Object
- Otto::CaddyTLS::Server
- Defined in:
- lib/otto/caddy_tls/server.rb
Overview
Registers the permission route and (by default) the localhost guard, and wraps the app-supplied decision block with fail-closed semantics.
Mirrors +Otto::MCP::Server+: a small per-integration object that owns its route and middleware registration and is referenced by its handler.
Instance Attribute Summary collapse
-
#endpoint ⇒ String?
readonly
The registered endpoint path.
-
#otto ⇒ Otto
readonly
The owning Otto instance.
Instance Method Summary collapse
-
#enable!(endpoint:, localhost_only:, permission:) ⇒ void
Enable the integration.
-
#enabled? ⇒ Boolean
-
#initialize(otto) ⇒ Server
constructor
A new instance of Server.
-
#permit?(domain) ⇒ Boolean
Fail-closed decision wrapper.
Constructor Details
#initialize(otto) ⇒ Server
Returns a new instance of Server.
24 25 26 27 |
# File 'lib/otto/caddy_tls/server.rb', line 24 def initialize(otto) @otto = otto @enabled = false end |
Instance Attribute Details
#endpoint ⇒ String? (readonly)
Returns the registered endpoint path.
21 22 23 |
# File 'lib/otto/caddy_tls/server.rb', line 21 def endpoint @endpoint end |
#otto ⇒ Otto (readonly)
Returns the owning Otto instance.
18 19 20 |
# File 'lib/otto/caddy_tls/server.rb', line 18 def otto @otto end |
Instance Method Details
#enable!(endpoint:, localhost_only:, permission:) ⇒ void
This method returns an undefined value.
Enable the integration. Idempotent: a second call is ignored so the route and guard are never duplicated.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/otto/caddy_tls/server.rb', line 41 def enable!(endpoint:, localhost_only:, permission:) return if @enabled # Normalize once so the guard's endpoint, the router's literal-route # key, and @endpoint all agree. Without this, a configured trailing # slash (or percent-encoding) registers a literal route the router can # never match — requests are normalized before lookup — while the guard # still targets it, so Caddy would get a denial instead of a decision. endpoint = Otto::Utils.normalize_path(endpoint) @endpoint = endpoint @permission = @localhost_only = localhost_only @enabled = true register_route(endpoint) if localhost_only # SECURITY: appended (via #use) so it is OUTERMOST in the stack and # runs BEFORE IPPrivacyMiddleware — the guard must see the raw socket # peer, not the forwarded-header-resolved client IP. See LocalhostGuard. @otto.use(Otto::CaddyTLS::LocalhostGuard, endpoint) else # Explicit opt-out: the endpoint then has no built-in access control, # so it must be isolated at the network layer. Surface that at setup. Otto.structured_log(:warn, '[CaddyTLS] localhost guard disabled (localhost_only: false); endpoint is ' \ 'reachable by any client that can reach this app — ensure network-level isolation', endpoint: endpoint) end # structured_log self-skips :debug unless Otto.debug is set. Otto.structured_log(:debug, '[CaddyTLS] enabled', endpoint: endpoint, localhost_only: localhost_only) end |
#enabled? ⇒ Boolean
30 31 32 |
# File 'lib/otto/caddy_tls/server.rb', line 30 def enabled? @enabled end |
#permit?(domain) ⇒ Boolean
Fail-closed decision wrapper. Any exception, +nil+, or +false+ from the app block denies — a broken decision must never authorize a cert.
82 83 84 85 86 87 88 |
# File 'lib/otto/caddy_tls/server.rb', line 82 def permit?(domain) !!@permission.call(domain) rescue StandardError => e Otto.structured_log(:error, '[CaddyTLS] permission callback raised; denying', domain: domain, error: e., error_class: e.class.name) false end |