mirror of
https://github.com/element-hq/synapse.git
synced 2025-12-05 01:10:13 +00:00
Compare commits
8 Commits
madlittlem
...
anoa/publi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb8d9e3d75 | ||
|
|
e8d30a0d05 | ||
|
|
7441f1ba5f | ||
|
|
10066b962c | ||
|
|
b733bca197 | ||
|
|
2cbf4dd4a4 | ||
|
|
687c9cf065 | ||
|
|
786f5c1964 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -72,3 +72,8 @@ book/
|
||||
|
||||
# Don't include users' poetry configs
|
||||
/poetry.toml
|
||||
|
||||
# Devenv
|
||||
.devenv*
|
||||
devenv.local.nix
|
||||
|
||||
|
||||
177
devenv.lock
Normal file
177
devenv.lock
Normal file
@@ -0,0 +1,177 @@
|
||||
{
|
||||
"nodes": {
|
||||
"devenv": {
|
||||
"locked": {
|
||||
"dir": "src/modules",
|
||||
"lastModified": 1673960114,
|
||||
"narHash": "sha256-YNCok1a8cy71nP0idJds2Dwn2B1T6zGw9+2H1A0lNa0=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "0960585a7221e6ede718cc9a2c2eade7ce75c229",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"dir": "src/modules",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1674023045,
|
||||
"narHash": "sha256-btQC+gTeVLmX9cYl/6Kig7BuDltVWJEh7TrITAc6QjA=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "75dbe699bc57323cdef636b82bcfef6028bd1530",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1668681692,
|
||||
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1667395993,
|
||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1660459072,
|
||||
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1673947312,
|
||||
"narHash": "sha256-xx/2nRwRy3bXrtry6TtydKpJpqHahjuDB5sFkQ/XNDE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "2d38b664b4400335086a713a0036aafaa002c003",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1671271954,
|
||||
"narHash": "sha256-cSvu+bnvN08sOlTBWbBrKaBHQZq8mvk8bgpt0ZJ2Snc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d513b448cc2a6da2c8803e3c197c9fc7e67b19e3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-22.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1674046351,
|
||||
"narHash": "sha256-vNErPj4gfO/G1vHuOh5/IbjLaydwePcRlD0fXlnUbmI=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "756cc26afb75b0f8bfec48bbc54a8836a04953fb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"devenv": "devenv",
|
||||
"fenix": "fenix",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1673979364,
|
||||
"narHash": "sha256-ecgQENol9XhhcYF+M9B8FMrsWYQ/ZvRsvgEWi8HI6D0=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "3a7271336536f2cd558498755254ae8c0e73baa7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
122
devenv.nix
Normal file
122
devenv.nix
Normal file
@@ -0,0 +1,122 @@
|
||||
{ inputs, pkgs, ... }:
|
||||
|
||||
{
|
||||
# Configure packages to install.
|
||||
# Search for package names at https://search.nixos.org/packages?channel=unstable
|
||||
packages = with pkgs; [
|
||||
# Native dependencies for running Synapse.
|
||||
icu
|
||||
libffi
|
||||
libjpeg
|
||||
libpqxx
|
||||
libwebp
|
||||
libxml2
|
||||
libxslt
|
||||
sqlite
|
||||
|
||||
# Native dependencies for unit tests (SyTest also requires OpenSSL).
|
||||
openssl
|
||||
|
||||
# Native dependencies for running Complement.
|
||||
olm
|
||||
|
||||
# Development tools.
|
||||
poetry
|
||||
];
|
||||
|
||||
# Activate (and create if necessary) a poetry virtualenv on startup.
|
||||
enterShell = ''
|
||||
. "$(dirname $(poetry run which python))/activate"
|
||||
'';
|
||||
|
||||
# Install dependencies for the additional programming languages
|
||||
# involved with Synapse development. Python is already available
|
||||
# from poetry's virtual environment.
|
||||
#
|
||||
# * Rust is used for developing and running Synapse.
|
||||
# * Golang is needed to run the Complement test suite.
|
||||
# * Perl is needed to run the SyTest test suite.
|
||||
languages.go.enable = true;
|
||||
languages.rust.enable = true;
|
||||
languages.rust.version = "latest";
|
||||
languages.perl.enable = true;
|
||||
|
||||
# Postgres is needed to run Synapse with postgres support and
|
||||
# to run certain unit tests that require postgres.
|
||||
services.postgres.enable = true;
|
||||
|
||||
# On the first invocation of `devenv up`, create a database for
|
||||
# Syanpse to store data in.
|
||||
services.postgres.initdbArgs = ["--locale=C" "--encoding=UTF8"];
|
||||
services.postgres.initialDatabases = [
|
||||
{ name = "synapse"; }
|
||||
];
|
||||
|
||||
# Redis is needed in order to run Synapse in worker mode.
|
||||
services.redis.enable = true;
|
||||
|
||||
# We wrap `poetry` with a bash script that disables the download
|
||||
# of binary wheels for certain packages if the user is running
|
||||
# NixOS. NixOS is special in that you can have multiple versions
|
||||
# of packages installed at once, including your libc linker!
|
||||
#
|
||||
# Some binaries built for Linux expect those to be in a certain
|
||||
# filepath, but that is not the case on NixOS. In that case, we
|
||||
# force compiling those binaries locally instead.
|
||||
scripts.poetry.exec = ''
|
||||
if [ -z "$__NIXOS_SET_ENVIRONMENT_DONE" ]; then
|
||||
# We are running on NixOS.
|
||||
#
|
||||
# Prevent poetry from downloading known problematic,
|
||||
# dynamically-linked binaries for python dependencies.
|
||||
POETRY_INSTALLER_NO_BINARY=ruff ${pkgs.poetry}/bin/poetry $@
|
||||
else
|
||||
${pkgs.poetry}/bin/poetry $@
|
||||
fi
|
||||
'';
|
||||
|
||||
# Define the perl modules we require to run SyTest.
|
||||
#
|
||||
# This list was compiled by cross-referencing https://metacpan.org/
|
||||
# with the modules defined in './cpanfile' and then finding the
|
||||
# corresponding nix packages on https://search.nixos.org/packages.
|
||||
#
|
||||
# This was done until `./install-deps.pl --dryrun` produced no output.
|
||||
env.PERL5LIB = "${with pkgs.perl536Packages; makePerlPath [
|
||||
DBI
|
||||
ClassMethodModifiers
|
||||
CryptEd25519
|
||||
DataDump
|
||||
DBDPg
|
||||
DigestHMAC
|
||||
DigestSHA1
|
||||
EmailAddressXS
|
||||
EmailMIME
|
||||
EmailSimple # required by Email::Mime
|
||||
EmailMessageID # required by Email::Mime
|
||||
EmailMIMEContentType # required by Email::Mime
|
||||
TextUnidecode # required by Email::Mime
|
||||
ModuleRuntime # required by Email::Mime
|
||||
EmailMIMEEncodings # required by Email::Mime
|
||||
FilePath
|
||||
FileSlurper
|
||||
Future
|
||||
GetoptLong
|
||||
HTTPMessage
|
||||
IOAsync
|
||||
IOAsyncSSL
|
||||
IOSocketSSL
|
||||
NetSSLeay
|
||||
JSON
|
||||
ListUtilsBy
|
||||
ScalarListUtils
|
||||
ModulePluggable
|
||||
NetAsyncHTTP
|
||||
MetricsAny # required by Net::Async::HTTP
|
||||
NetAsyncHTTPServer
|
||||
StructDumb
|
||||
URI
|
||||
YAMLLibYAML
|
||||
]}";
|
||||
|
||||
}
|
||||
8
devenv.yaml
Normal file
8
devenv.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
inputs:
|
||||
nixpkgs:
|
||||
url: github:NixOS/nixpkgs/nixpkgs-unstable
|
||||
fenix:
|
||||
url: github:nix-community/fenix
|
||||
inputs:
|
||||
nixpkgs:
|
||||
follows: nixpkgs
|
||||
@@ -59,8 +59,6 @@ from synapse.config.homeserver import HomeServerConfig
|
||||
from synapse.config.server import ListenerConfig, ManholeConfig
|
||||
from synapse.crypto import context_factory
|
||||
from synapse.events.presence_router import load_legacy_presence_router
|
||||
from synapse.events.spamcheck import load_legacy_spam_checkers
|
||||
from synapse.events.third_party_rules import load_legacy_third_party_event_rules
|
||||
from synapse.handlers.auth import load_legacy_password_auth_providers
|
||||
from synapse.http.site import SynapseSite
|
||||
from synapse.logging.context import PreserveLoggingContext
|
||||
@@ -68,6 +66,10 @@ from synapse.logging.opentracing import init_tracer
|
||||
from synapse.metrics import install_gc_manager, register_threadpool
|
||||
from synapse.metrics.background_process_metrics import wrap_as_background_process
|
||||
from synapse.metrics.jemalloc import setup_jemalloc_stats
|
||||
from synapse.module_api.callbacks.spamchecker_callbacks import load_legacy_spam_checkers
|
||||
from synapse.module_api.callbacks.third_party_event_rules import (
|
||||
load_legacy_third_party_event_rules,
|
||||
)
|
||||
from synapse.types import ISynapseReactor
|
||||
from synapse.util import SYNAPSE_VERSION
|
||||
from synapse.util.caches.lrucache import setup_expire_lru_cache_entries
|
||||
|
||||
@@ -51,7 +51,7 @@ class FederationBase:
|
||||
|
||||
self.server_name = hs.hostname
|
||||
self.keyring = hs.get_keyring()
|
||||
self.spam_checker = hs.get_spam_checker()
|
||||
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
|
||||
self.store = hs.get_datastores().main
|
||||
self._clock = hs.get_clock()
|
||||
self._storage_controllers = hs.get_storage_controllers()
|
||||
@@ -137,9 +137,9 @@ class FederationBase:
|
||||
)
|
||||
return redacted_event
|
||||
|
||||
spam_check = await self.spam_checker.check_event_for_spam(pdu)
|
||||
spam_check = await self._spam_checker_module_callbacks.check_event_for_spam(pdu)
|
||||
|
||||
if spam_check != self.spam_checker.NOT_SPAM:
|
||||
if spam_check != self._spam_checker_module_callbacks.NOT_SPAM:
|
||||
logger.warning("Event contains spam, soft-failing %s", pdu.event_id)
|
||||
log_kv(
|
||||
{
|
||||
|
||||
@@ -130,7 +130,7 @@ class FederationServer(FederationBase):
|
||||
super().__init__(hs)
|
||||
|
||||
self.handler = hs.get_federation_handler()
|
||||
self._spam_checker = hs.get_spam_checker()
|
||||
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
|
||||
self._federation_event_handler = hs.get_federation_event_handler()
|
||||
self.state = hs.get_state_handler()
|
||||
self._event_auth_handler = hs.get_event_auth_handler()
|
||||
@@ -1129,7 +1129,7 @@ class FederationServer(FederationBase):
|
||||
logger.warning("event id %s: %s", pdu.event_id, e)
|
||||
raise FederationError("ERROR", 403, str(e), affected=pdu.event_id)
|
||||
|
||||
if await self._spam_checker.should_drop_federated_event(pdu):
|
||||
if await self._spam_checker_module_callbacks.should_drop_federated_event(pdu):
|
||||
logger.warning(
|
||||
"Unstaged federated event contains spam, dropping %s", pdu.event_id
|
||||
)
|
||||
@@ -1174,7 +1174,9 @@ class FederationServer(FederationBase):
|
||||
|
||||
origin, event = next
|
||||
|
||||
if await self._spam_checker.should_drop_federated_event(event):
|
||||
if await self._spam_checker_module_callbacks.should_drop_federated_event(
|
||||
event
|
||||
):
|
||||
logger.warning(
|
||||
"Staged federated event contains spam, dropping %s",
|
||||
event.event_id,
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
import email.mime.multipart
|
||||
import email.utils
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Awaitable, Callable, List, Optional, Tuple
|
||||
|
||||
from twisted.web.http import Request
|
||||
from typing import TYPE_CHECKING, List, Optional, Tuple
|
||||
|
||||
from synapse.api.errors import AuthError, StoreError, SynapseError
|
||||
from synapse.metrics.background_process_metrics import wrap_as_background_process
|
||||
@@ -30,25 +28,17 @@ if TYPE_CHECKING:
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Types for callbacks to be registered via the module api
|
||||
IS_USER_EXPIRED_CALLBACK = Callable[[str], Awaitable[Optional[bool]]]
|
||||
ON_USER_REGISTRATION_CALLBACK = Callable[[str], Awaitable]
|
||||
# Temporary hooks to allow for a transition from `/_matrix/client` endpoints
|
||||
# to `/_synapse/client/account_validity`. See `register_account_validity_callbacks`.
|
||||
ON_LEGACY_SEND_MAIL_CALLBACK = Callable[[str], Awaitable]
|
||||
ON_LEGACY_RENEW_CALLBACK = Callable[[str], Awaitable[Tuple[bool, bool, int]]]
|
||||
ON_LEGACY_ADMIN_REQUEST = Callable[[Request], Awaitable]
|
||||
|
||||
|
||||
class AccountValidityHandler:
|
||||
def __init__(self, hs: "HomeServer"):
|
||||
self.hs = hs
|
||||
self.config = hs.config
|
||||
self.store = self.hs.get_datastores().main
|
||||
self.send_email_handler = self.hs.get_send_email_handler()
|
||||
self.clock = self.hs.get_clock()
|
||||
self.store = hs.get_datastores().main
|
||||
self.send_email_handler = hs.get_send_email_handler()
|
||||
self.clock = hs.get_clock()
|
||||
|
||||
self._app_name = self.hs.config.email.email_app_name
|
||||
self._app_name = hs.config.email.email_app_name
|
||||
self._module_api_callbacks = hs.get_module_api_callbacks().account_validity
|
||||
|
||||
self._account_validity_enabled = (
|
||||
hs.config.account_validity.account_validity_enabled
|
||||
@@ -78,69 +68,6 @@ class AccountValidityHandler:
|
||||
if hs.config.worker.run_background_tasks:
|
||||
self.clock.looping_call(self._send_renewal_emails, 30 * 60 * 1000)
|
||||
|
||||
self._is_user_expired_callbacks: List[IS_USER_EXPIRED_CALLBACK] = []
|
||||
self._on_user_registration_callbacks: List[ON_USER_REGISTRATION_CALLBACK] = []
|
||||
self._on_legacy_send_mail_callback: Optional[
|
||||
ON_LEGACY_SEND_MAIL_CALLBACK
|
||||
] = None
|
||||
self._on_legacy_renew_callback: Optional[ON_LEGACY_RENEW_CALLBACK] = None
|
||||
|
||||
# The legacy admin requests callback isn't a protected attribute because we need
|
||||
# to access it from the admin servlet, which is outside of this handler.
|
||||
self.on_legacy_admin_request_callback: Optional[ON_LEGACY_ADMIN_REQUEST] = None
|
||||
|
||||
def register_account_validity_callbacks(
|
||||
self,
|
||||
is_user_expired: Optional[IS_USER_EXPIRED_CALLBACK] = None,
|
||||
on_user_registration: Optional[ON_USER_REGISTRATION_CALLBACK] = None,
|
||||
on_legacy_send_mail: Optional[ON_LEGACY_SEND_MAIL_CALLBACK] = None,
|
||||
on_legacy_renew: Optional[ON_LEGACY_RENEW_CALLBACK] = None,
|
||||
on_legacy_admin_request: Optional[ON_LEGACY_ADMIN_REQUEST] = None,
|
||||
) -> None:
|
||||
"""Register callbacks from module for each hook."""
|
||||
if is_user_expired is not None:
|
||||
self._is_user_expired_callbacks.append(is_user_expired)
|
||||
|
||||
if on_user_registration is not None:
|
||||
self._on_user_registration_callbacks.append(on_user_registration)
|
||||
|
||||
# The builtin account validity feature exposes 3 endpoints (send_mail, renew, and
|
||||
# an admin one). As part of moving the feature into a module, we need to change
|
||||
# the path from /_matrix/client/unstable/account_validity/... to
|
||||
# /_synapse/client/account_validity, because:
|
||||
#
|
||||
# * the feature isn't part of the Matrix spec thus shouldn't live under /_matrix
|
||||
# * the way we register servlets means that modules can't register resources
|
||||
# under /_matrix/client
|
||||
#
|
||||
# We need to allow for a transition period between the old and new endpoints
|
||||
# in order to allow for clients to update (and for emails to be processed).
|
||||
#
|
||||
# Once the email-account-validity module is loaded, it will take control of account
|
||||
# validity by moving the rows from our `account_validity` table into its own table.
|
||||
#
|
||||
# Therefore, we need to allow modules (in practice just the one implementing the
|
||||
# email-based account validity) to temporarily hook into the legacy endpoints so we
|
||||
# can route the traffic coming into the old endpoints into the module, which is
|
||||
# why we have the following three temporary hooks.
|
||||
if on_legacy_send_mail is not None:
|
||||
if self._on_legacy_send_mail_callback is not None:
|
||||
raise RuntimeError("Tried to register on_legacy_send_mail twice")
|
||||
|
||||
self._on_legacy_send_mail_callback = on_legacy_send_mail
|
||||
|
||||
if on_legacy_renew is not None:
|
||||
if self._on_legacy_renew_callback is not None:
|
||||
raise RuntimeError("Tried to register on_legacy_renew twice")
|
||||
|
||||
self._on_legacy_renew_callback = on_legacy_renew
|
||||
|
||||
if on_legacy_admin_request is not None:
|
||||
if self.on_legacy_admin_request_callback is not None:
|
||||
raise RuntimeError("Tried to register on_legacy_admin_request twice")
|
||||
|
||||
self.on_legacy_admin_request_callback = on_legacy_admin_request
|
||||
|
||||
async def is_user_expired(self, user_id: str) -> bool:
|
||||
"""Checks if a user has expired against third-party modules.
|
||||
|
||||
@@ -150,7 +77,7 @@ class AccountValidityHandler:
|
||||
Returns:
|
||||
Whether the user has expired.
|
||||
"""
|
||||
for callback in self._is_user_expired_callbacks:
|
||||
for callback in self._module_api_callbacks.is_user_expired_callbacks:
|
||||
expired = await delay_cancellation(callback(user_id))
|
||||
if expired is not None:
|
||||
return expired
|
||||
@@ -168,7 +95,7 @@ class AccountValidityHandler:
|
||||
Args:
|
||||
user_id: The ID of the newly registered user.
|
||||
"""
|
||||
for callback in self._on_user_registration_callbacks:
|
||||
for callback in self._module_api_callbacks.on_user_registration_callbacks:
|
||||
await callback(user_id)
|
||||
|
||||
@wrap_as_background_process("send_renewals")
|
||||
@@ -198,8 +125,8 @@ class AccountValidityHandler:
|
||||
"""
|
||||
# If a module supports sending a renewal email from here, do that, otherwise do
|
||||
# the legacy dance.
|
||||
if self._on_legacy_send_mail_callback is not None:
|
||||
await self._on_legacy_send_mail_callback(user_id)
|
||||
if self._module_api_callbacks.on_legacy_send_mail_callback is not None:
|
||||
await self._module_api_callbacks.on_legacy_send_mail_callback(user_id)
|
||||
return
|
||||
|
||||
if not self._account_validity_renew_by_email_enabled:
|
||||
@@ -336,8 +263,10 @@ class AccountValidityHandler:
|
||||
"""
|
||||
# If a module supports triggering a renew from here, do that, otherwise do the
|
||||
# legacy dance.
|
||||
if self._on_legacy_renew_callback is not None:
|
||||
return await self._on_legacy_renew_callback(renewal_token)
|
||||
if self._module_api_callbacks.on_legacy_renew_callback is not None:
|
||||
return await self._module_api_callbacks.on_legacy_renew_callback(
|
||||
renewal_token
|
||||
)
|
||||
|
||||
try:
|
||||
(
|
||||
|
||||
@@ -212,7 +212,7 @@ class AuthHandler:
|
||||
self._password_enabled_for_login = hs.config.auth.password_enabled_for_login
|
||||
self._password_enabled_for_reauth = hs.config.auth.password_enabled_for_reauth
|
||||
self._password_localdb_enabled = hs.config.auth.password_localdb_enabled
|
||||
self._third_party_rules = hs.get_third_party_event_rules()
|
||||
self._third_party_rules = hs.get_module_api_callbacks().third_party_event_rules
|
||||
|
||||
# Ratelimiter for failed auth during UIA. Uses same ratelimit config
|
||||
# as per `rc_login.failed_attempts`.
|
||||
|
||||
@@ -39,11 +39,11 @@ class DeactivateAccountHandler:
|
||||
self._profile_handler = hs.get_profile_handler()
|
||||
self.user_directory_handler = hs.get_user_directory_handler()
|
||||
self._server_name = hs.hostname
|
||||
self._third_party_rules = hs.get_third_party_event_rules()
|
||||
self._third_party_rules = hs.get_module_api_callbacks().third_party_event_rules
|
||||
|
||||
# Flag that indicates whether the process to part users from rooms is running
|
||||
self._user_parter_running = False
|
||||
self._third_party_rules = hs.get_third_party_event_rules()
|
||||
self._third_party_rules = hs.get_module_api_callbacks().third_party_event_rules
|
||||
|
||||
# Start the user parter loop so it can resume parting users from rooms where
|
||||
# it left off (if it has work left to do).
|
||||
|
||||
@@ -52,7 +52,9 @@ class DirectoryHandler:
|
||||
self.config = hs.config
|
||||
self.enable_room_list_search = hs.config.roomdirectory.enable_room_list_search
|
||||
self.require_membership = hs.config.server.require_membership_for_aliases
|
||||
self.third_party_event_rules = hs.get_third_party_event_rules()
|
||||
self._third_party_event_rules = (
|
||||
hs.get_module_api_callbacks().third_party_event_rules
|
||||
)
|
||||
self.server_name = hs.hostname
|
||||
|
||||
self.federation = hs.get_federation_client()
|
||||
@@ -60,7 +62,7 @@ class DirectoryHandler:
|
||||
"directory", self.on_directory_query
|
||||
)
|
||||
|
||||
self.spam_checker = hs.get_spam_checker()
|
||||
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
|
||||
|
||||
async def _create_association(
|
||||
self,
|
||||
@@ -145,10 +147,12 @@ class DirectoryHandler:
|
||||
403, "You must be in the room to create an alias for it"
|
||||
)
|
||||
|
||||
spam_check = await self.spam_checker.user_may_create_room_alias(
|
||||
user_id, room_alias
|
||||
spam_check = (
|
||||
await self._spam_checker_module_callbacks.user_may_create_room_alias(
|
||||
user_id, room_alias
|
||||
)
|
||||
)
|
||||
if spam_check != self.spam_checker.NOT_SPAM:
|
||||
if spam_check != self._spam_checker_module_callbacks.NOT_SPAM:
|
||||
raise AuthError(
|
||||
403,
|
||||
"This user is not permitted to create this alias",
|
||||
@@ -444,7 +448,9 @@ class DirectoryHandler:
|
||||
"""
|
||||
user_id = requester.user.to_string()
|
||||
|
||||
spam_check = await self.spam_checker.user_may_publish_room(user_id, room_id)
|
||||
spam_check = await self._spam_checker_module_callbacks.user_may_publish_room(
|
||||
user_id, room_id
|
||||
)
|
||||
if spam_check != NOT_SPAM:
|
||||
raise AuthError(
|
||||
403,
|
||||
@@ -499,7 +505,7 @@ class DirectoryHandler:
|
||||
# Check if publishing is blocked by a third party module
|
||||
allowed_by_third_party_rules = (
|
||||
await (
|
||||
self.third_party_event_rules.check_visibility_can_be_modified(
|
||||
self._third_party_event_rules.check_visibility_can_be_modified(
|
||||
room_id, visibility
|
||||
)
|
||||
)
|
||||
|
||||
@@ -141,7 +141,7 @@ class FederationHandler:
|
||||
self.server_name = hs.hostname
|
||||
self.keyring = hs.get_keyring()
|
||||
self.is_mine_id = hs.is_mine_id
|
||||
self.spam_checker = hs.get_spam_checker()
|
||||
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
|
||||
self.event_creation_handler = hs.get_event_creation_handler()
|
||||
self.event_builder_factory = hs.get_event_builder_factory()
|
||||
self._event_auth_handler = hs.get_event_auth_handler()
|
||||
@@ -169,7 +169,9 @@ class FederationHandler:
|
||||
|
||||
self._room_backfill = Linearizer("room_backfill")
|
||||
|
||||
self.third_party_event_rules = hs.get_third_party_event_rules()
|
||||
self._third_party_event_rules = (
|
||||
hs.get_module_api_callbacks().third_party_event_rules
|
||||
)
|
||||
|
||||
# Tracks running partial state syncs by room ID.
|
||||
# Partial state syncs currently only run on the main process, so it's okay to
|
||||
@@ -1041,7 +1043,7 @@ class FederationHandler:
|
||||
if self.hs.config.server.block_non_admin_invites:
|
||||
raise SynapseError(403, "This server does not accept room invites")
|
||||
|
||||
spam_check = await self.spam_checker.user_may_invite(
|
||||
spam_check = await self._spam_checker_module_callbacks.user_may_invite(
|
||||
event.sender, event.state_key, event.room_id
|
||||
)
|
||||
if spam_check != NOT_SPAM:
|
||||
@@ -1252,7 +1254,7 @@ class FederationHandler:
|
||||
unpersisted_context,
|
||||
) = await self.event_creation_handler.create_new_client_event(builder=builder)
|
||||
|
||||
event_allowed, _ = await self.third_party_event_rules.check_event_allowed(
|
||||
event_allowed, _ = await self._third_party_event_rules.check_event_allowed(
|
||||
event, unpersisted_context
|
||||
)
|
||||
if not event_allowed:
|
||||
|
||||
@@ -154,7 +154,9 @@ class FederationEventHandler:
|
||||
self._get_room_member_handler = hs.get_room_member_handler
|
||||
|
||||
self._federation_client = hs.get_federation_client()
|
||||
self._third_party_event_rules = hs.get_third_party_event_rules()
|
||||
self._third_party_event_rules = (
|
||||
hs.get_module_api_callbacks().third_party_event_rules
|
||||
)
|
||||
self._notifier = hs.get_notifier()
|
||||
|
||||
self._is_mine_id = hs.is_mine_id
|
||||
|
||||
@@ -77,7 +77,6 @@ from synapse.util.metrics import measure_func
|
||||
from synapse.visibility import get_effective_room_visibility_from_state
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from synapse.events.third_party_rules import ThirdPartyEventRules
|
||||
from synapse.server import HomeServer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -505,9 +504,9 @@ class EventCreationHandler:
|
||||
|
||||
self._bulk_push_rule_evaluator = hs.get_bulk_push_rule_evaluator()
|
||||
|
||||
self.spam_checker = hs.get_spam_checker()
|
||||
self.third_party_event_rules: "ThirdPartyEventRules" = (
|
||||
self.hs.get_third_party_event_rules()
|
||||
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
|
||||
self._third_party_event_rules = (
|
||||
self.hs.get_module_api_callbacks().third_party_event_rules
|
||||
)
|
||||
|
||||
self._block_events_without_consent_error = (
|
||||
@@ -1021,8 +1020,12 @@ class EventCreationHandler:
|
||||
event.sender,
|
||||
)
|
||||
|
||||
spam_check_result = await self.spam_checker.check_event_for_spam(event)
|
||||
if spam_check_result != self.spam_checker.NOT_SPAM:
|
||||
spam_check_result = (
|
||||
await self._spam_checker_module_callbacks.check_event_for_spam(
|
||||
event
|
||||
)
|
||||
)
|
||||
if spam_check_result != self._spam_checker_module_callbacks.NOT_SPAM:
|
||||
if isinstance(spam_check_result, tuple):
|
||||
try:
|
||||
[code, dict] = spam_check_result
|
||||
@@ -1269,7 +1272,7 @@ class EventCreationHandler:
|
||||
if requester:
|
||||
context.app_service = requester.app_service
|
||||
|
||||
res, new_content = await self.third_party_event_rules.check_event_allowed(
|
||||
res, new_content = await self._third_party_event_rules.check_event_allowed(
|
||||
event, context
|
||||
)
|
||||
if res is False:
|
||||
|
||||
@@ -61,7 +61,7 @@ class ProfileHandler:
|
||||
|
||||
self.server_name = hs.config.server.server_name
|
||||
|
||||
self._third_party_rules = hs.get_third_party_event_rules()
|
||||
self._third_party_rules = hs.get_module_api_callbacks().third_party_event_rules
|
||||
|
||||
async def get_profile(self, user_id: str) -> JsonDict:
|
||||
target_user = UserID.from_string(user_id)
|
||||
|
||||
@@ -110,7 +110,7 @@ class RegistrationHandler:
|
||||
self._server_notices_mxid = hs.config.servernotices.server_notices_mxid
|
||||
self._server_name = hs.hostname
|
||||
|
||||
self.spam_checker = hs.get_spam_checker()
|
||||
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
|
||||
|
||||
if hs.config.worker.worker_app:
|
||||
self._register_client = ReplicationRegisterServlet.make_client(hs)
|
||||
@@ -259,7 +259,7 @@ class RegistrationHandler:
|
||||
|
||||
await self.check_registration_ratelimit(address)
|
||||
|
||||
result = await self.spam_checker.check_registration_for_spam(
|
||||
result = await self._spam_checker_module_callbacks.check_registration_for_spam(
|
||||
threepid,
|
||||
localpart,
|
||||
user_agent_ips or [],
|
||||
|
||||
@@ -105,7 +105,7 @@ class RoomCreationHandler:
|
||||
self.auth_blocking = hs.get_auth_blocking()
|
||||
self.clock = hs.get_clock()
|
||||
self.hs = hs
|
||||
self.spam_checker = hs.get_spam_checker()
|
||||
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
|
||||
self.event_creation_handler = hs.get_event_creation_handler()
|
||||
self.room_member_handler = hs.get_room_member_handler()
|
||||
self._event_auth_handler = hs.get_event_auth_handler()
|
||||
@@ -159,7 +159,9 @@ class RoomCreationHandler:
|
||||
)
|
||||
self._server_notices_mxid = hs.config.servernotices.server_notices_mxid
|
||||
|
||||
self.third_party_event_rules = hs.get_third_party_event_rules()
|
||||
self._third_party_event_rules = (
|
||||
hs.get_module_api_callbacks().third_party_event_rules
|
||||
)
|
||||
|
||||
async def upgrade_room(
|
||||
self, requester: Requester, old_room_id: str, new_version: RoomVersion
|
||||
@@ -445,7 +447,9 @@ class RoomCreationHandler:
|
||||
"""
|
||||
user_id = requester.user.to_string()
|
||||
|
||||
spam_check = await self.spam_checker.user_may_create_room(user_id)
|
||||
spam_check = await self._spam_checker_module_callbacks.user_may_create_room(
|
||||
user_id
|
||||
)
|
||||
if spam_check != NOT_SPAM:
|
||||
raise SynapseError(
|
||||
403,
|
||||
@@ -735,7 +739,7 @@ class RoomCreationHandler:
|
||||
|
||||
# Let the third party rules modify the room creation config if needed, or abort
|
||||
# the room creation entirely with an exception.
|
||||
await self.third_party_event_rules.on_create_room(
|
||||
await self._third_party_event_rules.on_create_room(
|
||||
requester, config, is_requester_admin=is_requester_admin
|
||||
)
|
||||
|
||||
@@ -756,7 +760,9 @@ class RoomCreationHandler:
|
||||
)
|
||||
|
||||
if not is_requester_admin:
|
||||
spam_check = await self.spam_checker.user_may_create_room(user_id)
|
||||
spam_check = await self._spam_checker_module_callbacks.user_may_create_room(
|
||||
user_id
|
||||
)
|
||||
if spam_check != NOT_SPAM:
|
||||
raise SynapseError(
|
||||
403,
|
||||
@@ -870,7 +876,7 @@ class RoomCreationHandler:
|
||||
# Check whether this visibility value is blocked by a third party module
|
||||
allowed_by_third_party_rules = (
|
||||
await (
|
||||
self.third_party_event_rules.check_visibility_can_be_modified(
|
||||
self._third_party_event_rules.check_visibility_can_be_modified(
|
||||
room_id, visibility
|
||||
)
|
||||
)
|
||||
@@ -1720,7 +1726,7 @@ class RoomShutdownHandler:
|
||||
self.room_member_handler = hs.get_room_member_handler()
|
||||
self._room_creation_handler = hs.get_room_creation_handler()
|
||||
self._replication = hs.get_replication_data_handler()
|
||||
self._third_party_rules = hs.get_third_party_event_rules()
|
||||
self._third_party_rules = hs.get_module_api_callbacks().third_party_event_rules
|
||||
self.event_creation_handler = hs.get_event_creation_handler()
|
||||
self.store = hs.get_datastores().main
|
||||
|
||||
|
||||
@@ -96,8 +96,10 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
|
||||
self.member_as_limiter = Linearizer(max_count=10, name="member_as_limiter")
|
||||
|
||||
self.clock = hs.get_clock()
|
||||
self.spam_checker = hs.get_spam_checker()
|
||||
self.third_party_event_rules = hs.get_third_party_event_rules()
|
||||
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
|
||||
self._third_party_event_rules = (
|
||||
hs.get_module_api_callbacks().third_party_event_rules
|
||||
)
|
||||
self._server_notices_mxid = self.config.servernotices.server_notices_mxid
|
||||
self._enable_lookup = hs.config.registration.enable_3pid_lookup
|
||||
self.allow_per_room_profiles = self.config.server.allow_per_room_profiles
|
||||
@@ -802,7 +804,7 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
|
||||
)
|
||||
block_invite_result = (Codes.FORBIDDEN, {})
|
||||
|
||||
spam_check = await self.spam_checker.user_may_invite(
|
||||
spam_check = await self._spam_checker_module_callbacks.user_may_invite(
|
||||
requester.user.to_string(), target_id, room_id
|
||||
)
|
||||
if spam_check != NOT_SPAM:
|
||||
@@ -931,8 +933,10 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
|
||||
# a room then they're allowed to join it.
|
||||
and not new_room
|
||||
):
|
||||
spam_check = await self.spam_checker.user_may_join_room(
|
||||
target.to_string(), room_id, is_invited=inviter is not None
|
||||
spam_check = (
|
||||
await self._spam_checker_module_callbacks.user_may_join_room(
|
||||
target.to_string(), room_id, is_invited=inviter is not None
|
||||
)
|
||||
)
|
||||
if spam_check != NOT_SPAM:
|
||||
raise SynapseError(
|
||||
@@ -1511,7 +1515,7 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
|
||||
# can't just rely on the standard ratelimiting of events.
|
||||
await self._third_party_invite_limiter.ratelimit(requester)
|
||||
|
||||
can_invite = await self.third_party_event_rules.check_threepid_can_be_invited(
|
||||
can_invite = await self._third_party_event_rules.check_threepid_can_be_invited(
|
||||
medium, address, room_id
|
||||
)
|
||||
if not can_invite:
|
||||
@@ -1541,11 +1545,13 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
|
||||
)
|
||||
else:
|
||||
# Check if the spamchecker(s) allow this invite to go through.
|
||||
spam_check = await self.spam_checker.user_may_send_3pid_invite(
|
||||
inviter_userid=requester.user.to_string(),
|
||||
medium=medium,
|
||||
address=address,
|
||||
room_id=room_id,
|
||||
spam_check = (
|
||||
await self._spam_checker_module_callbacks.user_may_send_3pid_invite(
|
||||
inviter_userid=requester.user.to_string(),
|
||||
medium=medium,
|
||||
address=address,
|
||||
room_id=room_id,
|
||||
)
|
||||
)
|
||||
if spam_check != NOT_SPAM:
|
||||
raise SynapseError(
|
||||
|
||||
@@ -63,7 +63,7 @@ class UserDirectoryHandler(StateDeltasHandler):
|
||||
self.is_mine_id = hs.is_mine_id
|
||||
self.update_user_directory = hs.config.worker.should_update_user_directory
|
||||
self.search_all_users = hs.config.userdirectory.user_directory_search_all_users
|
||||
self.spam_checker = hs.get_spam_checker()
|
||||
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
|
||||
# The current position in the current_state_delta stream
|
||||
self.pos: Optional[int] = None
|
||||
|
||||
@@ -101,7 +101,9 @@ class UserDirectoryHandler(StateDeltasHandler):
|
||||
# Remove any spammy users from the results.
|
||||
non_spammy_users = []
|
||||
for user in results["results"]:
|
||||
if not await self.spam_checker.check_username_for_spam(user):
|
||||
if not await self._spam_checker_module_callbacks.check_username_for_spam(
|
||||
user
|
||||
):
|
||||
non_spammy_users.append(user)
|
||||
results["results"] = non_spammy_users
|
||||
|
||||
|
||||
@@ -44,40 +44,7 @@ from synapse.events.presence_router import (
|
||||
GET_USERS_FOR_STATES_CALLBACK,
|
||||
PresenceRouter,
|
||||
)
|
||||
from synapse.events.spamcheck import (
|
||||
CHECK_EVENT_FOR_SPAM_CALLBACK,
|
||||
CHECK_MEDIA_FILE_FOR_SPAM_CALLBACK,
|
||||
CHECK_REGISTRATION_FOR_SPAM_CALLBACK,
|
||||
CHECK_USERNAME_FOR_SPAM_CALLBACK,
|
||||
SHOULD_DROP_FEDERATED_EVENT_CALLBACK,
|
||||
USER_MAY_CREATE_ROOM_ALIAS_CALLBACK,
|
||||
USER_MAY_CREATE_ROOM_CALLBACK,
|
||||
USER_MAY_INVITE_CALLBACK,
|
||||
USER_MAY_JOIN_ROOM_CALLBACK,
|
||||
USER_MAY_PUBLISH_ROOM_CALLBACK,
|
||||
USER_MAY_SEND_3PID_INVITE_CALLBACK,
|
||||
SpamChecker,
|
||||
)
|
||||
from synapse.events.third_party_rules import (
|
||||
CHECK_CAN_DEACTIVATE_USER_CALLBACK,
|
||||
CHECK_CAN_SHUTDOWN_ROOM_CALLBACK,
|
||||
CHECK_EVENT_ALLOWED_CALLBACK,
|
||||
CHECK_THREEPID_CAN_BE_INVITED_CALLBACK,
|
||||
CHECK_VISIBILITY_CAN_BE_MODIFIED_CALLBACK,
|
||||
ON_CREATE_ROOM_CALLBACK,
|
||||
ON_NEW_EVENT_CALLBACK,
|
||||
ON_PROFILE_UPDATE_CALLBACK,
|
||||
ON_THREEPID_BIND_CALLBACK,
|
||||
ON_USER_DEACTIVATION_STATUS_CHANGED_CALLBACK,
|
||||
)
|
||||
from synapse.handlers.account_data import ON_ACCOUNT_DATA_UPDATED_CALLBACK
|
||||
from synapse.handlers.account_validity import (
|
||||
IS_USER_EXPIRED_CALLBACK,
|
||||
ON_LEGACY_ADMIN_REQUEST,
|
||||
ON_LEGACY_RENEW_CALLBACK,
|
||||
ON_LEGACY_SEND_MAIL_CALLBACK,
|
||||
ON_USER_REGISTRATION_CALLBACK,
|
||||
)
|
||||
from synapse.handlers.auth import (
|
||||
CHECK_3PID_AUTH_CALLBACK,
|
||||
CHECK_AUTH_CALLBACK,
|
||||
@@ -103,6 +70,39 @@ from synapse.logging.context import (
|
||||
run_in_background,
|
||||
)
|
||||
from synapse.metrics.background_process_metrics import run_as_background_process
|
||||
from synapse.module_api.callbacks.account_validity_callbacks import (
|
||||
IS_USER_EXPIRED_CALLBACK,
|
||||
ON_LEGACY_ADMIN_REQUEST,
|
||||
ON_LEGACY_RENEW_CALLBACK,
|
||||
ON_LEGACY_SEND_MAIL_CALLBACK,
|
||||
ON_USER_REGISTRATION_CALLBACK,
|
||||
)
|
||||
from synapse.module_api.callbacks.spamchecker_callbacks import (
|
||||
CHECK_EVENT_FOR_SPAM_CALLBACK,
|
||||
CHECK_MEDIA_FILE_FOR_SPAM_CALLBACK,
|
||||
CHECK_REGISTRATION_FOR_SPAM_CALLBACK,
|
||||
CHECK_USERNAME_FOR_SPAM_CALLBACK,
|
||||
SHOULD_DROP_FEDERATED_EVENT_CALLBACK,
|
||||
USER_MAY_CREATE_ROOM_ALIAS_CALLBACK,
|
||||
USER_MAY_CREATE_ROOM_CALLBACK,
|
||||
USER_MAY_INVITE_CALLBACK,
|
||||
USER_MAY_JOIN_ROOM_CALLBACK,
|
||||
USER_MAY_PUBLISH_ROOM_CALLBACK,
|
||||
USER_MAY_SEND_3PID_INVITE_CALLBACK,
|
||||
SpamCheckerModuleApiCallbacks,
|
||||
)
|
||||
from synapse.module_api.callbacks.third_party_event_rules import (
|
||||
CHECK_CAN_DEACTIVATE_USER_CALLBACK,
|
||||
CHECK_CAN_SHUTDOWN_ROOM_CALLBACK,
|
||||
CHECK_EVENT_ALLOWED_CALLBACK,
|
||||
CHECK_THREEPID_CAN_BE_INVITED_CALLBACK,
|
||||
CHECK_VISIBILITY_CAN_BE_MODIFIED_CALLBACK,
|
||||
ON_CREATE_ROOM_CALLBACK,
|
||||
ON_NEW_EVENT_CALLBACK,
|
||||
ON_PROFILE_UPDATE_CALLBACK,
|
||||
ON_THREEPID_BIND_CALLBACK,
|
||||
ON_USER_DEACTIVATION_STATUS_CHANGED_CALLBACK,
|
||||
)
|
||||
from synapse.rest.client.login import LoginResponse
|
||||
from synapse.storage import DataStore
|
||||
from synapse.storage.background_updates import (
|
||||
@@ -145,7 +145,7 @@ are loaded into Synapse.
|
||||
"""
|
||||
|
||||
PRESENCE_ALL_USERS = PresenceRouter.ALL_USERS
|
||||
NOT_SPAM = SpamChecker.NOT_SPAM
|
||||
NOT_SPAM = SpamCheckerModuleApiCallbacks.NOT_SPAM
|
||||
|
||||
__all__ = [
|
||||
"errors",
|
||||
@@ -248,6 +248,7 @@ class ModuleApi:
|
||||
self._push_rules_handler = hs.get_push_rules_handler()
|
||||
self._device_handler = hs.get_device_handler()
|
||||
self.custom_template_dir = hs.config.server.custom_template_directory
|
||||
self._callbacks = hs.get_module_api_callbacks()
|
||||
|
||||
try:
|
||||
app_name = self._hs.config.email.email_app_name
|
||||
@@ -268,9 +269,6 @@ class ModuleApi:
|
||||
self._public_room_list_manager = PublicRoomListManager(hs)
|
||||
self._account_data_manager = AccountDataManager(hs)
|
||||
|
||||
self._spam_checker = hs.get_spam_checker()
|
||||
self._account_validity_handler = hs.get_account_validity_handler()
|
||||
self._third_party_event_rules = hs.get_third_party_event_rules()
|
||||
self._password_auth_provider = hs.get_password_auth_provider()
|
||||
self._presence_router = hs.get_presence_router()
|
||||
self._account_data_handler = hs.get_account_data_handler()
|
||||
@@ -303,7 +301,7 @@ class ModuleApi:
|
||||
|
||||
Added in Synapse v1.37.0.
|
||||
"""
|
||||
return self._spam_checker.register_callbacks(
|
||||
return self._callbacks.spam_checker.register_callbacks(
|
||||
check_event_for_spam=check_event_for_spam,
|
||||
should_drop_federated_event=should_drop_federated_event,
|
||||
user_may_join_room=user_may_join_room,
|
||||
@@ -330,7 +328,7 @@ class ModuleApi:
|
||||
|
||||
Added in Synapse v1.39.0.
|
||||
"""
|
||||
return self._account_validity_handler.register_account_validity_callbacks(
|
||||
return self._callbacks.account_validity.register_callbacks(
|
||||
is_user_expired=is_user_expired,
|
||||
on_user_registration=on_user_registration,
|
||||
on_legacy_send_mail=on_legacy_send_mail,
|
||||
@@ -362,7 +360,7 @@ class ModuleApi:
|
||||
|
||||
Added in Synapse v1.39.0.
|
||||
"""
|
||||
return self._third_party_event_rules.register_third_party_rules_callbacks(
|
||||
return self._callbacks.third_party_event_rules.register_third_party_rules_callbacks(
|
||||
check_event_allowed=check_event_allowed,
|
||||
on_create_room=on_create_room,
|
||||
check_threepid_can_be_invited=check_threepid_can_be_invited,
|
||||
|
||||
34
synapse/module_api/callbacks/__init__.py
Normal file
34
synapse/module_api/callbacks/__init__.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from synapse.server import HomeServer
|
||||
|
||||
from .account_validity_callbacks import AccountValidityModuleApiCallbacks
|
||||
from .spamchecker_callbacks import SpamCheckerModuleApiCallbacks
|
||||
from .third_party_event_rules import ThirdPartyEventRulesModuleApiCallbacks
|
||||
|
||||
__all__ = [
|
||||
"AccountValidityModuleApiCallbacks",
|
||||
"ModuleApiCallbacks",
|
||||
]
|
||||
|
||||
|
||||
class ModuleApiCallbacks:
|
||||
def __init__(self, hs: "HomeServer") -> None:
|
||||
self.account_validity = AccountValidityModuleApiCallbacks()
|
||||
self.spam_checker = SpamCheckerModuleApiCallbacks(hs)
|
||||
self.third_party_event_rules = ThirdPartyEventRulesModuleApiCallbacks(hs)
|
||||
93
synapse/module_api/callbacks/account_validity_callbacks.py
Normal file
93
synapse/module_api/callbacks/account_validity_callbacks.py
Normal file
@@ -0,0 +1,93 @@
|
||||
# Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
from typing import Awaitable, Callable, List, Optional, Tuple
|
||||
|
||||
from twisted.web.http import Request
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Types for callbacks to be registered via the module api
|
||||
IS_USER_EXPIRED_CALLBACK = Callable[[str], Awaitable[Optional[bool]]]
|
||||
ON_USER_REGISTRATION_CALLBACK = Callable[[str], Awaitable]
|
||||
# Temporary hooks to allow for a transition from `/_matrix/client` endpoints
|
||||
# to `/_synapse/client/account_validity`. See `register_account_validity_callbacks`.
|
||||
ON_LEGACY_SEND_MAIL_CALLBACK = Callable[[str], Awaitable]
|
||||
ON_LEGACY_RENEW_CALLBACK = Callable[[str], Awaitable[Tuple[bool, bool, int]]]
|
||||
ON_LEGACY_ADMIN_REQUEST = Callable[[Request], Awaitable]
|
||||
|
||||
|
||||
class AccountValidityModuleApiCallbacks:
|
||||
def __init__(self) -> None:
|
||||
self.is_user_expired_callbacks: List[IS_USER_EXPIRED_CALLBACK] = []
|
||||
self.on_user_registration_callbacks: List[ON_USER_REGISTRATION_CALLBACK] = []
|
||||
self.on_legacy_send_mail_callback: Optional[ON_LEGACY_SEND_MAIL_CALLBACK] = None
|
||||
self.on_legacy_renew_callback: Optional[ON_LEGACY_RENEW_CALLBACK] = None
|
||||
|
||||
# The legacy admin requests callback isn't a protected attribute because we need
|
||||
# to access it from the admin servlet, which is outside of this handler.
|
||||
self.on_legacy_admin_request_callback: Optional[ON_LEGACY_ADMIN_REQUEST] = None
|
||||
|
||||
def register_callbacks(
|
||||
self,
|
||||
is_user_expired: Optional[IS_USER_EXPIRED_CALLBACK] = None,
|
||||
on_user_registration: Optional[ON_USER_REGISTRATION_CALLBACK] = None,
|
||||
on_legacy_send_mail: Optional[ON_LEGACY_SEND_MAIL_CALLBACK] = None,
|
||||
on_legacy_renew: Optional[ON_LEGACY_RENEW_CALLBACK] = None,
|
||||
on_legacy_admin_request: Optional[ON_LEGACY_ADMIN_REQUEST] = None,
|
||||
) -> None:
|
||||
"""Register callbacks from module for each hook."""
|
||||
if is_user_expired is not None:
|
||||
self.is_user_expired_callbacks.append(is_user_expired)
|
||||
|
||||
if on_user_registration is not None:
|
||||
self.on_user_registration_callbacks.append(on_user_registration)
|
||||
|
||||
# The builtin account validity feature exposes 3 endpoints (send_mail, renew, and
|
||||
# an admin one). As part of moving the feature into a module, we need to change
|
||||
# the path from /_matrix/client/unstable/account_validity/... to
|
||||
# /_synapse/client/account_validity, because:
|
||||
#
|
||||
# * the feature isn't part of the Matrix spec thus shouldn't live under /_matrix
|
||||
# * the way we register servlets means that modules can't register resources
|
||||
# under /_matrix/client
|
||||
#
|
||||
# We need to allow for a transition period between the old and new endpoints
|
||||
# in order to allow for clients to update (and for emails to be processed).
|
||||
#
|
||||
# Once the email-account-validity module is loaded, it will take control of account
|
||||
# validity by moving the rows from our `account_validity` table into its own table.
|
||||
#
|
||||
# Therefore, we need to allow modules (in practice just the one implementing the
|
||||
# email-based account validity) to temporarily hook into the legacy endpoints so we
|
||||
# can route the traffic coming into the old endpoints into the module, which is
|
||||
# why we have the following three temporary hooks.
|
||||
if on_legacy_send_mail is not None:
|
||||
if self.on_legacy_send_mail_callback is not None:
|
||||
raise RuntimeError("Tried to register on_legacy_send_mail twice")
|
||||
|
||||
self.on_legacy_send_mail_callback = on_legacy_send_mail
|
||||
|
||||
if on_legacy_renew is not None:
|
||||
if self.on_legacy_renew_callback is not None:
|
||||
raise RuntimeError("Tried to register on_legacy_renew twice")
|
||||
|
||||
self.on_legacy_renew_callback = on_legacy_renew
|
||||
|
||||
if on_legacy_admin_request is not None:
|
||||
if self.on_legacy_admin_request_callback is not None:
|
||||
raise RuntimeError("Tried to register on_legacy_admin_request twice")
|
||||
|
||||
self.on_legacy_admin_request_callback = on_legacy_admin_request
|
||||
@@ -286,11 +286,10 @@ def load_legacy_spam_checkers(hs: "synapse.server.HomeServer") -> None:
|
||||
api.register_spam_checker_callbacks(**hooks)
|
||||
|
||||
|
||||
class SpamChecker:
|
||||
class SpamCheckerModuleApiCallbacks:
|
||||
NOT_SPAM: Literal["NOT_SPAM"] = "NOT_SPAM"
|
||||
|
||||
def __init__(self, hs: "synapse.server.HomeServer") -> None:
|
||||
self.hs = hs
|
||||
self.clock = hs.get_clock()
|
||||
|
||||
self._check_event_for_spam_callbacks: List[CHECK_EVENT_FOR_SPAM_CALLBACK] = []
|
||||
@@ -138,7 +138,7 @@ def load_legacy_third_party_event_rules(hs: "HomeServer") -> None:
|
||||
api.register_third_party_rules_callbacks(**hooks)
|
||||
|
||||
|
||||
class ThirdPartyEventRules:
|
||||
class ThirdPartyEventRulesModuleApiCallbacks:
|
||||
"""Allows server admins to provide a Python module implementing an extra
|
||||
set of rules to apply when processing events.
|
||||
|
||||
@@ -147,8 +147,6 @@ class ThirdPartyEventRules:
|
||||
"""
|
||||
|
||||
def __init__(self, hs: "HomeServer"):
|
||||
self.third_party_rules = None
|
||||
|
||||
self.store = hs.get_datastores().main
|
||||
self._storage_controllers = hs.get_storage_controllers()
|
||||
|
||||
@@ -232,7 +232,7 @@ class Notifier:
|
||||
|
||||
self._federation_client = hs.get_federation_http_client()
|
||||
|
||||
self._third_party_rules = hs.get_third_party_event_rules()
|
||||
self._third_party_rules = hs.get_module_api_callbacks().third_party_event_rules
|
||||
|
||||
self.clock = hs.get_clock()
|
||||
self.appservice_handler = hs.get_application_service_handler()
|
||||
|
||||
@@ -70,7 +70,7 @@ class RoomRestV2Servlet(RestServlet):
|
||||
self._auth = hs.get_auth()
|
||||
self._store = hs.get_datastores().main
|
||||
self._pagination_handler = hs.get_pagination_handler()
|
||||
self._third_party_rules = hs.get_third_party_event_rules()
|
||||
self._third_party_rules = hs.get_module_api_callbacks().third_party_event_rules
|
||||
|
||||
async def on_DELETE(
|
||||
self, request: SynapseRequest, room_id: str
|
||||
|
||||
@@ -676,19 +676,18 @@ class AccountValidityRenewServlet(RestServlet):
|
||||
PATTERNS = admin_patterns("/account_validity/validity$")
|
||||
|
||||
def __init__(self, hs: "HomeServer"):
|
||||
self.account_activity_handler = hs.get_account_validity_handler()
|
||||
self.account_validity_handler = hs.get_account_validity_handler()
|
||||
self.account_validity_module_callbacks = (
|
||||
hs.get_module_api_callbacks().account_validity
|
||||
)
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
|
||||
await assert_requester_is_admin(self.auth, request)
|
||||
|
||||
if self.account_activity_handler.on_legacy_admin_request_callback:
|
||||
expiration_ts = (
|
||||
await (
|
||||
self.account_activity_handler.on_legacy_admin_request_callback(
|
||||
request
|
||||
)
|
||||
)
|
||||
if self.account_validity_module_callbacks.on_legacy_admin_request_callback:
|
||||
expiration_ts = await self.account_validity_module_callbacks.on_legacy_admin_request_callback(
|
||||
request
|
||||
)
|
||||
else:
|
||||
body = parse_json_object_from_request(request)
|
||||
@@ -699,7 +698,7 @@ class AccountValidityRenewServlet(RestServlet):
|
||||
"Missing property 'user_id' in the request body",
|
||||
)
|
||||
|
||||
expiration_ts = await self.account_activity_handler.renew_account_for_user(
|
||||
expiration_ts = await self.account_validity_handler.renew_account_for_user(
|
||||
body["user_id"],
|
||||
body.get("expiration_ts"),
|
||||
not body.get("enable_renewal_emails", True),
|
||||
|
||||
@@ -36,7 +36,6 @@ from twisted.internet.defer import Deferred
|
||||
from twisted.internet.interfaces import IConsumer
|
||||
from twisted.protocols.basic import FileSender
|
||||
|
||||
import synapse
|
||||
from synapse.api.errors import NotFoundError
|
||||
from synapse.logging.context import defer_to_thread, make_deferred_yieldable
|
||||
from synapse.util import Clock
|
||||
@@ -74,7 +73,7 @@ class MediaStorage:
|
||||
self.local_media_directory = local_media_directory
|
||||
self.filepaths = filepaths
|
||||
self.storage_providers = storage_providers
|
||||
self.spam_checker = hs.get_spam_checker()
|
||||
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
|
||||
self.clock = hs.get_clock()
|
||||
|
||||
async def store_file(self, source: IO, file_info: FileInfo) -> str:
|
||||
@@ -145,10 +144,10 @@ class MediaStorage:
|
||||
f.flush()
|
||||
f.close()
|
||||
|
||||
spam_check = await self.spam_checker.check_media_file_for_spam(
|
||||
spam_check = await self._spam_checker_module_callbacks.check_media_file_for_spam(
|
||||
ReadableFileWrapper(self.clock, fname), file_info
|
||||
)
|
||||
if spam_check != synapse.module_api.NOT_SPAM:
|
||||
if spam_check != self._spam_checker_module_callbacks.NOT_SPAM:
|
||||
logger.info("Blocking media due to spam checker")
|
||||
# Note that we'll delete the stored media, due to the
|
||||
# try/except below. The media also won't be stored in
|
||||
|
||||
@@ -40,8 +40,6 @@ from synapse.crypto.context_factory import RegularPolicyForHTTPS
|
||||
from synapse.crypto.keyring import Keyring
|
||||
from synapse.events.builder import EventBuilderFactory
|
||||
from synapse.events.presence_router import PresenceRouter
|
||||
from synapse.events.spamcheck import SpamChecker
|
||||
from synapse.events.third_party_rules import ThirdPartyEventRules
|
||||
from synapse.events.utils import EventClientSerializer
|
||||
from synapse.federation.federation_client import FederationClient
|
||||
from synapse.federation.federation_server import (
|
||||
@@ -107,6 +105,7 @@ from synapse.http.client import InsecureInterceptableContextFactory, SimpleHttpC
|
||||
from synapse.http.matrixfederationclient import MatrixFederationHttpClient
|
||||
from synapse.metrics.common_usage_metrics import CommonUsageMetricsManager
|
||||
from synapse.module_api import ModuleApi
|
||||
from synapse.module_api.callbacks import ModuleApiCallbacks
|
||||
from synapse.notifier import Notifier, ReplicationNotifier
|
||||
from synapse.push.bulk_push_rule_evaluator import BulkPushRuleEvaluator
|
||||
from synapse.push.pusherpool import PusherPool
|
||||
@@ -665,14 +664,6 @@ class HomeServer(metaclass=abc.ABCMeta):
|
||||
def get_stats_handler(self) -> StatsHandler:
|
||||
return StatsHandler(self)
|
||||
|
||||
@cache_in_self
|
||||
def get_spam_checker(self) -> SpamChecker:
|
||||
return SpamChecker(self)
|
||||
|
||||
@cache_in_self
|
||||
def get_third_party_event_rules(self) -> ThirdPartyEventRules:
|
||||
return ThirdPartyEventRules(self)
|
||||
|
||||
@cache_in_self
|
||||
def get_password_auth_provider(self) -> PasswordAuthProvider:
|
||||
return PasswordAuthProvider()
|
||||
@@ -779,6 +770,10 @@ class HomeServer(metaclass=abc.ABCMeta):
|
||||
def get_module_api(self) -> ModuleApi:
|
||||
return ModuleApi(self, self.get_auth_handler())
|
||||
|
||||
@cache_in_self
|
||||
def get_module_api_callbacks(self) -> ModuleApiCallbacks:
|
||||
return ModuleApiCallbacks(self)
|
||||
|
||||
@cache_in_self
|
||||
def get_account_data_handler(self) -> AccountDataHandler:
|
||||
return AccountDataHandler(self)
|
||||
|
||||
46
synapse/util/caches/cache_in_self_decorator.py
Normal file
46
synapse/util/caches/cache_in_self_decorator.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import functools
|
||||
from typing import Callable, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
U = TypeVar("U")
|
||||
|
||||
|
||||
def cache_in_self(builder: Callable[[T], U]) -> Callable[[T], U]:
|
||||
"""Wraps a function called e.g. `get_foo`, checking if `self.foo` exists and
|
||||
returning if so. If not, calls the given function and sets `self.foo` to it.
|
||||
|
||||
Also ensures that dependency cycles throw an exception correctly, rather
|
||||
than overflowing the stack.
|
||||
"""
|
||||
|
||||
if not builder.__name__.startswith("get_"):
|
||||
raise Exception(
|
||||
"@cache_in_self can only be used on functions starting with `get_`"
|
||||
)
|
||||
|
||||
# get_attr -> _attr
|
||||
depname = builder.__name__[len("get") :]
|
||||
|
||||
building = [False]
|
||||
|
||||
@functools.wraps(builder)
|
||||
def _get(self: T) -> U:
|
||||
try:
|
||||
return getattr(self, depname)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# Prevent cyclic dependencies from deadlocking
|
||||
if building[0]:
|
||||
raise ValueError("Cyclic dependency while building %s" % (depname,))
|
||||
|
||||
building[0] = True
|
||||
try:
|
||||
dep = builder(self)
|
||||
setattr(self, depname, dep)
|
||||
finally:
|
||||
building[0] = False
|
||||
|
||||
return dep
|
||||
|
||||
return _get
|
||||
@@ -791,7 +791,7 @@ class UserDirectoryTestCase(unittest.HomeserverTestCase):
|
||||
return False
|
||||
|
||||
# Configure a spam checker that does not filter any users.
|
||||
spam_checker = self.hs.get_spam_checker()
|
||||
spam_checker = self.hs.get_module_api_callbacks().spam_checker
|
||||
spam_checker._check_username_for_spam_callbacks = [allow_all]
|
||||
|
||||
# The results do not change:
|
||||
|
||||
@@ -1249,9 +1249,8 @@ class AccountStatusTestCase(unittest.HomeserverTestCase):
|
||||
# account status will fail.
|
||||
return UserID.from_string(user_id).localpart == "someuser"
|
||||
|
||||
self.hs.get_account_validity_handler()._is_user_expired_callbacks.append(
|
||||
is_expired
|
||||
)
|
||||
account_validity_callbacks = self.hs.get_module_api_callbacks().account_validity
|
||||
account_validity_callbacks.is_user_expired_callbacks.append(is_expired)
|
||||
|
||||
self._test_status(
|
||||
users=[user],
|
||||
|
||||
@@ -814,7 +814,9 @@ class RoomsCreateTestCase(RoomBase):
|
||||
return False
|
||||
|
||||
join_mock = Mock(side_effect=user_may_join_room)
|
||||
self.hs.get_spam_checker()._user_may_join_room_callbacks.append(join_mock)
|
||||
self.hs.get_module_api_callbacks().spam_checker._user_may_join_room_callbacks.append(
|
||||
join_mock
|
||||
)
|
||||
|
||||
channel = self.make_request(
|
||||
"POST",
|
||||
@@ -840,7 +842,9 @@ class RoomsCreateTestCase(RoomBase):
|
||||
return Codes.CONSENT_NOT_GIVEN
|
||||
|
||||
join_mock = Mock(side_effect=user_may_join_room_codes)
|
||||
self.hs.get_spam_checker()._user_may_join_room_callbacks.append(join_mock)
|
||||
self.hs.get_module_api_callbacks().spam_checker._user_may_join_room_callbacks.append(
|
||||
join_mock
|
||||
)
|
||||
|
||||
channel = self.make_request(
|
||||
"POST",
|
||||
@@ -1162,7 +1166,9 @@ class RoomJoinTestCase(RoomBase):
|
||||
# `spec` argument is needed for this function mock to have `__qualname__`, which
|
||||
# is needed for `Measure` metrics buried in SpamChecker.
|
||||
callback_mock = Mock(side_effect=user_may_join_room, spec=lambda *x: None)
|
||||
self.hs.get_spam_checker()._user_may_join_room_callbacks.append(callback_mock)
|
||||
self.hs.get_module_api_callbacks().spam_checker._user_may_join_room_callbacks.append(
|
||||
callback_mock
|
||||
)
|
||||
|
||||
# Join a first room, without being invited to it.
|
||||
self.helper.join(self.room1, self.user2, tok=self.tok2)
|
||||
@@ -1227,7 +1233,9 @@ class RoomJoinTestCase(RoomBase):
|
||||
# `spec` argument is needed for this function mock to have `__qualname__`, which
|
||||
# is needed for `Measure` metrics buried in SpamChecker.
|
||||
callback_mock = Mock(side_effect=user_may_join_room, spec=lambda *x: None)
|
||||
self.hs.get_spam_checker()._user_may_join_room_callbacks.append(callback_mock)
|
||||
self.hs.get_module_api_callbacks().spam_checker._user_may_join_room_callbacks.append(
|
||||
callback_mock
|
||||
)
|
||||
|
||||
# Join a first room, without being invited to it.
|
||||
self.helper.join(self.room1, self.user2, tok=self.tok2)
|
||||
@@ -1643,7 +1651,7 @@ class RoomMessagesTestCase(RoomBase):
|
||||
|
||||
spam_checker = SpamCheck()
|
||||
|
||||
self.hs.get_spam_checker()._check_event_for_spam_callbacks.append(
|
||||
self.hs.get_module_api_callbacks().spam_checker._check_event_for_spam_callbacks.append(
|
||||
spam_checker.check_event_for_spam
|
||||
)
|
||||
|
||||
@@ -3381,7 +3389,9 @@ class ThreepidInviteTestCase(unittest.HomeserverTestCase):
|
||||
# `spec` argument is needed for this function mock to have `__qualname__`, which
|
||||
# is needed for `Measure` metrics buried in SpamChecker.
|
||||
mock = Mock(return_value=make_awaitable(True), spec=lambda *x: None)
|
||||
self.hs.get_spam_checker()._user_may_send_3pid_invite_callbacks.append(mock)
|
||||
self.hs.get_module_api_callbacks().spam_checker._user_may_send_3pid_invite_callbacks.append(
|
||||
mock
|
||||
)
|
||||
|
||||
# Send a 3PID invite into the room and check that it succeeded.
|
||||
email_to_invite = "teresa@example.com"
|
||||
@@ -3446,7 +3456,9 @@ class ThreepidInviteTestCase(unittest.HomeserverTestCase):
|
||||
return_value=make_awaitable(synapse.module_api.NOT_SPAM),
|
||||
spec=lambda *x: None,
|
||||
)
|
||||
self.hs.get_spam_checker()._user_may_send_3pid_invite_callbacks.append(mock)
|
||||
self.hs.get_module_api_callbacks().spam_checker._user_may_send_3pid_invite_callbacks.append(
|
||||
mock
|
||||
)
|
||||
|
||||
# Send a 3PID invite into the room and check that it succeeded.
|
||||
email_to_invite = "teresa@example.com"
|
||||
|
||||
@@ -22,7 +22,9 @@ from synapse.api.errors import SynapseError
|
||||
from synapse.api.room_versions import RoomVersion
|
||||
from synapse.config.homeserver import HomeServerConfig
|
||||
from synapse.events import EventBase
|
||||
from synapse.events.third_party_rules import load_legacy_third_party_event_rules
|
||||
from synapse.module_api.callbacks.third_party_event_rules import (
|
||||
load_legacy_third_party_event_rules,
|
||||
)
|
||||
from synapse.rest import admin
|
||||
from synapse.rest.client import account, login, profile, room
|
||||
from synapse.server import HomeServer
|
||||
@@ -146,7 +148,7 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
return ev.type != "foo.bar.forbidden", None
|
||||
|
||||
callback = Mock(spec=[], side_effect=check)
|
||||
self.hs.get_third_party_event_rules()._check_event_allowed_callbacks = [
|
||||
self.hs.get_module_api_callbacks().third_party_event_rules._check_event_allowed_callbacks = [
|
||||
callback
|
||||
]
|
||||
|
||||
@@ -202,7 +204,9 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
) -> Tuple[bool, Optional[JsonDict]]:
|
||||
raise NastyHackException(429, "message")
|
||||
|
||||
self.hs.get_third_party_event_rules()._check_event_allowed_callbacks = [check]
|
||||
self.hs.get_module_api_callbacks().third_party_event_rules._check_event_allowed_callbacks = [
|
||||
check
|
||||
]
|
||||
|
||||
# Make a request
|
||||
channel = self.make_request(
|
||||
@@ -229,7 +233,9 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
ev.content = {"x": "y"}
|
||||
return True, None
|
||||
|
||||
self.hs.get_third_party_event_rules()._check_event_allowed_callbacks = [check]
|
||||
self.hs.get_module_api_callbacks().third_party_event_rules._check_event_allowed_callbacks = [
|
||||
check
|
||||
]
|
||||
|
||||
# now send the event
|
||||
channel = self.make_request(
|
||||
@@ -253,7 +259,9 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
d["content"] = {"x": "y"}
|
||||
return True, d
|
||||
|
||||
self.hs.get_third_party_event_rules()._check_event_allowed_callbacks = [check]
|
||||
self.hs.get_module_api_callbacks().third_party_event_rules._check_event_allowed_callbacks = [
|
||||
check
|
||||
]
|
||||
|
||||
# now send the event
|
||||
channel = self.make_request(
|
||||
@@ -289,7 +297,9 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
}
|
||||
return True, d
|
||||
|
||||
self.hs.get_third_party_event_rules()._check_event_allowed_callbacks = [check]
|
||||
self.hs.get_module_api_callbacks().third_party_event_rules._check_event_allowed_callbacks = [
|
||||
check
|
||||
]
|
||||
|
||||
# Send an event, then edit it.
|
||||
channel = self.make_request(
|
||||
@@ -440,7 +450,9 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
)
|
||||
return True, None
|
||||
|
||||
self.hs.get_third_party_event_rules()._check_event_allowed_callbacks = [test_fn]
|
||||
self.hs.get_module_api_callbacks().third_party_event_rules._check_event_allowed_callbacks = [
|
||||
test_fn
|
||||
]
|
||||
|
||||
# Sometimes the bug might not happen the first time the event type is added
|
||||
# to the state but might happen when an event updates the state of the room for
|
||||
@@ -466,7 +478,7 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
def test_on_new_event(self) -> None:
|
||||
"""Test that the on_new_event callback is called on new events"""
|
||||
on_new_event = Mock(make_awaitable(None))
|
||||
self.hs.get_third_party_event_rules()._on_new_event_callbacks.append(
|
||||
self.hs.get_module_api_callbacks().third_party_event_rules._on_new_event_callbacks.append(
|
||||
on_new_event
|
||||
)
|
||||
|
||||
@@ -569,7 +581,9 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
|
||||
# Register a mock callback.
|
||||
m = Mock(return_value=make_awaitable(None))
|
||||
self.hs.get_third_party_event_rules()._on_profile_update_callbacks.append(m)
|
||||
self.hs.get_module_api_callbacks().third_party_event_rules._on_profile_update_callbacks.append(
|
||||
m
|
||||
)
|
||||
|
||||
# Change the display name.
|
||||
channel = self.make_request(
|
||||
@@ -628,7 +642,9 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
|
||||
# Register a mock callback.
|
||||
m = Mock(return_value=make_awaitable(None))
|
||||
self.hs.get_third_party_event_rules()._on_profile_update_callbacks.append(m)
|
||||
self.hs.get_module_api_callbacks().third_party_event_rules._on_profile_update_callbacks.append(
|
||||
m
|
||||
)
|
||||
|
||||
# Register an admin user.
|
||||
self.register_user("admin", "password", admin=True)
|
||||
@@ -667,7 +683,7 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
"""
|
||||
# Register a mocked callback.
|
||||
deactivation_mock = Mock(return_value=make_awaitable(None))
|
||||
third_party_rules = self.hs.get_third_party_event_rules()
|
||||
third_party_rules = self.hs.get_module_api_callbacks().third_party_event_rules
|
||||
third_party_rules._on_user_deactivation_status_changed_callbacks.append(
|
||||
deactivation_mock,
|
||||
)
|
||||
@@ -675,7 +691,7 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
# deactivation code calls it in a way that let modules know the user is being
|
||||
# deactivated.
|
||||
profile_mock = Mock(return_value=make_awaitable(None))
|
||||
self.hs.get_third_party_event_rules()._on_profile_update_callbacks.append(
|
||||
self.hs.get_module_api_callbacks().third_party_event_rules._on_profile_update_callbacks.append(
|
||||
profile_mock,
|
||||
)
|
||||
|
||||
@@ -725,7 +741,7 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
"""
|
||||
# Register a mock callback.
|
||||
m = Mock(return_value=make_awaitable(None))
|
||||
third_party_rules = self.hs.get_third_party_event_rules()
|
||||
third_party_rules = self.hs.get_module_api_callbacks().third_party_event_rules
|
||||
third_party_rules._on_user_deactivation_status_changed_callbacks.append(m)
|
||||
|
||||
# Register an admin user.
|
||||
@@ -779,7 +795,7 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
"""
|
||||
# Register a mocked callback.
|
||||
deactivation_mock = Mock(return_value=make_awaitable(False))
|
||||
third_party_rules = self.hs.get_third_party_event_rules()
|
||||
third_party_rules = self.hs.get_module_api_callbacks().third_party_event_rules
|
||||
third_party_rules._check_can_deactivate_user_callbacks.append(
|
||||
deactivation_mock,
|
||||
)
|
||||
@@ -825,7 +841,7 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
"""
|
||||
# Register a mocked callback.
|
||||
deactivation_mock = Mock(return_value=make_awaitable(False))
|
||||
third_party_rules = self.hs.get_third_party_event_rules()
|
||||
third_party_rules = self.hs.get_module_api_callbacks().third_party_event_rules
|
||||
third_party_rules._check_can_deactivate_user_callbacks.append(
|
||||
deactivation_mock,
|
||||
)
|
||||
@@ -864,7 +880,7 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
"""
|
||||
# Register a mocked callback.
|
||||
shutdown_mock = Mock(return_value=make_awaitable(False))
|
||||
third_party_rules = self.hs.get_third_party_event_rules()
|
||||
third_party_rules = self.hs.get_module_api_callbacks().third_party_event_rules
|
||||
third_party_rules._check_can_shutdown_room_callbacks.append(
|
||||
shutdown_mock,
|
||||
)
|
||||
@@ -900,7 +916,7 @@ class ThirdPartyRulesTestCase(unittest.FederatingHomeserverTestCase):
|
||||
"""
|
||||
# Register a mocked callback.
|
||||
threepid_bind_mock = Mock(return_value=make_awaitable(None))
|
||||
third_party_rules = self.hs.get_third_party_event_rules()
|
||||
third_party_rules = self.hs.get_module_api_callbacks().third_party_event_rules
|
||||
third_party_rules._on_threepid_bind_callbacks.append(threepid_bind_mock)
|
||||
|
||||
# Register an admin user.
|
||||
|
||||
@@ -31,10 +31,10 @@ from twisted.test.proto_helpers import MemoryReactor
|
||||
|
||||
from synapse.api.errors import Codes
|
||||
from synapse.events import EventBase
|
||||
from synapse.events.spamcheck import load_legacy_spam_checkers
|
||||
from synapse.http.types import QueryParams
|
||||
from synapse.logging.context import make_deferred_yieldable
|
||||
from synapse.module_api import ModuleApi
|
||||
from synapse.module_api.callbacks.spamchecker_callbacks import load_legacy_spam_checkers
|
||||
from synapse.rest import admin
|
||||
from synapse.rest.client import login
|
||||
from synapse.rest.media.v1._base import FileInfo
|
||||
|
||||
@@ -72,11 +72,13 @@ from twisted.web.server import Request, Site
|
||||
from synapse.config.database import DatabaseConnectionConfig
|
||||
from synapse.config.homeserver import HomeServerConfig
|
||||
from synapse.events.presence_router import load_legacy_presence_router
|
||||
from synapse.events.spamcheck import load_legacy_spam_checkers
|
||||
from synapse.events.third_party_rules import load_legacy_third_party_event_rules
|
||||
from synapse.handlers.auth import load_legacy_password_auth_providers
|
||||
from synapse.http.site import SynapseRequest
|
||||
from synapse.logging.context import ContextResourceUsage
|
||||
from synapse.module_api.callbacks.spamchecker_callbacks import load_legacy_spam_checkers
|
||||
from synapse.module_api.callbacks.third_party_event_rules import (
|
||||
load_legacy_third_party_event_rules,
|
||||
)
|
||||
from synapse.server import HomeServer
|
||||
from synapse.storage import DataStore
|
||||
from synapse.storage.engines import PostgresEngine, create_engine
|
||||
|
||||
Reference in New Issue
Block a user