@@ -400,9 +400,16 @@ pub async fn upgrade_to_smb_volume(volume_id: String) -> Result<String, String>
400400 info. username
401401 ) ;
402402
403- // Try to get credentials from Keychain (using the username/server from the mount).
404- // If that fails, try guest access.
405- let creds = get_keychain_password ( & info. server , & info. share ) . await ;
403+ // Try to get credentials from Keychain. The mount source has the IP, but Cmdr
404+ // stores Keychain credentials keyed by hostname (from mDNS). Try both.
405+ let hostname = resolve_ip_to_hostname ( & info. server ) ;
406+ let creds = get_keychain_password ( & info. server , hostname. as_deref ( ) , & info. share ) . await ;
407+
408+ match & creds {
409+ Some ( ( u, _) ) => log:: info!( "Found Keychain credentials for user={}" , u) ,
410+ None => log:: info!( "No Keychain credentials found, trying guest access" ) ,
411+ }
412+
406413 let ( username, password) = match & creds {
407414 Some ( ( u, p) ) => ( Some ( u. as_str ( ) ) , Some ( p. as_str ( ) ) ) ,
408415 None => ( None , None ) ,
@@ -422,30 +429,62 @@ pub async fn upgrade_to_smb_volume(volume_id: String) -> Result<String, String>
422429 ) )
423430}
424431
432+ /// Looks up the mDNS hostname for an IP address from discovered hosts.
433+ ///
434+ /// Returns the hostname (like "naspolya") without `.local` suffix.
435+ fn resolve_ip_to_hostname ( ip : & str ) -> Option < String > {
436+ let hosts = get_discovered_hosts ( ) ;
437+ for host in & hosts {
438+ if host. ip_address . as_deref ( ) == Some ( ip) {
439+ // Return the service name (lowercased), which is what Keychain keys use
440+ return Some ( host. name . to_lowercase ( ) ) ;
441+ }
442+ }
443+ None
444+ }
445+
425446/// Tries to retrieve SMB credentials from the Keychain.
426447///
427- /// Checks share-level first (more specific), then server-level.
428- async fn get_keychain_password ( server : & str , share : & str ) -> Option < ( String , String ) > {
429- let server = server. to_string ( ) ;
448+ /// Tries multiple keys: by IP (from statfs), by hostname (from mDNS discovery),
449+ /// at both share-level and server-level.
450+ async fn get_keychain_password (
451+ server_ip : & str ,
452+ hostname : Option < & str > ,
453+ share : & str ,
454+ ) -> Option < ( String , String ) > {
455+ let server_ip = server_ip. to_string ( ) ;
456+ let hostname = hostname. map ( |s| s. to_string ( ) ) ;
430457 let share = share. to_string ( ) ;
431458
432- // Keychain access can block, so run in a blocking task
433459 tokio:: task:: spawn_blocking ( move || {
434460 use crate :: network:: keychain;
435461
436- // Try share-level credentials first (more specific )
437- if let Ok ( creds ) = keychain :: get_credentials ( & server , Some ( & share ) ) {
438- log :: debug! ( "Found Keychain credentials for {}/{}" , server , share ) ;
439- return Some ( ( creds . username , creds . password ) ) ;
462+ // Build a list of server names to try (hostname first, then IP )
463+ let mut servers_to_try : Vec < & str > = Vec :: new ( ) ;
464+ if let Some ( ref h ) = hostname {
465+ servers_to_try . push ( h ) ;
440466 }
441-
442- // Try server-level credentials
443- if let Ok ( creds) = keychain:: get_credentials ( & server, None ) {
444- log:: debug!( "Found Keychain credentials for {} (server-level)" , server) ;
445- return Some ( ( creds. username , creds. password ) ) ;
467+ servers_to_try. push ( & server_ip) ;
468+
469+ for server in & servers_to_try {
470+ // Try share-level credentials first (more specific)
471+ if let Ok ( creds) = keychain:: get_credentials ( server, Some ( & share) ) {
472+ log:: debug!( "Found Keychain credentials via {}/{}" , server, share) ;
473+ return Some ( ( creds. username , creds. password ) ) ;
474+ }
475+ // Try server-level credentials
476+ if let Ok ( creds) = keychain:: get_credentials ( server, None ) {
477+ log:: debug!( "Found Keychain credentials via {} (server-level)" , server) ;
478+ return Some ( ( creds. username , creds. password ) ) ;
479+ }
446480 }
447481
448- log:: debug!( "No Keychain credentials for {}/{}" , server, share) ;
482+ log:: debug!(
483+ "No Keychain credentials for {:?} / {} / {}" ,
484+ hostname,
485+ server_ip,
486+ share
487+ ) ;
449488 None
450489 } )
451490 . await
0 commit comments