mirror of
https://github.com/Chatterino/chatterino2.git
synced 2026-08-24 10:04:53 -05:00
dev: remove QtKeychain dependency (#7078)
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
@@ -17,9 +17,6 @@
|
||||
[submodule "lib/rapidjson"]
|
||||
path = lib/rapidjson
|
||||
url = https://github.com/Tencent/rapidjson
|
||||
[submodule "lib/qtkeychain"]
|
||||
path = lib/qtkeychain
|
||||
url = https://github.com/frankosterfeld/qtkeychain
|
||||
[submodule "cmake/sanitizers-cmake"]
|
||||
path = cmake/sanitizers-cmake
|
||||
url = https://github.com/arsenm/sanitizers-cmake
|
||||
|
||||
@@ -17,7 +17,7 @@ The built binary should be exportable from the final image & able to run on your
|
||||
### Debian 13 (trixie) or later
|
||||
|
||||
```sh
|
||||
sudo apt install qt6-base-dev qt6-svg-dev qt6-image-formats-plugins libboost-dev libnotify-dev libssl-dev libsecret-1-dev pkg-config cmake g++ git hunspell
|
||||
sudo apt install qt6-base-dev qt6-svg-dev qt6-image-formats-plugins libboost-dev libnotify-dev libssl-dev pkg-config cmake g++ git hunspell
|
||||
```
|
||||
|
||||
### Arch Linux
|
||||
@@ -39,7 +39,7 @@ sudo zypper install cmake pkgconf boost-devel libboost_json1_89_0-devel desktop-
|
||||
### Gentoo Linux
|
||||
|
||||
```sh
|
||||
doas emerge dev-libs/openssl dev-qt/qt5compat dev-qt/qtbase dev-qt/qtsvg dev-qt/qtimageformats x11-libs/libnotify dev-libs/qtkeychain dev-libs/boost dev-build/cmake app-text/hunspell
|
||||
doas emerge dev-libs/openssl dev-qt/qt5compat dev-qt/qtbase dev-qt/qtsvg dev-qt/qtimageformats x11-libs/libnotify dev-libs/boost dev-build/cmake app-text/hunspell
|
||||
```
|
||||
|
||||
### Fedora 42 and above
|
||||
@@ -67,7 +67,7 @@ nix-shell -p openssl boost qt6.full pkg-config cmake libnotify hunspell
|
||||
```
|
||||
1. Generate build files. To enable Lua plugins in your build add `-DCHATTERINO_PLUGINS=ON` to this command.
|
||||
```sh
|
||||
cmake -DBUILD_WITH_QTKEYCHAIN=OFF -DCHATTERINO_SPELLCHECK=On ..
|
||||
cmake -DCHATTERINO_SPELLCHECK=On ..
|
||||
```
|
||||
1. Build the project
|
||||
```sh
|
||||
|
||||
@@ -20,16 +20,12 @@ option(BUILD_TESTS "Build the tests for Chatterino" OFF)
|
||||
option(BUILD_BENCHMARKS "Build the benchmarks for Chatterino" OFF)
|
||||
option(USE_SYSTEM_PAJLADA_SETTINGS "Use system pajlada settings library" OFF)
|
||||
option(USE_SYSTEM_LIBCOMMUNI "Use system communi library" OFF)
|
||||
option(USE_SYSTEM_QTKEYCHAIN "Use system QtKeychain library" OFF)
|
||||
option(BUILD_WITH_QTKEYCHAIN "Build Chatterino with support for your system key chain" ON)
|
||||
option(USE_SYSTEM_MINIAUDIO "Build Chatterino with your system miniaudio" OFF)
|
||||
option(BUILD_WITH_CRASHPAD "Build chatterino with crashpad" OFF)
|
||||
option(USE_PRECOMPILED_HEADERS "Use precompiled headers (Temporarily not supported on macOS)" ON)
|
||||
option(BUILD_WITH_QT6 "Build with Qt6" On)
|
||||
option(BUILD_WITH_LIBNOTIFY "Build with libnotify" ON)
|
||||
option(CHATTERINO_GENERATE_COVERAGE "Generate coverage files" OFF)
|
||||
# We don't use translations, and we don't want qtkeychain to build translations
|
||||
option(BUILD_TRANSLATIONS "" OFF)
|
||||
option(BUILD_SHARED_LIBS "" OFF)
|
||||
option(CHATTERINO_LTO "Enable LTO for all targets" OFF)
|
||||
# CMake doesn't detect LTO for some compilers (e.g. clang-cl: https://gitlab.kitware.com/cmake/cmake/-/issues/21635),
|
||||
@@ -196,32 +192,6 @@ else()
|
||||
add_subdirectory("${LIBCOMMUNI_ROOT_LIB_FOLDER}" EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
if (BUILD_WITH_QTKEYCHAIN)
|
||||
# Link QtKeychain statically
|
||||
if (USE_SYSTEM_QTKEYCHAIN)
|
||||
find_package(Qt${MAJOR_QT_VERSION}Keychain REQUIRED)
|
||||
else()
|
||||
set(QTKEYCHAIN_ROOT_LIB_FOLDER "${CMAKE_SOURCE_DIR}/lib/qtkeychain")
|
||||
if (NOT EXISTS "${QTKEYCHAIN_ROOT_LIB_FOLDER}/CMakeLists.txt")
|
||||
message(FATAL_ERROR "Submodules probably not loaded, unable to find lib/qtkeychain/CMakeLists.txt")
|
||||
endif()
|
||||
|
||||
set(_prev_testing ${BUILD_TESTING})
|
||||
set(BUILD_TESTING Off)
|
||||
add_subdirectory("${QTKEYCHAIN_ROOT_LIB_FOLDER}" EXCLUDE_FROM_ALL)
|
||||
set(BUILD_TESTING ${_prev_testing})
|
||||
|
||||
if (NOT TARGET qt${MAJOR_QT_VERSION}keychain)
|
||||
message(FATAL_ERROR "qt${MAJOR_QT_VERSION}keychain target was not created :@")
|
||||
endif()
|
||||
if (MSVC AND "${MAJOR_QT_VERSION}" STREQUAL "5")
|
||||
target_compile_definitions(qt5keychain PRIVATE UNICODE)
|
||||
target_compile_options(qt5keychain PRIVATE /utf-8)
|
||||
set_target_properties(qt5keychain PROPERTIES CXX_STANDARD 17)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (BUILD_TESTS)
|
||||
include(GoogleTest)
|
||||
# For MSVC: Prevent overriding the parent project's compiler/linker settings
|
||||
|
||||
Submodule lib/qtkeychain deleted from 53a8e6a31f
@@ -1,20 +0,0 @@
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+6
-20
@@ -26,8 +26,6 @@ set(SOURCE_FILES
|
||||
common/ChatterinoSetting.hpp
|
||||
common/ChatterSet.cpp
|
||||
common/ChatterSet.hpp
|
||||
common/Credentials.cpp
|
||||
common/Credentials.hpp
|
||||
common/Env.cpp
|
||||
common/Env.hpp
|
||||
common/LastMessageLineStyle.hpp
|
||||
@@ -888,6 +886,12 @@ list(APPEND SOURCE_FILES ${RES_AUTOGEN_FILES})
|
||||
|
||||
add_library(${LIBRARY_PROJECT} OBJECT ${SOURCE_FILES})
|
||||
|
||||
if (APPLE)
|
||||
target_link_libraries(${LIBRARY_PROJECT} PRIVATE
|
||||
"$<LINK_LIBRARY:FRAMEWORK,Security>"
|
||||
)
|
||||
endif ()
|
||||
|
||||
if(CHATTERINO_PLUGINS)
|
||||
target_compile_definitions(${LIBRARY_PROJECT}
|
||||
PUBLIC
|
||||
@@ -916,7 +920,6 @@ if (CHATTERINO_GENERATE_COVERAGE)
|
||||
EXCLUDE "lib/lua/*"
|
||||
EXCLUDE "lib/magic_enum/*"
|
||||
EXCLUDE "lib/miniaudio/*"
|
||||
EXCLUDE "lib/qtkeychain/*"
|
||||
EXCLUDE "lib/rapidjson/*"
|
||||
EXCLUDE "lib/semver/*"
|
||||
EXCLUDE "lib/serialize/*"
|
||||
@@ -977,18 +980,6 @@ if (CHATTERINO_ALLOW_PRIVATE_QT_API)
|
||||
CHATTERINO_WITH_PRIVATE_QT_API)
|
||||
endif()
|
||||
|
||||
if (BUILD_WITH_QTKEYCHAIN)
|
||||
target_link_libraries(${LIBRARY_PROJECT}
|
||||
PUBLIC
|
||||
qt${MAJOR_QT_VERSION}keychain
|
||||
)
|
||||
else()
|
||||
target_compile_definitions(${LIBRARY_PROJECT}
|
||||
PUBLIC
|
||||
NO_QTKEYCHAIN
|
||||
)
|
||||
endif()
|
||||
|
||||
# Set the output of TARGET to be
|
||||
# - CMAKE_BIN_DIR/lib for libraries
|
||||
# - CMAKE_BIN_DIR/bin for BINARIES
|
||||
@@ -1200,11 +1191,6 @@ set(_c2_qt_defs
|
||||
target_compile_definitions(${VERSION_PROJECT} PUBLIC ${_c2_qt_defs})
|
||||
target_compile_definitions(${LIBRARY_PROJECT} PUBLIC ${_c2_qt_defs})
|
||||
|
||||
if (USE_SYSTEM_QTKEYCHAIN)
|
||||
target_compile_definitions(${LIBRARY_PROJECT} PUBLIC
|
||||
CMAKE_BUILD
|
||||
)
|
||||
endif ()
|
||||
if (WIN32)
|
||||
target_compile_definitions(${LIBRARY_PROJECT} PUBLIC
|
||||
USEWINSDK
|
||||
|
||||
@@ -1,274 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019 Contributors to Chatterino <https://chatterino.com>
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "common/Credentials.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "common/Modes.hpp"
|
||||
#include "debug/AssertInGuiThread.hpp"
|
||||
#include "singletons/Paths.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "util/CombinePath.hpp"
|
||||
#include "util/Variant.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QSaveFile>
|
||||
#include <QStringBuilder>
|
||||
|
||||
#include <variant>
|
||||
|
||||
#ifndef NO_QTKEYCHAIN
|
||||
# ifdef CMAKE_BUILD
|
||||
# include "qt6keychain/keychain.h"
|
||||
# else
|
||||
# include <qtkeychain/keychain.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace chatterino;
|
||||
|
||||
QString formatName(const QString &provider, const QString &name)
|
||||
{
|
||||
assert(!provider.contains(":"));
|
||||
return u"chatterino:" % provider % u':' % name;
|
||||
}
|
||||
|
||||
bool useKeyring()
|
||||
{
|
||||
#ifdef NO_QTKEYCHAIN
|
||||
return false;
|
||||
#endif
|
||||
if (Modes::instance().isPortable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
return getSettings()->useKeyring;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Insecure storage:
|
||||
QString insecurePath()
|
||||
{
|
||||
return combinePath(getApp()->getPaths().settingsDirectory,
|
||||
"credentials.json");
|
||||
}
|
||||
|
||||
QJsonDocument loadInsecure()
|
||||
{
|
||||
QFile file(insecurePath());
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return QJsonDocument::fromJson(file.readAll());
|
||||
}
|
||||
|
||||
void storeInsecure(const QJsonDocument &doc)
|
||||
{
|
||||
QSaveFile file(insecurePath());
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
return;
|
||||
}
|
||||
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, QApplication::instance(), [] {
|
||||
storeInsecure(insecureInstance());
|
||||
isQueued = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// QKeychain runs jobs asyncronously, so we have to assure that set/erase
|
||||
// jobs gets executed in order.
|
||||
struct SetJob {
|
||||
QString name;
|
||||
QString credential;
|
||||
};
|
||||
|
||||
struct EraseJob {
|
||||
QString name;
|
||||
};
|
||||
|
||||
using Job = std::variant<SetJob, EraseJob>;
|
||||
|
||||
std::queue<Job> &jobQueue()
|
||||
{
|
||||
static std::queue<Job> jobs;
|
||||
return jobs;
|
||||
}
|
||||
|
||||
void runNextJob()
|
||||
{
|
||||
#ifndef NO_QTKEYCHAIN
|
||||
auto &&queue = jobQueue();
|
||||
|
||||
if (!queue.empty())
|
||||
{
|
||||
// we were gonna use std::visit here but macos is shit
|
||||
|
||||
auto &&item = queue.front();
|
||||
|
||||
std::visit(
|
||||
variant::Overloaded{
|
||||
[](const SetJob &set) {
|
||||
auto *job = new QKeychain::WritePasswordJob("chatterino");
|
||||
job->setAutoDelete(true);
|
||||
job->setKey(set.name);
|
||||
job->setTextData(set.credential);
|
||||
QObject::connect(job, &QKeychain::Job::finished,
|
||||
QApplication::instance(), [](auto) {
|
||||
runNextJob();
|
||||
});
|
||||
job->start();
|
||||
},
|
||||
[](const EraseJob &erase) {
|
||||
auto *job = new QKeychain::DeletePasswordJob("chatterino");
|
||||
job->setAutoDelete(true);
|
||||
job->setKey(erase.name);
|
||||
QObject::connect(job, &QKeychain::Job::finished,
|
||||
QApplication::instance(), [](auto) {
|
||||
runNextJob();
|
||||
});
|
||||
job->start();
|
||||
},
|
||||
},
|
||||
item);
|
||||
|
||||
queue.pop();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void queueJob(Job &&job)
|
||||
{
|
||||
auto &&queue = jobQueue();
|
||||
|
||||
queue.push(std::move(job));
|
||||
if (queue.size() == 1)
|
||||
{
|
||||
runNextJob();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
Credentials &Credentials::instance()
|
||||
{
|
||||
static Credentials creds;
|
||||
return creds;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
void Credentials::get(const QString &provider, const QString &name_,
|
||||
QObject *receiver,
|
||||
std::function<void(const QString &)> &&onLoaded)
|
||||
{
|
||||
assertInGuiThread();
|
||||
|
||||
auto name = formatName(provider, name_);
|
||||
|
||||
if (useKeyring())
|
||||
{
|
||||
#ifndef NO_QTKEYCHAIN
|
||||
// if NO_QTKEYCHAIN is set, then this code is never used either way
|
||||
auto *job = new QKeychain::ReadPasswordJob("chatterino");
|
||||
job->setAutoDelete(true);
|
||||
job->setKey(name);
|
||||
QObject::connect(
|
||||
job, &QKeychain::Job::finished, receiver,
|
||||
[job, onLoaded = std::move(onLoaded)](auto) mutable {
|
||||
onLoaded(job->textData());
|
||||
},
|
||||
Qt::DirectConnection);
|
||||
job->start();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto &instance = insecureInstance();
|
||||
|
||||
onLoaded(instance[name].toString());
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
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 = formatName(provider, name_);
|
||||
|
||||
if (useKeyring())
|
||||
{
|
||||
queueJob(SetJob{name, credential});
|
||||
}
|
||||
else
|
||||
{
|
||||
auto &instance = insecureInstance();
|
||||
|
||||
auto obj = instance.object();
|
||||
obj[name] = credential;
|
||||
instance.setObject(obj);
|
||||
|
||||
queueInsecureSave();
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
void Credentials::erase(const QString &provider, const QString &name_)
|
||||
{
|
||||
assertInGuiThread();
|
||||
|
||||
auto name = formatName(provider, name_);
|
||||
|
||||
if (useKeyring())
|
||||
{
|
||||
queueJob(EraseJob{name});
|
||||
}
|
||||
else
|
||||
{
|
||||
auto &instance = insecureInstance();
|
||||
|
||||
if (auto it = instance.object().find(name);
|
||||
it != instance.object().end())
|
||||
{
|
||||
instance.object().erase(it);
|
||||
}
|
||||
|
||||
queueInsecureSave();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -1,29 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019 Contributors to Chatterino <https://chatterino.com>
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Credentials
|
||||
{
|
||||
public:
|
||||
static Credentials &instance();
|
||||
|
||||
void get(const QString &provider, const QString &name, QObject *receiver,
|
||||
std::function<void(const QString &)> &&onLoaded);
|
||||
void set(const QString &provider, const QString &name,
|
||||
const QString &credential);
|
||||
void erase(const QString &provider, const QString &name);
|
||||
|
||||
private:
|
||||
Credentials() = default;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -726,9 +726,6 @@ 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", ""};
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "Application.hpp"
|
||||
#include "common/Args.hpp"
|
||||
#include "common/Common.hpp"
|
||||
#include "common/Credentials.hpp"
|
||||
#include "common/Modes.hpp"
|
||||
#include "common/QLogging.hpp"
|
||||
#include "common/Version.hpp"
|
||||
|
||||
@@ -121,11 +121,6 @@ AboutPage::AboutPage()
|
||||
addLicense(form.getElement(), "Pajlada/Serialize",
|
||||
"https://github.com/pajlada/serialize",
|
||||
":/licenses/pajlada_serialize.txt");
|
||||
#ifndef NO_QTKEYCHAIN
|
||||
addLicense(form.getElement(), "QtKeychain",
|
||||
"https://github.com/frankosterfeld/qtkeychain",
|
||||
":/licenses/qtkeychain.txt");
|
||||
#endif
|
||||
addLicense(form.getElement(), "lrucache",
|
||||
"https://github.com/lamerman/cpp-lru-cache",
|
||||
":/licenses/lrucache.txt");
|
||||
|
||||
@@ -1364,16 +1364,6 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
||||
->setTooltip("When possible, restart Chatterino if the program crashes")
|
||||
->addTo(layout);
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(NO_QTKEYCHAIN)
|
||||
if (!getApp()->getPaths().isPortable())
|
||||
{
|
||||
SettingWidget::checkbox(
|
||||
"Use libsecret/KWallet/Gnome keychain to secure passwords",
|
||||
s.useKeyring)
|
||||
->addTo(layout);
|
||||
}
|
||||
#endif
|
||||
|
||||
SettingWidget::inverseCheckbox("Show moderation messages",
|
||||
s.hideModerationActions)
|
||||
->setTooltip(
|
||||
|
||||
Reference in New Issue
Block a user