mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-24 16:54:43 +00:00
fix(slack): route file downloads to the owning workspace via URL-embedded team id
Salvaged from #59742 (downloads half only). Main already resolves the event-level team id from the channel→workspace cache before downloads (the file-EVENT half was covered by #30456), but when neither the event nor the cache knows the workspace, both download helpers silently fell back to the PRIMARY workspace token — Slack then returns an HTML login page instead of file bytes for any non-primary workspace file. Slack private file URLs embed the owning workspace id (files-pri/<TEAM_ID>-<FILE_ID>/...), so _resolve_download_token now prefers: explicit team_id -> URL-embedded team id -> primary token. Both _download_slack_file and _download_slack_file_bytes route through it. Deferred from #59742 (out of this correctness cluster's scope): the channel→team disk persistence, the pre-send conversations.info probe loop, and the thread-file ingestion feature. Reapplied from #59742 by @benjamin2026-dot onto the current adapter (original targeted the pre-#30456 download sites).
This commit is contained in:
parent
c1c991ae9e
commit
ca8aee87e8
1 changed files with 27 additions and 10 deletions
|
|
@ -7879,6 +7879,31 @@ class SlackAdapter(BasePlatformAdapter):
|
|||
cls._SLACK_CDN_HOST_SUFFIXES
|
||||
)
|
||||
|
||||
def _resolve_download_token(self, url: str, team_id: str = "") -> str:
|
||||
"""Pick the correct bot token for a Slack file download.
|
||||
|
||||
Order of preference:
|
||||
1. Explicit team_id that maps to a known workspace client.
|
||||
2. team_id parsed from the file URL itself — Slack private file URLs
|
||||
embed the workspace id as ``files-pri/<TEAM_ID>-<FILE_ID>/...`` so
|
||||
we can route to the right workspace even when the triggering event
|
||||
carried no team info (thread replies / mentions in multi-workspace
|
||||
installs). This prevents defaulting to the primary workspace token,
|
||||
which makes Slack return an HTML login page instead of file bytes.
|
||||
3. Primary workspace token as a last resort.
|
||||
"""
|
||||
if team_id and team_id in self._team_clients:
|
||||
return self._team_clients[team_id].token
|
||||
try:
|
||||
m = re.search(r"/files-pri/(T[A-Z0-9]+)-", url or "")
|
||||
if m:
|
||||
url_team = m.group(1)
|
||||
if url_team in self._team_clients:
|
||||
return self._team_clients[url_team].token
|
||||
except Exception: # pragma: no cover - defensive
|
||||
pass
|
||||
return self.config.token or ""
|
||||
|
||||
async def _download_slack_file(
|
||||
self, url: str, ext: str, audio: bool = False, team_id: str = ""
|
||||
) -> str:
|
||||
|
|
@ -7909,11 +7934,7 @@ class SlackAdapter(BasePlatformAdapter):
|
|||
f"{safe_url_for_log(url)}"
|
||||
)
|
||||
|
||||
bot_token = (
|
||||
self._team_clients[team_id].token
|
||||
if team_id and team_id in self._team_clients
|
||||
else self.config.token
|
||||
)
|
||||
bot_token = self._resolve_download_token(url, team_id)
|
||||
|
||||
# DNS-pinned client: resolve + validate once, dial the vetted IP
|
||||
# (closes the DNS-rebinding TOCTOU window between is_safe_url and
|
||||
|
|
@ -7989,11 +8010,7 @@ class SlackAdapter(BasePlatformAdapter):
|
|||
f"{safe_url_for_log(url)}"
|
||||
)
|
||||
|
||||
bot_token = (
|
||||
self._team_clients[team_id].token
|
||||
if team_id and team_id in self._team_clients
|
||||
else self.config.token
|
||||
)
|
||||
bot_token = self._resolve_download_token(url, team_id)
|
||||
|
||||
# DNS-pinned client: resolve + validate once, dial the vetted IP
|
||||
# (closes the DNS-rebinding TOCTOU window between is_safe_url and
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue