From: Riley Date: Mon, 6 Dec 2021 14:54:47 +0000 (-0600) Subject: Don't drop error context when adding a message to errors (#1958) X-Git-Url: http://these/git/%22https:/nerdica.net/README.md?a=commitdiff_plain;h=35cbae61bc03a1a0af29f79ee55223d4e9766c07;p=lemmy.git Don't drop error context when adding a message to errors (#1958) * Respond directly with LemmyError Instrument Perform implementations for more precise traces Use ApiError to format JSON errors when messages are present Keep SpanTrace output in LemmyError Display impl * Hide SpanTrace debug output from LemmyError * Don't log when entering spans, only when leaving * Update actix-web * Update actix-rt * Add newline after error info in LemmyError Display impl * Propogate span information to blocking operations * Instrument apub functions * Use skip_all for more instrument attributes, don't skip 'self' in some api actions * Make message a static string * Send proper JSON over websocket * Add 'message' to LemmyError display if present * Use a quieter root span builder, don't pretty-print logs * Keep passwords and emails out of logs * Re-enable logging Login * Instrument feeds * Emit our own errors * Move error log after status code recording * Make Sensitive generic over the inner type * Remove line that logged secrets --- diff --git a/Cargo.lock b/Cargo.lock index 5e879b8a..9485c570 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.0.0-beta.12" +version = "3.0.0-beta.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afaeb3d3fcb06b775ac62f05d580aae4afe5a149513333a73f688fdf26c06639" +checksum = "1bc3f9d97e32d75fae3ad7d955ac005eea3fd3ea60a89132768700911a60fd94" dependencies = [ "actix-codec", "actix-rt", @@ -130,9 +130,9 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0c218d0a17c120f10ee0c69c9f0c45d87319e8f66b1f065e8412b612fc3e24" +checksum = "05c2f80ce8d0c990941c7a7a931f69fd0701b76d521f8d36298edf59cd3fbf1f" dependencies = [ "actix-macros", "futures-core", @@ -170,9 +170,9 @@ dependencies = [ [[package]] name = "actix-tls" -version = "3.0.0-beta.8" +version = "3.0.0-beta.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a563b0245222230c860c1b077ca7309179fff0f575b1914967c1ee385aa5da64" +checksum = "53d4739910b49c77ea88308a9fbfae544524b34884161527f9978c0102052da0" dependencies = [ "actix-codec", "actix-rt", @@ -182,6 +182,7 @@ dependencies = [ "futures-core", "http", "log", + "pin-project-lite", "tokio-rustls", "tokio-util", "webpki-roots", @@ -199,9 +200,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.0.0-beta.11" +version = "4.0.0-beta.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e85aa9bb018d83a0db70f557ba0cde9c6170a5d1de4fede02e377f68c1ac5aa9" +checksum = "e87cfc4efaad42f8a054e269d1b85046397ff4e8707e49128dea3f99a512a9d6" dependencies = [ "actix-codec", "actix-http", @@ -388,9 +389,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "awc" -version = "3.0.0-beta.10" +version = "3.0.0-beta.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f122bed94dc044b13a991b292ff6a3cde4c3fba890a4e3dbbec0f2eedc607f0a" +checksum = "f9f7d0c472987e454f41c3f4c7fa336ca139707ab255644b0480144c2060c800" dependencies = [ "actix-codec", "actix-http", @@ -1759,6 +1760,7 @@ dependencies = [ "strum_macros", "thiserror", "tokio", + "tracing", "url", "uuid", ] @@ -1777,6 +1779,7 @@ dependencies = [ "lemmy_utils", "serde", "serde_json", + "tracing", "url", ] @@ -1982,6 +1985,7 @@ dependencies = [ "serde", "sha2", "strum", + "tracing", "url", ] @@ -3998,9 +4002,9 @@ dependencies = [ [[package]] name = "tracing-actix-web" -version = "0.5.0-beta.2" +version = "0.5.0-beta.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cac34827e06f78b69523b2fbe5b2dd4dfc75940b2ea5ba37e4fa2a25d4a0edf" +checksum = "994e4a59135823bdca121a8d086e3fcc71741c8677b47fa95a6afdd15e8f646f" dependencies = [ "actix-web", "pin-project", diff --git a/Cargo.toml b/Cargo.toml index 0d38c2e7..040a25cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ serde = { version = "1.0.130", features = ["derive"] } actix = "0.12.0" actix-web = { version = "4.0.0-beta.9", default-features = false, features = ["rustls"] } tracing = "0.1.29" -tracing-actix-web = "0.5.0-beta.2" +tracing-actix-web = { version = "0.5.0-beta.3", default-features = false } tracing-error = "0.2.0" tracing-log = "0.1.2" tracing-subscriber = { version = "0.3.2", features = ["env-filter"] } diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index 96b47f46..c2bc77fa 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -48,5 +48,6 @@ async-trait = "0.1.51" captcha = "0.0.8" anyhow = "1.0.44" thiserror = "1.0.29" +tracing = "0.1.29" background-jobs = "0.11.0" reqwest = { version = "0.11.4", features = ["json"] } diff --git a/crates/api/src/comment.rs b/crates/api/src/comment.rs index e673d497..ac066227 100644 --- a/crates/api/src/comment.rs +++ b/crates/api/src/comment.rs @@ -23,7 +23,7 @@ use lemmy_db_schema::{ traits::{Likeable, Saveable}, }; use lemmy_db_views::{comment_view::CommentView, local_user_view::LocalUserView}; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperation}; use crate::Perform; @@ -32,6 +32,7 @@ use crate::Perform; impl Perform for MarkCommentAsRead { type Response = CommentResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -56,7 +57,7 @@ impl Perform for MarkCommentAsRead { // Verify that only the recipient can mark as read if local_user_view.person.id != orig_comment.get_recipient_id() { - return Err(ApiError::err_plain("no_comment_edit_allowed").into()); + return Err(LemmyError::from_message("no_comment_edit_allowed")); } // Do the mark as read @@ -65,7 +66,8 @@ impl Perform for MarkCommentAsRead { Comment::update_read(conn, comment_id, read) }) .await? - .map_err(|_| ApiError::err_plain("couldnt_update_comment"))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment"))?; // Refetch it let comment_id = data.comment_id; @@ -89,6 +91,7 @@ impl Perform for MarkCommentAsRead { impl Perform for SaveComment { type Response = CommentResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -107,12 +110,14 @@ impl Perform for SaveComment { let save_comment = move |conn: &'_ _| CommentSaved::save(conn, &comment_saved_form); blocking(context.pool(), save_comment) .await? - .map_err(|e| ApiError::err("couldnt_save_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_save_comment"))?; } else { let unsave_comment = move |conn: &'_ _| CommentSaved::unsave(conn, &comment_saved_form); blocking(context.pool(), unsave_comment) .await? - .map_err(|e| ApiError::err("couldnt_save_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_save_comment"))?; } let comment_id = data.comment_id; @@ -134,6 +139,7 @@ impl Perform for SaveComment { impl Perform for CreateCommentLike { type Response = CommentResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -201,7 +207,8 @@ impl Perform for CreateCommentLike { let like = move |conn: &'_ _| CommentLike::like(conn, &like_form2); blocking(context.pool(), like) .await? - .map_err(|e| ApiError::err("couldnt_like_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_like_comment"))?; Vote::send( &object, diff --git a/crates/api/src/comment_report.rs b/crates/api/src/comment_report.rs index f1bf7023..8c3e10e5 100644 --- a/crates/api/src/comment_report.rs +++ b/crates/api/src/comment_report.rs @@ -14,7 +14,7 @@ use lemmy_db_views::{ comment_report_view::{CommentReportQueryBuilder, CommentReportView}, comment_view::CommentView, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation}; /// Creates a comment report and notifies the moderators of the community @@ -22,6 +22,7 @@ use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation} impl Perform for CreateCommentReport { type Response = CommentReportResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -34,10 +35,10 @@ impl Perform for CreateCommentReport { // check size of report and check for whitespace let reason = data.reason.trim(); if reason.is_empty() { - return Err(ApiError::err_plain("report_reason_required").into()); + return Err(LemmyError::from_message("report_reason_required")); } if reason.chars().count() > 1000 { - return Err(ApiError::err_plain("report_too_long").into()); + return Err(LemmyError::from_message("report_too_long")); } let person_id = local_user_view.person.id; @@ -60,7 +61,8 @@ impl Perform for CreateCommentReport { CommentReport::report(conn, &report_form) }) .await? - .map_err(|e| ApiError::err("couldnt_create_report", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_report"))?; let comment_report_view = blocking(context.pool(), move |conn| { CommentReportView::read(conn, report.id, person_id) @@ -96,6 +98,7 @@ impl Perform for CreateCommentReport { impl Perform for ResolveCommentReport { type Response = CommentReportResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -126,7 +129,8 @@ impl Perform for ResolveCommentReport { blocking(context.pool(), resolve_fun) .await? - .map_err(|e| ApiError::err("couldnt_resolve_report", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_resolve_report"))?; let report_id = data.report_id; let comment_report_view = blocking(context.pool(), move |conn| { @@ -155,6 +159,7 @@ impl Perform for ResolveCommentReport { impl Perform for ListCommentReports { type Response = ListCommentReportsResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api/src/community.rs b/crates/api/src/community.rs index b47a4ec6..c0aea602 100644 --- a/crates/api/src/community.rs +++ b/crates/api/src/community.rs @@ -54,13 +54,14 @@ use lemmy_db_views_actor::{ community_view::CommunityView, person_view::PersonViewSafe, }; -use lemmy_utils::{location_info, utils::naive_from_unix, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{location_info, utils::naive_from_unix, ConnectionId, LemmyError}; use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperation}; #[async_trait::async_trait(?Send)] impl Perform for FollowCommunity { type Response = CommunityResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -90,13 +91,15 @@ impl Perform for FollowCommunity { let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form); blocking(context.pool(), follow) .await? - .map_err(|e| ApiError::err("community_follower_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_follower_already_exists"))?; } else { let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form); blocking(context.pool(), unfollow) .await? - .map_err(|e| ApiError::err("community_follower_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_follower_already_exists"))?; } } else if data.follow { // Dont actually add to the community followers here, because you need @@ -109,7 +112,8 @@ impl Perform for FollowCommunity { let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form); blocking(context.pool(), unfollow) .await? - .map_err(|e| ApiError::err("community_follower_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_follower_already_exists"))?; } let community_id = data.community_id; @@ -134,6 +138,7 @@ impl Perform for FollowCommunity { impl Perform for BlockCommunity { type Response = BlockCommunityResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -154,7 +159,8 @@ impl Perform for BlockCommunity { let block = move |conn: &'_ _| CommunityBlock::block(conn, &community_block_form); blocking(context.pool(), block) .await? - .map_err(|e| ApiError::err("community_block_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_block_already_exists"))?; // Also, unfollow the community, and send a federated unfollow let community_follower_form = CommunityFollowerForm { @@ -176,7 +182,8 @@ impl Perform for BlockCommunity { let unblock = move |conn: &'_ _| CommunityBlock::unblock(conn, &community_block_form); blocking(context.pool(), unblock) .await? - .map_err(|e| ApiError::err("community_block_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_block_already_exists"))?; } let community_view = blocking(context.pool(), move |conn| { @@ -195,6 +202,7 @@ impl Perform for BlockCommunity { impl Perform for BanFromCommunity { type Response = BanFromCommunityResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -230,7 +238,8 @@ impl Perform for BanFromCommunity { let ban = move |conn: &'_ _| CommunityPersonBan::ban(conn, &community_user_ban_form); blocking(context.pool(), ban) .await? - .map_err(|e| ApiError::err("community_user_already_banned", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_user_already_banned"))?; // Also unsubscribe them from the community, if they are subscribed let community_follower_form = CommunityFollowerForm { @@ -255,7 +264,8 @@ impl Perform for BanFromCommunity { let unban = move |conn: &'_ _| CommunityPersonBan::unban(conn, &community_user_ban_form); blocking(context.pool(), unban) .await? - .map_err(|e| ApiError::err("community_user_already_banned", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_user_already_banned"))?; UndoBlockUserFromCommunity::send( &community, &banned_person, @@ -336,6 +346,7 @@ impl Perform for BanFromCommunity { impl Perform for AddModToCommunity { type Response = AddModToCommunityResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -359,12 +370,14 @@ impl Perform for AddModToCommunity { let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); blocking(context.pool(), join) .await? - .map_err(|e| ApiError::err("community_moderator_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_moderator_already_exists"))?; } else { let leave = move |conn: &'_ _| CommunityModerator::leave(conn, &community_moderator_form); blocking(context.pool(), leave) .await? - .map_err(|e| ApiError::err("community_moderator_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_moderator_already_exists"))?; } // Mod tables @@ -434,6 +447,7 @@ impl Perform for AddModToCommunity { impl Perform for TransferCommunity { type Response = GetCommunityResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -472,7 +486,7 @@ impl Perform for TransferCommunity { .map(|a| a.person.id) .any(|x| x == local_user_view.person.id) { - return Err(ApiError::err_plain("not_an_admin").into()); + return Err(LemmyError::from_message("not_an_admin")); } // You have to re-do the community_moderator table, reordering it. @@ -502,7 +516,8 @@ impl Perform for TransferCommunity { let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); blocking(context.pool(), join) .await? - .map_err(|e| ApiError::err("community_moderator_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_moderator_already_exists"))?; } // Mod tables @@ -523,14 +538,16 @@ impl Perform for TransferCommunity { CommunityView::read(conn, community_id, Some(person_id)) }) .await? - .map_err(|e| ApiError::err("couldnt_find_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community"))?; let community_id = data.community_id; let moderators = blocking(context.pool(), move |conn| { CommunityModeratorView::for_community(conn, community_id) }) .await? - .map_err(|e| ApiError::err("couldnt_find_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community"))?; // Return the jwt Ok(GetCommunityResponse { diff --git a/crates/api/src/local_user.rs b/crates/api/src/local_user.rs index 6f63d14b..a0711d69 100644 --- a/crates/api/src/local_user.rs +++ b/crates/api/src/local_user.rs @@ -49,9 +49,9 @@ use lemmy_utils::{ email::send_email, location_info, utils::{generate_random_string, is_valid_display_name, is_valid_matrix_id, naive_from_unix}, - ApiError, ConnectionId, LemmyError, + Sensitive, }; use lemmy_websocket::{ messages::{CaptchaItem, SendAllMessage}, @@ -63,6 +63,7 @@ use lemmy_websocket::{ impl Perform for Login { type Response = LoginResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -76,7 +77,8 @@ impl Perform for Login { LocalUserView::find_by_email_or_name(conn, &username_or_email) }) .await? - .map_err(|e| ApiError::err("couldnt_find_that_username_or_email", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_that_username_or_email"))?; // Verify the password let valid: bool = verify( @@ -85,7 +87,7 @@ impl Perform for Login { ) .unwrap_or(false); if !valid { - return Err(ApiError::err_plain("password_incorrect").into()); + return Err(LemmyError::from_message("password_incorrect")); } // Return the jwt @@ -94,7 +96,8 @@ impl Perform for Login { local_user_view.local_user.id.0, &context.secret().jwt_secret, &context.settings().hostname, - )?, + )? + .into(), }) } } @@ -103,6 +106,7 @@ impl Perform for Login { impl Perform for GetCaptcha { type Response = GetCaptchaResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -148,6 +152,7 @@ impl Perform for GetCaptcha { impl Perform for SaveUserSettings { type Response = LoginResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -159,7 +164,7 @@ impl Perform for SaveUserSettings { let avatar = diesel_option_overwrite_to_url(&data.avatar)?; let banner = diesel_option_overwrite_to_url(&data.banner)?; - let email = diesel_option_overwrite(&data.email); + let email = diesel_option_overwrite(&data.email.clone().map(Sensitive::into_inner)); let bio = diesel_option_overwrite(&data.bio); let display_name = diesel_option_overwrite(&data.display_name); let matrix_user_id = diesel_option_overwrite(&data.matrix_user_id); @@ -167,7 +172,7 @@ impl Perform for SaveUserSettings { if let Some(Some(bio)) = &bio { if bio.chars().count() > 300 { - return Err(ApiError::err_plain("bio_length_overflow").into()); + return Err(LemmyError::from_message("bio_length_overflow")); } } @@ -176,13 +181,13 @@ impl Perform for SaveUserSettings { display_name.trim(), context.settings().actor_name_max_length, ) { - return Err(ApiError::err_plain("invalid_username").into()); + return Err(LemmyError::from_message("invalid_username")); } } if let Some(Some(matrix_user_id)) = &matrix_user_id { if !is_valid_matrix_id(matrix_user_id) { - return Err(ApiError::err_plain("invalid_matrix_id").into()); + return Err(LemmyError::from_message("invalid_matrix_id")); } } @@ -219,7 +224,8 @@ impl Perform for SaveUserSettings { Person::update(conn, person_id, &person_form) }) .await? - .map_err(|e| ApiError::err("user_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("user_already_exists"))?; let local_user_form = LocalUserForm { person_id, @@ -253,7 +259,7 @@ impl Perform for SaveUserSettings { "user_already_exists" }; - return Err(ApiError::err(err_type, e).into()); + return Err(LemmyError::from(e).with_message(err_type)); } }; @@ -263,7 +269,8 @@ impl Perform for SaveUserSettings { updated_local_user.id.0, &context.secret().jwt_secret, &context.settings().hostname, - )?, + )? + .into(), }) } } @@ -272,6 +279,7 @@ impl Perform for SaveUserSettings { impl Perform for ChangePassword { type Response = LoginResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -279,13 +287,13 @@ impl Perform for ChangePassword { ) -> Result { let data: &ChangePassword = self; let local_user_view = - get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?; + get_local_user_view_from_jwt(data.auth.as_ref(), context.pool(), context.secret()).await?; password_length_check(&data.new_password)?; // Make sure passwords match if data.new_password != data.new_password_verify { - return Err(ApiError::err_plain("passwords_dont_match").into()); + return Err(LemmyError::from_message("passwords_dont_match")); } // Check the old password @@ -295,7 +303,7 @@ impl Perform for ChangePassword { ) .unwrap_or(false); if !valid { - return Err(ApiError::err_plain("password_incorrect").into()); + return Err(LemmyError::from_message("password_incorrect")); } let local_user_id = local_user_view.local_user.id; @@ -311,7 +319,8 @@ impl Perform for ChangePassword { updated_local_user.id.0, &context.secret().jwt_secret, &context.settings().hostname, - )?, + )? + .into(), }) } } @@ -320,6 +329,7 @@ impl Perform for ChangePassword { impl Perform for AddAdmin { type Response = AddAdminResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -338,7 +348,8 @@ impl Perform for AddAdmin { Person::add_admin(conn, added_person_id, added) }) .await? - .map_err(|e| ApiError::err("couldnt_update_user", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_user"))?; // Mod tables let form = ModAddForm { @@ -378,6 +389,7 @@ impl Perform for AddAdmin { impl Perform for BanPerson { type Response = BanPersonResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -395,7 +407,8 @@ impl Perform for BanPerson { let ban_person = move |conn: &'_ _| Person::ban_person(conn, banned_person_id, ban); blocking(context.pool(), ban_person) .await? - .map_err(|e| ApiError::err("couldnt_update_user", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_user"))?; // Remove their data if that's desired if data.remove_data.unwrap_or(false) { @@ -471,6 +484,7 @@ impl Perform for BanPerson { impl Perform for BlockPerson { type Response = BlockPersonResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -485,7 +499,7 @@ impl Perform for BlockPerson { // Don't let a person block themselves if target_id == person_id { - return Err(ApiError::err_plain("cant_block_yourself").into()); + return Err(LemmyError::from_message("cant_block_yourself")); } let person_block_form = PersonBlockForm { @@ -497,12 +511,14 @@ impl Perform for BlockPerson { let block = move |conn: &'_ _| PersonBlock::block(conn, &person_block_form); blocking(context.pool(), block) .await? - .map_err(|e| ApiError::err("person_block_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("person_block_already_exists"))?; } else { let unblock = move |conn: &'_ _| PersonBlock::unblock(conn, &person_block_form); blocking(context.pool(), unblock) .await? - .map_err(|e| ApiError::err("person_block_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("person_block_already_exists"))?; } // TODO does any federated stuff need to be done here? @@ -525,6 +541,7 @@ impl Perform for BlockPerson { impl Perform for GetReplies { type Response = GetRepliesResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -563,6 +580,7 @@ impl Perform for GetReplies { impl Perform for GetPersonMentions { type Response = GetPersonMentionsResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -598,6 +616,7 @@ impl Perform for GetPersonMentions { impl Perform for MarkPersonMentionAsRead { type Response = PersonMentionResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -614,7 +633,7 @@ impl Perform for MarkPersonMentionAsRead { .await??; if local_user_view.person.id != read_person_mention.recipient_id { - return Err(ApiError::err_plain("couldnt_update_comment").into()); + return Err(LemmyError::from_message("couldnt_update_comment")); } let person_mention_id = read_person_mention.id; @@ -623,7 +642,8 @@ impl Perform for MarkPersonMentionAsRead { move |conn: &'_ _| PersonMention::update_read(conn, person_mention_id, read); blocking(context.pool(), update_mention) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment"))?; let person_mention_id = read_person_mention.id; let person_id = local_user_view.person.id; @@ -642,6 +662,7 @@ impl Perform for MarkPersonMentionAsRead { impl Perform for MarkAllAsRead { type Response = GetRepliesResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -671,7 +692,8 @@ impl Perform for MarkAllAsRead { let mark_as_read = move |conn: &'_ _| Comment::update_read(conn, reply_id, true); blocking(context.pool(), mark_as_read) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment"))?; } // Mark all user mentions as read @@ -679,13 +701,15 @@ impl Perform for MarkAllAsRead { move |conn: &'_ _| PersonMention::mark_all_as_read(conn, person_id); blocking(context.pool(), update_person_mentions) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment"))?; // Mark all private_messages as read let update_pm = move |conn: &'_ _| PrivateMessage::mark_all_as_read(conn, person_id); blocking(context.pool(), update_pm) .await? - .map_err(|e| ApiError::err("couldnt_update_private_message", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_private_message"))?; Ok(GetRepliesResponse { replies: vec![] }) } @@ -695,6 +719,7 @@ impl Perform for MarkAllAsRead { impl Perform for PasswordReset { type Response = PasswordResetResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -708,7 +733,8 @@ impl Perform for PasswordReset { LocalUserView::find_by_email(conn, &email) }) .await? - .map_err(|e| ApiError::err("couldnt_find_that_username_or_email", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_that_username_or_email"))?; // Generate a random token let token = generate_random_string(); @@ -734,7 +760,9 @@ impl Perform for PasswordReset { html, &context.settings(), ) - .map_err(|e| ApiError::err("email_send_failed", e))?; + .map_err(|e| anyhow::anyhow!("{}", e)) + .map_err(LemmyError::from) + .map_err(|e| e.with_message("email_send_failed"))?; Ok(PasswordResetResponse {}) } @@ -744,6 +772,7 @@ impl Perform for PasswordReset { impl Perform for PasswordChange { type Response = LoginResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -762,7 +791,7 @@ impl Perform for PasswordChange { // Make sure passwords match if data.password != data.password_verify { - return Err(ApiError::err_plain("passwords_dont_match").into()); + return Err(LemmyError::from_message("passwords_dont_match")); } // Update the user with the new password @@ -771,7 +800,8 @@ impl Perform for PasswordChange { LocalUser::update_password(conn, local_user_id, &password) }) .await? - .map_err(|e| ApiError::err("couldnt_update_user", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_user"))?; // Return the jwt Ok(LoginResponse { @@ -779,7 +809,8 @@ impl Perform for PasswordChange { updated_local_user.id.0, &context.secret().jwt_secret, &context.settings().hostname, - )?, + )? + .into(), }) } } @@ -788,6 +819,7 @@ impl Perform for PasswordChange { impl Perform for GetReportCount { type Response = GetReportCountResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -825,6 +857,7 @@ impl Perform for GetReportCount { impl Perform for GetUnreadCount { type Response = GetUnreadCountResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api/src/post.rs b/crates/api/src/post.rs index 60a580b8..64c3a930 100644 --- a/crates/api/src/post.rs +++ b/crates/api/src/post.rs @@ -29,7 +29,7 @@ use lemmy_db_schema::{ traits::{Crud, Likeable, Saveable}, }; use lemmy_db_views::post_view::PostView; -use lemmy_utils::{request::fetch_site_metadata, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{request::fetch_site_metadata, ConnectionId, LemmyError}; use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperation}; use std::convert::TryInto; @@ -37,6 +37,7 @@ use std::convert::TryInto; impl Perform for CreatePostLike { type Response = PostResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -83,7 +84,8 @@ impl Perform for CreatePostLike { let like = move |conn: &'_ _| PostLike::like(conn, &like_form2); blocking(context.pool(), like) .await? - .map_err(|e| ApiError::err("couldnt_like_post", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_like_post"))?; Vote::send( &object, @@ -123,6 +125,7 @@ impl Perform for CreatePostLike { impl Perform for MarkPostAsRead { type Response = PostResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -158,6 +161,7 @@ impl Perform for MarkPostAsRead { impl Perform for LockPost { type Response = PostResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -227,6 +231,7 @@ impl Perform for LockPost { impl Perform for StickyPost { type Response = PostResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -300,6 +305,7 @@ impl Perform for StickyPost { impl Perform for SavePost { type Response = PostResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -318,12 +324,14 @@ impl Perform for SavePost { let save = move |conn: &'_ _| PostSaved::save(conn, &post_saved_form); blocking(context.pool(), save) .await? - .map_err(|e| ApiError::err("couldnt_save_post", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_save_post"))?; } else { let unsave = move |conn: &'_ _| PostSaved::unsave(conn, &post_saved_form); blocking(context.pool(), unsave) .await? - .map_err(|e| ApiError::err("couldnt_save_post", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_save_post"))?; } let post_id = data.post_id; @@ -344,6 +352,7 @@ impl Perform for SavePost { impl Perform for GetSiteMetadata { type Response = GetSiteMetadataResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api/src/post_report.rs b/crates/api/src/post_report.rs index 0e47f592..02afc795 100644 --- a/crates/api/src/post_report.rs +++ b/crates/api/src/post_report.rs @@ -23,7 +23,7 @@ use lemmy_db_views::{ post_report_view::{PostReportQueryBuilder, PostReportView}, post_view::PostView, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation}; /// Creates a post report and notifies the moderators of the community @@ -31,6 +31,7 @@ use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation} impl Perform for CreatePostReport { type Response = PostReportResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -43,10 +44,10 @@ impl Perform for CreatePostReport { // check size of report and check for whitespace let reason = data.reason.trim(); if reason.is_empty() { - return Err(ApiError::err_plain("report_reason_required").into()); + return Err(LemmyError::from_message("report_reason_required")); } if reason.chars().count() > 1000 { - return Err(ApiError::err_plain("report_too_long").into()); + return Err(LemmyError::from_message("report_too_long")); } let person_id = local_user_view.person.id; @@ -71,7 +72,8 @@ impl Perform for CreatePostReport { PostReport::report(conn, &report_form) }) .await? - .map_err(|e| ApiError::err("couldnt_create_report", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_report"))?; let post_report_view = blocking(context.pool(), move |conn| { PostReportView::read(conn, report.id, person_id) @@ -105,6 +107,7 @@ impl Perform for CreatePostReport { impl Perform for ResolvePostReport { type Response = PostReportResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -135,7 +138,8 @@ impl Perform for ResolvePostReport { blocking(context.pool(), resolve_fun) .await? - .map_err(|e| ApiError::err("couldnt_resolve_report", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_resolve_report"))?; let post_report_view = blocking(context.pool(), move |conn| { PostReportView::read(conn, report_id, person_id) @@ -161,6 +165,7 @@ impl Perform for ResolvePostReport { impl Perform for ListPostReports { type Response = ListPostReportsResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api/src/private_message.rs b/crates/api/src/private_message.rs index 1c80f44f..b0d04731 100644 --- a/crates/api/src/private_message.rs +++ b/crates/api/src/private_message.rs @@ -6,13 +6,14 @@ use lemmy_api_common::{ person::{MarkPrivateMessageAsRead, PrivateMessageResponse}, }; use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud}; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperation}; #[async_trait::async_trait(?Send)] impl Perform for MarkPrivateMessageAsRead { type Response = PrivateMessageResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -29,7 +30,7 @@ impl Perform for MarkPrivateMessageAsRead { }) .await??; if local_user_view.person.id != orig_private_message.recipient_id { - return Err(ApiError::err_plain("couldnt_update_private_message").into()); + return Err(LemmyError::from_message("couldnt_update_private_message")); } // Doing the update @@ -39,7 +40,8 @@ impl Perform for MarkPrivateMessageAsRead { PrivateMessage::update_read(conn, private_message_id, read) }) .await? - .map_err(|e| ApiError::err("couldnt_update_private_message", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_private_message"))?; // No need to send an apub update let op = UserOperation::MarkPrivateMessageAsRead; diff --git a/crates/api/src/site.rs b/crates/api/src/site.rs index be9dc5da..99906bf6 100644 --- a/crates/api/src/site.rs +++ b/crates/api/src/site.rs @@ -49,20 +49,14 @@ use lemmy_db_views_moderator::{ mod_sticky_post_view::ModStickyPostView, mod_transfer_community_view::ModTransferCommunityView, }; -use lemmy_utils::{ - location_info, - settings::structs::Settings, - version, - ApiError, - ConnectionId, - LemmyError, -}; +use lemmy_utils::{location_info, settings::structs::Settings, version, ConnectionId, LemmyError}; use lemmy_websocket::LemmyContext; #[async_trait::async_trait(?Send)] impl Perform for GetModlog { type Response = GetModlogResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -143,6 +137,7 @@ impl Perform for GetModlog { impl Perform for Search { type Response = SearchResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -151,7 +146,8 @@ impl Perform for Search { let data: &Search = self; let local_user_view = - get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; + get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret()) + .await?; let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw); let show_bot_accounts = local_user_view @@ -383,19 +379,23 @@ impl Perform for Search { impl Perform for ResolveObject { type Response = ResolveObjectResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, _websocket_id: Option, ) -> Result { let local_user_view = - get_local_user_view_from_jwt_opt(&self.auth, context.pool(), context.secret()).await?; + get_local_user_view_from_jwt_opt(self.auth.as_ref(), context.pool(), context.secret()) + .await?; let res = search_by_apub_id(&self.q, context) .await - .map_err(|e| ApiError::err("couldnt_find_object", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_object"))?; convert_response(res, local_user_view.map(|l| l.person.id), context.pool()) .await - .map_err(|e| ApiError::err("couldnt_find_object", e).into()) + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_object")) } } @@ -442,6 +442,7 @@ async fn convert_response( impl Perform for TransferSite { type Response = GetSiteResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -457,14 +458,15 @@ impl Perform for TransferSite { // Make sure user is the creator if read_site.creator_id != local_user_view.person.id { - return Err(ApiError::err_plain("not_an_admin").into()); + return Err(LemmyError::from_message("not_an_admin")); } let new_creator_id = data.person_id; let transfer_site = move |conn: &'_ _| Site::transfer(conn, new_creator_id); blocking(context.pool(), transfer_site) .await? - .map_err(|e| ApiError::err("couldnt_update_site", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_site"))?; // Mod tables let form = ModAddForm { @@ -509,6 +511,7 @@ impl Perform for TransferSite { impl Perform for GetSiteConfig { type Response = GetSiteConfigResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -531,6 +534,7 @@ impl Perform for GetSiteConfig { impl Perform for SaveSiteConfig { type Response = GetSiteConfigResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -545,7 +549,8 @@ impl Perform for SaveSiteConfig { // Make sure docker doesn't have :ro at the end of the volume, so its not a read-only filesystem let config_hjson = Settings::save_config_file(&data.config_hjson) - .map_err(|e| ApiError::err("couldnt_update_site", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_site"))?; Ok(GetSiteConfigResponse { config_hjson }) } diff --git a/crates/api/src/websocket.rs b/crates/api/src/websocket.rs index fa03e4ec..00a7e686 100644 --- a/crates/api/src/websocket.rs +++ b/crates/api/src/websocket.rs @@ -11,6 +11,7 @@ use lemmy_websocket::{ impl Perform for UserJoin { type Response = UserJoinResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -35,6 +36,7 @@ impl Perform for UserJoin { impl Perform for CommunityJoin { type Response = CommunityJoinResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -57,6 +59,7 @@ impl Perform for CommunityJoin { impl Perform for ModJoin { type Response = ModJoinResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -79,6 +82,7 @@ impl Perform for ModJoin { impl Perform for PostJoin { type Response = PostJoinResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api_common/Cargo.toml b/crates/api_common/Cargo.toml index 078987eb..553ccb5b 100644 --- a/crates/api_common/Cargo.toml +++ b/crates/api_common/Cargo.toml @@ -23,4 +23,5 @@ diesel = "1.4.8" actix-web = { version = "4.0.0-beta.9", default-features = false, features = ["cookies"] } chrono = { version = "0.4.19", features = ["serde"] } serde_json = { version = "1.0.68", features = ["preserve_order"] } +tracing = "0.1.29" url = "2.2.2" diff --git a/crates/api_common/src/comment.rs b/crates/api_common/src/comment.rs index afe76a99..84717800 100644 --- a/crates/api_common/src/comment.rs +++ b/crates/api_common/src/comment.rs @@ -1,74 +1,75 @@ use lemmy_db_schema::newtypes::{CommentId, CommentReportId, CommunityId, LocalUserId, PostId}; use lemmy_db_views::{comment_report_view::CommentReportView, comment_view::CommentView}; +use lemmy_utils::Sensitive; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct CreateComment { pub content: String, pub post_id: PostId, pub parent_id: Option, pub form_id: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetComment { pub id: CommentId, - pub auth: Option, + pub auth: Option>, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct EditComment { pub content: String, pub comment_id: CommentId, pub form_id: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct DeleteComment { pub comment_id: CommentId, pub deleted: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct RemoveComment { pub comment_id: CommentId, pub removed: bool, pub reason: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct MarkCommentAsRead { pub comment_id: CommentId, pub read: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct SaveComment { pub comment_id: CommentId, pub save: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct CommentResponse { pub comment_view: CommentView, pub recipient_ids: Vec, pub form_id: Option, // An optional front end ID, to tell which is coming back } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct CreateCommentLike { pub comment_id: CommentId, pub score: i16, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetComments { pub type_: Option, pub sort: Option, @@ -77,34 +78,34 @@ pub struct GetComments { pub community_id: Option, pub community_name: Option, pub saved_only: Option, - pub auth: Option, + pub auth: Option>, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetCommentsResponse { pub comments: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct CreateCommentReport { pub comment_id: CommentId, pub reason: String, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct CommentReportResponse { pub comment_report_view: CommentReportView, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ResolveCommentReport { pub report_id: CommentReportId, pub resolved: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ListCommentReports { pub page: Option, pub limit: Option, @@ -112,10 +113,10 @@ pub struct ListCommentReports { pub unresolved_only: Option, /// if no community is given, it returns reports for all communities moderated by the auth user pub community_id: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ListCommentReportsResponse { pub comment_reports: Vec, } diff --git a/crates/api_common/src/community.rs b/crates/api_common/src/community.rs index 1f32267f..9686172a 100644 --- a/crates/api_common/src/community.rs +++ b/crates/api_common/src/community.rs @@ -4,24 +4,25 @@ use lemmy_db_views_actor::{ community_view::CommunityView, person_view::PersonViewSafe, }; +use lemmy_utils::Sensitive; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetCommunity { pub id: Option, /// Example: star_trek , or star_trek@xyz.tld pub name: Option, - pub auth: Option, + pub auth: Option>, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetCommunityResponse { pub community_view: CommunityView, pub moderators: Vec, pub online: usize, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct CreateCommunity { pub name: String, pub title: String, @@ -29,10 +30,10 @@ pub struct CreateCommunity { pub icon: Option, pub banner: Option, pub nsfw: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct CommunityResponse { pub community_view: CommunityView, } @@ -43,7 +44,7 @@ pub struct ListCommunities { pub sort: Option, pub page: Option, pub limit: Option, - pub auth: Option, + pub auth: Option>, } #[derive(Serialize, Deserialize, Debug)] @@ -51,7 +52,7 @@ pub struct ListCommunitiesResponse { pub communities: Vec, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct BanFromCommunity { pub community_id: CommunityId, pub person_id: PersonId, @@ -59,29 +60,29 @@ pub struct BanFromCommunity { pub remove_data: Option, pub reason: Option, pub expires: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct BanFromCommunityResponse { pub person_view: PersonViewSafe, pub banned: bool, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct AddModToCommunity { pub community_id: CommunityId, pub person_id: PersonId, pub added: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct AddModToCommunityResponse { pub moderators: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct EditCommunity { pub community_id: CommunityId, pub title: Option, @@ -89,48 +90,48 @@ pub struct EditCommunity { pub icon: Option, pub banner: Option, pub nsfw: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct DeleteCommunity { pub community_id: CommunityId, pub deleted: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct RemoveCommunity { pub community_id: CommunityId, pub removed: bool, pub reason: Option, pub expires: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct FollowCommunity { pub community_id: CommunityId, pub follow: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct BlockCommunity { pub community_id: CommunityId, pub block: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct BlockCommunityResponse { pub community_view: CommunityView, pub blocked: bool, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct TransferCommunity { pub community_id: CommunityId, pub person_id: PersonId, - pub auth: String, + pub auth: Sensitive, } diff --git a/crates/api_common/src/lib.rs b/crates/api_common/src/lib.rs index f5b6ebad..29e26e1e 100644 --- a/crates/api_common/src/lib.rs +++ b/crates/api_common/src/lib.rs @@ -23,7 +23,7 @@ use lemmy_db_views_actor::{ community_person_ban_view::CommunityPersonBanView, community_view::CommunityView, }; -use lemmy_utils::{claims::Claims, settings::structs::FederationConfig, ApiError, LemmyError}; +use lemmy_utils::{claims::Claims, settings::structs::FederationConfig, LemmyError, Sensitive}; use url::Url; pub async fn blocking(pool: &DbPool, f: F) -> Result @@ -32,9 +32,12 @@ where T: Send + 'static, { let pool = pool.clone(); + let blocking_span = tracing::info_span!("blocking operation"); let res = actix_web::web::block(move || { + let entered = blocking_span.enter(); let conn = pool.get()?; let res = (f)(&conn); + drop(entered); Ok(res) as Result }) .await?; @@ -52,14 +55,14 @@ pub async fn is_mod_or_admin( }) .await?; if !is_mod_or_admin { - return Err(ApiError::err_plain("not_a_mod_or_admin").into()); + return Err(LemmyError::from_message("not_a_mod_or_admin")); } Ok(()) } pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> { if !local_user_view.person.admin { - return Err(ApiError::err_plain("not_an_admin").into()); + return Err(LemmyError::from_message("not_an_admin")); } Ok(()) } @@ -67,7 +70,8 @@ pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> { pub async fn get_post(post_id: PostId, pool: &DbPool) -> Result { blocking(pool, move |conn| Post::read(conn, post_id)) .await? - .map_err(|_| ApiError::err_plain("couldnt_find_post").into()) + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_post")) } pub async fn mark_post_as_read( @@ -81,7 +85,8 @@ pub async fn mark_post_as_read( PostRead::mark_as_read(conn, &post_read_form) }) .await? - .map_err(|e| ApiError::err("couldnt_mark_post_as_read", e).into()) + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_mark_post_as_read")) } pub async fn mark_post_as_unread( @@ -95,7 +100,8 @@ pub async fn mark_post_as_unread( PostRead::mark_as_unread(conn, &post_read_form) }) .await? - .map_err(|e| ApiError::err("couldnt_mark_post_as_read", e).into()) + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_mark_post_as_read")) } pub async fn get_local_user_view_from_jwt( @@ -104,19 +110,20 @@ pub async fn get_local_user_view_from_jwt( secret: &Secret, ) -> Result { let claims = Claims::decode(jwt, &secret.jwt_secret) - .map_err(|e| ApiError::err("not_logged_in", e))? + .map_err(LemmyError::from) + .map_err(|e| e.with_message("not_logged_in"))? .claims; let local_user_id = LocalUserId(claims.sub); let local_user_view = blocking(pool, move |conn| LocalUserView::read(conn, local_user_id)).await??; // Check for a site ban if local_user_view.person.banned { - return Err(ApiError::err_plain("site_ban").into()); + return Err(LemmyError::from_message("site_ban")); } // Check for user deletion if local_user_view.person.deleted { - return Err(ApiError::err_plain("deleted").into()); + return Err(LemmyError::from_message("deleted")); } check_validator_time(&local_user_view.local_user.validator_time, &claims)?; @@ -131,14 +138,14 @@ pub fn check_validator_time( ) -> Result<(), LemmyError> { let user_validation_time = validator_time.timestamp(); if user_validation_time > claims.iat { - Err(ApiError::err_plain("not_logged_in").into()) + Err(LemmyError::from_message("not_logged_in")) } else { Ok(()) } } pub async fn get_local_user_view_from_jwt_opt( - jwt: &Option, + jwt: Option<&Sensitive>, pool: &DbPool, secret: &Secret, ) -> Result, LemmyError> { @@ -149,12 +156,13 @@ pub async fn get_local_user_view_from_jwt_opt( } pub async fn get_local_user_settings_view_from_jwt( - jwt: &str, + jwt: &Sensitive, pool: &DbPool, secret: &Secret, ) -> Result { - let claims = Claims::decode(jwt, &secret.jwt_secret) - .map_err(|e| ApiError::err("not_logged_in", e))? + let claims = Claims::decode(jwt.as_ref(), &secret.jwt_secret) + .map_err(LemmyError::from) + .map_err(|e| e.with_message("not_logged_in"))? .claims; let local_user_id = LocalUserId(claims.sub); let local_user_view = blocking(pool, move |conn| { @@ -163,7 +171,7 @@ pub async fn get_local_user_settings_view_from_jwt( .await??; // Check for a site ban if local_user_view.person.banned { - return Err(ApiError::err_plain("site_ban").into()); + return Err(LemmyError::from_message("site_ban")); } check_validator_time(&local_user_view.local_user.validator_time, &claims)?; @@ -172,7 +180,7 @@ pub async fn get_local_user_settings_view_from_jwt( } pub async fn get_local_user_settings_view_from_jwt_opt( - jwt: &Option, + jwt: Option<&Sensitive>, pool: &DbPool, secret: &Secret, ) -> Result, LemmyError> { @@ -192,7 +200,7 @@ pub async fn check_community_ban( let is_banned = move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok(); if blocking(pool, is_banned).await? { - Err(ApiError::err_plain("community_ban").into()) + Err(LemmyError::from_message("community_ban")) } else { Ok(()) } @@ -204,9 +212,10 @@ pub async fn check_community_deleted_or_removed( ) -> Result<(), LemmyError> { let community = blocking(pool, move |conn| Community::read(conn, community_id)) .await? - .map_err(|e| ApiError::err("couldnt_find_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community"))?; if community.deleted || community.removed { - Err(ApiError::err_plain("deleted").into()) + Err(LemmyError::from_message("deleted")) } else { Ok(()) } @@ -214,7 +223,7 @@ pub async fn check_community_deleted_or_removed( pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> { if post.deleted || post.removed { - Err(ApiError::err_plain("deleted").into()) + Err(LemmyError::from_message("deleted")) } else { Ok(()) } @@ -227,7 +236,7 @@ pub async fn check_person_block( ) -> Result<(), LemmyError> { let is_blocked = move |conn: &'_ _| PersonBlock::read(conn, potential_blocker_id, my_id).is_ok(); if blocking(pool, is_blocked).await? { - Err(ApiError::err_plain("person_block").into()) + Err(LemmyError::from_message("person_block")) } else { Ok(()) } @@ -237,7 +246,7 @@ pub async fn check_downvotes_enabled(score: i16, pool: &DbPool) -> Result<(), Le if score == -1 { let site = blocking(pool, Site::read_simple).await??; if !site.enable_downvotes { - return Err(ApiError::err_plain("downvotes_disabled").into()); + return Err(LemmyError::from_message("downvotes_disabled")); } } Ok(()) @@ -288,7 +297,7 @@ pub async fn build_federated_instances( /// Checks the password length pub fn password_length_check(pass: &str) -> Result<(), LemmyError> { if !(10..=60).contains(&pass.len()) { - Err(ApiError::err_plain("invalid_password").into()) + Err(LemmyError::from_message("invalid_password")) } else { Ok(()) } @@ -297,7 +306,7 @@ pub fn password_length_check(pass: &str) -> Result<(), LemmyError> { /// Checks the site description length pub fn site_description_length_check(description: &str) -> Result<(), LemmyError> { if description.len() > 150 { - Err(ApiError::err_plain("site_description_length_overflow").into()) + Err(LemmyError::from_message("site_description_length_overflow")) } else { Ok(()) } @@ -306,7 +315,7 @@ pub fn site_description_length_check(description: &str) -> Result<(), LemmyError /// Checks for a honeypot. If this field is filled, fail the rest of the function pub fn honeypot_check(honeypot: &Option) -> Result<(), LemmyError> { if honeypot.is_some() { - Err(ApiError::err_plain("honeypot_fail").into()) + Err(LemmyError::from_message("honeypot_fail")) } else { Ok(()) } diff --git a/crates/api_common/src/person.rs b/crates/api_common/src/person.rs index b93d47ea..5dddc5dc 100644 --- a/crates/api_common/src/person.rs +++ b/crates/api_common/src/person.rs @@ -8,43 +8,44 @@ use lemmy_db_views_actor::{ person_mention_view::PersonMentionView, person_view::PersonViewSafe, }; +use lemmy_utils::Sensitive; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct Login { - pub username_or_email: String, - pub password: String, + pub username_or_email: Sensitive, + pub password: Sensitive, } use lemmy_db_schema::newtypes::{CommunityId, PersonId, PersonMentionId, PrivateMessageId}; -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct Register { pub username: String, - pub password: String, - pub password_verify: String, + pub password: Sensitive, + pub password_verify: Sensitive, pub show_nsfw: bool, - pub email: Option, + pub email: Option>, pub captcha_uuid: Option, pub captcha_answer: Option, pub honeypot: Option, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetCaptcha {} -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetCaptchaResponse { pub ok: Option, // Will be None if captchas are disabled } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct CaptchaResponse { pub png: String, // A Base64 encoded png pub wav: String, // A Base64 encoded wav audio pub uuid: String, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct SaveUserSettings { pub show_nsfw: Option, pub show_scores: Option, @@ -55,7 +56,7 @@ pub struct SaveUserSettings { pub avatar: Option, pub banner: Option, pub display_name: Option, - pub email: Option, + pub email: Option>, pub bio: Option, pub matrix_user_id: Option, pub show_avatars: Option, @@ -64,23 +65,23 @@ pub struct SaveUserSettings { pub show_bot_accounts: Option, pub show_read_posts: Option, pub show_new_post_notifs: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ChangePassword { - pub new_password: String, - pub new_password_verify: String, - pub old_password: String, - pub auth: String, + pub new_password: Sensitive, + pub new_password_verify: Sensitive, + pub old_password: Sensitive, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct LoginResponse { - pub jwt: String, + pub jwt: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetPersonDetails { pub person_id: Option, // One of these two are required /// Example: dessalines , or dessalines@xyz.tld @@ -90,10 +91,10 @@ pub struct GetPersonDetails { pub limit: Option, pub community_id: Option, pub saved_only: Option, - pub auth: Option, + pub auth: Option>, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetPersonDetailsResponse { pub person_view: PersonViewSafe, pub comments: Vec, @@ -101,178 +102,178 @@ pub struct GetPersonDetailsResponse { pub moderates: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetRepliesResponse { pub replies: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetPersonMentionsResponse { pub mentions: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct MarkAllAsRead { - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct AddAdmin { pub person_id: PersonId, pub added: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct AddAdminResponse { pub admins: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct BanPerson { pub person_id: PersonId, pub ban: bool, pub remove_data: Option, pub reason: Option, pub expires: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct BanPersonResponse { pub person_view: PersonViewSafe, pub banned: bool, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct BlockPerson { pub person_id: PersonId, pub block: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct BlockPersonResponse { pub person_view: PersonViewSafe, pub blocked: bool, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetReplies { pub sort: Option, pub page: Option, pub limit: Option, pub unread_only: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetPersonMentions { pub sort: Option, pub page: Option, pub limit: Option, pub unread_only: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct MarkPersonMentionAsRead { pub person_mention_id: PersonMentionId, pub read: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct PersonMentionResponse { pub person_mention_view: PersonMentionView, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct DeleteAccount { - pub password: String, - pub auth: String, + pub password: Sensitive, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct PasswordReset { - pub email: String, + pub email: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct PasswordResetResponse {} -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct PasswordChange { - pub token: String, - pub password: String, - pub password_verify: String, + pub token: Sensitive, + pub password: Sensitive, + pub password_verify: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct CreatePrivateMessage { pub content: String, pub recipient_id: PersonId, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct EditPrivateMessage { pub private_message_id: PrivateMessageId, pub content: String, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct DeletePrivateMessage { pub private_message_id: PrivateMessageId, pub deleted: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct MarkPrivateMessageAsRead { pub private_message_id: PrivateMessageId, pub read: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetPrivateMessages { pub unread_only: Option, pub page: Option, pub limit: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct PrivateMessagesResponse { pub private_messages: Vec, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct PrivateMessageResponse { pub private_message_view: PrivateMessageView, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetReportCount { pub community_id: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct GetReportCountResponse { pub community_id: Option, pub comment_reports: i64, pub post_reports: i64, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetUnreadCount { - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct GetUnreadCountResponse { pub replies: i64, pub mentions: i64, diff --git a/crates/api_common/src/post.rs b/crates/api_common/src/post.rs index 6e2c3179..7f8ea319 100644 --- a/crates/api_common/src/post.rs +++ b/crates/api_common/src/post.rs @@ -8,7 +8,7 @@ use lemmy_db_views_actor::{ community_moderator_view::CommunityModeratorView, community_view::CommunityView, }; -use lemmy_utils::request::SiteMetadata; +use lemmy_utils::{request::SiteMetadata, Sensitive}; use serde::{Deserialize, Serialize}; use url::Url; @@ -20,21 +20,21 @@ pub struct CreatePost { pub body: Option, pub honeypot: Option, pub nsfw: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct PostResponse { pub post_view: PostView, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetPost { pub id: PostId, - pub auth: Option, + pub auth: Option>, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetPostResponse { pub post_view: PostView, pub community_view: CommunityView, @@ -52,7 +52,7 @@ pub struct GetPosts { pub community_id: Option, pub community_name: Option, pub saved_only: Option, - pub auth: Option, + pub auth: Option>, } #[derive(Serialize, Deserialize, Debug)] @@ -60,86 +60,86 @@ pub struct GetPostsResponse { pub posts: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct CreatePostLike { pub post_id: PostId, pub score: i16, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct EditPost { pub post_id: PostId, pub name: Option, pub url: Option, pub body: Option, pub nsfw: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct DeletePost { pub post_id: PostId, pub deleted: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct RemovePost { pub post_id: PostId, pub removed: bool, pub reason: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct MarkPostAsRead { pub post_id: PostId, pub read: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct LockPost { pub post_id: PostId, pub locked: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct StickyPost { pub post_id: PostId, pub stickied: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct SavePost { pub post_id: PostId, pub save: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct CreatePostReport { pub post_id: PostId, pub reason: String, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct PostReportResponse { pub post_report_view: PostReportView, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ResolvePostReport { pub report_id: PostReportId, pub resolved: bool, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ListPostReports { pub page: Option, pub limit: Option, @@ -147,10 +147,10 @@ pub struct ListPostReports { pub unresolved_only: Option, /// if no community is given, it returns reports for all communities moderated by the auth user pub community_id: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ListPostReportsResponse { pub post_reports: Vec, } diff --git a/crates/api_common/src/site.rs b/crates/api_common/src/site.rs index db81fce4..ff53cb51 100644 --- a/crates/api_common/src/site.rs +++ b/crates/api_common/src/site.rs @@ -25,6 +25,7 @@ use lemmy_db_views_moderator::{ mod_sticky_post_view::ModStickyPostView, mod_transfer_community_view::ModTransferCommunityView, }; +use lemmy_utils::Sensitive; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] @@ -38,7 +39,7 @@ pub struct Search { pub listing_type: Option, pub page: Option, pub limit: Option, - pub auth: Option, + pub auth: Option>, } #[derive(Serialize, Deserialize, Debug)] @@ -53,10 +54,10 @@ pub struct SearchResponse { #[derive(Serialize, Deserialize, Debug)] pub struct ResolveObject { pub q: String, - pub auth: Option, + pub auth: Option>, } -#[derive(Serialize, Deserialize, Default)] +#[derive(Debug, Serialize, Deserialize, Default)] pub struct ResolveObjectResponse { pub comment: Option, pub post: Option, @@ -64,7 +65,7 @@ pub struct ResolveObjectResponse { pub person: Option, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetModlog { pub mod_person_id: Option, pub community_id: Option, @@ -72,7 +73,7 @@ pub struct GetModlog { pub limit: Option, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetModlogResponse { pub removed_posts: Vec, pub locked_posts: Vec, @@ -86,7 +87,7 @@ pub struct GetModlogResponse { pub added: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct CreateSite { pub name: String, pub sidebar: Option, @@ -97,10 +98,10 @@ pub struct CreateSite { pub open_registration: Option, pub enable_nsfw: Option, pub community_creation_admin_only: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct EditSite { pub name: Option, pub sidebar: Option, @@ -111,20 +112,20 @@ pub struct EditSite { pub open_registration: Option, pub enable_nsfw: Option, pub community_creation_admin_only: Option, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetSite { - pub auth: Option, + pub auth: Option>, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct SiteResponse { pub site_view: SiteView, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetSiteResponse { pub site_view: Option, // Because the site might not be set up yet pub admins: Vec, @@ -135,7 +136,7 @@ pub struct GetSiteResponse { pub federated_instances: Option, // Federation may be disabled } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct MyUserInfo { pub local_user_view: LocalUserSettingsView, pub follows: Vec, @@ -144,29 +145,29 @@ pub struct MyUserInfo { pub person_blocks: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct TransferSite { pub person_id: PersonId, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetSiteConfig { - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetSiteConfigResponse { pub config_hjson: String, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct SaveSiteConfig { pub config_hjson: String, - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct FederatedInstances { pub linked: Vec, pub allowed: Option>, diff --git a/crates/api_common/src/websocket.rs b/crates/api_common/src/websocket.rs index 5ab94d92..06665512 100644 --- a/crates/api_common/src/websocket.rs +++ b/crates/api_common/src/websocket.rs @@ -1,12 +1,13 @@ use lemmy_db_schema::newtypes::{CommunityId, PostId}; +use lemmy_utils::Sensitive; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] pub struct UserJoin { - pub auth: String, + pub auth: Sensitive, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct UserJoinResponse { pub joined: bool, } @@ -16,7 +17,7 @@ pub struct CommunityJoin { pub community_id: CommunityId, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct CommunityJoinResponse { pub joined: bool, } @@ -26,7 +27,7 @@ pub struct ModJoin { pub community_id: CommunityId, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct ModJoinResponse { pub joined: bool, } @@ -36,7 +37,7 @@ pub struct PostJoin { pub post_id: PostId, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct PostJoinResponse { pub joined: bool, } diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index 025e12c8..1b0289b4 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -30,7 +30,6 @@ use lemmy_db_schema::{ use lemmy_db_views::comment_view::CommentView; use lemmy_utils::{ utils::{remove_slurs, scrape_text_for_mentions}, - ApiError, ConnectionId, LemmyError, }; @@ -44,6 +43,7 @@ use lemmy_websocket::{ impl PerformCrud for CreateComment { type Response = CommentResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -67,7 +67,7 @@ impl PerformCrud for CreateComment { // Check if post is locked, no new comments if post.locked { - return Err(ApiError::err_plain("locked").into()); + return Err(LemmyError::from_message("locked")); } // If there's a parent_id, check to make sure that comment is in that post @@ -75,11 +75,12 @@ impl PerformCrud for CreateComment { // Make sure the parent comment exists let parent = blocking(context.pool(), move |conn| Comment::read(conn, parent_id)) .await? - .map_err(|e| ApiError::err("couldnt_create_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_comment"))?; // Strange issue where sometimes the post ID is incorrect if parent.post_id != post_id { - return Err(ApiError::err_plain("couldnt_create_comment").into()); + return Err(LemmyError::from_message("couldnt_create_comment")); } } @@ -97,7 +98,8 @@ impl PerformCrud for CreateComment { Comment::create(conn, &comment_form2) }) .await? - .map_err(|e| ApiError::err("couldnt_create_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_comment"))?; // Necessary to update the ap_id let inserted_comment_id = inserted_comment.id; @@ -113,7 +115,8 @@ impl PerformCrud for CreateComment { Ok(Comment::update_ap_id(conn, inserted_comment_id, apub_id)?) }) .await? - .map_err(|e| ApiError::err("couldnt_create_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_comment"))?; // Scan the comment for user mentions, add those rows let post_id = post.id; @@ -139,7 +142,8 @@ impl PerformCrud for CreateComment { let like = move |conn: &'_ _| CommentLike::like(conn, &like_form); blocking(context.pool(), like) .await? - .map_err(|e| ApiError::err("couldnt_like_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_like_comment"))?; let apub_comment: ApubComment = updated_comment.into(); CreateOrUpdateComment::send( @@ -174,7 +178,8 @@ impl PerformCrud for CreateComment { Comment::update_read(conn, comment_id, true) }) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment"))?; } // If its a reply, mark the parent as read if let Some(parent_id) = data.parent_id { @@ -187,7 +192,8 @@ impl PerformCrud for CreateComment { Comment::update_read(conn, parent_id, true) }) .await? - .map_err(|e| ApiError::err("couldnt_update_parent_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_parent_comment"))?; } // If the parent has PersonMentions mark them as read too let person_id = local_user_view.person.id; @@ -200,7 +206,8 @@ impl PerformCrud for CreateComment { PersonMention::update_read(conn, mention.id, true) }) .await? - .map_err(|e| ApiError::err("couldnt_update_person_mentions", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_person_mentions"))?; } } diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index 7e920882..84be30fa 100644 --- a/crates/api_crud/src/comment/delete.rs +++ b/crates/api_crud/src/comment/delete.rs @@ -18,7 +18,7 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::comment_view::CommentView; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{ send::{send_comment_ws_message, send_local_notifs}, LemmyContext, @@ -29,6 +29,7 @@ use lemmy_websocket::{ impl PerformCrud for DeleteComment { type Response = CommentResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -46,7 +47,7 @@ impl PerformCrud for DeleteComment { // Dont delete it if its already been deleted. if orig_comment.comment.deleted == data.deleted { - return Err(ApiError::err_plain("couldnt_update_comment").into()); + return Err(LemmyError::from_message("couldnt_update_comment")); } check_community_ban( @@ -58,7 +59,7 @@ impl PerformCrud for DeleteComment { // Verify that only the creator can delete if local_user_view.person.id != orig_comment.creator.id { - return Err(ApiError::err_plain("no_comment_edit_allowed").into()); + return Err(LemmyError::from_message("no_comment_edit_allowed")); } // Do the delete @@ -67,7 +68,8 @@ impl PerformCrud for DeleteComment { Comment::update_deleted(conn, comment_id, deleted) }) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment"))?; let post_id = updated_comment.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -112,6 +114,7 @@ impl PerformCrud for DeleteComment { impl PerformCrud for RemoveComment { type Response = CommentResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -148,7 +151,8 @@ impl PerformCrud for RemoveComment { Comment::update_removed(conn, comment_id, removed) }) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment"))?; // Mod tables let form = ModRemoveCommentForm { diff --git a/crates/api_crud/src/comment/read.rs b/crates/api_crud/src/comment/read.rs index 4789b84f..bd1f475f 100644 --- a/crates/api_crud/src/comment/read.rs +++ b/crates/api_crud/src/comment/read.rs @@ -13,13 +13,14 @@ use lemmy_db_schema::{ SortType, }; use lemmy_db_views::comment_view::{CommentQueryBuilder, CommentView}; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::LemmyContext; #[async_trait::async_trait(?Send)] impl PerformCrud for GetComment { type Response = CommentResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -27,7 +28,8 @@ impl PerformCrud for GetComment { ) -> Result { let data = self; let local_user_view = - get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; + get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret()) + .await?; let person_id = local_user_view.map(|u| u.person.id); let id = data.id; @@ -35,7 +37,8 @@ impl PerformCrud for GetComment { CommentView::read(conn, id, person_id) }) .await? - .map_err(|e| ApiError::err("couldnt_find_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_comment"))?; Ok(Self::Response { comment_view, @@ -49,6 +52,7 @@ impl PerformCrud for GetComment { impl PerformCrud for GetComments { type Response = GetCommentsResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -56,7 +60,8 @@ impl PerformCrud for GetComments { ) -> Result { let data: &GetComments = self; let local_user_view = - get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; + get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret()) + .await?; let show_bot_accounts = local_user_view .as_ref() @@ -91,7 +96,8 @@ impl PerformCrud for GetComments { .list() }) .await? - .map_err(|e| ApiError::err("couldnt_get_comments", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_get_comments"))?; // Blank out deleted or removed info for cv in comments diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs index 7b293792..334181f2 100644 --- a/crates/api_crud/src/comment/update.rs +++ b/crates/api_crud/src/comment/update.rs @@ -16,7 +16,6 @@ use lemmy_db_schema::source::comment::Comment; use lemmy_db_views::comment_view::CommentView; use lemmy_utils::{ utils::{remove_slurs, scrape_text_for_mentions}, - ApiError, ConnectionId, LemmyError, }; @@ -32,6 +31,7 @@ use crate::PerformCrud; impl PerformCrud for EditComment { type Response = CommentResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -59,7 +59,7 @@ impl PerformCrud for EditComment { // Verify that only the creator can edit if local_user_view.person.id != orig_comment.creator.id { - return Err(ApiError::err_plain("no_comment_edit_allowed").into()); + return Err(LemmyError::from_message("no_comment_edit_allowed")); } // Do the update @@ -70,7 +70,8 @@ impl PerformCrud for EditComment { Comment::update_content(conn, comment_id, &content_slurs_removed) }) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment"))?; // Do the mentions / recipients let updated_comment_content = updated_comment.content.to_owned(); diff --git a/crates/api_crud/src/community/create.rs b/crates/api_crud/src/community/create.rs index 19c6fc6b..fb090b86 100644 --- a/crates/api_crud/src/community/create.rs +++ b/crates/api_crud/src/community/create.rs @@ -34,7 +34,6 @@ use lemmy_db_views_actor::community_view::CommunityView; use lemmy_utils::{ apub::generate_actor_keypair, utils::{check_slurs, check_slurs_opt, is_valid_actor_name}, - ApiError, ConnectionId, LemmyError, }; @@ -44,6 +43,7 @@ use lemmy_websocket::LemmyContext; impl PerformCrud for CreateCommunity { type Response = CommunityResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -55,7 +55,9 @@ impl PerformCrud for CreateCommunity { let site = blocking(context.pool(), move |conn| Site::read(conn, 0)).await??; if site.community_creation_admin_only && is_admin(&local_user_view).is_err() { - return Err(ApiError::err_plain("only_admins_can_create_communities").into()); + return Err(LemmyError::from_message( + "only_admins_can_create_communities", + )); } check_slurs(&data.name, &context.settings().slur_regex())?; @@ -63,7 +65,7 @@ impl PerformCrud for CreateCommunity { check_slurs_opt(&data.description, &context.settings().slur_regex())?; if !is_valid_actor_name(&data.name, context.settings().actor_name_max_length) { - return Err(ApiError::err_plain("invalid_community_name").into()); + return Err(LemmyError::from_message("invalid_community_name")); } // Double check for duplicate community actor_ids @@ -75,7 +77,7 @@ impl PerformCrud for CreateCommunity { let community_actor_id_wrapped = ObjectId::::new(community_actor_id.clone()); let community_dupe = community_actor_id_wrapped.dereference_local(context).await; if community_dupe.is_ok() { - return Err(ApiError::err_plain("community_already_exists").into()); + return Err(LemmyError::from_message("community_already_exists")); } // Check to make sure the icon and banners are urls @@ -105,7 +107,8 @@ impl PerformCrud for CreateCommunity { Community::create(conn, &community_form) }) .await? - .map_err(|e| ApiError::err("community_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_already_exists"))?; // The community creator becomes a moderator let community_moderator_form = CommunityModeratorForm { @@ -115,7 +118,9 @@ impl PerformCrud for CreateCommunity { let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); if blocking(context.pool(), join).await?.is_err() { - return Err(ApiError::err_plain("community_moderator_already_exists").into()); + return Err(LemmyError::from_message( + "community_moderator_already_exists", + )); } // Follow your own community @@ -127,7 +132,9 @@ impl PerformCrud for CreateCommunity { let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form); if blocking(context.pool(), follow).await?.is_err() { - return Err(ApiError::err_plain("community_follower_already_exists").into()); + return Err(LemmyError::from_message( + "community_follower_already_exists", + )); } let person_id = local_user_view.person.id; diff --git a/crates/api_crud/src/community/delete.rs b/crates/api_crud/src/community/delete.rs index aec45192..5769bc53 100644 --- a/crates/api_crud/src/community/delete.rs +++ b/crates/api_crud/src/community/delete.rs @@ -10,13 +10,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView; -use lemmy_utils::{utils::naive_from_unix, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{utils::naive_from_unix, ConnectionId, LemmyError}; use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud}; #[async_trait::async_trait(?Send)] impl PerformCrud for DeleteCommunity { type Response = CommunityResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -35,7 +36,7 @@ impl PerformCrud for DeleteCommunity { // Make sure deleter is the top mod if local_user_view.person.id != community_mods[0].moderator.id { - return Err(ApiError::err_plain("no_community_edit_allowed").into()); + return Err(LemmyError::from_message("no_community_edit_allowed")); } // Do the delete @@ -45,7 +46,8 @@ impl PerformCrud for DeleteCommunity { Community::update_deleted(conn, community_id, deleted) }) .await? - .map_err(|e| ApiError::err("couldnt_update_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_community"))?; // Send apub messages send_apub_delete( @@ -72,6 +74,7 @@ impl PerformCrud for DeleteCommunity { impl PerformCrud for RemoveCommunity { type Response = CommunityResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -91,7 +94,8 @@ impl PerformCrud for RemoveCommunity { Community::update_removed(conn, community_id, removed) }) .await? - .map_err(|e| ApiError::err("couldnt_update_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_community"))?; // Mod tables let expires = data.expires.map(naive_from_unix); diff --git a/crates/api_crud/src/community/read.rs b/crates/api_crud/src/community/read.rs index 54f27851..7a6d4354 100644 --- a/crates/api_crud/src/community/read.rs +++ b/crates/api_crud/src/community/read.rs @@ -17,13 +17,14 @@ use lemmy_db_views_actor::{ community_moderator_view::CommunityModeratorView, community_view::{CommunityQueryBuilder, CommunityView}, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{messages::GetCommunityUsersOnline, LemmyContext}; #[async_trait::async_trait(?Send)] impl PerformCrud for GetCommunity { type Response = GetCommunityResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -31,7 +32,8 @@ impl PerformCrud for GetCommunity { ) -> Result { let data: &GetCommunity = self; let local_user_view = - get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; + get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret()) + .await?; let person_id = local_user_view.map(|u| u.person.id); let community_id = match data.id { @@ -45,7 +47,8 @@ impl PerformCrud for GetCommunity { ObjectId::::new(community_actor_id) .dereference(context, &mut 0) .await - .map_err(|e| ApiError::err("couldnt_find_community", e))? + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community"))? .id } }; @@ -54,7 +57,8 @@ impl PerformCrud for GetCommunity { CommunityView::read(conn, community_id, person_id) }) .await? - .map_err(|e| ApiError::err("couldnt_find_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community"))?; // Blank out deleted or removed info for non-logged in users if person_id.is_none() && (community_view.community.deleted || community_view.community.removed) @@ -66,7 +70,8 @@ impl PerformCrud for GetCommunity { CommunityModeratorView::for_community(conn, community_id) }) .await? - .map_err(|e| ApiError::err("couldnt_find_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community"))?; let online = context .chat_server() @@ -89,6 +94,7 @@ impl PerformCrud for GetCommunity { impl PerformCrud for ListCommunities { type Response = ListCommunitiesResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -96,7 +102,8 @@ impl PerformCrud for ListCommunities { ) -> Result { let data: &ListCommunities = self; let local_user_view = - get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; + get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret()) + .await?; let person_id = local_user_view.to_owned().map(|l| l.person.id); diff --git a/crates/api_crud/src/community/update.rs b/crates/api_crud/src/community/update.rs index a4f877d6..324b90eb 100644 --- a/crates/api_crud/src/community/update.rs +++ b/crates/api_crud/src/community/update.rs @@ -14,13 +14,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView; -use lemmy_utils::{utils::check_slurs_opt, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{utils::check_slurs_opt, ConnectionId, LemmyError}; use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud}; #[async_trait::async_trait(?Send)] impl PerformCrud for EditCommunity { type Response = CommunityResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -41,7 +42,7 @@ impl PerformCrud for EditCommunity { }) .await??; if !mods.contains(&local_user_view.person.id) { - return Err(ApiError::err_plain("not_a_moderator").into()); + return Err(LemmyError::from_message("not_a_moderator")); } let community_id = data.community_id; @@ -70,7 +71,8 @@ impl PerformCrud for EditCommunity { Community::update(conn, community_id, &community_form) }) .await? - .map_err(|e| ApiError::err("couldnt_update_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_community"))?; UpdateCommunity::send( updated_community.into(), diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index a4a92f25..bc2f29f7 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -27,7 +27,6 @@ use lemmy_db_schema::{ use lemmy_utils::{ request::fetch_site_data, utils::{check_slurs, check_slurs_opt, clean_url_params, is_valid_post_title}, - ApiError, ConnectionId, LemmyError, }; @@ -40,6 +39,7 @@ use webmention::{Webmention, WebmentionError}; impl PerformCrud for CreatePost { type Response = PostResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -55,7 +55,7 @@ impl PerformCrud for CreatePost { honeypot_check(&data.honeypot)?; if !is_valid_post_title(&data.name) { - return Err(ApiError::err_plain("invalid_post_title").into()); + return Err(LemmyError::from_message("invalid_post_title")); } check_community_ban(local_user_view.person.id, data.community_id, context.pool()).await?; @@ -93,7 +93,7 @@ impl PerformCrud for CreatePost { "couldnt_create_post" }; - return Err(ApiError::err(err_type, e).into()); + return Err(LemmyError::from(e).with_message(err_type)); } }; @@ -108,7 +108,8 @@ impl PerformCrud for CreatePost { Ok(Post::update_ap_id(conn, inserted_post_id, apub_id)?) }) .await? - .map_err(|e| ApiError::err("couldnt_create_post", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_post"))?; // They like their own post by default let person_id = local_user_view.person.id; @@ -121,7 +122,7 @@ impl PerformCrud for CreatePost { let like = move |conn: &'_ _| PostLike::like(conn, &like_form); if blocking(context.pool(), like).await?.is_err() { - return Err(ApiError::err_plain("couldnt_like_post").into()); + return Err(LemmyError::from_message("couldnt_like_post")); } // Mark the post as read diff --git a/crates/api_crud/src/post/delete.rs b/crates/api_crud/src/post/delete.rs index a974feb1..0777153b 100644 --- a/crates/api_crud/src/post/delete.rs +++ b/crates/api_crud/src/post/delete.rs @@ -17,13 +17,14 @@ use lemmy_db_schema::{ }, traits::Crud, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud}; #[async_trait::async_trait(?Send)] impl PerformCrud for DeletePost { type Response = PostResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -38,7 +39,7 @@ impl PerformCrud for DeletePost { // Dont delete it if its already been deleted. if orig_post.deleted == data.deleted { - return Err(ApiError::err_plain("couldnt_update_post").into()); + return Err(LemmyError::from_message("couldnt_update_post")); } check_community_ban( @@ -51,7 +52,7 @@ impl PerformCrud for DeletePost { // Verify that only the creator can delete if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { - return Err(ApiError::err_plain("no_post_edit_allowed").into()); + return Err(LemmyError::from_message("no_post_edit_allowed")); } // Update the post @@ -91,6 +92,7 @@ impl PerformCrud for DeletePost { impl PerformCrud for RemovePost { type Response = PostResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api_crud/src/post/read.rs b/crates/api_crud/src/post/read.rs index 720a18a4..42e84254 100644 --- a/crates/api_crud/src/post/read.rs +++ b/crates/api_crud/src/post/read.rs @@ -20,13 +20,14 @@ use lemmy_db_views_actor::{ community_moderator_view::CommunityModeratorView, community_view::CommunityView, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{messages::GetPostUsersOnline, LemmyContext}; #[async_trait::async_trait(?Send)] impl PerformCrud for GetPost { type Response = GetPostResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -34,7 +35,8 @@ impl PerformCrud for GetPost { ) -> Result { let data: &GetPost = self; let local_user_view = - get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; + get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret()) + .await?; let show_bot_accounts = local_user_view .as_ref() @@ -46,7 +48,8 @@ impl PerformCrud for GetPost { PostView::read(conn, id, person_id) }) .await? - .map_err(|e| ApiError::err("couldnt_find_post", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_post"))?; // Mark the post as read if let Some(person_id) = person_id { @@ -70,7 +73,8 @@ impl PerformCrud for GetPost { CommunityView::read(conn, community_id, person_id) }) .await? - .map_err(|e| ApiError::err("couldnt_find_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community"))?; // Blank out deleted or removed info for non-logged in users if person_id.is_none() { @@ -115,6 +119,7 @@ impl PerformCrud for GetPost { impl PerformCrud for GetPosts { type Response = GetPostsResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -122,7 +127,8 @@ impl PerformCrud for GetPosts { ) -> Result { let data: &GetPosts = self; let local_user_view = - get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; + get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret()) + .await?; let person_id = local_user_view.to_owned().map(|l| l.person.id); @@ -165,7 +171,8 @@ impl PerformCrud for GetPosts { .list() }) .await? - .map_err(|e| ApiError::err("couldnt_get_posts", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_get_posts"))?; // Blank out deleted or removed info for non-logged in users if person_id.is_none() { diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index 2cfc67d4..97dab1cb 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -19,7 +19,6 @@ use lemmy_db_schema::{ use lemmy_utils::{ request::fetch_site_data, utils::{check_slurs_opt, clean_url_params, is_valid_post_title}, - ApiError, ConnectionId, LemmyError, }; @@ -31,6 +30,7 @@ use crate::PerformCrud; impl PerformCrud for EditPost { type Response = PostResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -46,7 +46,7 @@ impl PerformCrud for EditPost { if let Some(name) = &data.name { if !is_valid_post_title(name) { - return Err(ApiError::err_plain("invalid_post_title").into()); + return Err(LemmyError::from_message("invalid_post_title")); } } @@ -63,7 +63,7 @@ impl PerformCrud for EditPost { // Verify that only the creator can edit if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { - return Err(ApiError::err_plain("no_post_edit_allowed").into()); + return Err(LemmyError::from_message("no_post_edit_allowed")); } // Fetch post links and Pictrs cached image @@ -103,7 +103,7 @@ impl PerformCrud for EditPost { "couldnt_update_post" }; - return Err(ApiError::err(err_type, e).into()); + return Err(LemmyError::from(e).with_message(err_type)); } }; diff --git a/crates/api_crud/src/private_message/create.rs b/crates/api_crud/src/private_message/create.rs index 0c637826..ae75d9ea 100644 --- a/crates/api_crud/src/private_message/create.rs +++ b/crates/api_crud/src/private_message/create.rs @@ -19,7 +19,7 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::local_user_view::LocalUserView; -use lemmy_utils::{utils::remove_slurs, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{utils::remove_slurs, ConnectionId, LemmyError}; use lemmy_websocket::{ send::{send_email_to_user, send_pm_ws_message}, LemmyContext, @@ -30,6 +30,7 @@ use lemmy_websocket::{ impl PerformCrud for CreatePrivateMessage { type Response = PrivateMessageResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -58,7 +59,7 @@ impl PerformCrud for CreatePrivateMessage { { Ok(private_message) => private_message, Err(e) => { - return Err(ApiError::err("couldnt_create_private_message", e).into()); + return Err(LemmyError::from(e).with_message("couldnt_create_private_message")); } }; @@ -80,7 +81,8 @@ impl PerformCrud for CreatePrivateMessage { }, ) .await? - .map_err(|e| ApiError::err("couldnt_create_private_message", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_private_message"))?; CreateOrUpdatePrivateMessage::send( updated_private_message.into(), diff --git a/crates/api_crud/src/private_message/delete.rs b/crates/api_crud/src/private_message/delete.rs index 06bc22ed..e28712cf 100644 --- a/crates/api_crud/src/private_message/delete.rs +++ b/crates/api_crud/src/private_message/delete.rs @@ -13,13 +13,14 @@ use lemmy_db_schema::{ source::private_message::PrivateMessage, traits::{Crud, DeleteableOrRemoveable}, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud}; #[async_trait::async_trait(?Send)] impl PerformCrud for DeletePrivateMessage { type Response = PrivateMessageResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -36,7 +37,7 @@ impl PerformCrud for DeletePrivateMessage { }) .await??; if local_user_view.person.id != orig_private_message.creator_id { - return Err(ApiError::err_plain("no_private_message_edit_allowed").into()); + return Err(LemmyError::from_message("no_private_message_edit_allowed")); } // Doing the update @@ -46,7 +47,8 @@ impl PerformCrud for DeletePrivateMessage { PrivateMessage::update_deleted(conn, private_message_id, deleted) }) .await? - .map_err(|e| ApiError::err("couldnt_update_private_message", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_private_message"))?; // Send the apub update if data.deleted { diff --git a/crates/api_crud/src/private_message/read.rs b/crates/api_crud/src/private_message/read.rs index ae2dc203..48ff239c 100644 --- a/crates/api_crud/src/private_message/read.rs +++ b/crates/api_crud/src/private_message/read.rs @@ -14,6 +14,7 @@ use lemmy_websocket::LemmyContext; impl PerformCrud for GetPrivateMessages { type Response = PrivateMessagesResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -21,7 +22,7 @@ impl PerformCrud for GetPrivateMessages { ) -> Result { let data: &GetPrivateMessages = self; let local_user_view = - get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?; + get_local_user_view_from_jwt(data.auth.as_ref(), context.pool(), context.secret()).await?; let person_id = local_user_view.person.id; let page = data.page; diff --git a/crates/api_crud/src/private_message/update.rs b/crates/api_crud/src/private_message/update.rs index 95cc5cb3..83e75687 100644 --- a/crates/api_crud/src/private_message/update.rs +++ b/crates/api_crud/src/private_message/update.rs @@ -10,13 +10,14 @@ use lemmy_apub::protocol::activities::{ CreateOrUpdateType, }; use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud}; -use lemmy_utils::{utils::remove_slurs, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{utils::remove_slurs, ConnectionId, LemmyError}; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud}; #[async_trait::async_trait(?Send)] impl PerformCrud for EditPrivateMessage { type Response = PrivateMessageResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -33,7 +34,7 @@ impl PerformCrud for EditPrivateMessage { }) .await??; if local_user_view.person.id != orig_private_message.creator_id { - return Err(ApiError::err_plain("no_private_message_edit_allowed").into()); + return Err(LemmyError::from_message("no_private_message_edit_allowed")); } // Doing the update @@ -43,7 +44,8 @@ impl PerformCrud for EditPrivateMessage { PrivateMessage::update_content(conn, private_message_id, &content_slurs_removed) }) .await? - .map_err(|e| ApiError::err("couldnt_update_private_message", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_private_message"))?; // Send the apub update CreateOrUpdatePrivateMessage::send( diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs index 865ade77..f638eb7f 100644 --- a/crates/api_crud/src/site/create.rs +++ b/crates/api_crud/src/site/create.rs @@ -16,7 +16,6 @@ use lemmy_db_schema::{ use lemmy_db_views::site_view::SiteView; use lemmy_utils::{ utils::{check_slurs, check_slurs_opt}, - ApiError, ConnectionId, LemmyError, }; @@ -26,6 +25,7 @@ use lemmy_websocket::LemmyContext; impl PerformCrud for CreateSite { type Response = SiteResponse; + #[tracing::instrument(skip(context, _websocket_id))] async fn perform( &self, context: &Data, @@ -35,7 +35,7 @@ impl PerformCrud for CreateSite { let read_site = Site::read_simple; if blocking(context.pool(), read_site).await?.is_ok() { - return Err(ApiError::err_plain("site_already_exists").into()); + return Err(LemmyError::from_message("site_already_exists")); }; let local_user_view = @@ -72,7 +72,7 @@ impl PerformCrud for CreateSite { let create_site = move |conn: &'_ _| Site::create(conn, &site_form); if blocking(context.pool(), create_site).await?.is_err() { - return Err(ApiError::err_plain("site_already_exists").into()); + return Err(LemmyError::from_message("site_already_exists")); } let site_view = blocking(context.pool(), SiteView::read).await??; diff --git a/crates/api_crud/src/site/read.rs b/crates/api_crud/src/site/read.rs index 837acc83..4410d66a 100644 --- a/crates/api_crud/src/site/read.rs +++ b/crates/api_crud/src/site/read.rs @@ -15,7 +15,7 @@ use lemmy_db_views_actor::{ person_block_view::PersonBlockView, person_view::PersonViewSafe, }; -use lemmy_utils::{version, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{version, ConnectionId, LemmyError}; use lemmy_websocket::{messages::GetUsersOnline, LemmyContext}; use tracing::info; @@ -23,6 +23,7 @@ use tracing::info; impl PerformCrud for GetSite { type Response = GetSiteResponse; + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -37,9 +38,9 @@ impl PerformCrud for GetSite { if let Some(setup) = context.settings().setup.as_ref() { let register = Register { username: setup.admin_username.to_owned(), - email: setup.admin_email.to_owned(), - password: setup.admin_password.to_owned(), - password_verify: setup.admin_password.to_owned(), + email: setup.admin_email.clone().map(|s| s.into()), + password: setup.admin_password.clone().into(), + password_verify: setup.admin_password.clone().into(), show_nsfw: true, captcha_uuid: None, captcha_answer: None, @@ -91,36 +92,43 @@ impl PerformCrud for GetSite { .unwrap_or(1); // Build the local user - let my_user = if let Some(local_user_view) = - get_local_user_settings_view_from_jwt_opt(&data.auth, context.pool(), context.secret()) - .await? + let my_user = if let Some(local_user_view) = get_local_user_settings_view_from_jwt_opt( + data.auth.as_ref(), + context.pool(), + context.secret(), + ) + .await? { let person_id = local_user_view.person.id; let follows = blocking(context.pool(), move |conn| { CommunityFollowerView::for_person(conn, person_id) }) .await? - .map_err(|e| ApiError::err("system_err_login", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("system_err_login"))?; let person_id = local_user_view.person.id; let community_blocks = blocking(context.pool(), move |conn| { CommunityBlockView::for_person(conn, person_id) }) .await? - .map_err(|e| ApiError::err("system_err_login", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("system_err_login"))?; let person_id = local_user_view.person.id; let person_blocks = blocking(context.pool(), move |conn| { PersonBlockView::for_person(conn, person_id) }) .await? - .map_err(|e| ApiError::err("system_err_login", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("system_err_login"))?; let moderates = blocking(context.pool(), move |conn| { CommunityModeratorView::for_person(conn, person_id) }) .await? - .map_err(|e| ApiError::err("system_err_login", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("system_err_login"))?; Some(MyUserInfo { local_user_view, diff --git a/crates/api_crud/src/site/update.rs b/crates/api_crud/src/site/update.rs index b6f06e3a..21dc50a2 100644 --- a/crates/api_crud/src/site/update.rs +++ b/crates/api_crud/src/site/update.rs @@ -15,12 +15,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::site_view::SiteView; -use lemmy_utils::{utils::check_slurs_opt, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{utils::check_slurs_opt, ConnectionId, LemmyError}; use lemmy_websocket::{messages::SendAllMessage, LemmyContext, UserOperationCrud}; #[async_trait::async_trait(?Send)] impl PerformCrud for EditSite { type Response = SiteResponse; + + #[tracing::instrument(skip(context, websocket_id))] async fn perform( &self, context: &Data, @@ -64,7 +66,8 @@ impl PerformCrud for EditSite { let update_site = move |conn: &'_ _| Site::update(conn, 1, &site_form); blocking(context.pool(), update_site) .await? - .map_err(|e| ApiError::err("couldnt_update_site", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_site"))?; let site_view = blocking(context.pool(), SiteView::read).await??; diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs index 2ce2fa36..a9ea9861 100644 --- a/crates/api_crud/src/user/create.rs +++ b/crates/api_crud/src/user/create.rs @@ -32,7 +32,6 @@ use lemmy_utils::{ apub::generate_actor_keypair, claims::Claims, utils::{check_slurs, is_valid_actor_name}, - ApiError, ConnectionId, LemmyError, }; @@ -42,6 +41,7 @@ use lemmy_websocket::{messages::CheckCaptcha, LemmyContext}; impl PerformCrud for Register { type Response = LoginResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -52,7 +52,7 @@ impl PerformCrud for Register { // Make sure site has open registration if let Ok(site) = blocking(context.pool(), Site::read_simple).await? { if !site.open_registration { - return Err(ApiError::err_plain("registration_closed").into()); + return Err(LemmyError::from_message("registration_closed")); } } @@ -61,7 +61,7 @@ impl PerformCrud for Register { // Make sure passwords match if data.password != data.password_verify { - return Err(ApiError::err_plain("passwords_dont_match").into()); + return Err(LemmyError::from_message("passwords_dont_match")); } // Check if there are admins. False if admins exist @@ -86,7 +86,7 @@ impl PerformCrud for Register { }) .await?; if !check { - return Err(ApiError::err_plain("captcha_incorrect").into()); + return Err(LemmyError::from_message("captcha_incorrect")); } } @@ -94,7 +94,7 @@ impl PerformCrud for Register { let actor_keypair = generate_actor_keypair()?; if !is_valid_actor_name(&data.username, context.settings().actor_name_max_length) { - return Err(ApiError::err_plain("invalid_username").into()); + return Err(LemmyError::from_message("invalid_username")); } let actor_id = generate_local_apub_endpoint( EndpointType::Person, @@ -121,14 +121,15 @@ impl PerformCrud for Register { Person::create(conn, &person_form) }) .await? - .map_err(|e| ApiError::err("user_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("user_already_exists"))?; // Create the local user // TODO some of these could probably use the DB defaults let local_user_form = LocalUserForm { person_id: inserted_person.id, - email: Some(data.email.to_owned()), - password_encrypted: data.password.to_owned(), + email: Some(data.email.as_deref().map(|s| s.to_owned())), + password_encrypted: data.password.to_string(), show_nsfw: Some(data.show_nsfw), show_bot_accounts: Some(true), theme: Some("browser".into()), @@ -163,7 +164,7 @@ impl PerformCrud for Register { }) .await??; - return Err(ApiError::err(err_type, e).into()); + return Err(LemmyError::from(e).with_message(err_type)); } }; @@ -213,7 +214,8 @@ impl PerformCrud for Register { let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form); blocking(context.pool(), follow) .await? - .map_err(|e| ApiError::err("community_follower_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_follower_already_exists"))?; // If its an admin, add them as a mod and follower to main if no_admins { @@ -225,7 +227,8 @@ impl PerformCrud for Register { let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); blocking(context.pool(), join) .await? - .map_err(|e| ApiError::err("community_moderator_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_moderator_already_exists"))?; } // Return the jwt @@ -234,7 +237,8 @@ impl PerformCrud for Register { inserted_local_user.id.0, &context.secret().jwt_secret, &context.settings().hostname, - )?, + )? + .into(), }) } } diff --git a/crates/api_crud/src/user/delete.rs b/crates/api_crud/src/user/delete.rs index 28f42831..0400ffe0 100644 --- a/crates/api_crud/src/user/delete.rs +++ b/crates/api_crud/src/user/delete.rs @@ -3,13 +3,14 @@ use actix_web::web::Data; use bcrypt::verify; use lemmy_api_common::{blocking, get_local_user_view_from_jwt, person::*}; use lemmy_db_schema::source::{comment::Comment, person::Person, post::Post}; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::LemmyContext; #[async_trait::async_trait(?Send)] impl PerformCrud for DeleteAccount { type Response = LoginResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -17,7 +18,7 @@ impl PerformCrud for DeleteAccount { ) -> Result { let data: &DeleteAccount = self; let local_user_view = - get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?; + get_local_user_view_from_jwt(data.auth.as_ref(), context.pool(), context.secret()).await?; // Verify the password let valid: bool = verify( @@ -26,7 +27,7 @@ impl PerformCrud for DeleteAccount { ) .unwrap_or(false); if !valid { - return Err(ApiError::err_plain("password_incorrect").into()); + return Err(LemmyError::from_message("password_incorrect")); } // Comments @@ -34,13 +35,15 @@ impl PerformCrud for DeleteAccount { let permadelete = move |conn: &'_ _| Comment::permadelete_for_creator(conn, person_id); blocking(context.pool(), permadelete) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment"))?; // Posts let permadelete = move |conn: &'_ _| Post::permadelete_for_creator(conn, person_id); blocking(context.pool(), permadelete) .await? - .map_err(|e| ApiError::err("couldnt_update_post", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_post"))?; blocking(context.pool(), move |conn| { Person::delete_account(conn, person_id) @@ -48,7 +51,7 @@ impl PerformCrud for DeleteAccount { .await??; Ok(LoginResponse { - jwt: data.auth.to_owned(), + jwt: data.auth.clone(), }) } } diff --git a/crates/api_crud/src/user/read.rs b/crates/api_crud/src/user/read.rs index e2084860..b63d95c8 100644 --- a/crates/api_crud/src/user/read.rs +++ b/crates/api_crud/src/user/read.rs @@ -13,13 +13,14 @@ use lemmy_db_views_actor::{ community_moderator_view::CommunityModeratorView, person_view::PersonViewSafe, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::LemmyContext; #[async_trait::async_trait(?Send)] impl PerformCrud for GetPersonDetails { type Response = GetPersonDetailsResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -27,7 +28,8 @@ impl PerformCrud for GetPersonDetails { ) -> Result { let data: &GetPersonDetails = self; let local_user_view = - get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; + get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret()) + .await?; let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw); let show_bot_accounts = local_user_view @@ -53,7 +55,8 @@ impl PerformCrud for GetPersonDetails { .dereference(context, &mut 0) .await; person - .map_err(|e| ApiError::err("couldnt_find_that_username_or_email", e))? + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_that_username_or_email"))? .id } }; diff --git a/crates/apub/src/activities/comment/create_or_update.rs b/crates/apub/src/activities/comment/create_or_update.rs index 649f566c..3b1ee393 100644 --- a/crates/apub/src/activities/comment/create_or_update.rs +++ b/crates/apub/src/activities/comment/create_or_update.rs @@ -28,6 +28,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperationCrud}; impl CreateOrUpdateComment { + #[tracing::instrument(skip(comment, actor, kind, context))] pub async fn send( comment: ApubComment, actor: &ApubPerson, @@ -83,6 +84,7 @@ impl CreateOrUpdateComment { impl ActivityHandler for CreateOrUpdateComment { type DataType = LemmyContext; + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -102,6 +104,7 @@ impl ActivityHandler for CreateOrUpdateComment { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, @@ -131,6 +134,7 @@ impl ActivityHandler for CreateOrUpdateComment { #[async_trait::async_trait(?Send)] impl GetCommunity for CreateOrUpdateComment { + #[tracing::instrument(skip_all)] async fn get_community( &self, context: &LemmyContext, diff --git a/crates/apub/src/activities/comment/mod.rs b/crates/apub/src/activities/comment/mod.rs index 17b4f50c..29c24952 100644 --- a/crates/apub/src/activities/comment/mod.rs +++ b/crates/apub/src/activities/comment/mod.rs @@ -11,6 +11,7 @@ use lemmy_websocket::{send::send_local_notifs, LemmyContext}; pub mod create_or_update; +#[tracing::instrument(skip_all)] async fn get_notif_recipients( actor: &ObjectId, comment: &Comment, diff --git a/crates/apub/src/activities/community/add_mod.rs b/crates/apub/src/activities/community/add_mod.rs index c244f652..3daedaa2 100644 --- a/crates/apub/src/activities/community/add_mod.rs +++ b/crates/apub/src/activities/community/add_mod.rs @@ -32,6 +32,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; impl AddMod { + #[tracing::instrument(skip_all)] pub async fn send( community: &ApubCommunity, added_mod: &ApubPerson, @@ -63,6 +64,7 @@ impl AddMod { impl ActivityHandler for AddMod { type DataType = LemmyContext; + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -77,6 +79,7 @@ impl ActivityHandler for AddMod { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, @@ -109,6 +112,7 @@ impl ActivityHandler for AddMod { #[async_trait::async_trait(?Send)] impl GetCommunity for AddMod { + #[tracing::instrument(skip_all)] async fn get_community( &self, context: &LemmyContext, diff --git a/crates/apub/src/activities/community/announce.rs b/crates/apub/src/activities/community/announce.rs index cc30a89f..0ece90b7 100644 --- a/crates/apub/src/activities/community/announce.rs +++ b/crates/apub/src/activities/community/announce.rs @@ -44,6 +44,7 @@ impl AnnounceActivity { }) } + #[tracing::instrument(skip_all)] pub async fn send( object: AnnouncableActivities, community: &ApubCommunity, @@ -85,6 +86,8 @@ impl AnnounceActivity { #[async_trait::async_trait(?Send)] impl ActivityHandler for AnnounceActivity { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -96,6 +99,7 @@ impl ActivityHandler for AnnounceActivity { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, diff --git a/crates/apub/src/activities/community/block_user.rs b/crates/apub/src/activities/community/block_user.rs index 0442fcc4..140b9a86 100644 --- a/crates/apub/src/activities/community/block_user.rs +++ b/crates/apub/src/activities/community/block_user.rs @@ -52,6 +52,7 @@ impl BlockUserFromCommunity { }) } + #[tracing::instrument(skip_all)] pub async fn send( community: &ApubCommunity, target: &ApubPerson, @@ -70,6 +71,8 @@ impl BlockUserFromCommunity { #[async_trait::async_trait(?Send)] impl ActivityHandler for BlockUserFromCommunity { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -83,6 +86,7 @@ impl ActivityHandler for BlockUserFromCommunity { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, @@ -119,6 +123,7 @@ impl ActivityHandler for BlockUserFromCommunity { #[async_trait::async_trait(?Send)] impl GetCommunity for BlockUserFromCommunity { + #[tracing::instrument(skip_all)] async fn get_community( &self, context: &LemmyContext, diff --git a/crates/apub/src/activities/community/mod.rs b/crates/apub/src/activities/community/mod.rs index 23f8f8e3..5961fa04 100644 --- a/crates/apub/src/activities/community/mod.rs +++ b/crates/apub/src/activities/community/mod.rs @@ -17,6 +17,7 @@ pub mod report; pub mod undo_block_user; pub mod update; +#[tracing::instrument(skip_all)] pub(crate) async fn send_activity_in_community( activity: AnnouncableActivities, activity_id: &Url, @@ -35,6 +36,7 @@ pub(crate) async fn send_activity_in_community( Ok(()) } +#[tracing::instrument(skip_all)] async fn get_community_from_moderators_url( moderators: &Url, context: &LemmyContext, diff --git a/crates/apub/src/activities/community/remove_mod.rs b/crates/apub/src/activities/community/remove_mod.rs index 36312070..b6a565f1 100644 --- a/crates/apub/src/activities/community/remove_mod.rs +++ b/crates/apub/src/activities/community/remove_mod.rs @@ -32,6 +32,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; impl RemoveMod { + #[tracing::instrument(skip_all)] pub async fn send( community: &ApubCommunity, removed_mod: &ApubPerson, @@ -62,6 +63,8 @@ impl RemoveMod { #[async_trait::async_trait(?Send)] impl ActivityHandler for RemoveMod { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -76,6 +79,7 @@ impl ActivityHandler for RemoveMod { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, @@ -99,6 +103,7 @@ impl ActivityHandler for RemoveMod { #[async_trait::async_trait(?Send)] impl GetCommunity for RemoveMod { + #[tracing::instrument(skip_all)] async fn get_community( &self, context: &LemmyContext, diff --git a/crates/apub/src/activities/community/report.rs b/crates/apub/src/activities/community/report.rs index 7207af61..35a42667 100644 --- a/crates/apub/src/activities/community/report.rs +++ b/crates/apub/src/activities/community/report.rs @@ -28,6 +28,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation}; impl Report { + #[tracing::instrument(skip_all)] pub async fn send( object_id: ObjectId, actor: &ApubPerson, @@ -65,6 +66,8 @@ impl Report { #[async_trait::async_trait(?Send)] impl ActivityHandler for Report { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -76,6 +79,7 @@ impl ActivityHandler for Report { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, diff --git a/crates/apub/src/activities/community/undo_block_user.rs b/crates/apub/src/activities/community/undo_block_user.rs index dbd6c5d5..2a7a2b15 100644 --- a/crates/apub/src/activities/community/undo_block_user.rs +++ b/crates/apub/src/activities/community/undo_block_user.rs @@ -29,6 +29,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; impl UndoBlockUserFromCommunity { + #[tracing::instrument(skip_all)] pub async fn send( community: &ApubCommunity, target: &ApubPerson, @@ -60,6 +61,8 @@ impl UndoBlockUserFromCommunity { #[async_trait::async_trait(?Send)] impl ActivityHandler for UndoBlockUserFromCommunity { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -74,6 +77,7 @@ impl ActivityHandler for UndoBlockUserFromCommunity { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, @@ -102,6 +106,7 @@ impl ActivityHandler for UndoBlockUserFromCommunity { #[async_trait::async_trait(?Send)] impl GetCommunity for UndoBlockUserFromCommunity { + #[tracing::instrument(skip_all)] async fn get_community( &self, context: &LemmyContext, diff --git a/crates/apub/src/activities/community/update.rs b/crates/apub/src/activities/community/update.rs index 7b2af3c4..e1c39241 100644 --- a/crates/apub/src/activities/community/update.rs +++ b/crates/apub/src/activities/community/update.rs @@ -26,6 +26,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud}; impl UpdateCommunity { + #[tracing::instrument(skip_all)] pub async fn send( community: ApubCommunity, actor: &ApubPerson, @@ -53,6 +54,8 @@ impl UpdateCommunity { #[async_trait::async_trait(?Send)] impl ActivityHandler for UpdateCommunity { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -73,6 +76,7 @@ impl ActivityHandler for UpdateCommunity { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, @@ -110,6 +114,7 @@ impl ActivityHandler for UpdateCommunity { #[async_trait::async_trait(?Send)] impl GetCommunity for UpdateCommunity { + #[tracing::instrument(skip_all)] async fn get_community( &self, context: &LemmyContext, diff --git a/crates/apub/src/activities/deletion/delete.rs b/crates/apub/src/activities/deletion/delete.rs index e50cfd85..9f53a8bf 100644 --- a/crates/apub/src/activities/deletion/delete.rs +++ b/crates/apub/src/activities/deletion/delete.rs @@ -11,7 +11,6 @@ use crate::{ protocol::activities::deletion::delete::Delete, }; use activitystreams_kinds::{activity::DeleteType, public}; -use anyhow::anyhow; use lemmy_api_common::blocking; use lemmy_apub_lib::{ data::Data, @@ -45,6 +44,8 @@ use url::Url; #[async_trait::async_trait(?Send)] impl ActivityHandler for Delete { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -65,6 +66,7 @@ impl ActivityHandler for Delete { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, @@ -112,6 +114,8 @@ impl Delete { unparsed: Default::default(), }) } + + #[tracing::instrument(skip_all)] pub(in crate::activities::deletion) async fn send( actor: &ApubPerson, community: &ApubCommunity, @@ -127,6 +131,7 @@ impl Delete { } } +#[tracing::instrument(skip_all)] pub(in crate::activities) async fn receive_remove_action( actor: &ObjectId, object: &Url, @@ -139,7 +144,9 @@ pub(in crate::activities) async fn receive_remove_action( match DeletableObjects::read_from_db(object, context).await? { DeletableObjects::Community(community) => { if community.local { - return Err(anyhow!("Only local admin can remove community").into()); + return Err(LemmyError::from_message( + "Only local admin can remove community", + )); } let form = ModRemoveCommunityForm { mod_person_id: actor.id, @@ -201,6 +208,7 @@ pub(in crate::activities) async fn receive_remove_action( #[async_trait::async_trait(?Send)] impl GetCommunity for Delete { + #[tracing::instrument(skip_all)] async fn get_community( &self, context: &LemmyContext, diff --git a/crates/apub/src/activities/deletion/mod.rs b/crates/apub/src/activities/deletion/mod.rs index ab2e7a0b..a9c72a3a 100644 --- a/crates/apub/src/activities/deletion/mod.rs +++ b/crates/apub/src/activities/deletion/mod.rs @@ -20,6 +20,7 @@ use url::Url; pub mod delete; pub mod undo_delete; +#[tracing::instrument(skip_all)] pub async fn send_apub_delete( actor: &ApubPerson, community: &ApubCommunity, @@ -36,6 +37,7 @@ pub async fn send_apub_delete( // TODO: remove reason is actually optional in lemmy. we set an empty string in that case, but its // ugly +#[tracing::instrument(skip_all)] pub async fn send_apub_remove( actor: &ApubPerson, community: &ApubCommunity, @@ -58,6 +60,7 @@ pub enum DeletableObjects { } impl DeletableObjects { + #[tracing::instrument(skip_all)] pub(crate) async fn read_from_db( ap_id: &Url, context: &LemmyContext, @@ -83,6 +86,7 @@ impl DeletableObjects { } } +#[tracing::instrument(skip_all)] pub(in crate::activities) async fn verify_delete_activity( object: &Url, actor: &ObjectId, @@ -128,6 +132,7 @@ pub(in crate::activities) async fn verify_delete_activity( Ok(()) } +#[tracing::instrument(skip_all)] async fn verify_delete_activity_post_or_comment( actor: &ObjectId, object_id: &Url, @@ -149,6 +154,7 @@ async fn verify_delete_activity_post_or_comment( /// Write deletion or restoring of an object to the database, and send websocket message. /// TODO: we should do something similar for receive_remove_action(), but its much more complicated /// because of the mod log +#[tracing::instrument(skip_all)] async fn receive_delete_action( object: &Url, actor: &ObjectId, diff --git a/crates/apub/src/activities/deletion/undo_delete.rs b/crates/apub/src/activities/deletion/undo_delete.rs index 8a867fbc..167f8961 100644 --- a/crates/apub/src/activities/deletion/undo_delete.rs +++ b/crates/apub/src/activities/deletion/undo_delete.rs @@ -11,7 +11,6 @@ use crate::{ protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete}, }; use activitystreams_kinds::{activity::UndoType, public}; -use anyhow::anyhow; use lemmy_api_common::blocking; use lemmy_apub_lib::{ data::Data, @@ -30,6 +29,8 @@ use url::Url; #[async_trait::async_trait(?Send)] impl ActivityHandler for UndoDelete { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -51,6 +52,7 @@ impl ActivityHandler for UndoDelete { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, @@ -72,6 +74,7 @@ impl ActivityHandler for UndoDelete { } impl UndoDelete { + #[tracing::instrument(skip_all)] pub(in crate::activities::deletion) async fn send( actor: &ApubPerson, community: &ApubCommunity, @@ -99,6 +102,7 @@ impl UndoDelete { send_activity_in_community(activity, &id, actor, community, vec![], context).await } + #[tracing::instrument(skip_all)] pub(in crate::activities) async fn receive_undo_remove_action( object: &Url, context: &LemmyContext, @@ -107,7 +111,9 @@ impl UndoDelete { match DeletableObjects::read_from_db(object, context).await? { DeletableObjects::Community(community) => { if community.local { - return Err(anyhow!("Only local admin can restore community").into()); + return Err(LemmyError::from_message( + "Only local admin can restore community", + )); } let deleted_community = blocking(context.pool(), move |conn| { Community::update_removed(conn, community.id, false) @@ -136,6 +142,7 @@ impl UndoDelete { #[async_trait::async_trait(?Send)] impl GetCommunity for UndoDelete { + #[tracing::instrument(skip_all)] async fn get_community( &self, context: &LemmyContext, diff --git a/crates/apub/src/activities/following/accept.rs b/crates/apub/src/activities/following/accept.rs index 6febd7d4..a45dcf3c 100644 --- a/crates/apub/src/activities/following/accept.rs +++ b/crates/apub/src/activities/following/accept.rs @@ -15,6 +15,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; impl AcceptFollowCommunity { + #[tracing::instrument(skip_all)] pub async fn send( follow: FollowCommunity, context: &LemmyContext, @@ -45,6 +46,8 @@ impl AcceptFollowCommunity { #[async_trait::async_trait(?Send)] impl ActivityHandler for AcceptFollowCommunity { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -56,6 +59,7 @@ impl ActivityHandler for AcceptFollowCommunity { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, diff --git a/crates/apub/src/activities/following/follow.rs b/crates/apub/src/activities/following/follow.rs index a5c2e77f..877df61f 100644 --- a/crates/apub/src/activities/following/follow.rs +++ b/crates/apub/src/activities/following/follow.rs @@ -40,6 +40,8 @@ impl FollowCommunity { unparsed: Default::default(), }) } + + #[tracing::instrument(skip_all)] pub async fn send( actor: &ApubPerson, community: &ApubCommunity, @@ -64,6 +66,8 @@ impl FollowCommunity { #[async_trait::async_trait(?Send)] impl ActivityHandler for FollowCommunity { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -76,6 +80,7 @@ impl ActivityHandler for FollowCommunity { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, diff --git a/crates/apub/src/activities/following/undo_follow.rs b/crates/apub/src/activities/following/undo_follow.rs index c7b926a2..8644cbc5 100644 --- a/crates/apub/src/activities/following/undo_follow.rs +++ b/crates/apub/src/activities/following/undo_follow.rs @@ -19,6 +19,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; impl UndoFollowCommunity { + #[tracing::instrument(skip_all)] pub async fn send( actor: &ApubPerson, community: &ApubCommunity, @@ -43,6 +44,8 @@ impl UndoFollowCommunity { #[async_trait::async_trait(?Send)] impl ActivityHandler for UndoFollowCommunity { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -55,6 +58,7 @@ impl ActivityHandler for UndoFollowCommunity { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index 1a3d01bb..8a4c4ffe 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -6,7 +6,6 @@ use crate::{ objects::{community::ApubCommunity, person::ApubPerson}, }; use activitystreams_kinds::public; -use anyhow::anyhow; use lemmy_api_common::blocking; use lemmy_apub_lib::{ activity_queue::send_activity, @@ -36,6 +35,7 @@ pub mod voting; /// Checks that the specified Url actually identifies a Person (by fetching it), and that the person /// doesn't have a site ban. +#[tracing::instrument(skip_all)] async fn verify_person( person_id: &ObjectId, context: &LemmyContext, @@ -43,13 +43,15 @@ async fn verify_person( ) -> Result<(), LemmyError> { let person = person_id.dereference(context, request_counter).await?; if person.banned { - return Err(anyhow!("Person {} is banned", person_id).into()); + let error = LemmyError::from(anyhow::anyhow!("Person {} is banned", person_id)); + return Err(error.with_message("banned")); } Ok(()) } /// Fetches the person and community to verify their type, then checks if person is banned from site /// or community. +#[tracing::instrument(skip_all)] pub(crate) async fn verify_person_in_community( person_id: &ObjectId, community: &ApubCommunity, @@ -58,14 +60,14 @@ pub(crate) async fn verify_person_in_community( ) -> Result<(), LemmyError> { let person = person_id.dereference(context, request_counter).await?; if person.banned { - return Err(anyhow!("Person is banned from site").into()); + return Err(LemmyError::from_message("Person is banned from site")); } let person_id = person.id; let community_id = community.id; let is_banned = move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok(); if blocking(context.pool(), is_banned).await? { - return Err(anyhow!("Person is banned from community").into()); + return Err(LemmyError::from_message("Person is banned from community")); } Ok(()) @@ -80,6 +82,7 @@ fn verify_activity(id: &Url, actor: &Url, settings: &Settings) -> Result<(), Lem /// Verify that the actor is a community mod. This check is only run if the community is local, /// because in case of remote communities, admins can also perform mod actions. As admin status /// is not federated, we cant verify their actions remotely. +#[tracing::instrument(skip_all)] pub(crate) async fn verify_mod_action( actor_id: &ObjectId, community: &ApubCommunity, @@ -98,7 +101,7 @@ pub(crate) async fn verify_mod_action( }) .await?; if !is_mod_or_admin { - return Err(anyhow!("Not a mod").into()); + return Err(LemmyError::from_message("Not a mod")); } } Ok(()) @@ -111,21 +114,23 @@ fn verify_add_remove_moderator_target( community: &ApubCommunity, ) -> Result<(), LemmyError> { if target != &generate_moderators_url(&community.actor_id)?.into() { - return Err(anyhow!("Unkown target url").into()); + return Err(LemmyError::from_message("Unkown target url")); } Ok(()) } pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> Result<(), LemmyError> { if ![to, cc].iter().any(|set| set.contains(&public())) { - return Err(anyhow!("Object is not public").into()); + return Err(LemmyError::from_message("Object is not public")); } Ok(()) } pub(crate) fn check_community_deleted_or_removed(community: &Community) -> Result<(), LemmyError> { if community.deleted || community.removed { - Err(anyhow!("New post or comment cannot be created in deleted or removed community").into()) + Err(LemmyError::from_message( + "New post or comment cannot be created in deleted or removed community", + )) } else { Ok(()) } @@ -146,6 +151,7 @@ where Url::parse(&id) } +#[tracing::instrument(skip_all)] async fn send_lemmy_activity( context: &LemmyContext, activity: &T, diff --git a/crates/apub/src/activities/post/create_or_update.rs b/crates/apub/src/activities/post/create_or_update.rs index 2e9c8071..24263776 100644 --- a/crates/apub/src/activities/post/create_or_update.rs +++ b/crates/apub/src/activities/post/create_or_update.rs @@ -13,7 +13,6 @@ use crate::{ protocol::activities::{create_or_update::post::CreateOrUpdatePost, CreateOrUpdateType}, }; use activitystreams_kinds::public; -use anyhow::anyhow; use lemmy_api_common::blocking; use lemmy_apub_lib::{ data::Data, @@ -47,6 +46,8 @@ impl CreateOrUpdatePost { unparsed: Default::default(), }) } + + #[tracing::instrument(skip_all)] pub async fn send( post: ApubPost, actor: &ApubPerson, @@ -70,6 +71,8 @@ impl CreateOrUpdatePost { #[async_trait::async_trait(?Send)] impl ActivityHandler for CreateOrUpdatePost { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -92,7 +95,9 @@ impl ActivityHandler for CreateOrUpdatePost { let is_stickied_or_locked = self.object.stickied == Some(true) || self.object.comments_enabled == Some(false); if community.local && is_stickied_or_locked { - return Err(anyhow!("New post cannot be stickied or locked").into()); + return Err(LemmyError::from_message( + "New post cannot be stickied or locked", + )); } } CreateOrUpdateType::Update => { @@ -109,6 +114,7 @@ impl ActivityHandler for CreateOrUpdatePost { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, @@ -127,6 +133,7 @@ impl ActivityHandler for CreateOrUpdatePost { #[async_trait::async_trait(?Send)] impl GetCommunity for CreateOrUpdatePost { + #[tracing::instrument(skip_all)] async fn get_community( &self, context: &LemmyContext, diff --git a/crates/apub/src/activities/private_message/create_or_update.rs b/crates/apub/src/activities/private_message/create_or_update.rs index e3d72f54..3374f224 100644 --- a/crates/apub/src/activities/private_message/create_or_update.rs +++ b/crates/apub/src/activities/private_message/create_or_update.rs @@ -18,6 +18,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud}; impl CreateOrUpdatePrivateMessage { + #[tracing::instrument(skip_all)] pub async fn send( private_message: ApubPrivateMessage, actor: &ApubPerson, @@ -46,9 +47,12 @@ impl CreateOrUpdatePrivateMessage { send_lemmy_activity(context, &create_or_update, &id, actor, inbox, true).await } } + #[async_trait::async_trait(?Send)] impl ActivityHandler for CreateOrUpdatePrivateMessage { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -61,6 +65,7 @@ impl ActivityHandler for CreateOrUpdatePrivateMessage { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, diff --git a/crates/apub/src/activities/private_message/delete.rs b/crates/apub/src/activities/private_message/delete.rs index 7269078a..af81db0e 100644 --- a/crates/apub/src/activities/private_message/delete.rs +++ b/crates/apub/src/activities/private_message/delete.rs @@ -36,6 +36,8 @@ impl DeletePrivateMessage { unparsed: Default::default(), }) } + + #[tracing::instrument(skip_all)] pub async fn send( actor: &ApubPerson, pm: &ApubPrivateMessage, @@ -57,6 +59,8 @@ impl DeletePrivateMessage { #[async_trait::async_trait(?Send)] impl ActivityHandler for DeletePrivateMessage { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -68,6 +72,7 @@ impl ActivityHandler for DeletePrivateMessage { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, diff --git a/crates/apub/src/activities/private_message/undo_delete.rs b/crates/apub/src/activities/private_message/undo_delete.rs index ce3cc49c..dbd84bd5 100644 --- a/crates/apub/src/activities/private_message/undo_delete.rs +++ b/crates/apub/src/activities/private_message/undo_delete.rs @@ -22,6 +22,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud}; impl UndoDeletePrivateMessage { + #[tracing::instrument(skip_all)] pub async fn send( actor: &ApubPerson, pm: &ApubPrivateMessage, @@ -54,6 +55,8 @@ impl UndoDeletePrivateMessage { #[async_trait::async_trait(?Send)] impl ActivityHandler for UndoDeletePrivateMessage { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -67,6 +70,7 @@ impl ActivityHandler for UndoDeletePrivateMessage { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, diff --git a/crates/apub/src/activities/voting/mod.rs b/crates/apub/src/activities/voting/mod.rs index 0a2a8fd1..c82b4efd 100644 --- a/crates/apub/src/activities/voting/mod.rs +++ b/crates/apub/src/activities/voting/mod.rs @@ -21,6 +21,7 @@ use crate::{ pub mod undo_vote; pub mod vote; +#[tracing::instrument(skip_all)] async fn vote_comment( vote_type: &VoteType, actor: ApubPerson, @@ -45,6 +46,7 @@ async fn vote_comment( Ok(()) } +#[tracing::instrument(skip_all)] async fn vote_post( vote_type: &VoteType, actor: ApubPerson, @@ -68,6 +70,7 @@ async fn vote_post( Ok(()) } +#[tracing::instrument(skip_all)] async fn undo_vote_comment( actor: ApubPerson, comment: &ApubComment, @@ -84,6 +87,7 @@ async fn undo_vote_comment( Ok(()) } +#[tracing::instrument(skip_all)] async fn undo_vote_post( actor: ApubPerson, post: &ApubPost, diff --git a/crates/apub/src/activities/voting/undo_vote.rs b/crates/apub/src/activities/voting/undo_vote.rs index f913ce5f..3e840391 100644 --- a/crates/apub/src/activities/voting/undo_vote.rs +++ b/crates/apub/src/activities/voting/undo_vote.rs @@ -28,6 +28,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; impl UndoVote { + #[tracing::instrument(skip_all)] pub async fn send( object: &PostOrComment, actor: &ApubPerson, @@ -63,6 +64,8 @@ impl UndoVote { #[async_trait::async_trait(?Send)] impl ActivityHandler for UndoVote { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -77,6 +80,7 @@ impl ActivityHandler for UndoVote { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, @@ -97,6 +101,7 @@ impl ActivityHandler for UndoVote { #[async_trait::async_trait(?Send)] impl GetCommunity for UndoVote { + #[tracing::instrument(skip_all)] async fn get_community( &self, context: &LemmyContext, diff --git a/crates/apub/src/activities/voting/vote.rs b/crates/apub/src/activities/voting/vote.rs index 65a92800..283b0435 100644 --- a/crates/apub/src/activities/voting/vote.rs +++ b/crates/apub/src/activities/voting/vote.rs @@ -46,6 +46,7 @@ impl Vote { }) } + #[tracing::instrument(skip_all)] pub async fn send( object: &PostOrComment, actor: &ApubPerson, @@ -69,6 +70,8 @@ impl Vote { #[async_trait::async_trait(?Send)] impl ActivityHandler for Vote { type DataType = LemmyContext; + + #[tracing::instrument(skip_all)] async fn verify( &self, context: &Data, @@ -81,6 +84,7 @@ impl ActivityHandler for Vote { Ok(()) } + #[tracing::instrument(skip_all)] async fn receive( self, context: &Data, @@ -97,6 +101,7 @@ impl ActivityHandler for Vote { #[async_trait::async_trait(?Send)] impl GetCommunity for Vote { + #[tracing::instrument(skip_all)] async fn get_community( &self, context: &LemmyContext, diff --git a/crates/apub/src/activity_lists.rs b/crates/apub/src/activity_lists.rs index d9b97649..0512ed62 100644 --- a/crates/apub/src/activity_lists.rs +++ b/crates/apub/src/activity_lists.rs @@ -88,6 +88,7 @@ pub enum AnnouncableActivities { #[async_trait::async_trait(?Send)] impl GetCommunity for AnnouncableActivities { + #[tracing::instrument(skip(self, context))] async fn get_community( &self, context: &LemmyContext, diff --git a/crates/apub/src/collections/community_moderators.rs b/crates/apub/src/collections/community_moderators.rs index 9b8d26d9..1f761917 100644 --- a/crates/apub/src/collections/community_moderators.rs +++ b/crates/apub/src/collections/community_moderators.rs @@ -29,6 +29,7 @@ impl ApubObject for ApubCommunityModerators { None } + #[tracing::instrument(skip_all)] async fn read_from_apub_id( _object_id: Url, data: &Self::DataType, @@ -46,10 +47,12 @@ impl ApubObject for ApubCommunityModerators { } } + #[tracing::instrument(skip_all)] async fn delete(self, _data: &Self::DataType) -> Result<(), LemmyError> { unimplemented!() } + #[tracing::instrument(skip_all)] async fn into_apub(self, data: &Self::DataType) -> Result { let ordered_items = self .0 @@ -67,6 +70,7 @@ impl ApubObject for ApubCommunityModerators { unimplemented!() } + #[tracing::instrument(skip_all)] async fn verify( group_moderators: &GroupModerators, expected_domain: &Url, @@ -77,6 +81,7 @@ impl ApubObject for ApubCommunityModerators { Ok(()) } + #[tracing::instrument(skip_all)] async fn from_apub( apub: Self::ApubType, data: &Self::DataType, diff --git a/crates/apub/src/collections/community_outbox.rs b/crates/apub/src/collections/community_outbox.rs index de55ffa6..eaa9acd9 100644 --- a/crates/apub/src/collections/community_outbox.rs +++ b/crates/apub/src/collections/community_outbox.rs @@ -33,6 +33,7 @@ impl ApubObject for ApubCommunityOutbox { None } + #[tracing::instrument(skip_all)] async fn read_from_apub_id( _object_id: Url, data: &Self::DataType, @@ -58,6 +59,7 @@ impl ApubObject for ApubCommunityOutbox { Ok(()) } + #[tracing::instrument(skip_all)] async fn into_apub(self, data: &Self::DataType) -> Result { let mut ordered_items = vec![]; for post in self.0 { @@ -80,6 +82,7 @@ impl ApubObject for ApubCommunityOutbox { unimplemented!() } + #[tracing::instrument(skip_all)] async fn verify( group_outbox: &GroupOutbox, expected_domain: &Url, @@ -90,6 +93,7 @@ impl ApubObject for ApubCommunityOutbox { Ok(()) } + #[tracing::instrument(skip_all)] async fn from_apub( apub: Self::ApubType, data: &Self::DataType, diff --git a/crates/apub/src/fetcher/post_or_comment.rs b/crates/apub/src/fetcher/post_or_comment.rs index 55d49481..2702385c 100644 --- a/crates/apub/src/fetcher/post_or_comment.rs +++ b/crates/apub/src/fetcher/post_or_comment.rs @@ -33,6 +33,7 @@ impl ApubObject for PostOrComment { } // TODO: this can probably be implemented using a single sql query + #[tracing::instrument(skip_all)] async fn read_from_apub_id( object_id: Url, data: &Self::DataType, @@ -46,6 +47,7 @@ impl ApubObject for PostOrComment { }) } + #[tracing::instrument(skip_all)] async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> { match self { PostOrComment::Post(p) => p.delete(data).await, @@ -61,6 +63,7 @@ impl ApubObject for PostOrComment { unimplemented!() } + #[tracing::instrument(skip_all)] async fn verify( apub: &Self::ApubType, expected_domain: &Url, @@ -73,6 +76,7 @@ impl ApubObject for PostOrComment { } } + #[tracing::instrument(skip_all)] async fn from_apub( apub: PageOrNote, context: &LemmyContext, diff --git a/crates/apub/src/fetcher/search.rs b/crates/apub/src/fetcher/search.rs index f8784a5e..816a0516 100644 --- a/crates/apub/src/fetcher/search.rs +++ b/crates/apub/src/fetcher/search.rs @@ -4,7 +4,6 @@ use crate::{ protocol::objects::{group::Group, note::Note, page::Page, person::Person}, EndpointType, }; -use anyhow::anyhow; use chrono::NaiveDateTime; use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject}; use lemmy_utils::LemmyError; @@ -19,6 +18,7 @@ use url::Url; /// http://lemmy_beta:8551/u/lemmy_alpha, or @lemmy_beta@lemmy_beta:8551 /// http://lemmy_gamma:8561/post/3 /// http://lemmy_delta:8571/comment/2 +#[tracing::instrument(skip_all)] pub async fn search_by_apub_id( query: &str, context: &LemmyContext, @@ -61,7 +61,7 @@ pub async fn search_by_apub_id( .await?, )) } - _ => Err(anyhow!("invalid query").into()), + _ => Err(LemmyError::from_message("invalid query")), } } } @@ -105,6 +105,7 @@ impl ApubObject for SearchableObjects { // a single query. // we could skip this and always return an error, but then it would always fetch objects // over http, and not be able to mark objects as deleted that were deleted by remote server. + #[tracing::instrument(skip_all)] async fn read_from_apub_id( object_id: Url, context: &LemmyContext, @@ -128,6 +129,7 @@ impl ApubObject for SearchableObjects { Ok(None) } + #[tracing::instrument(skip_all)] async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> { match self { SearchableObjects::Person(p) => p.delete(data).await, @@ -145,6 +147,7 @@ impl ApubObject for SearchableObjects { unimplemented!() } + #[tracing::instrument(skip_all)] async fn verify( apub: &Self::ApubType, expected_domain: &Url, @@ -167,6 +170,7 @@ impl ApubObject for SearchableObjects { } } + #[tracing::instrument(skip_all)] async fn from_apub( apub: Self::ApubType, context: &LemmyContext, diff --git a/crates/apub/src/fetcher/user_or_community.rs b/crates/apub/src/fetcher/user_or_community.rs index 00612cbb..9e38e3dc 100644 --- a/crates/apub/src/fetcher/user_or_community.rs +++ b/crates/apub/src/fetcher/user_or_community.rs @@ -35,6 +35,7 @@ impl ApubObject for UserOrCommunity { }) } + #[tracing::instrument(skip_all)] async fn read_from_apub_id( object_id: Url, data: &Self::DataType, @@ -48,6 +49,7 @@ impl ApubObject for UserOrCommunity { }) } + #[tracing::instrument(skip_all)] async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> { match self { UserOrCommunity::User(p) => p.delete(data).await, @@ -63,6 +65,7 @@ impl ApubObject for UserOrCommunity { unimplemented!() } + #[tracing::instrument(skip_all)] async fn verify( apub: &Self::ApubType, expected_domain: &Url, @@ -79,6 +82,7 @@ impl ApubObject for UserOrCommunity { } } + #[tracing::instrument(skip_all)] async fn from_apub( apub: Self::ApubType, data: &Self::DataType, diff --git a/crates/apub/src/fetcher/webfinger.rs b/crates/apub/src/fetcher/webfinger.rs index b44030b0..426ec2d6 100644 --- a/crates/apub/src/fetcher/webfinger.rs +++ b/crates/apub/src/fetcher/webfinger.rs @@ -1,5 +1,4 @@ use crate::{generate_local_apub_endpoint, EndpointType}; -use anyhow::anyhow; use itertools::Itertools; use lemmy_apub_lib::{ object_id::ObjectId, @@ -34,6 +33,7 @@ pub struct WebfingerResponse { /// /// TODO: later provide a method in ApubObject to generate the endpoint, so that we dont have to /// pass in EndpointType +#[tracing::instrument(skip_all)] pub async fn webfinger_resolve( identifier: &str, endpoint_type: EndpointType, @@ -61,6 +61,7 @@ where /// Turns a person id like `@name@example.com` into an apub ID, like `https://example.com/user/name`, /// using webfinger. +#[tracing::instrument(skip_all)] pub(crate) async fn webfinger_resolve_actor( identifier: &str, context: &LemmyContext, @@ -114,5 +115,9 @@ where return object.map(|o| o.actor_id().into()); } } - Err(anyhow!("Failed to resolve actor for {}", identifier).into()) + let error = LemmyError::from(anyhow::anyhow!( + "Failed to resolve actor for {}", + identifier + )); + Err(error.with_message("failed_to_resolve")) } diff --git a/crates/apub/src/http/comment.rs b/crates/apub/src/http/comment.rs index f62ff36e..562905ad 100644 --- a/crates/apub/src/http/comment.rs +++ b/crates/apub/src/http/comment.rs @@ -2,7 +2,7 @@ use crate::{ http::{create_apub_response, create_apub_tombstone_response}, objects::comment::ApubComment, }; -use actix_web::{body::Body, web, web::Path, HttpResponse}; +use actix_web::{body::AnyBody, web, web::Path, HttpResponse}; use diesel::result::Error::NotFound; use lemmy_api_common::blocking; use lemmy_apub_lib::traits::ApubObject; @@ -17,10 +17,11 @@ pub(crate) struct CommentQuery { } /// Return the ActivityPub json representation of a local comment over HTTP. +#[tracing::instrument(skip_all)] pub(crate) async fn get_apub_comment( info: Path, context: web::Data, -) -> Result, LemmyError> { +) -> Result, LemmyError> { let id = CommentId(info.comment_id.parse::()?); let comment: ApubComment = blocking(context.pool(), move |conn| Comment::read(conn, id)) .await?? diff --git a/crates/apub/src/http/community.rs b/crates/apub/src/http/community.rs index b040a4a8..d974e31d 100644 --- a/crates/apub/src/http/community.rs +++ b/crates/apub/src/http/community.rs @@ -21,7 +21,7 @@ use crate::{ collections::group_followers::GroupFollowers, }, }; -use actix_web::{body::Body, web, web::Payload, HttpRequest, HttpResponse}; +use actix_web::{body::AnyBody, web, web::Payload, HttpRequest, HttpResponse}; use lemmy_api_common::blocking; use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject}; use lemmy_db_schema::source::community::Community; @@ -36,10 +36,11 @@ pub(crate) struct CommunityQuery { } /// Return the ActivityPub json representation of a local community over HTTP. +#[tracing::instrument(skip_all)] pub(crate) async fn get_apub_community_http( info: web::Path, context: web::Data, -) -> Result, LemmyError> { +) -> Result, LemmyError> { let community: ApubCommunity = blocking(context.pool(), move |conn| { Community::read_from_name(conn, &info.community_name) }) @@ -56,6 +57,7 @@ pub(crate) async fn get_apub_community_http( } /// Handler for all incoming receive to community inboxes. +#[tracing::instrument(skip_all)] pub async fn community_inbox( request: HttpRequest, payload: Payload, @@ -96,7 +98,7 @@ pub(in crate::http) async fn receive_group_inbox( pub(crate) async fn get_apub_community_followers( info: web::Path, context: web::Data, -) -> Result, LemmyError> { +) -> Result, LemmyError> { let community = blocking(context.pool(), move |conn| { Community::read_from_name(conn, &info.community_name) }) @@ -110,7 +112,7 @@ pub(crate) async fn get_apub_community_followers( pub(crate) async fn get_apub_community_outbox( info: web::Path, context: web::Data, -) -> Result, LemmyError> { +) -> Result, LemmyError> { let community = blocking(context.pool(), move |conn| { Community::read_from_name(conn, &info.community_name) }) @@ -121,10 +123,11 @@ pub(crate) async fn get_apub_community_outbox( Ok(create_apub_response(&outbox.into_apub(&outbox_data).await?)) } +#[tracing::instrument(skip_all)] pub(crate) async fn get_apub_community_moderators( info: web::Path, context: web::Data, -) -> Result, LemmyError> { +) -> Result, LemmyError> { let community: ApubCommunity = blocking(context.pool(), move |conn| { Community::read_from_name(conn, &info.community_name) }) diff --git a/crates/apub/src/http/mod.rs b/crates/apub/src/http/mod.rs index 0d484e8f..5e40b9d6 100644 --- a/crates/apub/src/http/mod.rs +++ b/crates/apub/src/http/mod.rs @@ -7,13 +7,13 @@ use crate::{ insert_activity, }; use actix_web::{ - body::Body, + body::AnyBody, web, web::{Bytes, BytesMut, Payload}, HttpRequest, HttpResponse, }; -use anyhow::{anyhow, Context}; +use anyhow::Context; use futures::StreamExt; use http::StatusCode; use lemmy_api_common::blocking; @@ -38,6 +38,7 @@ mod person; mod post; pub mod routes; +#[tracing::instrument(skip_all)] pub async fn shared_inbox( request: HttpRequest, payload: Payload, @@ -75,6 +76,7 @@ pub(crate) struct ActivityCommonFields { } // TODO: move most of this code to library +#[tracing::instrument(skip_all)] async fn receive_activity<'a, T>( request: HttpRequest, activity: T, @@ -117,7 +119,7 @@ where /// Convert the data to json and turn it into an HTTP Response with the correct ActivityPub /// headers. -fn create_apub_response(data: &T) -> HttpResponse +fn create_apub_response(data: &T) -> HttpResponse where T: Serialize, { @@ -126,13 +128,13 @@ where .json(WithContext::new(data)) } -fn create_json_apub_response(data: serde_json::Value) -> HttpResponse { +fn create_json_apub_response(data: serde_json::Value) -> HttpResponse { HttpResponse::Ok() .content_type(APUB_JSON_CONTENT_TYPE) .json(data) } -fn create_apub_tombstone_response(data: &T) -> HttpResponse +fn create_apub_tombstone_response(data: &T) -> HttpResponse where T: Serialize, { @@ -149,10 +151,11 @@ pub struct ActivityQuery { } /// Return the ActivityPub json representation of a local activity over HTTP. +#[tracing::instrument(skip_all)] pub(crate) async fn get_activity( info: web::Path, context: web::Data, -) -> Result, LemmyError> { +) -> Result, LemmyError> { let settings = context.settings(); let activity_id = Url::parse(&format!( "{}/activities/{}/{}", @@ -178,13 +181,11 @@ fn assert_activity_not_local(id: &Url, hostname: &str) -> Result<(), LemmyError> let activity_domain = id.domain().context(location_info!())?; if activity_domain == hostname { - return Err( - anyhow!( - "Error: received activity which was sent by local instance: {:?}", - id - ) - .into(), - ); + let error = LemmyError::from(anyhow::anyhow!( + "Error: received activity which was sent by local instance: {:?}", + id + )); + return Err(error.with_message("received_local_activity")); } Ok(()) } diff --git a/crates/apub/src/http/person.rs b/crates/apub/src/http/person.rs index b98f189c..a58ae725 100644 --- a/crates/apub/src/http/person.rs +++ b/crates/apub/src/http/person.rs @@ -11,7 +11,7 @@ use crate::{ objects::person::ApubPerson, protocol::collections::person_outbox::PersonOutbox, }; -use actix_web::{body::Body, web, web::Payload, HttpRequest, HttpResponse}; +use actix_web::{body::AnyBody, web, web::Payload, HttpRequest, HttpResponse}; use lemmy_api_common::blocking; use lemmy_apub_lib::traits::ApubObject; use lemmy_db_schema::source::person::Person; @@ -26,10 +26,11 @@ pub struct PersonQuery { } /// Return the ActivityPub json representation of a local person over HTTP. +#[tracing::instrument(skip_all)] pub(crate) async fn get_apub_person_http( info: web::Path, context: web::Data, -) -> Result, LemmyError> { +) -> Result, LemmyError> { let user_name = info.into_inner().user_name; // TODO: this needs to be able to read deleted persons, so that it can send tombstones let person: ApubPerson = blocking(context.pool(), move |conn| { @@ -47,6 +48,7 @@ pub(crate) async fn get_apub_person_http( } } +#[tracing::instrument(skip_all)] pub async fn person_inbox( request: HttpRequest, payload: Payload, @@ -69,10 +71,11 @@ pub(in crate::http) async fn receive_person_inbox( receive_activity(request, activity, activity_data, context).await } +#[tracing::instrument(skip_all)] pub(crate) async fn get_apub_person_outbox( info: web::Path, context: web::Data, -) -> Result, LemmyError> { +) -> Result, LemmyError> { let person = blocking(context.pool(), move |conn| { Person::find_by_name(conn, &info.user_name) }) diff --git a/crates/apub/src/http/post.rs b/crates/apub/src/http/post.rs index 52fe002a..0b1d79e1 100644 --- a/crates/apub/src/http/post.rs +++ b/crates/apub/src/http/post.rs @@ -2,7 +2,7 @@ use crate::{ http::{create_apub_response, create_apub_tombstone_response}, objects::post::ApubPost, }; -use actix_web::{body::Body, web, HttpResponse}; +use actix_web::{body::AnyBody, web, HttpResponse}; use diesel::result::Error::NotFound; use lemmy_api_common::blocking; use lemmy_apub_lib::traits::ApubObject; @@ -17,10 +17,11 @@ pub(crate) struct PostQuery { } /// Return the ActivityPub json representation of a local post over HTTP. +#[tracing::instrument(skip_all)] pub(crate) async fn get_apub_post( info: web::Path, context: web::Data, -) -> Result, LemmyError> { +) -> Result, LemmyError> { let id = PostId(info.post_id.parse::()?); let post: ApubPost = blocking(context.pool(), move |conn| Post::read(conn, id)) .await?? diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index b3c7eff7..44c2d0d5 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -1,5 +1,5 @@ use crate::fetcher::post_or_comment::PostOrComment; -use anyhow::{anyhow, Context}; +use anyhow::Context; use lemmy_api_common::blocking; use lemmy_db_schema::{newtypes::DbUrl, source::activity::Activity, DbPool}; use lemmy_utils::{location_info, settings::structs::Settings, LemmyError}; @@ -28,6 +28,7 @@ pub mod protocol; /// /// `use_strict_allowlist` should be true only when parsing a remote community, or when parsing a /// post/comment in a local community. +#[tracing::instrument(skip(settings))] pub(crate) fn check_is_apub_id_valid( apub_id: &Url, use_strict_allowlist: bool, @@ -40,24 +41,28 @@ pub(crate) fn check_is_apub_id_valid( return if domain == local_instance { Ok(()) } else { - Err( - anyhow!( - "Trying to connect with {}, but federation is disabled", - domain - ) - .into(), - ) + let error = LemmyError::from(anyhow::anyhow!( + "Trying to connect with {}, but federation is disabled", + domain + )); + Err(error.with_message("federation_disabled")) }; } let host = apub_id.host_str().context(location_info!())?; let host_as_ip = host.parse::(); if host == "localhost" || host_as_ip.is_ok() { - return Err(anyhow!("invalid hostname {}: {}", host, apub_id).into()); + let error = LemmyError::from(anyhow::anyhow!("invalid hostname {}: {}", host, apub_id)); + return Err(error.with_message("invalid_hostname")); } if apub_id.scheme() != settings.get_protocol_string() { - return Err(anyhow!("invalid apub id scheme {}: {}", apub_id.scheme(), apub_id).into()); + let error = LemmyError::from(anyhow::anyhow!( + "invalid apub id scheme {}: {}", + apub_id.scheme(), + apub_id + )); + return Err(error.with_message("invalid_scheme")); } // TODO: might be good to put the part above in one method, and below in another @@ -65,7 +70,8 @@ pub(crate) fn check_is_apub_id_valid( // -> no that doesnt make sense, we still need the code below for blocklist and strict allowlist if let Some(blocked) = settings.to_owned().federation.blocked_instances { if blocked.contains(&domain) { - return Err(anyhow!("{} is in federation blocklist", domain).into()); + let error = LemmyError::from(anyhow::anyhow!("{} is in federation blocklist", domain)); + return Err(error.with_message("federation_blocked")); } } @@ -78,7 +84,8 @@ pub(crate) fn check_is_apub_id_valid( allowed.push(local_instance); if !allowed.contains(&domain) { - return Err(anyhow!("{} not in federation allowlist", domain).into()); + let error = LemmyError::from(anyhow::anyhow!("{} not in federation allowlist", domain)); + return Err(error.with_message("federation_not_allowed")); } } } @@ -163,6 +170,7 @@ fn generate_moderators_url(community_id: &DbUrl) -> Result { /// Store a sent or received activity in the database, for logging purposes. These records are not /// persistent. +#[tracing::instrument(skip(pool))] async fn insert_activity( ap_id: &Url, activity: serde_json::Value, diff --git a/crates/apub/src/mentions.rs b/crates/apub/src/mentions.rs index f8de4385..5912d808 100644 --- a/crates/apub/src/mentions.rs +++ b/crates/apub/src/mentions.rs @@ -34,6 +34,7 @@ pub struct MentionsAndAddresses { /// This takes a comment, and builds a list of to_addresses, inboxes, /// and mention tags, so they know where to be sent to. /// Addresses are the persons / addresses that go in the cc field. +#[tracing::instrument(skip(comment, community_id, context))] pub async fn collect_non_local_mentions( comment: &ApubComment, community_id: ObjectId, @@ -88,6 +89,7 @@ pub async fn collect_non_local_mentions( /// Returns the apub ID of the person this comment is responding to. Meaning, in case this is a /// top-level comment, the creator of the post, otherwise the creator of the parent comment. +#[tracing::instrument(skip(pool, comment))] async fn get_comment_parent_creator( pool: &DbPool, comment: &Comment, diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index 41ea12b9..57bbbe12 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -12,7 +12,6 @@ use crate::{ PostOrComment, }; use activitystreams_kinds::{object::NoteType, public}; -use anyhow::anyhow; use chrono::NaiveDateTime; use html2md::parse_html; use lemmy_api_common::blocking; @@ -65,6 +64,7 @@ impl ApubObject for ApubComment { None } + #[tracing::instrument(skip_all)] async fn read_from_apub_id( object_id: Url, context: &LemmyContext, @@ -78,6 +78,7 @@ impl ApubObject for ApubComment { ) } + #[tracing::instrument(skip_all)] async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> { if !self.deleted { blocking(context.pool(), move |conn| { @@ -88,6 +89,7 @@ impl ApubObject for ApubComment { Ok(()) } + #[tracing::instrument(skip_all)] async fn into_apub(self, context: &LemmyContext) -> Result { let creator_id = self.creator_id; let creator = blocking(context.pool(), move |conn| Person::read(conn, creator_id)).await??; @@ -136,6 +138,7 @@ impl ApubObject for ApubComment { Ok(Tombstone::new(self.ap_id.clone().into())) } + #[tracing::instrument(skip_all)] async fn verify( note: &Note, expected_domain: &Url, @@ -160,7 +163,7 @@ impl ApubObject for ApubComment { ) .await?; if post.locked { - return Err(anyhow!("Post is locked").into()); + return Err(LemmyError::from_message("Post is locked")); } Ok(()) } @@ -168,6 +171,7 @@ impl ApubObject for ApubComment { /// Converts a `Note` to `Comment`. /// /// If the parent community, post and comment(s) are not known locally, these are also fetched. + #[tracing::instrument(skip_all)] async fn from_apub( note: Note, context: &LemmyContext, diff --git a/crates/apub/src/objects/community.rs b/crates/apub/src/objects/community.rs index 7bb57ce6..c560278e 100644 --- a/crates/apub/src/objects/community.rs +++ b/crates/apub/src/objects/community.rs @@ -55,6 +55,7 @@ impl ApubObject for ApubCommunity { Some(self.last_refreshed_at) } + #[tracing::instrument(skip_all)] async fn read_from_apub_id( object_id: Url, context: &LemmyContext, @@ -68,6 +69,7 @@ impl ApubObject for ApubCommunity { ) } + #[tracing::instrument(skip_all)] async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> { blocking(context.pool(), move |conn| { Community::update_deleted(conn, self.id, true) @@ -76,6 +78,7 @@ impl ApubObject for ApubCommunity { Ok(()) } + #[tracing::instrument(skip_all)] async fn into_apub(self, _context: &LemmyContext) -> Result { let source = self.description.clone().map(|bio| Source { content: bio, @@ -115,6 +118,7 @@ impl ApubObject for ApubCommunity { Ok(Tombstone::new(self.actor_id())) } + #[tracing::instrument(skip_all)] async fn verify( group: &Group, expected_domain: &Url, @@ -125,6 +129,7 @@ impl ApubObject for ApubCommunity { } /// Converts a `Group` to `Community`, inserts it into the database and updates moderators. + #[tracing::instrument(skip_all)] async fn from_apub( group: Group, context: &LemmyContext, @@ -181,6 +186,7 @@ impl ActorType for ApubCommunity { impl ApubCommunity { /// For a given community, returns the inboxes of all followers. + #[tracing::instrument(skip_all)] pub(crate) async fn get_follower_inboxes( &self, context: &LemmyContext, diff --git a/crates/apub/src/objects/person.rs b/crates/apub/src/objects/person.rs index 9c93e76d..a4f858c0 100644 --- a/crates/apub/src/objects/person.rs +++ b/crates/apub/src/objects/person.rs @@ -57,6 +57,7 @@ impl ApubObject for ApubPerson { Some(self.last_refreshed_at) } + #[tracing::instrument(skip_all)] async fn read_from_apub_id( object_id: Url, context: &LemmyContext, @@ -70,6 +71,7 @@ impl ApubObject for ApubPerson { ) } + #[tracing::instrument(skip_all)] async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> { blocking(context.pool(), move |conn| { DbPerson::update_deleted(conn, self.id, true) @@ -78,6 +80,7 @@ impl ApubObject for ApubPerson { Ok(()) } + #[tracing::instrument(skip_all)] async fn into_apub(self, _pool: &LemmyContext) -> Result { let kind = if self.bot_account { UserTypes::Service @@ -118,6 +121,7 @@ impl ApubObject for ApubPerson { unimplemented!() } + #[tracing::instrument(skip_all)] async fn verify( person: &Person, expected_domain: &Url, @@ -135,6 +139,7 @@ impl ApubObject for ApubPerson { Ok(()) } + #[tracing::instrument(skip_all)] async fn from_apub( person: Person, context: &LemmyContext, diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs index cb86b97d..37c0fb3f 100644 --- a/crates/apub/src/objects/post.rs +++ b/crates/apub/src/objects/post.rs @@ -60,6 +60,7 @@ impl ApubObject for ApubPost { None } + #[tracing::instrument(skip_all)] async fn read_from_apub_id( object_id: Url, context: &LemmyContext, @@ -73,6 +74,7 @@ impl ApubObject for ApubPost { ) } + #[tracing::instrument(skip_all)] async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> { if !self.deleted { blocking(context.pool(), move |conn| { @@ -84,6 +86,7 @@ impl ApubObject for ApubPost { } // Turn a Lemmy post into an ActivityPub page that can be sent out over the network. + #[tracing::instrument(skip_all)] async fn into_apub(self, context: &LemmyContext) -> Result { let creator_id = self.creator_id; let creator = blocking(context.pool(), move |conn| Person::read(conn, creator_id)).await??; @@ -125,6 +128,7 @@ impl ApubObject for ApubPost { Ok(Tombstone::new(self.ap_id.clone().into())) } + #[tracing::instrument(skip_all)] async fn verify( page: &Page, expected_domain: &Url, @@ -146,6 +150,7 @@ impl ApubObject for ApubPost { Ok(()) } + #[tracing::instrument(skip_all)] async fn from_apub( page: Page, context: &LemmyContext, diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs index d624e133..a96a14e8 100644 --- a/crates/apub/src/objects/private_message.rs +++ b/crates/apub/src/objects/private_message.rs @@ -2,7 +2,6 @@ use crate::protocol::{ objects::chat_message::{ChatMessage, ChatMessageType}, Source, }; -use anyhow::anyhow; use chrono::NaiveDateTime; use html2md::parse_html; use lemmy_api_common::blocking; @@ -53,6 +52,7 @@ impl ApubObject for ApubPrivateMessage { None } + #[tracing::instrument(skip_all)] async fn read_from_apub_id( object_id: Url, context: &LemmyContext, @@ -71,6 +71,7 @@ impl ApubObject for ApubPrivateMessage { unimplemented!() } + #[tracing::instrument(skip_all)] async fn into_apub(self, context: &LemmyContext) -> Result { let creator_id = self.creator_id; let creator = blocking(context.pool(), move |conn| Person::read(conn, creator_id)).await??; @@ -101,6 +102,7 @@ impl ApubObject for ApubPrivateMessage { unimplemented!() } + #[tracing::instrument(skip_all)] async fn verify( note: &ChatMessage, expected_domain: &Url, @@ -114,11 +116,12 @@ impl ApubObject for ApubPrivateMessage { .dereference(context, request_counter) .await?; if person.banned { - return Err(anyhow!("Person is banned from site").into()); + return Err(LemmyError::from_message("Person is banned from site")); } Ok(()) } + #[tracing::instrument(skip_all)] async fn from_apub( note: ChatMessage, context: &LemmyContext, diff --git a/crates/apub/src/protocol/activities/voting/vote.rs b/crates/apub/src/protocol/activities/voting/vote.rs index ba5c629c..1d66b5be 100644 --- a/crates/apub/src/protocol/activities/voting/vote.rs +++ b/crates/apub/src/protocol/activities/voting/vote.rs @@ -3,7 +3,6 @@ use crate::{ objects::person::ApubPerson, protocol::Unparsed, }; -use anyhow::anyhow; use lemmy_apub_lib::object_id::ObjectId; use lemmy_utils::LemmyError; use serde::{Deserialize, Serialize}; @@ -40,7 +39,7 @@ impl TryFrom for VoteType { match value { 1 => Ok(VoteType::Like), -1 => Ok(VoteType::Dislike), - _ => Err(anyhow!("invalid vote value").into()), + _ => Err(LemmyError::from_message("invalid vote value")), } } } diff --git a/crates/apub/src/protocol/objects/page.rs b/crates/apub/src/protocol/objects/page.rs index 1fca51e4..bac85600 100644 --- a/crates/apub/src/protocol/objects/page.rs +++ b/crates/apub/src/protocol/objects/page.rs @@ -3,7 +3,6 @@ use crate::{ protocol::{ImageObject, Source, Unparsed}, }; use activitystreams_kinds::object::PageType; -use anyhow::anyhow; use chrono::{DateTime, FixedOffset}; use lemmy_apub_lib::{ data::Data, @@ -75,7 +74,7 @@ impl Page { break Ok(c); } } else { - return Err(anyhow!("No community found in cc").into()); + return Err(LemmyError::from_message("No community found in cc")); } } } diff --git a/crates/db_schema/src/lib.rs b/crates/db_schema/src/lib.rs index ddff1375..257abe4d 100644 --- a/crates/db_schema/src/lib.rs +++ b/crates/db_schema/src/lib.rs @@ -21,7 +21,7 @@ pub type DbPool = diesel::r2d2::Pool) -> Option> { pub fn diesel_option_overwrite_to_url( opt: &Option, -) -> Result>, ApiError> { +) -> Result>, LemmyError> { match opt.as_ref().map(|s| s.as_str()) { // An empty string is an erase Some("") => Ok(Some(None)), Some(str_url) => match Url::parse(str_url) { Ok(url) => Ok(Some(Some(url.into()))), - Err(e) => Err(ApiError::err("invalid_url", e)), + Err(e) => Err(LemmyError::from(e).with_message("invalid_url")), }, None => Ok(None), } diff --git a/crates/routes/Cargo.toml b/crates/routes/Cargo.toml index c187ead6..25ab77f7 100644 --- a/crates/routes/Cargo.toml +++ b/crates/routes/Cargo.toml @@ -32,3 +32,4 @@ awc = { version = "3.0.0-beta.8", default-features = false } url = { version = "2.2.2", features = ["serde"] } strum = "0.21.0" once_cell = "1.8.0" +tracing = "0.1.29" diff --git a/crates/routes/src/feeds.rs b/crates/routes/src/feeds.rs index 534ec9fb..ce95c93a 100644 --- a/crates/routes/src/feeds.rs +++ b/crates/routes/src/feeds.rs @@ -58,6 +58,7 @@ static RSS_NAMESPACE: Lazy> = Lazy::new(|| { h }); +#[tracing::instrument(skip_all)] async fn get_all_feed( info: web::Query, context: web::Data, @@ -66,6 +67,7 @@ async fn get_all_feed( Ok(get_feed_data(&context, ListingType::All, sort_type).await?) } +#[tracing::instrument(skip_all)] async fn get_local_feed( info: web::Query, context: web::Data, @@ -74,6 +76,7 @@ async fn get_local_feed( Ok(get_feed_data(&context, ListingType::Local, sort_type).await?) } +#[tracing::instrument(skip_all)] async fn get_feed_data( context: &LemmyContext, listing_type: ListingType, @@ -114,6 +117,7 @@ async fn get_feed_data( ) } +#[tracing::instrument(skip_all)] async fn get_feed( req: HttpRequest, info: web::Query, @@ -167,6 +171,7 @@ fn get_sort_type(info: web::Query) -> Result { SortType::from_str(&sort_query) } +#[tracing::instrument(skip_all)] fn get_feed_user( conn: &PgConnection, sort_type: &SortType, @@ -194,6 +199,7 @@ fn get_feed_user( Ok(channel_builder) } +#[tracing::instrument(skip_all)] fn get_feed_community( conn: &PgConnection, sort_type: &SortType, @@ -225,6 +231,7 @@ fn get_feed_community( Ok(channel_builder) } +#[tracing::instrument(skip_all)] fn get_feed_front( conn: &PgConnection, jwt_secret: &str, @@ -260,6 +267,7 @@ fn get_feed_front( Ok(channel_builder) } +#[tracing::instrument(skip_all)] fn get_feed_inbox( conn: &PgConnection, jwt_secret: &str, @@ -303,6 +311,7 @@ fn get_feed_inbox( Ok(channel_builder) } +#[tracing::instrument(skip_all)] fn create_reply_and_mention_items( replies: Vec, mentions: Vec, @@ -346,6 +355,7 @@ fn create_reply_and_mention_items( Ok(reply_items) } +#[tracing::instrument(skip_all)] fn build_item( creator_name: &str, published: &NaiveDateTime, @@ -376,6 +386,7 @@ fn build_item( Ok(i.build().map_err(|e| anyhow!(e))?) } +#[tracing::instrument(skip_all)] fn create_post_items( posts: Vec, protocol_and_hostname: &str, diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 5eaff30e..04c60e3f 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -15,10 +15,13 @@ mod test; pub mod utils; pub mod version; +mod sensitive; + +pub use sensitive::Sensitive; + +use actix_web::HttpResponse; use http::StatusCode; use std::{fmt, fmt::Display}; -use thiserror::Error; -use tracing::warn; use tracing_error::SpanTrace; pub type ConnectionId = usize; @@ -44,30 +47,40 @@ macro_rules! location_info { }; } -#[derive(Debug, Error)] -#[error("{{\"error\":\"{message}\"}}")] -pub struct ApiError { - message: String, +#[derive(serde::Serialize)] +struct ApiError { + error: &'static str, +} + +pub struct LemmyError { + pub message: Option<&'static str>, + pub inner: anyhow::Error, + pub context: SpanTrace, } -impl ApiError { - pub fn err_plain(msg: &str) -> Self { - ApiError { - message: msg.to_string(), +impl LemmyError { + pub fn from_message(message: &'static str) -> Self { + let inner = anyhow::anyhow!("{}", message); + LemmyError { + message: Some(message), + inner, + context: SpanTrace::capture(), } } - pub fn err(msg: &str, original_error: E) -> Self { - warn!("{}", original_error); - ApiError { - message: msg.to_string(), + pub fn with_message(self, message: &'static str) -> Self { + LemmyError { + message: Some(message), + ..self } } -} + pub fn to_json(&self) -> Result { + let api_error = match self.message { + Some(error) => ApiError { error }, + None => ApiError { error: "Unknown" }, + }; -#[derive(Debug)] -pub struct LemmyError { - pub inner: anyhow::Error, - pub context: SpanTrace, + Ok(serde_json::to_string(&api_error)?) + } } impl From for LemmyError @@ -76,15 +89,29 @@ where { fn from(t: T) -> Self { LemmyError { + message: None, inner: t.into(), context: SpanTrace::capture(), } } } +impl std::fmt::Debug for LemmyError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("LemmyError") + .field("message", &self.message) + .field("inner", &self.inner) + .field("context", &"SpanTrace") + .finish() + } +} + impl Display for LemmyError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - self.inner.fmt(f)?; + if let Some(message) = self.message { + write!(f, "{}: ", message)?; + } + writeln!(f, "{}", self.inner)?; self.context.fmt(f) } } @@ -93,7 +120,17 @@ impl actix_web::error::ResponseError for LemmyError { fn status_code(&self) -> StatusCode { match self.inner.downcast_ref::() { Some(diesel::result::Error::NotFound) => StatusCode::NOT_FOUND, - _ => StatusCode::INTERNAL_SERVER_ERROR, + _ => StatusCode::BAD_REQUEST, + } + } + + fn error_response(&self) -> HttpResponse { + if let Some(message) = &self.message { + HttpResponse::build(self.status_code()).json(ApiError { error: message }) + } else { + HttpResponse::build(self.status_code()) + .content_type("text/plain") + .body(self.inner.to_string()) } } } diff --git a/crates/utils/src/rate_limit/rate_limiter.rs b/crates/utils/src/rate_limit/rate_limiter.rs index 46819915..580ed3e7 100644 --- a/crates/utils/src/rate_limit/rate_limiter.rs +++ b/crates/utils/src/rate_limit/rate_limiter.rs @@ -1,4 +1,4 @@ -use crate::{ApiError, IpAddr, LemmyError}; +use crate::{IpAddr, LemmyError}; use std::{collections::HashMap, time::SystemTime}; use strum::IntoEnumIterator; use tracing::debug; @@ -79,18 +79,14 @@ impl RateLimiter { time_passed, rate_limit.allowance ); - Err( - ApiError { - message: format!( - "Too many requests. type: {}, IP: {}, {} per {} seconds", - type_.as_ref(), - ip, - rate, - per - ), - } - .into(), - ) + let error = LemmyError::from(anyhow::anyhow!( + "Too many requests. type: {}, IP: {}, {} per {} seconds", + type_.as_ref(), + ip, + rate, + per + )); + Err(error.with_message("too_many_requests")) } else { if !check_only { rate_limit.allowance -= 1.0; diff --git a/crates/utils/src/sensitive.rs b/crates/utils/src/sensitive.rs new file mode 100644 index 00000000..c71f357e --- /dev/null +++ b/crates/utils/src/sensitive.rs @@ -0,0 +1,98 @@ +use std::{ + borrow::Borrow, + ops::{Deref, DerefMut}, +}; + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize)] +#[serde(transparent)] +pub struct Sensitive(T); + +impl Sensitive { + pub fn new(item: T) -> Self { + Sensitive(item) + } + + pub fn into_inner(this: Self) -> T { + this.0 + } +} + +impl std::fmt::Debug for Sensitive { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Sensitive").finish() + } +} + +impl AsRef for Sensitive { + fn as_ref(&self) -> &T { + &self.0 + } +} + +impl AsRef for Sensitive { + fn as_ref(&self) -> &str { + &self.0 + } +} + +impl AsRef<[u8]> for Sensitive { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl AsRef<[u8]> for Sensitive> { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl AsMut for Sensitive { + fn as_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +impl AsMut for Sensitive { + fn as_mut(&mut self) -> &mut str { + &mut self.0 + } +} + +impl Deref for Sensitive { + type Target = str; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Sensitive { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl From for Sensitive { + fn from(t: T) -> Self { + Sensitive(t) + } +} + +impl From<&str> for Sensitive { + fn from(s: &str) -> Self { + Sensitive(s.into()) + } +} + +impl Borrow for Sensitive { + fn borrow(&self) -> &T { + &self.0 + } +} + +impl Borrow for Sensitive { + fn borrow(&self) -> &str { + &self.0 + } +} diff --git a/crates/utils/src/utils.rs b/crates/utils/src/utils.rs index 1c33b4c5..90f780e2 100644 --- a/crates/utils/src/utils.rs +++ b/crates/utils/src/utils.rs @@ -1,4 +1,4 @@ -use crate::{ApiError, IpAddr}; +use crate::{IpAddr, LemmyError}; use actix_web::dev::ConnectionInfo; use chrono::{DateTime, FixedOffset, NaiveDateTime}; use itertools::Itertools; @@ -60,15 +60,19 @@ pub(crate) fn slur_check<'a>( } } -pub fn check_slurs(text: &str, slur_regex: &Option) -> Result<(), ApiError> { +pub fn check_slurs(text: &str, slur_regex: &Option) -> Result<(), LemmyError> { if let Err(slurs) = slur_check(text, slur_regex) { - Err(ApiError::err_plain(&slurs_vec_to_str(slurs))) + let error = LemmyError::from(anyhow::anyhow!("{}", slurs_vec_to_str(slurs))); + Err(error.with_message("slurs")) } else { Ok(()) } } -pub fn check_slurs_opt(text: &Option, slur_regex: &Option) -> Result<(), ApiError> { +pub fn check_slurs_opt( + text: &Option, + slur_regex: &Option, +) -> Result<(), LemmyError> { match text { Some(t) => check_slurs(t, slur_regex), None => Ok(()), diff --git a/crates/websocket/src/chat_server.rs b/crates/websocket/src/chat_server.rs index 2b58b2c1..5d91800e 100644 --- a/crates/websocket/src/chat_server.rs +++ b/crates/websocket/src/chat_server.rs @@ -22,7 +22,6 @@ use lemmy_utils::{ location_info, rate_limit::RateLimit, settings::structs::Settings, - ApiError, ConnectionId, IpAddr, LemmyError, @@ -477,7 +476,7 @@ impl ChatServer { let data = &json["data"].to_string(); let op = &json["op"] .as_str() - .ok_or_else(|| ApiError::err_plain("missing op"))?; + .ok_or_else(|| LemmyError::from_message("missing op"))?; if let Ok(user_operation_crud) = UserOperationCrud::from_str(op) { let fut = (message_handler_crud)(context, msg.id, user_operation_crud.clone(), data); diff --git a/crates/websocket/src/handlers.rs b/crates/websocket/src/handlers.rs index 1e67cdb3..f35e8b31 100644 --- a/crates/websocket/src/handlers.rs +++ b/crates/websocket/src/handlers.rs @@ -76,7 +76,10 @@ impl Handler for ChatServer { } Err(e) => { error!("Error during message handling {}", e); - Ok(e.to_string()) + Ok( + e.to_json() + .unwrap_or_else(|_| String::from(r#"{"error":"failed to serialize json"}"#)), + ) } } }) diff --git a/crates/websocket/src/routes.rs b/crates/websocket/src/routes.rs index e5551b41..71df5515 100644 --- a/crates/websocket/src/routes.rs +++ b/crates/websocket/src/routes.rs @@ -115,7 +115,6 @@ impl StreamHandler> for WsSession { } ws::Message::Text(text) => { let m = text.trim().to_owned(); - info!("Message received: {:?} from id: {}", &m, self.id); self .cs_addr diff --git a/src/api_routes.rs b/src/api_routes.rs index ae5fa40c..3fbb7f05 100644 --- a/src/api_routes.rs +++ b/src/api_routes.rs @@ -1,4 +1,4 @@ -use actix_web::{error::ErrorBadRequest, *}; +use actix_web::*; use lemmy_api::Perform; use lemmy_api_common::{comment::*, community::*, person::*, post::*, site::*, websocket::*}; use lemmy_api_crud::PerformCrud; @@ -232,8 +232,7 @@ where let res = data .perform(&context, None) .await - .map(|json| HttpResponse::Ok().json(json)) - .map_err(ErrorBadRequest)?; + .map(|json| HttpResponse::Ok().json(json))?; Ok(res) } @@ -268,8 +267,7 @@ where let res = data .perform(&context, None) .await - .map(|json| HttpResponse::Ok().json(json)) - .map_err(ErrorBadRequest)?; + .map(|json| HttpResponse::Ok().json(json))?; Ok(res) } diff --git a/src/lib.rs b/src/lib.rs index 98c2320d..62d07166 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,21 +1,20 @@ #![recursion_limit = "512"] pub mod api_routes; pub mod code_migrations; +pub mod root_span_builder; pub mod scheduled_tasks; use lemmy_utils::LemmyError; use tracing::subscriber::set_global_default; use tracing_error::ErrorLayer; use tracing_log::LogTracer; -use tracing_subscriber::{fmt::format::FmtSpan, layer::SubscriberExt, EnvFilter, Registry}; +use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; pub fn init_tracing() -> Result<(), LemmyError> { LogTracer::init()?; let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); - let format_layer = tracing_subscriber::fmt::layer() - .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE) - .pretty(); + let format_layer = tracing_subscriber::fmt::layer(); let subscriber = Registry::default() .with(env_filter) diff --git a/src/main.rs b/src/main.rs index 8a0b37f3..8f130fde 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,7 @@ use lemmy_server::{ api_routes, code_migrations::run_advanced_migrations, init_tracing, + root_span_builder::QuieterRootSpanBuilder, scheduled_tasks, }; use lemmy_utils::{ @@ -123,7 +124,8 @@ async fn main() -> Result<(), LemmyError> { ); let rate_limiter = rate_limiter.clone(); App::new() - .wrap(TracingLogger::default()) + .wrap(actix_web::middleware::Logger::default()) + .wrap(TracingLogger::::new()) .app_data(Data::new(context)) // The routes .configure(|cfg| api_routes::config(cfg, &rate_limiter)) diff --git a/src/root_span_builder.rs b/src/root_span_builder.rs new file mode 100644 index 00000000..84a7817c --- /dev/null +++ b/src/root_span_builder.rs @@ -0,0 +1,85 @@ +use actix_web::{http::StatusCode, ResponseError}; +use tracing::Span; +use tracing_actix_web::RootSpanBuilder; + +// Code in this module adapted from DefaultRootSpanBuilder +// https://github.com/LukeMathWalker/tracing-actix-web/blob/main/src/root_span_builder.rs +// and root_span! +// https://github.com/LukeMathWalker/tracing-actix-web/blob/main/src/root_span_macro.rs + +pub struct QuieterRootSpanBuilder; + +impl RootSpanBuilder for QuieterRootSpanBuilder { + fn on_request_start(request: &actix_web::dev::ServiceRequest) -> Span { + let request_id = tracing_actix_web::root_span_macro::private::get_request_id(request); + + tracing::info_span!( + "HTTP request", + http.method = %request.method(), + http.scheme = request.connection_info().scheme(), + http.host = %request.connection_info().host(), + http.target = %request.uri().path(), + http.status_code = tracing::field::Empty, + otel.kind = "server", + otel.status_code = tracing::field::Empty, + trace_id = tracing::field::Empty, + request_id = %request_id, + exception.message = tracing::field::Empty, + // Not proper OpenTelemetry, but their terminology is fairly exception-centric + exception.details = tracing::field::Empty, + ) + } + + fn on_request_end( + span: tracing::Span, + outcome: &Result, actix_web::Error>, + ) { + match &outcome { + Ok(response) => { + if let Some(error) = response.response().error() { + // use the status code already constructed for the outgoing HTTP response + handle_error(span, response.status(), error.as_response_error()); + } else { + let code: i32 = response.response().status().as_u16().into(); + span.record("http.status_code", &code); + span.record("otel.status_code", &"OK"); + } + } + Err(error) => { + let response_error = error.as_response_error(); + handle_error(span, response_error.status_code(), response_error); + } + }; + } +} + +fn handle_error(span: Span, status_code: StatusCode, response_error: &dyn ResponseError) { + let code: i32 = status_code.as_u16().into(); + + span.record("http.status_code", &code); + + if status_code.is_client_error() { + span.record("otel.status_code", &"OK"); + } else { + span.record("otel.status_code", &"ERROR"); + } + + // pre-formatting errors is a workaround for https://github.com/tokio-rs/tracing/issues/1565 + let display_error = format!("{}", response_error); + let debug_error = format!("{:?}", response_error); + + tracing::info_span!( + parent: None, + "Error encountered while processing the incoming HTTP request" + ) + .in_scope(|| { + if status_code.is_client_error() { + tracing::warn!("{}\n{}", display_error, debug_error); + } else { + tracing::error!("{}\n{}", display_error, debug_error); + } + }); + + span.record("exception.message", &tracing::field::display(display_error)); + span.record("exception.details", &tracing::field::display(debug_error)); +}