# Ingeniería Reversa de la API de Adif (Elcano) Este proyecto contiene la documentación y herramientas para interactuar con la API no documentada de Adif (sistema Elcano) obtenida mediante ingeniería reversa de la aplicación móvil oficial. ## Archivos - `base.apk` - Aplicación móvil original de Adif - `API_DOCUMENTATION.md` - Documentación completa de la API descubierta - `adif_client.py` - Cliente Python para interactuar con la API - `decompiled/` - Código fuente descompilado de la APK (generado) - `apk_extracted/` - Contenido extraído de la APK (generado) ## Hallazgos Principales ### URLs Base - **Estaciones**: `https://estaciones.api.adif.es` - **Circulaciones**: `https://circulacion.api.adif.es` - **Avisa (Incidencias)**: `https://avisa.adif.es` ### Autenticación La API usa **User-keys** en los headers HTTP en lugar de autenticación OAuth tradicional: ```http Content-Type: application/json;charset=utf-8 User-key: f4ce9fbfa9d721e39b8984805901b5df # Para circulaciones User-key: 0d021447a2fd2ac64553674d5a0c1a6f # Para estaciones ``` ### Endpoints Principales #### Circulaciones (Trenes) - `POST /portroyalmanager/secure/circulationpaths/departures/traffictype/` - Salidas - `POST /portroyalmanager/secure/circulationpaths/arrivals/traffictype/` - Llegadas - `POST /portroyalmanager/secure/circulationpaths/betweenstations/traffictype/` - Entre estaciones - `POST /portroyalmanager/secure/circulationpathdetails/onepaths/` - Detalles de ruta #### Estaciones - `GET /portroyalmanager/secure/stations/allstations/reducedinfo/{token}/` - Todas las estaciones - `POST /portroyalmanager/secure/stations/onestation/` - Detalles de estación ## Uso del Cliente Python ### Instalación ```bash # Crear y activar entorno virtual python3 -m venv venv source venv/bin/activate # En Linux/Mac # O en Windows: venv\Scripts\activate # Instalar dependencias pip install requests ``` ### Ejemplo Básico ```python from adif_client import AdifClient, TrafficType, State # Crear cliente client = AdifClient(debug=True) # Obtener salidas de una estación departures = client.get_departures( station_code="10200", # Madrid Atocha traffic_type=TrafficType.CERCANIAS, size=10 ) # Obtener trenes entre dos estaciones trains = client.get_between_stations( origin_station="10200", # Madrid Atocha destination_station="10302", # Madrid Chamartín traffic_type=TrafficType.ALL ) # Obtener detalles de una estación station = client.get_station_details("10200") ``` ### Ejecutar el ejemplo ```bash ./venv/bin/python adif_client.py ``` ## Estructura de la Aplicación La app está construida con: - **Kotlin** como lenguaje principal - **Retrofit** para las llamadas HTTP - **Hilt** para inyección de dependencias - **Coroutines** para operaciones asíncronas - **Firebase** para analytics ### Arquitectura ``` com.adif.elcanomovil/ ├── serviceNetworking/ # Capa de red │ ├── circulations/ # Servicios de circulaciones │ ├── stations/ # Servicios de estaciones │ ├── compositions/ # Composiciones de trenes │ ├── avisa/ # Sistema de incidencias │ └── subscriptions/ # Suscripciones ├── repositories/ # Repositorios (patrón Repository) ├── domain/ # Lógica de negocio └── ui*/ # Capas de presentación ``` ## Información Técnica ### Estados (State Enum) - `YES` - Sí - `NOT` - No - `BOTH` - Ambos **Nota**: En BuildConfig aparece como "ALL" pero en el código real es "BOTH" ### Tipos de Tráfico (TrafficType) - `CERCANIAS` - Trenes de cercanías - `MEDIA_DISTANCIA` - Media distancia - `LARGA_DISTANCIA` - Larga distancia - `ALL` - Todos los tipos ### PageInfo La paginación solo usa `pageNumber` (no incluye `size`): ```json { "page": { "pageNumber": 0 } } ``` ## ⚠️ ACTUALIZACIÓN IMPORTANTE: Sistema de Autenticación **Los tests iniciales fallaron porque la API usa un sistema de autenticación HMAC-SHA256 similar a AWS Signature V4.** ### El Problema Real La API NO usa simples API keys. Cada petición requiere: 1. **Headers especiales**: - `X-Elcano-Host` - `X-Elcano-Client: AndroidElcanoApp` - `X-Elcano-Date` (timestamp ISO UTC) - `X-Elcano-UserId` (ID único) - `Authorization` con firma HMAC-SHA256 2. **Claves secretas** almacenadas en librería nativa (`libapi-keys.so`): - `accessKey` (método nativo) - `secretKey` (método nativo) 3. **Firma de cada petición** que incluye: - Método HTTP - Path y parámetros - Payload (body JSON) - Headers canónicos - Timestamp ### Cómo Obtener las Claves **Método recomendado: Frida** ```bash # 1. Instalar Frida pip install frida-tools # 2. Conectar dispositivo Android / iniciar emulador adb devices # 3. Instalar la app adb install base.apk # 4. Ejecutar el script de extracción frida -U -f com.adif.elcanomovil -l frida_extract_keys.js --no-pause # 5. Interactuar con la app (ver trenes, etc.) # Las claves aparecerán en la consola ``` Ver `AUTH_EXPLAINED.md` para detalles completos del sistema de autenticación. ## Limitaciones Conocidas 1. **⚠️ Sistema de autenticación complejo**: Requiere extracción de claves nativas (ver arriba) 2. **Certificate Pinning**: La app implementa certificate pinning (bypasseable con Frida) 3. **UserID dinámico**: Se genera por instalación, no es fijo 4. **Autenticación Avisa**: El sistema Avisa requiere OAuth2 con flujo de password adicional ## Códigos de Estación Comunes - `10200` - Madrid Puerta de Atocha - `10302` - Madrid Chamartín-Clara Campoamor - `71801` - Barcelona Sants - `50000` - Valencia Nord - `11401` - Sevilla Santa Justa ## Herramientas Utilizadas - **jadx** - Descompilador de Android APK a código Java - **unzip** - Para extraer contenido de la APK - **Python requests** - Cliente HTTP - **curl** - Pruebas de endpoints ## Descompilación Para descompilar la APK manualmente: ```bash # Descargar jadx wget https://github.com/skylot/jadx/releases/download/v1.5.0/jadx-1.5.0.zip unzip jadx-1.5.0.zip -d jadx # Descompilar ./jadx/bin/jadx -d decompiled base.apk ``` ## Próximos Pasos - [ ] Investigar el formato exacto de los objetos de petición - [ ] Obtener un token válido para el endpoint de estaciones - [ ] Implementar autenticación OAuth para Avisa - [ ] Documentar códigos de estación - [ ] Crear mappings de respuestas JSON - [ ] Implementar manejo de errores robusto ## Advertencia Legal Este proyecto es solo para fines educativos y de investigación. La API de Adif es propiedad de ADIF y debe usarse respetando sus términos de servicio. No se debe abusar de la API ni usarla para fines comerciales sin autorización. ## Autor Proyecto de ingeniería reversa educativa.