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

MSC3847: Ignoring invites with policy rooms #3847

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions proposals/3847-ignoring-invites-with-policy-rooms.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# MSC3847: Ignoring invites using individual policy rooms

Receiving unwanted invites is something that users currently need to live
with on the Matrix network. To alleviate this, Matrix needs a mechanism to
let users specify that they are not interested in invites from specific
users or towards specific rooms.

In this proposal, we introduce the necessary extensions to let users do
this and to let clients perform filtering of unwanted invites.

We proceed as follows:

1. We build upon the mechanism of policy rooms, introduced in [MSC2313](https://github.com/matrix-org/matrix-doc/pull/2313), and define
a user's individual policy room, which may be created on behalf of the user by
a Matrix client, and which is shared across all devices and clients of the user.
2. We build upon the mechanism of recommendations, also introduced in [MSC2313](https://github.com/matrix-org/matrix-doc/pull/2313),
and create a new recommendation for ignoring invites from a specific user, from
a specific server or towards a specific room.


## Proposal

### Background

[Matrix specs define policy rooms](https://spec.matrix.org/v1.3/client-server-api/#moderation-policy-lists).
A policy room is a room in which rules such as the following may be published:

```jsonc
{
"type": "m.policy.rule.user", // Or `m.policy.rule.server` or `m.policy.rule.room`.
"state_key": "rule_1", // Arbitrary.
"content": {
"entity": "@alice:example.org",
"recommendation": "m.ban",
"reason": "undesirable behaviour"
}
}
```

Policy rooms are designed to be associated with entire servers, communities,
individual rooms or individual users, but there is no specification
clarifying how to associate an issuer with a policy room.

### Associating policy rooms to a user

For individual users, we introduce a new event `m.policies`, designed
to be used as part of account data. This event has content:

| Content | Type | Description |
|---------|------|-------------|
| `m.ignore.invites` | `Policies` | A list of rooms in which policies should be understood as "ignore invite" lists. |

We expect that future MSCs will expand upon this event `m.policies` and
add further fields with other lists of rooms in which policies should be
understood differently. This is, however, beyond the scope of the current
MSC.
Comment on lines +53 to +56
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this MSC include requiring invite reasons to be specified for an invite to be acceptable or is that something for a future MSC that these lines speak of?


We also expect that future MSCs will expand upon this event `m.policies`
to add semantics in other positions than account data, e.g. community rooms.
This is also beyond the scope of the current MSC.
Comment on lines +58 to +60
Copy link
Contributor

Choose a reason for hiding this comment

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

I do have some concerns regarding that, which maybe should affect the design even now:

I moderate 3 very different communities with partially shared and partially separate banlists (and one of them is a bigger community moderation effort across very different communities). In this case we currently have usually 2 different policy rooms per community, although this varies a bit. So in my case that would be 5 separate policy rooms.

Currently we only issue m.ban and having a specific list for ignores or invite ignores probably has different rules, but in general I think there needs to be a method to pick out of several policy lists as a target. This can of course have different methods, that might be useful. For example since usually community rooms are inside a space, it might make sense to pick the policy rooms for that space. This would probably be set in the room account data. Alternatively targets could be a list, where the client automatically picks the only list, if there is only one, but if there are multiple elements, it could offer a choice.

Now yes, this is out of scope for this MSC, but I think if it adds something incompatible with such goals, that might interfere with some use cases in the future?

Copy link
Author

Choose a reason for hiding this comment

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

So you'd like all the users who join any room in your space to share a list of ignored invites? Or do I misunderstand?

Copy link
Contributor

Choose a reason for hiding this comment

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

No, but if this is ever reused for something like m.ban, I don't want all my bans to automatically go to one list, I want it to go to different lists depending on what list I have open. I can't have a single "target" list in account data.

Copy link
Author

Choose a reason for hiding this comment

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

So, if I understand correctly your concern, you're afraid that some Matrix client could start issuing policies into a community policy room (e.g. a space's CoC room) instead of your own individual policy room (e.g. the list of invites that you, as a user, don't want to see). Is that correct?

Normally, this shouldn't happen.

The idea is that all your individual bans (i.e. the bans that are expected to affect only events you receive) will go into your individual policy rooms, as specified by the target. However, your community bans (i.e. the bans that you're enacting as a moderator/admin/... for a room/a space/a server) go to their policy rooms, just as they do right now.

Unless you specifically configure your account to use a community room as your individual policy room (and I don't see any reason why someone would do that), these lists are entirely distinct. Chances are that they are going to be managed by different tools, too (your usual Matrix client for the individual policies, Mjölnir or another bot for the community policies).

Does this make sense?

Copy link
Contributor

Choose a reason for hiding this comment

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

No, my concern is that this duplicates/conflicts with how I planned to have Nheko apply policy rules in the next major release, where you can define a list of target policy rooms per space to which the ban recommendations get posted. The plan was to control that by adding a policy target account data event to each space, which has a list of targets and sources from which policy rules are taken or to which the policy rules are posted.

Copy link
Author

Choose a reason for hiding this comment

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

This looks complementary, no?

You're defining source/target per space, I'm defining source/target for individual users.

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, usually you have an inheritance change of a global default (for the account) and then finer grained settings for each space/room.


Where `Policies` is defined as:

| Content | Type | Description |
|-------------|------|-------------|
| `target` | Room ID | A room in which to issue new policies. |
| `sources` | Room ID [] | A list of rooms from which to apply new policies. Should generally include `target`. |

The expected behavior is that:

- if a user Alice has a `m.policies` with key `m.ignore.invites` and `target` R,
then whenever Alice issues a new policy to ignore invites from their client
or another trusted agent, this policy will be stored in room R.

- if a user Alice has a `m.policies` with key `m.ignore.invites` and `sources`
containing room R, any client or trusted agent acting on behalf of Alice will
monitor room R for new policies and apply the recommendations on behalf of Alice,
interpreting such policies as "ignore invites".

### Expanding recommendations to individual events

Policy lists define three scopes `m.policy.rule.user` for rules that deal with users,
`m.policy.rule.room` for rules that deals with rooms and `m.policy.rule.server` for
rules that deal with servers.

We expand these lists with a fourth scope `m.policy.rule.event` for rules that deal
with individual events, in this case ignoring a specific invite.

### Suggested client behaviour

If a user Alice has a `m.policies` with key `m.ignore.invites` and `sources` containing
room R *and* if a new policy `m.ban` appears in R:

- any pending invite currently displayed that matches the `entity` is removed from display;
- any incoming invite that matches the `entity` is not displayed among invites.

However, clients are expected to offer the ability to look at any ignored invite,
in a manner similar to a trashcan/recycle bin/undelete mechanism for desktop file
systems.

Similarly, if a policy `m.ban` in a `m.ignore.invites` room is redacted/amended,
clients should show any invite that doesn't match any `m.ignore.invites` & `m.ban`
entities anymore.

If the client detects that one of the rooms has been upgraded, it should follow
the tombstone to the new room.

### Server behavior

None at this stage. While implementation details may differ, key `m.ignore.invites` is
designed *a priori* to be executed entirely client-side.

## Potential issues

### Number of events

There is a risk that the list of ignored invites of some users may grow a lot, which might have
performance impact, both during initial sync and during filtering. We believe that this risk is
limited. If necessary, clients may decide to cleanup ignored invites after some time.

### Sync size

With this proposal, any invite ignored with `m.ignore.invites` will still show up at each `/sync`.
In time, this can grow expensive. This is, however, necessary to be able to un-ignore invites
from the client.
Copy link

Choose a reason for hiding this comment

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

Literal rule matches can be filtered out using a sync filter


We plan to file a followup MSC to introduce a `m.policies` key `m.drop.invites`, which will
ask the server to simply not send the invites during the next `/sync` operations.

## Alternatives

### Rejecting invites

A client could of course reject invites instead of ignoring them. However, experience shows that
spam/bullying tools monitor invite rejections to send invite spam. This entire MSC is meant to
offer an alternative mechanism that would close this gap and let users ignore invites without
notifying the sender.

### Server-side filtering

Just as `m.ignored_users_list` is handled mostly on the server, we could handle `m.invites.ignore`
largely on the server. However, this would make it much harder to undo erroneous ignores (i.e.
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be nice to mention #3659 here which does the filtering on the server.

Copy link

@joshqou joshqou Jun 2, 2024

Choose a reason for hiding this comment

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

@Johennes Both specs aim to fix the same problem but #3659 drops invites as opposed to ignoring them. imo dropping invites is better than a client-side ignore since it wouldn't require all a user's clients to support the spec, even if such behaviour is more "destructive".

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I merely meant to say that mentioning #3659 here would be nice for context on prior art, not necessarily that I'd prefer one over the other. On that matter, filtering invites on the server sounds more efficient but it won't allow you to review ignored invites (and possibly even unignore them). So both seem to have pros and cons.

implementing some sort of recovery from trashcan) on the client.

Consequently, we prefer handling things on the client, even if this may require more traffic.

## Security considerations

### Room aliases
We have decided to specify room IDs rather than room aliases as room aliases can, in some circumstances,
be forged by malicious users/administrators.

### Trust
If the administrator of a policy room R is malicious, they can use this room to specify that all invites,
or some specific good invites, should be ignored. A user who uses R as a `source` will therefore not see
some invites that they would otherwise see.

In other words, using a room as source requires trusting the administrator of that room.

## Unstable prefix

During testing:

- `m.ignore.invites` should be prefixed `org.matrix.msc3847.ignore.invites`;
- `m.policies` should be prefixed `org.matrix.msc3847.policies`;
- `m.policy.rule.event` should be prefixed `org.matrix.msc3847.policy.rule.event`.