docs: Simplify XMPP integration - replace detailed Prosody/Ejabberd configs with standard XEP-0363 info
This commit is contained in:
334
README.md
334
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 = <<Filename/binary, (integer_to_binary(Size))/binary,
|
||||
(integer_to_binary(Timestamp))/binary, UploadId/binary>>,
|
||||
Signature = base64:encode(crypto:mac(hmac, sha256, Secret, Message)),
|
||||
|
||||
% Construct URLs
|
||||
PutURLFinal = <<PutURL/binary, "?filename=", Filename/binary,
|
||||
"×tamp=", (integer_to_binary(Timestamp))/binary,
|
||||
"&uploadid=", UploadId/binary,
|
||||
"&signature=", Signature/binary>>,
|
||||
GetURLFinal = <<GetURL/binary, "/", Filename/binary>>,
|
||||
|
||||
% 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.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user