diff --git a/Cargo.lock b/Cargo.lock index f1201d4..fc47954 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1264,6 +1264,8 @@ dependencies = [ "serde", "serde_json", "sqlx", + "thiserror 2.0.12", + "tracing", "url", "uuid", ] @@ -2161,6 +2163,8 @@ dependencies = [ "rocket", "rocket_db_pools", "sqlx", + "tracing", + "tracing-subscriber", "url", "uuid", ] @@ -2740,6 +2744,16 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.19" @@ -2750,12 +2764,15 @@ dependencies = [ "nu-ansi-term", "once_cell", "regex", + "serde", + "serde_json", "sharded-slab", "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log", + "tracing-serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e039c64..0f7cb23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,10 @@ rocket = { version = "0.5.1", features = ["json"] } sqlx = { version = "0.7", features = [ "runtime-tokio", "sqlite", "macros" ], default-features = false } uuid = { version = "1.16.0", features = ["v4"] } chrono = "0.4.40" -rand = "0.8" \ No newline at end of file +rand = "0.8" +thiserror = "2.0.12" + +tracing = "0.1.40" +tracing-appender = "0.2.3" +tracing-log = "0.2.0" +tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json", "registry", "smallvec"] } \ No newline at end of file diff --git a/ferri-main/Cargo.toml b/ferri-main/Cargo.toml index 0d91f57..cca1ac5 100644 --- a/ferri-main/Cargo.toml +++ b/ferri-main/Cargo.toml @@ -5,13 +5,15 @@ edition = "2024" [dependencies] serde = { workspace = true } -serde_json = "1.0.140" sqlx = { workspace = true } chrono = { workspace = true } reqwest = { workspace = true } uuid = { workspace = true } +rand = { workspace = true } +thiserror = { workspace = true } +tracing = { workspace = true } base64 = "0.22.1" rsa = { version = "0.9.8", features = ["sha2"] } -rand = { workspace = true } url = "2.5.4" +serde_json = "1.0.140" \ No newline at end of file diff --git a/ferri-main/src/ap/activity.rs b/ferri-main/src/ap/activity.rs index bf834f1..59af769 100644 --- a/ferri-main/src/ap/activity.rs +++ b/ferri-main/src/ap/activity.rs @@ -1,8 +1,9 @@ use crate::ap::{Actor, User, http}; -use chrono::{DateTime, Local}; +use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use sqlx::Sqlite; use std::fmt::Debug; +use tracing::{event, Level}; #[derive(Debug, Clone)] pub enum ActivityType { @@ -28,7 +29,7 @@ pub struct Activity { pub id: String, pub ty: ActivityType, pub object: T, - pub published: DateTime, + pub published: DateTime, pub to: Vec, pub cc: Vec, } @@ -39,7 +40,7 @@ impl Default for Activity { id: Default::default(), ty: ActivityType::Unknown, object: Default::default(), - published: Local::now(), + published: Utc::now(), to: Default::default(), cc: Default::default(), } @@ -102,19 +103,18 @@ impl<'a> Outbox<'a> { } pub async fn post(&self, activity: OutgoingActivity) { - dbg!(&activity); + event!(Level::INFO, ?activity, "activity in outbox"); + let raw = RawActivity { context: "https://www.w3.org/ns/activitystreams".to_string(), - id: activity.req.id, + id: activity.req.id.clone(), ty: activity.req.ty.to_raw(), actor: self.user.actor().id().to_string(), object: activity.req.object, published: activity.req.published.to_rfc3339(), }; - dbg!(&raw); - - let follow_res = self + let outbox_res = self .transport .post(activity.to.inbox()) .activity() @@ -127,7 +127,10 @@ impl<'a> Outbox<'a> { .await .unwrap(); - dbg!(follow_res); + event!(Level::DEBUG, + outbox_res, activity = activity.req.id, + "got response for outbox dispatch" + ); } pub fn for_user(user: User, transport: &'a OutboxTransport) -> Outbox<'a> { diff --git a/ferri-main/src/ap/http.rs b/ferri-main/src/ap/http.rs index 5c45cca..ca0e026 100644 --- a/ferri-main/src/ap/http.rs +++ b/ferri-main/src/ap/http.rs @@ -12,6 +12,7 @@ use rsa::{ use base64::prelude::*; use chrono::Utc; +use tracing::{event, Level}; pub struct HttpClient { client: reqwest::Client, @@ -59,7 +60,8 @@ impl RequestBuilder { } pub async fn send(self) -> Result { - dbg!(&self.inner); + event!(Level::DEBUG, ?self.inner, "sending an http request"); + self.inner.send().await } diff --git a/ferri-main/src/ap/mod.rs b/ferri-main/src/ap/mod.rs index 44ae578..f86ba50 100644 --- a/ferri-main/src/ap/mod.rs +++ b/ferri-main/src/ap/mod.rs @@ -12,7 +12,7 @@ pub use user::*; mod post; pub use post::*; -pub const AS_CONTEXT: &'static str = "https://www.w3.org/ns/activitystreams"; +pub const AS_CONTEXT: &str = "https://www.w3.org/ns/activitystreams"; pub fn new_id() -> String { Uuid::new_v4().to_string() diff --git a/ferri-main/src/ap/post.rs b/ferri-main/src/ap/post.rs index 53bfe03..53c33e0 100644 --- a/ferri-main/src/ap/post.rs +++ b/ferri-main/src/ap/post.rs @@ -3,7 +3,7 @@ use chrono::{DateTime, Utc}; use serde::Serialize; use sqlx::Sqlite; -const POST_TYPE: &'static str = "Post"; +const POST_TYPE: &str = "Post"; #[derive(Clone)] pub struct Post { diff --git a/ferri-main/src/ap/user.rs b/ferri-main/src/ap/user.rs index 4178cfb..b080181 100644 --- a/ferri-main/src/ap/user.rs +++ b/ferri-main/src/ap/user.rs @@ -1,5 +1,6 @@ use sqlx::Sqlite; use std::fmt::Debug; +use thiserror::Error; #[derive(Debug, Clone)] pub struct Actor { @@ -20,6 +21,10 @@ impl Actor { pub fn inbox(&self) -> &str { &self.inbox } + + pub fn outbox(&self) -> &str { + &self.outbox + } } #[derive(Debug, Clone)] @@ -30,6 +35,13 @@ pub struct User { display_name: String, } + +#[derive(Error, Debug)] +pub enum UserError { + #[error("user `{0}` not found")] + NotFound(String), +} + impl User { pub fn id(&self) -> &str { &self.id @@ -55,7 +67,7 @@ impl User { format!("https://ferri.amy.mov/users/{}", self.id()) } - pub async fn from_id(uuid: &str, conn: impl sqlx::Executor<'_, Database = Sqlite>) -> User { + pub async fn from_id(uuid: &str, conn: impl sqlx::Executor<'_, Database = Sqlite>) -> Result { let user = sqlx::query!( r#" SELECT u.*, a.id as "actor_own_id", a.inbox, a.outbox @@ -65,10 +77,11 @@ impl User { "#, uuid ) - .fetch_one(conn) - .await - .unwrap(); - User { + .fetch_one(conn) + .await + .map_err(|_| UserError::NotFound(uuid.to_string()))?; + + Ok(User { id: user.id, username: user.username, actor: Actor { @@ -77,7 +90,7 @@ impl User { outbox: user.outbox, }, display_name: user.display_name, - } + }) } pub async fn from_username( diff --git a/ferri-server/Cargo.toml b/ferri-server/Cargo.toml index fba127f..91b72fe 100644 --- a/ferri-server/Cargo.toml +++ b/ferri-server/Cargo.toml @@ -5,12 +5,14 @@ edition = "2024" [dependencies] main = { path = "../ferri-main/" } -rocket = { workspace = true } rocket_db_pools = { version = "0.2.0", features = ["sqlx_sqlite"] } +url = "2.5.4" + +rocket = { workspace = true } reqwest = { workspace = true } sqlx = { workspace = true } uuid = { workspace = true } chrono = { workspace = true } rand = { workspace = true } - -url = "2.5.4" \ No newline at end of file +tracing = { workspace = true } +tracing-subscriber = { workspace = true } \ No newline at end of file diff --git a/ferri-server/src/endpoints/api/status.rs b/ferri-server/src/endpoints/api/status.rs index 92cb6ec..c0e6898 100644 --- a/ferri-server/src/endpoints/api/status.rs +++ b/ferri-server/src/endpoints/api/status.rs @@ -1,17 +1,17 @@ use crate::timeline::TimelineStatus; -use chrono::Local; use main::ap::{self, http::HttpClient}; use rocket::{ FromForm, State, form::Form, post, + get, serde::{Deserialize, Serialize, json::Json}, }; use rocket_db_pools::Connection; use uuid::Uuid; use crate::api::user::CredentialAcount; -use crate::{AuthenticatedUser, Db, types::content}; +use crate::{AuthenticatedUser, Db}; #[derive(Serialize, Deserialize, Debug, FromForm)] #[serde(crate = "rocket::serde")] @@ -19,17 +19,36 @@ pub struct Status { status: String, } +#[derive(Serialize, Deserialize, Debug, FromForm)] +#[serde(crate = "rocket::serde")] +pub struct StatusContext { + ancestors: Vec, + descendants: Vec +} + +#[get("/statuses//context")] +pub async fn status_context( + status: &str, + user: AuthenticatedUser, + mut db: Connection +) -> Json { + Json(StatusContext { + ancestors: vec![], + descendants: vec![], + }) +} + async fn create_status( user: AuthenticatedUser, mut db: Connection, http: &HttpClient, status: &Status, ) -> TimelineStatus { - let user = ap::User::from_id(&user.username, &mut **db).await; + let user = ap::User::from_id(&user.id, &mut **db).await.unwrap(); let outbox = ap::Outbox::for_user(user.clone(), http); let post_id = ap::new_id(); - let now = ap::new_ts(); + let now = ap::now(); let post = ap::Post::from_parts(post_id, status.status.clone(), user.clone()) .to(format!("{}/followers", user.uri())) @@ -55,6 +74,7 @@ async fn create_status( ty: ap::ActivityType::Create, object: post.clone().to_ap(), to: vec![format!("{}/followers", user.uri())], + published: now, cc: vec!["https://www.w3.org/ns/activitystreams#Public".to_string()], ..Default::default() }; diff --git a/ferri-server/src/endpoints/api/timeline.rs b/ferri-server/src/endpoints/api/timeline.rs index 3a3ec13..ae1f771 100644 --- a/ferri-server/src/endpoints/api/timeline.rs +++ b/ferri-server/src/endpoints/api/timeline.rs @@ -37,7 +37,6 @@ pub async fn home( limit: i64, user: AuthenticatedUser, ) -> Json> { - dbg!(user); let posts = sqlx::query!( r#" SELECT p.id as "post_id", u.id as "user_id", p.content, p.uri as "post_uri", diff --git a/ferri-server/src/endpoints/api/user.rs b/ferri-server/src/endpoints/api/user.rs index edf84f2..a6be6aa 100644 --- a/ferri-server/src/endpoints/api/user.rs +++ b/ferri-server/src/endpoints/api/user.rs @@ -5,6 +5,7 @@ use rocket::{ }; use rocket_db_pools::Connection; use uuid::Uuid; +use rocket::response::status::NotFound; use crate::timeline::{TimelineAccount, TimelineStatus}; use crate::{AuthenticatedUser, Db, http::HttpClient}; @@ -62,9 +63,12 @@ pub async fn new_follow( http: &State, uuid: &str, user: AuthenticatedUser, -) { +) -> Result<(), NotFound> { let follower = ap::User::from_actor_id(&user.actor_id, &mut **db).await; - let followed = ap::User::from_id(uuid, &mut **db).await; + + let followed = ap::User::from_id(uuid, &mut **db) + .await + .map_err(|e| NotFound(e.to_string()))?; let outbox = ap::Outbox::for_user(follower.clone(), http.inner()); @@ -83,6 +87,8 @@ pub async fn new_follow( req.save(&mut **db).await; outbox.post(req).await; + + Ok(()) } #[get("/accounts/")] @@ -90,10 +96,12 @@ pub async fn account( mut db: Connection, uuid: &str, user: AuthenticatedUser, -) -> Json { - let user = ap::User::from_id(uuid, &mut **db).await; +) -> Result, NotFound> { + let user = ap::User::from_id(uuid, &mut **db) + .await + .map_err(|e| NotFound(e.to_string()))?; let user_uri = format!("https://ferri.amy.mov/users/{}", user.username()); - Json(CredentialAcount { + Ok(Json(CredentialAcount { id: user.id().to_string(), username: user.username().to_string(), acct: user.username().to_string(), @@ -112,7 +120,7 @@ pub async fn account( following_count: 1, statuses_count: 1, last_status_at: "2025-04-10T22:14:34Z".to_string(), - }) + })) } #[get("/accounts//statuses?")] @@ -121,8 +129,10 @@ pub async fn statuses( uuid: &str, limit: Option, user: AuthenticatedUser, -) -> Json> { - let user = ap::User::from_id(uuid, &mut **db).await; +) -> Result>, NotFound> { + let user = ap::User::from_id(uuid, &mut **db) + .await + .map_err(|e| NotFound(e.to_string()))?; let uid = user.id(); let posts = sqlx::query!( @@ -181,5 +191,5 @@ pub async fn statuses( }); } - Json(out) + Ok(Json(out)) } diff --git a/ferri-server/src/endpoints/custom.rs b/ferri-server/src/endpoints/custom.rs index 25dca75..ff3bea8 100644 --- a/ferri-server/src/endpoints/custom.rs +++ b/ferri-server/src/endpoints/custom.rs @@ -118,7 +118,5 @@ pub async fn test(http: &State) -> &'static str { .await .unwrap(); - dbg!(follow); - "Hello, world!" } diff --git a/ferri-server/src/endpoints/inbox.rs b/ferri-server/src/endpoints/inbox.rs index 3291799..5d1972a 100644 --- a/ferri-server/src/endpoints/inbox.rs +++ b/ferri-server/src/endpoints/inbox.rs @@ -6,6 +6,7 @@ use rocket_db_pools::Connection; use sqlx::Sqlite; use url::Url; use uuid::Uuid; +use tracing::{event, span, Level, debug, warn, info}; use crate::{ Db, @@ -14,12 +15,12 @@ use crate::{ }; fn handle_delete_activity(activity: activity::DeleteActivity) { - dbg!(activity); + warn!(?activity, "unimplemented delete activity"); } async fn create_actor( user: &Person, - actor: String, + actor: &str, conn: impl sqlx::Executor<'_, Database = Sqlite>, ) { sqlx::query!( @@ -39,7 +40,7 @@ async fn create_actor( async fn create_user( user: &Person, - actor: String, + actor: &str, conn: impl sqlx::Executor<'_, Database = Sqlite>, ) { // HACK: Allow us to formulate a `user@host` username by assuming the actor is on the same host as the user @@ -84,7 +85,7 @@ async fn create_follow( } async fn handle_follow_activity( - followed_account: String, + followed_account: &str, activity: activity::FollowActivity, http: &HttpClient, mut db: Connection, @@ -99,8 +100,8 @@ async fn handle_follow_activity( .await .unwrap(); - create_actor(&user, activity.actor.clone(), &mut **db).await; - create_user(&user, activity.actor.clone(), &mut **db).await; + create_actor(&user, &activity.actor, &mut **db).await; + create_user(&user, &activity.actor, &mut **db).await; create_follow(&activity, &mut **db).await; let follower = ap::User::from_actor_id(&activity.actor, &mut **db).await; @@ -128,11 +129,17 @@ async fn handle_follow_activity( } async fn handle_like_activity(activity: activity::LikeActivity, mut db: Connection) { + warn!(?activity, "unimplemented like activity"); + let target_post = sqlx::query!("SELECT * FROM post WHERE uri = ?1", activity.object) .fetch_one(&mut **db) - .await - .unwrap(); - dbg!(&target_post); + .await; + + if let Ok(post) = target_post { + warn!(?post, "tried to like post"); + } else { + warn!(post = ?activity.object, "could not find post"); + } } async fn handle_create_activity( @@ -141,6 +148,8 @@ async fn handle_create_activity( mut db: Connection, ) { assert!(&activity.object.ty == "Note"); + debug!("resolving user {}", activity.actor); + let user = http .get(&activity.actor) .activity() @@ -151,10 +160,14 @@ async fn handle_create_activity( .await .unwrap(); - create_actor(&user, activity.actor.clone(), &mut **db).await; - create_user(&user, activity.actor.clone(), &mut **db).await; + debug!("creating actor {}", activity.actor); + create_actor(&user, &activity.actor, &mut **db).await; + + debug!("creating user {}", activity.actor); + create_user(&user, &activity.actor, &mut **db).await; let user = ap::User::from_actor_id(&activity.actor, &mut **db).await; + debug!("user created {:?}", user); let user_id = user.id(); let now = Local::now().to_rfc3339(); @@ -162,6 +175,8 @@ async fn handle_create_activity( let post_id = Uuid::new_v4().to_string(); let uri = activity.id; + info!(post_id, "creating post"); + sqlx::query!( r#" INSERT INTO post (id, uri, user_id, content, created_at) @@ -173,14 +188,19 @@ async fn handle_create_activity( content, now ) - .execute(&mut **db) - .await - .unwrap(); + .execute(&mut **db) + .await + .unwrap(); } #[post("/users//inbox", data = "")] -pub async fn inbox(db: Connection, http: &State, user: String, body: String) { +pub async fn inbox(db: Connection, http: &State, user: &str, body: String) { let min = serde_json::from_str::(&body).unwrap(); + let inbox_span = span!(Level::INFO, "inbox-post", user_id = user); + + let _enter = inbox_span.enter(); + event!(Level::INFO, ?min, "received an activity"); + match min.ty.as_str() { "Delete" => { let activity = serde_json::from_str::(&body).unwrap(); @@ -198,11 +218,11 @@ pub async fn inbox(db: Connection, http: &State, user: String, b let activity = serde_json::from_str::(&body).unwrap(); handle_like_activity(activity, db).await; } - unknown => { - eprintln!("WARN: Unknown activity '{}' - {}", unknown, body); + act => { + warn!(act, body, "unknown activity"); } } - dbg!(min); - println!("Body in inbox: {}", body); + debug!("body in inbox: {}", body); + drop(_enter) } diff --git a/ferri-server/src/endpoints/oauth.rs b/ferri-server/src/endpoints/oauth.rs index 7045ec1..81c8d55 100644 --- a/ferri-server/src/endpoints/oauth.rs +++ b/ferri-server/src/endpoints/oauth.rs @@ -23,10 +23,10 @@ pub async fn authorize( // This will act as a token for the user, but we will in future say that it expires very shortly // and can only be used for obtaining an access token etc sqlx::query!( - r#" - INSERT INTO auth (token, user_id) - VALUES (?1, ?2) - "#, + r#" + INSERT INTO auth (token, user_id) + VALUES (?1, ?2) + "#, code, user_id ) @@ -35,7 +35,7 @@ pub async fn authorize( .unwrap(); let id_token = main::gen_token(10); - + // Add an oauth entry for the `code` which /oauth/token will rewrite sqlx::query!( r#" @@ -67,7 +67,7 @@ pub struct Token { #[derive(Deserialize, Debug, FromForm)] #[serde(crate = "rocket::serde")] -struct NewTokenRequest { +pub struct NewTokenRequest { client_id: String, redirect_uri: String, grant_type: String, @@ -77,19 +77,15 @@ struct NewTokenRequest { #[post("/oauth/token", data = "")] pub async fn new_token(req: Form, mut db: Connection) -> Json { - let oauth = sqlx::query!( - r#" + let oauth = sqlx::query!(" SELECT o.*, a.* FROM oauth o INNER JOIN auth a ON a.token = ?2 WHERE o.access_token = ?1 - "#, - req.code, - req.code - ) - .fetch_one(&mut **db) - .await - .unwrap(); + ", req.code, req.code) + .fetch_one(&mut **db) + .await + .unwrap(); let access_token = main::gen_token(15); diff --git a/ferri-server/src/endpoints/user.rs b/ferri-server/src/endpoints/user.rs index 7cc0550..3963926 100644 --- a/ferri-server/src/endpoints/user.rs +++ b/ferri-server/src/endpoints/user.rs @@ -1,6 +1,7 @@ use main::ap; use rocket::{get, http::ContentType, serde::json::Json}; use rocket_db_pools::Connection; +use rocket::response::status::NotFound; use crate::{ Db, @@ -20,7 +21,6 @@ pub async fn inbox(user: String) -> Json { #[get("/users//outbox")] pub async fn outbox(user: String) -> Json { - dbg!(&user); Json(OrderedCollection { ty: "OrderedCollection".to_string(), total_items: 0, @@ -29,8 +29,11 @@ pub async fn outbox(user: String) -> Json { } #[get("/users//followers")] -pub async fn followers(mut db: Connection, uuid: &str) -> Json { - let target = ap::User::from_id(uuid, &mut **db).await; +pub async fn followers(mut db: Connection, uuid: &str) -> Result, NotFound> { + let target = ap::User::from_id(uuid, &mut **db) + .await + .map_err(|e| NotFound(e.to_string()))?; + let actor_id = target.actor_id(); let followers = sqlx::query!( @@ -44,19 +47,22 @@ pub async fn followers(mut db: Connection, uuid: &str) -> Json>(), - }) + })) } #[get("/users//following")] -pub async fn following(mut db: Connection, uuid: &str) -> Json { - let target = ap::User::from_id(uuid, &mut **db).await; +pub async fn following(mut db: Connection, uuid: &str) -> Result, NotFound> { + let target = ap::User::from_id(uuid, &mut **db) + .await + .map_err(|e| NotFound(e.to_string()))?; + let actor_id = target.actor_id(); let following = sqlx::query!( @@ -70,14 +76,14 @@ pub async fn following(mut db: Connection, uuid: &str) -> Json>(), - }) + })) } #[get("/users//posts/")] @@ -111,14 +117,17 @@ pub async fn post( } #[get("/users/")] -pub async fn user(mut db: Connection, uuid: &str) -> (ContentType, Json) { - let user = ap::User::from_id(uuid, &mut **db).await; - ( +pub async fn user(mut db: Connection, uuid: &str) -> Result<(ContentType, Json), NotFound> { + let user = ap::User::from_id(uuid, &mut **db) + .await + .map_err(|e| NotFound(e.to_string()))?; + + Ok(( activity_type(), Json(Person { context: "https://www.w3.org/ns/activitystreams".to_string(), ty: "Person".to_string(), - id: user.id().to_string(), + id: format!("https://ferri.amy.mov/users/{}", user.id()), name: user.username().to_string(), preferred_username: user.display_name().to_string(), followers: format!("https://ferri.amy.mov/users/{}/followers", uuid), @@ -132,5 +141,5 @@ pub async fn user(mut db: Connection, uuid: &str) -> (ContentType, Json &'static str { // https://mastodon.social/.well-known/webfinger?resource=acct:gargron@mastodon.social #[get("/.well-known/webfinger?")] pub async fn webfinger(mut db: Connection, resource: &str) -> Json { - println!("Webfinger request for {}", resource); + info!(?resource, "incoming webfinger request"); + let acct = resource.strip_prefix("acct:").unwrap(); let (user, _) = acct.split_once("@").unwrap(); let user = ap::User::from_username(user, &mut **db).await; @@ -29,13 +31,13 @@ pub async fn webfinger(mut db: Connection, resource: &str) -> Json) -> (ContentType, &'static str) { - dbg!(cfg); (ContentType::HTML, "

hello

") } #[get("/activities/")] async fn activity_endpoint(activity: String) { - dbg!(activity); + } #[derive(Debug)] struct AuthenticatedUser { - username: String, - token: String, - actor_id: String, + pub username: String, + pub id: String, + pub token: String, + pub actor_id: String, } #[derive(Debug)] @@ -52,7 +54,7 @@ impl<'a> FromRequest<'a> for AuthenticatedUser { type Error = LoginError; async fn from_request(request: &'a Request<'_>) -> Outcome { let token = request.headers().get_one("Authorization"); - + if let Some(token) = token { let token = token .strip_prefix("Bearer") @@ -60,29 +62,49 @@ impl<'a> FromRequest<'a> for AuthenticatedUser { .unwrap_or(token); let mut conn = request.guard::>().await.unwrap(); - let auth = sqlx::query!(r#" + let auth = sqlx::query!( + r#" SELECT * FROM auth a INNER JOIN user u ON a.user_id = u.id WHERE token = ?1 - "#, token) - .fetch_one(&mut **conn) - .await; + "#, + token + ) + .fetch_one(&mut **conn) + .await; if let Ok(auth) = auth { return Outcome::Success(AuthenticatedUser { token: auth.token, + id: auth.id, username: auth.display_name, actor_id: auth.actor_id, - }) - } - } - + }); + } + } + Outcome::Forward(Status::Unauthorized) } } + + pub fn launch(cfg: Config) -> Rocket { + let format = fmt::format() + .with_ansi(true) + .without_time() + .with_level(true) + .with_target(false) + .with_thread_names(false) + .with_source_location(false) + .compact(); + + tracing_subscriber::fmt() + .event_format(format) + .with_writer(std::io::stdout) + .init(); + let http_client = http::HttpClient::new(); build() .manage(cfg) @@ -114,6 +136,7 @@ pub fn launch(cfg: Config) -> Rocket { .mount( "/api/v1", routes![ + api::status::status_context, api::status::new_status, api::status::new_status_json, api::user::new_follow,