Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dev.gajim.org/gajim/python-nbxmpp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwurstsalat <mailtrash@posteo.de>2021-11-09 01:14:11 +0300
committerwurstsalat <mailtrash@posteo.de>2021-11-10 23:54:31 +0300
commit22aaefb2b36eb46a5306092496c2be680b167f61 (patch)
treebe14dcdee9cb692e6e402eeb837ee0141079a4ed
parentb948ba2efbd51baeeba21cdacd9099b49c539991 (diff)
Add XEP-0425: Message Moderation
-rw-r--r--nbxmpp/dispatcher.py2
-rw-r--r--nbxmpp/modules/muc/moderation.py98
-rw-r--r--nbxmpp/modules/muc/muc.py6
-rw-r--r--nbxmpp/namespaces.py3
-rw-r--r--nbxmpp/structs.py16
-rw-r--r--python-nbxmpp.doap7
6 files changed, 132 insertions, 0 deletions
diff --git a/nbxmpp/dispatcher.py b/nbxmpp/dispatcher.py
index 4b57a7b..b52bbb7 100644
--- a/nbxmpp/dispatcher.py
+++ b/nbxmpp/dispatcher.py
@@ -44,6 +44,7 @@ from nbxmpp.modules.iq import BaseIq
from nbxmpp.modules.nickname import Nickname
from nbxmpp.modules.delay import Delay
from nbxmpp.modules.muc import MUC
+from nbxmpp.modules.muc.moderation import Moderation
from nbxmpp.modules.idle import Idle
from nbxmpp.modules.pgplegacy import PGPLegacy
from nbxmpp.modules.vcard_avatar import VCardAvatar
@@ -156,6 +157,7 @@ class StanzaDispatcher(Observable):
self._modules['HTTPAuth'] = HTTPAuth(self._client)
self._modules['Nickname'] = Nickname(self._client)
self._modules['MUC'] = MUC(self._client)
+ self._modules['Moderation'] = Moderation(self._client)
self._modules['Delay'] = Delay(self._client)
self._modules['Captcha'] = Captcha(self._client)
self._modules['Idle'] = Idle(self._client)
diff --git a/nbxmpp/modules/muc/moderation.py b/nbxmpp/modules/muc/moderation.py
new file mode 100644
index 0000000..bf4772a
--- /dev/null
+++ b/nbxmpp/modules/muc/moderation.py
@@ -0,0 +1,98 @@
+# This file is part of nbxmpp.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 3
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+# XEP-0425: Message Moderation
+
+from typing import Optional
+
+from nbxmpp.modules.base import BaseModule
+from nbxmpp.modules.util import process_response
+
+from nbxmpp import JID
+from nbxmpp.namespaces import Namespace
+from nbxmpp.protocol import Iq
+from nbxmpp.structs import StanzaHandler
+from nbxmpp.structs import MessageProperties
+from nbxmpp.structs import ModerationData
+from nbxmpp.simplexml import Node
+from nbxmpp.task import iq_request_task
+
+
+class Moderation(BaseModule):
+ def __init__(self, client):
+ BaseModule.__init__(self, client)
+
+ self._client = client
+ self.handlers = [
+ StanzaHandler(name='message',
+ callback=self._process_message,
+ typ='groupchat',
+ ns=Namespace.FASTEN,
+ priority=20),
+ ]
+
+ @iq_request_task
+ def send_retract_request(self, muc_jid: JID, stanza_id: str,
+ reason: Optional[str] = None):
+ _task = yield
+
+ response = yield _make_retract_request(muc_jid, stanza_id, reason)
+
+ yield process_response(response)
+
+ @staticmethod
+ def _process_message(_client, stanza: Node,
+ properties: MessageProperties) -> None:
+ if not properties.jid.is_bare:
+ return
+
+ apply_to = stanza.getTag(
+ 'apply-to', namespace=Namespace.FASTEN)
+ if apply_to is None:
+ return
+
+ moderated = apply_to.getTag(
+ 'moderated', namespace=Namespace.MESSAGE_MODERATE)
+ if moderated is None:
+ return
+
+ retract = moderated.getTag(
+ 'retract', namespace=Namespace.MESSAGE_RETRACT)
+ if retract is None:
+ # Tag can be 'retract' or 'retracted', depending on whether the
+ # server applies a tombstone for MAM messages or not.
+ retract = moderated.getTag(
+ 'retracted', namespace=Namespace.MESSAGE_RETRACT)
+ if retract is None:
+ return
+
+ properties.moderation = ModerationData(
+ stanza_id=apply_to.getAttr('id'),
+ moderator_jid=moderated.getAttr('by'),
+ reason=moderated.getTagData('reason'),
+ timestamp=retract.getAttr('stamp'))
+
+
+def _make_retract_request(muc_jid: JID, stanza_id: str,
+ reason: Optional[str]) -> Iq:
+ iq = Iq('set', Namespace.FASTEN, to=muc_jid)
+ query = iq.setQuery(name='apply-to')
+ query.setAttr('id', stanza_id)
+ moderate = query.addChild(name='moderate',
+ namespace=Namespace.MESSAGE_MODERATE)
+ moderate.addChild(name='retract', namespace=Namespace.MESSAGE_RETRACT)
+ if reason is not None:
+ moderate.addChild(name='reason', payload=[reason])
+ return iq
diff --git a/nbxmpp/modules/muc/muc.py b/nbxmpp/modules/muc/muc.py
index c596761..0d94375 100644
--- a/nbxmpp/modules/muc/muc.py
+++ b/nbxmpp/modules/muc/muc.py
@@ -15,6 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program; If not, see <http://www.gnu.org/licenses/>.
+from typing import Optional
from nbxmpp.namespaces import Namespace
from nbxmpp.protocol import ERR_NOT_ACCEPTABLE
@@ -61,6 +62,7 @@ class MUC(BaseModule):
_depends = {
'disco_info': 'Discovery',
'request_vcard': 'VCardTemp',
+ 'send_retract_request': 'Moderation',
}
def __init__(self, client):
@@ -468,6 +470,10 @@ class MUC(BaseModule):
response = yield make_set_role_request(room_jid, nick, role, reason)
yield process_response(response)
+ def retract_message(self, room_jid: JID, stanza_id: str,
+ reason: Optional[str] = None) -> None:
+ self.send_retract_request(room_jid, stanza_id, reason)
+
def set_subject(self, room_jid, subject):
message = Message(room_jid, typ='groupchat', subject=subject)
self._log.info('Set subject for %s', room_jid)
diff --git a/nbxmpp/namespaces.py b/nbxmpp/namespaces.py
index fd8464b..b2c52e9 100644
--- a/nbxmpp/namespaces.py
+++ b/nbxmpp/namespaces.py
@@ -62,6 +62,7 @@ class _Namespaces:
DOMAIN_BASED_NAME: str = 'urn:xmpp:domain-based-name:1'
EME: str = 'urn:xmpp:eme:0'
ENCRYPTED: str = 'jabber:x:encrypted'
+ FASTEN: str = 'urn:xmpp:fasten:0'
FILE_METADATA: str = 'urn:xmpp:file:metadata:0'
FORWARD: str = 'urn:xmpp:forward:0'
FRAMING: str = 'urn:ietf:params:xml:ns:xmpp-framing'
@@ -99,6 +100,8 @@ class _Namespaces:
LOCATION: str = 'http://jabber.org/protocol/geoloc'
MAM_1: str = 'urn:xmpp:mam:1'
MAM_2: str = 'urn:xmpp:mam:2'
+ MESSAGE_MODERATE: str = 'urn:xmpp:message-moderate:0'
+ MESSAGE_RETRACT: str = 'urn:xmpp:message-retract:0'
MOOD: str = 'http://jabber.org/protocol/mood'
MSG_HINTS: str = 'urn:xmpp:hints'
MUCLUMBUS: str = 'https://xmlns.zombofant.net/muclumbus/search/1.0'
diff --git a/nbxmpp/structs.py b/nbxmpp/structs.py
index 80e5831..29b48d9 100644
--- a/nbxmpp/structs.py
+++ b/nbxmpp/structs.py
@@ -284,6 +284,13 @@ class CorrectionData(NamedTuple):
id: str
+class ModerationData(NamedTuple):
+ stanza_id: str
+ moderator_jid: str
+ reason: Optional[str] = None
+ timestamp: Optional[str] = None
+
+
class DiscoItems(NamedTuple):
jid: JID
node: str
@@ -469,6 +476,10 @@ class DiscoInfo(NamedTuple):
return Namespace.HTTPUPLOAD_0 in self.features
@property
+ def has_message_moderation(self) -> bool:
+ return Namespace.MESSAGE_MODERATE in self.features
+
+ @property
def is_muc(self) -> bool:
for identity in self.identities:
if identity.category == 'conference':
@@ -960,6 +971,7 @@ class MessageProperties:
receipt: Optional[ReceiptData] = None
oob: Optional[OOBData] = None
correction: Optional[CorrectionData] = None
+ moderation: Optional[ModerationData] = None
attention: bool = False
forms = None
xhtml: Optional[str] = None
@@ -1070,6 +1082,10 @@ class MessageProperties:
return self.correction is not None
@property
+ def is_moderation(self) -> bool:
+ return self.moderation is not None
+
+ @property
def has_attention(self) -> bool:
return self.attention
diff --git a/python-nbxmpp.doap b/python-nbxmpp.doap
index 0a02787..b6f87b4 100644
--- a/python-nbxmpp.doap
+++ b/python-nbxmpp.doap
@@ -392,5 +392,12 @@
<xmpp:version>0.3.0</xmpp:version>
</xmpp:SupportedXep>
</implements>
+ <implements>
+ <xmpp:SupportedXep>
+ <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0425.html" />
+ <xmpp:status>complete</xmpp:status>
+ <xmpp:version>0.2.1</xmpp:version>
+ </xmpp:SupportedXep>
+ </implements>
</Project>
</rdf:RDF>