Skip to content

Commit 65dc295

Browse files
committed
comment
1 parent 70a0bed commit 65dc295

3 files changed

Lines changed: 83 additions & 28 deletions

File tree

app/src/remote_server/server_model.rs

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,37 @@ impl PendingFileOps {
130130
}
131131
}
132132

133+
/// Client-supplied auth credentials and user identity for the daemon.
134+
///
135+
/// Populated by `Initialize` and `Authenticate` messages. The auth token
136+
/// is used for server API calls; the user identity is forwarded to Sentry
137+
/// so crash reports from the daemon are attributed to the connecting user.
138+
///
139+
/// All fields are intentionally retained across proxy connection teardown
140+
/// and cleared only by daemon process exit.
141+
struct DaemonAuthContext {
142+
/// Bearer credential set by Initialize / Authenticate.
143+
auth_token: Option<String>,
144+
/// User ID from the most recent `Initialize` handshake (Firebase UID).
145+
#[cfg(feature = "crash_reporting")]
146+
sentry_user_id: String,
147+
/// User email from the most recent `Initialize` handshake.
148+
#[cfg(feature = "crash_reporting")]
149+
sentry_user_email: String,
150+
}
151+
152+
impl DaemonAuthContext {
153+
fn new() -> Self {
154+
Self {
155+
auth_token: None,
156+
#[cfg(feature = "crash_reporting")]
157+
sentry_user_id: String::new(),
158+
#[cfg(feature = "crash_reporting")]
159+
sentry_user_email: String::new(),
160+
}
161+
}
162+
}
163+
133164
/// The top-level server-side orchestrator model.
134165
///
135166
/// Receives `ClientMessage`s from connected proxy sessions and routes
@@ -164,13 +195,8 @@ pub struct ServerModel {
164195
executors: HashMap<SessionId, Arc<LocalCommandExecutor>>,
165196
/// Tracks in-flight file write/delete operations and handles cleanup.
166197
pending_file_ops: PendingFileOps,
167-
/// Daemon-wide bearer credential for the identity-scoped daemon.
168-
///
169-
/// The token is written by Initialize when the client supplies a
170-
/// non-empty credential, or by Authenticate during token rotation. It is
171-
/// intentionally retained across proxy connection teardown and cleared
172-
/// only by daemon process exit.
173-
auth_token: Option<String>,
198+
/// Daemon-wide auth credentials and user identity.
199+
auth: DaemonAuthContext,
174200
}
175201

176202
impl Entity for ServerModel {
@@ -195,7 +221,7 @@ impl ServerModel {
195221
host_id,
196222
executors: HashMap::new(),
197223
pending_file_ops: PendingFileOps::new(),
198-
auth_token: None,
224+
auth: DaemonAuthContext::new(),
199225
};
200226
// Subscribe to FileModel and RepoMetadataModel events
201227
// file operation results and repo metadata pushes are forwarded to all
@@ -530,18 +556,15 @@ impl ServerModel {
530556
// Update crash reporting based on client-supplied preferences.
531557
#[cfg(feature = "crash_reporting")]
532558
{
559+
if !msg.user_id.is_empty() {
560+
self.auth.sentry_user_id = msg.user_id.clone();
561+
}
562+
if !msg.user_email.is_empty() {
563+
self.auth.sentry_user_email = msg.user_email.clone();
564+
}
565+
533566
if msg.crash_reporting_enabled {
534-
if !msg.user_id.is_empty() {
535-
crate::crash_reporting::set_user_id(
536-
crate::auth::UserUid::new(&msg.user_id),
537-
if msg.user_email.is_empty() {
538-
None
539-
} else {
540-
Some(msg.user_email)
541-
},
542-
ctx,
543-
);
544-
}
567+
self.apply_sentry_user_id(ctx);
545568
} else {
546569
crate::crash_reporting::uninit_sentry();
547570
}
@@ -562,7 +585,25 @@ impl ServerModel {
562585
/// Extracted so unit tests can call it without a `ModelContext`.
563586
fn apply_initialize_auth(&mut self, msg: &Initialize) {
564587
if !msg.auth_token.is_empty() {
565-
self.auth_token = Some(msg.auth_token.clone());
588+
self.auth.auth_token = Some(msg.auth_token.clone());
589+
}
590+
}
591+
592+
/// Sets the Sentry user identity from the stored `DaemonAuthContext`.
593+
/// Called both during `Initialize` and when re-enabling crash reporting
594+
/// via `UpdatePreferences`.
595+
#[cfg(feature = "crash_reporting")]
596+
fn apply_sentry_user_id(&self, ctx: &mut warpui::AppContext) {
597+
if !self.auth.sentry_user_id.is_empty() {
598+
crate::crash_reporting::set_user_id(
599+
crate::auth::UserUid::new(&self.auth.sentry_user_id),
600+
if self.auth.sentry_user_email.is_empty() {
601+
None
602+
} else {
603+
Some(self.auth.sentry_user_email.clone())
604+
},
605+
ctx,
606+
);
566607
}
567608
}
568609

@@ -580,10 +621,9 @@ impl ServerModel {
580621
#[cfg(feature = "crash_reporting")]
581622
{
582623
if msg.crash_reporting_enabled {
583-
// Re-enable if not already initialized. Use stored auth info.
584-
// If we don't have user info, init_sentry with no user is fine.
585624
if !crate::crash_reporting::is_initialized() {
586625
crate::crash_reporting::init(ctx);
626+
self.apply_sentry_user_id(ctx);
587627
}
588628
} else {
589629
crate::crash_reporting::uninit_sentry();
@@ -598,11 +638,11 @@ impl ServerModel {
598638
log::warn!("Received Authenticate notification with empty auth token; ignoring");
599639
return;
600640
}
601-
self.auth_token = Some(msg.auth_token);
641+
self.auth.auth_token = Some(msg.auth_token);
602642
}
603643

604644
pub fn auth_token(&self) -> Option<&str> {
605-
self.auth_token.as_deref()
645+
self.auth.auth_token.as_deref()
606646
}
607647

608648
/// Handles `Abort` by cancelling the in-progress request it targets.

app/src/remote_server/server_model_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::collections::HashMap;
22

33
use super::super::proto::{Authenticate, Initialize};
44
use super::super::protocol::RequestId;
5-
use super::{PendingFileOps, ServerModel};
5+
use super::{DaemonAuthContext, PendingFileOps, ServerModel};
66

77
fn test_model() -> ServerModel {
88
ServerModel {
@@ -13,7 +13,7 @@ fn test_model() -> ServerModel {
1313
host_id: "test-host-id".to_string(),
1414
executors: HashMap::new(),
1515
pending_file_ops: PendingFileOps::new(),
16-
auth_token: None,
16+
auth: DaemonAuthContext::new(),
1717
}
1818
}
1919

app/src/terminal/writeable_pty/remote_server_controller.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::terminal::warpify::settings::{SshExtensionInstallMode, WarpifySetting
1414
use crate::remote_server::manager::{RemoteServerManager, RemoteServerManagerEvent};
1515
use crate::remote_server::ssh_transport::SshTransport;
1616
use crate::server::server_api::ServerApiProvider;
17+
use crate::settings::{PrivacySettings, PrivacySettingsChangedEvent};
1718
use crate::terminal::model::session::{IsLegacySSHSession, SessionInfo};
1819
use crate::terminal::model_events::{ModelEvent, ModelEventDispatcher};
1920
use crate::{send_telemetry_from_ctx, TelemetryEvent};
@@ -94,15 +95,29 @@ impl<T: EventLoopSender> RemoteServerController<T> {
9495
) -> Self {
9596
let auth_state = AuthStateProvider::as_ref(ctx).get().clone();
9697
let crash_reporting_enabled = Arc::new(parking_lot::RwLock::new(
97-
crate::settings::PrivacySettings::handle(ctx)
98+
PrivacySettings::handle(ctx)
9899
.as_ref(ctx)
99100
.is_crash_reporting_enabled,
100101
));
101102
let auth_context = Arc::new(server_api_auth_context(
102103
auth_state,
103104
ServerApiProvider::as_ref(ctx).get_auth_client(),
104-
crash_reporting_enabled,
105+
crash_reporting_enabled.clone(),
105106
));
107+
108+
// Keep the shared crash-reporting flag in sync with the user's
109+
// privacy settings so that future daemon handshakes send the
110+
// current value rather than a stale snapshot.
111+
let privacy_settings = PrivacySettings::handle(ctx);
112+
ctx.subscribe_to_model(&privacy_settings, move |_, event, _| {
113+
if let &PrivacySettingsChangedEvent::UpdateIsCrashReportingEnabled {
114+
new_value, ..
115+
} = event
116+
{
117+
*crash_reporting_enabled.write() = new_value;
118+
}
119+
});
120+
106121
ctx.subscribe_to_model(&model_event_dispatcher, |me, event, ctx| {
107122
if let ModelEvent::SshInitShell {
108123
pending_session_info,

0 commit comments

Comments
 (0)