#include "configfile.h"
#include "creds/abstractcredentials.h"
+#include <QApplication>
+
using namespace QKeychain;
namespace OCC {
_serviceName = Theme::instance()->appName();
}
+Job::~Job()
+{
+ _chunkCount = 0;
+ _chunkBuffer.clear();
+}
+
/*
* WriteJob
*/
_chunkCount = 0;
}
+WriteJob::WriteJob(const QString &key, const QByteArray &data, QObject *parent)
+ : WriteJob(nullptr, key, data, parent)
+{
+#ifdef Q_OS_WIN
+ // NOTE: The following is normally done in AbstractCredentials::keychainKey
+ // when an _account is specified by our other ctr overload (see 'kck' in this file).
+
+ // On Windows the credential keys aren't namespaced properly
+ // by qtkeychain. To work around that we manually add namespacing
+ // to the generated keys. See #6125.
+ // It's safe to do that since the key format is changing for 2.4
+ // anyway to include the account ids. That means old keys can be
+ // migrated to new namespaced keys on windows for 2.4.
+ _key.prepend(QCoreApplication::applicationName() + "_");
+#endif
+}
+
void WriteJob::start()
{
+ _isJobRunning = true;
slotWriteJobDone(nullptr);
}
+bool WriteJob::startAwait()
+{
+ start();
+
+ while (_isJobRunning) {
+ QApplication::processEvents(QEventLoop::AllEvents, 200);
+ }
+
+ if (error() != NoError) {
+ qCWarning(lcKeychainChunk) << "WritePasswordJob failed with" << errorString();
+ return false;
+ }
+
+ return true;
+}
+
void WriteJob::slotWriteJobDone(QKeychain::Job *incomingJob)
{
auto *writeJob = static_cast<QKeychain::WritePasswordJob *>(incomingJob);
_chunkBuffer.clear();
+ _isJobRunning = false;
emit finished(this);
return;
}
- const QString kck = AbstractCredentials::keychainKey(
- _account->url().toString(),
- _key + (index > 0 ? (QString(".") + QString::number(index)) : QString()),
- _account->id());
+ const QString keyWithIndex = _key + (index > 0 ? (QString(".") + QString::number(index)) : QString());
+ const QString kck = _account ? AbstractCredentials::keychainKey(
+ _account->url().toString(),
+ keyWithIndex,
+ _account->id()
+ ) : keyWithIndex;
auto *job = new QKeychain::WritePasswordJob(_serviceName);
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
chunk.clear();
} else {
+ _isJobRunning = false;
emit finished(this);
}
_chunkBuffer.clear();
}
+ReadJob::ReadJob(const QString &key, QObject *parent)
+ : ReadJob(nullptr, key, false, parent)
+{
+#ifdef Q_OS_WIN
+ // NOTE: The following is normally done in AbstractCredentials::keychainKey
+ // when an _account is specified by our other ctr overload (see 'kck' in this file).
+
+ // On Windows the credential keys aren't namespaced properly
+ // by qtkeychain. To work around that we manually add namespacing
+ // to the generated keys. See #6125.
+ // It's safe to do that since the key format is changing for 2.4
+ // anyway to include the account ids. That means old keys can be
+ // migrated to new namespaced keys on windows for 2.4.
+ _key.prepend(QCoreApplication::applicationName() + "_");
+#endif
+}
+
void ReadJob::start()
{
_chunkCount = 0;
_chunkBuffer.clear();
- const QString kck = AbstractCredentials::keychainKey(
- _account->url().toString(),
- _key,
- _keychainMigration ? QString() : _account->id());
+ const QString kck = _account ? AbstractCredentials::keychainKey(
+ _account->url().toString(),
+ _key,
+ _keychainMigration ? QString() : _account->id()
+ ) : _key;
auto *job = new QKeychain::ReadPasswordJob(_serviceName);
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
job->setInsecureFallback(_insecureFallback);
job->setKey(kck);
connect(job, &QKeychain::Job::finished, this, &KeychainChunk::ReadJob::slotReadJobDone);
+ _isJobRunning = true;
job->start();
}
+bool ReadJob::startAwait()
+{
+ start();
+
+ while (_isJobRunning) {
+ QApplication::processEvents(QEventLoop::AllEvents, 200);
+ }
+
+ if (error() == NoError) {
+ return true;
+ }
+
+ _chunkCount = 0;
+ _chunkBuffer.clear();
+ if (error() != EntryNotFound) {
+ qCWarning(lcKeychainChunk) << "ReadPasswordJob failed with" << errorString();
+ }
+ return false;
+}
+
void ReadJob::slotReadJobDone(QKeychain::Job *incomingJob)
{
// Errors or next chunk?
#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());
+ const QString keyWithIndex = _key + QString(".") + QString::number(_chunkCount);
+ const QString kck = _account ? AbstractCredentials::keychainKey(
+ _account->url().toString(),
+ keyWithIndex,
+ _keychainMigration ? QString() : _account->id()
+ ) : keyWithIndex;
QKeychain::ReadPasswordJob *job = new QKeychain::ReadPasswordJob(_serviceName);
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
readJob->deleteLater();
}
+ _isJobRunning = false;
emit finished(this);
}
public:
Job(QObject *parent = nullptr);
+ virtual ~Job();
+
const QKeychain::Error error() const {
return _error;
}
QByteArray binaryData() const {
return _chunkBuffer;
}
+ QString textData() const {
+ return _chunkBuffer;
+ }
const bool insecureFallback() const {
return _insecureFallback;
QString _key;
bool _insecureFallback = false;
bool _keychainMigration = false;
+ bool _isJobRunning = false;
QKeychain::Error _error = QKeychain::NoError;
QString _errorString;
Q_OBJECT
public:
WriteJob(Account *account, const QString &key, const QByteArray &data, QObject *parent = nullptr);
+ WriteJob(const QString &key, const QByteArray &data, QObject *parent = nullptr);
+
+ /**
+ * Call this method to start the job (async).
+ * You should connect some slot to the finished() signal first.
+ *
+ * @see QKeychain::Job::start()
+ */
void start();
+ /**
+ * Call this method to start the job synchronously.
+ * Awaits completion with no need to connect some slot to the finished() signal first.
+ *
+ * @return Returns true on succeess (QKeychain::NoError).
+ */
+ bool startAwait();
+
signals:
void finished(KeychainChunk::WriteJob *incomingJob);
Q_OBJECT
public:
ReadJob(Account *account, const QString &key, const bool &keychainMigration, QObject *parent = nullptr);
+ ReadJob(const QString &key, QObject *parent = nullptr);
+
+ /**
+ * Call this method to start the job (async).
+ * You should connect some slot to the finished() signal first.
+ *
+ * @see QKeychain::Job::start()
+ */
void start();
+ /**
+ * Call this method to start the job synchronously.
+ * Awaits completion with no need to connect some slot to the finished() signal first.
+ *
+ * @return Returns true on succeess (QKeychain::NoError).
+ */
+ bool startAwait();
+
signals:
void finished(KeychainChunk::ReadJob *incomingJob);