mirror of
https://github.com/TeamPGM/PagerMaid-Pyro.git
synced 2024-11-21 18:18:17 +00:00
🔖 Update to v1.2.25
Support qr login.
This commit is contained in:
parent
efea7afd01
commit
aa42ed7372
1
.gitignore
vendored
1
.gitignore
vendored
@ -131,6 +131,7 @@ unknown_errors.txt
|
||||
pagermaid*.txt
|
||||
exception*.txt
|
||||
output.log
|
||||
qrcode.png
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
|
@ -10,6 +10,7 @@
|
||||
# API Credentials of your telegram application created at https://my.telegram.org/apps
|
||||
api_id: "ID_HERE"
|
||||
api_hash: "HASH_HERE"
|
||||
qrcode_login: "False"
|
||||
|
||||
# Either debug logging is enabled or not
|
||||
debug: "False"
|
||||
|
@ -12,7 +12,7 @@ from pagermaid.scheduler import scheduler
|
||||
import pyromod.listen
|
||||
from pyrogram import Client
|
||||
|
||||
pgm_version = "1.2.24"
|
||||
pgm_version = "1.2.25"
|
||||
CMD_LIST = {}
|
||||
module_dir = __path__[0]
|
||||
working_dir = getcwd()
|
||||
|
@ -10,6 +10,7 @@ from pagermaid.hook import Hook
|
||||
from pagermaid.modules import module_list, plugin_list
|
||||
from pagermaid.single_utils import safe_remove
|
||||
from pagermaid.utils import lang, process_exit
|
||||
from pyromod.methods.sign_in_qrcode import start_client
|
||||
|
||||
path.insert(1, f"{working_dir}{sep}plugins")
|
||||
|
||||
@ -18,7 +19,7 @@ async def main():
|
||||
logs.info(lang('platform') + platform + lang('platform_load'))
|
||||
|
||||
try:
|
||||
await bot.start()
|
||||
await start_client(bot)
|
||||
except AuthKeyUnregistered:
|
||||
safe_remove("pagermaid.session")
|
||||
exit()
|
||||
|
@ -43,6 +43,7 @@ class Config:
|
||||
# TGX
|
||||
API_ID = DEFAULT_API_ID
|
||||
API_HASH = DEFAULT_API_HASH
|
||||
QRCODE_LOGIN = strtobool(os.environ.get("QRCODE_LOGIN", config.get("qrcode_login", "false")))
|
||||
STRING_SESSION = os.environ.get("STRING_SESSION")
|
||||
DEBUG = strtobool(os.environ.get("PGM_DEBUG", config["debug"]))
|
||||
ERROR_REPORT = strtobool(os.environ.get("PGM_ERROR_REPORT", config["error_report"]), True)
|
||||
|
@ -1,20 +0,0 @@
|
||||
"""
|
||||
pyromod - A monkeypatcher add-on for Pyrogram
|
||||
Copyright (C) 2020 Cezar H. <https://github.com/usernein>
|
||||
|
||||
This file is part of pyromod.
|
||||
|
||||
pyromod is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
pyromod is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with pyromod. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from .helpers import ikb, bki, ntb, btn, kb, kbtn, array_chunk, force_reply
|
@ -1,75 +0,0 @@
|
||||
from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ForceReply
|
||||
|
||||
|
||||
def ikb(rows=None):
|
||||
if rows is None:
|
||||
rows = []
|
||||
lines = []
|
||||
for row in rows:
|
||||
line = []
|
||||
for button in row:
|
||||
button = btn(*button) # InlineKeyboardButton
|
||||
line.append(button)
|
||||
lines.append(line)
|
||||
return InlineKeyboardMarkup(inline_keyboard=lines)
|
||||
# return {'inline_keyboard': lines}
|
||||
|
||||
|
||||
def btn(text, value, type='callback_data'):
|
||||
return InlineKeyboardButton(text, **{type: value})
|
||||
# return {'text': text, type: value}
|
||||
|
||||
|
||||
# The inverse of above
|
||||
def bki(keyboard):
|
||||
lines = []
|
||||
for row in keyboard.inline_keyboard:
|
||||
line = []
|
||||
for button in row:
|
||||
button = ntb(button) # btn() format
|
||||
line.append(button)
|
||||
lines.append(line)
|
||||
return lines
|
||||
# return ikb() format
|
||||
|
||||
|
||||
def ntb(button):
|
||||
for btn_type in ['callback_data', 'url', 'switch_inline_query', 'switch_inline_query_current_chat',
|
||||
'callback_game']:
|
||||
value = getattr(button, btn_type)
|
||||
if value:
|
||||
break
|
||||
button = [button.text, value]
|
||||
if btn_type != 'callback_data':
|
||||
button.append(btn_type)
|
||||
return button
|
||||
# return {'text': text, type: value}
|
||||
|
||||
|
||||
def kb(rows=None, **kwargs):
|
||||
if rows is None:
|
||||
rows = []
|
||||
lines = []
|
||||
for row in rows:
|
||||
line = []
|
||||
for button in row:
|
||||
button_type = type(button)
|
||||
if button_type == str:
|
||||
button = KeyboardButton(button)
|
||||
elif button_type == dict:
|
||||
button = KeyboardButton(**button)
|
||||
|
||||
line.append(button)
|
||||
lines.append(line)
|
||||
return ReplyKeyboardMarkup(keyboard=lines, **kwargs)
|
||||
|
||||
|
||||
kbtn = KeyboardButton
|
||||
|
||||
|
||||
def force_reply(selective=True):
|
||||
return ForceReply(selective=selective)
|
||||
|
||||
|
||||
def array_chunk(input_, size):
|
||||
return [input_[i:i + size] for i in range(0, len(input_), size)]
|
0
pyromod/methods/__init__.py
Normal file
0
pyromod/methods/__init__.py
Normal file
127
pyromod/methods/sign_in_qrcode.py
Normal file
127
pyromod/methods/sign_in_qrcode.py
Normal file
@ -0,0 +1,127 @@
|
||||
import asyncio
|
||||
import base64
|
||||
from typing import Optional
|
||||
|
||||
import pyrogram
|
||||
from pyqrcode import QRCode
|
||||
from pyrogram import Client
|
||||
from pyrogram.errors import SessionPasswordNeeded, BadRequest
|
||||
from pyrogram.session import Auth, Session
|
||||
from pyrogram.utils import ainput
|
||||
|
||||
from pagermaid import Config
|
||||
|
||||
|
||||
async def sign_in_qrcode(
|
||||
client: Client,
|
||||
) -> Optional[str]:
|
||||
req = await client.invoke(
|
||||
pyrogram.raw.functions.auth.ExportLoginToken(
|
||||
api_id=client.api_id,
|
||||
api_hash=client.api_hash,
|
||||
except_ids=[],
|
||||
)
|
||||
)
|
||||
|
||||
if isinstance(req, pyrogram.raw.types.auth.LoginToken):
|
||||
token = base64.b64encode(req.token)
|
||||
return f"tg://login?token={token.decode('utf-8')}"
|
||||
elif isinstance(req, pyrogram.raw.types.auth.LoginTokenMigrateTo):
|
||||
await client.session.stop()
|
||||
await client.storage.dc_id(req.dc_id)
|
||||
await client.storage.auth_key(
|
||||
await Auth(client, await client.storage.dc_id(), await client.storage.test_mode()).create()
|
||||
)
|
||||
client.session = Session(
|
||||
client, await client.storage.dc_id(),
|
||||
await client.storage.auth_key(), await client.storage.test_mode()
|
||||
)
|
||||
await client.session.start()
|
||||
req = await client.invoke(pyrogram.raw.functions.auth.ImportLoginToken(token=req.token))
|
||||
await client.storage.user_id(req.user.id)
|
||||
await client.storage.is_bot(False)
|
||||
return pyrogram.types.User._parse(client, req.user)
|
||||
elif isinstance(req, pyrogram.raw.types.auth.LoginTokenSuccess):
|
||||
await client.storage.user_id(req.authorization.user.id)
|
||||
await client.storage.is_bot(False)
|
||||
return pyrogram.types.User._parse(client, req.authorization.user)
|
||||
|
||||
|
||||
async def authorize_by_qrcode(
|
||||
client: Client,
|
||||
):
|
||||
print(f"Welcome to Pyrogram (version {pyrogram.__version__})")
|
||||
print(f"Pyrogram is free software and comes with ABSOLUTELY NO WARRANTY. Licensed\n"
|
||||
f"under the terms of the {pyrogram.__license__}.\n")
|
||||
|
||||
while True:
|
||||
qrcode = None
|
||||
try:
|
||||
qrcode = await sign_in_qrcode(client)
|
||||
except BadRequest as e:
|
||||
print(e.MESSAGE)
|
||||
except SessionPasswordNeeded as e:
|
||||
print(e.MESSAGE)
|
||||
while True:
|
||||
print(f"Password hint: {await client.get_password_hint()}")
|
||||
|
||||
if not client.password:
|
||||
client.password = await ainput("Enter password (empty to recover): ", hide=client.hide_password)
|
||||
|
||||
try:
|
||||
if client.password:
|
||||
return await client.check_password(client.password)
|
||||
confirm = await ainput("Confirm password recovery (y/n): ")
|
||||
|
||||
if confirm == "y":
|
||||
email_pattern = await client.send_recovery_code()
|
||||
print(f"The recovery code has been sent to {email_pattern}")
|
||||
|
||||
while True:
|
||||
recovery_code = await ainput("Enter recovery code: ")
|
||||
|
||||
try:
|
||||
return await client.recover_password(recovery_code)
|
||||
except BadRequest as e:
|
||||
print(e.MESSAGE)
|
||||
else:
|
||||
client.password = None
|
||||
except BadRequest as e:
|
||||
print(e.MESSAGE)
|
||||
client.password = None
|
||||
if isinstance(qrcode, str):
|
||||
qr_obj = QRCode(qrcode)
|
||||
try:
|
||||
qr_obj.png("qrcode.png", scale=6)
|
||||
except Exception:
|
||||
print("Save qrcode.png failed.")
|
||||
print(qr_obj.terminal())
|
||||
print(f"Scan the QR code above, the qrcode.png file or visit {qrcode} to log in.\n")
|
||||
print("QR code will expire in 20 seconds. If you have scanned it, please wait...")
|
||||
await asyncio.sleep(20)
|
||||
elif isinstance(qrcode, pyrogram.types.User):
|
||||
return qrcode
|
||||
|
||||
|
||||
async def start_client(client: Client):
|
||||
is_authorized = await client.connect()
|
||||
|
||||
try:
|
||||
if not is_authorized:
|
||||
if Config.QRCODE_LOGIN:
|
||||
await authorize_by_qrcode(client)
|
||||
else:
|
||||
await client.authorize()
|
||||
|
||||
if not await client.storage.is_bot() and client.takeout:
|
||||
client.takeout_id = (await client.invoke(pyrogram.raw.functions.account.InitTakeoutSession())).id
|
||||
|
||||
await client.invoke(pyrogram.raw.functions.updates.GetState())
|
||||
except (Exception, KeyboardInterrupt):
|
||||
await client.disconnect()
|
||||
raise
|
||||
else:
|
||||
client.me = await client.get_me()
|
||||
await client.initialize()
|
||||
|
||||
return client
|
@ -1,20 +0,0 @@
|
||||
"""
|
||||
pyromod - A monkeypatcher add-on for Pyrogram
|
||||
Copyright (C) 2020 Cezar H. <https://github.com/usernein>
|
||||
|
||||
This file is part of pyromod.
|
||||
|
||||
pyromod is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
pyromod is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with pyromod. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from .pagination import Pagination
|
@ -1,91 +0,0 @@
|
||||
"""
|
||||
pyromod - A monkeypatcher add-on for Pyrogram
|
||||
Copyright (C) 2020 Cezar H. <https://github.com/usernein>
|
||||
|
||||
This file is part of pyromod.
|
||||
|
||||
pyromod is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
pyromod is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with pyromod. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
import math
|
||||
from ..helpers import array_chunk
|
||||
|
||||
|
||||
class Pagination:
|
||||
def __init__(self, objects, page_data=None, item_data=None, item_title=None):
|
||||
default_page_callback = (lambda x: str(x))
|
||||
default_item_callback = (lambda i, pg: f'[{pg}] {i}')
|
||||
self.objects = objects
|
||||
self.page_data = page_data or default_page_callback
|
||||
self.item_data = item_data or default_item_callback
|
||||
self.item_title = item_title or default_item_callback
|
||||
|
||||
def create(self, page, lines=5, columns=1):
|
||||
quant_per_page = lines * columns
|
||||
page = 1 if page <= 0 else page
|
||||
offset = (page - 1) * quant_per_page
|
||||
stop = offset + quant_per_page
|
||||
cutted = self.objects[offset:stop]
|
||||
|
||||
total = len(self.objects)
|
||||
pages_range = [*range(1, math.ceil(total / quant_per_page) + 1)] # each item is a page
|
||||
last_page = len(pages_range)
|
||||
|
||||
nav = []
|
||||
if page <= 3:
|
||||
for n in [1, 2, 3]:
|
||||
if n not in pages_range:
|
||||
continue
|
||||
text = f"· {n} ·" if n == page else n
|
||||
nav.append((text, self.page_data(n)))
|
||||
if last_page >= 4:
|
||||
nav.append(
|
||||
('4 ›' if last_page > 5 else 4, self.page_data(4))
|
||||
)
|
||||
if last_page > 4:
|
||||
nav.append(
|
||||
(f'{last_page} »' if last_page > 5 else last_page, self.page_data(last_page))
|
||||
)
|
||||
elif page >= last_page - 2:
|
||||
nav.extend(
|
||||
[
|
||||
('« 1' if last_page > 5 else 1, self.page_data(1)),
|
||||
(
|
||||
f'‹ {last_page - 3}' if last_page > 5 else last_page - 3,
|
||||
self.page_data(last_page - 3),
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
for n in range(last_page - 2, last_page + 1):
|
||||
text = f"· {n} ·" if n == page else n
|
||||
nav.append((text, self.page_data(n)))
|
||||
else:
|
||||
nav = [
|
||||
('« 1', self.page_data(1)),
|
||||
(f'‹ {page - 1}', self.page_data(page - 1)),
|
||||
(f'· {page} ·', "noop"),
|
||||
(f'{page + 1} ›', self.page_data(page + 1)),
|
||||
(f'{last_page} »', self.page_data(last_page)),
|
||||
]
|
||||
|
||||
buttons = [
|
||||
(self.item_title(item, page), self.item_data(item, page))
|
||||
for item in cutted
|
||||
]
|
||||
|
||||
kb_lines = array_chunk(buttons, columns)
|
||||
if last_page > 1:
|
||||
kb_lines.append(nav)
|
||||
|
||||
return kb_lines
|
@ -10,3 +10,5 @@ apscheduler
|
||||
sqlitedict
|
||||
casbin==1.17.5
|
||||
sentry-sdk==1.13.0
|
||||
PyQRCode>=1.2.1
|
||||
PyPng
|
||||
|
@ -19,7 +19,10 @@ configure () {
|
||||
printf "请输入应用程序 api_hash(不懂请直接回车):"
|
||||
read -r api_hash <&1
|
||||
sed -i "s/HASH_HERE/$api_hash/" $config_file
|
||||
printf "请输入应用程序语言(默认:zh-cn):"
|
||||
read -p "二维码扫码登录?(避免无法收到验证码) [Y/n]" choi
|
||||
if [ "$choi" == "y" ] || [ "$choi" == "Y" ]; then
|
||||
sed -i "s/qrcode_login: \"False\"/qrcode_login: \"True\"/" $config_file
|
||||
fi
|
||||
read -r application_language <&1
|
||||
if [ -z "$application_language" ]
|
||||
then
|
||||
|
Loading…
Reference in New Issue
Block a user