Merge branch 'main' into add_bio_federation

This commit is contained in:
Dessalines 2020-08-04 11:00:42 -04:00
commit 891315610e
15 changed files with 442 additions and 947 deletions

85
server/Cargo.lock generated vendored
View file

@ -110,9 +110,9 @@ dependencies = [
[[package]] [[package]]
name = "actix-http" name = "actix-http"
version = "2.0.0-beta.1" version = "2.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33f501768e82e8548763b7f55309e2f8bcc7f9f4273c75b47af99ac2b2581f37" checksum = "44529cd6813ebf4a2f2a6ea36ffe88a0e4b0bc08b26ad0b8f7f4581d4d4f3247"
dependencies = [ dependencies = [
"actix-codec", "actix-codec",
"actix-connect", "actix-connect",
@ -386,9 +386,9 @@ checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
[[package]] [[package]]
name = "adler32" name = "adler32"
version = "1.1.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
@ -468,9 +468,9 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]] [[package]]
name = "awc" name = "awc"
version = "2.0.0-beta.1" version = "2.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374057b508d4083208996be82141891c2e14c8885f45991b21c1621200ab6df3" checksum = "eafb5c150b1dc89bf6aa5907ed6900534320c41920b5d6f13ff3ddb40f14dfac"
dependencies = [ dependencies = [
"actix-codec", "actix-codec",
"actix-http", "actix-http",
@ -812,12 +812,13 @@ dependencies = [
[[package]] [[package]]
name = "cookie" name = "cookie"
version = "0.14.1" version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca761767cf3fa9068cc893ec8c247a22d0fd0535848e65640c0548bd1f8bbb36" checksum = "1373a16a4937bc34efec7b391f9c1500c30b8478a701a4f44c9165cc0475a6e0"
dependencies = [ dependencies = [
"percent-encoding", "percent-encoding",
"time 0.2.16", "time 0.2.16",
"version_check 0.9.2",
] ]
[[package]] [[package]]
@ -1647,9 +1648,9 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.42" version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52732a3d3ad72c58ad2dc70624f9c17b46ecd0943b9a4f1ee37c4c18c5d983e2" checksum = "85a7e2c92a4804dd459b86c339278d0fe87cf93757fae222c3fa3ae75458bc73"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
@ -1821,9 +1822,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.73" version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9" checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10"
[[package]] [[package]]
name = "linked-hash-map" name = "linked-hash-map"
@ -2311,18 +2312,18 @@ dependencies = [
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "0.4.22" version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17" checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa"
dependencies = [ dependencies = [
"pin-project-internal", "pin-project-internal",
] ]
[[package]] [[package]]
name = "pin-project-internal" name = "pin-project-internal"
version = "0.4.22" version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7" checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2376,9 +2377,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro-hack" name = "proc-macro-hack"
version = "0.5.16" version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598"
[[package]] [[package]]
name = "proc-macro-nested" name = "proc-macro-nested"
@ -2872,9 +2873,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.56" version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"itoa", "itoa",
@ -3094,9 +3095,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.35" version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0" checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3229,9 +3230,9 @@ checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "0.2.21" version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d099fa27b9702bed751524694adbe393e18b36b204da91eb1cbbbbb4a5ee2d58" checksum = "5d34ca54d84bf2b5b4d7d31e901a8464f7b60ac145a284fba25ceb801f2ddccd"
dependencies = [ dependencies = [
"bytes", "bytes",
"fnv", "fnv",
@ -3291,9 +3292,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.16" version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e2a2de6b0d5cbb13fc21193a2296888eaab62b6044479aafb3c54c01c29fcd" checksum = "f0aae59226cf195d8e74d4b34beae1859257efb4e5fed3f147d2dc2c7d372178"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"log", "log",
@ -3302,9 +3303,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.11" version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94ae75f0d28ae10786f3b1895c55fe72e79928fd5ccdebb5438c75e93fec178f" checksum = "b2734b5a028fa697686f16c6d18c2c6a3c7e41513f9a213abb6754c4acb3c8d7"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
] ]
@ -3473,9 +3474,9 @@ dependencies = [
[[package]] [[package]]
name = "v_escape" name = "v_escape"
version = "0.12.0" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b66158ce426982197fd44266d68125fd4000f1d42f5ee33ef02b500b4b6b0024" checksum = "7b2d5ca56f0412d5ad5e642202e5c8fb61b61ad39435a53ed501fbd45380e8d3"
dependencies = [ dependencies = [
"buf-min", "buf-min",
"v_escape_derive", "v_escape_derive",
@ -3535,9 +3536,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.65" version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3edbcc9536ab7eababcc6d2374a0b7bfe13a2b6d562c5e07f370456b1a8f33d" checksum = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"wasm-bindgen-macro", "wasm-bindgen-macro",
@ -3545,9 +3546,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.65" version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ed2fb8c84bfad20ea66b26a3743f3e7ba8735a69fe7d95118c33ec8fc1244d" checksum = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"lazy_static", "lazy_static",
@ -3560,9 +3561,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.65" version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb071268b031a64d92fc6cf691715ca5a40950694d8f683c5bb43db7c730929e" checksum = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -3570,9 +3571,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.65" version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf592c807080719d1ff2f245a687cbadb3ed28b2077ed7084b47aba8b691f2c6" checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3583,15 +3584,15 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.65" version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b6c0220ded549d63860c78c38f3bcc558d1ca3f4efa74942c536ddbbb55e87" checksum = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092"
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.42" version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8be2398f326b7ba09815d0b403095f34dd708579220d099caae89be0b32137b2" checksum = "dda38f4e5ca63eda02c059d243aa25b5f35ab98451e518c51612cd0f1bd19a47"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",

View file

@ -1,5 +1,13 @@
use crate::{ use crate::{
api::{claims::Claims, is_mod_or_admin, APIError, Oper, Perform}, api::{
check_community_ban,
get_user_from_jwt,
get_user_from_jwt_opt,
is_mod_or_admin,
APIError,
Oper,
Perform,
},
apub::{ApubLikeableType, ApubObjectType}, apub::{ApubLikeableType, ApubObjectType},
blocking, blocking,
websocket::{ websocket::{
@ -13,7 +21,6 @@ use crate::{
use lemmy_db::{ use lemmy_db::{
comment::*, comment::*,
comment_view::*, comment_view::*,
community_view::*,
moderator::*, moderator::*,
post::*, post::*,
site_view::*, site_view::*,
@ -123,13 +130,7 @@ impl Perform for Oper<CreateComment> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<CommentResponse, LemmyError> { ) -> Result<CommentResponse, LemmyError> {
let data: &CreateComment = &self.data; let data: &CreateComment = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let content_slurs_removed = remove_slurs(&data.content.to_owned()); let content_slurs_removed = remove_slurs(&data.content.to_owned());
@ -137,7 +138,7 @@ impl Perform for Oper<CreateComment> {
content: content_slurs_removed, content: content_slurs_removed,
parent_id: data.parent_id.to_owned(), parent_id: data.parent_id.to_owned(),
post_id: data.post_id, post_id: data.post_id,
creator_id: user_id, creator_id: user.id,
removed: None, removed: None,
deleted: None, deleted: None,
read: None, read: None,
@ -151,18 +152,7 @@ impl Perform for Oper<CreateComment> {
let post_id = data.post_id; let post_id = data.post_id;
let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??; let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??;
let community_id = post.community_id; check_community_ban(user.id, post.community_id, pool).await?;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Check for a site ban
let user = blocking(pool, move |conn| User_::read(&conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Check if post is locked, no new comments // Check if post is locked, no new comments
if post.locked { if post.locked {
@ -203,7 +193,7 @@ impl Perform for Oper<CreateComment> {
let like_form = CommentLikeForm { let like_form = CommentLikeForm {
comment_id: inserted_comment.id, comment_id: inserted_comment.id,
post_id: data.post_id, post_id: data.post_id,
user_id, user_id: user.id,
score: 1, score: 1,
}; };
@ -214,6 +204,7 @@ impl Perform for Oper<CreateComment> {
updated_comment.send_like(&user, &self.client, pool).await?; updated_comment.send_like(&user, &self.client, pool).await?;
let user_id = user.id;
let comment_view = blocking(pool, move |conn| { let comment_view = blocking(pool, move |conn| {
CommentView::read(&conn, inserted_comment.id, Some(user_id)) CommentView::read(&conn, inserted_comment.id, Some(user_id))
}) })
@ -251,34 +242,16 @@ impl Perform for Oper<EditComment> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<CommentResponse, LemmyError> { ) -> Result<CommentResponse, LemmyError> {
let data: &EditComment = &self.data; let data: &EditComment = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let edit_id = data.edit_id; let edit_id = data.edit_id;
let orig_comment = let orig_comment =
blocking(pool, move |conn| CommentView::read(&conn, edit_id, None)).await??; blocking(pool, move |conn| CommentView::read(&conn, edit_id, None)).await??;
// Check for a site ban check_community_ban(user.id, orig_comment.community_id, pool).await?;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Check for a community ban
let community_id = orig_comment.community_id;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Verify that only the creator can edit // Verify that only the creator can edit
if user_id != orig_comment.creator_id { if user.id != orig_comment.creator_id {
return Err(APIError::err("no_comment_edit_allowed").into()); return Err(APIError::err("no_comment_edit_allowed").into());
} }
@ -309,6 +282,7 @@ impl Perform for Oper<EditComment> {
send_local_notifs(mentions, updated_comment, &user, post, pool, false).await?; send_local_notifs(mentions, updated_comment, &user, post, pool, false).await?;
let edit_id = data.edit_id; let edit_id = data.edit_id;
let user_id = user.id;
let comment_view = blocking(pool, move |conn| { let comment_view = blocking(pool, move |conn| {
CommentView::read(conn, edit_id, Some(user_id)) CommentView::read(conn, edit_id, Some(user_id))
}) })
@ -346,34 +320,16 @@ impl Perform for Oper<DeleteComment> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<CommentResponse, LemmyError> { ) -> Result<CommentResponse, LemmyError> {
let data: &DeleteComment = &self.data; let data: &DeleteComment = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let edit_id = data.edit_id; let edit_id = data.edit_id;
let orig_comment = let orig_comment =
blocking(pool, move |conn| CommentView::read(&conn, edit_id, None)).await??; blocking(pool, move |conn| CommentView::read(&conn, edit_id, None)).await??;
// Check for a site ban check_community_ban(user.id, orig_comment.community_id, pool).await?;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Check for a community ban
let community_id = orig_comment.community_id;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Verify that only the creator can delete // Verify that only the creator can delete
if user_id != orig_comment.creator_id { if user.id != orig_comment.creator_id {
return Err(APIError::err("no_comment_edit_allowed").into()); return Err(APIError::err("no_comment_edit_allowed").into());
} }
@ -401,6 +357,7 @@ impl Perform for Oper<DeleteComment> {
// Refetch it // Refetch it
let edit_id = data.edit_id; let edit_id = data.edit_id;
let user_id = user.id;
let comment_view = blocking(pool, move |conn| { let comment_view = blocking(pool, move |conn| {
CommentView::read(conn, edit_id, Some(user_id)) CommentView::read(conn, edit_id, Some(user_id))
}) })
@ -445,34 +402,16 @@ impl Perform for Oper<RemoveComment> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<CommentResponse, LemmyError> { ) -> Result<CommentResponse, LemmyError> {
let data: &RemoveComment = &self.data; let data: &RemoveComment = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let edit_id = data.edit_id; let edit_id = data.edit_id;
let orig_comment = let orig_comment =
blocking(pool, move |conn| CommentView::read(&conn, edit_id, None)).await??; blocking(pool, move |conn| CommentView::read(&conn, edit_id, None)).await??;
// Check for a site ban check_community_ban(user.id, orig_comment.community_id, pool).await?;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Check for a community ban
let community_id = orig_comment.community_id;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Verify that only a mod or admin can remove // Verify that only a mod or admin can remove
is_mod_or_admin(pool, user_id, community_id).await?; is_mod_or_admin(pool, user.id, orig_comment.community_id).await?;
// Do the remove // Do the remove
let removed = data.removed; let removed = data.removed;
@ -487,7 +426,7 @@ impl Perform for Oper<RemoveComment> {
// Mod tables // Mod tables
let form = ModRemoveCommentForm { let form = ModRemoveCommentForm {
mod_user_id: user_id, mod_user_id: user.id,
comment_id: data.edit_id, comment_id: data.edit_id,
removed: Some(removed), removed: Some(removed),
reason: data.reason.to_owned(), reason: data.reason.to_owned(),
@ -507,6 +446,7 @@ impl Perform for Oper<RemoveComment> {
// Refetch it // Refetch it
let edit_id = data.edit_id; let edit_id = data.edit_id;
let user_id = user.id;
let comment_view = blocking(pool, move |conn| { let comment_view = blocking(pool, move |conn| {
CommentView::read(conn, edit_id, Some(user_id)) CommentView::read(conn, edit_id, Some(user_id))
}) })
@ -551,31 +491,13 @@ impl Perform for Oper<MarkCommentAsRead> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<CommentResponse, LemmyError> { ) -> Result<CommentResponse, LemmyError> {
let data: &MarkCommentAsRead = &self.data; let data: &MarkCommentAsRead = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let edit_id = data.edit_id; let edit_id = data.edit_id;
let orig_comment = let orig_comment =
blocking(pool, move |conn| CommentView::read(&conn, edit_id, None)).await??; blocking(pool, move |conn| CommentView::read(&conn, edit_id, None)).await??;
// Check for a site ban check_community_ban(user.id, orig_comment.community_id, pool).await?;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Check for a community ban
let community_id = orig_comment.community_id;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Verify that only the recipient can mark as read // Verify that only the recipient can mark as read
// Needs to fetch the parent comment / post to get the recipient // Needs to fetch the parent comment / post to get the recipient
@ -584,14 +506,14 @@ impl Perform for Oper<MarkCommentAsRead> {
Some(pid) => { Some(pid) => {
let parent_comment = let parent_comment =
blocking(pool, move |conn| CommentView::read(&conn, pid, None)).await??; blocking(pool, move |conn| CommentView::read(&conn, pid, None)).await??;
if user_id != parent_comment.creator_id { if user.id != parent_comment.creator_id {
return Err(APIError::err("no_comment_edit_allowed").into()); return Err(APIError::err("no_comment_edit_allowed").into());
} }
} }
None => { None => {
let parent_post_id = orig_comment.post_id; let parent_post_id = orig_comment.post_id;
let parent_post = blocking(pool, move |conn| Post::read(conn, parent_post_id)).await??; let parent_post = blocking(pool, move |conn| Post::read(conn, parent_post_id)).await??;
if user_id != parent_post.creator_id { if user.id != parent_post.creator_id {
return Err(APIError::err("no_comment_edit_allowed").into()); return Err(APIError::err("no_comment_edit_allowed").into());
} }
} }
@ -606,6 +528,7 @@ impl Perform for Oper<MarkCommentAsRead> {
// Refetch it // Refetch it
let edit_id = data.edit_id; let edit_id = data.edit_id;
let user_id = user.id;
let comment_view = blocking(pool, move |conn| { let comment_view = blocking(pool, move |conn| {
CommentView::read(conn, edit_id, Some(user_id)) CommentView::read(conn, edit_id, Some(user_id))
}) })
@ -631,17 +554,11 @@ impl Perform for Oper<SaveComment> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<CommentResponse, LemmyError> { ) -> Result<CommentResponse, LemmyError> {
let data: &SaveComment = &self.data; let data: &SaveComment = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let comment_saved_form = CommentSavedForm { let comment_saved_form = CommentSavedForm {
comment_id: data.comment_id, comment_id: data.comment_id,
user_id, user_id: user.id,
}; };
if data.save { if data.save {
@ -657,6 +574,7 @@ impl Perform for Oper<SaveComment> {
} }
let comment_id = data.comment_id; let comment_id = data.comment_id;
let user_id = user.id;
let comment_view = blocking(pool, move |conn| { let comment_view = blocking(pool, move |conn| {
CommentView::read(conn, comment_id, Some(user_id)) CommentView::read(conn, comment_id, Some(user_id))
}) })
@ -680,13 +598,7 @@ impl Perform for Oper<CreateCommentLike> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<CommentResponse, LemmyError> { ) -> Result<CommentResponse, LemmyError> {
let data: &CreateCommentLike = &self.data; let data: &CreateCommentLike = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let mut recipient_ids = Vec::new(); let mut recipient_ids = Vec::new();
@ -702,21 +614,9 @@ impl Perform for Oper<CreateCommentLike> {
let orig_comment = let orig_comment =
blocking(pool, move |conn| CommentView::read(&conn, comment_id, None)).await??; blocking(pool, move |conn| CommentView::read(&conn, comment_id, None)).await??;
// Check for a community ban
let post_id = orig_comment.post_id; let post_id = orig_comment.post_id;
let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??; let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??;
let community_id = post.community_id; check_community_ban(user.id, post.community_id, pool).await?;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Check for a site ban
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
let comment_id = data.comment_id; let comment_id = data.comment_id;
let comment = blocking(pool, move |conn| Comment::read(conn, comment_id)).await??; let comment = blocking(pool, move |conn| Comment::read(conn, comment_id)).await??;
@ -725,7 +625,7 @@ impl Perform for Oper<CreateCommentLike> {
match comment.parent_id { match comment.parent_id {
Some(parent_id) => { Some(parent_id) => {
let parent_comment = blocking(pool, move |conn| Comment::read(conn, parent_id)).await??; let parent_comment = blocking(pool, move |conn| Comment::read(conn, parent_id)).await??;
if parent_comment.creator_id != user_id { if parent_comment.creator_id != user.id {
let parent_user = blocking(pool, move |conn| { let parent_user = blocking(pool, move |conn| {
User_::read(conn, parent_comment.creator_id) User_::read(conn, parent_comment.creator_id)
}) })
@ -741,7 +641,7 @@ impl Perform for Oper<CreateCommentLike> {
let like_form = CommentLikeForm { let like_form = CommentLikeForm {
comment_id: data.comment_id, comment_id: data.comment_id,
post_id, post_id,
user_id, user_id: user.id,
score: data.score, score: data.score,
}; };
@ -769,6 +669,7 @@ impl Perform for Oper<CreateCommentLike> {
// Have to refetch the comment to get the current state // Have to refetch the comment to get the current state
let comment_id = data.comment_id; let comment_id = data.comment_id;
let user_id = user.id;
let liked_comment = blocking(pool, move |conn| { let liked_comment = blocking(pool, move |conn| {
CommentView::read(conn, comment_id, Some(user_id)) CommentView::read(conn, comment_id, Some(user_id))
}) })
@ -806,19 +707,8 @@ impl Perform for Oper<GetComments> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<GetCommentsResponse, LemmyError> { ) -> Result<GetCommentsResponse, LemmyError> {
let data: &GetComments = &self.data; let data: &GetComments = &self.data;
let user = get_user_from_jwt_opt(&data.auth, pool).await?;
let user_claims: Option<Claims> = match &data.auth { let user_id = user.map(|u| u.id);
Some(auth) => match Claims::decode(&auth) {
Ok(claims) => Some(claims.claims),
Err(_e) => None,
},
None => None,
};
let user_id = match &user_claims {
Some(claims) => Some(claims.id),
None => None,
};
let type_ = ListingType::from_str(&data.type_)?; let type_ = ListingType::from_str(&data.type_)?;
let sort = SortType::from_str(&data.sort)?; let sort = SortType::from_str(&data.sort)?;

View file

@ -1,6 +1,6 @@
use super::*; use super::*;
use crate::{ use crate::{
api::{claims::Claims, is_admin, is_mod_or_admin, APIError, Oper, Perform}, api::{is_admin, is_mod_or_admin, APIError, Oper, Perform},
apub::ActorType, apub::ActorType,
blocking, blocking,
websocket::{ websocket::{
@ -16,8 +16,6 @@ use lemmy_utils::{
is_valid_community_name, is_valid_community_name,
make_apub_endpoint, make_apub_endpoint,
naive_from_unix, naive_from_unix,
slur_check,
slurs_vec_to_str,
EndpointType, EndpointType,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -154,17 +152,8 @@ impl Perform for Oper<GetCommunity> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<GetCommunityResponse, LemmyError> { ) -> Result<GetCommunityResponse, LemmyError> {
let data: &GetCommunity = &self.data; let data: &GetCommunity = &self.data;
let user = get_user_from_jwt_opt(&data.auth, pool).await?;
let user_id: Option<i32> = match &data.auth { let user_id = user.map(|u| u.id);
Some(auth) => match Claims::decode(&auth) {
Ok(claims) => {
let user_id = claims.claims.id;
Some(user_id)
}
Err(_e) => None,
},
None => None,
};
let name = data.name.to_owned().unwrap_or_else(|| "main".to_string()); let name = data.name.to_owned().unwrap_or_else(|| "main".to_string());
let community = match data.id { let community = match data.id {
@ -234,38 +223,16 @@ impl Perform for Oper<CreateCommunity> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<CommunityResponse, LemmyError> { ) -> Result<CommunityResponse, LemmyError> {
let data: &CreateCommunity = &self.data; let data: &CreateCommunity = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) { check_slurs(&data.name)?;
Ok(claims) => claims.claims, check_slurs(&data.title)?;
Err(_e) => return Err(APIError::err("not_logged_in").into()), check_slurs_opt(&data.description)?;
};
if let Err(slurs) = slur_check(&data.name) {
return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
}
if let Err(slurs) = slur_check(&data.title) {
return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
}
if let Some(description) = &data.description {
if let Err(slurs) = slur_check(description) {
return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
}
}
if !is_valid_community_name(&data.name) { if !is_valid_community_name(&data.name) {
return Err(APIError::err("invalid_community_name").into()); return Err(APIError::err("invalid_community_name").into());
} }
let user_id = claims.id;
// Check for a site ban
let user_view = blocking(pool, move |conn| UserView::read(conn, user_id)).await??;
if user_view.banned {
return Err(APIError::err("site_ban").into());
}
// Double check for duplicate community actor_ids // Double check for duplicate community actor_ids
let actor_id = make_apub_endpoint(EndpointType::Community, &data.name).to_string(); let actor_id = make_apub_endpoint(EndpointType::Community, &data.name).to_string();
let actor_id_cloned = actor_id.to_owned(); let actor_id_cloned = actor_id.to_owned();
@ -285,7 +252,7 @@ impl Perform for Oper<CreateCommunity> {
title: data.title.to_owned(), title: data.title.to_owned(),
description: data.description.to_owned(), description: data.description.to_owned(),
category_id: data.category_id, category_id: data.category_id,
creator_id: user_id, creator_id: user.id,
removed: None, removed: None,
deleted: None, deleted: None,
nsfw: data.nsfw, nsfw: data.nsfw,
@ -306,7 +273,7 @@ impl Perform for Oper<CreateCommunity> {
let community_moderator_form = CommunityModeratorForm { let community_moderator_form = CommunityModeratorForm {
community_id: inserted_community.id, community_id: inserted_community.id,
user_id, user_id: user.id,
}; };
let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form);
@ -316,7 +283,7 @@ impl Perform for Oper<CreateCommunity> {
let community_follower_form = CommunityFollowerForm { let community_follower_form = CommunityFollowerForm {
community_id: inserted_community.id, community_id: inserted_community.id,
user_id, user_id: user.id,
}; };
let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form); let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form);
@ -324,6 +291,7 @@ impl Perform for Oper<CreateCommunity> {
return Err(APIError::err("community_follower_already_exists").into()); return Err(APIError::err("community_follower_already_exists").into());
} }
let user_id = user.id;
let community_view = blocking(pool, move |conn| { let community_view = blocking(pool, move |conn| {
CommunityView::read(conn, inserted_community.id, Some(user_id)) CommunityView::read(conn, inserted_community.id, Some(user_id))
}) })
@ -345,29 +313,10 @@ impl Perform for Oper<EditCommunity> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<CommunityResponse, LemmyError> { ) -> Result<CommunityResponse, LemmyError> {
let data: &EditCommunity = &self.data; let data: &EditCommunity = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
if let Err(slurs) = slur_check(&data.title) { check_slurs(&data.title)?;
return Err(APIError::err(&slurs_vec_to_str(slurs)).into()); check_slurs_opt(&data.description)?;
}
if let Some(description) = &data.description {
if let Err(slurs) = slur_check(description) {
return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
}
}
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
// Check for a site ban
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Verify its a mod (only mods can edit it) // Verify its a mod (only mods can edit it)
let edit_id = data.edit_id; let edit_id = data.edit_id;
@ -376,7 +325,7 @@ impl Perform for Oper<EditCommunity> {
.map(|v| v.into_iter().map(|m| m.user_id).collect()) .map(|v| v.into_iter().map(|m| m.user_id).collect())
}) })
.await??; .await??;
if !mods.contains(&user_id) { if !mods.contains(&user.id) {
return Err(APIError::err("not_a_moderator").into()); return Err(APIError::err("not_a_moderator").into());
} }
@ -415,6 +364,7 @@ impl Perform for Oper<EditCommunity> {
// process for communities and users // process for communities and users
let edit_id = data.edit_id; let edit_id = data.edit_id;
let user_id = user.id;
let community_view = blocking(pool, move |conn| { let community_view = blocking(pool, move |conn| {
CommunityView::read(conn, edit_id, Some(user_id)) CommunityView::read(conn, edit_id, Some(user_id))
}) })
@ -440,24 +390,12 @@ impl Perform for Oper<DeleteCommunity> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<CommunityResponse, LemmyError> { ) -> Result<CommunityResponse, LemmyError> {
let data: &DeleteCommunity = &self.data; let data: &DeleteCommunity = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
// Check for a site ban
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Verify its the creator (only a creator can delete the community) // Verify its the creator (only a creator can delete the community)
let edit_id = data.edit_id; let edit_id = data.edit_id;
let read_community = blocking(pool, move |conn| Community::read(conn, edit_id)).await??; let read_community = blocking(pool, move |conn| Community::read(conn, edit_id)).await??;
if read_community.creator_id != user_id { if read_community.creator_id != user.id {
return Err(APIError::err("no_community_edit_allowed").into()); return Err(APIError::err("no_community_edit_allowed").into());
} }
@ -485,6 +423,7 @@ impl Perform for Oper<DeleteCommunity> {
} }
let edit_id = data.edit_id; let edit_id = data.edit_id;
let user_id = user.id;
let community_view = blocking(pool, move |conn| { let community_view = blocking(pool, move |conn| {
CommunityView::read(conn, edit_id, Some(user_id)) CommunityView::read(conn, edit_id, Some(user_id))
}) })
@ -510,22 +449,10 @@ impl Perform for Oper<RemoveCommunity> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<CommunityResponse, LemmyError> { ) -> Result<CommunityResponse, LemmyError> {
let data: &RemoveCommunity = &self.data; let data: &RemoveCommunity = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
// Check for a site ban
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Verify its an admin (only an admin can remove a community) // Verify its an admin (only an admin can remove a community)
is_admin(pool, user_id).await?; is_admin(pool, user.id).await?;
// Do the remove // Do the remove
let edit_id = data.edit_id; let edit_id = data.edit_id;
@ -545,7 +472,7 @@ impl Perform for Oper<RemoveCommunity> {
None => None, None => None,
}; };
let form = ModRemoveCommunityForm { let form = ModRemoveCommunityForm {
mod_user_id: user_id, mod_user_id: user.id,
community_id: data.edit_id, community_id: data.edit_id,
removed: Some(removed), removed: Some(removed),
reason: data.reason.to_owned(), reason: data.reason.to_owned(),
@ -565,6 +492,7 @@ impl Perform for Oper<RemoveCommunity> {
} }
let edit_id = data.edit_id; let edit_id = data.edit_id;
let user_id = user.id;
let community_view = blocking(pool, move |conn| { let community_view = blocking(pool, move |conn| {
CommunityView::read(conn, edit_id, Some(user_id)) CommunityView::read(conn, edit_id, Some(user_id))
}) })
@ -590,19 +518,7 @@ impl Perform for Oper<ListCommunities> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<ListCommunitiesResponse, LemmyError> { ) -> Result<ListCommunitiesResponse, LemmyError> {
let data: &ListCommunities = &self.data; let data: &ListCommunities = &self.data;
let user = get_user_from_jwt_opt(&data.auth, pool).await?;
// For logged in users, you need to get back subscribed, and settings
let user: Option<User_> = match &data.auth {
Some(auth) => match Claims::decode(&auth) {
Ok(claims) => {
let user_id = claims.claims.id;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
Some(user)
}
Err(_e) => None,
},
None => None,
};
let user_id = match &user { let user_id = match &user {
Some(user) => Some(user.id), Some(user) => Some(user.id),
@ -644,19 +560,13 @@ impl Perform for Oper<FollowCommunity> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<CommunityResponse, LemmyError> { ) -> Result<CommunityResponse, LemmyError> {
let data: &FollowCommunity = &self.data; let data: &FollowCommunity = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let community_id = data.community_id; let community_id = data.community_id;
let community = blocking(pool, move |conn| Community::read(conn, community_id)).await??; let community = blocking(pool, move |conn| Community::read(conn, community_id)).await??;
let community_follower_form = CommunityFollowerForm { let community_follower_form = CommunityFollowerForm {
community_id: data.community_id, community_id: data.community_id,
user_id, user_id: user.id,
}; };
if community.local { if community.local {
@ -672,29 +582,25 @@ impl Perform for Oper<FollowCommunity> {
return Err(APIError::err("community_follower_already_exists").into()); return Err(APIError::err("community_follower_already_exists").into());
} }
} }
} else if data.follow {
// Dont actually add to the community followers here, because you need
// to wait for the accept
user
.send_follow(&community.actor_id, &self.client, pool)
.await?;
} else { } else {
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??; user
.send_unfollow(&community.actor_id, &self.client, pool)
if data.follow { .await?;
// Dont actually add to the community followers here, because you need let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form);
// to wait for the accept if blocking(pool, unfollow).await?.is_err() {
user return Err(APIError::err("community_follower_already_exists").into());
.send_follow(&community.actor_id, &self.client, pool)
.await?;
} else {
user
.send_unfollow(&community.actor_id, &self.client, pool)
.await?;
let unfollow =
move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form);
if blocking(pool, unfollow).await?.is_err() {
return Err(APIError::err("community_follower_already_exists").into());
}
} }
// TODO: this needs to return a "pending" state, until Accept is received from the remote server
} }
// TODO: this needs to return a "pending" state, until Accept is received from the remote server
let community_id = data.community_id; let community_id = data.community_id;
let user_id = user.id;
let community_view = blocking(pool, move |conn| { let community_view = blocking(pool, move |conn| {
CommunityView::read(conn, community_id, Some(user_id)) CommunityView::read(conn, community_id, Some(user_id))
}) })
@ -716,14 +622,9 @@ impl Perform for Oper<GetFollowedCommunities> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<GetFollowedCommunitiesResponse, LemmyError> { ) -> Result<GetFollowedCommunitiesResponse, LemmyError> {
let data: &GetFollowedCommunities = &self.data; let data: &GetFollowedCommunities = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) { let user_id = user.id;
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let communities = match blocking(pool, move |conn| { let communities = match blocking(pool, move |conn| {
CommunityFollowerView::for_user(conn, user_id) CommunityFollowerView::for_user(conn, user_id)
}) })
@ -748,18 +649,12 @@ impl Perform for Oper<BanFromCommunity> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<BanFromCommunityResponse, LemmyError> { ) -> Result<BanFromCommunityResponse, LemmyError> {
let data: &BanFromCommunity = &self.data; let data: &BanFromCommunity = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let community_id = data.community_id; let community_id = data.community_id;
// Verify that only mods or admins can ban // Verify that only mods or admins can ban
is_mod_or_admin(pool, user_id, community_id).await?; is_mod_or_admin(pool, user.id, community_id).await?;
let community_user_ban_form = CommunityUserBanForm { let community_user_ban_form = CommunityUserBanForm {
community_id: data.community_id, community_id: data.community_id,
@ -786,7 +681,7 @@ impl Perform for Oper<BanFromCommunity> {
}; };
let form = ModBanFromCommunityForm { let form = ModBanFromCommunityForm {
mod_user_id: user_id, mod_user_id: user.id,
other_user_id: data.user_id, other_user_id: data.user_id,
community_id: data.community_id, community_id: data.community_id,
reason: data.reason.to_owned(), reason: data.reason.to_owned(),
@ -826,13 +721,7 @@ impl Perform for Oper<AddModToCommunity> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<AddModToCommunityResponse, LemmyError> { ) -> Result<AddModToCommunityResponse, LemmyError> {
let data: &AddModToCommunity = &self.data; let data: &AddModToCommunity = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let community_moderator_form = CommunityModeratorForm { let community_moderator_form = CommunityModeratorForm {
community_id: data.community_id, community_id: data.community_id,
@ -842,7 +731,7 @@ impl Perform for Oper<AddModToCommunity> {
let community_id = data.community_id; let community_id = data.community_id;
// Verify that only mods or admins can add mod // Verify that only mods or admins can add mod
is_mod_or_admin(pool, user_id, community_id).await?; is_mod_or_admin(pool, user.id, community_id).await?;
if data.added { if data.added {
let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form);
@ -858,7 +747,7 @@ impl Perform for Oper<AddModToCommunity> {
// Mod tables // Mod tables
let form = ModAddCommunityForm { let form = ModAddCommunityForm {
mod_user_id: user_id, mod_user_id: user.id,
other_user_id: data.user_id, other_user_id: data.user_id,
community_id: data.community_id, community_id: data.community_id,
removed: Some(!data.added), removed: Some(!data.added),
@ -896,13 +785,7 @@ impl Perform for Oper<TransferCommunity> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<GetCommunityResponse, LemmyError> { ) -> Result<GetCommunityResponse, LemmyError> {
let data: &TransferCommunity = &self.data; let data: &TransferCommunity = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let community_id = data.community_id; let community_id = data.community_id;
let read_community = blocking(pool, move |conn| Community::read(conn, community_id)).await??; let read_community = blocking(pool, move |conn| Community::read(conn, community_id)).await??;
@ -917,7 +800,7 @@ impl Perform for Oper<TransferCommunity> {
admins.insert(0, creator_user); admins.insert(0, creator_user);
// Make sure user is the creator, or an admin // Make sure user is the creator, or an admin
if user_id != read_community.creator_id && !admins.iter().map(|a| a.id).any(|x| x == user_id) { if user.id != read_community.creator_id && !admins.iter().map(|a| a.id).any(|x| x == user.id) {
return Err(APIError::err("not_an_admin").into()); return Err(APIError::err("not_an_admin").into());
} }
@ -962,7 +845,7 @@ impl Perform for Oper<TransferCommunity> {
// Mod tables // Mod tables
let form = ModAddCommunityForm { let form = ModAddCommunityForm {
mod_user_id: user_id, mod_user_id: user.id,
other_user_id: data.user_id, other_user_id: data.user_id,
community_id: data.community_id, community_id: data.community_id,
removed: Some(false), removed: Some(false),
@ -970,6 +853,7 @@ impl Perform for Oper<TransferCommunity> {
blocking(pool, move |conn| ModAddCommunity::create(conn, &form)).await??; blocking(pool, move |conn| ModAddCommunity::create(conn, &form)).await??;
let community_id = data.community_id; let community_id = data.community_id;
let user_id = user.id;
let community_view = match blocking(pool, move |conn| { let community_view = match blocking(pool, move |conn| {
CommunityView::read(conn, community_id, Some(user_id)) CommunityView::read(conn, community_id, Some(user_id))
}) })

View file

@ -1,4 +1,4 @@
use crate::{blocking, websocket::WebsocketInfo, DbPool, LemmyError}; use crate::{api::claims::Claims, blocking, websocket::WebsocketInfo, DbPool, LemmyError};
use actix_web::client::Client; use actix_web::client::Client;
use lemmy_db::{ use lemmy_db::{
community::*, community::*,
@ -9,6 +9,7 @@ use lemmy_db::{
user_view::*, user_view::*,
Crud, Crud,
}; };
use lemmy_utils::{slur_check, slurs_vec_to_str};
use thiserror::Error; use thiserror::Error;
pub mod claims; pub mod claims;
@ -75,3 +76,56 @@ pub async fn is_admin(pool: &DbPool, user_id: i32) -> Result<(), LemmyError> {
} }
Ok(()) Ok(())
} }
pub(in crate::api) async fn get_user_from_jwt(
jwt: &str,
pool: &DbPool,
) -> Result<User_, LemmyError> {
let claims = match Claims::decode(&jwt) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
// Check for a site ban
if user.banned {
return Err(APIError::err("site_ban").into());
}
Ok(user)
}
pub(in crate::api) async fn get_user_from_jwt_opt(
jwt: &Option<String>,
pool: &DbPool,
) -> Result<Option<User_>, LemmyError> {
match jwt {
Some(jwt) => Ok(Some(get_user_from_jwt(jwt, pool).await?)),
None => Ok(None),
}
}
pub(in crate::api) fn check_slurs(text: &str) -> Result<(), APIError> {
if let Err(slurs) = slur_check(text) {
Err(APIError::err(&slurs_vec_to_str(slurs)))
} else {
Ok(())
}
}
pub(in crate::api) fn check_slurs_opt(text: &Option<String>) -> Result<(), APIError> {
match text {
Some(t) => check_slurs(t),
None => Ok(()),
}
}
pub(in crate::api) async fn check_community_ban(
user_id: i32,
community_id: i32,
pool: &DbPool,
) -> Result<(), LemmyError> {
let is_banned = move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
Err(APIError::err("community_ban").into())
} else {
Ok(())
}
}

View file

@ -1,5 +1,15 @@
use crate::{ use crate::{
api::{claims::Claims, is_mod_or_admin, APIError, Oper, Perform}, api::{
check_community_ban,
check_slurs,
check_slurs_opt,
get_user_from_jwt,
get_user_from_jwt_opt,
is_mod_or_admin,
APIError,
Oper,
Perform,
},
apub::{ApubLikeableType, ApubObjectType}, apub::{ApubLikeableType, ApubObjectType},
blocking, blocking,
fetch_iframely_and_pictrs_data, fetch_iframely_and_pictrs_data,
@ -19,20 +29,13 @@ use lemmy_db::{
post::*, post::*,
post_view::*, post_view::*,
site_view::*, site_view::*,
user::*,
Crud, Crud,
Likeable, Likeable,
ListingType, ListingType,
Saveable, Saveable,
SortType, SortType,
}; };
use lemmy_utils::{ use lemmy_utils::{is_valid_post_title, make_apub_endpoint, EndpointType};
is_valid_post_title,
make_apub_endpoint,
slur_check,
slurs_vec_to_str,
EndpointType,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::str::FromStr; use std::str::FromStr;
use url::Url; use url::Url;
@ -146,41 +149,16 @@ impl Perform for Oper<CreatePost> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<PostResponse, LemmyError> { ) -> Result<PostResponse, LemmyError> {
let data: &CreatePost = &self.data; let data: &CreatePost = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) { check_slurs(&data.name)?;
Ok(claims) => claims.claims, check_slurs_opt(&data.body)?;
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
if let Err(slurs) = slur_check(&data.name) {
return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
}
if let Some(body) = &data.body {
if let Err(slurs) = slur_check(body) {
return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
}
}
if !is_valid_post_title(&data.name) { if !is_valid_post_title(&data.name) {
return Err(APIError::err("invalid_post_title").into()); return Err(APIError::err("invalid_post_title").into());
} }
let user_id = claims.id; check_community_ban(user.id, data.community_id, pool).await?;
// Check for a community ban
let community_id = data.community_id;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Check for a site ban
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
if let Some(url) = data.url.as_ref() { if let Some(url) = data.url.as_ref() {
match Url::parse(url) { match Url::parse(url) {
@ -198,7 +176,7 @@ impl Perform for Oper<CreatePost> {
url: data.url.to_owned(), url: data.url.to_owned(),
body: data.body.to_owned(), body: data.body.to_owned(),
community_id: data.community_id, community_id: data.community_id,
creator_id: user_id, creator_id: user.id,
removed: None, removed: None,
deleted: None, deleted: None,
nsfw: data.nsfw, nsfw: data.nsfw,
@ -244,7 +222,7 @@ impl Perform for Oper<CreatePost> {
// They like their own post by default // They like their own post by default
let like_form = PostLikeForm { let like_form = PostLikeForm {
post_id: inserted_post.id, post_id: inserted_post.id,
user_id, user_id: user.id,
score: 1, score: 1,
}; };
@ -258,7 +236,7 @@ impl Perform for Oper<CreatePost> {
// Refetch the view // Refetch the view
let inserted_post_id = inserted_post.id; let inserted_post_id = inserted_post.id;
let post_view = match blocking(pool, move |conn| { let post_view = match blocking(pool, move |conn| {
PostView::read(conn, inserted_post_id, Some(user_id)) PostView::read(conn, inserted_post_id, Some(user.id))
}) })
.await? .await?
{ {
@ -290,17 +268,8 @@ impl Perform for Oper<GetPost> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<GetPostResponse, LemmyError> { ) -> Result<GetPostResponse, LemmyError> {
let data: &GetPost = &self.data; let data: &GetPost = &self.data;
let user = get_user_from_jwt_opt(&data.auth, pool).await?;
let user_id: Option<i32> = match &data.auth { let user_id = user.map(|u| u.id);
Some(auth) => match Claims::decode(&auth) {
Ok(claims) => {
let user_id = claims.claims.id;
Some(user_id)
}
Err(_e) => None,
},
None => None,
};
let id = data.id; let id = data.id;
let post_view = match blocking(pool, move |conn| PostView::read(conn, id, user_id)).await? { let post_view = match blocking(pool, move |conn| PostView::read(conn, id, user_id)).await? {
@ -369,19 +338,7 @@ impl Perform for Oper<GetPosts> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<GetPostsResponse, LemmyError> { ) -> Result<GetPostsResponse, LemmyError> {
let data: &GetPosts = &self.data; let data: &GetPosts = &self.data;
let user = get_user_from_jwt_opt(&data.auth, pool).await?;
// For logged in users, you need to get back subscribed, and settings
let user: Option<User_> = match &data.auth {
Some(auth) => match Claims::decode(&auth) {
Ok(claims) => {
let user_id = claims.claims.id;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
Some(user)
}
Err(_e) => None,
},
None => None,
};
let user_id = match &user { let user_id = match &user {
Some(user) => Some(user.id), Some(user) => Some(user.id),
@ -446,13 +403,7 @@ impl Perform for Oper<CreatePostLike> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<PostResponse, LemmyError> { ) -> Result<PostResponse, LemmyError> {
let data: &CreatePostLike = &self.data; let data: &CreatePostLike = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
// Don't do a downvote if site has downvotes disabled // Don't do a downvote if site has downvotes disabled
if data.score == -1 { if data.score == -1 {
@ -466,22 +417,11 @@ impl Perform for Oper<CreatePostLike> {
let post_id = data.post_id; let post_id = data.post_id;
let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??; let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??;
let community_id = post.community_id; check_community_ban(user.id, post.community_id, pool).await?;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Check for a site ban
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
let like_form = PostLikeForm { let like_form = PostLikeForm {
post_id: data.post_id, post_id: data.post_id,
user_id, user_id: user.id,
score: data.score, score: data.score,
}; };
@ -508,6 +448,7 @@ impl Perform for Oper<CreatePostLike> {
} }
let post_id = data.post_id; let post_id = data.post_id;
let user_id = user.id;
let post_view = match blocking(pool, move |conn| { let post_view = match blocking(pool, move |conn| {
PostView::read(conn, post_id, Some(user_id)) PostView::read(conn, post_id, Some(user_id))
}) })
@ -541,47 +482,22 @@ impl Perform for Oper<EditPost> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<PostResponse, LemmyError> { ) -> Result<PostResponse, LemmyError> {
let data: &EditPost = &self.data; let data: &EditPost = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
if let Err(slurs) = slur_check(&data.name) { check_slurs(&data.name)?;
return Err(APIError::err(&slurs_vec_to_str(slurs)).into()); check_slurs_opt(&data.body)?;
}
if let Some(body) = &data.body {
if let Err(slurs) = slur_check(body) {
return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
}
}
if !is_valid_post_title(&data.name) { if !is_valid_post_title(&data.name) {
return Err(APIError::err("invalid_post_title").into()); return Err(APIError::err("invalid_post_title").into());
} }
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let edit_id = data.edit_id; let edit_id = data.edit_id;
let orig_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??; let orig_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??;
// Check for a community ban check_community_ban(user.id, orig_post.community_id, pool).await?;
let community_id = orig_post.community_id;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Check for a site ban
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Verify that only the creator can edit // Verify that only the creator can edit
if !Post::is_post_creator(user_id, orig_post.creator_id) { if !Post::is_post_creator(user.id, orig_post.creator_id) {
return Err(APIError::err("no_post_edit_allowed").into()); return Err(APIError::err("no_post_edit_allowed").into());
} }
@ -630,7 +546,7 @@ impl Perform for Oper<EditPost> {
let edit_id = data.edit_id; let edit_id = data.edit_id;
let post_view = blocking(pool, move |conn| { let post_view = blocking(pool, move |conn| {
PostView::read(conn, edit_id, Some(user_id)) PostView::read(conn, edit_id, Some(user.id))
}) })
.await??; .await??;
@ -658,33 +574,15 @@ impl Perform for Oper<DeletePost> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<PostResponse, LemmyError> { ) -> Result<PostResponse, LemmyError> {
let data: &DeletePost = &self.data; let data: &DeletePost = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let edit_id = data.edit_id; let edit_id = data.edit_id;
let orig_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??; let orig_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??;
// Check for a site ban check_community_ban(user.id, orig_post.community_id, pool).await?;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Check for a community ban
let community_id = orig_post.community_id;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Verify that only the creator can delete // Verify that only the creator can delete
if !Post::is_post_creator(user_id, orig_post.creator_id) { if !Post::is_post_creator(user.id, orig_post.creator_id) {
return Err(APIError::err("no_post_edit_allowed").into()); return Err(APIError::err("no_post_edit_allowed").into());
} }
@ -708,7 +606,7 @@ impl Perform for Oper<DeletePost> {
// Refetch the post // Refetch the post
let edit_id = data.edit_id; let edit_id = data.edit_id;
let post_view = blocking(pool, move |conn| { let post_view = blocking(pool, move |conn| {
PostView::read(conn, edit_id, Some(user_id)) PostView::read(conn, edit_id, Some(user.id))
}) })
.await??; .await??;
@ -736,33 +634,15 @@ impl Perform for Oper<RemovePost> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<PostResponse, LemmyError> { ) -> Result<PostResponse, LemmyError> {
let data: &RemovePost = &self.data; let data: &RemovePost = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let edit_id = data.edit_id; let edit_id = data.edit_id;
let orig_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??; let orig_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??;
// Check for a site ban check_community_ban(user.id, orig_post.community_id, pool).await?;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Check for a community ban
let community_id = orig_post.community_id;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Verify that only the mods can remove // Verify that only the mods can remove
is_mod_or_admin(pool, user_id, community_id).await?; is_mod_or_admin(pool, user.id, orig_post.community_id).await?;
// Update the post // Update the post
let edit_id = data.edit_id; let edit_id = data.edit_id;
@ -774,7 +654,7 @@ impl Perform for Oper<RemovePost> {
// Mod tables // Mod tables
let form = ModRemovePostForm { let form = ModRemovePostForm {
mod_user_id: user_id, mod_user_id: user.id,
post_id: data.edit_id, post_id: data.edit_id,
removed: Some(removed), removed: Some(removed),
reason: data.reason.to_owned(), reason: data.reason.to_owned(),
@ -792,6 +672,7 @@ impl Perform for Oper<RemovePost> {
// Refetch the post // Refetch the post
let edit_id = data.edit_id; let edit_id = data.edit_id;
let user_id = user.id;
let post_view = blocking(pool, move |conn| { let post_view = blocking(pool, move |conn| {
PostView::read(conn, edit_id, Some(user_id)) PostView::read(conn, edit_id, Some(user_id))
}) })
@ -821,33 +702,15 @@ impl Perform for Oper<LockPost> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<PostResponse, LemmyError> { ) -> Result<PostResponse, LemmyError> {
let data: &LockPost = &self.data; let data: &LockPost = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let edit_id = data.edit_id; let edit_id = data.edit_id;
let orig_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??; let orig_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??;
// Check for a site ban check_community_ban(user.id, orig_post.community_id, pool).await?;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Check for a community ban
let community_id = orig_post.community_id;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Verify that only the mods can lock // Verify that only the mods can lock
is_mod_or_admin(pool, user_id, community_id).await?; is_mod_or_admin(pool, user.id, orig_post.community_id).await?;
// Update the post // Update the post
let edit_id = data.edit_id; let edit_id = data.edit_id;
@ -857,7 +720,7 @@ impl Perform for Oper<LockPost> {
// Mod tables // Mod tables
let form = ModLockPostForm { let form = ModLockPostForm {
mod_user_id: user_id, mod_user_id: user.id,
post_id: data.edit_id, post_id: data.edit_id,
locked: Some(locked), locked: Some(locked),
}; };
@ -869,7 +732,7 @@ impl Perform for Oper<LockPost> {
// Refetch the post // Refetch the post
let edit_id = data.edit_id; let edit_id = data.edit_id;
let post_view = blocking(pool, move |conn| { let post_view = blocking(pool, move |conn| {
PostView::read(conn, edit_id, Some(user_id)) PostView::read(conn, edit_id, Some(user.id))
}) })
.await??; .await??;
@ -897,33 +760,15 @@ impl Perform for Oper<StickyPost> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<PostResponse, LemmyError> { ) -> Result<PostResponse, LemmyError> {
let data: &StickyPost = &self.data; let data: &StickyPost = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let edit_id = data.edit_id; let edit_id = data.edit_id;
let orig_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??; let orig_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??;
// Check for a site ban check_community_ban(user.id, orig_post.community_id, pool).await?;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Check for a community ban
let community_id = orig_post.community_id;
let is_banned =
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
if blocking(pool, is_banned).await? {
return Err(APIError::err("community_ban").into());
}
// Verify that only the mods can sticky // Verify that only the mods can sticky
is_mod_or_admin(pool, user_id, community_id).await?; is_mod_or_admin(pool, user.id, orig_post.community_id).await?;
// Update the post // Update the post
let edit_id = data.edit_id; let edit_id = data.edit_id;
@ -935,7 +780,7 @@ impl Perform for Oper<StickyPost> {
// Mod tables // Mod tables
let form = ModStickyPostForm { let form = ModStickyPostForm {
mod_user_id: user_id, mod_user_id: user.id,
post_id: data.edit_id, post_id: data.edit_id,
stickied: Some(stickied), stickied: Some(stickied),
}; };
@ -948,7 +793,7 @@ impl Perform for Oper<StickyPost> {
// Refetch the post // Refetch the post
let edit_id = data.edit_id; let edit_id = data.edit_id;
let post_view = blocking(pool, move |conn| { let post_view = blocking(pool, move |conn| {
PostView::read(conn, edit_id, Some(user_id)) PostView::read(conn, edit_id, Some(user.id))
}) })
.await??; .await??;
@ -976,17 +821,11 @@ impl Perform for Oper<SavePost> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<PostResponse, LemmyError> { ) -> Result<PostResponse, LemmyError> {
let data: &SavePost = &self.data; let data: &SavePost = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let post_saved_form = PostSavedForm { let post_saved_form = PostSavedForm {
post_id: data.post_id, post_id: data.post_id,
user_id, user_id: user.id,
}; };
if data.save { if data.save {
@ -1002,6 +841,7 @@ impl Perform for Oper<SavePost> {
} }
let post_id = data.post_id; let post_id = data.post_id;
let user_id = user.id;
let post_view = blocking(pool, move |conn| { let post_view = blocking(pool, move |conn| {
PostView::read(conn, post_id, Some(user_id)) PostView::read(conn, post_id, Some(user_id))
}) })

View file

@ -1,6 +1,15 @@
use super::user::Register; use super::user::Register;
use crate::{ use crate::{
api::{claims::Claims, is_admin, APIError, Oper, Perform}, api::{
check_slurs,
check_slurs_opt,
get_user_from_jwt,
get_user_from_jwt_opt,
is_admin,
APIError,
Oper,
Perform,
},
apub::fetcher::search_by_apub_id, apub::fetcher::search_by_apub_id,
blocking, blocking,
version, version,
@ -24,7 +33,7 @@ use lemmy_db::{
SearchType, SearchType,
SortType, SortType,
}; };
use lemmy_utils::{settings::Settings, slur_check, slurs_vec_to_str}; use lemmy_utils::settings::Settings;
use log::{debug, info}; use log::{debug, info};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::str::FromStr; use std::str::FromStr;
@ -243,30 +252,18 @@ impl Perform for Oper<CreateSite> {
) -> Result<SiteResponse, LemmyError> { ) -> Result<SiteResponse, LemmyError> {
let data: &CreateSite = &self.data; let data: &CreateSite = &self.data;
let claims = match Claims::decode(&data.auth) { let user = get_user_from_jwt(&data.auth, pool).await?;
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
if let Err(slurs) = slur_check(&data.name) { check_slurs(&data.name)?;
return Err(APIError::err(&slurs_vec_to_str(slurs)).into()); check_slurs_opt(&data.description)?;
}
if let Some(description) = &data.description {
if let Err(slurs) = slur_check(description) {
return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
}
}
let user_id = claims.id;
// Make sure user is an admin // Make sure user is an admin
is_admin(pool, user_id).await?; is_admin(pool, user.id).await?;
let site_form = SiteForm { let site_form = SiteForm {
name: data.name.to_owned(), name: data.name.to_owned(),
description: data.description.to_owned(), description: data.description.to_owned(),
creator_id: user_id, creator_id: user.id,
enable_downvotes: data.enable_downvotes, enable_downvotes: data.enable_downvotes,
open_registration: data.open_registration, open_registration: data.open_registration,
enable_nsfw: data.enable_nsfw, enable_nsfw: data.enable_nsfw,
@ -293,26 +290,13 @@ impl Perform for Oper<EditSite> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<SiteResponse, LemmyError> { ) -> Result<SiteResponse, LemmyError> {
let data: &EditSite = &self.data; let data: &EditSite = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) { check_slurs(&data.name)?;
Ok(claims) => claims.claims, check_slurs_opt(&data.description)?;
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
if let Err(slurs) = slur_check(&data.name) {
return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
}
if let Some(description) = &data.description {
if let Err(slurs) = slur_check(description) {
return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
}
}
let user_id = claims.id;
// Make sure user is an admin // Make sure user is an admin
is_admin(pool, user_id).await?; is_admin(pool, user.id).await?;
let found_site = blocking(pool, move |conn| Site::read(conn, 1)).await??; let found_site = blocking(pool, move |conn| Site::read(conn, 1)).await??;
@ -421,21 +405,12 @@ impl Perform for Oper<GetSite> {
0 0
}; };
// Giving back your user, if you're logged in let my_user = get_user_from_jwt_opt(&data.auth, pool).await?.map(|mut u| {
let my_user: Option<User_> = match &data.auth { u.password_encrypted = "".to_string();
Some(auth) => match Claims::decode(&auth) { u.private_key = None;
Ok(claims) => { u.public_key = None;
let user_id = claims.claims.id; u
let mut user = blocking(pool, move |conn| User_::read(conn, user_id)).await??; });
user.password_encrypted = "".to_string();
user.private_key = None;
user.public_key = None;
Some(user)
}
Err(_e) => None,
},
None => None,
};
Ok(GetSiteResponse { Ok(GetSiteResponse {
site: site_view, site: site_view,
@ -466,16 +441,8 @@ impl Perform for Oper<Search> {
Err(e) => debug!("Failed to resolve search query as activitypub ID: {}", e), Err(e) => debug!("Failed to resolve search query as activitypub ID: {}", e),
} }
let user_id: Option<i32> = match &data.auth { let user = get_user_from_jwt_opt(&data.auth, pool).await?;
Some(auth) => match Claims::decode(&auth) { let user_id = user.map(|u| u.id);
Ok(claims) => {
let user_id = claims.claims.id;
Some(user_id)
}
Err(_e) => None,
},
None => None,
};
let type_ = SearchType::from_str(&data.type_)?; let type_ = SearchType::from_str(&data.type_)?;
@ -630,14 +597,8 @@ impl Perform for Oper<TransferSite> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<GetSiteResponse, LemmyError> { ) -> Result<GetSiteResponse, LemmyError> {
let data: &TransferSite = &self.data; let data: &TransferSite = &self.data;
let mut user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let mut user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
// TODO add a User_::read_safe() for this. // TODO add a User_::read_safe() for this.
user.password_encrypted = "".to_string(); user.password_encrypted = "".to_string();
user.private_key = None; user.private_key = None;
@ -646,7 +607,7 @@ impl Perform for Oper<TransferSite> {
let read_site = blocking(pool, move |conn| Site::read(conn, 1)).await??; let read_site = blocking(pool, move |conn| Site::read(conn, 1)).await??;
// Make sure user is the creator // Make sure user is the creator
if read_site.creator_id != user_id { if read_site.creator_id != user.id {
return Err(APIError::err("not_an_admin").into()); return Err(APIError::err("not_an_admin").into());
} }
@ -667,7 +628,7 @@ impl Perform for Oper<TransferSite> {
// Mod tables // Mod tables
let form = ModAddForm { let form = ModAddForm {
mod_user_id: user_id, mod_user_id: user.id,
other_user_id: data.user_id, other_user_id: data.user_id,
removed: Some(false), removed: Some(false),
}; };
@ -707,16 +668,10 @@ impl Perform for Oper<GetSiteConfig> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<GetSiteConfigResponse, LemmyError> { ) -> Result<GetSiteConfigResponse, LemmyError> {
let data: &GetSiteConfig = &self.data; let data: &GetSiteConfig = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
// Only let admins read this // Only let admins read this
is_admin(pool, user_id).await?; is_admin(pool, user.id).await?;
let config_hjson = Settings::read_config_file()?; let config_hjson = Settings::read_config_file()?;
@ -734,19 +689,13 @@ impl Perform for Oper<SaveSiteConfig> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<GetSiteConfigResponse, LemmyError> { ) -> Result<GetSiteConfigResponse, LemmyError> {
let data: &SaveSiteConfig = &self.data; let data: &SaveSiteConfig = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
// Only let admins read this // Only let admins read this
let admins = blocking(pool, move |conn| UserView::admins(conn)).await??; let admins = blocking(pool, move |conn| UserView::admins(conn)).await??;
let admin_ids: Vec<i32> = admins.into_iter().map(|m| m.id).collect(); let admin_ids: Vec<i32> = admins.into_iter().map(|m| m.id).collect();
if !admin_ids.contains(&user_id) { if !admin_ids.contains(&user.id) {
return Err(APIError::err("not_an_admin").into()); return Err(APIError::err("not_an_admin").into());
} }

View file

@ -1,5 +1,14 @@
use crate::{ use crate::{
api::{claims::Claims, is_admin, APIError, Oper, Perform}, api::{
check_slurs,
claims::Claims,
get_user_from_jwt,
get_user_from_jwt_opt,
is_admin,
APIError,
Oper,
Perform,
},
apub::ApubObjectType, apub::ApubObjectType,
blocking, blocking,
captcha_espeak_wav_base64, captcha_espeak_wav_base64,
@ -47,8 +56,6 @@ use lemmy_utils::{
remove_slurs, remove_slurs,
send_email, send_email,
settings::Settings, settings::Settings,
slur_check,
slurs_vec_to_str,
EndpointType, EndpointType,
}; };
use log::error; use log::error;
@ -366,9 +373,7 @@ impl Perform for Oper<Register> {
}; };
} }
if let Err(slurs) = slur_check(&data.username) { check_slurs(&data.username)?;
return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
}
// Make sure there are no admins // Make sure there are no admins
let any_admins = blocking(pool, move |conn| { let any_admins = blocking(pool, move |conn| {
@ -543,14 +548,9 @@ impl Perform for Oper<SaveUserSettings> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<LoginResponse, LemmyError> { ) -> Result<LoginResponse, LemmyError> {
let data: &SaveUserSettings = &self.data; let data: &SaveUserSettings = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) { let user_id = user.id;
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let read_user = blocking(pool, move |conn| User_::read(conn, user_id)).await??; let read_user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
let email = match &data.email { let email = match &data.email {
@ -665,24 +665,7 @@ impl Perform for Oper<GetUserDetails> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<GetUserDetailsResponse, LemmyError> { ) -> Result<GetUserDetailsResponse, LemmyError> {
let data: &GetUserDetails = &self.data; let data: &GetUserDetails = &self.data;
let user = get_user_from_jwt_opt(&data.auth, pool).await?;
// For logged in users, you need to get back subscribed, and settings
let user: Option<User_> = match &data.auth {
Some(auth) => match Claims::decode(&auth) {
Ok(claims) => {
let user_id = claims.claims.id;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
Some(user)
}
Err(_e) => None,
},
None => None,
};
let user_id = match &user {
Some(user) => Some(user.id),
None => None,
};
let show_nsfw = match &user { let show_nsfw = match &user {
Some(user) => user.show_nsfw, Some(user) => user.show_nsfw,
@ -712,6 +695,7 @@ impl Perform for Oper<GetUserDetails> {
let limit = data.limit; let limit = data.limit;
let saved_only = data.saved_only; let saved_only = data.saved_only;
let community_id = data.community_id; let community_id = data.community_id;
let user_id = user.map(|u| u.id);
let (posts, comments) = blocking(pool, move |conn| { let (posts, comments) = blocking(pool, move |conn| {
let mut posts_query = PostQueryBuilder::create(conn) let mut posts_query = PostQueryBuilder::create(conn)
.sort(&sort) .sort(&sort)
@ -780,16 +764,10 @@ impl Perform for Oper<AddAdmin> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<AddAdminResponse, LemmyError> { ) -> Result<AddAdminResponse, LemmyError> {
let data: &AddAdmin = &self.data; let data: &AddAdmin = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
// Make sure user is an admin // Make sure user is an admin
is_admin(pool, user_id).await?; is_admin(pool, user.id).await?;
let added = data.added; let added = data.added;
let added_user_id = data.user_id; let added_user_id = data.user_id;
@ -800,7 +778,7 @@ impl Perform for Oper<AddAdmin> {
// Mod tables // Mod tables
let form = ModAddForm { let form = ModAddForm {
mod_user_id: user_id, mod_user_id: user.id,
other_user_id: data.user_id, other_user_id: data.user_id,
removed: Some(!data.added), removed: Some(!data.added),
}; };
@ -839,16 +817,10 @@ impl Perform for Oper<BanUser> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<BanUserResponse, LemmyError> { ) -> Result<BanUserResponse, LemmyError> {
let data: &BanUser = &self.data; let data: &BanUser = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
// Make sure user is an admin // Make sure user is an admin
is_admin(pool, user_id).await?; is_admin(pool, user.id).await?;
let ban = data.ban; let ban = data.ban;
let banned_user_id = data.user_id; let banned_user_id = data.user_id;
@ -864,7 +836,7 @@ impl Perform for Oper<BanUser> {
}; };
let form = ModBanForm { let form = ModBanForm {
mod_user_id: user_id, mod_user_id: user.id,
other_user_id: data.user_id, other_user_id: data.user_id,
reason: data.reason.to_owned(), reason: data.reason.to_owned(),
banned: Some(data.ban), banned: Some(data.ban),
@ -903,19 +875,14 @@ impl Perform for Oper<GetReplies> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<GetRepliesResponse, LemmyError> { ) -> Result<GetRepliesResponse, LemmyError> {
let data: &GetReplies = &self.data; let data: &GetReplies = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let sort = SortType::from_str(&data.sort)?; let sort = SortType::from_str(&data.sort)?;
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
let unread_only = data.unread_only; let unread_only = data.unread_only;
let user_id = user.id;
let replies = blocking(pool, move |conn| { let replies = blocking(pool, move |conn| {
ReplyQueryBuilder::create(conn, user_id) ReplyQueryBuilder::create(conn, user_id)
.sort(&sort) .sort(&sort)
@ -940,19 +907,14 @@ impl Perform for Oper<GetUserMentions> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<GetUserMentionsResponse, LemmyError> { ) -> Result<GetUserMentionsResponse, LemmyError> {
let data: &GetUserMentions = &self.data; let data: &GetUserMentions = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let sort = SortType::from_str(&data.sort)?; let sort = SortType::from_str(&data.sort)?;
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
let unread_only = data.unread_only; let unread_only = data.unread_only;
let user_id = user.id;
let mentions = blocking(pool, move |conn| { let mentions = blocking(pool, move |conn| {
UserMentionQueryBuilder::create(conn, user_id) UserMentionQueryBuilder::create(conn, user_id)
.sort(&sort) .sort(&sort)
@ -977,19 +939,13 @@ impl Perform for Oper<MarkUserMentionAsRead> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<UserMentionResponse, LemmyError> { ) -> Result<UserMentionResponse, LemmyError> {
let data: &MarkUserMentionAsRead = &self.data; let data: &MarkUserMentionAsRead = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let user_mention_id = data.user_mention_id; let user_mention_id = data.user_mention_id;
let read_user_mention = let read_user_mention =
blocking(pool, move |conn| UserMention::read(conn, user_mention_id)).await??; blocking(pool, move |conn| UserMention::read(conn, user_mention_id)).await??;
if user_id != read_user_mention.recipient_id { if user.id != read_user_mention.recipient_id {
return Err(APIError::err("couldnt_update_comment").into()); return Err(APIError::err("couldnt_update_comment").into());
} }
@ -1001,6 +957,7 @@ impl Perform for Oper<MarkUserMentionAsRead> {
}; };
let user_mention_id = read_user_mention.id; let user_mention_id = read_user_mention.id;
let user_id = user.id;
let user_mention_view = blocking(pool, move |conn| { let user_mention_view = blocking(pool, move |conn| {
UserMentionView::read(conn, user_mention_id, user_id) UserMentionView::read(conn, user_mention_id, user_id)
}) })
@ -1022,14 +979,9 @@ impl Perform for Oper<MarkAllAsRead> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<GetRepliesResponse, LemmyError> { ) -> Result<GetRepliesResponse, LemmyError> {
let data: &MarkAllAsRead = &self.data; let data: &MarkAllAsRead = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) { let user_id = user.id;
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let replies = blocking(pool, move |conn| { let replies = blocking(pool, move |conn| {
ReplyQueryBuilder::create(conn, user_id) ReplyQueryBuilder::create(conn, user_id)
.unread_only(true) .unread_only(true)
@ -1076,15 +1028,7 @@ impl Perform for Oper<DeleteAccount> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<LoginResponse, LemmyError> { ) -> Result<LoginResponse, LemmyError> {
let data: &DeleteAccount = &self.data; let data: &DeleteAccount = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
// Verify the password // Verify the password
let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false); let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false);
@ -1093,6 +1037,7 @@ impl Perform for Oper<DeleteAccount> {
} }
// Comments // Comments
let user_id = user.id;
let comments = blocking(pool, move |conn| { let comments = blocking(pool, move |conn| {
CommentQueryBuilder::create(conn) CommentQueryBuilder::create(conn)
.for_creator_id(user_id) .for_creator_id(user_id)
@ -1230,27 +1175,15 @@ impl Perform for Oper<CreatePrivateMessage> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<PrivateMessageResponse, LemmyError> { ) -> Result<PrivateMessageResponse, LemmyError> {
let data: &CreatePrivateMessage = &self.data; let data: &CreatePrivateMessage = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let hostname = &format!("https://{}", Settings::get().hostname); let hostname = &format!("https://{}", Settings::get().hostname);
// Check for a site ban
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
let content_slurs_removed = remove_slurs(&data.content.to_owned()); let content_slurs_removed = remove_slurs(&data.content.to_owned());
let private_message_form = PrivateMessageForm { let private_message_form = PrivateMessageForm {
content: content_slurs_removed.to_owned(), content: content_slurs_removed.to_owned(),
creator_id: user_id, creator_id: user.id,
recipient_id: data.recipient_id, recipient_id: data.recipient_id,
deleted: None, deleted: None,
read: None, read: None,
@ -1341,25 +1274,13 @@ impl Perform for Oper<EditPrivateMessage> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<PrivateMessageResponse, LemmyError> { ) -> Result<PrivateMessageResponse, LemmyError> {
let data: &EditPrivateMessage = &self.data; let data: &EditPrivateMessage = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
// Check for a site ban
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Checking permissions // Checking permissions
let edit_id = data.edit_id; let edit_id = data.edit_id;
let orig_private_message = let orig_private_message =
blocking(pool, move |conn| PrivateMessage::read(conn, edit_id)).await??; blocking(pool, move |conn| PrivateMessage::read(conn, edit_id)).await??;
if user_id != orig_private_message.creator_id { if user.id != orig_private_message.creator_id {
return Err(APIError::err("no_private_message_edit_allowed").into()); return Err(APIError::err("no_private_message_edit_allowed").into());
} }
@ -1409,25 +1330,13 @@ impl Perform for Oper<DeletePrivateMessage> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<PrivateMessageResponse, LemmyError> { ) -> Result<PrivateMessageResponse, LemmyError> {
let data: &DeletePrivateMessage = &self.data; let data: &DeletePrivateMessage = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
// Check for a site ban
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Checking permissions // Checking permissions
let edit_id = data.edit_id; let edit_id = data.edit_id;
let orig_private_message = let orig_private_message =
blocking(pool, move |conn| PrivateMessage::read(conn, edit_id)).await??; blocking(pool, move |conn| PrivateMessage::read(conn, edit_id)).await??;
if user_id != orig_private_message.creator_id { if user.id != orig_private_message.creator_id {
return Err(APIError::err("no_private_message_edit_allowed").into()); return Err(APIError::err("no_private_message_edit_allowed").into());
} }
@ -1483,25 +1392,13 @@ impl Perform for Oper<MarkPrivateMessageAsRead> {
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<PrivateMessageResponse, LemmyError> { ) -> Result<PrivateMessageResponse, LemmyError> {
let data: &MarkPrivateMessageAsRead = &self.data; let data: &MarkPrivateMessageAsRead = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
// Check for a site ban
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
if user.banned {
return Err(APIError::err("site_ban").into());
}
// Checking permissions // Checking permissions
let edit_id = data.edit_id; let edit_id = data.edit_id;
let orig_private_message = let orig_private_message =
blocking(pool, move |conn| PrivateMessage::read(conn, edit_id)).await??; blocking(pool, move |conn| PrivateMessage::read(conn, edit_id)).await??;
if user_id != orig_private_message.recipient_id { if user.id != orig_private_message.recipient_id {
return Err(APIError::err("couldnt_update_private_message").into()); return Err(APIError::err("couldnt_update_private_message").into());
} }
@ -1548,13 +1445,8 @@ impl Perform for Oper<GetPrivateMessages> {
_websocket_info: Option<WebsocketInfo>, _websocket_info: Option<WebsocketInfo>,
) -> Result<PrivateMessagesResponse, LemmyError> { ) -> Result<PrivateMessagesResponse, LemmyError> {
let data: &GetPrivateMessages = &self.data; let data: &GetPrivateMessages = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) { let user_id = user.id;
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
@ -1578,24 +1470,21 @@ impl Perform for Oper<UserJoin> {
async fn perform( async fn perform(
&self, &self,
_pool: &DbPool, pool: &DbPool,
websocket_info: Option<WebsocketInfo>, websocket_info: Option<WebsocketInfo>,
) -> Result<UserJoinResponse, LemmyError> { ) -> Result<UserJoinResponse, LemmyError> {
let data: &UserJoin = &self.data; let data: &UserJoin = &self.data;
let user = get_user_from_jwt(&data.auth, pool).await?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()),
};
let user_id = claims.id;
if let Some(ws) = websocket_info { if let Some(ws) = websocket_info {
if let Some(id) = ws.id { if let Some(id) = ws.id {
ws.chatserver.do_send(JoinUserRoom { user_id, id }); ws.chatserver.do_send(JoinUserRoom {
user_id: user.id,
id,
});
} }
} }
Ok(UserJoinResponse { user_id }) Ok(UserJoinResponse { user_id: user.id })
} }
} }

View file

@ -1,9 +1,9 @@
use crate::{ use crate::{
apub::{ apub::{
check_is_apub_id_valid,
community::do_announce, community::do_announce,
extensions::signatures::sign, extensions::signatures::sign,
insert_activity, insert_activity,
is_apub_id_valid,
ActorType, ActorType,
}, },
request::retry_custom, request::retry_custom,
@ -50,10 +50,7 @@ pub async fn send_activity(
for t in to { for t in to {
let to_url = Url::parse(&t)?; let to_url = Url::parse(&t)?;
if !is_apub_id_valid(&to_url) { check_is_apub_id_valid(&to_url)?;
debug!("Not sending activity to {} (invalid or blocklisted)", t);
continue;
}
let res = retry_custom(|| async { let res = retry_custom(|| async {
let request = client.post(&t).header("Content-Type", "application/json"); let request = client.post(&t).header("Content-Type", "application/json");

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
api::site::SearchResponse, api::site::SearchResponse,
apub::{ apub::{
is_apub_id_valid, check_is_apub_id_valid,
ActorType, ActorType,
FromApub, FromApub,
GroupExt, GroupExt,
@ -66,9 +66,7 @@ pub async fn fetch_remote_object<Response>(
where where
Response: for<'de> Deserialize<'de>, Response: for<'de> Deserialize<'de>,
{ {
if !is_apub_id_valid(&url) { check_is_apub_id_valid(&url)?;
return Err(anyhow!("Activitypub uri invalid or blocked: {}", url).into());
}
let timeout = Duration::from_secs(60); let timeout = Duration::from_secs(60);

View file

@ -39,7 +39,6 @@ pub async fn receive_create(
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let create = Create::from_any_base(activity)?.unwrap(); let create = Create::from_any_base(activity)?.unwrap();
dbg!(create.object().as_single_kind_str());
match create.object().as_single_kind_str() { match create.object().as_single_kind_str() {
Some("Page") => receive_create_post(create, client, pool, chat_server).await, Some("Page") => receive_create_post(create, client, pool, chat_server).await,
Some("Note") => receive_create_comment(create, client, pool, chat_server).await, Some("Note") => receive_create_comment(create, client, pool, chat_server).await,

View file

@ -1,7 +1,8 @@
use crate::{ use crate::{
apub::{ apub::{
check_is_apub_id_valid,
extensions::signatures::verify, extensions::signatures::verify,
fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user}, fetcher::get_or_fetch_and_upsert_user,
insert_activity, insert_activity,
ActorType, ActorType,
}, },
@ -10,7 +11,8 @@ use crate::{
LemmyError, LemmyError,
}; };
use activitystreams::{ use activitystreams::{
activity::{Follow, Undo}, activity::{ActorAndObject, Follow, Undo},
base::AnyBase,
prelude::*, prelude::*,
}; };
use actix_web::{client::Client, web, HttpRequest, HttpResponse}; use actix_web::{client::Client, web, HttpRequest, HttpResponse};
@ -21,37 +23,28 @@ use lemmy_db::{
Followable, Followable,
}; };
use log::debug; use log::debug;
use serde::Deserialize; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
#[serde(untagged)] #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
#[derive(Deserialize, Debug)] #[serde(rename_all = "PascalCase")]
pub enum CommunityAcceptedObjects { pub enum ValidTypes {
Follow(Follow), Follow,
Undo(Undo), Undo,
} }
impl CommunityAcceptedObjects { pub type AcceptedActivities = ActorAndObject<ValidTypes>;
fn follow(&self) -> Result<Follow, LemmyError> {
match self {
CommunityAcceptedObjects::Follow(f) => Ok(f.to_owned()),
CommunityAcceptedObjects::Undo(u) => {
Ok(Follow::from_any_base(u.object().as_one().unwrap().to_owned())?.unwrap())
}
}
}
}
/// Handler for all incoming activities to community inboxes. /// Handler for all incoming activities to community inboxes.
pub async fn community_inbox( pub async fn community_inbox(
request: HttpRequest, request: HttpRequest,
input: web::Json<CommunityAcceptedObjects>, input: web::Json<AcceptedActivities>,
path: web::Path<String>, path: web::Path<String>,
db: DbPoolParam, db: DbPoolParam,
client: web::Data<Client>, client: web::Data<Client>,
_chat_server: ChatServerParam, _chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let input = input.into_inner(); let activity = input.into_inner();
let path = path.into_inner(); let path = path.into_inner();
let community = blocking(&db, move |conn| Community::read_from_name(&conn, &path)).await??; let community = blocking(&db, move |conn| Community::read_from_name(&conn, &path)).await??;
@ -67,34 +60,35 @@ pub async fn community_inbox(
} }
debug!( debug!(
"Community {} received activity {:?}", "Community {} received activity {:?}",
&community.name, &input &community.name, &activity
); );
let follow = input.follow()?; let user_uri = activity.actor()?.as_single_xsd_any_uri().unwrap();
let user_uri = follow.actor()?.as_single_xsd_any_uri().unwrap(); check_is_apub_id_valid(user_uri)?;
let community_uri = follow.object().as_single_xsd_any_uri().unwrap();
let user = get_or_fetch_and_upsert_user(&user_uri, &client, &db).await?; let user = get_or_fetch_and_upsert_user(&user_uri, &client, &db).await?;
let community = get_or_fetch_and_upsert_community(community_uri, &client, &db).await?;
verify(&request, &user)?; verify(&request, &user)?;
match input { insert_activity(user.id, activity.clone(), false, &db).await?;
CommunityAcceptedObjects::Follow(f) => handle_follow(f, user, community, &client, db).await,
CommunityAcceptedObjects::Undo(u) => handle_undo_follow(u, user, community, db).await, let any_base = activity.clone().into_any_base()?;
let kind = activity.kind().unwrap();
match kind {
ValidTypes::Follow => handle_follow(any_base, user, community, &client, db).await,
ValidTypes::Undo => handle_undo_follow(any_base, user, community, db).await,
} }
} }
/// Handle a follow request from a remote user, adding it to the local database and returning an /// Handle a follow request from a remote user, adding it to the local database and returning an
/// Accept activity. /// Accept activity.
async fn handle_follow( async fn handle_follow(
follow: Follow, activity: AnyBase,
user: User_, user: User_,
community: Community, community: Community,
client: &Client, client: &Client,
db: DbPoolParam, db: DbPoolParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
insert_activity(user.id, follow.clone(), false, &db).await?; let follow = Follow::from_any_base(activity)?.unwrap();
let community_follower_form = CommunityFollowerForm { let community_follower_form = CommunityFollowerForm {
community_id: community.id, community_id: community.id,
user_id: user.id, user_id: user.id,
@ -112,12 +106,12 @@ async fn handle_follow(
} }
async fn handle_undo_follow( async fn handle_undo_follow(
undo: Undo, activity: AnyBase,
user: User_, user: User_,
community: Community, community: Community,
db: DbPoolParam, db: DbPoolParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
insert_activity(user.id, undo, false, &db).await?; let _undo = Undo::from_any_base(activity)?.unwrap();
let community_follower_form = CommunityFollowerForm { let community_follower_form = CommunityFollowerForm {
community_id: community.id, community_id: community.id,

View file

@ -1,5 +1,6 @@
use crate::{ use crate::{
apub::{ apub::{
check_is_apub_id_valid,
community::do_announce, community::do_announce,
extensions::signatures::verify, extensions::signatures::verify,
fetcher::{ fetcher::{
@ -32,11 +33,11 @@ use activitystreams::{
use actix_web::{client::Client, web, HttpRequest, HttpResponse}; use actix_web::{client::Client, web, HttpRequest, HttpResponse};
use lemmy_db::user::User_; use lemmy_db::user::User_;
use log::debug; use log::debug;
use serde::Serialize; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
use url::Url; use url::Url;
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, serde::Deserialize, serde::Serialize)] #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
#[serde(rename_all = "PascalCase")] #[serde(rename_all = "PascalCase")]
pub enum ValidTypes { pub enum ValidTypes {
Create, Create,
@ -67,16 +68,19 @@ pub async fn shared_inbox(
debug!("Shared inbox received activity: {}", json); debug!("Shared inbox received activity: {}", json);
let sender = &activity.actor()?.to_owned().single_xsd_any_uri().unwrap(); let sender = &activity.actor()?.to_owned().single_xsd_any_uri().unwrap();
// TODO: pass this actor in instead of using get_user_from_activity() // TODO: pass this actor in instead of using get_user_from_activity()
let actor = get_or_fetch_and_upsert_actor(sender, &client, &pool).await?; let actor = get_or_fetch_and_upsert_actor(sender, &client, &pool).await?;
let community = get_community_id_from_activity(&activity).await;
check_is_apub_id_valid(sender)?;
check_is_apub_id_valid(&community)?;
verify(&request, actor.as_ref())?; verify(&request, actor.as_ref())?;
insert_activity(actor.user_id(), activity.clone(), false, &pool).await?; insert_activity(actor.user_id(), activity.clone(), false, &pool).await?;
let any_base = activity.clone().into_any_base()?; let any_base = activity.clone().into_any_base()?;
let kind = activity.kind().unwrap(); let kind = activity.kind().unwrap();
dbg!(kind);
match kind { match kind {
ValidTypes::Announce => receive_announce(any_base, &client, &pool, chat_server).await, ValidTypes::Announce => receive_announce(any_base, &client, &pool, chat_server).await,
ValidTypes::Create => receive_create(any_base, &client, &pool, chat_server).await, ValidTypes::Create => receive_create(any_base, &client, &pool, chat_server).await,
@ -112,6 +116,15 @@ where
get_or_fetch_and_upsert_user(&user_uri, client, pool).await get_or_fetch_and_upsert_user(&user_uri, client, pool).await
} }
pub(in crate::apub::inbox) async fn get_community_id_from_activity<T, A>(activity: &T) -> Url
where
T: AsBase<A> + ActorAndObjectRef + AsObject<A>,
{
let cc = activity.cc().unwrap();
let cc = cc.as_many().unwrap();
cc.first().unwrap().as_xsd_any_uri().unwrap().to_owned()
}
pub(in crate::apub::inbox) async fn announce_if_community_is_local<T, Kind>( pub(in crate::apub::inbox) async fn announce_if_community_is_local<T, Kind>(
activity: T, activity: T,
user: &User_, user: &User_,

View file

@ -1,8 +1,9 @@
use crate::{ use crate::{
api::user::PrivateMessageResponse, api::user::PrivateMessageResponse,
apub::{ apub::{
check_is_apub_id_valid,
extensions::signatures::verify, extensions::signatures::verify,
fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user}, fetcher::{get_or_fetch_and_upsert_actor, get_or_fetch_and_upsert_community},
insert_activity, insert_activity,
FromApub, FromApub,
}, },
@ -13,7 +14,8 @@ use crate::{
LemmyError, LemmyError,
}; };
use activitystreams::{ use activitystreams::{
activity::{Accept, Create, Delete, Undo, Update}, activity::{Accept, ActorAndObject, Create, Delete, Undo, Update},
base::AnyBase,
object::Note, object::Note,
prelude::*, prelude::*,
}; };
@ -28,68 +30,76 @@ use lemmy_db::{
Followable, Followable,
}; };
use log::debug; use log::debug;
use serde::Deserialize; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
#[serde(untagged)] #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
#[derive(Deserialize, Debug)] #[serde(rename_all = "PascalCase")]
pub enum UserAcceptedObjects { pub enum ValidTypes {
Accept(Box<Accept>), Accept,
Create(Box<Create>), Create,
Update(Box<Update>), Update,
Delete(Box<Delete>), Delete,
Undo(Box<Undo>), Undo,
} }
pub type AcceptedActivities = ActorAndObject<ValidTypes>;
/// Handler for all incoming activities to user inboxes. /// Handler for all incoming activities to user inboxes.
pub async fn user_inbox( pub async fn user_inbox(
request: HttpRequest, request: HttpRequest,
input: web::Json<UserAcceptedObjects>, input: web::Json<AcceptedActivities>,
path: web::Path<String>, path: web::Path<String>,
client: web::Data<Client>, client: web::Data<Client>,
db: DbPoolParam, pool: DbPoolParam,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
// TODO: would be nice if we could do the signature check here, but we cant access the actor property let activity = input.into_inner();
let input = input.into_inner();
let username = path.into_inner(); let username = path.into_inner();
debug!("User {} received activity: {:?}", &username, &input); debug!("User {} received activity: {:?}", &username, &activity);
match input { let actor_uri = activity.actor()?.as_single_xsd_any_uri().unwrap();
UserAcceptedObjects::Accept(a) => receive_accept(*a, &request, &username, &client, &db).await,
UserAcceptedObjects::Create(c) => { check_is_apub_id_valid(actor_uri)?;
receive_create_private_message(*c, &request, &client, &db, chat_server).await
let actor = get_or_fetch_and_upsert_actor(actor_uri, &client, &pool).await?;
verify(&request, actor.as_ref())?;
insert_activity(actor.user_id(), activity.clone(), false, &pool).await?;
let any_base = activity.clone().into_any_base()?;
let kind = activity.kind().unwrap();
match kind {
ValidTypes::Accept => receive_accept(any_base, username, &client, &pool).await,
ValidTypes::Create => {
receive_create_private_message(any_base, &client, &pool, chat_server).await
} }
UserAcceptedObjects::Update(u) => { ValidTypes::Update => {
receive_update_private_message(*u, &request, &client, &db, chat_server).await receive_update_private_message(any_base, &client, &pool, chat_server).await
} }
UserAcceptedObjects::Delete(d) => { ValidTypes::Delete => {
receive_delete_private_message(*d, &request, &client, &db, chat_server).await receive_delete_private_message(any_base, &client, &pool, chat_server).await
} }
UserAcceptedObjects::Undo(u) => { ValidTypes::Undo => {
receive_undo_delete_private_message(*u, &request, &client, &db, chat_server).await receive_undo_delete_private_message(any_base, &client, &pool, chat_server).await
} }
} }
} }
/// Handle accepted follows. /// Handle accepted follows.
async fn receive_accept( async fn receive_accept(
accept: Accept, activity: AnyBase,
request: &HttpRequest, username: String,
username: &str,
client: &Client, client: &Client,
pool: &DbPool, pool: &DbPool,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let accept = Accept::from_any_base(activity)?.unwrap();
let community_uri = accept.actor()?.to_owned().single_xsd_any_uri().unwrap(); let community_uri = accept.actor()?.to_owned().single_xsd_any_uri().unwrap();
let community = get_or_fetch_and_upsert_community(&community_uri, client, pool).await?; let community = get_or_fetch_and_upsert_community(&community_uri, client, pool).await?;
verify(request, &community)?;
let username = username.to_owned();
let user = blocking(pool, move |conn| User_::read_from_name(conn, &username)).await??; let user = blocking(pool, move |conn| User_::read_from_name(conn, &username)).await??;
insert_activity(community.creator_id, accept, false, pool).await?;
// Now you need to add this to the community follower // Now you need to add this to the community follower
let community_follower_form = CommunityFollowerForm { let community_follower_form = CommunityFollowerForm {
community_id: community.id, community_id: community.id,
@ -107,20 +117,14 @@ async fn receive_accept(
} }
async fn receive_create_private_message( async fn receive_create_private_message(
create: Create, activity: AnyBase,
request: &HttpRequest,
client: &Client, client: &Client,
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user_uri = &create.actor()?.to_owned().single_xsd_any_uri().unwrap(); let create = Create::from_any_base(activity)?.unwrap();
let note = Note::from_any_base(create.object().as_one().unwrap().to_owned())?.unwrap(); let note = Note::from_any_base(create.object().as_one().unwrap().to_owned())?.unwrap();
let user = get_or_fetch_and_upsert_user(user_uri, client, pool).await?;
verify(request, &user)?;
insert_activity(user.id, create, false, pool).await?;
let private_message = PrivateMessageForm::from_apub(&note, client, pool).await?; let private_message = PrivateMessageForm::from_apub(&note, client, pool).await?;
let inserted_private_message = blocking(pool, move |conn| { let inserted_private_message = blocking(pool, move |conn| {
@ -148,20 +152,14 @@ async fn receive_create_private_message(
} }
async fn receive_update_private_message( async fn receive_update_private_message(
update: Update, activity: AnyBase,
request: &HttpRequest,
client: &Client, client: &Client,
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user_uri = &update.actor()?.to_owned().single_xsd_any_uri().unwrap(); let update = Update::from_any_base(activity)?.unwrap();
let note = Note::from_any_base(update.object().as_one().unwrap().to_owned())?.unwrap(); let note = Note::from_any_base(update.object().as_one().unwrap().to_owned())?.unwrap();
let user = get_or_fetch_and_upsert_user(&user_uri, client, pool).await?;
verify(request, &user)?;
insert_activity(user.id, update, false, pool).await?;
let private_message_form = PrivateMessageForm::from_apub(&note, client, pool).await?; let private_message_form = PrivateMessageForm::from_apub(&note, client, pool).await?;
let private_message_ap_id = private_message_form.ap_id.clone(); let private_message_ap_id = private_message_form.ap_id.clone();
@ -197,20 +195,14 @@ async fn receive_update_private_message(
} }
async fn receive_delete_private_message( async fn receive_delete_private_message(
delete: Delete, activity: AnyBase,
request: &HttpRequest,
client: &Client, client: &Client,
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let user_uri = &delete.actor()?.to_owned().single_xsd_any_uri().unwrap(); let delete = Delete::from_any_base(activity)?.unwrap();
let note = Note::from_any_base(delete.object().as_one().unwrap().to_owned())?.unwrap(); let note = Note::from_any_base(delete.object().as_one().unwrap().to_owned())?.unwrap();
let user = get_or_fetch_and_upsert_user(&user_uri, client, pool).await?;
verify(request, &user)?;
insert_activity(user.id, delete, false, pool).await?;
let private_message_form = PrivateMessageForm::from_apub(&note, client, pool).await?; let private_message_form = PrivateMessageForm::from_apub(&note, client, pool).await?;
let private_message_ap_id = private_message_form.ap_id; let private_message_ap_id = private_message_form.ap_id;
@ -258,20 +250,14 @@ async fn receive_delete_private_message(
} }
async fn receive_undo_delete_private_message( async fn receive_undo_delete_private_message(
undo: Undo, activity: AnyBase,
request: &HttpRequest,
client: &Client, client: &Client,
pool: &DbPool, pool: &DbPool,
chat_server: ChatServerParam, chat_server: ChatServerParam,
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let undo = Undo::from_any_base(activity)?.unwrap();
let delete = Delete::from_any_base(undo.object().as_one().unwrap().to_owned())?.unwrap(); let delete = Delete::from_any_base(undo.object().as_one().unwrap().to_owned())?.unwrap();
let note = Note::from_any_base(delete.object().as_one().unwrap().to_owned())?.unwrap(); let note = Note::from_any_base(delete.object().as_one().unwrap().to_owned())?.unwrap();
let user_uri = &delete.actor()?.to_owned().single_xsd_any_uri().unwrap();
let user = get_or_fetch_and_upsert_user(&user_uri, client, pool).await?;
verify(request, &user)?;
insert_activity(user.id, delete, false, pool).await?;
let private_message = PrivateMessageForm::from_apub(&note, client, pool).await?; let private_message = PrivateMessageForm::from_apub(&note, client, pool).await?;

View file

@ -63,33 +63,34 @@ where
} }
// Checks if the ID has a valid format, correct scheme, and is in the allowed instance list. // Checks if the ID has a valid format, correct scheme, and is in the allowed instance list.
fn is_apub_id_valid(apub_id: &Url) -> bool { fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> {
debug!("Checking {}", apub_id);
if apub_id.scheme() != get_apub_protocol_string() { if apub_id.scheme() != get_apub_protocol_string() {
debug!("invalid scheme: {:?}", apub_id.scheme()); return Err(anyhow!("invalid apub id scheme: {:?}", apub_id.scheme()).into());
return false;
} }
let allowed_instances: Vec<String> = Settings::get() let mut allowed_instances: Vec<String> = Settings::get()
.federation .federation
.allowed_instances .allowed_instances
.split(',') .split(',')
.map(|d| d.to_string()) .map(|d| d.to_string())
.collect(); .collect();
// need to allow this explicitly because apub activities might contain objects from our local
// instance. replace is needed to remove the port in our federation test setup.
let settings = Settings::get();
let local_instance = settings.hostname.split(':').collect::<Vec<&str>>();
allowed_instances.push(local_instance.first().unwrap().to_string());
match apub_id.domain() { match apub_id.domain() {
Some(d) => { Some(d) => {
let contains = allowed_instances.contains(&d.to_owned()); let contains = allowed_instances.contains(&d.to_owned());
if !contains { if !contains {
debug!("{} not in {:?}", d, allowed_instances); return Err(anyhow!("{} not in federation allowlist", d).into());
} }
contains Ok(())
}
None => {
debug!("missing domain");
false
} }
None => Err(anyhow!("federation allowlist is empty").into()),
} }
} }

2
ui/package.json vendored
View file

@ -6,7 +6,7 @@
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"api-test": "jest src/api_tests/ --max-workers=1", "api-test": "jest src/api_tests/ -i --verbose",
"build": "node fuse prod", "build": "node fuse prod",
"lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src", "lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src",
"prebuild": "node generate_translations.js", "prebuild": "node generate_translations.js",