diff --git a/Cargo.toml b/Cargo.toml index 68c42e7..97ae11f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,4 +22,4 @@ urlencoding = "2.1.3" fjall = { git = "https://github.com/90-008/fjall.git", version = "3.1.4", features = ["lz4", "zstd"] } base64 = "0.22.1" futures = "0.3.32" -tower-http = { version = "0.6.8", features = ["cors"] } +tower-http = { version = "0.6.8", features = ["cors", "trace"] } diff --git a/src/main.rs b/src/main.rs index 9a174fe..142695a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -175,6 +175,7 @@ async fn main() -> miette::Result<()> { .route("/xrpc/app.bsky.draft.deleteDraft", post(delete_draft)) .fallback(proxy_request) .layer(tower_http::cors::CorsLayer::permissive()) + .layer(tower_http::trace::TraceLayer::new_for_http()) .with_state(app_state); let port = std::env::var("PORT") @@ -195,6 +196,7 @@ async fn main() -> miette::Result<()> { } async fn proxy_request(req: Request) -> Result { + tracing::info!("Proxying request: {} {}", req.method(), req.uri()); let client = reqwest::Client::new(); let uri = req.uri(); let mut url = format!("https://public.api.bsky.app{}", uri.path()); @@ -258,7 +260,11 @@ async fn seed_account_follows(hydrant: Hydrant, seed_account: String) { let doc = match hydrant.resolver().resolve_doc(&seed_did).await { Ok(d) => d, Err(e) => { - tracing::warn!("Could not resolve DID doc for seed account {}: {}", seed_did, e); + tracing::warn!( + "Could not resolve DID doc for seed account {}: {}", + seed_did, + e + ); return; } }; @@ -328,8 +334,9 @@ async fn seed_account_follows(hydrant: Hydrant, seed_account: String) { #[derive(Deserialize)] struct GetPostThreadParams { uri: String, + #[serde(default)] depth: Option, - #[serde(rename = "parentHeight")] + #[serde(default, rename = "parentHeight")] parent_height: Option, } @@ -340,7 +347,7 @@ async fn get_post_thread( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let viewer_did = get_auth_did(&req); @@ -522,11 +529,11 @@ async fn get_profile( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(ident) = AtIdentifier::new(¶ms.actor) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; if let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await { @@ -696,7 +703,9 @@ async fn get_profile_internal( #[derive(Deserialize)] struct GetAuthorFeedParams { actor: String, + #[serde(default)] limit: Option, + #[serde(default)] cursor: Option, } @@ -707,11 +716,11 @@ async fn get_author_feed( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(ident) = AtIdentifier::new(¶ms.actor) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { @@ -763,7 +772,9 @@ async fn get_author_feed( #[derive(Deserialize)] struct GetLikesParams { uri: String, + #[serde(default)] limit: Option, + #[serde(default)] cursor: Option, } @@ -774,7 +785,7 @@ async fn get_likes( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let limit = params.limit.unwrap_or(50).min(100); @@ -848,7 +859,7 @@ async fn get_reposted_by( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let limit = params.limit.unwrap_or(50).min(100); @@ -964,7 +975,9 @@ async fn get_posts( #[derive(Deserialize)] struct GetFollowsParams { actor: String, + #[serde(default)] limit: Option, + #[serde(default)] cursor: Option, } @@ -975,11 +988,11 @@ async fn get_follows( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(ident) = AtIdentifier::new(¶ms.actor) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { return proxy_request(req).await; @@ -1028,11 +1041,11 @@ async fn get_followers( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(ident) = AtIdentifier::new(¶ms.actor) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { return proxy_request(req).await; @@ -1171,7 +1184,9 @@ async fn delete_bookmark( #[derive(Deserialize)] struct GetBookmarksParams { + #[serde(default)] limit: Option, + #[serde(default)] cursor: Option, } @@ -1386,7 +1401,9 @@ async fn delete_draft( #[derive(Deserialize)] struct GetDraftsParams { + #[serde(default)] limit: Option, + #[serde(default)] cursor: Option, } @@ -1447,8 +1464,11 @@ async fn get_drafts( #[derive(Deserialize)] struct GetTimelineParams { + #[serde(default)] algorithm: Option, + #[serde(default)] limit: Option, + #[serde(default)] cursor: Option, } @@ -1459,7 +1479,7 @@ async fn get_timeline( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Some(did_str) = get_auth_did(&req) else { @@ -1467,7 +1487,7 @@ async fn get_timeline( }; let Ok(ident) = AtIdentifier::new(&did_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { return proxy_request(req).await; @@ -1605,8 +1625,11 @@ async fn get_timeline( #[derive(Deserialize)] struct GetQuotesParams { uri: String, + #[serde(default)] cid: Option, + #[serde(default)] limit: Option, + #[serde(default)] cursor: Option, } @@ -1617,7 +1640,7 @@ async fn get_quotes( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let limit = params.limit.unwrap_or(50).min(100); @@ -1703,7 +1726,9 @@ async fn get_quotes( #[derive(Deserialize)] struct GetActorLikesParams { actor: String, + #[serde(default)] limit: Option, + #[serde(default)] cursor: Option, } @@ -1714,11 +1739,11 @@ async fn get_actor_likes( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(ident) = AtIdentifier::new(¶ms.actor) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { return proxy_request(req).await; @@ -1766,7 +1791,7 @@ async fn get_relationships( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let others = extract_query_array(query_str, "others"); @@ -1775,7 +1800,7 @@ async fn get_relationships( } let Ok(ident) = AtIdentifier::new(¶ms.actor) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { return proxy_request(req).await; @@ -1869,14 +1894,14 @@ async fn get_known_followers( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Some(did_str) = get_auth_did(&req) else { return Err(StatusCode::UNAUTHORIZED); }; let Ok(auth_ident) = AtIdentifier::new(&did_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(auth_repo) = app_state.hydrant.repos.resolve(&auth_ident).await else { return proxy_request(req).await; @@ -1905,7 +1930,7 @@ async fn get_known_followers( } let Ok(ident) = AtIdentifier::new(¶ms.actor) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { return proxy_request(req).await; @@ -1973,14 +1998,14 @@ async fn get_blocks( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Some(did_str) = get_auth_did(&req) else { return Err(StatusCode::UNAUTHORIZED); }; let Ok(ident) = AtIdentifier::new(&did_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { return proxy_request(req).await; @@ -2022,15 +2047,17 @@ async fn get_list(State(app_state): State, req: Request) -> Result, + #[serde(default)] cursor: Option, } let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(uri) = jacquard_common::types::string::AtUri::new(¶ms.list) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let author_ident = uri.authority(); let rkey = uri @@ -2127,11 +2154,11 @@ async fn get_lists( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(ident) = AtIdentifier::new(¶ms.actor) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { return proxy_request(req).await; @@ -2178,11 +2205,11 @@ async fn get_lists_with_membership( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(ident) = AtIdentifier::new(¶ms.actor) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { return proxy_request(req).await; @@ -2221,11 +2248,11 @@ async fn get_actor_feeds( // let hydrant = &app_state.hydrant; let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(ident) = AtIdentifier::new(¶ms.actor) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { return proxy_request(req).await; @@ -2282,11 +2309,11 @@ async fn get_feed_generator( feed: String, } let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(uri) = jacquard_common::types::string::AtUri::new(¶ms.feed) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let author_ident = uri.authority(); let rkey = uri @@ -2509,7 +2536,7 @@ async fn get_mutes( let query_str = req.uri().query().unwrap_or(""); let Ok(params) = serde_urlencoded::from_str::(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let limit = params.limit.unwrap_or(50).min(100); @@ -2723,7 +2750,9 @@ async fn notification_indexer(app_state: AppState) { #[derive(Deserialize)] struct ListNotificationsParams { + #[serde(default)] limit: Option, + #[serde(default)] cursor: Option, } @@ -2879,7 +2908,9 @@ async fn update_seen( #[derive(Deserialize)] struct GetFeedParams { feed: String, + #[serde(default)] limit: Option, + #[serde(default)] cursor: Option, } @@ -2887,11 +2918,11 @@ async fn get_feed(State(app_state): State, req: Request) -> Result(query_str) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let Ok(uri) = jacquard_common::types::string::AtUri::new(¶ms.feed) else { - return proxy_request(req).await; + return Err(StatusCode::BAD_REQUEST); }; let author_ident = uri.authority(); let rkey = uri @@ -2911,11 +2942,11 @@ async fn get_feed(State(app_state): State, req: Request) -> Result, req: Request) -> Result Result { - let host = req.headers().get("host").and_then(|h| h.to_str().ok()).unwrap_or("localhost:8000"); - +async fn get_well_known_did(req: Request) -> Result { + let host = req + .headers() + .get("host") + .and_then(|h| h.to_str().ok()) + .unwrap_or("localhost:8000"); + let did = if host.contains(':') { format!("did:web:{}", host.replace(':', "%3A")) } else { format!("did:web:{}", host) }; - let scheme = if host.starts_with("localhost") || host.starts_with("127.0.0.1") { "http" } else { "https" }; + let scheme = if host.starts_with("localhost") || host.starts_with("127.0.0.1") { + "http" + } else { + "https" + }; let service_endpoint = format!("{}://{}", scheme, host); Ok(Json(serde_json::json!({ @@ -3048,5 +3085,6 @@ async fn get_well_known_did( "serviceEndpoint": service_endpoint } ] - })).into_response()) + })) + .into_response()) }