From 90870d90e4bf3d503f7cfc6627bd02706b5fc1fc Mon Sep 17 00:00:00 2001 From: Alexander Renz Date: Wed, 26 Nov 2025 20:27:04 +0100 Subject: [PATCH] docs: Simplify XMPP integration - replace detailed Prosody/Ejabberd configs with standard XEP-0363 info --- README.md | 334 +++--------------------------------------------------- 1 file changed, 13 insertions(+), 321 deletions(-) diff --git a/README.md b/README.md index d0e1dfa..977eb82 100644 --- a/README.md +++ b/README.md @@ -185,8 +185,7 @@ Test Coverage: - [Podman Deployment](#podman-deployment) - [Nginx Reverse Proxy](#nginx-reverse-proxy) - [Apache2 Reverse Proxy](#apache2-reverse-proxy) -- [Prosody XMPP Integration](#prosody-xmpp-integration) -- [Ejabberd XMPP Integration](#ejabberd-xmpp-integration) +- [XMPP Server Integration](#xmpp-server-integration) - [XEP-0363 Implementation](#xep-0363-implementation) - [API Versions (V1, V2, V3)](#api-versions) @@ -1521,334 +1520,27 @@ server { --- -## Prosody XMPP Integration +## XMPP Server Integration -### Prosody Configuration -```lua --- /etc/prosody/prosody.cfg.lua --- HMAC File Server integration for XEP-0363 +HMAC File Server implements the standard **XEP-0363: HTTP File Upload** protocol and works out-of-the-box with all XMPP servers including Prosody, Ejabberd, Openfire, and others. --- Enable HTTP file upload module -modules_enabled = { - -- Core modules - "roster"; - "saslauth"; - "tls"; - "dialback"; - "disco"; - "carbons"; - "pep"; - "private"; - "blocklist"; - "vcard4"; - "vcard_legacy"; - "version"; - "uptime"; - "time"; - "ping"; - "admin_adhoc"; +### Quick Setup - -- HTTP file upload - "http_upload_external"; -} +Configure your XMPP server's `http_upload_external` module to point to your HMAC File Server: --- VirtualHost configuration -VirtualHost "example.com" - enabled = true - - -- SSL configuration - ssl = { - key = "/etc/prosody/certs/example.com.key"; - certificate = "/etc/prosody/certs/example.com.crt"; - } - - -- HTTP file upload configuration - http_upload_external_base_url = "https://files.example.com" - http_upload_external_secret = "your-very-secret-hmac-key" - http_upload_external_file_size_limit = 10737418240 -- 10GB - http_upload_external_quota = 1073741824000 -- 1TB per user - - -- Custom upload URL patterns (for HMAC File Server) - http_upload_external_put_url = "https://files.example.com/upload/{filename}" - http_upload_external_get_url = "https://files.example.com/download/{filename}" - --- Component for file upload service -Component "upload.example.com" "http_upload_external" - http_upload_external_base_url = "https://files.example.com" - http_upload_external_secret = "your-very-secret-hmac-key" - http_upload_external_file_size_limit = 10737418240 - --- Logging -log = { - info = "/var/log/prosody/prosody.log"; - error = "/var/log/prosody/prosody.err"; - "*syslog"; -} -``` - -### Prosody Module Configuration -```lua --- /usr/lib/prosody/modules/mod_http_upload_external.lua --- Custom module for HMAC File Server integration - -local hmac_sha256 = require "util.hashes".hmac_sha256; -local base64 = require "util.encodings".base64; -local uuid = require "util.uuid".generate; -local http = require "net.http"; - -module:depends("disco"); - -local external_base_url = module:get_option_string("http_upload_external_base_url"); -local external_secret = module:get_option_string("http_upload_external_secret"); -local file_size_limit = module:get_option_number("http_upload_external_file_size_limit", 100*1024*1024); -local quota = module:get_option_number("http_upload_external_quota", 1024*1024*1024); - --- XEP-0363 disco feature -module:add_feature("urn:xmpp:http:upload:0"); - --- Handle upload requests -function handle_upload_request(event) - local stanza = event.stanza; - local filename = stanza:get_child_text("filename", "urn:xmpp:http:upload:0"); - local filesize = tonumber(stanza:get_child_text("size", "urn:xmpp:http:upload:0")); - local content_type = stanza:get_child_text("content-type", "urn:xmpp:http:upload:0") or "application/octet-stream"; - - if not filename or not filesize then - return st.error_reply(stanza, "modify", "bad-request", "Missing filename or size"); - end - - if filesize > file_size_limit then - return st.error_reply(stanza, "modify", "not-acceptable", "File too large"); - end - - -- Generate HMAC authentication - local timestamp = os.time(); - local upload_id = uuid(); - local message = filename .. filesize .. timestamp .. upload_id; - local signature = base64.encode(hmac_sha256(external_secret, message)); - - -- Construct URLs - local put_url = string.format("%s/upload?filename=%s×tamp=%d&uploadid=%s&signature=%s", - external_base_url, - filename, - timestamp, - upload_id, - signature - ); - - local get_url = string.format("%s/download/%s", external_base_url, filename); - - -- Return slot - local reply = st.reply(stanza) - :tag("slot", {xmlns="urn:xmpp:http:upload:0"}) - :tag("put", {url=put_url}):up() - :tag("get", {url=get_url}):up() - :up(); - - return reply; -end - -module:hook("iq-get/host/urn:xmpp:http:upload:0:request", handle_upload_request); -``` - ---- - -## Ejabberd XMPP Integration - -### Ejabberd Configuration ```yaml -# /etc/ejabberd/ejabberd.yml -# HMAC File Server integration - -hosts: - - "example.com" - -listen: - - - port: 5222 - ip: "::" - module: ejabberd_c2s - starttls: true - certfile: "/etc/ejabberd/certs/example.com.pem" - - - - port: 5269 - ip: "::" - module: ejabberd_s2s_in - - - - port: 5443 - ip: "::" - module: ejabberd_http - tls: true - certfile: "/etc/ejabberd/certs/example.com.pem" - request_handlers: - "/upload": mod_http_upload - "/admin": ejabberd_web_admin - "/api": mod_http_api - -modules: - mod_adhoc: {} - mod_admin_extra: {} - mod_announce: {} - mod_avatar: {} - mod_blocking: {} - mod_bosh: {} - mod_caps: {} - mod_carboncopy: {} - mod_client_state: {} - mod_configure: {} - mod_disco: {} - mod_fail2ban: {} - mod_http_api: {} - mod_http_upload: - put_url: "https://files.example.com/upload" - get_url: "https://files.example.com/download" - external_secret: "your-very-secret-hmac-key" - max_size: 10737418240 # 10GB - thumbnail: false - custom_headers: - "Access-Control-Allow-Origin": "*" - "Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS" - "Access-Control-Allow-Headers": "Content-Type" - mod_last: {} - mod_mam: {} - mod_mqtt: {} - mod_muc: {} - mod_muc_admin: {} - mod_offline: {} - mod_ping: {} - mod_privacy: {} - mod_private: {} - mod_proxy65: {} - mod_pubsub: {} - mod_push: {} - mod_register: {} - mod_roster: {} - mod_shared_roster: {} - mod_stats: {} - mod_time: {} - mod_vcard: {} - mod_version: {} - -# Authentication -auth_method: internal - -# Database -default_db: mnesia - -# Access rules -access_rules: - local: - - allow: local - c2s: - - deny: blocked - - allow - announce: - - allow: admin - configure: - - allow: admin - muc_create: - - allow: local - pubsub_createnode: - - allow: local - register: - - allow - trusted_network: - - allow: loopback - -# ACL -acl: - local: - user_regexp: "" - loopback: - ip: - - "127.0.0.0/8" - - "::1/128" - - "::FFFF:127.0.0.1/128" - admin: - user: - - "admin@example.com" - -# Logging -loglevel: 4 -log_rotate_size: 10485760 -log_rotate_count: 5 +# Standard XEP-0363 configuration (works with any XMPP server) +http_upload_external: + base_url: "https://files.example.com" + secret: "your-shared-hmac-secret" + max_file_size: 10737418240 # 10GB ``` -### Custom Ejabberd HTTP Upload Module -```erlang -% /opt/ejabberd/lib/ejabberd-23.01/ebin/mod_http_upload_external.erl -% Custom module for HMAC File Server integration +The server handles all the HMAC authentication and file management automatically. No custom modules required. --module(mod_http_upload_external). --author('admin@example.com'). +### Experimental Custom Modules --behaviour(gen_mod). - --export([start/2, stop/1, process_iq/1, mod_opt_type/1, mod_options/1]). - --include("ejabberd.hrl"). --include("logger.hrl"). --include("xmpp.hrl"). - -start(Host, Opts) -> - gen_iq_handler:add_iq_handler(ejabberd_local, Host, - ?NS_HTTP_UPLOAD_0, ?MODULE, - process_iq). - -stop(Host) -> - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_HTTP_UPLOAD_0). - -process_iq(#iq{type = get, sub_els = [#upload_request{filename = Filename, - size = Size, - 'content-type' = ContentType}]} = IQ) -> - Host = ejabberd_config:get_myname(), - - % Get configuration - PutURL = gen_mod:get_module_opt(Host, ?MODULE, put_url), - GetURL = gen_mod:get_module_opt(Host, ?MODULE, get_url), - Secret = gen_mod:get_module_opt(Host, ?MODULE, external_secret), - MaxSize = gen_mod:get_module_opt(Host, ?MODULE, max_size), - - % Validate file size - case Size =< MaxSize of - true -> - % Generate HMAC signature - Timestamp = erlang:system_time(second), - UploadId = uuid:uuid_to_string(uuid:get_v4()), - Message = <>, - Signature = base64:encode(crypto:mac(hmac, sha256, Secret, Message)), - - % Construct URLs - PutURLFinal = <>, - - % Return slot - Slot = #upload_slot{get = GetURLFinal, put = PutURLFinal}, - xmpp:make_iq_result(IQ, Slot); - false -> - xmpp:make_error(IQ, xmpp:err_not_acceptable(<<"File too large">>, ?MYLANG)) - end; - -process_iq(IQ) -> - xmpp:make_error(IQ, xmpp:err_bad_request()). - -mod_opt_type(put_url) -> fun iolist_to_binary/1; -mod_opt_type(get_url) -> fun iolist_to_binary/1; -mod_opt_type(external_secret) -> fun iolist_to_binary/1; -mod_opt_type(max_size) -> fun(I) when is_integer(I), I > 0 -> I end. - -mod_options(_Host) -> - [{put_url, <<"">>}, - {get_url, <<"">>}, - {external_secret, <<"">>}, - {max_size, 104857600}]. -``` +Advanced users can explore experimental Prosody and Ejabberd modules in the `ejabberd-module/` directory. These are **development stage** and require additional testing. The standard XEP-0363 implementation is recommended for production use. ---