1use anyhow::{Context, Result};
2use keyring::Entry;
3
4const SERVICE_NAME: &str = "greppy";
5
6const GOOGLE_USER: &str = "google_oauth_token";
8const ANTHROPIC_USER: &str = "anthropic_oauth_token";
9const LEGACY_USER: &str = "oauth_token";
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum Provider {
14 Google,
15 Anthropic,
16}
17
18impl Provider {
19 fn storage_key(&self) -> &'static str {
20 match self {
21 Provider::Google => GOOGLE_USER,
22 Provider::Anthropic => ANTHROPIC_USER,
23 }
24 }
25}
26
27pub fn save_token(provider: Provider, token: &str) -> Result<()> {
28 let entry = Entry::new(SERVICE_NAME, provider.storage_key())?;
29 entry.set_password(token)?;
30 Ok(())
31}
32
33pub fn load_token(provider: Provider) -> Result<String> {
34 let entry = Entry::new(SERVICE_NAME, provider.storage_key())?;
35 entry.get_password().context(format!(
36 "No {:?} auth token found. Please run 'greppy login'.",
37 provider
38 ))
39}
40
41pub fn delete_token(provider: Provider) -> Result<()> {
42 let entry = Entry::new(SERVICE_NAME, provider.storage_key())?;
43 match entry.delete_password() {
44 Ok(_) => Ok(()),
45 Err(keyring::Error::NoEntry) => Ok(()), Err(e) => Err(e.into()),
47 }
48}
49
50pub fn has_token(provider: Provider) -> bool {
52 load_token(provider).is_ok()
53}
54
55pub fn delete_all_tokens() -> Result<()> {
57 let _ = delete_token(Provider::Google);
58 let _ = delete_token(Provider::Anthropic);
59 if let Ok(entry) = Entry::new(SERVICE_NAME, LEGACY_USER) {
61 let _ = entry.delete_password();
62 }
63 Ok(())
64}
65
66pub fn save_token_legacy(token: &str) -> Result<()> {
68 save_token(Provider::Google, token)
69}
70
71pub fn load_token_legacy() -> Result<String> {
72 load_token(Provider::Google).or_else(|_| {
74 let entry = Entry::new(SERVICE_NAME, LEGACY_USER)?;
75 entry
76 .get_password()
77 .context("No auth token found. Please run 'greppy login'.")
78 })
79}
80
81pub fn delete_token_legacy() -> Result<()> {
82 delete_token(Provider::Google)
83}