From e96b8fd970b947c71e559a5ddc89d64a829ab615 Mon Sep 17 00:00:00 2001 From: chayleaf Date: Sat, 4 Nov 2023 08:38:56 +0700 Subject: [PATCH 1/3] maubot: add plugins & plugins update script --- pkgs/tools/networking/maubot/default.nix | 39 +- .../networking/maubot/plugins/default.nix | 64 + .../networking/maubot/plugins/generated.json | 2225 +++++++++++++++++ .../networking/maubot/plugins/generated.nix | 74 + .../tools/networking/maubot/plugins/update.py | 200 ++ pkgs/tools/networking/maubot/wrapper.nix | 70 + 6 files changed, 2663 insertions(+), 9 deletions(-) create mode 100644 pkgs/tools/networking/maubot/plugins/default.nix create mode 100644 pkgs/tools/networking/maubot/plugins/generated.json create mode 100644 pkgs/tools/networking/maubot/plugins/generated.nix create mode 100755 pkgs/tools/networking/maubot/plugins/update.py create mode 100644 pkgs/tools/networking/maubot/wrapper.nix diff --git a/pkgs/tools/networking/maubot/default.nix b/pkgs/tools/networking/maubot/default.nix index e2b9e543a8b4..2eb5c9e76bae 100644 --- a/pkgs/tools/networking/maubot/default.nix +++ b/pkgs/tools/networking/maubot/default.nix @@ -1,6 +1,7 @@ { lib , fetchPypi , fetchpatch +, callPackage , runCommand , python3 , encryptionSupport ? true @@ -88,15 +89,6 @@ let rm $out/example-config.yaml ''; - passthru = { - inherit python; - tests = { - simple = runCommand "${pname}-tests" { } '' - ${maubot}/bin/mbc --help > $out - ''; - }; - }; - # Setuptools is trying to do python -m maubot test dontUseSetuptoolsCheck = true; @@ -104,6 +96,35 @@ let "maubot" ]; + passthru = let + wrapper = callPackage ./wrapper.nix { + unwrapped = maubot; + python3 = python; + }; + in + { + tests = { + simple = runCommand "${pname}-tests" { } '' + ${maubot}/bin/mbc --help > $out + ''; + }; + + inherit python; + + plugins = callPackage ./plugins { + maubot = maubot; + python3 = python; + }; + + withPythonPackages = pythonPackages: wrapper { inherit pythonPackages; }; + + # This adds the plugins to lib/maubot-plugins + withPlugins = plugins: wrapper { inherit plugins; }; + + # This changes example-config.yaml in module directory + withBaseConfig = baseConfig: wrapper { inherit baseConfig; }; + }; + meta = with lib; { description = "A plugin-based Matrix bot system written in Python"; homepage = "https://maubot.xyz/"; diff --git a/pkgs/tools/networking/maubot/plugins/default.nix b/pkgs/tools/networking/maubot/plugins/default.nix new file mode 100644 index 000000000000..0a7c606909a0 --- /dev/null +++ b/pkgs/tools/networking/maubot/plugins/default.nix @@ -0,0 +1,64 @@ +{ lib +, fetchgit +, fetchFromGitHub +, fetchFromGitLab +, fetchFromGitea +, stdenvNoCC +, callPackage +, maubot +, python3 +, poetry +, formats +}: + +let + # pname: plugin id (example: xyz.maubot.echo) + # version: plugin version + # other attributes are passed directly to stdenv.mkDerivation (you at least need src) + buildMaubotPlugin = attrs@{ version, pname, base_config ? null, ... }: + stdenvNoCC.mkDerivation (builtins.removeAttrs attrs [ "base_config" ] // { + pluginName = "${pname}-v${version}.mbp"; + nativeBuildInputs = (attrs.nativeBuildInputs or [ ]) ++ [ maubot ]; + buildPhase = '' + runHook preBuild + + mbc build + + runHook postBuild + ''; + + postPatch = lib.optionalString (base_config != null) '' + [ -e base-config.yaml ] || (echo "base-config.yaml doesn't exist, can't override it" && exit 1) + cp "${if builtins.isPath base_config || lib.isDerivation base_config then base_config + else if builtins.isString base_config then builtins.toFile "base-config.yaml" base_config + else (formats.yaml { }).generate "base-config.yaml" base_config}" base-config.yaml + '' + attrs.postPatch or ""; + + installPhase = '' + runHook preInstall + + mkdir -p $out/lib/maubot-plugins + install -m 444 $pluginName $out/lib/maubot-plugins + + runHook postInstall + ''; + }); + + generated = import ./generated.nix { + inherit lib fetchgit fetchFromGitHub fetchFromGitLab + fetchFromGitea python3 poetry buildMaubotPlugin; + }; +in +generated // { + inherit buildMaubotPlugin; + + allOfficialPlugins = + builtins.filter + (x: x.isOfficial && !x.meta.broken) + (builtins.attrValues generated); + + allPlugins = + builtins.filter + (x: !x.meta.broken) + (builtins.attrValues generated); +} diff --git a/pkgs/tools/networking/maubot/plugins/generated.json b/pkgs/tools/networking/maubot/plugins/generated.json new file mode 100644 index 000000000000..555de6c05821 --- /dev/null +++ b/pkgs/tools/networking/maubot/plugins/generated.json @@ -0,0 +1,2225 @@ +{ + "URLDownload": { + "attrs": { + "meta": { + "changelog": "https://codeberg.org/LukeLR/matrix-url-download/releases", + "description": "A plugin for the maubot bot framework implementing URL downloads in matrix rooms.", + "downloadPage": "https://codeberg.org/LukeLR/matrix-url-download/releases", + "homepage": "https://codeberg.org/LukeLR/matrix-url-download" + } + }, + "gitea": { + "domain": "codeberg.org", + "hash": "sha256-JLYhoQKxsYO46mqRJZEcWTHck6bli6itYGu8ZPbxyjg=", + "owner": "LukeLR", + "repo": "matrix-url-download", + "rev": "3a006d98faa6950edab1a45b7a8c6a6d7d908bff" + }, + "manifest": { + "config": true, + "database": true, + "database_type": "asyncpg", + "extra_files": [ + "base-config.yaml" + ], + "id": "de.lukelr.urldownload", + "license": "LGPL-3.0-only", + "main_class": "URLDownloadBot", + "maubot": "0.1.0", + "modules": [ + "urldownload" + ], + "version": "0.0.3" + } + }, + "activity-tracker": { + "attrs": { + "meta": { + "changelog": "https://github.com/williamkray/maubot-kickbot/releases", + "description": "A plugin that minimally tracks user activity within a space. Useful for kicking inactive users from a private community.", + "downloadPage": "https://github.com/williamkray/maubot-kickbot/releases", + "homepage": "https://github.com/williamkray/maubot-kickbot" + } + }, + "github": { + "hash": "sha256-TLaGpLrTR4TLR0TjY3v9FFST8JxEP4swJ7kzt0fDwJI=", + "owner": "williamkray", + "repo": "maubot-kickbot", + "rev": "a4c31c7a1492585f2155705be8cab7e3f73f6b69" + }, + "manifest": { + "database": true, + "database_type": "asyncpg", + "extra_files": [ + "base-config.yaml" + ], + "id": "org.jobmachine.kickbot", + "license": "MIT", + "main_class": "KickBot", + "maubot": "0.1.0", + "modules": [ + "kickbot" + ], + "version": "0.0.10" + } + }, + "alertbot": { + "attrs": { + "meta": { + "changelog": "https://github.com/moan0s/alertbot/blob/v1.1.1/CHANGELOG.md", + "description": "A bot that recives monitoring alerts via alertmanager and forwards them to a matrix room.", + "downloadPage": "https://github.com/moan0s/alertbot/releases", + "homepage": "https://github.com/moan0s/alertbot" + } + }, + "github": { + "hash": "sha256-hA4Wl1mrIuThQVHTPhMAVsvdbhhx/rHqpOResWO8xiI=", + "owner": "moan0s", + "repo": "alertbot", + "rev": "v1.1.1" + }, + "manifest": { + "id": "de.hyteck.alertbot", + "license": "AGPL-3.0-or-later", + "main_class": "AlertBot", + "maubot": "0.1.0", + "modules": [ + "alertbot" + ], + "version": "1.1.1", + "webapp": true + } + }, + "altalias": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/altalias/releases", + "description": "A bot that lets users publish alternate aliases in rooms.", + "downloadPage": "https://github.com/maubot/altalias/releases", + "homepage": "https://github.com/maubot/altalias" + } + }, + "github": { + "hash": "sha256-+qW3CX2ae86jc5l/7poyLs2cQycLjft9l3rul9eYby4=", + "owner": "maubot", + "repo": "altalias", + "rev": "b07b7866c9647612bfe784700b37087855432028" + }, + "isOfficial": true, + "manifest": { + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.altalias", + "license": "AGPL-3.0-or-later", + "main_class": "AltAliasBot", + "maubot": "0.1.0", + "modules": [ + "altalias" + ], + "version": "1.0.0" + } + }, + "alternatingcaps": { + "attrs": { + "meta": { + "changelog": "https://github.com/rom4nik/maubot-alternatingcaps/releases", + "description": "A bot repeating last message using aLtErNaTiNg cApS.", + "downloadPage": "https://github.com/rom4nik/maubot-alternatingcaps/releases", + "homepage": "https://github.com/rom4nik/maubot-alternatingcaps" + } + }, + "github": { + "hash": "sha256-O3FhZ6US4iACEzEKdHLjBZfOJlHNGEeLSrHdqWULFvk=", + "owner": "rom4nik", + "repo": "maubot-alternatingcaps", + "rev": "v0.1.2" + }, + "manifest": { + "id": "pl.rom4nik.maubot.alternatingcaps", + "license": "MIT", + "main_class": "AlternatingCaps", + "modules": [ + "alternatingcaps" + ], + "version": "0.1.2" + } + }, + "animemanga": { + "attrs": { + "meta": { + "changelog": "https://github.com/coffeebank/coffee-maubot/releases", + "description": "An anime/manga bot for Matrix. Search anime, manga (manhwa/manhua), and light novels from Anilist. See series info, status, and episodes/chapters.", + "downloadPage": "https://github.com/coffeebank/coffee-maubot/releases", + "homepage": "https://github.com/coffeebank/coffee-maubot/tree/master/animemanga" + }, + "postPatch": "cd animemanga" + }, + "github": { + "hash": "sha256-k+M/Wk4nyXUZBJxmxQr64dPp3rK7i1oQeLFtncle3dI=", + "owner": "coffeebank", + "repo": "coffee-maubot", + "rev": "b25112508d65f7560910e67d3074dd60f4048821" + }, + "manifest": { + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "coffee.maubot.animemanga", + "license": "AGPL-3.0-or-later", + "main_class": "AnimeMangaBot", + "maubot": "0.1.0", + "modules": [ + "animemanga" + ], + "version": "0.1.1.216" + } + }, + "antithread": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/antithread/releases", + "description": "A bot that redacts all messages in threads.", + "downloadPage": "https://github.com/maubot/antithread/releases", + "homepage": "https://github.com/maubot/antithread" + } + }, + "github": { + "hash": "sha256-O6rxvxR62DboRGaNevJRCZynGl3xthRICaxRCvLScdM=", + "owner": "maubot", + "repo": "antithread", + "rev": "0577b8eefcf01925452678b9fe380aac4270c672" + }, + "isOfficial": true, + "manifest": { + "id": "xyz.maubot.antithread", + "license": "MIT", + "main_class": "AntiThreadBot", + "modules": [ + "antithread" + ], + "version": "1.0.0" + } + }, + "autoreply": { + "attrs": { + "meta": { + "changelog": "https://github.com/babolivier/maubot-autoreply/releases", + "description": "A bot that sends automated replies when you're away, and shows you a summary of missed messages when you come back.", + "downloadPage": "https://github.com/babolivier/maubot-autoreply/releases", + "homepage": "https://github.com/babolivier/maubot-autoreply" + } + }, + "github": { + "hash": "sha256-ULOL5C1tzH4g0IWu+GmMdl3+aCZK0n/G4I8wIvd7f6U=", + "owner": "babolivier", + "repo": "maubot-autoreply", + "rev": "v1.0.0" + }, + "manifest": { + "config": true, + "database": true, + "database_type": "asyncpg", + "extra_files": [ + "base-config.yaml" + ], + "id": "bzh.abolivier.autoreply", + "license": "Apache-2.0", + "main_class": "AutoReplyBot", + "maubot": "v0.1.0", + "modules": [ + "autoreply" + ], + "version": "1.0.0" + } + }, + "bard": { + "attrs": { + "meta": { + "changelog": "https://github.com/ser/maubot-bard/releases", + "description": "Allow your maubot instance to return queries from Google(TM) Bard(TM) pseudoAI", + "downloadPage": "https://github.com/ser/maubot-bard/releases", + "homepage": "https://github.com/ser/maubot-bard/", + "license": "MIT" + } + }, + "github": { + "hash": "sha256-E8pz71wfH+SmFNzBcPUrnqK0xs7wlyB6SaRXH/PDqKw=", + "owner": "ser", + "repo": "maubot-bard", + "rev": "4ff3ce8d86ed19c973dee89228779fed74811341" + }, + "manifest": { + "config": true, + "dependencies": [ + "bardapi" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "sergevictor.eu.maubot.bard", + "main_class": "BardPlugin", + "modules": [ + "bard" + ], + "version": "0.99.100" + } + }, + "characterai": { + "attrs": { + "meta": { + "changelog": "https://github.com/Matthieu-LAURENT39/maubot-characterai/releases", + "description": "Chat with characters from [character.ai](https://character.ai/) in your Matrix rooms! Very customizable.", + "downloadPage": "https://github.com/Matthieu-LAURENT39/maubot-characterai/releases", + "homepage": "https://github.com/Matthieu-LAURENT39/maubot-characterai" + } + }, + "github": { + "hash": "sha256-nyVz0PDyNGAIFCxakWzEe8AG/PU+HlZJQQ85SL1bEvs=", + "owner": "Matthieu-LAURENT39", + "repo": "maubot-characterai", + "rev": "v0.2.1" + }, + "manifest": { + "config": true, + "database": true, + "database_type": "asyncpg", + "dependencies": [ + "characterai" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "com.github.Matthieu-LAURENT39.maubot-characterai", + "license": "MIT", + "main_class": "CAIBot", + "maubot": "0.1.0", + "modules": [ + "cai" + ], + "version": "0.2.1" + } + }, + "chatgpt": { + "attrs": { + "meta": { + "changelog": "https://github.com/williamkray/maubot-chatgpt/releases", + "description": "ChatGPT plugin for maubot. Multi-user aware for use in group rooms! Customize your prompts to \"train\" your assistant contextually.", + "downloadPage": "https://github.com/williamkray/maubot-chatgpt/releases", + "homepage": "https://github.com/williamkray/maubot-chatgpt", + "license": "MIT" + } + }, + "github": { + "hash": "sha256-iRo4oFOOXgISALFskPZUonV4cBn7HmBACdi5uhgQq8o=", + "owner": "williamkray", + "repo": "maubot-chatgpt", + "rev": "f3974dc3818da170a3f1e091359d31f3140245e0" + }, + "manifest": { + "config": true, + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "org.jobmachine.chatgpt", + "main_class": "GPTPlugin", + "maubot": "0.1.0", + "modules": [ + "gpt" + ], + "version": "0.0.9" + } + }, + "choose": { + "attrs": { + "meta": { + "changelog": "https://github.com/coffeebank/coffee-maubot/releases", + "description": "Have the bot choose for you ( item1 | item2 | item3 ) with a divider", + "downloadPage": "https://github.com/coffeebank/coffee-maubot/releases", + "homepage": "https://github.com/coffeebank/coffee-maubot/tree/master/choose" + }, + "postPatch": "cd choose" + }, + "github": { + "hash": "sha256-k+M/Wk4nyXUZBJxmxQr64dPp3rK7i1oQeLFtncle3dI=", + "owner": "coffeebank", + "repo": "coffee-maubot", + "rev": "b25112508d65f7560910e67d3074dd60f4048821" + }, + "manifest": { + "database": false, + "id": "coffee.maubot.choose", + "license": "AGPL-3.0-or-later", + "main_class": "ChooseBot", + "maubot": "0.1.0", + "modules": [ + "choose" + ], + "version": "0.1.0.3" + } + }, + "commitstrip": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/commitstrip/releases", + "description": "A bot to view CommitStrips.", + "downloadPage": "https://github.com/maubot/commitstrip/releases", + "homepage": "https://github.com/maubot/commitstrip" + } + }, + "github": { + "hash": "sha256-P5u4oDmsMj4r48JZIZ1Cg8cX11aimv9dGI+J0lJrY34=", + "owner": "maubot", + "repo": "commitstrip", + "rev": "28ab63c2725aa989a151f5659cb37a674b002a80" + }, + "isOfficial": true, + "manifest": { + "database": true, + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.commitstrip", + "license": "AGPL-3.0-or-later", + "main_class": "CommitBot", + "maubot": "0.1.0", + "modules": [ + "commitstrip" + ], + "version": "1.0.0" + } + }, + "create-room": { + "attrs": { + "meta": { + "changelog": "https://github.com/williamkray/maubot-createroom/releases", + "description": "A plugin that creates new rooms and automatically sets them to be part of a private Matrix Space.", + "downloadPage": "https://github.com/williamkray/maubot-createroom/releases", + "homepage": "https://github.com/williamkray/maubot-createroom" + } + }, + "github": { + "hash": "sha256-x1eoUX8u1IR/hLgS8YcpSoTByl+m3GoTW3fnFMDs1XA=", + "owner": "williamkray", + "repo": "maubot-createroom", + "rev": "4eecdcffa6c06276287c2a3d4e65905a72ad18ad" + }, + "manifest": { + "config": true, + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "org.jobmachine.createspaceroom", + "license": "MIT", + "main_class": "CreateSpaceRoom", + "maubot": "0.1.0", + "modules": [ + "createspaceroom" + ], + "version": "0.1.2" + } + }, + "dice": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/dice/releases", + "description": "A combined dice rolling and calculator bot.", + "downloadPage": "https://github.com/maubot/dice/releases", + "homepage": "https://github.com/maubot/dice" + } + }, + "github": { + "hash": "sha256-xnqcxOXHhsHR9RjLaOa6QZOx87V6kLQJW+mRWF/S5eM=", + "owner": "maubot", + "repo": "dice", + "rev": "v1.1.0" + }, + "isOfficial": true, + "manifest": { + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.dice", + "license": "AGPL-3.0-or-later", + "main_class": "DiceBot", + "maubot": "0.1.0", + "modules": [ + "dice" + ], + "version": "1.1.0" + } + }, + "disruptor": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/disruptor/releases", + "description": "A bot that disrupts monologues with cat pictures.", + "downloadPage": "https://github.com/maubot/disruptor/releases", + "homepage": "https://github.com/maubot/disruptor" + } + }, + "github": { + "hash": "sha256-/wm/CNl4XzRBClhW+jOp9S7P/nIz65aOtt+E9AnIPNA=", + "owner": "maubot", + "repo": "disruptor", + "rev": "v0.2.0" + }, + "isOfficial": true, + "manifest": { + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.disruptor", + "license": "AGPL-3.0-or-later", + "main_class": "DisruptorBot", + "maubot": "0.4.1", + "modules": [ + "disruptor" + ], + "version": "0.2.0" + } + }, + "echo": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/echo/releases", + "description": "A bot that echoes pings and other stuff.\n\nSee [#ping:maunium.net](https://matrix.to/#/#ping:maunium.net) for a room\nwith lots of echo bots.\n", + "downloadPage": "https://github.com/maubot/echo/releases", + "homepage": "https://github.com/maubot/echo" + } + }, + "github": { + "hash": "sha256-/ajDs2vpWqejxDF7naXtKi1nYRs2lJpuc0R0dV7oVHI=", + "owner": "maubot", + "repo": "echo", + "rev": "v1.4.0" + }, + "isOfficial": true, + "manifest": { + "id": "xyz.maubot.echo", + "license": "MIT", + "main_class": "EchoBot", + "maubot": "0.1.0", + "modules": [ + "echo" + ], + "version": "1.4.0" + } + }, + "exec": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/exec/releases", + "description": "A bot that executes code.", + "downloadPage": "https://github.com/maubot/exec/releases", + "homepage": "https://github.com/maubot/exec" + } + }, + "github": { + "hash": "sha256-bwy3eB7ULYTGeJXtTNFMfry9dWQmnTjcU6HWdRznWxc=", + "owner": "maubot", + "repo": "exec", + "rev": "475d0fe70dc30e1c14e29028694fd4ac38690932" + }, + "isOfficial": true, + "manifest": { + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.exec", + "license": "AGPL-3.0-or-later", + "main_class": "ExecBot", + "maubot": "0.1.0", + "modules": [ + "exec" + ], + "version": "0.1.0" + } + }, + "factorial": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/factorial/releases", + "description": "A bot to calculate unexpected factorials.", + "downloadPage": "https://github.com/maubot/factorial/releases", + "homepage": "https://github.com/maubot/factorial" + } + }, + "github": { + "hash": "sha256-XHAwAloJZpFdY0kRrUjkEGJoryHK4PSQgBf2QH9C/6o=", + "owner": "maubot", + "repo": "factorial", + "rev": "v3.0.0" + }, + "isOfficial": true, + "manifest": { + "id": "xyz.maubot.factorial", + "license": "AGPL-3.0-or-later", + "main_class": "FactorialBot", + "maubot": "0.1.0", + "modules": [ + "factorial" + ], + "version": "3.0.0" + } + }, + "gifme": { + "attrs": { + "meta": { + "changelog": "https://github.com/williamkray/maubot-gifme/releases", + "description": "Superior gif responses. Save your own library of image or video responses.\nAllows fallback behavior to Giphy or Tenor, optionally saves quotes from\nusers for comedic effect or to be used as an FAQ bot!\n", + "downloadPage": "https://github.com/williamkray/maubot-gifme/releases", + "homepage": "https://github.com/williamkray/maubot-gifme" + } + }, + "github": { + "hash": "sha256-5MHLtm3qktUyvWyuwQEUQWL8fxszZ6h/hHClLLr0Uvs=", + "owner": "williamkray", + "repo": "maubot-gifme", + "rev": "6dbbb9ebce903887b62f95b04f4640779762e57a" + }, + "manifest": { + "database": true, + "database_type": "asyncpg", + "extra_files": [ + "base-config.yaml" + ], + "id": "org.jobmachine.gifme", + "license": "MIT", + "main_class": "GifMe", + "maubot": "0.4.0", + "modules": [ + "gifme" + ], + "version": "0.1.0" + } + }, + "giphy": { + "attrs": { + "meta": { + "changelog": "https://github.com/TomCasavant/GiphyMaubot/releases", + "description": "A bot that generates a gif (from giphy) given search terms.", + "downloadPage": "https://github.com/TomCasavant/GiphyMaubot/releases", + "homepage": "https://github.com/TomCasavant/GiphyMaubot" + } + }, + "github": { + "hash": "sha256-bY9jCHwI2UZwn+W02hSEAD0aRRsM7cAeeYpnk3jTTBY=", + "owner": "TomCasavant", + "repo": "GiphyMaubot", + "rev": "3.3.0" + }, + "manifest": { + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "casavant.tom.giphy", + "license": "MIT", + "main_class": "GiphyPlugin", + "maubot": "0.1.0", + "modules": [ + "giphy" + ], + "version": "3.3.0" + } + }, + "github": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/github/releases", + "description": "A GitHub client and webhook receiver.", + "downloadPage": "https://github.com/maubot/github/releases", + "homepage": "https://github.com/maubot/github" + } + }, + "github": { + "hash": "sha256-Qc0KH8iGqMDa+1BXaB5fHtRIcsZRpTF2IufGMEXqV6Q=", + "owner": "maubot", + "repo": "github", + "rev": "v0.1.2" + }, + "isOfficial": true, + "manifest": { + "config": true, + "database": true, + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.github", + "license": "AGPL-3.0-or-later", + "main_class": "GitHubBot", + "maubot": "0.3.0", + "modules": [ + "github" + ], + "version": "0.1.2", + "webapp": true + } + }, + "gitlab": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/gitlab/releases", + "description": "A GitLab client and webhook receiver.", + "downloadPage": "https://github.com/maubot/gitlab/releases", + "homepage": "https://github.com/maubot/gitlab" + } + }, + "github": { + "hash": "sha256-lkHGR+uLnT3f7prWDAbJplwzwAyOfMCwf8B2LeiJzIo=", + "owner": "maubot", + "repo": "gitlab", + "rev": "v0.2.1" + }, + "isOfficial": true, + "manifest": { + "config": true, + "database": true, + "extra_files": [ + "base-config.yaml", + "templates/macros.html", + "templates/messages/*.html", + "templates/mixins/*.html" + ], + "id": "xyz.maubot.gitlab", + "license": "AGPL-3.0-or-later", + "main_class": "GitlabBot", + "maubot": "0.1.2", + "modules": [ + "gitlab_matrix" + ], + "soft_dependencies": [ + "python-gitlab" + ], + "version": "0.2.1", + "webapp": true + } + }, + "hasswebhookbot": { + "attrs": { + "meta": { + "changelog": "https://github.com/v411e/hasswebhookbot/releases", + "description": "A bot receiving webhooks from [Home Assistant](https://github.com/home-assistant).", + "downloadPage": "https://github.com/v411e/hasswebhookbot/releases", + "homepage": "https://github.com/v411e/hasswebhookbot" + } + }, + "github": { + "hash": "sha256-Tjr2sbFMpasBy4dR1Lqxt/jnO3ay26XY2d263JkFyKg=", + "owner": "v411e", + "repo": "hasswebhookbot", + "rev": "v0.0.15" + }, + "manifest": { + "config": true, + "database": true, + "dependencies": [ + "Markdown", + "pytz" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "com.valentinriess.hasswebhook", + "license": "MIT", + "main_class": "HassWebhook", + "maubot": "0.1.0", + "modules": [ + "hasswebhook" + ], + "soft_dependencies": [ + "Pillow" + ], + "version": "0.0.15", + "webapp": true + } + }, + "hateheif": { + "attrs": { + "meta": { + "changelog": "https://github.com/ser/maubot-hateheif/releases", + "description": "A bot which sends converted HEIF into JPEG. Works in encrypted and unencrypted rooms.", + "downloadPage": "https://github.com/ser/maubot-hateheif/releases", + "homepage": "https://github.com/ser/maubot-hateheif/" + } + }, + "github": { + "hash": "sha256-twvVeMD2nRwpazc21inbdr6mUjMXJ4T6v5ieNrwB+O4=", + "owner": "ser", + "repo": "maubot-hateheif", + "rev": "52cf166960ac3fb71d291e13d5f3621caa9d7af1" + }, + "manifest": { + "config": true, + "dependencies": [ + "pillow-heif" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "eu.sergevictor.hateheif", + "license": "MIT", + "main_class": "HateHeifBot", + "modules": [ + "hateheif" + ], + "version": "0.99.100" + } + }, + "help": { + "attrs": { + "meta": { + "description": "A plugin to add a `!help` command to maubot. Returns all built-in help commands for all plugins loaded in the client instance.", + "homepage": "https://git.skeg1.se/vondassendorf/maubot_mauhelp" + } + }, + "gitlab": { + "domain": "git.skeg1.se", + "hash": "sha256-xQ0GzdWPHstMSEOXwmW/DFxClK/oEwfyTrm752S5iFQ=", + "owner": "vondassendorf", + "repo": "maubot_mauhelp", + "rev": "v0.2.0" + }, + "manifest": { + "database": false, + "id": "se.skeg1.mauhelp", + "license": "MIT", + "main_class": "MauHelp", + "maubot": "0.3.1", + "modules": [ + "mauhelp" + ], + "version": "0.2.0" + } + }, + "holopin": { + "attrs": { + "meta": { + "changelog": "https://github.com/itrich/HolopinMaubot/releases", + "description": "A plugin to issue [Holopin](https://holopin.io) badges to users.", + "downloadPage": "https://github.com/itrich/HolopinMaubot/releases", + "homepage": "https://github.com/itrich/HolopinMaubot" + } + }, + "github": { + "hash": "sha256-fQDa4e2hN5WFXwPVqefCU9YBzXHxvtXntAta0oZxp5M=", + "owner": "itrich", + "repo": "HolopinMaubot", + "rev": "v0.0.1" + }, + "manifest": { + "config": true, + "database": false, + "dependencies": null, + "extra_files": [ + "base-config.yaml" + ], + "id": "net.itrich.maubot.holopin", + "license": "MIT", + "main_class": "HolopinPlugin", + "maubot": "0.1.0", + "modules": [ + "holopin" + ], + "soft_dependencies": null, + "version": "0.0.1", + "webapp": false + } + }, + "invite": { + "attrs": { + "meta": { + "changelog": "https://github.com/williamkray/maubot-invite/releases", + "description": "A bot to generate invitation tokens from [matrix-registration](https://github.com/ZerataX/matrix-registration).", + "downloadPage": "https://github.com/williamkray/maubot-invite/releases", + "homepage": "https://github.com/williamkray/maubot-invite" + } + }, + "github": { + "hash": "sha256-VQufveYgxVOoMWtfNJ8LYWvjbFtboSNZzdRn7MA7DLA=", + "owner": "williamkray", + "repo": "maubot-invite", + "rev": "v0.3.1" + }, + "manifest": { + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "org.jobmachine.invitebot", + "license": "MIT", + "main_class": "Invite", + "maubot": "0.1.0", + "modules": [ + "invite" + ], + "version": "0.3.1" + } + }, + "jadict": { + "attrs": { + "meta": { + "changelog": "https://github.com/coffeebank/coffee-maubot/releases", + "description": "A Japanese dictionary Matrix bot for searching and translating Japanese vocabulary (Hiragana, Katakana, Kanji, Romaji). Searches Jisho using Jisho API.", + "downloadPage": "https://github.com/coffeebank/coffee-maubot/releases", + "homepage": "https://github.com/coffeebank/coffee-maubot/tree/master/jadict" + }, + "postPatch": "cd jadict" + }, + "github": { + "hash": "sha256-k+M/Wk4nyXUZBJxmxQr64dPp3rK7i1oQeLFtncle3dI=", + "owner": "coffeebank", + "repo": "coffee-maubot", + "rev": "b25112508d65f7560910e67d3074dd60f4048821" + }, + "manifest": { + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "coffee.maubot.jadict", + "license": "AGPL-3.0-or-later", + "main_class": "JadictBot", + "maubot": "0.1.0", + "modules": [ + "jadict" + ], + "version": "0.1.0.10" + } + }, + "join": { + "attrs": { + "meta": { + "changelog": "https://github.com/williamkray/maubot-join/releases", + "description": "A plugin that restricts who can convince your bot to join new rooms to certain users.", + "downloadPage": "https://github.com/williamkray/maubot-join/releases", + "homepage": "https://github.com/williamkray/maubot-join" + } + }, + "github": { + "hash": "sha256-aqpL+KO5p0hre7RCUZrM270Ah+cR4cQxZn7LTXLT79k=", + "owner": "williamkray", + "repo": "maubot-join", + "rev": "1b57758dfe3a2191588bb903ea546328146e69d8" + }, + "manifest": { + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "org.jobmachine.join", + "license": "MIT", + "main_class": "Join", + "maubot": "0.1.0", + "modules": [ + "join" + ], + "version": "0.3.0" + } + }, + "karma": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/karma/releases", + "description": "A user karma tracker bot.", + "downloadPage": "https://github.com/maubot/karma/releases", + "homepage": "https://github.com/maubot/karma" + } + }, + "github": { + "hash": "sha256-7CK4NReLhU/d0FXTWj9eM7C5yL9nXkM+vpPExv4VPfE=", + "owner": "maubot", + "repo": "karma", + "rev": "v1.0.1" + }, + "isOfficial": true, + "manifest": { + "database": true, + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.karma", + "license": "AGPL-3.0-or-later", + "main_class": "KarmaBot", + "maubot": "0.1.0", + "modules": [ + "karma" + ], + "version": "1.0.1" + } + }, + "ldap-ad-inviterbot": { + "attrs": { + "meta": { + "changelog": "https://github.com/SAPUCC/inviterbot/blob/v0.1.5/CHANGELOG.md", + "description": "A plugin to sync users from Microsoft Azure AD and LDAP into matrix rooms. (Membership, Power-Levels)", + "downloadPage": "https://github.com/SAPUCC/inviterbot/releases", + "homepage": "https://github.com/SAPUCC/inviterbot", + "license": "GPL-3.0-or-later" + } + }, + "github": { + "hash": "sha256-Ve420Mfa+Ikxp0P/8b6rZIu54VOfKhH3sWDNNMClj9E=", + "owner": "SAPUCC", + "repo": "inviterbot", + "rev": "v0.1.5" + }, + "manifest": { + "config": true, + "database": false, + "dependencies": [ + null + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "de.in4md-service.inviterbot", + "license": "GPLv3", + "main_class": "InviterBot", + "maubot": "0.2.0", + "modules": [ + "inviter" + ], + "version": "0.1.5" + } + }, + "local-stt": { + "attrs": { + "meta": { + "changelog": "https://github.com/ElishaAz/mau_local_stt/releases", + "description": "A Maubot to transcribe audio messages in matrix rooms using local open-source libraries", + "downloadPage": "https://github.com/ElishaAz/mau_local_stt/releases", + "homepage": "https://github.com/ElishaAz/mau_local_stt", + "license": "GPL-3.0-only" + } + }, + "github": { + "hash": "sha256-EyDJ4RtQjBl7BQ7Y/0LWfX4zkVVqBOqjnhb9tXhFxio=", + "owner": "ElishaAz", + "repo": "mau_local_stt", + "rev": "v1.0.2" + }, + "manifest": { + "config": true, + "dependencies": [ + "whispercpp", + "numpy", + "vosk" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "com.elishaaz.maulocalstt", + "license": "GPLv3", + "main_class": "MauLocalSTT", + "maubot": "0.1.0", + "modules": [ + "maulocalstt" + ], + "version": "1.0.2" + } + }, + "manhole": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/manhole/releases", + "description": "A plugin that lets you access a Python shell inside maubot.", + "downloadPage": "https://github.com/maubot/manhole/releases", + "homepage": "https://github.com/maubot/manhole" + } + }, + "github": { + "hash": "sha256-F3Nrl6NOUmwDuBsCxIfopRnLU9rltdaCJL/OcNGzw1Q=", + "owner": "maubot", + "repo": "manhole", + "rev": "47f1f7501b5b353a0fa74bf5929cead559496174" + }, + "isOfficial": true, + "manifest": { + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.manhole", + "license": "AGPL-3.0-or-later", + "main_class": "ManholeBot", + "maubot": "0.1.0", + "modules": [ + "manhole" + ], + "version": "1.0.0" + } + }, + "media": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/media/releases", + "description": "A bot that replies with the MXC URI of images you send it.", + "downloadPage": "https://github.com/maubot/media/releases", + "homepage": "https://github.com/maubot/media" + } + }, + "github": { + "hash": "sha256-00zESMN2WxKYPAQbpyvDpkyJIFkILLOP+m256k0Avzk=", + "owner": "maubot", + "repo": "media", + "rev": "v1.0.0" + }, + "isOfficial": true, + "manifest": { + "id": "xyz.maubot.media", + "license": "MIT", + "main_class": "MediaBot", + "modules": [ + "media" + ], + "version": "1.0.0" + } + }, + "metric": { + "attrs": { + "meta": { + "changelog": "https://github.com/edwardsdean/maubot_metric_bot/releases", + "description": "A bot that will reply to a message that contains imperial units and replace them with metric units.", + "downloadPage": "https://github.com/edwardsdean/maubot_metric_bot/releases", + "homepage": "https://github.com/edwardsdean/maubot_metric_bot" + } + }, + "github": { + "hash": "sha256-qtGGCaATIzJMRhLWzFN0kSa6P/tlckCkxatKEfXyi0E=", + "owner": "edwardsdean", + "repo": "maubot_metric_bot", + "rev": "0.0.4" + }, + "manifest": { + "database": false, + "id": "me.edwardsdean.maubot.metric", + "license": "MIT", + "main_class": "MetricPlugin", + "maubot": "0.1.0", + "modules": [ + "metric" + ], + "version": "0.0.4" + } + }, + "ntfy": { + "attrs": { + "meta": { + "description": "A bot for subscribing to [ntfy](https://ntfy.sh) topics and posting messages to Matrix.", + "homepage": "https://gitlab.com/999eagle/maubot-ntfy" + } + }, + "gitlab": { + "hash": "sha256-6522dVqhGoPc/qjz65D3kXHks5LLb3yVe0K5abqdXrw=", + "owner": "999eagle", + "repo": "maubot-ntfy", + "rev": "256aa8f315cbb184eba0256c2ec818abbdd2d408" + }, + "manifest": { + "config": true, + "database": true, + "database_type": "asyncpg", + "extra_files": [ + "base-config.yaml" + ], + "id": "cloud.catgirl.ntfy", + "license": "AGPL-3.0-or-later", + "main_class": "NtfyBot", + "maubot": "0.3.0", + "modules": [ + "ntfy" + ], + "soft_dependencies": [ + "emoji>=2.0" + ], + "version": "0.1.0" + } + }, + "ovgumensabot": { + "attrs": { + "meta": { + "changelog": "https://github.com/v411e/ovgumensabot/releases", + "description": "A bot that automatically sends meals from OvGU canteen every day.", + "downloadPage": "https://github.com/v411e/ovgumensabot/releases", + "homepage": "https://github.com/v411e/ovgumensabot" + } + }, + "github": { + "hash": "sha256-nuOLUPwE0F15FgOtbq3+qmNNd2eHRrRNJPMM+v1Ksy0=", + "owner": "v411e", + "repo": "ovgumensabot", + "rev": "v0.0.8" + }, + "manifest": { + "database": true, + "dependencies": [ + "requests", + "beautifulsoup4" + ], + "extra_files": [ + "LICENSE.txt" + ], + "id": "com.valentinriess.mensa", + "license": "MIT", + "main_class": "MensaBot", + "maubot": "0.2.0", + "modules": [ + "ovgumensabot" + ], + "version": "0.0.8" + } + }, + "pingcheck": { + "attrs": { + "meta": { + "description": "A bot to ping the echo bot and send rtt to Icinga passive check.", + "homepage": "https://edugit.org/nik/maubot-pingcheck" + } + }, + "gitlab": { + "domain": "edugit.org", + "hash": "sha256-ljNi4si7ZkcCidO5l9jJcgdrj4P8RESB1wznxJvzPNQ=", + "owner": "nik", + "repo": "maubot-pingcheck", + "rev": "0.1.0" + }, + "manifest": { + "dependencie": [ + "requests" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.pingcheck", + "license": "MIT", + "main_class": "PingcheckBot", + "maubot": "0.1.0", + "modules": [ + "pingcheck" + ], + "version": "0.1.0" + } + }, + "pocket": { + "attrs": { + "meta": { + "changelog": "https://github.com/jaywink/maubot-pocket/blob/v0.2.5/CHANGELOG.md", + "description": "A bot integrating with Pocket to fetch articles and archive them.", + "downloadPage": "https://github.com/jaywink/maubot-pocket/releases", + "homepage": "https://github.com/jaywink/maubot-pocket" + } + }, + "github": { + "hash": "sha256-I3+nfdkW9WkscsAYN2E1jEyoVujaN/zOTJ8HLReqq44=", + "owner": "jaywink", + "repo": "maubot-pocket", + "rev": "v0.2.5" + }, + "manifest": { + "database": true, + "extra_files": [ + "base-config.yaml" + ], + "id": "me.jasonrobinson.pocket", + "license": "MIT", + "main_class": "PocketPlugin", + "maubot": "0.3.1", + "modules": [ + "pocket" + ], + "version": "0.2.5", + "webapp": true + } + }, + "poll": { + "attrs": { + "meta": { + "changelog": "https://github.com/TomCasavant/PollMaubot/releases", + "description": "A bot that will create a simple poll for users in a room.", + "downloadPage": "https://github.com/TomCasavant/PollMaubot/releases", + "homepage": "https://github.com/TomCasavant/PollMaubot" + } + }, + "github": { + "hash": "sha256-o+9DP9QHZEibmAhy13/fJn72r8hLPY1uuOrTXchjRmw=", + "owner": "TomCasavant", + "repo": "PollMaubot", + "rev": "3.0.1" + }, + "manifest": { + "database": false, + "id": "casavant.tom.poll", + "license": "MIT", + "main_class": "PollPlugin", + "maubot": "0.1.0", + "modules": [ + "poll" + ], + "version": "3.0.1" + } + }, + "random-quote": { + "attrs": { + "meta": { + "changelog": "https://github.com/itrich/QuoteMaubot/releases", + "description": "A plugin to answer with a random quote from a configurable list.", + "downloadPage": "https://github.com/itrich/QuoteMaubot/releases", + "homepage": "https://github.com/itrich/QuoteMaubot" + } + }, + "github": { + "hash": "sha256-NJ6sUC7L4f7ERDAKNcs2RD8q4mGzW0d4rhxh+wqzhVw=", + "owner": "itrich", + "repo": "QuoteMaubot", + "rev": "v0.0.1" + }, + "manifest": { + "config": true, + "database": false, + "dependencies": null, + "extra_files": null, + "id": "net.itrich.maubot.quote", + "license": "MIT", + "main_class": "QuotePlugin", + "maubot": "0.1.0", + "modules": [ + "quote" + ], + "soft_dependencies": null, + "version": "0.0.1", + "webapp": false + } + }, + "random-subreddit-post": { + "attrs": { + "meta": { + "changelog": "https://github.com/williamkray/maubot-reddit/releases", + "description": "A plugin that returns a random post from a given subreddit.", + "downloadPage": "https://github.com/williamkray/maubot-reddit/releases", + "homepage": "https://github.com/williamkray/maubot-reddit" + } + }, + "github": { + "hash": "sha256-xinkSNTWTdKSNE0YFLS3yy26HbqD+I11Z8dGVh/tHNw=", + "owner": "williamkray", + "repo": "maubot-reddit", + "rev": "v0.3.6" + }, + "manifest": { + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "org.jobmachine.reddit", + "license": "MIT", + "main_class": "Post", + "maubot": "0.1.0", + "modules": [ + "reddit" + ], + "version": "0.3.6" + } + }, + "reactbot": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/reactbot/releases", + "description": "A bot that responds to messages that match predefined rules.", + "downloadPage": "https://github.com/maubot/reactbot/releases", + "homepage": "https://github.com/maubot/reactbot" + } + }, + "github": { + "hash": "sha256-ARN9zbOFJCVoqz6ooLRm9DDKUZpbQf7KcfsfoOxeeLE=", + "owner": "maubot", + "repo": "reactbot", + "rev": "v2.2.0" + }, + "isOfficial": true, + "manifest": { + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.reactbot", + "license": "AGPL-3.0-or-later", + "main_class": "ReactBot", + "maubot": "0.1.0", + "modules": [ + "reactbot" + ], + "version": "2.2.0" + } + }, + "redactbot": { + "attrs": { + "meta": { + "description": "A bot that immediately redacts any posted file (except for whitelisted types).", + "homepage": "https://gitlab.com/sspaeth/redactbot" + } + }, + "gitlab": { + "hash": "sha256-uIcXnD3nXVT7mA9SgdyrXGIZuW4CgnCVbCP7TxxnziM=", + "owner": "sspaeth", + "repo": "redactbot", + "rev": "2bca49b14024844c0aa53b9c4802ef6f8702d99d" + }, + "manifest": { + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.redactbot", + "license": "AGPL-3.0-or-later", + "main_class": "RedactBot", + "maubot": "0.1.0", + "modules": [ + "redactbot" + ], + "version": "2.2.0" + } + }, + "reminder": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/reminder/releases", + "description": "A bot to remind you about things.", + "downloadPage": "https://github.com/maubot/reminder/releases", + "homepage": "https://github.com/maubot/reminder" + } + }, + "github": { + "hash": "sha256-BCyeWl5xPKvUGWkrnuGh498gKxfhfNZ7oBrsZzpKxkg=", + "owner": "maubot", + "repo": "reminder", + "rev": "v0.2.2" + }, + "isOfficial": true, + "manifest": { + "database": true, + "dependencies": [ + "python-dateutil", + "pytz" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.reminder", + "license": "AGPL-3.0-or-later", + "main_class": "ReminderBot", + "maubot": "0.1.0", + "modules": [ + "reminder" + ], + "version": "0.2.2" + } + }, + "reminder-agenda": { + "attrs": { + "meta": { + "changelog": "https://github.com/MxMarx/reminder/releases", + "description": "Create reminders, recurring reminders, and agenda items. A maubot port of [matrix-reminder-bot](https://github.com/anoadragon453/matrix-reminder-bot/tree/master) combined with [maubot/reminder](https://github.com/maubot/reminder)", + "downloadPage": "https://github.com/MxMarx/reminder/releases", + "homepage": "https://github.com/MxMarx/reminder" + } + }, + "github": { + "hash": "sha256-3I2EIbyGgtj1NblLAEKCVLSDFnT25YRAp5RXvFHdu2w=", + "owner": "MxMarx", + "repo": "reminder", + "rev": "v0.1.1" + }, + "manifest": { + "database": true, + "database_type": "asyncpg", + "dependencies": [ + "pytz", + "dateparser", + "apscheduler" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "org.bytemarx.reminder", + "license": "AGPL-3.0-or-later", + "main_class": "ReminderBot", + "maubot": "0.4.1", + "modules": [ + "reminder" + ], + "soft_dependencies": [ + "cron_descriptor" + ], + "version": "0.1.1" + } + }, + "rss": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/rss/releases", + "description": "A bot that posts RSS feed updates to Matrix.", + "downloadPage": "https://github.com/maubot/rss/releases", + "homepage": "https://github.com/maubot/rss" + } + }, + "github": { + "hash": "sha256-p/xJpJbzsOeQGcowvOhJSclPtmZyNyBaZBz+mexVqIY=", + "owner": "maubot", + "repo": "rss", + "rev": "v0.3.2" + }, + "isOfficial": true, + "manifest": { + "database": true, + "database_type": "asyncpg", + "dependencies": [ + "feedparser>=5.1" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.rss", + "license": "AGPL-3.0-or-later", + "main_class": "RSSBot", + "maubot": "0.3.0", + "modules": [ + "rss" + ], + "version": "0.3.2" + } + }, + "satwcomic": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/satwcomic/releases", + "description": "A bot to view SatWComics.", + "downloadPage": "https://github.com/maubot/satwcomic/releases", + "homepage": "https://github.com/maubot/satwcomic" + } + }, + "github": { + "hash": "sha256-TyXrPUUQdLC0IXbpQquA9eegzDoBm1g2WaeQuqhYPco=", + "owner": "maubot", + "repo": "satwcomic", + "rev": "0241bce4807ce860578e2f4fde76bb043bcebe95" + }, + "isOfficial": true, + "manifest": { + "database": true, + "dependencies": [ + "pyquery" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.satwcomic", + "license": "AGPL-3.0-or-later", + "main_class": "SatWBot", + "maubot": "0.1.0", + "modules": [ + "satwcomic" + ], + "soft_dependencies": [ + "Pillow" + ], + "version": "1.0.0" + } + }, + "sed": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/sed/releases", + "description": "A bot to do sed-like replacements.", + "downloadPage": "https://github.com/maubot/sed/releases", + "homepage": "https://github.com/maubot/sed" + } + }, + "github": { + "hash": "sha256-raVUYEEuNHDFEE+b/yb8DyokFOrbVn0miul+2tJbR+s=", + "owner": "maubot", + "repo": "sed", + "rev": "v1.1.0" + }, + "isOfficial": true, + "manifest": { + "id": "xyz.maubot.sed", + "license": "AGPL-3.0-or-later", + "main_class": "SedBot", + "modules": [ + "sed" + ], + "version": "1.1.0" + } + }, + "send-custom-html": { + "attrs": { + "meta": { + "changelog": "https://github.com/coffeebank/coffee-maubot/releases", + "description": "Have the bot send a message as custom HTML. Test and preview formatted HTML body in Matrix.", + "downloadPage": "https://github.com/coffeebank/coffee-maubot/releases", + "homepage": "https://github.com/coffeebank/coffee-maubot/tree/master/send-custom-html" + }, + "postPatch": "cd send-custom-html" + }, + "github": { + "hash": "sha256-k+M/Wk4nyXUZBJxmxQr64dPp3rK7i1oQeLFtncle3dI=", + "owner": "coffeebank", + "repo": "coffee-maubot", + "rev": "b25112508d65f7560910e67d3074dd60f4048821" + }, + "manifest": { + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "coffee.maubot.sendcustomhtml", + "license": "AGPL-3.0-or-later", + "main_class": "SendCustomHtmlBot", + "maubot": "0.1.0", + "modules": [ + "sendcustomhtml" + ], + "version": "0.1.0.6" + } + }, + "social-media-download": { + "attrs": { + "meta": { + "changelog": "https://github.com/ggogel/SocialMediaDownloadMaubot/releases", + "description": "A bot that that downloads content from various social media websites given a link.", + "downloadPage": "https://github.com/ggogel/SocialMediaDownloadMaubot/releases", + "homepage": "https://github.com/ggogel/SocialMediaDownloadMaubot" + } + }, + "github": { + "hash": "sha256-RMyQzGz2Z4m9FN0Nt5E6Tj0yZarysygCtvEZDfG143M=", + "owner": "ggogel", + "repo": "SocialMediaDownloadMaubot", + "rev": "1.2.0" + }, + "manifest": { + "config": true, + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "me.gogel.maubot.socialmediadownload", + "license": "MIT", + "main_class": "socialmediadownload/SocialMediaDownloadPlugin", + "maubot": "0.1.0", + "modules": [ + "instaloader", + "socialmediadownload" + ], + "version": "1.2.0" + } + }, + "songwhip": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/songwhip/releases", + "description": "A bot to post Songwhip links.", + "downloadPage": "https://github.com/maubot/songwhip/releases", + "homepage": "https://github.com/maubot/songwhip" + } + }, + "github": { + "hash": "sha256-oghM1IECN88KhwRhGZCTJo4uMwc495sWNHeK9KaK4FU=", + "owner": "maubot", + "repo": "songwhip", + "rev": "c8d00999ab77a77d0036ee6c71b2cf11583f8edd" + }, + "isOfficial": true, + "manifest": { + "id": "xyz.maubot.songwhip", + "license": "MIT", + "main_class": "SongwhipBot", + "maubot": "0.1.0", + "modules": [ + "songwhip" + ], + "version": "0.1.0" + } + }, + "subreddit-linkifier": { + "attrs": { + "meta": { + "changelog": "https://github.com/TomCasavant/RedditMaubot/releases", + "description": "A bot that condescendingly corrects a user when they enter an r/subreddit without providing a link to that subreddit.", + "downloadPage": "https://github.com/TomCasavant/RedditMaubot/releases", + "homepage": "https://github.com/TomCasavant/RedditMaubot" + } + }, + "github": { + "hash": "sha256-4F59gCmSl7FNWTys5c9r4Ha0gschDyiYjsX7emhRwuU=", + "owner": "TomCasavant", + "repo": "RedditMaubot", + "rev": "1.5.0" + }, + "manifest": { + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "casavant.tom.reddit", + "license": "MIT", + "main_class": "RedditPlugin", + "maubot": "0.1.0", + "modules": [ + "reddit" + ], + "version": "1.5.0" + } + }, + "supportportal": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/supportportal/releases", + "description": "A bot to manage customer support on Matrix.", + "downloadPage": "https://github.com/maubot/supportportal/releases", + "homepage": "https://github.com/maubot/supportportal" + } + }, + "github": { + "hash": "sha256-9CmA9KfkOkzqTycAGE8jaZuDwS7IvFwWGUer3iR8ooM=", + "owner": "maubot", + "repo": "supportportal", + "rev": "v0.1.0" + }, + "isOfficial": true, + "manifest": { + "config": true, + "database": true, + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.supportportal", + "license": "AGPL-3.0-or-later", + "main_class": "SupportPortalBot", + "maubot": "0.1.0", + "modules": [ + "supportportal" + ], + "version": "0.1.0" + } + }, + "tex": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/tex/releases", + "description": "A bot that renders LaTeX.", + "downloadPage": "https://github.com/maubot/tex/releases", + "homepage": "https://github.com/maubot/tex" + } + }, + "github": { + "hash": "sha256-6Iq/rOiMQiFtKvAYeYuF+2xXVcR7VIxQTejbpYBpy2A=", + "owner": "maubot", + "repo": "tex", + "rev": "a6617da41409b5fc5960dc8de06046bbac091318" + }, + "isOfficial": true, + "manifest": { + "dependencies": [ + "matplotlib", + "Pillow" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.tex", + "license": "AGPL-3.0-or-later", + "main_class": "TexBot", + "maubot": "0.1.0", + "modules": [ + "tex" + ], + "version": "0.1.0" + } + }, + "ticker": { + "attrs": { + "meta": { + "changelog": "https://github.com/williamkray/maubot-ticker/releases", + "description": "A bot to return financial data about a stock or cryptocurrency.", + "downloadPage": "https://github.com/williamkray/maubot-ticker/releases", + "homepage": "https://github.com/williamkray/maubot-ticker" + } + }, + "github": { + "hash": "sha256-o/AjzuNaVzHKnpV10p19vDJthEUZ75nAg3KT0Ff3LEg=", + "owner": "williamkray", + "repo": "maubot-ticker", + "rev": "v0.0.6" + }, + "manifest": { + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "org.jobmachine.tickerbot", + "license": "MIT", + "main_class": "TickerBot", + "maubot": "0.1.0", + "modules": [ + "tickerbot" + ], + "version": "0.0.6" + } + }, + "timein": { + "attrs": { + "meta": { + "changelog": "https://github.com/coffeebank/coffee-maubot/releases", + "description": "Get the time in specific cities. Check timezones. !timein New York (Python 3.9+) (Python <3.9 requires pytz, fuzzywuzzy)", + "downloadPage": "https://github.com/coffeebank/coffee-maubot/releases", + "homepage": "https://github.com/coffeebank/coffee-maubot/tree/master/timein" + }, + "postPatch": "cd timein" + }, + "github": { + "hash": "sha256-k+M/Wk4nyXUZBJxmxQr64dPp3rK7i1oQeLFtncle3dI=", + "owner": "coffeebank", + "repo": "coffee-maubot", + "rev": "b25112508d65f7560910e67d3074dd60f4048821" + }, + "manifest": { + "database": false, + "dependencies": [ + "pytz", + "fuzzywuzzy" + ], + "id": "coffee.maubot.timein", + "license": "AGPL-3.0-or-later", + "main_class": "TimeinBot", + "maubot": "0.1.0", + "modules": [ + "timein" + ], + "version": "0.1.0.6" + } + }, + "tmdb": { + "attrs": { + "meta": { + "changelog": "https://codeberg.org/lomion/tmdb-bot/releases", + "description": "A bot that posts information about movies fetched from TheMovieDB.org.", + "downloadPage": "https://codeberg.org/lomion/tmdb-bot/releases", + "homepage": "https://codeberg.org/lomion/tmdb-bot", + "license": "AGPL-3.0-only" + } + }, + "gitea": { + "domain": "codeberg.org", + "hash": "sha256-QeKpIukLCeJOxi/+H+Hukf7mA38gvf8q37o4FOuigAU=", + "owner": "lomion", + "repo": "tmdb-bot", + "rev": "rel.1.3.0" + }, + "manifest": { + "database": true, + "id": "lomion.tmdb", + "license": "AGPL 3.0", + "main_class": "TmdbBot", + "maubot": "0.1.0", + "modules": [ + "tmdb" + ], + "version": "1.3.0" + } + }, + "token": { + "attrs": { + "meta": { + "changelog": "https://github.com/yoxcu/maubot-token/releases", + "description": "A maubot to create and manage your synapse user registration tokens.", + "downloadPage": "https://github.com/yoxcu/maubot-token/releases", + "homepage": "https://github.com/yoxcu/maubot-token" + } + }, + "github": { + "hash": "sha256-8ZAH9Kn0EQYY9gLx48gF+aEsFOdlZlrbUIvLMP0uwi4=", + "owner": "yoxcu", + "repo": "maubot-token", + "rev": "v1.1.0" + }, + "manifest": { + "config": true, + "database": false, + "extra_files": [ + "base-config.yaml", + "LICENSE" + ], + "id": "de.yoxcu.token", + "license": "AGPL-3.0-or-later", + "main_class": "TokenBot", + "maubot": "0.1.0", + "modules": [ + "tokenbot" + ], + "version": "1.1.0" + } + }, + "translate": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/translate/releases", + "description": "A bot to translate words.", + "downloadPage": "https://github.com/maubot/translate/releases", + "homepage": "https://github.com/maubot/translate" + } + }, + "github": { + "hash": "sha256-eaiTNjnBa0r2zeCzYZH/k04dGftBSGuGaDvwOGKKZDA=", + "owner": "maubot", + "repo": "translate", + "rev": "v0.1.0" + }, + "isOfficial": true, + "manifest": { + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.translate", + "license": "AGPL-3.0-or-later", + "main_class": "TranslatorBot", + "modules": [ + "translate" + ], + "version": "0.1.0" + } + }, + "trump": { + "attrs": { + "meta": { + "changelog": "https://github.com/jeffcasavant/MaubotTrumpTweet/releases", + "description": "A bot that generates a Trump tweet with the given content.", + "downloadPage": "https://github.com/jeffcasavant/MaubotTrumpTweet/releases", + "homepage": "https://github.com/jeffcasavant/MaubotTrumpTweet" + } + }, + "github": { + "hash": "sha256-WlrFt+uj6E7Ecg+3KW6fjrMXSUP5YFA5ZyitvBON3pA=", + "owner": "jeffcasavant", + "repo": "MaubotTrumpTweet", + "rev": "v1.1.2" + }, + "isPoetry": true, + "manifest": { + "database": false, + "dependencies": [ + "Pillow>=9.0.1, <10.0.0" + ], + "extra_files": [ + "res/font/Roboto-Black.ttf", + "res/font/Roboto-Regular.ttf", + "res/img/avatars/cartoon0.jpg", + "res/img/avatars/cartoon1.jpg", + "res/img/avatars/cartoon2.jpg", + "res/img/avatars/cartoon3.jpg", + "res/img/avatars/cartoon4.jpg", + "res/img/avatars/cartoon5.jpg", + "res/img/avatars/cartoon6.jpg", + "res/img/avatars/cartoon7.jpg", + "res/img/avatars/cartoon8.jpg", + "res/img/avatars/cartoon9.jpg", + "res/img/avatars/default.png", + "res/img/avatars/real0.jpg", + "res/img/avatars/real1.jpg", + "res/img/avatars/real10.jpg", + "res/img/avatars/real11.jpg", + "res/img/avatars/real12.jpg", + "res/img/avatars/real13.jpg", + "res/img/avatars/real14.jpg", + "res/img/avatars/real15.jpeg", + "res/img/avatars/real16.jpg", + "res/img/avatars/real17.jpg", + "res/img/avatars/real18.jpg", + "res/img/avatars/real19.jpeg", + "res/img/avatars/real2.jpg", + "res/img/avatars/real20.jpg", + "res/img/avatars/real21.jpg", + "res/img/avatars/real22.jpg", + "res/img/avatars/real23.jpg", + "res/img/avatars/real24.jpg", + "res/img/avatars/real25.jpg", + "res/img/avatars/real26.jpg", + "res/img/avatars/real27.jpg", + "res/img/avatars/real28.jpeg", + "res/img/avatars/real29.jpg", + "res/img/avatars/real3.jpeg", + "res/img/avatars/real4.jpg", + "res/img/avatars/real5.jpg", + "res/img/avatars/real6.jpeg", + "res/img/avatars/real7.jpg", + "res/img/avatars/real8.jpeg", + "res/img/avatars/real9.jpg", + "res/img/like.png", + "res/img/reply.png", + "res/img/retweet.png", + "res/img/trump.jpg", + "res/img/verified.png" + ], + "id": "casavant.jeff.trumptweet", + "license": "MIT", + "main_class": "TrumpTweetPlugin", + "maubot": "0.1.0", + "modules": [ + "trumptweet" + ], + "version": "1.1.2" + } + }, + "twilio": { + "attrs": { + "meta": { + "changelog": "https://github.com/jeffcasavant/MaubotTwilio/releases", + "description": "Maubot-based SMS bridge.", + "downloadPage": "https://github.com/jeffcasavant/MaubotTwilio/releases", + "homepage": "https://github.com/jeffcasavant/MaubotTwilio" + } + }, + "github": { + "hash": "sha256-b1M9+uXVq3yb4IgcoL/5YqRZ8a13HfyqMw6QFBuBLAM=", + "owner": "jeffcasavant", + "repo": "MaubotTwilio", + "rev": "0.1.0" + }, + "manifest": { + "database": true, + "dependencies": [ + "maubot==0.1.0b1", + "mautrix==0.5.0b2" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "org.casavant.jeff.twilio", + "license": "MIT", + "main_class": "TwilioPlugin", + "maubot": "0.1.0", + "modules": [ + "twilio_plugin" + ], + "version": "0.1.0", + "webapp": true + } + }, + "urban": { + "attrs": { + "meta": { + "changelog": "https://github.com/dvdgsng/UrbanMaubot/releases", + "description": "A bot that fetches definitions from [Urban Dictionary](https://www.urbandictionary.com/).", + "downloadPage": "https://github.com/dvdgsng/UrbanMaubot/releases", + "homepage": "https://github.com/dvdgsng/UrbanMaubot" + } + }, + "github": { + "hash": "sha256-JQ2PpsH/Nno7XqcF1HpZHM/Qv/gta/xGPjfIKtY+pxM=", + "owner": "dvdgsng", + "repo": "UrbanMaubot", + "rev": "1.0.2" + }, + "manifest": { + "id": "com.dvdgsng.maubot.urban", + "license": "AGPL-3.0-or-later", + "main_class": "UrbanDictBot", + "modules": [ + "urban" + ], + "version": "1.0.2" + } + }, + "urlpreview": { + "attrs": { + "meta": { + "changelog": "https://github.com/coffeebank/coffee-maubot/releases", + "description": "Add URL preview embeds to Matrix! A bot that responds to links with a link preview embed, using Matrix API to fetch meta tags. Supports fetching JSON previews.", + "downloadPage": "https://github.com/coffeebank/coffee-maubot/releases", + "homepage": "https://github.com/coffeebank/coffee-maubot/tree/master/urlpreview" + }, + "postPatch": "cd urlpreview" + }, + "github": { + "hash": "sha256-k+M/Wk4nyXUZBJxmxQr64dPp3rK7i1oQeLFtncle3dI=", + "owner": "coffeebank", + "repo": "coffee-maubot", + "rev": "b25112508d65f7560910e67d3074dd60f4048821" + }, + "manifest": { + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "coffee.maubot.urlpreview", + "license": "AGPL-3.0-or-later", + "main_class": "UrlPreviewBot", + "maubot": "0.1.0", + "modules": [ + "urlpreview" + ], + "version": "0.3.4.26" + } + }, + "weather": { + "attrs": { + "meta": { + "changelog": "https://github.com/kellya/maubot-weather/blob/v0.4.1/CHANGELOG.md", + "description": "A bot to get the weather from wttr.in and return a single line of text for the location specified.", + "downloadPage": "https://github.com/kellya/maubot-weather/releases", + "homepage": "https://github.com/kellya/maubot-weather" + } + }, + "github": { + "hash": "sha256-DHMsemVbiXONeg45IpeaP477fbgkftz5mZdI6OhRHOI=", + "owner": "kellya", + "repo": "maubot-weather", + "rev": "v0.4.1" + }, + "manifest": { + "extra_files": [ + "base-config.yaml" + ], + "id": "com.arachnitech.weather", + "license": "MIT", + "main_class": "WeatherBot", + "maubot": "0.1.0", + "modules": [ + "weather" + ], + "version": "0.4.1" + } + }, + "webhook": { + "attrs": { + "meta": { + "changelog": "https://github.com/jkhsjdhjs/maubot-webhook/releases", + "description": "Send messages to rooms via user-defined webhooks.", + "downloadPage": "https://github.com/jkhsjdhjs/maubot-webhook/releases", + "homepage": "https://github.com/jkhsjdhjs/maubot-webhook" + } + }, + "github": { + "hash": "sha256-GGbd7PvW2P0u1h7Cp1GMuEg3uQ0osZBWWHzSW524aBc=", + "owner": "jkhsjdhjs", + "repo": "maubot-webhook", + "rev": "v0.2.0" + }, + "manifest": { + "config": true, + "dependencies": [ + "Jinja2~=3.1" + ], + "extra_files": [ + "base-config.yaml" + ], + "id": "me.jkhsjdhjs.maubot.webhook", + "license": "AGPL-3.0-or-later", + "main_class": "WebhookPlugin", + "maubot": "0.3.1", + "modules": [ + "plugin" + ], + "version": "0.2.0", + "webapp": true + } + }, + "welcome": { + "attrs": { + "meta": { + "changelog": "https://github.com/williamkray/maubot-welcome/releases", + "description": "A plugin that greets new people with a configurable message when they join a room.", + "downloadPage": "https://github.com/williamkray/maubot-welcome/releases", + "homepage": "https://github.com/williamkray/maubot-welcome" + } + }, + "github": { + "hash": "sha256-8BIDj/kHys/Pw1n1lLtxjYOstI/UG5UAlxD+3rpKj0Q=", + "owner": "williamkray", + "repo": "maubot-welcome", + "rev": "a6d3e6cbea87056a1d4694f5379c9ae9d9cdf1c5" + }, + "manifest": { + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "org.jobmachine.welcome", + "license": "MIT", + "main_class": "Greeter", + "maubot": "0.1.0", + "modules": [ + "welcome" + ], + "version": "0.0.4" + } + }, + "wolframalpha": { + "attrs": { + "meta": { + "changelog": "https://github.com/ggogel/WolframAlphaMaubot/releases", + "description": "A bot that allows requesting information from [WolframAlpha](https://www.wolframalpha.com/).", + "downloadPage": "https://github.com/ggogel/WolframAlphaMaubot/releases", + "homepage": "https://github.com/ggogel/WolframAlphaMaubot" + } + }, + "github": { + "hash": "sha256-2GJPAHc9xY7uznALpjzxkpAX16PBxMMSl3QMzjudA+w=", + "owner": "ggogel", + "repo": "WolframAlphaMaubot", + "rev": "v0.0.4" + }, + "manifest": { + "database": false, + "extra_files": [ + "base-config.yaml" + ], + "id": "me.gogel.maubot.wolframalpha", + "license": "MIT", + "main_class": "WolframAlphaPlugin", + "maubot": "0.1.0", + "modules": [ + "wolframalpha" + ], + "version": "0.0.4" + } + }, + "xkcd": { + "attrs": { + "meta": { + "changelog": "https://github.com/maubot/xkcd/releases", + "description": "A bot to view xkcd comics.", + "downloadPage": "https://github.com/maubot/xkcd/releases", + "homepage": "https://github.com/maubot/xkcd" + } + }, + "github": { + "hash": "sha256-dtst/QuIZrMjk5RdbXjTksCbGwf8HCBsECDWtp70W1U=", + "owner": "maubot", + "repo": "xkcd", + "rev": "v1.2.0" + }, + "isOfficial": true, + "manifest": { + "config": true, + "database": true, + "extra_files": [ + "base-config.yaml" + ], + "id": "xyz.maubot.xkcd", + "license": "AGPL-3.0-or-later", + "main_class": "XKCDBot", + "maubot": "0.1.0", + "modules": [ + "xkcd" + ], + "soft_dependencies": [ + "python-magic>=0.4", + "Pillow>=5.1" + ], + "version": "1.2.0" + } + } +} diff --git a/pkgs/tools/networking/maubot/plugins/generated.nix b/pkgs/tools/networking/maubot/plugins/generated.nix new file mode 100644 index 000000000000..241151eb6ca0 --- /dev/null +++ b/pkgs/tools/networking/maubot/plugins/generated.nix @@ -0,0 +1,74 @@ +{ lib +, fetchgit +, fetchFromGitHub +, fetchFromGitLab +, fetchFromGitea +, python3 +, poetry +, buildMaubotPlugin +}: + +let + json = builtins.fromJSON (builtins.readFile ./generated.json); +in + +lib.flip builtins.mapAttrs json (name: entry: +let + inherit (entry) manifest; + + resolveDeps = deps: map + (name: + let + packageName = builtins.head (builtins.match "([^~=<>]*).*" name); + lower = lib.toLower packageName; + dash = builtins.replaceStrings ["_"] ["-"] packageName; + lowerDash = builtins.replaceStrings ["_"] ["-"] lower; + in + python3.pkgs.${packageName} + or python3.pkgs.${lower} + or python3.pkgs.${dash} + or python3.pkgs.${lowerDash} + or null) + (builtins.filter (x: x != "maubot" && x != null) deps); + + reqDeps = resolveDeps (lib.toList (manifest.dependencies or null)); + optDeps = resolveDeps (lib.toList (manifest.soft_dependencies or null)); +in + +lib.makeOverridable buildMaubotPlugin (entry.attrs // { + pname = manifest.id; + inherit (manifest) version; + + src = + if entry?github then fetchFromGitHub entry.github + else if entry?git then fetchgit entry.git + else if entry?gitlab then fetchFromGitLab entry.gitlab + else if entry?gitea then fetchFromGitea entry.gitea + else throw "Invalid generated entry for ${manifest.id}: missing source"; + + propagatedBuildInputs = builtins.filter (x: x != null) (reqDeps ++ optDeps); + + passthru.isOfficial = entry.isOfficial or false; + + meta = entry.attrs.meta // { + license = + let + spdx = entry.attrs.meta.license or manifest.license or "unfree"; + spdxLicenses = builtins.listToAttrs + (map (x: lib.nameValuePair x.spdxId x) (builtins.filter (x: x?spdxId) (builtins.attrValues lib.licenses))); + in + spdxLicenses.${spdx}; + broken = builtins.any (x: x == null) reqDeps; + }; +} // lib.optionalAttrs (entry.isPoetry or false) { + nativeBuildInputs = [ + poetry + (python3.withPackages (p: with p; [ toml ruamel-yaml isort ])) + ]; + + preBuild = lib.optionalString (entry?attrs.preBuild) (entry.attrs.preBuild + "\n") + '' + export HOME=$(mktemp -d) + [[ ! -d scripts ]] || patchShebangs --build scripts + make maubot.yaml + ''; +})) diff --git a/pkgs/tools/networking/maubot/plugins/update.py b/pkgs/tools/networking/maubot/plugins/update.py new file mode 100755 index 000000000000..a430753870fb --- /dev/null +++ b/pkgs/tools/networking/maubot/plugins/update.py @@ -0,0 +1,200 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i python3 -p git nurl "(python3.withPackages (ps: with ps; [ toml gitpython requests ruamel-yaml ]))" + +import git +import json +import os +import subprocess +import ruamel.yaml +import sys +import toml +import zipfile + +from typing import Dict, List + +HOSTNAMES = { + 'git.skeg1.se': 'gitlab', + 'edugit.org': 'gitlab', + 'codeberg.org': 'gitea', +} +PLUGINS: Dict[str, dict] = {} + +yaml = ruamel.yaml.YAML(typ='safe') + +TMP = os.environ.get('TEMPDIR', '/tmp') + +def process_repo(path: str, official: bool): + global PLUGINS + with open(path, 'rt') as f: + data = yaml.load(f) + name, repourl, license, desc = data['name'], data['repo'], data['license'], data['description'] + origurl = repourl + if '/' in name or ' ' in name: + name = os.path.split(path)[-1].removesuffix('.yaml') + name = name.replace('_', '-') + if name in PLUGINS.keys(): + raise ValueError(f'Duplicate plugin {name}, refusing to continue') + repodir = os.path.join(TMP, 'maubot-plugins', name) + plugindir = repodir + if '/tree/' in repourl: + repourl, rev_path = repourl.split('/tree/') + rev, subdir = rev_path.strip('/').split('/') + plugindir = os.path.join(plugindir, subdir) + else: + rev = None + subdir = None + + if repourl.startswith('http:'): + repourl = 'https' + repourl[4:] + repourl = repourl.rstrip('/') + if not os.path.exists(repodir): + print('Fetching', name) + repo = git.Repo.clone_from(repourl + '.git', repodir) + else: + repo = git.Repo(repodir) + tags = sorted(repo.tags, key=lambda t: t.commit.committed_datetime) + tags = list(filter(lambda x: 'rc' not in str(x), tags)) + if tags: + repo.git.checkout(tags[-1]) + rev = str(tags[-1]) + else: + rev = str(repo.commit('HEAD')) + ret: dict = {'attrs':{}} + if subdir: + ret['attrs']['postPatch'] = f'cd {subdir}' + domain, query = repourl.removeprefix('https://').split('/', 1) + hash = subprocess.run([ + 'nurl', + '--hash', + f'file://{repodir}', + rev + ], capture_output=True, check=True).stdout.decode('utf-8') + ret['attrs']['meta'] = { + 'description': desc, + 'homepage': origurl, + } + if domain.endswith('github.com'): + owner, repo = query.split('/') + ret['github'] = { + 'owner': owner, + 'repo': repo, + 'rev': rev, + 'hash': hash, + } + ret['attrs']['meta']['downloadPage'] = f'{repourl}/releases' + ret['attrs']['meta']['changelog'] = f'{repourl}/releases' + repobase = f'{repourl}/blob/{rev}' + elif HOSTNAMES.get(domain, 'gitea' if 'gitea.' in domain or 'forgejo.' in domain else None) == 'gitea': + owner, repo = query.split('/') + ret['gitea'] = { + 'domain': domain, + 'owner': owner, + 'repo': repo, + 'rev': rev, + 'hash': hash, + } + repobase = f'{repourl}/src/commit/{rev}' + ret['attrs']['meta']['downloadPage'] = f'{repourl}/releases' + ret['attrs']['meta']['changelog'] = f'{repourl}/releases' + elif HOSTNAMES.get(domain, 'gitlab' if 'gitlab.' in domain else None) == 'gitlab': + owner, repo = query.split('/') + ret['gitlab'] = { + 'owner': owner, + 'repo': repo, + 'rev': rev, + 'hash': hash, + } + if domain != 'gitlab.com': + ret['gitlab']['domain'] = domain + repobase = f'{repourl}/-/blob/{rev}' + else: + raise ValueError(f'Is {domain} Gitea or Gitlab, or something else? Please specify in the Python script!') + if os.path.exists(os.path.join(plugindir, 'CHANGELOG.md')): + ret['attrs']['meta']['changelog'] = f'{repobase}/CHANGELOG.md' + if os.path.exists(os.path.join(plugindir, 'maubot.yaml')): + with open(os.path.join(plugindir, 'maubot.yaml'), 'rt') as f: + ret['manifest'] = yaml.load(f) + elif os.path.exists(os.path.join(plugindir, 'pyproject.toml')): + ret['isPoetry'] = True + with open(os.path.join(plugindir, 'pyproject.toml'), 'rt') as f: + data = toml.load(f) + deps = [] + for key, val in data['tool']['poetry'].get('dependencies', {}).items(): + if key in ['maubot', 'mautrix', 'python']: + continue + reqs = [] + for req in val.split(','): + reqs.extend(poetry_to_pep(req)) + deps.append(key + ', '.join(reqs)) + ret['manifest'] = data['tool']['maubot'] + ret['manifest']['id'] = data['tool']['poetry']['name'] + ret['manifest']['version'] = data['tool']['poetry']['version'] + ret['manifest']['license'] = data['tool']['poetry']['license'] + if deps: + ret['manifest']['dependencies'] = deps + else: + raise ValueError(f'No maubot.yaml or pyproject.toml found in {repodir}') + # normalize non-spdx-conformant licenses this way + # (and fill out missing license info) + if 'license' not in ret['manifest'] or ret['manifest']['license'] in ['GPLv3', 'AGPL 3.0']: + ret['attrs']['meta']['license'] = license + elif ret['manifest']['license'] != license: + print(f"Warning: licenses for {repourl} don't match! {ret['manifest']['license']} != {license}") + if official: + ret['isOfficial'] = official + PLUGINS[name] = ret + +def next_incomp(ver_s: str) -> str: + ver = ver_s.split('.') + zero = False + for i in range(len(ver)): + try: + seg = int(ver[i]) + except ValueError: + if zero: + ver = ver[:i] + break + continue + if zero: + ver[i] = '0' + elif seg: + ver[i] = str(seg + 1) + zero = True + return '.'.join(ver) + +def poetry_to_pep(ver_req: str) -> List[str]: + if '*' in ver_req: + raise NotImplementedError('Wildcard poetry versions not implemented!') + if ver_req.startswith('^'): + return ['>=' + ver_req[1:], '<' + next_incomp(ver_req[1:])] + if ver_req.startswith('~'): + return ['~=' + ver_req[1:]] + return [ver_req] + +def main(): + cache_path = os.path.join(TMP, 'maubot-plugins') + if not os.path.exists(cache_path): + os.makedirs(cache_path) + git.Repo.clone_from('https://github.com/maubot/plugins.maubot.xyz', os.path.join(cache_path, '_repo')) + else: + pass + + repodir = os.path.join(cache_path, '_repo') + + for suffix, official in (('official', True), ('thirdparty', False)): + directory = os.path.join(repodir, 'data', 'plugins', suffix) + for plugin_name in os.listdir(directory): + process_repo(os.path.join(directory, plugin_name), official) + + if os.path.isdir('pkgs/tools/networking/maubot/plugins'): + generated = 'pkgs/tools/networking/maubot/plugins/generated.json' + else: + script_dir = os.path.dirname(os.path.realpath(__file__)) + generated = os.path.join(script_dir, 'generated.json') + + with open(generated, 'wt') as file: + json.dump(PLUGINS, file, indent=' ', separators=(',', ': '), sort_keys=True) + file.write('\n') + +if __name__ == '__main__': + main() diff --git a/pkgs/tools/networking/maubot/wrapper.nix b/pkgs/tools/networking/maubot/wrapper.nix new file mode 100644 index 000000000000..baa0c29052e9 --- /dev/null +++ b/pkgs/tools/networking/maubot/wrapper.nix @@ -0,0 +1,70 @@ +{ lib +, symlinkJoin +, runCommand +, unwrapped +, python3 +, formats +}: + +let wrapper = { pythonPackages ? (_: [ ]), plugins ? (_: [ ]), baseConfig ? null }: + let + plugins' = plugins unwrapped.plugins; + extraPythonPackages = builtins.concatLists (map (p: p.propagatedBuildInputs or [ ]) plugins'); + in + symlinkJoin { + name = "${unwrapped.pname}-with-plugins-${unwrapped.version}"; + + inherit unwrapped; + paths = lib.optional (baseConfig != null) unwrapped ++ plugins'; + pythonPath = lib.optional (baseConfig == null) unwrapped ++ pythonPackages python3.pkgs ++ extraPythonPackages; + + nativeBuildInputs = [ python3.pkgs.wrapPython ]; + + postBuild = '' + rm -f $out/nix-support/propagated-build-inputs + rmdir $out/nix-support || true + ${lib.optionalString (baseConfig != null) '' + rm $out/${python3.sitePackages}/maubot/example-config.yaml + substituteAll ${(formats.yaml { }).generate "example-config.yaml" (lib.recursiveUpdate baseConfig { + plugin_directories = lib.optionalAttrs (plugins' != []) { + load = [ "@out@/lib/maubot-plugins" ] ++ (baseConfig.plugin_directories.load or []); + }; + # Normally it should be set to false by default to take it from package + # root, but aiohttp doesn't follow symlinks when serving static files + # unless follow_symlinks=True is passed. Instead of patching maubot, use + # this non-invasive approach + # XXX: would patching maubot be better? See: + # https://github.com/maubot/maubot/blob/75879cfb9370aade6fa0e84e1dde47222625139a/maubot/server.py#L106 + server.override_resource_path = + if builtins.isNull (baseConfig.server.override_resource_path or null) + then "${unwrapped}/${python3.sitePackages}/maubot/management/frontend/build" + else baseConfig.server.override_resource_path; + })})} $out/${python3.sitePackages}/maubot/example-config.yaml + rm -rf $out/bin + ''} + mkdir -p $out/bin + cp $unwrapped/bin/.mbc-wrapped $out/bin/mbc + cp $unwrapped/bin/.maubot-wrapped $out/bin/maubot + wrapPythonProgramsIn "$out/bin" "${lib.optionalString (baseConfig != null) "$out "}$pythonPath" + ''; + + passthru = { + inherit unwrapped; + python = python3; + withPythonPackages = filter: wrapper { + pythonPackages = pkgs: pythonPackages pkgs ++ filter pkgs; + inherit plugins baseConfig; + }; + withPlugins = filter: wrapper { + plugins = pkgs: plugins pkgs ++ filter pkgs; + inherit pythonPackages baseConfig; + }; + withBaseConfig = baseConfig: wrapper { + inherit baseConfig pythonPackages plugins; + }; + }; + + meta.priority = (unwrapped.meta.priority or 0) - 1; + }; +in +wrapper From 00070cf866af5945cefdb59803005de8a47abaf2 Mon Sep 17 00:00:00 2001 From: chayleaf Date: Sat, 4 Nov 2023 08:53:27 +0700 Subject: [PATCH 2/3] nixos/maubot: init --- .../manual/release-notes/rl-2405.section.md | 2 +- nixos/modules/module-list.nix | 1 + nixos/modules/services/matrix/maubot.md | 103 ++++ nixos/modules/services/matrix/maubot.nix | 459 ++++++++++++++++++ 4 files changed, 564 insertions(+), 1 deletion(-) create mode 100644 nixos/modules/services/matrix/maubot.md create mode 100644 nixos/modules/services/matrix/maubot.nix diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index e2f99c20cfc8..70b3391e0a29 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -14,7 +14,7 @@ In addition to numerous new and upgraded packages, this release has the followin -- Create the first release note entry in this section! +- [maubot](https://github.com/maubot/maubot), a plugin-based Matrix bot framework. Available as [services.maubot](#opt-services.maubot.enable). ## Backward Incompatibilities {#sec-release-24.05-incompatibilities} diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 2ef049beeca4..b92786506a29 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -621,6 +621,7 @@ ./services/matrix/appservice-irc.nix ./services/matrix/conduit.nix ./services/matrix/dendrite.nix + ./services/matrix/maubot.nix ./services/matrix/mautrix-facebook.nix ./services/matrix/mautrix-telegram.nix ./services/matrix/mautrix-whatsapp.nix diff --git a/nixos/modules/services/matrix/maubot.md b/nixos/modules/services/matrix/maubot.md new file mode 100644 index 000000000000..f6a05db56caf --- /dev/null +++ b/nixos/modules/services/matrix/maubot.md @@ -0,0 +1,103 @@ +# Maubot {#module-services-maubot} + +[Maubot](https://github.com/maubot/maubot) is a plugin-based bot +framework for Matrix. + +## Configuration {#module-services-maubot-configuration} + +1. Set [](#opt-services.maubot.enable) to `true`. The service will use + SQLite by default. +2. If you want to use PostgreSQL instead of SQLite, do this: + + ```nix + services.maubot.settings.database = "postgresql://maubot@localhost/maubot"; + ``` + + If the PostgreSQL connection requires a password, you will have to + add it later on step 8. +3. If you plan to expose your Maubot interface to the web, do something + like this: + ```nix + services.nginx.virtualHosts."matrix.example.org".locations = { + "/_matrix/maubot/" = { + proxyPass = "http://127.0.0.1:${toString config.services.maubot.settings.server.port}"; + proxyWebsockets = true; + }; + }; + services.maubot.settings.server.public_url = "matrix.example.org"; + # do the following only if you want to use something other than /_matrix/maubot... + services.maubot.settings.server.ui_base_path = "/another/base/path"; + ``` +4. Optionally, set `services.maubot.pythonPackages` to a list of python3 + packages to make available for Maubot plugins. +5. Optionally, set `services.maubot.plugins` to a list of Maubot + plugins (full list available at https://plugins.maubot.xyz/): + ```nix + services.maubot.plugins = with config.services.maubot.package.plugins; [ + reactbot + # This will only change the default config! After you create a + # plugin instance, the default config will be copied into that + # instance's config in Maubot's database, and further base config + # changes won't affect the running plugin. + (rss.override { + base_config = { + update_interval = 60; + max_backoff = 7200; + spam_sleep = 2; + command_prefix = "rss"; + admins = [ "@chayleaf:pavluk.org" ]; + }; + }) + ]; + # ...or... + services.maubot.plugins = config.services.maubot.package.plugins.allOfficialPlugins; + # ...or... + services.maubot.plugins = config.services.maubot.package.plugins.allPlugins; + # ...or... + services.maubot.plugins = with config.services.maubot.package.plugins; [ + (weather.override { + # you can pass base_config as a string + base_config = '' + default_location: New York + default_units: M + default_language: + show_link: true + show_image: false + ''; + }) + ]; + ``` +6. Start Maubot at least once before doing the following steps (it's + necessary to generate the initial config). +7. If your PostgreSQL connection requires a password, add + `database: postgresql://user:password@localhost/maubot` + to `/var/lib/maubot/config.yaml`. This overrides the Nix-provided + config. Even then, don't remove the `database` line from Nix config + so the module knows you use PostgreSQL! +8. To create a user account for logging into Maubot web UI and + configuring it, generate a password using the shell command + `mkpasswd -R 12 -m bcrypt`, and edit `/var/lib/maubot/config.yaml` + with the following: + + ```yaml + admins: + admin_username: $2b$12$g.oIStUeUCvI58ebYoVMtO/vb9QZJo81PsmVOomHiNCFbh0dJpZVa + ``` + + Where `admin_username` is your username, and `$2b...` is the bcrypted + password. +9. Optional: if you want to be able to register new users with the + Maubot CLI (`mbc`), and your homeserver is private, add your + homeserver's registration key to `/var/lib/maubot/config.yaml`: + + ```yaml + homeservers: + matrix.example.org: + url: https://matrix.example.org + secret: your-very-secret-key + ``` +10. Restart Maubot after editing `/var/lib/maubot/config.yaml`,and + Maubot will be available at + `https://matrix.example.org/_matrix/maubot`. If you want to use the + `mbc` CLI, it's available using the `maubot` package (`nix-shell -p + maubot`). diff --git a/nixos/modules/services/matrix/maubot.nix b/nixos/modules/services/matrix/maubot.nix new file mode 100644 index 000000000000..6cdb57fa72ef --- /dev/null +++ b/nixos/modules/services/matrix/maubot.nix @@ -0,0 +1,459 @@ +{ lib +, config +, pkgs +, ... +}: + +let + cfg = config.services.maubot; + + wrapper1 = + if cfg.plugins == [ ] + then cfg.package + else cfg.package.withPlugins (_: cfg.plugins); + + wrapper2 = + if cfg.pythonPackages == [ ] + then wrapper1 + else wrapper1.withPythonPackages (_: cfg.pythonPackages); + + settings = lib.recursiveUpdate cfg.settings { + plugin_directories.trash = + if cfg.settings.plugin_directories.trash == null + then "delete" + else cfg.settings.plugin_directories.trash; + server.unshared_secret = "generate"; + }; + + finalPackage = wrapper2.withBaseConfig settings; + + isPostgresql = db: builtins.isString db && lib.hasPrefix "postgresql://" db; + isLocalPostgresDB = db: isPostgresql db && builtins.any (x: lib.hasInfix x db) [ + "@127.0.0.1/" + "@::1/" + "@[::1]/" + "@localhost/" + ]; + parsePostgresDB = db: + let + noSchema = lib.removePrefix "postgresql://" db; + in { + username = builtins.head (lib.splitString "@" noSchema); + database = lib.last (lib.splitString "/" noSchema); + }; + + postgresDBs = [ + cfg.settings.database + cfg.settings.crypto_database + cfg.settings.plugin_databases.postgres + ]; + + localPostgresDBs = builtins.filter isLocalPostgresDB postgresDBs; + + parsedLocalPostgresDBs = map parsePostgresDB localPostgresDBs; + parsedPostgresDBs = map parsePostgresDB postgresDBs; + + hasLocalPostgresDB = localPostgresDBs != [ ]; +in +{ + options.services.maubot = with lib; { + enable = mkEnableOption (mdDoc "maubot"); + + package = lib.mkPackageOptionMD pkgs "maubot" { }; + + plugins = mkOption { + type = types.listOf types.package; + default = [ ]; + example = literalExpression '' + with config.services.maubot.package.plugins; [ + xyz.maubot.reactbot + xyz.maubot.rss + ]; + ''; + description = mdDoc '' + List of additional maubot plugins to make available. + ''; + }; + + pythonPackages = mkOption { + type = types.listOf types.package; + default = [ ]; + example = literalExpression '' + with pkgs.python3Packages; [ + aiohttp + ]; + ''; + description = mdDoc '' + List of additional Python packages to make available for maubot. + ''; + }; + + dataDir = mkOption { + type = types.str; + default = "/var/lib/maubot"; + description = mdDoc '' + The directory where maubot stores its stateful data. + ''; + }; + + extraConfigFile = mkOption { + type = types.str; + default = "./config.yaml"; + defaultText = literalExpression ''"''${config.services.maubot.dataDir}/config.yaml"''; + description = mdDoc '' + A file for storing secrets. You can pass homeserver registration keys here. + If it already exists, **it must contain `server.unshared_secret`** which is used for signing API keys. + If `configMutable` is not set to true, **maubot user must have write access to this file**. + ''; + }; + + configMutable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Whether maubot should write updated config into `extraConfigFile`. **This will make your Nix module settings have no effect besides the initial config, as extraConfigFile takes precedence over NixOS settings!** + ''; + }; + + settings = mkOption { + default = { }; + description = mdDoc '' + YAML settings for maubot. See the + [example configuration](https://github.com/maubot/maubot/blob/master/maubot/example-config.yaml) + for more info. + + Secrets should be passed in by using `extraConfigFile`. + ''; + type = with types; submodule { + options = { + database = mkOption { + type = str; + default = "sqlite:maubot.db"; + example = "postgresql://username:password@hostname/dbname"; + description = mdDoc '' + The full URI to the database. SQLite and Postgres are fully supported. + Other DBMSes supported by SQLAlchemy may or may not work. + ''; + }; + + crypto_database = mkOption { + type = str; + default = "default"; + example = "postgresql://username:password@hostname/dbname"; + description = mdDoc '' + Separate database URL for the crypto database. By default, the regular database is also used for crypto. + ''; + }; + + database_opts = mkOption { + type = types.attrs; + default = { }; + description = mdDoc '' + Additional arguments for asyncpg.create_pool() or sqlite3.connect() + ''; + }; + + plugin_directories = mkOption { + default = { }; + description = mdDoc "Plugin directory paths"; + type = submodule { + options = { + upload = mkOption { + type = types.str; + default = "./plugins"; + defaultText = literalExpression ''"''${config.services.maubot.dataDir}/plugins"''; + description = mdDoc '' + The directory where uploaded new plugins should be stored. + ''; + }; + load = mkOption { + type = types.listOf types.str; + default = [ "./plugins" ]; + defaultText = literalExpression ''[ "''${config.services.maubot.dataDir}/plugins" ]''; + description = mdDoc '' + The directories from which plugins should be loaded. Duplicate plugin IDs will be moved to the trash. + ''; + }; + trash = mkOption { + type = with types; nullOr str; + default = "./trash"; + defaultText = literalExpression ''"''${config.services.maubot.dataDir}/trash"''; + description = mdDoc '' + The directory where old plugin versions and conflicting plugins should be moved. Set to null to delete files immediately. + ''; + }; + }; + }; + }; + + plugin_databases = mkOption { + description = mdDoc "Plugin database settings"; + default = { }; + type = submodule { + options = { + sqlite = mkOption { + type = types.str; + default = "./plugins"; + defaultText = literalExpression ''"''${config.services.maubot.dataDir}/plugins"''; + description = mdDoc '' + The directory where SQLite plugin databases should be stored. + ''; + }; + + postgres = mkOption { + type = types.nullOr types.str; + default = if isPostgresql cfg.settings.database then "default" else null; + defaultText = literalExpression ''if isPostgresql config.services.maubot.settings.database then "default" else null''; + description = mdDoc '' + The connection URL for plugin database. See [example config](https://github.com/maubot/maubot/blob/master/maubot/example-config.yaml) for exact format. + ''; + }; + + postgres_max_conns_per_plugin = mkOption { + type = types.nullOr types.int; + default = 3; + description = mdDoc '' + Maximum number of connections per plugin instance. + ''; + }; + + postgres_opts = mkOption { + type = types.attrs; + default = { }; + description = mdDoc '' + Overrides for the default database_opts when using a non-default postgres connection URL. + ''; + }; + }; + }; + }; + + server = mkOption { + default = { }; + description = mdDoc "Listener config"; + type = submodule { + options = { + hostname = mkOption { + type = types.str; + default = "127.0.0.1"; + description = mdDoc '' + The IP to listen on + ''; + }; + port = mkOption { + type = types.port; + default = 29316; + description = mdDoc '' + The port to listen on + ''; + }; + public_url = mkOption { + type = types.str; + default = "http://${cfg.settings.server.hostname}:${toString cfg.settings.server.port}"; + defaultText = literalExpression ''"http://''${config.services.maubot.settings.server.hostname}:''${toString config.services.maubot.settings.server.port}"''; + description = mdDoc '' + Public base URL where the server is visible. + ''; + }; + ui_base_path = mkOption { + type = types.str; + default = "/_matrix/maubot"; + description = mdDoc '' + The base path for the UI. + ''; + }; + plugin_base_path = mkOption { + type = types.str; + default = "${config.services.maubot.settings.server.ui_base_path}/plugin/"; + defaultText = literalExpression '' + "''${config.services.maubot.settings.server.ui_base_path}/plugin/" + ''; + description = mdDoc '' + The base path for plugin endpoints. The instance ID will be appended directly. + ''; + }; + override_resource_path = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + Override path from where to load UI resources. + ''; + }; + }; + }; + }; + + homeservers = mkOption { + type = types.attrsOf (types.submodule { + options = { + url = mkOption { + type = types.str; + description = mdDoc '' + Client-server API URL + ''; + }; + }; + }); + default = { + "matrix.org" = { + url = "https://matrix-client.matrix.org"; + }; + }; + description = mdDoc '' + Known homeservers. This is required for the `mbc auth` command and also allows more convenient access from the management UI. + If you want to specify registration secrets, pass this via extraConfigFile instead. + ''; + }; + + admins = mkOption { + type = types.attrsOf types.str; + default = { root = ""; }; + description = mdDoc '' + List of administrator users. Plaintext passwords will be bcrypted on startup. Set empty password + to prevent normal login. Root is a special user that can't have a password and will always exist. + ''; + }; + + api_features = mkOption { + type = types.attrsOf bool; + default = { + login = true; + plugin = true; + plugin_upload = true; + instance = true; + instance_database = true; + client = true; + client_proxy = true; + client_auth = true; + dev_open = true; + log = true; + }; + description = mdDoc '' + API feature switches. + ''; + }; + + logging = mkOption { + type = types.attrs; + description = mdDoc '' + Python logging configuration. See [section 16.7.2 of the Python + documentation](https://docs.python.org/3.6/library/logging.config.html#configuration-dictionary-schema) + for more info. + ''; + default = { + version = 1; + formatters = { + colored = { + "()" = "maubot.lib.color_log.ColorFormatter"; + format = "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s"; + }; + normal = { + format = "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s"; + }; + }; + handlers = { + file = { + class = "logging.handlers.RotatingFileHandler"; + formatter = "normal"; + filename = "./maubot.log"; + maxBytes = 10485760; + backupCount = 10; + }; + console = { + class = "logging.StreamHandler"; + formatter = "colored"; + }; + }; + loggers = { + maubot = { + level = "DEBUG"; + }; + mau = { + level = "DEBUG"; + }; + aiohttp = { + level = "INFO"; + }; + }; + root = { + level = "DEBUG"; + handlers = [ "file" "console" ]; + }; + }; + }; + }; + }; + }; + }; + + config = lib.mkIf cfg.enable { + warnings = lib.optional (builtins.any (x: x.username != x.database) parsedLocalPostgresDBs) '' + The Maubot database username doesn't match the database name! This means the user won't be automatically + granted ownership of the database. Consider changing either the username or the database name. + ''; + assertions = [ + { + assertion = builtins.all (x: !lib.hasInfix ":" x.username) parsedPostgresDBs; + message = '' + Putting database passwords in your Nix config makes them world-readable. To securely put passwords + in your Maubot config, change /var/lib/maubot/config.yaml after running Maubot at least once as + described in the NixOS manual. + ''; + } + { + assertion = hasLocalPostgresDB -> config.services.postgresql.enable; + message = '' + Cannot deploy maubot with a configuration for a local postgresql database and a missing postgresql service. + ''; + } + ]; + + services.postgresql = lib.mkIf hasLocalPostgresDB { + enable = true; + ensureDatabases = map (x: x.database) parsedLocalPostgresDBs; + ensureUsers = lib.flip map parsedLocalPostgresDBs (x: { + name = x.username; + ensureDBOwnership = lib.mkIf (x.username == x.database) true; + }); + }; + + users.users.maubot = { + group = "maubot"; + home = cfg.dataDir; + # otherwise StateDirectory is enough + createHome = lib.mkIf (cfg.dataDir != "/var/lib/maubot") true; + isSystemUser = true; + }; + + users.groups.maubot = { }; + + systemd.services.maubot = rec { + description = "maubot - a plugin-based Matrix bot system written in Python"; + after = [ "network.target" ] ++ wants ++ lib.optional hasLocalPostgresDB "postgresql.service"; + # all plugins get automatically disabled if maubot starts before synapse + wants = lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; + wantedBy = [ "multi-user.target" ]; + + preStart = '' + if [ ! -f "${cfg.extraConfigFile}" ]; then + echo "server:" > "${cfg.extraConfigFile}" + echo " unshared_secret: $(head -c40 /dev/random | base32 | ${pkgs.gawk}/bin/awk '{print tolower($0)}')" > "${cfg.extraConfigFile}" + chmod 640 "${cfg.extraConfigFile}" + fi + ''; + + serviceConfig = { + ExecStart = "${finalPackage}/bin/maubot --config ${cfg.extraConfigFile}" + lib.optionalString (!cfg.configMutable) " --no-update"; + User = "maubot"; + Group = "maubot"; + Restart = "on-failure"; + RestartSec = "10s"; + StateDirectory = lib.mkIf (cfg.dataDir == "/var/lib/maubot") "maubot"; + WorkingDirectory = cfg.dataDir; + }; + }; + }; + + meta.maintainers = with lib.maintainers; [ chayleaf ]; + meta.doc = ./maubot.md; +} From 352d3a3ad9345a0d9864c3923904b81a0e1f4ef7 Mon Sep 17 00:00:00 2001 From: chayleaf Date: Mon, 20 Nov 2023 05:02:23 +0700 Subject: [PATCH 3/3] maubot: switch to ensureNewerSourcesForZipFilesHook --- .../allow-building-plugins-from-nix-store.patch | 13 ------------- pkgs/tools/networking/maubot/default.nix | 2 -- pkgs/tools/networking/maubot/plugins/default.nix | 6 +++++- 3 files changed, 5 insertions(+), 16 deletions(-) delete mode 100644 pkgs/tools/networking/maubot/allow-building-plugins-from-nix-store.patch diff --git a/pkgs/tools/networking/maubot/allow-building-plugins-from-nix-store.patch b/pkgs/tools/networking/maubot/allow-building-plugins-from-nix-store.patch deleted file mode 100644 index 1df88b92aa51..000000000000 --- a/pkgs/tools/networking/maubot/allow-building-plugins-from-nix-store.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/maubot/cli/commands/build.py b/maubot/cli/commands/build.py -index ec3ac26..4de85f2 100644 ---- a/maubot/cli/commands/build.py -+++ b/maubot/cli/commands/build.py -@@ -84,7 +84,7 @@ def read_output_path(output: str, meta: PluginMeta) -> str | None: - - - def write_plugin(meta: PluginMeta, output: str | IO) -> None: -- with zipfile.ZipFile(output, "w") as zip: -+ with zipfile.ZipFile(output, "w", strict_timestamps=False) as zip: - meta_dump = BytesIO() - yaml.dump(meta.serialize(), meta_dump) - zip.writestr("maubot.yaml", meta_dump.getvalue()) diff --git a/pkgs/tools/networking/maubot/default.nix b/pkgs/tools/networking/maubot/default.nix index 2eb5c9e76bae..acee6f1dedb3 100644 --- a/pkgs/tools/networking/maubot/default.nix +++ b/pkgs/tools/networking/maubot/default.nix @@ -56,8 +56,6 @@ let url = "https://github.com/maubot/maubot/commit/283f0a3ed5dfae13062b6f0fd153fbdc477f4381.patch"; sha256 = "0yn5357z346qzy5v5g124mgiah1xsi9yyfq42zg028c8paiw8s8x"; }) - # allow running "mbc build" in a nix derivation - ./allow-building-plugins-from-nix-store.patch ]; propagatedBuildInputs = with python.pkgs; [ diff --git a/pkgs/tools/networking/maubot/plugins/default.nix b/pkgs/tools/networking/maubot/plugins/default.nix index 0a7c606909a0..b60589b9df7e 100644 --- a/pkgs/tools/networking/maubot/plugins/default.nix +++ b/pkgs/tools/networking/maubot/plugins/default.nix @@ -5,6 +5,7 @@ , fetchFromGitea , stdenvNoCC , callPackage +, ensureNewerSourcesForZipFilesHook , maubot , python3 , poetry @@ -18,7 +19,10 @@ let buildMaubotPlugin = attrs@{ version, pname, base_config ? null, ... }: stdenvNoCC.mkDerivation (builtins.removeAttrs attrs [ "base_config" ] // { pluginName = "${pname}-v${version}.mbp"; - nativeBuildInputs = (attrs.nativeBuildInputs or [ ]) ++ [ maubot ]; + nativeBuildInputs = (attrs.nativeBuildInputs or [ ]) ++ [ + ensureNewerSourcesForZipFilesHook + maubot + ]; buildPhase = '' runHook preBuild