summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDessalines <tyhou13@gmx.com>2020-04-26 13:20:42 -0400
committerDessalines <tyhou13@gmx.com>2020-04-26 13:20:42 -0400
commit3ce061836242813730ec0b63240097347647dfc4 (patch)
treed6ebe9074753b4a92e4d4d94ba6b4b2d0770ea4d
parent079ac091ebbeb2e3e1f91fba6c93b3e11e1c5fd6 (diff)
Making a trait function for follow and accept.
-rw-r--r--server/Cargo.lock10
-rw-r--r--server/Cargo.toml1
-rw-r--r--server/src/api/community.rs2
-rw-r--r--server/src/api/mod.rs4
-rw-r--r--server/src/api/post.rs4
-rw-r--r--server/src/apub/activities.rs78
-rw-r--r--server/src/apub/community.rs39
-rw-r--r--server/src/apub/community_inbox.rs3
-rw-r--r--server/src/apub/mod.rs36
-rw-r--r--server/src/apub/shared_inbox.rs1
-rw-r--r--server/src/apub/user.rs28
11 files changed, 128 insertions, 78 deletions
diff --git a/server/Cargo.lock b/server/Cargo.lock
index cbb6248b..fe54cfb4 100644
--- a/server/Cargo.lock
+++ b/server/Cargo.lock
@@ -1456,6 +1456,15 @@ dependencies = [
]
[[package]]
+name = "itertools"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
+dependencies = [
+ "either",
+]
+
+[[package]]
name = "itoa"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1544,6 +1553,7 @@ dependencies = [
"http",
"http-signature-normalization",
"isahc",
+ "itertools",
"jsonwebtoken",
"lazy_static 1.4.0",
"lettre",
diff --git a/server/Cargo.toml b/server/Cargo.toml
index 5f4d24ce..a521a966 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -44,3 +44,4 @@ http-signature-normalization = "0.4.1"
base64 = "0.12.0"
tokio = "0.2.18"
futures = "0.3.4"
+itertools = "0.9.0"
diff --git a/server/src/api/community.rs b/server/src/api/community.rs
index ace5b353..174a91c8 100644
--- a/server/src/api/community.rs
+++ b/server/src/api/community.rs
@@ -488,7 +488,7 @@ impl Perform for Oper<FollowCommunity> {
} else {
// TODO: still have to implement unfollow
let user = User_::read(&conn, user_id)?;
- follow_community(&community, &user, &conn)?;
+ user.send_follow(&community.actor_id)?;
// TODO: this needs to return a "pending" state, until Accept is received from the remote server
}
diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs
index 04d69001..0595f2a4 100644
--- a/server/src/api/mod.rs
+++ b/server/src/api/mod.rs
@@ -23,10 +23,10 @@ use crate::{
};
use crate::apub::{
- activities::{follow_community, post_create, post_update},
+ activities::{send_post_create, send_post_update},
fetcher::search_by_apub_id,
signatures::generate_actor_keypair,
- {make_apub_endpoint, EndpointType},
+ {make_apub_endpoint, ActorType, EndpointType},
};
use crate::settings::Settings;
use crate::websocket::UserOperation;
diff --git a/server/src/api/post.rs b/server/src/api/post.rs
index 32eb5470..89f1dd1d 100644
--- a/server/src/api/post.rs
+++ b/server/src/api/post.rs
@@ -160,7 +160,7 @@ impl Perform for Oper<CreatePost> {
Err(_e) => return Err(APIError::err("couldnt_create_post").into()),
};
- post_create(&updated_post, &user, &conn)?;
+ send_post_create(&updated_post, &user, &conn)?;
// They like their own post by default
let like_form = PostLikeForm {
@@ -531,7 +531,7 @@ impl Perform for Oper<EditPost> {
ModStickyPost::create(&conn, &form)?;
}
- post_update(&updated_post, &user, &conn)?;
+ send_post_update(&updated_post, &user, &conn)?;
let post_view = PostView::read(&conn, data.edit_id, Some(user_id))?;
diff --git a/server/src/apub/activities.rs b/server/src/apub/activities.rs
index 24631a35..cb98e973 100644
--- a/server/src/apub/activities.rs
+++ b/server/src/apub/activities.rs
@@ -17,7 +17,7 @@ fn populate_object_props(
}
/// Send an activity to a list of recipients, using the correct headers etc.
-fn send_activity<A>(
+pub fn send_activity<A>(
activity: &A,
private_key: &str,
sender_id: &str,
@@ -52,15 +52,18 @@ where
fn get_follower_inboxes(conn: &PgConnection, community: &Community) -> Result<Vec<String>, Error> {
Ok(
CommunityFollowerView::for_community(conn, community.id)?
- .iter()
+ .into_iter()
.filter(|c| !c.user_local)
+ // TODO eventually this will have to use the inbox or shared_inbox column, meaning that view
+ // will have to change
.map(|c| format!("{}/inbox", c.user_actor_id.to_owned()))
+ .unique()
.collect(),
)
}
/// Send out information about a newly created post, to the followers of the community.
-pub fn post_create(post: &Post, creator: &User_, conn: &PgConnection) -> Result<(), Error> {
+pub fn send_post_create(post: &Post, creator: &User_, conn: &PgConnection) -> Result<(), Error> {
let page = post.to_apub(conn)?;
let community = Community::read(conn, post.community_id)?;
let mut create = Create::new();
@@ -83,7 +86,7 @@ pub fn post_create(post: &Post, creator: &User_, conn: &PgConnection) -> Result<
}
/// Send out information about an edited post, to the followers of the community.
-pub fn post_update(post: &Post, creator: &User_, conn: &PgConnection) -> Result<(), Error> {
+pub fn send_post_update(post: &Post, creator: &User_, conn: &PgConnection) -> Result<(), Error> {
let page = post.to_apub(conn)?;
let community = Community::read(conn, post.community_id)?;
let mut update = Update::new();
@@ -104,70 +107,3 @@ pub fn post_update(post: &Post, creator: &User_, conn: &PgConnection) -> Result<
)?;
Ok(())
}
-
-/// As a given local user, send out a follow request to a remote community.
-pub fn follow_community(
- community: &Community,
- user: &User_,
- _conn: &PgConnection,
-) -> Result<(), Error> {
- let mut follow = Follow::new();
- follow
- .object_props
- .set_context_xsd_any_uri(context())?
- // TODO: needs proper id
- .set_id(user.actor_id.clone())?;
- follow
- .follow_props
- .set_actor_xsd_any_uri(user.actor_id.clone())?
- .set_object_xsd_any_uri(community.actor_id.clone())?;
- // TODO this is incorrect, the to field should not be the inbox, but the followers url
- let to = format!("{}/inbox", community.actor_id);
- send_activity(
- &follow,
- &user.private_key.as_ref().unwrap(),
- &community.actor_id,
- vec![to],
- )?;
- Ok(())
-}
-
-/// As a local community, accept the follow request from a remote user.
-pub fn accept_follow(follow: &Follow, conn: &PgConnection) -> Result<(), Error> {
- let community_uri = follow
- .follow_props
- .get_object_xsd_any_uri()
- .unwrap()
- .to_string();
- let actor_uri = follow
- .follow_props
- .get_actor_xsd_any_uri()
- .unwrap()
- .to_string();
- let community = Community::read_from_actor_id(conn, &community_uri)?;
- let mut accept = Accept::new();
- accept
- .object_props
- .set_context_xsd_any_uri(context())?
- // TODO: needs proper id
- .set_id(
- follow
- .follow_props
- .get_actor_xsd_any_uri()
- .unwrap()
- .to_string(),
- )?;
- accept
- .accept_props
- .set_actor_xsd_any_uri(community.actor_id.clone())?
- .set_object_base_box(BaseBox::from_concrete(follow.clone())?)?;
- // TODO this is incorrect, the to field should not be the inbox, but the followers url
- let to = format!("{}/inbox", actor_uri);
- send_activity(
- &accept,
- &community.private_key.unwrap(),
- &community.actor_id,
- vec![to],
- )?;
- Ok(())
-}
diff --git a/server/src/apub/community.rs b/server/src/apub/community.rs
index e74a5fd1..bc984b25 100644
--- a/server/src/apub/community.rs
+++ b/server/src/apub/community.rs
@@ -30,12 +30,17 @@ impl ToApub for Community {
oprops.set_summary_xsd_string(d)?;
}
+ let mut endpoint_props = EndpointProperties::default();
+
+ endpoint_props.set_shared_inbox(self.get_shared_inbox_url())?;
+
let mut actor_props = ApActorProperties::default();
actor_props
.set_preferred_username(self.title.to_owned())?
.set_inbox(self.get_inbox_url())?
.set_outbox(self.get_outbox_url())?
+ .set_endpoints(endpoint_props)?
.set_followers(self.get_followers_url())?;
Ok(group.extend(actor_props).extend(self.get_public_key_ext()))
@@ -50,6 +55,40 @@ impl ActorType for Community {
fn public_key(&self) -> String {
self.public_key.to_owned().unwrap()
}
+
+ /// As a local community, accept the follow request from a remote user.
+ fn send_accept_follow(&self, follow: &Follow) -> Result<(), Error> {
+ let actor_uri = follow
+ .follow_props
+ .get_actor_xsd_any_uri()
+ .unwrap()
+ .to_string();
+
+ let mut accept = Accept::new();
+ accept
+ .object_props
+ .set_context_xsd_any_uri(context())?
+ // TODO: needs proper id
+ .set_id(
+ follow
+ .follow_props
+ .get_actor_xsd_any_uri()
+ .unwrap()
+ .to_string(),
+ )?;
+ accept
+ .accept_props
+ .set_actor_xsd_any_uri(self.actor_id.to_owned())?
+ .set_object_base_box(BaseBox::from_concrete(follow.clone())?)?;
+ let to = format!("{}/inbox", actor_uri);
+ send_activity(
+ &accept,
+ &self.private_key.to_owned().unwrap(),
+ &self.actor_id,
+ vec![to],
+ )?;
+ Ok(())
+ }
}
impl FromApub for CommunityForm {
diff --git a/server/src/apub/community_inbox.rs b/server/src/apub/community_inbox.rs
index 6931cdf1..04a64b69 100644
--- a/server/src/apub/community_inbox.rs
+++ b/server/src/apub/community_inbox.rs
@@ -63,6 +63,7 @@ fn handle_follow(
// This will fail if they're already a follower, but ignore the error.
CommunityFollower::follow(&conn, &community_follower_form).ok();
- accept_follow(&follow, &conn)?;
+ community.send_accept_follow(&follow)?;
+
Ok(HttpResponse::Ok().finish())
}
diff --git a/server/src/apub/mod.rs b/server/src/apub/mod.rs
index 671f8c5a..5c585299 100644
--- a/server/src/apub/mod.rs
+++ b/server/src/apub/mod.rs
@@ -3,6 +3,7 @@ pub mod community;
pub mod community_inbox;
pub mod fetcher;
pub mod post;
+pub mod shared_inbox;
pub mod signatures;
pub mod user;
pub mod user_inbox;
@@ -12,6 +13,7 @@ use activitystreams::{
actor::{properties::ApActorProperties, Actor, Group, Person},
collection::UnorderedCollection,
context,
+ endpoint::EndpointProperties,
ext::{Ext, Extensible, Extension},
object::{properties::ObjectProperties, Page},
public, BaseBox,
@@ -26,6 +28,7 @@ use failure::_core::fmt::Debug;
use http::request::Builder;
use http_signature_normalization::Config;
use isahc::prelude::*;
+use itertools::Itertools;
use log::debug;
use openssl::hash::MessageDigest;
use openssl::sign::{Signer, Verifier};
@@ -47,7 +50,7 @@ use crate::routes::nodeinfo::{NodeInfo, NodeInfoWellKnown};
use crate::routes::{ChatServerParam, DbPoolParam};
use crate::{convert_datetime, naive_now, Settings};
-use activities::accept_follow;
+use activities::send_activity;
use fetcher::{get_or_fetch_and_upsert_remote_community, get_or_fetch_and_upsert_remote_user};
use signatures::verify;
use signatures::{sign, PublicKey, PublicKeyExtension};
@@ -144,9 +147,38 @@ pub trait ActorType {
fn public_key(&self) -> String;
+ // These two have default impls, since currently a community can't follow anything,
+ // and a user can't be followed (yet)
+ #[allow(unused_variables)]
+ fn send_follow(&self, follow_actor_id: &str) -> Result<(), Error> {
+ Ok(())
+ }
+
+ #[allow(unused_variables)]
+ fn send_accept_follow(&self, follow: &Follow) -> Result<(), Error> {
+ Ok(())
+ }
+
+ // TODO move these to the db rows
fn get_inbox_url(&self) -> String {
format!("{}/inbox", &self.actor_id())
}
+
+ fn get_shared_inbox_url(&self) -> String {
+ let url = Url::parse(&self.actor_id()).unwrap();
+ let url_str = format!(
+ "{}://{}{}/inbox",
+ &url.scheme(),
+ &url.host_str().unwrap(),
+ if let Some(port) = url.port() {
+ format!(":{}", port)
+ } else {
+ "".to_string()
+ },
+ );
+ format!("{}/inbox", &url_str)
+ }
+
fn get_outbox_url(&self) -> String {
format!("{}/outbox", &self.actor_id())
}
@@ -154,9 +186,11 @@ pub trait ActorType {
fn get_followers_url(&self) -> String {
format!("{}/followers", &self.actor_id())
}
+
fn get_following_url(&self) -> String {
format!("{}/following", &self.actor_id())
}
+
fn get_liked_url(&self) -> String {
format!("{}/liked", &self.actor_id())
}
diff --git a/server/src/apub/shared_inbox.rs b/server/src/apub/shared_inbox.rs
new file mode 100644
index 00000000..35ba3908
--- /dev/null
+++ b/server/src/apub/shared_inbox.rs
@@ -0,0 +1 @@
+// use super::*;
diff --git a/server/src/apub/user.rs b/server/src/apub/user.rs
index 88238b5d..b4b3b35b 100644
--- a/server/src/apub/user.rs
+++ b/server/src/apub/user.rs
@@ -27,11 +27,16 @@ impl ToApub for User_ {
oprops.set_name_xsd_string(i.to_owned())?;
}
+ let mut endpoint_props = EndpointProperties::default();
+
+ endpoint_props.set_shared_inbox(self.get_shared_inbox_url())?;
+
let mut actor_props = ApActorProperties::default();
actor_props
.set_inbox(self.get_inbox_url())?
.set_outbox(self.get_outbox_url())?
+ .set_endpoints(endpoint_props)?
.set_followers(self.get_followers_url())?
.set_following(self.get_following_url())?
.set_liked(self.get_liked_url())?;
@@ -48,6 +53,29 @@ impl ActorType for User_ {
fn public_key(&self) -> String {
self.public_key.to_owned().unwrap()
}
+
+ // TODO might be able to move this to a default trait fn
+ /// As a given local user, send out a follow request to a remote community.
+ fn send_follow(&self, follow_actor_id: &str) -> Result<(), Error> {
+ let mut follow = Follow::new();
+ follow
+ .object_props
+ .set_context_xsd_any_uri(context())?
+ // TODO: needs proper id
+ .set_id(self.actor_id.to_owned())?;
+ follow
+ .follow_props
+ .set_actor_xsd_any_uri(self.actor_id.to_owned())?
+ .set_object_xsd_any_uri(follow_actor_id)?;
+ let to = format!("{}/inbox", follow_actor_id);
+ send_activity(
+ &follow,
+ &self.private_key.as_ref().unwrap(),
+ &follow_actor_id,
+ vec![to],
+ )?;
+ Ok(())
+ }
}
impl FromApub for UserForm {