392 lines
22 KiB
Python
392 lines
22 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
Тестовый скрипт для диагностики проблемы с использованием специальных заголовков
|
||
"""
|
||
|
||
import requests
|
||
import logging
|
||
import json
|
||
import sys
|
||
import os
|
||
import urllib3
|
||
import time
|
||
import socket
|
||
from requests.adapters import HTTPAdapter
|
||
from urllib3.util import Retry
|
||
|
||
# Отключение предупреждений о небезопасных SSL-соединениях
|
||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||
|
||
# Настройка логирования
|
||
logging.basicConfig(
|
||
level=logging.DEBUG,
|
||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||
)
|
||
logger = logging.getLogger(__name__)
|
||
|
||
# Тестовые учетные данные (для примера)
|
||
SYNOLOGY_HOST = "192.168.0.102"
|
||
SYNOLOGY_PORT = 5000
|
||
SYNOLOGY_USERNAME = "superadmin"
|
||
SYNOLOGY_PASSWORD = "Cl0ud_1985!"
|
||
SYNOLOGY_SECURE = False
|
||
SYNOLOGY_TIMEOUT = 10
|
||
|
||
def test_api_with_headers():
|
||
"""Тестирование API с использованием специальных заголовков для решения проблемы 119"""
|
||
|
||
# Создаем сессию
|
||
session = requests.Session()
|
||
session.verify = False # Отключаем проверку SSL
|
||
|
||
# Настройки повторных попыток
|
||
retry_strategy = Retry(
|
||
total=3,
|
||
status_forcelist=[429, 500, 502, 503, 504],
|
||
allowed_methods=["GET", "POST"],
|
||
backoff_factor=1.0
|
||
)
|
||
adapter = HTTPAdapter(max_retries=retry_strategy)
|
||
session.mount("http://", adapter)
|
||
session.mount("https://", adapter)
|
||
|
||
# Формируем базовый URL
|
||
protocol = "https" if SYNOLOGY_SECURE else "http"
|
||
base_url = f"{protocol}://{SYNOLOGY_HOST}:{SYNOLOGY_PORT}/webapi"
|
||
|
||
logger.info(f"Тестирование API с заголовками для {base_url}")
|
||
|
||
# Тест 1: Получение SID с настройкой cookie и user-agent
|
||
logger.info("Тест 1: Авторизация с настройкой cookie и user-agent")
|
||
|
||
# Добавление пользовательских заголовков
|
||
custom_headers = {
|
||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
||
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
||
'Accept-Language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
|
||
'X-Requested-With': 'XMLHttpRequest',
|
||
'Connection': 'keep-alive',
|
||
'Referer': f'{protocol}://{SYNOLOGY_HOST}:{SYNOLOGY_PORT}/'
|
||
}
|
||
|
||
session.headers.update(custom_headers)
|
||
|
||
try:
|
||
# Определяем путь для авторизации
|
||
auth_info_url = f"{base_url}/entry.cgi"
|
||
auth_info_params = {
|
||
"api": "SYNO.API.Info",
|
||
"version": "1",
|
||
"method": "query",
|
||
"query": "SYNO.API.Auth"
|
||
}
|
||
|
||
auth_info_response = session.get(auth_info_url, params=auth_info_params)
|
||
auth_info_data = auth_info_response.json()
|
||
|
||
if auth_info_data.get("success"):
|
||
auth_info = auth_info_data.get("data", {}).get("SYNO.API.Auth", {})
|
||
auth_path = auth_info.get("path", "auth.cgi")
|
||
auth_max_version = auth_info.get("maxVersion", 6)
|
||
|
||
logger.info(f"API авторизации: путь={auth_path}, макс. версия={auth_max_version}")
|
||
|
||
# Используем версию 3 вместо 6 - тестирование на возможное решение проблемы
|
||
auth_version = min(3, auth_max_version) # Пробуем более старую версию API
|
||
|
||
# Выполняем авторизацию
|
||
auth_url = f"{base_url}/{auth_path}"
|
||
auth_params = {
|
||
"api": "SYNO.API.Auth",
|
||
"version": str(auth_version),
|
||
"method": "login",
|
||
"account": SYNOLOGY_USERNAME,
|
||
"passwd": SYNOLOGY_PASSWORD,
|
||
"session": "DirectHeaderTest",
|
||
"format": "cookie"
|
||
}
|
||
|
||
if auth_version >= 6:
|
||
auth_params["enable_syno_token"] = "yes"
|
||
|
||
logger.info(f"Авторизация с использованием SYNO.API.Auth v{auth_version}")
|
||
auth_response = session.get(auth_url, params=auth_params)
|
||
auth_data = auth_response.json()
|
||
|
||
if auth_data.get("success"):
|
||
sid = auth_data.get("data", {}).get("sid")
|
||
logger.info(f"Авторизация успешна! SID: {sid[:10]}...")
|
||
|
||
# Теперь проверим, работает ли получение информации о системе
|
||
# с настройкой cookie и заголовков
|
||
|
||
# Сначала настроим куки для сохранения SID
|
||
cookies = {
|
||
'id': sid,
|
||
'sid': sid
|
||
}
|
||
session.cookies.update(cookies)
|
||
|
||
# Определяем путь для SYNO.DSM.Info
|
||
info_info_url = f"{base_url}/entry.cgi"
|
||
info_info_params = {
|
||
"api": "SYNO.API.Info",
|
||
"version": "1",
|
||
"method": "query",
|
||
"query": "SYNO.DSM.Info"
|
||
}
|
||
|
||
info_info_response = session.get(info_info_url, params=info_info_params)
|
||
info_info_data = info_info_response.json()
|
||
|
||
if info_info_data.get("success"):
|
||
info_info = info_info_data.get("data", {}).get("SYNO.DSM.Info", {})
|
||
info_path = info_info.get("path", "entry.cgi")
|
||
info_max_version = info_info.get("maxVersion", 1)
|
||
info_min_version = info_info.get("minVersion", 1)
|
||
|
||
logger.info(f"API SYNO.DSM.Info: путь={info_path}, версия={info_min_version}-{info_max_version}")
|
||
|
||
# Используем правильную версию API
|
||
info_version = min(2, info_max_version)
|
||
|
||
# Делаем запрос для получения информации о системе
|
||
# с использованием sid как параметр запроса
|
||
logger.info("Тест 2: Получение информации о системе с SID как параметром")
|
||
info_url = f"{base_url}/{info_path}"
|
||
info_params = {
|
||
"api": "SYNO.DSM.Info",
|
||
"version": str(info_version),
|
||
"method": "getinfo",
|
||
"_sid": sid
|
||
}
|
||
|
||
logger.info(f"Запрос информации с использованием SYNO.DSM.Info v{info_version}")
|
||
info_response = session.get(info_url, params=info_params)
|
||
info_data = info_response.json()
|
||
|
||
if info_data.get("success"):
|
||
logger.info("Успешно получена информация о системе!")
|
||
logger.info(f"Данные: {json.dumps(info_data.get('data', {}), indent=2)}")
|
||
else:
|
||
error_code = info_data.get("error", {}).get("code", -1)
|
||
logger.error(f"Не удалось получить информацию о системе. Ошибка: {error_code}")
|
||
|
||
# Пробуем альтернативный способ
|
||
logger.info("Тест 3: Попытка получить базовую информацию через SYNO.Core.System")
|
||
|
||
# Определяем путь для SYNO.Core.System
|
||
system_info_url = f"{base_url}/entry.cgi"
|
||
system_info_params = {
|
||
"api": "SYNO.API.Info",
|
||
"version": "1",
|
||
"method": "query",
|
||
"query": "SYNO.Core.System"
|
||
}
|
||
|
||
system_info_response = session.get(system_info_url, params=system_info_params)
|
||
system_info_data = system_info_response.json()
|
||
|
||
if system_info_data.get("success"):
|
||
system_info = system_info_data.get("data", {}).get("SYNO.Core.System", {})
|
||
system_path = system_info.get("path", "entry.cgi")
|
||
system_max_version = system_info.get("maxVersion", 1)
|
||
system_min_version = system_info.get("minVersion", 1)
|
||
|
||
logger.info(f"API SYNO.Core.System: путь={system_path}, версия={system_min_version}-{system_max_version}")
|
||
|
||
# Используем правильную версию API
|
||
system_version = 1
|
||
|
||
# Пробуем альтернативную стратегию с X-SYNO-TOKEN
|
||
# Некоторые API Synology требуют специальный токен в заголовках
|
||
token = auth_data.get("data", {}).get("synotoken")
|
||
if token:
|
||
session.headers.update({'X-SYNO-TOKEN': token})
|
||
logger.info(f"Добавлен X-SYNO-TOKEN: {token}")
|
||
|
||
# Делаем запрос для получения информации о системе
|
||
system_url = f"{base_url}/{system_path}"
|
||
system_params = {
|
||
"api": "SYNO.Core.System",
|
||
"version": str(system_version),
|
||
"method": "info",
|
||
"_sid": sid
|
||
}
|
||
|
||
logger.info(f"Запрос информации с использованием SYNO.Core.System v{system_version}")
|
||
system_response = session.get(system_url, params=system_params)
|
||
system_data = system_response.json()
|
||
|
||
if system_data.get("success"):
|
||
logger.info("Успешно получена информация о системе через SYNO.Core.System!")
|
||
logger.info(f"Данные: {json.dumps(system_data.get('data', {}), indent=2)}")
|
||
else:
|
||
error_code = system_data.get("error", {}).get("code", -1)
|
||
logger.error(f"Не удалось получить информацию через SYNO.Core.System. Ошибка: {error_code}")
|
||
|
||
# Пробуем другие методы для диагностики
|
||
logger.info("Тест 4: Попытка использовать различные методы и заголовки")
|
||
|
||
# Пробуем создать полностью новую сессию
|
||
new_session = requests.Session()
|
||
new_session.verify = False
|
||
new_session.headers.update(custom_headers)
|
||
|
||
# Пробуем версию 1 для авторизации
|
||
auth_version = 1
|
||
auth_params["version"] = str(auth_version)
|
||
|
||
auth_response = new_session.get(auth_url, params=auth_params)
|
||
auth_data = auth_response.json()
|
||
|
||
if auth_data.get("success"):
|
||
sid = auth_data.get("data", {}).get("sid")
|
||
logger.info(f"Новая авторизация (v{auth_version}) успешна! SID: {sid[:10]}...")
|
||
|
||
# Добавляем SID как куки
|
||
cookies = {
|
||
'id': sid,
|
||
'sid': sid
|
||
}
|
||
new_session.cookies.update(cookies)
|
||
|
||
# Пробуем другой подход: разделение запросов во времени
|
||
logger.info("Тест 5: Разделение запросов во времени")
|
||
|
||
# Даем некоторое время для инициализации сессии на сервере
|
||
time.sleep(2)
|
||
|
||
# Пробуем получить список файлов
|
||
filestation_info_url = f"{base_url}/entry.cgi"
|
||
filestation_info_params = {
|
||
"api": "SYNO.API.Info",
|
||
"version": "1",
|
||
"method": "query",
|
||
"query": "SYNO.FileStation.List"
|
||
}
|
||
|
||
filestation_info_response = new_session.get(filestation_info_url, params=filestation_info_params)
|
||
filestation_info_data = filestation_info_response.json()
|
||
|
||
if filestation_info_data.get("success"):
|
||
filestation_info = filestation_info_data.get("data", {}).get("SYNO.FileStation.List", {})
|
||
filestation_path = filestation_info.get("path", "entry.cgi")
|
||
filestation_max_version = filestation_info.get("maxVersion", 1)
|
||
|
||
logger.info(f"API SYNO.FileStation.List: путь={filestation_path}, макс. версия={filestation_max_version}")
|
||
|
||
# Используем правильную версию API
|
||
filestation_version = min(2, filestation_max_version)
|
||
|
||
# Делаем запрос для получения списка общих папок
|
||
filestation_url = f"{base_url}/{filestation_path}"
|
||
filestation_params = {
|
||
"api": "SYNO.FileStation.List",
|
||
"version": str(filestation_version),
|
||
"method": "list_share",
|
||
"_sid": sid
|
||
}
|
||
|
||
logger.info(f"Запрос списка общих папок с использованием SYNO.FileStation.List v{filestation_version}")
|
||
filestation_response = new_session.get(filestation_url, params=filestation_params)
|
||
filestation_data = filestation_response.json()
|
||
|
||
if filestation_data.get("success"):
|
||
logger.info("Успешно получен список общих папок!")
|
||
shares = filestation_data.get("data", {}).get("shares", [])
|
||
logger.info(f"Общие папки: {json.dumps(shares, indent=2)[:200]}...")
|
||
else:
|
||
error_code = filestation_data.get("error", {}).get("code", -1)
|
||
logger.error(f"Не удалось получить список общих папок. Ошибка: {error_code}")
|
||
else:
|
||
error_code = auth_data.get("error", {}).get("code", -1)
|
||
logger.error(f"Новая авторизация не удалась! Код ошибки: {error_code}")
|
||
else:
|
||
logger.error("Не удалось получить информацию о SYNO.Core.System API")
|
||
else:
|
||
logger.error("Не удалось получить информацию о SYNO.DSM.Info API")
|
||
else:
|
||
error_code = auth_data.get("error", {}).get("code", -1)
|
||
logger.error(f"Авторизация не удалась! Код ошибки: {error_code}")
|
||
else:
|
||
logger.error("Не удалось получить информацию об API авторизации")
|
||
|
||
except Exception as e:
|
||
logger.error(f"Произошла ошибка: {str(e)}")
|
||
|
||
# Тест 6: Проверка сетевой доступности
|
||
logger.info("Тест 6: Проверка сетевой доступности")
|
||
|
||
try:
|
||
# Проверка базового TCP-соединения
|
||
socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||
socket_obj.settimeout(SYNOLOGY_TIMEOUT)
|
||
result = socket_obj.connect_ex((SYNOLOGY_HOST, SYNOLOGY_PORT))
|
||
socket_obj.close()
|
||
|
||
if result == 0:
|
||
logger.info("TCP-соединение успешно установлено")
|
||
else:
|
||
logger.error(f"Не удалось установить TCP-соединение, код ошибки: {result}")
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при проверке TCP-соединения: {str(e)}")
|
||
|
||
# Тест 7: Запрос без аутентификации для проверки доступности API
|
||
logger.info("Тест 7: Запрос без аутентификации для проверки доступности API")
|
||
|
||
try:
|
||
# Создаем новую сессию без аутентификации
|
||
simple_session = requests.Session()
|
||
simple_session.verify = False
|
||
|
||
# Запрос к SYNO.API.Info не требует аутентификации
|
||
api_info_url = f"{base_url}/entry.cgi"
|
||
api_info_params = {
|
||
"api": "SYNO.API.Info",
|
||
"version": "1",
|
||
"method": "query",
|
||
"query": "all"
|
||
}
|
||
|
||
logger.info("Запрос информации о всех API без аутентификации")
|
||
api_info_response = simple_session.get(api_info_url, params=api_info_params)
|
||
|
||
if api_info_response.status_code == 200:
|
||
logger.info("API доступно без аутентификации")
|
||
api_info_data = api_info_response.json()
|
||
|
||
if api_info_data.get("success"):
|
||
logger.info("Успешно получена информация о всех API")
|
||
api_count = len(api_info_data.get("data", {}))
|
||
logger.info(f"Количество доступных API: {api_count}")
|
||
|
||
# Поиск API для управления питанием
|
||
power_apis = []
|
||
for api_name, api_info in api_info_data.get("data", {}).items():
|
||
if "power" in api_name.lower() or "reboot" in api_name.lower() or "shutdown" in api_name.lower():
|
||
power_apis.append(f"{api_name}: {api_info}")
|
||
|
||
logger.info(f"Найдены API для управления питанием: {power_apis}")
|
||
|
||
# Поиск API для получения информации о системе
|
||
info_apis = []
|
||
for api_name, api_info in api_info_data.get("data", {}).items():
|
||
if "info" in api_name.lower() or "system" in api_name.lower() or "status" in api_name.lower():
|
||
info_apis.append(f"{api_name}: {api_info}")
|
||
|
||
logger.info(f"Найдены API для информации о системе: {info_apis[:5]} и еще {len(info_apis)-5}")
|
||
else:
|
||
error_code = api_info_data.get("error", {}).get("code", -1)
|
||
logger.error(f"Запрос к API без аутентификации не удался! Код ошибки: {error_code}")
|
||
else:
|
||
logger.error(f"API не доступно без аутентификации. HTTP статус: {api_info_response.status_code}")
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при проверке доступности API: {str(e)}")
|
||
|
||
if __name__ == "__main__":
|
||
logger.info("Запуск теста API с заголовками")
|
||
test_api_with_headers()
|