mirror of
https://github.com/MuRuLOSE/limoka.git
synced 2026-06-16 22:34:19 +02:00
Added and updated repositories 2025-11-21 01:04:46
This commit is contained in:
@@ -1,114 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
version = (1, 0, 0)
|
||||
|
||||
# meta developer: @RUIS_VlP
|
||||
|
||||
import random
|
||||
from datetime import timedelta
|
||||
from telethon import TelegramClient, events
|
||||
from telethon import functions
|
||||
from telethon.tl.types import Message
|
||||
import os
|
||||
from .. import loader, utils
|
||||
|
||||
import paramiko
|
||||
|
||||
# requires: paramiko
|
||||
|
||||
def upload_file_sftp(host, port, username, password, local_file, remote_file):
|
||||
try:
|
||||
# Создаем экземпляр SSHClient
|
||||
client = paramiko.SSHClient()
|
||||
|
||||
# Загружаем параметры по умолчанию
|
||||
client.load_system_host_keys()
|
||||
|
||||
# Разрешаем соединение с сервером, если ключа нет в системе
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
|
||||
# Подключаемся к серверу
|
||||
client.connect(hostname=host, port=port, username=username, password=password)
|
||||
|
||||
# Открываем SFTP сессию
|
||||
sftp = client.open_sftp()
|
||||
|
||||
try:
|
||||
sftp.listdir("SFTP_files")
|
||||
except IOError:
|
||||
sftp.mkdir("SFTP_files")
|
||||
|
||||
# Загружаем файл
|
||||
sftp.put(local_file, remote_file)
|
||||
|
||||
print(f'Файл {local_file} успешно загружен на {remote_file}')
|
||||
|
||||
except Exception as e:
|
||||
print(f'Произошла ошибка: {e}')
|
||||
finally:
|
||||
# Закрываем SFTP сессию и SSH соединение
|
||||
if 'sftp' in locals():
|
||||
sftp.close()
|
||||
client.close()
|
||||
|
||||
|
||||
@loader.tds
|
||||
class SFTPUploaderMod(loader.Module):
|
||||
"""Загрузка файлов на SFTP"""
|
||||
|
||||
strings = {
|
||||
"name": "SFTPUploader",
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
loader.ConfigValue(
|
||||
"host",
|
||||
"None",
|
||||
"IP address or domain",
|
||||
validator=loader.validators.String()
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"username",
|
||||
"None",
|
||||
"SFTP username",
|
||||
validator=loader.validators.String()
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"password",
|
||||
"None",
|
||||
"SFTP password",
|
||||
validator=loader.validators.Hidden()
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"Port",
|
||||
22,
|
||||
"SFTP port",
|
||||
validator=loader.validators.String()
|
||||
),
|
||||
)
|
||||
|
||||
@loader.command()
|
||||
async def sftp(self, message):
|
||||
"""<reply> - загружает файл на SFPT"""
|
||||
host = self.config["host"] or "None"
|
||||
username = self.config["username"] or "None"
|
||||
password = self.config["password"] or "None"
|
||||
port = self.config["Port"] or "None"
|
||||
if host == "None" or username == "None" or password == "None" or port == "None":
|
||||
await utils.answer(message, "<b>Значения не указаны. Укажите их через команду:</b>\n<code>.config SFTPUploader</code>")
|
||||
return
|
||||
reply = await message.get_reply_message()
|
||||
if reply:
|
||||
if reply.media:
|
||||
await utils.answer(message, f"<b>Начинаю загрузку....</b>")
|
||||
file_path = await message.client.download_media(reply.media)
|
||||
sftp_path = f"SFTP_files/{file_path}"
|
||||
upld = upload_file_sftp(host, port, username, password, file_path, sftp_path)
|
||||
os.remove(file_path)
|
||||
await utils.answer(message, f"<b>Файл загружен на SFTP сервер(не факт), расположение файла:</b> <code>~/SFTP_files/{file_path}</code>")
|
||||
else:
|
||||
await utils.answer(message, "<b>В сообщении не найдены файлы!</b>")
|
||||
else:
|
||||
await utils.answer(message, "<b>Команда должна быть ответом на сообщение!</b>")
|
||||
return
|
||||
|
||||
@@ -1,207 +1,480 @@
|
||||
version = (1, 0, 0)
|
||||
version = (2, 0, 0)
|
||||
|
||||
# meta developer: @RUIS_VlP
|
||||
# requires: paramiko
|
||||
|
||||
import random
|
||||
from datetime import timedelta
|
||||
from telethon import TelegramClient, events
|
||||
from telethon import functions
|
||||
from telethon.tl.types import Message
|
||||
import asyncio
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
from .. import loader, utils
|
||||
|
||||
import paramiko
|
||||
|
||||
def upload_file_sftp(host, port, username, password, local_file, remote_file):
|
||||
try:
|
||||
# Создаем экземпляр SSHClient
|
||||
client = paramiko.SSHClient()
|
||||
|
||||
# Загружаем параметры по умолчанию
|
||||
client.load_system_host_keys()
|
||||
|
||||
# Разрешаем соединение с сервером, если ключа нет в системе
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
|
||||
# Подключаемся к серверу
|
||||
client.connect(hostname=host, port=port, username=username, password=password)
|
||||
|
||||
# Открываем SFTP сессию
|
||||
sftp = client.open_sftp()
|
||||
|
||||
try:
|
||||
sftp.listdir("sshmod")
|
||||
except IOError:
|
||||
sftp.mkdir("sshmod")
|
||||
|
||||
# Загружаем файл
|
||||
sftp.put(local_file, remote_file)
|
||||
|
||||
print(f'Файл {local_file} успешно загружен на {remote_file}')
|
||||
|
||||
except Exception as e:
|
||||
print(f'Произошла ошибка: {e}')
|
||||
finally:
|
||||
# Закрываем SFTP сессию и SSH соединение
|
||||
if 'sftp' in locals():
|
||||
sftp.close()
|
||||
client.close()
|
||||
|
||||
def execute_ssh_command(host, port, username, password, command):
|
||||
try:
|
||||
# Создаем экземпляр SSHClient
|
||||
client = paramiko.SSHClient()
|
||||
|
||||
# Загружаем параметры по умолчанию
|
||||
client.load_system_host_keys()
|
||||
|
||||
# Разрешаем соединение с сервером, если ключа нет в системе
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
|
||||
# Подключаемся к серверу
|
||||
client.connect(hostname=host, port=port, username=username, password=password)
|
||||
|
||||
# Выполняем команду
|
||||
stdin, stdout, stderr = client.exec_command(command)
|
||||
|
||||
# Получаем вывод и ошибки
|
||||
output = stdout.read().decode()
|
||||
error = stderr.read().decode()
|
||||
exit_code = stdout.channel.recv_exit_status()
|
||||
|
||||
return exit_code, output, error
|
||||
|
||||
except Exception as e:
|
||||
print(f'Произошла ошибка: {e}')
|
||||
return None, None, str(e)
|
||||
finally:
|
||||
# Закрываем SSH соединение
|
||||
client.close()
|
||||
class SSHConnection:
|
||||
|
||||
def __init__(self, host, port, username, password=None, key_path=None):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.key_path = key_path
|
||||
self.client = None
|
||||
|
||||
async def connect(self):
|
||||
loop = asyncio.get_event_loop()
|
||||
await loop.run_in_executor(None, self._connect_sync)
|
||||
|
||||
def _connect_sync(self):
|
||||
self.client = paramiko.SSHClient()
|
||||
self.client.load_system_host_keys()
|
||||
self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
|
||||
connect_kwargs = {
|
||||
'hostname': self.host,
|
||||
'port': self.port,
|
||||
'username': self.username
|
||||
}
|
||||
|
||||
if self.key_path and self.key_path != "None":
|
||||
try:
|
||||
private_key = paramiko.RSAKey.from_private_key_file(self.key_path)
|
||||
connect_kwargs['pkey'] = private_key
|
||||
except:
|
||||
try:
|
||||
private_key = paramiko.Ed25519Key.from_private_key_file(self.key_path)
|
||||
connect_kwargs['pkey'] = private_key
|
||||
except:
|
||||
private_key = paramiko.ECDSAKey.from_private_key_file(self.key_path)
|
||||
connect_kwargs['pkey'] = private_key
|
||||
else:
|
||||
connect_kwargs['password'] = self.password
|
||||
|
||||
self.client.connect(**connect_kwargs)
|
||||
|
||||
async def upload_file(self, local_file, remote_file):
|
||||
loop = asyncio.get_event_loop()
|
||||
await loop.run_in_executor(None, self._upload_file_sync, local_file, remote_file)
|
||||
|
||||
def _upload_file_sync(self, local_file, remote_file):
|
||||
sftp = self.client.open_sftp()
|
||||
|
||||
remote_dir = os.path.dirname(remote_file)
|
||||
if remote_dir:
|
||||
self._create_remote_dir(sftp, remote_dir)
|
||||
|
||||
sftp.put(local_file, remote_file)
|
||||
sftp.close()
|
||||
|
||||
def _create_remote_dir(self, sftp, path):
|
||||
dirs = []
|
||||
while path and path != '/':
|
||||
try:
|
||||
sftp.stat(path)
|
||||
break
|
||||
except IOError:
|
||||
dirs.append(path)
|
||||
path = os.path.dirname(path)
|
||||
|
||||
while dirs:
|
||||
dir_path = dirs.pop()
|
||||
try:
|
||||
sftp.mkdir(dir_path)
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
async def download_file(self, remote_file, local_file):
|
||||
loop = asyncio.get_event_loop()
|
||||
await loop.run_in_executor(None, self._download_file_sync, remote_file, local_file)
|
||||
|
||||
def _download_file_sync(self, remote_file, local_file):
|
||||
sftp = self.client.open_sftp()
|
||||
sftp.get(remote_file, local_file)
|
||||
sftp.close()
|
||||
|
||||
async def execute_command_stream(self, command, callback):
|
||||
loop = asyncio.get_event_loop()
|
||||
return await loop.run_in_executor(
|
||||
None,
|
||||
self._execute_command_stream_sync,
|
||||
command,
|
||||
callback
|
||||
)
|
||||
|
||||
def _execute_command_stream_sync(self, command, callback):
|
||||
stdin, stdout, stderr = self.client.exec_command(command, get_pty=True)
|
||||
|
||||
channel = stdout.channel
|
||||
pid = channel.get_id()
|
||||
|
||||
output_lines = []
|
||||
error_lines = []
|
||||
|
||||
while not stdout.channel.exit_status_ready() or stdout.channel.recv_ready():
|
||||
if stdout.channel.recv_ready():
|
||||
line = stdout.readline()
|
||||
if line:
|
||||
output_lines.append(line)
|
||||
callback('stdout', line, pid)
|
||||
|
||||
remaining = stdout.read().decode()
|
||||
if remaining:
|
||||
output_lines.append(remaining)
|
||||
callback('stdout', remaining, pid)
|
||||
|
||||
error_output = stderr.read().decode()
|
||||
if error_output:
|
||||
error_lines.append(error_output)
|
||||
callback('stderr', error_output, pid)
|
||||
|
||||
exit_code = stdout.channel.recv_exit_status()
|
||||
|
||||
return exit_code, ''.join(output_lines), ''.join(error_lines), pid
|
||||
|
||||
def close(self):
|
||||
if self.client:
|
||||
self.client.close()
|
||||
|
||||
|
||||
@loader.tds
|
||||
class SSHMod(loader.Module):
|
||||
"""SSH module for uploading files and executing commands"""
|
||||
"""Модуль для работы с SSH"""
|
||||
|
||||
strings = {
|
||||
"name": "SSHMod",
|
||||
"cfg_host": "IP address or domain",
|
||||
"cfg_username": "SSH username",
|
||||
"cfg_password": "SSH password",
|
||||
"cfg_port": "SSH port",
|
||||
"save_description": "<reply> - saves the file to the ~/sshmod directory",
|
||||
"save_uploading": "<b>Starting upload....</b>",
|
||||
"save_success": "<b>File uploaded to SSH server, file location:</b> <code>~/sshmod/{}</code>",
|
||||
"save_no_file": "<b>No files found in the message!</b>",
|
||||
"save_reply_required": "<b>The command must be a reply to a message!</b>",
|
||||
"sterminal_description": "<command> - executes a command on the SSH server",
|
||||
"sterminal_no_command": "<b>No command specified!</b>",
|
||||
"sterminal_output": "⌨️<b> System command</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>Exit code:</b> <code>{}</code>\n<b>📼 Output:</b>\n<pre><code class='language-stdout'>{}</code></pre>",
|
||||
"sterminal_error": "⌨️<b> System command</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>Exit code:</b> <code>{}</code>\n<b>🚫 Errors:</b>\n<pre><code class='language-stderr'>{}</code></pre>",
|
||||
"sterminal_output_and_error": "⌨️<b> System command</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>Exit code:</b> <code>{}</code>\n<b>📼 Output:</b>\n<pre><code class='language-stdout'>{}</code></pre>\n<b>🚫 Errors:</b>\n<pre><code class='language-stderr'>{}</code></pre>",
|
||||
"config_not_set": "<b>Values are not set. Set them using the command:</b>\n<code>.config SSHMod</code>",
|
||||
}
|
||||
strings = {
|
||||
"name": "SSHMod",
|
||||
"cfg_host": "IP address or domain",
|
||||
"cfg_username": "SSH username",
|
||||
"cfg_password": "SSH password (leave None if using key)",
|
||||
"cfg_key": "Path to private SSH key (leave None if using password)",
|
||||
"cfg_port": "SSH port",
|
||||
"cfg_default_dir": "Default directory for saving files",
|
||||
"sftpsave_description": "<reply> [directory] - saves the file to the specified directory",
|
||||
"sftpsave_uploading": "<b>Starting upload....</b>",
|
||||
"sftpsave_success": "<b>File uploaded to SSH server, file location:</b> <code>{}</code>",
|
||||
"sftpsave_no_file": "<b>No files found in the message!</b>",
|
||||
"sftpsave_reply_required": "<b>The command must be a reply to a message!</b>",
|
||||
"sftpupload_description": "<file_path> - downloads file from SSH server",
|
||||
"sftpupload_no_path": "<b>No file path specified!</b>",
|
||||
"sftpupload_downloading": "<b>Downloading file from SSH server...</b>",
|
||||
"sftpupload_error": "<b>Error downloading file:</b> <code>{}</code>",
|
||||
"sterminal_description": "<command> - executes a command on the SSH server",
|
||||
"sterminal_no_command": "<b>No command specified!</b>",
|
||||
"sterminal_starting": "⌨️<b> System command</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>PID:</b> <code>{}</code>\n<b>Status:</b> Running...\n<b>📼 Output:</b>\n<pre><code class='language-stdout'>{}</code></pre>",
|
||||
"sterminal_output": "⌨️<b> System command</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>PID:</b> <code>{}</code>\n<b>Exit code:</b> <code>{}</code>\n<b>📼 Output:</b>\n<pre><code class='language-stdout'>{}</code></pre>",
|
||||
"sterminal_error": "⌨️<b> System command</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>PID:</b> <code>{}</code>\n<b>Exit code:</b> <code>{}</code>\n<b>🚫 Errors:</b>\n<pre><code class='language-stderr'>{}</code></pre>",
|
||||
"sterminal_output_and_error": "⌨️<b> System command</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>PID:</b> <code>{}</code>\n<b>Exit code:</b> <code>{}</code>\n<b>📼 Output:</b>\n<pre><code class='language-stdout'>{}</code></pre>\n<b>🚫 Errors:</b>\n<pre><code class='language-stderr'>{}</code></pre>",
|
||||
"sterminal_stopped": "⌨️<b> System command</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>PID:</b> <code>{}</code>\n<b>Status:</b> ⛔ Stopped by user\n<b>📼 Output:</b>\n<pre><code class='language-stdout'>{}</code></pre>",
|
||||
"addkey_description": "<key_content> - saves SSH private key to .ssh directory",
|
||||
"addkey_no_key": "<b>No key content provided!</b>",
|
||||
"addkey_success": "<b>Key saved successfully!</b>\n<b>Key file:</b> <code>{}</code>\n<b>Full path:</b> <code>{}</code>\n\nYou can now set it in config:\n<code>.fcfg SSHMod key_path {}</code>",
|
||||
"addkey_error": "<b>Error saving key:</b> <code>{}</code>",
|
||||
"config_not_set": "<b>Values are not set. Set them using the command:</b>\n<code>.config SSHMod</code>",
|
||||
"stop_button": "⛔ Stop",
|
||||
}
|
||||
|
||||
strings_ru = {
|
||||
"name": "SSHMod",
|
||||
"cfg_host": "IP-адрес или домен",
|
||||
"cfg_username": "Имя пользователя SSH",
|
||||
"cfg_password": "Пароль SSH",
|
||||
"cfg_port": "Порт SSH",
|
||||
"save_description": "<reply> - сохраняет файл в директорию ~/sshmod",
|
||||
"save_uploading": "<b>Начинаю загрузку....</b>",
|
||||
"save_success": "<b>Файл загружен на SSH сервер, расположение файла:</b> <code>~/sshmod/{}</code>",
|
||||
"save_no_file": "<b>В сообщении не найдены файлы!</b>",
|
||||
"save_reply_required": "<b>Команда должна быть ответом на сообщение!</b>",
|
||||
"sterminal_description": "<command> - выполняет команду на SSH сервере",
|
||||
"sterminal_no_command": "<b>Не указана команда для выполнения!</b>",
|
||||
"sterminal_output": "⌨️<b> Системная команда</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>Код выхода:</b> <code>{}</code>\n<b>📼 Вывод:</b>\n<pre><code class='language-stdout'>{}</code></pre>",
|
||||
"sterminal_error": "⌨️<b> Системная команда</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>Код выхода:</b> <code>{}</code>\n<b>🚫 Ошибки:</b>\n<pre><code class='language-stderr'>{}</code></pre>",
|
||||
"sterminal_output_and_error": "⌨️<b> Системная команда</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>Код выхода:</b> <code>{}</code>\n<b>📼 Вывод:</b>\n<pre><code class='language-stdout'>{}</code></pre>\n<b>🚫 Ошибки:</b>\n<pre><code class='language-stderr'>{}</code></pre>",
|
||||
"config_not_set": "<b>Значения не указаны. Укажите их через команду:</b>\n<code>.config SSHMod</code>",
|
||||
}
|
||||
strings_ru = {
|
||||
"name": "SSHMod",
|
||||
"cfg_host": "IP-адрес или домен",
|
||||
"cfg_username": "Имя пользователя SSH",
|
||||
"cfg_password": "Пароль SSH (оставьте None при использовании ключа)",
|
||||
"cfg_key": "Путь к закрытому SSH ключу (оставьте None при использовании пароля)",
|
||||
"cfg_port": "Порт SSH",
|
||||
"cfg_default_dir": "Директория по умолчанию для сохранения файлов",
|
||||
"sftpsave_description": "<reply> [директория] - сохраняет файл в указанную директорию",
|
||||
"sftpsave_uploading": "<b>Начинаю загрузку....</b>",
|
||||
"sftpsave_success": "<b>Файл загружен на SSH сервер, расположение файла:</b> <code>{}</code>",
|
||||
"sftpsave_no_file": "<b>В сообщении не найдены файлы!</b>",
|
||||
"sftpsave_reply_required": "<b>Команда должна быть ответом на сообщение!</b>",
|
||||
"sftpupload_description": "<путь_к_файлу> - скачивает файл с SSH сервера",
|
||||
"sftpupload_no_path": "<b>Не указан путь к файлу!</b>",
|
||||
"sftpupload_downloading": "<b>Скачиваю файл с SSH сервера...</b>",
|
||||
"sftpupload_error": "<b>Ошибка при скачивании файла:</b> <code>{}</code>",
|
||||
"sterminal_description": "<command> - выполняет команду на SSH сервере",
|
||||
"sterminal_no_command": "<b>Не указана команда для выполнения!</b>",
|
||||
"sterminal_starting": "⌨️<b> Системная команда</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>PID:</b> <code>{}</code>\n<b>Статус:</b> Выполняется...\n<b>📼 Вывод:</b>\n<pre><code class='language-stdout'>{}</code></pre>",
|
||||
"sterminal_output": "⌨️<b> Системная команда</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>PID:</b> <code>{}</code>\n<b>Код выхода:</b> <code>{}</code>\n<b>📼 Вывод:</b>\n<pre><code class='language-stdout'>{}</code></pre>",
|
||||
"sterminal_error": "⌨️<b> Системная команда</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>PID:</b> <code>{}</code>\n<b>Код выхода:</b> <code>{}</code>\n<b>🚫 Ошибки:</b>\n<pre><code class='language-stderr'>{}</code></pre>",
|
||||
"sterminal_output_and_error": "⌨️<b> Системная команда</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>PID:</b> <code>{}</code>\n<b>Код выхода:</b> <code>{}</code>\n<b>📼 Вывод:</b>\n<pre><code class='language-stdout'>{}</code></pre>\n<b>🚫 Ошибки:</b>\n<pre><code class='language-stderr'>{}</code></pre>",
|
||||
"sterminal_stopped": "⌨️<b> Системная команда</b>\n<pre><code class='language-bash'>{}</code></pre>\n<b>PID:</b> <code>{}</code>\n<b>Статус:</b> ⛔ Остановлено пользователем\n<b>📼 Вывод:</b>\n<pre><code class='language-stdout'>{}</code></pre>",
|
||||
"addkey_description": "<содержимое_ключа> - сохраняет SSH ключ в директорию .ssh",
|
||||
"addkey_no_key": "<b>Не указано содержимое ключа!</b>",
|
||||
"addkey_success": "<b>Ключ успешно сохранён!</b>\n<b>Имя файла:</b> <code>{}</code>\n<b>Полный путь:</b> <code>{}</code>\n\nДля применения напишите:\n<code>.fcfg SSHMod key_path {}</code>",
|
||||
"addkey_error": "<b>Ошибка при сохранении ключа:</b> <code>{}</code>",
|
||||
"config_not_set": "<b>Значения не указаны. Укажите их через команду:</b>\n<code>.config SSHMod</code>",
|
||||
"stop_button": "⛔ Остановить",
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
loader.ConfigValue(
|
||||
"host",
|
||||
"None",
|
||||
lambda: self.strings["cfg_host"],
|
||||
validator=loader.validators.String(),
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"username",
|
||||
"None",
|
||||
lambda: self.strings["cfg_username"],
|
||||
validator=loader.validators.String(),
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"password",
|
||||
"None",
|
||||
lambda: self.strings["cfg_password"],
|
||||
validator=loader.validators.Hidden(),
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"Port",
|
||||
22,
|
||||
lambda: self.strings["cfg_port"],
|
||||
validator=loader.validators.String(),
|
||||
),
|
||||
)
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
loader.ConfigValue(
|
||||
"host",
|
||||
"None",
|
||||
lambda: self.strings["cfg_host"],
|
||||
validator=loader.validators.String(),
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"username",
|
||||
"None",
|
||||
lambda: self.strings["cfg_username"],
|
||||
validator=loader.validators.String(),
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"password",
|
||||
"None",
|
||||
lambda: self.strings["cfg_password"],
|
||||
validator=loader.validators.Hidden(),
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"key_path",
|
||||
"None",
|
||||
lambda: self.strings["cfg_key"],
|
||||
validator=loader.validators.String(),
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"Port",
|
||||
22,
|
||||
lambda: self.strings["cfg_port"],
|
||||
validator=loader.validators.Integer(),
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"default_directory",
|
||||
"sshmod",
|
||||
lambda: self.strings["cfg_default_dir"],
|
||||
validator=loader.validators.String(),
|
||||
),
|
||||
)
|
||||
self.active_tasks = {}
|
||||
|
||||
@loader.command(alias="save")
|
||||
async def save(self, message):
|
||||
"""<reply> - saves the file to the ~/sshmod directory"""
|
||||
host = self.config["host"] or "None"
|
||||
username = self.config["username"] or "None"
|
||||
password = self.config["password"] or "None"
|
||||
port = self.config["Port"] or "None"
|
||||
if host == "None" or username == "None" or password == "None" or port == "None":
|
||||
await utils.answer(message, self.strings["config_not_set"])
|
||||
return
|
||||
reply = await message.get_reply_message()
|
||||
if reply:
|
||||
if reply.media:
|
||||
await utils.answer(message, self.strings["save_uploading"])
|
||||
file_path = await message.client.download_media(reply.media)
|
||||
sftp_path = f"sshmod/{os.path.basename(file_path)}"
|
||||
upload_file_sftp(host, port, username, password, file_path, sftp_path)
|
||||
os.remove(file_path)
|
||||
await utils.answer(
|
||||
message,
|
||||
self.strings["save_success"].format(os.path.basename(file_path)),
|
||||
)
|
||||
else:
|
||||
await utils.answer(message, self.strings["save_no_file"])
|
||||
else:
|
||||
await utils.answer(message, self.strings["save_reply_required"])
|
||||
@loader.command()
|
||||
async def sftpsave(self, message):
|
||||
"""<reply> [dir] - сохраняет указанных файл на сервер"""
|
||||
host = self.config["host"]
|
||||
username = self.config["username"]
|
||||
password = self.config["password"]
|
||||
key_path = self.config["key_path"]
|
||||
port = self.config["Port"]
|
||||
|
||||
if host == "None" or username == "None" or (password == "None" and key_path == "None"):
|
||||
await utils.answer(message, self.strings["config_not_set"])
|
||||
return
|
||||
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await utils.answer(message, self.strings["sftpsave_reply_required"])
|
||||
return
|
||||
|
||||
if not reply.media:
|
||||
await utils.answer(message, self.strings["sftpsave_no_file"])
|
||||
return
|
||||
args = utils.get_args_raw(message)
|
||||
remote_dir = args if args else self.config["default_directory"]
|
||||
|
||||
await utils.answer(message, self.strings["sftpsave_uploading"])
|
||||
|
||||
file_path = await message.client.download_media(reply.media)
|
||||
file_name = os.path.basename(file_path)
|
||||
sftp_path = f"{remote_dir}/{file_name}"
|
||||
|
||||
conn = SSHConnection(host, port, username, password, key_path)
|
||||
await conn.connect()
|
||||
await conn.upload_file(file_path, sftp_path)
|
||||
conn.close()
|
||||
|
||||
os.remove(file_path)
|
||||
|
||||
await utils.answer(
|
||||
message,
|
||||
self.strings["sftpsave_success"].format(sftp_path),
|
||||
)
|
||||
|
||||
@loader.command(alias="sterminal")
|
||||
async def sterminal(self, message):
|
||||
"""<command> - executes a command on the SSH server"""
|
||||
host = self.config["host"] or "None"
|
||||
username = self.config["username"] or "None"
|
||||
password = self.config["password"] or "None"
|
||||
port = self.config["Port"] or "None"
|
||||
if host == "None" or username == "None" or password == "None" or port == "None":
|
||||
await utils.answer(message, self.strings["config_not_set"])
|
||||
return
|
||||
command = utils.get_args_raw(message)
|
||||
if not command:
|
||||
await utils.answer(message, self.strings["sterminal_no_command"])
|
||||
return
|
||||
@loader.command()
|
||||
async def sftpdownload(self, message):
|
||||
"""<path> - скачивает указанных файл с сервера"""
|
||||
host = self.config["host"]
|
||||
username = self.config["username"]
|
||||
password = self.config["password"]
|
||||
key_path = self.config["key_path"]
|
||||
port = self.config["Port"]
|
||||
|
||||
if host == "None" or username == "None" or (password == "None" and key_path == "None"):
|
||||
await utils.answer(message, self.strings["config_not_set"])
|
||||
return
|
||||
|
||||
remote_path = utils.get_args_raw(message)
|
||||
if not remote_path:
|
||||
await utils.answer(message, self.strings["sftpupload_no_path"])
|
||||
return
|
||||
|
||||
await utils.answer(message, self.strings["sftpupload_downloading"])
|
||||
|
||||
local_file = f"/tmp/sftp_download_{random.randint(1000, 9999)}_{os.path.basename(remote_path)}"
|
||||
|
||||
try:
|
||||
conn = SSHConnection(host, port, username, password, key_path)
|
||||
await conn.connect()
|
||||
await conn.download_file(remote_path, local_file)
|
||||
conn.close()
|
||||
|
||||
await utils.answer_file(
|
||||
message,
|
||||
local_file,
|
||||
f"📥 File from SSH server: <code>{remote_path}</code>"
|
||||
)
|
||||
|
||||
if os.path.exists(local_file):
|
||||
os.remove(local_file)
|
||||
|
||||
except Exception as e:
|
||||
await utils.answer(message, self.strings["sftpupload_error"].format(str(e)))
|
||||
if os.path.exists(local_file):
|
||||
os.remove(local_file)
|
||||
|
||||
# Выполняем команду на SSH сервере
|
||||
exit_code, output, error = execute_ssh_command(host, port, username, password, command)
|
||||
@loader.command()
|
||||
async def addkey(self, message):
|
||||
"""<ключ> - сохраняет указанный ssh ключ"""
|
||||
key_content = utils.get_args_raw(message)
|
||||
|
||||
if not key_content:
|
||||
await utils.answer(message, self.strings["addkey_no_key"])
|
||||
return
|
||||
|
||||
try:
|
||||
ssh_dir = os.path.expanduser("~/.ssh")
|
||||
os.makedirs(ssh_dir, exist_ok=True)
|
||||
|
||||
random_name = ''.join(random.choices(string.ascii_lowercase + string.digits, k=12))
|
||||
key_filename = f"ssh_key_{random_name}"
|
||||
key_path = os.path.join(ssh_dir, key_filename)
|
||||
|
||||
with open(key_path, 'w') as f:
|
||||
f.write(key_content)
|
||||
|
||||
os.chmod(key_path, 0o600)
|
||||
|
||||
await utils.answer(
|
||||
message,
|
||||
self.strings["addkey_success"].format(key_filename, key_path, key_path)
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
await utils.answer(message, self.strings["addkey_error"].format(str(e)))
|
||||
|
||||
# Формируем ответ в зависимости от наличия вывода и ошибок
|
||||
if output and not error:
|
||||
response = self.strings["sterminal_output"].format(command, exit_code, output)
|
||||
elif error and not output:
|
||||
response = self.strings["sterminal_error"].format(command, exit_code, error)
|
||||
elif output and error:
|
||||
response = self.strings["sterminal_output_and_error"].format(command, exit_code, output, error)
|
||||
else:
|
||||
response = f"⌨️<b> System command</b>\n<pre><code class='language-bash'>{command}</code></pre>\n<b>Exit code:</b> <code>{exit_code}</code>"
|
||||
@loader.command(alias="ssh")
|
||||
async def sterminal(self, message):
|
||||
"""<команда> - выполняет команду на ssh сервере"""
|
||||
host = self.config["host"]
|
||||
username = self.config["username"]
|
||||
password = self.config["password"]
|
||||
key_path = self.config["key_path"]
|
||||
port = self.config["Port"]
|
||||
|
||||
if host == "None" or username == "None" or (password == "None" and key_path == "None"):
|
||||
await utils.answer(message, self.strings["config_not_set"])
|
||||
return
|
||||
|
||||
command = utils.get_args_raw(message)
|
||||
if not command:
|
||||
await utils.answer(message, self.strings["sterminal_no_command"])
|
||||
return
|
||||
|
||||
await utils.answer(message, response)
|
||||
conn = SSHConnection(host, port, username, password, key_path)
|
||||
await conn.connect()
|
||||
|
||||
output_buffer = []
|
||||
error_buffer = []
|
||||
current_pid = None
|
||||
stop_flag = False
|
||||
|
||||
def stream_callback(stream_type, data, pid):
|
||||
nonlocal current_pid
|
||||
if current_pid is None:
|
||||
current_pid = pid
|
||||
if stream_type == 'stdout':
|
||||
output_buffer.append(data)
|
||||
else:
|
||||
error_buffer.append(data)
|
||||
|
||||
stop_button = {
|
||||
"text": self.strings["stop_button"],
|
||||
"callback": self._stop_callback,
|
||||
"args": (message.chat_id, message.id),
|
||||
}
|
||||
|
||||
task_id = f"{message.chat_id}_{message.id}"
|
||||
self.active_tasks[task_id] = {'stop': False, 'conn': conn}
|
||||
|
||||
msg = await utils.answer(
|
||||
message,
|
||||
self.strings["sterminal_starting"].format(command, "...", ""),
|
||||
reply_markup=[[stop_button]]
|
||||
)
|
||||
|
||||
async def execute_task():
|
||||
try:
|
||||
exit_code, output, error, pid = await conn.execute_command_stream(
|
||||
command,
|
||||
stream_callback
|
||||
)
|
||||
|
||||
if self.active_tasks.get(task_id, {}).get('stop'):
|
||||
current_output = ''.join(output_buffer)
|
||||
await utils.answer(
|
||||
msg,
|
||||
self.strings["sterminal_stopped"].format(
|
||||
command,
|
||||
pid if pid else "N/A",
|
||||
current_output if current_output else "No output"
|
||||
)
|
||||
)
|
||||
else:
|
||||
if output and not error:
|
||||
response = self.strings["sterminal_output"].format(command, pid, exit_code, output)
|
||||
elif error and not output:
|
||||
response = self.strings["sterminal_error"].format(command, pid, exit_code, error)
|
||||
elif output and error:
|
||||
response = self.strings["sterminal_output_and_error"].format(command, pid, exit_code, output, error)
|
||||
else:
|
||||
response = f"⌨️<b> System command</b>\n<pre><code class='language-bash'>{command}</code></pre>\n<b>PID:</b> <code>{pid}</code>\n<b>Exit code:</b> <code>{exit_code}</code>"
|
||||
|
||||
await utils.answer(msg, response)
|
||||
|
||||
except Exception as e:
|
||||
await utils.answer(msg, f"<b>Error:</b> {str(e)}")
|
||||
finally:
|
||||
conn.close()
|
||||
if task_id in self.active_tasks:
|
||||
del self.active_tasks[task_id]
|
||||
|
||||
asyncio.create_task(execute_task())
|
||||
|
||||
for _ in range(60):
|
||||
await asyncio.sleep(2)
|
||||
|
||||
if task_id not in self.active_tasks:
|
||||
break
|
||||
|
||||
if self.active_tasks[task_id].get('stop'):
|
||||
break
|
||||
|
||||
current_output = ''.join(output_buffer[-20:])
|
||||
if current_output:
|
||||
await msg.edit(
|
||||
self.strings["sterminal_starting"].format(
|
||||
command,
|
||||
current_pid if current_pid else "...",
|
||||
current_output[-1500:] # Ограничение длины
|
||||
),
|
||||
reply_markup=[[stop_button]]
|
||||
)
|
||||
|
||||
async def _stop_callback(self, call, chat_id, msg_id):
|
||||
"""Callback для кнопки остановки"""
|
||||
task_id = f"{chat_id}_{msg_id}"
|
||||
if task_id in self.active_tasks:
|
||||
self.active_tasks[task_id]['stop'] = True
|
||||
try:
|
||||
self.active_tasks[task_id]['conn'].close()
|
||||
except:
|
||||
pass
|
||||
await call.answer("Stopping...")
|
||||
@@ -49,34 +49,4 @@ class TTFMod(loader.Module):
|
||||
|
||||
# Удаление файла
|
||||
os.remove(file_path)
|
||||
|
||||
@loader.command()
|
||||
async def ttf_noreply(self, message):
|
||||
"""
|
||||
Создает текстовый файл с заданным именем и расширением,
|
||||
записывает в него текст, отправляет его в Telegram и удаляет с диска.
|
||||
|
||||
Пример:
|
||||
.ttf название.txt
|
||||
Текст для файла
|
||||
|
||||
"""
|
||||
args = utils.get_args_raw(message).split("\n")
|
||||
if len(args) < 1:
|
||||
await message.edit("Недостаточно аргументов. Используйте: .ttf название.txt\nТекст для файла")
|
||||
return
|
||||
|
||||
filename = args[0].strip()
|
||||
text = "\n".join(args[1:])
|
||||
|
||||
# Создание файла
|
||||
file_path = os.path.join(os.getcwd(), filename)
|
||||
with open(file_path, 'w') as file:
|
||||
file.write(text)
|
||||
await message.client.delete_messages(message.chat_id, message.id)
|
||||
# Отправка файла
|
||||
await message.client.send_file(message.chat_id, file_path)
|
||||
|
||||
# Удаление файла
|
||||
os.remove(file_path)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user