aboutsummaryrefslogtreecommitdiffstats
path: root/crates/turtle/src/atuin_client/auth.rs
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-11 16:27:35 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-11 16:27:35 +0200
commit5a4c4b9fa0df891fcdd9beee18be0db4a45da701 (patch)
treeb467a1bd5706643b77962e7a82d651a803bfc436 /crates/turtle/src/atuin_client/auth.rs
parentchore(server): Simplify the database support (diff)
downloadatuin-5a4c4b9fa0df891fcdd9beee18be0db4a45da701.zip
chore(server): Remove the last remnants of the "hub" sync-server thingy
Diffstat (limited to 'crates/turtle/src/atuin_client/auth.rs')
-rw-r--r--crates/turtle/src/atuin_client/auth.rs94
1 files changed, 26 insertions, 68 deletions
diff --git a/crates/turtle/src/atuin_client/auth.rs b/crates/turtle/src/atuin_client/auth.rs
index b260d433..620e127e 100644
--- a/crates/turtle/src/atuin_client/auth.rs
+++ b/crates/turtle/src/atuin_client/auth.rs
@@ -1,4 +1,3 @@
-use async_trait::async_trait;
use eyre::{Context, Result, bail};
use reqwest::{Url, header::USER_AGENT};
@@ -14,66 +13,19 @@ use crate::atuin_client::settings::Settings;
static APP_USER_AGENT: &str = concat!("atuin/", env!("CARGO_PKG_VERSION"));
-/// Result of an auth operation that may require 2FA.
-pub(crate) enum AuthResponse {
- /// Operation succeeded; for login/register, contains the session token.
- /// `auth_type` indicates the kind of token: `Some("hub")` for Hub API
- /// tokens (prefixed `atapi_`), `Some("cli")` for legacy CLI session
- /// tokens. `None` when the server didn't include the field (old servers).
- Success {
- session: String,
- auth_type: Option<String>,
- },
- /// Two-factor authentication is required; the caller should prompt for a
- /// TOTP code and retry with it.
- TwoFactorRequired,
-}
-
-/// Result of a mutating account operation that may require 2FA.
-pub(crate) enum MutateResponse {
- /// Operation completed successfully.
- Success,
- /// Two-factor authentication is required; the caller should prompt for a
- /// TOTP code and retry.
- TwoFactorRequired,
-}
-
-/// Abstraction over the legacy (Rust sync server) and Hub auth APIs.
-///
-/// CLI commands use this trait so they don't need to know which backend is
-/// active — they just prompt for input and call these methods.
-#[async_trait]
-pub(crate) trait AuthClient: Send + Sync {
- /// Log in with username + password, optionally providing a TOTP code.
- async fn login(&self, username: &str, password: &str) -> Result<AuthResponse>;
-
- /// Register a new account.
- async fn register(&self, username: &str, email: &str, password: &str) -> Result<AuthResponse>;
-
- /// Change the account password, optionally providing a TOTP code.
- async fn change_password(
- &self,
- current_password: &str,
- new_password: &str,
- totp_code: Option<&str>,
- ) -> Result<MutateResponse>;
-
- /// Delete the account, requiring the current password and optionally a TOTP code.
- async fn delete_account(
- &self,
- password: &str,
- totp_code: Option<&str>,
- ) -> Result<MutateResponse>;
+/// Result of an auth operation
+pub(crate) struct AuthResponse {
+ pub(crate) session: String,
}
/// Resolve the appropriate [`AuthClient`] for the current settings.
-pub(crate) async fn auth_client(settings: &Settings) -> Box<dyn AuthClient> {
- Box::new(LegacyAuthClient::new(
+pub(crate) async fn auth_client(settings: &Settings) -> LegacyAuthClient {
+ LegacyAuthClient::new(
&settings.sync_address,
settings.session_token().await.ok(),
settings.network_connect_timeout,
settings.network_timeout,
- )) as Box<dyn AuthClient>
+ )
}
// ---------------------------------------------------------------------------
@@ -125,9 +77,9 @@ impl LegacyAuthClient {
}
}
-#[async_trait]
-impl AuthClient for LegacyAuthClient {
- async fn login(&self, username: &str, password: &str) -> Result<AuthResponse> {
+impl LegacyAuthClient {
+ /// Log in with username + password, optionally providing a TOTP code.
+ pub(crate) async fn login(&self, username: &str, password: &str) -> Result<AuthResponse> {
// The legacy server has no 2FA support; totp_code is ignored.
let resp = api_client::login(
&self.address,
@@ -138,26 +90,31 @@ impl AuthClient for LegacyAuthClient {
)
.await?;
- Ok(AuthResponse::Success {
+ Ok(AuthResponse {
session: resp.session,
- auth_type: resp.auth.or(Some("cli".into())),
})
}
- async fn register(&self, username: &str, email: &str, password: &str) -> Result<AuthResponse> {
+ /// Register a new account.
+ pub(crate) async fn register(
+ &self,
+ username: &str,
+ email: &str,
+ password: &str,
+ ) -> Result<AuthResponse> {
let resp = api_client::register(&self.address, username, email, password).await?;
- Ok(AuthResponse::Success {
+ Ok(AuthResponse {
session: resp.session,
- auth_type: resp.auth.or(Some("cli".into())),
})
}
- async fn change_password(
+ /// Change the account password, optionally providing a TOTP code.
+ pub(crate) async fn change_password(
&self,
current_password: &str,
new_password: &str,
_totp_code: Option<&str>,
- ) -> Result<MutateResponse> {
+ ) -> Result<()> {
let client = self.authenticated_client()?;
let url = make_url(&self.address, "/account/password")?;
@@ -171,18 +128,19 @@ impl AuthClient for LegacyAuthClient {
.await?;
match resp.status().as_u16() {
- 200 => Ok(MutateResponse::Success),
+ 200 => Ok(()),
401 => bail!("current password is incorrect"),
403 => bail!("invalid login details"),
_ => bail!("unknown error"),
}
}
- async fn delete_account(
+ /// Delete the account, requiring the current password and optionally a TOTP code.
+ pub(crate) async fn delete_account(
&self,
password: &str,
_totp_code: Option<&str>,
- ) -> Result<MutateResponse> {
+ ) -> Result<()> {
let client = self.authenticated_client()?;
let url = make_url(&self.address, "/account")?;
@@ -193,7 +151,7 @@ impl AuthClient for LegacyAuthClient {
.await?;
match resp.status().as_u16() {
- 200 => Ok(MutateResponse::Success),
+ 200 => Ok(()),
401 => bail!("password is incorrect"),
403 => bail!("invalid login details"),
_ => bail!("unknown error"),