mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-12 03:28:20 +08:00
[feat] unify Windows unattended hosting and device identity
This commit is contained in:
1 parent
930ccd9ea1
commit
4e2532f33c
67 files changed
+3491
-941
No files matched your search
@@ -3,6 +3,7 @@
|
||||
#include <SDL3/SDL_audio.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_init.h>
|
||||
#include <SDL3/SDL_timer.h>
|
||||
|
||||
#include <display_stream_id.h>
|
||||
#include <remote_action.h>
|
||||
@@ -50,7 +51,7 @@ SessionDeviceManager::SessionDeviceManager(GuiRuntime &owner)
|
||||
owner_.WithController(
|
||||
id, [&](MiniRtcPeerPtr* peer, const std::string& wire) {
|
||||
frame.captured_timestamp = MiniRtcGetSystemTimeMicros(peer);
|
||||
return MiniRtcSendAudioFrameToPeer(peer, &frame,
|
||||
return PeerSendAudioFrameToPeer(peer, &frame,
|
||||
owner_.audio_label_.c_str(),
|
||||
wire.data(), wire.size());
|
||||
});
|
||||
@@ -58,6 +59,19 @@ SessionDeviceManager::SessionDeviceManager(GuiRuntime &owner)
|
||||
|
||||
SessionDeviceManager::~SessionDeviceManager() { speaker_capture_.Shutdown(); }
|
||||
|
||||
#ifdef _WIN32
|
||||
bool SessionDeviceManager::OwnsNativeCursor() const {
|
||||
const auto* windows = dynamic_cast<ScreenCapturerWin*>(screen_capturer_);
|
||||
return windows && windows->OwnsNativeCursor();
|
||||
}
|
||||
void SessionDeviceManager::SetNativeCursorPolicy(bool default_enabled, bool current_enabled) {
|
||||
owner_.host_cursor_default_ = default_enabled;
|
||||
owner_.host_cursor_preference_ = current_enabled;
|
||||
if (auto* windows = dynamic_cast<ScreenCapturerWin*>(screen_capturer_))
|
||||
windows->SetNativeCursorPolicy(default_enabled, current_enabled);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool SessionDeviceManager::ShouldSendCapturedFrame(
|
||||
std::chrono::steady_clock::time_point now, int fps) {
|
||||
const auto interval =
|
||||
@@ -148,7 +162,8 @@ int SessionDeviceManager::InitializeScreenCapturer() {
|
||||
screen_capturer_->SetPrivacyController(&owner_.privacy_);
|
||||
#ifdef _WIN32
|
||||
if (auto windows = dynamic_cast<ScreenCapturerWin*>(screen_capturer_)) {
|
||||
windows->SetCaptureMethod(owner_.config_center_->GetScreenCaptureMethod());
|
||||
windows->SetUnattendedHost(owner_.unattended_host_);
|
||||
windows->SetNativeCursorPolicy(owner_.host_cursor_default_, owner_.host_cursor_preference_);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -176,6 +191,7 @@ int SessionDeviceManager::InitializeScreenCapturer() {
|
||||
const auto now_time = std::chrono::steady_clock::now();
|
||||
bool from_secure_desktop = false;
|
||||
#ifdef _WIN32
|
||||
owner_.host_capture_tick_ = SDL_GetTicks();
|
||||
from_secure_desktop =
|
||||
ScreenCapturerWin::CurrentFrameIsFromSecureDesktop();
|
||||
#endif
|
||||
@@ -236,6 +252,7 @@ int SessionDeviceManager::InitializeScreenCapturer() {
|
||||
const auto send_started = std::chrono::steady_clock::now();
|
||||
uint64_t send_errors = 0;
|
||||
for (const std::string &remote_id : connected_remote_ids) {
|
||||
if (owner_.managed_host_frontend_ && remote_id.rfind("lan/", 0) != 0) continue;
|
||||
if (!owner_.preview_subscriptions_.ShouldSend(remote_id, now_time,
|
||||
stream_id)) continue;
|
||||
if (owner_.WithController(
|
||||
@@ -243,7 +260,7 @@ int SessionDeviceManager::InitializeScreenCapturer() {
|
||||
if (resumed_after_gap || stream_changed)
|
||||
MiniRtcRequestVideoKeyFrame(peer, stream_id.c_str());
|
||||
frame.captured_timestamp = MiniRtcGetSystemTimeMicros(peer);
|
||||
return MiniRtcSendVideoFrameToPeer(peer, &frame, stream_id.c_str(),
|
||||
return PeerSendVideoFrameToPeer(peer, &frame, stream_id.c_str(),
|
||||
wire.data(), wire.size());
|
||||
}) != 0)
|
||||
++send_errors;
|
||||
@@ -702,14 +719,20 @@ void SessionDeviceManager::UpdateInteractions() {
|
||||
#endif
|
||||
|
||||
if (owner_.start_screen_capturer_ && !owner_.screen_capturer_is_started_) {
|
||||
if (StartScreenCapturer() == 0) {
|
||||
owner_.screen_capturer_is_started_ = true;
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if (now >= next_capture_start_retry_) {
|
||||
next_capture_start_retry_ = now + std::chrono::seconds(1);
|
||||
if (StartScreenCapturer() == 0) {
|
||||
owner_.screen_capturer_is_started_ = true;
|
||||
next_capture_start_retry_ = {};
|
||||
}
|
||||
}
|
||||
} else if (!owner_.start_screen_capturer_ &&
|
||||
owner_.screen_capturer_is_started_) {
|
||||
StopScreenCapturer();
|
||||
owner_.screen_capturer_is_started_ = false;
|
||||
}
|
||||
if (!owner_.start_screen_capturer_) next_capture_start_retry_ = {};
|
||||
|
||||
UpdateScreenSharingPower();
|
||||
|
||||
|
||||
@@ -66,6 +66,8 @@ public:
|
||||
return remote_mouse_buttons_.Apply(remote_id, flag, std::move(send));
|
||||
}
|
||||
#ifdef _WIN32
|
||||
bool OwnsNativeCursor() const;
|
||||
void SetNativeCursorPolicy(bool default_enabled, bool current_enabled);
|
||||
std::string SendServiceMouseCommand(int x, int y, int wheel, int flag);
|
||||
#endif
|
||||
// Requests are asynchronous; Stop drains/revokes audio delivery before
|
||||
@@ -145,6 +147,7 @@ private:
|
||||
#endif
|
||||
std::chrono::steady_clock::time_point last_frame_time_{};
|
||||
std::chrono::steady_clock::time_point next_frame_deadline_{};
|
||||
std::chrono::steady_clock::time_point next_capture_start_retry_{};
|
||||
std::mutex capture_metrics_mutex_;
|
||||
std::chrono::steady_clock::time_point capture_metrics_started_{};
|
||||
std::chrono::steady_clock::time_point last_capture_callback_{};
|
||||
|
||||
@@ -126,7 +126,7 @@ void FileTransferManager::ProcessQueue(std::shared_ptr<RemoteSession> props) {
|
||||
auto callback = events->EnterCallback();
|
||||
if (!callback || !events->DataAllowed()) return -1;
|
||||
const auto wire_id = events->WireId(file.remote_id);
|
||||
return MiniRtcSendReliableDataFrameToPeer(
|
||||
return PeerSendReliableDataFrameToPeer(
|
||||
peer, data, size, file.file_label.c_str(),
|
||||
wire_id.data(), wire_id.size());
|
||||
}, file_transfer::Session::Progress{});
|
||||
@@ -176,7 +176,7 @@ void FileTransferManager::ProcessQueue(std::shared_ptr<RemoteSession> props) {
|
||||
// Release that reservation even though no data chunk was ever sent.
|
||||
const auto packet = EncodeFileCancel(id, 0);
|
||||
const auto wire_id = events->WireId(file.remote_id);
|
||||
MiniRtcSendReliableDataFrameToPeer(peer, packet.data(), packet.size(),
|
||||
PeerSendReliableDataFrameToPeer(peer, packet.data(), packet.size(),
|
||||
file.file_label.c_str(), wire_id.data(), wire_id.size());
|
||||
}
|
||||
}
|
||||
@@ -382,7 +382,7 @@ std::shared_ptr<FileReceiver> FileTransferManager::ReceiverFor(
|
||||
if (!callback || !events->DataAllowed()) return -1;
|
||||
const auto bytes = EncodeFileTransferAck(ack);
|
||||
const auto wire_id = events->WireId(remote);
|
||||
return MiniRtcSendReliableDataFrameToPeer(
|
||||
return PeerSendReliableDataFrameToPeer(
|
||||
peer, bytes.data(), bytes.size(), kFileFeedbackStream,
|
||||
wire_id.data(), wire_id.size());
|
||||
});
|
||||
@@ -533,7 +533,7 @@ bool FileTransferManager::SendBrowser(const std::string& remote, const FileBrows
|
||||
const auto data = message.dump(-1, ' ', false, FileBrowser::Json::error_handler_t::replace);
|
||||
if (!peer || data.size() > 60000) return false;
|
||||
const auto wire_id = events->WireId(remote);
|
||||
return MiniRtcSendReliableDataFrameToPeer(peer, data.data(), data.size(),
|
||||
return PeerSendReliableDataFrameToPeer(peer, data.data(), data.size(),
|
||||
owner_.control_data_label_.c_str(), wire_id.data(), wire_id.size()) == 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,6 @@
|
||||
namespace crossdesk {
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t kCacheV3Magic = 0x33444358; // "XCD3"
|
||||
constexpr uint32_t kCacheV3Version = 3;
|
||||
|
||||
#if defined(__linux__) && !defined(__OHOS__)
|
||||
constexpr const char *kCredentialCacheNames[] = {
|
||||
"secure_cache_v3.enc", "secure_cache_v2.enc", "secure_cache.enc"};
|
||||
@@ -132,16 +129,6 @@ void CopyString(char (&destination)[Size], const char *source) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t CacheChecksum(const void *data, size_t size) {
|
||||
const auto *bytes = static_cast<const unsigned char *>(data);
|
||||
uint32_t hash = 2166136261u;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
hash ^= bytes[i];
|
||||
hash *= 16777619u;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::filesystem::path TemporaryPathFor(
|
||||
const std::filesystem::path &target) {
|
||||
const auto timestamp = std::chrono::steady_clock::now()
|
||||
@@ -259,6 +246,15 @@ bool WriteFileAtomically(const std::filesystem::path &target,
|
||||
|
||||
SettingsManager::SettingsManager(GuiRuntime &owner) : owner_(owner) {}
|
||||
|
||||
bool SettingsManager::ApplyHostIdentity(const std::string& identity, bool self_hosted) {
|
||||
if (identity.size() != 16 || identity[9] != '@' ||
|
||||
identity.substr(0, 9).find_first_not_of("0123456789") != std::string::npos)
|
||||
return false;
|
||||
std::lock_guard lock(cache_mutex_);
|
||||
ActivateIdentity(identity.c_str(), self_hosted);
|
||||
return SaveLocked() == 0;
|
||||
}
|
||||
|
||||
int SettingsManager::Save() {
|
||||
std::lock_guard<std::mutex> lock(cache_mutex_);
|
||||
return SaveLocked();
|
||||
@@ -271,8 +267,8 @@ int SettingsManager::SaveLocked() {
|
||||
std::memcpy(cache_v2_.iv, owner_.aes128_iv_, sizeof(owner_.aes128_iv_));
|
||||
CopyString(cache_v2_.self_hosted_id, owner_.self_hosted_id_);
|
||||
|
||||
cache_v3_.magic = kCacheV3Magic;
|
||||
cache_v3_.version = kCacheV3Version;
|
||||
cache_v3_.magic = credential_cache::kMagic;
|
||||
cache_v3_.version = credential_cache::kVersion;
|
||||
cache_v3_.base = cache_v2_;
|
||||
cache_v3_.pending_identity[sizeof(cache_v3_.pending_identity) - 1] = '\0';
|
||||
cache_v3_.pending_server_host[sizeof(cache_v3_.pending_server_host) - 1] =
|
||||
@@ -280,7 +276,7 @@ int SettingsManager::SaveLocked() {
|
||||
cache_v3_.pending_request_id[sizeof(cache_v3_.pending_request_id) - 1] =
|
||||
'\0';
|
||||
cache_v3_.checksum =
|
||||
CacheChecksum(&cache_v3_, offsetof(CacheV3, checksum));
|
||||
credential_cache::Checksum(&cache_v3_, offsetof(CacheV3, checksum));
|
||||
|
||||
if (!WriteFileAtomically(owner_.cache_path_ + "/secure_cache_v3.enc",
|
||||
&cache_v3_, sizeof(cache_v3_))) {
|
||||
@@ -302,7 +298,7 @@ int SettingsManager::SaveLocked() {
|
||||
LOG_WARN("Failed to update legacy v1 credential cache");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return owner_.PublishSharedIdentity() ? 0 : -1;
|
||||
}
|
||||
|
||||
bool SettingsManager::ReadV3Locked() {
|
||||
@@ -325,9 +321,7 @@ bool SettingsManager::ReadV3Locked() {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (loaded.magic != kCacheV3Magic ||
|
||||
loaded.version != kCacheV3Version ||
|
||||
loaded.checksum != CacheChecksum(&loaded, offsetof(CacheV3, checksum))) {
|
||||
if (!credential_cache::Valid(loaded)) {
|
||||
LOG_WARN("Ignore invalid v3 credential cache");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#include "thumbnail.h"
|
||||
#include "common/credential_cache.h"
|
||||
|
||||
namespace crossdesk {
|
||||
|
||||
@@ -21,6 +22,7 @@ public:
|
||||
int Save();
|
||||
int Load();
|
||||
std::string ActiveIdentity() const;
|
||||
bool ApplyHostIdentity(const std::string& identity, bool self_hosted);
|
||||
|
||||
int LoadRecentConnectionAliases();
|
||||
int SaveRecentConnectionAliases() const;
|
||||
@@ -56,46 +58,9 @@ public:
|
||||
bool ClearPendingPasswordChange();
|
||||
|
||||
private:
|
||||
struct CacheV1 {
|
||||
char client_id_with_password[17];
|
||||
int language;
|
||||
// Reserved legacy slots: retain the on-disk cache layout.
|
||||
int legacy_video_quality;
|
||||
int legacy_video_frame_rate;
|
||||
int video_encode_format;
|
||||
bool legacy_enable_hardware_video_codec;
|
||||
bool enable_turn;
|
||||
bool enable_srtp;
|
||||
unsigned char key[16];
|
||||
unsigned char iv[16];
|
||||
};
|
||||
|
||||
struct CacheV2 {
|
||||
char client_id_with_password[17];
|
||||
int language;
|
||||
// Reserved legacy slots: retain the on-disk cache layout.
|
||||
int legacy_video_quality;
|
||||
int legacy_video_frame_rate;
|
||||
int video_encode_format;
|
||||
bool legacy_enable_hardware_video_codec;
|
||||
bool enable_turn;
|
||||
bool enable_srtp;
|
||||
unsigned char key[16];
|
||||
unsigned char iv[16];
|
||||
char self_hosted_id[17];
|
||||
};
|
||||
|
||||
struct CacheV3 {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
CacheV2 base;
|
||||
char pending_identity[17];
|
||||
char pending_server_host[256];
|
||||
int pending_server_port;
|
||||
bool pending_self_hosted;
|
||||
char pending_request_id[64];
|
||||
uint32_t checksum;
|
||||
};
|
||||
using CacheV1 = credential_cache::CacheV1;
|
||||
using CacheV2 = credential_cache::CacheV2;
|
||||
using CacheV3 = credential_cache::CacheV3;
|
||||
|
||||
int SaveLocked();
|
||||
bool ReadV3Locked();
|
||||
|
||||
Reference in new issue
Block a user