Mercurial > prosody-modules
view mod_muc_log/mod_muc_log.lua @ 5193:2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Replaces previous explicit registration that required either the
additional module mod_adhoc_oauth2_client or manually editing the
database. That method was enough to have something to test with, but
would not probably not scale easily.
Dynamic client registration allows creating clients on the fly, which
may be even easier in theory.
In order to not allow basically unauthenticated writes to the database,
we implement a stateless model here.
per_host_key := HMAC(config -> oauth2_registration_key, hostname)
client_id := JWT { client metadata } signed with per_host_key
client_secret := HMAC(per_host_key, client_id)
This should ensure everything we need to know is part of the client_id,
allowing redirects etc to be validated, and the client_secret can be
validated with only the client_id and the per_host_key.
A nonce injected into the client_id JWT should ensure nobody can submit
the same client metadata and retrieve the same client_secret
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Fri, 03 Mar 2023 21:14:19 +0100 |
parents | 585bb8ac11bb |
children |
line wrap: on
line source
-- Copyright (C) 2009 Thilo Cestonaro -- Copyright (C) 2009 Waqas Hussain -- Copyright (C) 2009-2013 Matthew Wild -- Copyright (C) 2013 Kim Alvefur -- Copyright (C) 2013 Marco Cirillo local hosts = prosody.hosts; local tostring = tostring; local split_jid = require "util.jid".split; local datamanager = require"core.storagemanager".olddm; local data_load, data_store = datamanager.load, datamanager.store; local datastore = "muc_log"; local muc_form_config_option = "muc#roomconfig_enablelogging" local log_by_default = module:get_option_boolean("muc_log_by_default", false); local log_presences = module:get_option_boolean("muc_log_presences", true); -- Module Definitions local function get_room_from_jid(jid) local node, host = split_jid(jid); local component = hosts[host]; if component then local muc = component.modules.muc if muc and rawget(muc,"rooms") then -- We're running 0.9.x or 0.10 (old MUC API) return muc.rooms[jid]; elseif muc and rawget(muc,"get_room_from_jid") then -- We're running >0.10 (new MUC API) return muc.get_room_from_jid(jid); else return end end end local function logging_enabled(room) local enabled = room._data.logging; if enabled == nil then return log_by_default; end return enabled; end function log_if_needed(event) local stanza = event.stanza; if (stanza.name == "presence") or (stanza.name == "iq") or (stanza.name == "message" and tostring(stanza.attr.type) == "groupchat") then local node, host = split_jid(stanza.attr.to); if node and host then local bare = node .. "@" .. host; if get_room_from_jid(bare) then local room = get_room_from_jid(bare) local today = os.date("!%y%m%d"); local now = os.date("!%H:%M:%S"); local muc_to = nil local muc_from = nil; local already_joined = false; if room._data.hidden then -- do not log any data of private rooms return; end if not logging_enabled(room) then -- do not log where logging is not enabled return; end if stanza.name == "presence" and stanza.attr.type == nil then muc_from = stanza.attr.to; if room._occupants and room._occupants[stanza.attr.to] then already_joined = true; stanza:tag("alreadyJoined"):text("true"); end elseif stanza.name == "iq" and stanza.attr.type == "set" then -- kick, to is the room, from is the admin, nick who is kicked is attr of iq->query->item if stanza.tags[1] and stanza.tags[1].name == "query" then local tmp = stanza.tags[1]; if tmp.tags[1] ~= nil and tmp.tags[1].name == "item" and tmp.tags[1].attr.nick then tmp = tmp.tags[1]; for jid, nick in pairs(room._jid_nick) do if nick == stanza.attr.to .. "/" .. tmp.attr.nick then muc_to = nick; break; end end end end else for jid, nick in pairs(room._jid_nick) do if jid == stanza.attr.from then muc_from = nick; break; end end end if (muc_from or muc_to) then local data = data_load(node, host, datastore .. "/" .. today); local realFrom = stanza.attr.from; local realTo = stanza.attr.to; if data == nil then data = {}; end stanza.attr.from = muc_from; stanza.attr.to = muc_to; data[#data + 1] = "<stanza time=\"".. now .. "\">" .. tostring(stanza) .. "</stanza>\n"; stanza.attr.from = realFrom; stanza.attr.to = realTo; if already_joined == true then if stanza[#stanza].name == "alreadyJoined" then -- normaly the faked element should be the last, remove it when it is the last stanza[#stanza] = nil; else for i = 1, #stanza, 1 do if stanza[i].name == "alreadyJoined" then -- remove the faked element stanza[i] = nil; break; end end end end datamanager.getpath(node, host, datastore, nil, true); -- create the datastore dir data_store(node, host, datastore .. "/" .. today, data); end end end end end module:hook("muc-config-form", function(event) local room, form = event.room, event.form; table.insert(form, { name = muc_form_config_option, type = "boolean", label = "Enable Logging?", value = logging_enabled(room), } ); end); module:hook("muc-config-submitted", function(event) local room, fields, changed = event.room, event.fields, event.changed; local new = fields[muc_form_config_option]; if new ~= room._data.logging then room._data.logging = new; if type(changed) == "table" then changed[muc_form_config_option] = true; else event.changed = true; end end end); module:hook("message/bare", log_if_needed, 1); if log_presences then module:hook("iq/bare", log_if_needed, 1); module:hook("presence/full", log_if_needed, 1); end module:log("debug", "module mod_muc_log loaded!");