Software / code / prosody
Comparison
plugins/mod_invites_register.lua @ 12144:3e292e2a1e02
mod_invites_register: Import from prosody-modules@797b51043767
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Wed, 29 Dec 2021 00:12:26 +0100 |
| child | 12284:b4424f131d5c |
comparison
equal
deleted
inserted
replaced
| 12143:51b7ade94d50 | 12144:3e292e2a1e02 |
|---|---|
| 1 local st = require "util.stanza"; | |
| 2 local jid_split = require "util.jid".split; | |
| 3 local jid_bare = require "util.jid".bare; | |
| 4 local rostermanager = require "core.rostermanager"; | |
| 5 | |
| 6 local require_encryption = module:get_option_boolean("c2s_require_encryption", | |
| 7 module:get_option_boolean("require_encryption", false)); | |
| 8 local invite_only = module:get_option_boolean("registration_invite_only", true); | |
| 9 | |
| 10 local invites; | |
| 11 if prosody.shutdown then -- COMPAT hack to detect prosodyctl | |
| 12 invites = module:depends("invites"); | |
| 13 end | |
| 14 | |
| 15 local legacy_invite_stream_feature = st.stanza("register", { xmlns = "urn:xmpp:invite" }):up(); | |
| 16 local invite_stream_feature = st.stanza("register", { xmlns = "urn:xmpp:ibr-token:0" }):up(); | |
| 17 module:hook("stream-features", function(event) | |
| 18 local session, features = event.origin, event.features; | |
| 19 | |
| 20 -- Advertise to unauthorized clients only. | |
| 21 if session.type ~= "c2s_unauthed" or (require_encryption and not session.secure) then | |
| 22 return | |
| 23 end | |
| 24 | |
| 25 features:add_child(legacy_invite_stream_feature); | |
| 26 features:add_child(invite_stream_feature); | |
| 27 end); | |
| 28 | |
| 29 -- XEP-0379: Pre-Authenticated Roster Subscription | |
| 30 module:hook("presence/bare", function (event) | |
| 31 local stanza = event.stanza; | |
| 32 if stanza.attr.type ~= "subscribe" then return end | |
| 33 | |
| 34 local preauth = stanza:get_child("preauth", "urn:xmpp:pars:0"); | |
| 35 if not preauth then return end | |
| 36 local token = preauth.attr.token; | |
| 37 if not token then return end | |
| 38 | |
| 39 local username, host = jid_split(stanza.attr.to); | |
| 40 | |
| 41 local invite, err = invites.get(token, username); | |
| 42 | |
| 43 if not invite then | |
| 44 module:log("debug", "Got invalid token, error: %s", err); | |
| 45 return; | |
| 46 end | |
| 47 | |
| 48 local contact = jid_bare(stanza.attr.from); | |
| 49 | |
| 50 module:log("debug", "Approving inbound subscription to %s from %s", username, contact); | |
| 51 if rostermanager.set_contact_pending_in(username, host, contact, stanza) then | |
| 52 if rostermanager.subscribed(username, host, contact) then | |
| 53 invite:use(); | |
| 54 rostermanager.roster_push(username, host, contact); | |
| 55 | |
| 56 -- Send back a subscription request (goal is mutual subscription) | |
| 57 if not rostermanager.is_user_subscribed(username, host, contact) | |
| 58 and not rostermanager.is_contact_pending_out(username, host, contact) then | |
| 59 module:log("debug", "Sending automatic subscription request to %s from %s", contact, username); | |
| 60 if rostermanager.set_contact_pending_out(username, host, contact) then | |
| 61 rostermanager.roster_push(username, host, contact); | |
| 62 module:send(st.presence({type = "subscribe", from = username.."@"..host, to = contact })); | |
| 63 else | |
| 64 module:log("warn", "Failed to set contact pending out for %s", username); | |
| 65 end | |
| 66 end | |
| 67 end | |
| 68 end | |
| 69 end, 1); | |
| 70 | |
| 71 -- Client is submitting a preauth token to allow registration | |
| 72 module:hook("stanza/iq/urn:xmpp:pars:0:preauth", function(event) | |
| 73 local preauth = event.stanza.tags[1]; | |
| 74 local token = preauth.attr.token; | |
| 75 local validated_invite = invites.get(token); | |
| 76 if not validated_invite then | |
| 77 local reply = st.error_reply(event.stanza, "cancel", "forbidden", "The invite token is invalid or expired"); | |
| 78 event.origin.send(reply); | |
| 79 return true; | |
| 80 end | |
| 81 event.origin.validated_invite = validated_invite; | |
| 82 local reply = st.reply(event.stanza); | |
| 83 event.origin.send(reply); | |
| 84 return true; | |
| 85 end); | |
| 86 | |
| 87 -- Registration attempt - ensure a valid preauth token has been supplied | |
| 88 module:hook("user-registering", function (event) | |
| 89 local validated_invite = event.validated_invite or (event.session and event.session.validated_invite); | |
| 90 if invite_only and not validated_invite then | |
| 91 event.allowed = false; | |
| 92 event.reason = "Registration on this server is through invitation only"; | |
| 93 return; | |
| 94 elseif not validated_invite then | |
| 95 -- This registration is not using an invite, but | |
| 96 -- the server is not in invite-only mode, so nothing | |
| 97 -- for this module to do... | |
| 98 return; | |
| 99 end | |
| 100 if validated_invite and validated_invite.additional_data and validated_invite.additional_data.allow_reset then | |
| 101 event.allow_reset = validated_invite.additional_data.allow_reset; | |
| 102 end | |
| 103 end); | |
| 104 | |
| 105 -- Make a *one-way* subscription. User will see when contact is online, | |
| 106 -- contact will not see when user is online. | |
| 107 function subscribe(host, user_username, contact_username) | |
| 108 local user_jid = user_username.."@"..host; | |
| 109 local contact_jid = contact_username.."@"..host; | |
| 110 -- Update user's roster to say subscription request is pending... | |
| 111 rostermanager.set_contact_pending_out(user_username, host, contact_jid); | |
| 112 -- Update contact's roster to say subscription request is pending... | |
| 113 rostermanager.set_contact_pending_in(contact_username, host, user_jid); | |
| 114 -- Update contact's roster to say subscription request approved... | |
| 115 rostermanager.subscribed(contact_username, host, user_jid); | |
| 116 -- Update user's roster to say subscription request approved... | |
| 117 rostermanager.process_inbound_subscription_approval(user_username, host, contact_jid); | |
| 118 end | |
| 119 | |
| 120 -- Make a mutual subscription between jid1 and jid2. Each JID will see | |
| 121 -- when the other one is online. | |
| 122 function subscribe_both(host, user1, user2) | |
| 123 subscribe(host, user1, user2); | |
| 124 subscribe(host, user2, user1); | |
| 125 end | |
| 126 | |
| 127 -- Registration successful, if there was a preauth token, mark it as used | |
| 128 module:hook("user-registered", function (event) | |
| 129 local validated_invite = event.validated_invite or (event.session and event.session.validated_invite); | |
| 130 if not validated_invite then | |
| 131 return; | |
| 132 end | |
| 133 local inviter_username = validated_invite.inviter; | |
| 134 local contact_username = event.username; | |
| 135 validated_invite:use(); | |
| 136 | |
| 137 if inviter_username then | |
| 138 module:log("debug", "Creating mutual subscription between %s and %s", inviter_username, contact_username); | |
| 139 subscribe_both(module.host, inviter_username, contact_username); | |
| 140 end | |
| 141 | |
| 142 if validated_invite.additional_data then | |
| 143 module:log("debug", "Importing roles from invite"); | |
| 144 local roles = validated_invite.additional_data.roles; | |
| 145 if roles then | |
| 146 module:open_store("roles"):set(contact_username, roles); | |
| 147 end | |
| 148 end | |
| 149 end); | |
| 150 | |
| 151 -- Equivalent of user-registered but for when the account already existed | |
| 152 -- (i.e. password reset) | |
| 153 module:hook("user-password-reset", function (event) | |
| 154 local validated_invite = event.validated_invite or (event.session and event.session.validated_invite); | |
| 155 if not validated_invite then | |
| 156 return; | |
| 157 end | |
| 158 validated_invite:use(); | |
| 159 end); | |
| 160 |