Handle the auth connect request. Reads `CF_Authorization` from the cookie header (server-side extraction handles `HttpOnly` cookies) and serves either a waiting page or a styled confirmation page with the token embedded.
(
State(state): State<Arc<ServerState>>,
Query(params): Query<ConnectParams>,
headers: HeaderMap,
)
| 85 | /// handles `HttpOnly` cookies) and serves either a waiting page or a |
| 86 | /// styled confirmation page with the token embedded. |
| 87 | async fn auth_connect( |
| 88 | State(state): State<Arc<ServerState>>, |
| 89 | Query(params): Query<ConnectParams>, |
| 90 | headers: HeaderMap, |
| 91 | ) -> impl IntoResponse { |
| 92 | // Reject codes that don't match the CLI-generated format to prevent |
| 93 | // reflected XSS via crafted URLs. |
| 94 | if !is_valid_code(¶ms.code) { |
| 95 | return Html( |
| 96 | "<html><body><p>Invalid confirmation code format.</p></body></html>".to_string(), |
| 97 | ) |
| 98 | .into_response(); |
| 99 | } |
| 100 | |
| 101 | let cf_token = headers |
| 102 | .get("cookie") |
| 103 | .and_then(|v| v.to_str().ok()) |
| 104 | .and_then(|cookies| extract_cookie(cookies, "CF_Authorization")); |
| 105 | |
| 106 | // Prefer the Host header (set by Cloudflare Tunnel / reverse proxies) |
| 107 | // so the page shows the external URL the user actually connected through |
| 108 | // rather than the internal bind address (e.g. 0.0.0.0:8080). |
| 109 | let gateway_display = headers |
| 110 | .get("x-forwarded-host") |
| 111 | .or_else(|| headers.get("host")) |
| 112 | .and_then(|v| v.to_str().ok()) |
| 113 | .map_or_else(|| state.config.bind_address.to_string(), String::from); |
| 114 | |
| 115 | let safe_gateway = html_escape(&gateway_display); |
| 116 | |
| 117 | if let Some(token) = cf_token { |
| 118 | let nonce = uuid::Uuid::new_v4().to_string(); |
| 119 | let csp = format!( |
| 120 | "default-src 'none'; script-src 'nonce-{nonce}'; style-src 'unsafe-inline'; connect-src http://127.0.0.1:*" |
| 121 | ); |
| 122 | ( |
| 123 | [(header::CONTENT_SECURITY_POLICY, csp)], |
| 124 | Html(render_connect_page( |
| 125 | &safe_gateway, |
| 126 | params.callback_port, |
| 127 | &token, |
| 128 | ¶ms.code, |
| 129 | &nonce, |
| 130 | )), |
| 131 | ) |
| 132 | .into_response() |
| 133 | } else { |
| 134 | let csp = "default-src 'none'; style-src 'unsafe-inline'".to_string(); |
| 135 | ( |
| 136 | [(header::CONTENT_SECURITY_POLICY, csp)], |
| 137 | Html(render_waiting_page(params.callback_port, ¶ms.code)), |
| 138 | ) |
| 139 | .into_response() |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | /// Extract a named cookie value from a `Cookie` header string. |
| 144 | fn extract_cookie(cookies: &str, name: &str) -> Option<String> { |
nothing calls this directly
no test coverage detected