activitypub/src/http.rs

124 lines
4.1 KiB
Rust
Raw Permalink Normal View History

2024-04-09 19:48:18 +02:00
use crate::{
2024-04-18 04:03:52 +02:00
database::StateHandle,
entities::user,
error::Error,
2025-02-11 14:03:32 +01:00
objects::person::{DbUser, PersonAcceptedActivities},
utils::generate_user_id,
2024-08-28 15:24:22 +02:00
versia::{
2024-07-17 02:08:39 +02:00
self,
2024-08-28 15:24:22 +02:00
conversion::{db_user_from_url, local_db_user_from_name, receive_versia_note},
2024-07-17 02:08:39 +02:00
},
API_DOMAIN, LYSAND_DOMAIN,
2024-04-09 19:48:18 +02:00
};
use activitypub_federation::{
actix_web::{inbox::receive_activity, signing_actor},
config::{Data, FederationConfig, FederationMiddleware},
2024-08-03 08:15:54 +02:00
fetch::webfinger::{build_webfinger_response, extract_webfinger_name, WebFingerError},
2024-04-09 19:48:18 +02:00
protocol::context::WithContext,
traits::{Actor, Object},
FEDERATION_CONTENT_TYPE,
};
use actix_web::{web, web::Bytes, App, HttpRequest, HttpResponse, HttpServer};
use anyhow::anyhow;
2024-08-03 08:15:54 +02:00
use once_cell::sync::Lazy;
use regex::Regex;
2024-04-09 19:48:18 +02:00
use serde::Deserialize;
use tracing::info;
2024-04-18 03:41:52 +02:00
use url::Url;
2024-07-17 02:08:39 +02:00
use webfinger::resolve;
2024-04-09 19:48:18 +02:00
2024-04-18 03:41:52 +02:00
pub fn listen(config: &FederationConfig<StateHandle>) -> Result<(), Error> {
2024-04-09 19:48:18 +02:00
let hostname = config.domain();
info!("Listening with actix-web on {hostname}");
let config = config.clone();
let server = HttpServer::new(move || {
App::new()
.wrap(FederationMiddleware::new(config.clone()))
//.route("/", web::get().to(http_get_system_user))
.route("/{user}", web::get().to(http_get_user))
.route("/{user}/inbox", web::post().to(http_post_user_inbox))
.route("/.well-known/webfinger", web::get().to(webfinger))
})
.bind(hostname)?
.run();
tokio::spawn(server);
Ok(())
}
2024-08-28 15:24:22 +02:00
pub fn versia_inbox(
note: web::Json<versia::objects::Note>,
feat: basic AP <-> lysand conversion (#4) * feat: Update API domain variable name * save changes, fake commit * feat: function to receive lysand note * [feat]: lysand to ap for posts and users * feat: Add .env file to gitignore and update dependencies The commit adds the `.env` file to the `.gitignore` and updates the dependencies in the `Cargo.toml` and `Cargo.lock` files. This change ensures that sensitive environment variables are not committed to the repository and keeps the dependencies up to date. * feat: Add db_post_from_url function The commit adds the `db_post_from_url` function to the `conversion.rs` file. This function retrieves a post from the database based on a given URL. If the post is not found in the database, it fetches the post from the URL, saves it to the database, and returns the post. This change enhances the functionality of the codebase by providing a convenient way to retrieve and store posts. * feat: Update dependencies and add async-recursion crate * fix: Refactor lysand note handling in conversion.rs The commit refactors the lysand note handling in the `conversion.rs` file. It updates the `receive_lysand_note` function to properly handle quoting and replying to notes. This change improves the functionality and readability of the codebase. * fix: use example as default user * me oopid * fix: Refactor lysand note handling in conversion.rs * fix: fix post printing * fix: Refactor lysand note handling in conversion.rs * fix: Refactor lysand note handling in conversion.rs * fix: make nix-bootstrap executable * fix: remove unused linux only import * fix: make person stop screaming at me :( * feat: remove test code * fix: update deps * fix: rm build.rs fully * feat: standard user to apservice * fix: format files
2024-06-18 03:56:25 +02:00
id: web::Path<String>,
data: Data<StateHandle>,
) -> Result<HttpResponse, Error> {
2024-08-28 15:24:22 +02:00
tokio::spawn(receive_versia_note(note.into_inner(), id.into_inner()));
feat: basic AP <-> lysand conversion (#4) * feat: Update API domain variable name * save changes, fake commit * feat: function to receive lysand note * [feat]: lysand to ap for posts and users * feat: Add .env file to gitignore and update dependencies The commit adds the `.env` file to the `.gitignore` and updates the dependencies in the `Cargo.toml` and `Cargo.lock` files. This change ensures that sensitive environment variables are not committed to the repository and keeps the dependencies up to date. * feat: Add db_post_from_url function The commit adds the `db_post_from_url` function to the `conversion.rs` file. This function retrieves a post from the database based on a given URL. If the post is not found in the database, it fetches the post from the URL, saves it to the database, and returns the post. This change enhances the functionality of the codebase by providing a convenient way to retrieve and store posts. * feat: Update dependencies and add async-recursion crate * fix: Refactor lysand note handling in conversion.rs The commit refactors the lysand note handling in the `conversion.rs` file. It updates the `receive_lysand_note` function to properly handle quoting and replying to notes. This change improves the functionality and readability of the codebase. * fix: use example as default user * me oopid * fix: Refactor lysand note handling in conversion.rs * fix: fix post printing * fix: Refactor lysand note handling in conversion.rs * fix: Refactor lysand note handling in conversion.rs * fix: make nix-bootstrap executable * fix: remove unused linux only import * fix: make person stop screaming at me :( * feat: remove test code * fix: update deps * fix: rm build.rs fully * feat: standard user to apservice * fix: format files
2024-06-18 03:56:25 +02:00
Ok(HttpResponse::Created().finish())
}
2024-04-09 19:48:18 +02:00
/// Handles requests to fetch system user json over HTTP
/*pub async fn http_get_system_user(data: Data<DatabaseHandle>) -> Result<HttpResponse, Error> {
let json_user = data.system_user.clone().into_json(&data).await?;
Ok(HttpResponse::Ok()
.content_type(FEDERATION_CONTENT_TYPE)
.json(WithContext::new_default(json_user)))
}*/
/// Handles requests to fetch user json over HTTP
pub async fn http_get_user(
request: HttpRequest,
user_name: web::Path<String>,
2024-04-18 03:41:52 +02:00
data: Data<StateHandle>,
2024-04-09 19:48:18 +02:00
) -> Result<HttpResponse, Error> {
2024-04-10 00:38:45 +02:00
//let signed_by = signing_actor::<DbUser>(&request, None, &data).await?;
2024-04-09 19:48:18 +02:00
// here, checks can be made on the actor or the domain to which
// it belongs, to verify whether it is allowed to access this resource
2024-04-10 00:38:45 +02:00
//info!(
// "Fetch user request is signed by system account {}",
// signed_by.id()
//);
2024-04-09 19:48:18 +02:00
2024-04-18 03:41:52 +02:00
let db_user = data.local_user().await?;
if user_name.into_inner() == db_user.username {
2024-04-09 19:48:18 +02:00
let json_user = db_user.into_json(&data).await?;
Ok(HttpResponse::Ok()
.content_type(FEDERATION_CONTENT_TYPE)
.json(WithContext::new_default(json_user)))
} else {
Err(anyhow!("Invalid user").into())
}
}
/// Handles messages received in user inbox
pub async fn http_post_user_inbox(
request: HttpRequest,
body: Bytes,
2024-04-18 03:41:52 +02:00
data: Data<StateHandle>,
2024-04-09 19:48:18 +02:00
) -> Result<HttpResponse, Error> {
2024-04-18 03:41:52 +02:00
receive_activity::<WithContext<PersonAcceptedActivities>, user::Model, StateHandle>(
2024-04-09 19:48:18 +02:00
request, body, &data,
)
.await
}
#[derive(Deserialize)]
pub struct WebfingerQuery {
resource: String,
}
pub async fn webfinger(
query: web::Query<WebfingerQuery>,
2024-04-18 03:41:52 +02:00
data: Data<StateHandle>,
2024-04-09 19:48:18 +02:00
) -> Result<HttpResponse, Error> {
2024-08-03 08:15:54 +02:00
static WEBFINGER_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^acct:([\p{L}0-9_\.\-]+)@(.*)$").expect("compile regex"));
let captures = WEBFINGER_REGEX
.captures(&query.resource)
.ok_or(WebFingerError::WrongFormat)?;
let account_name = captures.get(1).ok_or(WebFingerError::WrongFormat)?;
let name = account_name.as_str();
2024-07-17 14:21:32 +02:00
let user = local_db_user_from_name(name.to_string()).await?;
2024-04-09 19:48:18 +02:00
Ok(HttpResponse::Ok().json(build_webfinger_response(
query.resource.clone(),
2024-07-17 02:08:39 +02:00
generate_user_id(&API_DOMAIN, &user.id)?,
2024-04-09 19:48:18 +02:00
)))
}