Merge pull request #86067 from NinjaTrappeur/nin-sane-prosody-defaults

nixos/prosody: make module defaults comply with XEP-0423
This commit is contained in:
Florian Klink 2020-05-01 20:07:13 +02:00 committed by GitHub
commit e148a72377
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 585 additions and 81 deletions

View File

@ -1,9 +1,7 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.prosody;
sslOpts = { ... }: {
@ -30,8 +28,21 @@ let
};
};
discoOpts = {
options = {
url = mkOption {
type = types.str;
description = "URL of the endpoint you want to make discoverable";
};
description = mkOption {
type = types.str;
description = "A short description of the endpoint you want to advertise";
};
};
};
moduleOpts = {
# Generally required
# Required for compliance with https://compliance.conversations.im/about/
roster = mkOption {
type = types.bool;
default = true;
@ -69,6 +80,18 @@ let
description = "Keep multiple clients in sync";
};
csi = mkOption {
type = types.bool;
default = true;
description = "Implements the CSI protocol that allows clients to report their active/inactive state to the server";
};
cloud_notify = mkOption {
type = types.bool;
default = true;
description = "Push notifications to inform users of new messages or other pertinent information even when they have no XMPP clients online";
};
pep = mkOption {
type = types.bool;
default = true;
@ -89,10 +112,22 @@ let
vcard = mkOption {
type = types.bool;
default = true;
default = false;
description = "Allow users to set vCards";
};
vcard_legacy = mkOption {
type = types.bool;
default = true;
description = "Converts users profiles and Avatars between old and new formats";
};
bookmarks = mkOption {
type = types.bool;
default = true;
description = "Allows interop between older clients that use XEP-0048: Bookmarks in its 1.0 version and recent clients which use it in PEP";
};
# Nice to have
version = mkOption {
type = types.bool;
@ -126,10 +161,16 @@ let
mam = mkOption {
type = types.bool;
default = false;
default = true;
description = "Store messages in an archive and allow users to access it";
};
smacks = mkOption {
type = types.bool;
default = true;
description = "Allow a client to resume a disconnected session, and prevent message loss";
};
# Admin interfaces
admin_adhoc = mkOption {
type = types.bool;
@ -137,6 +178,18 @@ let
description = "Allows administration via an XMPP client that supports ad-hoc commands";
};
http_files = mkOption {
type = types.bool;
default = true;
description = "Serve static files from a directory over HTTP";
};
proxy65 = mkOption {
type = types.bool;
default = true;
description = "Enables a file transfer proxy service which clients behind NAT can use";
};
admin_telnet = mkOption {
type = types.bool;
default = false;
@ -156,12 +209,6 @@ let
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;
@ -210,13 +257,6 @@ let
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:
@ -235,6 +275,153 @@ let
};
'';
mucOpts = { ... }: {
options = {
domain = mkOption {
type = types.str;
description = "Domain name of the MUC";
};
name = mkOption {
type = types.str;
description = "The name to return in service discovery responses for the MUC service itself";
default = "Prosody Chatrooms";
};
restrictRoomCreation = mkOption {
type = types.enum [ true false "admin" "local" ];
default = false;
description = "Restrict room creation to server admins";
};
maxHistoryMessages = mkOption {
type = types.int;
default = 20;
description = "Specifies a limit on what each room can be configured to keep";
};
roomLocking = mkOption {
type = types.bool;
default = true;
description = ''
Enables room locking, which means that a room must be
configured before it can be used. Locked rooms are invisible
and cannot be entered by anyone but the creator
'';
};
roomLockTimeout = mkOption {
type = types.int;
default = 300;
description = ''
Timout after which the room is destroyed or unlocked if not
configured, in seconds
'';
};
tombstones = mkOption {
type = types.bool;
default = true;
description = ''
When a room is destroyed, it leaves behind a tombstone which
prevents the room being entered or recreated. It also allows
anyone who was not in the room at the time it was destroyed
to learn about it, and to update their bookmarks. Tombstones
prevents the case where someone could recreate a previously
semi-anonymous room in order to learn the real JIDs of those
who often join there.
'';
};
tombstoneExpiry = mkOption {
type = types.int;
default = 2678400;
description = ''
This settings controls how long a tombstone is considered
valid. It defaults to 31 days. After this time, the room in
question can be created again.
'';
};
vcard_muc = mkOption {
type = types.bool;
default = true;
description = "Adds the ability to set vCard for Multi User Chat rooms";
};
# Extra parameters. Defaulting to prosody default values.
# Adding them explicitly to make them visible from the options
# documentation.
#
# See https://prosody.im/doc/modules/mod_muc for more details.
roomDefaultPublic = mkOption {
type = types.bool;
default = true;
description = "If set, the MUC rooms will be public by default.";
};
roomDefaultMembersOnly = mkOption {
type = types.bool;
default = false;
description = "If set, the MUC rooms will only be accessible to the members by default.";
};
roomDefaultModerated = mkOption {
type = types.bool;
default = false;
description = "If set, the MUC rooms will be moderated by default.";
};
roomDefaultPublicJids = mkOption {
type = types.bool;
default = false;
description = "If set, the MUC rooms will display the public JIDs by default.";
};
roomDefaultChangeSubject = mkOption {
type = types.bool;
default = false;
description = "If set, the rooms will display the public JIDs by default.";
};
roomDefaultHistoryLength = mkOption {
type = types.int;
default = 20;
description = "Number of history message sent to participants by default.";
};
roomDefaultLanguage = mkOption {
type = types.str;
default = "en";
description = "Default room language.";
};
};
};
uploadHttpOpts = { ... }: {
options = {
domain = mkOption {
type = types.nullOr types.str;
description = "Domain name for the http-upload service";
};
uploadFileSizeLimit = mkOption {
type = types.str;
default = "50 * 1024 * 1024";
description = "Maximum file size, in bytes. Defaults to 50MB.";
};
uploadExpireAfter = mkOption {
type = types.str;
default = "60 * 60 * 24 * 7";
description = "Max age of a file before it gets deleted, in seconds.";
};
userQuota = mkOption {
type = types.nullOr types.int;
default = null;
example = 1234;
description = ''
Maximum size of all uploaded files per user, in bytes. There
will be no quota if this option is set to null.
'';
};
httpUploadPath = mkOption {
type = types.str;
description = ''
Directory where the uploaded files will be stored. By
default, uploaded files are put in a sub-directory of the
default Prosody storage path (usually /var/lib/prosody).
'';
default = "/var/lib/prosody";
};
};
};
vHostOpts = { ... }: {
options = {
@ -283,6 +470,27 @@ in
description = "Whether to enable the prosody server";
};
xmppComplianceSuite = mkOption {
type = types.bool;
default = true;
description = ''
The XEP-0423 defines a set of recommended XEPs to implement
for a server. It's generally a good idea to implement this
set of extensions if you want to provide your users with a
good XMPP experience.
This NixOS module aims to provide a "advanced server"
experience as per defined in the XEP-0423[1] specification.
Setting this option to true will prevent you from building a
NixOS configuration which won't comply with this standard.
You can explicitely decide to ignore this standard if you
know what you are doing by setting this option to false.
[1] https://xmpp.org/extensions/xep-0423.html
'';
};
package = mkOption {
type = types.package;
description = "Prosody package to use";
@ -302,6 +510,12 @@ in
default = "/var/lib/prosody";
};
disco_items = mkOption {
type = types.listOf (types.submodule discoOpts);
default = [];
description = "List of discoverable items you want to advertise.";
};
user = mkOption {
type = types.str;
default = "prosody";
@ -320,6 +534,31 @@ in
description = "Allow account creation";
};
# HTTP server-related options
httpPorts = mkOption {
type = types.listOf types.int;
description = "Listening HTTP ports list for this service.";
default = [ 5280 ];
};
httpInterfaces = mkOption {
type = types.listOf types.str;
default = [ "*" "::" ];
description = "Interfaces on which the HTTP server will listen on.";
};
httpsPorts = mkOption {
type = types.listOf types.int;
description = "Listening HTTPS ports list for this service.";
default = [ 5281 ];
};
httpsInterfaces = mkOption {
type = types.listOf types.str;
default = [ "*" "::" ];
description = "Interfaces on which the HTTPS server will listen on.";
};
c2sRequireEncryption = mkOption {
type = types.bool;
default = true;
@ -387,6 +626,26 @@ in
description = "Addtional path in which to look find plugins/modules";
};
uploadHttp = mkOption {
description = ''
Configures the Prosody builtin HTTP server to handle user uploads.
'';
type = types.nullOr (types.submodule uploadHttpOpts);
default = null;
example = {
domain = "uploads.my-xmpp-example-host.org";
};
};
muc = mkOption {
type = types.listOf (types.submodule mucOpts);
default = [ ];
example = [ {
domain = "conference.my-xmpp-example-host.org";
} ];
description = "Multi User Chat (MUC) configuration";
};
virtualHosts = mkOption {
description = "Define the virtual hosts";
@ -443,9 +702,44 @@ in
config = mkIf cfg.enable {
assertions = let
genericErrMsg = ''
Having a server not XEP-0423-compliant might make your XMPP
experience terrible. See the NixOS manual for further
informations.
If you know what you're doing, you can disable this warning by
setting config.services.prosody.xmppComplianceSuite to false.
'';
errors = [
{ assertion = (builtins.length cfg.muc > 0) || !cfg.xmppComplianceSuite;
message = ''
You need to setup at least a MUC domain to comply with
XEP-0423.
'' + genericErrMsg;}
{ assertion = cfg.uploadHttp != null || !cfg.xmppComplianceSuite;
message = ''
You need to setup the uploadHttp module through
config.services.prosody.uploadHttp to comply with
XEP-0423.
'' + genericErrMsg;}
];
in errors;
environment.systemPackages = [ cfg.package ];
environment.etc."prosody/prosody.cfg.lua".text = ''
environment.etc."prosody/prosody.cfg.lua".text =
let
httpDiscoItems = if (cfg.uploadHttp != null)
then [{ url = cfg.uploadHttp.domain; description = "HTTP upload endpoint";}]
else [];
mucDiscoItems = builtins.foldl'
(acc: muc: [{ url = muc.domain; description = "${muc.domain} MUC endpoint";}] ++ acc)
[]
cfg.muc;
discoItems = cfg.disco_items ++ httpDiscoItems ++ mucDiscoItems;
in ''
pidfile = "/run/prosody/prosody.pid"
@ -472,6 +766,10 @@ in
${ lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.extraModules)}
};
disco_items = {
${ lib.concatStringsSep "\n" (builtins.map (x: ''{ "${x.url}", "${x.description}"};'') discoItems)}
};
allow_registration = ${toLua cfg.allowRegistration}
c2s_require_encryption = ${toLua cfg.c2sRequireEncryption}
@ -486,6 +784,42 @@ in
authentication = ${toLua cfg.authentication}
http_interfaces = ${toLua cfg.httpInterfaces}
https_interfaces = ${toLua cfg.httpsInterfaces}
http_ports = ${toLua cfg.httpPorts}
https_ports = ${toLua cfg.httpsPorts}
${lib.concatMapStrings (muc: ''
Component ${toLua muc.domain} "muc"
modules_enabled = { "muc_mam"; ${optionalString muc.vcard_muc ''"vcard_muc";'' } }
name = ${toLua muc.name}
restrict_room_creation = ${toLua muc.restrictRoomCreation}
max_history_messages = ${toLua muc.maxHistoryMessages}
muc_room_locking = ${toLua muc.roomLocking}
muc_room_lock_timeout = ${toLua muc.roomLockTimeout}
muc_tombstones = ${toLua muc.tombstones}
muc_tombstone_expiry = ${toLua muc.tombstoneExpiry}
muc_room_default_public = ${toLua muc.roomDefaultPublic}
muc_room_default_members_only = ${toLua muc.roomDefaultMembersOnly}
muc_room_default_moderated = ${toLua muc.roomDefaultModerated}
muc_room_default_public_jids = ${toLua muc.roomDefaultPublicJids}
muc_room_default_change_subject = ${toLua muc.roomDefaultChangeSubject}
muc_room_default_history_length = ${toLua muc.roomDefaultHistoryLength}
muc_room_default_language = ${toLua muc.roomDefaultLanguage}
'') cfg.muc}
${ lib.optionalString (cfg.uploadHttp != null) ''
Component ${toLua cfg.uploadHttp.domain} "http_upload"
http_upload_file_size_limit = ${cfg.uploadHttp.uploadFileSizeLimit}
http_upload_expire_after = ${cfg.uploadHttp.uploadExpireAfter}
${lib.optionalString (cfg.uploadHttp.userQuota != null) "http_upload_quota = ${toLua cfg.uploadHttp.userQuota}"}
http_upload_path = ${toLua cfg.uploadHttp.httpUploadPath}
''}
${ cfg.extraConfig }
${ lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: ''
@ -522,9 +856,22 @@ in
PIDFile = "/run/prosody/prosody.pid";
ExecStart = "${cfg.package}/bin/prosodyctl start";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
MemoryDenyWriteExecute = true;
PrivateDevices = true;
PrivateMounts = true;
PrivateTmp = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
};
};
};
meta.doc = ./prosody.xml;
}

View File

@ -0,0 +1,88 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="module-services-prosody">
<title>Prosody</title>
<para>
<link xlink:href="https://prosody.im/">Prosody</link> is an open-source, modern XMPP server.
</para>
<section xml:id="module-services-prosody-basic-usage">
<title>Basic usage</title>
<para>
A common struggle for most XMPP newcomers is to find the right set
of XMPP Extensions (XEPs) to setup. Forget to activate a few of
those and your XMPP experience might turn into a nightmare!
</para>
<para>
The XMPP community tackles this problem by creating a meta-XEP
listing a decent set of XEPs you should implement. This meta-XEP
is issued every year, the 2020 edition being
<link xlink:href="https://xmpp.org/extensions/xep-0423.html">XEP-0423</link>.
</para>
<para>
The NixOS Prosody module will implement most of these recommendend XEPs out of
the box. That being said, two components still require some
manual configuration: the
<link xlink:href="https://xmpp.org/extensions/xep-0045.html">Multi User Chat (MUC)</link>
and the <link xlink:href="https://xmpp.org/extensions/xep-0363.html">HTTP File Upload</link> ones.
You'll need to create a DNS subdomain for each of those. The current convention is to name your
MUC endpoint <literal>conference.example.org</literal> and your HTTP upload domain <literal>upload.example.org</literal>.
</para>
<para>
A good configuration to start with, including a
<link xlink:href="https://xmpp.org/extensions/xep-0045.html">Multi User Chat (MUC)</link>
endpoint as well as a <link xlink:href="https://xmpp.org/extensions/xep-0363.html">HTTP File Upload</link>
endpoint will look like this:
<programlisting>
services.prosody = {
<link linkend="opt-services.prosody.enable">enable</link> = true;
<link linkend="opt-services.prosody.admins">admins</link> = [ "root@example.org" ];
<link linkend="opt-services.prosody.ssl.cert">ssl.cert</link> = "/var/lib/acme/example.org/fullchain.pem";
<link linkend="opt-services.prosody.ssl.key">ssl.key</link> = "/var/lib/acme/example.org/key.pem";
<link linkend="opt-services.prosody.virtualHosts">virtualHosts</link>."example.org" = {
<link linkend="opt-services.prosody.virtualHosts._name__.enabled">enabled</link> = true;
<link linkend="opt-services.prosody.virtualHosts._name__.domain">domain</link> = "example.org";
<link linkend="opt-services.prosody.virtualHosts._name__.ssl.cert">ssl.cert</link> = "/var/lib/acme/example.org/fullchain.pem";
<link linkend="opt-services.prosody.virtualHosts._name__.ssl.key">ssl.key</link> = "/var/lib/acme/example.org/key.pem";
};
<link linkend="opt-services.prosody.muc">muc</link> = [ {
<link linkend="opt-services.prosody.muc">domain</link> = "conference.example.org";
} ];
<link linkend="opt-services.prosody.uploadHttp">uploadHttp</link> = {
<link linkend="opt-services.prosody.uploadHttp.domain">domain</link> = "upload.example.org";
};
};</programlisting>
</para>
</section>
<section xml:id="module-services-prosody-letsencrypt">
<title>Let's Encrypt Configuration</title>
<para>
As you can see in the code snippet from the
<link linkend="module-services-prosody-basic-usage">previous section</link>,
you'll need a single TLS certificate covering your main endpoint,
the MUC one as well as the HTTP Upload one. We can generate such a
certificate by leveraging the ACME
<link linkend="opt-security.acme.certs._name_.extraDomains">extraDomains</link> module option.
</para>
<para>
Provided the setup detailed in the previous section, you'll need the following acme configuration to generate
a TLS certificate for the three endponits:
<programlisting>
security.acme = {
<link linkend="opt-security.acme.email">email</link> = "root@example.org";
<link linkend="opt-security.acme.acceptTerms">acceptTerms</link> = true;
<link linkend="opt-security.acme.certs">certs</link> = {
"example.org" = {
<link linkend="opt-security.acme.certs._name_.webroot">webroot</link> = "/var/www/example.org";
<link linkend="opt-security.acme.certs._name_.email">email</link> = "root@example.org";
<link linkend="opt-security.acme.certs._name_.extraDomains">extraDomains."conference.example.org"</link> = null;
<link linkend="opt-security.acme.certs._name_.extraDomains">extraDomains."upload.example.org"</link> = null;
};
};
};</programlisting>
</para>
</section>
</chapter>

View File

@ -1,27 +1,80 @@
import ../make-test-python.nix {
name = "prosody";
let
cert = pkgs: pkgs.runCommandNoCC "selfSignedCerts" { buildInputs = [ pkgs.openssl ]; } ''
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -subj '/CN=example.com/CN=uploads.example.com/CN=conference.example.com'
mkdir -p $out
cp key.pem cert.pem $out
'';
createUsers = pkgs: pkgs.writeScriptBin "create-prosody-users" ''
#!${pkgs.bash}/bin/bash
set -e
# Creates and set password for the 2 xmpp test users.
#
# Doing that in a bash script instead of doing that in the test
# script allow us to easily provision the users when running that
# test interactively.
prosodyctl register cthon98 example.com nothunter2
prosodyctl register azurediamond example.com hunter2
'';
delUsers = pkgs: pkgs.writeScriptBin "delete-prosody-users" ''
#!${pkgs.bash}/bin/bash
set -e
# Deletes the test users.
#
# Doing that in a bash script instead of doing that in the test
# script allow us to easily provision the users when running that
# test interactively.
prosodyctl deluser cthon98@example.com
prosodyctl deluser azurediamond@example.com
'';
in import ../make-test-python.nix {
name = "prosody";
nodes = {
client = { nodes, pkgs, ... }: {
client = { nodes, pkgs, config, ... }: {
security.pki.certificateFiles = [ "${cert pkgs}/cert.pem" ];
console.keyMap = "fr-bepo";
networking.extraHosts = ''
${nodes.server.config.networking.primaryIPAddress} example.com
${nodes.server.config.networking.primaryIPAddress} conference.example.com
${nodes.server.config.networking.primaryIPAddress} uploads.example.com
'';
environment.systemPackages = [
(pkgs.callPackage ./xmpp-sendmessage.nix { connectTo = nodes.server.config.networking.primaryIPAddress; })
];
};
server = { config, pkgs, ... }: {
security.pki.certificateFiles = [ "${cert pkgs}/cert.pem" ];
console.keyMap = "fr-bepo";
networking.extraHosts = ''
${config.networking.primaryIPAddress} example.com
${config.networking.primaryIPAddress} conference.example.com
${config.networking.primaryIPAddress} uploads.example.com
'';
networking.firewall.enable = false;
environment.systemPackages = [
(createUsers pkgs)
(delUsers pkgs)
];
services.prosody = {
enable = true;
# TODO: use a self-signed certificate
c2sRequireEncryption = false;
extraConfig = ''
storage = "sql"
'';
virtualHosts.test = {
ssl.cert = "${cert pkgs}/cert.pem";
ssl.key = "${cert pkgs}/key.pem";
virtualHosts.example = {
domain = "example.com";
enabled = true;
ssl.cert = "${cert pkgs}/cert.pem";
ssl.key = "${cert pkgs}/key.pem";
};
muc = [
{
domain = "conference.example.com";
}
];
uploadHttp = {
domain = "uploads.example.com";
};
};
};
@ -31,16 +84,8 @@ import ../make-test-python.nix {
server.wait_for_unit("prosody.service")
server.succeed('prosodyctl status | grep "Prosody is running"')
# set password to 'nothunter2' (it's asked twice)
server.succeed("yes nothunter2 | prosodyctl adduser cthon98@example.com")
# set password to 'y'
server.succeed("yes | prosodyctl adduser azurediamond@example.com")
# correct password to "hunter2"
server.succeed("yes hunter2 | prosodyctl passwd azurediamond@example.com")
client.succeed("send-message")
server.succeed("prosodyctl deluser cthon98@example.com")
server.succeed("prosodyctl deluser azurediamond@example.com")
server.succeed("create-prosody-users")
client.succeed('send-message 2>&1 | grep "XMPP SCRIPT TEST SUCCESS"')
server.succeed("delete-prosody-users")
'';
}

View File

@ -1,46 +1,61 @@
{ writeScriptBin, python3, connectTo ? "localhost" }:
writeScriptBin "send-message" ''
#!${(python3.withPackages (ps: [ ps.sleekxmpp ])).interpreter}
# 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
{ writeScriptBin, writeText, python3, connectTo ? "localhost" }:
let
dummyFile = writeText "dummy-file" ''
Dear dog,
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)
Please find this *really* important attachment.
self.recipient = recipient
self.msg = message
Yours truly,
John
'';
in writeScriptBin "send-message" ''
#!${(python3.withPackages (ps: [ ps.slixmpp ])).interpreter}
import logging
import sys
from types import MethodType
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)
from slixmpp import ClientXMPP
from slixmpp.exceptions import IqError, IqTimeout
if __name__ == '__main__':
xmpp = SendMsgBot("cthon98@example.com", "nothunter2", "azurediamond@example.com", "hey, if you type in your pw, it will show as stars")
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0199') # XMPP Ping
class CthonTest(ClientXMPP):
# TODO: verify certificate
# If you want to verify the SSL certificates offered by a server:
# xmpp.ca_certs = "path/to/ca/cert"
def __init__(self, jid, password):
ClientXMPP.__init__(self, jid, password)
self.add_event_handler("session_start", self.session_start)
if xmpp.connect(('${connectTo}', 5222)):
xmpp.process(block=True)
else:
print("Unable to connect.")
sys.exit(1)
async def session_start(self, event):
log = logging.getLogger(__name__)
self.send_presence()
self.get_roster()
# Sending a test message
self.send_message(mto="azurediamond@example.com", mbody="Hello, this is dog.", mtype="chat")
log.info('Message sent')
# Test http upload (XEP_0363)
def timeout_callback(arg):
log.error("ERROR: Cannot upload file. XEP_0363 seems broken")
sys.exit(1)
url = await self['xep_0363'].upload_file("${dummyFile}",timeout=10, timeout_callback=timeout_callback)
log.info('Upload success!')
# Test MUC
self.plugin['xep_0045'].join_muc('testMucRoom', 'cthon98', wait=True)
log.info('MUC join success!')
log.info('XMPP SCRIPT TEST SUCCESS')
self.disconnect(wait=True)
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG,
format='%(levelname)-8s %(message)s')
ct = CthonTest('cthon98@example.com', 'nothunter2')
ct.register_plugin('xep_0071')
ct.register_plugin('xep_0128')
# HTTP Upload
ct.register_plugin('xep_0363')
# MUC
ct.register_plugin('xep_0045')
ct.connect(("server", 5222))
ct.process(forever=False)
''

View File

@ -1,4 +1,4 @@
{ stdenv, fetchurl, libidn, openssl, makeWrapper, fetchhg
{ stdenv, fetchurl, lib, libidn, openssl, makeWrapper, fetchhg
, lua5, luasocket, luasec, luaexpat, luafilesystem, luabitop
, withLibevent ? true, luaevent ? null
, withDBI ? true, luadbi ? null
@ -16,7 +16,16 @@ with stdenv.lib;
stdenv.mkDerivation rec {
version = "0.11.5"; # also update communityModules
pname = "prosody";
# The following community modules are necessary for the nixos module
# prosody module to comply with XEP-0423 and provide a working
# default setup.
nixosModuleDeps = [
"bookmarks"
"cloud_notify"
"vcard_muc"
"smacks"
"http_upload"
];
src = fetchurl {
url = "https://prosody.im/downloads/source/${pname}-${version}.tar.gz";
sha256 = "12s0hn6hvjbi61cdw3165l6iw0878971dmlvfg663byjsmjvvy2m";
@ -52,7 +61,7 @@ stdenv.mkDerivation rec {
postInstall = ''
${concatMapStringsSep "\n" (module: ''
cp -r $communityModules/mod_${module} $out/lib/prosody/modules/
'') (withCommunityModules ++ withOnlyInstalledCommunityModules)}
'') (lib.lists.unique(nixosModuleDeps ++ withCommunityModules ++ withOnlyInstalledCommunityModules))}
wrapProgram $out/bin/prosody \
--prefix LUA_PATH ';' "$LUA_PATH" \
--prefix LUA_CPATH ';' "$LUA_CPATH"