summaryrefslogtreecommitdiff
path: root/credentials.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'credentials.cpp')
-rw-r--r--credentials.cpp218
1 files changed, 218 insertions, 0 deletions
diff --git a/credentials.cpp b/credentials.cpp
new file mode 100644
index 0000000..5cd6e6f
--- /dev/null
+++ b/credentials.cpp
@@ -0,0 +1,218 @@
+#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();
+}