Compare commits
2 commits
main
...
public-ip-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d0845431d | ||
|
|
a087c489a0 |
12 changed files with 34 additions and 129 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -4,7 +4,7 @@ version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "activitypub_federation"
|
name = "activitypub_federation"
|
||||||
version = "0.7.0-beta.11"
|
version = "0.7.0-beta.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"activitystreams-kinds",
|
"activitystreams-kinds",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "activitypub_federation"
|
name = "activitypub_federation"
|
||||||
version = "0.7.0-beta.11"
|
version = "0.7.0-beta.9"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "High-level Activitypub framework"
|
description = "High-level Activitypub framework"
|
||||||
keywords = ["activitypub", "activitystreams", "federation", "fediverse"]
|
keywords = ["activitypub", "activitystreams", "federation", "fediverse"]
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,10 @@ impl Object for SearchableDbObjects {
|
||||||
type Kind = SearchableObjects;
|
type Kind = SearchableObjects;
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
fn id(&self) -> Url {
|
fn id(&self) -> &Url {
|
||||||
match self {
|
match self {
|
||||||
SearchableDbObjects::User(p) => p.federation_id.clone(),
|
SearchableDbObjects::User(p) => &p.federation_id,
|
||||||
SearchableDbObjects::Post(n) => n.federation_id.clone(),
|
SearchableDbObjects::Post(n) => &n.federation_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,8 @@ impl Object for DbUser {
|
||||||
type Kind = Person;
|
type Kind = Person;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn id(&self) -> Url {
|
fn id(&self) -> &Url {
|
||||||
self.ap_id.inner().clone()
|
self.ap_id.inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,8 @@ impl Object for DbPost {
|
||||||
type Kind = Note;
|
type Kind = Note;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn id(&self) -> Url {
|
fn id(&self) -> &Url {
|
||||||
self.ap_id.inner().clone()
|
self.ap_id.inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_from_id(
|
async fn read_from_id(
|
||||||
|
|
|
||||||
|
|
@ -134,8 +134,8 @@ impl Object for DbUser {
|
||||||
type Kind = Person;
|
type Kind = Person;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn id(&self) -> Url {
|
fn id(&self) -> &Url {
|
||||||
self.ap_id.inner().clone()
|
self.ap_id.inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@ impl Object for DbPost {
|
||||||
type Kind = Note;
|
type Kind = Note;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn id(&self) -> Url {
|
fn id(&self) -> &Url {
|
||||||
self.ap_id.inner().clone()
|
self.ap_id.inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_from_id(
|
async fn read_from_id(
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ where
|
||||||
// PKey is internally like an Arc<>, so cloning is ok
|
// PKey is internally like an Arc<>, so cloning is ok
|
||||||
data.config
|
data.config
|
||||||
.actor_pkey_cache
|
.actor_pkey_cache
|
||||||
.try_get_with_by_ref(&actor_id, async {
|
.try_get_with_by_ref(actor_id, async {
|
||||||
let private_key_pem = actor.private_key_pem().ok_or_else(|| {
|
let private_key_pem = actor.private_key_pem().ok_or_else(|| {
|
||||||
Error::Other(format!(
|
Error::Other(format!(
|
||||||
"Actor {actor_id} does not contain a private key for signing"
|
"Actor {actor_id} does not contain a private key for signing"
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,13 @@
|
||||||
//! Serde deserialization functions which help to receive differently shaped data
|
//! Serde deserialization functions which help to receive differently shaped data
|
||||||
|
|
||||||
use activitystreams_kinds::public;
|
use serde::{Deserialize, Deserializer};
|
||||||
use itertools::Itertools;
|
|
||||||
use serde::{de::Error, Deserialize, Deserializer};
|
|
||||||
use serde_json::Value;
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
/// Deserialize JSON single value or array into `Vec<Url>`.
|
/// Deserialize JSON single value or array into Vec.
|
||||||
///
|
///
|
||||||
/// Useful if your application can handle multiple values for a field, but another federated
|
/// Useful if your application can handle multiple values for a field, but another federated
|
||||||
/// platform only sends a single one.
|
/// platform only sends a single one.
|
||||||
///
|
///
|
||||||
/// Also accepts common `Public` aliases for recipient fields. Some implementations send `Public`
|
|
||||||
/// or `as:Public` instead of the canonical `https://www.w3.org/ns/activitystreams#Public` URL
|
|
||||||
/// in fields such as `to` and `cc`.
|
|
||||||
///
|
|
||||||
/// ```
|
/// ```
|
||||||
/// # use activitypub_federation::kinds::public;
|
|
||||||
/// # use activitypub_federation::protocol::helpers::deserialize_one_or_many;
|
/// # use activitypub_federation::protocol::helpers::deserialize_one_or_many;
|
||||||
/// # use url::Url;
|
/// # use url::Url;
|
||||||
/// #[derive(serde::Deserialize)]
|
/// #[derive(serde::Deserialize)]
|
||||||
|
|
@ -34,39 +25,24 @@ use url::Url;
|
||||||
/// "https://lemmy.ml/u/bob"
|
/// "https://lemmy.ml/u/bob"
|
||||||
/// ]}"#)?;
|
/// ]}"#)?;
|
||||||
/// assert_eq!(multiple.to.len(), 2);
|
/// assert_eq!(multiple.to.len(), 2);
|
||||||
///
|
/// Ok::<(), anyhow::Error>(())
|
||||||
/// let note: Note = serde_json::from_str(r#"{"to": ["Public", "as:Public"]}"#)?;
|
pub fn deserialize_one_or_many<'de, T, D>(deserializer: D) -> Result<Vec<T>, D::Error>
|
||||||
/// assert_eq!(note.to, vec![public()]);
|
|
||||||
/// # Ok::<(), anyhow::Error>(())
|
|
||||||
/// ```
|
|
||||||
pub fn deserialize_one_or_many<'de, D>(deserializer: D) -> Result<Vec<Url>, D::Error>
|
|
||||||
where
|
where
|
||||||
|
T: Deserialize<'de>,
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
enum OneOrMany {
|
enum OneOrMany<T> {
|
||||||
Many(Vec<Value>),
|
One(T),
|
||||||
One(Value),
|
Many(Vec<T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
let result: OneOrMany = Deserialize::deserialize(deserializer)?;
|
let result: OneOrMany<T> = Deserialize::deserialize(deserializer)?;
|
||||||
let values = match result {
|
Ok(match result {
|
||||||
|
OneOrMany::Many(list) => list,
|
||||||
OneOrMany::One(value) => vec![value],
|
OneOrMany::One(value) => vec![value],
|
||||||
OneOrMany::Many(values) => values,
|
})
|
||||||
};
|
|
||||||
|
|
||||||
values
|
|
||||||
.into_iter()
|
|
||||||
.map(|value| match value {
|
|
||||||
Value::String(value) if matches!(value.as_str(), "Public" | "as:Public") => {
|
|
||||||
Ok(public())
|
|
||||||
}
|
|
||||||
Value::String(value) => Url::parse(&value).map_err(D::Error::custom),
|
|
||||||
value => Url::deserialize(value).map_err(D::Error::custom),
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>, _>>()
|
|
||||||
.map(|values| values.into_iter().unique().collect())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialize JSON single value or single element array into single value.
|
/// Deserialize JSON single value or single element array into single value.
|
||||||
|
|
@ -164,11 +140,6 @@ where
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::deserialize_one_or_many;
|
|
||||||
use activitystreams_kinds::public;
|
|
||||||
use anyhow::Result;
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn deserialize_one_multiple_values() {
|
fn deserialize_one_multiple_values() {
|
||||||
use crate::protocol::helpers::deserialize_one;
|
use crate::protocol::helpers::deserialize_one;
|
||||||
|
|
@ -184,70 +155,4 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(note.is_err());
|
assert!(note.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialize_one_or_many_single_public_aliases() -> Result<()> {
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Note {
|
|
||||||
#[serde(deserialize_with = "deserialize_one_or_many")]
|
|
||||||
to: Vec<Url>,
|
|
||||||
}
|
|
||||||
|
|
||||||
for alias in ["Public", "as:Public"] {
|
|
||||||
let note = serde_json::from_str::<Note>(&format!(r#"{{"to": "{alias}"}}"#))?;
|
|
||||||
assert_eq!(note.to, vec![public()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialize_one_or_many_array() -> Result<()> {
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Note {
|
|
||||||
#[serde(deserialize_with = "deserialize_one_or_many")]
|
|
||||||
to: Vec<Url>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let note = serde_json::from_str::<Note>(
|
|
||||||
r#"{
|
|
||||||
"to": [
|
|
||||||
"https://example.com/c/main",
|
|
||||||
"Public",
|
|
||||||
"as:Public",
|
|
||||||
"https://www.w3.org/ns/activitystreams#Public"
|
|
||||||
]
|
|
||||||
}"#,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
note.to,
|
|
||||||
vec![Url::parse("https://example.com/c/main")?, public(),]
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialize_one_or_many_leaves_other_strings_unchanged() -> Result<()> {
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Note {
|
|
||||||
#[serde(deserialize_with = "deserialize_one_or_many")]
|
|
||||||
to: Vec<Url>,
|
|
||||||
content: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
let note = serde_json::from_str::<Note>(r#"{"to": "Public", "content": "Public"}"#)?;
|
|
||||||
|
|
||||||
assert_eq!(note.to, vec![public()]);
|
|
||||||
assert_eq!(note.content, "Public");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ where
|
||||||
type Error = E;
|
type Error = E;
|
||||||
|
|
||||||
/// `id` field of the object
|
/// `id` field of the object
|
||||||
fn id(&self) -> Url {
|
fn id(&self) -> &Url {
|
||||||
match self {
|
match self {
|
||||||
Either::Left(l) => l.id(),
|
Either::Left(l) => l.id(),
|
||||||
Either::Right(r) => r.id(),
|
Either::Right(r) => r.id(),
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ pub mod tests;
|
||||||
/// type Kind = Note;
|
/// type Kind = Note;
|
||||||
/// type Error = anyhow::Error;
|
/// type Error = anyhow::Error;
|
||||||
///
|
///
|
||||||
/// fn id(&self) -> Url { self.ap_id.inner().clone() }
|
/// fn id(&self) -> &Url { self.ap_id.inner() }
|
||||||
///
|
///
|
||||||
/// async fn read_from_id(object_id: Url, data: &Data<Self::DataType>) -> Result<Option<Self>, Self::Error> {
|
/// async fn read_from_id(object_id: Url, data: &Data<Self::DataType>) -> Result<Option<Self>, Self::Error> {
|
||||||
/// // Attempt to read object from local database. Return Ok(None) if not found.
|
/// // Attempt to read object from local database. Return Ok(None) if not found.
|
||||||
|
|
@ -110,7 +110,7 @@ pub trait Object: Sized + Debug {
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
/// `id` field of the object
|
/// `id` field of the object
|
||||||
fn id(&self) -> Url;
|
fn id(&self) -> &Url;
|
||||||
|
|
||||||
/// Returns the last time this object was updated.
|
/// Returns the last time this object was updated.
|
||||||
///
|
///
|
||||||
|
|
@ -194,8 +194,8 @@ pub trait Object: Sized + Debug {
|
||||||
redirect_remote_object,
|
redirect_remote_object,
|
||||||
};
|
};
|
||||||
let id = self.id();
|
let id = self.id();
|
||||||
let res = if !data.config.is_local_url(&id) {
|
let res = if !data.config.is_local_url(id) {
|
||||||
redirect_remote_object(&id)
|
redirect_remote_object(id)
|
||||||
} else if !self.is_deleted() {
|
} else if !self.is_deleted() {
|
||||||
let json = self.into_json(data).await?;
|
let json = self.into_json(data).await?;
|
||||||
create_http_response(json, federation_context)?
|
create_http_response(json, federation_context)?
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,8 @@ impl Object for DbUser {
|
||||||
type Kind = Person;
|
type Kind = Person;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn id(&self) -> Url {
|
fn id(&self) -> &Url {
|
||||||
self.federation_id.clone()
|
&self.federation_id
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_from_id(
|
async fn read_from_id(
|
||||||
|
|
@ -179,7 +179,7 @@ impl Object for DbPost {
|
||||||
type Kind = Note;
|
type Kind = Note;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn id(&self) -> Url {
|
fn id(&self) -> &Url {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue