stuff
This commit is contained in:
parent
d0f37c699f
commit
bff0567c27
13 changed files with 56 additions and 35 deletions
|
|
@ -12,9 +12,9 @@ use activitypub_federation::{
|
||||||
kinds::activity::CreateType,
|
kinds::activity::CreateType,
|
||||||
protocol::{context::WithContext, helpers::deserialize_one_or_many},
|
protocol::{context::WithContext, helpers::deserialize_one_or_many},
|
||||||
traits::{ActivityHandler, Object},
|
traits::{ActivityHandler, Object},
|
||||||
|
url::Url,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@ use activitypub_federation::{
|
||||||
kinds::actor::PersonType,
|
kinds::actor::PersonType,
|
||||||
protocol::{public_key::PublicKey, verification::verify_domains_match},
|
protocol::{public_key::PublicKey, verification::verify_domains_match},
|
||||||
traits::{ActivityHandler, Actor, Object},
|
traits::{ActivityHandler, Actor, Object},
|
||||||
|
url::Url,
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::{fmt::Debug, str::FromStr};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DbUser {
|
pub struct DbUser {
|
||||||
|
|
@ -36,8 +36,8 @@ pub enum PersonAcceptedActivities {
|
||||||
|
|
||||||
impl DbUser {
|
impl DbUser {
|
||||||
pub fn new(hostname: &str, name: &str) -> Result<DbUser, Error> {
|
pub fn new(hostname: &str, name: &str) -> Result<DbUser, Error> {
|
||||||
let ap_id = Url::parse(&format!("https://{}/{}", hostname, &name))?.into();
|
let ap_id = Url::from_str(&format!("https://{}/{}", hostname, &name))?.into();
|
||||||
let inbox = Url::parse(&format!("https://{}/{}/inbox", hostname, &name))?;
|
let inbox = Url::from_str(&format!("https://{}/{}/inbox", hostname, &name))?;
|
||||||
let keypair = generate_actor_keypair()?;
|
let keypair = generate_actor_keypair()?;
|
||||||
Ok(DbUser {
|
Ok(DbUser {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@ use activitypub_federation::{
|
||||||
kinds::{object::NoteType, public},
|
kinds::{object::NoteType, public},
|
||||||
protocol::{helpers::deserialize_one_or_many, verification::verify_domains_match},
|
protocol::{helpers::deserialize_one_or_many, verification::verify_domains_match},
|
||||||
traits::{Actor, Object},
|
traits::{Actor, Object},
|
||||||
|
url::Url,
|
||||||
};
|
};
|
||||||
use activitystreams_kinds::link::MentionType;
|
use activitystreams_kinds::link::MentionType;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DbPost {
|
pub struct DbPost {
|
||||||
|
|
@ -63,7 +63,7 @@ impl Object for DbPost {
|
||||||
id: self.ap_id,
|
id: self.ap_id,
|
||||||
content: self.text,
|
content: self.text,
|
||||||
attributed_to: self.creator,
|
attributed_to: self.creator,
|
||||||
to: vec![public()],
|
to: vec![public().try_into()?],
|
||||||
tag: vec![],
|
tag: vec![],
|
||||||
in_reply_to: None,
|
in_reply_to: None,
|
||||||
})
|
})
|
||||||
|
|
@ -98,7 +98,7 @@ impl Object for DbPost {
|
||||||
kind: Default::default(),
|
kind: Default::default(),
|
||||||
id: generate_object_id(data.domain())?.into(),
|
id: generate_object_id(data.domain())?.into(),
|
||||||
attributed_to: data.local_user().ap_id,
|
attributed_to: data.local_user().ap_id,
|
||||||
to: vec![public()],
|
to: vec![public().try_into()?],
|
||||||
content: format!("Hello {}", creator.name),
|
content: format!("Hello {}", creator.name),
|
||||||
in_reply_to: Some(json.id.clone()),
|
in_reply_to: Some(json.id.clone()),
|
||||||
tag: vec![mention],
|
tag: vec![mention],
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use activitypub_federation::url::Url;
|
||||||
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
||||||
use url::{ParseError, Url};
|
use url::ParseError;
|
||||||
|
|
||||||
/// Just generate random url as object id. In a real project, you probably want to use
|
/// Just generate random url as object id. In a real project, you probably want to use
|
||||||
/// an url which contains the database id for easy retrieval (or store the random id in db).
|
/// an url which contains the database id for easy retrieval (or store the random id in db).
|
||||||
|
|
@ -9,5 +12,5 @@ pub fn generate_object_id(domain: &str) -> Result<Url, ParseError> {
|
||||||
.take(7)
|
.take(7)
|
||||||
.map(char::from)
|
.map(char::from)
|
||||||
.collect();
|
.collect();
|
||||||
Url::parse(&format!("https://{}/objects/{}", domain, id))
|
Url::from_str(&format!("https://{}/objects/{}", domain, id))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ use activitypub_federation::{
|
||||||
fetch::object_id::ObjectId,
|
fetch::object_id::ObjectId,
|
||||||
kinds::activity::AcceptType,
|
kinds::activity::AcceptType,
|
||||||
traits::ActivityHandler,
|
traits::ActivityHandler,
|
||||||
|
url::Url,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ use activitypub_federation::{
|
||||||
kinds::activity::CreateType,
|
kinds::activity::CreateType,
|
||||||
protocol::helpers::deserialize_one_or_many,
|
protocol::helpers::deserialize_one_or_many,
|
||||||
traits::{ActivityHandler, Object},
|
traits::{ActivityHandler, Object},
|
||||||
|
url::Url,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ use activitypub_federation::{
|
||||||
fetch::object_id::ObjectId,
|
fetch::object_id::ObjectId,
|
||||||
kinds::activity::FollowType,
|
kinds::activity::FollowType,
|
||||||
traits::{ActivityHandler, Actor},
|
traits::{ActivityHandler, Actor},
|
||||||
|
url::Url,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,23 @@ use crate::{
|
||||||
objects::{person::DbUser, post::DbPost},
|
objects::{person::DbUser, post::DbPost},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
use activitypub_federation::config::{FederationConfig, UrlVerifier};
|
use activitypub_federation::{
|
||||||
|
config::{FederationConfig, UrlVerifier},
|
||||||
|
url::Url,
|
||||||
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use std::{
|
use std::{
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
pub async fn new_instance(
|
pub async fn new_instance(
|
||||||
hostname: &str,
|
hostname: &str,
|
||||||
name: String,
|
name: String,
|
||||||
) -> Result<FederationConfig<DatabaseHandle>, Error> {
|
) -> Result<FederationConfig<DatabaseHandle>, Error> {
|
||||||
let mut system_user = DbUser::new(hostname, "system".into())?;
|
let mut system_user = DbUser::new(hostname, "system".into())?;
|
||||||
system_user.ap_id = Url::parse(&format!("http://{}/", hostname))?.into();
|
system_user.ap_id = Url::from_str(&format!("http://{}/", hostname))?.into();
|
||||||
|
|
||||||
let local_user = DbUser::new(hostname, name)?;
|
let local_user = DbUser::new(hostname, name)?;
|
||||||
let database = Arc::new(Database {
|
let database = Arc::new(Database {
|
||||||
|
|
@ -51,7 +53,7 @@ struct MyUrlVerifier();
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl UrlVerifier for MyUrlVerifier {
|
impl UrlVerifier for MyUrlVerifier {
|
||||||
async fn verify(&self, url: &Url) -> Result<(), activitypub_federation::error::Error> {
|
async fn verify(&self, url: &Url) -> Result<(), activitypub_federation::error::Error> {
|
||||||
if url.domain() == Some("malicious.com") {
|
if url.domain() == "malicious.com" {
|
||||||
Err(activitypub_federation::error::Error::Other(
|
Err(activitypub_federation::error::Error::Other(
|
||||||
"malicious domain".into(),
|
"malicious domain".into(),
|
||||||
))
|
))
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,11 @@ use activitypub_federation::{
|
||||||
kinds::actor::PersonType,
|
kinds::actor::PersonType,
|
||||||
protocol::{context::WithContext, public_key::PublicKey, verification::verify_domains_match},
|
protocol::{context::WithContext, public_key::PublicKey, verification::verify_domains_match},
|
||||||
traits::{ActivityHandler, Actor, Object},
|
traits::{ActivityHandler, Actor, Object},
|
||||||
|
url::Url,
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::{fmt::Debug, str::FromStr};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DbUser {
|
pub struct DbUser {
|
||||||
|
|
@ -46,8 +46,8 @@ pub enum PersonAcceptedActivities {
|
||||||
|
|
||||||
impl DbUser {
|
impl DbUser {
|
||||||
pub fn new(hostname: &str, name: String) -> Result<DbUser, Error> {
|
pub fn new(hostname: &str, name: String) -> Result<DbUser, Error> {
|
||||||
let ap_id = Url::parse(&format!("http://{}/{}", hostname, &name))?.into();
|
let ap_id = Url::from_str(&format!("http://{}/{}", hostname, &name))?.into();
|
||||||
let inbox = Url::parse(&format!("http://{}/{}/inbox", hostname, &name))?;
|
let inbox = Url::from_str(&format!("http://{}/{}/inbox", hostname, &name))?;
|
||||||
let keypair = generate_actor_keypair()?;
|
let keypair = generate_actor_keypair()?;
|
||||||
Ok(DbUser {
|
Ok(DbUser {
|
||||||
name,
|
name,
|
||||||
|
|
@ -79,7 +79,7 @@ impl DbUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn followers_url(&self) -> Result<Url, Error> {
|
pub fn followers_url(&self) -> Result<Url, Error> {
|
||||||
Ok(Url::parse(&format!("{}/followers", self.ap_id.inner()))?)
|
Ok(Url::from_str(&format!("{}/followers", self.ap_id.inner()))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn follow(&self, other: &str, data: &Data<DatabaseHandle>) -> Result<(), Error> {
|
pub async fn follow(&self, other: &str, data: &Data<DatabaseHandle>) -> Result<(), Error> {
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ use activitypub_federation::{
|
||||||
kinds::{object::NoteType, public},
|
kinds::{object::NoteType, public},
|
||||||
protocol::{helpers::deserialize_one_or_many, verification::verify_domains_match},
|
protocol::{helpers::deserialize_one_or_many, verification::verify_domains_match},
|
||||||
traits::Object,
|
traits::Object,
|
||||||
|
url::Url,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DbPost {
|
pub struct DbPost {
|
||||||
|
|
@ -19,7 +19,7 @@ pub struct DbPost {
|
||||||
|
|
||||||
impl DbPost {
|
impl DbPost {
|
||||||
pub fn new(text: String, creator: ObjectId<DbUser>) -> Result<DbPost, Error> {
|
pub fn new(text: String, creator: ObjectId<DbUser>) -> Result<DbPost, Error> {
|
||||||
let ap_id = generate_object_id(creator.inner().domain().unwrap())?.into();
|
let ap_id = generate_object_id(creator.inner().domain())?.try_into()?;
|
||||||
Ok(DbPost {
|
Ok(DbPost {
|
||||||
text,
|
text,
|
||||||
ap_id,
|
ap_id,
|
||||||
|
|
@ -65,7 +65,7 @@ impl Object for DbPost {
|
||||||
kind: Default::default(),
|
kind: Default::default(),
|
||||||
id: self.ap_id,
|
id: self.ap_id,
|
||||||
attributed_to: self.creator,
|
attributed_to: self.creator,
|
||||||
to: vec![public(), creator.followers_url()?],
|
to: vec![public().try_into()?, creator.followers_url()?],
|
||||||
content: self.text,
|
content: self.text,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ where
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
activity_sending::generate_request_headers,
|
activity_sending::generate_request_headers,
|
||||||
|
|
@ -165,7 +167,7 @@ mod test {
|
||||||
actor: ObjectId::parse("http://localhost:123").unwrap(),
|
actor: ObjectId::parse("http://localhost:123").unwrap(),
|
||||||
object: ObjectId::parse("http://localhost:124").unwrap(),
|
object: ObjectId::parse("http://localhost:124").unwrap(),
|
||||||
kind: Default::default(),
|
kind: Default::default(),
|
||||||
id: "http://localhost:123/1".try_into().unwrap(),
|
id: "http://localhost:123/1".parse().unwrap(),
|
||||||
};
|
};
|
||||||
let body: Bytes = serde_json::to_vec(&activity).unwrap().into();
|
let body: Bytes = serde_json::to_vec(&activity).unwrap().into();
|
||||||
let incoming_request = construct_request(&body, activity.actor.inner()).await;
|
let incoming_request = construct_request(&body, activity.actor.inner()).await;
|
||||||
|
|
|
||||||
|
|
@ -135,13 +135,13 @@ async fn fetch_object_http_with_accept<T: Clone, Kind: DeserializeOwned>(
|
||||||
match serde_json::from_slice(&text) {
|
match serde_json::from_slice(&text) {
|
||||||
Ok(object) => Ok(FetchObjectResponse {
|
Ok(object) => Ok(FetchObjectResponse {
|
||||||
object,
|
object,
|
||||||
url: url.into(),
|
url: url.try_into()?,
|
||||||
content_type,
|
content_type,
|
||||||
object_id,
|
object_id,
|
||||||
}),
|
}),
|
||||||
Err(e) => Err(ParseFetchedObject(
|
Err(e) => Err(ParseFetchedObject(
|
||||||
e,
|
e,
|
||||||
url.into(),
|
url.try_into()?,
|
||||||
String::from_utf8(Vec::from(text))?,
|
String::from_utf8(Vec::from(text))?,
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
28
src/url.rs
28
src/url.rs
|
|
@ -1,13 +1,12 @@
|
||||||
//! Wrapper for `url::Url` type.
|
//! Wrapper for `url::Url` type.
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{Display, Formatter},
|
fmt::{Display, Formatter},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
/// Wrapper for `url::Url` type. Has `domain` as mandatory field, and prints plain
|
/// Wrapper for `url::Url` type. Has `domain` as mandatory field, and prints plain
|
||||||
/// string for debugging.
|
/// string for debugging.
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
|
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
|
||||||
|
|
@ -22,6 +21,7 @@ impl Deref for Url {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Url {
|
impl Display for Url {
|
||||||
|
#[allow(clippy::to_string_in_format_args)]
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{}", self.0.to_string())
|
write!(f, "{}", self.0.to_string())
|
||||||
}
|
}
|
||||||
|
|
@ -30,14 +30,24 @@ impl Display for Url {
|
||||||
impl Url {
|
impl Url {
|
||||||
/// Returns domain of the url
|
/// Returns domain of the url
|
||||||
pub fn domain(&self) -> &str {
|
pub fn domain(&self) -> &str {
|
||||||
// TODO: must have error handling, or ensure at creation that it has domain
|
|
||||||
self.0.domain().expect("has domain")
|
self.0.domain().expect("has domain")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<url::Url> for Url {
|
impl TryFrom<url::Url> for Url {
|
||||||
fn from(value: url::Url) -> Self {
|
type Error = url::ParseError;
|
||||||
Url(value)
|
fn try_from(value: url::Url) -> Result<Self, Self::Error> {
|
||||||
|
if value.domain().is_none() {
|
||||||
|
return Err(url::ParseError::EmptyHost);
|
||||||
|
}
|
||||||
|
Ok(Url(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::from_over_into)]
|
||||||
|
impl Into<url::Url> for Url {
|
||||||
|
fn into(self) -> url::Url {
|
||||||
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,6 +55,10 @@ impl FromStr for Url {
|
||||||
type Err = url::ParseError;
|
type Err = url::ParseError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
Ok(url::Url::from_str(s).map(Url).unwrap())
|
let url = url::Url::from_str(s)?;
|
||||||
|
if url.domain().is_none() {
|
||||||
|
return Err(url::ParseError::EmptyHost);
|
||||||
|
}
|
||||||
|
Ok(Url(url))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue