pub mod oauth;
pub mod server;
pub mod session;
pub mod setup;
pub mod token;
use std::sync::Arc;
use anyhow::Result;
use token::{OAuthTokens, TokenStore};
use crate::api::client::{Credentials, LinearClient, StaticCredentials};
use crate::api::types::Viewer;
use crate::config::Config;
pub enum AuthMethod {
OAuth(OAuthTokens),
ApiKey(String),
}
impl AuthMethod {
fn authorization_header(&self) -> String {
match self {
AuthMethod::OAuth(tokens) => format!("Bearer {}", tokens.access_token),
AuthMethod::ApiKey(key) => key.clone(),
}
}
pub fn label(&self) -> &'static str {
match self {
AuthMethod::OAuth(_) => "OAuth",
AuthMethod::ApiKey(_) => "API key",
}
}
pub fn into_credentials(self, store: TokenStore) -> Arc<dyn Credentials> {
match self {
AuthMethod::OAuth(tokens) => Arc::new(session::OAuthSession::new(store, tokens)),
AuthMethod::ApiKey(key) => Arc::new(StaticCredentials(key)),
}
}
}
pub fn has_credentials(token_store: &TokenStore, config: &Config) -> Result<bool> {
Ok(token_store.load()?.is_some() || config.auth.api_key.is_some())
}
pub async fn resolve_auth(token_store: &TokenStore, api_key: Option<&str>) -> Result<AuthMethod> {
if let Some(mut tokens) = token_store.load()? {
if tokens.is_expired() {
if tokens.refresh_token.is_empty() {
anyhow::bail!(
"Your session expired and no refresh token was stored. \
Run `linear-tui auth login` to sign in again."
);
}
tokens = oauth::refresh_token(&tokens.refresh_token).await?;
token_store.save(&tokens)?;
}
return Ok(AuthMethod::OAuth(tokens));
}
if let Some(key) = api_key {
return Ok(AuthMethod::ApiKey(key.to_string()));
}
anyhow::bail!("Not authenticated. Run `linear-tui auth login` to sign in.")
}
pub async fn identify(auth: &AuthMethod) -> Result<Viewer> {
Ok(LinearClient::with_header(auth.authorization_header())
.viewer()
.await?)
}