
    ,jW                    l    d Z ddlmZ ddlZddlmZ ddlmZ ddlm	Z	 ddl
mZmZ  G d d	          ZdS )
a  User-authorization methods for ``GatewayRunner``.

Extracted from ``gateway/run.py`` as part of the god-file decomposition campaign
(``~/.hermes/plans/god-file-decomposition.md``, Phase 3 mechanical mixin lifts).
This mixin holds the inbound-message authorization cluster: whether a user/chat
is allowed to talk to the agent, the per-adapter DM policy, and the
unauthorized-DM behavior.

Behavior-neutral: every method is lifted verbatim from ``GatewayRunner``.
``self.*`` calls resolve unchanged via the MRO. Neutral dependencies import at
module top; the module-level ``logger`` is imported lazily inside the one method
that uses it (``from gateway.run import logger`` resolves at call time, when
``gateway.run`` is fully loaded) so this module never imports ``gateway.run`` at
import time -> no import cycle. The lazy import preserves the exact logger name
(``"gateway.run"``) so log records are unchanged.
    )annotationsN)Optional)Platform)SessionSource)expand_whatsapp_aliasesnormalize_whatsapp_identifierc                  2    e Zd ZdZddZddZddZddZdS )GatewayAuthorizationMixinz6User/chat authorization methods for ``GatewayRunner``.platformOptional[Platform]returnboolc                    |sdS t          | dd          }|sdS |                    |          }|dS t          t          |dd                    S )a*  Whether the adapter for *platform* gates access at intake itself.

        Mirrors ``BasePlatformAdapter.enforces_own_access_policy``. Adapters
        such as WeCom, Weixin, Yuanbao, QQBot, and WhatsApp evaluate their
        documented ``dm_policy`` / ``group_policy`` / ``allow_from`` config before a
        message is dispatched to the gateway, so a message that reaches
        ``_is_user_authorized`` has already been authorized by the adapter.
        Defaults to ``False`` when the adapter is unknown or doesn't expose
        the flag.
        FadaptersNenforces_own_access_policy)getattrgetr   )selfr   r   adapters       8/home/ubuntu/.hermes/hermes-agent/gateway/authz_mixin.py#_adapter_enforces_own_access_policyz=GatewayAuthorizationMixin._adapter_enforces_own_access_policy"   sg      	5 4T22 	5,,x((?5GG%A5IIJJJ    strc                   |sdS t          | dd          pi }|                    |          }|t          |dd          nd}|~t          | dd          }|*t          |d          r|j                            |          nd}|rt          |dd          nd}t	          |t
                    r|                    d          }t          |pd                                                                          S )	uB  Best-effort read of an own-policy adapter's effective DM policy.

        Returns the lowercased ``dm_policy`` (``"open"`` / ``"allowlist"`` /
        ``"disabled"`` / ``"pairing"``) for *platform*, or ``""`` when unknown.
        Prefers the live adapter's resolved ``_dm_policy`` — which already folds
        in both ``config.extra`` and the ``<PLATFORM>_DM_POLICY`` env var (the
        env var is not always bridged back into ``config.extra``) — and falls
        back to ``config.extra`` for bare runners built without a live adapter.

        Used by ``_is_user_authorized`` to carve ``dm_policy: pairing`` out of
        the adapter-trust shortcut: in pairing mode the adapter forwards the DM
        so the gateway can run its pairing handshake, so "reached the gateway"
        must not be read as "authorized".
         r   N
_dm_policyconfig	platformsextra	dm_policy)	r   r   hasattrr   
isinstancedictr   striplower)r   r   r   r   policyr   platform_cfgr   s           r   _adapter_dm_policyz,GatewayAuthorizationMixin._adapter_dm_policy:   s     	24T228b,,x((9@9L,555RV>T8T22F %'&+*F*F%  $$X... 
 =IRGL'4888dE%&& 0;//6<R  &&((..000r   sourcer   c                   ddl m} |j        t          j        t          j        hv rdS |j        }|j        dv r|j        rt          j	        dt          j
        di                    |j        d          }|rWt          j        |d                                          }|r.d |                    d	          D             }d
|v s	|j        |v rdS |sdS i t          j	        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j
        dt          j        di}t          j	        di}t          j	        dt          j
        di}	i t          j	        dt          j        d t          j        d!t          j        d"t          j        d#t          j        d$t          j        d%t          j        d&t          j        d't          j        d(t          j        d)t          j        d*t          j        d+t          j        d,t          j        d-t          j        d.t          j
        d/t          j        d0i}
t          j        d1t          j        d2i}|j        |vre	 dd3l m!} |                    |j        j"                  }|r,|j#        r|j#        ||j        <   |j$        r|j$        |
|j        <   n# tJ          $ r Y nw xY w|
                    |j        d          }|r+t          j        |d          &                                d4v rdS tO          |d5d          du rdS tO          |d6d          rY|                    |j                  }|r=t          j        |d7          &                                                                d8v rdS |j        r|j        j"        nd}| j(        )                    ||          rdS t          j        |                    |j        d          d                                          }d}d}|j        d9v rt          j        |                    |j        d          d                                          }t          j        |	                    |j        d          d                                          }t          j        d:d                                          }|st|sr|sp|sn| *                    |j                  r+|j        d;k    r| +                    |j                  d<k    sdS t          j        d=d          &                                d4v S |r>|j        d9v r5|j        r.d> |                    d	          D             }d
|v s	|j        |v rdS |j        t          j	        k    r|r|j        d9v r|j        rzd? |                    d	          D             }|rYtO          | d@d          s=|,                    dAd	-                    t]          |                               d| _/        |j        |v rdS ta                      }|r2|1                    dB |                    d	          D                        |r2|1                    dC |                    d	          D                        |r2|1                    dD |                    d	          D                        d
|v rdS |h}dE|v r.|2                    |                    dE          d                    |j        t          j        k    rta                      }|D ]$}|1                    tg          |                     %|r|}|1                    tg          |                     ti          |          }|r|2                    |           |j        1|j        j"        dGk    r!|j5        r|2                    |j5                   tm          ||z            S )Hao  
        Check if a user is authorized to use the bot.
        
        Checks in order:
        1. Per-platform allow-all flag (e.g., DISCORD_ALLOW_ALL_USERS=true)
        2. Environment variable allowlists (TELEGRAM_ALLOWED_USERS, etc.)
        3. DM pairing approved list
        4. Global allow-all (GATEWAY_ALLOW_ALL_USERS=true)
        5. Default: deny
        r   )loggerT>   forumgroupchannelTELEGRAM_GROUP_ALLOWED_CHATSQQ_GROUP_ALLOWED_USERSr   c                ^    h | ]*}|                                 |                                 +S  r$   ).0cids     r   	<setcomp>z@GatewayAuthorizationMixin._is_user_authorized.<locals>.<setcomp>   s>     ) ) )99;;)		) ) )r   ,*FTELEGRAM_ALLOWED_USERSDISCORD_ALLOWED_USERSWHATSAPP_ALLOWED_USERSWHATSAPP_CLOUD_ALLOWED_USERSSLACK_ALLOWED_USERSSIGNAL_ALLOWED_USERSEMAIL_ALLOWED_USERSSMS_ALLOWED_USERSMATTERMOST_ALLOWED_USERSMATRIX_ALLOWED_USERSDINGTALK_ALLOWED_USERSFEISHU_ALLOWED_USERSWECOM_ALLOWED_USERSWECOM_CALLBACK_ALLOWED_USERSWEIXIN_ALLOWED_USERSBLUEBUBBLES_ALLOWED_USERSQQ_ALLOWED_USERSYUANBAO_ALLOWED_USERSTELEGRAM_GROUP_ALLOWED_USERSTELEGRAM_ALLOW_ALL_USERSDISCORD_ALLOW_ALL_USERSWHATSAPP_ALLOW_ALL_USERSWHATSAPP_CLOUD_ALLOW_ALL_USERSSLACK_ALLOW_ALL_USERSSIGNAL_ALLOW_ALL_USERSEMAIL_ALLOW_ALL_USERSSMS_ALLOW_ALL_USERSMATTERMOST_ALLOW_ALL_USERSMATRIX_ALLOW_ALL_USERSDINGTALK_ALLOW_ALL_USERSFEISHU_ALLOW_ALL_USERSWECOM_ALLOW_ALL_USERSWECOM_CALLBACK_ALLOW_ALL_USERSWEIXIN_ALLOW_ALL_USERSBLUEBUBBLES_ALLOW_ALL_USERSQQ_ALLOW_ALL_USERSYUANBAO_ALLOW_ALL_USERSDISCORD_ALLOW_BOTSFEISHU_ALLOW_BOTS)platform_registry>   1yestruerole_authorizedis_botnone>   allmentions>   r,   r-   GATEWAY_ALLOWED_USERSdmpairingGATEWAY_ALLOW_ALL_USERSc                ^    h | ]*}|                                 |                                 +S r2   r3   )r4   chat_ids     r   r6   z@GatewayAuthorizationMixin._is_user_authorized.<locals>.<setcomp>  sB     ! ! !$+RYR_R_RaRa!! ! !r   c                    h | ]=}|                                                     d           )|                                 >S )-)r$   
startswith)r4   vs     r   r6   z@GatewayAuthorizationMixin._is_user_authorized.<locals>.<setcomp>  sL       7799'',,		  r   #_warned_telegram_group_users_legacyu   TELEGRAM_GROUP_ALLOWED_USERS contains chat-ID-shaped values (%s). Treating them as chat IDs for backward compatibility. Move chat IDs to TELEGRAM_GROUP_ALLOWED_CHATS — the _USERS var is now for sender user IDs.c              3  f   K   | ],}|                                 |                                 V  -d S Nr3   r4   uids     r   	<genexpr>z@GatewayAuthorizationMixin._is_user_authorized.<locals>.<genexpr>7  s<      ccsWZW`W`WbWbcsyy{{ccccccr   c              3  f   K   | ],}|                                 |                                 V  -d S ru   r3   rv   s     r   rx   z@GatewayAuthorizationMixin._is_user_authorized.<locals>.<genexpr>9  s<      eesY\YbYbYdYdesyy{{eeeeeer   c              3  f   K   | ],}|                                 |                                 V  -d S ru   r3   rv   s     r   rx   z@GatewayAuthorizationMixin._is_user_authorized.<locals>.<genexpr>;  s<      aasUXU^U^U`U`asyy{{aaaaaar   @Nsimplex)7gateway.runr+   r   r   HOMEASSISTANTWEBHOOKuser_id	chat_typern   TELEGRAMQQBOTr   osgetenvr$   splitDISCORDWHATSAPPWHATSAPP_CLOUDSLACKSIGNALEMAILSMS
MATTERMOSTMATRIXDINGTALKFEISHUWECOMWECOM_CALLBACKWEIXINBLUEBUBBLESYUANBAOgateway.platform_registryr`   valueallowed_users_envallow_all_env	Exceptionr%   r   pairing_storeis_approvedr   r(   warningjoinsortedrs   setupdateadd_expand_whatsapp_auth_aliases_normalize_whatsapp_identifier	user_namer   )r   r)   r+   r   chat_allowlist_envraw_chat_allowlistallowed_group_idsplatform_env_mapplatform_group_user_env_mapplatform_group_chat_env_mapplatform_allow_all_mapplatform_allow_bots_mapr`   entryplatform_allow_all_varallow_bots_varplatform_nameplatform_allowlistgroup_user_allowlistgroup_chat_allowlistglobal_allowlistlegacy_chat_idsallowed_ids	check_idsnormalized_allowed_ids
allowed_idnormalized_user_ids                              r   _is_user_authorizedz-GatewayAuthorizationMixin._is_user_authorizedZ   s	    	'&&&&& ?x5x7GHHH4. <<<<!#A 8" c&/2&&  " 	$%'Y/A2%F%F%L%L%N%N"% $) )#5#;#;C#@#@) ) )%
 ///6>EV3V3V#t 	5
7
5
 7
 #%C	

 N1
 O3
 N1
 L-
 !;
 O3
 7
 O3
 N1
 #%C
 O3
   "=!
" N.#
$ 5%
 
* ='
# =N4'
#"
9"
7"
 9"
 #%E	"

 N3"
 O5"
 N3"
 L/"
 !="
 O5"
 9"
 O5"
 N3"
 #%E"
 O5"
   "?!"
" N0#"
$ 7%"
 "
, 2O0#
 ?"222	GGGGGG)--fo.CDD V. T<A<S(9* VBGBU.v?    "8!;!;FOR!P!P! 	bi0F&K&K&Q&Q&S&SWk&k&k4 6,e44<<468U++ 	488IIN ")NF"C"C"I"I"K"K"Q"Q"S"SWj"j"jt 28H--b))-AA 	4  Y'7';';FOR'P'PRTUU[[]]!!111#%9-H-L-LV_^`-a-ace#f#f#l#l#n#n #%9-H-L-LV_^`-a-ace#f#f#l#l#n#n 9%<bAAGGII! 	\*> 	\G[ 	\dt 	\ 77HH   $,,//@@IMM496;;AACCG[[[
   	F$48J$J$Jv~$J! !/C/I/I#/N/N! ! ! '''6>=N+N+Nt Ox000$ 1 $666 7 -33C88  O
   t%JERR DNN6 !8!899   @DD<>_444 ee 	dcc6H6N6Ns6S6Scccccc 	fee6J6P6PQT6U6Ueeeeee 	baa6F6L6LS6Q6Qaaaaaa +4I	'>>MM'--,,Q/000 ?h///%(UU") Y Y
&--.KJ.W.WXXXX% 54:7CCDDD!?!H!H! 20111 O'%22  3 MM&*+++I+,,,s   5AM	 	
MMc                   t          | dd          }|rht          |d          rX|rVt          |d          r|j                            |          nd}|r(dt          |di           v r|                    |          S |r"t          |d          r|j        dk    r|j        S |r|rt          |d          r|j                            |          }|rt          |dd          nd}t          |t                    rVt          |                    d          pd	          	                                
                                }|d
k    rdS |dv rdS |ryi t          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        d}t          j        dt          j        di}t;          j        |                    |d	          d	          	                                rdS |                    |d           D ],}t;          j        |d	          	                                r dS -t;          j        d!d	          	                                rdS dS )"u  Return how unauthorized DMs should be handled for a platform.

        Resolution order:
        1. Explicit per-platform ``unauthorized_dm_behavior`` in config — always wins.
        2. Explicit global ``unauthorized_dm_behavior`` in config — wins when no per-platform.
        3. When an allowlist (``PLATFORM_ALLOWED_USERS``,
           ``PLATFORM_GROUP_ALLOWED_USERS`` / ``PLATFORM_GROUP_ALLOWED_CHATS``,
           or ``GATEWAY_ALLOWED_USERS``) is configured, default to ``"ignore"`` —
           the allowlist signals that the owner has deliberately restricted
           access; spamming unknown contacts with pairing codes is both noisy
           and a potential info-leak. (#9337)
        4. No allowlist and no explicit config → ``"pair"`` (open-gateway default).
        r   Nget_unauthorized_dm_behaviorr   unauthorized_dm_behaviorr   pairr    r   rk   >   disabled	allowlistignorer9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   )rK   r/   )r0   r2   ri   )r   r!   r   r   r   r   r"   r#   r   r$   r%   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )	r   r   r   r'   r   r    r   platform_group_env_mapenv_keys	            r   _get_unauthorized_dm_behaviorz7GatewayAuthorizationMixin._get_unauthorized_dm_behaviord  so    x..  	Egf&DEE 	E( 	E=DV[=Y=Yc6+//999_cL E :glT[]_>`>` ` `::8DDD  	7gf&@AA 	7.&8866  	$ 	$76;#?#? 	$!+//99L<HRGL'4888dE%&& $		+ 6 6 <"==CCEEKKMM		))!6 999#8
  	$ !#;  #:  !#;  ')G	 
 #8  #9  #8  #6  #%?  #9  !#;  #9  #8  ')G  #9   $&A! " #5# ( ! $  ;&" y)--h;;R@@FFHH  x155hCC $ $9Wb))//11 $#88$ 9,b117799 	8vr   N)r   r   r   r   )r   r   r   r   )r)   r   r   r   )__name__
__module____qualname____doc__r   r(   r   r   r2   r   r   r
   r
      sz        @@K K K K01 1 1 1@H- H- H- H-TQ Q Q Q Q Qr   r
   )r   
__future__r   r   typingr   gateway.configr   gateway.sessionr   gateway.whatsapp_identityr   r   r   r   r
   r2   r   r   <module>r      s    " # " " " " " 				       # # # # # # ) ) ) ) ) )       V V V V V V V V V Vr   