Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f813e2ef48 | |||
| 872ea2f4de | |||
| 386e72a22d | |||
| c6987f65fe | |||
| 1469fed0e3 | |||
| 6c82b3759f | |||
| 94f239d911 | |||
| 673970bb5a | |||
| cb76892c7d | |||
| cd02bfc026 | |||
| 5f06488418 | |||
| 278b530875 | |||
| b7a7ff6ee3 | |||
| 1d45ad8b2a | |||
| d24346f530 | |||
| 1433b5d5b6 | |||
| fab495a9e1 | |||
| cacda2d1f5 | |||
| 755bfeee3a | |||
| da2c93d4b6 | |||
| 09c602b558 | |||
| 70b3396506 | |||
| 3841900aaa | |||
| 0b7830e457 | |||
| 695a85d1bc | |||
| fe50738e59 | |||
| 04d7f56f53 |
@@ -8,4 +8,11 @@
|
||||
# E203: whitespace before ':' (which is contrary to pep8?)
|
||||
# E731: do not assign a lambda expression, use a def
|
||||
# E501: Line too long (black enforces this for us)
|
||||
ignore=W503,W504,E203,E731,E501
|
||||
#
|
||||
# flake8-bugbear runs extra checks. Its error codes are described at
|
||||
# https://github.com/PyCQA/flake8-bugbear#list-of-warnings
|
||||
# B019: Use of functools.lru_cache or functools.cache on methods can lead to memory leaks
|
||||
# B023: Functions defined inside a loop must not use variables redefined in the loop
|
||||
# B024: Abstract base class with no abstract method.
|
||||
|
||||
ignore=W503,W504,E203,E731,E501,B019,B023,B024
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup mdbook
|
||||
uses: peaceiris/actions-mdbook@4b5ef36b314c2599664ca107bb8c02412548d79d # v1.1.14
|
||||
uses: peaceiris/actions-mdbook@adeb05db28a0c0004681db83893d56c0388ea9ea # v1.2.0
|
||||
with:
|
||||
mdbook-version: '0.4.17'
|
||||
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
|
||||
# Deploy to the target directory.
|
||||
- name: Deploy to gh pages
|
||||
uses: peaceiris/actions-gh-pages@068dc23d9710f1ba62e86896f84735d869951305 # v3.8.0
|
||||
uses: peaceiris/actions-gh-pages@de7ea6f8efb354206b205ef54722213d99067935 # v3.9.0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./book
|
||||
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-10.15]
|
||||
os: [ubuntu-20.04, macos-11]
|
||||
arch: [x86_64, aarch64]
|
||||
# is_pr is a flag used to exclude certain jobs from the matrix on PRs.
|
||||
# It is not read by the rest of the workflow.
|
||||
@@ -109,9 +109,9 @@ jobs:
|
||||
exclude:
|
||||
# Don't build macos wheels on PR CI.
|
||||
- is_pr: true
|
||||
os: "macos-10.15"
|
||||
os: "macos-11"
|
||||
# Don't build aarch64 wheels on mac.
|
||||
- os: "macos-10.15"
|
||||
- os: "macos-11"
|
||||
arch: aarch64
|
||||
# Don't build aarch64 wheels on PR CI.
|
||||
- is_pr: true
|
||||
|
||||
@@ -5,24 +5,11 @@ on:
|
||||
types: [ opened ]
|
||||
|
||||
jobs:
|
||||
add_new_issues:
|
||||
name: Add new issues to the triage board
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
id: add_to_project
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAIB0Bs4AFDdZ"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
triage:
|
||||
uses: matrix-org/backend-meta/.github/workflows/triage-incoming.yml@v1
|
||||
with:
|
||||
project_id: 'PVT_kwDOAIB0Bs4AFDdZ'
|
||||
content_id: ${{ github.event.issue.node_id }}
|
||||
secrets:
|
||||
github_access_token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
|
||||
Generated
+8
-8
@@ -13,9 +13,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.65"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
|
||||
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
@@ -323,18 +323,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.145"
|
||||
version = "1.0.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
|
||||
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.145"
|
||||
version = "1.0.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
|
||||
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -343,9 +343,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.86"
|
||||
version = "1.0.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074"
|
||||
checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Fix a long-standing bug where the `update_synapse_database` script could not be run with multiple databases. Contributed by @thefinn93 @ Beeper.
|
||||
@@ -0,0 +1 @@
|
||||
Improve aesthetics of HTML templates. Note that these changes do not retroactively apply to templates which have been [customised](https://matrix-org.github.io/synapse/latest/templates.html#templates) by server admins.
|
||||
@@ -0,0 +1 @@
|
||||
Fix a long-standing bug where Synapse would count codepoints instead of bytes when validating the size of some fields.
|
||||
@@ -0,0 +1 @@
|
||||
Bump flake8-bugbear from 21.3.2 to 22.9.23.
|
||||
@@ -0,0 +1 @@
|
||||
Fix a long-standing bug where Synapse would accidentally include extra information in the response to [`PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`](https://spec.matrix.org/v1.4/server-server-api/#put_matrixfederationv2inviteroomideventid).
|
||||
@@ -0,0 +1 @@
|
||||
Correct the name of the config option [`encryption_enabled_by_default_for_room_type`](https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html#encryption_enabled_by_default_for_room_type).
|
||||
@@ -0,0 +1 @@
|
||||
Bump types-opentracing from 2.4.7 to 2.4.10.
|
||||
@@ -0,0 +1 @@
|
||||
Update docstrings of `SynapseError` and `FederationError` to bettter describe what they are used for and the effects of using them are.
|
||||
@@ -0,0 +1 @@
|
||||
Show erasure status when listing users in the Admin API.
|
||||
@@ -0,0 +1 @@
|
||||
Add initial power level event to batch of bulk persisted events when creating a new room.
|
||||
@@ -0,0 +1 @@
|
||||
Refactor `/key/` endpoints to use `RestServlet` classes.
|
||||
@@ -0,0 +1 @@
|
||||
Switch to using the `matrix-org/backend-meta` version of `triage-incoming` for new issues in CI.
|
||||
@@ -0,0 +1 @@
|
||||
Build wheels on macos 11, not 10.15.
|
||||
@@ -0,0 +1,2 @@
|
||||
Fix a bug introduced in Synapse 1.60.0 which caused an error to be logged when Synapse received a SIGHUP signal, and debug logging was enabled.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Add debugging to help diagnose lost device-list-update.
|
||||
@@ -0,0 +1 @@
|
||||
Bump pysaml2 from 7.1.2 to 7.2.1.
|
||||
@@ -0,0 +1 @@
|
||||
Bump jinja2 from 3.0.3 to 3.1.2.
|
||||
@@ -0,0 +1 @@
|
||||
Bump types-requests from 2.28.11 to 2.28.11.2.
|
||||
@@ -0,0 +1 @@
|
||||
Bump setuptools-rust from 1.5.1 to 1.5.2.
|
||||
@@ -0,0 +1 @@
|
||||
Bump prometheus-client from 0.14.0 to 0.15.0.
|
||||
@@ -0,0 +1 @@
|
||||
Bump peaceiris/actions-mdbook from 1.1.14 to 1.2.0.
|
||||
@@ -0,0 +1 @@
|
||||
Bump peaceiris/actions-gh-pages from 3.8.0 to 3.9.0.
|
||||
@@ -0,0 +1 @@
|
||||
Bump serde from 1.0.145 to 1.0.147.
|
||||
@@ -0,0 +1 @@
|
||||
Bump anyhow from 1.0.65 to 1.0.66.
|
||||
@@ -0,0 +1 @@
|
||||
Bump serde_json from 1.0.86 to 1.0.87.
|
||||
@@ -37,6 +37,7 @@ It returns a JSON body like the following:
|
||||
"is_guest": 0,
|
||||
"admin": 0,
|
||||
"deactivated": 0,
|
||||
"erased": false,
|
||||
"shadow_banned": 0,
|
||||
"creation_ts": 1560432506,
|
||||
"appservice_id": null,
|
||||
@@ -167,6 +168,7 @@ A response body like the following is returned:
|
||||
"admin": 0,
|
||||
"user_type": null,
|
||||
"deactivated": 0,
|
||||
"erased": false,
|
||||
"shadow_banned": 0,
|
||||
"displayname": "<User One>",
|
||||
"avatar_url": null,
|
||||
@@ -177,6 +179,7 @@ A response body like the following is returned:
|
||||
"admin": 1,
|
||||
"user_type": null,
|
||||
"deactivated": 0,
|
||||
"erased": false,
|
||||
"shadow_banned": 0,
|
||||
"displayname": "<User Two>",
|
||||
"avatar_url": "<avatar_url>",
|
||||
@@ -247,6 +250,7 @@ The following fields are returned in the JSON response body:
|
||||
- `user_type` - string - Type of the user. Normal users are type `None`.
|
||||
This allows user type specific behaviour. There are also types `support` and `bot`.
|
||||
- `deactivated` - bool - Status if that user has been marked as deactivated.
|
||||
- `erased` - bool - Status if that user has been marked as erased.
|
||||
- `shadow_banned` - bool - Status if that user has been marked as shadow banned.
|
||||
- `displayname` - string - The user's display name if they have set one.
|
||||
- `avatar_url` - string - The user's avatar URL if they have set one.
|
||||
|
||||
@@ -3385,7 +3385,7 @@ push:
|
||||
Config options relating to rooms.
|
||||
|
||||
---
|
||||
### `encryption_enabled_by_default`
|
||||
### `encryption_enabled_by_default_for_room_type`
|
||||
|
||||
Controls whether locally-created rooms should be end-to-end encrypted by
|
||||
default.
|
||||
|
||||
Generated
+24
-24
@@ -260,7 +260,7 @@ pyflakes = ">=2.4.0,<2.5.0"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-bugbear"
|
||||
version = "21.3.2"
|
||||
version = "22.9.23"
|
||||
description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle."
|
||||
category = "dev"
|
||||
optional = false
|
||||
@@ -271,7 +271,7 @@ attrs = ">=19.2.0"
|
||||
flake8 = ">=3.0.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["black", "coverage", "hypothesis", "hypothesmith"]
|
||||
dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit"]
|
||||
|
||||
[[package]]
|
||||
name = "flake8-comprehensions"
|
||||
@@ -438,11 +438,11 @@ trio = ["async_generator", "trio"]
|
||||
|
||||
[[package]]
|
||||
name = "jinja2"
|
||||
version = "3.0.3"
|
||||
version = "3.1.2"
|
||||
description = "A very fast and expressive template engine."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
MarkupSafe = ">=2.0"
|
||||
@@ -710,7 +710,7 @@ test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock
|
||||
|
||||
[[package]]
|
||||
name = "prometheus-client"
|
||||
version = "0.14.0"
|
||||
version = "0.15.0"
|
||||
description = "Python client for the Prometheus monitoring system."
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -918,14 +918,14 @@ python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "pysaml2"
|
||||
version = "7.1.2"
|
||||
version = "7.2.1"
|
||||
description = "Python implementation of SAML Version 2 Standard"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = "<4,>=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
cryptography = ">=1.4"
|
||||
cryptography = ">=3.1"
|
||||
defusedxml = "*"
|
||||
importlib-resources = {version = "*", markers = "python_version < \"3.9\""}
|
||||
pyOpenSSL = "*"
|
||||
@@ -1120,7 +1120,7 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (
|
||||
|
||||
[[package]]
|
||||
name = "setuptools-rust"
|
||||
version = "1.5.1"
|
||||
version = "1.5.2"
|
||||
description = "Setuptools Rust extension plugin"
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -1426,7 +1426,7 @@ python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "types-opentracing"
|
||||
version = "2.4.7"
|
||||
version = "2.4.10"
|
||||
description = "Typing stubs for opentracing"
|
||||
category = "dev"
|
||||
optional = false
|
||||
@@ -1469,7 +1469,7 @@ python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "types-requests"
|
||||
version = "2.28.11"
|
||||
version = "2.28.11.2"
|
||||
description = "Typing stubs for requests"
|
||||
category = "dev"
|
||||
optional = false
|
||||
@@ -1826,8 +1826,8 @@ flake8 = [
|
||||
{file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
|
||||
]
|
||||
flake8-bugbear = [
|
||||
{file = "flake8-bugbear-21.3.2.tar.gz", hash = "sha256:cadce434ceef96463b45a7c3000f23527c04ea4b531d16c7ac8886051f516ca0"},
|
||||
{file = "flake8_bugbear-21.3.2-py36.py37.py38-none-any.whl", hash = "sha256:5d6ccb0c0676c738a6e066b4d50589c408dcc1c5bf1d73b464b18b73cd6c05c2"},
|
||||
{file = "flake8-bugbear-22.9.23.tar.gz", hash = "sha256:17b9623325e6e0dcdcc80ed9e4aa811287fcc81d7e03313b8736ea5733759937"},
|
||||
{file = "flake8_bugbear-22.9.23-py3-none-any.whl", hash = "sha256:cd2779b2b7ada212d7a322814a1e5651f1868ab0d3f24cc9da66169ab8fda474"},
|
||||
]
|
||||
flake8-comprehensions = [
|
||||
{file = "flake8-comprehensions-3.8.0.tar.gz", hash = "sha256:8e108707637b1d13734f38e03435984f6b7854fa6b5a4e34f93e69534be8e521"},
|
||||
@@ -1999,8 +1999,8 @@ jeepney = [
|
||||
{file = "jeepney-0.7.1.tar.gz", hash = "sha256:fa9e232dfa0c498bd0b8a3a73b8d8a31978304dcef0515adc859d4e096f96f4f"},
|
||||
]
|
||||
jinja2 = [
|
||||
{file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"},
|
||||
{file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"},
|
||||
{file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
|
||||
{file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
|
||||
]
|
||||
jsonschema = [
|
||||
{file = "jsonschema-4.16.0-py3-none-any.whl", hash = "sha256:9e74b8f9738d6a946d70705dc692b74b5429cd0960d58e79ffecfc43b2221eb9"},
|
||||
@@ -2301,8 +2301,8 @@ platformdirs = [
|
||||
{file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"},
|
||||
]
|
||||
prometheus-client = [
|
||||
{file = "prometheus_client-0.14.0-py3-none-any.whl", hash = "sha256:f4aba3fdd1735852049f537c1f0ab177159b7ab76f271ecc4d2f45aa2a1d01f2"},
|
||||
{file = "prometheus_client-0.14.0.tar.gz", hash = "sha256:8f7a922dd5455ad524b6ba212ce8eb2b4b05e073f4ec7218287f88b1cac34750"},
|
||||
{file = "prometheus_client-0.15.0-py3-none-any.whl", hash = "sha256:db7c05cbd13a0f79975592d112320f2605a325969b270a94b71dcabc47b931d2"},
|
||||
{file = "prometheus_client-0.15.0.tar.gz", hash = "sha256:be26aa452490cfcf6da953f9436e95a9f2b4d578ca80094b4458930e5f584ab1"},
|
||||
]
|
||||
psycopg2 = [
|
||||
{file = "psycopg2-2.9.4-cp310-cp310-win32.whl", hash = "sha256:8de6a9fc5f42fa52f559e65120dcd7502394692490c98fed1221acf0819d7797"},
|
||||
@@ -2445,8 +2445,8 @@ pyrsistent = [
|
||||
{file = "pyrsistent-0.18.1.tar.gz", hash = "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96"},
|
||||
]
|
||||
pysaml2 = [
|
||||
{file = "pysaml2-7.1.2-py2.py3-none-any.whl", hash = "sha256:d915961aaa4d4d97d952b30fe5d18d64cf053465acf3e38d8090b36c5ff08325"},
|
||||
{file = "pysaml2-7.1.2.tar.gz", hash = "sha256:1ec94442306511b93fe7a5710f224e05e0aba948682d506614d1e04f3232f827"},
|
||||
{file = "pysaml2-7.2.1-py2.py3-none-any.whl", hash = "sha256:2ca155f4eeb1471b247a7b0cc79ccfd5780046d33d0b201e1199a00698dce795"},
|
||||
{file = "pysaml2-7.2.1.tar.gz", hash = "sha256:f40f9576dce9afef156469179277ffeeca36829248be333252af0517a26d0b1f"},
|
||||
]
|
||||
python-dateutil = [
|
||||
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
|
||||
@@ -2539,8 +2539,8 @@ setuptools = [
|
||||
{file = "setuptools-65.3.0.tar.gz", hash = "sha256:7732871f4f7fa58fb6bdcaeadb0161b2bd046c85905dbaa066bdcbcc81953b57"},
|
||||
]
|
||||
setuptools-rust = [
|
||||
{file = "setuptools-rust-1.5.1.tar.gz", hash = "sha256:0e05e456645d59429cb1021370aede73c0760e9360bbfdaaefb5bced530eb9d7"},
|
||||
{file = "setuptools_rust-1.5.1-py3-none-any.whl", hash = "sha256:306b236ff3aa5229180e58292610d0c2c51bb488191122d2fc559ae4caeb7d5e"},
|
||||
{file = "setuptools-rust-1.5.2.tar.gz", hash = "sha256:d8daccb14dc0eae1b6b6eb3ecef79675bd37b4065369f79c35393dd5c55652c7"},
|
||||
{file = "setuptools_rust-1.5.2-py3-none-any.whl", hash = "sha256:8eb45851e34288f2296cd5ab9e924535ac1757318b730a13fe6836867843f206"},
|
||||
]
|
||||
signedjson = [
|
||||
{file = "signedjson-1.1.4-py3-none-any.whl", hash = "sha256:45569ec54241c65d2403fe3faf7169be5322547706a231e884ca2b427f23d228"},
|
||||
@@ -2767,8 +2767,8 @@ types-jsonschema = [
|
||||
{file = "types_jsonschema-4.4.6-py3-none-any.whl", hash = "sha256:1db9031ca49a8444d01bd2ce8cf2f89318382b04610953b108321e6f8fb03390"},
|
||||
]
|
||||
types-opentracing = [
|
||||
{file = "types-opentracing-2.4.7.tar.gz", hash = "sha256:be60e9618355aa892571ace002e6b353702538b1c0dc4fbc1c921219d6658830"},
|
||||
{file = "types_opentracing-2.4.7-py3-none-any.whl", hash = "sha256:861fb8103b07cf717f501dd400cb274ca9992552314d4d6c7a824b11a215e512"},
|
||||
{file = "types-opentracing-2.4.10.tar.gz", hash = "sha256:6101414f3b6d3b9c10f1c510a261e8439b6c8d67c723d5c2872084697b4580a7"},
|
||||
{file = "types_opentracing-2.4.10-py3-none-any.whl", hash = "sha256:66d9cfbbdc4a6f8ca8189a15ad26f0fe41cee84c07057759c5d194e2505b84c2"},
|
||||
]
|
||||
types-pillow = [
|
||||
{file = "types-Pillow-9.2.2.1.tar.gz", hash = "sha256:85c139e06e1c46ec5f9c634d5c54a156b0958d5d0e8be024ed353db0c804b426"},
|
||||
@@ -2787,8 +2787,8 @@ types-PyYAML = [
|
||||
{file = "types_PyYAML-6.0.12-py3-none-any.whl", hash = "sha256:29228db9f82df4f1b7febee06bbfb601677882e98a3da98132e31c6874163e15"},
|
||||
]
|
||||
types-requests = [
|
||||
{file = "types-requests-2.28.11.tar.gz", hash = "sha256:7ee827eb8ce611b02b5117cfec5da6455365b6a575f5e3ff19f655ba603e6b4e"},
|
||||
{file = "types_requests-2.28.11-py3-none-any.whl", hash = "sha256:af5f55e803cabcfb836dad752bd6d8a0fc8ef1cd84243061c0e27dee04ccf4fd"},
|
||||
{file = "types-requests-2.28.11.2.tar.gz", hash = "sha256:fdcd7bd148139fb8eef72cf4a41ac7273872cad9e6ada14b11ff5dfdeee60ed3"},
|
||||
{file = "types_requests-2.28.11.2-py3-none-any.whl", hash = "sha256:14941f8023a80b16441b3b46caffcbfce5265fd14555844d6029697824b5a2ef"},
|
||||
]
|
||||
types-setuptools = [
|
||||
{file = "types-setuptools-65.5.0.1.tar.gz", hash = "sha256:5b297081c8f1fbd992cd8b305a97ed96ee6ffc765e9115124029597dd10b8a71"},
|
||||
|
||||
+3
-3
@@ -20,15 +20,15 @@ crate-type = ["lib", "cdylib"]
|
||||
name = "synapse.synapse_rust"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.63"
|
||||
anyhow = "1.0.66"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4.17"
|
||||
pyo3 = { version = "0.17.1", features = ["extension-module", "macros", "anyhow", "abi3", "abi3-py37"] }
|
||||
pyo3-log = "0.7.0"
|
||||
pythonize = "0.17.0"
|
||||
regex = "1.6.0"
|
||||
serde = { version = "1.0.144", features = ["derive"] }
|
||||
serde_json = "1.0.85"
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = "1.0.87"
|
||||
|
||||
[build-dependencies]
|
||||
blake2 = "0.10.4"
|
||||
|
||||
Executable → Regular
-8
@@ -15,7 +15,6 @@
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
from typing import cast
|
||||
|
||||
import yaml
|
||||
@@ -100,13 +99,6 @@ def main() -> None:
|
||||
# Load, process and sanity-check the config.
|
||||
hs_config = yaml.safe_load(args.database_config)
|
||||
|
||||
if "database" not in hs_config and "databases" not in hs_config:
|
||||
sys.stderr.write(
|
||||
"The configuration file must have a 'database' or 'databases' section. "
|
||||
"See https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html#database"
|
||||
)
|
||||
sys.exit(4)
|
||||
|
||||
config = HomeServerConfig()
|
||||
config.parse_config_dict(hs_config, "", "")
|
||||
|
||||
|
||||
+21
-3
@@ -155,7 +155,13 @@ class RedirectException(CodeMessageException):
|
||||
|
||||
class SynapseError(CodeMessageException):
|
||||
"""A base exception type for matrix errors which have an errcode and error
|
||||
message (as well as an HTTP status code).
|
||||
message (as well as an HTTP status code). These often bubble all the way up to the
|
||||
client API response so the error code and status often reach the client directly as
|
||||
defined here. If the error doesn't make sense to present to a client, then it
|
||||
probably shouldn't be a `SynapseError`. For example, if we contact another
|
||||
homeserver over federation, we shouldn't automatically ferry response errors back to
|
||||
the client on our end (a 500 from a remote server does not make sense to a client
|
||||
when our server did not experience a 500).
|
||||
|
||||
Attributes:
|
||||
errcode: Matrix error code e.g 'M_FORBIDDEN'
|
||||
@@ -600,8 +606,20 @@ def cs_error(msg: str, code: str = Codes.UNKNOWN, **kwargs: Any) -> "JsonDict":
|
||||
|
||||
|
||||
class FederationError(RuntimeError):
|
||||
"""This class is used to inform remote homeservers about erroneous
|
||||
PDUs they sent us.
|
||||
"""
|
||||
Raised when we process an erroneous PDU.
|
||||
|
||||
There are two kinds of scenarios where this exception can be raised:
|
||||
|
||||
1. We may pull an invalid PDU from a remote homeserver (e.g. during backfill). We
|
||||
raise this exception to signal an error to the rest of the application.
|
||||
2. We may be pushed an invalid PDU as part of a `/send` transaction from a remote
|
||||
homeserver. We raise so that we can respond to the transaction and include the
|
||||
error string in the "PDU Processing Result". The message which will likely be
|
||||
ignored by the remote homeserver and is not machine parse-able since it's just a
|
||||
string.
|
||||
|
||||
TODO: In the future, we should split these usage scenarios into their own error types.
|
||||
|
||||
FATAL: The remote server could not interpret the source event.
|
||||
(e.g., it was missing a required field)
|
||||
|
||||
@@ -91,12 +91,11 @@ ROOM_EVENT_FILTER_SCHEMA = {
|
||||
"lazy_load_members": {"type": "boolean"},
|
||||
"include_redundant_members": {"type": "boolean"},
|
||||
"unread_thread_notifications": {"type": "boolean"},
|
||||
"org.matrix.msc3773.unread_thread_notifications": {"type": "boolean"},
|
||||
# Include or exclude events with the provided labels.
|
||||
# cf https://github.com/matrix-org/matrix-doc/pull/2326
|
||||
"org.matrix.labels": {"type": "array", "items": {"type": "string"}},
|
||||
"org.matrix.not_labels": {"type": "array", "items": {"type": "string"}},
|
||||
# MSC3440, filtering by event relations.
|
||||
# Filtering by event relations, deprecated.
|
||||
"related_by_senders": {"type": "array", "items": {"type": "string"}},
|
||||
"related_by_rel_types": {"type": "array", "items": {"type": "string"}},
|
||||
},
|
||||
@@ -318,13 +317,6 @@ class Filter:
|
||||
self.unread_thread_notifications: bool = filter_json.get(
|
||||
"unread_thread_notifications", False
|
||||
)
|
||||
if (
|
||||
not self.unread_thread_notifications
|
||||
and hs.config.experimental.msc3773_enabled
|
||||
):
|
||||
self.unread_thread_notifications = filter_json.get(
|
||||
"org.matrix.msc3773.unread_thread_notifications", False
|
||||
)
|
||||
|
||||
self.types = filter_json.get("types", None)
|
||||
self.not_types = filter_json.get("not_types", [])
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ FEDERATION_V1_PREFIX = FEDERATION_PREFIX + "/v1"
|
||||
FEDERATION_V2_PREFIX = FEDERATION_PREFIX + "/v2"
|
||||
FEDERATION_UNSTABLE_PREFIX = FEDERATION_PREFIX + "/unstable"
|
||||
STATIC_PREFIX = "/_matrix/static"
|
||||
SERVER_KEY_V2_PREFIX = "/_matrix/key/v2"
|
||||
SERVER_KEY_PREFIX = "/_matrix/key"
|
||||
MEDIA_R0_PREFIX = "/_matrix/media/r0"
|
||||
MEDIA_V3_PREFIX = "/_matrix/media/v3"
|
||||
LEGACY_MEDIA_PREFIX = "/_matrix/media/v1"
|
||||
|
||||
@@ -558,7 +558,7 @@ def reload_cache_config(config: HomeServerConfig) -> None:
|
||||
logger.warning(f)
|
||||
else:
|
||||
logger.debug(
|
||||
"New cache config. Was:\n %s\nNow:\n",
|
||||
"New cache config. Was:\n %s\nNow:\n %s",
|
||||
previous_cache_config.__dict__,
|
||||
config.caches.__dict__,
|
||||
)
|
||||
|
||||
@@ -28,7 +28,7 @@ from synapse.api.urls import (
|
||||
LEGACY_MEDIA_PREFIX,
|
||||
MEDIA_R0_PREFIX,
|
||||
MEDIA_V3_PREFIX,
|
||||
SERVER_KEY_V2_PREFIX,
|
||||
SERVER_KEY_PREFIX,
|
||||
)
|
||||
from synapse.app import _base
|
||||
from synapse.app._base import (
|
||||
@@ -89,7 +89,7 @@ from synapse.rest.client.register import (
|
||||
RegistrationTokenValidityRestServlet,
|
||||
)
|
||||
from synapse.rest.health import HealthResource
|
||||
from synapse.rest.key.v2 import KeyApiV2Resource
|
||||
from synapse.rest.key.v2 import KeyResource
|
||||
from synapse.rest.synapse.client import build_synapse_client_resource_tree
|
||||
from synapse.rest.well_known import well_known_resource
|
||||
from synapse.server import HomeServer
|
||||
@@ -325,13 +325,13 @@ class GenericWorkerServer(HomeServer):
|
||||
|
||||
presence.register_servlets(self, resource)
|
||||
|
||||
resources.update({CLIENT_API_PREFIX: resource})
|
||||
resources[CLIENT_API_PREFIX] = resource
|
||||
|
||||
resources.update(build_synapse_client_resource_tree(self))
|
||||
resources.update({"/.well-known": well_known_resource(self)})
|
||||
resources["/.well-known"] = well_known_resource(self)
|
||||
|
||||
elif name == "federation":
|
||||
resources.update({FEDERATION_PREFIX: TransportLayerServer(self)})
|
||||
resources[FEDERATION_PREFIX] = TransportLayerServer(self)
|
||||
elif name == "media":
|
||||
if self.config.media.can_load_media_repo:
|
||||
media_repo = self.get_media_repository_resource()
|
||||
@@ -359,16 +359,12 @@ class GenericWorkerServer(HomeServer):
|
||||
# Only load the openid resource separately if federation resource
|
||||
# is not specified since federation resource includes openid
|
||||
# resource.
|
||||
resources.update(
|
||||
{
|
||||
FEDERATION_PREFIX: TransportLayerServer(
|
||||
self, servlet_groups=["openid"]
|
||||
)
|
||||
}
|
||||
resources[FEDERATION_PREFIX] = TransportLayerServer(
|
||||
self, servlet_groups=["openid"]
|
||||
)
|
||||
|
||||
if name in ["keys", "federation"]:
|
||||
resources[SERVER_KEY_V2_PREFIX] = KeyApiV2Resource(self)
|
||||
resources[SERVER_KEY_PREFIX] = KeyResource(self)
|
||||
|
||||
if name == "replication":
|
||||
resources[REPLICATION_PREFIX] = ReplicationRestResource(self)
|
||||
|
||||
@@ -31,7 +31,7 @@ from synapse.api.urls import (
|
||||
LEGACY_MEDIA_PREFIX,
|
||||
MEDIA_R0_PREFIX,
|
||||
MEDIA_V3_PREFIX,
|
||||
SERVER_KEY_V2_PREFIX,
|
||||
SERVER_KEY_PREFIX,
|
||||
STATIC_PREFIX,
|
||||
)
|
||||
from synapse.app import _base
|
||||
@@ -60,7 +60,7 @@ from synapse.replication.http import REPLICATION_PREFIX, ReplicationRestResource
|
||||
from synapse.rest import ClientRestResource
|
||||
from synapse.rest.admin import AdminRestResource
|
||||
from synapse.rest.health import HealthResource
|
||||
from synapse.rest.key.v2 import KeyApiV2Resource
|
||||
from synapse.rest.key.v2 import KeyResource
|
||||
from synapse.rest.synapse.client import build_synapse_client_resource_tree
|
||||
from synapse.rest.well_known import well_known_resource
|
||||
from synapse.server import HomeServer
|
||||
@@ -215,30 +215,22 @@ class SynapseHomeServer(HomeServer):
|
||||
consent_resource: Resource = ConsentResource(self)
|
||||
if compress:
|
||||
consent_resource = gz_wrap(consent_resource)
|
||||
resources.update({"/_matrix/consent": consent_resource})
|
||||
resources["/_matrix/consent"] = consent_resource
|
||||
|
||||
if name == "federation":
|
||||
federation_resource: Resource = TransportLayerServer(self)
|
||||
if compress:
|
||||
federation_resource = gz_wrap(federation_resource)
|
||||
resources.update({FEDERATION_PREFIX: federation_resource})
|
||||
resources[FEDERATION_PREFIX] = federation_resource
|
||||
|
||||
if name == "openid":
|
||||
resources.update(
|
||||
{
|
||||
FEDERATION_PREFIX: TransportLayerServer(
|
||||
self, servlet_groups=["openid"]
|
||||
)
|
||||
}
|
||||
resources[FEDERATION_PREFIX] = TransportLayerServer(
|
||||
self, servlet_groups=["openid"]
|
||||
)
|
||||
|
||||
if name in ["static", "client"]:
|
||||
resources.update(
|
||||
{
|
||||
STATIC_PREFIX: StaticResource(
|
||||
os.path.join(os.path.dirname(synapse.__file__), "static")
|
||||
)
|
||||
}
|
||||
resources[STATIC_PREFIX] = StaticResource(
|
||||
os.path.join(os.path.dirname(synapse.__file__), "static")
|
||||
)
|
||||
|
||||
if name in ["media", "federation", "client"]:
|
||||
@@ -257,7 +249,7 @@ class SynapseHomeServer(HomeServer):
|
||||
)
|
||||
|
||||
if name in ["keys", "federation"]:
|
||||
resources[SERVER_KEY_V2_PREFIX] = KeyApiV2Resource(self)
|
||||
resources[SERVER_KEY_PREFIX] = KeyResource(self)
|
||||
|
||||
if name == "metrics" and self.config.metrics.enable_metrics:
|
||||
metrics_resource: Resource = MetricsResource(RegistryProxy)
|
||||
|
||||
@@ -95,9 +95,6 @@ class ExperimentalConfig(Config):
|
||||
# MSC2815 (allow room moderators to view redacted event content)
|
||||
self.msc2815_enabled: bool = experimental.get("msc2815_enabled", False)
|
||||
|
||||
# MSC3773: Thread notifications
|
||||
self.msc3773_enabled: bool = experimental.get("msc3773_enabled", False)
|
||||
|
||||
# MSC3848: Introduce errcodes for specific event sending failures
|
||||
self.msc3848_enabled: bool = experimental.get("msc3848_enabled", False)
|
||||
|
||||
|
||||
@@ -342,15 +342,15 @@ def check_state_dependent_auth_rules(
|
||||
|
||||
|
||||
def _check_size_limits(event: "EventBase") -> None:
|
||||
if len(event.user_id) > 255:
|
||||
if len(event.user_id.encode("utf-8")) > 255:
|
||||
raise EventSizeError("'user_id' too large")
|
||||
if len(event.room_id) > 255:
|
||||
if len(event.room_id.encode("utf-8")) > 255:
|
||||
raise EventSizeError("'room_id' too large")
|
||||
if event.is_state() and len(event.state_key) > 255:
|
||||
if event.is_state() and len(event.state_key.encode("utf-8")) > 255:
|
||||
raise EventSizeError("'state_key' too large")
|
||||
if len(event.type) > 255:
|
||||
if len(event.type.encode("utf-8")) > 255:
|
||||
raise EventSizeError("'type' too large")
|
||||
if len(event.event_id) > 255:
|
||||
if len(event.event_id.encode("utf-8")) > 255:
|
||||
raise EventSizeError("'event_id' too large")
|
||||
if len(encode_canonical_json(event.get_pdu_json())) > MAX_PDU_SIZE:
|
||||
raise EventSizeError("event too large")
|
||||
|
||||
@@ -481,6 +481,14 @@ class FederationServer(FederationBase):
|
||||
pdu_results[pdu.event_id] = await process_pdu(pdu)
|
||||
|
||||
async def process_pdu(pdu: EventBase) -> JsonDict:
|
||||
"""
|
||||
Processes a pushed PDU sent to us via a `/send` transaction
|
||||
|
||||
Returns:
|
||||
JsonDict representing a "PDU Processing Result" that will be bundled up
|
||||
with the other processed PDU's in the `/send` transaction and sent back
|
||||
to remote homeserver.
|
||||
"""
|
||||
event_id = pdu.event_id
|
||||
with nested_logging_context(event_id):
|
||||
try:
|
||||
|
||||
@@ -499,6 +499,11 @@ class FederationV2InviteServlet(BaseFederationServerServlet):
|
||||
result = await self.handler.on_invite_request(
|
||||
origin, event, room_version_id=room_version
|
||||
)
|
||||
|
||||
# We only store invite_room_state for internal use, so remove it before
|
||||
# returning the event to the remote homeserver.
|
||||
result["event"].get("unsigned", {}).pop("invite_room_state", None)
|
||||
|
||||
return 200, result
|
||||
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ class AdminHandler:
|
||||
user_info_dict["avatar_url"] = profile.avatar_url
|
||||
user_info_dict["threepids"] = threepids
|
||||
user_info_dict["external_ids"] = external_ids
|
||||
user_info_dict["erased"] = await self.store.is_user_erased(user.to_string())
|
||||
|
||||
return user_info_dict
|
||||
|
||||
|
||||
@@ -1017,7 +1017,9 @@ class FederationHandler:
|
||||
|
||||
context = EventContext.for_outlier(self._storage_controllers)
|
||||
|
||||
await self._bulk_push_rule_evaluator.action_for_event_by_user(event, context)
|
||||
await self._bulk_push_rule_evaluator.action_for_events_by_user(
|
||||
[(event, context)]
|
||||
)
|
||||
try:
|
||||
await self._federation_event_handler.persist_events_and_notify(
|
||||
event.room_id, [(event, context)]
|
||||
|
||||
@@ -2171,8 +2171,8 @@ class FederationEventHandler:
|
||||
min_depth,
|
||||
)
|
||||
else:
|
||||
await self._bulk_push_rule_evaluator.action_for_event_by_user(
|
||||
event, context
|
||||
await self._bulk_push_rule_evaluator.action_for_events_by_user(
|
||||
[(event, context)]
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -1433,17 +1433,9 @@ class EventCreationHandler:
|
||||
a room that has been un-partial stated.
|
||||
"""
|
||||
|
||||
for event, context in events_and_context:
|
||||
# Skip push notification actions for historical messages
|
||||
# because we don't want to notify people about old history back in time.
|
||||
# The historical messages also do not have the proper `context.current_state_ids`
|
||||
# and `state_groups` because they have `prev_events` that aren't persisted yet
|
||||
# (historical messages persisted in reverse-chronological order).
|
||||
if not event.internal_metadata.is_historical():
|
||||
with opentracing.start_active_span("calculate_push_actions"):
|
||||
await self._bulk_push_rule_evaluator.action_for_event_by_user(
|
||||
event, context
|
||||
)
|
||||
await self._bulk_push_rule_evaluator.action_for_events_by_user(
|
||||
events_and_context
|
||||
)
|
||||
|
||||
try:
|
||||
# If we're a worker we need to hit out to the master.
|
||||
|
||||
+10
-29
@@ -1055,9 +1055,6 @@ class RoomCreationHandler:
|
||||
event_keys = {"room_id": room_id, "sender": creator_id, "state_key": ""}
|
||||
depth = 1
|
||||
|
||||
# the last event sent/persisted to the db
|
||||
last_sent_event_id: Optional[str] = None
|
||||
|
||||
# the most recently created event
|
||||
prev_event: List[str] = []
|
||||
# a map of event types, state keys -> event_ids. We collect these mappings this as events are
|
||||
@@ -1102,26 +1099,6 @@ class RoomCreationHandler:
|
||||
|
||||
return new_event, new_context
|
||||
|
||||
async def send(
|
||||
event: EventBase,
|
||||
context: synapse.events.snapshot.EventContext,
|
||||
creator: Requester,
|
||||
) -> int:
|
||||
nonlocal last_sent_event_id
|
||||
|
||||
ev = await self.event_creation_handler.handle_new_client_event(
|
||||
requester=creator,
|
||||
events_and_context=[(event, context)],
|
||||
ratelimit=False,
|
||||
ignore_shadow_ban=True,
|
||||
)
|
||||
|
||||
last_sent_event_id = ev.event_id
|
||||
|
||||
# we know it was persisted, so must have a stream ordering
|
||||
assert ev.internal_metadata.stream_ordering
|
||||
return ev.internal_metadata.stream_ordering
|
||||
|
||||
try:
|
||||
config = self._presets_dict[preset_config]
|
||||
except KeyError:
|
||||
@@ -1135,10 +1112,14 @@ class RoomCreationHandler:
|
||||
)
|
||||
|
||||
logger.debug("Sending %s in new room", EventTypes.Member)
|
||||
await send(creation_event, creation_context, creator)
|
||||
ev = await self.event_creation_handler.handle_new_client_event(
|
||||
requester=creator,
|
||||
events_and_context=[(creation_event, creation_context)],
|
||||
ratelimit=False,
|
||||
ignore_shadow_ban=True,
|
||||
)
|
||||
last_sent_event_id = ev.event_id
|
||||
|
||||
# Room create event must exist at this point
|
||||
assert last_sent_event_id is not None
|
||||
member_event_id, _ = await self.room_member_handler.update_membership(
|
||||
creator,
|
||||
creator.user,
|
||||
@@ -1157,6 +1138,7 @@ class RoomCreationHandler:
|
||||
depth += 1
|
||||
state_map[(EventTypes.Member, creator.user.to_string())] = member_event_id
|
||||
|
||||
events_to_send = []
|
||||
# We treat the power levels override specially as this needs to be one
|
||||
# of the first events that get sent into a room.
|
||||
pl_content = initial_state.pop((EventTypes.PowerLevels, ""), None)
|
||||
@@ -1165,7 +1147,7 @@ class RoomCreationHandler:
|
||||
EventTypes.PowerLevels, pl_content, False
|
||||
)
|
||||
current_state_group = power_context._state_group
|
||||
await send(power_event, power_context, creator)
|
||||
events_to_send.append((power_event, power_context))
|
||||
else:
|
||||
power_level_content: JsonDict = {
|
||||
"users": {creator_id: 100},
|
||||
@@ -1214,9 +1196,8 @@ class RoomCreationHandler:
|
||||
False,
|
||||
)
|
||||
current_state_group = pl_context._state_group
|
||||
await send(pl_event, pl_context, creator)
|
||||
events_to_send.append((pl_event, pl_context))
|
||||
|
||||
events_to_send = []
|
||||
if room_alias and (EventTypes.CanonicalAlias, "") not in initial_state:
|
||||
room_alias_event, room_alias_context = await create_event(
|
||||
EventTypes.CanonicalAlias, {"alias": room_alias.to_string()}, True
|
||||
|
||||
@@ -165,8 +165,21 @@ class BulkPushRuleEvaluator:
|
||||
return rules_by_user
|
||||
|
||||
async def _get_power_levels_and_sender_level(
|
||||
self, event: EventBase, context: EventContext
|
||||
self,
|
||||
event: EventBase,
|
||||
context: EventContext,
|
||||
event_id_to_event: Mapping[str, EventBase],
|
||||
) -> Tuple[dict, Optional[int]]:
|
||||
"""
|
||||
Given an event and an event context, get the power level event relevant to the event
|
||||
and the power level of the sender of the event.
|
||||
Args:
|
||||
event: event to check
|
||||
context: context of event to check
|
||||
event_id_to_event: a mapping of event_id to event for a set of events being
|
||||
batch persisted. This is needed as the sought-after power level event may
|
||||
be in this batch rather than the DB
|
||||
"""
|
||||
# There are no power levels and sender levels possible to get from outlier
|
||||
if event.internal_metadata.is_outlier():
|
||||
return {}, None
|
||||
@@ -177,15 +190,26 @@ class BulkPushRuleEvaluator:
|
||||
)
|
||||
pl_event_id = prev_state_ids.get(POWER_KEY)
|
||||
|
||||
# fastpath: if there's a power level event, that's all we need, and
|
||||
# not having a power level event is an extreme edge case
|
||||
if pl_event_id:
|
||||
# fastpath: if there's a power level event, that's all we need, and
|
||||
# not having a power level event is an extreme edge case
|
||||
auth_events = {POWER_KEY: await self.store.get_event(pl_event_id)}
|
||||
# Get the power level event from the batch, or fall back to the database.
|
||||
pl_event = event_id_to_event.get(pl_event_id)
|
||||
if pl_event:
|
||||
auth_events = {POWER_KEY: pl_event}
|
||||
else:
|
||||
auth_events = {POWER_KEY: await self.store.get_event(pl_event_id)}
|
||||
else:
|
||||
auth_events_ids = self._event_auth_handler.compute_auth_events(
|
||||
event, prev_state_ids, for_verification=False
|
||||
)
|
||||
auth_events_dict = await self.store.get_events(auth_events_ids)
|
||||
# Some needed auth events might be in the batch, combine them with those
|
||||
# fetched from the database.
|
||||
for auth_event_id in auth_events_ids:
|
||||
auth_event = event_id_to_event.get(auth_event_id)
|
||||
if auth_event:
|
||||
auth_events_dict[auth_event_id] = auth_event
|
||||
auth_events = {(e.type, e.state_key): e for e in auth_events_dict.values()}
|
||||
|
||||
sender_level = get_user_power_level(event.sender, auth_events)
|
||||
@@ -194,16 +218,38 @@ class BulkPushRuleEvaluator:
|
||||
|
||||
return pl_event.content if pl_event else {}, sender_level
|
||||
|
||||
@measure_func("action_for_event_by_user")
|
||||
async def action_for_event_by_user(
|
||||
self, event: EventBase, context: EventContext
|
||||
async def action_for_events_by_user(
|
||||
self, events_and_context: List[Tuple[EventBase, EventContext]]
|
||||
) -> None:
|
||||
"""Given an event and context, evaluate the push rules, check if the message
|
||||
should increment the unread count, and insert the results into the
|
||||
event_push_actions_staging table.
|
||||
"""Given a list of events and their associated contexts, evaluate the push rules
|
||||
for each event, check if the message should increment the unread count, and
|
||||
insert the results into the event_push_actions_staging table.
|
||||
"""
|
||||
if not event.internal_metadata.is_notifiable():
|
||||
# Push rules for events that aren't notifiable can't be processed by this
|
||||
# For batched events the power level events may not have been persisted yet,
|
||||
# so we pass in the batched events. Thus if the event cannot be found in the
|
||||
# database we can check in the batch.
|
||||
event_id_to_event = {e.event_id: e for e, _ in events_and_context}
|
||||
for event, context in events_and_context:
|
||||
await self._action_for_event_by_user(event, context, event_id_to_event)
|
||||
|
||||
@measure_func("action_for_event_by_user")
|
||||
async def _action_for_event_by_user(
|
||||
self,
|
||||
event: EventBase,
|
||||
context: EventContext,
|
||||
event_id_to_event: Mapping[str, EventBase],
|
||||
) -> None:
|
||||
|
||||
if (
|
||||
not event.internal_metadata.is_notifiable()
|
||||
or event.internal_metadata.is_historical()
|
||||
):
|
||||
# Push rules for events that aren't notifiable can't be processed by this and
|
||||
# we want to skip push notification actions for historical messages
|
||||
# because we don't want to notify people about old history back in time.
|
||||
# The historical messages also do not have the proper `context.current_state_ids`
|
||||
# and `state_groups` because they have `prev_events` that aren't persisted yet
|
||||
# (historical messages persisted in reverse-chronological order).
|
||||
return
|
||||
|
||||
# Disable counting as unread unless the experimental configuration is
|
||||
@@ -223,7 +269,9 @@ class BulkPushRuleEvaluator:
|
||||
(
|
||||
power_levels,
|
||||
sender_power_level,
|
||||
) = await self._get_power_levels_and_sender_level(event, context)
|
||||
) = await self._get_power_levels_and_sender_level(
|
||||
event, context, event_id_to_event
|
||||
)
|
||||
|
||||
# Find the event's thread ID.
|
||||
relation = relation_from_event(event)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<style type="text/css">
|
||||
{%- include 'style.css' without context %}
|
||||
</style>
|
||||
{% block header %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<header class="mx_Header">
|
||||
{% if app_name == "Riot" %}
|
||||
<img src="http://riot.im/img/external/riot-logo-email.png" width="83" height="83" alt="[Riot]"/>
|
||||
{% elif app_name == "Vector" %}
|
||||
<img src="http://matrix.org/img/vector-logo-email.png" width="64" height="83" alt="[Vector]"/>
|
||||
{% elif app_name == "Element" %}
|
||||
<img src="https://static.element.io/images/email-logo.png" width="83" height="83" alt="[Element]"/>
|
||||
{% else %}
|
||||
<img src="http://matrix.org/img/matrix-120x51.png" width="120" height="51" alt="[matrix]"/>
|
||||
{% endif %}
|
||||
</header>
|
||||
|
||||
{% block body %}{% endblock %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,12 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Your account is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.</title>
|
||||
</head>
|
||||
<body>
|
||||
Your account is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.
|
||||
</body>
|
||||
</html>
|
||||
{% extends "_base.html" %}
|
||||
{% block title %}Your account is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<p>Your account is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.</p>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Your account has been successfully renewed and is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.</title>
|
||||
</head>
|
||||
<body>
|
||||
Your account has been successfully renewed and is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.
|
||||
</body>
|
||||
</html>
|
||||
{% extends "_base.html" %}
|
||||
{% block title %}Your account has been successfully renewed and is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<p>Your account has been successfully renewed and is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.</p>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Request to add an email address to your Matrix account</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>A request to add an email address to your Matrix account has been received. If this was you, please click the link below to confirm adding this email:</p>
|
||||
<a href="{{ link }}">{{ link }}</a>
|
||||
<p>If this was not you, you can safely ignore this email. Thank you.</p>
|
||||
</body>
|
||||
</html>
|
||||
{% extends "_base.html" %}
|
||||
{% block title %}Request to add an email address to your Matrix account{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<p>A request to add an email address to your Matrix account has been received. If this was you, please click the link below to confirm adding this email:</p>
|
||||
<a href="{{ link }}">{{ link }}</a>
|
||||
<p>If this was not you, you can safely ignore this email. Thank you.</p>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Request failed</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>The request failed for the following reason: {{ failure_reason }}.</p>
|
||||
<p>No changes have been made to your account.</p>
|
||||
</body>
|
||||
</html>
|
||||
{% extends "_base.html" %}
|
||||
{% block title %}Request failed{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<p>The request failed for the following reason: {{ failure_reason }}.</p>
|
||||
<p>No changes have been made to your account.</p>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Your email has now been validated</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Your email has now been validated, please return to your client. You may now close this window.</p>
|
||||
</body>
|
||||
</html>
|
||||
{% extends "_base.html" %}
|
||||
{% block title %}Your email has now been validated{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<p>Your email has now been validated, please return to your client. You may now close this window.</p>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Success!</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% extends "_base.html" %}
|
||||
{% block title %}Success!{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<link rel="stylesheet" href="/_matrix/static/client/register/style.css">
|
||||
<script>
|
||||
if (window.onAuthDone) {
|
||||
window.onAuthDone();
|
||||
} else if (window.opener && window.opener.postMessage) {
|
||||
window.opener.postMessage("authDone", "*");
|
||||
window.opener.postMessage("authDone", "*");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<p>Thank you</p>
|
||||
<p>You may now close this window and return to the application</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div>
|
||||
<p>Thank you</p>
|
||||
<p>You may now close this window and return to the application</p>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Invalid renewal token.</title>
|
||||
</head>
|
||||
<body>
|
||||
Invalid renewal token.
|
||||
</body>
|
||||
</html>
|
||||
{% block title %}Invalid renewal token.{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<p>Invalid renewal token.</p>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,47 +1,46 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style type="text/css">
|
||||
{% include 'mail.css' without context %}
|
||||
{% include "mail-%s.css" % app_name ignore missing without context %}
|
||||
{% include 'mail-expiry.css' without context %}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table id="page">
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td id="inner">
|
||||
<table class="header">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="salutation">Hi {{ display_name }},</div>
|
||||
</td>
|
||||
<td class="logo">
|
||||
{% if app_name == "Riot" %}
|
||||
<img src="http://riot.im/img/external/riot-logo-email.png" width="83" height="83" alt="[Riot]"/>
|
||||
{% elif app_name == "Vector" %}
|
||||
<img src="http://matrix.org/img/vector-logo-email.png" width="64" height="83" alt="[Vector]"/>
|
||||
{% elif app_name == "Element" %}
|
||||
<img src="https://static.element.io/images/email-logo.png" width="83" height="83" alt="[Element]"/>
|
||||
{% else %}
|
||||
<img src="http://matrix.org/img/matrix-120x51.png" width="120" height="51" alt="[matrix]"/>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="noticetext">Your account will expire on {{ expiration_ts|format_ts("%d-%m-%Y") }}. This means that you will lose access to your account after this date.</div>
|
||||
<div class="noticetext">To extend the validity of your account, please click on the link below (or copy and paste it into a new browser tab):</div>
|
||||
<div class="noticetext"><a href="{{ url }}">{{ url }}</a></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
{% extends "_base.html" %}
|
||||
{% block title %}Notice of expiry{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<style type="text/css">
|
||||
{% include 'mail.css' without context %}
|
||||
{% include "mail-%s.css" % app_name ignore missing without context %}
|
||||
{% include 'mail-expiry.css' without context %}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<table id="page">
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td id="inner">
|
||||
<table class="header">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="salutation">Hi {{ display_name }},</div>
|
||||
</td>
|
||||
<td class="logo">
|
||||
{% if app_name == "Riot" %}
|
||||
<img src="http://riot.im/img/external/riot-logo-email.png" width="83" height="83" alt="[Riot]"/>
|
||||
{% elif app_name == "Vector" %}
|
||||
<img src="http://matrix.org/img/vector-logo-email.png" width="64" height="83" alt="[Vector]"/>
|
||||
{% elif app_name == "Element" %}
|
||||
<img src="https://static.element.io/images/email-logo.png" width="83" height="83" alt="[Element]"/>
|
||||
{% else %}
|
||||
<img src="http://matrix.org/img/matrix-120x51.png" width="120" height="51" alt="[matrix]"/>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="noticetext">Your account will expire on {{ expiration_ts|format_ts("%d-%m-%Y") }}. This means that you will lose access to your account after this date.</div>
|
||||
<div class="noticetext">To extend the validity of your account, please click on the link below (or copy and paste it into a new browser tab):</div>
|
||||
<div class="noticetext"><a href="{{ url }}">{{ url }}</a></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,59 +1,57 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style type="text/css">
|
||||
{%- include 'mail.css' without context %}
|
||||
{%- include "mail-%s.css" % app_name ignore missing without context %}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table id="page">
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td id="inner">
|
||||
<table class="header">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="salutation">Hi {{ user_display_name }},</div>
|
||||
<div class="summarytext">{{ summary_text }}</div>
|
||||
</td>
|
||||
<td class="logo">
|
||||
{%- if app_name == "Riot" %}
|
||||
<img src="http://riot.im/img/external/riot-logo-email.png" width="83" height="83" alt="[Riot]"/>
|
||||
{%- elif app_name == "Vector" %}
|
||||
<img src="http://matrix.org/img/vector-logo-email.png" width="64" height="83" alt="[Vector]"/>
|
||||
{%- elif app_name == "Element" %}
|
||||
<img src="https://static.element.io/images/email-logo.png" width="83" height="83" alt="[Element]"/>
|
||||
{%- else %}
|
||||
<img src="http://matrix.org/img/matrix-120x51.png" width="120" height="51" alt="[matrix]"/>
|
||||
{%- endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{%- for room in rooms %}
|
||||
{%- include 'room.html' with context %}
|
||||
{%- endfor %}
|
||||
<div class="footer">
|
||||
<a href="{{ unsubscribe_link }}">Unsubscribe</a>
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="debug">
|
||||
Sending email at {{ reason.now|format_ts("%c") }} due to activity in room {{ reason.room_name }} because
|
||||
an event was received at {{ reason.received_at|format_ts("%c") }}
|
||||
which is more than {{ "%.1f"|format(reason.delay_before_mail_ms / (60*1000)) }} ({{ reason.delay_before_mail_ms }}) mins ago,
|
||||
{%- if reason.last_sent_ts %}
|
||||
and the last time we sent a mail for this room was {{ reason.last_sent_ts|format_ts("%c") }},
|
||||
which is more than {{ "%.1f"|format(reason.throttle_ms / (60*1000)) }} (current throttle_ms) mins ago.
|
||||
{%- else %}
|
||||
and we don't have a last time we sent a mail for this room.
|
||||
{%- endif %}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
{% block title %}New activity in room{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<style type="text/css">
|
||||
{%- include 'mail.css' without context %}
|
||||
{%- include "mail-%s.css" % app_name ignore missing without context %}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<table id="page">
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td id="inner">
|
||||
<table class="header">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="salutation">Hi {{ user_display_name }},</div>
|
||||
<div class="summarytext">{{ summary_text }}</div>
|
||||
</td>
|
||||
<td class="logo">
|
||||
{%- if app_name == "Riot" %}
|
||||
<img src="http://riot.im/img/external/riot-logo-email.png" width="83" height="83" alt="[Riot]"/>
|
||||
{%- elif app_name == "Vector" %}
|
||||
<img src="http://matrix.org/img/vector-logo-email.png" width="64" height="83" alt="[Vector]"/>
|
||||
{%- elif app_name == "Element" %}
|
||||
<img src="https://static.element.io/images/email-logo.png" width="83" height="83" alt="[Element]"/>
|
||||
{%- else %}
|
||||
<img src="http://matrix.org/img/matrix-120x51.png" width="120" height="51" alt="[matrix]"/>
|
||||
{%- endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{%- for room in rooms %}
|
||||
{%- include 'room.html' with context %}
|
||||
{%- endfor %}
|
||||
<div class="footer">
|
||||
<a href="{{ unsubscribe_link }}">Unsubscribe</a>
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="debug">
|
||||
Sending email at {{ reason.now|format_ts("%c") }} due to activity in room {{ reason.room_name }} because
|
||||
an event was received at {{ reason.received_at|format_ts("%c") }}
|
||||
which is more than {{ "%.1f"|format(reason.delay_before_mail_ms / (60*1000)) }} ({{ reason.delay_before_mail_ms }}) mins ago,
|
||||
{%- if reason.last_sent_ts %}
|
||||
and the last time we sent a mail for this room was {{ reason.last_sent_ts|format_ts("%c") }},
|
||||
which is more than {{ "%.1f"|format(reason.throttle_ms / (60*1000)) }} (current throttle_ms) mins ago.
|
||||
{%- else %}
|
||||
and we don't have a last time we sent a mail for this room.
|
||||
{%- endif %}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Password reset</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body>
|
||||
<p>A password reset request has been received for your Matrix account. If this was you, please click the link below to confirm resetting your password:</p>
|
||||
{% block title %}Password reset{% endblock %}
|
||||
|
||||
<a href="{{ link }}">{{ link }}</a>
|
||||
{% block body %}
|
||||
<p>A password reset request has been received for your Matrix account. If this was you, please click the link below to confirm resetting your password:</p>
|
||||
|
||||
<p>If this was not you, <strong>do not</strong> click the link above and instead contact your server administrator. Thank you.</p>
|
||||
</body>
|
||||
</html>
|
||||
<a href="{{ link }}">{{ link }}</a>
|
||||
|
||||
<p>If this was not you, <strong>do not</strong> click the link above and instead contact your server administrator. Thank you.</p>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Password reset confirmation</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body>
|
||||
{% block title %}Password reset confirmation{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<!--Use a hidden form to resubmit the information necessary to reset the password-->
|
||||
<form method="post">
|
||||
<input type="hidden" name="sid" value="{{ sid }}">
|
||||
@@ -15,6 +11,4 @@
|
||||
If you did not mean to do this, please close this page and your password will not be changed.</p>
|
||||
<p><button type="submit">Confirm changing my password</button></p>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Password reset failure</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body>
|
||||
<p>The request failed for the following reason: {{ failure_reason }}.</p>
|
||||
{% block title %}Password reset failure{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<p>The request failed for the following reason: {{ failure_reason }}.</p>
|
||||
<p>Your password has not been reset.</p>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body>
|
||||
{% block title %}Password reset success{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<p>Your email has now been validated, please return to your client to reset your password. You may now close this window.</p>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Authentication</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="https://www.recaptcha.net/recaptcha/api.js"
|
||||
async defer></script>
|
||||
{% block title %}Authentication{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<script src="https://www.recaptcha.net/recaptcha/api.js" async defer></script>
|
||||
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
|
||||
<link rel="stylesheet" href="/_matrix/static/client/register/style.css">
|
||||
<script>
|
||||
@@ -12,8 +9,9 @@ function captchaDone() {
|
||||
$('#registrationForm').submit();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<form id="registrationForm" method="post" action="{{ myurl }}">
|
||||
<div>
|
||||
{% if error is defined %}
|
||||
@@ -37,5 +35,4 @@ function captchaDone() {
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
@@ -1,16 +1,11 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Registration</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body>
|
||||
<p>You have asked us to register this email with a new Matrix account. If this was you, please click the link below to confirm your email address:</p>
|
||||
{% block title %}Registration{% endblock %}
|
||||
|
||||
<a href="{{ link }}">Verify Your Email Address</a>
|
||||
{% block body %}
|
||||
<p>You have asked us to register this email with a new Matrix account. If this was you, please click the link below to confirm your email address:</p>
|
||||
|
||||
<p>If this was not you, you can safely disregard this email.</p>
|
||||
<a href="{{ link }}">Verify Your Email Address</a>
|
||||
|
||||
<p>Thank you.</p>
|
||||
</body>
|
||||
</html>
|
||||
<p>If this was not you, you can safely disregard this email.</p>
|
||||
|
||||
<p>Thank you.</p>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body>
|
||||
{% block title %}Registration failure{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<p>Validation failed for the following reason: {{ failure_reason }}.</p>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Your email has now been validated</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body>
|
||||
{% block title %}Your email has now been validated{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<p>Your email has now been validated, please return to your client. You may now close this window.</p>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Authentication</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% block title %}Authentication{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<link rel="stylesheet" href="/_matrix/static/client/register/style.css">
|
||||
</head>
|
||||
<body>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<form id="registrationForm" method="post" action="{{ myurl }}">
|
||||
<div>
|
||||
{% if error is defined %}
|
||||
@@ -19,5 +18,4 @@
|
||||
<input type="submit" value="Authenticate" />
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>SSO account deactivated</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
</style>
|
||||
</head>
|
||||
<body class="error_page">
|
||||
<header>
|
||||
<h1>Your account has been deactivated</h1>
|
||||
<p>
|
||||
<strong>No account found</strong>
|
||||
</p>
|
||||
<p>
|
||||
Your account might have been deactivated by the server administrator.
|
||||
You can either try to create a new account or contact the server’s
|
||||
administrator.
|
||||
</p>
|
||||
</header>
|
||||
{% include "sso_footer.html" without context %}
|
||||
</body>
|
||||
</html>
|
||||
{% block title %}SSO account deactivated{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="error_page">
|
||||
<header>
|
||||
<h1>Your account has been deactivated</h1>
|
||||
<p>
|
||||
<strong>No account found</strong>
|
||||
</p>
|
||||
<p>
|
||||
Your account might have been deactivated by the server administrator.
|
||||
You can either try to create a new account or contact the server’s
|
||||
administrator.
|
||||
</p>
|
||||
</header>
|
||||
</div>
|
||||
{% include "sso_footer.html" without context %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,189 +1,185 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Create your account</title>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script type="text/javascript">
|
||||
let wasKeyboard = false;
|
||||
document.addEventListener("mousedown", function() { wasKeyboard = false; });
|
||||
document.addEventListener("keydown", function() { wasKeyboard = true; });
|
||||
document.addEventListener("focusin", function() {
|
||||
if (wasKeyboard) {
|
||||
document.body.classList.add("keyboard-focus");
|
||||
} else {
|
||||
document.body.classList.remove("keyboard-focus");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
{% block title %}Create your account{% endblock %}
|
||||
|
||||
body.keyboard-focus :focus, body.keyboard-focus .username_input:focus-within {
|
||||
outline: 3px solid #17191C;
|
||||
outline-offset: 4px;
|
||||
}
|
||||
{% block header %}
|
||||
<script type="text/javascript">
|
||||
let wasKeyboard = false;
|
||||
document.addEventListener("mousedown", function() { wasKeyboard = false; });
|
||||
document.addEventListener("keydown", function() { wasKeyboard = true; });
|
||||
document.addEventListener("focusin", function() {
|
||||
if (wasKeyboard) {
|
||||
document.body.classList.add("keyboard-focus");
|
||||
} else {
|
||||
document.body.classList.remove("keyboard-focus");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
|
||||
.username_input {
|
||||
display: flex;
|
||||
border: 2px solid #418DED;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
position: relative;
|
||||
margin: 16px 0;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
body.keyboard-focus :focus, body.keyboard-focus .username_input:focus-within {
|
||||
outline: 3px solid #17191C;
|
||||
outline-offset: 4px;
|
||||
}
|
||||
|
||||
.username_input.invalid {
|
||||
border-color: #FE2928;
|
||||
}
|
||||
.username_input {
|
||||
display: flex;
|
||||
border: 2px solid #418DED;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
position: relative;
|
||||
margin: 16px 0;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.username_input.invalid input, .username_input.invalid label {
|
||||
color: #FE2928;
|
||||
}
|
||||
.username_input.invalid {
|
||||
border-color: #FE2928;
|
||||
}
|
||||
|
||||
.username_input div, .username_input input {
|
||||
line-height: 18px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.username_input.invalid input, .username_input.invalid label {
|
||||
color: #FE2928;
|
||||
}
|
||||
|
||||
.username_input label {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 14px;
|
||||
font-size: 10px;
|
||||
line-height: 10px;
|
||||
background: white;
|
||||
padding: 0 2px;
|
||||
}
|
||||
.username_input div, .username_input input {
|
||||
line-height: 18px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.username_input input {
|
||||
flex: 1;
|
||||
display: block;
|
||||
min-width: 0;
|
||||
border: none;
|
||||
}
|
||||
.username_input label {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 14px;
|
||||
font-size: 10px;
|
||||
line-height: 10px;
|
||||
background: white;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
/* only clear the outline if we know it will be shown on the parent div using :focus-within */
|
||||
@supports selector(:focus-within) {
|
||||
.username_input input {
|
||||
outline: none !important;
|
||||
}
|
||||
}
|
||||
.username_input input {
|
||||
flex: 1;
|
||||
display: block;
|
||||
min-width: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.username_input div {
|
||||
color: #8D99A5;
|
||||
}
|
||||
/* only clear the outline if we know it will be shown on the parent div using :focus-within */
|
||||
@supports selector(:focus-within) {
|
||||
.username_input input {
|
||||
outline: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.idp-pick-details {
|
||||
border: 1px solid #E9ECF1;
|
||||
border-radius: 8px;
|
||||
margin: 24px 0;
|
||||
}
|
||||
.username_input div {
|
||||
color: #8D99A5;
|
||||
}
|
||||
|
||||
.idp-pick-details h2 {
|
||||
margin: 0;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
.idp-pick-details {
|
||||
border: 1px solid #E9ECF1;
|
||||
border-radius: 8px;
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
.idp-pick-details .idp-detail {
|
||||
border-top: 1px solid #E9ECF1;
|
||||
padding: 12px;
|
||||
display: block;
|
||||
}
|
||||
.idp-pick-details .check-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.idp-pick-details h2 {
|
||||
margin: 0;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.idp-pick-details .check-row .name {
|
||||
flex: 1;
|
||||
}
|
||||
.idp-pick-details .idp-detail {
|
||||
border-top: 1px solid #E9ECF1;
|
||||
padding: 12px;
|
||||
display: block;
|
||||
}
|
||||
.idp-pick-details .check-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.idp-pick-details .use, .idp-pick-details .idp-value {
|
||||
color: #737D8C;
|
||||
}
|
||||
.idp-pick-details .check-row .name {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.idp-pick-details .idp-value {
|
||||
margin: 0;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.idp-pick-details .use, .idp-pick-details .idp-value {
|
||||
color: #737D8C;
|
||||
}
|
||||
|
||||
.idp-pick-details .avatar {
|
||||
width: 53px;
|
||||
height: 53px;
|
||||
border-radius: 100%;
|
||||
display: block;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.idp-pick-details .idp-value {
|
||||
margin: 0;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
output {
|
||||
padding: 0 14px;
|
||||
display: block;
|
||||
}
|
||||
.idp-pick-details .avatar {
|
||||
width: 53px;
|
||||
height: 53px;
|
||||
border-radius: 100%;
|
||||
display: block;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
output.error {
|
||||
color: #FE2928;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<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 (required)</label>
|
||||
<div class="prefix">@</div>
|
||||
<input type="text" name="username" id="field-username" value="{{ user_attributes.localpart }}" autofocus autocorrect="off" autocapitalize="none">
|
||||
<div class="postfix">:{{ server_name }}</div>
|
||||
output {
|
||||
padding: 0 14px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
output.error {
|
||||
color: #FE2928;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<header>
|
||||
<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 (required)</label>
|
||||
<div class="prefix">@</div>
|
||||
<input type="text" name="username" id="field-username" value="{{ user_attributes.localpart }}" autofocus autocorrect="off" autocapitalize="none">
|
||||
<div class="postfix">:{{ server_name }}</div>
|
||||
</div>
|
||||
<output for="username_input" id="field-username-output"></output>
|
||||
<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 %}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">
|
||||
<span class="name">Avatar</span>
|
||||
<span class="use">Use</span>
|
||||
<input type="checkbox" name="use_avatar" id="idp-avatar" value="true" checked>
|
||||
</div>
|
||||
<output for="username_input" id="field-username-output"></output>
|
||||
<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 %}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">
|
||||
<span class="name">Avatar</span>
|
||||
<span class="use">Use</span>
|
||||
<input type="checkbox" name="use_avatar" id="idp-avatar" value="true" checked>
|
||||
</div>
|
||||
<img src="{{ user_attributes.avatar_url }}" class="avatar" />
|
||||
</label>
|
||||
{% endif %}
|
||||
{% if user_attributes.display_name %}
|
||||
<label class="idp-detail" for="idp-displayname">
|
||||
<div class="check-row">
|
||||
<span class="name">Display name</span>
|
||||
<span class="use">Use</span>
|
||||
<input type="checkbox" name="use_display_name" id="idp-displayname" value="true" checked>
|
||||
</div>
|
||||
<p class="idp-value">{{ user_attributes.display_name }}</p>
|
||||
</label>
|
||||
{% endif %}
|
||||
{% for email in user_attributes.emails %}
|
||||
<label class="idp-detail" for="idp-email{{ loop.index }}">
|
||||
<div class="check-row">
|
||||
<span class="name">E-mail</span>
|
||||
<span class="use">Use</span>
|
||||
<input type="checkbox" name="use_email" id="idp-email{{ loop.index }}" value="{{ email }}" checked>
|
||||
</div>
|
||||
<p class="idp-value">{{ email }}</p>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% endif %}
|
||||
</form>
|
||||
</main>
|
||||
{% include "sso_footer.html" without context %}
|
||||
<script type="text/javascript">
|
||||
{% include "sso_auth_account_details.js" without context %}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<img src="{{ user_attributes.avatar_url }}" class="avatar" />
|
||||
</label>
|
||||
{% endif %}
|
||||
{% if user_attributes.display_name %}
|
||||
<label class="idp-detail" for="idp-displayname">
|
||||
<div class="check-row">
|
||||
<span class="name">Display name</span>
|
||||
<span class="use">Use</span>
|
||||
<input type="checkbox" name="use_display_name" id="idp-displayname" value="true" checked>
|
||||
</div>
|
||||
<p class="idp-value">{{ user_attributes.display_name }}</p>
|
||||
</label>
|
||||
{% endif %}
|
||||
{% for email in user_attributes.emails %}
|
||||
<label class="idp-detail" for="idp-email{{ loop.index }}">
|
||||
<div class="check-row">
|
||||
<span class="name">E-mail</span>
|
||||
<span class="use">Use</span>
|
||||
<input type="checkbox" name="use_email" id="idp-email{{ loop.index }}" value="{{ email }}" checked>
|
||||
</div>
|
||||
<p class="idp-value">{{ email }}</p>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% endif %}
|
||||
</form>
|
||||
</main>
|
||||
{% include "sso_footer.html" without context %}
|
||||
<script type="text/javascript">
|
||||
{% include "sso_auth_account_details.js" without context %}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Authentication failed</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
</style>
|
||||
</head>
|
||||
<body class="error_page">
|
||||
<header>
|
||||
<h1>That doesn't look right</h1>
|
||||
<p>
|
||||
<strong>We were unable to validate your {{ server_name }} account</strong>
|
||||
via single sign‑on (SSO), because the SSO Identity
|
||||
Provider returned different details than when you logged in.
|
||||
</p>
|
||||
<p>
|
||||
Try the operation again, and ensure that you use the same details on
|
||||
the Identity Provider as when you log into your account.
|
||||
</p>
|
||||
</header>
|
||||
{% include "sso_footer.html" without context %}
|
||||
</body>
|
||||
</html>
|
||||
{% block title %}Authentication failed{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="error_page">
|
||||
<header>
|
||||
<h1>That doesn't look right</h1>
|
||||
<p>
|
||||
<strong>We were unable to validate your {{ server_name }} account</strong>
|
||||
via single sign‑on (SSO), because the SSO Identity
|
||||
Provider returned different details than when you logged in.
|
||||
</p>
|
||||
<p>
|
||||
Try the operation again, and ensure that you use the same details on
|
||||
the Identity Provider as when you log into your account.
|
||||
</p>
|
||||
</header>
|
||||
</div>
|
||||
{% include "sso_footer.html" without context %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Confirm it's you</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Confirm it's you to continue</h1>
|
||||
<p>
|
||||
A client is trying to {{ description }}. To confirm this action
|
||||
re-authorize your account with single sign-on.
|
||||
</p>
|
||||
<p><strong>
|
||||
If you did not expect this, your account may be compromised.
|
||||
</strong></p>
|
||||
</header>
|
||||
<main>
|
||||
<a href="{{ redirect_url }}" class="primary-button">
|
||||
Continue with {{ idp.idp_name }}
|
||||
</a>
|
||||
</main>
|
||||
{% include "sso_footer.html" without context %}
|
||||
</body>
|
||||
</html>
|
||||
{% block title %}Confirm it's you{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<header>
|
||||
<h1>Confirm it's you to continue</h1>
|
||||
<p>
|
||||
A client is trying to {{ description }}. To confirm this action
|
||||
re-authorize your account with single sign-on.
|
||||
</p>
|
||||
<p><strong>
|
||||
If you did not expect this, your account may be compromised.
|
||||
</strong></p>
|
||||
</header>
|
||||
<main>
|
||||
<a href="{{ redirect_url }}" class="primary-button">
|
||||
Continue with {{ idp.idp_name }}
|
||||
</a>
|
||||
</main>
|
||||
{% include "sso_footer.html" without context %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,29 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Authentication successful</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
</style>
|
||||
<script>
|
||||
if (window.onAuthDone) {
|
||||
window.onAuthDone();
|
||||
} else if (window.opener && window.opener.postMessage) {
|
||||
window.opener.postMessage("authDone", "*");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Thank you</h1>
|
||||
<p>
|
||||
Now we know it’s you, you can close this window and return to the
|
||||
application.
|
||||
</p>
|
||||
</header>
|
||||
{% include "sso_footer.html" without context %}
|
||||
</body>
|
||||
</html>
|
||||
{% block title %}Authentication successful{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
</style>
|
||||
<script>
|
||||
if (window.onAuthDone) {
|
||||
window.onAuthDone();
|
||||
} else if (window.opener && window.opener.postMessage) {
|
||||
window.opener.postMessage("authDone", "*");
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<header>
|
||||
<h1>Thank you</h1>
|
||||
<p>
|
||||
Now we know it’s you, you can close this window and return to the
|
||||
application.
|
||||
</p>
|
||||
</header>
|
||||
{% include "sso_footer.html" without context %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Authentication failed</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
{% block title %}Authentication failed{% endblock %}
|
||||
|
||||
#error_code {
|
||||
margin-top: 56px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="error_page">
|
||||
{% block header %}
|
||||
{% if error == "unauthorised" %}
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
|
||||
#error_code {
|
||||
margin-top: 56px;
|
||||
}
|
||||
</style>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="error_page">
|
||||
{# If an error of unauthorised is returned it means we have actively rejected their login #}
|
||||
{% if error == "unauthorised" %}
|
||||
<header>
|
||||
@@ -66,5 +66,5 @@
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,63 +1,59 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8">
|
||||
<title>Choose identity provider</title>
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
{% block title %}Choose identity provider{% endblock %}
|
||||
|
||||
.providers {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
{% block header %}
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
|
||||
.providers li {
|
||||
margin: 12px;
|
||||
}
|
||||
.providers {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.providers a {
|
||||
display: block;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #17191C;
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: #17191C;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
.providers li {
|
||||
margin: 12px;
|
||||
}
|
||||
|
||||
.providers a img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
.providers a span {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Log in to {{ server_name }} </h1>
|
||||
<p>Choose an identity provider to log in</p>
|
||||
</header>
|
||||
<main>
|
||||
<ul class="providers">
|
||||
{% for p in providers %}
|
||||
<li>
|
||||
<a href="pick_idp?idp={{ p.idp_id }}&redirectUrl={{ redirect_url | urlencode }}">
|
||||
{% if p.idp_icon %}
|
||||
<img src="{{ p.idp_icon | mxc_to_http(32, 32) }}"/>
|
||||
{% endif %}
|
||||
<span>{{ p.idp_name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</main>
|
||||
{% include "sso_footer.html" without context %}
|
||||
</body>
|
||||
</html>
|
||||
.providers a {
|
||||
display: block;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #17191C;
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: #17191C;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.providers a img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
.providers a span {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<header>
|
||||
<h1>Log in to {{ server_name }} </h1>
|
||||
<p>Choose an identity provider to log in</p>
|
||||
</header>
|
||||
<main>
|
||||
<ul class="providers">
|
||||
{% for p in providers %}
|
||||
<li>
|
||||
<a href="pick_idp?idp={{ p.idp_id }}&redirectUrl={{ redirect_url | urlencode }}">
|
||||
{% if p.idp_icon %}
|
||||
<img src="{{ p.idp_icon | mxc_to_http(32, 32) }}"/>
|
||||
{% endif %}
|
||||
<span>{{ p.idp_name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</main>
|
||||
{% include "sso_footer.html" without context %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,33 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Agree to terms and conditions</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
{% block title %}Agree to terms and conditions{% endblock %}
|
||||
|
||||
#consent_form {
|
||||
margin-top: 56px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Your account is nearly ready</h1>
|
||||
<p>Agree to the terms to create your account.</p>
|
||||
</header>
|
||||
<main>
|
||||
{% include "sso_partial_profile.html" %}
|
||||
<form method="post" action="{{my_url}}" id="consent_form">
|
||||
<p>
|
||||
<input id="accepted_version" type="checkbox" name="accepted_version" value="{{ consent_version }}" required>
|
||||
<label for="accepted_version">I have read and agree to the <a href="{{ terms_url }}" target="_blank" rel="noopener">terms and conditions</a>.</label>
|
||||
</p>
|
||||
<input type="submit" class="primary-button" value="Continue"/>
|
||||
</form>
|
||||
</main>
|
||||
{% include "sso_footer.html" without context %}
|
||||
</body>
|
||||
</html>
|
||||
{% block header %}
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
|
||||
#consent_form {
|
||||
margin-top: 56px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<header>
|
||||
<h1>Your account is nearly ready</h1>
|
||||
<p>Agree to the terms to create your account.</p>
|
||||
</header>
|
||||
<main>
|
||||
{% include "sso_partial_profile.html" %}
|
||||
<form method="post" action="{{my_url}}" id="consent_form">
|
||||
<p>
|
||||
<input id="accepted_version" type="checkbox" name="accepted_version" value="{{ consent_version }}" required>
|
||||
<label for="accepted_version">I have read and agree to the <a href="{{ terms_url }}" target="_blank" rel="noopener">terms and conditions</a>.</label>
|
||||
</p>
|
||||
<input type="submit" class="primary-button" value="Continue"/>
|
||||
</form>
|
||||
</main>
|
||||
{% include "sso_footer.html" without context %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,41 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Continue to your account</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
{% block title %}Continue to your account{% endblock %}
|
||||
|
||||
.confirm-trust {
|
||||
margin: 34px 0;
|
||||
color: #8D99A5;
|
||||
}
|
||||
.confirm-trust strong {
|
||||
color: #17191C;
|
||||
}
|
||||
{% block header %}
|
||||
<style type="text/css">
|
||||
{% include "sso.css" without context %}
|
||||
|
||||
.confirm-trust::before {
|
||||
content: "";
|
||||
background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgiIGhlaWdodD0iMTgiIHZpZXdCb3g9IjAgMCAxOCAxOCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNi41IDlDMTYuNSAxMy4xNDIxIDEzLjE0MjEgMTYuNSA5IDE2LjVDNC44NTc4NiAxNi41IDEuNSAxMy4xNDIxIDEuNSA5QzEuNSA0Ljg1Nzg2IDQuODU3ODYgMS41IDkgMS41QzEzLjE0MjEgMS41IDE2LjUgNC44NTc4NiAxNi41IDlaTTcuMjUgOUM3LjI1IDkuNDY1OTYgNy41Njg2OSA5Ljg1NzQ4IDggOS45Njg1VjEyLjM3NUM4IDEyLjkyNzMgOC40NDc3MiAxMy4zNzUgOSAxMy4zNzVIMTAuMTI1QzEwLjY3NzMgMTMuMzc1IDExLjEyNSAxMi45MjczIDExLjEyNSAxMi4zNzVDMTEuMTI1IDExLjgyMjcgMTAuNjc3MyAxMS4zNzUgMTAuMTI1IDExLjM3NUgxMFY5QzEwIDguOTY1NDggOS45OTgyNSA4LjkzMTM3IDkuOTk0ODQgOC44OTc3NkM5Ljk0MzYzIDguMzkzNSA5LjUxNzc3IDggOSA4SDguMjVDNy42OTc3MiA4IDcuMjUgOC40NDc3MiA3LjI1IDlaTTkgNy41QzkuNjIxMzIgNy41IDEwLjEyNSA2Ljk5NjMyIDEwLjEyNSA2LjM3NUMxMC4xMjUgNS43NTM2OCA5LjYyMTMyIDUuMjUgOSA1LjI1QzguMzc4NjggNS4yNSA3Ljg3NSA1Ljc1MzY4IDcuODc1IDYuMzc1QzcuODc1IDYuOTk2MzIgOC4zNzg2OCA3LjUgOSA3LjVaIiBmaWxsPSIjQzFDNkNEIi8+Cjwvc3ZnPgoK');
|
||||
background-repeat: no-repeat;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Continue to your account</h1>
|
||||
</header>
|
||||
<main>
|
||||
{% include "sso_partial_profile.html" %}
|
||||
<p class="confirm-trust">Continuing will grant <strong>{{ display_url }}</strong> access to your account.</p>
|
||||
<a href="{{ redirect_url }}" class="primary-button">Continue</a>
|
||||
</main>
|
||||
{% include "sso_footer.html" without context %}
|
||||
</body>
|
||||
</html>
|
||||
.confirm-trust {
|
||||
margin: 34px 0;
|
||||
color: #8D99A5;
|
||||
}
|
||||
.confirm-trust strong {
|
||||
color: #17191C;
|
||||
}
|
||||
|
||||
.confirm-trust::before {
|
||||
content: "";
|
||||
background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgiIGhlaWdodD0iMTgiIHZpZXdCb3g9IjAgMCAxOCAxOCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNi41IDlDMTYuNSAxMy4xNDIxIDEzLjE0MjEgMTYuNSA5IDE2LjVDNC44NTc4NiAxNi41IDEuNSAxMy4xNDIxIDEuNSA5QzEuNSA0Ljg1Nzg2IDQuODU3ODYgMS41IDkgMS41QzEzLjE0MjEgMS41IDE2LjUgNC44NTc4NiAxNi41IDlaTTcuMjUgOUM3LjI1IDkuNDY1OTYgNy41Njg2OSA5Ljg1NzQ4IDggOS45Njg1VjEyLjM3NUM4IDEyLjkyNzMgOC40NDc3MiAxMy4zNzUgOSAxMy4zNzVIMTAuMTI1QzEwLjY3NzMgMTMuMzc1IDExLjEyNSAxMi45MjczIDExLjEyNSAxMi4zNzVDMTEuMTI1IDExLjgyMjcgMTAuNjc3MyAxMS4zNzUgMTAuMTI1IDExLjM3NUgxMFY5QzEwIDguOTY1NDggOS45OTgyNSA4LjkzMTM3IDkuOTk0ODQgOC44OTc3NkM5Ljk0MzYzIDguMzkzNSA5LjUxNzc3IDggOSA4SDguMjVDNy42OTc3MiA4IDcuMjUgOC40NDc3MiA3LjI1IDlaTTkgNy41QzkuNjIxMzIgNy41IDEwLjEyNSA2Ljk5NjMyIDEwLjEyNSA2LjM3NUMxMC4xMjUgNS43NTM2OCA5LjYyMTMyIDUuMjUgOSA1LjI1QzguMzc4NjggNS4yNSA3Ljg3NSA1Ljc1MzY4IDcuODc1IDYuMzc1QzcuODc1IDYuOTk2MzIgOC4zNzg2OCA3LjUgOSA3LjVaIiBmaWxsPSIjQzFDNkNEIi8+Cjwvc3ZnPgoK');
|
||||
background-repeat: no-repeat;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<header>
|
||||
<h1>Continue to your account</h1>
|
||||
</header>
|
||||
<main>
|
||||
{% include "sso_partial_profile.html" %}
|
||||
<p class="confirm-trust">Continuing will grant <strong>{{ display_url }}</strong> access to your account.</p>
|
||||
<a href="{{ redirect_url }}" class="primary-button">Continue</a>
|
||||
</main>
|
||||
{% include "sso_footer.html" without context %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #f9fafb;
|
||||
max-width: 680px;
|
||||
margin: auto;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
}
|
||||
|
||||
.mx_Header {
|
||||
border-bottom: 3px solid #ddd;
|
||||
margin-bottom: 1rem;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1120px) {
|
||||
body {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
h1 { font-size: 1rem; }
|
||||
h2 { font-size: .9rem; }
|
||||
h3 { font-size: .85rem; }
|
||||
h4 { font-size: .8rem; }
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Authentication</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% block title %}Authentication{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<link rel="stylesheet" href="/_matrix/static/client/register/style.css">
|
||||
</head>
|
||||
<body>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<form id="registrationForm" method="post" action="{{ myurl }}">
|
||||
<div>
|
||||
{% if error is defined %}
|
||||
@@ -19,5 +18,4 @@
|
||||
<input type="submit" value="Agree" />
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
|
||||
@@ -100,7 +100,6 @@ class SyncRestServlet(RestServlet):
|
||||
self._server_notices_sender = hs.get_server_notices_sender()
|
||||
self._event_serializer = hs.get_event_client_serializer()
|
||||
self._msc2654_enabled = hs.config.experimental.msc2654_enabled
|
||||
self._msc3773_enabled = hs.config.experimental.msc3773_enabled
|
||||
|
||||
async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
|
||||
# This will always be set by the time Twisted calls us.
|
||||
@@ -512,10 +511,6 @@ class SyncRestServlet(RestServlet):
|
||||
result["unread_notifications"] = room.unread_notifications
|
||||
if room.unread_thread_notifications:
|
||||
result["unread_thread_notifications"] = room.unread_thread_notifications
|
||||
if self._msc3773_enabled:
|
||||
result[
|
||||
"org.matrix.msc3773.unread_thread_notifications"
|
||||
] = room.unread_thread_notifications
|
||||
result["summary"] = room.summary
|
||||
if self._msc2654_enabled:
|
||||
result["org.matrix.msc2654.unread_count"] = room.unread_count
|
||||
|
||||
@@ -103,11 +103,6 @@ class VersionsRestServlet(RestServlet):
|
||||
"org.matrix.msc2716": self.config.experimental.msc2716_enabled,
|
||||
# Adds support for jump to date endpoints (/timestamp_to_event) as per MSC3030
|
||||
"org.matrix.msc3030": self.config.experimental.msc3030_enabled,
|
||||
# Adds support for thread relations, per MSC3440.
|
||||
"org.matrix.msc3440.stable": True, # TODO: remove when "v1.3" is added above
|
||||
# Support for thread read receipts & notification counts.
|
||||
"org.matrix.msc3771": True,
|
||||
"org.matrix.msc3773": self.config.experimental.msc3773_enabled,
|
||||
# Allows moderators to fetch redacted event content as described in MSC2815
|
||||
"fi.mau.msc2815": self.config.experimental.msc2815_enabled,
|
||||
# Adds support for login token requests as per MSC3882
|
||||
|
||||
@@ -14,17 +14,20 @@
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from twisted.web.resource import Resource
|
||||
|
||||
from .local_key_resource import LocalKey
|
||||
from .remote_key_resource import RemoteKey
|
||||
from synapse.http.server import HttpServer, JsonResource
|
||||
from synapse.rest.key.v2.local_key_resource import LocalKey
|
||||
from synapse.rest.key.v2.remote_key_resource import RemoteKey
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from synapse.server import HomeServer
|
||||
|
||||
|
||||
class KeyApiV2Resource(Resource):
|
||||
class KeyResource(JsonResource):
|
||||
def __init__(self, hs: "HomeServer"):
|
||||
Resource.__init__(self)
|
||||
self.putChild(b"server", LocalKey(hs))
|
||||
self.putChild(b"query", RemoteKey(hs))
|
||||
super().__init__(hs, canonical_json=True)
|
||||
self.register_servlets(self, hs)
|
||||
|
||||
@staticmethod
|
||||
def register_servlets(http_server: HttpServer, hs: "HomeServer") -> None:
|
||||
LocalKey(hs).register(http_server)
|
||||
RemoteKey(hs).register(http_server)
|
||||
|
||||
@@ -13,16 +13,15 @@
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
import re
|
||||
from typing import TYPE_CHECKING, Optional, Tuple
|
||||
|
||||
from canonicaljson import encode_canonical_json
|
||||
from signedjson.sign import sign_json
|
||||
from unpaddedbase64 import encode_base64
|
||||
|
||||
from twisted.web.resource import Resource
|
||||
from twisted.web.server import Request
|
||||
|
||||
from synapse.http.server import respond_with_json_bytes
|
||||
from synapse.http.site import SynapseRequest
|
||||
from synapse.http.servlet import RestServlet
|
||||
from synapse.types import JsonDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -31,7 +30,7 @@ if TYPE_CHECKING:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LocalKey(Resource):
|
||||
class LocalKey(RestServlet):
|
||||
"""HTTP resource containing encoding the TLS X.509 certificate and NACL
|
||||
signature verification keys for this server::
|
||||
|
||||
@@ -61,18 +60,17 @@ class LocalKey(Resource):
|
||||
}
|
||||
"""
|
||||
|
||||
isLeaf = True
|
||||
PATTERNS = (re.compile("^/_matrix/key/v2/server(/(?P<key_id>[^/]*))?$"),)
|
||||
|
||||
def __init__(self, hs: "HomeServer"):
|
||||
self.config = hs.config
|
||||
self.clock = hs.get_clock()
|
||||
self.update_response_body(self.clock.time_msec())
|
||||
Resource.__init__(self)
|
||||
|
||||
def update_response_body(self, time_now_msec: int) -> None:
|
||||
refresh_interval = self.config.key.key_refresh_interval
|
||||
self.valid_until_ts = int(time_now_msec + refresh_interval)
|
||||
self.response_body = encode_canonical_json(self.response_json_object())
|
||||
self.response_body = self.response_json_object()
|
||||
|
||||
def response_json_object(self) -> JsonDict:
|
||||
verify_keys = {}
|
||||
@@ -99,9 +97,11 @@ class LocalKey(Resource):
|
||||
json_object = sign_json(json_object, self.config.server.server_name, key)
|
||||
return json_object
|
||||
|
||||
def render_GET(self, request: SynapseRequest) -> Optional[int]:
|
||||
def on_GET(
|
||||
self, request: Request, key_id: Optional[str] = None
|
||||
) -> Tuple[int, JsonDict]:
|
||||
time_now = self.clock.time_msec()
|
||||
# Update the expiry time if less than half the interval remains.
|
||||
if time_now + self.config.key.key_refresh_interval / 2 > self.valid_until_ts:
|
||||
self.update_response_body(time_now)
|
||||
return respond_with_json_bytes(request, 200, self.response_body)
|
||||
return 200, self.response_body
|
||||
|
||||
@@ -13,15 +13,20 @@
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Dict, Set
|
||||
import re
|
||||
from typing import TYPE_CHECKING, Dict, Optional, Set, Tuple
|
||||
|
||||
from signedjson.sign import sign_json
|
||||
|
||||
from synapse.api.errors import Codes, SynapseError
|
||||
from twisted.web.server import Request
|
||||
|
||||
from synapse.crypto.keyring import ServerKeyFetcher
|
||||
from synapse.http.server import DirectServeJsonResource, respond_with_json
|
||||
from synapse.http.servlet import parse_integer, parse_json_object_from_request
|
||||
from synapse.http.site import SynapseRequest
|
||||
from synapse.http.server import HttpServer
|
||||
from synapse.http.servlet import (
|
||||
RestServlet,
|
||||
parse_integer,
|
||||
parse_json_object_from_request,
|
||||
)
|
||||
from synapse.types import JsonDict
|
||||
from synapse.util import json_decoder
|
||||
from synapse.util.async_helpers import yieldable_gather_results
|
||||
@@ -32,7 +37,7 @@ if TYPE_CHECKING:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RemoteKey(DirectServeJsonResource):
|
||||
class RemoteKey(RestServlet):
|
||||
"""HTTP resource for retrieving the TLS certificate and NACL signature
|
||||
verification keys for a collection of servers. Checks that the reported
|
||||
X.509 TLS certificate matches the one used in the HTTPS connection. Checks
|
||||
@@ -88,11 +93,7 @@ class RemoteKey(DirectServeJsonResource):
|
||||
}
|
||||
"""
|
||||
|
||||
isLeaf = True
|
||||
|
||||
def __init__(self, hs: "HomeServer"):
|
||||
super().__init__()
|
||||
|
||||
self.fetcher = ServerKeyFetcher(hs)
|
||||
self.store = hs.get_datastores().main
|
||||
self.clock = hs.get_clock()
|
||||
@@ -101,36 +102,48 @@ class RemoteKey(DirectServeJsonResource):
|
||||
)
|
||||
self.config = hs.config
|
||||
|
||||
async def _async_render_GET(self, request: SynapseRequest) -> None:
|
||||
assert request.postpath is not None
|
||||
if len(request.postpath) == 1:
|
||||
(server,) = request.postpath
|
||||
query: dict = {server.decode("ascii"): {}}
|
||||
elif len(request.postpath) == 2:
|
||||
server, key_id = request.postpath
|
||||
def register(self, http_server: HttpServer) -> None:
|
||||
http_server.register_paths(
|
||||
"GET",
|
||||
(
|
||||
re.compile(
|
||||
"^/_matrix/key/v2/query/(?P<server>[^/]*)(/(?P<key_id>[^/]*))?$"
|
||||
),
|
||||
),
|
||||
self.on_GET,
|
||||
self.__class__.__name__,
|
||||
)
|
||||
http_server.register_paths(
|
||||
"POST",
|
||||
(re.compile("^/_matrix/key/v2/query$"),),
|
||||
self.on_POST,
|
||||
self.__class__.__name__,
|
||||
)
|
||||
|
||||
async def on_GET(
|
||||
self, request: Request, server: str, key_id: Optional[str] = None
|
||||
) -> Tuple[int, JsonDict]:
|
||||
if server and key_id:
|
||||
minimum_valid_until_ts = parse_integer(request, "minimum_valid_until_ts")
|
||||
arguments = {}
|
||||
if minimum_valid_until_ts is not None:
|
||||
arguments["minimum_valid_until_ts"] = minimum_valid_until_ts
|
||||
query = {server.decode("ascii"): {key_id.decode("ascii"): arguments}}
|
||||
query = {server: {key_id: arguments}}
|
||||
else:
|
||||
raise SynapseError(404, "Not found %r" % request.postpath, Codes.NOT_FOUND)
|
||||
query = {server: {}}
|
||||
|
||||
await self.query_keys(request, query, query_remote_on_cache_miss=True)
|
||||
return 200, await self.query_keys(query, query_remote_on_cache_miss=True)
|
||||
|
||||
async def _async_render_POST(self, request: SynapseRequest) -> None:
|
||||
async def on_POST(self, request: Request) -> Tuple[int, JsonDict]:
|
||||
content = parse_json_object_from_request(request)
|
||||
|
||||
query = content["server_keys"]
|
||||
|
||||
await self.query_keys(request, query, query_remote_on_cache_miss=True)
|
||||
return 200, await self.query_keys(query, query_remote_on_cache_miss=True)
|
||||
|
||||
async def query_keys(
|
||||
self,
|
||||
request: SynapseRequest,
|
||||
query: JsonDict,
|
||||
query_remote_on_cache_miss: bool = False,
|
||||
) -> None:
|
||||
self, query: JsonDict, query_remote_on_cache_miss: bool = False
|
||||
) -> JsonDict:
|
||||
logger.info("Handling query for keys %r", query)
|
||||
|
||||
store_queries = []
|
||||
@@ -232,7 +245,7 @@ class RemoteKey(DirectServeJsonResource):
|
||||
for server_name, keys in cache_misses.items()
|
||||
),
|
||||
)
|
||||
await self.query_keys(request, query, query_remote_on_cache_miss=False)
|
||||
return await self.query_keys(query, query_remote_on_cache_miss=False)
|
||||
else:
|
||||
signed_keys = []
|
||||
for key_json_raw in json_results:
|
||||
@@ -244,6 +257,4 @@ class RemoteKey(DirectServeJsonResource):
|
||||
|
||||
signed_keys.append(key_json)
|
||||
|
||||
response = {"server_keys": signed_keys}
|
||||
|
||||
respond_with_json(request, 200, response, canonical_json=True)
|
||||
return {"server_keys": signed_keys}
|
||||
|
||||
@@ -201,7 +201,7 @@ class DataStore(
|
||||
name: Optional[str] = None,
|
||||
guests: bool = True,
|
||||
deactivated: bool = False,
|
||||
order_by: str = UserSortOrder.USER_ID.value,
|
||||
order_by: str = UserSortOrder.NAME.value,
|
||||
direction: str = "f",
|
||||
approved: bool = True,
|
||||
) -> Tuple[List[JsonDict], int]:
|
||||
@@ -261,6 +261,7 @@ class DataStore(
|
||||
sql_base = f"""
|
||||
FROM users as u
|
||||
LEFT JOIN profiles AS p ON u.name = '@' || p.user_id || ':' || ?
|
||||
LEFT JOIN erased_users AS eu ON u.name = eu.user_id
|
||||
{where_clause}
|
||||
"""
|
||||
sql = "SELECT COUNT(*) as total_users " + sql_base
|
||||
@@ -269,7 +270,8 @@ class DataStore(
|
||||
|
||||
sql = f"""
|
||||
SELECT name, user_type, is_guest, admin, deactivated, shadow_banned,
|
||||
displayname, avatar_url, creation_ts * 1000 as creation_ts, approved
|
||||
displayname, avatar_url, creation_ts * 1000 as creation_ts, approved,
|
||||
eu.user_id is not null as erased
|
||||
{sql_base}
|
||||
ORDER BY {order_by_column} {order}, u.name ASC
|
||||
LIMIT ? OFFSET ?
|
||||
@@ -277,6 +279,13 @@ class DataStore(
|
||||
args += [limit, start]
|
||||
txn.execute(sql, args)
|
||||
users = self.db_pool.cursor_to_dict(txn)
|
||||
|
||||
# some of those boolean values are returned as integers when we're on SQLite
|
||||
columns_to_boolify = ["erased"]
|
||||
for user in users:
|
||||
for column in columns_to_boolify:
|
||||
user[column] = bool(user[column])
|
||||
|
||||
return users, count
|
||||
|
||||
return await self.db_pool.runInteraction(
|
||||
|
||||
@@ -274,6 +274,13 @@ class DeviceWorkerStore(RoomMemberWorkerStore, EndToEndKeyWorkerStore):
|
||||
destination, int(from_stream_id)
|
||||
)
|
||||
if not has_changed:
|
||||
# debugging for https://github.com/matrix-org/synapse/issues/14251
|
||||
issue_8631_logger.debug(
|
||||
"%s: no change between %i and %i",
|
||||
destination,
|
||||
from_stream_id,
|
||||
now_stream_id,
|
||||
)
|
||||
return now_stream_id, []
|
||||
|
||||
updates = await self.db_pool.runInteraction(
|
||||
@@ -1848,7 +1855,7 @@ class DeviceStore(DeviceWorkerStore, DeviceBackgroundUpdateStore):
|
||||
self,
|
||||
txn: LoggingTransaction,
|
||||
user_id: str,
|
||||
device_ids: Iterable[str],
|
||||
device_id: str,
|
||||
hosts: Collection[str],
|
||||
stream_ids: List[int],
|
||||
context: Optional[Dict[str, str]],
|
||||
@@ -1864,6 +1871,21 @@ class DeviceStore(DeviceWorkerStore, DeviceBackgroundUpdateStore):
|
||||
stream_id_iterator = iter(stream_ids)
|
||||
|
||||
encoded_context = json_encoder.encode(context)
|
||||
mark_sent = not self.hs.is_mine_id(user_id)
|
||||
|
||||
values = [
|
||||
(
|
||||
destination,
|
||||
next(stream_id_iterator),
|
||||
user_id,
|
||||
device_id,
|
||||
mark_sent,
|
||||
now,
|
||||
encoded_context if whitelisted_homeserver(destination) else "{}",
|
||||
)
|
||||
for destination in hosts
|
||||
]
|
||||
|
||||
self.db_pool.simple_insert_many_txn(
|
||||
txn,
|
||||
table="device_lists_outbound_pokes",
|
||||
@@ -1876,23 +1898,21 @@ class DeviceStore(DeviceWorkerStore, DeviceBackgroundUpdateStore):
|
||||
"ts",
|
||||
"opentracing_context",
|
||||
),
|
||||
values=[
|
||||
(
|
||||
destination,
|
||||
next(stream_id_iterator),
|
||||
user_id,
|
||||
device_id,
|
||||
not self.hs.is_mine_id(
|
||||
user_id
|
||||
), # We only need to send out update for *our* users
|
||||
now,
|
||||
encoded_context if whitelisted_homeserver(destination) else "{}",
|
||||
)
|
||||
for destination in hosts
|
||||
for device_id in device_ids
|
||||
],
|
||||
values=values,
|
||||
)
|
||||
|
||||
# debugging for https://github.com/matrix-org/synapse/issues/14251
|
||||
if issue_8631_logger.isEnabledFor(logging.DEBUG):
|
||||
issue_8631_logger.debug(
|
||||
"Recorded outbound pokes for %s:%s with device stream ids %s",
|
||||
user_id,
|
||||
device_id,
|
||||
{
|
||||
stream_id: destination
|
||||
for (destination, stream_id, _, _, _, _, _) in values
|
||||
},
|
||||
)
|
||||
|
||||
def _add_device_outbound_room_poke_txn(
|
||||
self,
|
||||
txn: LoggingTransaction,
|
||||
@@ -1997,7 +2017,7 @@ class DeviceStore(DeviceWorkerStore, DeviceBackgroundUpdateStore):
|
||||
self._add_device_outbound_poke_to_stream_txn(
|
||||
txn,
|
||||
user_id=user_id,
|
||||
device_ids=[device_id],
|
||||
device_id=device_id,
|
||||
hosts=hosts,
|
||||
stream_ids=stream_ids,
|
||||
context=context,
|
||||
|
||||
@@ -707,8 +707,8 @@ class RoomMemberWorkerStore(EventsWorkerStore):
|
||||
|
||||
# 250 users is pretty arbitrary but the data can be quite large if users
|
||||
# are in many rooms.
|
||||
for user_ids in batch_iter(user_ids, 250):
|
||||
all_user_rooms.update(await self._get_rooms_for_users(user_ids))
|
||||
for batch_user_ids in batch_iter(user_ids, 250):
|
||||
all_user_rooms.update(await self._get_rooms_for_users(batch_user_ids))
|
||||
|
||||
return all_user_rooms
|
||||
|
||||
|
||||
@@ -395,8 +395,8 @@ class DeferredCache(Generic[KT, VT]):
|
||||
# _pending_deferred_cache.pop should either return a CacheEntry, or, in the
|
||||
# case of a TreeCache, a dict of keys to cache entries. Either way calling
|
||||
# iterate_tree_cache_entry on it will do the right thing.
|
||||
for entry in iterate_tree_cache_entry(entry):
|
||||
for cb in entry.get_invalidation_callbacks(key):
|
||||
for iter_entry in iterate_tree_cache_entry(entry):
|
||||
for cb in iter_entry.get_invalidation_callbacks(key):
|
||||
cb()
|
||||
|
||||
def invalidate_all(self) -> None:
|
||||
|
||||
@@ -432,7 +432,7 @@ class DeferredCacheListDescriptor(_CacheDescriptorBase):
|
||||
num_args = cached_method.num_args
|
||||
|
||||
if num_args != self.num_args:
|
||||
raise Exception(
|
||||
raise TypeError(
|
||||
"Number of args (%s) does not match underlying cache_method_name=%s (%s)."
|
||||
% (self.num_args, self.cached_method_name, num_args)
|
||||
)
|
||||
|
||||
@@ -79,7 +79,7 @@ class FederationReaderOpenIDListenerTests(HomeserverTestCase):
|
||||
self.assertEqual(channel.code, 401)
|
||||
|
||||
|
||||
@patch("synapse.app.homeserver.KeyApiV2Resource", new=Mock())
|
||||
@patch("synapse.app.homeserver.KeyResource", new=Mock())
|
||||
class SynapseHomeserverOpenIDListenerTests(HomeserverTestCase):
|
||||
def make_homeserver(self, reactor, clock):
|
||||
hs = self.setup_test_homeserver(
|
||||
|
||||
@@ -17,6 +17,7 @@ from unittest.mock import Mock
|
||||
|
||||
from synapse.api.room_versions import RoomVersions
|
||||
from synapse.federation.transport.client import SendJoinParser
|
||||
from synapse.util import ExceptionBundle
|
||||
|
||||
from tests.unittest import TestCase
|
||||
|
||||
@@ -121,10 +122,8 @@ class SendJoinParserTestCase(TestCase):
|
||||
# Send half of the data to the parser
|
||||
parser.write(serialisation[: len(serialisation) // 2])
|
||||
|
||||
# Close the parser. There should be _some_ kind of exception, but it need not
|
||||
# be that RuntimeError directly. E.g. we might want to raise a wrapper
|
||||
# encompassing multiple errors from multiple coroutines.
|
||||
with self.assertRaises(Exception):
|
||||
# Close the parser. There should be _some_ kind of exception.
|
||||
with self.assertRaises(ExceptionBundle):
|
||||
parser.finish()
|
||||
|
||||
# In any case, we should have tried to close both coros.
|
||||
|
||||
@@ -71,4 +71,4 @@ class TestBulkPushRuleEvaluator(unittest.HomeserverTestCase):
|
||||
|
||||
bulk_evaluator = BulkPushRuleEvaluator(self.hs)
|
||||
# should not raise
|
||||
self.get_success(bulk_evaluator.action_for_event_by_user(event, context))
|
||||
self.get_success(bulk_evaluator.action_for_events_by_user([(event, context)]))
|
||||
|
||||
@@ -371,7 +371,7 @@ class BaseMultiWorkerStreamTestCase(unittest.HomeserverTestCase):
|
||||
config=worker_hs.config.server.listeners[0],
|
||||
resource=resource,
|
||||
server_version_string="1",
|
||||
max_request_body_size=4096,
|
||||
max_request_body_size=8192,
|
||||
reactor=self.reactor,
|
||||
)
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ from synapse.api.room_versions import RoomVersions
|
||||
from synapse.rest.client import devices, login, logout, profile, register, room, sync
|
||||
from synapse.rest.media.v1.filepath import MediaFilePaths
|
||||
from synapse.server import HomeServer
|
||||
from synapse.types import JsonDict, UserID
|
||||
from synapse.types import JsonDict, UserID, create_requester
|
||||
from synapse.util import Clock
|
||||
|
||||
from tests import unittest
|
||||
@@ -924,6 +924,36 @@ class UsersListTestCase(unittest.HomeserverTestCase):
|
||||
self.assertEqual(1, len(non_admin_user_ids), non_admin_user_ids)
|
||||
self.assertEqual(not_approved_user, non_admin_user_ids[0])
|
||||
|
||||
def test_erasure_status(self) -> None:
|
||||
# Create a new user.
|
||||
user_id = self.register_user("eraseme", "eraseme")
|
||||
|
||||
# They should appear in the list users API, marked as not erased.
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
self.url + "?deactivated=true",
|
||||
access_token=self.admin_user_tok,
|
||||
)
|
||||
users = {user["name"]: user for user in channel.json_body["users"]}
|
||||
self.assertIs(users[user_id]["erased"], False)
|
||||
|
||||
# Deactivate that user, requesting erasure.
|
||||
deactivate_account_handler = self.hs.get_deactivate_account_handler()
|
||||
self.get_success(
|
||||
deactivate_account_handler.deactivate_account(
|
||||
user_id, erase_data=True, requester=create_requester(user_id)
|
||||
)
|
||||
)
|
||||
|
||||
# Repeat the list users query. They should now be marked as erased.
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
self.url + "?deactivated=true",
|
||||
access_token=self.admin_user_tok,
|
||||
)
|
||||
users = {user["name"]: user for user in channel.json_body["users"]}
|
||||
self.assertIs(users[user_id]["erased"], True)
|
||||
|
||||
def _order_test(
|
||||
self,
|
||||
expected_user_list: List[str],
|
||||
@@ -1195,6 +1225,7 @@ class DeactivateAccountTestCase(unittest.HomeserverTestCase):
|
||||
self.assertEqual("foo@bar.com", channel.json_body["threepids"][0]["address"])
|
||||
self.assertEqual("mxc://servername/mediaid", channel.json_body["avatar_url"])
|
||||
self.assertEqual("User1", channel.json_body["displayname"])
|
||||
self.assertFalse(channel.json_body["erased"])
|
||||
|
||||
# Deactivate and erase user
|
||||
channel = self.make_request(
|
||||
@@ -1219,6 +1250,7 @@ class DeactivateAccountTestCase(unittest.HomeserverTestCase):
|
||||
self.assertEqual(0, len(channel.json_body["threepids"]))
|
||||
self.assertIsNone(channel.json_body["avatar_url"])
|
||||
self.assertIsNone(channel.json_body["displayname"])
|
||||
self.assertTrue(channel.json_body["erased"])
|
||||
|
||||
self._is_erased("@user:test", True)
|
||||
|
||||
@@ -2757,6 +2789,7 @@ class UserRestTestCase(unittest.HomeserverTestCase):
|
||||
self.assertIn("avatar_url", content)
|
||||
self.assertIn("admin", content)
|
||||
self.assertIn("deactivated", content)
|
||||
self.assertIn("erased", content)
|
||||
self.assertIn("shadow_banned", content)
|
||||
self.assertIn("creation_ts", content)
|
||||
self.assertIn("appservice_id", content)
|
||||
|
||||
@@ -26,7 +26,7 @@ from twisted.web.resource import NoResource, Resource
|
||||
|
||||
from synapse.crypto.keyring import PerspectivesKeyFetcher
|
||||
from synapse.http.site import SynapseRequest
|
||||
from synapse.rest.key.v2 import KeyApiV2Resource
|
||||
from synapse.rest.key.v2 import KeyResource
|
||||
from synapse.server import HomeServer
|
||||
from synapse.storage.keys import FetchKeyResult
|
||||
from synapse.types import JsonDict
|
||||
@@ -46,7 +46,7 @@ class BaseRemoteKeyResourceTestCase(unittest.HomeserverTestCase):
|
||||
|
||||
def create_test_resource(self) -> Resource:
|
||||
return create_resource_tree(
|
||||
{"/_matrix/key/v2": KeyApiV2Resource(self.hs)}, root_resource=NoResource()
|
||||
{"/_matrix/key/v2": KeyResource(self.hs)}, root_resource=NoResource()
|
||||
)
|
||||
|
||||
def expect_outgoing_key_request(
|
||||
|
||||
@@ -1037,5 +1037,5 @@ class CachedListDescriptorTestCase(unittest.TestCase):
|
||||
obj = Cls()
|
||||
|
||||
# Make sure this raises an error about the arg mismatch
|
||||
with self.assertRaises(Exception):
|
||||
with self.assertRaises(TypeError):
|
||||
obj.list_fn([("foo", "bar")])
|
||||
|
||||
Reference in New Issue
Block a user