Full Code of GzGod/Dawn for AI

main 713a43396606 cached
29 files
60.7 KB
13.8k tokens
99 symbols
1 requests
Download .txt
Repository: GzGod/Dawn
Branch: main
Commit: 713a43396606
Files: 29
Total size: 60.7 KB

Directory structure:
gitextract_p0kopyhp/

├── README.md
├── config/
│   ├── data/
│   │   ├── farm.txt
│   │   ├── proxies.txt
│   │   └── register.txt
│   └── settings.yaml
├── console/
│   ├── __init__.py
│   ├── logger.py
│   └── main.py
├── core/
│   ├── api.py
│   ├── bot.py
│   ├── exceptions/
│   │   └── base.py
│   └── solvers/
│       ├── __init__.py
│       ├── anti_captcha.py
│       └── two_captcha.py
├── database/
│   ├── __init__.py
│   ├── models/
│   │   ├── __init__.py
│   │   └── accounts.py
│   └── settings.py
├── loader.py
├── models/
│   ├── __init__.py
│   ├── bot.py
│   └── config.py
├── requirements.txt
├── run.py
└── utils/
    ├── __init__.py
    ├── console.py
    ├── file_utils.py
    ├── imap_utils.py
    └── load_config.py

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
# Dawn Extension Bot [1.5]
# 原作者https://github.com/Jaammerr/The-Dawn-Bot 防止正义人士
<div align="center">
  <img src="./console/1.png" alt="Dawn Extension Bot Console" width="600"/>
</div>


**我的推特: [@Hy78516012,如果觉得有用请给我点个关注吧)**


---

## 🚀 功能

- ✅ 自动账户注册和登录
- 📧 自动账户重新验证
- 🌾 自动完成所有任务
- 💰 自动获取积分
- 📊 导出账户统计数据
- 🔄 保持会话功能
- 🧩 高级跳码

---

## 💻 环境及需要的账户

- Python >= 3.11
- 安装Python虚拟环境
- 能注册DAWN的邮箱号
- 代理IP(可选)

---

## 🛠️ 设置

1. 克隆仓库:
   ```bash
   git clone https://github.com/GzGod/Dawn
   ```
2. 创建并激活虚拟环境:
   ```bash
   Windows系统:
   python -m venv venv
   cd venv/Scripts
   activate
   Linux(服务器):
   python3 -m venv venv
   cd venv/bin
   source activate
   cd ../..
   ```
3. 安装依赖:
   ```bash
   pip install -r requirements.txt
   ```

---

## ⚙️ 配置

### settings.yaml

该文件包含机器人的常规设置:

```yaml
threads: 5 # 同时进行账户操作的线程数
keepalive_interval: 120 # 保持会话请求之间的延迟(秒)
referral_code: "YOUR_REFERRAL_CODE" # 注册推荐码
captcha_service: "2captcha" # 验证码解决服务(2captcha或anticaptcha都可以)
two_captcha_api_key: "YOUR_2CAPTCHA_API_KEY"
anti_captcha_api_key: "YOUR_ANTICAPTCHA_API_KEY"

imap_settings: # 电子邮件提供商的IMAP设置
  gmail.com: imap.gmail.com
  outlook.com: imap-mail.outlook.com
  # 根据需要添加更多电子邮件提供商
```

### 其他配置文件

#### 📁 register.txt
包含注册账户信息。注意 这里的邮箱的password需要的是imap授权码,小白不建议用这种
老老实实注册然后填在farm.txt即可
```
格式:
email:password
email:password
...
```

#### 📁 farm.txt
包含用于获取积分和完成任务的账户信息。
```
格式:
email:password
email:password
...
```

#### 📁 proxies.txt
包含代理信息。
```
格式:
http://user:pass@ip:port
http://ip:port:user:pass
http://ip:port@user:pass
http://user:pass:ip:port
...
```

---

## 🚀 使用

1. 确保所有配置文件已正确设置。
2. 运行机器人:
   ```bash
   python run.py
   ```

---

## ⚠️ 重要提示

- 建议的保持会话请求之间的延迟为120秒。
- 如果有未验证的账户,可以再次使用`register`模块重新验证。
- 由于验证码复杂性的变化,现在使用外部服务(2captcha,anti-captcha)来解决验证码。
- 使用数据库来优化登录过程,通过存储授权令牌。
- 对于像Gmail这样的电子邮件服务,可能需要使用应用程序专用密码而不是常规电子邮件密码。

---

## 🔧 问题排查

- **Email Verification Issues**:检查`settings.yaml`中的电子邮件提供商IMAP设置。
- **Captcha Problems**:验证您的验证码服务API密钥和账户余额。
- **Proxy Issues**:确保您的代理格式正确且代理功能正常。

---


================================================
FILE: config/data/farm.txt
================================================
test@gmail.com:password

================================================
FILE: config/data/proxies.txt
================================================
http://proxy

================================================
FILE: config/data/register.txt
================================================
test@gmail.com:password

================================================
FILE: config/settings.yaml
================================================
# Application Configuration File
# =============================

# Core Settings
# ------------
threads: 10                    # Number of concurrent threads to run (minimum: 1)
keepalive_interval: 120        # How often to send keepalive signal (in seconds)
referral_code: "hegbhf"        # Your referral code for the application

# Captcha Settings
# ---------------
captcha_module: 2captcha       # Captcha service to use: '2captcha' or 'anticaptcha'
two_captcha_api_key: ""        # API key for 2captcha service
anti_captcha_api_key: ""       # API key for anti-captcha service

# Startup Delay Configuration
# -------------------------
delay_before_start:
  min: 2                       # Minimum delay before starting (seconds)
  max: 3                       # Maximum delay before starting (seconds)

# Email Provider IMAP Settings
# --------------------------
imap_settings:
  # Common email providers and their IMAP servers
  gmail.com: imap.gmail.com          # Google Mail
  yahoo.com: imap.mail.yahoo.com     # Yahoo Mail
  outlook.com: imap-mail.outlook.com  # Microsoft Outlook
  hotmail.com: imap-mail.outlook.com  # Microsoft Hotmail
  mail.ru: imap.mail.ru              # Mail.ru
  rambler.ru: imap.rambler.ru        # Rambler
  gmx.com: imap.gmx.com              # GMX Mail
  gmx.net: imap.gmx.net             # GMX Germany
  gmx.de: imap.gmx.net              # GMX Germany (alternate domain)

================================================
FILE: console/__init__.py
================================================
from .main import Console


================================================
FILE: console/logger.py
================================================
from colorama import Fore


def error_log(message: str):
    print(Fore.RED + ">> ERROR |" + Fore.LIGHTBLACK_EX + f" {message}")


def success_log(message: str):
    print(Fore.GREEN + ">> SUCCESS |" + Fore.LIGHTBLACK_EX + f" {message}")


def info_log(message: str):
    print(Fore.LIGHTBLACK_EX + f">> INFO | {message}")


================================================
FILE: console/main.py
================================================
import os
import sys
import inquirer

from inquirer.themes import GreenPassion
from art import text2art
from colorama import Fore
from loader import config

from rich.console import Console as RichConsole
from rich.panel import Panel
from rich.table import Table
from rich import box
from rich.text import Text

sys.path.append(os.path.realpath("."))


class Console:
    MODULES = (
        "Register",
        "Farm",
        "Complete tasks",
        "Export statistics",
        "Exit",
    )
    MODULES_DATA = {
        "Register": "register",
        "Farm": "farm",
        "Exit": "exit",
        "Export statistics": "export_stats",
        "Complete tasks": "complete_tasks",
    }

    def __init__(self):
        self.rich_console = RichConsole()

    def show_dev_info(self):
        os.system("cls" if os.name == "nt" else "clear")

        title = text2art("JamBit", font="small")
        styled_title = Text(title, style="bold cyan")

        version = Text("VERSION: 1.5", style="blue")
        telegram = Text("我的推特主页: https://x.com/Hy78516012", style="green")
        github = Text("我的GitHub: https://github.com/Gzgod", style="green")

        dev_panel = Panel(
            Text.assemble(styled_title, "\n", version, "\n", telegram, "\n", github),
            border_style="yellow",
            expand=False,
            title="[bold green]Welcome[/bold green]",
            subtitle="[italic]Powered by Jammer[/italic]",
        )

        self.rich_console.print(dev_panel)
        print()

    @staticmethod
    def prompt(data: list):
        answers = inquirer.prompt(data, theme=GreenPassion())
        return answers

    def get_module(self):
        questions = [
            inquirer.List(
                "module",
                message=Fore.LIGHTBLACK_EX + "Select the module",
                choices=self.MODULES,
            ),
        ]

        answers = self.prompt(questions)
        return answers.get("module")

    def display_info(self):
        table = Table(title="Dawn Configuration", box=box.ROUNDED)
        table.add_column("Parameter", style="cyan")
        table.add_column("Value", style="magenta")

        table.add_row("Accounts to register", str(len(config.accounts_to_register)))
        table.add_row("Accounts to farm", str(len(config.accounts_to_farm)))
        table.add_row("Threads", str(config.threads))
        table.add_row(
            "Delay before start",
            f"{config.delay_before_start.min} - {config.delay_before_start.max} sec",
        )

        panel = Panel(
            table,
            expand=False,
            border_style="green",
            title="[bold yellow]System Information[/bold yellow]",
            subtitle="[italic]Use arrow keys to navigate[/italic]",
        )
        self.rich_console.print(panel)

    def build(self) -> None:
        self.show_dev_info()
        self.display_info()

        module = self.get_module()
        config.module = self.MODULES_DATA[module]

        if config.module == "exit":
            exit(0)


================================================
FILE: core/api.py
================================================
import asyncio
import json
import names

from datetime import datetime, timezone
from typing import Literal, Tuple, Any
from curl_cffi.requests import AsyncSession

from models import Account
from .exceptions.base import APIError, SessionRateLimited, ServerError
from loader import captcha_solver, config


class DawnExtensionAPI:
    API_URL = "https://www.aeropres.in/chromeapi/dawn"

    def __init__(self, account: Account):
        self.account_data = account
        self.wallet_data: dict[str, Any] = {}
        self.session = self.setup_session()

    def setup_session(self) -> AsyncSession:
        session = AsyncSession(impersonate="chrome124", verify=False)
        session.timeout = 30
        session.headers = {
            "accept": "*/*",
            "accept-language": "en-US,en;q=0.9",
            "origin": "chrome-extension://fpdkjdnhkakefebpekbdhillbhonfjjp",
            "priority": "u=1, i",
            "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",
        }

        if self.account_data.proxy:
            session.proxies = {
                "http": self.account_data.proxy.as_url,
                "https": self.account_data.proxy.as_url,
            }

        return session

    async def clear_request(self, url: str):
        session = AsyncSession(impersonate="chrome124", verify=False, timeout=30)
        session.proxies = self.session.proxies

        response = await session.get(url)
        return response

    async def send_request(
        self,
        request_type: Literal["POST", "GET", "OPTIONS"] = "POST",
        method: str = None,
        json_data: dict = None,
        params: dict = None,
        url: str = None,
        headers: dict = None,
        cookies: dict = None,
        verify: bool = True,
        max_retries: int = 3,
        retry_delay: float = 3.0,
    ):
        def verify_response(response_data: dict | list) -> dict | list:
            if "status" in str(response_data):
                if isinstance(response_data, dict):
                    if response_data.get("status") is False:
                        raise APIError(
                            f"API returned an error: {response_data}", response_data
                        )

            elif "success" in str(response_data):
                if isinstance(response_data, dict):
                    if response_data.get("success") is False:
                        raise APIError(
                            f"API returned an error: {response_data}", response_data
                        )

            return response_data

        for attempt in range(max_retries):
            try:
                if request_type == "POST":
                    if not url:
                        response = await self.session.post(
                            f"{self.API_URL}{method}",
                            json=json_data,
                            params=params,
                            headers=headers if headers else self.session.headers,
                            cookies=cookies,
                        )
                    else:
                        response = await self.session.post(
                            url,
                            json=json_data,
                            params=params,
                            headers=headers if headers else self.session.headers,
                            cookies=cookies,
                        )
                elif request_type == "OPTIONS":
                    response = await self.session.options(
                        url,
                        headers=headers if headers else self.session.headers,
                        cookies=cookies,
                    )
                else:
                    if not url:
                        response = await self.session.get(
                            f"{self.API_URL}{method}",
                            params=params,
                            headers=headers if headers else self.session.headers,
                            cookies=cookies,
                        )
                    else:
                        response = await self.session.get(
                            url,
                            params=params,
                            headers=headers if headers else self.session.headers,
                            cookies=cookies,
                        )

                if verify:

                    if response.status_code == 403:
                        raise SessionRateLimited("Session is rate limited")

                    if response.status_code in (500, 502, 503, 504):
                        raise ServerError(f"Server error - {response.status_code}")

                    try:
                        return verify_response(response.json())
                    except json.JSONDecodeError:
                        return response.text

                return response.text

            except ServerError as error:
                if attempt == max_retries - 1:
                    raise error
                await asyncio.sleep(retry_delay)


            except APIError:
                raise

            except SessionRateLimited:
                raise

            except Exception as error:
                if attempt == max_retries - 1:
                    raise ServerError(
                        f"Failed to send request after {max_retries} attempts: {error}"
                    )
                await asyncio.sleep(retry_delay)

        raise ServerError(f"Failed to send request after {max_retries} attempts")

    @staticmethod
    async def solve_puzzle(
        image: str,
    ) -> Tuple[str | int, bool, str | int] | Tuple[str, bool] | Tuple[str, bool, str]:
        response = await captcha_solver.solve(image)
        return response

    @staticmethod
    async def report_invalid_puzzle(task_id: int | str) -> None:
        await captcha_solver.report_bad(task_id)

    async def get_puzzle_id(self) -> str:
        if "Berear" in self.session.headers:
            del self.session.headers["Berear"]
            self.session.cookies.clear()

        params = {
            'appid': 'undefined',
        }

        response = await self.send_request(
            method="/v1/puzzle/get-puzzle",
            request_type="GET",
            params=params,
        )
        return response["puzzle_id"]

    async def get_puzzle_image(self, puzzle_id: str) -> str:
        response = await self.send_request(
            method="/v1/puzzle/get-puzzle-image",
            request_type="GET",
            params={"puzzle_id": puzzle_id, "appid": "undefined"},
        )

        return response.get("imgBase64")

    async def register(self, puzzle_id: str, answer: str) -> dict:
        json_data = {
            "firstname": names.get_first_name(),
            "lastname": names.get_last_name(),
            "email": self.account_data.email,
            "mobile": "",
            "password": self.account_data.password,
            "country": "+91",
            "referralCode": config.referral_code,
            "puzzle_id": puzzle_id,
            "ans": answer,
        }

        return await self.send_request(
            method="/v1/puzzle/validate-register",
            json_data=json_data,
        )

    async def keepalive(self) -> dict | str:
        headers = {
            "accept": "*/*",
            "accept-language": "en-US,en;q=0.9,ru;q=0.8",
            "authorization": f'Berear {self.session.headers["Berear"]}',
            "content-type": "application/json",
            "origin": "chrome-extension://fpdkjdnhkakefebpekbdhillbhonfjjp",
            "user-agent": self.session.headers["user-agent"],
        }

        json_data = {
            "username": self.account_data.email,
            "extensionid": "fpdkjdnhkakefebpekbdhillbhonfjjp",
            "numberoftabs": 0,
            "_v": "1.0.9",
        }

        params = {
            'appid': 'undefined',
        }

        return await self.send_request(
            method="/v1/userreward/keepalive",
            json_data=json_data,
            verify=False,
            headers=headers,
            params=params,
        )

    async def user_info(self) -> dict:
        headers = self.session.headers.copy()
        headers["authorization"] = f'Berear {self.session.headers["Berear"]}'
        headers["content-type"] = "application/json"
        del headers["Berear"]

        params = {
            'appid': 'undefined',
        }

        response = await self.send_request(
            url="https://www.aeropres.in/api/atom/v1/userreferral/getpoint",
            request_type="GET",
            headers=headers,
            params=params,
        )

        return response["data"]

    async def complete_tasks(self, tasks: list[str] = None, delay: int = 1) -> None:
        if not tasks:
            tasks = ["telegramid", "discordid", "twitter_x_id"]

        headers = self.session.headers.copy()
        headers["authorization"] = f'Brearer {self.session.headers["Berear"]}'
        headers["content-type"] = "application/json"
        del headers["Berear"]

        for task in tasks:
            json_data = {
                task: task,
            }

            await self.send_request(
                method="/v1/profile/update",
                json_data=json_data,
                headers=headers,
            )

            await asyncio.sleep(delay)

    async def verify_session(self) -> tuple[bool, str]:
        try:
            await self.user_info()
            return True, "Session is valid"

        except ServerError:
            return True, "Server error"

        except APIError as error:
            return False, str(error)

    async def login(self, puzzle_id: str, answer: str):
        current_time = datetime.now(timezone.utc)
        formatted_datetime_str = (
            current_time.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
        )

        params = {
            'appid': 'undefined',
        }

        json_data = {
            "username": self.account_data.email,
            "password": self.account_data.password,
            "logindata": {
                "_v": "1.0.9",
                "datetime": formatted_datetime_str,
            },
            "puzzle_id": puzzle_id,
            "ans": answer,
        }

        response = await self.send_request(
            method="/v1/user/login/v2",
            json_data=json_data,
            params=params,
        )

        berear = response.get("data", {}).get("token")
        if berear:
            self.wallet_data = response.get("data", {}).get("wallet")
            self.session.headers.update({"Berear": berear})
        else:
            raise APIError(f"Failed to login: {response}")


================================================
FILE: core/bot.py
================================================
from datetime import datetime, timedelta
from typing import Tuple, Any, Optional

import pytz
from loguru import logger
from loader import config, file_operations
from models import Account, OperationResult, StatisticData

from .api import DawnExtensionAPI
from utils import check_email_for_link, check_if_email_valid
from database import Accounts
from .exceptions.base import APIError, SessionRateLimited, CaptchaSolvingFailed


class Bot(DawnExtensionAPI):
    def __init__(self, account: Account):
        super().__init__(account)

    async def get_captcha_data(self) -> Tuple[str, Any, Optional[Any]]:
        for _ in range(5):
            try:
                puzzle_id = await self.get_puzzle_id()
                image = await self.get_puzzle_image(puzzle_id)

                logger.info(
                    f"Account: {self.account_data.email} | Got puzzle image, solving..."
                )
                answer, solved, *rest = await self.solve_puzzle(image)

                if solved and len(answer) == 6:
                    logger.success(
                        f"Account: {self.account_data.email} | Puzzle solved: {answer}"
                    )
                    return puzzle_id, answer, rest[0] if rest else None

                if len(answer) != 6 and rest:
                    await self.report_invalid_puzzle(rest[0])

                logger.error(
                    f"Account: {self.account_data.email} | Failed to solve puzzle: Incorrect answer | Retrying..."
                )

            except SessionRateLimited:
                raise

            except Exception as e:
                logger.error(
                    f"Account: {self.account_data.email} | Error occurred while solving captcha: {str(e)} | Retrying..."
                )

        raise CaptchaSolvingFailed("Failed to solve captcha after 5 attempts")

    async def clear_account_and_session(self) -> None:
        if await Accounts.get_account(email=self.account_data.email):
            await Accounts.delete_account(email=self.account_data.email)
        self.session = self.setup_session()

    async def process_reverify_email(self) -> OperationResult:
        await self.clear_account_and_session()

        try:
            confirm_url = await check_email_for_link(
                imap_server=self.account_data.imap_server,
                email=self.account_data.email,
                password=self.account_data.password,
            )

            if confirm_url is None:
                logger.error(
                    f"Account: {self.account_data.email} | Confirmation link not found"
                )
                return OperationResult(
                    identifier=self.account_data.email,
                    data=self.account_data.password,
                    status=False,
                )

            logger.success(
                f"Account: {self.account_data.email} | Link found, confirming registration..."
            )
            response = await self.clear_request(url=confirm_url)
            if response.status_code == 200:
                logger.success(
                    f"Account: {self.account_data.email} | Successfully confirmed registration"
                )
                return OperationResult(
                    identifier=self.account_data.email,
                    data=self.account_data.password,
                    status=True,
                )

            logger.error(
                f"Account: {self.account_data.email} | Failed to confirm registration"
            )

        except Exception as error:
            logger.error(
                f"Account: {self.account_data.email} | Failed to reverify email: {error}"
            )

        return OperationResult(
            identifier=self.account_data.email,
            data=self.account_data.password,
            status=False,
        )


    async def process_registration(self) -> OperationResult:
        task_id = None

        try:
            if not await check_if_email_valid(
                self.account_data.imap_server,
                self.account_data.email,
                self.account_data.password,
            ):
                logger.error(f"Account: {self.account_data.email} | Invalid email")
                return OperationResult(
                    identifier=self.account_data.email,
                    data=self.account_data.password,
                    status=False,
                )

            logger.info(f"Account: {self.account_data.email} | Registering...")
            puzzle_id, answer, task_id = await self.get_captcha_data()

            await self.register(puzzle_id, answer)
            logger.info(
                f"Account: {self.account_data.email} | Successfully registered, waiting for email..."
            )

            confirm_url = await check_email_for_link(
                imap_server=self.account_data.imap_server,
                email=self.account_data.email,
                password=self.account_data.password,
            )

            if confirm_url is None:
                logger.error(
                    f"Account: {self.account_data.email} | Confirmation link not found"
                )
                return OperationResult(
                    identifier=self.account_data.email,
                    data=self.account_data.password,
                    status=False,
                )

            logger.success(
                f"Account: {self.account_data.email} | Link found, confirming registration..."
            )
            response = await self.clear_request(url=confirm_url)
            if response.status_code == 200:
                logger.success(
                    f"Account: {self.account_data.email} | Successfully confirmed registration"
                )
                return OperationResult(
                    identifier=self.account_data.email,
                    data=self.account_data.password,
                    status=True,
                )

            logger.error(
                f"Account: {self.account_data.email} | Failed to confirm registration"
            )

        except APIError as error:
            if error.error_message in error.BASE_MESSAGES:
                if error.error_message == "Incorrect answer. Try again!":
                    logger.warning(
                        f"Account: {self.account_data.email} | Captcha answer incorrect, re-solving..."
                    )
                    if task_id:
                        await self.report_invalid_puzzle(task_id)

                elif error.error_message == "email already exists":
                    logger.warning(f"Account: {self.account_data.email} | Email already exists, re-verifying...")
                    return await self.process_reverify_email()

                else:
                    logger.warning(
                        f"Account: {self.account_data.email} | Captcha expired, re-solving..."
                    )
                return await self.process_registration()

            logger.error(
                f"Account: {self.account_data.email} | Failed to register: {error}"
            )

        except Exception as error:
            logger.error(
                f"Account: {self.account_data.email} | Failed to register: {error}"
            )

        return OperationResult(
            identifier=self.account_data.email,
            data=self.account_data.password,
            status=False,
        )

    @staticmethod
    def get_sleep_until(blocked: bool = False) -> datetime:
        duration = (
            timedelta(minutes=10)
            if blocked
            else timedelta(seconds=config.keepalive_interval)
        )
        return datetime.now(pytz.UTC) + duration

    async def process_farming(self) -> None:
        try:
            db_account_data = await Accounts.get_account(email=self.account_data.email)

            if db_account_data and db_account_data.session_blocked_until:
                if await self.handle_sleep(db_account_data.session_blocked_until):
                    return

            if not db_account_data or not db_account_data.headers:
                if not await self.login_new_account():
                    return

            elif not await self.handle_existing_account(db_account_data):
                return

            await self.perform_farming_actions()

        except SessionRateLimited:
            await self.handle_session_blocked()

        except APIError as error:
            logger.error(
                f"Account: {self.account_data.email} | Failed to farm: {error}"
            )


        except Exception as error:
            logger.error(
                f"Account: {self.account_data.email} | Failed to farm: {error}"
            )

        return

    async def process_get_user_info(self) -> StatisticData:
        try:
            db_account_data = await Accounts.get_account(email=self.account_data.email)

            if db_account_data and db_account_data.session_blocked_until:
                if await self.handle_sleep(db_account_data.session_blocked_until):
                    return StatisticData(
                        success=False, referralPoint=None, rewardPoint=None
                    )

            if not db_account_data or not db_account_data.headers:
                if not await self.login_new_account():
                    return StatisticData(
                        success=False, referralPoint=None, rewardPoint=None
                    )

            elif not await self.handle_existing_account(db_account_data):
                return StatisticData(
                    success=False, referralPoint=None, rewardPoint=None
                )

            user_info = await self.user_info()
            logger.success(
                f"Account: {self.account_data.email} | Successfully got user info"
            )
            return StatisticData(
                success=True,
                referralPoint=user_info["referralPoint"],
                rewardPoint=user_info["rewardPoint"],
            )

        except SessionRateLimited:
            await self.handle_session_blocked()
        except APIError as error:
            logger.error(
                f"Account: {self.account_data.email} | Failed to get user info: {error}"
            )
        except Exception as error:
            logger.error(
                f"Account: {self.account_data.email} | Failed to get user info: {error}"
            )

        return StatisticData(success=False, referralPoint=None, rewardPoint=None)

    async def process_complete_tasks(self) -> OperationResult:
        try:
            db_account_data = await Accounts.get_account(email=self.account_data.email)
            if db_account_data is None:
                if not await self.login_new_account():
                    return OperationResult(
                        identifier=self.account_data.email,
                        data=self.account_data.password,
                        status=False,
                    )
            else:
                await self.handle_existing_account(db_account_data)

            logger.info(f"Account: {self.account_data.email} | Completing tasks...")
            await self.complete_tasks()

            logger.success(
                f"Account: {self.account_data.email} | Successfully completed tasks"
            )
            return OperationResult(
                identifier=self.account_data.email,
                data=self.account_data.password,
                status=True,
            )

        except Exception as error:
            logger.error(
                f"Account: {self.account_data.email} | Failed to complete tasks: {error}"
            )
            return OperationResult(
                identifier=self.account_data.email,
                data=self.account_data.password,
                status=False,
            )

    async def login_new_account(self):
        task_id = None

        try:
            logger.info(f"Account: {self.account_data.email} | Logging in...")
            puzzle_id, answer, task_id = await self.get_captcha_data()

            await self.login(puzzle_id, answer)
            logger.info(f"Account: {self.account_data.email} | Successfully logged in")

            await Accounts.create_account(
                email=self.account_data.email, headers=self.session.headers
            )
            return True

        except APIError as error:
            if error.error_message in error.BASE_MESSAGES:
                if error.error_message == "Incorrect answer. Try again!":
                    logger.warning(
                        f"Account: {self.account_data.email} | Captcha answer incorrect, re-solving..."
                    )
                    if task_id:
                        await self.report_invalid_puzzle(task_id)

                elif error.error_message == "Email not verified , Please check spam folder incase you did not get email":
                    logger.error(
                        f"Account: {self.account_data.email} | Email not verified, run registration process again"
                    )

                    await file_operations.export_unverified_email(self.account_data.email, self.account_data.password)
                    for account in config.accounts_to_farm:
                        if account.email == self.account_data.email:
                            config.accounts_to_farm.remove(account)

                    return False

                else:
                    logger.warning(
                        f"Account: {self.account_data.email} | Captcha expired, re-solving..."
                    )

                return await self.login_new_account()

            logger.error(
                f"Account: {self.account_data.email} | Failed to login: {error}"
            )
            return False

        except CaptchaSolvingFailed:
            sleep_until = self.get_sleep_until()
            await Accounts.set_sleep_until(self.account_data.email, sleep_until)
            logger.error(
                f"Account: {self.account_data.email} | Failed to solve captcha after 5 attempts, sleeping..."
            )
            return False

        except Exception as error:
            logger.error(
                f"Account: {self.account_data.email} | Failed to login: {error}"
            )
            return False

    async def handle_existing_account(self, db_account_data) -> bool | None:
        if db_account_data.sleep_until and await self.handle_sleep(
            db_account_data.sleep_until
        ):
            return False

        self.session.headers = db_account_data.headers
        status, result = await self.verify_session()
        if not status:
            logger.warning(
                f"Account: {self.account_data.email} | Session is invalid, re-logging in: {result}"
            )
            await self.clear_account_and_session()
            return await self.process_farming()

        logger.info(f"Account: {self.account_data.email} | Using existing session")
        return True

    async def handle_session_blocked(self):
        await self.clear_account_and_session()
        logger.error(
            f"Account: {self.account_data.email} | Session rate-limited | Sleeping..."
        )
        sleep_until = self.get_sleep_until(blocked=True)
        await Accounts.set_session_blocked_until(self.account_data.email, sleep_until)

    async def handle_sleep(self, sleep_until):
        current_time = datetime.now(pytz.UTC)
        sleep_until = sleep_until.replace(tzinfo=pytz.UTC)

        if sleep_until > current_time:
            sleep_duration = (sleep_until - current_time).total_seconds()
            logger.debug(
                f"Account: {self.account_data.email} | Sleeping until {sleep_until} (duration: {sleep_duration:.2f} seconds)"
            )
            return True

        return False

    async def close_session(self):
        try:
            await self.session.close()
        except Exception as error:
            logger.debug(
                f"Account: {self.account_data.email} | Failed to close session: {error}"
            )

    async def perform_farming_actions(self):
        try:
            await self.keepalive()
            logger.success(
                f"Account: {self.account_data.email} | Sent keepalive request"
            )

            user_info = await self.user_info()
            logger.info(
                f"Account: {self.account_data.email} | Total points earned: {user_info['rewardPoint']['points']}"
            )

        except Exception as error:
            logger.error(
                f"Account: {self.account_data.email} | Failed to perform farming actions: {error}"
            )

        finally:
            new_sleep_until = self.get_sleep_until()
            await Accounts.set_sleep_until(
                email=self.account_data.email, sleep_until=new_sleep_until
            )


================================================
FILE: core/exceptions/base.py
================================================
class APIError(Exception):
    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"]
    """Base class for API exceptions"""

    def __init__(self, error: str, response_data: dict = None):
        self.error = error
        self.response_data = response_data

    @property
    def error_message(self) -> str:
        if self.response_data and "message" in self.response_data:
            return self.response_data["message"]

    def __str__(self):
        return self.error


class SessionRateLimited(Exception):
    """Raised when the session is rate limited"""

    pass


class CaptchaSolvingFailed(Exception):
    """Raised when the captcha solving failed"""

    pass


class ServerError(APIError):
    """Raised when the server returns an error"""

    pass


================================================
FILE: core/solvers/__init__.py
================================================
from .anti_captcha import AntiCaptchaImageSolver
from .two_captcha import TwoCaptchaImageSolver


================================================
FILE: core/solvers/anti_captcha.py
================================================
import asyncio
from typing import Any, Tuple
import httpx


class AntiCaptchaImageSolver:
    BASE_URL = "https://api.anti-captcha.com"

    def __init__(self, api_key: str):
        self.api_key = api_key
        self.client = httpx.AsyncClient(timeout=10)

    async def solve(self, image: str) -> Tuple[str, bool]:
        try:
            captcha_data = {
                "clientKey": self.api_key,
                "softId": 1201,
                "task": {
                    "type": "ImageToTextTask",
                    "body": image,
                    "phrase": False,
                    "case": True,
                    "numeric": 0,
                    "math": False,
                    "minLength": 6,
                    "maxLength": 6,
                    "comment": "Pay close attention to the letter case.",
                },
            }

            resp = await self.client.post(
                f"{self.BASE_URL}/createTask", json=captcha_data
            )
            resp.raise_for_status()
            data = resp.json()

            if data.get("errorId") == 0:
                return await self.get_captcha_result(data.get("taskId"))
            return data.get("errorDescription"), False

        except httpx.HTTPStatusError as err:
            return f"HTTP error occurred: {err}", False
        except Exception as err:
            return f"An unexpected error occurred: {err}", False

    async def get_captcha_result(self, task_id: int | str) -> Tuple[Any, bool]:
        for _ in range(10):
            try:
                resp = await self.client.post(
                    f"{self.BASE_URL}/getTaskResult",
                    json={"clientKey": self.api_key, "taskId": task_id},
                )
                resp.raise_for_status()
                result = resp.json()

                if result.get("errorId") != 0:
                    return result.get("errorDescription"), False

                if result.get("status") == "ready":
                    return result["solution"].get("text", ""), True

                await asyncio.sleep(3)

            except httpx.HTTPStatusError as err:
                return f"HTTP error occurred: {err}", False
            except Exception as err:
                return f"An unexpected error occurred: {err}", False

        return "Max time for solving exhausted", False

    async def report_bad(self, task_id: int | str) -> Tuple[Any, bool]:
        try:
            resp = await self.client.post(
                f"{self.BASE_URL}/reportIncorrectImageCaptcha",
                json={"clientKey": self.api_key, "taskId": task_id},
            )
            resp.raise_for_status()
            return resp.json(), True
        except httpx.HTTPStatusError as err:
            return f"HTTP error occurred: {err}", False
        except Exception as err:
            return f"An unexpected error occurred: {err}", False


================================================
FILE: core/solvers/two_captcha.py
================================================
import asyncio
from typing import Any, Tuple
import httpx


class TwoCaptchaImageSolver:
    BASE_URL = "https://api.2captcha.com"

    def __init__(self, api_key: str):
        self.api_key = api_key
        self.client = httpx.AsyncClient(timeout=10)

    async def solve(self, image: str) -> Tuple[str, bool]:
        try:
            captcha_data = {
                "clientKey": self.api_key,
                "softId": 4706,
                "task": {
                    "type": "ImageToTextTask",
                    "body": image,
                    "phrase": False,
                    "case": True,
                    "numeric": 4,
                    "math": False,
                    "minLength": 6,
                    "maxLength": 6,
                    "comment": "Pay close attention to the letter case.",
                },
            }

            resp = await self.client.post(
                f"{self.BASE_URL}/createTask", json=captcha_data
            )
            resp.raise_for_status()
            data = resp.json()

            if data.get("errorId") == 0:
                return await self.get_captcha_result(data.get("taskId"))
            return data.get("errorDescription"), False

        except httpx.HTTPStatusError as err:
            return f"HTTP error occurred: {err}", False
        except Exception as err:
            return f"An unexpected error occurred: {err}", False

    async def get_captcha_result(
        self, task_id: int | str
    ) -> tuple[Any, bool, int | str] | tuple[str, bool, int | str] | tuple[str, bool]:
        for _ in range(10):
            try:
                resp = await self.client.post(
                    f"{self.BASE_URL}/getTaskResult",
                    json={"clientKey": self.api_key, "taskId": task_id},
                )
                resp.raise_for_status()
                result = resp.json()

                if result.get("errorId") != 0:
                    return result.get("errorDescription"), False, task_id

                if result.get("status") == "ready":
                    return result["solution"].get("text", ""), True, task_id

                await asyncio.sleep(3)

            except httpx.HTTPStatusError as err:
                return f"HTTP error occurred: {err}", False, task_id
            except Exception as err:
                return f"An unexpected error occurred: {err}", False, task_id

        return "Max time for solving exhausted", False

    async def report_bad(self, task_id: str | int) -> Tuple[Any, bool]:
        try:
            resp = await self.client.post(
                f"{self.BASE_URL}/reportIncorrect",
                json={"clientKey": self.api_key, "taskId": task_id},
            )
            resp.raise_for_status()
            return resp.json(), True
        except httpx.HTTPStatusError as err:
            return f"HTTP error occurred: {err}", False
        except Exception as err:
            return f"An unexpected error occurred: {err}", False


================================================
FILE: database/__init__.py
================================================
from .models import Accounts
from .settings import initialize_database


================================================
FILE: database/models/__init__.py
================================================
from .accounts import Accounts


================================================
FILE: database/models/accounts.py
================================================
import pytz

from datetime import datetime
from tortoise import Model, fields
from loguru import logger


class Accounts(Model):
    email = fields.CharField(max_length=255, unique=True)
    headers = fields.JSONField(null=True)
    sleep_until = fields.DatetimeField(null=True)
    session_blocked_until = fields.DatetimeField(null=True)

    class Meta:
        table = "dawn_accounts_v1.4"

    @classmethod
    async def get_account(cls, email: str):
        return await cls.get_or_none(email=email)

    @classmethod
    async def get_accounts(cls):
        return await cls.all()

    @classmethod
    async def create_account(cls, email: str, headers: dict = None):
        account = await cls.get_account(email=email)
        if account is None:
            account = await cls.create(email=email, headers=headers)
            return account
        else:
            account.headers = headers
            await account.save()
            return account

    @classmethod
    async def delete_account(cls, email: str):
        account = await cls.get_account(email=email)
        if account is None:
            return False

        await account.delete()
        return True

    @classmethod
    async def set_sleep_until(cls, email: str, sleep_until: datetime):
        account = await cls.get_account(email=email)
        if account is None:
            return False

        if sleep_until.tzinfo is None:
            sleep_until = pytz.UTC.localize(sleep_until)
        else:
            sleep_until = sleep_until.astimezone(pytz.UTC)

        account.sleep_until = sleep_until
        await account.save()
        logger.info(f"Account: {email} | Set new sleep_until: {sleep_until}")
        return True

    @classmethod
    async def set_session_blocked_until(
        cls, email: str, session_blocked_until: datetime
    ):
        account = await cls.get_account(email=email)
        if account is None:
            account = await cls.create_account(email=email)
            account.session_blocked_until = session_blocked_until
            await account.save()
            logger.info(
                f"Account: {email} | Set new session_blocked_until: {session_blocked_until}"
            )
            return

        if session_blocked_until.tzinfo is None:
            session_blocked_until = pytz.UTC.localize(session_blocked_until)
        else:
            session_blocked_until = session_blocked_until.astimezone(pytz.UTC)

        account.session_blocked_until = session_blocked_until
        await account.save()
        logger.info(
            f"Account: {email} | Set new session_blocked_until: {session_blocked_until}"
        )


================================================
FILE: database/settings.py
================================================
from loguru import logger
from tortoise import Tortoise


async def initialize_database() -> None:
    try:
        await Tortoise.init(
            db_url="sqlite://database/database.sqlite3",
            modules={"models": ["database.models.accounts"]},
            timezone="UTC",
        )

        await Tortoise.generate_schemas(safe=True)

    except Exception as error:
        logger.error(f"Error while initializing database: {error}")
        exit(0)


================================================
FILE: loader.py
================================================
import asyncio

from core.solvers import *
from utils import load_config, FileOperations

config = load_config()
captcha_solver = (
    AntiCaptchaImageSolver(config.anti_captcha_api_key)
    if config.captcha_module == "anticaptcha"
    else TwoCaptchaImageSolver(config.two_captcha_api_key)
)
file_operations = FileOperations()
semaphore = asyncio.Semaphore(config.threads)


================================================
FILE: models/__init__.py
================================================
from .config import *
from .bot import *


================================================
FILE: models/bot.py
================================================
from typing import Literal, TypedDict


ModuleType = Literal["register", "tasks", "stats", "accounts"]


class OperationResult(TypedDict):
    identifier: str
    data: str
    status: bool


class StatisticData(TypedDict):
    success: bool
    referralPoint: dict | None
    rewardPoint: dict | None


================================================
FILE: models/config.py
================================================
from typing import Literal

from better_proxy import Proxy
from pydantic import BaseModel, PositiveInt, ConfigDict


class Account(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)

    email: str
    password: str
    imap_server: str = ""
    proxy: Proxy


class Config(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)

    class DelayBeforeStart(BaseModel):
        min: int
        max: int

    accounts_to_register: list[Account] = []
    accounts_to_farm: list[Account] = []
    referral_code: str = ""
    two_captcha_api_key: str = ""
    anti_captcha_api_key: str = ""
    delay_before_start: DelayBeforeStart

    threads: PositiveInt
    imap_settings: dict[str, str]

    keepalive_interval: PositiveInt
    module: str = ""
    captcha_module: Literal["2captcha", "anticaptcha"] = ""


================================================
FILE: requirements.txt
================================================
names~=0.3.0
curl_cffi~=0.7.1
pytz~=2024.1
loguru~=0.7.2
httpx~=0.27.0
urllib3~=2.2.2
art~=6.2
PyYAML~=6.0.2
pydantic~=2.8.2
inquirer~=3.3.0
colorama~=0.4.6
better_proxy
tortoise-orm
imap_tools
numpy~=1.26.4
aiofiles~=24.1.0
aiocsv~=1.3.2
rich~=13.9.2

================================================
FILE: run.py
================================================
import asyncio
import random
import sys
from typing import Callable, Coroutine, Any, List, Set

from loguru import logger
from loader import config, semaphore, file_operations
from core.bot import Bot
from models import Account
from utils import setup
from console import Console
from database import initialize_database


accounts_with_initial_delay: Set[str] = set()


async def run_module_safe(
        account: Account, process_func: Callable[[Bot], Coroutine[Any, Any, Any]]
) -> Any:
    global accounts_with_initial_delay

    async with semaphore:
        bot = Bot(account)
        try:
            if config.delay_before_start.min > 0:
                if process_func == process_farming and account.email not in accounts_with_initial_delay:
                    random_delay = random.randint(config.delay_before_start.min, config.delay_before_start.max)
                    logger.info(f"Account: {account.email} | Initial farming delay: {random_delay} sec")
                    await asyncio.sleep(random_delay)
                    accounts_with_initial_delay.add(account.email)

                elif process_func != process_farming:
                    random_delay = random.randint(config.delay_before_start.min, config.delay_before_start.max)
                    logger.info(f"Account: {account.email} | Sleep for {random_delay} sec")
                    await asyncio.sleep(random_delay)

            result = await process_func(bot)
            return result
        finally:
            await bot.close_session()


async def process_registration(bot: Bot) -> None:
    operation_result = await bot.process_registration()
    await file_operations.export_result(operation_result, "register")


async def process_farming(bot: Bot) -> None:
    await bot.process_farming()


async def process_export_stats(bot: Bot) -> None:
    data = await bot.process_get_user_info()
    await file_operations.export_stats(data)


async def process_complete_tasks(bot: Bot) -> None:
    operation_result = await bot.process_complete_tasks()
    await file_operations.export_result(operation_result, "tasks")


async def run_module(
        accounts: List[Account], process_func: Callable[[Bot], Coroutine[Any, Any, Any]]
) -> tuple[Any]:
    tasks = [run_module_safe(account, process_func) for account in accounts]
    return await asyncio.gather(*tasks)


async def farm_continuously(accounts: List[Account]) -> None:
    while True:
        random.shuffle(accounts)
        await run_module(accounts, process_farming)
        await asyncio.sleep(10)


def reset_initial_delays():
    global accounts_with_initial_delay
    accounts_with_initial_delay.clear()


async def run() -> None:
    await initialize_database()
    await file_operations.setup_files()
    reset_initial_delays()

    module_map = {
        "register": (config.accounts_to_register, process_registration),
        "farm": (config.accounts_to_farm, farm_continuously),
        "complete_tasks": (config.accounts_to_farm, process_complete_tasks),
        "export_stats": (config.accounts_to_farm, process_export_stats),
    }

    while True:
        Console().build()

        if config.module not in module_map:
            logger.error(f"Unknown module: {config.module}")
            break

        accounts, process_func = module_map[config.module]

        if not accounts:
            logger.error(f"No accounts for {config.module}")
            break

        if config.module == "farm":
            await process_func(accounts)
        else:
            await run_module(accounts, process_func)
            input("\n\nPress Enter to continue...")


if __name__ == "__main__":
    if sys.platform == "win32":
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

    setup()
    asyncio.run(run())

================================================
FILE: utils/__init__.py
================================================
from .load_config import load_config
from .console import *
from .file_utils import *
from .imap_utils import *


================================================
FILE: utils/console.py
================================================
import os
import sys

import urllib3
from art import tprint
from loguru import logger


def setup():
    urllib3.disable_warnings()
    logger.remove()
    logger.add(
        sys.stdout,
        colorize=True,
        format="<light-cyan>{time:HH:mm:ss}</light-cyan> | <level> {level: <8}</level> | - <white>{"
        "message}</white>",
    )
    logger.add("./logs/logs.log", rotation="1 day", retention="7 days")


def show_dev_info():
    os.system("cls")
    tprint("JamBit")
    print("\033[36m" + "我的推特主页: " + "\033[34m" + "https://x.com/Hy78516012" + "\033[34m")
    print(
        "\033[36m"
        + "我的GitHub: "
        + "\033[34m"
        + "https://github.com/Gzgod"
        + "\033[34m"
    )
    print()


================================================
FILE: utils/file_utils.py
================================================
import asyncio

import aiofiles

from pathlib import Path
from aiocsv import AsyncWriter
from models import ModuleType, OperationResult, StatisticData



class FileOperations:
    def __init__(self, base_path: str = "./results"):
        self.base_path = Path(base_path)
        self.lock = asyncio.Lock()
        self.module_paths: dict[ModuleType, dict[str, Path]] = {
            "register": {
                "success": self.base_path / "registration_success.txt",
                "failed": self.base_path / "registration_failed.txt",
            },
            "tasks": {
                "success": self.base_path / "tasks_success.txt",
                "failed": self.base_path / "tasks_failed.txt",
            },
            "stats": {
                "base": self.base_path / "accounts_stats.csv",
            },
            "accounts": {
                "unverified": self.base_path / "unverified_accounts.txt",
            },
        }

    async def setup_files(self):
        self.base_path.mkdir(exist_ok=True)
        for module_paths in self.module_paths.values():
            for path in module_paths.values():
                path.touch(exist_ok=True)

        async with aiofiles.open(self.module_paths["stats"]["base"], "w") as f:
            writer = AsyncWriter(f)
            await writer.writerow(
                [
                    "Email",
                    "Referral Code",
                    "Points",
                    "Referral Points",
                    "Total Points",
                    "Registration Date",
                    "Completed Tasks",
                ]
            )

    async def export_result(self, result: OperationResult, module: ModuleType):
        if module not in self.module_paths:
            raise ValueError(f"Unknown module: {module}")

        file_path = self.module_paths[module][
            "success" if result["status"] else "failed"
        ]
        async with self.lock:
            try:
                async with aiofiles.open(file_path, "a") as file:
                    await file.write(f"{result['identifier']}:{result['data']}\n")
            except IOError as e:
                print(f"Error writing to file: {e}")


    async def export_unverified_email(self, email: str, password: str):
        file_path = self.module_paths["accounts"]["unverified"]
        async with self.lock:
            try:
                async with aiofiles.open(file_path, "a") as file:
                    await file.write(f"{email}:{password}\n")
            except IOError as e:
                print(f"Error writing to file: {e}")


    async def export_stats(self, data: StatisticData):
        file_path = self.module_paths["stats"]["base"]
        async with self.lock:
            try:
                async with aiofiles.open(file_path, mode="a", newline="") as f:
                    writer = AsyncWriter(f)

                    if not data or not data["referralPoint"] or not data["rewardPoint"]:
                        return

                    await writer.writerow(
                        [
                            data["referralPoint"]["email"],
                            data["referralPoint"]["referralCode"],
                            data["rewardPoint"]["points"],
                            data["referralPoint"]["commission"],
                            float(data["rewardPoint"]["points"])
                            + float(data["referralPoint"]["commission"]),
                            data["rewardPoint"]["registerpointsdate"],
                            (
                                True
                                if data["rewardPoint"]["twitter_x_id_points"] == 5000
                                and data["rewardPoint"]["discordid_points"] == 5000
                                and data["rewardPoint"]["telegramid_points"] == 5000
                                else False
                            ),
                        ]
                    )

            except IOError as e:
                print(f"Error writing to file: {e}")


================================================
FILE: utils/imap_utils.py
================================================
import re
from typing import Optional
import asyncio

from loguru import logger
from imap_tools import MailBox, AND


async def check_if_email_valid(
    imap_server: str,
    email: str,
    password: str,
) -> bool:
    logger.info(f"Account: {email} | Checking if email is valid...")

    try:
        await asyncio.to_thread(lambda: MailBox(imap_server).login(email, password))
        return True
    except Exception as error:
        logger.error(f"Account: {email} | Email is invalid (IMAP): {error}")
        return False


async def check_email_for_link(
    imap_server: str,
    email: str,
    password: str,
    max_attempts: int = 8,
    delay_seconds: int = 5,
) -> Optional[str]:
    link_pattern = (
        r"https://www\.aeropres\.in/chromeapi/dawn/v1/user/verifylink\?key=[a-f0-9-]+"
    )
    logger.info(f"Account: {email} | Checking email for link...")

    try:

        async def search_in_mailbox():
            return await asyncio.to_thread(
                lambda: search_for_link_sync(
                    MailBox(imap_server).login(email, password), link_pattern
                )
            )

        for attempt in range(max_attempts):
            link = await search_in_mailbox()
            if link:
                return link

            if attempt < max_attempts - 1:
                logger.info(
                    f"Account: {email} | Link not found. Waiting {delay_seconds} seconds before next attempt..."
                )
                await asyncio.sleep(delay_seconds)

        logger.warning(
            f"Account: {email} | Link not found after {max_attempts} attempts, searching in spam folder..."
        )

        spam_folders = ("SPAM", "Spam", "spam", "Junk", "junk", "Spamverdacht")
        for spam_folder in spam_folders:

            async def search_in_spam():
                return await asyncio.to_thread(
                    lambda: search_for_link_in_spam_sync(
                        MailBox(imap_server).login(email, password),
                        link_pattern,
                        spam_folder,
                    )
                )

            link = await search_in_spam()
            if link:
                return link

        logger.error(
            f"Account: {email} | Link not found in spam folder after multiple attempts"
        )
        return None

    except Exception as error:
        logger.error(f"Account: {email} | Failed to check email for link: {error}")
        return None


def search_for_link_sync(mailbox: MailBox, link_pattern: str) -> Optional[str]:
    messages = mailbox.fetch()

    for msg in messages:
        if msg.from_ == "hello@dawninternet.com":
            body = msg.text or msg.html
            if body:
                match = re.search(link_pattern, body)
                if match:
                    return match.group(0)

    return None


def search_for_link_in_spam_sync(
    mailbox: MailBox, link_pattern: str, spam_folder: str
) -> Optional[str]:
    if mailbox.folder.exists(spam_folder):
        mailbox.folder.set(spam_folder)
        return search_for_link_sync(mailbox, link_pattern)
    return None


================================================
FILE: utils/load_config.py
================================================
import os
import yaml
from itertools import cycle
from loguru import logger
from models import Config, Account
from better_proxy import Proxy
from typing import List, Dict, Generator

CONFIG_PATH = os.path.join(os.getcwd(), "config")
CONFIG_DATA_PATH = os.path.join(CONFIG_PATH, "data")
CONFIG_PARAMS = os.path.join(CONFIG_PATH, "settings.yaml")

REQUIRED_DATA_FILES = ("accounts.txt", "proxies.txt")
REQUIRED_PARAMS_FIELDS = (
    "threads",
    "keepalive_interval",
    "imap_settings",
    "captcha_module",
    "delay_before_start",
    "referral_code",
)


def read_file(
    file_path: str, check_empty: bool = True, is_yaml: bool = False
) -> List[str] | Dict:
    if not os.path.exists(file_path):
        raise FileNotFoundError(f"File not found: {file_path}")

    if check_empty and os.stat(file_path).st_size == 0:
        raise ValueError(f"File is empty: {file_path}")

    if is_yaml:
        with open(file_path, "r", encoding="utf-8") as file:
            return yaml.safe_load(file)

    with open(file_path, "r", encoding="utf-8") as file:
        return [line.strip() for line in file]


def get_params() -> Dict:
    data = read_file(CONFIG_PARAMS, is_yaml=True)
    missing_fields = set(REQUIRED_PARAMS_FIELDS) - set(data.keys())
    if missing_fields:
        raise ValueError(f"Missing fields in config file: {', '.join(missing_fields)}")
    return data


def get_proxies() -> List[Proxy]:
    try:
        proxies = read_file(
            os.path.join(CONFIG_DATA_PATH, "proxies.txt"), check_empty=False
        )
        return [Proxy.from_str(line) for line in proxies] if proxies else []
    except Exception as exc:
        raise ValueError(f"Failed to parse proxy: {exc}")


def get_accounts(file_name: str) -> Generator[Account, None, None]:
    proxies = get_proxies()
    proxy_cycle = cycle(proxies) if proxies else None
    accounts = read_file(os.path.join(CONFIG_DATA_PATH, file_name), check_empty=False)

    for account in accounts:
        try:
            email, password = account.split(":")
            yield Account(
                email=email,
                password=password,
                proxy=next(proxy_cycle) if proxy_cycle else None,
            )
        except ValueError:
            logger.error(f"Failed to parse account: {account}")


def validate_domains(accounts: List[Account], domains: Dict[str, str]) -> List[Account]:
    for account in accounts:
        domain = account.email.split("@")[1]
        if domain not in domains:
            raise ValueError(
                f"Domain '{domain}' is not supported, please add it to the config file"
            )
        account.imap_server = domains[domain]
    return accounts


def load_config() -> Config:
    try:
        reg_accounts = list(get_accounts("register.txt"))
        farm_accounts = list(get_accounts("farm.txt"))

        if not reg_accounts and not farm_accounts:
            raise ValueError("No accounts found in data files")

        params = get_params()
        config = Config(
            **params, accounts_to_farm=farm_accounts, accounts_to_register=reg_accounts
        )

        if reg_accounts:
            config.accounts_to_register = validate_domains(
                reg_accounts, config.imap_settings
            )

        if config.captcha_module == "2captcha" and not config.two_captcha_api_key:
            raise ValueError("2Captcha API key is missing")
        elif config.captcha_module == "anticaptcha" and not config.anti_captcha_api_key:
            raise ValueError("AntiCaptcha API key is missing")

        return config

    except Exception as exc:
        logger.error(f"Failed to load config: {exc}")
        exit(1)
Download .txt
gitextract_p0kopyhp/

├── README.md
├── config/
│   ├── data/
│   │   ├── farm.txt
│   │   ├── proxies.txt
│   │   └── register.txt
│   └── settings.yaml
├── console/
│   ├── __init__.py
│   ├── logger.py
│   └── main.py
├── core/
│   ├── api.py
│   ├── bot.py
│   ├── exceptions/
│   │   └── base.py
│   └── solvers/
│       ├── __init__.py
│       ├── anti_captcha.py
│       └── two_captcha.py
├── database/
│   ├── __init__.py
│   ├── models/
│   │   ├── __init__.py
│   │   └── accounts.py
│   └── settings.py
├── loader.py
├── models/
│   ├── __init__.py
│   ├── bot.py
│   └── config.py
├── requirements.txt
├── run.py
└── utils/
    ├── __init__.py
    ├── console.py
    ├── file_utils.py
    ├── imap_utils.py
    └── load_config.py
Download .txt
SYMBOL INDEX (99 symbols across 16 files)

FILE: console/logger.py
  function error_log (line 4) | def error_log(message: str):
  function success_log (line 8) | def success_log(message: str):
  function info_log (line 12) | def info_log(message: str):

FILE: console/main.py
  class Console (line 19) | class Console:
    method __init__ (line 35) | def __init__(self):
    method show_dev_info (line 38) | def show_dev_info(self):
    method prompt (line 60) | def prompt(data: list):
    method get_module (line 64) | def get_module(self):
    method display_info (line 76) | def display_info(self):
    method build (line 98) | def build(self) -> None:

FILE: core/api.py
  class DawnExtensionAPI (line 14) | class DawnExtensionAPI:
    method __init__ (line 17) | def __init__(self, account: Account):
    method setup_session (line 22) | def setup_session(self) -> AsyncSession:
    method clear_request (line 41) | async def clear_request(self, url: str):
    method send_request (line 48) | async def send_request(
    method solve_puzzle (line 156) | async def solve_puzzle(
    method report_invalid_puzzle (line 163) | async def report_invalid_puzzle(task_id: int | str) -> None:
    method get_puzzle_id (line 166) | async def get_puzzle_id(self) -> str:
    method get_puzzle_image (line 182) | async def get_puzzle_image(self, puzzle_id: str) -> str:
    method register (line 191) | async def register(self, puzzle_id: str, answer: str) -> dict:
    method keepalive (line 209) | async def keepalive(self) -> dict | str:
    method user_info (line 238) | async def user_info(self) -> dict:
    method complete_tasks (line 257) | async def complete_tasks(self, tasks: list[str] = None, delay: int = 1...
    method verify_session (line 279) | async def verify_session(self) -> tuple[bool, str]:
    method login (line 290) | async def login(self, puzzle_id: str, answer: str):

FILE: core/bot.py
  class Bot (line 15) | class Bot(DawnExtensionAPI):
    method __init__ (line 16) | def __init__(self, account: Account):
    method get_captcha_data (line 19) | async def get_captcha_data(self) -> Tuple[str, Any, Optional[Any]]:
    method clear_account_and_session (line 53) | async def clear_account_and_session(self) -> None:
    method process_reverify_email (line 58) | async def process_reverify_email(self) -> OperationResult:
    method process_registration (line 108) | async def process_registration(self) -> OperationResult:
    method get_sleep_until (line 201) | def get_sleep_until(blocked: bool = False) -> datetime:
    method process_farming (line 209) | async def process_farming(self) -> None:
    method process_get_user_info (line 242) | async def process_get_user_info(self) -> StatisticData:
    method process_complete_tasks (line 286) | async def process_complete_tasks(self) -> OperationResult:
    method login_new_account (line 321) | async def login_new_account(self):
    method handle_existing_account (line 383) | async def handle_existing_account(self, db_account_data) -> bool | None:
    method handle_session_blocked (line 401) | async def handle_session_blocked(self):
    method handle_sleep (line 409) | async def handle_sleep(self, sleep_until):
    method close_session (line 422) | async def close_session(self):
    method perform_farming_actions (line 430) | async def perform_farming_actions(self):

FILE: core/exceptions/base.py
  class APIError (line 1) | class APIError(Exception):
    method __init__ (line 5) | def __init__(self, error: str, response_data: dict = None):
    method error_message (line 10) | def error_message(self) -> str:
    method __str__ (line 14) | def __str__(self):
  class SessionRateLimited (line 18) | class SessionRateLimited(Exception):
  class CaptchaSolvingFailed (line 24) | class CaptchaSolvingFailed(Exception):
  class ServerError (line 30) | class ServerError(APIError):

FILE: core/solvers/anti_captcha.py
  class AntiCaptchaImageSolver (line 6) | class AntiCaptchaImageSolver:
    method __init__ (line 9) | def __init__(self, api_key: str):
    method solve (line 13) | async def solve(self, image: str) -> Tuple[str, bool]:
    method get_captcha_result (line 46) | async def get_captcha_result(self, task_id: int | str) -> Tuple[Any, b...
    method report_bad (line 71) | async def report_bad(self, task_id: int | str) -> Tuple[Any, bool]:

FILE: core/solvers/two_captcha.py
  class TwoCaptchaImageSolver (line 6) | class TwoCaptchaImageSolver:
    method __init__ (line 9) | def __init__(self, api_key: str):
    method solve (line 13) | async def solve(self, image: str) -> Tuple[str, bool]:
    method get_captcha_result (line 46) | async def get_captcha_result(
    method report_bad (line 73) | async def report_bad(self, task_id: str | int) -> Tuple[Any, bool]:

FILE: database/models/accounts.py
  class Accounts (line 8) | class Accounts(Model):
    class Meta (line 14) | class Meta:
    method get_account (line 18) | async def get_account(cls, email: str):
    method get_accounts (line 22) | async def get_accounts(cls):
    method create_account (line 26) | async def create_account(cls, email: str, headers: dict = None):
    method delete_account (line 37) | async def delete_account(cls, email: str):
    method set_sleep_until (line 46) | async def set_sleep_until(cls, email: str, sleep_until: datetime):
    method set_session_blocked_until (line 62) | async def set_session_blocked_until(

FILE: database/settings.py
  function initialize_database (line 5) | async def initialize_database() -> None:

FILE: models/bot.py
  class OperationResult (line 7) | class OperationResult(TypedDict):
  class StatisticData (line 13) | class StatisticData(TypedDict):

FILE: models/config.py
  class Account (line 7) | class Account(BaseModel):
  class Config (line 16) | class Config(BaseModel):
    class DelayBeforeStart (line 19) | class DelayBeforeStart(BaseModel):

FILE: run.py
  function run_module_safe (line 18) | async def run_module_safe(
  function process_registration (line 44) | async def process_registration(bot: Bot) -> None:
  function process_farming (line 49) | async def process_farming(bot: Bot) -> None:
  function process_export_stats (line 53) | async def process_export_stats(bot: Bot) -> None:
  function process_complete_tasks (line 58) | async def process_complete_tasks(bot: Bot) -> None:
  function run_module (line 63) | async def run_module(
  function farm_continuously (line 70) | async def farm_continuously(accounts: List[Account]) -> None:
  function reset_initial_delays (line 77) | def reset_initial_delays():
  function run (line 82) | async def run() -> None:

FILE: utils/console.py
  function setup (line 9) | def setup():
  function show_dev_info (line 21) | def show_dev_info():

FILE: utils/file_utils.py
  class FileOperations (line 11) | class FileOperations:
    method __init__ (line 12) | def __init__(self, base_path: str = "./results"):
    method setup_files (line 32) | async def setup_files(self):
    method export_result (line 52) | async def export_result(self, result: OperationResult, module: ModuleT...
    method export_unverified_email (line 67) | async def export_unverified_email(self, email: str, password: str):
    method export_stats (line 77) | async def export_stats(self, data: StatisticData):

FILE: utils/imap_utils.py
  function check_if_email_valid (line 9) | async def check_if_email_valid(
  function check_email_for_link (line 24) | async def check_email_for_link(
  function search_for_link_sync (line 86) | def search_for_link_sync(mailbox: MailBox, link_pattern: str) -> Optiona...
  function search_for_link_in_spam_sync (line 100) | def search_for_link_in_spam_sync(

FILE: utils/load_config.py
  function read_file (line 24) | def read_file(
  function get_params (line 41) | def get_params() -> Dict:
  function get_proxies (line 49) | def get_proxies() -> List[Proxy]:
  function get_accounts (line 59) | def get_accounts(file_name: str) -> Generator[Account, None, None]:
  function validate_domains (line 76) | def validate_domains(accounts: List[Account], domains: Dict[str, str]) -...
  function load_config (line 87) | def load_config() -> Config:
Condensed preview — 29 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (68K chars).
[
  {
    "path": "README.md",
    "chars": 2009,
    "preview": "# Dawn Extension Bot [1.5]\n# 原作者https://github.com/Jaammerr/The-Dawn-Bot 防止正义人士\n<div align=\"center\">\n  <img src=\"./conso"
  },
  {
    "path": "config/data/farm.txt",
    "chars": 23,
    "preview": "test@gmail.com:password"
  },
  {
    "path": "config/data/proxies.txt",
    "chars": 12,
    "preview": "http://proxy"
  },
  {
    "path": "config/data/register.txt",
    "chars": 23,
    "preview": "test@gmail.com:password"
  },
  {
    "path": "config/settings.yaml",
    "chars": 1411,
    "preview": "# Application Configuration File\n# =============================\n\n# Core Settings\n# ------------\nthreads: 10            "
  },
  {
    "path": "console/__init__.py",
    "chars": 26,
    "preview": "from .main import Console\n"
  },
  {
    "path": "console/logger.py",
    "chars": 323,
    "preview": "from colorama import Fore\n\n\ndef error_log(message: str):\n    print(Fore.RED + \">> ERROR |\" + Fore.LIGHTBLACK_EX + f\" {me"
  },
  {
    "path": "console/main.py",
    "chars": 3041,
    "preview": "import os\nimport sys\nimport inquirer\n\nfrom inquirer.themes import GreenPassion\nfrom art import text2art\nfrom colorama im"
  },
  {
    "path": "core/api.py",
    "chars": 10822,
    "preview": "import asyncio\nimport json\nimport names\n\nfrom datetime import datetime, timezone\nfrom typing import Literal, Tuple, Any\n"
  },
  {
    "path": "core/bot.py",
    "chars": 17014,
    "preview": "from datetime import datetime, timedelta\nfrom typing import Tuple, Any, Optional\n\nimport pytz\nfrom loguru import logger\n"
  },
  {
    "path": "core/exceptions/base.py",
    "chars": 890,
    "preview": "class APIError(Exception):\n    BASE_MESSAGES = [\"refresh your captcha!!\", \"Incorrect answer. Try again!\", \"Email not ver"
  },
  {
    "path": "core/solvers/__init__.py",
    "chars": 96,
    "preview": "from .anti_captcha import AntiCaptchaImageSolver\nfrom .two_captcha import TwoCaptchaImageSolver\n"
  },
  {
    "path": "core/solvers/anti_captcha.py",
    "chars": 2911,
    "preview": "import asyncio\nfrom typing import Any, Tuple\nimport httpx\n\n\nclass AntiCaptchaImageSolver:\n    BASE_URL = \"https://api.an"
  },
  {
    "path": "core/solvers/two_captcha.py",
    "chars": 3004,
    "preview": "import asyncio\nfrom typing import Any, Tuple\nimport httpx\n\n\nclass TwoCaptchaImageSolver:\n    BASE_URL = \"https://api.2ca"
  },
  {
    "path": "database/__init__.py",
    "chars": 71,
    "preview": "from .models import Accounts\nfrom .settings import initialize_database\n"
  },
  {
    "path": "database/models/__init__.py",
    "chars": 31,
    "preview": "from .accounts import Accounts\n"
  },
  {
    "path": "database/models/accounts.py",
    "chars": 2667,
    "preview": "import pytz\n\nfrom datetime import datetime\nfrom tortoise import Model, fields\nfrom loguru import logger\n\n\nclass Accounts"
  },
  {
    "path": "database/settings.py",
    "chars": 462,
    "preview": "from loguru import logger\nfrom tortoise import Tortoise\n\n\nasync def initialize_database() -> None:\n    try:\n        awai"
  },
  {
    "path": "loader.py",
    "chars": 376,
    "preview": "import asyncio\n\nfrom core.solvers import *\nfrom utils import load_config, FileOperations\n\nconfig = load_config()\ncaptcha"
  },
  {
    "path": "models/__init__.py",
    "chars": 41,
    "preview": "from .config import *\nfrom .bot import *\n"
  },
  {
    "path": "models/bot.py",
    "chars": 302,
    "preview": "from typing import Literal, TypedDict\n\n\nModuleType = Literal[\"register\", \"tasks\", \"stats\", \"accounts\"]\n\n\nclass Operation"
  },
  {
    "path": "models/config.py",
    "chars": 844,
    "preview": "from typing import Literal\n\nfrom better_proxy import Proxy\nfrom pydantic import BaseModel, PositiveInt, ConfigDict\n\n\ncla"
  },
  {
    "path": "requirements.txt",
    "chars": 251,
    "preview": "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"
  },
  {
    "path": "run.py",
    "chars": 3802,
    "preview": "import asyncio\nimport random\nimport sys\nfrom typing import Callable, Coroutine, Any, List, Set\n\nfrom loguru import logge"
  },
  {
    "path": "utils/__init__.py",
    "chars": 112,
    "preview": "from .load_config import load_config\nfrom .console import *\nfrom .file_utils import *\nfrom .imap_utils import *\n"
  },
  {
    "path": "utils/console.py",
    "chars": 723,
    "preview": "import os\nimport sys\n\nimport urllib3\nfrom art import tprint\nfrom loguru import logger\n\n\ndef setup():\n    urllib3.disable"
  },
  {
    "path": "utils/file_utils.py",
    "chars": 4066,
    "preview": "import asyncio\n\nimport aiofiles\n\nfrom pathlib import Path\nfrom aiocsv import AsyncWriter\nfrom models import ModuleType, "
  },
  {
    "path": "utils/imap_utils.py",
    "chars": 3147,
    "preview": "import re\nfrom typing import Optional\nimport asyncio\n\nfrom loguru import logger\nfrom imap_tools import MailBox, AND\n\n\nas"
  },
  {
    "path": "utils/load_config.py",
    "chars": 3688,
    "preview": "import os\nimport yaml\nfrom itertools import cycle\nfrom loguru import logger\nfrom models import Config, Account\nfrom bett"
  }
]

About this extraction

This page contains the full source code of the GzGod/Dawn GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 29 files (60.7 KB), approximately 13.8k tokens, and a symbol index with 99 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!