]> Untitled Git - lemmy.git/commitdiff
Implement instance blocklist (#85)
authornutomic <nutomic@noreply.yerbamate.dev>
Thu, 13 Aug 2020 20:26:49 +0000 (20:26 +0000)
committerdessalines <dessalines@noreply.yerbamate.dev>
Thu, 13 Aug 2020 20:26:49 +0000 (20:26 +0000)
Implement instance blocklist

Co-authored-by: Felix Ableitner <me@nutomic.com>
Reviewed-on: https://yerbamate.dev/LemmyNet/lemmy/pulls/85

server/config/defaults.hjson
server/lemmy_utils/src/settings.rs
server/src/apub/mod.rs

index 9e9fc998818c899a86d6c940c7703345f752c6a4..591f68f6d11b0f86bcd77a2977d789b9a59c36bf 100644 (file)
     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
index 16fd424cbb0b933d6022c09ba0988865fc7e5f91..1d82b231c4fd39960b99f2064cef1b08e649cdec 100644 (file)
@@ -8,7 +8,7 @@ static CONFIG_FILE: &str = "config/config.hjson";
 #[derive(Debug, Deserialize, Clone)]
 pub struct Settings {
   pub setup: Option<Setup>,
-  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<EmailConfig>,
-  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<String> {
+    let mut blocked_instances: Vec<String> = 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<String, Error> {
     fs::write(CONFIG_FILE, data)?;
 
index c759db1a8f8969a8d57b707a3edba8a6f4e31c29..1af1cc0ca2f62907feceda8bbd0a83f02d64bd50 100644 (file)
@@ -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<String> = 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::<Vec<&str>>();
-  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::<Vec<&str>>();
+    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");
   }
 }