From 8f219b735e44056edf7ef2529a8948e35592869d Mon Sep 17 00:00:00 2001 From: Vamshi Maskuri <117595548+varshith257@users.noreply.github.com> Date: Tue, 28 Jan 2025 23:13:46 +0530 Subject: [PATCH] feat!: Add support for FingerPrintDatabase --- src/lib/base/CMakeLists.txt | 1 + src/lib/base/finally.h | 51 ++++++++++ src/lib/io/CMakeLists.txt | 10 ++ src/lib/io/filesystem.cpp | 57 +++++++++++ src/lib/io/filesystem.h | 28 +++++ src/lib/io/win32/encoding_utilities.cpp | 35 +++++++ src/lib/io/win32/encoding_utilities.h | 21 ++++ src/lib/net/CMakeLists.txt | 6 +- src/lib/net/FingerprintData.cpp | 45 +++++++++ src/lib/net/FingerprintData.h | 38 +++++++ src/lib/net/FingerprintDatabase.cpp | 129 ++++++++++++++++++++++++ src/lib/net/FingerprintDatabase.h | 46 +++++++++ 12 files changed, 466 insertions(+), 1 deletion(-) create mode 100644 src/lib/base/finally.h create mode 100644 src/lib/io/filesystem.cpp create mode 100644 src/lib/io/filesystem.h create mode 100644 src/lib/io/win32/encoding_utilities.cpp create mode 100644 src/lib/io/win32/encoding_utilities.h create mode 100644 src/lib/net/FingerprintData.cpp create mode 100644 src/lib/net/FingerprintData.h create mode 100644 src/lib/net/FingerprintDatabase.cpp create mode 100644 src/lib/net/FingerprintDatabase.h diff --git a/src/lib/base/CMakeLists.txt b/src/lib/base/CMakeLists.txt index ab54b91d9..9cbf44029 100644 --- a/src/lib/base/CMakeLists.txt +++ b/src/lib/base/CMakeLists.txt @@ -15,6 +15,7 @@ add_library(base STATIC FunctionEventJob.h FunctionJob.cpp FunctionJob.h + finally.h IEventJob.h IEventQueue.h IEventQueueBuffer.h diff --git a/src/lib/base/finally.h b/src/lib/base/finally.h new file mode 100644 index 000000000..918059b1f --- /dev/null +++ b/src/lib/base/finally.h @@ -0,0 +1,51 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2024 Deskflow Developers + * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception + */ + +#pragma once + +#include + +namespace deskflow { + +// this implements a common pattern of executing an action at the end of function + +template class FinalAction +{ +public: + FinalAction() noexcept + { + } + + FinalAction(Callable callable) noexcept : callable_{callable} + { + } + + ~FinalAction() noexcept + { + if (!invoked_) { + callable_(); + } + } + + FinalAction(FinalAction &&other) noexcept : callable_{std::move(other.callable_)} + { + std::swap(invoked_, other.invoked_); + } + + FinalAction(const FinalAction &) = delete; + FinalAction &operator=(const FinalAction &) = delete; + +private: + bool invoked_ = false; + Callable callable_; +}; + +template inline FinalAction finally(Callable &&callable) noexcept +{ + return FinalAction(std::forward(callable)); +} + +} // namespace deskflow diff --git a/src/lib/io/CMakeLists.txt b/src/lib/io/CMakeLists.txt index 0f6adac25..955b9ba58 100644 --- a/src/lib/io/CMakeLists.txt +++ b/src/lib/io/CMakeLists.txt @@ -4,6 +4,8 @@ # SPDX-License-Identifier: MIT add_library(io STATIC + filesystem.cpp + filesystem.h IStream.h StreamBuffer.cpp StreamBuffer.h @@ -12,3 +14,11 @@ add_library(io STATIC XIO.cpp XIO.h ) + +# Windows-specific files +if(WIN32) + target_sources(io PRIVATE + win32/encoding_utilities.cpp + win32/encoding_utilities.h + ) +endif() diff --git a/src/lib/io/filesystem.cpp b/src/lib/io/filesystem.cpp new file mode 100644 index 000000000..e3df9d6f1 --- /dev/null +++ b/src/lib/io/filesystem.cpp @@ -0,0 +1,57 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2024 Deskflow Developers + * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception + */ + +// TODO: remove dead code if not used in PR #7931 + +#include "filesystem.h" + +#include "common/common.h" + +#if SYSAPI_WIN32 +#include "io/win32/encoding_utilities.h" +#endif + +#include + +namespace deskflow { + +namespace { + +template void openUtf8PathImpl(Stream &stream, const fs::path &path, std::ios_base::openmode mode) +{ + stream.open(path.native().c_str(), mode); +} + +} // namespace + +void openUtf8Path(std::ifstream &stream, const fs::path &path, std::ios_base::openmode mode) +{ + openUtf8PathImpl(stream, path, mode); +} + +void openUtf8Path(std::ofstream &stream, const fs::path &path, std::ios_base::openmode mode) +{ + openUtf8PathImpl(stream, path, mode); +} + +void openUtf8Path(std::fstream &stream, const fs::path &path, std::ios_base::openmode mode) +{ + openUtf8PathImpl(stream, path, mode); +} + +std::FILE *fopenUtf8Path(const fs::path &path, const std::string &mode) +{ +#if SYSAPI_WIN32 + std::wstring wpath = path.native(); + std::wstring wmode(mode.begin(), mode.end()); + + return _wfopen(wpath.c_str(), wmode.c_str()); +#else + return std::fopen(path.native().c_str(), mode.c_str()); +#endif +} + +} // namespace deskflow diff --git a/src/lib/io/filesystem.h b/src/lib/io/filesystem.h new file mode 100644 index 000000000..62abd986b --- /dev/null +++ b/src/lib/io/filesystem.h @@ -0,0 +1,28 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2024 Deskflow Developers + * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception + */ + +// TODO: remove dead code if not used in PR #7931 + +#pragma once + +#include +#include +#include +#include + +namespace deskflow { + +namespace fs = std::filesystem; + +void openUtf8Path(std::ifstream &stream, const fs::path &path, std::ios_base::openmode mode = std::ios_base::in); +void openUtf8Path(std::ofstream &stream, const fs::path &path, std::ios_base::openmode mode = std::ios_base::out); +void openUtf8Path( + std::fstream &stream, const fs::path &path, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out +); + +std::FILE *fopenUtf8Path(const fs::path &path, const std::string &mode); + +} // namespace deskflow diff --git a/src/lib/io/win32/encoding_utilities.cpp b/src/lib/io/win32/encoding_utilities.cpp new file mode 100644 index 000000000..a9e545ba4 --- /dev/null +++ b/src/lib/io/win32/encoding_utilities.cpp @@ -0,0 +1,35 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2024 Deskflow Developers + * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception + */ + +// TODO: remove dead code if not used in PR #7931 + +#include "encoding_utilities.h" + +#include + +namespace deskflow { + +// TODO: use this function in PR #7931 or delete it +std::string winWcharToUtf8(const WCHAR *utfStr) +{ + int utfLength = lstrlenW(utfStr); + int mbLength = WideCharToMultiByte(CP_UTF8, 0, utfStr, utfLength, NULL, 0, NULL, NULL); + std::string mbStr(mbLength, 0); + WideCharToMultiByte(CP_UTF8, 0, utfStr, utfLength, &mbStr[0], mbLength, NULL, NULL); + return mbStr; +} + +// TODO: use this function in PR #7931 or delete it +std::vector utf8ToWinChar(const std::string &str) +{ + int result_len = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), NULL, 0); + std::vector result; + result.resize(result_len + 1, 0); + MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), result.data(), result_len); + return result; +} + +} // namespace deskflow diff --git a/src/lib/io/win32/encoding_utilities.h b/src/lib/io/win32/encoding_utilities.h new file mode 100644 index 000000000..e18a7623c --- /dev/null +++ b/src/lib/io/win32/encoding_utilities.h @@ -0,0 +1,21 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2024 Deskflow Developers + * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception + */ + +// TODO: remove dead code if not used in PR #7931 + +#pragma once + +#include +#include + +#include + +namespace deskflow { + +std::string winWcharToUtf8(const WCHAR *utfStr); +std::vector utf8ToWinChar(const std::string &str); + +} // namespace deskflow diff --git a/src/lib/net/CMakeLists.txt b/src/lib/net/CMakeLists.txt index 165b521e2..bca356d27 100644 --- a/src/lib/net/CMakeLists.txt +++ b/src/lib/net/CMakeLists.txt @@ -4,6 +4,10 @@ # SPDX-License-Identifier: MIT add_library(net STATIC + FingerprintData.cpp + FingerprintData.h + FingerprintDatabase.cpp + FingerprintDatabase.h IDataSocket.cpp IDataSocket.h IListenSocket.h @@ -51,5 +55,5 @@ target_link_libraries( PRIVATE mt io) if(WIN32) - target_link_libraries(net PRIVATE Crypt32 ws2_32) + target_link_libraries(net PRIVATE Crypt32 ws2_32 OpenSSL::applink) endif() diff --git a/src/lib/net/FingerprintData.cpp b/src/lib/net/FingerprintData.cpp new file mode 100644 index 000000000..ec56b81ed --- /dev/null +++ b/src/lib/net/FingerprintData.cpp @@ -0,0 +1,45 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2024 Deskflow Developers + * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception + */ + +#include "FingerprintDatabase.h" +#include "io/filesystem.h" +#include +#include + +namespace deskflow { + +bool FingerprintData::operator==(const FingerprintData &other) const +{ + return algorithm == other.algorithm && data == other.data; +} + +const char *fingerprintTypeToString(FingerprintType type) +{ + switch (type) { + case FingerprintType::INVALID: + return "invalid"; + case FingerprintType::SHA1: + return "sha1"; + case FingerprintType::SHA256: + return "sha256"; + default: + break; + } + return "invalid"; +} + +FingerprintType fingerprintTypeFromString(const std::string &type) +{ + if (type == "sha1") { + return FingerprintType::SHA1; + } + if (type == "sha256") { + return FingerprintType::SHA256; + } + return FingerprintType::INVALID; +} + +} // namespace deskflow diff --git a/src/lib/net/FingerprintData.h b/src/lib/net/FingerprintData.h new file mode 100644 index 000000000..31f39dcab --- /dev/null +++ b/src/lib/net/FingerprintData.h @@ -0,0 +1,38 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2024 Deskflow Developers + * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception + */ + +#pragma once + +#include +#include +#include + +namespace deskflow { + +enum FingerprintType +{ + INVALID, + SHA1, // deprecated + SHA256, +}; + +struct FingerprintData +{ + std::string algorithm; + std::vector data; + + bool valid() const + { + return !algorithm.empty(); + } + + bool operator==(const FingerprintData &other) const; +}; + +const char *fingerprintTypeToString(FingerprintType type); +FingerprintType fingerprintTypeFromString(const std::string &type); + +} // namespace deskflow diff --git a/src/lib/net/FingerprintDatabase.cpp b/src/lib/net/FingerprintDatabase.cpp new file mode 100644 index 000000000..59c465370 --- /dev/null +++ b/src/lib/net/FingerprintDatabase.cpp @@ -0,0 +1,129 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2024 Deskflow Developers + * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception + */ + +// TODO: remove dead code if not used in PR #7931 + +#include "FingerprintDatabase.h" + +#include "base/String.h" +#include "io/filesystem.h" + +#include +#include + +namespace deskflow { + +void FingerprintDatabase::read(const fs::path &path) +{ + std::ifstream file; + openUtf8Path(file, path, std::ios_base::in); + readStream(file); +} + +void FingerprintDatabase::write(const fs::path &path) +{ + std::ofstream file; + openUtf8Path(file, path, std::ios_base::out); + writeStream(file); +} + +void FingerprintDatabase::readStream(std::istream &stream) +{ + if (!stream.good()) { + return; + } + + std::string line; + while (std::getline(stream, line)) { + if (line.empty()) { + continue; + } + + auto fingerprint = parseDbLine(line); + if (!fingerprint.valid()) { + continue; + } + + m_fingerprints.push_back(fingerprint); + } +} + +void FingerprintDatabase::writeStream(std::ostream &stream) +{ + if (!stream.good()) { + return; + } + + for (const auto &fingerprint : m_fingerprints) { + stream << toDbLine(fingerprint) << "\n"; + } +} + +void FingerprintDatabase::clear() +{ + m_fingerprints.clear(); +} + +void FingerprintDatabase::addTrusted(const FingerprintData &fingerprint) +{ + if (isTrusted(fingerprint)) { + return; + } + m_fingerprints.push_back(fingerprint); +} + +bool FingerprintDatabase::isTrusted(const FingerprintData &fingerprint) +{ + auto found = std::find(m_fingerprints.begin(), m_fingerprints.end(), fingerprint); + return found != m_fingerprints.end(); +} + +FingerprintData FingerprintDatabase::parseDbLine(const std::string &line) +{ + FingerprintData result; + + // legacy v1 certificate handling + if (std::count(line.begin(), line.end(), ':') == 19 && line.size() == 40 + 19) { + auto data = string::fromHex(line); + if (data.empty()) { + return result; + } + result.algorithm = fingerprintTypeToString(FingerprintType::SHA1); + result.data = data; + return result; + } + + auto versionEndPos = line.find(':'); + if (versionEndPos == std::string::npos) { + return result; + } + if (line.substr(0, versionEndPos) != "v2") { + return result; + } + auto algoStartPos = versionEndPos + 1; + auto algoEndPos = line.find(':', algoStartPos); + if (algoEndPos == std::string::npos) { + return result; + } + auto algorithm = line.substr(algoStartPos, algoEndPos - algoStartPos); + auto data = string::fromHex(line.substr(algoEndPos + 1)); + + if (data.empty()) { + return result; + } + + result.algorithm = algorithm; + result.data = data; + return result; +} + +std::string FingerprintDatabase::toDbLine(const FingerprintData &fingerprint) +{ + std::string fingerprintStr(fingerprint.data.begin(), fingerprint.data.end()); + return "v2:" + fingerprint.algorithm + ":" + string::toHex(fingerprintStr, 2); +} + +} // namespace deskflow diff --git a/src/lib/net/FingerprintDatabase.h b/src/lib/net/FingerprintDatabase.h new file mode 100644 index 000000000..d458d6811 --- /dev/null +++ b/src/lib/net/FingerprintDatabase.h @@ -0,0 +1,46 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2024 Deskflow Developers + * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception + */ + +// TODO: remove dead code if not used in PR #7931 + +#pragma once + +#include "FingerprintData.h" + +#include "io/filesystem.h" + +#include +#include +#include + +namespace deskflow { + +class FingerprintDatabase +{ +public: + void read(const fs::path &path); + void write(const fs::path &path); + + void readStream(std::istream &stream); + void writeStream(std::ostream &stream); + + void clear(); + void addTrusted(const FingerprintData &fingerprint); + bool isTrusted(const FingerprintData &fingerprint); + + const std::vector &getFingerprints() const + { + return m_fingerprints; + } + + static FingerprintData parseDbLine(const std::string &line); + static std::string toDbLine(const FingerprintData &fingerprint); + +private: + std::vector m_fingerprints; +}; + +} // namespace deskflow