diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index daa2a967..7d61e476 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -51,9 +51,9 @@ jobs: with: pkgs: boost-json cpr gettext-libintl glib gtest libsecret maddy triplet: ${{ matrix.variant.triplet }} - revision: 4103f46cb1ebb69ef5511cab840ecea0f441fbd7 + revision: b1b19307e2d2ec1eefbdb7ea069de7d4bcd31f01 token: ${{ github.token }} - cache-key: ${{ matrix.variant.triplet }}-4103f46cb1ebb69ef5511cab840ecea0f441fbd7 + cache-key: ${{ matrix.variant.triplet }}-b1b19307e2d2ec1eefbdb7ea069de7d4bcd31f01 - name: "Build" working-directory: ${{github.workspace}}/build run: | diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 277eba85..b028f54f 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -31,9 +31,9 @@ jobs: with: pkgs: boost-json cpr gettext-libintl glib gtest maddy triplet: arm64-osx - revision: 4103f46cb1ebb69ef5511cab840ecea0f441fbd7 + revision: b1b19307e2d2ec1eefbdb7ea069de7d4bcd31f01 token: ${{ github.token }} - cache-key: "arm64-osx-4103f46cb1ebb69ef5511cab840ecea0f441fbd7" + cache-key: "arm64-osx-b1b19307e2d2ec1eefbdb7ea069de7d4bcd31f01" - name: "Build" working-directory: ${{github.workspace}}/build run: | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index ef3cd0ff..8caaf216 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -38,9 +38,9 @@ jobs: with: pkgs: boost-json cpr gettext-libintl gtest maddy sqlcipher triplet: ${{ matrix.variant.triplet }} - revision: 4103f46cb1ebb69ef5511cab840ecea0f441fbd7 + revision: b1b19307e2d2ec1eefbdb7ea069de7d4bcd31f01 token: ${{ github.token }} - cache-key: ${{ matrix.variant.triplet }}-4103f46cb1ebb69ef5511cab840ecea0f441fbd7 + cache-key: ${{ matrix.variant.triplet }}-b1b19307e2d2ec1eefbdb7ea069de7d4bcd31f01 - name: "Build" working-directory: ${{github.workspace}}/build run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 740466ae..cd9c3aa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,40 @@ # Changelog +## 2025.9.0 +### Breaking Changes +#### App +- Removed `DataFileBase` +- Removed `DataFileManager` +- Moved `AppInfo::convertUrlMapToVector()` to `Helpers::CodeHelpers` namespace +- Moved `App::CancellationToken` to `Helpers` namespace +#### Database +- Rewrote all classes with a more modern interface +- Renamed all classes with `Sqlite` prefix +#### Keyring +- Rewrote `Keyring` class with a more modern interface +- Moved `SystemCredentials` to `System::Credentials` namespace +- Removed `CredentialCheckStatus` enum +- Removed `PasswordStrength` module +#### Network +- Removed `DNS` module +- Removed `Socket` and related classes +#### Taskbar +- Removed module +### New APIs +#### Helpers +- Added `DEFINE_ENUM_FLAGS()` macro to `CodeHelpers` namespace +- Added `IJsonSerializable` interface +- Added `JsonFileBase` to replace `DataFileBase` +- Added `quote()` function to `StringHelpers` namespace +#### Keyring +- Added `Space` value to `PasswordContent` +#### System +- Added `execAsync()` function to `Environment` namespace +### Fixes +- Marked functions and methods with `noexcept` where applicable +#### System +- Fixed `Process`'s handling of quoted strings + ## 2025.8.0 ### Breaking Changes None diff --git a/CMakeLists.txt b/CMakeLists.txt index 21cdc6d0..755eb940 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ endif() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") #libnick Definition -project ("libnick" LANGUAGES C CXX VERSION 2025.8.0 DESCRIPTION "A cross-platform base for native Nickvision applications.") +project ("libnick" LANGUAGES C CXX VERSION 2025.9.0 DESCRIPTION "A cross-platform base for native Nickvision applications.") include(CMakePackageConfigHelpers) include(GNUInstallDirs) include(CTest) @@ -36,14 +36,12 @@ if(NOT WIN32) endif() add_library (${PROJECT_NAME} "include/app/appinfo.h" - "include/app/cancellationtoken.h" - "include/app/datafilebase.h" - "include/app/datafilemanager.h" "include/app/windowgeometry.h" - "include/database/sqlcontext.h" - "include/database/sqldatabase.h" - "include/database/sqlstatement.h" - "include/database/sqlvalue.h" + "include/database/sqlite.h" + "include/database/sqlitedatabase.h" + "include/database/sqlitefunctioncontext.h" + "include/database/sqlitestatement.h" + "include/database/sqlitevalue.h" "include/events/event.h" "include/events/eventargs.h" "include/events/parameventargs.h" @@ -54,33 +52,30 @@ add_library (${PROJECT_NAME} "include/filesystem/userdirectories.h" "include/filesystem/userdirectory.h" "include/filesystem/watcherflags.h" + "include/helpers/cancellationtoken.h" "include/helpers/codehelpers.h" + "include/helpers/ijsonserializable.h" + "include/helpers/jsonfilebase.h" "include/helpers/pairhash.h" "include/helpers/stringhelpers.h" "include/keyring/credential.h" - "include/keyring/credentialcheckstatus.h" "include/keyring/keyring.h" "include/keyring/passwordcontent.h" "include/keyring/passwordgenerator.h" - "include/keyring/passwordstrength.h" - "include/keyring/systemcredentials.h" "include/localization/documentation.h" "include/localization/gettext.h" - "include/network/addressfamily.h" - "include/network/dns.h" "include/network/ipv4address.h" "include/network/macaddress.h" "include/network/networkmonitor.h" "include/network/networkstate.h" "include/network/networkstatechangedeventargs.h" - "include/network/socket.h" - "include/network/sockettype.h" "include/network/web.h" "include/notifications/appnotification.h" "include/notifications/notificationsenteventargs.h" "include/notifications/notificationseverity.h" "include/notifications/shellnotification.h" "include/notifications/shellnotificationsenteventargs.h" + "include/system/credentials.h" "include/system/dependencysearchoption.h" "include/system/deploymentmode.h" "include/system/environment.h" @@ -90,49 +85,42 @@ add_library (${PROJECT_NAME} "include/system/processexitedeventargs.h" "include/system/processstate.h" "include/system/suspendinhibitor.h" - "include/taskbar/progressstate.h" - "include/taskbar/taskbaritem.h" "include/update/updater.h" "include/update/version.h" "include/update/versiontype.h" "src/app/appinfo.cpp" - "src/app/cancellationtoken.cpp" - "src/app/datafilebase.cpp" - "src/app/datafilemanager.cpp" "src/app/windowgeometry.cpp" - "src/database/sqlcontext.cpp" - "src/database/sqldatabase.cpp" - "src/database/sqlstatement.cpp" - "src/database/sqlvalue.cpp" + "src/database/sqlitedatabase.cpp" + "src/database/sqlitefunctioncontext.cpp" + "src/database/sqlitestatement.cpp" + "src/database/sqlitevalue.cpp" "src/filesystem/filesystemchangedeventargs.cpp" "src/filesystem/filesystemwatcher.cpp" "src/filesystem/userdirectories.cpp" + "src/helpers/cancellationtoken.cpp" "src/helpers/codehelpers.cpp" + "src/helpers/jsonfilebase.cpp" "src/helpers/stringhelpers.cpp" "src/keyring/credential.cpp" "src/keyring/keyring.cpp" "src/keyring/passwordgenerator.cpp" - "src/keyring/passwordstrength.cpp" - "src/keyring/systemcredentials.cpp" "src/localization/documentation.cpp" "src/localization/gettext.cpp" - "src/network/dns.cpp" "src/network/ipv4address.cpp" "src/network/macaddress.cpp" "src/network/networkmonitor.cpp" "src/network/networkstatechangedeventargs.cpp" - "src/network/socket.cpp" "src/network/web.cpp" "src/notifications/appnotification.cpp" "src/notifications/notificationsenteventargs.cpp" "src/notifications/shellnotification.cpp" "src/notifications/shellnotificationsenteventargs.cpp" + "src/system/credentials.cpp" "src/system/environment.cpp" "src/system/hardwareinfo.cpp" "src/system/process.cpp" "src/system/processexitedeventargs.cpp" "src/system/suspendinhibitor.cpp" - "src/taskbar/taskbaritem.cpp" "src/update/updater.cpp" "src/update/version.cpp") target_include_directories(${PROJECT_NAME} PUBLIC "$" "$") @@ -152,7 +140,7 @@ find_package(maddy CONFIG REQUIRED) target_link_libraries(${PROJECT_NAME} PUBLIC Boost::json cpr::cpr Intl::Intl maddy::maddy) if(WIN32) find_package(sqlcipher CONFIG REQUIRED) - target_link_libraries(${PROJECT_NAME} PUBLIC sqlcipher::sqlcipher Advapi32 Dnsapi Dwmapi Gdiplus Kernel32 Shell32 UxTheme Ws2_32) + target_link_libraries(${PROJECT_NAME} PUBLIC sqlcipher::sqlcipher Advapi32 Dnsapi Dwmapi Gdiplus Kernel32 Shell32 UxTheme) elseif(APPLE) set(THREADS_PREFER_PTHREAD_FLAG ON) find_library(CF_LIBRARY CoreFoundation) @@ -204,11 +192,10 @@ if (BUILD_TESTING) add_executable(${PROJECT_NAME}_test "tests/codetests.cpp" "tests/databasetests.cpp" - "tests/datafiletests.cpp" - "tests/dnstests.cpp" "tests/eventtests.cpp" "tests/filewatchertests.cpp" "tests/hardwaretests.cpp" + "tests/jsonfiletests.cpp" "tests/keyringtests.cpp" "tests/localizationtests.cpp" "tests/main.cpp" @@ -217,9 +204,7 @@ if (BUILD_TESTING) "tests/passwordtests.cpp" "tests/processtests.cpp" "tests/stringtests.cpp" - "tests/systemcredentialstests.cpp" "tests/systemtests.cpp" - "tests/taskbartests.cpp" "tests/updatertests.cpp" "tests/versiontests.cpp" "tests/webtests.cpp") diff --git a/Doxyfile b/Doxyfile index c563fd9a..0c74f2ee 100644 --- a/Doxyfile +++ b/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = "libnick" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "2025.8.0" +PROJECT_NUMBER = "2025.9.0" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/include/app/appinfo.h b/include/app/appinfo.h index 2840bda7..6b537f10 100644 --- a/include/app/appinfo.h +++ b/include/app/appinfo.h @@ -39,190 +39,194 @@ namespace Nickvision::App /** * @brief Constructs an AppInfo. */ - AppInfo() = default; + AppInfo() noexcept = default; + AppInfo(const AppInfo&) noexcept = default; + AppInfo(AppInfo&&) noexcept = default; /** * @brief Constructs an AppInfo. * @param id The application id * @param name The application name * @param englishShortName The application short name in English */ - AppInfo(const std::string& id, const std::string& name, const std::string& englishShortName); + AppInfo(const std::string& id, const std::string& name, const std::string& englishShortName) noexcept; /** * @brief Gets the application id. * @return The application id */ - const std::string& getId() const; + const std::string& getId() const noexcept; /** * @brief Sets the application id. * @param id The application id */ - void setId(const std::string& id); + void setId(const std::string& id) noexcept; /** * @brief Gets the application name. * @return The application name */ - const std::string& getName() const; + const std::string& getName() const noexcept; /** * @brief Sets the application name. * @param name The application name */ - void setName(const std::string& name); + void setName(const std::string& name) noexcept; /** * @brief Gets the application short name. * @return The application short name */ - const std::string& getShortName() const; + const std::string& getShortName() const noexcept; /** * @brief Sets the application short name. * @param shortName The application short name */ - void setShortName(const std::string& shortName); + void setShortName(const std::string& shortName) noexcept; /** * @brief Gets the application English short name. * @return The application English short name */ - const std::string& getEnglishShortName() const; + const std::string& getEnglishShortName() const noexcept; /** * @brief Sets the application English short name. * @param englishShortName The application English short name */ - void setEnglishShortName(const std::string& englishShortName); + void setEnglishShortName(const std::string& englishShortName) noexcept; /** * @brief Gets the application description. * @return The application description */ - const std::string& getDescription() const; + const std::string& getDescription() const noexcept; /** * @brief Sets the application description. * @param description The application description */ - void setDescription(const std::string& description); + void setDescription(const std::string& description) noexcept; /** * @brief Gets the application version. * @return The application version */ - const Update::Version& getVersion() const; + const Update::Version& getVersion() const noexcept; /** * @brief Sets the application version. * @param version The application version */ - void setVersion(const Update::Version& version); + void setVersion(const Update::Version& version) noexcept; /** * @brief Gets the application changelog. * @return The application changelog */ - const std::string& getChangelog() const; + const std::string& getChangelog() const noexcept; /** * @brief Sets the application changelog. * @param changelog The application changelog */ - void setChangelog(const std::string& changelog); + void setChangelog(const std::string& changelog) noexcept; /** * @brief Gets the application changelog in HTML form * @return The application changelog in HTML */ - const std::string& getHtmlChangelog() const; + const std::string& getHtmlChangelog() const noexcept; /** * @brief Gets the application source repo url * @return The application source repo url */ - const std::string& getSourceRepo() const; + const std::string& getSourceRepo() const noexcept; /** * @brief Sets the application source repo url * @param sourceRepo The application source repo url * @return True if the new source repo was set, else false * @return A false return value means that the sourceRepo param was not a valid formatted URL */ - bool setSourceRepo(const std::string& sourceRepo); + bool setSourceRepo(const std::string& sourceRepo) noexcept; /** * @brief Gets the application issue tracker url * @return The application issue tracker url */ - const std::string& getIssueTracker() const; + const std::string& getIssueTracker() const noexcept; /** * @brief Sets the application issue tracker url * @param issueTracker The application issue tracker url * @return True if the new issue tracker was set, else false * @return A false return value means that the issueTracker param was not a valid formatted URL */ - bool setIssueTracker(const std::string& issueTracker); + bool setIssueTracker(const std::string& issueTracker) noexcept; /** * @brief Gets the application support url * @return The application support url */ - const std::string& getSupportUrl() const; + const std::string& getSupportUrl() const noexcept; /** * @brief Sets the application support url * @param supportUrl The application support url * @return True if the new support url was set, else false * @return A false return value means that the supportUrl param was not a valid formatted URL */ - bool setSupportUrl(const std::string& supportUrl); + bool setSupportUrl(const std::string& supportUrl) noexcept; /** * @brief Gets the application html docs store url * @return The application html docs store url */ - const std::string& getHtmlDocsStore() const; + const std::string& getHtmlDocsStore() const noexcept; /** * @brief Sets the application html docs store url * @param htmlDocsStore The application html docs store url */ - void setHtmlDocsStore(const std::string& htmlDocsStore); + void setHtmlDocsStore(const std::string& htmlDocsStore) noexcept; /** * @brief Gets the extra links for the application * @return The extra links for the application */ - std::unordered_map& getExtraLinks(); + std::unordered_map& getExtraLinks() noexcept; /** * @brief Gets the extra links for the application * @return The extra links for the application */ - const std::unordered_map& getExtraLinks() const; + const std::unordered_map& getExtraLinks() const noexcept; /** * @brief Gets the application developers * @return The application developers */ - std::unordered_map& getDevelopers(); + std::unordered_map& getDevelopers() noexcept; /** * @brief Gets the application developers * @return The application developers */ - const std::unordered_map& getDevelopers() const; + const std::unordered_map& getDevelopers() const noexcept; /** * @brief Gets the application designers * @return The application designers */ - std::unordered_map& getDesigners(); + std::unordered_map& getDesigners() noexcept; /** * @brief Gets the application designers * @return The application designers */ - const std::unordered_map& getDesigners() const; + const std::unordered_map& getDesigners() const noexcept; /** * @brief Gets the application artists * @return The application artists */ - std::unordered_map& getArtists(); + std::unordered_map& getArtists() noexcept; /** * @brief Gets the application artists * @return The application artists */ - const std::unordered_map& getArtists() const; + const std::unordered_map& getArtists() const noexcept; /** * @brief Gets the application translator credits * @return The application translator credits */ - const std::string& getTranslatorCredits() const; + const std::string& getTranslatorCredits() const noexcept; /** * @brief Sets the application translator credits * @param translatorCredits The application translator credits */ - void setTranslatorCredits(const std::string& translatorCredits); + void setTranslatorCredits(const std::string& translatorCredits) noexcept; /** * @brief Gets the list of translator names * @return The application translator credits */ - std::vector getTranslatorNames() const; + std::vector getTranslatorNames() const noexcept; + AppInfo& operator=(const AppInfo&) noexcept = default; + AppInfo& operator=(AppInfo&&) noexcept = default; private: std::string m_id; @@ -242,14 +246,6 @@ namespace Nickvision::App std::unordered_map m_designers; std::unordered_map m_artists; std::string m_translatorCredits; - - public: - /** - * @brief Converts a map of URLs to a vector - * @param urls The map of URLs - * @return The vector of URLs - */ - static std::vector convertUrlMapToVector(const std::unordered_map& urls); }; } diff --git a/include/app/datafilebase.h b/include/app/datafilebase.h deleted file mode 100644 index d928e832..00000000 --- a/include/app/datafilebase.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @file - * @author Nicholas Logozzo - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details at - * https://www.gnu.org/copyleft/gpl.html - * - * @section DESCRIPTION - * - * A base class for json data files. - */ - -#ifndef DATAFILEBASE_H -#define DATAFILEBASE_H - -#include -#include -#include -#include "events/event.h" - -namespace Nickvision::App -{ - /** - * @brief A base class for json data files. - */ - class DataFileBase - { - public: - /** - * @brief Constructs a DataFileBase, loading the file from disk. - * @param key The key of the config file - * @param appName The name of the application the data file belongs to - * @param isPortable Whether or not the config file is portable - * @throw std::invalid_argument Thrown if key is empty - * @throw std::invalid_argument Thrown if appName is empty - */ - DataFileBase(const std::string& key, const std::string& appName, bool isPortable); - /** - * @brief Destructs a DataFileBase. - */ - virtual ~DataFileBase() = default; - /** - * Gets the key of the config file. - * @return The key of the config file - */ - const std::string& getKey() const; - /** - * @brief Gets the Saved event. - * @return The Saved event - */ - Events::Event& saved(); - /** - * @brief Saves the config file to disk. - * @return True if saved to disk, else false - */ - bool save(); - - protected: - mutable boost::json::object m_json; - - private: - std::string m_key; - std::filesystem::path m_path; - Events::Event m_saved; - }; -} - -#endif //DATAFILEBASE_H diff --git a/include/app/datafilemanager.h b/include/app/datafilemanager.h deleted file mode 100644 index 03df8efc..00000000 --- a/include/app/datafilemanager.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @file - * @author Nicholas Logozzo - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details at - * https://www.gnu.org/copyleft/gpl.html - * - * @section DESCRIPTION - * - * A manager of data files for an application. - */ - -#ifndef DATAFILEMANAGER_H -#define DATAFILEMANAGER_H - -#include -#include -#include -#include -#include "datafilebase.h" - -namespace Nickvision::App -{ - template - concept DerivedDataFileBase = std::is_base_of_v; - - /** - * @brief A manager of data files for an application. - */ - class DataFileManager - { - public: - /** - * @brief Constructs a DataFileManager. - * @param appName The name of the application (used in determining the path to store data files on disk) - * @param isPortable Whether or not the application is portable (the config files should live in the same exe directory) - */ - DataFileManager(const std::string& appName, bool isPortable); - // Delete copy and move constructors and assignment operators - DataFileManager(const DataFileManager&) = delete; - DataFileManager(DataFileManager&&) = delete; - void operator=(const DataFileManager&) = delete; - void operator=(DataFileManager&&) = delete; - /** - * @brief Gets a data object. - * @tparam T Derived type of DataFileBase - * @param key The key of the data file - * @throw std::invalid_argument Thrown if key is empty - * @return The data object - */ - template - T& get(const std::string& key) - { - if (key.empty()) - { - throw std::invalid_argument("Key must not be empty."); - } - if (!m_files.contains(key)) - { - m_files[key] = std::make_unique(key, m_appName, m_isPortable); - } - return *static_cast(m_files[key].get()); - } - - private: - std::string m_appName; - bool m_isPortable; - std::unordered_map> m_files; - }; -} - -#endif //DATAFILEMANAGER_H diff --git a/include/app/windowgeometry.h b/include/app/windowgeometry.h index 39d702b5..72f9ae0d 100644 --- a/include/app/windowgeometry.h +++ b/include/app/windowgeometry.h @@ -24,26 +24,29 @@ #define WINDOWGEOMETRY_H #include +#include "helpers/ijsonserializable.h" namespace Nickvision::App { /** - * @brief A model of a window's geometry. + * @brief A model of a window's geometry. */ - class WindowGeometry + class WindowGeometry : public Helpers::IJsonSerializable { public: /** * @brief Construct a WindowGeometry. */ - WindowGeometry(); + WindowGeometry() noexcept; + WindowGeometry(const WindowGeometry&) noexcept = default; + WindowGeometry(WindowGeometry&&) noexcept = default; /** * @brief Construct a WindowGeometry. * @param width The width of the window * @param height The height of the window * @param isMaximized Whether or not the window is maximized */ - WindowGeometry(long width, long height, bool isMaximized); + WindowGeometry(long width, long height, bool isMaximized) noexcept; /** * @brief Construct a WindowGeometry. * @param width The width of the window @@ -52,67 +55,69 @@ namespace Nickvision::App * @param x The x position of the window * @param y The y position of the window */ - WindowGeometry(long width, long height, bool isMaximized, long x, long y); + WindowGeometry(long width, long height, bool isMaximized, long x, long y) noexcept; /** * @brief Constructs a WindowGeometry. * @param json The json object */ - WindowGeometry(boost::json::object json); + WindowGeometry(boost::json::object json) noexcept; /** * @brief Gets the width of the window. * @return The width of the window */ - long getWidth() const; + long getWidth() const noexcept; /** * @brief Sets the width of the window. * @param width The new width of the window */ - void setWidth(long width); + void setWidth(long width) noexcept; /** * @brief Gets the height of the window. * @return The height of the window */ - long getHeight() const; + long getHeight() const noexcept; /** * @brief Sets the height of the window. * @param height The new height of the window */ - void setHeight(long height); + void setHeight(long height) noexcept; /** * @brief Gets whether or not the window is maximized. * @return True if maximized, else false */ - bool isMaximized() const; + bool isMaximized() const noexcept; /** * @brief Sets whether or not the window is maximized. * @param isMaximized True if maximized, else false */ - void setIsMaximized(bool isMaximized); + void setIsMaximized(bool isMaximized) noexcept; /** * @brief Gets the x position of the window. * @return The x position of the window */ - long getX() const; + long getX() const noexcept; /** * @brief Sets the x position of the window. * @param x The new x position of the window */ - void setX(long x); + void setX(long x) noexcept; /** * @brief Gets the y position of the window. * @return The y position of the window */ - long getY() const; + long getY() const noexcept; /** * @brief Sets the y position of the window. * @param x The new y position of the window */ - void setY(long y); + void setY(long y) noexcept; /** - * @brief Converts the WindowGeometry to a json object. - * @return The json representation of the WindowGeometry + * @brief Serializes the object to Json. + * @return The Json representation of the object */ - boost::json::object toJson() const; + boost::json::value toJson() const noexcept override; + WindowGeometry& operator=(const WindowGeometry&) noexcept = default; + WindowGeometry& operator=(WindowGeometry&&) noexcept = default; private: long m_width; diff --git a/include/database/sqlcontext.h b/include/database/sqlcontext.h deleted file mode 100644 index 8d9e0c11..00000000 --- a/include/database/sqlcontext.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @file - * @author Nicholas Logozzo - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details at - * https://www.gnu.org/copyleft/gpl.html - * - * @section DESCRIPTION - * - * A sqlite function context. - */ - -#ifndef SQLCONTEXT_H -#define SQLCONTEXT_H - -#ifndef SQLITE_HAS_CODEC -#define SQLITE_HAS_CODEC -#endif - -#include -#include -#ifdef _WIN32 -#include -#else -#include -#endif -#include "sqlvalue.h" - -namespace Nickvision::Database -{ - /** - * @brief A sqlite function context. - */ - class SqlContext - { - public: - /** - * @brief Constructs an SqlContext. - * @param ctx sqlite3_context* - * @param argc The number of arguments passed to the context - * @param argv The sqlite3_value*'s passed to the context - */ - SqlContext(sqlite3_context* ctx, int argc, sqlite3_value** argv); - /** - * @brief Gets the pointer to the user data for the context. - * @return The user data pointer - */ - void* getUserData() const; - /** - * @brief Gets the list of SqlValue arguments passed to the function. - * @return The list of arguments - */ - const std::vector& getArgs() const; - /** - * @brief Returns a NULL value from the sql function. - */ - void result(); - /** - * @brief Returns an int value from the sql function. - * @param value The int value to return - */ - void result(int value); - /** - * @brief Returns an int64 value from the sql function. - * @param value The int64 value to return - */ - void result(sqlite3_int64 value); - /** - * @brief Returns a double value from the sql function. - * @param value The double value to return - */ - void result(double value); - /** - * @brief Returns a bool value from the sql function. - * @param value The bool value to return - */ - void result(bool value); - /** - * @brief Returns a string value from the sql function. - * @param value The string value to return - */ - void result(const std::string& value); - /** - * @brief Returns a blob value from the sql function. - * @param value The blob value to return - * @param n The size of the blob value - */ - void result(void* value, int n); - /** - * @brief Returns an error from the sql function. - * @param err The error message - */ - void error(const std::string& err); - /** - * @brief Returns an error from the sql function. - * @param err The error code - */ - void error(int err); - - private: - sqlite3_context* m_context; - std::vector m_values; - }; -} - -#endif //SQLCONTEXT_H \ No newline at end of file diff --git a/include/database/sqldatabase.h b/include/database/sqldatabase.h deleted file mode 100644 index 9017d9c8..00000000 --- a/include/database/sqldatabase.h +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @file - * @author Nicholas Logozzo - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details at - * https://www.gnu.org/copyleft/gpl.html - * - * @section DESCRIPTION - * - * A sqlite (sqlcipher) database. - */ - -#ifndef SQLDATABASE_H -#define SQLDATABASE_H - -#ifndef SQLITE_HAS_CODEC -#define SQLITE_HAS_CODEC -#endif - -#include -#include -#include -#include -#include -#include -#ifdef _WIN32 -#include -#else -#include -#endif -#include "sqlcontext.h" -#include "sqlstatement.h" - -namespace Nickvision::Database -{ - using SqliteCustomFunction = std::function; - - /** - * @brief A sqlite (sqlcipher) database. - */ - class SqlDatabase - { - public: - /** - * @brief Constructs a SqlDatabase. - * @param path The path to the database file - * @param flags The flags for opening the database - * @throw std::runtime_error Thrown if error in executing sql statement - */ - SqlDatabase(const std::filesystem::path& path, int flags); - /** - * @brief Copies a SqlDatabase object. - * @param database The object to move - */ - SqlDatabase(const SqlDatabase& database); - /** - * @brief Moves a SqlDatabase object. - * @param database The object to move - */ - SqlDatabase(SqlDatabase&& database) noexcept; - /** - * @brief Gets the path of the database file. - * @return The database file path - */ - const std::filesystem::path& getPath() const; - /** - * @brief Gets whether or not the database is encrypted. - * @return True if encrypted, else false - */ - bool isEncrypted() const; - /** - * @brief Returns the underlying sqlite3 object pointer for the database. - * @brief Using this method is strongly discouraged, as you can break the state of this object. - * @return sqlite3* - */ - sqlite3* c_obj(); - /** - * @brief Unlocks the database. - * @brief If the database is not encrypted and is newly created, this will encrypt and set its password. - * @param password The password of the database - * @return True if unlocked, else false - */ - bool unlock(const std::string& password); - /** - * @brief Changes the database's password. - * @brief Passing an empty string will unencrypt the database. - * @brief Changing the password on an encrypted database requires that the database be unlocked first, even if removing the password. - * @param password The new database password - * @return True if password changed, else false - * @throw std::runtime_error Thrown if error in executing sql statement - */ - bool changePassword(const std::string& password); - /** - * @brief Executes an sql command on the database. - * @param command The command to execute - * @return True if command returned SQLITE_OK, else false - */ - bool exec(const std::string& command); - /** - * @brief Creates an new SqlStatement for the database. - * @param command The command to bind to the statement. - * @return The new SqlStatement - * @throw std::runtime_error Thrown if error in executing sql statement - */ - SqlStatement createStatement(const std::string& command); - /** - * @brief Registers a custom sql function to the database. - * @param name The name of the sql function - * @param expectedArgs The number of args the sql function expects to receive (specify -1 for unlimited number of args) - * @param func The sql function - * @return True if function registered, else false - */ - bool registerFunction(const std::string& name, const SqliteCustomFunction& func, int expectedArgs = -1); - /** - * @brief Copies a SqlDatabase object. - * @param database The SqlDatabase to copy - * @return this - */ - SqlDatabase& operator=(const SqlDatabase& database); - /** - * @brief Moves a SqlDatabase object. - * @param database The SqlDatabase to move - * @return this - */ - SqlDatabase& operator=(SqlDatabase&& database) noexcept; - /** - * @brief Gets whether or not the object is valid or not. - * @return True if valid (if isEncrypted ? isUnlocked : true), else false - */ - operator bool() const; - - private: - mutable std::mutex m_mutex; - std::filesystem::path m_path; - int m_flags; - bool m_isEncrypted; - std::shared_ptr m_database; - bool m_isUnlocked; - std::unordered_map m_custom; - }; -} - -#endif //SQLDATABASE_H \ No newline at end of file diff --git a/include/network/dns.h b/include/database/sqlite.h similarity index 52% rename from include/network/dns.h rename to include/database/sqlite.h index 621a89c8..8bbba942 100644 --- a/include/network/dns.h +++ b/include/database/sqlite.h @@ -17,30 +17,33 @@ * * @section DESCRIPTION * - * Functions for working with DNS. + * Headers and common definitions for SQLite database interactions. */ -#ifndef DNS_H -#define DNS_H +#ifndef SQLITE_H +#define SQLITE_H +#ifndef SQLITE_HAS_CODEC +#define SQLITE_HAS_CODEC +#endif + +#include #include -#include -#include "ipv4address.h" +#include +#ifdef _WIN32 +#include +#else +#include +#endif -namespace Nickvision::Network::DNS +namespace Nickvision::Database { - /** - * @brief Resolves a hostname to IPv4 addresses. - * @param hostname The hostname to resolve - * @return A list of IPv4 addresses that the hostname resolves to - */ - std::vector a(const std::string& hostname); - /** - * @brief Gets text records for a hostname. - * @param hostname The hostname to resolve - * @return A list of text records for the hostname - */ - std::vector txt(const std::string& hostname); + template + concept SupportedSqliteValue = std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; } -#endif //DNS_H \ No newline at end of file +#endif //SQLITE_H \ No newline at end of file diff --git a/include/database/sqlitedatabase.h b/include/database/sqlitedatabase.h new file mode 100644 index 00000000..56c436ce --- /dev/null +++ b/include/database/sqlitedatabase.h @@ -0,0 +1,144 @@ +/** + * @file + * @author Nicholas Logozzo + * + * @section LICENSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details at + * https://www.gnu.org/copyleft/gpl.html + * + * @section DESCRIPTION + * + * A thread-safe sqlite (sqlcipher) database. + */ + +#ifndef SQLDATABASE_H +#define SQLDATABASE_H + +#ifndef SQLITE_HAS_CODEC +#define SQLITE_HAS_CODEC +#endif + +#include +#include +#include +#include +#include +#include +#include "sqlite.h" +#include "sqlitefunctioncontext.h" +#include "sqlitestatement.h" + +namespace Nickvision::Database +{ + using SqliteCustomFunction = std::function; + + /** + * @brief A thread-safe sqlite (sqlcipher) database. + */ + class SqliteDatabase + { + public: + /** + * @brief Constructs a SqliteDatabase. + * @brief If the database if not encrypted, it will be unlocked automatically. + * @param path The path to the database file + * @param flags The flags for opening the database + * @throw std::runtime_error Thrown if error in executing sql statement + */ + SqliteDatabase(const std::filesystem::path& path, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); + SqliteDatabase(const SqliteDatabase&) = delete; + /** + * @brief Constructs a SqliteDatabase via move. + * @param other The SqliteDatabase to move + */ + SqliteDatabase(SqliteDatabase&& other) noexcept; + /** + * @brief Destructs a SqliteDatabase. + */ + ~SqliteDatabase() noexcept; + /** + * @brief Gets the path of the database file. + * @return The database file path + */ + const std::filesystem::path& getPath() const noexcept; + /** + * @brief Gets whether or not the database is encrypted. + * @return True if encrypted, else false + */ + bool isEncrypted() const noexcept; + /** + * @brief Gets whether or not the database is unlocked. + * @return True if unlocked, else false + */ + bool isUnlocked() const noexcept; + /** + * @brief Unlocks the database. + * @brief If the database is not encrypted, this method will have no effect and return true. + * @brief If the database is encrypted, this method must be called before any other operations. + * @param password The password of the database + * @return True if unlocked, else false + */ + bool unlock(const std::string& password) noexcept; + /** + * @brief Sets the database's password. + * @brief If the database is not encrypted, it will be encrypted with the password. + * @brief If the database is encrypted and locked, this method will return false. + * @brief If the database is encrypted and unlocked and the password is empty, it will be decrypted. + * @brief If the database is encrypted and unlocked and the password is not empty, it will be reencrypted with the new password. + * @param password The new database password + * @return True if successful, else false + * @throw std::runtime_error Thrown if database cannot be opened + */ + bool setPassword(const std::string& password); + /** + * @brief Registers a custom sql function to the database. + * @param name The name of the sql function + * @param func The custom sql function + * @param expectedArgs The number of args the sql function expects to receive (specify -1 for unlimited number of args) + * @return True if function registered, else false + */ + bool registerFunction(const std::string& name, const SqliteCustomFunction& func, int expectedArgs = -1) noexcept; + /** + * @brief Creates a new SqlStatement for the database. + * @brief Executing the statement is controlled by calling step() on the statement object. + * @param command The command to bind to the statement. + * @return The new SqlStatement if successful + * @return An empty SqlStatement if failed (can be checked with operator bool()) + * @throw std::runtime_error Thrown if error in executing sql statement + */ + SqliteStatement createStatement(const std::string& command); + /** + * @brief Executes a sql command on the database. + * @param command The command to execute + * @return True if command returned SQLITE_OK, else false + */ + bool execute(const std::string& command) noexcept; + SqliteDatabase& operator=(const SqliteDatabase&) = delete; + /** + * @brief Assigns a SqliteDatabase via move. + * @param other The SqliteDatabase to move + * @return Reference to this SqliteDatabase + */ + SqliteDatabase& operator=(SqliteDatabase&& other) noexcept; + + private: + mutable std::mutex m_mutex; + std::filesystem::path m_path; + int m_flags; + bool m_isEncrypted; + bool m_isUnlocked; + sqlite3* m_database; + std::unordered_map m_customFunctions; + }; +} + +#endif //SQLDATABASE_H \ No newline at end of file diff --git a/include/database/sqlitefunctioncontext.h b/include/database/sqlitefunctioncontext.h new file mode 100644 index 00000000..31553dd5 --- /dev/null +++ b/include/database/sqlitefunctioncontext.h @@ -0,0 +1,122 @@ +/** + * @file + * @author Nicholas Logozzo + * + * @section LICENSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details at + * https://www.gnu.org/copyleft/gpl.html + * + * @section DESCRIPTION + * + * A sqlite function context. + */ + +#ifndef SQLITEFUNCTIONCONTEXT_H +#define SQLITEFUNCTIONCONTEXT_H + +#include +#include "sqlite.h" +#include "sqlitevalue.h" + +namespace Nickvision::Database +{ + /** + * @brief A sqlite function context. + */ + class SqliteFunctionContext + { + public: + /** + * @brief Constructs an SqliteFunctionContext. + * @param ctx sqlite3_context* + * @param argc The number of arguments passed to the context + * @param argv The array of sqlite3_value* passed to the context + */ + SqliteFunctionContext(sqlite3_context* ctx, int argc, sqlite3_value** argv) noexcept; + SqliteFunctionContext(const SqliteFunctionContext&) = delete; + /** + * @brief Constructs a SqliteFunctionContext via move. + * @param other The other SqliteFunctionContext to move + */ + SqliteFunctionContext(SqliteFunctionContext&& other) noexcept; + /** + * @brief Gets the pointer to the user data for the context. + * @return The user data pointer + */ + void* getUserData() const noexcept; + /** + * @brief Gets the list of SqliteValue arguments passed to the function. + * @return The list of arguments + */ + const std::vector& getArgs() const noexcept; + /** + * @brief Returns a NULL value from the sql function. + */ + void result() noexcept; + /** + * @brief Returns a value from the sqlite function. + * @tparam T The type of the value to return + * @param value The value to return + */ + template + void result(const T& value) noexcept + { + if(!m_context) + { + return; + } + if constexpr (std::is_same_v) + { + sqlite3_result_int(m_context, value); + } + else if constexpr (std::is_same_v) + { + sqlite3_result_int64(m_context, value); + } + else if constexpr (std::is_same_v) + { + sqlite3_result_double(m_context, value); + } + else if constexpr (std::is_same_v) + { + sqlite3_result_int(m_context, value ? 1 : 0); + } + else if constexpr (std::is_same_v) + { + sqlite3_result_text(m_context, value.c_str(), value.size(), SQLITE_TRANSIENT); + } + } + /** + * @brief Returns an error from the sql function. + * @param err The error message + */ + void error(const std::string& err) noexcept; + /** + * @brief Returns an error from the sql function. + * @param err The error code + */ + void error(int err) noexcept; + SqliteFunctionContext& operator=(const SqliteFunctionContext&) = delete; + /** + * @brief Assigns a SqliteFunctionContext via move. + * @param other The other SqliteFunctionContext to move + * @return Reference to this SqliteFunctionContext + */ + SqliteFunctionContext& operator=(SqliteFunctionContext&& other) noexcept; + + private: + sqlite3_context* m_context; + std::vector m_values; + }; +} + +#endif //SQLITEFUNCTIONCONTEXT_H \ No newline at end of file diff --git a/include/database/sqlitestatement.h b/include/database/sqlitestatement.h new file mode 100644 index 00000000..8cb12345 --- /dev/null +++ b/include/database/sqlitestatement.h @@ -0,0 +1,162 @@ +/** + * @file + * @author Nicholas Logozzo + * + * @section LICENSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details at + * https://www.gnu.org/copyleft/gpl.html + * + * @section DESCRIPTION + * + * A sqlite statement. + */ + +#ifndef SQLITESTATEMENT_H +#define SQLITESTATEMENT_H + +#include "sqlite.h" +#include "sqlitestepresult.h" + +namespace Nickvision::Database +{ + /** + * @brief A sqlite statement. + */ + class SqliteStatement + { + public: + /** + * @brief Constructs a SqliteStatement. + * @param database The sqlite3 database + * @param command The sql command to set to the statement + * @throw std::runtime_error Thrown if error in executing sql statement + */ + SqliteStatement(sqlite3* database, const std::string& command); + SqliteStatement(const SqliteStatement&) = delete; + /** + * @brief Constructs a SqliteStatement via move. + * @param other The other SqliteStatement to move + */ + SqliteStatement(SqliteStatement&& other) noexcept; + /** + * @brief Destructs a SqliteStatement. + */ + ~SqliteStatement() noexcept; + /** + * @brief Steps through the statement. + * @returns SqliteStepResult + */ + SqliteStepResult step() noexcept; + /** + * @brief Binds a value to a sqlite parameter. + * @tparam T The type of the value to bind + * @param index The index of the parameter + * @param value The value to bind + * @return True if bind was successful, else false + */ + template + bool bind(int index, T value) noexcept + { + if(!m_statement) + { + return false; + } + if constexpr (std::is_same_v) + { + return sqlite3_bind_int(m_statement, index, value) == SQLITE_OK; + } + else if constexpr (std::is_same_v) + { + return sqlite3_bind_int64(m_statement, index, value) == SQLITE_OK; + } + else if constexpr (std::is_same_v) + { + return sqlite3_bind_double(m_statement, index, value) == SQLITE_OK; + } + else if constexpr (std::is_same_v) + { + return sqlite3_bind_int(m_statement, index, value ? 1 : 0) == SQLITE_OK; + } + else if constexpr (std::is_same_v) + { + return sqlite3_bind_text(m_statement, index, value.c_str(), -1, SQLITE_TRANSIENT) == SQLITE_OK; + } + } + /** + * @brief Gets the sqlite column value as a specific type. + * @tparam T The type to get the sqlite column value as (Can be: int, std::int64_t, double, bool, std::string) + * @return The sqlite column value as the specified type + * @return A default value if the sqlite column value is not of the specified type + */ + template + T getColumn(int index) noexcept + { + if constexpr (std::is_same_v) + { + if(!m_statement) + { + return 0; + } + return sqlite3_column_int(m_statement, index); + } + else if constexpr (std::is_same_v) + { + if(!m_statement) + { + return 0; + } + return sqlite3_column_int64(m_statement, index); + } + else if constexpr (std::is_same_v) + { + if(!m_statement) + { + return 0.0; + } + return sqlite3_column_double(m_statement, index); + } + else if constexpr (std::is_same_v) + { + if(!m_statement) + { + return false; + } + return static_cast(sqlite3_column_int(m_statement, index)); + } + else if constexpr (std::is_same_v) + { + if(!m_statement) + { + return ""; + } + return { reinterpret_cast(sqlite3_column_text(m_statement, index)), static_cast(sqlite3_column_bytes(m_statement, index)) }; + } + } + SqliteStatement& operator=(const SqliteStatement&) = delete; + /** + * @brief Assigns a SqliteStatement via move. + * @param other The other SqliteStatement to move + * @return Reference to this SqliteStatement + */ + SqliteStatement& operator=(SqliteStatement&& other) noexcept; + /** + * @brief Gets whether or not the object is valid or not. + * @return True if valid, else false + */ + operator bool() const noexcept; + + private: + sqlite3_stmt* m_statement; + }; +} + +#endif //SQLITESTATEMENT_H \ No newline at end of file diff --git a/include/taskbar/progressstate.h b/include/database/sqlitestepresult.h similarity index 52% rename from include/taskbar/progressstate.h rename to include/database/sqlitestepresult.h index 1bf28449..cdc1aa82 100644 --- a/include/taskbar/progressstate.h +++ b/include/database/sqlitestepresult.h @@ -17,25 +17,15 @@ * * @section DESCRIPTION * - * States of progress on a taskbar button. + * Results of a SQLite statement step. */ -#ifndef PROGRESSSTATE_H -#define PROGRESSSTATE_H - -namespace Nickvision::Taskbar +namespace Nickvision::Database { - /** - * @brief States of progress on a taskbar button. - */ - enum class ProgressState + enum class SqliteStepResult { - NoProgress = 0, ///< The taskbar item is in a no progress state. - Indeterminate = 1, ///< The taskbar item is in an indeterminate progress state. - Normal = 2, ///< The taskbar item is in a normal progress state. - Error = 4, ///< The taskbar item is in an error progress state. - Paused = 8 ///< The taskbar item is in a paused progress state. + Error, + Row = 100, + Done = 101 }; -} - -#endif //PROGRESSSTATE_H \ No newline at end of file +} \ No newline at end of file diff --git a/include/database/sqlitevalue.h b/include/database/sqlitevalue.h new file mode 100644 index 00000000..baaa9c06 --- /dev/null +++ b/include/database/sqlitevalue.h @@ -0,0 +1,123 @@ +/** + * @file + * @author Nicholas Logozzo + * + * @section LICENSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details at + * https://www.gnu.org/copyleft/gpl.html + * + * @section DESCRIPTION + * + * A sqlite value. + */ + +#ifndef SQLITEVALUE_H +#define SQLITEVALUE_H + +#include "sqlite.h" + +namespace Nickvision::Database +{ + /** + * @brief A sqlite value. + */ + class SqliteValue + { + public: + /** + * @brief Constructs an SqliteValue. + * @param value sqlite3_value* + */ + SqliteValue(sqlite3_value* value) noexcept; + /** + * @brief Constructs a SqliteValue via copy. + * @param other The other SqliteValue to copy + */ + SqliteValue(const SqliteValue& other) noexcept; + /** + * @brief Constructs a SqliteValue via move. + * @param other The other SqliteValue to move + */ + SqliteValue(SqliteValue&& other) noexcept; + /** + * @brief Destructs the SqliteValue. + */ + ~SqliteValue() noexcept; + /** + * @brief Gets the sqlite value as a specific type. + * @tparam T The type to get the sqlite value as (Can be: int, std::int64_t, double, bool, std::string) + * @return The sqlite value as the specified type + * @return A default value if the sqlite value is not of the specified type + */ + template + T as() const noexcept + { + if constexpr (std::is_same_v) + { + if(!m_value || m_type != SQLITE_INTEGER) + { + return 0; + } + return sqlite3_value_int(m_value); + } + else if constexpr (std::is_same_v) + { + if(!m_value || m_type != SQLITE_INTEGER) + { + return 0; + } + return sqlite3_value_int64(m_value); + } + else if constexpr (std::is_same_v) + { + if(!m_value || m_type != SQLITE_FLOAT) + { + return 0.0; + } + return sqlite3_value_double(m_value); + } + else if constexpr (std::is_same_v) + { + if(!m_value || m_type != SQLITE_INTEGER) + { + return false; + } + return static_cast(sqlite3_value_int(m_value)); + } + else if constexpr (std::is_same_v) + { + if(!m_value || m_type != SQLITE3_TEXT) + { + return ""; + } + return { reinterpret_cast(sqlite3_value_text(m_value)), static_cast(sqlite3_value_bytes(m_value)) }; + } + } + /** + * @brief Assigns a SqliteValue via copy. + * @param other The other SqliteValue to copy + */ + SqliteValue& operator=(const SqliteValue& other) noexcept; + /** + * @brief Assigns a SqliteValue via move. + * @param other The other SqliteValue to move + */ + SqliteValue& operator=(SqliteValue&& other) noexcept; + + private: + sqlite3_value* m_value; + int m_type; + }; +} + +#endif //SQLITEVALUE_H + diff --git a/include/database/sqlstatement.h b/include/database/sqlstatement.h deleted file mode 100644 index 2764daea..00000000 --- a/include/database/sqlstatement.h +++ /dev/null @@ -1,150 +0,0 @@ -/** - * @file - * @author Nicholas Logozzo - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details at - * https://www.gnu.org/copyleft/gpl.html - * - * @section DESCRIPTION - * - * A sqlite statement. - */ - -#ifndef SQLSTATEMENT_H -#define SQLSTATEMENT_H - -#ifndef SQLITE_HAS_CODEC -#define SQLITE_HAS_CODEC -#endif - -#include -#include -#include -#ifdef _WIN32 -#include -#else -#include -#endif - -namespace Nickvision::Database -{ - /** - * @brief A sqlite statement. - */ - class SqlStatement - { - public: - /** - * @brief Constructs a SqlStatement. - * @param database The sqlite3 database - * @param command The sql command to bind to the statement - * @throw std::runtime_error Thrown if error in executing sql statement - */ - SqlStatement(const std::shared_ptr& database, const std::string& command); - /** - * @brief Binds an int to a parameter. - * @param index The index of the parameter - * @param value The int to bind - * @return True if bind was successful, else false - */ - bool bind(int index, int value); - /** - * @brief Binds an int64 to a parameter. - * @param index The index of the parameter - * @param value The int64 to bind - * @return True if bind was successful, else false - */ - bool bind(int index, sqlite3_int64 value); - /** - * @brief Binds a double to a parameter. - * @param index The index of the parameter - * @param value The double to bind - * @return True if bind was successful, else false - */ - bool bind(int index, double value); - /** - * @brief Binds a bool to a parameter. - * @param index The index of the parameter - * @param value The bool to bind - * @return True if bind was successful, else false - */ - bool bind(int index, bool value); - /** - * @brief Binds a string to a parameter. - * @param index The index of the parameter - * @param value The string to bind - * @return True if bind was successful, else false - */ - bool bind(int index, const std::string& value); - /** - * @brief Binds a blob to a parameter. - * @param index The index of the parameter - * @param value The blob to bind - * @param n The size of the blob - * @return True if bind was successful, else false - */ - bool bind(int index, void* value, int n); - /** - * @brief Steps through the statement. - * @returns True if SQLITE_ROW, else false - * @throw std::runtime_error Thrown if error in executing sql statement - */ - bool step(); - /** - * @brief Gets an int from a column. - * @param index The index of the column - * @return The int from the column - */ - int getColumnInt(int index) const; - /** - * @brief Gets an int64 from a column. - * @param index The index of the column - * @return The int64 from the column - */ - sqlite3_int64 getColumnInt64(int index) const; - /** - * @brief Gets a double from a column. - * @param index The index of the column - * @return The double from the column - */ - double getColumnDouble(int index) const; - /** - * @brief Gets a bool from a column. - * @param index The index of the column - * @return The bool from the column - */ - bool getColumnBool(int index) const; - /** - * @brief Gets a string from a column. - * @param index The index of the column - * @return The string from the column - */ - std::string getColumnString(int index) const; - /** - * @brief Gets a blob from a column. - * @param index The index of the column - * @return A pair of the blob from the column and the blob's size - */ - std::pair getColumnBlob(int index) const; - /** - * @brief Gets whether or not the object is valid or not. - * @return True if valid, else false - */ - operator bool() const; - - private: - std::shared_ptr m_statement; - }; -} - -#endif //SQLSTATEMENT_H \ No newline at end of file diff --git a/include/database/sqlvalue.h b/include/database/sqlvalue.h deleted file mode 100644 index b7e8e433..00000000 --- a/include/database/sqlvalue.h +++ /dev/null @@ -1,88 +0,0 @@ -/** - * @file - * @author Nicholas Logozzo - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details at - * https://www.gnu.org/copyleft/gpl.html - * - * @section DESCRIPTION - * - * A sqlite value. - */ - -#ifndef SQLVALUE_H -#define SQLVALUE_H - -#ifndef SQLITE_HAS_CODEC -#define SQLITE_HAS_CODEC -#endif - -#include -#include -#ifdef _WIN32 -#include -#else -#include -#endif - -namespace Nickvision::Database -{ - /** - * @brief A sqlite value. - */ - class SqlValue - { - public: - /** - * @brief Constructs an SqlValue. - * @param value sqlite3_value* - */ - SqlValue(sqlite3_value* value); - /** - * @brief Gets an int from a value. - * @return The int from the value - */ - int getInt() const; - /** - * @brief Gets an int64 from a value. - * @return The int64 from the value - */ - sqlite3_int64 getInt64() const; - /** - * @brief Gets a double from a value. - * @return The double from the value - */ - double getDouble() const; - /** - * @brief Gets a bool from a value. - * @return The bool from the value - */ - bool getBool() const; - /** - * @brief Gets a string from a value. - * @return The string from the value - */ - std::string getString() const; - /** - * @brief Gets a blob from a value. - * @return A pair of the blob from the value and the blob's size - */ - std::pair getBlob() const; - - private: - sqlite3_value* m_value; - }; -} - -#endif //SQLVALUE_H - diff --git a/include/events/event.h b/include/events/event.h index 7cdc0f5d..c02a49fe 100644 --- a/include/events/event.h +++ b/include/events/event.h @@ -23,7 +23,6 @@ #ifndef EVENT_H #define EVENT_H -#include #include #include #include @@ -51,12 +50,12 @@ namespace Nickvision::Events /** * @brief Constructs an Event. */ - Event() = default; + Event() noexcept = default; /** * @brief Constructs an Event via copy. * @param e The object to copy */ - Event(const Event& e) + Event(const Event& e) noexcept { std::lock_guard lock{ e.m_mutex }; m_handlers = e.m_handlers; @@ -69,12 +68,13 @@ namespace Nickvision::Events { std::lock_guard lock{ e.m_mutex }; m_handlers = std::move(e.m_handlers); + e.m_handlers.clear(); } /** * @brief Gets the number of handlers subscribed to the event. * @return The number of handlers */ - size_t count() const + size_t count() const noexcept { std::lock_guard lock{ m_mutex }; return m_handlers.size(); @@ -84,7 +84,7 @@ namespace Nickvision::Events * @param handler The handler function * @return The handler id */ - HandlerId subscribe(const std::function& handler) + HandlerId subscribe(const std::function& handler) noexcept { std::lock_guard lock{ m_mutex }; m_handlers.push_back(handler); @@ -94,7 +94,7 @@ namespace Nickvision::Events * @brief Unsubscribes a handler from the event. * @param id The handler id */ - void unsubscribe(HandlerId id) + void unsubscribe(HandlerId id) noexcept { std::lock_guard lock{ m_mutex }; if (static_cast(id) < 0 || static_cast(id) >= m_handlers.size()) @@ -107,7 +107,7 @@ namespace Nickvision::Events * @brief Invokes the event, calling all handlers. * @param param The parameter to pass to the handlers */ - void invoke(const T& param) const + void invoke(const T& param) const noexcept { std::lock_guard lock{ m_mutex }; for (const std::function& handler : m_handlers) @@ -123,7 +123,7 @@ namespace Nickvision::Events * @param handler The handler function * @return The handler id */ - HandlerId operator+=(const std::function& handler) + HandlerId operator+=(const std::function& handler) noexcept { return subscribe(handler); } @@ -131,7 +131,7 @@ namespace Nickvision::Events * @brief Unsubscribes a handler from the event. * @param id The handler id */ - void operator-=(HandlerId id) + void operator-=(HandlerId id) noexcept { unsubscribe(id); } @@ -139,7 +139,7 @@ namespace Nickvision::Events * @brief Invokes the event, calling all handlers. * @param param The parameter to pass to the handlers */ - void operator()(const T& param) + void operator()(const T& param) noexcept { invoke(param); } @@ -148,7 +148,7 @@ namespace Nickvision::Events * @param e The Event to copy * @return this */ - Event& operator=(const Event& e) + Event& operator=(const Event& e) noexcept { if (this != &e) { @@ -170,6 +170,7 @@ namespace Nickvision::Events std::lock_guard lock{ m_mutex }; std::lock_guard lock2{ e.m_mutex }; m_handlers = std::move(e.m_handlers); + e.m_handlers.clear(); } return *this; } @@ -177,7 +178,7 @@ namespace Nickvision::Events * @brief Gets whether or not the object is valid or not. * @return True if valid (if count() > 0), else false */ - operator bool() const + operator bool() const noexcept { return count() > 0; } diff --git a/include/events/eventargs.h b/include/events/eventargs.h index f56b491f..0b6b9be2 100644 --- a/include/events/eventargs.h +++ b/include/events/eventargs.h @@ -34,7 +34,7 @@ namespace Nickvision::Events /** * @brief Constructs an EventArgs. */ - EventArgs() = default; + EventArgs() noexcept = default; }; } diff --git a/include/events/parameventargs.h b/include/events/parameventargs.h index 142f38bd..f3b8073d 100644 --- a/include/events/parameventargs.h +++ b/include/events/parameventargs.h @@ -43,16 +43,18 @@ namespace Nickvision::Events * @brief Constructs a ParamEventArgs. * @param param The parameter to store in the event args */ - ParamEventArgs(const T& param) + ParamEventArgs(const T& param) noexcept : m_param{ param } { } + ParamEventArgs(const ParamEventArgs&) noexcept = default; + ParamEventArgs(ParamEventArgs&&) noexcept = default; /** * @brief Gets the param stored in the event args. * @return The param stored */ - const T& getParam() const + const T& getParam() const noexcept { return m_param; } @@ -60,7 +62,7 @@ namespace Nickvision::Events * @brief Gets the param stored in the event args. * @return The param stored */ - const T* operator->() const + const T* operator->() const noexcept { return &m_param; } @@ -68,7 +70,7 @@ namespace Nickvision::Events * @brief Gets the param stored in the event args. * @return The param stored */ - T* operator->() + T* operator->() noexcept { return &m_param; } @@ -76,7 +78,7 @@ namespace Nickvision::Events * @brief Gets the param stored in the event args. * @return The param stored */ - const T& operator*() const + const T& operator*() const noexcept { return m_param; } @@ -84,10 +86,12 @@ namespace Nickvision::Events * @brief Gets the param stored in the event args. * @return The param stored */ - T& operator*() + T& operator*() noexcept { return m_param; } + ParamEventArgs& operator=(const ParamEventArgs&) noexcept = default; + ParamEventArgs& operator=(ParamEventArgs&&) noexcept = default; private: T m_param; diff --git a/include/filesystem/filesystemchangedeventargs.h b/include/filesystem/filesystemchangedeventargs.h index ac1d6cbd..58f1210c 100644 --- a/include/filesystem/filesystemchangedeventargs.h +++ b/include/filesystem/filesystemchangedeventargs.h @@ -40,17 +40,21 @@ namespace Nickvision::Filesystem * @param path The path of the file/folder that changed * @param why The action that caused the file system object to change */ - FileSystemChangedEventArgs(const std::filesystem::path& path, FileAction why); + FileSystemChangedEventArgs(const std::filesystem::path& path, FileAction why) noexcept; + FileSystemChangedEventArgs(const FileSystemChangedEventArgs&) noexcept = default; + FileSystemChangedEventArgs(FileSystemChangedEventArgs&&) noexcept = default; /** * @brief Gets the path of the changed file system object system object. * @return The path of the changed file/folder */ - const std::filesystem::path& getPath() const; + const std::filesystem::path& getPath() const noexcept; /** * @brief Gets the action that caused the file system object to change. * @return The action that caused the file system object to change */ - FileAction getWhy() const; + FileAction getWhy() const noexcept; + FileSystemChangedEventArgs& operator=(const FileSystemChangedEventArgs&) noexcept = default; + FileSystemChangedEventArgs& operator=(FileSystemChangedEventArgs&&) noexcept = default; private: std::filesystem::path m_path; diff --git a/include/filesystem/filesystemwatcher.h b/include/filesystem/filesystemwatcher.h index a3c39b42..2b55fa9f 100644 --- a/include/filesystem/filesystemwatcher.h +++ b/include/filesystem/filesystemwatcher.h @@ -55,57 +55,57 @@ namespace Nickvision::Filesystem /** * @brief Destructs a FileSystemWatcher. */ - ~FileSystemWatcher(); + ~FileSystemWatcher() noexcept; /** * @brief Gets the path of the folder being watched. * @return The path of the folder being watched */ - const std::filesystem::path& getPath() const; + const std::filesystem::path& getPath() const noexcept; /** * @brief Gets the flags of what to watch changes for. * @return The flags of watched properties */ - WatcherFlags getWatcherFlags() const; + WatcherFlags getWatcherFlags() const noexcept; /** * @brief Gets whether or not subdirectories of the folder are watched. * @return True if subdirectories watched, else false */ - bool getIncludeSubdirectories() const; + bool getIncludeSubdirectories() const noexcept; /** * @brief Gets the event for when a watched flag of the folder is changed. * @return The changed event */ - Events::Event& changed(); + Events::Event& changed() noexcept; /** * @brief Gets whether or not a file extension is being watched. * @param extension The file extension to check * @return True if extension is being watched, else false * @return True if list of extension filters is empty */ - bool isExtensionWatched(const std::filesystem::path& extension); + bool isExtensionWatched(const std::filesystem::path& extension) const noexcept; /** * @brief Adds an extension of a file to watch for changes in the folder. * @param extension The file extension to add * @return True if successful, else false */ - bool addExtensionFilter(const std::filesystem::path& extension); + bool addExtensionFilter(const std::filesystem::path& extension) noexcept; /** * @brief Removes an extension of a file to watch for changes in the folder. * @param extension The file extension to remove * @return True if successful, else false */ - bool removeExtensionFilter(const std::filesystem::path& extension); + bool removeExtensionFilter(const std::filesystem::path& extension) noexcept; /** * @brief Clears all watched extension filters. This will cause all extensions to be implicitly watched. * @return True if successful, else false */ - bool clearExtensionFilters(); + bool clearExtensionFilters() noexcept; private: /** * @brief Runs the loop to watch a folder for changes. */ - void watch(); + void watch() noexcept; std::thread m_watchThread; mutable std::mutex m_mutex; std::filesystem::path m_path; @@ -119,7 +119,7 @@ namespace Nickvision::Filesystem #elif defined(__linux__) int m_notify; #elif defined(__APPLE__) - static void callback(ConstFSEventStreamRef stream, void* clientCallBackInfo, size_t numEvents, void* eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]); + static void callback(ConstFSEventStreamRef stream, void* clientCallBackInfo, size_t numEvents, void* eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) noexcept; FSEventStreamRef m_stream; CFRunLoopRef m_runLoop; #endif diff --git a/include/filesystem/userdirectories.h b/include/filesystem/userdirectories.h index d54ccf3a..ecacd18c 100644 --- a/include/filesystem/userdirectories.h +++ b/include/filesystem/userdirectories.h @@ -36,7 +36,7 @@ namespace Nickvision::Filesystem::UserDirectories * @param directory The UserDirectory to get the path of * @return The path of the directory */ - std::filesystem::path get(UserDirectory directory); + std::filesystem::path get(UserDirectory directory) noexcept; /** * @brief Gets the path of an application user directory. * @brief Supports XDG directories on Linux. @@ -44,7 +44,7 @@ namespace Nickvision::Filesystem::UserDirectories * @param appName The application name * @return The path of the directory */ - std::filesystem::path get(ApplicationUserDirectory directory, const std::string& appName); + std::filesystem::path get(ApplicationUserDirectory directory, const std::string& appName) noexcept; } #endif //USERDIRECTORIES_H \ No newline at end of file diff --git a/include/filesystem/watcherflags.h b/include/filesystem/watcherflags.h index 47975555..69270e5e 100644 --- a/include/filesystem/watcherflags.h +++ b/include/filesystem/watcherflags.h @@ -23,6 +23,8 @@ #ifndef WATCHERFLAGS_H #define WATCHERFLAGS_H +#include "helpers/codehelpers.h" + namespace Nickvision::Filesystem { /** @@ -38,40 +40,7 @@ namespace Nickvision::Filesystem LastAccess = 32 ///< The last access time of an item in the file system object has changed. }; - constexpr WatcherFlags operator~(WatcherFlags a) - { - return static_cast(~static_cast(a)); - } - - constexpr WatcherFlags operator|(WatcherFlags a, WatcherFlags b) - { - return static_cast(static_cast(a) | static_cast(b)); - } - - constexpr WatcherFlags operator&(WatcherFlags a, WatcherFlags b) - { - return static_cast(static_cast(a) & static_cast(b)); - } - - constexpr WatcherFlags operator^(WatcherFlags a, WatcherFlags b) - { - return static_cast(static_cast(a) ^ static_cast(b)); - } - - inline WatcherFlags& operator|=(WatcherFlags& a, WatcherFlags b) - { - return reinterpret_cast(reinterpret_cast(a) |= static_cast(b)); - } - - inline WatcherFlags& operator&=(WatcherFlags& a, WatcherFlags b) - { - return reinterpret_cast(reinterpret_cast(a) &= static_cast(b)); - } - - inline WatcherFlags& operator^=(WatcherFlags& a, WatcherFlags b) - { - return reinterpret_cast(reinterpret_cast(a) ^= static_cast(b)); - } + DEFINE_ENUM_FLAGS(WatcherFlags) } #endif \ No newline at end of file diff --git a/include/app/cancellationtoken.h b/include/helpers/cancellationtoken.h similarity index 59% rename from include/app/cancellationtoken.h rename to include/helpers/cancellationtoken.h index 0bb040f7..8c0fe67e 100644 --- a/include/app/cancellationtoken.h +++ b/include/helpers/cancellationtoken.h @@ -1,10 +1,32 @@ +/** + * @file + * @author Nicholas Logozzo + * + * @section LICENSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details at + * https://www.gnu.org/copyleft/gpl.html + * + * @section DESCRIPTION + * + * A token that can be used to cancel operations. + */ + #ifndef CANCELLATIONTOKEN_H #define CANCELLATIONTOKEN_H #include #include -namespace Nickvision::App +namespace Nickvision::Helpers { /** * @brief A token that can be used to cancel an operation. @@ -16,36 +38,36 @@ namespace Nickvision::App * @brief Constructs a CancellationToken. * @param cancelFunction A callback function to call when the token is cancelled */ - CancellationToken(const std::function& cancelFunction = {}); + CancellationToken(const std::function& cancelFunction = {}) noexcept; /** * @brief Gets whether or not the token is cancelled. * @return True if token is cancelled, else false */ - bool isCancelled() const; + bool isCancelled() const noexcept; /** * @brief Gets the cancel function to be called when the token is cancelled. * @return The cancel function */ - const std::function& getCancelFunction() const; + const std::function& getCancelFunction() const noexcept; /** * @brief Sets the cancel function to be called when the token is cancelled. * @param cancelFunction The cancel function */ - void setCancelFunction(const std::function& cancelFunction); + void setCancelFunction(const std::function& cancelFunction) noexcept; /** * @brief Cancels the token. */ - void cancel(); + void cancel() noexcept; /** * @brief Resets the token to its initial state. * @brief Removes the cancel function and sets the cancelled state to false. */ - void reset(); + void reset() noexcept; /** * @brief Converts the token to a boolean. * @return True if token is cancelled, else false */ - operator bool() const; + operator bool() const noexcept; private: mutable std::mutex m_mutex; diff --git a/include/helpers/codehelpers.h b/include/helpers/codehelpers.h index 2a49b41c..bb1907d8 100644 --- a/include/helpers/codehelpers.h +++ b/include/helpers/codehelpers.h @@ -27,27 +27,68 @@ #include #include #include +#include + +#define DEFINE_ENUM_FLAGS(ENUM_TYPE) \ +inline constexpr ENUM_TYPE operator~(ENUM_TYPE a) noexcept { \ + using underlying = std::underlying_type_t; \ + return static_cast(~static_cast(a)); \ +} \ +inline constexpr ENUM_TYPE operator|(ENUM_TYPE lhs, ENUM_TYPE rhs) noexcept { \ + using underlying = std::underlying_type_t; \ + return static_cast(static_cast(lhs) | static_cast(rhs)); \ +} \ +inline constexpr ENUM_TYPE operator&(ENUM_TYPE lhs, ENUM_TYPE rhs) noexcept { \ + using underlying = std::underlying_type_t; \ + return static_cast(static_cast(lhs) & static_cast(rhs)); \ +} \ +inline constexpr ENUM_TYPE operator^(ENUM_TYPE lhs, ENUM_TYPE rhs) noexcept { \ + using underlying = std::underlying_type_t; \ + return static_cast(static_cast(lhs) ^ static_cast(rhs)); \ +} \ +inline ENUM_TYPE& operator|=(ENUM_TYPE& lhs, ENUM_TYPE rhs) noexcept { \ + return lhs = (lhs | rhs); \ +} \ +inline ENUM_TYPE& operator&=(ENUM_TYPE& lhs, ENUM_TYPE rhs) noexcept { \ + return lhs = (lhs & rhs); \ +} \ +inline ENUM_TYPE& operator^=(ENUM_TYPE& lhs, ENUM_TYPE rhs) noexcept { \ + return lhs = (lhs ^ rhs); \ +} namespace Nickvision::Helpers::CodeHelpers { + /** + * @brief Combines two hash values together. + * @param a The first hash value + * @param b The second hash value + * @return The combined hash value + */ + size_t combineHash(size_t a, size_t b) noexcept; + /** + * @brief Converts a map of URLs to a vector + * @param urls The map of URLs + * @return The vector of URLs + */ + std::vector convertUrlMapToVector(const std::unordered_map& urls) noexcept; /** * @brief Get the last system api call error message. * @return The last system error message */ - std::string getLastSystemError(); + std::string getLastSystemError() noexcept; /** * @brief Reads a file as a vector of bytes. * @param path The path to the file * @return The bytes from the file */ - std::vector readFileBytes(const std::filesystem::path& path); + std::vector readFileBytes(const std::filesystem::path& path) noexcept; /** * @brief Unmoves a value. * @param t An rvalue of T * @return The lvalue of t */ template - const T& unmove(T&& t) + const T& unmove(T&& t) noexcept { return t; } @@ -58,14 +99,7 @@ namespace Nickvision::Helpers::CodeHelpers * @param overwrite Whether or not to overwrite the file if it already exists * @return True if successful, false otherwise. False is returned if overwrite is false and the file exists. */ - bool writeFileBytes(const std::filesystem::path& path, const std::vector& bytes, bool overwrite = true); - /** - * @brief Combines two hash values together. - * @param a The first hash value - * @param b The second hash value - * @return The combined hash value - */ - size_t combineHash(size_t a, size_t b); + bool writeFileBytes(const std::filesystem::path& path, const std::vector& bytes, bool overwrite = true) noexcept; } #endif //CODEHELPERS_H diff --git a/include/helpers/ijsonserializable.h b/include/helpers/ijsonserializable.h new file mode 100644 index 00000000..047356b8 --- /dev/null +++ b/include/helpers/ijsonserializable.h @@ -0,0 +1,37 @@ +#ifndef IJSONSERIALIZABLE_H +#define IJSONSERIALIZABLE_H + +#include +#include +#include + +namespace Nickvision::Helpers +{ + /** + * @brief An interface for objects serializable to Json. + */ + class IJsonSerializable + { + public: + virtual ~IJsonSerializable() = default; + /** + * @brief Serializes the object to Json. + * @return The Json representation of the object + */ + virtual boost::json::value toJson() const noexcept = 0; + }; + + template + concept DerivedJsonSerializable = std::is_base_of_v; + + template + concept SupportedJsonValue = std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; +} + +#endif //IJSONSERIALIZABLE_H \ No newline at end of file diff --git a/include/helpers/jsonfilebase.h b/include/helpers/jsonfilebase.h new file mode 100644 index 00000000..ee980ab6 --- /dev/null +++ b/include/helpers/jsonfilebase.h @@ -0,0 +1,166 @@ +/** + * @file + * @author Nicholas Logozzo + * + * @section LICENSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details at + * https://www.gnu.org/copyleft/gpl.html + * + * @section DESCRIPTION + * + * A base class for thread-safe json data files. + */ + +#ifndef JSONFILEBASE_H +#define JSONFILEBASE_H + +#include +#include +#include +#include +#include "events/event.h" +#include "ijsonserializable.h" + +namespace Nickvision::Helpers +{ + /** + * @brief A base class for thread-safe json data files. + */ + class JsonFileBase : public IJsonSerializable + { + public: + /** + * @brief Constructs a JsonFileBase, loading the file from disk. + * @param path The path to the json file + * @throw std::invalid_argument Thrown if the path is empty + */ + JsonFileBase(const std::filesystem::path& path); + /** + * @brief Destructs a JsonFileBase. + */ + virtual ~JsonFileBase() noexcept = default; + /** + * @brief Gets the path of the json file. + * @return The path of the json file + */ + const std::filesystem::path& getPath() const noexcept; + /** + * @brief Gets the Saved event. + * @return The Saved event + */ + Events::Event& saved() noexcept; + /** + * @brief Saves the config file to disk. + * @return True if saved to disk, else false + */ + bool save() noexcept; + /** + * @brief Serializes the object to Json. + * @return The Json representation of the object + */ + boost::json::value toJson() const noexcept override; + + protected: + /** + * @brief Gets whether or not the json object contains a key. + */ + bool contains(const std::string& key) const noexcept; + /** + * @brief Gets a value from the json object. + * @tparam T The type of the value to get + * @param key The key of the value to get + * @param defaultValue The default value to return if the key is not found or if the value is not of the expected type + * @return The value associated with the key + */ + template + T get(const std::string& key, const T& defaultValue) const noexcept + { + std::lock_guard lock{ m_mutex }; + if constexpr (std::is_same_v) + { + if(!m_json.contains(key) || !m_json[key].is_int64()) + { + return defaultValue; + } + return static_cast(m_json[key].as_int64()); + } + else if constexpr (std::is_same_v) + { + if(!m_json.contains(key) || !m_json[key].is_int64()) + { + return defaultValue; + } + return m_json[key].as_int64(); + } + else if constexpr (std::is_same_v) + { + if(!m_json.contains(key) || !m_json[key].is_double()) + { + return defaultValue; + } + return m_json[key].as_double(); + } + else if constexpr (std::is_same_v) + { + if(!m_json.contains(key) || !m_json[key].is_bool()) + { + return defaultValue; + } + return m_json[key].as_bool(); + } + else if constexpr (std::is_same_v) + { + if(!m_json.contains(key) || !m_json[key].is_string()) + { + return defaultValue; + } + return m_json[key].as_string(); + } + else if constexpr (std::is_same_v) + { + if(!m_json.contains(key) || !m_json[key].is_array()) + { + return defaultValue; + } + return m_json[key].as_array(); + } + else if constexpr (std::is_same_v) + { + if(!m_json.contains(key) || !m_json[key].is_object()) + { + return defaultValue; + } + return m_json[key].as_object(); + } + } + /** + * @brief Sets a value in the json object. + * @tparam T The type of the value to set + * @param key The key of the value to set + * @param value The value to set + */ + template + void set(const std::string& key, const T& value) noexcept + { + std::lock_guard lock{ m_mutex }; + m_json[key] = value; + } + + private: + mutable std::mutex m_mutex; + std::filesystem::path m_path; + mutable boost::json::object m_json; + Events::Event m_saved; + }; +} + +#endif //JSONFILEBASE_H diff --git a/include/helpers/pairhash.h b/include/helpers/pairhash.h index f333d460..6eef916a 100644 --- a/include/helpers/pairhash.h +++ b/include/helpers/pairhash.h @@ -15,14 +15,14 @@ namespace Nickvision::Helpers /** * @brief Constructs a PairHash. */ - PairHash() = default; + PairHash() noexcept = default; /** * @brief The call operator. * @param p The std::pair to determine a hash value for * @return The hash value of the std::pair */ template - size_t operator()(const std::pair& p) const + size_t operator()(const std::pair& p) const noexcept { return CodeHelpers::combineHash(std::hash()(p.first), std::hash()(p.second)); } diff --git a/include/helpers/sizehelpers.h b/include/helpers/sizehelpers.h index f47cc55e..0cae84e5 100644 --- a/include/helpers/sizehelpers.h +++ b/include/helpers/sizehelpers.h @@ -11,37 +11,37 @@ namespace Nickvision::Helpers::SizeHelpers concept Numeric = std::is_arithmetic_v; template - constexpr T bytesToKilobytes(const T value) + constexpr T bytesToKilobytes(const T value) noexcept { return value / FACTOR; } template - constexpr T kilobytesToBytes(const T value) + constexpr T kilobytesToBytes(const T value) noexcept { return value * FACTOR; } template - constexpr T bytesToMegabytes(const T value) + constexpr T bytesToMegabytes(const T value) noexcept { return value / (FACTOR * FACTOR); } template - constexpr T megabytesToBytes(const T value) + constexpr T megabytesToBytes(const T value) noexcept { return value * (FACTOR * FACTOR); } template - constexpr T bytesToGigabytes(const T value) + constexpr T bytesToGigabytes(const T value) noexcept { return value / (FACTOR * FACTOR * FACTOR); } template - constexpr T gigabytesToBytes(const T value) + constexpr T gigabytesToBytes(const T value) noexcept { return value * (FACTOR * FACTOR * FACTOR); } diff --git a/include/helpers/stringhelpers.h b/include/helpers/stringhelpers.h index 84bcd432..49239b77 100644 --- a/include/helpers/stringhelpers.h +++ b/include/helpers/stringhelpers.h @@ -39,19 +39,19 @@ namespace Nickvision::Helpers::StringHelpers * @param base64 The base64 encoded string * @return The bytes list from the base64 encoded string, empty list if error */ - std::vector decode(const std::string& base64); + std::vector decode(const std::string& base64) noexcept; /** * @brief Converts a list of bytes into a base64 encoded string. * @param bytes The list of bytes * @return The base64 encoded string of the bytes list */ - std::string encode(const std::vector& bytes); + std::string encode(const std::vector& bytes) noexcept; /** * @brief Gets whether or not the provided string is a valid url * @param s The string to check * @return True if the string is a valid url, else false */ - bool isValidUrl(const std::string& s); + bool isValidUrl(const std::string& s) noexcept; /** * @brief Concatenates the elements of a string list using the specified separator between each element. * @param values The list of strings to join @@ -59,31 +59,37 @@ namespace Nickvision::Helpers::StringHelpers * @param separateLast Whether or not to include the separator for the last joined element * @return A single string that consists of all elements of the string list separated by the delimiter */ - std::string join(const std::vector& values, const std::string& separator, bool separateLast = false); + std::string join(const std::vector& values, const std::string& separator, bool separateLast = false) noexcept; /** * @brief Gets a fully lowercase string from the provided string. * @param s The string to get lowercase * @return The new lowercase string */ - std::string lower(std::string s); + std::string lower(std::string s) noexcept; /** * @brief Generates a new uuid value. * @return The uuid value */ - std::string newUuid(); + std::string newUuid() noexcept; /** * @brief Generates a new guid value. * @brief This function simple calls newUuid() and returns the result. * @return The guid value */ - std::string newGuid(); + std::string newGuid() noexcept; /** * @brief Normalizes a string for use in a filename. * @param s The string to normalize * @param windowsOnly Whether or not to normalize strictly for Windows * @return The new normalized string */ - std::string normalizeForFilename(const std::string& s, bool windowsOnly = false); + std::string normalizeForFilename(const std::string& s, bool windowsOnly = false) noexcept; + /** + * @brief Quotes a string for use in a command line. + * @param s The string to quote + * @return The quoted string + */ + std::string quote(const std::string& s) noexcept; /** * @brief Replaces a substring within a string with a new string. * @param s The string to work on @@ -91,7 +97,7 @@ namespace Nickvision::Helpers::StringHelpers * @param replace The new string to replace with * @return The new replaced string */ - std::string replace(std::string s, const std::string& toReplace, const std::string& replace); + std::string replace(std::string s, const std::string& toReplace, const std::string& replace) noexcept; /** * @brief Replaces a character within a string with a new character. * @param s The string to work on @@ -99,19 +105,19 @@ namespace Nickvision::Helpers::StringHelpers * @param replace The new character to replace with * @return The new replaced string */ - std::string replace(std::string s, char toReplace, char replace); + std::string replace(std::string s, char toReplace, char replace) noexcept; /** * @brief Splits a string based on argument delimiters. * @param s The string to split * @return The splits of the argument string */ - std::vector splitArgs(std::string s); + std::vector splitArgs(std::string s) noexcept; /** * @brief Converts the wstring to a string. * @param s The wstring to convert * @return The string version of the wstring */ - std::string str(const std::wstring& s); + std::string str(const std::wstring& s) noexcept; /** * @brief Converts a string to an unsigned int * @param s The string to convert @@ -121,32 +127,32 @@ namespace Nickvision::Helpers::StringHelpers * @return UINT_MAX if the converted string is too long * @return 0 if error */ - unsigned int stoui(const std::string& s, size_t* idx = nullptr, int base = 10); + unsigned int stoui(const std::string& s, size_t* idx = nullptr, int base = 10) noexcept; /** * @brief Trims whitespace form the beginning and end of a string. * @param s The string to trim (unmodified) * @return The new trimmed string */ - std::string trim(const std::string& s); + std::string trim(const std::string& s) noexcept; /** * @brief Trims the delimiter character form the beginning and end of a string. * @param s The string to trim (unmodified) * @param delimiter The character to trim * @return The new trimmed string */ - std::string trim(const std::string& s, char delimiter); + std::string trim(const std::string& s, char delimiter) noexcept; /** * @brief Gets a fully uppercase string from the provided string. * @param s The string to get uppercase * @return The new uppercase string */ - std::string upper(std::string s); + std::string upper(std::string s) noexcept; /** * @brief Converts the string to a wstring. * @param s The string to convert * @return The wstring version of the string */ - std::wstring wstr(const std::string& s); + std::wstring wstr(const std::string& s) noexcept; /** * @brief Splits a string based on a delimiter. * @tparam T The type of the resulting splits (must be a type that can be implicitly converted to string) @@ -156,7 +162,7 @@ namespace Nickvision::Helpers::StringHelpers * @return The splits of the string */ template - std::vector split(const std::string& s, const std::string& delimiter, bool includeEmpty = true) + std::vector split(const std::string& s, const std::string& delimiter, bool includeEmpty = true) noexcept { std::vector splits; size_t last{ 0 }; @@ -187,7 +193,7 @@ namespace Nickvision::Helpers::StringHelpers * @return The splits of the string */ template - std::vector split(const std::string& s, char delimiter, bool includeEmpty = true) + std::vector split(const std::string& s, char delimiter, bool includeEmpty = true) noexcept { return split(s, std::string(1, delimiter), includeEmpty); } diff --git a/include/keyring/credential.h b/include/keyring/credential.h index acfcfa3b..f0493a37 100644 --- a/include/keyring/credential.h +++ b/include/keyring/credential.h @@ -23,7 +23,6 @@ #ifndef CREDENTIAL_H #define CREDENTIAL_H -#include #include namespace Nickvision::Keyring @@ -34,6 +33,10 @@ namespace Nickvision::Keyring class Credential { public: + /** + * @brief Constructs a credential. + */ + Credential() = default; /** * @brief Constructs a credential. * @param name The name of the credential @@ -41,75 +44,53 @@ namespace Nickvision::Keyring * @param username The username of the credential * @param password The password of the credential */ - Credential(const std::string& name, const std::string& uri, const std::string& username, const std::string& password); + Credential(const std::string& name, const std::string& uri, const std::string& username, const std::string& password) noexcept; /** * @brief Gets the name of the credential * @return The name of the credential */ - const std::string& getName() const; + const std::string& getName() const noexcept; /** * @brief Sets the name of the credential * @param name The name of the credential */ - void setName(const std::string& name); + void setName(const std::string& name) noexcept; /** * @brief Gets the uri of the credential (can also be used as a comment for the Credential) * @return The uri of the credential */ - const std::string& getUri() const; + const std::string& getUri() const noexcept; /** * @brief Sets the uri of the credential (can also be used as a comment for the Credential) * @param uri The uri of the credential */ - void setUri(const std::string& uri); + void setUri(const std::string& uri) noexcept; /** * @brief Gets the username of the credential * @return The username of the credential */ - const std::string& getUsername() const; + const std::string& getUsername() const noexcept; /** * @brief Sets the username of the credential * @param username The username of the credential */ - void setUsername(const std::string& username); + void setUsername(const std::string& username) noexcept; /** * @brief Gets the password of the credential * @return The password of the credential */ - const std::string& getPassword() const; + const std::string& getPassword() const noexcept; /** * @brief Sets the password of the credential * @param password The password of the credential */ - void setPassword(const std::string& password); - /** - * @brief Compares Credential objects via < operator - * @param compare The Credential object to compare too - * @return True if this < compare - */ - bool operator<(const Credential& compare) const; - /** - * @brief Compares Credential objects via > operator - * @param compare The Credential object to compare too - * @return True if this > compare - */ - bool operator>(const Credential& compare) const; + void setPassword(const std::string& password) noexcept; /** - * @brief Compares Credential objects via == operator + * @brief Compares Credential objects via spaceship operator * @param compare The Credential object to compare too - * @return True if this == compare - */ - bool operator==(const Credential& compare) const; - /** - * @brief Compares Credential objects via != operator - * @param compare The Credential object to compare too - * @return True if this != compare - */ - bool operator!=(const Credential& compare) const; - /** - * @brief Outputs the Credential object + * @return A strong_ordering value representing the comparison */ - friend std::ostream& operator<<(std::ostream& os, const Credential& credential); + std::strong_ordering operator<=>(const Credential&) const noexcept = default; private: std::string m_name; diff --git a/include/keyring/credentialcheckstatus.h b/include/keyring/credentialcheckstatus.h deleted file mode 100644 index 49bbcc32..00000000 --- a/include/keyring/credentialcheckstatus.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file - * @author Nicholas Logozzo - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details at - * https://www.gnu.org/copyleft/gpl.html - * - * @section DESCRIPTION - * - * Flags to describe the status of a validated credential. - */ - -#ifndef CREDENTIALCHECKSTATUS_H -#define CREDENTIALCHECKSTATUS_H - -namespace Nickvision::Keyring -{ - /** - * @brief Flags to describe the status of a validated credential. - */ - enum class CredentialCheckStatus - { - Valid = 1, ///< The credential is valid. - EmptyName = 2, ///< The credential has an empty name. - EmptyUsernamePassword = 4, ///< The credential has an empty username or password. - InvalidUri = 8 ///< The credential has an invalid URI. - }; - - constexpr CredentialCheckStatus operator~(CredentialCheckStatus a) - { - return static_cast(~static_cast(a)); - } - - constexpr CredentialCheckStatus operator|(CredentialCheckStatus a, CredentialCheckStatus b) - { - return static_cast(static_cast(a) | static_cast(b)); - } - - constexpr CredentialCheckStatus operator&(CredentialCheckStatus a, CredentialCheckStatus b) - { - return static_cast(static_cast(a) & static_cast(b)); - } - - constexpr CredentialCheckStatus operator^(CredentialCheckStatus a, CredentialCheckStatus b) - { - return static_cast(static_cast(a) ^ static_cast(b)); - } - - inline CredentialCheckStatus& operator|=(CredentialCheckStatus& a, CredentialCheckStatus b) - { - return reinterpret_cast(reinterpret_cast(a) |= static_cast(b)); - } - - inline CredentialCheckStatus& operator&=(CredentialCheckStatus& a, CredentialCheckStatus b) - { - return reinterpret_cast(reinterpret_cast(a) &= static_cast(b)); - } - - inline CredentialCheckStatus& operator^=(CredentialCheckStatus& a, CredentialCheckStatus b) - { - return reinterpret_cast(reinterpret_cast(a) ^= static_cast(b)); - } -} - -#endif //CREDENTIALCHECKSTATUS_H \ No newline at end of file diff --git a/include/keyring/keyring.h b/include/keyring/keyring.h index c71f02b1..7e0e74c8 100644 --- a/include/keyring/keyring.h +++ b/include/keyring/keyring.h @@ -24,76 +24,92 @@ #define KEYRING_H #include +#include #include #include #include #include "credential.h" -#include "database/sqldatabase.h" +#include "database/sqlitedatabase.h" namespace Nickvision::Keyring { /** * @brief A model of a keyring object for managing credentials. - * @brief The keyring is encrypted with a password stored in the system's credential manager. + * @brief The keyring is an sqlite database, encrypted with a password stored in the system's credential manager. */ class Keyring { public: /** * @brief Constructs a Keyring. - * @brief If the system credential manager is not available, the object will be functional but will not save any data to disk. + * @brief If the system credential manager is not available, an in-memory database will be used (credentials will not be saved to disk). * @param name The name of the keyring + * @throw std::runtime_error Thrown if error in database operations */ Keyring(const std::string& name); + Keyring(const Keyring&) = delete; + /** + * @brief Constructs a Keyring via move. + * @param other The Keyring to move + */ + Keyring(Keyring&& other) noexcept; /** * @brief Gets the name of the keyring. * @return The name of the keyring. */ - const std::string& getName() const; + const std::string& getName() const noexcept; /** * @brief Gets whether the keyring is saving data to disk. * @return True if saving data to disk, else false */ - bool isSavingToDisk() const; + bool isSavingToDisk() const noexcept; /** * @brief Gets all credentials in the keyring. * @return The list of all credentials */ - const std::vector& getCredentials() const; + const std::vector& getAll() const noexcept; /** * @brief Gets the credential matching the provided name. * @param name The name of the credential * @return The credential matching the name, std::nullopt if no matching credential found */ - std::optional getCredential(const std::string& name); + std::optional get(const std::string& name) noexcept; /** * @brief Adds a credential to the keyring. * @param credential The credential to add * @return True if successful, else false */ - bool addCredential(const Credential& credential); + bool add(const Credential& credential) noexcept; /** * @brief Updates a credential in the keyring. * @param credential The credential to update * @return True if successful, else false */ - bool updateCredential(const Credential& credential); + bool update(const Credential& credential) noexcept; /** * @brief Deletes a credential from the keyring. * @param name The name of the credential to delete * @return True if successful, else false */ - bool deleteCredential(const std::string& name); + bool remove(const std::string& name) noexcept; /** * @brief Destroys the keyring. - * @brief This will delete all data in the keyring and put the object in a state where no data can be saved to disk. + * @brief This will delete all data in the keyring and remove it from the system. + * @brief The object should not be used after as all methods will return false. * @return True if successful, else false */ - bool destroy(); + bool destroy() noexcept; + Keyring& operator=(const Keyring&) = delete; + /** + * @brief Assigns a Keyring via move. + * @param other The Keyring to move + */ + Keyring& operator=(Keyring&& other) noexcept; private: + mutable std::mutex m_mutex; std::string m_name; - std::shared_ptr m_database; + std::unique_ptr m_database; std::vector m_credentials; }; } diff --git a/include/keyring/passwordcontent.h b/include/keyring/passwordcontent.h index 78c6c9e9..d2e01d5e 100644 --- a/include/keyring/passwordcontent.h +++ b/include/keyring/passwordcontent.h @@ -23,6 +23,8 @@ #ifndef PASSWORDCONTENT_H #define PASSWORDCONTENT_H +#include "helpers/codehelpers.h" + namespace Nickvision::Keyring { /** @@ -33,43 +35,11 @@ namespace Nickvision::Keyring Numeric = 1, ///< The password contains numeric characters. Uppercase = 2, ///< The password contains uppercase characters. Lowercase = 4, ///< The password contains lowercase characters. - Special = 8 ///< The password contains special characters. + Special = 8, ///< The password contains special characters. + Space = 16 ///< The password contains spaces. }; - constexpr PasswordContent operator~(PasswordContent a) - { - return static_cast(~static_cast(a)); - } - - constexpr PasswordContent operator|(PasswordContent a, PasswordContent b) - { - return static_cast(static_cast(a) | static_cast(b)); - } - - constexpr PasswordContent operator&(PasswordContent a, PasswordContent b) - { - return static_cast(static_cast(a) & static_cast(b)); - } - - constexpr PasswordContent operator^(PasswordContent a, PasswordContent b) - { - return static_cast(static_cast(a) ^ static_cast(b)); - } - - inline PasswordContent& operator|=(PasswordContent& a, PasswordContent b) - { - return reinterpret_cast(reinterpret_cast(a) |= static_cast(b)); - } - - inline PasswordContent& operator&=(PasswordContent& a, PasswordContent b) - { - return reinterpret_cast(reinterpret_cast(a) &= static_cast(b)); - } - - inline PasswordContent& operator^=(PasswordContent& a, PasswordContent b) - { - return reinterpret_cast(reinterpret_cast(a) ^= static_cast(b)); - } + DEFINE_ENUM_FLAGS(PasswordContent) } #endif //PASSWORDCONTENT_H \ No newline at end of file diff --git a/include/keyring/passwordgenerator.h b/include/keyring/passwordgenerator.h index 2747cde0..640f37f6 100644 --- a/include/keyring/passwordgenerator.h +++ b/include/keyring/passwordgenerator.h @@ -23,8 +23,8 @@ #ifndef PASSWORDGENERATOR_H #define PASSWORDGENERATOR_H +#include #include -#include #include "passwordcontent.h" namespace Nickvision::Keyring @@ -37,28 +37,30 @@ namespace Nickvision::Keyring public: /** * @brief Constructs a PasswordGenerator. - * @param contentFlags Flags of possible characters in a generated password + * @param contentFlags Flags of possible characters for the generator to use */ - PasswordGenerator(PasswordContent contentFlags = PasswordContent::Numeric | PasswordContent::Uppercase | PasswordContent::Lowercase | PasswordContent::Special); + PasswordGenerator(PasswordContent contentFlags = PasswordContent::Numeric | PasswordContent::Uppercase | PasswordContent::Lowercase | PasswordContent::Special | PasswordContent::Space) noexcept; /** - * @brief Gets the flags of possible characters in a generated password. - * @return The flags of possible characters in a generated password + * @brief Gets the flags of possible characters for the generator to use. + * @return The flags of possible characters for the generator to use */ - PasswordContent getContentFlags() const; + PasswordContent getContentFlags() const noexcept; /** - * @brief Sets the flags of possible characters in a generated password. - * @param contentFlags Flags of possible characters in a generated password + * @brief Sets the flags of possible characters for the generator to use. + * @param contentFlags Flags of possible characters for the generator to use */ - void setContentFlags(PasswordContent contentFlags); + void setContentFlags(PasswordContent contentFlags) noexcept; /** * @brief Generates a new password * @param length The length of the generated password * @return The generated password */ - std::string next(size_t length = 16); + std::string next(size_t length = 16) noexcept; private: PasswordContent m_contentFlags; + std::random_device m_randomDevice; + std::mt19937 m_randomEngine; }; } diff --git a/include/keyring/passwordstrength.h b/include/keyring/passwordstrength.h deleted file mode 100644 index fc70b3af..00000000 --- a/include/keyring/passwordstrength.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @file - * @author Nicholas Logozzo - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details at - * https://www.gnu.org/copyleft/gpl.html - * - * @section DESCRIPTION - * - * Strengths for a password. - */ - -#ifndef PASSWORDSTRENGTH_H -#define PASSWORDSTRENGTH_H - -#include - -namespace Nickvision::Keyring -{ - /** - * @brief Strengths for a password. - */ - enum class PasswordStrength - { - Blank = 0, ///< A blank password. - VeryWeak, ///< A very weak password. - Weak, ///< A weak password. - Medium, ///< A medium password. - Strong, ///< A strong password. - VeryStrong ///< A very strong password. - }; - - /** - * @brief Calculates the strength of a given password. - * @param password The password to measure the strength of - * @return The strength of the password - */ - PasswordStrength getPasswordStrength(const std::string& password); -} - -#endif //PASSWORDSTRENGTH_H \ No newline at end of file diff --git a/include/keyring/systemcredentials.h b/include/keyring/systemcredentials.h deleted file mode 100644 index 72a56820..00000000 --- a/include/keyring/systemcredentials.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @file - * @author Nicholas Logozzo - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details at - * https://www.gnu.org/copyleft/gpl.html - * - * @section DESCRIPTION - * - * Functions for working with the system credential manager. - */ - -#ifndef SYSTEMCREDENTIALS_H -#define SYSTEMCREDENTIALS_H - -#include -#include -#include "credential.h" - -namespace Nickvision::Keyring::SystemCredentials -{ - /** - * @brief Gets a credential from the system's credential manager. - * @param name The name of the credential - * @return The Credential object, if found - */ - std::optional getCredential(const std::string& name); - /** - * @brief Adds a new credential with a random password to the system's credential manager. - * @param name The name of the credential - * @return The new Credential object, if successful - */ - std::optional addCredential(const std::string& name); - /** - * @brief Adds a new credential to the system's credential manager. - * @brief On Linux, only the name and password of a credential will be stored. - * @brief On Windows, all fields of a credential will be stored. - * @brief On macOS, all fields of a credential will be stored. - * @param credential The new credential object - * @return True if successful, else false - */ - bool addCredential(const Credential& credential); - /** - * @brief Updates a credential in the system's credential manager. - * @brief On Linux, only the name and password of a credential will be stored. - * @brief On Windows, all fields of a credential will be stored. - * @brief On macOS, all fields of a credential will be stored. - * @param credential The updated credential object - * @return True if successful, else false - */ - bool updateCredential(const Credential& credential); - /** - * @brief Deletes a credential from the system's credential manager. - * @param name The name of the credential to delete - * @return True if successful, else false - */ - bool deleteCredential(const std::string& name); -} - -#endif //SYSTEMCREDENTIALS_H \ No newline at end of file diff --git a/include/localization/documentation.h b/include/localization/documentation.h index 8d2c5b98..1f944669 100644 --- a/include/localization/documentation.h +++ b/include/localization/documentation.h @@ -35,7 +35,7 @@ namespace Nickvision::Localization::Documentation * @param pageName The name of the documentation page to get * @return The url for the documentation page */ - std::string getHelpUrl(const std::string& englishShortName, const std::string& htmlDocStore, const std::string& pageName); + std::string getHelpUrl(const std::string& englishShortName, const std::string& htmlDocStore, const std::string& pageName) noexcept; } #endif //DOCUMENTATION_H \ No newline at end of file diff --git a/include/localization/gettext.h b/include/localization/gettext.h index a7238f1f..c4e8aafa 100644 --- a/include/localization/gettext.h +++ b/include/localization/gettext.h @@ -43,30 +43,30 @@ namespace Nickvision::Localization::Gettext * @param domainName The domain name to use for gettext translations. Must be lowercase and contain no spaces * @return True if initialized, else false */ - bool init(const std::string& domainName); + bool init(const std::string& domainName) noexcept; /** * @brief Gets the domain name used for gettext translations. * @return The gettext domain name */ - const std::string& getDomainName(); + const std::string& getDomainName() noexcept; /** * @brief Gets the list of available translated languages. * @brief Does not include the "C" language (the default language). * @return The list of available translated languages. */ - const std::vector& getAvailableLanguages(); + const std::vector& getAvailableLanguages() noexcept; /** * @brief Changes the current language for gettext translations. * @param language The language code to change translations to (use "C" to turn off translations; use "" to use the system default language) * @return True if the language was changed successfully, else false */ - bool changeLanguage(const std::string& language); + bool changeLanguage(const std::string& language) noexcept; /** * @brief Translates a message. * @param msgid The message to translate * @return The translated message */ - const char* dgettext(const char* msgid); + const char* dgettext(const char* msgid) noexcept; /** * @brief Translates a plural message. * @param msg The message to translate @@ -74,7 +74,7 @@ namespace Nickvision::Localization::Gettext * @param n The number of objects (used to determine whether or not to use the plural version of the message) * @return The translated message for the given number of objects */ - const char* dngettext(const char* msg, const char* msgPlural, unsigned long n); + const char* dngettext(const char* msg, const char* msgPlural, unsigned long n) noexcept; /** * @brief Translates a message and formats it with the given arguments. * @param msg The message to translate @@ -82,7 +82,7 @@ namespace Nickvision::Localization::Gettext * @return The formatted translated message */ template - std::string fgettext(const char* msg, Args&&... args) + std::string fgettext(const char* msg, Args&&... args) noexcept { return std::vformat(Nickvision::Localization::Gettext::dgettext(msg), std::make_format_args(args...)); } @@ -95,7 +95,7 @@ namespace Nickvision::Localization::Gettext * @return The formatted translated message for the given number of objects */ template - std::string fngettext(const char* msg, const char* msgPlural, unsigned long n, Args&&... args) + std::string fngettext(const char* msg, const char* msgPlural, unsigned long n, Args&&... args) noexcept { return std::vformat(Nickvision::Localization::Gettext::dngettext(msg, msgPlural, n), std::make_format_args(args...)); } @@ -105,7 +105,7 @@ namespace Nickvision::Localization::Gettext * @param msg The message to translate * @return The translated message for the given context. */ - const char* pgettext(const char* context, const char* msg); + const char* pgettext(const char* context, const char* msg) noexcept; /** * @brief Translates a plural message for a given context. * @param context The context of the message @@ -114,7 +114,7 @@ namespace Nickvision::Localization::Gettext * @param n The number of objects (used to determine whether or not to use the plural version of the message) * @return The translated message for the given context and number of objects. */ - const char* pngettext(const char* context, const char* msg, const char* msgPlural, unsigned long n); + const char* pngettext(const char* context, const char* msg, const char* msgPlural, unsigned long n) noexcept; } #endif //GETTEXT_H diff --git a/include/network/addressfamily.h b/include/network/addressfamily.h deleted file mode 100644 index b2cf3fd6..00000000 --- a/include/network/addressfamily.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef ADDRESSFAMILY_H -#define ADDRESSFAMILY_H - -#ifdef _WIN32 -#include -#else -#include -#endif - -namespace Nickvision::Network -{ - /** - * @brief Type of address that can be used by a socket. - */ - enum class AddressFamily - { -#ifdef _WIN32 - Pipe, -#else - Unix = AF_UNIX, -#endif - IPv4 = AF_INET - }; -} - -#endif //ADDRESSFAMILY_H diff --git a/include/network/ipv4address.h b/include/network/ipv4address.h index bfac138e..ea18d16f 100644 --- a/include/network/ipv4address.h +++ b/include/network/ipv4address.h @@ -41,48 +41,48 @@ namespace Nickvision::Network * @param third The third byte of the address * @param fourth The fourth byte of the address */ - IPv4Address(unsigned char first, unsigned char second, unsigned char third, unsigned char fourth); + IPv4Address(unsigned char first, unsigned char second, unsigned char third, unsigned char fourth) noexcept; /** * @brief Constructs an IPv4Address. * @param address The address as a long */ - IPv4Address(unsigned long address); + IPv4Address(unsigned long address) noexcept; + /** + * @brief Parses an IPv4Address from a string. + * @param address The string address to parse + * @return The parsed address if successful, else std::nullopt + */ + static std::optional parse(const std::string& address) noexcept; /** * @brief Gets the first byte of the address. * @return The first byte of the address */ - unsigned char getFirst() const; + unsigned char getFirst() const noexcept; /** * @brief Gets the second byte of the address. * @return The second byte of the address */ - unsigned char getSecond() const; + unsigned char getSecond() const noexcept; /** * @brief Gets the third byte of the address. * @return The third byte of the address */ - unsigned char getThird() const; + unsigned char getThird() const noexcept; /** * @brief Gets the fourth byte of the address. * @return The fourth byte of the address */ - unsigned char getFourth() const; + unsigned char getFourth() const noexcept; /** * @brief Gets the address in network byte order. * @return The address in network byte order */ - unsigned long getNetworkByteOrder() const; + unsigned long getNetworkByteOrder() const noexcept; /** * @brief Gets the string representation of the address. * @return The string representation of the address */ - std::string str() const; - /** - * @brief Parses an IPv4Address from a string. - * @param address The string address to parse - * @return The parsed address if successful, else std::nullopt - */ - static std::optional parse(const std::string& address); + std::string str() const noexcept; private: unsigned char m_first; diff --git a/include/network/macaddress.h b/include/network/macaddress.h index 09e0348e..62b1792e 100644 --- a/include/network/macaddress.h +++ b/include/network/macaddress.h @@ -43,48 +43,48 @@ namespace Nickvision::Network * @param nic2 The second byte of the NIC * @param nic3 The third byte of the NIC */ - MacAddress(unsigned char oui1, unsigned char oui2, unsigned char oui3, unsigned char nic1, unsigned char nic2, unsigned char nic3); + MacAddress(unsigned char oui1, unsigned char oui2, unsigned char oui3, unsigned char nic1, unsigned char nic2, unsigned char nic3) noexcept; + /** + * @brief Parses a MacAddress from a string. + * @param address The string address to parse + * @return The parsed address if successful, else std::nullopt + */ + static std::optional parse(const std::string& address) noexcept; /** * @brief Gets the first byte of the address. * @return The first byte of the address */ - unsigned char getFirst() const; + unsigned char getFirst() const noexcept; /** * @brief Gets the second byte of the address. * @return The second byte of the address */ - unsigned char getSecond() const; + unsigned char getSecond() const noexcept; /** * @brief Gets the third byte of the address. * @return The third byte of the address */ - unsigned char getThird() const; + unsigned char getThird() const noexcept; /** * @brief Gets the fourth byte of the address. * @return The fourth byte of the address */ - unsigned char getFourth() const; + unsigned char getFourth() const noexcept; /** * @brief Gets the fifth byte of the address. * @return The fifth byte of the address */ - unsigned char getFifth() const; + unsigned char getFifth() const noexcept; /** * @brief Gets the sixth byte of the address. * @return The sixth byte of the address */ - unsigned char getSixth() const; + unsigned char getSixth() const noexcept; /** * @brief Gets the string representation of the address. * @return The string representation of the address */ - std::string str() const; - /** - * @brief Parses a MacAddress from a string. - * @param address The string address to parse - * @return The parsed address if successful, else std::nullopt - */ - static std::optional parse(const std::string& address); + std::string str() const noexcept; private: unsigned char m_oui1; diff --git a/include/network/networkmonitor.h b/include/network/networkmonitor.h index 39918091..15c6d9a8 100644 --- a/include/network/networkmonitor.h +++ b/include/network/networkmonitor.h @@ -52,17 +52,17 @@ namespace Nickvision::Network /** * @brief Destructs a NetworkMonitor. */ - ~NetworkMonitor(); + ~NetworkMonitor() noexcept; /** * @brief Gets the StateChanged event. This event is invoked whenever the state of the network connection changes. * @return The StateChanged event */ - Events::Event& stateChanged(); + Events::Event& stateChanged() noexcept; /** * @brief Gets the state of the network connection. * @return NetworkState */ - NetworkState getConnectionState() const; + NetworkState getConnectionState() const noexcept; #ifdef _WIN32 ULONG STDMETHODCALLTYPE AddRef() override; ULONG STDMETHODCALLTYPE Release() override; @@ -75,7 +75,7 @@ namespace Nickvision::Network /** * @brief Manually checks the state of the system's network connection. If a change is detected, the StateChanged event will be invoked. */ - void checkConnectionState(); + void checkConnectionState() noexcept; mutable std::mutex m_mutex; Events::Event m_stateChanged; NetworkState m_connectionState; diff --git a/include/network/networkstatechangedeventargs.h b/include/network/networkstatechangedeventargs.h index 00b43448..fc5e8c64 100644 --- a/include/network/networkstatechangedeventargs.h +++ b/include/network/networkstatechangedeventargs.h @@ -38,12 +38,12 @@ namespace Nickvision::Network * @brief Constructs a NetworkStateChangedEventArgs. * @param state NetworkStae */ - NetworkStateChangedEventArgs(NetworkState state); + NetworkStateChangedEventArgs(NetworkState state) noexcept; /** * @brief Gets the network state. * @return NetworkState */ - NetworkState getState() const; + NetworkState getState() const noexcept; private: NetworkState m_state; diff --git a/include/network/socket.h b/include/network/socket.h deleted file mode 100644 index 787e3267..00000000 --- a/include/network/socket.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef SOCKET_H -#define SOCKET_H - -#include -#include -#ifdef _WIN32 -#include -#endif -#include "addressfamily.h" -#include "socketpurpose.h" -#include "sockettype.h" - -namespace Nickvision::Network -{ - /** - * @brief A network socket (an endpoint for communication). - */ - class Socket - { - public: - /** - * @brief Constructs a Socket. - * @param purpose The purpose of the socket - * @param type The SocketType of the socket (Ignored when AddressFamily::Pipe is used) - * @param family The AddressFamily of the socket - * @param address The address to bind/connect the socket to - * @param port The port to bind/connect the socket to (Ignored when AddressFamily::Unix or AddressFamily::Pipe is used) - * @throw std::invalid_argument Thrown if the address is invalid - * @throw std::logic_error Thrown if the socket cannot be binded to (i.e. A server socket already exists) - * @throw std::runtime_error Thrown on Windows if winsock cannot be initialized - * @throw std::runtime_error Thrown if the socket cannot be created or listened - */ - Socket(SocketPurpose purpose, SocketType type, AddressFamily family, const std::string& address, int port); - /** - * @brief Destructs a Socket. - * @brief This will disconnect from a child socket if disconnect was not already called. - */ - ~Socket(); - /** - * @brief Establishes a connection. - * @brief If the socket's purpose is SocketPurpose::Server, this method will block until a client is connected. - * @brief Is the socket's purpose is SocketPurpose::Client, this method will connect to the server. - * @return True if connected, else false - */ - bool connect(); - /** - * @brief Closes a connection. - * @brief If the socket's purpose is SocketPurpose::Server, this method will drop the connection with the client. - * @brief If the socket's purpose is SocketPurpose::Client, this method will have no effect. - * @return True if disconnected, else false - */ - bool disconnect(); - /** - * @brief Receives a message. - * @brief connect() must have been called first and have returned true. - * @brief If the socket's purpose is SocketPurpose::Server, this method will receive a message from the client. - * @brief If the socket's purpose is SocketPurpose::Client, this method will receive a message from the server. - * @return The received message - */ - std::string receiveMessage() const; - /** - * @brief Sends a message. - * @brief connect() must have been called first and have returned true. - * @brief If the socket's purpose is SocketPurpose::Server, this method will send a message to the client. - * @brief If the socket's purpose is SocketPurpose::Client, this method will send a message to the server. - * @param message The message to send - * @return True if message sent successfully, else false - */ - bool sendMessage(const std::string& message) const; - - private: - SocketPurpose m_purpose; - SocketType m_type; - AddressFamily m_family; - std::string m_address; - int m_port; -#ifdef _WIN32 - SOCKET m_socket; - SOCKET m_child; - HANDLE m_pipe; -#else - int m_socket; - int m_child; -#endif - }; -} - -#endif //SOCKET_H diff --git a/include/network/socketpurpose.h b/include/network/socketpurpose.h deleted file mode 100644 index 7016d0dc..00000000 --- a/include/network/socketpurpose.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef SOCKETPURPOSE_H -#define SOCKETPURPOSE_H - -namespace Nickvision::Network -{ - /** - * @brief Purposes of sockets. - */ - enum class SocketPurpose - { - Server, - Client - }; -} - -#endif // SOCKETPURPOSE_H diff --git a/include/network/sockettype.h b/include/network/sockettype.h deleted file mode 100644 index c22c3e45..00000000 --- a/include/network/sockettype.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef SOCKETTYPE_H -#define SOCKETTYPE_H - -#ifdef _WIN32 -#include -#else -#include -#endif - -namespace Nickvision::Network -{ - /** - * @brief Type of sockets. - */ - enum class SocketType - { - Stream = SOCK_STREAM, - Datagram = SOCK_DGRAM, -#ifdef __linux__ - SequencedPacket = SOCK_SEQPACKET -#endif - }; -} - -#endif // SOCKETTYPE_H diff --git a/include/network/web.h b/include/network/web.h index 83ef5291..d6ddfc9a 100644 --- a/include/network/web.h +++ b/include/network/web.h @@ -35,14 +35,14 @@ namespace Nickvision::Network::Web * @param url The url to check * @return True if valid website, else false */ - bool getWebsiteExists(const std::string& url); + bool getWebsiteExists(const std::string& url) noexcept; /** * @brief Makes a GET request for json from a url. * @param url The url of the json resource * @return The parsed json value * @return An empty json value if error */ - boost::json::value getJson(const std::string& url); + boost::json::value getJson(const std::string& url) noexcept; /** * @brief Downloads a file to disk. * @param url The url of the file to download @@ -50,7 +50,7 @@ namespace Nickvision::Network::Web * @param progress An optional function to receive progress on the download * @param overwrite Whether or not to overwrite existing files on disk */ - bool downloadFile(const std::string& url, const std::filesystem::path& path, const cpr::ProgressCallback& progress = {}, bool overwrite = true); + bool downloadFile(const std::string& url, const std::filesystem::path& path, const cpr::ProgressCallback& progress = {}, bool overwrite = true) noexcept; } #endif //WEB_H diff --git a/include/notifications/appnotification.h b/include/notifications/appnotification.h index 4617e021..b7b7eec6 100644 --- a/include/notifications/appnotification.h +++ b/include/notifications/appnotification.h @@ -10,12 +10,12 @@ namespace Nickvision::Notifications::AppNotification * @brief Gets the event for when an app notification is sent. * @return The app notification sent event */ - Events::Event& sent(); + Events::Event& sent() noexcept; /** * @brief Sends a notification to the app. * @param args NotificationSentEventArgs */ - void send(const NotificationSentEventArgs& args); + void send(const NotificationSentEventArgs& args) noexcept; } #endif //APPNOTIFICATION_H diff --git a/include/notifications/notificationsenteventargs.h b/include/notifications/notificationsenteventargs.h index 26d2f498..daa1afec 100644 --- a/include/notifications/notificationsenteventargs.h +++ b/include/notifications/notificationsenteventargs.h @@ -42,27 +42,27 @@ namespace Nickvision::Notifications * @param action An additional action for the notification * @param actionParam The parameter of the additional action */ - NotificationSentEventArgs(const std::string& message, NotificationSeverity severity, const std::string& action = "", const std::string& actionParam = ""); + NotificationSentEventArgs(const std::string& message, NotificationSeverity severity, const std::string& action = "", const std::string& actionParam = "") noexcept; /** * @brief Gets the message of the notification. * @return The message of the notification */ - const std::string& getMessage() const; + const std::string& getMessage() const noexcept; /** * @brief Gets the severity of the notification. * @return The severity of the notification */ - NotificationSeverity getSeverity() const; + NotificationSeverity getSeverity() const noexcept; /** * @brief Gets the optional action of the notification. * @return The optional action of the notification */ - const std::string& getAction() const; + const std::string& getAction() const noexcept; /** * @brief Gets the parameter of the optional action. * @return The parameter of the optional action */ - const std::string& getActionParam() const; + const std::string& getActionParam() const noexcept; protected: std::string m_message; diff --git a/include/notifications/shellnotification.h b/include/notifications/shellnotification.h index 7bd8d02a..2c9e9592 100644 --- a/include/notifications/shellnotification.h +++ b/include/notifications/shellnotification.h @@ -42,7 +42,7 @@ namespace Nickvision::Notifications::ShellNotification * @return True if notification sent * @return False if notification not sent */ - void send(const ShellNotificationSentEventArgs& e, const App::AppInfo& info, const std::string& openText = ""); + void send(const ShellNotificationSentEventArgs& e, const App::AppInfo& info, const std::string& openText = "") noexcept; } #endif //SHELLNOTIFICATION_H diff --git a/include/notifications/shellnotificationsenteventargs.h b/include/notifications/shellnotificationsenteventargs.h index 7f94bf6e..a0084a6b 100644 --- a/include/notifications/shellnotificationsenteventargs.h +++ b/include/notifications/shellnotificationsenteventargs.h @@ -41,12 +41,12 @@ namespace Nickvision::Notifications * @param action An additional action for the notification * @param actionParam The parameter of the additional action */ - ShellNotificationSentEventArgs(const std::string& title, const std::string& message, NotificationSeverity severity, const std::string& action = "", const std::string& actionParam = ""); + ShellNotificationSentEventArgs(const std::string& title, const std::string& message, NotificationSeverity severity, const std::string& action = "", const std::string& actionParam = "") noexcept; /** * @brief Gets the title of the notification. * @return The title of the notification */ - const std::string& getTitle() const; + const std::string& getTitle() const noexcept; protected: std::string m_title; diff --git a/include/system/credentials.h b/include/system/credentials.h new file mode 100644 index 00000000..537de09c --- /dev/null +++ b/include/system/credentials.h @@ -0,0 +1,75 @@ +/** + * @file + * @author Nicholas Logozzo + * + * @section LICENSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details at + * https://www.gnu.org/copyleft/gpl.html + * + * @section DESCRIPTION + * + * Functions for working with the system credential manager (secret store). + */ + +#ifndef CREDENTIALS_H +#define CREDENTIALS_H + +#include +#include +#include "keyring/credential.h" + +namespace Nickvision::System::Credentials +{ + /** + * @brief Gets a credential from the system's credential manager. + * @param name The name of the credential + * @return The Credential object + * @return std::nullopt if the credential was not found + */ + std::optional get(const std::string& name) noexcept; + /** + * @brief Creates a new credential with a random password and adds it to the system's credential manager. + * @param name The name of the credential to create + * @return The new Credential object + * @return std::nullopt if the credential could not be created + */ + std::optional create(const std::string& name) noexcept; + /** + * @brief Adds a new credential object to the system's credential manager. + * @brief On Linux, only the name and password of a credential object will be stored. + * @brief On Windows, all fields of a credential object will be stored. + * @brief On macOS, all fields of a credential object will be stored. + * @param credential The new credential object + * @return True if the credential object was added + * @return False if the credential object was not added + */ + bool add(const Keyring::Credential& credential) noexcept; + /** + * @brief Updates a credential object in the system's credential manager. + * @brief On Linux, only the name and password of a credential object will be stored. + * @brief On Windows, all fields of a credential object will be stored. + * @brief On macOS, all fields of a credential object will be stored. + * @param credential The updated credential object + * @return True if the credential object was updated + * @return False if the credential object was not updated + */ + bool update(const Keyring::Credential& credential) noexcept; + /** + * @brief Removes a credential object from the system's credential manager. + * @param name The name of the credential to remove + * @return True if the credential object was removed + * @return False if the credential object was not removed + */ + bool remove(const std::string& name) noexcept; +} + +#endif //SYSTEMCREDENTIALS_H \ No newline at end of file diff --git a/include/system/dependencysearchoption.h b/include/system/dependencysearchoption.h index 04e0214c..6eceb874 100644 --- a/include/system/dependencysearchoption.h +++ b/include/system/dependencysearchoption.h @@ -1,10 +1,32 @@ +/** + * @file + * @author Nicholas Logozzo + * + * @section LICENSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details at + * https://www.gnu.org/copyleft/gpl.html + * + * @section DESCRIPTION + * + * Search options for search for dependencies on the system. + */ + #ifndef DEPENDENCYSEARCHOPTION_H #define DEPENDENCYSEARCHOPTION_H namespace Nickvision::System { /** - * @brief Search options for search for dependencies on the system + * @brief Search options for search for dependencies on the system. */ enum class DependencySearchOption { diff --git a/include/system/environment.h b/include/system/environment.h index 863589c4..1a17806f 100644 --- a/include/system/environment.h +++ b/include/system/environment.h @@ -17,7 +17,7 @@ * * @section DESCRIPTION * - * Functions for working with the system's shell and environment. + * Functions for working with the apps's shell and environment. */ #ifndef ENVIRONMENT_H @@ -28,6 +28,7 @@ #endif #include +#include #include #include #include "app/appinfo.h" @@ -35,13 +36,16 @@ #include "deploymentmode.h" #include "operatingsystem.h" +/** + * @brief Functions for working with the apps's shell and environment. + */ namespace Nickvision::System::Environment { /** * @brief Gets the current operating system. * @return The current operating system */ - constexpr OperatingSystem getOperatingSystem() + constexpr OperatingSystem getOperatingSystem() noexcept { #ifdef _WIN32 return OperatingSystem::Windows; @@ -57,79 +61,85 @@ namespace Nickvision::System::Environment * @brief Gets the current deployment mode. * @return The current deployment mode */ - DeploymentMode getDeploymentMode(); + DeploymentMode getDeploymentMode() noexcept; /** * @brief Gets the path of the executable's directory. * @return The executable's directory path */ - const std::filesystem::path& getExecutableDirectory(); + const std::filesystem::path& getExecutableDirectory() noexcept; /** * @brief Gets the path of the executable file. * @return The executable file's path */ - const std::filesystem::path& getExecutablePath(); + const std::filesystem::path& getExecutablePath() noexcept; /** * @brief Gets the name of the current locale. * @return The locale name */ - std::string getLocaleName(); + std::string getLocaleName() noexcept; /** * @brief Checks if an environment variable exists. * @param key The environment variable to check * @return True if the environment variable exists, else false */ - bool hasVariable(const std::string& key); + bool hasVariable(const std::string& key) noexcept; /** * @brief Gets the value of an environment variable. * @param key The environment variable to get * @return The environment variable value if found, else empty string */ - std::string getVariable(const std::string& key); + std::string getVariable(const std::string& key) noexcept; /** * @brief Sets the value of an environment variable. * @param key The environment variable to set * @param value The value for the environment variable * @return True if set, else false */ - bool setVariable(const std::string& key, const std::string& value); + bool setVariable(const std::string& key, const std::string& value) noexcept; /** * @brief Clears an environment variable. * @param key The environment variable to delete * @return True if deleted, else false */ - bool clearVariable(const std::string& key); + bool clearVariable(const std::string& key) noexcept; /** * @brief Tests an environment variable value to see if it is true. * @brief A true value is one that is "true", "t", "yes", "y", or "1". * @param key The environment variable to test * @return True if the value is true, else false */ - bool testVariable(const std::string& key); + bool testVariable(const std::string& key) noexcept; /** * @brief Gets a list of directories from the system PATH variable. * @return The list of directories from PATH */ - std::vector getPath(); + std::vector getPath() noexcept; /** * @brief Executes a command in the system shell. * @param cmd The command to execute * @return The output of the command */ - std::string exec(const std::string& cmd); + std::string exec(const std::string& cmd) noexcept; + /** + * @brief Executes a command asynchronously in the system shell. + * @param cmd The command to execute + * @return The future containing the output of the command + */ + std::future execAsync(const std::string& cmd) noexcept; /** * @brief Finds the path of a given executable dependency in the system. * @param dependency The name of the executable dependency to find * @param search The DependencySearchOption to use in the dependency search * @return The path to the executable dependency if found, else empty path */ - const std::filesystem::path& findDependency(std::string dependency, DependencySearchOption search = DependencySearchOption::Global); + const std::filesystem::path& findDependency(std::string dependency, DependencySearchOption search = DependencySearchOption::Global) noexcept; /** * @brief Gets a debug information string about the user's environment. * @brief appInfo The application's AppInfo * @brief extraInformation Extra information to append to the end of the debug information string * @return The debug information string */ - std::string getDebugInformation(const App::AppInfo& appInfo, const std::string& extraInformation = ""); + std::string getDebugInformation(const App::AppInfo& appInfo, const std::string& extraInformation = "") noexcept; } #endif //ENVIRONMENT_H diff --git a/include/system/hardwareinfo.h b/include/system/hardwareinfo.h index 20dc00ad..b5c4a367 100644 --- a/include/system/hardwareinfo.h +++ b/include/system/hardwareinfo.h @@ -1,23 +1,48 @@ +/** + * @file + * @author Nicholas Logozzo + * + * @section LICENSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details at + * https://www.gnu.org/copyleft/gpl.html + * + * @section DESCRIPTION + * + * Functions for working with the system's hardware information. + */ + #ifndef HARDWAREINFO_H #define HARDWAREINFO_H +/** + * @brief Functions for working with the system's hardware information. + */ namespace Nickvision::System::HardwareInfo { /** * @brief Gets the number of logical processors (CPU) on the system. * @return The number of logical processors */ - unsigned int getNumberOfProcessors(); + unsigned int getNumberOfProcessors() noexcept; /** * @brief Gets the amount of RAM in the system in bytes. * @return The amount of RAM in bytes */ - unsigned long long getTotalRamSize(); + unsigned long long getTotalRamSize() noexcept; /** * @brief Gets the amount of RAM free in the system in bytes. * @return The amount of free RAM in bytes */ - unsigned long long getFreeRamSize(); + unsigned long long getFreeRamSize() noexcept; } #endif //HARDWAREINFO_H diff --git a/include/system/process.h b/include/system/process.h index 333ec988..c29ade1c 100644 --- a/include/system/process.h +++ b/include/system/process.h @@ -59,88 +59,88 @@ namespace Nickvision::System * @brief Destructs a Process. * @brief This method will wait for the process to exit if it is still running. */ - ~Process(); + ~Process() noexcept; /** * @brief Gets the event for when the process has exited. * @return The process exited event */ - Events::Event& exited(); + Events::Event& exited() noexcept; /** * @brief Gets the path of the process. * @return The path of the process */ - const std::filesystem::path& getPath() const; + const std::filesystem::path& getPath() const noexcept; /** * @brief Gets the state of the proicess. * @return The state of the process. */ - ProcessState getState() const; + ProcessState getState() const noexcept; /** * @brief Gets the exit code of the process. * @return The exit code of the process. -1 if the process has not completed */ - int getExitCode() const; + int getExitCode() const noexcept; /** * @brief Gets the console output of the process. * @return The console output of the process. Empty if the process has not completed */ - const std::string& getOutput() const; + const std::string& getOutput() const noexcept; /** * @brief Gets the percent of the CPU being used by the process. * @return The CPU usage of the process */ - double getCPUUsage() const; + double getCPUUsage() const noexcept; /** * @brief Gets the amount of RAM being used by the process in bytes. * @return The amount of RAM used by the process */ - unsigned long long getRAMUsage() const; + unsigned long long getRAMUsage() const noexcept; /** * @brief Starts the process. * @brief Use Process::resume() to start again a paused process. * @return True if the process was started, else false */ - bool start(); + bool start() noexcept; /** * @brief Kills the process. * @return True if the process was killed, else false */ - bool kill(); + bool kill() noexcept; /** * @brief Resumes the process. * @return True if the process was resumed, else false */ - bool resume(); + bool resume() noexcept; /** * @brief Pauses the process. * @return True if the process was paused, else false */ - bool pause(); + bool pause() noexcept; /** * @brief Waits for the process to exit. * @brief This function will block until the process has exited. * @brief Make sure to call start() / resume() before calling this function. * @return The exit code of the process */ - int waitForExit(); + int waitForExit() noexcept; /** * @brief Sends text to the process' console. * @param s The text to send * @return True if the text is sent, else false */ - bool send(const std::string& s); + bool send(const std::string& s) noexcept; /** * @brief Sends text to the process' console and adds the return characters. * @param s The command to send * @return True if the command is sent, else false */ - bool sendCommand(std::string s); + bool sendCommand(std::string s) noexcept; private: /** * @brief Watches the process. */ - void watch(); + void watch() noexcept; mutable std::mutex m_mutex; std::filesystem::path m_path; std::vector m_args; diff --git a/include/system/suspendinhibitor.h b/include/system/suspendinhibitor.h index 8dca16b7..f595e279 100644 --- a/include/system/suspendinhibitor.h +++ b/include/system/suspendinhibitor.h @@ -40,49 +40,49 @@ namespace Nickvision::System * @brief Constructs a SuspendInhibitor. * @brief This will not inhibit the system from suspending until the inhibit() function is called. */ - SuspendInhibitor(); + SuspendInhibitor() noexcept; /** - * @brief Copies a SuspendInhibitor object. - * @param inhibitor The object to move + * @brief Constructs a SuspendInhibitor via copy. + * @param other The object to copy */ - SuspendInhibitor(const SuspendInhibitor& inhibitor); + SuspendInhibitor(const SuspendInhibitor& other) noexcept; /** - * @brief Moves a SuspendInhibitor object. - * @param inhibitor The object to move + * @brief Constructs a SuspendInhibitor via move. + * @param other The object to move */ - SuspendInhibitor(SuspendInhibitor&& inhibitor) noexcept; + SuspendInhibitor(SuspendInhibitor&& other) noexcept; /** * @brief Destructs a SuspendInhibitor. * @brief If the system is being inhibited, it will uninhibit. */ - ~SuspendInhibitor(); + ~SuspendInhibitor() noexcept; /** * @brief Gets whether or not the system is being inhibited from suspending. * @return True if inhibiting, else false */ - bool isInhibiting() const; + bool isInhibiting() const noexcept; /** * @brief Inhibits the system from suspending. * @return True if successful, else false */ - bool inhibit(); + bool inhibit() noexcept; /** * @brief Uninhibits the system from suspending. * @return True if successful, else false */ - bool uninhibit(); + bool uninhibit() noexcept; /** - * @brief Copies a SuspendInhibitor object. - * @param inhibitor The SuspendInhibitor to copy + * @brief Assigns a SuspendInhibitor via copy. + * @param other The object to copy * @return this */ - SuspendInhibitor& operator=(const SuspendInhibitor& inhibitor); + SuspendInhibitor& operator=(const SuspendInhibitor& other) noexcept; /** - * @brief Moves a SuspendInhibitor object. - * @param inhibitor The SuspendInhibitor to move + * @brief Assigns a SuspendInhibitor via move. + * @param other The object to move * @return this */ - SuspendInhibitor& operator=(SuspendInhibitor&& inhibitor) noexcept; + SuspendInhibitor& operator=(SuspendInhibitor&& other) noexcept; private: mutable std::mutex m_mutex; diff --git a/include/taskbar/taskbaritem.h b/include/taskbar/taskbaritem.h deleted file mode 100644 index 67c0f8a1..00000000 --- a/include/taskbar/taskbaritem.h +++ /dev/null @@ -1,149 +0,0 @@ -/** - * @file - * @author Nicholas Logozzo - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details at - * https://www.gnu.org/copyleft/gpl.html - * - * @section DESCRIPTION - * - * An item on the taskbar. - */ - -#ifndef TASKBARITEM_H -#define TASKBARITEM_H - -#include -#include -#include -#include "progressstate.h" -#ifdef _WIN32 -#include -#include -#include -#include -#elif defined(__linux__) -#include -#endif - -namespace Nickvision::Taskbar -{ - /** - * @brief An item on the taskbar. - */ - class TaskbarItem - { - public: - /** - * @brief Constructs a TaskbarItem. - */ - TaskbarItem(); - /** - * @brief Destructs a TaskbarItem. - */ - ~TaskbarItem(); - /** - * @brief Gets the state of the progress. - * @return ProgressState - */ - ProgressState getProgressState() const; - /** - * @brief Sets the state of the progress. - * @param state The new ProgressState - */ - void setProgressState(ProgressState state); - /** - * @brief Gets the value of the progress. - * @return The progress value - */ - double getProgress() const; - /** - * @brief Sets the value of the progress. Setting the progress value will set the progress state to Normal if progress > 0, else will set progress state to NoProgress. - * @brief Should be a value between 0 and 1. - * @param progress The new progress value - */ - void setProgress(double progress); - /** - * @brief Gets whether or not the taskbar item is shown in an urgent state. - * @return True if in urgent state, else false - */ - bool getUrgent() const; - /** - * @brief Sets whether or not the taskbar item is shown in an urgent state. - * @param urgent True for urgent state, else false - */ - void setUrgent(bool urgent); - /** - * @brief Gets whether or not the count is visible on the taskbar item. - * @return True if count visible, else false - */ - bool getCountVisible() const; - /** - * @brief Sets whether or not the count is visible on the taskbar item. - * @param countVisible True for visible count, else false - */ - void setCountVisible(bool countVisible); - /** - * @brief Gets the count shown on the taskbar item. - * @return The count value - */ - long getCount() const; - /** - * @brief Sets the count shown on the taskbar item. - * @param count The new count value - */ - void setCount(long count); -#ifdef _WIN32 - /** - * @brief Connects a taskbar item to the application. - * @param hwnd The HWND of the main application window - * @return True if connection successful, else false - */ - bool connect(HWND hwnd); -#elif defined(__linux__) - /** - * @brief Connects a taskbar item to the application. - * @param desktopFile The desktop file name with the file extension of the running application - * @return True if connection successful, else false - */ - bool connect(const std::string& desktopFile); -#endif - - private: - mutable std::mutex m_mutex; - ProgressState m_progressState; - double m_progress; - bool m_urgent; - bool m_countVisible; - long m_count; -#ifdef _WIN32 - /** - * @brief Draws the icon with the item's count on the TaskbarItem. - */ - void drawCountIcon(); - HWND m_hwnd; - CComPtr m_taskbar; - ULONG_PTR m_gdi; -#elif defined(__linux__) - /** - * @brief Sends the com.canonical.Unity.LauncherEntry.Update signal over the session dbus. - */ - void sendDBusUpdate(); - GDBusConnection* m_connection; - std::string m_objectPath; - std::string m_appUri; -#endif - }; -} - -#endif //TASKBARITEM_H \ No newline at end of file diff --git a/include/update/updater.h b/include/update/updater.h index 4609ede4..67a1cffa 100644 --- a/include/update/updater.h +++ b/include/update/updater.h @@ -47,7 +47,7 @@ namespace Nickvision::Update * @brief Constructs an Updater via copy. * @param u The object to copy */ - Updater(const Updater& u); + Updater(const Updater& u) noexcept; /** * @brief Constructs an Updater via move. * @param u The object to move @@ -59,7 +59,7 @@ namespace Nickvision::Update * @param versionType The type of the version to get * @return The current version of the provided type if available, else empty Version */ - Version fetchCurrentVersion(VersionType versionType); + Version fetchCurrentVersion(VersionType versionType) noexcept; /** * @brief Downloads an update for the application. * @brief fetchCurrentVersion should be called first before running this method. @@ -70,7 +70,7 @@ namespace Nickvision::Update * @param progress An optional cpr::ProgressCallback to track the downloading update * @return True if successful, else false */ - bool downloadUpdate(VersionType versionType, const std::filesystem::path& path, const std::string& assetName, bool exactMatch = true, const cpr::ProgressCallback& progress = {}); + bool downloadUpdate(VersionType versionType, const std::filesystem::path& path, const std::string& assetName, bool exactMatch = true, const cpr::ProgressCallback& progress = {}) noexcept; #ifdef _WIN32 /** * @brief Downloads and installs an application update for Windows. @@ -80,14 +80,14 @@ namespace Nickvision::Update * @param progress An optional cpr::ProgressCallback to track the downloading update * @return True if successful, else false */ - bool windowsUpdate(VersionType versionType, const cpr::ProgressCallback& progress = {}); + bool windowsUpdate(VersionType versionType, const cpr::ProgressCallback& progress = {}) noexcept; #endif /** * @brief Copies an Updater. * @param u The Updater to copy * @return this */ - Updater& operator=(const Updater& u); + Updater& operator=(const Updater& u) noexcept; /** * @brief Moves an Updater. * @param u The Updater to move diff --git a/include/update/version.h b/include/update/version.h index df1e2f65..4948b0ca 100644 --- a/include/update/version.h +++ b/include/update/version.h @@ -39,14 +39,14 @@ namespace Nickvision::Update /** * @brief Constructs a Version. */ - Version(); + Version() noexcept; /** * @brief Constructs a Version. * @param major The major number * @param minor The minor number * @param build The build number */ - Version(int major, int minor, int build); + Version(int major, int minor, int build) noexcept; /** * @brief Constructs a Version. * @param major The major number @@ -66,77 +66,73 @@ namespace Nickvision::Update * @brief Gets the major number of the version. * @return The major number */ - int getMajor() const; + int getMajor() const noexcept; /** * @brief Gets the minor number of the version. * @return The minor number */ - int getMinor() const; + int getMinor() const noexcept; /** * @brief Gets the build number of the version. * @return The build number */ - int getBuild() const; + int getBuild() const noexcept; /** * @brief Gets the dev string of the version. * @return The dev string */ - const std::string& getDev() const; + const std::string& getDev() const noexcept; /** * @brief Gets the type of the version. * @return VersionType */ - VersionType getVersionType() const; + VersionType getVersionType() const noexcept; /** * @brief Gets a string representation of the Version. * @return The string representation of the Version */ - const std::string& str() const; + const std::string& str() const noexcept; /** * @brief Gets whether or not the Version object is empty * @return True if empty, else false */ - bool empty() const; + bool empty() const noexcept; /** * @brief Compares Version objects via < operator * @param compare The Version object to compare too * @return True if this < compare */ - bool operator<(const Version& compare) const; + bool operator<(const Version& compare) const noexcept; /** * @brief Compares Version objects via <= operator * @param compare The Version object to compare too * @return True if this <= compare */ - bool operator<=(const Version& compare) const; + bool operator<=(const Version& compare) const noexcept; /** * @brief Compares Version objects via > operator * @param compare The Version object to compare too * @return True if this > compare */ - bool operator>(const Version& compare) const; + bool operator>(const Version& compare) const noexcept; /** * @brief Compares Version objects via >= operator * @param compare The Version object to compare too * @return True if this >= compare */ - bool operator>=(const Version& compare) const; + bool operator>=(const Version& compare) const noexcept; /** * @brief Compares Version objects via == operator * @param compare The Version object to compare too * @return True if this == compare */ - bool operator==(const Version& compare) const; + bool operator==(const Version& compare) const noexcept; /** * @brief Compares Version objects via != operator * @param compare The Version object to compare too * @return True if this != compare */ - bool operator!=(const Version& compare) const; - /** - * @brief Outputs the Version object - */ - friend std::ostream& operator<<(std::ostream& os, const Version& version); + bool operator!=(const Version& compare) const noexcept; private: int m_major; diff --git a/manual/README.md b/manual/README.md index 891d4719..17afd5e7 100644 --- a/manual/README.md +++ b/manual/README.md @@ -6,15 +6,39 @@ libnick provides Nickvision apps with a common set of cross-platform APIs for managing system and desktop app functionality such as network management, taskbar icons, translations, app updates, and more. -## 2025.8.0 +## 2025.9.0 ### Breaking Changes -None -### New APIs #### App -- Added `reset()` method to `CancellationToken` +- Removed `DataFileBase` +- Removed `DataFileManager` +- Moved `AppInfo::convertUrlMapToVector()` to `Helpers::CodeHelpers` namespace +- Moved `App::CancellationToken` to `Helpers` namespace +#### Database +- Rewrote all classes with a more modern interface +- Renamed all classes with `Sqlite` prefix +#### Keyring +- Rewrote `Keyring` class with a more modern interface +- Moved `SystemCredentials` to `System::Credentials` namespace +- Removed `CredentialCheckStatus` enum +- Removed `PasswordStrength` module +#### Network +- Removed `DNS` module +#### Taskbar +- Removed module +### New APIs +#### Helpers +- Added `DEFINE_ENUM_FLAGS()` macro to `CodeHelpers` namespace +- Added `IJsonSerializable` interface +- Added `JsonFileBase` to replace `DataFileBase` +- Added `quote()` function to `StringHelpers` namespace +#### Keyring +- Added `Space` value to `PasswordContent` +#### System +- Added `execAsync()` function to `Environment` namespace ### Fixes -#### Events -- Fixed the `operator->()` method for `ParamEventArgs` +- Marked functions and methods with `noexcept` where applicable +#### System +- Fixed `Process`'s handling of quoted strings ## Dependencies The following are a list of dependencies used by libnick. diff --git a/manual/datafiles.md b/manual/datafiles.md deleted file mode 100644 index 041e51b3..00000000 --- a/manual/datafiles.md +++ /dev/null @@ -1,56 +0,0 @@ -# Creating Your Own Data Files -The purpose of `DataFileBase` is to act as a base when defining your own data objects that you would like to be saved and retrieved from disk. - -Here are some key points when defining your own configuration objects: -- Your data object's constructor must take `const std::string& key` and `const std::string& appName` parameters and pass it to `DataFileBase`'s constructor. - - Although you will not use `key` and `appName` in your own implementation, it is required for `DataFileBase`'s functionality and will be filled-in by the `DataFileManager`. -- `DataFileBase` exposes a protected `m_json` object which you must use in your implementation of getting and storing variables of your data object. - - If this `m_json` object is not used, your data object will not be stored to disk correctly. -- You must explicitly call the `save` method on your configuration object when you want to save the configuration to disk. Writing to the `m_json` (of type `boost::json::object`) object is not enough to trigger saving the file on disk. - -Here is an example of a custom configuration object using `DataFileBase`: -```cpp -using namespace Nickvision::App; -using namespace Nickvision::Events; - -class AppConfig : public DataFileBase -{ -public: - AppConfig(const std::string& key, const std::string& appName) - : DataFileBase{ key, appName } - { - - } - - bool getAutomaticallyCheckForUpdates() const - { - const boost::json::value& value{ m_json["AutomaticallyCheckForUpdates"] }; - if(!value.is_bool()) - { - return true; - } - return value.as_bool(); - } - - void setAutomaticallyCheckForUpdates(bool value) - { - m_json["AutomaticallyCheckForUpdates"] = value; - } -}; - -//This object can now be used with the DataFileManager: - -int main() -{ - DataFileManager dfm{ "AppName" }; - AppConfig& config{ dfm.get("config") }; - config.saved() += [](const EventArgs& e) { std::cout << "Config saved to disk." << std::endl; }; - if(config.getPreviousCount() > 0) - { - std::cout << config.getPreviousCount() << std::endl; - } - config.setPreviousCount(6); - config.save(); //above lambda will be invoked on success - return 0; -} -``` \ No newline at end of file diff --git a/manual/events.md b/manual/events.md index 1d61e3d9..691061dd 100644 --- a/manual/events.md +++ b/manual/events.md @@ -1,12 +1,12 @@ # Defining Events In Your Classes libnick events are designed to easily integrate within your classes to easily notify consumers of changes in state of an object. -Let's take a look at `Nickvision::App::DataFileBase` and how it defines and uses events. +Let's take a look at `Nickvision::Helpers::JsonFileBase` and how it defines and uses events. ```cpp -namespace Nickvision::App +namespace Nickvision::Helpers { - class DataFileBase + class JsonFileBase { public: ... @@ -29,12 +29,12 @@ namespace Nickvision::App } ``` -Here we can see how `Nickvision::App::DataFileBase` defines a `saved` event, exposes it to the consumer, and triggers/invokes the event within its `save` method. +Here we can see how `Nickvision::Helpers::JsonFileBase` defines a `saved` `Nickvision::Events::Event`, exposes it to the consumer, and triggers/invokes the event within its `save` method. -A consumer of `Nickvision::App::DataFileBase` can easily subscribe to the event and have its handler called when the configuration object is saved: +A consumer of `Nickvision::Helpers::JsonFileBase` can easily subscribe to the event, via the `subscribe()` method or `+=` operator, and have its handler called when the configuration object is saved: ```cpp -using namespace Nickvision::App; using namespace Nickvision::Events; +using namespace Nickvision::Helpers; void handler(const EventArgs& e) { @@ -43,7 +43,7 @@ void handler(const EventArgs& e) int main() { - DataFileBase base{ ... }; + JsonFileBase base{ ... }; base.saved() += handler; base.save(); } diff --git a/manual/ipc.md b/manual/ipc.md deleted file mode 100644 index 9e3074a5..00000000 --- a/manual/ipc.md +++ /dev/null @@ -1,37 +0,0 @@ -# Performing Inter-Process Communication -libnick uses named-pipes on Windows and Unix Domain Sockets on Linux and macOS to establish inter process server and client communicators, while abstracting all of that away from the consumer in the easy to use `Nickvision::App::InterProcessCommunicator` API. - -Upon creating an `Nickvision::App::InterProcessCommunicator` object, either `isServer()` or `isClient()` will return true depending on whether or not this instance is a server or client respectively. Server instances should register a callback to the `CommandReceived` event to be invoked when clients send commands to the server. - -NOTE: Server instance of `Nickvision::App::InterProcessCommunicator` should be kept alive for the entire need for the communicator. This includes when the need to receive client messages is present. - -Let's consider an example scenario for using the `Nickvision::App::InterProcessCommunicator`. Assume we have an application where we want the first instance to be considered the main, running instance. Assume that if other instances of said application are started, we want its arguments to be passed to the main instance and then have said other instances be closed. This will allow, for example, a GUI main instance to be manipulated via secondary CLI instances. - -Here's the code for this: -```cpp -using namespace Nickvision::App; -using namespace Nickvision::Events; - -int main(int argc, char*[] argv) -{ - std::vector modernArgs; - for(int i = 0; i < argc; i++) - { - if(argv[i]) - { - modernArgs.push_back({ argv[i] }); - } - } - InterProcessCommunicator& ipc{ "appid" }; - ipc.commandReceived() += handleArguments; - ipc.communicate(modernArgs, true); -} - -void handleArguments(const ParamEventArgs>& args) -{ - ... -} -``` -If this program is ran for the first time, `ipc` will be the server instance. The `handleArguments` function will be invoked after `communicate` with its own arguments, as `communicate` still invokes `CommandReceived` even if ipc is the server instance. - -If this program is ran *not* for the first time, its arguments will be sent to the first instance and this instance itself will close (as `true` was passed as the second argument of `communicate`). The first instance's `handleArguments` function will be called as a result of `CommandReceived` being invoked by the ipc server receiving the command. \ No newline at end of file diff --git a/manual/jsonfiles.md b/manual/jsonfiles.md new file mode 100644 index 00000000..ecd50aa9 --- /dev/null +++ b/manual/jsonfiles.md @@ -0,0 +1,46 @@ +# Working with Json configuration files +The purpose of `Nickvision::Helpers::JsonFileBase` is to act as a base when defining your own json data objects that you would like to be saved and retrieved from disk. + +Here are some key points when defining your own configuration objects: +- Your data object's constructor must take `const std::filesystem::path& path` parameter and pass it to `JsonFileBase`'s constructor. +- `JsonFileBase` exposes protected templated `T get(const std::string& key, const T& defaultValue)` and `void set(const std::string& key, const T& value)` methods which you must use in your implementation to get and store data from the json object. +- You must explicitly call the `save` method on your object when you want to save the configuration json file to disk. Calling `get` and `set` are not enough to trigger saving the file on disk. + +Here is an example of a custom configuration object using `JsonFileBase`: +```cpp +using namespace Nickvision::Events; +using namespace Nickvision::Helpers; + +class AppConfig : public JsonFileBase +{ +public: + AppConfig(const std::filesystem::path& path) + : JsonFileBase{ path } + { + + } + + bool getAutomaticallyCheckForUpdates() const + { + return get("AutomaticallyCheckForUpdates", true); + } + + void setAutomaticallyCheckForUpdates(bool value) + { + set("AutomaticallyCheckForUpdates", value); + } +}; + +int main() +{ + AppConfig config{ "config.json" }; + config.saved() += [](const EventArgs& e) { std::cout << "Config saved to disk." << std::endl; }; + if(config.getAutomaticallyCheckForUpdates()) + { + std::cout << "Checking for updates..." << std::endl; + } + config.setAutomaticallyCheckForUpdates(false); + config.save(); //above lambda will be invoked + return 0; +} +``` diff --git a/src/app/appinfo.cpp b/src/app/appinfo.cpp index 94d9c7c2..b53aa965 100644 --- a/src/app/appinfo.cpp +++ b/src/app/appinfo.cpp @@ -1,5 +1,4 @@ #include "app/appinfo.h" -#include #include #include "helpers/stringhelpers.h" @@ -8,7 +7,7 @@ using namespace Nickvision::Update; namespace Nickvision::App { - AppInfo::AppInfo(const std::string& id, const std::string& name, const std::string& englishShortName) + AppInfo::AppInfo(const std::string& id, const std::string& name, const std::string& englishShortName) noexcept : m_id{ id }, m_name{ name }, m_englishShortName{ englishShortName } @@ -16,72 +15,72 @@ namespace Nickvision::App } - const std::string& AppInfo::getId() const + const std::string& AppInfo::getId() const noexcept { return m_id; } - void AppInfo::setId(const std::string& id) + void AppInfo::setId(const std::string& id) noexcept { m_id = id; } - const std::string& AppInfo::getName() const + const std::string& AppInfo::getName() const noexcept { return m_name; } - void AppInfo::setName(const std::string& name) + void AppInfo::setName(const std::string& name) noexcept { m_name = name; } - const std::string& AppInfo::getShortName() const + const std::string& AppInfo::getShortName() const noexcept { return m_shortName; } - void AppInfo::setShortName(const std::string& shortName) + void AppInfo::setShortName(const std::string& shortName) noexcept { m_shortName = shortName; } - const std::string& AppInfo::getEnglishShortName() const + const std::string& AppInfo::getEnglishShortName() const noexcept { return m_englishShortName; } - void AppInfo::setEnglishShortName(const std::string& englishShortName) + void AppInfo::setEnglishShortName(const std::string& englishShortName) noexcept { m_englishShortName = englishShortName; } - const std::string& AppInfo::getDescription() const + const std::string& AppInfo::getDescription() const noexcept { return m_description; } - void AppInfo::setDescription(const std::string& description) + void AppInfo::setDescription(const std::string& description) noexcept { m_description = description; } - const Version& AppInfo::getVersion() const + const Version& AppInfo::getVersion() const noexcept { return m_version; } - void AppInfo::setVersion(const Version& version) + void AppInfo::setVersion(const Version& version) noexcept { m_version = version; } - const std::string& AppInfo::getChangelog() const + const std::string& AppInfo::getChangelog() const noexcept { return m_changelog; } - void AppInfo::setChangelog(const std::string& changelog) + void AppInfo::setChangelog(const std::string& changelog) noexcept { m_changelog = changelog; if (m_changelog.empty()) @@ -103,17 +102,17 @@ namespace Nickvision::App m_htmlChangelog = parser.Parse(markdown); } - const std::string& AppInfo::getHtmlChangelog() const + const std::string& AppInfo::getHtmlChangelog() const noexcept { return m_htmlChangelog; } - const std::string& AppInfo::getSourceRepo() const + const std::string& AppInfo::getSourceRepo() const noexcept { return m_sourceRepo; } - bool AppInfo::setSourceRepo(const std::string& sourceRepo) + bool AppInfo::setSourceRepo(const std::string& sourceRepo) noexcept { if (!StringHelpers::isValidUrl(sourceRepo)) { @@ -123,12 +122,12 @@ namespace Nickvision::App return true; } - const std::string& AppInfo::getIssueTracker() const + const std::string& AppInfo::getIssueTracker() const noexcept { return m_issueTracker; } - bool AppInfo::setIssueTracker(const std::string& issueTracker) + bool AppInfo::setIssueTracker(const std::string& issueTracker) noexcept { if (!StringHelpers::isValidUrl(issueTracker)) { @@ -138,12 +137,12 @@ namespace Nickvision::App return true; } - const std::string& AppInfo::getSupportUrl() const + const std::string& AppInfo::getSupportUrl() const noexcept { return m_supportUrl; } - bool AppInfo::setSupportUrl(const std::string& supportUrl) + bool AppInfo::setSupportUrl(const std::string& supportUrl) noexcept { if (!StringHelpers::isValidUrl(supportUrl)) { @@ -153,67 +152,67 @@ namespace Nickvision::App return true; } - const std::string& AppInfo::getHtmlDocsStore() const + const std::string& AppInfo::getHtmlDocsStore() const noexcept { return m_htmlDocsStore; } - void AppInfo::setHtmlDocsStore(const std::string& htmlDocsStore) + void AppInfo::setHtmlDocsStore(const std::string& htmlDocsStore) noexcept { m_htmlDocsStore = htmlDocsStore; } - std::unordered_map& AppInfo::getExtraLinks() + std::unordered_map& AppInfo::getExtraLinks() noexcept { return m_extraLinks; } - const std::unordered_map& AppInfo::getExtraLinks() const + const std::unordered_map& AppInfo::getExtraLinks() const noexcept { return m_extraLinks; } - std::unordered_map& AppInfo::getDevelopers() + std::unordered_map& AppInfo::getDevelopers() noexcept { return m_developers; } - const std::unordered_map& AppInfo::getDevelopers() const + const std::unordered_map& AppInfo::getDevelopers() const noexcept { return m_developers; } - std::unordered_map& AppInfo::getDesigners() + std::unordered_map& AppInfo::getDesigners() noexcept { return m_designers; } - const std::unordered_map& AppInfo::getDesigners() const + const std::unordered_map& AppInfo::getDesigners() const noexcept { return m_designers; } - std::unordered_map& AppInfo::getArtists() + std::unordered_map& AppInfo::getArtists() noexcept { return m_artists; } - const std::unordered_map& AppInfo::getArtists() const + const std::unordered_map& AppInfo::getArtists() const noexcept { return m_artists; } - const std::string& AppInfo::getTranslatorCredits() const + const std::string& AppInfo::getTranslatorCredits() const noexcept { return m_translatorCredits; } - void AppInfo::setTranslatorCredits(const std::string& translatorCredits) + void AppInfo::setTranslatorCredits(const std::string& translatorCredits) noexcept { m_translatorCredits = translatorCredits; } - std::vector AppInfo::getTranslatorNames() const + std::vector AppInfo::getTranslatorNames() const noexcept { if (m_translatorCredits.empty()) { @@ -238,14 +237,4 @@ namespace Nickvision::App } return vec; } - - std::vector AppInfo::convertUrlMapToVector(const std::unordered_map& urls) - { - std::vector vec; - for (const std::pair& pair : urls) - { - vec.push_back(pair.first + " " + pair.second); - } - return vec; - } } \ No newline at end of file diff --git a/src/app/datafilebase.cpp b/src/app/datafilebase.cpp deleted file mode 100644 index ecb0c356..00000000 --- a/src/app/datafilebase.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "app/datafilebase.h" -#include -#include -#include "filesystem/userdirectories.h" -#include "system/environment.h" - -using namespace Nickvision::Filesystem; -using namespace Nickvision::System; - -namespace Nickvision::App -{ - DataFileBase::DataFileBase(const std::string& key, const std::string& appName, bool isPortable) - : m_key{ key } - { - if (m_key.empty()) - { - throw std::invalid_argument("Key must not be empty."); - } - if(appName.empty()) - { - throw std::invalid_argument("Application name must not be empty."); - } - m_path = (isPortable ? Environment::getExecutableDirectory() : UserDirectories::get(ApplicationUserDirectory::Config, appName)) / (m_key + ".json"); - if (std::filesystem::exists(m_path)) - { - try - { - std::ifstream in{ m_path }; - boost::json::stream_parser parser; - std::string line; - while(std::getline(in, line)) - { - parser.write(line); - } - parser.finish(); - boost::json::value value = parser.release(); - if(value.is_object()) - { - m_json = value.as_object(); - } - } - catch(...) { } - } - } - - const std::string& DataFileBase::getKey() const - { - return m_key; - } - - Events::Event& DataFileBase::saved() - { - return m_saved; - } - - bool DataFileBase::save() - { - std::ofstream out{ m_path }; - out << m_json << std::endl; - m_saved({}); - return true; - } -} diff --git a/src/app/datafilemanager.cpp b/src/app/datafilemanager.cpp deleted file mode 100644 index 3bb2b3f3..00000000 --- a/src/app/datafilemanager.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "app/datafilemanager.h" - -namespace Nickvision::App -{ - DataFileManager::DataFileManager(const std::string& appName, bool isPortable) - : m_appName{ appName }, - m_isPortable{ isPortable } - { - - } -} diff --git a/src/app/windowgeometry.cpp b/src/app/windowgeometry.cpp index 77b6065d..9bea1144 100644 --- a/src/app/windowgeometry.cpp +++ b/src/app/windowgeometry.cpp @@ -2,7 +2,7 @@ namespace Nickvision::App { - WindowGeometry::WindowGeometry() + WindowGeometry::WindowGeometry() noexcept : m_width{ 800 }, m_height{ 600 }, m_isMaximized{ false }, @@ -12,7 +12,7 @@ namespace Nickvision::App } - WindowGeometry::WindowGeometry(long width, long height, bool isMaximized) + WindowGeometry::WindowGeometry(long width, long height, bool isMaximized) noexcept : m_width{ width }, m_height{ height }, m_isMaximized{ isMaximized }, @@ -22,7 +22,7 @@ namespace Nickvision::App } - WindowGeometry::WindowGeometry(long width, long height, bool isMaximized, long x, long y) + WindowGeometry::WindowGeometry(long width, long height, bool isMaximized, long x, long y) noexcept : m_width{ width }, m_height{ height }, m_isMaximized{ isMaximized }, @@ -32,7 +32,7 @@ namespace Nickvision::App } - WindowGeometry::WindowGeometry(boost::json::object json) + WindowGeometry::WindowGeometry(boost::json::object json) noexcept : m_width{ json["Width"].is_int64() ? static_cast(json["Width"].as_int64()) : 800 }, m_height{ json["Height"].is_int64() ? static_cast(json["Height"].as_int64()) : 600 }, m_isMaximized{ json["IsMaximized"].is_bool() ? json["IsMaximized"].as_bool() : false }, @@ -42,57 +42,57 @@ namespace Nickvision::App } - long WindowGeometry::getWidth() const + long WindowGeometry::getWidth() const noexcept { return m_width; } - void WindowGeometry::setWidth(long width) + void WindowGeometry::setWidth(long width) noexcept { m_width = width; } - long WindowGeometry::getHeight() const + long WindowGeometry::getHeight() const noexcept { return m_height; } - void WindowGeometry::setHeight(long height) + void WindowGeometry::setHeight(long height) noexcept { m_height = height; } - bool WindowGeometry::isMaximized() const + bool WindowGeometry::isMaximized() const noexcept { return m_isMaximized; } - void WindowGeometry::setIsMaximized(bool isMaximized) + void WindowGeometry::setIsMaximized(bool isMaximized) noexcept { m_isMaximized = isMaximized; } - long WindowGeometry::getX() const + long WindowGeometry::getX() const noexcept { return m_x; } - void WindowGeometry::setX(long x) + void WindowGeometry::setX(long x) noexcept { m_x = x; } - long WindowGeometry::getY() const + long WindowGeometry::getY() const noexcept { return m_y; } - void WindowGeometry::setY(long y) + void WindowGeometry::setY(long y) noexcept { m_y = y; } - boost::json::object WindowGeometry::toJson() const + boost::json::value WindowGeometry::toJson() const noexcept { boost::json::object json; json["Width"] = m_width; diff --git a/src/database/sqlcontext.cpp b/src/database/sqlcontext.cpp deleted file mode 100644 index dacf7526..00000000 --- a/src/database/sqlcontext.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "database/sqlcontext.h" - -namespace Nickvision::Database -{ - SqlContext::SqlContext(sqlite3_context* ctx, int argc, sqlite3_value** argv) - : m_context{ ctx } - { - m_values.reserve(argc); - for(int i = 0; i < argc; i++) - { - m_values.push_back({ argv[i] }); - } - } - - void* SqlContext::getUserData() const - { - return sqlite3_user_data(m_context); - } - - const std::vector& SqlContext::getArgs() const - { - return m_values; - } - - void SqlContext::result() - { - sqlite3_result_null(m_context); - } - - void SqlContext::result(int value) - { - sqlite3_result_int(m_context, value); - } - - void SqlContext::result(sqlite_int64 value) - { - sqlite3_result_int64(m_context, value); - } - - void SqlContext::result(double value) - { - sqlite3_result_double(m_context, value); - } - - void SqlContext::result(bool value) - { - sqlite3_result_int(m_context, static_cast(value)); - } - - void SqlContext::result(const std::string& value) - { - sqlite3_result_text(m_context, value.c_str(), static_cast(value.size()), SQLITE_TRANSIENT); - } - - void SqlContext::result(void* value, int n) - { - sqlite3_result_blob(m_context, value, n, SQLITE_TRANSIENT); - } - - void SqlContext::error(const std::string& err) - { - sqlite3_result_error(m_context, err.c_str(), static_cast(err.size())); - } - - void SqlContext::error(int err) - { - sqlite3_result_error_code(m_context, err); - } -} \ No newline at end of file diff --git a/src/database/sqldatabase.cpp b/src/database/sqldatabase.cpp deleted file mode 100644 index 9243f24d..00000000 --- a/src/database/sqldatabase.cpp +++ /dev/null @@ -1,222 +0,0 @@ -#include "database/sqldatabase.h" -#include - -namespace Nickvision::Database -{ - SqlDatabase::SqlDatabase(const std::filesystem::path& path, int flags) - : m_path{ path }, - m_flags{ flags }, - m_isEncrypted{ false }, - m_database{ nullptr }, - m_isUnlocked{ true } - { - sqlite3* database{ nullptr }; - if (sqlite3_open_v2(m_path.string().c_str(), &database, m_flags, nullptr) != SQLITE_OK) - { - throw std::runtime_error("Unable to open sql database."); - } - if(sqlite3_exec(database, "PRAGMA schema_version", nullptr, nullptr, nullptr) != SQLITE_OK) - { - m_isEncrypted = true; - m_isUnlocked = false; - } - m_database = { database, [](sqlite3* sql) - { - sqlite3_close(sql); - } }; - } - - SqlDatabase::SqlDatabase(const SqlDatabase& database) - { - std::lock_guard lock{ database.m_mutex }; - m_path = database.m_path; - m_isEncrypted = database.m_isEncrypted; - m_database = database.m_database; - m_isUnlocked = database.m_isUnlocked; - } - - SqlDatabase::SqlDatabase(SqlDatabase&& database) noexcept - { - std::lock_guard lock{ database.m_mutex }; - m_path = std::move(database.m_path); - m_isEncrypted = std::move(database.m_isEncrypted); - m_database = std::move(database.m_database); - m_isUnlocked = std::move(database.m_isUnlocked); - } - - const std::filesystem::path& SqlDatabase::getPath() const - { - std::lock_guard lock{ m_mutex }; - return m_path; - } - - bool SqlDatabase::isEncrypted() const - { - std::lock_guard lock{ m_mutex }; - return m_isEncrypted; - } - - sqlite3* SqlDatabase::c_obj() - { - return m_database.get(); - } - - bool SqlDatabase::unlock(const std::string& password) - { - std::unique_lock lock{ m_mutex }; - if(!m_isEncrypted) - { - m_isUnlocked = true; - } - else - { - if(sqlite3_key(m_database.get(), password.c_str(), static_cast(password.size())) != SQLITE_OK) - { - m_isUnlocked = false; - } - else - { - lock.unlock(); - m_isUnlocked = exec("PRAGMA schema_version"); - } - } - return m_isUnlocked; - } - - bool SqlDatabase::changePassword(const std::string& password) - { - std::unique_lock lock{ m_mutex }; - //Remove password if empty (decrypt) - if(password.empty()) - { - if(m_isEncrypted) - { - if(!m_isUnlocked) - { - return false; - } - //Create temp decrypted database - std::filesystem::path tempPath{ (m_path.string() + ".decrypt") }; - lock.unlock(); - exec("ATTACH DATABASE '" + tempPath.string() + "' AS plaintext KEY ''"); - exec("SELECT sqlcipher_export('plaintext')"); - exec("DETACH DATABASE plaintext"); - lock.lock(); - //Remove old encrypted database - m_database.reset(); - std::filesystem::remove(m_path); - std::filesystem::rename(tempPath, m_path); - //Open new decrypted database - sqlite3* database{ nullptr }; - if (sqlite3_open_v2(m_path.string().c_str(), &database, m_flags, nullptr) != SQLITE_OK) - { - throw std::runtime_error("Unable to open sql database."); - } - m_database = { database, [](sqlite3* sql) - { - sqlite3_close(sql); - } }; - m_isEncrypted = false; - m_isUnlocked = true; - } - } - //Change password on encrypted database - else if(m_isEncrypted) - { - if(!m_isUnlocked) - { - return false; - } - sqlite3_rekey(m_database.get(), password.c_str(), static_cast(password.size())); - } - //Set new password (encrypts for the first time) - else - { - //Create temp encrypted database - std::filesystem::path tempPath{ (m_path.string() + ".encrypt") }; - lock.unlock(); - exec("ATTACH DATABASE '" + tempPath.string() + "' AS encrypted KEY '" + password + "'"); - exec("SELECT sqlcipher_export('encrypted')"); - exec("DETACH DATABASE encrypted"); - lock.lock(); - //Remove old encrypted database - m_database.reset(); - std::filesystem::remove(m_path); - std::filesystem::rename(tempPath, m_path); - //Open new encrypted database - sqlite3* database{ nullptr }; - if (sqlite3_open_v2(m_path.string().c_str(), &database, m_flags, nullptr) != SQLITE_OK) - { - throw std::runtime_error("Unable to open sql database."); - } - if(sqlite3_key(database, password.c_str(), static_cast(password.size())) != SQLITE_OK) - { - throw std::runtime_error("Unable to key sql database."); - } - m_database = { database, [](sqlite3* sql) - { - sqlite3_close(sql); - } }; - m_isEncrypted = true; - m_isUnlocked = true; - } - return true; - } - - bool SqlDatabase::exec(const std::string& command) - { - std::lock_guard lock{ m_mutex }; - return sqlite3_exec(m_database.get(), command.c_str(), nullptr, nullptr, nullptr) == SQLITE_OK; - } - - SqlStatement SqlDatabase::createStatement(const std::string& command) - { - std::lock_guard lock{ m_mutex }; - return { m_database, command }; - } - - bool SqlDatabase::registerFunction(const std::string& name, const SqliteCustomFunction& func, int expectedArgs) - { - m_custom[name] = func; - return sqlite3_create_function(m_database.get(), name.c_str(), expectedArgs, SQLITE_UTF8, &m_custom[name], +[](sqlite3_context* ctx, int argc, sqlite3_value** argv) - { - SqlContext context{ ctx, argc, argv }; - SqliteCustomFunction& func{ *(static_cast(context.getUserData())) }; - func(context); - }, nullptr, nullptr) == SQLITE_OK; - } - - SqlDatabase& SqlDatabase::operator=(const SqlDatabase& database) - { - if (this != &database) - { - std::lock_guard lock{ m_mutex }; - std::lock_guard lock2{ database.m_mutex }; - m_path = database.m_path; - m_isEncrypted = database.m_isEncrypted; - m_database = database.m_database; - m_isUnlocked = database.m_isUnlocked; - } - return *this; - } - - SqlDatabase& SqlDatabase::operator=(SqlDatabase&& database) noexcept - { - if (this != &database) - { - std::lock_guard lock{ m_mutex }; - std::lock_guard lock2{ database.m_mutex }; - m_path = std::move(database.m_path); - m_isEncrypted = std::move(database.m_isEncrypted); - m_database = std::move(database.m_database); - m_isUnlocked = std::move(database.m_isUnlocked); - } - return *this; - } - - SqlDatabase::operator bool() const - { - std::lock_guard lock{ m_mutex }; - return m_database.operator bool() && (m_isEncrypted ? m_isUnlocked : true); - } -} \ No newline at end of file diff --git a/src/database/sqlitedatabase.cpp b/src/database/sqlitedatabase.cpp new file mode 100644 index 00000000..e0926a4d --- /dev/null +++ b/src/database/sqlitedatabase.cpp @@ -0,0 +1,205 @@ +#include "database/sqlitedatabase.h" +#include + +namespace Nickvision::Database +{ + SqliteDatabase::SqliteDatabase(const std::filesystem::path& path, int flags) + : m_path{ path }, + m_flags{ flags }, + m_isEncrypted{ false }, + m_isUnlocked{ true }, + m_database{ nullptr } + { + if (sqlite3_open_v2(m_path.string().c_str(), &m_database, m_flags, nullptr) != SQLITE_OK) + { + throw std::runtime_error("Unable to open sql database."); + } + if(sqlite3_exec(m_database, "PRAGMA schema_version", nullptr, nullptr, nullptr) != SQLITE_OK) + { + m_isEncrypted = true; + m_isUnlocked = false; + } + } + + SqliteDatabase::SqliteDatabase(SqliteDatabase&& other) noexcept + { + std::lock_guard lock{ other.m_mutex }; + m_path = std::move(other.m_path); + m_isEncrypted = std::move(other.m_isEncrypted); + m_isUnlocked = std::move(other.m_isUnlocked); + m_database = other.m_database; + other.m_database = nullptr; + m_customFunctions = std::move(other.m_customFunctions); + } + + SqliteDatabase::~SqliteDatabase() noexcept + { + if (m_database) + { + sqlite3_close(m_database); + } + } + + const std::filesystem::path& SqliteDatabase::getPath() const noexcept + { + return m_path; + } + + bool SqliteDatabase::isEncrypted() const noexcept + { + std::lock_guard lock{ m_mutex }; + if(!m_database) + { + return false; + } + return m_isEncrypted; + } + + bool SqliteDatabase::isUnlocked() const noexcept + { + std::lock_guard lock{ m_mutex }; + if(!m_database) + { + return false; + } + return m_isUnlocked; + } + + bool SqliteDatabase::unlock(const std::string& password) noexcept + { + std::lock_guard lock{ m_mutex }; + if(!m_database) + { + return false; + } + if(!m_isEncrypted || m_isUnlocked) + { + return true; + } + if(sqlite3_key(m_database, password.c_str(), static_cast(password.size())) != SQLITE_OK) + { + m_isUnlocked = false; + } + else + { + m_isUnlocked = sqlite3_exec(m_database, "PRAGMA schema_version", nullptr, nullptr, nullptr) == SQLITE_OK; + } + return m_isUnlocked; + } + + bool SqliteDatabase::setPassword(const std::string& password) + { + std::lock_guard lock{ m_mutex }; + if(!m_database) + { + return false; + } + //Encrypt non encrypted database + if(!m_isEncrypted) + { + if(password.empty()) + { + return true; + } + //Create temp encrypted database + std::filesystem::path tempPath{ (m_path.string() + ".encrypt") }; + std::string cmd{ "ATTACH DATABASE '" + tempPath.string() + "' AS encrypted KEY '" + password + "'" }; + sqlite3_exec(m_database, cmd.c_str(), nullptr, nullptr, nullptr); + sqlite3_exec(m_database, "SELECT sqlcipher_export('encrypted')", nullptr, nullptr, nullptr); + sqlite3_exec(m_database, "DETACH DATABASE encrypted", nullptr, nullptr, nullptr); + //Remove old encrypted database + sqlite3_close(m_database); + std::filesystem::remove(m_path); + std::filesystem::rename(tempPath, m_path); + //Open new encrypted database + if (sqlite3_open_v2(m_path.string().c_str(), &m_database, m_flags, nullptr) != SQLITE_OK) + { + throw std::runtime_error("Unable to open sql database."); + } + if(sqlite3_key(m_database, password.c_str(), static_cast(password.size())) != SQLITE_OK) + { + throw std::runtime_error("Unable to open sql database with password."); + } + m_isUnlocked = sqlite3_exec(m_database, "PRAGMA schema_version", nullptr, nullptr, nullptr) == SQLITE_OK; + m_isEncrypted = true; + return true; + } + //Encrypted database locked + if(!m_isUnlocked) + { + return false; + } + //Remove encryption + if(password.empty()) + { + //Create temporary decrypted database + std::filesystem::path tempPath{ (m_path.string() + ".decrypt") }; + std::string cmd{ "ATTACH DATABASE '" + tempPath.string() + "' AS plaintext KEY ''" }; + sqlite3_exec(m_database, cmd.c_str(), nullptr, nullptr, nullptr); + sqlite3_exec(m_database, "SELECT sqlcipher_export('plaintext')", nullptr, nullptr, nullptr); + sqlite3_exec(m_database, "DETACH DATABASE plaintext", nullptr, nullptr, nullptr); + //Remove old encrypted database + sqlite3_close(m_database); + std::filesystem::remove(m_path); + std::filesystem::rename(tempPath, m_path); + //Open new decrypted database + if (sqlite3_open_v2(m_path.string().c_str(), &m_database, m_flags, nullptr) != SQLITE_OK) + { + throw std::runtime_error("Unable to open sql database."); + } + m_isEncrypted = false; + m_isUnlocked = true; + return true; + } + //Reencrypt with new password + sqlite3_rekey(m_database, password.c_str(), static_cast(password.size())); + return true; + } + + bool SqliteDatabase::registerFunction(const std::string& name, const SqliteCustomFunction& func, int expectedArgs) noexcept + { + m_customFunctions[name] = func; + return sqlite3_create_function(m_database, name.c_str(), expectedArgs, SQLITE_UTF8, &m_customFunctions[name], +[](sqlite3_context* ctx, int argc, sqlite3_value** argv) + { + SqliteFunctionContext context{ ctx, argc, argv }; + SqliteCustomFunction& func{ *(static_cast(context.getUserData())) }; + func(context); + }, nullptr, nullptr) == SQLITE_OK; + } + + SqliteStatement SqliteDatabase::createStatement(const std::string& command) + { + std::lock_guard lock{ m_mutex }; + if (!m_database || !m_isUnlocked) + { + return { nullptr, "" }; + } + return { m_database, command }; + } + + bool SqliteDatabase::execute(const std::string& command) noexcept + { + std::lock_guard lock{ m_mutex }; + if (!m_database || !m_isUnlocked) + { + return false; + } + return sqlite3_exec(m_database, command.c_str(), nullptr, nullptr, nullptr) == SQLITE_OK; + } + + SqliteDatabase& SqliteDatabase::operator=(SqliteDatabase&& other) noexcept + { + if (this != &other) + { + std::lock_guard lock{ m_mutex }; + std::lock_guard lock2{ other.m_mutex }; + m_path = std::move(other.m_path); + m_isEncrypted = std::move(other.m_isEncrypted); + m_isUnlocked = std::move(other.m_isUnlocked); + m_database = other.m_database; + other.m_database = nullptr; + m_customFunctions = std::move(other.m_customFunctions); + } + return *this; + } +} \ No newline at end of file diff --git a/src/database/sqlitefunctioncontext.cpp b/src/database/sqlitefunctioncontext.cpp new file mode 100644 index 00000000..27491f04 --- /dev/null +++ b/src/database/sqlitefunctioncontext.cpp @@ -0,0 +1,73 @@ +#include "database/sqlitefunctioncontext.h" + +namespace Nickvision::Database +{ + SqliteFunctionContext::SqliteFunctionContext(sqlite3_context* ctx, int argc, sqlite3_value** argv) noexcept + : m_context{ ctx } + { + m_values.reserve(argc); + for(int i = 0; i < argc; i++) + { + m_values.push_back({ argv[i] }); + } + } + + SqliteFunctionContext::SqliteFunctionContext(SqliteFunctionContext&& other) noexcept + : m_context{ other.m_context }, + m_values{ std::move(other.m_values) } + { + other.m_context = nullptr; + } + + void* SqliteFunctionContext::getUserData() const noexcept + { + if(!m_context) + { + return nullptr; + } + return sqlite3_user_data(m_context); + } + + const std::vector& SqliteFunctionContext::getArgs() const noexcept + { + return m_values; + } + + void SqliteFunctionContext::result() noexcept + { + if(!m_context) + { + return; + } + sqlite3_result_null(m_context); + } + + void SqliteFunctionContext::error(const std::string& err) noexcept + { + if(!m_context) + { + return; + } + sqlite3_result_error(m_context, err.c_str(), static_cast(err.size())); + } + + void SqliteFunctionContext::error(int err) noexcept + { + if(!m_context) + { + return; + } + sqlite3_result_error_code(m_context, err); + } + + SqliteFunctionContext& SqliteFunctionContext::operator=(SqliteFunctionContext&& other) noexcept + { + if (this != &other) + { + m_context = other.m_context; + m_values = std::move(other.m_values); + other.m_context = nullptr; + } + return *this; + } +} \ No newline at end of file diff --git a/src/database/sqlitestatement.cpp b/src/database/sqlitestatement.cpp new file mode 100644 index 00000000..28ef4745 --- /dev/null +++ b/src/database/sqlitestatement.cpp @@ -0,0 +1,65 @@ +#include "database/sqlitestatement.h" +#include + +namespace Nickvision::Database +{ + SqliteStatement::SqliteStatement(sqlite3* database, const std::string& command) + : m_statement{ nullptr } + { + if(sqlite3_prepare_v2(database, command.c_str(), static_cast(command.size()), &m_statement, nullptr) != SQLITE_OK) + { + throw std::runtime_error("Unable to create sql statement."); + } + } + + SqliteStatement::SqliteStatement(SqliteStatement&& other) noexcept + : m_statement{ other.m_statement } + { + other.m_statement = nullptr; + } + + SqliteStatement::~SqliteStatement() noexcept + { + if(m_statement) + { + sqlite3_finalize(m_statement); + } + } + + SqliteStepResult SqliteStatement::step() noexcept + { + if(!m_statement) + { + return SqliteStepResult::Error; + } + int res{ sqlite3_step(m_statement) }; + if(res == SQLITE_ROW) + { + return SqliteStepResult::Row; + } + else if(res == SQLITE_DONE) + { + return SqliteStepResult::Done; + } + return SqliteStepResult::Error; + } + + SqliteStatement& SqliteStatement::operator=(SqliteStatement&& other) noexcept + { + if(this != &other) + { + if(m_statement) + { + sqlite3_finalize(m_statement); + } + m_statement = other.m_statement; + other.m_statement = nullptr; + } + return *this; + } + + SqliteStatement::operator bool() const noexcept + { + return m_statement != nullptr; + } +} \ No newline at end of file diff --git a/src/database/sqlitevalue.cpp b/src/database/sqlitevalue.cpp new file mode 100644 index 00000000..2236e899 --- /dev/null +++ b/src/database/sqlitevalue.cpp @@ -0,0 +1,65 @@ +#include "database/sqlitevalue.h" + +namespace Nickvision::Database +{ + SqliteValue::SqliteValue(sqlite3_value* value) noexcept + : m_value{ sqlite3_value_dup(value) }, + m_type{ value ? sqlite3_value_type(value) : SQLITE_NULL } + { + + } + + SqliteValue::SqliteValue(const SqliteValue& other) noexcept + : m_value{ sqlite3_value_dup(other.m_value) }, + m_type{ other.m_type } + { + + } + + SqliteValue::SqliteValue(SqliteValue&& other) noexcept + : m_value{ other.m_value }, + m_type{ other.m_type } + { + other.m_value = nullptr; + other.m_type = SQLITE_NULL; + } + + + SqliteValue::~SqliteValue() noexcept + { + if(m_value) + { + sqlite3_value_free(m_value); + } + } + + SqliteValue& SqliteValue::operator=(const SqliteValue& other) noexcept + { + if (this != &other) + { + if(m_value) + { + sqlite3_value_free(m_value); + } + m_value = sqlite3_value_dup(other.m_value); + m_type = other.m_type; + } + return *this; + } + + SqliteValue& SqliteValue::operator=(SqliteValue&& other) noexcept + { + if (this != &other) + { + if(m_value) + { + sqlite3_value_free(m_value); + } + m_value = other.m_value; + m_type = other.m_type; + other.m_value = nullptr; + other.m_type = SQLITE_NULL; + } + return *this; + } +} \ No newline at end of file diff --git a/src/database/sqlstatement.cpp b/src/database/sqlstatement.cpp deleted file mode 100644 index 98dacc84..00000000 --- a/src/database/sqlstatement.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "database/sqlstatement.h" -#include - -namespace Nickvision::Database -{ - SqlStatement::SqlStatement(const std::shared_ptr& database, const std::string& command) - { - sqlite3_stmt* statement; - if(sqlite3_prepare_v2(database.get(), command.c_str(), static_cast(command.size()), &statement, nullptr) != SQLITE_OK) - { - throw std::runtime_error("Unable to create sql statement."); - } - m_statement = { statement, [](sqlite3_stmt* stmt) - { - sqlite3_finalize(stmt); - } }; - } - - bool SqlStatement::bind(int index, int value) - { - return sqlite3_bind_int(m_statement.get(), index, value) == SQLITE_OK; - } - - bool SqlStatement::bind(int index, sqlite3_int64 value) - { - return sqlite3_bind_int64(m_statement.get(), index, value) == SQLITE_OK; - } - - bool SqlStatement::bind(int index, double value) - { - return sqlite3_bind_double(m_statement.get(), index, value) == SQLITE_OK; - } - - bool SqlStatement::bind(int index, bool value) - { - return sqlite3_bind_int(m_statement.get(), index, static_cast(value)) == SQLITE_OK; - } - - bool SqlStatement::bind(int index, const std::string& value) - { - return sqlite3_bind_text(m_statement.get(), index, value.c_str(), static_cast(value.size()), SQLITE_TRANSIENT) == SQLITE_OK; - } - - bool SqlStatement::bind(int index, void* value, int n) - { - return sqlite3_bind_blob(m_statement.get(), index, value, n, SQLITE_TRANSIENT) == SQLITE_OK; - } - - bool SqlStatement::step() - { - int res{ sqlite3_step(m_statement.get()) }; - if(res != SQLITE_ROW && res != SQLITE_DONE) - { - throw std::runtime_error("Unable to step sql statement."); - } - return res == SQLITE_ROW; - } - - int SqlStatement::getColumnInt(int index) const - { - return sqlite3_column_int(m_statement.get(), index); - } - - sqlite3_int64 SqlStatement::getColumnInt64(int index) const - { - return sqlite3_column_int64(m_statement.get(), index); - } - - double SqlStatement::getColumnDouble(int index) const - { - return sqlite3_column_double(m_statement.get(), index); - } - - bool SqlStatement::getColumnBool(int index) const - { - return static_cast(sqlite3_column_int(m_statement.get(), index)); - } - - std::string SqlStatement::getColumnString(int index) const - { - return { (const char*)sqlite3_column_text(m_statement.get(), index), static_cast(sqlite3_column_bytes(m_statement.get(), index)) }; - } - - std::pair SqlStatement::getColumnBlob(int index) const - { - return { sqlite3_column_blob(m_statement.get(), index), static_cast(sqlite3_column_bytes(m_statement.get(), index)) }; - } - - SqlStatement::operator bool() const - { - return m_statement.operator bool(); - } -} \ No newline at end of file diff --git a/src/database/sqlvalue.cpp b/src/database/sqlvalue.cpp deleted file mode 100644 index 34f6b049..00000000 --- a/src/database/sqlvalue.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "database/sqlvalue.h" - -namespace Nickvision::Database -{ - SqlValue::SqlValue(sqlite3_value* value) - : m_value{ value } - { - - } - - int SqlValue::getInt() const - { - return sqlite3_value_int(m_value); - } - - sqlite3_int64 SqlValue::getInt64() const - { - return sqlite3_value_int64(m_value); - } - - double SqlValue::getDouble() const - { - return sqlite3_value_double(m_value); - } - - bool SqlValue::getBool() const - { - return static_cast(sqlite3_value_int(m_value)); - } - - std::string SqlValue::getString() const - { - return { (const char*)sqlite3_value_text(m_value), static_cast(sqlite3_value_bytes(m_value)) }; - } - - std::pair SqlValue::getBlob() const - { - return { sqlite3_value_blob(m_value), static_cast(sqlite3_value_bytes(m_value)) }; - } -} \ No newline at end of file diff --git a/src/filesystem/filesystemchangedeventargs.cpp b/src/filesystem/filesystemchangedeventargs.cpp index 557f8a64..9d065323 100644 --- a/src/filesystem/filesystemchangedeventargs.cpp +++ b/src/filesystem/filesystemchangedeventargs.cpp @@ -2,19 +2,19 @@ namespace Nickvision::Filesystem { - FileSystemChangedEventArgs::FileSystemChangedEventArgs(const std::filesystem::path& path, FileAction why) + FileSystemChangedEventArgs::FileSystemChangedEventArgs(const std::filesystem::path& path, FileAction why) noexcept : m_path{ path }, m_why{ why } { } - const std::filesystem::path& FileSystemChangedEventArgs::getPath() const + const std::filesystem::path& FileSystemChangedEventArgs::getPath() const noexcept { return m_path; } - FileAction FileSystemChangedEventArgs::getWhy() const + FileAction FileSystemChangedEventArgs::getWhy() const noexcept { return m_why; } diff --git a/src/filesystem/filesystemwatcher.cpp b/src/filesystem/filesystemwatcher.cpp index 33605b1a..620e7d4a 100644 --- a/src/filesystem/filesystemwatcher.cpp +++ b/src/filesystem/filesystemwatcher.cpp @@ -20,9 +20,9 @@ FSEventStreamEventFlags kFSEventStreamEventFlagItemRenamed = 0x00000800; namespace Nickvision::Filesystem { - FileSystemWatcher::FileSystemWatcher(const std::filesystem::path& path, bool incudeSubdirectories, WatcherFlags watcherFlags) + FileSystemWatcher::FileSystemWatcher(const std::filesystem::path& path, bool includeSubdirectories, WatcherFlags watcherFlags) : m_path{ path }, - m_includeSubdirectories{ incudeSubdirectories }, + m_includeSubdirectories{ includeSubdirectories }, m_watcherFlags{ watcherFlags }, m_watching{ true } { @@ -52,7 +52,7 @@ namespace Nickvision::Filesystem m_watchThread = std::thread(&FileSystemWatcher::watch, this); } - FileSystemWatcher::~FileSystemWatcher() + FileSystemWatcher::~FileSystemWatcher() noexcept { m_watching = false; #ifdef _WIN32 @@ -72,27 +72,27 @@ namespace Nickvision::Filesystem } } - const std::filesystem::path& FileSystemWatcher::getPath() const + const std::filesystem::path& FileSystemWatcher::getPath() const noexcept { return m_path; } - WatcherFlags FileSystemWatcher::getWatcherFlags() const + WatcherFlags FileSystemWatcher::getWatcherFlags() const noexcept { return m_watcherFlags; } - bool FileSystemWatcher::getIncludeSubdirectories() const + bool FileSystemWatcher::getIncludeSubdirectories() const noexcept { return m_includeSubdirectories; } - Events::Event& FileSystemWatcher::changed() + Events::Event& FileSystemWatcher::changed() noexcept { return m_changed; } - bool FileSystemWatcher::isExtensionWatched(const std::filesystem::path& extension) + bool FileSystemWatcher::isExtensionWatched(const std::filesystem::path& extension) const noexcept { std::lock_guard lock{ m_mutex }; if (m_extensionFilters.size() == 0) @@ -102,7 +102,7 @@ namespace Nickvision::Filesystem return std::find(m_extensionFilters.begin(), m_extensionFilters.end(), extension) != m_extensionFilters.end(); } - bool FileSystemWatcher::addExtensionFilter(const std::filesystem::path& extension) + bool FileSystemWatcher::addExtensionFilter(const std::filesystem::path& extension) noexcept { std::lock_guard lock{ m_mutex }; if (std::find(m_extensionFilters.begin(), m_extensionFilters.end(), extension) == m_extensionFilters.end()) @@ -113,7 +113,7 @@ namespace Nickvision::Filesystem return false; } - bool FileSystemWatcher::removeExtensionFilter(const std::filesystem::path& extension) + bool FileSystemWatcher::removeExtensionFilter(const std::filesystem::path& extension) noexcept { std::lock_guard lock{ m_mutex }; auto find{ std::find(m_extensionFilters.begin(), m_extensionFilters.end(), extension) }; @@ -125,14 +125,14 @@ namespace Nickvision::Filesystem return false; } - bool FileSystemWatcher::clearExtensionFilters() + bool FileSystemWatcher::clearExtensionFilters() noexcept { std::lock_guard lock{ m_mutex }; m_extensionFilters.clear(); return true; } - void FileSystemWatcher::watch() + void FileSystemWatcher::watch() noexcept { #ifdef _WIN32 HANDLE folder{ CreateFileW(m_path.c_str(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, nullptr) }; @@ -283,7 +283,7 @@ namespace Nickvision::Filesystem } #ifdef __APPLE__ - void FileSystemWatcher::callback(ConstFSEventStreamRef stream, void* clientCallBackInfo, size_t numEvents, void* eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) + void FileSystemWatcher::callback(ConstFSEventStreamRef stream, void* clientCallBackInfo, size_t numEvents, void* eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) noexcept { FileSystemWatcher* watcher{ static_cast(clientCallBackInfo) }; char** paths{ static_cast(eventPaths) }; diff --git a/src/filesystem/userdirectories.cpp b/src/filesystem/userdirectories.cpp index 40c65b84..ddb4d216 100644 --- a/src/filesystem/userdirectories.cpp +++ b/src/filesystem/userdirectories.cpp @@ -18,7 +18,7 @@ using namespace Nickvision::System; namespace Nickvision::Filesystem { #ifdef _WIN32 - static std::filesystem::path getKnownDir(REFKNOWNFOLDERID rfid) + static std::filesystem::path getKnownDir(REFKNOWNFOLDERID rfid) noexcept { std::filesystem::path result; wchar_t* p{ nullptr }; @@ -30,7 +30,7 @@ namespace Nickvision::Filesystem return result; } #elif defined(__linux__) - static std::filesystem::path getXDGDir(const std::string& key) + static std::filesystem::path getXDGDir(const std::string& key) noexcept { std::string var{ Environment::getVariable(key) }; if (!var.empty()) @@ -64,7 +64,7 @@ namespace Nickvision::Filesystem } #endif - std::filesystem::path UserDirectories::get(UserDirectory directory) + std::filesystem::path UserDirectories::get(UserDirectory directory) noexcept { std::filesystem::path result; switch(directory) @@ -206,7 +206,7 @@ namespace Nickvision::Filesystem return result; } - std::filesystem::path UserDirectories::get(ApplicationUserDirectory directory, const std::string& appName) + std::filesystem::path UserDirectories::get(ApplicationUserDirectory directory, const std::string& appName) noexcept { std::filesystem::path result; if(appName.empty()) diff --git a/src/app/cancellationtoken.cpp b/src/helpers/cancellationtoken.cpp similarity index 74% rename from src/app/cancellationtoken.cpp rename to src/helpers/cancellationtoken.cpp index 510f90d3..c023f883 100644 --- a/src/app/cancellationtoken.cpp +++ b/src/helpers/cancellationtoken.cpp @@ -1,33 +1,33 @@ -#include "app/cancellationtoken.h" +#include "helpers/cancellationtoken.h" -namespace Nickvision::App +namespace Nickvision::Helpers { - CancellationToken::CancellationToken(const std::function& cancelFunction) + CancellationToken::CancellationToken(const std::function& cancelFunction) noexcept : m_cancelled{ false }, m_cancelFunction{ cancelFunction } { } - bool CancellationToken::isCancelled() const + bool CancellationToken::isCancelled() const noexcept { std::lock_guard lock{ m_mutex }; return m_cancelled; } - const std::function& CancellationToken::getCancelFunction() const + const std::function& CancellationToken::getCancelFunction() const noexcept { std::lock_guard lock{ m_mutex }; return m_cancelFunction; } - void CancellationToken::setCancelFunction(const std::function& cancelFunction) + void CancellationToken::setCancelFunction(const std::function& cancelFunction) noexcept { std::lock_guard lock{ m_mutex }; m_cancelFunction = cancelFunction; } - void CancellationToken::cancel() + void CancellationToken::cancel() noexcept { std::unique_lock lock{ m_mutex }; if(m_cancelled) @@ -42,14 +42,14 @@ namespace Nickvision::App } } - void CancellationToken::reset() + void CancellationToken::reset() noexcept { std::lock_guard lock{ m_mutex }; m_cancelled = false; m_cancelFunction = {}; } - CancellationToken::operator bool() const + CancellationToken::operator bool() const noexcept { std::lock_guard lock{ m_mutex }; return m_cancelled; diff --git a/src/helpers/codehelpers.cpp b/src/helpers/codehelpers.cpp index 52b2ade5..27ee866f 100644 --- a/src/helpers/codehelpers.cpp +++ b/src/helpers/codehelpers.cpp @@ -9,7 +9,30 @@ namespace Nickvision::Helpers { - std::string CodeHelpers::getLastSystemError() + size_t CodeHelpers::combineHash(size_t a, size_t b) noexcept + { + if constexpr(sizeof(size_t) >= 8) + { + a ^= b + 0x517cc1b727220a95 + (a << 6) + (a >> 2); + } + else + { + a ^= b + 0x9e3779b9 + (a << 6) + (a >> 2); + } + return a; + } + + std::vector CodeHelpers::convertUrlMapToVector(const std::unordered_map& urls) noexcept + { + std::vector vec; + for (const std::pair& pair : urls) + { + vec.push_back(pair.first + " " + pair.second); + } + return vec; + } + + std::string CodeHelpers::getLastSystemError() noexcept { #ifdef _WIN32 DWORD errorMessageID{ GetLastError() }; @@ -27,7 +50,7 @@ namespace Nickvision::Helpers #endif } - std::vector CodeHelpers::readFileBytes(const std::filesystem::path& path) + std::vector CodeHelpers::readFileBytes(const std::filesystem::path& path) noexcept { if(!std::filesystem::exists(path)) { @@ -43,7 +66,7 @@ namespace Nickvision::Helpers return {}; } - bool CodeHelpers::writeFileBytes(const std::filesystem::path& path, const std::vector& bytes, bool overwrite) + bool CodeHelpers::writeFileBytes(const std::filesystem::path& path, const std::vector& bytes, bool overwrite) noexcept { if(std::filesystem::exists(path) && !overwrite) { @@ -57,17 +80,4 @@ namespace Nickvision::Helpers } return false; } - - size_t CodeHelpers::combineHash(size_t a, size_t b) - { - if constexpr(sizeof(size_t) >= 8) - { - a ^= b + 0x517cc1b727220a95 + (a << 6) + (a >> 2); - } - else - { - a ^= b + 0x9e3779b9 + (a << 6) + (a >> 2); - } - return a; - } } diff --git a/src/helpers/jsonfilebase.cpp b/src/helpers/jsonfilebase.cpp new file mode 100644 index 00000000..54d3c122 --- /dev/null +++ b/src/helpers/jsonfilebase.cpp @@ -0,0 +1,72 @@ +#include "helpers/jsonfilebase.h" +#include +#include + +namespace Nickvision::Helpers +{ + JsonFileBase::JsonFileBase(const std::filesystem::path& path) + : m_path{ path } + { + if (m_path.empty()) + { + throw std::invalid_argument("Path must not be empty."); + } + if (std::filesystem::exists(m_path)) + { + try + { + std::ifstream in{ m_path }; + boost::json::stream_parser parser; + std::string line; + while(std::getline(in, line)) + { + parser.write(line); + } + parser.finish(); + boost::json::value value = parser.release(); + if(value.is_object()) + { + m_json = value.as_object(); + } + } + catch(...) { } + } + } + + const std::filesystem::path& JsonFileBase::getPath() const noexcept + { + std::lock_guard lock{ m_mutex }; + return m_path; + } + + Events::Event& JsonFileBase::saved() noexcept + { + std::lock_guard lock{ m_mutex }; + return m_saved; + } + + bool JsonFileBase::save() noexcept + { + std::lock_guard lock{ m_mutex }; + if(m_path.has_parent_path()) + { + std::filesystem::create_directories(m_path.parent_path()); + } + std::ofstream out{ m_path }; + out << m_json << std::endl; + m_saved({}); + return true; + } + + boost::json::value JsonFileBase::toJson() const noexcept + { + std::lock_guard lock{ m_mutex }; + return m_json; + } + + bool JsonFileBase::contains(const std::string& key) const noexcept + { + std::lock_guard lock{ m_mutex }; + return m_json.contains(key); + } +} diff --git a/src/helpers/stringhelpers.cpp b/src/helpers/stringhelpers.cpp index fcc2dc43..b1b0eb2f 100644 --- a/src/helpers/stringhelpers.cpp +++ b/src/helpers/stringhelpers.cpp @@ -18,7 +18,7 @@ using namespace Nickvision::System; namespace Nickvision::Helpers { - std::vector StringHelpers::decode(const std::string& base64) + std::vector StringHelpers::decode(const std::string& base64) noexcept { if(base64.empty() || base64.size() % 4 != 0) { @@ -60,7 +60,7 @@ namespace Nickvision::Helpers return bytes; } - std::string StringHelpers::encode(const std::vector& bytes) + std::string StringHelpers::encode(const std::vector& bytes) noexcept { if(bytes.empty()) { @@ -99,7 +99,7 @@ namespace Nickvision::Helpers return string; } - bool StringHelpers::isValidUrl(const std::string& s) + bool StringHelpers::isValidUrl(const std::string& s) noexcept { if (s.empty()) { @@ -109,7 +109,7 @@ namespace Nickvision::Helpers return std::regex_match(s, urlRegex); } - std::string StringHelpers::join(const std::vector& values, const std::string& separator, bool separateLast) + std::string StringHelpers::join(const std::vector& values, const std::string& separator, bool separateLast) noexcept { std::stringstream builder; for(size_t i = 0; i < values.size(); i++) @@ -124,7 +124,13 @@ namespace Nickvision::Helpers return builder.str(); } - std::string StringHelpers::newUuid() + std::string StringHelpers::lower(std::string s) noexcept + { + std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); }); + return s; + } + + std::string StringHelpers::newUuid() noexcept { #ifdef _WIN32 GUID guid; @@ -144,12 +150,12 @@ namespace Nickvision::Helpers #endif } - std::string StringHelpers::newGuid() + std::string StringHelpers::newGuid() noexcept { return newUuid(); } - std::string StringHelpers::normalizeForFilename(const std::string& s, bool windowsOnly) + std::string StringHelpers::normalizeForFilename(const std::string& s, bool windowsOnly) noexcept { std::string result{ s }; result = replace(result, '/', '_'); //invalid on all operating systems @@ -167,7 +173,26 @@ namespace Nickvision::Helpers return result; } - std::string StringHelpers::replace(std::string s, const std::string& toReplace, const std::string& replace) + std::string StringHelpers::quote(const std::string& s) noexcept + { + if(s[0] == '"' && s[s.size() - 1] == '"') + { + return s; + } +#ifndef _WIN32 + else if(s[0] == '\'' && s[s.size() - 1] == '\'') + { + return s; + } + if(s.find('"') != std::string::npos) + { + return '\'' + s + '\''; + } +#endif + return '"' + s + '"'; + } + + std::string StringHelpers::replace(std::string s, const std::string& toReplace, const std::string& replace) noexcept { if (s.empty() || toReplace.empty()) { @@ -182,7 +207,7 @@ namespace Nickvision::Helpers return s; } - std::string StringHelpers::replace(std::string s, char toReplace, char replace) + std::string StringHelpers::replace(std::string s, char toReplace, char replace) noexcept { if (s.empty()) { @@ -192,7 +217,7 @@ namespace Nickvision::Helpers return s; } - std::vector StringHelpers::splitArgs(std::string s) + std::vector StringHelpers::splitArgs(std::string s) noexcept { std::vector args; std::regex regex{ "((?:[^\\s'\"]+|\"[^\"]*\"|'[^']*')+)" }; @@ -214,7 +239,7 @@ namespace Nickvision::Helpers return args; } - std::string StringHelpers::str(const std::wstring& s) + std::string StringHelpers::str(const std::wstring& s) noexcept { #ifdef _WIN32 int size{ WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, nullptr, 0, nullptr, nullptr) }; @@ -239,7 +264,7 @@ namespace Nickvision::Helpers #endif } - unsigned int StringHelpers::stoui(const std::string& s, size_t* idx, int base) + unsigned int StringHelpers::stoui(const std::string& s, size_t* idx, int base) noexcept { try { @@ -256,19 +281,7 @@ namespace Nickvision::Helpers } } - std::string StringHelpers::lower(std::string s) - { - std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); }); - return s; - } - - std::string StringHelpers::upper(std::string s) - { - std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::toupper(c); }); - return s; - } - - std::string StringHelpers::trim(const std::string& s) + std::string StringHelpers::trim(const std::string& s) noexcept { if(s.empty()) { @@ -286,7 +299,7 @@ namespace Nickvision::Helpers return result; } - std::string StringHelpers::trim(const std::string& s, char delimiter) + std::string StringHelpers::trim(const std::string& s, char delimiter) noexcept { if(s.empty()) { @@ -304,7 +317,13 @@ namespace Nickvision::Helpers return result; } - std::wstring StringHelpers::wstr(const std::string& s) + std::string StringHelpers::upper(std::string s) noexcept + { + std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::toupper(c); }); + return s; + } + + std::wstring StringHelpers::wstr(const std::string& s) noexcept { #ifdef _WIN32 int size{ MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, nullptr, 0) }; diff --git a/src/keyring/credential.cpp b/src/keyring/credential.cpp index 95c84528..02dfebc4 100644 --- a/src/keyring/credential.cpp +++ b/src/keyring/credential.cpp @@ -1,12 +1,8 @@ #include "keyring/credential.h" -#include "keyring/passwordstrength.h" -#include "helpers/stringhelpers.h" - -using namespace Nickvision::Helpers; namespace Nickvision::Keyring { - Credential::Credential(const std::string& name, const std::string& uri, const std::string& username, const std::string& password) + Credential::Credential(const std::string& name, const std::string& uri, const std::string& username, const std::string& password) noexcept : m_name{ name }, m_uri{ uri }, m_username{ username }, @@ -15,73 +11,43 @@ namespace Nickvision::Keyring } - const std::string& Credential::getName() const + const std::string& Credential::getName() const noexcept { return m_name; } - void Credential::setName(const std::string& name) + void Credential::setName(const std::string& name) noexcept { m_name = name; } - const std::string& Credential::getUri() const + const std::string& Credential::getUri() const noexcept { return m_uri; } - void Credential::setUri(const std::string& uri) + void Credential::setUri(const std::string& uri) noexcept { m_uri = uri; } - const std::string& Credential::getUsername() const + const std::string& Credential::getUsername() const noexcept { return m_username; } - void Credential::setUsername(const std::string& username) + void Credential::setUsername(const std::string& username) noexcept { m_username = username; } - const std::string& Credential::getPassword() const + const std::string& Credential::getPassword() const noexcept { return m_password; } - void Credential::setPassword(const std::string& password) + void Credential::setPassword(const std::string& password) noexcept { m_password = password; } - - bool Credential::operator<(const Credential& compare) const - { - return m_name < compare.m_name; - } - - bool Credential::operator>(const Credential& compare) const - { - return m_name > compare.m_name; - } - - bool Credential::operator==(const Credential& compare) const - { - return m_name == compare.m_name; - } - - bool Credential::operator!=(const Credential& compare) const - { - return m_name != compare.m_name; - } - - std::ostream& operator<<(std::ostream& os, const Credential& credential) - { - os << "[CRED: " << credential.getName() << "] " << std::endl; - os << "Uri: " << credential.getUri() << std::endl; - os << "Username: " << credential.getUsername() << std::endl; - os << "Password: " << credential.getPassword() << std::endl; - os << "Strength: " << (int)getPasswordStrength(credential.getPassword()) << std::endl; - return os; - } } \ No newline at end of file diff --git a/src/keyring/keyring.cpp b/src/keyring/keyring.cpp index 1a33fcea..daf18875 100644 --- a/src/keyring/keyring.cpp +++ b/src/keyring/keyring.cpp @@ -1,10 +1,11 @@ #include "keyring/keyring.h" -#include "database/sqlstatement.h" +#include "database/sqlitestatement.h" #include "filesystem/userdirectories.h" -#include "keyring/systemcredentials.h" +#include "system/credentials.h" using namespace Nickvision::Database; using namespace Nickvision::Filesystem; +using namespace Nickvision::System; namespace Nickvision::Keyring { @@ -12,51 +13,73 @@ namespace Nickvision::Keyring : m_name{ name }, m_database{ nullptr } { - std::optional credential{ SystemCredentials::getCredential(name) }; + std::optional credential{ Credentials::get(name) }; if(!credential) { - credential = SystemCredentials::addCredential(name); + credential = Credentials::create(name); } if(credential) { - std::filesystem::path keyringDir{ UserDirectories::get(UserDirectory::Config) / "Nickvision" / "Keyring" }; + static std::filesystem::path keyringDir{ UserDirectories::get(UserDirectory::Config) / "Nickvision" / "Keyring" }; std::filesystem::create_directories(keyringDir); - m_database = std::make_shared(keyringDir / (m_name + ".ring2"), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); - if(m_database->unlock(credential->getPassword())) + m_database = std::make_unique(keyringDir / (m_name + ".ring2")); + if(m_database->isEncrypted()) // Existing Keyring { - if(!m_database->exec("CREATE TABLE IF NOT EXISTS credentials (name TEXT, uri TEXT, username TEXT, password TEXT)")) + if(!m_database->unlock(credential->getPassword())) { m_database.reset(); } - else + SqliteStatement statement{ m_database->createStatement("SELECT * FROM credentials") }; + while(statement.step() != SqliteStepResult::Done) { - SqlStatement statement{ m_database->createStatement("SELECT * FROM credentials") }; - while(statement.step()) - { - m_credentials.push_back({ statement.getColumnString(0), statement.getColumnString(1), statement.getColumnString(2), statement.getColumnString(3) }); - } + m_credentials.push_back({ statement.getColumn(0), statement.getColumn(1), statement.getColumn(2), statement.getColumn(3) }); + } + } + else // New Keyring + { + if(!m_database->setPassword(credential->getPassword())) + { + m_database.reset(); + } + else if(!m_database->execute("CREATE TABLE IF NOT EXISTS credentials (name TEXT, uri TEXT, username TEXT, password TEXT)")) + { + m_database.reset(); } } } } - const std::string& Keyring::getName() const + Keyring::Keyring(Keyring&& other) noexcept + : m_name{ std::move(other.m_name) }, + m_database{ std::move(other.m_database) }, + m_credentials{ std::move(other.m_credentials) } + { + std::lock_guard lock{ other.m_mutex }; + other.m_database = nullptr; + other.m_credentials.clear(); + } + + const std::string& Keyring::getName() const noexcept { + std::lock_guard lock{ m_mutex }; return m_name; } - bool Keyring::isSavingToDisk() const + bool Keyring::isSavingToDisk() const noexcept { + std::lock_guard lock{ m_mutex }; return m_database != nullptr; } - const std::vector& Keyring::getCredentials() const + const std::vector& Keyring::getAll() const noexcept { + std::lock_guard lock{ m_mutex }; return m_credentials; } - std::optional Keyring::getCredential(const std::string& name) + std::optional Keyring::get(const std::string& name) noexcept { + std::lock_guard lock{ m_mutex }; for(const Credential& credential : m_credentials) { if(credential.getName() == name) @@ -67,8 +90,9 @@ namespace Nickvision::Keyring return std::nullopt; } - bool Keyring::addCredential(const Credential& credential) + bool Keyring::add(const Credential& credential) noexcept { + std::lock_guard lock{ m_mutex }; for(const Credential& c : m_credentials) { if(c.getName() == credential.getName()) @@ -76,70 +100,95 @@ namespace Nickvision::Keyring return false; } } - m_credentials.push_back(credential); if(m_database) { - SqlStatement statement{ m_database->createStatement("INSERT INTO credentials (name, uri, username, password) VALUES (?, ?, ?, ?)") }; + SqliteStatement statement{ m_database->createStatement("INSERT INTO credentials (name, uri, username, password) VALUES (?, ?, ?, ?)") }; statement.bind(1, credential.getName()); statement.bind(2, credential.getUri()); statement.bind(3, credential.getUsername()); statement.bind(4, credential.getPassword()); - return !statement.step(); + if(statement.step() != SqliteStepResult::Done) + { + return false; + } } + m_credentials.push_back(credential); return true; } - bool Keyring::updateCredential(const Credential& credential) + bool Keyring::update(const Credential& credential) noexcept { + std::lock_guard lock{ m_mutex }; for(Credential& c : m_credentials) { if(c.getName() == credential.getName()) { - c = credential; if(m_database) { - SqlStatement statement{ m_database->createStatement("UPDATE credentials SET uri = ?, username = ?, password = ? WHERE name = ?") }; + SqliteStatement statement{ m_database->createStatement("UPDATE credentials SET uri = ?, username = ?, password = ? WHERE name = ?") }; statement.bind(1, credential.getUri()); statement.bind(2, credential.getUsername()); statement.bind(3, credential.getPassword()); statement.bind(4, credential.getName()); - return !statement.step(); + if(statement.step() != SqliteStepResult::Done) + { + return false; + } } + c = credential; return true; } } return false; } - bool Keyring::deleteCredential(const std::string& name) + bool Keyring::remove(const std::string& name) noexcept { - for(auto it = m_credentials.begin(); it != m_credentials.end(); ++it) + for(std::vector::iterator it = m_credentials.begin(); it != m_credentials.end(); ++it) { if(it->getName() == name) { - m_credentials.erase(it); if(m_database) { - SqlStatement statement{ m_database->createStatement("DELETE FROM credentials WHERE name = ?") }; + SqliteStatement statement{ m_database->createStatement("DELETE FROM credentials WHERE name = ?") }; statement.bind(1, name); - return !statement.step(); + if(statement.step() != SqliteStepResult::Done) + { + return false; + } } + m_credentials.erase(it); return true; } } return false; } - bool Keyring::destroy() + bool Keyring::destroy() noexcept { if(m_database) { std::filesystem::path path{ m_database->getPath() }; m_database.reset(); m_database = nullptr; - std::filesystem::remove(path); m_credentials.clear(); + return std::filesystem::remove(path); } return true; } + + Keyring& Keyring::operator=(Keyring&& other) noexcept + { + if(this != &other) + { + std::lock_guard lock{ m_mutex }; + std::lock_guard lock2{ other.m_mutex }; + m_name = std::move(other.m_name); + m_credentials = std::move(other.m_credentials); + m_database = std::move(other.m_database); + other.m_database = nullptr; + other.m_credentials.clear(); + } + return *this; + } } \ No newline at end of file diff --git a/src/keyring/passwordgenerator.cpp b/src/keyring/passwordgenerator.cpp index a5754947..3ffba77d 100644 --- a/src/keyring/passwordgenerator.cpp +++ b/src/keyring/passwordgenerator.cpp @@ -1,53 +1,62 @@ #include "keyring/passwordgenerator.h" #include -#include -#include +#include namespace Nickvision::Keyring { - PasswordGenerator::PasswordGenerator(PasswordContent contentFlags) - : m_contentFlags{ contentFlags } + PasswordGenerator::PasswordGenerator(PasswordContent contentFlags) noexcept + : m_contentFlags{ contentFlags }, + m_randomEngine{ m_randomDevice() } { - srand(static_cast(time(nullptr))); + } - PasswordContent PasswordGenerator::getContentFlags() const + PasswordContent PasswordGenerator::getContentFlags() const noexcept { return m_contentFlags; } - void PasswordGenerator::setContentFlags(PasswordContent contentFlags) + void PasswordGenerator::setContentFlags(PasswordContent contentFlags) noexcept { m_contentFlags = contentFlags; } - std::string PasswordGenerator::next(size_t length) + std::string PasswordGenerator::next(size_t length) noexcept { static std::vector numericChars{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', }; static std::vector upperChars{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; static std::vector lowerChars{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; static std::vector specialChars{ '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~' }; - std::string pass; + static std::uniform_int_distribution typeDistribution{ 0, 4 }; + static std::uniform_int_distribution numericDistribution{ 0, numericChars.size() - 1 }; + static std::uniform_int_distribution upperDistribution{ 0, upperChars.size() - 1 }; + static std::uniform_int_distribution lowerDistribution{ 0, lowerChars.size() - 1 }; + static std::uniform_int_distribution specialDistribution{ 0, specialChars.size() - 1 }; + std::string password; for(size_t i = 0; i < length; i++) { while(true) { - PasswordContent randomType{ static_cast(std::pow(2, rand() % 4)) }; + PasswordContent randomType{ static_cast(std::pow(2, typeDistribution(m_randomEngine))) }; if((m_contentFlags & randomType) == PasswordContent::Numeric) { - pass += numericChars[rand() % numericChars.size()]; + password += numericChars[numericDistribution(m_randomEngine)]; } else if((m_contentFlags & randomType) == PasswordContent::Uppercase) { - pass += upperChars[rand() % upperChars.size()]; + password += upperChars[upperDistribution(m_randomEngine)]; } else if((m_contentFlags & randomType) == PasswordContent::Lowercase) { - pass += lowerChars[rand() % lowerChars.size()]; + password += lowerChars[lowerDistribution(m_randomEngine)]; } else if((m_contentFlags & randomType) == PasswordContent::Special) { - pass += specialChars[rand() % specialChars.size()]; + password += specialChars[specialDistribution(m_randomEngine)]; + } + else if((m_contentFlags & randomType) == PasswordContent::Space) + { + password += ' '; } else { @@ -56,6 +65,6 @@ namespace Nickvision::Keyring break; } } - return pass; + return password; } } \ No newline at end of file diff --git a/src/keyring/passwordstrength.cpp b/src/keyring/passwordstrength.cpp deleted file mode 100644 index b6f22083..00000000 --- a/src/keyring/passwordstrength.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "keyring/passwordstrength.h" - -namespace Nickvision::Keyring -{ - PasswordStrength getPasswordStrength(const std::string& password) - { - if (password.empty()) - { - return PasswordStrength::Blank; - } - if (password.size() <= 6) - { - return PasswordStrength::VeryWeak; - } - int strength{ 0 }; - bool containsDigit = false; - bool containsLower = false; - bool containsUpper = false; - bool containsSymbol = false; - if (password.size() >= 12) - { - strength++; - } - for (char ch : password) - { - if (!containsDigit && std::isdigit(ch)) - { - strength++; - containsDigit = true; - } - if (!containsLower && std::isalpha(ch) && std::islower(ch)) - { - strength++; - containsLower = true; - } - if (!containsUpper && std::isalpha(ch) && std::isupper(ch)) - { - strength++; - containsUpper = true; - } - if (!containsSymbol && !std::isalnum(ch)) - { - strength++; - containsSymbol = true; - } - } - return (PasswordStrength)strength; - } -} \ No newline at end of file diff --git a/src/localization/documentation.cpp b/src/localization/documentation.cpp index 549970a6..5e9df78c 100644 --- a/src/localization/documentation.cpp +++ b/src/localization/documentation.cpp @@ -8,7 +8,7 @@ using namespace Nickvision::System; namespace Nickvision::Localization { - std::string Documentation::getHelpUrl(const std::string& englishShortName, const std::string& htmlDocStore, const std::string& pageName) + std::string Documentation::getHelpUrl(const std::string& englishShortName, const std::string& htmlDocStore, const std::string& pageName) noexcept { #ifdef __linux__ if (Environment::getDeploymentMode() != DeploymentMode::Snap) diff --git a/src/localization/gettext.cpp b/src/localization/gettext.cpp index ef2bebea..cf4cc9dc 100644 --- a/src/localization/gettext.cpp +++ b/src/localization/gettext.cpp @@ -13,7 +13,7 @@ namespace Nickvision::Localization static std::string s_domainName{}; static bool s_translationsOff{ false }; - bool Gettext::init(const std::string& domainName) + bool Gettext::init(const std::string& domainName) noexcept { static bool initialized{ false }; if(!initialized) @@ -34,12 +34,12 @@ namespace Nickvision::Localization return true; } - const std::string& Gettext::getDomainName() + const std::string& Gettext::getDomainName() noexcept { return s_domainName; } - const std::vector& Gettext::getAvailableLanguages() + const std::vector& Gettext::getAvailableLanguages() noexcept { static std::vector langs; if(langs.empty()) @@ -56,7 +56,7 @@ namespace Nickvision::Localization return langs; } - bool Gettext::changeLanguage(const std::string& language) + bool Gettext::changeLanguage(const std::string& language) noexcept { if(language.empty()) { @@ -82,7 +82,7 @@ namespace Nickvision::Localization return true; } - const char* Gettext::dgettext(const char* msgid) + const char* Gettext::dgettext(const char* msgid) noexcept { if(s_translationsOff) { @@ -91,7 +91,7 @@ namespace Nickvision::Localization return ::dgettext(s_domainName.c_str(), msgid); } - const char* Gettext::dngettext(const char* msg, const char* msgPlural, unsigned long n) + const char* Gettext::dngettext(const char* msg, const char* msgPlural, unsigned long n) noexcept { if(s_translationsOff) { @@ -100,7 +100,7 @@ namespace Nickvision::Localization return ::dngettext(s_domainName.c_str(), msg, msgPlural, n); } - const char* Gettext::pgettext(const char* context, const char* msg) + const char* Gettext::pgettext(const char* context, const char* msg) noexcept { if(s_translationsOff) { @@ -114,7 +114,7 @@ namespace Nickvision::Localization return translation; } - const char* Gettext::pngettext(const char* context, const char* msg, const char* msgPlural, unsigned long n) + const char* Gettext::pngettext(const char* context, const char* msg, const char* msgPlural, unsigned long n) noexcept { if(s_translationsOff) { diff --git a/src/network/dns.cpp b/src/network/dns.cpp deleted file mode 100644 index b521f318..00000000 --- a/src/network/dns.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "network/dns.h" -#ifdef _WIN32 -#include -#include -#else -#include -#endif - -namespace Nickvision::Network -{ - std::vector DNS::a(const std::string& hostname) - { - std::vector addresses; -#ifdef _WIN32 - DNS_RECORDA* record{ nullptr }; - if(DnsQuery_A(hostname.c_str(), DNS_TYPE_A, DNS_QUERY_STANDARD, nullptr, &record, nullptr) == 0) - { - for(DNS_RECORDA* r = record; r; r = r->pNext) - { - if(r->wType == DNS_TYPE_A) - { - addresses.push_back({ r->Data.A.IpAddress }); - } - } - } - DnsFree(record, DnsFreeRecordList); - -#else - GResolver* resolver{ g_resolver_get_default() }; - GList* record{ g_resolver_lookup_by_name_with_flags(resolver, hostname.c_str(), G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY, nullptr, nullptr) }; - if(record) - { - for(GList* r = record; r; r = r->next) - { - GInetAddress* address{ G_INET_ADDRESS(r->data) }; - if(g_inet_address_get_family(address) == G_SOCKET_FAMILY_IPV4 && g_inet_address_get_native_size(address) == 4) - { - const unsigned char* bytes{ g_inet_address_to_bytes(address) }; - addresses.push_back({ bytes[0], bytes[1], bytes[2], bytes[3] }); - } - } - g_resolver_free_addresses(record); - } - g_object_unref(resolver); -#endif - return addresses; - } - - std::vector DNS::txt(const std::string& hostname) - { - std::vector aliases; -#ifdef _WIN32 - DNS_RECORDA* record{ nullptr }; - if(DnsQuery_A(hostname.c_str(), DNS_TYPE_TEXT, DNS_QUERY_STANDARD, nullptr, &record, nullptr) == 0) - { - for(DNS_RECORDA* r = record; r; r = r->pNext) - { - if(r->wType == DNS_TYPE_TEXT) - { - for(unsigned long i = 0; i < r->Data.TXT.dwStringCount; i++) - { - aliases.push_back(r->Data.TXT.pStringArray[i]); - } - } - } - } - DnsFree(record, DnsFreeRecordList); -#else - GResolver* resolver{ g_resolver_get_default() }; - GList* records{ g_resolver_lookup_records(resolver, hostname.c_str(), G_RESOLVER_RECORD_TXT, nullptr, nullptr) }; - if(records) - { - for(GList* r = records; r; r = r->next) - { - const gchar** contents; - g_variant_get(static_cast(r->data), "(^a&s)", &contents); - for(int i = 0; contents[i]; i++) - { - aliases.push_back(contents[i]); - } - g_free(contents); - } - g_list_free_full(records, GDestroyNotify(+[](gpointer data){ g_variant_unref(static_cast(data)); })); - } - g_object_unref(resolver); -#endif - return aliases; - } -} \ No newline at end of file diff --git a/src/network/ipv4address.cpp b/src/network/ipv4address.cpp index d88b1756..d51e0ff3 100644 --- a/src/network/ipv4address.cpp +++ b/src/network/ipv4address.cpp @@ -1,13 +1,13 @@ #include "network/ipv4address.h" +#include #include -#include #include "helpers/stringhelpers.h" using namespace Nickvision::Helpers; namespace Nickvision::Network { - IPv4Address::IPv4Address(unsigned char first, unsigned char second, unsigned char third, unsigned char fourth) + IPv4Address::IPv4Address(unsigned char first, unsigned char second, unsigned char third, unsigned char fourth) noexcept : m_first{ first }, m_second{ second }, m_third{ third }, @@ -16,7 +16,7 @@ namespace Nickvision::Network } - IPv4Address::IPv4Address(unsigned long address) + IPv4Address::IPv4Address(unsigned long address) noexcept : m_first{ static_cast((address >> 24) & 0xFF) }, m_second{ static_cast((address >> 16) & 0xFF) }, m_third{ static_cast((address >> 8) & 0xFF) }, @@ -25,37 +25,7 @@ namespace Nickvision::Network } - unsigned char IPv4Address::getFirst() const - { - return m_first; - } - - unsigned char IPv4Address::getSecond() const - { - return m_second; - } - - unsigned char IPv4Address::getThird() const - { - return m_third; - } - - unsigned char IPv4Address::getFourth() const - { - return m_fourth; - } - - unsigned long IPv4Address::getNetworkByteOrder() const - { - return (static_cast(m_first) << 24) | (static_cast(m_second) << 16) | (static_cast(m_third) << 8) | static_cast(m_fourth); - } - - std::string IPv4Address::str() const - { - return std::to_string(static_cast(m_first)) + "." + std::to_string(static_cast(m_second)) + "." + std::to_string(static_cast(m_third)) + "." + std::to_string(static_cast(m_fourth)); - } - - std::optional IPv4Address::parse(const std::string& address) + std::optional IPv4Address::parse(const std::string& address) noexcept { if(address == "localhost") { @@ -84,4 +54,34 @@ namespace Nickvision::Network return std::nullopt; } } + + unsigned char IPv4Address::getFirst() const noexcept + { + return m_first; + } + + unsigned char IPv4Address::getSecond() const noexcept + { + return m_second; + } + + unsigned char IPv4Address::getThird() const noexcept + { + return m_third; + } + + unsigned char IPv4Address::getFourth() const noexcept + { + return m_fourth; + } + + unsigned long IPv4Address::getNetworkByteOrder() const noexcept + { + return (static_cast(m_first) << 24) | (static_cast(m_second) << 16) | (static_cast(m_third) << 8) | static_cast(m_fourth); + } + + std::string IPv4Address::str() const noexcept + { + return std::format("{}.{}.{}.{}", static_cast(m_first), static_cast(m_second), static_cast(m_third), static_cast(m_fourth)); + } } diff --git a/src/network/macaddress.cpp b/src/network/macaddress.cpp index 9ee5273a..990faee6 100644 --- a/src/network/macaddress.cpp +++ b/src/network/macaddress.cpp @@ -1,14 +1,13 @@ #include "network/macaddress.h" -#include +#include #include -#include #include "helpers/stringhelpers.h" using namespace Nickvision::Helpers; namespace Nickvision::Network { - MacAddress::MacAddress(unsigned char oui1, unsigned char oui2, unsigned char oui3, unsigned char nic1, unsigned char nic2, unsigned char nic3) + MacAddress::MacAddress(unsigned char oui1, unsigned char oui2, unsigned char oui3, unsigned char nic1, unsigned char nic2, unsigned char nic3) noexcept : m_oui1{ oui1 }, m_oui2{ oui2 }, m_oui3{ oui3 }, @@ -19,50 +18,7 @@ namespace Nickvision::Network } - unsigned char MacAddress::getFirst() const - { - return m_oui1; - } - - unsigned char MacAddress::getSecond() const - { - return m_oui2; - } - - unsigned char MacAddress::getThird() const - { - return m_oui3; - } - - unsigned char MacAddress::getFourth() const - { - return m_nic1; - } - - unsigned char MacAddress::getFifth() const - { - return m_nic2; - } - - unsigned char MacAddress::getSixth() const - { - return m_nic3; - } - - std::string MacAddress::str() const - { - std::stringstream builder; - builder << std::setfill('0') << std::setw(2) << std::hex; - builder << static_cast(m_oui1) << ":"; - builder << static_cast(m_oui2) << ":"; - builder << static_cast(m_oui3) << ":"; - builder << static_cast(m_nic1) << ":"; - builder << static_cast(m_nic2) << ":"; - builder << static_cast(m_nic3); - return StringHelpers::upper(builder.str()); - } - - std::optional MacAddress::parse(const std::string& address) + std::optional MacAddress::parse(const std::string& address) noexcept { std::vector parts{ StringHelpers::split(address, ":") }; if(parts.size() != 6) @@ -89,4 +45,39 @@ namespace Nickvision::Network return std::nullopt; } } + + unsigned char MacAddress::getFirst() const noexcept + { + return m_oui1; + } + + unsigned char MacAddress::getSecond() const noexcept + { + return m_oui2; + } + + unsigned char MacAddress::getThird() const noexcept + { + return m_oui3; + } + + unsigned char MacAddress::getFourth() const noexcept + { + return m_nic1; + } + + unsigned char MacAddress::getFifth() const noexcept + { + return m_nic2; + } + + unsigned char MacAddress::getSixth() const noexcept + { + return m_nic3; + } + + std::string MacAddress::str() const noexcept + { + return StringHelpers::upper(std::format("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", m_oui1, m_oui2, m_oui3, m_nic1, m_nic2, m_nic3)); + } } \ No newline at end of file diff --git a/src/network/networkmonitor.cpp b/src/network/networkmonitor.cpp index d09584aa..202f9067 100644 --- a/src/network/networkmonitor.cpp +++ b/src/network/networkmonitor.cpp @@ -56,7 +56,7 @@ namespace Nickvision::Network checkConnectionState(); } - NetworkMonitor::~NetworkMonitor() + NetworkMonitor::~NetworkMonitor() noexcept { #ifdef _WIN32 m_connectionPoint->Unadvise(m_cookie); @@ -65,50 +65,29 @@ namespace Nickvision::Network #endif } - Events::Event& NetworkMonitor::stateChanged() + Events::Event& NetworkMonitor::stateChanged() noexcept { return m_stateChanged; } - NetworkState NetworkMonitor::getConnectionState() const + NetworkState NetworkMonitor::getConnectionState() const noexcept { std::lock_guard lock{ m_mutex }; return m_connectionState; } - void NetworkMonitor::checkConnectionState() + void NetworkMonitor::checkConnectionState() noexcept { NetworkState newState{ NetworkState::Disconnected }; - if(Environment::testVariable("AURA_DISABLE_NETCHECK")) - { - newState = NetworkState::ConnectedGlobal; - } - else - { #ifdef _WIN32 - NLM_CONNECTIVITY connection{ NLM_CONNECTIVITY_DISCONNECTED }; - if (m_netListManager->GetConnectivity(&connection) == S_OK) - { - if (connection == NLM_CONNECTIVITY_DISCONNECTED) - { - newState = NetworkState::Disconnected; - } - else if (connection & NLM_CONNECTIVITY_IPV4_INTERNET || connection & NLM_CONNECTIVITY_IPV6_INTERNET) - { - newState = NetworkState::ConnectedGlobal; - } - else - { - newState = NetworkState::ConnectedLocal; - } - } -#else - GNetworkConnectivity connection{ g_network_monitor_get_connectivity(g_network_monitor_get_default()) }; - if (connection == G_NETWORK_CONNECTIVITY_LOCAL) + NLM_CONNECTIVITY connection{ NLM_CONNECTIVITY_DISCONNECTED }; + if (m_netListManager->GetConnectivity(&connection) == S_OK) + { + if (connection == NLM_CONNECTIVITY_DISCONNECTED) { newState = NetworkState::Disconnected; } - else if (connection == G_NETWORK_CONNECTIVITY_FULL) + else if (connection & NLM_CONNECTIVITY_IPV4_INTERNET || connection & NLM_CONNECTIVITY_IPV6_INTERNET) { newState = NetworkState::ConnectedGlobal; } @@ -116,8 +95,22 @@ namespace Nickvision::Network { newState = NetworkState::ConnectedLocal; } -#endif } +#else + GNetworkConnectivity connection{ g_network_monitor_get_connectivity(g_network_monitor_get_default()) }; + if (connection == G_NETWORK_CONNECTIVITY_LOCAL) + { + newState = NetworkState::Disconnected; + } + else if (connection == G_NETWORK_CONNECTIVITY_FULL) + { + newState = NetworkState::ConnectedGlobal; + } + else + { + newState = NetworkState::ConnectedLocal; + } +#endif if (m_connectionState != newState) { std::unique_lock lock{ m_mutex }; diff --git a/src/network/networkstatechangedeventargs.cpp b/src/network/networkstatechangedeventargs.cpp index 4091dc78..91aee3a7 100644 --- a/src/network/networkstatechangedeventargs.cpp +++ b/src/network/networkstatechangedeventargs.cpp @@ -2,13 +2,13 @@ namespace Nickvision::Network { - NetworkStateChangedEventArgs::NetworkStateChangedEventArgs(NetworkState state) + NetworkStateChangedEventArgs::NetworkStateChangedEventArgs(NetworkState state) noexcept : m_state{ state } { } - NetworkState NetworkStateChangedEventArgs::getState() const + NetworkState NetworkStateChangedEventArgs::getState() const noexcept { return m_state; } diff --git a/src/network/socket.cpp b/src/network/socket.cpp deleted file mode 100644 index d1ac1177..00000000 --- a/src/network/socket.cpp +++ /dev/null @@ -1,335 +0,0 @@ -#include "network/socket.h" -#include -#include -#include -#include -#ifdef _WIN32 -#include -#else -#include -#include -#include -#include -#endif -#include "helpers/stringhelpers.h" -#include "network/ipv4address.h" - -#ifndef _WIN32 -#ifdef __linux__ - #define MAX_UNIX_PATH_LENGTH 108 -#else - #define MAX_UNIX_PATH_LENGTH 104 -#endif -#endif -#define BACKLOG 5 - -using namespace Nickvision::Helpers; - -namespace Nickvision::Network -{ -#ifdef _WIN32 - static bool isSocketValid(SOCKET socket) - { - return socket != INVALID_SOCKET; - } - - static bool isSocketValid(HANDLE pipe) - { - return pipe != INVALID_HANDLE_VALUE; - } -#else - static bool isSocketValid(int socket) - { - return socket != -1; - } -#endif - - Socket::Socket(SocketPurpose purpose, SocketType type, AddressFamily family, const std::string& address, int port) - : m_purpose{ purpose }, - m_type{ type }, - m_family{ family }, - m_address{ address }, - m_port{ port } - { -#ifdef _WIN32 - //Check if winsock is initialized - static bool winsockInitialized{ false }; - if(!winsockInitialized) - { - WSADATA wsaData; - if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0) - { - throw std::runtime_error("Unable to initialize winsock"); - } - winsockInitialized = true; - } - //Create pipe - if(m_family == AddressFamily::Pipe) - { - if(m_purpose == SocketPurpose::Server) - { - std::wstring path{ L"\\\\.\\pipe\\" + StringHelpers::wstr(m_address) }; - WIN32_FIND_DATAW fd; - HANDLE find{ FindFirstFileW(path.c_str(), &fd) }; - if(find == INVALID_HANDLE_VALUE) - { - m_pipe = CreateNamedPipeW(path.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 0, 0, NMPWAIT_USE_DEFAULT_WAIT, nullptr); - if(m_pipe == INVALID_HANDLE_VALUE) - { - throw std::runtime_error("Unable to create pipe"); - } - FindClose(find); - } - else - { - throw std::logic_error("Unable to create pipe. Server already exists"); - } - } - return; - } -#endif - //Create the socket - m_socket = socket(static_cast(m_family), static_cast(m_type), 0); - if(!isSocketValid(m_socket)) - { - throw std::runtime_error("Unable to create socket"); - } - //Create the address struct - int bindResult{ 0 }; - switch(m_family) - { -#ifndef _WIN32 - case AddressFamily::Unix: - { - std::string domainPath{ "/tmp/" + m_address + ".socket" }; - domainPath.resize(MAX_UNIX_PATH_LENGTH); - struct sockaddr_un addr; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, domainPath.c_str()); - bindResult = bind(m_socket, reinterpret_cast(&addr), sizeof(addr)); - break; - } -#endif - case AddressFamily::IPv4: - { - std::optional ipv4{ IPv4Address::parse(m_address) }; - if(!ipv4) - { - throw std::invalid_argument("Invalid IPv4 Address"); - } - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = m_port; -#ifdef _WIN32 - addr.sin_addr.S_un.S_un_b.s_b1 = ipv4->getFirst(); - addr.sin_addr.S_un.S_un_b.s_b2 = ipv4->getSecond(); - addr.sin_addr.S_un.S_un_b.s_b3 = ipv4->getThird(); - addr.sin_addr.S_un.S_un_b.s_b4 = ipv4->getFourth(); -#else - addr.sin_addr.s_addr = ipv4->getNetworkByteOrder(); -#endif - bindResult = bind(m_socket, reinterpret_cast(&addr), sizeof(addr)); - break; - } - } - //Bind and listen if server socket - if(m_purpose == SocketPurpose::Server) - { - if(bindResult != 0) - { -#ifdef _WIN32 - closesocket(m_socket); -#else - close(m_socket); -#endif - throw std::logic_error("Unable to bind socket. Server already exists"); - } - if(listen(m_socket, BACKLOG) != 0) - { -#ifdef _WIN32 - closesocket(m_socket); -#else - close(m_socket); -#endif - throw std::runtime_error("Unable to listen on socket"); - } - } - } - - Socket::~Socket() - { - //Disconnect from child - disconnect(); - //Close the socket -#ifdef _WIN32 - if(isSocketValid(m_socket)) - { - shutdown(m_socket, SD_BOTH); - closesocket(m_socket); - } - if(isSocketValid(m_pipe)) - { - if(m_purpose == SocketPurpose::Server) - { - CancelSynchronousIo(m_pipe); - } - CloseHandle(m_pipe); - } -#else - shutdown(m_socket, SHUT_RDWR); - close(m_socket); - if(m_family == AddressFamily::Unix) - { - std::string domainPath{ "/tmp/" + m_address + ".socket" }; - domainPath.resize(MAX_UNIX_PATH_LENGTH); - unlink(domainPath.c_str()); - } -#endif - } - - bool Socket::connect() - { - if(m_purpose == SocketPurpose::Server) - { -#ifdef _WIN32 - if(m_family == AddressFamily::Pipe) - { - return ConnectNamedPipe(m_pipe, nullptr); - } -#endif - m_child = accept(m_socket, nullptr, nullptr); - return isSocketValid(m_child); - } - else if(m_purpose == SocketPurpose::Client) - { - switch(m_family) - { -#ifdef _WIN32 - case AddressFamily::Pipe: - { - std::wstring path{ L"\\\\.\\pipe\\" + StringHelpers::wstr(m_address) }; - m_pipe = CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - return isSocketValid(m_pipe); - } -#else - case AddressFamily::Unix: - { - std::string domainPath{ "/tmp/" + m_address + ".socket" }; - domainPath.resize(MAX_UNIX_PATH_LENGTH); - struct sockaddr_un address; - memset(&address, 0, sizeof(address)); - address.sun_family = AF_UNIX; - strcpy(address.sun_path, domainPath.c_str()); - return ::connect(m_socket, reinterpret_cast(&address), sizeof(address)) == 0; - } -#endif - case AddressFamily::IPv4: - { - std::optional ipv4{ IPv4Address::parse(m_address) }; - if(!ipv4) - { - throw std::invalid_argument("Invalid IPv4 Address"); - } - struct sockaddr_in address; - memset(&address, 0, sizeof(address)); - address.sin_family = AF_INET; - address.sin_port = m_port; -#ifdef _WIN32 - address.sin_addr.S_un.S_un_b.s_b1 = ipv4->getFirst(); - address.sin_addr.S_un.S_un_b.s_b2 = ipv4->getSecond(); - address.sin_addr.S_un.S_un_b.s_b3 = ipv4->getThird(); - address.sin_addr.S_un.S_un_b.s_b4 = ipv4->getFourth(); -#else - address.sin_addr.s_addr = ipv4->getNetworkByteOrder(); -#endif - return ::connect(m_socket, reinterpret_cast(&address), sizeof(address)) == 0; - } - } - } - return false; - } - - bool Socket::disconnect() - { -#ifdef _WIN32 - if(m_family == AddressFamily::Pipe && m_purpose == SocketPurpose::Server) - { - return DisconnectNamedPipe(m_pipe); - } -#endif - if(!isSocketValid(m_child)) - { - return false; - } -#ifdef _WIN32 - closesocket(m_child); - m_child = INVALID_SOCKET; -#else - close(m_child); - m_child = -1; -#endif - return true; - } - - std::string Socket::receiveMessage() const - { - std::vector buffer(1024); - std::string message; -#ifdef _WIN32 - if(m_family == AddressFamily::Pipe) - { - DWORD bytes; - do - { - if(!ReadFile(m_pipe, &buffer[0], DWORD(buffer.size()), &bytes, nullptr)) - { - break; - } - message += std::string(&buffer[0], static_cast(bytes)); - } while (bytes > 0); - return message; - } - SOCKET socket{ m_socket }; -#else - int socket{ m_socket }; -#endif - if(m_purpose == SocketPurpose::Server && isSocketValid(m_child)) - { - socket = m_child; - } -#ifdef _WIN32 - int bytes{ 0 }; -#else - ssize_t bytes{ 0 }; -#endif - do - { - bytes = recv(socket, &buffer[0], buffer.size(), 0); - if(bytes > 0) - { - message += std::string(&buffer[0], static_cast(bytes)); - } - } while(bytes > 0); - return message; - } - - bool Socket::sendMessage(const std::string& message) const - { -#ifdef _WIN32 - if(m_family == AddressFamily::Pipe) - { - return WriteFile(m_pipe, message.c_str(), DWORD(message.size()), nullptr, nullptr); - } - SOCKET socket{ m_socket }; -#else - int socket{ m_socket }; -#endif - if(m_purpose == SocketPurpose::Server && isSocketValid(m_child)) - { - socket = m_child; - } - return static_cast(send(socket, message.c_str(), message.size(), 0)) == message.size(); - } -} diff --git a/src/network/web.cpp b/src/network/web.cpp index a6ef204f..f5e0ca19 100644 --- a/src/network/web.cpp +++ b/src/network/web.cpp @@ -8,7 +8,7 @@ using namespace Nickvision::System; namespace Nickvision::Network { - static bool isResponseOk(const cpr::Response& response) + static bool isResponseOk(const cpr::Response& response) noexcept { if(response.status_code == 0) { @@ -17,7 +17,7 @@ namespace Nickvision::Network return response.status_code >= 100 && response.status_code < 400; } - bool Web::getWebsiteExists(const std::string& url) + bool Web::getWebsiteExists(const std::string& url) noexcept { if(url.empty()) { @@ -28,7 +28,7 @@ namespace Nickvision::Network return isResponseOk(session.Get()); } - boost::json::value Web::getJson(const std::string& url) + boost::json::value Web::getJson(const std::string& url) noexcept { if(url.empty()) { @@ -58,7 +58,7 @@ namespace Nickvision::Network return {}; } - bool Web::downloadFile(const std::string& url, const std::filesystem::path& path, const cpr::ProgressCallback& progress, bool overwrite) + bool Web::downloadFile(const std::string& url, const std::filesystem::path& path, const cpr::ProgressCallback& progress, bool overwrite) noexcept { if(url.empty()) { diff --git a/src/notifications/appnotification.cpp b/src/notifications/appnotification.cpp index c63ea6b7..7b07ad14 100644 --- a/src/notifications/appnotification.cpp +++ b/src/notifications/appnotification.cpp @@ -6,12 +6,12 @@ namespace Nickvision::Notifications { static Event s_sent; - Event& AppNotification::sent() + Event& AppNotification::sent() noexcept { return s_sent; } - void AppNotification::send(const NotificationSentEventArgs& args) + void AppNotification::send(const NotificationSentEventArgs& args) noexcept { s_sent.invoke(args); } diff --git a/src/notifications/notificationsenteventargs.cpp b/src/notifications/notificationsenteventargs.cpp index 894484dd..53cda4d9 100644 --- a/src/notifications/notificationsenteventargs.cpp +++ b/src/notifications/notificationsenteventargs.cpp @@ -2,7 +2,7 @@ namespace Nickvision::Notifications { - NotificationSentEventArgs::NotificationSentEventArgs(const std::string& message, NotificationSeverity severity, const std::string& action, const std::string& actionParam) + NotificationSentEventArgs::NotificationSentEventArgs(const std::string& message, NotificationSeverity severity, const std::string& action, const std::string& actionParam) noexcept : m_message{ message }, m_severity{ severity }, m_action{ action }, @@ -11,22 +11,22 @@ namespace Nickvision::Notifications } - const std::string& NotificationSentEventArgs::getMessage() const + const std::string& NotificationSentEventArgs::getMessage() const noexcept { return m_message; } - NotificationSeverity NotificationSentEventArgs::getSeverity() const + NotificationSeverity NotificationSentEventArgs::getSeverity() const noexcept { return m_severity; } - const std::string& NotificationSentEventArgs::getAction() const + const std::string& NotificationSentEventArgs::getAction() const noexcept { return m_action; } - const std::string& NotificationSentEventArgs::getActionParam() const + const std::string& NotificationSentEventArgs::getActionParam() const noexcept { return m_actionParam; } diff --git a/src/notifications/shellnotification.cpp b/src/notifications/shellnotification.cpp index 6a01de56..d0a97bb4 100644 --- a/src/notifications/shellnotification.cpp +++ b/src/notifications/shellnotification.cpp @@ -21,7 +21,7 @@ using namespace Nickvision::System; #ifdef _WIN32 static std::filesystem::path s_openPath; -static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept { if(msg == WM_TRAYICON) { @@ -51,7 +51,7 @@ static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara namespace Nickvision::Notifications { - void ShellNotification::send(const ShellNotificationSentEventArgs& e, const AppInfo& info, const std::string& openText) + void ShellNotification::send(const ShellNotificationSentEventArgs& e, const AppInfo& info, const std::string& openText) noexcept { #ifdef _WIN32 s_openPath = e.getAction() == "open" ? e.getActionParam() : ""; diff --git a/src/notifications/shellnotificationsenteventargs.cpp b/src/notifications/shellnotificationsenteventargs.cpp index 5ac5fa8c..b4437a34 100644 --- a/src/notifications/shellnotificationsenteventargs.cpp +++ b/src/notifications/shellnotificationsenteventargs.cpp @@ -2,14 +2,14 @@ namespace Nickvision::Notifications { - ShellNotificationSentEventArgs::ShellNotificationSentEventArgs(const std::string& title, const std::string& message, NotificationSeverity severity, const std::string& action, const std::string& actionParam) + ShellNotificationSentEventArgs::ShellNotificationSentEventArgs(const std::string& title, const std::string& message, NotificationSeverity severity, const std::string& action, const std::string& actionParam) noexcept : NotificationSentEventArgs{ message, severity, action, actionParam }, m_title{ title } { } - const std::string& ShellNotificationSentEventArgs::getTitle() const + const std::string& ShellNotificationSentEventArgs::getTitle() const noexcept { return m_title; } diff --git a/src/keyring/systemcredentials.cpp b/src/system/credentials.cpp similarity index 95% rename from src/keyring/systemcredentials.cpp rename to src/system/credentials.cpp index e09811b0..02357ddf 100644 --- a/src/keyring/systemcredentials.cpp +++ b/src/system/credentials.cpp @@ -1,4 +1,4 @@ -#include "keyring/systemcredentials.h" +#include "system/credentials.h" #include #include "helpers/stringhelpers.h" #include "keyring/passwordgenerator.h" @@ -13,14 +13,15 @@ #endif using namespace Nickvision::Helpers; +using namespace Nickvision::Keyring; -namespace Nickvision::Keyring +namespace Nickvision::System { #if !defined(_WIN32) && (!defined(__APPLE__) || defined(APPLE_USE_LIBSECRET)) static const SecretSchema KEYRING_SCHEMA = { "org.nickvision.libnick", SECRET_SCHEMA_NONE, { { "application", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "NULL", SECRET_SCHEMA_ATTRIBUTE_STRING } } }; #endif - std::optional SystemCredentials::getCredential(const std::string& name) + std::optional Credentials::get(const std::string& name) noexcept { #ifdef _WIN32 CREDENTIALW* cred{ nullptr }; @@ -90,18 +91,18 @@ namespace Nickvision::Keyring return std::nullopt; } - std::optional SystemCredentials::addCredential(const std::string& name) + std::optional Credentials::create(const std::string& name) noexcept { PasswordGenerator passGen; - Credential c{ name, "", "default", passGen.next() }; - if (addCredential(c)) + Credential c{ name, "", "default", passGen.next(64) }; + if (add(c)) { return c; } return std::nullopt; } - bool SystemCredentials::addCredential(const Credential& credential) + bool Credentials::add(const Credential& credential) noexcept { if(credential.getPassword().empty()) { @@ -156,7 +157,7 @@ namespace Nickvision::Keyring #endif } - bool SystemCredentials::updateCredential(const Credential& credential) + bool Credentials::update(const Credential& credential) noexcept { if(credential.getPassword().empty()) { @@ -237,7 +238,7 @@ namespace Nickvision::Keyring return false; } - bool SystemCredentials::deleteCredential(const std::string& name) + bool Credentials::remove(const std::string& name) noexcept { #ifdef _WIN32 std::wstring wName{ StringHelpers::wstr(name) }; diff --git a/src/system/environment.cpp b/src/system/environment.cpp index 7ab3ff8e..34ea761d 100644 --- a/src/system/environment.cpp +++ b/src/system/environment.cpp @@ -21,7 +21,7 @@ using namespace Nickvision::Helpers; namespace Nickvision::System { - DeploymentMode Environment::getDeploymentMode() + DeploymentMode Environment::getDeploymentMode() noexcept { if(hasVariable("container")) { @@ -34,34 +34,13 @@ namespace Nickvision::System return DeploymentMode::Local; } - const std::filesystem::path& Environment::getExecutableDirectory() + const std::filesystem::path& Environment::getExecutableDirectory() noexcept { - static std::filesystem::path executableDirectory; - if (!executableDirectory.empty()) - { - return executableDirectory; - } -#ifdef _WIN32 - wchar_t pth[MAX_PATH]; - DWORD len{ GetModuleFileNameW(nullptr, pth, sizeof(pth)) }; - if(len > 0) - { - executableDirectory = std::filesystem::path(std::wstring(pth, len)).parent_path(); - } -#elif defined(__linux__) - executableDirectory = std::filesystem::canonical("/proc/self/exe").parent_path(); -#elif defined(__APPLE__) - char path[PATH_MAX+1]; - uint32_t size{ sizeof(path) }; - if(_NSGetExecutablePath(path, &size) == 0) - { - executableDirectory = std::filesystem::canonical(path).parent_path(); - } -#endif + static std::filesystem::path executableDirectory{ getExecutablePath().parent_path() }; return executableDirectory; } - const std::filesystem::path& Environment::getExecutablePath() + const std::filesystem::path& Environment::getExecutablePath() noexcept { static std::filesystem::path executablePath; if (!executablePath.empty()) @@ -88,7 +67,7 @@ namespace Nickvision::System return executablePath; } - std::string Environment::getLocaleName() + std::string Environment::getLocaleName() noexcept { #ifdef _WIN32 LCID lcid{ GetThreadLocale() }; @@ -107,12 +86,12 @@ namespace Nickvision::System return ""; } - bool Environment::hasVariable(const std::string& key) + bool Environment::hasVariable(const std::string& key) noexcept { return std::getenv(key.c_str()); } - std::string Environment::getVariable(const std::string& key) + std::string Environment::getVariable(const std::string& key) noexcept { char* var{ std::getenv(key.c_str()) }; if (var) @@ -122,7 +101,7 @@ namespace Nickvision::System return ""; } - bool Environment::setVariable(const std::string& key, const std::string& value) + bool Environment::setVariable(const std::string& key, const std::string& value) noexcept { #ifdef _WIN32 return _putenv_s(key.c_str(), value.c_str()) == 0; @@ -131,12 +110,12 @@ namespace Nickvision::System #endif } - bool Environment::clearVariable(const std::string& key) + bool Environment::clearVariable(const std::string& key) noexcept { return setVariable(key, ""); } - bool Environment::testVariable(const std::string& key) + bool Environment::testVariable(const std::string& key) noexcept { std::string value{ getVariable(key) }; if(value.empty()) @@ -147,7 +126,7 @@ namespace Nickvision::System return value == "true" || value == "t" || value == "yes" || value == "y" || value == "1"; } - std::vector Environment::getPath() + std::vector Environment::getPath() noexcept { std::string env{ getVariable("PATH") }; if (!env.empty()) @@ -161,17 +140,16 @@ namespace Nickvision::System return {}; } - std::string Environment::exec(const std::string& command) + std::string Environment::exec(const std::string& command) noexcept { if(command.empty()) { return ""; } - std::vector args{ StringHelpers::splitArgs(command) }; #ifdef _WIN32 - args.insert(args.begin(), "/c"); - Process process{ findDependency("cmd.exe"), args }; + Process process{ findDependency("cmd.exe"), { "/c", command } }; #else + std::vector args{ StringHelpers::splitArgs(command) }; std::string cmd{ args[0] }; args.erase(args.begin()); Process process{ cmd, args }; @@ -184,7 +162,12 @@ namespace Nickvision::System return ""; } - const std::filesystem::path& Environment::findDependency(std::string dependency, DependencySearchOption search) + std::future Environment::execAsync(const std::string& command) noexcept + { + return std::async(std::launch::async, [command]() { return exec(command); }); + } + + const std::filesystem::path& Environment::findDependency(std::string dependency, DependencySearchOption search) noexcept { static std::unordered_map, std::filesystem::path, PairHash> dependencies; #ifdef _WIN32 @@ -258,7 +241,7 @@ namespace Nickvision::System return dependencies[pair]; } - std::string Environment::getDebugInformation(const AppInfo& appInfo, const std::string& extraInformation) + std::string Environment::getDebugInformation(const AppInfo& appInfo, const std::string& extraInformation) noexcept { std::stringstream builder; builder << appInfo.getId() << std::endl; @@ -277,7 +260,7 @@ namespace Nickvision::System builder << "Unknown OS" << std::endl; break; } - builder << appInfo.getVersion() << std::endl << std::endl; + builder << appInfo.getVersion().str() << std::endl << std::endl; builder << "Deployment Mode: "; switch(getDeploymentMode()) { diff --git a/src/system/hardwareinfo.cpp b/src/system/hardwareinfo.cpp index f38c1ad7..d0585d6a 100644 --- a/src/system/hardwareinfo.cpp +++ b/src/system/hardwareinfo.cpp @@ -16,12 +16,12 @@ using namespace Nickvision::Helpers; namespace Nickvision::System { - unsigned int HardwareInfo::getNumberOfProcessors() + unsigned int HardwareInfo::getNumberOfProcessors() noexcept { return std::thread::hardware_concurrency(); } - unsigned long long HardwareInfo::getTotalRamSize() + unsigned long long HardwareInfo::getTotalRamSize() noexcept { #ifdef _WIN32 MEMORYSTATUSEX status{}; @@ -50,7 +50,7 @@ namespace Nickvision::System return 0; } - unsigned long long HardwareInfo::getFreeRamSize() + unsigned long long HardwareInfo::getFreeRamSize() noexcept { #ifdef _WIN32 MEMORYSTATUSEX status{}; diff --git a/src/system/process.cpp b/src/system/process.cpp index 1232cb64..02e423b0 100644 --- a/src/system/process.cpp +++ b/src/system/process.cpp @@ -28,7 +28,7 @@ using namespace Nickvision::Helpers; namespace Nickvision::System { #ifdef _WIN32 - static std::vector getJobProcesses(HANDLE job) + static std::vector getJobProcesses(HANDLE job) noexcept { std::vector pids; size_t bufferSize{ sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + 255 * sizeof(ULONG_PTR) }; @@ -97,12 +97,12 @@ namespace Nickvision::System } SetInformationJobObject(m_job, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)); //Create process arguments - std::wstring appArgs{ L"\"" + m_path.wstring() + L"\"" }; + std::wstring appArgs{ StringHelpers::wstr(StringHelpers::quote(m_path.string())) }; for(const std::string& arg : m_args) { - if(arg.find(' ') != std::string::npos && arg[0] != '\"') + if(arg.find(' ') != std::string::npos) { - appArgs += L" \"" + StringHelpers::wstr(arg) + L"\""; + appArgs += L" " + StringHelpers::wstr(StringHelpers::quote(arg)); } else { @@ -141,7 +141,7 @@ namespace Nickvision::System #endif } - Process::~Process() + Process::~Process() noexcept { if(m_watchThread.joinable()) { @@ -161,37 +161,37 @@ namespace Nickvision::System #endif } - Event& Process::exited() + Event& Process::exited() noexcept { std::lock_guard lock{ m_mutex }; return m_exited; } - const std::filesystem::path& Process::getPath() const + const std::filesystem::path& Process::getPath() const noexcept { std::lock_guard lock{ m_mutex }; return m_path; } - ProcessState Process::getState() const + ProcessState Process::getState() const noexcept { std::lock_guard lock{ m_mutex }; return m_state; } - int Process::getExitCode() const + int Process::getExitCode() const noexcept { std::lock_guard lock{ m_mutex }; return m_exitCode; } - const std::string& Process::getOutput() const + const std::string& Process::getOutput() const noexcept { std::lock_guard lock{ m_mutex }; return m_output; } - double Process::getCPUUsage() const + double Process::getCPUUsage() const noexcept { if(m_state != ProcessState::Running) { @@ -275,7 +275,7 @@ namespace Nickvision::System return 0.0; } - unsigned long long Process::getRAMUsage() const + unsigned long long Process::getRAMUsage() const noexcept { if(m_state != ProcessState::Running) { @@ -351,7 +351,7 @@ namespace Nickvision::System return 0L; } - bool Process::start() + bool Process::start() noexcept { std::lock_guard lock{ m_mutex }; if(m_state == ProcessState::Running) @@ -382,6 +382,10 @@ namespace Nickvision::System } //Create process arguments std::string filename{ m_path.filename().string() }; + if(filename.find(' ') != std::string::npos) + { + filename = StringHelpers::quote(filename); + } std::vector appArgs; appArgs.push_back(filename.data()); for(std::string& arg : m_args) @@ -414,7 +418,7 @@ namespace Nickvision::System return true; } - bool Process::kill() + bool Process::kill() noexcept { std::lock_guard lock{ m_mutex }; if(m_state != ProcessState::Running && m_state != ProcessState::Paused) @@ -434,7 +438,7 @@ namespace Nickvision::System return true; } - bool Process::resume() + bool Process::resume() noexcept { std::lock_guard lock{ m_mutex }; if(m_state != ProcessState::Paused) @@ -479,7 +483,7 @@ namespace Nickvision::System return true; } - bool Process::pause() + bool Process::pause() noexcept { std::lock_guard lock{ m_mutex }; if(m_state != ProcessState::Running) @@ -524,7 +528,7 @@ namespace Nickvision::System return true; } - int Process::waitForExit() + int Process::waitForExit() noexcept { while(getState() != ProcessState::Completed) { @@ -533,7 +537,7 @@ namespace Nickvision::System return getExitCode(); } - bool Process::send(const std::string& s) + bool Process::send(const std::string& s) noexcept { if(m_state != ProcessState::Running) { @@ -546,7 +550,7 @@ namespace Nickvision::System #endif } - bool Process::sendCommand(std::string s) + bool Process::sendCommand(std::string s) noexcept { #ifndef _WIN32 s += "\n"; @@ -556,7 +560,7 @@ namespace Nickvision::System return send(s); } - void Process::watch() + void Process::watch() noexcept { #ifdef _WIN32 DWORD exitCode{ 0 }; diff --git a/src/system/suspendinhibitor.cpp b/src/system/suspendinhibitor.cpp index ed1b2799..c9437ec7 100644 --- a/src/system/suspendinhibitor.cpp +++ b/src/system/suspendinhibitor.cpp @@ -9,7 +9,7 @@ namespace Nickvision::System { - SuspendInhibitor::SuspendInhibitor() + SuspendInhibitor::SuspendInhibitor() noexcept : m_inhibiting{ false } #ifdef __linux__ , m_cookie{ 0 } @@ -18,25 +18,27 @@ namespace Nickvision::System } - SuspendInhibitor::SuspendInhibitor(const SuspendInhibitor& inhibitor) + SuspendInhibitor::SuspendInhibitor(const SuspendInhibitor& other) noexcept { - std::lock_guard lock{ inhibitor.m_mutex }; - m_inhibiting = inhibitor.m_inhibiting; + std::lock_guard lock{ other.m_mutex }; + m_inhibiting = other.m_inhibiting; #ifndef _WIN32 - m_cookie = inhibitor.m_cookie; + m_cookie = other.m_cookie; #endif } - SuspendInhibitor::SuspendInhibitor(SuspendInhibitor&& inhibitor) noexcept + SuspendInhibitor::SuspendInhibitor(SuspendInhibitor&& other) noexcept { - std::lock_guard lock{ inhibitor.m_mutex }; - m_inhibiting = std::move(inhibitor.m_inhibiting); + std::lock_guard lock{ other.m_mutex }; + m_inhibiting = std::move(other.m_inhibiting); #ifndef _WIN32 - m_cookie = std::move(inhibitor.m_cookie); + m_cookie = std::move(other.m_cookie); + other.m_cookie = 0; #endif + other.m_inhibiting = false; } - SuspendInhibitor::~SuspendInhibitor() + SuspendInhibitor::~SuspendInhibitor() noexcept { if(m_inhibiting) { @@ -44,13 +46,14 @@ namespace Nickvision::System } } - bool SuspendInhibitor::isInhibiting() const + bool SuspendInhibitor::isInhibiting() const noexcept { return m_inhibiting; } - bool SuspendInhibitor::inhibit() + bool SuspendInhibitor::inhibit() noexcept { + std::lock_guard lock{ m_mutex }; if(m_inhibiting) { return true; @@ -93,8 +96,9 @@ namespace Nickvision::System return true; } - bool SuspendInhibitor::uninhibit() + bool SuspendInhibitor::uninhibit() noexcept { + std::lock_guard lock{ m_mutex }; if(!m_inhibiting) { return true; @@ -132,30 +136,32 @@ namespace Nickvision::System return true; } - SuspendInhibitor& SuspendInhibitor::operator=(const SuspendInhibitor& inhibitor) + SuspendInhibitor& SuspendInhibitor::operator=(const SuspendInhibitor& other) noexcept { - if (this != &inhibitor) + if (this != &other) { std::lock_guard lock{ m_mutex }; - std::lock_guard lock2{ inhibitor.m_mutex }; - m_inhibiting = inhibitor.m_inhibiting; + std::lock_guard lock2{ other.m_mutex }; + m_inhibiting = other.m_inhibiting; #ifndef _WIN32 - m_cookie = inhibitor.m_cookie; + m_cookie = other.m_cookie; #endif } return *this; } - SuspendInhibitor& SuspendInhibitor::operator=(SuspendInhibitor&& inhibitor) noexcept + SuspendInhibitor& SuspendInhibitor::operator=(SuspendInhibitor&& other) noexcept { - if (this != &inhibitor) + if (this != &other) { std::lock_guard lock{ m_mutex }; - std::lock_guard lock2{ inhibitor.m_mutex }; - m_inhibiting = std::move(inhibitor.m_inhibiting); + std::lock_guard lock2{ other.m_mutex }; + m_inhibiting = std::move(other.m_inhibiting); #ifndef _WIN32 - m_cookie = std::move(inhibitor.m_cookie); + m_cookie = std::move(other.m_cookie); + other.m_cookie = 0; #endif + other.m_inhibiting = false; } return *this; } diff --git a/src/taskbar/taskbaritem.cpp b/src/taskbar/taskbaritem.cpp deleted file mode 100644 index 670b3759..00000000 --- a/src/taskbar/taskbaritem.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include "taskbar/taskbaritem.h" -#include -#include -#ifdef _WIN32 -#include -using namespace Gdiplus; -#endif - -namespace Nickvision::Taskbar -{ - TaskbarItem::TaskbarItem() - : m_progressState{ ProgressState::NoProgress }, - m_progress{ 0.0 }, - m_urgent{ false }, - m_countVisible{ false }, - m_count{ 0 } - { -#ifdef _WIN32 - GdiplusStartupInput gdiStartupIn; - GdiplusStartupOutput gdiStartupOut; - CoInitializeEx(nullptr, COINIT_MULTITHREADED); - GdiplusStartup(&m_gdi, &gdiStartupIn, &gdiStartupOut); - m_hwnd = nullptr; - m_taskbar = nullptr; -#elif defined(__linux__) - m_connection = nullptr; - m_objectPath = ""; - m_appUri = ""; -#endif - } - - TaskbarItem::~TaskbarItem() - { - setProgressState(ProgressState::NoProgress); - setUrgent(false); - setCountVisible(false); -#ifdef _WIN32 - GdiplusShutdown(m_gdi); -#endif - } - - ProgressState TaskbarItem::getProgressState() const - { - std::lock_guard lock{ m_mutex }; - return m_progressState; - } - - void TaskbarItem::setProgressState(ProgressState state) - { - std::lock_guard lock{ m_mutex }; - m_progressState = state; -#ifdef _WIN32 - if (m_taskbar) - { - m_taskbar->SetProgressState(m_hwnd, (TBPFLAG)m_progressState); - } -#elif defined(__linux__) - sendDBusUpdate(); -#endif - } - - double TaskbarItem::getProgress() const - { - std::lock_guard lock{ m_mutex }; - return m_progress; - } - - void TaskbarItem::setProgress(double progress) - { - setProgressState(progress > 0 ? ProgressState::Normal : ProgressState::NoProgress); - std::lock_guard lock{ m_mutex }; - m_progress = progress; -#ifdef _WIN32 - if (m_taskbar) - { - m_taskbar->SetProgressValue(m_hwnd, static_cast(m_progress * 100), 100u); - } -#elif defined(__linux__) - sendDBusUpdate(); -#endif - } - - bool TaskbarItem::getUrgent() const - { - std::lock_guard lock{ m_mutex }; - return m_urgent; - } - - void TaskbarItem::setUrgent(bool urgent) - { - std::lock_guard lock{ m_mutex }; - m_urgent = urgent; -#ifdef _WIN32 - if (m_taskbar) - { - FLASHWINFO flashInfo; - flashInfo.cbSize = sizeof(FLASHWINFO); - flashInfo.hwnd = m_hwnd; - flashInfo.dwFlags = m_urgent ? (FLASHW_TRAY | FLASHW_TIMER) : FLASHW_STOP; - flashInfo.uCount = (std::numeric_limits::max)(); - flashInfo.dwTimeout = 0; - FlashWindowEx(&flashInfo); - } -#elif defined(__linux__) - sendDBusUpdate(); -#endif - } - - bool TaskbarItem::getCountVisible() const - { - std::lock_guard lock{ m_mutex }; - return m_countVisible; - } - - void TaskbarItem::setCountVisible(bool countVisible) - { - std::lock_guard lock{ m_mutex }; - m_countVisible = countVisible; -#ifdef _WIN32 - if (m_taskbar) - { - if (!m_countVisible) - { - m_taskbar->SetOverlayIcon(m_hwnd, nullptr, L""); - } - else - { - drawCountIcon(); - } - } -#elif defined(__linux__) - sendDBusUpdate(); -#endif - } - - long TaskbarItem::getCount() const - { - std::lock_guard lock{ m_mutex }; - return m_count; - } - - void TaskbarItem::setCount(long count) - { - std::lock_guard lock{ m_mutex }; - m_count = count; -#ifdef _WIN32 - if(m_countVisible) - { - drawCountIcon(); - } -#elif defined(__linux__) - sendDBusUpdate(); -#endif - } - -#ifdef _WIN32 - bool TaskbarItem::connect(HWND hwnd) - { - if(m_hwnd) - { - return true; - } - std::lock_guard lock{ m_mutex }; - if (!hwnd) - { - return false; - } - if (CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_ALL, __uuidof(ITaskbarList3), (LPVOID*)&m_taskbar) == S_OK) - { - m_hwnd = hwnd; - return m_taskbar->HrInit() == S_OK; - } - return false; - } - - void TaskbarItem::drawCountIcon() - { - if (m_taskbar) - { - Graphics windowGraphics{ m_hwnd }; - SolidBrush background{ Color::Color(0, 0, 0) }; - SolidBrush foreground{ Color::Color(255, 255, 255) }; - DWORD accentARGB; - BOOL opaque{ FALSE }; - if(DwmGetColorizationColor(&accentARGB, &opaque) == S_OK) - { - Color accentColor{ accentARGB }; - background.SetColor({ 230, accentColor.GetR(), accentColor.GetG(), accentColor.GetB() }); - } - Bitmap bitmap{ 16, 16, &windowGraphics }; - Graphics graphics{ &bitmap }; - FontFamily fontFamily{ L"Segoe UI" }; - Font font{ &fontFamily, m_count <= 99 ? (m_count < 10 ? 8.0f : 7.5f) : 7.0f }; - std::wstring countStr{ m_count > 99 ? L"99+" : std::to_wstring(m_count) }; - SizeF stringSize; - graphics.MeasureString(countStr.c_str(), (int)countStr.length(), &font, SizeF(16, 16), StringFormat::GenericDefault(), &stringSize); - graphics.FillEllipse(&background, Rect(0, 0, 16, 16)); - graphics.DrawString(countStr.c_str(), (int)countStr.length(), &font, PointF((16 - stringSize.Width) / 2, (16 - stringSize.Height) / 2), &foreground); - HICON icon{ nullptr }; - bitmap.GetHICON(&icon); - m_taskbar->SetOverlayIcon(m_hwnd, icon, std::to_wstring(m_count).c_str()); - DestroyIcon(icon); - } - } -#elif defined(__linux__) - bool TaskbarItem::connect(const std::string& desktopFile) - { - if(m_connection) - { - return true; - } - std::lock_guard lock{ m_mutex }; - if (desktopFile.empty()) - { - return false; - } - m_connection = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr); //returns a singleton, no need to manage it - if (m_connection) - { - unsigned long hash{ 5381 }; - for(char c : desktopFile) - { - hash = (hash << 5) + hash + c; - } - m_objectPath = "/com/canonical/unity/launcherentry/" + std::to_string(hash); - m_appUri = "application://" + desktopFile; - return true; - } - return false; - } - - void TaskbarItem::sendDBusUpdate() - { - if(m_connection) - { - GVariantBuilder builder; - g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); - g_variant_builder_add(&builder, "{sv}", "progress-visible", g_variant_new_boolean(m_progressState >= ProgressState::Normal)); - g_variant_builder_add(&builder, "{sv}", "progress", g_variant_new_double(m_progress)); - g_variant_builder_add(&builder, "{sv}", "urgent", g_variant_new_boolean(m_urgent)); - g_variant_builder_add(&builder, "{sv}", "count-visible", g_variant_new_boolean(m_countVisible)); - g_variant_builder_add(&builder, "{sv}", "count", g_variant_new_int64(m_count)); - GVariant* params[2]{ g_variant_new_string(m_appUri.c_str()), g_variant_builder_end(&builder) }; - GVariant* tuple{ g_variant_new_tuple(params, 2) }; - g_dbus_connection_emit_signal(m_connection, nullptr, m_objectPath.c_str(), "com.canonical.Unity.LauncherEntry", "Update", tuple, nullptr); - } - } -#endif -} \ No newline at end of file diff --git a/src/update/updater.cpp b/src/update/updater.cpp index 7f4481be..dd659ae8 100644 --- a/src/update/updater.cpp +++ b/src/update/updater.cpp @@ -37,7 +37,7 @@ namespace Nickvision::Update } } - Updater::Updater(const Updater& u) + Updater::Updater(const Updater& u) noexcept { std::lock_guard lock{ u.m_mutex }; m_repoOwner = u.m_repoOwner; @@ -55,7 +55,7 @@ namespace Nickvision::Update m_latestPreviewReleaseId = std::move(u.m_latestPreviewReleaseId); } - Version Updater::fetchCurrentVersion(VersionType versionType) + Version Updater::fetchCurrentVersion(VersionType versionType) noexcept { std::lock_guard lock{ m_mutex }; boost::json::value root = Web::getJson("https://api.github.com/repos/" + m_repoOwner + "/" + m_repoName + "/releases"); @@ -106,7 +106,7 @@ namespace Nickvision::Update return Version(); } - bool Updater::downloadUpdate(VersionType versionType, const std::filesystem::path& path, const std::string& assetName, bool exactMatch, const cpr::ProgressCallback& progress) + bool Updater::downloadUpdate(VersionType versionType, const std::filesystem::path& path, const std::string& assetName, bool exactMatch, const cpr::ProgressCallback& progress) noexcept { std::lock_guard lock{ m_mutex }; if (versionType == VersionType::Stable ? m_latestStableReleaseId == -1 : m_latestPreviewReleaseId == -1) @@ -151,7 +151,7 @@ namespace Nickvision::Update } #ifdef _WIN32 - bool Updater::windowsUpdate(VersionType versionType, const cpr::ProgressCallback& progress) + bool Updater::windowsUpdate(VersionType versionType, const cpr::ProgressCallback& progress) noexcept { std::filesystem::path setupPath{ UserDirectories::get(UserDirectory::Cache) / (m_repoOwner + "_" + m_repoName + "_Setup.exe") }; if(downloadUpdate(versionType, setupPath, "setup.exe", false, progress)) @@ -166,7 +166,7 @@ namespace Nickvision::Update } #endif - Updater& Updater::operator=(const Updater& u) + Updater& Updater::operator=(const Updater& u) noexcept { if (this != &u) { diff --git a/src/update/version.cpp b/src/update/version.cpp index 605d57da..c7c77183 100644 --- a/src/update/version.cpp +++ b/src/update/version.cpp @@ -4,7 +4,7 @@ namespace Nickvision::Update { - Version::Version() + Version::Version() noexcept : m_major{ 0 }, m_minor{ 0 }, m_build{ 0 }, @@ -13,7 +13,7 @@ namespace Nickvision::Update } - Version::Version(int major, int minor, int build) + Version::Version(int major, int minor, int build) noexcept : m_major{ major }, m_minor{ minor }, m_build{ build }, @@ -31,7 +31,7 @@ namespace Nickvision::Update { if (m_dev[0] != '-' && m_dev[0] != '.') { - throw std::invalid_argument("Dev version must contain a '-'."); + throw std::invalid_argument("Dev version must contain a '-' or '.' as the first character."); } } @@ -66,51 +66,54 @@ namespace Nickvision::Update throw std::invalid_argument("Ill-formated version string."); } size_t dashIndex{ s.find('-') }; - m_build = std::stoi(s.substr(0, dashIndex)); + if(dashIndex == std::string::npos) + { + dashIndex = s.find('.'); + } s.erase(0, dashIndex); - if (!s.empty() && s[0] == '-') //dev version + if (!s.empty() && (s[0] == '-' || s[0] == '.')) //dev version { m_dev = s; } m_str = std::to_string(m_major) + "." + std::to_string(m_minor) + "." + std::to_string(m_build) + m_dev; } - int Version::getMajor() const + int Version::getMajor() const noexcept { return m_major; } - int Version::getMinor() const + int Version::getMinor() const noexcept { return m_minor; } - int Version::getBuild() const + int Version::getBuild() const noexcept { return m_build; } - const std::string& Version::getDev() const + const std::string& Version::getDev() const noexcept { return m_dev; } - VersionType Version::getVersionType() const + VersionType Version::getVersionType() const noexcept { return m_dev.empty() ? VersionType::Stable : VersionType::Preview; } - const std::string& Version::str() const + const std::string& Version::str() const noexcept { return m_str; } - bool Version::empty() const + bool Version::empty() const noexcept { return m_major == 0 && m_minor == 0 && m_build == 0 && m_dev.empty(); } - bool Version::operator<(const Version& compare) const + bool Version::operator<(const Version& compare) const noexcept { if(m_major > compare.m_major) { @@ -156,12 +159,12 @@ namespace Nickvision::Update return false; } - bool Version::operator<=(const Version& compare) const + bool Version::operator<=(const Version& compare) const noexcept { return operator<(compare) || operator==(compare); } - bool Version::operator>(const Version& compare) const + bool Version::operator>(const Version& compare) const noexcept { if(m_major > compare.m_major) { @@ -207,24 +210,18 @@ namespace Nickvision::Update return false; } - bool Version::operator>=(const Version& compare) const + bool Version::operator>=(const Version& compare) const noexcept { return operator>(compare) || operator==(compare); } - bool Version::operator==(const Version& compare) const + bool Version::operator==(const Version& compare) const noexcept { return m_major == compare.m_major && m_minor == compare.m_minor && m_build == compare.m_build && m_dev == compare.m_dev; } - bool Version::operator!=(const Version& compare) const + bool Version::operator!=(const Version& compare) const noexcept { return !(operator==(compare)); } - - std::ostream& operator<<(std::ostream& os, const Version& version) - { - os << version.str(); - return os; - } } \ No newline at end of file diff --git a/tests/databasetests.cpp b/tests/databasetests.cpp index 5630a492..c1416766 100644 --- a/tests/databasetests.cpp +++ b/tests/databasetests.cpp @@ -1,26 +1,26 @@ #include #include #include -#include "database/sqldatabase.h" +#include "database/sqlitedatabase.h" using namespace Nickvision::Database; class Person { public: - Person(const std::string& name, int age) + Person(const std::string& name, int age) noexcept : m_name{ name }, m_age{ age } { } - const std::string& getName() const + const std::string& getName() const noexcept { return m_name; } - int getAge() const + int getAge() const noexcept { return m_age; } @@ -33,96 +33,91 @@ class Person class DatabaseTest : public testing::Test { public: - static std::filesystem::path m_encryptedPath; - static std::string m_encryptedPassword; - static std::unique_ptr m_encrypted; - - static void SetUpTestSuite() - { - m_encrypted = std::make_unique(m_encryptedPath, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); - } + static std::filesystem::path m_path; + static std::unique_ptr m_database; static void TearDownTestSuite() { - m_encrypted.reset(); - std::filesystem::remove(m_encryptedPath); + m_database.reset(); + std::filesystem::remove(m_path); } - static Person getPerson1() + static const Person& getPerson1() { - return { "Bob Hope", 67 }; + static Person one{ "Bob Hope", 67 }; + return one; } - static Person getPerson2() + static const Person& getPerson2() { - return { "Chris Pratt", 32 }; + static Person two{ "Chris Pratt", 32 }; + return two; } }; -std::filesystem::path DatabaseTest::m_encryptedPath = "enc.sqlite3"; -std::string DatabaseTest::m_encryptedPassword = "abc3845@#$"; -std::unique_ptr DatabaseTest::m_encrypted = nullptr; +std::filesystem::path DatabaseTest::m_path = "enc.sqlite3"; +std::unique_ptr DatabaseTest::m_database = nullptr; -TEST_F(DatabaseTest, EncryptDatabase) +TEST_F(DatabaseTest, OpenDatabase) { - ASSERT_FALSE(m_encrypted->isEncrypted()); - ASSERT_TRUE(m_encrypted->unlock("")); - ASSERT_TRUE(m_encrypted->changePassword(m_encryptedPassword)); - ASSERT_TRUE(m_encrypted->isEncrypted()); + ASSERT_NO_THROW(m_database = std::make_unique(m_path)); + ASSERT_TRUE(m_database->isUnlocked()); + ASSERT_FALSE(m_database->isEncrypted()); } TEST_F(DatabaseTest, AddTable) { - ASSERT_TRUE(m_encrypted->exec("CREATE TABLE people (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")); + ASSERT_TRUE(m_database->execute("CREATE TABLE people (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")); +} + +TEST_F(DatabaseTest, EncryptDatabase) +{ + ASSERT_TRUE(m_database->setPassword("abc3845@#$")); + ASSERT_TRUE(m_database->isEncrypted()); + ASSERT_TRUE(m_database->isUnlocked()); } TEST_F(DatabaseTest, AddPerson1) { - Person p1{ getPerson1() }; - SqlStatement statement{ m_encrypted->createStatement("INSERT INTO people (id, name, age) VALUES (?,?,?)") }; + SqliteStatement statement{ m_database->createStatement("INSERT INTO people (id, name, age) VALUES (?,?,?)") }; statement.bind(1, 1); - statement.bind(2, p1.getName()); - statement.bind(3, p1.getAge()); - ASSERT_FALSE(statement.step()); + statement.bind(2, getPerson1().getName()); + statement.bind(3, getPerson1().getAge()); + ASSERT_EQ(statement.step(), SqliteStepResult::Done); } TEST_F(DatabaseTest, AddPerson2) { - Person p2{ getPerson2() }; - SqlStatement statement{ m_encrypted->createStatement("INSERT INTO people (id, name, age) VALUES (?,?,?)") }; + SqliteStatement statement{ m_database->createStatement("INSERT INTO people (id, name, age) VALUES (?,?,?)") }; statement.bind(1, 2); - statement.bind(2, p2.getName()); - statement.bind(3, p2.getAge()); - ASSERT_FALSE(statement.step()); + statement.bind(2, getPerson2().getName()); + statement.bind(3, getPerson2().getAge()); + ASSERT_EQ(statement.step(), SqliteStepResult::Done); } TEST_F(DatabaseTest, GetPerson1) { - Person p1{ getPerson1() }; - SqlStatement statement{ m_encrypted->createStatement("SELECT * FROM people WHERE id = 1") }; - ASSERT_TRUE(statement.step()); - ASSERT_EQ(statement.getColumnInt(0), 1); - ASSERT_EQ(statement.getColumnString(1), p1.getName()); - ASSERT_EQ(statement.getColumnInt(2), p1.getAge()); - ASSERT_FALSE(statement.step()); + SqliteStatement statement{ m_database->createStatement("SELECT * FROM people WHERE id = 1") }; + ASSERT_EQ(statement.step(), SqliteStepResult::Row); + ASSERT_EQ(statement.getColumn(0), 1); + ASSERT_EQ(statement.getColumn(1), getPerson1().getName()); + ASSERT_EQ(statement.getColumn(2), getPerson1().getAge()); + ASSERT_EQ(statement.step(), SqliteStepResult::Done); } -TEST_F(DatabaseTest, GetPerson2) +TEST_F(DatabaseTest, DecryptDatabase) { - Person p2{ getPerson2() }; - SqlStatement statement{ m_encrypted->createStatement("SELECT * FROM people WHERE id = 2") }; - ASSERT_TRUE(statement.step()); - ASSERT_EQ(statement.getColumnInt(0), 2); - ASSERT_EQ(statement.getColumnString(1), p2.getName()); - ASSERT_EQ(statement.getColumnInt(2), p2.getAge()); - ASSERT_FALSE(statement.step()); + ASSERT_TRUE(m_database->setPassword("")); + ASSERT_FALSE(m_database->isEncrypted()); + ASSERT_TRUE(m_database->isUnlocked()); } -TEST_F(DatabaseTest, DecryptDatabase) +TEST_F(DatabaseTest, GetPerson2) { - ASSERT_TRUE(m_encrypted->changePassword("")); - ASSERT_FALSE(m_encrypted->isEncrypted()); - SqlStatement statement{ m_encrypted->createStatement("SELECT COUNT(id) FROM people") }; - ASSERT_TRUE(statement.step()); - ASSERT_EQ(statement.getColumnInt(0), 2); + SqliteStatement statement{ m_database->createStatement("SELECT * FROM people WHERE id = 2") }; + ASSERT_EQ(statement.step(), SqliteStepResult::Row); + ASSERT_EQ(statement.getColumn(0), 2); + ASSERT_EQ(statement.getColumn(1), getPerson2().getName()); + ASSERT_EQ(statement.getColumn(2), getPerson2().getAge()); + ASSERT_EQ(statement.step(), SqliteStepResult::Done); } \ No newline at end of file diff --git a/tests/datafiletests.cpp b/tests/datafiletests.cpp deleted file mode 100644 index f73d98e4..00000000 --- a/tests/datafiletests.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include -#include -#include "app/datafilebase.h" -#include "app/datafilemanager.h" -#include "app/windowgeometry.h" -#include "filesystem/userdirectories.h" - -using namespace Nickvision::App; -using namespace Nickvision::Filesystem; - -enum class Theme -{ - Light = 0, - Dark, - System -}; - -class AppConfig : public DataFileBase -{ -public: - AppConfig(const std::string& key, const std::string& appName, bool isPortable) - : DataFileBase{ key, appName, isPortable } - { - - } - - Theme getTheme() const - { - const boost::json::value& theme{ m_json["Theme"] }; - if(!theme.is_int64()) - { - return Theme::System; - } - return static_cast(theme.as_int64()); - } - - void setTheme(Theme theme) - { - m_json["Theme"] = static_cast(theme); - } - - WindowGeometry getWindowGeometry() const - { - WindowGeometry geometry; - if(!m_json["WindowGeometry"].is_object()) - { - geometry.setWidth(800); - geometry.setHeight(600); - geometry.setIsMaximized(false); - return geometry; - } - boost::json::object& obj{ m_json["WindowGeometry"].as_object() }; - geometry.setWidth(obj["Width"].is_int64() ? obj["Width"].as_int64() : 800); - geometry.setHeight(obj["Height"].is_int64() ? obj["Height"].as_int64() : 600); - geometry.setIsMaximized(obj["IsMaximized"].is_bool() ? obj["IsMaximized"].as_bool() : false); - return geometry; - } - - void setWindowGeometry(const WindowGeometry& geometry) - { - boost::json::object obj; - obj["Width"] = geometry.getWidth(); - obj["Height"] = geometry.getHeight(); - obj["IsMaximized"] = geometry.isMaximized(); - m_json["WindowGeometry"] = obj; - } - - bool getAutomaticallyCheckForUpdates() const - { - const boost::json::value& value{ m_json["AutomaticallyCheckForUpdates"] }; - if(!value.is_bool()) - { - return true; - } - return value.as_bool(); - } - - void setAutomaticallyCheckForUpdates(bool value) - { - m_json["AutomaticallyCheckForUpdates"] = value; - } -}; - -class DataFileTest : public testing::Test -{ -public: - static std::shared_ptr m_manager; - static std::shared_ptr m_portableManager; - - static void SetUpTestSuite() - { - std::filesystem::remove(UserDirectories::get(ApplicationUserDirectory::Config, "Nickvision Aura Tests") / ("config.json")); - std::filesystem::remove("config.json"); - m_manager = std::make_shared("Nickvision Aura Tests", false); - m_portableManager = std::make_shared("Nickvision Aura Tests", true); - } - - static void TearDownTestSuite() - { - m_manager.reset(); - m_portableManager.reset(); - std::filesystem::remove_all(UserDirectories::get(ApplicationUserDirectory::Config, "Nickvision Aura Tests")); - std::filesystem::remove("config.json"); - } -}; - -std::shared_ptr DataFileTest::m_manager{ nullptr }; -std::shared_ptr DataFileTest::m_portableManager{ nullptr }; - -TEST_F(DataFileTest, EnsureDefaultAppConfig) -{ - AppConfig& config{ m_manager->get("config") }; - WindowGeometry geometry{ config.getWindowGeometry() }; - ASSERT_EQ(config.getTheme(), Theme::System); - ASSERT_EQ(geometry.getWidth(), 800); - ASSERT_EQ(geometry.getHeight(), 600); - ASSERT_EQ(geometry.isMaximized(), false); - ASSERT_EQ(config.getAutomaticallyCheckForUpdates(), true); -} - -TEST_F(DataFileTest, EnsureDefaultPortableAppConfig) -{ - AppConfig& config{ m_portableManager->get("config") }; - WindowGeometry geometry{ config.getWindowGeometry() }; - ASSERT_EQ(config.getTheme(), Theme::System); - ASSERT_EQ(geometry.getWidth(), 800); - ASSERT_EQ(geometry.getHeight(), 600); - ASSERT_EQ(geometry.isMaximized(), false); - ASSERT_EQ(config.getAutomaticallyCheckForUpdates(), true); -} - -TEST_F(DataFileTest, ChangeAppConfig1) -{ - AppConfig& config{ m_manager->get("config") }; - ASSERT_NO_THROW(config.setTheme(Theme::Light)); - ASSERT_NO_THROW(config.setWindowGeometry(WindowGeometry{ 1920, 1080, true })); - ASSERT_TRUE(config.save()); -} - -TEST_F(DataFileTest, ChangePortableAppConfig1) -{ - AppConfig& config{ m_portableManager->get("config") }; - ASSERT_NO_THROW(config.setTheme(Theme::Light)); - ASSERT_NO_THROW(config.setWindowGeometry(WindowGeometry{ 1920, 1080, true })); - ASSERT_TRUE(config.save()); -} - -TEST_F(DataFileTest, EnsureChangeInAppConfig) -{ - AppConfig& config{ m_manager->get("config") }; - ASSERT_EQ(config.getTheme(), Theme::Light); - WindowGeometry geometry{ config.getWindowGeometry() }; - ASSERT_EQ(geometry.getWidth(), 1920); - ASSERT_EQ(geometry.getHeight(), 1080); - ASSERT_EQ(geometry.isMaximized(), true); -} - -TEST_F(DataFileTest, EnsureChangeInPortableAppConfig) -{ - AppConfig& config{ m_portableManager->get("config") }; - ASSERT_EQ(config.getTheme(), Theme::Light); - WindowGeometry geometry{ config.getWindowGeometry() }; - ASSERT_EQ(geometry.getWidth(), 1920); - ASSERT_EQ(geometry.getHeight(), 1080); - ASSERT_EQ(geometry.isMaximized(), true); -} - -TEST_F(DataFileTest, ChangeAppConfig2) -{ - AppConfig& config{ m_manager->get("config") }; - ASSERT_NO_THROW(config.setAutomaticallyCheckForUpdates(false)); - ASSERT_TRUE(config.save()); -} - -TEST_F(DataFileTest, ChangePortableAppConfig2) -{ - AppConfig& config{ m_portableManager->get("config") }; - ASSERT_NO_THROW(config.setAutomaticallyCheckForUpdates(false)); - ASSERT_TRUE(config.save()); -} - -TEST_F(DataFileTest, EnsureChangeInAppConfig2) -{ - AppConfig& config{ m_manager->get("config") }; - ASSERT_EQ(config.getAutomaticallyCheckForUpdates(), false); -} - -TEST_F(DataFileTest, EnsureChangeInPortableAppConfig2) -{ - AppConfig& config{ m_portableManager->get("config") }; - ASSERT_EQ(config.getAutomaticallyCheckForUpdates(), false); -} - -TEST_F(DataFileTest, ReloadAndCheckConfig) -{ - m_manager.reset(); - m_manager = std::make_shared("Nickvision Aura Tests", false); - AppConfig& config{ m_manager->get("config") }; - ASSERT_EQ(config.getTheme(), Theme::Light); - WindowGeometry geometry{ config.getWindowGeometry() }; - ASSERT_EQ(geometry.getWidth(), 1920); - ASSERT_EQ(geometry.getHeight(), 1080); - ASSERT_EQ(geometry.isMaximized(), true); - ASSERT_EQ(config.getAutomaticallyCheckForUpdates(), false); -} - -TEST_F(DataFileTest, ReloadAndCheckPortableConfig) -{ - m_portableManager.reset(); - m_portableManager = std::make_shared("Nickvision Aura Tests", true); - AppConfig& config{ m_portableManager->get("config") }; - ASSERT_EQ(config.getTheme(), Theme::Light); - WindowGeometry geometry{ config.getWindowGeometry() }; - ASSERT_EQ(geometry.getWidth(), 1920); - ASSERT_EQ(geometry.getHeight(), 1080); - ASSERT_EQ(geometry.isMaximized(), true); - ASSERT_EQ(config.getAutomaticallyCheckForUpdates(), false); -} diff --git a/tests/dnstests.cpp b/tests/dnstests.cpp deleted file mode 100644 index d456d13f..00000000 --- a/tests/dnstests.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include "network/dns.h" - -using namespace Nickvision::Network; - -TEST(DnsTests, A1) -{ - ASSERT_FALSE(DNS::a("www.google.com").empty()); -} - -TEST(DnsTests, TXT1) -{ - ASSERT_FALSE(DNS::txt("example.com").empty()); -} diff --git a/tests/jsonfiletests.cpp b/tests/jsonfiletests.cpp new file mode 100644 index 00000000..4c45fdc1 --- /dev/null +++ b/tests/jsonfiletests.cpp @@ -0,0 +1,201 @@ +#include +#include +#include +#include "app/windowgeometry.h" +#include "filesystem/userdirectories.h" +#include "helpers/jsonfilebase.h" + +using namespace Nickvision::App; +using namespace Nickvision::Filesystem; +using namespace Nickvision::Helpers; + +enum class Theme +{ + Light = 0, + Dark, + System +}; + +class AppConfig : public JsonFileBase +{ +public: + AppConfig(const std::filesystem::path& path) + : JsonFileBase{ path } + { + + } + + Theme getTheme() const + { + return static_cast(get("Theme", static_cast(Theme::System))); + } + + void setTheme(Theme theme) + { + set("Theme", static_cast(theme)); + } + + WindowGeometry getWindowGeometry() const + { + WindowGeometry geometry; + boost::json::object obj = get("WindowGeometry", {}); + if(obj.empty()) + { + geometry.setWidth(800); + geometry.setHeight(600); + geometry.setIsMaximized(false); + return geometry; + } + geometry.setWidth(obj["Width"].is_int64() ? obj["Width"].as_int64() : 800); + geometry.setHeight(obj["Height"].is_int64() ? obj["Height"].as_int64() : 600); + geometry.setIsMaximized(obj["IsMaximized"].is_bool() ? obj["IsMaximized"].as_bool() : false); + return geometry; + } + + void setWindowGeometry(const WindowGeometry& geometry) + { + boost::json::object obj; + obj["Width"] = geometry.getWidth(); + obj["Height"] = geometry.getHeight(); + obj["IsMaximized"] = geometry.isMaximized(); + set("WindowGeometry", obj); + } + + bool getAutomaticallyCheckForUpdates() const + { + return get("AutomaticallyCheckForUpdates", true); + } + + void setAutomaticallyCheckForUpdates(bool value) + { + set("AutomaticallyCheckForUpdates", value); + } +}; + +class JsonFileTest : public testing::Test +{ +public: + static std::filesystem::path m_path; + static std::filesystem::path m_portablePath; + static std::shared_ptr m_config; + static std::shared_ptr m_portableConfig; + + static void SetUpTestSuite() + { + std::filesystem::remove(m_path); + std::filesystem::remove(m_portablePath); + m_config = std::make_shared(m_path); + m_portableConfig = std::make_shared(m_portablePath); + } + + static void TearDownTestSuite() + { + m_config.reset(); + m_portableConfig.reset(); + std::filesystem::remove_all(m_path.parent_path()); + std::filesystem::remove("config.json"); + } +}; + +std::filesystem::path JsonFileTest::m_path{ UserDirectories::get(ApplicationUserDirectory::Config, "Nickvision Aura Tests") / "config.json" }; +std::filesystem::path JsonFileTest::m_portablePath{ "config.json" }; +std::shared_ptr JsonFileTest::m_config{ nullptr }; +std::shared_ptr JsonFileTest::m_portableConfig{ nullptr }; + +TEST_F(JsonFileTest, EnsureDefaultAppConfig) +{ + WindowGeometry geometry{ m_config->getWindowGeometry() }; + ASSERT_EQ(m_config->getTheme(), Theme::System); + ASSERT_EQ(geometry.getWidth(), 800); + ASSERT_EQ(geometry.getHeight(), 600); + ASSERT_EQ(geometry.isMaximized(), false); + ASSERT_EQ(m_config->getAutomaticallyCheckForUpdates(), true); +} + +TEST_F(JsonFileTest, EnsureDefaultPortableAppConfig) +{ + WindowGeometry geometry{ m_portableConfig->getWindowGeometry() }; + ASSERT_EQ(m_portableConfig->getTheme(), Theme::System); + ASSERT_EQ(geometry.getWidth(), 800); + ASSERT_EQ(geometry.getHeight(), 600); + ASSERT_EQ(geometry.isMaximized(), false); + ASSERT_EQ(m_portableConfig->getAutomaticallyCheckForUpdates(), true); +} + +TEST_F(JsonFileTest, ChangeAppConfig1) +{ + ASSERT_NO_THROW(m_config->setTheme(Theme::Light)); + ASSERT_NO_THROW(m_config->setWindowGeometry(WindowGeometry{ 1920, 1080, true })); + ASSERT_TRUE(m_config->save()); +} + +TEST_F(JsonFileTest, ChangePortableAppConfig1) +{ + ASSERT_NO_THROW(m_portableConfig->setTheme(Theme::Light)); + ASSERT_NO_THROW(m_portableConfig->setWindowGeometry(WindowGeometry{ 1920, 1080, true })); + ASSERT_TRUE(m_portableConfig->save()); +} + +TEST_F(JsonFileTest, EnsureChangeInAppConfig) +{ + ASSERT_EQ(m_config->getTheme(), Theme::Light); + WindowGeometry geometry{ m_config->getWindowGeometry() }; + ASSERT_EQ(geometry.getWidth(), 1920); + ASSERT_EQ(geometry.getHeight(), 1080); + ASSERT_EQ(geometry.isMaximized(), true); +} + +TEST_F(JsonFileTest, EnsureChangeInPortableAppConfig) +{ + ASSERT_EQ(m_portableConfig->getTheme(), Theme::Light); + WindowGeometry geometry{ m_portableConfig->getWindowGeometry() }; + ASSERT_EQ(geometry.getWidth(), 1920); + ASSERT_EQ(geometry.getHeight(), 1080); + ASSERT_EQ(geometry.isMaximized(), true); +} + +TEST_F(JsonFileTest, ChangeAppConfig2) +{ + ASSERT_NO_THROW(m_config->setAutomaticallyCheckForUpdates(false)); + ASSERT_TRUE(m_config->save()); +} + +TEST_F(JsonFileTest, ChangePortableAppConfig2) +{ + ASSERT_NO_THROW(m_portableConfig->setAutomaticallyCheckForUpdates(false)); + ASSERT_TRUE(m_portableConfig->save()); +} + +TEST_F(JsonFileTest, EnsureChangeInAppConfig2) +{ + ASSERT_EQ(m_config->getAutomaticallyCheckForUpdates(), false); +} + +TEST_F(JsonFileTest, EnsureChangeInPortableAppConfig2) +{ + ASSERT_EQ(m_portableConfig->getAutomaticallyCheckForUpdates(), false); +} + +TEST_F(JsonFileTest, ReloadAndCheckConfig) +{ + m_config.reset(); + m_config = std::make_shared(m_path); + ASSERT_EQ(m_config->getTheme(), Theme::Light); + WindowGeometry geometry{ m_config->getWindowGeometry() }; + ASSERT_EQ(geometry.getWidth(), 1920); + ASSERT_EQ(geometry.getHeight(), 1080); + ASSERT_EQ(geometry.isMaximized(), true); + ASSERT_EQ(m_config->getAutomaticallyCheckForUpdates(), false); +} + +TEST_F(JsonFileTest, ReloadAndCheckPortableConfig) +{ + m_portableConfig.reset(); + m_portableConfig = std::make_shared(m_portablePath); + ASSERT_EQ(m_portableConfig->getTheme(), Theme::Light); + WindowGeometry geometry{ m_portableConfig->getWindowGeometry() }; + ASSERT_EQ(geometry.getWidth(), 1920); + ASSERT_EQ(geometry.getHeight(), 1080); + ASSERT_EQ(geometry.isMaximized(), true); + ASSERT_EQ(m_portableConfig->getAutomaticallyCheckForUpdates(), false); +} \ No newline at end of file diff --git a/tests/keyringtests.cpp b/tests/keyringtests.cpp index 2a1510a8..35de32af 100644 --- a/tests/keyringtests.cpp +++ b/tests/keyringtests.cpp @@ -4,8 +4,6 @@ #include "keyring/keyring.h" #include "system/environment.h" -#define KEYRING_NAME std::string("org.nickvision.libnick.test") - using namespace Nickvision::Filesystem; using namespace Nickvision::Keyring; using namespace Nickvision::System; @@ -13,6 +11,7 @@ using namespace Nickvision::System; class KeyringTest : public testing::Test { public: + static std::string m_keyringName; static std::unique_ptr m_keyring; static std::filesystem::path m_keyringPath; @@ -28,12 +27,13 @@ class KeyringTest : public testing::Test } }; +std::string KeyringTest::m_keyringName{ "org.nickvision.libnick.test" }; std::unique_ptr KeyringTest::m_keyring{ nullptr }; -std::filesystem::path KeyringTest::m_keyringPath{ UserDirectories::get(UserDirectory::Config) / "Nickvision" / "Keyring" / (KEYRING_NAME + ".ring2") }; +std::filesystem::path KeyringTest::m_keyringPath{ UserDirectories::get(UserDirectory::Config) / "Nickvision" / "Keyring" / "org.nickvision.libnick.test.ring2" }; TEST_F(KeyringTest, Create) { - ASSERT_NO_THROW(m_keyring = std::make_unique(KEYRING_NAME)); + ASSERT_NO_THROW(m_keyring = std::make_unique(m_keyringName)); #ifdef __APPLE__ if(!Environment::hasVariable("GITHUB_ACTIONS")) { @@ -47,60 +47,68 @@ TEST_F(KeyringTest, Create) TEST_F(KeyringTest, AddCredential1) { Credential credential{ "YouTube", "https://youtube.com", "theawesomeguy", "abc123!" }; - ASSERT_TRUE(m_keyring->addCredential(credential)); - ASSERT_EQ(m_keyring->getCredentials().size(), 1); - ASSERT_EQ(m_keyring->getCredential("YouTube"), credential); + ASSERT_TRUE(m_keyring->add(credential)); + ASSERT_EQ(m_keyring->getAll().size(), 1); + ASSERT_EQ(m_keyring->get("YouTube"), credential); } TEST_F(KeyringTest, AddCredential2) { Credential credential{ "GitHub", "https://github.com", "theawesomeguy", "abc123!" }; - ASSERT_TRUE(m_keyring->addCredential(credential)); - ASSERT_EQ(m_keyring->getCredentials().size(), 2); - ASSERT_EQ(m_keyring->getCredential("GitHub"), credential); + ASSERT_TRUE(m_keyring->add(credential)); + ASSERT_EQ(m_keyring->getAll().size(), 2); + ASSERT_EQ(m_keyring->get("GitHub"), credential); } TEST_F(KeyringTest, AddCredential3) { Credential credential{ "YouTube", "https://youtube.com", "me@gmail.com", "abc123!" }; - ASSERT_FALSE(m_keyring->addCredential(credential)); + ASSERT_FALSE(m_keyring->add(credential)); +} + +TEST_F(KeyringTest, UpdateCredential1) +{ + Credential credential{ "YouTube", "https://youtube.com", "me@gmail.com", "abc123!" }; + ASSERT_TRUE(m_keyring->update(credential)); + ASSERT_EQ(m_keyring->getAll().size(), 2); + ASSERT_EQ(m_keyring->get("YouTube"), credential); } TEST_F(KeyringTest, ReloadAndValidate) { ASSERT_NO_THROW(m_keyring.reset()); - ASSERT_NO_THROW(m_keyring = std::make_unique(KEYRING_NAME)); - ASSERT_EQ(m_keyring->getCredentials().size(), 2); + ASSERT_NO_THROW(m_keyring = std::make_unique(m_keyringName)); + ASSERT_EQ(m_keyring->getAll().size(), 2); } -TEST_F(KeyringTest, GetCredential1) +TEST_F(KeyringTest, GetBadCredential1) { - ASSERT_EQ(m_keyring->getCredential("Microsoft"), std::nullopt); + ASSERT_EQ(m_keyring->get("Microsoft"), std::nullopt); } -TEST_F(KeyringTest, DeleteCredential1) +TEST_F(KeyringTest, RemoveCredential1) { - ASSERT_TRUE(m_keyring->deleteCredential("YouTube")); - ASSERT_EQ(m_keyring->getCredentials().size(), 1); - ASSERT_EQ(m_keyring->getCredential("YouTube"), std::nullopt); + ASSERT_TRUE(m_keyring->remove("YouTube")); + ASSERT_EQ(m_keyring->getAll().size(), 1); + ASSERT_EQ(m_keyring->get("YouTube"), std::nullopt); } -TEST_F(KeyringTest, DeleteCredential2) +TEST_F(KeyringTest, RemoveCredential2) { - ASSERT_TRUE(m_keyring->deleteCredential("GitHub")); - ASSERT_EQ(m_keyring->getCredentials().size(), 0); - ASSERT_EQ(m_keyring->getCredential("GitHub"), std::nullopt); + ASSERT_TRUE(m_keyring->remove("GitHub")); + ASSERT_EQ(m_keyring->getAll().size(), 0); + ASSERT_EQ(m_keyring->get("GitHub"), std::nullopt); } -TEST_F(KeyringTest, DeleteCredential3) +TEST_F(KeyringTest, RemoveCredential3) { - ASSERT_FALSE(m_keyring->deleteCredential("YouTube")); + ASSERT_FALSE(m_keyring->remove("YouTube")); } TEST_F(KeyringTest, Destroy) { ASSERT_TRUE(m_keyring->destroy()); - ASSERT_EQ(m_keyring->getCredentials().size(), 0); + ASSERT_EQ(m_keyring->getAll().size(), 0); ASSERT_FALSE(m_keyring->isSavingToDisk()); ASSERT_FALSE(std::filesystem::exists(m_keyringPath)); } \ No newline at end of file diff --git a/tests/networktests.cpp b/tests/networktests.cpp index bc251ad4..faf0fe2f 100644 --- a/tests/networktests.cpp +++ b/tests/networktests.cpp @@ -13,13 +13,6 @@ TEST(NetworkTests, ConnectedGlobal) ASSERT_EQ(netmon.getConnectionState(), NetworkState::ConnectedGlobal); } -TEST(NetworkTests, DisableNetCheck) -{ - ASSERT_TRUE(Environment::setVariable("AURA_DISABLE_NETCHECK", "true")); - NetworkMonitor netmon; - ASSERT_EQ(netmon.getConnectionState(), NetworkState::ConnectedGlobal); -} - TEST(NetworkTests, IPv4Address1) { IPv4Address ip{ 192, 168, 1, 1 }; diff --git a/tests/passwordtests.cpp b/tests/passwordtests.cpp index d33db0d6..e656f88c 100644 --- a/tests/passwordtests.cpp +++ b/tests/passwordtests.cpp @@ -1,64 +1,37 @@ #include +#include #include "keyring/passwordgenerator.h" -#include "keyring/passwordstrength.h" using namespace Nickvision::Keyring; -TEST(PasswordTests, Strength1) -{ - ASSERT_TRUE(getPasswordStrength("") == PasswordStrength::Blank); -} - -TEST(PasswordTests, Strength2) -{ - ASSERT_TRUE(getPasswordStrength("abc123") == PasswordStrength::VeryWeak); -} - -TEST(PasswordTests, Strength3) -{ - ASSERT_TRUE(getPasswordStrength("abcdefg") == PasswordStrength::VeryWeak); -} - -TEST(PasswordTests, Strength4) -{ - ASSERT_TRUE(getPasswordStrength("abc1234") == PasswordStrength::Weak); -} - -TEST(PasswordTests, Strength5) -{ - ASSERT_TRUE(getPasswordStrength("rtyh6785sd32") == PasswordStrength::Medium); -} - -TEST(PasswordTests, Strength6) -{ - ASSERT_TRUE(getPasswordStrength("asdh%^asdjhk123") == PasswordStrength::Strong); -} - -TEST(PasswordTests, Strength7) -{ - ASSERT_TRUE(getPasswordStrength("aSDh%^asdjhk123") == PasswordStrength::VeryStrong); -} - TEST(PasswordTests, Generator1) { PasswordGenerator gen; - ASSERT_TRUE(gen.next().size() == 16); + std::string password{ gen.next() }; + std::cerr << "[INFO] Password generated: " << password << std::endl; + ASSERT_TRUE(password.size() == 16); } TEST(PasswordTests, Generator2) { PasswordGenerator gen{ PasswordContent::Numeric }; - ASSERT_TRUE(getPasswordStrength(gen.next()) == PasswordStrength::Weak); + std::string password{ gen.next(23) }; + std::cerr << "[INFO] Password generated: " << password << std::endl; + ASSERT_TRUE(password.size() == 23); } TEST(PasswordTests, Generator3) { PasswordGenerator gen{ PasswordContent::Numeric | PasswordContent::Lowercase }; - ASSERT_TRUE(getPasswordStrength(gen.next(4)) == PasswordStrength::VeryWeak); + std::string password{ gen.next(12) }; + std::cerr << "[INFO] Password generated: " << password << std::endl; + ASSERT_TRUE(password.size() == 12); } TEST(PasswordTests, Generator4) { PasswordGenerator gen; - ASSERT_TRUE(getPasswordStrength(gen.next()) >= PasswordStrength::Medium); + std::string password{ gen.next(64) }; + std::cerr << "[INFO] Password generated: " << password << std::endl; + ASSERT_TRUE(password.size() == 64); } \ No newline at end of file diff --git a/tests/processtests.cpp b/tests/processtests.cpp index 6e4ed641..2bf2dc63 100644 --- a/tests/processtests.cpp +++ b/tests/processtests.cpp @@ -75,8 +75,12 @@ TEST_F(ProcessTest, Send) Process p{ Environment::findDependency("sh") }; #endif ASSERT_TRUE(p.start()); - ASSERT_TRUE(p.sendCommand("echo \"Hello\"")); + ASSERT_TRUE(p.sendCommand("echo Hello")); ASSERT_TRUE(p.sendCommand("exit")); p.waitForExit(); - ASSERT_FALSE(p.getOutput().empty()); +#ifdef _WIN32 + ASSERT_TRUE(!p.getOutput().empty()); +#else + ASSERT_EQ(p.getOutput(), "Hello\n"); +#endif } diff --git a/tests/systemcredentialstests.cpp b/tests/systemcredentialstests.cpp deleted file mode 100644 index 9987659c..00000000 --- a/tests/systemcredentialstests.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include "keyring/credential.h" -#include "keyring/systemcredentials.h" - -using namespace Nickvision::Keyring; - -static const std::string randCredentialName{ "RandomAuraTestCredential1" }; - -TEST(SystemCredentialsTests, AddRandCredential) -{ - std::optional cred{ SystemCredentials::addCredential(randCredentialName) }; - ASSERT_TRUE(cred.has_value()); - ASSERT_EQ(cred.value().getName(), randCredentialName); - ASSERT_TRUE(!cred.value().getPassword().empty()); -} - -TEST(SystemCredentialsTests, FetchRandCredential) -{ - std::optional cred{ SystemCredentials::getCredential(randCredentialName) }; - ASSERT_TRUE(cred.has_value()); - ASSERT_EQ(cred.value().getName(), randCredentialName); - ASSERT_TRUE(!cred.value().getPassword().empty()); -} - -TEST(SystemCredentialsTests, UpdateRandCredential) -{ - Credential updatedCred{ randCredentialName, "", "", "abc123" }; - ASSERT_TRUE(SystemCredentials::updateCredential(updatedCred)); - std::optional cred{ SystemCredentials::getCredential(randCredentialName) }; - ASSERT_TRUE(cred.has_value()); - ASSERT_EQ(cred.value().getName(), randCredentialName); - ASSERT_EQ(cred.value().getPassword(), "abc123"); -} - -TEST(SystemCredentialsTest, DeleteRandCredential) -{ - ASSERT_TRUE(SystemCredentials::deleteCredential(randCredentialName)); -} \ No newline at end of file diff --git a/tests/systemtests.cpp b/tests/systemtests.cpp index 13e35a58..4b4252b8 100644 --- a/tests/systemtests.cpp +++ b/tests/systemtests.cpp @@ -1,13 +1,16 @@ #include #include +#include "system/credentials.h" #include "system/environment.h" #include "system/suspendinhibitor.h" +using namespace Nickvision::Keyring; using namespace Nickvision::System; class SystemTest : public testing::Test { public: + static std::string m_randCredentialName; static std::unique_ptr m_inhibitor; static void SetUpTestSuite() @@ -16,40 +19,47 @@ class SystemTest : public testing::Test } }; +std::string SystemTest::m_randCredentialName = "RandomAuraTestCredential1"; std::unique_ptr SystemTest::m_inhibitor = nullptr; -TEST_F(SystemTest, GetPath) +TEST_F(SystemTest, GetRandomCredential) { - ASSERT_FALSE(Environment::getVariable("PATH").empty()); + ASSERT_EQ(Credentials::get(m_randCredentialName), std::nullopt); } -TEST_F(SystemTest, SetTestVar) +TEST_F(SystemTest, CreateRandomCredential) { - ASSERT_TRUE(Environment::setVariable("AURA_TEST_VAR", "yes")); + std::optional cred{ Credentials::create(m_randCredentialName) }; + ASSERT_TRUE(cred.has_value()); + ASSERT_EQ(cred.value().getName(), m_randCredentialName); + ASSERT_TRUE(!cred.value().getPassword().empty()); } -TEST_F(SystemTest, EnsureTestVar) +TEST_F(SystemTest, FetchRandCredential) { - ASSERT_EQ(Environment::getVariable("AURA_TEST_VAR"), "yes"); + std::optional cred{ Credentials::get(m_randCredentialName) }; + ASSERT_TRUE(cred.has_value()); + ASSERT_EQ(cred.value().getName(), m_randCredentialName); + ASSERT_TRUE(!cred.value().getPassword().empty()); } -TEST_F(SystemTest, TestTestVar) +TEST_F(SystemTest, UpdateRandCredential) { - ASSERT_TRUE(Environment::testVariable("AURA_TEST_VAR")); + Credential updatedCred{ m_randCredentialName, "", "", "abc123" }; + ASSERT_TRUE(Credentials::update(updatedCred)); } -TEST_F(SystemTest, ClearTestVar) +TEST_F(SystemTest, FetchUpdatedRandCredential) { - ASSERT_TRUE(Environment::clearVariable("AURA_TEST_VAR")); + std::optional cred{ Credentials::get(m_randCredentialName) }; + ASSERT_TRUE(cred.has_value()); + ASSERT_EQ(cred.value().getName(), m_randCredentialName); + ASSERT_EQ(cred.value().getPassword(), "abc123"); } -TEST_F(SystemTest, Exec) +TEST_F(SystemTest, RemoveRandomCredential) { -#ifdef _WIN32 - ASSERT_EQ(Environment::exec("echo \"Hello World\""), "\"Hello World\"\r\n"); -#else - ASSERT_EQ(Environment::exec("echo \"Hello World\""), "Hello World\n"); -#endif + ASSERT_TRUE(Credentials::remove(m_randCredentialName)); } TEST_F(SystemTest, InhibitSuspend) @@ -76,6 +86,53 @@ TEST_F(SystemTest, UninhibitSuspend) ASSERT_FALSE(SystemTest::m_inhibitor->isInhibiting()); } +TEST_F(SystemTest, GetPath) +{ + ASSERT_FALSE(Environment::getVariable("PATH").empty()); +} + +TEST_F(SystemTest, SetTestVar) +{ + ASSERT_TRUE(Environment::setVariable("AURA_TEST_VAR", "yes")); +} + +TEST_F(SystemTest, EnsureTestVar) +{ + ASSERT_EQ(Environment::getVariable("AURA_TEST_VAR"), "yes"); +} + +TEST_F(SystemTest, TestTestVar) +{ + ASSERT_TRUE(Environment::testVariable("AURA_TEST_VAR")); +} + +TEST_F(SystemTest, ClearTestVar) +{ + ASSERT_TRUE(Environment::clearVariable("AURA_TEST_VAR")); +} + +TEST_F(SystemTest, Exec) +{ +#ifdef _WIN32 + ASSERT_EQ(Environment::exec("echo Hello World"), "Hello World\r\n"); +#else + ASSERT_EQ(Environment::exec("echo Hello World"), "Hello World\n"); +#endif +} + +TEST_F(SystemTest, ExecAsync) +{ + std::future cmd1{ Environment::execAsync("echo Hello World") }; + std::future cmd2{ Environment::execAsync("echo World Hello") }; +#ifdef _WIN32 + ASSERT_EQ(cmd1.get(), "Hello World\r\n"); + ASSERT_EQ(cmd2.get(), "World Hello\r\n"); +#else + ASSERT_EQ(cmd1.get(), "Hello World\n"); + ASSERT_EQ(cmd2.get(), "World Hello\n"); +#endif +} + TEST_F(SystemTest, RunningInformationChecks) { ASSERT_TRUE(!Environment::getExecutableDirectory().empty()); diff --git a/tests/taskbartests.cpp b/tests/taskbartests.cpp deleted file mode 100644 index d23db510..00000000 --- a/tests/taskbartests.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include "taskbar/taskbaritem.h" - -using namespace Nickvision::Taskbar; - -class TaskbarTest : public testing::Test -{ -public: - static std::unique_ptr m_taskbar; - - static void SetUpTestSuite() - { - m_taskbar = std::make_unique(); - } -}; - -std::unique_ptr TaskbarTest::m_taskbar = nullptr; - -#ifdef _WIN32 -TEST_F(TaskbarTest, ConnectWindows) -{ - HWND hwnd{ GetConsoleWindow() }; - if (hwnd) - { - ASSERT_TRUE(m_taskbar->connect(hwnd)); - } -} -#elif defined(__linux__) -TEST_F(TaskbarTest, ConnectLinux) -{ - ASSERT_TRUE(m_taskbar->connect("firefox.desktop")); -} -#endif - -TEST_F(TaskbarTest, SetProgress) -{ - ASSERT_NO_THROW(m_taskbar->setProgress(0.35)); - ASSERT_TRUE(m_taskbar->getProgressState() == ProgressState::Normal); -} - -TEST_F(TaskbarTest, SetProgressPaused) -{ - ASSERT_NO_THROW(m_taskbar->setProgressState(ProgressState::Paused)); -} - -TEST_F(TaskbarTest, SetUrgent) -{ - ASSERT_NO_THROW(m_taskbar->setUrgent(true)); -} - -TEST_F(TaskbarTest, SetCount) -{ - ASSERT_NO_THROW(m_taskbar->setCountVisible(true)); - ASSERT_NO_THROW(m_taskbar->setCount(5)); -} - -TEST_F(TaskbarTest, Cleanup) -{ - std::this_thread::sleep_for(std::chrono::seconds(2)); - ASSERT_NO_THROW(m_taskbar.reset()); -} \ No newline at end of file diff --git a/tests/updatertests.cpp b/tests/updatertests.cpp index 0fa6c987..3a6aa534 100644 --- a/tests/updatertests.cpp +++ b/tests/updatertests.cpp @@ -16,17 +16,34 @@ TEST(UpdaterTests, ParabolicStableUpdate) Version stable{ updater.fetchCurrentVersion(VersionType::Stable) }; ASSERT_TRUE(!stable.empty()); ASSERT_TRUE(stable.getVersionType() == VersionType::Stable); - ASSERT_TRUE(stable >= Version("2023.12.0")); + ASSERT_TRUE(stable >= Version("2025.8.0")); +} + +TEST(UpdaterTests, YtdlpUpdate) +{ + if(Environment::hasVariable("GITHUB_ACTIONS")) + { + GTEST_SKIP(); + } + std::filesystem::path downloadPath{ Environment::getExecutableDirectory() / "yt-dlp" }; + Updater updater{ "https://github.com/yt-dlp/yt-dlp" }; + Version stable{ updater.fetchCurrentVersion(VersionType::Stable) }; + ASSERT_TRUE(!stable.empty()); + ASSERT_TRUE(stable.getVersionType() == VersionType::Stable); + ASSERT_TRUE(stable >= Version("2025.8.11")); + ASSERT_TRUE(updater.downloadUpdate(VersionType::Stable, downloadPath, "yt-dlp")); + ASSERT_TRUE(std::filesystem::exists(downloadPath)); + ASSERT_TRUE(std::filesystem::remove(downloadPath)); } #ifdef _WIN32 -TEST(UpdaterTests, SpotlightWindowsUpdate) +TEST(UpdaterTests, ParabolicWindowsUpdate) { if(Environment::hasVariable("GITHUB_ACTIONS")) { GTEST_SKIP(); } - Updater updater{ "https://github.com/NickvisionApps/Spotlight" }; + Updater updater{ "https://github.com/NickvisionApps/Parabolic" }; Version stable{ updater.fetchCurrentVersion(VersionType::Stable) }; ASSERT_TRUE(!stable.empty()); ASSERT_TRUE(updater.windowsUpdate(VersionType::Stable));