xxcc/credentials.cpp

219 lines
5.4 KiB
C++

#include "credentials.h"
#include <qt5keychain/keychain.h>
#include <QXmppPromise.h>
#include <QXmppConfiguration.h>
#include <iostream>
static const QString service = "xxcc", sep = ";";
QXmppTask<Credentials::PairListResult> Credentials::load(
Credentials::PairList &pairs,
QStringList::const_iterator &it,
QStringList::const_iterator end)
{
if (it == end)
return QXmpp::Private::makeReadyTask<PairListResult>(
PairListResult(pairs));
QXmppPromise<PairListResult> promise;
load(*it).then(this,
[=] (LoadResult &&result) mutable
{
if (std::holds_alternative<QString>(result))
{
pairs << Pair(*it, std::get<QString>(result));
load(pairs, ++it, end).then(this,
[=] (PairListResult &&result) mutable
{
promise.finish(result);
});
}
else if (std::holds_alternative<Error>(result))
promise.finish(Error{std::get<Error>(result)});
});
return promise.task();
}
QXmppTask<Credentials::PairListResult> Credentials::load()
{
QXmppPromise<PairListResult> promise;
storedUsers().then(this,
[=] (Users &&result) mutable
{
if (std::holds_alternative<QStringList>(result))
{
PairList pairs;
auto list = new QStringList(std::get<QStringList>(result));
auto begin = list->cbegin();
const auto end = list->cend();
load(pairs, begin, end).then(this,
[=] (PairListResult &&result) mutable
{
delete list;
promise.finish(result);
});
}
else if (std::holds_alternative<Error>(result))
promise.finish(Error{std::get<Error>(result)});
});
return promise.task();
}
QXmppTask<Credentials::StoreResult> Credentials::store(Client *c)
{
QXmppPromise<StoreResult> promise;
const QXmppConfiguration &cfg = c->configuration();
const QString user = cfg.jidBare();
store(user, cfg.password()).then(this,
[=] (StoreResult &&result) mutable
{
store(user).then(this,
[=] (StoreResult &&result) mutable
{
promise.finish(result);
});
});
return promise.task();
}
QXmppTask<Credentials::StoreResult> Credentials::store(const QString &user)
{
QXmppPromise<StoreResult> promise;
storedUsersList().then(this,
[=] (LoadResult &&result) mutable
{
if (std::holds_alternative<QString>(result))
{
auto &list = std::get<QString>(result);
if (!list.isEmpty())
list += sep;
list += user;
store("users", list).then(this,
[=] (StoreResult &&result) mutable
{
promise.finish(result);
});
}
else if (std::holds_alternative<Error>(result))
{
store("users", user).then(this,
[=] (StoreResult &&result) mutable
{
promise.finish(result);
});
}
});
return promise.task();
}
QXmppTask<Credentials::LoadResult> Credentials::storedUsersList()
{
QXmppPromise<LoadResult> promise;
load("users").then(this,
[=] (LoadResult &&result) mutable
{
promise.finish(result);
});
return promise.task();
}
QXmppTask<Credentials::LoadResult> Credentials::load(const QString &key)
{
QXmppPromise<LoadResult> promise;
auto job = new QKeychain::ReadPasswordJob(service);
job->setKey(key);
job->connect(job, &QKeychain::Job::finished, this,
[=] (QKeychain::Job *const job) mutable
{
auto readjob = dynamic_cast<QKeychain::ReadPasswordJob *>(job);
if (readjob->error())
{
const auto error = "Failed to load " + key + ": "
+ readjob->errorString();
std::cerr << qPrintable(error) << std::endl;
promise.finish(Error{error});
}
else
{
auto users = readjob->textData();
promise.finish(QString(users));
}
});
job->start();
return promise.task();
}
QXmppTask<Credentials::StoreResult> Credentials::store(const QString &key,
const QString &value)
{
QXmppPromise<StoreResult> promise;
auto job = new QKeychain::WritePasswordJob(service);
job->setKey(key);
job->setTextData(value);
job->connect(job, &QKeychain::Job::finished, this,
[=] (QKeychain::Job *const job) mutable
{
if (job->error())
{
StoreResult sr;
const auto error = "Failed to store " + key + ": "
+ job->errorString();
std::cerr << qPrintable(error) << std::endl;
sr = Error{error};
promise.finish(StoreResult(sr));
}
else
promise.finish(Success{});
});
job->start();
return promise.task();
}
QXmppTask<Credentials::Users> Credentials::storedUsers()
{
QXmppPromise<Users> promise;
storedUsersList().then(this,
[=] (LoadResult &&result) mutable
{
if (std::holds_alternative<QString>(result))
{
const auto &value = std::get<QString>(result);
promise.finish(QStringList(value.split(sep)));
}
else if (std::holds_alternative<Error>(result))
{
const auto &error = std::get<Error>(result);
promise.finish(Error{error.description});
}
});
return promise.task();
}