Mercurial > prosody-modules
view mod_http_connect/mod_http_connect.lua @ 6280:6ea80b73d8f2
mod_http_oauth2: Only require redirect URIs when using grant types that need it
In the Device flow, no redirect URI is used because the client instead
receives responses by polling. It is therefore unnecessary to enforce a
requirement that these include redirect URI(s).
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Thu, 03 Jul 2025 15:42:42 +0200 |
| parents | 706867e05809 |
| children |
line wrap: on
line source
-- This feature was added after Prosody 13.0 --% requires: net-connect-filter local hashes = require "prosody.util.hashes"; local server = require "prosody.net.server"; local connect = require"prosody.net.connect".connect; local basic = require "prosody.net.resolvers.basic"; local new_ip = require "prosody.util.ip".new_ip; local b64_decode = require "prosody.util.encodings".base64.decode; local proxy_secret = module:get_option_string("http_proxy_secret", require "prosody.util.id".long()); local allow_private_ips = module:get_option_boolean("http_proxy_to_private_ips", false); local allow_all_ports = module:get_option_boolean("http_proxy_to_all_ports", false); local allowed_target_ports = module:get_option_set("http_proxy_to_ports", { "443", "5281", "5443", "7443" }) / tonumber; local sessions = {}; local listeners = {}; function listeners.onconnect(conn) local event = sessions[conn]; local response = event.response; response.status_code = 200; response:send(""); response.conn:onwritable(); response.conn:setlistener(listeners, event); server.link(conn, response.conn); server.link(response.conn, conn); response.conn = nil; end function listeners.onattach(conn, event) sessions[conn] = event; end function listeners.onfail(event, err) local response = event.response; if assert(response) then response.status_code = 500; response:send(err); end end function listeners.ondisconnect(conn, err) --luacheck: ignore 212/conn 212/err end local function is_permitted_target(conn_type, ip, port) if not (allow_all_ports or allowed_target_ports:contains(tonumber(port))) then module:log("warn", "Forbidding tunnel to %s:%d (forbidden port)", ip, port); return false; end if not allow_private_ips then local family = (conn_type:byte(-1, -1) == 54) and "IPv6" or "IPv4"; local parsed_ip = new_ip(ip, family); if parsed_ip.private then module:log("warn", "Forbidding tunnel to %s:%d (forbidden ip)", ip, port); return false; end end return true; end local function verify_auth(user, password) local expiry = tonumber(user, 10); if os.time() > expiry then module:log("warn", "Attempt to use expired credentials"); return nil; end local expected_password = hashes.hmac_sha1(proxy_secret, user); if hashes.equals(b64_decode(password), expected_password) then return true; end module:log("warn", "Credential mismatch for %s: expected '%q' got '%q'", user, expected_password, password); end module:depends("http"); module:provides("http", { default_path = "/"; route = { ["CONNECT /*"] = function(event) local request, response = event.request, event.response; local host, port = request.url.scheme, request.url.path; if port == "" then return 400 end -- Auth check local realm = host; local headers = request.headers; if not headers.proxy_authorization then response.headers.proxy_authenticate = ("Basic realm=%q"):format(realm); return 407 end local user, password = b64_decode(headers.proxy_authorization:match"[^ ]*$"):match"([^:]*):(.*)"; if not verify_auth(user, password) then response.headers.proxy_authenticate = ("Basic realm=%q"):format(realm); return 407 end local resolve = basic.new(host, port, "tcp", { filter = is_permitted_target; }); connect(resolve, listeners, nil, event) return true; end; } }); local http_url = module:http_url(); local parsed_url = require "socket.url".parse(http_url); local proxy_host = parsed_url.host; local proxy_port = tonumber(parsed_url.port); if not proxy_port then if parsed_url.scheme == "https" then proxy_port = 443; elseif parsed_url.scheme == "http" then proxy_port = 80; end end module:depends "external_services"; module:add_item("external_service", { type = "http"; transport = "tcp"; host = proxy_host; port = proxy_port; secret = proxy_secret; algorithm = "turn"; ttl = 3600; });
