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

MSC3395: Synthetic appservice events #3395

Open
wants to merge 5 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
162 changes: 162 additions & 0 deletions proposals/3395-synthetic-appservice-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# MSC3395: Synthetic Appservice Events
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not a fan of the name, happy to for something better. Mainly to distinguish that these aren't "real" events.


Most services today have the concept of a webhook, which is used to inform an external service about
the state of another service. For instance when a new user is registered on a platform, it is useful
to alert a bot to send a welcome message.

In Matrix we already have the concept of services which complement the homeserver, known as Application
Services. However, they can only be informed of user actions that have taken place in rooms (with
the notable exception of presence / device updates via EDUs). This proposal aims to extend the existing
AS spec to include "synthetic" events where the homeserver can inform the appservice when a variety of
things have happened on the homeserver.

For clarity, this MSC introduces a modest set events that could be extended by further MSCs:

- User registration
- User login
- User logout
- User deactivation
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Noting that @Yoric had some interest in being able to intercept reports from users into services, so perhaps the ideal flow is that appservices are sent reports via this mechanism.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Media creation / deletion would be a good one too.


## Proposal

An appservice must subscribe to the changes that it wishes to listen for. This can be done by setting a new
key in the appservice registration file: `m.synthetic_events`, under the `namespaces` key:

```yaml
namespaces:
users:
- exclusive: false # This needs to be false to allow for registrations
regex: "@.*:mydomain"
m.events: false # Allow or disallow normal events to be sent from this namespace.
m.synthetic_events:
events:
- "m.user.registration"
- "m.user.login"
- "m.user.logout"
- "m.user.deactivated"
```

Currently only the `namespaces.users` field can contain this key, though the door is left open for
future MSCs to expand upon this feature and allow synthetic events for different contexts.
Comment on lines +39 to +40
Copy link
Contributor

Choose a reason for hiding this comment

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

Bikeshed: What about introducing a synthetic namespace where these events are listed instead? I assume this'd be helpful if it were introduced for all users, i think an additional "exclude" (by regex) key could be useful in the future then to exclude the likes of bridged users (to reduce noise)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So the plan atm is to have the m.synthetic_events key sit under the user namespaces, which organically excludes users we don't care about and only include users we do care about.

If you did want all users, you could do a .*. If you wanted all users except bridges, I'd imagine you'd have a regex that negatively matches the bridge users?

There might be scope for a exclusionary namespace eventually for ease of configuration, but definitely out of scope for this MSC


Then, when the homeserver wishes to inform a appservice of an event it would send the event over the
appservice `/transaction` API. If the application service is down, these events SHOULD be retried when
the appservice comes back up.

As the synthetic events are namespaced, the AS should only be sent events for users in that namespace.

Because a namespace is listed for these users, the AS will also recieve room events for these users by default. To opt-out
of sending room events to the AS (and allow only synthetic events to be sent), the key `m.events` can be set to `false`.

```
PUT /_matrix/app/v1/transactions/{txnId}
```

```json5
{
"m.synthetic_events": [{
"type": "m.user.deactivated",
"content": {
"user_id": "@alice:example.com"
},
"ts": 1432735824653,
}],
"events": [/* ... */]
}
```

For each of the event types given above, there is an expected schema. As with all Matrix
event contents, this can be extended to include implementation specific metadata.

### `m.user.registration`

This should be sent when a new user registers on the homeserver.

```json5
{
"type": "m.user.registration",
"content": {
"user_id": "@alice:example.com"
}
}
```

### `m.user.login`

This should be sent when an existing user logs in on the homeserver.

```json5
{
"type": "m.user.login",
"content": {
"user_id": "@alice:example.com",
"device_id": "ABCDEF"
}
}
```

### `m.user.logout`

This should be sent when an existing user logs out of their session.

```json5
{
"type": "m.user.logout",
"content": {
"user_id": "@alice:example.com",
"soft_logout": true,
"device_id": "ABCDEF"
}
}
```

### `m.user.deactivated`

This should be sent when an existing user deactivates their account.

```json5
{
"type": "m.user.logout",
"content": {
"user_id": "@alice:example.com"
}
}
```

## Potential issues

Appservices can now request permissions to reveal quite intimate details about each user, which means that homeserver
Half-Shot marked this conversation as resolved.
Show resolved Hide resolved
administrators will need to be more careful when adding new appservice registrations. However, it has always been the
case that appservices should be considered powerful tools that need review before being connected. The ability to
namespace the events sent allows for fine-grained control.

This proposal would not work over a federated context, as federated homeservers are not aware of foregin appservices.
That being said the events suggested in this proposal are sensitive and are expected to only be shared with immediate
appservices connected to the homeserver. It would be possible for an appservice to "proxy" these events to a seperate room
if federation of the information is desired, though.

## Alternatives

One alternative would be to have homeserver implementations make an "events" room, which sends these events
as normal room events rather than synthetic events. Appservices would be joined and left to this room and would
recieve events organically. However there are some problems with this approach:

- It increases the burden on the homeserver implementor to manage these rooms, including membership of
each appservice.
- It would require each of these events to be stored in the homeserver database, which would increase storage
costs over time and would require homeservers to store lots of activity in the database.
- While varying by implementation, it would be slower to store an event in a room and send it to an AS, than
just to send it.
- Each event type would need it's own room to allow fine grained control over which events the appservice would
recieve, at least until a form of per-message ACLs lands in the spec.

For these reasons, the suggested proposal was chosen.

## Security considerations

These events will be sent down the same channel as other AS events, and so the security footprint
is not impacted.

## Unstable prefix

All keys mentioned in this document beginning with `m.` will use `uk.half-shot.msc3395.` as the prefix.