2015-04-09 17:19:17 +03:00
|
|
|
/*
|
|
|
|
* Copyright (C) by Olivier Goffart <ogoffart@woboq.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
2016-10-25 12:00:07 +03:00
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
2015-04-09 17:19:17 +03:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "accountmanager.h"
|
2022-12-07 19:11:28 +03:00
|
|
|
|
2015-04-17 18:56:17 +03:00
|
|
|
#include "sslerrordialog.h"
|
2015-07-16 15:21:51 +03:00
|
|
|
#include "proxyauthhandler.h"
|
2019-03-01 10:46:33 +03:00
|
|
|
#include "common/asserts.h"
|
2022-12-07 19:11:28 +03:00
|
|
|
#include "creds/credentialsfactory.h"
|
|
|
|
#include "creds/abstractcredentials.h"
|
|
|
|
#include "libsync/clientsideencryption.h"
|
|
|
|
#include "libsync/configfile.h"
|
|
|
|
#include "libsync/cookiejar.h"
|
|
|
|
#include "libsync/theme.h"
|
|
|
|
|
2015-04-09 17:19:17 +03:00
|
|
|
#include <QSettings>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QNetworkAccessManager>
|
2018-01-21 21:50:40 +03:00
|
|
|
#include <QMessageBox>
|
2023-09-20 18:26:27 +03:00
|
|
|
#include <QPushButton>
|
2015-04-09 17:19:17 +03:00
|
|
|
|
|
|
|
namespace {
|
2022-10-10 13:56:51 +03:00
|
|
|
constexpr auto urlC = "url";
|
|
|
|
constexpr auto authTypeC = "authType";
|
|
|
|
constexpr auto userC = "user";
|
|
|
|
constexpr auto displayNameC = "displayName";
|
|
|
|
constexpr auto httpUserC = "http_user";
|
|
|
|
constexpr auto davUserC = "dav_user";
|
2023-04-30 18:14:07 +03:00
|
|
|
constexpr auto webflowUserC = "webflow_user";
|
2022-10-10 13:02:22 +03:00
|
|
|
constexpr auto shibbolethUserC = "shibboleth_shib_user";
|
2022-10-10 13:56:51 +03:00
|
|
|
constexpr auto caCertsKeyC = "CaCertificates";
|
|
|
|
constexpr auto accountsC = "Accounts";
|
|
|
|
constexpr auto versionC = "version";
|
|
|
|
constexpr auto serverVersionC = "serverVersion";
|
2023-08-01 11:00:39 +03:00
|
|
|
constexpr auto serverColorC = "serverColor";
|
|
|
|
constexpr auto serverTextColorC = "serverTextColor";
|
2023-05-05 17:15:09 +03:00
|
|
|
constexpr auto skipE2eeMetadataChecksumValidationC = "skipE2eeMetadataChecksumValidation";
|
2022-10-10 13:02:22 +03:00
|
|
|
constexpr auto generalC = "General";
|
|
|
|
|
|
|
|
constexpr auto dummyAuthTypeC = "dummy";
|
|
|
|
constexpr auto httpAuthTypeC = "http";
|
|
|
|
constexpr auto webflowAuthTypeC = "webflow";
|
|
|
|
constexpr auto shibbolethAuthTypeC = "shibboleth";
|
|
|
|
constexpr auto httpAuthPrefix = "http_";
|
|
|
|
constexpr auto webflowAuthPrefix = "webflow_";
|
|
|
|
|
|
|
|
constexpr auto legacyRelativeConfigLocationC = "/ownCloud/owncloud.cfg";
|
2022-11-07 20:33:39 +03:00
|
|
|
constexpr auto legacyCfgFileNameC = "owncloud.cfg";
|
2018-05-02 16:40:54 +03:00
|
|
|
|
|
|
|
// The maximum versions that this client can read
|
2022-10-10 13:02:22 +03:00
|
|
|
constexpr auto maxAccountsVersion = 2;
|
|
|
|
constexpr auto maxAccountVersion = 1;
|
2015-04-09 17:19:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace OCC {
|
|
|
|
|
2017-12-28 22:33:10 +03:00
|
|
|
Q_LOGGING_CATEGORY(lcAccountManager, "nextcloud.gui.account.manager", QtInfoMsg)
|
2017-05-09 15:24:11 +03:00
|
|
|
|
2015-04-09 17:19:17 +03:00
|
|
|
AccountManager *AccountManager::instance()
|
|
|
|
{
|
|
|
|
static AccountManager instance;
|
|
|
|
return &instance;
|
|
|
|
}
|
|
|
|
|
2023-04-30 12:49:46 +03:00
|
|
|
AccountManager::AccountsRestoreResult AccountManager::restore(const bool alsoRestoreLegacySettings)
|
2015-04-23 16:42:18 +03:00
|
|
|
{
|
2018-05-14 15:37:48 +03:00
|
|
|
QStringList skipSettingsKeys;
|
|
|
|
backwardMigrationSettingsKeys(&skipSettingsKeys, &skipSettingsKeys);
|
|
|
|
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
|
2018-10-13 19:45:01 +03:00
|
|
|
if (settings->status() != QSettings::NoError || !settings->isWritable()) {
|
2017-03-30 14:46:20 +03:00
|
|
|
qCWarning(lcAccountManager) << "Could not read settings from" << settings->fileName()
|
2017-02-08 16:28:50 +03:00
|
|
|
<< settings->status();
|
2023-04-30 12:49:46 +03:00
|
|
|
return AccountsRestoreFailure;
|
2017-02-08 16:28:50 +03:00
|
|
|
}
|
2015-04-23 16:42:18 +03:00
|
|
|
|
2018-05-14 15:37:48 +03:00
|
|
|
if (skipSettingsKeys.contains(settings->group())) {
|
|
|
|
// Should not happen: bad container keys should have been deleted
|
|
|
|
qCWarning(lcAccountManager) << "Accounts structure is too new, ignoring";
|
2023-04-30 12:49:46 +03:00
|
|
|
return AccountsRestoreSuccessWithSkipped;
|
2018-05-14 15:37:48 +03:00
|
|
|
}
|
|
|
|
|
2015-04-23 16:42:18 +03:00
|
|
|
// If there are no accounts, check the old format.
|
2023-01-13 19:55:35 +03:00
|
|
|
if (settings->childGroups().isEmpty() && !settings->contains(QLatin1String(versionC)) && alsoRestoreLegacySettings) {
|
2017-02-08 16:28:50 +03:00
|
|
|
restoreFromLegacySettings();
|
2023-04-30 12:49:46 +03:00
|
|
|
return AccountsRestoreSuccessFromLegacyVersion;
|
2015-04-23 16:42:18 +03:00
|
|
|
}
|
|
|
|
|
2023-04-30 12:49:46 +03:00
|
|
|
auto result = AccountsRestoreSuccess;
|
2022-10-24 18:53:40 +03:00
|
|
|
const auto settingsChildGroups = settings->childGroups();
|
|
|
|
for (const auto &accountId : settingsChildGroups) {
|
2015-04-23 16:42:18 +03:00
|
|
|
settings->beginGroup(accountId);
|
2018-05-14 15:37:48 +03:00
|
|
|
if (!skipSettingsKeys.contains(settings->group())) {
|
2022-10-10 13:02:22 +03:00
|
|
|
if (const auto acc = loadAccountHelper(*settings)) {
|
2018-05-14 15:37:48 +03:00
|
|
|
acc->_id = accountId;
|
|
|
|
if (auto accState = AccountState::loadFromSettings(acc, *settings)) {
|
2019-03-01 10:46:33 +03:00
|
|
|
auto jar = qobject_cast<CookieJar*>(acc->_am->cookieJar());
|
|
|
|
ASSERT(jar);
|
2023-08-15 19:20:18 +03:00
|
|
|
if (jar) {
|
2019-03-01 10:46:33 +03:00
|
|
|
jar->restore(acc->cookieJarPath());
|
2023-08-15 19:20:18 +03:00
|
|
|
}
|
2018-05-14 15:37:48 +03:00
|
|
|
addAccountState(accState);
|
|
|
|
}
|
2016-03-01 18:08:23 +03:00
|
|
|
}
|
2018-05-14 15:37:48 +03:00
|
|
|
} else {
|
|
|
|
qCInfo(lcAccountManager) << "Account" << accountId << "is too new, ignoring";
|
|
|
|
_additionalBlockedAccountIds.insert(accountId);
|
2023-04-30 12:49:46 +03:00
|
|
|
result = AccountsRestoreSuccessWithSkipped;
|
2015-04-23 16:42:18 +03:00
|
|
|
}
|
|
|
|
settings->endGroup();
|
|
|
|
}
|
|
|
|
|
2023-04-30 12:49:46 +03:00
|
|
|
return result;
|
2015-04-23 16:42:18 +03:00
|
|
|
}
|
|
|
|
|
2018-05-14 15:37:48 +03:00
|
|
|
void AccountManager::backwardMigrationSettingsKeys(QStringList *deleteKeys, QStringList *ignoreKeys)
|
2018-05-02 16:40:54 +03:00
|
|
|
{
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
|
|
|
|
const auto accountsVersion = settings->value(QLatin1String(versionC)).toInt();
|
|
|
|
|
2018-05-02 16:40:54 +03:00
|
|
|
if (accountsVersion <= maxAccountsVersion) {
|
2022-10-24 18:53:40 +03:00
|
|
|
const auto settingsChildGroups = settings->childGroups();
|
|
|
|
for (const auto &accountId : settingsChildGroups) {
|
2018-05-02 16:40:54 +03:00
|
|
|
settings->beginGroup(accountId);
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto accountVersion = settings->value(QLatin1String(versionC), 1).toInt();
|
|
|
|
|
2018-05-02 16:40:54 +03:00
|
|
|
if (accountVersion > maxAccountVersion) {
|
2018-05-14 15:37:48 +03:00
|
|
|
ignoreKeys->append(settings->group());
|
2018-05-02 16:40:54 +03:00
|
|
|
}
|
|
|
|
settings->endGroup();
|
|
|
|
}
|
|
|
|
} else {
|
2018-05-14 15:37:48 +03:00
|
|
|
deleteKeys->append(settings->group());
|
2018-05-02 16:40:54 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-23 16:42:18 +03:00
|
|
|
bool AccountManager::restoreFromLegacySettings()
|
2015-04-09 17:19:17 +03:00
|
|
|
{
|
2017-03-30 14:46:20 +03:00
|
|
|
qCInfo(lcAccountManager) << "Migrate: restoreFromLegacySettings, checking settings group"
|
2017-02-08 16:28:50 +03:00
|
|
|
<< Theme::instance()->appName();
|
|
|
|
|
2022-12-01 16:04:02 +03:00
|
|
|
// try to open the correctly themed settings
|
2017-08-16 09:36:52 +03:00
|
|
|
auto settings = ConfigFile::settingsWithGroup(Theme::instance()->appName());
|
2015-04-09 17:19:17 +03:00
|
|
|
|
2022-12-01 16:04:02 +03:00
|
|
|
// if the settings file could not be opened, the childKeys list is empty
|
|
|
|
// then try to load settings from a very old place
|
2015-04-09 17:19:17 +03:00
|
|
|
if (settings->childKeys().isEmpty()) {
|
2022-12-01 16:04:02 +03:00
|
|
|
// Legacy settings used QDesktopServices to get the location for the config folder in 2.4 and before
|
2022-12-06 16:07:28 +03:00
|
|
|
const auto legacy2_4CfgSettingsLocation = QString(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/data"));
|
2022-12-01 16:04:02 +03:00
|
|
|
const auto legacy2_4CfgFileParentFolder = legacy2_4CfgSettingsLocation.left(legacy2_4CfgSettingsLocation.lastIndexOf('/'));
|
|
|
|
|
|
|
|
// 2.5+ (rest of 2.x series)
|
|
|
|
const auto legacy2_5CfgSettingsLocation = QStandardPaths::writableLocation(Utility::isWindows() ? QStandardPaths::AppDataLocation : QStandardPaths::AppConfigLocation);
|
|
|
|
const auto legacy2_5CfgFileParentFolder = legacy2_5CfgSettingsLocation.left(legacy2_5CfgSettingsLocation.lastIndexOf('/'));
|
|
|
|
|
|
|
|
// Now try the locations we use today
|
2022-11-07 20:33:39 +03:00
|
|
|
const auto fullLegacyCfgFile = QDir::fromNativeSeparators(settings->fileName());
|
|
|
|
const auto legacyCfgFileParentFolder = fullLegacyCfgFile.left(fullLegacyCfgFile.lastIndexOf('/'));
|
|
|
|
const auto legacyCfgFileGrandParentFolder = legacyCfgFileParentFolder.left(legacyCfgFileParentFolder.lastIndexOf('/'));
|
|
|
|
|
2022-12-01 16:04:02 +03:00
|
|
|
const auto legacyCfgFileNamePath = QString(QStringLiteral("/") + legacyCfgFileNameC);
|
|
|
|
const auto legacyCfgFileRelativePath = QString(legacyRelativeConfigLocationC);
|
|
|
|
|
|
|
|
const auto legacyLocations = QVector<QString>{legacy2_4CfgFileParentFolder + legacyCfgFileRelativePath,
|
|
|
|
legacy2_5CfgFileParentFolder + legacyCfgFileRelativePath,
|
|
|
|
legacyCfgFileParentFolder + legacyCfgFileNamePath,
|
|
|
|
legacyCfgFileGrandParentFolder + legacyCfgFileRelativePath};
|
|
|
|
|
|
|
|
for (const auto &configFile : legacyLocations) {
|
2023-09-20 16:42:18 +03:00
|
|
|
auto oCSettings = std::make_unique<QSettings>(configFile, QSettings::IniFormat);
|
|
|
|
if (oCSettings->status() != QSettings::Status::NoError) {
|
|
|
|
qCInfo(lcAccountManager) << "Error reading legacy configuration file" << oCSettings->status();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
oCSettings->beginGroup(QLatin1String(accountsC));
|
|
|
|
const auto accountsListSize = oCSettings->childGroups().size();
|
|
|
|
oCSettings->endGroup();
|
2023-05-05 05:17:45 +03:00
|
|
|
if (const QFileInfo configFileInfo(configFile); configFileInfo.exists() && configFileInfo.isReadable()) {
|
2022-11-07 20:33:39 +03:00
|
|
|
qCInfo(lcAccountManager) << "Migrate: checking old config " << configFile;
|
2023-09-20 16:42:18 +03:00
|
|
|
if (!forceLegacyImport() && accountsListSize > 0) {
|
|
|
|
const auto importQuestion = accountsListSize > 1
|
|
|
|
? tr("%1 accounts were detected on a legacy desktop client.\n"
|
|
|
|
"Should the accounts be imported?").arg(QString::number(accountsListSize))
|
|
|
|
: tr("One account was detected on a legacy desktop client.\n"
|
|
|
|
"Should the account be imported?");
|
2023-09-20 18:26:27 +03:00
|
|
|
const auto importMessageBox = new QMessageBox(QMessageBox::Question, tr("Legacy import"), importQuestion);
|
2023-09-20 16:42:18 +03:00
|
|
|
importMessageBox->addButton(tr("Import"), QMessageBox::AcceptRole);
|
2023-09-20 18:26:27 +03:00
|
|
|
const auto skipButton = importMessageBox->addButton(tr("Skip"), QMessageBox::DestructiveRole);
|
2023-09-20 16:42:18 +03:00
|
|
|
importMessageBox->setAttribute(Qt::WA_DeleteOnClose);
|
2023-09-20 18:26:27 +03:00
|
|
|
importMessageBox->exec();
|
|
|
|
if (importMessageBox->clickedButton() == skipButton) {
|
2023-05-08 15:24:41 +03:00
|
|
|
return false;
|
|
|
|
}
|
2023-05-05 05:17:45 +03:00
|
|
|
}
|
|
|
|
|
2022-12-15 15:27:12 +03:00
|
|
|
// Check the theme url to see if it is the same url that the oC config was for
|
2023-01-11 18:58:48 +03:00
|
|
|
const auto overrideUrl = Theme::instance()->overrideServerUrl();
|
|
|
|
const auto cleanOverrideUrl = overrideUrl.endsWith('/') ? overrideUrl.chopped(1) : overrideUrl;
|
|
|
|
qCInfo(lcAccountManager) << "Migrate: overrideUrl" << cleanOverrideUrl;
|
|
|
|
|
|
|
|
if (!cleanOverrideUrl.isEmpty()) {
|
2023-01-11 21:22:56 +03:00
|
|
|
oCSettings->beginGroup(QLatin1String(accountsC));
|
|
|
|
const auto accountsChildGroups = oCSettings->childGroups();
|
|
|
|
for (const auto &accountId : accountsChildGroups) {
|
|
|
|
oCSettings->beginGroup(accountId);
|
|
|
|
const auto oCUrl = oCSettings->value(QLatin1String(urlC)).toString();
|
|
|
|
const auto cleanOCUrl = oCUrl.endsWith('/') ? oCUrl.chopped(1) : oCUrl;
|
|
|
|
|
|
|
|
// in case the urls are equal reset the settings object to read from
|
|
|
|
// the ownCloud settings object
|
|
|
|
qCInfo(lcAccountManager) << "Migrate oC config if " << cleanOCUrl << " == " << cleanOverrideUrl << ":"
|
|
|
|
<< (cleanOCUrl == cleanOverrideUrl ? "Yes" : "No");
|
|
|
|
if (cleanOCUrl == cleanOverrideUrl) {
|
|
|
|
qCInfo(lcAccountManager) << "Copy settings" << oCSettings->allKeys().join(", ");
|
|
|
|
oCSettings->endGroup(); // current accountID group
|
|
|
|
oCSettings->endGroup(); // accounts group
|
|
|
|
settings = std::move(oCSettings);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
oCSettings->endGroup();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oCSettings) {
|
|
|
|
oCSettings->endGroup();
|
2022-11-07 20:33:39 +03:00
|
|
|
}
|
2022-12-15 15:27:12 +03:00
|
|
|
} else {
|
|
|
|
qCInfo(lcAccountManager) << "Copy settings" << oCSettings->allKeys().join(", ");
|
|
|
|
settings = std::move(oCSettings);
|
2015-04-09 17:19:17 +03:00
|
|
|
}
|
2022-12-15 15:27:12 +03:00
|
|
|
|
2023-04-30 13:40:34 +03:00
|
|
|
ConfigFile::setDiscoveredLegacyConfigPath(configFileInfo.canonicalPath());
|
2022-12-15 15:27:12 +03:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
qCInfo(lcAccountManager) << "Migrate: could not read old config " << configFile;
|
2015-04-09 17:19:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-23 16:42:18 +03:00
|
|
|
// Try to load the single account.
|
2015-04-09 17:19:17 +03:00
|
|
|
if (!settings->childKeys().isEmpty()) {
|
2022-11-07 20:33:39 +03:00
|
|
|
settings->beginGroup(accountsC);
|
|
|
|
const auto childGroups = settings->childGroups();
|
|
|
|
for (const auto &accountId : childGroups) {
|
|
|
|
settings->beginGroup(accountId);
|
|
|
|
if (const auto acc = loadAccountHelper(*settings)) {
|
2023-09-17 19:45:28 +03:00
|
|
|
addAccount(acc);
|
2022-11-07 20:33:39 +03:00
|
|
|
}
|
2023-09-12 15:54:31 +03:00
|
|
|
settings->endGroup();
|
2015-04-09 17:19:17 +03:00
|
|
|
}
|
2023-09-12 15:54:31 +03:00
|
|
|
return true;
|
2015-04-09 17:19:17 +03:00
|
|
|
}
|
2023-05-05 05:22:38 +03:00
|
|
|
|
|
|
|
QMessageBox::information(nullptr,
|
|
|
|
tr("Legacy import"),
|
|
|
|
tr("Could not import accounts from legacy client configuration."));
|
2015-04-09 17:19:17 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-08-06 13:49:18 +03:00
|
|
|
void AccountManager::save(bool saveCredentials)
|
2015-04-09 17:19:17 +03:00
|
|
|
{
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
|
2018-05-02 16:40:54 +03:00
|
|
|
settings->setValue(QLatin1String(versionC), maxAccountsVersion);
|
2020-09-27 14:02:27 +03:00
|
|
|
for (const auto &acc : qAsConst(_accounts)) {
|
2015-04-23 16:42:18 +03:00
|
|
|
settings->beginGroup(acc->account()->id());
|
2016-03-01 18:08:23 +03:00
|
|
|
saveAccountHelper(acc->account().data(), *settings, saveCredentials);
|
2015-04-23 16:42:18 +03:00
|
|
|
settings->endGroup();
|
2015-04-17 18:56:17 +03:00
|
|
|
}
|
2015-09-17 14:48:05 +03:00
|
|
|
|
|
|
|
settings->sync();
|
2017-03-30 14:46:20 +03:00
|
|
|
qCInfo(lcAccountManager) << "Saved all account settings, status:" << settings->status();
|
2015-04-17 18:56:17 +03:00
|
|
|
}
|
|
|
|
|
2016-03-01 18:08:23 +03:00
|
|
|
void AccountManager::saveAccount(Account *a)
|
2015-08-14 12:31:01 +03:00
|
|
|
{
|
2020-07-08 16:49:27 +03:00
|
|
|
qCDebug(lcAccountManager) << "Saving account" << a->url().toString();
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
|
2015-08-14 12:31:01 +03:00
|
|
|
settings->beginGroup(a->id());
|
2016-03-01 18:08:23 +03:00
|
|
|
saveAccountHelper(a, *settings, false); // don't save credentials they might not have been loaded yet
|
2015-08-14 12:31:01 +03:00
|
|
|
settings->endGroup();
|
2015-09-17 14:48:05 +03:00
|
|
|
|
|
|
|
settings->sync();
|
2020-07-08 16:49:27 +03:00
|
|
|
qCDebug(lcAccountManager) << "Saved account settings, status:" << settings->status();
|
2015-08-14 12:31:01 +03:00
|
|
|
}
|
|
|
|
|
2016-03-01 18:08:23 +03:00
|
|
|
void AccountManager::saveAccountState(AccountState *a)
|
|
|
|
{
|
2020-07-08 16:49:27 +03:00
|
|
|
qCDebug(lcAccountManager) << "Saving account state" << a->account()->url().toString();
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
|
2016-03-01 18:08:23 +03:00
|
|
|
settings->beginGroup(a->account()->id());
|
|
|
|
settings->endGroup();
|
|
|
|
|
|
|
|
settings->sync();
|
2020-07-08 16:49:27 +03:00
|
|
|
qCDebug(lcAccountManager) << "Saved account state settings, status:" << settings->status();
|
2016-03-01 18:08:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void AccountManager::saveAccountHelper(Account *acc, QSettings &settings, bool saveCredentials)
|
2015-04-17 18:56:17 +03:00
|
|
|
{
|
2023-08-15 19:20:18 +03:00
|
|
|
qCDebug(lcAccountManager) << "Saving settings to" << settings.fileName();
|
2018-05-02 16:40:54 +03:00
|
|
|
settings.setValue(QLatin1String(versionC), maxAccountVersion);
|
2015-04-24 11:18:33 +03:00
|
|
|
settings.setValue(QLatin1String(urlC), acc->_url.toString());
|
2018-10-05 20:45:43 +03:00
|
|
|
settings.setValue(QLatin1String(davUserC), acc->_davUser);
|
2022-10-06 20:44:51 +03:00
|
|
|
settings.setValue(QLatin1String(displayNameC), acc->_displayName);
|
2016-03-02 13:59:36 +03:00
|
|
|
settings.setValue(QLatin1String(serverVersionC), acc->_serverVersion);
|
2023-08-01 11:00:39 +03:00
|
|
|
settings.setValue(QLatin1String(serverColorC), acc->_serverColor);
|
|
|
|
settings.setValue(QLatin1String(serverTextColorC), acc->_serverTextColor);
|
2023-05-05 17:15:09 +03:00
|
|
|
if (!acc->_skipE2eeMetadataChecksumValidation) {
|
|
|
|
settings.remove(QLatin1String(skipE2eeMetadataChecksumValidationC));
|
|
|
|
} else {
|
|
|
|
settings.setValue(QLatin1String(skipE2eeMetadataChecksumValidationC), acc->_skipE2eeMetadataChecksumValidation);
|
|
|
|
}
|
2022-10-06 20:44:51 +03:00
|
|
|
|
2015-04-09 17:19:17 +03:00
|
|
|
if (acc->_credentials) {
|
2015-08-06 13:49:18 +03:00
|
|
|
if (saveCredentials) {
|
|
|
|
// Only persist the credentials if the parameter is set, on migration from 1.8.x
|
|
|
|
// we want to save the accounts but not overwrite the credentials
|
|
|
|
// (This is easier than asynchronously fetching the credentials from keychain and then
|
|
|
|
// re-persisting them)
|
|
|
|
acc->_credentials->persist();
|
|
|
|
}
|
2022-10-10 13:02:22 +03:00
|
|
|
|
|
|
|
const auto settingsMapKeys = acc->_settingsMap.keys();
|
|
|
|
for (const auto &key : settingsMapKeys) {
|
2015-04-24 11:18:33 +03:00
|
|
|
settings.setValue(key, acc->_settingsMap.value(key));
|
2015-04-09 17:19:17 +03:00
|
|
|
}
|
2015-04-24 11:18:33 +03:00
|
|
|
settings.setValue(QLatin1String(authTypeC), acc->_credentials->authType());
|
2015-04-09 17:19:17 +03:00
|
|
|
|
|
|
|
// HACK: Save http_user also as user
|
2023-08-15 19:20:18 +03:00
|
|
|
if (acc->_settingsMap.contains(httpUserC)) {
|
2015-04-24 11:18:33 +03:00
|
|
|
settings.setValue(userC, acc->_settingsMap.value(httpUserC));
|
2023-08-15 19:20:18 +03:00
|
|
|
}
|
2015-04-09 17:19:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Save accepted certificates.
|
2022-10-10 13:02:22 +03:00
|
|
|
settings.beginGroup(QLatin1String(generalC));
|
2017-03-30 14:46:20 +03:00
|
|
|
qCInfo(lcAccountManager) << "Saving " << acc->approvedCerts().count() << " unknown certs.";
|
2015-04-09 17:19:17 +03:00
|
|
|
QByteArray certs;
|
2022-10-24 18:53:40 +03:00
|
|
|
const auto approvedCerts = acc->approvedCerts();
|
|
|
|
for (const auto &cert : approvedCerts) {
|
2015-04-09 17:19:17 +03:00
|
|
|
certs += cert.toPem() + '\n';
|
|
|
|
}
|
|
|
|
if (!certs.isEmpty()) {
|
2015-04-24 11:18:33 +03:00
|
|
|
settings.setValue(QLatin1String(caCertsKeyC), certs);
|
2015-04-09 17:19:17 +03:00
|
|
|
}
|
2015-04-24 11:18:33 +03:00
|
|
|
settings.endGroup();
|
2015-04-09 17:19:17 +03:00
|
|
|
|
|
|
|
// Save cookies.
|
|
|
|
if (acc->_am) {
|
2020-05-18 21:54:23 +03:00
|
|
|
auto *jar = qobject_cast<CookieJar *>(acc->_am->cookieJar());
|
2015-04-09 17:19:17 +03:00
|
|
|
if (jar) {
|
2017-03-30 14:46:20 +03:00
|
|
|
qCInfo(lcAccountManager) << "Saving cookies." << acc->cookieJarPath();
|
2020-01-24 19:57:34 +03:00
|
|
|
if (!jar->save(acc->cookieJarPath()))
|
|
|
|
{
|
|
|
|
qCWarning(lcAccountManager) << "Failed to save cookies to" << acc->cookieJarPath();
|
|
|
|
}
|
2015-04-09 17:19:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-01 18:08:23 +03:00
|
|
|
AccountPtr AccountManager::loadAccountHelper(QSettings &settings)
|
2015-04-23 16:42:18 +03:00
|
|
|
{
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto urlConfig = settings.value(QLatin1String(urlC));
|
2016-10-11 12:46:51 +03:00
|
|
|
if (!urlConfig.isValid()) {
|
|
|
|
// No URL probably means a corrupted entry in the account settings
|
2017-03-30 14:46:20 +03:00
|
|
|
qCWarning(lcAccountManager) << "No URL for account " << settings.group();
|
2016-10-11 12:46:51 +03:00
|
|
|
return AccountPtr();
|
|
|
|
}
|
|
|
|
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto acc = createAccount();
|
2015-04-23 16:42:18 +03:00
|
|
|
|
2022-10-10 13:02:22 +03:00
|
|
|
auto authType = settings.value(QLatin1String(authTypeC)).toString();
|
2017-01-03 12:37:42 +03:00
|
|
|
|
|
|
|
// There was an account-type saving bug when 'skip folder config' was used
|
2023-08-15 19:20:18 +03:00
|
|
|
// See owncloud#5408. This attempts to fix up the "dummy" or empty authType
|
|
|
|
if (authType == QLatin1String(dummyAuthTypeC) || authType.isEmpty()) {
|
2022-10-10 13:02:22 +03:00
|
|
|
if (settings.contains(QLatin1String(httpUserC))) {
|
|
|
|
authType = httpAuthTypeC;
|
|
|
|
} else if (settings.contains(QLatin1String(shibbolethUserC))) {
|
|
|
|
authType = shibbolethAuthTypeC;
|
2023-04-30 18:14:07 +03:00
|
|
|
} else if (settings.contains(webflowUserC)) {
|
|
|
|
authType = webflowAuthTypeC;
|
2017-01-03 12:37:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto overrideUrl = Theme::instance()->overrideServerUrl();
|
|
|
|
const auto forceAuth = Theme::instance()->forceConfigAuthType();
|
2016-06-28 15:27:00 +03:00
|
|
|
if (!forceAuth.isEmpty() && !overrideUrl.isEmpty()) {
|
|
|
|
// If forceAuth is set, this might also mean the overrideURL has changed.
|
|
|
|
// See enterprise issues #1126
|
2016-04-15 14:16:49 +03:00
|
|
|
acc->setUrl(overrideUrl);
|
2016-06-28 15:27:00 +03:00
|
|
|
authType = forceAuth;
|
2016-04-15 14:16:49 +03:00
|
|
|
} else {
|
2016-10-11 12:46:51 +03:00
|
|
|
acc->setUrl(urlConfig.toUrl());
|
2016-04-15 14:16:49 +03:00
|
|
|
}
|
2017-01-11 11:30:59 +03:00
|
|
|
|
2018-11-02 11:49:43 +03:00
|
|
|
// Migrate to webflow
|
2022-10-10 13:02:22 +03:00
|
|
|
if (authType == QLatin1String(httpAuthTypeC)) {
|
|
|
|
authType = webflowAuthTypeC;
|
2023-08-15 19:20:18 +03:00
|
|
|
acc->_settingsMap.insert(QLatin1String(authTypeC), authType);
|
2018-11-02 11:49:43 +03:00
|
|
|
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto settingsChildKeys = settings.childKeys();
|
|
|
|
for (const auto &key : settingsChildKeys) {
|
2023-08-15 19:20:18 +03:00
|
|
|
if (!key.startsWith(httpAuthPrefix)) {
|
2018-11-02 11:49:43 +03:00
|
|
|
continue;
|
2023-08-15 19:20:18 +03:00
|
|
|
}
|
|
|
|
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto newkey = QString::fromLatin1(webflowAuthPrefix).append(key.mid(5));
|
2023-08-15 19:20:18 +03:00
|
|
|
acc->_settingsMap.insert(newkey, settings.value(key));
|
2018-11-02 11:49:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-30 14:46:20 +03:00
|
|
|
qCInfo(lcAccountManager) << "Account for" << acc->url() << "using auth type" << authType;
|
2017-01-11 11:30:59 +03:00
|
|
|
|
2016-03-02 13:59:36 +03:00
|
|
|
acc->_serverVersion = settings.value(QLatin1String(serverVersionC)).toString();
|
2023-08-01 11:00:39 +03:00
|
|
|
acc->_serverColor = settings.value(QLatin1String(serverColorC)).value<QColor>();
|
|
|
|
acc->_serverTextColor = settings.value(QLatin1String(serverTextColorC)).value<QColor>();
|
2023-05-05 17:15:09 +03:00
|
|
|
acc->_skipE2eeMetadataChecksumValidation = settings.value(QLatin1String(skipE2eeMetadataChecksumValidationC), {}).toBool();
|
2023-08-15 19:20:18 +03:00
|
|
|
acc->_davUser = settings.value(QLatin1String(davUserC)).toString();
|
2015-04-23 16:42:18 +03:00
|
|
|
|
2015-04-24 11:18:33 +03:00
|
|
|
acc->_settingsMap.insert(QLatin1String(userC), settings.value(userC));
|
2022-10-06 20:44:51 +03:00
|
|
|
acc->_displayName = settings.value(QLatin1String(displayNameC), "").toString();
|
2023-08-15 19:20:18 +03:00
|
|
|
const QString authTypePrefix = authType + "_";
|
2022-10-24 18:53:40 +03:00
|
|
|
const auto settingsChildKeys = settings.childKeys();
|
|
|
|
for (const auto &key : settingsChildKeys) {
|
2023-08-15 19:20:18 +03:00
|
|
|
if (!key.startsWith(authTypePrefix)) {
|
2015-04-23 16:42:18 +03:00
|
|
|
continue;
|
2023-08-15 19:20:18 +03:00
|
|
|
}
|
2015-04-24 11:18:33 +03:00
|
|
|
acc->_settingsMap.insert(key, settings.value(key));
|
2015-04-23 16:42:18 +03:00
|
|
|
}
|
|
|
|
|
2016-04-15 14:16:49 +03:00
|
|
|
acc->setCredentials(CredentialsFactory::create(authType));
|
2015-04-23 16:42:18 +03:00
|
|
|
|
2017-01-02 10:34:02 +03:00
|
|
|
// now the server cert, it is in the general group
|
2022-10-10 13:02:22 +03:00
|
|
|
settings.beginGroup(QLatin1String(generalC));
|
2020-02-10 15:08:19 +03:00
|
|
|
const auto certs = QSslCertificate::fromData(settings.value(caCertsKeyC).toByteArray());
|
|
|
|
qCInfo(lcAccountManager) << "Restored: " << certs.count() << " unknown certs.";
|
|
|
|
acc->setApprovedCerts(certs);
|
2015-04-24 11:18:33 +03:00
|
|
|
settings.endGroup();
|
|
|
|
|
2015-04-23 16:42:18 +03:00
|
|
|
return acc;
|
|
|
|
}
|
|
|
|
|
2015-11-12 19:50:00 +03:00
|
|
|
AccountStatePtr AccountManager::account(const QString &name)
|
|
|
|
{
|
2020-09-27 14:02:27 +03:00
|
|
|
const auto it = std::find_if(_accounts.cbegin(), _accounts.cend(), [name](const auto &acc) {
|
|
|
|
return acc->account()->displayName() == name;
|
|
|
|
});
|
|
|
|
return it != _accounts.cend() ? *it : AccountStatePtr();
|
2015-11-12 19:50:00 +03:00
|
|
|
}
|
|
|
|
|
2022-10-26 20:10:21 +03:00
|
|
|
AccountStatePtr AccountManager::accountFromUserId(const QString &id) const
|
|
|
|
{
|
2022-10-24 18:53:40 +03:00
|
|
|
const auto accountsList = accounts();
|
|
|
|
for (const auto &account : accountsList) {
|
2022-10-26 20:10:21 +03:00
|
|
|
const auto isUserIdWithPort = id.split(QLatin1Char(':')).size() > 1;
|
|
|
|
const auto port = isUserIdWithPort ? account->account()->url().port() : -1;
|
|
|
|
const auto portString = (port > 0 && port != 80 && port != 443) ? QStringLiteral(":%1").arg(port) : QStringLiteral("");
|
|
|
|
const QString davUserId = QStringLiteral("%1@%2").arg(account->account()->davUser(), account->account()->url().host()) + portString;
|
|
|
|
|
|
|
|
if (davUserId == id) {
|
|
|
|
return account;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2015-04-27 18:43:07 +03:00
|
|
|
AccountState *AccountManager::addAccount(const AccountPtr &newAccount)
|
2015-04-17 18:56:17 +03:00
|
|
|
{
|
2015-04-24 08:02:51 +03:00
|
|
|
auto id = newAccount->id();
|
|
|
|
if (id.isEmpty() || !isAccountIdAvailable(id)) {
|
|
|
|
id = generateFreeAccountId();
|
|
|
|
}
|
|
|
|
newAccount->_id = id;
|
|
|
|
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto newAccountState = new AccountState(newAccount);
|
2016-03-01 18:08:23 +03:00
|
|
|
addAccountState(newAccountState);
|
|
|
|
return newAccountState;
|
2015-04-17 18:56:17 +03:00
|
|
|
}
|
|
|
|
|
2015-05-12 16:16:32 +03:00
|
|
|
void AccountManager::deleteAccount(AccountState *account)
|
|
|
|
{
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto it = std::find(_accounts.begin(), _accounts.end(), account);
|
2015-05-12 16:16:32 +03:00
|
|
|
if (it == _accounts.end()) {
|
|
|
|
return;
|
|
|
|
}
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto copy = *it; // keep a reference to the shared pointer so it does not delete it just yet
|
2015-05-12 16:16:32 +03:00
|
|
|
_accounts.erase(it);
|
2015-05-12 16:37:16 +03:00
|
|
|
|
2017-05-22 10:32:11 +03:00
|
|
|
// Forget account credentials, cookies
|
|
|
|
account->account()->credentials()->forgetSensitiveData();
|
2017-01-26 12:54:03 +03:00
|
|
|
QFile::remove(account->account()->cookieJarPath());
|
|
|
|
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
|
2015-05-12 16:37:16 +03:00
|
|
|
settings->remove(account->account()->id());
|
|
|
|
|
2017-12-20 17:35:23 +03:00
|
|
|
// Forget E2E keys
|
2021-01-19 17:09:38 +03:00
|
|
|
account->account()->e2e()->forgetSensitiveData(account->account());
|
2017-12-20 17:35:23 +03:00
|
|
|
|
2021-07-28 16:52:56 +03:00
|
|
|
account->account()->deleteAppToken();
|
|
|
|
|
2021-03-09 12:56:17 +03:00
|
|
|
emit accountSyncConnectionRemoved(account);
|
2015-07-03 12:13:19 +03:00
|
|
|
emit accountRemoved(account);
|
2015-05-12 16:16:32 +03:00
|
|
|
}
|
|
|
|
|
2015-07-16 15:21:51 +03:00
|
|
|
AccountPtr AccountManager::createAccount()
|
|
|
|
{
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto acc = Account::create();
|
2015-07-16 15:21:51 +03:00
|
|
|
acc->setSslErrorHandler(new SslDialogErrorHandler);
|
2017-09-20 11:14:48 +03:00
|
|
|
connect(acc.data(), &Account::proxyAuthenticationRequired,
|
|
|
|
ProxyAuthHandler::instance(), &ProxyAuthHandler::handleProxyAuthenticationRequired);
|
2022-04-20 14:44:19 +03:00
|
|
|
connect(acc.data(), &Account::lockFileError,
|
|
|
|
Systray::instance(), &Systray::showErrorMessageDialog);
|
2018-01-21 21:50:40 +03:00
|
|
|
|
2015-07-16 15:21:51 +03:00
|
|
|
return acc;
|
|
|
|
}
|
|
|
|
|
2015-04-17 18:56:17 +03:00
|
|
|
void AccountManager::shutdown()
|
|
|
|
{
|
2020-09-27 14:02:27 +03:00
|
|
|
const auto accountsCopy = _accounts;
|
2015-04-17 18:56:17 +03:00
|
|
|
_accounts.clear();
|
2020-09-27 14:02:27 +03:00
|
|
|
for (const auto &acc : accountsCopy) {
|
2015-04-17 18:56:17 +03:00
|
|
|
emit accountRemoved(acc.data());
|
2019-07-24 14:56:21 +03:00
|
|
|
emit removeAccountFolders(acc.data());
|
2015-04-17 18:56:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-18 17:12:35 +03:00
|
|
|
QList<AccountStatePtr> AccountManager::accounts() const
|
|
|
|
{
|
|
|
|
return _accounts;
|
|
|
|
}
|
|
|
|
|
2015-04-24 08:02:51 +03:00
|
|
|
bool AccountManager::isAccountIdAvailable(const QString &id) const
|
|
|
|
{
|
2018-05-14 15:37:48 +03:00
|
|
|
if (_additionalBlockedAccountIds.contains(id))
|
|
|
|
return false;
|
|
|
|
|
2020-09-29 20:23:06 +03:00
|
|
|
return std::none_of(_accounts.cbegin(), _accounts.cend(), [id](const auto &acc) {
|
2020-09-27 14:02:27 +03:00
|
|
|
return acc->account()->id() == id;
|
|
|
|
});
|
2015-04-24 08:02:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
QString AccountManager::generateFreeAccountId() const
|
|
|
|
{
|
2022-10-10 13:02:22 +03:00
|
|
|
auto i = 0;
|
2015-04-24 08:02:51 +03:00
|
|
|
forever {
|
2022-10-10 13:02:22 +03:00
|
|
|
const auto id = QString::number(i);
|
2015-04-24 08:02:51 +03:00
|
|
|
if (isAccountIdAvailable(id)) {
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
2015-04-09 17:19:17 +03:00
|
|
|
|
2016-03-01 18:08:23 +03:00
|
|
|
void AccountManager::addAccountState(AccountState *accountState)
|
|
|
|
{
|
|
|
|
QObject::connect(accountState->account().data(),
|
2017-09-20 11:14:48 +03:00
|
|
|
&Account::wantsAccountSaved,
|
|
|
|
this, &AccountManager::saveAccount);
|
2016-03-01 18:08:23 +03:00
|
|
|
|
|
|
|
AccountStatePtr ptr(accountState);
|
|
|
|
_accounts << ptr;
|
2023-03-03 19:50:27 +03:00
|
|
|
ptr->trySignIn();
|
2016-03-01 18:08:23 +03:00
|
|
|
emit accountAdded(accountState);
|
|
|
|
}
|
2023-05-05 05:44:10 +03:00
|
|
|
|
|
|
|
bool AccountManager::forceLegacyImport() const
|
|
|
|
{
|
|
|
|
return _forceLegacyImport;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AccountManager::setForceLegacyImport(const bool forceLegacyImport)
|
|
|
|
{
|
|
|
|
if (_forceLegacyImport == forceLegacyImport) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_forceLegacyImport = forceLegacyImport;
|
|
|
|
Q_EMIT forceLegacyImportChanged();
|
|
|
|
}
|
2015-04-23 15:47:31 +03:00
|
|
|
}
|