]> Untitled Git - lemmy.git/blobdiff - crates/apub/src/objects/mod.rs
Cache & Optimize Woodpecker CI (#3450)
[lemmy.git] / crates / apub / src / objects / mod.rs
index 78013b0cc39e01a1a6249aa6c155f4530b2d2a26..b3653172ac5242a7cb255408a33baf0abce194e1 100644 (file)
@@ -1,7 +1,8 @@
-use crate::protocol::{ImageObject, Source};
+use crate::protocol::Source;
+use activitypub_federation::protocol::values::MediaTypeMarkdownOrHtml;
+use anyhow::anyhow;
 use html2md::parse_html;
-use lemmy_apub_lib::verify::verify_domains_match;
-use lemmy_utils::LemmyError;
+use lemmy_utils::{error::LemmyError, settings::structs::Settings};
 use url::Url;
 
 pub mod comment;
@@ -11,28 +12,41 @@ pub mod person;
 pub mod post;
 pub mod private_message;
 
-pub(crate) fn read_from_string_or_source(raw: &str, source: &Option<Source>) -> String {
+pub(crate) fn read_from_string_or_source(
+  content: &str,
+  media_type: &Option<MediaTypeMarkdownOrHtml>,
+  source: &Option<Source>,
+) -> String {
   if let Some(s) = source {
+    // markdown sent by lemmy in source field
     s.content.clone()
+  } else if media_type == &Some(MediaTypeMarkdownOrHtml::Markdown) {
+    // markdown sent by peertube in content field
+    content.to_string()
   } else {
-    parse_html(raw)
+    // otherwise, convert content html to markdown
+    parse_html(content)
   }
 }
 
 pub(crate) fn read_from_string_or_source_opt(
-  raw: &Option<String>,
+  content: &Option<String>,
+  media_type: &Option<MediaTypeMarkdownOrHtml>,
   source: &Option<Source>,
 ) -> Option<String> {
-  if let Some(s2) = source {
-    Some(s2.content.clone())
-  } else {
-    raw.as_ref().map(|s| parse_html(s))
-  }
+  content
+    .as_ref()
+    .map(|content| read_from_string_or_source(content, media_type, source))
 }
 
-pub fn verify_image_domain_matches(a: &Url, b: &Option<ImageObject>) -> Result<(), LemmyError> {
-  if let Some(b) = b {
-    verify_domains_match(a, &b.url)
+/// When for example a Post is made in a remote community, the community will send it back,
+/// wrapped in Announce. If we simply receive this like any other federated object, overwrite the
+/// existing, local Post. In particular, it will set the field local = false, so that the object
+/// can't be fetched from the Activitypub HTTP endpoint anymore (which only serves local objects).
+pub(crate) fn verify_is_remote_object(id: &Url, settings: &Settings) -> Result<(), LemmyError> {
+  let local_domain = settings.get_hostname_without_port()?;
+  if id.domain() == Some(&local_domain) {
+    Err(anyhow!("cant accept local object from remote instance").into())
   } else {
     Ok(())
   }
@@ -40,76 +54,63 @@ pub fn verify_image_domain_matches(a: &Url, b: &Option<ImageObject>) -> Result<(
 
 #[cfg(test)]
 pub(crate) mod tests {
-  use actix::Actor;
-  use diesel::{
-    r2d2::{ConnectionManager, Pool},
-    PgConnection,
-  };
-  use lemmy_apub_lib::activity_queue::create_activity_queue;
-  use lemmy_db_schema::{
-    establish_unpooled_connection,
-    get_database_url_from_env,
-    source::secret::Secret,
-  };
+  #![allow(clippy::unwrap_used)]
+  #![allow(clippy::indexing_slicing)]
+
+  use activitypub_federation::config::{Data, FederationConfig};
+  use anyhow::anyhow;
+  use lemmy_api_common::{context::LemmyContext, request::build_user_agent};
+  use lemmy_db_schema::{source::secret::Secret, utils::build_db_pool_for_tests};
   use lemmy_utils::{
-    rate_limit::{rate_limiter::RateLimiter, RateLimit},
-    request::build_user_agent,
-    settings::structs::Settings,
-    LemmyError,
+    rate_limit::{RateLimitCell, RateLimitConfig},
+    settings::SETTINGS,
   };
-  use lemmy_websocket::{chat_server::ChatServer, LemmyContext};
-  use parking_lot::Mutex;
-  use reqwest::Client;
-  use reqwest_middleware::ClientBuilder;
-  use std::sync::Arc;
+  use reqwest::{Client, Request, Response};
+  use reqwest_middleware::{ClientBuilder, Middleware, Next};
+  use task_local_extensions::Extensions;
+
+  struct BlockedMiddleware;
+
+  /// A reqwest middleware which blocks all requests
+  #[async_trait::async_trait]
+  impl Middleware for BlockedMiddleware {
+    async fn handle(
+      &self,
+      _req: Request,
+      _extensions: &mut Extensions,
+      _next: Next<'_>,
+    ) -> reqwest_middleware::Result<Response> {
+      Err(anyhow!("Network requests not allowed").into())
+    }
+  }
 
   // TODO: would be nice if we didnt have to use a full context for tests.
-  //       or at least write a helper function so this code is shared with main.rs
-  pub(crate) fn init_context() -> LemmyContext {
-    let client = reqwest::Client::new().into();
-    // activity queue isnt used in tests, so worker count makes no difference
-    let queue_manager = create_activity_queue(client, 4);
-    let activity_queue = queue_manager.queue_handle().clone();
+  pub(crate) async fn init_context() -> Data<LemmyContext> {
     // call this to run migrations
-    establish_unpooled_connection();
-    let settings = Settings::init().unwrap();
-    let rate_limiter = RateLimit {
-      rate_limiter: Arc::new(Mutex::new(RateLimiter::default())),
-      rate_limit_config: settings.rate_limit.to_owned().unwrap_or_default(),
-    };
+    let pool = build_db_pool_for_tests().await;
+
+    let settings = SETTINGS.clone();
     let client = Client::builder()
       .user_agent(build_user_agent(&settings))
       .build()
       .unwrap();
 
-    let client = ClientBuilder::new(client).build();
+    let client = ClientBuilder::new(client).with(BlockedMiddleware).build();
     let secret = Secret {
       id: 0,
-      jwt_secret: "".to_string(),
+      jwt_secret: String::new(),
     };
-    let db_url = match get_database_url_from_env() {
-      Ok(url) => url,
-      Err(_) => settings.get_database_url(),
-    };
-    let manager = ConnectionManager::<PgConnection>::new(&db_url);
-    let pool = Pool::builder()
-      .max_size(settings.database.pool_size)
-      .build(manager)
-      .unwrap_or_else(|_| panic!("Error connecting to {}", db_url));
-    async fn x() -> Result<String, LemmyError> {
-      Ok("".to_string())
-    }
-    let chat_server = ChatServer::startup(
-      pool.clone(),
-      rate_limiter,
-      |_, _, _, _| Box::pin(x()),
-      |_, _, _, _| Box::pin(x()),
-      client.clone(),
-      activity_queue.clone(),
-      settings.clone(),
-      secret.clone(),
-    )
-    .start();
-    LemmyContext::create(pool, chat_server, client, activity_queue, settings, secret)
+
+    let rate_limit_config = RateLimitConfig::builder().build();
+    let rate_limit_cell = RateLimitCell::new(rate_limit_config).await;
+
+    let context = LemmyContext::create(pool, client, secret, rate_limit_cell.clone());
+    let config = FederationConfig::builder()
+      .domain("example.com")
+      .app_data(context)
+      .build()
+      .await
+      .unwrap();
+    config.to_request_data()
   }
 }