mod_lastlog2/mod_lastlog2.lua
author Kim Alvefur <zash@zash.se>
Sun, 03 Mar 2024 11:23:40 +0100
changeset 5857 97c9b76867ca
parent 5780 5239ed05bd71
child 5880 c5df6d53f17f
permissions -rw-r--r--
mod_log_ringbuffer: Detach event handlers on logging reload (thanks Menel) Otherwise the global event handlers accumulate, one added each time logging is reoladed, and each invocation of the signal or event triggers one dump of each created ringbuffer.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1049
59f031d1cd38 mod_last_offline: Merge into an option of mod_lastlog
Kim Alvefur <zash@zash.se>
parents: 1048
diff changeset
     1
local jid = require "util.jid";
615
4134d0e25242 mod_lastlog: New module to record last time a user authenticated
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     2
local time = os.time;
616
884ae37d76bf mod_lastlog: Add option to also log the users IP address.
Kim Alvefur <zash@zash.se>
parents: 615
diff changeset
     3
local log_ip = module:get_option_boolean("lastlog_ip_address", false);
4016
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
     4
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
     5
local store;
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
     6
if module.host ~= "*" then -- workaround for prosodyctl loading into global context
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
     7
	store = module:open_store(nil, "map");
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
     8
end
615
4134d0e25242 mod_lastlog: New module to record last time a user authenticated
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     9
4134d0e25242 mod_lastlog: New module to record last time a user authenticated
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    10
module:hook("authentication-success", function(event)
4134d0e25242 mod_lastlog: New module to record last time a user authenticated
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    11
	local session = event.session;
4134d0e25242 mod_lastlog: New module to record last time a user authenticated
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    12
	if session.username then
4016
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
    13
		store:set(session.username, "login", {
1047
38781835c911 mod_lastlog: Keep track of last logout time
Kim Alvefur <zash@zash.se>
parents: 1039
diff changeset
    14
			timestamp = time(),
1493
d5e8758d391d mod_lastlog: Fix traceback if no session included with event (eg from mod_register_web) (thanks biszkopcik)
Kim Alvefur <zash@zash.se>
parents: 1343
diff changeset
    15
			ip = log_ip and session and session.ip or nil,
1047
38781835c911 mod_lastlog: Keep track of last logout time
Kim Alvefur <zash@zash.se>
parents: 1039
diff changeset
    16
		});
38781835c911 mod_lastlog: Keep track of last logout time
Kim Alvefur <zash@zash.se>
parents: 1039
diff changeset
    17
	end
38781835c911 mod_lastlog: Keep track of last logout time
Kim Alvefur <zash@zash.se>
parents: 1039
diff changeset
    18
end);
38781835c911 mod_lastlog: Keep track of last logout time
Kim Alvefur <zash@zash.se>
parents: 1039
diff changeset
    19
38781835c911 mod_lastlog: Keep track of last logout time
Kim Alvefur <zash@zash.se>
parents: 1039
diff changeset
    20
module:hook("resource-unbind", function(event)
38781835c911 mod_lastlog: Keep track of last logout time
Kim Alvefur <zash@zash.se>
parents: 1039
diff changeset
    21
	local session = event.session;
38781835c911 mod_lastlog: Keep track of last logout time
Kim Alvefur <zash@zash.se>
parents: 1039
diff changeset
    22
	if session.username then
4016
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
    23
		store:set(session.username, "logout", {
615
4134d0e25242 mod_lastlog: New module to record last time a user authenticated
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    24
			timestamp = time(),
1493
d5e8758d391d mod_lastlog: Fix traceback if no session included with event (eg from mod_register_web) (thanks biszkopcik)
Kim Alvefur <zash@zash.se>
parents: 1343
diff changeset
    25
			ip = log_ip and session and session.ip or nil,
615
4134d0e25242 mod_lastlog: New module to record last time a user authenticated
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    26
		});
4134d0e25242 mod_lastlog: New module to record last time a user authenticated
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    27
	end
4134d0e25242 mod_lastlog: New module to record last time a user authenticated
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    28
end);
1039
3f91f17ddaca mod_lastlog: Add prosodyctl command (prosodyctl mod_lastlog JID) to show last login time and IP of user (if available)
Matthew Wild <mwild1@gmail.com>
parents: 616
diff changeset
    29
1173
8999967fc4fe mod_lastlog: Collect timestamp on registration
Kim Alvefur <zash@zash.se>
parents: 1172
diff changeset
    30
module:hook("user-registered", function(event)
8999967fc4fe mod_lastlog: Collect timestamp on registration
Kim Alvefur <zash@zash.se>
parents: 1172
diff changeset
    31
	local session = event.session;
4106
4e7ff27c212c mod_lastlog2: Fix 'registered' event (Thanks Ge0rG)
Kim Alvefur <zash@zash.se>
parents: 4016
diff changeset
    32
	store:set(event.username, "registered", {
1173
8999967fc4fe mod_lastlog: Collect timestamp on registration
Kim Alvefur <zash@zash.se>
parents: 1172
diff changeset
    33
		timestamp = time(),
1493
d5e8758d391d mod_lastlog: Fix traceback if no session included with event (eg from mod_register_web) (thanks biszkopcik)
Kim Alvefur <zash@zash.se>
parents: 1343
diff changeset
    34
		ip = log_ip and session and session.ip or nil,
1173
8999967fc4fe mod_lastlog: Collect timestamp on registration
Kim Alvefur <zash@zash.se>
parents: 1172
diff changeset
    35
	});
8999967fc4fe mod_lastlog: Collect timestamp on registration
Kim Alvefur <zash@zash.se>
parents: 1172
diff changeset
    36
end);
8999967fc4fe mod_lastlog: Collect timestamp on registration
Kim Alvefur <zash@zash.se>
parents: 1172
diff changeset
    37
1174
bd7901fef71b mod_lastlog: If loaded on a component, store a timestamp of the last message sent, eg to a MUC room
Kim Alvefur <zash@zash.se>
parents: 1173
diff changeset
    38
bd7901fef71b mod_lastlog: If loaded on a component, store a timestamp of the last message sent, eg to a MUC room
Kim Alvefur <zash@zash.se>
parents: 1173
diff changeset
    39
if module:get_host_type() == "component" then
bd7901fef71b mod_lastlog: If loaded on a component, store a timestamp of the last message sent, eg to a MUC room
Kim Alvefur <zash@zash.se>
parents: 1173
diff changeset
    40
	module:hook("message/bare", function(event)
1175
9eac4e2386d2 mod_lastlog: Fix jid.split call
Kim Alvefur <zash@zash.se>
parents: 1174
diff changeset
    41
		local room = jid.split(event.stanza.attr.to);
1174
bd7901fef71b mod_lastlog: If loaded on a component, store a timestamp of the last message sent, eg to a MUC room
Kim Alvefur <zash@zash.se>
parents: 1173
diff changeset
    42
		if room then
4016
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
    43
			store:set(room, module.host, "message", {
1174
bd7901fef71b mod_lastlog: If loaded on a component, store a timestamp of the last message sent, eg to a MUC room
Kim Alvefur <zash@zash.se>
parents: 1173
diff changeset
    44
				timestamp = time(),
bd7901fef71b mod_lastlog: If loaded on a component, store a timestamp of the last message sent, eg to a MUC room
Kim Alvefur <zash@zash.se>
parents: 1173
diff changeset
    45
			});
bd7901fef71b mod_lastlog: If loaded on a component, store a timestamp of the last message sent, eg to a MUC room
Kim Alvefur <zash@zash.se>
parents: 1173
diff changeset
    46
		end
bd7901fef71b mod_lastlog: If loaded on a component, store a timestamp of the last message sent, eg to a MUC room
Kim Alvefur <zash@zash.se>
parents: 1173
diff changeset
    47
	end);
1049
59f031d1cd38 mod_last_offline: Merge into an option of mod_lastlog
Kim Alvefur <zash@zash.se>
parents: 1048
diff changeset
    48
end
59f031d1cd38 mod_last_offline: Merge into an option of mod_lastlog
Kim Alvefur <zash@zash.se>
parents: 1048
diff changeset
    49
5778
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    50
do
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    51
	local user_sessions = prosody.hosts[module.host].sessions;
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    52
	local kv_store = module:open_store();
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    53
	function get_last_active(username) --luacheck: ignore 131/get_last_active
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    54
		if user_sessions[username] then
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    55
			return os.time(); -- Currently connected
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    56
		else
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    57
			local last_activity = kv_store:get(username);
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    58
			if not last_activity then return nil; end
5780
5239ed05bd71 mod_lastlog2: Fix to interpret stored data structure correctly
Matthew Wild <mwild1@gmail.com>
parents: 5778
diff changeset
    59
			local last_login = last_activity.login;
5239ed05bd71 mod_lastlog2: Fix to interpret stored data structure correctly
Matthew Wild <mwild1@gmail.com>
parents: 5778
diff changeset
    60
			local last_logout = last_activity.logout;
5239ed05bd71 mod_lastlog2: Fix to interpret stored data structure correctly
Matthew Wild <mwild1@gmail.com>
parents: 5778
diff changeset
    61
			local latest = math.max(last_login and last_login.timestamp or 0, last_logout and last_logout.timestamp or 0);
5778
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    62
			if latest == 0 then
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    63
				return nil; -- Never logged in
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    64
			end
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    65
			return latest;
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    66
		end
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    67
	end
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    68
end
7b722955c59b mod_lastlog2: Expose API to query the last active time of a user
Matthew Wild <mwild1@gmail.com>
parents: 4107
diff changeset
    69
1039
3f91f17ddaca mod_lastlog: Add prosodyctl command (prosodyctl mod_lastlog JID) to show last login time and IP of user (if available)
Matthew Wild <mwild1@gmail.com>
parents: 616
diff changeset
    70
function module.command(arg)
1103
59657e03c25c mod_lastlog: Make the command show a help message instead of a traceback when no user given
Kim Alvefur <zash@zash.se>
parents: 1049
diff changeset
    71
	if not arg[1] or arg[1] == "--help" then
59657e03c25c mod_lastlog: Make the command show a help message instead of a traceback when no user given
Kim Alvefur <zash@zash.se>
parents: 1049
diff changeset
    72
		require"util.prosodyctl".show_usage([[mod_lastlog <user@host>]], [[Show when user last logged in or out]]);
59657e03c25c mod_lastlog: Make the command show a help message instead of a traceback when no user given
Kim Alvefur <zash@zash.se>
parents: 1049
diff changeset
    73
		return 1;
59657e03c25c mod_lastlog: Make the command show a help message instead of a traceback when no user given
Kim Alvefur <zash@zash.se>
parents: 1049
diff changeset
    74
	end
1049
59f031d1cd38 mod_last_offline: Merge into an option of mod_lastlog
Kim Alvefur <zash@zash.se>
parents: 1048
diff changeset
    75
	local user, host = jid.prepped_split(table.remove(arg, 1));
1048
50bed746aa16 mod_lastlog: Fix command
Kim Alvefur <zash@zash.se>
parents: 1047
diff changeset
    76
	require"core.storagemanager".initialize_host(host);
4016
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
    77
	store = module:context(host):open_store();
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
    78
	local lastlog = store:get(user);
1048
50bed746aa16 mod_lastlog: Fix command
Kim Alvefur <zash@zash.se>
parents: 1047
diff changeset
    79
	if lastlog then
4016
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
    80
		for event, data in pairs(lastlog) do
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
    81
			print(("Last %s: %s"):format(event,
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
    82
				data.timestamp and os.date("%Y-%m-%d %H:%M:%S", data.timestamp) or "<unknown>"));
4107
ecc6ad057383 mod_lastlog2: Fix reporting of IP address (thanks Ge0rG)
Kim Alvefur <zash@zash.se>
parents: 4106
diff changeset
    83
			if data.ip then
ecc6ad057383 mod_lastlog2: Fix reporting of IP address (thanks Ge0rG)
Kim Alvefur <zash@zash.se>
parents: 4106
diff changeset
    84
				print("IP address: "..data.ip);
4016
fd582067c732 mod_lastlog2: Store last timestamp per account event
Kim Alvefur <zash@zash.se>
parents: 1493
diff changeset
    85
			end
1048
50bed746aa16 mod_lastlog: Fix command
Kim Alvefur <zash@zash.se>
parents: 1047
diff changeset
    86
		end
50bed746aa16 mod_lastlog: Fix command
Kim Alvefur <zash@zash.se>
parents: 1047
diff changeset
    87
	else
50bed746aa16 mod_lastlog: Fix command
Kim Alvefur <zash@zash.se>
parents: 1047
diff changeset
    88
		print("No record found");
1172
1e8b793d8ff9 mod_lastlog: Return a non-zero exit code if no lastlog records were found
Kim Alvefur <zash@zash.se>
parents: 1103
diff changeset
    89
		return 1;
1039
3f91f17ddaca mod_lastlog: Add prosodyctl command (prosodyctl mod_lastlog JID) to show last login time and IP of user (if available)
Matthew Wild <mwild1@gmail.com>
parents: 616
diff changeset
    90
	end
3f91f17ddaca mod_lastlog: Add prosodyctl command (prosodyctl mod_lastlog JID) to show last login time and IP of user (if available)
Matthew Wild <mwild1@gmail.com>
parents: 616
diff changeset
    91
	return 0;
3f91f17ddaca mod_lastlog: Add prosodyctl command (prosodyctl mod_lastlog JID) to show last login time and IP of user (if available)
Matthew Wild <mwild1@gmail.com>
parents: 616
diff changeset
    92
end