(
state: &Arc<ServerState>,
request: Request<RevokeSshSessionRequest>,
)
| 1404 | } |
| 1405 | |
| 1406 | pub(super) async fn handle_revoke_ssh_session( |
| 1407 | state: &Arc<ServerState>, |
| 1408 | request: Request<RevokeSshSessionRequest>, |
| 1409 | ) -> Result<Response<RevokeSshSessionResponse>, Status> { |
| 1410 | let token = request.into_inner().token; |
| 1411 | if token.is_empty() { |
| 1412 | return Err(Status::invalid_argument("token is required")); |
| 1413 | } |
| 1414 | |
| 1415 | let session = state |
| 1416 | .store |
| 1417 | .get_message::<SshSession>(&token) |
| 1418 | .await |
| 1419 | .map_err(|e| Status::internal(format!("fetch ssh session failed: {e}")))?; |
| 1420 | |
| 1421 | let Some(mut session) = session else { |
| 1422 | return Ok(Response::new(RevokeSshSessionResponse { revoked: false })); |
| 1423 | }; |
| 1424 | |
| 1425 | let resource_version = session |
| 1426 | .metadata |
| 1427 | .as_ref() |
| 1428 | .map_or(0, |metadata| metadata.resource_version); |
| 1429 | |
| 1430 | session.revoked = true; |
| 1431 | |
| 1432 | // Use CAS to prevent lost updates from concurrent revocations |
| 1433 | state |
| 1434 | .store |
| 1435 | .put_if( |
| 1436 | SshSession::object_type(), |
| 1437 | session.object_id(), |
| 1438 | session.object_name(), |
| 1439 | &session.encode_to_vec(), |
| 1440 | None, |
| 1441 | WriteCondition::MatchResourceVersion(resource_version), |
| 1442 | ) |
| 1443 | .await |
| 1444 | .map_err(|e| super::persistence_error_to_status(e, "revoke ssh session"))?; |
| 1445 | |
| 1446 | Ok(Response::new(RevokeSshSessionResponse { revoked: true })) |
| 1447 | } |
| 1448 | |
| 1449 | // --------------------------------------------------------------------------- |
| 1450 | // Exec transport helpers |
no test coverage detected