diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 4ac6c217..e91ce9f3 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -325,7 +325,13 @@ jobs: COMMIT: ${{ needs.setup_release.outputs.release_commit }} run: | chmod +x ./scripts/linux_build.sh - ./scripts/linux_build.sh --skip-cleanup --skip-package --ubuntu-test-repo ${{ matrix.EXTRA_ARGS }} + ./scripts/linux_build.sh \ + --publisher-name='${{ github.repository_owner }}' \ + --publisher-website='https://app.lizardbyte.dev' \ + --publisher-issue-url='https://app.lizardbyte.dev/support' \ + --skip-cleanup \ + --skip-package \ + --ubuntu-test-repo ${{ matrix.EXTRA_ARGS }} - name: Set AppImage Version if: | @@ -1101,6 +1107,9 @@ jobs: -DBUILD_WERROR=ON \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DSUNSHINE_ASSETS_DIR=assets \ + -DSUNSHINE_PUBLSIHER_NAME='${{ github.repository_owner }}' \ + -DSUNSHINE_PUBLISHER_WEBSITE='https://app.lizardbyte.dev' \ + -DSUNSHINE_PUBLISHER_ISSUE_URL='https://app.lizardbyte.dev/support' \ -DTESTS_SOFTWARE_ENCODER_UNAVAILABLE='skip' ninja -C build diff --git a/.gitignore b/.gitignore index b3c5bd85..30818d52 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,7 @@ package-lock.json # Dummy macOS files .DS_Store + +# Python +*.pyc +venv/ diff --git a/cmake/compile_definitions/common.cmake b/cmake/compile_definitions/common.cmake index a2260595..7b13168a 100644 --- a/cmake/compile_definitions/common.cmake +++ b/cmake/compile_definitions/common.cmake @@ -124,6 +124,11 @@ list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_ASSETS_DIR="${SUNSHINE_ASSETS_DIR_DEF} list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_TRAY=${SUNSHINE_TRAY}) +# Publisher metadata +list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_PUBLISHER_NAME="${SUNSHINE_PUBLISHER_NAME}") +list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_PUBLISHER_WEBSITE="${SUNSHINE_PUBLISHER_WEBSITE}") +list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_PUBLISHER_ISSUE_URL="${SUNSHINE_PUBLISHER_ISSUE_URL}") + include_directories("${CMAKE_SOURCE_DIR}") include_directories( diff --git a/cmake/prep/options.cmake b/cmake/prep/options.cmake index f358f727..f1b33f08 100644 --- a/cmake/prep/options.cmake +++ b/cmake/prep/options.cmake @@ -1,3 +1,12 @@ +# Publisher Metadata +set(SUNSHINE_PUBLISHER_NAME "Third Party Publisher" + CACHE STRING "The name of the publisher (not developer) of the application.") +set(SUNSHINE_PUBLISHER_WEBSITE "" + CACHE STRING "The URL of the publisher's website.") +set(SUNSHINE_PUBLISHER_ISSUE_URL "https://app.lizardbyte.dev/support" + CACHE STRING "The URL of the publisher's support site or issue tracker. + If you provide a modified version of Sunshine, we kindly request that you use your own url.") + option(BUILD_DOCS "Build documentation" ON) option(BUILD_TESTS "Build tests" ON) option(TESTS_ENABLE_PYTHON_TESTS "Enable Python tests" ON) diff --git a/docker/debian-bookworm.dockerfile b/docker/debian-bookworm.dockerfile index 8a6db148..b98bb96d 100644 --- a/docker/debian-bookworm.dockerfile +++ b/docker/debian-bookworm.dockerfile @@ -31,7 +31,11 @@ RUN <<_BUILD #!/bin/bash set -e chmod +x ./scripts/linux_build.sh -./scripts/linux_build.sh --sudo-off +./scripts/linux_build.sh \ + --publisher-name='LizardByte' \ + --publisher-website='https://app.lizardbyte.dev' \ + --publisher-issue-url='https://app.lizardbyte.dev/support' \ + --sudo-off apt-get clean rm -rf /var/lib/apt/lists/* _BUILD diff --git a/docker/fedora-39.dockerfile b/docker/fedora-39.dockerfile index e50fffdb..87d2eb29 100644 --- a/docker/fedora-39.dockerfile +++ b/docker/fedora-39.dockerfile @@ -29,7 +29,11 @@ RUN <<_BUILD #!/bin/bash set -e chmod +x ./scripts/linux_build.sh -./scripts/linux_build.sh --sudo-off +./scripts/linux_build.sh \ + --publisher-name='LizardByte' \ + --publisher-website='https://app.lizardbyte.dev' \ + --publisher-issue-url='https://app.lizardbyte.dev/support' \ + --sudo-off dnf clean all rm -rf /var/cache/yum _BUILD diff --git a/docker/fedora-40.dockerfile b/docker/fedora-40.dockerfile index 24735eef..61c6cced 100644 --- a/docker/fedora-40.dockerfile +++ b/docker/fedora-40.dockerfile @@ -29,7 +29,11 @@ RUN <<_BUILD #!/bin/bash set -e chmod +x ./scripts/linux_build.sh -./scripts/linux_build.sh --sudo-off +./scripts/linux_build.sh \ + --publisher-name='LizardByte' \ + --publisher-website='https://app.lizardbyte.dev' \ + --publisher-issue-url='https://app.lizardbyte.dev/support' \ + --sudo-off dnf clean all rm -rf /var/cache/yum _BUILD diff --git a/docker/ubuntu-22.04.dockerfile b/docker/ubuntu-22.04.dockerfile index bfb2c3d0..46952532 100644 --- a/docker/ubuntu-22.04.dockerfile +++ b/docker/ubuntu-22.04.dockerfile @@ -31,7 +31,11 @@ RUN <<_BUILD #!/bin/bash set -e chmod +x ./scripts/linux_build.sh -./scripts/linux_build.sh --sudo-off +./scripts/linux_build.sh \ + --publisher-name='LizardByte' \ + --publisher-website='https://app.lizardbyte.dev' \ + --publisher-issue-url='https://app.lizardbyte.dev/support' \ + --sudo-off apt-get clean rm -rf /var/lib/apt/lists/* _BUILD diff --git a/docker/ubuntu-24.04.dockerfile b/docker/ubuntu-24.04.dockerfile index cbadaa62..1decc62f 100644 --- a/docker/ubuntu-24.04.dockerfile +++ b/docker/ubuntu-24.04.dockerfile @@ -31,7 +31,11 @@ RUN <<_BUILD #!/bin/bash set -e chmod +x ./scripts/linux_build.sh -./scripts/linux_build.sh --sudo-off +./scripts/linux_build.sh \ + --publisher-name='LizardByte' \ + --publisher-website='https://app.lizardbyte.dev' \ + --publisher-issue-url='https://app.lizardbyte.dev/support' \ + --sudo-off apt-get clean rm -rf /var/lib/apt/lists/* _BUILD diff --git a/packaging/linux/Arch/PKGBUILD b/packaging/linux/Arch/PKGBUILD index 496ab699..e8eb8521 100644 --- a/packaging/linux/Arch/PKGBUILD +++ b/packaging/linux/Arch/PKGBUILD @@ -83,7 +83,10 @@ build() { -D BUILD_WERROR=ON \ -D CMAKE_INSTALL_PREFIX=/usr \ -D SUNSHINE_EXECUTABLE_PATH=/usr/bin/sunshine \ - -D SUNSHINE_ASSETS_DIR="share/sunshine" + -D SUNSHINE_ASSETS_DIR="share/sunshine" \ + -D SUNSHINE_PUBLSIHER_NAME='LizardByte' \ + -D SUNSHINE_PUBLISHER_WEBSITE='https://app.lizardbyte.dev' \ + -D SUNSHINE_PUBLISHER_ISSUE_URL='https://app.lizardbyte.dev/support' make -C build } diff --git a/packaging/linux/flatpak/dev.lizardbyte.app.Sunshine.yml b/packaging/linux/flatpak/dev.lizardbyte.app.Sunshine.yml index d2b71022..f5e90739 100644 --- a/packaging/linux/flatpak/dev.lizardbyte.app.Sunshine.yml +++ b/packaging/linux/flatpak/dev.lizardbyte.app.Sunshine.yml @@ -71,12 +71,15 @@ modules: - -DCMAKE_BUILD_TYPE=Release - -DCMAKE_CUDA_COMPILER=/app/cuda/bin/nvcc - -DSUNSHINE_ASSETS_DIR=share/sunshine + - -DSUNSHINE_BUILD_FLATPAK=ON - -DSUNSHINE_EXECUTABLE_PATH=/app/bin/sunshine - -DSUNSHINE_ENABLE_WAYLAND=ON - -DSUNSHINE_ENABLE_X11=ON - -DSUNSHINE_ENABLE_DRM=ON - -DSUNSHINE_ENABLE_CUDA=ON - - -DSUNSHINE_BUILD_FLATPAK=ON + - -DSUNSHINE_PUBLSIHER_NAME='LizardByte' + -DSUNSHINE_PUBLISHER_WEBSITE='https://app.lizardbyte.dev' + -DSUNSHINE_PUBLISHER_ISSUE_URL='https://app.lizardbyte.dev/support' sources: - type: git url: "@GITHUB_CLONE_URL@" diff --git a/packaging/macos/Portfile b/packaging/macos/Portfile index 1b9e1bda..a2a9eb5e 100644 --- a/packaging/macos/Portfile +++ b/packaging/macos/Portfile @@ -43,7 +43,10 @@ depends_lib port:curl \ configure.args -DBOOST_USE_STATIC=ON \ -DBUILD_WERROR=ON \ -DCMAKE_INSTALL_PREFIX=${prefix} \ - -DSUNSHINE_ASSETS_DIR=etc/sunshine/assets + -DSUNSHINE_ASSETS_DIR=etc/sunshine/assets \ + -DSUNSHINE_PUBLSIHER_NAME='LizardByte' \ + -DSUNSHINE_PUBLISHER_WEBSITE='https://app.lizardbyte.dev' \ + -DSUNSHINE_PUBLISHER_ISSUE_URL='https://app.lizardbyte.dev/support' configure.env-append BRANCH=@GITHUB_BRANCH@ configure.env-append BUILD_VERSION=@BUILD_VERSION@ diff --git a/packaging/sunshine.rb b/packaging/sunshine.rb index cf6886b4..a8d9a661 100644 --- a/packaging/sunshine.rb +++ b/packaging/sunshine.rb @@ -71,6 +71,9 @@ class @PROJECT_NAME@ < Formula -DSUNSHINE_ASSETS_DIR=sunshine/assets -DSUNSHINE_BUILD_HOMEBREW=ON -DSUNSHINE_ENABLE_TRAY=OFF + -DSUNSHINE_PUBLSIHER_NAME='LizardByte' + -DSUNSHINE_PUBLISHER_WEBSITE='https://app.lizardbyte.dev' + -DSUNSHINE_PUBLISHER_ISSUE_URL='https://app.lizardbyte.dev/support' ] if build.with? "docs-off" diff --git a/scripts/linux_build.sh b/scripts/linux_build.sh index 0ad3aaf6..f0cd3d7f 100644 --- a/scripts/linux_build.sh +++ b/scripts/linux_build.sh @@ -3,6 +3,9 @@ set -e # Default value for arguments appimage_build=0 +publisher_name="Third Party Publisher" +publisher_website="" +publisher_issue_url="https://app.lizardbyte.dev/support" skip_cleanup=0 skip_cuda=0 skip_libva=0 @@ -21,14 +24,18 @@ Usage: $0 [options] Options: - -h, --help Display this help message. - -s, --sudo-off Disable sudo command. - --appimage-build Compile for AppImage, this will not create the AppImage, just the executable. - --skip-cleanup Do not restore the original gcc alternatives, or the math-vector.h file. - --skip-cuda Skip CUDA installation. - --skip-libva Skip libva installation. This will automatically be enabled if passing --appimage-build. - --skip-package Skip creating DEB, or RPM package. - --ubuntu-test-repo Install ppa:ubuntu-toolchain-r/test repo on Ubuntu. + -h, --help Display this help message. + -s, --sudo-off Disable sudo command. + --appimage-build Compile for AppImage, this will not create the AppImage, just the executable. + --publisher-name The name of the publisher (not developer) of the application. + --publisher-website The URL of the publisher's website. + --publisher-issue-url The URL of the publisher's support site or issue tracker. + If you provide a modified version of Sunshine, we kindly request that you use your own url. + --skip-cleanup Do not restore the original gcc alternatives, or the math-vector.h file. + --skip-cuda Skip CUDA installation. + --skip-libva Skip libva installation. This will automatically be enabled if passing --appimage-build. + --skip-package Skip creating DEB, or RPM package. + --ubuntu-test-repo Install ppa:ubuntu-toolchain-r/test repo on Ubuntu. EOF exit "$exit_code" @@ -46,6 +53,15 @@ while getopts ":hs-:" opt; do appimage_build=1 skip_libva=1 ;; + publisher-name=*) + publisher_name="${OPTARG#*=}" + ;; + publisher-website=*) + publisher_website="${OPTARG#*=}" + ;; + publisher-issue-url=*) + publisher_issue_url="${OPTARG#*=}" + ;; skip-cleanup) skip_cleanup=1 ;; skip-cuda) skip_cuda=1 ;; skip-libva) skip_libva=1 ;; @@ -268,6 +284,17 @@ function run_install() { cmake_args+=("-DSUNSHINE_BUILD_APPIMAGE=ON") fi + # Publisher metadata + if [ -n "$publisher_name" ]; then + cmake_args+=("-DSUNSHINE_PUBLISHER_NAME='${publisher_name}'") + fi + if [ -n "$publisher_website" ]; then + cmake_args+=("-DSUNSHINE_PUBLISHER_WEBSITE='${publisher_website}'") + fi + if [ -n "$publisher_issue_url" ]; then + cmake_args+=("-DSUNSHINE_PUBLISHER_ISSUE_URL='${publisher_issue_url}'") + fi + # Update the package list $package_update_command diff --git a/src/crypto.h b/src/crypto.h index 20651ecb..859c6675 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -34,6 +34,11 @@ namespace crypto { using pkey_ctx_t = util::safe_ptr; using bignum_t = util::safe_ptr; + /** + * @brief Hashes the given plaintext using SHA-256. + * @param plaintext + * @return The SHA-256 hash of the plaintext. + */ sha256_t hash(const std::string_view &plaintext); diff --git a/src/entry_handler.cpp b/src/entry_handler.cpp index fb1ece2c..2f755e9a 100644 --- a/src/entry_handler.cpp +++ b/src/entry_handler.cpp @@ -109,6 +109,13 @@ namespace lifetime { } } // namespace lifetime +void +log_publisher_data() { + BOOST_LOG(info) << "Package Publisher: "sv << SUNSHINE_PUBLISHER_NAME; + BOOST_LOG(info) << "Publisher Website: "sv << SUNSHINE_PUBLISHER_WEBSITE; + BOOST_LOG(info) << "Get support: "sv << SUNSHINE_PUBLISHER_ISSUE_URL; +} + #ifdef _WIN32 bool is_gamestream_enabled() { diff --git a/src/entry_handler.h b/src/entry_handler.h index 7e680b43..a2c9735a 100644 --- a/src/entry_handler.h +++ b/src/entry_handler.h @@ -108,6 +108,12 @@ namespace lifetime { get_argv(); } // namespace lifetime +/** + * @brief Log the publisher metadata provided from CMake. + */ +void +log_publisher_data(); + #ifdef _WIN32 /** * @brief Check if NVIDIA's GameStream software is running. diff --git a/src/main.cpp b/src/main.cpp index 1a1d5ef2..c4ded3d5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -114,6 +114,9 @@ main(int argc, char *argv[]) { // the version should be printed to the log before anything else BOOST_LOG(info) << PROJECT_NAME << " version: " << PROJECT_VER; + // Log publisher metadata + log_publisher_data(); + if (!config::sunshine.cmd.name.empty()) { auto fn = cmd_to_func.find(config::sunshine.cmd.name); if (fn == std::end(cmd_to_func)) { diff --git a/tests/tests_log_checker.h b/tests/tests_log_checker.h new file mode 100644 index 00000000..656151f6 --- /dev/null +++ b/tests/tests_log_checker.h @@ -0,0 +1,135 @@ +/** + * @file tests/tests_log_checker.h + * @brief Utility functions to check log file contents. + */ +#pragma once + +#include +#include +#include +#include + +#include + +namespace log_checker { + + /** + * @brief Remove the timestamp prefix from a log line. + * @param line The log line. + * @return The log line without the timestamp prefix. + */ + inline std::string + remove_timestamp_prefix(const std::string &line) { + static const std::regex timestamp_regex(R"(\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\]: )"); + return std::regex_replace(line, timestamp_regex, ""); + } + + /** + * @brief Check if a log file contains a line that starts with the given string. + * @param log_file Path to the log file. + * @param start_str The string that the line should start with. + * @return True if such a line is found, false otherwise. + */ + inline bool + line_starts_with(const std::string &log_file, const std::string_view &start_str) { + logging::log_flush(); + + std::ifstream input(log_file); + if (!input.is_open()) { + return false; + } + + for (std::string line; std::getline(input, line);) { + line = remove_timestamp_prefix(line); + if (line.rfind(start_str, 0) == 0) { + return true; + } + } + return false; + } + + /** + * @brief Check if a log file contains a line that ends with the given string. + * @param log_file Path to the log file. + * @param end_str The string that the line should end with. + * @return True if such a line is found, false otherwise. + */ + inline bool + line_ends_with(const std::string &log_file, const std::string_view &end_str) { + logging::log_flush(); + + std::ifstream input(log_file); + if (!input.is_open()) { + return false; + } + + for (std::string line; std::getline(input, line);) { + line = remove_timestamp_prefix(line); + if (line.size() >= end_str.size() && + line.compare(line.size() - end_str.size(), end_str.size(), end_str) == 0) { + return true; + } + } + return false; + } + + /** + * @brief Check if a log file contains a line that equals the given string. + * @param log_file Path to the log file. + * @param str The string that the line should equal. + * @return True if such a line is found, false otherwise. + */ + inline bool + line_equals(const std::string &log_file, const std::string_view &str) { + logging::log_flush(); + + std::ifstream input(log_file); + if (!input.is_open()) { + return false; + } + + for (std::string line; std::getline(input, line);) { + line = remove_timestamp_prefix(line); + if (line == str) { + return true; + } + } + return false; + } + + /** + * @brief Check if a log file contains a line that contains the given substring. + * @param log_file Path to the log file. + * @param substr The substring to search for. + * @param case_insensitive Whether the search should be case-insensitive. + * @return True if such a line is found, false otherwise. + */ + inline bool + line_contains(const std::string &log_file, const std::string_view &substr, bool case_insensitive = false) { + logging::log_flush(); + + std::ifstream input(log_file); + if (!input.is_open()) { + return false; + } + + std::string search_str(substr); + if (case_insensitive) { + // sonarcloud complains about this, but the solution doesn't work for macOS-12 + std::transform(search_str.begin(), search_str.end(), search_str.begin(), ::tolower); + } + + for (std::string line; std::getline(input, line);) { + line = remove_timestamp_prefix(line); + if (case_insensitive) { + // sonarcloud complains about this, but the solution doesn't work for macOS-12 + std::transform(line.begin(), line.end(), line.begin(), ::tolower); + } + if (line.find(search_str) != std::string::npos) { + return true; + } + } + return false; + } + +} // namespace log_checker diff --git a/tests/unit/test_entry_handler.cpp b/tests/unit/test_entry_handler.cpp new file mode 100644 index 00000000..d1e2b061 --- /dev/null +++ b/tests/unit/test_entry_handler.cpp @@ -0,0 +1,18 @@ +/** + * @file tests/unit/test_entry_handler.cpp + * @brief Test src/entry_handler.*. + */ +#include + +#include "../tests_common.h" +#include "../tests_log_checker.h" + +TEST(EntryHandlerTests, LogPublisherDataTest) { + // call log_publisher_data + log_publisher_data(); + + // check if specific log messages exist + ASSERT_TRUE(log_checker::line_starts_with("test_sunshine.log", "Info: Package Publisher: ")); + ASSERT_TRUE(log_checker::line_starts_with("test_sunshine.log", "Info: Publisher Website: ")); + ASSERT_TRUE(log_checker::line_starts_with("test_sunshine.log", "Info: Get support: ")); +} diff --git a/tests/unit/test_logging.cpp b/tests/unit/test_logging.cpp index 99b4b264..b53b493b 100644 --- a/tests/unit/test_logging.cpp +++ b/tests/unit/test_logging.cpp @@ -5,8 +5,8 @@ #include #include "../tests_common.h" +#include "../tests_log_checker.h" -#include #include namespace { @@ -40,25 +40,5 @@ TEST_P(LogLevelsTest, PutMessage) { auto test_message = std::to_string(rand_gen()) + std::to_string(rand_gen()); BOOST_LOG(logger) << test_message; - // Flush logger and search for the message in the log file - - logging::log_flush(); - - std::ifstream input(log_file); - ASSERT_TRUE(input.is_open()); - - bool found = false; - for (std::string line; std::getline(input, line);) { - if (line.find(test_message) != std::string::npos) { - // Assume that logger may change the case of log level label - std::transform(line.begin(), line.end(), line.begin(), - [](char c) { return std::tolower(c); }); - - if (line.find(label) != std::string::npos) { - found = true; - break; - } - } - } - ASSERT_TRUE(found); + ASSERT_TRUE(log_checker::line_contains(log_file, test_message)); }