aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Wild <mwild1@gmail.com>2019-12-19 10:03:16 +0000
committerMatthew Wild <mwild1@gmail.com>2019-12-19 10:03:16 +0000
commit173990157fad6d4507e8ce2dc214e7bf35a17822 (patch)
tree1d7cba4384d9413b605b7e06c729b3fb44dfa1fa
parentad26a3b047ab0ae2efa0d61553e32f77da2ccac4 (diff)
downloadprosody-173990157fad6d4507e8ce2dc214e7bf35a17822.tar.gz
prosody-173990157fad6d4507e8ce2dc214e7bf35a17822.zip
rostermanager, mod_presence: Support for subscription preapproval (fixes #686)
-rw-r--r--core/rostermanager.lua23
-rw-r--r--plugins/mod_presence.lua12
-rw-r--r--spec/scansion/presence_preapproval.scs74
3 files changed, 104 insertions, 5 deletions
diff --git a/core/rostermanager.lua b/core/rostermanager.lua
index d551a1b1..7b104339 100644
--- a/core/rostermanager.lua
+++ b/core/rostermanager.lua
@@ -301,6 +301,11 @@ function is_contact_pending_out(username, host, jid)
local item = roster[jid];
return item and item.ask;
end
+local function is_contact_preapproved(username, host, jid)
+ local roster = load_roster(username, host);
+ local item = roster[jid];
+ return item and (item.approved == "true");
+end
local function set_contact_pending_out(username, host, jid) -- subscribe
local roster = load_roster(username, host);
local item = roster[jid];
@@ -331,9 +336,10 @@ local function unsubscribe(username, host, jid)
return save_roster(username, host, roster, jid);
end
local function subscribed(username, host, jid)
+ local roster = load_roster(username, host);
+ local item = roster[jid];
+
if is_contact_pending_in(username, host, jid) then
- local roster = load_roster(username, host);
- local item = roster[jid];
if not item then -- FIXME should roster item be auto-created?
item = {subscription = "none", groups = {}};
roster[jid] = item;
@@ -345,7 +351,17 @@ local function subscribed(username, host, jid)
end
roster[false].pending[jid] = nil;
return save_roster(username, host, roster, jid);
- end -- TODO else implement optional feature pre-approval (ask = subscribed)
+ elseif not item or item.subscription == "none" or item.subscription == "to" then
+ -- Contact is not subscribed and has not sent a subscription request.
+ -- We store a pre-approval as per RFC6121 3.4
+ if not item then
+ item = {subscription = "none", groups = {}};
+ roster[jid] = item;
+ end
+ item.approved = "true";
+ log("debug", "Storing preapproval for %s", jid);
+ return save_roster(username, host, roster, jid);
+ end
end
local function unsubscribed(username, host, jid)
local roster = load_roster(username, host);
@@ -403,6 +419,7 @@ return {
set_contact_pending_in = set_contact_pending_in;
is_contact_pending_out = is_contact_pending_out;
set_contact_pending_out = set_contact_pending_out;
+ is_contact_preapproved = is_contact_preapproved;
unsubscribe = unsubscribe;
subscribed = subscribed;
unsubscribed = unsubscribed;
diff --git a/plugins/mod_presence.lua b/plugins/mod_presence.lua
index f7f458ca..b874277c 100644
--- a/plugins/mod_presence.lua
+++ b/plugins/mod_presence.lua
@@ -181,8 +181,10 @@ function handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_
if rostermanager.subscribed(node, host, to_bare) then
rostermanager.roster_push(node, host, to_bare);
end
- core_post_stanza(origin, stanza);
- send_presence_of_available_resources(node, host, to_bare, origin);
+ if rostermanager.is_contact_subscribed(node, host, to_bare) then
+ core_post_stanza(origin, stanza);
+ send_presence_of_available_resources(node, host, to_bare, origin);
+ end
if rostermanager.is_user_subscribed(node, host, to_bare) then
core_post_stanza(origin, st.presence({ type = "probe", from = from_bare, to = to_bare }));
end
@@ -229,6 +231,12 @@ function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_b
if 0 == send_presence_of_available_resources(node, host, from_bare, origin) then
core_post_stanza(hosts[host], st.presence({from=to_bare, to=from_bare, type="unavailable"}), true); -- TODO send last activity
end
+ elseif rostermanager.is_contact_preapproved(node, host, from_bare) then
+ if not rostermanager.is_contact_pending_in(node, host, from_bare) then
+ if rostermanager.set_contact_pending_in(node, host, from_bare, stanza) then
+ core_post_stanza(hosts[host], st.presence({from=to_bare, to=from_bare, type="subscribed"}), true);
+ end -- TODO else return error, unable to save
+ end
else
core_post_stanza(hosts[host], st.presence({from=to_bare, to=from_bare, type="unavailable"}), true); -- acknowledging receipt
if not rostermanager.is_contact_pending_in(node, host, from_bare) then
diff --git a/spec/scansion/presence_preapproval.scs b/spec/scansion/presence_preapproval.scs
new file mode 100644
index 00000000..ce6158d2
--- /dev/null
+++ b/spec/scansion/presence_preapproval.scs
@@ -0,0 +1,74 @@
+# server supports contact subscription pre-approval (RFC 6121 3.4)
+
+[Client] Alice
+ jid: preappove-a@localhost
+ password: password
+
+[Client] Bob
+ jid: preapprove-b@localhost
+ password: password
+
+---------
+
+Alice connects
+
+Alice sends:
+ <presence/>
+
+Alice receives:
+ <presence/>
+
+Alice sends:
+ <presence to="${Bob's JID}" type="subscribed"/>
+
+Bob connects
+
+Bob sends:
+ <iq type="get" id="roster1">
+ <query xmlns="jabber:iq:roster"/>
+ </iq>
+
+Bob receives:
+ <iq type="result" id="roster1">
+ <query xmlns="jabber:iq:roster" ver="{scansion:any}">
+ </query>
+ </iq>
+
+Bob sends:
+ <presence/>
+
+Bob receives:
+ <presence from="${Bob's full JID}"/>
+
+Bob sends:
+ <presence to="${Alice's JID}" type="subscribe" />
+
+Bob receives:
+ <iq type='set' id='{scansion:any}'>
+ <query ver='1' xmlns='jabber:iq:roster'>
+ <item jid="${Alice's JID}" subscription='none' ask='subscribe' />
+ </query>
+ </iq>
+
+
+
+Bob receives:
+ <presence from="${Alice's JID}" type="subscribed" />
+
+Bob disconnects
+
+Alice sends:
+ <iq type="get" id="roster1">
+ <query xmlns="jabber:iq:roster"/>
+ </iq>
+
+Alice receives:
+ <iq type="result" id="roster1">
+ <query xmlns="jabber:iq:roster" ver="{scansion:any}">
+ <item jid="${Bob's JID}" subscription="from" />
+ </query>
+ </iq>
+
+Alice disconnects
+
+Bob disconnects