#include "apikeystore.h" #include #include #include #include #include using namespace Qt::Literals::StringLiterals; namespace { const QString Service = u"dev.trivk.qtpotato"_s; const QString Key = u"translation-api-key"_s; struct JobDeleter { void operator()(QKeychain::Job *job) const { job->deleteLater(); } }; template std::unique_ptr makeJob() { auto job = std::unique_ptr(new T(Service)); job->setAutoDelete(false); job->setKey(Key); return job; } } ApiKeyStore::ApiKeyStore(QObject *parent) : QObject(parent) { refresh(); } bool ApiKeyStore::hasKey() const { return m_hasKey; } QString ApiKeyStore::error() const { return m_error; } bool ApiKeyStore::busy() const { return m_busy; } void ApiKeyStore::setKey(const QString &key) { if (m_busy) { return; } m_pendingKey = key.trimmed(); m_retryStore = true; store(m_pendingKey); } void ApiKeyStore::retry() { if (m_busy) { return; } if (m_retryStore) { store(m_pendingKey); } else { refresh(); } } QCoro::Task ApiKeyStore::readKey() { auto job = makeJob(); job->start(); co_await qCoro(job.get(), &QKeychain::Job::finished); if (job->error() == QKeychain::EntryNotFound) { co_return ReadResult{}; } if (job->error() != QKeychain::NoError) { co_return ReadResult{{}, i18nc("@info", "Could not read the API key from the system wallet.\nMake sure KWallet or Secret Service is running, then retry.")}; } co_return ReadResult{job->textData(), {}}; } QCoro::Task<> ApiKeyStore::refresh() { setBusy(true); QPointer self(this); const ReadResult result = co_await readKey(); if (!self) { co_return; } setHasKey(!result.key.isEmpty()); setError(result.error); setBusy(false); } QCoro::Task<> ApiKeyStore::store(QString key) { setBusy(true); QPointer self(this); std::unique_ptr job; if (key.isEmpty()) { job = makeJob(); } else { auto write = makeJob(); write->setTextData(key); job.reset(write.release()); } job->start(); co_await qCoro(job.get(), &QKeychain::Job::finished); if (!self) { co_return; } if (job->error() != QKeychain::NoError && job->error() != QKeychain::EntryNotFound) { setError(key.isEmpty() ? i18nc("@info", "Could not remove the API key from the system wallet.\nMake sure KWallet or Secret Service is running, then retry.") : i18nc("@info", "Could not store the API key in the system wallet.\nMake sure KWallet or Secret Service is running, then retry.")); setBusy(false); co_return; } setError({}); setHasKey(!key.isEmpty()); m_retryStore = false; m_pendingKey.clear(); setBusy(false); } void ApiKeyStore::setHasKey(bool hasKey) { if (hasKey != m_hasKey) { m_hasKey = hasKey; Q_EMIT hasKeyChanged(); } } void ApiKeyStore::setError(const QString &error) { if (error != m_error) { m_error = error; Q_EMIT errorChanged(); } } void ApiKeyStore::setBusy(bool busy) { if (busy != m_busy) { m_busy = busy; Q_EMIT busyChanged(); } }