Rebuilt from the exact zed-industries/zed @ 8c74db00c4053d6c0a9037863d7bd048658da4ca tree (previous orphan was based on a stale/wrong fetch). Same 3-file patch: - serial.rs: add SerialKind::KeyboardEnter - client.rs: store wl_keyboard.enter serial; add latest_serial_of() - window.rs: activate() uses keyboard-enter serial (Mutter focus gate) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
87 lines
2.9 KiB
Rust
87 lines
2.9 KiB
Rust
use crate::entities::User;
|
|
use crate::{AppState, Error, db::UserId, rpc::Principal};
|
|
use anyhow::Context as _;
|
|
use axum::{
|
|
http::{self, Request, StatusCode},
|
|
middleware::Next,
|
|
response::IntoResponse,
|
|
};
|
|
use cloud_api_types::GetAuthenticatedUserResponse;
|
|
pub use rpc::auth::random_token;
|
|
use std::sync::Arc;
|
|
|
|
/// Validates the authorization header and adds an Extension<Principal> to the request.
|
|
/// Authorization: <user-id> <token>
|
|
/// <token> is the access_token attached to that user.
|
|
/// Authorization: "dev-server-token" <token>
|
|
pub async fn validate_header<B>(mut req: Request<B>, next: Next<B>) -> impl IntoResponse {
|
|
let mut auth_header = req
|
|
.headers()
|
|
.get(http::header::AUTHORIZATION)
|
|
.and_then(|header| header.to_str().ok())
|
|
.ok_or_else(|| {
|
|
Error::http(
|
|
StatusCode::UNAUTHORIZED,
|
|
"missing authorization header".to_string(),
|
|
)
|
|
})?
|
|
.split_whitespace();
|
|
|
|
let state = req.extensions().get::<Arc<AppState>>().unwrap();
|
|
|
|
let first = auth_header.next().unwrap_or("");
|
|
if first == "dev-server-token" {
|
|
Err(Error::http(
|
|
StatusCode::UNAUTHORIZED,
|
|
"Dev servers were removed in Zed 0.157 please upgrade to SSH remoting".to_string(),
|
|
))?;
|
|
}
|
|
|
|
let user_id = UserId(first.parse().map_err(|_| {
|
|
Error::http(
|
|
StatusCode::BAD_REQUEST,
|
|
"missing user id in authorization header".to_string(),
|
|
)
|
|
})?);
|
|
|
|
let access_token = auth_header.next().ok_or_else(|| {
|
|
Error::http(
|
|
StatusCode::BAD_REQUEST,
|
|
"missing access token in authorization header".to_string(),
|
|
)
|
|
})?;
|
|
|
|
let http_client = state.http_client.clone().expect("no HTTP client");
|
|
|
|
let response = http_client
|
|
.get(format!("{}/client/users/me", state.config.zed_cloud_url()))
|
|
.header("Content-Type", "application/json")
|
|
.header("Authorization", format!("{user_id} {access_token}"))
|
|
.send()
|
|
.await
|
|
.context("failed to validate access token")?;
|
|
if let Ok(response) = response.error_for_status() {
|
|
let response_body: GetAuthenticatedUserResponse = response
|
|
.json()
|
|
.await
|
|
.context("failed to parse response body")?;
|
|
|
|
let user = User {
|
|
id: UserId(response_body.user.id),
|
|
github_login: response_body.user.github_login,
|
|
avatar_url: response_body.user.avatar_url,
|
|
name: response_body.user.name,
|
|
admin: response_body.user.is_staff,
|
|
connected_once: response_body.user.has_connected_to_collab_once,
|
|
};
|
|
|
|
req.extensions_mut().insert(Principal::User(user));
|
|
return Ok::<_, Error>(next.run(req).await);
|
|
}
|
|
|
|
Err(Error::http(
|
|
StatusCode::UNAUTHORIZED,
|
|
"invalid credentials".to_string(),
|
|
))
|
|
}
|