from __future__ import annotations import os from dataclasses import dataclass @dataclass class SlackCredentials: account_id: str = "default" bot_token: str = "" app_token: str = "" user_token: str = "" signing_secret: str = "" bot_token_source: str = "none" app_token_source: str = "none" user_token_source: str = "none" signing_secret_source: str = "none" @classmethod def from_config(cls, account_id: str, config: dict[str, str]) -> SlackCredentials: creds = cls(account_id=account_id) creds.bot_token = config.get("bot_token", "") creds.app_token = config.get("app_token", "") creds.user_token = config.get("user_token", "") creds.signing_secret = config.get("signing_secret", "") if creds.bot_token: creds.bot_token_source = "config" else: creds.bot_token = os.getenv("SLACK_BOT_TOKEN", "") creds.bot_token_source = "env" if creds.bot_token else "none" if creds.app_token: creds.app_token_source = "config" else: creds.app_token = os.getenv("SLACK_APP_TOKEN", "") creds.app_token_source = "env" if creds.app_token else "none" if creds.user_token: creds.user_token_source = "config" else: creds.user_token = os.getenv("SLACK_USER_TOKEN", "") creds.user_token_source = "env" if creds.user_token else "none" if creds.signing_secret: creds.signing_secret_source = "config" else: creds.signing_secret = os.getenv("SLACK_SIGNING_SECRET", "") creds.signing_secret_source = "env" if creds.signing_secret else "none" return creds @classmethod def from_env(cls, account_id: str = "default") -> SlackCredentials: creds = cls(account_id=account_id) creds.bot_token = os.getenv("SLACK_BOT_TOKEN", "") creds.app_token = os.getenv("SLACK_APP_TOKEN", "") creds.user_token = os.getenv("SLACK_USER_TOKEN", "") creds.signing_secret = os.getenv("SLACK_SIGNING_SECRET", "") creds.bot_token_source = "env" if creds.bot_token else "none" creds.app_token_source = "env" if creds.app_token else "none" creds.user_token_source = "env" if creds.user_token else "none" creds.signing_secret_source = "env" if creds.signing_secret else "none" return creds def validate(self) -> list[str]: errors: list[str] = [] if self.bot_token and not self.bot_token.startswith("xoxb-"): errors.append(f"bot_token must start with 'xoxb-', got: {self.bot_token[:5]}...") if self.app_token and not self.app_token.startswith("xapp-"): errors.append(f"app_token must start with 'xapp-', got: {self.app_token[:5]}...") if self.user_token and not self.user_token.startswith("xoxp-"): errors.append(f"user_token must start with 'xoxp-', got: {self.user_token[:5]}...") return errors def to_dict(self) -> dict[str, str]: return { "account_id": self.account_id, "bot_token_source": self.bot_token_source, "app_token_source": self.app_token_source, "user_token_source": self.user_token_source, "signing_secret_source": self.signing_secret_source, }