|
@@ -888,11 +888,11 @@ class ChattoAdapter(BasePlatformAdapter):
|
|
|
Deliberately our own gate instead of the gateway's authz_mixin: its
|
|
Deliberately our own gate instead of the gateway's authz_mixin: its
|
|
|
group allowlists key on chat_type and per-platform env vars
|
|
group allowlists key on chat_type and per-platform env vars
|
|
|
(``{PLATFORM}_GROUP_ALLOWED_USERS``), none of which fit Chatto's one
|
|
(``{PLATFORM}_GROUP_ALLOWED_USERS``), none of which fit Chatto's one
|
|
|
- flat member directory. ``CHATTO_ALLOWED_USERS`` matches login and id,
|
|
|
|
|
- ``CHATTO_ALLOW_ALL_USERS`` overrides both — the gate stays
|
|
|
|
|
|
|
+ flat member directory. ``CHATTO_ALLOWED_USERS`` matches user IDs,
|
|
|
|
|
+ ``CHATTO_ALLOW_ALL_USERS`` overrides it — the gate stays
|
|
|
chat_type-independent by design.
|
|
chat_type-independent by design.
|
|
|
"""
|
|
"""
|
|
|
- if self._is_authorized(user.id, user.login):
|
|
|
|
|
|
|
+ if self._is_authorized(user.id):
|
|
|
return True
|
|
return True
|
|
|
logger.warning(
|
|
logger.warning(
|
|
|
"Chatto: rejecting message from unauthorized user '%s' (%s)",
|
|
"Chatto: rejecting message from unauthorized user '%s' (%s)",
|
|
@@ -1908,7 +1908,7 @@ class ChattoAdapter(BasePlatformAdapter):
|
|
|
# third party talking.
|
|
# third party talking.
|
|
|
return f"{me.login} (this bot): {body}"
|
|
return f"{me.login} (this bot): {body}"
|
|
|
author = f"@{user.login}" if user else f"@{message.actor_id}"
|
|
author = f"@{user.login}" if user else f"@{message.actor_id}"
|
|
|
- if not self._is_authorized(message.actor_id, user.login if user else None):
|
|
|
|
|
|
|
+ if not self._is_authorized(message.actor_id):
|
|
|
# Auth gates the trigger message only; the rest of a shared thread
|
|
# Auth gates the trigger message only; the rest of a shared thread
|
|
|
# is reference text from people who may not be on the allowlist,
|
|
# is reference text from people who may not be on the allowlist,
|
|
|
# so it is marked as unverified rather than presented as trusted
|
|
# so it is marked as unverified rather than presented as trusted
|
|
@@ -1916,35 +1916,19 @@ class ChattoAdapter(BasePlatformAdapter):
|
|
|
return f"{author} (unverified): {body}"
|
|
return f"{author} (unverified): {body}"
|
|
|
return f"{author}: {body}"
|
|
return f"{author}: {body}"
|
|
|
|
|
|
|
|
- def _is_authorized(self, actor_id: str, login: str | None = None) -> bool:
|
|
|
|
|
- """Whether a Chatto user may talk to the agent, by id or login.
|
|
|
|
|
|
|
+ def _is_authorized(self, actor_id: str) -> bool:
|
|
|
|
|
+ """Whether a Chatto user may talk to the agent, by user ID.
|
|
|
|
|
|
|
|
The allowlist test itself, without the logging _check_auth adds: a
|
|
The allowlist test itself, without the logging _check_auth adds: a
|
|
|
rendering path asks the same question about someone quoted into the
|
|
rendering path asks the same question about someone quoted into the
|
|
|
prompt, where denial is a normal sight rather than an event worth a
|
|
prompt, where denial is a normal sight rather than an event worth a
|
|
|
- warning. Callers pass the login when they already hold the User;
|
|
|
|
|
- otherwise it is read from the user cache.
|
|
|
|
|
|
|
+ warning. IDs only — a login entry would pass this intake but fail the
|
|
|
|
|
+ gateway's fresh-role recheck, which matches raw IDs, and the message
|
|
|
|
|
+ would be silently dropped between the two gates.
|
|
|
"""
|
|
"""
|
|
|
if self.chatto_config.allow_all_users.value:
|
|
if self.chatto_config.allow_all_users.value:
|
|
|
return True
|
|
return True
|
|
|
- allowed = self.chatto_config.allowed_users.value
|
|
|
|
|
- if actor_id in allowed:
|
|
|
|
|
- return True
|
|
|
|
|
- if login is None:
|
|
|
|
|
- user = self._user_cache.get(actor_id)
|
|
|
|
|
- login = user.login if user else None
|
|
|
|
|
- return login is not None and login in allowed
|
|
|
|
|
-
|
|
|
|
|
- def _is_allowed_user_id(self, user_id: str) -> bool:
|
|
|
|
|
- """Whether a Chatto user identified only by id may talk to the agent.
|
|
|
|
|
-
|
|
|
|
|
- Lighter than ``_check_auth``: callers such as reaction routing hold
|
|
|
|
|
- only an actor id, not a ``User`` or ``MessageEvent``. Consults the
|
|
|
|
|
- same ``CHATTO_ALLOWED_USERS`` / ``CHATTO_ALLOW_ALL_USERS`` settings,
|
|
|
|
|
- including a login looked up from ``_user_cache`` when the id itself
|
|
|
|
|
- is not listed. Fail-closed when neither setting allows anyone.
|
|
|
|
|
- """
|
|
|
|
|
- return self._is_authorized(user_id)
|
|
|
|
|
|
|
+ return actor_id in self.chatto_config.allowed_users.value
|
|
|
|
|
|
|
|
def _interactive_prompt_expired(self, prompt: Any) -> bool:
|
|
def _interactive_prompt_expired(self, prompt: Any) -> bool:
|
|
|
"""Whether an interactive prompt has passed its expiry deadline."""
|
|
"""Whether an interactive prompt has passed its expiry deadline."""
|
|
@@ -2006,7 +1990,7 @@ class ChattoAdapter(BasePlatformAdapter):
|
|
|
return True
|
|
return True
|
|
|
|
|
|
|
|
# Authorization (fail-closed).
|
|
# Authorization (fail-closed).
|
|
|
- if not self._is_allowed_user_id(actor_id):
|
|
|
|
|
|
|
+ if not self._is_authorized(actor_id):
|
|
|
return True
|
|
return True
|
|
|
|
|
|
|
|
# Double-click guard.
|
|
# Double-click guard.
|