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 防止正义人士
**我的推特: [@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="{time:HH:mm:ss} | {level: <8} | - {"
"message}",
)
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)