Начальный этап бота с выдачей ключей
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
/venv
|
||||
/__pycache__
|
||||
/vpn_users.db
|
||||
/config.py
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
import requests
|
||||
from config import GET_INBOUNDS_URL, AUTH_URL, DOMEN
|
||||
import json
|
||||
|
||||
def login_with_credentials(username, password):
|
||||
auth_url = AUTH_URL
|
||||
data = {
|
||||
"username": username,
|
||||
"password": password
|
||||
}
|
||||
response = requests.post(auth_url, json=data)
|
||||
if response.status_code == 200:
|
||||
session = requests.Session()
|
||||
session.cookies.update(response.cookies)
|
||||
return session
|
||||
else:
|
||||
raise Exception(f"Ошибка авторизации: {response.status_code}, {response.text}")
|
||||
|
||||
def get_clients(session):
|
||||
response = session.get(GET_INBOUNDS_URL)
|
||||
if response.status_code == 200:
|
||||
return response.json() # Возвращает данные по инбаундам и клиентам
|
||||
else:
|
||||
raise Exception(f"Ошибка при получении клиентов: {response.status_code}, {response.text}")
|
||||
|
||||
def link(session, user_id: str):
|
||||
"""
|
||||
Получение ссылки для подключения по ID пользователя.
|
||||
:param session: requests.Session - авторизованная сессия
|
||||
:param user_id: str - идентификатор пользователя (email или другой параметр)
|
||||
:return: str - ссылка для подключения
|
||||
"""
|
||||
client_id = ''
|
||||
|
||||
# Получаем список клиентов через API
|
||||
response = get_clients(session)
|
||||
|
||||
if 'obj' not in response or len(response['obj']) == 0:
|
||||
raise Exception("Не удалось получить данные клиентов.")
|
||||
|
||||
# Извлекаем данные клиента
|
||||
inbounds = response['obj'][0] # Убедитесь, что это правильный индекс
|
||||
settings = json.loads(inbounds['settings'])
|
||||
|
||||
# Ищем клиента по user_id
|
||||
for client in settings["clients"]:
|
||||
if client['email'] == user_id:
|
||||
client_id = client["id"]
|
||||
break
|
||||
|
||||
if not client_id:
|
||||
raise Exception(f"Клиент с идентификатором {user_id} не найден.")
|
||||
|
||||
# Получаем streamSettings и генерируем ссылку
|
||||
stream_settings = json.loads(inbounds['streamSettings'])
|
||||
tcp = stream_settings.get('network', 'tcp') # Предположим, по умолчанию 'tcp'
|
||||
reality = stream_settings.get('security', 'reality') # Предположим, по умолчанию 'reality'
|
||||
flow = stream_settings.get('flow', 'xtls-rprx-vision') # Предположим, по умолчанию 'xtls-rprx-vision'
|
||||
email = user_id
|
||||
|
||||
# Создание ссылки для подключения VLESS
|
||||
val = f"vless://{client_id}@{DOMEN}?type={tcp}&security={reality}&fp=chrome&pbk=ZIMoEnEd8-qMJkReVU5JxbiEj8CCSrvpm_ckvJ-46TE&sni=yahoo.com&sid=0fb4b595&spx=%2F&flow={flow}#VPN_F-{email}"
|
||||
|
||||
return val
|
||||
@@ -0,0 +1,63 @@
|
||||
from aiogram import Bot, Dispatcher, Router, F, types
|
||||
from aiogram.filters import Command
|
||||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message
|
||||
from aiogram.fsm.storage.memory import MemoryStorage
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from auth import login_with_credentials, link
|
||||
from client import add_client, generate_client_id
|
||||
from datetime import datetime, timedelta
|
||||
from config import API_TOKEN, ADMIN_PASSWORD, ADMIN_USERNAME
|
||||
|
||||
|
||||
|
||||
class Form(StatesGroup):
|
||||
waiting_for_key_name = State()
|
||||
|
||||
bot = Bot(token=API_TOKEN)
|
||||
storage = MemoryStorage()
|
||||
dp = Dispatcher(bot=bot, storage=storage)
|
||||
router = Router()
|
||||
|
||||
@dp.message(Command("start"))
|
||||
async def start_command(message: Message):
|
||||
button_create_key = InlineKeyboardButton(text='Создать ключ', callback_data='create_key')
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[[button_create_key]])
|
||||
|
||||
await message.reply("Выберите действие:", reply_markup=keyboard)
|
||||
|
||||
@dp.callback_query(F.data == 'create_key')
|
||||
async def process_callback_create_key(callback_query: types.CallbackQuery, state: FSMContext):
|
||||
await callback_query.message.reply("Введите имя вашего профиля VPN:")
|
||||
await state.set_state(Form.waiting_for_key_name)
|
||||
|
||||
await callback_query.answer()
|
||||
|
||||
@dp.message()
|
||||
async def handle_text(message: types.Message, state: FSMContext):
|
||||
current_state = await state.get_state()
|
||||
|
||||
if current_state == Form.waiting_for_key_name.state:
|
||||
try:
|
||||
session = login_with_credentials(ADMIN_USERNAME, ADMIN_PASSWORD)
|
||||
|
||||
tg_id = message.from_user.id
|
||||
|
||||
email = message.text
|
||||
client_id = generate_client_id()
|
||||
email = message.text
|
||||
limit_ip = 1
|
||||
total_gb = 0
|
||||
current_time = datetime.utcnow()
|
||||
expiry_time = int((current_time + timedelta(days=30)).timestamp() * 1000)
|
||||
enable = True
|
||||
flow = "xtls-rprx-vision"
|
||||
|
||||
add_client(session, client_id, email, tg_id, limit_ip, total_gb, expiry_time, enable, flow)
|
||||
connection_link = link(session, email)
|
||||
|
||||
await message.reply(f"Ключ создан:\n<pre>{connection_link}</pre>", parse_mode="HTML")
|
||||
|
||||
await state.clear()
|
||||
except Exception as e:
|
||||
await message.reply(f"Произошла ошибка: {e}")
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
from aiogram import Bot, Dispatcher, Router, F, types
|
||||
from aiogram.filters import Command
|
||||
from aiogram.types import Message
|
||||
from aiogram.filters import Command
|
||||
import requests
|
||||
from database import add_user, get_user, update_subscription
|
||||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from aiogram.fsm.storage.memory import MemoryStorage
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
import uuid
|
||||
|
||||
|
||||
API_TOKEN = '7436953421:AAH9iUg86cLC8oxO_XZeqYEfSBhDGBodV5o'
|
||||
API_URL = "https://vpn.pocomacho.ru:34268/solonet"
|
||||
ADMIN_USERNAME = "paneladmin"
|
||||
ADMIN_PASSWORD = "L7CMDASN9x7g"
|
||||
ADD_CLIENT_URL = f"{API_URL}/panel/api/inbounds/addClient"
|
||||
|
||||
bot = Bot(token=API_TOKEN)
|
||||
storage = MemoryStorage()
|
||||
dp = Dispatcher(storage=storage)
|
||||
router = Router()
|
||||
|
||||
class Form(StatesGroup):
|
||||
waiting_for_key_name = State()
|
||||
|
||||
def login_with_credentials(username, password):
|
||||
auth_url = "https://vpn.pocomacho.ru:34268/solonet/login/"
|
||||
data = {
|
||||
"username": ADMIN_USERNAME,
|
||||
"password": ADMIN_PASSWORD
|
||||
}
|
||||
response = requests.post(auth_url, json=data)
|
||||
if response.status_code == 200:
|
||||
# Если API возвращает токен, используйте его в заголовке
|
||||
# return {"Authorization": f"Bearer {response.json().get('token')}"}
|
||||
|
||||
# Если API использует сессии (например, с cookies)
|
||||
session = requests.Session()
|
||||
session.cookies.update(response.cookies)
|
||||
return session
|
||||
|
||||
else:
|
||||
raise Exception(f"Ошибка авторизации: {response.status_code}, {response.text}")
|
||||
|
||||
def add_client(session, client_id, email, tg_id, limit_ip, total_gb, expiry_time, enable, flow):
|
||||
settings = {
|
||||
"clients": [
|
||||
{
|
||||
"id": client_id,
|
||||
"alterId": 0,
|
||||
"email": email,
|
||||
"limitIp": limit_ip,
|
||||
"totalGB": total_gb,
|
||||
"expiryTime": expiry_time,
|
||||
"enable": enable,
|
||||
"tgId": tg_id,
|
||||
"subId": "",
|
||||
"flow": flow
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
data = {
|
||||
"id": 1, # Можно изменить в зависимости от ваших требований
|
||||
"settings": json.dumps(settings)
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
response = session.post(ADD_CLIENT_URL, headers=headers, json=data)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
raise Exception(f"Ошибка при добавлении клиента: {response.status_code}, {response.text}")
|
||||
|
||||
# Обработчик команды /start
|
||||
@dp.message(Command("start"))
|
||||
async def start_command(message: Message):
|
||||
# Создаем кнопки
|
||||
button_create_key = InlineKeyboardButton(text='Создать ключ', callback_data='create_key')
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[[button_create_key]])
|
||||
|
||||
await message.reply("Выберите действие:", reply_markup=keyboard)
|
||||
|
||||
# Обработчик нажатия кнопки
|
||||
@dp.callback_query(F.data == 'create_key')
|
||||
async def process_callback_create_key(callback_query: types.CallbackQuery, state: FSMContext):
|
||||
await callback_query.message.reply("Введите имя для нового ключа:")
|
||||
await state.set_state(Form.waiting_for_key_name) # Устанавливаем состояние
|
||||
|
||||
await callback_query.answer()
|
||||
|
||||
# Обработчик текстовых сообщений
|
||||
@dp.message()
|
||||
async def handle_text(message: types.Message, state: FSMContext):
|
||||
# Получаем текущее состояние
|
||||
current_state = await state.get_state()
|
||||
|
||||
if current_state == Form.waiting_for_key_name.state:
|
||||
try:
|
||||
# Авторизация
|
||||
session = login_with_credentials(ADMIN_USERNAME, ADMIN_PASSWORD)
|
||||
|
||||
# Параметры клиента
|
||||
client_id = str(uuid.uuid4()) # Пример UUID
|
||||
email = message.text
|
||||
limit_ip = 1
|
||||
tg_id = message.from_user.id
|
||||
total_gb = 0 # В байтах
|
||||
current_time = datetime.utcnow()
|
||||
expiry_time = int((current_time + timedelta(days=30)).timestamp() * 1000) # Временная метка в миллисекундах
|
||||
enable = True
|
||||
flow = "xtls-rprx-vision"
|
||||
|
||||
# Добавление клиента
|
||||
result = add_client(session, client_id, email, tg_id, limit_ip, total_gb, expiry_time, enable, flow)
|
||||
|
||||
await message.reply(f"Ключ создан: {result}")
|
||||
|
||||
# Сброс состояния
|
||||
await state.clear()
|
||||
except Exception as e:
|
||||
await message.reply(f"Произошла ошибка: {e}")
|
||||
|
||||
# Запуск бота
|
||||
async def main():
|
||||
dp.include_router(router) # Подключение роутера
|
||||
await dp.start_polling(bot) # Запуск поллинга
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
import json
|
||||
import uuid
|
||||
from config import ADD_CLIENT_URL
|
||||
|
||||
def add_client(session, client_id, email, tg_id, limit_ip, total_gb, expiry_time, enable, flow):
|
||||
settings = {
|
||||
"clients": [
|
||||
{
|
||||
"id": client_id,
|
||||
"alterId": 0,
|
||||
"email": email,
|
||||
"limitIp": limit_ip,
|
||||
"totalGB": total_gb,
|
||||
"expiryTime": expiry_time,
|
||||
"enable": enable,
|
||||
"tgId": tg_id,
|
||||
"subId": "",
|
||||
"flow": flow
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
data = {
|
||||
"id": 1, # Можно изменить в зависимости от ваших требований
|
||||
"settings": json.dumps(settings)
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
response = session.post(ADD_CLIENT_URL, headers=headers, json=data)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
raise Exception(f"Ошибка при добавлении клиента: {response.status_code}, {response.text}")
|
||||
|
||||
def generate_client_id():
|
||||
return str(uuid.uuid4())
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
from sqlalchemy import create_engine, Column, Integer, String, DateTime
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
import datetime
|
||||
|
||||
DATABASE_URL = 'sqlite:///vpn_users.db'
|
||||
|
||||
engine = create_engine(DATABASE_URL)
|
||||
Session = sessionmaker(bind=engine)
|
||||
session = Session()
|
||||
Base = declarative_base()
|
||||
|
||||
class VPNUser(Base):
|
||||
__tablename__ = 'vpn_users'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
telegram_id = Column(Integer, unique=True)
|
||||
username = Column(String)
|
||||
subscription_end = Column(DateTime)
|
||||
access_key = Column(String)
|
||||
|
||||
Base.metadata.create_all(engine)
|
||||
|
||||
def add_user(telegram_id, username, access_key):
|
||||
user = VPNUser(telegram_id=telegram_id, username=username,
|
||||
subscription_end=datetime.datetime.now() + datetime.timedelta(days=30),
|
||||
access_key=access_key)
|
||||
session.add(user)
|
||||
session.commit()
|
||||
|
||||
def get_user(telegram_id):
|
||||
return session.query(VPNUser).filter(VPNUser.telegram_id == telegram_id).first()
|
||||
|
||||
def update_subscription(telegram_id, days):
|
||||
user = get_user(telegram_id)
|
||||
if user:
|
||||
user.subscription_end += datetime.timedelta(days=days)
|
||||
session.commit()
|
||||
@@ -0,0 +1,26 @@
|
||||
aiofiles==23.2.1
|
||||
aiogram==3.2.0
|
||||
aiohttp==3.9.5
|
||||
aiosignal==1.3.1
|
||||
annotated-types==0.7.0
|
||||
anyio==4.4.0
|
||||
attrs==24.2.0
|
||||
certifi==2024.8.30
|
||||
charset-normalizer==3.3.2
|
||||
frozenlist==1.4.1
|
||||
greenlet==3.1.0
|
||||
h11==0.14.0
|
||||
httpcore==1.0.5
|
||||
httpx==0.27.2
|
||||
idna==3.8
|
||||
magic-filter==1.0.12
|
||||
multidict==6.1.0
|
||||
py3xui==0.2.3
|
||||
pydantic==2.5.3
|
||||
pydantic_core==2.14.6
|
||||
requests==2.32.3
|
||||
sniffio==1.3.1
|
||||
SQLAlchemy==2.0.34
|
||||
typing_extensions==4.12.2
|
||||
urllib3==2.2.3
|
||||
yarl==1.11.1
|
||||
Reference in New Issue
Block a user