Software / code / prosody
File
util/fsm.lua @ 13854:0b01f40df0f9 13.0
mod_http_file_share: Add media-src 'self' to Content-Security-Policy header
This allows certain media files to be loaded when navigated to directly in a
web browser.
Note that in some browsers (Chrome), the media gets transformed
internally into a HTML page with some basic styles, but these are blocked due
to our default-src policy of 'none' Although this could be unblocked with
style-src unsafe-inline, it is not our plan to fix this, because this would
have negative security implications.
The reason for our CSP is to prevent the file share service from being used to
host malicious HTML/CSS/JS. Yes, CSS can be malicious.
Our file share service is for uploading and downloading files, it is not a
substitute for website/content hosting.
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Fri, 18 Apr 2025 12:25:06 +0100 |
| parent | 13165:9c13c11b199d |
line wrap: on
line source
local events = require "prosody.util.events"; local fsm_methods = {}; local fsm_mt = { __index = fsm_methods }; local function is_fsm(o) local mt = getmetatable(o); return mt == fsm_mt; end local function notify_transition(fire_event, transition_event) local ret; ret = fire_event("transition", transition_event); if ret ~= nil then return ret; end if transition_event.from ~= transition_event.to then ret = fire_event("leave/"..transition_event.from, transition_event); if ret ~= nil then return ret; end end ret = fire_event("transition/"..transition_event.name, transition_event); if ret ~= nil then return ret; end end local function notify_transitioned(fire_event, transition_event) if transition_event.to ~= transition_event.from then fire_event("enter/"..transition_event.to, transition_event); end if transition_event.name then fire_event("transitioned/"..transition_event.name, transition_event); end fire_event("transitioned", transition_event); end local function do_transition(name) return function (self, attr) local new_state = self.fsm.states[self.state][name] or self.fsm.states["*"][name]; if not new_state then return error(("Invalid state transition: %s cannot %s"):format(self.state, name)); end local transition_event = { instance = self; name = name; to = new_state; to_attr = attr; from = self.state; from_attr = self.state_attr; }; local fire_event = self.fsm.events.fire_event; local ret = notify_transition(fire_event, transition_event); if ret ~= nil then return nil, ret; end self.state = new_state; self.state_attr = attr; notify_transitioned(fire_event, transition_event); return true; end; end local function new(desc) local self = setmetatable({ default_state = desc.default_state; events = events.new(); }, fsm_mt); -- states[state_name][transition_name] = new_state_name local states = { ["*"] = {} }; if desc.default_state then states[desc.default_state] = {}; end self.states = states; local instance_methods = {}; self._instance_mt = { __index = instance_methods }; for _, transition in ipairs(desc.transitions or {}) do local from_states = transition.from; if type(from_states) ~= "table" then from_states = { from_states }; end for _, from in ipairs(from_states) do if not states[from] then states[from] = {}; end if not states[transition.to] then states[transition.to] = {}; end if states[from][transition.name] then return error(("Duplicate transition in FSM specification: %s from %s"):format(transition.name, from)); end states[from][transition.name] = transition.to; end -- Add public method to trigger this transition instance_methods[transition.name] = do_transition(transition.name); end if desc.state_handlers then for state_name, handler in pairs(desc.state_handlers) do self.events.add_handler("enter/"..state_name, handler); end end if desc.transition_handlers then for transition_name, handler in pairs(desc.transition_handlers) do self.events.add_handler("transition/"..transition_name, handler); end end if desc.handlers then self.events.add_handlers(desc.handlers); end return self; end function fsm_methods:init(state_name, state_attr) local initial_state = assert(state_name or self.default_state, "no initial state specified"); if not self.states[initial_state] then return error("Invalid initial state: "..initial_state); end local instance = setmetatable({ fsm = self; state = initial_state; state_attr = state_attr; }, self._instance_mt); if initial_state ~= self.default_state then local fire_event = self.events.fire_event; notify_transitioned(fire_event, { instance = instance; to = initial_state; to_attr = state_attr; from = self.default_state; }); end return instance; end function fsm_methods:is_instance(o) local mt = getmetatable(o); return mt == self._instance_mt; end return { new = new; is_fsm = is_fsm; };