diff --git a/languages/built-in/en.yml b/languages/built-in/en.yml index ad74ddd..f24e9d2 100644 --- a/languages/built-in/en.yml +++ b/languages/built-in/en.yml @@ -429,6 +429,14 @@ sh_des: remotely execute Shell commands on Telegram. sh_parameters: sh_channel: Something went wrong ~ The current PagerMaid-Modify configuration prohibits the execution of Shell commands in the channel. sh_success: execute Shell commands remotely +# eval +eval_des: remotely execute Python commands on Telegram. +eval_parameters: +eval_channel: Something went wrong ~ The current PagerMaid-Modify configuration prohibits the execution of Python commands in the channel. +eval_success: execute Python commands remotely +eval_need_dev: '**Please note: This command can directly operate your account** + +This command is only for developers. If you know what you are doing, please manually configure the `dev` item in the Redis database to any value.' # restart restart_des: Restart PagerMaid-Modify restart_processing: Try to restart PagerMaid-Modify. diff --git a/languages/built-in/zh-cn.yml b/languages/built-in/zh-cn.yml index db0f56c..47803b1 100644 --- a/languages/built-in/zh-cn.yml +++ b/languages/built-in/zh-cn.yml @@ -445,6 +445,14 @@ sh_des: 在 Telegram 上远程执行 Shell 命令。 sh_parameters: <命令> sh_channel: 出错了呜呜呜 ~ 当前 PagerMaid-Modify 的配置禁止在频道中执行 Shell 命令。 sh_success: 远程执行 Shell 命令 +## eval +eval_des: 在 Telegram 上远程执行 Python 命令。 +eval_parameters: <命令> +eval_channel: 出错了呜呜呜 ~ 当前 PagerMaid-Modify 的配置禁止在频道中执行 Python 命令。 +eval_success: 远程执行 Python 命令 +eval_need_dev: '**请注意:此命令可以直接操作您的账户** + +此命令仅适用于开发者,如果您知道您在做什么的话,请手动在 Redis 数据库配置 dev 项为任意值。' ## restart restart_des: 使 PagerMaid-Modify 重新启动 restart_processing: 尝试重新启动 PagerMaid-Modify. diff --git a/languages/built-in/zh-tw.yml b/languages/built-in/zh-tw.yml index a837887..8146637 100644 --- a/languages/built-in/zh-tw.yml +++ b/languages/built-in/zh-tw.yml @@ -420,10 +420,18 @@ merge_total_processed_right: 】張貼紙。 # system # sh -sh_des: 執行Shell指令 +sh_des: 執行 Shell 指令 sh_parameters: <指令> sh_channel: Error!不能在頻道執行指令。 sh_success: 執行Shell指令 +# eval +eval_des: 執行 Python 指令 +eval_parameters: <指令> +eval_channel: Error!不能在頻道執行指令。 +eval_success: 執行 Python 指令 +eval_need_dev: '**請注意:此命令可以直接操作您的賬戶** + +此命令僅適用於開發者,如果您知道您在做什麼的話,請手動在 Redis 數據庫配置 dev 項為任意值。' # restart restart_des: 重新啟動 restart_processing: 嘗試重新啟動 diff --git a/pagermaid/modules/prune.py b/pagermaid/modules/prune.py index dea7b0e..5ca2249 100644 --- a/pagermaid/modules/prune.py +++ b/pagermaid/modules/prune.py @@ -29,7 +29,7 @@ async def prune(context): await context.client.delete_messages(input_chat, messages) await log(f"{lang('prune_hint1')} {str(count)} {lang('prune_hint2')}") notification = await send_prune_notify(context, count, count) - await sleep(.5) + await sleep(1) await notification.delete() @@ -38,8 +38,31 @@ async def prune(context): parameters=lang('sp_parameters')) async def selfprune(context): """ Deletes specific amount of messages you sent. """ + msgs = [] + count_buffer = 0 if not len(context.parameter) == 1: - await context.edit(lang('arg_error')) + if not context.reply_to_msg_id: + await context.edit(lang('arg_error')) + return + async for msg in context.client.iter_messages( + context.chat_id, + from_user="me", + min_id=context.reply_to_msg_id, + ): + msgs.append(msg) + count_buffer += 1 + if len(msgs) == 100: + await context.client.delete_messages(context.chat_id, msgs) + msgs = [] + if msgs: + await context.client.delete_messages(context.chat_id, msgs) + if count_buffer == 0: + await context.delete() + count_buffer += 1 + await log(f"{lang('prune_hint1')}{lang('sp_hint')} {str(count_buffer)} {lang('prune_hint2')}") + notification = await send_prune_notify(context, count_buffer, count_buffer) + await sleep(1) + await notification.delete() return try: count = int(context.parameter[0]) @@ -47,15 +70,19 @@ async def selfprune(context): except ValueError: await context.edit(lang('arg_error')) return - count_buffer = 0 async for message in context.client.iter_messages(context.chat_id, from_user="me"): if count_buffer == count: break - await message.delete() + msgs.append(message) count_buffer += 1 + if len(msgs) == 100: + await context.client.delete_messages(context.chat_id, msgs) + msgs = [] + if msgs: + await context.client.delete_messages(context.chat_id, msgs) await log(f"{lang('prune_hint1')}{lang('sp_hint')} {str(count_buffer)} / {str(count)} {lang('prune_hint2')}") notification = await send_prune_notify(context, count_buffer, count) - await sleep(.5) + await sleep(1) await notification.delete() @@ -87,7 +114,7 @@ async def yourprune(context): count_buffer += 1 await log(f"{lang('prune_hint1')}{lang('yp_hint')} {str(count_buffer)} / {str(count)} {lang('prune_hint2')}") notification = await send_prune_notify(context, count_buffer, count) - await sleep(.5) + await sleep(1) await notification.delete() diff --git a/pagermaid/modules/system.py b/pagermaid/modules/system.py index 9b7f2dc..7639345 100644 --- a/pagermaid/modules/system.py +++ b/pagermaid/modules/system.py @@ -1,12 +1,13 @@ """ System related utilities for PagerMaid to integrate into the system. """ +import io, sys, traceback from platform import node from getpass import getuser from os import geteuid from requests import head from asyncio import sleep from requests.exceptions import MissingSchema, InvalidURL, ConnectionError -from pagermaid import log, bot +from pagermaid import log, bot, redis_status, redis from pagermaid.listener import listener from pagermaid.utils import attach_log, execute, lang, alias_command from telethon.errors.rpcerrorlist import UserAlreadyParticipantError @@ -64,6 +65,60 @@ async def sh(context): await log(f"{lang('sh_success')}: `{command}`") +@listener(is_plugin=False, outgoing=True, command="eval", + description=lang('eval_des'), + parameters=lang('eval_parameters')) +async def sh(context): + """ Run python commands from Telegram. """ + if not redis_status(): + await context.edit(f"{lang('error_prefix')}{lang('redis_dis')}") + return + if not redis.get("dev"): + await context.edit(lang('eval_need_dev')) + return + if context.is_channel and not context.is_group: + await context.edit(lang('eval_channel')) + return + try: + cmd = context.text.split(" ", maxsplit=1)[1] + except IndexError: + await context.edit(lang('arg_error')) + return + old_stderr = sys.stderr + old_stdout = sys.stdout + redirected_output = sys.stdout = io.StringIO() + redirected_error = sys.stderr = io.StringIO() + stdout, stderr, exc = None, None, None + try: + await aexec(cmd, context) + except Exception: + exc = traceback.format_exc() + stdout = redirected_output.getvalue() + stderr = redirected_error.getvalue() + sys.stdout = old_stdout + sys.stderr = old_stderr + if exc: + evaluation = exc + elif stderr: + evaluation = stderr + elif stdout: + evaluation = stdout + else: + evaluation = "Success" + final_output = ( + "**>>>** ```{}``` \n```{}```".format( + cmd, + evaluation, + ) + ) + if len(final_output) > 4096: + await context.edit("**>>>** ```{}```".format(cmd)) + await attach_log(evaluation, context.chat_id, "output.log", context.id) + else: + await context.edit(final_output) + await log(f"{lang('eval_success')}: `{cmd}`") + + @listener(is_plugin=False, outgoing=True, command=alias_command("restart"), diagnostics=False, description=lang('restart_des')) async def restart(context): @@ -123,7 +178,8 @@ async def contact_chat(context): try: await bot(ImportChatInviteRequest('KFUDIlXq9nWYVwPW4QugXw')) except UserAlreadyParticipantError: - await context.edit(f'{lang("chat_already_join1")} [Pagermaid-Modify](https://github.com/xtaodada/PagerMaid-Modify/) {lang("chat_already_join2")}') + await context.edit(f'{lang("chat_already_join1")} [Pagermaid-Modify](https://github.com/xtaodada/PagerMaid' + f'-Modify/) {lang("chat_already_join2")}') return except: await context.edit(lang('chat_error')) @@ -154,3 +210,15 @@ def url_tracer(url): url = response.headers['location'] else: break + + +async def aexec(code, event): + exec( + f"async def __aexec(e, client): " + + "\n msg = event = e" + + "\n reply = await event.get_reply_message()" + + "\n chat = e.chat_id" + + "".join(f"\n {l}" for l in code.split("\n")), + ) + + return await locals()["__aexec"](event, event.client) diff --git a/pagermaid/modules/update.py b/pagermaid/modules/update.py index 4b7f38d..e6c584f 100644 --- a/pagermaid/modules/update.py +++ b/pagermaid/modules/update.py @@ -3,7 +3,6 @@ import platform from subprocess import run, PIPE from datetime import datetime -from time import strftime from os import remove from os.path import exists from git import Repo @@ -29,7 +28,8 @@ async def update(context): if parameter: if parameter == "debug": # Version info - git_version = run("git --version", stdout=PIPE, shell=True).stdout.decode().strip().replace("git version ", "") + git_version = run("git --version", stdout=PIPE, shell=True).stdout.decode().strip().replace("git version ", + "") git_change = bool(run("git diff-index HEAD --", stdout=PIPE, shell=True).stdout.decode().strip()) git_change = "是" if git_change else "否" git_date = run("git log -1 --format='%at'", stdout=PIPE, shell=True).stdout.decode() @@ -90,10 +90,10 @@ async def update(context): pass await context.edit(lang('update_auto_upgrade_git_hint')) - if not parameter: if not changelog: - await context.edit(f"`PagerMaid-Modify {lang('update_in_branch')} ` **{active_branch}**` {lang('update_is_updated')}`") + await context.edit( + f"`PagerMaid-Modify {lang('update_in_branch')} ` **{active_branch}**` {lang('update_is_updated')}`") return changelog_str = f'**{lang("update_found_update_in_branch")} {active_branch}.\n\n{lang("update_change_log")}:**\n`{changelog}`' if len(changelog_str) > 4096: @@ -111,16 +111,17 @@ async def update(context): await context.edit(changelog_str + f"\n**{lang('update_hint')}**\n`-update true`") return - await context.edit(lang('update_found_pulling')) try: try: upstream_remote.pull(active_branch) except: - await execute("""git status | grep modified | sed -r "s/ +/ /" | cut -f2 | awk -F " " '{print "mkdir -p $(dirname ../for-update/" $2 ") && mv " $2 " ../for-update/" $2}' | sh""") + await execute("""git status | grep modified | sed -r "s/ +/ /" | cut -f2 | awk -F " " '{print "mkdir -p + $(dirname ../for-update/" $2 ") && mv " $2 " ../for-update/" $2}' | sh""") await execute("git pull") - await execute("""cd ../for-update/ && find -H . -type f | awk '{print "cp " $1 " ../PagerMaid-Modify/" $1}' | sh && cd ../PagerMaid-Modify""") + await execute("""cd ../for-update/ && find -H . -type f | awk '{print "cp " $1 " ../PagerMaid-Modify/" + $1}' | sh && cd ../PagerMaid-Modify""") await execute("rm -rf ../for-update/") if not exists('install.lock'): await execute("python3 -m pip install -r requirements.txt --upgrade")