Hello à tous,
j'ai tenté de mon côté de réaliser un plugin pour restituer les données de l'appli WeConnect de Volskwagen, mais mes limites de bidouilleurs ont vite été atteintes, et c'est pourquoi je sollicite une âme charitable de vrai développeur pour tenter de poursuivre mes travaux....
Je ne suis pas allé très loin, je suis déjà bloqué à la recherche désespérée du token de connexion perdu...
Ci-après les infos que j'ai pu glaner :
- il n'y a pas d'API officielle bien entendu, il s'agit de simuler une connexion classique, soit à l'appli smartphone, soit au site web, puis, une fois le token de session obtenu, on peut charger les pages d'informations d'une ou plusieurs voitures ("fetcher" les data des véhicules), voire lancer des actions à distance (clim, etc.).
- il existe une bibliothèque de composants non officielle réalisée en python ici :
https://pypi.org/project/weconnect/, qui mène notamment à la page github suivante à partir de laquelle je me suis inspiré pour le code de connexion :
https://github.com/tillsteinbach/WeConnect-python/blob/main/weconnect/auth/we_connect_session.py- même genre de travaux ici :
https://github.com/trocotronic/weconnect/blob/master/WebAPI.py- notez qu'il y avait un autre mode de connexion au système volkswagen il y a quelques années, et donc on peut trouver des travaux devenus obsolètes depuis
- évidemment, la page initiale de connexion n'est pas la même en fonction du pays. Les travaux réalisés par des allemands n'aident pas au début...
Le principe de connexion est le suivant :
- on charge une première page web avec des paramètres, qui redirige vers la véritable page de connexion qui contient des premiers paramètres de sessions visibles dans l'url (on récupère cette redirection en lisant le header "location" récupéré au lancement de la première page).
- cette location ressemble à
https://identity.vwgroup.io/signin-service/v1/signin/0de3e2e5-9309-4d32-b828-8ff3ef16f0b9@apps_vw-dilab_com?relayState=00323b4403e9686163c737d44c924bd9d15d48cc, et ça c'est la page de connexion initiale à MyVolkswagen, ça demande l'email du compte.
- on simule donc la validation du formulaire de saisie avec l'email en ayant récupéré au préalable dans la page quelques paramètres.
- on arrive alors sur la page de saisie du mot de passe.
- même principe, on lance le formulaire avec des paramètres et le mot de passe et la nouvelle page de destination prévue, et on est censé arriver sur la bonne page de consultation avec toutes les données de token de session à conserver pour les appels suivants... Mais, l'exécution de ce formulaire ne fonctionne pas pour moi....et je bloque...je tourne en rond, j'abandonne...
Voici le code du plugin à ce stade :
- Code : Tout sélectionner
<?php
$xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>";
//***********************************************************************************************************************
// V0.1 : Volskwagen We Connect / copyright Influman 2022
/*
*/
$action = getArg("action", true);
$login = getArg("login", true); // VAR1
$password = getArg("pass", true); // VAR2
$car = getArg("car", false,1); // VAR3
$value = getArg("value", false);
$periph_id = getArg('eedomus_controller_module_id');
if ($action == '' ) {
die();
}
$xml .= "<WECONNECT>";
// SESSIONS // Ouverture de sessions
//if ($action != "polling") {
// recherche authorisation url
$scope = "profession cars address phone openid profile dealers vin carConfigurations";
$state= "ZKhFLavOMAyJ-967SOnF6DX2NRELd0RYzWrIwtbUvO8=";
$redirect_uri = "https://www.volkswagen.fr/app/authproxy/login/oauth2/code/vw-fr";
$nonce = sdk_get_random_string(43);
$client_id = "0de3e2e5-9309-4d32-b828-8ff3ef16f0b9@apps_vw-dilab_com";
$url = "https://identity.vwgroup.io/oidc/v1/authorize?response_type=code&client_id=".$client_id."&scope=".$scope."&redirect_uri=".$redirect_uri."&nonce=".$nonce;
//$url = "https://login.apps.emea.vwapps.io/authorize?response_type=code&client_id=".$client_id."&scope=".$scope."&redirect_uri=".$redirect_uri."&nonce=".$nonce;
$response = httpQuery($url, 'GET', NULL, NULL, NULL, false, false, &$info_init, NULL);
$xml.= "<HTTP_CODE1>".$info_init['http_code']."</HTTP_CODE1>";
$header_response = preg_replace("# {2,}#"," ",preg_replace("#(\r\n|\n\r|\n|\r)#"," ",$info_init['header']));
//$xml.= "<HTTP_HEADER1>".$header_response."</HTTP_HEADER1>";
$input_Location = '/location: (?P<url>[^\s]*) apigw-requestid/';
preg_match_all($input_Location, $header_response, $matches);
$location = $matches['url'][0];
$xml.= "<LOCATION>".$location."</LOCATION>";
// 1er appel avec url login
// ******************************************************************************************************
$response = httpQuery($location, 'GET', NULL, NULL, NULL, true, false, &$info2,'', false);
$xml.= "<AUTH_CODE2>".$info2['http_code']."</AUTH_CODE2>";
//$xml .= $response;
$response = preg_replace("# {2,}#"," ",preg_replace("#(\r\n|\n\r|\n|\r)#"," ",$response));
$emailFormRegex = '/<form.+id=\"emailPasswordForm\".*action=\"(?P<formAction>[^\"]+)\"[^>]*>(?P<formContent>.+?(?=<\/form>))<\/form>/';
if (preg_match($emailFormRegex, $response, $matches) == 1) {
$target = $matches['formAction'];
$formcontent = $matches['formContent'];
$xml.= "<TARGET>".$target."</TARGET>";
}
else {
$xml.= "<ERROR_EMAILFORM>Error - No login email form found</ERROR_EMAILFORM>";
}
$fields = array();
$_csrf = "";
$input_csrf = '/<input[\\n\\r\s][^\/]*name=\"_csrf\"([\\n\\r\s]value=\"(?P<value>[^\"]+)\")?[^\/]*\/>/';
if (preg_match($input_csrf, $formcontent, $matches) == 1) {
$_csrf = $matches['value'];
$fields["_csrf"] = $_csrf;
$xml.= "<_CSRF>".$_csrf."</_CSRF>";
} else {
$xml.= "<ERROR_CSRFFORM>Could not find _csrf input field in login page</ERROR_CSRFFORM>";
}
$relayState = "";
$input_relaystate = '/<input[\\n\\r\s][^\/]*name=\"relayState\"([\\n\\r\s]value=\"(?P<value>[^\"]+)\")?[^\/]*\/>/';
if (preg_match($input_relaystate, $formcontent, $matches) == 1) {
$relayState = $matches['value'];
$fields["relayState"] = $relayState;
$xml.= "<relayState>".$relayState."</relayState>";
} else {
$xml.= "<ERROR_RELAYFFORM>Could not find relayState input field in login page</ERROR_RELAYFFORM>";
}
$hmac = "";
$input_hmac = '/<input[\\n\\r\s][^\/]*name=\"hmac\"([\\n\\r\s]value=\"(?P<value>[^\"]+)\")?[^\/]*\/>/';
if (preg_match($input_hmac, $formcontent, $matches) == 1) {
$hmac = $matches['value'];
$fields["hmac"] = $hmac;
$xml.= "<hmac>".$fields["hmac"]."</hmac>";
} else {
$xml.= "<ERROR_HMACFFORM>Could not find hmac input field in login page</ERROR_HMACFFORM>";
}
$fields["email"] = $login;
$xml.= "<email>".$fields["email"]."</email>";
//
$headers = array(
'user-agent: Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.185 Mobile Safari/537.36',
'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
'accept-language: en-US,en;q=0.9',
'accept-encoding: gzip, deflate',
'upgrade-insecure-requests: 1',
'Content-Type: application/x-www-form-urlencoded'
);
// Second appel avec l'email saisi
// ******************************************************************************************************
$fields2 = array();
$url='https://identity.vwgroup.io'.$target;
$xml.= "<URL2>".$url."</URL2>";
$fields_url = "hmac=".$fields["hmac"]."&relayState=".$fields["relayState"]."&email=".$fields["email"]."&_csrf=".$fields["_csrf"];
$response2 = httpQuery($url, "POST", $fields_url, NULL, $headers, true, false, &$info, NULL, true);
$xml.= "<HTTP_CODE2>".$info['http_code']."</HTTP_CODE2>";
$response2 = preg_replace("# {2,}#"," ",preg_replace("#(\r\n|\n\r|\n|\r)#"," ",$response2));
$hmac2 = "";
$input_hmac2 = '/\"hmac\":\"([^\"]*)\"/';
if (preg_match($input_hmac2, $response2, $matches) == 1) {
$hmac2 = $matches[1];
$fields2["hmac"] = $hmac2;
$xml.= "<hmac2>".$hmac2."</hmac2>";
} else {
$xml.= "<ERROR>Could not find hmac input field in password page</ERROR>";
}
$relayState2 = "";
$input_relayState2 = '/\"relayState\":\"([^\"]*)\"/';
if (preg_match($input_relayState2, $response2, $matches) == 1) {
$relayState2 = $matches[1];
$fields2["relayState"] = $relayState2;
$xml.= "<relayState2>".$relayState2."</relayState2>";
} else {
$xml.= "<ERROR>Could not find relayState input field in password page</ERROR>";
}
$email2 = "";
$input_email2 = '/\"email\":\"([^\"]*)\"/';
if (preg_match($input_email2, $response2, $matches) == 1) {
$email2 = $matches[1];
$fields2["email"] = $email2;
$xml.= "<email2>".$email2."</email2>";
} else {
$xml.= "<ERROR>Could not find email input field in password page</ERROR>";
}
$input_postAction = '/\"postAction\":\"([^\"]*)\"/';
if (preg_match($input_postAction, $response2, $matches) == 1) {
$target2 = $matches[1];
$xml.= "<TARGET2>".$target2."</TARGET2>";
} else {
$xml.= "<ERROR>Could not find postAction input field in password page</ERROR>";
}
$input_csrf_token = '/csrf_token: \'([^\"]*)\', userSession/';
if (preg_match($input_csrf_token, $response2, $matches) == 1) {
$csrf2 = $matches[1];
$fields2["_csrf"] = $csrf2;
$xml.= "<CSRF2>".$csrf2."</CSRF2>";
} else {
$xml.= "<ERROR>Could not find csrf_token input field in password page</ERROR>";
}
$fields2["password"] = $password;
$xml.= "<password>".$password."</password>";
// Troisieme appel avec le mot de passe
// ******************************************************************************************************
$url='https://identity.vwgroup.io/signin-service/v1/'.$client_id.'/'.$target2;
$xml.= "<URL3>".$url."</URL3>";
$fields_url = "hmac=".$fields2["hmac"]."&relayState=".$fields2["relayState"]."&email=".$fields2["email"]."&_csrf=".$fields2["_csrf"]."&password=".$fields2["password"];
$xml.= "<FIELDS2>".$fields_url."</FIELDS2>";
// httpQuery($url, $action = 'GET'/*GET,POST,PUT,DELETE*/, $post = NULL, $oauth_token = NULL, $headers = NULL, $use_cookies = false, $ignore_errors = false, &$info = null, $user_pwd = NULL)
$response3 = httpQuery($url, "POST", $fields_url, NULL, $headers, true, false, &$info3, NULL, false);
$header_response = preg_replace("# {2,}#"," ",preg_replace("#(\r\n|\n\r|\n|\r)#"," ",$info3['header']));
$xml.= "<HTTP_HEADER3>".$header_response."</HTTP_HEADER3>";
$xml.= "<HTTP_CODE3>".$info3['http_code']."</HTTP_CODE3>";
$response3 = preg_replace("# {2,}#"," ",preg_replace("#(\r\n|\n\r|\n|\r)#"," ",$response3));
$xml.= $response3;
$xml .= "</WECONNECT>";
sdk_header('text/xml');
echo $xml;
die();
function sdk_get_random_string($length) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
?>
J'ai juste créé un périphérique lecteur http, avec l'adresse :
http://localhost/script/?exec=weconnect ... tus&login=[VAR1]&pass=[VAR2]&car=[VAR3]
et /WECONNECT/STATUS en chemin XPATH
et je teste l'appel manuellement...
voilà.
Le login/mdp du compte ne sont pas les miens. Si possible, si qqun a une première piste sérieuse rien qu'en étudiant le code, ce serait bien avant d'aller plus loin.
Merci d'avance pour toute aide