Alcatel MW40 – API access

Jakiś czas temu zmuszony byłem do używania urządzenia, które jest widoczne na obrazku powyżej. Już tak mam, że jak jakieś urządzenie ma własną baterię to staram się odpinać ładowarkę, tak aby bateria miała szansę odpocząć od ładowarki.

Niestety często umykała mi mrugająca czerwona dioda informująca o niskim poziomie naładowania i urządzenie po prostu się wyłączało zanim zdążyłem ponownie podłączyć kabel ładowarki.

Postanowiłem więc przyjrzeć się softowi, który chodzi na urządzeniu.

Po wejściu do panelu admina widać taki widok

Na stronie widać procent naładowania baterii. W zakładce Network w Chromie były widoczne wysyłane żądania do API a w jednym z nich znajdowało się pole bat_cap, które zapewne pokazuje wartość naładowania baterii. Przydatne wydają się też takie pola jak bat_level i chg_status

Postanowiłem spróbować wysłać takie samo żądanie przez klienta REST. Niestety w odpowiedzi dostałem

{
	"jsonrpc": "2.0",
	"error": {
		"code": "-32697",
		"message": "Authentication Failure"
	},
	"id": "1.1"
}

Wracając do zakładki Network zobaczyłem, że podczas wysyłania tego żądania dodawane są nagłówki _TclRequestVerificationKey, _TclRequestVerificationToken oraz Cookie.

Zacząłem przeglądać pliki .js, które używane są na stronie i trafiłem na plik sdk.js, w którym namierzyłem taką funkcję

function getHeaders(apiName) {
   var headers = {};    

   (...)

    try {
        headers['_TclRequestVerificationKey'] = "KSDHSDFOGQ5WERYTUIQWERTYUISDFG1HJZXCVCXBN2GDSMNDHKVKFsVBNf";
        headers['_TclRequestVerificationToken'] = getCookie("loginToken") || "null";
    } catch (err) {

    }

    return headers;
}

Okej, w takim razie mam wartość pierwszego nagłówka. To po prostu stała. Jedną linię niżej jest wartość drugiego nagłówka – to wartość ciasteczka o nazwie loginToken. Szukam więc gdzie to ciasteczko jest ustawiane.

W tym samym pliku znajduje funkcję Login, która zawiera takie linie kodu jak:

var params = {
   "UserName": newEncrypt(Username),
   "Password": newEncrypt(Password)
}

var result = requestJsonRpcSync("Login", params, "1.1");
setCookie("loginToken", newEncrypt(result.result.token))

Nie znam wartości pola Username bo przy logowaniu się do panelu podaje się tylko hasło, jednak w innym pliku szybko namierzyłem var usernameVal = "admin". Stary dobry admin – można było obstawić w ciemno.

Hasło znam, więc mogę przejść do zbudowania wartości dla tego nagłówka.

W metodzie requestJsonRpcSync sprawdzam jak budowane jest ciało requesta używane przy logowaniu do aplikacji.

var postData = {
    "jsonrpc": "2.0",
    "method": method,
    "params": params,
    "id": id
};

Muszę podać jedynie params – pole przekazane jest z metody wyżej, które to składa się tylko z UserName i Password, a wartości tych pól są zakodowane za pomocą metody newEncrypt.

Kopiuję ciało metody do konsoli js w Chrome, podaje login, potem hasło, otrzymany output podstawiam do zmiennych. Teraz mogę wykonać requesta Login, aby dostać token.

Niestety – żądanie zablokowane. Ale na szczęście po dodaniu nagłówka Referer wszystko przechodzi.

Po otrzymaniu tokena możemy przejść dalej do uzupełnienia wartości nagłówka _TclRequestVerificationToken. Bierzemy wartość odczytaną z requesta – w naszym wypadku 14986374.

Sklejamy wszystko w jedną całość

Request pięknie zwraca dane.

Mając już wiedzę, jak to jest zbudowane, mogłem napisać sobie prostą aplikację w Swift aby monitorować status naładowania baterii 🙂 Aplikacja pokazuje ikonę ładowania, procent baterii, a nawet wysyła SMSa do mnie, kiedy procent spada poniżej 10. Swoją drogą jest to pierwsza aplikacja w Swift jaką miałem okazję napisać.

Aplikacja jest dostępna tutaj: https://github.com/szyn33k/AlcatelStatusApp

W plikach .js można znaleźć wiele innych requestów, które brzmią ciekawie np: setFtpStatus. Co prawda skusiłem się o sprawdzenia czy uda mi się uzyskać roota na urządzeniu, jednak nie udało mi się tego dokonać. Może któregoś dnia do tego wrócę i spróbuję jeszcze raz 🙂

A tymczasem do następnego!