From 153ccbfd614f5e1709897e39b1a7e8e54edb12dc Mon Sep 17 00:00:00 2001 From: teknium1 Date: Fri, 13 Mar 2026 09:35:39 -0700 Subject: [PATCH] fix: strip user: prefix from Discord allowed user IDs in onboarding Users sometimes paste Discord IDs with prefixes like 'user:123456', '<@123456>', or '<@!123456>' from Discord's UI or third-party tools. This caused auth failures since the allowlist contained 'user:123' but the actual user_id from messages was just '123'. Fixes: - Added _clean_discord_id() helper in discord.py to strip common prefixes - Applied sanitization at runtime when parsing DISCORD_ALLOWED_USERS env var - Applied sanitization in hermes setup and hermes gateway setup input flows - Handles user:, <@>, and <@!> prefix formats --- gateway/platforms/discord.py | 20 +++++++++++++++++++- hermes_cli/gateway.py | 12 ++++++++++++ hermes_cli/setup.py | 24 ++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/gateway/platforms/discord.py b/gateway/platforms/discord.py index 257756ad..e68e5292 100644 --- a/gateway/platforms/discord.py +++ b/gateway/platforms/discord.py @@ -43,6 +43,23 @@ from gateway.platforms.base import ( ) +def _clean_discord_id(entry: str) -> str: + """Strip common prefixes from a Discord user ID or username entry. + + Users sometimes paste IDs with prefixes like ``user:123``, ``<@123>``, + or ``<@!123>`` from Discord's UI or other tools. This normalises the + entry to just the bare ID or username. + """ + entry = entry.strip() + # Strip Discord mention syntax: <@123> or <@!123> + if entry.startswith("<@") and entry.endswith(">"): + entry = entry.lstrip("<@!").rstrip(">") + # Strip "user:" prefix (seen in some Discord tools / onboarding pastes) + if entry.lower().startswith("user:"): + entry = entry[5:] + return entry.strip() + + def check_discord_requirements() -> bool: """Check if Discord dependencies are available.""" return DISCORD_AVAILABLE @@ -99,7 +116,8 @@ class DiscordAdapter(BasePlatformAdapter): allowed_env = os.getenv("DISCORD_ALLOWED_USERS", "") if allowed_env: self._allowed_user_ids = { - uid.strip() for uid in allowed_env.split(",") if uid.strip() + _clean_discord_id(uid) for uid in allowed_env.split(",") + if uid.strip() } adapter_self = self # capture for closure diff --git a/hermes_cli/gateway.py b/hermes_cli/gateway.py index 26a8f598..5ba2f64b 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -623,6 +623,18 @@ def _setup_standard_platform(platform: dict): value = prompt(f" {var['prompt']}", password=False) if value: cleaned = value.replace(" ", "") + # For Discord, strip common prefixes (user:123, <@123>, <@!123>) + if "DISCORD" in var["name"]: + parts = [] + for uid in cleaned.split(","): + uid = uid.strip() + if uid.startswith("<@") and uid.endswith(">"): + uid = uid.lstrip("<@!").rstrip(">") + if uid.lower().startswith("user:"): + uid = uid[5:] + if uid: + parts.append(uid) + cleaned = ",".join(parts) save_env_value(var["name"], cleaned) print_success(f" Saved — only these users can interact with the bot.") allowed_val_set = cleaned diff --git a/hermes_cli/setup.py b/hermes_cli/setup.py index baff9e6e..b2e53c87 100644 --- a/hermes_cli/setup.py +++ b/hermes_cli/setup.py @@ -1935,7 +1935,17 @@ def setup_gateway(config: dict): "Allowed user IDs or usernames (comma-separated, leave empty for open access)" ) if allowed_users: - save_env_value("DISCORD_ALLOWED_USERS", allowed_users.replace(" ", "")) + # Clean up common prefixes (user:123, <@123>, <@!123>) + cleaned_ids = [] + for uid in allowed_users.replace(" ", "").split(","): + uid = uid.strip() + if uid.startswith("<@") and uid.endswith(">"): + uid = uid.lstrip("<@!").rstrip(">") + if uid.lower().startswith("user:"): + uid = uid[5:] + if uid: + cleaned_ids.append(uid) + save_env_value("DISCORD_ALLOWED_USERS", ",".join(cleaned_ids)) print_success("Discord allowlist configured") else: print_info( @@ -1970,8 +1980,18 @@ def setup_gateway(config: dict): ) allowed_users = prompt("Allowed user IDs (comma-separated)") if allowed_users: + # Clean up common prefixes (user:123, <@123>, <@!123>) + cleaned_ids = [] + for uid in allowed_users.replace(" ", "").split(","): + uid = uid.strip() + if uid.startswith("<@") and uid.endswith(">"): + uid = uid.lstrip("<@!").rstrip(">") + if uid.lower().startswith("user:"): + uid = uid[5:] + if uid: + cleaned_ids.append(uid) save_env_value( - "DISCORD_ALLOWED_USERS", allowed_users.replace(" ", "") + "DISCORD_ALLOWED_USERS", ",".join(cleaned_ids) ) print_success("Discord allowlist configured")