diff --git a/Cargo.lock b/Cargo.lock index 8a6fffb..7da3ffc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "activitypub_federation" -version = "0.4.0-rc2" +version = "0.4.0-rc3" dependencies = [ "activitystreams-kinds", "actix-rt", diff --git a/docs/03_federating_users.md b/docs/03_federating_users.md index 1eb2027..a45eac7 100644 --- a/docs/03_federating_users.md +++ b/docs/03_federating_users.md @@ -73,7 +73,7 @@ pub struct DbUser { pub display_name: String, pub password_hash: Option, pub email: Option, - pub apub_id: Url, + pub federation_id: Url, pub inbox: Url, pub outbox: Url, pub local: bool, @@ -83,8 +83,8 @@ pub struct DbUser { } ``` -Field names and other details of this type can be chosen freely according to your requirements. It only matters that the required data is being stored. Its important that this struct doesn't represent only local users who registered directly on our website, but also remote users that are registered on other instances and federated to us. The `local` column helps to easily distinguish both. It can also be distinguished from the domain of the `apub_id` URL, but that would be a much more expensive operation. All users have a `public_key`, but only local users have a `private_key`. On the other hand, `password_hash` and `email` are only present for local users. inbox` and `outbox` URLs need to be stored because each implementation is free to choose its own format for them, so they can't be regenerated on the fly. +Field names and other details of this type can be chosen freely according to your requirements. It only matters that the required data is being stored. Its important that this struct doesn't represent only local users who registered directly on our website, but also remote users that are registered on other instances and federated to us. The `local` column helps to easily distinguish both. It can also be distinguished from the domain of the `federation_id` URL, but that would be a much more expensive operation. All users have a `public_key`, but only local users have a `private_key`. On the other hand, `password_hash` and `email` are only present for local users. inbox` and `outbox` URLs need to be stored because each implementation is free to choose its own format for them, so they can't be regenerated on the fly. -In larger projects it makes sense to split this data in two. One for data relevant to local users (`password_hash`, `email` etc.) and one for data that is shared by both local and federated users (`apub_id`, `public_key` etc). +In larger projects it makes sense to split this data in two. One for data relevant to local users (`password_hash`, `email` etc.) and one for data that is shared by both local and federated users (`federation_id`, `public_key` etc). -Finally we need to implement the traits [ApubObject](crate::traits::ApubObject) and [Actor](crate::traits::Actor) for `DbUser`. These traits are used to convert between `Person` and `DbUser` types. [ApubObject::from_apub](crate::traits::ApubObject::from_apub) must store the received object in database, so that it can later be retrieved without network calls using [ApubObject::read_from_apub_id](crate::traits::ApubObject::read_from_apub_id). Refer to the documentation for more details. +Finally we need to implement the traits [Object](crate::traits::Object) and [Actor](crate::traits::Actor) for `DbUser`. These traits are used to convert between `Person` and `DbUser` types. [Object::from_json](crate::traits::Object::from_json) must store the received object in database, so that it can later be retrieved without network calls using [Object::read_from_id](crate::traits::Object::read_from_id). Refer to the documentation for more details. diff --git a/docs/04_federating_posts.md b/docs/04_federating_posts.md index c0baea6..fffdf72 100644 --- a/docs/04_federating_posts.md +++ b/docs/04_federating_posts.md @@ -25,4 +25,4 @@ The most important fields are: - `attributedTo`: ID of the user who created this post - `to`, `cc`: Who the object is for. The special "public" URL indicates that everyone can view it. It also gets delivered to followers of the LemmyDev account. -Just like for `Person` before, we need to implement a protocol type and a database type, then implement trait `ApubObject`. See the example for details. +Just like for `Person` before, we need to implement a protocol type and a database type, then implement trait `Object`. See the example for details. diff --git a/docs/06_http_endpoints_axum.md b/docs/06_http_endpoints_axum.md index f96b643..d2eea49 100644 --- a/docs/06_http_endpoints_axum.md +++ b/docs/06_http_endpoints_axum.md @@ -6,17 +6,17 @@ The next step is to allow other servers to fetch our actors and objects. For thi # use std::net::SocketAddr; # use activitypub_federation::config::FederationConfig; # use activitypub_federation::protocol::context::WithContext; -# use activitypub_federation::axum::json::ApubJson; +# use activitypub_federation::axum::json::FederationJson; # use anyhow::Error; # use activitypub_federation::traits::tests::Person; # use activitypub_federation::config::Data; # use activitypub_federation::traits::tests::DbConnection; # use axum::extract::Path; -# use activitypub_federation::config::ApubMiddleware; +# use activitypub_federation::config::FederationMiddleware; # use axum::routing::get; -# use crate::activitypub_federation::traits::ApubObject; +# use crate::activitypub_federation::traits::Object; # use axum::headers::ContentType; -# use activitypub_federation::APUB_JSON_CONTENT_TYPE; +# use activitypub_federation::FEDERATION_CONTENT_TYPE; # use axum::TypedHeader; # use axum::response::IntoResponse; # use http::HeaderMap; @@ -31,7 +31,7 @@ async fn main() -> Result<(), Error> { let app = axum::Router::new() .route("/user/:name", get(http_get_user)) - .layer(ApubMiddleware::new(data)); + .layer(FederationMiddleware::new(data)); let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); tracing::debug!("listening on {}", addr); @@ -47,10 +47,10 @@ async fn http_get_user( data: Data, ) -> impl IntoResponse { let accept = header_map.get("accept").map(|v| v.to_str().unwrap()); - if accept == Some(APUB_JSON_CONTENT_TYPE) { + if accept == Some(FEDERATION_CONTENT_TYPE) { let db_user = data.read_local_user(name).await.unwrap(); - let apub_user = db_user.into_apub(&data).await.unwrap(); - ApubJson(WithContext::new_default(apub_user)).into_response() + let json_user = db_user.into_json(&data).await.unwrap(); + FederationJson(WithContext::new_default(json_user)).into_response() } else { generate_user_html(name, data).await @@ -60,7 +60,7 @@ async fn http_get_user( There are a couple of things going on here. Like before we are constructing the federation config with our domain and application data. We pass this to a middleware to make it available in request handlers, then listening on a port with the axum webserver. -The `http_get_user` method allows retrieving a user profile from `/user/:name`. It checks the `accept` header, and compares it to the one used by Activitypub (`application/activity+json`). If it matches, the user is read from database and converted to Activitypub json format. The `context` field is added (`WithContext` for `json-ld` compliance), and it is converted to a JSON response with header `content-type: application/activity+json` using `ApubJson`. It can now be retrieved with the command `curl -H 'Accept: application/activity+json' ...` introduced earlier, or with `ObjectId`. +The `http_get_user` method allows retrieving a user profile from `/user/:name`. It checks the `accept` header, and compares it to the one used by Activitypub (`application/activity+json`). If it matches, the user is read from database and converted to Activitypub json format. The `context` field is added (`WithContext` for `json-ld` compliance), and it is converted to a JSON response with header `content-type: application/activity+json` using `FederationJson`. It can now be retrieved with the command `curl -H 'Accept: application/activity+json' ...` introduced earlier, or with `ObjectId`. If the `accept` header doesn't match, it renders the user profile as HTML for viewing in a web browser. @@ -89,6 +89,6 @@ async fn webfinger( ) -> Result, Error> { let name = extract_webfinger_name(&query.resource, &data)?; let db_user = data.read_local_user(name).await?; - Ok(Json(build_webfinger_response(query.resource, db_user.apub_id))) + Ok(Json(build_webfinger_response(query.resource, db_user.federation_id))) } ``` diff --git a/docs/07_fetching_data.md b/docs/07_fetching_data.md index cf877dd..caab27f 100644 --- a/docs/07_fetching_data.md +++ b/docs/07_fetching_data.md @@ -21,7 +21,7 @@ assert!(user.is_ok()); }).unwrap() ``` -`dereference` retrieves the object JSON at the given URL, and uses serde to convert it to `Person`. It then calls your method `ApubObject::from_apub` which inserts it in the database and returns a `DbUser` struct. `request_data` contains the federation config as well as a counter of outgoing HTTP requests. If this counter exceeds the configured maximum, further requests are aborted in order to avoid recursive fetching which could allow for a denial of service attack. +`dereference` retrieves the object JSON at the given URL, and uses serde to convert it to `Person`. It then calls your method `Object::from_json` which inserts it in the database and returns a `DbUser` struct. `request_data` contains the federation config as well as a counter of outgoing HTTP requests. If this counter exceeds the configured maximum, further requests are aborted in order to avoid recursive fetching which could allow for a denial of service attack. After dereferencing a remote object, it is stored in the local database and can be retrieved using [ObjectId::dereference_local](crate::fetch::object_id::ObjectId::dereference_local) without any network requests. This is important for performance reasons and for searching. diff --git a/docs/09_sending_activities.md b/docs/09_sending_activities.md index e971d05..a7262ea 100644 --- a/docs/09_sending_activities.md +++ b/docs/09_sending_activities.md @@ -21,7 +21,7 @@ To send an activity we need to initialize our previously defined struct, and pic # let recipient = DB_USER.clone(); let activity = Follow { actor: ObjectId::parse("https://lemmy.ml/u/nutomic")?, - object: recipient.apub_id.clone().into(), + object: recipient.federation_id.clone().into(), kind: Default::default(), id: "https://lemmy.ml/activities/321".try_into()? }; diff --git a/docs/10_fetching_objects_with_unknown_type.md b/docs/10_fetching_objects_with_unknown_type.md index fba165e..ffabb7a 100644 --- a/docs/10_fetching_objects_with_unknown_type.md +++ b/docs/10_fetching_objects_with_unknown_type.md @@ -5,7 +5,7 @@ It is sometimes necessary to fetch from a URL, but we don't know the exact type ```no_run # use activitypub_federation::traits::tests::{DbUser, DbPost}; # use activitypub_federation::fetch::object_id::ObjectId; -# use activitypub_federation::traits::ApubObject; +# use activitypub_federation::traits::Object; # use activitypub_federation::config::FederationConfig; # use serde::{Deserialize, Serialize}; # use activitypub_federation::traits::tests::DbConnection; @@ -20,43 +20,43 @@ pub enum SearchableDbObjects { #[derive(Deserialize, Serialize)] #[serde(untagged)] -pub enum SearchableApubObjects { +pub enum SearchableObjects { Person(Person), Note(Note) } #[async_trait::async_trait] -impl ApubObject for SearchableDbObjects { +impl Object for SearchableDbObjects { type DataType = DbConnection; - type ApubType = SearchableApubObjects; + type Kind = SearchableObjects; type Error = anyhow::Error; - async fn read_from_apub_id( + async fn read_from_id( object_id: Url, data: &Data, ) -> Result, Self::Error> { Ok(None) } - async fn into_apub( + async fn into_json( self, data: &Data, - ) -> Result { + ) -> Result { unimplemented!(); } - async fn verify(apub: &Self::ApubType, expected_domain: &Url, _data: &Data) -> Result<(), Self::Error> { + async fn verify(json: &Self::Kind, expected_domain: &Url, _data: &Data) -> Result<(), Self::Error> { Ok(()) } - async fn from_apub( - apub: Self::ApubType, + async fn from_json( + json: Self::Kind, data: &Data, ) -> Result { use SearchableDbObjects::*; - match apub { - SearchableApubObjects::Person(p) => Ok(User(DbUser::from_apub(p, data).await?)), - SearchableApubObjects::Note(n) => Ok(Post(DbPost::from_apub(n, data).await?)), + match json { + SearchableObjects::Person(p) => Ok(User(DbUser::from_json(p, data).await?)), + SearchableObjects::Note(n) => Ok(Post(DbPost::from_json(n, data).await?)), } } } diff --git a/examples/live_federation/activities/create_post.rs b/examples/live_federation/activities/create_post.rs index 965df33..66928a6 100644 --- a/examples/live_federation/activities/create_post.rs +++ b/examples/live_federation/activities/create_post.rs @@ -11,7 +11,7 @@ use activitypub_federation::{ fetch::object_id::ObjectId, kinds::activity::CreateType, protocol::{context::WithContext, helpers::deserialize_one_or_many}, - traits::{ActivityHandler, ApubObject}, + traits::{ActivityHandler, Object}, }; use serde::{Deserialize, Serialize}; use url::Url; @@ -63,7 +63,7 @@ impl ActivityHandler for CreatePost { } async fn receive(self, data: &Data) -> Result<(), Self::Error> { - DbPost::from_apub(self.object, data).await?; + DbPost::from_json(self.object, data).await?; Ok(()) } } diff --git a/examples/live_federation/http.rs b/examples/live_federation/http.rs index bb96622..d626396 100644 --- a/examples/live_federation/http.rs +++ b/examples/live_federation/http.rs @@ -6,12 +6,12 @@ use crate::{ use activitypub_federation::{ axum::{ inbox::{receive_activity, ActivityData}, - json::ApubJson, + json::FederationJson, }, config::Data, fetch::webfinger::{build_webfinger_response, extract_webfinger_name, Webfinger}, protocol::context::WithContext, - traits::ApubObject, + traits::Object, }; use axum::{ extract::{Path, Query}, @@ -32,10 +32,10 @@ impl IntoResponse for Error { pub async fn http_get_user( Path(name): Path, data: Data, -) -> Result>, Error> { +) -> Result>, Error> { let db_user = data.read_user(&name)?; - let apub_user = db_user.into_apub(&data).await?; - Ok(ApubJson(WithContext::new_default(apub_user))) + let json_user = db_user.into_json(&data).await?; + Ok(FederationJson(WithContext::new_default(json_user))) } #[debug_handler] diff --git a/examples/live_federation/main.rs b/examples/live_federation/main.rs index 1734f28..134c93b 100644 --- a/examples/live_federation/main.rs +++ b/examples/live_federation/main.rs @@ -4,7 +4,7 @@ use crate::{ objects::{person::DbUser, post::DbPost}, utils::generate_object_id, }; -use activitypub_federation::config::{ApubMiddleware, FederationConfig}; +use activitypub_federation::config::{FederationConfig, FederationMiddleware}; use axum::{ routing::{get, post}, Router, @@ -55,7 +55,7 @@ async fn main() -> Result<(), Error> { .route("/:user", get(http_get_user)) .route("/:user/inbox", post(http_post_user_inbox)) .route("/.well-known/webfinger", get(webfinger)) - .layer(ApubMiddleware::new(config)); + .layer(FederationMiddleware::new(config)); let addr = BIND_ADDRESS .to_socket_addrs()? diff --git a/examples/live_federation/objects/person.rs b/examples/live_federation/objects/person.rs index 0323d09..7d30320 100644 --- a/examples/live_federation/objects/person.rs +++ b/examples/live_federation/objects/person.rs @@ -5,7 +5,7 @@ use activitypub_federation::{ http_signatures::generate_actor_keypair, kinds::actor::PersonType, protocol::{public_key::PublicKey, verification::verify_domains_match}, - traits::{ActivityHandler, Actor, ApubObject}, + traits::{ActivityHandler, Actor, Object}, }; use chrono::{Local, NaiveDateTime}; use serde::{Deserialize, Serialize}; @@ -64,16 +64,16 @@ pub struct Person { } #[async_trait::async_trait] -impl ApubObject for DbUser { +impl Object for DbUser { type DataType = DatabaseHandle; - type ApubType = Person; + type Kind = Person; type Error = Error; fn last_refreshed_at(&self) -> Option { Some(self.last_refreshed_at) } - async fn read_from_apub_id( + async fn read_from_id( object_id: Url, data: &Data, ) -> Result, Self::Error> { @@ -85,7 +85,7 @@ impl ApubObject for DbUser { Ok(res) } - async fn into_apub(self, _data: &Data) -> Result { + async fn into_json(self, _data: &Data) -> Result { Ok(Person { preferred_username: self.name.clone(), kind: Default::default(), @@ -96,23 +96,23 @@ impl ApubObject for DbUser { } async fn verify( - apub: &Self::ApubType, + json: &Self::Kind, expected_domain: &Url, _data: &Data, ) -> Result<(), Self::Error> { - verify_domains_match(apub.id.inner(), expected_domain)?; + verify_domains_match(json.id.inner(), expected_domain)?; Ok(()) } - async fn from_apub( - apub: Self::ApubType, + async fn from_json( + json: Self::Kind, _data: &Data, ) -> Result { Ok(DbUser { - name: apub.preferred_username, - ap_id: apub.id, - inbox: apub.inbox, - public_key: apub.public_key.public_key_pem, + name: json.preferred_username, + ap_id: json.id, + inbox: json.inbox, + public_key: json.public_key.public_key_pem, private_key: None, last_refreshed_at: Local::now().naive_local(), followers: vec![], diff --git a/examples/live_federation/objects/post.rs b/examples/live_federation/objects/post.rs index 2a84031..9a08b9d 100644 --- a/examples/live_federation/objects/post.rs +++ b/examples/live_federation/objects/post.rs @@ -10,7 +10,7 @@ use activitypub_federation::{ fetch::object_id::ObjectId, kinds::{object::NoteType, public}, protocol::{helpers::deserialize_one_or_many, verification::verify_domains_match}, - traits::{Actor, ApubObject}, + traits::{Actor, Object}, }; use activitystreams_kinds::link::MentionType; use serde::{Deserialize, Serialize}; @@ -46,44 +46,41 @@ pub struct Mention { } #[async_trait::async_trait] -impl ApubObject for DbPost { +impl Object for DbPost { type DataType = DatabaseHandle; - type ApubType = Note; + type Kind = Note; type Error = Error; - async fn read_from_apub_id( + async fn read_from_id( _object_id: Url, _data: &Data, ) -> Result, Self::Error> { Ok(None) } - async fn into_apub(self, _data: &Data) -> Result { + async fn into_json(self, _data: &Data) -> Result { unimplemented!() } async fn verify( - apub: &Self::ApubType, + json: &Self::Kind, expected_domain: &Url, _data: &Data, ) -> Result<(), Self::Error> { - verify_domains_match(apub.id.inner(), expected_domain)?; + verify_domains_match(json.id.inner(), expected_domain)?; Ok(()) } - async fn from_apub( - apub: Self::ApubType, - data: &Data, - ) -> Result { + async fn from_json(json: Self::Kind, data: &Data) -> Result { println!( "Received post with content {} and id {}", - &apub.content, &apub.id + &json.content, &json.id ); - let creator = apub.attributed_to.dereference(data).await?; + let creator = json.attributed_to.dereference(data).await?; let post = DbPost { - text: apub.content, - ap_id: apub.id.clone(), - creator: apub.attributed_to.clone(), + text: json.content, + ap_id: json.id.clone(), + creator: json.attributed_to.clone(), local: false, }; @@ -97,7 +94,7 @@ impl ApubObject for DbPost { attributed_to: data.local_user().ap_id, to: vec![public()], content: format!("Hello {}", creator.name), - in_reply_to: Some(apub.id.clone()), + in_reply_to: Some(json.id.clone()), tag: vec![mention], }; CreatePost::send(note, creator.shared_inbox_or_inbox(), data).await?; diff --git a/examples/local_federation/activities/create_post.rs b/examples/local_federation/activities/create_post.rs index 661452b..6f85e2d 100644 --- a/examples/local_federation/activities/create_post.rs +++ b/examples/local_federation/activities/create_post.rs @@ -8,7 +8,7 @@ use activitypub_federation::{ fetch::object_id::ObjectId, kinds::activity::CreateType, protocol::helpers::deserialize_one_or_many, - traits::{ActivityHandler, ApubObject}, + traits::{ActivityHandler, Object}, }; use serde::{Deserialize, Serialize}; use url::Url; @@ -56,7 +56,7 @@ impl ActivityHandler for CreatePost { } async fn receive(self, data: &Data) -> Result<(), Self::Error> { - DbPost::from_apub(self.object, data).await?; + DbPost::from_json(self.object, data).await?; Ok(()) } } diff --git a/examples/local_federation/actix_web/http.rs b/examples/local_federation/actix_web/http.rs index 238f85b..cb9e911c 100644 --- a/examples/local_federation/actix_web/http.rs +++ b/examples/local_federation/actix_web/http.rs @@ -5,11 +5,11 @@ use crate::{ }; use activitypub_federation::{ actix_web::inbox::receive_activity, - config::{ApubMiddleware, Data, FederationConfig}, + config::{Data, FederationConfig, FederationMiddleware}, fetch::webfinger::{build_webfinger_response, extract_webfinger_name}, protocol::context::WithContext, - traits::ApubObject, - APUB_JSON_CONTENT_TYPE, + traits::Object, + FEDERATION_CONTENT_TYPE, }; use actix_web::{web, web::Bytes, App, HttpRequest, HttpResponse, HttpServer}; use anyhow::anyhow; @@ -22,7 +22,7 @@ pub fn listen(config: &FederationConfig) -> Result<(), Error> { let config = config.clone(); let server = HttpServer::new(move || { App::new() - .wrap(ApubMiddleware::new(config.clone())) + .wrap(FederationMiddleware::new(config.clone())) .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)) @@ -40,10 +40,10 @@ pub async fn http_get_user( ) -> Result { let db_user = data.local_user(); if user_name.into_inner() == db_user.name { - let apub_user = db_user.into_apub(&data).await?; + let json_user = db_user.into_json(&data).await?; Ok(HttpResponse::Ok() - .content_type(APUB_JSON_CONTENT_TYPE) - .json(WithContext::new_default(apub_user))) + .content_type(FEDERATION_CONTENT_TYPE) + .json(WithContext::new_default(json_user))) } else { Err(anyhow!("Invalid user").into()) } diff --git a/examples/local_federation/axum/http.rs b/examples/local_federation/axum/http.rs index a14b86b..c67df08 100644 --- a/examples/local_federation/axum/http.rs +++ b/examples/local_federation/axum/http.rs @@ -6,12 +6,12 @@ use crate::{ use activitypub_federation::{ axum::{ inbox::{receive_activity, ActivityData}, - json::ApubJson, + json::FederationJson, }, - config::{ApubMiddleware, Data, FederationConfig}, + config::{Data, FederationConfig, FederationMiddleware}, fetch::webfinger::{build_webfinger_response, extract_webfinger_name, Webfinger}, protocol::context::WithContext, - traits::ApubObject, + traits::Object, }; use axum::{ extract::{Path, Query}, @@ -33,7 +33,7 @@ pub fn listen(config: &FederationConfig) -> Result<(), Error> { .route("/:user/inbox", post(http_post_user_inbox)) .route("/:user", get(http_get_user)) .route("/.well-known/webfinger", get(webfinger)) - .layer(ApubMiddleware::new(config)); + .layer(FederationMiddleware::new(config)); let addr = hostname .to_socket_addrs()? @@ -49,10 +49,10 @@ pub fn listen(config: &FederationConfig) -> Result<(), Error> { async fn http_get_user( Path(name): Path, data: Data, -) -> Result>, Error> { +) -> Result>, Error> { let db_user = data.read_user(&name)?; - let apub_user = db_user.into_apub(&data).await?; - Ok(ApubJson(WithContext::new_default(apub_user))) + let json_user = db_user.into_json(&data).await?; + Ok(FederationJson(WithContext::new_default(json_user))) } #[debug_handler] diff --git a/examples/local_federation/objects/person.rs b/examples/local_federation/objects/person.rs index 517f147..5579af0 100644 --- a/examples/local_federation/objects/person.rs +++ b/examples/local_federation/objects/person.rs @@ -12,7 +12,7 @@ use activitypub_federation::{ http_signatures::generate_actor_keypair, kinds::actor::PersonType, protocol::{context::WithContext, public_key::PublicKey, verification::verify_domains_match}, - traits::{ActivityHandler, Actor, ApubObject}, + traits::{ActivityHandler, Actor, Object}, }; use chrono::{Local, NaiveDateTime}; use serde::{Deserialize, Serialize}; @@ -92,7 +92,7 @@ impl DbUser { pub async fn post(&self, post: DbPost, data: &Data) -> Result<(), Error> { let id = generate_object_id(data.domain())?; - let create = CreatePost::new(post.into_apub(data).await?, id.clone()); + let create = CreatePost::new(post.into_json(data).await?, id.clone()); let mut inboxes = vec![]; for f in self.followers.clone() { let user: DbUser = ObjectId::from(f).dereference(data).await?; @@ -119,16 +119,16 @@ impl DbUser { } #[async_trait::async_trait] -impl ApubObject for DbUser { +impl Object for DbUser { type DataType = DatabaseHandle; - type ApubType = Person; + type Kind = Person; type Error = Error; fn last_refreshed_at(&self) -> Option { Some(self.last_refreshed_at) } - async fn read_from_apub_id( + async fn read_from_id( object_id: Url, data: &Data, ) -> Result, Self::Error> { @@ -140,7 +140,7 @@ impl ApubObject for DbUser { Ok(res) } - async fn into_apub(self, _data: &Data) -> Result { + async fn into_json(self, _data: &Data) -> Result { Ok(Person { preferred_username: self.name.clone(), kind: Default::default(), @@ -151,23 +151,20 @@ impl ApubObject for DbUser { } async fn verify( - apub: &Self::ApubType, + json: &Self::Kind, expected_domain: &Url, _data: &Data, ) -> Result<(), Self::Error> { - verify_domains_match(apub.id.inner(), expected_domain)?; + verify_domains_match(json.id.inner(), expected_domain)?; Ok(()) } - async fn from_apub( - apub: Self::ApubType, - data: &Data, - ) -> Result { + async fn from_json(json: Self::Kind, data: &Data) -> Result { let user = DbUser { - name: apub.preferred_username, - ap_id: apub.id, - inbox: apub.inbox, - public_key: apub.public_key.public_key_pem, + name: json.preferred_username, + ap_id: json.id, + inbox: json.inbox, + public_key: json.public_key.public_key_pem, private_key: None, last_refreshed_at: Local::now().naive_local(), followers: vec![], diff --git a/examples/local_federation/objects/post.rs b/examples/local_federation/objects/post.rs index 5e2f0a0..cbdf8e8 100644 --- a/examples/local_federation/objects/post.rs +++ b/examples/local_federation/objects/post.rs @@ -4,7 +4,7 @@ use activitypub_federation::{ fetch::object_id::ObjectId, kinds::{object::NoteType, public}, protocol::{helpers::deserialize_one_or_many, verification::verify_domains_match}, - traits::ApubObject, + traits::Object, }; use serde::{Deserialize, Serialize}; use url::Url; @@ -42,12 +42,12 @@ pub struct Note { } #[async_trait::async_trait] -impl ApubObject for DbPost { +impl Object for DbPost { type DataType = DatabaseHandle; - type ApubType = Note; + type Kind = Note; type Error = Error; - async fn read_from_apub_id( + async fn read_from_id( object_id: Url, data: &Data, ) -> Result, Self::Error> { @@ -59,7 +59,7 @@ impl ApubObject for DbPost { Ok(res) } - async fn into_apub(self, data: &Data) -> Result { + async fn into_json(self, data: &Data) -> Result { let creator = self.creator.dereference_local(data).await?; Ok(Note { kind: Default::default(), @@ -71,22 +71,19 @@ impl ApubObject for DbPost { } async fn verify( - apub: &Self::ApubType, + json: &Self::Kind, expected_domain: &Url, _data: &Data, ) -> Result<(), Self::Error> { - verify_domains_match(apub.id.inner(), expected_domain)?; + verify_domains_match(json.id.inner(), expected_domain)?; Ok(()) } - async fn from_apub( - apub: Self::ApubType, - data: &Data, - ) -> Result { + async fn from_json(json: Self::Kind, data: &Data) -> Result { let post = DbPost { - text: apub.content, - ap_id: apub.id, - creator: apub.attributed_to, + text: json.content, + ap_id: json.id, + creator: json.attributed_to, local: false, }; diff --git a/src/activity_queue.rs b/src/activity_queue.rs index 8f7a6b7..896f48f 100644 --- a/src/activity_queue.rs +++ b/src/activity_queue.rs @@ -8,7 +8,7 @@ use crate::{ http_signatures::sign_request, reqwest_shim::ResponseExt, traits::{ActivityHandler, Actor}, - APUB_JSON_CONTENT_TYPE, + FEDERATION_CONTENT_TYPE, }; use anyhow::anyhow; use background_jobs::{ @@ -203,7 +203,7 @@ fn generate_request_headers(inbox_url: &Url) -> HeaderMap { let mut headers = HeaderMap::new(); headers.insert( HeaderName::from_static("content-type"), - HeaderValue::from_static(APUB_JSON_CONTENT_TYPE), + HeaderValue::from_static(FEDERATION_CONTENT_TYPE), ); headers.insert( HeaderName::from_static("host"), diff --git a/src/actix_web/inbox.rs b/src/actix_web/inbox.rs index d9cd4b1..2aba973 100644 --- a/src/actix_web/inbox.rs +++ b/src/actix_web/inbox.rs @@ -5,7 +5,7 @@ use crate::{ error::Error, fetch::object_id::ObjectId, http_signatures::{verify_inbox_hash, verify_signature}, - traits::{ActivityHandler, Actor, ApubObject}, + traits::{ActivityHandler, Actor, Object}, }; use actix_web::{web::Bytes, HttpRequest, HttpResponse}; use serde::de::DeserializeOwned; @@ -21,13 +21,13 @@ pub async fn receive_activity( ) -> Result::Error> where Activity: ActivityHandler + DeserializeOwned + Send + 'static, - ActorT: ApubObject + Actor + Send + 'static, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + ActorT: Object + Actor + Send + 'static, + for<'de2> ::Kind: serde::Deserialize<'de2>, ::Error: From + From - + From<::Error> + + From<::Error> + From, - ::Error: From + From, + ::Error: From + From, Datatype: Clone, { verify_inbox_hash(request.headers().get("Digest"), &body)?; diff --git a/src/actix_web/middleware.rs b/src/actix_web/middleware.rs index 1ca3c05..afa0117 100644 --- a/src/actix_web/middleware.rs +++ b/src/actix_web/middleware.rs @@ -1,4 +1,4 @@ -use crate::config::{ApubMiddleware, Data, FederationConfig}; +use crate::config::{Data, FederationConfig, FederationMiddleware}; use actix_web::{ dev::{forward_ready, Payload, Service, ServiceRequest, ServiceResponse, Transform}, Error, @@ -8,7 +8,7 @@ use actix_web::{ }; use std::future::{ready, Ready}; -impl Transform for ApubMiddleware +impl Transform for FederationMiddleware where S: Service, Error = Error>, S::Future: 'static, @@ -17,12 +17,12 @@ where { type Response = ServiceResponse; type Error = Error; - type Transform = ApubService; + type Transform = FederationService; type InitError = (); type Future = Ready>; fn new_transform(&self, service: S) -> Self::Future { - ready(Ok(ApubService { + ready(Ok(FederationService { service, config: self.0.clone(), })) @@ -31,7 +31,7 @@ where /// Passes [FederationConfig] to HTTP handlers, converting it to [Data] in the process #[doc(hidden)] -pub struct ApubService +pub struct FederationService where S: Service, S::Future: 'static, @@ -41,7 +41,7 @@ where config: FederationConfig, } -impl Service for ApubService +impl Service for FederationService where S: Service, Error = Error>, S::Future: 'static, @@ -69,7 +69,7 @@ impl FromRequest for Data { ready(match req.extensions().get::>() { Some(c) => Ok(c.to_request_data()), None => Err(actix_web::error::ErrorBadRequest( - "Missing extension, did you register ApubMiddleware?", + "Missing extension, did you register FederationMiddleware?", )), }) } diff --git a/src/axum/inbox.rs b/src/axum/inbox.rs index 3f761d0..73266ba 100644 --- a/src/axum/inbox.rs +++ b/src/axum/inbox.rs @@ -7,7 +7,7 @@ use crate::{ error::Error, fetch::object_id::ObjectId, http_signatures::{verify_inbox_hash, verify_signature}, - traits::{ActivityHandler, Actor, ApubObject}, + traits::{ActivityHandler, Actor, Object}, }; use axum::{ async_trait, @@ -27,13 +27,13 @@ pub async fn receive_activity( ) -> Result<(), ::Error> where Activity: ActivityHandler + DeserializeOwned + Send + 'static, - ActorT: ApubObject + Actor + Send + 'static, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + ActorT: Object + Actor + Send + 'static, + for<'de2> ::Kind: serde::Deserialize<'de2>, ::Error: From + From - + From<::Error> + + From<::Error> + From, - ::Error: From + From, + ::Error: From + From, Datatype: Clone, { verify_inbox_hash(activity_data.headers.get("Digest"), &activity_data.body)?; diff --git a/src/axum/json.rs b/src/axum/json.rs index 55604a2..f8a649e 100644 --- a/src/axum/json.rs +++ b/src/axum/json.rs @@ -3,34 +3,34 @@ //! ``` //! # use anyhow::Error; //! # use axum::extract::Path; -//! # use activitypub_federation::axum::json::ApubJson; +//! # use activitypub_federation::axum::json::FederationJson; //! # use activitypub_federation::protocol::context::WithContext; //! # use activitypub_federation::config::Data; -//! # use activitypub_federation::traits::ApubObject; +//! # use activitypub_federation::traits::Object; //! # use activitypub_federation::traits::tests::{DbConnection, DbUser, Person}; -//! async fn http_get_user(Path(name): Path, data: Data) -> Result>, Error> { +//! async fn http_get_user(Path(name): Path, data: Data) -> Result>, Error> { //! let user: DbUser = data.read_local_user(name).await?; -//! let person = user.into_apub(&data).await?; +//! let person = user.into_json(&data).await?; //! -//! Ok(ApubJson(WithContext::new_default(person))) +//! Ok(FederationJson(WithContext::new_default(person))) //! } //! ``` -use crate::APUB_JSON_CONTENT_TYPE; +use crate::FEDERATION_CONTENT_TYPE; use axum::response::IntoResponse; use http::header; use serde::Serialize; /// Wrapper struct to respond with `application/activity+json` in axum handlers #[derive(Debug, Clone, Copy, Default)] -pub struct ApubJson(pub Json); +pub struct FederationJson(pub Json); -impl IntoResponse for ApubJson { +impl IntoResponse for FederationJson { fn into_response(self) -> axum::response::Response { let mut response = axum::response::Json(self.0).into_response(); response.headers_mut().insert( header::CONTENT_TYPE, - APUB_JSON_CONTENT_TYPE + FEDERATION_CONTENT_TYPE .parse() .expect("Parsing 'application/activity+json' should never fail"), ); diff --git a/src/axum/middleware.rs b/src/axum/middleware.rs index 11b6c4a..290dc94 100644 --- a/src/axum/middleware.rs +++ b/src/axum/middleware.rs @@ -1,14 +1,14 @@ -use crate::config::{ApubMiddleware, Data, FederationConfig}; +use crate::config::{Data, FederationConfig, FederationMiddleware}; use axum::{async_trait, body::Body, extract::FromRequestParts, http::Request, response::Response}; use http::{request::Parts, StatusCode}; use std::task::{Context, Poll}; use tower::{Layer, Service}; -impl Layer for ApubMiddleware { - type Service = ApubService; +impl Layer for FederationMiddleware { + type Service = FederationService; fn layer(&self, inner: S) -> Self::Service { - ApubService { + FederationService { inner, config: self.0.clone(), } @@ -18,12 +18,12 @@ impl Layer for ApubMiddleware { /// Passes [FederationConfig] to HTTP handlers, converting it to [Data] in the process #[doc(hidden)] #[derive(Clone)] -pub struct ApubService { +pub struct FederationService { inner: S, config: FederationConfig, } -impl Service> for ApubService +impl Service> for FederationService where S: Service, Response = Response> + Send + 'static, S::Future: Send + 'static, @@ -56,7 +56,7 @@ where Some(c) => Ok(c.to_request_data()), None => Err(( StatusCode::INTERNAL_SERVER_ERROR, - "Missing extension, did you register ApubMiddleware?", + "Missing extension, did you register FederationMiddleware?", )), } } diff --git a/src/config.rs b/src/config.rs index b4b40d8..c5e46a9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -295,11 +295,11 @@ impl Deref for Data { /// Middleware for HTTP handlers which provides access to [Data] #[derive(Clone)] -pub struct ApubMiddleware(pub(crate) FederationConfig); +pub struct FederationMiddleware(pub(crate) FederationConfig); -impl ApubMiddleware { +impl FederationMiddleware { /// Construct a new middleware instance pub fn new(config: FederationConfig) -> Self { - ApubMiddleware(config) + FederationMiddleware(config) } } diff --git a/src/fetch/collection_id.rs b/src/fetch/collection_id.rs index 4524e6f..48e3867 100644 --- a/src/fetch/collection_id.rs +++ b/src/fetch/collection_id.rs @@ -1,4 +1,4 @@ -use crate::{config::Data, error::Error, fetch::fetch_object_http, traits::ApubCollection}; +use crate::{config::Data, error::Error, fetch::fetch_object_http, traits::Collection}; use serde::{Deserialize, Serialize}; use std::{ fmt::{Debug, Display, Formatter}, @@ -11,13 +11,13 @@ use url::Url; #[serde(transparent)] pub struct CollectionId(Box, PhantomData) where - Kind: ApubCollection, - for<'de2> ::ApubType: Deserialize<'de2>; + Kind: Collection, + for<'de2> ::Kind: Deserialize<'de2>; impl CollectionId where - Kind: ApubCollection, - for<'de2> ::ApubType: Deserialize<'de2>, + Kind: Collection, + for<'de2> ::Kind: Deserialize<'de2>, { /// Construct a new CollectionId instance pub fn parse(url: T) -> Result @@ -34,23 +34,23 @@ where /// any caching. pub async fn dereference( &self, - owner: &::Owner, - data: &Data<::DataType>, - ) -> Result::Error> + owner: &::Owner, + data: &Data<::DataType>, + ) -> Result::Error> where - ::Error: From, + ::Error: From, { - let apub = fetch_object_http(&self.0, data).await?; - Kind::verify(&apub, &self.0, data).await?; - Kind::from_apub(apub, owner, data).await + let json = fetch_object_http(&self.0, data).await?; + Kind::verify(&json, &self.0, data).await?; + Kind::from_json(json, owner, data).await } } /// Need to implement clone manually, to avoid requiring Kind to be Clone impl Clone for CollectionId where - Kind: ApubCollection, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + Kind: Collection, + for<'de2> ::Kind: serde::Deserialize<'de2>, { fn clone(&self) -> Self { CollectionId(self.0.clone(), self.1) @@ -59,8 +59,8 @@ where impl Display for CollectionId where - Kind: ApubCollection, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + Kind: Collection, + for<'de2> ::Kind: serde::Deserialize<'de2>, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0.as_str()) @@ -69,8 +69,8 @@ where impl Debug for CollectionId where - Kind: ApubCollection, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + Kind: Collection, + for<'de2> ::Kind: serde::Deserialize<'de2>, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0.as_str()) @@ -78,8 +78,8 @@ where } impl From> for Url where - Kind: ApubCollection, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + Kind: Collection, + for<'de2> ::Kind: serde::Deserialize<'de2>, { fn from(id: CollectionId) -> Self { *id.0 @@ -88,8 +88,8 @@ where impl From for CollectionId where - Kind: ApubCollection + Send + 'static, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + Kind: Collection + Send + 'static, + for<'de2> ::Kind: serde::Deserialize<'de2>, { fn from(url: Url) -> Self { CollectionId(Box::new(url), PhantomData::) diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index be76966..a19827d 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -2,7 +2,7 @@ //! #![doc = include_str!("../../docs/07_fetching_data.md")] -use crate::{config::Data, error::Error, reqwest_shim::ResponseExt, APUB_JSON_CONTENT_TYPE}; +use crate::{config::Data, error::Error, reqwest_shim::ResponseExt, FEDERATION_CONTENT_TYPE}; use http::StatusCode; use serde::de::DeserializeOwned; use std::sync::atomic::Ordering; @@ -44,7 +44,7 @@ pub async fn fetch_object_http( let res = config .client .get(url.as_str()) - .header("Accept", APUB_JSON_CONTENT_TYPE) + .header("Accept", FEDERATION_CONTENT_TYPE) .timeout(config.request_timeout) .send() .await diff --git a/src/fetch/object_id.rs b/src/fetch/object_id.rs index f0d2f76..1155493 100644 --- a/src/fetch/object_id.rs +++ b/src/fetch/object_id.rs @@ -1,4 +1,4 @@ -use crate::{config::Data, error::Error, fetch::fetch_object_http, traits::ApubObject}; +use crate::{config::Data, error::Error, fetch::fetch_object_http, traits::Object}; use anyhow::anyhow; use chrono::{Duration as ChronoDuration, NaiveDateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -11,8 +11,8 @@ use url::Url; impl FromStr for ObjectId where - T: ApubObject + Send + 'static, - for<'de2> ::ApubType: Deserialize<'de2>, + T: Object + Send + 'static, + for<'de2> ::Kind: Deserialize<'de2>, { type Err = url::ParseError; @@ -58,13 +58,13 @@ where #[serde(transparent)] pub struct ObjectId(Box, PhantomData) where - Kind: ApubObject, - for<'de2> ::ApubType: serde::Deserialize<'de2>; + Kind: Object, + for<'de2> ::Kind: serde::Deserialize<'de2>; impl ObjectId where - Kind: ApubObject + Send + 'static, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + Kind: Object + Send + 'static, + for<'de2> ::Kind: serde::Deserialize<'de2>, { /// Construct a new objectid instance pub fn parse(url: T) -> Result @@ -88,10 +88,10 @@ where /// Fetches an activitypub object, either from local database (if possible), or over http. pub async fn dereference( &self, - data: &Data<::DataType>, - ) -> Result::Error> + data: &Data<::DataType>, + ) -> Result::Error> where - ::Error: From + From, + ::Error: From + From, { let db_object = self.dereference_from_db(data).await?; @@ -123,10 +123,10 @@ where /// the object is not found in the database. pub async fn dereference_local( &self, - data: &Data<::DataType>, - ) -> Result::Error> + data: &Data<::DataType>, + ) -> Result::Error> where - ::Error: From, + ::Error: From, { let object = self.dereference_from_db(data).await?; object.ok_or_else(|| Error::NotFound.into()) @@ -135,19 +135,19 @@ where /// returning none means the object was not found in local db async fn dereference_from_db( &self, - data: &Data<::DataType>, - ) -> Result, ::Error> { + data: &Data<::DataType>, + ) -> Result, ::Error> { let id = self.0.clone(); - ApubObject::read_from_apub_id(*id, data).await + Object::read_from_id(*id, data).await } async fn dereference_from_http( &self, - data: &Data<::DataType>, + data: &Data<::DataType>, db_object: Option, - ) -> Result::Error> + ) -> Result::Error> where - ::Error: From + From, + ::Error: From + From, { let res = fetch_object_http(&self.0, data).await; @@ -161,15 +161,15 @@ where let res2 = res?; Kind::verify(&res2, self.inner(), data).await?; - Kind::from_apub(res2, data).await + Kind::from_json(res2, data).await } } /// Need to implement clone manually, to avoid requiring Kind to be Clone impl Clone for ObjectId where - Kind: ApubObject, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + Kind: Object, + for<'de2> ::Kind: serde::Deserialize<'de2>, { fn clone(&self) -> Self { ObjectId(self.0.clone(), self.1) @@ -195,8 +195,8 @@ fn should_refetch_object(last_refreshed: NaiveDateTime) -> bool { impl Display for ObjectId where - Kind: ApubObject, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + Kind: Object, + for<'de2> ::Kind: serde::Deserialize<'de2>, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0.as_str()) @@ -205,8 +205,8 @@ where impl Debug for ObjectId where - Kind: ApubObject, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + Kind: Object, + for<'de2> ::Kind: serde::Deserialize<'de2>, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0.as_str()) @@ -215,8 +215,8 @@ where impl From> for Url where - Kind: ApubObject, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + Kind: Object, + for<'de2> ::Kind: serde::Deserialize<'de2>, { fn from(id: ObjectId) -> Self { *id.0 @@ -225,8 +225,8 @@ where impl From for ObjectId where - Kind: ApubObject + Send + 'static, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + Kind: Object + Send + 'static, + for<'de2> ::Kind: serde::Deserialize<'de2>, { fn from(url: Url) -> Self { ObjectId(Box::new(url), PhantomData::) @@ -235,8 +235,8 @@ where impl PartialEq for ObjectId where - Kind: ApubObject, - for<'de2> ::ApubType: serde::Deserialize<'de2>, + Kind: Object, + for<'de2> ::Kind: serde::Deserialize<'de2>, { fn eq(&self, other: &Self) -> bool { self.0.eq(&other.0) && self.1 == other.1 diff --git a/src/fetch/webfinger.rs b/src/fetch/webfinger.rs index 281b005..8160e36 100644 --- a/src/fetch/webfinger.rs +++ b/src/fetch/webfinger.rs @@ -2,8 +2,8 @@ use crate::{ config::Data, error::{Error, Error::WebfingerResolveFailed}, fetch::{fetch_object_http, object_id::ObjectId}, - traits::{Actor, ApubObject}, - APUB_JSON_CONTENT_TYPE, + traits::{Actor, Object}, + FEDERATION_CONTENT_TYPE, }; use anyhow::anyhow; use itertools::Itertools; @@ -20,11 +20,11 @@ use url::Url; pub async fn webfinger_resolve_actor( identifier: &str, data: &Data, -) -> Result::Error> +) -> Result::Error> where - Kind: ApubObject + Actor + Send + 'static + ApubObject, - for<'de2> ::ApubType: serde::Deserialize<'de2>, - ::Error: + Kind: Object + Actor + Send + 'static + Object, + for<'de2> ::Kind: serde::Deserialize<'de2>, + ::Error: From + From + From + Send + Sync, { let (_, domain) = identifier @@ -107,7 +107,7 @@ pub fn build_webfinger_response(subject: String, url: Url) -> Webfinger { }, WebfingerLink { rel: Some("self".to_string()), - kind: Some(APUB_JSON_CONTENT_TYPE.to_string()), + kind: Some(FEDERATION_CONTENT_TYPE.to_string()), href: Some(url), properties: Default::default(), }, diff --git a/src/lib.rs b/src/lib.rs index 41fbce2..2031c98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,4 +26,4 @@ pub mod traits; pub use activitystreams_kinds as kinds; /// Mime type for Activitypub data, used for `Accept` and `Content-Type` HTTP headers -pub static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json"; +pub static FEDERATION_CONTENT_TYPE: &str = "application/activity+json"; diff --git a/src/traits.rs b/src/traits.rs index 6ec244d..876bdbf 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -18,7 +18,7 @@ use url::Url; /// # use activitypub_federation::config::Data; /// # use activitypub_federation::fetch::object_id::ObjectId; /// # use activitypub_federation::protocol::verification::verify_domains_match; -/// # use activitypub_federation::traits::{Actor, ApubObject}; +/// # use activitypub_federation::traits::{Actor, Object}; /// # use activitypub_federation::traits::tests::{DbConnection, DbUser}; /// # /// /// How the post is read/written in the local database @@ -43,18 +43,18 @@ use url::Url; /// } /// /// #[async_trait::async_trait] -/// impl ApubObject for DbPost { +/// impl Object for DbPost { /// type DataType = DbConnection; -/// type ApubType = Note; +/// type Kind = Note; /// type Error = anyhow::Error; /// -/// async fn read_from_apub_id(object_id: Url, data: &Data) -> Result, Self::Error> { +/// async fn read_from_id(object_id: Url, data: &Data) -> Result, Self::Error> { /// // Attempt to read object from local database. Return Ok(None) if not found. -/// let post: Option = data.read_post_from_apub_id(object_id).await?; +/// let post: Option = data.read_post_from_json_id(object_id).await?; /// Ok(post) /// } /// -/// async fn into_apub(self, data: &Data) -> Result { +/// async fn into_json(self, data: &Data) -> Result { /// // Called when a local object gets sent out over Activitypub. Simply convert it to the /// // protocol struct /// Ok(Note { @@ -66,20 +66,20 @@ use url::Url; /// }) /// } /// -/// async fn verify(apub: &Self::ApubType, expected_domain: &Url, data: &Data,) -> Result<(), Self::Error> { -/// verify_domains_match(apub.id.inner(), expected_domain)?; +/// async fn verify(json: &Self::Kind, expected_domain: &Url, data: &Data,) -> Result<(), Self::Error> { +/// verify_domains_match(json.id.inner(), expected_domain)?; /// // additional application specific checks /// Ok(()) /// } /// -/// async fn from_apub(apub: Self::ApubType, data: &Data) -> Result { +/// async fn from_json(json: Self::Kind, data: &Data) -> Result { /// // Called when a remote object gets received over Activitypub. Validate and insert it /// // into the database. /// /// let post = DbPost { -/// text: apub.content, -/// ap_id: apub.id, -/// creator: apub.attributed_to, +/// text: json.content, +/// ap_id: json.id, +/// creator: json.attributed_to, /// local: false, /// }; /// @@ -93,12 +93,12 @@ use url::Url; /// /// } #[async_trait] -pub trait ApubObject: Sized { +pub trait Object: Sized { /// App data type passed to handlers. Must be identical to /// [crate::config::FederationConfigBuilder::app_data] type. type DataType: Clone + Send + Sync; /// The type of protocol struct which gets sent over network to federate this database struct. - type ApubType; + type Kind; /// Error type returned by handler methods type Error; @@ -118,7 +118,7 @@ pub trait ApubObject: Sized { /// Try to read the object with given `id` from local database. /// /// Should return `Ok(None)` if not found. - async fn read_from_apub_id( + async fn read_from_id( object_id: Url, data: &Data, ) -> Result, Self::Error>; @@ -134,7 +134,7 @@ pub trait ApubObject: Sized { /// /// Called when a local object gets fetched by another instance over HTTP, or when an object /// gets sent in an activity. - async fn into_apub(self, data: &Data) -> Result; + async fn into_json(self, data: &Data) -> Result; /// Verifies that the received object is valid. /// @@ -144,7 +144,7 @@ pub trait ApubObject: Sized { /// It is necessary to use a separate method for this, because it might be used for activities /// like `Delete/Note`, which shouldn't perform any database write for the inner `Note`. async fn verify( - apub: &Self::ApubType, + json: &Self::Kind, expected_domain: &Url, data: &Data, ) -> Result<(), Self::Error>; @@ -154,10 +154,7 @@ pub trait ApubObject: Sized { /// Called when an object is received from HTTP fetch or as part of an activity. This method /// should write the received object to database. Note that there is no distinction between /// create and update, so an `upsert` operation should be used. - async fn from_apub( - apub: Self::ApubType, - data: &Data, - ) -> Result; + async fn from_json(json: Self::Kind, data: &Data) -> Result; } /// Handler for receiving incoming activities. @@ -227,12 +224,12 @@ pub trait ActivityHandler { /// Called when an activity is received. /// /// Should perform validation and possibly write action to the database. In case the activity - /// has a nested `object` field, must call `object.from_apub` handler. + /// has a nested `object` field, must call `object.from_json` handler. async fn receive(self, data: &Data) -> Result<(), Self::Error>; } /// Trait to allow retrieving common Actor data. -pub trait Actor: ApubObject + Send + 'static { +pub trait Actor: Object + Send + 'static { /// `id` field of the actor fn id(&self) -> Url; @@ -295,14 +292,14 @@ where /// Trait for federating collections #[async_trait] -pub trait ApubCollection: Sized { +pub trait Collection: Sized { /// Actor or object that this collection belongs to type Owner; /// App data type passed to handlers. Must be identical to /// [crate::config::FederationConfigBuilder::app_data] type. type DataType: Clone + Send + Sync; /// The type of protocol struct which gets sent over network to federate this database struct. - type ApubType: for<'de2> Deserialize<'de2>; + type Kind: for<'de2> Deserialize<'de2>; /// Error type returned by handler methods type Error; @@ -310,14 +307,14 @@ pub trait ApubCollection: Sized { async fn read_local( owner: &Self::Owner, data: &Data, - ) -> Result; + ) -> Result; /// Verifies that the received object is valid. /// /// You should check here that the domain of id matches `expected_domain`. Additionally you /// should perform any application specific checks. async fn verify( - apub: &Self::ApubType, + json: &Self::Kind, expected_domain: &Url, data: &Data, ) -> Result<(), Self::Error>; @@ -327,8 +324,8 @@ pub trait ApubCollection: Sized { /// Called when an object is received from HTTP fetch or as part of an activity. This method /// should also write the received object to database. Note that there is no distinction /// between create and update, so an `upsert` operation should be used. - async fn from_apub( - apub: Self::ApubType, + async fn from_json( + json: Self::Kind, owner: &Self::Owner, data: &Data, ) -> Result; @@ -355,7 +352,7 @@ pub mod tests { pub struct DbConnection; impl DbConnection { - pub async fn read_post_from_apub_id(&self, _: Url) -> Result, Error> { + pub async fn read_post_from_json_id(&self, _: Url) -> Result, Error> { Ok(None) } pub async fn read_local_user(&self, _: String) -> Result { @@ -382,7 +379,7 @@ pub mod tests { #[derive(Debug, Clone)] pub struct DbUser { pub name: String, - pub apub_id: Url, + pub federation_id: Url, pub inbox: Url, pub public_key: String, #[allow(dead_code)] @@ -395,7 +392,7 @@ pub mod tests { pub static DB_USER: Lazy = Lazy::new(|| DbUser { name: String::new(), - apub_id: "https://localhost/123".parse().unwrap(), + federation_id: "https://localhost/123".parse().unwrap(), inbox: "https://localhost/123/inbox".parse().unwrap(), public_key: DB_USER_KEYPAIR.public_key.clone(), private_key: Some(DB_USER_KEYPAIR.private_key.clone()), @@ -404,49 +401,46 @@ pub mod tests { }); #[async_trait] - impl ApubObject for DbUser { + impl Object for DbUser { type DataType = DbConnection; - type ApubType = Person; + type Kind = Person; type Error = Error; - async fn read_from_apub_id( + async fn read_from_id( _object_id: Url, _data: &Data, ) -> Result, Self::Error> { Ok(Some(DB_USER.clone())) } - async fn into_apub( - self, - _data: &Data, - ) -> Result { + async fn into_json(self, _data: &Data) -> Result { Ok(Person { preferred_username: self.name.clone(), kind: Default::default(), - id: self.apub_id.clone().into(), + id: self.federation_id.clone().into(), inbox: self.inbox.clone(), public_key: self.public_key(), }) } async fn verify( - apub: &Self::ApubType, + json: &Self::Kind, expected_domain: &Url, _data: &Data, ) -> Result<(), Self::Error> { - verify_domains_match(apub.id.inner(), expected_domain)?; + verify_domains_match(json.id.inner(), expected_domain)?; Ok(()) } - async fn from_apub( - apub: Self::ApubType, + async fn from_json( + json: Self::Kind, _data: &Data, ) -> Result { Ok(DbUser { - name: apub.preferred_username, - apub_id: apub.id.into(), - inbox: apub.inbox, - public_key: apub.public_key.public_key_pem, + name: json.preferred_username, + federation_id: json.id.into(), + inbox: json.inbox, + public_key: json.public_key.public_key_pem, private_key: None, followers: vec![], local: false, @@ -456,7 +450,7 @@ pub mod tests { impl Actor for DbUser { fn id(&self) -> Url { - self.apub_id.clone() + self.federation_id.clone() } fn public_key_pem(&self) -> &str { @@ -511,34 +505,31 @@ pub mod tests { pub struct DbPost {} #[async_trait] - impl ApubObject for DbPost { + impl Object for DbPost { type DataType = DbConnection; - type ApubType = Note; + type Kind = Note; type Error = Error; - async fn read_from_apub_id( + async fn read_from_id( _: Url, _: &Data, ) -> Result, Self::Error> { todo!() } - async fn into_apub(self, _: &Data) -> Result { + async fn into_json(self, _: &Data) -> Result { todo!() } async fn verify( - _: &Self::ApubType, + _: &Self::Kind, _: &Url, _: &Data, ) -> Result<(), Self::Error> { todo!() } - async fn from_apub( - _: Self::ApubType, - _: &Data, - ) -> Result { + async fn from_json(_: Self::Kind, _: &Data) -> Result { todo!() } }