diff --git a/src/apps/deskflow-gui/MainWindow.cpp b/src/apps/deskflow-gui/MainWindow.cpp
index ffeca7fdd..959d6f758 100644
--- a/src/apps/deskflow-gui/MainWindow.cpp
+++ b/src/apps/deskflow-gui/MainWindow.cpp
@@ -1,6 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
- * SPDX-FileCopyrightText: (C) 2024 Chris Rizzitello
+ * SPDX-FileCopyrightText: (C) 2024 - 2025 Chris Rizzitello
* SPDX-FileCopyrightText: (C) 2012 - 2024 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2008 Volker Lanz
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@@ -13,6 +13,7 @@
#include "dialogs/ServerConfigDialog.h"
#include "dialogs/SettingsDialog.h"
+#include "base/String.h"
#include "common/constants.h"
#include "gui/Logger.h"
#include "gui/config/ConfigScopes.h"
@@ -23,7 +24,9 @@
#include "gui/string_utils.h"
#include "gui/style_utils.h"
#include "gui/styles.h"
-#include "gui/tls/TlsFingerprint.h"
+#include "net/FingerprintDatabase.h"
+#include "net/SecureUtils.h"
+
#include "platform/wayland.h"
#if defined(Q_OS_LINUX)
@@ -466,7 +469,29 @@ void MainWindow::updateSize()
void MainWindow::showMyFingerprint()
{
- QMessageBox::information(this, "TLS fingerprint", TlsFingerprint::local().readFirst());
+ auto localPath = QStringLiteral("%1/%2").arg(getTlsPath(), kFingerprintLocalFilename).toStdString();
+ if (!QFile::exists(QString::fromStdString(localPath))) {
+ QMessageBox::information(
+ this, tr("TLS fingerprint Error"),
+ tr("Unable to read localfinger print: %1\n You may want to regenerate your keys.")
+ .arg(QString::fromStdString(localPath))
+ );
+ return;
+ }
+
+ deskflow::FingerprintDatabase db;
+ db.read(localPath);
+ if (db.fingerprints().empty()) {
+ QMessageBox::information(
+ this, tr("TLS fingerprint Error"),
+ tr("Unable to read localDatabase\n You may want to regenerate your keys.")
+ .arg(QString::fromStdString(localPath))
+ );
+ return;
+ }
+
+ const auto fingerprint = QString::fromStdString(deskflow::formatSSLFingerprint(db.fingerprints().front().data));
+ QMessageBox::information(this, "TLS fingerprint", fingerprint);
}
void MainWindow::setModeServer()
@@ -669,8 +694,13 @@ void MainWindow::checkFingerprint(const QString &line)
return;
}
- auto fingerprint = match.captured(1);
- if (TlsFingerprint::trustedServers().isTrusted(fingerprint)) {
+ auto localPath = QStringLiteral("%1/%2").arg(getTlsPath(), kFingerprintTrustedServersFilename).toStdString();
+
+ deskflow::FingerprintDatabase db;
+ db.read(localPath);
+
+ const deskflow::FingerprintData fingerprint{"sha1", deskflow::string::fromHex(match.captured(1).toStdString())};
+ if (db.isTrusted(fingerprint)) {
return;
}
@@ -690,13 +720,13 @@ void MainWindow::checkFingerprint(const QString &line)
"you're expecting (it could be a malicious user).
"
"Do you want to trust this fingerprint for future "
"connections? If you don't, a connection cannot be made.
")
- .arg(fingerprint),
+ .arg(QString::fromStdString(deskflow::formatSSLFingerprint(fingerprint.data))),
QMessageBox::Yes | QMessageBox::No
);
if (fingerprintReply == QMessageBox::Yes) {
- // start core process again after trusting fingerprint.
- TlsFingerprint::trustedServers().trust(fingerprint);
+ db.addTrusted(fingerprint);
+ db.write(localPath);
m_coreProcess.start();
}
@@ -897,7 +927,8 @@ void MainWindow::updateLocalFingerprint()
{
bool fingerprintExists = false;
try {
- fingerprintExists = TlsFingerprint::local().fileExists();
+ auto localPath = QStringLiteral("%1/%2").arg(getTlsPath(), kFingerprintLocalFilename).toStdString();
+ fingerprintExists = QFile::exists(QString::fromStdString(localPath));
} catch (const std::exception &e) {
qDebug() << e.what();
qFatal() << "failed to check if fingerprint exists";
@@ -1026,3 +1057,9 @@ void MainWindow::showAndActivate()
m_actionRestore->setVisible(false);
m_actionMinimize->setVisible(true);
}
+
+QString MainWindow::getTlsPath()
+{
+ CoreTool coreTool;
+ return QStringLiteral("%1/%2").arg(coreTool.getProfileDir(), kSslDir);
+}
diff --git a/src/apps/deskflow-gui/MainWindow.h b/src/apps/deskflow-gui/MainWindow.h
index 239ca9a95..d6f07d0ab 100644
--- a/src/apps/deskflow-gui/MainWindow.h
+++ b/src/apps/deskflow-gui/MainWindow.h
@@ -164,6 +164,8 @@ private:
void updateStatus();
void showAndActivate();
+ QString getTlsPath();
+
VersionChecker m_versionChecker;
bool m_secureSocket = false;
deskflow::gui::config::ServerConfigDialogState m_serverConfigDialogState;
diff --git a/src/lib/common/constants.h.in b/src/lib/common/constants.h.in
index e5a7db4ce..266362128 100644
--- a/src/lib/common/constants.h.in
+++ b/src/lib/common/constants.h.in
@@ -29,4 +29,5 @@ const auto kDebugBuild = false;
const auto kSslDir = "tls";
const auto kCertificateFilename = "@CMAKE_PROJECT_NAME@.pem";
+const auto kFingerprintLocalFilename = "local-fingerprint";
const auto kFingerprintTrustedServersFilename = "trusted-servers";
diff --git a/src/lib/gui/CMakeLists.txt b/src/lib/gui/CMakeLists.txt
index 2c9435a1d..210d78e80 100644
--- a/src/lib/gui/CMakeLists.txt
+++ b/src/lib/gui/CMakeLists.txt
@@ -77,8 +77,6 @@ add_library(${target} STATIC
proxy/QSettingsProxy.h
tls/TlsCertificate.cpp
tls/TlsCertificate.h
- tls/TlsFingerprint.cpp
- tls/TlsFingerprint.h
tls/TlsUtility.cpp
tls/TlsUtility.h
validators/AliasValidator.cpp
diff --git a/src/lib/gui/tls/TlsCertificate.cpp b/src/lib/gui/tls/TlsCertificate.cpp
index 0c61f40e1..1f9e3e323 100644
--- a/src/lib/gui/tls/TlsCertificate.cpp
+++ b/src/lib/gui/tls/TlsCertificate.cpp
@@ -7,9 +7,10 @@
#include "TlsCertificate.h"
-#include "TlsFingerprint.h"
-
#include "common/constants.h"
+#include "gui/core/CoreTool.h"
+#include "net/FingerprintData.h"
+#include "net/FingerprintDatabase.h"
#include "net/SecureUtils.h"
#include
@@ -47,7 +48,18 @@ bool TlsCertificate::generateFingerprint(const QString &certificateFilename)
try {
auto fingerprint =
deskflow::pemFileCertFingerprint(certificateFilename.toStdString(), deskflow::FingerprintType::SHA1);
- TlsFingerprint::local().trust(QString::fromStdString(deskflow::formatSSLFingerprint(fingerprint)), false);
+
+ CoreTool coreTool;
+ QString profileDir = coreTool.getProfileDir();
+
+ auto localPath = QStringLiteral("%1/%2/%3").arg(profileDir, kSslDir, kFingerprintLocalFilename).toStdString();
+
+ const deskflow::FingerprintData data{"sha1", fingerprint};
+
+ deskflow::FingerprintDatabase db;
+ db.addTrusted(data);
+ db.write(localPath);
+
qDebug("tls fingerprint generated");
return true;
} catch (const std::exception &e) {
diff --git a/src/lib/gui/tls/TlsFingerprint.cpp b/src/lib/gui/tls/TlsFingerprint.cpp
deleted file mode 100644
index bed144609..000000000
--- a/src/lib/gui/tls/TlsFingerprint.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Deskflow -- mouse and keyboard sharing utility
- * SPDX-FileCopyrightText: (C) 2015 Symless Ltd.
- * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
- */
-
-#include "TlsFingerprint.h"
-
-#include "gui/core/CoreTool.h"
-
-#include
-#include
-
-// TODO: Reduce duplication of these strings between here and SecureSocket.cpp
-static const char kDirName[] = "tls";
-static const char kLocalFilename[] = "local-fingerprint";
-static const char kTrustedServersFilename[] = "trusted-servers";
-static const char kTrustedClientsFilename[] = "trusted-clients";
-
-TlsFingerprint::TlsFingerprint(const QString &filename) : m_Filename(filename)
-{
-}
-
-void TlsFingerprint::trust(const QString &fingerprintText, bool append) const
-{
- TlsFingerprint::persistDirectory();
-
- QIODevice::OpenMode openMode;
- if (append) {
- openMode = QIODevice::Append;
- } else {
- openMode = QIODevice::WriteOnly;
- }
-
- QFile file(filePath());
- if (file.open(openMode)) {
- QTextStream out(&file);
- out << fingerprintText << "\n";
- file.close();
- }
-}
-
-bool TlsFingerprint::fileExists() const
-{
- QString dirName = TlsFingerprint::directoryPath();
- if (!QDir(dirName).exists()) {
- return false;
- }
-
- QFile file(filePath());
- return file.exists();
-}
-
-bool TlsFingerprint::isTrusted(const QString &fingerprintText) const
-{
- const QStringList list = readList();
- for (const auto &trusted : list) {
- if (trusted == fingerprintText) {
- return true;
- }
- }
- return false;
-}
-
-QStringList TlsFingerprint::readList(const int readTo) const
-{
- QStringList list;
-
- QString dirName = TlsFingerprint::directoryPath();
- if (!QDir(dirName).exists()) {
- return list;
- }
-
- QFile file(filePath());
-
- if (file.open(QIODevice::ReadOnly)) {
- QTextStream in(&file);
- while (!in.atEnd()) {
- list.append(in.readLine());
- if (list.size() == readTo) {
- break;
- }
- }
- file.close();
- }
-
- return list;
-}
-
-QString TlsFingerprint::readFirst() const
-{
- QStringList list = readList(1);
- return list.at(0);
-}
-
-QString TlsFingerprint::filePath() const
-{
- QString dir = TlsFingerprint::directoryPath();
- return QString("%1/%2").arg(dir, m_Filename);
-}
-
-void TlsFingerprint::persistDirectory()
-{
- QDir dir(TlsFingerprint::directoryPath());
- if (!dir.exists()) {
- dir.mkpath(".");
- }
-}
-
-QString TlsFingerprint::directoryPath()
-{
- CoreTool coreTool;
- QString profileDir = coreTool.getProfileDir();
-
- return QString("%1/%2").arg(profileDir, kDirName);
-}
-
-TlsFingerprint TlsFingerprint::local()
-{
- return TlsFingerprint(kLocalFilename);
-}
-
-TlsFingerprint TlsFingerprint::trustedServers()
-{
- return TlsFingerprint(kTrustedServersFilename);
-}
-
-TlsFingerprint TlsFingerprint::trustedClients()
-{
- return TlsFingerprint(kTrustedClientsFilename);
-}
diff --git a/src/lib/gui/tls/TlsFingerprint.h b/src/lib/gui/tls/TlsFingerprint.h
deleted file mode 100644
index e196a5cc4..000000000
--- a/src/lib/gui/tls/TlsFingerprint.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Deskflow -- mouse and keyboard sharing utility
- * SPDX-FileCopyrightText: (C) 2015 Symless Ltd.
- * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
- */
-
-#pragma once
-
-#include
-
-class TlsFingerprint
-{
-private:
- explicit TlsFingerprint(const QString &filename);
-
-public:
- static TlsFingerprint local();
- static TlsFingerprint trustedServers();
- static TlsFingerprint trustedClients();
- static QString directoryPath();
- static QString localFingerprint();
- static bool localFingerprintExists();
- static void persistDirectory();
-
- void trust(const QString &fingerprintText, bool append = true) const;
- bool isTrusted(const QString &fingerprintText) const;
- QStringList readList(const int readTo = -1) const;
- QString readFirst() const;
- QString filePath() const;
- bool fileExists() const;
-
-private:
- QString m_Filename;
-};
diff --git a/src/lib/net/SecureSocket.cpp b/src/lib/net/SecureSocket.cpp
index 94234bd28..7ba987869 100644
--- a/src/lib/net/SecureSocket.cpp
+++ b/src/lib/net/SecureSocket.cpp
@@ -15,6 +15,7 @@
#include "base/TMethodEventJob.h"
#include "common/constants.h"
#include "mt/Lock.h"
+#include "net/FingerprintDatabase.h"
#include "net/TCPSocket.h"
#include "net/TSocketMultiplexerMethodJob.h"
#include
@@ -621,34 +622,35 @@ bool SecureSocket::verifyCertFingerprint()
return false;
}
- auto fingerprint = deskflow::formatSSLFingerprint(fingerprint_raw);
- LOG((CLOG_NOTE "server fingerprint: %s", fingerprint.c_str()));
+ LOG((CLOG_NOTE "server fingerprint: %s", deskflow::formatSSLFingerprint(fingerprint_raw).c_str()));
- std::string trustedServersFilename;
- trustedServersFilename = deskflow::string::sprintf(
+ std::string trustedServersFilename = deskflow::string::sprintf(
"%s/%s/%s", ARCH->getProfileDirectory().c_str(), kSslDir, kFingerprintTrustedServersFilename
);
// check if this fingerprint exist
std::string fileLine;
std::ifstream file;
- file.open(deskflow::filesystem::path(trustedServersFilename));
- bool isValid = false;
- if (file.is_open()) {
- while (!file.eof()) {
- getline(file, fileLine);
- if (!fileLine.empty() && !fileLine.compare(fingerprint)) {
- isValid = true;
- break;
- }
- }
+ deskflow::openUtf8Path(file, trustedServersFilename);
+ deskflow::FingerprintDatabase db;
+ db.read(trustedServersFilename);
+ if (!db.fingerprints().empty()) {
+ LOG((CLOG_NOTE "read %d fingerprints from %s", db.fingerprints().size(), trustedServersFilename.c_str()));
} else {
- LOG((CLOG_ERR "fail to open trusted fingerprints file: %s", trustedServersFilename.c_str()));
+ LOG((CLOG_ERR "failed to open trusted fingerprints file: %s", trustedServersFilename.c_str()));
+ return false;
}
- file.close();
- return isValid;
+ deskflow::FingerprintData fingerprint{"sha1", fingerprint_raw};
+
+ if (!db.isTrusted(fingerprint)) {
+ LOG((CLOG_WARN "fingerprint does not match trusted fingerprint"));
+ return false;
+ }
+
+ LOG((CLOG_NOTE "fingerprint matches trusted fingerprint"));
+ return true;
}
ISocketMultiplexerJob *SecureSocket::serviceConnect(ISocketMultiplexerJob *job, bool, bool write, bool error)