Introducción:

Hace unos días tuve que tomar un colectivo pero no sabía exactamente donde tenía una de sus paradas ni cual era su frecuencia habitual. Recordando que RedBus tiene una aplicación para android decido bajarla pero en la misma solo se puede consultar el saldo y ver los puntos de venta de la tarjeta, aunque ninguna de esas opciones se encuentra actualmente en funcionamiento; el captcha que utilizan (para?…) nunca carga ergo no se puede consultar el saldo y puntos de venta responde con un “no se puede completar la operación”, entonces podríamos decir que la aplicación no sirve para nada aunque admito que tiene 3 funciones más las cuales ni siquiera quise probar: “Iniciar Sesión”, “Registrarme”, y “Restablecer Contraseña”.

Veamos si tenemos más suerte con su sitio web, en el momento que intenté visitarlo por primera vez el servidor estaba caído y subsecuentemente me pasó lo mismo en varias oportunidades durante el transcuros del mes, así que podríamos concluir que el nivel de confiabilidad para hacer consultas no es el mejor pero al menos era posible usar las funciones a diferencia de la aplicación de Android, siempre y cuando la página de RedBus no estuviese caída.

Análisis:

El sitio tiene varias funciones pero nos vamos a concentrar solo en una: Mapa de Buses y Cuando Viene (son exactamente lo mismo). Contiene un mapa donde se muestran los recorridos de las líneas de colectivo local y (en algunos casos) sus correspondientes paradas (aunque a veces de forma parcial) junto con la posición actual de los colectivos que están realizando el recorrido seleccionado. Viendo solo el código HTML podemos deducir que se está usando leaflet para crear y modificar el mapa:

<!-- Leaflet -->
<link rel="stylesheet" href="css/vendors/leaflet.1.71.min.css">
<script src="js/vendors/leaflet/leaflet.js"></script>
<script src="js/vendors/leaflet/rotatedMarker.js"></script>
<script src="js/vendors/leaflet/easy-button.js"></script>

También podemos ver que hay muchos scripts (115!) y cuando empezamos a revisar algunos podemos apreciar que en la mayoría el código javascript está totalmente ofuscado:

const _0x5b30a2 = _0x21cc;
(function(_0x4638df, _0xd17bb3) {
    const _0x37a139 = _0x21cc,
        _0xf9549a = _0x4638df();
    while (!![]) {
        try {
            const _0x1c4ba9 = parseInt(_0x37a139(0xb9)) / 0x1 * (-parseInt(_0x37a139(0xd1)) / 0x2) + parseInt(_0x37a139(0xc3)) / 0x3 + -parseInt(_0x37a139(0xc0)) / 0x4 + -parseInt(_0x37a139(0xb5)) / 0x5 * (-parseInt(_0x37a139(0xb8)) / 0x6) + parseInt(_0x37a139(0xcd)) / 0x7 * (-parseInt(_0x37a139(0xcc)) / 0x8) + -parseInt(_0x37a139(0xbe)) / 0x9 + parseInt(_0x37a139(0xc6)) / 0xa;
            if (_0x1c4ba9 === _0xd17bb3) break;
            else _0xf9549a['push'](_0xf9549a['shift']());
        } catch (_0x180fb0) {
            _0xf9549a['push'](_0xf9549a['shift']());
        }
    }
}(_0x2177, 0x392f7));

Pero antes de empezar a perder tiempo analizando código ofuscado veamos si las respuestas de red devuelven algo interesante:

devtools1
URL de respuesta en devtools.
devtools2
Respuesta del JSON con información de ubicación de paradas y rutas.
devtools3
Respuesta del JSON con información de los colectivos.

Como encontramos algo interesante ahora podemos volver a ver el código HTML y concentrarnos en esta sección que parece relevante:

<!-- Config -->
<script src="js/endpoints.min.js"></script>
<script src="rest/config.js/"></script>

Veamos un segmento de js/endpoints.min.js después de dejarlo mínimamente legible pero sin de-ofuscarlo realmente:

const endpoint = {
--snip--
    'getConfig': '/rest/getConfiguracion',
    'gruposLineas': '/rest/gruposLineas',
--snip--
};

Usando estas nuevas URLs obtenemos información muy valiosa, especialmente de gruposLineas que devuelve un JSON con todas las líneas de colectivo disponibles y un código que las identifica individualmente, esta información es usada por la página para armar el listado de colectivos en los elementos input. Si observamos el panel de devtools con las respuestas de red mientras los colectivos realizan su recorrido podemos ver que recibimos una actualización periódica de sus posiciones en la siguiente URL: /rest/posicionesBuses/X donde X es un número y ese número corresponde al mismo que es utilizado en gruposLineas para idetenficar cada línea con su ramal, además ese mismo número es utilizado también para encontrar un JSON que contiene, entre otros datos, un array con los puntos de latitud y longitud necesarios para crear los recorridos de los colectivos con sus respectivas paradas en: /rest/rutaLinea/X.

Con está información ya tenemos todo lo necesario para re-implementar el mismo sistema, podríamos tratar de entender el código ofuscado y ver alguna forma de re-escribirlo pero por experiencia esto es extremadamente tedioso y consume mucho tiempo, quizás sería mejor y más rápido hacer nuestra propia implementación y en caso de ser necesario volver y buscar que es lo que realmente están haciendo algunas funciones específicas.

Creando el nuevo código:

No voy a detallar mucho acá ya que el código está disponible en mi cuenta de github (y comentado!), pero sí me parece interesante explicar algunas cosas a tener en cuenta. Todo este proyecto lo hice durante un fin de semana aproximadamente y está en paridad con el código original en términos de funcionalidad; si realicé algunos cambios menores para (en mi opinión) mejorar la usabilidad pero el mayor desafío fué familiarizarme con leaflet (que no había usado con anterioridad) para poder renderizar los mapas, marcar wavepoints con sus coordenadas, crear rutas, capas, etc. El resto es simplemente entender los JSON, interpretarlos (en este caso fué sencillo especular a que funciones correspondían la mayoría de los valores, otros en menor medida requirieron ver el código ofuscado) y crear las funciones necesarias en javascript, obviamente también se requiere un mínimo conocimiento de CSS y HTML pero todo esto es relativamente básico.

Conclusiones:

Para finalizar, con la información obtenida se pueden realizar diferentes análisis y generar aplicaciones que nos podrían ser incluso aún más útil que su propósito original como por ejemplo: crear todo tipo de estadistícas incluyendo la cantidad activa de unidades por recorrido dada una franja horaria, cumplimiento de horarios y frecuencias, recibir alertas cuando el colectivo esté a cierta distancia, etc. Mi favorita es ver todos los colectivos activos al mismo tiempo, esto puede dar una pauta de que tan congestionado podría estar el tráfico en algunos sectores pero mejor aún, da la posibilidad de evitar los colectivos en tiempo real si así uno lo quisiese.

mapbuses
Un día de semana normal poco después de las 17hs.

También se podría crear una aplicación Android que funcione mayormente offline para al menos tener acceso a las rutas y paradas de los colectivos sin necesidad de depender de un servidor y poder acceder siempre a la información que realmente no necesita tener una conexión a internet en primer lugar. Quizás en un próximo blog…