§
    øžyj!!  ã                  óÆ   — d Z ddlmZ ddlZddlZddlZddlmZ  ej        e	¦  «        Z
 ej        d¦  «        ZddlmZ dd
„Z ej        d¦  «        Zdd„Zdd„Zdd„ZdS )uÍ  Shared helpers for canonicalising WhatsApp sender identity.

WhatsApp's bridge can surface the same human under two different JID shapes
within a single conversation:

- LID form: ``999999999999999@lid``
- Phone form: ``15551234567@s.whatsapp.net``

Both the authorisation path (:mod:`gateway.run`) and the session-key path
(:mod:`gateway.session`) need to collapse these aliases to a single stable
identity. This module is the single source of truth for that resolution so
the two paths can never drift apart.

Public helpers:

- :func:`normalize_whatsapp_identifier` â€” strip JID/LID/device/plus syntax
  down to the bare numeric identifier.
- :func:`canonical_whatsapp_identifier` â€” walk the bridge's
  ``lid-mapping-*.json`` files and return a stable canonical identity
  across phone/LID variants.
- :func:`expand_whatsapp_aliases` â€” return the full alias set for an
  identifier. Used by authorisation code that needs to match any known
  form of a sender against an allow-list.

Plugins that need per-sender behaviour on WhatsApp (role-based routing,
per-contact authorisation, policy gating in a gateway hook) should use
``canonical_whatsapp_identifier`` so their bookkeeping lines up with
Hermes' own session keys.
é    )ÚannotationsN)ÚSetz^[A-Za-z0-9@.+\-]+$)Úget_hermes_dirÚvalueÚstrÚreturnc                óÚ   — t          | pd¦  «                             ¦   «                              ddd¦  «                             dd¦  «        d                              dd¦  «        d         S )aN  Strip WhatsApp JID/LID syntax down to its stable numeric identifier.

    Accepts any of the identifier shapes the WhatsApp bridge may emit:
    ``"60123456789@s.whatsapp.net"``, ``"60123456789:47@s.whatsapp.net"``,
    ``"60123456789@lid"``, or a bare ``"+601****6789"`` / ``"60123456789"``.
    Returns just the numeric identifier (``"60123456789"``) suitable for
    equality comparisons.

    Useful for plugins that want to match sender IDs against
    user-supplied config (phone numbers in ``config.yaml``) without
    worrying about which variant the bridge happens to deliver.
    Ú ú+é   ú:r   ú@)r   ÚstripÚreplaceÚsplit)r   s    ú?/home/ragecks/.hermes/hermes-agent/gateway/whatsapp_identity.pyÚnormalize_whatsapp_identifierr   0   s\   € õ 	ˆEˆK�RÑÔß	Š‰Œß	Š��b˜!Ñ	Ô	ß	Šˆs�A‰Œ�qô	÷ 
Šˆs�A‰Œ�qô		ðó    z^\+?[\d\s().\-]+$c                óN  — | sdS t          | ¦  «                             ¦   «         }d|v r>d|v r:|                     d¦  «        \  }}}|                     dd¦  «        d         › d|› �}d|v r|S t                               |¦  «        rt          j        dd|¦  «        }|r|› d�S |S )u€  Normalize an *outbound* WhatsApp target to a bridge-safe JID.

    Baileys' ``jidDecode`` crashes on a bare phone number â€” it expects a
    fully-qualified JID such as ``50766715226@s.whatsapp.net``. This helper
    is the inverse of :func:`normalize_whatsapp_identifier`: instead of
    stripping a JID down to its numeric core for comparison, it *builds* the
    JID a send must use.

    Behaviour:

    - ``"+50766715226"`` / ``"50766715226"`` â†’ ``"50766715226@s.whatsapp.net"``
    - ``"50766715226@s.whatsapp.net"`` â†’ unchanged
    - ``"group-id@g.us"`` / ``"130631430344750@lid"`` â†’ unchanged
    - ``"user:device@s.whatsapp.net"`` style colon-before-``@`` â†’ ``@`` form
    - anything that isn't a recognizable bare phone â†’ returned unchanged so
      the bridge can surface a meaningful error rather than us mangling it.

    Returns ``""`` for an empty/whitespace input.
    r
   r   r   r   r   z\D+z@s.whatsapp.net)r   r   Ú	partitionr   Ú_BARE_PHONE_REÚ	fullmatchÚreÚsub)r   Ú
normalizedÚprefixÚ_ÚdomainÚdigitss         r   Úto_whatsapp_jidr    M   sØ   € ð( ð Øˆrå�U‘”×!Ò!Ñ#Ô#€Jð
 ˆjÐÐ˜S JÐ.Ð.Ø&×0Ò0°Ñ5Ô5Ñˆ��6ØŸš S¨!Ñ,Ô,¨QÔ/Ð:Ð:°&Ð:Ð:ˆ
ð ˆjÐÐØÐå×Ò 
Ñ+Ô+ð .Ý”˜  JÑ/Ô/ˆØð 	.ØÐ-Ð-Ð-Ð-àÐr   Ú
identifierúSet[str]c                ó–  — t          | ¦  «        }|st          ¦   «         S t          dd¦  «        }t          ¦   «         }|g}|�r|                     d¦  «        }|r||v rŒt                               |¦  «        sŒ:|                     |¦  «         dD ]³}|d|› |› d�z  }|                     ¦   «         sŒ"	 t          t          j	        | 
                    d¬¦  «        ¦  «        ¦  «        }n?# t          t          j        f$ r&}	t                               d	||	¦  «         Y d
}	~	Œ�d
}	~	ww xY w|r||vr|                     |¦  «         Œ´|�°|S )aà  Resolve WhatsApp phone/LID aliases via bridge session mapping files.

    Returns the set of all identifiers transitively reachable through the
    bridge's ``$HERMES_HOME/whatsapp/session/lid-mapping-*.json`` files,
    starting from ``identifier``. The result always includes the
    normalized input itself, so callers can safely ``in`` check against
    the return value without a separate fallback branch.

    Returns an empty set if ``identifier`` normalizes to empty.
    zplatforms/whatsapp/sessionzwhatsapp/sessionr   )r
   Ú_reversezlid-mapping-z.jsonzutf-8)Úencodingz(whatsapp_identity: failed to read %s: %sN)r   Úsetr   ÚpopÚ_SAFE_IDENTIFIER_REÚmatchÚaddÚexistsÚjsonÚloadsÚ	read_textÚOSErrorÚJSONDecodeErrorÚloggerÚdebugÚappend)
r!   r   Úsession_dirÚresolvedÚqueueÚcurrentÚsuffixÚmapping_pathÚmappedÚexcs
             r   Úexpand_whatsapp_aliasesr<   y   s•  € õ /¨zÑ:Ô:€JØð Ý‰uŒuˆå Ð!=Ð?QÑRÔR€KÝ™œ€HØˆL€Eà
ñ %Ø—)’)˜A‘,”,ˆØð 	˜' XÐ-Ð-Øõ #×(Ò(¨Ñ1Ô1ð 	Øà�Š�WÑÔÐØ&ð 	%ð 	%ˆFØ&Ð)N¸Ð)NÀÐ)NÐ)NÐ)NÑNˆLØ×&Ò&Ñ(Ô(ð ØðÝ6Ý”J˜|×5Ò5¸wÐ5ÑGÔGÑHÔHñô ��øõ �TÔ1Ð2ð ð ð Ý—’ÐGÈÐWZÑ[Ô[Ð[Ø����øøøøðøøøð ð %˜&¨Ð0Ð0Ø—’˜VÑ$Ô$Ð$øð9 ñ %ð< €Os   Â55C+Ã+D'ÄD"Ä"D'c                ój   — t          | ¦  «        }|sdS t          |¦  «        }t          |d„ ¬¦  «        S )uÃ  Return a stable WhatsApp sender identity across phone-JID/LID variants.

    WhatsApp may surface the same person under either a phone-format JID
    (``60123456789@s.whatsapp.net``) or a LID (``1234567890@lid``). This
    applies to a DM ``chat_id`` *and* to the ``participant_id`` of a
    member inside a group chat â€” both represent a user identity, and the
    bridge may flip between the two for the same human.

    This helper reads the bridge's ``whatsapp/session/lid-mapping-*.json``
    files, walks the mapping transitively, and picks the shortest
    (numeric-preferred) alias as the canonical identity.
    :func:`gateway.session.build_session_key` uses this for both WhatsApp
    DM chat_ids and WhatsApp group participant_ids, so callers get the
    same session-key identity Hermes itself uses.

    Plugins that need per-sender behaviour (role-based routing,
    authorisation, per-contact policy) should use this so their
    bookkeeping lines up with Hermes' session bookkeeping even when
    the bridge reshuffles aliases.

    Returns an empty string if ``identifier`` normalizes to empty. If no
    mapping files exist yet (fresh bridge install), returns the
    normalized input unchanged.
    r
   c                ó$   — t          | ¦  «        | fS )N)Úlen)Ú	candidates    r   ú<lambda>z/canonical_whatsapp_identifier.<locals>.<lambda>Î   s   € ­s°9©~¬~¸yÐ.I€ r   )Úkey)r   r<   Úmin)r!   r   Úaliasess      r   Úcanonical_whatsapp_identifierrE   ­   sD   € õ2 /¨zÑ:Ô:€JØð Øˆrõ
 & jÑ1Ô1€GÝˆwÐIÐIÐJÑJÔJÐJr   )r   r   r   r   )r!   r   r   r"   )r!   r   r   r   )Ú__doc__Ú
__future__r   r,   Úloggingr   Útypingr   Ú	getLoggerÚ__name__r1   Úcompiler(   Úhermes_constantsr   r   r   r    r<   rE   © r   r   ú<module>rO      sÿ   ððð ð< #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 	€	€	€	Ø Ð Ð Ð Ð Ð à	ˆÔ	˜8Ñ	$Ô	$€ð
 !�b”jÐ!7Ñ8Ô8Ð à +Ð +Ð +Ð +Ð +Ð +ðð ð ð ð4 �”Ð0Ñ1Ô1€ð)ð )ð )ð )ðX1ð 1ð 1ð 1ðh!Kð !Kð !Kð !Kð !Kð !Kr   