Skip to main content

mobius_cli/
lib.rs

1//! Shared terminal frontends.
2
3pub mod command;
4pub mod frontend;
5
6/// Adds optional WebSocket admission only to its explicitly configured endpoint.
7/// # Errors
8///
9/// Returns an error when the bearer endpoint/token configuration is incomplete or invalid.
10pub fn authenticated_endpoint(
11    endpoint: mobius_gateway::client::Endpoint,
12) -> mobius_gateway::Result<mobius_gateway::client::Endpoint> {
13    use std::env::{VarError, var};
14
15    match (var("MOBIUS_GATEWAY_BEARER_ENDPOINT"), var("MOBIUS_GATEWAY_BEARER_TOKEN")) {
16        (Err(VarError::NotPresent), Err(VarError::NotPresent)) => Ok(endpoint),
17        (Ok(scope), Ok(token)) => scoped_bearer(endpoint, &scope, &token),
18        _ => Err(mobius_gateway::Error::Config(
19            "set both MOBIUS_GATEWAY_BEARER_ENDPOINT and MOBIUS_GATEWAY_BEARER_TOKEN for WebSocket admission".into(),
20        )),
21    }
22}
23
24fn scoped_bearer(
25    endpoint: mobius_gateway::client::Endpoint,
26    scope: &str,
27    token: &str,
28) -> mobius_gateway::Result<mobius_gateway::client::Endpoint> {
29    let scope: mobius_gateway::client::Endpoint = scope.parse()?;
30    if !scope.is_websocket() {
31        return Err(mobius_gateway::Error::Config(
32            "WebSocket admission requires a wss:// endpoint".into(),
33        ));
34    }
35    if endpoint == scope {
36        endpoint.with_websocket_bearer(token)
37    } else {
38        Ok(endpoint)
39    }
40}
41
42/// Converts a gateway transport/protocol failure without losing its diagnostic text.
43pub fn gateway_error(error: mobius_gateway::Error) -> mobius::Error {
44    mobius::Error::Stopped(error.to_string())
45}
46
47#[cfg(test)]
48mod tests {
49    #[test]
50    fn websocket_admission_is_scoped_to_the_explicit_secure_endpoint() {
51        let scope = "wss://gateway.example";
52        let endpoint: mobius_gateway::client::Endpoint = scope.parse().expect("endpoint");
53        let authenticated =
54            super::scoped_bearer(endpoint.clone(), "wss://gateway.example:443", "secret")
55                .expect("admission");
56        assert_ne!(authenticated, endpoint);
57        assert_eq!(authenticated.to_string(), scope);
58        assert!(!format!("{authenticated:?}").contains("secret"));
59        for endpoint in [
60            "wss://another.example",
61            "wss://gateway.example.evil.example",
62            "wss://gateway.example:8443",
63            "tls://gateway.example:443",
64            "tcp://127.0.0.1:8741",
65        ] {
66            let endpoint: mobius_gateway::client::Endpoint = endpoint.parse().expect("endpoint");
67            let authenticated = super::scoped_bearer(endpoint.clone(), scope, "secret")
68                .expect("other endpoints receive no admission credential");
69            assert_eq!(authenticated, endpoint);
70        }
71        assert!(super::scoped_bearer(endpoint, "tcp://127.0.0.1:8741", "secret").is_err());
72    }
73}