feat: add purge vault endpoint for deleting all ciphers and folders

This commit is contained in:
qaz741wsd856 2025-12-05 03:38:44 +00:00
parent a724719f4b
commit 40f07dcd58
5 changed files with 65 additions and 4 deletions

View file

@ -20,7 +20,7 @@ use crate::{
cipher::CipherData,
sync::Profile,
user::{
ChangeKdfRequest, ChangePasswordRequest, DeleteAccountRequest, PreloginResponse,
ChangeKdfRequest, ChangePasswordRequest, PasswordOrOtpData, PreloginResponse,
RegisterRequest, RotateKeyRequest, User,
},
},
@ -314,7 +314,7 @@ pub async fn get_profile(
pub async fn delete_account(
claims: Claims,
State(env): State<Arc<Env>>,
Json(payload): Json<DeleteAccountRequest>,
Json(payload): Json<PasswordOrOtpData>,
) -> Result<Json<Value>, AppError> {
let db = db::get_db(&env)?;
let user_id = &claims.sub;

View file

@ -2,6 +2,7 @@ use super::get_batch_size;
use axum::{extract::State, Json};
use chrono::Utc;
use serde::Deserialize;
use serde_json::Value;
use std::sync::Arc;
use uuid::Uuid;
use worker::{query, D1PreparedStatement, Env};
@ -10,6 +11,7 @@ use crate::auth::Claims;
use crate::db;
use crate::error::AppError;
use crate::models::cipher::{Cipher, CipherData, CipherRequestData, CreateCipherRequest};
use crate::models::user::{PasswordOrOtpData, User};
use axum::extract::Path;
#[worker::send]
@ -440,3 +442,57 @@ pub async fn create_cipher_simple(
Ok(Json(cipher))
}
/// Purge the user's vault - delete all ciphers and folders
/// POST /api/ciphers/purge
///
/// This is a destructive operation that requires password verification.
/// In vaultwarden, this endpoint also supports purging organization vaults,
/// but this simplified version only supports personal vault purge.
#[worker::send]
pub async fn purge_vault(
claims: Claims,
State(env): State<Arc<Env>>,
Json(payload): Json<PasswordOrOtpData>,
) -> Result<Json<()>, AppError> {
let db = db::get_db(&env)?;
let user_id = &claims.sub;
// Get the user from the database
let user: Value = db
.prepare("SELECT * FROM users WHERE id = ?1")
.bind(&[user_id.clone().into()])?
.first(None)
.await
.map_err(|_| AppError::Database)?
.ok_or_else(|| AppError::NotFound("User not found".to_string()))?;
let user: User = serde_json::from_value(user).map_err(|_| AppError::Internal)?;
// Validate password (OTP not supported in this simplified version)
let provided_hash = payload
.master_password_hash
.ok_or_else(|| AppError::BadRequest("Missing master password hash".to_string()))?;
let verification = user.verify_master_password(&provided_hash).await?;
if !verification.is_valid() {
return Err(AppError::Unauthorized("Invalid password".to_string()));
}
// Delete all user's ciphers (both active and soft-deleted)
query!(&db, "DELETE FROM ciphers WHERE user_id = ?1", user_id)
.map_err(|_| AppError::Database)?
.run()
.await?;
// Delete all user's folders
query!(&db, "DELETE FROM folders WHERE user_id = ?1", user_id)
.map_err(|_| AppError::Database)?
.run()
.await?;
// Update user's revision date to trigger client sync
db::touch_user_updated_at(&db, user_id).await?;
Ok(Json(()))
}

View file

@ -134,10 +134,12 @@ pub struct KeyData {
pub encrypted_private_key: String,
}
// For DELETE /accounts request
/// Request body for password-protected operations (delete account, purge vault, etc.)
/// Supports both master password hash and OTP verification.
/// Note: OTP verification is not implemented in this simplified version.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DeleteAccountRequest {
pub struct PasswordOrOtpData {
#[serde(alias = "MasterPasswordHash")]
pub master_password_hash: Option<String>,
pub otp: Option<String>,

View file

@ -67,6 +67,8 @@ pub fn api_router(env: Env) -> Router {
.route("/api/ciphers/{id}/restore", put(ciphers::restore_cipher))
// Cipher bulk restore
.route("/api/ciphers/restore", put(ciphers::restore_ciphers_bulk))
// Purge vault - delete all ciphers and folders (requires password verification)
.route("/api/ciphers/purge", post(ciphers::purge_vault))
// Folders CRUD
.route("/api/folders", post(folders::create_folder))
.route("/api/folders/{id}", put(folders::update_folder))

1
vaultwarden Submodule

@ -0,0 +1 @@
Subproject commit cb2f5741accd5bf510d03233ed8457cef8a6a35c