mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-02-20 03:11:47 +00:00
@@ -64,8 +64,9 @@ REDIS_URL=redis://redis:6379/0
|
||||
REMNAWAVE_API_URL=https://panel.example.com
|
||||
REMNAWAVE_API_KEY=your_api_key_here
|
||||
|
||||
# Тип авторизации: "api_key", "basic_auth"
|
||||
# Тип авторизации: "api_key", "basic_auth", "caddy"
|
||||
REMNAWAVE_AUTH_TYPE=api_key
|
||||
REMNAWAVE_CADDY_TOKEN=YWRtaW46cGFzc3dvcmQ=
|
||||
|
||||
# Для панелей с Basic Auth (опционально)
|
||||
REMNAWAVE_USERNAME=
|
||||
|
||||
12
README.md
12
README.md
@@ -61,12 +61,12 @@
|
||||
|
||||
### 📚 Поддерживаемые методы авторизации
|
||||
|
||||
| Метод | Заголовок | Описание |
|
||||
|-------|-----------|----------|
|
||||
| API Key | X-Api-Key: your_api_key | Стандартный API ключ |
|
||||
| Bearer Token | Authorization: Bearer token | Классический Bearer token |
|
||||
| Basic Auth | X-Api-Key: Basic base64(user:pass) | Basic Authentication |
|
||||
| eGames Cookies | Cookies в формате key:value | Для панелей eGames |
|
||||
| Конфигурация | Authorization | X-Api-Key |
|
||||
|------------------|---------------------|---------------------|
|
||||
| Только API Key | Bearer <api_key> | <api_key> |
|
||||
| Basic Auth | Bearer <api_key> | Basic <user:pass> |
|
||||
| Caddy + API Key | Basic <caddy_token> | <api_key> |
|
||||
| Cookies (eGames) | Bearer <api_key> | <api_key> + cookies |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -79,7 +79,8 @@ class Settings(BaseSettings):
|
||||
|
||||
REMNAWAVE_USERNAME: Optional[str] = None
|
||||
REMNAWAVE_PASSWORD: Optional[str] = None
|
||||
REMNAWAVE_AUTH_TYPE: str = "api_key"
|
||||
REMNAWAVE_CADDY_TOKEN: Optional[str] = None
|
||||
REMNAWAVE_AUTH_TYPE: str = "api_key" # api_key, basic, bearer, cookies, caddy
|
||||
REMNAWAVE_USER_DESCRIPTION_TEMPLATE: str = "Bot user: {full_name} {username}"
|
||||
REMNAWAVE_USER_USERNAME_TEMPLATE: str = "user_{telegram_id}"
|
||||
REMNAWAVE_USER_DELETE_MODE: str = "delete" # "delete" или "disable"
|
||||
@@ -575,6 +576,7 @@ class Settings(BaseSettings):
|
||||
"secret_key": self.REMNAWAVE_SECRET_KEY,
|
||||
"username": self.REMNAWAVE_USERNAME,
|
||||
"password": self.REMNAWAVE_PASSWORD,
|
||||
"caddy_token": self.REMNAWAVE_CADDY_TOKEN,
|
||||
"auth_type": self.REMNAWAVE_AUTH_TYPE
|
||||
}
|
||||
|
||||
|
||||
41
app/external/remnawave_api.py
vendored
41
app/external/remnawave_api.py
vendored
@@ -225,14 +225,24 @@ class RemnaWaveAPIError(Exception):
|
||||
|
||||
|
||||
class RemnaWaveAPI:
|
||||
|
||||
def __init__(self, base_url: str, api_key: str, secret_key: Optional[str] = None,
|
||||
username: Optional[str] = None, password: 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,
|
||||
caddy_token: Optional[str] = None,
|
||||
auth_type: str = "api_key",
|
||||
):
|
||||
self.base_url = base_url.rstrip('/')
|
||||
self.api_key = api_key
|
||||
self.secret_key = secret_key
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.caddy_token = caddy_token
|
||||
self.auth_type = auth_type.lower() if auth_type else "api_key"
|
||||
self.session: Optional[aiohttp.ClientSession] = None
|
||||
self.authenticated = False
|
||||
|
||||
@@ -264,19 +274,32 @@ class RemnaWaveAPI:
|
||||
'X-Forwarded-For': '127.0.0.1',
|
||||
'X-Real-IP': '127.0.0.1'
|
||||
}
|
||||
|
||||
if self.username and self.password:
|
||||
import base64
|
||||
|
||||
# Caddy авторизация — добавляется поверх основной
|
||||
if self.caddy_token:
|
||||
# Caddy Security: готовый base64 токен используется как есть
|
||||
headers['Authorization'] = f'Basic {self.caddy_token}'
|
||||
logger.debug("Используем Caddy Basic Auth")
|
||||
|
||||
# Основная авторизация RemnaWave API
|
||||
if self.auth_type == "basic" and self.username and self.password:
|
||||
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 заголовке")
|
||||
elif self.auth_type == "caddy":
|
||||
# Для caddy auth_type основная авторизация уже в Authorization header
|
||||
# Но API ключ всё равно нужен для RemnaWave
|
||||
if self.api_key:
|
||||
headers['X-Api-Key'] = self.api_key
|
||||
logger.debug("Используем API ключ для RemnaWave + Caddy авторизацию")
|
||||
else:
|
||||
# api_key или bearer — стандартный режим
|
||||
headers['X-Api-Key'] = self.api_key
|
||||
if not self.caddy_token:
|
||||
headers['Authorization'] = f'Bearer {self.api_key}'
|
||||
logger.debug("Используем API ключ в X-Api-Key заголовке")
|
||||
|
||||
headers['Authorization'] = f'Bearer {self.api_key}'
|
||||
|
||||
|
||||
return headers
|
||||
|
||||
async def __aenter__(self):
|
||||
|
||||
@@ -293,6 +293,8 @@ class MaintenanceService:
|
||||
secret_key = (auth_params.get("secret_key") or "").strip() or None
|
||||
username = (auth_params.get("username") or "").strip() or None
|
||||
password = (auth_params.get("password") or "").strip() or None
|
||||
caddy_token = (auth_params.get("caddy_token") or "").strip() or None
|
||||
auth_type = (auth_params.get("auth_type") or "api_key").strip()
|
||||
|
||||
if not base_url:
|
||||
logger.error("REMNAWAVE_API_URL не настроен, пропускаем проверку API")
|
||||
@@ -311,7 +313,9 @@ class MaintenanceService:
|
||||
api_key=api_key,
|
||||
secret_key=secret_key,
|
||||
username=username,
|
||||
password=password
|
||||
password=password,
|
||||
caddy_token=caddy_token,
|
||||
auth_type=auth_type,
|
||||
)
|
||||
|
||||
attempts = settings.get_maintenance_retry_attempts()
|
||||
|
||||
@@ -165,7 +165,9 @@ class RemnaWaveService:
|
||||
api_key=api_key,
|
||||
secret_key=auth_params.get("secret_key"),
|
||||
username=auth_params.get("username"),
|
||||
password=auth_params.get("password")
|
||||
password=auth_params.get("password"),
|
||||
caddy_token=auth_params.get("caddy_token"),
|
||||
auth_type=auth_params.get("auth_type") or "api_key",
|
||||
)
|
||||
|
||||
@property
|
||||
|
||||
@@ -94,7 +94,8 @@ class SubscriptionService:
|
||||
secret_key = (auth_params.get("secret_key") or "").strip() or None
|
||||
username = (auth_params.get("username") or "").strip() or None
|
||||
password = (auth_params.get("password") or "").strip() or None
|
||||
auth_type = (auth_params.get("auth_type") or "").strip() or None
|
||||
caddy_token = (auth_params.get("caddy_token") or "").strip() or None
|
||||
auth_type = (auth_params.get("auth_type") or "api_key").strip()
|
||||
|
||||
config_signature = (
|
||||
base_url,
|
||||
@@ -102,7 +103,8 @@ class SubscriptionService:
|
||||
secret_key or "",
|
||||
username or "",
|
||||
password or "",
|
||||
auth_type or "",
|
||||
caddy_token or "",
|
||||
auth_type,
|
||||
)
|
||||
|
||||
if config_signature == self._last_config_signature:
|
||||
@@ -122,6 +124,8 @@ class SubscriptionService:
|
||||
secret_key=secret_key,
|
||||
username=username,
|
||||
password=password,
|
||||
caddy_token=caddy_token,
|
||||
auth_type=auth_type,
|
||||
)
|
||||
|
||||
if self._config_error:
|
||||
|
||||
Reference in New Issue
Block a user