diff --git a/Cargo.lock b/Cargo.lock
index f7d99de7f..cf731ca1a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -386,19 +386,6 @@ dependencies = [
"alloc-no-stdlib",
]
-[[package]]
-name = "ammonia"
-version = "3.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64e6d1c7838db705c9b756557ee27c384ce695a1c51a6fe528784cb1c6840170"
-dependencies = [
- "html5ever",
- "maplit",
- "once_cell",
- "tendril",
- "url",
-]
-
[[package]]
name = "android-tzdata"
version = "0.1.1"
@@ -2613,7 +2600,6 @@ version = "0.18.1"
dependencies = [
"activitypub_federation",
"actix-web",
- "ammonia",
"anyhow",
"chrono",
"encoding",
@@ -3028,12 +3014,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "maplit"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
-
[[package]]
name = "markdown-it"
version = "0.5.1"
diff --git a/api_tests/src/post.spec.ts b/api_tests/src/post.spec.ts
index 42173dba8..52fe72d3d 100644
--- a/api_tests/src/post.spec.ts
+++ b/api_tests/src/post.spec.ts
@@ -513,7 +513,7 @@ test("Sanitize HTML", async () => {
}
let name = randomString(5);
- let body = " hello";
+ let body = " hello &\"'";
let form: CreatePost = {
name,
body,
@@ -521,5 +521,14 @@ test("Sanitize HTML", async () => {
community_id: betaCommunity.community.id,
};
let post = await beta.client.createPost(form);
- expect(post.post_view.post.body).toBe(" hello");
+ // first escaping for the api
+ expect(post.post_view.post.body).toBe(
+ "<script>alert('xss');</script> hello &"'",
+ );
+
+ let alphaPost = (await resolvePost(alpha, post.post_view.post)).post;
+ // second escaping over federation, avoid double escape of &
+ expect(alphaPost?.post.body).toBe(
+ "<script>alert('xss');</script> hello &"'",
+ );
});
diff --git a/crates/api/src/comment_report/create.rs b/crates/api/src/comment_report/create.rs
index 2ea973d3c..e493d60a3 100644
--- a/crates/api/src/comment_report/create.rs
+++ b/crates/api/src/comment_report/create.rs
@@ -8,7 +8,7 @@ use lemmy_api_common::{
utils::{
check_community_ban,
local_user_view_from_jwt,
- sanitize_html,
+ sanitize_html_api,
send_new_report_email_to_admins,
},
};
@@ -31,7 +31,7 @@ pub async fn create_comment_report(
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
let local_site = LocalSite::read(&mut context.pool()).await?;
- let reason = sanitize_html(data.reason.trim());
+ let reason = sanitize_html_api(data.reason.trim());
check_report_reason(&reason, &local_site)?;
let person_id = local_user_view.person.id;
diff --git a/crates/api/src/community/ban.rs b/crates/api/src/community/ban.rs
index d04a8a0a9..e969e9b78 100644
--- a/crates/api/src/community/ban.rs
+++ b/crates/api/src/community/ban.rs
@@ -8,7 +8,7 @@ use lemmy_api_common::{
is_mod_or_admin,
local_user_view_from_jwt,
remove_user_data_in_community,
- sanitize_html_opt,
+ sanitize_html_api_opt,
},
};
use lemmy_db_schema::{
@@ -86,7 +86,7 @@ pub async fn ban_from_community(
mod_person_id: local_user_view.person.id,
other_person_id: data.person_id,
community_id: data.community_id,
- reason: sanitize_html_opt(&data.reason),
+ reason: sanitize_html_api_opt(&data.reason),
banned: Some(data.ban),
expires,
};
diff --git a/crates/api/src/community/hide.rs b/crates/api/src/community/hide.rs
index 10ca6372a..8fd270181 100644
--- a/crates/api/src/community/hide.rs
+++ b/crates/api/src/community/hide.rs
@@ -5,7 +5,7 @@ use lemmy_api_common::{
community::{CommunityResponse, HideCommunity},
context::LemmyContext,
send_activity::{ActivityChannel, SendActivityData},
- utils::{is_admin, local_user_view_from_jwt, sanitize_html_opt},
+ utils::{is_admin, local_user_view_from_jwt, sanitize_html_api_opt},
};
use lemmy_db_schema::{
source::{
@@ -33,7 +33,7 @@ pub async fn hide_community(
let mod_hide_community_form = ModHideCommunityForm {
community_id: data.community_id,
mod_person_id: local_user_view.person.id,
- reason: sanitize_html_opt(&data.reason),
+ reason: sanitize_html_api_opt(&data.reason),
hidden: Some(data.hidden),
};
diff --git a/crates/api/src/local_user/ban_person.rs b/crates/api/src/local_user/ban_person.rs
index 3a3a240da..3a83d6c6e 100644
--- a/crates/api/src/local_user/ban_person.rs
+++ b/crates/api/src/local_user/ban_person.rs
@@ -4,7 +4,7 @@ use lemmy_api_common::{
context::LemmyContext,
person::{BanPerson, BanPersonResponse},
send_activity::{ActivityChannel, SendActivityData},
- utils::{is_admin, local_user_view_from_jwt, remove_user_data, sanitize_html_opt},
+ utils::{is_admin, local_user_view_from_jwt, remove_user_data, sanitize_html_api_opt},
};
use lemmy_db_schema::{
source::{
@@ -54,7 +54,7 @@ pub async fn ban_from_site(
let form = ModBanForm {
mod_person_id: local_user_view.person.id,
other_person_id: data.person_id,
- reason: sanitize_html_opt(&data.reason),
+ reason: sanitize_html_api_opt(&data.reason),
banned: Some(data.ban),
expires,
};
diff --git a/crates/api/src/local_user/save_settings.rs b/crates/api/src/local_user/save_settings.rs
index c45c69f7f..8368eada0 100644
--- a/crates/api/src/local_user/save_settings.rs
+++ b/crates/api/src/local_user/save_settings.rs
@@ -2,7 +2,7 @@ use actix_web::web::{Data, Json};
use lemmy_api_common::{
context::LemmyContext,
person::{LoginResponse, SaveUserSettings},
- utils::{local_user_view_from_jwt, sanitize_html_opt, send_verification_email},
+ utils::{local_user_view_from_jwt, sanitize_html_api_opt, send_verification_email},
};
use lemmy_db_schema::{
source::{
@@ -34,8 +34,8 @@ pub async fn save_user_settings(
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
let site_view = SiteView::read_local(&mut context.pool()).await?;
- let bio = sanitize_html_opt(&data.bio);
- let display_name = sanitize_html_opt(&data.display_name);
+ let bio = sanitize_html_api_opt(&data.bio);
+ let display_name = sanitize_html_api_opt(&data.display_name);
let avatar = diesel_option_overwrite_to_url(&data.avatar)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?;
@@ -85,7 +85,7 @@ pub async fn save_user_settings(
let person_id = local_user_view.person.id;
let default_listing_type = data.default_listing_type;
let default_sort_type = data.default_sort_type;
- let theme = sanitize_html_opt(&data.theme);
+ let theme = sanitize_html_api_opt(&data.theme);
let person_form = PersonUpdateForm {
display_name,
diff --git a/crates/api/src/post_report/create.rs b/crates/api/src/post_report/create.rs
index d4100a84e..8a5162a60 100644
--- a/crates/api/src/post_report/create.rs
+++ b/crates/api/src/post_report/create.rs
@@ -8,7 +8,7 @@ use lemmy_api_common::{
utils::{
check_community_ban,
local_user_view_from_jwt,
- sanitize_html,
+ sanitize_html_api,
send_new_report_email_to_admins,
},
};
@@ -31,7 +31,7 @@ pub async fn create_post_report(
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
let local_site = LocalSite::read(&mut context.pool()).await?;
- let reason = sanitize_html(data.reason.trim());
+ let reason = sanitize_html_api(data.reason.trim());
check_report_reason(&reason, &local_site)?;
let person_id = local_user_view.person.id;
diff --git a/crates/api/src/private_message_report/create.rs b/crates/api/src/private_message_report/create.rs
index e1479d3c3..ed19fdc35 100644
--- a/crates/api/src/private_message_report/create.rs
+++ b/crates/api/src/private_message_report/create.rs
@@ -3,7 +3,7 @@ use actix_web::web::{Data, Json};
use lemmy_api_common::{
context::LemmyContext,
private_message::{CreatePrivateMessageReport, PrivateMessageReportResponse},
- utils::{local_user_view_from_jwt, sanitize_html, send_new_report_email_to_admins},
+ utils::{local_user_view_from_jwt, sanitize_html_api, send_new_report_email_to_admins},
};
use lemmy_db_schema::{
source::{
@@ -24,7 +24,7 @@ pub async fn create_pm_report(
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
let local_site = LocalSite::read(&mut context.pool()).await?;
- let reason = sanitize_html(data.reason.trim());
+ let reason = sanitize_html_api(data.reason.trim());
check_report_reason(&reason, &local_site)?;
let person_id = local_user_view.person.id;
diff --git a/crates/api/src/site/purge/comment.rs b/crates/api/src/site/purge/comment.rs
index 391be98d7..fa0973cf1 100644
--- a/crates/api/src/site/purge/comment.rs
+++ b/crates/api/src/site/purge/comment.rs
@@ -2,7 +2,7 @@ use actix_web::web::{Data, Json};
use lemmy_api_common::{
context::LemmyContext,
site::{PurgeComment, PurgeItemResponse},
- utils::{is_admin, local_user_view_from_jwt, sanitize_html_opt},
+ utils::{is_admin, local_user_view_from_jwt, sanitize_html_api_opt},
};
use lemmy_db_schema::{
source::{
@@ -35,7 +35,7 @@ pub async fn purge_comment(
Comment::delete(&mut context.pool(), comment_id).await?;
// Mod tables
- let reason = sanitize_html_opt(&data.reason);
+ let reason = sanitize_html_api_opt(&data.reason);
let form = AdminPurgeCommentForm {
admin_person_id: local_user_view.person.id,
reason,
diff --git a/crates/api/src/site/purge/community.rs b/crates/api/src/site/purge/community.rs
index 60c1142c3..8e609501a 100644
--- a/crates/api/src/site/purge/community.rs
+++ b/crates/api/src/site/purge/community.rs
@@ -3,7 +3,12 @@ use lemmy_api_common::{
context::LemmyContext,
request::purge_image_from_pictrs,
site::{PurgeCommunity, PurgeItemResponse},
- utils::{is_admin, local_user_view_from_jwt, purge_image_posts_for_community, sanitize_html_opt},
+ utils::{
+ is_admin,
+ local_user_view_from_jwt,
+ purge_image_posts_for_community,
+ sanitize_html_api_opt,
+ },
};
use lemmy_db_schema::{
source::{
@@ -42,7 +47,7 @@ pub async fn purge_community(
Community::delete(&mut context.pool(), community_id).await?;
// Mod tables
- let reason = sanitize_html_opt(&data.reason);
+ let reason = sanitize_html_api_opt(&data.reason);
let form = AdminPurgeCommunityForm {
admin_person_id: local_user_view.person.id,
reason,
diff --git a/crates/api/src/site/purge/person.rs b/crates/api/src/site/purge/person.rs
index ed38e2354..b2968ec31 100644
--- a/crates/api/src/site/purge/person.rs
+++ b/crates/api/src/site/purge/person.rs
@@ -3,7 +3,7 @@ use lemmy_api_common::{
context::LemmyContext,
request::delete_image_from_pictrs,
site::{PurgeItemResponse, PurgePerson},
- utils::{is_admin, local_user_view_from_jwt, sanitize_html_opt},
+ utils::{is_admin, local_user_view_from_jwt, sanitize_html_api_opt},
};
use lemmy_db_schema::{
source::{
@@ -42,7 +42,7 @@ pub async fn purge_person(
Person::delete(&mut context.pool(), person_id).await?;
// Mod tables
- let reason = sanitize_html_opt(&data.reason);
+ let reason = sanitize_html_api_opt(&data.reason);
let form = AdminPurgePersonForm {
admin_person_id: local_user_view.person.id,
reason,
diff --git a/crates/api/src/site/purge/post.rs b/crates/api/src/site/purge/post.rs
index a6e6c1825..53dbf44e3 100644
--- a/crates/api/src/site/purge/post.rs
+++ b/crates/api/src/site/purge/post.rs
@@ -3,7 +3,7 @@ use lemmy_api_common::{
context::LemmyContext,
request::purge_image_from_pictrs,
site::{PurgeItemResponse, PurgePost},
- utils::{is_admin, local_user_view_from_jwt, sanitize_html_opt},
+ utils::{is_admin, local_user_view_from_jwt, sanitize_html_api_opt},
};
use lemmy_db_schema::{
source::{
@@ -43,7 +43,7 @@ pub async fn purge_post(
Post::delete(&mut context.pool(), post_id).await?;
// Mod tables
- let reason = sanitize_html_opt(&data.reason);
+ let reason = sanitize_html_api_opt(&data.reason);
let form = AdminPurgePostForm {
admin_person_id: local_user_view.person.id,
reason,
diff --git a/crates/api_common/Cargo.toml b/crates/api_common/Cargo.toml
index d74acd136..8a23a4cb2 100644
--- a/crates/api_common/Cargo.toml
+++ b/crates/api_common/Cargo.toml
@@ -34,7 +34,6 @@ full = [
"actix-web",
"futures",
"once_cell",
- "ammonia",
]
[dependencies]
@@ -67,4 +66,3 @@ once_cell = { workspace = true, optional = true }
actix-web = { workspace = true, optional = true }
# necessary for wasmt compilation
getrandom = { version = "0.2.10", features = ["js"] }
-ammonia = { version = "3.3.0", optional = true }
diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs
index 3a1f1f945..9d8181a2e 100644
--- a/crates/api_common/src/utils.rs
+++ b/crates/api_common/src/utils.rs
@@ -798,21 +798,35 @@ pub fn generate_moderators_url(community_id: &DbUrl) -> Result String {
- ammonia::Builder::default()
- .rm_tags(&["a", "img"])
- .clean(data)
- .to_string()
- // restore markdown quotes
- .replace(">", ">")
- // restore white space
- .replace(" ", " ")
+/// Replace special HTML characters in API parameters to prevent XSS attacks.
+///
+/// Taken from https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.md#output-encoding-for-html-contexts
+///
+/// `>` is left in place because it is interpreted as markdown quote.
+pub fn sanitize_html_api(data: &str) -> String {
+ data
+ .replace('&', "&")
+ .replace('<', "<")
+ .replace('\"', """)
+ .replace('\'', "'")
}
-pub fn sanitize_html_opt(data: &Option) -> Option {
- data.as_ref().map(|d| sanitize_html(d))
+pub fn sanitize_html_api_opt(data: &Option) -> Option {
+ data.as_ref().map(|d| sanitize_html_api(d))
+}
+
+/// Replace special HTML characters in federation parameters to prevent XSS attacks.
+///
+/// Unlike [sanitize_html_api()] it leaves `&` in place to avoid double escaping.
+pub fn sanitize_html_federation(data: &str) -> String {
+ data
+ .replace('<', "<")
+ .replace('\"', """)
+ .replace('\'', "'")
+}
+
+pub fn sanitize_html_federation_opt(data: &Option) -> Option {
+ data.as_ref().map(|d| sanitize_html_federation(d))
}
#[cfg(test)]
@@ -820,7 +834,7 @@ mod tests {
#![allow(clippy::unwrap_used)]
#![allow(clippy::indexing_slicing)]
- use crate::utils::{honeypot_check, password_length_check, sanitize_html};
+ use crate::utils::{honeypot_check, password_length_check};
#[test]
#[rustfmt::skip]
@@ -838,14 +852,4 @@ mod tests {
assert!(honeypot_check(&Some("1".to_string())).is_err());
assert!(honeypot_check(&Some("message".to_string())).is_err());
}
-
- #[test]
- fn test_sanitize_html() {
- let sanitized = sanitize_html(" hello");
- assert_eq!(sanitized, " hello");
- let sanitized = sanitize_html(" test");
- assert_eq!(sanitized, " test");
- let sanitized = sanitize_html("Hello World");
- assert_eq!(sanitized, "Hello World");
- }
}
diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs
index 00762a31b..3ba19d1b9 100644
--- a/crates/api_crud/src/comment/create.rs
+++ b/crates/api_crud/src/comment/create.rs
@@ -13,7 +13,7 @@ use lemmy_api_common::{
get_post,
local_site_to_slur_regex,
local_user_view_from_jwt,
- sanitize_html,
+ sanitize_html_api,
EndpointType,
},
};
@@ -52,7 +52,7 @@ pub async fn create_comment(
&local_site_to_slur_regex(&local_site),
);
is_valid_body_field(&Some(content.clone()), false)?;
- let content = sanitize_html(&content);
+ let content = sanitize_html_api(&content);
// Check for a community ban
let post_id = data.post_id;
diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs
index 16f56092f..bf6bdff84 100644
--- a/crates/api_crud/src/comment/update.rs
+++ b/crates/api_crud/src/comment/update.rs
@@ -9,7 +9,7 @@ use lemmy_api_common::{
check_community_ban,
local_site_to_slur_regex,
local_user_view_from_jwt,
- sanitize_html_opt,
+ sanitize_html_api_opt,
},
};
use lemmy_db_schema::{
@@ -68,7 +68,7 @@ pub async fn update_comment(
.as_ref()
.map(|c| remove_slurs(c, &local_site_to_slur_regex(&local_site)));
is_valid_body_field(&content, false)?;
- let content = sanitize_html_opt(&content);
+ let content = sanitize_html_api_opt(&content);
let comment_id = data.comment_id;
let form = CommentUpdateForm {
diff --git a/crates/api_crud/src/community/create.rs b/crates/api_crud/src/community/create.rs
index ef6a317e9..d6c07c128 100644
--- a/crates/api_crud/src/community/create.rs
+++ b/crates/api_crud/src/community/create.rs
@@ -12,8 +12,8 @@ use lemmy_api_common::{
is_admin,
local_site_to_slur_regex,
local_user_view_from_jwt,
- sanitize_html,
- sanitize_html_opt,
+ sanitize_html_api,
+ sanitize_html_api_opt,
EndpointType,
},
};
@@ -58,9 +58,9 @@ pub async fn create_community(
let icon = diesel_option_overwrite_to_url_create(&data.icon)?;
let banner = diesel_option_overwrite_to_url_create(&data.banner)?;
- let name = sanitize_html(&data.name);
- let title = sanitize_html(&data.title);
- let description = sanitize_html_opt(&data.description);
+ let name = sanitize_html_api(&data.name);
+ let title = sanitize_html_api(&data.title);
+ let description = sanitize_html_api_opt(&data.description);
let slur_regex = local_site_to_slur_regex(&local_site);
check_slurs(&name, &slur_regex)?;
diff --git a/crates/api_crud/src/community/update.rs b/crates/api_crud/src/community/update.rs
index b55693598..122cab94e 100644
--- a/crates/api_crud/src/community/update.rs
+++ b/crates/api_crud/src/community/update.rs
@@ -5,7 +5,7 @@ use lemmy_api_common::{
community::{CommunityResponse, EditCommunity},
context::LemmyContext,
send_activity::{ActivityChannel, SendActivityData},
- utils::{local_site_to_slur_regex, local_user_view_from_jwt, sanitize_html_opt},
+ utils::{local_site_to_slur_regex, local_user_view_from_jwt, sanitize_html_api_opt},
};
use lemmy_db_schema::{
newtypes::PersonId,
@@ -36,8 +36,8 @@ pub async fn update_community(
check_slurs_opt(&data.description, &slur_regex)?;
is_valid_body_field(&data.description, false)?;
- let title = sanitize_html_opt(&data.title);
- let description = sanitize_html_opt(&data.description);
+ let title = sanitize_html_api_opt(&data.title);
+ let description = sanitize_html_api_opt(&data.description);
let icon = diesel_option_overwrite_to_url(&data.icon)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?;
diff --git a/crates/api_crud/src/custom_emoji/create.rs b/crates/api_crud/src/custom_emoji/create.rs
index 589174455..046003627 100644
--- a/crates/api_crud/src/custom_emoji/create.rs
+++ b/crates/api_crud/src/custom_emoji/create.rs
@@ -3,7 +3,7 @@ use actix_web::web::Json;
use lemmy_api_common::{
context::LemmyContext,
custom_emoji::{CreateCustomEmoji, CustomEmojiResponse},
- utils::{is_admin, local_user_view_from_jwt, sanitize_html},
+ utils::{is_admin, local_user_view_from_jwt, sanitize_html_api},
};
use lemmy_db_schema::source::{
custom_emoji::{CustomEmoji, CustomEmojiInsertForm},
@@ -24,9 +24,9 @@ pub async fn create_custom_emoji(
// Make sure user is an admin
is_admin(&local_user_view)?;
- let shortcode = sanitize_html(data.shortcode.to_lowercase().trim());
- let alt_text = sanitize_html(&data.alt_text);
- let category = sanitize_html(&data.category);
+ let shortcode = sanitize_html_api(data.shortcode.to_lowercase().trim());
+ let alt_text = sanitize_html_api(&data.alt_text);
+ let category = sanitize_html_api(&data.category);
let emoji_form = CustomEmojiInsertForm::builder()
.local_site_id(local_site.id)
diff --git a/crates/api_crud/src/custom_emoji/update.rs b/crates/api_crud/src/custom_emoji/update.rs
index 7a2056895..965250feb 100644
--- a/crates/api_crud/src/custom_emoji/update.rs
+++ b/crates/api_crud/src/custom_emoji/update.rs
@@ -3,7 +3,7 @@ use actix_web::web::Json;
use lemmy_api_common::{
context::LemmyContext,
custom_emoji::{CustomEmojiResponse, EditCustomEmoji},
- utils::{is_admin, local_user_view_from_jwt, sanitize_html},
+ utils::{is_admin, local_user_view_from_jwt, sanitize_html_api},
};
use lemmy_db_schema::source::{
custom_emoji::{CustomEmoji, CustomEmojiUpdateForm},
@@ -24,8 +24,8 @@ pub async fn update_custom_emoji(
// Make sure user is an admin
is_admin(&local_user_view)?;
- let alt_text = sanitize_html(&data.alt_text);
- let category = sanitize_html(&data.category);
+ let alt_text = sanitize_html_api(&data.alt_text);
+ let category = sanitize_html_api(&data.category);
let emoji_form = CustomEmojiUpdateForm::builder()
.local_site_id(local_site.id)
diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs
index 9d27f5d62..d0b0f368c 100644
--- a/crates/api_crud/src/post/create.rs
+++ b/crates/api_crud/src/post/create.rs
@@ -14,8 +14,8 @@ use lemmy_api_common::{
local_site_to_slur_regex,
local_user_view_from_jwt,
mark_post_as_read,
- sanitize_html,
- sanitize_html_opt,
+ sanitize_html_api,
+ sanitize_html_api_opt,
EndpointType,
},
};
@@ -93,10 +93,10 @@ pub async fn create_post(
.map(|u| (u.title, u.description, u.embed_video_url))
.unwrap_or_default();
- let name = sanitize_html(data.name.trim());
- let body = sanitize_html_opt(&data.body);
- let embed_title = sanitize_html_opt(&embed_title);
- let embed_description = sanitize_html_opt(&embed_description);
+ let name = sanitize_html_api(data.name.trim());
+ let body = sanitize_html_api_opt(&data.body);
+ let embed_title = sanitize_html_api_opt(&embed_title);
+ let embed_description = sanitize_html_api_opt(&embed_description);
// Only need to check if language is allowed in case user set it explicitly. When using default
// language, it already only returns allowed languages.
diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs
index c475d7a26..880991b8e 100644
--- a/crates/api_crud/src/post/update.rs
+++ b/crates/api_crud/src/post/update.rs
@@ -10,7 +10,7 @@ use lemmy_api_common::{
check_community_ban,
local_site_to_slur_regex,
local_user_view_from_jwt,
- sanitize_html_opt,
+ sanitize_html_api_opt,
},
};
use lemmy_db_schema::{
@@ -79,11 +79,11 @@ pub async fn update_post(
.map(|u| (Some(u.title), Some(u.description), Some(u.embed_video_url)))
.unwrap_or_default();
- let name = sanitize_html_opt(&data.name);
- let body = sanitize_html_opt(&data.body);
+ let name = sanitize_html_api_opt(&data.name);
+ let body = sanitize_html_api_opt(&data.body);
let body = diesel_option_overwrite(body);
- let embed_title = embed_title.map(|e| sanitize_html_opt(&e));
- let embed_description = embed_description.map(|e| sanitize_html_opt(&e));
+ let embed_title = embed_title.map(|e| sanitize_html_api_opt(&e));
+ let embed_description = embed_description.map(|e| sanitize_html_api_opt(&e));
let language_id = data.language_id;
CommunityLanguage::is_allowed_community_language(
diff --git a/crates/api_crud/src/private_message/create.rs b/crates/api_crud/src/private_message/create.rs
index f5e4b15ab..1e22935ce 100644
--- a/crates/api_crud/src/private_message/create.rs
+++ b/crates/api_crud/src/private_message/create.rs
@@ -10,7 +10,7 @@ use lemmy_api_common::{
get_interface_language,
local_site_to_slur_regex,
local_user_view_from_jwt,
- sanitize_html,
+ sanitize_html_api,
send_email_to_user,
EndpointType,
},
@@ -36,7 +36,7 @@ pub async fn create_private_message(
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
let local_site = LocalSite::read(&mut context.pool()).await?;
- let content = sanitize_html(&data.content);
+ let content = sanitize_html_api(&data.content);
let content = remove_slurs(&content, &local_site_to_slur_regex(&local_site));
is_valid_body_field(&Some(content.clone()), false)?;
diff --git a/crates/api_crud/src/private_message/update.rs b/crates/api_crud/src/private_message/update.rs
index 44cc1ab3b..258dd8bcb 100644
--- a/crates/api_crud/src/private_message/update.rs
+++ b/crates/api_crud/src/private_message/update.rs
@@ -4,7 +4,7 @@ use lemmy_api_common::{
context::LemmyContext,
private_message::{EditPrivateMessage, PrivateMessageResponse},
send_activity::{ActivityChannel, SendActivityData},
- utils::{local_site_to_slur_regex, local_user_view_from_jwt, sanitize_html},
+ utils::{local_site_to_slur_regex, local_user_view_from_jwt, sanitize_html_api},
};
use lemmy_db_schema::{
source::{
@@ -36,7 +36,7 @@ pub async fn update_private_message(
}
// Doing the update
- let content = sanitize_html(&data.content);
+ let content = sanitize_html_api(&data.content);
let content = remove_slurs(&content, &local_site_to_slur_regex(&local_site));
is_valid_body_field(&Some(content.clone()), false)?;
diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs
index 78bbb64ef..5cf9a04a7 100644
--- a/crates/api_crud/src/site/create.rs
+++ b/crates/api_crud/src/site/create.rs
@@ -9,8 +9,8 @@ use lemmy_api_common::{
is_admin,
local_site_rate_limit_to_rate_limit_config,
local_user_view_from_jwt,
- sanitize_html,
- sanitize_html_opt,
+ sanitize_html_api,
+ sanitize_html_api_opt,
},
};
use lemmy_db_schema::{
@@ -56,9 +56,9 @@ pub async fn create_site(
let actor_id: DbUrl = Url::parse(&context.settings().get_protocol_and_hostname())?.into();
let inbox_url = Some(generate_site_inbox_url(&actor_id)?);
let keypair = generate_actor_keypair()?;
- let name = sanitize_html(&data.name);
- let sidebar = sanitize_html_opt(&data.sidebar);
- let description = sanitize_html_opt(&data.description);
+ let name = sanitize_html_api(&data.name);
+ let sidebar = sanitize_html_api_opt(&data.sidebar);
+ let description = sanitize_html_api_opt(&data.description);
let site_form = SiteUpdateForm {
name: Some(name),
@@ -78,9 +78,9 @@ pub async fn create_site(
Site::update(&mut context.pool(), site_id, &site_form).await?;
- let application_question = sanitize_html_opt(&data.application_question);
- let default_theme = sanitize_html_opt(&data.default_theme);
- let legal_information = sanitize_html_opt(&data.legal_information);
+ let application_question = sanitize_html_api_opt(&data.application_question);
+ let default_theme = sanitize_html_api_opt(&data.default_theme);
+ let legal_information = sanitize_html_api_opt(&data.legal_information);
let local_site_form = LocalSiteUpdateForm {
// Set the site setup to true
diff --git a/crates/api_crud/src/site/update.rs b/crates/api_crud/src/site/update.rs
index 6148d546e..4d1fbd4d9 100644
--- a/crates/api_crud/src/site/update.rs
+++ b/crates/api_crud/src/site/update.rs
@@ -7,7 +7,7 @@ use lemmy_api_common::{
is_admin,
local_site_rate_limit_to_rate_limit_config,
local_user_view_from_jwt,
- sanitize_html_opt,
+ sanitize_html_api_opt,
},
};
use lemmy_db_schema::{
@@ -59,9 +59,9 @@ pub async fn update_site(
SiteLanguage::update(&mut context.pool(), discussion_languages.clone(), &site).await?;
}
- let name = sanitize_html_opt(&data.name);
- let sidebar = sanitize_html_opt(&data.sidebar);
- let description = sanitize_html_opt(&data.description);
+ let name = sanitize_html_api_opt(&data.name);
+ let sidebar = sanitize_html_api_opt(&data.sidebar);
+ let description = sanitize_html_api_opt(&data.description);
let site_form = SiteUpdateForm {
name,
@@ -79,9 +79,9 @@ pub async fn update_site(
// Diesel will throw an error for empty update forms
.ok();
- let application_question = sanitize_html_opt(&data.application_question);
- let default_theme = sanitize_html_opt(&data.default_theme);
- let legal_information = sanitize_html_opt(&data.legal_information);
+ let application_question = sanitize_html_api_opt(&data.application_question);
+ let default_theme = sanitize_html_api_opt(&data.default_theme);
+ let legal_information = sanitize_html_api_opt(&data.legal_information);
let local_site_form = LocalSiteUpdateForm {
enable_downvotes: data.enable_downvotes,
diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs
index d855434ec..02c95cb04 100644
--- a/crates/api_crud/src/user/create.rs
+++ b/crates/api_crud/src/user/create.rs
@@ -10,7 +10,7 @@ use lemmy_api_common::{
honeypot_check,
local_site_to_slur_regex,
password_length_check,
- sanitize_html,
+ sanitize_html_api,
send_new_applicant_email_to_admins,
send_verification_email,
EndpointType,
@@ -89,7 +89,7 @@ pub async fn register(
let slur_regex = local_site_to_slur_regex(&local_site);
check_slurs(&data.username, &slur_regex)?;
check_slurs_opt(&data.answer, &slur_regex)?;
- let username = sanitize_html(&data.username);
+ let username = sanitize_html_api(&data.username);
let actor_keypair = generate_actor_keypair()?;
is_valid_actor_name(&data.username, local_site.actor_name_max_length as usize)?;
diff --git a/crates/apub/src/activities/block/block_user.rs b/crates/apub/src/activities/block/block_user.rs
index 7b14213ca..07fe0b75b 100644
--- a/crates/apub/src/activities/block/block_user.rs
+++ b/crates/apub/src/activities/block/block_user.rs
@@ -23,7 +23,7 @@ use anyhow::anyhow;
use chrono::{DateTime, Utc};
use lemmy_api_common::{
context::LemmyContext,
- utils::{remove_user_data, remove_user_data_in_community, sanitize_html_opt},
+ utils::{remove_user_data, remove_user_data_in_community, sanitize_html_federation_opt},
};
use lemmy_db_schema::{
source::{
@@ -172,7 +172,7 @@ impl ActivityHandler for BlockUser {
let form = ModBanForm {
mod_person_id: mod_person.id,
other_person_id: blocked_person.id,
- reason: sanitize_html_opt(&self.summary),
+ reason: sanitize_html_federation_opt(&self.summary),
banned: Some(true),
expires,
};
@@ -206,7 +206,7 @@ impl ActivityHandler for BlockUser {
mod_person_id: mod_person.id,
other_person_id: blocked_person.id,
community_id: community.id,
- reason: sanitize_html_opt(&self.summary),
+ reason: sanitize_html_federation_opt(&self.summary),
banned: Some(true),
expires,
};
diff --git a/crates/apub/src/activities/block/undo_block_user.rs b/crates/apub/src/activities/block/undo_block_user.rs
index 5f6bf84cb..889d6a286 100644
--- a/crates/apub/src/activities/block/undo_block_user.rs
+++ b/crates/apub/src/activities/block/undo_block_user.rs
@@ -17,7 +17,7 @@ use activitypub_federation::{
protocol::verification::verify_domains_match,
traits::{ActivityHandler, Actor},
};
-use lemmy_api_common::{context::LemmyContext, utils::sanitize_html_opt};
+use lemmy_api_common::{context::LemmyContext, utils::sanitize_html_federation_opt};
use lemmy_db_schema::{
source::{
community::{CommunityPersonBan, CommunityPersonBanForm},
@@ -117,7 +117,7 @@ impl ActivityHandler for UndoBlockUser {
let form = ModBanForm {
mod_person_id: mod_person.id,
other_person_id: blocked_person.id,
- reason: sanitize_html_opt(&self.object.summary),
+ reason: sanitize_html_federation_opt(&self.object.summary),
banned: Some(false),
expires,
};
@@ -136,7 +136,7 @@ impl ActivityHandler for UndoBlockUser {
mod_person_id: mod_person.id,
other_person_id: blocked_person.id,
community_id: community.id,
- reason: sanitize_html_opt(&self.object.summary),
+ reason: sanitize_html_federation_opt(&self.object.summary),
banned: Some(false),
expires,
};
diff --git a/crates/apub/src/activities/community/report.rs b/crates/apub/src/activities/community/report.rs
index a17df7119..16f8c3bdf 100644
--- a/crates/apub/src/activities/community/report.rs
+++ b/crates/apub/src/activities/community/report.rs
@@ -11,7 +11,7 @@ use activitypub_federation::{
kinds::activity::FlagType,
traits::{ActivityHandler, Actor},
};
-use lemmy_api_common::{context::LemmyContext, utils::sanitize_html};
+use lemmy_api_common::{context::LemmyContext, utils::sanitize_html_federation};
use lemmy_db_schema::{
source::{
comment_report::{CommentReport, CommentReportForm},
@@ -86,7 +86,7 @@ impl ActivityHandler for Report {
post_id: post.id,
original_post_name: post.name.clone(),
original_post_url: post.url.clone(),
- reason: sanitize_html(&self.summary),
+ reason: sanitize_html_federation(&self.summary),
original_post_body: post.body.clone(),
};
PostReport::report(&mut context.pool(), &report_form).await?;
@@ -96,7 +96,7 @@ impl ActivityHandler for Report {
creator_id: actor.id,
comment_id: comment.id,
original_comment_text: comment.content.clone(),
- reason: sanitize_html(&self.summary),
+ reason: sanitize_html_federation(&self.summary),
};
CommentReport::report(&mut context.pool(), &report_form).await?;
}
diff --git a/crates/apub/src/activities/deletion/delete.rs b/crates/apub/src/activities/deletion/delete.rs
index af289640b..88bf2b523 100644
--- a/crates/apub/src/activities/deletion/delete.rs
+++ b/crates/apub/src/activities/deletion/delete.rs
@@ -8,7 +8,7 @@ use crate::{
protocol::{activities::deletion::delete::Delete, IdOrNestedObject},
};
use activitypub_federation::{config::Data, kinds::activity::DeleteType, traits::ActivityHandler};
-use lemmy_api_common::{context::LemmyContext, utils::sanitize_html_opt};
+use lemmy_api_common::{context::LemmyContext, utils::sanitize_html_federation_opt};
use lemmy_db_schema::{
source::{
comment::{Comment, CommentUpdateForm},
@@ -105,7 +105,7 @@ pub(in crate::activities) async fn receive_remove_action(
reason: Option,
context: &Data,
) -> Result<(), LemmyError> {
- let reason = sanitize_html_opt(&reason);
+ let reason = sanitize_html_federation_opt(&reason);
match DeletableObjects::read_from_db(object, context).await? {
DeletableObjects::Community(community) => {
diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs
index 888e0fffb..599dd7387 100644
--- a/crates/apub/src/objects/comment.rs
+++ b/crates/apub/src/objects/comment.rs
@@ -18,7 +18,7 @@ use activitypub_federation::{
use chrono::{DateTime, Utc};
use lemmy_api_common::{
context::LemmyContext,
- utils::{local_site_opt_to_slur_regex, sanitize_html},
+ utils::{local_site_opt_to_slur_regex, sanitize_html_federation},
};
use lemmy_db_schema::{
source::{
@@ -162,7 +162,7 @@ impl Object for ApubComment {
let local_site = LocalSite::read(&mut context.pool()).await.ok();
let slur_regex = &local_site_opt_to_slur_regex(&local_site);
let content = remove_slurs(&content, slur_regex);
- let content = sanitize_html(&content);
+ let content = sanitize_html_federation(&content);
let language_id =
LanguageTag::to_language_id_single(note.language, &mut context.pool()).await?;
diff --git a/crates/apub/src/objects/instance.rs b/crates/apub/src/objects/instance.rs
index 5cbe75eda..72c21e518 100644
--- a/crates/apub/src/objects/instance.rs
+++ b/crates/apub/src/objects/instance.rs
@@ -18,7 +18,7 @@ use activitypub_federation::{
use chrono::{DateTime, Utc};
use lemmy_api_common::{
context::LemmyContext,
- utils::{local_site_opt_to_slur_regex, sanitize_html_opt},
+ utils::{local_site_opt_to_slur_regex, sanitize_html_federation_opt},
};
use lemmy_db_schema::{
newtypes::InstanceId,
@@ -133,8 +133,8 @@ impl Object for ApubSite {
let instance = DbInstance::read_or_create(&mut data.pool(), domain.to_string()).await?;
let sidebar = read_from_string_or_source_opt(&apub.content, &None, &apub.source);
- let sidebar = sanitize_html_opt(&sidebar);
- let description = sanitize_html_opt(&apub.summary);
+ let sidebar = sanitize_html_federation_opt(&sidebar);
+ let description = sanitize_html_federation_opt(&apub.summary);
let site_form = SiteInsertForm {
name: apub.name.clone(),
diff --git a/crates/apub/src/objects/person.rs b/crates/apub/src/objects/person.rs
index a0e7f590a..c5468e432 100644
--- a/crates/apub/src/objects/person.rs
+++ b/crates/apub/src/objects/person.rs
@@ -19,7 +19,12 @@ use activitypub_federation::{
use chrono::{DateTime, Utc};
use lemmy_api_common::{
context::LemmyContext,
- utils::{generate_outbox_url, local_site_opt_to_slur_regex, sanitize_html, sanitize_html_opt},
+ utils::{
+ generate_outbox_url,
+ local_site_opt_to_slur_regex,
+ sanitize_html_federation,
+ sanitize_html_federation_opt,
+ },
};
use lemmy_db_schema::{
source::person::{Person as DbPerson, PersonInsertForm, PersonUpdateForm},
@@ -141,10 +146,10 @@ impl Object for ApubPerson {
) -> Result {
let instance_id = fetch_instance_actor_for_object(&person.id, context).await?;
- let name = sanitize_html(&person.preferred_username);
- let display_name = sanitize_html_opt(&person.name);
+ let name = sanitize_html_federation(&person.preferred_username);
+ let display_name = sanitize_html_federation_opt(&person.name);
let bio = read_from_string_or_source_opt(&person.summary, &None, &person.source);
- let bio = sanitize_html_opt(&bio);
+ let bio = sanitize_html_federation_opt(&bio);
// Some Mastodon users have `name: ""` (empty string), need to convert that to `None`
// https://github.com/mastodon/mastodon/issues/25233
@@ -260,7 +265,7 @@ pub(crate) mod tests {
assert_eq!(person.name, "lanodan");
assert!(!person.local);
assert_eq!(context.request_count(), 0);
- assert_eq!(person.bio.as_ref().unwrap().len(), 873);
+ assert_eq!(person.bio.as_ref().unwrap().len(), 878);
cleanup((person, site), &context).await;
}
diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs
index aee2eaf90..29867fced 100644
--- a/crates/apub/src/objects/post.rs
+++ b/crates/apub/src/objects/post.rs
@@ -29,8 +29,8 @@ use lemmy_api_common::{
is_mod_or_admin,
local_site_opt_to_sensitive,
local_site_opt_to_slur_regex,
- sanitize_html,
- sanitize_html_opt,
+ sanitize_html_federation,
+ sanitize_html_federation_opt,
},
};
use lemmy_db_schema::{
@@ -237,9 +237,9 @@ impl Object for ApubPost {
let language_id =
LanguageTag::to_language_id_single(page.language, &mut context.pool()).await?;
- let name = sanitize_html(&name);
- let embed_title = sanitize_html_opt(&embed_title);
- let embed_description = sanitize_html_opt(&embed_description);
+ let name = sanitize_html_federation(&name);
+ let embed_title = sanitize_html_federation_opt(&embed_title);
+ let embed_description = sanitize_html_federation_opt(&embed_description);
PostInsertForm {
name,
diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs
index 3d637d624..97bf595d5 100644
--- a/crates/apub/src/objects/private_message.rs
+++ b/crates/apub/src/objects/private_message.rs
@@ -14,7 +14,7 @@ use activitypub_federation::{
use chrono::{DateTime, Utc};
use lemmy_api_common::{
context::LemmyContext,
- utils::{check_person_block, sanitize_html},
+ utils::{check_person_block, sanitize_html_federation},
};
use lemmy_db_schema::{
source::{
@@ -125,7 +125,7 @@ impl Object for ApubPrivateMessage {
check_person_block(creator.id, recipient.id, &mut context.pool()).await?;
let content = read_from_string_or_source(¬e.content, &None, ¬e.source);
- let content = sanitize_html(&content);
+ let content = sanitize_html_federation(&content);
let form = PrivateMessageInsertForm {
creator_id: creator.id,
diff --git a/crates/apub/src/protocol/objects/group.rs b/crates/apub/src/protocol/objects/group.rs
index 3ee788f94..9d0229785 100644
--- a/crates/apub/src/protocol/objects/group.rs
+++ b/crates/apub/src/protocol/objects/group.rs
@@ -25,7 +25,7 @@ use activitypub_federation::{
use chrono::{DateTime, Utc};
use lemmy_api_common::{
context::LemmyContext,
- utils::{local_site_opt_to_slur_regex, sanitize_html, sanitize_html_opt},
+ utils::{local_site_opt_to_slur_regex, sanitize_html_federation, sanitize_html_federation_opt},
};
use lemmy_db_schema::{
newtypes::InstanceId,
@@ -97,10 +97,10 @@ impl Group {
}
pub(crate) fn into_insert_form(self, instance_id: InstanceId) -> CommunityInsertForm {
- let name = sanitize_html(&self.preferred_username);
- let title = sanitize_html(&self.name.unwrap_or(self.preferred_username));
+ let name = sanitize_html_federation(&self.preferred_username);
+ let title = sanitize_html_federation(&self.name.unwrap_or(self.preferred_username));
let description = read_from_string_or_source_opt(&self.summary, &None, &self.source);
- let description = sanitize_html_opt(&description);
+ let description = sanitize_html_federation_opt(&description);
CommunityInsertForm {
name,
diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs
index e5901200f..ffcdbebe8 100644
--- a/crates/db_schema/src/schema.rs
+++ b/crates/db_schema/src/schema.rs
@@ -299,16 +299,6 @@ diesel::table! {
}
}
-diesel::table! {
- image_upload (id) {
- id -> Int4,
- local_user_id -> Int4,
- pictrs_alias -> Text,
- pictrs_delete_token -> Text,
- published -> Timestamptz,
- }
-}
-
diesel::table! {
instance (id) {
id -> Int4,
@@ -415,9 +405,9 @@ diesel::table! {
totp_2fa_secret -> Nullable,
totp_2fa_url -> Nullable,
open_links_in_new_tab -> Bool,
- infinite_scroll_enabled -> Bool,
blur_nsfw -> Bool,
auto_expand -> Bool,
+ infinite_scroll_enabled -> Bool,
admin -> Bool,
post_listing_mode -> PostListingModeEnum,
}
@@ -903,7 +893,6 @@ diesel::joinable!(custom_emoji_keyword -> custom_emoji (custom_emoji_id));
diesel::joinable!(email_verification -> local_user (local_user_id));
diesel::joinable!(federation_allowlist -> instance (instance_id));
diesel::joinable!(federation_blocklist -> instance (instance_id));
-diesel::joinable!(image_upload -> local_user (local_user_id));
diesel::joinable!(local_site -> site (site_id));
diesel::joinable!(local_site_rate_limit -> local_site (local_site_id));
diesel::joinable!(local_user -> person (person_id));
@@ -978,7 +967,6 @@ diesel::allow_tables_to_appear_in_same_query!(
email_verification,
federation_allowlist,
federation_blocklist,
- image_upload,
instance,
language,
local_site,