diff options
| author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2026-06-10 23:12:17 +0200 |
|---|---|---|
| committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2026-06-10 23:12:17 +0200 |
| commit | 9eb2ffb2e9b52cdec70acb268e7a12131811db10 (patch) | |
| tree | 4db12e8f58aee8aba614bab7d5d7803a5807ef0e | |
| parent | chore: Remove more (kinda) useless stuff (diff) | |
| download | atuin-9eb2ffb2e9b52cdec70acb268e7a12131811db10.zip | |
chore: Somewhat simplify sync code
| -rw-r--r-- | Cargo.lock | 35 | ||||
| -rw-r--r-- | crates/atuin-client/Cargo.toml | 1 | ||||
| -rw-r--r-- | crates/atuin-client/src/api_client.rs | 24 | ||||
| -rw-r--r-- | crates/atuin-client/src/login.rs | 21 | ||||
| -rw-r--r-- | crates/atuin-client/src/settings.rs | 9 | ||||
| -rw-r--r-- | crates/atuin-server/src/lib.rs | 9 | ||||
| -rw-r--r-- | crates/atuin/Cargo.toml | 1 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/account/login.rs | 49 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/doctor.rs | 2 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/history.rs | 34 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/store/rekey.rs | 22 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/sync.rs | 79 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/sync/status.rs | 12 |
13 files changed, 47 insertions, 251 deletions
@@ -228,7 +228,6 @@ dependencies = [ "sysinfo", "tempfile", "time", - "tiny-bip39", "tokio", "toml_edit", "tracing", @@ -286,7 +285,6 @@ dependencies = [ "testing_logger", "thiserror 2.0.18", "time", - "tiny-bip39", "tokio", "typed-builder", "urlencoding", @@ -3006,16 +3004,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - -[[package]] name = "pem-rfc7468" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3828,12 +3816,6 @@ dependencies = [ ] [[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] name = "rustc_version" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4856,23 +4838,6 @@ dependencies = [ ] [[package]] -name = "tiny-bip39" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a30fd743a02bf35236f6faf99adb03089bb77e91c998dac2c2ad76bb424f668c" -dependencies = [ - "once_cell", - "pbkdf2", - "rand 0.8.5", - "rustc-hash", - "sha2", - "thiserror 1.0.69", - "unicode-normalization", - "wasm-bindgen", - "zeroize", -] - -[[package]] name = "tinystr" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/crates/atuin-client/Cargo.toml b/crates/atuin-client/Cargo.toml index b5ac49a4..c6a0f261 100644 --- a/crates/atuin-client/Cargo.toml +++ b/crates/atuin-client/Cargo.toml @@ -69,7 +69,6 @@ reqwest = { workspace = true, optional = true } hex = { version = "0.4", optional = true } sha2 = { version = "0.10", optional = true } indicatif = "0.18.0" -tiny-bip39 = "2.0.0" # theme crossterm = { workspace = true, features = ["serde"] } diff --git a/crates/atuin-client/src/api_client.rs b/crates/atuin-client/src/api_client.rs index 066fecb5..ca2fc661 100644 --- a/crates/atuin-client/src/api_client.rs +++ b/crates/atuin-client/src/api_client.rs @@ -40,8 +40,6 @@ static APP_USER_AGENT: &str = concat!("atuin/", env!("CARGO_PKG_VERSION"),); /// authentication across CLI and Hub features. #[derive(Debug, Clone)] pub enum AuthToken { - /// Hub API token, used with "Bearer {token}" header - Bearer(String), /// Legacy CLI session token, used with "Token {token}" header Token(String), } @@ -50,7 +48,6 @@ impl AuthToken { /// Format the token as an Authorization header value fn to_header_value(&self) -> String { match self { - AuthToken::Bearer(token) => format!("Bearer {token}"), AuthToken::Token(token) => format!("Token {token}"), } } @@ -139,27 +136,6 @@ pub async fn login(address: &str, req: LoginRequest) -> Result<LoginResponse> { Ok(session) } -#[cfg(feature = "check-update")] -pub async fn latest_version() -> Result<Version> { - use atuin_common::api::IndexResponse; - - ensure_crypto_provider(); - let url = "https://api.atuin.sh"; - let client = reqwest::Client::new(); - - let resp = client - .get(url) - .header(USER_AGENT, APP_USER_AGENT) - .send() - .await?; - let resp = handle_resp_error(resp).await?; - - let index = resp.json::<IndexResponse>().await?; - let version = Version::parse(index.version.as_str())?; - - Ok(version) -} - pub fn ensure_version(response: &Response) -> Result<bool> { let version = response.headers().get(ATUIN_HEADER_VERSION); diff --git a/crates/atuin-client/src/login.rs b/crates/atuin-client/src/login.rs index d72d1c09..2545e890 100644 --- a/crates/atuin-client/src/login.rs +++ b/crates/atuin-client/src/login.rs @@ -7,7 +7,7 @@ use tokio::io::AsyncWriteExt; use crate::{ api_client, - encryption::{Key, decode_key, encode_key, load_key}, + encryption::{decode_key, load_key}, record::{sqlite_store::SqliteStore, store::Store}, settings::Settings, }; @@ -19,25 +19,6 @@ pub async fn login( password: String, key: String, ) -> Result<String> { - // try parse the key as a mnemonic... - let key = match bip39::Mnemonic::from_phrase(&key, bip39::Language::English) { - Ok(mnemonic) => encode_key(Key::from_slice(mnemonic.entropy()))?, - Err(err) => { - match err { - // assume they copied in the base64 key - bip39::ErrorKind::InvalidWord(_) => key, - bip39::ErrorKind::InvalidChecksum => { - bail!("key mnemonic was not valid") - } - bip39::ErrorKind::InvalidKeysize(_) - | bip39::ErrorKind::InvalidWordLength(_) - | bip39::ErrorKind::InvalidEntropyLength(_, _) => { - bail!("key was not the correct length") - } - } - } - }; - let key_path = settings.key_path.as_str(); let key_path = PathBuf::from(key_path); diff --git a/crates/atuin-client/src/settings.rs b/crates/atuin-client/src/settings.rs index ce84c053..5fb65c17 100644 --- a/crates/atuin-client/src/settings.rs +++ b/crates/atuin-client/src/settings.rs @@ -336,11 +336,6 @@ impl Default for Stats { } } -#[derive(Clone, Debug, Deserialize, Default, Serialize)] -pub struct Sync { - pub records: bool, -} - /// Sync protocol type for authentication. /// /// This setting is primarily for development/testing. When not explicitly set, @@ -1103,9 +1098,6 @@ pub struct Settings { pub stats: Stats, #[serde(default)] - pub sync: Sync, - - #[serde(default)] pub keys: Keys, #[serde(default)] @@ -1330,7 +1322,6 @@ impl Settings { // muscle memory. // New users will get the new default, that is more similar to what they are used to. .set_default("enter_accept", false)? - .set_default("sync.records", true)? .set_default("keys.scroll_exits", true)? .set_default("keys.accept_past_line_end", true)? .set_default("keys.exit_past_line_start", true)? diff --git a/crates/atuin-server/src/lib.rs b/crates/atuin-server/src/lib.rs index fcf5dde6..02e50e1e 100644 --- a/crates/atuin-server/src/lib.rs +++ b/crates/atuin-server/src/lib.rs @@ -34,15 +34,6 @@ async fn shutdown_signal() { eprintln!("Shutting down gracefully..."); } -#[cfg(target_family = "windows")] -async fn shutdown_signal() { - signal::windows::ctrl_c() - .expect("failed to register signal handler") - .recv() - .await; - eprintln!("Shutting down gracefully..."); -} - pub async fn launch<Db: Database>(settings: Settings, addr: SocketAddr) -> Result<()> { launch_with_tcp_listener::<Db>( settings, diff --git a/crates/atuin/Cargo.toml b/crates/atuin/Cargo.toml index 1ec6f754..6cdc57fa 100644 --- a/crates/atuin/Cargo.toml +++ b/crates/atuin/Cargo.toml @@ -50,7 +50,6 @@ rpassword = "7.0" semver = { workspace = true } rustix = { workspace = true } runtime-format = "0.1.3" -tiny-bip39 = "2" futures-util = "0.3" fuzzy-matcher = "0.3.7" colored = "2.0.4" diff --git a/crates/atuin/src/command/client/account/login.rs b/crates/atuin/src/command/client/account/login.rs index 13918638..e320e80b 100644 --- a/crates/atuin/src/command/client/account/login.rs +++ b/crates/atuin/src/command/client/account/login.rs @@ -6,7 +6,7 @@ use tokio::{fs::File, io::AsyncWriteExt}; use atuin_client::{ auth::{self, AuthResponse}, - encryption::{Key, decode_key, encode_key, load_key}, + encryption::{decode_key, load_key}, record::sqlite_store::SqliteStore, record::store::Store, record::sync::{self, SyncError}, @@ -98,31 +98,6 @@ impl Cmd { "encryption key [blank to use existing key file]", ); - // if provided, the key may be EITHER base64, or a bip mnemonic - // try to normalize on base64 - let key = if key.is_empty() { - key - } else { - // try parse the key as a mnemonic... - match bip39::Mnemonic::from_phrase(&key, bip39::Language::English) { - Ok(mnemonic) => encode_key(Key::from_slice(mnemonic.entropy()))?, - Err(err) => { - match err { - // assume they copied in the base64 key - bip39::ErrorKind::InvalidWord(_) => key, - bip39::ErrorKind::InvalidChecksum => { - bail!("Key mnemonic is not valid") - } - bip39::ErrorKind::InvalidKeysize(_) - | bip39::ErrorKind::InvalidWordLength(_) - | bip39::ErrorKind::InvalidEntropyLength(_, _) => { - bail!("Key is not the correct length") - } - } - } - } - }; - if key.is_empty() { if key_path.exists() { let bytes = fs_err::read_to_string(&key_path).context(format!( @@ -229,25 +204,3 @@ fn read_user_input(name: &'static str) -> String { eprint!("Please enter {name}: "); get_input().expect("Failed to read from input") } - -#[cfg(test)] -mod tests { - use atuin_client::encryption::Key; - - #[test] - fn mnemonic_round_trip() { - let key = Key::from([ - 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, - 7, 9, 5, - ]); - let phrase = bip39::Mnemonic::from_entropy(&key, bip39::Language::English) - .unwrap() - .into_phrase(); - let mnemonic = bip39::Mnemonic::from_phrase(&phrase, bip39::Language::English).unwrap(); - assert_eq!(mnemonic.entropy(), key.as_slice()); - assert_eq!( - phrase, - "adapt amused able anxiety mother adapt beef gaze amount else seat alcohol cage lottery avoid scare alcohol cactus school avoid coral adjust catch pink" - ); - } -} diff --git a/crates/atuin/src/command/client/doctor.rs b/crates/atuin/src/command/client/doctor.rs index 6c9dcca6..1bf003db 100644 --- a/crates/atuin/src/command/client/doctor.rs +++ b/crates/atuin/src/command/client/doctor.rs @@ -237,7 +237,6 @@ impl SystemInfo { #[derive(Debug, Serialize)] struct SyncInfo { pub auth_state: String, - pub records: bool, pub auto_sync: bool, pub last_sync: String, @@ -263,7 +262,6 @@ impl SyncInfo { Self { auth_state, auto_sync: settings.auto_sync, - records: settings.sync.records, last_sync: Settings::last_sync() .await .map_or_else(|_| "no last sync".to_string(), |v| v.to_string()), diff --git a/crates/atuin/src/command/client/history.rs b/crates/atuin/src/command/client/history.rs index ccbf66cf..abf39cc2 100644 --- a/crates/atuin/src/command/client/history.rs +++ b/crates/atuin/src/command/client/history.rs @@ -528,21 +528,11 @@ async fn handle_end( history_store.push(h).await?; if settings.should_sync().await? { - #[cfg(feature = "sync")] - { - if settings.sync.records { - let (_, downloaded) = - record::sync::sync(settings, &store, &history_store.encryption_key).await?; - Settings::save_sync_time().await?; + let (_, downloaded) = + record::sync::sync(settings, &store, &history_store.encryption_key).await?; + Settings::save_sync_time().await?; - crate::sync::build(settings, &store, db, Some(&downloaded)).await?; - } else { - debug!("running periodic background sync"); - sync::sync(settings, false, db).await?; - } - } - #[cfg(not(feature = "sync"))] - debug!("not compiled with sync support"); + crate::sync::build(settings, &store, db, Some(&downloaded)).await?; } else { debug!("sync disabled! not syncing"); } @@ -1016,12 +1006,8 @@ impl Cmd { for entry in matches { eprintln!("deleting {}", entry.id); - if settings.sync.records { - let (id, _) = history_store.delete(entry.id.clone()).await?; - history_store.incremental_build(db, &[id]).await?; - } else { - db.delete(entry.clone()).await?; - } + let (id, _) = history_store.delete(entry.id.clone()).await?; + history_store.incremental_build(db, &[id]).await?; } #[cfg(feature = "daemon")] @@ -1077,12 +1063,8 @@ impl Cmd { for entry in matches { eprintln!("deleting {}", entry.id); - if settings.sync.records { - let (id, _) = history_store.delete(entry.id).await?; - history_store.incremental_build(db, &[id]).await?; - } else { - db.delete(entry).await?; - } + let (id, _) = history_store.delete(entry.id).await?; + history_store.incremental_build(db, &[id]).await?; } #[cfg(feature = "daemon")] diff --git a/crates/atuin/src/command/client/store/rekey.rs b/crates/atuin/src/command/client/store/rekey.rs index 4c537a48..c92d2555 100644 --- a/crates/atuin/src/command/client/store/rekey.rs +++ b/crates/atuin/src/command/client/store/rekey.rs @@ -1,9 +1,9 @@ use clap::Args; -use eyre::{Result, bail}; +use eyre::Result; use tokio::{fs::File, io::AsyncWriteExt}; use atuin_client::{ - encryption::{Key, decode_key, encode_key, generate_encoded_key, load_key}, + encryption::{decode_key, generate_encoded_key, load_key}, record::sqlite_store::SqliteStore, record::store::Store, settings::Settings, @@ -20,23 +20,7 @@ impl Rekey { let key = if let Some(key) = self.key.clone() { println!("Re-encrypting store with specified key"); - match bip39::Mnemonic::from_phrase(&key, bip39::Language::English) { - Ok(mnemonic) => encode_key(Key::from_slice(mnemonic.entropy()))?, - Err(err) => { - match err { - // assume they copied in the base64 key - bip39::ErrorKind::InvalidWord(_) => key, - bip39::ErrorKind::InvalidChecksum => { - bail!("key mnemonic was not valid") - } - bip39::ErrorKind::InvalidKeysize(_) - | bip39::ErrorKind::InvalidWordLength(_) - | bip39::ErrorKind::InvalidEntropyLength(_, _) => { - bail!("key was not the correct length") - } - } - } - } + key } else { println!("Re-encrypting store with freshly-generated key"); let (_, encoded) = generate_encoded_key()?; diff --git a/crates/atuin/src/command/client/sync.rs b/crates/atuin/src/command/client/sync.rs index 76dd6eeb..5b8c2cb7 100644 --- a/crates/atuin/src/command/client/sync.rs +++ b/crates/atuin/src/command/client/sync.rs @@ -33,11 +33,7 @@ pub enum Cmd { Register(account::register::Cmd), /// Print the encryption key for transfer to another machine - Key { - /// Switch to base64 output of the key - #[arg(long)] - base64: bool, - }, + Key {}, /// Display the sync status Status, @@ -55,19 +51,14 @@ impl Cmd { Self::Login(l) => l.run(&settings, &store).await, Self::Logout => account::logout::run().await, Self::Register(r) => r.run(&settings).await, - Self::Status => status::run(&settings, db).await, - Self::Key { base64 } => { + Self::Status => status::run(&settings).await, + Self::Key {} => { use atuin_client::encryption::{encode_key, load_key}; let key = load_key(&settings).wrap_err("could not load encryption key")?; - if base64 { - let encode = encode_key(&key).wrap_err("could not encode encryption key")?; - println!("{encode}"); - } else { - let mnemonic = bip39::Mnemonic::from_entropy(&key, bip39::Language::English) - .map_err(|_| eyre::eyre!("invalid key"))?; - println!("{mnemonic}"); - } + let encode = encode_key(&key).wrap_err("could not encode encryption key")?; + println!("{encode}"); + Ok(()) } } @@ -80,49 +71,43 @@ async fn run( db: &impl Database, store: SqliteStore, ) -> Result<()> { - if settings.sync.records { - let encryption_key: [u8; 32] = encryption::load_key(settings) - .context("could not load encryption key")? - .into(); + let encryption_key: [u8; 32] = encryption::load_key(settings) + .context("could not load encryption key")? + .into(); - let host_id = Settings::host_id().await?; - let history_store = HistoryStore::new(store.clone(), host_id, encryption_key); + let host_id = Settings::host_id().await?; + let history_store = HistoryStore::new(store.clone(), host_id, encryption_key); - let (uploaded, downloaded) = sync::sync(settings, &store, &encryption_key) - .await - .map_err(crate::print_error::format_sync_error)?; + let (uploaded, downloaded) = sync::sync(settings, &store, &encryption_key) + .await + .map_err(crate::print_error::format_sync_error)?; - crate::sync::build(settings, &store, db, Some(&downloaded)).await?; + crate::sync::build(settings, &store, db, Some(&downloaded)).await?; - println!("{uploaded}/{} up/down to record store", downloaded.len()); + println!("{uploaded}/{} up/down to record store", downloaded.len()); - let history_length = db.history_count(true).await?; - let store_history_length = store.len_tag("history").await?; + let history_length = db.history_count(true).await?; + let store_history_length = store.len_tag("history").await?; - #[expect(clippy::cast_sign_loss)] - if history_length as u64 > store_history_length { - println!( - "{history_length} in history index, but {store_history_length} in history store" - ); - println!("Running automatic history store init..."); + #[expect(clippy::cast_sign_loss)] + if history_length as u64 > store_history_length { + println!("{history_length} in history index, but {store_history_length} in history store"); + println!("Running automatic history store init..."); - // Internally we use the global filter mode, so this context is ignored. - // don't recurse or loop here. - history_store.init_store(db).await?; + // Internally we use the global filter mode, so this context is ignored. + // don't recurse or loop here. + history_store.init_store(db).await?; - println!("Re-running sync due to new records locally"); + println!("Re-running sync due to new records locally"); - // we'll want to run sync once more, as there will now be stuff to upload - let (uploaded, downloaded) = sync::sync(settings, &store, &encryption_key) - .await - .map_err(crate::print_error::format_sync_error)?; + // we'll want to run sync once more, as there will now be stuff to upload + let (uploaded, downloaded) = sync::sync(settings, &store, &encryption_key) + .await + .map_err(crate::print_error::format_sync_error)?; - crate::sync::build(settings, &store, db, Some(&downloaded)).await?; + crate::sync::build(settings, &store, db, Some(&downloaded)).await?; - println!("{uploaded}/{} up/down to record store", downloaded.len()); - } - } else { - atuin_client::sync::sync(settings, force, db).await?; + println!("{uploaded}/{} up/down to record store", downloaded.len()); } println!( diff --git a/crates/atuin/src/command/client/sync/status.rs b/crates/atuin/src/command/client/sync/status.rs index 54911cc8..c992eb3e 100644 --- a/crates/atuin/src/command/client/sync/status.rs +++ b/crates/atuin/src/command/client/sync/status.rs @@ -1,9 +1,9 @@ use crate::{SHA, VERSION}; -use atuin_client::{api_client, database::Database, settings::Settings}; +use atuin_client::{api_client, settings::Settings}; use colored::Colorize; use eyre::{Result, bail}; -pub async fn run(settings: &Settings, db: &impl Database) -> Result<()> { +pub async fn run(settings: &Settings) -> Result<()> { if !settings.logged_in().await? { bail!("You are not logged in to a sync server - cannot show sync status"); } @@ -27,14 +27,6 @@ pub async fn run(settings: &Settings, db: &impl Database) -> Result<()> { println!("Last sync: {}", last_sync.to_offset(settings.timezone.0)); } - if !settings.sync.records { - let local_count = db.history_count(false).await?; - let deleted_count = db.history_count(true).await? - local_count; - - println!("History count: {local_count}"); - println!("Deleted history count: {deleted_count}\n"); - } - if settings.auto_sync { println!("{}", "[Remote]".green()); println!("Address: {}", settings.sync_address); |
