Merge branch 'develop' of github.com:matrix-org/synapse into babolivier/rewrite_is_url
This commit is contained in:
18
CHANGES.md
18
CHANGES.md
@@ -1,8 +1,20 @@
|
||||
Synapse 1.55.0rc1 (2022-03-15)
|
||||
==============================
|
||||
Synapse 1.55.0 (2022-03-22)
|
||||
===========================
|
||||
|
||||
This release removes a workaround introduced in Synapse 1.50.0 for Mjolnir compatibility. **This breaks compatibility with Mjolnir 1.3.1 and earlier. ([\#11700](https://github.com/matrix-org/synapse/issues/11700))**; Mjolnir users should upgrade Mjolnir before upgrading Synapse to this version.
|
||||
|
||||
This release also moves the location of the `synctl` script; see the [upgrade notes](https://github.com/matrix-org/synapse/blob/develop/docs/upgrade.md#synctl-script-has-been-moved) for more details.
|
||||
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Tweak copy for default Single Sign-On account details template to better adhere to mobile app store guidelines. ([\#12265](https://github.com/matrix-org/synapse/issues/12265), [\#12260](https://github.com/matrix-org/synapse/issues/12260))
|
||||
|
||||
|
||||
Synapse 1.55.0rc1 (2022-03-15)
|
||||
==============================
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
@@ -38,6 +50,7 @@ Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
- **Remove workaround introduced in Synapse 1.50.0 for Mjolnir compatibility. Breaks compatibility with Mjolnir 1.3.1 and earlier. ([\#11700](https://github.com/matrix-org/synapse/issues/11700))**
|
||||
- **`synctl` has been moved into into `synapse._scripts` and is exposed as an entry point; see [upgrade notes](https://github.com/matrix-org/synapse/blob/develop/docs/upgrade.md#synctl-script-has-been-moved). ([\#12140](https://github.com/matrix-org/synapse/issues/12140))
|
||||
- Remove backwards compatibilty with pagination tokens from the `/relations` and `/aggregations` endpoints generated from Synapse < v1.52.0. ([\#12138](https://github.com/matrix-org/synapse/issues/12138))
|
||||
- The groups/communities feature in Synapse has been deprecated. ([\#12200](https://github.com/matrix-org/synapse/issues/12200))
|
||||
|
||||
@@ -56,7 +69,6 @@ Internal Changes
|
||||
- Fix CI not attaching source distributions and wheels to the GitHub releases. ([\#12131](https://github.com/matrix-org/synapse/issues/12131))
|
||||
- Remove unused mocks from `test_typing`. ([\#12136](https://github.com/matrix-org/synapse/issues/12136))
|
||||
- Give `scripts-dev` scripts suffixes for neater CI config. ([\#12137](https://github.com/matrix-org/synapse/issues/12137))
|
||||
- Move `synctl` into `synapse._scripts` and expose as an entry point. ([\#12140](https://github.com/matrix-org/synapse/issues/12140))
|
||||
- Move the snapcraft configuration file to `contrib`. ([\#12142](https://github.com/matrix-org/synapse/issues/12142))
|
||||
- Enable [MSC3030](https://github.com/matrix-org/matrix-doc/pull/3030) Complement tests in CI. ([\#12144](https://github.com/matrix-org/synapse/issues/12144))
|
||||
- Enable [MSC2716](https://github.com/matrix-org/matrix-doc/pull/2716) Complement tests in CI. ([\#12145](https://github.com/matrix-org/synapse/issues/12145))
|
||||
|
||||
1
changelog.d/12036.misc
Normal file
1
changelog.d/12036.misc
Normal file
@@ -0,0 +1 @@
|
||||
Rename `shared_rooms` to `mutual_rooms` (MSC2666), as per proposal changes.
|
||||
1
changelog.d/12038.misc
Normal file
1
changelog.d/12038.misc
Normal file
@@ -0,0 +1 @@
|
||||
Remove check on `update_user_directory` for shared rooms handler (MSC2666), and update/expand documentation.
|
||||
1
changelog.d/12250.feature
Normal file
1
changelog.d/12250.feature
Normal file
@@ -0,0 +1 @@
|
||||
Allow registering admin users using the module API. Contributed by Famedly.
|
||||
@@ -1 +0,0 @@
|
||||
Reword 'Choose your user name' as 'Choose your account name' in the SSO registration template, in order to comply with SIWA guidelines.
|
||||
1
changelog.d/12262.misc
Normal file
1
changelog.d/12262.misc
Normal file
@@ -0,0 +1 @@
|
||||
Refuse to start if DB has non-`C` locale, unless config flag `allow_unsafe_db_locale` is set to true.
|
||||
1
changelog.d/12266.misc
Normal file
1
changelog.d/12266.misc
Normal file
@@ -0,0 +1 @@
|
||||
Optionally include account validity expiration information to experimental [MSC3720](https://github.com/matrix-org/matrix-doc/pull/3720) account status responses.
|
||||
1
changelog.d/12269.misc
Normal file
1
changelog.d/12269.misc
Normal file
@@ -0,0 +1 @@
|
||||
Use type stubs for `psycopg2`.
|
||||
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -1,3 +1,9 @@
|
||||
matrix-synapse-py3 (1.55.0) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.55.0.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Tue, 22 Mar 2022 13:59:26 +0000
|
||||
|
||||
matrix-synapse-py3 (1.55.0~rc1) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.55.0~rc1.
|
||||
|
||||
@@ -234,12 +234,13 @@ host all all ::1/128 ident
|
||||
### Fixing incorrect `COLLATE` or `CTYPE`
|
||||
|
||||
Synapse will refuse to set up a new database if it has the wrong values of
|
||||
`COLLATE` and `CTYPE` set, and will log warnings on existing databases. Using
|
||||
different locales can cause issues if the locale library is updated from
|
||||
`COLLATE` and `CTYPE` set. Synapse will also refuse to start an existing database with incorrect values
|
||||
of `COLLATE` and `CTYPE` unless the config flag `allow_unsafe_locale`, found in the
|
||||
`database` section of the config, is set to true. Using different locales can cause issues if the locale library is updated from
|
||||
underneath the database, or if a different version of the locale is used on any
|
||||
replicas.
|
||||
|
||||
The safest way to fix the issue is to dump the database and recreate it with
|
||||
If you have a databse with an unsafe locale, the safest way to fix the issue is to dump the database and recreate it with
|
||||
the correct locale parameter (as shown above). It is also possible to change the
|
||||
parameters on a live database and run a `REINDEX` on the entire database,
|
||||
however extreme care must be taken to avoid database corruption.
|
||||
|
||||
@@ -800,6 +800,12 @@ caches:
|
||||
# 'txn_limit' gives the maximum number of transactions to run per connection
|
||||
# before reconnecting. Defaults to 0, which means no limit.
|
||||
#
|
||||
# 'allow_unsafe_locale' is an option specific to Postgres. Under the default behavior, Synapse will refuse to
|
||||
# start if the postgres db is set to a non-C locale. You can override this behavior (which is *not* recommended)
|
||||
# by setting 'allow_unsafe_locale' to true. Note that doing so may corrupt your database. You can find more information
|
||||
# here: https://matrix-org.github.io/synapse/latest/postgres.html#fixing-incorrect-collate-or-ctype and here:
|
||||
# https://wiki.postgresql.org/wiki/Locale_data_changes
|
||||
#
|
||||
# 'args' gives options which are passed through to the database engine,
|
||||
# except for options starting 'cp_', which are used to configure the Twisted
|
||||
# connection pool. For a reference to valid arguments, see:
|
||||
|
||||
@@ -528,10 +528,19 @@ the following regular expressions:
|
||||
|
||||
^/_matrix/client/(r0|v3|unstable)/user_directory/search$
|
||||
|
||||
When using this worker you must also set `update_user_directory: False` in the
|
||||
When using this worker you must also set `update_user_directory: false` in the
|
||||
shared configuration file to stop the main synapse running background
|
||||
jobs related to updating the user directory.
|
||||
|
||||
Above endpoint is not *required* to be routed to this worker. By default,
|
||||
`update_user_directory` is set to `true`, which means the main process
|
||||
will handle updates. All workers configured with `client` can handle the above
|
||||
endpoint as long as either this worker or the main process are configured to
|
||||
handle it, and are online.
|
||||
|
||||
If `update_user_directory` is set to `false`, and this worker is not running,
|
||||
the above endpoint may give outdated results.
|
||||
|
||||
### `synapse.app.frontend_proxy`
|
||||
|
||||
Proxies some frequently-requested client endpoints to add caching and remove
|
||||
|
||||
1
setup.py
1
setup.py
@@ -108,6 +108,7 @@ CONDITIONAL_REQUIREMENTS["mypy"] = [
|
||||
"types-jsonschema>=3.2.0",
|
||||
"types-opentracing>=2.4.2",
|
||||
"types-Pillow>=8.3.4",
|
||||
"types-psycopg2>=2.9.9",
|
||||
"types-pyOpenSSL>=20.0.7",
|
||||
"types-PyYAML>=5.4.10",
|
||||
"types-requests>=2.26.0",
|
||||
|
||||
@@ -68,7 +68,7 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
__version__ = "1.55.0rc1"
|
||||
__version__ = "1.55.0"
|
||||
|
||||
if bool(os.environ.get("SYNAPSE_TEST_PATCH_LOG_CONTEXTS", False)):
|
||||
# We import here so that we don't have to install a bunch of deps when
|
||||
|
||||
@@ -37,6 +37,12 @@ DEFAULT_CONFIG = """\
|
||||
# 'txn_limit' gives the maximum number of transactions to run per connection
|
||||
# before reconnecting. Defaults to 0, which means no limit.
|
||||
#
|
||||
# 'allow_unsafe_locale' is an option specific to Postgres. Under the default behavior, Synapse will refuse to
|
||||
# start if the postgres db is set to a non-C locale. You can override this behavior (which is *not* recommended)
|
||||
# by setting 'allow_unsafe_locale' to true. Note that doing so may corrupt your database. You can find more information
|
||||
# here: https://matrix-org.github.io/synapse/latest/postgres.html#fixing-incorrect-collate-or-ctype and here:
|
||||
# https://wiki.postgresql.org/wiki/Locale_data_changes
|
||||
#
|
||||
# 'args' gives options which are passed through to the database engine,
|
||||
# except for options starting 'cp_', which are used to configure the Twisted
|
||||
# connection pool. For a reference to valid arguments, see:
|
||||
|
||||
@@ -676,6 +676,10 @@ class ServerConfig(Config):
|
||||
):
|
||||
raise ConfigError("'custom_template_directory' must be a string")
|
||||
|
||||
self.use_account_validity_in_account_status: bool = (
|
||||
config.get("use_account_validity_in_account_status") or False
|
||||
)
|
||||
|
||||
self.identity_server_rewrite_map: Dict[str, str] = (
|
||||
config.get("rewrite_identity_server_base_urls") or {}
|
||||
)
|
||||
|
||||
@@ -26,6 +26,10 @@ class AccountHandler:
|
||||
self._main_store = hs.get_datastores().main
|
||||
self._is_mine = hs.is_mine
|
||||
self._federation_client = hs.get_federation_client()
|
||||
self._use_account_validity_in_account_status = (
|
||||
hs.config.server.use_account_validity_in_account_status
|
||||
)
|
||||
self._account_validity_handler = hs.get_account_validity_handler()
|
||||
|
||||
async def get_account_statuses(
|
||||
self,
|
||||
@@ -106,6 +110,13 @@ class AccountHandler:
|
||||
"deactivated": userinfo.is_deactivated,
|
||||
}
|
||||
|
||||
if self._use_account_validity_in_account_status:
|
||||
status[
|
||||
"org.matrix.expired"
|
||||
] = await self._account_validity_handler.is_user_expired(
|
||||
user_id.to_string()
|
||||
)
|
||||
|
||||
return status
|
||||
|
||||
async def _get_remote_account_statuses(
|
||||
|
||||
@@ -611,15 +611,18 @@ class ModuleApi:
|
||||
localpart: str,
|
||||
displayname: Optional[str] = None,
|
||||
emails: Optional[List[str]] = None,
|
||||
admin: bool = False,
|
||||
) -> "defer.Deferred[str]":
|
||||
"""Registers a new user with given localpart and optional displayname, emails.
|
||||
|
||||
Added in Synapse v1.2.0.
|
||||
Changed in Synapse v1.56.0: add 'admin' argument to register the user as admin.
|
||||
|
||||
Args:
|
||||
localpart: The localpart of the new user.
|
||||
displayname: The displayname of the new user.
|
||||
emails: Emails to bind to the new user.
|
||||
admin: True if the user should be registered as a server admin.
|
||||
|
||||
Raises:
|
||||
SynapseError if there is an error performing the registration. Check the
|
||||
@@ -633,6 +636,7 @@ class ModuleApi:
|
||||
localpart=localpart,
|
||||
default_display_name=displayname,
|
||||
bind_emails=emails or [],
|
||||
admin=admin,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -130,13 +130,13 @@
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Choose your account name</h1>
|
||||
<p>This is required to create your account on {{ server_name }}, and you can't change this later.</p>
|
||||
<h1>Create your account</h1>
|
||||
<p>This is required. Continue to create your account on {{ server_name }}. You can't change this later.</p>
|
||||
</header>
|
||||
<main>
|
||||
<form method="post" class="form__input" id="form">
|
||||
<div class="username_input" id="username_input">
|
||||
<label for="field-username">Username</label>
|
||||
<label for="field-username">Username (required)</label>
|
||||
<div class="prefix">@</div>
|
||||
<input type="text" name="username" id="field-username" value="{{ user_attributes.localpart }}" autofocus>
|
||||
<div class="postfix">:{{ server_name }}</div>
|
||||
@@ -145,7 +145,7 @@
|
||||
<input type="submit" value="Continue" class="primary-button">
|
||||
{% if user_attributes.avatar_url or user_attributes.display_name or user_attributes.emails %}
|
||||
<section class="idp-pick-details">
|
||||
<h2>{% if idp.idp_icon %}<img src="{{ idp.idp_icon | mxc_to_http(24, 24) }}"/>{% endif %}Information from {{ idp.idp_name }}</h2>
|
||||
<h2>{% if idp.idp_icon %}<img src="{{ idp.idp_icon | mxc_to_http(24, 24) }}"/>{% endif %}Optional data from {{ idp.idp_name }}</h2>
|
||||
{% if user_attributes.avatar_url %}
|
||||
<label class="idp-detail idp-avatar" for="idp-avatar">
|
||||
<div class="check-row">
|
||||
|
||||
@@ -62,7 +62,7 @@ function validateUsername(username) {
|
||||
usernameField.parentElement.classList.remove("invalid");
|
||||
usernameOutput.classList.remove("error");
|
||||
if (!username) {
|
||||
return reportError("Please provide a username");
|
||||
return reportError("This is required. Please provide a username");
|
||||
}
|
||||
if (username.length > 255) {
|
||||
return reportError("Too long, please choose something shorter");
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<p>An open network for secure, decentralized communication.<br>© 2021 The Matrix.org Foundation C.I.C.</p>
|
||||
<p>An open network for secure, decentralized communication.<br>© 2022 The Matrix.org Foundation C.I.C.</p>
|
||||
</footer>
|
||||
@@ -32,6 +32,7 @@ from synapse.rest.client import (
|
||||
knock,
|
||||
login as v1_login,
|
||||
logout,
|
||||
mutual_rooms,
|
||||
notifications,
|
||||
openid,
|
||||
password_policy,
|
||||
@@ -49,7 +50,6 @@ from synapse.rest.client import (
|
||||
room_keys,
|
||||
room_upgrade_rest_servlet,
|
||||
sendtodevice,
|
||||
shared_rooms,
|
||||
sync,
|
||||
tags,
|
||||
thirdparty,
|
||||
@@ -132,4 +132,4 @@ class ClientRestResource(JsonResource):
|
||||
admin.register_servlets_for_client_rest_resource(hs, client_resource)
|
||||
|
||||
# unstable
|
||||
shared_rooms.register_servlets(hs, client_resource)
|
||||
mutual_rooms.register_servlets(hs, client_resource)
|
||||
|
||||
@@ -28,13 +28,13 @@ if TYPE_CHECKING:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UserSharedRoomsServlet(RestServlet):
|
||||
class UserMutualRoomsServlet(RestServlet):
|
||||
"""
|
||||
GET /uk.half-shot.msc2666/user/shared_rooms/{user_id} HTTP/1.1
|
||||
GET /uk.half-shot.msc2666/user/mutual_rooms/{user_id} HTTP/1.1
|
||||
"""
|
||||
|
||||
PATTERNS = client_patterns(
|
||||
"/uk.half-shot.msc2666/user/shared_rooms/(?P<user_id>[^/]*)",
|
||||
"/uk.half-shot.msc2666/user/mutual_rooms/(?P<user_id>[^/]*)",
|
||||
releases=(), # This is an unstable feature
|
||||
)
|
||||
|
||||
@@ -42,17 +42,19 @@ class UserSharedRoomsServlet(RestServlet):
|
||||
super().__init__()
|
||||
self.auth = hs.get_auth()
|
||||
self.store = hs.get_datastores().main
|
||||
self.user_directory_active = hs.config.server.update_user_directory
|
||||
self.user_directory_search_enabled = (
|
||||
hs.config.userdirectory.user_directory_search_enabled
|
||||
)
|
||||
|
||||
async def on_GET(
|
||||
self, request: SynapseRequest, user_id: str
|
||||
) -> Tuple[int, JsonDict]:
|
||||
|
||||
if not self.user_directory_active:
|
||||
if not self.user_directory_search_enabled:
|
||||
raise SynapseError(
|
||||
code=400,
|
||||
msg="The user directory is disabled on this server. Cannot determine shared rooms.",
|
||||
errcode=Codes.FORBIDDEN,
|
||||
msg="User directory searching is disabled. Cannot determine shared rooms.",
|
||||
errcode=Codes.UNKNOWN,
|
||||
)
|
||||
|
||||
UserID.from_string(user_id)
|
||||
@@ -64,7 +66,8 @@ class UserSharedRoomsServlet(RestServlet):
|
||||
msg="You cannot request a list of shared rooms with yourself",
|
||||
errcode=Codes.FORBIDDEN,
|
||||
)
|
||||
rooms = await self.store.get_shared_rooms_for_users(
|
||||
|
||||
rooms = await self.store.get_mutual_rooms_for_users(
|
||||
requester.user.to_string(), user_id
|
||||
)
|
||||
|
||||
@@ -72,4 +75,4 @@ class UserSharedRoomsServlet(RestServlet):
|
||||
|
||||
|
||||
def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None:
|
||||
UserSharedRoomsServlet(hs).register(http_server)
|
||||
UserMutualRoomsServlet(hs).register(http_server)
|
||||
@@ -288,7 +288,7 @@ class LoggingTransaction:
|
||||
"""
|
||||
|
||||
if isinstance(self.database_engine, PostgresEngine):
|
||||
from psycopg2.extras import execute_batch # type: ignore
|
||||
from psycopg2.extras import execute_batch
|
||||
|
||||
self._do_execute(lambda *x: execute_batch(self.txn, *x), sql, args)
|
||||
else:
|
||||
@@ -302,10 +302,18 @@ class LoggingTransaction:
|
||||
rows (e.g. INSERTs).
|
||||
"""
|
||||
assert isinstance(self.database_engine, PostgresEngine)
|
||||
from psycopg2.extras import execute_values # type: ignore
|
||||
from psycopg2.extras import execute_values
|
||||
|
||||
return self._do_execute(
|
||||
lambda *x: execute_values(self.txn, *x, fetch=fetch), sql, *args
|
||||
# Type ignore: mypy is unhappy because if `x` is a 5-tuple, then there will
|
||||
# be two values for `fetch`: one given positionally, and another given
|
||||
# as a keyword argument. We might be able to fix this by
|
||||
# - propagating the signature of psycopg2.extras.execute_values to this
|
||||
# function, or
|
||||
# - changing `*args: Any` to `values: T` for some appropriate T.
|
||||
lambda *x: execute_values(self.txn, *x, fetch=fetch), # type: ignore[misc]
|
||||
sql,
|
||||
*args,
|
||||
)
|
||||
|
||||
def execute(self, sql: str, *args: Any) -> None:
|
||||
|
||||
@@ -730,7 +730,7 @@ class UserDirectoryStore(UserDirectoryBackgroundUpdateStore):
|
||||
users.update(rows)
|
||||
return list(users)
|
||||
|
||||
async def get_shared_rooms_for_users(
|
||||
async def get_mutual_rooms_for_users(
|
||||
self, user_id: str, other_user_id: str
|
||||
) -> Set[str]:
|
||||
"""
|
||||
@@ -744,7 +744,7 @@ class UserDirectoryStore(UserDirectoryBackgroundUpdateStore):
|
||||
A set of room ID's that the users share.
|
||||
"""
|
||||
|
||||
def _get_shared_rooms_for_users_txn(
|
||||
def _get_mutual_rooms_for_users_txn(
|
||||
txn: LoggingTransaction,
|
||||
) -> List[Dict[str, str]]:
|
||||
txn.execute(
|
||||
@@ -768,7 +768,7 @@ class UserDirectoryStore(UserDirectoryBackgroundUpdateStore):
|
||||
return rows
|
||||
|
||||
rows = await self.db_pool.runInteraction(
|
||||
"get_shared_rooms_for_users", _get_shared_rooms_for_users_txn
|
||||
"get_mutual_rooms_for_users", _get_mutual_rooms_for_users_txn
|
||||
)
|
||||
|
||||
return {row["room_id"] for row in rows}
|
||||
|
||||
@@ -27,7 +27,7 @@ def create_engine(database_config) -> BaseDatabaseEngine:
|
||||
|
||||
if name == "psycopg2":
|
||||
# Note that psycopg2cffi-compat provides the psycopg2 module on pypy.
|
||||
import psycopg2 # type: ignore
|
||||
import psycopg2
|
||||
|
||||
return PostgresEngine(psycopg2, database_config)
|
||||
|
||||
|
||||
@@ -47,17 +47,26 @@ class PostgresEngine(BaseDatabaseEngine):
|
||||
self.default_isolation_level = (
|
||||
self.module.extensions.ISOLATION_LEVEL_REPEATABLE_READ
|
||||
)
|
||||
self.config = database_config
|
||||
|
||||
@property
|
||||
def single_threaded(self) -> bool:
|
||||
return False
|
||||
|
||||
def get_db_locale(self, txn):
|
||||
txn.execute(
|
||||
"SELECT datcollate, datctype FROM pg_database WHERE datname = current_database()"
|
||||
)
|
||||
collation, ctype = txn.fetchone()
|
||||
return collation, ctype
|
||||
|
||||
def check_database(self, db_conn, allow_outdated_version: bool = False):
|
||||
# Get the version of PostgreSQL that we're using. As per the psycopg2
|
||||
# docs: The number is formed by converting the major, minor, and
|
||||
# revision numbers into two-decimal-digit numbers and appending them
|
||||
# together. For example, version 8.1.5 will be returned as 80105
|
||||
self._version = db_conn.server_version
|
||||
allow_unsafe_locale = self.config.get("allow_unsafe_locale", False)
|
||||
|
||||
# Are we on a supported PostgreSQL version?
|
||||
if not allow_outdated_version and self._version < 100000:
|
||||
@@ -72,33 +81,39 @@ class PostgresEngine(BaseDatabaseEngine):
|
||||
"See docs/postgres.md for more information." % (rows[0][0],)
|
||||
)
|
||||
|
||||
txn.execute(
|
||||
"SELECT datcollate, datctype FROM pg_database WHERE datname = current_database()"
|
||||
)
|
||||
collation, ctype = txn.fetchone()
|
||||
collation, ctype = self.get_db_locale(txn)
|
||||
if collation != "C":
|
||||
logger.warning(
|
||||
"Database has incorrect collation of %r. Should be 'C'\n"
|
||||
"See docs/postgres.md for more information.",
|
||||
"Database has incorrect collation of %r. Should be 'C'",
|
||||
collation,
|
||||
)
|
||||
if not allow_unsafe_locale:
|
||||
raise IncorrectDatabaseSetup(
|
||||
"Database has incorrect collation of %r. Should be 'C'\n"
|
||||
"See docs/postgres.md for more information. You can override this check by"
|
||||
"setting 'allow_unsafe_locale' to true in the database config.",
|
||||
collation,
|
||||
)
|
||||
|
||||
if ctype != "C":
|
||||
logger.warning(
|
||||
"Database has incorrect ctype of %r. Should be 'C'\n"
|
||||
"See docs/postgres.md for more information.",
|
||||
ctype,
|
||||
)
|
||||
if not allow_unsafe_locale:
|
||||
logger.warning(
|
||||
"Database has incorrect ctype of %r. Should be 'C'",
|
||||
ctype,
|
||||
)
|
||||
raise IncorrectDatabaseSetup(
|
||||
"Database has incorrect ctype of %r. Should be 'C'\n"
|
||||
"See docs/postgres.md for more information. You can override this check by"
|
||||
"setting 'allow_unsafe_locale' to true in the database config.",
|
||||
ctype,
|
||||
)
|
||||
|
||||
def check_new_database(self, txn):
|
||||
"""Gets called when setting up a brand new database. This allows us to
|
||||
apply stricter checks on new databases versus existing database.
|
||||
"""
|
||||
|
||||
txn.execute(
|
||||
"SELECT datcollate, datctype FROM pg_database WHERE datname = current_database()"
|
||||
)
|
||||
collation, ctype = txn.fetchone()
|
||||
collation, ctype = self.get_db_locale(txn)
|
||||
|
||||
errors = []
|
||||
|
||||
|
||||
@@ -86,6 +86,16 @@ class ModuleApiTestCase(HomeserverTestCase):
|
||||
displayname = self.get_success(self.store.get_profile_displayname("bob"))
|
||||
self.assertEqual(displayname, "Bobberino")
|
||||
|
||||
def test_can_register_admin_user(self):
|
||||
user_id = self.get_success(
|
||||
self.register_user(
|
||||
"bob_module_admin", "1234", displayname="Bobberino Admin", admin=True
|
||||
)
|
||||
)
|
||||
found_user = self.get_success(self.module_api.get_userinfo_by_id(user_id))
|
||||
self.assertEqual(found_user.user_id.to_string(), user_id)
|
||||
self.assertIdentical(found_user.is_admin, True)
|
||||
|
||||
def test_get_userinfo_by_id(self):
|
||||
user_id = self.register_user("alice", "1234")
|
||||
found_user = self.get_success(self.module_api.get_userinfo_by_id(user_id))
|
||||
|
||||
@@ -31,7 +31,7 @@ from synapse.rest import admin
|
||||
from synapse.rest.client import account, login, register, room
|
||||
from synapse.rest.synapse.client.password_reset import PasswordResetSubmitTokenResource
|
||||
from synapse.server import HomeServer
|
||||
from synapse.types import JsonDict
|
||||
from synapse.types import JsonDict, UserID
|
||||
from synapse.util import Clock
|
||||
|
||||
from tests import unittest
|
||||
@@ -1222,6 +1222,62 @@ class AccountStatusTestCase(unittest.HomeserverTestCase):
|
||||
expected_failures=[users[2]],
|
||||
)
|
||||
|
||||
@unittest.override_config(
|
||||
{
|
||||
"use_account_validity_in_account_status": True,
|
||||
}
|
||||
)
|
||||
def test_no_account_validity(self) -> None:
|
||||
"""Tests that if we decide to include account validity in the response but no
|
||||
account validity 'is_user_expired' callback is provided, we default to marking all
|
||||
users as not expired.
|
||||
"""
|
||||
user = self.register_user("someuser", "password")
|
||||
|
||||
self._test_status(
|
||||
users=[user],
|
||||
expected_statuses={
|
||||
user: {
|
||||
"exists": True,
|
||||
"deactivated": False,
|
||||
"org.matrix.expired": False,
|
||||
},
|
||||
},
|
||||
expected_failures=[],
|
||||
)
|
||||
|
||||
@unittest.override_config(
|
||||
{
|
||||
"use_account_validity_in_account_status": True,
|
||||
}
|
||||
)
|
||||
def test_account_validity_expired(self) -> None:
|
||||
"""Test that if we decide to include account validity in the response and the user
|
||||
is expired, we return the correct info.
|
||||
"""
|
||||
user = self.register_user("someuser", "password")
|
||||
|
||||
async def is_expired(user_id: str) -> bool:
|
||||
# We can't blindly say everyone is expired, otherwise the request to get the
|
||||
# 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
|
||||
)
|
||||
|
||||
self._test_status(
|
||||
users=[user],
|
||||
expected_statuses={
|
||||
user: {
|
||||
"exists": True,
|
||||
"deactivated": False,
|
||||
"org.matrix.expired": True,
|
||||
},
|
||||
},
|
||||
expected_failures=[],
|
||||
)
|
||||
|
||||
def _test_status(
|
||||
self,
|
||||
users: Optional[List[str]],
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
from twisted.test.proto_helpers import MemoryReactor
|
||||
|
||||
import synapse.rest.admin
|
||||
from synapse.rest.client import login, room, shared_rooms
|
||||
from synapse.rest.client import login, mutual_rooms, room
|
||||
from synapse.server import HomeServer
|
||||
from synapse.util import Clock
|
||||
|
||||
@@ -22,16 +22,16 @@ from tests import unittest
|
||||
from tests.server import FakeChannel
|
||||
|
||||
|
||||
class UserSharedRoomsTest(unittest.HomeserverTestCase):
|
||||
class UserMutualRoomsTest(unittest.HomeserverTestCase):
|
||||
"""
|
||||
Tests the UserSharedRoomsServlet.
|
||||
Tests the UserMutualRoomsServlet.
|
||||
"""
|
||||
|
||||
servlets = [
|
||||
login.register_servlets,
|
||||
synapse.rest.admin.register_servlets_for_client_rest_resource,
|
||||
room.register_servlets,
|
||||
shared_rooms.register_servlets,
|
||||
mutual_rooms.register_servlets,
|
||||
]
|
||||
|
||||
def make_homeserver(self, reactor: MemoryReactor, clock: Clock) -> HomeServer:
|
||||
@@ -43,10 +43,10 @@ class UserSharedRoomsTest(unittest.HomeserverTestCase):
|
||||
self.store = hs.get_datastores().main
|
||||
self.handler = hs.get_user_directory_handler()
|
||||
|
||||
def _get_shared_rooms(self, token: str, other_user: str) -> FakeChannel:
|
||||
def _get_mutual_rooms(self, token: str, other_user: str) -> FakeChannel:
|
||||
return self.make_request(
|
||||
"GET",
|
||||
"/_matrix/client/unstable/uk.half-shot.msc2666/user/shared_rooms/%s"
|
||||
"/_matrix/client/unstable/uk.half-shot.msc2666/user/mutual_rooms/%s"
|
||||
% other_user,
|
||||
access_token=token,
|
||||
)
|
||||
@@ -56,14 +56,14 @@ class UserSharedRoomsTest(unittest.HomeserverTestCase):
|
||||
A room should show up in the shared list of rooms between two users
|
||||
if it is public.
|
||||
"""
|
||||
self._check_shared_rooms_with(room_one_is_public=True, room_two_is_public=True)
|
||||
self._check_mutual_rooms_with(room_one_is_public=True, room_two_is_public=True)
|
||||
|
||||
def test_shared_room_list_private(self) -> None:
|
||||
"""
|
||||
A room should show up in the shared list of rooms between two users
|
||||
if it is private.
|
||||
"""
|
||||
self._check_shared_rooms_with(
|
||||
self._check_mutual_rooms_with(
|
||||
room_one_is_public=False, room_two_is_public=False
|
||||
)
|
||||
|
||||
@@ -72,9 +72,9 @@ class UserSharedRoomsTest(unittest.HomeserverTestCase):
|
||||
The shared room list between two users should contain both public and private
|
||||
rooms.
|
||||
"""
|
||||
self._check_shared_rooms_with(room_one_is_public=True, room_two_is_public=False)
|
||||
self._check_mutual_rooms_with(room_one_is_public=True, room_two_is_public=False)
|
||||
|
||||
def _check_shared_rooms_with(
|
||||
def _check_mutual_rooms_with(
|
||||
self, room_one_is_public: bool, room_two_is_public: bool
|
||||
) -> None:
|
||||
"""Checks that shared public or private rooms between two users appear in
|
||||
@@ -94,7 +94,7 @@ class UserSharedRoomsTest(unittest.HomeserverTestCase):
|
||||
|
||||
# Check shared rooms from user1's perspective.
|
||||
# We should see the one room in common
|
||||
channel = self._get_shared_rooms(u1_token, u2)
|
||||
channel = self._get_mutual_rooms(u1_token, u2)
|
||||
self.assertEqual(200, channel.code, channel.result)
|
||||
self.assertEqual(len(channel.json_body["joined"]), 1)
|
||||
self.assertEqual(channel.json_body["joined"][0], room_id_one)
|
||||
@@ -107,7 +107,7 @@ class UserSharedRoomsTest(unittest.HomeserverTestCase):
|
||||
self.helper.join(room_id_two, user=u2, tok=u2_token)
|
||||
|
||||
# Check shared rooms again. We should now see both rooms.
|
||||
channel = self._get_shared_rooms(u1_token, u2)
|
||||
channel = self._get_mutual_rooms(u1_token, u2)
|
||||
self.assertEqual(200, channel.code, channel.result)
|
||||
self.assertEqual(len(channel.json_body["joined"]), 2)
|
||||
for room_id_id in channel.json_body["joined"]:
|
||||
@@ -128,7 +128,7 @@ class UserSharedRoomsTest(unittest.HomeserverTestCase):
|
||||
self.helper.join(room, user=u2, tok=u2_token)
|
||||
|
||||
# Assert user directory is not empty
|
||||
channel = self._get_shared_rooms(u1_token, u2)
|
||||
channel = self._get_mutual_rooms(u1_token, u2)
|
||||
self.assertEqual(200, channel.code, channel.result)
|
||||
self.assertEqual(len(channel.json_body["joined"]), 1)
|
||||
self.assertEqual(channel.json_body["joined"][0], room)
|
||||
@@ -136,11 +136,11 @@ class UserSharedRoomsTest(unittest.HomeserverTestCase):
|
||||
self.helper.leave(room, user=u1, tok=u1_token)
|
||||
|
||||
# Check user1's view of shared rooms with user2
|
||||
channel = self._get_shared_rooms(u1_token, u2)
|
||||
channel = self._get_mutual_rooms(u1_token, u2)
|
||||
self.assertEqual(200, channel.code, channel.result)
|
||||
self.assertEqual(len(channel.json_body["joined"]), 0)
|
||||
|
||||
# Check user2's view of shared rooms with user1
|
||||
channel = self._get_shared_rooms(u2_token, u1)
|
||||
channel = self._get_mutual_rooms(u2_token, u1)
|
||||
self.assertEqual(200, channel.code, channel.result)
|
||||
self.assertEqual(len(channel.json_body["joined"]), 0)
|
||||
46
tests/storage/test_unsafe_locale.py
Normal file
46
tests/storage/test_unsafe_locale.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# Copyright 2022 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 unittest.mock import MagicMock, patch
|
||||
|
||||
from synapse.storage.database import make_conn
|
||||
from synapse.storage.engines._base import IncorrectDatabaseSetup
|
||||
|
||||
from tests.unittest import HomeserverTestCase
|
||||
from tests.utils import USE_POSTGRES_FOR_TESTS
|
||||
|
||||
|
||||
class UnsafeLocaleTest(HomeserverTestCase):
|
||||
if not USE_POSTGRES_FOR_TESTS:
|
||||
skip = "Requires Postgres"
|
||||
|
||||
@patch("synapse.storage.engines.postgres.PostgresEngine.get_db_locale")
|
||||
def test_unsafe_locale(self, mock_db_locale: MagicMock) -> None:
|
||||
mock_db_locale.return_value = ("B", "B")
|
||||
database = self.hs.get_datastores().databases[0]
|
||||
|
||||
db_conn = make_conn(database._database_config, database.engine, "test_unsafe")
|
||||
with self.assertRaises(IncorrectDatabaseSetup):
|
||||
database.engine.check_database(db_conn)
|
||||
with self.assertRaises(IncorrectDatabaseSetup):
|
||||
database.engine.check_new_database(db_conn)
|
||||
db_conn.close()
|
||||
|
||||
def test_safe_locale(self) -> None:
|
||||
database = self.hs.get_datastores().databases[0]
|
||||
|
||||
db_conn = make_conn(database._database_config, database.engine, "test_unsafe")
|
||||
with db_conn.cursor() as txn:
|
||||
res = database.engine.get_db_locale(txn)
|
||||
self.assertEqual(res, ("C", "C"))
|
||||
db_conn.close()
|
||||
Reference in New Issue
Block a user