summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--slixmpp/plugins/xep_0421/__init__.py13
-rw-r--r--slixmpp/plugins/xep_0421/occupant_id.py31
-rw-r--r--slixmpp/plugins/xep_0421/stanza.py40
-rw-r--r--tests/test_stanza_xep_0421.py29
4 files changed, 113 insertions, 0 deletions
diff --git a/slixmpp/plugins/xep_0421/__init__.py b/slixmpp/plugins/xep_0421/__init__.py
new file mode 100644
index 00000000..4595ffad
--- /dev/null
+++ b/slixmpp/plugins/xep_0421/__init__.py
@@ -0,0 +1,13 @@
+"""
+ Slixmpp: The Slick XMPP Library
+ Copyright (C) 2020 "Maxime “pep” Buquet <pep@bouah.net>"
+ This file is part of Slixmpp.
+
+ See the file LICENSE for copying permission.
+"""
+
+from slixmpp.plugins.base import register_plugin
+from slixmpp.plugins.xep_0421.stanza import OccupantId
+from slixmpp.plugins.xep_0421.occupant_id import XEP_0421
+
+register_plugin(XEP_0421)
diff --git a/slixmpp/plugins/xep_0421/occupant_id.py b/slixmpp/plugins/xep_0421/occupant_id.py
new file mode 100644
index 00000000..116bf2d9
--- /dev/null
+++ b/slixmpp/plugins/xep_0421/occupant_id.py
@@ -0,0 +1,31 @@
+"""
+ Slixmpp: The Slick XMPP Library
+ Copyright (C) 2020 "Maxime “pep” Buquet <pep@bouah.net>"
+ This file is part of Slixmpp.
+
+ See the file LICENSE for copying permission.
+"""
+
+from slixmpp import JID, Message
+from slixmpp.plugins import BasePlugin
+from slixmpp.xmlstream import register_stanza_plugin
+from slixmpp.plugins.xep_0421 import stanza
+from slixmpp.plugins.xep_0421.stanza import OccupantId
+
+
+class XEP_0421(BasePlugin):
+ '''XEP-0421: Anonymous unique occupant identifiers for MUCs'''
+
+ name = 'xep_0421'
+ description = 'Anonymous unique occupant identifiers for MUCs'
+ dependencies = {'xep_0030', 'xep_0045'}
+ stanza = stanza
+ namespace = stanza.NS
+
+ def plugin_init(self) -> None:
+ # XXX: This should be MucMessage. Someday..
+ register_stanza_plugin(Message, OccupantId)
+
+ async def has_feature(self, jid: JID) -> bool:
+ info = await self.xmpp['xep_0030'].get_info(jid)
+ return self.namespace in info.get_features()
diff --git a/slixmpp/plugins/xep_0421/stanza.py b/slixmpp/plugins/xep_0421/stanza.py
new file mode 100644
index 00000000..0cb93959
--- /dev/null
+++ b/slixmpp/plugins/xep_0421/stanza.py
@@ -0,0 +1,40 @@
+"""
+ Slixmpp: The Slick XMPP Library
+ Copyright (C) 2020 "Maxime “pep” Buquet <pep@bouah.net>"
+ This file is part of Slixmpp.
+
+ See the file LICENSE for copying permission.
+"""
+
+from slixmpp.xmlstream import ElementBase
+
+
+NS = 'urn:xmpp:occupant-id:0'
+
+
+class OccupantId(ElementBase):
+ '''
+ An Occupant-id tag.
+
+ An <occupant-id/> tag is set by the MUC.
+
+ This is useful in semi-anon MUCs (and MUC-PMs) as a stable identifier to
+ prevent the usual races with nicknames.
+
+ Without occupant-id, getting the following messages from MUC history would
+ prevent a client from asserting senders are the same entity:
+
+ <message type='groupchat' from='foo@muc/nick1' id='message1'>
+ <body>Some message</body>
+ <occupant-id xmlns='urn:xmpp:occupant-id:0' id='unique-opaque-id1'/>
+ </message>
+ <message type='groupchat' from='foo@muc/nick2' id='message2'>
+ <body>Some correction</body>
+ <occupant-id xmlns='urn:xmpp:occupant-id:0' id='unique-opaque-id1'/>
+ <replace xmlns='urn:xmpp:message-correct:0' id='message1'/>
+ </message>
+ '''
+
+ name = 'occupant-id'
+ namespace = NS
+ interface = {'id'}
diff --git a/tests/test_stanza_xep_0421.py b/tests/test_stanza_xep_0421.py
new file mode 100644
index 00000000..dbd7a592
--- /dev/null
+++ b/tests/test_stanza_xep_0421.py
@@ -0,0 +1,29 @@
+import unittest
+from slixmpp import JID, Message
+from slixmpp.test import SlixTest
+import slixmpp.plugins.xep_0421 as xep_0421
+from slixmpp.xmlstream import register_stanza_plugin
+
+
+class TestOccupantId(SlixTest):
+
+ def setUp(self):
+ register_stanza_plugin(Message, xep_0421.stanza.OccupantId)
+
+ def testReadOccupantId(self):
+ result = """
+ <message type='groupchat' from='foo@muc/nick1'>
+ <body>Some message</body>
+ <occupant-id xmlns='urn:xmpp:occupant-id:0' id='unique-id1'/>
+ </message>
+ """
+
+ msg = self.Message()
+ msg['type'] = 'groupchat'
+ msg['from'] = JID('foo@muc/nick1')
+ msg['body'] = 'Some message'
+ msg['occupant-id']['id'] = 'unique-id1'
+
+ self.check(msg, result)
+
+suite = unittest.TestLoader().loadTestsFromTestCase(TestOccupantId)