Merge pull request #69 from oplexz/main
Implement login via QR-code in session_string_generator; bump Telethon to 1.42.0
This commit is contained in:
commit
26b1287a5b
4 changed files with 130 additions and 49 deletions
|
|
@ -29,7 +29,8 @@ dependencies = [
|
|||
"nest-asyncio>=1.6.0",
|
||||
"python-dotenv>=1.1.0",
|
||||
"python-json-logger>=3.3.0",
|
||||
"telethon>=1.39.0"
|
||||
"qrcode>=8.2",
|
||||
"telethon>=1.42.0",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@ mcp[cli]>=1.4.1
|
|||
nest-asyncio>=1.6.0
|
||||
python-dotenv>=1.1.0
|
||||
python-json-logger>=3.3.0
|
||||
telethon>=1.39.0
|
||||
qrcode>=8.2
|
||||
telethon>=1.42.0
|
||||
|
|
@ -19,16 +19,76 @@ parameters support integer IDs, string representations of IDs (e.g., "123456"),
|
|||
and usernames (e.g., "@mychannel").
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import io
|
||||
import os
|
||||
from telethon.sync import TelegramClient
|
||||
from telethon.sessions import StringSession
|
||||
from dotenv import load_dotenv
|
||||
import sys
|
||||
|
||||
# Load environment variables from .env file
|
||||
from dotenv import load_dotenv
|
||||
from telethon import errors
|
||||
from telethon.sessions import StringSession
|
||||
from telethon.sync import TelegramClient
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
def _qr_login(client: TelegramClient) -> None:
|
||||
import qrcode
|
||||
|
||||
qr = client.qr_login()
|
||||
|
||||
print("\n----- QR Code Login -----\n")
|
||||
|
||||
qr_obj = qrcode.QRCode(border=1)
|
||||
qr_obj.add_data(qr.url)
|
||||
qr_obj.make(fit=True)
|
||||
f = io.StringIO()
|
||||
qr_obj.print_ascii(out=f, invert=True)
|
||||
print(f.getvalue())
|
||||
|
||||
print("Scan the QR code above with your Telegram app:")
|
||||
print(" Open Telegram > Settings > Devices > Link Desktop Device\n")
|
||||
print(f"Or open this link on a device where you're logged in:\n {qr.url}\n")
|
||||
print(f"Expires at: {qr.expires.strftime('%H:%M:%S')}")
|
||||
print("Waiting for you to scan...")
|
||||
|
||||
try:
|
||||
client.loop.run_until_complete(qr.wait(timeout=120))
|
||||
except asyncio.TimeoutError:
|
||||
print("\nQR code expired. Please try again.")
|
||||
client.disconnect()
|
||||
sys.exit(1)
|
||||
except errors.SessionPasswordNeededError:
|
||||
pw = input("\nTwo-factor authentication enabled. Please enter your password: ")
|
||||
client.sign_in(password=pw)
|
||||
|
||||
|
||||
def _phone_login(client: TelegramClient) -> None:
|
||||
phone = input("Please enter your phone (or bot token): ")
|
||||
|
||||
try:
|
||||
client.send_code_request(phone)
|
||||
except errors.FloodWaitError as e:
|
||||
print(f"\nFlood wait error; you must wait {e.seconds} seconds before trying again.")
|
||||
client.disconnect()
|
||||
sys.exit(1)
|
||||
except errors.PhoneNumberInvalidError:
|
||||
print("\nThe phone number is invalid.")
|
||||
client.disconnect()
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"\nError sending code: {e}")
|
||||
client.disconnect()
|
||||
sys.exit(1)
|
||||
|
||||
code = input("\nPlease enter the code you received: ")
|
||||
try:
|
||||
client.sign_in(phone, code)
|
||||
except errors.SessionPasswordNeededError:
|
||||
pw = input("Two-factor authentication enabled. Please enter your password: ")
|
||||
client.sign_in(password=pw)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
API_ID = os.getenv("TELEGRAM_API_ID")
|
||||
API_HASH = os.getenv("TELEGRAM_API_HASH")
|
||||
|
|
@ -38,7 +98,6 @@ def main() -> None:
|
|||
print("Create an .env file with your credentials from https://my.telegram.org/apps")
|
||||
sys.exit(1)
|
||||
|
||||
# Convert API_ID to integer
|
||||
try:
|
||||
API_ID = int(API_ID)
|
||||
except ValueError:
|
||||
|
|
@ -47,56 +106,62 @@ def main() -> None:
|
|||
|
||||
print("\n----- Telegram Session String Generator -----\n")
|
||||
print("This script will generate a session string for your Telegram account.")
|
||||
print(
|
||||
"You will be asked to enter your phone number and the verification code sent to your Telegram app."
|
||||
)
|
||||
print("The generated session string can be added to your .env file.")
|
||||
print(
|
||||
"\nYour credentials will NOT be stored on any server and are only used for local authentication.\n"
|
||||
)
|
||||
|
||||
print("Choose login method:")
|
||||
print(" 1) QR code login (recommended -- scan from your Telegram app)")
|
||||
print(" 2) Phone number + verification code")
|
||||
method = input("\nEnter 1 or 2 [default: 1]: ").strip() or "1"
|
||||
|
||||
try:
|
||||
# Connect to Telegram and generate the session string
|
||||
with TelegramClient(StringSession(), API_ID, API_HASH) as client:
|
||||
# The client.session.save() function from StringSession returns the session string
|
||||
session_string = StringSession.save(client.session)
|
||||
client = TelegramClient(StringSession(), API_ID, API_HASH)
|
||||
client.connect()
|
||||
|
||||
print("\nAuthentication successful!")
|
||||
print("\n----- Your Session String -----")
|
||||
print(f"\n{session_string}\n")
|
||||
print("Add this to your .env file as:")
|
||||
print(f"TELEGRAM_SESSION_STRING={session_string}")
|
||||
print("\nIMPORTANT: Keep this string private and never share it with anyone!")
|
||||
if not client.is_user_authorized():
|
||||
if method == "1":
|
||||
_qr_login(client)
|
||||
else:
|
||||
_phone_login(client)
|
||||
|
||||
# Optional: auto-update the .env file
|
||||
choice = input(
|
||||
"\nWould you like to automatically update your .env file with this session string? (y/N): "
|
||||
)
|
||||
if choice.lower() == "y":
|
||||
try:
|
||||
# Read the current .env file
|
||||
with open(".env", "r") as file:
|
||||
env_contents = file.readlines()
|
||||
session_string = StringSession.save(client.session)
|
||||
|
||||
# Update or add the SESSION_STRING line
|
||||
session_string_line_found = False
|
||||
for i, line in enumerate(env_contents):
|
||||
if line.startswith("TELEGRAM_SESSION_STRING="):
|
||||
env_contents[i] = f"TELEGRAM_SESSION_STRING={session_string}\n"
|
||||
session_string_line_found = True
|
||||
break
|
||||
print("\nAuthentication successful!")
|
||||
print("\n----- Your Session String -----")
|
||||
print(f"\n{session_string}\n")
|
||||
print("Add this to your .env file as:")
|
||||
print(f"TELEGRAM_SESSION_STRING={session_string}")
|
||||
print("\nIMPORTANT: Keep this string private and never share it with anyone!")
|
||||
|
||||
if not session_string_line_found:
|
||||
env_contents.append(f"TELEGRAM_SESSION_STRING={session_string}\n")
|
||||
choice = input(
|
||||
"\nWould you like to automatically update your .env file with this session string? (y/N): "
|
||||
)
|
||||
if choice.lower() == "y":
|
||||
try:
|
||||
with open(".env", "r") as file:
|
||||
env_contents = file.readlines()
|
||||
|
||||
# Write back to the .env file
|
||||
with open(".env", "w") as file:
|
||||
file.writelines(env_contents)
|
||||
session_string_line_found = False
|
||||
for i, line in enumerate(env_contents):
|
||||
if line.startswith("TELEGRAM_SESSION_STRING="):
|
||||
env_contents[i] = f"TELEGRAM_SESSION_STRING={session_string}\n"
|
||||
session_string_line_found = True
|
||||
break
|
||||
|
||||
print("\n.env file updated successfully!")
|
||||
except Exception as e:
|
||||
print(f"\nError updating .env file: {e}")
|
||||
print("Please manually add the session string to your .env file.")
|
||||
if not session_string_line_found:
|
||||
env_contents.append(f"TELEGRAM_SESSION_STRING={session_string}\n")
|
||||
|
||||
with open(".env", "w") as file:
|
||||
file.writelines(env_contents)
|
||||
|
||||
print("\n.env file updated successfully!")
|
||||
except Exception as e:
|
||||
print(f"\nError updating .env file: {e}")
|
||||
print("Please manually add the session string to your .env file.")
|
||||
|
||||
client.disconnect()
|
||||
|
||||
except Exception as e:
|
||||
print(f"\nError: {e}")
|
||||
|
|
|
|||
22
uv.lock
22
uv.lock
|
|
@ -825,6 +825,18 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qrcode"
|
||||
version = "8.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8f/b2/7fc2931bfae0af02d5f53b174e9cf701adbb35f39d69c2af63d4a39f81a9/qrcode-8.2.tar.gz", hash = "sha256:35c3f2a4172b33136ab9f6b3ef1c00260dd2f66f858f24d88418a015f446506c", size = 43317, upload-time = "2025-05-01T15:44:24.726Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/b8/d2d6d731733f51684bbf76bf34dab3b70a9148e8f2cef2bb544fccec681a/qrcode-8.2-py3-none-any.whl", hash = "sha256:16e64e0716c14960108e85d853062c9e8bba5ca8252c0b4d0231b9df4060ff4f", size = 45986, upload-time = "2025-05-01T15:44:22.781Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "referencing"
|
||||
version = "0.37.0"
|
||||
|
|
@ -1041,6 +1053,7 @@ dependencies = [
|
|||
{ name = "nest-asyncio" },
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "python-json-logger" },
|
||||
{ name = "qrcode" },
|
||||
{ name = "telethon" },
|
||||
]
|
||||
|
||||
|
|
@ -1060,7 +1073,8 @@ requires-dist = [
|
|||
{ name = "nest-asyncio", specifier = ">=1.6.0" },
|
||||
{ name = "python-dotenv", specifier = ">=1.1.0" },
|
||||
{ name = "python-json-logger", specifier = ">=3.3.0" },
|
||||
{ name = "telethon", specifier = ">=1.39.0" },
|
||||
{ name = "qrcode", specifier = ">=8.2" },
|
||||
{ name = "telethon", specifier = ">=1.42.0" },
|
||||
]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
|
|
@ -1073,15 +1087,15 @@ dev = [
|
|||
|
||||
[[package]]
|
||||
name = "telethon"
|
||||
version = "1.39.0"
|
||||
version = "1.42.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pyaes" },
|
||||
{ name = "rsa" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/54/b2/6e48b593a0e4e678578a682332ef36e54648c78ef13a5d395e5cdd293c6d/telethon-1.39.0.tar.gz", hash = "sha256:35d4795d8c91deac515fb0bcb3723866b924de1c724e1d5c230460e96f284a63", size = 640634, upload-time = "2025-02-20T17:30:44.562Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/10/8c8c9476bfce767a856d8aaf9eae8ea1869df4e970da16f1c5b638fd1b0c/telethon-1.42.0.tar.gz", hash = "sha256:032e95511261d5ead719f75494c6c85ece2ce71816b54f3c65d6ccc371d6994d", size = 672734, upload-time = "2025-11-05T19:15:19.849Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/32/f2/4e66a59c6d0cb6a25c0c2a630b4b184d81cfe8cb982bf3b65ce32b020fc8/Telethon-1.39.0-py3-none-any.whl", hash = "sha256:aa9f394b94be144799a6f6a93ab463867bc7c63503ede9631751940a98f6c703", size = 715851, upload-time = "2025-02-20T17:30:41.955Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/e4/8ce0ff55251381966a7c3f88bd5b34abda79b225a8e7fb51ddef3b849c94/telethon-1.42.0-py3-none-any.whl", hash = "sha256:cf361c94586bcacd6d0fc8959a2bce509d1bb37007fe6476a80c4fb4a2decc29", size = 748466, upload-time = "2025-11-05T19:15:18.241Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
Loading…
Reference in a new issue