1pub mod command;
4pub mod frontend;
5
6pub 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
42pub 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}