diff --git a/src/auth.rs b/src/auth.rs index 40dedd5..fa33d6b 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -18,6 +18,13 @@ pub enum AuthCommand { /// The key to add. If not present, the key will be read in from stdin. key: Option, }, + SetApiUrl { + /// Sets the URL to access for API calls for this host. + /// + /// This can be useful if the api is hosted on a subdomain, or if the + /// ssh and http access are on different domains. + url: url::Url, + }, /// List all instances you're currently logged into List, } @@ -65,12 +72,25 @@ impl AuthCommand { crate::keys::LoginInfo::Application { name: user, token: key, + api_url: host_url.clone(), }, ); } else { println!("key for {host} already exists"); } } + AuthCommand::SetApiUrl { url } => { + let repo_info = crate::repo::RepoInfo::get_current(host_name, None, None)?; + let host_url = repo_info.host_url(); + let host = crate::host_with_port(&host_url); + match keys.hosts.get_mut(host) { + Some(key_info) => match key_info { + crate::LoginInfo::OAuth { api_url, .. } => *api_url = url, + crate::LoginInfo::Application { api_url, .. } => *api_url = url, + }, + None => println!("Not signed in to {host}"), + } + } AuthCommand::List => { if keys.hosts.is_empty() { println!("No logins."); @@ -173,6 +193,7 @@ async fn oauth_login( token: response.access_token, refresh_token: response.refresh_token, expires_at, + api_url: host.clone(), }; let domain = crate::host_with_port(&host); keys.hosts.insert(domain.to_owned(), login_info); diff --git a/src/keys.rs b/src/keys.rs index 58fc57d..fa7f9a7 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -52,7 +52,7 @@ impl KeyInfo { } pub async fn get_api(&mut self, url: &Url) -> eyre::Result { - self.get_login(url)?.api_for(url).await.map_err(Into::into) + self.get_login(url)?.api_for().await.map_err(Into::into) } } @@ -62,12 +62,14 @@ pub enum LoginInfo { Application { name: String, token: String, + api_url: Url, }, OAuth { name: String, token: String, refresh_token: String, expires_at: time::OffsetDateTime, + api_url: Url, }, } @@ -79,23 +81,25 @@ impl LoginInfo { } } - pub async fn api_for(&mut self, url: &Url) -> eyre::Result { + pub async fn api_for(&mut self) -> eyre::Result { match self { - LoginInfo::Application { token, .. } => { - let api = forgejo_api::Forgejo::new(forgejo_api::Auth::Token(token), url.clone())?; + LoginInfo::Application { token, api_url, .. } => { + let api = + forgejo_api::Forgejo::new(forgejo_api::Auth::Token(token), api_url.clone())?; Ok(api) } LoginInfo::OAuth { token, refresh_token, expires_at, + api_url, .. } => { if time::OffsetDateTime::now_utc() >= *expires_at { - let api = forgejo_api::Forgejo::new(forgejo_api::Auth::None, url.clone())?; - let (client_id, client_secret) = crate::auth::get_client_info_for(url) + let api = forgejo_api::Forgejo::new(forgejo_api::Auth::None, api_url.clone())?; + let (client_id, client_secret) = crate::auth::get_client_info_for(api_url) .ok_or_else(|| { - eyre::eyre!("Can't refresh token; no client info for {url}. How did this happen?") + eyre::eyre!("Can't refresh token; no client info for {api_url}. How did this happen?") })?; let response = api .oauth_get_access_token(forgejo_api::structs::OAuthTokenRequest::Refresh { @@ -113,7 +117,8 @@ impl LoginInfo { ); *expires_at = time::OffsetDateTime::now_utc() + expires_in; } - let api = forgejo_api::Forgejo::new(forgejo_api::Auth::Token(token), url.clone())?; + let api = + forgejo_api::Forgejo::new(forgejo_api::Auth::Token(token), api_url.clone())?; Ok(api) } }