--- /dev/null
+/*
+ * Copyright (C) by Michael Schuster <michael@nextcloud.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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 "account.h"
+#include "keychainchunk.h"
+#include "theme.h"
+#include "networkjobs.h"
+#include "configfile.h"
+#include "creds/abstractcredentials.h"
+
+using namespace QKeychain;
+
+namespace OCC {
+
+Q_LOGGING_CATEGORY(lcKeychainChunk, "nextcloud.sync.credentials.keychainchunk", QtInfoMsg)
+
+namespace KeychainChunk {
+
+#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
+static void addSettingsToJob(Account *account, QKeychain::Job *job)
+{
+ Q_UNUSED(account)
+ auto settings = ConfigFile::settingsWithGroup(Theme::instance()->appName());
+ settings->setParent(job); // make the job parent to make setting deleted properly
+ job->setSettings(settings.release());
+}
+#endif
+
+/*
+* Job
+*/
+Job::Job(QObject *parent)
+ : QObject(parent)
+{
+ _serviceName = Theme::instance()->appName();
+}
+
+/*
+* WriteJob
+*/
+WriteJob::WriteJob(Account *account, const QString &key, const QByteArray &data, QObject *parent)
+ : Job(parent)
+{
+ _account = account;
+ _key = key;
+
+ // Windows workaround: Split the private key into chunks of 2048 bytes,
+ // to allow 4k (4096 bit) keys to be saved (obey Windows's limits)
+ _chunkBuffer = data;
+ _chunkCount = 0;
+}
+
+void WriteJob::start()
+{
+ slotWriteJobDone(nullptr);
+}
+
+void WriteJob::slotWriteJobDone(QKeychain::Job *incomingJob)
+{
+ QKeychain::WritePasswordJob *writeJob = static_cast<QKeychain::WritePasswordJob *>(incomingJob);
+
+ // errors?
+ if (writeJob) {
+ _error = writeJob->error();
+ _errorString = writeJob->errorString();
+
+ if (writeJob->error() != NoError) {
+ qCWarning(lcKeychainChunk) << "Error while writing" << writeJob->key() << "chunk" << writeJob->errorString();
+ _chunkBuffer.clear();
+ }
+ }
+
+ // write a chunk if there is any in the buffer
+ if (!_chunkBuffer.isEmpty()) {
+#if defined(Q_OS_WIN)
+ // Windows workaround: Split the data into chunks of 2048 bytes,
+ // to allow 4k (4096 bit) keys to be saved (obey Windows's limits)
+ auto chunk = _chunkBuffer.left(KeychainChunk::ChunkSize);
+
+ _chunkBuffer = _chunkBuffer.right(_chunkBuffer.size() - chunk.size());
+#else
+ // write full data in one chunk on non-Windows, as usual
+ auto chunk = _chunkBuffer;
+
+ _chunkBuffer.clear();
+#endif
+ auto index = (_chunkCount++);
+
+ // keep the limit
+ if (_chunkCount > KeychainChunk::MaxChunks) {
+ qCWarning(lcKeychainChunk) << "Maximum chunk count exceeded while writing" << writeJob->key() << "chunk" << QString::number(index) << "cutting off after" << QString::number(KeychainChunk::MaxChunks) << "chunks";
+
+ writeJob->deleteLater();
+
+ _chunkBuffer.clear();
+
+ emit finished(this);
+ return;
+ }
+
+ const QString kck = AbstractCredentials::keychainKey(
+ _account->url().toString(),
+ _key + (index > 0 ? (QString(".") + QString::number(index)) : QString()),
+ _account->id());
+
+ QKeychain::WritePasswordJob *job = new QKeychain::WritePasswordJob(_serviceName);
+#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
+ addSettingsToJob(_account, job);
+#endif
+ job->setInsecureFallback(_insecureFallback);
+ connect(job, &QKeychain::Job::finished, this, &KeychainChunk::WriteJob::slotWriteJobDone);
+ // only add the key's (sub)"index" after the first element, to stay compatible with older versions and non-Windows
+ job->setKey(kck);
+ job->setBinaryData(chunk);
+ job->start();
+
+ chunk.clear();
+ } else {
+ emit finished(this);
+ }
+
+ writeJob->deleteLater();
+}
+
+/*
+* ReadJob
+*/
+ReadJob::ReadJob(Account *account, const QString &key, const bool &keychainMigration, QObject *parent)
+ : Job(parent)
+{
+ _account = account;
+ _key = key;
+
+ _keychainMigration = keychainMigration;
+
+ _chunkCount = 0;
+ _chunkBuffer.clear();
+}
+
+void ReadJob::start()
+{
+ _chunkCount = 0;
+ _chunkBuffer.clear();
+
+ const QString kck = AbstractCredentials::keychainKey(
+ _account->url().toString(),
+ _key,
+ _keychainMigration ? QString() : _account->id());
+
+ QKeychain::ReadPasswordJob *job = new QKeychain::ReadPasswordJob(_serviceName);
+#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
+ addSettingsToJob(_account, job);
+#endif
+ job->setInsecureFallback(_insecureFallback);
+ job->setKey(kck);
+ connect(job, &QKeychain::Job::finished, this, &KeychainChunk::ReadJob::slotReadJobDone);
+ job->start();
+}
+
+void ReadJob::slotReadJobDone(QKeychain::Job *incomingJob)
+{
+ // Errors or next chunk?
+ QKeychain::ReadPasswordJob *readJob = static_cast<QKeychain::ReadPasswordJob *>(incomingJob);
+
+ if (readJob) {
+ _error = readJob->error();
+ _errorString = readJob->errorString();
+
+ if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
+ _chunkBuffer.append(readJob->binaryData());
+ _chunkCount++;
+
+#if defined(Q_OS_WIN)
+ // try to fetch next chunk
+ if (_chunkCount < KeychainChunk::MaxChunks) {
+ const QString kck = AbstractCredentials::keychainKey(
+ _account->url().toString(),
+ _key + QString(".") + QString::number(_chunkCount),
+ _keychainMigration ? QString() : _account->id());
+
+ QKeychain::ReadPasswordJob *job = new QKeychain::ReadPasswordJob(_serviceName);
+#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
+ addSettingsToJob(_account, job);
+#endif
+ job->setInsecureFallback(_insecureFallback);
+ job->setKey(kck);
+ connect(job, &QKeychain::Job::finished, this, &KeychainChunk::ReadJob::slotReadJobDone);
+ job->start();
+
+ readJob->deleteLater();
+ return;
+ } else {
+ qCWarning(lcKeychainChunk) << "Maximum chunk count for" << readJob->key() << "reached, ignoring after" << KeychainChunk::MaxChunks;
+ }
+#endif
+ } else {
+ qCWarning(lcKeychainChunk) << "Unable to read" << readJob->key() << "chunk" << QString::number(_chunkCount) << readJob->errorString();
+ }
+
+ readJob->deleteLater();
+ }
+
+ emit finished(this);
+}
+
+} // namespace KeychainChunk
+
+} // namespace OCC
#include "theme.h"
#include "wizard/webview.h"
#include "webflowcredentialsdialog.h"
+#include "keychainchunk.h"
using namespace QKeychain;
QPointer<const WebFlowCredentials> _cred;
};
+#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
static void addSettingsToJob(Account *account, QKeychain::Job *job)
{
Q_UNUSED(account)
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
}
+#endif
WebFlowCredentials::WebFlowCredentials()
: _ready(false)
// write cert if there is one
if (!_clientSslCertificate.isNull()) {
- WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
- addSettingsToJob(_account, job);
- job->setInsecureFallback(false);
- connect(job, &Job::finished, this, &WebFlowCredentials::slotWriteClientCertPEMJobDone);
- job->setKey(keychainKey(_account->url().toString(), _user + clientCertificatePEMC, _account->id()));
- job->setBinaryData(_clientSslCertificate.toPem());
+ auto *job = new KeychainChunk::WriteJob(_account,
+ _user + clientCertificatePEMC,
+ _clientSslCertificate.toPem());
+ connect(job, &KeychainChunk::WriteJob::finished, this, &WebFlowCredentials::slotWriteClientCertPEMJobDone);
job->start();
} else {
// no cert, just write credentials
- slotWriteClientCertPEMJobDone();
+ slotWriteClientCertPEMJobDone(nullptr);
}
}
-void WebFlowCredentials::slotWriteClientCertPEMJobDone()
+void WebFlowCredentials::slotWriteClientCertPEMJobDone(KeychainChunk::WriteJob *writeJob)
{
+ if(writeJob)
+ writeJob->deleteLater();
+
// write ssl key if there is one
if (!_clientSslKey.isNull()) {
- // Windows workaround: Split the private key into chunks of 2048 bytes,
- // to allow 4k (4096 bit) keys to be saved (obey Windows's limits)
- _clientSslKeyChunkBufferPEM = _clientSslKey.toPem();
- _clientSslKeyChunkCount = 0;
-
- writeSingleClientKeyChunkPEM(nullptr);
- } else {
- // no key, just write credentials
- slotWriteClientKeyPEMJobDone();
- }
-}
-
-void WebFlowCredentials::writeSingleClientKeyChunkPEM(QKeychain::Job *incomingJob)
-{
- // errors?
- if (incomingJob) {
- WritePasswordJob *writeJob = static_cast<WritePasswordJob *>(incomingJob);
-
- if (writeJob->error() != NoError) {
- qCWarning(lcWebFlowCredentials) << "Error while writing client CA key chunk" << writeJob->errorString();
-
- _clientSslKeyChunkBufferPEM.clear();
- }
- }
-
- // write a key chunk if there is any in the buffer
- if (!_clientSslKeyChunkBufferPEM.isEmpty()) {
-#if defined(Q_OS_WIN)
- // Windows workaround: Split the private key into chunks of 2048 bytes,
- // to allow 4k (4096 bit) keys to be saved (obey Windows's limits)
- auto chunk = _clientSslKeyChunkBufferPEM.left(_clientSslKeyChunkSize);
-
- _clientSslKeyChunkBufferPEM = _clientSslKeyChunkBufferPEM.right(_clientSslKeyChunkBufferPEM.size() - chunk.size());
-#else
- // write full key in one slot on non-Windows, as usual
- auto chunk = _clientSslKeyChunkBufferPEM;
-
- _clientSslKeyChunkBufferPEM.clear();
-#endif
- auto index = (_clientSslKeyChunkCount++);
-
- // keep the limit
- if (_clientSslKeyChunkCount > _clientSslKeyMaxChunks) {
- qCWarning(lcWebFlowCredentials) << "Maximum client key chunk count exceeded while writing slot" << QString::number(index) << "cutting off after" << QString::number(_clientSslKeyMaxChunks) << "chunks";
-
- _clientSslKeyChunkBufferPEM.clear();
-
- slotWriteClientKeyPEMJobDone();
- return;
- }
-
- WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
- addSettingsToJob(_account, job);
- job->setInsecureFallback(false);
- connect(job, &Job::finished, this, &WebFlowCredentials::writeSingleClientKeyChunkPEM);
- // only add the key's (sub)"index" after the first element, to stay compatible with older versions and non-Windows
- job->setKey(keychainKey(_account->url().toString(), _user + clientKeyPEMC + (index > 0 ? (QString(".") + QString::number(index)) : QString()), _account->id()));
- job->setBinaryData(chunk);
+ auto *job = new KeychainChunk::WriteJob(_account,
+ _user + clientKeyPEMC,
+ _clientSslKey.toPem());
+ connect(job, &KeychainChunk::WriteJob::finished, this, &WebFlowCredentials::slotWriteClientKeyPEMJobDone);
job->start();
-
- chunk.clear();
} else {
- slotWriteClientKeyPEMJobDone();
+ // no key, just write credentials
+ slotWriteClientKeyPEMJobDone(nullptr);
}
}
return;
}
- WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
- addSettingsToJob(_account, job);
- job->setInsecureFallback(false);
- connect(job, &Job::finished, this, &WebFlowCredentials::slotWriteClientCaCertsPEMJobDone);
- job->setKey(keychainKey(_account->url().toString(), _user + clientCaCertificatePEMC + QString::number(index), _account->id()));
- job->setBinaryData(cert.toPem());
+ auto *job = new KeychainChunk::WriteJob(_account,
+ _user + clientCaCertificatePEMC + QString::number(index),
+ cert.toPem());
+ connect(job, &KeychainChunk::WriteJob::finished, this, &WebFlowCredentials::slotWriteClientCaCertsPEMJobDone);
job->start();
} else {
slotWriteClientCaCertsPEMJobDone(nullptr);
}
}
-void WebFlowCredentials::slotWriteClientKeyPEMJobDone()
+void WebFlowCredentials::slotWriteClientKeyPEMJobDone(KeychainChunk::WriteJob *writeJob)
{
+ if(writeJob)
+ writeJob->deleteLater();
+
_clientSslCaCertificatesWriteQueue.clear();
// write ca certs if there are any
}
}
-void WebFlowCredentials::slotWriteClientCaCertsPEMJobDone(QKeychain::Job *incomingJob)
+void WebFlowCredentials::slotWriteClientCaCertsPEMJobDone(KeychainChunk::WriteJob *writeJob)
{
// errors / next ca cert?
- if (incomingJob && !_clientSslCaCertificates.isEmpty()) {
- WritePasswordJob *writeJob = static_cast<WritePasswordJob *>(incomingJob);
-
+ if (writeJob && !_clientSslCaCertificates.isEmpty()) {
if (writeJob->error() != NoError) {
qCWarning(lcWebFlowCredentials) << "Error while writing client CA cert" << writeJob->errorString();
}
+ writeJob->deleteLater();
+
if (!_clientSslCaCertificatesWriteQueue.isEmpty()) {
// next ca cert
writeSingleClientCaCertPEM();
// done storing ca certs, time for the password
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
+#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
addSettingsToJob(_account, job);
+#endif
job->setInsecureFallback(false);
connect(job, &Job::finished, this, &WebFlowCredentials::slotWriteJobDone);
job->setKey(keychainKey(_account->url().toString(), _user, _account->id()));
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
job->setInsecureFallback(false);
job->setKey(kck);
+ connect(job, &Job::finished, this, [](QKeychain::Job *job) {
+ DeletePasswordJob *djob = qobject_cast<DeletePasswordJob *>(job);
+ djob->deleteLater();
+ });
job->start();
invalidateToken();
void WebFlowCredentials::fetchFromKeychainHelper() {
// Read client cert from keychain
- const QString kck = keychainKey(
- _account->url().toString(),
- _user + clientCertificatePEMC,
- _keychainMigration ? QString() : _account->id());
-
- ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
- addSettingsToJob(_account, job);
- job->setInsecureFallback(false);
- job->setKey(kck);
- connect(job, &Job::finished, this, &WebFlowCredentials::slotReadClientCertPEMJobDone);
+ auto *job = new KeychainChunk::ReadJob(_account,
+ _user + clientCertificatePEMC,
+ _keychainMigration);
+ connect(job, &KeychainChunk::ReadJob::finished, this, &WebFlowCredentials::slotReadClientCertPEMJobDone);
job->start();
}
-void WebFlowCredentials::slotReadClientCertPEMJobDone(QKeychain::Job *incomingJob)
+void WebFlowCredentials::slotReadClientCertPEMJobDone(KeychainChunk::ReadJob *readJob)
{
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
- Q_ASSERT(!incomingJob->insecureFallback()); // If insecureFallback is set, the next test would be pointless
- if (_retryOnKeyChainError && (incomingJob->error() == QKeychain::NoBackendAvailable
- || incomingJob->error() == QKeychain::OtherError)) {
+ Q_ASSERT(!readJob->insecureFallback()); // If insecureFallback is set, the next test would be pointless
+ if (_retryOnKeyChainError && (readJob->error() == QKeychain::NoBackendAvailable
+ || readJob->error() == QKeychain::OtherError)) {
// Could be that the backend was not yet available. Wait some extra seconds.
// (Issues #4274 and #6522)
// (For kwallet, the error is OtherError instead of NoBackendAvailable, maybe a bug in QtKeychain)
- qCInfo(lcWebFlowCredentials) << "Backend unavailable (yet?) Retrying in a few seconds." << incomingJob->errorString();
+ qCInfo(lcWebFlowCredentials) << "Backend unavailable (yet?) Retrying in a few seconds." << readJob->errorString();
QTimer::singleShot(10000, this, &WebFlowCredentials::fetchFromKeychainHelper);
_retryOnKeyChainError = false;
return;
#endif
// Store PEM in memory
- ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incomingJob);
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(readJob->binaryData(), QSsl::Pem);
if (sslCertificateList.length() >= 1) {
}
}
- // Load key too
- _clientSslKeyChunkCount = 0;
- _clientSslKeyChunkBufferPEM.clear();
+ readJob->deleteLater();
- const QString kck = keychainKey(
- _account->url().toString(),
- _user + clientKeyPEMC,
- _keychainMigration ? QString() : _account->id());
-
- ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
- addSettingsToJob(_account, job);
- job->setInsecureFallback(false);
- job->setKey(kck);
- connect(job, &Job::finished, this, &WebFlowCredentials::slotReadClientKeyPEMJobDone);
+ // Load key too
+ auto *job = new KeychainChunk::ReadJob(_account,
+ _user + clientKeyPEMC,
+ _keychainMigration);
+ connect(job, &KeychainChunk::ReadJob::finished, this, &WebFlowCredentials::slotReadClientKeyPEMJobDone);
job->start();
}
-void WebFlowCredentials::slotReadClientKeyPEMJobDone(QKeychain::Job *incomingJob)
+void WebFlowCredentials::slotReadClientKeyPEMJobDone(KeychainChunk::ReadJob *readJob)
{
- // Errors or next key chunk?
- ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incomingJob);
-
- if (readJob) {
- if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
- _clientSslKeyChunkBufferPEM.append(readJob->binaryData());
- _clientSslKeyChunkCount++;
-
-#if defined(Q_OS_WIN)
- // try to fetch next chunk
- if (_clientSslKeyChunkCount < _clientSslKeyMaxChunks) {
- const QString kck = keychainKey(
- _account->url().toString(),
- _user + clientKeyPEMC + QString(".") + QString::number(_clientSslKeyChunkCount),
- _keychainMigration ? QString() : _account->id());
-
- ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
- addSettingsToJob(_account, job);
- job->setInsecureFallback(false);
- job->setKey(kck);
- connect(job, &Job::finished, this, &WebFlowCredentials::slotReadClientKeyPEMJobDone);
- job->start();
-
- return;
- } else {
- qCWarning(lcWebFlowCredentials) << "Maximum client key chunk count reached, ignoring after" << _clientSslKeyMaxChunks;
- }
-#endif
- } else {
- if (readJob->error() != QKeychain::Error::EntryNotFound ||
- ((readJob->error() == QKeychain::Error::EntryNotFound) && _clientSslKeyChunkCount == 0)) {
- qCWarning(lcWebFlowCredentials) << "Unable to read client key chunk slot" << QString::number(_clientSslKeyChunkCount) << readJob->errorString();
- }
- }
- }
-
// Store key in memory
- if (_clientSslKeyChunkBufferPEM.size() > 0) {
+ if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
+ QByteArray clientKeyPEM = readJob->binaryData();
// FIXME Unfortunately Qt has a bug and we can't just use QSsl::Opaque to let it
// load whatever we have. So we try until it works.
- _clientSslKey = QSslKey(_clientSslKeyChunkBufferPEM, QSsl::Rsa);
+ _clientSslKey = QSslKey(clientKeyPEM, QSsl::Rsa);
if (_clientSslKey.isNull()) {
- _clientSslKey = QSslKey(_clientSslKeyChunkBufferPEM, QSsl::Dsa);
+ _clientSslKey = QSslKey(clientKeyPEM, QSsl::Dsa);
}
if (_clientSslKey.isNull()) {
- _clientSslKey = QSslKey(_clientSslKeyChunkBufferPEM, QSsl::Ec);
+ _clientSslKey = QSslKey(clientKeyPEM, QSsl::Ec);
}
if (_clientSslKey.isNull()) {
qCWarning(lcWebFlowCredentials) << "Could not load SSL key into Qt!";
}
- // clear key chunk buffer, but don't set _clientSslKeyChunkCount to zero because we need it for deleteKeychainEntries
- _clientSslKeyChunkBufferPEM.clear();
+ clientKeyPEM.clear();
+ } else {
+ qCWarning(lcWebFlowCredentials) << "Unable to read client key" << readJob->errorString();
}
+ readJob->deleteLater();
+
// Start fetching client CA certs
_clientSslCaCertificates.clear();
{
// try to fetch a client ca cert
if (_clientSslCaCertificates.count() < _clientSslCaCertificatesMaxCount) {
- const QString kck = keychainKey(
- _account->url().toString(),
- _user + clientCaCertificatePEMC + QString::number(_clientSslCaCertificates.count()),
- _keychainMigration ? QString() : _account->id());
-
- ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
- addSettingsToJob(_account, job);
- job->setInsecureFallback(false);
- job->setKey(kck);
- connect(job, &Job::finished, this, &WebFlowCredentials::slotReadClientCaCertsPEMJobDone);
+ auto *job = new KeychainChunk::ReadJob(_account,
+ _user + clientCaCertificatePEMC + QString::number(_clientSslCaCertificates.count()),
+ _keychainMigration);
+ connect(job, &KeychainChunk::ReadJob::finished, this, &WebFlowCredentials::slotReadClientCaCertsPEMJobDone);
job->start();
} else {
qCWarning(lcWebFlowCredentials) << "Maximum client CA cert count exceeded while reading, ignoring after" << _clientSslCaCertificatesMaxCount;
}
}
-void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(QKeychain::Job *incomingJob) {
- // Store key in memory
- ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incomingJob);
-
+void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(KeychainChunk::ReadJob *readJob) {
+ // Store cert in memory
if (readJob) {
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(readJob->binaryData(), QSsl::Pem);
_clientSslCaCertificates.append(sslCertificateList.at(0));
}
+ readJob->deleteLater();
+
// try next cert
readSingleClientCaCertPEM();
return;
qCWarning(lcWebFlowCredentials) << "Unable to read client CA cert slot" << QString::number(_clientSslCaCertificates.count()) << readJob->errorString();
}
}
+
+ readJob->deleteLater();
}
// Now fetch the actual server password
_keychainMigration ? QString() : _account->id());
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
+#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
addSettingsToJob(_account, job);
+#endif
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, &Job::finished, this, &WebFlowCredentials::slotReadPasswordJobDone);
}
void WebFlowCredentials::slotReadPasswordJobDone(Job *incomingJob) {
- QKeychain::ReadPasswordJob *job = static_cast<ReadPasswordJob *>(incomingJob);
+ QKeychain::ReadPasswordJob *job = qobject_cast<ReadPasswordJob *>(incomingJob);
QKeychain::Error error = job->error();
// If we could not find the entry try the old entries
}
emit fetched();
+ job->deleteLater();
+
// If keychain data was read from legacy location, wipe these entries and store new ones
if (_keychainMigration && _ready) {
_keychainMigration = false;
}
void WebFlowCredentials::deleteKeychainEntries(bool oldKeychainEntries) {
- auto startDeleteJob = [this, oldKeychainEntries](QString user) {
+ auto startDeleteJob = [this, oldKeychainEntries](QString key) {
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
+#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
addSettingsToJob(_account, job);
+#endif
job->setInsecureFallback(false);
job->setKey(keychainKey(_account->url().toString(),
- user,
+ key,
oldKeychainEntries ? QString() : _account->id()));
+
+ connect(job, &Job::finished, this, [](QKeychain::Job *job) {
+ DeletePasswordJob *djob = qobject_cast<DeletePasswordJob *>(job);
+ djob->deleteLater();
+ });
job->start();
};
}
#if defined(Q_OS_WIN)
- // also delete key sub-chunks (Windows workaround)
- for (auto i = 1; i < _clientSslKeyChunkCount; i++) {
- startDeleteJob(_user + clientKeyPEMC + QString(".") + QString::number(i));
+ // Also delete key / cert sub-chunks (Windows workaround)
+ // The first chunk (0) has no suffix, to stay compatible with older versions and non-Windows
+ for (auto chunk = 1; chunk < KeychainChunk::MaxChunks; chunk++) {
+ const QString strChunkSuffix = QString(".") + QString::number(chunk);
+
+ startDeleteJob(_user + clientKeyPEMC + strChunkSuffix);
+ startDeleteJob(_user + clientCertificatePEMC + strChunkSuffix);
+
+ for (auto i = 0; i < _clientSslCaCertificates.count(); i++) {
+ startDeleteJob(_user + clientCaCertificatePEMC + QString::number(i));
+ }
}
#endif
// FIXME MS@2019-12-07 -->
// <-- FIXME MS@2019-12-07
}
-}
+} // namespace OCC