File indexing completed on 2024-11-24 04:43:58
0001 /* 0002 SPDX-FileCopyrightText: 2011-2013 Dan Vratil <dan@progdan.cz> 0003 SPDX-FileCopyrightText: 2020 Igor Poboiko <igor.poboiko@gmail.com> 0004 SPDX-FileCopyrightText: 2021 Carl Schwan <carl@carlschwan.eu> 0005 0006 SPDX-License-Identifier: GPL-3.0-or-later 0007 */ 0008 0009 #include "googlesettings.h" 0010 #include "googleresource_debug.h" 0011 #include "googlescopes.h" 0012 #include "settingsadaptor.h" 0013 0014 #include <KGAPI/Account> 0015 #include <KLocalizedString> 0016 #include <KMessageBox> 0017 0018 #include <QDataStream> 0019 #include <QIODevice> 0020 0021 #include <qt6keychain/keychain.h> 0022 using namespace QKeychain; 0023 0024 using namespace KGAPI2; 0025 0026 static const QString googleWalletFolder = QStringLiteral("Akonadi Google"); 0027 0028 GoogleSettings::GoogleSettings(const KSharedConfigPtr &config, Options options) 0029 : SettingsBase(config) 0030 { 0031 if (options & Option::ExportToDBus) { 0032 new SettingsAdaptor(this); 0033 QDBusConnection::sessionBus().registerObject(QStringLiteral("/Settings"), 0034 this, 0035 QDBusConnection::ExportAdaptors | QDBusConnection::ExportScriptableContents); 0036 } 0037 } 0038 0039 void GoogleSettings::init() 0040 { 0041 if (account().isEmpty()) { 0042 qCWarning(GOOGLE_LOG) << Q_FUNC_INFO << "No username set"; 0043 Q_EMIT accountReady(false); 0044 return; 0045 } 0046 0047 qCWarning(GOOGLE_LOG) << "Trying to read password for" << account(); 0048 0049 // First read from QtKeyChain 0050 auto job = new QKeychain::ReadPasswordJob(googleWalletFolder, this); 0051 job->setKey(account()); 0052 connect(job, &QKeychain::Job::finished, this, [this, job]() { 0053 if (job->error() != QKeychain::Error::NoError) { 0054 qCWarning(GOOGLE_LOG) << "Unable to read password" << job->error(); 0055 Q_EMIT accountReady(false); 0056 return; 0057 } 0058 0059 // Found something with QtKeyChain 0060 m_account = fetchAccountFromKeychain(account(), job); 0061 m_isReady = true; 0062 Q_EMIT accountReady(true); 0063 }); 0064 job->start(); 0065 } 0066 0067 KGAPI2::AccountPtr GoogleSettings::fetchAccountFromKeychain(const QString &accountName, QKeychain::ReadPasswordJob *job) 0068 { 0069 QMap<QString, QString> map; 0070 auto value = job->binaryData(); 0071 if (value.isEmpty()) { 0072 qCWarning(GOOGLE_LOG) << "Account" << accountName << "not found in KWallet"; 0073 return {}; 0074 } 0075 0076 QDataStream ds(value); 0077 ds >> map; 0078 0079 const QStringList scopes = map[QStringLiteral("scopes")].split(QLatin1Char(','), Qt::SkipEmptyParts); 0080 QList<QUrl> scopeUrls; 0081 scopeUrls.reserve(scopes.count()); 0082 for (const QString &scope : scopes) { 0083 scopeUrls << QUrl(scope); 0084 } 0085 AccountPtr account(new Account(accountName, map[QStringLiteral("accessToken")], map[QStringLiteral("refreshToken")], scopeUrls)); 0086 return account; 0087 } 0088 0089 WritePasswordJob *GoogleSettings::storeAccount(AccountPtr account) 0090 { 0091 // Removing the old one (if present) 0092 if (m_account && (account->accountName() != m_account->accountName())) { 0093 cleanup(); 0094 } 0095 // Populating the new one 0096 m_account = account; 0097 0098 QStringList scopes; 0099 const QList<QUrl> urlScopes = googleScopes(); 0100 scopes.reserve(urlScopes.count()); 0101 for (const QUrl &url : urlScopes) { 0102 scopes << url.toString(); 0103 } 0104 0105 const QMap<QString, QString> map = { 0106 {QStringLiteral("accessToken"), m_account->accessToken()}, 0107 {QStringLiteral("refreshToken"), m_account->refreshToken()}, 0108 {QStringLiteral("scopes"), scopes.join(QLatin1Char(','))}, 0109 }; 0110 0111 // Legacy: store the map exactly like Kwallet is doing it 0112 QByteArray mapData; 0113 QDataStream ds(&mapData, QIODevice::WriteOnly); 0114 ds << map; 0115 0116 auto writeJob = new WritePasswordJob(googleWalletFolder, this); 0117 writeJob->setKey(m_account->accountName()); 0118 writeJob->setBinaryData(mapData); 0119 0120 connect(writeJob, &WritePasswordJob::finished, this, [this, writeJob]() { 0121 if (writeJob->error()) { 0122 qCWarning(GOOGLE_LOG) << "Unable to write password" << writeJob->error(); 0123 return; 0124 } 0125 SettingsBase::setAccount(m_account->accountName()); 0126 m_isReady = true; 0127 }); 0128 0129 return writeJob; 0130 } 0131 0132 void GoogleSettings::cleanup() 0133 { 0134 if (m_account) { 0135 auto deleteJob = new DeletePasswordJob(googleWalletFolder, this); 0136 deleteJob->setKey(m_account->accountName()); 0137 deleteJob->start(); 0138 } 0139 } 0140 0141 void GoogleSettings::addCalendar(const QString &calendar) 0142 { 0143 if (calendars().isEmpty() || calendars().contains(calendar)) { 0144 return; 0145 } 0146 setCalendars(calendars() << calendar); 0147 save(); 0148 } 0149 0150 void GoogleSettings::addTaskList(const QString &taskList) 0151 { 0152 if (calendars().isEmpty() || taskLists().contains(taskList)) { 0153 return; 0154 } 0155 setTaskLists(taskLists() << taskList); 0156 save(); 0157 } 0158 0159 QString GoogleSettings::clientId() const 0160 { 0161 return QStringLiteral("554041944266.apps.googleusercontent.com"); 0162 } 0163 0164 QString GoogleSettings::clientSecret() const 0165 { 0166 return QStringLiteral("mdT1DjzohxN3npUUzkENT0gO"); 0167 } 0168 0169 bool GoogleSettings::isReady() const 0170 { 0171 return m_isReady; 0172 } 0173 0174 AccountPtr GoogleSettings::accountPtr() 0175 { 0176 return m_account; 0177 } 0178 0179 void GoogleSettings::setWindowId(WId id) 0180 { 0181 m_winId = id; 0182 } 0183 0184 void GoogleSettings::setResourceId(const QString &resourceIdentificator) 0185 { 0186 m_resourceId = resourceIdentificator; 0187 } 0188 0189 #include "moc_googlesettings.cpp"