summaryrefslogtreecommitdiffstats
path: root/server/src/apub
diff options
context:
space:
mode:
authorFelix <me@nutomic.com>2020-04-17 19:34:18 +0200
committerFelix <me@nutomic.com>2020-04-17 19:34:18 +0200
commitb1b97db11a130a063768169ba7ce90798ef4d659 (patch)
treeba4efccca8792841a163c9aacf1e118130b33b5b /server/src/apub
parentc5ced6fa5e0a5f80c9e58c3a4bf199434194195a (diff)
Implement instance whitelist
Diffstat (limited to 'server/src/apub')
-rw-r--r--server/src/apub/activities.rs8
-rw-r--r--server/src/apub/community_inbox.rs10
-rw-r--r--server/src/apub/fetcher.rs7
-rw-r--r--server/src/apub/mod.rs23
-rw-r--r--server/src/apub/user_inbox.rs13
5 files changed, 41 insertions, 20 deletions
diff --git a/server/src/apub/activities.rs b/server/src/apub/activities.rs
index f31be9db..d4900806 100644
--- a/server/src/apub/activities.rs
+++ b/server/src/apub/activities.rs
@@ -1,3 +1,4 @@
+use crate::apub::is_apub_id_valid;
use crate::db::community::Community;
use crate::db::community_view::CommunityFollowerView;
use crate::db::post::Post;
@@ -36,9 +37,12 @@ where
A: Serialize + Debug,
{
let json = serde_json::to_string(&activity)?;
- debug!("Sending activitypub activity {}", json);
+ debug!("Sending activitypub activity {} to {:?}", json, to);
for t in to {
- debug!("Sending activity to: {}", t);
+ if is_apub_id_valid(&t) {
+ debug!("Not sending activity to {} (invalid or blacklisted)", t);
+ continue;
+ }
let res = Request::post(t)
.header("Content-Type", "application/json")
.body(json.to_owned())?
diff --git a/server/src/apub/community_inbox.rs b/server/src/apub/community_inbox.rs
index ea0d9105..65d7bec1 100644
--- a/server/src/apub/community_inbox.rs
+++ b/server/src/apub/community_inbox.rs
@@ -17,22 +17,18 @@ pub enum CommunityAcceptedObjects {
Follow(Follow),
}
-#[derive(Deserialize)]
-pub struct Params {
- community_name: String,
-}
-
/// Handler for all incoming activities to community inboxes.
pub async fn community_inbox(
input: web::Json<CommunityAcceptedObjects>,
- params: web::Query<Params>,
+ path: web::Path<String>,
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
) -> Result<HttpResponse, Error> {
let input = input.into_inner();
let conn = &db.get().unwrap();
debug!(
"Community {} received activity {:?}",
- &params.community_name, &input
+ &path.into_inner(),
+ &input
);
match input {
CommunityAcceptedObjects::Follow(f) => handle_follow(&f, conn),
diff --git a/server/src/apub/fetcher.rs b/server/src/apub/fetcher.rs
index 368aa4dc..d44fdcb5 100644
--- a/server/src/apub/fetcher.rs
+++ b/server/src/apub/fetcher.rs
@@ -8,7 +8,6 @@ use crate::db::user::{UserForm, User_};
use crate::db::user_view::UserView;
use crate::db::{Crud, SearchType};
use crate::routes::nodeinfo::{NodeInfo, NodeInfoWellKnown};
-use crate::settings::Settings;
use activitystreams::collection::OrderedCollection;
use activitystreams::object::Page;
use activitystreams::BaseBox;
@@ -68,8 +67,8 @@ pub fn fetch_remote_object<Response>(url: &Url) -> Result<Response, Error>
where
Response: for<'de> Deserialize<'de>,
{
- if Settings::get().federation.tls_enabled && url.scheme() != "https" {
- return Err(format_err!("Activitypub uri is insecure: {}", url));
+ if !is_apub_id_valid(&url.to_string()) {
+ return Err(format_err!("Activitypub uri invalid or blocked: {}", url));
}
// TODO: this function should return a future
let timeout = Duration::from_secs(60);
@@ -86,7 +85,7 @@ where
/// The types of ActivityPub objects that can be fetched directly by searching for their ID.
#[serde(untagged)]
-#[derive(serde::Deserialize)]
+#[derive(serde::Deserialize, Debug)]
pub enum SearchAcceptedObjects {
Person(Box<PersonExt>),
Group(Box<GroupExt>),
diff --git a/server/src/apub/mod.rs b/server/src/apub/mod.rs
index a7f0668a..634f3510 100644
--- a/server/src/apub/mod.rs
+++ b/server/src/apub/mod.rs
@@ -88,3 +88,26 @@ pub fn gen_keypair_str() -> (String, String) {
fn vec_bytes_to_str(bytes: Vec<u8>) -> String {
String::from_utf8_lossy(&bytes).into_owned()
}
+
+// Checks if the ID has a valid format, correct scheme, and is in the whitelist.
+fn is_apub_id_valid(apub_id: &str) -> bool {
+ let url = match Url::parse(apub_id) {
+ Ok(u) => u,
+ Err(_) => return false,
+ };
+
+ if url.scheme() != get_apub_protocol_string() {
+ return false;
+ }
+
+ let whitelist: Vec<String> = Settings::get()
+ .federation
+ .instance_whitelist
+ .split(',')
+ .map(|d| d.to_string())
+ .collect();
+ match url.domain() {
+ Some(d) => whitelist.contains(&d.to_owned()),
+ None => false,
+ }
+}
diff --git a/server/src/apub/user_inbox.rs b/server/src/apub/user_inbox.rs
index 7d146308..75cd4e47 100644
--- a/server/src/apub/user_inbox.rs
+++ b/server/src/apub/user_inbox.rs
@@ -17,20 +17,19 @@ pub enum UserAcceptedObjects {
Accept(Accept),
}
-#[derive(Deserialize)]
-pub struct Params {
- user_name: String,
-}
-
/// Handler for all incoming activities to user inboxes.
pub async fn user_inbox(
input: web::Json<UserAcceptedObjects>,
- params: web::Query<Params>,
+ path: web::Path<String>,
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
) -> Result<HttpResponse, Error> {
let input = input.into_inner();
let conn = &db.get().unwrap();
- debug!("User {} received activity: {:?}", &params.user_name, &input);
+ debug!(
+ "User {} received activity: {:?}",
+ &path.into_inner(),
+ &input
+ );
match input {
UserAcceptedObjects::Create(c) => handle_create(&c, conn),