玉兔远程控制 0.1.0-bate4
载入中...
搜索中...
未找到
PasswordStore.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QCoreApplication>
4#include <QEventLoop>
5#include <QJsonDocument>
6#include <QJsonObject>
7#include <QTimer>
8#include <QLoggingCategory>
9#include <QSettings>
10#if HAVE_QTKEYCHAIN
11 #include "keychain.h"
12#endif
13
14#include "ParameterPlugin.h"
15#include "PasswordStore.h"
16#include "RabbitCommonEncrypt.h"
17#include "RabbitCommonDir.h"
18
19static constexpr int KEYCHAIN_TIMEOUT_MS = 2000; // timeout for blocking waits
20static Q_LOGGING_CATEGORY(log, "WebBrowser.PasswordStore")
22 : QObject(parent)
23 , m_pPara(pPara)
24{
25 qDebug(log) << Q_FUNC_INFO;
26}
27
28CPasswordStore::~CPasswordStore()
29{
30 qDebug(log) << Q_FUNC_INFO;
31}
32
33static QString ServiceName()
34{
35 // Use application name as the keychain service; fall back to a sensible default.
36 return "io.github.KangLin/RabbitRemoteControl";
37}
38
39#if HAVE_QTKEYCHAIN
40QVariantMap CPasswordStore::getCredentials(const QString &host)
41{
42 QVariantMap result;
43 if (host.isEmpty()) return result;
44
45 const QString key = ServiceName() + QStringLiteral("autofill/%1").arg(host);
46 auto pJob = new QKeychain::ReadPasswordJob(ServiceName());
47 bool check = connect(pJob, &QKeychain::ReadPasswordJob::finished,
48 this, [this, pJob, host]() {
49 if (pJob->error() != QKeychain::NoError) {
50 qDebug(log) << "ReadPasswordJob error for" << host << ":"
51 << pJob->errorString();
52 return;
53 }
54 QString text = pJob->textData();
55 if (!text.isEmpty()) {
56 QVariantMap result;
57 // Expect JSON { "username": "...", "password": "..." }
58 QJsonDocument doc = QJsonDocument::fromJson(text.toUtf8());
59 if (doc.isObject()) {
60 QJsonObject obj = doc.object();
61 if (obj.contains(QStringLiteral("username")))
62 result["username"] = obj.value(QStringLiteral("username")).toString();
63 if (obj.contains(QStringLiteral("password")))
64 result["password"] = obj.value(QStringLiteral("password")).toString();
65 } else {
66 // Fallback: treat stored text as password only
67 result["password"] = text;
68 }
69 qDebug(log) << "Get credentials for" << host;
70 emit this->sigCredentialsReady(host, result);
71 }
72 });
73 Q_ASSERT(check);
74 pJob->setKey(key);
75 pJob->start();
76
77 return result;
78}
79
80void CPasswordStore::saveCredentials(
81 const QString &host, const QString &username, const QString &password)
82{
83 if (host.isEmpty() || username.isEmpty()) return;
84
85 const QString key = ServiceName() + QStringLiteral("autofill/%1").arg(host);
86
87 QJsonObject obj;
88 obj.insert(QStringLiteral("username"), username);
89 obj.insert(QStringLiteral("password"), password);
90 const QString payload =
91 QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
92 auto pJob = new QKeychain::WritePasswordJob(ServiceName());
93 bool check = connect(pJob, &QKeychain::WritePasswordJob::finished,
94 [this, host, pJob]() {
95 if (pJob->error() != QKeychain::NoError) {
96 qDebug(log) << "Saved credentials error for" << host << ":"
97 << pJob->errorString();
98 return;
99 }
100 emit this->credentialsSaved(host);
101 qDebug(log) << "Saved credentials for" << host;
102 });
103 Q_ASSERT(check);
104 pJob->setKey(key);
105 pJob->setTextData(payload);
106 pJob->start();
107}
108#else
109QVariantMap CPasswordStore::getCredentials(const QString &host)
110{
111 QVariantMap result;
112 if (host.isEmpty()) return result;
113
114 QString szFile;
115 szFile = RabbitCommon::CDir::Instance()->GetDirUserData()
116 + QDir::separator() + "WebCredentialsStore.ini";
117 QSettings set(szFile, QSettings::IniFormat);
118 const QString key = QStringLiteral("autofill/%1").arg(host);
119 QString text;
120 int nRet = m_pPara->LoadPassword("Password", key, text, set);
121 if (!nRet && !text.isEmpty()) {
122 // Expect JSON { "username": "...", "password": "..." }
123 QJsonDocument doc = QJsonDocument::fromJson(text.toUtf8());
124 if (doc.isObject()) {
125 QJsonObject obj = doc.object();
126 if (obj.contains(QStringLiteral("username")))
127 result["username"] = obj.value(QStringLiteral("username")).toString();
128 if (obj.contains(QStringLiteral("password")))
129 result["password"] = obj.value(QStringLiteral("password")).toString();
130 } else {
131 // Fallback: treat stored text as password only
132 result["password"] = text;
133 }
134 emit sigCredentialsReady(host, result);
135 } else
136 qCritical(log) << "Get credentials fail:" << host;
137
138 return result;
139}
140
141void CPasswordStore::saveCredentials(
142 const QString &host, const QString &username, const QString &password)
143{
144 if (host.isEmpty() || username.isEmpty()) return;
145
146 QString szFile;
147 szFile = RabbitCommon::CDir::Instance()->GetDirUserData()
148 + QDir::separator() + "WebCredentialsStore.ini";
149 QSettings set(szFile, QSettings::IniFormat);
150
151 const QString key = QStringLiteral("autofill/%1").arg(host);
152 QJsonObject obj;
153 obj.insert(QStringLiteral("username"), username);
154 obj.insert(QStringLiteral("password"), password);
155 const QString payload = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
156 m_pPara->SavePassword(key, payload, set, m_pPara->GetAutoFillUserAndPassword());
157 emit credentialsSaved(host);
158}
159#endif