view mod_nodeinfo2/mod_nodeinfo2.lua @ 4651:8231774f5bfd

mod_cloud_notify_encrypted: Ensure body substring remains valid UTF-8 The `body:sub()` call risks splitting the string in the middle of a multi-byte UTF-8 sequence. This should have been caught by util.stanza validation, but that would have caused some havoc, at the very least causing the notification to not be sent. There have been no reports of this happening. Likely because this module isn't widely deployed among users with languages that use many longer UTF-8 sequences. The util.encodings.utf8.valid() function is O(n) where only the last sequence really needs to be checked, but it's in C and expected to be fast.
author Kim Alvefur <zash@zash.se>
date Sun, 22 Aug 2021 13:22:59 +0200
parents bac3dae031ee
children
line wrap: on
line source

local json = require "util.json";
local array = require "util.array";
local add_task = require "util.timer".add_task;
local get_stats = require "core.statsmanager".get_stats;
local list_users = require "core.usermanager".users;
local os_time = os.time;

assert(get_stats, "not compatible with trunk based on openmetrics");

module:depends("http");

local expose_users = module:get_option_boolean("nodeinfo2_expose_users", true);
if expose_users then
	module:depends("lastlog");
end

local expose_posts = module:get_option_boolean("nodeinfo2_expose_posts", true);
if expose_posts then
	module:depends("measure_message_e2ee");
end

local main_store = module:open_store();
local lastlog_store = module:open_store("lastlog");

local data;
if expose_posts then
	data = main_store:get("nodeinfo2") or { message_count = 0 };
end

local total_users = 0;
local week_users = 0;
local month_users = 0;
local half_year_users = 0;

local function update_user_list()
	for user in list_users(module.host) do
		total_users = total_users + 1;
		local lastlog = lastlog_store:get(user);
		if lastlog and lastlog.timestamp then
			local delta = os_time() - lastlog.timestamp;
			if delta < 7 * 86400 then
				week_users = week_users + 1;
			end
			if delta < 30 * 86400 then
				month_users = month_users + 1;
			end
			if delta < 6 * 30 * 86400 then
				half_year_users = half_year_users + 1;
			end
		end
	end

	-- Remove the properties if we couldn’t find a single active user.  It most likely means mod_lastlog isn’t in use.
	if half_year_users == 0 and month_users == 0 and week_users == 0 then
		week_users = nil;
		month_users = nil;
		half_year_users = nil;
	end
end

if expose_users then
	add_task(86400, update_user_list);
	update_user_list();
end

module:provides("http", {
	default_path = "/.well-known/x-nodeinfo2";
	route = {
		GET = function (event)
			local usage = {};
			if expose_users then
				usage.users = {
					total = total_users;
					activeWeek = week_users;
					activeMonth = month_users;
					activeHalfyear = half_year_users;
				};
			end

			if expose_posts then
				local stats, changed_only, extras = get_stats();
				for stat, _ in pairs(stats) do
					if stat == "/"..module.host.."/mod_measure_message_e2ee/message:rate" then
						local new_message_count = extras[stat].total;
						if new_message_count ~= data.message_count then
							data = { message_count = new_message_count };
							main_store:set("nodeinfo2", data);
						end
					end
				end
				usage.localPosts = data.message_count;
				-- TODO: also count PubSub replies here.
				usage.localComments = 0;
			end

			event.response.headers.content_type = "application/json";
			return json.encode({
				version = "1.0";
				server = {
					baseUrl = module:http_url("","/");
					name = module.host;
					software = "Prosody";
					version = prosody.version;
				};
				--[[ TODO re-use data from mod_server_contact_info ?
				organization = {
					name = "";
					contact = "";
					account = "";
				};
				--]]
				protocols = array {
					"xmpp",
				};
				services = {
					inbound = array {
						"xmpp";
					};
					outbound = array {
						"xmpp";
					};
				};
				openRegistrations = module:get_option_boolean("allow_registration", false);
				usage = usage;
			});
		end;
	}
});