Software /
code /
prosody-modules
Changeset
6309:342f88e8d522 draft default tip
Merge update
author | Trần H. Trung <xmpp:trần.h.trung@trung.fun> |
---|---|
date | Sun, 15 Jun 2025 01:08:46 +0700 (10 days ago) |
parents | 6279:b92aea4e7ff4 (current diff) 6308:e1c54de06905 (diff) |
children | |
files | mod_admin_blocklist/README.md mod_csi_grace_period/README.md mod_http_oauth2/mod_http_oauth2.lua mod_http_upload_external/README.md mod_private_adhoc/mod_private_adhoc.lua mod_tls_policy/mod_tls_policy.lua |
diffstat | 15 files changed, 243 insertions(+), 209 deletions(-) [+] |
line wrap: on
line diff
--- a/mod_admin_blocklist/README.md Sun Jun 01 21:32:49 2025 +0700 +++ b/mod_admin_blocklist/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -23,9 +23,8 @@ # Compatibility - Prosody-Version Status - --------------- ------ - trunk* Works - 0.12 Works - -*as of 2024-12-21 + Prosody Version Status + ----------------- ------------------------ + trunk Works as of 2025-06-13 + 13.0 Works + 0.12 Works
--- a/mod_audit/README.md Sun Jun 01 21:32:49 2025 +0700 +++ b/mod_audit/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -52,6 +52,7 @@ # Compatibilty -Requires Prosody **trunk** as of 2025-02-11. - -Does not work with Prosody 0.12 or earlier. + Prosody-Version Status + ----------------- --------------- + 13.0 Works + 0.12 Does not work
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_auto156/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -0,0 +1,7 @@ +This module was meant to help convert the deprecated [XEP-0156] TXT records into JSON format. + +```shell +$ prosodyctl mod_auto156 example.com [another.example ...] +{"links":[{"href":"https://xmpp.example.com/bosh","rel":"urn:xmpp:alt-connections:xbosh"}]} +... +```
--- a/mod_cloud_notify/README.md Sun Jun 01 21:32:49 2025 +0700 +++ b/mod_cloud_notify/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -4,106 +4,109 @@ 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. +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. +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. -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. +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. -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. +This protocol is described for developers in [XEP-0357: Push +Notifications]. -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]. +For this module to work reliably, you must have [mod_smacks], +[mod_mam] and [mod_carbons] also enabled on your server. -Configuration -============= +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 - 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`. +`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.0 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)
--- a/mod_csi_grace_period/README.md Sun Jun 01 21:32:49 2025 +0700 +++ b/mod_csi_grace_period/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -16,9 +16,8 @@ Works with [mod_csi_simple][doc:modules:mod_csi_simple] which is included with Prosody. - ------- -------------- - trunk* Works - 0.12 Works - ------- -------------- - -*as of 2024-10-22 + ------- ------------------------ + trunk Works as of 2025-06-13 + 13 Works + 0.12 Works + ------- ------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_flags/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -0,0 +1,4 @@ +View and manage flags on user accounts via shell/API. +See [documentation for mod_flags at Prosody site][doc:modules:mod_flags] + +This module is included with Prosody 13.0.x and is provided here for users of Prosody 0.12.x
--- a/mod_http_admin_api/mod_http_admin_api.lua Sun Jun 01 21:32:49 2025 +0700 +++ b/mod_http_admin_api/mod_http_admin_api.lua Sun Jun 15 01:08:46 2025 +0700 @@ -15,7 +15,7 @@ local tokens = module:depends("tokenauth"); local mod_pep = module:depends("pep"); local mod_groups = module:depends("groups_internal"); -local mod_lastlog2 = module:depends("lastlog2"); +local mod_account_activity = module:depends("account_activity"); local push_errors = module:shared("cloud_notify/push_errors"); @@ -30,8 +30,6 @@ local xmlns_pubsub = "http://jabber.org/protocol/pubsub"; local xmlns_nick = "http://jabber.org/protocol/nick"; -assert(mod_lastlog2.get_last_active, "Newer version of mod_lastlog2 is required to use this module"); - local deleted_users = module:open_store("accounts_cleanup"); local function check_credentials(request) @@ -242,7 +240,7 @@ secondary_roles = secondary_roles; roles = legacy_roles; -- COMPAT w/0.12 enabled = enabled; - last_active = mod_lastlog2.get_last_active(username); + last_active = mod_account_activity.get_last_active(username); deletion_request = not enabled and deleted_users:get(username) or nil; avatar_info = get_user_avatar_info(username); };
--- a/mod_http_oauth2/mod_http_oauth2.lua Sun Jun 01 21:32:49 2025 +0700 +++ b/mod_http_oauth2/mod_http_oauth2.lua Sun Jun 15 01:08:46 2025 +0700 @@ -410,7 +410,10 @@ local request_username if expect_username_jid then - local request_jid = assert(params.username, oauth_error("invalid_request", "missing 'username' (JID)")); + local request_jid = params.username; + if not request_jid then + return oauth_error("invalid_request", "missing 'username' (JID)"); + end local _request_username, request_host = jid.prepped_split(request_jid); if not (_request_username and request_host) or request_host ~= module.host then @@ -419,15 +422,36 @@ request_username = _request_username else - request_username = assert(params.username, oauth_error("invalid_request", "missing 'username'")); + request_username = params.username; + if not request_username then + return oauth_error("invalid_request", "missing 'username'"); + end + end + + local request_password = params.password; + if not request_password then + return oauth_error("invalid_request", "missing 'password'"); end - local request_password = assert(params.password, oauth_error("invalid_request", "missing 'password'")); + local auth_event = { + session = { + type = "oauth2"; + ip = "::"; + username = request_username; + host = module.host; + log = module._log; + sasl_handler = { username = request_username; selected = "x-oauth2-password" }; + client_id = client.client_name; + }; + }; if not usermanager.test_password(request_username, module.host, request_password) then + module:fire_event("authentication-failure", auth_event); return oauth_error("invalid_grant", "incorrect credentials"); end + module:fire_event("authentication-success", auth_event); + local granted_jid = jid.join(request_username, module.host); local granted_scopes, granted_role = filter_scopes(request_username, params.scope); return json.encode(new_access_token(granted_jid, granted_role, granted_scopes, client)); @@ -552,21 +576,9 @@ return json.encode(new_access_token(code.granted_jid, code.granted_role, code.granted_scopes, client, code.id_token)); end -function grant_type_handlers.refresh_token(params) - if not params.client_id then return oauth_error("invalid_request", "missing 'client_id'"); end - if not params.client_secret then return oauth_error("invalid_request", "missing 'client_secret'"); end +function grant_type_handlers.refresh_token(params, client) if not params.refresh_token then return oauth_error("invalid_request", "missing 'refresh_token'"); end - local client = check_client(params.client_id); - if not client then - return oauth_error("invalid_client", "incorrect credentials"); - end - - if not verify_client_secret(params.client_id, params.client_secret) then - module:log("debug", "client_secret mismatch"); - return oauth_error("invalid_client", "incorrect credentials"); - end - local refresh_token_info = tokens.get_token_info(params.refresh_token); if not refresh_token_info or refresh_token_info.purpose ~= "oauth2-refresh" then return oauth_error("invalid_grant", "invalid refresh token"); @@ -598,21 +610,9 @@ return json.encode(new_access_token(refresh_token_info.jid, role, new_scopes, client, nil, refresh_token_info)); end -grant_type_handlers[device_uri] = function(params) - if not params.client_id then return oauth_error("invalid_request", "missing 'client_id'"); end - if not params.client_secret then return oauth_error("invalid_request", "missing 'client_secret'"); end +grant_type_handlers[device_uri] = function(params, client) if not params.device_code then return oauth_error("invalid_request", "missing 'device_code'"); end - local client = check_client(params.client_id); - if not client then - return oauth_error("invalid_client", "incorrect credentials"); - end - - if not verify_client_secret(params.client_id, params.client_secret) then - module:log("debug", "client_secret mismatch"); - return oauth_error("invalid_client", "incorrect credentials"); - end - local code = codes:get("device_code:" .. params.client_id .. "#" .. params.device_code); if type(code) ~= "table" or code_expired(code) then return oauth_error("expired_token"); @@ -747,8 +747,14 @@ local component_secret = assert(module:get_option_string("component_secret"), "'component_secret' is a required setting when loaded on a Component"); function grant_type_handlers.password(params) - local request_jid = assert(params.username, oauth_error("invalid_request", "missing 'username' (JID)")); - local request_password = assert(params.password, oauth_error("invalid_request", "missing 'password'")); + local request_jid = params.username; + if not request_jid then + return oauth_error("invalid_request", "missing 'username' (JID)"); + end + local request_password = params.password + if not request_password then + return oauth_error("invalid_request", "missing 'password'"); + end local request_username, request_host, request_resource = jid.prepped_split(request_jid); if params.scope then -- TODO shouldn't we support scopes / roles here? @@ -781,15 +787,28 @@ -- the redirect_uri is missing or invalid. In those cases, we render an -- error directly to the user-agent. local function error_response(request, redirect_uri, err) - if not redirect_uri or redirect_uri == oob_uri or redirect_uri == device_uri then + if not redirect_uri or redirect_uri == oob_uri then return render_error(err); end - local q = strict_formdecode(request.url.query); + local params = strict_formdecode(request.url.query); + if redirect_uri == device_uri then + local is_device, device_state = verify_device_token(params.state); + if is_device then + local device_code = b64url(hashes.hmac_sha256(verification_key, device_state.user_code)); + local code = codes:get("device_code:" .. params.client_id .. "#" .. device_code); + if type(code) == "table" then + code.error = err; + code.expires = os.time() + 60; + codes:set("device_code:" .. params.client_id .. "#" .. device_code, code); + end + end + return render_error(err); + end local redirect_query = url.parse(redirect_uri); local sep = redirect_query.query and "&" or "?"; redirect_uri = redirect_uri .. sep .. http.formencode(err.extra.oauth2_response) - .. "&" .. http.formencode({ state = q.state, iss = get_issuer() }); + .. "&" .. http.formencode({ state = params.state, iss = get_issuer() }); module:log("debug", "Sending error response to client via redirect to %s", redirect_uri); return { status_code = 303; @@ -842,6 +861,15 @@ end end +local function array_contains(haystack, needle) + for _, item in ipairs(haystack) do + if item == needle then + return true + end + end + return false +end + function handle_token_grant(event) local credentials = get_request_credentials(event.request); @@ -874,10 +902,15 @@ local grant_type = params.grant_type + if not array_contains(client.grant_types or { "authorization_code" }, grant_type) then + return oauth_error("invalid_request", "'grant_type' not registered"); + end + local grant_handler = grant_type_handlers[grant_type]; if not grant_handler then - return oauth_error("invalid_request", "No such grant type."); + return oauth_error("invalid_request", "'grant_type' not available"); end + return grant_handler(params, client); end @@ -909,10 +942,16 @@ end -- From this point we know that redirect_uri is safe to use - local client_response_types = set.new(array(client.response_types or { "code" })); - client_response_types = set.intersection(client_response_types, allowed_response_type_handlers); - if not client_response_types:contains(params.response_type) then - return error_response(request, redirect_uri, oauth_error("invalid_client", "'response_type' not allowed")); + local response_type = params.response_type; + if not array_contains(client.response_types or { "code" }, response_type) then + return error_response(request, redirect_uri, oauth_error("invalid_client", "'response_type' not registered")); + end + if not allowed_response_type_handlers:contains(response_type) then + return error_response(request, redirect_uri, oauth_error("unsupported_response_type", "'response_type' not allowed")); + end + local response_handler = response_type_handlers[response_type]; + if not response_handler then + return error_response(request, redirect_uri, oauth_error("unsupported_response_type")); end local requested_scopes = parse_scopes(params.scope or ""); @@ -976,16 +1015,6 @@ end elseif not auth_state.consent then -- Notify client of rejection - if redirect_uri == device_uri then - local is_device, device_state = verify_device_token(params.state); - if is_device then - local device_code = b64url(hashes.hmac_sha256(verification_key, device_state.user_code)); - local code = codes:get("device_code:" .. params.client_id .. "#" .. device_code); - code.error = oauth_error("access_denied"); - code.expires = os.time() + 60; - codes:set("device_code:" .. params.client_id .. "#" .. device_code, code); - end - end return error_response(request, redirect_uri, oauth_error("access_denied")); end -- else auth_state.consent == true @@ -1009,13 +1038,8 @@ aud = params.client_id; auth_time = auth_state.user.iat; nonce = params.nonce; - amr = auth_state.user.amr; + amr = auth_state.user.amr; -- RFC 8176: Authentication Method Reference Values }); - local response_type = params.response_type; - local response_handler = response_type_handlers[response_type]; - if not response_handler then - return error_response(request, redirect_uri, oauth_error("unsupported_response_type")); - end local ret = response_handler(client, params, user_jid, id_token); if errors.is_err(ret) then return error_response(request, redirect_uri, ret); @@ -1307,7 +1331,6 @@ response_types = { title = "Response Types"; type = "array"; - minItems = 1; uniqueItems = true; items = { type = "string"; enum = { "code"; "token" } }; default = { "code" }; @@ -1471,18 +1494,18 @@ local grant_types = set.new(client_metadata.grant_types); local response_types = set.new(client_metadata.response_types); + if not (grant_types - allowed_grant_type_handlers):empty() then + return nil, oauth_error("invalid_client_metadata", "Disallowed 'grant_types' specified"); + elseif not (response_types - allowed_response_type_handlers):empty() then + return nil, oauth_error("invalid_client_metadata", "Disallowed 'response_types' specified"); + end + if grant_types:contains("authorization_code") and not response_types:contains("code") then return nil, oauth_error("invalid_client_metadata", "Inconsistency between 'grant_types' and 'response_types'"); elseif grant_types:contains("implicit") and not response_types:contains("token") then return nil, oauth_error("invalid_client_metadata", "Inconsistency between 'grant_types' and 'response_types'"); end - if set.intersection(grant_types, allowed_grant_type_handlers):empty() then - return nil, oauth_error("invalid_client_metadata", "No allowed 'grant_types' specified"); - elseif set.intersection(response_types, allowed_response_type_handlers):empty() then - return nil, oauth_error("invalid_client_metadata", "No allowed 'response_types' specified"); - end - if client_metadata.token_endpoint_auth_method ~= "none" then -- Ensure that each client_id JWT with a client_secret is unique. -- A short ID along with the issued at timestamp should be sufficient to @@ -1669,28 +1692,35 @@ issuer = get_issuer(); authorization_endpoint = handle_authorization_request and module:http_url() .. "/authorize" or nil; token_endpoint = handle_token_grant and module:http_url() .. "/token" or nil; + jwks_uri = nil; -- REQUIRED in OpenID Discovery but not in OAuth 2.0 Metadata registration_endpoint = handle_register_request and module:http_url() .. "/register" or nil; scopes_supported = usermanager.get_all_roles and array(it.keys(usermanager.get_all_roles(module.host))):push("xmpp"):append(array(openid_claims:items())); response_types_supported = array(it.keys(response_type_handlers)); - token_endpoint_auth_methods_supported = array({ "client_secret_post"; "client_secret_basic" }); + response_modes_supported = array(it.keys(response_type_handlers)):map(tmap { token = "fragment"; code = "query" }); + grant_types_supported = array(it.keys(grant_type_handlers)); + token_endpoint_auth_methods_supported = array({ "client_secret_basic"; "client_secret_post"; "none" }); + token_endpoint_auth_signing_alg_values_supported = nil; + service_documentation = module:get_option_string("oauth2_service_documentation", "https://modules.prosody.im/mod_http_oauth2.html"); + ui_locales_supported = allowed_locales[1] and allowed_locales; op_policy_uri = module:get_option_string("oauth2_policy_url", nil); op_tos_uri = module:get_option_string("oauth2_terms_url", nil); revocation_endpoint = handle_revocation_request and module:http_url() .. "/revoke" or nil; - revocation_endpoint_auth_methods_supported = array({ "client_secret_basic" }); - device_authorization_endpoint = handle_device_authorization_request and module:http_url() .. "/device"; + revocation_endpoint_auth_methods_supported = array({ "client_secret_basic"; "client_secret_post"; "none" }); + revocation_endpoint_auth_signing_alg_values_supported = nil; introspection_endpoint = handle_introspection_request and module:http_url() .. "/introspect"; introspection_endpoint_auth_methods_supported = nil; + introspection_endpoint_auth_signing_alg_values_supported = nil; code_challenge_methods_supported = array(it.keys(verifier_transforms)); - grant_types_supported = array(it.keys(grant_type_handlers)); - response_modes_supported = array(it.keys(response_type_handlers)):map(tmap { token = "fragment"; code = "query" }); + + -- RFC 8628: OAuth 2.0 Device Authorization Grant + device_authorization_endpoint = handle_device_authorization_request and module:http_url() .. "/device"; + + -- RFC 9207: OAuth 2.0 Authorization Server Issuer Identification authorization_response_iss_parameter_supported = true; - service_documentation = module:get_option_string("oauth2_service_documentation", "https://modules.prosody.im/mod_http_oauth2.html"); - ui_locales_supported = allowed_locales[1] and allowed_locales; - -- OpenID + -- OpenID Connect Discovery 1.0 userinfo_endpoint = handle_userinfo_request and module:http_url() .. "/userinfo" or nil; - jwks_uri = nil; -- REQUIRED in OpenID Discovery but not in OAuth 2.0 Metadata id_token_signing_alg_values_supported = { "HS256" }; -- The algorithm RS256 MUST be included, but we use HS256 and client_secret as shared key. } return authorization_server_metadata;
--- a/mod_http_upload_external/README.md Sun Jun 01 21:32:49 2025 +0700 +++ b/mod_http_upload_external/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -19,7 +19,6 @@ * [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) -* [Go implementation, HMAC File Server](https://github.com/PlusOne/hmac-file-server) * [Perl implementation for nginx](https://github.com/weiss/ngx_http_upload) * [Rust implementation](https://gitlab.com/nyovaya/xmpp-http-upload) @@ -88,8 +87,9 @@ ============= Prosody-Version Status - ---------------- -------------------- - trunk Works as of 24-12-12 + ----------------- ---------------------- + trunk Works as of 25-06-13 + 13.0 Works 0.12 Works Implementation
--- a/mod_muc_moderation/README.md Sun Jun 01 21:32:49 2025 +0700 +++ b/mod_muc_moderation/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -27,10 +27,11 @@ # Compatibility - ------- --------------- - trunk Works^[as of 2024-10-22] + ------- ------------------------ + trunk Works as of 2025-06-13 + 13 Works 0.12 Works - ------- --------------- + ------- ------------------------ ## XEP version
--- a/mod_pastebin/README.md Sun Jun 01 21:32:49 2025 +0700 +++ b/mod_pastebin/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -37,12 +37,14 @@ Pastes will be available by default at `http://<your-prosody>:5280/pastebin/` by default. -In Prosody 0.9 and later this can be changed with [HTTP -settings](https://prosody.im/doc/http). +Ports and path can be changed with [HTTP +settings](https://prosody.im/doc/http), for example like: -In 0.8 and older this can be changed with `pastebin_ports` (see below), -or you can forward another external URL from your web server to Prosody, -use `pastebin_url` to set that URL. +``` {.lua} + http_paths = { + pastebin = "/$host-paste"; + } +``` # Discovery @@ -82,27 +84,16 @@ pastebin_line_threshold The maximum number of lines a message may have before it is sent to the pastebin. (default 4 lines) pastebin_trigger A string of characters (e.g. "!paste ") which if detected at the start of a message, always sends the message to the pastebin, regardless of length. (default: not set) pastebin_expire_after Number of hours after which to expire (remove) a paste, defaults to 24. Set to 0 to store pastes permanently on disk. - pastebin_ports List of ports to run the HTTP server on, same format as mod_httpserver's http_ports[^1] - pastebin_url Base URL to display for pastebin links, must end with / and redirect to Prosody's built-in HTTP server[^2] # Compatibility - ------ ------- - trunk Works - 0.12 Works - 0.11 Works - 0.10 Works - 0.9 Works - 0.8 Works - ------ ------- + ------- ---------------------- + trunk Works as of 25-06-13 + 13.0 Works + 0.12 Works + ------- ---------------------- # Todo - Maximum paste length - Web interface to submit pastes? - -[^1]: As of Prosody 0.9, `pastebin_ports` is replaced by `http_ports`, - see [Prosody HTTP server documentation](https://prosody.im/doc/http) - -[^2]: See also - [http_external_url](https://prosody.im/doc/http#external_url)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_s2s_auth_samecert/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -0,0 +1,2 @@ +This module authenticates server-to-server connections by looking for an already established connection that uses the exact same certificate, reusing +the earlier validation results and letting Prosody skip performing slower validation methods such as [POSH][mod_s2s_auth_posh] twice.
--- a/mod_s2s_idle_timeout/README.md Sun Jun 01 21:32:49 2025 +0700 +++ b/mod_s2s_idle_timeout/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -25,9 +25,7 @@ ============= Prosody Version Status - ----------------- ----------- - trunk[^1] Works + ----------------- ------------------------ + trunk Works as of 2025-06-13 + 13.0 Works 0.12 Works - ----------------- ----------- - -[^1]: as of 2024-10-22
--- a/mod_s2s_keepalive/README.md Sun Jun 01 21:32:49 2025 +0700 +++ b/mod_s2s_keepalive/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -34,9 +34,7 @@ ============= Prosody Version Status - ----------------- ----------- - trunk[^1] Works + ----------------- ------------------------ + trunk Works as of 2025-06-13 + 13.0 Works 0.12 Works - ----------------- ----------- - -[^1]: as of 2024-11-11
--- a/mod_s2soutinjection/README.md Sun Jun 01 21:32:49 2025 +0700 +++ b/mod_s2soutinjection/README.md Sun Jun 15 01:08:46 2025 +0700 @@ -28,4 +28,7 @@ # Compatibility -Requires 0.9.x or later. Tested on 0.12.0 + Prosody version Status + ----------------- --------------- + 13.0.x Does not work + 0.12.x Works