Philipp Hörist pushed to branch master at gajim / python-nbxmpp


Commits:
f4098bee by Philipp Hörist at 2026-08-26T18:41:04+02:00
imprv: VCardAvatars: Validate and normalize sha1

- - - - -


2 changed files:

- nbxmpp/modules/vcard_avatar.py
- nbxmpp/util.py


Changes:

=====================================
nbxmpp/modules/vcard_avatar.py
=====================================
@@ -15,6 +15,7 @@ from nbxmpp.namespaces import Namespace
 from nbxmpp.protocol import Presence
 from nbxmpp.structs import PresenceProperties
 from nbxmpp.structs import StanzaHandler
+from nbxmpp.util import normalize_sha1
 
 if TYPE_CHECKING:
     from nbxmpp.client import Client
@@ -47,15 +48,27 @@ class VCardAvatar(BaseModule):
         avatar_sha = update.getTagData("photo")
         if avatar_sha is None:
             properties.avatar_state = AvatarState.NOT_READY
-            self._log.info("%s is not ready to promote an avatar", 
stanza.getFrom())
+            self._log.info("%s is not ready to promote an avatar", 
properties.jid)
             # Empty update element, ignore
             return
 
         if avatar_sha == "":
             properties.avatar_state = AvatarState.EMPTY
-            self._log.info("%s empty avatar advertised", stanza.getFrom())
+            self._log.info("%s empty avatar advertised", properties.jid)
+            return
+
+        # XEP-0153 hashes are hex SHA-1 of the image bytes. Implementations 
must
+        # accept mixed case and should emit lowercase.
+        normalized_sha = normalize_sha1(avatar_sha)
+        if normalized_sha is None:
+            properties.avatar_state = AvatarState.IGNORE
+            self._log.warning(
+                "%s advertised invalid avatar hash: %r",
+                properties.jid,
+                avatar_sha,
+            )
             return
 
         properties.avatar_sha = avatar_sha
         properties.avatar_state = AvatarState.ADVERTISED
-        self._log.info("%s advertises %s", stanza.getFrom(), avatar_sha)
+        self._log.info("%s advertises %s", properties.jid, avatar_sha)


=====================================
nbxmpp/util.py
=====================================
@@ -53,6 +53,8 @@ if TYPE_CHECKING:
 
 log = logging.getLogger("nbxmpp.util")
 
+SHA1_RX = re.compile(r"[a-f0-9]{40}")
+
 
 def b64decode(data: str | bytes) -> bytes:
     if not data:
@@ -475,3 +477,11 @@ def parse_websocket_uri(data: str) -> str:
                 raise ValueError("No href attr found")
             return href
     raise ValueError("no websocket uri found")
+
+
+def normalize_sha1(value: str) -> str | None:
+    """Return a canonical lowercase SHA-1 hex digest, or None if invalid."""
+    value = value.lower()
+    if SHA1_RX.fullmatch(value) is None:
+        return None
+    return value



View it on GitLab: 
https://dev.gajim.org/gajim/python-nbxmpp/-/commit/f4098beeddbc1dbd29320ab40513f0adcb57eb9f

-- 
View it on GitLab: 
https://dev.gajim.org/gajim/python-nbxmpp/-/commit/f4098beeddbc1dbd29320ab40513f0adcb57eb9f
You're receiving this email because of your account on dev.gajim.org.


_______________________________________________
Commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to