mirror of
https://github.com/the-draupnir-project/Draupnir.git
synced 2026-07-17 00:47:01 +02:00
Monoreponir (#1046)
* Move src to apps/draupnir/src https://github.com/the-draupnir-project/planning/issues/100 * Move package.json https://github.com/the-draupnir-project/planning/issues/100 * Add matrix-basic-types to monorepo. Get everything working including linting and prettier :3 https://github.com/the-draupnir-project/planning/issues/100 * Add interface-manager to monorepo. This was a bitch because apparently we forgot to delete node_modules before creating the workspace package.json. So it had linked a bunch of local stuff like was in node_modules for Draupnir... Anyways i think we're still on track. https://github.com/the-draupnir-project/planning/issues/100 * idk why there are prettier changes in apps but there are. * Add matrix-protection-suite to monorepo. https://github.com/the-draupnir-project/planning/issues/100 * Add matrix-protection-suite-for-matrix-bot-sdk https://github.com/the-draupnir-project/planning/issues/100 We will need to add the real upstreams and versions and remove the file links as we publish the packages. * Move mps-interface-adaptor into monorepo https://github.com/the-draupnir-project/planning/issues/100 Wohoo, i think only draupnir is left now? * Move Draupnir test files to draupnir directory smh smh smh. https://github.com/the-draupnir-project/planning/issues/100 * Fix typescript config for tests and eslint. Now we get proper linting and type checking of tests. https://github.com/the-draupnir-project/planning/issues/100 * WIP Integrating draupnir into monorepo tooling... https://github.com/the-draupnir-project/planning/issues/100 We need to stop aliasing bot-sdk but we should first check that upstream is using a consistent name too. * Remove matrix-bot-sdk alias for vector fork. https://github.com/the-draupnir-project/planning/issues/100 * Add top command description type and weave through API. A more recent version of typescript meant that the exectutor's contravariance got checked which destroyed the API so we had to make a top type for command descriptions and parametrise some of the API. https://github.com/the-draupnir-project/planning/issues/100 * Fix typescript errors related to class property initialisation changes. https://www.typescriptlang.org/tsconfig/#useDefineForClassFields Seems like they were using defineProperty before which meant properites were initialised after the constructor ran. Honestly i like that more but we're going to stick with what they intend to be the default. https://github.com/the-draupnir-project/planning/issues/100 * Fix tests lacking fixtures context. https://github.com/the-draupnir-project/planning/issues/100 * Fix typescript errors related to error destructuring in tests. https://github.com/the-draupnir-project/planning/issues/100 * Pin postgres package to workaround upstream issue https://github.com/porsager/postgres/issues/1150 Documented in DEPENDENCIES.md https://github.com/the-draupnir-project/planning/issues/100 * Fix contravariance issue in hash store helper. Part of the TS 5.9 upgrade fallout. https://github.com/the-draupnir-project/planning/issues/100 * Fix minor typescript 5.9 migration issuess All typescript errors finished, yay. * Fix REUSE missing headers. * Fix assets script in draupnir app. * Add Draupnir to eslint scope * Remove the appservice web API. There are too many eslint errors here to do with unsafe parsing of properties from the body etc. And there's actually no consumers to this API. It's also a widget API, and all it does is provision the bot and nothing more. * Fix eslint config for DeadDocumentJSX. It wasn't working well with the jsx templates. We should probably delete the tsconfig.eslint.json shite now. * Update src/utils.ts for eslint. This shit is legacy i hate it. * Fix eslint errors in config. Really this is paint over rot since the config doesn't have a schema, and we can't really make one either. * Fix eslint issues in ReportManager. This code is diabolical. It hasn't really been fixed that will take refactoring and making sure people don't write this sorts of bad code ever again. Which thankfully we have process in place for. * Fix clientHelper eslint issues. * Fix eslint for ImportCommand. * Grinding eslint fml. * Fix miscellaneous eslint issues. * allow no-deprecate for logMessage. shit's being annoying. * Fix remaining eslint issues... We also deleted one of the scripts used to evaluate the performance of various endpoints, which we were not using. * Give bot toggle asyncDispose for code consistency. * Fix package.json access issues. * Adjust Docker and CI for new app location in monorepo. * Fix broken integration tests. * Remove prepare script from matrix-protection-suite package. Isn't needed anymore * Fix build:all script missing base files. * Remove test script from matrix-protection-suite-for-matrix-bot-sdk It doesn't have any tests :/ * Order of setup is wrong in integration test workflows. * Fix mps interface adaptor doesn't have any tests. * Fix appservice registration for test harness. * Fix matrix-basic-types jest configuration * Fix no build step in mjolnir.yaml * Transfer common dev dependencies to the workspace root. They were just wrong.
This commit is contained in:
+6
-7
@@ -1,18 +1,17 @@
|
||||
# SPDX-FileCopyrightText: 2024 Aminda Suomalainen <suomalainen+git@mikaela.info>
|
||||
# SPDX-FileCopyrightText: 2024 Gnuxie <Gnuxie@protonmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
# SPDX-License-Identifier: 0BSD
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{LICENSE,NOTICE,*.{md,yml,yaml,json,txt}}]
|
||||
[LICENSES/**.txt]
|
||||
trim_trailing_whitespace = false
|
||||
indent_style = space
|
||||
indent_size = unset
|
||||
|
||||
@@ -26,9 +26,9 @@ jobs:
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: corepack enable
|
||||
- run: corepack yarn install
|
||||
- run: corepack yarn build
|
||||
- run: corepack yarn lint
|
||||
- run: corepack npm install
|
||||
- run: corepack npm run build:all
|
||||
- run: corepack npm run lint
|
||||
unit:
|
||||
name: Unit tests
|
||||
runs-on: ubuntu-latest
|
||||
@@ -38,8 +38,9 @@ jobs:
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "20"
|
||||
- run: corepack yarn install
|
||||
- run: corepack yarn test:unit
|
||||
- run: corepack npm install
|
||||
- run: corepack npm run build:all
|
||||
- run: corepack npm run test
|
||||
integration:
|
||||
name: Integration tests
|
||||
runs-on: ubuntu-latest
|
||||
@@ -54,10 +55,10 @@ jobs:
|
||||
with:
|
||||
crate: mx-tester
|
||||
version: "0.3.3"
|
||||
- name: Setup dependencies
|
||||
run: corepack npm install && corepack npm run build:all
|
||||
- name: Setup image
|
||||
run: RUST_LOG=debug,hyper=info,rusttls=info mx-tester build up
|
||||
- name: Setup dependencies
|
||||
run: corepack yarn install
|
||||
- name: Run tests
|
||||
run: RUST_LOG=debug,hyper=info,rusttls=info mx-tester run
|
||||
- name: Cleanup
|
||||
@@ -76,11 +77,11 @@ jobs:
|
||||
with:
|
||||
crate: mx-tester
|
||||
version: "0.3.3"
|
||||
- name: Setup dependencies
|
||||
run: corepack npm install && corepack npm run build:all
|
||||
- name: Setup image
|
||||
run: RUST_LOG=debug,hyper=info,rusttls=info mx-tester build up
|
||||
- name: Setup dependencies
|
||||
run: corepack yarn install
|
||||
- name: Run tests
|
||||
run: corepack yarn test:appservice:integration
|
||||
run: corepack npm run -w apps/draupnir test:appservice:integration
|
||||
- name: Cleanup
|
||||
run: mx-tester down
|
||||
|
||||
+6
-1
@@ -8,7 +8,12 @@ config/*
|
||||
|
||||
# Draupnir test data
|
||||
draupnir-registration.yaml
|
||||
test/harness/mjolnir-data/*
|
||||
|
||||
# Monorepo
|
||||
**/node_modules/
|
||||
**/dist/
|
||||
**/lib/
|
||||
*.tsbuildinfo
|
||||
|
||||
# Misc
|
||||
|
||||
|
||||
+15
-10
@@ -1,13 +1,13 @@
|
||||
# SPDX-FileCopyrightText: 2024 Aminda Suomalainen <suomalainen+git@mikaela.info>
|
||||
# SPDX-FileCopyrightText: 2024 Gnuxie <Gnuxie@protonmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
# SPDX-License-Identifier: 0BSD
|
||||
|
||||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
# See https://pre-commit.ci for more information
|
||||
ci:
|
||||
autoupdate_schedule: weekly
|
||||
skip: [yarn-lint]
|
||||
autoupdate_schedule: monthly
|
||||
skip: [npm-lint, npm-build]
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
@@ -18,9 +18,6 @@ repos:
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
- id: check-executables-have-shebangs
|
||||
- id: check-shebang-scripts-are-executable
|
||||
- id: check-illegal-windows-names
|
||||
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
|
||||
rev: "3.6.1"
|
||||
hooks:
|
||||
@@ -32,10 +29,18 @@ repos:
|
||||
- id: reuse
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: yarn-lint
|
||||
name: linter
|
||||
entry: corepack yarn lint
|
||||
- id: npm-build
|
||||
name: npm build
|
||||
entry: npm run build:all
|
||||
language: system
|
||||
pass_filenames: false
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: npm-lint
|
||||
name: linter
|
||||
entry: npm run lint
|
||||
language: system
|
||||
pass_filenames: false
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.37.0
|
||||
hooks:
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# SPDX-FileCopyrightText: 2024 Gnuxie <Gnuxie@protonmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: AFL-3.0
|
||||
|
||||
dist
|
||||
packages/matrix-protection-suite/docs
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# SPDX-FileCopyrightText: 2024 Gnuxie <Gnuxie@protonmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
# SPDX-License-Identifier: 0BSD
|
||||
|
||||
tabWidth: 2
|
||||
useTabs: false
|
||||
|
||||
@@ -752,7 +752,6 @@ Special thanks to all contributors who helped in the beta programme: @avdb13,
|
||||
https://github.com/the-draupnir-project/Draupnir/issues/622.
|
||||
|
||||
- The `JoinWaveShortCircuitProtection` has been improved:
|
||||
|
||||
- The `JoinWaveShortCircuitProtection` now uses a leaky bucket token
|
||||
algorithm, prior to this the entire bucket got dumped after a preconfigured
|
||||
time.
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2026 Gnuxie <Gnuxie@protonmail.com>
|
||||
|
||||
SPDX-License-Identifier: 0BSD
|
||||
-->
|
||||
|
||||
# Dependencies
|
||||
|
||||
## Pinned dependencies
|
||||
|
||||
### @vector-im/matrix-bot-sdk
|
||||
|
||||
This is pinned and overridden because we need to have the exact same version for
|
||||
all dependencies. As we create and pass `MatrixClient` through Draupnir,
|
||||
matrix-protection-suite-for-matrix-bot-sdk, the vector bot-sdk fork itself, and
|
||||
also matrix-appservice-bridge.
|
||||
|
||||
### postgres
|
||||
|
||||
https://github.com/porsager/postgres/issues/1143
|
||||
|
||||
This is pinned specifically as a work around for this issue.
|
||||
|
||||
## Workspace dependencies
|
||||
|
||||
Workspace dependencies should be kept at their same version and changesets
|
||||
should be used for any changes. Package release should only be made from the
|
||||
main branch once changesets have been merged and the associated package versions
|
||||
bumped. This allows for the workspace state to always be used to build Draupnir
|
||||
reproducibly on any branch of PR.
|
||||
|
||||
## Developer tooling
|
||||
|
||||
Developer tooling related `devDependencies` should be kept in the root package
|
||||
unless it is not common to most packages. This is to make sure the versioning
|
||||
remains consistent without relying on npm to do that.
|
||||
+5
-6
@@ -10,16 +10,15 @@ COPY . /tmp/src
|
||||
RUN cd /tmp/src && git describe > version.txt.tmp && mv version.txt.tmp version.txt
|
||||
# build and install
|
||||
RUN cd /tmp/src \
|
||||
&& yarn install --frozen-lockfile --network-timeout 100000 \
|
||||
&& yarn build \
|
||||
&& yarn install --frozen-lockfile --production --network-timeout 100000
|
||||
&& npm ci \
|
||||
&& npm run build \
|
||||
&& npm prune --production
|
||||
|
||||
FROM node:20-slim as final-stage
|
||||
COPY --from=build-stage /tmp/src/version.txt version.txt
|
||||
COPY --from=build-stage /tmp/src/lib/ /draupnir/
|
||||
COPY --from=build-stage /tmp/src/apps/draupnir /apps/draupnir
|
||||
COPY --from=build-stage /tmp/src/packages /packages
|
||||
COPY --from=build-stage /tmp/src/node_modules /node_modules
|
||||
COPY --from=build-stage /tmp/src/draupnir-entrypoint.sh /
|
||||
COPY --from=build-stage /tmp/src/package.json /
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV NODE_CONFIG_DIR=/data/config
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Copyright (C) YEAR by AUTHOR EMAIL
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
@@ -0,0 +1,18 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
||||
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+29
-11
@@ -7,37 +7,55 @@ SPDX-PackageDownloadLocation = "https://github.com/the-draupnir-project/Draupnir
|
||||
path = ".github/ISSUE_TEMPLATE/bug-report.md"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "tsconfig.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "tsconfig.base.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "tsconfig.all.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "tsconfig.eslint.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "REUSE.toml"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "yarn.lock"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "package-lock.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "NOTICE"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "test/tsconfig.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "package.json"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-FileCopyrightText: 2026 Gnuxie <Gnuxie@protonmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: 0BSD
|
||||
|
||||
test/harness/mjolnir-data/*
|
||||
@@ -0,0 +1,64 @@
|
||||
version = 1
|
||||
SPDX-PackageName = "Draupnir"
|
||||
SPDX-PackageSupplier = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-PackageDownloadLocation = "https://github.com/the-draupnir-project/Draupnir"
|
||||
|
||||
[[annotations]]
|
||||
path = ".github/ISSUE_TEMPLATE/bug-report.md"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "tsconfig.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "tsconfig.test.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "tsconfig.base.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "REUSE.toml"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "yarn.lock"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "package-lock.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "NOTICE"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "test/tsconfig.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "0BSD"
|
||||
|
||||
[[annotations]]
|
||||
path = "package.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Gnuxie <Gnuxie@protonmail.com>"
|
||||
SPDX-License-Identifier = "AFL-3.0"
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"name": "draupnir",
|
||||
"version": "2.9.0",
|
||||
"description": "A moderation tool for Matrix",
|
||||
"main": "lib/index.js",
|
||||
"repository": "https://github.com/the-draupnir-project/Draupnir.git",
|
||||
"author": "Gnuxie",
|
||||
"license": "AFL-3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "tsc --project test/tsconfig.json && npm run build:assets",
|
||||
"build:assets": "cp src/protections/DraupnirNews/news.json dist/protections/DraupnirNews/news.json && npm run describe-version",
|
||||
"describe-version": "(git describe > version.txt.tmp && mv version.txt.tmp version.txt) || true && rm -f version.txt.tmp",
|
||||
"harness-registration": "node dist/appservice/cli.js -r -u \"http://host.docker.internal:9000\" --enable-source-maps",
|
||||
"test:unit": "mocha --require './test/tsnode.cjs' --forbid-only 'test/unit/**/*.{ts,tsx}'",
|
||||
"test:unit:single": "mocha --require test/tsnode.cjs",
|
||||
"test:integration": "NODE_ENV=harness mocha --require test/tsnode.cjs --async-stack-traces --forbid-only --require test/integration/fixtures.ts --timeout 300000 --project ./tsconfig.json \"test/integration/**/*Test.ts\" -- --draupnir-config ../../config/harness.yaml",
|
||||
"test:integration:single": "NODE_ENV=harness mocha --require test/tsnode.cjs --require test/integration/fixtures.ts --timeout 300000 --project ./tsconfig.json -- --draupnir-config ../../config/harness.yaml",
|
||||
"test:appservice:integration": "NODE_ENV=harness mocha --require test/tsnode.cjs --async-stack-traces --forbid-only --timeout 300000 --project ./tsconfig.json \"test/appservice/integration/**/*Test.ts\" -- --draupnir-config ../../config/harness.yaml",
|
||||
"test:appservice:integration:single": "NODE_ENV=harness mocha --require test/tsnode.cjs --timeout 300000 --project ./tsconfig.json -- --draupnir-config ../../config/harness.yaml",
|
||||
"test:manual": "NODE_ENV=harness ts-node test/integration/manualLaunchScript.ts -- --draupnir-config ../../config/harness.yaml"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/better-sqlite3": "^7.6.9",
|
||||
"@types/config": "^3.3.1",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/html-to-text": "^8.0.1",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/jsdom": "21.1.7",
|
||||
"@types/mocha": "^10.0.7",
|
||||
"@types/nedb": "^1.8.16",
|
||||
"@types/node": "^20.14.11",
|
||||
"@types/pg": "^8.6.5",
|
||||
"@types/request": "^2.48.12",
|
||||
"crypto-js": "^4.2.0",
|
||||
"expect": "^29.7.0",
|
||||
"mocha": "^10.7.0",
|
||||
"ts-auto-mock": "^3.7.4",
|
||||
"ts-node": "^10.9.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@gnuxie/typescript-result": "^1.0.0",
|
||||
"@sentry/node": "^7.17.2",
|
||||
"@sinclair/typebox": "0.34.13",
|
||||
"@the-draupnir-project/interface-manager": "4.2.6",
|
||||
"@the-draupnir-project/matrix-basic-types": "1.5.0",
|
||||
"@the-draupnir-project/mps-interface-adaptor": "file:../../packages/mps-interface-adaptor",
|
||||
"@vector-im/matrix-bot-sdk": "0.7.1-element.6",
|
||||
"better-sqlite3": "^9.4.3",
|
||||
"body-parser": "^1.20.2",
|
||||
"config": "^3.3.9",
|
||||
"express": "^4.19",
|
||||
"html-to-text": "^8.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsdom": "^24.0.0",
|
||||
"matrix-appservice-bridge": "10.3.1",
|
||||
"matrix-protection-suite": "file:../../packages/matrix-protection-suite",
|
||||
"matrix-protection-suite-for-matrix-bot-sdk": "file:../../packages/matrix-protection-suite-for-matrix-bot-sdk",
|
||||
"pg": "^8.8.0",
|
||||
"yaml": "^2.3.2"
|
||||
},
|
||||
"overrides": {
|
||||
"@vector-im/matrix-bot-sdk": "0.7.1-element.6",
|
||||
"@the-draupnir-project/matrix-basic-types": "$the-draupnir-project/matrix-basic-types",
|
||||
"@the-draupnir-project/interface-manager": "$the-draupnir-project/interface-manager",
|
||||
"matrix-protection-suite": "$matrix-protection-suite"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ import {
|
||||
SynapseAdminClient,
|
||||
} from "matrix-protection-suite-for-matrix-bot-sdk";
|
||||
import { IConfig } from "./config";
|
||||
import { LogLevel } from "matrix-bot-sdk";
|
||||
import { LogLevel } from "@vector-im/matrix-bot-sdk";
|
||||
import { RendererMessageCollector } from "./capabilities/RendererMessageCollector";
|
||||
import { DraupnirRendererMessageCollector } from "./capabilities/DraupnirRendererMessageCollector";
|
||||
import { renderProtectionFailedToStart } from "./protections/ProtectedRoomsSetRenderers";
|
||||
@@ -97,7 +97,9 @@ export class Draupnir implements Client, MatrixAdaptorContext {
|
||||
*/
|
||||
public unlistedUserRedactionQueue = new UnlistedUserRedactionQueue();
|
||||
|
||||
private readonly commandDispatcher = makeDraupnirCommandDispatcher(this);
|
||||
private readonly commandDispatcher: ReturnType<
|
||||
typeof makeDraupnirCommandDispatcher
|
||||
>;
|
||||
public taskQueue: ThrottlingQueue;
|
||||
/**
|
||||
* Reporting back to the management room.
|
||||
@@ -115,32 +117,21 @@ export class Draupnir implements Client, MatrixAdaptorContext {
|
||||
|
||||
public readonly reactionHandler: MatrixReactionHandler;
|
||||
|
||||
public readonly purgingDeactivate =
|
||||
this.synapseAdminClient && this.stores.userRestrictionAuditLog
|
||||
? new HomeserverUserPurgingDeactivate(
|
||||
this.synapseAdminClient,
|
||||
this.stores.userRestrictionAuditLog
|
||||
)
|
||||
: undefined;
|
||||
public readonly purgingDeactivate:
|
||||
| HomeserverUserPurgingDeactivate
|
||||
| undefined;
|
||||
|
||||
private readonly timelineEventListener = this.handleTimelineEvent.bind(this);
|
||||
|
||||
public readonly capabilityMessageRenderer: RendererMessageCollector;
|
||||
|
||||
private readonly commandDispatcherTimelineListener =
|
||||
makeCommandDispatcherTimelineListener(
|
||||
this.managementRoom,
|
||||
this.client,
|
||||
this.commandDispatcher
|
||||
);
|
||||
private readonly commandDispatcherTimelineListener: ReturnType<
|
||||
typeof makeCommandDispatcherTimelineListener
|
||||
>;
|
||||
|
||||
private readonly JSInterfaceDispatcher: JSInterfaceCommandDispatcher<BasicInvocationInformation> =
|
||||
makeDraupnirJSCommandDispatcher(this);
|
||||
private readonly JSInterfaceDispatcher: JSInterfaceCommandDispatcher<BasicInvocationInformation>;
|
||||
|
||||
public readonly timelineRedactionQueue = new TimelineRedactionQueue(
|
||||
this.clientPlatform.toRoomMessages(),
|
||||
this.clientPlatform.toRoomEventRedacter()
|
||||
);
|
||||
public readonly timelineRedactionQueue: TimelineRedactionQueue;
|
||||
|
||||
private constructor(
|
||||
public readonly client: MatrixSendClient,
|
||||
@@ -163,6 +154,25 @@ export class Draupnir implements Client, MatrixAdaptorContext {
|
||||
public readonly synapseAdminClient: SynapseAdminClient | undefined,
|
||||
public readonly synapseHTTPAntispam: SynapseHttpAntispam | undefined
|
||||
) {
|
||||
this.commandDispatcher = makeDraupnirCommandDispatcher(this);
|
||||
this.purgingDeactivate =
|
||||
this.synapseAdminClient && this.stores.userRestrictionAuditLog
|
||||
? new HomeserverUserPurgingDeactivate(
|
||||
this.synapseAdminClient,
|
||||
this.stores.userRestrictionAuditLog
|
||||
)
|
||||
: undefined;
|
||||
this.commandDispatcherTimelineListener =
|
||||
makeCommandDispatcherTimelineListener(
|
||||
this.managementRoom,
|
||||
this.client,
|
||||
this.commandDispatcher
|
||||
);
|
||||
this.JSInterfaceDispatcher = makeDraupnirJSCommandDispatcher(this);
|
||||
this.timelineRedactionQueue = new TimelineRedactionQueue(
|
||||
this.clientPlatform.toRoomMessages(),
|
||||
this.clientPlatform.toRoomEventRedacter()
|
||||
);
|
||||
this.managementRoomOutput = new ManagementRoomOutput(
|
||||
this.managementRoomDetail,
|
||||
this.clientUserID,
|
||||
@@ -68,9 +68,8 @@ export function constructWebAPIs(draupnir: Draupnir): WebAPIs {
|
||||
* The appservice also implements `SafeModeToggle` but has different requirements.
|
||||
* This interface is exlusively used by the entrypoints to draupnir's bot mode.
|
||||
*/
|
||||
interface BotModeTogle extends SafeModeToggle {
|
||||
interface BotModeTogle extends SafeModeToggle, AsyncDisposable {
|
||||
encryptionInitialized(): Promise<void>;
|
||||
stopEverything(): void;
|
||||
startFromScratch(
|
||||
options?: SafeModeToggleOptions
|
||||
): Promise<Result<Draupnir | SafeModeDraupnir>>;
|
||||
@@ -276,7 +275,7 @@ export class DraupnirBotModeToggle implements BotModeTogle {
|
||||
|
||||
public async maybeRecoverWithSafeMode(
|
||||
error: ResultError,
|
||||
options?: SafeModeToggleOptions | undefined
|
||||
options?: SafeModeToggleOptions
|
||||
): Promise<Result<SafeModeDraupnir>> {
|
||||
switch (this.config.safeMode?.bootOption) {
|
||||
case SafeModeBootOption.Never:
|
||||
@@ -303,14 +302,9 @@ export class DraupnirBotModeToggle implements BotModeTogle {
|
||||
|
||||
public async encryptionInitialized(): Promise<void> {
|
||||
if (this.draupnir !== null) {
|
||||
try {
|
||||
this.webAPIs = constructWebAPIs(this.draupnir);
|
||||
await this.webAPIs.start();
|
||||
await this.draupnir.startupComplete();
|
||||
} catch (e) {
|
||||
await this.stopEverything();
|
||||
throw e;
|
||||
}
|
||||
this.webAPIs = constructWebAPIs(this.draupnir);
|
||||
await this.webAPIs.start();
|
||||
await this.draupnir.startupComplete();
|
||||
} else if (this.safeModeDraupnir !== null) {
|
||||
this.safeModeDraupnir.startupComplete();
|
||||
}
|
||||
@@ -328,7 +322,7 @@ export class DraupnirBotModeToggle implements BotModeTogle {
|
||||
this.safeModeDraupnir = null;
|
||||
}
|
||||
|
||||
public async stopEverything(): Promise<void> {
|
||||
public async [Symbol.asyncDispose](): Promise<void> {
|
||||
await this.stopDraupnir();
|
||||
this.stopSafeModeDraupnir();
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
} from "matrix-appservice-bridge";
|
||||
import { DataStore } from ".//datastore";
|
||||
import { PgDataStore } from "./postgres/PgDataStore";
|
||||
import { Api } from "./Api";
|
||||
import { AppserviceConfig } from "./config/config";
|
||||
import { AccessControl } from "./AccessControl";
|
||||
import { AppserviceCommandHandler } from "./bot/AppserviceCommandHandler";
|
||||
@@ -57,7 +56,6 @@ const log = new Logger("AppService");
|
||||
* the entrypoint of the application.
|
||||
*/
|
||||
export class MjolnirAppService {
|
||||
private readonly api: Api;
|
||||
public readonly commands: AppserviceCommandHandler;
|
||||
|
||||
/**
|
||||
@@ -78,7 +76,6 @@ export class MjolnirAppService {
|
||||
public readonly accessControlRoomID: StringRoomID,
|
||||
public readonly botUserID: StringUserID
|
||||
) {
|
||||
this.api = new Api(config.homeserver.url, draupnirManager);
|
||||
const client = this.bridge.getBot().getClient();
|
||||
this.commands = new AppserviceCommandHandler(
|
||||
botUserID,
|
||||
@@ -278,7 +275,8 @@ export class MjolnirAppService {
|
||||
);
|
||||
} catch (e: unknown) {
|
||||
log.error(
|
||||
`Failed to join the room by ${mxEvent.sender} to display the welcome flow`
|
||||
`Failed to join the room by ${mxEvent.sender} to display the welcome flow`,
|
||||
e
|
||||
);
|
||||
}
|
||||
try {
|
||||
@@ -364,7 +362,6 @@ export class MjolnirAppService {
|
||||
"Starting DraupnirAppService, Matrix-side to listen on port",
|
||||
port
|
||||
);
|
||||
this.api.start(this.config.webAPI.port);
|
||||
await this.bridge.listen(port);
|
||||
this.prometheusMetrics.addAppServicePath(this.bridge);
|
||||
this.bridge.addAppServicePath({
|
||||
@@ -384,7 +381,6 @@ export class MjolnirAppService {
|
||||
public async close(): Promise<void> {
|
||||
await this.bridge.close();
|
||||
await this.dataStore.close();
|
||||
await this.api.close();
|
||||
this.draupnirManager.unregisterListeners();
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import { Bridge, Intent, Logger } from "matrix-appservice-bridge";
|
||||
import { getProvisionedMjolnirConfig } from "../config";
|
||||
import { MatrixClient } from "matrix-bot-sdk";
|
||||
import { MatrixClient } from "@vector-im/matrix-bot-sdk";
|
||||
import { DataStore, MjolnirRecord } from "./datastore";
|
||||
import { AccessControl } from "./AccessControl";
|
||||
import { randomUUID } from "crypto";
|
||||
@@ -26,7 +26,10 @@ const cli = new Cli({
|
||||
defaults: {},
|
||||
},
|
||||
generateRegistration: MjolnirAppService.generateRegistration,
|
||||
run: function (port: number) {
|
||||
run: function (port) {
|
||||
if (port === null) {
|
||||
throw new Error("Please specify a port for the appservice to run");
|
||||
}
|
||||
const config = cli.getConfig();
|
||||
if (config === null) {
|
||||
throw new Error("Couldn't load config");
|
||||
-4
@@ -13,10 +13,6 @@ db:
|
||||
# See docs/access_control.md
|
||||
adminRoom: "#draupnir-admin:localhost:9999"
|
||||
|
||||
# This is a web api that the widget connects to in order to interact with the appservice.
|
||||
webAPI:
|
||||
port: 9001
|
||||
|
||||
# The directory the bot should store various bits of information in
|
||||
dataPath: "/data/storage"
|
||||
|
||||
-3
@@ -8,9 +8,6 @@ db:
|
||||
|
||||
adminRoom: "#draupnir-admin:localhost:9999"
|
||||
|
||||
webAPI:
|
||||
port: 9001
|
||||
|
||||
# The directory the bot should store various bits of information in
|
||||
dataPath: "./test/harness/mjolnir-data/"
|
||||
|
||||
@@ -80,18 +80,6 @@ export const AppserviceConfig = Type.Object({
|
||||
},
|
||||
{ description: "Details for the database backend" }
|
||||
),
|
||||
webAPI: Type.Object(
|
||||
{
|
||||
port: Type.Number({
|
||||
description:
|
||||
"Port number for the web API used to access the appservice via the widget",
|
||||
}),
|
||||
},
|
||||
{
|
||||
description:
|
||||
"Config for the web api used to access the appservice via the widget",
|
||||
}
|
||||
),
|
||||
adminRoom: Type.String({
|
||||
description:
|
||||
"The admin room for the appservice bot. Not called managementRoom like draupnir on purpose, so they're not mixed in code somehow.",
|
||||
+6
-11
@@ -2,22 +2,17 @@
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { PostgresStore, SchemaUpdateFunction } from "matrix-appservice-bridge";
|
||||
import { PostgresStore } from "matrix-appservice-bridge";
|
||||
import { DataStore, MjolnirRecord } from "../datastore";
|
||||
|
||||
function getSchema(): SchemaUpdateFunction[] {
|
||||
const nSchema = 2;
|
||||
const schema = [];
|
||||
for (let schemaID = 1; schemaID < nSchema + 1; schemaID++) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
schema.push(require(`./schema/v${schemaID}`).runSchema);
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
import { runSchema as v1 } from "./schema/v1";
|
||||
import { runSchema as v2 } from "./schema/v2";
|
||||
|
||||
const Schema = [v1, v2];
|
||||
|
||||
export class PgDataStore extends PostgresStore implements DataStore {
|
||||
constructor(connectionString: string) {
|
||||
super(getSchema(), { url: connectionString });
|
||||
super(Schema, { url: connectionString });
|
||||
}
|
||||
|
||||
public async init(): Promise<void> {
|
||||
+7
-7
@@ -259,19 +259,19 @@ export class SqliteHashReversalStore
|
||||
}, "Error trying to reverse hashed policies");
|
||||
}
|
||||
|
||||
private storeUndiscoveredEntities<Record>(
|
||||
entities: string[],
|
||||
private storeUndiscoveredEntities<TEntity extends string, TRecord>(
|
||||
entities: TEntity[],
|
||||
filterStatement: Statement,
|
||||
insertOrIgnore: Statement,
|
||||
recordFactoryFn: (entity: string, hash: string) => Record,
|
||||
eventEmitFn: (newRecords: Record[]) => void,
|
||||
serverExtractFn?: (record: Record) => StringServerName
|
||||
): Result<Record[]> {
|
||||
recordFactoryFn: (entity: TEntity, hash: string) => TRecord,
|
||||
eventEmitFn: (newRecords: TRecord[]) => void,
|
||||
serverExtractFn?: (record: TRecord) => StringServerName
|
||||
): Result<TRecord[]> {
|
||||
return wrapInTryCatch(() => {
|
||||
const undiscoveredEntities = entities.filter((entity) =>
|
||||
filterStatement.get(entity)
|
||||
);
|
||||
const rowsToInsert: Record[] = undiscoveredEntities.map((entity) =>
|
||||
const rowsToInsert: TRecord[] = undiscoveredEntities.map((entity) =>
|
||||
recordFactoryFn(
|
||||
entity,
|
||||
createHash("sha256").update(entity, "utf8").digest("base64")
|
||||
+1
-1
@@ -200,7 +200,7 @@ export class SqliteRoomStateBackingStore
|
||||
.prepare(`SELECT json(event) FROM room_state_event WHERE room_id = ?`)
|
||||
.pluck()
|
||||
.iterate(roomID) as IterableIterator<string>) {
|
||||
const rawJson = JSON.parse(event, jsonReviver);
|
||||
const rawJson: unknown = JSON.parse(event, jsonReviver);
|
||||
// We can't trust what's in the store, because our event decoders might have gotten
|
||||
// stricter in more recent versions. Meaning the store could have invalid events
|
||||
// that we don't want to blindly intern.
|
||||
+6
-4
@@ -86,10 +86,12 @@ export function checkKnownTables(
|
||||
unsortedKnownTables: string[]
|
||||
): boolean {
|
||||
const knownTables = unsortedKnownTables.slice().sort(),
|
||||
currentTables = db
|
||||
.prepare(`SELECT name FROM "sqlite_master" WHERE type = 'table';`)
|
||||
.pluck()
|
||||
.all()
|
||||
currentTables = (
|
||||
db
|
||||
.prepare(`SELECT name FROM "sqlite_master" WHERE type = 'table';`)
|
||||
.pluck()
|
||||
.all() as string[]
|
||||
)
|
||||
.sort()
|
||||
.filter((table: string) => !/^sqlite_/.test(table));
|
||||
if (knownTables.length !== currentTables.length) {
|
||||
+1
-3
@@ -19,9 +19,7 @@ import {
|
||||
} from "@the-draupnir-project/interface-manager";
|
||||
import { sendMatrixEventsFromDeadDocument } from "@the-draupnir-project/mps-interface-adaptor";
|
||||
|
||||
export class DraupnirRendererMessageCollector
|
||||
implements RendererMessageCollector
|
||||
{
|
||||
export class DraupnirRendererMessageCollector implements RendererMessageCollector {
|
||||
constructor(
|
||||
private readonly roomMessageSender: RoomMessageSender,
|
||||
private readonly managementRoomID: StringRoomID
|
||||
+1
-3
@@ -35,9 +35,7 @@ export interface RendererMessage {
|
||||
/**
|
||||
* Used by capabilities to send messages to the users of Draupnir.
|
||||
*/
|
||||
export class AbstractRendererMessageCollector
|
||||
implements RendererMessageCollector
|
||||
{
|
||||
export class AbstractRendererMessageCollector implements RendererMessageCollector {
|
||||
private readonly messages: RendererMessage[] = [];
|
||||
public getMessages(): RendererMessage[] {
|
||||
return this.messages;
|
||||
+12
-5
@@ -64,11 +64,6 @@ function renderTakedown(
|
||||
}
|
||||
|
||||
class StandardRoomTakedownCapabilityRenderer implements RoomTakedownCapability {
|
||||
public readonly requiredEventPermissions =
|
||||
this.capability.requiredEventPermissions;
|
||||
public readonly requiredPermissions = this.capability.requiredPermissions;
|
||||
public readonly requiredStatePermissions =
|
||||
this.capability.requiredStatePermissions;
|
||||
constructor(
|
||||
private readonly description: DescriptionMeta,
|
||||
private readonly messageCollector: RendererMessageCollector,
|
||||
@@ -77,6 +72,18 @@ class StandardRoomTakedownCapabilityRenderer implements RoomTakedownCapability {
|
||||
// nothing to do.
|
||||
}
|
||||
|
||||
public get requiredEventPermissions() {
|
||||
return this.capability.requiredEventPermissions;
|
||||
}
|
||||
|
||||
public get requiredPermissions() {
|
||||
return this.capability.requiredPermissions;
|
||||
}
|
||||
|
||||
public get requiredStatePermissions() {
|
||||
return this.capability.requiredStatePermissions;
|
||||
}
|
||||
|
||||
public async isRoomTakendown(roomID: StringRoomID): Promise<Result<boolean>> {
|
||||
// pass this one through without rendering because it doesn't really have a consequence
|
||||
return await this.capability.isRoomTakendown(roomID);
|
||||
+13
-8
@@ -32,9 +32,7 @@ import {
|
||||
renderRoomSetResult,
|
||||
} from "@the-draupnir-project/mps-interface-adaptor";
|
||||
|
||||
class StandardServerBanSynchronisationCapabilityRenderer
|
||||
implements ServerBanSynchronisationCapability
|
||||
{
|
||||
class StandardServerBanSynchronisationCapabilityRenderer implements ServerBanSynchronisationCapability {
|
||||
constructor(
|
||||
private readonly description: DescriptionMeta,
|
||||
private readonly messageCollector: RendererMessageCollector,
|
||||
@@ -42,11 +40,6 @@ class StandardServerBanSynchronisationCapabilityRenderer
|
||||
) {
|
||||
// nothing to do.
|
||||
}
|
||||
public readonly requiredEventPermissions =
|
||||
this.capability.requiredEventPermissions;
|
||||
public readonly requiredPermissions = this.capability.requiredPermissions;
|
||||
public readonly requiredStatePermissions =
|
||||
this.capability.requiredStatePermissions;
|
||||
public async outcomeFromIntentInRoom(
|
||||
roomID: StringRoomID,
|
||||
projection: ServerBanIntentProjection
|
||||
@@ -111,6 +104,18 @@ class StandardServerBanSynchronisationCapabilityRenderer
|
||||
}
|
||||
return capabilityResult;
|
||||
}
|
||||
|
||||
public get requiredEventPermissions() {
|
||||
return this.capability.requiredEventPermissions;
|
||||
}
|
||||
|
||||
public get requiredPermissions() {
|
||||
return this.capability.requiredPermissions;
|
||||
}
|
||||
|
||||
public get requiredStatePermissions() {
|
||||
return this.capability.requiredStatePermissions;
|
||||
}
|
||||
}
|
||||
|
||||
describeCapabilityRenderer<ServerBanSynchronisationCapability, Draupnir>({
|
||||
+12
-5
@@ -36,11 +36,6 @@ class StandardEventConsequencesRenderer implements EventConsequences {
|
||||
) {
|
||||
// nothing to do.
|
||||
}
|
||||
public readonly requiredEventPermissions =
|
||||
this.capability.requiredEventPermissions;
|
||||
public readonly requiredPermissions = this.capability.requiredPermissions;
|
||||
public readonly requiredStatePermissions =
|
||||
this.capability.requiredStatePermissions;
|
||||
public async consequenceForEvent(
|
||||
roomID: StringRoomID,
|
||||
eventID: StringEventID,
|
||||
@@ -69,6 +64,18 @@ class StandardEventConsequencesRenderer implements EventConsequences {
|
||||
this.messageCollector.addOneliner(this.description, this.capability, title);
|
||||
return capabilityResult;
|
||||
}
|
||||
|
||||
public get requiredEventPermissions() {
|
||||
return this.capability.requiredEventPermissions;
|
||||
}
|
||||
|
||||
public get requiredPermissions() {
|
||||
return this.capability.requiredPermissions;
|
||||
}
|
||||
|
||||
public get requiredStatePermissions() {
|
||||
return this.capability.requiredStatePermissions;
|
||||
}
|
||||
}
|
||||
|
||||
describeCapabilityRenderer<EventConsequences, Draupnir>({
|
||||
+11
-5
@@ -103,11 +103,17 @@ class StandardUserConsequencesRenderer implements UserConsequences {
|
||||
) {
|
||||
// nothing to do.
|
||||
}
|
||||
public readonly requiredEventPermissions =
|
||||
this.capability.requiredEventPermissions;
|
||||
public readonly requiredPermissions = this.capability.requiredPermissions;
|
||||
public readonly requiredStatePermissions =
|
||||
this.capability.requiredStatePermissions;
|
||||
public get requiredEventPermissions() {
|
||||
return this.capability.requiredEventPermissions;
|
||||
}
|
||||
|
||||
public get requiredPermissions() {
|
||||
return this.capability.requiredPermissions;
|
||||
}
|
||||
|
||||
public get requiredStatePermissions() {
|
||||
return this.capability.requiredStatePermissions;
|
||||
}
|
||||
|
||||
public async consequenceForUserInRoom(
|
||||
roomID: StringRoomID,
|
||||
+9
-11
@@ -41,17 +41,15 @@ export class SynapseAdminRoomDetailsProvider implements RoomDetailsProvider {
|
||||
}
|
||||
}
|
||||
|
||||
export class SynapseAdminRoomTakedownCapability
|
||||
implements RoomTakedownCapability
|
||||
{
|
||||
export class SynapseAdminRoomTakedownCapability implements RoomTakedownCapability {
|
||||
public readonly requiredPermissions = [];
|
||||
public readonly requiredStatePermissions = [];
|
||||
public readonly requiredEventPermissions = [];
|
||||
private readonly roomDetailsProvider = new SynapseAdminRoomDetailsProvider(
|
||||
this.adminClient
|
||||
);
|
||||
private readonly roomDetailsProvider: SynapseAdminRoomDetailsProvider;
|
||||
public constructor(private readonly adminClient: SynapseAdminClient) {
|
||||
// nothing to do mare.
|
||||
this.roomDetailsProvider = new SynapseAdminRoomDetailsProvider(
|
||||
this.adminClient
|
||||
);
|
||||
}
|
||||
|
||||
public async isRoomTakendown(roomID: StringRoomID): Promise<Result<boolean>> {
|
||||
@@ -118,12 +116,12 @@ export class SimulatedRoomTakedownCapability implements RoomTakedownCapability {
|
||||
public readonly requiredPermissions = [];
|
||||
public readonly requiredStatePermissions = [];
|
||||
public readonly requiredEventPermissions = [];
|
||||
private readonly roomDetailsProvider = new SynapseAdminRoomDetailsProvider(
|
||||
this.adminClient
|
||||
);
|
||||
private readonly roomDetailsProvider: SynapseAdminRoomDetailsProvider;
|
||||
isSimulated?: true;
|
||||
public constructor(private readonly adminClient: SynapseAdminClient) {
|
||||
// nothing to do mare.
|
||||
this.roomDetailsProvider = new SynapseAdminRoomDetailsProvider(
|
||||
this.adminClient
|
||||
);
|
||||
}
|
||||
|
||||
public async isRoomTakendown(roomID: StringRoomID): Promise<Result<boolean>> {
|
||||
@@ -10,10 +10,14 @@
|
||||
|
||||
import {
|
||||
ActionResult,
|
||||
MembershipEventContent,
|
||||
MultipleErrors,
|
||||
PolicyRuleType,
|
||||
RoomActionError,
|
||||
RoomUpdateError,
|
||||
ServerACLContent,
|
||||
StateEvent,
|
||||
Value,
|
||||
isError,
|
||||
} from "matrix-protection-suite";
|
||||
import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk";
|
||||
@@ -65,17 +69,20 @@ export const DraupnirImportCommand = describeCommand({
|
||||
if (isError(policyRoomEditor)) {
|
||||
return policyRoomEditor;
|
||||
}
|
||||
const state = await draupnir.client.getRoomState(
|
||||
const state = (await draupnir.client.getRoomState(
|
||||
importFromRoom.ok.toRoomIDOrAlias()
|
||||
);
|
||||
)) as StateEvent[];
|
||||
const errors: RoomUpdateError[] = [];
|
||||
for (const stateEvent of state) {
|
||||
const content = stateEvent["content"] || {};
|
||||
if (!content || Object.keys(content).length === 0) continue;
|
||||
|
||||
const content = stateEvent["content"];
|
||||
if (Object.keys(content).length === 0) {
|
||||
// redacted event.
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
stateEvent["type"] === "m.room.member" &&
|
||||
stateEvent["state_key"] !== ""
|
||||
stateEvent["state_key"] !== "" &&
|
||||
Value.Check(MembershipEventContent, content)
|
||||
) {
|
||||
// Member event - check for ban
|
||||
if (content["membership"] === "ban") {
|
||||
@@ -93,7 +100,8 @@ export const DraupnirImportCommand = describeCommand({
|
||||
}
|
||||
} else if (
|
||||
stateEvent["type"] === "m.room.server_acl" &&
|
||||
stateEvent["state_key"] === ""
|
||||
stateEvent["state_key"] === "" &&
|
||||
Value.Check(ServerACLContent, content)
|
||||
) {
|
||||
// ACL event - ban denied servers
|
||||
if (!content["deny"]) continue;
|
||||
@@ -8,7 +8,7 @@
|
||||
// https://github.com/matrix-org/mjolnir
|
||||
// </text>
|
||||
|
||||
import { MatrixGlob } from "matrix-bot-sdk";
|
||||
import { MatrixGlob } from "@vector-im/matrix-bot-sdk";
|
||||
import {
|
||||
ActionError,
|
||||
Ok,
|
||||
+9
-9
@@ -2,14 +2,14 @@
|
||||
//
|
||||
// SPDX-License-Identifier: AFL-3.0
|
||||
|
||||
import { Ok, Result } from "@gnuxie/typescript-result";
|
||||
import { isError, Ok, Result } from "@gnuxie/typescript-result";
|
||||
import {
|
||||
StringPresentationType,
|
||||
describeCommand,
|
||||
} from "@the-draupnir-project/interface-manager";
|
||||
import { Draupnir } from "../Draupnir";
|
||||
import { ActionError } from "matrix-protection-suite";
|
||||
import { DraupnirInterfaceAdaptor } from "./DraupnirCommandPrerequisites";
|
||||
import { resultifyBotSDKRequestError } from "matrix-protection-suite-for-matrix-bot-sdk";
|
||||
|
||||
export const DraupnirDisplaynameCommand = describeCommand({
|
||||
summary:
|
||||
@@ -26,15 +26,15 @@ export const DraupnirDisplaynameCommand = describeCommand({
|
||||
displaynameParts
|
||||
): Promise<Result<void>> {
|
||||
const displayname = displaynameParts.join(" ");
|
||||
try {
|
||||
await draupnir.client.setDisplayName(displayname);
|
||||
} catch (e) {
|
||||
const message = e.message || (e.body ? e.body.error : "<no message>");
|
||||
return ActionError.Result(
|
||||
`Failed to set displayname to ${displayname}: ${message}`
|
||||
const setDisplaynameResult = await draupnir.client
|
||||
.setDisplayName(displayname)
|
||||
.then((_) => Ok(undefined), resultifyBotSDKRequestError);
|
||||
if (isError(setDisplaynameResult)) {
|
||||
return setDisplaynameResult.elaborate(
|
||||
`Failed to set displayname to ${displayname}`
|
||||
);
|
||||
}
|
||||
return Ok(undefined);
|
||||
return setDisplaynameResult;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -135,7 +135,7 @@ export function draupnirStatusInfo(draupnir: Draupnir): StatusInfo {
|
||||
subscribedButPartedLists: watchedListInfo.subscribedButPartedLists,
|
||||
documentationURL: DOCUMENTATION_URL,
|
||||
version: SOFTWARE_VERSION,
|
||||
repository: PACKAGE_JSON["repository"] ?? "Unknown",
|
||||
repository: (PACKAGE_JSON["repository"] as string | undefined) ?? "Unknown",
|
||||
...extractProtectionNotificationRooms(draupnir),
|
||||
};
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as fs from "fs";
|
||||
import { load } from "js-yaml";
|
||||
import { LogService, RichConsoleLogger } from "matrix-bot-sdk";
|
||||
import { LogService, RichConsoleLogger } from "@vector-im/matrix-bot-sdk";
|
||||
// Needed for https://github.com/the-draupnir-project/Draupnir/issues/480
|
||||
// sorry buddy...
|
||||
process.env.SUPPRESS_NO_CONFIG_WARNING = "y";
|
||||
@@ -23,6 +23,13 @@ LogService.setLogger(new RichConsoleLogger());
|
||||
setGlobalLoggerProvider(new RichConsoleLogger());
|
||||
const log = new Logger("Draupnir config");
|
||||
|
||||
/**
|
||||
* Ideally we'd just have a schema for the config.
|
||||
*/
|
||||
function isConfigRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of the configuration that has been explicitly provided,
|
||||
* and does not contain default values. Secrets are marked with "REDACTED".
|
||||
@@ -30,26 +37,23 @@ const log = new Logger("Draupnir config");
|
||||
export function getNonDefaultConfigProperties(
|
||||
config: IConfig
|
||||
): Record<string, unknown> {
|
||||
const nonDefault = Config.util.diffDeep(defaultConfig, config);
|
||||
const nonDefault = Config.util.diffDeep(defaultConfig, config) as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
if ("accessToken" in nonDefault) {
|
||||
nonDefault.accessToken = "REDACTED";
|
||||
}
|
||||
if (
|
||||
"pantalaimon" in nonDefault &&
|
||||
typeof nonDefault.pantalaimon === "object"
|
||||
) {
|
||||
if ("pantalaimon" in nonDefault && isConfigRecord(nonDefault.pantalaimon)) {
|
||||
nonDefault.pantalaimon.password = "REDACTED";
|
||||
}
|
||||
if (
|
||||
"web" in nonDefault &&
|
||||
typeof nonDefault["web"] === "object" &&
|
||||
nonDefault["web"] !== null &&
|
||||
isConfigRecord(nonDefault.web) &&
|
||||
"synapseHTTPAntispam" in nonDefault["web"] &&
|
||||
typeof nonDefault["web"]["synapseHTTPAntispam"] === "object"
|
||||
isConfigRecord(nonDefault["web"]["synapseHTTPAntispam"])
|
||||
) {
|
||||
if (nonDefault["web"]["synapseHTTPAntispam"] !== null) {
|
||||
nonDefault["web"]["synapseHTTPAntispam"].authorization = "REDACTED";
|
||||
}
|
||||
nonDefault["web"]["synapseHTTPAntispam"].authorization = "REDACTED";
|
||||
}
|
||||
return nonDefault;
|
||||
}
|
||||
@@ -271,7 +275,7 @@ const defaultConfig: IConfig = {
|
||||
};
|
||||
|
||||
export function getDefaultConfig(): IConfig {
|
||||
return Config.util.cloneDeep(defaultConfig);
|
||||
return Config.util.cloneDeep(defaultConfig) as IConfig;
|
||||
}
|
||||
|
||||
function logNonDefaultConfiguration(config: IConfig): void {
|
||||
@@ -435,7 +439,7 @@ export function getProvisionedMjolnirConfig(managementRoomId: string): IConfig {
|
||||
allowedKeys.reduce((existingConfig, key) => {
|
||||
return { ...existingConfig, [key]: configTemplate[key as keyof IConfig] };
|
||||
}, {})
|
||||
);
|
||||
) as IConfig;
|
||||
|
||||
config.managementRoom = managementRoomId;
|
||||
return config;
|
||||
@@ -445,7 +449,7 @@ export const PACKAGE_JSON = (() => {
|
||||
try {
|
||||
return JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, "../package.json"), "utf-8")
|
||||
);
|
||||
) as Record<string, unknown>;
|
||||
} catch (e) {
|
||||
LogService.error("config", "Could not read Draupnir package.json", e);
|
||||
return {};
|
||||
@@ -455,7 +459,7 @@ export const PACKAGE_JSON = (() => {
|
||||
export const SOFTWARE_VERSION = (() => {
|
||||
let versionFile;
|
||||
const defaultText =
|
||||
PACKAGE_JSON.version ??
|
||||
(PACKAGE_JSON.version as string | undefined) ??
|
||||
"A version was either not provided when building Draupnir or could not be read.";
|
||||
try {
|
||||
versionFile = fs.readFileSync(
|
||||
+2
-2
@@ -43,7 +43,7 @@ async function safelyFetchProfile(
|
||||
): Promise<{ displayname?: string } | undefined> {
|
||||
const clientProfileResult = await client.getUserProfile(clientUserID).then(
|
||||
(value) => Ok(value),
|
||||
(error) => resultifyBotSDKRequestErrorWith404AsUndefined(error)
|
||||
(error: unknown) => resultifyBotSDKRequestErrorWith404AsUndefined(error)
|
||||
);
|
||||
// We opt to report to the log rather than fail outright. Because this is on the critical startup path
|
||||
// and when we did crash, we had unexplained server behaviour https://github.com/the-draupnir-project/Draupnir/issues/703
|
||||
@@ -54,7 +54,7 @@ async function safelyFetchProfile(
|
||||
);
|
||||
return undefined;
|
||||
} else {
|
||||
return clientProfileResult.ok;
|
||||
return clientProfileResult.ok as { displayname?: string };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// </text>
|
||||
|
||||
import * as http from "http";
|
||||
import { LogService } from "matrix-bot-sdk";
|
||||
import { LogService } from "@vector-im/matrix-bot-sdk";
|
||||
import { IConfig } from "../config";
|
||||
// allowed to use the global configuration since this is only intended to be used by `src/index.ts`.
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
PantalaimonClient,
|
||||
SimpleFsStorageProvider,
|
||||
RustSdkCryptoStorageProvider,
|
||||
} from "matrix-bot-sdk";
|
||||
} from "@vector-im/matrix-bot-sdk";
|
||||
import { StoreType } from "@matrix-org/matrix-sdk-crypto-nodejs";
|
||||
import { configRead as configRead, getStoragePath } from "./config";
|
||||
import { initializeSentry } from "./utils";
|
||||
@@ -99,9 +99,10 @@ void (async function () {
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
`Failed to setup draupnir from the config ${config.dataPath}: ${err}`
|
||||
`Failed to setup draupnir from the config ${config.dataPath}`,
|
||||
err
|
||||
);
|
||||
await bot?.stopEverything();
|
||||
await bot?.[Symbol.asyncDispose]();
|
||||
throw err;
|
||||
}
|
||||
try {
|
||||
@@ -109,8 +110,8 @@ void (async function () {
|
||||
await bot.encryptionInitialized();
|
||||
healthz.isHealthy = true;
|
||||
} catch (err) {
|
||||
console.error(`Draupnir failed to start: ${err}`);
|
||||
await bot.stopEverything();
|
||||
console.error(`Draupnir failed to start:`, err);
|
||||
await bot[Symbol.asyncDispose]();
|
||||
throw err;
|
||||
}
|
||||
})();
|
||||
+2
-4
@@ -14,7 +14,7 @@ import {
|
||||
LogService,
|
||||
MessageType,
|
||||
TextualMessageEventContent,
|
||||
} from "matrix-bot-sdk";
|
||||
} from "@vector-im/matrix-bot-sdk";
|
||||
import { IConfig } from "../config";
|
||||
import { htmlEscape } from "../utils";
|
||||
import { MatrixSendClient } from "matrix-protection-suite-for-matrix-bot-sdk";
|
||||
@@ -60,9 +60,7 @@ export interface ManagementRoomOutput {
|
||||
/**
|
||||
* Allows the different componenets of draupnir to send messages back to the management room without introducing a dependency on the entirity of a `Draupnir` instance.
|
||||
*/
|
||||
export default class StandardManagementRoomOutput
|
||||
implements ManagementRoomOutput
|
||||
{
|
||||
export default class StandardManagementRoomOutput implements ManagementRoomOutput {
|
||||
private isSuccessfullySendingMessages = false;
|
||||
constructor(
|
||||
private readonly managementRoomDetail: ManagementRoomDetail,
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from "@the-draupnir-project/matrix-basic-types";
|
||||
import { Draupnir } from "../Draupnir";
|
||||
import { DraupnirProtection } from "./Protection";
|
||||
import { LogLevel } from "matrix-bot-sdk";
|
||||
import { LogLevel } from "@vector-im/matrix-bot-sdk";
|
||||
import {
|
||||
AbstractProtection,
|
||||
ActionResult,
|
||||
@@ -118,7 +118,7 @@ function lastEventsRoomEntry(
|
||||
if (roomEntry) {
|
||||
return roomEntry;
|
||||
} else {
|
||||
const nextEntry = new Map();
|
||||
const nextEntry = new Map<StringUserID, LastEvents>();
|
||||
lastEvents.set(roomID, nextEntry);
|
||||
return nextEntry;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user