summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorParthiv Seetharaman <pachum99@myrdd.info>2022-01-16 21:29:21 -0800
committerParthiv Seetharaman <pachum99@myrdd.info>2022-01-16 21:44:42 -0800
commit8c05a809d70aeeb6c6e23d405ba693040ad00730 (patch)
tree70cc604e5eeb943e15c925f8e0c4d6d1eae8ed7c
init the module, README, packages, and other stuff
-rw-r--r--README.md108
-rw-r--r--flake.lock77
-rw-r--r--flake.nix40
-rw-r--r--module/as-formats.nix160
-rw-r--r--module/as-options.nix144
-rw-r--r--module/default.nix182
-rw-r--r--pkgs/default.nix10
-rw-r--r--pkgs/mautrix-instagram/default.nix77
-rw-r--r--pkgs/mautrix-twitter/default.nix77
-rw-r--r--pkgs/mautrix-wsproxy/default.nix34
-rw-r--r--pkgs/mx-puppet-groupme/default.nix46
-rwxr-xr-xpkgs/mx-puppet-groupme/generate.sh16
-rw-r--r--pkgs/mx-puppet-groupme/node-composition.nix17
-rw-r--r--pkgs/mx-puppet-groupme/node-env.nix567
-rw-r--r--pkgs/mx-puppet-groupme/node-packages.nix3342
-rw-r--r--pkgs/mx-puppet-groupme/package-lock.json2527
-rw-r--r--pkgs/mx-puppet-groupme/package.json24
-rw-r--r--pkgs/mx-puppet-slack/default.nix59
-rwxr-xr-xpkgs/mx-puppet-slack/generate.sh24
-rw-r--r--pkgs/mx-puppet-slack/node-composition.nix20
-rw-r--r--pkgs/mx-puppet-slack/node-env.nix578
-rw-r--r--pkgs/mx-puppet-slack/node-packages.nix4217
-rw-r--r--profile.nix73
-rw-r--r--test.nix123
24 files changed, 12542 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..39e7294
--- /dev/null
+++ b/README.md
@@ -0,0 +1,108 @@
+# Universal NixOS module for Matrix appservices
+Use this flake to easily setup matrix appservices on a nixos server.
+
+You no longer have to think about generating registration files or
+configuring docker or systemd to run the appservices.
+
+This module can take care of the heavy lifting, so you only have to
+think about the important settings that the appservice needs.
+
+## Usage
+Once you have imported the module(see next section), you can spin
+up most appservices with just a few lines of nixos configuration.
+
+For example, here is how you would setup mautrix-whatsapp:
+```
+{ pkgs, ... }:
+{
+ services.matrix-appservices = {
+ whatsapp = {
+ port = 29183;
+ format = "mautrix-go";
+ package = pkgs.mautrix-whatsapp;
+ };
+ };
+}
+```
+
+There you go! Once you rebuild, mautrix-whatsapp will be running
+as a systemd service named `matrix-as-whatsapp` and all its data will
+be stored in `/var/lib/matrix-as-whatsapp`.
+
+If you would like the module to configure synapse or dendrite to
+include all appservice registration files you can just set:
+`services.matrix-appservices.addRegistrationFiles = true`.
+
+## Configuring
+There are many options available to configure the way each appservice
+is setup. But to consolidate similarities, there are three formats
+available which set sane defaults for those options: `mautrix-go`,
+`mautrix-python`, and `mx-puppet`.
+
+For the majority of appservices meant for personal use, you likely
+will only have to set a `port`, `format`, and `package`. And if the
+appservice is more complicated you can take advantage of the other
+options to
+
+In the preStart script of each appservice, a registration file is automatically
+generated with random strings for the important tokens and any data passed
+to the `registrationData` option. This file will be available to your `settings`
+and `startScript` as `$REGISTRATION_FILE`.
+
+After this, a configuration file is generated based on the `settings` passed
+to the appservice. Environment variables are also substuted in with envsubst,
+so the `environmentFile` option can be used to pass secrets for the appservice.
+
+### Environment Variables
+These variables are available in your `startScript` and `settings`(substituted in):
+ - $REGISTRATION_FILE => The registration file generated automatically
+ - $SETTINGS_FILE => Settings file generated
+ - $DIR => Data directory of the appservice
+ - $AS_TOKEN => Appservice token(needs to be kept secret)
+ - $HS_TOKEN => Homeserver token(needs to be kept secret)
+
+## Importing the module
+### With Flakes
+Add this flake as an input, then import the `nixosModule` output in
+your configuration.
+```
+{
+ inputs.nix-matrix-appservices.url = "gitlab:coffeetables/nix-matrix-appservices";
+
+ outputs = { self, nixpkgs, nix-matrix-appservices }: {
+ # change `yourhostname` to your actual hostname
+ nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem {
+ # change to your system:
+ system = "x86_64-linux";
+ modules = [
+ ./configuration.nix
+ nix-matrix-appservices.nixosModule
+ ];
+ };
+ };
+}
+```
+Or if you use digga/devos or flake-utils-plus, you could pass the module
+to the `hostDefaults.modules` argument, which is under the `nixos` category in digga.
+
+### Without Flakes(legacy)
+In your `configuration.nix` or any other profile/module:
+```
+{ pkgs, ... }:
+let
+ nix-matrix-appservices = fetchTarball
+ "https://gitlab.com/coffeetables/nix-matrix-appservices/-/archive/master/myrdd-master.tar.gz";
+{
+ imports = [
+ "${nix-matrix-appservices}/module"
+ ];
+}
+```
+
+## TODO
+ - [ ] Generate docs for options
+ - [ ] Re-package matrix-appservices even ones in nixpkgs, so I can export packages
+ that I know work with the module
+ - [ ] Improve test to message the bot and check for a response to ensure registration was
+ done right
+ - [ ] Test more appservices(right now only discord is being tested)
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..d3d2487
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,77 @@
+{
+ "nodes": {
+ "devshell": {
+ "locked": {
+ "lastModified": 1642188268,
+ "narHash": "sha256-DNz4xScpXIn7rSDohdayBpPR9H9OWCMDOgTYegX081k=",
+ "owner": "numtide",
+ "repo": "devshell",
+ "rev": "696acc29668b644df1740b69e1601119bf6da83b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "devshell",
+ "type": "github"
+ }
+ },
+ "flake-utils": {
+ "locked": {
+ "lastModified": 1638122382,
+ "narHash": "sha256-sQzZzAbvKEqN9s0bzWuYmRaA03v40gaJ4+iL1LXjaeI=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "74f7e4319258e287b0f9cb95426c9853b282730b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "fup": {
+ "inputs": {
+ "flake-utils": "flake-utils"
+ },
+ "locked": {
+ "lastModified": 1638994888,
+ "narHash": "sha256-iz/ynGNZlvqKCOnFrEKqGA+BVKGQMG+g2JT+e3OOLN8=",
+ "owner": "divnix",
+ "repo": "flake-utils-plus",
+ "rev": "b4f9f517574cb7bd6ee3f19c72c19634c9f536e1",
+ "type": "github"
+ },
+ "original": {
+ "owner": "divnix",
+ "repo": "flake-utils-plus",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1642388384,
+ "narHash": "sha256-ooGGteIJHxB0wIC6Hnn2Yn+rPPQR5yxO8GNu74OZoO0=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "fc618794a5faac44e203b3a66002bd8d883019c4",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "release-21.11",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "devshell": "devshell",
+ "fup": "fup",
+ "nixpkgs": "nixpkgs"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..b7319cf
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,40 @@
+{
+ inputs = {
+ fup.url = "github:divnix/flake-utils-plus";
+ devshell.url = "github:numtide/devshell";
+ nixpkgs.url = "github:NixOS/nixpkgs/release-21.11";
+ };
+
+ outputs = inputs@{ self, nixpkgs, fup, devshell }:
+ fup.lib.mkFlake {
+ inherit self inputs;
+
+ supportedSystems = [ "aarch64-linux" "x86_64-linux" ];
+
+ nixosModules.matrix-appservices = import ./module;
+ nixosModule = self.nixosModules.matrix-appservices;
+
+ overlays.matrix-appservices = import ./pkgs;
+ overlay = self.overlays.matrix-appservices;
+
+ sharedOverlays = [
+ self.overlay
+ devshell.overlay
+ ];
+
+ channels.pkgs.input = nixpkgs;
+
+ outputsBuilder = { pkgs }: {
+ packages = {
+ inherit (pkgs)
+ mx-puppet-groupme
+ mx-puppet-slack
+
+ mautrix-twitter
+ mautrix-instagram
+ ;
+ };
+ checks.matrix-appservices = import ./test.nix { inherit pkgs; };
+ };
+ };
+}
diff --git a/module/as-formats.nix b/module/as-formats.nix
new file mode 100644
index 0000000..fa7a4cf
--- /dev/null
+++ b/module/as-formats.nix
@@ -0,0 +1,160 @@
+{ name, systemConfig, asConfig, lib, pkgs, ... }:
+
+with lib;
+let
+ inherit (systemConfig.services.matrix-appservices)
+ homeserverURL
+ homeserverDomain;
+ package = asConfig.package;
+ pname = getName package;
+ command = "${package}/bin/${pname}";
+
+ mautrix = {
+ startupScript = ''
+ ${command} --config=$SETTINGS_FILE \
+ --registration=$REGISTRATION_FILE
+ '';
+
+ settings = {
+ homeserver = {
+ address = homeserverURL;
+ domain = homeserverDomain;
+ };
+
+ appservice = with asConfig; {
+ address = "http://${host}:${toString port}";
+
+ hostname = host;
+ inherit port;
+
+ state_store_path = "$DIR/mx-state.json";
+ # mautrix stores the registration tokens in the config file
+ as_token = "$AS_TOKEN";
+ hs_token = "$HS_TOKEN";
+ };
+
+ bridge = {
+ username_template = "${name}_{userid}";
+ permissions = {
+ ${homeserverDomain} = "user";
+ };
+ };
+ };
+ };
+
+in
+{
+ other = {
+ description = ''
+ No defaults will be set.
+ '';
+ };
+
+ matrix-appservice = {
+ startupScript = ''
+ ${command} \
+ --config=$SETTINGS_FILE \
+ --port=$(echo ${asConfig.listenAddress} | sed 's/.*://') \
+ --file=$REGISTRATION_FILE
+ '';
+
+ description = ''
+ For bridges based on the matrix-appservice-bridge library. The settings for these
+ bridges are NOT configured automatically, because of the various differences
+ between them.
+ '';
+ };
+
+ mx-puppet = {
+ startupScript = ''
+ ${command} \
+ --config=$SETTINGS_FILE \
+ --registration-file=$REGISTRATION_FILE
+ '';
+
+ registrationData =
+ let
+ # mx-puppet virtual users are always created based on the package name
+ botName = removePrefix "mx-puppet-" pname;
+ in
+ {
+ id = "${botName}-puppet";
+ sender_localpart = "_${botName}puppet_bot";
+ protocols = [ ];
+ namespaces = {
+ rooms = [ ];
+ users = [
+ {
+ regex = "@_${botName}puppet_.*:${homeserverDomain}";
+ exclusive = true;
+ }
+ ];
+ aliases = [
+ {
+ regex = "#_${botName}puppet_.*:${homeserverDomain}";
+ exclusive = true;
+ }
+ ];
+ };
+ };
+
+ settings = {
+ bridge = {
+ inherit (asConfig) port;
+ bindAddress = asConfig.host;
+ domain = homeserverDomain;
+ homeserverUrl = homeserverURL;
+ };
+ database.filename = "$DIR/database.db";
+ provisioning.whitelist = [ "@.*:${homeserverDomain}" ];
+ relay.whitelist = [ "@.*:${homeserverDomain}" ];
+ selfService.whitelist = [ "@.*:${homeserverDomain}" ];
+ logging = {
+ lineDateFormat = "";
+ files = [ ];
+ };
+ };
+
+ serviceConfig.WorkingDirectory =
+ "${package}/lib/node_modules/${pname}";
+
+ description = ''
+ For bridges based on the mx-puppet-bridge library. The settings will be
+ configured to use a sqlite database. Make sure to override database.filename,
+ if you plan to use another database.
+ '';
+
+ };
+
+ mautrix-go = {
+ inherit (mautrix) startupScript;
+
+ settings = recursiveUpdate mautrix.settings {
+ bridge.username_template = "${name}_{{.}}";
+ appservice.database = {
+ type = "sqlite3";
+ uri = "$DIR/database.db";
+ };
+ };
+
+ description = ''
+ The settings are configured to use a sqlite database. The startupScript will
+ create a new config file on every run to set the tokens, because mautrix
+ requires them to be in the config file.
+ '';
+ };
+
+ mautrix-python = {
+ settings = recursiveUpdate mautrix.settings {
+ appservice.database = "sqlite:///$DIR/database.db";
+ };
+
+ startupScript = optionalString (package ? alembic)
+ "${package.alembic}/bin/alembic -x config=$SETTINGS_FILE upgrade head\n"
+ + mautrix.startupScript;
+ description = ''
+ Same properties as mautrix-go. This will also upgrade the database on every run
+ '';
+ };
+
+}
diff --git a/module/as-options.nix b/module/as-options.nix
new file mode 100644
index 0000000..2afbbbf
--- /dev/null
+++ b/module/as-options.nix
@@ -0,0 +1,144 @@
+{ systemConfig, lib, pkgs, ... }:
+with lib;
+types.submodule ({ config, name, ... }:
+ let
+ inherit (systemConfig.services.matrix-appservices)
+ homeserverDomain;
+
+ asFormats = (import ./as-formats.nix) {
+ inherit name lib pkgs systemConfig;
+ asConfig = config;
+ };
+ asFormat = asFormats.${config.format};
+ settingsFormat = pkgs.formats.json { };
+ in
+ {
+ options = rec {
+
+ format = mkOption {
+ type = types.enum (mapAttrsToList (n: _: n) asFormats);
+ default = "other";
+ description = ''
+ Format of the appservice, used to set option defaults for appservice.
+ This is usually determined by the library the appservice is based on.
+
+ Below are descriptions for each format
+
+ '' + (concatStringsSep "\n" (mapAttrsToList
+ (n: v: "${n}: ${v.description}")
+ asFormats));
+ };
+
+ package = mkOption {
+ type = types.nullOr types.package;
+ default = null;
+ example = "pkgs.mautrix-whatsapp";
+ description = ''
+ The package for the appservice. Used by formats except 'other'.
+ This is unecessary if startupScript is set.
+ '';
+ };
+
+ settings = mkOption rec {
+ type = settingsFormat.type;
+ apply = recursiveUpdate default;
+ default = asFormat.settings or { };
+ defaultText = "Format will attempt to configure database and allow homeserver users";
+ example = literalExpression ''
+ {
+ bridge = {
+ domain = "public-domain.tld";
+ homeserverUrl = "http://public-domain.tld:8008";
+ };
+ }
+ '';
+ description = ''
+ Appservice configuration as a Nix attribute set.
+ All environment variables will be substituted.
+ Including:
+ - $DIR which refers to the appservice's data directory.
+ - $AS_TOKEN, $HS_TOKEN which refers to the Appservice and
+ Homeserver registration tokens.
+
+ Secret tokens, should be specified in serviceConfig.EnvironmentFile
+ instead of this world-readable attribute set.
+
+ Configuration options should match those described as per your appservice's settings
+ Check out the confg sample for this.
+
+ '';
+ };
+
+ registrationData = mkOption {
+ type = settingsFormat.type;
+ default = asFormat.registrationData or {
+ namespaces = {
+ users = [
+ {
+ regex = "@${name}_.*:${homeserverDomain}";
+ exclusive = true;
+ }
+ {
+ regex = "@${name}bot:${homeserverDomain}";
+ exclusive = true;
+ }
+ ];
+ };
+ };
+ defaultText = ''
+ Reserve usernames under the homeserver that start with
+ this appservice's name followed by an _ or "bot"
+ '';
+ description = ''
+ Data to set in the registration file for the appservice. The default
+ set or the format should usually deal with this.
+ '';
+ };
+
+ host = mkOption {
+ type = types.str;
+ default = "localhost";
+ description = ''
+ The host the appservice will listen on.
+ Will need to specified in config, but most formats will do it for you using
+ this option.
+ '';
+ };
+
+ port = mkOption {
+ type = types.port;
+ description = ''
+ The port the appservice will listen on.
+ Will need to specified in config, but most formats will do it for you using
+ this option.
+ '';
+ };
+
+ startupScript = mkOption {
+ type = types.str;
+ default = asFormat.startupScript or "";
+ description = ''
+ Script that starts the appservice.
+ The settings file will be available as $SETTINGS_FILE
+ and the registration file as $REGISTRATION_FILE
+ '';
+ };
+
+ serviceConfig = mkOption rec {
+ type = types.attrs;
+ apply = x: default // x;
+ default = asFormat.serviceConfig or { };
+ description = ''
+ Overrides for settings in the service's serviceConfig
+ '';
+ };
+
+ serviceDependencies = mkOption {
+ type = types.listOf types.str;
+ default = [ ];
+ description = ''
+ Services started before this appservice
+ '';
+ };
+ };
+ })
diff --git a/module/default.nix b/module/default.nix
new file mode 100644
index 0000000..a368365
--- /dev/null
+++ b/module/default.nix
@@ -0,0 +1,182 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+ cfg = config.services.matrix-appservices;
+ asOpts = import ./as-options.nix {
+ inherit lib pkgs;
+ systemConfig = config;
+ };
+ mkService = name: opts:
+ with opts;
+ let
+ settingsFormat = pkgs.formats.json { };
+ dataDir = "/var/lib/matrix-as-${name}";
+ registrationFile = "${dataDir}/${name}-registration.yaml";
+ # Replace all references to $DIR to the dat directory
+ settingsData = settingsFormat.generate "config.json" settings;
+ settingsFile = "${dataDir}/config.json";
+ serviceDeps = [ "network-online.target" ] ++ serviceDependencies;
+
+ registrationContent = {
+ id = name;
+ url = "http://${host}:${toString port}";
+ as_token = "$AS_TOKEN";
+ hs_token = "$HS_TOKEN";
+ sender_localpart = "$SENDER_LOCALPART";
+ rate_limited = false;
+ } // registrationData;
+ in
+ {
+ description = "A matrix appservice for ${name}.";
+
+ wantedBy = [ "multi-user.target" ];
+ wants = serviceDeps;
+ after = serviceDeps;
+ # Appservices don't need synapse up, but synapse exists if registration files are missing
+ before = mkIf (cfg.homeserver != null) [ "${cfg.homeserver}.service" ];
+
+ path = [ pkgs.yq ];
+ environment = {
+ DIR = dataDir;
+ SETTINGS_FILE = settingsFile;
+ REGISTRATION_FILE = registrationFile;
+ };
+
+ preStart = ''
+ if [ ! -f ${registrationFile} ]; then
+ AS_TOKEN=$(cat /proc/sys/kernel/random/uuid) \
+ HS_TOKEN=$(cat /proc/sys/kernel/random/uuid) \
+ SENDER_LOCALPART=$(cat /proc/sys/kernel/random/uuid) \
+ ${pkgs.envsubst}/bin/envsubst \
+ -i ${settingsFormat.generate "config.json" registrationContent} \
+ -o ${registrationFile}
+
+ chmod 640 ${registrationFile}
+ fi
+
+ AS_TOKEN=$(cat ${registrationFile} | yq .as_token | tr -d '"') \
+ HS_TOKEN=$(cat ${registrationFile} | yq .hs_token | tr -d '"') \
+ ${pkgs.envsubst}/bin/envsubst -i ${settingsData} -o ${settingsFile}
+ chmod 640 ${settingsFile}
+ '';
+
+ script = ''
+ ${startupScript}
+ '';
+
+ serviceConfig = {
+ Type = "simple";
+ Restart = "always";
+
+ ProtectSystem = "strict";
+ PrivateTmp = true;
+ ProtectHome = true;
+ ProtectKernelTunables = true;
+ ProtectKernelModules = true;
+ ProtectControlGroups = true;
+
+ User = "matrix-as-${name}";
+ Group = "matrix-as-${name}";
+ WorkingDirectory = dataDir;
+ StateDirectory = "${baseNameOf dataDir}";
+ StateDirectoryMode = "0750";
+ UMask = 0027;
+ } // opts.serviceConfig;
+ };
+
+in
+{
+ options = {
+ services.matrix-appservices = {
+ services = mkOption {
+ type = types.attrsOf asOpts;
+ default = { };
+ example = literalExpression ''
+ whatsapp = {
+ format = "mautrix-go";
+ package = pkgs.mautrix-whatsapp;
+ };
+ '';
+ description = ''
+ Appservices to setup.
+ Each appservice will be started as a systemd service with the prefix matrix-as.
+ And its data will be stored in /var/lib/matrix-as-name.
+ '';
+ };
+
+ homeserver = mkOption {
+ type = types.enum [ "matrix-synapse" "dendrite" null ];
+ default = "matrix-synapse";
+ description = ''
+ The homeserver software the appservices connect to. This will ensure appservices
+ start after the homeserver and it will be used by the addRegistrationFiles option.
+ '';
+ };
+
+ homeserverURL = mkOption {
+ type = types.str;
+ default = "https://${cfg.homeserverDomain}";
+ description = ''
+ URL of the homeserver the apservices connect to
+ '';
+ };
+
+ homeserverDomain = mkOption {
+ type = types.str;
+ default = if config.networking.domain != null then config.networking.domain else "";
+ defaultText = "\${config.networking.domain}";
+ description = ''
+ Domain of the homeserver the appservices connect to
+ '';
+ };
+
+ addRegistrationFiles = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to add the application service registration files to the homeserver configuration.
+ It is recommended to verify appservice files, located in /var/lib/matrix-as-*, before adding them
+ '';
+ };
+ };
+ };
+
+ config = mkIf (cfg.services != { }) {
+
+ assertions = mapAttrsToList
+ (n: v: {
+ assertion = v.format == "other" || v.package != null;
+ message = "A package must be provided if a custom format is set";
+ })
+ cfg.services;
+
+ users.users = mapAttrs'
+ (n: v: nameValuePair "matrix-as-${n}" {
+ group = "matrix-as-${n}";
+ isSystemUser = true;
+ })
+ cfg.services;
+ users.groups = mapAttrs' (n: v: nameValuePair "matrix-as-${n}" { }) cfg.services;
+
+ # Create a service for each appservice
+ systemd.services = (mapAttrs' (n: v: nameValuePair "matrix-as-${n}" (mkService n v)) cfg.services) // {
+ # Add the matrix service to the groups of all appservices to give access to the registration file
+ matrix-synapse.serviceConfig.SupplementaryGroups = mapAttrsToList (n: v: "matrix-as-${n}") cfg.services;
+ dendrite.serviceConfig.SupplementaryGroups = mapAttrsToList (n: v: "matrix-as-${n}") cfg.services;
+ };
+
+ services =
+ let
+ registrationFiles = mapAttrsToList (n: _: "/var/lib/matrix-as-${n}/${n}-registration.yaml")
+ (filterAttrs (_: v: v.registrationData != { }) cfg.services);
+ in
+ mkIf cfg.addRegistrationFiles {
+ matrix-synapse.app_service_config_files = mkIf (cfg.homeserver == "matrix-synapse") registrationFiles;
+ dendrite.settings.app_service_api.config_files = mkIf (cfg.homeserver == "dendrite") registrationFiles;
+ };
+ };
+
+ meta.maintainers = with maintainers; [ pacman99 Flakebi ];
+
+}
diff --git a/pkgs/default.nix b/pkgs/default.nix
new file mode 100644
index 0000000..7589f50
--- /dev/null
+++ b/pkgs/default.nix
@@ -0,0 +1,10 @@
+final: prev: {
+ mx-puppet-groupme = prev.callPackage ./mx-puppet-groupme { };
+ mx-puppet-slack = prev.callPackage ./mx-puppet-slack { };
+
+ mautrix-twitter = prev.callPackage ./mautrix-twitter { };
+ mautrix-instagram = prev.callPackage ./mautrix-instagram { };
+ mautrix-wsproxy = prev.callPackage ./mautrix-wsproxy { };
+
+ matrix-emailbridge = prev.callPackage ./matrix-emailbridge { };
+}
diff --git a/pkgs/mautrix-instagram/default.nix b/pkgs/mautrix-instagram/default.nix
new file mode 100644
index 0000000..14cb1c6
--- /dev/null
+++ b/pkgs/mautrix-instagram/default.nix
@@ -0,0 +1,77 @@
+{ stdenv
+, lib
+, python3
+, makeWrapper
+, fetchFromGitHub
+}:
+
+with python3.pkgs;
+
+let
+ # officially supported database drivers
+ dbDrivers = [
+ asyncpg
+ # sqlite driver is already shipped with python by default
+ ];
+
+in
+
+buildPythonApplication rec {
+ pname = "mautrix-instagram";
+ version = "unstable-2021-11-15";
+
+ src = fetchFromGitHub {
+ owner = "tulir";
+ repo = pname;
+ rev = "13b6b157b6eaff5c34506a458aa761362aad8c64";
+ sha256 = "1xkjcmh31pzli3dck2glg0a64x59n4x05zjmg2v65rcfz8snb1mw";
+ };
+
+ postPatch = ''
+ sed -i -e '/alembic>/d' requirements.txt
+ '';
+ postFixup = ''
+ makeWrapper ${python}/bin/python $out/bin/mautrix-instagram \
+ --add-flags "-m mautrix_instagram" \
+ --prefix PYTHONPATH : "$(toPythonPath ${mautrix}):$(toPythonPath $out):$PYTHONPATH"
+ '';
+
+ propagatedBuildInputs = [
+ mautrix
+ yarl
+ aiohttp
+ aiosqlite
+ beautifulsoup4
+ sqlalchemy
+ CommonMark
+ ruamel_yaml
+ paho-mqtt
+ python_magic
+ attrs
+ pillow
+ qrcode
+ phonenumbers
+ pycryptodome
+ python-olm
+ unpaddedbase64
+ setuptools
+ ] ++ dbDrivers;
+
+ checkInputs = [
+ pytest
+ pytestrunner
+ pytest-mock
+ pytest-asyncio
+ ];
+
+ doCheck = false;
+
+ meta = with lib; {
+ homepage = "https://github.com/tulir/mautrix-instagram";
+ description = "A Matrix-Instagram DM puppeting bridge";
+ license = licenses.agpl3Plus;
+ platforms = platforms.linux;
+ };
+
+}
+
diff --git a/pkgs/mautrix-twitter/default.nix b/pkgs/mautrix-twitter/default.nix
new file mode 100644
index 0000000..be5385a
--- /dev/null
+++ b/pkgs/mautrix-twitter/default.nix
@@ -0,0 +1,77 @@
+{ stdenv
+, lib
+, python3
+, makeWrapper
+, fetchFromGitHub
+}:
+
+with python3.pkgs;
+
+let
+ # officially supported database drivers
+ dbDrivers = [
+ asyncpg
+ # sqlite driver is already shipped with python by default
+ ];
+
+in
+
+buildPythonApplication rec {
+ pname = "mautrix-twitter";
+ version = "unstable-2021-11-12";
+
+ src = fetchFromGitHub {
+ owner = "mautrix";
+ repo = "twitter";
+ rev = "deae0e10e6e376be2a0d02edcdc70965b46f05a7";
+ sha256 = "sha256-tATiqZlOIi+w6GTBdssv6+pvyHacZh+bDVH5kOrr0Js=";
+ };
+
+ postPatch = ''
+ sed -i -e '/alembic>/d' requirements.txt
+ '';
+ postFixup = ''
+ makeWrapper ${python}/bin/python $out/bin/mautrix-twitter \
+ --add-flags "-m mautrix_twitter" \
+ --prefix PYTHONPATH : "$(toPythonPath ${mautrix}):$(toPythonPath $out):$PYTHONPATH"
+ '';
+
+ propagatedBuildInputs = [
+ mautrix
+ yarl
+ aiohttp
+ aiosqlite
+ beautifulsoup4
+ sqlalchemy
+ CommonMark
+ ruamel_yaml
+ paho-mqtt
+ python_magic
+ attrs
+ pillow
+ qrcode
+ phonenumbers
+ pycryptodome
+ python-olm
+ unpaddedbase64
+ setuptools
+ ] ++ dbDrivers;
+
+ checkInputs = [
+ pytest
+ pytestrunner
+ pytest-mock
+ pytest-asyncio
+ ];
+
+ doCheck = false;
+
+ meta = with lib; {
+ homepage = "https://github.com/tulir/mautrix-twitter";
+ description = "A Matrix-Twitter DM puppeting bridge";
+ license = licenses.agpl3Plus;
+ platforms = platforms.linux;
+ };
+
+}
+
diff --git a/pkgs/mautrix-wsproxy/default.nix b/pkgs/mautrix-wsproxy/default.nix
new file mode 100644
index 0000000..fb5d7d9
--- /dev/null
+++ b/pkgs/mautrix-wsproxy/default.nix
@@ -0,0 +1,34 @@
+{ lib, buildGoModule, fetchFromGitHub, olm }:
+
+buildGoModule rec {
+ pname = "mautrix-wsproxy-bin";
+ version = "unstable-2021-09-07";
+
+ src = fetchFromGitHub {
+ owner = "mautrix";
+ repo = "wsproxy";
+ rev = "2f097e3f2b6d003b3c913933839f12a8cd9d2d41";
+ sha256 = "0sy7ns60nzq58j500cswvj04q75ji18cnn01bacdrqwnklmh2g24";
+ };
+
+ buildInputs = [ olm ];
+
+ vendorSha256 = "sha256-kJw3w14RQBAdMoFItjT/LmzuKaDTR09mW3H+7gNUS3s=";
+