Compare commits

...

8 Commits

9 changed files with 171 additions and 30 deletions
+1
View File
@@ -501,6 +501,7 @@ jobs:
run: |
cat > version.json << EOF
{
"latest_version": "${{ steps.version.outputs.VERSION_NUM }}",
"version": "${{ steps.version.outputs.VERSION_NUM }}",
"releaseDate": "${{ steps.version.outputs.BUILD_DATE_ISO }}",
"patch": ${{ steps.version.outputs.PATCH_NUMBER }},
@@ -140,6 +140,7 @@ jobs:
# Generate version.json using cat and heredoc
cat > version.json << EOF
{
"latest_version": "${{ steps.version.outputs.VERSION_FULL }}",
"version": "${{ steps.version.outputs.VERSION_FULL }}",
"releaseDate": "${{ steps.version.outputs.BUILD_DATE_ISO }}",
"patch": ${{ steps.version.outputs.PATCH_NUMBER }},
@@ -158,6 +158,9 @@ struct TranslationRow {
X(signal_connected, u8"已连接服务器", "Connected", u8"Подключено к серверу") \
X(signal_disconnected, u8"未连接服务器", "Disconnected", \
u8"Нет подключения к серверу") \
X(signal_tls_cert_error, u8"证书验证失败,请重新安装自托管根证书", \
"Certificate verification failed. Reinstall the self-hosted root certificate.", \
u8"Ошибка проверки сертификата. Переустановите корневой сертификат.") \
X(p2p_connected, u8"对等连接已建立", "P2P Connected", u8"P2P подключено") \
X(p2p_disconnected, u8"对等连接已断开", "P2P Disconnected", \
u8"P2P отключено") \
+35 -20
View File
@@ -1719,26 +1719,6 @@ int Render::DrawServerWindow() {
}
int Render::Run() {
latest_version_info_ = CheckUpdate();
if (!latest_version_info_.empty() &&
latest_version_info_.contains("version") &&
latest_version_info_["version"].is_string()) {
latest_version_ = 'v' + latest_version_info_["version"].get<std::string>();
if (latest_version_info_.contains("releaseNotes") &&
latest_version_info_["releaseNotes"].is_string()) {
release_notes_ = latest_version_info_["releaseNotes"].get<std::string>();
} else {
release_notes_ = "";
}
update_available_ = IsNewerVersion(CROSSDESK_VERSION, latest_version_);
if (update_available_) {
show_update_notification_window_ = true;
}
} else {
latest_version_ = "";
update_available_ = false;
}
path_manager_ = std::make_unique<PathManager>("CrossDesk");
if (path_manager_) {
exec_log_path_ = path_manager_->GetLogPath().string();
@@ -1767,6 +1747,41 @@ int Render::Run() {
InitializeLogger();
LOG_INFO("CrossDesk version: {}", CROSSDESK_VERSION);
latest_version_info_ = CheckUpdate();
if (!latest_version_info_.empty()) {
std::string version;
if (latest_version_info_.contains("latest_version") &&
latest_version_info_["latest_version"].is_string()) {
version = latest_version_info_["latest_version"].get<std::string>();
} else if (latest_version_info_.contains("version") &&
latest_version_info_["version"].is_string()) {
version = latest_version_info_["version"].get<std::string>();
}
if (!version.empty()) {
latest_version_ = 'v' + version;
} else {
latest_version_ = "";
}
if (latest_version_info_.contains("releaseNotes") &&
latest_version_info_["releaseNotes"].is_string()) {
release_notes_ = latest_version_info_["releaseNotes"].get<std::string>();
} else {
release_notes_ = "";
}
update_available_ =
!version.empty() && IsNewerVersion(CROSSDESK_VERSION, latest_version_);
LOG_INFO("Update check: current={}, latest={}, available={}",
CROSSDESK_VERSION, latest_version_, update_available_);
if (update_available_) {
show_update_notification_window_ = true;
}
} else {
latest_version_ = "";
update_available_ = false;
LOG_WARN("Update check skipped: version.json is empty or missing latest_version");
}
InitializeSettings();
InitializeSDL();
InitializeModules();
+4
View File
@@ -1231,6 +1231,8 @@ void Render::OnSignalStatusCb(SignalStatus status, const char* user_id,
render->signal_connected_ = false;
} else if (SignalStatus::SignalServerClosed == status) {
render->signal_connected_ = false;
} else if (SignalStatus::SignalTlsCertError == status) {
render->signal_connected_ = false;
}
} else {
if (client_id.rfind("C-", 0) != 0) {
@@ -1258,6 +1260,8 @@ void Render::OnSignalStatusCb(SignalStatus status, const char* user_id,
props->signal_connected_ = false;
} else if (SignalStatus::SignalServerClosed == status) {
props->signal_connected_ = false;
} else if (SignalStatus::SignalTlsCertError == status) {
props->signal_connected_ = false;
}
}
}
+18 -7
View File
@@ -26,20 +26,31 @@ int Render::StatusBar() {
ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddCircleFilled(dot_pos, status_bar_height * 0.25f,
ImColor(1.0f, 1.0f, 1.0f), 100);
bool tls_cert_error =
signal_status_ == SignalStatus::SignalTlsCertError;
draw_list->AddCircleFilled(dot_pos, status_bar_height * 0.2f,
ImColor(signal_connected_ ? 0.0f : 1.0f,
signal_connected_ ? 1.0f : 0.0f, 0.0f),
tls_cert_error
? ImColor(1.0f, 0.65f, 0.0f)
: ImColor(signal_connected_ ? 0.0f : 1.0f,
signal_connected_ ? 1.0f : 0.0f,
0.0f),
100);
ImGui::SetWindowFontScale(0.6f);
const char* signal_status_text =
tls_cert_error
? localization::signal_tls_cert_error[localization_language_index_]
.c_str()
: (signal_connected_
? localization::signal_connected[localization_language_index_]
.c_str()
: localization::signal_disconnected
[localization_language_index_]
.c_str());
draw_list->AddText(
ImVec2(status_bar_width * 0.045f,
io.DisplaySize.y * (1 - STATUS_BAR_HEIGHT * 0.9f)),
ImColor(0.0f, 0.0f, 0.0f),
signal_connected_
? localization::signal_connected[localization_language_index_].c_str()
: localization::signal_disconnected[localization_language_index_]
.c_str());
ImColor(0.0f, 0.0f, 0.0f), signal_status_text);
ImGui::SetWindowFontScale(1.0f);
ImGui::EndChild();
+99 -2
View File
@@ -8,8 +8,13 @@
#include <httplib.h>
#include "rd_log.h"
#include <algorithm>
#include <array>
#include <cctype>
#include <cstdlib>
#include <filesystem>
#include <iostream>
#include <limits>
#include <sstream>
@@ -225,6 +230,85 @@ bool ReadPatchField(const nlohmann::json& json, int* patch) {
return false;
}
void LogHttpError(const httplib::Result& result) {
LOG_WARN("Failed to fetch version.json: error={}, message={}",
static_cast<int>(result.error()), httplib::to_string(result.error()));
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
LOG_WARN("version.json SSL error={}, OpenSSL error={}", result.ssl_error(),
result.ssl_openssl_error());
#endif
}
#if defined(CPPHTTPLIB_OPENSSL_SUPPORT) && defined(__linux__)
bool PathExists(const std::string& path) {
if (path.empty()) {
return false;
}
std::error_code ec;
return std::filesystem::exists(path, ec);
}
std::string GetEnvPathIfExists(const char* key) {
const char* value = std::getenv(key);
if (!value) {
return "";
}
const std::string path = value;
return PathExists(path) ? path : "";
}
std::string FindFirstExistingPath(
const std::vector<std::string>& candidates) {
for (const auto& candidate : candidates) {
if (PathExists(candidate)) {
return candidate;
}
}
return "";
}
void ConfigureLinuxCaCerts(httplib::Client* cli) {
const std::string ca_file = [&]() {
const std::string env_path = GetEnvPathIfExists("SSL_CERT_FILE");
if (!env_path.empty()) {
return env_path;
}
return FindFirstExistingPath({
"/etc/ssl/certs/ca-certificates.crt",
"/etc/pki/tls/certs/ca-bundle.crt",
"/etc/ssl/cert.pem",
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
});
}();
const std::string ca_dir = [&]() {
const std::string env_path = GetEnvPathIfExists("SSL_CERT_DIR");
if (!env_path.empty()) {
return env_path;
}
return FindFirstExistingPath({
"/etc/ssl/certs",
"/etc/pki/tls/certs",
"/etc/openssl/certs",
});
}();
if (ca_file.empty() && ca_dir.empty()) {
LOG_WARN("No Linux CA bundle found for version.json request; relying on OpenSSL defaults");
return;
}
cli->set_ca_cert_path(ca_file, ca_dir);
LOG_INFO("Configured version.json TLS CA bundle: file={}, dir={}",
ca_file.empty() ? "<none>" : ca_file,
ca_dir.empty() ? "<none>" : ca_dir);
}
#endif
} // namespace
std::string ExtractNumericPart(const std::string& ver) {
@@ -312,8 +396,14 @@ nlohmann::json CheckUpdate() {
cli.set_connection_timeout(5);
cli.set_read_timeout(5);
cli.set_follow_location(true);
if (auto res = cli.Get("/version.json")) {
#if defined(CPPHTTPLIB_OPENSSL_SUPPORT) && defined(__linux__)
ConfigureLinuxCaCerts(&cli);
#endif
auto res = cli.Get("/version.json");
if (res) {
if (res->status == 200) {
try {
auto j = nlohmann::json::parse(res->body);
@@ -324,16 +414,23 @@ nlohmann::json CheckUpdate() {
}
latest_patch_ = 0;
latest_patch_available_ = ReadPatchField(j, &latest_patch_);
LOG_INFO("Fetched version.json: latest_version={}, releaseDate={}, patch={}",
j.value("latest_version", j.value("version", "")),
j.value("releaseDate", ""),
latest_patch_available_ ? latest_patch_ : -1);
return j;
} catch (std::exception&) {
} catch (const std::exception& e) {
LOG_WARN("Failed to parse version.json: {}", e.what());
ResetLatestMetadata();
return nlohmann::json{};
}
} else {
LOG_WARN("Failed to fetch version.json: HTTP status={}", res->status);
ResetLatestMetadata();
return nlohmann::json{};
}
} else {
LogHttpError(res);
ResetLatestMetadata();
return nlohmann::json{};
}
+9
View File
@@ -74,9 +74,14 @@ function setup_targets()
set_kind("binary")
set_default(false)
add_packages("cpp-httplib")
add_deps("rd_log")
add_includedirs("src/version_checker")
add_files("tests/version_checker_test.cpp",
"src/version_checker/version_checker.cpp")
if is_os("macosx") then
add_defines("CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN")
add_frameworks("Security", "CoreFoundation")
end
target("screen_capturer")
set_kind("object")
@@ -177,6 +182,10 @@ function setup_targets()
add_deps("rd_log")
add_files("src/version_checker/*.cpp")
add_includedirs("src/version_checker", {public = true})
if is_os("macosx") then
add_defines("CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN")
add_frameworks("Security", "CoreFoundation")
end
target("tools")
set_kind("object")