Harden release readiness gates
ci / test (push) Has been cancelled
ci / fuzz-smoke (push) Has been cancelled
ci / windows-client (push) Has been cancelled
ci / package-release (linux-x86_64, ubuntu-latest) (push) Has been cancelled
ci / package-release (macos-aarch64, macos-14) (push) Has been cancelled
ci / package-release (macos-x86_64, macos-13) (push) Has been cancelled
ci / package-release (windows-x86_64, windows-latest) (push) Has been cancelled
ci / remote-bench (push) Has been cancelled

This commit is contained in:
DuProcess
2026-06-22 17:14:59 -04:00
parent fb6cf4e7c2
commit f9a378a9cd
7 changed files with 231 additions and 206 deletions
+195 -183
View File
@@ -651,10 +651,10 @@ impl ServerState {
/// Remove a client from whichever session holds it, keeping the index in
/// sync. Returns true when a client was actually removed.
fn remove_client_everywhere(&mut self, client_id: &[u8; 16]) -> bool {
if let Some(session_name) = self.client_index.remove(client_id) {
if let Some(session) = self.sessions.get_mut(&session_name) {
return session.clients.remove(client_id).is_some();
}
if let Some(session_name) = self.client_index.remove(client_id)
&& let Some(session) = self.sessions.get_mut(&session_name)
{
return session.clients.remove(client_id).is_some();
}
false
}
@@ -987,9 +987,9 @@ async fn handle_native_user_auth(
let body = protocol::decrypt_body(packet, &pending.session_key, CLIENT_TO_SERVER)?;
let req: NativeUserAuthBody = protocol::from_body(&body)?;
if pending.client.requested_mode == "doctor" {
let check = {
let check_result = {
let locked = state.lock().expect("server state poisoned");
if let Err(err) = verify_native_user_auth_from_config(
verify_native_user_auth_from_config(
&locked.config,
&pending.client,
&pending.server,
@@ -997,16 +997,7 @@ async fn handle_native_user_auth(
Some(peer.ip()),
)
.context("verify native user auth")
{
return send_reject_to_client(
socket,
peer,
packet.header.conn_id,
&format!("{err:#}"),
)
.await;
}
NativeAuthCheckOkBody {
.map(|_| NativeAuthCheckOkBody {
requested_user: pending.client.requested_user.clone(),
native_auth_enabled: locked.config.native_auth,
allow_tcp_forwarding: locked.config.allow_tcp_forwarding,
@@ -1014,6 +1005,18 @@ async fn handle_native_user_auth(
allow_agent_forwarding: locked.config.allow_agent_forwarding,
policy_flags: Vec::new(),
server_version: env!("CARGO_PKG_VERSION").to_string(),
})
};
let check = match check_result {
Ok(check) => check,
Err(err) => {
return send_reject_to_client(
socket,
peer,
packet.header.conn_id,
&format!("{err:#}"),
)
.await;
}
};
let body = protocol::to_body(&check)?;
@@ -1065,17 +1068,19 @@ async fn handle_native_user_auth(
});
}
let attached: Result<(
[u8; 16],
[u8; 16],
Vec<u8>,
[u8; 32],
String,
String,
u64,
Vec<u8>,
Vec<ForwardingRequest>,
)> = {
struct NativeAttachResult {
client_id: [u8; 16],
key_id: [u8; 16],
attach_ticket: Vec<u8>,
attach_ticket_psk: [u8; 32],
session_name: String,
mode: String,
output_seq: u64,
snapshot: Vec<u8>,
requested_forwardings: Vec<ForwardingRequest>,
}
let attached: Result<NativeAttachResult> = {
let mut locked = state.lock().expect("server state poisoned");
verify_native_user_auth_from_config(
&locked.config,
@@ -1150,7 +1155,7 @@ async fn handle_native_user_auth(
previous_session_key: None,
},
);
Ok((
Ok(NativeAttachResult {
client_id,
key_id,
attach_ticket,
@@ -1159,22 +1164,12 @@ async fn handle_native_user_auth(
mode,
output_seq,
snapshot,
req.auth.requested_forwardings.clone(),
))
requested_forwardings: req.auth.requested_forwardings.clone(),
})
})
};
let (
client_id,
key_id,
attach_ticket,
attach_ticket_psk,
session_name,
mode,
output_seq,
snapshot,
requested_forwardings,
) = match attached {
let attached = match attached {
Ok(attached) => attached,
Err(err) => {
// Auth/session setup failed: clean up the agent socket we bound early.
@@ -1185,11 +1180,12 @@ async fn handle_native_user_auth(
.await;
}
};
let client_id = attached.client_id;
if let Err(err) = start_remote_forwards(
state,
socket,
client_id,
requested_forwardings.clone(),
attached.requested_forwardings.clone(),
pending.client.requested_session.clone(),
)
.await
@@ -1207,14 +1203,14 @@ async fn handle_native_user_auth(
let ok = NativeAuthOk {
client_id,
session: session_name,
mode,
session: attached.session_name,
mode: attached.mode,
session_key: pending.session_key,
session_key_id: key_id,
attach_ticket,
attach_ticket_psk,
initial_seq: output_seq,
snapshot,
session_key_id: attached.key_id,
attach_ticket: attached.attach_ticket,
attach_ticket_psk: attached.attach_ticket_psk,
initial_seq: attached.output_seq,
snapshot: attached.snapshot,
policy_flags: Vec::new(),
};
let body = protocol::to_body(&NativeAuthOkBody { ok })?;
@@ -1238,78 +1234,84 @@ async fn handle_bootstrap_attach(
body: Vec<u8>,
) -> Result<()> {
let req: BootstrapAttachRequest = protocol::from_body(&body)?;
let (client_id, key, key_id, session_name, mode, output_seq, snapshot) = {
type BootstrapAttachResult = ([u8; 16], [u8; 32], [u8; 16], String, String, u64, Vec<u8>);
let attached: Result<BootstrapAttachResult> = {
let mut locked = state.lock().expect("server state poisoned");
if !verify_bootstrap(&req.bootstrap, &locked.secret)? {
return send_reject(socket, peer, "invalid or expired bootstrap").await;
}
if !locked.sessions.contains_key(&req.bootstrap.session) && !locked.config.create_on_attach
Err(anyhow!("invalid or expired bootstrap"))
} else if !locked.sessions.contains_key(&req.bootstrap.session)
&& !locked.config.create_on_attach
{
return send_reject(socket, peer, "session does not exist").await;
}
locked.ensure_session(
&req.bootstrap.session,
req.cols,
req.rows,
&req.bootstrap.mode,
&req.requested_env,
)?;
let session = locked
.sessions
.get_mut(&req.bootstrap.session)
.expect("session exists");
if mode_allows_terminal_updates(&req.bootstrap.mode) {
apply_terminal_size(
session.pty.as_ref(),
&mut session.parser,
Err(anyhow!("session does not exist"))
} else {
locked.ensure_session(
&req.bootstrap.session,
req.cols,
req.rows,
&req.bootstrap.mode,
&req.requested_env,
)?;
let session = locked
.sessions
.get_mut(&req.bootstrap.session)
.expect("session exists");
if mode_allows_terminal_updates(&req.bootstrap.mode) {
apply_terminal_size(
session.pty.as_ref(),
&mut session.parser,
req.cols,
req.rows,
)?;
}
let client_id = crypto::random_16();
let snapshot = screen_snapshot(session.parser.screen());
let output_seq = session.output_seq;
let bootstrap_session = req.bootstrap.session.clone();
locked.insert_client(
&bootstrap_session,
client_id,
ClientState {
endpoint: peer,
mode: req.bootstrap.mode.clone(),
session_key: req.bootstrap.session_key,
last_acked: output_seq,
replay: ReplayWindow::default(),
send_seq: 1,
cols: req.cols,
rows: req.rows,
last_seen: Instant::now(),
pending: VecDeque::new(),
last_frame_sent: Instant::now() - Duration::from_secs(3600),
paced_snapshot_due: false,
allowed_forwardings: Vec::new(),
stream_writers: HashMap::new(),
opened_streams: HashSet::new(),
stream_send_credit: HashMap::new(),
stream_pending_data: HashMap::new(),
stream_next_send_offset: HashMap::new(),
stream_sent_data: HashMap::new(),
stream_next_recv_offset: HashMap::new(),
stream_recv_pending: HashMap::new(),
epoch: 0,
epoch_started: Instant::now(),
epoch_packets: 0,
previous_session_key: None,
},
);
Ok((
client_id,
req.bootstrap.session_key,
req.bootstrap.session_key_id,
req.bootstrap.session.clone(),
req.bootstrap.mode.clone(),
output_seq,
snapshot,
))
}
let client_id = crypto::random_16();
let snapshot = screen_snapshot(session.parser.screen());
let output_seq = session.output_seq;
let bootstrap_session = req.bootstrap.session.clone();
locked.insert_client(
&bootstrap_session,
client_id,
ClientState {
endpoint: peer,
mode: req.bootstrap.mode.clone(),
session_key: req.bootstrap.session_key,
last_acked: output_seq,
replay: ReplayWindow::default(),
send_seq: 1,
cols: req.cols,
rows: req.rows,
last_seen: Instant::now(),
pending: VecDeque::new(),
last_frame_sent: Instant::now() - Duration::from_secs(3600),
paced_snapshot_due: false,
allowed_forwardings: Vec::new(),
stream_writers: HashMap::new(),
opened_streams: HashSet::new(),
stream_send_credit: HashMap::new(),
stream_pending_data: HashMap::new(),
stream_next_send_offset: HashMap::new(),
stream_sent_data: HashMap::new(),
stream_next_recv_offset: HashMap::new(),
stream_recv_pending: HashMap::new(),
epoch: 0,
epoch_started: Instant::now(),
epoch_packets: 0,
previous_session_key: None,
},
);
(
client_id,
req.bootstrap.session_key,
req.bootstrap.session_key_id,
req.bootstrap.session.clone(),
req.bootstrap.mode.clone(),
output_seq,
snapshot,
)
};
let (client_id, key, key_id, session_name, mode, output_seq, snapshot) = match attached {
Ok(attached) => attached,
Err(err) => return send_reject(socket, peer, &err.to_string()).await,
};
let ok = AttachOk {
client_id,
@@ -1341,24 +1343,29 @@ async fn handle_ticket_attach(
body: Vec<u8>,
) -> Result<()> {
let env: TicketAttachEnvelope = protocol::from_body(&body)?;
let (ticket, request_plain) = {
let opened = {
let locked = state.lock().expect("server state poisoned");
if !locked.config.allow_attach_tickets {
return send_reject(socket, peer, "attach tickets disabled").await;
Err(anyhow!("attach tickets disabled"))
} else {
let ticket = open_attach_ticket(&locked.secret, &env.ticket)?;
let request_key = crypto::hkdf32(
&ticket.psk,
&env.client_nonce,
b"dosh/ticket-attach-request/v1",
)?;
let request_plain = crypto::open(
&request_key,
&env.client_nonce,
b"dosh-ticket-attach-request-v1",
&env.ciphertext,
)?;
Ok((ticket, request_plain))
}
let ticket = open_attach_ticket(&locked.secret, &env.ticket)?;
let request_key = crypto::hkdf32(
&ticket.psk,
&env.client_nonce,
b"dosh/ticket-attach-request/v1",
)?;
let request_plain = crypto::open(
&request_key,
&env.client_nonce,
b"dosh-ticket-attach-request-v1",
&env.ciphertext,
)?;
(ticket, request_plain)
};
let (ticket, request_plain) = match opened {
Ok(opened) => opened,
Err(err) => return send_reject(socket, peer, &err.to_string()).await,
};
let req: TicketAttachBody = protocol::from_body(&request_plain)?;
if req.session != ticket.session || req.mode != ticket.mode {
@@ -1367,66 +1374,71 @@ async fn handle_ticket_attach(
let session_key = crypto::random_32();
let session_key_id = protocol::session_key_id(&session_key);
let (client_id, output_seq, snapshot) = {
let attached = {
let mut locked = state.lock().expect("server state poisoned");
if !locked.sessions.contains_key(&req.session) && !locked.config.create_on_attach {
return send_reject(socket, peer, "session does not exist").await;
}
locked.ensure_session(
&req.session,
req.cols,
req.rows,
&req.mode,
&req.requested_env,
)?;
let session = locked
.sessions
.get_mut(&req.session)
.expect("session exists");
if mode_allows_terminal_updates(&req.mode) {
apply_terminal_size(
session.pty.as_ref(),
&mut session.parser,
Err(anyhow!("session does not exist"))
} else {
locked.ensure_session(
&req.session,
req.cols,
req.rows,
&req.mode,
&req.requested_env,
)?;
let session = locked
.sessions
.get_mut(&req.session)
.expect("session exists");
if mode_allows_terminal_updates(&req.mode) {
apply_terminal_size(
session.pty.as_ref(),
&mut session.parser,
req.cols,
req.rows,
)?;
}
let client_id = crypto::random_16();
let snapshot = screen_snapshot(session.parser.screen());
let output_seq = session.output_seq;
let ticket_session = req.session.clone();
locked.insert_client(
&ticket_session,
client_id,
ClientState {
endpoint: peer,
mode: req.mode.clone(),
session_key,
last_acked: output_seq,
replay: ReplayWindow::default(),
send_seq: 1,
cols: req.cols,
rows: req.rows,
last_seen: Instant::now(),
pending: VecDeque::new(),
last_frame_sent: Instant::now() - Duration::from_secs(3600),
paced_snapshot_due: false,
allowed_forwardings: Vec::new(),
stream_writers: HashMap::new(),
opened_streams: HashSet::new(),
stream_send_credit: HashMap::new(),
stream_pending_data: HashMap::new(),
stream_next_send_offset: HashMap::new(),
stream_sent_data: HashMap::new(),
stream_next_recv_offset: HashMap::new(),
stream_recv_pending: HashMap::new(),
epoch: 0,
epoch_started: Instant::now(),
epoch_packets: 0,
previous_session_key: None,
},
);
Ok((client_id, output_seq, snapshot))
}
let client_id = crypto::random_16();
let snapshot = screen_snapshot(session.parser.screen());
let output_seq = session.output_seq;
let ticket_session = req.session.clone();
locked.insert_client(
&ticket_session,
client_id,
ClientState {
endpoint: peer,
mode: req.mode.clone(),
session_key,
last_acked: output_seq,
replay: ReplayWindow::default(),
send_seq: 1,
cols: req.cols,
rows: req.rows,
last_seen: Instant::now(),
pending: VecDeque::new(),
last_frame_sent: Instant::now() - Duration::from_secs(3600),
paced_snapshot_due: false,
allowed_forwardings: Vec::new(),
stream_writers: HashMap::new(),
opened_streams: HashSet::new(),
stream_send_credit: HashMap::new(),
stream_pending_data: HashMap::new(),
stream_next_send_offset: HashMap::new(),
stream_sent_data: HashMap::new(),
stream_next_recv_offset: HashMap::new(),
stream_recv_pending: HashMap::new(),
epoch: 0,
epoch_started: Instant::now(),
epoch_packets: 0,
previous_session_key: None,
},
);
(client_id, output_seq, snapshot)
};
let (client_id, output_seq, snapshot) = match attached {
Ok(attached) => attached,
Err(err) => return send_reject(socket, peer, &err.to_string()).await,
};
let ok = AttachOk {