diff --git a/CHANGELOG.md b/CHANGELOG.md index b8153bc..d599f2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed - Use proof suites with prefix `Mitra`. +- Add `https://w3id.org/security/data-integrity/v1` to JSON-LD context. ## [1.12.0] - 2023-01-26 diff --git a/FEDERATION.md b/FEDERATION.md index fbd10c2..02b57a8 100644 --- a/FEDERATION.md +++ b/FEDERATION.md @@ -43,7 +43,10 @@ Example: ```json { - "@context": "https://www.w3.org/ns/activitystreams", + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/data-integrity/v1" + ], "actor": "https://example.com/users/alice", "cc": [], "id": "https://example.com/objects/0185f5f8-10b5-1b69-f45e-25f06792f411", diff --git a/src/activitypub/actors/types.rs b/src/activitypub/actors/types.rs index 9fe70db..194b125 100644 --- a/src/activitypub/actors/types.rs +++ b/src/activitypub/actors/types.rs @@ -7,7 +7,11 @@ use serde::{ use serde_json::{json, Value}; use crate::activitypub::{ - constants::{ACTOR_KEY_SUFFIX, AP_CONTEXT}, + constants::{ + ACTOR_KEY_SUFFIX, + AP_CONTEXT, + W3ID_SECURITY_CONTEXT, + }, identifiers::{local_actor_id, LocalActorCollection}, receiver::parse_property_value, vocabulary::{IDENTITY_PROOF, IMAGE, LINK, PERSON, PROPERTY_VALUE, SERVICE}, @@ -33,8 +37,6 @@ use super::attachments::{ parse_payment_option, }; -const W3ID_CONTEXT: &str = "https://w3id.org/security/v1"; - #[derive(Clone, Debug, Deserialize, Serialize)] #[cfg_attr(test, derive(Default))] #[serde(rename_all = "camelCase")] @@ -300,7 +302,7 @@ pub fn get_local_actor( let actor = Actor { context: Some(json!([ AP_CONTEXT.to_string(), - W3ID_CONTEXT.to_string(), + W3ID_SECURITY_CONTEXT.to_string(), ])), id: actor_id.clone(), object_type: PERSON.to_string(), @@ -339,7 +341,7 @@ pub fn get_instance_actor( let actor = Actor { context: Some(json!([ AP_CONTEXT.to_string(), - W3ID_CONTEXT.to_string(), + W3ID_SECURITY_CONTEXT.to_string(), ])), id: actor_id, object_type: SERVICE.to_string(), diff --git a/src/activitypub/builders/accept_follow.rs b/src/activitypub/builders/accept_follow.rs index 68d5d01..fff87f0 100644 --- a/src/activitypub/builders/accept_follow.rs +++ b/src/activitypub/builders/accept_follow.rs @@ -2,9 +2,9 @@ use serde::Serialize; use crate::activitypub::{ actors::types::Actor, - constants::AP_CONTEXT, deliverer::OutgoingActivity, identifiers::{local_actor_id, local_object_id}, + types::{build_default_context, Context}, vocabulary::ACCEPT, }; use crate::config::Instance; @@ -15,7 +15,7 @@ use crate::utils::id::new_uuid; #[derive(Serialize)] struct AcceptFollow { #[serde(rename = "@context")] - context: String, + context: Context, #[serde(rename = "type")] activity_type: String, @@ -37,7 +37,7 @@ fn build_accept_follow( let activity_id = local_object_id(instance_url, &new_uuid()); let actor_id = local_actor_id(instance_url, &actor_profile.username); AcceptFollow { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: ACCEPT.to_string(), id: activity_id, actor: actor_id, diff --git a/src/activitypub/builders/add_person.rs b/src/activitypub/builders/add_person.rs index 8bfef5a..b58e355 100644 --- a/src/activitypub/builders/add_person.rs +++ b/src/activitypub/builders/add_person.rs @@ -2,9 +2,9 @@ use serde::Serialize; use crate::activitypub::{ actors::types::Actor, - constants::AP_CONTEXT, deliverer::OutgoingActivity, identifiers::{local_actor_id, local_object_id, LocalActorCollection}, + types::{build_default_context, Context}, vocabulary::{ADD, REMOVE}, }; use crate::config::Instance; @@ -14,7 +14,7 @@ use crate::utils::id::new_uuid; #[derive(Serialize)] struct AddOrRemovePerson { #[serde(rename = "@context")] - context: String, + context: Context, #[serde(rename = "type")] activity_type: String, @@ -39,7 +39,7 @@ fn build_update_collection( let activity_type = if remove { REMOVE } else { ADD }; let collection_id = collection.of(&actor_id); AddOrRemovePerson { - context: AP_CONTEXT.to_string(), + context: build_default_context(), id: activity_id, activity_type: activity_type.to_string(), actor: actor_id, diff --git a/src/activitypub/builders/announce.rs b/src/activitypub/builders/announce.rs index 83ffec1..823cadf 100644 --- a/src/activitypub/builders/announce.rs +++ b/src/activitypub/builders/announce.rs @@ -3,9 +3,10 @@ use serde::Serialize; use crate::activitypub::{ actors::types::Actor, - constants::{AP_CONTEXT, AP_PUBLIC}, + constants::AP_PUBLIC, deliverer::OutgoingActivity, identifiers::{local_actor_followers, local_actor_id, local_object_id}, + types::{build_default_context, Context}, vocabulary::ANNOUNCE, }; use crate::config::Instance; @@ -17,7 +18,7 @@ use crate::models::users::types::User; #[derive(Serialize)] struct Announce { #[serde(rename = "@context")] - context: String, + context: Context, #[serde(rename = "type")] activity_type: String, @@ -43,7 +44,7 @@ fn build_announce( let recipient_id = post.author.actor_id(instance_url); let followers = local_actor_followers(instance_url, sender_username); Announce { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: ANNOUNCE.to_string(), actor: actor_id, id: activity_id, diff --git a/src/activitypub/builders/create_note.rs b/src/activitypub/builders/create_note.rs index 93041e3..bb4c906 100644 --- a/src/activitypub/builders/create_note.rs +++ b/src/activitypub/builders/create_note.rs @@ -3,7 +3,7 @@ use serde::Serialize; use crate::activitypub::{ actors::types::Actor, - constants::{AP_MEDIA_TYPE, AP_CONTEXT, AP_PUBLIC}, + constants::{AP_MEDIA_TYPE, AP_PUBLIC}, deliverer::OutgoingActivity, identifiers::{ local_actor_id, @@ -13,7 +13,15 @@ use crate::activitypub::{ local_object_id, local_tag_collection, }, - types::{Attachment, EmojiTag, EmojiTagImage, LinkTag, SimpleTag}, + types::{ + build_default_context, + Attachment, + Context, + EmojiTag, + EmojiTagImage, + LinkTag, + SimpleTag, + }, vocabulary::*, }; use crate::config::Instance; @@ -40,7 +48,7 @@ enum Tag { #[serde(rename_all = "camelCase")] pub struct Note { #[serde(rename = "@context")] - context: String, + context: Context, id: String, @@ -180,7 +188,7 @@ pub fn build_note( None => None, }; Note { - context: AP_CONTEXT.to_string(), + context: build_default_context(), id: object_id, object_type: NOTE.to_string(), attachment: attachments, @@ -198,7 +206,7 @@ pub fn build_note( #[derive(Serialize)] pub struct CreateNote { #[serde(rename = "@context")] - context: String, + context: Context, #[serde(rename = "type")] activity_type: String, @@ -221,7 +229,7 @@ pub fn build_create_note( let secondary_audience = object.cc.clone(); let activity_id = format!("{}/create", object.id); CreateNote { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: CREATE.to_string(), id: activity_id, actor: object.attributed_to.clone(), diff --git a/src/activitypub/builders/delete_note.rs b/src/activitypub/builders/delete_note.rs index 8500c13..8f11ecb 100644 --- a/src/activitypub/builders/delete_note.rs +++ b/src/activitypub/builders/delete_note.rs @@ -1,9 +1,9 @@ use serde::Serialize; use crate::activitypub::{ - constants::AP_CONTEXT, deliverer::OutgoingActivity, identifiers::local_actor_id, + types::{build_default_context, Context}, vocabulary::{DELETE, NOTE, TOMBSTONE}, }; use crate::config::Instance; @@ -31,7 +31,7 @@ struct Tombstone { #[derive(Serialize)] struct DeleteNote { #[serde(rename = "@context")] - context: String, + context: Context, #[serde(rename = "type")] activity_type: String, @@ -58,7 +58,7 @@ fn build_delete_note( post, ); DeleteNote { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: DELETE.to_string(), id: activity_id, actor: actor_id, diff --git a/src/activitypub/builders/delete_person.rs b/src/activitypub/builders/delete_person.rs index a2f7b40..ef85d98 100644 --- a/src/activitypub/builders/delete_person.rs +++ b/src/activitypub/builders/delete_person.rs @@ -3,8 +3,9 @@ use uuid::Uuid; use crate::activitypub::{ actors::types::Actor, - constants::{AP_CONTEXT, AP_PUBLIC}, + constants::AP_PUBLIC, deliverer::OutgoingActivity, + types::{build_default_context, Context}, vocabulary::DELETE, }; use crate::config::Instance; @@ -15,7 +16,7 @@ use crate::models::users::types::User; #[derive(Serialize)] struct DeletePerson { #[serde(rename = "@context")] - context: String, + context: Context, #[serde(rename = "type")] activity_type: String, @@ -34,7 +35,7 @@ fn build_delete_person( let actor_id = user.profile.actor_id(instance_url); let activity_id = format!("{}/delete", actor_id); DeletePerson { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: DELETE.to_string(), id: activity_id, actor: actor_id.clone(), diff --git a/src/activitypub/builders/follow.rs b/src/activitypub/builders/follow.rs index e91816d..d7d7a62 100644 --- a/src/activitypub/builders/follow.rs +++ b/src/activitypub/builders/follow.rs @@ -3,9 +3,9 @@ use uuid::Uuid; use crate::activitypub::{ actors::types::Actor, - constants::AP_CONTEXT, deliverer::OutgoingActivity, identifiers::{local_actor_id, local_object_id}, + types::{build_default_context, Context}, vocabulary::FOLLOW, }; use crate::config::Instance; @@ -15,7 +15,7 @@ use crate::models::users::types::User; #[derive(Serialize)] pub(super) struct Follow { #[serde(rename = "@context")] - pub context: String, + pub context: Context, #[serde(rename = "type")] pub activity_type: String, @@ -36,7 +36,7 @@ fn build_follow( let activity_id = local_object_id(instance_url, follow_request_id); let actor_id = local_actor_id(instance_url, &actor_profile.username); Follow { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: FOLLOW.to_string(), id: activity_id, actor: actor_id, diff --git a/src/activitypub/builders/like.rs b/src/activitypub/builders/like.rs index cd1f179..32bac4a 100644 --- a/src/activitypub/builders/like.rs +++ b/src/activitypub/builders/like.rs @@ -3,9 +3,10 @@ use uuid::Uuid; use crate::activitypub::{ actors::types::Actor, - constants::{AP_CONTEXT, AP_PUBLIC}, + constants::AP_PUBLIC, deliverer::OutgoingActivity, identifiers::{local_actor_id, local_object_id}, + types::{build_default_context, Context}, vocabulary::LIKE, }; use crate::config::Instance; @@ -17,7 +18,7 @@ use crate::models::users::types::User; #[derive(Serialize)] struct Like { #[serde(rename = "@context")] - context: String, + context: Context, #[serde(rename = "type")] activity_type: String, @@ -55,7 +56,7 @@ fn build_like( let (primary_audience, secondary_audience) = get_like_audience(post_author_id, post_visibility); Like { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: LIKE.to_string(), id: activity_id, actor: actor_id, diff --git a/src/activitypub/builders/move_person.rs b/src/activitypub/builders/move_person.rs index 60f6939..da1589f 100644 --- a/src/activitypub/builders/move_person.rs +++ b/src/activitypub/builders/move_person.rs @@ -3,9 +3,9 @@ use uuid::Uuid; use crate::activitypub::{ actors::types::Actor, - constants::AP_CONTEXT, deliverer::OutgoingActivity, identifiers::{local_actor_id, local_object_id}, + types::{build_default_context, Context}, vocabulary::MOVE, }; use crate::config::Instance; @@ -15,7 +15,7 @@ use crate::utils::id::new_uuid; #[derive(Serialize)] pub struct MovePerson { #[serde(rename = "@context")] - context: String, + context: Context, #[serde(rename = "type")] activity_type: String, @@ -40,7 +40,7 @@ pub fn build_move_person( let activity_id = local_object_id(instance_url, &internal_activity_id); let actor_id = local_actor_id(instance_url, &sender.profile.username); MovePerson { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: MOVE.to_string(), id: activity_id, actor: actor_id.clone(), diff --git a/src/activitypub/builders/undo_announce.rs b/src/activitypub/builders/undo_announce.rs index 0de1963..be60b40 100644 --- a/src/activitypub/builders/undo_announce.rs +++ b/src/activitypub/builders/undo_announce.rs @@ -2,9 +2,10 @@ use serde::Serialize; use uuid::Uuid; use crate::activitypub::{ - constants::{AP_CONTEXT, AP_PUBLIC}, + constants::AP_PUBLIC, deliverer::OutgoingActivity, identifiers::{local_actor_id, local_actor_followers, local_object_id}, + types::{build_default_context, Context}, vocabulary::UNDO, }; use crate::config::Instance; @@ -17,7 +18,7 @@ use super::announce::get_announce_recipients; #[derive(Serialize)] struct UndoAnnounce { #[serde(rename = "@context")] - context: String, + context: Context, #[serde(rename = "type")] activity_type: String, @@ -47,7 +48,7 @@ fn build_undo_announce( local_actor_followers(instance_url, &actor_profile.username), ]; UndoAnnounce { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: UNDO.to_string(), id: activity_id, actor: actor_id, diff --git a/src/activitypub/builders/undo_follow.rs b/src/activitypub/builders/undo_follow.rs index a743555..d29946a 100644 --- a/src/activitypub/builders/undo_follow.rs +++ b/src/activitypub/builders/undo_follow.rs @@ -3,9 +3,9 @@ use uuid::Uuid; use crate::activitypub::{ actors::types::Actor, - constants::AP_CONTEXT, deliverer::OutgoingActivity, identifiers::{local_actor_id, local_object_id}, + types::{build_default_context, Context}, vocabulary::{FOLLOW, UNDO}, }; use crate::config::Instance; @@ -16,7 +16,7 @@ use super::follow::Follow; #[derive(Serialize)] struct UndoFollow { #[serde(rename = "@context")] - context: String, + context: Context, #[serde(rename = "type")] activity_type: String, @@ -43,7 +43,7 @@ fn build_undo_follow( &actor_profile.username, ); let object = Follow { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: FOLLOW.to_string(), id: follow_activity_id, actor: follow_actor_id, @@ -53,7 +53,7 @@ fn build_undo_follow( let activity_id = format!("{}/undo", object.id); let actor_id = local_actor_id(instance_url, &actor_profile.username); UndoFollow { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: UNDO.to_string(), id: activity_id, actor: actor_id, diff --git a/src/activitypub/builders/undo_like.rs b/src/activitypub/builders/undo_like.rs index 8dca1fa..1898ad0 100644 --- a/src/activitypub/builders/undo_like.rs +++ b/src/activitypub/builders/undo_like.rs @@ -2,9 +2,9 @@ use serde::Serialize; use uuid::Uuid; use crate::activitypub::{ - constants::AP_CONTEXT, deliverer::OutgoingActivity, identifiers::{local_actor_id, local_object_id}, + types::{build_default_context, Context}, vocabulary::UNDO, }; use crate::config::Instance; @@ -20,7 +20,7 @@ use super::like::{ #[derive(Serialize)] struct UndoLike { #[serde(rename = "@context")] - context: String, + context: Context, #[serde(rename = "type")] activity_type: String, @@ -46,7 +46,7 @@ fn build_undo_like( let (primary_audience, secondary_audience) = get_like_audience(post_author_id, post_visibility); UndoLike { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: UNDO.to_string(), id: activity_id, actor: actor_id, diff --git a/src/activitypub/builders/update_person.rs b/src/activitypub/builders/update_person.rs index e9b4ac3..0658514 100644 --- a/src/activitypub/builders/update_person.rs +++ b/src/activitypub/builders/update_person.rs @@ -3,9 +3,10 @@ use uuid::Uuid; use crate::activitypub::{ actors::types::{get_local_actor, Actor, ActorKeyError}, - constants::{AP_CONTEXT, AP_PUBLIC}, + constants::AP_PUBLIC, deliverer::OutgoingActivity, identifiers::{local_actor_followers, local_object_id}, + types::{build_default_context, Context}, vocabulary::UPDATE, }; use crate::config::Instance; @@ -17,7 +18,7 @@ use crate::utils::id::new_uuid; #[derive(Serialize)] pub struct UpdatePerson { #[serde(rename = "@context")] - context: String, + context: Context, #[serde(rename = "type")] activity_type: String, @@ -40,7 +41,7 @@ pub fn build_update_person( maybe_internal_activity_id.unwrap_or(new_uuid()); let activity_id = local_object_id(instance_url, &internal_activity_id); let activity = UpdatePerson { - context: AP_CONTEXT.to_string(), + context: build_default_context(), activity_type: UPDATE.to_string(), id: activity_id, actor: actor.id.clone(), diff --git a/src/activitypub/collections.rs b/src/activitypub/collections.rs index 67a5999..e3cc02a 100644 --- a/src/activitypub/collections.rs +++ b/src/activitypub/collections.rs @@ -1,14 +1,14 @@ use serde::Serialize; use serde_json::{json, Value}; -use super::constants::AP_CONTEXT; +use super::types::{build_default_context, Context}; use super::vocabulary::{ORDERED_COLLECTION, ORDERED_COLLECTION_PAGE}; #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct OrderedCollection { #[serde(rename = "@context")] - pub context: Value, + pub context: Context, pub id: String, @@ -29,7 +29,7 @@ impl OrderedCollection { total_items: Option, ) -> Self { Self { - context: json!(AP_CONTEXT), + context: build_default_context(), id: collection_id, object_type: ORDERED_COLLECTION.to_string(), first: first_page_id, @@ -44,7 +44,7 @@ pub const COLLECTION_PAGE_SIZE: u16 = 10; #[serde(rename_all = "camelCase")] pub struct OrderedCollectionPage { #[serde(rename = "@context")] - pub context: Value, + pub context: Context, pub id: String, @@ -62,7 +62,7 @@ impl OrderedCollectionPage { let ordered_items = items.into_iter() .map(|item| json!(item)).collect(); Self { - context: json!(AP_CONTEXT), + context: build_default_context(), id: collection_page_id, object_type: ORDERED_COLLECTION_PAGE.to_string(), ordered_items, diff --git a/src/activitypub/constants.rs b/src/activitypub/constants.rs index 05c7bc8..4f09ead 100644 --- a/src/activitypub/constants.rs +++ b/src/activitypub/constants.rs @@ -2,7 +2,10 @@ pub const AP_MEDIA_TYPE: &str = r#"application/ld+json; profile="https://www.w3.org/ns/activitystreams""#; pub const AS_MEDIA_TYPE: &str = "application/activity+json"; +// Contexts pub const AP_CONTEXT: &str = "https://www.w3.org/ns/activitystreams"; pub const AP_PUBLIC: &str = "https://www.w3.org/ns/activitystreams#Public"; +pub const W3ID_SECURITY_CONTEXT: &str = "https://w3id.org/security/v1"; +pub const W3ID_DATA_INTEGRITY_CONTEXT: &str = "https://w3id.org/security/data-integrity/v1"; pub const ACTOR_KEY_SUFFIX: &str = "#main-key"; diff --git a/src/activitypub/types.rs b/src/activitypub/types.rs index d0786a0..d3bd8b5 100644 --- a/src/activitypub/types.rs +++ b/src/activitypub/types.rs @@ -2,6 +2,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_json::Value; +use super::constants::{AP_CONTEXT, W3ID_DATA_INTEGRITY_CONTEXT}; use super::vocabulary::HASHTAG; #[derive(Deserialize, Serialize)] @@ -99,3 +100,12 @@ pub struct Object { pub updated: Option>, pub url: Option, } + +pub type Context = [&'static str; 2]; + +pub const fn build_default_context() -> Context { + [ + AP_CONTEXT, + W3ID_DATA_INTEGRITY_CONTEXT, + ] +}