activitypub-federation-rust/examples/local_federation/instance.rs
Nutomic a2ac97db98
Allow fetching from local domain in case it redirects to remote (#104)
* Allow fetching from local domain in case it redirects to remote

* clippy

* fix lemmy tests
2024-04-09 11:28:22 +02:00

106 lines
2.8 KiB
Rust

use crate::{
objects::{person::DbUser, post::DbPost},
Error,
};
use activitypub_federation::config::{FederationConfig, UrlVerifier};
use anyhow::anyhow;
use async_trait::async_trait;
use std::{
str::FromStr,
sync::{Arc, Mutex},
};
use url::Url;
pub async fn new_instance(
hostname: &str,
name: String,
) -> Result<FederationConfig<DatabaseHandle>, Error> {
let mut system_user = DbUser::new(hostname, "system".into())?;
system_user.ap_id = Url::parse(&format!("http://{}/", hostname))?.into();
let local_user = DbUser::new(hostname, name)?;
let database = Arc::new(Database {
system_user: system_user.clone(),
users: Mutex::new(vec![local_user]),
posts: Mutex::new(vec![]),
});
let config = FederationConfig::builder()
.domain(hostname)
.signed_fetch_actor(&system_user)
.app_data(database)
.url_verifier(Box::new(MyUrlVerifier()))
.debug(true)
.build()
.await?;
Ok(config)
}
pub type DatabaseHandle = Arc<Database>;
/// Our "database" which contains all known posts and users (local and federated)
pub struct Database {
pub system_user: DbUser,
pub users: Mutex<Vec<DbUser>>,
pub posts: Mutex<Vec<DbPost>>,
}
/// Use this to store your federation blocklist, or a database connection needed to retrieve it.
#[derive(Clone)]
struct MyUrlVerifier();
#[async_trait]
impl UrlVerifier for MyUrlVerifier {
async fn verify(&self, url: &Url) -> Result<(), activitypub_federation::error::Error> {
if url.domain() == Some("malicious.com") {
Err(activitypub_federation::error::Error::Other(
"malicious domain".into(),
))
} else {
Ok(())
}
}
}
pub enum Webserver {
Axum,
ActixWeb,
}
impl FromStr for Webserver {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"axum" => Webserver::Axum,
"actix-web" => Webserver::ActixWeb,
_ => panic!("Invalid webserver parameter, must be either `axum` or `actix-web`"),
})
}
}
pub fn listen(
config: &FederationConfig<DatabaseHandle>,
webserver: &Webserver,
) -> Result<(), Error> {
match webserver {
Webserver::Axum => crate::axum::http::listen(config)?,
Webserver::ActixWeb => crate::actix_web::http::listen(config)?,
}
Ok(())
}
impl Database {
pub fn local_user(&self) -> DbUser {
let lock = self.users.lock().unwrap();
lock.first().unwrap().clone()
}
pub fn read_user(&self, name: &str) -> Result<DbUser, Error> {
let db_user = self.local_user();
if name == db_user.name {
Ok(db_user)
} else {
Err(anyhow!("Invalid user {name}").into())
}
}
}