From 164a9c29fe7db9a93bc7777972dd86b349c78e69 Mon Sep 17 00:00:00 2001 From: nutomic Date: Thu, 13 Aug 2020 20:26:49 +0000 Subject: [PATCH] Implement instance blocklist (#85) Implement instance blocklist Co-authored-by: Felix Ableitner Reviewed-on: https://yerbamate.dev/LemmyNet/lemmy/pulls/85 --- server/config/defaults.hjson | 4 ++- server/lemmy_utils/src/settings.rs | 23 ++++++++++++--- server/src/apub/mod.rs | 47 +++++++++++++++++------------- 3 files changed, 48 insertions(+), 26 deletions(-) diff --git a/server/config/defaults.hjson b/server/config/defaults.hjson index 9e9fc998..591f68f6 100644 --- a/server/config/defaults.hjson +++ b/server/config/defaults.hjson @@ -62,8 +62,10 @@ enabled: false # whether tls is required for activitypub. only disable this for debugging, never for producion. tls_enabled: true - # comma seperated list of instances with which federation is allowed + # comma separated list of instances with which federation is allowed allowed_instances: "" + # comma separated list of instances which are blocked from federating + blocked_instances: "" } captcha: { enabled: true diff --git a/server/lemmy_utils/src/settings.rs b/server/lemmy_utils/src/settings.rs index 16fd424c..1d82b231 100644 --- a/server/lemmy_utils/src/settings.rs +++ b/server/lemmy_utils/src/settings.rs @@ -8,7 +8,7 @@ static CONFIG_FILE: &str = "config/config.hjson"; #[derive(Debug, Deserialize, Clone)] pub struct Settings { pub setup: Option, - pub database: Database, + pub database: DatabaseConfig, pub hostname: String, pub bind: IpAddr, pub port: u16, @@ -17,7 +17,7 @@ pub struct Settings { pub pictrs_url: String, pub rate_limit: RateLimitConfig, pub email: Option, - pub federation: Federation, + pub federation: FederationConfig, pub captcha: CaptchaConfig, } @@ -57,7 +57,7 @@ pub struct CaptchaConfig { } #[derive(Debug, Deserialize, Clone)] -pub struct Database { +pub struct DatabaseConfig { pub user: String, pub password: String, pub host: String, @@ -67,10 +67,11 @@ pub struct Database { } #[derive(Debug, Deserialize, Clone)] -pub struct Federation { +pub struct FederationConfig { pub enabled: bool, pub tls_enabled: bool, pub allowed_instances: String, + pub blocked_instances: String, } lazy_static! { @@ -143,6 +144,20 @@ impl Settings { allowed_instances } + pub fn get_blocked_instances(&self) -> Vec { + let mut blocked_instances: Vec = self + .federation + .blocked_instances + .split(',') + .map(|d| d.to_string()) + .collect(); + + // The defaults.hjson config always returns a [""] + blocked_instances.retain(|d| !d.eq("")); + + blocked_instances + } + pub fn save_config_file(data: &str) -> Result { fs::write(CONFIG_FILE, data)?; diff --git a/server/src/apub/mod.rs b/server/src/apub/mod.rs index c759db1a..1af1cc0c 100644 --- a/server/src/apub/mod.rs +++ b/server/src/apub/mod.rs @@ -76,30 +76,35 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> { return Err(anyhow!("invalid apub id scheme: {:?}", apub_id.scheme()).into()); } - let mut allowed_instances: Vec = Settings::get().get_allowed_instances(); - - // need to allow this explicitly because apub activities might contain objects from our local - // instance. replace is needed to remove the port in our federation test setup. - let settings = Settings::get(); - let local_instance = settings.hostname.split(':').collect::>(); - allowed_instances.push( - local_instance - .first() - .context(location_info!())? - .to_string(), - ); - - match apub_id.domain() { - Some(d) => { - let contains = allowed_instances.contains(&d.to_owned()); - - if !contains { - return Err(anyhow!("{} not in federation allowlist", d).into()); - } + let mut allowed_instances = Settings::get().get_allowed_instances(); + let blocked_instances = Settings::get().get_blocked_instances(); + + let domain = apub_id.domain().context(location_info!())?.to_string(); + if !allowed_instances.is_empty() { + // need to allow this explicitly because apub activities might contain objects from our local + // instance. split is needed to remove the port in our federation test setup. + let settings = Settings::get(); + let local_instance = settings.hostname.split(':').collect::>(); + allowed_instances.push( + local_instance + .first() + .context(location_info!())? + .to_string(), + ); + if allowed_instances.contains(&domain) { Ok(()) + } else { + Err(anyhow!("{} not in federation allowlist", domain).into()) } - None => Err(anyhow!("federation allowlist is empty").into()), + } else if !blocked_instances.is_empty() { + if blocked_instances.contains(&domain) { + Err(anyhow!("{} is in federation blocklist", domain).into()) + } else { + Ok(()) + } + } else { + panic!("Invalid config, both allowed_instances and blocked_instances are specified"); } } -- 2.44.1