use axum::{ extract::State, routing::{get, post}, Json, Router, }; use serde::Deserialize; use crate::auth_middleware::AuthFingerprint; use crate::errors::AppResult; use crate::state::AppState; pub fn routes() -> Router { Router::new() .route("/friends", get(get_friends)) .route("/friends", post(save_friends)) } /// Get the encrypted friend list blob for the authenticated user. async fn get_friends( auth: AuthFingerprint, State(state): State, ) -> AppResult> { match state.db.friends.get(auth.fingerprint.as_bytes())? { Some(data) => { let blob = base64::Engine::encode(&base64::engine::general_purpose::STANDARD, &data); Ok(Json(serde_json::json!({ "fingerprint": auth.fingerprint, "data": blob, }))) } None => Ok(Json(serde_json::json!({ "fingerprint": auth.fingerprint, "data": null, }))), } } #[derive(Deserialize)] struct SaveFriendsRequest { data: String, // base64-encoded encrypted blob } /// Save the encrypted friend list blob. async fn save_friends( auth: AuthFingerprint, State(state): State, Json(req): Json, ) -> AppResult> { let blob = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, &req.data) .map_err(|e| anyhow::anyhow!("invalid base64: {}", e))?; state.db.friends.insert(auth.fingerprint.as_bytes(), blob)?; tracing::info!("Saved friend list for {} ({} bytes)", auth.fingerprint, req.data.len()); Ok(Json(serde_json::json!({ "ok": true }))) }