branch: elpa/jabber
commit 4e96ed6f0c2068062be528defbe0dac9e01ea05d
Author: Thanos Apollo <[email protected]>
Commit: Thanos Apollo <[email protected]>

    pep: Implement XEP-0163 Personal Eventing Protocol
    
    Advertise +notify disco features for OMEMO device list and OpenPGP
    public keys so the server auto-delivers PEP events mid-session.
    
    Add jabber-openpgp--handle-keys-event to fetch updated keys when a
    contact publishes new OpenPGP key metadata via PEP.
    
    Validate that PEP events come from bare JIDs per XEP-0163 s4.3 in
    jabber-pubsub--process-event, rejecting full JIDs as malformed.
---
 doap.xml               |  8 ++++++++
 lisp/jabber-omemo.el   |  1 +
 lisp/jabber-openpgp.el | 40 +++++++++++++++++++++++++++++++++++++++-
 lisp/jabber-pubsub.el  | 28 +++++++++++++++-------------
 4 files changed, 63 insertions(+), 14 deletions(-)

diff --git a/doap.xml b/doap.xml
index 7580175340..58a4b4cbbb 100644
--- a/doap.xml
+++ b/doap.xml
@@ -326,6 +326,14 @@
        <xmpp:note>The pixel size limits on avatars are not 
enforced.</xmpp:note>
       </xmpp:SupportedXep>
     </implements>
+    <implements>
+      <xmpp:SupportedXep>
+        <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0163.html"/>
+        <xmpp:status>complete</xmpp:status>
+        <xmpp:version>1.2.2</xmpp:version>
+        <xmpp:since>0.10.1-alpha</xmpp:since>
+      </xmpp:SupportedXep>
+    </implements>
     <implements>
       <xmpp:SupportedXep>
         <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0184.html"/>
diff --git a/lisp/jabber-omemo.el b/lisp/jabber-omemo.el
index eb13769988..424e83742d 100644
--- a/lisp/jabber-omemo.el
+++ b/lisp/jabber-omemo.el
@@ -1310,6 +1310,7 @@ Returns non-nil if handled, nil to fall through to 
plaintext."
 ;;; Disco and PubSub registration
 
 (jabber-disco-advertise-feature jabber-omemo-xmlns)
+(jabber-disco-advertise-feature (concat jabber-omemo-devicelist-node 
"+notify"))
 
 (with-eval-after-load "jabber-pubsub"
   (push (cons jabber-omemo-devicelist-node
diff --git a/lisp/jabber-openpgp.el b/lisp/jabber-openpgp.el
index 8840361e8c..3740107664 100644
--- a/lisp/jabber-openpgp.el
+++ b/lisp/jabber-openpgp.el
@@ -443,9 +443,47 @@ OPENPGP-EL is the <openpgp> child element."
     (jabber-chat--set-body xml-data
                           (or body-text "[OpenPGP: empty payload]"))))
 
-;;; Disco and hooks
+;;; Disco, PubSub registration, and hooks
 
 (jabber-disco-advertise-feature jabber-openpgp-xmlns)
+(jabber-disco-advertise-feature (concat jabber-openpgp-pubkeys-node "+notify"))
+
+(defun jabber-openpgp--handle-keys-event (jc from _node items)
+  "Handle PubSub event for OpenPGP public key updates.
+JC is the connection, FROM is the sender JID, ITEMS is the list
+of child elements from the event.  Fetches updated key into the
+local GPG keyring."
+  (let* ((item-el (car items))
+         (keys-list (and (listp item-el)
+                         (car (jabber-xml-get-children
+                               item-el 'public-keys-list))))
+         (meta (and keys-list
+                    (car (jabber-xml-get-children
+                          keys-list 'pubkey-metadata))))
+         (fingerprint (and meta
+                           (jabber-xml-get-attribute meta 'v4-fingerprint)))
+         (jid (jabber-jid-user from)))
+    (if (null fingerprint)
+        (message "OpenPGP: key update from %s but no fingerprint in metadata" 
jid)
+      (message "OpenPGP: %s updated key %s, fetching..." jid fingerprint)
+      (let ((node (concat jabber-openpgp-pubkeys-node ":" fingerprint)))
+        (jabber-pubsub-request
+         jc jid node
+         (lambda (_jc xml-data _closure)
+           (jabber-openpgp--handle-key-response
+            xml-data fingerprint
+            (lambda (key)
+              (if key
+                  (message "OpenPGP: imported updated key for %s" jid)
+                (message "OpenPGP: failed to import key for %s" jid)))))
+         (lambda (_jc _xml-data _closure)
+           (message "OpenPGP: failed to fetch key %s for %s"
+                    fingerprint jid)))))))
+
+(with-eval-after-load "jabber-pubsub"
+  (push (cons jabber-openpgp-pubkeys-node
+              #'jabber-openpgp--handle-keys-event)
+        jabber-pubsub-node-handlers))
 
 (jabber-chat-register-decrypt-handler
  'openpgp
diff --git a/lisp/jabber-pubsub.el b/lisp/jabber-pubsub.el
index 5ffd6a2cfd..9d019e0e4d 100644
--- a/lisp/jabber-pubsub.el
+++ b/lisp/jabber-pubsub.el
@@ -138,19 +138,21 @@ where ITEMS is the list of child elements (item or 
retract).")
 
 (defun jabber-pubsub--process-event (jc xml-data)
   "Process incoming PubSub event notifications.
-JC is the Jabber connection.  XML-DATA is the message stanza."
-  (let ((event (jabber-xml-child-with-xmlns xml-data 
jabber-pubsub-event-xmlns)))
-    (when event
-      (let* ((items-or-purge (or (car (jabber-xml-get-children event 'items))
-                                 (car (jabber-xml-get-children event 'purge))))
-             (node (and items-or-purge
-                        (jabber-xml-get-attribute items-or-purge 'node)))
-             (handler (and node (cdr (assoc node 
jabber-pubsub-node-handlers)))))
-        (when handler
-          (funcall handler jc
-                   (jabber-xml-get-attribute xml-data 'from)
-                   node
-                   (jabber-xml-node-children items-or-purge)))))))
+JC is the Jabber connection.  XML-DATA is the message stanza.
+Per XEP-0163 s4.3, PEP events MUST come from bare JIDs."
+  (let* ((event (jabber-xml-child-with-xmlns xml-data 
jabber-pubsub-event-xmlns))
+         (from (and event (jabber-xml-get-attribute xml-data 'from))))
+    (when (and event from)
+      (if (jabber-jid-resource from)
+          (message "PubSub: ignoring event from full JID %s" from)
+        (let* ((items-or-purge (or (car (jabber-xml-get-children event 'items))
+                                   (car (jabber-xml-get-children event 
'purge))))
+               (node (and items-or-purge
+                          (jabber-xml-get-attribute items-or-purge 'node)))
+               (handler (and node (cdr (assoc node 
jabber-pubsub-node-handlers)))))
+          (when handler
+            (funcall handler jc from node
+                     (jabber-xml-node-children items-or-purge))))))))
 
 (with-eval-after-load "jabber-core"
   (jabber-chain-add 'jabber-message-chain #'jabber-pubsub--process-event))

Reply via email to