diff --git a/gateway/platforms/whatsapp_cloud.py b/gateway/platforms/whatsapp_cloud.py index bd5ac92b55f..3a74d33ebb0 100644 --- a/gateway/platforms/whatsapp_cloud.py +++ b/gateway/platforms/whatsapp_cloud.py @@ -225,18 +225,35 @@ class WhatsAppCloudAdapter(WhatsAppBehaviorMixin, BasePlatformAdapter): import os self._reply_prefix: Optional[str] = extra.get("reply_prefix") - self._dm_policy: str = str( - extra.get("dm_policy") - or os.getenv("WHATSAPP_CLOUD_DM_POLICY") - or os.getenv("WHATSAPP_DM_POLICY", "open") - ).strip().lower() + # Allowlist: honor the *documented* WHATSAPP_CLOUD_ALLOWED_USERS (the + # var the setup wizard writes) in addition to WHATSAPP_CLOUD_ALLOW_FROM. + # The adapter historically read only ALLOW_FROM, so an allowlist + # configured via the documented var silently dropped every inbound. self._allow_from: set[str] = self._normalize_allow_ids( self._coerce_allow_list( extra.get("allow_from") or extra.get("allowFrom") or os.getenv("WHATSAPP_CLOUD_ALLOW_FROM") + or os.getenv("WHATSAPP_CLOUD_ALLOWED_USERS") ) ) + # DM policy: explicit config wins; otherwise choose a safe, working + # default -- "open" if the operator opted into allow-all, else + # "allowlist" when an allowlist is configured (so it is actually + # enforced instead of silently dropping), else "open". + _allow_all_optin = str( + os.getenv("WHATSAPP_CLOUD_ALLOW_ALL_USERS", "") + ).strip().lower() in {"true", "1", "yes"} + _default_dm_policy = ( + "open" if _allow_all_optin + else ("allowlist" if self._allow_from else "open") + ) + self._dm_policy: str = str( + extra.get("dm_policy") + or os.getenv("WHATSAPP_CLOUD_DM_POLICY") + or os.getenv("WHATSAPP_DM_POLICY") + or _default_dm_policy + ).strip().lower() self._group_policy: str = str( extra.get("group_policy") or os.getenv("WHATSAPP_CLOUD_GROUP_POLICY") @@ -347,6 +364,17 @@ class WhatsAppCloudAdapter(WhatsAppBehaviorMixin, BasePlatformAdapter): return (bare or sender_id) in self._allow_from return super()._is_dm_allowed(sender_id) + def _open_dm_opted_in(self) -> bool: + """Also honor the documented WHATSAPP_CLOUD_ALLOW_ALL_USERS opt-in. + + The shared mixin only checks GATEWAY_ALLOW_ALL_USERS / + WHATSAPP_ALLOW_ALL_USERS; the Cloud adapter's documented open-access + opt-in is WHATSAPP_CLOUD_ALLOW_ALL_USERS, so honor it here too. + """ + if str(os.getenv("WHATSAPP_CLOUD_ALLOW_ALL_USERS", "")).strip().lower() in {"true", "1", "yes"}: + return True + return super()._open_dm_opted_in() + # ------------------------------------------------------------------ lifecycle async def connect(self, *, is_reconnect: bool = False) -> bool: if not check_whatsapp_cloud_requirements():