pub struct Config {
pub server: ServerSection,
pub security: SecuritySection,
pub transport: TransportSection,
pub logging: LoggingSection,
}Expand description
Application configuration.
Fields§
§server: ServerSectionServer configuration.
security: SecuritySectionSecurity configuration.
transport: TransportSectionHow the server is made reachable.
logging: LoggingSectionLogging configuration.
Implementations§
Source§impl Config
impl Config
Sourcepub fn from_file(path: &Path) -> Result<Self, ConfigError>
pub fn from_file(path: &Path) -> Result<Self, ConfigError>
Load configuration from a JSON file.
Sourcepub fn apply_args(&mut self, args: &Args)
pub fn apply_args(&mut self, args: &Args)
Apply CLI argument overrides.
A flag that was passed replaces what the file or the environment said;
a flag that was not passed leaves them alone. That reading is only
possible for arguments that can tell “not passed” from “passed the
default value” — hence host_explicit/port_explicit, since Args
carries 127.0.0.1 and 3000 either way and an unconditional
assignment made a configured bind address unreachable.
It is not a universal, and the exceptions are not accidents. The
boolean flags below (--no-auth, --require-auth, --no-rate-limit,
--cors-allow-any) are one-way: passing one sets it, omitting one
leaves the file’s value, and there is no flag that turns rate limiting
back on from the command line. Documenting the rule as universal has
been tried three times here and was false each time.
Sourcepub fn load(args: &Args) -> Result<Self, ConfigError>
pub fn load(args: &Args) -> Result<Self, ConfigError>
Load configuration with full priority chain.
Priority: CLI args > env vars > config file > defaults
Sourcepub fn allowed_hosts(&self, args: &Args, published: bool) -> Option<Vec<String>>
pub fn allowed_hosts(&self, args: &Args, published: bool) -> Option<Vec<String>>
Host names this server should answer to, or None to accept any.
Only a loopback-bound server that is not published gets a list. That is
exactly where DNS rebinding applies: a browser resolves the attacker’s
name to 127.0.0.1, so the request is same-origin and CORS never sees
it, but the Host header still says whose name it was. A server reached
through a tunnel or relay is deliberately published under a name we may
not know, so checking would only refuse legitimate traffic.
Sourcepub fn tunnel_provider(
&self,
) -> Result<Option<Box<dyn TunnelProvider>>, ConfigError>
pub fn tunnel_provider( &self, ) -> Result<Option<Box<dyn TunnelProvider>>, ConfigError>
Build the tunnel provider this configuration asks for, if any.
Sourcepub fn posture(&self, tunnel_configured: bool, relay_attached: bool) -> Posture
pub fn posture(&self, tunnel_configured: bool, relay_attached: bool) -> Posture
Determine how far this configuration is exposed.
tunnel_configured is a single fact after the CLI (--tunnel/--tunnel-command)
and config file (transport.mode) are merged — this function does not need to know
which input path it came from. relay_attached indicates whether --relay was given.
Bind address is judged by !ip.is_loopback() alone. This condition is the same one
this file already uses for warnings — no new rules are introduced.
Sourcepub fn harden_for_public_exposure(
&mut self,
args: &Args,
) -> Result<PublicExposure, ConfigError>
pub fn harden_for_public_exposure( &mut self, args: &Args, ) -> Result<PublicExposure, ConfigError>
Harden the configuration for a publicly reachable deployment.
Exposing the server through a tunnel turns every weak default into an
internet-facing one, so this is enforced rather than advised:
authentication is switched on, and a key is generated when none was
supplied (the caller reports it — an unusable server would be worse).
--no-auth is refused outright instead of being silently overridden.
An unscoped token is likewise defaulted rather than warned about: it is
scoped to the operator preset unless the consumer already chose a
scope.
The remaining risk is a real but legitimate choice, so it is warned about rather than blocked: rate limiting turned off.
Sourcepub fn ensure_api_key(&mut self) -> Option<String>
pub fn ensure_api_key(&mut self) -> Option<String>
Issue the API key this server will serve with, when authentication is on and nothing supplied one.
Returns the key that was generated — the only copy anyone gets — so the
caller can put it in front of the operator. None means there was
nothing to issue: a key was already supplied, or authentication is off.
Calling it twice is safe for the same reason.
Issuing it here rather than inside the server is what makes it
printable. serve_on has no banner to print on, so a key created there
can only reach the operator as a tracing line — and that line is gone
at -l warn while the server still starts and still refuses every
request that does not carry the key nobody was told.
Sourcepub fn to_server_config(&self) -> Result<ServerConfig, ConfigError>
pub fn to_server_config(&self) -> Result<ServerConfig, ConfigError>
Convert to ServerConfig for the API server.
Sourcepub fn resolved_capabilities(
&self,
) -> Result<Option<CapabilitySet>, ConfigError>
pub fn resolved_capabilities( &self, ) -> Result<Option<CapabilitySet>, ConfigError>
The capability set an issued token will actually carry.
None means nothing narrowed it — the full-control default, which is
the wildcard. Resolved from the same two fields to_server_config uses
and through the same function, so a caller that wants to describe the
scope cannot drift from the one that enforces it. Call it after
harden_for_public_exposure, or the answer predates the promotion.
Sourcepub fn log_filter(&self) -> &str
pub fn log_filter(&self) -> &str
Get the log level filter string.