From b8daa5673a215b7367eabc2a8467c540a833a34d Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Tue, 1 Feb 2022 22:14:44 +0100 Subject: [PATCH] start adding api tests --- api_tests/package.json | 2 +- api_tests/src/post.spec.ts | 75 ++++++++++++------- api_tests/src/shared.ts | 19 ++--- api_tests/src/user.spec.ts | 43 +++++++++++ crates/api/src/community.rs | 29 +------ crates/api_common/src/lib.rs | 38 +++++++++- crates/api_crud/src/site/create.rs | 4 +- .../apub/src/activities/block/block_user.rs | 10 +-- crates/apub/src/http/routes.rs | 4 +- crates/apub/src/http/site.rs | 1 - crates/apub/src/lib.rs | 4 +- 11 files changed, 155 insertions(+), 74 deletions(-) diff --git a/api_tests/package.json b/api_tests/package.json index e8f62b23ff..ddf5ca3de6 100644 --- a/api_tests/package.json +++ b/api_tests/package.json @@ -9,7 +9,7 @@ "scripts": { "lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src", "fix": "prettier --write src && eslint --fix src", - "api-test": "jest src/ -i --verbose" + "api-test": "jest src/post.spec.ts -i --verbose -t 'Enforce site ban for federated user'" }, "devDependencies": { "@types/jest": "^26.0.23", diff --git a/api_tests/src/post.spec.ts b/api_tests/src/post.spec.ts index b3b52ee0be..a4a0928b3f 100644 --- a/api_tests/src/post.spec.ts +++ b/api_tests/src/post.spec.ts @@ -298,28 +298,43 @@ test('A and G subscribe to B (center) A posts, it gets announced to G', async () test('Enforce site ban for federated user', async () => { let alphaShortname = `@lemmy_alpha@lemmy-alpha:8541`; - let alphaPerson = (await resolvePerson(beta, alphaShortname)).person; + let alphaPerson = (await resolvePerson(alpha, alphaShortname)).person; expect(alphaPerson).toBeDefined(); - // ban alpha from beta site - let banAlpha = await banPersonFromSite(beta, alphaPerson.person.id, true); + let postRes1 = await createPost(alpha, betaCommunity.community.id); + let searchBeta1 = await searchPostLocal(beta, postRes1.post_view.post); + expect(searchBeta1.posts[0]).toBeDefined(); + + // ban alpha from site + let banAlpha = await banPersonFromSite(alpha, alphaPerson.person.id, true, true); expect(banAlpha.banned).toBe(true); - // Alpha makes post on beta - let postRes = await createPost(alpha, betaCommunity.community.id); - expect(postRes.post_view.post).toBeDefined(); - expect(postRes.post_view.community.local).toBe(false); - expect(postRes.post_view.creator.local).toBe(true); - expect(postRes.post_view.counts.score).toBe(1); + // alpha ban should be federated to beta + let alphaUserOnBeta1 = await resolvePerson(beta, alphaPerson.person.actor_id); + console.debug(alphaUserOnBeta1); + expect(alphaUserOnBeta1.person.person.banned).toBe(true); + + // post should be removed + let searchBeta2 = await searchPostLocal(beta, postRes1.post_view.post); + expect(searchBeta2.posts[0]).toBeUndefined(); + + // Alpha makes new post on beta + let postRes2 = await createPost(alpha, betaCommunity.community.id); + expect(postRes2.post_view.post).toBeDefined(); + expect(postRes2.post_view.community.local).toBe(false); + expect(postRes2.post_view.creator.local).toBe(true); + expect(postRes2.post_view.counts.score).toBe(1); // Make sure that post doesn't make it to beta - let searchBeta = await searchPostLocal(beta, postRes.post_view.post); - let betaPost = searchBeta.posts[0]; - expect(betaPost).toBeUndefined(); + let searchBeta = await searchPostLocal(beta, postRes2.post_view.post); + expect(searchBeta.posts[0]).toBeUndefined(); // Unban alpha - let unBanAlpha = await banPersonFromSite(beta, alphaPerson.person.id, false); + let unBanAlpha = await banPersonFromSite(alpha, alphaPerson.person.id, false, false); expect(unBanAlpha.banned).toBe(false); + + let alphaUserOnBeta2 = await resolvePerson(beta, alphaPerson.person.actor_id) + expect(alphaUserOnBeta2.person.person.banned).toBe(false); }); test('Enforce community ban for federated user', async () => { @@ -327,33 +342,41 @@ test('Enforce community ban for federated user', async () => { let alphaPerson = (await resolvePerson(beta, alphaShortname)).person; expect(alphaPerson).toBeDefined(); - // ban alpha from beta site - await banPersonFromCommunity(beta, alphaPerson.person.id, 2, false); - let banAlpha = await banPersonFromCommunity(beta, alphaPerson.person.id, 2, true); + // make a post in beta, it goes through + let postRes1 = await createPost(alpha, betaCommunity.community.id); + let searchBeta1 = await searchPostLocal(beta, postRes1.post_view.post); + expect(searchBeta1.posts[0]).toBeDefined(); + + // ban alpha from beta community + let banAlpha = await banPersonFromCommunity(beta, alphaPerson.person.id, 2, true, true); expect(banAlpha.banned).toBe(true); + // ensure that the post by alpha got removed + let searchAlpha1 = await searchPostLocal(alpha, postRes1.post_view.post); + expect(searchAlpha1.posts[0]).toBeUndefined(); + // Alpha tries to make post on beta, but it fails because of ban - let postRes = await createPost(alpha, betaCommunity.community.id); - expect(postRes.post_view).toBeUndefined(); + let postRes2 = await createPost(alpha, betaCommunity.community.id); + expect(postRes2.post_view).toBeUndefined(); // Unban alpha let unBanAlpha = await banPersonFromCommunity( beta, alphaPerson.person.id, 2, + false, false ); expect(unBanAlpha.banned).toBe(false); - let postRes2 = await createPost(alpha, betaCommunity.community.id); - expect(postRes2.post_view.post).toBeDefined(); - expect(postRes2.post_view.community.local).toBe(false); - expect(postRes2.post_view.creator.local).toBe(true); - expect(postRes2.post_view.counts.score).toBe(1); + let postRes3 = await createPost(alpha, betaCommunity.community.id); + expect(postRes3.post_view.post).toBeDefined(); + expect(postRes3.post_view.community.local).toBe(false); + expect(postRes3.post_view.creator.local).toBe(true); + expect(postRes3.post_view.counts.score).toBe(1); // Make sure that post makes it to beta community - let searchBeta = await searchPostLocal(beta, postRes2.post_view.post); - let betaPost = searchBeta.posts[0]; - expect(betaPost).toBeDefined(); + let searchBeta2 = await searchPostLocal(beta, postRes3.post_view.post); + expect(searchBeta2.posts[0]).toBeDefined(); }); test('Report a post', async () => { diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index 1eec6dcfb3..8c4e08ff4f 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -66,23 +66,23 @@ export interface API { } export let alpha: API = { - client: new LemmyHttp('http://localhost:8541'), + client: new LemmyHttp('http://127.0.0.1:8541'), }; export let beta: API = { - client: new LemmyHttp('http://localhost:8551'), + client: new LemmyHttp('http://127.0.0.1:8551'), }; export let gamma: API = { - client: new LemmyHttp('http://localhost:8561'), + client: new LemmyHttp('http://127.0.0.1:8561'), }; export let delta: API = { - client: new LemmyHttp('http://localhost:8571'), + client: new LemmyHttp('http://127.0.0.1:8571'), }; export let epsilon: API = { - client: new LemmyHttp('http://localhost:8581'), + client: new LemmyHttp('http://127.0.0.1:8581'), }; const password = 'lemmylemmy' @@ -289,13 +289,14 @@ export async function resolvePerson( export async function banPersonFromSite( api: API, person_id: number, - ban: boolean + ban: boolean, + remove_data: boolean, ): Promise { // Make sure lemmy-beta/c/main is cached on lemmy_alpha let form: BanPerson = { person_id, ban, - remove_data: false, + remove_data, auth: api.auth, }; return api.client.banPerson(form); @@ -305,13 +306,13 @@ export async function banPersonFromCommunity( api: API, person_id: number, community_id: number, + remove_data: boolean, ban: boolean ): Promise { - // Make sure lemmy-beta/c/main is cached on lemmy_alpha let form: BanFromCommunity = { person_id, community_id, - remove_data: false, + remove_data, ban, auth: api.auth, }; diff --git a/api_tests/src/user.spec.ts b/api_tests/src/user.spec.ts index 788987e2c0..73fcedeeca 100644 --- a/api_tests/src/user.spec.ts +++ b/api_tests/src/user.spec.ts @@ -6,16 +6,27 @@ import { resolvePerson, saveUserSettings, getSite, + createCommunity, + setupLogins, + banPersonFromSite, + API, + createPost, + searchPostLocal } from './shared'; import { PersonViewSafe, SaveUserSettings, SortType, ListingType, + LemmyHttp, } from 'lemmy-js-client'; let apShortname: string; +beforeAll(async () => { + await setupLogins(); +}); + function assertUserFederation(userOne: PersonViewSafe, userTwo: PersonViewSafe) { expect(userOne.person.name).toBe(userTwo.person.name); expect(userOne.person.display_name).toBe(userTwo.person.display_name); @@ -60,3 +71,35 @@ test('Set some user settings, check that they are federated', async () => { let betaPerson = (await resolvePerson(beta, apShortname)).person; assertUserFederation(alphaPerson, betaPerson); }); + +/* +test('Ban user from site over federation', async () => { + // create a new user on alpha, get details + let userRes = await registerUser(alpha); + let alphaUser: API = { + client: new LemmyHttp('http://127.0.0.1:8541'), + auth: userRes.jwt + }; + let site = await getSite(alphaUser); + let alphaUserId = site.my_user.local_user_view.person.id; + expect(alphaUserId).toBeDefined(); + + // alpha user makes a post in beta community + let communityRes = await createCommunity(beta); + let postRes1 = await createPost(alphaUser, communityRes.community_view.community.id); + let searchBeta1 = await searchPostLocal(beta, postRes1.post_view.post); + expect(searchBeta1.posts[0]).toBeDefined(); + + let banResponse = await banPersonFromSite(alpha, alphaUserId, true, true); + expect(banResponse).toBeDefined(); + + // alpha should be marked as banned on beta + let alphaUserOnBeta = await resolvePerson(alpha, site.my_user.local_user_view.person.actor_id) + expect(alphaUserOnBeta.person.person.banned).toBeTruthy(); + + // post should be removed + let searchBeta2 = await searchPostLocal(beta, postRes1.post_view.post); + expect(searchBeta2.posts[0]).toBeUndefined(); + +}); +*/ \ No newline at end of file diff --git a/crates/api/src/community.rs b/crates/api/src/community.rs index 3b98eb7d59..57c4b6c3be 100644 --- a/crates/api/src/community.rs +++ b/crates/api/src/community.rs @@ -8,6 +8,7 @@ use lemmy_api_common::{ community::*, get_local_user_view_from_jwt, is_mod_or_admin, + remove_user_data_in_community, }; use lemmy_apub::{ activities::block::SiteOrCommunity, @@ -20,7 +21,6 @@ use lemmy_apub::{ }; use lemmy_db_schema::{ source::{ - comment::Comment, community::{ Community, CommunityFollower, @@ -40,11 +40,9 @@ use lemmy_db_schema::{ ModTransferCommunityForm, }, person::Person, - post::Post, }, traits::{Bannable, Blockable, Crud, Followable, Joinable}, }; -use lemmy_db_views::comment_view::CommentQueryBuilder; use lemmy_db_views_actor::{ community_moderator_view::CommunityModeratorView, community_view::CommunityView, @@ -280,30 +278,7 @@ impl Perform for BanFromCommunity { // Remove/Restore their data if that's desired if remove_data { - // Posts - blocking(context.pool(), move |conn: &'_ _| { - Post::update_removed_for_creator(conn, banned_person_id, Some(community_id), true) - }) - .await??; - - // Comments - // TODO Diesel doesn't allow updates with joins, so this has to be a loop - let comments = blocking(context.pool(), move |conn| { - CommentQueryBuilder::create(conn) - .creator_id(banned_person_id) - .community_id(community_id) - .limit(std::i64::MAX) - .list() - }) - .await??; - - for comment_view in &comments { - let comment_id = comment_view.comment.id; - blocking(context.pool(), move |conn: &'_ _| { - Comment::update_removed(conn, comment_id, true) - }) - .await??; - } + remove_user_data_in_community(community_id, banned_person_id, context.pool()).await?; } // Mod tables diff --git a/crates/api_common/src/lib.rs b/crates/api_common/src/lib.rs index 06b7ff7537..bc41b0c957 100644 --- a/crates/api_common/src/lib.rs +++ b/crates/api_common/src/lib.rs @@ -23,7 +23,10 @@ use lemmy_db_schema::{ traits::{ApubActor, Crud, Readable}, DbPool, }; -use lemmy_db_views::local_user_view::{LocalUserSettingsView, LocalUserView}; +use lemmy_db_views::{ + comment_view::CommentQueryBuilder, + local_user_view::{LocalUserSettingsView, LocalUserView}, +}; use lemmy_db_views_actor::{ community_moderator_view::CommunityModeratorView, community_person_ban_view::CommunityPersonBanView, @@ -593,3 +596,36 @@ pub async fn remove_user_data(banned_person_id: PersonId, pool: &DbPool) -> Resu Ok(()) } + +pub async fn remove_user_data_in_community( + community_id: CommunityId, + banned_person_id: PersonId, + pool: &DbPool, +) -> Result<(), LemmyError> { + // Posts + blocking(pool, move |conn| { + Post::update_removed_for_creator(conn, banned_person_id, Some(community_id), true) + }) + .await??; + + // Comments + // TODO Diesel doesn't allow updates with joins, so this has to be a loop + let comments = blocking(pool, move |conn| { + CommentQueryBuilder::create(conn) + .creator_id(banned_person_id) + .community_id(community_id) + .limit(std::i64::MAX) + .list() + }) + .await??; + + for comment_view in &comments { + let comment_id = comment_view.comment.id; + blocking(pool, move |conn| { + Comment::update_removed(conn, comment_id, true) + }) + .await??; + } + + Ok(()) +} diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs index 3e813e4756..d714afea7d 100644 --- a/crates/api_crud/src/site/create.rs +++ b/crates/api_crud/src/site/create.rs @@ -63,6 +63,7 @@ impl PerformCrud for CreateSite { } let actor_id: DbUrl = Url::parse(&Settings::get().get_protocol_and_hostname())?.into(); + let inbox_url = Some(generate_site_inbox_url(&actor_id)?); let keypair = generate_actor_keypair()?; let site_form = SiteForm { name: data.name.to_owned(), @@ -74,8 +75,9 @@ impl PerformCrud for CreateSite { open_registration: data.open_registration, enable_nsfw: data.enable_nsfw, community_creation_admin_only: data.community_creation_admin_only, + actor_id: Some(actor_id), last_refreshed_at: Some(naive_now()), - inbox_url: Some(generate_site_inbox_url(&actor_id)?), + inbox_url, private_key: Some(Some(keypair.private_key)), public_key: Some(keypair.public_key), ..SiteForm::default() diff --git a/crates/apub/src/activities/block/block_user.rs b/crates/apub/src/activities/block/block_user.rs index 78787c40c1..151861438a 100644 --- a/crates/apub/src/activities/block/block_user.rs +++ b/crates/apub/src/activities/block/block_user.rs @@ -16,7 +16,7 @@ use crate::{ use activitystreams_kinds::{activity::BlockType, public}; use anyhow::anyhow; use chrono::NaiveDateTime; -use lemmy_api_common::{blocking, remove_user_data}; +use lemmy_api_common::{blocking, remove_user_data, remove_user_data_in_community}; use lemmy_apub_lib::{ data::Data, object_id::ObjectId, @@ -148,11 +148,11 @@ impl ActivityHandler for BlockUser { .object .dereference(context, context.client(), request_counter) .await?; - match self + let target = self .target .dereference(context, context.client(), request_counter) - .await? - { + .await?; + match target { SiteOrCommunity::Site(_site) => { let blocked_person = blocking(context.pool(), move |conn| { Person::ban_person(conn, blocked_person.id, true, expires) @@ -196,7 +196,7 @@ impl ActivityHandler for BlockUser { .ok(); if self.remove_data.unwrap_or(false) { - todo!() + remove_user_data_in_community(community.id, blocked_person.id, context.pool()).await?; } // write to mod log diff --git a/crates/apub/src/http/routes.rs b/crates/apub/src/http/routes.rs index c62a45ac8c..d90bf40029 100644 --- a/crates/apub/src/http/routes.rs +++ b/crates/apub/src/http/routes.rs @@ -29,7 +29,6 @@ pub fn config(cfg: &mut web::ServiceConfig, settings: &Settings) { cfg .route("/", web::get().to(get_apub_site_http)) .route("/site_outbox", web::get().to(get_apub_site_outbox)) - .route("/site_inbox", web::get().to(get_apub_site_inbox)) .route( "/c/{community_name}", web::get().to(get_apub_community_http), @@ -61,7 +60,8 @@ pub fn config(cfg: &mut web::ServiceConfig, settings: &Settings) { .guard(InboxRequestGuard) .route("/c/{community_name}/inbox", web::post().to(community_inbox)) .route("/u/{user_name}/inbox", web::post().to(person_inbox)) - .route("/inbox", web::post().to(shared_inbox)), + .route("/inbox", web::post().to(shared_inbox)) + .route("/site_inbox", web::post().to(get_apub_site_inbox)), ); } } diff --git a/crates/apub/src/http/site.rs b/crates/apub/src/http/site.rs index 26be5f9241..894622ad62 100644 --- a/crates/apub/src/http/site.rs +++ b/crates/apub/src/http/site.rs @@ -39,7 +39,6 @@ pub(crate) async fn get_apub_site_outbox() -> Result { pub async fn get_apub_site_inbox( request: HttpRequest, payload: Payload, - _path: web::Path, context: web::Data, ) -> Result { let unparsed = payload_to_string(payload).await?; diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index 4e33ba3924..0652048dc3 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -165,7 +165,9 @@ pub fn generate_inbox_url(actor_id: &DbUrl) -> Result { } pub fn generate_site_inbox_url(actor_id: &DbUrl) -> Result { - Ok(Url::parse(&format!("{}/site_inbox", actor_id))?.into()) + let mut actor_id: Url = actor_id.clone().into(); + actor_id.set_path("site_inbox"); + Ok(actor_id.into()) } pub fn generate_shared_inbox_url(actor_id: &DbUrl) -> Result {