Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Receive and store remote site bans (fixes #3399) #5515

Merged
merged 35 commits into from
Mar 28, 2025
Merged

Conversation

Nutomic
Copy link
Member

@Nutomic Nutomic commented Mar 17, 2025

Continued from #4571

Todo:

  • New fields for instance_actions: received_ban and ban_expires
  • Scheduled task for ban expiration
  • Remove ban_nonlocal_user_from_local_communities(), send ban activity for remote users
  • Receive site bans from federated instances and write to instance_actions
  • Add modlog column mod_ban.instance_id
  • When receiving remote ban, only remove content in communities from that instance
  • Check for ban before posting to remote community
  • Remove person.banned column?

@Nutomic Nutomic marked this pull request as ready for review March 18, 2025 14:27
Some(site.instance_id),
true,
)
.await?;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the main logic for receiving federated site bans.

ADD COLUMN instance_id int NOT NULL REFERENCES instance ON UPDATE CASCADE ON DELETE CASCADE;

-- insert existing bans into instance_actions table, assuming they were all banned from home instance
INSERT INTO instance_actions (person_id, instance_id, received_ban, ban_expires)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've never federated instance bans before this, so I think it's safer to only ban them from our local instance, not their home instance.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bans are already federated if they were made on the user's home instance, eg:

https://lemmy.ml/u/[email protected]
https://lemmy.ml/modlog?page=1&actionType=All&userId=17706104

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also add rows for local instance bans also? Seems like we don't know where these bans actually took place then, so it might be safer to do both.

} else {
Ok(())
}
InstanceActions::check_ban(&mut context.pool(), person.id, person.instance_id).await?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should check both.

@@ -160,6 +161,10 @@ impl Post {
update = update.filter(post::community_id.eq(for_community_id));
}

if let Some(for_instance_id) = for_instance_id {
update = update.filter(post::instance_id.eq(for_instance_id));
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

post.instance_id is the instance where the community is hosted, right? Otherwise this would be wrong. Not entirely clear to me where this gets set.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yikes, it looks like instance_id isn't being set (and its default 0!).

I'll make an issue to remove that column, because it should rely on the community's instance_id anyway.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

pub async fn read(pool: &mut DbPool<'_>, local_user_id: LocalUserId) -> Result<Self, Error> {
pub async fn read(pool: &mut DbPool<'_>, local_user_id: LocalUserId) -> LemmyResult<Self> {
let local_instance_id = SiteView::read_local(pool).await?.instance.id;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd much prefer all these read_locals were brought up a level. Instead make local_instance_id a function param.

Lets try to keep view and schema functions to a single DB query whenever possible, and keep multiple reads at the API / APUB level.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont like that idea because it makes all the callsites more verbose. These methods are called in many dozens of places so it would have to be passed everywhere, its much easier to read the instance id only a couple of times here. Anyway thanks to caching it doesnt perform a actual db read in most cases.

.optional()?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?,
)
static CACHE: CacheLock<SiteView> = LazyLock::new(build_cache);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove caching from LocalSite::read, and replace every case of it with this one. Possibly even remove that function or make it non-public.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment here: #5515 (comment)

Comment on lines 177 to 184
#[diesel::dsl::auto_type]
pub fn person_with_instance_actions(local_instance_id: InstanceId) -> _ {
person::table.inner_join(
instance_actions::table.on(
instance_actions::instance_id
.eq(local_instance_id)
.and(instance_actions::person_id.eq(person::id)),
),
Copy link
Member

@dessalines dessalines Mar 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename this to local_instance_person_join, and remove line 179.

Then do person::table.left_join(local_instance_person_join(local_instance_id))

Then its more flexible.

Also I think it should be a left join.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed to left join. This function is always used together with person::table so may as well make the calling code simpler by including it here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather any filtering / common join statements be independent of the table, and only include the .on clause. Check out here for an example.

If I included the original search_combined table in all those, it would've been impossible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright changed

@@ -499,9 +500,9 @@ test("Enforce site ban federation for local user", async () => {
// alpha ban should be federated to beta
let alphaUserOnBeta1 = await waitUntil(
() => resolvePerson(beta, alphaUserActorId!),
res => res.person?.person.banned ?? false,
res => res.person?.instance_actions?.received_ban != null,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is now failing, because PersonView only returns the ban for the local instance, but not the ban from user's home instance. Not sure what we should do here, return two instance_action fields for local instance and for user's home instance?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, probably named local_instance_actions and home_instance_actions. This unfortunately is going to require aliasing similar to creator_community_actions.

We need to do the same for every view that joins to the instance table: one for the person's home instance, and another for our local instance.

Grepping for every case of instance_actions in db_views/structs should be enough.

Let me know if you want me to do this, as I went through this process recently.

Copy link
Member Author

@Nutomic Nutomic Mar 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. One disadvantage is that home_instance_actions is also included for local users, so there is the same data twice. Also need to update the js client to get tests passing.

Copy link
Member

@dessalines dessalines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm realizing that the way I did instance_actions is a bit wrong, so I'll start working on a PR to correct it to this one.

In short, I'm currently only doing instance actions for my user. In reality, similar to creator_community_actions, we need it for the creator of the content. So we need a total of three:

  • instance_actions : for my own actions to the item's home
  • creator_local_instance_actions : for creator to our local instance
  • creator_home_instance_actions : for creator to item's home instance

Comment on lines -20 to -28
static CACHE: CacheLock<LocalSite> = LazyLock::new(build_cache);
Ok(
CACHE
.try_get_with((), async {
let conn = &mut get_conn(pool).await?;
local_site::table.first(conn).await
})
.await?,
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@Nutomic
Copy link
Member Author

Nutomic commented Mar 28, 2025

Im not sure that is right. instance_actions only stores data for bans and user-instance blocks. Blocks are not federated so we only need those for the local instance id. For bans we care about these specific cases:

  • user banned from local instance
  • user banned from his home instance
  • user banned from a third instance, this only matters in communities belonging to that instance

I suppose the last one is what you are talking about, so we need to add community_instance_actions to post_view and comment_view. However its better to merge this pr first and make further changes directly to main branch. Otherwise there will be too many conflicts with other changes and constant rebasing.

@dessalines
Copy link
Member

The main issue is that the current instance_actions are always using my user, as opposed to the item creator. But I agree we can merge this to main, since I'm already cleaning this up anyway.

@dessalines dessalines merged commit 636811e into main Mar 28, 2025
0 of 2 checks passed
Nothing4You added a commit to Nothing4You/lemmy that referenced this pull request Mar 29, 2025
this was originally removed in LemmyNet#5546, but LemmyNet#5515 introduced a new usage of it.
due to the order of PR merges this slipped through and broke the build on main.

fixes LemmyNet#5561
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants