├── static ├── .nojekyll └── img │ ├── logo.png │ ├── favicon.ico │ ├── logo.png.license │ └── favicon.ico.license ├── .gitattributes ├── docs ├── matrix-protection-suite │ ├── concepts │ │ ├── _category_.json │ │ ├── revisions.md │ │ ├── protection.md │ │ └── protected-rooms-set.md │ └── _category_.json ├── bot │ ├── _category_.json │ ├── setup_selfbuild.md │ ├── encryption.md │ ├── setup_management_room.md │ ├── systemd.md │ ├── setup.md │ ├── starting_draupnir.md │ ├── setup_docker.md │ ├── synapse-http-antispam.md │ ├── synapse_module.md │ ├── homeserver-administration.md │ ├── setup_debian.md │ └── setup_draupnir_account.md ├── governance │ ├── _category_.json │ ├── reports │ │ ├── _category_.json │ │ ├── 0000A-selection.md │ │ ├── 0000A-cycle-review-template.md │ │ ├── 2510A-cycle-review.md │ │ └── 2510A-selection.md │ ├── longhouse-consultation.md │ ├── inspiration.md │ ├── longhouse-presentation.md │ ├── governance.md │ ├── groups.md │ ├── longhouse-cycle.md │ └── ethical-values.md ├── contributing │ ├── _category_.json │ ├── long-term-workflow.md │ ├── development.md │ ├── releasing-draupnir.md │ ├── accessibility.md │ ├── triaging.md │ ├── draupnir-news.md │ ├── code-style.md │ ├── security.md │ ├── context.md │ ├── development-environment.md │ └── CONTRIBUTING.md ├── appservice │ ├── _category_.json │ └── appservice.md ├── concepts │ ├── _category_.json │ ├── management-room.md │ ├── policy-lists.md │ ├── encryption.md │ ├── room-essentials.md │ └── power-levels.md ├── moderator │ ├── _category_.json │ ├── setting-up-and-configuring.md │ ├── managing-policy-lists.md │ ├── room-upgrades.md │ ├── managing-users.md │ └── managing-protected-rooms.md ├── protections │ ├── _category_.json │ ├── homeserver-user-policy-protection.md │ ├── protections.md │ ├── block-invitations-on-server-protection.md │ ├── new-joiner-protection.md │ ├── mention-limit-protection.md │ ├── trusted-reporters.md │ ├── room-takedown-protection.md │ └── configuring-protections.md ├── shared │ ├── _category_.json │ └── dogfood.md └── intro.md ├── babel.config.js ├── tsconfig.json ├── .github ├── renovate.json5 └── workflows │ ├── test-deploy.yml │ ├── deploy.yml │ └── sign-off.yml ├── src ├── components │ └── HomepageFeatures │ │ ├── styles.module.css │ │ └── index.tsx └── css │ └── custom.css ├── .gitignore ├── .cspell.json ├── .editorconfig ├── .cspell-allowed-words ├── sidebars.ts ├── .pre-commit-config.yaml ├── README.md ├── package.json └── docusaurus.config.ts /static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.gif filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /docs/matrix-protection-suite/concepts/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Concepts" 3 | } 4 | -------------------------------------------------------------------------------- /docs/matrix-protection-suite/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Matrix Protection Suite" 3 | } 4 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-draupnir-project/draupnir-documentation/main/static/img/logo.png -------------------------------------------------------------------------------- /static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-draupnir-project/draupnir-documentation/main/static/img/favicon.ico -------------------------------------------------------------------------------- /docs/bot/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Bot Mode", 3 | "position": 1, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Bot mode specific Documentation" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/governance/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Governance", 3 | "position": 4, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Governance documentation" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/contributing/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Contributing", 3 | "position": 4, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Contributor Documentation" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/appservice/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Appservice", 3 | "position": 2, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Appservice Mode Specific Documentation" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/concepts/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Concepts", 3 | "position": 2.5, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Draupnir & Matrix Concepts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@docusaurus/tsconfig", 4 | "compilerOptions": { 5 | "baseUrl": "." 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docs/moderator/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Moderator's Guide", 3 | "position": 2.5, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Moderator Documentation" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Aminda Suomalainen 2 | // 3 | // SPDX-License-Identifier: CC0-1.0 4 | { 5 | extends: ["github>the-draupnir-project/.github:renovate-shared"], 6 | } 7 | -------------------------------------------------------------------------------- /src/components/HomepageFeatures/styles.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | } 7 | 8 | .featureSvg { 9 | height: 200px; 10 | width: 200px; 11 | } 12 | -------------------------------------------------------------------------------- /static/img/logo.png.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2024 Mysha 2 | 3 | SPDX-License-Identifier: CC-BY-SA-4.0 4 | 5 | SPDX-FileAttributionText: 6 | https://www.furaffinity.net/user/bonnietappert/ 7 | 8 | -------------------------------------------------------------------------------- /static/img/favicon.ico.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2024 Mysha 2 | 3 | SPDX-License-Identifier: CC-BY-SA-4.0 4 | 5 | SPDX-FileAttributionText: 6 | https://www.furaffinity.net/user/bonnietappert/ 7 | 8 | -------------------------------------------------------------------------------- /docs/protections/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Protections", 3 | "position": 2.7, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Documentation for individual protections offered by Draupnir" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/shared/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Shared Documentation", 3 | "position": 3, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Documentation that is shared between both Bot mode and Application Service Mode" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/governance/reports/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Reports", 3 | "collapsed": true, 4 | "link": { 5 | "type": "generated-index", 6 | "title": "Reports", 7 | "description": "Reports from the longhouse process and root contribution circle." 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | # Emacs 23 | *~ 24 | 25 | # They are generated by Docusaurus 26 | /docs/api 27 | -------------------------------------------------------------------------------- /docs/protections/homeserver-user-policy-protection.md: -------------------------------------------------------------------------------- 1 | # Homeserver User Policy Protection 2 | 3 | :::info 4 | 5 | You need to be using Draupnir v2.3.0 or above to use this protection. 6 | 7 | This protection SHOULD be enabled if you have public registration. 8 | 9 | ::: 10 | 11 | This is a protection to automatically suspend resident users that match policies 12 | from watched lists, and prompt to optionally deactivate them if appropriate. 13 | -------------------------------------------------------------------------------- /.cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", 4 | "version": "0.2", 5 | "language": "en_GB", 6 | "words": ["add", "to", ".cspell-allowed-words", "instead"], 7 | "flagWords": ["flaggedword", "hte"], 8 | "dictionaries": ["cspell-allowed-words"], 9 | 10 | "dictionaryDefinitions": [ 11 | { 12 | "name": "cspell-allowed-words", 13 | "path": "./.cspell-allowed-words", 14 | "addWords": true 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{ts, tsx, js, jsx}] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*{.md}] 12 | end_of_line = lf 13 | trim_trailing_whitespace = true 14 | insert_final_newline = true 15 | charset = utf-8 16 | indent_style = space 17 | indent_size = 4 18 | 19 | [{LICENSE,NOTICE,*.{yml,yaml,json}}] 20 | trim_trailing_whitespace = false 21 | indent_style = space 22 | indent_size = unset 23 | -------------------------------------------------------------------------------- /docs/concepts/management-room.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | sidebar_label: Management room 4 | --- 5 | 6 | 11 | 12 | # Management room 13 | 14 | The management room is where you will interact with Draupnir. This is 15 | the room where Draupnir will respond to commands, allowing you to 16 | coordinate with Draupnir and other moderators without disrupting your 17 | public Matrix rooms. 18 | 19 | The management room should not be public, as anyone present in this 20 | room can perform any action supported by the bot. 21 | -------------------------------------------------------------------------------- /.cspell-allowed-words: -------------------------------------------------------------------------------- 1 | aminda 2 | appservice 3 | appservices 4 | datadirectory 5 | deanonymisation 6 | deanonymise 7 | displayname 8 | dockerised 9 | dogfooded 10 | draupnir 11 | draupnir's 12 | draupnirs 13 | filepermissions 14 | gnuxie 15 | homeserver 16 | homeservers 17 | honor 18 | honoring 19 | introspected 20 | joinable 21 | journalctl 22 | mjolnir 23 | mxid 24 | mxids 25 | neko 26 | nodesource 27 | nord 28 | localpart 29 | pantalaimon 30 | powerlevel 31 | precalculated 32 | preemptively 33 | preminor 34 | ralston 35 | roomid 36 | rustup 37 | seibel's 38 | spammy 39 | sublicensable 40 | takedown 41 | trusteduser 42 | unbannable 43 | useraccount 44 | -------------------------------------------------------------------------------- /sidebars.ts: -------------------------------------------------------------------------------- 1 | import type { SidebarsConfig } from '@docusaurus/plugin-content-docs'; 2 | import apisidebar from './docs/api/sidebar'; 3 | 4 | /** 5 | * This is generated by the docusaurus template that we chose from. 6 | */ 7 | const sidebars: SidebarsConfig = { 8 | // By default, Docusaurus generates a sidebar from the docs folder structure 9 | mainSidebar: [ 10 | { type: 'autogenerated', dirName: '.' }, 11 | { 12 | type: 'category', 13 | label: 'API Specification', 14 | items: apisidebar, 15 | link: { 16 | type: 'doc', 17 | id: 'api/draupnir-api', 18 | } 19 | }, 20 | ], 21 | 22 | }; 23 | 24 | export default sidebars; 25 | -------------------------------------------------------------------------------- /.github/workflows/test-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Test deployment 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | # Review gh actions docs if you want to further define triggers, paths, etc 8 | # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on 9 | 10 | jobs: 11 | test-deploy: 12 | name: Test deployment 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | - uses: actions/setup-node@v4 19 | with: 20 | node-version: 20 21 | cache: yarn 22 | 23 | - name: Install dependencies 24 | run: yarn install --frozen-lockfile 25 | - name: Test build website 26 | run: yarn build 27 | -------------------------------------------------------------------------------- /docs/contributing/long-term-workflow.md: -------------------------------------------------------------------------------- 1 | # Long term workflow 2 | 3 | :::info 4 | 5 | For an overview of planning, please see [planning](./planning.md). 6 | 7 | ::: 8 | 9 | In order to devise long term plans, the-draupnir-project uses a planning system. 10 | 11 | ## Where can I find Draupnir's plans? 12 | 13 | Draupnir's plans are kept within the 14 | [planning issue tracker](https://github.com/the-draupnir-project/planning/issues). 15 | This is a separate github repository that holds Draupnir's plans. 16 | 17 | ## Finding issues which may need planning 18 | 19 | Once issues have been [triaged](./triaging), it is possible to view a list of 20 | issues that are the most painful to the project in this 21 | [project view](https://github.com/orgs/the-draupnir-project/projects/5/views/8). 22 | -------------------------------------------------------------------------------- /docs/governance/longhouse-consultation.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | --- 4 | 5 | # Longhouse consultation 6 | 7 | The _longhouse assembly_ may consult the _contribution guild_ with a request to 8 | fix a specific bug or implement a feature at any time. 9 | 10 | Consultations may take place within 11 | [Draupnir - Contribution Guild Consultation](https://matrix.to/#/!HMEUBVghQjScFABjfW:matrix.org/%24k7hteExVxh5ve-LZd0VsU7efWqKriW21k3dokC_Nsdw?via=matrix.org&via=asgard.chat). 12 | 13 | They must follow the template: 14 | 15 | ``` 16 | #### Request 17 | 18 | I would like the feature from issue #123 to be considered. 19 | 20 | #### Why 21 | 22 | Our moderation team is struggling without this feature at the moment. 23 | ``` 24 | 25 | These consultations may still happen informally and jump directly to the 26 | presentation step if a contributor has agreed. 27 | -------------------------------------------------------------------------------- /docs/contributing/development.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Developing Draupnir 6 | 7 | This document is a part of our [contributing documentation](./CONTRIBUTING.md), 8 | which you should take a read of if you didn't already. 9 | 10 | Draupnir is a TypeScript project that depends on the labour of a 11 | handful of developers, testers and users. The code base is in relatively 12 | good shape, and if you would like to contribute or gain an understanding 13 | of the workings of Draupnir, then please read our [context document](./context.md). 14 | 15 | Then you should read our tests, tools and environment [document](./development-environment.md). 16 | As it goes into some details about how to setup your environment 17 | and debug code. 18 | 19 | Once you are happy to start writing code, you should glance at our 20 | [code style document](./code-style.md). 21 | -------------------------------------------------------------------------------- /docs/moderator/setting-up-and-configuring.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 0 3 | sidebar_label: Configuring your Draupnir 4 | --- 5 | 6 | 11 | 12 | # Quick start 13 | 14 | When you first get your Draupnir there are a few steps you should take 15 | so that your community is protected. Along the way, if you struggle at 16 | any point you can find reference documentation for each command by 17 | using `!draupnir help`. 18 | 19 | 1. [Managing protected rooms](./managing-protected-rooms.md) - 20 | choosing which rooms to be protected by Draupnir. 21 | 2. [Managing policy lists](./managing-policy-lists.md) - how to create 22 | or watch lists created by other communities. 23 | 3. [Managing users](./managing-users.md) - How to ban, remove and 24 | manage the power level of users. 25 | 4. [Managing protections](../protections) - Modules 26 | that offer extra functionality. 27 | -------------------------------------------------------------------------------- /docs/governance/inspiration.md: -------------------------------------------------------------------------------- 1 | # Governance inspiration and resources 2 | 3 | Here are some of the resources that we used or inspired us to create this 4 | governance system. If you are trying to create something similar, don't fret, it 5 | takes time and you need to think about it for awhile. 6 | 7 | - The Death of Consequences - Christopher Neugebauer 8 | https://2025.pycon.org.au/program/7XVERX/. 9 | 10 | - Dawn Foster's introductory governance blog series: 11 | https://fastwonderblog.com/2025/07/29/governance-part-1-why-is-it-important/ 12 | 13 | - The Open Source Collective's Guides are invaluable and pragmatic 14 | https://docs.oscollective.org/resources. 15 | 16 | - This blogpost by [Sumana Harihareswara](https://www.harihareswara.net/) has a 17 | wealth of resources 18 | https://www.harihareswara.net/posts/2023/maintainer-burnout-pycon-us-2023-followup/#succession-new-folks. 19 | 20 | - Stealing ideas from https://www.cncf.io/ (note: this is corporatist 21 | governance). 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/governance/longhouse-presentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Longhouse presentation 6 | 7 | Longhouse proposals and presentations will be announced in the 8 | [longhouse assembly announcements](https://matrix.to/#/!DtwZFWORUIApKsOVWi:matrix.org?via=matrix.org&via=asgard.chat) 9 | room and conducted in the 10 | [longhouse assembly discussion room](https://matrix.to/#/!UMROhYUQcvtGuoIIka:matrix.org?via=matrix.org&via=asgard.chat) 11 | 12 | ## Longhouse proposal 13 | 14 | A _longhouse proposal_ is an individual vote or affirmation about a possible 15 | contribution or contribution pathway. 16 | 17 | ## Longhouse cycle presentation 18 | 19 | The Longhouse cycle presentation starts with an evaluation by the _contributors 20 | guild_ of the direction of the draupnir project and any progress made in the 21 | current cycle, including an estimation of when work from the current cycle will 22 | be finished. 23 | 24 | Then individual proposals relevant to the session will be sent seeking for the 25 | _longhouse assembly_ to voice opinion on each individual proposal. 26 | -------------------------------------------------------------------------------- /docs/bot/setup_selfbuild.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 7 3 | sidebar_label: Advanced setup from source 4 | --- 5 | 6 | # Advanced setup from source 7 | 8 | :::tip 9 | 10 | This guide is for experienced system administrators. 11 | The recommended installation method is [using Docker with systemd](./systemd). 12 | 13 | ::: 14 | 15 | :::info 16 | 17 | This guide is meant to be read in conjunction with [Draupnir parameters and options](./starting_draupnir). 18 | 19 | ::: 20 | 21 | These instructions are to build and run draupnir without using [Docker](./setup_docker.md). 22 | You need to have installed `yarn` 1.x and Node 20. 23 | 24 | ```bash 25 | git clone https://github.com/the-draupnir-project/Draupnir.git 26 | cd draupnir 27 | git fetch --tags 28 | 29 | yarn install 30 | yarn build 31 | 32 | # Copy and edit the config. It *is* recommended to change the data path, 33 | # as this is set to `/data` by default for dockerised draupnir. 34 | cp config/default.yaml config/production.yaml 35 | nano config/production.yaml 36 | 37 | node lib/index.js --draupnir-config ./config/production.yaml 38 | ``` 39 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | # See https://pre-commit.ci for more information 4 | ci: 5 | autoupdate_schedule: weekly 6 | repos: 7 | - repo: https://github.com/pre-commit/pre-commit-hooks 8 | rev: v5.0.0 9 | hooks: 10 | - id: trailing-whitespace 11 | args: ["--markdown-linebreak-ext", "md"] 12 | exclude_types: [svg] 13 | - id: end-of-file-fixer 14 | - id: check-yaml 15 | - id: check-added-large-files 16 | - repo: https://github.com/editorconfig-checker/editorconfig-checker.python 17 | rev: "3.2.1" 18 | hooks: 19 | - id: editorconfig-checker 20 | alias: ec 21 | - repo: https://github.com/streetsidesoftware/cspell-cli 22 | rev: v9.0.1 23 | hooks: 24 | - id: cspell # Spell check changed files 25 | types: ["markdown"] 26 | args: 27 | - "--no-progress" 28 | - "--show-suggestions" 29 | - "--show-context" 30 | - "--no-summary" 31 | - "--config" 32 | - ".cspell.json" 33 | -------------------------------------------------------------------------------- /docs/protections/protections.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 0 3 | sidebar_label: Protections overview 4 | --- 5 | 6 | 11 | 12 | :::tip 13 | 14 | This is an overview of Draupnir protections, for a more in-depth (but 15 | still friendly) explanation, please view [this 16 | page](./matrix-protection-suite/concepts/protection). 17 | 18 | ::: 19 | 20 | # Protections 21 | 22 | Protections are plugins or individual modules that work with 23 | Draupnir's protected rooms and the management room. 24 | 25 | You can find a list of available protections by using the 26 | `!draupnir protections` command. 27 | 28 | Please also see the sidebar, or the [protections 29 | category](https://the-draupnir-project.github.io/draupnir-documentation/category/protections), 30 | in this documentation site to see the list of protections that have a 31 | dedicated documentation page. 32 | 33 | Several protections are enabled by default, as almost all of 34 | Draupnir's core functionality is implemented using the protection 35 | system. 36 | -------------------------------------------------------------------------------- /docs/governance/reports/0000A-selection.md: -------------------------------------------------------------------------------- 1 | # 202X-XX-A-Selection: Selection 2 | 3 | _The purpose of selection is to affirm contributors for the work they have done 4 | or are doing._ 5 | 6 | ## Context 7 | 8 | _A link to the current or previous cycle review or an evaluation of the 9 | direction (including any findings or challenges relevant to the need for 10 | selection) if one cannot be made._ 11 | 12 | ## Options 13 | 14 | _A list of options should be presented here. Options should always include a 15 | "none of the above" to signal no or low confidence in the options._ 16 | 17 | ## Discounted options 18 | 19 | _Options that didn't make the selection, but are relevant to current context or 20 | development. And explanation should be provided about why the options are not 21 | going to be incremented at this time_. 22 | 23 | ## Feedback and discussion 24 | 25 | _Any important points that were raised during the discussion of the options that 26 | should be noted_. 27 | 28 | ## Outcome 29 | 30 | _A statement from the contribution guild on the outcome of the vote and any 31 | remarks. This is an opportunity to reaffirm the direction of the project._ 32 | -------------------------------------------------------------------------------- /src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #2e8555; 10 | --ifm-color-primary-dark: #29784c; 11 | --ifm-color-primary-darker: #277148; 12 | --ifm-color-primary-darkest: #205d3b; 13 | --ifm-color-primary-light: #33925d; 14 | --ifm-color-primary-lighter: #359962; 15 | --ifm-color-primary-lightest: #3cad6e; 16 | --ifm-code-font-size: 95%; 17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 18 | } 19 | 20 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 21 | [data-theme='dark'] { 22 | --ifm-color-primary: #25c2a0; 23 | --ifm-color-primary-dark: #21af90; 24 | --ifm-color-primary-darker: #1fa588; 25 | --ifm-color-primary-darkest: #1a8870; 26 | --ifm-color-primary-light: #29d5b0; 27 | --ifm-color-primary-lighter: #32d8b4; 28 | --ifm-color-primary-lightest: #4fddbf; 29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); 30 | } 31 | -------------------------------------------------------------------------------- /docs/contributing/releasing-draupnir.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: Releasing Draupnir 3 | --- 4 | 5 | 6 | 7 | # Releasing Draupnir 8 | 9 | To produce a release, checkout main. 10 | 11 | Update `CHANGELOG.md`, usually this is done by reading the commits, and checking 12 | closed issues. And taking the time to acknowledge all contributors. Including 13 | those from the support room. 14 | 15 | Once this is done, stage the changelog in git. 16 | 17 | Use `yarn version --minor` (or `--major` or `--patch`) to create a tagged commit 18 | and change all the numbers. This was also automatically include the staged 19 | changelog. 20 | 21 | To create a beta release use `yarn version --preminor --preid beta`. 22 | 23 | Now push the commit to GitHub with `git push --atomic origin main v2.3.0` 24 | 25 | Go to the releases section on GitHub and copy in the CHANGELOG. Make sure to 26 | check beta releases as a pre-release and do not set them to be the latest 27 | release. 28 | 29 | Publishing a release causes the docker images do be built. 30 | 31 | You can wait for those GitHub actions to complete before announcing the release 32 | in other channels such as TWIM. 33 | -------------------------------------------------------------------------------- /docs/governance/governance.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Governance 6 | 7 | Governance is essential to any project that has responsibilities and obligations 8 | to other parties. While the open source software movement have relied on 9 | licenses alone to organise their projects. This is only really suitable for 10 | projects that exist as libraries where the consumers are primarily developers. 11 | Draupnir is a project that has no direct business that can sustain the project. 12 | Draupnir therefore needs a formal governance system. Please also see the project 13 | [vision](../contributing/vision.md), and the project's 14 | [ethical values](./ethical-values.md). 15 | 16 | ## The Draupnir Longhouse 17 | 18 | Draupnir's long term decisions are made through a process called the _Draupnir 19 | longhouse_. This process is cyclic and happens in _sessions_. There are five 20 | stages to each session, and all of the interaction is lightweight and 21 | asynchronous. 22 | 23 | Short term decisions can also be made through the longhouse, but these happen 24 | outside of the cycle. For example, irregular contributors may wish to present to 25 | the longhouse assembly for affirmation. 26 | -------------------------------------------------------------------------------- /docs/governance/reports/0000A-cycle-review-template.md: -------------------------------------------------------------------------------- 1 | # 202X-XX-A-Review: Longhouse Cycle Review 2 | 3 | _The purpose of this review is to formally close off the prior cycle of work and 4 | communicate progress or changes in direction to the wider community._ 5 | 6 | ## Overview 7 | 8 | _Short summary of what the cycle's focus was on. Short statement on how the 9 | cycle felt and success._ 10 | 11 | ## Direction 12 | 13 | _Commentary about the direction of the project that may be relevant to any 14 | future selection or proposals_. 15 | 16 | ## Completed work 17 | 18 | _A link to or a list of tasks that were completed._ 19 | 20 | ## Uncompleted work 21 | 22 | _Any work still in progress or placed back into the backlog and why._ 23 | 24 | ## Direction 25 | 26 | _A statement on the project priorities, sometimes it is valid to close a cycle 27 | early to change direction entirely, this may happen naturally and unannounced at 28 | first, and the formal change comes later and announced here_ 29 | 30 | ## Findings and challenges 31 | 32 | _Anything that has been learnt during the cycle in any aspect, planning, 33 | governance, programming, triaging, issues_ 34 | 35 | ## Recommendations 36 | 37 | _Any recommendations or ideas for change that could be acted upon_. 38 | -------------------------------------------------------------------------------- /docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 0 3 | slug: / 4 | --- 5 | 6 | # Welcome 7 | 8 | ## Moderators 9 | 10 | If you are a moderator looking for documentation for how to use an 11 | existing Draupnir, you will want to review the following pages: 12 | 13 | - [Moderator's guide](./moderator/setting-up-and-configuring) - 14 | Managing your Draupnir and your protected rooms. 15 | - [Protections](./protections) - Configuring the protections 16 | offered by Draupnir. 17 | - Review whether you require additional [server administrative 18 | features](./bot/homeserver-administration). 19 | 20 | ## System administrators 21 | 22 | If you are a system administrator and you are looking for how 23 | to setup Draupnir: 24 | 25 | - [Setup Draupnir as a bot](./bot/setup) - Configuring Draupnir as a 26 | bot to protect a single community. 27 | - [Setup Draupnir as an appservice](./appservice) - Configuring 28 | Draupnir as an appservice that can manage and provision multiple 29 | individual Draupnir bots to your homeserver's users or others. 30 | - Review whether you require additional [server administrative 31 | features](./bot/homeserver-administration). 32 | 33 | ## Contributors 34 | 35 | If you are a contributor: 36 | 37 | - [Contributing](./contributing) - How to contribute to Draupnir. 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. 4 | 5 | ## Installation 6 | 7 | ```bash 8 | yarn 9 | ``` 10 | 11 | ## Local Development 12 | 13 | ```bash 14 | yarn start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ## Build 20 | 21 | ```bash 22 | yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ## Deployment 28 | 29 | Using SSH: 30 | 31 | ```bash 32 | USE_SSH=true yarn deploy 33 | ``` 34 | 35 | Not using SSH: 36 | 37 | ```bash 38 | GIT_USER= yarn deploy 39 | ``` 40 | 41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 42 | 43 | ## Updating the API Specification 44 | 45 | The API specification is generated from the openapi spec in `/api/draupnir-openapi.yaml`. 46 | 47 | To update the API specification, run the following command: 48 | 49 | ```bash 50 | yarn regenerate-api 51 | ``` 52 | 53 | This will regenerate the mdx files in the `docs/api` directory. 54 | -------------------------------------------------------------------------------- /docs/governance/groups.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Governance Groups 6 | 7 | ## The root contributor circle 8 | 9 | The root contributor circle are at the root of responsibility for all of the 10 | functions of the Draupnir project. Fundamentally they are are deeply trusted 11 | individuals who are faithful to the project's 12 | [vision](../contributing/vision.md). And are here to see Draupnir through any 13 | continuance crisis. 14 | 15 | ### Members 16 | 17 | - Gnuxie 18 | - Cat 19 | - Nex 20 | - Sky 21 | 22 | ## The longhouse contribution guild 23 | 24 | The contribution guild allows contributors themselves to present the work they 25 | feel able to do to the longhouse. This process allows contributors to seek 26 | affirmation from the longhouse for future work. They may provide a choice to the 27 | longhouse as a part of that, if the contributor feels there are multiple 28 | pathways forward. Implicitly, this allows the longhouse assembly to voice the 29 | direction of the project without any contributor feeling like they are working 30 | for the assembly. 31 | 32 | All Draupnir contributors are automatically associated with the contribution 33 | guild. And only they can assess their own capability to contribute for the next 34 | session and use that knowledge to present proposals for future work. 35 | 36 | ## The longhouse assembly 37 | 38 | The longhouse assembly are all of draupnir's interested parties and users. 39 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | # Review gh actions docs if you want to further define triggers, paths, etc 8 | # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on 9 | 10 | jobs: 11 | build: 12 | name: Build Docusaurus 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | - uses: actions/setup-node@v4 19 | with: 20 | node-version: 20 21 | cache: yarn 22 | 23 | - name: Install dependencies 24 | run: yarn install --frozen-lockfile 25 | - name: Build website 26 | run: yarn build 27 | 28 | - name: Upload Build Artifact 29 | uses: actions/upload-pages-artifact@v3 30 | with: 31 | path: build 32 | 33 | deploy: 34 | name: Deploy to GitHub Pages 35 | needs: build 36 | 37 | # Grant GITHUB_TOKEN the permissions required to make a Pages deployment 38 | permissions: 39 | pages: write # to deploy to Pages 40 | id-token: write # to verify the deployment originates from an appropriate source 41 | 42 | # Deploy to the github-pages environment 43 | environment: 44 | name: github-pages 45 | url: ${{ steps.deployment.outputs.page_url }} 46 | 47 | runs-on: ubuntu-latest 48 | steps: 49 | - name: Deploy to GitHub Pages 50 | id: deployment 51 | uses: actions/deploy-pages@v4 52 | -------------------------------------------------------------------------------- /docs/contributing/accessibility.md: -------------------------------------------------------------------------------- 1 | # Accessibility 2 | 3 | ## Render methods for `org.matrix.custom.html` (DeadDocument) 4 | 5 | To render command responses to Matrix, we use a custom JSX factory from 6 | [interface-manager](https://github.com/the-draupnir-project/interface-manager) 7 | to provide us with elements from `org.matrix.custom.html` (and the DOM that 8 | facilitates this is called `DeadDocument`). 9 | 10 | The general rule to keeping message content accessible is use semantic HTML 11 | elements over arbitrary ways of maintaining structure. 12 | 13 | The following describes what we should be doing to improve the accessibility of 14 | message content. Pull request reviewers should check rendered messages match the 15 | recommendations in this document. 16 | 17 | ### Headings 18 | 19 | Headings should be used at the beginning of each section within a message. This 20 | is because users of screen readers who depend on keyboard navigation need 21 | headings to properly skip over sections. 22 | 23 | ### Descriptive text for indicators 24 | 25 | If emoji or symbols are used to show a status, then the meaning should be 26 | written explicitly. For example, the `!draupnir protections` command shows 27 | whether each command is enabled or disabled with the green circle `🟢` and red 28 | circle emoji `🔴`. But next to each we also say what these mean with `(enabled)` 29 | or `(disabled)`. This is important not only for users struggling with colour 30 | perception, but also because it can be unclear to users what the emoji means in 31 | the first place. 32 | -------------------------------------------------------------------------------- /docs/protections/block-invitations-on-server-protection.md: -------------------------------------------------------------------------------- 1 | # Block invitations on server protection 2 | 3 | :::info 4 | 5 | You need to be using Draupnir v2.3.0 or above to use this protection. 6 | 7 | You also need to follow the 8 | [instructions](../bot/synapse-http-antispam) for adding the 9 | synapse-http-antispam module. 10 | 11 | This functionality is compatible with synapse workers and replaces the 12 | legacy synapse module from mjolnir. 13 | 14 | ::: 15 | 16 | This protection blocks invitations on your homeserver based on the 17 | lists that Draupnir is subscribed to. 18 | 19 | ## Which policies will result in a rejected invitation 20 | 21 | For policies that have a recommendation to ban users, the policy will 22 | only apply if the ban reason matches one of the configured 23 | `automaticallyRedactForReasons` in your Draupnir's [configuration 24 | file](../bot/starting_draupnir#the-configuration-file). If 25 | the user is targeted by a policy with the `takedown` recommendation, 26 | invitations from them will always be blocked. 27 | 28 | For policies that ban or takedown servers and rooms, matching invitations will 29 | always be blocked. 30 | 31 | ## Enabling the protection 32 | 33 | Run `!draupnir protections enable BlockInvitationsOnServerProtection` 34 | in the management room. 35 | 36 | ## Taking down targeted invitations 37 | 38 | The most effective way to remove invitations targeting users on your 39 | server to a room with intolerable content is by using the `!draupnir 40 | takedown` command in conjunction with the [room takedown protection](./room-takedown-protection). 41 | -------------------------------------------------------------------------------- /docs/bot/encryption.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | sidebar_label: Setting up encryption 4 | --- 5 | 6 | 11 | 12 | # Setting up encryption 13 | 14 | :::info 15 | 16 | Draupnir can still protect encrypted rooms without an E2EE capable 17 | device. Please see protecting encrypted rooms [here](../moderator/managing-protected-rooms#protecting-encrypted-rooms). 18 | 19 | ::: 20 | 21 | :::danger 22 | 23 | We can not at this time recommend setting up Draupnir with an E2EE 24 | capable device - neither with Pantalaimon or the rust crypto. 25 | 26 | ::: 27 | 28 | Historically there have been two options for providing an E2EE capable 29 | device to Draupnir: Pantalaimon and the matrix-bot-sdk's 30 | experimental rust crypto. Neither of these options are of a high 31 | enough quality. 32 | 33 | While we have previously permitted the use of Pantalaimon, it has 34 | consistently confused beginners that are setting it up with Draupnir, 35 | and we do not use it ourselves. Experienced system admins are welcome 36 | to attempt to set up Pantalaimon, but must be aware that any issues 37 | that they experience getting Draupnir to start are extremely likely to 38 | be from the Pantalaimon configuration and not Draupnir itself. 39 | Additionally, there are a couple of known bugs that inhibit the use of 40 | reactions in the management room when using Pantalaimon. Which are 41 | a core part of Draupnir's UX rework. 42 | 43 | You can find individual keys in Draupnir's configuration relating to 44 | both the matrix-bot-sdk and Pantalaimon. 45 | -------------------------------------------------------------------------------- /docs/concepts/policy-lists.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | sidebar_label: Policy lists 4 | --- 5 | 6 | 11 | 12 | # Policy lists 13 | 14 | ## Policies 15 | 16 | Policies are what Matrix uses to describe a recommendation for an 17 | action against an entity. An entity can be any first class Matrix 18 | concept, but the most common entity is a Matrix user. A recommendation 19 | is just a flag that describes what the policy is for. For example, 20 | banning a user from a room with Draupnir usually results in the 21 | creation of a policy of the type `m.policy.room.user` with the 22 | recommendation `m.ban`. You can read about in the Matrix specification 23 | [here](https://spec.matrix.org/latest/client-server-api/#moderation-policy-lists) 24 | 25 | These policies are stored in Matrix rooms as _state events_. When 26 | this happens, we can refer to the room as a _policy room_. 27 | If you are unfamiliar with state events, you can read our Matrix 28 | room essentials documentation [here](./room-essentials.md). 29 | 30 | ## Policy room vs policy list 31 | 32 | A policy room is a Matrix room that contains policies. A policy room 33 | is also a policy list, however Draupnir may use the term policy list 34 | to also refer to what is effectively virtual policy list. A virtual 35 | policy list would be a collection of policies where the list is not 36 | backed up by a single Matrix room as the source of the 37 | policies. Internally, Draupnir actually collects all the policies 38 | together and places them into the same virtual policy list. 39 | -------------------------------------------------------------------------------- /docs/protections/new-joiner-protection.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: New Joiner Protection 3 | --- 4 | 5 | 10 | 11 | # New Joiner Protection 12 | 13 | :::danger 14 | 15 | This is an experimental protection that should only be used as a last 16 | resort when your community is under persistent attack. 17 | 18 | This protection is unavailable in Draupnir version `2.0.0-beta.4` and 19 | below. 20 | 21 | This protection may be removed or changed entirely. 22 | 23 | ::: 24 | 25 | This is a protection that can help when one of your rooms is coming 26 | under a persistent attack from new joiners. Whether that be wave spam 27 | or targeted attacked. 28 | 29 | The protection works by banning new users from a set of configured 30 | servers, leaving existing community members from the target servers 31 | unaffected. The protection serves as an alternative to banning 32 | the server outright. 33 | 34 | ## Configuration 35 | 36 | To configure the protection, append the following under the 37 | `protections:` header in your config file: 38 | 39 | ```yaml 40 | newJoinerProtection: 41 | serverNames: 42 | - "example.com" 43 | ``` 44 | 45 | You will need to restart the bot to make this effective. We recommend 46 | that you leave servers where abuse typically originates in the 47 | configuration file. Then the protection can be enabled and disabled at 48 | will without restarting the bot. 49 | 50 | The ban message can also be changed with the option `banMessage:`. 51 | 52 | By default this reads "Unfortunately we cannot accept new users from 53 | your homeserver at this time.". 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "draupnir-documentation", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "regenerate-api": "docusaurus clean-api-docs all && docusaurus gen-api-docs all", 8 | "start": "yarn regenerate-api all && docusaurus start", 9 | "build": "yarn regenerate-api all && docusaurus build", 10 | "swizzle": "docusaurus swizzle", 11 | "deploy": "docusaurus deploy", 12 | "clear": "docusaurus clear", 13 | "serve": "docusaurus serve", 14 | "write-translations": "docusaurus write-translations", 15 | "write-heading-ids": "docusaurus write-heading-ids", 16 | "typecheck": "tsc" 17 | }, 18 | "dependencies": { 19 | "@docusaurus/core": "^3.8.0", 20 | "@docusaurus/preset-classic": "^3.8.0", 21 | "@mdx-js/react": "^3.0.0", 22 | "clsx": "^2.0.0", 23 | "docusaurus-plugin-openapi-docs": "^4.3.7", 24 | "docusaurus-theme-openapi-docs": "^4.3.7", 25 | "prism-react-renderer": "^2.3.0", 26 | "react": "^19.0.0", 27 | "react-dom": "^19.0.0" 28 | }, 29 | "devDependencies": { 30 | "@docusaurus/module-type-aliases": "^3.8.0", 31 | "@docusaurus/tsconfig": "^3.8.0", 32 | "@docusaurus/types": "^3.8.0", 33 | "typescript": "~5.8.0" 34 | }, 35 | "browserslist": { 36 | "production": [ 37 | ">0.5%", 38 | "not dead", 39 | "not op_mini all" 40 | ], 41 | "development": [ 42 | "last 3 chrome version", 43 | "last 3 firefox version", 44 | "last 5 safari version" 45 | ] 46 | }, 47 | "engines": { 48 | "node": ">=20.0" 49 | }, 50 | "packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610" 51 | } 52 | -------------------------------------------------------------------------------- /docs/protections/mention-limit-protection.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: Mention Limit Protection 3 | --- 4 | 5 | 10 | 11 | # Mention Limit Protection 12 | 13 | :::info 14 | 15 | This protection is unavailable in Draupnir version `2.0.0-beta.4` and below. 16 | 17 | Versions below `v2.3.0` have to be configured from the configuration file. 18 | 19 | ::: 20 | 21 | This is a protection that can help when one of your rooms is coming under a 22 | persistent attack where a user pings your room members. 23 | 24 | The protection will redact any message that contains more mentions than a 25 | preconfigured limit. 26 | 27 | ## Usage 28 | 29 | Use `!draupnir protections show MentionLimitProtection` to show the available 30 | protection settings for this protection. 31 | 32 | The protection will redact any messages containing mentions over `maxMentions`. 33 | The user who sent the message will then be warned not to send such a message 34 | again. 35 | 36 | If they send another message containing messages over the limit within a short 37 | timeframe, they will be banned from the room. 38 | 39 | ## Configuration prior to `v2.3.0` 40 | 41 | To configure the protection, append the following under the `protections:` 42 | header in your config file: 43 | 44 | ```yaml 45 | mentionLimitProtection: 46 | maxMentions: 3 47 | ``` 48 | 49 | You will need to restart the bot to make this effective. 50 | 51 | The redact reason can also be changed with the option `redactReason:`. 52 | 53 | By default this reads "You have mentioned too many users in this message, so we 54 | have had to redact it.". 55 | -------------------------------------------------------------------------------- /docs/protections/trusted-reporters.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: Trusted reporters 3 | --- 4 | 5 | 16 | 17 | # Trusted reporters 18 | 19 | The trusted reporters protection can be used if you have abuse 20 | reporting enabled for your Draupnir. 21 | 22 | When the trusted reporters protection receives a sufficient number of 23 | reports from trusted users concerning a given message, the protection 24 | will take an automated action, such as redacting the reported message. 25 | 26 | The users to trust, the actions to take, and the thresholds needed for 27 | those actions are all configurable. 28 | 29 | Prerequisites: 30 | 31 | * `pollReport: true` in Draupnir config file 32 | * restart Draupnir 33 | * `!draupnir enable TrustedReporters` 34 | * `!draupnir config add TrustedReporters.mxids @trusteduser:example.com` 35 | * `!draupnir config set TrustedReporters.alertThreshold 3` 36 | 37 | TrustedReporters supports 3 different thresholds; `alertThreshold`, 38 | `redactThreshold`, and `banThreshold`. By default, only 39 | `alertThreshold` is enabled, and is set to `3`. Draupnir will only 40 | consider reports that take place in rooms Draupnir is 41 | protecting. `alertThreshold` is separate from Draupnir's ability to 42 | log each report, which is `displayReports` in Draupnir's config file. 43 | 44 | Make sure that anything you have sat in front of Synapse (e.g. nginx) 45 | is correctly configured to forward `/_synapse/admin/v1/event_reports` 46 | and `/_synapse/admin/v1/rooms/${room_id}/context/${event_id}` to 47 | Synapse, or Draupnir will not be able to poll for new 48 | reports. Draupnir polls for new reports every 30 seconds. 49 | -------------------------------------------------------------------------------- /docs/governance/longhouse-cycle.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | --- 4 | 5 | # Longhouse cycle 6 | 7 | Draupnir's long-term decisions and regular development is conducted through a 8 | cyclic process. 9 | 10 | ### Consultation 11 | 12 | Consultation is an ambient rotating process that is always open. When 13 | consultation for the current session ends. Consultation for the next session 14 | remains open until the current session is over and the selection process for the 15 | next session has begun to take place. 16 | 17 | See [longhouse consultation](./longhouse-consultation.md). 18 | 19 | ### Selection 20 | 21 | The _contribution guild_ reviews issues and creates plans from the triage 22 | process as part of their regular work. They select which plans to present to the 23 | longhouse assembly, with consideration from the current consultation session. 24 | The beginning of this process rotates the consultation session. 25 | 26 | The _contribution guild_ will only select options that are within material 27 | constraints. Members of the assembly may pledge material support against options 28 | as part of the consultation process. 29 | 30 | ### Presentation 31 | 32 | The _contribution guild_ presents a document that discusses the results and 33 | progress towards the priorities decided in the previous session. Alongside this, 34 | the _contribution guild_ forms a document with opinions for each option within 35 | the context of the current state of development. 36 | 37 | See [longhouse presentation](./longhouse-presentation.md). 38 | 39 | ### Choice 40 | 41 | The longhouse assembly votes on the presentation, either affirming a decision 42 | made by the _contribution guild_ with a consensus or voting on the options. 43 | 44 | Objections may be raised at anytime about any of the options and these can be 45 | discussed. 46 | 47 | ### Development 48 | 49 | Once the session is over, work begins on the decided outcome. The outcome is 50 | recorded in a log. 51 | -------------------------------------------------------------------------------- /docs/shared/dogfood.md: -------------------------------------------------------------------------------- 1 | # The Dogfood Guide 2 | 3 | Welcome to the Dogfood Guide. This document details a semi updated list of who is Dogfooding what and this list serves to inform you of what components are under the most review due to this. 4 | 5 | ## The List 6 | 7 | Out of our installation methods from setup.md the dogfood statuses are 8 | 9 | - [Docker](/bot/setup_docker.md) is run by Gnuxie using Develop as the target. 10 | - [Building It](/bot/setup_selfbuild.md) This Install Method is NOT dogfooded currently. 11 | - [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/configuring-playbook-bot-draupnir.md) is run by Cat using Develop as target. 12 | 13 | While its not mentioned in Setup.md the nix module and package for Draupnir that is being worked on by Emma is what Emma is running. This package is always tied to a release of Draupnir and does not track git. 14 | 15 | And as for Install methods for the appservice mode the statuses are as follows 16 | 17 | - [Docker](/appservice/appservice.md) Run by MTRNord on a special derivative branch under K8s and this branch is currently not tracking 2.0 waiting for the work of untangling the merge mess to be done on their end. 18 | - Building It: Not run by any member of the draupnir project. 19 | - [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/configuring-playbook-appservice-draupnir-for-all.md) is run by Cat using Develop as target. This method is thought of as being close to bug compatible with Docker due to that its essentially just ansible orchestrating docker containers to exist to be managed by a systemd service. 20 | 21 | ## E2EE Support 22 | 23 | E2EE support is not dogfooded by any party mentioned in this document currently and this means that we can not guarantee that [Pantalaimon](https://github.com/matrix-org/pantalaimon) or the experimental native rust crypto support is working. Especially as the CI does not use these it complicates testing for them. 24 | -------------------------------------------------------------------------------- /docs/bot/setup_management_room.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | sidebar_label: Creating the management room 4 | --- 5 | 6 | 11 | 12 | # Creating the management room 13 | 14 | ## Introduction 15 | 16 | The management room is where you will interact with Draupnir. This is 17 | the room where Draupnir will respond to commands, allowing you to 18 | coordinate with Draupnir and other moderators without disrupting your 19 | public Matrix rooms. You can find further information about the 20 | management room [here](../concepts/management-room). 21 | 22 | You should create this room after you have created a user for your 23 | Draupnir bot. 24 | 25 | ## Creating the room 26 | 27 | :::warning 28 | 29 | We strongly recommend against encrypting the management room, and we 30 | cannot provide support if you do. Please see the section on encrypting 31 | the management room [here](#encrypting-the-management-room). 32 | 33 | ::: 34 | 35 | The management room should be created using your client from any 36 | Matrix user account. The room should not be public as any user that 37 | joins this room will be able to control Draupnir. 38 | 39 | Once you have created the room, you should invite the bot user that 40 | you created for Draupnir to the room. 41 | 42 | You will also need to acquire the room ID of this room, in Element Web 43 | you can find this by going to the room, going to: Settings -> Advanced 44 | -> "Internal Room ID". 45 | 46 | In your configuration, set `managementRoom` to this Room ID, and now 47 | Draupnir will only respond to commands originating from that room. If 48 | you want to upgrade your room in the future, you will have to update 49 | the configuration with it. Alternatively, you can create a room alias. 50 | 51 | ## Encrypting the management room 52 | 53 | We do not recommend setting up an encrypted management room, and we 54 | cannot provide support for setting one up. Please see our notes on 55 | encryption [here](./encryption). 56 | -------------------------------------------------------------------------------- /src/components/HomepageFeatures/index.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | import Heading from '@theme/Heading'; 3 | import styles from './styles.module.css'; 4 | 5 | type FeatureItem = { 6 | title: string; 7 | Svg: React.ComponentType>; 8 | description: JSX.Element; 9 | }; 10 | 11 | const FeatureList: FeatureItem[] = [ 12 | { 13 | title: 'Easy to Use', 14 | Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, 15 | description: ( 16 | <> 17 | Docusaurus was designed from the ground up to be easily installed and 18 | used to get your website up and running quickly. 19 | 20 | ), 21 | }, 22 | { 23 | title: 'Focus on What Matters', 24 | Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, 25 | description: ( 26 | <> 27 | Docusaurus lets you focus on your docs, and we'll do the chores. Go 28 | ahead and move your docs into the docs directory. 29 | 30 | ), 31 | }, 32 | { 33 | title: 'Powered by React', 34 | Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, 35 | description: ( 36 | <> 37 | Extend or customize your website layout by reusing React. Docusaurus can 38 | be extended while reusing the same header and footer. 39 | 40 | ), 41 | }, 42 | ]; 43 | 44 | function Feature({title, Svg, description}: FeatureItem) { 45 | return ( 46 |
47 |
48 | 49 |
50 |
51 | {title} 52 |

{description}

53 |
54 |
55 | ); 56 | } 57 | 58 | export default function HomepageFeatures(): JSX.Element { 59 | return ( 60 |
61 |
62 |
63 | {FeatureList.map((props, idx) => ( 64 | 65 | ))} 66 |
67 |
68 |
69 | ); 70 | } 71 | -------------------------------------------------------------------------------- /docs/governance/ethical-values.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1.5 3 | --- 4 | 5 | # Ethical values 6 | 7 | :::info 8 | 9 | These values are written in grey, contributors will be fine without ever reading 10 | them. They do not serve as a purity test and we do not ask for contributors 11 | themselves to align to the values. What is important is actions within the 12 | context of the project and serious conflicts of interest. Our work will 13 | naturally align with them if the work is true to Draupnir's community focus. 14 | This document reinforces Draupnir's community focus and also acts as a deterrent 15 | and canary. 16 | 17 | ::: 18 | 19 | Our society provides a great incentive for people to build systems and 20 | organisations that exert top down control. It takes effort to avoid them. It is 21 | important for these values to be expressed so that the project is protected from 22 | a hostile takeover. These values are at the essence of Draupnir, and the project 23 | would not be the same without them. 24 | 25 | ## Liberation 26 | 27 | The Draupnir project only exists as a small part of an eternal struggle to fight 28 | against oppression and authoritarianism in any form, and in all appearances. 29 | 30 | Draupnir will not work with or legitimise any entity that enforces arbitrary 31 | detention, terrorizes communities, or persecutes minorities. 32 | 33 | Draupnir is blind to the law when liberation is concerned. What is legal is not 34 | what is right. Breaking power that is used by authoritarians will always be more 35 | important than the continuance of any project. 36 | 37 | ## Empowerment 38 | 39 | We build pathways for others to follow us through as equals. We reject systems 40 | that allow parties to control or extract from others. 41 | 42 | ## Accountability 43 | 44 | Draupnir belongs to its contributors and the communities it serves. Decisions 45 | about direction, funding, and governance are made transparently and with 46 | accountability to those affected. Opaque authority and influence must be 47 | actively and continuously brought into transparency in any form in which they 48 | present themselves. 49 | 50 | ## Integrity 51 | 52 | Contributions to Draupnir are made in confidence of these values. Should any 53 | contributor's actions clearly conflict with these values, it is expected that 54 | their contribution will end. 55 | -------------------------------------------------------------------------------- /docs/bot/systemd.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | sidebar_label: Installation with Docker and systemd 4 | --- 5 | 6 | # Installation with Docker and systemd 7 | 8 | If docker is installed on your system, installing Draupnir is as 9 | simple as creating the following systemd unit file. 10 | 11 | ## Pre-requisites 12 | 13 | This guide assumes you have read over the different options available 14 | for starting Draupnir and understand the requirements Draupnir 15 | has, which you can read [here](./starting_draupnir). 16 | 17 | ## Preparing your system 18 | 19 | The first thing that you will need to do is create the directory 20 | `/var/lib/draupnir`, which will be used to store Draupnir's 21 | persistent data. 22 | 23 | You will then want to copy your configuration file for Draupnir to 24 | `/var/lib/draupnir/config/production.yaml`. 25 | 26 | Then you will want to copy the following systemd unit file to 27 | `/etc/systemd/system/draupnir.service`. 28 | 29 | ```ini 30 | [Unit] 31 | Description=Draupnir Docker Container 32 | After=docker.service 33 | Requires=docker.service 34 | 35 | After=network-online.target 36 | Wants=network-online.target 37 | 38 | [Service] 39 | Type=exec 40 | # Update Draupnir 41 | ExecStartPre=docker image pull gnuxie/draupnir:latest 42 | # Clean up any accidentally existing containers 43 | ExecStartPre=docker container rm --force draupnir 44 | 45 | ExecStart=docker container run --rm --pull=never --name=draupnir -v /var/lib/draupnir:/data gnuxie/draupnir:latest bot --draupnir-config /data/config/production.yaml 46 | 47 | ExecStop=-docker container stop --time=10 draupnir 48 | 49 | # Let Docker handle timeout instead 50 | TimeoutStopSec=infinity 51 | 52 | Restart=always 53 | RestartSec=30 54 | 55 | [Install] 56 | WantedBy=multi-user.target 57 | ``` 58 | 59 | You will then need to run `systemctl daemon-reload` to register the 60 | service file. 61 | 62 | Finally run `systemctl enable draupnir.service` to tell systemd to 63 | start Draupnir the next time your system boots. 64 | 65 | ## Managing Draupnir 66 | 67 | Now you can start draupnir with `systemctl start draupnir.service`. 68 | 69 | If you need to access the logs, you can use 70 | `journalctl -u draupnir.service`. If you need to follow the logs 71 | because you want to watch Draupnir start, you can use `-f` option. 72 | 73 | Draupnir can then be restarted or stopped with `systemctl restart 74 | draupnir.service` and `systemctl stop draupnir.service` respectively. 75 | -------------------------------------------------------------------------------- /docs/bot/setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | sidebar_label: Setting up Draupnir 4 | --- 5 | 6 | # Setting up Draupnir 7 | 8 | This page describes how to setup Draupnir as a bot user that runs 9 | against any Matrix homeserver. This includes homeservers that you do 10 | not administer. 11 | 12 | ## Overview 13 | 14 | There are a number of steps to complete to get Draupnir running: 15 | 16 | 1. [Create an account](./setup_draupnir_account) for Draupnir to use. 17 | - Optionally disabling rate limits for this account. 18 | 2. Review our notes on [encryption](./encryption). 19 | 3. [Create a management room](./setup_management_room) for Draupnir to use. 20 | 4. [Install Draupnir](#installation) on your system. 21 | 5. [Fill out Draupnir's config file](./starting_draupnir) to complete 22 | the installation. 23 | 6. Start using Draupnir by referring to the [moderator's guide](../moderator/setting-up-and-configuring). 24 | 25 | ## Installation 26 | 27 | Draupnir can be installed in three ways, via Docker, building it 28 | yourself from source, or via 29 | [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/configuring-playbook-bot-draupnir.md). 30 | 31 | :::tip 32 | 33 | We strongly recommend new or inexperienced system administrators to 34 | follow our guide for [installation with Docker and 35 | systemd](./systemd). If you are preparing to administer a new 36 | homeserver, then we strongly recommend using 37 | [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy). 38 | 39 | ::: 40 | 41 | See the following links for corresponding installation documentation: 42 | 43 | - [Installation with Docker and systemd](./systemd.md) - The 44 | recommended and supported setup for users who do not wish to use 45 | matrix-docker-ansible-deploy. 46 | - [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/configuring-playbook-bot-draupnir.md) - 47 | the most convenient way to run Matrix services. Recommended if you 48 | are preparing a new homeserver or are already using 49 | matrix-docker-ansible-deploy. 50 | - [Installation on Debian](./setup_debian.md) - Installation on debian by using [NodeSource](https://github.com/nodesource/distributions?tab=readme-ov-file). 51 | - [Advanced Docker setup](./setup_docker.md) - for experienced system 52 | administrators. 53 | - [Advanced setup from source](./setup_selfbuild.md) - for experienced 54 | system administrators. 55 | -------------------------------------------------------------------------------- /docs/protections/room-takedown-protection.md: -------------------------------------------------------------------------------- 1 | # Room Takedown Protection 2 | 3 | :::info 4 | 5 | You need to be using Draupnir v2.3.0 or above to use this protection. Since 6 | Draupnir v2.4.1, this protection no longer depends upon synapse-http-antispam. 7 | 8 | ::: 9 | 10 | :::tip 11 | 12 | While this protection does not depend on synapse-http-antispam. You may wish to 13 | install the protection if you want to preemptively block invitations as soon as 14 | possible. You should follow our [instructions](../bot/synapse-http-antispam) for 15 | adding the synapse-http-antispam module. 16 | 17 | ::: 18 | 19 | The room takedown protection matches policies from Draupnir's watched lists 20 | against the rooms your homeserver is joined to. 21 | 22 | This protection is useful when you are administrating a server with open 23 | registration and need to protect yourself and your users from two scenarios: 24 | 25 | 1. Spam invitations targetting your local users that have already been sent and 26 | need to be rejected automatically. 27 | 28 | 2. Preventing local users from joining rooms with intolerable or illegal 29 | content, and removing these rooms if they are detected on the homeserver. 30 | 31 | If the protection discovers a room is marked with the `takedown` recommendation, 32 | then the protection will instruct your homeserver to shutdown the room. This 33 | will force all local participants to leave the room, purge the history from your 34 | database, and block the room. 35 | 36 | ## Room Discovery 37 | 38 | The protection provides a means of oversight into the rooms your homeserver is 39 | participating within. When a room is discovered no your homeserver, a 40 | notification is sent to a configured room with details about the room: the 41 | title, description, creator, and member count. 42 | 43 | The protection includes a threshold `discoveryNotificationMembershipThreshold` 44 | that must be met before displaying the notification. By default, a room needs to 45 | have `20` members before its details will be displayed. This is a privacy 46 | concious default to balance between alerting the server admins of all rooms, and 47 | those that are large enough to be of concern. 48 | 49 | ## Configuration 50 | 51 | See [configuring protections](./configuring-protections) for a guide on how to 52 | configure this protection. 53 | 54 | ## Taking down a room 55 | 56 | To takedown a room yourself, you will need to use the `!draupnir takedown` 57 | command. You will be prompted for confirmation, and will be required to read the 58 | details very carefully. 59 | -------------------------------------------------------------------------------- /docs/moderator/managing-policy-lists.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | sidebar_label: Managing policy lists 4 | --- 5 | 6 | 11 | 12 | # Managing policy lists 13 | 14 | If you are struggling to understand what a policy list or a policy 15 | room is, and why they are useful you should see our [policy 16 | lists](../concepts/policy-lists) documentation. 17 | 18 | ## Reviewing which lists Draupnir is watching 19 | 20 | After watching or unwatching policy rooms, you may wish to confirm 21 | what policy lists Draupnir is watching. This can be done by issuing 22 | the `!draupnir status` command. 23 | 24 | Rooms that are marked as `protected` also belong to Draupnir's 25 | protected rooms set, and you likely have write access to these lists. 26 | You can find the documentation for managing protected rooms 27 | [here](./managing-protected-rooms.md). 28 | 29 | ## Inviting Draupnir to policy rooms 30 | 31 | Just by inviting Draupnir to a policy room, Draupnir will ask you 32 | within the management room whether you wish for Draupnir to watch for 33 | and to subscribe to policies. 34 | 35 | The answer to the question can be given by clicking on the reactions in 36 | your Matrix client. By selecting 'Ok', Draupnir will watch the list, 37 | and if all goes well Draupnir will leave behind a green tick. 38 | 39 | ## Using Draupnir's `watch` command to subscribe to policy rooms 40 | 41 | The easiest way to watch a room is to use the `!draupnir watch` 42 | command. This will tell Draupnir to watch the list and apply its 43 | policies to your rooms. We recommend subscribe to to the list curated 44 | by the community moderation effort, which exclusively focuses on 45 | spam. You can do so with the following command `!draupnir watch #community-moderation-effort-bl:neko.dev`. 46 | 47 | ## Using the `status` command to view watched lists 48 | 49 | By calling `!draupnir status`, you will be able to see a list of 50 | policy rooms and their associated "shortcodes". 51 | 52 | Usually, lists that you can write to will be marked as protected. 53 | 54 | ## Using Draupnir's `list create` command to create a policy room 55 | 56 | If for some reason you don't have access to a writeable list, you can 57 | create one using `!draupnir list create`. So for example, if I wanted 58 | to create a a policy room for paw prints community, then I would use 59 | the command like so `!draupnir list create my-bans my-bans-bl`. This 60 | will create a policy room with the shortcode `my-bans` and an alias 61 | `#my-bans-bl:example.com`, which can be used to share the list with 62 | other communities. 63 | -------------------------------------------------------------------------------- /.github/workflows/sign-off.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Catalan Lover 2 | # Copyright 2022 - 2024 The Matrix.org Foundation C.I.C. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | # 6 | # SPDX-FileAttributionText: 7 | # This modified file incorporates work from matrix-org/backend-meta 8 | # https://github.com/matrix-org/backend-meta 9 | # 10 | name: Contribution requirements 11 | 12 | on: 13 | pull_request: 14 | types: [opened, edited, synchronize] 15 | workflow_call: 16 | 17 | jobs: 18 | signoff: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Check PR for sign-off text 22 | uses: actions/github-script@v7 23 | with: 24 | script: | 25 | // We don't require owners or members of the org to sign off. 26 | const authorAssociation = context.payload.pull_request.author_association; 27 | if (['OWNER', 'MEMBER'].includes(authorAssociation) || 28 | // GitHub sometimes mislables users as 'CONTRIBUTOR'/'COLLABORATOR', 29 | // so check that the user created the PR on the base project to check they have write access. 30 | context.payload.pull_request.head.user.login === context.repo.owner) { 31 | core.notice('Pull request does not require sign-off.'); 32 | return; 33 | } 34 | 35 | // This regex is intentionally left lenient. 36 | const signOffRegex = /signed[_\- ]off[_\- ]by: [\S ]+ ?/i; 37 | 38 | if (signOffRegex.test(context.payload.pull_request.body ?? "")) { 39 | core.notice('Pull request body contains a sign-off notice'); 40 | return; 41 | } 42 | 43 | const commits = await github.rest.pulls.listCommits({ 44 | pull_number: context.payload.pull_request.number, 45 | owner: context.repo.owner, 46 | repo: context.repo.repo, 47 | // It's *possible* the author has buried the sign-off 101 commits down, but 48 | // we don't want to max out the API searching for it. 49 | per_page: 100, 50 | }); 51 | 52 | const commit = commits.data.find(c => signOffRegex.test(c.commit.message)); 53 | if (commit) { 54 | core.notice(`Commit '${commit.id}' contains a sign-off notice`); 55 | return; 56 | } 57 | 58 | core.setFailed('No sign off found. Please ensure you have signed off following the advice in https://the-draupnir-project.github.io/draupnir-documentation/contributing#sign-off .') 59 | core.notice('Ensure you have matched the format `Signed-off-by: Your Name `') 60 | -------------------------------------------------------------------------------- /docs/bot/starting_draupnir.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | sidebar_label: Draupnir parameters and options 4 | --- 5 | 6 | 11 | 12 | # Draupnir parameters and options 13 | 14 | :::info 15 | 16 | This section is supposed to be read in conjunction with one of the 17 | following installation routes: 18 | 19 | 1. [Installation with Docker and systemd](./systemd) (recommended). 20 | 2. [Installation on Debian](./setup_debian) 21 | 3. [Advanced Docker setup](./setup_docker). 22 | 4. [Advanced setup from source](./setup_selfbuild). 23 | 24 | ::: 25 | 26 | Before you proceed with the installation method, you will need to be 27 | aware of the files and directories that Draupnir requires access to. 28 | 29 | ## The configuration file 30 | 31 | Most of Draupnir's configuration is done through a YAML file. The path 32 | of this config is provided with the `--draupnir-config` option. 33 | 34 | Please go through [the sample configuration file's 35 | documentation](https://github.com/the-draupnir-project/Draupnir/blob/main/config/default.yaml), 36 | download it, and rename it `production.yaml`. You should read over the 37 | different options and edit them to your liking. This is the file that 38 | will be referred to as "the config" throughout Draupnir's 39 | documentation. Your copy of the config file should be named 40 | `production.yaml` and placed within `./config/production.yaml` 41 | relative to [the data directory](#the-data-directory) (explained 42 | below). Where your data directory is will depend on the 43 | installation method you are using, so please refer to the respective 44 | guide that you are following. 45 | 46 | ## The data directory 47 | 48 | :::warning 49 | 50 | Do not change the value for `dataPath` if you are using Docker, this 51 | is the path that Draupnir will use to find the path within the Docker 52 | container, not the host filesystem. Please see either [installation 53 | with Docker and systemd](./systemd) or [advanced Docker 54 | setup](./setup_docker). 55 | 56 | ::: 57 | 58 | Draupnir stores persistent data to a directory called the *data 59 | directory*. This is a directory that Draupnir must have read and write 60 | access to. This is configured using the top-level `dataPath` option 61 | within Draupnir's configuration. 62 | 63 | ## Secret Management 64 | 65 | If you need to use a secret management system, such as systemd's 66 | service credentials, the following options are available at the 67 | command line: 68 | 69 | - The access token can be provided with the option `--access-token-path`. 70 | - The Pantalaimon password can be provided with the option 71 | `--pantalaimon-password-path`. 72 | 73 | These are files that Draupnir will load the associated secrets from. 74 | -------------------------------------------------------------------------------- /docs/contributing/triaging.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Triaging issues 6 | 7 | The issue triaging process was developed in this [blog post](https://marewolf.me/posts/draupnir/2401.html#triaging) 8 | and we use [another post](https://lostgarden.home.blog/2008/05/20/improving-bug-triage-with-user-pain/) 9 | as our primary resource. 10 | 11 | ## The purpose of triaging 12 | 13 | For us, we use triaging primarily to create an order of issues that 14 | need attention first. It's very loose, and what should be worked on 15 | first will always remain subjective. However, this is a best effort 16 | of creating a list that can be easily looked at with less noise. 17 | 18 | ## Labels 19 | 20 | ### Likelihood 21 | 22 | Likelihood is just an estimation of the proportion of users that are 23 | likely to come across the issue, with a range from one to five. 24 | 25 | When the issue is within the context of a developer improvement, 26 | or something workflow related, you should consider the maximum 27 | value for the issue's likelihood to effect either users or developers. 28 | 29 | ### Annoyance 30 | 31 | Annoyance is how annoying the issue is. This is a range from one to 32 | three and we avoid passive-aggressive labelling, for example labelling 33 | of an issue as "tolerable" is renown for frustrating issue reporters. 34 | When an issue is the most annoying, outrageous, the user is at risk of 35 | no longer wanting to use or engage with Draupnir altogether. 36 | This is independent of whether the user is technically able to continue. 37 | There is a reserved fourth level for something that blocks all development, 38 | for example a CI failure. 39 | Most issues are expected to sit around the second level, aggravating. 40 | 41 | ### Impact 42 | 43 | Finally there is a categorisation of the issue type, which we call impact. 44 | The reason we call this impact and not type, is because this seems to 45 | be a shortcoming in the original model. They have a linear score for 46 | the issue type label, and put documentation and visual issues at the 47 | lower end. From what I can tell, the intention of the scoring is to 48 | represent how the issue relates to workflow. The highest score, crash, 49 | means that work can't continue or there's other consequences such as 50 | data loss. So by calling this label impact instead of type, we are 51 | explicitly saying that its purpose is to highlight issues that hinder 52 | people's ability to use or continue to use Draupnir. This includes 53 | documentation issues that would prevent them from setting up Draupnir 54 | or describing how they can use a feature. If a documentation issue 55 | means that a new user can't start or use Draupnir, then this will 56 | still be tier six, which is named crash, rather than tier two or below. 57 | This is extremely important because categorising issues naively by type 58 | and then ranking them (as Tailscale and the linked blog posts appear to) 59 | would make critical documentation issues seem less important at a glance. 60 | -------------------------------------------------------------------------------- /docs/bot/setup_docker.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | sidebar_label: Advanced Docker setup 4 | --- 5 | 6 | # Advanced Docker setup 7 | 8 | :::tip 9 | 10 | This guide is for experienced system administrators. If you are 11 | unfamiliar with Docker or system administration in general, 12 | then you should refer to our recommended installation method 13 | of [using Docker with systemd](./systemd). 14 | 15 | ::: 16 | 17 | ## Images 18 | 19 | Draupnir is available as an image from Docker Hub as 20 | [`gnuxie/draupnir`](https://hub.docker.com/r/gnuxie/draupnir/tags). 21 | Draupnir is available under the following release tags: 22 | 23 | ### `latest` 24 | 25 | The latest tag will always refer to the latest stable release. This 26 | tag excludes any pre-releases. Please be aware, depending on the 27 | container system you are using, that this means your Draupnir can 28 | implicitly upgrade when restarted. Which may or may not be a problem 29 | for your use case. 30 | 31 | ### Version tags - `vX.X.X` 32 | 33 | :::warning 34 | 35 | Releases and tags marked with `-beta.*` are pre-releases and are 36 | intended for advanced users who are providing feedback via our support 37 | room, 38 | [#draupnir:matrix.org](https://matrix.to/#/#draupnir:matrix.org). You 39 | are welcome to participate, but expect these releases to be of lower 40 | quality and to contain bugs. 41 | 42 | ::: 43 | 44 | Version tags are available for individual releases, you can find what 45 | releases are available on the [release page on 46 | GitHub](https://github.com/the-draupnir-project/Draupnir/releases). 47 | If there are pre-releases, you should scroll down until you find the 48 | latest release. 49 | 50 | ### `develop` 51 | 52 | The `develop` tag will always refer to an image built from the `main` 53 | branch of Draupnir's git repository. You will not experience any 54 | severe breakages by using this tag, but you will want to be present 55 | within the Draupnir support room. 56 | 57 | ## Running with Docker 58 | 59 | Before any other steps, a configuration file must be prepared. You 60 | should read through the [configuration and options 61 | guide](./starting_draupnir) alongside this one as some sections 62 | require cross referencing. 63 | 64 | You will also need to have chosen a place on your system to serve as 65 | the data directory for Draupnir. For most users this will be 66 | `/var/lib/draupnir`. 67 | 68 | ### Docker Run 69 | 70 | :::info 71 | 72 | Arguments to Draupnir itself from `docker run` begin with `bot`. 73 | 74 | ::: 75 | 76 | The container entry-point is shared with the option to deploy Draupnir 77 | as an appservice, and therefore *bot mode* must be explicitly asked 78 | for when providing options with `docker run`. This is done by ensuring 79 | the first argument that gets passed to the container is `bot`. 80 | 81 | So for example: o start Draupnir, you could use the following command: 82 | 83 | ```bash 84 | docker run --rm -it --name=draupnir -v ./var/lib/draupnir:/data gnuxie/draupnir:latest bot --draupnir-config /data/config/production.yaml 85 | ``` 86 | -------------------------------------------------------------------------------- /docs/moderator/room-upgrades.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: Room upgrades 3 | --- 4 | 5 | 10 | 11 | # Room upgrades 12 | 13 | :::tip 14 | 15 | It is recommended that you use Draupnir v2.6.1 or above before upgrading rooms. 16 | 17 | See https://github.com/the-draupnir-project/planning/issues/44 for progress on 18 | room upgrade features. 19 | 20 | ::: 21 | 22 | ## Hydra disclosure 23 | 24 | :::note 25 | 26 | This advice is provided in relation to the 27 | [hydra security disclosure](https://matrix.org/blog/2025/08/project-hydra-improving-state-res/). 28 | 29 | ::: 30 | 31 | We strongly recommend communities do not upgrade their rooms until Draupnir 32 | provides a way to upgrade rooms itself. 33 | 34 | This is because the upgrade UX on Matrix is currently poor, and if managed 35 | naively it is possible to down your own community by mistake. 36 | 37 | Additionally it is taking time for community servers to update to the latest 38 | releases that support room V12. The result of which is that many users will be 39 | unable to participate in the replacement rooms, and may forget to join them as 40 | room activity decays. This may mean that they never join the replacement room if 41 | you upgrade too soon. 42 | 43 | If you have done your own research, and you are willing to accept the risks and 44 | take responsibility, then the rest of this page does offer advice about the 45 | current level of support in Draupnir for room upgrades. 46 | 47 | ## Upgrading protected rooms 48 | 49 | When protected rooms are upgraded, Draupnir will automatically join and protect 50 | the replacement room. This behaviour is provided as a part of the 51 | `RoomsSetBehaviour` protection, which is enabled by default. 52 | 53 | Please follow the 54 | [official guide](https://matrix.org/docs/communities/administration/) for how to 55 | upgrade rooms. 56 | 57 | ## Upgrading policy rooms 58 | 59 | :::danger 60 | 61 | Just don't do this yet. You do not know better. Please speak to us in 62 | #draupnir:matrix.org if you think that you do. But you do not. 63 | 64 | ::: 65 | 66 | Policy rooms may only be upgraded at the moment with the expectation that 67 | policies will not be moved across to the new room, and that the old policy room 68 | will need to remain watched. Draupnir will not currently do anything if it 69 | notices a policy room has been upgraded. Please see 70 | https://github.com/the-draupnir-project/planning/issues/44. 71 | 72 | ## Upgrading the management room 73 | 74 | :::danger 75 | 76 | Just don't do this yet. There is no reason to as the management room is a 77 | private room. You do not know better. Please speak to us in #draupnir:matrix.org 78 | if you think that you do. But you do not. 79 | 80 | ::: 81 | 82 | Upgrading the management room is not supported currently. This is due to data 83 | that is stored within the management room that would need to be copied into the 84 | replacement room. And doing so can result in a loss of data to protection 85 | settings. 86 | -------------------------------------------------------------------------------- /docs/concepts/encryption.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | sidebar_label: Encryption 4 | --- 5 | 10 | # Encryption and Draupnir 11 | 12 | :::info 13 | 14 | **Draupnir does not need support for encryption**. In Draupnir's 15 | context, E2EE does not provide any additional security. And Draupnir 16 | can still protect encrypted rooms. 17 | 18 | ::: 19 | 20 | ### Management Room Encryption 21 | 22 | :::tip 23 | 24 | Sensitive moderation discussions should be conducted in dedicated E2EE 25 | rooms outside of the management room. We strongly recommend against 26 | encrypting the management room. 27 | 28 | ::: 29 | 30 | E2EE provides only limited protection against unauthorised access to 31 | the information in the management room. The main reason for encrypting 32 | the management room is the belief that encryption would protect the 33 | messages in the management room from a snooping server admin or a 34 | compromised homeserver database. 35 | 36 | However **Draupnir does not enforce cross signing** and therefore 37 | Draupnir does not protect against impersonation attacks. This 38 | includes impersonation of the bot itself, any other user in the 39 | management room. 40 | 41 | For this reason we strongly recommend against encrypting the 42 | management room. 43 | 44 | Sensitive discussions should be relegated to dedicated moderation 45 | communication channels that can use E2EE properly to avoid needing 46 | E2EE for the Draupnir management room. Draupnir should not be present 47 | in these rooms. 48 | 49 | Another thing to note is that E2EE does not protect commands from 50 | metadata based deanonymisation. Because the sender is encoded in the 51 | plain text portion of Matrix events, along with the time the message 52 | was sent, it is straightforward for anyone with access to the room 53 | history to deanonymise the sender of bot commands. And as commands 54 | often have observable effects outside of the management room, like a 55 | ban or a policy creation, the exact command used can also be reversed. 56 | 57 | ### Room Level Encryption 58 | 59 | :::warning 60 | 61 | Matrix users in encrypted rooms can selectively withhold encryption 62 | keys from moderators and Draupnir to bypass automated protections that 63 | scan message content, such as the `WordListProtection`. 64 | 65 | Maliciously and selectively withholding encryption keys is 66 | indistinguishable from regularly occurring Matrix encryption errors. 67 | 68 | ::: 69 | 70 | Also see [Protecting encrypted rooms](../moderator/managing-protected-rooms#protecting-encrypted-rooms). 71 | 72 | ## How to disable Management Room Encryption 73 | 74 | To disable encryption support in your bot you have to disable the 75 | encryption in your management room. To do this you have two options: 76 | 77 | * Create a completely separate management room. 78 | * Execute a manual room upgrade on the room. If doing a manual room 79 | upgrade usage of scripts like [this 80 | one](https://gitea.blesmrt.net/mikaela/scripts/src/branch/master/bash/matrix-upgrade-room.bash) 81 | by Aminda, which is strongly recommended. 82 | 83 | Please note that protection settings are stored in the management 84 | room's room state and will be reset to default by the migration away 85 | from E2EE. Unless you have tooling to copy these over to the new room. 86 | -------------------------------------------------------------------------------- /docs/bot/synapse-http-antispam.md: -------------------------------------------------------------------------------- 1 | # Synapse http antispam 2 | 3 | :::info 4 | 5 | You need to be using Draupnir v2.3.0 or above to use this Synapse module. 6 | 7 | ::: 8 | 9 | The [synapse-http-antispam](https://github.com/maunium/synapse-http-antispam) 10 | module allows Draupnir to make decisions about events that are received by your 11 | homeserver. This module replaces the functionality of the legacy Mjolnir 12 | antispam module. 13 | 14 | Please see the page on [homeserver administration](./homeserver-administration) 15 | to see the range of features that this module enables. 16 | 17 | ## Installation 18 | 19 | If you are using matrix-docker-ansible-deploy, then enabling the module is very 20 | simple 21 | [link](https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/configuring-playbook-bot-draupnir.md#enabling-synapse-http-antispam-support). 22 | 23 | Otherwise follow the instructions from the 24 | [synapse-http-antispam readme](https://github.com/maunium/synapse-http-antispam). 25 | 26 | ## Configuration 27 | 28 | Your synapse module configuration should look something like this: 29 | 30 | ```yaml 31 | modules: 32 | - module: synapse_http_antispam.HTTPAntispam 33 | config: 34 | # http://`:/api/1/spam_check` 35 | base_url: http://localhost:8080/api/1/spam_check 36 | authorization: YOUR_SECRET_TOKEN 37 | do_ping: true 38 | enabled_callbacks: 39 | - user_may_invite 40 | - user_may_join_room 41 | fail_open: 42 | user_may_invite: true 43 | user_may_join_room: true 44 | ``` 45 | 46 | Currently we only support the `user_may_invite`, and `user_may_join_room` 47 | callbacks. We strongly recommend that these endpoints are configured to 48 | `fail_open` so that your homeserver's service is not degraded should Draupnir 49 | fail or go offline. 50 | 51 | ### Draupnir Configuration 52 | 53 | You will also need to enable `synapseHTTPAntispam` under the `web` property in 54 | Draupnir's config (see 55 | [default.yaml](https://github.com/the-draupnir-project/Draupnir/blob/main/config/default.yaml)). 56 | 57 | ## Troubleshooting or verifying connection from Synapse 58 | 59 | :::info 60 | 61 | Support for `do_ping` is available from Draupnir v2.4.0. 62 | 63 | ::: 64 | 65 | In order to verify that Synapse, or any of its workers, are able to reach the 66 | draupnir antispam server, you can look for the following messages in Synapse 67 | logs. 68 | 69 | 1. Verify that the Synapse module is loaded by searching for `Loaded module`. 70 | You should find a line that looks like this: 71 | `synapse.app._base - 584 - INFO - sentinel - Loaded module ` 72 | 73 | 2. Verify that synapse-http-antispam is able to reach Draupnir by searching for 74 | `Successfully pinged antispam server`. You should be able to see a line that 75 | looks like this: 76 | `synapse_http_antispam - 65 - INFO - sentinel - Successfully pinged antispam server with request ID UAhDvDkv` 77 | 78 | 3. Verify that synapse-http-antispam is unable to reach Draupnir by searching 79 | for `Failed to ping antispam server`. You should be able to see a line that 80 | looks like this: 81 | `synapse_http_antispam - 68 - ERROR - sentinel - Failed to ping antispam server (POST http://draupnir:localhost:8082/api/1/spam_check/ping)` 82 | 83 | 4. Verify that Draupnir's configuration is correct by looking for the message 84 | `There are unknown configuration properties` in Draupnir's log, and checking 85 | if any properties are relevant. 86 | -------------------------------------------------------------------------------- /docs/contributing/draupnir-news.md: -------------------------------------------------------------------------------- 1 | # Draupnir news 2 | 3 | :::info 4 | 5 | This guide explains: 6 | 7 | 1. Editing and viewing news items locally. 8 | 2. What the style guidelines are for news items. 9 | 3. What should be included in the pull request to release news items. 10 | 4. The review process for news items. 11 | 12 | ::: 13 | 14 | ## Where does Draupnir news come from? 15 | 16 | Draupnir news is requested from the github repository main branch version of 17 | `src/protections/DraupnirNews/draupnir_news.json`. Additionally, the local 18 | source version of this file is also used to source news. Editing news involves 19 | editing the local copy of the news file. 20 | 21 | ## Editing and viewing news items locally 22 | 23 | The process for editing news items goes as follows: 24 | 25 | 1. Use a Matrix client of your choice to format a Matrix message announcing the 26 | news. This is just the same as writing a message, use markdown to structure 27 | the message however you like, within the style guidelines. You are probably 28 | better off just copying the markdown from a similar event if that is easier. 29 | 30 | 2. Once you are happy you can send the event to a test room. 31 | 32 | 3. View the event source and copy the event content into your local 33 | `draupnir_news.json`. 34 | 35 | 4. Create a UUID v4 for the news item. This can be done just by using 36 | `node -e "console.log(crypto.randomUUID())"` or an equivalent command. 37 | 38 | Your Draupnir news should look something like this: 39 | 40 | 41 | 42 | ```json 43 | { 44 | "news": [ 45 | { 46 | "news_id": "cd1881d2-60d0-49ad-9951-321205efa64b", 47 | "matrix_event_content": { 48 | "msgtype": "m.notice", 49 | "body": "#### 📰 Draupnir Assembly: Call for Participation\n\nThe Longhouse Assembly is determining the next direction for the project.\n\nReview the current cycle and cast your vote:\n\n➡️ [Join the Assembly Discussion](https://matrix.to/#/!DtwZFWORUIApKsOVWi:matrix.org?via=matrix.org&via=feline.support&via=asgard.chat)", 50 | "format": "org.matrix.custom.html", 51 | "formatted_body": "

📰 Draupnir Assembly: Call for Participation

\n

The Longhouse Assembly is determining the next direction for the project.

\n

Review the current cycle and cast your vote:

\n

➡️ Join the Assembly Discussion

\n" 52 | } 53 | } 54 | ] 55 | } 56 | ``` 57 | 58 | ## Style Guidelines 59 | 60 | 1. Use a small header (`

`) with boldface and an emoji to make it look 61 | professional e.g. `#### 📰 Draupnir Assembly: Call for Participation`. 62 | 63 | 2. Keep the message 1-2 sentences long and link directly to the subject matter. 64 | 65 | 3. Try to base your message off of previous events. 66 | 67 | ## Creating a pull request for a news item 68 | 69 | The pull request should contain the following: 70 | 71 | - `DraupnirNews` in the title. 72 | - A screenshot of the news content in the description. 73 | - Any context of the news. 74 | - The client used to design the message. 75 | 76 | The pull request should remain a draft until you are sure that it is ready to 77 | merge. This prevents accidents. 78 | 79 | Here is an example pull request: 80 | https://github.com/the-draupnir-project/Draupnir/pull/984 81 | 82 | ## Reviewing a pull request for a news item 83 | 84 | Reviewers should take care to verify that draupnir actually sends the content as 85 | depicted in the screenshot or in any part of the pull request. 86 | -------------------------------------------------------------------------------- /docs/moderator/managing-users.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | sidebar_label: Managing users 4 | --- 5 | 6 | 11 | 12 | # Managing users 13 | 14 | ## Context 15 | 16 | To be able to understand how to manage users effectively, you will 17 | want to read our conceptual documentation on Matrix room membership 18 | [here](../concepts/room-essentials/#membership). 19 | 20 | ## Checking whether a user is banned 21 | 22 | If you want to check whether a user is already banned, you can use 23 | the following command to check whether there are existing policies 24 | that match the user: `!draupnir rules matching @spam:example.com`. 25 | 26 | ## The `BanPropagationProtection` 27 | 28 | Just by banning or unbanning users as you would normally from your 29 | Matrix client in a single room, Draupnir will detect the actions you 30 | have taken. Once Draupnir has detected a ban or an unban, Draupnir 31 | will send a prompt to the management room asking whether to create a 32 | policy which will be enforced across the entire set of protected 33 | rooms. 34 | 35 | It's important to note that if you ban a user from a room in your 36 | client, then the user will be able to see that your account banned 37 | them. If you need anonymity, then you can use the [ban 38 | command](#the-ban-command). 39 | 40 | When unbanning a user with the `BanPropagationProtection`, the target 41 | user will be unbanned from the protected rooms set and the associated 42 | policies will be removed from all lists where Draupnir has write 43 | access. 44 | 45 | ## The `ban` command 46 | 47 | In order to preserve anonymity while issuing a ban, you can use the 48 | ban command. 49 | 50 | In order to do so, you must first know which list you want to create 51 | the policy within. If you are unsure about which list to use, you can 52 | check the `!draupnir status` to see which lists you have watched. 53 | 54 | Alternatively, you can just use `!draupnir ban @spam:example.com` and 55 | follow the prompts. During the prompt stage, Draupnir will only show 56 | policy rooms that you have write access for. 57 | 58 | ## The `unban` command 59 | 60 | The `unban` command Works exactly the same way as the ban command, 61 | although please note that you will need to provide the option `--true` 62 | if you want the command to unban users from all rooms. 63 | 64 | ## Wildcards 65 | 66 | It is possible to create policies that target a range of users 67 | by using wildcards. For instance, if I wanted to target all of 68 | the users with `spam` in their mxid from the server `example.com`, 69 | then i would use the pattern `@*spam*:example.com`. 70 | 71 | Be very careful when issuing with wildcards, as it can be difficult to 72 | predict their effect. 73 | 74 | You can find the specification for Matrix's glob syntax [here](https://spec.matrix.org/v1.8/appendices/#glob-style-matching). 75 | 76 | ## Redaction 77 | 78 | If a user has sent a large number of messages to a Matrix room, you 79 | can use the `!draupnir redact` command to clean up the room. So for 80 | example if the user `@spam:example.com` has spammed 81 | `#my-room:example.com`, then issuing the following command will redact 82 | the messages sent by `@spam:example.com` up to a limit: `!draupnir 83 | redact @spam:example.com #my-room:example.com`. 84 | 85 | ## Automatic redaction 86 | 87 | There is limited support for automatic redactions when Draupnir issues 88 | a ban. These are triggered by the words configured under the 89 | `automaticallyRedactForReasons` key in Draupnir's config. 90 | -------------------------------------------------------------------------------- /docs/governance/reports/2510A-cycle-review.md: -------------------------------------------------------------------------------- 1 | # 2025-10-A: Longhouse Cycle Review 2 | 3 | ## Overview 4 | 5 | _written by @Gnuxie_ 6 | 7 | Milestone: https://github.com/the-draupnir-project/planning/milestone/1 8 | 9 | It's become clear to me that I need to feel closer to draupnir users in order to 10 | continue effective development of the project. And to achieve this, I've worked 11 | to create new governance and planning changes for the project. With the primary 12 | aim of giving draupnir users control over the project direction. And a way to 13 | affirm contributors for the work being done. 14 | 15 | As a part of this, development conducted by the _root contribution circle_ will 16 | now take place over cycles that aren't bounded by time. Cycles are used to work 17 | on iterations of work and report back to the community on the results. Adding 18 | accountability between core contributors and users. This is done in a way that 19 | explicitly preserves voluntary association in both directions. 20 | 21 | ## Direction 22 | 23 | 24 | 25 | The longer context of this is that the goals of the 26 | [NLnet grant](https://marewolf.me/posts/draupnir/24-nlnet-goals.html) were 27 | designed when I was less experienced at project management, and this meant that 28 | the roadmap was effectively rigid. This meant that we were opportunistically at 29 | a major disadvantage. To adapt the roadmap to changes in circumstance, such as 30 | the need for homeserver admin tools earlier in the year, and project hydra 31 | itself, meant putting NLnet work on hold. Additionally, we didn't have a 32 | mechanism to receive affirmation or support for the decisions that we made to 33 | suspend that work. And I think that such a mechanism is needed because I crashed 34 | out a number of times. Draupnir is not just some personal project, it is an 35 | obligation and this work is responsible for the continuance of _a lot_ of 36 | communities. 37 | 38 | The [NLnet grant](https://marewolf.me/posts/draupnir/24-nlnet-goals.html) itself 39 | will be expiring in December. And for full transparency I have received around 40 | €9.7k in total from NLnet to support development that has been going on for well 41 | over a year. This has been my main income, and only income outside of my ko-fi 42 | and GitHub sponsors, since 2022, and this has allowed me to develop Draupnir as 43 | a primary occupation. I'm incredibly grateful for the grant, but I need to make 44 | clear that this is a grant that kept Draupnir afloat and there has to be a more 45 | sustainable solution for the project. In addition, I have mostly supported this 46 | work with savings I made from my from prior jobs and living as frugally as a 47 | student, at great sacrifice to myself. 48 | 49 | Therefore it's desirable to close off some milestones before the grant expires 50 | so that development can continue into 2026. And this will mean putting project 51 | hydra mitigation (room upgrade support) on hold. 52 | 53 | The aim of the governance rework that has taken place is simply to confirm that 54 | the work being done on this project is valuable to its users. 55 | 56 | ## Completed work this cycle 57 | 58 | _Note: this isn't all work that has been completed, this section just relates to 59 | the goals of the cycle_. 60 | 61 | - Entirely new [governance documentation](../governance.md) for the project. 62 | 63 | - A news reader in Draupnir to inform end users about development progress and 64 | updates. 65 | 66 | - A new [planning](../../contributing/planning.md) system has been designed to 67 | support open decision making. It's not entirely new, but more documenting and 68 | formalising the system that was already in use, then revising it a couple of 69 | times. 70 | 71 | - A new Matrix space to facilitate feedback and governance participation, called 72 | [the Draupnir longhouse](https://matrix.to/#/%23the-draupnir-longhouse:matrix.org). 73 | -------------------------------------------------------------------------------- /docs/concepts/room-essentials.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 0 3 | sidebar_label: Room essentials 4 | --- 5 | 6 | 11 | 12 | # Room essentials 13 | 14 | In Matrix, the place where you talk and see other users is called a 15 | Matrix room. This is Matrix's equivalent to *channels* that you might 16 | be familiar with on other platforms. 17 | 18 | ## Events 19 | 20 | Everything that happens in Matrix is expressed with *events*. 21 | This includes everything from the messages that you send to other 22 | users, notifications that are sent to show that you are typing, 23 | and profile changes such as changing your displayname within 24 | a Matrix room. 25 | 26 | These events accumulate in the room *timeline*, which is the what you 27 | can see when you look at a Matrix room within your client. 28 | 29 | You can read what the Matrix specification has to say for events [here](https://spec.matrix.org/latest/client-server-api/#events) 30 | 31 | ## State events 32 | 33 | Matrix also has a concept of *state events*. These are special events 34 | that servers, bots, bridges and clients all use to store and retrieve 35 | data associated with the room easily. For example, the avatar 36 | and displayname of a given user in a Matrix room is stored within 37 | a state event to make it convenient for clients to access. 38 | 39 | ## Authorization events 40 | 41 | Matrix also has a concept of *authorization events*. These are special 42 | *state events* that are used to control what other events can be 43 | sent to the room. For example, the `m.room.power_levels` event is 44 | an authorization event that can be used to control which users can 45 | send messages to a room. 46 | 47 | Your own membership event, of the type `m.room.member`, is also an 48 | authorization event, that authorizes you to participate within a 49 | Matrix room. 50 | 51 | ## Membership 52 | 53 | When you join a Matrix room, your homeserver creates a membership 54 | state event in the room that you are joining. This membership event 55 | tells all of the servers present within the room that you are also 56 | present so that they can authorise your messages. They will also 57 | use the event to remember to send your homeserver new messages. 58 | 59 | This membership state event is called `m.room.member`, you can read 60 | the specification for the event 61 | [here](https://spec.matrix.org/latest/client-server-api/#room-membership) 62 | 63 | The membership event has a protected content field called `membership`, 64 | which describes the membership state for a Matrix user in a room. 65 | 66 | Whenever you ban or remove a user from a room, your homeserver has to 67 | create a membership event for that user that supersedes their current 68 | membership event. Explicitly marking the target user's membership as 69 | `ban` or `leave`. 70 | 71 | ## Lazy bans 72 | 73 | Unfortunately, due to the nature of Matrix and state events, Draupnir 74 | has to issue bans lazily. What this means is that Draupnir will not 75 | ban users from Matrix rooms until they have joined. Normally the ban 76 | will be issued by Draupnir instantaneously. 77 | 78 | It is technically possible for room moderators to issue bans 79 | preemptively, however if there is another user within the room from 80 | the same server as the target of the ban, then the target will be 81 | force-joined to the Matrix room. This normally is not a problem, but 82 | for private rooms this behaviour can actually alert the target of the 83 | presence of the room and give them access to the title and profile 84 | picture. 85 | 86 | The other reason Draupnir does not prematurely apply bans is that this 87 | would lead Draupnir to send thousands of redundant state events to 88 | every room that is being protected. This is because most of the users 89 | that are banned will never actually attempt to join a room. These 90 | events can degrade the performance of all servers that are 91 | participating. 92 | -------------------------------------------------------------------------------- /docs/concepts/power-levels.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | sidebar_label: Matrix power levels 4 | --- 5 | 6 | 17 | 18 | # Matrix power levels 19 | 20 | Instead of a system like roles that you may be familiar with, Matrix has a 21 | system called power levels. A power level is a number that normally ranges 22 | between 0 to 100[^power-levels-range]. Within a room, each user has a power level 23 | and each _permission_ also has a power level. For a user to be 24 | able to use a _permission_, to for example remove a user, they have to have 25 | the same (or a greater) power level than the power level of the permission. 26 | 27 | ## Standard roles 28 | 29 | By default, Matrix homeservers and clients use different power levels to define 30 | three roles: 31 | 32 | | Power Level | Role | 33 | | ----------- | ------------- | 34 | | 0 | User | 35 | | 50 | Moderator | 36 | | 100 | Administrator | 37 | 38 | With the defaults, each member of a role will be able to do the following: 39 | 40 | - **Users** can send messages, media, reactions and redact their own messages in 41 | a room. 42 | - **Moderators** can also change the room name, address, topic, remove users 43 | from the room (temporarily or permanently), redact other's messages and send a 44 | notification to everyone in the room at once using `@room`. 45 | - **Administrators** can also change the history visibility (whether people can 46 | see messages from before they joined or not), enable encryption in the room, 47 | remove entire servers from the room, and promote others to Moderator or 48 | Administrator. 49 | 50 | Most members of a community are going to be regular users. Usually 51 | Moderators are appointed to handle ad-hoc moderation issues, for example 52 | removing or banning spam bots. 53 | 54 | If you're taking over a community previously managed by someone with a high 55 | level of technical expertise in Matrix, it could be possible that the roles may 56 | not be the same. That's to say that the previous administrator could have 57 | deviated from the defaults[^help]. 58 | 59 | ## Permissions 60 | 61 | Room permissions are broken down into three types: permissions, event 62 | permissions, and state permissions. 63 | 64 | ### Standard permissions 65 | 66 | Standard permissions include the ability to `ban` another room member, `redact` 67 | another room member's messages, `invite` new user's to the room, and `kick` 68 | members from the room. These are all fields that are _top level_ to the content 69 | of the `m.room.power_levels` event, and all have an associated power level. 70 | You can find the defaults [here](https://spec.matrix.org/latest/client-server-api/#mroompower_levels). 71 | 72 | ### Event permissions 73 | 74 | Event permissions are used to encode the power level required for a user to send 75 | a Matrix event of a given `type`. So for example, the ability for a user to send 76 | most messages to a room would be `m.room.message`. These can be specified under 77 | the `events` field at the top level of the `m.room.power_levels` event content. 78 | 79 | If the `type` of an event cannot be found under the `events` field, then the 80 | power level of the `events_default` field at the top level of the 81 | `m.room.power_levels` event content will be used instead. 82 | 83 | ### State permissions 84 | 85 | State permissions are used to encode the power level required for a user to send 86 | a state event of a given `type`. Usually you do not want to give users the 87 | ability to send state events. 88 | 89 | If the `type` of a state event cannot be found under the `events` field, then 90 | the power level of the `state_default` field at the top level of the 91 | `m.room.power_levels` event content will be used instead. 92 | 93 | ## See also 94 | 95 | - [The matrix specification for `m.room.power_levels`](https://spec.matrix.org/latest/client-server-api/#mroompower_levels) 96 | 97 | [^power-levels-range]: Advanced users may use a different range. 98 | [^help]: 99 | In that case, we recommend you to join the draupnir support room for 100 | help [#draupnir:matrix.org](https://matrix.to/#/#draupnir:matrix.org). 101 | 102 | [^power-levels-spec]: The Matrix Specification for `m.room.power_levels` https://spec.matrix.org/latest/client-server-api/#mroompower_levels. 103 | -------------------------------------------------------------------------------- /docs/bot/synapse_module.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: Synapse module 3 | --- 4 | 5 | 6 | # Synapse module 7 | 8 | :::info 9 | 10 | The version of the Synapse module in the Draupnir repository that was inherited from Mjolnir has been removed. 11 | The module was unmaintained and untouched for its whole lifetime in Draupnir, and we always directed 12 | users to the Mjolnir version, which still exists and is still compatible with Draupnir's policy lists. 13 | 14 | ::: 15 | 16 | :::warning 17 | 18 | When Synapse workers are used, changes to policy lists may not 19 | propagate to all workers until Synapse is restarted. 20 | 21 | ::: 22 | 23 | :::tip 24 | 25 | See also configuration of [synapse-http-antispam](./synapse-http-antispam). 26 | 27 | ::: 28 | 29 | **This requires Synapse 1.53.0 or higher** 30 | 31 | The Synapse module is intended to be used to apply policies to the 32 | entire homeserver, to affect all of your users. This is primarily 33 | meant to block invites from undesired homeservers/users, Mjolnir's 34 | Synapse module is a way to interpret ban lists and apply them to your 35 | entire homeserver. 36 | 37 | First, install the module to your Synapse python environment: 38 | 39 | ```bash 40 | pip install -e "git+https://github.com/matrix-org/mjolnir.git#egg=mjolnir&subdirectory=synapse_antispam" 41 | ``` 42 | 43 | _Note_: Where your python environment is depends on your installation method. Visit 44 | [#synapse:matrix.org](https://matrix.to/#/#synapse:matrix.org) if you're not sure. 45 | 46 | Then add the following to your `homeserver.yaml`: 47 | 48 | ```yaml 49 | modules: 50 | - module: mjolnir.Module 51 | config: 52 | # Prevent servers/users in the ban lists from inviting users on this 53 | # server to rooms. Default true. 54 | block_invites: true 55 | # Flag messages sent by servers/users in the ban lists as spam. Currently 56 | # this means that spammy messages will appear as empty to users. Default 57 | # false. 58 | block_messages: false 59 | # Remove users from the user directory search by filtering matrix IDs and 60 | # display names by the entries in the user ban list. Default false. 61 | block_usernames: false 62 | # The room IDs of the ban lists to honour. Unlike other parts of Mjolnir, 63 | # this list cannot be room aliases or permalinks. This server is expected 64 | # to already be joined to the room - Mjolnir will not automatically join 65 | # these rooms. 66 | ban_lists: 67 | - "!roomid:example.org" 68 | #message_max_length: 69 | # Limit the characters in a message (event body) that a client can send in an event on this server. 70 | # By default there is no limit (beyond the the limit the spec enforces on event size). 71 | # Uncomment if you want messages to be limited to 510 characters. 72 | # threshold: 510 73 | 74 | # Limit messages only in certain rooms rooms. 75 | # By default all rooms will enforce the limit. 76 | # Uncomment if you want messages to only be subject to character limits in certain rooms. 77 | # rooms: 78 | # - "!vMvyOCeCxHsggkmALd:localhost:9999" 79 | 80 | # Also hide messages from remote servers that are over the `message_limit`. 81 | # By default only events from this server will be limited. 82 | # WARNING: Remote users on other servers will still be able to messages over the limit. 83 | # Uncomment to enforce the `message_limit` on events from remote servers. 84 | # remote_servers: true 85 | ``` 86 | 87 | _Note_: Although this is described as a "spam checker", it does much more than fight 88 | spam. 89 | 90 | Be sure to change the configuration to match your setup. Your server is expected to 91 | already be participating in the ban lists - if it is not, you will need to have a user 92 | on your homeserver join. The antispam module will not join the rooms for you. 93 | 94 | If you change the configuration, you will need to restart Synapse. You'll also need 95 | to restart Synapse to install the plugin. 96 | 97 | ### Docker 98 | 99 | Installations that use the Docker image of `synapse` that wish to use the synapse module require the `./Draupnir/synapse_antispam/mjolnir` project directory to be bind mounted into the `synapse` container's `/usr/local/lib/python3.12/site-packages/mjolnir` directory. Clone the project (`git clone https://github.com/the-draupnir-project/Draupnir`), then use the following `docker-compose` block as an example. 100 | 101 | ```yaml 102 | version: '3.7' 103 | services: 104 | synapse: 105 | volumes: 106 | - //draupnir/synapse_antispam/mjolnir:/usr/local/lib/python3.12/site-packages/mjolnir 107 | ``` 108 | -------------------------------------------------------------------------------- /docs/contributing/code-style.md: -------------------------------------------------------------------------------- 1 | # Code style 2 | 3 | For now we don't have many objective code recommendations. Just try to stay 4 | consistent with the rest of the project, if that is alien to you, it's ok, just 5 | try. In the worst case we will clean things up for you. 6 | 7 | We give some general advice about style below. 8 | 9 | ## Code style: optimisation 10 | 11 | One of the most important things a Draupnir developer should do is let to go of 12 | any tendencies that they may have towards micro optimisation. We want clear code 13 | so much more than anything else, optimisation should not be a concern at all 14 | when actually writing code. 15 | 16 | If you are somewhat unseasoned, you may find this somewhat puzzling. 17 | 18 | We believe the only way to effectively optimise is through design, and the use 19 | of a profiler. There are very few things more inefficient for programmers to 20 | work with than code written with overbearing concerns about performance. Using 21 | idioms and data structures appropriate for the programming language and problem 22 | being solved will always be enough. And I invite you to believe that, if micro 23 | optimisation is something you struggle with, then tell yourself that it does not 24 | matter. 25 | 26 | ## Code style: scope 27 | 28 | You might notice that we try to keep the scope (which by "scope" here we really 29 | mean "how much stuff" is in a function/method) as small as possible. This is 30 | something you should stick to as well. 31 | 32 | It really helps to introduce local functions if your method body starts getting 33 | too large. I can't really tell you how large too large is, but this quote 34 | captures the spirit well. 35 | 36 | > A friend of mine was once interviewing an engineer for a programming job and 37 | > asked him a typical interview question: how do you know when a function or 38 | > method is too big? Well, said the candidate, I don't like any method to be 39 | > bigger than my head. You mean you can't keep all the details in your head? No, 40 | > I mean I put my head up against my monitor, and the code shouldn't be bigger 41 | > than my head. 42 | 43 | Quote from Peter Seibel's 44 | [Practical Common Lisp](https://gigamonkeys.com/book/). 45 | 46 | ## Code style: `const` 47 | 48 | Something you may notice is that we almost always try to use `const`. `const` 49 | should be the default when introducing a lexical variable (that's to say use 50 | `const` instead of `let` and `var`). 51 | 52 | You will very likely reach a point where you need to reassign a lexical 53 | variable. Don't stress too much about it, give it a try but if it's not 54 | practical then don't worry about using `let`, it's ok. 55 | 56 | A common hack that we use is an 57 | [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) if you have to, 58 | or just make local helper functions like so: 59 | 60 | ### Why we do this? 61 | 62 | This improves the quality of code in numerous ways. First of all, we don't have 63 | to check if a variable is null, undefined, or some other default value because 64 | the variable is always initialized. Second of all it signals that we cannot 65 | reassign anything half way down the function body, and that takes off some 66 | mental load we'd otherwise have to worry about. 67 | 68 | ## Code style: parameterized dependencies 69 | 70 | Whenever a module or component is being developed, it is essential to ensure 71 | that its dependencies are expressed as parameters. This ensures that code is 72 | modular, and as a result it is also more testable and understandable. 73 | 74 | Consider the behaviour to protect replacement rooms in Draupnir upon the receipt 75 | of a tombstone event. This behaviour is implemented by a class named 76 | `ProtectReplacementRooms`. 77 | 78 | ```typescript 79 | export class ProtectReplacementRooms { 80 | public constructor( 81 | private readonly managementRoomID: StringRoomID, 82 | private readonly roomJoiner: RoomJoiner, 83 | private readonly roomMessageSender: RoomMessageSender, 84 | private readonly protectedRoomsManager: ProtectedRoomsManager 85 | ) { 86 | // nothing to do. 87 | } 88 | } 89 | ``` 90 | 91 | This class needs to join the replacement room, protect it using the _protected 92 | rooms manager_, and then send a message to the management room using the 93 | `managementRoomID`, and the `RoomMessageSender`. 94 | 95 | If we wanted to unit test this class, we can already see all of the dependencies 96 | that we might need to provide or mock. And we don't need to setup a huge 97 | environment or harness. 98 | 99 | For unit testing generally we recommend using _Working Effectively with Legacy 100 | Code_ by Michael C. Feathers as a reference. And also a survival guide if you 101 | are in the industry. 102 | -------------------------------------------------------------------------------- /docs/bot/homeserver-administration.md: -------------------------------------------------------------------------------- 1 | # Homeserver administration 2 | 3 | 4 | 5 | :::danger 6 | 7 | The Matrix protocol is unsafe by default. Your homeserver will be abused by 8 | malicious actors, and your resident users will receive unsolicited abuse. If you 9 | have a homeserver with public registration you will want to read this section 10 | carefully. ALL of the offered homeserver protections in this document are 11 | recommended and necessary to maintain a safe homeserver on Matrix. If you have 12 | concerns about a specific protection or use case, please reach out to us in 13 | [#draupnir:matrix.org](https://matrix.to/#/%23draupnir%3Amatrix.org). We are 14 | happy to make changes or offer advice. 15 | 16 | ::: 17 | 18 | ## Draupnir protections & features 19 | 20 | Draupnir offers capabilities for homeserver admins that are particularly 21 | relevant when registration on a homeserver is open or public 22 | 23 | These features may require either a 24 | [synapse admin account](./setup_draupnir_account#making-draupnir-a-synapse-admin) 25 | or [synapse-http-antispam](./synapse-http-antispam) to be available to Draupnir. 26 | 27 | ### Room takedown protection 28 | 29 | The [Room takedown protection](../protections/room-takedown-protection) can 30 | provide insight into the Matrix rooms your server is participating in and allow 31 | them to be blocked and taken down. This protection is essential to prevent 32 | resident users joining rooms containing CSAM or other abusive content, including 33 | receiving unsolicited invitations to such rooms. 34 | 35 | - See the [Room takedown protection](../protections/room-takedown-protection). 36 | 37 | ### Block invitations on server protection 38 | 39 | The 40 | [block invitations on server protection](../protections/block-invitations-on-server-protection) 41 | provides invitation management. Draupnir can block invitations from users, 42 | servers, or rooms. And reject invitations sent on behalf of your users that were 43 | sent from taken down rooms when used in conjunction with the _room takedown 44 | protection_. 45 | 46 | - See the 47 | [Block invitations on server protection](../protections/block-invitations-on-server-protection). 48 | - See the [Room takedown protection](../protections/room-takedown-protection) 49 | 50 | ### Homeserver user policy protection 51 | 52 | Resident user accounts can be automatically suspended via the 53 | [Homeserver user policy protection](../protections/homeserver-user-policy-protection) 54 | when Draupnir receives a matching policy. Draupnir can also be prompted for 55 | deactivation. 56 | 57 | - See the 58 | [Homeserver user policy protection](../protections/homeserver-user-policy-protection). 59 | 60 | ### Suspension and account restriction 61 | 62 | Resident user accounts can be managed using commands: 63 | 64 | - The `!draupnir deactivate` command will prompt for confirmation before 65 | deactivation and can optionally purge all messages. While purging messages, 66 | users will be shadowbanned. 67 | - The `!draupnir unrestrict` command can be used to unsuspend or unshadowban 68 | users. 69 | - The `!draupnir suspend` command can suspend users without logging them out. 70 | 71 | ### Report forwarding 72 | 73 | - Report forwarding and review: Draupnir can be used to view reports submitted 74 | by users on your homeserver. 75 | 76 | #### Enabling readable abuse reports 77 | 78 | Draupnir offers the ability to replace the Matrix endpoint used to report abuse 79 | and display it into a room, instead of requiring you to request this data from 80 | an admin API. 81 | 82 | This requires two configuration steps: 83 | 84 | 1. In your Draupnir configuration file, typically 85 | `/etc/draupnir/config/production.yaml`, copy and paste the `web` section from 86 | `default.yaml`, if you don't have it yet (it appears with version 1.20) and 87 | set `enabled: true` for both `web` and `abuseReporting`. 88 | 2. Setup a reverse proxy that will redirect requests from 89 | `^/_matrix/client/(r0|v3)/rooms/([^/]*)/report/(.*)$` to 90 | `http://host:port/api/1/report/$2/$3`, where `host` is the host where you run 91 | Draupnir, and `port` is the port you configured in `production.yaml`. For an 92 | example nginx configuration, see `test/nginx.conf`. It's the confirmation we 93 | use during runtime testing. 94 | 95 | #### Security note 96 | 97 | This mechanism can extract some information from **unencrypted** rooms. We have 98 | taken precautions to ensure that this cannot be abused: the only case in which 99 | this feature will publish information from room _foo_ is: 100 | 101 | 1. If it is used by a member of room _foo_; AND 102 | 2. If said member did witness the event; AND 103 | 3. If the event was unencrypted; AND 104 | 4. If the event was not redacted/removed/... 105 | 106 | Essentially, this is a more restricted variant of the Admin APIs available on 107 | homeservers. 108 | 109 | However, if you are uncomfortable with this, please do not activate this 110 | feature. Also, you should probably setup your `production.yaml` to ensure that 111 | the web server can only receive requests from your reverse proxy (e.g. 112 | `localhost`). 113 | -------------------------------------------------------------------------------- /docs/bot/setup_debian.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | sidebar_label: Installation on Debian 4 | --- 5 | 6 | 7 | 8 | # Installation on Debian 9 | 10 | :::tip 11 | 12 | These are instructions for the installation of draupnir from source on Debian. 13 | This installation method is intended for experienced sysadmins. 14 | 15 | ::: 16 | 17 | ## Installation 18 | 19 | install git curl and sudo 20 | 21 | ```shell 22 | apt update && apt install -y git curl sudo 23 | ``` 24 | 25 | install node 20 from the node source repo, the full instructions can be found at https://nodesource.com/products/distributions 26 | 27 | ```shell 28 | curl -fsSL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh 29 | bash nodesource_setup.sh 30 | apt update && apt install nodejs -y 31 | ``` 32 | 33 | install yarn via npm 34 | 35 | ```shell 36 | npm install --global yarn 37 | ``` 38 | 39 | create the directory to clone the repo 40 | 41 | ```shell 42 | mkdir /opt/mod-bot 43 | ``` 44 | 45 | clone the repo and fetch the tags 46 | 47 | ```shell 48 | git clone https://github.com/the-draupnir-project/Draupnir.git /opt/mod-bot/Draupnir 49 | ``` 50 | 51 | ```shell 52 | git -C /opt/mod-bot/Draupnir fetch --tags 53 | ``` 54 | 55 | create the directory for draupnirs datastorage 56 | 57 | ```shell 58 | mkdir /opt/mod-bot/Draupnir/datastorage 59 | ``` 60 | 61 | add corepack 62 | 63 | ```shell 64 | yarn global add corepack 65 | ``` 66 | 67 | add a user to run the bot 68 | this user will be used by systemd to run the bot since there is no need to run it with root permissions 69 | 70 | ```shell 71 | useradd -m draupnir 72 | ``` 73 | 74 | give ownership of the draupnir directory to the bot user 75 | 76 | ```shell 77 | chown -R draupnir:draupnir /opt/mod-bot/Draupnir 78 | ``` 79 | 80 | build the bot with yarn 81 | 82 | ```shell 83 | sudo -u draupnir bash -c "cd /opt/mod-bot/Draupnir && yarn install" 84 | sudo -u draupnir bash -c "cd /opt/mod-bot/Draupnir && yarn build" 85 | ``` 86 | 87 | ## Edit the config 88 | 89 | copy the default config to production.yaml 90 | 91 | ```shell 92 | cp /opt/mod-bot/Draupnir/config/default.yaml /opt/mod-bot/Draupnir/config/production.yaml 93 | ``` 94 | 95 | change the path of the datadirectory from the default to the directory we created earlier since the default dir is for the docker setup 96 | 97 | ```shell 98 | sed -i 's|dataPath: "/data/storage"|dataPath: "/opt/mod-bot/Draupnir/datastorage"|' /opt/mod-bot/Draupnir/config/production.yaml 99 | ``` 100 | 101 | edit the production config: 102 | the most important things to configure are the `homeserverUrl:`, the `rawHomeserverUrl:`, the `accessToken:` and the `managementRoom:` 103 | 104 | ```shell 105 | nano /opt/mod-bot/Draupnir/config/production.yaml 106 | ``` 107 | 108 | ## Example systemd service 109 | 110 | copy this to `/etc/systemd/system/draupnir.service` and enable with `systemctl enable draupnir`, then simply start with `systemctl start draupnir` 111 | 112 | :::tip 113 | 114 | before you attempt to start the service, make sure that the management room for draupnir exists on your homeserver and is joinable by draupnir (either public room or invite the bot account in advance) 115 | 116 | ::: 117 | 118 | ```ini 119 | [Unit] 120 | Description=Draupnir 121 | #After=matrix-synapse.service # You can enable this if your matrix server is synapse, otherwise you might want to change it to the service that starts your homeserver 122 | #After=matrix-synapse.target # You can enable this if your matrix server is synapse and you have installed workers via the official instructions 123 | 124 | [Service] 125 | ExecStart=/usr/bin/node /opt/mod-bot/Draupnir/lib/index.js --draupnir-config /opt/mod-bot/Draupnir/config/production.yaml 126 | WorkingDirectory=/opt/mod-bot/Draupnir 127 | Restart=always 128 | User=draupnir 129 | Environment=PATH=/usr/bin:/usr/local/bin 130 | Environment=NODE_ENV=production 131 | SyslogIdentifier=draupnir 132 | 133 | ReadWritePaths=/opt/mod-bot/Draupnir 134 | NoNewPrivileges=yes 135 | PrivateDevices=yes 136 | PrivateTmp=yes 137 | ProtectHome=yes 138 | ProtectSystem=strict 139 | ProtectControlGroups=true 140 | RestrictSUIDSGID=true 141 | RestrictRealtime=true 142 | LockPersonality=true 143 | ProtectKernelLogs=true 144 | ProtectKernelTunables=true 145 | ProtectHostname=true 146 | ProtectKernelModules=true 147 | PrivateUsers=true 148 | ProtectClock=true 149 | SystemCallArchitectures=native 150 | SystemCallErrorNumber=EPERM 151 | SystemCallFilter=@system-service 152 | # EnvironmentFile=-/path/to/env/file # Optional: if you want to load environment variables from a file 153 | 154 | [Install] 155 | WantedBy=multi-user.target 156 | ``` 157 | 158 | ## Updating the bot 159 | 160 | if you want to update && upgrade everything, use the draupnir useraccount in order to not create conflicts with filepermissions/ownerships 161 | 162 | stop the bot 163 | 164 | ```shell 165 | systemctl stop draupnir 166 | ``` 167 | 168 | pull updates from github with 169 | 170 | ```shell 171 | sudo -u draupnir bash -c "cd /opt/mod-bot/Draupnir && git pull && git fetch --tags" 172 | ``` 173 | 174 | install/update yarn 175 | 176 | ```shell 177 | sudo -u draupnir bash -c "cd /opt/mod-bot/Draupnir && yarn install" 178 | ``` 179 | 180 | build the bot 181 | 182 | ```shell 183 | sudo -u draupnir bash -c "cd /opt/mod-bot/Draupnir && yarn build" 184 | ``` 185 | 186 | then simply start the bot again with 187 | 188 | ```shell 189 | systemctl restart draupnir 190 | ``` 191 | -------------------------------------------------------------------------------- /docs/moderator/managing-protected-rooms.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | sidebar_label: Managing protected rooms 4 | --- 5 | 6 | 11 | 12 | # Protecting rooms 13 | 14 | Draupnir functions by protecting a set of rooms, called the protected 15 | rooms set. Draupnir works by applying protections across the set of 16 | protected rooms, and some of these protections in turn work to enforce 17 | policies across the same set of protected rooms. 18 | 19 | When you first use Draupnir, Draupnir will not know which 20 | rooms to protect yet, and so you will need to configure which rooms 21 | that you want Draupnir to protect. 22 | 23 | ## Confirming the protection status of a room 24 | 25 | If you are unsure whether Draupnir is protecting a room, you can issue 26 | the `!draupnir rooms list` command to view a list of rooms that 27 | Draupnir is currently protecting. You may wish to do this after 28 | attempting to protect rooms with the following methods, so that you 29 | can confirm that all is ok. 30 | 31 | ## Inviting Draupnir to rooms 32 | 33 | Just by inviting your Draupnir bot to rooms, Draupnir will ask you 34 | within the management room whether you wish to protect the room. 35 | 36 | The answer to the question can be given by clicking on the reactions 37 | in your Matrix client. By selecting 'Ok', Draupnir will protect the 38 | room, and if all goes well Draupnir will leave behind a green tick 39 | once this is complete. 40 | 41 | ## Using the Draupnir `rooms` command 42 | 43 | You can also manage which rooms Draupnir is protecting by using the 44 | `!draupnir rooms add` and the `!draupnir rooms remove` commands. 45 | 46 | If the room you are protecting is private, you will first need to 47 | invite your Draupnir bot user to the room that you are trying to 48 | protect. 49 | 50 | If you believe Draupnir is able to freely join the room you are trying 51 | to protect, you can now use the `!draupnir rooms add` command. 52 | 53 | ### Obtaining a room reference 54 | 55 | In order to refer to the room that you are trying to manage, you will 56 | need to obtain a reference to the room. The easiest way to do this is 57 | to go to the room that you are trying to manage in your client. Then 58 | once you can see the room timeline, go to the "room info" section or 59 | "room settings". From there you should be able to "copy link" or 60 | "share" the room. You want to then copy this link and provide it to 61 | Draupnir like so: `!draupnir rooms add ` which will look 62 | like this: `!draupnir rooms add 63 | https://matrix.to/#/#my-room:example.com`. 64 | 65 | The same can be done if you are trying to remove a room 66 | `!draupnir rooms remove ` which will look like this 67 | `!draupnir rooms remove https://matrix.to#/#my-room:example.com`. 68 | 69 | ## Giving Draupnir permissions 70 | 71 | Once Draupnir is protecting a room, Draupnir may start to complain 72 | about missing permissions. You will want to first take note of which 73 | permissions Draupnir has described as missing. Then you will go to the 74 | protected room's settings in your client and give Draupnir the 75 | "Admin" power level. 76 | 77 | To understand how permissions work in Matrix, you can review our 78 | power levels document [here](../concepts/power-levels). 79 | 80 | ## Using Rory&'s Matrix Utils 81 | 82 | A third party tool can be used to quickly add entire groups of rooms to 83 | be protected Draupnir. You will have to sign in using the same account 84 | as Draupnir, so this is only supported by users of "bot mode" for now. 85 | You can find the tool [here](https://mru.rory.gay/Moderation/DraupnirProtectedRoomsEditor). 86 | 87 | ## Protecting encrypted rooms 88 | 89 | :::warning 90 | 91 | When public Matrix rooms are encrypted, untrusted parties can deny 92 | Draupnir, yourself, and your moderators access to the decryption keys 93 | of malicious messages. Meaning that you will be unable to read them, 94 | while the rest of your community can. 95 | 96 | ::: 97 | 98 | :::info 99 | 100 | Draupnir can still protect encrypted rooms without an E2EE capable 101 | device. 102 | 103 | ::: 104 | 105 | Draupnir can still protect encrypted rooms even without enabling any 106 | E2EE device for Draupnir to use. Most functionality will 107 | work without any problem, however some protections will be unable to 108 | reliably function. Specifically any protection that needs to access 109 | the content of an event can encounter problems. This includes 110 | protections such as `WordList` and `FirstMessageIsImage`. 111 | 112 | If your Draupnir deployment supports encryption, protections that 113 | require access to event content can be bypassed by malicious 114 | users. The Matrix specification currently does not provide mechanisms 115 | that allow a device to get message keys from third parties, so unless 116 | Draupnir is provided keys directly from the event sender, then 117 | Draupnir will be unable to decrypt a given message. While considering 118 | the frequency of E2EE issues, Draupnir can not make a choice to 119 | sanction users for not providing keys automatically, which could 120 | otherwise be used as a workaround. 121 | 122 | The E2EE functionality is not part of the Dogfooding program that 123 | Draupnir has in place as an extra layer of quality assurance above 124 | that offered by our CI testing. You can read more about this program 125 | in [The Dogfood Guide](/shared/dogfood.md). 126 | -------------------------------------------------------------------------------- /docs/matrix-protection-suite/concepts/revisions.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | sidebar_label: Revisions 4 | --- 5 | 6 | 11 | 12 | # Revisions 13 | 14 | :::tip 15 | 16 | This page is intended for advanced users of Draupnir and protection 17 | developers, who want to understand how protections work within the 18 | matrix-protection-suite. Revisions are probably the most important 19 | component of the matrix-protection-suite. 20 | 21 | ::: 22 | 23 | :::note 24 | 25 | There may be a legitimate name for this pattern, that we have 26 | independently recreated. 27 | 28 | ::: 29 | 30 | ## Introduction to revisions 31 | 32 | The matrix-protection-suite uses _revisions_ to model various forms of 33 | state in Matrix. These are immutable snapshots that accurately reflect 34 | some state at the point the revision was created. 35 | 36 | Revisions can be used for almost anything, but as a list of examples 37 | revisions are usually used to model the Matrix room state, or a collection 38 | of moderation policies, and even the rooms that a matrix user is joined to 39 | at a point in time. 40 | 41 | ### Evaluating the utility of revisions 42 | 43 | There are a few reasons why we use an immutable snapshot to model. 44 | 45 | * Avoiding a situation where an asynchronous task consuming a model 46 | of room state races with a service responsible for updating the model. 47 | Essentially if a background task is running incrementally against a model, 48 | the model changing half way through could have unintended consequences. 49 | 50 | * The ability to cheaply create copies of models with slight 51 | variations, for the purpose of dry-running protections against new 52 | moderation policies or room state. Or dry-running commands and other 53 | changes, and being able to provide a preview of the outcome. 54 | 55 | * Being able to see exactly what changed between one update and the 56 | previous. _Revision issuers_ provide both the new current and 57 | previous revisions as well as a delta that describes exactly how the 58 | revisions were changed. This allows for very efficient and precise 59 | responses to updates, where only the changes need to be considered 60 | by the consumer. Previous versions of Draupnir and Mjolnir that 61 | depended on a mutable model for room state and moderation policies 62 | would need to reapply and reconsider the entire model contents, 63 | rather than just the changes. 64 | 65 | * Persistent data structures make keeping different versions of 66 | revisions very space efficient by reusing the original data 67 | structures. In other words, the original contents of a revision do 68 | not ever change, and so subsequent revisions can be encoded by 69 | wrapping the original revision with the changes. 70 | 71 | Are there any drawbacks from using revisions? 72 | 73 | * Calculating deltas between revisions can be complicated and requires 74 | robust unit testing because so much has to depend and trust this 75 | code. 76 | 77 | * The dependency graph between various _revision issuers_ can be 78 | complicated. For instance the `MembershipPolicyRevisionIssuer` 79 | depends on both a `SetMembershipRevisionIssuer` and a 80 | `PolicyListRevisionIssuer` to produce its revisions. 81 | 82 | * Without clever design in revision calculation, it is easy to create 83 | revisions where a lot of data is cached indefinitely. While 84 | previous revisions are garbage collected as soon as they stop being 85 | consumed, the current revision alone for something like the room 86 | state of a large room can be very large. 87 | 88 | ## Revision Issuers 89 | 90 | Revision issuers are responsible for revising revisions to be more 91 | accurate as state changes in Matrix. So for example, there is a 92 | `RoomMembershipRevisionIssuer` that is responsible for creating a new 93 | revision for a specific room when users join or leave it. 94 | 95 | Revision issuers always have a public property, `currentRevision`, 96 | that can be used by developers to get the most up to date revision. 97 | 98 | Revision issuers may also provide the `EventEmitter` interface so 99 | that components can provide a listener whenever a revision is created. 100 | 101 | ### The many revision issuers 102 | 103 | :::info 104 | 105 | While various interfaces described here use the `Manager` suffix, they 106 | are in reality _factories_ for revision issuers. That also enforce 107 | each revision issuer relevant to a room is a singleton. 108 | 109 | ::: 110 | 111 | :::tip 112 | 113 | If you are writing a protection, you may want to view the 114 | documentation for the various revision issuers used by the _[protected 115 | rooms 116 | set](./protected-rooms-set#the-revision-issuers-used-by-a-protectedroomsset)_ 117 | as all the revision issuers that you may need to access are provided there. 118 | 119 | ::: 120 | 121 | There are lots of revision issuers that make the 122 | matrix-protection-suite work. However, most of the time they are only 123 | used indirectly, by the handles that protections can provide when they 124 | implement the `Protection` interface. 125 | 126 | * `RoomStateRevisionIssuer` produces models of the room state, 127 | and is currently acquired by using the `RoomStateManager`. 128 | 129 | * `RoomMembershipRevisionIssuer` produces models for room membership, 130 | and is currently acquired by using the `RoomMembershipManager`. 131 | 132 | * `PolicyRoomRevisionIssuer` produces models for the policies in a 133 | matrix room's state, and is acquired by using the `PolicyRoomManager`. 134 | 135 | * `PolicyListRevisionIssuer` produces models for aggregated and virtual 136 | policy lists that make up policies from several policy rooms. These 137 | are used to implement list subscription. 138 | 139 | * `SetMembershipRevisionIssuer` produces a consolidated model for membership 140 | over a set of rooms. 141 | 142 | * `SetMembershipPolicyRevisionIssuer` produces a revision containing 143 | all of the members from a `SetMembershipRevisionIssuer` that also 144 | have matching policies from a `PolicyListRevisionIssuer`. 145 | -------------------------------------------------------------------------------- /docs/matrix-protection-suite/concepts/protection.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 0 3 | sidebar_label: Protections & Capabilities 4 | --- 5 | 10 | 11 | # Protections & Capabilities 12 | 13 | :::tip 14 | 15 | For a tutorial on how to use protections, please see [the protections 16 | tutorial](../../protections/configuring-protections). This page is for an 17 | advanced explanation of how protections work and what capabilities 18 | are. Intended for room moderators with advanced use cases and 19 | protection developers. 20 | 21 | ::: 22 | 23 | ## Overview 24 | 25 | A protection is a self contained module that can hook into a variety of 26 | different events and react to them: 27 | 28 | * Protections provide functionality that is directly useful to the end 29 | user, often in reaction to other events. 30 | - So for example, in Draupnir, a protection exists to ban room members 31 | in reaction to policies that exist on Draupnir's watched policy lists. 32 | 33 | * Protections can be toggled between enabled and disabled at runtime 34 | to dynamically toggle functionality. 35 | - As an example, a community under a targeted attack may wish to 36 | enabled the `JoinWaveShortCircuitProtection` for the duration 37 | of the period, but might want to turn it off if they are 38 | advertising their community or have been featured somewhere. 39 | 40 | * Protections have their own independent configuration settings, that 41 | can be changed dynamically at runtime. 42 | - No need to restart the bot to change protection settings. So for 43 | example, tweaking the allowed number of joins in the 44 | `JoinWaveShortCircuitProtection`. 45 | 46 | What sets protections apart from library and supporting code is that 47 | supporting code provides protections with the means to fetch information, 48 | and cause effects. 49 | 50 | So as another example, library code needs to provide the underlying 51 | functionality to watch policy lists. Library code also needs to 52 | provide the infrastructure to inform protections when policies are 53 | added and removed. Another example is that library code also needs to 54 | provide code for effects, a protection cannot issue room level bans if 55 | there is no supporting code to do that. 56 | 57 | ### How do protections express their behaviour? 58 | 59 | In Draupnir, and the _matrix-protection-suite_, protections express 60 | their behaviour and effects through _capabilities_. As an example, the 61 | `MemberBanSynchronisationProtection`, which is responsible for issuing 62 | room level bans in reaction to policies, uses a capability interface 63 | called `UserConsequences`. When the protection needs to ban a user, 64 | this capability is used to provide the room level bans. 65 | 66 | ### Why do protections cause effects through capabilities? 67 | 68 | Conventionally in software, effects are caused by using _ambient 69 | authority_. This is to say effects are caused directly, by using 70 | authority that is available to the entire application. Draupnir has 71 | access to the entire Matrix account it has been configured to use, and 72 | so conventionally all parts of Draupnir could cause any effect. 73 | Whether that be to shutdown Matrix rooms, ban users, hijack rooms, or 74 | go rogue. Draupnir has the ambient authority to do all these things, 75 | we have to challenge this authority and create ways of containing and 76 | auditing it. Because without, any protection that is enabled could 77 | act with the entire authority of Draupnir, to shutdown rooms and ban 78 | users, and this would be very confusing to the end user, especially 79 | when trying to find which protection is causing these effects and why. 80 | 81 | Additionally, without describing effects through capability 82 | interfaces, dry running protections or behaviours would require 83 | special cased code to exist in sprinkles throughout the code base, and 84 | would be very fragile to maintain. This was the reality of _Mjolnir_'s 85 | dry-run feature. It became very easy for contributors to forget the 86 | feature existed, or not realise that a behaviour they were creating 87 | should have a special case. Because effects were being implemented 88 | implicitly with the general protection business logic. 89 | 90 | By using capability interfaces we can make these effects explicit, and 91 | accounting for different modes of operation becomes a first class 92 | feature that is implicit to using capabilities. No special casing or 93 | thought is required to implement a dry-run mode, because we can now 94 | just replace the capabilities that are provided to the protection, 95 | just by matching their interface. 96 | 97 | ### What is a capability interface? 98 | 99 | A capability interface represents a place in the protection for a 100 | specific behaviour. This interface gets used by the protection's code 101 | in place of the _concrete_ (actual, real) capability. 102 | 103 | So for example, in the matrix-protection-suite, we use the 104 | `UserConsequences` interface for protections in place of the actual 105 | capability to ban users from rooms. 106 | 107 | When a protection is enabled, the protection asks Draupnir for 108 | capabilities matching its capability interfaces. And this allows 109 | Draupnir to choose whether to provide the capability to ban a user, or 110 | instead a capability that simply logs a message when the protection 111 | tried to ban a user. Without causing any other effect. 112 | 113 | ### What is a capability provider? 114 | 115 | A capability provider is essentially a factory that produces a 116 | specific capability for an interface, from an application context, 117 | such as Draupnir. This is essentially used to provide the glue code to 118 | decouple capabilities from the application context. The capability 119 | provider is used by the application context to produce fresh 120 | capabilities for a protection as the protection as enabled. The 121 | capability provider that is used for this purpose is called the 122 | _active_ capability provider. 123 | 124 | Capability providers in Draupnir are configurable on a per protection 125 | basis. 126 | -------------------------------------------------------------------------------- /docs/appservice/appservice.md: -------------------------------------------------------------------------------- 1 | # Appservice 2 | 3 | Draupnir can be run as an appservice, allowing users you trust or on your homeserver to run their own Draupnir without hosting anything themselves. 4 | This module is currently alpha quality and is subject to rapid changes, 5 | it is not recommended currently and support will be limited. 6 | 7 | Usage of the [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/configuring-playbook-bot-draupnir.md) role for Draupnir for all is recommended instead of trying to deploy Draupnir for all from scratch as much more support is offered when taking this route. Especially if not deviating from defaults. 8 | 9 | ## Prerequisites 10 | 11 | This guide assumes you will be using Docker and that you are able to provide a postgres database for Draupnir to connect to in application service mode. 12 | 13 | Please note that Draupnir in appservice mode does not support E2EE nor support use of an E2EE proxy like [pantalaimon](https://github.com/matrix-org/pantalaimon) as there is currently no proxy for appservices like there is for /sync 14 | 15 | ## Setup 16 | 17 | 1. Create a new temporarily public Matrix room that will act as a combined Policy List and Management room for the appservice. 18 | FIXME: Currently required to be aliased. 19 | FIXME: Should ideally be an Admin Room and a separate Policy list, but waiting for command refactor before doing that. 20 | 21 | 2. Give the room from step 1 an alias that you put in your configuration that you will create later. `$MANAGEMENT_ALIAS` is how we will refer to this room in the remaining instructions. 22 | FIXME: Make it so we can just invite the bot to the room and give the bot a room ID in it’s config instead. (Inviting the bot to the room makes the bot think you want to provision not just grant it access to it’s own management room.) 23 | 24 | 3. Decide on a spare local TCP port number to use that will listen for messages from the matrix homeserver. Take care to configure firewalls appropriately. We will call this port `$MATRIX_PORT` in the remaining instructions. 25 | 26 | 4. Create a `config/config.appservice.yaml` file that can be copied from the example in `src/appservice/config/config.example.yaml`. Your config file needs to be accessible to the docker container later on. To do this you could create a directory called `draupnir-data` so we can map it to a volume when we launch the container later on. The `$MANAGEMENT_ALIAS` created earlier on is added to this file under the `adminRoom` key in the config. Please note that the whole config is needed to keep Draupnir happy D4A happy. It will crash if any non-commented out in the template part is missing. 27 | 28 | 5. Generate the appservice registration file. This will be used by both the appservice and your homeserver. 29 | Here, you must specify the direct link the Matrix Homeserver can use to access the appservice, including the Matrix port it will send messages through (if this bridge runs on the same machine you can use `localhost` as the `$HOST` name): 30 | 31 | `docker run --rm -v /your/path/to/draupnir-data:/data gnuxie/draupnir appservice -r -u "http://$HOST:$MATRIX_PORT" -f /data/config/draupnir-registration.yaml` 32 | 33 | 6. Create a `config/config.production.yaml` file that can be copied from the example in `config/default.yaml` just like in step 4. The file also needs to be accessible to the container so whatever path is used for `config/config.appservice.yaml` can be reused to also house this file. 34 | 35 | The provisioned Draupnirs only inherit a subset of the configuration options that are accessible to Bot mode Draupnir. Those are the following options. If there's `:` as a suffix to a config option that means there are sub options like how under commands in the default config you also find `additionalPrefixes:` with a value of `draupnir`. 36 | 37 | ```yaml 38 | logLevel 39 | syncOnStartup 40 | fasterMembershipChecks 41 | automaticallyRedactForReasons: 42 | protectAllJoinedRooms 43 | backgroundDelayMS 44 | commands: 45 | protections: 46 | ``` 47 | 48 | 7. Start the application service `docker run -v /your/path/to/draupnir-data/:/data/ gnuxie/draupnir appservice -c /data/config/config.appservice.yaml -f /data/config/draupnir-registration.yaml -p $MATRIX_PORT --draupnir-config /data/config/production.yaml` 49 | 50 | 8. Copy the `draupnir-registration.yaml` to your matrix homeserver and refer to it in `homeserver.yaml` like so: 51 | 52 | ```yaml 53 | app_service_config_files: 54 | - "/data/draupnir-registration.yaml" 55 | ``` 56 | 57 | ## Post Install Setup and Configuration 58 | 59 | If you successfully followed Steps 1-8 or got to the point your running the bot through other means congratulations. Then there are some post install steps and configuration that you should apply to your appservice 60 | 61 | 1. If your successfully at this point it’s assumed that your `draupnir-moderation` or `draupnir-main` bot is in the admin room (the room with designated by `$MANAGEMENT_ALIAS`). So go back up and follow those steps if you haven't got there yet. 62 | 63 | 2. Set your appservice management room to private, if you didn't already. Anyone with access to this room can manage access to the appservice, so be careful who you share this with. 64 | 65 | 3. Set your appservice to have powerlevel 50 or greater in the appservice management room as to allow it to write policies into this room. The bot uses these policies to control who is allowed to use the bot. 66 | 67 | 4. Decide if you want to allow provisioning per homeserver or per user. If you choose to only provision per user skip to step 6. 68 | 69 | 5. Allow provisioning per homeserver. To provision per homeserver you write in your control room /plain MXID_OF_APPSERVICE_HERE allow @\*:homeserver_to_allow 70 | 71 | 6. Allow provisioning per user. To Provision per user you write in your control room /plain MXID_OF_APPSERVICE_HERE allow MXID_TO_ALLOW 72 | FIXME: If the client is being dumb and adding escapes to lone instances of \* in the command strip them out so you don't have to mandate /plain use to guarantee the client doesn’t screw the user over. 73 | 74 | 7. Provisioning a Draupnir is done via inviting your main draupnir into a room. If the user who did it is allowed to Draupnir rejects the invite and provisions a Draupnir shortly and invites the user to the newly created policy list and control room for this Draupnir. 75 | -------------------------------------------------------------------------------- /docs/governance/reports/2510A-selection.md: -------------------------------------------------------------------------------- 1 | # 2025-10-A-Selection: Selection 2 | 3 | Milestone: https://github.com/the-draupnir-project/planning/milestone/2 4 | 5 | ## Context 6 | 7 | In the [current cycle](./2510A-cycle-review.md) we have been making changes to 8 | give draupnir users more control in the project's direction. And to reaffirm 9 | contributors work on the project. 10 | 11 | ## Options 12 | 13 | As per [the longhouse cycle](../longhouse-cycle.md) process, the _contribution 14 | guild_ will only select options within material constraints. Members of the 15 | assembly may pledge material support against options as part of the 16 | [_consultation_](../longhouse-consultation.md) process. Contributors retain the 17 | right of self determination as contribution is a voluntary process. 18 | 19 | You SHOULD read the context of the selection before voting. See the 20 | [cycle review](./2510A-cycle-review.md). 21 | 22 | ### Option A: Policy room subscription preview 23 | 24 | 25 | 26 | This would mean changing the policy room watch command to preview the effects of 27 | all protections when subscribing to the room. 28 | [Milestone for the cycle](https://github.com/the-draupnir-project/planning/milestone/2). 29 | 30 | Material support: NLnet goal 31 | https://marewolf.me/posts/draupnir/24-nlnet-goals.html#goal-preview-policy-list. 32 | 33 | ### Option Z: None of the above 34 | 35 | This is an expression of no confidence in the direction. If you have further 36 | comments, please see [consultation](../longhouse-consultation.md). 37 | 38 | ## Discounted options 39 | 40 | These are options that haven't been included but would be good candidates. 41 | 42 | ### Continue with room upgrade support for Hydra 43 | 44 | This would mean incrementing towards full room upgrade management by 45 | implementing 46 | [MSC4321](https://github.com/matrix-org/matrix-spec-proposals/pull/4321) in its 47 | entirety. See 48 | [project hydra mitigation](https://github.com/the-draupnir-project/planning/issues/44). 49 | 50 | This is still important and will likely become the primary focus of the project 51 | once the NLnet grant expires. Synapse does not yet create rooms at V12 by 52 | default, and we take this as a signal from the proponents of hydra that the risk 53 | to V11 rooms is very low. Which matches our own assessment. 54 | 55 | Material support: None. 56 | 57 | ### Increment user familiarity metric 58 | 59 | We last worked on 60 | [user familiarity](https://github.com/the-draupnir-project/planning/issues/43) 61 | in July, formerly known as 62 | [participation metric](https://github.com/the-draupnir-project/planning/issues/24). 63 | 64 | The user familiarity metric would be used to bias protections to discriminate 65 | more against less familiar users, and less against more familiar users. And 66 | potentially be used to add further safe guards to Draupnir. This is a core piece 67 | of the roadmap that we do eventually want to deliver. 68 | 69 | However, this is a large piece of work that will take a long time for end users 70 | to receive value from. And we need more certainty about the support of the 71 | project before we can sustain focus on a large piece of work like this. 72 | 73 | Material support: NLnet goal, but unlikely to be attainable. 74 | 75 | ### Increment explicit agreement & approval / disapproval 76 | 77 | We last explored approval/disapproval in June, and we have even written 78 | [MSC4273](https://github.com/matrix-org/matrix-spec-proposals/pull/4273) to 79 | describe how the ratings would be persisted and shared. 80 | 81 | This is an essential missing building block for Matrix policy rooms, providing 82 | the ability to subjectively rate policies in order to determine whether they can 83 | be considered for evaluation by your tools. 84 | 85 | While we could easily provide an increment with the ability to rate policies, I 86 | don't think that provides value without the explicit agreement policy room 87 | subscription. And changes to policy room subscription requires more thought in 88 | the design space at this time. Particularly, subscription needs to be framed in 89 | terms of the policy curators themselves, the people writing the policies. And 90 | scoping trust for direct propagation to specific policy rooms and 91 | recommendations. And I just haven't had time to do that work. 92 | 93 | Material support: NLnet goal. 94 | 95 | ### Policy server support 96 | 97 | [MSC4248: Policy Servers](https://github.com/matrix-org/matrix-spec-proposals/pull/4284) 98 | are unable to provide pre-emptive moderation capability to most Draupnir 99 | deployments without significant work, see 100 | https://github.com/matrix-org/matrix-spec-proposals/pull/4284/files#r2446071861. 101 | 102 | We would have to create a proxy to provide pass-through capability, similar to 103 | synapse-http-antispam, or implement the necessary parts of the server-server 104 | specification ourselves. Which has already led to critical security bugs in 105 | implementations that attempted to do this. 106 | 107 | Still, the pre-emptive moderation capability provided by policy servers is 108 | incredibly powerful and we need it. 109 | 110 | Material support: None. 111 | 112 | ### Service architecture 113 | 114 | We're exploring the design space around _Draupnir for all_, and we do have an 115 | architecture design that would allow us to host more Draupnir than Matrix would 116 | ever need (the homeserver would fall over first). And we do think that it will 117 | be necessary in the future to do this to provide the capabilities of draupnir to 118 | any Matrix community. And allow Draupnir to become the backend for a community 119 | management platform. 120 | 121 | Material support: None. 122 | 123 | ### We need your support to implement these options 124 | 125 | Many of these discounted options would already have been implemented if the 126 | project had the support and participation of the Matrix foundation, and 127 | representatives of organisations using Draupnir much earlier. Support is 128 | increasing, and the [_longhouse_](../governance.md) system is supposed to 129 | facilitate this participation. 130 | 131 | ## Feedback and discussion 132 | 133 | _Voting is still in progress or has not yet occurred_. 134 | 135 | ## Outcome 136 | 137 | _Voting is still in progress or has not yet occurred_. 138 | -------------------------------------------------------------------------------- /docs/matrix-protection-suite/concepts/protected-rooms-set.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | sidebar_label: Protected Rooms Set 4 | --- 5 | 6 | 11 | 12 | # Protected Rooms Set 13 | 14 | :::tip 15 | 16 | This page is intended for advanced users of Draupnir and protection 17 | developers, who want to understand how protections work within the 18 | matrix-protection-suite. 19 | 20 | ::: 21 | 22 | The _protected rooms set_ is one of the most important components of 23 | the matrix-protection-suite. A _protected rooms set_ is a set of rooms 24 | that a group of protections will interact with. So with each protected 25 | rooms set, there is a collection of [protections](./protection) that 26 | are enabled to protect the rooms. Draupnir itself is closely 27 | associated with exactly one protected rooms set. 28 | 29 | The protected rooms set is therefore responsible for listening for 30 | events in all of the rooms marked as protected and inform protections 31 | about them. The protected rooms set also keeps protections informed 32 | about changes to membership and moderation policies from watched 33 | policy rooms. 34 | 35 | ## The revision issuers used by a `ProtectedRoomsSet` 36 | 37 | The protected rooms set sources its information by managing subscriptions 38 | to multiple [revision issuers](./revisions). 39 | 40 | ### Sourcing moderation policies vis the _watched policy rooms_ 41 | 42 | The first of these can be found under the `watchedPolicyRooms` 43 | property and the `WatchedPolicyRooms` object contained within 44 | it. There is a `PolicyListRevisionIssuer` here that aggregates and 45 | filters all policies from the various policy list subscription 46 | profiles into one `PolicyListRevision` that can directly be consumed 47 | by protections within the `ProtectedRoomsSet`. 48 | 49 | When this _policy list revision issuer_ updates, _protections_ within 50 | the _protected rooms set_ will each be called with the handle 51 | `handlePolicyChange` described on the `Protection` interface. This 52 | handle will provide an updated `PolicyListRevision` revision and any 53 | changes that were made since the _previous revision_. 54 | 55 | ### Sourcing room state via the _set room state_ 56 | 57 | A _protected rooms set_ keeps track of changes to room state by 58 | keeping a `SetRoomState` object under the `setRoomState` 59 | property. This provides protections with immediate access to all room 60 | state within the protected rooms set. By using the `SetRoomState` 61 | interface, protections are able to retrieve any current 62 | `RoomStateRevision` for any room within the _protected rooms set_. 63 | 64 | When the room state of any room within the _protected rooms set_ is 65 | changed, _protections_ within the _protected rooms set_ will be called 66 | with the handle `handleStateChange` described on the `Protection` 67 | interface. This will include the new _revision_ and also specify the 68 | nature of any change to the room state. 69 | 70 | ### Sourcing room membership via the _set room membership_ 71 | 72 | Details of individual room membership can be found by accessing the 73 | `setRoomMembership` property to obtain an object with the 74 | `SetRoomMembership` interface. From here, protections can get 75 | immediate access to to the membership information for each room. 76 | This is provided in the form of a `RoomMembershipRevision`. 77 | 78 | When a user's membership within a _protected room_ changes, the 79 | `handleMembershipChange` handle will be called for each _protection_ 80 | as described in the `Protection` interface. _Protections_ will 81 | be given a new `RoomMembershipRevision` for the protected room, 82 | and the exact details of any membership changes. 83 | 84 | ### Sourcing set membership via _set membership_ 85 | 86 | In addition to tracking user membership to each of the individual 87 | _protected rooms_, the _protected rooms set_ also tracks each user's 88 | membership to the community overall. This membership is reduced into 89 | two simple possibilities, that the user is _present_ in the _protected 90 | rooms set_ or they are _absent_. 91 | 92 | This membership information can be accessed from the `setMembership` 93 | property, implementing the `SetMembership` interface. From there, it 94 | will be possible to obtain the current `SetMembershipRevision` for the 95 | entire _protected rooms set_. 96 | 97 | When a user's membership to the _protected rooms set_ changes overall, 98 | because they have left all _protected rooms_ or have joined the 99 | community for the first time, `handleSetMembershipChange` will be 100 | called on protections. This will provide the current 101 | `SetMembershipRevision`, as well as the exact detail of any changes to 102 | set membership. 103 | 104 | ### Sourcing policy matches against members via _set membership policies_ 105 | 106 | In Mjolnir and previous versions of Draupnir, policy matching would 107 | happen at the protection level. That's to say protections had to have 108 | their own way of hand matching policies against room 109 | members. Naturally, this led to inconsistencies, and also a great 110 | waste of CPU time. As policy matching is the most CPU intensive task 111 | Draupnir has to perform. This was compounded by the fact the current 112 | Draupnir conception of _[revisions](./revisions)_ did not exist, and 113 | so changes to room membership or policies were not calculated, and 114 | each change needed the entire set of both policies and membership to 115 | be rescanned and matched. 116 | 117 | In order to provide a unified and shared means of accessing policies 118 | relevant to room members, the matrix-protection-suite combines a 119 | `SetMembershipRevision` and a `PolicyListRevision` to produce a 120 | `SetMembershipPolicyRevision`, containing only the members that have 121 | matching policies, alongside each of these policies. 122 | 123 | Protections then only have to access precalculated matches when 124 | enforcing consequences in relation to moderation policies. 125 | 126 | This can be accessed from the `setPoliciesMatchingMembership` property 127 | on the _protected rooms set_. 128 | 129 | When the matches change, an enabled protection's 130 | `handleSetMembershipPolicyMatchesChange` method will be called with a 131 | new revision, and the precise changes that were made. 132 | -------------------------------------------------------------------------------- /docs/contributing/security.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | ## Programming practices and considerations 4 | 5 | Here are some general practices you should follow when programming in 6 | TypeScript, which could otherwise have security implications. 7 | 8 | ### Property access with user supplied property names 9 | 10 | The following example appears a lot in JavaScript code bases, particularly when 11 | exposing configuration objects to the user interface: 12 | 13 | ```typescript 14 | const config = readConfigFromFile(); 15 | const propertyName = readUserInput(); 16 | if (object[propertyName] !== undefined) { 17 | doSomething(config[propertyName]); 18 | } 19 | ``` 20 | 21 | This looks innocent enough, but the issue is that this use of property access 22 | also allows the user to access properties from the `Object.prototype`. Which at 23 | best can cause a `TypeError` to be thrown, but at worst can lead to an RCE 24 | vulnerability. 25 | 26 | To prevent this, it is recommended to use the `Object.hasOwn` method to guard 27 | user supplied property access. The `@gnuxie/typescript-result` package offers 28 | its own generic `hasOwn` / `getOwn` functions that support type inference. 29 | 30 | ```typescript 31 | const config = readConfigFromFile(); 32 | const propertyName = readUserInput(); 33 | if (hasOwn(config, propertyName) !== undefined) { 34 | doSomething(getOwn(config, propertyName)); 35 | } 36 | ``` 37 | 38 | #### Resources 39 | 40 | - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors 41 | - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 42 | - https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/the-dangers-of-square-bracket-notation.md 43 | 44 | ### ReDoS 45 | 46 | Can't provide an explanation for this one but just be careful with capturing 47 | groups and check against the owasp resource below. 48 | 49 | #### Resources 50 | 51 | - [How regexes got catastrophic](https://www.youtube.com/watch?v=gITmP0IWff0&t=212s). 52 | - https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS 53 | 54 | ### Prototype pollution 55 | 56 | Prototype pollution is the collision of object property names with intrinsic 57 | properties, in most contexts this means properties defined on the 58 | `Object.prototype`, such as the `toString` method. 59 | 60 | Prototype pollution typically effects programs in the following situations: 61 | 62 | - Using an object as a map or dictionary instead of just using a 63 | [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map). 64 | Leading to problems when keys are derived from user input (including external 65 | APIs). 66 | - Deserializing JSON payloads. 67 | 68 | It is a mistake to ever use an object as a generic map, but it happens because 69 | JSON configuration typically forms part of an interface with the program. And 70 | the standard pattern is for JSON to be deserialized to objects through the use 71 | of 72 | [`JSON.parse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse). 73 | And now we're stuck with this history. 74 | 75 | Here is a list of properties that you should be considerate of if you ever end 76 | up in a situation where it is important to sanitize property names 77 | https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#object_prototype_properties. 78 | 79 | Be sure to also use the jsonReviver provided by Draupnir 80 | https://github.com/the-draupnir-project/Draupnir/blob/0c448ab85e53e24cd4a9ffb81174c04a1a1f381b/src/utils.ts#L517-L531. 81 | 82 | ### Joe's law 83 | 84 | Joe's law: crash, crash, crash, crash crash. 85 | 86 | It is important to maintain awareness over situations that a program has 87 | implicitly not been written to handle, and make these explicit by "crashing". 88 | 89 | What this means for us is checking state and throwing a 90 | [`TypeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError). 91 | 92 | This prevents the program from running in unanticipated ways and producing 93 | potentially safety and security critical side effects. In other words, failing 94 | to do this can allow attackers to exploit the application. This also makes sure 95 | that developers do not use components inappropriately, in contexts that they 96 | were not written for. Which can also lead to the same outcome. The environment 97 | around code is always changing. 98 | 99 | It also provides visibility to both the system administrator and eventually the 100 | developer over the problem. You may think that doing this causes the program to 101 | be less reliable or fault tolerant, but the opposite is actually true. As a 102 | result of these assertions we get feedback from error states faster and can 103 | adjust the program accordingly, leading to a more resilient program in the long 104 | run. 105 | 106 | ### Matrix mixin validation and parsing 107 | 108 | 109 | 110 | While you may be tempted to treat Matrix event parsing as atomic, this would be 111 | a mistake, especially in a security and safety context. The Matrix specification 112 | places no requirement for events to be "valid" or conform to the provided 113 | schema. The only exception to this are specific event properties that are 114 | validated as part of authorization rules. Even then, this happens implicitly as 115 | part of imperative rule flow rather than declaratively. 116 | 117 | Additionally, with the advent of extensible events, Matrix events actually have 118 | multiple parts embedded within them that conform independently to different 119 | schema. These independent units are called mixins. 120 | 121 | In most cases Matrix clients will still display malformed events as best they 122 | can, in adherence with the opposite of Joe's law, Postel's law. This allows 123 | malicious actors to craft events specifically to trip up certain matrix clients 124 | in order to make abuse visible only to specific clients. 125 | 126 | It is exceptionally important to keep malformed events represented and in the 127 | event processing pipeline as otherwise you can allow users to evade Draupnir 128 | protections. 129 | 130 | The approach Draupnir then takes to event parsing is to try parse a minimal 131 | "core" of each mixin and otherwise provide a generic "invalid event" type. Valid 132 | events with invalid mixins will be flagged for redaction to prevent external 133 | abuse. 134 | -------------------------------------------------------------------------------- /docusaurus.config.ts: -------------------------------------------------------------------------------- 1 | import { themes as prismThemes } from 'prism-react-renderer'; 2 | import type { Config } from '@docusaurus/types'; 3 | import type * as Preset from '@docusaurus/preset-classic'; 4 | import type * as OpenApiPlugin from "docusaurus-plugin-openapi-docs"; 5 | 6 | const config: Config = { 7 | title: 'Draupnir Documentation', 8 | tagline: 'Draupnir Documentation Website', 9 | favicon: 'img/favicon.ico', 10 | 11 | // Set the production url of your site here 12 | url: 'https://the-draupnir-project.github.com', 13 | // Set the // pathname under which your site is served 14 | // For GitHub pages deployment, it is often '//' 15 | baseUrl: '/draupnir-documentation/', 16 | 17 | // GitHub pages deployment config. 18 | // If you aren't using GitHub pages, you don't need these. 19 | organizationName: 'the-draupnir-project', // Usually your GitHub org/user name. 20 | projectName: 'draupnir-documentation', // Usually your repo name. 21 | deploymentBranch: 'gh-pages', 22 | trailingSlash: false, 23 | 24 | onBrokenLinks: 'throw', 25 | onBrokenMarkdownLinks: 'warn', 26 | 27 | // Even if you don't use internationalization, you can use this field to set 28 | // useful metadata like html lang. For example, if your site is Chinese, you 29 | // may want to replace "en" with "zh-Hans". 30 | i18n: { 31 | defaultLocale: 'en', 32 | locales: ['en'], 33 | }, 34 | 35 | presets: [ 36 | [ 37 | '@docusaurus/preset-classic', 38 | { 39 | docs: { 40 | sidebarPath: './sidebars.ts', 41 | docItemComponent: "@theme/ApiItem", // Derived from docusaurus-theme-openapi 42 | // Please change this to your repo. 43 | // Remove this to remove the "edit this page" links. 44 | editUrl: 45 | 'https://github.com/the-draupnir-project/draupnir-documentation/tree/main/', 46 | routeBasePath: '/', 47 | async sidebarItemsGenerator({ defaultSidebarItemsGenerator, ...args }) { 48 | const sidebarItems = await defaultSidebarItemsGenerator(args); 49 | // Remove the api sidebar items from the main sidebar (id contains "api/" as the first part) 50 | const filteredSidebarItems = sidebarItems.filter((item) => { 51 | if (item.type === 'category') { 52 | return !item.items.some((subItem) => { 53 | if (subItem.type === 'doc') { 54 | return subItem.id.startsWith('api/'); 55 | } 56 | return false; // Keep other types of items 57 | }); 58 | } 59 | if (item.type === 'doc') { 60 | return !item.id.startsWith('api/'); 61 | } 62 | return true; // Keep other types of items 63 | }); 64 | return filteredSidebarItems; 65 | }, 66 | }, 67 | blog: false, 68 | pages: false, 69 | //{ 70 | // showReadingTime: true, 71 | // // Please change this to your repo. 72 | // // Remove this to remove the "edit this page" links. 73 | // editUrl: 74 | // 'https://github.com/the-draupnir-project/Draupnir', 75 | //}, 76 | theme: { 77 | customCss: './src/css/custom.css', 78 | }, 79 | 80 | } satisfies Preset.Options, 81 | ] 82 | ], 83 | 84 | themeConfig: { 85 | // Replace with your project's social card 86 | //image: 'img/docusaurus-social-card.jpg', 87 | navbar: { 88 | title: 'Draupnir Documentation', 89 | logo: { 90 | alt: 'Draupnir Logo', 91 | src: 'img/logo.png', 92 | }, 93 | items: [ 94 | { 95 | href: 'https://github.com/the-draupnir-project/Draupnir', 96 | label: 'GitHub', 97 | position: 'right', 98 | }, 99 | ], 100 | }, 101 | footer: { 102 | style: 'dark', 103 | links: [ 104 | { 105 | title: 'Community', 106 | items: [ 107 | { 108 | label: 'Matrix', 109 | href: 'https://matrix.to/#/#draupnir:matrix.org', 110 | }, 111 | ], 112 | }, 113 | { 114 | title: 'More', 115 | items: [ 116 | { 117 | label: 'GitHub', 118 | href: 'https://github.com/the-draupnir-project/Draupnir', 119 | }, 120 | ], 121 | }, 122 | ], 123 | copyright: `Copyright © ${new Date().getFullYear()} The Draupnir Project, Built with Docusaurus.`, 124 | }, 125 | prism: { 126 | theme: prismThemes.github, 127 | darkTheme: prismThemes.dracula, 128 | }, 129 | algolia: { 130 | // The application ID provided by Algolia 131 | appId: 'I9VD7VPVD9', 132 | 133 | // Public API key: it is safe to commit it 134 | apiKey: '234f6dbf8b44abc0ee75f4f8a750d8e4', 135 | 136 | indexName: 'the-draupnir-projectio', 137 | 138 | // Optional: see doc section below 139 | // contextualSearch: true, 140 | 141 | // Optional: Specify domains where the navigation should occur through window.location instead on history.push. Useful when our Algolia config crawls multiple documentation sites and we want to navigate with window.location.href to them. 142 | // externalUrlRegex: 'external\\.com|domain\\.com', 143 | 144 | // Optional: Replace parts of the item URLs from Algolia. Useful when using the same search index for multiple deployments using a different baseUrl. You can use regexp or string in the `from` param. For example: localhost:3000 vs myCompany.com/docs 145 | // replaceSearchResultPathname: { 146 | // from: '/docs/', // or as RegExp: /\/docs\// 147 | // to: '/', 148 | //}, 149 | 150 | // Optional: Algolia search parameters 151 | searchParameters: {}, 152 | 153 | // Optional: path for search page that enabled by default (`false` to disable it) 154 | searchPagePath: 'search', 155 | 156 | // Optional: whether the insights feature is enabled or not on Docsearch (`false` by default) 157 | insights: true, 158 | 159 | //... other Algolia params 160 | }, 161 | } satisfies Preset.ThemeConfig, 162 | 163 | plugins: [ 164 | [ 165 | 'docusaurus-plugin-openapi-docs', 166 | { 167 | id: "api", // plugin id 168 | docsPluginId: "classic", // configured for preset-classic 169 | config: { 170 | draupnir: { 171 | specPath: "api/draupnir-openapi.yaml", 172 | outputDir: "docs/api", 173 | sidebarOptions: { 174 | groupPathsBy: "tag" 175 | }, 176 | hideSendButton: true, 177 | // They are mostly confusing 178 | showSchemas: false 179 | } satisfies OpenApiPlugin.Options, 180 | } 181 | }, 182 | ], 183 | ], 184 | themes: ["docusaurus-theme-openapi-docs"] 185 | }; 186 | 187 | export default config; 188 | -------------------------------------------------------------------------------- /docs/protections/configuring-protections.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | sidebar_label: Configuring protections 4 | --- 5 | 6 | 11 | 12 | # Configuring protections 13 | 14 | :::info 15 | 16 | This is a tutorial that aims to guide a moderator through configuring 17 | a protection. We use the `JoinWaveShortCircuitProtection` in the 18 | examples, but the steps are the same for every protection. 19 | 20 | ::: 21 | 22 | ## Displaying the protection settings 23 | 24 | :::tip 25 | 26 | The commands displaying protections have key names surrounded in 27 | _code_ blocks to make them easy to copy by double clicking. 28 | 29 | You can copy _protection names_ from the `!draupnir protections`, 30 | and copy individual protection _setting names_ from `!draupnir 31 | protections show`. 32 | 33 | ::: 34 | 35 | Each protection can provide different configuration options, which are 36 | sometimes also referred to as _protection settings_. The command that 37 | is used to view these settings is the `protections show` command. 38 | 39 | To display an overview for a protection's protection settings, you can 40 | use the `!draupnir protections show ` command. If you 41 | don't know the name of the protection that you are trying to find, you 42 | can copy the name from the list provided when using the `!draupnir 43 | protections` command. 44 | 45 | From the `protections show` command We are provided with a short 46 | description of each setting, and the setting's name that we can copy 47 | into a further command to edit the settings. 48 | 49 | ### An example, using the `JoinWaveShortCircuitProtection`: 50 | 51 | When wanting to view the settings for the the 52 | `JoinWaveShortCircuitProtection`, invoking the command would look like 53 | this: 54 | 55 | `!draupnir protections show JoinWaveShortCircuitProtection`: 56 | 57 | **Protection Settings** 58 | 59 | - `maxPer`: The maximum number of users that can join a room in the 60 | timescaleMinutes timescale before the room is set to invite-only. 61 | default value: 50 (number) 62 | 63 | - `timescaleMinutes`: The timescale in minutes over which the maxPer 64 | users can join before the room is set to invite-only. 65 | 66 | ## Changing protection settings 67 | 68 | :::tip 69 | 70 | Use the `!draupnir protections config reset ` command 71 | to restore the default settings for a given protection. 72 | 73 | ::: 74 | 75 | Let's consider adjusting the protection settings for the 76 | `JoinWaveShortCircuitProtection`. If we have a particularly inactive 77 | room, we might want to reduce the timescale and the maximum number of 78 | joins within it. 79 | 80 | To do this, we can use the `!draupnir protections config set 81 | ` command. 82 | 83 | `!draupnir protections config set JoinWaveShortCircuitProtection 84 | maxPer 5` would set the `maxPer` setting to just 5 joins. And 85 | `!draupnir protections config set JoinWaveShortCircuitProtection 86 | timescaleMinutes 10` would make sure that a maximum of 5 joins is 87 | allowed over a period of 10 minutes before triggering the short 88 | circuit. 89 | 90 | ### Managing sets 91 | 92 | Some protections have settings that are a set of values. The 93 | `TrustedReporters` protection has a setting like this. 94 | 95 | - `mxids`: The users who are marked as trusted reporters. default 96 | value: [] (empty array) 97 | 98 | To manage the list, we can use the `!draupnir protections config ` command. 99 | 100 | So to add a user to the list of trusted reporters, we would use 101 | `!draupnir protections config add TrustedReporters mxids 102 | @alice:example.com`, and to remove a user `!draupnir protections 103 | config remove TrustedReporters mxids @alice:example.com`. 104 | 105 | ## Configuring protection capabilities 106 | 107 | :::info 108 | 109 | For more details about capabilities, see the [conceptual 110 | documentation](../matrix-protection-suite/concepts/protection). 111 | Capabilities are a relatively new feature in Draupnir, and we're still 112 | working to update protections to make use of them. 113 | 114 | Managing capabilities is a relatively advanced feature, and we aim to 115 | make use of the functionality though protection specific configuration 116 | commands that are easier to use. 117 | 118 | ::: 119 | 120 | Protections use capabilities to cause actions such as redacting an 121 | event, banning a user, or sending an alert to the management room. 122 | 123 | A protection can have more than one capability, and each capability 124 | has a name. Think of capabilities as a place for a specific piece of 125 | functionality. Such as the ability to ban users is often provided by 126 | the `StandardUserConsequences` _capability provider_ which satisfies 127 | the `UserConsequences` _capability interface_. The configured provider 128 | that gives a protection the functionality for a specific capability is 129 | called the _active capability provider_. And collectively the 130 | configured capability providers for all the protection's capabilities 131 | is called _the capability provider set_. 132 | 133 | ### Viewing configured capability providers 134 | 135 | To view which capability providers are currently active we can use the 136 | `!draupnir protections show ` command. 137 | 138 | Under the `Capability provider set` heading, each capability that the 139 | protection supports is shown. There are three key pieces of 140 | information here: 141 | 142 | - The capability name 143 | - The _capability interface_, which determines which _capability providers_ are 144 | compatible or interchangeable with this capability. 145 | - The _active capability provider_, showing which of the compatible _capability providers_ is configured 146 | for and being used for this capability. 147 | 148 | If you expand the details, you will be able to see a list of 149 | compatible capability providers for the _capability interface_ 150 | designated for this capability. Protections will always have at least 151 | two different options, a standard capability and a simulated 152 | capability. You will be able to read a description of what each capability 153 | provider does. 154 | 155 | ### Changing the active capability provider for a protection capability 156 | 157 | :::tip 158 | 159 | To avoid typos, try copy and pasting the details from the `!draupnir 160 | protections show ` command. 161 | 162 | ::: 163 | 164 | To change the active capability provider for a protection, we can use 165 | the `!draupnir protections capability ` command. 167 | 168 | ### Restoring the default capability provider set for a protection 169 | 170 | If you need to restore the default capability providers for a 171 | protection, then you can use the `!draupnir protections capability 172 | reset` command. This will restore all the default capability providers 173 | for each capability that the protection offers. 174 | -------------------------------------------------------------------------------- /docs/bot/setup_draupnir_account.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | sidebar_label: Creating an account and access token for Draupnir 4 | --- 5 | 6 | 7 | 8 | # Creating an account and access token for Draupnir 9 | 10 | :::note 11 | 12 | To deactivate users, move aliases, and shutdown rooms, Draupnir will need to be 13 | a server admin. These features are only supported on Synapse. 14 | 15 | ::: 16 | 17 | :::info 18 | 19 | While Draupnir can be run on a rate limited account without issue. We recommend 20 | disabling rate limiting if the option is available to you. After you have 21 | created your account, you can see how to manage rate limiting 22 | [here](#disabling-rate-limiting). 23 | 24 | ::: 25 | 26 | ## Pre-requisites 27 | 28 | This page is going to tell you how to: 29 | 30 | 1. Create a fresh Matrix account for your Draupnir bot to use, optionally with 31 | server admin capabilities. 32 | 2. Create an _access token_ for your bot to use to access the Matrix account. 33 | Which is an opaque string that you will paste into your 34 | [config](./starting_draupnir) file under the `accessToken` key (or via the 35 | `--access-token-path` option). 36 | 3. Optionally disable rate limits for the account. 37 | 4. Optionally turn an existing Synapse account into a synapse admin account. 38 | 39 | ## Creating an account 40 | 41 | ### Synapse 42 | 43 | To create a new server admin account, you can use Synapse's 44 | `register_new_matrix_user` command. See the Synapse documentation for the 45 | [admin api](https://element-hq.github.io/synapse/latest/usage/administration/admin_api/index.html). 46 | 47 | If you are using MAS (Element's 48 | [matrix-authentication-service](https://element-hq.github.io/matrix-authentication-service/index.html)), 49 | see how to register users using the 50 | [mas-cli](https://element-hq.github.io/matrix-authentication-service/reference/cli/manage.html#manage-register-user). 51 | 52 | Once you have created an account proceed to 53 | [creating a token](#creating-a-token-all-homeservers). 54 | 55 | ### Dendrite 56 | 57 | Please see the dendrite documentation for the `create-account` command 58 | [here](https://element-hq.github.io/dendrite/administration/createusers#from-the-command-line). 59 | 60 | ### Other or no server admin access 61 | 62 | Proceed to 63 | [creating an account or logging in with Element](#creating-an-account-or-logging-in-with-element). 64 | 65 | ## Creating a token (all homeservers) 66 | 67 | ### Creating a token with access to mas-cli 68 | 69 | :::info 70 | 71 | If you are deployed against a homeserver using MAS, but without access to the 72 | mas-cli, you will need to follow the instructions for 73 | [creating a token with curl](#getting-a-token-with-curl-mas-and-encryption-friendly). 74 | 75 | ::: 76 | 77 | If you are using MAS, and you are a homeserver administrator, you will then need 78 | to create a token for Draupnir using `mas-cli`. 79 | 80 | 1. `mas-cli manage issue-compatibility-token --yes-i-want-to-grant-synapse-admin-privileges `[^compat-token] 81 | 1. `mas-cli manage provision-all-users` [^provision] 82 | 83 | Note that these two command require an existing account. 84 | 85 | ### Creating an account or logging in with Element 86 | 87 | You should create an account or login by opening 88 | [Element](https://app.element.io) in a separate browser profile or incognito tab 89 | and registering an account for the bot. 90 | 91 | ### Getting a token from Element web 92 | 93 | :::info 94 | 95 | Do not copy the access token from Element web if your homeserver is using MAS 96 | (matrix-authentication-service). This includes bots deployed against matrix.org. 97 | Instead, you should use curl (see below). This is because the token Element web 98 | provisions expires very quickly. You can still register the user with Element 99 | however. 100 | 101 | ::: 102 | 103 | If your Draupnir is not configured to use Encryption, you can then, go to "All 104 | Settings", "Help & About", and click the little triangle next to "Access token". 105 | Copy and paste that into your [config](./starting_draupnir) file under the 106 | `accessToken` key. 107 | 108 | Do not log out, just close the window, otherwise the access token will be 109 | invalidated. 110 | 111 | If you have presence enabled on your homeserver, do not keep the window open or 112 | use the same session to login to the Draupnir account as this will cause you to 113 | accidentally trigger a bug in Synapse or Element web that will flood presence 114 | updates. 115 | 116 | ### Getting a token with curl (MAS and Encryption friendly) 117 | 118 | To get an access token with curl, you will need three pieces of information. 119 | 120 | 1. The base url for client-server connections. 121 | 2. Your draupnir user id localpart. 122 | 3. Your draupnir user password. 123 | 124 | #### Finding the base url 125 | 126 | To find the base url for your homeserver, you will need to visit 127 | `https://example.com/.well-known/matrix/client` in your browser or with curl: 128 | 129 | `curl https://example.com/.well-known/matrix/client`. You should see some JSON 130 | like this in response: 131 | 132 | ``` 133 | { 134 | "m.homeserver": { 135 | "base_url": "https://matrix-client.example.com" 136 | } 137 | } 138 | ``` 139 | 140 | The `base_url` under `m.homeserver` is your client-server base_url. 141 | 142 | #### Finding the draupnir user id localpart 143 | 144 | If your draupnir user matrix identifier is `@draupnir:example.com` the localpart 145 | will be `draupnir`. 146 | 147 | #### Fetching the access token 148 | 149 | To create the access token replace DRAUPNIR_LOCALPART, DRAUPNIR_USER_PASSWORD, 150 | and CLIENT_BASE_URL with the information gathered prior. 151 | 152 | ``` 153 | curl -XPOST -d '{ 154 | "identifier": { "type": "m.id.user", "user": "DRAUPNIR_LOCALPART" }, 155 | "password": "DRAUPNIR_USER_PASSWORD", 156 | "type": "m.login.password", 157 | }' 'CLIENT_BASE_URL/_matrix/client/r0/login' 158 | ``` 159 | 160 | So that it should look like this: 161 | 162 | ``` 163 | curl -XPOST -d '{ 164 | "identifier": { "type": "m.id.user", "user": "draupnir" }, 165 | "password": "********", 166 | "type": "m.login.password", 167 | }' 'https://matrix-client.example.com/_matrix/client/r0/login' 168 | ``` 169 | 170 | You should get a response containing your access token. 171 | 172 | ## Disabling rate limiting 173 | 174 | By default, Draupnir will be rate limited by homeservers, which can inhibit 175 | Draupnir's ability to respond in some scenarios, particularly while redacting 176 | lots of messages. 177 | 178 | It's therefore recommended to turn off ratelimiting for a draupnir bot, see 179 | [the synapse admin API documentation](https://matrix-org.github.io/synapse/latest/admin_api/user_admin_api.html#set-ratelimit) 180 | for more information. For Dendrite this is configured in 181 | [dendrite.yaml](https://github.com/element-hq/dendrite/blob/main/dendrite-sample.yaml#L211) 182 | by adding `exempt_user_ids:` under `rate_limiting:`. 183 | 184 | ## Making Draupnir a Synapse Admin 185 | 186 | If you registered a new account, please see the Synapse documentation for how to 187 | make an existing account a Synapse admin 188 | [here](https://element-hq.github.io/synapse/latest/usage/administration/admin_api/index.html). 189 | 190 | [^compat-token]: 191 | You can find more about it in the official documentation at 192 | [https://element-hq.github.io/matrix-authentication-service/reference/cli/manage.html#manage-issue-compatibility-token](https://element-hq.github.io/matrix-authentication-service/reference/cli/manage.html#manage-issue-compatibility-token) 193 | 194 | [^provision]: 195 | This ensures that synapse is aware of the user's new device. Otherwise 196 | synapse will reject requests. 197 | [Check upstream for more information](https://element-hq.github.io/matrix-authentication-service/reference/cli/manage.html#manage-provision-all-users) 198 | -------------------------------------------------------------------------------- /docs/contributing/context.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Context 6 | 7 | ## Context for developing Draupnir 8 | 9 | alternatively context that is essential for developing 10 | anything that uses Policy Lists. 11 | 12 | ### The synchronisation loop 13 | 14 | In order to understand how Draupnir works you have to first understand 15 | the sync loop of Matrix Clients. All Matrix clients have a sync loop. 16 | The idea is that a client sends a request to the server with a 17 | pagination token called a sync token that the server will then 18 | respond to with any new events that the client needs to know about. 19 | You can read more about sync [here](https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3sync) 20 | 21 | Draupnir uses the 22 | [matrix-bot-sdk](https://github.com/turt2live/matrix-bot-sdk) 23 | for its client library. The `MatrixClient` from the matrix-bot-sdk can 24 | only provide us with the timeline portion of the `/sync` response. 25 | Because the timeline portion of `/sync` provides a client with events 26 | in the order in which they are received by the server (and also 27 | as they are received by the server). As opposed to their 28 | [mainline order](https://spec.matrix.org/v1.6/rooms/v2/#definitions) 29 | in the DAG, then there is no way for Draupnir to rely on `/sync` to 30 | provide an accurate representation of state for a room[^full-state]. 31 | 32 | #### Maintaining state 33 | 34 | As Draupnir cannot rely on the `timeline` component of the `/sync` 35 | response. Draupnir re-requests the entire state of a policy list each 36 | time Draupnir receives a state event in that policy list. 37 | This has to be because there is no immediate way to know whether the 38 | new state event represents the current state of the room, or is a 39 | stale event that has been discovered by Draupnir's homeserver 40 | (ie a fork in the DAG maintained by another homeserver has converged 41 | back with the one maintained by Draupnir's own homeserver). 42 | 43 | ### Policy Lists 44 | 45 | As in an introduction only, policy lists are Matrix rooms that contain 46 | bans curated by one group of moderators. As these are Matrix rooms 47 | and the bans are represented as room state, they can be shared and 48 | introspected upon from a Matrix client, as is the case with any other 49 | Matrix room. 50 | 51 | #### State events 52 | 53 | [State events](https://spec.matrix.org/latest/client-server-api/#types-of-room-events) 54 | are a way of giving rooms generic meta-data. 55 | They events are conveniently indexable by a key composed of both the 56 | `type` field on the event and also a `state_key`. 57 | These are both individually limited by a string which is no larger 58 | than "[255 bytes](https://spec.matrix.org/latest/client-server-api/#size-limits)". 59 | It is still unclear how implementations interpret this statement 60 | though, so it is better to be as conservative as possible, especially 61 | as you will still be dealing with legacy room versions. 62 | 63 | When a state event is sent to a room, the current mapping of the tuple 64 | `(type, state_key)` for a room is updated to refer to the new event. 65 | It is important to be aware that because of the nature of Matrix, 66 | every time a state event is sent there is a possibility 67 | for the DAG to diverge between different server's perspectives of 68 | the room. Meaning that the state of a room can move under your feet 69 | as these perspectives converge, 70 | and there is only one somewhat reliable way to tell when that has 71 | happened. Draupnir doesn't use a reliable method[^full-state], 72 | and it is unclear if there are any clients or bots that do. 73 | 74 | #### Policies 75 | 76 | Policies are generic state events that are usually composed of three 77 | parts. You should read specification about policy lists 78 | [here](https://spec.matrix.org/latest/client-server-api/#moderation-policy-lists) 79 | after this introduction. 80 | 81 | - `entity`: This is the target of a given policy such as a user that 82 | is being banned. 83 | 84 | - `recommendation`: This is basically what the policy recommends that 85 | the "consumer" does. The only specified recommendation in the matrix 86 | spec is `m.ban`. How `m.ban` is interpreted is even left to 87 | interpretation, as it depends on what the "consumer" of the policy is. 88 | In Draupnir's case, it usually means to ban the user from any 89 | protected room. 90 | 91 | - `reason`: This field is used by the `m.ban` recommendation as a 92 | place to replicate the "reason" field found when banning a user 93 | at the room level. It's not clear whether the field will be 94 | appropriate for all uses of `recommendation`. 95 | 96 | Currently there are only three state events that are defined by the 97 | spec and these were chosen to be intrinsically tied to the entities 98 | that the policies affect. The types are of these events are 99 | `m.policy.rule.user`, `m.policy.rule.server` and `m.policy.rule.room`. 100 | The reason why these types are scoped per entity is possibly to make 101 | policies searchable within `/devtools` -> `Explore room state` 102 | of Element Web (while also re-using the entity field of a policy as 103 | the state key). 104 | However, this choice of indexes for mapping policies to room state 105 | means that there can only be one `recommendation` per entity at a 106 | time. It also leads people to assume that every policy will be created 107 | with this combination of indexes, which in the wild isn't true. 108 | As such for a long part of Mjolnir's history some users were 109 | unbannable because this is also what was assumed in its implementation 110 | of unban. 111 | 112 | ### The ban command 113 | 114 | When the ban command is invoked, Draupnir creates a new policy in 115 | the policy list that was selected by the user. This policy recommends 116 | that the entity specified in the command (usually a user) is to be 117 | banned. That is the extent of the command's responsibilities. 118 | However, rather than waiting for Draupnir to be informed of the new 119 | policy via the `/sync` loop, the ban command does take a shortcut 120 | by informing Draupnir's internal model of the policy list of the new 121 | policy immediately. 122 | 123 | ### Policy application in Draupnir 124 | 125 | When Draupnir finds a new policy from a `/sync` response, and Draupnir 126 | has re-requested the room state for the policy list Draupnir will 127 | begin synchronising policies with with the protected rooms. 128 | Draupnir starts synchronising rooms by visiting the most recently 129 | active room first. 130 | 131 | ### A history of moderation projects 132 | 133 | Mjolnir was originally created by 134 | [Travis Ralston](https://github.com/turt2live) as a good enough 135 | solution temporarily made permanent. 136 | The abstract architecture of Mjolnir remains today and we are 137 | thankful for good foundations, and significantly 138 | [policies](https://spec.matrix.org/latest/client-server-api/#moderation-policy-lists) 139 | that were 140 | [proposed](https://github.com/matrix-org/matrix-spec-proposals/pull/2313) 141 | by [Matthew Hodgson](https://github.com/ara4n). 142 | 143 | There were several other similar solutions known to us that were 144 | developed and deployed at the same time as Mjolnir in the earlier days 145 | and either directly or indirectly had influence on things to come. 146 | Notably [Fly Swatter](https://github.com/serra-allgood/matrix-fly-swatter) 147 | and [Luna](https://gitlab.com/Gnuxie/luna). 148 | 149 | After a period of maintenance, Mjolnir was then developed by other 150 | contributors from Element who restructured the project, tackled 151 | usability concerns and would go on to produce a multi-tenancy 152 | appservice mode of deployment called "Mjolnir for all". 153 | With the eventual aim of integrating the functions of Mjolnir 154 | transparently with both homeservers and clients. 155 | 156 | This effort is now continued by the Matrix community in the form 157 | of Draupnir and [MTRNord](https://github.com/MTRNord)'s 158 | [Draupnir4all deployment](https://docs.draupnir.midnightthoughts.space/). 159 | 160 | [^full-state]: 161 | matrix-bot-sdk could be modified to sync with 162 | `full_state` set to true. This has been 163 | [attempted](https://github.com/turt2live/matrix-bot-sdk/pull/215) 164 | but the maintainer of the matrix-bot-sdk is opposed to the idea. 165 | -------------------------------------------------------------------------------- /docs/contributing/development-environment.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | sidebar_label: Tests, tools, and environment 4 | --- 5 | 6 | # Developing Draupnir - tests, tools, and environment 7 | 8 | This document is a part of our [contributing documentation](./CONTRIBUTING.md) 9 | and describes how to setup a development environment that we to develop 10 | Draupnir. If you already have your own workflow for typescript projects, you 11 | should still read this document to spot any caveats that might require you to 12 | adapt for our recommendations. 13 | 14 | ## matrix-protection-suite 15 | 16 | While not necessary, some changes will require you to make changes to the 17 | [matrix-protection-suite](https://github.com/Gnuxie/matrix-protection-suite) and 18 | the associated backend for the matrix-bot-sdk: 19 | [matrix-protection-suite-for-matrix-bot-sdk](https://github.com/Gnuxie/matrix-protection-suite-for-matrix-bot-sdk). 20 | 21 | You should clone these locally and then link them by using `yarn link` in each 22 | directory followed by 23 | `yarn link matrix-protection-suite matrix-protection-suite-for-matrix-bot-sdk` 24 | within Draupnir. 25 | 26 | You will probably also want to download 27 | [interface-manager](https://the-draupnir-project/interface-manager) if you need 28 | to make fundamental changes to the command framework. 29 | 30 | You may also need to 31 | `yarn add --dev "matrix-bot-sdk@npm:@vector-im/matrix-bot-sdk@^0.7.1-element.6"` 32 | within the `matrix-protection-suite-for-matrix-bot-sdk` directory to ensure that 33 | that the local copy is using the same version as Draupnir. I don't understand 34 | why `yarn` will not respect overrides for linked dependencies. 35 | 36 | For convenience there is also a 37 | [script](https://gist.github.com/Gnuxie/f27a6efc8a0d55918e25167add19fe8f) to 38 | link and unlink our maintained dependencies that you can add to your path 39 | 40 | ### VSCode 41 | 42 | You will also want to edit your `settings.json` to match something like this, so 43 | that you can debug into MPS while debugging Draupnir. 44 | 45 | ```json 46 | "debug.javascript.terminalOptions": { 47 | "runtimeArgs": ["--preserve-symlinks"], 48 | "sourceMaps": true, 49 | "outFiles": [ 50 | "${userHome}/experiments/draupnir/lib/**/*.js", 51 | "${userHome}/experiments/draupnir/src/**/*.ts", 52 | "${userHome}/experiments/draupnir/test/**/*.ts", 53 | "${userHome}/experiments/matrix-protection-suite/dist/**/*.js", 54 | "${userHome}/experiments/matrix-protection-suite/src/**/*.ts", 55 | "${userHome}/experiments/matrix-protection-suite-for-matrix-bot-sdk/dist/**/*.js", 56 | "${userHome}/experiments/matrix-protection-suite-for-matrix-bot-sdk/src/**/*.ts", 57 | "${userHome}/experiments/interface-manager/src/**/*.ts", 58 | "${userHome}/experiments/interface-manager/dist/**/*.js" 59 | ] 60 | } 61 | ``` 62 | 63 | ## mx-tester 64 | 65 | WARNING: mx-tester is currently work in progress, but it can still save you some 66 | time and is better than struggling with nothing. 67 | 68 | For integration testing, and spinning up a local synapse we use 69 | [mx-tester](https://github.com/matrix-org/mx-tester). While not required for 70 | basic changes, it is strongly recommended to use mx-tester or have the ability 71 | to spin up your own development Synapse to develop draupnir interactively. 72 | 73 | To install `mx-tester` you will need the [rust toolchain](https://rustup.rs/) 74 | and Docker. You should refer to your linux distribution's documentation for 75 | installing both, and do not naively follow the instructions from rustup.rs 76 | without doing so first. Then you will be able to install `mx-tester` with 77 | `cargo install mx-tester`. Updating mx-tester can be done by installing 78 | `cargo install cargo-update` and using `cargo install-update mx-tester`, though 79 | you may skip this step until it is necessary to update `mx-tester`. 80 | 81 | ### Usage 82 | 83 | You can then start a local synapse using `mx-tester build`, followed by 84 | `mx-tester up`. You can then use `up`, `down` as many times as you like. If for 85 | some reason you need to get a clean Synapse database, you can just use 86 | `mx-tester down build`. 87 | 88 | ### Development and testing with mx-tester 89 | 90 | If you have docker installed you can quickly get setup with a development 91 | environment by using [mx-tester](https://github.com/matrix-org/mx-tester). 92 | 93 | To use mx-tester you will need to have rust installed. You can do that at 94 | [rustup](https://rustup.rs/) or 95 | [here](https://rust-lang.github.io/rustup/installation/other.html), you should 96 | probably also check your distro's documentation first to see if they have 97 | specific instructions for installing rust. 98 | 99 | Once rust is installed you can install mx-tester like so. 100 | 101 | ```bash 102 | cargo install mx-tester 103 | ``` 104 | 105 | Once you have mx-tester installed you we will want to build a synapse image with 106 | synapse_antispam from the Draupnir project root. 107 | 108 | ```bash 109 | mx-tester build 110 | ``` 111 | 112 | Then we can start a container that uses that image and the config in 113 | `mx-tester.yml`. 114 | 115 | ```bash 116 | mx-tester up 117 | ``` 118 | 119 | Once you have called `mx-tester up` you can run the integration tests. 120 | 121 | ```bash 122 | yarn test:integration 123 | ``` 124 | 125 | After calling `mx-tester up`, if we want to play with Draupnir locally we can 126 | run the following and then point a matrix client to http://localhost:9999. You 127 | should then be able to join the management room at `#moderators:localhost:9999`. 128 | 129 | ```bash 130 | yarn test:manual 131 | ``` 132 | 133 | Once we are finished developing we can stop the synapse container. 134 | 135 | ```bash 136 | mx-tester down 137 | ``` 138 | 139 | ## Debugging 140 | 141 | For debugging mx-tester it is recommended to use Visual Studio Code. If you open 142 | the project in visual studio code, press `F1`, type 143 | `Debug: JavaScript Debug Terminal` (see the 144 | [documentation](https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_javascript-debug-terminal)), 145 | and you should get a terminal from which node will always connect to Visual 146 | Studio Code. 147 | 148 | The following sections assume that a Synapse is running and 149 | `config/harness.yaml` has been configured to connect to it. If you are using 150 | `mx-tester` and you use `mx-tester up`, this will already be the case. 151 | 152 | ### Debugging and reproducing an issue 153 | 154 | If you need to debug an issue that is occurring through use in matrix, say the 155 | unban command has stopped working, you can launch draupnir from the JavaScript 156 | Debug Terminal using `yarn test:manual`. This will launch draupnir using the 157 | config found in `config/harness.yaml`. You can now open https://app.element.io, 158 | change the server to `localhost:8081`, and then create an account. From here you 159 | can join the room `#moderators:localhost:9999` (you will also be able to find it 160 | in the rooms directory) and interact with draupnir. 161 | 162 | It is recommended to set breakpoints in the editor while interacting and switch 163 | the tab to "DEBUG CONSOLE" (within Visual Studio Code) to evaluate arbitrary 164 | expressions in the currently paused context (when a breakpoint has been hit). 165 | 166 | ### Running integration tests 167 | 168 | The integration tests can be run with `yarn test:integration`. The config that 169 | the tests use is in `config/harness.yaml` and by default this is configured to 170 | work with the server specified in `mx-tester.yml`, but you can configure it 171 | however you like to run against your own setup. 172 | 173 | ### Debugging an integration test 174 | 175 | To debug the integration test suite from the JavaScript Debug Terminal, you can 176 | start them using `yarn test:integration`. However, more often than not there is 177 | a specific section of code you will be working on that has specific tests. 178 | Running the entire suite is therefore unnecessary. To run a specific test from 179 | the JavaScript Debug Terminal, you can use the script 180 | `yarn test:integration:single test/integration/banListTest.ts`, where 181 | `test/integration/banListTest.ts` is the name of the integration test you want 182 | to run. 183 | -------------------------------------------------------------------------------- /docs/contributing/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 0 3 | --- 4 | 5 | # Contributing to Draupnir 6 | 7 | ## Welcome 8 | 9 | Hi, thank you for considering to contribute to Draupnir. 10 | 11 | Do not worry about following the guidance in this document to the letter, we'd 12 | much rather you get involved than avoid doing so because of a technicality. 13 | Please keep this in mind throughout. 14 | 15 | ## Getting Started 16 | 17 | What kind of contribution are you trying to make? 18 | 19 | If you are looking to document an issue, request a feature, develop a feature, 20 | please proceed into the [Issue](#issue) section. 21 | 22 | If you are looking to develop or contribute a fix, feature, or documentation for 23 | an existing issue, please proceed to the 24 | [Fixing or implementing an existing issue](#fixing-or-implementing-an-existing-issue) 25 | section. 26 | 27 | ### Issue 28 | 29 | If you can, just open the issue on the repository and we'll see it and come 30 | speak to you. 31 | 32 | Alternatively, if you aren't comfortable doing so or can't phrase the problem or 33 | feature, then come speak to us in our support room. We'll probably end up 34 | creating the issue for you! 35 | 36 | In either case, you should join our support room 37 | [#draupnir:matrix.org](https://matrix.to/#/#draupnir:matrix.org) :3 38 | 39 | Do not worry about making duplicates or alignment with project goals, the triage 40 | process is supposed to find that for you. 41 | 42 | ### Fixing or implementing an existing issue 43 | 44 | If we have triaged the issue, even without writing our own context or 45 | clarifications, then the issue is likely ready to implement. 46 | 47 | You should write a small statement in the issue or a quick message to our 48 | support room about how you intend to resolve the issue before getting started. 49 | 50 | If you don't know how to get started or what to change, please ask! 51 | 52 | ## Where to start 53 | 54 | Join our room [#draupnir:matrix.org](https://matrix.to/#/#draupnir:matrix.org)! 55 | 56 | ### How Draupnir works 57 | 58 | Checkout our [context document](./context.md). 59 | 60 | ### Code 61 | 62 | Checkout our [development guide](./development.md). 63 | 64 | ### Issues & Triaging 65 | 66 | We don't have a specific guide for opening issues, just go ahead. 67 | 68 | You can read about our issue triaging process [here](./triaging.md) 69 | 70 | ### Documentation 71 | 72 | Documentation is kept on a distinct site 73 | https://github.com/the-draupnir-project/draupnir-documentation. Issues relating 74 | to documentation should be opened on the Draupnir repository itself, as we 75 | consider documentation to be an essential part of the software, and so will be 76 | triaged and documented as the same. 77 | 78 | ## Making Pull Requests 79 | 80 | The preferred and easiest way to contribute changes to Draupnir is to fork the 81 | relevant repo on github, and then 82 | [create a pull request](https://help.github.com/articles/using-pull-requests/) 83 | to ask us to pull your changes into the repo. 84 | 85 | We use Github Actions for continuous integration. If your change breaks the 86 | build, this will be shown in GitHub, so please keep an eye on the pull request 87 | for feedback. 88 | 89 | ## Sign off 90 | 91 | We ask that everybody who contributes to Draupnir repositories signs off their 92 | contributions, as explained below. 93 | 94 | We follow a simple 'inbound=outbound' model for contributions: the act of 95 | submitting an 'inbound' contribution means that the contributor agrees to 96 | license their contribution under the same terms as the project's overall 97 | 'outbound' license - in our case, this is the Academic Free License v. 3.0 (see 98 | [LICENSE](https://github.com/the-draupnir-project/Draupnir/blob/main/LICENSES/AFL-3.0.txt)). 99 | 100 | In order to have a concrete record that your contribution is intentional and you 101 | agree to license it under the same terms as the project's license, we've adopted 102 | the same lightweight approach used by the 103 | [Linux Kernel](https://www.kernel.org/doc/html/latest/process/submitting-patches.html), 104 | [Docker](https://github.com/docker/docker/blob/master/CONTRIBUTING.md), and many 105 | other projects: the 106 | [Developer Certificate of Origin](https://developercertificate.org/) (DCO). This 107 | is a simple declaration that you wrote the contribution or otherwise have the 108 | right to contribute it to The Draupnir Project: 109 | 110 | ``` 111 | Developer Certificate of Origin 112 | Version 1.1 113 | 114 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 115 | 660 York Street, Suite 102, 116 | San Francisco, CA 94110 USA 117 | 118 | Everyone is permitted to copy and distribute verbatim copies of this 119 | license document, but changing it is not allowed. 120 | 121 | Developer's Certificate of Origin 1.1 122 | 123 | By making a contribution to this project, I certify that: 124 | 125 | (a) The contribution was created in whole or in part by me and I 126 | have the right to submit it under the open source license 127 | indicated in the file; or 128 | 129 | (b) The contribution is based upon previous work that, to the best 130 | of my knowledge, is covered under an appropriate open source 131 | license and I have the right under that license to submit that 132 | work with modifications, whether created in whole or in part 133 | by me, under the same open source license (unless I am 134 | permitted to submit under a different license), as indicated 135 | in the file; or 136 | 137 | (c) The contribution was provided directly to me by some other 138 | person who certified (a), (b) or (c) and I have not modified 139 | it. 140 | 141 | (d) I understand and agree that this project and the contribution 142 | are public and that a record of the contribution (including all 143 | personal information I submit with it, including my sign-off) is 144 | maintained indefinitely and may be redistributed consistent with 145 | this project or the open source license(s) involved. 146 | ``` 147 | 148 | If you agree to this for your contribution, then all that's needed is to include 149 | the line in your commit or pull request comment: 150 | 151 | ``` 152 | Signed-off-by: Your Name 153 | ``` 154 | 155 | Git allows you to add this signoff automatically when using the `-s` flag to 156 | `git commit`, which uses the name and email set in your `user.name` and 157 | `user.email` git configs. 158 | 159 | ## Conclusion 160 | 161 | That's it! Matrix is a very open and collaborative project as you might expect 162 | given our obsession with open communication. If we're going to successfully 163 | matrix together all the fragmented communication technologies out there we are 164 | reliant on contributions and collaboration from the community to do so. So 165 | please get involved - and we hope you have as much fun hacking on Matrix as we 166 | do! 167 | 168 | ## Further notes on license and its relation to business in general 169 | 170 | Ultimately most open source software contributions start by gifting labour 171 | without any obligation or transaction. 172 | 173 | There is no ethical way to directly sell this labour. 174 | 175 | Many so called post open source[^post-open-source] ideas fixate on finding a way 176 | to conduct business in an ethical way, and this is problematic. 177 | 178 | Once you start working within capitalism with capitalism, and exchange your 179 | power and influence over a work to monetize the work itself, the work will gain 180 | inertia and a power of its own that you cannot control. You will work for the 181 | work, for external interests, and these won't be the interests of your powerless 182 | users who you were among to begin with. 183 | 184 | It would be extreme, but I am tempted to suggest that by performing a business 185 | this way, you are part of an effort which not only reinforces capitalism but 186 | works to make it more efficient. Effectively working to make capitalism more 187 | powerful. Congratulations. 188 | 189 | Another point that is often brought up in these discussions is how software 190 | licensing relies on an appeal to state power, the power of the law. 191 | 192 | Therefore I propose a new licensing model, one which appeals to the power of 193 | public pressure rather than the law. 194 | 195 | Such a license would be liberal, allowing incorporating into proprietary works 196 | provided it retained a notice. However, any work which is used in any way to 197 | conduct business must report all software being used by the business with this 198 | license, all turnover made by the business, all profit made by the business and 199 | an estimation of both profit and turnover made by the business in relation to 200 | the collection of software reported. 201 | 202 | It is not clear to me how often these figures should be reported and when, or 203 | even where they should be reported to (ideally they could be found centrally). 204 | It is also unclear how to create the legalise required. 205 | 206 | With the information these licenses would provide, public pressure could then be 207 | used to demand reparations for the profits made by pillaging and destructive 208 | businesses. It is not clear yet how any reparations would be distributed, 209 | probably through some system of 210 | [venture communes](https://wiki.p2pfoundation.net/Venture_Commune). The idea is 211 | to ensure that the developers and users of projects would not be distracted from 212 | providing each other mutual support and to give them a hope of escaping. 213 | 214 | [^post-open-source] 215 | https://applied-langua.ge/posts/the-poverty-of-post-open-source.html. 216 | --------------------------------------------------------------------------------