aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-10 23:12:17 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-10 23:12:17 +0200
commit9eb2ffb2e9b52cdec70acb268e7a12131811db10 (patch)
tree4db12e8f58aee8aba614bab7d5d7803a5807ef0e
parentchore: Remove more (kinda) useless stuff (diff)
downloadatuin-9eb2ffb2e9b52cdec70acb268e7a12131811db10.zip
chore: Somewhat simplify sync code
-rw-r--r--Cargo.lock35
-rw-r--r--crates/atuin-client/Cargo.toml1
-rw-r--r--crates/atuin-client/src/api_client.rs24
-rw-r--r--crates/atuin-client/src/login.rs21
-rw-r--r--crates/atuin-client/src/settings.rs9
-rw-r--r--crates/atuin-server/src/lib.rs9
-rw-r--r--crates/atuin/Cargo.toml1
-rw-r--r--crates/atuin/src/command/client/account/login.rs49
-rw-r--r--crates/atuin/src/command/client/doctor.rs2
-rw-r--r--crates/atuin/src/command/client/history.rs34
-rw-r--r--crates/atuin/src/command/client/store/rekey.rs22
-rw-r--r--crates/atuin/src/command/client/sync.rs79
-rw-r--r--crates/atuin/src/command/client/sync/status.rs12
13 files changed, 47 insertions, 251 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 8c2c5d14..d10c4402 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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);