From 7c6f744e73daa483a618df70498d7d41d72ccaed Mon Sep 17 00:00:00 2001 From: fourtf Date: Fri, 13 Sep 2019 19:26:52 +0200 Subject: [PATCH] added insecure credential store --- chatterino.pro | 2 - src/common/Credentials.cpp | 122 +++++++++++++++++--- src/singletons/Settings.hpp | 4 + src/widgets/Window.cpp | 3 +- src/widgets/dialogs/IrcConnectionPopup.cpp | 38 ------ src/widgets/dialogs/IrcConnectionPopup.hpp | 13 --- src/widgets/dialogs/SelectChannelDialog.cpp | 1 - src/widgets/settingspages/GeneralPage.cpp | 9 ++ 8 files changed, 118 insertions(+), 74 deletions(-) delete mode 100644 src/widgets/dialogs/IrcConnectionPopup.cpp delete mode 100644 src/widgets/dialogs/IrcConnectionPopup.hpp diff --git a/chatterino.pro b/chatterino.pro index d59bbb0fd..0f74a6030 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -179,7 +179,6 @@ SOURCES += \ src/widgets/AttachedWindow.cpp \ src/widgets/dialogs/EmotePopup.cpp \ src/widgets/dialogs/IrcConnectionEditor.cpp \ - src/widgets/dialogs/IrcConnectionPopup.cpp \ src/widgets/dialogs/LastRunCrashDialog.cpp \ src/widgets/dialogs/LoginDialog.cpp \ src/widgets/dialogs/LogsPopup.cpp \ @@ -360,7 +359,6 @@ HEADERS += \ src/widgets/AttachedWindow.hpp \ src/widgets/dialogs/EmotePopup.hpp \ src/widgets/dialogs/IrcConnectionEditor.hpp \ - src/widgets/dialogs/IrcConnectionPopup.hpp \ src/widgets/dialogs/LastRunCrashDialog.hpp \ src/widgets/dialogs/LoginDialog.hpp \ src/widgets/dialogs/LogsPopup.hpp \ diff --git a/src/common/Credentials.cpp b/src/common/Credentials.cpp index ad0e9c423..91575e787 100644 --- a/src/common/Credentials.cpp +++ b/src/common/Credentials.cpp @@ -2,6 +2,10 @@ #include "keychain.h" #include "singletons/Paths.hpp" +#include "singletons/Settings.hpp" +#include "util/CombinePath.hpp" + +#include #define FORMAT_NAME \ ([&] { \ @@ -11,6 +15,65 @@ namespace chatterino { +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 + Credentials &Credentials::getInstance() { static Credentials creds; @@ -24,15 +87,11 @@ Credentials::Credentials() QString Credentials::get(const QString &provider, const QString &name_, std::function &&onLoaded) { + assertInGuiThread(); + auto name = FORMAT_NAME; - if (getPaths()->isPortable()) - { - assert(false); - - return {}; - } - else + if (useKeyring()) { auto job = new QKeychain::ReadPasswordJob("chatterino"); job->setAutoDelete(true); @@ -45,44 +104,69 @@ QString Credentials::get(const QString &provider, const QString &name_, return job->textData(); } + else + { + auto &instance = insecureInstance(); + + return instance.object().find(name).value().toString(); + } } void Credentials::set(const QString &provider, const QString &name_, const QString &credential) { + assertInGuiThread(); + + /// On linux, we try to use a keychain but show a message to disable it when it fails. + /// XXX: add said message + auto name = FORMAT_NAME; - if (getPaths()->isPortable()) - { - assert(false); - } - else + if (useKeyring()) { auto job = new QKeychain::WritePasswordJob("chatterino"); job->setAutoDelete(true); job->setKey(name); job->setTextData(credential); - QObject::connect(job, &QKeychain::Job::finished, qApp, [](auto) {}); + //QObject::connect(job, &QKeychain::Job::finished, qApp, [](auto) {}); job->start(); } + else + { + auto &instance = insecureInstance(); + + instance.object()[name] = credential; + + queueInsecureSave(); + } } void Credentials::erase(const QString &provider, const QString &name_) { + assertInGuiThread(); + auto name = FORMAT_NAME; - if (getPaths()->isPortable()) - { - assert(false); - } - else + if (useKeyring()) { auto job = new QKeychain::DeletePasswordJob("chatterino"); job->setAutoDelete(true); job->setKey(name); - QObject::connect(job, &QKeychain::Job::finished, qApp, [](auto) {}); + //QObject::connect(job, &QKeychain::Job::finished, qApp, [](auto) {}); job->start(); } + else + { + auto &instance = insecureInstance(); + + if (auto it = instance.object().find(name); + it != instance.object().end()) + { + instance.object().erase(it); + } + + queueInsecureSave(); + } } } // namespace chatterino diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index 1d0d87be1..ea0d901e0 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -199,6 +199,10 @@ public: /// Misc BoolSetting betaUpdates = {"/misc/beta", false}; +#ifdef Q_OS_LINUX + BoolSetting useKeyring = {"/misc/useKeyring", true}; +#endif + IntSetting startUpNotification = {"/misc/startUpNotification", 0}; QStringSetting currentVersion = {"/misc/currentVersion", ""}; BoolSetting loadTwitchMessageHistoryOnConnect = { diff --git a/src/widgets/Window.cpp b/src/widgets/Window.cpp index a5bc714d3..edfac26a9 100644 --- a/src/widgets/Window.cpp +++ b/src/widgets/Window.cpp @@ -1,6 +1,7 @@ #include "widgets/Window.hpp" #include "Application.hpp" +#include "common/Credentials.hpp" #include "common/Version.hpp" #include "controllers/accounts/AccountController.hpp" #include "providers/twitch/TwitchServer.hpp" @@ -103,7 +104,7 @@ bool Window::event(QEvent *event) break; default:; - }; + } return BaseWindow::event(event); } diff --git a/src/widgets/dialogs/IrcConnectionPopup.cpp b/src/widgets/dialogs/IrcConnectionPopup.cpp deleted file mode 100644 index 23b8aa974..000000000 --- a/src/widgets/dialogs/IrcConnectionPopup.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "IrcConnectionPopup.hpp" - -#include "providers/irc/Irc2.hpp" -#include "util/LayoutHelper.hpp" -#include "widgets/helper/EditableModelView.hpp" - -#include -#include - -namespace chatterino { - -IrcConnectionPopup::IrcConnectionPopup(QWidget *parent) - : BaseWindow(parent, BaseWindow::Flags::EnableCustomFrame) -{ - this->setWindowTitle("Edit Irc Connections"); - - // view - auto view = - new EditableModelView(Irc::getInstance().newConnectionModel(this)); - - view->setTitles({"host", "port", "ssl", "user", "nick", "password"}); - view->getTableView()->horizontalHeader()->resizeSection(0, 140); - view->getTableView()->horizontalHeader()->resizeSection(1, 30); - view->getTableView()->horizontalHeader()->resizeSection(2, 30); - - this->setScaleIndependantSize(800, 500); - - view->addButtonPressed.connect([] { - auto unique = IrcServerData{}; - unique.id = Irc::getInstance().uniqueId(); - Irc::getInstance().connections.appendItem(unique); - }); - - // init layout - this->getLayoutContainer()->setLayout(makeLayout({view})); -} - -} // namespace chatterino diff --git a/src/widgets/dialogs/IrcConnectionPopup.hpp b/src/widgets/dialogs/IrcConnectionPopup.hpp deleted file mode 100644 index 8d0ca333e..000000000 --- a/src/widgets/dialogs/IrcConnectionPopup.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "widgets/BaseWindow.hpp" - -namespace chatterino { - -class IrcConnectionPopup : public BaseWindow -{ -public: - IrcConnectionPopup(QWidget *parent); -}; - -} // namespace chatterino diff --git a/src/widgets/dialogs/SelectChannelDialog.cpp b/src/widgets/dialogs/SelectChannelDialog.cpp index bb88902df..123484efc 100644 --- a/src/widgets/dialogs/SelectChannelDialog.cpp +++ b/src/widgets/dialogs/SelectChannelDialog.cpp @@ -6,7 +6,6 @@ #include "util/LayoutCreator.hpp" #include "widgets/Notebook.hpp" #include "widgets/dialogs/IrcConnectionEditor.hpp" -#include "widgets/dialogs/IrcConnectionPopup.hpp" #include "widgets/helper/NotebookTab.hpp" #include diff --git a/src/widgets/settingspages/GeneralPage.cpp b/src/widgets/settingspages/GeneralPage.cpp index 934d4f432..b554e5883 100644 --- a/src/widgets/settingspages/GeneralPage.cpp +++ b/src/widgets/settingspages/GeneralPage.cpp @@ -377,6 +377,15 @@ void GeneralPage::initLayout(SettingsLayout &layout) layout.addTitle("Miscellaneous"); +#ifdef Q_OS_LINUX + if (!getPaths()->isPortable()) + { + layout.addCheckbox( + "Use libsecret/KWallet/Gnome keychain to secure passwords", + s.useKeyring); + } +#endif + layout.addCheckbox("Show moderation messages", s.hideModerationActions, true); layout.addCheckbox("Random username color for users who never set a color",