From: Michael Schuster Date: Wed, 24 Jun 2020 23:08:59 +0000 (+0200) Subject: Move KeychainChunk class from gui to libsync X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~222^2^2~111^2~7 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=2a3ef044be79b90f479ea24e49bbd3ebf48583e5;p=nextcloud-desktop.git Move KeychainChunk class from gui to libsync Signed-off-by: Michael Schuster --- diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index b83106441..57c876c33 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -112,7 +112,6 @@ set(client_SRCS creds/httpcredentialsgui.cpp creds/oauth.cpp creds/flow2auth.cpp - creds/keychainchunk.cpp creds/webflowcredentials.cpp creds/webflowcredentialsdialog.cpp wizard/postfixlineedit.cpp diff --git a/src/gui/creds/keychainchunk.cpp b/src/gui/creds/keychainchunk.cpp deleted file mode 100644 index 836be0b01..000000000 --- a/src/gui/creds/keychainchunk.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (C) by Michael Schuster - * - * 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) -{ - auto *writeJob = static_cast(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()); - - auto *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()); - - auto *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? - auto *readJob = static_cast(incomingJob); - - if (readJob) { - 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 { -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) - if (!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(lcKeychainChunk) << "Backend unavailable (yet?) Retrying in a few seconds." << readJob->errorString(); - QTimer::singleShot(10000, this, &ReadJob::start); - _retryOnKeyChainError = false; - readJob->deleteLater(); - return; - } - _retryOnKeyChainError = false; - } -#endif - - if (readJob->error() != QKeychain::EntryNotFound || - ((readJob->error() == QKeychain::EntryNotFound) && _chunkCount == 0)) { - _error = readJob->error(); - _errorString = readJob->errorString(); - qCWarning(lcKeychainChunk) << "Unable to read" << readJob->key() << "chunk" << QString::number(_chunkCount) << readJob->errorString(); - } - } - - readJob->deleteLater(); - } - - emit finished(this); -} - -} // namespace KeychainChunk - -} // namespace OCC diff --git a/src/gui/creds/keychainchunk.h b/src/gui/creds/keychainchunk.h deleted file mode 100644 index d1ae1e9dd..000000000 --- a/src/gui/creds/keychainchunk.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) by Michael Schuster - * - * 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. - */ - -#pragma once -#ifndef KEYCHAINCHUNK_H -#define KEYCHAINCHUNK_H - -#include -#include -#include "accountfwd.h" - -// We don't support insecure fallback -// #define KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK - -namespace OCC { - -namespace KeychainChunk { - -/* -* Workaround for Windows: -* -* Split the keychain entry's data into chunks of 2048 bytes, -* to allow 4k (4096 bit) keys / large certs to be saved (see limits in webflowcredentials.h) -*/ -static constexpr int ChunkSize = 2048; -static constexpr int MaxChunks = 10; - -/* - * @brief: Abstract base class for KeychainChunk jobs. - */ -class Job : public QObject { - Q_OBJECT -public: - Job(QObject *parent = nullptr); - - const QKeychain::Error error() const { - return _error; - } - const QString errorString() const { - return _errorString; - } - - QByteArray binaryData() const { - return _chunkBuffer; - } - - const bool insecureFallback() const { - return _insecureFallback; - } - -// If we use it but don't support insecure fallback, give us nice compilation errors ;p -#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK) - void setInsecureFallback(const bool &insecureFallback) - { - _insecureFallback = insecureFallback; - } -#endif - -protected: - QString _serviceName; - Account *_account; - QString _key; - bool _insecureFallback = false; - bool _keychainMigration = false; - - QKeychain::Error _error = QKeychain::NoError; - QString _errorString; - - int _chunkCount = 0; - QByteArray _chunkBuffer; -}; // class Job - -/* -* @brief: Simple wrapper class for QKeychain::WritePasswordJob, splits too large keychain entry's data into chunks on Windows -*/ -class WriteJob : public KeychainChunk::Job { - Q_OBJECT -public: - WriteJob(Account *account, const QString &key, const QByteArray &data, QObject *parent = nullptr); - void start(); - -signals: - void finished(KeychainChunk::WriteJob *incomingJob); - -private slots: - void slotWriteJobDone(QKeychain::Job *incomingJob); -}; // class WriteJob - -/* -* @brief: Simple wrapper class for QKeychain::ReadPasswordJob, splits too large keychain entry's data into chunks on Windows -*/ -class ReadJob : public KeychainChunk::Job { - Q_OBJECT -public: - ReadJob(Account *account, const QString &key, const bool &keychainMigration, QObject *parent = nullptr); - void start(); - -signals: - void finished(KeychainChunk::ReadJob *incomingJob); - -private slots: - void slotReadJobDone(QKeychain::Job *incomingJob); - -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) -private: - bool _retryOnKeyChainError = true; // true if we haven't done yet any reading from keychain -#endif -}; // class ReadJob - -} // namespace KeychainChunk - -} // namespace OCC - -#endif // KEYCHAINCHUNK_H diff --git a/src/gui/creds/webflowcredentials.cpp b/src/gui/creds/webflowcredentials.cpp index ff5c2eb2a..e6c1f141a 100644 --- a/src/gui/creds/webflowcredentials.cpp +++ b/src/gui/creds/webflowcredentials.cpp @@ -1,13 +1,13 @@ #include "webflowcredentials.h" #include "creds/httpcredentials.h" +#include "creds/keychainchunk.h" #include #include #include #include #include -#include #include #include #include @@ -18,7 +18,6 @@ #include "theme.h" #include "wizard/webview.h" #include "webflowcredentialsdialog.h" -#include "keychainchunk.h" using namespace QKeychain; diff --git a/src/libsync/CMakeLists.txt b/src/libsync/CMakeLists.txt index 146e0910a..aef76d246 100644 --- a/src/libsync/CMakeLists.txt +++ b/src/libsync/CMakeLists.txt @@ -59,6 +59,7 @@ set(libsync_SRCS creds/dummycredentials.cpp creds/abstractcredentials.cpp creds/credentialscommon.cpp + creds/keychainchunk.cpp ) if(TOKEN_AUTH_ONLY) diff --git a/src/libsync/creds/keychainchunk.cpp b/src/libsync/creds/keychainchunk.cpp new file mode 100644 index 000000000..836be0b01 --- /dev/null +++ b/src/libsync/creds/keychainchunk.cpp @@ -0,0 +1,238 @@ +/* + * Copyright (C) by Michael Schuster + * + * 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) +{ + auto *writeJob = static_cast(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()); + + auto *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()); + + auto *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? + auto *readJob = static_cast(incomingJob); + + if (readJob) { + 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 { +#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) + if (!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(lcKeychainChunk) << "Backend unavailable (yet?) Retrying in a few seconds." << readJob->errorString(); + QTimer::singleShot(10000, this, &ReadJob::start); + _retryOnKeyChainError = false; + readJob->deleteLater(); + return; + } + _retryOnKeyChainError = false; + } +#endif + + if (readJob->error() != QKeychain::EntryNotFound || + ((readJob->error() == QKeychain::EntryNotFound) && _chunkCount == 0)) { + _error = readJob->error(); + _errorString = readJob->errorString(); + qCWarning(lcKeychainChunk) << "Unable to read" << readJob->key() << "chunk" << QString::number(_chunkCount) << readJob->errorString(); + } + } + + readJob->deleteLater(); + } + + emit finished(this); +} + +} // namespace KeychainChunk + +} // namespace OCC diff --git a/src/libsync/creds/keychainchunk.h b/src/libsync/creds/keychainchunk.h new file mode 100644 index 000000000..d1d207b55 --- /dev/null +++ b/src/libsync/creds/keychainchunk.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) by Michael Schuster + * + * 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. + */ + +#pragma once +#ifndef KEYCHAINCHUNK_H +#define KEYCHAINCHUNK_H + +#include +#include +#include "accountfwd.h" + +// We don't support insecure fallback +// #define KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK + +namespace OCC { + +namespace KeychainChunk { + +/* +* Workaround for Windows: +* +* Split the keychain entry's data into chunks of 2048 bytes, +* to allow 4k (4096 bit) keys / large certs to be saved (see limits in webflowcredentials.h) +*/ +static constexpr int ChunkSize = 2048; +static constexpr int MaxChunks = 10; + +/* + * @brief: Abstract base class for KeychainChunk jobs. + */ +class Job : public QObject +{ + Q_OBJECT +public: + Job(QObject *parent = nullptr); + + const QKeychain::Error error() const { + return _error; + } + const QString errorString() const { + return _errorString; + } + + QByteArray binaryData() const { + return _chunkBuffer; + } + + const bool insecureFallback() const { + return _insecureFallback; + } + +// If we use it but don't support insecure fallback, give us nice compilation errors ;p +#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK) + void setInsecureFallback(const bool &insecureFallback) + { + _insecureFallback = insecureFallback; + } +#endif + +protected: + QString _serviceName; + Account *_account; + QString _key; + bool _insecureFallback = false; + bool _keychainMigration = false; + + QKeychain::Error _error = QKeychain::NoError; + QString _errorString; + + int _chunkCount = 0; + QByteArray _chunkBuffer; +}; // class Job + +/* +* @brief: Simple wrapper class for QKeychain::WritePasswordJob, splits too large keychain entry's data into chunks on Windows +*/ +class OWNCLOUDSYNC_EXPORT WriteJob : public KeychainChunk::Job +{ + Q_OBJECT +public: + WriteJob(Account *account, const QString &key, const QByteArray &data, QObject *parent = nullptr); + void start(); + +signals: + void finished(KeychainChunk::WriteJob *incomingJob); + +private slots: + void slotWriteJobDone(QKeychain::Job *incomingJob); +}; // class WriteJob + +/* +* @brief: Simple wrapper class for QKeychain::ReadPasswordJob, splits too large keychain entry's data into chunks on Windows +*/ +class OWNCLOUDSYNC_EXPORT ReadJob : public KeychainChunk::Job +{ + Q_OBJECT +public: + ReadJob(Account *account, const QString &key, const bool &keychainMigration, QObject *parent = nullptr); + void start(); + +signals: + void finished(KeychainChunk::ReadJob *incomingJob); + +private slots: + void slotReadJobDone(QKeychain::Job *incomingJob); + +#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) +private: + bool _retryOnKeyChainError = true; // true if we haven't done yet any reading from keychain +#endif +}; // class ReadJob + +} // namespace KeychainChunk + +} // namespace OCC + +#endif // KEYCHAINCHUNK_H