From f2d97fb17dcf4f52123da89532d7964ed8f8124c Mon Sep 17 00:00:00 2001 From: asepharyana Date: Thu, 16 Jul 2026 16:00:06 +0700 Subject: [PATCH] fix(iam): set permission 0600 pada file token OAuth Co-Authored-By: Claude Sonnet 5 --- .../infrastructure/persistence/oauth_repo.rs | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/zesdex-iam/src/infrastructure/persistence/oauth_repo.rs b/crates/zesdex-iam/src/infrastructure/persistence/oauth_repo.rs index 3e4512a..48fc6d3 100644 --- a/crates/zesdex-iam/src/infrastructure/persistence/oauth_repo.rs +++ b/crates/zesdex-iam/src/infrastructure/persistence/oauth_repo.rs @@ -7,7 +7,8 @@ //! Filesystem-backed `OAuthRepository` implementation. //! //! Tokens are stored as a single JSON file. Writes use a write-then-rename -//! + fsync pattern for crash safety. +//! plus fsync pattern for crash safety, with restrictive owner-only mode +//! 0o600 on Unix. use std::path::Path; use crate::domain::oauth::OAuthToken; @@ -32,6 +33,11 @@ impl OAuthRepository for FileSystemOAuthRepository { let data = serde_json::to_string_pretty(token)?; let tmp = path.with_extension("tmp"); std::fs::write(&tmp, data)?; + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(&tmp, std::fs::Permissions::from_mode(0o600))?; + } let f = std::fs::File::open(&tmp)?; f.sync_all()?; std::fs::rename(&tmp, path)?; @@ -50,3 +56,29 @@ impl OAuthRepository for FileSystemOAuthRepository { Ok(Some(token)) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(unix)] + fn save_token_sets_owner_only_permissions() { + use std::os::unix::fs::PermissionsExt; + let dir = std::env::temp_dir().join(format!("zesdex-iam-perm-test-{}", uuid::Uuid::new_v4())); + let path = dir.join("oauth_test.json"); + let repo = FileSystemOAuthRepository::new(); + let token = OAuthToken { + access_token: "secret".to_string(), + refresh_token: None, + expires_at: 0, + token_type: "Bearer".to_string(), + }; + repo.save_token(&path, &token).expect("save_token should succeed"); + + let mode = std::fs::metadata(&path).unwrap().permissions().mode() & 0o777; + assert_eq!(mode, 0o600, "token file must be readable/writable by owner only, got {mode:o}"); + + let _ = std::fs::remove_dir_all(&dir); + } +}