@@ -413,15 +413,18 @@ impl Args {
413413 #[ cfg( unix) ]
414414 {
415415 use std:: io:: Write as _;
416- use std:: os:: unix:: fs:: OpenOptionsExt ;
416+ use std:: os:: unix:: fs:: { OpenOptionsExt , PermissionsExt } ;
417417 let mut to_file = OpenOptions :: new ( )
418418 . create ( true )
419419 . truncate ( true )
420420 . write ( true )
421421 . mode ( 0o600 )
422422 . open ( & path) ?;
423423 to_file. write_all ( content. as_bytes ( ) ) ?;
424- fix_config_permissions ( ) ;
424+ std:: fs:: set_permissions ( & path, std:: fs:: Permissions :: from_mode ( 0o600 ) ) ?;
425+ if let Ok ( root) = self . config_dir ( ) {
426+ fix_config_permissions ( root) ;
427+ }
425428 }
426429
427430 #[ cfg( not( unix) ) ]
@@ -526,13 +529,9 @@ impl Pwd for Args {
526529}
527530
528531#[ cfg( unix) ]
529- fn fix_config_permissions ( ) {
532+ fn fix_config_permissions ( root : std :: path :: PathBuf ) {
530533 use std:: os:: unix:: fs:: PermissionsExt ;
531534
532- let Ok ( root) = global_config_path ( ) else {
533- return ;
534- } ;
535-
536535 let mut bad_dirs = Vec :: new ( ) ;
537536 let mut bad_files = Vec :: new ( ) ;
538537 let mut stack = vec ! [ root] ;
@@ -589,7 +588,7 @@ pub fn ensure_directory(dir: PathBuf) -> Result<PathBuf, Error> {
589588 . mode ( 0o700 )
590589 . create ( parent)
591590 . map_err ( |_| dir_creation_failed ( parent) ) ?;
592- fix_config_permissions ( ) ;
591+ fix_config_permissions ( parent . to_path_buf ( ) ) ;
593592 }
594593
595594 #[ cfg( not( unix) ) ]
@@ -630,9 +629,6 @@ impl KeyType {
630629 path : path. to_path_buf ( ) ,
631630 } ) ?;
632631
633- #[ cfg( unix) ]
634- fix_config_permissions ( ) ;
635-
636632 Ok ( toml:: from_str ( & data) ?)
637633 }
638634
@@ -704,7 +700,16 @@ impl KeyType {
704700 } ) ?;
705701
706702 #[ cfg( unix) ]
707- fix_config_permissions ( ) ;
703+ {
704+ use std:: os:: unix:: fs:: PermissionsExt ;
705+ std:: fs:: set_permissions ( & filepath, std:: fs:: Permissions :: from_mode ( 0o600 ) ) . map_err (
706+ |error| Error :: IdCreationFailed {
707+ filepath : filepath. clone ( ) ,
708+ error,
709+ } ,
710+ ) ?;
711+ fix_config_permissions ( pwd. to_path_buf ( ) ) ;
712+ }
708713
709714 Ok ( filepath)
710715 }
@@ -860,6 +865,39 @@ mod tests {
860865 use serial_test:: serial;
861866 use std:: collections:: HashMap ;
862867
868+ #[ test]
869+ fn overwrite_resets_file_permissions_to_0600 ( ) {
870+ use std:: os:: unix:: fs:: PermissionsExt ;
871+
872+ let dir = tempfile:: tempdir ( ) . unwrap ( ) ;
873+ let identity_dir = dir. path ( ) . join ( "identity" ) ;
874+ std:: fs:: create_dir_all ( & identity_dir) . unwrap ( ) ;
875+
876+ // Pre-create alice.toml at 0644 to simulate an inherited insecure mode.
877+ let alice = identity_dir. join ( "alice.toml" ) ;
878+ std:: fs:: write ( & alice, "seed_phrase = \" old\" \n " ) . unwrap ( ) ;
879+ std:: fs:: set_permissions ( & alice, std:: fs:: Permissions :: from_mode ( 0o644 ) ) . unwrap ( ) ;
880+
881+ assert_eq ! (
882+ std:: fs:: metadata( & alice) . unwrap( ) . permissions( ) . mode( ) & 0o777 ,
883+ 0o644 ,
884+ "setup: alice.toml should start at 0644"
885+ ) ;
886+
887+ let value: HashMap < String , String > = HashMap :: new ( ) ;
888+ KeyType :: Identity
889+ . write ( "alice" , & value, dir. path ( ) )
890+ . unwrap ( ) ;
891+
892+ let perms = std:: fs:: metadata ( & alice) . unwrap ( ) . permissions ( ) ;
893+ assert_eq ! (
894+ perms. mode( ) & 0o777 ,
895+ 0o600 ,
896+ "overwritten identity file should be 0600, got {:o}" ,
897+ perms. mode( ) & 0o777
898+ ) ;
899+ }
900+
863901 #[ test]
864902 fn test_write_sets_file_permissions_to_0600 ( ) {
865903 use std:: os:: unix:: fs:: PermissionsExt ;
0 commit comments