Annotate

plugins/mod_tombstones.lua @ 12115:94de6b7596cc

mod_tombstones: Remember deleted accounts #1307 Presence subscriptions are normally revoked on account deletion, which informs the contact. Sometimes this notification gets lost e.g. due to s2s problems. The accounts JID may also be present e.g. in MUC affiliations, chat group member lists, pubsub subscriptions or other systems. These may grant privileges which would fall to someone who creates the same account again, which this module is meant to prevent.
author Kim Alvefur <zash@zash.se>
date Thu, 23 Dec 2021 14:08:20 +0100
child 12117:0c9b64178eda
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
12115
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
1 -- TODO warn when trying to create an user before the tombstone expires
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
2 -- e.g. via telnet or other admin interface
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
3 local datetime = require "util.datetime";
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
4 local errors = require "util.error";
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
5 local jid_split = require"util.jid".split;
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
6 local st = require "util.stanza";
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
7
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
8 -- Using a map store as key-value store so that removal of all user data
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
9 -- does not also remove the tombstone, which would defeat the point
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
10 local graveyard = module:open_store(nil, "map");
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
11
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
12 local ttl = module:get_option_number("user_tombstone_expiry", nil);
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
13 -- Keep tombstones forever by default
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
14 --
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
15 -- Rationale:
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
16 -- There is no way to be completely sure when remote services have
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
17 -- forgotten and revoked all memberships.
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
18
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
19 module:hook_global("user-deleted", function(event)
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
20 if event.host == module.host then
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
21 local ok, err = graveyard:set(nil, event.username, os.time());
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
22 if not ok then module:log("error", "Could store tombstone for %s: %s", event.username, err); end
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
23 end
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
24 end);
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
25
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
26 -- Public API
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
27 function has_tombstone(username)
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
28 local tombstone, err = graveyard:get(nil, username);
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
29
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
30 if err or not tombstone then return tombstone, err; end
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
31
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
32 if ttl and tombstone + ttl < os.time() then
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
33 module:log("debug", "Tombstone for %s created at %s has expired", username, datetime.datetime(tombstone));
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
34 graveyard:set(nil, username, nil);
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
35 return nil;
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
36 end
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
37 return tombstone;
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
38 end
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
39
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
40 module:hook("user-registering", function(event)
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
41 local tombstone, err = has_tombstone(event.username);
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
42
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
43 if err then
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
44 event.allowed, event.error = errors.coerce(false, err);
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
45 return true;
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
46 elseif not tombstone then
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
47 -- Feel free
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
48 return;
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
49 end
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
50
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
51 module:log("debug", "Tombstone for %s created at %s", event.username, datetime.datetime(tombstone));
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
52 event.allowed = false;
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
53 return true;
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
54 end);
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
55
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
56 module:hook("presence/bare", function(event)
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
57 local origin, presence = event.origin, event.stanza;
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
58
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
59 -- We want to undo any left-over presence subscriptions and notify the former
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
60 -- contact that they're gone.
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
61 --
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
62 -- FIXME This leaks that the user once existed. Hard to avoid without keeping
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
63 -- the contact list in some form, which we don't want to do for privacy
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
64 -- reasons. Bloom filter perhaps?
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
65 if has_tombstone(jid_split(presence.attr.to)) then
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
66 if presence.attr.type == "probe" then
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
67 origin.send(st.error_reply(presence, "cancel", "gone", "User deleted"));
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
68 origin.send(st.presence({ type = "unsubscribed"; to = presence.attr.from; from = presence.attr.to }));
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
69 elseif presence.attr.type == nil or presence.attr.type == "unavailable" then
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
70 origin.send(st.error_reply(presence, "cancel", "gone", "User deleted"));
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
71 origin.send(st.presence({ type = "unsubscribe"; to = presence.attr.from; from = presence.attr.to }));
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
72 end
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
73 return true;
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
74 end
94de6b7596cc mod_tombstones: Remember deleted accounts #1307
Kim Alvefur <zash@zash.se>
parents:
diff changeset
75 end, 1);