diff --git a/CMakeLists.txt b/CMakeLists.txt index 14c7abe..8d4266a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,10 +93,26 @@ add_executable(ARC WIN32 ${ANDROID_SOURCES} views/bank/BankSettingsWindow.cpp views/bank/BankSettingsWindow.h + views/bank/BankSetupWizard.cpp + views/bank/BankSetupWizard.h views/log/FileLogWindow.cpp views/log/FileLogWindow.h + views/log/LogDetailWindow.cpp + views/log/LogDetailWindow.h database/dao/GeneralLogDAO.cpp database/dao/GeneralLogDAO.h + android/dushanbe/CommonScript.cpp + android/dushanbe/CommonScript.h + android/dushanbe/GetCardInfoScript.cpp + android/dushanbe/GetCardInfoScript.h + android/dushanbe/GetLastTransactionsScript.cpp + android/dushanbe/GetLastTransactionsScript.h + android/dushanbe/GetProfileInfoScript.cpp + android/dushanbe/GetProfileInfoScript.h + android/dushanbe/LoginAndCheckAccountsScript.cpp + android/dushanbe/LoginAndCheckAccountsScript.h + android/dushanbe/ScreenXmlParser.cpp + android/dushanbe/ScreenXmlParser.h ) elseif (APPLE) add_executable(ARC @@ -108,10 +124,26 @@ elseif (APPLE) ${ANDROID_SOURCES} views/bank/BankSettingsWindow.cpp views/bank/BankSettingsWindow.h + views/bank/BankSetupWizard.cpp + views/bank/BankSetupWizard.h views/log/FileLogWindow.cpp views/log/FileLogWindow.h + views/log/LogDetailWindow.cpp + views/log/LogDetailWindow.h database/dao/GeneralLogDAO.cpp database/dao/GeneralLogDAO.h + android/dushanbe/CommonScript.cpp + android/dushanbe/CommonScript.h + android/dushanbe/GetCardInfoScript.cpp + android/dushanbe/GetCardInfoScript.h + android/dushanbe/GetLastTransactionsScript.cpp + android/dushanbe/GetLastTransactionsScript.h + android/dushanbe/GetProfileInfoScript.cpp + android/dushanbe/GetProfileInfoScript.h + android/dushanbe/LoginAndCheckAccountsScript.cpp + android/dushanbe/LoginAndCheckAccountsScript.h + android/dushanbe/ScreenXmlParser.cpp + android/dushanbe/ScreenXmlParser.h ) endif () @@ -132,7 +164,15 @@ if (WIN32) file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/eng.traineddata" DESTINATION "${CMAKE_BINARY_DIR}") file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/config.ini" DESTINATION "${CMAKE_BINARY_DIR}") file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/no_devices.png" DESTINATION "${CMAKE_BINARY_DIR}") - file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tools/adb/windows" DESTINATION "${CMAKE_BINARY_DIR}/tools/adb") + # adb копируется в post-build чтобы не падать при configure если adb.exe занят + file(GLOB _adb_files "${CMAKE_CURRENT_SOURCE_DIR}/tools/adb/windows/*") + foreach(_adb_file ${_adb_files}) + get_filename_component(_adb_fname "${_adb_file}" NAME) + add_custom_command(TARGET ARC POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "$/tools/adb/windows" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_adb_file}" "$/tools/adb/windows/${_adb_fname}" + ) + endforeach() add_custom_command(TARGET ARC POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory @@ -161,12 +201,17 @@ if (WIN32) COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/no_devices.png" "$/no_devices.png" - - COMMAND ${CMAKE_COMMAND} -E copy_directory - "${CMAKE_CURRENT_SOURCE_DIR}/tools/adb/windows" - "$/tools/adb/windows" ) + # Copy OpenSSL DLLs required for HTTPS (Qt SSL backend) + file(GLOB _openssl_dlls "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/libssl*.dll" + "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/libcrypto*.dll") + foreach(_dll ${_openssl_dlls}) + add_custom_command(TARGET ARC POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_dll}" "$" + ) + endforeach() + elseif (APPLE) target_link_libraries(ARC Qt6::Widgets diff --git a/main.cpp b/main.cpp index 36986c2..d192003 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #include "dao/MaterialDAO.h" @@ -11,6 +12,35 @@ #include #include + +#ifdef Q_OS_WIN +#include +#include +#pragma comment(lib, "dbghelp.lib") + +static LONG WINAPI crashHandler(EXCEPTION_POINTERS *ep) { + fprintf(stderr, "\n=== CRASH ===\n"); + fprintf(stderr, "Exception code: 0x%08lX\n", ep->ExceptionRecord->ExceptionCode); + fprintf(stderr, "Exception addr: 0x%p\n", ep->ExceptionRecord->ExceptionAddress); + fprintf(stderr, "Thread ID: %lu\n", GetCurrentThreadId()); + + HANDLE process = GetCurrentProcess(); + SymInitialize(process, NULL, TRUE); + void *stack[64]; + USHORT frames = CaptureStackBackTrace(0, 64, stack, NULL); + SYMBOL_INFO *symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + 256, 1); + symbol->MaxNameLen = 255; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + for (USHORT i = 0; i < frames; i++) { + SymFromAddr(process, (DWORD64)stack[i], 0, symbol); + fprintf(stderr, " [%2u] %s (0x%0llX)\n", i, symbol->Name, symbol->Address); + } + free(symbol); + SymCleanup(process); + fflush(stderr); + return EXCEPTION_EXECUTE_HANDLER; +} +#endif #include #include #include @@ -206,8 +236,9 @@ void messageHandler( const QString source = context.function ? QString("%1:%2").arg(context.function).arg(context.line) : QString(); + const char *func = context.function ? context.function : "unknown"; const QString line = QString("%1 [%2] [%3:%4] %5\n") - .arg(timestamp, level, context.function, QString::number(context.line), msg); + .arg(timestamp, level, func, QString::number(context.line), msg); // Записываем в файл (потокобезопасно) { QMutexLocker locker(&logMutex); @@ -237,10 +268,21 @@ void messageHandler( } int main(int argc, char *argv[]) { +#ifdef Q_OS_WIN + SetUnhandledExceptionFilter(crashHandler); +#endif QApplication app(argc, argv); app.setApplicationName("ARC"); app.setWindowIcon(QIcon("arc.png")); + // Используем Schannel (нативный Windows TLS) — не требует OpenSSL DLL + if (QSslSocket::availableBackends().contains("schannel")) { + QSslSocket::setActiveBackend("schannel"); + qDebug() << "[main] TLS backend set to schannel"; + } else { + qDebug() << "[main] Available TLS backends:" << QSslSocket::availableBackends(); + } + // Выбрать стиль Fusion + принудительная светлая тема QApplication::setStyle(QStyleFactory::create("Fusion")); diff --git a/views/log/FileLogWindow.cpp b/views/log/FileLogWindow.cpp index 8a16b1c..2e37b1b 100644 --- a/views/log/FileLogWindow.cpp +++ b/views/log/FileLogWindow.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -163,6 +164,7 @@ void FileLogWindow::updatePagination() { } void FileLogWindow::sendLogToTelegram() { + qDebug() << "[sendLogToTelegram] step 1: checking log file"; const QString logPath = QCoreApplication::applicationDirPath() + "/application.log"; if (!QFile::exists(logPath)) { QMessageBox::warning(this, "Ошибка", "Файл application.log не найден"); @@ -172,6 +174,7 @@ void FileLogWindow::sendLogToTelegram() { m_sendBtn->setEnabled(false); m_sendBtn->setText("Подготовка..."); + qDebug() << "[sendLogToTelegram] step 2: creating tmp dir"; // Собираем временную папку для архива const QString tmpDir = QDir::tempPath() + "/arc_logs_export"; QDir().mkpath(tmpDir); @@ -180,6 +183,7 @@ void FileLogWindow::sendLogToTelegram() { QFile::remove(tmpDir + "/application.log"); QFile::copy(logPath, tmpDir + "/application.log"); + qDebug() << "[sendLogToTelegram] step 3: exporting errors"; // 2. Экспортируем events с ошибками в errors.txt const QList errors = EventDAO::getAllEvents(EventStatus::Error); if (!errors.isEmpty()) { @@ -201,6 +205,7 @@ void FileLogWindow::sendLogToTelegram() { } } + qDebug() << "[sendLogToTelegram] step 4: exporting event screenshots"; // 3. Экспортируем скриншоты ошибок из events QDir().mkpath(tmpDir + "/screenshots"); int screenshotCount = 0; @@ -219,6 +224,7 @@ void FileLogWindow::sendLogToTelegram() { } } + qDebug() << "[sendLogToTelegram] step 5: exporting log screenshots"; // 3.5. Экспортируем скриншоты из general_logs (ошибки скриптов) const QList logErrors = GeneralLogDAO::getLogs(0, 100, {"WARNING", "CRITICAL", "FATAL"}); for (const GeneralLogEntry &gl : logErrors) { @@ -234,6 +240,7 @@ void FileLogWindow::sendLogToTelegram() { } } + qDebug() << "[sendLogToTelegram] step 6: creating archive with powershell"; // 4. Создаём архив #ifdef Q_OS_WIN const QString archivePath = QDir::tempPath() + "/arc_logs.zip"; @@ -243,7 +250,12 @@ void FileLogWindow::sendLogToTelegram() { archiver.start("powershell", QStringList() << "-NoProfile" << "-Command" << QString("Compress-Archive -Path '%1/*' -DestinationPath '%2' -Force").arg(tmpDir, archivePath)); - archiver.waitForFinished(30000); + if (!archiver.waitForFinished(30000)) { + qWarning() << "[sendLogToTelegram] powershell archiver timeout/error:" << archiver.errorString(); + } + qDebug() << "[sendLogToTelegram] step 6.1: archiver exit code:" << archiver.exitCode() + << "stdout:" << archiver.readAllStandardOutput() + << "stderr:" << archiver.readAllStandardError(); #else const QString archivePath = QDir::tempPath() + "/arc_logs.zip"; QFile::remove(archivePath); @@ -256,6 +268,9 @@ void FileLogWindow::sendLogToTelegram() { // Чистим временную папку QDir(tmpDir).removeRecursively(); + qDebug() << "[sendLogToTelegram] step 7: archive exists:" << QFile::exists(archivePath) + << "path:" << archivePath; + if (!QFile::exists(archivePath)) { QMessageBox::warning(this, "Ошибка", "Не удалось создать архив"); m_sendBtn->setEnabled(true); @@ -274,6 +289,19 @@ void FileLogWindow::sendLogToTelegram() { return; } + // Проверяем поддержку SSL + if (!QSslSocket::supportsSsl()) { + qWarning() << "[sendLogToTelegram] SSL not supported! Build:" << QSslSocket::sslLibraryBuildVersionString() + << "Runtime:" << QSslSocket::sslLibraryVersionString(); + QMessageBox::warning(this, "Ошибка", "SSL не поддерживается.\nНевозможно отправить логи через HTTPS."); + delete zipFile; + m_sendBtn->setEnabled(true); + m_sendBtn->setText("Отправить"); + return; + } + + qDebug() << "[sendLogToTelegram] SSL OK, sending..."; + // Telegram Bot API const QString botToken = "8256716069:AAFgZRB_0Y6KTpqFQmCxIlZiWdY5m2dR2D8"; const QString chatId = "-5177086220"; @@ -304,8 +332,19 @@ void FileLogWindow::sendLogToTelegram() { zipFile->setParent(multiPart); multiPart->append(filePart); + qDebug() << "[sendLogToTelegram] step 8: creating network request"; auto *manager = new QNetworkAccessManager(this); - QNetworkReply *reply = manager->post(QNetworkRequest(url), multiPart); + + // Принудительно используем Schannel (нативный Windows TLS) вместо OpenSSL + QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration(); + sslConfig.setBackendConfigurationOption("SslProtocol", "TlsV1_2OrLater"); + QNetworkRequest req(url); + req.setSslConfiguration(sslConfig); + + qDebug() << "[sendLogToTelegram] step 9: posting to telegram..." + << "SSL backend:" << QSslSocket::activeBackend(); + QNetworkReply *reply = manager->post(req, multiPart); + qDebug() << "[sendLogToTelegram] step 10: post sent, waiting for reply"; multiPart->setParent(reply); connect(reply, &QNetworkReply::finished, this, [this, reply, manager, archivePath]() { diff --git a/views/widget/loader/LoaderWindow.cpp b/views/widget/loader/LoaderWindow.cpp index 9dacc2e..cce138a 100644 --- a/views/widget/loader/LoaderWindow.cpp +++ b/views/widget/loader/LoaderWindow.cpp @@ -31,21 +31,17 @@ LoaderWindow::LoaderWindow(QWidget *parent) : QWidget(parent) { connect(networkService, &NetworkService::finished, networkService, &QObject::deleteLater); connect(thread, &QThread::finished, thread, &QThread::deleteLater); - connect(networkService, &NetworkService::finishedWithResult, [&](const int result) { + connect(networkService, &NetworkService::finishedWithResult, this, [this](const int result) { m_checkResult = result; if (m_checkResult == -1) { if (timer) { - QMetaObject::invokeMethod(timer, "stop", Qt::QueuedConnection); + timer->stop(); } - QMetaObject::invokeMethod(this, [=]() { - emit loadingFinished(m_checkResult); - }, Qt::QueuedConnection); + emit loadingFinished(m_checkResult); } else if (progressBar->value() >= 100) { - QMetaObject::invokeMethod(this, [=]() { - emit loadingFinished(m_checkResult); - }, Qt::QueuedConnection); + emit loadingFinished(m_checkResult); } - }); + }, Qt::QueuedConnection); thread->start(); }