Mercurial > prosody-modules
view mod_http_upload_external/README.md @ 6257:fa45ae704b79
mod_cloud_notify: Update Readme
diff --git a/mod_cloud_notify/README.md b/mod_cloud_notify/README.md
--- a/mod_cloud_notify/README.md
+++ b/mod_cloud_notify/README.md
@@ -1,109 +1,106 @@
----
-labels:
-- 'Stage-Beta'
-summary: 'XEP-0357: Cloud push notifications'
----
+# Introduction
-Introduction
-============
+This module enables support for sending "push notifications" to clients
+that need it, typically those running on certain mobile devices.
-This module enables support for sending "push notifications" to clients that
-need it, typically those running on certain mobile devices.
+As well as this module, your client must support push notifications (the
+apps that need it generally do, of course) and the app developer's push
+gateway must be reachable from your Prosody server (this happens over a
+normal XMPP server-to-server 's2s' connection).
-As well as this module, your client must support push notifications (the apps
-that need it generally do, of course) and the app developer's push gateway
-must be reachable from your Prosody server (this happens over a normal XMPP
-server-to-server 's2s' connection).
-
-Details
-=======
+# Details
Some platforms, notably Apple's iOS and many versions of Android, impose
-limits that prevent applications from running or accessing the network in the
-background. This makes it difficult or impossible for an XMPP application to
-remain reliably connected to a server to receive messages.
-
-In order for messaging and other apps to receive notifications, the OS vendors
-run proprietary servers that their OS maintains a permanent connection to in
-the background. Then they provide APIs to application developers that allow
-sending notifications to specific devices via those servers.
+limits that prevent applications from running or accessing the network
+in the background. This makes it difficult or impossible for an XMPP
+application to remain reliably connected to a server to receive
+messages.
-When you connect to your server with an app that requires push notifications,
-it will use this module to set up a "push registration". When you receive
-a message but your device is not connected to the server, this module will
-generate a notification and send it to the push gateway operated by your
-application's developers). Their gateway will then connect to your device's
-OS vendor and ask them to forward the notification to your device. When your
-device receives the notification, it will display it or wake up the app so it
-can connect to XMPP and receive any pending messages.
+In order for messaging and other apps to receive notifications, the OS
+vendors run proprietary servers that their OS maintains a permanent
+connection to in the background. Then they provide APIs to application
+developers that allow sending notifications to specific devices via
+those servers.
-This protocol is described for developers in [XEP-0357: Push Notifications].
+When you connect to your server with an app that requires push
+notifications, it will use this module to set up a "push registration".
+When you receive a message but your device is not connected to the
+server, this module will generate a notification and send it to the push
+gateway operated by your application's developers). Their gateway will
+then connect to your device's OS vendor and ask them to forward the
+notification to your device. When your device receives the notification,
+it will display it or wake up the app so it can connect to XMPP and
+receive any pending messages.
-For this module to work reliably, you must have [mod_smacks], [mod_mam] and
-[mod_carbons] also enabled on your server.
+This protocol is described for developers in \[XEP-0357: Push
+Notifications\].
+
+For this module to work reliably, you must have \[mod_smacks\],
+\[mod_mam\] and \[mod_carbons\] also enabled on your server.
-Some clients, notably Siskin and Snikket iOS need some additional extensions
-that are not currently defined in a standard XEP. To support these clients,
-see [mod_cloud_notify_extensions].
+Some clients, notably Siskin and Snikket iOS need some additional
+extensions that are not currently defined in a standard XEP. To support
+these clients, see \[mod_cloud_notify_extensions\].
-Configuration
-=============
+# Configuration
- Option Default Description
- ------------------------------------ ----------------- -------------------------------------------------------------------------------------------------------------------
- `push_notification_important_body` `New Message!` The body text to use when the stanza is important (see above), no message body is sent if this is empty
- `push_max_errors` `16` How much persistent push errors are tolerated before notifications for the identifier in question are disabled
- `push_max_devices` `5` The number of allowed devices per user (the oldest devices are automatically removed if this threshold is reached)
- `push_max_hibernation_timeout` `259200` (72h) Number of seconds to extend the smacks timeout if no push was triggered yet (default: 72 hours)
- `push_notification_with_body` (\*) `false` Whether or not to send the real message body to remote pubsub node. Without end-to-end encryption, enabling this may expose your message contents to your client developers and OS vendor. Not recommended.
- `push_notification_with_sender` (\*) `false` Whether or not to send the real message sender to remote pubsub node. Enabling this may expose your contacts to your client developers and OS vendor. Not recommended.
+ Option Default Description
+ -------------------------------------- ---------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ `push_notification_important_body` `New Message!` The body text to use when the stanza is important (see above), no message body is sent if this is empty
+ `push_max_errors` `16` How much persistent push errors are tolerated before notifications for the identifier in question are disabled
+ `push_max_devices` `5` The number of allowed devices per user (the oldest devices are automatically removed if this threshold is reached)
+ `push_max_hibernation_timeout` `259200` (72h) Number of seconds to extend the smacks timeout if no push was triggered yet (default: 72 hours)
+ `push_notification_with_body` (\*) `false` Whether or not to send the real message body to remote pubsub node. Without end-to-end encryption, enabling this may expose your message contents to your client developers and OS vendor. Not recommended.
+ `push_notification_with_sender` (\*) `false` Whether or not to send the real message sender to remote pubsub node. Enabling this may expose your contacts to your client developers and OS vendor. Not recommended.
-(\*) There are privacy implications for enabling these options.
+(\*) There are privacy implications for enabling these options.[^1]
-Internal design notes
-=====================
+# Internal design notes
-App servers are notified about offline messages, messages stored by [mod_mam]
-or messages waiting in the smacks queue.
-The business rules outlined [here](//mail.jabber.org/pipermail/standards/2016-February/030925.html) are all honored[^2].
+App servers are notified about offline messages, messages stored by
+\[mod_mam\] or messages waiting in the smacks queue. The business rules
+outlined
+[here](//mail.jabber.org/pipermail/standards/2016-February/030925.html)
+are all honored[^2].
-To cooperate with [mod_smacks] this module consumes some events:
-`smacks-ack-delayed`, `smacks-hibernation-start` and `smacks-hibernation-end`.
-These events allow this module to send out notifications for messages received
-while the session is hibernated by [mod_smacks] or even when smacks
-acknowledgements for messages are delayed by a certain amount of seconds
-configurable with the [mod_smacks] setting `smacks_max_ack_delay`.
+To cooperate with \[mod_smacks\] this module consumes some events:
+`smacks-ack-delayed`, `smacks-hibernation-start` and
+`smacks-hibernation-end`. These events allow this module to send out
+notifications for messages received while the session is hibernated by
+\[mod_smacks\] or even when smacks acknowledgements for messages are
+delayed by a certain amount of seconds configurable with the
+\[mod_smacks\] setting `smacks_max_ack_delay`.
-The `smacks_max_ack_delay` setting allows to send out notifications to clients
-which aren't already in smacks hibernation state (because the read timeout or
-connection close didn't already happen) but also aren't responding to acknowledgement
-request in a timely manner. This setting thus allows conversations to be smoother
-under such circumstances.
+The `smacks_max_ack_delay` setting allows to send out notifications to
+clients which aren't already in smacks hibernation state (because the
+read timeout or connection close didn't already happen) but also aren't
+responding to acknowledgement request in a timely manner. This setting
+thus allows conversations to be smoother under such circumstances.
-The new event `cloud-notify-ping` can be used by any module to send out a cloud
-notification to either all registered endpoints for the given user or only the endpoints
-given in the event data.
+The new event `cloud-notify-ping` can be used by any module to send out
+a cloud notification to either all registered endpoints for the given
+user or only the endpoints given in the event data.
-The config setting `push_notification_important_body` can be used to specify an alternative
-body text to send to the remote pubsub node if the stanza is encrypted or has a body.
-This way the real contents of the message aren't revealed to the push appserver but it
-can still see that the push is important.
-This is used by Chatsecure on iOS to send out high priority pushes in those cases for example.
+The config setting `push_notification_important_body` can be used to
+specify an alternative body text to send to the remote pubsub node if
+the stanza is encrypted or has a body. This way the real contents of the
+message aren't revealed to the push appserver but it can still see that
+the push is important. This is used by Chatsecure on iOS to send out
+high priority pushes in those cases for example.
-Compatibility
-=============
-
-**Note:** This module should be used with Lua 5.2 and higher. Using it with
-Lua 5.1 may cause push notifications to not be sent to some clients.
+# Compatibility
------- -----------------------------------------------------------------------------
- trunk Works
- 0.12 Works
- 0.11 Works
- 0.10 Works
- 0.9 Support dropped, use last supported version [675726ab06d3](//hg.prosody.im/prosody-modules/raw-file/675726ab06d3/mod_cloud_notify/mod_cloud_notify.lua)
------- -----------------------------------------------------------------------------
+**Note:** This module should be used with Lua 5.2 and higher. Using it
+with Lua 5.1 may cause push notifications to not be sent to some
+clients.
+ ------- -----------------------------------------------------------------
+ trunk Works as of 25-06-13
+ 13 Works
+ 0.12 Works
+ ------- -----------------------------------------------------------------
-[^1]: The service which is expected to forward notifications to something like Google Cloud Messaging or Apple Notification Service
-[^2]: [business_rules.markdown](//hg.prosody.im/prosody-modules/file/tip/mod_cloud_notify/business_rules.markdown)
+[^1]: The service which is expected to forward notifications to
+ something like Google Cloud Messaging or Apple Notification Service
+
+[^2]: [business_rules.md](//hg.prosody.im/prosody-modules/file/tip/mod_cloud_notify/business_rules.md)
| author | Menel <menel@snikket.de> |
|---|---|
| date | Fri, 13 Jun 2025 10:36:52 +0200 |
| parents | 502963b86fbc |
| children | fe0a58b863db |
line wrap: on
line source
--- description: HTTP File Upload (external service) labels: - Stage-Beta --- Introduction ============ This module implements [XEP-0363], which lets clients upload files over HTTP to an external web server. This module generates URLs that are signed using a HMAC. Any web service that can authenticate these URLs can be used. Implementations --------------- * [PHP implementation](https://hg.prosody.im/prosody-modules/raw-file/tip/mod_http_upload_external/share.php) * [Python3+Flask implementation](https://github.com/horazont/xmpp-http-upload) * [Go implementation, Prosody Filer](https://github.com/ThomasLeister/prosody-filer) * [Perl implementation for nginx](https://github.com/weiss/ngx_http_upload) * [Rust implementation](https://gitlab.com/nyovaya/xmpp-http-upload) To implement your own service compatible with this module, check out the implementation notes below (and if you publish your implementation - let us know!). Configuration ============= The module can be added as a new Component definition: ``` {.lua} Component "upload.example.org" "http_upload_external" http_upload_external_base_url = "https://your.example.com/upload/service" http_upload_external_secret = "your shared secret" ``` It should **not** be added to modules_enabled. External URL ------------ You need to provide the path to the external service. Ensure it ends with '/'. For example, to use the PHP implementation linked above, you might set it to: ``` {.lua} http_upload_external_base_url = "https://your.example.com/path/to/share.php/" ``` Secret ------ Set a long and unpredictable string as your secret. This is so the upload service can verify that the upload comes from mod_http_upload_external, and random strangers can't upload to your server. ``` {.lua} http_upload_external_secret = "this is a secret string!" ``` You need to set exactly the same secret string in your external service. Limits ------ A maximum file size can be set by: ``` {.lua} http_upload_external_file_size_limit = 123 -- bytes ``` Default is 100MB (100\*1024\*1024). Access ------ You may want to give upload access to additional entities such as components by using the `http_upload_external_access` config option. ``` {.lua} http_upload_external_access = {"gateway.example.com"}; ``` Compatibility ============= Prosody-Version Status ---------------- -------------------- trunk Works as of 25-06-13 13 Works 0.12 Works Implementation ============== To implement your own external service that is compatible with this module, you need to expose a simple API that allows the HTTP GET, HEAD and PUT methods on arbitrary URLs located on your service. For example, if http_upload_external_base_url is set to `https://example.com/upload/` then your service might receive the following requests: Upload a new file: ``` PUT https://example.com/upload/foo/bar.jpg?v=49e9309ff543ace93d25be90635ba8e9965c4f23fc885b2d86c947a5d59e55b2 ``` Recipient checks the file size and other headers: ``` HEAD https://example.com/upload/foo/bar.jpg ``` Recipient downloads the file: ``` GET https://example.com/upload/foo/bar.jpg ``` The only tricky logic is in validation of the PUT request. Firstly, don't overwrite existing files (return 409 Conflict). Then you need to validate the auth token. ### Validating the auth token | Version | Supports | |:--------|:--------------------------------------------------------------------------------------------------------| | v | Validates only filename and size. Does not support file type restrictions by the XMPP server. | | v2 | Validates the filename, size and MIME type. This allows the server to implement MIME type restrictions. | It is probable that a future v3 will be specified that allows carrying information about the uploader identity, allowing the implementation of per-user quotas and limits. Implementations may implement one or more versions of the protocol simultaneously. The XMPP server generates the URLs and ultimately selects which version will be used. XMPP servers MUST only generate URLs with **one** of the versions listed here. However in case multiple parameters are present, upload services MUST **only** use the token from the highest parameter version that they support. #### Version 1 (v) The token will be in the URL query parameter 'v'. If it is absent, fail with 403 Forbidden. Calculate the expected auth token by reading the value of the Content-Length header of the PUT request. E.g. for a 1MB file will have a Content-Length of '1048576'. Append this to the uploaded file name, separated by a space (0x20) character. For the above example, you would end up with the following string: "foo/bar.jpg 1048576" The auth token is a SHA256 HMAC of this string, using the configured secret as the key. E.g. ``` calculated_auth_token = hmac_sha256("foo/bar.jpg 1048576", "secret string") ``` If this is not equal to the 'v' parameter provided in the upload URL, reject the upload with 403 Forbidden. **Security note:** When comparing `calculated_auth_token` with the token provided in the URL, you must use a constant-time string comparison, otherwise an attacker may be able to discover your secret key. Most languages/environments provide such a function, such as `hash_equals()` in PHP, `hmac.compare_digest()` in Python, or `ConstantTimeCompare()` from `crypto/subtle` in Go. #### Version 2 (v2) The token will be in the URL query parameter 'v2'. If it is absent, fail with 403 Forbidden. | Input | Example |Read from | |:----------------|:------------|:--------------------------------------------------------------------| |`file_path` | foo/bar.jpg | The URL of the PUT request, with the service's base prefix removed. | |`content_length` | 1048576 | Content-Length header | |`content_type` | image/jpeg | Content-Type header | The parameters should be joined into a single string, separated by NUL bytes (`\0`): ``` signed_string = ( file_path + '\0' + content_length + '\0' + content_type ) ``` ``` signed_string = "foo/bar.jpg\01048576\0image/jpeg" ``` The expected auth token is the SHA256 HMAC of this string, using the configured secret key as the key. E.g.: ``` calculated_auth_token = hmac_sha256(signed_string, "secret string") ``` If this is not equal to the 'v2' parameter provided in the upload URL, reject the upload with 403 Forbidden. **Security note:** When comparing `calculated_auth_token` with the token provided in the URL, you must use a constant-time string comparison, otherwise an attacker may be able to discover your secret key. Most languages/environments provide such a function, such as `hash_equals()` in PHP, `hmac.compare_digest()` in Python, or `ConstantTimeCompare()` from `crypto/subtle` in Go. ### Security considerations #### HTTPS All uploads and downloads should only be over HTTPS. The security of the served content is protected only by the uniqueness present in the URLs themselves, and not using HTTPS may leak the URLs and contents to third-parties. Implementations should consider including HSTS and HPKP headers, with consent of the administrator. #### MIME types If the upload Content-Type header matches any of the following MIME types, it MUST be preserved and included in the Content-Type of any GET requests made to download the file: - `image/*` - `video/*` - `audio/*` - `text/plain` It is recommended that other MIME types are preserved, but served with the addition of the following header: ``` Content-Disposition: attachment ``` This prevents the browser interpreting scripts and other resources that may potentially be malicious. Some browsers may also benefit from explicitly telling them not to try guessing the type of a file: ``` X-Content-Type-Options: nosniff ``` #### Security headers The following headers should be included to provide additional sandboxing of resources, considering the uploaded content is not understood or trusted by the upload service: ``` Content-Security-Policy: default-src 'none' X-Content-Security-Policy: default-src 'none' X-WebKit-CSP: default-src 'none' ```
