view mod_conversejs/mod_conversejs.lua @ 5418:f2c7bb3af600

mod_http_oauth2: Add role selector to consent page List includes all roles available to the user, if more than one. Defaults to either the first role in the scope string or the users primary role. Earlier draft listed all roles, but having options that can't be selected is bad UX and the entire list of all roles on the server could be long, and perhaps even sensitive. Allows e.g. picking a role with fewer permissions than what might otherwise have been selected. UX wise, doing this with more checkboxes or possibly radio buttons would have been confusion and/or looked messier. Fixes the previous situation where unselecting a role would default to the primary role, which could be more permissions than requested.
author Kim Alvefur <zash@zash.se>
date Fri, 05 May 2023 01:23:13 +0200
parents 079ca766193b
children 1c8197075d04
line wrap: on
line source

-- mod_conversejs
-- Copyright (C) 2017-2022 Kim Alvefur

local json_encode = require"util.json".encode;
local xml_escape = require "util.stanza".xml_escape;
local urlencode = require "util.http".urlencode;
local render = require "util.interpolation".new("%b{}", xml_escape, { json = json_encode });

module:depends"http";

local has_bosh = pcall(function ()
	module:depends"bosh";
end);

local has_ws = pcall(function ()
	module:depends("websocket");
end);

pcall(function ()
	module:depends("bookmarks");
end);

local cdn_url = module:get_option_string("conversejs_cdn", "https://cdn.conversejs.org");

local version = module:get_option_string("conversejs_version", "");
if version ~= "" then version = "/" .. version end

local serve_dist = nil;
local resources = module:get_option_path("conversejs_resources");
if resources then
	local serve;
	if prosody.process_type == "prosody" then
		-- Prosody >= trunk / 0.12
		local http_files = require "net.http.files";
		serve = http_files.serve;
	else
		-- Prosody <= 0.11
		serve = module:depends "http_files".serve;
	end
	local mime_map = module:shared("/*/http_files/mime").types or {css = "text/css"; js = "application/javascript"};
	serve_dist = serve({path = resources; mime_map = mime_map});

	cdn_url = module:http_url();
end

local js_url = module:get_option_string("conversejs_script", cdn_url..version.."/dist/converse.min.js");
local css_url = module:get_option_string("conversejs_css", cdn_url..version.."/dist/converse.min.css");

local html_template;

do
	local template_filename = module:get_option_string(module.name .. "_html_template", "templates/template.html");
	local template_file, err = module:load_resource(template_filename);
	if template_file then
		html_template, err = template_file:read("*a");
		template_file:close();
	end
	if not html_template then
		module:log("error", "Error loading HTML template: %s", err);
		html_template = render("<h1>mod_{module} could not read the template</h1>\
		<p>Tried to open <b>{filename}</b></p>\
		<pre>{error}</pre>",
			{ module = module.name, filename = template_filename, error = err });
	end
end

local js_template;
do
	local template_filename = module:get_option_string(module.name .. "_js_template", "templates/template.js");
	local template_file, err = module:load_resource(template_filename);
	if template_file then
		js_template, err = template_file:read("*a");
		template_file:close();
	end
	if not js_template then
		module:log("error", "Error loading JS template: %s", err);
		js_template = render("console.log(\"mod_{module} could not read the JS template: %s\", {error|json})",
			{ module = module.name, filename = template_filename, error = err });
	end
end

local function get_converse_options()
	local user_options = module:get_option("conversejs_options");

	local allow_registration = module:get_option_boolean("allow_registration", false);
	local converse_options = {
		-- Auto-detected connection endpoints
		bosh_service_url = has_bosh and module:http_url("bosh","/http-bind") or nil;
		websocket_url = has_ws and module:http_url("websocket","xmpp-websocket"):gsub("^http", "ws") or nil;
		-- Since we provide those, XEP-0156 based auto-discovery should not be used
		discover_connection_methods = false;
		-- Authentication mode to use (normal or guest login)
		authentication = module:get_option_string("authentication") == "anonymous" and "anonymous" or "login";
		-- Host to connect to for anonymous access
		jid = module.host;
		-- Let users login with only username
		default_domain = module.host;
		domain_placeholder = module.host;
		-- If registration is enabled
		allow_registration = allow_registration;
		-- and if it is, which domain to register with
		registration_domain = allow_registration and module.host or nil;
		-- Path to resources like emoji, icons, sounds
		assets_path = cdn_url..version.."/dist/";
		-- Default most suited for use as a "normal" client
		view_mode = "fullscreen";
	};

	-- Let config override the above defaults
	if type(user_options) == "table" then
		for k,v in pairs(user_options) do
			converse_options[k] = v;
		end
	end

	return converse_options;
end

local add_tags = module:get_option_array("conversejs_tags", {});

module:provides("http", {
	title = "Converse.js";
	route = {
		GET = function (event)
			local converse_options = get_converse_options();

			event.response.headers.content_type = "text/html";
			return render(html_template, {
					service_name = module:get_option_string("name");
					header_scripts = { js_url };
					header_style = { css_url };
					header_tags = add_tags;
					conversejs = {
						options = converse_options;
						startup = { script = js_template:format(json_encode(converse_options)); }
					};
				});
		end;

		["GET /prosody-converse.js"] = function (event)
			local converse_options = get_converse_options();

			event.response.headers.content_type = "application/javascript";
			return js_template:format(json_encode(converse_options));
		end;
		["GET /dist/*"] = serve_dist;
	}
});

module:provides("site-app", {
	name = "Converse.js";
	text = [[A free and open-source XMPP chat client in your browser]];
	image = "assets/logos/converse-js.svg";
	link = "https://conversejs.org/";
	magic_link_format = "/register?t={invite.token}&c=converse-js";
	login_link_format = module:http_url();
	platforms = { "Web" };
	download = {
		buttons = {
			{
				text = "Open web chat";
				url = module:http_url();
			};
		};
	};

});