1pub mod auto_refresh;
2pub mod current;
3pub mod login;
4pub mod output;
5pub mod refresh;
6pub mod remote;
7pub mod remove;
8pub mod save;
9pub mod status;
10pub mod sync;
11pub mod use_secret;
12
13use anyhow::Result;
14use std::path::Path;
15
16pub const ACCESS_ONLY_REFRESH_TOKEN_PLACEHOLDER: &str = "codex-remote-access-only-placeholder";
17
18pub fn identity_from_auth_file(path: &Path) -> Result<Option<String>> {
19 crate::runtime::auth::identity_from_auth_file(path).map_err(anyhow::Error::from)
20}
21
22pub fn email_from_auth_file(path: &Path) -> Result<Option<String>> {
23 crate::runtime::auth::email_from_auth_file(path).map_err(anyhow::Error::from)
24}
25
26pub fn account_id_from_auth_file(path: &Path) -> Result<Option<String>> {
27 crate::runtime::auth::account_id_from_auth_file(path).map_err(anyhow::Error::from)
28}
29
30pub fn last_refresh_from_auth_file(path: &Path) -> Result<Option<String>> {
31 crate::runtime::auth::last_refresh_from_auth_file(path).map_err(anyhow::Error::from)
32}
33
34pub fn identity_key_from_auth_file(path: &Path) -> Result<Option<String>> {
35 crate::runtime::auth::identity_key_from_auth_file(path).map_err(anyhow::Error::from)
36}
37
38pub fn is_invalid_secret_target(target: &str) -> bool {
39 target.contains('/') || target.contains('\\') || target.contains("..")
40}
41
42pub fn normalize_secret_file_name(target: &str) -> String {
43 if target.ends_with(".json") {
44 return target.to_string();
45 }
46 format!("{target}.json")
47}
48
49pub fn is_real_refresh_token(value: &str) -> bool {
50 !value.is_empty() && value != ACCESS_ONLY_REFRESH_TOKEN_PLACEHOLDER
51}
52
53#[cfg(test)]
54mod tests {
55 use super::{is_invalid_secret_target, normalize_secret_file_name};
56
57 #[test]
58 fn secret_target_validation_rejects_paths_and_traversal() {
59 assert!(is_invalid_secret_target("../a.json"));
60 assert!(is_invalid_secret_target("a/b.json"));
61 assert!(is_invalid_secret_target(r"a\b.json"));
62 assert!(!is_invalid_secret_target("alpha"));
63 assert!(!is_invalid_secret_target("alpha.json"));
64 }
65
66 #[test]
67 fn normalize_secret_file_name_appends_json_suffix_only_once() {
68 assert_eq!(normalize_secret_file_name("alpha"), "alpha.json");
69 assert_eq!(normalize_secret_file_name("alpha.json"), "alpha.json");
70 }
71}