summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nixos/doc/manual/release-notes/rl-1803.xml32
-rw-r--r--nixos/modules/services/networking/prosody.nix214
-rw-r--r--nixos/release.nix1
-rw-r--r--nixos/tests/prosody.nix75
-rw-r--r--pkgs/servers/xmpp/prosody/default.nix23
-rw-r--r--pkgs/top-level/all-packages.nix5
-rw-r--r--pkgs/top-level/lua-packages.nix5
7 files changed, 318 insertions, 37 deletions
diff --git a/nixos/doc/manual/release-notes/rl-1803.xml b/nixos/doc/manual/release-notes/rl-1803.xml
index b755245a69f..e67f1448466 100644
--- a/nixos/doc/manual/release-notes/rl-1803.xml
+++ b/nixos/doc/manual/release-notes/rl-1803.xml
@@ -322,6 +322,38 @@ following incompatible changes:</para>
       <link xlink:href="https://github.com/rvl/pump.io-nixos">external module</link>.
     </para>
   </listitem>
+  <listitem>
+    <para>
+      The Prosody XMPP server has received a major update. The following modules were renamed:
+      <itemizedlist>
+        <listitem>
+          <para>
+            <option>services.prosody.modules.httpserver</option> is now <option>services.prosody.modules.http_files</option>
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <option>services.prosody.modules.console</option> is now <option>services.prosody.modules.admin_telnet</option>
+          </para>
+        </listitem>
+      </itemizedlist>
+    </para>
+
+    <para>
+      Many new modules are now core modules, most notably <option>services.prosody.modules.carbons</option>
+      and <option>services.prosody.modules.mam</option>.
+    </para>
+
+    <para>
+      The better-performing <literal>libevent</literal> backend is now enabled by default.
+    </para>
+
+    <para>
+      <literal>withCommunityModules</literal> now passes through the modules to <option>services.prosody.extraModules</option>.
+      Use <literal>withOnlyInstalledCommunityModules</literal> for modules that should not be enabled directly, e.g <literal>lib_ldap</literal>.
+    </para>
+  </listitem>
+
 </itemizedlist>
 
 </section>
diff --git a/nixos/modules/services/networking/prosody.nix b/nixos/modules/services/networking/prosody.nix
index 9d7e6d6018a..d57ebb61f63 100644
--- a/nixos/modules/services/networking/prosody.nix
+++ b/nixos/modules/services/networking/prosody.nix
@@ -15,6 +15,7 @@ let
         description = "Path to the key file.";
       };
 
+      # TODO: rename to certificate to match the prosody config
       cert = mkOption {
         type = types.path;
         description = "Path to the certificate file.";
@@ -30,7 +31,7 @@ let
   };
 
   moduleOpts = {
-
+    # Generally required
     roster = mkOption {
       type = types.bool;
       default = true;
@@ -61,12 +62,38 @@ let
       description = "Service discovery";
     };
 
-    legacyauth = mkOption {
+    # Not essential, but recommended
+    carbons = mkOption {
       type = types.bool;
       default = true;
-      description = "Legacy authentication. Only used by some old clients and bots";
+      description = "Keep multiple clients in sync";
+    };
+
+    pep = mkOption {
+      type = types.bool;
+      default = true;
+      description = "Enables users to publish their mood, activity, playing music and more";
+    };
+
+    private = mkOption {
+      type = types.bool;
+      default = true;
+      description = "Private XML storage (for room bookmarks, etc.)";
+    };
+
+    blocklist = mkOption {
+      type = types.bool;
+      default = true;
+      description = "Allow users to block communications with other users";
     };
 
+    vcard = mkOption {
+      type = types.bool;
+      default = true;
+      description = "Allow users to set vCards";
+    };
+
+    # Nice to have
     version = mkOption {
       type = types.bool;
       default = true;
@@ -91,36 +118,112 @@ let
       description = "Replies to XMPP pings with pongs";
     };
 
-    console = mkOption {
+    register = mkOption {
+      type = types.bool;
+      default = true;
+      description = "Allow users to register on this server using a client and change passwords";
+    };
+
+    mam = mkOption {
       type = types.bool;
       default = false;
-      description = "telnet to port 5582";
+      description = "Store messages in an archive and allow users to access it";
     };
 
+    # Admin interfaces
+    admin_adhoc = mkOption {
+      type = types.bool;
+      default = true;
+      description = "Allows administration via an XMPP client that supports ad-hoc commands";
+    };
+
+    admin_telnet = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Opens telnet console interface on localhost port 5582";
+    };
+
+    # HTTP modules
     bosh = mkOption {
       type = types.bool;
       default = false;
       description = "Enable BOSH clients, aka 'Jabber over HTTP'";
     };
 
-    httpserver = mkOption {
+    websocket = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Enable WebSocket support";
+    };
+
+    http_files = mkOption {
       type = types.bool;
       default = false;
       description = "Serve static files from a directory over HTTP";
     };
 
-    websocket = mkOption {
+    # Other specific functionality
+    limits = mkOption {
       type = types.bool;
       default = false;
-      description = "Enable WebSocket support";
+      description = "Enable bandwidth limiting for XMPP connections";
+    };
+
+    groups = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Shared roster support";
+    };
+
+    server_contact_info = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Publish contact information for this service";
+    };
+
+    announce = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Send announcement to all online users";
+    };
+
+    welcome = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Welcome users who register accounts";
+    };
+
+    watchregistrations = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Alert admins of registrations";
+    };
+
+    motd = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Send a message to users when they log in";
+    };
+
+    legacyauth = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Legacy authentication. Only used by some old clients and bots";
+    };
+
+    proxy65 = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Enables a file transfer proxy service which clients behind NAT can use";
     };
 
   };
 
   toLua = x:
     if builtins.isString x then ''"${x}"''
-    else if builtins.isBool x then toString x
+    else if builtins.isBool x then (if x == true then "true" else "false")
     else if builtins.isInt x then toString x
+    else if builtins.isList x then ''{ ${lib.concatStringsSep ", " (map (n: toLua n) x) } }''
     else throw "Invalid Lua value";
 
   createSSLOptsStr = o: ''
@@ -198,6 +301,59 @@ in
         description = "Allow account creation";
       };
 
+      c2sRequireEncryption = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Force clients to use encrypted connections? This option will
+          prevent clients from authenticating unless they are using encryption.
+        '';
+      };
+
+      s2sRequireEncryption = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Force servers to use encrypted connections? This option will
+          prevent servers from authenticating unless they are using encryption.
+          Note that this is different from authentication.
+        '';
+      };
+
+      s2sSecureAuth = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Force certificate authentication for server-to-server connections?
+          This provides ideal security, but requires servers you communicate
+          with to support encryption AND present valid, trusted certificates.
+          For more information see https://prosody.im/doc/s2s#security
+        '';
+      };
+
+      s2sInsecureDomains = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "insecure.example.com" ];
+        description = ''
+          Some servers have invalid or self-signed certificates. You can list
+          remote domains here that will not be required to authenticate using
+          certificates. They will be authenticated using DNS instead, even
+          when s2s_secure_auth is enabled.
+        '';
+      };
+
+      s2sSecureDomains = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "jabber.org" ];
+        description = ''
+          Even if you leave s2s_secure_auth disabled, you can still require valid
+          certificates for some domains by specifying a list here.
+        '';
+      };
+
+
       modules = moduleOpts;
 
       extraModules = mkOption {
@@ -206,6 +362,12 @@ in
         description = "Enable custom modules";
       };
 
+      extraPluginPaths = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        description = "Addtional path in which to look find plugins/modules";
+      };
+
       virtualHosts = mkOption {
 
         description = "Define the virtual hosts";
@@ -255,37 +417,47 @@ in
 
   config = mkIf cfg.enable {
 
-    environment.systemPackages = [ pkgs.prosody ];
+    environment.systemPackages = [ cfg.package ];
 
     environment.etc."prosody/prosody.cfg.lua".text = ''
 
       pidfile = "/var/lib/prosody/prosody.pid"
 
-
       log = "*syslog"
 
       data_path = "/var/lib/prosody"
-
-      allow_registration = ${boolToString cfg.allowRegistration};
-
-      ${ optionalString cfg.modules.console "console_enabled = true;" }
+      plugin_paths = {
+        ${lib.concatStringsSep ", " (map (n: "\"${n}\"") cfg.extraPluginPaths) }
+      }
 
       ${ optionalString  (cfg.ssl != null) (createSSLOptsStr cfg.ssl) }
 
-      admins = { ${lib.concatStringsSep ", " (map (n: "\"${n}\"") cfg.admins) } };
+      admins = ${toLua cfg.admins}
+
+      -- we already build with libevent, so we can just enable it for a more performant server
+      use_libevent = true
 
       modules_enabled = {
 
         ${ lib.concatStringsSep "\n\ \ " (lib.mapAttrsToList
-          (name: val: optionalString val ''"${name}";'')
+          (name: val: optionalString val "${toLua name};")
         cfg.modules) }
+        ${ lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.package.communityModules)}
+        ${ lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.extraModules)}
+      };
 
-        ${ optionalString cfg.allowRegistration "\"register\"\;" }
+      allow_registration = ${toLua cfg.allowRegistration}
 
-        ${ lib.concatStringsSep "\n" (map (x: "\"${x}\";") cfg.extraModules)}
+      c2s_require_encryption = ${toLua cfg.c2sRequireEncryption}
+
+      s2s_require_encryption = ${toLua cfg.s2sRequireEncryption}
+
+      s2s_secure_auth = ${toLua cfg.s2sSecureAuth}
+
+      s2s_insecure_domains = ${toLua cfg.s2sInsecureDomains}
+
+      s2s_secure_domains = ${toLua cfg.s2sSecureDomains}
 
-        "posix";
-      };
 
       ${ cfg.extraConfig }
 
diff --git a/nixos/release.nix b/nixos/release.nix
index 0b8d7318cd8..9b4aa4b0399 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -344,6 +344,7 @@ in rec {
   tests.predictable-interface-names = callSubTests tests/predictable-interface-names.nix {};
   tests.printing = callTest tests/printing.nix {};
   tests.prometheus = callTest tests/prometheus.nix {};
+  tests.prosody = callTest tests/prosody.nix {};
   tests.proxy = callTest tests/proxy.nix {};
   # tests.quagga = callTest tests/quagga.nix {};
   tests.quake3 = callTest tests/quake3.nix {};
diff --git a/nixos/tests/prosody.nix b/nixos/tests/prosody.nix
new file mode 100644
index 00000000000..fcebfaf74e1
--- /dev/null
+++ b/nixos/tests/prosody.nix
@@ -0,0 +1,75 @@
+import ./make-test.nix {
+  name = "prosody";
+
+  machine = { config, pkgs, ... }: {
+    services.prosody = {
+      enable = true;
+      # TODO: use a self-signed certificate
+      c2sRequireEncryption = false;
+    };
+    environment.systemPackages = let
+      sendMessage = pkgs.writeScriptBin "send-message" ''
+        #!/usr/bin/env python3
+        # Based on the sleekxmpp send_client example, look there for more details:
+        # https://github.com/fritzy/SleekXMPP/blob/develop/examples/send_client.py
+        import sleekxmpp
+
+        class SendMsgBot(sleekxmpp.ClientXMPP):
+            """
+            A basic SleekXMPP bot that will log in, send a message,
+            and then log out.
+            """
+            def __init__(self, jid, password, recipient, message):
+                sleekxmpp.ClientXMPP.__init__(self, jid, password)
+
+                self.recipient = recipient
+                self.msg = message
+
+                self.add_event_handler("session_start", self.start, threaded=True)
+
+            def start(self, event):
+                self.send_presence()
+                self.get_roster()
+
+                self.send_message(mto=self.recipient,
+                                  mbody=self.msg,
+                                  mtype='chat')
+
+                self.disconnect(wait=True)
+
+
+        if __name__ == '__main__':
+            xmpp = SendMsgBot("test1@localhost", "test1", "test2@localhost", "Hello World!")
+            xmpp.register_plugin('xep_0030') # Service Discovery
+            xmpp.register_plugin('xep_0199') # XMPP Ping
+
+            # TODO: verify certificate
+            # If you want to verify the SSL certificates offered by a server:
+            # xmpp.ca_certs = "path/to/ca/cert"
+
+            if xmpp.connect(('localhost', 5222)):
+                xmpp.process(block=True)
+            else:
+                print("Unable to connect.")
+                sys.exit(1)
+      '';
+    in [ (pkgs.python3.withPackages (ps: [ ps.sleekxmpp ])) sendMessage ];
+  };
+
+  testScript = ''
+    $machine->waitForUnit('prosody.service');
+    $machine->succeed('prosodyctl status') =~ /Prosody is running/;
+
+    # set password to 'test' (it's asked twice)
+    $machine->succeed('yes test1 | prosodyctl adduser test1@localhost');
+    # set password to 'y'
+    $machine->succeed('yes | prosodyctl adduser test2@localhost');
+    # correct password to 'test2'
+    $machine->succeed('yes test2 | prosodyctl passwd test2@localhost');
+
+    $machine->succeed("send-message");
+
+    $machine->succeed('prosodyctl deluser test1@localhost');
+    $machine->succeed('prosodyctl deluser test2@localhost');
+  '';
+}
diff --git a/pkgs/servers/xmpp/prosody/default.nix b/pkgs/servers/xmpp/prosody/default.nix
index b0e3492c0da..2d0e1a529da 100644
--- a/pkgs/servers/xmpp/prosody/default.nix
+++ b/pkgs/servers/xmpp/prosody/default.nix
@@ -1,14 +1,13 @@
 { stdenv, fetchurl, libidn, openssl, makeWrapper, fetchhg
 , lua5, luasocket, luasec, luaexpat, luafilesystem, luabitop
 , withLibevent ? true, luaevent ? null
-, withZlib ? true, luazlib ? null
 , withDBI ? true, luadbi ? null
 # use withExtraLibs to add additional dependencies of community modules
 , withExtraLibs ? [ ]
+, withOnlyInstalledCommunityModules ? [ ]
 , withCommunityModules ? [ ] }:
 
 assert withLibevent -> luaevent != null;
-assert withZlib -> luazlib != null;
 assert withDBI -> luadbi != null;
 
 with stdenv.lib;
@@ -16,7 +15,6 @@ with stdenv.lib;
 let
   libs        = [ luasocket luasec luaexpat luafilesystem luabitop ]
                 ++ optional withLibevent luaevent
-                ++ optional withZlib luazlib
                 ++ optional withDBI luadbi
                 ++ withExtraLibs;
   getPath     = lib : type : "${lib}/lib/lua/${lua5.luaversion}/?.${type};${lib}/share/lua/${lua5.luaversion}/?.${type}";
@@ -27,21 +25,22 @@ let
 in
 
 stdenv.mkDerivation rec {
-  version = "0.9.12";
+  version = "0.10.0";
   name = "prosody-${version}";
 
   src = fetchurl {
     url = "http://prosody.im/downloads/source/${name}.tar.gz";
-    sha256 = "139yxqpinajl32ryrybvilh54ddb1q6s0ajjhlcs4a0rnwia6n8s";
+    sha256 = "1644jy5dk46vahmh6nna36s79k8k668sbi3qamjb4q3c4m3y853l";
   };
 
   communityModules = fetchhg {
     url = "https://hg.prosody.im/prosody-modules";
-    rev = "9a3e51f348fe";
-    sha256 = "09g4vi52rv0r3jzcm0bsgp4ngqq6iapfbxfh0l7qj36qnajp4vm6";
+    rev = "150a7bd59043";
+    sha256 = "0nfx3lngcy88nd81gb7v4kh3nz1bzsm67bxgpd2lprk54diqcrz1";
   };
 
-  buildInputs = [ lua5 makeWrapper libidn openssl ];
+  buildInputs = [ lua5 makeWrapper libidn openssl ]
+    ++ optional withDBI luadbi;
 
   configureFlags = [
     "--ostype=linux"
@@ -52,7 +51,7 @@ stdenv.mkDerivation rec {
   postInstall = ''
       ${concatMapStringsSep "\n" (module: ''
         cp -r $communityModules/mod_${module} $out/lib/prosody/modules/
-      '') withCommunityModules}
+      '') (withCommunityModules ++ withOnlyInstalledCommunityModules)}
       wrapProgram $out/bin/prosody \
         --set LUA_PATH '${luaPath};' \
         --set LUA_CPATH '${luaCPath};'
@@ -62,11 +61,13 @@ stdenv.mkDerivation rec {
         --set LUA_CPATH '${luaCPath};'
     '';
 
+  passthru.communityModules = withCommunityModules;
+
   meta = {
     description = "Open-source XMPP application server written in Lua";
     license = licenses.mit;
-    homepage = http://www.prosody.im;
+    homepage = https://prosody.im;
     platforms = platforms.linux;
-    maintainers = [ ];
+    maintainers = with maintainers; [ fpletz globin ];
   };
 }
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index ae0d11474b6..1936a57dded 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -12269,8 +12269,9 @@ with pkgs;
   hyp = callPackage ../servers/http/hyp/default.nix { };
 
   prosody = callPackage ../servers/xmpp/prosody {
-    lua5 = lua5_1;
-    inherit (lua51Packages) luasocket luasec luaexpat luafilesystem luabitop luaevent luazlib luadbi;
+    # _compat can probably be removed on next minor version after 0.10.0
+    lua5 = lua5_2_compat;
+    inherit (lua52Packages) luasocket luasec luaexpat luafilesystem luabitop luaevent luadbi;
   };
 
   biboumi = callPackage ../servers/xmpp/biboumi { };
diff --git a/pkgs/top-level/lua-packages.nix b/pkgs/top-level/lua-packages.nix
index 0cc4482f402..a23de670836 100644
--- a/pkgs/top-level/lua-packages.nix
+++ b/pkgs/top-level/lua-packages.nix
@@ -167,15 +167,14 @@ let
   };
 
   luaevent = buildLuaPackage rec {
-    version = "0.4.3";
+    version = "0.4.4";
     name = "luaevent-${version}";
-    disabled = isLua52;
 
     src = fetchFromGitHub {
       owner = "harningt";
       repo = "luaevent";
       rev = "v${version}";
-      sha256 = "1c1n2zqx5rwfwkqaq1jj8gvx1vswvbihj2sy445w28icz1xfhpik";
+      sha256 = "1krzxr0jkv3gmhpckp02byhdd9s5dd0hpyqc8irc8i79dd8x0p53";
     };
 
     preBuild = ''