Skip to main content

codex_cli/auth/
sync.rs

1use anyhow::Result;
2use std::path::{Path, PathBuf};
3
4use crate::auth;
5use crate::fs;
6use crate::paths;
7
8pub fn run() -> Result<i32> {
9    let auth_file = match paths::resolve_auth_file() {
10        Some(path) => path,
11        None => return Ok(0),
12    };
13
14    if !auth_file.is_file() {
15        return Ok(0);
16    }
17
18    let auth_key = match auth::identity_key_from_auth_file(&auth_file) {
19        Ok(Some(key)) => key,
20        _ => return Ok(0),
21    };
22
23    let auth_last_refresh = auth::last_refresh_from_auth_file(&auth_file).unwrap_or(None);
24    let auth_hash = match fs::sha256_file(&auth_file) {
25        Ok(hash) => hash,
26        Err(_) => {
27            eprintln!("codex: failed to hash {}", auth_file.display());
28            return Ok(1);
29        }
30    };
31
32    let secret_dir = paths::resolve_secret_dir();
33    if let Some(secret_dir) = secret_dir
34        && let Ok(entries) = std::fs::read_dir(&secret_dir)
35    {
36        for entry in entries.flatten() {
37            let path = entry.path();
38            if path.extension().and_then(|s| s.to_str()) != Some("json") {
39                continue;
40            }
41            let candidate_key = match auth::identity_key_from_auth_file(&path) {
42                Ok(Some(key)) => key,
43                _ => continue,
44            };
45            if candidate_key != auth_key {
46                continue;
47            }
48
49            let secret_hash = match fs::sha256_file(&path) {
50                Ok(hash) => hash,
51                Err(_) => {
52                    eprintln!("codex: failed to hash {}", path.display());
53                    return Ok(1);
54                }
55            };
56            if secret_hash == auth_hash {
57                continue;
58            }
59
60            let contents = std::fs::read(&auth_file)?;
61            fs::write_atomic(&path, &contents, fs::SECRET_FILE_MODE)?;
62
63            let timestamp_path = secret_timestamp_path(&path)?;
64            fs::write_timestamp(&timestamp_path, auth_last_refresh.as_deref())?;
65        }
66    }
67
68    let auth_timestamp = secret_timestamp_path(&auth_file)?;
69    fs::write_timestamp(&auth_timestamp, auth_last_refresh.as_deref())?;
70
71    Ok(0)
72}
73
74fn secret_timestamp_path(target_file: &Path) -> Result<PathBuf> {
75    let cache_dir = paths::resolve_secret_cache_dir()
76        .ok_or_else(|| anyhow::anyhow!("CODEX_SECRET_CACHE_DIR not resolved"))?;
77    let name = target_file
78        .file_name()
79        .and_then(|name| name.to_str())
80        .unwrap_or("auth.json");
81    Ok(cache_dir.join(format!("{name}.timestamp")))
82}