- Add Proof of Concept (PoC) for executing JavaScript scripts fetched remotely. - Integrate `Black::GetProfileInfoScript` logic into a JS version with fallback to C++ on errors. - Extend `ScreenXmlParser` with additional JS-to-C++ bridge methods. - Update `config.ini` for scripting configuration. - Ensure scripts are securely fetched with SHA-256 validation and use an atomic caching mechanism. - Add developer tools for debugging JS scripts and enable easier script updates without app re-deployment.
174 lines
6.9 KiB
JavaScript
174 lines
6.9 KiB
JavaScript
// black/get_profile_info.js
|
||
//
|
||
// JS-порт Black::GetProfileInfoScript. Логика 1:1 с C++ (см.
|
||
// android/black/GetProfileInfoScript.cpp), обращения к ADB/DAO/парсеру
|
||
// идут через host.*-мост.
|
||
//
|
||
// Контракт:
|
||
// params.deviceId — серийный или android_id
|
||
// params.appCode — "black"
|
||
// Возвращает:
|
||
// "" / null / undefined → success
|
||
// строку → бизнес-ошибка (попадёт в EventInfo.error)
|
||
// При выбросе исключения runtime сделает fallback на C++.
|
||
|
||
function run(host) {
|
||
var deviceId = host.params.deviceId;
|
||
var appCode = host.params.appCode;
|
||
var counter = 0;
|
||
|
||
// 1. Резолвим device (id может быть как android_id, так и adb serial).
|
||
var device = host.dao.deviceGetById(deviceId);
|
||
if (!device || !device.id) {
|
||
device = host.dao.deviceFindByAdbSerial(deviceId);
|
||
}
|
||
if (device && device.adbSerial) {
|
||
deviceId = device.adbSerial;
|
||
}
|
||
var app = host.dao.bankProfileGet(device.id, appCode);
|
||
if (!device || !device.id || !app || app.id < 0) {
|
||
var msg = "Device or app not found: " + deviceId + " " + appCode;
|
||
host.log.error(msg);
|
||
return msg;
|
||
}
|
||
|
||
host.dump.beginScope("black", "FETCH_PROFILE_INFO", deviceId, {});
|
||
|
||
try {
|
||
// 2. Читаем текущий экран
|
||
host.parser.parseAndSaveXml(host.adb.getScreenDumpAsXml(deviceId, ++counter));
|
||
|
||
// 3. Если не на домашнем экране — перезапускаем приложение
|
||
if (!host.parser.isHomeScreen()) {
|
||
host.log.debug("Not on home screen, restarting app...");
|
||
if (!host.helpers.runAppAndGoToHomeScreen(deviceId, app.package, app.pinCode,
|
||
device.screenWidth, device.screenHeight)) {
|
||
var err = "Cannot reach home screen: " + device.name + " (" + deviceId + ") " + appCode;
|
||
host.log.warn(err);
|
||
host.adb.tryToKillApplication(deviceId, app.package);
|
||
return err;
|
||
}
|
||
host.parser.parseAndSaveXml(host.adb.getScreenDumpAsXml(deviceId, ++counter));
|
||
}
|
||
|
||
// 4. Тапаем "¡Hola!"
|
||
var holaNode = host.parser.findHolaButton();
|
||
if (holaNode.isEmpty) {
|
||
var err2 = "Cannot find Hola button on home screen: " + deviceId;
|
||
host.log.warn(err2);
|
||
host.adb.tryToKillApplication(deviceId, app.package);
|
||
return err2;
|
||
}
|
||
|
||
// 5. Парсим имя и баланс с домашнего экрана
|
||
var fullName = host.parser.parseUserNameFromHomeScreen();
|
||
var balance = host.parser.parseBalanceFromHomeScreen();
|
||
host.log.debug("fullName from home: " + fullName + " balance: " + balance);
|
||
|
||
// Сохраняем баланс
|
||
host.dao.bankProfileUpdateAmount(app.id, balance);
|
||
|
||
host.adb.makeTap(deviceId, holaNode.x, holaNode.y);
|
||
host.timer.sleep(2000);
|
||
|
||
// 6. Ждём боковое меню
|
||
var sideMenuFound = false;
|
||
for (var i = 0; i < 5; ++i) {
|
||
host.parser.parseAndSaveXml(host.adb.getScreenDumpAsXml(deviceId, ++counter));
|
||
if (host.parser.isSideMenu()) {
|
||
sideMenuFound = true;
|
||
break;
|
||
}
|
||
host.timer.sleep(1000);
|
||
}
|
||
if (!sideMenuFound) {
|
||
var err3 = "Side menu not detected: " + deviceId;
|
||
host.log.warn(err3);
|
||
host.adb.tryToKillApplication(deviceId, app.package);
|
||
return err3;
|
||
}
|
||
|
||
// 7. Тапаем "Tu Información"
|
||
var tuInfoNode = host.parser.findNodeByContentDesc("Tu Información");
|
||
if (tuInfoNode.isEmpty) {
|
||
var err4 = "Cannot find Tu Información button: " + deviceId;
|
||
host.log.warn(err4);
|
||
host.adb.tryToKillApplication(deviceId, app.package);
|
||
return err4;
|
||
}
|
||
host.adb.makeTap(deviceId, tuInfoNode.x, tuInfoNode.y);
|
||
host.timer.sleep(2500);
|
||
|
||
// 8. Ждём страницу профиля
|
||
var profileFound = false;
|
||
for (var j = 0; j < 5; ++j) {
|
||
host.parser.parseAndSaveXml(host.adb.getScreenDumpAsXml(deviceId, ++counter));
|
||
if (host.parser.isProfilePage()) {
|
||
profileFound = true;
|
||
break;
|
||
}
|
||
host.timer.sleep(1000);
|
||
}
|
||
if (!profileFound) {
|
||
var err5 = "Profile page not detected: " + deviceId;
|
||
host.log.warn(err5);
|
||
host.adb.tryToKillApplication(deviceId, app.package);
|
||
return err5;
|
||
}
|
||
|
||
// 9. Парсим данные профиля
|
||
var nombre = host.parser.parseProfileNombre();
|
||
var apellido = host.parser.parseProfileApellido();
|
||
var email = host.parser.parseProfileEmail();
|
||
|
||
// 10. Скроллим вниз чтобы увидеть телефон
|
||
var x = Math.floor(device.screenWidth / 2);
|
||
var fromY = Math.floor(device.screenHeight * 3 / 4);
|
||
var toY = Math.floor(device.screenHeight / 4);
|
||
host.adb.makeSwipe(deviceId, x, fromY, x, toY);
|
||
host.timer.sleep(1500);
|
||
host.parser.parseAndSaveXml(host.adb.getScreenDumpAsXml(deviceId, ++counter));
|
||
|
||
var phone = host.parser.parseProfilePhone();
|
||
|
||
// Собираем полное имя
|
||
var parsedFullName;
|
||
if (nombre && apellido) {
|
||
parsedFullName = nombre + " " + apellido;
|
||
} else if (nombre) {
|
||
parsedFullName = nombre;
|
||
} else {
|
||
parsedFullName = fullName;
|
||
}
|
||
|
||
host.log.debug("nombre: " + nombre + " apellido: " + apellido
|
||
+ " email: " + email + " phone: " + phone
|
||
+ " fullName: " + parsedFullName);
|
||
|
||
// 11. Сохраняем профиль
|
||
if (!host.dao.bankProfileUpdateProfileInfo(app.id, parsedFullName, phone, email)) {
|
||
host.log.warn("Failed to save profile info to DB");
|
||
}
|
||
|
||
// 12. Создаём bank profile на сервере если нет
|
||
host.helpers.createBankProfileIfNeeded(deviceId, appCode, -1);
|
||
|
||
// 13. Отправляем аккаунты без material_id на сервер
|
||
var allAccounts = host.dao.materialGetAccounts(device.id, appCode);
|
||
var accountsToPost = [];
|
||
for (var k = 0; k < allAccounts.length; ++k) {
|
||
if (!allAccounts[k].materialId) accountsToPost.push(allAccounts[k]);
|
||
}
|
||
if (accountsToPost.length > 0) {
|
||
host.helpers.postAccountsData(accountsToPost);
|
||
}
|
||
|
||
host.dump.endScope("");
|
||
return ""; // success
|
||
} catch (e) {
|
||
// Любая JS-ошибка → engine error для runtime → fallback на C++.
|
||
host.dump.endScope(String(e));
|
||
throw e;
|
||
}
|
||
}
|