aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/doap.xml8
-rw-r--r--plugins/mod_csi_simple.lua3
-rw-r--r--plugins/mod_lastactivity.lua2
-rw-r--r--plugins/mod_mam/mod_mam.lua73
-rw-r--r--plugins/mod_uptime.lua2
-rw-r--r--spec/scansion/lastactivity.scs45
-rw-r--r--spec/scansion/prosody.cfg.lua14
-rw-r--r--spec/scansion/uptime.scs21
-rw-r--r--spec/scansion/version.scs27
-rw-r--r--spec/util_hashes_spec.lua28
-rw-r--r--util-src/hashes.c2
11 files changed, 203 insertions, 22 deletions
diff --git a/doc/doap.xml b/doc/doap.xml
index c23334ae..540cbe51 100644
--- a/doc/doap.xml
+++ b/doc/doap.xml
@@ -431,6 +431,14 @@
</implements>
<implements>
<xmpp:SupportedXep>
+ <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0249.html"/>
+ <xmpp:version>1.2</xmpp:version>
+ <xmpp:since>0.12</xmpp:since>
+ <xmpp:note>mod_csi_simple</xmpp:note>
+ </xmpp:SupportedXep>
+ </implements>
+ <implements>
+ <xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0280.html"/>
<xmpp:version>0.12.1</xmpp:version>
<xmpp:status>complete</xmpp:status>
diff --git a/plugins/mod_csi_simple.lua b/plugins/mod_csi_simple.lua
index e439bf38..cc15f033 100644
--- a/plugins/mod_csi_simple.lua
+++ b/plugins/mod_csi_simple.lua
@@ -48,6 +48,9 @@ module:hook("csi-is-stanza-important", function (event)
if stanza:get_child("encryption", "urn:xmpp:eme:0") then
return true;
end
+ if stanza:get_child("x", "jabber:x:conference") or stanza:find("{http://jabber.org/protocol/muc#user}x/invite") then
+ return true;
+ end
for important in important_payloads do
if stanza:find(important) then
return true;
diff --git a/plugins/mod_lastactivity.lua b/plugins/mod_lastactivity.lua
index 575e66be..91d11bd2 100644
--- a/plugins/mod_lastactivity.lua
+++ b/plugins/mod_lastactivity.lua
@@ -30,7 +30,7 @@ module:hook("iq-get/bare/jabber:iq:last:query", function(event)
if not stanza.attr.to or is_contact_subscribed(username, module.host, jid_bare(stanza.attr.from)) then
local seconds, text = "0", "";
if map[username] then
- seconds = tostring(os.difftime(os.time(), map[username].t));
+ seconds = string.format("%d", os.difftime(os.time(), map[username].t));
text = map[username].s;
end
origin.send(st.reply(stanza):tag('query', {xmlns='jabber:iq:last', seconds=seconds}):text(text));
diff --git a/plugins/mod_mam/mod_mam.lua b/plugins/mod_mam/mod_mam.lua
index 8229eb4e..d61d4883 100644
--- a/plugins/mod_mam/mod_mam.lua
+++ b/plugins/mod_mam/mod_mam.lua
@@ -263,11 +263,65 @@ local function strip_stanza_id(stanza, user)
return stanza;
end
+local function should_store(stanza) --> boolean, reason: string
+ local st_type = stanza.attr.type or "normal";
+ -- FIXME pass direction of stanza and use that along with bare/full JID addressing
+ -- for more accurate MUC / type=groupchat check
+
+ if st_type == "headline" then
+ -- Headline messages are ephemeral by definition
+ return false, "headline";
+ end
+ if st_type == "error" then
+ return true, "bounce";
+ end
+ if st_type == "groupchat" then
+ -- MUC messages always go to the full JID, usually archived by the MUC
+ return false, "groupchat";
+ end
+ if stanza:get_child("no-store", "urn:xmpp:hints")
+ or stanza:get_child("no-permanent-store", "urn:xmpp:hints") then
+ -- XXX Experimental XEP
+ return false, "hint";
+ end
+ if stanza:get_child("store", "urn:xmpp:hints") then
+ return true, "hint";
+ end
+ if stanza:get_child("body") then
+ return true, "body";
+ end
+ if stanza:get_child("subject") then
+ -- XXX Who would send a message with a subject but without a body?
+ return true, "subject";
+ end
+ if stanza:get_child("encryption", "urn:xmpp:eme:0") then
+ -- Since we can't know what an encrypted message contains, we assume it's important
+ -- XXX Experimental XEP
+ return true, "encrypted";
+ end
+ if stanza:get_child(nil, "urn:xmpp:receipts") then
+ -- If it's important enough to ask for a receipt then it's important enough to archive
+ -- and the same applies to the receipt
+ return true, "receipt";
+ end
+ if stanza:get_child(nil, "urn:xmpp:chat-markers:0") then
+ -- XXX Experimental XEP
+ return true, "marker";
+ end
+ if stanza:get_child("x", "jabber:x:conference")
+ or stanza:find("{http://jabber.org/protocol/muc#user}x/invite") then
+ return true, "invite";
+ end
+
+ -- The IM-NG thing to do here would be to return `not st_to_full`
+ -- One day ...
+ return false, "default";
+end
+
-- Handle messages
local function message_handler(event, c2s)
local origin, stanza = event.origin, event.stanza;
local log = c2s and origin.log or module._log;
- local orig_type = stanza.attr.type or "normal";
local orig_from = stanza.attr.from;
local orig_to = stanza.attr.to or orig_from;
-- Stanza without 'to' are treated as if it was to their own bare jid
@@ -280,21 +334,12 @@ local function message_handler(event, c2s)
-- Filter out <stanza-id> that claim to be from us
event.stanza = strip_stanza_id(stanza, store_user);
- -- We store chat messages or normal messages that have a body
- if not(orig_type == "chat" or (orig_type == "normal" and stanza:get_child("body")) ) then
- log("debug", "Not archiving stanza: %s (type)", stanza:top_tag());
+ local should, why = should_store(stanza);
+ if not should then
+ log("debug", "Not archiving stanza: %s (%s)", stanza:top_tag(), why);
return;
end
- -- or if hints suggest we shouldn't
- if not stanza:get_child("store", "urn:xmpp:hints") then -- No hint telling us we should store
- if stanza:get_child("no-permanent-store", "urn:xmpp:hints")
- or stanza:get_child("no-store", "urn:xmpp:hints") then -- Hint telling us we should NOT store
- log("debug", "Not archiving stanza: %s (hint)", stanza:top_tag());
- return;
- end
- end
-
local clone_for_storage;
if not strip_tags:empty() then
clone_for_storage = st.clone(stanza);
@@ -315,7 +360,7 @@ local function message_handler(event, c2s)
-- Check with the users preferences
if shall_store(store_user, with) then
- log("debug", "Archiving stanza: %s", stanza:top_tag());
+ log("debug", "Archiving stanza: %s (%s)", stanza:top_tag(), why);
-- And stash it
local time = time_now();
diff --git a/plugins/mod_uptime.lua b/plugins/mod_uptime.lua
index 035f7e9b..8a01fb17 100644
--- a/plugins/mod_uptime.lua
+++ b/plugins/mod_uptime.lua
@@ -16,7 +16,7 @@ module:add_feature("jabber:iq:last");
module:hook("iq-get/host/jabber:iq:last:query", function(event)
local origin, stanza = event.origin, event.stanza;
- origin.send(st.reply(stanza):tag("query", {xmlns = "jabber:iq:last", seconds = tostring(os.difftime(os.time(), start_time))}));
+ origin.send(st.reply(stanza):tag("query", {xmlns = "jabber:iq:last", seconds = tostring(("%d"):format(os.difftime(os.time(), start_time)))}));
return true;
end);
diff --git a/spec/scansion/lastactivity.scs b/spec/scansion/lastactivity.scs
new file mode 100644
index 00000000..44f4e516
--- /dev/null
+++ b/spec/scansion/lastactivity.scs
@@ -0,0 +1,45 @@
+# XEP-0012: Last Activity / mod_lastactivity
+
+[Client] Romeo
+ jid: romeo@localhost
+ password: password
+
+-----
+
+Romeo connects
+
+Romeo sends:
+ <presence>
+ <status>Hello</status>
+ </presence>
+
+Romeo receives:
+ <presence from="${Romeo's full JID}">
+ <status>Hello</status>
+ </presence>
+
+Romeo sends:
+ <presence type="unavailable">
+ <status>Goodbye</status>
+ </presence>
+
+Romeo receives:
+ <presence from="${Romeo's full JID}" type="unavailable">
+ <status>Goodbye</status>
+ </presence>
+
+# mod_lastlog saves time + status message from the last unavailable presence
+
+Romeo sends:
+ <iq id='a' type='get'>
+ <query xmlns='jabber:iq:last'/>
+ </iq>
+
+Romeo receives:
+ <iq type='result' id='a'>
+ <query xmlns='jabber:iq:last' seconds='0'>Goodbye</query>
+ </iq>
+
+Romeo disconnects
+
+# recording ended on 2020-04-20T14:39:47Z
diff --git a/spec/scansion/prosody.cfg.lua b/spec/scansion/prosody.cfg.lua
index 6a72584d..b7d6ccd5 100644
--- a/spec/scansion/prosody.cfg.lua
+++ b/spec/scansion/prosody.cfg.lua
@@ -1,5 +1,16 @@
--luacheck: ignore
+-- Mock time functions to simplify tests
+function _G.os.time()
+ return 1219439344;
+end
+package.preload["util.time"] = function ()
+ return {
+ now = function () return 1219439344.1; end;
+ monotonic = function () return 0.1; end;
+ }
+end
+
admins = { "admin@localhost" }
use_libevent = true
@@ -48,6 +59,7 @@ modules_enabled = {
--"motd"; -- Send a message to users when they log in
--"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
--"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use
+ "lastactivity";
-- Useful for testing
--"scansion_record"; -- Records things that happen in scansion test case format
@@ -84,6 +96,8 @@ pidfile = "prosody.pid"
VirtualHost "localhost"
+hide_os_type = true -- absense tested for in version.scs
+
Component "conference.localhost" "muc"
storage = "memory"
diff --git a/spec/scansion/uptime.scs b/spec/scansion/uptime.scs
new file mode 100644
index 00000000..188b9eb5
--- /dev/null
+++ b/spec/scansion/uptime.scs
@@ -0,0 +1,21 @@
+# XEP-0012: Last Activity / mod_uptime
+
+[Client] Romeo
+ jid: romeo@localhost
+ password: password
+
+-----
+
+Romeo connects
+
+Romeo sends:
+ <iq id='a' type='get' to='localhost'>
+ <query xmlns='jabber:iq:last'/>
+ </iq>
+
+Romeo receives:
+ <iq type='result' id='a' from='localhost'>
+ <query xmlns='jabber:iq:last' seconds='0'/>
+ </iq>
+
+Romeo disconnects
diff --git a/spec/scansion/version.scs b/spec/scansion/version.scs
new file mode 100644
index 00000000..6c841dd9
--- /dev/null
+++ b/spec/scansion/version.scs
@@ -0,0 +1,27 @@
+# XEP-0092: Software Version / mod_version
+
+[Client] Romeo
+ password: password
+ jid: romeo@localhost/dfaZpuxV
+
+-----
+
+Romeo connects
+
+Romeo sends:
+ <iq id='lx2' to='localhost' type='get'>
+ <query xmlns='jabber:iq:version'/>
+ </iq>
+
+# Version string would vary so we can't do an exact match atm
+# Inclusion of <os/> is disabled in the config, it should be absent
+Romeo receives:
+ <iq id='lx2' from='localhost' type='result'>
+ <query xmlns='jabber:iq:version' scansion:strict='true'>
+ <name>Prosody</name>
+ <version scansion:strict='false'/>
+ </query>
+ </iq>
+
+
+Romeo disconnects
diff --git a/spec/util_hashes_spec.lua b/spec/util_hashes_spec.lua
index 1e6187bb..3639dd4e 100644
--- a/spec/util_hashes_spec.lua
+++ b/spec/util_hashes_spec.lua
@@ -4,34 +4,52 @@ local hex = require "util.hex";
-- Also see spec for util.hmac where HMAC test cases reside
-describe("PBKDF2-SHA1", function ()
+describe("PBKDF2-HMAC-SHA1", function ()
it("test vector 1", function ()
local P = "password"
local S = "salt"
local c = 1
local DK = "0c60c80f961f0e71f3a9b524af6012062fe037a6";
- assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c)));
+ assert.equal(DK, hex.to(hashes.pbkdf2_hmac_sha1(P, S, c)));
end);
it("test vector 2", function ()
local P = "password"
local S = "salt"
local c = 2
local DK = "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957";
- assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c)));
+ assert.equal(DK, hex.to(hashes.pbkdf2_hmac_sha1(P, S, c)));
end);
it("test vector 3", function ()
local P = "password"
local S = "salt"
local c = 4096
local DK = "4b007901b765489abead49d926f721d065a429c1";
- assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c)));
+ assert.equal(DK, hex.to(hashes.pbkdf2_hmac_sha1(P, S, c)));
end);
it("test vector 4 #SLOW", function ()
local P = "password"
local S = "salt"
local c = 16777216
local DK = "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984";
- assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c)));
+ assert.equal(DK, hex.to(hashes.pbkdf2_hmac_sha1(P, S, c)));
end);
end);
+describe("PBKDF2-HMAC-SHA256", function ()
+ it("test vector 1", function ()
+ local P = "password";
+ local S = "salt";
+ local c = 1
+ local DK = "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b";
+ assert.equal(DK, hex.to(hashes.pbkdf2_hmac_sha256(P, S, c)));
+ end);
+ it("test vector 2", function ()
+ local P = "password";
+ local S = "salt";
+ local c = 2
+ local DK = "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43";
+ assert.equal(DK, hex.to(hashes.pbkdf2_hmac_sha256(P, S, c)));
+ end);
+end);
+
+
diff --git a/util-src/hashes.c b/util-src/hashes.c
index 51c7611c..84a604ef 100644
--- a/util-src/hashes.c
+++ b/util-src/hashes.c
@@ -129,7 +129,7 @@ static int Lpbkdf2_sha256(lua_State *L) {
return luaL_error(L, "PKCS5_PBKDF2_HMAC() failed");
}
- lua_pushlstring(L, (char *)out, SHA_DIGEST_LENGTH);
+ lua_pushlstring(L, (char *)out, SHA256_DIGEST_LENGTH);
return 1;
}