fix: cleanup warnings; centralise url creation into config

This commit is contained in:
nullishamy 2025-04-26 13:08:49 +01:00
parent 4b88100373
commit 9bc6c12392
Signed by: amy
SSH key fingerprint: SHA256:WmV0uk6WgAQvDJlM8Ld4mFPHZo02CLXXP5VkwQ5xtyk
11 changed files with 102 additions and 55 deletions

View file

@ -1,6 +1,6 @@
use std::sync::mpsc; use std::sync::mpsc;
use std::thread; use std::thread;
use tracing::{debug, info, span, Level}; use tracing::{info, span, Level};
#[derive(Debug)] #[derive(Debug)]
pub enum QueueMessage { pub enum QueueMessage {

View file

@ -9,3 +9,41 @@ pub struct ServerConfig {
pub struct Config { pub struct Config {
pub server: ServerConfig, pub server: ServerConfig,
} }
impl Config {
pub fn host(&self) -> &str {
&self.server.host
}
pub fn user_url(&self, user_uuid: &str) -> String {
format!("{}/users/{}", self.host(), user_uuid)
}
pub fn user_web_url(&self, user_name: &str) -> String {
format!("{}/{}", self.host(), user_name)
}
pub fn followers_url(&self, user_uuid: &str) -> String {
format!("{}/followers", self.user_url(user_uuid))
}
pub fn following_url(&self, user_uuid: &str) -> String {
format!("{}/following", self.user_url(user_uuid))
}
pub fn inbox_url(&self, user_uuid: &str) -> String {
format!("{}/inbox", self.user_url(user_uuid))
}
pub fn outbox_url(&self, user_uuid: &str) -> String {
format!("{}/outbox", self.user_url(user_uuid))
}
pub fn post_url(&self, poster_uuid: &str, post_uuid: &str) -> String {
format!("{}/{}", self.user_url(poster_uuid), post_uuid)
}
pub fn activity_url(&self, activity_uuid: &str) -> String {
format!("{}/activities/{}", self.host(), activity_uuid)
}
}

View file

@ -1,4 +1,6 @@
use rocket::{get, serde::json::Json}; use rocket::{get, serde::json::Json, State};
use crate::Config;
use crate::types::instance::{ use crate::types::instance::{
Accounts, Configuration, Contact, Instance, MediaAttachments, Polls, Registrations, Statuses, Accounts, Configuration, Contact, Instance, MediaAttachments, Polls, Registrations, Statuses,
@ -6,9 +8,9 @@ use crate::types::instance::{
}; };
#[get("/instance")] #[get("/instance")]
pub async fn instance() -> Json<Instance> { pub async fn instance(config: &State<Config>) -> Json<Instance> {
Json(Instance { Json(Instance {
domain: "ferri.amy.mov".to_string(), domain: config.host().to_string(),
title: "Ferri".to_string(), title: "Ferri".to_string(),
version: "0.0.1".to_string(), version: "0.0.1".to_string(),
source_url: "https://forge.amy.mov/amy/ferri".to_string(), source_url: "https://forge.amy.mov/amy/ferri".to_string(),

View file

@ -26,11 +26,11 @@ pub struct StatusContext {
descendants: Vec<Status> descendants: Vec<Status>
} }
#[get("/statuses/<status>/context")] #[get("/statuses/<_status>/context")]
pub async fn status_context( pub async fn status_context(
status: &str, _status: &str,
user: AuthenticatedUser, _user: AuthenticatedUser,
mut db: Connection<Db> _db: Connection<Db>
) -> Json<StatusContext> { ) -> Json<StatusContext> {
Json(StatusContext { Json(StatusContext {
ancestors: vec![], ancestors: vec![],

View file

@ -1,5 +1,6 @@
use crate::{AuthenticatedUser, Db, endpoints::api::user::CredentialAcount}; use crate::{AuthenticatedUser, Db, endpoints::api::user::CredentialAcount, Config};
use rocket::{ use rocket::{
State,
get, get,
serde::{Deserialize, Serialize, json::Json}, serde::{Deserialize, Serialize, json::Json},
}; };
@ -32,11 +33,12 @@ pub struct TimelineStatus {
pub account: TimelineAccount, pub account: TimelineAccount,
} }
#[get("/timelines/home?<limit>")] #[get("/timelines/home?<_limit>")]
pub async fn home( pub async fn home(
mut db: Connection<Db>, mut db: Connection<Db>,
limit: i64, config: &State<Config>,
user: AuthenticatedUser, _limit: i64,
_user: AuthenticatedUser,
) -> Json<Vec<TimelineStatus>> { ) -> Json<Vec<TimelineStatus>> {
let posts = sqlx::query!( let posts = sqlx::query!(
r#" r#"
@ -66,7 +68,7 @@ pub async fn home(
.await .await
.unwrap(); .unwrap();
let user_uri = format!("https://ferri.amy.mov/users/{}", record.user_id); let user_uri = config.user_url(&record.user_id);
boost = Some(Box::new(TimelineStatus { boost = Some(Box::new(TimelineStatus {
id: record.post_id.clone(), id: record.post_id.clone(),
created_at: record.created_at.clone(), created_at: record.created_at.clone(),
@ -110,7 +112,7 @@ pub async fn home(
})) }))
} }
let user_uri = format!("https://ferri.amy.mov/users/{}", record.username); let user_uri = config.user_web_url(&record.username);
out.push(TimelineStatus { out.push(TimelineStatus {
id: record.post_id.clone(), id: record.post_id.clone(),
created_at: record.created_at.clone(), created_at: record.created_at.clone(),

View file

@ -95,7 +95,7 @@ pub async fn new_follow(
pub async fn account( pub async fn account(
mut db: Connection<Db>, mut db: Connection<Db>,
uuid: &str, uuid: &str,
user: AuthenticatedUser, _user: AuthenticatedUser,
) -> Result<Json<TimelineAccount>, NotFound<String>> { ) -> Result<Json<TimelineAccount>, NotFound<String>> {
let user = ap::User::from_id(uuid, &mut **db) let user = ap::User::from_id(uuid, &mut **db)
.await .await
@ -123,12 +123,12 @@ pub async fn account(
})) }))
} }
#[get("/accounts/<uuid>/statuses?<limit>")] #[get("/accounts/<uuid>/statuses?<_limit>")]
pub async fn statuses( pub async fn statuses(
mut db: Connection<Db>, mut db: Connection<Db>,
uuid: &str, uuid: &str,
limit: Option<i64>, _limit: Option<i64>,
user: AuthenticatedUser, _user: AuthenticatedUser,
) -> Result<Json<Vec<TimelineStatus>>, NotFound<String>> { ) -> Result<Json<Vec<TimelineStatus>>, NotFound<String>> {
let user = ap::User::from_id(uuid, &mut **db) let user = ap::User::from_id(uuid, &mut **db)
.await .await

View file

@ -123,5 +123,7 @@ pub async fn test(http: &State<HttpClient>, outbound: &State<OutboundQueue>) ->
.await .await
.unwrap(); .unwrap();
dbg!(follow);
"Hello, world!" "Hello, world!"
} }

View file

@ -8,12 +8,12 @@ use rocket::{
}; };
use rocket_db_pools::Connection; use rocket_db_pools::Connection;
#[get("/oauth/authorize?<client_id>&<scope>&<redirect_uri>&<response_type>")] #[get("/oauth/authorize?<client_id>&<scope>&<redirect_uri>&<_response_type>")]
pub async fn authorize( pub async fn authorize(
client_id: &str, client_id: &str,
scope: &str, scope: &str,
redirect_uri: &str, redirect_uri: &str,
response_type: &str, _response_type: &str,
mut db: Connection<Db>, mut db: Connection<Db>,
) -> Redirect { ) -> Redirect {
// For now, we will always authorize the request and assign it to an admin user // For now, we will always authorize the request and assign it to an admin user
@ -68,11 +68,11 @@ pub struct Token {
#[derive(Deserialize, Debug, FromForm)] #[derive(Deserialize, Debug, FromForm)]
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
pub struct NewTokenRequest { pub struct NewTokenRequest {
client_id: String, // pub client_id: String,
redirect_uri: String, // pub redirect_uri: String,
grant_type: String, // pub grant_type: String,
code: String, pub code: String,
client_secret: String, // pub client_secret: String,
} }
#[post("/oauth/token", data = "<req>")] #[post("/oauth/token", data = "<req>")]

View file

@ -1,17 +1,18 @@
use main::ap; use main::ap;
use rocket::{get, http::ContentType, serde::json::Json}; use rocket::{get, http::ContentType, serde::json::Json, State};
use rocket_db_pools::Connection; use rocket_db_pools::Connection;
use rocket::response::status::NotFound; use rocket::response::status::NotFound;
use crate::{ use crate::{
Config,
Db, Db,
types::{OrderedCollection, Person, UserKey, content}, types::{OrderedCollection, Person, UserKey, content},
}; };
use super::activity_type; use super::activity_type;
#[get("/users/<user>/inbox")] #[get("/users/<_user>/inbox")]
pub async fn inbox(user: String) -> Json<OrderedCollection> { pub async fn inbox(_user: String) -> Json<OrderedCollection> {
Json(OrderedCollection { Json(OrderedCollection {
ty: "OrderedCollection".to_string(), ty: "OrderedCollection".to_string(),
total_items: 0, total_items: 0,
@ -19,8 +20,8 @@ pub async fn inbox(user: String) -> Json<OrderedCollection> {
}) })
} }
#[get("/users/<user>/outbox")] #[get("/users/<_user>/outbox")]
pub async fn outbox(user: String) -> Json<OrderedCollection> { pub async fn outbox(_user: String) -> Json<OrderedCollection> {
Json(OrderedCollection { Json(OrderedCollection {
ty: "OrderedCollection".to_string(), ty: "OrderedCollection".to_string(),
total_items: 0, total_items: 0,
@ -89,6 +90,7 @@ pub async fn following(mut db: Connection<Db>, uuid: &str) -> Result<Json<Ordere
#[get("/users/<uuid>/posts/<post>")] #[get("/users/<uuid>/posts/<post>")]
pub async fn post( pub async fn post(
mut db: Connection<Db>, mut db: Connection<Db>,
config: &State<Config>,
uuid: &str, uuid: &str,
post: String, post: String,
) -> (ContentType, Json<content::Post>) { ) -> (ContentType, Json<content::Post>) {
@ -106,19 +108,23 @@ pub async fn post(
activity_type(), activity_type(),
Json(content::Post { Json(content::Post {
context: "https://www.w3.org/ns/activitystreams".to_string(), context: "https://www.w3.org/ns/activitystreams".to_string(),
id: format!("https://ferri.amy.mov/users/{}/posts/{}", uuid, post.id), id: config.post_url(uuid, &post.id),
attributed_to: Some(format!("https://ferri.amy.mov/users/{}/posts/{}", uuid, post.id)), attributed_to: Some(config.user_url(uuid)),
ty: "Note".to_string(), ty: "Note".to_string(),
content: post.content, content: post.content,
ts: post.created_at, ts: post.created_at,
to: vec!["https://ferri.amy.mov/users/amy/followers".to_string()], to: vec![config.followers_url(uuid)],
cc: vec!["https://www.w3.org/ns/activitystreams#Public".to_string()], cc: vec!["https://www.w3.org/ns/activitystreams#Public".to_string()],
}), }),
) )
} }
#[get("/users/<uuid>")] #[get("/users/<uuid>")]
pub async fn user(mut db: Connection<Db>, uuid: &str) -> Result<(ContentType, Json<Person>), NotFound<String>> { pub async fn user(
mut db: Connection<Db>,
config: &State<Config>,
uuid: &str
) -> Result<(ContentType, Json<Person>), NotFound<String>> {
let user = ap::User::from_id(uuid, &mut **db) let user = ap::User::from_id(uuid, &mut **db)
.await .await
.map_err(|e| NotFound(e.to_string()))?; .map_err(|e| NotFound(e.to_string()))?;
@ -128,17 +134,17 @@ pub async fn user(mut db: Connection<Db>, uuid: &str) -> Result<(ContentType, Js
Json(Person { Json(Person {
context: "https://www.w3.org/ns/activitystreams".to_string(), context: "https://www.w3.org/ns/activitystreams".to_string(),
ty: "Person".to_string(), ty: "Person".to_string(),
id: format!("https://ferri.amy.mov/users/{}", user.id()), id: config.user_url(user.id()),
name: user.username().to_string(), name: user.username().to_string(),
preferred_username: user.display_name().to_string(), preferred_username: user.display_name().to_string(),
followers: format!("https://ferri.amy.mov/users/{}/followers", uuid), followers: config.followers_url(user.id()),
following: format!("https://ferri.amy.mov/users/{}/following", uuid), following: config.following_url(user.id()),
summary: format!("ferri {}", user.username()), summary: format!("ferri {}", user.username()),
inbox: format!("https://ferri.amy.mov/users/{}/inbox", uuid), inbox: config.inbox_url(user.id()),
outbox: format!("https://ferri.amy.mov/users/{}/outbox", uuid), outbox: config.outbox_url(user.id()),
public_key: Some(UserKey { public_key: Some(UserKey {
id: format!("https://ferri.amy.mov/users/{}#main-key", uuid), id: format!("https://ferri.amy.mov/users/{}#main-key", uuid),
owner: format!("https://ferri.amy.mov/users/{}", uuid), owner: config.user_url(user.id()),
public_key: include_str!("../../../public.pem").to_string(), public_key: include_str!("../../../public.pem").to_string(),
}), }),
}), }),

View file

@ -1,9 +1,10 @@
use main::ap; use main::ap;
use rocket::{get, serde::json::Json}; use rocket::{get, serde::json::Json, State};
use rocket_db_pools::Connection; use rocket_db_pools::Connection;
use tracing::info; use tracing::info;
use crate::{ use crate::{
Config,
Db, Db,
types::webfinger::{Link, WebfingerResponse}, types::webfinger::{Link, WebfingerResponse},
}; };
@ -20,7 +21,7 @@ pub async fn host_meta() -> &'static str {
// https://mastodon.social/.well-known/webfinger?resource=acct:gargron@mastodon.social // https://mastodon.social/.well-known/webfinger?resource=acct:gargron@mastodon.social
#[get("/.well-known/webfinger?<resource>")] #[get("/.well-known/webfinger?<resource>")]
pub async fn webfinger(mut db: Connection<Db>, resource: &str) -> Json<WebfingerResponse> { pub async fn webfinger(mut db: Connection<Db>, config: &State<Config>, resource: &str) -> Json<WebfingerResponse> {
info!(?resource, "incoming webfinger request"); info!(?resource, "incoming webfinger request");
let acct = resource.strip_prefix("acct:").unwrap(); let acct = resource.strip_prefix("acct:").unwrap();
@ -30,19 +31,19 @@ pub async fn webfinger(mut db: Connection<Db>, resource: &str) -> Json<Webfinger
Json(WebfingerResponse { Json(WebfingerResponse {
subject: resource.to_string(), subject: resource.to_string(),
aliases: vec![ aliases: vec![
format!("https://ferri.amy.mov/users/{}", user.id()), config.user_url(user.id()),
format!("https://ferri.amy.mov/{}", user.username()), config.user_web_url(user.username())
], ],
links: vec![ links: vec![
Link { Link {
rel: "http://webfinger.net/rel/profile-page".to_string(), rel: "http://webfinger.net/rel/profile-page".to_string(),
ty: Some("text/html".to_string()), ty: Some("text/html".to_string()),
href: Some(format!("https://ferri.amy.mov/{}", user.username())), href: Some(config.user_web_url(user.username())),
}, },
Link { Link {
rel: "self".to_string(), rel: "self".to_string(),
ty: Some("application/activity+json".to_string()), ty: Some("application/activity+json".to_string()),
href: Some(format!("https://ferri.amy.mov/users/{}", user.id())), href: Some(config.user_url(user.id())),
}, },
], ],
}) })

View file

@ -3,7 +3,6 @@ use endpoints::{
custom, inbox, oauth, user, well_known, custom, inbox, oauth, user, well_known,
}; };
use tracing::Level;
use tracing_subscriber::fmt; use tracing_subscriber::fmt;
use main::ap; use main::ap;
@ -27,17 +26,17 @@ mod types;
pub struct Db(sqlx::SqlitePool); pub struct Db(sqlx::SqlitePool);
#[get("/")] #[get("/")]
async fn user_profile(cfg: &rocket::State<Config>) -> (ContentType, &'static str) { async fn user_profile() -> (ContentType, &'static str) {
(ContentType::HTML, "<p>hello</p>") (ContentType::HTML, "<p>hello</p>")
} }
#[get("/activities/<activity>")] #[get("/activities/<_activity>")]
async fn activity_endpoint(activity: String) { async fn activity_endpoint(_activity: String) {
} }
#[derive(Debug)] #[derive(Debug)]
struct AuthenticatedUser { pub struct AuthenticatedUser {
pub username: String, pub username: String,
pub id: String, pub id: String,
pub token: String, pub token: String,
@ -45,10 +44,7 @@ struct AuthenticatedUser {
} }
#[derive(Debug)] #[derive(Debug)]
enum LoginError { pub enum LoginError {
InvalidData,
UsernameDoesNotExist,
WrongPassword,
} }
#[rocket::async_trait] #[rocket::async_trait]