fix: harden OpenSim session readiness
Some checks failed
CI / rust-skia (Rust only) (push) Has been cancelled
CI / required (push) Has been cancelled

This commit is contained in:
2026-08-21 20:37:16 +02:00
parent db25a977b7
commit adf5165033
14 changed files with 503 additions and 67 deletions

View File

@@ -929,35 +929,43 @@ impl crate::session::GridSessionBackend for LibremetaverseSessionBackend {
.delivery_generation
.write()
.unwrap_or_else(std::sync::PoisonError::into_inner) = None;
let mut params = self
.network
.native_default_login_params(
self.first_name.clone(),
self.last_name.clone(),
self.password.expose_secret().to_owned(),
"MetaCrate".to_owned(),
env!("CARGO_PKG_VERSION").to_owned(),
)
.map_err(|_| {
crate::session::SessionFailure::new(
crate::session::SessionFailureKind::InvalidConfiguration,
let mut start = "last";
loop {
let mut params = self
.network
.native_default_login_params(
self.first_name.clone(),
self.last_name.clone(),
self.password.expose_secret().to_owned(),
"MetaCrate".to_owned(),
env!("CARGO_PKG_VERSION").to_owned(),
)
})?;
params.uri.clone_from(&self.login_url);
"last".clone_into(&mut params.start);
let logged_in = self
.network
.native_login(params, Some(cancellation))
.await
.map_err(|_| {
crate::session::SessionFailure::new(
crate::session::SessionFailureKind::TransientTransport,
)
})?;
if !logged_in {
return Err(classify_native_login_failure(
&self.network.native_login_error_key(),
));
.map_err(|_| {
crate::session::SessionFailure::new(
crate::session::SessionFailureKind::InvalidConfiguration,
)
})?;
params.uri.clone_from(&self.login_url);
start.clone_into(&mut params.start);
let logged_in = self
.network
.native_login(params, Some(cancellation.clone()))
.await
.map_err(|_| {
crate::session::SessionFailure::new(
crate::session::SessionFailureKind::TransientTransport,
)
})?;
if logged_in {
break;
}
let error_key = self.network.native_login_error_key();
let message = self.network.native_login_message();
if start == "last" && native_last_location_unavailable(&message) {
start = "home";
continue;
}
return Err(classify_native_login_failure(&error_key, &message));
}
// Native login has already installed the current simulator and
@@ -1252,9 +1260,16 @@ fn native_delivery_id(prefix: &str, fields: &[&str]) -> String {
}
#[cfg(feature = "live-grid")]
fn classify_native_login_failure(error_key: &str) -> crate::session::SessionFailure {
fn classify_native_login_failure(error_key: &str, message: &str) -> crate::session::SessionFailure {
let normalized = error_key.trim().to_ascii_lowercase();
let kind = if matches!(
let kind = if native_last_location_unavailable(message)
|| message
.trim()
.to_ascii_lowercase()
.contains("already logged in")
{
crate::session::SessionFailureKind::ServerFailure
} else if matches!(
normalized.as_str(),
"key" | "password" | "credential" | "account" | "username" | "user"
) {
@@ -1267,6 +1282,13 @@ fn classify_native_login_failure(error_key: &str) -> crate::session::SessionFail
crate::session::SessionFailure::new(kind)
}
#[cfg(feature = "live-grid")]
fn native_last_location_unavailable(message: &str) -> bool {
let message = message.trim().to_ascii_lowercase();
message.contains("failed to verify user presence")
|| message.contains("access denied to region")
}
impl GridBackend for OfflineGridBackend {
fn name(&self) -> &'static str {
"offline-fake"
@@ -1315,4 +1337,24 @@ mod tests {
cancellation.cancel();
run.await.expect("clean cancellation");
}
#[cfg(feature = "live-grid")]
#[test]
fn stale_presence_is_retryable_without_masking_bad_credentials() {
assert!(native_last_location_unavailable(
"Failed to verify user presence in the grid, access denied to region",
));
assert_eq!(
classify_native_login_failure(
"account",
"Failed to verify user presence in the grid, access denied to region",
)
.kind(),
crate::session::SessionFailureKind::ServerFailure,
);
assert_eq!(
classify_native_login_failure("account", "Invalid credentials").kind(),
crate::session::SessionFailureKind::InvalidCredentials,
);
}
}