Document Synapse's behaviour when dealing with multiple modules (#11096)
Document Synapse's behaviour when multiple modules register the same callback/web resource/etc. Co-authored-by: reivilibre <oliverw@matrix.org>
This commit is contained in:
parent
e8f24b6c35
commit
73743b8ad1
|
@ -0,0 +1 @@
|
||||||
|
Document Synapse's behaviour when dealing with multiple modules registering the same callbacks and/or handlers for the same HTTP endpoints.
|
|
@ -22,6 +22,11 @@ If the module returns `True`, the current request will be denied with the error
|
||||||
`ORG_MATRIX_EXPIRED_ACCOUNT` and the HTTP status code 403. Note that this doesn't
|
`ORG_MATRIX_EXPIRED_ACCOUNT` and the HTTP status code 403. Note that this doesn't
|
||||||
invalidate the user's access token.
|
invalidate the user's access token.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `None`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `None` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
### `on_user_registration`
|
### `on_user_registration`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -31,3 +36,5 @@ async def on_user_registration(user: str) -> None
|
||||||
Called after successfully registering a user, in case the module needs to perform extra
|
Called after successfully registering a user, in case the module needs to perform extra
|
||||||
operations to keep track of them. (e.g. add them to a database table). The user is
|
operations to keep track of them. (e.g. add them to a database table). The user is
|
||||||
represented by their Matrix user ID.
|
represented by their Matrix user ID.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, Synapse runs them all in order.
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
Synapse supports extending its functionality by configuring external modules.
|
Synapse supports extending its functionality by configuring external modules.
|
||||||
|
|
||||||
|
**Note**: When using third-party modules, you effectively allow someone else to run
|
||||||
|
custom code on your Synapse homeserver. Server admins are encouraged to verify the
|
||||||
|
provenance of the modules they use on their homeserver and make sure the modules aren't
|
||||||
|
running malicious code on their instance.
|
||||||
|
|
||||||
## Using modules
|
## Using modules
|
||||||
|
|
||||||
To use a module on Synapse, add it to the `modules` section of the configuration file:
|
To use a module on Synapse, add it to the `modules` section of the configuration file:
|
||||||
|
@ -18,17 +23,31 @@ modules:
|
||||||
Each module is defined by a path to a Python class as well as a configuration. This
|
Each module is defined by a path to a Python class as well as a configuration. This
|
||||||
information for a given module should be available in the module's own documentation.
|
information for a given module should be available in the module's own documentation.
|
||||||
|
|
||||||
**Note**: When using third-party modules, you effectively allow someone else to run
|
## Using multiple modules
|
||||||
custom code on your Synapse homeserver. Server admins are encouraged to verify the
|
|
||||||
provenance of the modules they use on their homeserver and make sure the modules aren't
|
|
||||||
running malicious code on their instance.
|
|
||||||
|
|
||||||
Also note that we are currently in the process of migrating module interfaces to this
|
The order in which modules are listed in this section is important. When processing an
|
||||||
system. While some interfaces might be compatible with it, others still require
|
action that can be handled by several modules, Synapse will always prioritise the module
|
||||||
configuring modules in another part of Synapse's configuration file.
|
that appears first (i.e. is the highest in the list). This means:
|
||||||
|
|
||||||
|
* If several modules register the same callback, the callback registered by the module
|
||||||
|
that appears first is used.
|
||||||
|
* If several modules try to register a handler for the same HTTP path, only the handler
|
||||||
|
registered by the module that appears first is used. Handlers registered by the other
|
||||||
|
module(s) are ignored and Synapse will log a warning message about them.
|
||||||
|
|
||||||
|
Note that Synapse doesn't allow multiple modules implementing authentication checkers via
|
||||||
|
the password auth provider feature for the same login type with different fields. If this
|
||||||
|
happens, Synapse will refuse to start.
|
||||||
|
|
||||||
|
## Current status
|
||||||
|
|
||||||
|
We are currently in the process of migrating module interfaces to this system. While some
|
||||||
|
interfaces might be compatible with it, others still require configuring modules in
|
||||||
|
another part of Synapse's configuration file.
|
||||||
|
|
||||||
Currently, only the following pre-existing interfaces are compatible with this new system:
|
Currently, only the following pre-existing interfaces are compatible with this new system:
|
||||||
|
|
||||||
* spam checker
|
* spam checker
|
||||||
* third-party rules
|
* third-party rules
|
||||||
* presence router
|
* presence router
|
||||||
|
* password auth providers
|
||||||
|
|
|
@ -44,6 +44,15 @@ instead.
|
||||||
|
|
||||||
If the authentication is unsuccessful, the module must return `None`.
|
If the authentication is unsuccessful, the module must return `None`.
|
||||||
|
|
||||||
|
If multiple modules register an auth checker for the same login type but with different
|
||||||
|
fields, Synapse will refuse to start.
|
||||||
|
|
||||||
|
If multiple modules register an auth checker for the same login type with the same fields,
|
||||||
|
then the callbacks will be executed in order, until one returns a Matrix User ID (and
|
||||||
|
optionally a callback). In that case, the return value of that callback will be accepted
|
||||||
|
and subsequent callbacks will not be fired. If every callback returns `None`, then the
|
||||||
|
authentication fails.
|
||||||
|
|
||||||
### `check_3pid_auth`
|
### `check_3pid_auth`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -67,7 +76,13 @@ If the authentication is successful, the module must return the user's Matrix ID
|
||||||
`@alice:example.com`) and optionally a callback to be called with the response to the `/login` request.
|
`@alice:example.com`) and optionally a callback to be called with the response to the `/login` request.
|
||||||
If the module doesn't wish to return a callback, it must return None instead.
|
If the module doesn't wish to return a callback, it must return None instead.
|
||||||
|
|
||||||
If the authentication is unsuccessful, the module must return None.
|
If the authentication is unsuccessful, the module must return `None`.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `None`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `None` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback. If every callback return `None`,
|
||||||
|
the authentication is denied.
|
||||||
|
|
||||||
### `on_logged_out`
|
### `on_logged_out`
|
||||||
|
|
||||||
|
@ -82,6 +97,8 @@ Called during a logout request for a user. It is passed the qualified user ID, t
|
||||||
deactivated device (if any: access tokens are occasionally created without an associated
|
deactivated device (if any: access tokens are occasionally created without an associated
|
||||||
device ID), and the (now deactivated) access token.
|
device ID), and the (now deactivated) access token.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, Synapse runs them all in order.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
The example module below implements authentication checkers for two different login types:
|
The example module below implements authentication checkers for two different login types:
|
||||||
|
|
|
@ -24,6 +24,10 @@ must return a dictionary that maps from Matrix user IDs (which can be local or r
|
||||||
|
|
||||||
Synapse will then attempt to send the specified presence updates to each user when possible.
|
Synapse will then attempt to send the specified presence updates to each user when possible.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, Synapse merges all the dictionaries returned
|
||||||
|
by the callbacks. If multiple callbacks return a dictionary containing the same key,
|
||||||
|
Synapse concatenates the sets associated with this key from each dictionary.
|
||||||
|
|
||||||
### `get_interested_users`
|
### `get_interested_users`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -44,6 +48,12 @@ query. The returned users can be local or remote.
|
||||||
Alternatively the callback can return `synapse.module_api.PRESENCE_ALL_USERS`
|
Alternatively the callback can return `synapse.module_api.PRESENCE_ALL_USERS`
|
||||||
to indicate that the user should receive updates from all known users.
|
to indicate that the user should receive updates from all known users.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. Synapse
|
||||||
|
calls each callback one by one, and use a concatenation of all the `set`s returned by the
|
||||||
|
callbacks. If one callback returns `synapse.module_api.PRESENCE_ALL_USERS`, Synapse uses
|
||||||
|
this value instead. If this happens, Synapse does not call any of the subsequent
|
||||||
|
implementations of this callback.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
The example below is a module that implements both presence router callbacks, and ensures
|
The example below is a module that implements both presence router callbacks, and ensures
|
||||||
|
|
|
@ -19,6 +19,11 @@ either a `bool` to indicate whether the event must be rejected because of spam,
|
||||||
to indicate the event must be rejected because of spam and to give a rejection reason to
|
to indicate the event must be rejected because of spam and to give a rejection reason to
|
||||||
forward to clients.
|
forward to clients.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `False`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `False` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
### `user_may_join_room`
|
### `user_may_join_room`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -34,6 +39,11 @@ currently has a pending invite in the room.
|
||||||
This callback isn't called if the join is performed by a server administrator, or in the
|
This callback isn't called if the join is performed by a server administrator, or in the
|
||||||
context of a room creation.
|
context of a room creation.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `True`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `True` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
### `user_may_invite`
|
### `user_may_invite`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -44,6 +54,11 @@ Called when processing an invitation. The module must return a `bool` indicating
|
||||||
the inviter can invite the invitee to the given room. Both inviter and invitee are
|
the inviter can invite the invitee to the given room. Both inviter and invitee are
|
||||||
represented by their Matrix user ID (e.g. `@alice:example.com`).
|
represented by their Matrix user ID (e.g. `@alice:example.com`).
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `True`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `True` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
### `user_may_send_3pid_invite`
|
### `user_may_send_3pid_invite`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -79,6 +94,11 @@ await user_may_send_3pid_invite(
|
||||||
**Note**: If the third-party identifier is already associated with a matrix user ID,
|
**Note**: If the third-party identifier is already associated with a matrix user ID,
|
||||||
[`user_may_invite`](#user_may_invite) will be used instead.
|
[`user_may_invite`](#user_may_invite) will be used instead.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `True`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `True` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
### `user_may_create_room`
|
### `user_may_create_room`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -88,6 +108,11 @@ async def user_may_create_room(user: str) -> bool
|
||||||
Called when processing a room creation request. The module must return a `bool` indicating
|
Called when processing a room creation request. The module must return a `bool` indicating
|
||||||
whether the given user (represented by their Matrix user ID) is allowed to create a room.
|
whether the given user (represented by their Matrix user ID) is allowed to create a room.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `True`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `True` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
### `user_may_create_room_with_invites`
|
### `user_may_create_room_with_invites`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -117,6 +142,11 @@ corresponding list(s) will be empty.
|
||||||
since no invites are sent when cloning a room. To cover this case, modules also need to
|
since no invites are sent when cloning a room. To cover this case, modules also need to
|
||||||
implement `user_may_create_room`.
|
implement `user_may_create_room`.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `True`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `True` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
### `user_may_create_room_alias`
|
### `user_may_create_room_alias`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -127,6 +157,11 @@ Called when trying to associate an alias with an existing room. The module must
|
||||||
`bool` indicating whether the given user (represented by their Matrix user ID) is allowed
|
`bool` indicating whether the given user (represented by their Matrix user ID) is allowed
|
||||||
to set the given alias.
|
to set the given alias.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `True`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `True` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
### `user_may_publish_room`
|
### `user_may_publish_room`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -137,6 +172,11 @@ Called when trying to publish a room to the homeserver's public rooms directory.
|
||||||
module must return a `bool` indicating whether the given user (represented by their
|
module must return a `bool` indicating whether the given user (represented by their
|
||||||
Matrix user ID) is allowed to publish the given room.
|
Matrix user ID) is allowed to publish the given room.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `True`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `True` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
### `check_username_for_spam`
|
### `check_username_for_spam`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -154,6 +194,11 @@ is represented as a dictionary with the following keys:
|
||||||
The module is given a copy of the original dictionary, so modifying it from within the
|
The module is given a copy of the original dictionary, so modifying it from within the
|
||||||
module cannot modify a user's profile when included in user directory search results.
|
module cannot modify a user's profile when included in user directory search results.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `False`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `False` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
### `check_registration_for_spam`
|
### `check_registration_for_spam`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -179,6 +224,12 @@ The arguments passed to this callback are:
|
||||||
used during the registration process.
|
used during the registration process.
|
||||||
* `auth_provider_id`: The identifier of the SSO authentication provider, if any.
|
* `auth_provider_id`: The identifier of the SSO authentication provider, if any.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `RegistrationBehaviour.ALLOW`, Synapse falls through to the next one.
|
||||||
|
The value of the first callback that does not return `RegistrationBehaviour.ALLOW` will
|
||||||
|
be used. If this happens, Synapse will not call any of the subsequent implementations of
|
||||||
|
this callback.
|
||||||
|
|
||||||
### `check_media_file_for_spam`
|
### `check_media_file_for_spam`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -191,6 +242,11 @@ async def check_media_file_for_spam(
|
||||||
Called when storing a local or remote file. The module must return a boolean indicating
|
Called when storing a local or remote file. The module must return a boolean indicating
|
||||||
whether the given file can be stored in the homeserver's media store.
|
whether the given file can be stored in the homeserver's media store.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `False`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `False` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
The example below is a module that implements the spam checker callback
|
The example below is a module that implements the spam checker callback
|
||||||
|
|
|
@ -44,6 +44,11 @@ dictionary, and modify the returned dictionary accordingly.
|
||||||
Note that replacing the event only works for events sent by local users, not for events
|
Note that replacing the event only works for events sent by local users, not for events
|
||||||
received over federation.
|
received over federation.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `True`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `True` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
### `on_create_room`
|
### `on_create_room`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -63,6 +68,12 @@ the request is a server admin.
|
||||||
Modules can modify the `request_content` (by e.g. adding events to its `initial_state`),
|
Modules can modify the `request_content` (by e.g. adding events to its `initial_state`),
|
||||||
or deny the room's creation by raising a `module_api.errors.SynapseError`.
|
or deny the room's creation by raising a `module_api.errors.SynapseError`.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns without raising an exception, Synapse falls through to the next one. The
|
||||||
|
room creation will be forbidden as soon as one of the callbacks raises an exception. If
|
||||||
|
this happens, Synapse will not call any of the subsequent implementations of this
|
||||||
|
callback.
|
||||||
|
|
||||||
### `check_threepid_can_be_invited`
|
### `check_threepid_can_be_invited`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -76,6 +87,11 @@ async def check_threepid_can_be_invited(
|
||||||
Called when processing an invite via a third-party identifier (i.e. email or phone number).
|
Called when processing an invite via a third-party identifier (i.e. email or phone number).
|
||||||
The module must return a boolean indicating whether the invite can go through.
|
The module must return a boolean indicating whether the invite can go through.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `True`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `True` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
### `check_visibility_can_be_modified`
|
### `check_visibility_can_be_modified`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -90,6 +106,11 @@ Called when changing the visibility of a room in the local public room directory
|
||||||
visibility is a string that's either "public" or "private". The module must return a
|
visibility is a string that's either "public" or "private". The module must return a
|
||||||
boolean indicating whether the change can go through.
|
boolean indicating whether the change can go through.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `True`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `True` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
The example below is a module that implements the third-party rules callback
|
The example below is a module that implements the third-party rules callback
|
||||||
|
|
|
@ -12,6 +12,21 @@ configuration associated with the module in Synapse's configuration file.
|
||||||
See the documentation for the `ModuleApi` class
|
See the documentation for the `ModuleApi` class
|
||||||
[here](https://github.com/matrix-org/synapse/blob/master/synapse/module_api/__init__.py).
|
[here](https://github.com/matrix-org/synapse/blob/master/synapse/module_api/__init__.py).
|
||||||
|
|
||||||
|
## When Synapse runs with several modules configured
|
||||||
|
|
||||||
|
If Synapse is running with other modules configured, the order each module appears in
|
||||||
|
within the `modules` section of the Synapse configuration file might restrict what it can
|
||||||
|
or cannot register. See [this section](index.html#using-multiple-modules) for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
On top of the rules listed in the link above, if a callback returns a value that should
|
||||||
|
cause the current operation to fail (e.g. if a callback checking an event returns with a
|
||||||
|
value that should cause the event to be denied), Synapse will fail the operation and
|
||||||
|
ignore any subsequent callbacks that should have been run after this one.
|
||||||
|
|
||||||
|
The documentation for each callback mentions how Synapse behaves when
|
||||||
|
multiple modules implement it.
|
||||||
|
|
||||||
## Handling the module's configuration
|
## Handling the module's configuration
|
||||||
|
|
||||||
A module can implement the following static method:
|
A module can implement the following static method:
|
||||||
|
|
Loading…
Reference in New Issue