mirror-chatterino2/src/common/Credentials.cpp

174 lines
4.1 KiB
C++
Raw Normal View History

2019-09-09 22:27:46 +02:00
#include "Credentials.hpp"
2019-09-14 15:50:05 +02:00
#include "debug/AssertInGuiThread.hpp"
2019-09-09 22:27:46 +02:00
#include "keychain.h"
#include "singletons/Paths.hpp"
2019-09-13 19:26:52 +02:00
#include "singletons/Settings.hpp"
#include "util/CombinePath.hpp"
#include <QSaveFile>
2019-09-09 22:27:46 +02:00
#define FORMAT_NAME \
([&] { \
assert(!provider.contains(":")); \
return QString("chatterino:%1:%2").arg(provider).arg(name_); \
})()
namespace chatterino {
2019-09-13 19:26:52 +02:00
namespace {
bool useKeyring()
{
if (getPaths()->isPortable())
{
return false;
}
else
{
#ifdef Q_OS_LINUX
return getSettings()->useKeyring;
#else
return true;
#endif
}
}
// Insecure storage:
QString insecurePath()
{
return combinePath(getPaths()->settingsDirectory, "credentials.json");
}
QJsonDocument loadInsecure()
{
QFile file(insecurePath());
file.open(QIODevice::ReadOnly);
return QJsonDocument::fromJson(file.readAll());
}
void storeInsecure(const QJsonDocument &doc)
{
QSaveFile file(insecurePath());
file.open(QIODevice::WriteOnly);
file.write(doc.toJson());
file.commit();
}
QJsonDocument &insecureInstance()
{
static auto store = loadInsecure();
return store;
}
void queueInsecureSave()
{
static bool isQueued = false;
if (!isQueued)
{
isQueued = true;
QTimer::singleShot(200, qApp, [] {
storeInsecure(insecureInstance());
isQueued = false;
});
}
}
} // namespace
2019-09-09 22:27:46 +02:00
Credentials &Credentials::getInstance()
{
static Credentials creds;
return creds;
}
Credentials::Credentials()
{
}
QString Credentials::get(const QString &provider, const QString &name_,
std::function<void(QString)> &&onLoaded)
{
2019-09-13 19:26:52 +02:00
assertInGuiThread();
2019-09-09 22:27:46 +02:00
2019-09-13 19:26:52 +02:00
auto name = FORMAT_NAME;
2019-09-09 22:27:46 +02:00
2019-09-13 19:26:52 +02:00
if (useKeyring())
2019-09-09 22:27:46 +02:00
{
auto job = new QKeychain::ReadPasswordJob("chatterino");
job->setAutoDelete(true);
job->setKey(name);
QObject::connect(job, &QKeychain::Job::finished, qApp,
[job, onLoaded = std::move(onLoaded)](auto) mutable {
onLoaded(job->textData());
});
job->start();
return job->textData();
}
2019-09-13 19:26:52 +02:00
else
{
auto &instance = insecureInstance();
return instance.object().find(name).value().toString();
}
2019-09-09 22:27:46 +02:00
}
void Credentials::set(const QString &provider, const QString &name_,
const QString &credential)
{
2019-09-13 19:26:52 +02:00
assertInGuiThread();
/// On linux, we try to use a keychain but show a message to disable it when it fails.
/// XXX: add said message
2019-09-09 22:27:46 +02:00
auto name = FORMAT_NAME;
2019-09-13 19:26:52 +02:00
if (useKeyring())
2019-09-09 22:27:46 +02:00
{
auto job = new QKeychain::WritePasswordJob("chatterino");
job->setAutoDelete(true);
job->setKey(name);
job->setTextData(credential);
2019-09-13 19:26:52 +02:00
//QObject::connect(job, &QKeychain::Job::finished, qApp, [](auto) {});
2019-09-09 22:27:46 +02:00
job->start();
}
2019-09-13 19:26:52 +02:00
else
{
auto &instance = insecureInstance();
instance.object()[name] = credential;
queueInsecureSave();
}
2019-09-09 22:27:46 +02:00
}
void Credentials::erase(const QString &provider, const QString &name_)
{
2019-09-13 19:26:52 +02:00
assertInGuiThread();
2019-09-09 22:27:46 +02:00
auto name = FORMAT_NAME;
2019-09-13 19:26:52 +02:00
if (useKeyring())
2019-09-09 22:27:46 +02:00
{
auto job = new QKeychain::DeletePasswordJob("chatterino");
job->setAutoDelete(true);
job->setKey(name);
2019-09-13 19:26:52 +02:00
//QObject::connect(job, &QKeychain::Job::finished, qApp, [](auto) {});
2019-09-09 22:27:46 +02:00
job->start();
}
2019-09-13 19:26:52 +02:00
else
{
auto &instance = insecureInstance();
if (auto it = instance.object().find(name);
it != instance.object().end())
{
instance.object().erase(it);
}
queueInsecureSave();
}
2019-09-09 22:27:46 +02:00
}
} // namespace chatterino