Skip to content

Commit 7806dd0

Browse files
committed
fix: access_hash gathering
1 parent a486156 commit 7806dd0

File tree

4 files changed

+159
-32
lines changed

4 files changed

+159
-32
lines changed

scripts/manage_account.py

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import getpass
55
import argparse
66
import logging
7-
from typing import Dict
7+
from typing import Dict, Optional
88

99
# Add project root to sys.path
1010
project_root = Path(__file__).resolve().parent.parent
@@ -19,25 +19,29 @@
1919
import userbot.src.db_manager as db_manager
2020
from userbot.src.encrypt import encryption_manager
2121

22-
logging.basicConfig(level=logging.WARNING)
22+
logging.basicConfig(level=logging.WARNING, format='%(name)s - %(levelname)s - %(message)s')
2323
logger = logging.getLogger('manage_account_cli')
2424
logger.setLevel(logging.INFO)
2525

26-
async def add_account_logic(args):
26+
async def add_account_logic(args: argparse.Namespace) -> None:
2727
"""
28-
Logic to add a new account with a full interactive Telethon login session.
28+
Handles the logic for adding a new account with a full interactive session.
29+
Allows for detailed configuration of device, proxy, and other settings.
30+
31+
Args:
32+
args (argparse.Namespace): The command-line arguments, expecting `args.name`.
2933
"""
3034
logger.info(f"--- Adding new account: {args.name} ---")
3135

32-
temp_client = None
36+
temp_client: Optional[TelegramClient] = None
3337
try:
3438
async with get_db() as db:
3539
if await db_manager.get_account(db, args.name):
3640
logger.error(f"Error: Account '{args.name}' already exists.")
3741
return
3842

39-
api_id = input("Enter API ID: ").strip()
40-
api_hash = getpass.getpass("Enter API Hash: ").strip()
43+
api_id: str = input("Enter API ID: ").strip()
44+
api_hash: str = getpass.getpass("Enter API Hash: ").strip()
4145

4246
if not api_id.isdigit() or not api_hash:
4347
logger.error("Error: API ID must be a number and API Hash cannot be empty.")
@@ -48,33 +52,80 @@ async def add_account_logic(args):
4852
await temp_client.connect()
4953

5054
if not await temp_client.is_user_authorized():
51-
phone_number = input("Session not found. Please enter your phone number (e.g., +1234567890): ").strip()
55+
phone_number: str = input("Session not found. Please enter your phone number (e.g., +1234567890): ").strip()
5256
await temp_client.send_code_request(phone_number)
53-
code = input("Please enter the code you received: ").strip()
57+
code: str = input("Please enter the code you received: ").strip()
5458
try:
5559
await temp_client.sign_in(phone_number, code)
5660
except SessionPasswordNeededError:
57-
two_fa_password = getpass.getpass("2FA Password required: ").strip()
61+
two_fa_password: str = getpass.getpass("2FA Password required: ").strip()
5862
await temp_client.sign_in(password=two_fa_password)
5963

6064
me = await temp_client.get_me(input_peer=True)
61-
user_id = me.user_id
62-
access_hash = me.access_hash
65+
user_id: int = me.user_id
66+
access_hash: int = me.access_hash
6367
logger.info(f"Successfully logged in as user ID: {user_id}.")
6468

6569
existing_by_id = await db_manager.get_account_by_user_id(db, user_id)
6670
if existing_by_id:
6771
logger.error(f"Error: This Telegram account (ID: {user_id}) already exists as '{existing_by_id.account_name}'.")
6872
return
6973

70-
device_details = _generate_random_device()
71-
lang_code = input(f"Enter language code (e.g., ru, en) [ru]: ").strip() or 'ru'
72-
is_enabled = (input("Enable this account now? (yes/no) [yes]: ").strip().lower() or 'yes').startswith('y')
73-
74+
# --- Interactive Configuration ---
75+
print("\n--- Account Configuration ---")
76+
lang_code: str = input(f"Enter language code (e.g., ru, en) [ru]: ").strip() or 'ru'
77+
is_enabled: bool = (input("Enable this account now? (yes/no) [yes]: ").strip().lower() or 'yes').startswith('y')
78+
79+
# Device Configuration
80+
if (input("Configure custom device details? (yes/no) [no]: ").strip().lower()).startswith('y'):
81+
device_model: str = input("Enter device model: ").strip()
82+
system_version: str = input("Enter system version: ").strip()
83+
app_version: str = input("Enter app version: ").strip()
84+
else:
85+
device_details: Dict[str, str] = _generate_random_device()
86+
device_model = device_details['device_model']
87+
system_version = device_details['system_version']
88+
app_version = device_details['app_version']
89+
logger.info("Generated random device details.")
90+
91+
# Proxy Configuration
92+
proxy_type: Optional[str] = None
93+
proxy_ip: Optional[str] = None
94+
proxy_port: Optional[int] = None
95+
proxy_username: Optional[str] = None
96+
proxy_password: Optional[str] = None
97+
if (input("Configure a proxy for this account? (yes/no) [no]: ").strip().lower()).startswith('y'):
98+
proxy_type_input = ""
99+
while proxy_type_input not in ["http", "socks4", "socks5"]:
100+
proxy_type_input = input("Enter proxy type (http, socks4, socks5): ").strip().lower()
101+
proxy_type = proxy_type_input
102+
proxy_ip = input("Enter proxy IP address: ").strip()
103+
proxy_port_str = ""
104+
while not proxy_port_str.isdigit():
105+
proxy_port_str = input("Enter proxy port: ").strip()
106+
proxy_port = int(proxy_port_str)
107+
if (input("Does the proxy require authentication? (yes/no) [no]: ").strip().lower()).startswith('y'):
108+
proxy_username = input("Enter proxy username: ").strip()
109+
proxy_password = getpass.getpass("Enter proxy password: ").strip()
110+
111+
logger.info("\nSaving account to the database...")
74112
new_account = await db_manager.add_account(
75-
db, args.name, api_id, api_hash, lang_code, is_enabled,
76-
device_details['device_model'], device_details['system_version'], device_details['app_version'],
77-
user_id, access_hash
113+
db,
114+
account_name=args.name,
115+
api_id=api_id,
116+
api_hash=api_hash,
117+
lang_code=lang_code,
118+
is_enabled=is_enabled,
119+
device_model=device_model,
120+
system_version=system_version,
121+
app_version=app_version,
122+
user_telegram_id=user_id,
123+
access_hash=access_hash,
124+
proxy_type=proxy_type,
125+
proxy_ip=proxy_ip,
126+
proxy_port=proxy_port,
127+
proxy_username=proxy_username,
128+
proxy_password=proxy_password
78129
)
79130

80131
if new_account:
@@ -89,7 +140,7 @@ async def add_account_logic(args):
89140
await temp_client.disconnect()
90141

91142

92-
async def edit_account_logic(args):
143+
async def edit_account_logic(args: argparse.Namespace) -> None:
93144
"""Logic to edit an account's properties."""
94145
logger.info(f"--- Editing account: {args.name} ---")
95146
async with get_db() as db:
@@ -108,7 +159,8 @@ async def edit_account_logic(args):
108159

109160
# ... (other logic functions like toggle, delete)
110161

111-
async def main():
162+
async def main() -> None:
163+
"""The main entry point for the CLI script."""
112164
parser = argparse.ArgumentParser(description="DeBot Account Management CLI")
113165
subparsers = parser.add_subparsers(dest="command", required=True)
114166

@@ -118,7 +170,7 @@ async def main():
118170

119171
# ... (full parser setup as in previous correct answer)
120172

121-
args = parser.parse_args()
173+
args: argparse.Namespace = parser.parse_args()
122174

123175
await initialize_database()
124176
if hasattr(args, 'func'):

userbot/src/core_handlers.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ async def add_account_handler(event: events.NewMessage.Event):
8484

8585
await conv.send_message(await event.client.get_string("verifying_creds"))
8686
temp_client = TelegramClient(StringSession(), int(api_id), api_hash)
87-
user_id = None
87+
8888
try:
8989
await temp_client.connect()
9090
if not await temp_client.is_user_authorized():
@@ -102,7 +102,9 @@ async def add_account_handler(event: events.NewMessage.Event):
102102
await pass_resp.delete()
103103
await temp_client.sign_in(password=two_fa_pass)
104104

105-
me = await temp_client.get_me(); user_id = me.id
105+
me = await temp_client.get_me(input_peer=True)
106+
user_id = me.user_id
107+
access_hash = me.access_hash
106108
await temp_client.disconnect()
107109

108110
async with get_db() as db:
@@ -119,8 +121,17 @@ async def add_account_handler(event: events.NewMessage.Event):
119121
await conv.send_message(await event.client.get_string("saving_to_db"))
120122
async with get_db() as db:
121123
new_acc = await db_manager.add_account(
122-
db, account_name, api_id, api_hash, lang_code, is_enabled,
123-
device_details['device_model'], device_details['system_version'], device_details['app_version'], user_id
124+
db,
125+
account_name=account_name,
126+
api_id=api_id,
127+
api_hash=api_hash,
128+
lang_code=lang_code,
129+
is_enabled=is_enabled,
130+
device_model=device_details['device_model'],
131+
system_version=device_details['system_version'],
132+
app_version=device_details['app_version'],
133+
user_telegram_id=user_id,
134+
access_hash=access_hash
124135
)
125136

126137
if new_acc:

userbot/src/db_manager.py

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from userbot.src.encrypt import encryption_manager
1111
from userbot.src.db.models import Account, Session, Module, AccountModule, Log, ModuleData
12+
from userbot.src.db.session import get_db
1213

1314
logger: logging.Logger = logging.getLogger(__name__)
1415

@@ -24,21 +25,62 @@ async def add_account(
2425
system_version: str,
2526
app_version: str,
2627
user_telegram_id: int,
27-
access_hash: int
28+
access_hash: int,
29+
proxy_type: Optional[str] = None,
30+
proxy_ip: Optional[str] = None,
31+
proxy_port: Optional[int] = None,
32+
proxy_username: Optional[str] = None,
33+
proxy_password: Optional[str] = None
2834
) -> Optional[Account]:
29-
"""Adds a new account, including its access_hash, to the database."""
35+
"""
36+
Adds a new account with its full configuration to the database.
37+
38+
Args:
39+
db (AsyncSession): The database session.
40+
account_name (str): The unique name for the account.
41+
api_id (str): The user's API ID.
42+
api_hash (str): The user's API Hash.
43+
lang_code (str): The language code for the account.
44+
is_enabled (bool): Whether the account should be active.
45+
device_model (str): The device model for the session.
46+
system_version (str): The system version for the session.
47+
app_version (str): The app version for the session.
48+
user_telegram_id (int): The Telegram user ID.
49+
access_hash (int): The user's access hash.
50+
proxy_type (Optional[str]): The type of proxy (e.g., 'http', 'socks5').
51+
proxy_ip (Optional[str]): The proxy IP address.
52+
proxy_port (Optional[int]): The proxy port.
53+
proxy_username (Optional[str]): The username for proxy authentication.
54+
proxy_password (Optional[str]): The password for proxy authentication.
55+
56+
Returns:
57+
Optional[Account]: The newly created Account object, or None on failure.
58+
"""
3059
try:
60+
encrypted_proxy_user = None
61+
if proxy_username:
62+
encrypted_proxy_user = encryption_manager.encrypt(proxy_username.encode('utf-8'))
63+
64+
encrypted_proxy_pass = None
65+
if proxy_password:
66+
encrypted_proxy_pass = encryption_manager.encrypt(proxy_password.encode('utf-8'))
67+
3168
new_account = Account(
3269
account_name=account_name,
33-
api_id=encryption_manager.encrypt(str(api_id).encode('utf-8')),
34-
api_hash=encryption_manager.encrypt(str(api_hash).encode('utf-8')),
70+
api_id=encryption_manager.encrypt(api_id.encode('utf-8')),
71+
api_hash=encryption_manager.encrypt(api_hash.encode('utf-8')),
3572
lang_code=lang_code,
3673
is_enabled=is_enabled,
3774
device_model=device_model,
3875
system_version=system_version,
3976
app_version=app_version,
4077
user_telegram_id=user_telegram_id,
41-
access_hash=access_hash
78+
access_hash=access_hash,
79+
proxy_type=proxy_type,
80+
proxy_ip=proxy_ip,
81+
proxy_port=proxy_port,
82+
proxy_username=encrypted_proxy_user,
83+
proxy_password=encrypted_proxy_pass
4284
)
4385
db.add(new_account)
4486
await db.flush()
@@ -99,6 +141,24 @@ async def update_account_lang(db: AsyncSession, account_id: int, lang_code: str)
99141
result = await db.execute(stmt)
100142
return result.rowcount > 0
101143

144+
async def update_account_self_info(account_id: int, user_id: int, access_hash: int) -> None:
145+
"""
146+
Updates the user_telegram_id and access_hash for an account.
147+
148+
This is useful if the information changes or was missing initially.
149+
150+
Args:
151+
account_id (int): The primary key of the account to update.
152+
user_id (int): The Telegram user ID.
153+
access_hash (int): The user's access hash.
154+
"""
155+
async with get_db() as db:
156+
stmt = update(Account).where(Account.account_id == account_id).values(
157+
user_telegram_id=user_id,
158+
access_hash=access_hash
159+
)
160+
await db.execute(stmt)
161+
102162
# --- Session CRUD ---
103163
async def get_session(db: AsyncSession, account_id: int) -> Optional[Session]:
104164
"""Retrieves a session for a given account and decrypts its auth key."""

userbot/src/db_session.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def get_input_entity(self, key: Any) -> Any:
128128
if key == 0:
129129
if self._self_user_id and self._self_access_hash:
130130
return InputPeerUser(self._self_user_id, self._self_access_hash)
131-
raise KeyError("Entity not found. Self-user ID and access hash were not available on session creation.")
131+
raise KeyError("Self-user ID and/or access hash were not found in the database for this account.")
132132

133133
def process_entities(self, tlo: object) -> None:
134134
if not hasattr(tlo, '__iter__'):
@@ -140,6 +140,10 @@ def process_entities(self, tlo: object) -> None:
140140
logger.info(f"Self-entity info for account {self.account_id} updated in-session.")
141141
self._self_user_id = entity.id
142142
self._self_access_hash = entity.access_hash
143+
# Persist the newly discovered access_hash to the database
144+
# This is a good place to ensure it's always up-to-date
145+
from asyncio import create_task
146+
create_task(db_manager.update_account_self_info(self.account_id, entity.id, entity.access_hash))
143147
break
144148

145149
def cache_file(self, md5_digest: bytes, file_size: int, instance: Any) -> None: pass

0 commit comments

Comments
 (0)