forked from mirrors/nixpkgs
Merge pull request #113988 from piegamesde/matrix-appservice-irc
This commit is contained in:
commit
b2ebc881cf
|
@ -7485,6 +7485,12 @@
|
|||
githubId = 627831;
|
||||
name = "Hoang Xuan Phu";
|
||||
};
|
||||
piegames = {
|
||||
name = "piegames";
|
||||
email = "nix@piegames.de";
|
||||
github = "piegamesde";
|
||||
githubId = 14054505;
|
||||
};
|
||||
pierrechevalier83 = {
|
||||
email = "pierrechevalier83@gmail.com";
|
||||
github = "pierrechevalier83";
|
||||
|
|
|
@ -499,6 +499,7 @@
|
|||
./services/misc/lifecycled.nix
|
||||
./services/misc/mame.nix
|
||||
./services/misc/matrix-appservice-discord.nix
|
||||
./services/misc/matrix-appservice-irc.nix
|
||||
./services/misc/matrix-synapse.nix
|
||||
./services/misc/mautrix-telegram.nix
|
||||
./services/misc/mbpfan.nix
|
||||
|
|
228
nixos/modules/services/misc/matrix-appservice-irc.nix
Normal file
228
nixos/modules/services/misc/matrix-appservice-irc.nix
Normal file
|
@ -0,0 +1,228 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.matrix-appservice-irc;
|
||||
|
||||
pkg = pkgs.matrix-appservice-irc;
|
||||
bin = "${pkg}/bin/matrix-appservice-irc";
|
||||
|
||||
jsonType = (pkgs.formats.json {}).type;
|
||||
|
||||
configFile = pkgs.runCommandNoCC "matrix-appservice-irc.yml" {
|
||||
# Because this program will be run at build time, we need `nativeBuildInputs`
|
||||
nativeBuildInputs = [ (pkgs.python3.withPackages (ps: [ ps.pyyaml ps.jsonschema ])) ];
|
||||
preferLocalBuild = true;
|
||||
|
||||
config = builtins.toJSON cfg.settings;
|
||||
passAsFile = [ "config" ];
|
||||
} ''
|
||||
# The schema is given as yaml, we need to convert it to json
|
||||
python -c 'import json; import yaml; import sys; json.dump(yaml.safe_load(sys.stdin), sys.stdout)' \
|
||||
< ${pkg}/lib/node_modules/matrix-appservice-irc/config.schema.yml \
|
||||
> config.schema.json
|
||||
python -m jsonschema config.schema.json -i $configPath
|
||||
cp "$configPath" "$out"
|
||||
'';
|
||||
registrationFile = "/var/lib/matrix-appservice-irc/registration.yml";
|
||||
in {
|
||||
options.services.matrix-appservice-irc = with types; {
|
||||
enable = mkEnableOption "the Matrix/IRC bridge";
|
||||
|
||||
port = mkOption {
|
||||
type = port;
|
||||
description = "The port to listen on";
|
||||
default = 8009;
|
||||
};
|
||||
|
||||
needBindingCap = mkOption {
|
||||
type = bool;
|
||||
description = "Whether the daemon needs to bind to ports below 1024 (e.g. for the ident service)";
|
||||
default = false;
|
||||
};
|
||||
|
||||
passwordEncryptionKeyLength = mkOption {
|
||||
type = ints.unsigned;
|
||||
description = "Length of the key to encrypt IRC passwords with";
|
||||
default = 4096;
|
||||
example = 8192;
|
||||
};
|
||||
|
||||
registrationUrl = mkOption {
|
||||
type = str;
|
||||
description = ''
|
||||
The URL where the application service is listening for homeserver requests,
|
||||
from the Matrix homeserver perspective.
|
||||
'';
|
||||
example = "http://localhost:8009";
|
||||
};
|
||||
|
||||
localpart = mkOption {
|
||||
type = str;
|
||||
description = "The user_id localpart to assign to the appservice";
|
||||
default = "appservice-irc";
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
description = ''
|
||||
Configuration for the appservice, see
|
||||
<link xlink:href="https://github.com/matrix-org/matrix-appservice-irc/blob/${pkgs.matrix-appservice-irc.version}/config.sample.yaml"/>
|
||||
for supported values
|
||||
'';
|
||||
default = {};
|
||||
type = submodule {
|
||||
freeformType = jsonType;
|
||||
|
||||
options = {
|
||||
homeserver = mkOption {
|
||||
description = "Homeserver configuration";
|
||||
default = {};
|
||||
type = submodule {
|
||||
freeformType = jsonType;
|
||||
|
||||
options = {
|
||||
url = mkOption {
|
||||
type = str;
|
||||
description = "The URL to the home server for client-server API calls";
|
||||
};
|
||||
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
description = ''
|
||||
The 'domain' part for user IDs on this home server. Usually
|
||||
(but not always) is the "domain name" part of the homeserver URL.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
database = mkOption {
|
||||
default = {};
|
||||
description = "Configuration for the database";
|
||||
type = submodule {
|
||||
freeformType = jsonType;
|
||||
|
||||
options = {
|
||||
engine = mkOption {
|
||||
type = str;
|
||||
description = "Which database engine to use";
|
||||
default = "nedb";
|
||||
example = "postgres";
|
||||
};
|
||||
|
||||
connectionString = mkOption {
|
||||
type = str;
|
||||
description = "The database connection string";
|
||||
default = "nedb://var/lib/matrix-appservice-irc/data";
|
||||
example = "postgres://username:password@host:port/databasename";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ircService = mkOption {
|
||||
default = {};
|
||||
description = "IRC bridge configuration";
|
||||
type = submodule {
|
||||
freeformType = jsonType;
|
||||
|
||||
options = {
|
||||
passwordEncryptionKeyPath = mkOption {
|
||||
type = str;
|
||||
description = ''
|
||||
Location of the key with which IRC passwords are encrypted
|
||||
for storage. Will be generated on first run if not present.
|
||||
'';
|
||||
default = "/var/lib/matrix-appservice-irc/passkey.pem";
|
||||
};
|
||||
|
||||
servers = mkOption {
|
||||
type = submodule { freeformType = jsonType; };
|
||||
description = "IRC servers to connect to";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.matrix-appservice-irc = {
|
||||
description = "Matrix-IRC bridge";
|
||||
before = [ "matrix-synapse.service" ]; # So the registration can be used by Synapse
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
preStart = ''
|
||||
umask 077
|
||||
# Generate key for crypting passwords
|
||||
if ! [ -f "${cfg.settings.ircService.passwordEncryptionKeyPath}" ]; then
|
||||
${pkgs.openssl}/bin/openssl genpkey \
|
||||
-out "${cfg.settings.ircService.passwordEncryptionKeyPath}" \
|
||||
-outform PEM \
|
||||
-algorithm RSA \
|
||||
-pkeyopt "rsa_keygen_bits:${toString cfg.passwordEncryptionKeyLength}"
|
||||
fi
|
||||
# Generate registration file
|
||||
if ! [ -f "${registrationFile}" ]; then
|
||||
# The easy case: the file has not been generated yet
|
||||
${bin} --generate-registration --file ${registrationFile} --config ${configFile} --url ${cfg.registrationUrl} --localpart ${cfg.localpart}
|
||||
else
|
||||
# The tricky case: we already have a generation file. Because the NixOS configuration might have changed, we need to
|
||||
# regenerate it. But this would give the service a new random ID and tokens, so we need to back up and restore them.
|
||||
# 1. Backup
|
||||
id=$(grep "^id:.*$" ${registrationFile})
|
||||
hs_token=$(grep "^hs_token:.*$" ${registrationFile})
|
||||
as_token=$(grep "^as_token:.*$" ${registrationFile})
|
||||
# 2. Regenerate
|
||||
${bin} --generate-registration --file ${registrationFile} --config ${configFile} --url ${cfg.registrationUrl} --localpart ${cfg.localpart}
|
||||
# 3. Restore
|
||||
sed -i "s/^id:.*$/$id/g" ${registrationFile}
|
||||
sed -i "s/^hs_token:.*$/$hs_token/g" ${registrationFile}
|
||||
sed -i "s/^as_token:.*$/$as_token/g" ${registrationFile}
|
||||
fi
|
||||
# Allow synapse access to the registration
|
||||
if ${getBin pkgs.glibc}/bin/getent group matrix-synapse > /dev/null; then
|
||||
chgrp matrix-synapse ${registrationFile}
|
||||
chmod g+r ${registrationFile}
|
||||
fi
|
||||
'';
|
||||
|
||||
serviceConfig = rec {
|
||||
Type = "simple";
|
||||
ExecStart = "${bin} --config ${configFile} --file ${registrationFile} --port ${toString cfg.port}";
|
||||
|
||||
ProtectHome = true;
|
||||
PrivateDevices = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectControlGroups = true;
|
||||
StateDirectory = "matrix-appservice-irc";
|
||||
StateDirectoryMode = "755";
|
||||
|
||||
User = "matrix-appservice-irc";
|
||||
Group = "matrix-appservice-irc";
|
||||
|
||||
CapabilityBoundingSet = [ "CAP_CHOWN" ] ++ optional (cfg.needBindingCap) "CAP_NET_BIND_SERVICE";
|
||||
AmbientCapabilities = CapabilityBoundingSet;
|
||||
NoNewPrivileges = true;
|
||||
|
||||
LockPersonality = true;
|
||||
RestrictRealtime = true;
|
||||
PrivateMounts = true;
|
||||
SystemCallFilter = "~@aio @clock @cpu-emulation @debug @keyring @memlock @module @mount @obsolete @raw-io @setuid @swap";
|
||||
SystemCallArchitectures = "native";
|
||||
RestrictAddressFamilies = "AF_INET AF_INET6";
|
||||
};
|
||||
};
|
||||
|
||||
users.groups.matrix-appservice-irc = {};
|
||||
users.users.matrix-appservice-irc = {
|
||||
description = "Service user for the Matrix-IRC bridge";
|
||||
group = "matrix-appservice-irc";
|
||||
isSystemUser = true;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -227,6 +227,7 @@ in
|
|||
mariadb-galera-mariabackup = handleTest ./mysql/mariadb-galera-mariabackup.nix {};
|
||||
mariadb-galera-rsync = handleTest ./mysql/mariadb-galera-rsync.nix {};
|
||||
matomo = handleTest ./matomo.nix {};
|
||||
matrix-appservice-irc = handleTest ./matrix-appservice-irc.nix {};
|
||||
matrix-synapse = handleTest ./matrix-synapse.nix {};
|
||||
mediawiki = handleTest ./mediawiki.nix {};
|
||||
memcached = handleTest ./memcached.nix {};
|
||||
|
|
162
nixos/tests/matrix-appservice-irc.nix
Normal file
162
nixos/tests/matrix-appservice-irc.nix
Normal file
|
@ -0,0 +1,162 @@
|
|||
import ./make-test-python.nix ({ pkgs, ... }:
|
||||
let
|
||||
homeserverUrl = "http://homeserver:8448";
|
||||
in
|
||||
{
|
||||
name = "matrix-appservice-irc";
|
||||
meta = {
|
||||
maintainers = pkgs.matrix-appservice-irc.meta.maintainers;
|
||||
};
|
||||
|
||||
nodes = {
|
||||
homeserver = { pkgs, ... }: {
|
||||
# We'll switch to this once the config is copied into place
|
||||
specialisation.running.configuration = {
|
||||
services.matrix-synapse = {
|
||||
enable = true;
|
||||
database_type = "sqlite3";
|
||||
app_service_config_files = [ "/registration.yml" ];
|
||||
|
||||
enable_registration = true;
|
||||
|
||||
listeners = [
|
||||
# The default but tls=false
|
||||
{
|
||||
"bind_address" = "";
|
||||
"port" = 8448;
|
||||
"resources" = [
|
||||
{ "compress" = true; "names" = [ "client" "webclient" ]; }
|
||||
{ "compress" = false; "names" = [ "federation" ]; }
|
||||
];
|
||||
"tls" = false;
|
||||
"type" = "http";
|
||||
"x_forwarded" = false;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 8448 ];
|
||||
};
|
||||
};
|
||||
|
||||
ircd = { pkgs, ... }: {
|
||||
services.ngircd = {
|
||||
enable = true;
|
||||
config = ''
|
||||
[Global]
|
||||
Name = ircd.ircd
|
||||
Info = Server Info Text
|
||||
AdminInfo1 = _
|
||||
|
||||
[Channel]
|
||||
Name = #test
|
||||
Topic = a cool place
|
||||
|
||||
[Options]
|
||||
PAM = no
|
||||
'';
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [ 6667 ];
|
||||
};
|
||||
|
||||
appservice = { pkgs, ... }: {
|
||||
services.matrix-appservice-irc = {
|
||||
enable = true;
|
||||
registrationUrl = "http://appservice:8009";
|
||||
|
||||
settings = {
|
||||
homeserver.url = homeserverUrl;
|
||||
homeserver.domain = "homeserver";
|
||||
|
||||
ircService.servers."ircd" = {
|
||||
name = "IRCd";
|
||||
port = 6667;
|
||||
dynamicChannels = {
|
||||
enabled = true;
|
||||
aliasTemplate = "#irc_$CHANNEL";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 8009 ];
|
||||
};
|
||||
|
||||
client = { pkgs, ... }: {
|
||||
environment.systemPackages = [
|
||||
(pkgs.writers.writePython3Bin "do_test"
|
||||
{ libraries = [ pkgs.python3Packages.matrix-client ]; } ''
|
||||
import socket
|
||||
from matrix_client.client import MatrixClient
|
||||
from time import sleep
|
||||
|
||||
matrix = MatrixClient("${homeserverUrl}")
|
||||
matrix.register_with_password(username="alice", password="foobar")
|
||||
|
||||
irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
irc.connect(("ircd", 6667))
|
||||
irc.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
irc.send(b"USER bob bob bob :bob\n")
|
||||
irc.send(b"NICK bob\n")
|
||||
|
||||
m_room = matrix.join_room("#irc_#test:homeserver")
|
||||
irc.send(b"JOIN #test\n")
|
||||
|
||||
# plenty of time for the joins to happen
|
||||
sleep(10)
|
||||
|
||||
m_room.send_text("hi from matrix")
|
||||
irc.send(b"PRIVMSG #test :hi from irc \r\n")
|
||||
|
||||
print("Waiting for irc message...")
|
||||
while True:
|
||||
buf = irc.recv(10000)
|
||||
if b"hi from matrix" in buf:
|
||||
break
|
||||
|
||||
print("Waiting for matrix message...")
|
||||
|
||||
|
||||
def callback(room, e):
|
||||
if "hi from irc" in e['content']['body']:
|
||||
exit(0)
|
||||
|
||||
|
||||
m_room.add_listener(callback, "m.room.message")
|
||||
matrix.listen_forever()
|
||||
''
|
||||
)
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
ircd.wait_for_unit("ngircd.service")
|
||||
ircd.wait_for_open_port(6667)
|
||||
|
||||
with subtest("start the appservice"):
|
||||
appservice.wait_for_unit("matrix-appservice-irc.service")
|
||||
appservice.wait_for_open_port(8009)
|
||||
|
||||
with subtest("copy the registration file"):
|
||||
appservice.copy_from_vm("/var/lib/matrix-appservice-irc/registration.yml")
|
||||
homeserver.copy_from_host(
|
||||
pathlib.Path(os.environ.get("out", os.getcwd())) / "registration.yml", "/"
|
||||
)
|
||||
homeserver.succeed("chmod 444 /registration.yml")
|
||||
|
||||
with subtest("start the homeserver"):
|
||||
homeserver.succeed(
|
||||
"/run/current-system/specialisation/running/bin/switch-to-configuration test >&2"
|
||||
)
|
||||
|
||||
homeserver.wait_for_unit("matrix-synapse.service")
|
||||
homeserver.wait_for_open_port(8448)
|
||||
|
||||
with subtest("ensure messages can be exchanged"):
|
||||
client.succeed("do_test")
|
||||
'';
|
||||
|
||||
})
|
|
@ -0,0 +1,28 @@
|
|||
{ pkgs, nodePackages, makeWrapper, nixosTests, nodejs, stdenv, lib, ... }:
|
||||
|
||||
let
|
||||
|
||||
packageName = with lib; concatStrings (map (entry: (concatStrings (mapAttrsToList (key: value: "${key}-${value}") entry))) (importJSON ./package.json));
|
||||
|
||||
ourNodePackages = import ./node-composition.nix {
|
||||
inherit pkgs nodejs;
|
||||
inherit (stdenv.hostPlatform) system;
|
||||
};
|
||||
in
|
||||
ourNodePackages."${packageName}".override {
|
||||
nativeBuildInputs = [ makeWrapper nodePackages.node-gyp-build ];
|
||||
|
||||
postInstall = ''
|
||||
makeWrapper '${nodejs}/bin/node' "$out/bin/matrix-appservice-irc" \
|
||||
--add-flags "$out/lib/node_modules/matrix-appservice-irc/app.js"
|
||||
'';
|
||||
|
||||
passthru.tests.matrix-appservice-irc = nixosTests.matrix-appservice-irc;
|
||||
|
||||
meta = with lib; {
|
||||
description = "Node.js IRC bridge for Matrix";
|
||||
maintainers = with maintainers; [ piegames ];
|
||||
homepage = "https://github.com/matrix-org/matrix-appservice-irc";
|
||||
license = licenses.asl20;
|
||||
};
|
||||
}
|
11
pkgs/servers/matrix-synapse/matrix-appservice-irc/generate-dependencies.sh
Executable file
11
pkgs/servers/matrix-synapse/matrix-appservice-irc/generate-dependencies.sh
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
ROOT="$(realpath "$(dirname -- "$(readlink -f -- "${BASH_SOURCE[0]}")")"/../../../..)"
|
||||
|
||||
$(nix-build $ROOT -A nodePackages.node2nix --no-out-link)/bin/node2nix \
|
||||
--nodejs-12 \
|
||||
--node-env ../../../development/node-packages/node-env.nix \
|
||||
--development \
|
||||
--input package.json \
|
||||
--output node-packages.nix \
|
||||
--composition node-composition.nix
|
|
@ -0,0 +1,17 @@
|
|||
# This file has been generated by node2nix 1.9.0. Do not edit!
|
||||
|
||||
{pkgs ? import <nixpkgs> {
|
||||
inherit system;
|
||||
}, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-12_x"}:
|
||||
|
||||
let
|
||||
nodeEnv = import ../../../development/node-packages/node-env.nix {
|
||||
inherit (pkgs) stdenv lib python2 runCommand writeTextFile;
|
||||
inherit pkgs nodejs;
|
||||
libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null;
|
||||
};
|
||||
in
|
||||
import ./node-packages.nix {
|
||||
inherit (pkgs) fetchurl nix-gitignore stdenv lib fetchgit;
|
||||
inherit nodeEnv;
|
||||
}
|
5165
pkgs/servers/matrix-synapse/matrix-appservice-irc/node-packages.nix
generated
Normal file
5165
pkgs/servers/matrix-synapse/matrix-appservice-irc/node-packages.nix
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,3 @@
|
|||
[
|
||||
{"matrix-appservice-irc": "git+https://github.com/matrix-org/matrix-appservice-irc.git#0.25.0" }
|
||||
]
|
|
@ -5933,6 +5933,8 @@ in
|
|||
|
||||
matrix-synapse-tools = recurseIntoAttrs matrix-synapse.tools;
|
||||
|
||||
matrix-appservice-irc = callPackage ../servers/matrix-synapse/matrix-appservice-irc { };
|
||||
|
||||
matrix-appservice-slack = callPackage ../servers/matrix-synapse/matrix-appservice-slack {};
|
||||
|
||||
matrix-appservice-discord = callPackage ../servers/matrix-appservice-discord { };
|
||||
|
|
Loading…
Reference in a new issue