Projet Monitor HaMo

De Wiki LOGre
Aller à : navigation, rechercher


Monitor HaMo

Ce projet consiste en une application C++ qui va récupérer sur le site de réservation de Citelib by HaMo des informations telles que les disponibilités des véhicules aux différentes stations. Cela peut permettre:

  • d éviter a l utilisateur de surveiller le site et lui générer des alertes
  • calculer des statistiques : occupation des stations, disponibilité des véhicules etc

Infos diverses

Commande

Ligne de commande pour lancer l application

Usage is :
        monitor_HaMo.exe [OPTIONS] <login>
OPTIONS : --<parameter_name>=<parameter_value>
        --proxy-host=...
        --proxy-password=...
        --proxy-port=...
        --proxy-user=...
        --verbose-content=...
        --verbose-curl=...

Si les passwords proxy et HaMo ne sont pas renseignes alors l utilisateur devra les entrer en ligne de commande (l application desactive l echo du terminal)

Status

Le code actuel se connecte au site en utilisant les identifiants fournit en ligne de commande, récupère le JSON indiquant les disponibilites des vehicules sur les differentes stations, le parse et le stocke dans une structure de donnee.
Si des changements ont eu lieu l application affiche un diff puis le statut complet

...
Achard                           : 2 places, 1 vehicules dont 0 Coms et 1 Iroads
Balzac                           : 3 places, 2 vehicules dont 2 Coms et 0 Iroads
Bonne                            : 1 places, 2 vehicules dont 2 Coms et 0 Iroads
CEA Cambridge                    : 3 places, 0 vehicules dont 0 Coms et 0 Iroads
CEA Ha:mo Test                   : 1 places, 2 vehicules dont 1 Coms et 1 Iroads
Chambre des Métiers              : 0 places, 2 vehicules dont 2 Coms et 0 Iroads
Cité Internationale              : 3 places, 0 vehicules dont 0 Coms et 0 Iroads
Dumont                           : 1 places, 3 vehicules dont 3 Coms et 0 Iroads
Fontaine                         : 2 places, 1 vehicules dont 1 Coms et 0 Iroads
Gares - Schuman                  : 2 places, 1 vehicules dont 0 Coms et 1 Iroads
Gières Gare                      : 2 places, 2 vehicules dont 1 Coms et 1 Iroads
Grand Sablon                     : 4 places, 0 vehicules dont 0 Coms et 0 Iroads
Horowitz                         : 4 places, 2 vehicules dont 2 Coms et 0 Iroads
Jean Pain -  Stade des Alpes     : 3 places, 1 vehicules dont 0 Coms et 1 Iroads
Jouhaux                          : 1 places, 2 vehicules dont 1 Coms et 1 Iroads
Les Taillées Universités         : 0 places, 3 vehicules dont 0 Coms et 3 Iroads
Louise Michel                    : 2 places, 2 vehicules dont 2 Coms et 0 Iroads
Malraux CCI                      : 2 places, 2 vehicules dont 2 Coms et 0 Iroads
Notre Dame Musée                 : 1 places, 2 vehicules dont 2 Coms et 0 Iroads
Saint Bruno                      : 3 places, 0 vehicules dont 0 Coms et 0 Iroads
Seyssinet Pariset Hôtel de ville : 4 places, 1 vehicules dont 0 Coms et 1 Iroads
Stéphane Jay                     : 4 places, 0 vehicules dont 0 Coms et 0 Iroads
Thiers                           : 1 places, 2 vehicules dont 1 Coms et 1 Iroads
Vaucanson                        : 3 places, 2 vehicules dont 2 Coms et 0 Iroads
Victor Hugo                      : 0 places, 3 vehicules dont 2 Coms et 1 Iroads
Soit 52 places, 38 vehicules dont 26 Coms et 12 Iroads repartis sur 25 stations

Check at Thu Oct  1 13:20:05 2015                 
Changements observes :
Chambre des Métiers              : 2 -> 1 vehicules, 2 -> 1 Coms
Horowitz                         : 4 -> 3 places
Soit 52 -> 51 places, 38 -> 37 vehicules, 26 -> 25 Coms
Nouveau status : 
Achard                           : 2 places, 1 vehicules dont 0 Coms et 1 Iroads
Balzac                           : 3 places, 2 vehicules dont 2 Coms et 0 Iroads
Bonne                            : 1 places, 2 vehicules dont 2 Coms et 0 Iroads
CEA Cambridge                    : 3 places, 0 vehicules dont 0 Coms et 0 Iroads
CEA Ha:mo Test                   : 1 places, 2 vehicules dont 1 Coms et 1 Iroads
Chambre des Métiers              : 0 places, 1 vehicules dont 1 Coms et 0 Iroads
Cité Internationale              : 3 places, 0 vehicules dont 0 Coms et 0 Iroads
Dumont                           : 1 places, 3 vehicules dont 3 Coms et 0 Iroads
Fontaine                         : 2 places, 1 vehicules dont 1 Coms et 0 Iroads
Gares - Schuman                  : 2 places, 1 vehicules dont 0 Coms et 1 Iroads
Gières Gare                      : 2 places, 2 vehicules dont 1 Coms et 1 Iroads
Grand Sablon                     : 4 places, 0 vehicules dont 0 Coms et 0 Iroads
Horowitz                         : 3 places, 2 vehicules dont 2 Coms et 0 Iroads
Jean Pain -  Stade des Alpes     : 3 places, 1 vehicules dont 0 Coms et 1 Iroads
Jouhaux                          : 1 places, 2 vehicules dont 1 Coms et 1 Iroads
Les Taillées Universités         : 0 places, 3 vehicules dont 0 Coms et 3 Iroads
Louise Michel                    : 2 places, 2 vehicules dont 2 Coms et 0 Iroads
Malraux CCI                      : 2 places, 2 vehicules dont 2 Coms et 0 Iroads
Notre Dame Musée                 : 1 places, 2 vehicules dont 2 Coms et 0 Iroads
Saint Bruno                      : 3 places, 0 vehicules dont 0 Coms et 0 Iroads
Seyssinet Pariset Hôtel de ville : 4 places, 1 vehicules dont 0 Coms et 1 Iroads
Stéphane Jay                     : 4 places, 0 vehicules dont 0 Coms et 0 Iroads
Thiers                           : 1 places, 2 vehicules dont 1 Coms et 1 Iroads
Vaucanson                        : 3 places, 2 vehicules dont 2 Coms et 0 Iroads
Victor Hugo                      : 0 places, 3 vehicules dont 2 Coms et 1 Iroads
Soit 51 places, 37 vehicules dont 25 Coms et 12 Iroads repartis sur 25 stations
...

L application peut fonctionner a travers un proxy si l utilisateur fournit les informations necessaires ( proxy host, proxy port, login, password)

Reverse engineering du site web


Analyse du code de la page de connection


Page de connection



  • Le passage des infos de connection se fait via un formulaire dont le code se situe entre les balises <form> et </form>
  • Les attributs method="POST" et action="/login/auth" indiquent que les donnees sont envoyes en HTTP par la methode POST a l URL https://gride.gr-tsc.com/login/auth
  • Les champs du formulaires sont declares dans les balises <input> et sont au nombre de 3 obligatoires: login[userId] , login[password] , login[_csrf_token]


Page de connection


Analyse de le requete de connection


Lorsque l utilisateur clique sur le bouton Connection les donnees du formulaires sont envoyees au site.
Il est possible de visualiser cela grace aux extensions de debug du navigateur ( par exemple Firebug pour Firefox )
Dans l exemple suivant nous envoyons comme login toto et comme mot de passe tata, Firebug permet d observer le formatage des parametres de la requete POST et de voir l URL a laquelle les informations sont envoyees.
On observe notamment que les noms de champs du formulaire sont echappes pour encoder les '[' et ']'

La requete POST vue dans Firebug


Analyse de la home page


Une fois connecte sur le site la page d accueil affiche une carte sur laquelle apparaissent des marqueurs representant chaque station
En cliquant sur les marqueurs un popup affiche le nombre de vehicules disponibles et le nombre de places disponibles
Il est possible de les filtrer par type de vehicule
Se sont ses informations que nous souhaitons recuperer
Une fois de plus Firebug permet de comprendre comment sont recuperees les informations

Requetes effectuees par le navigateur pour afficher la home page


En triant les requetes par domaine on voit clairement:

  • les requetes effectuees pour recuperer les tuiles de la carte
  • les requetes sur le site [gride.gr-tsc.com gride.gr-tsc.com] pour recuperer les elements graphique du site ainsi que les informations recherchees


Le contenu JSON des sites de citelib


On voit pour chaque station

  • Ses coordonnees
  • Son nom
  • Son Id
  • Le nombre de vehicules disponibles ( champ ev )
  • Le nombre de vehicules disponibles par type ( champ evByType : 1 pour les COMS, 2 pour les Iroads )))
  • Le nombre de places de parking ( champ garage )


Code de l application


Recuperation de la page de login


On a vu dans la partie analyse du code du site web que la page de login contient un token de connection.
La premiere etape est donc de recuperer le code de la page de login.
Au passage on active:

  • la gestion des cookies afin de conserver la connection une fois celle ci effectuee
  • la gestion des redirections
std::string l_login_url = "https://gride.gr-tsc.com/login";
curl_easy_setopt(l_curl_handler, CURLOPT_COOKIESESSION,true); 
curl_easy_setopt(l_curl_handler, CURLOPT_COOKIEFILE,"toto.txt"); 
curl_easy_setopt(l_curl_handler,CURLOPT_FOLLOWLOCATION,true);
download_buffer l_buffer;
curl_easy_setopt(l_curl_handler, CURLOPT_WRITEFUNCTION,receive_data); 
curl_easy_setopt(l_curl_handler, CURLOPT_WRITEDATA, (void *)&l_buffer);
curl_easy_setopt(l_curl_handler, CURLOPT_URL,l_login_url.c_str());
if(l_verbose_curl_parameter.value_set())
  {
    curl_easy_setopt(l_curl_handler, CURLOPT_VERBOSE,1);
  }
 
CURLcode l_curl_status = curl_easy_perform(l_curl_handler);
if(l_curl_status)
  {
    std::stringstream l_stream;
    l_stream << "Error when downloading \"" << l_login_url << "\" : " << curl_easy_strerror(l_curl_status);
    throw quicky_exception::quicky_runtime_exception(l_stream.str(),__LINE__,__FILE__);
  }


Dans le code HTML de la page on recupere le token de login

// Extract login token
std::string l_login_token_id = "login[_csrf_token]";
std::string l_content(l_buffer.get_data(),l_buffer.get_size());
size_t l_pos = l_content.find(l_login_token_id);
assert(std::string::npos != l_pos);
l_pos = l_content.find("value",l_pos);
assert(std::string::npos != l_pos);
l_pos += std::string("value").size();
l_pos = l_content.find('"',l_pos);
assert(std::string::npos != l_pos);
++l_pos;
size_t l_pos_end = l_content.find('"',l_pos);
std::string login_token = l_content.substr(l_pos,l_pos_end - l_pos);


Envoi des informations de connection


Les informations de connections doivent etre envoyees par une methode post, on prepare les parametres a envoyer

std::string l_post_logging_url  = "https://gride.gr-tsc.com/login/auth";
std::string l_post_fields_begin = "login%5BuserId%5D="+l_user_name+"&login%5Bpassword%5D="+l_user_password+"&login%5B_csrf_token%5D=";
std::string l_post_fields_end = "";
std::string l_post_fields = l_post_fields_begin + login_token + l_post_fields_end;
 
curl_easy_setopt(l_curl_handler, CURLOPT_POST, true);
curl_easy_setopt(l_curl_handler, CURLOPT_POSTFIELDS,l_post_fields.c_str());
curl_easy_setopt(l_curl_handler, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
curl_easy_setopt(l_curl_handler, CURLOPT_URL,l_post_logging_url.c_str());
 
l_buffer.clear();
l_curl_status = curl_easy_perform(l_curl_handler);
if(l_curl_status)
  {
    std::stringstream l_stream;
    l_stream << "Error when downloading \"" << l_post_logging_url << "\" : " << curl_easy_strerror(l_curl_status);
    throw quicky_exception::quicky_runtime_exception(l_stream.str(),__LINE__,__FILE__);
  }
 
l_content = std::string(l_buffer.get_data(),l_buffer.get_size());
if(std::string::npos != l_content.find("Incorrect ID or password"))
  {
    throw quicky_exception::quicky_logic_exception("Connection failed !!! Please check your credentials",__LINE__,__FILE__);
  }