Open milankolecek opened 3 years ago
Podíval jsem se na to, konkrétně na funkci cz.dpp.praguepublictransport.utils.b0.k(String, long, String)
, která je asi předmětem zájmu. Zdrojový kód z cfr
nebyl nic moc, ale i stará verze Procyonu to dekompilovala moc hezky (čím víc dekompilátorů tím štastnější reverser?). S trochou inlinování vypadá podstatná část kódu takto (v skoro-Javě):
public static String k(final String str, final long l, String f) {
if (TextUtils.isEmpty(str)) {
return null;
}
String obj = "";
if (!TextUtils.isEmpty(f)) {
final byte[] e = SHA256(String.format("MOS%dMOS", l / 30L));
final byte[] c = BaseEncoding.hex().decode(f.toUpperCase());
h.a.a.a("Unix time stamp: %d", l);
f = BaseEncoding.base32hex().encode(r0(c, e));
if (f != null && f.length() >= 4) {
str = "X-PTS:" + f.substring(0, 4) + "*";
}
}
if (str.contains("X-PTS:")) {
return str.replaceAll("X-PTS.*", obj);
}
return str + obj;
}
private static byte[] r0(final byte[] array, final byte[] array2) {
final byte[] out = new byte[16];
int outLen = Math.min(16, Math.min(array.length, array2.length));
for (int j = 0; j < outLen; ++j) {
out[j] = (byte)(array[j] ^ array2[j]);
}
if (outLen < 16) {
if (array.length > outLen) {
int length;
if (array.length >= 16) {
length = 16;
}
else {
length = array.length;
}
for (int k = outLen; k < length; ++k) {
out[k] = array[k];
}
}
if (array2.length > outLen) {
int length2;
if (array2.length >= 16) {
length2 = 16;
}
else {
length2 = array2.length;
}
while (outLen < length2) {
out[outLen] = array2[i];
++outLen;
}
}
}
return out;
}
r0()
vezme dvě pole bytů, vyXORuje je mezi sebou dokud to jde a pokud není výsledek dostatečně dlouhý (16 bytů), snaží se to dopadovat nejdřív prvky z prvního, pak druhého, pole.
k()
má dva call sity, vybral jsem z nich ten asi víc relevantní. Tam je l
opravdu generován jako UNIX time a f
je generován jako j(f(unixTime))
. f
zaokrouhlí timestamp na 300s (f(n) = n / 300 * 300
). j()
kupodivu provádí databázový dotaz: SELECT key FROM timeKey WHERE timestamp == ?
. Tyto klíče stahuje třída TimeKeysWorker
. Odkud přesně je bere už jsem nezjistil, ale kód vypadá hezky dekompilovaný, s logováním a někdy i názvy metod.
Na zbytek kódu jsem se nedíval, tak snad tyto postřehy půjdou zasadit do většího celku. Až bude vaše aplikace v použitelném stavu, tak rozhodně bych se rád podíval na její kód a případně si přečetl nějaké postřehy k fungování API PID Lítačky :)
p.s. Byl bych pro založení nějakého fóra/jiného místa, kde bychom mohli tyto věci (jak získat data/API a co s nimi) diskutovat, pokud se k tomu přidá alespoň pár lidí.
Moc díky, tohle mi strašně pomohlo.
Teď už mi dělá starosti jen
String.format("MOS%dMOS", l / 30L)
protože to vrací to samé, ať dám do l
cokoliv. Nejsem Javista, takže předpokládám, že to bude něco úplně zřejmého.
Co se týče toho selektu z databáze, to bude nejspíše ten API endpoint, co jsem zmiňoval. Aplikace si zřejmě timeKeys ukládá do interní DB, aby fungovala i offline. Zkusím ji nechat dlouho offline, zajímá mě, co začne dělat, když jí dojdou načtené klíče.
Zdrojové kódy určitě dám na GitHub hned, jak nějaké budou.
Fórum mi přijde jako úplně skvělý nápad. Jsem si docela jistý, že by se tu ještě pár zájemců našlo (můžete dávat na tenhle příspěvek thumbs up). Já mám taky v zásobě ještě pár zajímavých APIček, o která se můžu podělit. Můžeme použít Reddit, vyrobit něco tady na GitHubu, nebo bych třeba mohl něco nasadit k sobě na server.
Co konkrétně nefunguje? Něco jiného než to začne házet až na větších číslech (je tam celočíselné dělení 30). Třeba
class Main {
public static void main(String[] args) {
final long l = 100;
System.out.println(String.format("MOS%dMOS", l / 30L));
}
}
Vypíše MOS5MOS
Ohledně fóra: Už provozuji fórum pro své dopravní projekty na adrese dadof.konarici.cz, které je aktuálně dost mrtvé. Na stejném serveru a asi na doméně .konarici.cz (možná bych si mohl půjčit .ggu.cz) bych mohl hostovat i další forum, asi zas na stejném softwaru. Pokud se na tom shodneme a vymyslíme jméno, můžu to zařídit.
@mvolfik Jo, moje chyba, zřejmě kvůli tomuhle se kód změní každých 30 sekund (to l
je timestamp).
@dvdkon Když se někdo z nás zaregistruje do https://education.github.com/, je tam jedna .me doména zadarmo a můžeme zaregistrovat něco jako dekompiluje.me. To Flarum jinak vypadá skvěle.
Jinak jsem ale teď bohužel trochu narazil, protože: hodnota QR kódu vypadá asi takhle:
ETD*1*IN:DPP*TT:PASS*X-DEV:<device indentifier - statický>*X-ACC:<nevím, co to je, ale taky je to statický>*SG:<hrozně dlouhý string, jeho část je statická, ale pár znaků uprostřed se mění>*X-PTS
:<náš slavný timestamp>*
Dřív jsem si nevšiml, že se mění i hodnota SG
, protože je to zčásti statické. A když se to teď snažím najít v kódu, nic nenalézám. Je tam jen jeden řádek, který to matchuje, ale jak se to generuje netuším. Dekompiluju teďka Jadxem, zkusím ještě Procyon, třeba to bude lepší.
Ahoj, tohle se úplně netýká Baka API, ale protože neznám skupinu lidí, co by se lépe vyznala v revezním engineeringu, tak se zkusím zeptat. Už delší dobu plánuju napsat si PID Lítačka appku pro Wear OS, tj. do Androidích hodinek - abych při kontrole v autobusech nemusel vytahovat telefon a mohl prostě ukázat hodinky. Mám už docela přehled o fungování API z aplikace PID Lítačka pro Android a taky zhruba vím, podle čeho se generuje QR kód pro inspekci. Jediné, na co pořád nemůžu přijít, je parametr X-PTS. Tenhle parametr se jako jediný v QR kódu periodicky mění (každých 30 sekund - v xx:xx:00 a xx:xx:30). Je to alfanumerický čtyřznakový string, tady jsou nějaké příklady: L3HR 5K4H Netuší někdo, jak by tahle věc mohla vznikat? Je to jakási forma timestampu, stejnou zkratku má Presentation timestamp (https://en.wikipedia.org/wiki/Presentation_timestamp), ale to asi bude něco jiného. V aplikaci je také nějaké volání na endpoint /api/v3/time-keys, které vrací něco takovéhohle: [ "e654cb6d", "16d589f2" ] Ale dekompilace nebyla tak dokonalá, abych si byl jistý, že se tyhle stringy reálně využívají k tvorbě X-PTS. Budu moc rád za jakékoliv nápady a kdyby se někdo chtěl připojit k tvorbě aplikace pro hodinky, budu moc rád. Kdyby měl někdo čas kouknout se i dovnitř oficiální aplikace, přikládám odkaz na APK: https://apkpure.com/pid-litacka/cz.dpp.praguepublictransport/download?from=details Milan