mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-20 03:40:26 +00:00
14
.env.example
14
.env.example
@@ -34,9 +34,17 @@ REDIS_URL=redis://redis:6379/0
|
||||
|
||||
# ===== REMNAWAVE API =====
|
||||
REMNAWAVE_API_URL=https://panel.example.com
|
||||
REMNAWAVE_API_KEY=
|
||||
# Для панелей установленных скриптом eGames прописывать ключ в формате XXXXXXX:DDDDDDDD - https://panel.example.com/auth/login?XXXXXXX=DDDDDDDD
|
||||
REMNAWAVE_SECRET_KEY=your_secret_key_here
|
||||
REMNAWAVE_API_KEY=your_api_key_here
|
||||
|
||||
# Тип авторизации: "api_key", "basic_auth"
|
||||
REMNAWAVE_AUTH_TYPE=api_key
|
||||
|
||||
# Для панелей с Basic Auth (опционально)
|
||||
REMNAWAVE_USERNAME=
|
||||
REMNAWAVE_PASSWORD=
|
||||
|
||||
# Для панелей установленных скриптом eGames прописывать ключ в формате XXXXXXX:DDDDDDDD
|
||||
REMNAWAVE_SECRET_KEY=
|
||||
|
||||
# ========= ПОДПИСКИ =========
|
||||
# ===== ТРИАЛ ПОДПИСКА =====
|
||||
|
||||
@@ -32,6 +32,10 @@ class Settings(BaseSettings):
|
||||
REMNAWAVE_API_URL: str
|
||||
REMNAWAVE_API_KEY: str
|
||||
REMNAWAVE_SECRET_KEY: Optional[str] = None
|
||||
|
||||
REMNAWAVE_USERNAME: Optional[str] = None
|
||||
REMNAWAVE_PASSWORD: Optional[str] = None
|
||||
REMNAWAVE_AUTH_TYPE: str = "api_key"
|
||||
|
||||
TRIAL_DURATION_DAYS: int = 3
|
||||
TRIAL_TRAFFIC_LIMIT_GB: int = 10
|
||||
@@ -238,6 +242,16 @@ class Settings(BaseSettings):
|
||||
|
||||
except (ValueError, AttributeError):
|
||||
return []
|
||||
|
||||
def get_remnawave_auth_params(self) -> Dict[str, Optional[str]]:
|
||||
return {
|
||||
"base_url": self.REMNAWAVE_API_URL,
|
||||
"api_key": self.REMNAWAVE_API_KEY,
|
||||
"secret_key": self.REMNAWAVE_SECRET_KEY,
|
||||
"username": self.REMNAWAVE_USERNAME,
|
||||
"password": self.REMNAWAVE_PASSWORD,
|
||||
"auth_type": self.REMNAWAVE_AUTH_TYPE
|
||||
}
|
||||
|
||||
def get_autopay_warning_days(self) -> List[int]:
|
||||
try:
|
||||
|
||||
40
app/external/remnawave_api.py
vendored
40
app/external/remnawave_api.py
vendored
@@ -1,6 +1,7 @@
|
||||
import asyncio
|
||||
import json
|
||||
import ssl
|
||||
import base64
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Optional, Union, Any
|
||||
from urllib.parse import urlparse
|
||||
@@ -103,12 +104,15 @@ class RemnaWaveAPIError(Exception):
|
||||
|
||||
class RemnaWaveAPI:
|
||||
|
||||
def __init__(self, base_url: str, api_key: str, secret_key: Optional[str] = None):
|
||||
def __init__(self, base_url: str, api_key: str, secret_key: Optional[str] = None,
|
||||
username: Optional[str] = None, password: Optional[str] = None):
|
||||
self.base_url = base_url.rstrip('/')
|
||||
self.api_key = api_key
|
||||
self.secret_key = secret_key
|
||||
self.secret_key = secret_key
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.session: Optional[aiohttp.ClientSession] = None
|
||||
self.authenticated = False
|
||||
self.authenticated = False
|
||||
|
||||
def _detect_connection_type(self) -> str:
|
||||
parsed = urlparse(self.base_url)
|
||||
@@ -129,14 +133,9 @@ class RemnaWaveAPI:
|
||||
return "local"
|
||||
|
||||
return "external"
|
||||
|
||||
async def __aenter__(self):
|
||||
conn_type = self._detect_connection_type()
|
||||
|
||||
logger.info(f"Подключение к Remnawave: {self.base_url} (тип: {conn_type})")
|
||||
|
||||
|
||||
def _prepare_auth_headers(self) -> Dict[str, str]:
|
||||
headers = {
|
||||
'Authorization': f'Bearer {self.api_key}',
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'X-Forwarded-Proto': 'https',
|
||||
@@ -144,6 +143,27 @@ class RemnaWaveAPI:
|
||||
'X-Real-IP': '127.0.0.1'
|
||||
}
|
||||
|
||||
if self.username and self.password:
|
||||
import base64
|
||||
credentials = f"{self.username}:{self.password}"
|
||||
encoded_credentials = base64.b64encode(credentials.encode()).decode()
|
||||
headers['X-Api-Key'] = f"Basic {encoded_credentials}"
|
||||
logger.debug("Используем Basic Auth в X-Api-Key заголовке")
|
||||
else:
|
||||
headers['X-Api-Key'] = self.api_key
|
||||
logger.debug("Используем API ключ в X-Api-Key заголовке")
|
||||
|
||||
headers['Authorization'] = f'Bearer {self.api_key}'
|
||||
|
||||
return headers
|
||||
|
||||
async def __aenter__(self):
|
||||
conn_type = self._detect_connection_type()
|
||||
|
||||
logger.info(f"Подключение к Remnawave: {self.base_url} (тип: {conn_type})")
|
||||
|
||||
headers = self._prepare_auth_headers()
|
||||
|
||||
cookies = None
|
||||
if self.secret_key:
|
||||
if ':' in self.secret_key:
|
||||
|
||||
@@ -264,7 +264,14 @@ class MaintenanceService:
|
||||
self._is_checking = True
|
||||
self._status.last_check = datetime.utcnow()
|
||||
|
||||
api = RemnaWaveAPI(settings.REMNAWAVE_API_URL, settings.REMNAWAVE_API_KEY)
|
||||
auth_params = settings.get_remnawave_auth_params()
|
||||
api = RemnaWaveAPI(
|
||||
base_url=auth_params["base_url"],
|
||||
api_key=auth_params["api_key"],
|
||||
secret_key=auth_params["secret_key"],
|
||||
username=auth_params["username"],
|
||||
password=auth_params["password"]
|
||||
)
|
||||
|
||||
async with api:
|
||||
is_connected = await test_api_connection(api)
|
||||
|
||||
@@ -23,10 +23,13 @@ logger = logging.getLogger(__name__)
|
||||
class RemnaWaveService:
|
||||
|
||||
def __init__(self):
|
||||
auth_params = settings.get_remnawave_auth_params()
|
||||
self.api = RemnaWaveAPI(
|
||||
base_url=settings.REMNAWAVE_API_URL,
|
||||
api_key=settings.REMNAWAVE_API_KEY,
|
||||
secret_key=settings.REMNAWAVE_SECRET_KEY
|
||||
base_url=auth_params["base_url"],
|
||||
api_key=auth_params["api_key"],
|
||||
secret_key=auth_params["secret_key"],
|
||||
username=auth_params["username"],
|
||||
password=auth_params["password"]
|
||||
)
|
||||
|
||||
def _parse_remnawave_date(self, date_str: str) -> datetime:
|
||||
@@ -351,7 +354,7 @@ class RemnaWaveService:
|
||||
|
||||
async def update_squad_inbounds(self, squad_uuid: str, inbound_uuids: List[str]) -> bool:
|
||||
try:
|
||||
async with RemnaWaveAPI(settings.REMNAWAVE_API_URL, settings.REMNAWAVE_API_KEY) as api:
|
||||
async with self.api as api:
|
||||
data = {
|
||||
'uuid': squad_uuid,
|
||||
'inbounds': inbound_uuids
|
||||
@@ -873,7 +876,7 @@ class RemnaWaveService:
|
||||
|
||||
async def get_squad_details(self, squad_uuid: str) -> Optional[Dict]:
|
||||
try:
|
||||
async with RemnaWaveAPI(settings.REMNAWAVE_API_URL, settings.REMNAWAVE_API_KEY) as api:
|
||||
async with self.api as api:
|
||||
squad = await api.get_internal_squad_by_uuid(squad_uuid)
|
||||
if squad:
|
||||
return {
|
||||
@@ -890,7 +893,7 @@ class RemnaWaveService:
|
||||
|
||||
async def add_all_users_to_squad(self, squad_uuid: str) -> bool:
|
||||
try:
|
||||
async with RemnaWaveAPI(settings.REMNAWAVE_API_URL, settings.REMNAWAVE_API_KEY) as api:
|
||||
async with self.api as api:
|
||||
response = await api._make_request('POST', f'/api/internal-squads/{squad_uuid}/bulk-actions/add-users')
|
||||
return response.get('response', {}).get('eventSent', False)
|
||||
except Exception as e:
|
||||
@@ -899,7 +902,7 @@ class RemnaWaveService:
|
||||
|
||||
async def remove_all_users_from_squad(self, squad_uuid: str) -> bool:
|
||||
try:
|
||||
async with RemnaWaveAPI(settings.REMNAWAVE_API_URL, settings.REMNAWAVE_API_KEY) as api:
|
||||
async with self.api as api:
|
||||
response = await api._make_request('DELETE', f'/api/internal-squads/{squad_uuid}/bulk-actions/remove-users')
|
||||
return response.get('response', {}).get('eventSent', False)
|
||||
except Exception as e:
|
||||
@@ -908,7 +911,7 @@ class RemnaWaveService:
|
||||
|
||||
async def delete_squad(self, squad_uuid: str) -> bool:
|
||||
try:
|
||||
async with RemnaWaveAPI(settings.REMNAWAVE_API_URL, settings.REMNAWAVE_API_KEY) as api:
|
||||
async with self.api as api:
|
||||
response = await api.delete_internal_squad(squad_uuid)
|
||||
return response
|
||||
except Exception as e:
|
||||
@@ -917,7 +920,7 @@ class RemnaWaveService:
|
||||
|
||||
async def get_all_inbounds(self) -> List[Dict]:
|
||||
try:
|
||||
async with RemnaWaveAPI(settings.REMNAWAVE_API_URL, settings.REMNAWAVE_API_KEY) as api:
|
||||
async with self.api as api:
|
||||
response = await api._make_request('GET', '/api/config-profiles/inbounds')
|
||||
inbounds_data = response.get('response', {}).get('inbounds', [])
|
||||
|
||||
@@ -938,7 +941,7 @@ class RemnaWaveService:
|
||||
|
||||
async def rename_squad(self, squad_uuid: str, new_name: str) -> bool:
|
||||
try:
|
||||
async with RemnaWaveAPI(settings.REMNAWAVE_API_URL, settings.REMNAWAVE_API_KEY) as api:
|
||||
async with self.api as api:
|
||||
data = {
|
||||
'uuid': squad_uuid,
|
||||
'name': new_name
|
||||
@@ -951,7 +954,7 @@ class RemnaWaveService:
|
||||
|
||||
async def create_squad(self, name: str, inbound_uuids: List[str]) -> bool:
|
||||
try:
|
||||
async with RemnaWaveAPI(settings.REMNAWAVE_API_URL, settings.REMNAWAVE_API_KEY) as api:
|
||||
async with self.api as api:
|
||||
squad = await api.create_internal_squad(name, inbound_uuids)
|
||||
return squad is not None
|
||||
except Exception as e:
|
||||
|
||||
@@ -23,9 +23,13 @@ logger = logging.getLogger(__name__)
|
||||
class SubscriptionService:
|
||||
|
||||
def __init__(self):
|
||||
auth_params = settings.get_remnawave_auth_params()
|
||||
self.api = RemnaWaveAPI(
|
||||
base_url=settings.REMNAWAVE_API_URL,
|
||||
api_key=settings.REMNAWAVE_API_KEY
|
||||
base_url=auth_params["base_url"],
|
||||
api_key=auth_params["api_key"],
|
||||
secret_key=auth_params["secret_key"],
|
||||
username=auth_params["username"],
|
||||
password=auth_params["password"]
|
||||
)
|
||||
|
||||
async def create_remnawave_user(
|
||||
|
||||
Reference in New Issue
Block a user