holy moly we're almost there

This commit is contained in:
Anish Lakhwara
2022-09-19 08:13:50 +10:00
commit 3693732aac
203 changed files with 17247 additions and 0 deletions
+378
View File
@@ -0,0 +1,378 @@
{ config, lib, pkgs, ... }:
{
services.matrix-synapse = {
enable = true;
settings = {
server_name = "sealight.xyz";
listeners = [
{
port = 8448;
tls = false;
resources = [{
compress = true;
names = [ "client" "federation" ];
}];
}
{
port = 9090;
type = "metrics";
bind_addresses = [ "0.0.0.0" ];
resources = [{
compress = false;
names = [ ];
}];
tls = false;
}
];
app_service_config_files = [
# The registration file is automatically generated after starting the appservice for the first time.
# cp /var/lib/matrix-appservice-discord/discord-registration.yaml /var/lib/matrix-synapse/
# chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/discord-registration.yaml
# "/var/lib/matrix-synapse/telegram-registration.yaml"
# "/var/lib/matrix-synapse/slack-registration.yaml"
# "/var/lib/matrix-synapse/discord-registration.yaml"
# "/var/lib/matrix-synapse/whatsapp-registration.yaml"
];
turn_uris = [
"turn:turn.sealight.xyz:3478?transport=udp"
"turn:turn.sealight.xyz:3478?transport=tcp"
];
turn_shared_secret = config.services.coturn.static-auth-secret;
extraConfig = ''
max_upload_size: "50M"
use_presence: false
registration_shared_secret: "hD9HQGTTDxp0mQsQ5JDsfudWMDiubmZENOgPchIvfBvUlPxlvQSvjoO4wn2L1seU";
'';
enable_metrics = true;
enable_registration = false;
database = {
name = "psycopg2";
args.password = "Da0?H*9i{x?,]|kq@iBwlIzu"; # TODO agenix
};
};
## coturn based TURN server integration (TURN server setup mentioned later),
## shared secret generated while configuring coturn
## and reused here (power of Nix being a real programming language)
};
services.coturn = {
enable = true;
use-auth-secret = true;
static-auth-secret = "jXW1ohIq6wM3NB00xeME3uBihY85xjpkhGoyzBIdwhOpj7gjyxXZu1fwp1lUiYwJ";
realm = "turn.sealight.xyz";
min-port = 49111;
max-port = 51111;
no-cli = true;
no-tcp-relay = true;
no-tls = true;
cert = "${config.security.acme.certs."turn.sealight.xyz".directory}/full.pem";
pkey = "${config.security.acme.certs."turn.sealight.xyz".directory}/key.pem";
extraConfig = ''
verbose
user-quota=12
total-quota=1200
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.0.2.0-192.0.2.255
denied-peer-ip=192.88.99.0-192.88.99.255
denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255
'';
};
security.acme.certs.${config.services.coturn.realm} = {
/* insert here the right configuration to obtain a certificate */
webroot = "/var/lib/acme/acme-challenge/";
email = "anish+acme@lakhwara.com";
postRun = "systemctl restart coturn.service";
group = "turnserver";
};
# TODO fix up jitsi bridge stuff
## services.jitsi-meet = {
## enable = true;
## hostName = "jitsi.sealight.xyz";
## };
## services.jitsi-videobridge.enable = true;
services.postgresql = {
enable = true;
## postgresql user and db name remains in the
## service.matrix-synapse.database_args setting which
## by default is matrix-synapse
# TODO agenix
initialScript = pkgs.writeText "synapse-init.sql" ''
CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD "Da0?H*9i{x?,]|kq@iBwlIzu";
CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
TEMPLATE template0
LC_COLLATE = "C"
LC_CTYPE = "C";
'';
authentication = ''
local matrix-synapse all ident map=matrix-synapse-users
'';
identMap = # Map the matrix-synapse user to postgresql
''
matrix-synapse-users matrix-synapse matrix-synapse
'';
};
networking.firewall =
let
range = with config.services.coturn; [{
from = min-port;
to = max-port;
}];
in
{
enable = true;
allowedUDPPortRanges = range; # coturn
allowedTCPPortRanges = range;
allowedTCPPorts = [
22 # SSH
8448 # Matrix federation
8008
80
443
3478 # Coturn service
5349 # Coturn service
9090 # Synapse Metrics
];
allowedUDPPorts = [
3478
5349 # Coturn service
];
};
nixpkgs.overlays = [
(self: super: {
element-web = super.element-web.override {
conf = {
default_server_config = {
"m.homeserver" = {
"base_url" = "https://chat.sealight.xyz";
"server_name" = "sealight.xyz";
};
"m.identity_server" = {
"base_url" = "https://vector.im";
};
};
## jitsi will be setup later,
## but we need to add to Riot configuration
jitsi.preferredDomain = "jitsi.sealight.xyz";
};
};
})
];
services.nginx = {
enable = true;
virtualHosts = {
"sealight.xyz" = {
forceSSL = true;
enableACME = true;
locations."/" = {
root = "/var/www/sealight.xyz";
};
locations."/_matrix" = {
proxyPass = "http://localhost:8448";
};
# locations."/slackbridge" = {
# proxyPass = "http://localhost:9899";
# };
};
## virtual host for Synapse
"chat.sealight.xyz" = {
forceSSL = true;
enableACME = true; # TODO
#useACMEHost = "sealight.xyz";
locations."/" = {
proxyPass = "http://localhost:8448";
};
};
## virtual host for Riot/Web
"element.sealight.xyz" = {
forceSSL = true;
enableACME = true; # TODO
#useACMEHost = "sealight.xyz";
## root points to the riot-web package content, also configured via Nix
locations."/" = {
root = pkgs.element-web;
};
};
# ${config.services.jitsi-meet.hostName} = {
# enableACME = true; # TODO
# forceSSL = true; # TODO
# };
};
## other nginx specific best practices
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedTlsSettings = true;
};
services.mautrix-telegram = {
enable = false;
environmentFile = /etc/secrets/telegram.env; # file containing the appservice and telegram tokens
# The appservice is pre-configured to use SQLite by default. It's also possible to use PostgreSQL.
settings = {
homeserver = {
address = "https://sealight.xyz";
domain = "sealight.xyz";
};
appservice = {
provisioning.enabled = false;
id = "telegram";
bot_username = "telegrambridge";
public = {
enabled = false;
prefix = "/public";
external = "https://chat.sealight.xyz/public";
};
address = "http://localhost:18787";
port = 18787;
# The service uses SQLite by default, but it's also possible to use PostgreSQL instead:
#database = "postgresql:///mautrix-telegram?host=/run/postgresql";
};
bridge = {
relaybot.authless_portals = false;
permissions = {
"@aynish:sealight.xyz" = "admin";
};
};
};
};
# services.heisenbridge = {
# enable = true;
# homeserver = "https://sealight.xyz";
# listenPort = 14456;
# appServiceToken = "wyujLh8kjpmk2bfKeEE3sZ2gWOEUBKK5";
# homeserverToken = "yEHs7lthD2ZHUibJOAv1APaFhEjxN5PT";
# };
# environment.systemPackages = with pkgs; [ matrix-appservice-slack ];
#services.mx-puppet-slack= {
#enable = false;
#settings = {
# bridge = {
# bindAddress = "localhost";
# port = 16786;
# domain = "sealight.xyz";
# homeserverUrl = "https://sealight.xyz";
# };
# provisioning = {
# whitelist = [ "@aynish:sealight.xyz" ];
# };
# relay = {
# whitelist = [ "@aynish:sealight.xyz" ];
# };
# namePatterns = {
# group = ":name";
# room = ":name[:team? - :team,]";
# user = ":name (Slack)";
# userOverride = ":displayname";
# };
# presence = {
# enabled = false;
# };
# oauth = {
# enabled = false;
# };
#};
#serviceDependencies = ["matrix-synapse.service"];
#};
# services.mautrix-whatsapp = {
# enable = false;
# The appservice is pre-configured to use SQLite by default. It's also possible to use PostgreSQL.
#configOptions = {
# homeserver = {
# address = "https://chat.sealight.xyz";
# domain = "sealight.xyz";
# };
# appservice = {
# id = "whatsapp";
# address = http://localhost:9897;
# hostname = "0.0.0.0";
# port = 9897;
# database = {
# type = "sqlite3";
# uri = "/var/lib/mautrix-whatsapp/mautrix-whatsapp.db";
# };
# state_store_path = "/var/lib/mautrix-whatsapp/mx-state.json";
# bot = {
# username = "whatsappbot";
# displayname = "WhatsApp bridge bot";
# avatar = "mxc://maunium.net/NeXNQarUbrlYBiPCpprYsRqr";
# };
# as_token = "";
# hs_token = "";
# };
# bridge = {
# username_template = "whatsapp_{{.}}";
# displayname_template = "{{if .Notify}}{{.Notify}}{{else}}{{.Jid}}{{end}} (WA)";
# command_prefix = "!wa";
# permissions = {
# "@aynish:sealight.xyz" = 100;
# };
# };
# logging = {
# directory = "/var/lib/mautrix-whatsapp/logs";
# file_name_format = "{{.Date}}-{{.Index}}.log";
# file_date_format = "\"2006-01-02\"";
# file_mode = 384;
# timestamp_format = "Jan _2, 2006 15:04:05";
# print_level = "debug";
# };
# metrics = {
# enabled = true;
# listen = "http://localhost:5070";
# };
#};
# };
#services.mx-puppet-discord = {
# enable = true;
# settings = {
# bridge = {
# bindAddress = "localhost";
# port = 16785;
# domain = "sealight.xyz";
# homeserverUrl = "https://sealight.xyz";
# avatarUrl = "https://discord.com/assets/2d20a45d79110dc5bf947137e9d99b66.svg";
# };
# provisioning = {
# whitelist = [ "@aynish:sealight.xyz" ];
# };
# relay = {
# whitelist = [ "@aynish:sealight.xyz" ];
# };
# namePatterns = {
# group = ":name";
# room = ":name";
# user = ":name (Discord)";
# userOverride = ":displayname";
# };
# presence = {
# enabled = false;
# };
# };
# serviceDependencies = [ "matrix-synapse.service" ];
#};
}
+154
View File
@@ -0,0 +1,154 @@
{ config, pkgs, lib, ... }:
with lib;
let
dataDir = "/var/lib/matrix-appservice-slack";
registrationFile = "${dataDir}/slack-registration.yaml";
#appDir = "${pkgs.matrix-appservice-slack}/${pkgs.matrix-appservice-slack.passthru.nodeAppDir}";
cfg = config.services.matrix-appservice-slack;
# TODO: switch to configGen.json once RFC42 is implemented
settingsFile = pkgs.writeText "matrix-appservice-slack-settings.json" (builtins.toJSON cfg.settings);
in
{
options = {
services.matrix-appservice-slack = {
enable = mkEnableOption "a bridge between Matrix and Slack";
settings = mkOption rec {
# TODO: switch to types.config.json as prescribed by RFC42 once it's implemented
type = types.attrs;
apply = recursiveUpdate default;
default = {
# empty values necessary for registration file generation
# actual values defined in environmentFile
auth = {
clientID = "";
botToken = "";
};
};
example = literalExample ''
{
bridge = {
domain = "public-domain.tld";
homeserverUrl = "http://public-domain.tld:8008";
};
}
'';
description = ''
<filename>config.yaml</filename> configuration as a Nix attribute set.
</para>
<para>
Configuration options should match those described in
<link xlink:href="https://github.com/Half-Shot/matrix-appservice-discord/blob/master/config/config.sample.yaml">
config.sample.yaml</link>.
</para>
<para>
<option>config.bridge.domain</option> and <option>config.bridge.homeserverUrl</option>
should be set to match the public host name of the Matrix homeserver for webhooks and avatars to work.
</para>
<para>
Secret tokens should be specified using <option>environmentFile</option>
instead of this world-readable attribute set.
'';
};
environmentFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
File containing environment variables to be passed to the matrix-appservice-discord service,
in which secret tokens can be specified securely by defining values for
<literal>APPSERVICE_SLACK_AUTH_CLIENT_I_D</literal> and
<literal>APPSERVICE_SLACK_AUTH_BOT_TOKEN</literal>.
'';
};
url = mkOption {
type = types.str;
default = "http://localhost:${toString cfg.port}";
description = ''
The URL where the application service is listening for HS requests.
'';
};
port = mkOption {
type = types.port;
default = 9898; # from https://github.com/matrix-org/matrix-appservice-slack/blob/develop/config/config.sample.yaml#L70
description = ''
Port number on which the bridge should listen for internal communication with the Matrix homeserver.
'';
};
localpart = mkOption {
type = with types; nullOr str;
default = null;
description = ''
The user_id localpart to assign to the AS.
'';
};
serviceDependencies = mkOption {
type = with types; listOf str;
default = optional config.services.matrix-synapse.enable "matrix-synapse.service";
description = ''
List of Systemd services to require and wait for when starting the application service,
such as the Matrix homeserver if it's running on the same host.
'';
};
};
};
config = mkIf cfg.enable {
systemd.services.matrix-appservice-slack = {
description = "A bridge between Matrix and Slack.";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ] ++ cfg.serviceDependencies;
after = [ "network-online.target" ] ++ cfg.serviceDependencies;
preStart = ''
if [ ! -f '${registrationFile}' ]; then
${pkgs.matrix-appservice-slack}/bin/matrix-appservice-slack \
--generate-registration \
--url=${escapeShellArg cfg.url} \
${optionalString (cfg.localpart != null) "--localpart=${escapeShellArg cfg.localpart}"} \
--config='${settingsFile}' \
--file='${registrationFile}'
fi
'';
serviceConfig = {
Type = "simple";
Restart = "always";
ProtectSystem = "strict";
ProtectHome = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
DynamicUser = true;
PrivateTmp = true;
#WorkingDirectory = appDir;
StateDirectory = baseNameOf dataDir;
UMask = 0027;
EnvironmentFile = cfg.environmentFile;
ExecStart = ''
${pkgs.matrix-appservice-slack}/bin/matrix-appservice-slack \
--file='${registrationFile}' \
--config='${settingsFile}' \
--port='${toString cfg.port}'
'';
};
};
};
meta.maintainers = with maintainers; [ chickensoupandrice ];
}
+97
View File
@@ -0,0 +1,97 @@
{ lib, config, pkgs, ... }:
with lib;
let
cfg = config.services.mautrix-whatsapp;
configFile = pkgs.runCommand "mautrix-whatsapp"
{
buildInputs = [ pkgs.mautrix-whatsapp pkgs.remarshal ];
preferLocalBuild = true;
} ''
mkdir -p $out
${pkgs.remarshal}/bin/json2yaml -i ${pkgs.writeText "config.json" (builtins.toJSON cfg.configOptions)} \
-o $out/config.yaml
${pkgs.mautrix-whatsapp}/bin/mautrix-whatsapp -c $out/config.yaml -g -r $out/registration.yaml
'';
in
{
options.services.mautrix-whatsapp = {
enable = mkEnableOption "Mautrix-whatsapp, a puppeting bridge between Matrix and WhatsApp.";
configOptions = mkOption {
type = types.attrs;
description = ''
This options will be transform in YAML configuration file for the bridge
Look <link xlink:href="https://github.com/tulir/mautrix-whatsapp/wiki/Bridge-setup">here</link> for documentation.
'';
example = {
configOptions = {
homeserver = {
address = https://matrix.org;
domain = "matrix.org";
};
appservice = {
address = http://localhost:8080;
hostname = "0.0.0.0";
port = 8080;
database = {
type = "sqlite3";
uri = "/var/lib/mautrix-whatsapp/mautrix-whatsapp.db";
};
state_store_path = "/var/lib/mautrix-whatsapp/mx-state.json";
id = "whatsapp";
bot = {
username = "whatsappbot";
displayname = "WhatsApp bridge bot";
avatar = "mxc://maunium.net/NeXNQarUbrlYBiPCpprYsRqr";
};
as_token = "";
hs_token = "";
};
bridge = {
username_template = "whatsapp_{{.}}";
displayname_template = "{{if .Notify}}{{.Notify}}{{else}}{{.Jid}}{{end}} (WA)";
command_prefix = "!wa";
permissions = {
"@example:matrix.org" = 100;
};
};
logging = {
directory = "/var/lib/mautrix-whatsapp/logs";
file_name_format = "{{.Date}}-{{.Index}}.log";
file_date_format = "\"2006-01-02\"";
file_mode = 384;
timestamp_format = "Jan _2, 2006 15:04:05";
print_level = "debug";
};
};
};
};
};
config = mkIf cfg.enable {
systemd.services.mautrix-whatsapp = {
description = "Mautrix-WhatsApp Service - A WhatsApp bridge for Matrix";
after = [ "network.target" "matrix-synapse.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
DynamicUser = true;
StateDirectory = "mautrix-whatsapp";
LoggingDir = "mautrix-whatsapp";
ExecStart = ''
${pkgs.mautrix-whatsapp}/bin/mautrix-whatsapp -c "${configFile}/config.yaml"
'';
Restart = "on-failure";
};
};
#services.matrix-synapse.app_service_config_files = [ "${configFile}/registration.yaml" ];
};
}
+125
View File
@@ -0,0 +1,125 @@
{ config, pkgs, lib, ... }:
with lib;
let
dataDir = "/var/lib/mx-puppet-slack";
registrationFile = "${dataDir}/slack-registration.yaml";
cfg = config.services.mx-puppet-slack;
settingsFormat = pkgs.formats.json { };
settingsFile = settingsFormat.generate "mx-puppet-slack-config.json" cfg.settings;
mx-puppet-slack = pkgs.callPackage ./pkg-mx-puppet-slack.nix { };
in
{
options = {
services.mx-puppet-slack = {
enable = mkEnableOption ''
mx-puppet-slack is a slack puppeting bridge for matrix.
It handles bridging private and group DMs, as well as Guilds (servers)
'';
settings = mkOption rec {
apply = recursiveUpdate default;
inherit (settingsFormat) type;
default = {
bridge.port = 8434;
presence = {
enabled = true;
interval = 500;
};
provisioning.whitelist = [ ];
relay.whitelist = [ ];
# variables are preceded by a colon.
namePatterns = {
user = ":name";
userOverride = ":displayname";
room = ":name";
group = ":name";
};
#defaults to sqlite but can be configured to use postgresql with
#connstring
database.filename = "${dataDir}/database.db";
logging = {
console = "info";
lineDateFormat = "MMM-D HH:mm:ss.SSS";
};
};
example = literalExpression ''
{
bridge = {
bindAddress = "localhost";
domain = "example.com";
homeserverUrl = "https://example.com";
};
provisioning.whitelist = [ "@admin:example.com" ];
relay.whitelist = [ "@.*:example.com" ];
}
'';
description = ''
<filename>config.yaml</filename> configuration as a Nix attribute set.
Configuration options should match those described in
<link xlink:href="https://github.com/matrix-slack/mx-puppet-slack/blob/master/sample.config.yaml">
sample.config.yaml</link>.
'';
};
serviceDependencies = mkOption {
type = with types; listOf str;
default = optional config.services.matrix-synapse.enable "matrix-synapse.service";
description = ''
List of Systemd services to require and wait for when starting the application service.
'';
};
};
};
config = mkIf cfg.enable {
systemd.services.mx-puppet-slack = {
description = ''
mx-puppet-slack is a slack puppeting bridge for matrix.
It handles bridging private and group DMs, as well as Guilds (servers).
'';
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ] ++ cfg.serviceDependencies;
after = [ "network-online.target" ] ++ cfg.serviceDependencies;
preStart = ''
# generate the appservice's registration file if absent
if [ ! -f '${registrationFile}' ]; then
${mx-puppet-slack}/bin/mx-puppet-slack -r -c ${settingsFile} \
-f ${registrationFile}
fi
'';
serviceConfig = {
Type = "simple";
Restart = "always";
ProtectSystem = "strict";
ProtectHome = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
DynamicUser = true;
PrivateTmp = true;
WorkingDirectory = mx-puppet-slack;
StateDirectory = baseNameOf dataDir;
UMask = 0027;
ExecStart = ''
${mx-puppet-slack}/bin/mx-puppet-slack \
-c ${settingsFile} \
-f ${registrationFile}
'';
};
};
};
meta.maintainers = with maintainers; [ chickensoupwithrice ];
}