aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYannick Ulrich <yannick.ulrich@durham.ac.uk>2023-05-16 22:00:59 +0100
committerGitHub <noreply@github.com>2023-05-16 22:00:59 +0100
commit7b9dea72e3d2435f75825e8e66a04285332d5aa5 (patch)
treee2b9ae2f8df86105b09547a55dc7ac455a55c0c8
parentInclude bash preexec warning (#983) (diff)
downloadatuin-7b9dea72e3d2435f75825e8e66a04285332d5aa5.zip
feat: add delete account option (attempt 2) (#980)
* Added DELETE register endpoint * Added remove function to database * Added unregister to client * Updated docs * Renamed functions * Reformatting * Used execute instead of fetch in delete_user
-rw-r--r--atuin-client/src/api_client.rs15
-rw-r--r--atuin-common/src/api.rs3
-rw-r--r--atuin-server/src/database.rs21
-rw-r--r--atuin-server/src/handlers/user.rs19
-rw-r--r--atuin-server/src/router.rs1
-rw-r--r--atuin/src/command/client/sync.rs5
-rw-r--r--atuin/src/command/client/sync/delete.rs23
-rw-r--r--docs/docs/commands/sync.md8
8 files changed, 94 insertions, 1 deletions
diff --git a/atuin-client/src/api_client.rs b/atuin-client/src/api_client.rs
index 80051ba6..2abb8159 100644
--- a/atuin-client/src/api_client.rs
+++ b/atuin-client/src/api_client.rs
@@ -217,4 +217,19 @@ impl<'a> Client<'a> {
Ok(())
}
+
+ pub async fn delete(&self) -> Result<()> {
+ let url = format!("{}/register", self.sync_addr);
+ let url = Url::parse(url.as_str())?;
+
+ let resp = self.client.delete(url).send().await?;
+
+ if resp.status() == 403 {
+ bail!("invalid login details");
+ } else if resp.status() == 200 {
+ Ok(())
+ } else {
+ bail!("Unknown error");
+ }
+ }
}
diff --git a/atuin-common/src/api.rs b/atuin-common/src/api.rs
index e9809329..2eff464e 100644
--- a/atuin-common/src/api.rs
+++ b/atuin-common/src/api.rs
@@ -20,6 +20,9 @@ pub struct RegisterResponse {
}
#[derive(Debug, Serialize, Deserialize)]
+pub struct DeleteUserResponse {}
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct LoginRequest {
pub username: String,
pub password: String,
diff --git a/atuin-server/src/database.rs b/atuin-server/src/database.rs
index 7f3e5dac..e7057f6b 100644
--- a/atuin-server/src/database.rs
+++ b/atuin-server/src/database.rs
@@ -27,6 +27,7 @@ pub trait Database {
async fn get_user(&self, username: &str) -> Result<User>;
async fn get_user_session(&self, u: &User) -> Result<Session>;
async fn add_user(&self, user: &NewUser) -> Result<i64>;
+ async fn delete_user(&self, u: &User) -> Result<()>;
async fn count_history(&self, user: &User) -> Result<i64>;
async fn count_history_cached(&self, user: &User) -> Result<i64>;
@@ -337,6 +338,26 @@ impl Database for Postgres {
}
#[instrument(skip_all)]
+ async fn delete_user(&self, u: &User) -> Result<()> {
+ sqlx::query("delete from sessions where user_id = $1")
+ .bind(u.id)
+ .execute(&self.pool)
+ .await?;
+
+ sqlx::query("delete from users where id = $1")
+ .bind(u.id)
+ .execute(&self.pool)
+ .await?;
+
+ sqlx::query("delete from history where user_id = $1")
+ .bind(u.id)
+ .execute(&self.pool)
+ .await?;
+
+ Ok(())
+ }
+
+ #[instrument(skip_all)]
async fn add_user(&self, user: &NewUser) -> Result<i64> {
let email: &str = &user.email;
let username: &str = &user.username;
diff --git a/atuin-server/src/handlers/user.rs b/atuin-server/src/handlers/user.rs
index 89aa0601..ec2131e1 100644
--- a/atuin-server/src/handlers/user.rs
+++ b/atuin-server/src/handlers/user.rs
@@ -18,7 +18,7 @@ use uuid::Uuid;
use super::{ErrorResponse, ErrorResponseStatus, RespExt};
use crate::{
database::Database,
- models::{NewSession, NewUser},
+ models::{NewSession, NewUser, User},
router::AppState,
};
@@ -138,6 +138,23 @@ pub async fn register<DB: Database>(
}
}
+#[instrument(skip_all, fields(user.id = user.id))]
+pub async fn delete<DB: Database>(
+ user: User,
+ state: State<AppState<DB>>,
+) -> Result<Json<DeleteUserResponse>, ErrorResponseStatus<'static>> {
+ debug!("request to delete user {}", user.id);
+
+ let db = &state.0.database;
+ if let Err(e) = db.delete_user(&user).await {
+ error!("failed to delete user: {}", e);
+
+ return Err(ErrorResponse::reply("failed to delete user")
+ .with_status(StatusCode::INTERNAL_SERVER_ERROR));
+ };
+ Ok(Json(DeleteUserResponse {}))
+}
+
#[instrument(skip_all, fields(user.username = login.username.as_str()))]
pub async fn login<DB: Database>(
state: State<AppState<DB>>,
diff --git a/atuin-server/src/router.rs b/atuin-server/src/router.rs
index 58aac3bd..20b11f45 100644
--- a/atuin-server/src/router.rs
+++ b/atuin-server/src/router.rs
@@ -72,6 +72,7 @@ pub fn router<DB: Database + Clone + Send + Sync + 'static>(
.route("/history", post(handlers::history::add))
.route("/history", delete(handlers::history::delete))
.route("/user/:username", get(handlers::user::get))
+ .route("/account", delete(handlers::user::delete))
.route("/register", post(handlers::user::register))
.route("/login", post(handlers::user::login));
diff --git a/atuin/src/command/client/sync.rs b/atuin/src/command/client/sync.rs
index 3980e13d..12664be5 100644
--- a/atuin/src/command/client/sync.rs
+++ b/atuin/src/command/client/sync.rs
@@ -3,6 +3,7 @@ use eyre::{Result, WrapErr};
use atuin_client::{database::Database, settings::Settings};
+mod delete;
mod login;
mod logout;
mod register;
@@ -27,6 +28,9 @@ pub enum Cmd {
/// Register with the configured server
Register(register::Cmd),
+ /// Unregister with the configured server
+ Unregister,
+
/// Print the encryption key for transfer to another machine
Key {
/// Switch to base64 output of the key
@@ -44,6 +48,7 @@ impl Cmd {
Self::Login(l) => l.run(&settings).await,
Self::Logout => logout::run(&settings),
Self::Register(r) => r.run(&settings).await,
+ Self::Unregister => delete::run(&settings).await,
Self::Status => status::run(&settings, db).await,
Self::Key { base64 } => {
use atuin_client::encryption::{encode_key, load_key};
diff --git a/atuin/src/command/client/sync/delete.rs b/atuin/src/command/client/sync/delete.rs
new file mode 100644
index 00000000..63e5b747
--- /dev/null
+++ b/atuin/src/command/client/sync/delete.rs
@@ -0,0 +1,23 @@
+use atuin_client::{api_client, encryption::load_encoded_key, settings::Settings};
+use eyre::{bail, Result};
+use std::path::PathBuf;
+
+pub async fn run(settings: &Settings) -> Result<()> {
+ let session_path = settings.session_path.as_str();
+
+ if !PathBuf::from(session_path).exists() {
+ bail!("You are not logged in");
+ }
+
+ let client = api_client::Client::new(
+ &settings.sync_address,
+ &settings.session_token,
+ load_encoded_key(settings)?,
+ )?;
+
+ client.delete().await?;
+
+ println!("Your account is deleted");
+
+ Ok(())
+}
diff --git a/docs/docs/commands/sync.md b/docs/docs/commands/sync.md
index d77a660f..8fbb0c47 100644
--- a/docs/docs/commands/sync.md
+++ b/docs/docs/commands/sync.md
@@ -32,6 +32,14 @@ notifications (security breaches, changes to service, etc).
Upon success, you are also logged in :) Syncing should happen automatically from
here!
+## Delete
+
+You can delete your sync account with
+
+```
+atuin unregister
+```
+
## Key
As all your data is encrypted, Atuin generates a key for you. It's stored in the