From 9a87ff9c00e97fe9b59f5ea5345ac4d464e9784d Mon Sep 17 00:00:00 2001 From: Kim Brose <2803622+HarHarLinks@users.noreply.github.com> Date: Mon, 5 Jan 2026 20:09:00 +0000 Subject: [PATCH] enable linting MD031 blank lines around code fences (#3133) Signed-off-by: HarHarLinks <2803622+HarHarLinks@users.noreply.github.com> --- .rumdl.toml | 2 +- CONTENT.md | 2 ++ .../03/2020-03-23-synapse-1-12-0-released.md | 2 ++ ...unication-service-with-matrix-and-jitsi.md | 1 + ...andwidth-matrix-an-implementation-guide.md | 11 ++++++- ...-03-type-coverage-for-sydent-motivation.md | 2 ++ ...-10-type-coverage-for-sydent-annotation.md | 1 + ...-17-type-coverage-for-sydent-evaluation.md | 4 +++ content/docs/older/e2ee-cross-signing.md | 30 +++++++++++++++++++ .../docs/spec-guides/state-res-2.1/_index.md | 1 + 10 files changed, 54 insertions(+), 2 deletions(-) diff --git a/.rumdl.toml b/.rumdl.toml index 5b59d9443..2d2ac2f98 100644 --- a/.rumdl.toml +++ b/.rumdl.toml @@ -6,7 +6,7 @@ # disable = ["MD013", "MD033"] # List of rules to enable exclusively (if provided, only these rules will run) -enable = ["MD001", "MD003", "MD011", "MD030", "MD034", "MD039"] +enable = ["MD001", "MD003", "MD011", "MD030", "MD031", "MD034", "MD039"] # List of file/directory patterns to include for linting (if provided, only these will be linted) # include = [ diff --git a/CONTENT.md b/CONTENT.md index 61fef02fa..48e779f63 100644 --- a/CONTENT.md +++ b/CONTENT.md @@ -99,11 +99,13 @@ In your markdown file, add this line to embed the YouTube player in a way that r ```jinja {{ youtube_player(video_id="S1nBXjWWHoU") }} ``` + You can also provide a start time using `start` and noscript-text using `noscript_text`, e.g. ```jinja {{ youtube_player(video_id="Xje32fIIUyg",start="1240",noscript_text="Matrix Live S11E05 - Project Hydra") }} ``` + which will start the video at 20:40 and add custom text for users with JavaScript disabled. ### Adding a picture for the socials diff --git a/content/blog/2020/03/2020-03-23-synapse-1-12-0-released.md b/content/blog/2020/03/2020-03-23-synapse-1-12-0-released.md index 8a788bbe7..a2a2b4ad4 100644 --- a/content/blog/2020/03/2020-03-23-synapse-1-12-0-released.md +++ b/content/blog/2020/03/2020-03-23-synapse-1-12-0-released.md @@ -60,9 +60,11 @@ installation remains secure. * Administrators who have [installed Synapse from source](https://github.com/matrix-org/synapse/blob/master/INSTALL.md#installing-from-source) should upgrade Twisted within their virtualenv by running: + ```sh /bin/pip install 'Twisted>=20.3.0' ``` + * Administrators who have installed Synapse from distribution packages should consult the information from their distributions. diff --git a/content/blog/2020/04/2020-04-06-running-your-own-secure-communication-service-with-matrix-and-jitsi.md b/content/blog/2020/04/2020-04-06-running-your-own-secure-communication-service-with-matrix-and-jitsi.md index 2852a6bdd..339e98c46 100644 --- a/content/blog/2020/04/2020-04-06-running-your-own-secure-communication-service-with-matrix-and-jitsi.md +++ b/content/blog/2020/04/2020-04-06-running-your-own-secure-communication-service-with-matrix-and-jitsi.md @@ -95,6 +95,7 @@ echo '{ "m.server": "matrix.dangerousdemos.net:443" }' > server ``` * **Alternatively**, you could advertise the server via DNS, if you don't have write access to `/.well-known` on your main domain. However, to prove you are allowed to host the Matrix traffic for dangerousdemos.net, you would have to configure nginx to use the dangerousdemos.net TLS certificate for the matrix.dangerousdemos.net vhost (i.e. the "wrong" one), and in general we think that `/.well-known` is much easier to reason about. In this case you would advertise the server with an SRV record like this: + ``` _matrix._tcp.dangerousdemos.net. 300 IN SRV 10 5 443 matrix.dangerousdemos.net. ``` diff --git a/content/blog/2021/06/2021-06-10-low-bandwidth-matrix-an-implementation-guide.md b/content/blog/2021/06/2021-06-10-low-bandwidth-matrix-an-implementation-guide.md index c1b7c66e6..510048099 100644 --- a/content/blog/2021/06/2021-06-10-low-bandwidth-matrix-an-implementation-guide.md +++ b/content/blog/2021/06/2021-06-10-low-bandwidth-matrix-an-implementation-guide.md @@ -42,19 +42,24 @@ Steps: - Build the low bandwidth proxy: `go build ./cmd/proxy` - Generate a elliptic curve DTLS key/certificate: (we use curve keys as they are smaller than RSA keys, but both work.) + ```bash openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem openssl req -new -x509 -key private-key.pem -out cert.pem -days 365 # you now have cert.pem and private-key.pem ``` + - Run it pointing at matrix.org: + ```bash ./proxy -local 'https://matrix-client.matrix.org' \ --tls-cert cert.pem --tls-key private-key.pem \ --advertise "http://127.0.0.1:8008" \ --dtls-bind-addr :8008 ``` + - You should see something like this: + ``` INFO[0000] Listening on :8008/tcp to reverse proxy from http://127.0.0.1:8008 to https://matrix-client.matrix.org - HTTPS enabled: false INFO[0000] Listening for DTLS on :8008 - ACK piggyback period: 5s @@ -65,6 +70,7 @@ not LibreSSL which comes by default: `openssl version`. To use OpenSSL, `brew in then dumps the binary to `/usr/local/opt/openssl/bin/openssl`. To test it is working correctly: + ```bash # build command line tools we can use to act as a low bandwidth client go build ./cmd/jc @@ -111,18 +117,22 @@ Steps: - Clone the low bandwidth repo if you haven't already: `git clone https://github.com/matrix-org/lb.git` - In the low bandwidth repo, build the mobile bindings: + ``` go get golang.org/x/mobile/cmd/gomobile cd mobile # if gomobile isn't on your path, then ~/go/bin/gomobile gomobile bind -target=android ``` + - Copy the output files to a directory in the Element Android repo which Gradle will pick up: + ``` mkdir $PATH_TO_ELEMENT_ANDROID_REPO/matrix-sdk-android/libs cp mobile-sources.jar $PATH_TO_ELEMENT_ANDROID_REPO/matrix-sdk-android/libs cp mobile.aar $PATH_TO_ELEMENT_ANDROID_REPO/matrix-sdk-android/libs ``` + - Open the project in Android Studio. - Build and run on a device/emulator. - Configure the proxy's `--advertise` address. If you are running on a local device, restart the @@ -171,4 +181,3 @@ and receive the response, including connection setup: network with so much data that the sync stream begins to fall behind. Future work will look to optimise the sync API. - The proxy currently doesn't implement the [low bandwidth response](https://github.com/matrix-org/matrix-doc/blob/kegan/low-bandwidth/proposals/3079-low-bandwidth-csapi.md#versioning) in `/versions`. - diff --git a/content/blog/2021/12/2021-12-03-type-coverage-for-sydent-motivation.md b/content/blog/2021/12/2021-12-03-type-coverage-for-sydent-motivation.md index 5884e1156..ff441e4a0 100644 --- a/content/blog/2021/12/2021-12-03-type-coverage-for-sydent-motivation.md +++ b/content/blog/2021/12/2021-12-03-type-coverage-for-sydent-motivation.md @@ -111,6 +111,8 @@ In this sample, `resp.headers` is a [twisted.web.http_headers.Headers](https://t headers = dict(resp.headers.getAllRawHeaders()) reveal_type(headers) ``` + + ``` $ mypy sydent/sms/openmarket.py:110: note: Revealed type is "builtins.dict[builtins.bytes*, typing.Sequence*[builtins.bytes]]" diff --git a/content/blog/2021/12/2021-12-10-type-coverage-for-sydent-annotation.md b/content/blog/2021/12/2021-12-10-type-coverage-for-sydent-annotation.md index ea5df0240..374b45d58 100644 --- a/content/blog/2021/12/2021-12-10-type-coverage-for-sydent-annotation.md +++ b/content/blog/2021/12/2021-12-10-type-coverage-for-sydent-annotation.md @@ -93,6 +93,7 @@ and later, [the IResponse](https://github.com/matrix-org/sydent/blob/e4b4dbbdf25 res: IResponse res = yield agent.request(method, uri, headers, bodyProducer) ``` + - In this example: - We yield a value `y: Deferred[Any]`. diff --git a/content/blog/2021/12/2021-12-17-type-coverage-for-sydent-evaluation.md b/content/blog/2021/12/2021-12-17-type-coverage-for-sydent-evaluation.md index c02205cb8..5cafdd9eb 100644 --- a/content/blog/2021/12/2021-12-17-type-coverage-for-sydent-evaluation.md +++ b/content/blog/2021/12/2021-12-17-type-coverage-for-sydent-evaluation.md @@ -198,6 +198,7 @@ After the sprint to improve coverage, I spent a short amount of time trying the - Didn't seem to recognise `getLogger` as being imported from `logging`. Not sure what happened there—maybe something wrong with its bundled version of `typeshed`? - In a few places, Sydent uses `urllib.parse.quote` but only imports `urllib`. We must be unintentionally relying on our dependencies to `import urllib.parse` somewhere! Mypy didn't complain about this; pyright did. - Seemed to give a better explanations of why complex types were incompatible. For example: + ``` /home/dmr/workspace/sydent/sydent/replication/pusher.py /home/dmr/workspace/sydent/sydent/replication/pusher.py:77:16 - error: Expression of type "DeferredList" cannot be assigned to return type "Deferred[List[Tuple[bool, None]]]" @@ -212,8 +213,10 @@ After the sprint to improve coverage, I spent a short amount of time trying the Type "_KT@dict" is incompatible with constrained type variable "AnyStr" Type cannot be assigned to type "None" (reportGeneralTypeIssues) ``` + This would have been really helpful when interpreting mypy's error reports; I'd love to see something like it in mypy. Here's another example where I tried running against a Synapse file. + ``` /home/dmr/workspace/synapse/synapse/storage/databases/main/cache.py /home/dmr/workspace/synapse/synapse/storage/databases/main/cache.py:103:53 - error: Expression of type "list[tuple[Unknown, Tuple[Unknown, ...]]]" cannot be assigned to declared type "List[Tuple[int, _CacheData]]" @@ -221,6 +224,7 @@ After the sprint to improve coverage, I spent a short amount of time trying the     Tuple entry 2 is incorrect type       Tuple size mismatch; expected 3 but received indeterminate number (reportGeneralTypeIssues) ``` + This is really valuable information. It's worth considering Pyright as an option to get a second opinion! - It looks like Pyright's name for `Any` is `Unknown`. I think that does a better job of emphasising that `Unknown` won't be type checked. I'd certainly be more reluctant to type `x: Unknown` versus `x: Any`! - Pyright is the machinery behind [Pylance](https://github.com/microsoft/pylance-release), which drives [VS Code's Python extension](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance). That alone probably makes it worthy of more eyes. diff --git a/content/docs/older/e2ee-cross-signing.md b/content/docs/older/e2ee-cross-signing.md index 02979d5d0..a9e33c749 100644 --- a/content/docs/older/e2ee-cross-signing.md +++ b/content/docs/older/e2ee-cross-signing.md @@ -92,7 +92,9 @@ containing your own device ID. A payload such as "foo": "bar" } ``` + would thus look like: + ```json { "foo": "bar", @@ -104,6 +106,7 @@ would thus look like: For room messages, the transaction ID, which is the event Id of the first event, is added in the `m.relates_to` section of the event. The device ID is the same as to_device massages; it should be set to the ID of the sending device. So the above payload becomes: + ```json { "foo": "bar", @@ -125,12 +128,14 @@ typically depends on whether the room they are sent in is encrypted or not. #### `m.key.verification.request` Sending this starts a verification request. It sends all the verification methods you know (in the case of SAS that is only `m.sas.v1`), along with the current timestamp in milliseconds. + ```json { "methods": ["m.sas.v1"], "timestamp": 1590314157821 } ``` + A receiving client is expected to reject the request if it is more than 10 minutes in the past or more than 5 minutes in the future. @@ -138,6 +143,7 @@ than 5 minutes in the future. Sending this indicates that you accept the key verification request and additionally reveals which methods you support yourself. That way both verification partners will be able to figure out which methods they have in common. + ```json { "methods": ["m.sas.v1"], @@ -147,6 +153,7 @@ methods they have in common. #### `m.key.verification.start` Sending this indicates that you are starting verification with a specific method. The exact payload is dependent on the verification method. + ```json { "method": "m.sas.v1", @@ -156,6 +163,7 @@ is dependent on the verification method. #### `m.key.verification.done` Sending this indicates that the verification process is *fully* done. + ```json {} ``` @@ -163,6 +171,7 @@ Sending this indicates that the verification process is *fully* done. #### `m.key.verification.cancel` Sending this cancels the verification (timeout, key mismatch, user cancellation, etc.). It has a human-readable reason, along with a cancellation code. + ```json { "reason": "The verification timed out", @@ -223,6 +232,7 @@ SAS introduces a few more cancellation codes, specific to SAS verification, This sends a bunch of parameters that the sending device supports. Please note that you will have to remember this object while performing a commitment check (explained in the next section), of the one that *includes* the metadata of `transaction_id` and `from_device` keys, omitted in these examples. + ```json { "method": "m.sas.v1", @@ -238,6 +248,7 @@ A commitment is an additional verification process. It is the hash (based on the specified) of the concatenated ephemeral public key you generate and the canonical json of the `m.key.verification.start` body. Libolm provides both the hashing method and the public/private key generation. Code for calculating the commitment could look as follows: + ```dart var sas = olm.SAS(); // save for later. This will generate our ephemeral public/private keypair var canonicalJson = ""; // the canonical json of the `m.key.verification.start` request @@ -255,6 +266,7 @@ if (hashMethod == "sha256") { #### `m.key.verification.accept` This accepts the `m.key.verification.start` request, and sends the parameters that both parties support. Along with that, it also sends a `commitment`, as defined above. + ```json { "method": "m.sas.v1", @@ -273,6 +285,7 @@ Be sure that if you received the commitment, you use the received public key to you received earlier. The public key is both added to the `sas` object with `sas.set_their_key(payload["key"]);` and also saved in a separate variable, as you'll need it later, as unfortunately the `sas` object does not allow for it to be retrieved again. + ```json { "key": "your-public-key" @@ -333,6 +346,7 @@ master cross-signing key. For that, a base information is created, which is the `MATRIX_KEY_VERIFICATION_MAC`, your own user ID, your own device ID, the other user's ID, the other device's ID, and the transaction ID. Note how, unlike SAS, no `|` delimiter is used and the order does *not* depend on who started the verification: + ```dart var baseInfo = 'MATRIX_KEY_VERIFICATION_MAC' + client.userID + @@ -343,6 +357,7 @@ var baseInfo = 'MATRIX_KEY_VERIFICATION_MAC' + ``` Next calculate the MAC of your device IDs and the fingerprints that you want to send: + ```dart String _calculateMac(String input, String info) { if (messageAuthenticationCode == "hkdf-hmac-sha256") { // this is from the m.key.verification.accept call @@ -384,6 +399,7 @@ After receiving the MAC and having the user verify that the emoji match (and thu your own MAC), you have to verify that the received MACs are valid, and only verify the keys if the MACs are valid. For that, generate the base info from the perspective of the other party; essentially placing other person's information before your own: + ```dart final baseInfo = 'MATRIX_KEY_VERIFICATION_MAC' + request.userId + @@ -392,8 +408,10 @@ final baseInfo = 'MATRIX_KEY_VERIFICATION_MAC' + client.deviceID + request.transactionId; ``` + Then generate the key list out of the dictionary keys of the `mac` object received and verify that the MAC matches up: + ```dart final keyList = payload["mac"].keys.toList(); keyList.sort(); @@ -402,6 +420,7 @@ if (payload["keys"] != _calculateMac(keyList.join(","), baseInfo + "KEY_IDS")) { return; } ``` + Then verify the MACs of the keys themselves by iterating over the objects, and calculating the MACs of the keys again as above. You should have the public key yourself already, as you are just verifying if the key matches. If you received the MAC of a key you don't know, just ignore it. It is likely to @@ -487,6 +506,7 @@ and update your `device_keys` dictionary accordingly, just as before. This endpo return the `master_keys`, `self_signing_keys` and `user_signing_keys` of a user, given they are using cross-signing. Simply update and store this information locally as well. The format of these are pretty similar to the `device_keys` dictionary: + ```json { "self_signing_keys": { @@ -505,6 +525,7 @@ pretty similar to the `device_keys` dictionary: } } ``` + In this example we have Bob's self-signing key which has a signature of Bob's master key. The `usage` array additionally indicates the usage of the key, which is `master`, `self_signing` or `user_signing`. While for cross-signing there should only be one item in `usage`, in the future some other keys might be added @@ -644,6 +665,7 @@ provided you have that secret cached. #### `m.secret.request` This requests a secret from another device, or cancels a pending request. + ```json { "action": "request", // or request_cancellation @@ -655,6 +677,7 @@ This requests a secret from another device, or cancels a pending request. #### `m.secret.send` This sends / shares a secret with another device + ```json { "request_id": "", @@ -955,6 +978,7 @@ and `signature` keys and sign the canonical json encoded object. Afterwards you server. For example, you want to sign the following device key: + ```json { "user_id": "@alice:example.com", @@ -980,6 +1004,7 @@ For example, you want to sign the following device key: ``` Then you strip the `signatures` and `unsigned` keys: + ```json { "user_id": "@alice:example.com", @@ -998,11 +1023,13 @@ Then you strip the `signatures` and `unsigned` keys: ``` And then the canonical json you need to sign is: + ``` {"algorithms":["m.olm.v1.curve25519-aes-sha2","m.megolm.v1.aes-sha2"],"device_id":"JLAFKJWSCS","keys":{"curve25519:JLAFKJWSCS":"3C5BFWi2Y8MaVvjM8M22DBmh24PmgR0nPvJOIArzgyI","ed25519:JLAFKJWSCS":"lEuiRJBit0IG6nUf5pUzWTUEsRVVe/HJkoKuEww9ULI"},"user_id":"@alice:example.com"} ``` You can easily sign a key with libolm: + ```dart String sign(String canonicalJson, Uint8List key) { final keyObj = olm.PkSigning(); @@ -1120,6 +1147,7 @@ support in-room verification. As the content of such an `m.room.message` for Alice to start an in-room verification request with Bob could look as follows: + ```json { "methods": [ @@ -1139,6 +1167,7 @@ property is still added as usual. As transaction ID the event ID of the original request is used. That, however, is added in an `m.relates_to` block as follows: + ```json { // other content of that specific type @@ -1229,6 +1258,7 @@ you can just base64 the randomly generated salt. After that, you use PBKDF2 to get the key from the passphrase, and calculate the MAC and IV. Code for generating the key could look as follows: + ```dart // "passphrase" is the passphrase by the user diff --git a/content/docs/spec-guides/state-res-2.1/_index.md b/content/docs/spec-guides/state-res-2.1/_index.md index 82470a0f5..7d58e050a 100644 --- a/content/docs/spec-guides/state-res-2.1/_index.md +++ b/content/docs/spec-guides/state-res-2.1/_index.md @@ -20,6 +20,7 @@ implemented. This is a trivial change to make. When performing the initial iterative auth checks, replace the unconflicted set with the empty set: + ```py resolved_state = await _iterative_auth_checks( clock,