Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e197315d2 | |||
| 18e43e1d35 | |||
| 09fca89ac5 | |||
| 9f19a2025d | |||
| 6b918966d4 | |||
| 328502c1cd | |||
| d15e461303 | |||
| 6946eead28 | |||
| 09d3240365 | |||
| 653ec3799e | |||
| 6de9f52d5a | |||
| 484e7d1d2a | |||
| dfa01541b3 | |||
| adbe9268ce | |||
| 3504e6e724 | |||
| 154b2ab490 | |||
| 2231ccf118 | |||
| d4d9f92ade | |||
| e4e1636da8 | |||
| e99aac9550 | |||
| ddb87168ed | |||
| 245c34e659 | |||
| 43b07be3fc |
+13
-13
@@ -235,20 +235,20 @@ jobs:
|
|||||||
name: Docker publish
|
name: Docker publish
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs: build
|
||||||
if: startsWith('refs/tags/v', github.ref) || github.ref == 'refs/heads/main' || (github.event_name == 'pull_request' && github.event.pull_request.draft == false)
|
if: (startsWith('refs/tags/v', github.ref) || github.ref == 'refs/heads/main' || (github.event_name == 'pull_request' && github.event.pull_request.draft == false)) && (vars.DOCKER_USERNAME != '') && (vars.GITLAB_USERNAME != '')
|
||||||
env:
|
env:
|
||||||
DOCKER_ARM64: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}-arm64v8
|
DOCKER_ARM64: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-arm64v8
|
||||||
DOCKER_AMD64: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}-amd64
|
DOCKER_AMD64: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-amd64
|
||||||
DOCKER_TAG: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}
|
DOCKER_TAG: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
|
||||||
DOCKER_BRANCH: docker.io/${{ github.repository }}:${{ (startsWith('refs/tags/v', github.ref) && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}
|
DOCKER_BRANCH: docker.io/${{ github.repository }}:${{ (startsWith('refs/tags/v', github.ref) && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
|
||||||
GHCR_ARM64: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}-arm64v8
|
GHCR_ARM64: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-arm64v8
|
||||||
GHCR_AMD64: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}-amd64
|
GHCR_AMD64: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-amd64
|
||||||
GHCR_TAG: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}
|
GHCR_TAG: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
|
||||||
GHCR_BRANCH: ghcr.io/${{ github.repository }}:${{ (startsWith('refs/tags/v', github.ref) && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}
|
GHCR_BRANCH: ghcr.io/${{ github.repository }}:${{ (startsWith('refs/tags/v', github.ref) && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
|
||||||
GLCR_ARM64: registry.gitlab.com/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}-arm64v8
|
GLCR_ARM64: registry.gitlab.com/conduwuit/conduwuit:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-arm64v8
|
||||||
GLCR_AMD64: registry.gitlab.com/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}-amd64
|
GLCR_AMD64: registry.gitlab.com/conduwuit/conduwuit:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-amd64
|
||||||
GLCR_TAG: registry.gitlab.com/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}-${{ github.sha }}
|
GLCR_TAG: registry.gitlab.com/conduwuit/conduwuit:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
|
||||||
GLCR_BRANCH: registry.gitlab.com/${{ github.repository }}:${{ (startsWith('refs/tags/v', github.ref) && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.head_ref)) || github.ref_name }}
|
GLCR_BRANCH: registry.gitlab.com/conduwuit/conduwuit:${{ (startsWith('refs/tags/v', github.ref) && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
|
||||||
|
|
||||||
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
|
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Run Trivy code and vulnerability scanner on repo
|
- name: Run Trivy code and vulnerability scanner on repo
|
||||||
uses: aquasecurity/trivy-action@0.19.0
|
uses: aquasecurity/trivy-action@0.20.0
|
||||||
with:
|
with:
|
||||||
scan-type: repo
|
scan-type: repo
|
||||||
format: sarif
|
format: sarif
|
||||||
@@ -34,7 +34,7 @@ jobs:
|
|||||||
severity: CRITICAL,HIGH,MEDIUM,LOW
|
severity: CRITICAL,HIGH,MEDIUM,LOW
|
||||||
|
|
||||||
- name: Run Trivy code and vulnerability scanner on filesystem
|
- name: Run Trivy code and vulnerability scanner on filesystem
|
||||||
uses: aquasecurity/trivy-action@0.19.0
|
uses: aquasecurity/trivy-action@0.20.0
|
||||||
with:
|
with:
|
||||||
scan-type: fs
|
scan-type: fs
|
||||||
format: sarif
|
format: sarif
|
||||||
|
|||||||
+3
-1
@@ -52,6 +52,8 @@ conduwuit's website uses [`mdbook`][mdbook] and deployed via CI using GitHub Pag
|
|||||||
|
|
||||||
To build the documentation using Nix, run: `bin/nix-build-and-cache just .#book`
|
To build the documentation using Nix, run: `bin/nix-build-and-cache just .#book`
|
||||||
|
|
||||||
|
The output of the mdbook generation is in `result/`. mdbooks can be opened in your browser from the individual HTML files without any web server needed.
|
||||||
|
|
||||||
### Inclusivity and Diversity
|
### Inclusivity and Diversity
|
||||||
|
|
||||||
All **MUST** code and write with inclusivity and diversity in mind. See the [following page by Google on writing inclusive code and documentation](https://developers.google.com/style/inclusive-documentation).
|
All **MUST** code and write with inclusivity and diversity in mind. See the [following page by Google on writing inclusive code and documentation](https://developers.google.com/style/inclusive-documentation).
|
||||||
@@ -68,7 +70,7 @@ Rust's default style and standards with regards to [function names, variable nam
|
|||||||
|
|
||||||
### Creating pull requests
|
### Creating pull requests
|
||||||
|
|
||||||
Please try to keep contributions to the GitHub. While the mirrors of conduwuit allow for pull/merge requests, there is no guarantee I will see them in a timely manner.
|
Please try to keep contributions to the GitHub. While the mirrors of conduwuit allow for pull/merge requests, there is no guarantee I will see them in a timely manner. Additionally, please mark WIP or unfinished or incomplete PRs as drafts. This prevents me from having to ping once in a while to double check the status of it, especially when the CI completed successfully and everything so it *looks* done.
|
||||||
|
|
||||||
If you open a pull request on one of the mirrors, it is your responsibility to inform me about its existence. In the future I may try to solve this with more repo bots in the conduwuit Matrix room. There is no mailing list or email-patch support on the sr.ht mirror, but if you'd like to email me a git patch you can do so at `strawberry@puppygock.gay`.
|
If you open a pull request on one of the mirrors, it is your responsibility to inform me about its existence. In the future I may try to solve this with more repo bots in the conduwuit Matrix room. There is no mailing list or email-patch support on the sr.ht mirror, but if you'd like to email me a git patch you can do so at `strawberry@puppygock.gay`.
|
||||||
|
|
||||||
|
|||||||
Generated
+84
-35
@@ -568,7 +568,7 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "conduit"
|
name = "conduit"
|
||||||
version = "0.3.2"
|
version = "0.3.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argon2",
|
"argon2",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -594,6 +594,7 @@ dependencies = [
|
|||||||
"hyper 1.3.1",
|
"hyper 1.3.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"image",
|
"image",
|
||||||
|
"infer",
|
||||||
"ipaddress",
|
"ipaddress",
|
||||||
"itertools",
|
"itertools",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
@@ -614,6 +615,7 @@ dependencies = [
|
|||||||
"ruma-identifiers-validation",
|
"ruma-identifiers-validation",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"rust-rocksdb",
|
"rust-rocksdb",
|
||||||
|
"sanitize-filename",
|
||||||
"sd-notify",
|
"sd-notify",
|
||||||
"sentry",
|
"sentry",
|
||||||
"sentry-tower",
|
"sentry-tower",
|
||||||
@@ -949,6 +951,17 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "find-folly"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d8bf7ad55e1e290ef089eaaa62c5ac3b86c5c6279c37fa67943937d108b01ef"
|
||||||
|
dependencies = [
|
||||||
|
"pkg-config",
|
||||||
|
"shlex",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "findshlibs"
|
name = "findshlibs"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@@ -1357,16 +1370,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "html5ever"
|
name = "html5ever"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
|
checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"mac",
|
"mac",
|
||||||
"markup5ever",
|
"markup5ever",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 2.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1605,6 +1618,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "infer"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inlinable_string"
|
name = "inlinable_string"
|
||||||
version = "0.1.15"
|
version = "0.1.15"
|
||||||
@@ -1885,9 +1904,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markup5ever"
|
name = "markup5ever"
|
||||||
version = "0.11.0"
|
version = "0.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016"
|
checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"phf",
|
"phf",
|
||||||
@@ -1899,9 +1918,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markup5ever_rcdom"
|
name = "markup5ever_rcdom"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9521dd6750f8e80ee6c53d65e2e4656d7de37064f3a7a5d2d11d05df93839c2"
|
checksum = "edaa21ab3701bfee5099ade5f7e1f84553fd19228cf332f13cd6e964bf59be18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"html5ever",
|
"html5ever",
|
||||||
"markup5ever",
|
"markup5ever",
|
||||||
@@ -2332,21 +2351,21 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf"
|
name = "phf"
|
||||||
version = "0.10.1"
|
version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
|
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_shared",
|
"phf_shared 0.11.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_codegen"
|
name = "phf_codegen"
|
||||||
version = "0.10.0"
|
version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
|
checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_generator",
|
"phf_generator 0.11.2",
|
||||||
"phf_shared",
|
"phf_shared 0.11.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2355,7 +2374,17 @@ version = "0.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
|
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_shared",
|
"phf_shared 0.10.0",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_generator"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
|
||||||
|
dependencies = [
|
||||||
|
"phf_shared 0.11.2",
|
||||||
"rand",
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2368,6 +2397,15 @@ dependencies = [
|
|||||||
"siphasher",
|
"siphasher",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.1.5"
|
version = "1.1.5"
|
||||||
@@ -2906,11 +2944,12 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-librocksdb-sys"
|
name = "rust-librocksdb-sys"
|
||||||
version = "0.21.0+9.1.1"
|
version = "0.21.0+9.1.1"
|
||||||
source = "git+https://github.com/zaidoon1/rust-rocksdb?branch=master#c5cd6bd25152ef1f8a488761351da0c3d29ed93a"
|
source = "git+https://github.com/girlbossceo/rust-rocksdb-zaidoon1?rev=9ecb597d966efb37ed96f4cfe3f09165013fd14a#9ecb597d966efb37ed96f4cfe3f09165013fd14a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bindgen",
|
"bindgen",
|
||||||
"bzip2-sys",
|
"bzip2-sys",
|
||||||
"cc",
|
"cc",
|
||||||
|
"find-folly",
|
||||||
"glob",
|
"glob",
|
||||||
"libc",
|
"libc",
|
||||||
"libz-sys",
|
"libz-sys",
|
||||||
@@ -2923,7 +2962,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-rocksdb"
|
name = "rust-rocksdb"
|
||||||
version = "0.25.0"
|
version = "0.25.0"
|
||||||
source = "git+https://github.com/zaidoon1/rust-rocksdb?branch=master#c5cd6bd25152ef1f8a488761351da0c3d29ed93a"
|
source = "git+https://github.com/girlbossceo/rust-rocksdb-zaidoon1?rev=9ecb597d966efb37ed96f4cfe3f09165013fd14a#9ecb597d966efb37ed96f4cfe3f09165013fd14a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"rust-librocksdb-sys",
|
"rust-librocksdb-sys",
|
||||||
@@ -3047,6 +3086,16 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sanitize-filename"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "schannel"
|
name = "schannel"
|
||||||
version = "0.1.23"
|
version = "0.1.23"
|
||||||
@@ -3244,18 +3293,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.200"
|
version = "1.0.201"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f"
|
checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.200"
|
version = "1.0.201"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb"
|
checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -3277,9 +3326,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.116"
|
version = "1.0.117"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
|
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@@ -3480,7 +3529,7 @@ dependencies = [
|
|||||||
"new_debug_unreachable",
|
"new_debug_unreachable",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"phf_shared",
|
"phf_shared 0.10.0",
|
||||||
"precomputed-hash",
|
"precomputed-hash",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -3491,8 +3540,8 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
|
checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_generator",
|
"phf_generator 0.10.0",
|
||||||
"phf_shared",
|
"phf_shared 0.10.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
]
|
]
|
||||||
@@ -3559,18 +3608,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.59"
|
version = "1.0.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
|
checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.59"
|
version = "1.0.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
|
checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -4277,9 +4326,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpage"
|
name = "webpage"
|
||||||
version = "2.0.0"
|
version = "2.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fb86b12e58d490a99867f561ce8466ffa7b73e24d015a8e7f5bc111d4424ba2"
|
checksum = "70862efc041d46e6bbaa82bb9c34ae0596d090e86cbd14bd9e93b36ee6802eac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"html5ever",
|
"html5ever",
|
||||||
"markup5ever_rcdom",
|
"markup5ever_rcdom",
|
||||||
@@ -4549,9 +4598,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xml5ever"
|
name = "xml5ever"
|
||||||
version = "0.17.0"
|
version = "0.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4034e1d05af98b51ad7214527730626f019682d797ba38b51689212118d8e650"
|
checksum = "7c376f76ed09df711203e20c3ef5ce556f0166fa03d39590016c0fd625437fad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"mac",
|
"mac",
|
||||||
|
|||||||
+12
-7
@@ -10,7 +10,7 @@ authors = [
|
|||||||
homepage = "https://conduwuit.puppyirl.gay/"
|
homepage = "https://conduwuit.puppyirl.gay/"
|
||||||
repository = "https://github.com/girlbossceo/conduwuit"
|
repository = "https://github.com/girlbossceo/conduwuit"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
version = "0.3.2"
|
version = "0.3.3"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See also `rust-toolchain.toml`
|
# See also `rust-toolchain.toml`
|
||||||
@@ -19,6 +19,8 @@ rust-version = "1.77.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
console-subscriber = { version = "0.2", optional = true }
|
console-subscriber = { version = "0.2", optional = true }
|
||||||
|
|
||||||
|
infer = { version = "0.15", default-features = false }
|
||||||
|
|
||||||
# for hot lib reload
|
# for hot lib reload
|
||||||
hot-lib-reloader = { version = "^0.7", optional = true }
|
hot-lib-reloader = { version = "^0.7", optional = true }
|
||||||
|
|
||||||
@@ -26,7 +28,7 @@ hot-lib-reloader = { version = "^0.7", optional = true }
|
|||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
|
||||||
# Used for conduit::Error type
|
# Used for conduit::Error type
|
||||||
thiserror = "1.0.59"
|
thiserror = "1.0.60"
|
||||||
|
|
||||||
# Used to encode server public key
|
# Used to encode server public key
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
@@ -77,6 +79,7 @@ url = { version = "2.5.0", features = ["serde"] }
|
|||||||
async-trait = "0.1.80"
|
async-trait = "0.1.80"
|
||||||
|
|
||||||
lru-cache = "0.1.2"
|
lru-cache = "0.1.2"
|
||||||
|
sanitize-filename = "0.5.0"
|
||||||
|
|
||||||
# standard date and time tools
|
# standard date and time tools
|
||||||
[dependencies.chrono]
|
[dependencies.chrono]
|
||||||
@@ -109,6 +112,7 @@ features = [
|
|||||||
"add-extension",
|
"add-extension",
|
||||||
"cors",
|
"cors",
|
||||||
"sensitive-headers",
|
"sensitive-headers",
|
||||||
|
"set-header",
|
||||||
"trace",
|
"trace",
|
||||||
"util",
|
"util",
|
||||||
"catch-panic",
|
"catch-panic",
|
||||||
@@ -129,14 +133,14 @@ features = ["rustls-tls-native-roots", "socks", "hickory-dns"]
|
|||||||
# all the serde stuff
|
# all the serde stuff
|
||||||
# Used for pdu definition
|
# Used for pdu definition
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0.200"
|
version = "1.0.201"
|
||||||
features = ["rc"]
|
features = ["rc"]
|
||||||
# Used for appservice registration files
|
# Used for appservice registration files
|
||||||
[dependencies.serde_yaml]
|
[dependencies.serde_yaml]
|
||||||
version = "0.9.34"
|
version = "0.9.34"
|
||||||
# Used for ruma wrapper
|
# Used for ruma wrapper
|
||||||
[dependencies.serde_json]
|
[dependencies.serde_json]
|
||||||
version = "1.0.116"
|
version = "1.0.117"
|
||||||
features = ["raw_value"]
|
features = ["raw_value"]
|
||||||
|
|
||||||
|
|
||||||
@@ -230,7 +234,7 @@ features = ["use_std"]
|
|||||||
|
|
||||||
# for URL previews
|
# for URL previews
|
||||||
[dependencies.webpage]
|
[dependencies.webpage]
|
||||||
version = "2.0"
|
version = "2.0.1"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
# to support multiple variations of setting a config option
|
# to support multiple variations of setting a config option
|
||||||
@@ -294,8 +298,9 @@ version = "0.24.1"
|
|||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dependencies.rust-rocksdb]
|
[dependencies.rust-rocksdb]
|
||||||
git = "https://github.com/zaidoon1/rust-rocksdb"
|
git = "https://github.com/girlbossceo/rust-rocksdb-zaidoon1"
|
||||||
branch = "master"
|
rev = "9ecb597d966efb37ed96f4cfe3f09165013fd14a"
|
||||||
|
#branch = "master"
|
||||||
optional = true
|
optional = true
|
||||||
default-features = true
|
default-features = true
|
||||||
features = ["multi-threaded-cf", "zstd"]
|
features = ["multi-threaded-cf", "zstd"]
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ friends or company.
|
|||||||
|
|
||||||
An official conduwuit server ran by me is available at transfem.dev ([element.transfem.dev](https://element.transfem.dev) / [cinny.transfem.dev](https://cinny.transfem.dev))
|
An official conduwuit server ran by me is available at transfem.dev ([element.transfem.dev](https://element.transfem.dev) / [cinny.transfem.dev](https://cinny.transfem.dev))
|
||||||
|
|
||||||
|
transfem.dev is a public homeserver that can be used, it is not a "test only homeserver". This means there are rules, so please read the rules: [https://transfem.dev/homeserver_rules.txt](https://transfem.dev/homeserver_rules.txt)
|
||||||
|
|
||||||
|
transfem.dev is also listed at [servers.joinmatrix.org](https://servers.joinmatrix.org/)
|
||||||
|
|
||||||
#### What is the current status?
|
#### What is the current status?
|
||||||
|
|
||||||
conduwuit is a hard fork of Conduit which is in beta, meaning you can join and participate in most
|
conduwuit is a hard fork of Conduit which is in beta, meaning you can join and participate in most
|
||||||
@@ -59,7 +63,8 @@ Both, but I prefer conduwuit.
|
|||||||
#### Mirrors of conduwuit
|
#### Mirrors of conduwuit
|
||||||
|
|
||||||
- GitHub: <https://github.com/girlbossceo/conduwuit>
|
- GitHub: <https://github.com/girlbossceo/conduwuit>
|
||||||
- GitLab: <https://gitlab.com/girlbossceo/conduwuit>
|
- GitLab: <https://gitlab.com/conduwuit/conduwuit>
|
||||||
|
- git.girlcock.ceo: <https://git.girlcock.ceo/strawberry/conduwuit>
|
||||||
- git.gay: <https://git.gay/june/conduwuit>
|
- git.gay: <https://git.gay/june/conduwuit>
|
||||||
- Codeberg: <https://codeberg.org/girlbossceo/conduwuit>
|
- Codeberg: <https://codeberg.org/girlbossceo/conduwuit>
|
||||||
- sourcehut: <https://git.sr.ht/~girlbossceo/conduwuit>
|
- sourcehut: <https://git.sr.ht/~girlbossceo/conduwuit>
|
||||||
|
|||||||
@@ -269,6 +269,19 @@ url_preview_check_root_domain = false
|
|||||||
# Defaults to true
|
# Defaults to true
|
||||||
allow_profile_lookup_federation_requests = true
|
allow_profile_lookup_federation_requests = true
|
||||||
|
|
||||||
|
# Config option to automatically deactivate the account of any user who attempts to join a:
|
||||||
|
# - banned room
|
||||||
|
# - forbidden room alias
|
||||||
|
# - room alias or ID with a forbidden server name
|
||||||
|
#
|
||||||
|
# This may be useful if all your banned lists consist of toxic rooms or servers that no good faith user would ever attempt to join, and
|
||||||
|
# to automatically remediate the problem without any admin user intervention.
|
||||||
|
#
|
||||||
|
# This will also make the user leave all rooms. Federation (e.g. remote room invites) are ignored here.
|
||||||
|
#
|
||||||
|
# Defaults to false as rooms can be banned for non-moderation-related reasons
|
||||||
|
#auto_deactivate_banned_room_attempts = false
|
||||||
|
|
||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
conduwuit for Debian
|
# conduwuit for Debian
|
||||||
==================
|
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|||||||
Vendored
+8
-6
@@ -1,13 +1,18 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=conduwuit Matrix homeserver
|
Description=conduwuit Matrix homeserver
|
||||||
|
Documentation=https://conduwuit.puppyirl.gay/
|
||||||
After=network-online.target
|
After=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
DynamicUser=yes
|
DynamicUser=yes
|
||||||
User=_conduwuit
|
User=conduwuit
|
||||||
Group=_conduwuit
|
Group=conduwuit
|
||||||
Type=notify
|
Type=notify
|
||||||
|
|
||||||
|
Environment="CONDUWUIT_CONFIG=/etc/conduwuit/conduwuit.toml"
|
||||||
|
|
||||||
|
ExecStart=/usr/sbin/conduwuit
|
||||||
|
|
||||||
AmbientCapabilities=
|
AmbientCapabilities=
|
||||||
CapabilityBoundingSet=
|
CapabilityBoundingSet=
|
||||||
|
|
||||||
@@ -39,14 +44,11 @@ SystemCallArchitectures=native
|
|||||||
SystemCallFilter=@system-service @resources
|
SystemCallFilter=@system-service @resources
|
||||||
SystemCallFilter=~@clock @debug @module @mount @reboot @swap @cpu-emulation @obsolete @timer @chown @setuid @privileged @keyring @ipc
|
SystemCallFilter=~@clock @debug @module @mount @reboot @swap @cpu-emulation @obsolete @timer @chown @setuid @privileged @keyring @ipc
|
||||||
SystemCallErrorNumber=EPERM
|
SystemCallErrorNumber=EPERM
|
||||||
StateDirectory=matrix-conduit
|
StateDirectory=conduwuit
|
||||||
|
|
||||||
RuntimeDirectory=conduit
|
RuntimeDirectory=conduit
|
||||||
RuntimeDirectoryMode=0750
|
RuntimeDirectoryMode=0750
|
||||||
|
|
||||||
Environment="CONDUIT_CONFIG=/etc/conduwuit/conduwuit.toml"
|
|
||||||
|
|
||||||
ExecStart=/usr/sbin/conduwuit
|
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
|
|
||||||
|
|||||||
Vendored
+4
-4
@@ -7,21 +7,21 @@ CONDUWUIT_DATABASE_PATH=/var/lib/conduwuit/
|
|||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
configure)
|
configure)
|
||||||
# Create the `_conduwuit` user if it does not exist yet.
|
# Create the `conduwuit` user if it does not exist yet.
|
||||||
if ! getent passwd _conduwuit > /dev/null ; then
|
if ! getent passwd conduwuit > /dev/null ; then
|
||||||
echo 'Adding system user for the conduwuit Matrix homeserver' 1>&2
|
echo 'Adding system user for the conduwuit Matrix homeserver' 1>&2
|
||||||
adduser --system --group --quiet \
|
adduser --system --group --quiet \
|
||||||
--home "$CONDUWUIT_DATABASE_PATH" \
|
--home "$CONDUWUIT_DATABASE_PATH" \
|
||||||
--disabled-login \
|
--disabled-login \
|
||||||
--shell "/usr/sbin/nologin" \
|
--shell "/usr/sbin/nologin" \
|
||||||
--force-badname \
|
--force-badname \
|
||||||
_conduwuit
|
conduwuit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create the database path if it does not exist yet and fix up ownership
|
# Create the database path if it does not exist yet and fix up ownership
|
||||||
# and permissions.
|
# and permissions.
|
||||||
mkdir -p "$CONDUWUIT_DATABASE_PATH"
|
mkdir -p "$CONDUWUIT_DATABASE_PATH"
|
||||||
chown _conduwuit:_conduwuit -R "$CONDUWUIT_DATABASE_PATH"
|
chown conduwuit:conduwuit -R "$CONDUWUIT_DATABASE_PATH"
|
||||||
chmod 700 "$CONDUWUIT_DATABASE_PATH"
|
chmod 700 "$CONDUWUIT_DATABASE_PATH"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
+6
-4
@@ -2,15 +2,17 @@
|
|||||||
|
|
||||||
- [Introduction](introduction.md)
|
- [Introduction](introduction.md)
|
||||||
- [Differences from upstream Conduit](differences.md)
|
- [Differences from upstream Conduit](differences.md)
|
||||||
|
|
||||||
- [Example configuration](configuration.md)
|
- [Example configuration](configuration.md)
|
||||||
- [Deploying](deploying.md)
|
- [Deploying](deploying.md)
|
||||||
- [Generic](deploying/generic.md)
|
- [Generic](deploying/generic.md)
|
||||||
- [Debian](deploying/debian.md)
|
|
||||||
- [Docker](deploying/docker.md)
|
|
||||||
- [NixOS](deploying/nixos.md)
|
- [NixOS](deploying/nixos.md)
|
||||||
|
- [Docker](deploying/docker.md)
|
||||||
|
- [Arch Linux](deploying/arch-linux.md)
|
||||||
|
- [Debian](deploying/debian.md)
|
||||||
- [TURN](turn.md)
|
- [TURN](turn.md)
|
||||||
- [Appservices](appservices.md)
|
- [Appservices](appservices.md)
|
||||||
|
- [Maintenance](maintenance.md)
|
||||||
|
- [Troubleshooting](troubleshooting.md)
|
||||||
- [Development](development.md)
|
- [Development](development.md)
|
||||||
- [Testing](development/testing.md)
|
|
||||||
- [Contributing](contributing.md)
|
- [Contributing](contributing.md)
|
||||||
|
- [Testing](development/testing.md)
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# conduwuit for Arch Linux
|
||||||
|
|
||||||
|
Currently conduwuit is only on the Arch User Repository (AUR).
|
||||||
|
|
||||||
|
The conduwuit AUR packages are community maintained and are not maintained by conduwuit development team, but the AUR package maintainers are in the Matrix room. Please attempt to verify your AUR package's PKGBUILD file looks fine before asking for support.
|
||||||
|
|
||||||
|
- [conduwuit](https://aur.archlinux.org/packages/conduwuit) - latest tagged conduwuit
|
||||||
|
- [conduwuit-git](https://aur.archlinux.org/packages/conduwuit-git) - latest git conduwuit from `main` branch
|
||||||
@@ -12,15 +12,15 @@ OCI images for conduwuit are available in the registries listed below.
|
|||||||
| Registry | Image | Size | Notes |
|
| Registry | Image | Size | Notes |
|
||||||
| --------------- | --------------------------------------------------------------- | ----------------------------- | ---------------------- |
|
| --------------- | --------------------------------------------------------------- | ----------------------------- | ---------------------- |
|
||||||
| GitHub Registry | [ghcr.io/girlbossceo/conduwuit:latest][gh] | ![Image Size][shield-latest] | Stable tagged image. |
|
| GitHub Registry | [ghcr.io/girlbossceo/conduwuit:latest][gh] | ![Image Size][shield-latest] | Stable tagged image. |
|
||||||
| GitLab Registry | [registry.gitlab.com/girlbossceo/conduwuit:latest][gl] | ![Image Size][shield-latest] | Stable tagged image. |
|
| GitLab Registry | [registry.gitlab.com/conduwuit/conduwuit:latest][gl] | ![Image Size][shield-latest] | Stable tagged image. |
|
||||||
| Docker Hub | [docker.io/girlbossceo/conduwuit:latest][dh] | ![Image Size][shield-latest] | Stable tagged image. |
|
| Docker Hub | [docker.io/girlbossceo/conduwuit:latest][dh] | ![Image Size][shield-latest] | Stable tagged image. |
|
||||||
| GitHub Registry | [ghcr.io/girlbossceo/conduwuit:main][gh] | ![Image Size][shield-main] | Stable main branch. |
|
| GitHub Registry | [ghcr.io/girlbossceo/conduwuit:main][gh] | ![Image Size][shield-main] | Stable main branch. |
|
||||||
| GitLab Registry | [registry.gitlab.com/girlbossceo/conduwuit:main][gl] | ![Image Size][shield-main] | Stable main branch. |
|
| GitLab Registry | [registry.gitlab.com/conduwuit/conduwuit:main][gl] | ![Image Size][shield-main] | Stable main branch. |
|
||||||
| Docker Hub | [docker.io/girlbossceo/conduwuit:main][dh] | ![Image Size][shield-main] | Stable main branch. |
|
| Docker Hub | [docker.io/girlbossceo/conduwuit:main][dh] | ![Image Size][shield-main] | Stable main branch. |
|
||||||
|
|
||||||
[dh]: https://hub.docker.com/repository/docker/girlbossceo/conduwuit
|
[dh]: https://hub.docker.com/repository/docker/girlbossceo/conduwuit
|
||||||
[gh]: https://github.com/girlbossceo/conduwuit/pkgs/container/conduwuit
|
[gh]: https://github.com/girlbossceo/conduwuit/pkgs/container/conduwuit
|
||||||
[gl]: https://gitlab.com/girlbossceo/conduwuit/container_registry/6351657
|
[gl]: https://gitlab.com/conduwuit/conduwuit/container_registry/6351657
|
||||||
[shield-latest]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/latest
|
[shield-latest]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/latest
|
||||||
[shield-main]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/main
|
[shield-main]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/main
|
||||||
|
|
||||||
@@ -51,9 +51,9 @@ docker run -d -p 8448:6167 \
|
|||||||
|
|
||||||
or you can use [docker compose](#docker-compose).
|
or you can use [docker compose](#docker-compose).
|
||||||
|
|
||||||
The `-d` flag lets the container run in detached mode. You may supply an optional `conduwuit.toml` config file, an example can be found [here](../configuration.md).
|
The `-d` flag lets the container run in detached mode. You may supply an optional `conduwuit.toml` config file, the example config can be found [here](../configuration.md).
|
||||||
You can pass in different env vars to change config values on the fly. You can even configure conduwuit completely by using env vars. For an overview of possible
|
You can pass in different env vars to change config values on the fly. You can even configure conduwuit completely by using env vars. For an overview of possible
|
||||||
values, please take a look at the `docker-compose.yml` file.
|
values, please take a look at the [`docker-compose.yml`](docker-compose.yml) file.
|
||||||
|
|
||||||
If you just want to test conduwuit for a short time, you can use the `--rm` flag, which will clean up everything related to your container after you stop it.
|
If you just want to test conduwuit for a short time, you can use the `--rm` flag, which will clean up everything related to your container after you stop it.
|
||||||
|
|
||||||
@@ -107,92 +107,7 @@ either expose ports `443` and `8448` or serve two endpoints `.well-known/matrix/
|
|||||||
|
|
||||||
With the service `well-known` we use a single `nginx` container that will serve those two files.
|
With the service `well-known` we use a single `nginx` container that will serve those two files.
|
||||||
|
|
||||||
So...step by step:
|
|
||||||
|
|
||||||
1. Copy [`docker-compose.for-traefik.yml`](docker-compose.for-traefik.yml) (or
|
|
||||||
[`docker-compose.with-traefik.yml`](docker-compose.with-traefik.yml)) and [`docker-compose.override.yml`](docker-compose.override.yml) from the repository and remove `.for-traefik` (or `.with-traefik`) from the filename.
|
|
||||||
2. Open both files and modify/adjust them to your needs. Meaning, change the `CONDUIT_SERVER_NAME` and the volume host mappings according to your needs.
|
|
||||||
3. Create the `conduwuit.toml` config file, an example can be found [here](../configuration.md), or set `CONDUIT_CONFIG=""` and configure conduwuit per env vars.
|
|
||||||
4. Uncomment the `element-web` service if you want to host your own Element Web Client and create a `element_config.json`.
|
|
||||||
5. Create the files needed by the `well-known` service.
|
|
||||||
|
|
||||||
- `./nginx/matrix.conf` (relative to the compose file, you can change this, but then also need to change the volume mapping)
|
|
||||||
|
|
||||||
```nginx
|
|
||||||
server {
|
|
||||||
server_name <SUBDOMAIN>.<DOMAIN>;
|
|
||||||
listen 80 default_server;
|
|
||||||
|
|
||||||
location /.well-known/matrix/server {
|
|
||||||
return 200 '{"m.server": "<SUBDOMAIN>.<DOMAIN>:443"}';
|
|
||||||
types { } default_type "application/json; charset=utf-8";
|
|
||||||
}
|
|
||||||
|
|
||||||
location /.well-known/matrix/client {
|
|
||||||
return 200 '{"m.homeserver": {"base_url": "https://<SUBDOMAIN>.<DOMAIN>"}}';
|
|
||||||
types { } default_type "application/json; charset=utf-8";
|
|
||||||
add_header "Access-Control-Allow-Origin" *;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
return 404;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
6. Run `docker compose up -d`
|
|
||||||
7. Connect to your homeserver with your preferred client and create a user. You should do this immediately after starting Conduit, because the first created user is the admin.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Voice communication
|
## Voice communication
|
||||||
|
|
||||||
In order to make or receive calls, a TURN server is required. conduwuit suggests using [Coturn](https://github.com/coturn/coturn) for this purpose, which is also available as a Docker image. Before proceeding with the software installation, it is essential to have the necessary configurations in place.
|
See the [TURN](../turn.md) page.
|
||||||
|
|
||||||
### Configuration
|
|
||||||
|
|
||||||
Create a configuration file called `coturn.conf` containing:
|
|
||||||
|
|
||||||
```conf
|
|
||||||
use-auth-secret
|
|
||||||
static-auth-secret=<a secret key>
|
|
||||||
realm=<your server domain>
|
|
||||||
```
|
|
||||||
A common way to generate a suitable alphanumeric secret key is by using `pwgen -s 64 1`.
|
|
||||||
|
|
||||||
These same values need to be set in conduwuit. You can either modify conduwuit.toml to include these lines:
|
|
||||||
```
|
|
||||||
turn_uris = ["turn:<your server domain>?transport=udp", "turn:<your server domain>?transport=tcp"]
|
|
||||||
turn_secret = "<secret key from coturn configuration>"
|
|
||||||
```
|
|
||||||
or append the following to the docker environment variables dependig on which configuration method you used earlier:
|
|
||||||
```yml
|
|
||||||
CONDUIT_TURN_URIS: '["turn:<your server domain>?transport=udp", "turn:<your server domain>?transport=tcp"]'
|
|
||||||
CONDUIT_TURN_SECRET: "<secret key from coturn configuration>"
|
|
||||||
```
|
|
||||||
Restart Conduit to apply these changes.
|
|
||||||
|
|
||||||
### Run
|
|
||||||
Run the [Coturn](https://hub.docker.com/r/coturn/coturn) image using
|
|
||||||
```bash
|
|
||||||
docker run -d --network=host -v $(pwd)/coturn.conf:/etc/coturn/turnserver.conf coturn/coturn
|
|
||||||
```
|
|
||||||
|
|
||||||
or docker-compose. For the latter, paste the following section into a file called `docker-compose.yml`
|
|
||||||
and run `docker compose up -d` in the same directory.
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: 3
|
|
||||||
services:
|
|
||||||
turn:
|
|
||||||
container_name: coturn-server
|
|
||||||
image: docker.io/coturn/coturn
|
|
||||||
restart: unless-stopped
|
|
||||||
network_mode: "host"
|
|
||||||
volumes:
|
|
||||||
- ./coturn.conf:/etc/coturn/turnserver.conf
|
|
||||||
```
|
|
||||||
|
|
||||||
To understand why the host networking mode is used and explore alternative configuration options, please visit the following link: https://github.com/coturn/coturn/blob/master/docker/coturn/README.md.
|
|
||||||
For security recommendations see Synapse's [Coturn documentation](https://github.com/matrix-org/synapse/blob/develop/docs/setup/turn/coturn.md#configuration).
|
|
||||||
|
|||||||
+19
-49
@@ -1,7 +1,5 @@
|
|||||||
# Generic deployment documentation
|
# Generic deployment documentation
|
||||||
|
|
||||||
### Please note that this documentation is not fully representative of conduwuit at the moment. Assume majority of it is outdated.
|
|
||||||
|
|
||||||
> ## Getting help
|
> ## Getting help
|
||||||
>
|
>
|
||||||
> If you run into any problems while setting up conduwuit, ask us
|
> If you run into any problems while setting up conduwuit, ask us
|
||||||
@@ -13,23 +11,16 @@ You may simply download the binary that fits your machine. Run `uname -m` to see
|
|||||||
|
|
||||||
Prebuilt binaries can be downloaded from the latest tagged release [here](https://github.com/girlbossceo/conduwuit/releases/latest).
|
Prebuilt binaries can be downloaded from the latest tagged release [here](https://github.com/girlbossceo/conduwuit/releases/latest).
|
||||||
|
|
||||||
Alternatively, you may compile the binary yourself. First, install any dependencies:
|
The latest tagged release also includes the Debian packages.
|
||||||
|
|
||||||
```bash
|
Alternatively, you may compile the binary yourself. We recommend using [Lix](https://lix.systems) to build conduwuit as this has the most guaranteed
|
||||||
# Debian
|
reproducibiltiy and easiest to get a build environment and output going.
|
||||||
$ sudo apt install libclang-dev build-essential
|
|
||||||
|
|
||||||
# RHEL
|
Otherwise, follow standard Rust project build guides (installing git and cloning the repo, getting the Rust toolchain via rustup, installing LLVM toolchain + libclang, installing liburing for io_uring and RocksDB, etc).
|
||||||
$ sudo dnf install clang
|
|
||||||
```
|
|
||||||
Then, `cd` into the source tree of conduwuit and run:
|
|
||||||
```bash
|
|
||||||
$ cargo build --release
|
|
||||||
```
|
|
||||||
|
|
||||||
## Adding a conduwuit user
|
## Adding a conduwuit user
|
||||||
|
|
||||||
While conduwuit can run as any user it is usually better to use dedicated users for different services. This also allows
|
While conduwuit can run as any user it is better to use dedicated users for different services. This also allows
|
||||||
you to make sure that the file permissions are correctly set up.
|
you to make sure that the file permissions are correctly set up.
|
||||||
|
|
||||||
In Debian or RHEL, you can use this command to create a conduwuit user:
|
In Debian or RHEL, you can use this command to create a conduwuit user:
|
||||||
@@ -38,6 +29,12 @@ In Debian or RHEL, you can use this command to create a conduwuit user:
|
|||||||
sudo adduser --system conduwuit --group --disabled-login --no-create-home
|
sudo adduser --system conduwuit --group --disabled-login --no-create-home
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For distros without `adduser`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo useradd -r --shell /usr/bin/nologin --no-create-home conduwuit
|
||||||
|
```
|
||||||
|
|
||||||
## Forwarding ports in the firewall or the router
|
## Forwarding ports in the firewall or the router
|
||||||
|
|
||||||
conduwuit uses the ports 443 and 8448 both of which need to be open in the firewall.
|
conduwuit uses the ports 443 and 8448 both of which need to be open in the firewall.
|
||||||
@@ -46,45 +43,18 @@ If conduwuit runs behind a router or in a container and has a different public I
|
|||||||
|
|
||||||
## Setting up a systemd service
|
## Setting up a systemd service
|
||||||
|
|
||||||
Now we'll set up a systemd service for conduwuit, so it's easy to start/stop conduwuit and set it to autostart when your
|
The systemd unit for conduwuit can be found [here](../../debian/conduwuit.service). You may need to change the `ExecStart=` path to where you placed the conduwuit binary.
|
||||||
server reboots. Simply paste the default systemd service you can find below into
|
|
||||||
`/etc/systemd/system/conduwuit.service`.
|
|
||||||
|
|
||||||
```systemd
|
|
||||||
[Unit]
|
|
||||||
Description=conduwuit Matrix Server
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Environment="CONDUWUIT_CONFIG=/etc/conduwuit/conduwuit.toml"
|
|
||||||
User=conduwuit
|
|
||||||
Group=conduwuit
|
|
||||||
RuntimeDirectory=conduwuit
|
|
||||||
RuntimeDirectoryMode=0750
|
|
||||||
Restart=always
|
|
||||||
ExecStart=/usr/local/bin/conduwuit
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, run
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ sudo systemctl daemon-reload
|
|
||||||
```
|
|
||||||
|
|
||||||
## Creating the conduwuit configuration file
|
## Creating the conduwuit configuration file
|
||||||
|
|
||||||
Now we need to create the conduwuit's config file in `/etc/conduwuit/conduwuit.toml`. Paste this in **and take a moment
|
Now we need to create the conduwuit's config file in `/etc/conduwuit/conduwuit.toml`. The example config can be found at [conduwuit-example.toml](../configuration.md).**Please take a moment to read it. You need to change at least the server name.**
|
||||||
to read it. You need to change at least the server name.**
|
|
||||||
RocksDB (`rocksdb`) is the only supported database backend. SQLite only exists for historical reasons and is not recommended. Any performance issues, storage issues, database issues, etc will not be assisted if using SQLite and you will be asked to migrate to RocksDB first.
|
|
||||||
|
|
||||||
See the following example config at [conduwuit-example.toml](../configuration.md)
|
RocksDB (`rocksdb`) is the only supported database backend. SQLite only exists for historical reasons and is not recommended. Any performance issues, storage issues, database issues, etc will not be assisted if using SQLite and you will be asked to migrate to RocksDB first.
|
||||||
|
|
||||||
## Setting the correct file permissions
|
## Setting the correct file permissions
|
||||||
|
|
||||||
As we are using a conduwuit specific user we need to allow it to read the config. To do that you can run this command on
|
If you are using a dedicated user for conduwuit, you will need to allow it to read the config. To do that you can run this command on
|
||||||
|
|
||||||
Debian or RHEL:
|
Debian or RHEL:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -102,7 +72,7 @@ sudo chmod 700 /var/lib/conduwuit/
|
|||||||
|
|
||||||
## Setting up the Reverse Proxy
|
## Setting up the Reverse Proxy
|
||||||
|
|
||||||
Refer to the documentation or various guides online of your chosen reverse proxy software. A Caddy example will be provided as this is the recommended reverse proxy for new users and is very trivial.
|
Refer to the documentation or various guides online of your chosen reverse proxy software. A [Caddy](https://caddyserver.com/) example will be provided as this is the recommended reverse proxy for new users and is very trivial to use (handles TLS, reverse proxy headers, etc transparently with proper defaults).
|
||||||
|
|
||||||
### Caddy
|
### Caddy
|
||||||
|
|
||||||
@@ -118,10 +88,10 @@ your.server.name, your.server.name:8448 {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
That's it! Just start or enable the service and you're set.
|
That's it! Just start and enable the service and you're set.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ sudo systemctl enable caddy
|
$ sudo systemctl enable --now caddy
|
||||||
```
|
```
|
||||||
|
|
||||||
## You're done!
|
## You're done!
|
||||||
|
|||||||
+11
-4
@@ -6,7 +6,7 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
|||||||
|
|
||||||
## Performance:
|
## Performance:
|
||||||
- Concurrency support for key fetching for faster remote room joins and room joins that will error less frequently
|
- Concurrency support for key fetching for faster remote room joins and room joins that will error less frequently
|
||||||
- Send `Cache-Control` response header with `immutable` and 1 year cache length for all media requests to instruct clients to cache media, and reduce server load from media requests that could be otherwise cached
|
- Send `Cache-Control` response header with `immutable` and 1 year cache length for all media requests (download and thumbnail) to instruct clients to cache media, and reduce server load from media requests that could be otherwise cached
|
||||||
- Add feature flags and config options to enable/build with zstd, brotli, and/or gzip HTTP body compression (response and request)
|
- Add feature flags and config options to enable/build with zstd, brotli, and/or gzip HTTP body compression (response and request)
|
||||||
- Eliminate all usage of the thread-blocking `getaddrinfo(3)` call upon DNS queries, significantly improving federation latency/ping and cache DNS results (NXDOMAINs, successful queries, etc) using hickory-dns / hickory-resolver
|
- Eliminate all usage of the thread-blocking `getaddrinfo(3)` call upon DNS queries, significantly improving federation latency/ping and cache DNS results (NXDOMAINs, successful queries, etc) using hickory-dns / hickory-resolver
|
||||||
- Vastly improve RocksDB default settings to use new features that help with performance significantly, uses settings tailored to SSDs, various ways to tweak RocksDB, and a conduwuit setting to tell RocksDB to use settings that are tailored to HDDs or slow spinning rust storage or buggy filesystems.
|
- Vastly improve RocksDB default settings to use new features that help with performance significantly, uses settings tailored to SSDs, various ways to tweak RocksDB, and a conduwuit setting to tell RocksDB to use settings that are tailored to HDDs or slow spinning rust storage or buggy filesystems.
|
||||||
@@ -22,6 +22,7 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
|||||||
- Add config options for RocksDB compression and bottommost compression, including choosing the algorithm and compression level
|
- Add config options for RocksDB compression and bottommost compression, including choosing the algorithm and compression level
|
||||||
- Use [loole](https://github.com/mahdi-shojaee/loole) MPSC channels instead of tokio MPSC channels for huge performance boosts in sending channels (mainly relevant for federation) and presence channels
|
- Use [loole](https://github.com/mahdi-shojaee/loole) MPSC channels instead of tokio MPSC channels for huge performance boosts in sending channels (mainly relevant for federation) and presence channels
|
||||||
- Use `tracing`/`log`'s `release_max_level_info` feature to improve performance, build speeds, binary size, and CPU usage in release builds by avoid compiling debug/trace log level macros that users will generally never use (can be disabled with a build-time feature flag)
|
- Use `tracing`/`log`'s `release_max_level_info` feature to improve performance, build speeds, binary size, and CPU usage in release builds by avoid compiling debug/trace log level macros that users will generally never use (can be disabled with a build-time feature flag)
|
||||||
|
- Enable RocksDB async read I/O via `io_uring` by default
|
||||||
|
|
||||||
|
|
||||||
## General Fixes:
|
## General Fixes:
|
||||||
@@ -35,7 +36,7 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
|||||||
- Increased graceful shutdown timeout from a low 60 seconds to 180 seconds to avoid killing connections and let the remaining ones finish processing
|
- Increased graceful shutdown timeout from a low 60 seconds to 180 seconds to avoid killing connections and let the remaining ones finish processing
|
||||||
- Return joined member count of rooms for push rules/conditions instead of a hardcoded value of 10
|
- Return joined member count of rooms for push rules/conditions instead of a hardcoded value of 10
|
||||||
- Make `CONDUIT_CONFIG` optional, relevant for container users that configure only by environment variables and no longer need to set `CONDUIT_CONFIG` to an empty string.
|
- Make `CONDUIT_CONFIG` optional, relevant for container users that configure only by environment variables and no longer need to set `CONDUIT_CONFIG` to an empty string.
|
||||||
- Allow HEAD HTTP requests in CORS for clients (despite not being explicity mentioned in Matrix spec, HTTP spec says all HEAD requests need to behave the same as GET requests, Synapse supports HEAD requests)
|
- Allow HEAD and PATCH (MSC4138) HTTP requests in CORS for clients (despite not being explicity mentioned in Matrix spec, HTTP spec says all HEAD requests need to behave the same as GET requests, Synapse supports HEAD requests)
|
||||||
- Resolve and remove some "features" from upstream that result in concurrency hazards, exponential backoff issues, or arbitrary performance limiters
|
- Resolve and remove some "features" from upstream that result in concurrency hazards, exponential backoff issues, or arbitrary performance limiters
|
||||||
- Find more servers for outbound federation `/hierarchy` requests instead of just the room ID server name
|
- Find more servers for outbound federation `/hierarchy` requests instead of just the room ID server name
|
||||||
- Support for suggesting servers to join through at `/_matrix/client/v3/directory/room/{roomAlias}`
|
- Support for suggesting servers to join through at `/_matrix/client/v3/directory/room/{roomAlias}`
|
||||||
@@ -55,6 +56,7 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
|||||||
- On new public room creations, only allow moderators to send `m.call.invite`, `org.matrix.msc3401.call`, and `org.matrix.msc3401.call.member` events
|
- On new public room creations, only allow moderators to send `m.call.invite`, `org.matrix.msc3401.call`, and `org.matrix.msc3401.call.member` events
|
||||||
- Add support for a "global ACLs" feature (`forbidden_remote_server_names`) that blocks inbound remote room invites, room joins by room ID on server name, room joins by room alias on server name, incoming federated joins, and incoming federated room directory requests. This is very helpful for blocking servers that are purely toxic/bad and serve no value in allowing our users to suffer from things like room invite spam or such. Please note that this is not a substitute for room ACLs.
|
- Add support for a "global ACLs" feature (`forbidden_remote_server_names`) that blocks inbound remote room invites, room joins by room ID on server name, room joins by room alias on server name, incoming federated joins, and incoming federated room directory requests. This is very helpful for blocking servers that are purely toxic/bad and serve no value in allowing our users to suffer from things like room invite spam or such. Please note that this is not a substitute for room ACLs.
|
||||||
- Add support for a config option to forbid our local users from sending federated room directory requests for (`forbidden_remote_room_directory_server_names`). Similar to above, useful for blocking servers that help prevent our users from wandering into bad areas of Matrix via room directories of those malicious servers.
|
- Add support for a config option to forbid our local users from sending federated room directory requests for (`forbidden_remote_room_directory_server_names`). Similar to above, useful for blocking servers that help prevent our users from wandering into bad areas of Matrix via room directories of those malicious servers.
|
||||||
|
- Add config option for auto remediating/deactivating local non-admin users who attempt to join bad/forbidden rooms (`auto_deactivate_banned_room_attempts`)
|
||||||
|
|
||||||
|
|
||||||
## Privacy/Security:
|
## Privacy/Security:
|
||||||
@@ -68,6 +70,9 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
|||||||
- Config option to disable incoming and/or outgoing remote read receipts
|
- Config option to disable incoming and/or outgoing remote read receipts
|
||||||
- Config option to disable incoming and/or outgoing remote typing indicators
|
- Config option to disable incoming and/or outgoing remote typing indicators
|
||||||
- Config option to disable incoming, outgoing, and/or local presence
|
- Config option to disable incoming, outgoing, and/or local presence
|
||||||
|
- Sanitise file names for the `Content-Disposition` header for all media requests (thumbnails, downloads, uploads)
|
||||||
|
- Return `inline` or `attachment` based on the detected file MIME type for the `Content-Disposition` and only allow images/videos/text/audio to be `inline`
|
||||||
|
- Send secure default HTTP headers such as a strong restrictive CSP, deny iframes, disable `X-XSS-Protection`, disable interest cohort in `Permission-Policy`, etc to mitigate any potential attack surface such as from untrusted media
|
||||||
|
|
||||||
|
|
||||||
## Administration/Logging:
|
## Administration/Logging:
|
||||||
@@ -81,7 +86,7 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
|||||||
- Warn on unknown config options specified
|
- Warn on unknown config options specified
|
||||||
- Add `/_conduwuit/server_version` route to return the version of conduwuit without relying on the federation API `/_matrix/federation/v1/version`
|
- Add `/_conduwuit/server_version` route to return the version of conduwuit without relying on the federation API `/_matrix/federation/v1/version`
|
||||||
- Add configurable RocksDB recovery modes to aid in recovering corrupted RocksDB databases
|
- Add configurable RocksDB recovery modes to aid in recovering corrupted RocksDB databases
|
||||||
- Support config options via `CONDUWUIT_` prefix
|
- Support config options via `CONDUWUIT_` prefix and accessing non-global struct config options with the `__` split (e.g. `CONDUWUIT_WELL_KNOWN__SERVER`)
|
||||||
- Add support for listening on multiple TCP ports
|
- Add support for listening on multiple TCP ports
|
||||||
- Disable update check by default as it's not useful for conduwuit
|
- Disable update check by default as it's not useful for conduwuit
|
||||||
- **Opt-in** Sentry.io telemetry and metrics, mainly used for crash reporting
|
- **Opt-in** Sentry.io telemetry and metrics, mainly used for crash reporting
|
||||||
@@ -89,7 +94,8 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
|||||||
|
|
||||||
## Maintenance/Stability:
|
## Maintenance/Stability:
|
||||||
- GitLab CI ported to GitHub Actions
|
- GitLab CI ported to GitHub Actions
|
||||||
- Repo is mirrored to GitHub, GitLab, git.gay, sourcehut, and Codeberg (see README.md for their links)
|
- Repo is mirrored to GitHub, GitLab, git.gay, git.girlcock.ceo, sourcehut, and Codeberg (see README.md for their links)
|
||||||
|
- Docker container images published to GitLab Container Registry, GitHub Container Registry, and Dockerhub
|
||||||
- Extensively revamp the example config to be extremely helpful and useful to both new users and power users
|
- Extensively revamp the example config to be extremely helpful and useful to both new users and power users
|
||||||
- Fixed every single clippy (default lints) and rustc warnings, including some that were performance related or potential safety issues / unsoundness
|
- Fixed every single clippy (default lints) and rustc warnings, including some that were performance related or potential safety issues / unsoundness
|
||||||
- Add a **lot** of other clippy and rustc lints and a rustfmt.toml file
|
- Add a **lot** of other clippy and rustc lints and a rustfmt.toml file
|
||||||
@@ -146,6 +152,7 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
|||||||
- Implement running and diff'ing Complement results in CI
|
- Implement running and diff'ing Complement results in CI
|
||||||
- Interest in supporting other operating systems such as macOS, BSDs, and Windows, and getting them added into CI and doing builds for them
|
- Interest in supporting other operating systems such as macOS, BSDs, and Windows, and getting them added into CI and doing builds for them
|
||||||
- Add config option for disabling RocksDB Direct IO if needed
|
- Add config option for disabling RocksDB Direct IO if needed
|
||||||
|
- Add various documentation on maintaining conduwuit, using RocksDB online backups, some troubleshooting, using admin commands, etc
|
||||||
- (Developers): Add support for tokio-console
|
- (Developers): Add support for tokio-console
|
||||||
- (Developers): Add support for tracing flame graphs
|
- (Developers): Add support for tracing flame graphs
|
||||||
- Add `release-debuginfo` Cargo build profile
|
- Add `release-debuginfo` Cargo build profile
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
# Maintaining your conduwuit setup
|
||||||
|
|
||||||
|
## Moderation
|
||||||
|
|
||||||
|
conduwuit has moderation through admin room commands. "binary commands" (medium priority) and an admin API (low priority) is planned. Some moderation-related config options are available in the example config such as "global ACLs" and blocking media requests to certain servers. See the example config for the moderation config options under the "Moderation / Privacy / Security" section.
|
||||||
|
|
||||||
|
conduwuit has moderation admin commands for:
|
||||||
|
- managing room aliases (`!admin rooms alias`)
|
||||||
|
- managing room directory (`!admin rooms directory`)
|
||||||
|
- managing room banning/blocking and user removal (`!admin rooms moderation`)
|
||||||
|
- managing user accounts (`!admin users`)
|
||||||
|
- fetching `/.well-known/matrix/support` from servers (`!admin federation`)
|
||||||
|
- blocking incoming federation for certain rooms (not the same as room banning) (`!admin federation`)
|
||||||
|
- deleting media (see [the media section](#media))
|
||||||
|
|
||||||
|
Any commands with `-list` in them will require a codeblock in the message with each object being newline delimited. An example of doing this is:
|
||||||
|
|
||||||
|
````
|
||||||
|
!admin rooms moderation ban-list-of-rooms
|
||||||
|
```
|
||||||
|
!roomid1:server.name
|
||||||
|
!roomid2:server.name
|
||||||
|
!roomid3:server.name
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
## Database
|
||||||
|
|
||||||
|
If using RocksDB, there's very little you need to do. Compaction is ran automatically based on various defined thresholds tuned for conduwuit to be high performance with the least I/O amplifcation or overhead. Manually running compaction is not recommended, or compaction via a timer. RocksDB is built with io_uring support via liburing for async read I/O.
|
||||||
|
|
||||||
|
Some RocksDB settings can be adjusted such as the compression method chosen. See the RocksDB section in the [example config](configuration.md). btrfs users may benefit from disabling compression on RocksDB if CoW is in use.
|
||||||
|
|
||||||
|
RocksDB troubleshooting can be found [in the RocksDB section of troubleshooting](troubleshooting.md).
|
||||||
|
|
||||||
|
## Backups
|
||||||
|
|
||||||
|
Currently only RocksDB supports online backups. If you'd like to backup your database online without any downtime, see the `!admin server` command for the backup commands and the `database_backup_path` config options in the example config. Please note that the format of the database backup is not the exact same. This is unfortunately a bad design choice by Facebook as we are using the database backup engine API from RocksDB, however the data is still there and can still be joined together.
|
||||||
|
|
||||||
|
To restore a backup from an online RocksDB backup:
|
||||||
|
- shutdown conduwuit
|
||||||
|
- create a new directory for merging together the data
|
||||||
|
- in the online backup created, copy all `.sst` files in `$DATABASE_BACKUP_PATH/shared_checksum` to your new directory
|
||||||
|
- trim all the strings so instead of `######_sxxxxxxxxx.sst`, it reads `######.sst`. A way of doing this with sed and bash is `for file in *.sst; do mv "$file" "$(echo "$file" | sed 's/_s.*/.sst/')"; done`
|
||||||
|
- copy all the files in `$DATABASE_BACKUP_PATH/1` to your new directory
|
||||||
|
- set your `database_path` config option to your new directory, or replace your old one with the new one you crafted
|
||||||
|
- start up conduwuit again and it should open as normal
|
||||||
|
|
||||||
|
If you'd like to do an offline backup, shutdown conduwuit and copy your `database_path` directory elsewhere. This can be restored with no modifications needed.
|
||||||
|
|
||||||
|
Backing up media is also just copying the `media/` directory from your database directory.
|
||||||
|
|
||||||
|
## Media
|
||||||
|
|
||||||
|
Media still needs various work, however conduwuit implements media deletion via:
|
||||||
|
- MXC URI
|
||||||
|
- Delete list of MXC URIs
|
||||||
|
- Delete remote media in the past `N` seconds/minutes
|
||||||
|
|
||||||
|
See the `!admin media` command for further information. All media in conduwuit is stored at `$DATABASE_DIR/media`. This will be configurable soon.
|
||||||
|
|
||||||
|
If you are finding yourself needing extensive granular control over media, we recommend looking into [Matrix Media Repo](https://github.com/t2bot/matrix-media-repo). conduwuit intends to implement various utilities for media, but MMR is dedicated to extensive media management.
|
||||||
|
|
||||||
|
Built-in S3 support is also planned, but for now using a "S3 filesystem" on `media/` works. conduwuit also sends a `Cache-Control` header of 1 year and immutable for all media requests (download and thumbnail) to reduce unnecessary media requests from browsers.
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# Troubleshooting conduwuit
|
||||||
|
|
||||||
|
> ## Docker users ⚠️
|
||||||
|
>
|
||||||
|
> Docker is extremely UX unfriendly. Because of this, a ton of issues or support is actually Docker support, not conduwuit support. We also cannot document the ever-growing list of Docker issues here.
|
||||||
|
>
|
||||||
|
> If you intend on asking for support and you are using Docker, **PLEASE** triple validate your issues are **NOT** because you have a misconfiguration in your Docker setup.
|
||||||
|
>
|
||||||
|
> If there are things like Compose file issues or Dockerhub image issues, those can still be mentioned as long as they're something we can fix.
|
||||||
|
|
||||||
|
## Rocksdb / database issues
|
||||||
|
|
||||||
|
#### Direct IO
|
||||||
|
|
||||||
|
Some filesystems may not like RocksDB using [Direct IO](https://github.com/facebook/rocksdb/wiki/Direct-IO). Direct IO is for non-buffered I/O which improves conduwuit performance, but at least FUSE is a filesystem potentially known to not like this. See the [example config](configuration.md) for disabling it if needed. Issues from Direct IO on unsupported filesystems are usually shown as startup errors.
|
||||||
|
|
||||||
|
#### Database corruption
|
||||||
|
|
||||||
|
If your database is corrupted and is failing to start (e.g. checksum mismatch), it may be recoverable but careful steps must be taken, and there is no guarantee it may be recoverable.
|
||||||
|
|
||||||
|
RocksDB has the following recovery modes:
|
||||||
|
|
||||||
|
- `TolerateCorruptedTailRecords`
|
||||||
|
- `AbsoluteConsistency`
|
||||||
|
- `PointInTime`
|
||||||
|
- `SkipAnyCorruptedRecord`
|
||||||
|
|
||||||
|
By default, conduwuit uses `TolerateCorruptedTailRecords` as generally these may be due to bad federation and we can re-fetch the correct data over federation. The RocksDB default is `PointInTime` which will attempt to restore a "snapshot" of the data when it was last known to be good. This data can be either a few seconds old, or multiple minutes prior. `PointInTime` may not be suitable for default usage due to clients and servers possibly not being able to handle sudden "backwards time travels", and `AbsoluteConsistency` may be too strict.
|
||||||
|
|
||||||
|
`AbsoluteConsistency` will fail to start the database if any sign of corruption is detected. `SkipAnyCorruptedRecord` will skip all forms of corruption unless it forbids the database from opening (e.g. too severe). Usage of `SkipAnyCorruptedRecord` voids any support as this may cause more damage and/or leave your database in a permanently inconsistent state, but it may do something if `PointInTime` does not work as a last ditch effort.
|
||||||
|
|
||||||
|
With this in mind:
|
||||||
|
- First start conduwuit with the `PointInTime` recovery method. See the [example config](configuration.md) for how to do this using `rocksdb_recovery_mode`
|
||||||
|
- If your database successfully opens, clients are recommended to clear their client cache to account for the rollback
|
||||||
|
- Leave your conduwuit running in `PointInTime` for at least 30-60 minutes so as much possible corruption is restored
|
||||||
|
- If all goes will, you should be able to restore back to using `TolerateCorruptedTailRecords` and you have successfully recovered your database
|
||||||
|
|
||||||
|
## Media
|
||||||
|
|
||||||
|
#### "File name too long"
|
||||||
|
|
||||||
|
If you are running into the "file name is too long" OS error for media requests, your filesystem cannot handle file name lengths >=255 characters. This is unfortuntely due to Conduit (upstream) using base64 for file name keys which is very problematic for some filesystems as the base64 input is untrusted and long file names or specific inputs can cause this. If you would like to avoid this, you may build conduwuit yourself with the `sha256_media` feature. **This will lose database compatibility with upstream**.
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
Note that users should not really be debugging things. If you find yourself debugging and find the issue, please let us know and/or how we can fix it. Various debug commands can be found in `!admin debug`.
|
||||||
|
|
||||||
|
#### Debug/Trace log level
|
||||||
|
|
||||||
|
conduwuit builds without debug or trace log levels by default for at least performance reasons. This may change in the future and/or binaries providing such configurations may be provided. If you need to access debug/trace log levels, you will need to build without the `release_max_log_level` feature.
|
||||||
|
|
||||||
|
#### Changing log level dynamically
|
||||||
|
|
||||||
|
conduwuit supports changing the tracing log environment filter on-the-fly using the admin command `!admin debug change-log-level`. This accepts a string **without quotes** the same format as the `log` config option.
|
||||||
|
|
||||||
|
#### Pinging servers
|
||||||
|
|
||||||
|
conduwuit can ping other servers using `!admin debug ping`. This takes a server name and goes through the server discovery process and queries `/_matrix/federation/v1/version`. Errors are outputted.
|
||||||
|
|
||||||
|
#### Allocator memory stats
|
||||||
|
|
||||||
|
If using jemalloc (for now) and built with jemallocator's `stats` feature, you can see conduwuit's jemalloc memory stats by using `!admin debug memory-stats`
|
||||||
+46
-16
@@ -1,25 +1,55 @@
|
|||||||
# Setting up TURN/STURN
|
# Setting up TURN/STURN
|
||||||
|
|
||||||
## General instructions
|
In order to make or receive calls, a TURN server is required. conduwuit suggests using [Coturn](https://github.com/coturn/coturn) for this purpose, which is also available as a Docker image.
|
||||||
|
|
||||||
* It is assumed you have a [Coturn server](https://github.com/coturn/coturn) up and running. See [Synapse reference implementation](https://github.com/matrix-org/synapse/blob/develop/docs/turn-howto.md).
|
### Configuration
|
||||||
|
|
||||||
## Edit/Add a few settings to your existing conduit.toml
|
Create a configuration file called `coturn.conf` containing:
|
||||||
|
|
||||||
|
```conf
|
||||||
|
use-auth-secret
|
||||||
|
static-auth-secret=<a secret key>
|
||||||
|
realm=<your server domain>
|
||||||
|
```
|
||||||
|
A common way to generate a suitable alphanumeric secret key is by using `pwgen -s 64 1`.
|
||||||
|
|
||||||
|
These same values need to be set in conduwuit. You can either modify conduwuit.toml to include these lines:
|
||||||
|
|
||||||
```
|
```
|
||||||
# Refer to your Coturn settings.
|
turn_uris = ["turn:<your server domain>?transport=udp", "turn:<your server domain>?transport=tcp"]
|
||||||
# `your.turn.url` has to match the REALM setting of your Coturn as well as `transport`.
|
turn_secret = "<secret key from coturn configuration>"
|
||||||
turn_uris = ["turn:your.turn.url?transport=udp", "turn:your.turn.url?transport=tcp"]
|
|
||||||
|
|
||||||
# static-auth-secret of your turnserver
|
|
||||||
turn_secret = "ADD SECRET HERE"
|
|
||||||
|
|
||||||
# If you have your TURN server configured to use a username and password
|
|
||||||
# you can provide these information too. In this case comment out `turn_secret above`!
|
|
||||||
#turn_username = ""
|
|
||||||
#turn_password = ""
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Apply settings
|
or append the following to the docker environment variables dependig on which configuration method you used earlier:
|
||||||
|
|
||||||
Restart Conduit.
|
```yml
|
||||||
|
CONDUIT_TURN_URIS: '["turn:<your server domain>?transport=udp", "turn:<your server domain>?transport=tcp"]'
|
||||||
|
CONDUIT_TURN_SECRET: "<secret key from coturn configuration>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Restart conduwuit to apply these changes.
|
||||||
|
|
||||||
|
### Run
|
||||||
|
Run the [Coturn](https://hub.docker.com/r/coturn/coturn) image using
|
||||||
|
```bash
|
||||||
|
docker run -d --network=host -v $(pwd)/coturn.conf:/etc/coturn/turnserver.conf coturn/coturn
|
||||||
|
```
|
||||||
|
|
||||||
|
or docker-compose. For the latter, paste the following section into a file called `docker-compose.yml`
|
||||||
|
and run `docker compose up -d` in the same directory.
|
||||||
|
|
||||||
|
```yml
|
||||||
|
version: 3
|
||||||
|
services:
|
||||||
|
turn:
|
||||||
|
container_name: coturn-server
|
||||||
|
image: docker.io/coturn/coturn
|
||||||
|
restart: unless-stopped
|
||||||
|
network_mode: "host"
|
||||||
|
volumes:
|
||||||
|
- ./coturn.conf:/etc/coturn/turnserver.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
To understand why the host networking mode is used and explore alternative configuration options, please visit [Coturn's Docker documentation](https://github.com/coturn/coturn/blob/master/docker/coturn/README.md).
|
||||||
|
|
||||||
|
For security recommendations see Synapse's [Coturn documentation](https://element-hq.github.io/synapse/latest/turn-howto.html).
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ stdenv.mkDerivation {
|
|||||||
include = [
|
include = [
|
||||||
"book.toml"
|
"book.toml"
|
||||||
"conduwuit-example.toml"
|
"conduwuit-example.toml"
|
||||||
|
"CONTRIBUTING.md"
|
||||||
"README.md"
|
"README.md"
|
||||||
"debian/README.md"
|
"debian/README.md"
|
||||||
"docs"
|
"docs"
|
||||||
|
|||||||
@@ -533,7 +533,7 @@ pub(crate) async fn deactivate_route(body: Ruma<deactivate::v3::Request>) -> Res
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make the user leave all rooms before deactivation
|
// Make the user leave all rooms before deactivation
|
||||||
client_server::leave_all_rooms(sender_user).await?;
|
client_server::leave_all_rooms(sender_user).await;
|
||||||
|
|
||||||
// Remove devices and mark account as deactivated
|
// Remove devices and mark account as deactivated
|
||||||
services().users.deactivate_account(sender_user)?;
|
services().users.deactivate_account(sender_user)?;
|
||||||
|
|||||||
@@ -17,7 +17,11 @@ use crate::{
|
|||||||
debug_warn,
|
debug_warn,
|
||||||
service::media::{FileMeta, UrlPreviewData},
|
service::media::{FileMeta, UrlPreviewData},
|
||||||
services,
|
services,
|
||||||
utils::{self, server_name::server_is_ours},
|
utils::{
|
||||||
|
self,
|
||||||
|
content_disposition::{content_disposition_type, make_content_disposition, sanitise_filename},
|
||||||
|
server_name::server_is_ours,
|
||||||
|
},
|
||||||
Error, Result, Ruma, RumaResponse,
|
Error, Result, Ruma, RumaResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -130,7 +134,13 @@ pub(crate) async fn create_content_route(
|
|||||||
mxc.clone(),
|
mxc.clone(),
|
||||||
body.filename
|
body.filename
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|filename| format!("attachment; filename={filename}"))
|
.map(|filename| {
|
||||||
|
format!(
|
||||||
|
"{}; filename={}",
|
||||||
|
content_disposition_type(&body.file, &body.content_type),
|
||||||
|
sanitise_filename(filename.to_owned())
|
||||||
|
)
|
||||||
|
})
|
||||||
.as_deref(),
|
.as_deref(),
|
||||||
body.content_type.as_deref(),
|
body.content_type.as_deref(),
|
||||||
&body.file,
|
&body.file,
|
||||||
@@ -175,19 +185,20 @@ pub(crate) async fn get_content_route(body: Ruma<get_content::v3::Request>) -> R
|
|||||||
if let Some(FileMeta {
|
if let Some(FileMeta {
|
||||||
content_type,
|
content_type,
|
||||||
file,
|
file,
|
||||||
..
|
content_disposition,
|
||||||
}) = services().media.get(mxc.clone()).await?
|
}) = services().media.get(mxc.clone()).await?
|
||||||
{
|
{
|
||||||
// TODO: safely sanitise filename to be included in the content-disposition
|
let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition));
|
||||||
|
|
||||||
Ok(get_content::v3::Response {
|
Ok(get_content::v3::Response {
|
||||||
file,
|
file,
|
||||||
content_type,
|
content_type,
|
||||||
content_disposition: Some("attachment".to_owned()),
|
content_disposition,
|
||||||
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
||||||
cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()),
|
cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()),
|
||||||
})
|
})
|
||||||
} else if !server_is_ours(&body.server_name) && body.allow_remote {
|
} else if !server_is_ours(&body.server_name) && body.allow_remote {
|
||||||
get_remote_content(
|
let response = get_remote_content(
|
||||||
&mxc,
|
&mxc,
|
||||||
&body.server_name,
|
&body.server_name,
|
||||||
body.media_id.clone(),
|
body.media_id.clone(),
|
||||||
@@ -198,6 +209,20 @@ pub(crate) async fn get_content_route(body: Ruma<get_content::v3::Request>) -> R
|
|||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
debug_warn!("Fetching media `{}` failed: {:?}", mxc, e);
|
debug_warn!("Fetching media `{}` failed: {:?}", mxc, e);
|
||||||
Error::BadRequest(ErrorKind::NotFound, "Remote media error.")
|
Error::BadRequest(ErrorKind::NotFound, "Remote media error.")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let content_disposition = Some(make_content_disposition(
|
||||||
|
&response.file,
|
||||||
|
&response.content_type,
|
||||||
|
response.content_disposition,
|
||||||
|
));
|
||||||
|
|
||||||
|
Ok(get_content::v3::Response {
|
||||||
|
file: response.file,
|
||||||
|
content_type: response.content_type,
|
||||||
|
content_disposition,
|
||||||
|
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
||||||
|
cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BadRequest(ErrorKind::NotFound, "Media not found."))
|
Err(Error::BadRequest(ErrorKind::NotFound, "Media not found."))
|
||||||
@@ -238,13 +263,15 @@ pub(crate) async fn get_content_as_filename_route(
|
|||||||
if let Some(FileMeta {
|
if let Some(FileMeta {
|
||||||
content_type,
|
content_type,
|
||||||
file,
|
file,
|
||||||
..
|
content_disposition,
|
||||||
}) = services().media.get(mxc.clone()).await?
|
}) = services().media.get(mxc.clone()).await?
|
||||||
{
|
{
|
||||||
|
let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition));
|
||||||
|
|
||||||
Ok(get_content_as_filename::v3::Response {
|
Ok(get_content_as_filename::v3::Response {
|
||||||
file,
|
file,
|
||||||
content_type,
|
content_type,
|
||||||
content_disposition: Some("attachment".to_owned()),
|
content_disposition,
|
||||||
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
||||||
cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()),
|
cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()),
|
||||||
})
|
})
|
||||||
@@ -258,13 +285,21 @@ pub(crate) async fn get_content_as_filename_route(
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(remote_content_response) => Ok(get_content_as_filename::v3::Response {
|
Ok(remote_content_response) => {
|
||||||
content_disposition: Some("attachment".to_owned()),
|
let content_disposition = Some(make_content_disposition(
|
||||||
|
&remote_content_response.file,
|
||||||
|
&remote_content_response.content_type,
|
||||||
|
remote_content_response.content_disposition,
|
||||||
|
));
|
||||||
|
|
||||||
|
Ok(get_content_as_filename::v3::Response {
|
||||||
|
content_disposition,
|
||||||
content_type: remote_content_response.content_type,
|
content_type: remote_content_response.content_type,
|
||||||
file: remote_content_response.file,
|
file: remote_content_response.file,
|
||||||
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
||||||
cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()),
|
cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()),
|
||||||
}),
|
})
|
||||||
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug_warn!("Fetching media `{}` failed: {:?}", mxc, e);
|
debug_warn!("Fetching media `{}` failed: {:?}", mxc, e);
|
||||||
Err(Error::BadRequest(ErrorKind::NotFound, "Remote media error."))
|
Err(Error::BadRequest(ErrorKind::NotFound, "Remote media error."))
|
||||||
@@ -309,7 +344,7 @@ pub(crate) async fn get_content_thumbnail_route(
|
|||||||
if let Some(FileMeta {
|
if let Some(FileMeta {
|
||||||
content_type,
|
content_type,
|
||||||
file,
|
file,
|
||||||
..
|
content_disposition,
|
||||||
}) = services()
|
}) = services()
|
||||||
.media
|
.media
|
||||||
.get_thumbnail(
|
.get_thumbnail(
|
||||||
@@ -323,12 +358,14 @@ pub(crate) async fn get_content_thumbnail_route(
|
|||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
|
let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition));
|
||||||
|
|
||||||
Ok(get_content_thumbnail::v3::Response {
|
Ok(get_content_thumbnail::v3::Response {
|
||||||
file,
|
file,
|
||||||
content_type,
|
content_type,
|
||||||
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
||||||
cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()),
|
cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()),
|
||||||
content_disposition: Some("attachment".to_owned()),
|
content_disposition,
|
||||||
})
|
})
|
||||||
} else if !server_is_ours(&body.server_name) && body.allow_remote {
|
} else if !server_is_ours(&body.server_name) && body.allow_remote {
|
||||||
if services()
|
if services()
|
||||||
@@ -373,12 +410,18 @@ pub(crate) async fn get_content_thumbnail_route(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let content_disposition = Some(make_content_disposition(
|
||||||
|
&get_thumbnail_response.file,
|
||||||
|
&get_thumbnail_response.content_type,
|
||||||
|
get_thumbnail_response.content_disposition,
|
||||||
|
));
|
||||||
|
|
||||||
Ok(get_content_thumbnail::v3::Response {
|
Ok(get_content_thumbnail::v3::Response {
|
||||||
file: get_thumbnail_response.file,
|
file: get_thumbnail_response.file,
|
||||||
content_type: get_thumbnail_response.content_type,
|
content_type: get_thumbnail_response.content_type,
|
||||||
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
||||||
cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()),
|
cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()),
|
||||||
content_disposition: Some("attachment".to_owned()),
|
content_disposition,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -437,12 +480,18 @@ async fn get_remote_content(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let content_disposition = Some(make_content_disposition(
|
||||||
|
&content_response.file,
|
||||||
|
&content_response.content_type,
|
||||||
|
content_response.content_disposition,
|
||||||
|
));
|
||||||
|
|
||||||
services()
|
services()
|
||||||
.media
|
.media
|
||||||
.create(
|
.create(
|
||||||
None,
|
None,
|
||||||
mxc.to_owned(),
|
mxc.to_owned(),
|
||||||
Some("attachment"),
|
content_disposition.as_deref(),
|
||||||
content_response.content_type.as_deref(),
|
content_response.content_type.as_deref(),
|
||||||
&content_response.file,
|
&content_response.file,
|
||||||
)
|
)
|
||||||
@@ -451,7 +500,7 @@ async fn get_remote_content(
|
|||||||
Ok(get_content::v3::Response {
|
Ok(get_content::v3::Response {
|
||||||
file: content_response.file,
|
file: content_response.file,
|
||||||
content_type: content_response.content_type,
|
content_type: content_response.content_type,
|
||||||
content_disposition: Some("attachment".to_owned()),
|
content_disposition,
|
||||||
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
||||||
cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()),
|
cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()),
|
||||||
})
|
})
|
||||||
|
|||||||
+100
-183
@@ -21,12 +21,13 @@ use ruma::{
|
|||||||
room::{
|
room::{
|
||||||
join_rules::{AllowRule, JoinRule, RoomJoinRulesEventContent},
|
join_rules::{AllowRule, JoinRule, RoomJoinRulesEventContent},
|
||||||
member::{MembershipState, RoomMemberEventContent},
|
member::{MembershipState, RoomMemberEventContent},
|
||||||
|
message::RoomMessageEventContent,
|
||||||
},
|
},
|
||||||
StateEventType, TimelineEventType,
|
StateEventType, TimelineEventType,
|
||||||
},
|
},
|
||||||
serde::Base64,
|
serde::Base64,
|
||||||
state_res, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId, OwnedServerName,
|
state_res, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId, OwnedServerName,
|
||||||
OwnedUserId, RoomId, RoomVersionId, UserId,
|
OwnedUserId, RoomId, RoomVersionId, ServerName, UserId,
|
||||||
};
|
};
|
||||||
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
|
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
@@ -40,6 +41,91 @@ use crate::{
|
|||||||
Error, PduEvent, Result, Ruma,
|
Error, PduEvent, Result, Ruma,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Checks if the room is banned in any way possible and the sender user is not
|
||||||
|
/// an admin.
|
||||||
|
///
|
||||||
|
/// Performs automatic deactivation if `auto_deactivate_banned_room_attempts` is
|
||||||
|
/// enabled
|
||||||
|
#[tracing::instrument]
|
||||||
|
async fn banned_room_check(user_id: &UserId, room_id: Option<&RoomId>, server_name: Option<&ServerName>) -> Result<()> {
|
||||||
|
if !services().users.is_admin(user_id)? {
|
||||||
|
if let Some(room_id) = room_id {
|
||||||
|
if services().rooms.metadata.is_banned(room_id)?
|
||||||
|
|| services()
|
||||||
|
.globals
|
||||||
|
.config
|
||||||
|
.forbidden_remote_server_names
|
||||||
|
.contains(&room_id.server_name().unwrap().to_owned())
|
||||||
|
{
|
||||||
|
warn!(
|
||||||
|
"User {user_id} who is not an admin attempted to send an invite for or attempted to join a banned \
|
||||||
|
room or banned room server name: {room_id}."
|
||||||
|
);
|
||||||
|
|
||||||
|
if services()
|
||||||
|
.globals
|
||||||
|
.config
|
||||||
|
.auto_deactivate_banned_room_attempts
|
||||||
|
{
|
||||||
|
warn!("Automatically deactivating user {user_id} due to attempted banned room join");
|
||||||
|
services()
|
||||||
|
.admin
|
||||||
|
.send_message(RoomMessageEventContent::text_plain(format!(
|
||||||
|
"Automatically deactivating user {user_id} due to attempted banned room join"
|
||||||
|
)))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// ignore errors
|
||||||
|
leave_all_rooms(user_id).await;
|
||||||
|
_ = services().users.deactivate_account(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::forbidden(),
|
||||||
|
"This room is banned on this homeserver.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if let Some(server_name) = server_name {
|
||||||
|
if services()
|
||||||
|
.globals
|
||||||
|
.config
|
||||||
|
.forbidden_remote_server_names
|
||||||
|
.contains(&server_name.to_owned())
|
||||||
|
{
|
||||||
|
warn!(
|
||||||
|
"User {user_id} who is not an admin tried joining a room which has the server name {server_name} \
|
||||||
|
that is globally forbidden. Rejecting.",
|
||||||
|
);
|
||||||
|
|
||||||
|
if services()
|
||||||
|
.globals
|
||||||
|
.config
|
||||||
|
.auto_deactivate_banned_room_attempts
|
||||||
|
{
|
||||||
|
warn!("Automatically deactivating user {user_id} due to attempted banned room join");
|
||||||
|
services()
|
||||||
|
.admin
|
||||||
|
.send_message(RoomMessageEventContent::text_plain(format!(
|
||||||
|
"Automatically deactivating user {user_id} due to attempted banned room join"
|
||||||
|
)))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// ignore errors
|
||||||
|
leave_all_rooms(user_id).await;
|
||||||
|
_ = services().users.deactivate_account(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::forbidden(),
|
||||||
|
"This remote server is banned on this homeserver.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/join`
|
/// # `POST /_matrix/client/r0/rooms/{roomId}/join`
|
||||||
///
|
///
|
||||||
/// Tries to join the sender user into a room.
|
/// Tries to join the sender user into a room.
|
||||||
@@ -53,32 +139,7 @@ pub(crate) async fn join_room_by_id_route(
|
|||||||
) -> Result<join_room_by_id::v3::Response> {
|
) -> Result<join_room_by_id::v3::Response> {
|
||||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||||
|
|
||||||
if services().rooms.metadata.is_banned(&body.room_id)? && !services().users.is_admin(sender_user)? {
|
banned_room_check(sender_user, Some(&body.room_id), body.room_id.server_name()).await?;
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::forbidden(),
|
|
||||||
"This room is banned on this homeserver.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(server) = body.room_id.server_name() {
|
|
||||||
if services()
|
|
||||||
.globals
|
|
||||||
.config
|
|
||||||
.forbidden_remote_server_names
|
|
||||||
.contains(&server.to_owned())
|
|
||||||
&& !services().users.is_admin(sender_user)?
|
|
||||||
{
|
|
||||||
warn!(
|
|
||||||
"User {sender_user} tried joining room ID {} which has a server name that is globally forbidden. \
|
|
||||||
Rejecting.",
|
|
||||||
body.room_id
|
|
||||||
);
|
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::forbidden(),
|
|
||||||
"This remote server is banned on this homeserver.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// There is no body.server_name for /roomId/join
|
// There is no body.server_name for /roomId/join
|
||||||
let mut servers = services()
|
let mut servers = services()
|
||||||
@@ -131,31 +192,7 @@ pub(crate) async fn join_room_by_id_or_alias_route(
|
|||||||
|
|
||||||
let (servers, room_id) = match OwnedRoomId::try_from(body.room_id_or_alias) {
|
let (servers, room_id) = match OwnedRoomId::try_from(body.room_id_or_alias) {
|
||||||
Ok(room_id) => {
|
Ok(room_id) => {
|
||||||
if services().rooms.metadata.is_banned(&room_id)? && !services().users.is_admin(sender_user)? {
|
banned_room_check(sender_user, Some(&room_id), room_id.server_name()).await?;
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::forbidden(),
|
|
||||||
"This room is banned on this homeserver.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(server) = room_id.server_name() {
|
|
||||||
if services()
|
|
||||||
.globals
|
|
||||||
.config
|
|
||||||
.forbidden_remote_server_names
|
|
||||||
.contains(&server.to_owned())
|
|
||||||
&& !services().users.is_admin(sender_user)?
|
|
||||||
{
|
|
||||||
warn!(
|
|
||||||
"User {sender_user} tried joining room ID {room_id} which has a server name that is globally \
|
|
||||||
forbidden. Rejecting.",
|
|
||||||
);
|
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::forbidden(),
|
|
||||||
"This remote server is banned on this homeserver.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut servers = body.server_name.clone();
|
let mut servers = body.server_name.clone();
|
||||||
servers.extend(
|
servers.extend(
|
||||||
@@ -186,69 +223,9 @@ pub(crate) async fn join_room_by_id_or_alias_route(
|
|||||||
(servers, room_id)
|
(servers, room_id)
|
||||||
},
|
},
|
||||||
Err(room_alias) => {
|
Err(room_alias) => {
|
||||||
if services()
|
|
||||||
.globals
|
|
||||||
.config
|
|
||||||
.forbidden_remote_server_names
|
|
||||||
.contains(&room_alias.server_name().to_owned())
|
|
||||||
&& !services().users.is_admin(sender_user)?
|
|
||||||
{
|
|
||||||
warn!(
|
|
||||||
"User {sender_user} tried joining room alias {room_alias} which has a server name that is \
|
|
||||||
globally forbidden. Rejecting.",
|
|
||||||
);
|
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::forbidden(),
|
|
||||||
"This remote server is banned on this homeserver.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let response = get_alias_helper(room_alias.clone(), Some(body.server_name.clone())).await?;
|
let response = get_alias_helper(room_alias.clone(), Some(body.server_name.clone())).await?;
|
||||||
|
|
||||||
if services().rooms.metadata.is_banned(&response.room_id)? && !services().users.is_admin(sender_user)? {
|
banned_room_check(sender_user, Some(&response.room_id), Some(room_alias.server_name())).await?;
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::forbidden(),
|
|
||||||
"This room is banned on this homeserver.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if services()
|
|
||||||
.globals
|
|
||||||
.config
|
|
||||||
.forbidden_remote_server_names
|
|
||||||
.contains(&room_alias.server_name().to_owned())
|
|
||||||
&& !services().users.is_admin(sender_user)?
|
|
||||||
{
|
|
||||||
warn!(
|
|
||||||
"User {sender_user} tried joining room alias {room_alias} with room ID {}, which the alias has a \
|
|
||||||
server name that is globally forbidden. Rejecting.",
|
|
||||||
&response.room_id
|
|
||||||
);
|
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::forbidden(),
|
|
||||||
"This remote server is banned on this homeserver.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(server) = response.room_id.server_name() {
|
|
||||||
if services()
|
|
||||||
.globals
|
|
||||||
.config
|
|
||||||
.forbidden_remote_server_names
|
|
||||||
.contains(&server.to_owned())
|
|
||||||
&& !services().users.is_admin(sender_user)?
|
|
||||||
{
|
|
||||||
warn!(
|
|
||||||
"User {sender_user} tried joining room alias {room_alias} with room ID {}, which has a server \
|
|
||||||
name that is globally forbidden. Rejecting.",
|
|
||||||
&response.room_id
|
|
||||||
);
|
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::forbidden(),
|
|
||||||
"This remote server is banned on this homeserver.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut servers = body.server_name;
|
let mut servers = body.server_name;
|
||||||
servers.extend(response.servers);
|
servers.extend(response.servers);
|
||||||
@@ -321,30 +298,7 @@ pub(crate) async fn invite_user_route(body: Ruma<invite_user::v3::Request>) -> R
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if services().rooms.metadata.is_banned(&body.room_id)? && !services().users.is_admin(sender_user)? {
|
banned_room_check(sender_user, Some(&body.room_id), body.room_id.server_name()).await?;
|
||||||
info!(
|
|
||||||
"Local user {} who is not an admin attempted to send an invite for banned room {}.",
|
|
||||||
&sender_user, &body.room_id
|
|
||||||
);
|
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::forbidden(),
|
|
||||||
"This room is banned on this homeserver.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(server) = body.room_id.server_name() {
|
|
||||||
if services()
|
|
||||||
.globals
|
|
||||||
.config
|
|
||||||
.forbidden_remote_server_names
|
|
||||||
.contains(&server.to_owned())
|
|
||||||
{
|
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::forbidden(),
|
|
||||||
"Server is banned on this homeserver.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let invite_user::v3::InvitationRecipient::UserId {
|
if let invite_user::v3::InvitationRecipient::UserId {
|
||||||
user_id,
|
user_id,
|
||||||
@@ -363,15 +317,6 @@ pub(crate) async fn invite_user_route(body: Ruma<invite_user::v3::Request>) -> R
|
|||||||
pub(crate) async fn kick_user_route(body: Ruma<kick_user::v3::Request>) -> Result<kick_user::v3::Response> {
|
pub(crate) async fn kick_user_route(body: Ruma<kick_user::v3::Request>) -> Result<kick_user::v3::Response> {
|
||||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||||
|
|
||||||
if let Ok(true) = services()
|
|
||||||
.rooms
|
|
||||||
.state_cache
|
|
||||||
.is_left(sender_user, &body.room_id)
|
|
||||||
{
|
|
||||||
info!("{} is not in room {}", &body.user_id, &body.room_id);
|
|
||||||
return Ok(kick_user::v3::Response {});
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut event: RoomMemberEventContent = serde_json::from_str(
|
let mut event: RoomMemberEventContent = serde_json::from_str(
|
||||||
services()
|
services()
|
||||||
.rooms
|
.rooms
|
||||||
@@ -428,17 +373,6 @@ pub(crate) async fn kick_user_route(body: Ruma<kick_user::v3::Request>) -> Resul
|
|||||||
pub(crate) async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_user::v3::Response> {
|
pub(crate) async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_user::v3::Response> {
|
||||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||||
|
|
||||||
if let Ok(Some(membership_event)) = services()
|
|
||||||
.rooms
|
|
||||||
.state_accessor
|
|
||||||
.get_member(&body.room_id, sender_user)
|
|
||||||
{
|
|
||||||
if membership_event.membership == MembershipState::Ban {
|
|
||||||
info!("{} is already banned in {}", &body.user_id, &body.room_id);
|
|
||||||
return Ok(ban_user::v3::Response {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let event = services()
|
let event = services()
|
||||||
.rooms
|
.rooms
|
||||||
.state_accessor
|
.state_accessor
|
||||||
@@ -446,11 +380,11 @@ pub(crate) async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<
|
|||||||
.map_or(
|
.map_or(
|
||||||
Ok(RoomMemberEventContent {
|
Ok(RoomMemberEventContent {
|
||||||
membership: MembershipState::Ban,
|
membership: MembershipState::Ban,
|
||||||
displayname: services().users.displayname(&body.user_id)?,
|
displayname: None,
|
||||||
avatar_url: services().users.avatar_url(&body.user_id)?,
|
avatar_url: None,
|
||||||
is_direct: None,
|
is_direct: None,
|
||||||
third_party_invite: None,
|
third_party_invite: None,
|
||||||
blurhash: services().users.blurhash(&body.user_id)?,
|
blurhash: services().users.blurhash(&body.user_id).unwrap_or_default(),
|
||||||
reason: body.reason.clone(),
|
reason: body.reason.clone(),
|
||||||
join_authorized_via_users_server: None,
|
join_authorized_via_users_server: None,
|
||||||
}),
|
}),
|
||||||
@@ -458,14 +392,8 @@ pub(crate) async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<
|
|||||||
serde_json::from_str(event.content.get())
|
serde_json::from_str(event.content.get())
|
||||||
.map(|event: RoomMemberEventContent| RoomMemberEventContent {
|
.map(|event: RoomMemberEventContent| RoomMemberEventContent {
|
||||||
membership: MembershipState::Ban,
|
membership: MembershipState::Ban,
|
||||||
displayname: services()
|
displayname: None,
|
||||||
.users
|
avatar_url: None,
|
||||||
.displayname(&body.user_id)
|
|
||||||
.unwrap_or_default(),
|
|
||||||
avatar_url: services()
|
|
||||||
.users
|
|
||||||
.avatar_url(&body.user_id)
|
|
||||||
.unwrap_or_default(),
|
|
||||||
blurhash: services().users.blurhash(&body.user_id).unwrap_or_default(),
|
blurhash: services().users.blurhash(&body.user_id).unwrap_or_default(),
|
||||||
reason: body.reason.clone(),
|
reason: body.reason.clone(),
|
||||||
join_authorized_via_users_server: None,
|
join_authorized_via_users_server: None,
|
||||||
@@ -514,17 +442,6 @@ pub(crate) async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<
|
|||||||
pub(crate) async fn unban_user_route(body: Ruma<unban_user::v3::Request>) -> Result<unban_user::v3::Response> {
|
pub(crate) async fn unban_user_route(body: Ruma<unban_user::v3::Request>) -> Result<unban_user::v3::Response> {
|
||||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||||
|
|
||||||
if let Ok(Some(membership_event)) = services()
|
|
||||||
.rooms
|
|
||||||
.state_accessor
|
|
||||||
.get_member(&body.room_id, sender_user)
|
|
||||||
{
|
|
||||||
if membership_event.membership != MembershipState::Ban {
|
|
||||||
info!("{} is already unbanned in {}", &body.user_id, &body.room_id);
|
|
||||||
return Ok(unban_user::v3::Response {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut event: RoomMemberEventContent = serde_json::from_str(
|
let mut event: RoomMemberEventContent = serde_json::from_str(
|
||||||
services()
|
services()
|
||||||
.rooms
|
.rooms
|
||||||
@@ -1606,8 +1523,9 @@ pub(crate) async fn invite_helper(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a user leave all their joined rooms
|
// Make a user leave all their joined rooms, forgets all rooms, and ignores
|
||||||
pub(crate) async fn leave_all_rooms(user_id: &UserId) -> Result<()> {
|
// errors
|
||||||
|
pub(crate) async fn leave_all_rooms(user_id: &UserId) {
|
||||||
let all_rooms = services()
|
let all_rooms = services()
|
||||||
.rooms
|
.rooms
|
||||||
.state_cache
|
.state_cache
|
||||||
@@ -1627,10 +1545,9 @@ pub(crate) async fn leave_all_rooms(user_id: &UserId) -> Result<()> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ignore errors
|
// ignore errors
|
||||||
|
_ = services().rooms.state_cache.forget(&room_id, user_id);
|
||||||
_ = leave_room(user_id, &room_id, None).await;
|
_ = leave_room(user_id, &room_id, None).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<String>) -> Result<()> {
|
pub(crate) async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<String>) -> Result<()> {
|
||||||
|
|||||||
@@ -91,12 +91,12 @@ fn is_report_valid(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if services()
|
if !services()
|
||||||
.rooms
|
.rooms
|
||||||
.state_cache
|
.state_cache
|
||||||
.room_members(&pdu.room_id)
|
.room_members(&pdu.room_id)
|
||||||
.filter_map(Result::ok)
|
.filter_map(Result::ok)
|
||||||
.any(|user_id| user_id != *sender_user)
|
.any(|user_id| user_id == *sender_user)
|
||||||
{
|
{
|
||||||
return Err(Error::BadRequest(
|
return Err(Error::BadRequest(
|
||||||
ErrorKind::NotFound,
|
ErrorKind::NotFound,
|
||||||
|
|||||||
@@ -207,6 +207,8 @@ pub(crate) struct Config {
|
|||||||
|
|
||||||
#[serde(default = "Vec::new")]
|
#[serde(default = "Vec::new")]
|
||||||
pub(crate) auto_join_rooms: Vec<OwnedRoomId>,
|
pub(crate) auto_join_rooms: Vec<OwnedRoomId>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) auto_deactivate_banned_room_attempts: bool,
|
||||||
|
|
||||||
#[serde(default = "default_rocksdb_log_level")]
|
#[serde(default = "default_rocksdb_log_level")]
|
||||||
pub(crate) rocksdb_log_level: String,
|
pub(crate) rocksdb_log_level: String,
|
||||||
@@ -612,6 +614,10 @@ impl fmt::Display for Config {
|
|||||||
"Allow incoming profile lookup federation requests",
|
"Allow incoming profile lookup federation requests",
|
||||||
&self.allow_profile_lookup_federation_requests.to_string(),
|
&self.allow_profile_lookup_federation_requests.to_string(),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"Auto deactivate banned room join attempts",
|
||||||
|
&self.auto_deactivate_banned_room_attempts.to_string(),
|
||||||
|
),
|
||||||
("Notification push path", &self.notification_push_path),
|
("Notification push path", &self.notification_push_path),
|
||||||
("Allow room creation", &self.allow_room_creation.to_string()),
|
("Allow room creation", &self.allow_room_creation.to_string()),
|
||||||
(
|
(
|
||||||
|
|||||||
+34
-1
@@ -6,7 +6,7 @@ use axum::{
|
|||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use http::{
|
use http::{
|
||||||
header::{self, HeaderName},
|
header::{self, HeaderName, HeaderValue},
|
||||||
Method, StatusCode, Uri,
|
Method, StatusCode, Uri,
|
||||||
};
|
};
|
||||||
use ruma::api::client::{
|
use ruma::api::client::{
|
||||||
@@ -17,6 +17,7 @@ use tower::ServiceBuilder;
|
|||||||
use tower_http::{
|
use tower_http::{
|
||||||
catch_panic::CatchPanicLayer,
|
catch_panic::CatchPanicLayer,
|
||||||
cors::{self, CorsLayer},
|
cors::{self, CorsLayer},
|
||||||
|
set_header::SetResponseHeaderLayer,
|
||||||
trace::{DefaultOnFailure, DefaultOnRequest, DefaultOnResponse, TraceLayer},
|
trace::{DefaultOnFailure, DefaultOnRequest, DefaultOnResponse, TraceLayer},
|
||||||
ServiceBuilderExt as _,
|
ServiceBuilderExt as _,
|
||||||
};
|
};
|
||||||
@@ -32,6 +33,9 @@ pub(crate) async fn build(server: &Server) -> io::Result<axum::routing::IntoMake
|
|||||||
let base_middlewares = base_middlewares.layer(sentry_tower::NewSentryLayer::<http::Request<_>>::new_from_top());
|
let base_middlewares = base_middlewares.layer(sentry_tower::NewSentryLayer::<http::Request<_>>::new_from_top());
|
||||||
|
|
||||||
let x_forwarded_for = HeaderName::from_static("x-forwarded-for");
|
let x_forwarded_for = HeaderName::from_static("x-forwarded-for");
|
||||||
|
let permissions_policy = HeaderName::from_static("permissions-policy");
|
||||||
|
let origin_agent_cluster = HeaderName::from_static("origin-agent-cluster"); // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin-Agent-Cluster
|
||||||
|
|
||||||
let middlewares = base_middlewares
|
let middlewares = base_middlewares
|
||||||
.sensitive_headers([header::AUTHORIZATION])
|
.sensitive_headers([header::AUTHORIZATION])
|
||||||
.sensitive_request_headers([x_forwarded_for].into())
|
.sensitive_request_headers([x_forwarded_for].into())
|
||||||
@@ -44,6 +48,33 @@ pub(crate) async fn build(server: &Server) -> io::Result<axum::routing::IntoMake
|
|||||||
.on_response(DefaultOnResponse::new().level(Level::DEBUG)),
|
.on_response(DefaultOnResponse::new().level(Level::DEBUG)),
|
||||||
)
|
)
|
||||||
.layer(axum::middleware::from_fn(request_handle))
|
.layer(axum::middleware::from_fn(request_handle))
|
||||||
|
.layer(SetResponseHeaderLayer::if_not_present(
|
||||||
|
origin_agent_cluster,
|
||||||
|
HeaderValue::from_static("?1"),
|
||||||
|
))
|
||||||
|
.layer(SetResponseHeaderLayer::if_not_present(
|
||||||
|
header::X_CONTENT_TYPE_OPTIONS,
|
||||||
|
HeaderValue::from_static("nosniff"),
|
||||||
|
))
|
||||||
|
.layer(SetResponseHeaderLayer::if_not_present(
|
||||||
|
header::X_XSS_PROTECTION,
|
||||||
|
HeaderValue::from_static("0"),
|
||||||
|
))
|
||||||
|
.layer(SetResponseHeaderLayer::if_not_present(
|
||||||
|
header::X_FRAME_OPTIONS,
|
||||||
|
HeaderValue::from_static("DENY"),
|
||||||
|
))
|
||||||
|
.layer(SetResponseHeaderLayer::if_not_present(
|
||||||
|
permissions_policy,
|
||||||
|
HeaderValue::from_static("interest-cohort=(),browsing-topics=()"),
|
||||||
|
))
|
||||||
|
.layer(SetResponseHeaderLayer::if_not_present(
|
||||||
|
header::CONTENT_SECURITY_POLICY,
|
||||||
|
HeaderValue::from_static(
|
||||||
|
"sandbox; default-src 'none'; font-src 'none'; script-src 'none'; plugin-types application/pdf; \
|
||||||
|
style-src 'unsafe-inline'; object-src 'self'; frame-ancesors 'none';",
|
||||||
|
),
|
||||||
|
))
|
||||||
.layer(cors_layer(server))
|
.layer(cors_layer(server))
|
||||||
.layer(DefaultBodyLimit::max(
|
.layer(DefaultBodyLimit::max(
|
||||||
server
|
server
|
||||||
@@ -130,6 +161,8 @@ fn request_result_log(method: &Method, uri: &Uri, result: &axum::response::Respo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cross-Origin-Resource-Sharing header as defined by spec:
|
||||||
|
/// <https://spec.matrix.org/latest/client-server-api/#web-browser-clients>
|
||||||
fn cors_layer(_server: &Server) -> CorsLayer {
|
fn cors_layer(_server: &Server) -> CorsLayer {
|
||||||
const METHODS: [Method; 7] = [
|
const METHODS: [Method; 7] = [
|
||||||
Method::GET,
|
Method::GET,
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ pub(crate) async fn deactivate(
|
|||||||
services().users.deactivate_account(&user_id)?;
|
services().users.deactivate_account(&user_id)?;
|
||||||
|
|
||||||
if leave_rooms {
|
if leave_rooms {
|
||||||
leave_all_rooms(&user_id).await?;
|
leave_all_rooms(&user_id).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(RoomMessageEventContent::text_plain(format!(
|
Ok(RoomMessageEventContent::text_plain(format!(
|
||||||
@@ -282,7 +282,7 @@ pub(crate) async fn deactivate_all(body: Vec<&str>, leave_rooms: bool, force: bo
|
|||||||
|
|
||||||
if leave_rooms {
|
if leave_rooms {
|
||||||
for &user_id in &user_ids {
|
for &user_id in &user_ids {
|
||||||
_ = leave_all_rooms(user_id).await;
|
leave_all_rooms(user_id).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
use infer::MatcherType;
|
||||||
|
|
||||||
|
/// Returns a Content-Disposition of `attachment` or `inline`, depending on the
|
||||||
|
/// *parsed* contents of the file uploaded via format magic keys using `infer`
|
||||||
|
/// crate (basically libmagic without needing libmagic).
|
||||||
|
///
|
||||||
|
/// This forbids trusting what the client or remote server says the file is from
|
||||||
|
/// their `Content-Type` and we try to detect it ourselves. Also returns
|
||||||
|
/// `attachment` if the Content-Type does not match what we detected.
|
||||||
|
///
|
||||||
|
/// TODO: add a "strict" function for comparing the Content-Type with what we
|
||||||
|
/// detected: `file_type.mime_type() != content_type`
|
||||||
|
pub(crate) fn content_disposition_type(buf: &[u8], _content_type: &Option<String>) -> &'static str {
|
||||||
|
let Some(file_type) = infer::get(buf) else {
|
||||||
|
return "attachment";
|
||||||
|
};
|
||||||
|
|
||||||
|
match file_type.matcher_type() {
|
||||||
|
MatcherType::Image | MatcherType::Audio | MatcherType::Text | MatcherType::Video => "inline",
|
||||||
|
_ => "attachment",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// sanitises the file name for the Content-Disposition using
|
||||||
|
/// `sanitize_filename` crate
|
||||||
|
#[tracing::instrument]
|
||||||
|
pub(crate) fn sanitise_filename(filename: String) -> String {
|
||||||
|
let options = sanitize_filename::Options {
|
||||||
|
truncate: false,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
sanitize_filename::sanitize_with_options(filename, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// creates the final Content-Disposition based on whether the filename exists
|
||||||
|
/// or not.
|
||||||
|
///
|
||||||
|
/// if filename exists: `Content-Disposition: attachment/inline;
|
||||||
|
/// filename=filename.ext` else: `Content-Disposition: attachment/inline`
|
||||||
|
#[tracing::instrument(skip(file))]
|
||||||
|
pub(crate) fn make_content_disposition(
|
||||||
|
file: &[u8], content_type: &Option<String>, content_disposition: Option<String>,
|
||||||
|
) -> String {
|
||||||
|
let filename = content_disposition.map_or_else(String::new, |content_disposition| {
|
||||||
|
let (_, filename) = content_disposition
|
||||||
|
.split_once("filename=")
|
||||||
|
.unwrap_or(("", ""));
|
||||||
|
|
||||||
|
if filename.is_empty() {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
sanitise_filename(filename.to_owned())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if !filename.is_empty() {
|
||||||
|
// Content-Disposition: attachment/inline; filename=filename.ext
|
||||||
|
format!("{}; filename={}", content_disposition_type(file, content_type), filename)
|
||||||
|
} else {
|
||||||
|
// Content-Disposition: attachment/inline
|
||||||
|
String::from(content_disposition_type(file, content_type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn string_sanitisation() {
|
||||||
|
const SAMPLE: &str =
|
||||||
|
"🏳️⚧️this\\r\\n įs \r\\n ä \\r\nstrïng 🥴that\n\r ../../../../../../../may be\r\n malicious🏳️⚧️";
|
||||||
|
const SANITISED: &str = "🏳️⚧️thisrn įs n ä rstrïng 🥴that ..............may be malicious🏳️⚧️";
|
||||||
|
|
||||||
|
let options = sanitize_filename::Options {
|
||||||
|
windows: true,
|
||||||
|
truncate: true,
|
||||||
|
replacement: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
// cargo test -- --nocapture
|
||||||
|
println!("{}", SAMPLE);
|
||||||
|
println!("{}", sanitize_filename::sanitize_with_options(SAMPLE, options.clone()));
|
||||||
|
println!("{:?}", SAMPLE);
|
||||||
|
println!("{:?}", sanitize_filename::sanitize_with_options(SAMPLE, options.clone()));
|
||||||
|
|
||||||
|
assert_eq!(SANITISED, sanitize_filename::sanitize_with_options(SAMPLE, options.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
pub(crate) mod clap;
|
pub(crate) mod clap;
|
||||||
|
pub(crate) mod content_disposition;
|
||||||
pub(crate) mod debug;
|
pub(crate) mod debug;
|
||||||
pub(crate) mod error;
|
pub(crate) mod error;
|
||||||
pub(crate) mod server_name;
|
pub(crate) mod server_name;
|
||||||
|
|||||||
Reference in New Issue
Block a user