File indexing completed on 2024-12-08 10:25:53

0001 /*
0002    SPDX-FileCopyrightText: 2017-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "rocketchataccountsettings.h"
0008 #include "config-ruqola.h"
0009 #include "localdatabase/localdatabaseutils.h"
0010 #include "managerdatapaths.h"
0011 #include "ruqola_debug.h"
0012 #include "ruqola_password_core_debug.h"
0013 
0014 #include <QDateTime>
0015 #include <QDir>
0016 #include <QFile>
0017 #include <QSettings>
0018 #include <QStandardPaths>
0019 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0020 #include <qt5keychain/keychain.h>
0021 #else
0022 #include <qt6keychain/keychain.h>
0023 #endif
0024 using namespace QKeychain;
0025 
0026 RocketChatAccountSettings::RocketChatAccountSettings(const QString &accountFileName, QObject *parent)
0027     : QObject(parent)
0028 {
0029     initializeSettings(accountFileName);
0030 }
0031 
0032 RocketChatAccountSettings::~RocketChatAccountSettings()
0033 {
0034     mSetting->sync();
0035     delete mSetting;
0036 }
0037 
0038 bool RocketChatAccountSettings::isValid() const
0039 {
0040     return !mServerUrl.isEmpty() && !mUserName.isEmpty();
0041 }
0042 
0043 void RocketChatAccountSettings::initializeSettings(const QString &accountFileName)
0044 {
0045     delete mSetting;
0046     mSetting = new QSettings(accountFileName, QSettings::IniFormat);
0047     qCDebug(RUQOLA_LOG) << "accountFileName " << accountFileName;
0048 
0049     mServerUrl = mSetting->value(QStringLiteral("serverURL"), QStringLiteral("open.rocket.chat")).toString();
0050     mUserName = mSetting->value(QStringLiteral("username")).toString();
0051     mUserId = mSetting->value(QStringLiteral("userID")).toString();
0052     mAuthToken = mSetting->value(QStringLiteral("authToken")).toString();
0053     mExpireToken = mSetting->value(QStringLiteral("expireToken")).toLongLong();
0054     mAccountName = mSetting->value(QStringLiteral("accountName")).toString();
0055     mUseLdap = mSetting->value(QStringLiteral("useLdap")).toBool();
0056     mAccountEnabled = mSetting->value(QStringLiteral("enabled"), true).toBool();
0057     mDisplayName = mSetting->value(QStringLiteral("displayName")).toString();
0058     mLastCheckedPreviewUrlCacheDate = mSetting->value(QStringLiteral("lastCheckedPreviewUrlDate")).toDate();
0059 
0060     if (mAccountEnabled && !mAccountName.isEmpty()) {
0061         qCDebug(RUQOLA_PASSWORD_CORE_LOG) << "Load password from QKeychain: accountname " << mAccountName;
0062         auto readJob = new ReadPasswordJob(QStringLiteral("Ruqola"), this);
0063         connect(readJob, &Job::finished, this, &RocketChatAccountSettings::slotPasswordRead);
0064         readJob->setKey(mAccountName);
0065         readJob->start();
0066     }
0067 }
0068 
0069 void RocketChatAccountSettings::slotPasswordRead(QKeychain::Job *baseJob)
0070 {
0071     auto job = qobject_cast<ReadPasswordJob *>(baseJob);
0072     Q_ASSERT(job);
0073     if (!job->error()) {
0074         mPassword = job->textData();
0075         qCDebug(RUQOLA_PASSWORD_CORE_LOG) << "OK, we have the password now";
0076         Q_EMIT passwordChanged();
0077     } else {
0078         qCWarning(RUQOLA_PASSWORD_CORE_LOG) << "We have an error during reading password " << job->errorString() << " Account name " << mAccountName;
0079     }
0080 }
0081 
0082 void RocketChatAccountSettings::slotPasswordWritten(QKeychain::Job *baseJob)
0083 {
0084     if (baseJob->error()) {
0085         qCWarning(RUQOLA_PASSWORD_CORE_LOG) << "Error writing password using QKeychain:" << baseJob->errorString();
0086     }
0087 }
0088 
0089 QDate RocketChatAccountSettings::lastCheckedPreviewUrlCacheDate() const
0090 {
0091     return mLastCheckedPreviewUrlCacheDate;
0092 }
0093 
0094 void RocketChatAccountSettings::setLastCheckedPreviewUrlCacheDate(const QDate &newLastCheckedPreviewUrlCacheDate)
0095 {
0096     if (mLastCheckedPreviewUrlCacheDate != newLastCheckedPreviewUrlCacheDate) {
0097         mLastCheckedPreviewUrlCacheDate = newLastCheckedPreviewUrlCacheDate;
0098         mSetting->setValue(QStringLiteral("lastCheckedPreviewUrlDate"), mLastCheckedPreviewUrlCacheDate);
0099         mSetting->sync();
0100     }
0101 }
0102 
0103 QString RocketChatAccountSettings::displayName() const
0104 {
0105     if (mDisplayName.isEmpty()) {
0106         return mAccountName;
0107     }
0108     return mDisplayName;
0109 }
0110 
0111 void RocketChatAccountSettings::setDisplayName(const QString &displayName)
0112 {
0113     if (mDisplayName != displayName) {
0114         mDisplayName = displayName;
0115         mSetting->setValue(QStringLiteral("displayName"), mDisplayName);
0116         mSetting->sync();
0117         Q_EMIT displayNameChanged();
0118     }
0119 }
0120 
0121 bool RocketChatAccountSettings::accountEnabled() const
0122 {
0123     return mAccountEnabled;
0124 }
0125 
0126 void RocketChatAccountSettings::setAccountEnabled(bool enabled)
0127 {
0128     if (mAccountEnabled != enabled) {
0129         mAccountEnabled = enabled;
0130         mSetting->setValue(QStringLiteral("enabled"), mAccountEnabled);
0131         mSetting->sync();
0132         Q_EMIT enableAccountChanged();
0133     }
0134 }
0135 
0136 QString RocketChatAccountSettings::lastSelectedRoom() const
0137 {
0138     return mSetting->value(QStringLiteral("SelectedRoom")).toString();
0139 }
0140 
0141 void RocketChatAccountSettings::setLastSelectedRoom(const QString &roomId)
0142 {
0143     if (!roomId.isEmpty()) {
0144         mSetting->setValue(QStringLiteral("SelectedRoom"), roomId);
0145     }
0146 }
0147 
0148 qint64 RocketChatAccountSettings::expireToken() const
0149 {
0150     return mExpireToken;
0151 }
0152 
0153 void RocketChatAccountSettings::setExpireToken(qint64 expireToken)
0154 {
0155     if (mExpireToken != expireToken) {
0156         mExpireToken = expireToken;
0157         mSetting->setValue(QStringLiteral("expireToken"), mExpireToken);
0158         mSetting->sync();
0159     }
0160 }
0161 
0162 bool RocketChatAccountSettings::tokenExpired() const
0163 {
0164     return mExpireToken < QDateTime::currentDateTime().toMSecsSinceEpoch();
0165 }
0166 
0167 QString RocketChatAccountSettings::userId() const
0168 {
0169     return mUserId;
0170 }
0171 
0172 void RocketChatAccountSettings::setUserId(const QString &userId)
0173 {
0174     // Don't use if( m_userID != userID) as we need to Q_EMIT userIDChanged
0175     mUserId = userId;
0176     mSetting->setValue(QStringLiteral("userID"), userId);
0177     mSetting->sync();
0178     Q_EMIT userIdChanged();
0179 }
0180 
0181 QString RocketChatAccountSettings::authToken() const
0182 {
0183     return mAuthToken;
0184 }
0185 
0186 void RocketChatAccountSettings::setAuthToken(const QString &authToken)
0187 {
0188     if (mAuthToken != authToken) {
0189         qCDebug(RUQOLA_LOG) << "Setting token to" << authToken;
0190         mAuthToken = authToken;
0191         mSetting->setValue(QStringLiteral("authToken"), authToken);
0192     }
0193 }
0194 
0195 void RocketChatAccountSettings::logout()
0196 {
0197     mSetting->setValue(QStringLiteral("authToken"), QString());
0198     mSetting->setValue(QStringLiteral("expireToken"), -1);
0199     mSetting->sync();
0200     mAuthToken.clear();
0201     mUserId.clear();
0202     mExpireToken = -1;
0203 }
0204 
0205 QString RocketChatAccountSettings::password() const
0206 {
0207     return mPassword;
0208 }
0209 
0210 void RocketChatAccountSettings::setPassword(const QString &password)
0211 {
0212     mPassword = password;
0213 
0214     auto writeJob = new WritePasswordJob(QStringLiteral("Ruqola"), this);
0215     connect(writeJob, &Job::finished, this, &RocketChatAccountSettings::slotPasswordWritten);
0216     writeJob->setKey(mAccountName);
0217     writeJob->setTextData(mPassword);
0218     writeJob->start();
0219 
0220     Q_EMIT passwordChanged();
0221 }
0222 
0223 QString RocketChatAccountSettings::twoFactorAuthenticationCode() const
0224 {
0225     return mTwoFactorAuthenticationCode;
0226 }
0227 
0228 void RocketChatAccountSettings::setTwoFactorAuthenticationCode(const QString &twoFactorAuthenticationCode)
0229 {
0230     if (mTwoFactorAuthenticationCode != twoFactorAuthenticationCode) {
0231         mTwoFactorAuthenticationCode = twoFactorAuthenticationCode;
0232 
0233         Q_EMIT twoFactorAuthenticationCodeChanged();
0234     }
0235 }
0236 
0237 QString RocketChatAccountSettings::userName() const
0238 {
0239     return mUserName;
0240 }
0241 
0242 void RocketChatAccountSettings::setUserName(const QString &userName)
0243 {
0244     if (mUserName != userName) {
0245         mUserName = userName;
0246         mSetting->setValue(QStringLiteral("username"), mUserName);
0247         mSetting->sync();
0248         Q_EMIT userNameChanged();
0249     }
0250 }
0251 
0252 QString RocketChatAccountSettings::accountName() const
0253 {
0254     return mAccountName;
0255 }
0256 
0257 void RocketChatAccountSettings::setAccountName(const QString &accountName)
0258 {
0259     if (mAccountName == accountName) {
0260         return;
0261     }
0262 
0263     initializeSettings(ManagerDataPaths::self()->accountConfigFileName(accountName));
0264     mSetting->setValue(QStringLiteral("accountName"), accountName);
0265     mSetting->sync();
0266     mAccountName = accountName;
0267     Q_EMIT accountNameChanged();
0268 }
0269 
0270 QString RocketChatAccountSettings::serverUrl() const
0271 {
0272     return mServerUrl;
0273 }
0274 
0275 void RocketChatAccountSettings::setServerUrl(const QString &serverUrl)
0276 {
0277     if (mServerUrl == serverUrl) {
0278         return;
0279     }
0280 
0281     mSetting->setValue(QStringLiteral("serverURL"), serverUrl);
0282     mSetting->sync();
0283     mServerUrl = serverUrl;
0284     Q_EMIT serverURLChanged();
0285 }
0286 
0287 QString RocketChatAccountSettings::cacheBasePath()
0288 {
0289     if (mServerUrl.isEmpty()) {
0290         return {};
0291     }
0292     if (mCachePath.isEmpty()) {
0293         mCachePath = ManagerDataPaths::self()->path(ManagerDataPaths::Cache, mAccountName);
0294         QDir dir;
0295         if (!dir.mkpath(mCachePath)) {
0296             qCWarning(RUQOLA_LOG) << "Impossible to create cache directory" << mCachePath;
0297         }
0298     }
0299     return mCachePath;
0300 }
0301 
0302 void RocketChatAccountSettings::removeSettings()
0303 {
0304     // Delete password
0305     auto deleteJob = new DeletePasswordJob(QStringLiteral("Ruqola"));
0306     deleteJob->setKey(mAccountName);
0307     deleteJob->start();
0308     QFile f(mSetting->fileName());
0309     if (!f.remove()) {
0310         qCWarning(RUQOLA_LOG) << "Impossible to delete config file: " << mSetting->fileName();
0311     }
0312 
0313     const QString storeCachePath = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1Char('/') + mAccountName + QLatin1Char('/');
0314     QDir dir(storeCachePath);
0315     if (!dir.removeRecursively()) {
0316         qCWarning(RUQOLA_LOG) << "Impossible to delete cache dir: " << storeCachePath;
0317     }
0318 }
0319 
0320 #include "moc_rocketchataccountsettings.cpp"