annotate mod_tos/mod_tos.lua @ 5401:c8d04ac200fc

mod_http_oauth2: Reject loopback URIs as client_uri This really should be a proper website with info, https://localhost is not good enough. Ideally we'd validate that it's got proper DNS and is actually reachable, but triggering HTTP or even DNS lookups seems like it would carry abuse potential that would best to avoid.
author Kim Alvefur <zash@zash.se>
date Tue, 02 May 2023 16:20:55 +0200
parents 7f61d89a594d
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
4655
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
1 local array = require"util.array";
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
2 local st = require"util.stanza";
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
3
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
4 local tos_version = assert(module:get_option("tos_version"), "tos_version must be set")
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
5
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
6 local status_storage;
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
7 if prosody.process_type == "prosody" or prosody.shutdown then
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
8 status_storage = module:open_store("tos_status", "keyval")
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
9 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
10
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
11 local documents = array{};
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
12
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
13 local function validate_doc(doc)
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
14 if not doc.title or not doc.sources or #doc.sources < 1 then
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
15 return false, "document needs to have a title and at least one source"
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
16 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
17 for _, source in ipairs(doc.sources) do
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
18 if not source.url or not source.type then
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
19 return false, "document " .. doc.title .. " has a source without url or type"
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
20 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
21 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
22 return true, doc
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
23 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
24
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
25 for _, doc in ipairs(assert(module:get_option("tos_documents"), "tos_documents option is required")) do
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
26 local ok, doc_or_err = validate_doc(doc)
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
27 if not ok then
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
28 error("invalid TOS document: "..doc_or_err)
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
29 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
30 documents:push(doc);
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
31 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
32
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
33 local function send_tos_push(session)
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
34 local to = session.username .. "@" .. session.host .. "/" .. session.resource;
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
35 local push = st.message({
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
36 type = "headline",
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
37 to = to,
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
38 }, "In order to continue to use the service, you have to accept the current version of the Terms of Service.");
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
39 local tos = push:tag("tos-push", { xmlns = "urn:xmpp:tos:0" }):tag("tos", { version = tos_version });
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
40 for _, doc in ipairs(documents) do
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
41 local doc_tag = tos:tag("document"):text_tag("title", doc.title);
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
42 for _, source in ipairs(doc.sources) do
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
43 doc_tag:tag("source", { url = source.url, type = source.type }):up();
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
44 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
45 doc_tag:up();
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
46 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
47 tos:up():up();
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
48 module:send(push);
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
49 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
50
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
51 local function check_tos(event)
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
52 local user = event.origin.username
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
53 assert(user)
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
54 local tos_status = status_storage:get(user)
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
55 if tos_status and tos_status.version and tos_status.version == tos_version then
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
56 module:log("debug", "user %s has signed the current tos", user);
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
57 return
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
58 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
59 module:log("debug", "user %s has not signed the current tos, sending tos push", user);
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
60 send_tos_push(event.origin)
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
61 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
62
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
63 local function handle_accept_tos_iq(event)
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
64 local user = event.origin.username;
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
65 assert(user);
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
66 local accept = event.stanza.tags[1];
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
67 local version = accept.attr["version"];
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
68 module:log("debug", "user %s has accepted ToS version %s", user, version);
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
69 if version ~= tos_version then
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
70 local reply = st.error_reply(event.stanza, "modify", "not-allowed", "Only the most recent version of the ToS can be accepted");
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
71 module:log("debug", "%s is not the most recent version (%s), rejecting", version, tos_version);
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
72 event.origin.send(reply);
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
73 return true;
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
74 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
75
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
76 status_storage:set(user, { version = tos_version });
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
77 local reply = st.reply(event.stanza);
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
78 event.origin.send(reply);
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
79 return true;
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
80 end
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
81
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
82 module:hook("presence/initial", check_tos, -100);
7f61d89a594d mod_tos: Initial draft
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
83 module:hook("iq-set/bare/urn:xmpp:tos:0:accept", handle_accept_tos_iq);