# HG changeset patch # User Trần H. Trung # Date 1688841089 -25200 # Node ID 04f36a470dca77e486f4162980739df2f37b597f # Parent 680fb3344357989e559b55cae99cbbe6f3ddf87d# Parent 59acf7f540c16fe64f0063785754a08e5b15e6b0 Update from upstream diff -r 680fb3344357 -r 04f36a470dca misc/lnav/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/lnav/README.md Sun Jul 09 01:31:29 2023 +0700 @@ -0,0 +1,6 @@ +% Prosody log format for lnav + +This is a format definition that allows to better +handle Prosody logs. + +Install it using `lnav -i ./prosody.json` diff -r 680fb3344357 -r 04f36a470dca misc/lnav/prosody.json --- a/misc/lnav/prosody.json Fri May 26 02:15:45 2023 +0700 +++ b/misc/lnav/prosody.json Sun Jul 09 01:31:29 2023 +0700 @@ -14,7 +14,7 @@ "ordered-by-time" : true, "regex" : { "standard" : { - "pattern" : "^(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2})\\s+(?\\S+)\\s+(?debug|info|warn|error)\\s+(?.+)$" + "pattern" : "^(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}\\s+)(?\\S+)\\s+(?debug|info|warn|error)\\s+(?.+)$" } }, "sample" : [ @@ -23,7 +23,9 @@ } ], "timestamp-field" : "timestamp", - "timestamp-format" : "%b %d %H:%M:%S ", + "timestamp-format" : [ + "%b %d %H:%M:%S " + ], "title" : "Prosody log", "url" : "https://prosody.im/doc/logging", "value" : { diff -r 680fb3344357 -r 04f36a470dca mod_auth_oauth_external/README.md --- a/mod_auth_oauth_external/README.md Fri May 26 02:15:45 2023 +0700 +++ b/mod_auth_oauth_external/README.md Sun Jul 09 01:31:29 2023 +0700 @@ -79,7 +79,7 @@ owner password grant. `oauth_external_scope` -: String. Defaults to `"oauth"`. Included in request for resource +: String. Defaults to `"openid"`. Included in request for resource owner password grant. # Compatibility diff -r 680fb3344357 -r 04f36a470dca mod_client_management/mod_client_management.lua --- a/mod_client_management/mod_client_management.lua Fri May 26 02:15:45 2023 +0700 +++ b/mod_client_management/mod_client_management.lua Sun Jul 09 01:31:29 2023 +0700 @@ -10,8 +10,8 @@ local strict = module:get_option_boolean("enforce_client_ids", false); -module:default_permission("prosody:user", ":list-clients"); -module:default_permission("prosody:user", ":manage-clients"); +module:default_permission("prosody:registered", ":list-clients"); +module:default_permission("prosody:registered", ":manage-clients"); local tokenauth = module:depends("tokenauth"); local mod_fast = module:depends("sasl2_fast"); @@ -35,6 +35,8 @@ if not (sasl_agent or token_agent) then return; end return { software = sasl_agent and sasl_agent.software or token_agent and token_agent.name or nil; + software_id = token_agent and token_agent.id or nil; + software_version = token_agent and token_agent.version or nil; uri = token_agent and token_agent.uri or nil; device = sasl_agent and sasl_agent.device or nil; }; @@ -348,7 +350,7 @@ local user_agent = st.stanza("user-agent"); if client.user_agent then if client.user_agent.software then - user_agent:text_tag("software", client.user_agent.software); + user_agent:text_tag("software", client.user_agent.software, { id = client.user_agent.software_id; version = client.user_agent.software_version }); end if client.user_agent.device then user_agent:text_tag("device", client.user_agent.device); diff -r 680fb3344357 -r 04f36a470dca mod_cloud_notify_extensions/README.markdown --- a/mod_cloud_notify_extensions/README.markdown Fri May 26 02:15:45 2023 +0700 +++ b/mod_cloud_notify_extensions/README.markdown Sun Jul 09 01:31:29 2023 +0700 @@ -38,13 +38,10 @@ There is no configuration for this module, just add it to modules\_enabled as normal. -Compatibility -============= +# Compatibility - ----- ------- - 0.12 Works - ----- ------- - 0.11 Should work - ----- ------- - trunk Works - ----- ------- + ------- ------------- + 0.12 Works + 0.11 Should work + trunk Works + ------- ------------- diff -r 680fb3344357 -r 04f36a470dca mod_compat_roles/mod_compat_roles.lua --- a/mod_compat_roles/mod_compat_roles.lua Fri May 26 02:15:45 2023 +0700 +++ b/mod_compat_roles/mod_compat_roles.lua Sun Jul 09 01:31:29 2023 +0700 @@ -33,8 +33,12 @@ local role_inheritance = { ["prosody:operator"] = "prosody:admin"; - ["prosody:admin"] = "prosody:user"; - ["prosody:user"] = "prosody:restricted"; + ["prosody:admin"] = "prosody:member"; + ["prosody:member"] = "prosody:registered"; + ["prosody:registered"] = "prosody:guest"; + + -- COMPAT + ["prosody:user"] = "prosody:registered"; }; local function role_may(host, role_name, permission) diff -r 680fb3344357 -r 04f36a470dca mod_firewall/README.markdown --- a/mod_firewall/README.markdown Fri May 26 02:15:45 2023 +0700 +++ b/mod_firewall/README.markdown Sun Jul 09 01:31:29 2023 +0700 @@ -10,6 +10,8 @@ mod_firewall.definitions: definitions.lib.lua mod_firewall.marks: marks.lib.lua mod_firewall.test: test.lib.lua + copy_directories: + - scripts --- ------------------------------------------------------------------------ @@ -253,12 +255,13 @@ ### Sender/recipient matching - Condition Matches - ------------- ------------------------------------------------------- - `FROM` The JID in the 'from' attribute matches the given JID. - `TO` The JID in the 'to' attribute matches the given JID. - `TO SELF` The stanza is sent by any of a user's resources to their own bare JID. - `TO FULL JID` The stanza is addressed to a valid full JID on the local server (full JIDs include a resource at the end, and only exist for the lifetime of a single session, therefore the recipient must be online, or this check will not match). + Condition Matches + --------------- ------------------------------------------------------- + `FROM` The JID in the 'from' attribute matches the given JID. + `TO` The JID in the 'to' attribute matches the given JID. + `TO SELF` The stanza is sent by any of a user's resources to their own bare JID. + `TO FULL JID` The stanza is addressed to a **valid** full JID on the local server (full JIDs include a resource at the end, and only exist for the lifetime of a single session, therefore the recipient **must be online**, or this check will not match). + `FROM FULL JID` The stanza is from a full JID (unlike `TO FULL JID` this check is on the format of the JID only). The TO and FROM conditions both accept wildcards in the JID when it is enclosed in angle brackets ('\<...\>'). For example: diff -r 680fb3344357 -r 04f36a470dca mod_firewall/actions.lib.lua --- a/mod_firewall/actions.lib.lua Fri May 26 02:15:45 2023 +0700 +++ b/mod_firewall/actions.lib.lua Sun Jul 09 01:31:29 2023 +0700 @@ -220,11 +220,29 @@ end function action_handlers.MARK_USER(name) - return [[if session.firewall_marks then session.firewall_marks.]]..idsafe(name)..[[ = current_timestamp; end]], { "timestamp" }; + return ([[if session.username and session.host == current_host then + fire_event("firewall/marked/user", { + username = session.username; + mark = %q; + timestamp = current_timestamp; + }); + else + log("warn", "Attempt to MARK a remote user - only local users may be marked"); + end]]):format(assert(idsafe(name), "Invalid characters in mark name: "..name)), { + "current_host"; + "timestamp"; + }; end function action_handlers.UNMARK_USER(name) - return [[if session.firewall_marks then session.firewall_marks.]]..idsafe(name)..[[ = nil; end]], { "timestamp" }; + return ([[if session.username and session.host == current_host then + fire_event("firewall/unmarked/user", { + username = session.username; + mark = %q; + }); + else + log("warn", "Attempt to UNMARK a remote user - only local users may be marked"); + end]]):format(assert(idsafe(name), "Invalid characters in mark name: "..name)); end function action_handlers.ADD_TO(spec) diff -r 680fb3344357 -r 04f36a470dca mod_firewall/conditions.lib.lua --- a/mod_firewall/conditions.lib.lua Fri May 26 02:15:45 2023 +0700 +++ b/mod_firewall/conditions.lib.lua Sun Jul 09 01:31:29 2023 +0700 @@ -67,6 +67,10 @@ return compile_jid_match("from", from), { "split_from" }; end +function condition_handlers.FROM_FULL_JID() + return "not "..compile_jid_match_part("from_resource", nil), { "split_from" }; +end + function condition_handlers.FROM_EXACTLY(from) local metadeps = {}; return ("from == %s"):format(metaq(from, metadeps)), { "from", unpack(metadeps) }; @@ -310,7 +314,9 @@ error("Error parsing mark name, see documentation for usage examples"); end if time then - return ("(current_timestamp - (session.firewall_marks and session.firewall_marks.%s or 0)) < %d"):format(idsafe(name), tonumber(time)), { "timestamp" }; + return ([[( + current_timestamp - (session.firewall_marks and session.firewall_marks.%s or 0) + ) < %d]]):format(idsafe(name), tonumber(time)), { "timestamp" }; end return ("not not (session.firewall_marks and session.firewall_marks."..idsafe(name)..")"); end @@ -341,7 +347,13 @@ if not (search_name) then error("Error parsing SCAN expression, syntax: SEARCH for PATTERN in LIST"); end - return ("scan_list(list_%s, %s)"):format(list_name, "tokens_"..search_name.."_"..pattern_name), { "scan_list", "tokens:"..search_name.."-"..pattern_name, "list:"..list_name }; + return ("scan_list(list_%s, %s)"):format( + list_name, + "tokens_"..search_name.."_"..pattern_name + ), { + "scan_list", + "tokens:"..search_name.."-"..pattern_name, "list:"..list_name + }; end -- COUNT: lines in body < 10 @@ -361,7 +373,12 @@ end local comp_op = comparator_expression:gsub("%s+", ""); assert(valid_comp_ops[comp_op], "Error parsing COUNT expression, unknown comparison operator: "..comp_op); - return ("it_count(search_%s:gmatch(pattern_%s)) %s %d"):format(search_name, pattern_name, comp_op, value), { "it_count", "search:"..search_name, "pattern:"..pattern_name }; + return ("it_count(search_%s:gmatch(pattern_%s)) %s %d"):format( + search_name, pattern_name, comp_op, value + ), { + "it_count", + "search:"..search_name, "pattern:"..pattern_name + }; end return condition_handlers; diff -r 680fb3344357 -r 04f36a470dca mod_firewall/marks.lib.lua --- a/mod_firewall/marks.lib.lua Fri May 26 02:15:45 2023 +0700 +++ b/mod_firewall/marks.lib.lua Sun Jul 09 01:31:29 2023 +0700 @@ -1,23 +1,35 @@ local mark_storage = module:open_store("firewall_marks"); +local mark_map_storage = module:open_store("firewall_marks", "map"); local user_sessions = prosody.hosts[module.host].sessions; -module:hook("resource-bind", function (event) - local session = event.session; - local username = session.username; - local user = user_sessions[username]; - local marks = user.firewall_marks; - if not marks then - marks = mark_storage:get(username) or {}; - user.firewall_marks = marks; -- luacheck: ignore 122 +module:hook("firewall/marked/user", function (event) + local user = user_sessions[event.username]; + local marks = user and user.firewall_marks; + if user and not marks then + -- Load marks from storage to cache on the user object + marks = mark_storage:get(event.username) or {}; + user.firewall_marks = marks; --luacheck: ignore 122 + end + if marks then + marks[event.mark] = event.timestamp; + end + local ok, err = mark_map_storage:set(event.username, event.mark, event.timestamp); + if not ok then + module:log("error", "Failed to mark user %q with %q: %s", event.username, event.mark, err); end - session.firewall_marks = marks; -end); + return true; +end, -1); -module:hook("resource-unbind", function (event) - local session = event.session; - local username = session.username; - local marks = session.firewall_marks; - mark_storage:set(username, marks); -end); - +module:hook("firewall/unmarked/user", function (event) + local user = user_sessions[event.username]; + local marks = user and user.firewall_marks; + if marks then + marks[event.mark] = nil; + end + local ok, err = mark_map_storage:set(event.username, event.mark, nil); + if not ok then + module:log("error", "Failed to unmark user %q with %q: %s", event.username, event.mark, err); + end + return true; +end, -1); diff -r 680fb3344357 -r 04f36a470dca mod_firewall/mod_firewall.lua --- a/mod_firewall/mod_firewall.lua Fri May 26 02:15:45 2023 +0700 +++ b/mod_firewall/mod_firewall.lua Sun Jul 09 01:31:29 2023 +0700 @@ -316,7 +316,7 @@ local condition_handlers = module:require("conditions"); local action_handlers = module:require("actions"); -if module:get_option_boolean("firewall_experimental_user_marks", false) then +if module:get_option_boolean("firewall_experimental_user_marks", true) then module:require"marks"; end @@ -742,3 +742,43 @@ print("end -- End of file "..filename); end end + + +-- Console + +local console_env = module:shared("/*/admin_shell/env"); + +console_env.firewall = {}; + +function console_env.firewall:mark(user_jid, mark_name) + local username, host = jid.split(user_jid); + if not username or not hosts[host] then + return nil, "Invalid JID supplied"; + elseif not idsafe(mark_name) then + return nil, "Invalid characters in mark name"; + end + if not module:context(host):fire_event("firewall/marked/user", { + username = session.username; + mark = mark_name; + timestamp = os.time(); + }) then + return nil, "Mark not set - is mod_firewall loaded on that host?"; + end + return true, "User marked"; +end + +function console_env.firewall:unmark(jid, mark_name) + local username, host = jid.split(user_jid); + if not username or not hosts[host] then + return nil, "Invalid JID supplied"; + elseif not idsafe(mark_name) then + return nil, "Invalid characters in mark name"; + end + if not module:context(host):fire_event("firewall/unmarked/user", { + username = session.username; + mark = mark_name; + }) then + return nil, "Mark not removed - is mod_firewall loaded on that host?"; + end + return true, "User unmarked"; +end diff -r 680fb3344357 -r 04f36a470dca mod_firewall/scripts/spam-blocking.pfw --- a/mod_firewall/scripts/spam-blocking.pfw Fri May 26 02:15:45 2023 +0700 +++ b/mod_firewall/scripts/spam-blocking.pfw Sun Jul 09 01:31:29 2023 +0700 @@ -97,6 +97,12 @@ TYPE: groupchat PASS. +# Mediated MUC invitations are naturally from 'strangers' and have special +# handling. We lean towards accepting them, unless overridden by custom rules. +NOT FROM FULL JID? +INSPECT: {http://jabber.org/protocol/muc#user}x/invite +JUMP CHAIN=user/spam_check_muc_invite + # Non-chat message types often generate pop-ups in clients, # so we won't accept them from strangers NOT TYPE: chat @@ -138,6 +144,18 @@ ################################################################## +#### Rules for MUC invitations ################################### + +::user/spam_check_muc_invite + +# This chain can be used to inspect the invitation and determine +# the appropriate action. Otherwise, we proceed with the default +# action below. +JUMP CHAIN=user/spam_check_muc_invite_custom + +# Allow mediated MUC invitations by default +PASS. + #### Stanzas reaching this chain will be rejected ################ ::user/spam_reject @@ -151,7 +169,7 @@ ################################################################## -#### Stanzas that may be spam, but we're not sure either way###### +#### Stanzas that may be spam, but we're not sure either way ##### ::user/spam_handle_unknown # This chain can be used by other scripts diff -r 680fb3344357 -r 04f36a470dca mod_firewall/scripts/spam-blocklists.pfw --- a/mod_firewall/scripts/spam-blocklists.pfw Fri May 26 02:15:45 2023 +0700 +++ b/mod_firewall/scripts/spam-blocklists.pfw Sun Jul 09 01:31:29 2023 +0700 @@ -8,3 +8,13 @@ CHECK LIST: blocklist contains $<@from|host> BOUNCE=policy-violation (Your server is blocked due to spam) + +::user/spam_check_muc_invite_custom + +# Check the server we received the invitation from +CHECK LIST: blocklist contains $<@from|host> +BOUNCE=policy-violation (Your server is blocked due to spam) + +# Check the inviter's JID against the blocklist, too +CHECK LIST: blocklist contains $<{http://jabber.org/protocol/muc#user}x/invite@from|host> +BOUNCE=policy-violation (Your server is blocked due to spam) diff -r 680fb3344357 -r 04f36a470dca mod_groups_oidc/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_groups_oidc/README.md Sun Jul 09 01:31:29 2023 +0700 @@ -0,0 +1,12 @@ +--- +summary: OIDC group membership in UserInfo +labels: +- Stage-Alpha +rockspec: + dependencies: + - mod_http_oauth2 >= 200 + - mod_groups_internal +--- + +This module exposes [mod_groups_internal] groups to +[OAuth 2.0][mod_http_oauth2] clients via a `groups` scope/claim. diff -r 680fb3344357 -r 04f36a470dca mod_groups_oidc/mod_groups_oidc.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_groups_oidc/mod_groups_oidc.lua Sun Jul 09 01:31:29 2023 +0700 @@ -0,0 +1,15 @@ +local array = require "util.array"; + +module:add_item("openid-claim", "groups"); + +local group_memberships = module:open_store("groups", "map"); +local function user_groups(username) + return pairs(group_memberships:get_all(username) or {}); +end + +module:hook("token/userinfo", function(event) + local userinfo = event.userinfo; + if event.claims:contains("groups") then + userinfo.groups = array(user_groups(event.username)); + end +end); diff -r 680fb3344357 -r 04f36a470dca mod_http_debug/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_http_debug/README.md Sun Jul 09 01:31:29 2023 +0700 @@ -0,0 +1,40 @@ +--- +summary: HTTP module returning info about requests for debugging +--- + +This module returns some info about HTTP requests as Prosody sees them +from an endpoint like `http://xmpp.example.net:5281/debug`. This can be +used to validate [reverse-proxy configuration][doc:http] and similar use +cases. + +# Example + +``` +$ curl -sSf https://xmpp.example.net:5281/debug | json_pp +{ + "body" : "", + "headers" : { + "accept" : "*/*", + "host" : "xmpp.example.net:5281", + "user_agent" : "curl/7.74.0" + }, + "httpversion" : "1.1", + "id" : "jmFROQKoduU3", + "ip" : "127.0.0.1", + "method" : "GET", + "path" : "/debug", + "secure" : true, + "url" : { + "path" : "/debug" + } +} +``` + +# Configuration + +HTTP Methods handled can be configured via the `http_debug_methods` +setting. By default, the most common methods are already enabled. + +```lua +http_debug_methods = { "GET"; "HEAD"; "DELETE"; "OPTIONS"; "PATCH"; "POST"; "PUT" }; +``` diff -r 680fb3344357 -r 04f36a470dca mod_http_debug/mod_http_debug.lua --- a/mod_http_debug/mod_http_debug.lua Fri May 26 02:15:45 2023 +0700 +++ b/mod_http_debug/mod_http_debug.lua Sun Jul 09 01:31:29 2023 +0700 @@ -1,26 +1,34 @@ local json = require "util.json" module:depends("http") +local function handle_request(event) + local request = event.request; + (request.log or module._log)("debug", "%s -- %s %q HTTP/%s -- %q -- %s", request.ip, request.method, request.url, request.httpversion, request.headers, request.body); + return { + status_code = 200; + headers = { content_type = "application/json" }; + host = module.host; + body = json.encode { + body = request.body; + headers = request.headers; + httpversion = request.httpversion; + id = request.id; + ip = request.ip; + method = request.method; + path = request.path; + secure = request.secure; + url = request.url; + }; + } +end + +local methods = module:get_option_set("http_debug_methods", { "GET"; "HEAD"; "DELETE"; "OPTIONS"; "PATCH"; "POST"; "PUT" }); +local route = {}; +for method in methods do + route[method] = handle_request; + route[method .. " /*"] = handle_request; +end + module:provides("http", { - route = { - GET = function(event) - local request = event.request; - return { - status_code = 200; - headers = { - content_type = "application/json", - }, - body = json.encode { - body = request.body; - headers = request.headers; - httpversion = request.httpversion; - ip = request.ip; - method = request.method; - path = request.path; - secure = request.secure; - url = request.url; - } - } - end; - } - }) + route = route; +}) diff -r 680fb3344357 -r 04f36a470dca mod_http_dir_listing/README.markdown --- a/mod_http_dir_listing/README.markdown Fri May 26 02:15:45 2023 +0700 +++ b/mod_http_dir_listing/README.markdown Sun Jul 09 01:31:29 2023 +0700 @@ -2,9 +2,9 @@ rockspec: build: copy_directories: - - mod_http_dir_listing/http_dir_listing/resources + - http_dir_listing/resources modules: - mod_http_dir_listing: mod_http_dir_listing/http_dir_listing/mod_http_dir_listing.lua + mod_http_dir_listing: http_dir_listing/mod_http_dir_listing.lua summary: HTTP directory listing ... diff -r 680fb3344357 -r 04f36a470dca mod_http_dir_listing2/README.markdown --- a/mod_http_dir_listing2/README.markdown Fri May 26 02:15:45 2023 +0700 +++ b/mod_http_dir_listing2/README.markdown Sun Jul 09 01:31:29 2023 +0700 @@ -1,6 +1,10 @@ --- summary: HTTP directory listing -... +rockspec: + build: + copy_directories: + - resources +--- Introduction ============ diff -r 680fb3344357 -r 04f36a470dca mod_http_muc_log/mod_http_muc_log.lua --- a/mod_http_muc_log/mod_http_muc_log.lua Fri May 26 02:15:45 2023 +0700 +++ b/mod_http_muc_log/mod_http_muc_log.lua Sun Jul 09 01:31:29 2023 +0700 @@ -128,17 +128,42 @@ local presence_logged = module:get_option_boolean("muc_log_presences", false); -local function hide_presence(request) +local function show_presence(request) --> boolean|nil + -- boolean -> yes or no + -- nil -> dunno if not presence_logged then - return false; + -- No presence stored, skip + return nil; end if request.url.query then local data = httplib.formdecode(request.url.query); - if data then - return data.p == "h" + if type(data) == "table" then + if data.p == "s" or data.p == "h" then + return data.p == "s"; + end end end - return false; +end + +local function presence_with(request) + local show = show_presence(request); + if show == true then + return nil; -- no filter, everything + elseif show == false or show == nil then + -- only messages + return "message ?p=[sh] + local show = show_presence(request); + if show == true then + return { p = "s" } + elseif show == false then + return { p = "h" } + else + return nil; + end end local function get_dates(room) --> { integer, ... } @@ -254,7 +279,8 @@ room = room_obj._data; jid = room_obj.jid; jid_node = jid_split(room_obj.jid); - hide_presence = hide_presence(request); + q = presence_query(request); + show_presence = show_presence(request); presence_available = presence_logged; dates = date_list; links = { @@ -300,7 +326,7 @@ local iter, err = archive:find(room, { ["start"] = day_start; ["end"] = day_start + 86399; - ["with"] = hide_presence(request) and "messageJoin via web } {links# -
  • {item.text}
  • } +
  • {item.text}
  • } @@ -28,7 +28,7 @@