Merge pull request #5026 from nextcloud/bugfix/modernise-account-code

Modernise and improve code in AccountManager
This commit is contained in:
Claudio Cambra 2022-10-26 19:11:33 +02:00 committed by GitHub
commit 2abbe5c251
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -35,14 +35,26 @@ constexpr auto userC = "user";
constexpr auto displayNameC = "displayName"; constexpr auto displayNameC = "displayName";
constexpr auto httpUserC = "http_user"; constexpr auto httpUserC = "http_user";
constexpr auto davUserC = "dav_user"; constexpr auto davUserC = "dav_user";
constexpr auto shibbolethUserC = "shibboleth_shib_user";
constexpr auto caCertsKeyC = "CaCertificates"; constexpr auto caCertsKeyC = "CaCertificates";
constexpr auto accountsC = "Accounts"; constexpr auto accountsC = "Accounts";
constexpr auto versionC = "version"; constexpr auto versionC = "version";
constexpr auto serverVersionC = "serverVersion"; constexpr auto serverVersionC = "serverVersion";
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";
constexpr auto legacyOcSettingsC = "ownCloud";
// The maximum versions that this client can read // The maximum versions that this client can read
static const int maxAccountsVersion = 2; constexpr auto maxAccountsVersion = 2;
static const int maxAccountVersion = 1; constexpr auto maxAccountVersion = 1;
} }
@ -61,7 +73,7 @@ bool AccountManager::restore()
QStringList skipSettingsKeys; QStringList skipSettingsKeys;
backwardMigrationSettingsKeys(&skipSettingsKeys, &skipSettingsKeys); backwardMigrationSettingsKeys(&skipSettingsKeys, &skipSettingsKeys);
auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC)); const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
if (settings->status() != QSettings::NoError || !settings->isWritable()) { if (settings->status() != QSettings::NoError || !settings->isWritable()) {
qCWarning(lcAccountManager) << "Could not read settings from" << settings->fileName() qCWarning(lcAccountManager) << "Could not read settings from" << settings->fileName()
<< settings->status(); << settings->status();
@ -84,7 +96,7 @@ bool AccountManager::restore()
for (const auto &accountId : settings->childGroups()) { for (const auto &accountId : settings->childGroups()) {
settings->beginGroup(accountId); settings->beginGroup(accountId);
if (!skipSettingsKeys.contains(settings->group())) { if (!skipSettingsKeys.contains(settings->group())) {
if (auto acc = loadAccountHelper(*settings)) { if (const auto acc = loadAccountHelper(*settings)) {
acc->_id = accountId; acc->_id = accountId;
if (auto accState = AccountState::loadFromSettings(acc, *settings)) { if (auto accState = AccountState::loadFromSettings(acc, *settings)) {
auto jar = qobject_cast<CookieJar*>(acc->_am->cookieJar()); auto jar = qobject_cast<CookieJar*>(acc->_am->cookieJar());
@ -106,12 +118,14 @@ bool AccountManager::restore()
void AccountManager::backwardMigrationSettingsKeys(QStringList *deleteKeys, QStringList *ignoreKeys) void AccountManager::backwardMigrationSettingsKeys(QStringList *deleteKeys, QStringList *ignoreKeys)
{ {
auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC)); const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
const int accountsVersion = settings->value(QLatin1String(versionC)).toInt(); const auto accountsVersion = settings->value(QLatin1String(versionC)).toInt();
if (accountsVersion <= maxAccountsVersion) { if (accountsVersion <= maxAccountsVersion) {
foreach (const auto &accountId, settings->childGroups()) { for (const auto &accountId : settings->childGroups()) {
settings->beginGroup(accountId); settings->beginGroup(accountId);
const int accountVersion = settings->value(QLatin1String(versionC), 1).toInt(); const auto accountVersion = settings->value(QLatin1String(versionC), 1).toInt();
if (accountVersion > maxAccountVersion) { if (accountVersion > maxAccountVersion) {
ignoreKeys->append(settings->group()); ignoreKeys->append(settings->group());
} }
@ -134,26 +148,26 @@ bool AccountManager::restoreFromLegacySettings()
// then try to load settings from a very old place // then try to load settings from a very old place
if (settings->childKeys().isEmpty()) { if (settings->childKeys().isEmpty()) {
// Now try to open the original ownCloud settings to see if they exist. // Now try to open the original ownCloud settings to see if they exist.
QString oCCfgFile = QDir::fromNativeSeparators(settings->fileName()); auto oCCfgFile = QDir::fromNativeSeparators(settings->fileName());
// replace the last two segments with ownCloud/owncloud.cfg // replace the last two segments with ownCloud/owncloud.cfg
oCCfgFile = oCCfgFile.left(oCCfgFile.lastIndexOf('/')); oCCfgFile = oCCfgFile.left(oCCfgFile.lastIndexOf('/'));
oCCfgFile = oCCfgFile.left(oCCfgFile.lastIndexOf('/')); oCCfgFile = oCCfgFile.left(oCCfgFile.lastIndexOf('/'));
oCCfgFile += QLatin1String("/ownCloud/owncloud.cfg"); oCCfgFile += QLatin1String(legacyRelativeConfigLocationC);
qCInfo(lcAccountManager) << "Migrate: checking old config " << oCCfgFile; qCInfo(lcAccountManager) << "Migrate: checking old config " << oCCfgFile;
QFileInfo fi(oCCfgFile); QFileInfo fi(oCCfgFile);
if (fi.isReadable()) { if (fi.isReadable()) {
std::unique_ptr<QSettings> oCSettings(new QSettings(oCCfgFile, QSettings::IniFormat)); std::unique_ptr<QSettings> oCSettings(new QSettings(oCCfgFile, QSettings::IniFormat));
oCSettings->beginGroup(QLatin1String("ownCloud")); oCSettings->beginGroup(QLatin1String(legacyOcSettingsC));
// Check the theme url to see if it is the same url that the oC config was for // Check the theme url to see if it is the same url that the oC config was for
QString overrideUrl = Theme::instance()->overrideServerUrl(); auto overrideUrl = Theme::instance()->overrideServerUrl();
if (!overrideUrl.isEmpty()) { if (!overrideUrl.isEmpty()) {
if (overrideUrl.endsWith('/')) { if (overrideUrl.endsWith('/')) {
overrideUrl.chop(1); overrideUrl.chop(1);
} }
QString oCUrl = oCSettings->value(QLatin1String(urlC)).toString(); auto oCUrl = oCSettings->value(QLatin1String(urlC)).toString();
if (oCUrl.endsWith('/')) { if (oCUrl.endsWith('/')) {
oCUrl.chop(1); oCUrl.chop(1);
} }
@ -171,7 +185,7 @@ bool AccountManager::restoreFromLegacySettings()
// Try to load the single account. // Try to load the single account.
if (!settings->childKeys().isEmpty()) { if (!settings->childKeys().isEmpty()) {
if (auto acc = loadAccountHelper(*settings)) { if (const auto acc = loadAccountHelper(*settings)) {
addAccount(acc); addAccount(acc);
return true; return true;
} }
@ -181,7 +195,7 @@ bool AccountManager::restoreFromLegacySettings()
void AccountManager::save(bool saveCredentials) void AccountManager::save(bool saveCredentials)
{ {
auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC)); const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
settings->setValue(QLatin1String(versionC), maxAccountsVersion); settings->setValue(QLatin1String(versionC), maxAccountsVersion);
for (const auto &acc : qAsConst(_accounts)) { for (const auto &acc : qAsConst(_accounts)) {
settings->beginGroup(acc->account()->id()); settings->beginGroup(acc->account()->id());
@ -197,7 +211,7 @@ void AccountManager::save(bool saveCredentials)
void AccountManager::saveAccount(Account *a) void AccountManager::saveAccount(Account *a)
{ {
qCDebug(lcAccountManager) << "Saving account" << a->url().toString(); qCDebug(lcAccountManager) << "Saving account" << a->url().toString();
auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC)); const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
settings->beginGroup(a->id()); settings->beginGroup(a->id());
saveAccountHelper(a, *settings, false); // don't save credentials they might not have been loaded yet saveAccountHelper(a, *settings, false); // don't save credentials they might not have been loaded yet
settings->endGroup(); settings->endGroup();
@ -209,7 +223,7 @@ void AccountManager::saveAccount(Account *a)
void AccountManager::saveAccountState(AccountState *a) void AccountManager::saveAccountState(AccountState *a)
{ {
qCDebug(lcAccountManager) << "Saving account state" << a->account()->url().toString(); qCDebug(lcAccountManager) << "Saving account state" << a->account()->url().toString();
auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC)); const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
settings->beginGroup(a->account()->id()); settings->beginGroup(a->account()->id());
a->writeToSettings(*settings); a->writeToSettings(*settings);
settings->endGroup(); settings->endGroup();
@ -234,7 +248,9 @@ void AccountManager::saveAccountHelper(Account *acc, QSettings &settings, bool s
// re-persisting them) // re-persisting them)
acc->_credentials->persist(); acc->_credentials->persist();
} }
for (const auto &key : acc->_settingsMap.keys()) {
const auto settingsMapKeys = acc->_settingsMap.keys();
for (const auto &key : settingsMapKeys) {
settings.setValue(key, acc->_settingsMap.value(key)); settings.setValue(key, acc->_settingsMap.value(key));
} }
settings.setValue(QLatin1String(authTypeC), acc->_credentials->authType()); settings.setValue(QLatin1String(authTypeC), acc->_credentials->authType());
@ -245,7 +261,7 @@ void AccountManager::saveAccountHelper(Account *acc, QSettings &settings, bool s
} }
// Save accepted certificates. // Save accepted certificates.
settings.beginGroup(QLatin1String("General")); settings.beginGroup(QLatin1String(generalC));
qCInfo(lcAccountManager) << "Saving " << acc->approvedCerts().count() << " unknown certs."; qCInfo(lcAccountManager) << "Saving " << acc->approvedCerts().count() << " unknown certs.";
QByteArray certs; QByteArray certs;
for (const auto &cert : acc->approvedCerts()) { for (const auto &cert : acc->approvedCerts()) {
@ -271,29 +287,29 @@ void AccountManager::saveAccountHelper(Account *acc, QSettings &settings, bool s
AccountPtr AccountManager::loadAccountHelper(QSettings &settings) AccountPtr AccountManager::loadAccountHelper(QSettings &settings)
{ {
auto urlConfig = settings.value(QLatin1String(urlC)); const auto urlConfig = settings.value(QLatin1String(urlC));
if (!urlConfig.isValid()) { if (!urlConfig.isValid()) {
// No URL probably means a corrupted entry in the account settings // No URL probably means a corrupted entry in the account settings
qCWarning(lcAccountManager) << "No URL for account " << settings.group(); qCWarning(lcAccountManager) << "No URL for account " << settings.group();
return AccountPtr(); return AccountPtr();
} }
auto acc = createAccount(); const auto acc = createAccount();
QString authType = settings.value(QLatin1String(authTypeC)).toString(); auto authType = settings.value(QLatin1String(authTypeC)).toString();
// There was an account-type saving bug when 'skip folder config' was used // There was an account-type saving bug when 'skip folder config' was used
// See #5408. This attempts to fix up the "dummy" authType // See #5408. This attempts to fix up the "dummy" authType
if (authType == QLatin1String("dummy")) { if (authType == QLatin1String(dummyAuthTypeC)) {
if (settings.contains(QLatin1String("http_user"))) { if (settings.contains(QLatin1String(httpUserC))) {
authType = "http"; authType = httpAuthTypeC;
} else if (settings.contains(QLatin1String("shibboleth_shib_user"))) { } else if (settings.contains(QLatin1String(shibbolethUserC))) {
authType = "shibboleth"; authType = shibbolethAuthTypeC;
} }
} }
QString overrideUrl = Theme::instance()->overrideServerUrl(); const auto overrideUrl = Theme::instance()->overrideServerUrl();
QString forceAuth = Theme::instance()->forceConfigAuthType(); const auto forceAuth = Theme::instance()->forceConfigAuthType();
if (!forceAuth.isEmpty() && !overrideUrl.isEmpty()) { if (!forceAuth.isEmpty() && !overrideUrl.isEmpty()) {
// If forceAuth is set, this might also mean the overrideURL has changed. // If forceAuth is set, this might also mean the overrideURL has changed.
// See enterprise issues #1126 // See enterprise issues #1126
@ -304,14 +320,15 @@ AccountPtr AccountManager::loadAccountHelper(QSettings &settings)
} }
// Migrate to webflow // Migrate to webflow
if (authType == QLatin1String("http")) { if (authType == QLatin1String(httpAuthTypeC)) {
authType = "webflow"; authType = webflowAuthTypeC;
settings.setValue(QLatin1String(authTypeC), authType); settings.setValue(QLatin1String(authTypeC), authType);
for (const QString &key : settings.childKeys()) { const auto settingsChildKeys = settings.childKeys();
if (!key.startsWith("http_")) for (const auto &key : settingsChildKeys) {
if (!key.startsWith(httpAuthPrefix))
continue; continue;
auto newkey = QString::fromLatin1("webflow_").append(key.mid(5)); const auto newkey = QString::fromLatin1(webflowAuthPrefix).append(key.mid(5));
settings.setValue(newkey, settings.value((key))); settings.setValue(newkey, settings.value((key)));
settings.remove(key); settings.remove(key);
} }
@ -335,7 +352,7 @@ AccountPtr AccountManager::loadAccountHelper(QSettings &settings)
acc->setCredentials(CredentialsFactory::create(authType)); acc->setCredentials(CredentialsFactory::create(authType));
// now the server cert, it is in the general group // now the server cert, it is in the general group
settings.beginGroup(QLatin1String("General")); settings.beginGroup(QLatin1String(generalC));
const auto certs = QSslCertificate::fromData(settings.value(caCertsKeyC).toByteArray()); const auto certs = QSslCertificate::fromData(settings.value(caCertsKeyC).toByteArray());
qCInfo(lcAccountManager) << "Restored: " << certs.count() << " unknown certs."; qCInfo(lcAccountManager) << "Restored: " << certs.count() << " unknown certs.";
acc->setApprovedCerts(certs); acc->setApprovedCerts(certs);
@ -360,25 +377,25 @@ AccountState *AccountManager::addAccount(const AccountPtr &newAccount)
} }
newAccount->_id = id; newAccount->_id = id;
auto newAccountState = new AccountState(newAccount); const auto newAccountState = new AccountState(newAccount);
addAccountState(newAccountState); addAccountState(newAccountState);
return newAccountState; return newAccountState;
} }
void AccountManager::deleteAccount(AccountState *account) void AccountManager::deleteAccount(AccountState *account)
{ {
auto it = std::find(_accounts.begin(), _accounts.end(), account); const auto it = std::find(_accounts.begin(), _accounts.end(), account);
if (it == _accounts.end()) { if (it == _accounts.end()) {
return; return;
} }
auto copy = *it; // keep a reference to the shared pointer so it does not delete it just yet const auto copy = *it; // keep a reference to the shared pointer so it does not delete it just yet
_accounts.erase(it); _accounts.erase(it);
// Forget account credentials, cookies // Forget account credentials, cookies
account->account()->credentials()->forgetSensitiveData(); account->account()->credentials()->forgetSensitiveData();
QFile::remove(account->account()->cookieJarPath()); QFile::remove(account->account()->cookieJarPath());
auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC)); const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
settings->remove(account->account()->id()); settings->remove(account->account()->id());
// Forget E2E keys // Forget E2E keys
@ -392,7 +409,7 @@ void AccountManager::deleteAccount(AccountState *account)
AccountPtr AccountManager::createAccount() AccountPtr AccountManager::createAccount()
{ {
AccountPtr acc = Account::create(); const auto acc = Account::create();
acc->setSslErrorHandler(new SslDialogErrorHandler); acc->setSslErrorHandler(new SslDialogErrorHandler);
connect(acc.data(), &Account::proxyAuthenticationRequired, connect(acc.data(), &Account::proxyAuthenticationRequired,
ProxyAuthHandler::instance(), &ProxyAuthHandler::handleProxyAuthenticationRequired); ProxyAuthHandler::instance(), &ProxyAuthHandler::handleProxyAuthenticationRequired);
@ -404,7 +421,7 @@ AccountPtr AccountManager::createAccount()
void AccountManager::displayMnemonic(const QString& mnemonic) void AccountManager::displayMnemonic(const QString& mnemonic)
{ {
auto *widget = new QDialog; const auto widget = new QDialog;
Ui_Dialog ui; Ui_Dialog ui;
ui.setupUi(widget); ui.setupUi(widget);
widget->setWindowTitle(tr("End-to-End encryption mnemonic")); widget->setWindowTitle(tr("End-to-End encryption mnemonic"));
@ -446,9 +463,9 @@ bool AccountManager::isAccountIdAvailable(const QString &id) const
QString AccountManager::generateFreeAccountId() const QString AccountManager::generateFreeAccountId() const
{ {
int i = 0; auto i = 0;
forever { forever {
QString id = QString::number(i); const auto id = QString::number(i);
if (isAccountIdAvailable(id)) { if (isAccountIdAvailable(id)) {
return id; return id;
} }