summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nixos/modules/misc/ids.nix2
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/services/misc/matrix-synapse-log_config.yaml25
-rw-r--r--nixos/modules/services/misc/matrix-synapse.nix279
-rw-r--r--pkgs/servers/matrix-synapse/default.nix45
-rw-r--r--pkgs/servers/matrix-synapse/matrix-synapse.patch20
-rw-r--r--pkgs/top-level/all-packages.nix2
-rw-r--r--pkgs/top-level/python-packages.nix162
8 files changed, 533 insertions, 3 deletions
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 39ed914994c1..6a3baf98a004 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -245,6 +245,7 @@
       opendkim = 221;
       dspam = 222;
       gale = 223;
+      matrix-synapse = 224;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -467,6 +468,7 @@
       opendkim = 221;
       dspam = 222;
       gale = 223;
+      matrix-synapse = 224;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index d9e8c2da5b32..4f125b09afbf 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -214,6 +214,7 @@
   ./services/misc/gpsd.nix
   ./services/misc/ihaskell.nix
   ./services/misc/mathics.nix
+  ./services/misc/matrix-synapse.nix
   ./services/misc/mbpfan.nix
   ./services/misc/mediatomb.nix
   ./services/misc/mesos-master.nix
diff --git a/nixos/modules/services/misc/matrix-synapse-log_config.yaml b/nixos/modules/services/misc/matrix-synapse-log_config.yaml
new file mode 100644
index 000000000000..d85bdd1208f9
--- /dev/null
+++ b/nixos/modules/services/misc/matrix-synapse-log_config.yaml
@@ -0,0 +1,25 @@
+version: 1
+
+# In systemd's journal, loglevel is implicitly stored, so let's omit it
+# from the message text.
+formatters:
+    journal_fmt:
+        format: '%(name)s: [%(request)s] %(message)s'
+
+filters:
+    context:
+        (): synapse.util.logcontext.LoggingContextFilter
+        request: ""
+
+handlers:
+    journal:
+        class: systemd.journal.JournalHandler
+        formatter: journal_fmt
+        filters: [context]
+        SYSLOG_IDENTIFIER: synapse
+
+root:
+    level: INFO
+    handlers: [journal]
+
+disable_existing_loggers: False
diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix
new file mode 100644
index 000000000000..27c5a38e6b88
--- /dev/null
+++ b/nixos/modules/services/misc/matrix-synapse.nix
@@ -0,0 +1,279 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.matrix-synapse;
+  logConfigFile = pkgs.writeText "log_config.yaml" cfg.logConfig;
+  configFile = pkgs.writeText "homeserver.yaml" ''
+tls_certificate_path: "${cfg.tls_certificate_path}"
+tls_private_key_path: "${cfg.tls_private_key_path}"
+tls_dh_params_path: "${cfg.tls_dh_params_path}"
+no_tls: ${if cfg.no_tls then "true" else "false"}
+bind_port: ${toString cfg.bind_port}
+unsecure_port: ${toString cfg.unsecure_port}
+bind_host: "${cfg.bind_host}"
+server_name: "${cfg.server_name}"
+pid_file: "/var/run/matrix-synapse.pid"
+web_client: ${if cfg.web_client then "true" else "false"}
+database: {
+  name: "${cfg.database_type}",
+  args: {
+    ${concatStringsSep ",\n    " (
+      mapAttrsToList (n: v: "\"${n}\": ${v}") cfg.database_args
+    )}
+  }
+}
+log_file: "/var/log/matrix-synapse/homeserver.log"
+log_config: "${logConfigFile}"
+media_store_path: "/var/lib/matrix-synapse/media"
+recaptcha_private_key: "${cfg.recaptcha_private_key}"
+recaptcha_public_key: "${cfg.recaptcha_public_key}"
+enable_registration_captcha: ${if cfg.enable_registration_captcha then "true" else "false"}
+turn_uris: ${if (length cfg.turn_uris) == 0 then "[]" else ("\n" + (concatStringsSep "\n" (map (s: "- " + s) cfg.turn_uris)))}
+turn_shared_secret: "${cfg.turn_shared_secret}"
+enable_registration: ${if cfg.enable_registration then "true" else "false"}
+${optionalString (cfg.registration_shared_secret != "") ''
+registration_shared_secret: "${cfg.registration_shared_secret}"
+''}
+enable_metrics: ${if cfg.enable_metrics then "true" else "false"}
+report_stats: ${if cfg.report_stats then "true" else "false"}
+signing_key_path: "/var/lib/matrix-synapse/homeserver.signing.key"
+perspectives:
+  servers: {
+    ${concatStringsSep "},\n" (mapAttrsToList (n: v: ''
+    "${n}": {
+      "verify_keys": {
+        ${concatStringsSep "},\n" (mapAttrsToList (n: v: ''
+        "${n}": {
+          "key": "${v}"
+        }'') v)}
+      }
+    '') cfg.servers)}
+    }
+  }
+${cfg.extraConfig}
+'';
+in {
+  options = {
+    services.matrix-synapse = {
+      enable = mkEnableOption "matrix.org synapse";
+      package = mkOption {
+        type = types.package;
+        default = pkgs.matrix-synapse;
+        description = ''
+          Overridable attribute of the matrix synapse server package to use.
+        '';
+      };
+      no_tls = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Don't bind to the https port
+        '';
+      };
+      tls_certificate_path = mkOption {
+        type = types.path;
+        default = "/var/lib/matrix-synapse/homeserver.tls.crt";
+        description = ''
+          PEM encoded X509 certificate for TLS
+        '';
+      };
+      tls_private_key_path = mkOption {
+        type = types.path;
+        default = "/var/lib/matrix-synapse/homeserver.tls.key";
+        description = ''
+          PEM encoded private key for TLS
+        '';
+      };
+      tls_dh_params_path = mkOption {
+        type = types.path;
+        default = "/var/lib/matrix-synapse/homeserver.tls.dh";
+        description = ''
+          PEM dh parameters for ephemeral keys
+        '';
+      };
+      bind_port = mkOption {
+        type = types.int;
+        default = 8448;
+        description = ''
+          The port to listen for HTTPS requests on.
+          For when matrix traffic is sent directly to synapse.
+        '';
+      };
+      unsecure_port = mkOption {
+        type = types.int;
+        default = 8008;
+        description = ''
+          The port to listen for HTTP requests on.
+          For when matrix traffic passes through loadbalancer that unwraps TLS.
+        '';
+      };
+      bind_host = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Local interface to listen on.
+          The empty string will cause synapse to listen on all interfaces.
+        '';
+      };
+      server_name = mkOption {
+        type = types.str;
+        description = ''
+          The domain name of the server, with optional explicit port.
+          This is used by remote servers to connect to this server,
+          e.g. matrix.org, localhost:8080, etc.
+          This is also the last part of your UserID.
+        '';
+      };
+      web_client = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to serve a web client from the HTTP/HTTPS root resource.
+        '';
+      };
+      database_type = mkOption {
+        type = types.enum [ "sqlite3" "psycopg2" ];
+        default = "sqlite3";
+        description = ''
+          The database engine name. Can be sqlite or psycopg2.
+        '';
+      };
+      database_args = mkOption {
+        type = types.attrs;
+        default = {
+          database = "/var/lib/matrix-synapse/homeserver.db";
+        };
+        description = ''
+          Arguments to pass to the engine.
+        '';
+      };
+      recaptcha_private_key = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          This Home Server's ReCAPTCHA private key.
+        '';
+      };
+      recaptcha_public_key = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          This Home Server's ReCAPTCHA public key.
+        '';
+      };
+      enable_registration_captcha = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enables ReCaptcha checks when registering, preventing signup
+          unless a captcha is answered. Requires a valid ReCaptcha
+          public/private key.
+        '';
+      };
+      turn_uris = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          The public URIs of the TURN server to give to clients
+        '';
+      };
+      turn_shared_secret = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          The shared secret used to compute passwords for the TURN server
+        '';
+      };
+      enable_registration = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable registration for new users.
+        '';
+      };
+      registration_shared_secret = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          If set, allows registration by anyone who also has the shared
+          secret, even if registration is otherwise disabled.
+        '';
+      };
+      enable_metrics = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable collection and rendering of performance metrics
+        '';
+      };
+      report_stats = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+        '';
+      };
+      servers = mkOption {
+        type = types.attrs;
+        default = {
+          "matrix.org" = {
+            "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
+          };
+        };
+        description = ''
+          The trusted servers to download signing keys from.
+        '';
+      };
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Extra config options for matrix-synapse.
+        '';
+      };
+      logConfig = mkOption {
+        type = types.lines;
+        default = readFile ./matrix-synapse-log_config.yaml;
+        description = ''
+          A yaml python logging config file
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraUsers = [
+      { name = "matrix-synapse";
+        group = "matrix-synapse";
+        home = "/var/lib/matrix-synapse";
+        createHome = true;
+        shell = "${pkgs.bash}/bin/bash";
+        uid = config.ids.uids.matrix-synapse;
+      } ];
+
+    users.extraGroups = [
+      { name = "matrix-synapse";
+        gid = config.ids.gids.matrix-synapse;
+      } ];
+
+    systemd.services.matrix-synapse = {
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      preStart = ''
+        mkdir -p /var/lib/matrix-synapse
+        chmod 700 /var/lib/matrix-synapse
+        chown -R matrix-synapse:matrix-synapse /var/lib/matrix-synapse
+        ${cfg.package}/bin/homeserver --config-path ${configFile} --generate-keys
+      '';
+      serviceConfig = {
+        Type = "simple";
+        User = "matrix-synapse";
+        Group = "matrix-synapse";
+        WorkingDirectory = "/var/lib/matrix-synapse";
+        PermissionsStartOnly = true;
+        ExecStart = "${cfg.package}/bin/homeserver --config-path ${configFile}";
+      };
+    };
+  };
+}
diff --git a/pkgs/servers/matrix-synapse/default.nix b/pkgs/servers/matrix-synapse/default.nix
new file mode 100644
index 000000000000..66d9e7258f4c
--- /dev/null
+++ b/pkgs/servers/matrix-synapse/default.nix
@@ -0,0 +1,45 @@
+{ pkgs, stdenv, buildPythonPackage, pythonPackages, fetchurl, fetchFromGitHub }:
+let
+  matrix-angular-sdk = buildPythonPackage rec {
+    name = "matrix-angular-sdk-${version}";
+    version = "0.6.6";
+
+    src = fetchurl {
+      url = "https://pypi.python.org/packages/source/m/matrix-angular-sdk/matrix-angular-sdk-${version}.tar.gz";
+      sha256 = "1vknhmibb8gh8lng50va2cdvng5xm7vqv9dl680m3gj38pg0bv8a";
+    };
+  };
+in
+buildPythonPackage rec {
+  name = "matrix-synapse-${version}";
+  version = "0.12.0";
+
+  src = fetchFromGitHub {
+    owner = "matrix-org";
+    repo = "synapse";
+    rev = "f35f8d06ea58e2d0cdccd82924c7a44fd93f4c38";
+    sha256 = "0b0k1am9lh0qglagc06m91qs26ybv37k7wpbg5333x8jaf5d1si4";
+  };
+
+  patches = [ ./matrix-synapse.patch ];
+
+  propagatedBuildInputs = with pythonPackages; [
+    blist canonicaljson daemonize dateutil frozendict pillow pybcrypt pyasn1
+    pydenticon pymacaroons-pynacl pynacl pyopenssl pysaml2 pytz requests2
+    service-identity signedjson systemd twisted15 ujson unpaddedbase64 pyyaml
+    matrix-angular-sdk
+  ];
+
+  # Checks fail because of Tox.
+  doCheck = false;
+
+  buildInputs = with pythonPackages; [
+    mock setuptoolsTrial
+  ];
+
+  meta = {
+    homepage = https://matrix.org;
+    description = "Matrix reference homeserver";
+    license = stdenv.lib.licenses.asl20;
+  };
+}
diff --git a/pkgs/servers/matrix-synapse/matrix-synapse.patch b/pkgs/servers/matrix-synapse/matrix-synapse.patch
new file mode 100644
index 000000000000..a6a393ea56c3
--- /dev/null
+++ b/pkgs/servers/matrix-synapse/matrix-synapse.patch
@@ -0,0 +1,20 @@
+diff --git a/homeserver b/homeserver
+new file mode 120000
+index 0000000..2f1d413
+--- /dev/null
++++ b/homeserver
+@@ -0,0 +1 @@
++synapse/app/homeserver.py
+\ No newline at end of file
+diff --git a/setup.py b/setup.py
+index 9d24761..f3e6a00 100755
+--- a/setup.py
++++ b/setup.py
+@@ -85,6 +85,6 @@ setup(
+     include_package_data=True,
+     zip_safe=False,
+     long_description=long_description,
+-    scripts=["synctl"] + glob.glob("scripts/*"),
++    scripts=["synctl", "homeserver"] + glob.glob("scripts/*"),
+     cmdclass={'test': Tox},
+ )
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 82708cd30e52..761bbed35184 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -2076,6 +2076,8 @@ let
 
   makebootfat = callPackage ../tools/misc/makebootfat { };
 
+  matrix-synapse = callPackage ../servers/matrix-synapse { };
+
   memtester = callPackage ../tools/system/memtester { };
 
   minidlna = callPackage ../tools/networking/minidlna { };
diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix
index ec17d9434a07..22324178843e 100644
--- a/pkgs/top-level/python-packages.nix
+++ b/pkgs/top-level/python-packages.nix
@@ -17823,7 +17823,7 @@ in modules // {
       md5 = "f16f4237c9ee483a0cd13208849d96ad";
     };
 
-    propagatedBuildInputs = with self; [ twisted ];
+    propagatedBuildInputs = with self; [ twisted15 ];
 
     meta = {
       description = "setuptools plug-in that helps run unit tests built with the \"Trial\" framework (from Twisted)";
@@ -17852,11 +17852,11 @@ in modules // {
 
 
   simplejson = buildPythonPackage (rec {
-    name = "simplejson-3.3.0";
+    name = "simplejson-3.8.1";
 
     src = pkgs.fetchurl {
       url = "http://pypi.python.org/packages/source/s/simplejson/${name}.tar.gz";
-      md5 = "0e29b393bceac8081fa4e93ff9f6a001";
+      sha256 = "14r4l4rcsyf87p2j4ycsbb017n4vzxfmv285rq2gny4w47rwi2j2";
     };
 
     meta = {
@@ -19758,6 +19758,35 @@ in modules // {
     };
   };
 
+  twisted15 = buildPythonPackage rec {
+    disabled = isPy3k;
+
+    name = "Twisted-15.5.0";
+    src = pkgs.fetchurl {
+      url = "https://pypi.python.org/packages/source/T/Twisted/${name}.tar.bz2";
+      sha256 = "0zy18lcrris4aaslil5k12i13k56c32hzfdv6h10kbnzl026h158";
+    };
+
+    propagatedBuildInputs = with self; [ zope_interface ];
+
+    # Generate Twisted's plug-in cache.  Twited users must do it as well.  See
+    # http://twistedmatrix.com/documents/current/core/howto/plugin.html#auto3
+    # and http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=477103 for
+    # details.
+    postInstall = "$out/bin/twistd --help > /dev/null";
+
+    meta = {
+      homepage = http://twistedmatrix.com/;
+      description = "Twisted, an event-driven networking engine written in Python";
+      longDescription = ''
+        Twisted is an event-driven networking engine written in Python
+        and licensed under the MIT license.
+      '';
+      license = licenses.mit;
+      maintainers = [ ];
+    };
+  };
+
   tzlocal = buildPythonPackage rec {
     name = "tzlocal-1.1.1";
 
@@ -22583,6 +22612,133 @@ in modules // {
     };
   };
 
+  blist = buildPythonPackage rec {
+    name = "blist-${version}";
+    version = "1.3.6";
+    disabled = isPyPy;
+
+    src = pkgs.fetchurl {
+      url = "https://pypi.python.org/packages/source/b/blist/blist-${version}.tar.gz";
+      sha256 = "1hqz9pqbwx0czvq9bjdqjqh5bwfksva1is0anfazig81n18c84is";
+    };
+  };
+
+  canonicaljson = buildPythonPackage rec {
+    name = "canonicaljson-${version}";
+    version = "1.0.0";
+
+    src = pkgs.fetchgit {
+      url = "https://github.com/matrix-org/python-canonicaljson.git";
+      rev = "refs/tags/v${version}";
+      sha256 = "29802d0effacd26ca1d6eccc8d4c7e4f543a194754ba89263861e87f44a83f0c";
+    };
+
+    propagatedBuildInputs = with self; [
+      frozendict simplejson
+    ];
+  };
+
+  daemonize = buildPythonPackage rec {
+    name = "daemonize-${version}";
+    version = "2.4.2";
+
+    src = pkgs.fetchurl {
+      url = "https://pypi.python.org/packages/source/d/daemonize/daemonize-${version}.tar.gz";
+      sha256 = "0y139sq657bpzfv6k0aqm4071z4s40i6ybpni9qvngvdcz6r86n2";
+    };
+  };
+
+  frozendict = buildPythonPackage rec {
+    name = "frozendict-${version}";
+    version = "0.5";
+
+    src = pkgs.fetchurl {
+      url = "https://pypi.python.org/packages/source/f/frozendict/frozendict-0.5.tar.gz";
+      sha256 = "0m4kg6hbadvf99if78nx01q7qnbyhdw3x4znl5dasgciyi54432n";
+    };
+  };
+
+  pydenticon = buildPythonPackage rec {
+    name = "pydenticon-${version}";
+    version = "0.2";
+
+    src = pkgs.fetchurl {
+      url = "https://pypi.python.org/packages/source/p/pydenticon/pydenticon-0.2.tar.gz";
+      sha256 = "035dawcspgjw2rksbnn863s7b0i9ac8cc1nshshvd1l837ir1czp";
+    };
+    propagatedBuildInputs = with self; [
+      pillow mock
+    ];
+  };
+
+  pymacaroons-pynacl = buildPythonPackage rec {
+    name = "pymacaroons-pynacl-${version}";
+    version = "0.9.3";
+
+    src = pkgs.fetchgit {
+      url = "https://github.com/matrix-org/pymacaroons.git";
+      rev = "refs/tags/v${version}";
+      sha256 = "481a486520f5a3ad2761c3cd3954d2b08f456a94fb080aaa4ad1e68ddc705b52";
+    };
+
+    propagatedBuildInputs = with self; [ pynacl six ];
+  };
+
+  pynacl = buildPythonPackage rec {
+    name = "pynacl-${version}";
+    version = "0.3.0";
+
+    src = pkgs.fetchurl {
+      url = "https://pypi.python.org/packages/source/P/PyNaCl/PyNaCl-0.3.0.tar.gz";
+      sha256 = "1hknxlp3a3f8njn19w92p8nhzl9jkfwzhv5fmxhmyq2m8hqrfj8j";
+    };
+
+    propagatedBuildInputs = with self; [pkgs.libsodium six cffi pycparser pytest];
+  };
+
+  service-identity = buildPythonPackage rec {
+    name = "service-identity-${version}";
+    version = "14.0.0";
+
+    src = pkgs.fetchurl {
+      url = "https://pypi.python.org/packages/source/s/service_identity/service_identity-${version}.tar.gz";
+      sha256 = "0njg9bklkkp4rl2b9vsfh9aasxy3w2dmjkv9cq34jn65lwcs619i";
+    };
+
+    propagatedBuildInputs = with self; [
+      characteristic pyasn1 pyasn1-modules pyopenssl idna
+    ];
+
+    buildInputs = with self; [
+      pytest
+    ];
+  };
+
+  signedjson = buildPythonPackage rec {
+    name = "signedjson-${version}";
+    version = "1.0.0";
+
+    src = pkgs.fetchgit {
+      url = "https://github.com/matrix-org/python-signedjson.git";
+      rev = "refs/tags/v${version}";
+      sha256 = "4ef1c89ea85846632d711a37a2e6aae1348c62b9d62ed0e80428b4a00642e9df";
+    };
+
+    propagatedBuildInputs = with self; [
+      canonicaljson unpaddedbase64 pynacl
+    ];
+  };
+
+  unpaddedbase64 = buildPythonPackage rec {
+    name = "unpaddedbase64-${version}";
+    version = "1.0.1";
+
+    src = pkgs.fetchgit {
+      url = "https://github.com/matrix-org/python-unpaddedbase64.git";
+      rev = "refs/tags/v${version}";
+      sha256 = "f221240a6d414c4244ab906b1dc8983c4d1114acb778cb857f6fc50d710be502";
+    };
+  };
 
 
   thumbor = buildPythonPackage rec {