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:
external module.
+
+
+ The Prosody XMPP server has received a major update. The following modules were renamed:
+
+
+
+ is now
+
+
+
+
+ is now
+
+
+
+
+
+
+ Many new modules are now core modules, most notably
+ and .
+
+
+
+ The better-performing libevent backend is now enabled by default.
+
+
+
+ withCommunityModules now passes through the modules to .
+ Use withOnlyInstalledCommunityModules for modules that should not be enabled directly, e.g lib_ldap.
+
+
+
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 = false;
- description = "telnet to port 5582";
+ default = true;
+ description = "Allow users to register on this server using a client and change passwords";
};
+ mam = mkOption {
+ type = types.bool;
+ default = false;
+ 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 {
- type = types.bool;
- default = false;
- description = "Serve static files from a directory over HTTP";
- };
-
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";
+ };
+
+ # Other specific functionality
+ limits = mkOption {
+ type = types.bool;
+ default = false;
+ 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,38 +417,48 @@ 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) }
-
- ${ optionalString cfg.allowRegistration "\"register\"\;" }
-
- ${ lib.concatStringsSep "\n" (map (x: "\"${x}\";") cfg.extraModules)}
-
- "posix";
+ ${ lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.package.communityModules)}
+ ${ lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.extraModules)}
};
+ allow_registration = ${toLua cfg.allowRegistration}
+
+ 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}
+
+
${ cfg.extraConfig }
${ lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: ''
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 = ''