
     Yj                    v    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 ddd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_identifier namestrdefaultreturnc                (   | s|S 	 ddl m}  ||           }|Bt          |                                          r!t          |                                          S n# t          $ r Y nw xY wt          j        |           p|                                S )zERead allowlist/auth env; prefer profile secret_scope under multiplex.r   )
get_secret)agent.secret_scoper   r   strip	Exceptionosgetenv)r
   r   r   vals       HC:\Users\server\AppData\Local\hermes\hermes-agent\gateway\authz_mixin.py	_auth_envr      s     111111j?s3xx~~//?s88>>###   IdOO&w--///s   AA 
A)(A)c                      e Zd ZdZ	 dddZdd
ZddddZddddZddddZddddZ	ddddZ
d dZd!dZddddZdS )"GatewayAuthorizationMixinz6User/chat authorization methods for ``GatewayRunner``.NplatformOptional[Platform]profileOptional[str]c                   |sdS |pd                                 pd}|r:|dk    r4t          | dd          pi }||v r||                             |          S dS t          | dd          pi }|                    |          S )a  Resolve the live adapter whose intake policy should gate authorization.

        In multiplex mode, secondary-profile adapters live in
        ``_profile_adapters[profile]`` while the default/active profile uses
        ``self.adapters``. ``SessionSource.profile`` selects which map to consult.
        When a stamped profile has its own adapter registry entry, the default
        profile's same-platform adapter must not be consulted as a fallback.
        Nr	   r   _profile_adaptersadapters)r   getattrget)selfr   r   profile_nameprofile_adaptersr    s         r   _authorization_adapterz0GatewayAuthorizationMixin._authorization_adapter1   s      	42,,..6$ 	LI55&t-@$GGM2///'599(CCC 44T228b||H%%%    sourceOptional[SessionSource]c                r    |dS |                      t          |dd          t          |dd                    S )z:Resolve the live adapter for an inbound ``SessionSource``.Nr   r   )r&   r!   )r#   r(   s     r   _adapter_for_sourcez-GatewayAuthorizationMixin._adapter_for_sourceL   sD    >4 **FJ--FIt,,
 
 	
r'   r   r   boolc               z    |sdS |                      ||          }|dS t          t          |dd                    S )a  Whether the adapter for *platform* delegates authz to a trusted upstream.

        Mirrors ``BasePlatformAdapter.authorization_is_upstream``. The relay
        adapter sets this True: the Team Gateway connector authenticates the
        gateway's WS and resolves owner-only author bindings before delivering,
        so an inbound relay event is already authorized as this instance's bound
        user. Unlike ``_adapter_enforces_own_access_policy`` (a LOCAL config
        policy the gateway mirrors only when it's an allowlist), this is an
        UPSTREAM decision the gateway honors directly. Defaults to ``False`` when
        the adapter is unknown or doesn't expose the flag.
        FNauthorization_is_upstreamr&   r-   r!   r#   r   r   adapters       r   "_adapter_authorization_is_upstreamz<GatewayAuthorizationMixin._adapter_authorization_is_upstreamW   sK    "  	5--h@@?5GG%@%HHIIIr'   c               z    |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. The flag alone is NOT "already
        authorized": these adapters default to ``open``, which forwards every
        sender, so ``_is_user_authorized`` only trusts the adapter when its
        effective policy for the chat type is an actual ``allowlist`` restriction
        (see that method). Defaults to ``False`` when the adapter is unknown or
        doesn't expose the flag.
        FNenforces_own_access_policyr0   r1   s       r   #_adapter_enforces_own_access_policyz=GatewayAuthorizationMixin._adapter_enforces_own_access_policyo   sM    $  	5 --h@@?5GG%A5IIJJJr'   r   c                  |sdS |                      ||          }|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 )u  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 decide whether an own-policy adapter
        actually restricted DM senders to a configured allowlist (trustworthy)
        or merely forwarded everyone under ``dm_policy: open`` / for a pairing
        handshake (not authorization). "Reached the gateway" only carries an
        authorization signal in the ``allowlist`` case.
        r	   N
_dm_policyconfig	platformsextra	dm_policy
r&   r!   hasattrr:   r"   
isinstancedictr   r   lowerr#   r   r   r2   policyr9   platform_cfgr;   s           r   _adapter_dm_policyz,GatewayAuthorizationMixin._adapter_dm_policy   s    *  	2--h@@9@9L,555RV>T8T22F %'&+*F*F%  $$X... 
 =IRGL'4888dE%&& 0;//6<R  &&((..000r'   c                  |sdS |                      ||          }|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 )a  Best-effort read of an own-policy adapter's effective group policy.

        Mirror of ``_adapter_dm_policy`` for group / forum / channel traffic:
        returns the lowercased ``group_policy`` (``"open"`` / ``"allowlist"`` /
        ``"disabled"``) for *platform*, or ``""`` when unknown. Prefers the live
        adapter's resolved ``_group_policy`` and falls back to ``config.extra``
        for bare runners built without a live adapter.

        Used by ``_is_user_authorized`` to decide whether an own-policy adapter
        restricted group senders to a configured allowlist (trustworthy) or
        forwarded the whole channel under ``group_policy: open`` (not
        authorization).
        r	   N_group_policyr9   r:   r;   group_policyr=   rB   s           r   _adapter_group_policyz/GatewayAuthorizationMixin._adapter_group_policy   s    &  	2--h@@<C<O/4888UY>T8T22F %'&+*F*F%  $$X... 
 =IRGL'4888dE%&& 3>226<R  &&((..000r'   chat_idc                  |r|sdS |                      ||          }|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          |t                    sdS t          |          }	|                    |	          }
t          |
t                    st|	                                }|	                                D ]K\  }}t          |t                    r1|                                |k    rt          |t                    r|}
 nLt          |
t                    s|                    d          }
t          |
t                    sdS |
                    d	          p|
                    d
          }t          |t                    r!t          |                                          S t          |t          t          t          f          rt          d |D                       S dS )a  Whether a per-group sender allowlist gated this group message.

        WeCom supports ``groups.<group_id>.allow_from`` on top of the top-level
        ``group_policy``. A group may be open at the chat level while still
        restricting which senders inside that group can invoke Hermes. If such a
        message reached the gateway, the adapter already checked that sender
        allowlist, so it is a trustworthy intake decision rather than the
        fail-open ``group_policy: open`` case.
        FN_groupsr9   r:   r;   groups*
allow_from	allowFromc              3  X   K   | ]%}t          |                                          V  &d S N)r   r   ).0items     r   	<genexpr>zPGatewayAuthorizationMixin._adapter_group_has_sender_allowlist.<locals>.<genexpr>  s2      BBTs4yy((BBBBBBr'   )r&   r!   r>   r:   r"   r?   r@   r   rA   itemsr-   r   listtuplesetany)r#   r   rJ   r   r2   rM   r9   rD   r;   chat_id_str	group_cfgloweredkeyvaluesender_allows                  r   #_adapter_group_has_sender_allowlistz=GatewayAuthorizationMixin._adapter_group_has_sender_allowlist   sJ      	w 	5--h@@6=6I)T222t>T8T22F %'&+*F*F%  $$X... 
 =IRGL'4888dE%&& -8,,&$'' 	5'llJJ{++	)T** 	!''))G$llnn  
Uc3'' CIIKK7,B,BzRWY]G^G^,B %IE)T** 	(

3I)T** 	5 }}\22PimmK6P6PlC(( 	.**,,---lT5#$677 	CBB\BBBBBBur'   'SessionSource'c                    t          | dd          pi }t          |dd          }|r||v r||         S t          | dd          S )a  Pick the per-profile PairingStore for a source, falling back to global.

        In a multiplexing gateway, each profile owns its own pairing whitelist
        so isolation is preserved. When the source has no profile (single-
        profile gateway, or a path that hasn't stamped profile yet) or the
        profile isn't registered, fall back to ``self.pairing_store`` (the
        global default) so existing behavior is preserved.
        pairing_storesNr   pairing_store)r!   )r#   r(   per_profiler   s       r   _pairing_store_forz,GatewayAuthorizationMixin._pairing_store_for  s[     d$4d;;Ar&)T22 	(w+--w''t_d333r'   r   c                J   ddl m} |j        t          j        t          j        hv rdS |j        du s!|                     |j        |j                  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 t          j        dt          j        dt          j        dt          j        di}t-          |dd          rY|                    |j                  }|r=t          j        |d                                                                          d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        d0t          j        d1t          j        d2t          j         d3t          j!        d4t          j"        d5t          j#        d6t          j        d7t          j$        d8i}|j        |	vre	 dd9l%m&} |                    |j        j'                  }|r,|j(        r|j(        |	|j        <   |j)        r|j)        ||j        <   n# tT          $ r Y nw xY w|                    |j        d          }|r%tW          |                                          d:v rdS t-          |d;d          du rdS |j        r|j        j'        nd}| ,                    |          }||-                    ||          rdS tW          |	                    |j        d                    }d}d}|j
        d=v rPtW          |
                    |j        d                    }tW          |                    |j        d                    }tW          d>          }|s|s|s|s| .                    |j        |j                  r}|j
        dv rK| /                    |j        |j                  }| 0                    |j        |j        |j                  rdS n!| 1                    |j        |j                  }|d?k    rdS tW          d@                                          d:v S |r>|j
        d=v r5|j        r.dA |                    d
          D             }d|v s	|j        |v rdS |j        t          j        k    r|r|j
        d=v r|j        rzdB |                    d
          D             }|rYt-          | dCd          s=|2                    dDd
3                    ti          |                               d| _5        |j        |v rdS tm                      }|r2|7                    dE |                    d
          D                        |r2|7                    dF |                    d
          D                        |r2|7                    dG |                    d
          D                        d|v rdS |h}dH|v r.|8                    |                    dH          d                    |j        t          j        k    rtm                      }|D ]$}|7                    ts          |                     %|r|}|7                    ts          |                     tu          |          }|r|8                    |           |j        1|j        j'        dIk    r!|j;        r|8                    |j;                   ty          ||z            S )Jao  
        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   )loggerTr,   >   forumgroupchannelTELEGRAM_GROUP_ALLOWED_CHATSQQ_GROUP_ALLOWED_USERSr	   c                ^    h | ]*}|                                 |                                 +S  r   )rS   cids     r   	<setcomp>z@GatewayAuthorizationMixin._is_user_authorized.<locals>.<setcomp>`  s>     ) ) )99;;)		) ) )r'   ,rN   DISCORD_ALLOW_BOTSFEISHU_ALLOW_BOTSTELEGRAM_ALLOW_BOTSSLACK_ALLOW_BOTSis_botFnone>   allmentions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)platform_registry>   1yestruerole_authorizedN>   rj   rk   GATEWAY_ALLOWED_USERS	allowlistGATEWAY_ALLOW_ALL_USERSc                ^    h | ]*}|                                 |                                 +S rp   rq   )rS   rJ   s     r   rs   z@GatewayAuthorizationMixin._is_user_authorized.<locals>.<setcomp>  sB     ! ! !$+RYR_R_RaRa!! ! !r'   c                    h | ]=}|                                                     d           )|                                 >S )-)r   
startswith)rS   vs     r   rs   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 rR   rq   rS   uids     r   rU   z@GatewayAuthorizationMixin._is_user_authorized.<locals>.<genexpr>A  s<      ccsWZW`W`WbWbcsyy{{ccccccr'   c              3  f   K   | ],}|                                 |                                 V  -d S rR   rq   r   s     r   rU   z@GatewayAuthorizationMixin._is_user_authorized.<locals>.<genexpr>C  s<      eesY\YbYbYdYdesyy{{eeeeeer'   c              3  f   K   | ],}|                                 |                                 V  -d S rR   rq   r   s     r   rU   z@GatewayAuthorizationMixin._is_user_authorized.<locals>.<genexpr>E  s<      aasUXU^U^U`U`asyy{{aaaaaar'   @simplex)=gateway.runri   r   r   HOMEASSISTANTWEBHOOKdelivered_via_upstream_relayr3   r   user_id	chat_typerJ   TELEGRAMQQBOTr"   r   r   r   splitDISCORDFEISHUSLACKr!   rA   WHATSAPPWHATSAPP_CLOUDSIGNALEMAILSMS
MATTERMOSTMATRIXDINGTALKWECOMWECOM_CALLBACKWEIXINBLUEBUBBLESYUANBAOgateway.platform_registryr   r_   allowed_users_envallow_all_envr   r   rg   is_approvedr6   rI   ra   rE   warningjoinsortedr   rY   updateadd_expand_whatsapp_auth_aliases_normalize_whatsapp_identifier	user_namer-   )r#   r(   ri   r   chat_allowlist_envraw_chat_allowlistallowed_group_idsplatform_allow_bots_mapallow_bots_varplatform_env_mapplatform_group_user_env_mapplatform_group_chat_env_mapplatform_allow_all_mapr   entryplatform_allow_all_varplatform_namere   platform_allowlistgroup_user_allowlistgroup_chat_allowlistglobal_allowlisteffective_policylegacy_chat_idsallowed_ids	check_idsnormalized_allowed_ids
allowed_idnormalized_user_ids                                r   _is_user_authorizedz-GatewayAuthorizationMixin._is_user_authorized  su
    	'&&&&& ?x5x7GHHH4: .$66$:a:aON ;b ;
 ;
6 4. <<<<!#A 8" c&/2&&  " 	$%'Y/A2%F%F%L%L%N%N"% $) )#5#;#;C#@#@) ) )%
 ///6>EV3V3V#t 2O04N.	#
 68U++ 	488IIN ")NF"C"C"I"I"K"K"Q"Q"S"SWj"j"j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22	GGGGGG)--fo.CDD V. T<A<S(9* VBGBU.v?    "8!;!;FOR!P!P! 	i0F&G&G&M&M&O&OSg&g&g4 6,e44<<4  28H--b//77$)B)B=RY)Z)Z$4 ''7';';FOR'P'PQQ!!111#,-H-L-LV_^`-a-a#b#b #,-H-L-LV_^`-a-a#b#b $%<==! /	X*> /	XG[ /	Xdt /	X0 77 8     #'DDD'+'A'A & (B ( ($ ?? & @   $
  $t$ (,'>'> & (? ( ($ ${224677==??CWWW
   	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   #AO7 7
PPc               @   t          | dd          }|rht          |d          rX|rVt          |d          r|j                            |          nd}|r(dt          |di           v r|                    |          S |t
          j        k    rdS |r"t          |d          r|j        dk    r|j        S |r|                     ||	          }|s|rt          |d          r|j                            |          }|rt          |dd          nd}t          |t                    rHt          |                    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. Email defaults to ``"ignore"`` unless explicitly opted into
           pairing. Inboxes may contain arbitrary unread human messages, so
           replying with pairing codes is not a safe platform default.
        3. Explicit global ``unauthorized_dm_behavior`` in config — wins for
           chat-shaped platforms when no per-platform override is set.
        4. When an adapter-level DM policy opts into pairing or silent drop, honor it.
        5. 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)
        6. No allowlist and no explicit config → ``"pair"`` (open-gateway default).
        r9   Nget_unauthorized_dm_behaviorr:   unauthorized_dm_behaviorr;   ignorepairr,   r<   r	   pairing>   disabledr   r}   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r   rm   )rn   rp   r   ) r!   r>   r:   r"   r   r   r   r   rE   r?   r@   r   r   rA   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )
r#   r   r   r9   rD   r<   r;   r   platform_group_env_mapenv_keys
             r   _get_unauthorized_dm_behaviorz7GatewayAuthorizationMixin._get_unauthorized_dm_behaviorn  s   0 x..  	Egf&DEE 	E( 	E=DV[=Y=Yc6+//999_cL E :glT[]_>`>` ` `::8DDD x~%%8  	7gf&@AA 	7.&8866  
	 //'/JJI R RGFK,H,H R%/33H==@LVgt<<<RVeT** R #EIIk$:$:$@b A A G G I I O O Q QII%%v555x
  	$ !#;  #:  !#;  ')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'   rR   )r   r   r   r   )r(   r)   )r   r   r   r   r   r-   )r   r   r   r   r   r   )r   r   rJ   r   r   r   r   r-   )r(   rb   )r(   r   r   r-   )__name__
__module____qualname____doc__r&   r+   r3   r6   rE   rI   ra   rg   r   r   rp   r'   r   r   r   .   sc       @@
 "&& & & & &6	
 	
 	
 	
 "&	J J J J J J8 "&	K K K K K K@ "&	#1 #1 #1 #1 #1 #1R "&	!1 !1 !1 !1 !1 !1P "&3 3 3 3 3 3j4 4 4 4U- U- U- U-v
 "&	g g g g g g g gr'   r   )r	   )r
   r   r   r   r   r   )r  
__future__r   r   typingr   gateway.configr   gateway.sessionr   gateway.whatsapp_identityr   r   r   r   r   r   rp   r'   r   <module>r     s    " # " " " " " 				       # # # # # # ) ) ) ) ) )       0 0 0 0 0g
 g
 g
 g
 g
 g
 g
 g
 g
 g
r'   