Software /
code /
prosody-modules
Changeset
6273:8ceedc336d0d
Merge update
author | Trần H. Trung <xmpp:trần.h.trung@trung.fun> |
---|---|
date | Sun, 01 Jun 2025 13:51:38 +0700 |
parents | 6263:10a1016d1c3a (current diff) 6272:ed6fa901cf94 (diff) |
children | 6274:6cf1f47f24b4 |
files | mod_http_oauth2/mod_http_oauth2.lua mod_invites_register_web/README.md mod_invites_register_web/mod_invites_register_web.lua |
diffstat | 8 files changed, 152 insertions(+), 59 deletions(-) [+] |
line wrap: on
line diff
--- a/mod_http_oauth2/mod_http_oauth2.lua Sun Jun 01 11:43:16 2025 +0700 +++ b/mod_http_oauth2/mod_http_oauth2.lua Sun Jun 01 13:51:38 2025 +0700 @@ -399,32 +399,19 @@ end local function make_client_secret(client_id) --> client_secret - return hashes.hmac_sha256(verification_key, client_id, true); + return hashes.hmac_sha256(verification_key, client_id, true); end local function verify_client_secret(client_id, client_secret) - return hashes.equals(make_client_secret(client_id), client_secret); + return hashes.equals(make_client_secret(client_id), client_secret); end -function grant_type_handlers.password(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 - - 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 - +function grant_type_handlers.password(params, client) local request_username if expect_username_jid then local request_jid = assert(params.username, oauth_error("invalid_request", "missing 'username' (JID)")); - local _request_username, request_host, request_resource = jid.prepped_split(request_jid); + local _request_username, request_host = jid.prepped_split(request_jid); if not (_request_username and request_host) or request_host ~= module.host then return oauth_error("invalid_request", "invalid JID"); @@ -537,24 +524,12 @@ } end -function grant_type_handlers.authorization_code(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.authorization_code(params, client) if not params.code then return oauth_error("invalid_request", "missing 'code'"); end if params.scope and params.scope ~= "" then -- FIXME allow a subset of granted scopes return oauth_error("invalid_scope", "unknown scope requested"); 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, err = codes:get("authorization_code:" .. params.client_id .. "#" .. params.code); if err then error(err); end -- MUST NOT use the authorization code more than once, so remove it to @@ -884,12 +859,26 @@ params.client_secret = http.urldecode(credentials.password); end + 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 + + 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 grant_type = params.grant_type local grant_handler = grant_type_handlers[grant_type]; if not grant_handler then return oauth_error("invalid_request", "No such grant type."); end - return grant_handler(params); + return grant_handler(params, client); end local function handle_authorization_request(event)
--- a/mod_invites_register_web/README.md Sun Jun 01 11:43:16 2025 +0700 +++ b/mod_invites_register_web/README.md Sun Jun 01 13:51:38 2025 +0700 @@ -34,8 +34,8 @@ validates invite tokens. It also supports guiding the user through client download and configuration via mod_register_apps. -This module depends on mod_invites_page solely for the case where an invalid -invite token is received - it will redirect to mod_invites_page so that an +This module depends on [mod_invites_page] solely for the case where an invalid +invite token is received - it will redirect to [mod_invites_page] so that an appropriate error can be served to the user. The module also depends on [mod_password_policy] (which will be automatically @@ -46,36 +46,43 @@ Configuration ============= -It uses the optional `site_name` to override the displayed site name. +The optional `site_name` setting can be used to override the displayed site name. + +```lua +site_name = "My Chat Service" +``` You can set `webchat_url` to the URL of a web chat that will be linked -to after successful registration. If not specified but mod_conversejs is loaded +to after successful registration. If not specified but [mod_conversejs] is loaded on the current host, it will default to the URL of that module. -You can use your own html templates with `invites_template_html`. Names of the -files MUST match the default. More over, you can offer multiple (human) +HTML templates can be overridden by using `invites_register_template_path`, see +the `html/` directory in the sources for the files needed. + +```lua +invites_register_template_path = "/path/to/templates/html" +``` + +Names of the files MUST match the default. More over, you can offer multiple (human) languages by adding the `&l=` to the URL. Meaning this module will serve `register.html` for your default URL: -``` - https://prosody.example.net/register?t=aowiefjoaij - +```lua +https://prosody.example.net/register?t=aowiefjoaij ``` And if you have a `register.en.html` in the directory you have specified in your config file, it will be served at: -``` - https://prosody.example.net/register?t=aowiefjoaij&l=en - +```lua +https://prosody.example.net/register?t=aowiefjoaij&l=en ``` So in your `register.html`, you can point to the English version by using an `<a>` tag like this: -``` - <a href="/register?t={token}&l=en">English</a> - +```lua +<a href="/register?t={token}&l=en">English</a> ``` You can further customize your URL with [mod_invites_page] too.
--- a/mod_invites_register_web/mod_invites_register_web.lua Sun Jun 01 11:43:16 2025 +0700 +++ b/mod_invites_register_web/mod_invites_register_web.lua Sun Jun 01 13:51:38 2025 +0700 @@ -34,10 +34,10 @@ local invites = module:depends("invites"); local invites_page = module:depends("invites_page"); -local templatePath = module:get_option_string("invites_template_html", "html"); -function template_get(sTemplate, sLang) - local template = sLang and templatePath.."/"..sTemplate.."."..sLang..".html" - or templatePath.."/"..sTemplate..".html"; +local template_path = module:get_option_path("invites_register_template_path", "html"); +function template_get(template, lang) + local template = lang and template_path.."/"..template.."."..lang..".html" + or template_path.."/"..template..".html"; return assert(module:load_resource(template):read("*a")); end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_migrate_lastlog2/README.md Sun Jun 01 13:51:38 2025 +0700 @@ -0,0 +1,21 @@ +--- +summary: mod_lastlog2 to mod_account_activity migrator +labels: +- Stage-Alpha +--- + + +This is a migration script for converting data stored by [mod_lastlog2] (a +community module) to mod_account_activity (a newer module which is supplied +with Prosody 13.0 and later). + +# Usage + +This module performs the migration automatically as soon as it is loaded. + +By default it will remove data from the mod_lastlog2 store unless you set +`migrate_lastlog2_auto_remove = false`. + +# Compatibility + +Works with Prosody 13.0 and later.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_migrate_lastlog2/mod_migrate_lastlog2.lua Sun Jun 01 13:51:38 2025 +0700 @@ -0,0 +1,67 @@ +-- This module is based on the shell command code from mod_account_activity + +local autoremove = module:get_option_boolean("migrate_lastlog2_auto_remove", true); + +local function do_migration() + local store = module:open_store("account_activity", "keyval+"); + local lastlog2 = module:open_store("lastlog2", "keyval+"); + local n_updated, n_errors, n_skipped = 0, 0, 0; + + local async = require "prosody.util.async"; + + local p = require "prosody.util.promise".new(function (resolve) + local async_runner = async.runner(function () + local n = 0; + for username in lastlog2:items() do + local was_error = nil; + n = n + 1; + if n % 100 == 0 then + module:log("debug", "Processed %d...", n); + async.sleep(0); + end + local lastlog2_data = lastlog2:get(username); + if lastlog2_data then + local current_data, err = store:get(username); + if not current_data then + if not err then + current_data = {}; + else + n_errors = n_errors + 1; + end + end + if current_data then + local imported_timestamp = current_data.timestamp; + local latest; + for k, v in pairs(lastlog2_data) do + if k ~= "registered" and (not latest or v.timestamp > latest) then + latest = v.timestamp; + end + end + if latest and (not imported_timestamp or imported_timestamp < latest) then + local ok, err = store:set_key(username, "timestamp", latest); + if ok then + n_updated = n_updated + 1; + else + module:log("error", "Failed to import %q: %s", username, err); + was_error = true; + n_errors = n_errors + 1; + end + else + n_skipped = n_skipped + 1; + end + end + if autoremove and not was_error then + lastlog2:set(username, nil); + end + end + end + return resolve(("%d accounts imported, %d errors, %d skipped"):format(n_updated, n_errors, n_skipped)); + end); + async_runner:run(true); + end); + return p; +end + +function module.ready() + do_migration(); +end
--- a/mod_push2/mod_push2.lua Sun Jun 01 11:43:16 2025 +0700 +++ b/mod_push2/mod_push2.lua Sun Jun 01 13:51:38 2025 +0700 @@ -355,6 +355,7 @@ end if send_push then + local any_match = false; local push_notification_payload = st.stanza("notification", { xmlns = xmlns_push }) push_notification_payload:text_tag("client", push_info.client) push_notification_payload:text_tag("priority", is_voip(stanza) and "high" or (is_important(stanza, session) and "normal" or "low")) @@ -411,6 +412,7 @@ if does_match and not sends_added[match.send] then sends_added[match.send] = true + any_match = true if match.send == "urn:xmpp:push2:send:notify-only" then -- Nothing more to add elseif match.send == "urn:xmpp:push2:send:sce+rfc8291+rfc8292:0" then @@ -422,12 +424,14 @@ end end - local push_publish = st.message({ to = push_info.service, from = module.host, id = uuid.generate() }) - :add_child(push_notification_payload):up() + if any_match then + local push_publish = st.message({ to = push_info.service, from = module.host, id = uuid.generate() }) + :add_child(push_notification_payload):up() - -- TODO: watch for message error replies and count or something - module:send(push_publish) - pushes = pushes + 1 + -- TODO: watch for message error replies and count or something + module:send(push_publish) + pushes = pushes + 1 + end end end
--- a/mod_rest/README.md Sun Jun 01 11:43:16 2025 +0700 +++ b/mod_rest/README.md Sun Jun 01 13:51:38 2025 +0700 @@ -37,13 +37,11 @@ ## As a Component -If you install this as a component, you won't be able to use user authentication above, -and must use OAuth2 authentication outlined below. +If you install this as a component, the HTTP Basic credentials are the components base JID along with its secret. ``` {.lua} Component "chat.example.com" "rest" component_secret = "dmVyeSBzZWNyZXQgdG9rZW4K" -modules_enabled = {"http_oauth2"} ``` ## User authentication
--- a/mod_rest/mod_rest.lua Sun Jun 01 11:43:16 2025 +0700 +++ b/mod_rest/mod_rest.lua Sun Jun 01 13:51:38 2025 +0700 @@ -64,7 +64,7 @@ return nil, post_errors.new("noauthz", { request = request }); end - if auth_type == "basic" then + if auth_type == "basic" and module:get_host_type() == "local" then local creds = base64.decode(auth_data); if not creds then return nil, post_errors.new("malformauthz", { request = request }); @@ -81,6 +81,13 @@ return false, post_errors.new("unauthz", { request = request }); end return { username = username; host = module.host }; + elseif auth_type == "basic" and module:get_host_type() == "component" then + local component_secret = module:get_option_string("component_secret"); + local creds = base64.decode(auth_data); + if creds ~= module.host .. ":" .. component_secret then + return nil, post_errors.new("malformauthz", { request = request }); + end + return { host = module.host }; elseif auth_type == "bearer" then if tokens.get_token_session then local token_session, err = tokens.get_token_session(auth_data);