374 lines
14 KiB
Python
Executable File
374 lines
14 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Script de prueba con los REQUEST BODIES COMPLETOS descubiertos
|
|
en el análisis de ingeniería reversa del código decompilado.
|
|
|
|
Incluye el objeto DetailedInfoDTO completo para estaciones.
|
|
"""
|
|
|
|
import requests
|
|
import json
|
|
import time
|
|
from datetime import datetime
|
|
|
|
# Headers correctos del análisis
|
|
HEADERS_CIRCULATION = {
|
|
"Content-Type": "application/json;charset=utf-8",
|
|
"User-key": "f4ce9fbfa9d721e39b8984805901b5df"
|
|
}
|
|
|
|
HEADERS_STATIONS = {
|
|
"Content-Type": "application/json;charset=utf-8",
|
|
"User-key": "0d021447a2fd2ac64553674d5a0c1a6f"
|
|
}
|
|
|
|
# URLs base
|
|
BASE_CIRCULATION = "https://circulacion.api.adif.es"
|
|
BASE_STATIONS = "https://estaciones.api.adif.es"
|
|
|
|
|
|
def test_endpoint(name, method, url, headers, data=None, save_response=False):
|
|
"""Probar un endpoint y mostrar resultado detallado"""
|
|
print(f"\n{'='*70}")
|
|
print(f"TEST: {name}")
|
|
print(f"{'='*70}")
|
|
print(f"Method: {method}")
|
|
print(f"URL: {url}")
|
|
print(f"Headers: {json.dumps(headers, indent=2)}")
|
|
|
|
if data:
|
|
print(f"\nRequest Body:")
|
|
print(json.dumps(data, indent=2, ensure_ascii=False))
|
|
|
|
try:
|
|
start_time = time.time()
|
|
|
|
if method == "GET":
|
|
response = requests.get(url, headers=headers, timeout=15, verify=True)
|
|
elif method == "POST":
|
|
response = requests.post(url, headers=headers, json=data, timeout=15, verify=True)
|
|
else:
|
|
print(f"❌ Método {method} no soportado")
|
|
return False
|
|
|
|
elapsed = time.time() - start_time
|
|
|
|
print(f"\n⏱️ Tiempo de respuesta: {elapsed:.2f}s")
|
|
print(f"📊 Status Code: {response.status_code}")
|
|
print(f"📦 Content-Length: {len(response.content)} bytes")
|
|
print(f"📋 Response Headers:")
|
|
for key, value in response.headers.items():
|
|
print(f" {key}: {value}")
|
|
|
|
if response.status_code == 200:
|
|
print("\n✅ SUCCESS - La petición funcionó!")
|
|
try:
|
|
result = response.json()
|
|
resp_str = json.dumps(result, indent=2, ensure_ascii=False)
|
|
print(f"\n📄 Response Body (primeros 1500 chars):")
|
|
print(resp_str[:1500])
|
|
if len(resp_str) > 1500:
|
|
print(f"\n... ({len(resp_str) - 1500} caracteres más)")
|
|
|
|
if save_response:
|
|
filename = f"response_{name.replace(' ', '_').replace('/', '_')}.json"
|
|
with open(filename, 'w', encoding='utf-8') as f:
|
|
json.dump(result, f, indent=2, ensure_ascii=False)
|
|
print(f"\n💾 Respuesta guardada en: {filename}")
|
|
|
|
return True
|
|
except json.JSONDecodeError:
|
|
print(f"\n⚠️ Respuesta no es JSON válido:")
|
|
print(response.text[:500])
|
|
return False
|
|
elif response.status_code == 401:
|
|
print("\n🔒 ERROR 401 - UNAUTHORIZED")
|
|
print("Problema de autenticación. Se necesitan headers adicionales.")
|
|
print(f"Response: {response.text[:500]}")
|
|
return False
|
|
elif response.status_code == 403:
|
|
print("\n🚫 ERROR 403 - FORBIDDEN")
|
|
print("Acceso denegado. Posible problema con User-key o autenticación.")
|
|
print(f"Response: {response.text[:500]}")
|
|
return False
|
|
elif response.status_code == 400:
|
|
print("\n❌ ERROR 400 - BAD REQUEST")
|
|
print("El formato del body es incorrecto.")
|
|
print(f"Response: {response.text[:500]}")
|
|
return False
|
|
elif response.status_code == 404:
|
|
print("\n❌ ERROR 404 - NOT FOUND")
|
|
print("El endpoint no existe.")
|
|
print(f"Response: {response.text[:500]}")
|
|
return False
|
|
else:
|
|
print(f"\n❌ ERROR {response.status_code}")
|
|
print(f"Response: {response.text[:500]}")
|
|
return False
|
|
|
|
except requests.exceptions.Timeout:
|
|
print("\n⏱️ ERROR: Timeout - El servidor no respondió a tiempo")
|
|
return False
|
|
except requests.exceptions.SSLError as e:
|
|
print(f"\n🔒 ERROR SSL: {str(e)}")
|
|
print("Posible certificate pinning activo en el servidor")
|
|
return False
|
|
except requests.exceptions.ConnectionError as e:
|
|
print(f"\n🌐 ERROR de Conexión: {str(e)}")
|
|
return False
|
|
except Exception as e:
|
|
print(f"\n💥 EXCEPTION: {type(e).__name__}: {str(e)}")
|
|
return False
|
|
|
|
|
|
def main():
|
|
print("=" * 70)
|
|
print("PRUEBAS CON REQUEST BODIES COMPLETOS")
|
|
print("Análisis de ingeniería reversa - Código decompilado")
|
|
print("=" * 70)
|
|
print(f"Fecha: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
|
|
results = {}
|
|
|
|
# =========================================================================
|
|
# TEST 1: Detalles de Estación con DetailedInfoDTO COMPLETO
|
|
# =========================================================================
|
|
print("\n\n" + "🔍 " * 20)
|
|
print("TEST 1: Detalles de Estación (DetailedInfoDTO completo)")
|
|
print("🔍 " * 20)
|
|
|
|
# Este es el body COMPLETO descubierto en el código
|
|
results['station_details'] = test_endpoint(
|
|
"Station Details - Madrid Atocha",
|
|
"POST",
|
|
f"{BASE_STATIONS}/portroyalmanager/secure/stations/onestation/",
|
|
HEADERS_STATIONS,
|
|
{
|
|
"detailedInfo": {
|
|
"extendedStationInfo": True,
|
|
"stationActivities": True,
|
|
"stationBanner": True,
|
|
"stationCommercialServices": True,
|
|
"stationInfo": True,
|
|
"stationServices": True,
|
|
"stationTransportServices": True
|
|
},
|
|
"stationCode": "10200", # Madrid Atocha
|
|
"token": "test_token_12345" # Token de prueba
|
|
},
|
|
save_response=True
|
|
)
|
|
|
|
# =========================================================================
|
|
# TEST 2: Observaciones de Estación
|
|
# =========================================================================
|
|
print("\n\n" + "🔍 " * 20)
|
|
print("TEST 2: Observaciones de Estación")
|
|
print("🔍 " * 20)
|
|
|
|
results['station_observations'] = test_endpoint(
|
|
"Station Observations - Multiple Stations",
|
|
"POST",
|
|
f"{BASE_STATIONS}/portroyalmanager/secure/stationsobservations/",
|
|
HEADERS_STATIONS,
|
|
{
|
|
"stationCodes": ["10200", "10302", "71801"] # Madrid, Madrid, Barcelona
|
|
},
|
|
save_response=True
|
|
)
|
|
|
|
# =========================================================================
|
|
# TEST 3: Salidas/Departures - TrafficCirculationPathRequest completo
|
|
# =========================================================================
|
|
print("\n\n" + "🔍 " * 20)
|
|
print("TEST 3: Salidas/Departures")
|
|
print("🔍 " * 20)
|
|
|
|
results['departures_all'] = test_endpoint(
|
|
"Departures - Madrid Atocha (ALL traffic)",
|
|
"POST",
|
|
f"{BASE_CIRCULATION}/portroyalmanager/secure/circulationpaths/departures/traffictype/",
|
|
HEADERS_CIRCULATION,
|
|
{
|
|
"commercialService": "BOTH",
|
|
"commercialStopType": "BOTH",
|
|
"destinationStationCode": None,
|
|
"originStationCode": None,
|
|
"page": {
|
|
"pageNumber": 0
|
|
},
|
|
"stationCode": "10200",
|
|
"trafficType": "ALL"
|
|
},
|
|
save_response=True
|
|
)
|
|
|
|
# =========================================================================
|
|
# TEST 4: Llegadas/Arrivals
|
|
# =========================================================================
|
|
print("\n\n" + "🔍 " * 20)
|
|
print("TEST 4: Llegadas/Arrivals")
|
|
print("🔍 " * 20)
|
|
|
|
results['arrivals_cercanias'] = test_endpoint(
|
|
"Arrivals - Madrid Atocha (CERCANIAS)",
|
|
"POST",
|
|
f"{BASE_CIRCULATION}/portroyalmanager/secure/circulationpaths/arrivals/traffictype/",
|
|
HEADERS_CIRCULATION,
|
|
{
|
|
"commercialService": "BOTH",
|
|
"commercialStopType": "BOTH",
|
|
"destinationStationCode": None,
|
|
"originStationCode": None,
|
|
"page": {
|
|
"pageNumber": 0
|
|
},
|
|
"stationCode": "10200",
|
|
"trafficType": "CERCANIAS"
|
|
},
|
|
save_response=True
|
|
)
|
|
|
|
# =========================================================================
|
|
# TEST 5: Entre Estaciones
|
|
# =========================================================================
|
|
print("\n\n" + "🔍 " * 20)
|
|
print("TEST 5: Entre Estaciones")
|
|
print("🔍 " * 20)
|
|
|
|
results['between_stations'] = test_endpoint(
|
|
"Between Stations - Madrid to Barcelona",
|
|
"POST",
|
|
f"{BASE_CIRCULATION}/portroyalmanager/secure/circulationpaths/betweenstations/traffictype/",
|
|
HEADERS_CIRCULATION,
|
|
{
|
|
"commercialService": "BOTH",
|
|
"commercialStopType": "BOTH",
|
|
"destinationStationCode": "71801", # Barcelona Sants
|
|
"originStationCode": "10200", # Madrid Atocha
|
|
"page": {
|
|
"pageNumber": 0
|
|
},
|
|
"stationCode": None,
|
|
"trafficType": "ALL"
|
|
},
|
|
save_response=True
|
|
)
|
|
|
|
# =========================================================================
|
|
# TEST 6: Detalles de Ruta - OneOrSeveralPathsRequest
|
|
# =========================================================================
|
|
print("\n\n" + "🔍 " * 20)
|
|
print("TEST 6: Detalles de Ruta Específica")
|
|
print("🔍 " * 20)
|
|
|
|
# Timestamp para hoy a las 00:00
|
|
today_timestamp = int(datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
|
|
|
results['onepaths'] = test_endpoint(
|
|
"OnePaths - Madrid to Barcelona",
|
|
"POST",
|
|
f"{BASE_CIRCULATION}/portroyalmanager/secure/circulationpathdetails/onepaths/",
|
|
HEADERS_CIRCULATION,
|
|
{
|
|
"allControlPoints": True,
|
|
"commercialNumber": None,
|
|
"destinationStationCode": "71801",
|
|
"launchingDate": today_timestamp, # Timestamp en milisegundos
|
|
"originStationCode": "10200"
|
|
},
|
|
save_response=True
|
|
)
|
|
|
|
# =========================================================================
|
|
# TEST 7: Composiciones de Tren
|
|
# =========================================================================
|
|
print("\n\n" + "🔍 " * 20)
|
|
print("TEST 7: Composiciones de Tren")
|
|
print("🔍 " * 20)
|
|
|
|
results['compositions'] = test_endpoint(
|
|
"Train Compositions",
|
|
"POST",
|
|
f"{BASE_CIRCULATION}/portroyalmanager/secure/circulationpaths/compositions/path/",
|
|
HEADERS_CIRCULATION,
|
|
{
|
|
"allControlPoints": False,
|
|
"commercialNumber": None,
|
|
"destinationStationCode": "71801",
|
|
"launchingDate": None,
|
|
"originStationCode": "10200"
|
|
},
|
|
save_response=True
|
|
)
|
|
|
|
# =========================================================================
|
|
# TEST 8: Salidas con diferentes TrafficTypes
|
|
# =========================================================================
|
|
print("\n\n" + "🔍 " * 20)
|
|
print("TEST 8: Diferentes TrafficTypes")
|
|
print("🔍 " * 20)
|
|
|
|
for traffic_type in ["AVLDMD", "TRAVELERS", "GOODS", "OTHERS"]:
|
|
results[f'departures_{traffic_type.lower()}'] = test_endpoint(
|
|
f"Departures - TrafficType={traffic_type}",
|
|
"POST",
|
|
f"{BASE_CIRCULATION}/portroyalmanager/secure/circulationpaths/departures/traffictype/",
|
|
HEADERS_CIRCULATION,
|
|
{
|
|
"commercialService": "BOTH",
|
|
"commercialStopType": "BOTH",
|
|
"page": {"pageNumber": 0},
|
|
"stationCode": "10200",
|
|
"trafficType": traffic_type
|
|
}
|
|
)
|
|
|
|
# =========================================================================
|
|
# RESUMEN FINAL
|
|
# =========================================================================
|
|
print("\n\n" + "="*70)
|
|
print("📊 RESUMEN DE PRUEBAS")
|
|
print("="*70)
|
|
|
|
total = len(results)
|
|
passed = sum(1 for v in results.values() if v)
|
|
failed = total - passed
|
|
|
|
print(f"\n📈 Estadísticas:")
|
|
print(f" Total de pruebas: {total}")
|
|
print(f" ✅ Exitosas: {passed}")
|
|
print(f" ❌ Fallidas: {failed}")
|
|
print(f" 📊 Tasa de éxito: {(passed/total*100):.1f}%")
|
|
|
|
print(f"\n📋 Detalle por prueba:")
|
|
for test_name, result in results.items():
|
|
status = "✅ PASS" if result else "❌ FAIL"
|
|
print(f" {status} - {test_name}")
|
|
|
|
print("\n" + "="*70)
|
|
|
|
if passed == total:
|
|
print("🎉 ¡ÉXITO TOTAL! Todas las pruebas pasaron.")
|
|
print("Los request bodies son correctos y el servidor los acepta.")
|
|
elif passed > 0:
|
|
print(f"⚠️ ÉXITO PARCIAL: {passed}/{total} pruebas funcionaron.")
|
|
print("\nLas pruebas fallidas probablemente requieren:")
|
|
print(" - Headers adicionales de autenticación (X-CanalMovil-*)")
|
|
print(" - Token válido generado por el sistema de autenticación HMAC")
|
|
print("\nVer API_REQUEST_BODIES.md sección 5 para más detalles.")
|
|
else:
|
|
print("❌ TODAS LAS PRUEBAS FALLARON")
|
|
print("\nPosibles causas:")
|
|
print(" 1. Sistema de autenticación HMAC-SHA256 requerido")
|
|
print(" 2. Headers X-CanalMovil-* faltantes")
|
|
print(" 3. Certificate pinning activo")
|
|
print(" 4. Servidor requiere User-Agent específico")
|
|
print("\nConsultar README.md sección 'Sistema de Autenticación'")
|
|
|
|
print("="*70 + "\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|