├── .dockerignore ├── .github ├── CODEOWNERS ├── FUNDING.yml ├── codecov.yaml ├── ISSUE_TEMPLATE │ └── FEATURE_REQUEST.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── helm.yml │ └── gh-pages.yml ├── cmd ├── create-account │ ├── testdata │ │ └── my.pass │ └── main_test.go ├── dendrite-demo-yggdrasil │ ├── embed │ │ └── embed_other.go │ ├── README.md │ └── yggconn │ │ └── client.go ├── dendrite-demo-pinecone │ ├── embed │ │ └── embed_other.go │ └── defaults │ │ └── defaults.go ├── dendrite │ └── main_test.go └── dendrite-upgrade-tests │ └── tar.go ├── mediaapi ├── bimg-96x96-crop.jpg ├── nfnt-96x96-crop.jpg ├── storage │ ├── storage_wasm.go │ ├── storage.go │ ├── sqlite3 │ │ └── mediaapi.go │ ├── postgres │ │ └── mediaapi.go │ ├── interface.go │ └── tables │ │ └── interface.go ├── routing │ └── download_test.go ├── README.md └── mediaapi.go ├── helm ├── dendrite │ ├── .helm-docs │ │ ├── state.gotmpl │ │ ├── about.gotmpl │ │ ├── appservices.gotmpl │ │ ├── database.gotmpl │ │ └── monitoring.gotmpl │ ├── grafana_dashboards │ │ └── dendrite-rev2.png │ ├── ci │ │ ├── ct-ingress-values.yaml │ │ └── ct-postgres-sharedsecret-values.yaml │ ├── templates │ │ ├── service.yaml │ │ ├── tests │ │ │ └── test-version.yaml │ │ ├── configmap_grafana_dashboards.yaml │ │ ├── _overrides.yaml │ │ ├── prometheus-rules.yaml │ │ ├── servicemonitor.yaml │ │ └── secrets.yaml │ ├── Chart.yaml │ └── README.md.gotmpl ├── cr.yaml └── ct.yaml ├── docs ├── images │ └── details-button-location.jpg ├── Gemfile ├── installation.md ├── administration.md ├── installation │ ├── manual.md │ ├── docker.md │ ├── helm.md │ ├── manual │ │ ├── 5_starting_dendrite.md │ │ └── 1_build.md │ └── helm │ │ └── 1_helm.md ├── development.md ├── _includes │ └── deprecation.html ├── _config.yml ├── hiawatha │ └── dendrite-sample.conf ├── INSTALL.md ├── nginx │ └── dendrite-sample.conf ├── index.md └── administration │ └── 3_presence.md ├── test-dendritejs.sh ├── setup ├── base │ ├── static │ │ └── client │ │ │ └── login │ │ │ ├── spinner.gif │ │ │ ├── style.css │ │ │ └── index.html │ ├── sanity_other.go │ ├── federation.go │ └── sanity_unix.go ├── config │ ├── config_keyserver.go │ ├── config_mscs.go │ ├── config_address.go │ ├── config_roomserver.go │ ├── config_address_test.go │ ├── config_relayapi.go │ ├── config_syncapi.go │ ├── config_jetstream.go │ └── config_userapi.go ├── jetstream │ └── log.go └── process │ └── process.go ├── test ├── wasm │ ├── package.json │ └── index.js ├── testrig │ └── jetstream.go ├── slice.go └── keyring.go ├── internal ├── sqlutil │ ├── sqlite_cgo.go │ ├── sqlite_native.go │ ├── writer_dummy.go │ ├── unique_constraint_wasm.go │ ├── unique_constraint.go │ ├── unique_constraint_cgo.go │ └── uri.go ├── tracing_test.go ├── caching │ ├── cache_roomversions.go │ ├── cache_space_rooms.go │ ├── cache_roomevents.go │ ├── cache_roomservernids.go │ ├── cache_federationevents.go │ ├── cache_lazy_load_members.go │ └── cache_eventstatekeys.go ├── pushrules │ ├── default_content.go │ ├── default.go │ ├── action_test.go │ └── condition.go ├── mutex.go ├── httputil │ ├── paths.go │ └── routing_test.go ├── pushgateway │ ├── client_test.go │ └── client.go ├── version.go ├── tracing.go └── log_windows.go ├── clientapi ├── auth │ ├── authtypes │ │ ├── logintypes.go │ │ ├── membership.go │ │ ├── flow.go │ │ ├── threepid.go │ │ └── profile.go │ └── login_application_service.go ├── README.md ├── api │ └── api.go ├── httputil │ └── parse.go ├── routing │ ├── directory_public_test.go │ ├── whoami.go │ ├── register_secret_test.go │ ├── capabilities.go │ ├── deactivate.go │ └── server_notices_test.go └── userutil │ └── userutil.go ├── userapi ├── storage │ ├── postgres │ │ └── deltas │ │ │ ├── 20200929203058_is_active.go │ │ │ ├── 2022110411000001_server_names.go │ │ │ ├── 20201001204705_last_seen_ts_ip.go │ │ │ ├── 2022021013023800_add_account_type.go │ │ │ └── 2022042612000000_xsigning_idx.go │ └── sqlite3 │ │ ├── constraint_wasm.go │ │ └── deltas │ │ ├── 2022110411000001_server_names.go │ │ ├── 2022021012490600_add_account_type.go │ │ └── 20200929203058_is_active.go ├── util │ ├── stats_wasm.go │ ├── stats_windows.go │ └── stats.go ├── internal │ ├── device_list_update_default.go │ └── device_list_update_sytest.go └── types │ └── statistics.go ├── syncapi ├── streams │ ├── template_stream.go │ ├── streamprovider.go │ ├── stream_devicelist.go │ └── stream_sendtodevice.go ├── producers │ ├── appservices.go │ └── federationapi_presence.go ├── storage │ ├── postgres │ │ └── deltas │ │ │ ├── 20230201152200_rename_index.go │ │ │ └── 20210112130000_sendtodevice_sentcolumn.go │ ├── storage_wasm.go │ ├── storage.go │ ├── shared │ │ └── storage_sync_test.go │ └── sqlite3 │ │ └── deltas │ │ └── 20201211125500_sequences.go ├── types │ └── provider.go └── synctypes │ └── filter_test.go ├── sytest-blacklist ├── federationapi ├── storage │ ├── postgres │ │ └── deltas │ │ │ ├── 2021020411080000_rooms.go │ │ │ └── 2022042812473400_addexpiresat.go │ ├── sqlite3 │ │ └── deltas │ │ │ └── 2021020411080000_rooms.go │ ├── shared │ │ └── receipt │ │ │ └── receipt.go │ ├── storage_wasm.go │ └── storage.go ├── routing │ └── version.go └── consumers │ └── roomserver_test.go ├── roomserver ├── internal │ └── perform │ │ ├── perform_forget.go │ │ └── perform_publish.go ├── api │ └── alias_test.go └── storage │ ├── postgres │ └── deltas │ │ ├── 20201028212440_add_forgotten_column.go │ │ ├── 20230131091021_published_appservice_pkey.go │ │ └── 20221027084407_published_appservice.go │ ├── storage_wasm.go │ ├── storage.go │ └── shared │ └── prepare.go ├── .gitignore ├── contrib ├── dendrite-demo-i2p │ └── main_test.go └── dendrite-demo-tor │ └── main_test.go ├── relayapi └── storage │ ├── storage_wasm.go │ └── storage.go └── Dockerfile /.dockerignore: -------------------------------------------------------------------------------- 1 | bin 2 | *.wasm -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @matrix-org/dendrite-core -------------------------------------------------------------------------------- /cmd/create-account/testdata/my.pass: -------------------------------------------------------------------------------- 1 | mySecretPass -------------------------------------------------------------------------------- /mediaapi/bimg-96x96-crop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matrix-org/dendrite/HEAD/mediaapi/bimg-96x96-crop.jpg -------------------------------------------------------------------------------- /mediaapi/nfnt-96x96-crop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matrix-org/dendrite/HEAD/mediaapi/nfnt-96x96-crop.jpg -------------------------------------------------------------------------------- /helm/dendrite/.helm-docs/state.gotmpl: -------------------------------------------------------------------------------- 1 | {{ define "chart.state" }} 2 | Status: **NOT PRODUCTION READY** 3 | {{ end }} -------------------------------------------------------------------------------- /docs/images/details-button-location.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matrix-org/dendrite/HEAD/docs/images/details-button-location.jpg -------------------------------------------------------------------------------- /helm/cr.yaml: -------------------------------------------------------------------------------- 1 | release-name-template: "helm-{{ .Name }}-{{ .Version }}" 2 | pages-index-path: docs/index.yaml 3 | make-release-latest: false -------------------------------------------------------------------------------- /test-dendritejs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | GOOS=js GOARCH=wasm go test -v -exec "$(pwd)/test/wasm/index.js" ./cmd/dendritejs-pinecone 4 | -------------------------------------------------------------------------------- /setup/base/static/client/login/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matrix-org/dendrite/HEAD/setup/base/static/client/login/spinner.gif -------------------------------------------------------------------------------- /helm/dendrite/grafana_dashboards/dendrite-rev2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matrix-org/dendrite/HEAD/helm/dendrite/grafana_dashboards/dendrite-rev2.png -------------------------------------------------------------------------------- /setup/base/sanity_other.go: -------------------------------------------------------------------------------- 1 | //go:build !unix 2 | // +build !unix 3 | 4 | package base 5 | 6 | func PlatformSanityChecks() { 7 | // Nothing to do yet. 8 | } 9 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # One username per supported platform and one custom link 2 | patreon: matrixdotorg 3 | liberapay: matrixdotorg 4 | custom: https://paypal.me/matrixdotorg 5 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | gem "github-pages", "~> 226", group: :jekyll_plugins 3 | group :jekyll_plugins do 4 | gem "jekyll-feed", "~> 0.15.1" 5 | end 6 | -------------------------------------------------------------------------------- /helm/dendrite/.helm-docs/about.gotmpl: -------------------------------------------------------------------------------- 1 | {{ define "chart.about" }} 2 | ## About 3 | 4 | This chart creates a monolith deployment, including an optionally enabled PostgreSQL dependency to connect to. 5 | {{ end }} -------------------------------------------------------------------------------- /test/wasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "isomorphic-ws": "^4.0.1", 4 | "sql.js": "github:neilalexander/sql.js#252a72bf57b0538cbd49bbd6f70af71e516966ae", 5 | "ws": "^7.5.10" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /cmd/dendrite-demo-yggdrasil/embed/embed_other.go: -------------------------------------------------------------------------------- 1 | //go:build !elementweb 2 | // +build !elementweb 3 | 4 | package embed 5 | 6 | import "github.com/gorilla/mux" 7 | 8 | func Embed(_ *mux.Router, _ int, _ string) { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /helm/dendrite/.helm-docs/appservices.gotmpl: -------------------------------------------------------------------------------- 1 | {{ define "chart.appservices" }} 2 | ## Usage with appservices 3 | 4 | Create a folder `appservices` and place your configurations in there. The configurations will be read and placed in a secret `dendrite-appservices-conf`. 5 | {{ end }} -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | has_children: true 4 | nav_order: 2 5 | permalink: /installation 6 | --- 7 | 8 | {% include deprecation.html %} 9 | 10 | # Installation 11 | 12 | This section contains documentation on installing a new Dendrite deployment. 13 | -------------------------------------------------------------------------------- /internal/sqlutil/sqlite_cgo.go: -------------------------------------------------------------------------------- 1 | //go:build cgo 2 | // +build cgo 3 | 4 | package sqlutil 5 | 6 | import ( 7 | _ "github.com/mattn/go-sqlite3" 8 | ) 9 | 10 | const SQLITE_DRIVER_NAME = "sqlite3" 11 | 12 | func sqliteDSNExtension(dsn string) string { 13 | return dsn 14 | } 15 | -------------------------------------------------------------------------------- /docs/administration.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Administration 3 | has_children: yes 4 | nav_order: 4 5 | permalink: /administration 6 | --- 7 | 8 | {% include deprecation.html %} 9 | 10 | # Administration 11 | 12 | This section contains documentation on managing your existing Dendrite deployment. 13 | -------------------------------------------------------------------------------- /docs/installation/manual.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Manual 3 | parent: Installation 4 | has_children: true 5 | nav_order: 5 6 | permalink: /manual 7 | --- 8 | 9 | {% include deprecation.html %} 10 | 11 | # Manual Installation 12 | 13 | This section contains documentation how to manually install Dendrite 14 | -------------------------------------------------------------------------------- /helm/ct.yaml: -------------------------------------------------------------------------------- 1 | remote: origin 2 | target-branch: main 3 | chart-repos: 4 | - bitnami=https://charts.bitnami.com/bitnami 5 | chart-dirs: 6 | - helm 7 | validate-maintainers: false 8 | # this should ensure the tarballs are in the appropriate location for GH pages, rather than repo root 9 | package-path: docs/ -------------------------------------------------------------------------------- /docs/installation/docker.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Docker 3 | parent: Installation 4 | has_children: true 5 | nav_order: 4 6 | permalink: /docker 7 | --- 8 | 9 | {% include deprecation.html %} 10 | 11 | # Installation using Docker 12 | 13 | This section contains documentation how to install Dendrite using Docker 14 | -------------------------------------------------------------------------------- /docs/development.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Development 3 | has_children: true 4 | permalink: /development 5 | --- 6 | 7 | {% include deprecation.html %} 8 | 9 | {% include deprecation.html %} 10 | 11 | # Development 12 | 13 | This section contains documentation that may be useful when helping to develop 14 | Dendrite. 15 | -------------------------------------------------------------------------------- /docs/installation/helm.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Helm 3 | parent: Installation 4 | has_children: true 5 | nav_order: 3 6 | permalink: /helm 7 | --- 8 | 9 | {% include deprecation.html %} 10 | 11 | # Helm 12 | 13 | This section contains documentation how to use [Helm](https://helm.sh/) to install Dendrite on a [Kubernetes](https://kubernetes.io/) cluster. 14 | -------------------------------------------------------------------------------- /helm/dendrite/ci/ct-ingress-values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | postgresql: 3 | enabled: true 4 | primary: 5 | persistence: 6 | size: 1Gi 7 | 8 | dendrite_config: 9 | global: 10 | server_name: "localhost" 11 | 12 | ingress: 13 | enabled: true 14 | 15 | # dashboard is an ConfigMap with labels - it does not harm on testing 16 | grafana: 17 | dashboards: 18 | enabled: true 19 | -------------------------------------------------------------------------------- /helm/dendrite/ci/ct-postgres-sharedsecret-values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | postgresql: 3 | enabled: true 4 | primary: 5 | persistence: 6 | size: 1Gi 7 | 8 | dendrite_config: 9 | global: 10 | server_name: "localhost" 11 | 12 | client_api: 13 | registration_shared_secret: "d233f2fcb0470845a8e150a20ef594ddbe0b4cf7fe482fb9d5120c198557acbf" # echo "dendrite" | sha256sum 14 | 15 | ingress: 16 | enabled: true 17 | -------------------------------------------------------------------------------- /.github/codecov.yaml: -------------------------------------------------------------------------------- 1 | flag_management: 2 | default_rules: 3 | carryforward: true 4 | 5 | coverage: 6 | status: 7 | project: 8 | default: 9 | target: auto 10 | threshold: 0.1% 11 | base: auto 12 | flags: 13 | - unittests 14 | patch: 15 | default: 16 | target: 75% 17 | threshold: 0% 18 | base: auto 19 | flags: 20 | - unittests -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | 11 | 12 | **Description:** 13 | 14 | 15 | -------------------------------------------------------------------------------- /helm/dendrite/templates/service.yaml: -------------------------------------------------------------------------------- 1 | {{ template "validate.config" . }} 2 | --- 3 | apiVersion: v1 4 | kind: Service 5 | metadata: 6 | namespace: {{ $.Release.Namespace }} 7 | name: {{ include "dendrite.fullname" . }} 8 | labels: 9 | {{- include "dendrite.labels" . | nindent 4 }} 10 | spec: 11 | selector: 12 | {{- include "dendrite.selectorLabels" . | nindent 4 }} 13 | ports: 14 | - name: http 15 | protocol: TCP 16 | port: {{ .Values.service.port }} 17 | targetPort: http -------------------------------------------------------------------------------- /docs/_includes/deprecation.html: -------------------------------------------------------------------------------- 1 | {: .warning-title } 2 | > This documentation is out of date! 3 | > 4 | > This documentation site is for the versions of Dendrite maintained by the Matrix.org Foundation (github.com/matrix-org/dendrite), available under the Apache 2.0 licence. 5 | > 6 | > If you are interested in the documentation for a later version of Dendrite, please refer to https://element-hq.github.io/dendrite/. -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | title: Dendrite 2 | description: >- 3 | Second-generation Matrix homeserver written in Go! 4 | baseurl: "/dendrite" # the subpath of your site, e.g. /blog 5 | url: "" 6 | twitter_username: matrixdotorg 7 | github_username: matrix-org 8 | remote_theme: just-the-docs/just-the-docs 9 | plugins: 10 | - jekyll-feed 11 | aux_links: 12 | "GitHub": 13 | - "//github.com/matrix-org/dendrite" 14 | aux_links_new_tab: true 15 | sass: 16 | sass_dir: _sass 17 | style: compressed 18 | exclude: 19 | - INSTALL.md 20 | -------------------------------------------------------------------------------- /helm/dendrite/.helm-docs/database.gotmpl: -------------------------------------------------------------------------------- 1 | {{ define "chart.dbCreation" }} 2 | ## Manual database creation 3 | 4 | (You can skip this, if you're deploying the PostgreSQL dependency) 5 | 6 | You'll need to create the following database before starting Dendrite (see [installation](https://matrix-org.github.io/dendrite/installation/database#single-database-creation)): 7 | 8 | ```postgres 9 | create database dendrite 10 | ``` 11 | 12 | or 13 | 14 | ```bash 15 | sudo -u postgres createdb -O dendrite -E UTF-8 dendrite 16 | ``` 17 | 18 | {{ end }} -------------------------------------------------------------------------------- /helm/dendrite/templates/tests/test-version.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: "{{ include "dendrite.fullname" . }}-test-version" 6 | labels: 7 | {{- include "dendrite.selectorLabels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | containers: 12 | - name: curl 13 | image: curlimages/curl 14 | imagePullPolicy: IfNotPresent 15 | args: 16 | - 'http://{{- include "dendrite.fullname" . -}}:8008/_matrix/client/versions' 17 | restartPolicy: Never 18 | -------------------------------------------------------------------------------- /internal/sqlutil/sqlite_native.go: -------------------------------------------------------------------------------- 1 | //go:build !cgo 2 | // +build !cgo 3 | 4 | package sqlutil 5 | 6 | import ( 7 | "strings" 8 | ) 9 | 10 | const SQLITE_DRIVER_NAME = "sqlite" 11 | 12 | func sqliteDSNExtension(dsn string) string { 13 | // add query parameters to the dsn 14 | if strings.Contains(dsn, "?") { 15 | dsn += "&" 16 | } else { 17 | dsn += "?" 18 | } 19 | 20 | // wait some time before erroring if the db is locked 21 | // https://gitlab.com/cznic/sqlite/-/issues/106#note_1058094993 22 | dsn += "_pragma=busy_timeout%3d10000" 23 | return dsn 24 | } 25 | -------------------------------------------------------------------------------- /helm/dendrite/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: dendrite 3 | version: "0.14.6" 4 | appVersion: "0.13.8" 5 | description: Dendrite Matrix Homeserver 6 | type: application 7 | icon: https://avatars.githubusercontent.com/u/8418310?s=48&v=4 8 | keywords: 9 | - matrix 10 | - chat 11 | - homeserver 12 | - dendrite 13 | home: https://github.com/matrix-org/dendrite 14 | sources: 15 | - https://github.com/matrix-org/dendrite 16 | dependencies: 17 | - name: postgresql 18 | version: 14.2.3 19 | repository: https://charts.bitnami.com/bitnami 20 | condition: postgresql.enabled 21 | -------------------------------------------------------------------------------- /clientapi/auth/authtypes/logintypes.go: -------------------------------------------------------------------------------- 1 | package authtypes 2 | 3 | // LoginType are specified by http://matrix.org/docs/spec/client_server/r0.2.0.html#login-types 4 | type LoginType string 5 | 6 | // The relevant login types implemented in Dendrite 7 | const ( 8 | LoginTypePassword = "m.login.password" 9 | LoginTypeDummy = "m.login.dummy" 10 | LoginTypeSharedSecret = "org.matrix.login.shared_secret" 11 | LoginTypeRecaptcha = "m.login.recaptcha" 12 | LoginTypeApplicationService = "m.login.application_service" 13 | LoginTypeToken = "m.login.token" 14 | ) 15 | -------------------------------------------------------------------------------- /internal/tracing_test.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestTracing(t *testing.T) { 11 | inCtx := context.Background() 12 | 13 | task, ctx := StartTask(inCtx, "testing") 14 | assert.NotNil(t, ctx) 15 | assert.NotNil(t, task) 16 | assert.NotEqual(t, inCtx, ctx) 17 | task.SetTag("key", "value") 18 | 19 | region, ctx2 := StartRegion(ctx, "testing") 20 | assert.NotNil(t, ctx) 21 | assert.NotNil(t, region) 22 | assert.NotEqual(t, ctx, ctx2) 23 | defer task.EndTask() 24 | defer region.EndRegion() 25 | } 26 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Pull Request Checklist 2 | 3 | 4 | 5 | * [ ] I have added Go unit tests or [Complement integration tests](https://github.com/matrix-org/complement) for this PR _or_ I have justified why this PR doesn't need tests 6 | * [ ] Pull request includes a [sign off below using a legally identifiable name](https://matrix-org.github.io/dendrite/development/contributing#sign-off) _or_ I have already signed off privately 7 | 8 | Signed-off-by: `Your Name ` 9 | -------------------------------------------------------------------------------- /helm/dendrite/README.md.gotmpl: -------------------------------------------------------------------------------- 1 | {{ template "chart.header" . }} 2 | {{ template "chart.deprecationWarning" . }} 3 | {{ template "chart.badgesSection" . }} 4 | {{ template "chart.description" . }} 5 | {{ template "chart.state" . }} 6 | {{ template "chart.about" . }} 7 | {{ template "chart.dbCreation" . }} 8 | {{ template "chart.appservices" . }} 9 | {{ template "chart.maintainersSection" . }} 10 | {{ template "chart.sourcesSection" . }} 11 | {{ template "chart.requirementsSection" . }} 12 | {{ template "chart.valuesSection" . }} 13 | {{ template "chart.monitoringSection" . }} 14 | {{ template "helm-docs.versionFooter" . }} -------------------------------------------------------------------------------- /setup/config/config_keyserver.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type KeyServer struct { 4 | Matrix *Global `yaml:"-"` 5 | 6 | Database DatabaseOptions `yaml:"database,omitempty"` 7 | } 8 | 9 | func (c *KeyServer) Defaults(opts DefaultOpts) { 10 | if opts.Generate { 11 | if !opts.SingleDatabase { 12 | c.Database.ConnectionString = "file:keyserver.db" 13 | } 14 | } 15 | } 16 | 17 | func (c *KeyServer) Verify(configErrs *ConfigErrors) { 18 | if c.Matrix.DatabaseOptions.ConnectionString == "" { 19 | checkNotEmpty(configErrs, "key_server.database.connection_string", string(c.Database.ConnectionString)) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /helm/dendrite/templates/configmap_grafana_dashboards.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.grafana.dashboards.enabled }} 2 | {{- range $path, $bytes := .Files.Glob "grafana_dashboards/*.json" }} 3 | --- 4 | apiVersion: v1 5 | kind: ConfigMap 6 | metadata: 7 | name: {{ include "dendrite.fullname" $ }}-grafana-dashboards-{{ base $path }} 8 | labels: 9 | {{- include "dendrite.labels" $ | nindent 4 }} 10 | {{- toYaml $.Values.grafana.dashboards.labels | nindent 4 }} 11 | annotations: 12 | {{- toYaml $.Values.grafana.dashboards.annotations | nindent 4 }} 13 | data: 14 | {{- ($.Files.Glob $path ).AsConfig | nindent 2 }} 15 | {{- end }} 16 | {{- end }} 17 | -------------------------------------------------------------------------------- /docs/hiawatha/dendrite-sample.conf: -------------------------------------------------------------------------------- 1 | # Depending on which port is used for federation (.well-known/matrix/server or SRV record), 2 | # ensure there's a binding for that port in the configuration. Replace "FEDPORT" with port 3 | # number, (e.g. "8448"), and "IPV4" with your server's ipv4 address (separate binding for 4 | # each ip address, e.g. if you use both ipv4 and ipv6 addresses). 5 | 6 | Binding { 7 | Port = FEDPORT 8 | Interface = IPV4 9 | TLScertFile = /path/to/fullchainandprivkey.pem 10 | } 11 | 12 | VirtualHost { 13 | ... 14 | ReverseProxy = /_matrix http://localhost:8008 600 15 | ... 16 | 17 | } 18 | -------------------------------------------------------------------------------- /helm/dendrite/templates/_overrides.yaml: -------------------------------------------------------------------------------- 1 | {{- define "override.config" }} 2 | {{- if .Values.postgresql.enabled }} 3 | {{- $_ := set .Values.dendrite_config.global.database "connection_string" (print "postgresql://" .Values.postgresql.auth.username ":" .Values.postgresql.auth.password "@" .Release.Name "-postgresql/dendrite?sslmode=disable") -}} 4 | {{ end }} 5 | global: 6 | private_key: /etc/dendrite/secrets/signing.key 7 | jetstream: 8 | in_memory: false 9 | {{ if (gt (len (.Files.Glob "appservices/*")) 0) }} 10 | app_service_api: 11 | config_files: 12 | {{- range $x, $y := .Files.Glob "appservices/*" }} 13 | - /etc/dendrite/appservices/{{ base $x }} 14 | {{ end }} 15 | {{ end }} 16 | {{ end }} 17 | -------------------------------------------------------------------------------- /internal/caching/cache_roomversions.go: -------------------------------------------------------------------------------- 1 | package caching 2 | 3 | import "github.com/matrix-org/gomatrixserverlib" 4 | 5 | // RoomVersionsCache contains the subset of functions needed for 6 | // a room version cache. 7 | type RoomVersionCache interface { 8 | GetRoomVersion(roomID string) (roomVersion gomatrixserverlib.RoomVersion, ok bool) 9 | StoreRoomVersion(roomID string, roomVersion gomatrixserverlib.RoomVersion) 10 | } 11 | 12 | func (c Caches) GetRoomVersion(roomID string) (gomatrixserverlib.RoomVersion, bool) { 13 | return c.RoomVersions.Get(roomID) 14 | } 15 | 16 | func (c Caches) StoreRoomVersion(roomID string, roomVersion gomatrixserverlib.RoomVersion) { 17 | c.RoomVersions.Set(roomID, roomVersion) 18 | } 19 | -------------------------------------------------------------------------------- /internal/caching/cache_space_rooms.go: -------------------------------------------------------------------------------- 1 | package caching 2 | 3 | import "github.com/matrix-org/gomatrixserverlib/fclient" 4 | 5 | // RoomHierarchy cache caches responses to federated room hierarchy requests (A.K.A. 'space summaries') 6 | type RoomHierarchyCache interface { 7 | GetRoomHierarchy(roomID string) (r fclient.RoomHierarchyResponse, ok bool) 8 | StoreRoomHierarchy(roomID string, r fclient.RoomHierarchyResponse) 9 | } 10 | 11 | func (c Caches) GetRoomHierarchy(roomID string) (r fclient.RoomHierarchyResponse, ok bool) { 12 | return c.RoomHierarchies.Get(roomID) 13 | } 14 | 15 | func (c Caches) StoreRoomHierarchy(roomID string, r fclient.RoomHierarchyResponse) { 16 | c.RoomHierarchies.Set(roomID, r) 17 | } 18 | -------------------------------------------------------------------------------- /helm/dendrite/templates/prometheus-rules.yaml: -------------------------------------------------------------------------------- 1 | {{- if and ( .Values.prometheus.rules.enabled ) ( .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" ) }} 2 | --- 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: PrometheusRule 5 | metadata: 6 | name: {{ include "dendrite.fullname" . }} 7 | labels: 8 | {{- include "dendrite.labels" . | nindent 4 }} 9 | {{- with .Values.prometheus.rules.labels }} 10 | {{- . | toYaml | nindent 4 }} 11 | {{- end }} 12 | spec: 13 | groups: 14 | {{- if .Values.prometheus.rules.additionalRules }} 15 | - name: {{ template "dendrite.name" . }}-Additional 16 | rules: {{- toYaml .Values.prometheus.rules.additionalRules | nindent 4 }} 17 | {{- end }} 18 | {{- end }} 19 | -------------------------------------------------------------------------------- /userapi/storage/postgres/deltas/20200929203058_is_active.go: -------------------------------------------------------------------------------- 1 | package deltas 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "fmt" 7 | ) 8 | 9 | func UpIsActive(ctx context.Context, tx *sql.Tx) error { 10 | _, err := tx.ExecContext(ctx, "ALTER TABLE userapi_accounts ADD COLUMN IF NOT EXISTS is_deactivated BOOLEAN DEFAULT FALSE;") 11 | if err != nil { 12 | return fmt.Errorf("failed to execute upgrade: %w", err) 13 | } 14 | return nil 15 | } 16 | 17 | func DownIsActive(ctx context.Context, tx *sql.Tx) error { 18 | _, err := tx.ExecContext(ctx, "ALTER TABLE userapi_accounts DROP COLUMN is_deactivated;") 19 | if err != nil { 20 | return fmt.Errorf("failed to execute downgrade: %w", err) 21 | } 22 | return nil 23 | } 24 | -------------------------------------------------------------------------------- /internal/pushrules/default_content.go: -------------------------------------------------------------------------------- 1 | package pushrules 2 | 3 | func defaultContentRules(localpart string) []*Rule { 4 | return []*Rule{ 5 | mRuleContainsUserNameDefinition(localpart), 6 | } 7 | } 8 | 9 | const ( 10 | MRuleContainsUserName = ".m.rule.contains_user_name" 11 | ) 12 | 13 | func mRuleContainsUserNameDefinition(localpart string) *Rule { 14 | return &Rule{ 15 | RuleID: MRuleContainsUserName, 16 | Default: true, 17 | Enabled: true, 18 | Pattern: &localpart, 19 | Actions: []*Action{ 20 | {Kind: NotifyAction}, 21 | { 22 | Kind: SetTweakAction, 23 | Tweak: SoundTweak, 24 | Value: "default", 25 | }, 26 | { 27 | Kind: SetTweakAction, 28 | Tweak: HighlightTweak, 29 | }, 30 | }, 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /docs/INSTALL.md: -------------------------------------------------------------------------------- 1 | 2 | {% include deprecation.html %} 3 | 4 | # Installation 5 | 6 | Please note that new installation instructions can be found 7 | on the [new documentation site](https://matrix-org.github.io/dendrite/), 8 | or alternatively, in the [installation](installation/) folder: 9 | 10 | 1. [Planning your deployment](installation/1_planning.md) 11 | 2. [Setting up the domain](installation/2_domainname.md) 12 | 3. [Installing Dendrite](installation/manual/1_build.md) 13 | 4. [Preparing database storage](installation/manual/2_database.md) 14 | 5. [Populate the configuration](installation/manual/3_configuration.md) 15 | 6. [Generating signing keys](installation/manual/4_signingkey.md) 16 | 7. [Starting Dendrite](installation/manual/5_starting_dendrite.md) 17 | -------------------------------------------------------------------------------- /internal/pushrules/default.go: -------------------------------------------------------------------------------- 1 | package pushrules 2 | 3 | import "github.com/matrix-org/gomatrixserverlib/spec" 4 | 5 | // DefaultAccountRuleSets is the complete set of default push rules 6 | // for an account. 7 | func DefaultAccountRuleSets(localpart string, serverName spec.ServerName) *AccountRuleSets { 8 | return &AccountRuleSets{ 9 | Global: *DefaultGlobalRuleSet(localpart, serverName), 10 | } 11 | } 12 | 13 | // DefaultGlobalRuleSet returns the default ruleset for a given (fully 14 | // qualified) MXID. 15 | func DefaultGlobalRuleSet(localpart string, serverName spec.ServerName) *RuleSet { 16 | return &RuleSet{ 17 | Override: defaultOverrideRules("@" + localpart + ":" + string(serverName)), 18 | Content: defaultContentRules(localpart), 19 | Underride: defaultUnderrideRules, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /internal/sqlutil/writer_dummy.go: -------------------------------------------------------------------------------- 1 | package sqlutil 2 | 3 | import ( 4 | "database/sql" 5 | ) 6 | 7 | // DummyWriter implements sqlutil.Writer. 8 | // The DummyWriter is designed to allow reuse of the sqlutil.Writer 9 | // interface but, unlike ExclusiveWriter, it will not guarantee 10 | // writer exclusivity. This is fine in PostgreSQL where overlapping 11 | // transactions and writes are acceptable. 12 | type DummyWriter struct { 13 | } 14 | 15 | // NewDummyWriter returns a new dummy writer. 16 | func NewDummyWriter() Writer { 17 | return &DummyWriter{} 18 | } 19 | 20 | func (w *DummyWriter) Do(db *sql.DB, txn *sql.Tx, f func(txn *sql.Tx) error) error { 21 | if db != nil && txn == nil { 22 | return WithTransaction(db, func(txn *sql.Tx) error { 23 | return f(txn) 24 | }) 25 | } else { 26 | return f(txn) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /userapi/util/stats_wasm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package util 16 | 17 | // stub, since WASM doesn't support syscall.Getrusage 18 | func getMemoryStats(p *phoneHomeStats) error { 19 | return nil 20 | } 21 | -------------------------------------------------------------------------------- /userapi/storage/sqlite3/constraint_wasm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build wasm 16 | // +build wasm 17 | 18 | package sqlite3 19 | 20 | func isConstraintError(err error) bool { 21 | return false 22 | } 23 | -------------------------------------------------------------------------------- /clientapi/README.md: -------------------------------------------------------------------------------- 1 | This component roughly corresponds to "Client Room Send" and "Client Sync" on [the WIRING diagram](https://github.com/matrix-org/dendrite/blob/master/WIRING.md). 2 | This component produces multiple binaries. 3 | 4 | ## Internals 5 | 6 | - HTTP routing is done using `gorilla/mux` and the routing paths are in the `routing` package. 7 | 8 | ### Writers 9 | - Each HTTP "write operation" (`/createRoom`, `/rooms/$room_id/send/$type`, etc) is contained entirely to a single file in the `writers` package. 10 | - This file contains the request and response `struct` definitions, as well as a `Validate() bool` function to validate incoming requests. 11 | - The entry point for each write operation is a stand-alone function as this makes testing easier. All dependencies should be injected into this function, including server keys/name, etc. 12 | -------------------------------------------------------------------------------- /userapi/internal/device_list_update_default.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !vw 16 | 17 | package internal 18 | 19 | import "time" 20 | 21 | const defaultWaitTime = time.Minute 22 | const hourWaitTime = time.Hour 23 | -------------------------------------------------------------------------------- /docs/installation/manual/5_starting_dendrite.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Starting Dendrite 3 | parent: Manual 4 | grand_parent: Installation 5 | nav_order: 5 6 | permalink: /installation/manual/start 7 | --- 8 | 9 | {% include deprecation.html %} 10 | 11 | # Starting Dendrite 12 | 13 | Once you have completed all preparation and installation steps, 14 | you can start your Dendrite deployment by executing the `dendrite` binary: 15 | 16 | ```bash 17 | ./dendrite -config /path/to/dendrite.yaml 18 | ``` 19 | 20 | By default, Dendrite will listen HTTP on port 8008. If you want to change the addresses 21 | or ports that Dendrite listens on, you can use the `-http-bind-address` and 22 | `-https-bind-address` command line arguments: 23 | 24 | ```bash 25 | ./dendrite -config /path/to/dendrite.yaml \ 26 | -http-bind-address 1.2.3.4:12345 \ 27 | -https-bind-address 1.2.3.4:54321 28 | ``` 29 | -------------------------------------------------------------------------------- /internal/mutex.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import "sync" 4 | 5 | type MutexByRoom struct { 6 | mu *sync.Mutex // protects the map 7 | roomToMu map[string]*sync.Mutex 8 | } 9 | 10 | func NewMutexByRoom() *MutexByRoom { 11 | return &MutexByRoom{ 12 | mu: &sync.Mutex{}, 13 | roomToMu: make(map[string]*sync.Mutex), 14 | } 15 | } 16 | 17 | func (m *MutexByRoom) Lock(roomID string) { 18 | m.mu.Lock() 19 | roomMu := m.roomToMu[roomID] 20 | if roomMu == nil { 21 | roomMu = &sync.Mutex{} 22 | } 23 | m.roomToMu[roomID] = roomMu 24 | m.mu.Unlock() 25 | // don't lock inside m.mu else we can deadlock 26 | roomMu.Lock() 27 | } 28 | 29 | func (m *MutexByRoom) Unlock(roomID string) { 30 | m.mu.Lock() 31 | roomMu := m.roomToMu[roomID] 32 | if roomMu == nil { 33 | panic("MutexByRoom: Unlock before Lock") 34 | } 35 | m.mu.Unlock() 36 | 37 | roomMu.Unlock() 38 | } 39 | -------------------------------------------------------------------------------- /cmd/dendrite-demo-pinecone/embed/embed_other.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !elementweb 16 | // +build !elementweb 17 | 18 | package embed 19 | 20 | import "github.com/gorilla/mux" 21 | 22 | func Embed(_ *mux.Router, _ int, _ string) { 23 | 24 | } 25 | -------------------------------------------------------------------------------- /clientapi/auth/authtypes/membership.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Vector Creations Ltd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package authtypes 16 | 17 | // Membership represents the relationship between a user and a room they're a 18 | // member of 19 | type Membership struct { 20 | Localpart string 21 | RoomID string 22 | EventID string 23 | } 24 | -------------------------------------------------------------------------------- /docs/installation/manual/1_build.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Building/Installing Dendrite 3 | parent: Manual 4 | grand_parent: Installation 5 | has_toc: true 6 | nav_order: 1 7 | permalink: /installation/manual/build 8 | --- 9 | 10 | {% include deprecation.html %} 11 | 12 | # Build all Dendrite commands 13 | 14 | Dendrite has numerous utility commands in addition to the actual server binaries. 15 | Build them all from the root of the source repo with: 16 | 17 | ```sh 18 | go build -o bin/ ./cmd/... 19 | ``` 20 | 21 | The resulting binaries will be placed in the `bin` subfolder. 22 | 23 | # Installing Dendrite 24 | 25 | You can install the Dendrite binary into `$GOPATH/bin` by using `go install`: 26 | 27 | ```sh 28 | go install ./cmd/dendrite 29 | ``` 30 | 31 | Alternatively, you can specify a custom path for the binary to be written to using `go build`: 32 | 33 | ```sh 34 | go build -o /usr/local/bin/ ./cmd/dendrite 35 | ``` 36 | -------------------------------------------------------------------------------- /cmd/dendrite-demo-pinecone/defaults/defaults.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package defaults 16 | 17 | import "github.com/matrix-org/gomatrixserverlib/spec" 18 | 19 | var DefaultServerNames = map[spec.ServerName]struct{}{ 20 | "3bf0258d23c60952639cc4c69c71d1508a7d43a0475d9000ff900a1848411ec7": {}, 21 | } 22 | -------------------------------------------------------------------------------- /syncapi/streams/template_stream.go: -------------------------------------------------------------------------------- 1 | package streams 2 | 3 | import ( 4 | "context" 5 | "sync" 6 | 7 | "github.com/matrix-org/dendrite/syncapi/storage" 8 | "github.com/matrix-org/dendrite/syncapi/types" 9 | ) 10 | 11 | type DefaultStreamProvider struct { 12 | DB storage.Database 13 | latest types.StreamPosition 14 | latestMutex sync.RWMutex 15 | } 16 | 17 | func (p *DefaultStreamProvider) Setup( 18 | ctx context.Context, snapshot storage.DatabaseTransaction, 19 | ) { 20 | } 21 | 22 | func (p *DefaultStreamProvider) Advance( 23 | latest types.StreamPosition, 24 | ) { 25 | p.latestMutex.Lock() 26 | defer p.latestMutex.Unlock() 27 | 28 | if latest > p.latest { 29 | p.latest = latest 30 | } 31 | } 32 | 33 | func (p *DefaultStreamProvider) LatestPosition( 34 | ctx context.Context, 35 | ) types.StreamPosition { 36 | p.latestMutex.RLock() 37 | defer p.latestMutex.RUnlock() 38 | 39 | return p.latest 40 | } 41 | -------------------------------------------------------------------------------- /internal/caching/cache_roomevents.go: -------------------------------------------------------------------------------- 1 | package caching 2 | 3 | import ( 4 | "github.com/matrix-org/dendrite/roomserver/types" 5 | ) 6 | 7 | // RoomServerEventsCache contains the subset of functions needed for 8 | // a roomserver event cache. 9 | type RoomServerEventsCache interface { 10 | GetRoomServerEvent(eventNID types.EventNID) (*types.HeaderedEvent, bool) 11 | StoreRoomServerEvent(eventNID types.EventNID, event *types.HeaderedEvent) 12 | InvalidateRoomServerEvent(eventNID types.EventNID) 13 | } 14 | 15 | func (c Caches) GetRoomServerEvent(eventNID types.EventNID) (*types.HeaderedEvent, bool) { 16 | return c.RoomServerEvents.Get(int64(eventNID)) 17 | } 18 | 19 | func (c Caches) StoreRoomServerEvent(eventNID types.EventNID, event *types.HeaderedEvent) { 20 | c.RoomServerEvents.Set(int64(eventNID), event) 21 | } 22 | 23 | func (c Caches) InvalidateRoomServerEvent(eventNID types.EventNID) { 24 | c.RoomServerEvents.Unset(int64(eventNID)) 25 | } 26 | -------------------------------------------------------------------------------- /clientapi/auth/authtypes/flow.go: -------------------------------------------------------------------------------- 1 | // Copyright Andrew Morgan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package authtypes 16 | 17 | // Flow represents one possible way that the client can authenticate a request. 18 | // https://matrix.org/docs/spec/client_server/r0.3.0.html#user-interactive-authentication-api 19 | type Flow struct { 20 | Stages []LoginType `json:"stages"` 21 | } 22 | -------------------------------------------------------------------------------- /clientapi/auth/authtypes/threepid.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Vector Creations Ltd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package authtypes 16 | 17 | // ThreePID represents a third-party identifier 18 | type ThreePID struct { 19 | Address string `json:"address"` 20 | Medium string `json:"medium"` 21 | AddedAt int64 `json:"added_at"` 22 | ValidatedAt int64 `json:"validated_at"` 23 | } 24 | -------------------------------------------------------------------------------- /setup/base/federation.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net" 7 | "net/http" 8 | ) 9 | 10 | // noOpHTTPTransport is used to disable federation. 11 | var noOpHTTPTransport = &http.Transport{ 12 | Dial: func(_, _ string) (net.Conn, error) { 13 | return nil, fmt.Errorf("federation prohibited by configuration") 14 | }, 15 | DialContext: func(_ context.Context, _, _ string) (net.Conn, error) { 16 | return nil, fmt.Errorf("federation prohibited by configuration") 17 | }, 18 | DialTLS: func(_, _ string) (net.Conn, error) { 19 | return nil, fmt.Errorf("federation prohibited by configuration") 20 | }, 21 | } 22 | 23 | func init() { 24 | noOpHTTPTransport.RegisterProtocol("matrix", &noOpHTTPRoundTripper{}) 25 | } 26 | 27 | type noOpHTTPRoundTripper struct { 28 | } 29 | 30 | func (y *noOpHTTPRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { 31 | return nil, fmt.Errorf("federation prohibited by configuration") 32 | } 33 | -------------------------------------------------------------------------------- /helm/dendrite/templates/servicemonitor.yaml: -------------------------------------------------------------------------------- 1 | {{- if and 2 | (and .Values.prometheus.servicemonitor.enabled .Values.dendrite_config.global.metrics.enabled ) 3 | ( .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" ) 4 | }} 5 | --- 6 | apiVersion: monitoring.coreos.com/v1 7 | kind: ServiceMonitor 8 | metadata: 9 | name: {{ include "dendrite.fullname" . }} 10 | labels: 11 | {{- include "dendrite.labels" . | nindent 4 }} 12 | {{- with .Values.prometheus.servicemonitor.labels }} 13 | {{- . | toYaml | nindent 4 }} 14 | {{- end }} 15 | spec: 16 | endpoints: 17 | - port: http 18 | basicAuth: 19 | username: 20 | name: {{ include "dendrite.fullname" . }}-metrics-basic-auth 21 | key: "user" 22 | password: 23 | name: {{ include "dendrite.fullname" . }}-metrics-basic-auth 24 | key: "password" 25 | selector: 26 | matchLabels: 27 | {{- include "dendrite.selectorLabels" . | nindent 6 }} 28 | {{- end }} 29 | -------------------------------------------------------------------------------- /userapi/util/stats_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !wasm 16 | // +build !wasm 17 | 18 | package util 19 | 20 | import ( 21 | "runtime" 22 | ) 23 | 24 | func getMemoryStats(p *phoneHomeStats) error { 25 | var memStats runtime.MemStats 26 | runtime.ReadMemStats(&memStats) 27 | p.stats["memory_rss"] = memStats.Alloc 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /userapi/storage/postgres/deltas/2022110411000001_server_names.go: -------------------------------------------------------------------------------- 1 | package deltas 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "fmt" 7 | 8 | "github.com/lib/pq" 9 | "github.com/matrix-org/gomatrixserverlib/spec" 10 | ) 11 | 12 | // I know what you're thinking: you're wondering "why doesn't this use $1 13 | // and pass variadic parameters to ExecContext?" — the answer is because 14 | // PostgreSQL doesn't expect the table name to be specified as a substituted 15 | // argument in that way so it results in a syntax error in the query. 16 | 17 | func UpServerNamesPopulate(ctx context.Context, tx *sql.Tx, serverName spec.ServerName) error { 18 | for _, table := range serverNamesTables { 19 | q := fmt.Sprintf( 20 | "UPDATE %s SET server_name = %s WHERE server_name = '';", 21 | pq.QuoteIdentifier(table), pq.QuoteLiteral(string(serverName)), 22 | ) 23 | if _, err := tx.ExecContext(ctx, q); err != nil { 24 | return fmt.Errorf("write server names to %q error: %w", table, err) 25 | } 26 | } 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /userapi/storage/sqlite3/deltas/2022110411000001_server_names.go: -------------------------------------------------------------------------------- 1 | package deltas 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "fmt" 7 | 8 | "github.com/lib/pq" 9 | "github.com/matrix-org/gomatrixserverlib/spec" 10 | ) 11 | 12 | // I know what you're thinking: you're wondering "why doesn't this use $1 13 | // and pass variadic parameters to ExecContext?" — the answer is because 14 | // PostgreSQL doesn't expect the table name to be specified as a substituted 15 | // argument in that way so it results in a syntax error in the query. 16 | 17 | func UpServerNamesPopulate(ctx context.Context, tx *sql.Tx, serverName spec.ServerName) error { 18 | for _, table := range serverNamesTables { 19 | q := fmt.Sprintf( 20 | "UPDATE %s SET server_name = %s WHERE server_name = '';", 21 | pq.QuoteIdentifier(table), pq.QuoteLiteral(string(serverName)), 22 | ) 23 | if _, err := tx.ExecContext(ctx, q); err != nil { 24 | return fmt.Errorf("write server names to %q error: %w", table, err) 25 | } 26 | } 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /userapi/storage/postgres/deltas/20201001204705_last_seen_ts_ip.go: -------------------------------------------------------------------------------- 1 | package deltas 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "fmt" 7 | ) 8 | 9 | func UpLastSeenTSIP(ctx context.Context, tx *sql.Tx) error { 10 | _, err := tx.ExecContext(ctx, ` 11 | ALTER TABLE userapi_devices ADD COLUMN IF NOT EXISTS last_seen_ts BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM CURRENT_TIMESTAMP)*1000; 12 | ALTER TABLE userapi_devices ADD COLUMN IF NOT EXISTS ip TEXT; 13 | ALTER TABLE userapi_devices ADD COLUMN IF NOT EXISTS user_agent TEXT;`) 14 | if err != nil { 15 | return fmt.Errorf("failed to execute upgrade: %w", err) 16 | } 17 | return nil 18 | } 19 | 20 | func DownLastSeenTSIP(ctx context.Context, tx *sql.Tx) error { 21 | _, err := tx.ExecContext(ctx, ` 22 | ALTER TABLE userapi_devices DROP COLUMN last_seen_ts; 23 | ALTER TABLE userapi_devices DROP COLUMN ip; 24 | ALTER TABLE userapi_devices DROP COLUMN user_agent;`) 25 | if err != nil { 26 | return fmt.Errorf("failed to execute downgrade: %w", err) 27 | } 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /internal/pushrules/action_test.go: -------------------------------------------------------------------------------- 1 | package pushrules 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/google/go-cmp/cmp" 9 | ) 10 | 11 | func TestActionJSON(t *testing.T) { 12 | tsts := []struct { 13 | Want Action 14 | }{ 15 | {Action{Kind: NotifyAction}}, 16 | {Action{Kind: SetTweakAction}}, 17 | 18 | {Action{Kind: SetTweakAction, Tweak: SoundTweak, Value: "default"}}, 19 | {Action{Kind: SetTweakAction, Tweak: HighlightTweak}}, 20 | {Action{Kind: SetTweakAction, Tweak: HighlightTweak, Value: "false"}}, 21 | } 22 | for _, tst := range tsts { 23 | t.Run(fmt.Sprintf("%+v", tst.Want), func(t *testing.T) { 24 | bs, err := json.Marshal(&tst.Want) 25 | if err != nil { 26 | t.Fatalf("Marshal failed: %v", err) 27 | } 28 | var got Action 29 | if err := json.Unmarshal(bs, &got); err != nil { 30 | t.Fatalf("Unmarshal failed: %v", err) 31 | } 32 | if diff := cmp.Diff(tst.Want, got); diff != "" { 33 | t.Errorf("+got -want:\n%s", diff) 34 | } 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sytest-blacklist: -------------------------------------------------------------------------------- 1 | # Blacklisted due to https://github.com/matrix-org/matrix-spec/issues/942 2 | The only membership state included in a gapped incremental sync is for senders in the timeline 3 | 4 | # Flakey 5 | AS-ghosted users can use rooms themselves 6 | AS-ghosted users can use rooms via AS 7 | Events in rooms with AS-hosted room aliases are sent to AS server 8 | Inviting an AS-hosted user asks the AS server 9 | Accesing an AS-hosted room alias asks the AS server 10 | If user leaves room, remote user changes device and rejoins we see update in /sync and /keys/changes 11 | New federated private chats get full presence information (SYN-115) 12 | 13 | # This will fail in HTTP API mode, so blacklisted for now 14 | If a device list update goes missing, the server resyncs on the next one 15 | 16 | # Might be a bug in the test because leaves do appear :-( 17 | Leaves are present in non-gapped incremental syncs 18 | 19 | # We don't have any state to calculate m.room.guest_access when accepting invites 20 | Guest users can accept invites to private rooms over federation -------------------------------------------------------------------------------- /test/testrig/jetstream.go: -------------------------------------------------------------------------------- 1 | package testrig 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | "github.com/matrix-org/dendrite/setup/config" 8 | "github.com/nats-io/nats.go" 9 | 10 | "github.com/matrix-org/dendrite/roomserver/api" 11 | "github.com/matrix-org/dendrite/setup/jetstream" 12 | ) 13 | 14 | func MustPublishMsgs(t *testing.T, jsctx nats.JetStreamContext, msgs ...*nats.Msg) { 15 | t.Helper() 16 | for _, msg := range msgs { 17 | if _, err := jsctx.PublishMsg(msg); err != nil { 18 | t.Fatalf("MustPublishMsgs: failed to publish message: %s", err) 19 | } 20 | } 21 | } 22 | 23 | func NewOutputEventMsg(t *testing.T, cfg *config.Dendrite, roomID string, update api.OutputEvent) *nats.Msg { 24 | t.Helper() 25 | msg := nats.NewMsg(cfg.Global.JetStream.Prefixed(jetstream.OutputRoomEvent)) 26 | msg.Header.Set(jetstream.RoomEventType, string(update.Type)) 27 | msg.Header.Set(jetstream.RoomID, roomID) 28 | var err error 29 | msg.Data, err = json.Marshal(update) 30 | if err != nil { 31 | t.Fatalf("failed to marshal update: %s", err) 32 | } 33 | return msg 34 | } 35 | -------------------------------------------------------------------------------- /setup/jetstream/log.go: -------------------------------------------------------------------------------- 1 | package jetstream 2 | 3 | import ( 4 | "github.com/nats-io/nats-server/v2/server" 5 | "github.com/sirupsen/logrus" 6 | ) 7 | 8 | var _ server.Logger = &LogAdapter{} 9 | 10 | type LogAdapter struct { 11 | entry *logrus.Entry 12 | } 13 | 14 | func NewLogAdapter() *LogAdapter { 15 | return &LogAdapter{ 16 | entry: logrus.StandardLogger().WithField("component", "jetstream"), 17 | } 18 | } 19 | 20 | func (l *LogAdapter) Noticef(format string, v ...interface{}) { 21 | l.entry.Infof(format, v...) 22 | } 23 | 24 | func (l *LogAdapter) Warnf(format string, v ...interface{}) { 25 | l.entry.Warnf(format, v...) 26 | } 27 | 28 | func (l *LogAdapter) Fatalf(format string, v ...interface{}) { 29 | l.entry.Fatalf(format, v...) 30 | } 31 | 32 | func (l *LogAdapter) Errorf(format string, v ...interface{}) { 33 | l.entry.Errorf(format, v...) 34 | } 35 | 36 | func (l *LogAdapter) Debugf(format string, v ...interface{}) { 37 | l.entry.Debugf(format, v...) 38 | } 39 | 40 | func (l *LogAdapter) Tracef(format string, v ...interface{}) { 41 | l.entry.Tracef(format, v...) 42 | } 43 | -------------------------------------------------------------------------------- /test/slice.go: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0 (the "License"); 2 | // you may not use this file except in compliance with the License. 3 | // You may obtain a copy of the License at 4 | // 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | package test 14 | 15 | import "sort" 16 | 17 | // UnsortedStringSliceEqual returns true if the slices have same length & elements. 18 | // Does not modify the given slice. 19 | func UnsortedStringSliceEqual(first, second []string) bool { 20 | if len(first) != len(second) { 21 | return false 22 | } 23 | 24 | a, b := first[:], second[:] 25 | sort.Strings(a) 26 | sort.Strings(b) 27 | for i := range a { 28 | if a[i] != b[i] { 29 | return false 30 | } 31 | } 32 | 33 | return true 34 | } 35 | -------------------------------------------------------------------------------- /userapi/internal/device_list_update_sytest.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build vw 16 | 17 | package internal 18 | 19 | import "time" 20 | 21 | // Sytest is expecting to receive a `/devices` request. The way it is implemented in Dendrite 22 | // results in a one-hour wait time from a previous device so the test times out. This is fine for 23 | // production, but makes an otherwise passing test fail. 24 | const defaultWaitTime = time.Second 25 | const hourWaitTime = time.Second 26 | -------------------------------------------------------------------------------- /cmd/dendrite-demo-yggdrasil/README.md: -------------------------------------------------------------------------------- 1 | # Yggdrasil Demo 2 | 3 | This is the Dendrite Yggdrasil demo! It's easy to get started - all you need is Go 1.21 or later. 4 | 5 | To run the homeserver, start at the root of the Dendrite repository and run: 6 | 7 | ``` 8 | go run ./cmd/dendrite-demo-yggdrasil 9 | ``` 10 | 11 | The following command line arguments are accepted: 12 | 13 | * `-peer tcp://a.b.c.d:e` to specify a static Yggdrasil peer to connect to - you will need to supply this if you do not have another Yggdrasil node on your network 14 | * `-port 12345` to specify a port to listen on for client connections 15 | 16 | If you need to find an internet peer, take a look at [this list](https://publicpeers.neilalexander.dev/). 17 | 18 | Then point your favourite Matrix client to the homeserver URL`http://localhost:8008` (or whichever `-port` you specified), create an account and log in. 19 | 20 | If your peering connection is operational then you should see a `Connected TCP:` line in the log output. If not then try a different peer. 21 | 22 | Once logged in, you should be able to open the room directory or join a room by its ID. 23 | -------------------------------------------------------------------------------- /internal/sqlutil/unique_constraint_wasm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build wasm 16 | // +build wasm 17 | 18 | package sqlutil 19 | 20 | import ( 21 | "modernc.org/sqlite" 22 | lib "modernc.org/sqlite/lib" 23 | ) 24 | 25 | // IsUniqueConstraintViolationErr returns true if the error is an unique_violation error 26 | func IsUniqueConstraintViolationErr(err error) bool { 27 | switch e := err.(type) { 28 | case *sqlite.Error: 29 | return e.Code() == lib.SQLITE_CONSTRAINT 30 | } 31 | return false 32 | } 33 | -------------------------------------------------------------------------------- /userapi/storage/postgres/deltas/2022021013023800_add_account_type.go: -------------------------------------------------------------------------------- 1 | package deltas 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "fmt" 7 | ) 8 | 9 | func UpAddAccountType(ctx context.Context, tx *sql.Tx) error { 10 | // initially set every account to useraccount, change appservice and guest accounts afterwards 11 | // (user = 1, guest = 2, admin = 3, appservice = 4) 12 | _, err := tx.ExecContext(ctx, `ALTER TABLE userapi_accounts ADD COLUMN IF NOT EXISTS account_type SMALLINT NOT NULL DEFAULT 1; 13 | UPDATE userapi_accounts SET account_type = 4 WHERE appservice_id <> ''; 14 | UPDATE userapi_accounts SET account_type = 2 WHERE localpart ~ '^[0-9]+$'; 15 | ALTER TABLE userapi_accounts ALTER COLUMN account_type DROP DEFAULT;`, 16 | ) 17 | if err != nil { 18 | return fmt.Errorf("failed to execute upgrade: %w", err) 19 | } 20 | return nil 21 | } 22 | 23 | func DownAddAccountType(ctx context.Context, tx *sql.Tx) error { 24 | _, err := tx.ExecContext(ctx, "ALTER TABLE userapi_accounts DROP COLUMN account_type;") 25 | if err != nil { 26 | return fmt.Errorf("failed to execute downgrade: %w", err) 27 | } 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /internal/httputil/paths.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package httputil 16 | 17 | const ( 18 | PublicClientPathPrefix = "/_matrix/client/" 19 | PublicFederationPathPrefix = "/_matrix/federation/" 20 | PublicKeyPathPrefix = "/_matrix/key/" 21 | PublicMediaPathPrefix = "/_matrix/media/" 22 | PublicStaticPath = "/_matrix/static/" 23 | PublicWellKnownPrefix = "/.well-known/matrix/" 24 | DendriteAdminPathPrefix = "/_dendrite/" 25 | SynapseAdminPathPrefix = "/_synapse/" 26 | ) 27 | -------------------------------------------------------------------------------- /syncapi/producers/appservices.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package producers 16 | 17 | import ( 18 | "github.com/nats-io/nats.go" 19 | ) 20 | 21 | // AppserviceEventProducer produces events for the appservice API to consume 22 | type AppserviceEventProducer struct { 23 | Topic string 24 | JetStream nats.JetStreamContext 25 | } 26 | 27 | func (a *AppserviceEventProducer) ProduceRoomEvents( 28 | msg *nats.Msg, 29 | ) error { 30 | msg.Subject = a.Topic 31 | _, err := a.JetStream.PublishMsg(msg) 32 | return err 33 | } 34 | -------------------------------------------------------------------------------- /syncapi/storage/postgres/deltas/20230201152200_rename_index.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package deltas 16 | 17 | import ( 18 | "context" 19 | "database/sql" 20 | "fmt" 21 | ) 22 | 23 | func UpRenameOutputRoomEventsIndex(ctx context.Context, tx *sql.Tx) error { 24 | _, err := tx.ExecContext(ctx, `ALTER TABLE syncapi_output_room_events RENAME CONSTRAINT syncapi_event_id_idx TO syncapi_output_room_event_id_idx;`) 25 | if err != nil { 26 | return fmt.Errorf("failed to execute upgrade: %w", err) 27 | } 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /syncapi/types/provider.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/sirupsen/logrus" 8 | 9 | "github.com/matrix-org/dendrite/syncapi/synctypes" 10 | userapi "github.com/matrix-org/dendrite/userapi/api" 11 | "github.com/matrix-org/gomatrixserverlib/spec" 12 | ) 13 | 14 | type SyncRequest struct { 15 | Context context.Context 16 | Log *logrus.Entry 17 | Device *userapi.Device 18 | Response *Response 19 | Filter synctypes.Filter 20 | Since StreamingToken 21 | Timeout time.Duration 22 | WantFullState bool 23 | 24 | // Updated by the PDU stream. 25 | Rooms map[string]string 26 | // Updated by the PDU stream. 27 | MembershipChanges map[string]struct{} 28 | // Updated by the PDU stream. 29 | IgnoredUsers IgnoredUsers 30 | } 31 | 32 | func (r *SyncRequest) IsRoomPresent(roomID string) bool { 33 | membership, ok := r.Rooms[roomID] 34 | if !ok { 35 | return false 36 | } 37 | switch membership { 38 | case spec.Join: 39 | return true 40 | case spec.Invite: 41 | return true 42 | case spec.Peek: 43 | return true 44 | default: 45 | return false 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /docs/nginx/dendrite-sample.conf: -------------------------------------------------------------------------------- 1 | # change IP to location of monolith server 2 | upstream monolith { 3 | server 127.0.0.1:8008; 4 | } 5 | server { 6 | listen 443 ssl; # IPv4 7 | listen [::]:443 ssl; # IPv6 8 | server_name my.hostname.com; 9 | 10 | ssl_certificate /path/to/fullchain.pem; 11 | ssl_certificate_key /path/to/privkey.pem; 12 | ssl_dhparam /path/to/ssl-dhparams.pem; 13 | 14 | proxy_set_header Host $host; 15 | proxy_set_header X-Real-IP $remote_addr; 16 | proxy_read_timeout 600; 17 | 18 | location /.well-known/matrix/server { 19 | return 200 '{ "m.server": "my.hostname.com:443" }'; 20 | } 21 | 22 | location /.well-known/matrix/client { 23 | # If your server_name here doesn't match your matrix homeserver URL 24 | # (e.g. hostname.com as server_name and matrix.hostname.com as homeserver URL) 25 | # uncomment the following line. 26 | # add_header Access-Control-Allow-Origin '*'; 27 | return 200 '{ "m.homeserver": { "base_url": "https://my.hostname.com" } }'; 28 | } 29 | 30 | location /_matrix { 31 | proxy_pass http://monolith; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /setup/config/config_mscs.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type MSCs struct { 4 | Matrix *Global `yaml:"-"` 5 | 6 | // The MSCs to enable. Supported MSCs include: 7 | // 'msc2444': Peeking over federation - https://github.com/matrix-org/matrix-doc/pull/2444 8 | // 'msc2753': Peeking via /sync - https://github.com/matrix-org/matrix-doc/pull/2753 9 | // 'msc2836': Threading - https://github.com/matrix-org/matrix-doc/pull/2836 10 | MSCs []string `yaml:"mscs"` 11 | 12 | Database DatabaseOptions `yaml:"database,omitempty"` 13 | } 14 | 15 | func (c *MSCs) Defaults(opts DefaultOpts) { 16 | if opts.Generate { 17 | if !opts.SingleDatabase { 18 | c.Database.ConnectionString = "file:mscs.db" 19 | } 20 | } 21 | } 22 | 23 | // Enabled returns true if the given msc is enabled. Should in the form 'msc12345'. 24 | func (c *MSCs) Enabled(msc string) bool { 25 | for _, m := range c.MSCs { 26 | if m == msc { 27 | return true 28 | } 29 | } 30 | return false 31 | } 32 | 33 | func (c *MSCs) Verify(configErrs *ConfigErrors) { 34 | if c.Matrix.DatabaseOptions.ConnectionString == "" { 35 | checkNotEmpty(configErrs, "mscs.database.connection_string", string(c.Database.ConnectionString)) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /federationapi/storage/postgres/deltas/2021020411080000_rooms.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package deltas 16 | 17 | import ( 18 | "context" 19 | "database/sql" 20 | "fmt" 21 | ) 22 | 23 | func UpRemoveRoomsTable(ctx context.Context, tx *sql.Tx) error { 24 | _, err := tx.ExecContext(ctx, ` 25 | DROP TABLE IF EXISTS federationsender_rooms; 26 | `) 27 | if err != nil { 28 | return fmt.Errorf("failed to execute upgrade: %w", err) 29 | } 30 | return nil 31 | } 32 | 33 | func DownRemoveRoomsTable(tx *sql.Tx) error { 34 | // We can't reverse this. 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /federationapi/storage/sqlite3/deltas/2021020411080000_rooms.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package deltas 16 | 17 | import ( 18 | "context" 19 | "database/sql" 20 | "fmt" 21 | ) 22 | 23 | func UpRemoveRoomsTable(ctx context.Context, tx *sql.Tx) error { 24 | _, err := tx.ExecContext(ctx, ` 25 | DROP TABLE IF EXISTS federationsender_rooms; 26 | `) 27 | if err != nil { 28 | return fmt.Errorf("failed to execute upgrade: %w", err) 29 | } 30 | return nil 31 | } 32 | 33 | func DownRemoveRoomsTable(tx *sql.Tx) error { 34 | // We can't reverse this. 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /test/keyring.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package test 16 | 17 | import ( 18 | "context" 19 | 20 | "github.com/matrix-org/gomatrixserverlib" 21 | ) 22 | 23 | // NopJSONVerifier is a JSONVerifier that verifies nothing and returns no errors. 24 | type NopJSONVerifier struct { 25 | // this verifier verifies nothing 26 | } 27 | 28 | func (t *NopJSONVerifier) VerifyJSONs(ctx context.Context, requests []gomatrixserverlib.VerifyJSONRequest) ([]gomatrixserverlib.VerifyJSONResult, error) { 29 | result := make([]gomatrixserverlib.VerifyJSONResult, len(requests)) 30 | return result, nil 31 | } 32 | -------------------------------------------------------------------------------- /internal/sqlutil/unique_constraint.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !wasm && !cgo 16 | // +build !wasm,!cgo 17 | 18 | package sqlutil 19 | 20 | import ( 21 | "github.com/lib/pq" 22 | "modernc.org/sqlite" 23 | lib "modernc.org/sqlite/lib" 24 | ) 25 | 26 | // IsUniqueConstraintViolationErr returns true if the error is an unique_violation error 27 | func IsUniqueConstraintViolationErr(err error) bool { 28 | switch e := err.(type) { 29 | case *pq.Error: 30 | return e.Code == "23505" 31 | case *sqlite.Error: 32 | return e.Code() == lib.SQLITE_CONSTRAINT 33 | } 34 | return false 35 | } 36 | -------------------------------------------------------------------------------- /roomserver/internal/perform/perform_forget.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package perform 16 | 17 | import ( 18 | "context" 19 | 20 | "github.com/matrix-org/dendrite/roomserver/api" 21 | "github.com/matrix-org/dendrite/roomserver/storage" 22 | ) 23 | 24 | type Forgetter struct { 25 | DB storage.Database 26 | } 27 | 28 | // PerformForget implements api.RoomServerQueryAPI 29 | func (f *Forgetter) PerformForget( 30 | ctx context.Context, 31 | request *api.PerformForgetRequest, 32 | response *api.PerformForgetResponse, 33 | ) error { 34 | return f.DB.ForgetRoom(ctx, request.UserID, request.RoomID, true) 35 | } 36 | -------------------------------------------------------------------------------- /setup/config/config_address.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "io/fs" 5 | "net/url" 6 | "strconv" 7 | ) 8 | 9 | const ( 10 | NetworkTCP = "tcp" 11 | NetworkUnix = "unix" 12 | ) 13 | 14 | type ServerAddress struct { 15 | Address string 16 | Scheme string 17 | UnixSocketPermission fs.FileMode 18 | } 19 | 20 | func (s ServerAddress) Enabled() bool { 21 | return s.Address != "" 22 | } 23 | 24 | func (s ServerAddress) IsUnixSocket() bool { 25 | return s.Scheme == NetworkUnix 26 | } 27 | 28 | func (s ServerAddress) Network() string { 29 | if s.Scheme == NetworkUnix { 30 | return NetworkUnix 31 | } else { 32 | return NetworkTCP 33 | } 34 | } 35 | 36 | func UnixSocketAddress(path string, perm string) (ServerAddress, error) { 37 | permission, err := strconv.ParseInt(perm, 8, 32) 38 | if err != nil { 39 | return ServerAddress{}, err 40 | } 41 | return ServerAddress{Address: path, Scheme: NetworkUnix, UnixSocketPermission: fs.FileMode(permission)}, nil 42 | } 43 | 44 | func HTTPAddress(urlAddress string) (ServerAddress, error) { 45 | parsedUrl, err := url.Parse(urlAddress) 46 | if err != nil { 47 | return ServerAddress{}, err 48 | } 49 | return ServerAddress{parsedUrl.Host, parsedUrl.Scheme, 0}, nil 50 | } 51 | -------------------------------------------------------------------------------- /userapi/types/statistics.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package types 16 | 17 | type UserStatistics struct { 18 | RegisteredUsersByType map[string]int64 19 | R30Users map[string]int64 20 | R30UsersV2 map[string]int64 21 | AllUsers int64 22 | NonBridgedUsers int64 23 | DailyUsers int64 24 | MonthlyUsers int64 25 | } 26 | 27 | type DatabaseEngine struct { 28 | Engine string 29 | Version string 30 | } 31 | 32 | type MessageStats struct { 33 | Messages int64 34 | SentMessages int64 35 | MessagesE2EE int64 36 | SentMessagesE2EE int64 37 | } 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | 3 | # Hidden files 4 | .* 5 | 6 | # Allow GitHub config 7 | !.github 8 | 9 | # Downloads 10 | /.downloads 11 | 12 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 13 | *.o 14 | *.a 15 | *.so 16 | 17 | # Folders 18 | /kafka 19 | /bin 20 | /pkg 21 | /_obj 22 | /_test 23 | /vendor/bin 24 | /docker/build 25 | /logs 26 | /jetstream 27 | 28 | # Architecture specific extensions/prefixes 29 | *.[568vq] 30 | [568vq].out 31 | 32 | *.cgo1.go 33 | *.cgo2.c 34 | _cgo_defun.c 35 | _cgo_gotypes.go 36 | _cgo_export.* 37 | 38 | _testmain.go 39 | 40 | *.exe 41 | *.test 42 | *.prof 43 | *.wasm 44 | *.aar 45 | *.jar 46 | *.framework 47 | *.xcframework 48 | 49 | # Generated keys 50 | *.pem 51 | *.key 52 | *.crt 53 | 54 | # Default configuration file 55 | dendrite.yaml 56 | 57 | # Database files 58 | *.db 59 | *.db-journal 60 | 61 | # Log files 62 | *.log* 63 | 64 | # Generated code 65 | cmd/dendrite-demo-yggdrasil/embed/fs*.go 66 | 67 | # Test dependencies 68 | test/wasm/node_modules 69 | 70 | # Ignore complement folder when running locally 71 | complement/ 72 | 73 | # Stuff from GitHub Pages 74 | docs/_site 75 | 76 | media_store/ 77 | build 78 | 79 | # golang workspaces 80 | go.work* 81 | 82 | # helm chart 83 | helm/dendrite/charts/ 84 | -------------------------------------------------------------------------------- /internal/sqlutil/unique_constraint_cgo.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !wasm && cgo 16 | // +build !wasm,cgo 17 | 18 | package sqlutil 19 | 20 | import ( 21 | "github.com/lib/pq" 22 | "github.com/mattn/go-sqlite3" 23 | ) 24 | 25 | // IsUniqueConstraintViolationErr returns true if the error is an unique_violation error 26 | func IsUniqueConstraintViolationErr(err error) bool { 27 | switch e := err.(type) { 28 | case *pq.Error: 29 | return e.Code == "23505" 30 | case *sqlite3.Error: 31 | return e.Code == sqlite3.ErrConstraint 32 | case sqlite3.Error: 33 | return e.Code == sqlite3.ErrConstraint 34 | } 35 | return false 36 | } 37 | -------------------------------------------------------------------------------- /internal/caching/cache_roomservernids.go: -------------------------------------------------------------------------------- 1 | package caching 2 | 3 | import ( 4 | "github.com/matrix-org/dendrite/roomserver/types" 5 | ) 6 | 7 | type RoomServerCaches interface { 8 | RoomServerNIDsCache 9 | RoomVersionCache 10 | RoomServerEventsCache 11 | RoomHierarchyCache 12 | EventStateKeyCache 13 | EventTypeCache 14 | } 15 | 16 | // RoomServerNIDsCache contains the subset of functions needed for 17 | // a roomserver NID cache. 18 | type RoomServerNIDsCache interface { 19 | GetRoomServerRoomID(roomNID types.RoomNID) (string, bool) 20 | // StoreRoomServerRoomID stores roomNID -> roomID and roomID -> roomNID 21 | StoreRoomServerRoomID(roomNID types.RoomNID, roomID string) 22 | GetRoomServerRoomNID(roomID string) (types.RoomNID, bool) 23 | } 24 | 25 | func (c Caches) GetRoomServerRoomID(roomNID types.RoomNID) (string, bool) { 26 | return c.RoomServerRoomIDs.Get(roomNID) 27 | } 28 | 29 | // StoreRoomServerRoomID stores roomNID -> roomID and roomID -> roomNID 30 | func (c Caches) StoreRoomServerRoomID(roomNID types.RoomNID, roomID string) { 31 | c.RoomServerRoomNIDs.Set(roomID, roomNID) 32 | c.RoomServerRoomIDs.Set(roomNID, roomID) 33 | } 34 | 35 | func (c Caches) GetRoomServerRoomNID(roomID string) (types.RoomNID, bool) { 36 | return c.RoomServerRoomNIDs.Get(roomID) 37 | } 38 | -------------------------------------------------------------------------------- /syncapi/streams/streamprovider.go: -------------------------------------------------------------------------------- 1 | package streams 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/matrix-org/dendrite/syncapi/storage" 7 | "github.com/matrix-org/dendrite/syncapi/types" 8 | ) 9 | 10 | type StreamProvider interface { 11 | Setup(ctx context.Context, snapshot storage.DatabaseTransaction) 12 | 13 | // Advance will update the latest position of the stream based on 14 | // an update and will wake callers waiting on StreamNotifyAfter. 15 | Advance(latest types.StreamPosition) 16 | 17 | // CompleteSync will update the response to include all updates as needed 18 | // for a complete sync. It will always return immediately. 19 | CompleteSync(ctx context.Context, snapshot storage.DatabaseTransaction, req *types.SyncRequest) types.StreamPosition 20 | 21 | // IncrementalSync will update the response to include all updates between 22 | // the from and to sync positions. It will always return immediately, 23 | // making no changes if the range contains no updates. 24 | IncrementalSync(ctx context.Context, snapshot storage.DatabaseTransaction, req *types.SyncRequest, from, to types.StreamPosition) types.StreamPosition 25 | 26 | // LatestPosition returns the latest stream position for this stream. 27 | LatestPosition(ctx context.Context) types.StreamPosition 28 | } 29 | -------------------------------------------------------------------------------- /clientapi/auth/authtypes/profile.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Vector Creations Ltd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package authtypes 16 | 17 | // Profile represents the profile for a Matrix account. 18 | type Profile struct { 19 | Localpart string `json:"local_part"` 20 | ServerName string `json:"server_name,omitempty"` // NOTSPEC: only set by Pinecone user provider 21 | DisplayName string `json:"display_name"` 22 | AvatarURL string `json:"avatar_url"` 23 | } 24 | 25 | // FullyQualifiedProfile represents the profile for a Matrix account. 26 | type FullyQualifiedProfile struct { 27 | UserID string `json:"user_id"` 28 | DisplayName string `json:"display_name"` 29 | AvatarURL string `json:"avatar_url"` 30 | } 31 | -------------------------------------------------------------------------------- /helm/dendrite/.helm-docs/monitoring.gotmpl: -------------------------------------------------------------------------------- 1 | {{ define "chart.monitoringSection" }} 2 | ## Monitoring 3 | 4 | ![Grafana Dashboard](grafana_dashboards/dendrite-rev2.png) 5 | 6 | * Works well with [Prometheus Operator](https://prometheus-operator.dev/) ([Helmchart](https://artifacthub.io/packages/helm/prometheus-community/kube-prometheus-stack)) and their setup of [Grafana](https://grafana.com/grafana/), by enabling the following values: 7 | ```yaml 8 | dendrite_config: 9 | global: 10 | metrics: 11 | enabled: true 12 | 13 | prometheus: 14 | servicemonitor: 15 | enabled: true 16 | labels: 17 | release: "kube-prometheus-stack" 18 | rules: 19 | enabled: true # will deploy alert rules 20 | labels: 21 | release: "kube-prometheus-stack" 22 | grafana: 23 | dashboards: 24 | enabled: true # will deploy default dashboards 25 | ``` 26 | PS: The label `release=kube-prometheus-stack` is setup with the helmchart of the Prometheus Operator. For Grafana Dashboards it may be necessary to enable scanning in the correct namespaces (or ALL), enabled by `sidecar.dashboards.searchNamespace` in [Helmchart of grafana](https://artifacthub.io/packages/helm/grafana/grafana) (which is part of PrometheusOperator, so `grafana.sidecar.dashboards.searchNamespace`) 27 | {{ end }} 28 | -------------------------------------------------------------------------------- /roomserver/internal/perform/perform_publish.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package perform 16 | 17 | import ( 18 | "context" 19 | 20 | "github.com/matrix-org/dendrite/roomserver/api" 21 | "github.com/matrix-org/dendrite/roomserver/storage" 22 | ) 23 | 24 | type Publisher struct { 25 | DB storage.Database 26 | } 27 | 28 | // PerformPublish publishes or unpublishes a room from the room directory. Returns a database error, if any. 29 | func (r *Publisher) PerformPublish( 30 | ctx context.Context, 31 | req *api.PerformPublishRequest, 32 | ) error { 33 | return r.DB.PublishRoom(ctx, req.RoomID, req.AppserviceID, req.NetworkID, req.Visibility == "public") 34 | } 35 | -------------------------------------------------------------------------------- /federationapi/routing/version.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 New Vector Ltd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package routing 16 | 17 | import ( 18 | "net/http" 19 | 20 | "github.com/matrix-org/dendrite/internal" 21 | "github.com/matrix-org/util" 22 | ) 23 | 24 | type version struct { 25 | Server server `json:"server"` 26 | } 27 | 28 | type server struct { 29 | Version string `json:"version"` 30 | Name string `json:"name"` 31 | } 32 | 33 | // Version returns the server version 34 | func Version() util.JSONResponse { 35 | return util.JSONResponse{ 36 | Code: http.StatusOK, 37 | JSON: &version{ 38 | server{ 39 | Name: "Dendrite", 40 | Version: internal.VersionString(), 41 | }, 42 | }, 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /helm/dendrite/templates/secrets.yaml: -------------------------------------------------------------------------------- 1 | {{- if (gt (len (.Files.Glob "appservices/*")) 0) }} 2 | --- 3 | apiVersion: v1 4 | kind: Secret 5 | metadata: 6 | name: {{ include "dendrite.fullname" . }}-appservices-conf 7 | type: Opaque 8 | data: 9 | {{ (.Files.Glob "appservices/*").AsSecrets | indent 2 }} 10 | {{- end }} 11 | 12 | {{- if and .Values.signing_key.create (not .Values.signing_key.existingSecret) }} 13 | --- 14 | apiVersion: v1 15 | kind: Secret 16 | metadata: 17 | annotations: 18 | helm.sh/resource-policy: keep 19 | name: {{ include "dendrite.fullname" . }}-signing-key 20 | type: Opaque 21 | {{- end }} 22 | 23 | {{- with .Values.dendrite_config.global.metrics }} 24 | {{- if .enabled }} 25 | --- 26 | apiVersion: v1 27 | kind: Secret 28 | metadata: 29 | name: {{ include "dendrite.fullname" $ }}-metrics-basic-auth 30 | type: Opaque 31 | stringData: 32 | user: {{ .basic_auth.user | quote }} 33 | password: {{ .basic_auth.password | quote }} 34 | {{- end }} 35 | {{- end }} 36 | 37 | --- 38 | apiVersion: v1 39 | kind: Secret 40 | metadata: 41 | name: {{ include "dendrite.fullname" . }}-conf 42 | type: Opaque 43 | stringData: 44 | dendrite.yaml: | 45 | {{ toYaml ( mustMergeOverwrite .Values.dendrite_config ( fromYaml (include "override.config" .) ) .Values.dendrite_config ) | nindent 4 }} -------------------------------------------------------------------------------- /setup/config/config_roomserver.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/matrix-org/gomatrixserverlib" 7 | log "github.com/sirupsen/logrus" 8 | ) 9 | 10 | type RoomServer struct { 11 | Matrix *Global `yaml:"-"` 12 | 13 | DefaultRoomVersion gomatrixserverlib.RoomVersion `yaml:"default_room_version,omitempty"` 14 | 15 | Database DatabaseOptions `yaml:"database,omitempty"` 16 | } 17 | 18 | func (c *RoomServer) Defaults(opts DefaultOpts) { 19 | c.DefaultRoomVersion = gomatrixserverlib.RoomVersionV10 20 | if opts.Generate { 21 | if !opts.SingleDatabase { 22 | c.Database.ConnectionString = "file:roomserver.db" 23 | } 24 | } 25 | } 26 | 27 | func (c *RoomServer) Verify(configErrs *ConfigErrors) { 28 | if c.Matrix.DatabaseOptions.ConnectionString == "" { 29 | checkNotEmpty(configErrs, "room_server.database.connection_string", string(c.Database.ConnectionString)) 30 | } 31 | 32 | if !gomatrixserverlib.KnownRoomVersion(c.DefaultRoomVersion) { 33 | configErrs.Add(fmt.Sprintf("invalid value for config key 'room_server.default_room_version': unsupported room version: %q", c.DefaultRoomVersion)) 34 | } else if !gomatrixserverlib.StableRoomVersion(c.DefaultRoomVersion) { 35 | log.Warnf("WARNING: Provided default room version %q is unstable", c.DefaultRoomVersion) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /clientapi/api/api.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package api 16 | 17 | import "github.com/matrix-org/gomatrixserverlib/fclient" 18 | 19 | // ExtraPublicRoomsProvider provides a way to inject extra published rooms into /publicRooms requests. 20 | type ExtraPublicRoomsProvider interface { 21 | // Rooms returns the extra rooms. This is called on-demand by clients, so cache appropriately. 22 | Rooms() []fclient.PublicRoom 23 | } 24 | 25 | type RegistrationToken struct { 26 | Token *string `json:"token"` 27 | UsesAllowed *int32 `json:"uses_allowed"` 28 | Pending *int32 `json:"pending"` 29 | Completed *int32 `json:"completed"` 30 | ExpiryTime *int64 `json:"expiry_time"` 31 | } 32 | -------------------------------------------------------------------------------- /.github/workflows/helm.yml: -------------------------------------------------------------------------------- 1 | name: Release Charts 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - 'helm/**' # only execute if we have helm chart changes 9 | workflow_dispatch: 10 | 11 | jobs: 12 | release: 13 | # depending on default permission settings for your org (contents being read-only or read-write for workloads), you will have to add permissions 14 | # see: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token 15 | permissions: 16 | contents: write 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 23 | 24 | - name: Configure Git 25 | run: | 26 | git config user.name "$GITHUB_ACTOR" 27 | git config user.email "$GITHUB_ACTOR@users.noreply.github.com" 28 | 29 | - name: Install Helm 30 | uses: azure/setup-helm@v3 31 | with: 32 | version: v3.10.0 33 | 34 | - name: Run chart-releaser 35 | uses: helm/chart-releaser-action@v1.6.0 36 | env: 37 | CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 38 | with: 39 | config: helm/cr.yaml 40 | charts_dir: helm/ 41 | mark_as_latest: false 42 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | nav_exclude: true 4 | --- 5 | 6 | {% include deprecation.html %} 7 | 8 | # Dendrite 9 | 10 | Dendrite is a second-generation Matrix homeserver written in Go! Following the microservice 11 | architecture model, Dendrite is designed to be efficient, reliable and scalable. Despite being beta, 12 | many Matrix features are already supported. 13 | 14 | This site aims to include relevant documentation to help you to get started with and 15 | run Dendrite. Check out the following sections: 16 | 17 | * **[Installation](installation.md)** for building and deploying your own Dendrite homeserver 18 | * **[Administration](administration.md)** for managing an existing Dendrite deployment 19 | * **[Development](development.md)** for developing against Dendrite 20 | 21 | You can also join us in our Matrix rooms dedicated to Dendrite, but please check first that 22 | your question hasn't already been [answered in the FAQ](FAQ.md): 23 | 24 | * **[#dendrite:matrix.org](https://matrix.to/#/#dendrite:matrix.org)** for general project discussion and support 25 | * **[#dendrite-dev:matrix.org](https://matrix.to/#/#dendrite-dev:matrix.org)** for chat on Dendrite development specifically 26 | * **[#dendrite-alerts:matrix.org](https://matrix.to/#/#dendrite-alerts:matrix.org)** for release notifications and other important announcements 27 | -------------------------------------------------------------------------------- /internal/httputil/routing_test.go: -------------------------------------------------------------------------------- 1 | package httputil 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "path/filepath" 7 | "testing" 8 | ) 9 | 10 | func TestRoutersError(t *testing.T) { 11 | r := NewRouters() 12 | 13 | // not found test 14 | rec := httptest.NewRecorder() 15 | req := httptest.NewRequest(http.MethodGet, filepath.Join(PublicFederationPathPrefix, "doesnotexist"), nil) 16 | r.Federation.ServeHTTP(rec, req) 17 | if rec.Code != http.StatusNotFound { 18 | t.Fatalf("unexpected status code: %d - %s", rec.Code, rec.Body.String()) 19 | } 20 | if ct := rec.Result().Header.Get("Content-Type"); ct != "application/json" { 21 | t.Fatalf("unexpected content-type: %s", ct) 22 | } 23 | 24 | // not allowed test 25 | r.DendriteAdmin. 26 | Handle("/test", http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {})). 27 | Methods(http.MethodPost) 28 | 29 | rec = httptest.NewRecorder() 30 | req = httptest.NewRequest(http.MethodGet, filepath.Join(DendriteAdminPathPrefix, "test"), nil) 31 | r.DendriteAdmin.ServeHTTP(rec, req) 32 | if rec.Code != http.StatusMethodNotAllowed { 33 | t.Fatalf("unexpected status code: %d - %s", rec.Code, rec.Body.String()) 34 | } 35 | if ct := rec.Result().Header.Get("Content-Type"); ct != "application/json" { 36 | t.Fatalf("unexpected content-type: %s", ct) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /setup/config/config_address_test.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "io/fs" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestHttpAddress_ParseGood(t *testing.T) { 11 | address, err := HTTPAddress("http://localhost:123") 12 | assert.NoError(t, err) 13 | assert.Equal(t, "localhost:123", address.Address) 14 | assert.Equal(t, "tcp", address.Network()) 15 | } 16 | 17 | func TestHttpAddress_ParseBad(t *testing.T) { 18 | _, err := HTTPAddress(":") 19 | assert.Error(t, err) 20 | } 21 | 22 | func TestUnixSocketAddress_Network(t *testing.T) { 23 | address, err := UnixSocketAddress("/tmp", "0755") 24 | assert.NoError(t, err) 25 | assert.Equal(t, "unix", address.Network()) 26 | } 27 | 28 | func TestUnixSocketAddress_Permission_LeadingZero_Ok(t *testing.T) { 29 | address, err := UnixSocketAddress("/tmp", "0755") 30 | assert.NoError(t, err) 31 | assert.Equal(t, fs.FileMode(0755), address.UnixSocketPermission) 32 | } 33 | 34 | func TestUnixSocketAddress_Permission_NoLeadingZero_Ok(t *testing.T) { 35 | address, err := UnixSocketAddress("/tmp", "755") 36 | assert.NoError(t, err) 37 | assert.Equal(t, fs.FileMode(0755), address.UnixSocketPermission) 38 | } 39 | 40 | func TestUnixSocketAddress_Permission_NonOctal_Bad(t *testing.T) { 41 | _, err := UnixSocketAddress("/tmp", "855") 42 | assert.Error(t, err) 43 | } 44 | -------------------------------------------------------------------------------- /setup/config/config_relayapi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package config 16 | 17 | type RelayAPI struct { 18 | Matrix *Global `yaml:"-"` 19 | 20 | // The database stores information used by the relay queue to 21 | // forward transactions to remote servers. 22 | Database DatabaseOptions `yaml:"database,omitempty"` 23 | } 24 | 25 | func (c *RelayAPI) Defaults(opts DefaultOpts) { 26 | if opts.Generate { 27 | if !opts.SingleDatabase { 28 | c.Database.ConnectionString = "file:relayapi.db" 29 | } 30 | } 31 | } 32 | 33 | func (c *RelayAPI) Verify(configErrs *ConfigErrors) { 34 | if c.Matrix.DatabaseOptions.ConnectionString == "" { 35 | checkNotEmpty(configErrs, "relay_api.database.connection_string", string(c.Database.ConnectionString)) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /mediaapi/storage/storage_wasm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package storage 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/matrix-org/dendrite/internal/sqlutil" 21 | "github.com/matrix-org/dendrite/mediaapi/storage/sqlite3" 22 | "github.com/matrix-org/dendrite/setup/config" 23 | ) 24 | 25 | // Open opens a postgres database. 26 | func NewMediaAPIDatasource(conMan sqlutil.Connections, dbProperties *config.DatabaseOptions) (Database, error) { 27 | switch { 28 | case dbProperties.ConnectionString.IsSQLite(): 29 | return sqlite3.NewDatabase(conMan, dbProperties) 30 | case dbProperties.ConnectionString.IsPostgres(): 31 | return nil, fmt.Errorf("can't use Postgres implementation") 32 | default: 33 | return nil, fmt.Errorf("unexpected database type") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /clientapi/httputil/parse.go: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0 (the "License"); 2 | // you may not use this file except in compliance with the License. 3 | // You may obtain a copy of the License at 4 | // 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | package httputil 14 | 15 | import ( 16 | "fmt" 17 | "net/http" 18 | "strconv" 19 | "time" 20 | ) 21 | 22 | // ParseTSParam takes a req (typically from an application service) and parses a Time object 23 | // from the req if it exists in the query parameters. If it doesn't exist, the 24 | // current time is returned. 25 | func ParseTSParam(req *http.Request) (time.Time, error) { 26 | // Use the ts parameter's value for event time if present 27 | tsStr := req.URL.Query().Get("ts") 28 | if tsStr == "" { 29 | return time.Now(), nil 30 | } 31 | 32 | // The parameter exists, parse into a Time object 33 | ts, err := strconv.ParseInt(tsStr, 10, 64) 34 | if err != nil { 35 | return time.Time{}, fmt.Errorf("param 'ts' is no valid int (%s)", err.Error()) 36 | } 37 | 38 | return time.UnixMilli(ts), nil 39 | } 40 | -------------------------------------------------------------------------------- /internal/pushgateway/client_test.go: -------------------------------------------------------------------------------- 1 | package pushgateway 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "net/http/httptest" 8 | "reflect" 9 | "testing" 10 | ) 11 | 12 | func TestNotify(t *testing.T) { 13 | wantResponse := NotifyResponse{ 14 | Rejected: []string{"testing"}, 15 | } 16 | 17 | var i = 0 18 | 19 | svr := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 20 | // /notify only accepts POST requests 21 | if r.Method != http.MethodPost { 22 | w.WriteHeader(http.StatusNotImplemented) 23 | return 24 | } 25 | 26 | if i != 0 { // error path 27 | w.WriteHeader(http.StatusBadRequest) 28 | return 29 | } 30 | 31 | // happy path 32 | json.NewEncoder(w).Encode(wantResponse) 33 | })) 34 | defer svr.Close() 35 | 36 | cl := NewHTTPClient(true) 37 | gotResponse := NotifyResponse{} 38 | 39 | // Test happy path 40 | err := cl.Notify(context.Background(), svr.URL, &NotifyRequest{}, &gotResponse) 41 | if err != nil { 42 | t.Errorf("failed to notify client") 43 | } 44 | if !reflect.DeepEqual(gotResponse, wantResponse) { 45 | t.Errorf("expected response %+v, got %+v", wantResponse, gotResponse) 46 | } 47 | 48 | // Test error path 49 | i++ 50 | err = cl.Notify(context.Background(), svr.URL, &NotifyRequest{}, &gotResponse) 51 | if err == nil { 52 | t.Errorf("expected notifying the pushgateway to fail, but it succeeded") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /setup/config/config_syncapi.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type SyncAPI struct { 4 | Matrix *Global `yaml:"-"` 5 | 6 | Database DatabaseOptions `yaml:"database,omitempty"` 7 | 8 | RealIPHeader string `yaml:"real_ip_header"` 9 | 10 | Fulltext Fulltext `yaml:"search"` 11 | } 12 | 13 | func (c *SyncAPI) Defaults(opts DefaultOpts) { 14 | c.Fulltext.Defaults(opts) 15 | if opts.Generate { 16 | if !opts.SingleDatabase { 17 | c.Database.ConnectionString = "file:syncapi.db" 18 | } 19 | } 20 | } 21 | 22 | func (c *SyncAPI) Verify(configErrs *ConfigErrors) { 23 | c.Fulltext.Verify(configErrs) 24 | if c.Matrix.DatabaseOptions.ConnectionString == "" { 25 | checkNotEmpty(configErrs, "sync_api.database", string(c.Database.ConnectionString)) 26 | } 27 | } 28 | 29 | type Fulltext struct { 30 | Enabled bool `yaml:"enabled"` 31 | IndexPath Path `yaml:"index_path"` 32 | InMemory bool `yaml:"in_memory"` // only useful in tests 33 | Language string `yaml:"language"` // the language to use when analysing content 34 | } 35 | 36 | func (f *Fulltext) Defaults(opts DefaultOpts) { 37 | f.Enabled = false 38 | f.IndexPath = "./searchindex" 39 | f.Language = "en" 40 | } 41 | 42 | func (f *Fulltext) Verify(configErrs *ConfigErrors) { 43 | if !f.Enabled { 44 | return 45 | } 46 | checkNotEmpty(configErrs, "syncapi.search.index_path", string(f.IndexPath)) 47 | checkNotEmpty(configErrs, "syncapi.search.language", f.Language) 48 | } 49 | -------------------------------------------------------------------------------- /roomserver/api/alias_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import "testing" 4 | 5 | func TestAliasEvent_Valid(t *testing.T) { 6 | type fields struct { 7 | Alias string 8 | AltAliases []string 9 | } 10 | tests := []struct { 11 | name string 12 | fields fields 13 | want bool 14 | }{ 15 | { 16 | name: "empty alias", 17 | fields: fields{ 18 | Alias: "", 19 | }, 20 | want: true, 21 | }, 22 | { 23 | name: "empty alias, invalid alt aliases", 24 | fields: fields{ 25 | Alias: "", 26 | AltAliases: []string{"%not:valid.local"}, 27 | }, 28 | }, 29 | { 30 | name: "valid alias, invalid alt aliases", 31 | fields: fields{ 32 | Alias: "#valid:test.local", 33 | AltAliases: []string{"%not:valid.local"}, 34 | }, 35 | }, 36 | { 37 | name: "empty alias, invalid alt aliases", 38 | fields: fields{ 39 | Alias: "", 40 | AltAliases: []string{"%not:valid.local"}, 41 | }, 42 | }, 43 | { 44 | name: "invalid alias", 45 | fields: fields{ 46 | Alias: "%not:valid.local", 47 | AltAliases: []string{}, 48 | }, 49 | }, 50 | } 51 | for _, tt := range tests { 52 | t.Run(tt.name, func(t *testing.T) { 53 | a := AliasEvent{ 54 | Alias: tt.fields.Alias, 55 | AltAliases: tt.fields.AltAliases, 56 | } 57 | if got := a.Valid(); got != tt.want { 58 | t.Errorf("Valid() = %v, want %v", got, tt.want) 59 | } 60 | }) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /roomserver/storage/postgres/deltas/20201028212440_add_forgotten_column.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package deltas 16 | 17 | import ( 18 | "context" 19 | "database/sql" 20 | "fmt" 21 | ) 22 | 23 | func UpAddForgottenColumn(ctx context.Context, tx *sql.Tx) error { 24 | _, err := tx.ExecContext(ctx, `ALTER TABLE roomserver_membership ADD COLUMN IF NOT EXISTS forgotten BOOLEAN NOT NULL DEFAULT false;`) 25 | if err != nil { 26 | return fmt.Errorf("failed to execute upgrade: %w", err) 27 | } 28 | return nil 29 | } 30 | 31 | func DownAddForgottenColumn(ctx context.Context, tx *sql.Tx) error { 32 | _, err := tx.ExecContext(ctx, `ALTER TABLE roomserver_membership DROP COLUMN IF EXISTS forgotten;`) 33 | if err != nil { 34 | return fmt.Errorf("failed to execute downgrade: %w", err) 35 | } 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /cmd/dendrite/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "os/signal" 6 | "strings" 7 | "syscall" 8 | "testing" 9 | ) 10 | 11 | // This is an instrumented main, used when running integration tests (sytest) with code coverage. 12 | // Compile: go test -c -race -cover -covermode=atomic -o monolith.debug -coverpkg "github.com/matrix-org/..." ./cmd/dendrite 13 | // Run the monolith: ./monolith.debug -test.coverprofile=/somewhere/to/dump/integrationcover.out DEVEL --config dendrite.yaml 14 | // Generate HTML with coverage: go tool cover -html=/somewhere/where/there/is/integrationcover.out -o cover.html 15 | // Source: https://dzone.com/articles/measuring-integration-test-coverage-rate-in-pouchc 16 | func TestMain(_ *testing.T) { 17 | var ( 18 | args []string 19 | ) 20 | 21 | for _, arg := range os.Args { 22 | switch { 23 | case strings.HasPrefix(arg, "DEVEL"): 24 | case strings.HasPrefix(arg, "-test"): 25 | default: 26 | args = append(args, arg) 27 | } 28 | } 29 | // only run the tests if there are args to be passed 30 | if len(args) <= 1 { 31 | return 32 | } 33 | 34 | waitCh := make(chan int, 1) 35 | os.Args = args 36 | go func() { 37 | main() 38 | close(waitCh) 39 | }() 40 | 41 | signalCh := make(chan os.Signal, 1) 42 | signal.Notify(signalCh, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGHUP) 43 | 44 | select { 45 | case <-signalCh: 46 | return 47 | case <-waitCh: 48 | return 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /roomserver/storage/postgres/deltas/20230131091021_published_appservice_pkey.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package deltas 16 | 17 | import ( 18 | "context" 19 | "database/sql" 20 | "fmt" 21 | ) 22 | 23 | func UpPulishedAppservicePrimaryKey(ctx context.Context, tx *sql.Tx) error { 24 | _, err := tx.ExecContext(ctx, `ALTER TABLE roomserver_published RENAME CONSTRAINT roomserver_published_pkey TO roomserver_published_pkeyold; 25 | CREATE UNIQUE INDEX roomserver_published_pkey ON roomserver_published (room_id, appservice_id, network_id); 26 | ALTER TABLE roomserver_published DROP CONSTRAINT roomserver_published_pkeyold; 27 | ALTER TABLE roomserver_published ADD PRIMARY KEY USING INDEX roomserver_published_pkey;`) 28 | if err != nil { 29 | return fmt.Errorf("failed to execute upgrade: %w", err) 30 | } 31 | return nil 32 | } 33 | -------------------------------------------------------------------------------- /syncapi/storage/storage_wasm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package storage 16 | 17 | import ( 18 | "context" 19 | "fmt" 20 | 21 | "github.com/matrix-org/dendrite/internal/sqlutil" 22 | "github.com/matrix-org/dendrite/setup/config" 23 | "github.com/matrix-org/dendrite/syncapi/storage/sqlite3" 24 | ) 25 | 26 | // NewPublicRoomsServerDatabase opens a database connection. 27 | func NewSyncServerDatasource(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions) (Database, error) { 28 | switch { 29 | case dbProperties.ConnectionString.IsSQLite(): 30 | return sqlite3.NewDatabase(ctx, conMan, dbProperties) 31 | case dbProperties.ConnectionString.IsPostgres(): 32 | return nil, fmt.Errorf("can't use Postgres implementation") 33 | default: 34 | return nil, fmt.Errorf("unexpected database type") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contrib/dendrite-demo-i2p/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "os/signal" 6 | "strings" 7 | "syscall" 8 | "testing" 9 | ) 10 | 11 | // This is an instrumented main, used when running integration tests (sytest) with code coverage. 12 | // Compile: go test -c -race -cover -covermode=atomic -o monolith.debug -coverpkg "github.com/matrix-org/..." ./cmd/dendrite 13 | // Run the monolith: ./monolith.debug -test.coverprofile=/somewhere/to/dump/integrationcover.out DEVEL --config dendrite.yaml 14 | // Generate HTML with coverage: go tool cover -html=/somewhere/where/there/is/integrationcover.out -o cover.html 15 | // Source: https://dzone.com/articles/measuring-integration-test-coverage-rate-in-pouchc 16 | func TestMain(t *testing.T) { 17 | var args []string 18 | 19 | for _, arg := range os.Args { 20 | switch { 21 | case strings.HasPrefix(arg, "DEVEL"): 22 | case strings.HasPrefix(arg, "-test"): 23 | default: 24 | args = append(args, arg) 25 | } 26 | } 27 | 28 | // only run the tests if there are args to be passed 29 | if len(args) <= 1 { 30 | return 31 | } 32 | t.Log(args) 33 | 34 | waitCh := make(chan int, 1) 35 | os.Args = args 36 | go func() { 37 | main() 38 | close(waitCh) 39 | }() 40 | 41 | signalCh := make(chan os.Signal, 1) 42 | signal.Notify(signalCh, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGHUP) 43 | 44 | select { 45 | case <-signalCh: 46 | return 47 | case <-waitCh: 48 | return 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /contrib/dendrite-demo-tor/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "os/signal" 6 | "strings" 7 | "syscall" 8 | "testing" 9 | ) 10 | 11 | // This is an instrumented main, used when running integration tests (sytest) with code coverage. 12 | // Compile: go test -c -race -cover -covermode=atomic -o monolith.debug -coverpkg "github.com/matrix-org/..." ./cmd/dendrite 13 | // Run the monolith: ./monolith.debug -test.coverprofile=/somewhere/to/dump/integrationcover.out DEVEL --config dendrite.yaml 14 | // Generate HTML with coverage: go tool cover -html=/somewhere/where/there/is/integrationcover.out -o cover.html 15 | // Source: https://dzone.com/articles/measuring-integration-test-coverage-rate-in-pouchc 16 | func TestMain(t *testing.T) { 17 | var args []string 18 | 19 | for _, arg := range os.Args { 20 | switch { 21 | case strings.HasPrefix(arg, "DEVEL"): 22 | case strings.HasPrefix(arg, "-test"): 23 | default: 24 | args = append(args, arg) 25 | } 26 | } 27 | 28 | // only run the tests if there are args to be passed 29 | if len(args) <= 1 { 30 | return 31 | } 32 | t.Log(args) 33 | 34 | waitCh := make(chan int, 1) 35 | os.Args = args 36 | go func() { 37 | main() 38 | close(waitCh) 39 | }() 40 | 41 | signalCh := make(chan os.Signal, 1) 42 | signal.Notify(signalCh, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGHUP) 43 | 44 | select { 45 | case <-signalCh: 46 | return 47 | case <-waitCh: 48 | return 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /mediaapi/routing/download_test.go: -------------------------------------------------------------------------------- 1 | package routing 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "net/http" 7 | "net/http/httptest" 8 | "testing" 9 | 10 | "github.com/matrix-org/dendrite/mediaapi/types" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func Test_dispositionFor(t *testing.T) { 15 | assert.Equal(t, "attachment", contentDispositionFor(""), "empty content type") 16 | assert.Equal(t, "attachment", contentDispositionFor("image/svg"), "image/svg") 17 | assert.Equal(t, "inline", contentDispositionFor("image/jpeg"), "image/jpg") 18 | } 19 | 20 | func Test_Multipart(t *testing.T) { 21 | r := &downloadRequest{ 22 | MediaMetadata: &types.MediaMetadata{}, 23 | } 24 | data := bytes.Buffer{} 25 | responseBody := "This media is plain text. Maybe somebody used it as a paste bin." 26 | data.WriteString(responseBody) 27 | 28 | srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { 29 | _, err := multipartResponse(w, r, "text/plain", &data) 30 | assert.NoError(t, err) 31 | })) 32 | defer srv.Close() 33 | 34 | resp, err := srv.Client().Get(srv.URL) 35 | assert.NoError(t, err) 36 | defer resp.Body.Close() 37 | // contentLength is always 0, since there's no Content-Length header on the multipart part. 38 | _, reader, err := parseMultipartResponse(r, resp, 1000) 39 | assert.NoError(t, err) 40 | gotResponse, err := io.ReadAll(reader) 41 | assert.NoError(t, err) 42 | assert.Equal(t, responseBody, string(gotResponse)) 43 | } 44 | -------------------------------------------------------------------------------- /syncapi/storage/postgres/deltas/20210112130000_sendtodevice_sentcolumn.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package deltas 16 | 17 | import ( 18 | "context" 19 | "database/sql" 20 | "fmt" 21 | ) 22 | 23 | func UpRemoveSendToDeviceSentColumn(ctx context.Context, tx *sql.Tx) error { 24 | _, err := tx.ExecContext(ctx, ` 25 | ALTER TABLE syncapi_send_to_device 26 | DROP COLUMN IF EXISTS sent_by_token; 27 | `) 28 | if err != nil { 29 | return fmt.Errorf("failed to execute upgrade: %w", err) 30 | } 31 | return nil 32 | } 33 | 34 | func DownRemoveSendToDeviceSentColumn(ctx context.Context, tx *sql.Tx) error { 35 | _, err := tx.ExecContext(ctx, ` 36 | ALTER TABLE syncapi_send_to_device 37 | ADD COLUMN IF NOT EXISTS sent_by_token TEXT; 38 | `) 39 | if err != nil { 40 | return fmt.Errorf("failed to execute downgrade: %w", err) 41 | } 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /clientapi/routing/directory_public_test.go: -------------------------------------------------------------------------------- 1 | package routing 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/matrix-org/gomatrixserverlib/fclient" 8 | ) 9 | 10 | func pubRoom(name string) fclient.PublicRoom { 11 | return fclient.PublicRoom{ 12 | Name: name, 13 | } 14 | } 15 | 16 | func TestSliceInto(t *testing.T) { 17 | slice := []fclient.PublicRoom{ 18 | pubRoom("a"), pubRoom("b"), pubRoom("c"), pubRoom("d"), pubRoom("e"), pubRoom("f"), pubRoom("g"), 19 | } 20 | limit := int64(3) 21 | testCases := []struct { 22 | since int64 23 | wantPrev int 24 | wantNext int 25 | wantSubset []fclient.PublicRoom 26 | }{ 27 | { 28 | since: 0, 29 | wantPrev: -1, 30 | wantNext: 3, 31 | wantSubset: slice[0:3], 32 | }, 33 | { 34 | since: 3, 35 | wantPrev: 0, 36 | wantNext: 6, 37 | wantSubset: slice[3:6], 38 | }, 39 | { 40 | since: 6, 41 | wantPrev: 3, 42 | wantNext: -1, 43 | wantSubset: slice[6:7], 44 | }, 45 | } 46 | for _, tc := range testCases { 47 | subset, prev, next := sliceInto(slice, tc.since, limit) 48 | if !reflect.DeepEqual(subset, tc.wantSubset) { 49 | t.Errorf("returned subset is wrong, got %v want %v", subset, tc.wantSubset) 50 | } 51 | if prev != tc.wantPrev { 52 | t.Errorf("returned prev is wrong, got %d want %d", prev, tc.wantPrev) 53 | } 54 | if next != tc.wantNext { 55 | t.Errorf("returned next is wrong, got %d want %d", next, tc.wantNext) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /syncapi/streams/stream_devicelist.go: -------------------------------------------------------------------------------- 1 | package streams 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/matrix-org/dendrite/roomserver/api" 7 | "github.com/matrix-org/dendrite/syncapi/internal" 8 | "github.com/matrix-org/dendrite/syncapi/storage" 9 | "github.com/matrix-org/dendrite/syncapi/types" 10 | userapi "github.com/matrix-org/dendrite/userapi/api" 11 | ) 12 | 13 | type DeviceListStreamProvider struct { 14 | DefaultStreamProvider 15 | rsAPI api.SyncRoomserverAPI 16 | userAPI userapi.SyncKeyAPI 17 | } 18 | 19 | func (p *DeviceListStreamProvider) CompleteSync( 20 | ctx context.Context, 21 | snapshot storage.DatabaseTransaction, 22 | req *types.SyncRequest, 23 | ) types.StreamPosition { 24 | return p.LatestPosition(ctx) 25 | } 26 | 27 | func (p *DeviceListStreamProvider) IncrementalSync( 28 | ctx context.Context, 29 | snapshot storage.DatabaseTransaction, 30 | req *types.SyncRequest, 31 | from, to types.StreamPosition, 32 | ) types.StreamPosition { 33 | var err error 34 | to, _, err = internal.DeviceListCatchup(context.Background(), snapshot, p.userAPI, p.rsAPI, req.Device.UserID, req.Response, from, to) 35 | if err != nil { 36 | req.Log.WithError(err).Error("internal.DeviceListCatchup failed") 37 | return from 38 | } 39 | err = internal.DeviceOTKCounts(req.Context, p.userAPI, req.Device.UserID, req.Device.ID, req.Response) 40 | if err != nil { 41 | req.Log.WithError(err).Error("internal.DeviceListCatchup failed") 42 | return from 43 | } 44 | 45 | return to 46 | } 47 | -------------------------------------------------------------------------------- /clientapi/routing/whoami.go: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0 (the "License"); 2 | // you may not use this file except in compliance with the License. 3 | // You may obtain a copy of the License at 4 | // 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | package routing 14 | 15 | import ( 16 | "net/http" 17 | 18 | "github.com/matrix-org/dendrite/userapi/api" 19 | "github.com/matrix-org/util" 20 | ) 21 | 22 | // whoamiResponse represents an response for a `whoami` request 23 | type whoamiResponse struct { 24 | UserID string `json:"user_id"` 25 | DeviceID string `json:"device_id"` 26 | IsGuest bool `json:"is_guest"` 27 | } 28 | 29 | // Whoami implements `/account/whoami` which enables client to query their account user id. 30 | // https://matrix.org/docs/spec/client_server/r0.3.0.html#get-matrix-client-r0-account-whoami 31 | func Whoami(req *http.Request, device *api.Device) util.JSONResponse { 32 | return util.JSONResponse{ 33 | Code: http.StatusOK, 34 | JSON: whoamiResponse{ 35 | UserID: device.UserID, 36 | DeviceID: device.ID, 37 | IsGuest: device.AccountType == api.AccountTypeGuest, 38 | }, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /docs/administration/3_presence.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Enabling presence 3 | parent: Administration 4 | permalink: /administration/presence 5 | nav_order: 3 6 | --- 7 | 8 | {% include deprecation.html %} 9 | 10 | # Enabling presence 11 | 12 | Dendrite supports presence, which allows you to send your online/offline status 13 | to other users, and to receive their statuses automatically. They will be displayed 14 | by supported clients. 15 | 16 | Note that enabling presence **can negatively impact** the performance of your Dendrite 17 | server — it will require more CPU time and will increase the "chattiness" of your server 18 | over federation. It is disabled by default for this reason. 19 | 20 | Dendrite has two options for controlling presence: 21 | 22 | * **Enable inbound presence**: Dendrite will handle presence updates for remote users 23 | and distribute them to local users on your homeserver; 24 | * **Enable outbound presence**: Dendrite will generate presence notifications for your 25 | local users and distribute them to remote users over the federation. 26 | 27 | This means that you can configure only one or other direction if you prefer, i.e. to 28 | receive presence from other servers without revealing the presence of your own users. 29 | 30 | ## Configuring presence 31 | 32 | Presence is controlled by the `presence` block in the `global` section of the 33 | configuration file: 34 | 35 | ```yaml 36 | global: 37 | # ... 38 | presence: 39 | enable_inbound: false 40 | enable_outbound: false 41 | ``` 42 | -------------------------------------------------------------------------------- /mediaapi/storage/storage.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !wasm 16 | // +build !wasm 17 | 18 | package storage 19 | 20 | import ( 21 | "fmt" 22 | 23 | "github.com/matrix-org/dendrite/internal/sqlutil" 24 | "github.com/matrix-org/dendrite/mediaapi/storage/postgres" 25 | "github.com/matrix-org/dendrite/mediaapi/storage/sqlite3" 26 | "github.com/matrix-org/dendrite/setup/config" 27 | ) 28 | 29 | // NewMediaAPIDatasource opens a database connection. 30 | func NewMediaAPIDatasource(conMan *sqlutil.Connections, dbProperties *config.DatabaseOptions) (Database, error) { 31 | switch { 32 | case dbProperties.ConnectionString.IsSQLite(): 33 | return sqlite3.NewDatabase(conMan, dbProperties) 34 | case dbProperties.ConnectionString.IsPostgres(): 35 | return postgres.NewDatabase(conMan, dbProperties) 36 | default: 37 | return nil, fmt.Errorf("unexpected database type") 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Jekyll site to GitHub Pages 2 | name: Deploy GitHub Pages dependencies preinstalled 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["gh-pages"] 8 | paths: 9 | - 'docs/**' # only execute if we have docs changes 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 15 | permissions: 16 | contents: read 17 | pages: write 18 | id-token: write 19 | 20 | # Allow one concurrent deployment 21 | concurrency: 22 | group: "pages" 23 | cancel-in-progress: true 24 | 25 | jobs: 26 | # Build job 27 | build: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - name: Checkout 31 | uses: actions/checkout@v4 32 | - name: Setup Pages 33 | uses: actions/configure-pages@v2 34 | - name: Build with Jekyll 35 | uses: actions/jekyll-build-pages@v1 36 | with: 37 | source: ./docs 38 | destination: ./_site 39 | - name: Upload artifact 40 | uses: actions/upload-pages-artifact@v1 41 | 42 | # Deployment job 43 | deploy: 44 | environment: 45 | name: github-pages 46 | url: ${{ steps.deployment.outputs.page_url }} 47 | runs-on: ubuntu-latest 48 | needs: build 49 | steps: 50 | - name: Deploy to GitHub Pages 51 | id: deployment 52 | uses: actions/deploy-pages@v1 53 | -------------------------------------------------------------------------------- /roomserver/storage/storage_wasm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package storage 16 | 17 | import ( 18 | "context" 19 | "fmt" 20 | 21 | "github.com/matrix-org/dendrite/internal/caching" 22 | "github.com/matrix-org/dendrite/internal/sqlutil" 23 | "github.com/matrix-org/dendrite/roomserver/storage/sqlite3" 24 | "github.com/matrix-org/dendrite/setup/config" 25 | ) 26 | 27 | // NewPublicRoomsServerDatabase opens a database connection. 28 | func Open(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (Database, error) { 29 | switch { 30 | case dbProperties.ConnectionString.IsSQLite(): 31 | return sqlite3.Open(ctx, conMan, dbProperties, cache) 32 | case dbProperties.ConnectionString.IsPostgres(): 33 | return nil, fmt.Errorf("can't use Postgres implementation") 34 | default: 35 | return nil, fmt.Errorf("unexpected database type") 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /setup/base/sanity_unix.go: -------------------------------------------------------------------------------- 1 | //go:build unix 2 | // +build unix 3 | 4 | package base 5 | 6 | import ( 7 | "syscall" 8 | 9 | "github.com/sirupsen/logrus" 10 | ) 11 | 12 | func PlatformSanityChecks() { 13 | // Dendrite needs a relatively high number of file descriptors in order 14 | // to function properly, particularly when federating with lots of servers. 15 | // If we run out of file descriptors, we might run into problems accessing 16 | // PostgreSQL amongst other things. Complain at startup if we think the 17 | // number of file descriptors is too low. 18 | warn := func(rLimit *syscall.Rlimit) { 19 | logrus.Warnf("IMPORTANT: Process file descriptor limit is currently %d, it is recommended to raise the limit for Dendrite to at least 65535 to avoid issues", rLimit.Cur) 20 | } 21 | var rLimit syscall.Rlimit 22 | if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit); err == nil && rLimit.Cur < 65535 { 23 | // The file descriptor count is too low. Let's try to raise it. 24 | rLimit.Cur = 65535 25 | if err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil { 26 | // We failed to raise it, so log an error. 27 | logrus.WithError(err).Warn("IMPORTANT: Failed to raise the file descriptor limit") 28 | warn(&rLimit) 29 | } else if err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit); err == nil && rLimit.Cur < 65535 { 30 | // We think we successfully raised the limit, but a second call to 31 | // get the limit told us that we didn't succeed. Log an error. 32 | warn(&rLimit) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /internal/caching/cache_federationevents.go: -------------------------------------------------------------------------------- 1 | package caching 2 | 3 | import ( 4 | "github.com/matrix-org/dendrite/roomserver/types" 5 | "github.com/matrix-org/gomatrixserverlib" 6 | ) 7 | 8 | // FederationCache contains the subset of functions needed for 9 | // a federation event cache. 10 | type FederationCache interface { 11 | GetFederationQueuedPDU(eventNID int64) (event *types.HeaderedEvent, ok bool) 12 | StoreFederationQueuedPDU(eventNID int64, event *types.HeaderedEvent) 13 | EvictFederationQueuedPDU(eventNID int64) 14 | 15 | GetFederationQueuedEDU(eventNID int64) (event *gomatrixserverlib.EDU, ok bool) 16 | StoreFederationQueuedEDU(eventNID int64, event *gomatrixserverlib.EDU) 17 | EvictFederationQueuedEDU(eventNID int64) 18 | } 19 | 20 | func (c Caches) GetFederationQueuedPDU(eventNID int64) (*types.HeaderedEvent, bool) { 21 | return c.FederationPDUs.Get(eventNID) 22 | } 23 | 24 | func (c Caches) StoreFederationQueuedPDU(eventNID int64, event *types.HeaderedEvent) { 25 | c.FederationPDUs.Set(eventNID, event) 26 | } 27 | 28 | func (c Caches) EvictFederationQueuedPDU(eventNID int64) { 29 | c.FederationPDUs.Unset(eventNID) 30 | } 31 | 32 | func (c Caches) GetFederationQueuedEDU(eventNID int64) (*gomatrixserverlib.EDU, bool) { 33 | return c.FederationEDUs.Get(eventNID) 34 | } 35 | 36 | func (c Caches) StoreFederationQueuedEDU(eventNID int64, event *gomatrixserverlib.EDU) { 37 | c.FederationEDUs.Set(eventNID, event) 38 | } 39 | 40 | func (c Caches) EvictFederationQueuedEDU(eventNID int64) { 41 | c.FederationEDUs.Unset(eventNID) 42 | } 43 | -------------------------------------------------------------------------------- /clientapi/routing/register_secret_test.go: -------------------------------------------------------------------------------- 1 | package routing 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "testing" 7 | 8 | "github.com/patrickmn/go-cache" 9 | ) 10 | 11 | func TestSharedSecretRegister(t *testing.T) { 12 | // these values have come from a local synapse instance to ensure compatibility 13 | jsonStr := []byte(`{"admin":false,"mac":"f1ba8d37123866fd659b40de4bad9b0f8965c565","nonce":"759f047f312b99ff428b21d581256f8592b8976e58bc1b543972dc6147e529a79657605b52d7becd160ff5137f3de11975684319187e06901955f79e5a6c5a79","password":"wonderland","username":"alice","displayname":"rabbit"}`) 14 | sharedSecret := "dendritetest" 15 | 16 | req, err := NewSharedSecretRegistrationRequest(io.NopCloser(bytes.NewBuffer(jsonStr))) 17 | if err != nil { 18 | t.Fatalf("failed to read request: %s", err) 19 | } 20 | 21 | r := NewSharedSecretRegistration(sharedSecret) 22 | 23 | // force the nonce to be known 24 | r.nonces.Set(req.Nonce, true, cache.DefaultExpiration) 25 | 26 | valid, err := r.IsValidMacLogin(req.Nonce, req.User, req.Password, req.Admin, req.MacBytes) 27 | if err != nil { 28 | t.Fatalf("failed to check for valid mac: %s", err) 29 | } 30 | if !valid { 31 | t.Errorf("mac login failed, wanted success") 32 | } 33 | 34 | // modify the mac so it fails 35 | req.MacBytes[0] = 0xff 36 | valid, err = r.IsValidMacLogin(req.Nonce, req.User, req.Password, req.Admin, req.MacBytes) 37 | if err != nil { 38 | t.Fatalf("failed to check for valid mac: %s", err) 39 | } 40 | if valid { 41 | t.Errorf("mac login succeeded, wanted failure") 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /syncapi/storage/storage.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !wasm 16 | // +build !wasm 17 | 18 | package storage 19 | 20 | import ( 21 | "context" 22 | "fmt" 23 | 24 | "github.com/matrix-org/dendrite/internal/sqlutil" 25 | "github.com/matrix-org/dendrite/setup/config" 26 | "github.com/matrix-org/dendrite/syncapi/storage/postgres" 27 | "github.com/matrix-org/dendrite/syncapi/storage/sqlite3" 28 | ) 29 | 30 | // NewSyncServerDatasource opens a database connection. 31 | func NewSyncServerDatasource(ctx context.Context, conMan *sqlutil.Connections, dbProperties *config.DatabaseOptions) (Database, error) { 32 | switch { 33 | case dbProperties.ConnectionString.IsSQLite(): 34 | return sqlite3.NewDatabase(ctx, conMan, dbProperties) 35 | case dbProperties.ConnectionString.IsPostgres(): 36 | return postgres.NewDatabase(ctx, conMan, dbProperties) 37 | default: 38 | return nil, fmt.Errorf("unexpected database type") 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /cmd/dendrite-upgrade-tests/tar.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "archive/tar" 5 | "compress/gzip" 6 | "io" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | ) 11 | 12 | // From https://gist.github.com/mimoo/25fc9716e0f1353791f5908f94d6e726 13 | // Modified to strip off top-level when compressing 14 | func compress(src string, buf io.Writer) error { 15 | // tar > gzip > buf 16 | zr := gzip.NewWriter(buf) 17 | tw := tar.NewWriter(zr) 18 | 19 | // walk through every file in the folder 20 | err := filepath.Walk(src, func(file string, fi os.FileInfo, e error) error { 21 | // generate tar header 22 | header, err := tar.FileInfoHeader(fi, file) 23 | if err != nil { 24 | return err 25 | } 26 | 27 | // must provide real name 28 | // (see https://golang.org/src/archive/tar/common.go?#L626) 29 | header.Name = strings.TrimPrefix(filepath.ToSlash(file), src+"/") 30 | // write header 31 | if err := tw.WriteHeader(header); err != nil { 32 | return err 33 | } 34 | // if not a dir, write file content 35 | if !fi.IsDir() { 36 | data, err := os.Open(file) 37 | if err != nil { 38 | return err 39 | } 40 | if _, err = io.Copy(tw, data); err != nil { 41 | return err 42 | } 43 | if err = data.Close(); err != nil { 44 | return err 45 | } 46 | } 47 | return nil 48 | }) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | // produce tar 54 | if err := tw.Close(); err != nil { 55 | return err 56 | } 57 | // produce gzip 58 | if err := zr.Close(); err != nil { 59 | return err 60 | } 61 | // 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /cmd/create-account/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "testing" 7 | ) 8 | 9 | func Test_getPassword(t *testing.T) { 10 | type args struct { 11 | password string 12 | pwdFile string 13 | pwdStdin bool 14 | reader io.Reader 15 | } 16 | 17 | pass := "mySecretPass" 18 | passwordFile := "testdata/my.pass" 19 | reader := &bytes.Buffer{} 20 | _, err := reader.WriteString(pass) 21 | if err != nil { 22 | t.Errorf("unable to write to buffer: %+v", err) 23 | } 24 | tests := []struct { 25 | name string 26 | args args 27 | want string 28 | wantErr bool 29 | }{ 30 | { 31 | name: "password defined", 32 | args: args{ 33 | password: pass, 34 | }, 35 | want: pass, 36 | }, 37 | { 38 | name: "pwdFile defined", 39 | args: args{ 40 | pwdFile: passwordFile, 41 | }, 42 | want: pass, 43 | }, 44 | { 45 | name: "pwdFile does not exist", 46 | args: args{pwdFile: "iDontExist"}, 47 | wantErr: true, 48 | }, 49 | { 50 | name: "read pass from stdin defined", 51 | args: args{ 52 | pwdStdin: true, 53 | reader: reader, 54 | }, 55 | want: pass, 56 | }, 57 | } 58 | for _, tt := range tests { 59 | t.Run(tt.name, func(t *testing.T) { 60 | got, err := getPassword(tt.args.password, tt.args.pwdFile, tt.args.pwdStdin, tt.args.reader) 61 | if !tt.wantErr && err != nil { 62 | t.Errorf("expected no error, but got %v", err) 63 | } 64 | if got != tt.want { 65 | t.Errorf("getPassword() = '%v', want '%v'", got, tt.want) 66 | } 67 | }) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /internal/sqlutil/uri.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package sqlutil 16 | 17 | import ( 18 | "errors" 19 | "fmt" 20 | "net/url" 21 | 22 | "github.com/matrix-org/dendrite/setup/config" 23 | ) 24 | 25 | // ParseFileURI returns the filepath in the given file: URI. Specifically, this will handle 26 | // both relative (file:foo.db) and absolute (file:///path/to/foo) paths. 27 | func ParseFileURI(dataSourceName config.DataSource) (string, error) { 28 | if !dataSourceName.IsSQLite() { 29 | return "", errors.New("ParseFileURI expects SQLite connection string") 30 | } 31 | uri, err := url.Parse(string(dataSourceName)) 32 | if err != nil { 33 | return "", err 34 | } 35 | var cs string 36 | if uri.Opaque != "" { // file:filename.db 37 | cs = uri.Opaque 38 | } else if uri.Path != "" { // file:///path/to/filename.db 39 | cs = uri.Path 40 | } else { 41 | return "", fmt.Errorf("invalid file uri: %s", dataSourceName) 42 | } 43 | return cs, nil 44 | } 45 | -------------------------------------------------------------------------------- /userapi/storage/sqlite3/deltas/2022021012490600_add_account_type.go: -------------------------------------------------------------------------------- 1 | package deltas 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "fmt" 7 | ) 8 | 9 | func UpAddAccountType(ctx context.Context, tx *sql.Tx) error { 10 | // initially set every account to useraccount, change appservice and guest accounts afterwards 11 | // (user = 1, guest = 2, admin = 3, appservice = 4) 12 | _, err := tx.ExecContext(ctx, `ALTER TABLE userapi_accounts RENAME TO userapi_accounts_tmp; 13 | CREATE TABLE userapi_accounts ( 14 | localpart TEXT NOT NULL PRIMARY KEY, 15 | server_name TEXT NOT NULL, 16 | created_ts BIGINT NOT NULL, 17 | password_hash TEXT, 18 | appservice_id TEXT, 19 | is_deactivated BOOLEAN DEFAULT 0, 20 | account_type INTEGER NOT NULL 21 | ); 22 | INSERT 23 | INTO userapi_accounts ( 24 | localpart, created_ts, password_hash, appservice_id, account_type 25 | ) SELECT 26 | localpart, created_ts, password_hash, appservice_id, 1 27 | FROM userapi_accounts_tmp 28 | ; 29 | UPDATE userapi_accounts SET account_type = 4 WHERE appservice_id <> ''; 30 | UPDATE userapi_accounts SET account_type = 2 WHERE localpart GLOB '[0-9]*'; 31 | DROP TABLE userapi_accounts_tmp;`) 32 | if err != nil { 33 | return fmt.Errorf("failed to add column: %w", err) 34 | } 35 | return nil 36 | } 37 | 38 | func DownAddAccountType(ctx context.Context, tx *sql.Tx) error { 39 | _, err := tx.ExecContext(ctx, `ALTER TABLE userapi_accounts DROP COLUMN account_type;`) 40 | if err != nil { 41 | return fmt.Errorf("failed to execute downgrade: %w", err) 42 | } 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /internal/caching/cache_lazy_load_members.go: -------------------------------------------------------------------------------- 1 | package caching 2 | 3 | import ( 4 | userapi "github.com/matrix-org/dendrite/userapi/api" 5 | ) 6 | 7 | type lazyLoadingCacheKey struct { 8 | UserID string // the user we're querying on behalf of 9 | DeviceID string // the user we're querying on behalf of 10 | RoomID string // the room in question 11 | TargetUserID string // the user whose membership we're asking about 12 | } 13 | 14 | type LazyLoadCache interface { 15 | StoreLazyLoadedUser(device *userapi.Device, roomID, userID, eventID string) 16 | IsLazyLoadedUserCached(device *userapi.Device, roomID, userID string) (string, bool) 17 | InvalidateLazyLoadedUser(device *userapi.Device, roomID, userID string) 18 | } 19 | 20 | func (c Caches) StoreLazyLoadedUser(device *userapi.Device, roomID, userID, eventID string) { 21 | c.LazyLoading.Set(lazyLoadingCacheKey{ 22 | UserID: device.UserID, 23 | DeviceID: device.ID, 24 | RoomID: roomID, 25 | TargetUserID: userID, 26 | }, eventID) 27 | } 28 | 29 | func (c Caches) IsLazyLoadedUserCached(device *userapi.Device, roomID, userID string) (string, bool) { 30 | return c.LazyLoading.Get(lazyLoadingCacheKey{ 31 | UserID: device.UserID, 32 | DeviceID: device.ID, 33 | RoomID: roomID, 34 | TargetUserID: userID, 35 | }) 36 | } 37 | 38 | func (c Caches) InvalidateLazyLoadedUser(device *userapi.Device, roomID, userID string) { 39 | c.LazyLoading.Unset(lazyLoadingCacheKey{ 40 | UserID: device.UserID, 41 | DeviceID: device.ID, 42 | RoomID: roomID, 43 | TargetUserID: userID, 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /federationapi/storage/shared/receipt/receipt.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // A Receipt contains the NIDs of a call to GetNextTransactionPDUs/EDUs. 15 | // We don't actually export the NIDs but we need the caller to be able 16 | // to pass them back so that we can clean up if the transaction sends 17 | // successfully. 18 | 19 | package receipt 20 | 21 | import "fmt" 22 | 23 | // Receipt is a wrapper type used to represent a nid that corresponds to a unique row entry 24 | // in some database table. 25 | // The internal nid value cannot be modified after a Receipt has been created. 26 | // This guarantees a receipt will always refer to the same table entry that it was created 27 | // to represent. 28 | type Receipt struct { 29 | nid int64 30 | } 31 | 32 | func NewReceipt(nid int64) Receipt { 33 | return Receipt{nid: nid} 34 | } 35 | 36 | func (r *Receipt) GetNID() int64 { 37 | return r.nid 38 | } 39 | 40 | func (r *Receipt) String() string { 41 | return fmt.Sprintf("%d", r.nid) 42 | } 43 | -------------------------------------------------------------------------------- /setup/base/static/client/login/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | } 4 | 5 | body { 6 | height: 100%; 7 | font-family: "Myriad Pro", "Myriad", Helvetica, Arial, sans-serif; 8 | font-size: 12pt; 9 | margin: 0px; 10 | } 11 | 12 | h1 { 13 | font-size: 20pt; 14 | } 15 | 16 | a:link { color: #666; } 17 | a:visited { color: #666; } 18 | a:hover { color: #000; } 19 | a:active { color: #000; } 20 | 21 | input { 22 | margin: 5px; 23 | } 24 | 25 | textbox, input[type="text"], input[type="password"] { 26 | width: 90%; 27 | } 28 | 29 | form { 30 | text-align: center; 31 | margin: 10px 0 0 0; 32 | } 33 | 34 | ul.radiobuttons { 35 | text-align: left; 36 | list-style: none; 37 | } 38 | 39 | /* 40 | * Add some padding to the viewport. 41 | */ 42 | #container { 43 | padding: 10px; 44 | } 45 | /* 46 | * Center all direct children of the main form. 47 | */ 48 | #container > * { 49 | display: block; 50 | margin-left: auto; 51 | margin-right: auto; 52 | text-align: center; 53 | } 54 | 55 | /* 56 | * A wrapper around each login flow. 57 | */ 58 | .login_flow { 59 | width: 300px; 60 | text-align: left; 61 | padding: 10px; 62 | margin-bottom: 40px; 63 | 64 | border-radius: 10px; 65 | box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.15); 66 | 67 | background-color: #f8f8f8; 68 | border: 1px #ccc solid; 69 | } 70 | 71 | /* 72 | * Used to show error content. 73 | */ 74 | #feedback { 75 | /* Red text. */ 76 | color: #ff0000; 77 | /* A little space to not overlap the box-shadow. */ 78 | margin-bottom: 20px; 79 | } 80 | -------------------------------------------------------------------------------- /roomserver/storage/storage.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !wasm 16 | // +build !wasm 17 | 18 | package storage 19 | 20 | import ( 21 | "context" 22 | "fmt" 23 | 24 | "github.com/matrix-org/dendrite/internal/caching" 25 | "github.com/matrix-org/dendrite/internal/sqlutil" 26 | "github.com/matrix-org/dendrite/roomserver/storage/postgres" 27 | "github.com/matrix-org/dendrite/roomserver/storage/sqlite3" 28 | "github.com/matrix-org/dendrite/setup/config" 29 | ) 30 | 31 | // Open opens a database connection. 32 | func Open(ctx context.Context, conMan *sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (Database, error) { 33 | switch { 34 | case dbProperties.ConnectionString.IsSQLite(): 35 | return sqlite3.Open(ctx, conMan, dbProperties, cache) 36 | case dbProperties.ConnectionString.IsPostgres(): 37 | return postgres.Open(ctx, conMan, dbProperties, cache) 38 | default: 39 | return nil, fmt.Errorf("unexpected database type") 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /relayapi/storage/storage_wasm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package storage 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/matrix-org/dendrite/internal/caching" 21 | "github.com/matrix-org/dendrite/internal/sqlutil" 22 | "github.com/matrix-org/dendrite/relayapi/storage/sqlite3" 23 | "github.com/matrix-org/dendrite/setup/config" 24 | "github.com/matrix-org/gomatrixserverlib" 25 | ) 26 | 27 | // NewDatabase opens a new database 28 | func NewDatabase( 29 | conMan sqlutil.Connections, 30 | dbProperties *config.DatabaseOptions, 31 | cache caching.FederationCache, 32 | isLocalServerName func(spec.ServerName) bool, 33 | ) (Database, error) { 34 | switch { 35 | case dbProperties.ConnectionString.IsSQLite(): 36 | return sqlite3.NewDatabase(conMan, dbProperties, cache, isLocalServerName) 37 | case dbProperties.ConnectionString.IsPostgres(): 38 | return nil, fmt.Errorf("can't use Postgres implementation") 39 | default: 40 | return nil, fmt.Errorf("unexpected database type") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /syncapi/storage/shared/storage_sync_test.go: -------------------------------------------------------------------------------- 1 | package shared 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/matrix-org/dendrite/syncapi/synctypes" 7 | ) 8 | 9 | func Test_isStatefilterEmpty(t *testing.T) { 10 | filterSet := []string{"a"} 11 | boolValue := false 12 | 13 | tests := []struct { 14 | name string 15 | filter *synctypes.StateFilter 16 | want bool 17 | }{ 18 | { 19 | name: "nil filter is empty", 20 | filter: nil, 21 | want: true, 22 | }, 23 | { 24 | name: "Empty filter is empty", 25 | filter: &synctypes.StateFilter{}, 26 | want: true, 27 | }, 28 | { 29 | name: "NotTypes is set", 30 | filter: &synctypes.StateFilter{ 31 | NotTypes: &filterSet, 32 | }, 33 | }, 34 | { 35 | name: "Types is set", 36 | filter: &synctypes.StateFilter{ 37 | Types: &filterSet, 38 | }, 39 | }, 40 | { 41 | name: "Senders is set", 42 | filter: &synctypes.StateFilter{ 43 | Senders: &filterSet, 44 | }, 45 | }, 46 | { 47 | name: "NotSenders is set", 48 | filter: &synctypes.StateFilter{ 49 | NotSenders: &filterSet, 50 | }, 51 | }, 52 | { 53 | name: "NotRooms is set", 54 | filter: &synctypes.StateFilter{ 55 | NotRooms: &filterSet, 56 | }, 57 | }, 58 | { 59 | name: "ContainsURL is set", 60 | filter: &synctypes.StateFilter{ 61 | ContainsURL: &boolValue, 62 | }, 63 | }, 64 | } 65 | for _, tt := range tests { 66 | t.Run(tt.name, func(t *testing.T) { 67 | if got := isStatefilterEmpty(tt.filter); got != tt.want { 68 | t.Errorf("isStatefilterEmpty() = %v, want %v", got, tt.want) 69 | } 70 | }) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /internal/caching/cache_eventstatekeys.go: -------------------------------------------------------------------------------- 1 | package caching 2 | 3 | import "github.com/matrix-org/dendrite/roomserver/types" 4 | 5 | // EventStateKeyCache contains the subset of functions needed for 6 | // a room event state key cache. 7 | type EventStateKeyCache interface { 8 | GetEventStateKey(eventStateKeyNID types.EventStateKeyNID) (string, bool) 9 | StoreEventStateKey(eventStateKeyNID types.EventStateKeyNID, eventStateKey string) 10 | GetEventStateKeyNID(eventStateKey string) (types.EventStateKeyNID, bool) 11 | } 12 | 13 | func (c Caches) GetEventStateKey(eventStateKeyNID types.EventStateKeyNID) (string, bool) { 14 | return c.RoomServerStateKeys.Get(eventStateKeyNID) 15 | } 16 | 17 | func (c Caches) StoreEventStateKey(eventStateKeyNID types.EventStateKeyNID, eventStateKey string) { 18 | c.RoomServerStateKeys.Set(eventStateKeyNID, eventStateKey) 19 | c.RoomServerStateKeyNIDs.Set(eventStateKey, eventStateKeyNID) 20 | } 21 | 22 | func (c Caches) GetEventStateKeyNID(eventStateKey string) (types.EventStateKeyNID, bool) { 23 | return c.RoomServerStateKeyNIDs.Get(eventStateKey) 24 | } 25 | 26 | type EventTypeCache interface { 27 | GetEventTypeKey(eventType string) (types.EventTypeNID, bool) 28 | StoreEventTypeKey(eventTypeNID types.EventTypeNID, eventType string) 29 | } 30 | 31 | func (c Caches) StoreEventTypeKey(eventTypeNID types.EventTypeNID, eventType string) { 32 | c.RoomServerEventTypeNIDs.Set(eventType, eventTypeNID) 33 | c.RoomServerEventTypes.Set(eventTypeNID, eventType) 34 | } 35 | 36 | func (c Caches) GetEventTypeKey(eventType string) (types.EventTypeNID, bool) { 37 | return c.RoomServerEventTypeNIDs.Get(eventType) 38 | } 39 | -------------------------------------------------------------------------------- /federationapi/storage/storage_wasm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package storage 16 | 17 | import ( 18 | "context" 19 | "fmt" 20 | 21 | "github.com/matrix-org/dendrite/federationapi/storage/sqlite3" 22 | "github.com/matrix-org/dendrite/internal/caching" 23 | "github.com/matrix-org/dendrite/internal/sqlutil" 24 | "github.com/matrix-org/dendrite/setup/config" 25 | "github.com/matrix-org/gomatrixserverlib" 26 | ) 27 | 28 | // NewDatabase opens a new database 29 | func NewDatabase(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.FederationCache, isLocalServerName func(spec.ServerName) bool) (Database, error) { 30 | switch { 31 | case dbProperties.ConnectionString.IsSQLite(): 32 | return sqlite3.NewDatabase(ctx, conMan, dbProperties, cache, isLocalServerName) 33 | case dbProperties.ConnectionString.IsPostgres(): 34 | return nil, fmt.Errorf("can't use Postgres implementation") 35 | default: 36 | return nil, fmt.Errorf("unexpected database type") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mediaapi/storage/sqlite3/mediaapi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2018 New Vector Ltd 2 | // Copyright 2019-2020 The Matrix.org Foundation C.I.C. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package sqlite3 17 | 18 | import ( 19 | // Import the postgres database driver. 20 | "github.com/matrix-org/dendrite/internal/sqlutil" 21 | "github.com/matrix-org/dendrite/mediaapi/storage/shared" 22 | "github.com/matrix-org/dendrite/setup/config" 23 | ) 24 | 25 | // NewDatabase opens a SQLIte database. 26 | func NewDatabase(conMan *sqlutil.Connections, dbProperties *config.DatabaseOptions) (*shared.Database, error) { 27 | db, writer, err := conMan.Connection(dbProperties) 28 | if err != nil { 29 | return nil, err 30 | } 31 | mediaRepo, err := NewSQLiteMediaRepositoryTable(db) 32 | if err != nil { 33 | return nil, err 34 | } 35 | thumbnails, err := NewSQLiteThumbnailsTable(db) 36 | if err != nil { 37 | return nil, err 38 | } 39 | return &shared.Database{ 40 | MediaRepository: mediaRepo, 41 | Thumbnails: thumbnails, 42 | DB: db, 43 | Writer: writer, 44 | }, nil 45 | } 46 | -------------------------------------------------------------------------------- /cmd/dendrite-demo-yggdrasil/yggconn/client.go: -------------------------------------------------------------------------------- 1 | package yggconn 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | 7 | "github.com/matrix-org/dendrite/setup/config" 8 | "github.com/matrix-org/gomatrixserverlib/fclient" 9 | ) 10 | 11 | type yggroundtripper struct { 12 | inner *http.Transport 13 | } 14 | 15 | func (y *yggroundtripper) RoundTrip(req *http.Request) (*http.Response, error) { 16 | req.URL.Scheme = "http" 17 | return y.inner.RoundTrip(req) 18 | } 19 | 20 | func (n *Node) CreateClient() *fclient.Client { 21 | tr := &http.Transport{} 22 | tr.RegisterProtocol( 23 | "matrix", &yggroundtripper{ 24 | inner: &http.Transport{ 25 | MaxIdleConns: -1, 26 | MaxIdleConnsPerHost: -1, 27 | TLSHandshakeTimeout: 10 * time.Second, 28 | ResponseHeaderTimeout: 10 * time.Second, 29 | IdleConnTimeout: 30 * time.Second, 30 | DialContext: n.DialerContext, 31 | }, 32 | }, 33 | ) 34 | return fclient.NewClient( 35 | fclient.WithTransport(tr), 36 | ) 37 | } 38 | 39 | func (n *Node) CreateFederationClient( 40 | cfg *config.Dendrite, 41 | ) fclient.FederationClient { 42 | tr := &http.Transport{} 43 | tr.RegisterProtocol( 44 | "matrix", &yggroundtripper{ 45 | inner: &http.Transport{ 46 | MaxIdleConns: -1, 47 | MaxIdleConnsPerHost: -1, 48 | TLSHandshakeTimeout: 10 * time.Second, 49 | ResponseHeaderTimeout: 10 * time.Second, 50 | IdleConnTimeout: 30 * time.Second, 51 | DialContext: n.DialerContext, 52 | }, 53 | }, 54 | ) 55 | return fclient.NewFederationClient( 56 | cfg.Global.SigningIdentities(), 57 | fclient.WithTransport(tr), 58 | ) 59 | } 60 | -------------------------------------------------------------------------------- /syncapi/synctypes/filter_test.go: -------------------------------------------------------------------------------- 1 | package synctypes 2 | 3 | import ( 4 | "encoding/json" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | func Test_Filter(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | input []byte 13 | want RoomEventFilter 14 | }{ 15 | { 16 | name: "empty types filter", 17 | input: []byte(`{ "types": [] }`), 18 | want: RoomEventFilter{ 19 | Limit: 0, 20 | NotSenders: nil, 21 | NotTypes: nil, 22 | Senders: nil, 23 | Types: &[]string{}, 24 | LazyLoadMembers: false, 25 | IncludeRedundantMembers: false, 26 | NotRooms: nil, 27 | Rooms: nil, 28 | ContainsURL: nil, 29 | }, 30 | }, 31 | { 32 | name: "absent types filter", 33 | input: []byte(`{}`), 34 | want: RoomEventFilter{ 35 | Limit: 0, 36 | NotSenders: nil, 37 | NotTypes: nil, 38 | Senders: nil, 39 | Types: nil, 40 | LazyLoadMembers: false, 41 | IncludeRedundantMembers: false, 42 | NotRooms: nil, 43 | Rooms: nil, 44 | ContainsURL: nil, 45 | }, 46 | }, 47 | } 48 | for _, tt := range tests { 49 | t.Run(tt.name, func(t *testing.T) { 50 | var f RoomEventFilter 51 | if err := json.Unmarshal(tt.input, &f); err != nil { 52 | t.Fatalf("unable to parse filter: %v", err) 53 | } 54 | if !reflect.DeepEqual(f, tt.want) { 55 | t.Fatalf("Expected %+v\ngot %+v", tt.want, f) 56 | } 57 | }) 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /userapi/storage/sqlite3/deltas/20200929203058_is_active.go: -------------------------------------------------------------------------------- 1 | package deltas 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "fmt" 7 | ) 8 | 9 | func UpIsActive(ctx context.Context, tx *sql.Tx) error { 10 | _, err := tx.ExecContext(ctx, ` 11 | ALTER TABLE userapi_accounts RENAME TO userapi_accounts_tmp; 12 | CREATE TABLE userapi_accounts ( 13 | localpart TEXT NOT NULL PRIMARY KEY, 14 | server_name TEXT NOT NULL, 15 | created_ts BIGINT NOT NULL, 16 | password_hash TEXT, 17 | appservice_id TEXT, 18 | is_deactivated BOOLEAN DEFAULT 0 19 | ); 20 | INSERT 21 | INTO userapi_accounts ( 22 | localpart, created_ts, password_hash, appservice_id 23 | ) SELECT 24 | localpart, created_ts, password_hash, appservice_id 25 | FROM userapi_accounts_tmp 26 | ; 27 | DROP TABLE userapi_accounts_tmp;`) 28 | if err != nil { 29 | return fmt.Errorf("failed to execute upgrade: %w", err) 30 | } 31 | return nil 32 | } 33 | 34 | func DownIsActive(ctx context.Context, tx *sql.Tx) error { 35 | _, err := tx.ExecContext(ctx, ` 36 | ALTER TABLE userapi_accounts RENAME TO userapi_accounts_tmp; 37 | CREATE TABLE userapi_accounts ( 38 | localpart TEXT NOT NULL PRIMARY KEY, 39 | created_ts BIGINT NOT NULL, 40 | password_hash TEXT, 41 | appservice_id TEXT 42 | ); 43 | INSERT 44 | INTO userapi_accounts ( 45 | localpart, created_ts, password_hash, appservice_id 46 | ) SELECT 47 | localpart, created_ts, password_hash, appservice_id 48 | FROM userapi_accounts_tmp 49 | ; 50 | DROP TABLE userapi_accounts_tmp;`) 51 | if err != nil { 52 | return fmt.Errorf("failed to execute downgrade: %w", err) 53 | } 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /mediaapi/storage/postgres/mediaapi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2018 New Vector Ltd 2 | // Copyright 2019-2020 The Matrix.org Foundation C.I.C. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package postgres 17 | 18 | import ( 19 | // Import the postgres database driver. 20 | _ "github.com/lib/pq" 21 | "github.com/matrix-org/dendrite/internal/sqlutil" 22 | "github.com/matrix-org/dendrite/mediaapi/storage/shared" 23 | "github.com/matrix-org/dendrite/setup/config" 24 | ) 25 | 26 | // NewDatabase opens a postgres database. 27 | func NewDatabase(conMan *sqlutil.Connections, dbProperties *config.DatabaseOptions) (*shared.Database, error) { 28 | db, writer, err := conMan.Connection(dbProperties) 29 | if err != nil { 30 | return nil, err 31 | } 32 | mediaRepo, err := NewPostgresMediaRepositoryTable(db) 33 | if err != nil { 34 | return nil, err 35 | } 36 | thumbnails, err := NewPostgresThumbnailsTable(db) 37 | if err != nil { 38 | return nil, err 39 | } 40 | return &shared.Database{ 41 | MediaRepository: mediaRepo, 42 | Thumbnails: thumbnails, 43 | DB: db, 44 | Writer: writer, 45 | }, nil 46 | } 47 | -------------------------------------------------------------------------------- /internal/version.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "fmt" 5 | "runtime/debug" 6 | "strings" 7 | ) 8 | 9 | // the final version string 10 | var version string 11 | 12 | // -ldflags "-X github.com/matrix-org/dendrite/internal.branch=master" 13 | var branch string 14 | 15 | // -ldflags "-X github.com/matrix-org/dendrite/internal.build=alpha" 16 | var build string 17 | 18 | const ( 19 | VersionMajor = 0 20 | VersionMinor = 13 21 | VersionPatch = 8 22 | VersionTag = "" // example: "rc1" 23 | 24 | gitRevLen = 7 // 7 matches the displayed characters on github.com 25 | ) 26 | 27 | func VersionString() string { 28 | return version 29 | } 30 | 31 | func init() { 32 | version = fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch) 33 | if VersionTag != "" { 34 | version += "-" + VersionTag 35 | } 36 | parts := []string{} 37 | if build != "" { 38 | parts = append(parts, build) 39 | } 40 | if branch != "" { 41 | parts = append(parts, branch) 42 | } 43 | 44 | defer func() { 45 | if len(parts) > 0 { 46 | version += "+" + strings.Join(parts, ".") 47 | } 48 | }() 49 | 50 | // Try to get the revision Dendrite was build from. 51 | // If we can't, e.g. Dendrite wasn't built (go run) or no VCS version is present, 52 | // we just use the provided version above. 53 | info, ok := debug.ReadBuildInfo() 54 | if !ok { 55 | return 56 | } 57 | 58 | for _, setting := range info.Settings { 59 | if setting.Key == "vcs.revision" { 60 | revLen := len(setting.Value) 61 | if revLen >= gitRevLen { 62 | parts = append(parts, setting.Value[:gitRevLen]) 63 | } else { 64 | parts = append(parts, setting.Value[:revLen]) 65 | } 66 | break 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /userapi/util/stats.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !wasm && !windows 16 | // +build !wasm,!windows 17 | 18 | package util 19 | 20 | import ( 21 | "syscall" 22 | "time" 23 | 24 | "github.com/sirupsen/logrus" 25 | ) 26 | 27 | func getMemoryStats(p *phoneHomeStats) error { 28 | oldUsage := p.prevData 29 | newUsage := syscall.Rusage{} 30 | if err := syscall.Getrusage(syscall.RUSAGE_SELF, &newUsage); err != nil { 31 | logrus.WithError(err).Error("unable to get usage") 32 | return err 33 | } 34 | newData := timestampToRUUsage{timestamp: time.Now().Unix(), usage: newUsage} 35 | p.prevData = newData 36 | 37 | usedCPUTime := (newUsage.Utime.Sec + newUsage.Stime.Sec) - (oldUsage.usage.Utime.Sec + oldUsage.usage.Stime.Sec) 38 | 39 | if usedCPUTime == 0 || newData.timestamp == oldUsage.timestamp { 40 | p.stats["cpu_average"] = 0 41 | } else { 42 | // conversion to int64 required for GOARCH=386 43 | p.stats["cpu_average"] = int64(usedCPUTime) / (newData.timestamp - oldUsage.timestamp) * 100 44 | } 45 | p.stats["memory_rss"] = newUsage.Maxrss 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /setup/config/config_jetstream.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type JetStream struct { 8 | Matrix *Global `yaml:"-"` 9 | 10 | // Persistent directory to store JetStream streams in. 11 | StoragePath Path `yaml:"storage_path"` 12 | // A list of NATS addresses to connect to. If none are specified, an 13 | // internal NATS server will be used when running in monolith mode only. 14 | Addresses []string `yaml:"addresses"` 15 | // The prefix to use for stream names for this homeserver - really only 16 | // useful if running more than one Dendrite on the same NATS deployment. 17 | TopicPrefix string `yaml:"topic_prefix"` 18 | // Keep all storage in memory. This is mostly useful for unit tests. 19 | InMemory bool `yaml:"in_memory"` 20 | // Disable logging. This is mostly useful for unit tests. 21 | NoLog bool `yaml:"-"` 22 | // Disables TLS validation. This should NOT be used in production 23 | DisableTLSValidation bool `yaml:"disable_tls_validation"` 24 | // A credentials file to be used for authentication, example: 25 | // https://docs.nats.io/using-nats/developer/connecting/creds 26 | Credentials Path `yaml:"credentials_path"` 27 | } 28 | 29 | func (c *JetStream) Prefixed(name string) string { 30 | return fmt.Sprintf("%s%s", c.TopicPrefix, name) 31 | } 32 | 33 | func (c *JetStream) Durable(name string) string { 34 | return c.Prefixed(name) 35 | } 36 | 37 | func (c *JetStream) Defaults(opts DefaultOpts) { 38 | c.Addresses = []string{} 39 | c.TopicPrefix = "Dendrite" 40 | if opts.Generate { 41 | c.StoragePath = Path("./") 42 | c.NoLog = true 43 | c.DisableTLSValidation = true 44 | c.Credentials = Path("") 45 | } 46 | } 47 | 48 | func (c *JetStream) Verify(configErrs *ConfigErrors) {} 49 | -------------------------------------------------------------------------------- /mediaapi/storage/interface.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package storage 16 | 17 | import ( 18 | "context" 19 | 20 | "github.com/matrix-org/dendrite/mediaapi/types" 21 | "github.com/matrix-org/gomatrixserverlib/spec" 22 | ) 23 | 24 | type Database interface { 25 | MediaRepository 26 | Thumbnails 27 | } 28 | 29 | type MediaRepository interface { 30 | StoreMediaMetadata(ctx context.Context, mediaMetadata *types.MediaMetadata) error 31 | GetMediaMetadata(ctx context.Context, mediaID types.MediaID, mediaOrigin spec.ServerName) (*types.MediaMetadata, error) 32 | GetMediaMetadataByHash(ctx context.Context, mediaHash types.Base64Hash, mediaOrigin spec.ServerName) (*types.MediaMetadata, error) 33 | } 34 | 35 | type Thumbnails interface { 36 | StoreThumbnail(ctx context.Context, thumbnailMetadata *types.ThumbnailMetadata) error 37 | GetThumbnail(ctx context.Context, mediaID types.MediaID, mediaOrigin spec.ServerName, width, height int, resizeMethod string) (*types.ThumbnailMetadata, error) 38 | GetThumbnails(ctx context.Context, mediaID types.MediaID, mediaOrigin spec.ServerName) ([]*types.ThumbnailMetadata, error) 39 | } 40 | -------------------------------------------------------------------------------- /relayapi/storage/storage.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !wasm 16 | // +build !wasm 17 | 18 | package storage 19 | 20 | import ( 21 | "fmt" 22 | 23 | "github.com/matrix-org/dendrite/internal/caching" 24 | "github.com/matrix-org/dendrite/internal/sqlutil" 25 | "github.com/matrix-org/dendrite/relayapi/storage/postgres" 26 | "github.com/matrix-org/dendrite/relayapi/storage/sqlite3" 27 | "github.com/matrix-org/dendrite/setup/config" 28 | "github.com/matrix-org/gomatrixserverlib/spec" 29 | ) 30 | 31 | // NewDatabase opens a new database 32 | func NewDatabase( 33 | conMan *sqlutil.Connections, 34 | dbProperties *config.DatabaseOptions, 35 | cache caching.FederationCache, 36 | isLocalServerName func(spec.ServerName) bool, 37 | ) (Database, error) { 38 | switch { 39 | case dbProperties.ConnectionString.IsSQLite(): 40 | return sqlite3.NewDatabase(conMan, dbProperties, cache, isLocalServerName) 41 | case dbProperties.ConnectionString.IsPostgres(): 42 | return postgres.NewDatabase(conMan, dbProperties, cache, isLocalServerName) 43 | default: 44 | return nil, fmt.Errorf("unexpected database type") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /federationapi/storage/postgres/deltas/2022042812473400_addexpiresat.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package deltas 16 | 17 | import ( 18 | "context" 19 | "database/sql" 20 | "fmt" 21 | "time" 22 | 23 | "github.com/matrix-org/gomatrixserverlib/spec" 24 | ) 25 | 26 | func UpAddexpiresat(ctx context.Context, tx *sql.Tx) error { 27 | _, err := tx.ExecContext(ctx, "ALTER TABLE federationsender_queue_edus ADD COLUMN IF NOT EXISTS expires_at BIGINT NOT NULL DEFAULT 0;") 28 | if err != nil { 29 | return fmt.Errorf("failed to execute upgrade: %w", err) 30 | } 31 | _, err = tx.ExecContext(ctx, "UPDATE federationsender_queue_edus SET expires_at = $1 WHERE edu_type != 'm.direct_to_device'", spec.AsTimestamp(time.Now().Add(time.Hour*24))) 32 | if err != nil { 33 | return fmt.Errorf("failed to update queue_edus: %w", err) 34 | } 35 | return nil 36 | } 37 | 38 | func DownAddexpiresat(ctx context.Context, tx *sql.Tx) error { 39 | _, err := tx.ExecContext(ctx, "ALTER TABLE federationsender_queue_edus DROP COLUMN expires_at;") 40 | if err != nil { 41 | return fmt.Errorf("failed to execute downgrade: %w", err) 42 | } 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #syntax=docker/dockerfile:1.2 2 | 3 | # 4 | # base installs required dependencies and runs go mod download to cache dependencies 5 | # 6 | FROM --platform=${BUILDPLATFORM} docker.io/golang:1.22-alpine AS base 7 | RUN apk --update --no-cache add bash build-base curl git 8 | 9 | # 10 | # build creates all needed binaries 11 | # 12 | FROM --platform=${BUILDPLATFORM} base AS build 13 | WORKDIR /src 14 | ARG TARGETOS 15 | ARG TARGETARCH 16 | RUN --mount=target=. \ 17 | --mount=type=cache,target=/root/.cache/go-build \ 18 | --mount=type=cache,target=/go/pkg/mod \ 19 | USERARCH=`go env GOARCH` \ 20 | GOARCH="$TARGETARCH" \ 21 | GOOS="linux" \ 22 | CGO_ENABLED=$([ "$TARGETARCH" = "$USERARCH" ] && echo "1" || echo "0") \ 23 | go build -v -trimpath -o /out/ ./cmd/... 24 | 25 | 26 | # 27 | # Builds the Dendrite image containing all required binaries 28 | # 29 | FROM alpine:latest 30 | RUN apk --update --no-cache add curl 31 | LABEL org.opencontainers.image.title="Dendrite" 32 | LABEL org.opencontainers.image.description="Next-generation Matrix homeserver written in Go" 33 | LABEL org.opencontainers.image.source="https://github.com/matrix-org/dendrite" 34 | LABEL org.opencontainers.image.licenses="Apache-2.0" 35 | LABEL org.opencontainers.image.documentation="https://matrix-org.github.io/dendrite/" 36 | LABEL org.opencontainers.image.vendor="The Matrix.org Foundation C.I.C." 37 | 38 | COPY --from=build /out/create-account /usr/bin/create-account 39 | COPY --from=build /out/generate-config /usr/bin/generate-config 40 | COPY --from=build /out/generate-keys /usr/bin/generate-keys 41 | COPY --from=build /out/dendrite /usr/bin/dendrite 42 | 43 | VOLUME /etc/dendrite 44 | WORKDIR /etc/dendrite 45 | 46 | ENTRYPOINT ["/usr/bin/dendrite"] 47 | EXPOSE 8008 8448 48 | 49 | -------------------------------------------------------------------------------- /syncapi/producers/federationapi_presence.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package producers 16 | 17 | import ( 18 | "strconv" 19 | "time" 20 | 21 | "github.com/matrix-org/dendrite/setup/jetstream" 22 | "github.com/matrix-org/dendrite/syncapi/types" 23 | "github.com/matrix-org/gomatrixserverlib/spec" 24 | "github.com/nats-io/nats.go" 25 | ) 26 | 27 | // FederationAPIPresenceProducer produces events for the federation API server to consume 28 | type FederationAPIPresenceProducer struct { 29 | Topic string 30 | JetStream nats.JetStreamContext 31 | } 32 | 33 | func (f *FederationAPIPresenceProducer) SendPresence( 34 | userID string, presence types.Presence, statusMsg *string, 35 | ) error { 36 | msg := nats.NewMsg(f.Topic) 37 | msg.Header.Set(jetstream.UserID, userID) 38 | msg.Header.Set("presence", presence.String()) 39 | msg.Header.Set("from_sync", "true") // only update last_active_ts and presence 40 | msg.Header.Set("last_active_ts", strconv.Itoa(int(spec.AsTimestamp(time.Now())))) 41 | 42 | if statusMsg != nil { 43 | msg.Header.Set("status_msg", *statusMsg) 44 | } 45 | 46 | _, err := f.JetStream.PublishMsg(msg) 47 | return err 48 | } 49 | -------------------------------------------------------------------------------- /federationapi/storage/storage.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !wasm 16 | // +build !wasm 17 | 18 | package storage 19 | 20 | import ( 21 | "context" 22 | "fmt" 23 | 24 | "github.com/matrix-org/dendrite/federationapi/storage/postgres" 25 | "github.com/matrix-org/dendrite/federationapi/storage/sqlite3" 26 | "github.com/matrix-org/dendrite/internal/caching" 27 | "github.com/matrix-org/dendrite/internal/sqlutil" 28 | "github.com/matrix-org/dendrite/setup/config" 29 | "github.com/matrix-org/gomatrixserverlib/spec" 30 | ) 31 | 32 | // NewDatabase opens a new database 33 | func NewDatabase(ctx context.Context, conMan *sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.FederationCache, isLocalServerName func(spec.ServerName) bool) (Database, error) { 34 | switch { 35 | case dbProperties.ConnectionString.IsSQLite(): 36 | return sqlite3.NewDatabase(ctx, conMan, dbProperties, cache, isLocalServerName) 37 | case dbProperties.ConnectionString.IsPostgres(): 38 | return postgres.NewDatabase(ctx, conMan, dbProperties, cache, isLocalServerName) 39 | default: 40 | return nil, fmt.Errorf("unexpected database type") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /mediaapi/README.md: -------------------------------------------------------------------------------- 1 | # Media API 2 | 3 | This server is responsible for serving `/media` requests as per: 4 | 5 | http://matrix.org/docs/spec/client_server/r0.2.0.html#id43 6 | 7 | ## Scaling libraries 8 | 9 | ### nfnt/resize (default) 10 | 11 | Thumbnailing uses https://github.com/nfnt/resize by default which is a pure golang image scaling library relying on image codecs from the standard library. It is ISC-licensed. 12 | 13 | It is multi-threaded and uses Lanczos3 so produces sharp images. Using Lanczos3 all the way makes it slower than some other approaches like bimg. (~845ms in total for pre-generating 32x32-crop, 96x96-crop, 320x240-scale, 640x480-scale and 800x600-scale from a given JPEG image on a given machine.) 14 | 15 | See the sample below for image quality with nfnt/resize: 16 | 17 | ![](nfnt-96x96-crop.jpg) 18 | 19 | ### bimg (uses libvips C library) 20 | 21 | Alternatively one can use `go build -tags bimg` to use bimg from https://github.com/h2non/bimg (MIT-licensed) which uses libvips from https://github.com/jcupitt/libvips (LGPL v2.1+ -licensed). libvips is a C library and must be installed/built separately. See the github page for details. Also note that libvips in turn has dependencies with a selection of FOSS licenses. 22 | 23 | bimg and libvips have significantly better performance than nfnt/resize but produce slightly less-sharp images. bimg uses a box filter for downscaling to within about 200% of the target scale and then uses Lanczos3 for the last bit. This is a much faster approach but comes at the expense of sharpness. (~295ms in total for pre-generating 32x32-crop, 96x96-crop, 320x240-scale, 640x480-scale and 800x600-scale from a given JPEG image on a given machine.) 24 | 25 | See the sample below for image quality with bimg: 26 | 27 | ![](bimg-96x96-crop.jpg) 28 | -------------------------------------------------------------------------------- /internal/tracing.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package internal 16 | 17 | import ( 18 | "context" 19 | "runtime/trace" 20 | 21 | "github.com/opentracing/opentracing-go" 22 | ) 23 | 24 | type Trace struct { 25 | span opentracing.Span 26 | region *trace.Region 27 | task *trace.Task 28 | } 29 | 30 | func StartTask(inCtx context.Context, name string) (Trace, context.Context) { 31 | ctx, task := trace.NewTask(inCtx, name) 32 | span, ctx := opentracing.StartSpanFromContext(ctx, name) 33 | return Trace{ 34 | span: span, 35 | task: task, 36 | }, ctx 37 | } 38 | 39 | func StartRegion(inCtx context.Context, name string) (Trace, context.Context) { 40 | region := trace.StartRegion(inCtx, name) 41 | span, ctx := opentracing.StartSpanFromContext(inCtx, name) 42 | return Trace{ 43 | span: span, 44 | region: region, 45 | }, ctx 46 | } 47 | 48 | func (t Trace) EndRegion() { 49 | t.span.Finish() 50 | if t.region != nil { 51 | t.region.End() 52 | } 53 | } 54 | 55 | func (t Trace) EndTask() { 56 | t.span.Finish() 57 | if t.task != nil { 58 | t.task.End() 59 | } 60 | } 61 | 62 | func (t Trace) SetTag(key string, value any) { 63 | t.span.SetTag(key, value) 64 | } 65 | -------------------------------------------------------------------------------- /mediaapi/mediaapi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Vector Creations Ltd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package mediaapi 16 | 17 | import ( 18 | "github.com/matrix-org/dendrite/internal/httputil" 19 | "github.com/matrix-org/dendrite/internal/sqlutil" 20 | "github.com/matrix-org/dendrite/mediaapi/routing" 21 | "github.com/matrix-org/dendrite/mediaapi/storage" 22 | "github.com/matrix-org/dendrite/setup/config" 23 | userapi "github.com/matrix-org/dendrite/userapi/api" 24 | "github.com/matrix-org/gomatrixserverlib" 25 | "github.com/matrix-org/gomatrixserverlib/fclient" 26 | "github.com/sirupsen/logrus" 27 | ) 28 | 29 | // AddPublicRoutes sets up and registers HTTP handlers for the MediaAPI component. 30 | func AddPublicRoutes( 31 | routers httputil.Routers, 32 | cm *sqlutil.Connections, 33 | cfg *config.Dendrite, 34 | userAPI userapi.MediaUserAPI, 35 | client *fclient.Client, 36 | fedClient fclient.FederationClient, 37 | keyRing gomatrixserverlib.JSONVerifier, 38 | ) { 39 | mediaDB, err := storage.NewMediaAPIDatasource(cm, &cfg.MediaAPI.Database) 40 | if err != nil { 41 | logrus.WithError(err).Panicf("failed to connect to media db") 42 | } 43 | 44 | routing.Setup( 45 | routers, cfg, mediaDB, userAPI, client, fedClient, keyRing, 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /docs/installation/helm/1_helm.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | parent: Helm 4 | grand_parent: Installation 5 | has_toc: true 6 | nav_order: 1 7 | permalink: /installation/helm/install 8 | --- 9 | 10 | {% include deprecation.html %} 11 | 12 | # Installing Dendrite using Helm 13 | 14 | To install Dendrite using the Helm chart, you first have to add the repository using the following commands: 15 | 16 | ```bash 17 | helm repo add dendrite https://matrix-org.github.io/dendrite/ 18 | helm repo update 19 | ``` 20 | 21 | Next you'll need to create a `values.yaml` file and configure it to your liking. All possible values can be found 22 | [here](https://github.com/matrix-org/dendrite/blob/main/helm/dendrite/values.yaml), but at least you need to configure 23 | a `server_name`, otherwise the chart will complain about it: 24 | 25 | ```yaml 26 | dendrite_config: 27 | global: 28 | server_name: "localhost" 29 | ``` 30 | 31 | If you are going to use an existing Postgres database, you'll also need to configure this connection: 32 | 33 | ```yaml 34 | dendrite_config: 35 | global: 36 | database: 37 | connection_string: "postgresql://PostgresUser:PostgresPassword@PostgresHostName/DendriteDatabaseName" 38 | max_open_conns: 90 39 | max_idle_conns: 5 40 | conn_max_lifetime: -1 41 | ``` 42 | 43 | ## Installing with PostgreSQL 44 | 45 | The chart comes with a dependency on Postgres, which can be installed alongside Dendrite, this needs to be enabled in 46 | the `values.yaml`: 47 | 48 | ```yaml 49 | postgresql: 50 | enabled: true # this installs Postgres 51 | primary: 52 | persistence: 53 | size: 1Gi # defines the size for $PGDATA 54 | 55 | dendrite_config: 56 | global: 57 | server_name: "localhost" 58 | ``` 59 | 60 | Using this option, the `database.connection_string` will be set for you automatically. -------------------------------------------------------------------------------- /internal/log_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package internal 16 | 17 | import ( 18 | "github.com/matrix-org/dendrite/setup/config" 19 | "github.com/sirupsen/logrus" 20 | ) 21 | 22 | // SetupHookLogging configures the logging hooks defined in the configuration. 23 | // If something fails here it means that the logging was improperly configured, 24 | // so we just exit with the error 25 | func SetupHookLogging(hooks []config.LogrusHook) { 26 | logrus.SetReportCaller(true) 27 | for _, hook := range hooks { 28 | // Check we received a proper logging level 29 | level, err := logrus.ParseLevel(hook.Level) 30 | if err != nil { 31 | logrus.Fatalf("Unrecognised logging level %s: %q", hook.Level, err) 32 | } 33 | 34 | // Perform a first filter on the logs according to the lowest level of all 35 | // (Eg: If we have hook for info and above, prevent logrus from processing debug logs) 36 | if logrus.GetLevel() < level { 37 | logrus.SetLevel(level) 38 | } 39 | 40 | switch hook.Type { 41 | case "file": 42 | checkFileHookParams(hook.Params) 43 | setupFileHook(hook, level) 44 | default: 45 | logrus.Fatalf("Unrecognised logging hook type: %s", hook.Type) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /syncapi/storage/sqlite3/deltas/20201211125500_sequences.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package deltas 16 | 17 | import ( 18 | "context" 19 | "database/sql" 20 | "fmt" 21 | ) 22 | 23 | func UpFixSequences(ctx context.Context, tx *sql.Tx) error { 24 | _, err := tx.ExecContext(ctx, ` 25 | -- We need to delete all of the existing receipts because the indexes 26 | -- will be wrong, and we'll get primary key violations if we try to 27 | -- reuse existing stream IDs from a different sequence. 28 | DELETE FROM syncapi_receipts; 29 | UPDATE syncapi_stream_id SET stream_id=1 WHERE stream_name="receipt"; 30 | `) 31 | if err != nil { 32 | return fmt.Errorf("failed to execute upgrade: %w", err) 33 | } 34 | return nil 35 | } 36 | 37 | func DownFixSequences(ctx context.Context, tx *sql.Tx) error { 38 | _, err := tx.ExecContext(ctx, ` 39 | -- We need to delete all of the existing receipts because the indexes 40 | -- will be wrong, and we'll get primary key violations if we try to 41 | -- reuse existing stream IDs from a different sequence. 42 | DELETE FROM syncapi_receipts; 43 | `) 44 | if err != nil { 45 | return fmt.Errorf("failed to execute downgrade: %w", err) 46 | } 47 | return nil 48 | } 49 | -------------------------------------------------------------------------------- /mediaapi/storage/tables/interface.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package tables 16 | 17 | import ( 18 | "context" 19 | "database/sql" 20 | 21 | "github.com/matrix-org/dendrite/mediaapi/types" 22 | "github.com/matrix-org/gomatrixserverlib/spec" 23 | ) 24 | 25 | type Thumbnails interface { 26 | InsertThumbnail(ctx context.Context, txn *sql.Tx, thumbnailMetadata *types.ThumbnailMetadata) error 27 | SelectThumbnail( 28 | ctx context.Context, txn *sql.Tx, 29 | mediaID types.MediaID, mediaOrigin spec.ServerName, 30 | width, height int, 31 | resizeMethod string, 32 | ) (*types.ThumbnailMetadata, error) 33 | SelectThumbnails( 34 | ctx context.Context, txn *sql.Tx, mediaID types.MediaID, 35 | mediaOrigin spec.ServerName, 36 | ) ([]*types.ThumbnailMetadata, error) 37 | } 38 | 39 | type MediaRepository interface { 40 | InsertMedia(ctx context.Context, txn *sql.Tx, mediaMetadata *types.MediaMetadata) error 41 | SelectMedia(ctx context.Context, txn *sql.Tx, mediaID types.MediaID, mediaOrigin spec.ServerName) (*types.MediaMetadata, error) 42 | SelectMediaByHash( 43 | ctx context.Context, txn *sql.Tx, 44 | mediaHash types.Base64Hash, mediaOrigin spec.ServerName, 45 | ) (*types.MediaMetadata, error) 46 | } 47 | -------------------------------------------------------------------------------- /syncapi/streams/stream_sendtodevice.go: -------------------------------------------------------------------------------- 1 | package streams 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/matrix-org/dendrite/syncapi/storage" 7 | "github.com/matrix-org/dendrite/syncapi/types" 8 | ) 9 | 10 | type SendToDeviceStreamProvider struct { 11 | DefaultStreamProvider 12 | } 13 | 14 | func (p *SendToDeviceStreamProvider) Setup( 15 | ctx context.Context, snapshot storage.DatabaseTransaction, 16 | ) { 17 | p.DefaultStreamProvider.Setup(ctx, snapshot) 18 | 19 | p.latestMutex.Lock() 20 | defer p.latestMutex.Unlock() 21 | 22 | id, err := snapshot.MaxStreamPositionForSendToDeviceMessages(ctx) 23 | if err != nil { 24 | panic(err) 25 | } 26 | p.latest = id 27 | } 28 | 29 | func (p *SendToDeviceStreamProvider) CompleteSync( 30 | ctx context.Context, 31 | snapshot storage.DatabaseTransaction, 32 | req *types.SyncRequest, 33 | ) types.StreamPosition { 34 | return p.IncrementalSync(ctx, snapshot, req, 0, p.LatestPosition(ctx)) 35 | } 36 | 37 | func (p *SendToDeviceStreamProvider) IncrementalSync( 38 | ctx context.Context, 39 | snapshot storage.DatabaseTransaction, 40 | req *types.SyncRequest, 41 | from, to types.StreamPosition, 42 | ) types.StreamPosition { 43 | // See if we have any new tasks to do for the send-to-device messaging. 44 | lastPos, events, err := snapshot.SendToDeviceUpdatesForSync(req.Context, req.Device.UserID, req.Device.ID, from, to) 45 | if err != nil { 46 | req.Log.WithError(err).Error("p.DB.SendToDeviceUpdatesForSync failed") 47 | return from 48 | } 49 | 50 | // Add the updates into the sync response. 51 | for _, event := range events { 52 | // skip ignored user events 53 | if _, ok := req.IgnoredUsers.List[event.Sender]; ok { 54 | continue 55 | } 56 | req.Response.ToDevice.Events = append(req.Response.ToDevice.Events, event.SendToDeviceEvent) 57 | } 58 | 59 | return lastPos 60 | } 61 | -------------------------------------------------------------------------------- /internal/pushgateway/client.go: -------------------------------------------------------------------------------- 1 | package pushgateway 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "crypto/tls" 7 | "encoding/json" 8 | "fmt" 9 | "net/http" 10 | "time" 11 | 12 | "github.com/matrix-org/dendrite/internal" 13 | ) 14 | 15 | type httpClient struct { 16 | hc *http.Client 17 | } 18 | 19 | // NewHTTPClient creates a new Push Gateway client. 20 | func NewHTTPClient(disableTLSValidation bool) Client { 21 | hc := &http.Client{ 22 | Timeout: 30 * time.Second, 23 | Transport: &http.Transport{ 24 | DisableKeepAlives: true, 25 | TLSClientConfig: &tls.Config{ 26 | InsecureSkipVerify: disableTLSValidation, 27 | }, 28 | Proxy: http.ProxyFromEnvironment, 29 | }, 30 | } 31 | return &httpClient{hc: hc} 32 | } 33 | 34 | func (h *httpClient) Notify(ctx context.Context, url string, req *NotifyRequest, resp *NotifyResponse) error { 35 | trace, ctx := internal.StartRegion(ctx, "Notify") 36 | defer trace.EndRegion() 37 | 38 | body, err := json.Marshal(req) 39 | if err != nil { 40 | return err 41 | } 42 | hreq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body)) 43 | if err != nil { 44 | return err 45 | } 46 | hreq.Header.Set("Content-Type", "application/json") 47 | 48 | hresp, err := h.hc.Do(hreq) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | defer internal.CloseAndLogIfError(ctx, hresp.Body, "failed to close response body") 54 | 55 | if hresp.StatusCode == http.StatusOK { 56 | return json.NewDecoder(hresp.Body).Decode(resp) 57 | } 58 | 59 | var errorBody struct { 60 | Message string `json:"message"` 61 | } 62 | if err := json.NewDecoder(hresp.Body).Decode(&errorBody); err == nil { 63 | return fmt.Errorf("push gateway: %d from %s: %s", hresp.StatusCode, url, errorBody.Message) 64 | } 65 | return fmt.Errorf("push gateway: %d from %s", hresp.StatusCode, url) 66 | } 67 | -------------------------------------------------------------------------------- /roomserver/storage/postgres/deltas/20221027084407_published_appservice.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package deltas 16 | 17 | import ( 18 | "context" 19 | "database/sql" 20 | "fmt" 21 | ) 22 | 23 | func UpPulishedAppservice(ctx context.Context, tx *sql.Tx) error { 24 | _, err := tx.ExecContext(ctx, `ALTER TABLE roomserver_published ADD COLUMN IF NOT EXISTS appservice_id TEXT NOT NULL DEFAULT '';`) 25 | if err != nil { 26 | return fmt.Errorf("failed to execute upgrade: %w", err) 27 | } 28 | _, err = tx.ExecContext(ctx, `ALTER TABLE roomserver_published ADD COLUMN IF NOT EXISTS network_id TEXT NOT NULL DEFAULT '';`) 29 | if err != nil { 30 | return fmt.Errorf("failed to execute upgrade: %w", err) 31 | } 32 | return nil 33 | } 34 | 35 | func DownPublishedAppservice(ctx context.Context, tx *sql.Tx) error { 36 | _, err := tx.ExecContext(ctx, `ALTER TABLE roomserver_published DROP COLUMN IF EXISTS appservice_id;`) 37 | if err != nil { 38 | return fmt.Errorf("failed to execute downgrade: %w", err) 39 | } 40 | _, err = tx.ExecContext(ctx, `ALTER TABLE roomserver_published DROP COLUMN IF EXISTS network_id;`) 41 | if err != nil { 42 | return fmt.Errorf("failed to execute downgrade: %w", err) 43 | } 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /federationapi/consumers/roomserver_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Vector Creations Ltd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package consumers 16 | 17 | import ( 18 | "testing" 19 | ) 20 | 21 | func TestCombineNoOp(t *testing.T) { 22 | inputAdd1 := []string{"a", "b", "c"} 23 | inputDel1 := []string{"a", "b", "d"} 24 | inputAdd2 := []string{"a", "d", "e"} 25 | inputDel2 := []string{"a", "c", "e", "e"} 26 | 27 | gotAdd, gotDel := combineDeltas(inputAdd1, inputDel1, inputAdd2, inputDel2) 28 | 29 | if len(gotAdd) != 0 { 30 | t.Errorf("wanted combined adds to be an empty list, got %#v", gotAdd) 31 | } 32 | 33 | if len(gotDel) != 0 { 34 | t.Errorf("wanted combined removes to be an empty list, got %#v", gotDel) 35 | } 36 | } 37 | 38 | func TestCombineDedup(t *testing.T) { 39 | inputAdd1 := []string{"a", "a"} 40 | inputDel1 := []string{"b", "b"} 41 | inputAdd2 := []string{"a", "a"} 42 | inputDel2 := []string{"b", "b"} 43 | 44 | gotAdd, gotDel := combineDeltas(inputAdd1, inputDel1, inputAdd2, inputDel2) 45 | 46 | if len(gotAdd) != 1 || gotAdd[0] != "a" { 47 | t.Errorf("wanted combined adds to be %#v, got %#v", []string{"a"}, gotAdd) 48 | } 49 | 50 | if len(gotDel) != 1 || gotDel[0] != "b" { 51 | t.Errorf("wanted combined removes to be %#v, got %#v", []string{"b"}, gotDel) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /clientapi/routing/capabilities.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package routing 16 | 17 | import ( 18 | "net/http" 19 | 20 | roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" 21 | "github.com/matrix-org/dendrite/roomserver/version" 22 | "github.com/matrix-org/gomatrixserverlib" 23 | "github.com/matrix-org/util" 24 | ) 25 | 26 | // GetCapabilities returns information about the server's supported feature set 27 | // and other relevant capabilities to an authenticated user. 28 | func GetCapabilities(rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse { 29 | versionsMap := map[gomatrixserverlib.RoomVersion]string{} 30 | for v, desc := range version.SupportedRoomVersions() { 31 | if desc.Stable() { 32 | versionsMap[v] = "stable" 33 | } else { 34 | versionsMap[v] = "unstable" 35 | } 36 | } 37 | 38 | response := map[string]interface{}{ 39 | "capabilities": map[string]interface{}{ 40 | "m.change_password": map[string]bool{ 41 | "enabled": true, 42 | }, 43 | "m.room_versions": map[string]interface{}{ 44 | "default": rsAPI.DefaultRoomVersion(), 45 | "available": versionsMap, 46 | }, 47 | }, 48 | } 49 | 50 | return util.JSONResponse{ 51 | Code: http.StatusOK, 52 | JSON: response, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /setup/base/static/client/login/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Login 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |

15 | 16 | 17 | 18 |
19 | 20 |
21 | 22 | 29 | 30 | 41 | 42 | 45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /setup/config/config_userapi.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "golang.org/x/crypto/bcrypt" 4 | 5 | type UserAPI struct { 6 | Matrix *Global `yaml:"-"` 7 | 8 | // The cost when hashing passwords. 9 | BCryptCost int `yaml:"bcrypt_cost"` 10 | 11 | // The length of time an OpenID token is condidered valid in milliseconds 12 | OpenIDTokenLifetimeMS int64 `yaml:"openid_token_lifetime_ms"` 13 | 14 | // Disable TLS validation on HTTPS calls to push gatways. NOT RECOMMENDED! 15 | PushGatewayDisableTLSValidation bool `yaml:"push_gateway_disable_tls_validation"` 16 | 17 | // The Account database stores the login details and account information 18 | // for local users. It is accessed by the UserAPI. 19 | AccountDatabase DatabaseOptions `yaml:"account_database,omitempty"` 20 | 21 | // Users who register on this homeserver will automatically 22 | // be joined to the rooms listed under this option. 23 | AutoJoinRooms []string `yaml:"auto_join_rooms"` 24 | 25 | // The number of workers to start for the DeviceListUpdater. Defaults to 8. 26 | // This only needs updating if the "InputDeviceListUpdate" stream keeps growing indefinitely. 27 | WorkerCount int `yaml:"worker_count"` 28 | } 29 | 30 | const DefaultOpenIDTokenLifetimeMS = 3600000 // 60 minutes 31 | 32 | func (c *UserAPI) Defaults(opts DefaultOpts) { 33 | c.BCryptCost = bcrypt.DefaultCost 34 | c.OpenIDTokenLifetimeMS = DefaultOpenIDTokenLifetimeMS 35 | c.WorkerCount = 8 36 | if opts.Generate { 37 | if !opts.SingleDatabase { 38 | c.AccountDatabase.ConnectionString = "file:userapi_accounts.db" 39 | } 40 | } 41 | } 42 | 43 | func (c *UserAPI) Verify(configErrs *ConfigErrors) { 44 | checkPositive(configErrs, "user_api.openid_token_lifetime_ms", c.OpenIDTokenLifetimeMS) 45 | if c.Matrix.DatabaseOptions.ConnectionString == "" { 46 | checkNotEmpty(configErrs, "user_api.account_database.connection_string", string(c.AccountDatabase.ConnectionString)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /clientapi/routing/deactivate.go: -------------------------------------------------------------------------------- 1 | package routing 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | 7 | "github.com/matrix-org/dendrite/clientapi/auth" 8 | "github.com/matrix-org/dendrite/userapi/api" 9 | "github.com/matrix-org/gomatrixserverlib" 10 | "github.com/matrix-org/gomatrixserverlib/spec" 11 | "github.com/matrix-org/util" 12 | ) 13 | 14 | // Deactivate handles POST requests to /account/deactivate 15 | func Deactivate( 16 | req *http.Request, 17 | userInteractiveAuth *auth.UserInteractive, 18 | accountAPI api.ClientUserAPI, 19 | deviceAPI *api.Device, 20 | ) util.JSONResponse { 21 | ctx := req.Context() 22 | defer req.Body.Close() // nolint:errcheck 23 | bodyBytes, err := io.ReadAll(req.Body) 24 | if err != nil { 25 | return util.JSONResponse{ 26 | Code: http.StatusBadRequest, 27 | JSON: spec.BadJSON("The request body could not be read: " + err.Error()), 28 | } 29 | } 30 | 31 | login, errRes := userInteractiveAuth.Verify(ctx, bodyBytes, deviceAPI) 32 | if errRes != nil { 33 | return *errRes 34 | } 35 | 36 | localpart, serverName, err := gomatrixserverlib.SplitID('@', login.Username()) 37 | if err != nil { 38 | util.GetLogger(req.Context()).WithError(err).Error("gomatrixserverlib.SplitID failed") 39 | return util.JSONResponse{ 40 | Code: http.StatusInternalServerError, 41 | JSON: spec.InternalServerError{}, 42 | } 43 | } 44 | 45 | var res api.PerformAccountDeactivationResponse 46 | err = accountAPI.PerformAccountDeactivation(ctx, &api.PerformAccountDeactivationRequest{ 47 | Localpart: localpart, 48 | ServerName: serverName, 49 | }, &res) 50 | if err != nil { 51 | util.GetLogger(ctx).WithError(err).Error("userAPI.PerformAccountDeactivation failed") 52 | return util.JSONResponse{ 53 | Code: http.StatusInternalServerError, 54 | JSON: spec.InternalServerError{}, 55 | } 56 | } 57 | 58 | return util.JSONResponse{ 59 | Code: http.StatusOK, 60 | JSON: struct{}{}, 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /clientapi/auth/login_application_service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package auth 16 | 17 | import ( 18 | "context" 19 | 20 | "github.com/matrix-org/dendrite/clientapi/auth/authtypes" 21 | "github.com/matrix-org/dendrite/clientapi/httputil" 22 | "github.com/matrix-org/dendrite/internal" 23 | "github.com/matrix-org/dendrite/setup/config" 24 | "github.com/matrix-org/util" 25 | ) 26 | 27 | // LoginTypeApplicationService describes how to authenticate as an 28 | // application service 29 | type LoginTypeApplicationService struct { 30 | Config *config.ClientAPI 31 | Token string 32 | } 33 | 34 | // Name implements Type 35 | func (t *LoginTypeApplicationService) Name() string { 36 | return authtypes.LoginTypeApplicationService 37 | } 38 | 39 | // LoginFromJSON implements Type 40 | func (t *LoginTypeApplicationService) LoginFromJSON( 41 | ctx context.Context, reqBytes []byte, 42 | ) (*Login, LoginCleanupFunc, *util.JSONResponse) { 43 | var r Login 44 | if err := httputil.UnmarshalJSON(reqBytes, &r); err != nil { 45 | return nil, nil, err 46 | } 47 | 48 | _, err := internal.ValidateApplicationServiceRequest(t.Config, r.Identifier.User, t.Token) 49 | if err != nil { 50 | return nil, nil, err 51 | } 52 | 53 | cleanup := func(ctx context.Context, j *util.JSONResponse) {} 54 | return &r, cleanup, nil 55 | } 56 | -------------------------------------------------------------------------------- /clientapi/userutil/userutil.go: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0 (the "License"); 2 | // you may not use this file except in compliance with the License. 3 | // You may obtain a copy of the License at 4 | // 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | package userutil 14 | 15 | import ( 16 | "errors" 17 | "fmt" 18 | "strings" 19 | 20 | "github.com/matrix-org/dendrite/setup/config" 21 | "github.com/matrix-org/gomatrixserverlib" 22 | "github.com/matrix-org/gomatrixserverlib/spec" 23 | ) 24 | 25 | // ParseUsernameParam extracts localpart from usernameParam. 26 | // usernameParam can either be a user ID or just the localpart/username. 27 | // If serverName is passed, it is verified against the domain obtained from usernameParam (if present) 28 | // Returns error in case of invalid usernameParam. 29 | func ParseUsernameParam(usernameParam string, cfg *config.Global) (string, spec.ServerName, error) { 30 | localpart := usernameParam 31 | 32 | if strings.HasPrefix(usernameParam, "@") { 33 | lp, domain, err := gomatrixserverlib.SplitID('@', usernameParam) 34 | 35 | if err != nil { 36 | return "", "", errors.New("invalid username") 37 | } 38 | 39 | if !cfg.IsLocalServerName(domain) { 40 | return "", "", errors.New("user ID does not belong to this server") 41 | } 42 | 43 | return lp, domain, nil 44 | } 45 | return localpart, cfg.ServerName, nil 46 | } 47 | 48 | // MakeUserID generates user ID from localpart & server name 49 | func MakeUserID(localpart string, server spec.ServerName) string { 50 | return fmt.Sprintf("@%s:%s", localpart, string(server)) 51 | } 52 | -------------------------------------------------------------------------------- /internal/pushrules/condition.go: -------------------------------------------------------------------------------- 1 | package pushrules 2 | 3 | // A Condition dictates extra conditions for a matching rules. See 4 | // ConditionKind. 5 | type Condition struct { 6 | // Kind is the primary discriminator for the condition 7 | // type. Required. 8 | Kind ConditionKind `json:"kind"` 9 | 10 | // Key indicates the dot-separated path of Event fields to 11 | // match. Required for EventMatchCondition and 12 | // SenderNotificationPermissionCondition. 13 | Key string `json:"key,omitempty"` 14 | 15 | // Pattern indicates the value pattern that must match. Required 16 | // for EventMatchCondition. 17 | Pattern *string `json:"pattern,omitempty"` 18 | 19 | // Is indicates the condition that must be fulfilled. Required for 20 | // RoomMemberCountCondition. 21 | Is string `json:"is,omitempty"` 22 | } 23 | 24 | // ConditionKind represents a kind of condition. 25 | // 26 | // SPEC: Unrecognised conditions MUST NOT match any events, 27 | // effectively making the push rule disabled. 28 | type ConditionKind string 29 | 30 | const ( 31 | UnknownCondition ConditionKind = "" 32 | 33 | // EventMatchCondition indicates the condition looks for a key 34 | // path and matches a pattern. How paths that don't reference a 35 | // simple value match against rules is implementation-specific. 36 | EventMatchCondition ConditionKind = "event_match" 37 | 38 | // ContainsDisplayNameCondition indicates the current user's 39 | // display name must be found in the content body. 40 | ContainsDisplayNameCondition ConditionKind = "contains_display_name" 41 | 42 | // RoomMemberCountCondition matches a simple arithmetic comparison 43 | // against the total number of members in a room. 44 | RoomMemberCountCondition ConditionKind = "room_member_count" 45 | 46 | // SenderNotificationPermissionCondition compares power level for 47 | // the sender in the event's room. 48 | SenderNotificationPermissionCondition ConditionKind = "sender_notification_permission" 49 | ) 50 | -------------------------------------------------------------------------------- /userapi/storage/postgres/deltas/2022042612000000_xsigning_idx.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Matrix.org Foundation C.I.C. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package deltas 16 | 17 | import ( 18 | "context" 19 | "database/sql" 20 | "fmt" 21 | ) 22 | 23 | func UpFixCrossSigningSignatureIndexes(ctx context.Context, tx *sql.Tx) error { 24 | _, err := tx.ExecContext(ctx, ` 25 | ALTER TABLE keyserver_cross_signing_sigs DROP CONSTRAINT keyserver_cross_signing_sigs_pkey; 26 | ALTER TABLE keyserver_cross_signing_sigs ADD PRIMARY KEY (origin_user_id, origin_key_id, target_user_id, target_key_id); 27 | 28 | CREATE INDEX IF NOT EXISTS keyserver_cross_signing_sigs_idx ON keyserver_cross_signing_sigs (origin_user_id, target_user_id, target_key_id); 29 | `) 30 | if err != nil { 31 | return fmt.Errorf("failed to execute upgrade: %w", err) 32 | } 33 | return nil 34 | } 35 | 36 | func DownFixCrossSigningSignatureIndexes(ctx context.Context, tx *sql.Tx) error { 37 | _, err := tx.ExecContext(ctx, ` 38 | ALTER TABLE keyserver_cross_signing_sigs DROP CONSTRAINT keyserver_cross_signing_sigs_pkey; 39 | ALTER TABLE keyserver_cross_signing_sigs ADD PRIMARY KEY (origin_user_id, target_user_id, target_key_id); 40 | 41 | DROP INDEX IF EXISTS keyserver_cross_signing_sigs_idx; 42 | `) 43 | if err != nil { 44 | return fmt.Errorf("failed to execute downgrade: %w", err) 45 | } 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /setup/process/process.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "context" 5 | "sync" 6 | 7 | "github.com/getsentry/sentry-go" 8 | "github.com/sirupsen/logrus" 9 | ) 10 | 11 | type ProcessContext struct { 12 | mu sync.RWMutex 13 | wg sync.WaitGroup // used to wait for components to shutdown 14 | ctx context.Context // cancelled when Stop is called 15 | shutdown context.CancelFunc // shut down Dendrite 16 | degraded map[string]struct{} // reasons why the process is degraded 17 | } 18 | 19 | func NewProcessContext() *ProcessContext { 20 | ctx, shutdown := context.WithCancel(context.Background()) 21 | return &ProcessContext{ 22 | ctx: ctx, 23 | shutdown: shutdown, 24 | wg: sync.WaitGroup{}, 25 | } 26 | } 27 | 28 | func (b *ProcessContext) Context() context.Context { 29 | return context.WithValue(b.ctx, "scope", "process") // nolint:staticcheck 30 | } 31 | 32 | func (b *ProcessContext) ComponentStarted() { 33 | b.wg.Add(1) 34 | } 35 | 36 | func (b *ProcessContext) ComponentFinished() { 37 | b.wg.Done() 38 | } 39 | 40 | func (b *ProcessContext) ShutdownDendrite() { 41 | b.shutdown() 42 | } 43 | 44 | func (b *ProcessContext) WaitForShutdown() <-chan struct{} { 45 | return b.ctx.Done() 46 | } 47 | 48 | func (b *ProcessContext) WaitForComponentsToFinish() { 49 | b.wg.Wait() 50 | } 51 | 52 | func (b *ProcessContext) Degraded(err error) { 53 | b.mu.Lock() 54 | defer b.mu.Unlock() 55 | if _, ok := b.degraded[err.Error()]; !ok { 56 | logrus.WithError(err).Warn("Dendrite has entered a degraded state") 57 | sentry.CaptureException(err) 58 | b.degraded[err.Error()] = struct{}{} 59 | } 60 | } 61 | 62 | func (b *ProcessContext) IsDegraded() (bool, []string) { 63 | b.mu.RLock() 64 | defer b.mu.RUnlock() 65 | if len(b.degraded) == 0 { 66 | return false, nil 67 | } 68 | reasons := make([]string, 0, len(b.degraded)) 69 | for reason := range b.degraded { 70 | reasons = append(reasons, reason) 71 | } 72 | return true, reasons 73 | } 74 | -------------------------------------------------------------------------------- /roomserver/storage/shared/prepare.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2018 New Vector Ltd 2 | // Copyright 2019-2020 The Matrix.org Foundation C.I.C. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package shared 17 | 18 | import ( 19 | "context" 20 | "database/sql" 21 | ) 22 | 23 | // StatementList is a list of SQL statements to prepare and a pointer to where to store the resulting prepared statement. 24 | type StatementList []struct { 25 | Statement **sql.Stmt 26 | SQL string 27 | } 28 | 29 | // Prepare the SQL for each statement in the list and assign the result to the prepared statement. 30 | func (s StatementList) Prepare(db *sql.DB) (err error) { 31 | for _, statement := range s { 32 | if *statement.Statement, err = db.Prepare(statement.SQL); err != nil { 33 | return 34 | } 35 | } 36 | return 37 | } 38 | 39 | type transaction struct { 40 | ctx context.Context 41 | txn *sql.Tx 42 | } 43 | 44 | // Commit implements types.Transaction 45 | func (t *transaction) Commit() error { 46 | if t.txn == nil { 47 | // The Updater structs can operate in useTxns=false mode. The code will still call this though. 48 | return nil 49 | } 50 | return t.txn.Commit() 51 | } 52 | 53 | // Rollback implements types.Transaction 54 | func (t *transaction) Rollback() error { 55 | if t.txn == nil { 56 | // The Updater structs can operate in useTxns=false mode. The code will still call this though. 57 | return nil 58 | } 59 | return t.txn.Rollback() 60 | } 61 | -------------------------------------------------------------------------------- /test/wasm/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /* 4 | Copyright 2021 The Matrix.org Foundation C.I.C. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | const fs = require('fs'); 20 | const path = require('path'); 21 | const childProcess = require('child_process'); 22 | 23 | (async function() { 24 | // sql.js 25 | const initSqlJs = require('sql.js'); 26 | await initSqlJs().then(SQL => { 27 | global._go_sqlite = SQL; 28 | console.log("Loaded sqlite") 29 | }); 30 | // dendritejs expects to write to `/idb` so we create that here 31 | // Since this is testing only, we use the default in-memory FS 32 | global._go_sqlite.FS.mkdir("/idb"); 33 | 34 | // WebSocket 35 | const WebSocket = require('isomorphic-ws'); 36 | global.WebSocket = WebSocket; 37 | 38 | // Load the generic Go Wasm exec helper inline to trigger built-in run call 39 | // This approach avoids copying `wasm_exec.js` into the repo, which is nice 40 | // to aim for since it can differ between Go versions. 41 | const goRoot = await new Promise((resolve, reject) => { 42 | childProcess.execFile('go', ['env', 'GOROOT'], (err, out) => { 43 | if (err) { 44 | reject("Can't find go"); 45 | } 46 | resolve(out.trim()); 47 | }); 48 | }); 49 | const execPath = path.join(goRoot, 'misc/wasm/wasm_exec.js'); 50 | const execCode = fs.readFileSync(execPath, 'utf8'); 51 | eval(execCode); 52 | })(); 53 | -------------------------------------------------------------------------------- /clientapi/routing/server_notices_test.go: -------------------------------------------------------------------------------- 1 | package routing 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test_sendServerNoticeRequest_validate(t *testing.T) { 8 | type fields struct { 9 | UserID string `json:"user_id,omitempty"` 10 | Content struct { 11 | MsgType string `json:"msgtype,omitempty"` 12 | Body string `json:"body,omitempty"` 13 | } `json:"content,omitempty"` 14 | Type string `json:"type,omitempty"` 15 | StateKey string `json:"state_key,omitempty"` 16 | } 17 | 18 | content := struct { 19 | MsgType string `json:"msgtype,omitempty"` 20 | Body string `json:"body,omitempty"` 21 | }{ 22 | MsgType: "m.text", 23 | Body: "Hello world!", 24 | } 25 | 26 | tests := []struct { 27 | name string 28 | fields fields 29 | wantOk bool 30 | }{ 31 | { 32 | name: "empty request", 33 | fields: fields{}, 34 | }, 35 | { 36 | name: "msgtype empty", 37 | fields: fields{ 38 | UserID: "@alice:localhost", 39 | Content: struct { 40 | MsgType string `json:"msgtype,omitempty"` 41 | Body string `json:"body,omitempty"` 42 | }{ 43 | Body: "Hello world!", 44 | }, 45 | }, 46 | }, 47 | { 48 | name: "msg body empty", 49 | fields: fields{ 50 | UserID: "@alice:localhost", 51 | }, 52 | }, 53 | { 54 | name: "statekey empty", 55 | fields: fields{ 56 | UserID: "@alice:localhost", 57 | Content: content, 58 | }, 59 | wantOk: true, 60 | }, 61 | { 62 | name: "type empty", 63 | fields: fields{ 64 | UserID: "@alice:localhost", 65 | Content: content, 66 | }, 67 | wantOk: true, 68 | }, 69 | } 70 | for _, tt := range tests { 71 | t.Run(tt.name, func(t *testing.T) { 72 | r := sendServerNoticeRequest{ 73 | UserID: tt.fields.UserID, 74 | Content: tt.fields.Content, 75 | Type: tt.fields.Type, 76 | StateKey: tt.fields.StateKey, 77 | } 78 | if gotOk := r.valid(); gotOk != tt.wantOk { 79 | t.Errorf("valid() = %v, want %v", gotOk, tt.wantOk) 80 | } 81 | }) 82 | } 83 | } 84 | --------------------------------------------------------------------------------