[
  {
    "path": "README.md",
    "content": "# Dawn Extension Bot [1.5]\n# 原作者https://github.com/Jaammerr/The-Dawn-Bot 防止正义人士\n<div align=\"center\">\n  <img src=\"./console/1.png\" alt=\"Dawn Extension Bot Console\" width=\"600\"/>\n</div>\n\n\n**我的推特: [@Hy78516012，如果觉得有用请给我点个关注吧)**\n\n\n---\n\n## 🚀 功能\n\n- ✅ 自动账户注册和登录\n- 📧 自动账户重新验证\n- 🌾 自动完成所有任务\n- 💰 自动获取积分\n- 📊 导出账户统计数据\n- 🔄 保持会话功能\n- 🧩 高级跳码\n\n---\n\n## 💻 环境及需要的账户\n\n- Python >= 3.11\n- 安装Python虚拟环境\n- 能注册DAWN的邮箱号\n- 代理IP（可选）\n\n---\n\n## 🛠️ 设置\n\n1. 克隆仓库：\n   ```bash\n   git clone https://github.com/GzGod/Dawn\n   ```\n2. 创建并激活虚拟环境：\n   ```bash\n   Windows系统：\n   python -m venv venv\n   cd venv/Scripts\n   activate\n   Linux（服务器）：\n   python3 -m venv venv\n   cd venv/bin\n   source activate\n   cd ../..\n   ```\n3. 安装依赖：\n   ```bash\n   pip install -r requirements.txt\n   ```\n\n---\n\n## ⚙️ 配置\n\n### settings.yaml\n\n该文件包含机器人的常规设置：\n\n```yaml\nthreads: 5 # 同时进行账户操作的线程数\nkeepalive_interval: 120 # 保持会话请求之间的延迟（秒）\nreferral_code: \"YOUR_REFERRAL_CODE\" # 注册推荐码\ncaptcha_service: \"2captcha\" # 验证码解决服务（2captcha或anticaptcha都可以）\ntwo_captcha_api_key: \"YOUR_2CAPTCHA_API_KEY\"\nanti_captcha_api_key: \"YOUR_ANTICAPTCHA_API_KEY\"\n\nimap_settings: # 电子邮件提供商的IMAP设置\n  gmail.com: imap.gmail.com\n  outlook.com: imap-mail.outlook.com\n  # 根据需要添加更多电子邮件提供商\n```\n\n### 其他配置文件\n\n#### 📁 register.txt\n包含注册账户信息。注意 这里的邮箱的password需要的是imap授权码，小白不建议用这种\n老老实实注册然后填在farm.txt即可\n```\n格式：\nemail:password\nemail:password\n...\n```\n\n#### 📁 farm.txt\n包含用于获取积分和完成任务的账户信息。\n```\n格式：\nemail:password\nemail:password\n...\n```\n\n#### 📁 proxies.txt\n包含代理信息。\n```\n格式：\nhttp://user:pass@ip:port\nhttp://ip:port:user:pass\nhttp://ip:port@user:pass\nhttp://user:pass:ip:port\n...\n```\n\n---\n\n## 🚀 使用\n\n1. 确保所有配置文件已正确设置。\n2. 运行机器人：\n   ```bash\n   python run.py\n   ```\n\n---\n\n## ⚠️ 重要提示\n\n- 建议的保持会话请求之间的延迟为120秒。\n- 如果有未验证的账户，可以再次使用`register`模块重新验证。\n- 由于验证码复杂性的变化，现在使用外部服务（2captcha，anti-captcha）来解决验证码。\n- 使用数据库来优化登录过程，通过存储授权令牌。\n- 对于像Gmail这样的电子邮件服务，可能需要使用应用程序专用密码而不是常规电子邮件密码。\n\n---\n\n## 🔧 问题排查\n\n- **Email Verification Issues**：检查`settings.yaml`中的电子邮件提供商IMAP设置。\n- **Captcha Problems**：验证您的验证码服务API密钥和账户余额。\n- **Proxy Issues**：确保您的代理格式正确且代理功能正常。\n\n---\n"
  },
  {
    "path": "config/data/farm.txt",
    "content": "test@gmail.com:password"
  },
  {
    "path": "config/data/proxies.txt",
    "content": "http://proxy"
  },
  {
    "path": "config/data/register.txt",
    "content": "test@gmail.com:password"
  },
  {
    "path": "config/settings.yaml",
    "content": "# Application Configuration File\n# =============================\n\n# Core Settings\n# ------------\nthreads: 10                    # Number of concurrent threads to run (minimum: 1)\nkeepalive_interval: 120        # How often to send keepalive signal (in seconds)\nreferral_code: \"hegbhf\"        # Your referral code for the application\n\n# Captcha Settings\n# ---------------\ncaptcha_module: 2captcha       # Captcha service to use: '2captcha' or 'anticaptcha'\ntwo_captcha_api_key: \"\"        # API key for 2captcha service\nanti_captcha_api_key: \"\"       # API key for anti-captcha service\n\n# Startup Delay Configuration\n# -------------------------\ndelay_before_start:\n  min: 2                       # Minimum delay before starting (seconds)\n  max: 3                       # Maximum delay before starting (seconds)\n\n# Email Provider IMAP Settings\n# --------------------------\nimap_settings:\n  # Common email providers and their IMAP servers\n  gmail.com: imap.gmail.com          # Google Mail\n  yahoo.com: imap.mail.yahoo.com     # Yahoo Mail\n  outlook.com: imap-mail.outlook.com  # Microsoft Outlook\n  hotmail.com: imap-mail.outlook.com  # Microsoft Hotmail\n  mail.ru: imap.mail.ru              # Mail.ru\n  rambler.ru: imap.rambler.ru        # Rambler\n  gmx.com: imap.gmx.com              # GMX Mail\n  gmx.net: imap.gmx.net             # GMX Germany\n  gmx.de: imap.gmx.net              # GMX Germany (alternate domain)"
  },
  {
    "path": "console/__init__.py",
    "content": "from .main import Console\n"
  },
  {
    "path": "console/logger.py",
    "content": "from colorama import Fore\n\n\ndef error_log(message: str):\n    print(Fore.RED + \">> ERROR |\" + Fore.LIGHTBLACK_EX + f\" {message}\")\n\n\ndef success_log(message: str):\n    print(Fore.GREEN + \">> SUCCESS |\" + Fore.LIGHTBLACK_EX + f\" {message}\")\n\n\ndef info_log(message: str):\n    print(Fore.LIGHTBLACK_EX + f\">> INFO | {message}\")\n"
  },
  {
    "path": "console/main.py",
    "content": "import os\nimport sys\nimport inquirer\n\nfrom inquirer.themes import GreenPassion\nfrom art import text2art\nfrom colorama import Fore\nfrom loader import config\n\nfrom rich.console import Console as RichConsole\nfrom rich.panel import Panel\nfrom rich.table import Table\nfrom rich import box\nfrom rich.text import Text\n\nsys.path.append(os.path.realpath(\".\"))\n\n\nclass Console:\n    MODULES = (\n        \"Register\",\n        \"Farm\",\n        \"Complete tasks\",\n        \"Export statistics\",\n        \"Exit\",\n    )\n    MODULES_DATA = {\n        \"Register\": \"register\",\n        \"Farm\": \"farm\",\n        \"Exit\": \"exit\",\n        \"Export statistics\": \"export_stats\",\n        \"Complete tasks\": \"complete_tasks\",\n    }\n\n    def __init__(self):\n        self.rich_console = RichConsole()\n\n    def show_dev_info(self):\n        os.system(\"cls\" if os.name == \"nt\" else \"clear\")\n\n        title = text2art(\"JamBit\", font=\"small\")\n        styled_title = Text(title, style=\"bold cyan\")\n\n        version = Text(\"VERSION: 1.5\", style=\"blue\")\n        telegram = Text(\"我的推特主页: https://x.com/Hy78516012\", style=\"green\")\n        github = Text(\"我的GitHub: https://github.com/Gzgod\", style=\"green\")\n\n        dev_panel = Panel(\n            Text.assemble(styled_title, \"\\n\", version, \"\\n\", telegram, \"\\n\", github),\n            border_style=\"yellow\",\n            expand=False,\n            title=\"[bold green]Welcome[/bold green]\",\n            subtitle=\"[italic]Powered by Jammer[/italic]\",\n        )\n\n        self.rich_console.print(dev_panel)\n        print()\n\n    @staticmethod\n    def prompt(data: list):\n        answers = inquirer.prompt(data, theme=GreenPassion())\n        return answers\n\n    def get_module(self):\n        questions = [\n            inquirer.List(\n                \"module\",\n                message=Fore.LIGHTBLACK_EX + \"Select the module\",\n                choices=self.MODULES,\n            ),\n        ]\n\n        answers = self.prompt(questions)\n        return answers.get(\"module\")\n\n    def display_info(self):\n        table = Table(title=\"Dawn Configuration\", box=box.ROUNDED)\n        table.add_column(\"Parameter\", style=\"cyan\")\n        table.add_column(\"Value\", style=\"magenta\")\n\n        table.add_row(\"Accounts to register\", str(len(config.accounts_to_register)))\n        table.add_row(\"Accounts to farm\", str(len(config.accounts_to_farm)))\n        table.add_row(\"Threads\", str(config.threads))\n        table.add_row(\n            \"Delay before start\",\n            f\"{config.delay_before_start.min} - {config.delay_before_start.max} sec\",\n        )\n\n        panel = Panel(\n            table,\n            expand=False,\n            border_style=\"green\",\n            title=\"[bold yellow]System Information[/bold yellow]\",\n            subtitle=\"[italic]Use arrow keys to navigate[/italic]\",\n        )\n        self.rich_console.print(panel)\n\n    def build(self) -> None:\n        self.show_dev_info()\n        self.display_info()\n\n        module = self.get_module()\n        config.module = self.MODULES_DATA[module]\n\n        if config.module == \"exit\":\n            exit(0)\n"
  },
  {
    "path": "core/api.py",
    "content": "import asyncio\nimport json\nimport names\n\nfrom datetime import datetime, timezone\nfrom typing import Literal, Tuple, Any\nfrom curl_cffi.requests import AsyncSession\n\nfrom models import Account\nfrom .exceptions.base import APIError, SessionRateLimited, ServerError\nfrom loader import captcha_solver, config\n\n\nclass DawnExtensionAPI:\n    API_URL = \"https://www.aeropres.in/chromeapi/dawn\"\n\n    def __init__(self, account: Account):\n        self.account_data = account\n        self.wallet_data: dict[str, Any] = {}\n        self.session = self.setup_session()\n\n    def setup_session(self) -> AsyncSession:\n        session = AsyncSession(impersonate=\"chrome124\", verify=False)\n        session.timeout = 30\n        session.headers = {\n            \"accept\": \"*/*\",\n            \"accept-language\": \"en-US,en;q=0.9\",\n            \"origin\": \"chrome-extension://fpdkjdnhkakefebpekbdhillbhonfjjp\",\n            \"priority\": \"u=1, i\",\n            \"user-agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36\",\n        }\n\n        if self.account_data.proxy:\n            session.proxies = {\n                \"http\": self.account_data.proxy.as_url,\n                \"https\": self.account_data.proxy.as_url,\n            }\n\n        return session\n\n    async def clear_request(self, url: str):\n        session = AsyncSession(impersonate=\"chrome124\", verify=False, timeout=30)\n        session.proxies = self.session.proxies\n\n        response = await session.get(url)\n        return response\n\n    async def send_request(\n        self,\n        request_type: Literal[\"POST\", \"GET\", \"OPTIONS\"] = \"POST\",\n        method: str = None,\n        json_data: dict = None,\n        params: dict = None,\n        url: str = None,\n        headers: dict = None,\n        cookies: dict = None,\n        verify: bool = True,\n        max_retries: int = 3,\n        retry_delay: float = 3.0,\n    ):\n        def verify_response(response_data: dict | list) -> dict | list:\n            if \"status\" in str(response_data):\n                if isinstance(response_data, dict):\n                    if response_data.get(\"status\") is False:\n                        raise APIError(\n                            f\"API returned an error: {response_data}\", response_data\n                        )\n\n            elif \"success\" in str(response_data):\n                if isinstance(response_data, dict):\n                    if response_data.get(\"success\") is False:\n                        raise APIError(\n                            f\"API returned an error: {response_data}\", response_data\n                        )\n\n            return response_data\n\n        for attempt in range(max_retries):\n            try:\n                if request_type == \"POST\":\n                    if not url:\n                        response = await self.session.post(\n                            f\"{self.API_URL}{method}\",\n                            json=json_data,\n                            params=params,\n                            headers=headers if headers else self.session.headers,\n                            cookies=cookies,\n                        )\n                    else:\n                        response = await self.session.post(\n                            url,\n                            json=json_data,\n                            params=params,\n                            headers=headers if headers else self.session.headers,\n                            cookies=cookies,\n                        )\n                elif request_type == \"OPTIONS\":\n                    response = await self.session.options(\n                        url,\n                        headers=headers if headers else self.session.headers,\n                        cookies=cookies,\n                    )\n                else:\n                    if not url:\n                        response = await self.session.get(\n                            f\"{self.API_URL}{method}\",\n                            params=params,\n                            headers=headers if headers else self.session.headers,\n                            cookies=cookies,\n                        )\n                    else:\n                        response = await self.session.get(\n                            url,\n                            params=params,\n                            headers=headers if headers else self.session.headers,\n                            cookies=cookies,\n                        )\n\n                if verify:\n\n                    if response.status_code == 403:\n                        raise SessionRateLimited(\"Session is rate limited\")\n\n                    if response.status_code in (500, 502, 503, 504):\n                        raise ServerError(f\"Server error - {response.status_code}\")\n\n                    try:\n                        return verify_response(response.json())\n                    except json.JSONDecodeError:\n                        return response.text\n\n                return response.text\n\n            except ServerError as error:\n                if attempt == max_retries - 1:\n                    raise error\n                await asyncio.sleep(retry_delay)\n\n\n            except APIError:\n                raise\n\n            except SessionRateLimited:\n                raise\n\n            except Exception as error:\n                if attempt == max_retries - 1:\n                    raise ServerError(\n                        f\"Failed to send request after {max_retries} attempts: {error}\"\n                    )\n                await asyncio.sleep(retry_delay)\n\n        raise ServerError(f\"Failed to send request after {max_retries} attempts\")\n\n    @staticmethod\n    async def solve_puzzle(\n        image: str,\n    ) -> Tuple[str | int, bool, str | int] | Tuple[str, bool] | Tuple[str, bool, str]:\n        response = await captcha_solver.solve(image)\n        return response\n\n    @staticmethod\n    async def report_invalid_puzzle(task_id: int | str) -> None:\n        await captcha_solver.report_bad(task_id)\n\n    async def get_puzzle_id(self) -> str:\n        if \"Berear\" in self.session.headers:\n            del self.session.headers[\"Berear\"]\n            self.session.cookies.clear()\n\n        params = {\n            'appid': 'undefined',\n        }\n\n        response = await self.send_request(\n            method=\"/v1/puzzle/get-puzzle\",\n            request_type=\"GET\",\n            params=params,\n        )\n        return response[\"puzzle_id\"]\n\n    async def get_puzzle_image(self, puzzle_id: str) -> str:\n        response = await self.send_request(\n            method=\"/v1/puzzle/get-puzzle-image\",\n            request_type=\"GET\",\n            params={\"puzzle_id\": puzzle_id, \"appid\": \"undefined\"},\n        )\n\n        return response.get(\"imgBase64\")\n\n    async def register(self, puzzle_id: str, answer: str) -> dict:\n        json_data = {\n            \"firstname\": names.get_first_name(),\n            \"lastname\": names.get_last_name(),\n            \"email\": self.account_data.email,\n            \"mobile\": \"\",\n            \"password\": self.account_data.password,\n            \"country\": \"+91\",\n            \"referralCode\": config.referral_code,\n            \"puzzle_id\": puzzle_id,\n            \"ans\": answer,\n        }\n\n        return await self.send_request(\n            method=\"/v1/puzzle/validate-register\",\n            json_data=json_data,\n        )\n\n    async def keepalive(self) -> dict | str:\n        headers = {\n            \"accept\": \"*/*\",\n            \"accept-language\": \"en-US,en;q=0.9,ru;q=0.8\",\n            \"authorization\": f'Berear {self.session.headers[\"Berear\"]}',\n            \"content-type\": \"application/json\",\n            \"origin\": \"chrome-extension://fpdkjdnhkakefebpekbdhillbhonfjjp\",\n            \"user-agent\": self.session.headers[\"user-agent\"],\n        }\n\n        json_data = {\n            \"username\": self.account_data.email,\n            \"extensionid\": \"fpdkjdnhkakefebpekbdhillbhonfjjp\",\n            \"numberoftabs\": 0,\n            \"_v\": \"1.0.9\",\n        }\n\n        params = {\n            'appid': 'undefined',\n        }\n\n        return await self.send_request(\n            method=\"/v1/userreward/keepalive\",\n            json_data=json_data,\n            verify=False,\n            headers=headers,\n            params=params,\n        )\n\n    async def user_info(self) -> dict:\n        headers = self.session.headers.copy()\n        headers[\"authorization\"] = f'Berear {self.session.headers[\"Berear\"]}'\n        headers[\"content-type\"] = \"application/json\"\n        del headers[\"Berear\"]\n\n        params = {\n            'appid': 'undefined',\n        }\n\n        response = await self.send_request(\n            url=\"https://www.aeropres.in/api/atom/v1/userreferral/getpoint\",\n            request_type=\"GET\",\n            headers=headers,\n            params=params,\n        )\n\n        return response[\"data\"]\n\n    async def complete_tasks(self, tasks: list[str] = None, delay: int = 1) -> None:\n        if not tasks:\n            tasks = [\"telegramid\", \"discordid\", \"twitter_x_id\"]\n\n        headers = self.session.headers.copy()\n        headers[\"authorization\"] = f'Brearer {self.session.headers[\"Berear\"]}'\n        headers[\"content-type\"] = \"application/json\"\n        del headers[\"Berear\"]\n\n        for task in tasks:\n            json_data = {\n                task: task,\n            }\n\n            await self.send_request(\n                method=\"/v1/profile/update\",\n                json_data=json_data,\n                headers=headers,\n            )\n\n            await asyncio.sleep(delay)\n\n    async def verify_session(self) -> tuple[bool, str]:\n        try:\n            await self.user_info()\n            return True, \"Session is valid\"\n\n        except ServerError:\n            return True, \"Server error\"\n\n        except APIError as error:\n            return False, str(error)\n\n    async def login(self, puzzle_id: str, answer: str):\n        current_time = datetime.now(timezone.utc)\n        formatted_datetime_str = (\n            current_time.strftime(\"%Y-%m-%dT%H:%M:%S.%f\")[:-3] + \"Z\"\n        )\n\n        params = {\n            'appid': 'undefined',\n        }\n\n        json_data = {\n            \"username\": self.account_data.email,\n            \"password\": self.account_data.password,\n            \"logindata\": {\n                \"_v\": \"1.0.9\",\n                \"datetime\": formatted_datetime_str,\n            },\n            \"puzzle_id\": puzzle_id,\n            \"ans\": answer,\n        }\n\n        response = await self.send_request(\n            method=\"/v1/user/login/v2\",\n            json_data=json_data,\n            params=params,\n        )\n\n        berear = response.get(\"data\", {}).get(\"token\")\n        if berear:\n            self.wallet_data = response.get(\"data\", {}).get(\"wallet\")\n            self.session.headers.update({\"Berear\": berear})\n        else:\n            raise APIError(f\"Failed to login: {response}\")\n"
  },
  {
    "path": "core/bot.py",
    "content": "from datetime import datetime, timedelta\nfrom typing import Tuple, Any, Optional\n\nimport pytz\nfrom loguru import logger\nfrom loader import config, file_operations\nfrom models import Account, OperationResult, StatisticData\n\nfrom .api import DawnExtensionAPI\nfrom utils import check_email_for_link, check_if_email_valid\nfrom database import Accounts\nfrom .exceptions.base import APIError, SessionRateLimited, CaptchaSolvingFailed\n\n\nclass Bot(DawnExtensionAPI):\n    def __init__(self, account: Account):\n        super().__init__(account)\n\n    async def get_captcha_data(self) -> Tuple[str, Any, Optional[Any]]:\n        for _ in range(5):\n            try:\n                puzzle_id = await self.get_puzzle_id()\n                image = await self.get_puzzle_image(puzzle_id)\n\n                logger.info(\n                    f\"Account: {self.account_data.email} | Got puzzle image, solving...\"\n                )\n                answer, solved, *rest = await self.solve_puzzle(image)\n\n                if solved and len(answer) == 6:\n                    logger.success(\n                        f\"Account: {self.account_data.email} | Puzzle solved: {answer}\"\n                    )\n                    return puzzle_id, answer, rest[0] if rest else None\n\n                if len(answer) != 6 and rest:\n                    await self.report_invalid_puzzle(rest[0])\n\n                logger.error(\n                    f\"Account: {self.account_data.email} | Failed to solve puzzle: Incorrect answer | Retrying...\"\n                )\n\n            except SessionRateLimited:\n                raise\n\n            except Exception as e:\n                logger.error(\n                    f\"Account: {self.account_data.email} | Error occurred while solving captcha: {str(e)} | Retrying...\"\n                )\n\n        raise CaptchaSolvingFailed(\"Failed to solve captcha after 5 attempts\")\n\n    async def clear_account_and_session(self) -> None:\n        if await Accounts.get_account(email=self.account_data.email):\n            await Accounts.delete_account(email=self.account_data.email)\n        self.session = self.setup_session()\n\n    async def process_reverify_email(self) -> OperationResult:\n        await self.clear_account_and_session()\n\n        try:\n            confirm_url = await check_email_for_link(\n                imap_server=self.account_data.imap_server,\n                email=self.account_data.email,\n                password=self.account_data.password,\n            )\n\n            if confirm_url is None:\n                logger.error(\n                    f\"Account: {self.account_data.email} | Confirmation link not found\"\n                )\n                return OperationResult(\n                    identifier=self.account_data.email,\n                    data=self.account_data.password,\n                    status=False,\n                )\n\n            logger.success(\n                f\"Account: {self.account_data.email} | Link found, confirming registration...\"\n            )\n            response = await self.clear_request(url=confirm_url)\n            if response.status_code == 200:\n                logger.success(\n                    f\"Account: {self.account_data.email} | Successfully confirmed registration\"\n                )\n                return OperationResult(\n                    identifier=self.account_data.email,\n                    data=self.account_data.password,\n                    status=True,\n                )\n\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to confirm registration\"\n            )\n\n        except Exception as error:\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to reverify email: {error}\"\n            )\n\n        return OperationResult(\n            identifier=self.account_data.email,\n            data=self.account_data.password,\n            status=False,\n        )\n\n\n    async def process_registration(self) -> OperationResult:\n        task_id = None\n\n        try:\n            if not await check_if_email_valid(\n                self.account_data.imap_server,\n                self.account_data.email,\n                self.account_data.password,\n            ):\n                logger.error(f\"Account: {self.account_data.email} | Invalid email\")\n                return OperationResult(\n                    identifier=self.account_data.email,\n                    data=self.account_data.password,\n                    status=False,\n                )\n\n            logger.info(f\"Account: {self.account_data.email} | Registering...\")\n            puzzle_id, answer, task_id = await self.get_captcha_data()\n\n            await self.register(puzzle_id, answer)\n            logger.info(\n                f\"Account: {self.account_data.email} | Successfully registered, waiting for email...\"\n            )\n\n            confirm_url = await check_email_for_link(\n                imap_server=self.account_data.imap_server,\n                email=self.account_data.email,\n                password=self.account_data.password,\n            )\n\n            if confirm_url is None:\n                logger.error(\n                    f\"Account: {self.account_data.email} | Confirmation link not found\"\n                )\n                return OperationResult(\n                    identifier=self.account_data.email,\n                    data=self.account_data.password,\n                    status=False,\n                )\n\n            logger.success(\n                f\"Account: {self.account_data.email} | Link found, confirming registration...\"\n            )\n            response = await self.clear_request(url=confirm_url)\n            if response.status_code == 200:\n                logger.success(\n                    f\"Account: {self.account_data.email} | Successfully confirmed registration\"\n                )\n                return OperationResult(\n                    identifier=self.account_data.email,\n                    data=self.account_data.password,\n                    status=True,\n                )\n\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to confirm registration\"\n            )\n\n        except APIError as error:\n            if error.error_message in error.BASE_MESSAGES:\n                if error.error_message == \"Incorrect answer. Try again!\":\n                    logger.warning(\n                        f\"Account: {self.account_data.email} | Captcha answer incorrect, re-solving...\"\n                    )\n                    if task_id:\n                        await self.report_invalid_puzzle(task_id)\n\n                elif error.error_message == \"email already exists\":\n                    logger.warning(f\"Account: {self.account_data.email} | Email already exists, re-verifying...\")\n                    return await self.process_reverify_email()\n\n                else:\n                    logger.warning(\n                        f\"Account: {self.account_data.email} | Captcha expired, re-solving...\"\n                    )\n                return await self.process_registration()\n\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to register: {error}\"\n            )\n\n        except Exception as error:\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to register: {error}\"\n            )\n\n        return OperationResult(\n            identifier=self.account_data.email,\n            data=self.account_data.password,\n            status=False,\n        )\n\n    @staticmethod\n    def get_sleep_until(blocked: bool = False) -> datetime:\n        duration = (\n            timedelta(minutes=10)\n            if blocked\n            else timedelta(seconds=config.keepalive_interval)\n        )\n        return datetime.now(pytz.UTC) + duration\n\n    async def process_farming(self) -> None:\n        try:\n            db_account_data = await Accounts.get_account(email=self.account_data.email)\n\n            if db_account_data and db_account_data.session_blocked_until:\n                if await self.handle_sleep(db_account_data.session_blocked_until):\n                    return\n\n            if not db_account_data or not db_account_data.headers:\n                if not await self.login_new_account():\n                    return\n\n            elif not await self.handle_existing_account(db_account_data):\n                return\n\n            await self.perform_farming_actions()\n\n        except SessionRateLimited:\n            await self.handle_session_blocked()\n\n        except APIError as error:\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to farm: {error}\"\n            )\n\n\n        except Exception as error:\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to farm: {error}\"\n            )\n\n        return\n\n    async def process_get_user_info(self) -> StatisticData:\n        try:\n            db_account_data = await Accounts.get_account(email=self.account_data.email)\n\n            if db_account_data and db_account_data.session_blocked_until:\n                if await self.handle_sleep(db_account_data.session_blocked_until):\n                    return StatisticData(\n                        success=False, referralPoint=None, rewardPoint=None\n                    )\n\n            if not db_account_data or not db_account_data.headers:\n                if not await self.login_new_account():\n                    return StatisticData(\n                        success=False, referralPoint=None, rewardPoint=None\n                    )\n\n            elif not await self.handle_existing_account(db_account_data):\n                return StatisticData(\n                    success=False, referralPoint=None, rewardPoint=None\n                )\n\n            user_info = await self.user_info()\n            logger.success(\n                f\"Account: {self.account_data.email} | Successfully got user info\"\n            )\n            return StatisticData(\n                success=True,\n                referralPoint=user_info[\"referralPoint\"],\n                rewardPoint=user_info[\"rewardPoint\"],\n            )\n\n        except SessionRateLimited:\n            await self.handle_session_blocked()\n        except APIError as error:\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to get user info: {error}\"\n            )\n        except Exception as error:\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to get user info: {error}\"\n            )\n\n        return StatisticData(success=False, referralPoint=None, rewardPoint=None)\n\n    async def process_complete_tasks(self) -> OperationResult:\n        try:\n            db_account_data = await Accounts.get_account(email=self.account_data.email)\n            if db_account_data is None:\n                if not await self.login_new_account():\n                    return OperationResult(\n                        identifier=self.account_data.email,\n                        data=self.account_data.password,\n                        status=False,\n                    )\n            else:\n                await self.handle_existing_account(db_account_data)\n\n            logger.info(f\"Account: {self.account_data.email} | Completing tasks...\")\n            await self.complete_tasks()\n\n            logger.success(\n                f\"Account: {self.account_data.email} | Successfully completed tasks\"\n            )\n            return OperationResult(\n                identifier=self.account_data.email,\n                data=self.account_data.password,\n                status=True,\n            )\n\n        except Exception as error:\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to complete tasks: {error}\"\n            )\n            return OperationResult(\n                identifier=self.account_data.email,\n                data=self.account_data.password,\n                status=False,\n            )\n\n    async def login_new_account(self):\n        task_id = None\n\n        try:\n            logger.info(f\"Account: {self.account_data.email} | Logging in...\")\n            puzzle_id, answer, task_id = await self.get_captcha_data()\n\n            await self.login(puzzle_id, answer)\n            logger.info(f\"Account: {self.account_data.email} | Successfully logged in\")\n\n            await Accounts.create_account(\n                email=self.account_data.email, headers=self.session.headers\n            )\n            return True\n\n        except APIError as error:\n            if error.error_message in error.BASE_MESSAGES:\n                if error.error_message == \"Incorrect answer. Try again!\":\n                    logger.warning(\n                        f\"Account: {self.account_data.email} | Captcha answer incorrect, re-solving...\"\n                    )\n                    if task_id:\n                        await self.report_invalid_puzzle(task_id)\n\n                elif error.error_message == \"Email not verified , Please check spam folder incase you did not get email\":\n                    logger.error(\n                        f\"Account: {self.account_data.email} | Email not verified, run registration process again\"\n                    )\n\n                    await file_operations.export_unverified_email(self.account_data.email, self.account_data.password)\n                    for account in config.accounts_to_farm:\n                        if account.email == self.account_data.email:\n                            config.accounts_to_farm.remove(account)\n\n                    return False\n\n                else:\n                    logger.warning(\n                        f\"Account: {self.account_data.email} | Captcha expired, re-solving...\"\n                    )\n\n                return await self.login_new_account()\n\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to login: {error}\"\n            )\n            return False\n\n        except CaptchaSolvingFailed:\n            sleep_until = self.get_sleep_until()\n            await Accounts.set_sleep_until(self.account_data.email, sleep_until)\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to solve captcha after 5 attempts, sleeping...\"\n            )\n            return False\n\n        except Exception as error:\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to login: {error}\"\n            )\n            return False\n\n    async def handle_existing_account(self, db_account_data) -> bool | None:\n        if db_account_data.sleep_until and await self.handle_sleep(\n            db_account_data.sleep_until\n        ):\n            return False\n\n        self.session.headers = db_account_data.headers\n        status, result = await self.verify_session()\n        if not status:\n            logger.warning(\n                f\"Account: {self.account_data.email} | Session is invalid, re-logging in: {result}\"\n            )\n            await self.clear_account_and_session()\n            return await self.process_farming()\n\n        logger.info(f\"Account: {self.account_data.email} | Using existing session\")\n        return True\n\n    async def handle_session_blocked(self):\n        await self.clear_account_and_session()\n        logger.error(\n            f\"Account: {self.account_data.email} | Session rate-limited | Sleeping...\"\n        )\n        sleep_until = self.get_sleep_until(blocked=True)\n        await Accounts.set_session_blocked_until(self.account_data.email, sleep_until)\n\n    async def handle_sleep(self, sleep_until):\n        current_time = datetime.now(pytz.UTC)\n        sleep_until = sleep_until.replace(tzinfo=pytz.UTC)\n\n        if sleep_until > current_time:\n            sleep_duration = (sleep_until - current_time).total_seconds()\n            logger.debug(\n                f\"Account: {self.account_data.email} | Sleeping until {sleep_until} (duration: {sleep_duration:.2f} seconds)\"\n            )\n            return True\n\n        return False\n\n    async def close_session(self):\n        try:\n            await self.session.close()\n        except Exception as error:\n            logger.debug(\n                f\"Account: {self.account_data.email} | Failed to close session: {error}\"\n            )\n\n    async def perform_farming_actions(self):\n        try:\n            await self.keepalive()\n            logger.success(\n                f\"Account: {self.account_data.email} | Sent keepalive request\"\n            )\n\n            user_info = await self.user_info()\n            logger.info(\n                f\"Account: {self.account_data.email} | Total points earned: {user_info['rewardPoint']['points']}\"\n            )\n\n        except Exception as error:\n            logger.error(\n                f\"Account: {self.account_data.email} | Failed to perform farming actions: {error}\"\n            )\n\n        finally:\n            new_sleep_until = self.get_sleep_until()\n            await Accounts.set_sleep_until(\n                email=self.account_data.email, sleep_until=new_sleep_until\n            )\n"
  },
  {
    "path": "core/exceptions/base.py",
    "content": "class APIError(Exception):\n    BASE_MESSAGES = [\"refresh your captcha!!\", \"Incorrect answer. Try again!\", \"Email not verified , Please check spam folder incase you did not get email\", \"email already exists\"]\n    \"\"\"Base class for API exceptions\"\"\"\n\n    def __init__(self, error: str, response_data: dict = None):\n        self.error = error\n        self.response_data = response_data\n\n    @property\n    def error_message(self) -> str:\n        if self.response_data and \"message\" in self.response_data:\n            return self.response_data[\"message\"]\n\n    def __str__(self):\n        return self.error\n\n\nclass SessionRateLimited(Exception):\n    \"\"\"Raised when the session is rate limited\"\"\"\n\n    pass\n\n\nclass CaptchaSolvingFailed(Exception):\n    \"\"\"Raised when the captcha solving failed\"\"\"\n\n    pass\n\n\nclass ServerError(APIError):\n    \"\"\"Raised when the server returns an error\"\"\"\n\n    pass\n"
  },
  {
    "path": "core/solvers/__init__.py",
    "content": "from .anti_captcha import AntiCaptchaImageSolver\nfrom .two_captcha import TwoCaptchaImageSolver\n"
  },
  {
    "path": "core/solvers/anti_captcha.py",
    "content": "import asyncio\nfrom typing import Any, Tuple\nimport httpx\n\n\nclass AntiCaptchaImageSolver:\n    BASE_URL = \"https://api.anti-captcha.com\"\n\n    def __init__(self, api_key: str):\n        self.api_key = api_key\n        self.client = httpx.AsyncClient(timeout=10)\n\n    async def solve(self, image: str) -> Tuple[str, bool]:\n        try:\n            captcha_data = {\n                \"clientKey\": self.api_key,\n                \"softId\": 1201,\n                \"task\": {\n                    \"type\": \"ImageToTextTask\",\n                    \"body\": image,\n                    \"phrase\": False,\n                    \"case\": True,\n                    \"numeric\": 0,\n                    \"math\": False,\n                    \"minLength\": 6,\n                    \"maxLength\": 6,\n                    \"comment\": \"Pay close attention to the letter case.\",\n                },\n            }\n\n            resp = await self.client.post(\n                f\"{self.BASE_URL}/createTask\", json=captcha_data\n            )\n            resp.raise_for_status()\n            data = resp.json()\n\n            if data.get(\"errorId\") == 0:\n                return await self.get_captcha_result(data.get(\"taskId\"))\n            return data.get(\"errorDescription\"), False\n\n        except httpx.HTTPStatusError as err:\n            return f\"HTTP error occurred: {err}\", False\n        except Exception as err:\n            return f\"An unexpected error occurred: {err}\", False\n\n    async def get_captcha_result(self, task_id: int | str) -> Tuple[Any, bool]:\n        for _ in range(10):\n            try:\n                resp = await self.client.post(\n                    f\"{self.BASE_URL}/getTaskResult\",\n                    json={\"clientKey\": self.api_key, \"taskId\": task_id},\n                )\n                resp.raise_for_status()\n                result = resp.json()\n\n                if result.get(\"errorId\") != 0:\n                    return result.get(\"errorDescription\"), False\n\n                if result.get(\"status\") == \"ready\":\n                    return result[\"solution\"].get(\"text\", \"\"), True\n\n                await asyncio.sleep(3)\n\n            except httpx.HTTPStatusError as err:\n                return f\"HTTP error occurred: {err}\", False\n            except Exception as err:\n                return f\"An unexpected error occurred: {err}\", False\n\n        return \"Max time for solving exhausted\", False\n\n    async def report_bad(self, task_id: int | str) -> Tuple[Any, bool]:\n        try:\n            resp = await self.client.post(\n                f\"{self.BASE_URL}/reportIncorrectImageCaptcha\",\n                json={\"clientKey\": self.api_key, \"taskId\": task_id},\n            )\n            resp.raise_for_status()\n            return resp.json(), True\n        except httpx.HTTPStatusError as err:\n            return f\"HTTP error occurred: {err}\", False\n        except Exception as err:\n            return f\"An unexpected error occurred: {err}\", False\n"
  },
  {
    "path": "core/solvers/two_captcha.py",
    "content": "import asyncio\nfrom typing import Any, Tuple\nimport httpx\n\n\nclass TwoCaptchaImageSolver:\n    BASE_URL = \"https://api.2captcha.com\"\n\n    def __init__(self, api_key: str):\n        self.api_key = api_key\n        self.client = httpx.AsyncClient(timeout=10)\n\n    async def solve(self, image: str) -> Tuple[str, bool]:\n        try:\n            captcha_data = {\n                \"clientKey\": self.api_key,\n                \"softId\": 4706,\n                \"task\": {\n                    \"type\": \"ImageToTextTask\",\n                    \"body\": image,\n                    \"phrase\": False,\n                    \"case\": True,\n                    \"numeric\": 4,\n                    \"math\": False,\n                    \"minLength\": 6,\n                    \"maxLength\": 6,\n                    \"comment\": \"Pay close attention to the letter case.\",\n                },\n            }\n\n            resp = await self.client.post(\n                f\"{self.BASE_URL}/createTask\", json=captcha_data\n            )\n            resp.raise_for_status()\n            data = resp.json()\n\n            if data.get(\"errorId\") == 0:\n                return await self.get_captcha_result(data.get(\"taskId\"))\n            return data.get(\"errorDescription\"), False\n\n        except httpx.HTTPStatusError as err:\n            return f\"HTTP error occurred: {err}\", False\n        except Exception as err:\n            return f\"An unexpected error occurred: {err}\", False\n\n    async def get_captcha_result(\n        self, task_id: int | str\n    ) -> tuple[Any, bool, int | str] | tuple[str, bool, int | str] | tuple[str, bool]:\n        for _ in range(10):\n            try:\n                resp = await self.client.post(\n                    f\"{self.BASE_URL}/getTaskResult\",\n                    json={\"clientKey\": self.api_key, \"taskId\": task_id},\n                )\n                resp.raise_for_status()\n                result = resp.json()\n\n                if result.get(\"errorId\") != 0:\n                    return result.get(\"errorDescription\"), False, task_id\n\n                if result.get(\"status\") == \"ready\":\n                    return result[\"solution\"].get(\"text\", \"\"), True, task_id\n\n                await asyncio.sleep(3)\n\n            except httpx.HTTPStatusError as err:\n                return f\"HTTP error occurred: {err}\", False, task_id\n            except Exception as err:\n                return f\"An unexpected error occurred: {err}\", False, task_id\n\n        return \"Max time for solving exhausted\", False\n\n    async def report_bad(self, task_id: str | int) -> Tuple[Any, bool]:\n        try:\n            resp = await self.client.post(\n                f\"{self.BASE_URL}/reportIncorrect\",\n                json={\"clientKey\": self.api_key, \"taskId\": task_id},\n            )\n            resp.raise_for_status()\n            return resp.json(), True\n        except httpx.HTTPStatusError as err:\n            return f\"HTTP error occurred: {err}\", False\n        except Exception as err:\n            return f\"An unexpected error occurred: {err}\", False\n"
  },
  {
    "path": "database/__init__.py",
    "content": "from .models import Accounts\nfrom .settings import initialize_database\n"
  },
  {
    "path": "database/models/__init__.py",
    "content": "from .accounts import Accounts\n"
  },
  {
    "path": "database/models/accounts.py",
    "content": "import pytz\n\nfrom datetime import datetime\nfrom tortoise import Model, fields\nfrom loguru import logger\n\n\nclass Accounts(Model):\n    email = fields.CharField(max_length=255, unique=True)\n    headers = fields.JSONField(null=True)\n    sleep_until = fields.DatetimeField(null=True)\n    session_blocked_until = fields.DatetimeField(null=True)\n\n    class Meta:\n        table = \"dawn_accounts_v1.4\"\n\n    @classmethod\n    async def get_account(cls, email: str):\n        return await cls.get_or_none(email=email)\n\n    @classmethod\n    async def get_accounts(cls):\n        return await cls.all()\n\n    @classmethod\n    async def create_account(cls, email: str, headers: dict = None):\n        account = await cls.get_account(email=email)\n        if account is None:\n            account = await cls.create(email=email, headers=headers)\n            return account\n        else:\n            account.headers = headers\n            await account.save()\n            return account\n\n    @classmethod\n    async def delete_account(cls, email: str):\n        account = await cls.get_account(email=email)\n        if account is None:\n            return False\n\n        await account.delete()\n        return True\n\n    @classmethod\n    async def set_sleep_until(cls, email: str, sleep_until: datetime):\n        account = await cls.get_account(email=email)\n        if account is None:\n            return False\n\n        if sleep_until.tzinfo is None:\n            sleep_until = pytz.UTC.localize(sleep_until)\n        else:\n            sleep_until = sleep_until.astimezone(pytz.UTC)\n\n        account.sleep_until = sleep_until\n        await account.save()\n        logger.info(f\"Account: {email} | Set new sleep_until: {sleep_until}\")\n        return True\n\n    @classmethod\n    async def set_session_blocked_until(\n        cls, email: str, session_blocked_until: datetime\n    ):\n        account = await cls.get_account(email=email)\n        if account is None:\n            account = await cls.create_account(email=email)\n            account.session_blocked_until = session_blocked_until\n            await account.save()\n            logger.info(\n                f\"Account: {email} | Set new session_blocked_until: {session_blocked_until}\"\n            )\n            return\n\n        if session_blocked_until.tzinfo is None:\n            session_blocked_until = pytz.UTC.localize(session_blocked_until)\n        else:\n            session_blocked_until = session_blocked_until.astimezone(pytz.UTC)\n\n        account.session_blocked_until = session_blocked_until\n        await account.save()\n        logger.info(\n            f\"Account: {email} | Set new session_blocked_until: {session_blocked_until}\"\n        )\n"
  },
  {
    "path": "database/settings.py",
    "content": "from loguru import logger\nfrom tortoise import Tortoise\n\n\nasync def initialize_database() -> None:\n    try:\n        await Tortoise.init(\n            db_url=\"sqlite://database/database.sqlite3\",\n            modules={\"models\": [\"database.models.accounts\"]},\n            timezone=\"UTC\",\n        )\n\n        await Tortoise.generate_schemas(safe=True)\n\n    except Exception as error:\n        logger.error(f\"Error while initializing database: {error}\")\n        exit(0)\n"
  },
  {
    "path": "loader.py",
    "content": "import asyncio\n\nfrom core.solvers import *\nfrom utils import load_config, FileOperations\n\nconfig = load_config()\ncaptcha_solver = (\n    AntiCaptchaImageSolver(config.anti_captcha_api_key)\n    if config.captcha_module == \"anticaptcha\"\n    else TwoCaptchaImageSolver(config.two_captcha_api_key)\n)\nfile_operations = FileOperations()\nsemaphore = asyncio.Semaphore(config.threads)\n"
  },
  {
    "path": "models/__init__.py",
    "content": "from .config import *\nfrom .bot import *\n"
  },
  {
    "path": "models/bot.py",
    "content": "from typing import Literal, TypedDict\n\n\nModuleType = Literal[\"register\", \"tasks\", \"stats\", \"accounts\"]\n\n\nclass OperationResult(TypedDict):\n    identifier: str\n    data: str\n    status: bool\n\n\nclass StatisticData(TypedDict):\n    success: bool\n    referralPoint: dict | None\n    rewardPoint: dict | None\n"
  },
  {
    "path": "models/config.py",
    "content": "from typing import Literal\n\nfrom better_proxy import Proxy\nfrom pydantic import BaseModel, PositiveInt, ConfigDict\n\n\nclass Account(BaseModel):\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n\n    email: str\n    password: str\n    imap_server: str = \"\"\n    proxy: Proxy\n\n\nclass Config(BaseModel):\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n\n    class DelayBeforeStart(BaseModel):\n        min: int\n        max: int\n\n    accounts_to_register: list[Account] = []\n    accounts_to_farm: list[Account] = []\n    referral_code: str = \"\"\n    two_captcha_api_key: str = \"\"\n    anti_captcha_api_key: str = \"\"\n    delay_before_start: DelayBeforeStart\n\n    threads: PositiveInt\n    imap_settings: dict[str, str]\n\n    keepalive_interval: PositiveInt\n    module: str = \"\"\n    captcha_module: Literal[\"2captcha\", \"anticaptcha\"] = \"\"\n"
  },
  {
    "path": "requirements.txt",
    "content": "names~=0.3.0\ncurl_cffi~=0.7.1\npytz~=2024.1\nloguru~=0.7.2\nhttpx~=0.27.0\nurllib3~=2.2.2\nart~=6.2\nPyYAML~=6.0.2\npydantic~=2.8.2\ninquirer~=3.3.0\ncolorama~=0.4.6\nbetter_proxy\ntortoise-orm\nimap_tools\nnumpy~=1.26.4\naiofiles~=24.1.0\naiocsv~=1.3.2\nrich~=13.9.2"
  },
  {
    "path": "run.py",
    "content": "import asyncio\nimport random\nimport sys\nfrom typing import Callable, Coroutine, Any, List, Set\n\nfrom loguru import logger\nfrom loader import config, semaphore, file_operations\nfrom core.bot import Bot\nfrom models import Account\nfrom utils import setup\nfrom console import Console\nfrom database import initialize_database\n\n\naccounts_with_initial_delay: Set[str] = set()\n\n\nasync def run_module_safe(\n        account: Account, process_func: Callable[[Bot], Coroutine[Any, Any, Any]]\n) -> Any:\n    global accounts_with_initial_delay\n\n    async with semaphore:\n        bot = Bot(account)\n        try:\n            if config.delay_before_start.min > 0:\n                if process_func == process_farming and account.email not in accounts_with_initial_delay:\n                    random_delay = random.randint(config.delay_before_start.min, config.delay_before_start.max)\n                    logger.info(f\"Account: {account.email} | Initial farming delay: {random_delay} sec\")\n                    await asyncio.sleep(random_delay)\n                    accounts_with_initial_delay.add(account.email)\n\n                elif process_func != process_farming:\n                    random_delay = random.randint(config.delay_before_start.min, config.delay_before_start.max)\n                    logger.info(f\"Account: {account.email} | Sleep for {random_delay} sec\")\n                    await asyncio.sleep(random_delay)\n\n            result = await process_func(bot)\n            return result\n        finally:\n            await bot.close_session()\n\n\nasync def process_registration(bot: Bot) -> None:\n    operation_result = await bot.process_registration()\n    await file_operations.export_result(operation_result, \"register\")\n\n\nasync def process_farming(bot: Bot) -> None:\n    await bot.process_farming()\n\n\nasync def process_export_stats(bot: Bot) -> None:\n    data = await bot.process_get_user_info()\n    await file_operations.export_stats(data)\n\n\nasync def process_complete_tasks(bot: Bot) -> None:\n    operation_result = await bot.process_complete_tasks()\n    await file_operations.export_result(operation_result, \"tasks\")\n\n\nasync def run_module(\n        accounts: List[Account], process_func: Callable[[Bot], Coroutine[Any, Any, Any]]\n) -> tuple[Any]:\n    tasks = [run_module_safe(account, process_func) for account in accounts]\n    return await asyncio.gather(*tasks)\n\n\nasync def farm_continuously(accounts: List[Account]) -> None:\n    while True:\n        random.shuffle(accounts)\n        await run_module(accounts, process_farming)\n        await asyncio.sleep(10)\n\n\ndef reset_initial_delays():\n    global accounts_with_initial_delay\n    accounts_with_initial_delay.clear()\n\n\nasync def run() -> None:\n    await initialize_database()\n    await file_operations.setup_files()\n    reset_initial_delays()\n\n    module_map = {\n        \"register\": (config.accounts_to_register, process_registration),\n        \"farm\": (config.accounts_to_farm, farm_continuously),\n        \"complete_tasks\": (config.accounts_to_farm, process_complete_tasks),\n        \"export_stats\": (config.accounts_to_farm, process_export_stats),\n    }\n\n    while True:\n        Console().build()\n\n        if config.module not in module_map:\n            logger.error(f\"Unknown module: {config.module}\")\n            break\n\n        accounts, process_func = module_map[config.module]\n\n        if not accounts:\n            logger.error(f\"No accounts for {config.module}\")\n            break\n\n        if config.module == \"farm\":\n            await process_func(accounts)\n        else:\n            await run_module(accounts, process_func)\n            input(\"\\n\\nPress Enter to continue...\")\n\n\nif __name__ == \"__main__\":\n    if sys.platform == \"win32\":\n        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())\n\n    setup()\n    asyncio.run(run())"
  },
  {
    "path": "utils/__init__.py",
    "content": "from .load_config import load_config\nfrom .console import *\nfrom .file_utils import *\nfrom .imap_utils import *\n"
  },
  {
    "path": "utils/console.py",
    "content": "import os\nimport sys\n\nimport urllib3\nfrom art import tprint\nfrom loguru import logger\n\n\ndef setup():\n    urllib3.disable_warnings()\n    logger.remove()\n    logger.add(\n        sys.stdout,\n        colorize=True,\n        format=\"<light-cyan>{time:HH:mm:ss}</light-cyan> | <level> {level: <8}</level> | - <white>{\"\n        \"message}</white>\",\n    )\n    logger.add(\"./logs/logs.log\", rotation=\"1 day\", retention=\"7 days\")\n\n\ndef show_dev_info():\n    os.system(\"cls\")\n    tprint(\"JamBit\")\n    print(\"\\033[36m\" + \"我的推特主页: \" + \"\\033[34m\" + \"https://x.com/Hy78516012\" + \"\\033[34m\")\n    print(\n        \"\\033[36m\"\n        + \"我的GitHub: \"\n        + \"\\033[34m\"\n        + \"https://github.com/Gzgod\"\n        + \"\\033[34m\"\n    )\n    print()\n"
  },
  {
    "path": "utils/file_utils.py",
    "content": "import asyncio\n\nimport aiofiles\n\nfrom pathlib import Path\nfrom aiocsv import AsyncWriter\nfrom models import ModuleType, OperationResult, StatisticData\n\n\n\nclass FileOperations:\n    def __init__(self, base_path: str = \"./results\"):\n        self.base_path = Path(base_path)\n        self.lock = asyncio.Lock()\n        self.module_paths: dict[ModuleType, dict[str, Path]] = {\n            \"register\": {\n                \"success\": self.base_path / \"registration_success.txt\",\n                \"failed\": self.base_path / \"registration_failed.txt\",\n            },\n            \"tasks\": {\n                \"success\": self.base_path / \"tasks_success.txt\",\n                \"failed\": self.base_path / \"tasks_failed.txt\",\n            },\n            \"stats\": {\n                \"base\": self.base_path / \"accounts_stats.csv\",\n            },\n            \"accounts\": {\n                \"unverified\": self.base_path / \"unverified_accounts.txt\",\n            },\n        }\n\n    async def setup_files(self):\n        self.base_path.mkdir(exist_ok=True)\n        for module_paths in self.module_paths.values():\n            for path in module_paths.values():\n                path.touch(exist_ok=True)\n\n        async with aiofiles.open(self.module_paths[\"stats\"][\"base\"], \"w\") as f:\n            writer = AsyncWriter(f)\n            await writer.writerow(\n                [\n                    \"Email\",\n                    \"Referral Code\",\n                    \"Points\",\n                    \"Referral Points\",\n                    \"Total Points\",\n                    \"Registration Date\",\n                    \"Completed Tasks\",\n                ]\n            )\n\n    async def export_result(self, result: OperationResult, module: ModuleType):\n        if module not in self.module_paths:\n            raise ValueError(f\"Unknown module: {module}\")\n\n        file_path = self.module_paths[module][\n            \"success\" if result[\"status\"] else \"failed\"\n        ]\n        async with self.lock:\n            try:\n                async with aiofiles.open(file_path, \"a\") as file:\n                    await file.write(f\"{result['identifier']}:{result['data']}\\n\")\n            except IOError as e:\n                print(f\"Error writing to file: {e}\")\n\n\n    async def export_unverified_email(self, email: str, password: str):\n        file_path = self.module_paths[\"accounts\"][\"unverified\"]\n        async with self.lock:\n            try:\n                async with aiofiles.open(file_path, \"a\") as file:\n                    await file.write(f\"{email}:{password}\\n\")\n            except IOError as e:\n                print(f\"Error writing to file: {e}\")\n\n\n    async def export_stats(self, data: StatisticData):\n        file_path = self.module_paths[\"stats\"][\"base\"]\n        async with self.lock:\n            try:\n                async with aiofiles.open(file_path, mode=\"a\", newline=\"\") as f:\n                    writer = AsyncWriter(f)\n\n                    if not data or not data[\"referralPoint\"] or not data[\"rewardPoint\"]:\n                        return\n\n                    await writer.writerow(\n                        [\n                            data[\"referralPoint\"][\"email\"],\n                            data[\"referralPoint\"][\"referralCode\"],\n                            data[\"rewardPoint\"][\"points\"],\n                            data[\"referralPoint\"][\"commission\"],\n                            float(data[\"rewardPoint\"][\"points\"])\n                            + float(data[\"referralPoint\"][\"commission\"]),\n                            data[\"rewardPoint\"][\"registerpointsdate\"],\n                            (\n                                True\n                                if data[\"rewardPoint\"][\"twitter_x_id_points\"] == 5000\n                                and data[\"rewardPoint\"][\"discordid_points\"] == 5000\n                                and data[\"rewardPoint\"][\"telegramid_points\"] == 5000\n                                else False\n                            ),\n                        ]\n                    )\n\n            except IOError as e:\n                print(f\"Error writing to file: {e}\")\n"
  },
  {
    "path": "utils/imap_utils.py",
    "content": "import re\nfrom typing import Optional\nimport asyncio\n\nfrom loguru import logger\nfrom imap_tools import MailBox, AND\n\n\nasync def check_if_email_valid(\n    imap_server: str,\n    email: str,\n    password: str,\n) -> bool:\n    logger.info(f\"Account: {email} | Checking if email is valid...\")\n\n    try:\n        await asyncio.to_thread(lambda: MailBox(imap_server).login(email, password))\n        return True\n    except Exception as error:\n        logger.error(f\"Account: {email} | Email is invalid (IMAP): {error}\")\n        return False\n\n\nasync def check_email_for_link(\n    imap_server: str,\n    email: str,\n    password: str,\n    max_attempts: int = 8,\n    delay_seconds: int = 5,\n) -> Optional[str]:\n    link_pattern = (\n        r\"https://www\\.aeropres\\.in/chromeapi/dawn/v1/user/verifylink\\?key=[a-f0-9-]+\"\n    )\n    logger.info(f\"Account: {email} | Checking email for link...\")\n\n    try:\n\n        async def search_in_mailbox():\n            return await asyncio.to_thread(\n                lambda: search_for_link_sync(\n                    MailBox(imap_server).login(email, password), link_pattern\n                )\n            )\n\n        for attempt in range(max_attempts):\n            link = await search_in_mailbox()\n            if link:\n                return link\n\n            if attempt < max_attempts - 1:\n                logger.info(\n                    f\"Account: {email} | Link not found. Waiting {delay_seconds} seconds before next attempt...\"\n                )\n                await asyncio.sleep(delay_seconds)\n\n        logger.warning(\n            f\"Account: {email} | Link not found after {max_attempts} attempts, searching in spam folder...\"\n        )\n\n        spam_folders = (\"SPAM\", \"Spam\", \"spam\", \"Junk\", \"junk\", \"Spamverdacht\")\n        for spam_folder in spam_folders:\n\n            async def search_in_spam():\n                return await asyncio.to_thread(\n                    lambda: search_for_link_in_spam_sync(\n                        MailBox(imap_server).login(email, password),\n                        link_pattern,\n                        spam_folder,\n                    )\n                )\n\n            link = await search_in_spam()\n            if link:\n                return link\n\n        logger.error(\n            f\"Account: {email} | Link not found in spam folder after multiple attempts\"\n        )\n        return None\n\n    except Exception as error:\n        logger.error(f\"Account: {email} | Failed to check email for link: {error}\")\n        return None\n\n\ndef search_for_link_sync(mailbox: MailBox, link_pattern: str) -> Optional[str]:\n    messages = mailbox.fetch()\n\n    for msg in messages:\n        if msg.from_ == \"hello@dawninternet.com\":\n            body = msg.text or msg.html\n            if body:\n                match = re.search(link_pattern, body)\n                if match:\n                    return match.group(0)\n\n    return None\n\n\ndef search_for_link_in_spam_sync(\n    mailbox: MailBox, link_pattern: str, spam_folder: str\n) -> Optional[str]:\n    if mailbox.folder.exists(spam_folder):\n        mailbox.folder.set(spam_folder)\n        return search_for_link_sync(mailbox, link_pattern)\n    return None\n"
  },
  {
    "path": "utils/load_config.py",
    "content": "import os\nimport yaml\nfrom itertools import cycle\nfrom loguru import logger\nfrom models import Config, Account\nfrom better_proxy import Proxy\nfrom typing import List, Dict, Generator\n\nCONFIG_PATH = os.path.join(os.getcwd(), \"config\")\nCONFIG_DATA_PATH = os.path.join(CONFIG_PATH, \"data\")\nCONFIG_PARAMS = os.path.join(CONFIG_PATH, \"settings.yaml\")\n\nREQUIRED_DATA_FILES = (\"accounts.txt\", \"proxies.txt\")\nREQUIRED_PARAMS_FIELDS = (\n    \"threads\",\n    \"keepalive_interval\",\n    \"imap_settings\",\n    \"captcha_module\",\n    \"delay_before_start\",\n    \"referral_code\",\n)\n\n\ndef read_file(\n    file_path: str, check_empty: bool = True, is_yaml: bool = False\n) -> List[str] | Dict:\n    if not os.path.exists(file_path):\n        raise FileNotFoundError(f\"File not found: {file_path}\")\n\n    if check_empty and os.stat(file_path).st_size == 0:\n        raise ValueError(f\"File is empty: {file_path}\")\n\n    if is_yaml:\n        with open(file_path, \"r\", encoding=\"utf-8\") as file:\n            return yaml.safe_load(file)\n\n    with open(file_path, \"r\", encoding=\"utf-8\") as file:\n        return [line.strip() for line in file]\n\n\ndef get_params() -> Dict:\n    data = read_file(CONFIG_PARAMS, is_yaml=True)\n    missing_fields = set(REQUIRED_PARAMS_FIELDS) - set(data.keys())\n    if missing_fields:\n        raise ValueError(f\"Missing fields in config file: {', '.join(missing_fields)}\")\n    return data\n\n\ndef get_proxies() -> List[Proxy]:\n    try:\n        proxies = read_file(\n            os.path.join(CONFIG_DATA_PATH, \"proxies.txt\"), check_empty=False\n        )\n        return [Proxy.from_str(line) for line in proxies] if proxies else []\n    except Exception as exc:\n        raise ValueError(f\"Failed to parse proxy: {exc}\")\n\n\ndef get_accounts(file_name: str) -> Generator[Account, None, None]:\n    proxies = get_proxies()\n    proxy_cycle = cycle(proxies) if proxies else None\n    accounts = read_file(os.path.join(CONFIG_DATA_PATH, file_name), check_empty=False)\n\n    for account in accounts:\n        try:\n            email, password = account.split(\":\")\n            yield Account(\n                email=email,\n                password=password,\n                proxy=next(proxy_cycle) if proxy_cycle else None,\n            )\n        except ValueError:\n            logger.error(f\"Failed to parse account: {account}\")\n\n\ndef validate_domains(accounts: List[Account], domains: Dict[str, str]) -> List[Account]:\n    for account in accounts:\n        domain = account.email.split(\"@\")[1]\n        if domain not in domains:\n            raise ValueError(\n                f\"Domain '{domain}' is not supported, please add it to the config file\"\n            )\n        account.imap_server = domains[domain]\n    return accounts\n\n\ndef load_config() -> Config:\n    try:\n        reg_accounts = list(get_accounts(\"register.txt\"))\n        farm_accounts = list(get_accounts(\"farm.txt\"))\n\n        if not reg_accounts and not farm_accounts:\n            raise ValueError(\"No accounts found in data files\")\n\n        params = get_params()\n        config = Config(\n            **params, accounts_to_farm=farm_accounts, accounts_to_register=reg_accounts\n        )\n\n        if reg_accounts:\n            config.accounts_to_register = validate_domains(\n                reg_accounts, config.imap_settings\n            )\n\n        if config.captcha_module == \"2captcha\" and not config.two_captcha_api_key:\n            raise ValueError(\"2Captcha API key is missing\")\n        elif config.captcha_module == \"anticaptcha\" and not config.anti_captcha_api_key:\n            raise ValueError(\"AntiCaptcha API key is missing\")\n\n        return config\n\n    except Exception as exc:\n        logger.error(f\"Failed to load config: {exc}\")\n        exit(1)\n"
  }
]