dev: remove QtKeychain dependency (#7078)

Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
teknsl
2026-07-04 09:34:07 +00:00
committed by GitHub
parent 305149a795
commit 0b28fbcba6
12 changed files with 9 additions and 399 deletions
-3
View File
@@ -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
+3 -3
View File
@@ -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
-30
View File
@@ -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
-20
View File
@@ -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
View File
@@ -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
-274
View File
@@ -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
-29
View File
@@ -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
-3
View File
@@ -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", ""};
-1
View File
@@ -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"
-5
View File
@@ -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");
-10
View File
@@ -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(