diff --git a/src/handlers/ciphers.rs b/src/handlers/ciphers.rs index 0d7e93f..6df9ba1 100644 --- a/src/handlers/ciphers.rs +++ b/src/handlers/ciphers.rs @@ -7,7 +7,8 @@ use worker::{query, Env}; use crate::auth::Claims; use crate::db; use crate::error::AppError; -use crate::models::cipher::{Cipher, CipherData, CreateCipherRequest}; +use crate::models::cipher::{Cipher, CipherData, CipherRequestData, CreateCipherRequest}; +use axum::extract::Path; #[worker::send] pub async fn create_cipher( @@ -78,3 +79,98 @@ pub async fn create_cipher( Ok(Json(cipher)) } + +#[worker::send] +pub async fn update_cipher( + claims: Claims, + State(env): State>, + Path(id): Path, + Json(payload): Json, +) -> Result, AppError> { + let db = db::get_db(&env)?; + let now = Utc::now(); + let now = now.format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string(); + + let existing_cipher: crate::models::cipher::CipherDBModel = query!( + &db, + "SELECT * FROM ciphers WHERE id = ?1 AND user_id = ?2", + id, + claims.sub + ) + .map_err(|_| AppError::Database)? + .first(None) + .await? + .ok_or(AppError::NotFound("Cipher not found".to_string()))?; + + let cipher_data_req = payload; + + let cipher_data = CipherData { + name: cipher_data_req.name, + notes: cipher_data_req.notes, + login: cipher_data_req.login, + card: cipher_data_req.card, + identity: cipher_data_req.identity, + secure_note: cipher_data_req.secure_note, + fields: cipher_data_req.fields, + password_history: cipher_data_req.password_history, + reprompt: cipher_data_req.reprompt, + }; + + let data_value = serde_json::to_value(&cipher_data).map_err(|_| AppError::Internal)?; + + let cipher = Cipher { + id: id.clone(), + user_id: Some(claims.sub.clone()), + organization_id: cipher_data_req.organization_id.clone(), + r#type: cipher_data_req.r#type, + data: data_value, + favorite: cipher_data_req.favorite, + folder_id: cipher_data_req.folder_id.clone(), + deleted_at: None, + created_at: existing_cipher.created_at, + updated_at: now.clone(), + object: "cipher".to_string(), + organization_use_totp: false, + edit: true, + view_password: true, + collection_ids: None, + }; + + let data = serde_json::to_string(&cipher.data).map_err(|_| AppError::Internal)?; + + query!( + &db, + "UPDATE ciphers SET organization_id = ?1, type = ?2, data = ?3, favorite = ?4, folder_id = ?5, updated_at = ?6 WHERE id = ?7 AND user_id = ?8", + cipher.organization_id, + cipher.r#type, + data, + cipher.favorite, + cipher.folder_id, + cipher.updated_at, + ).map_err(|_|AppError::Database)? + .run() + .await?; + + Ok(Json(cipher)) +} + +#[worker::send] +pub async fn delete_cipher( + claims: Claims, + State(env): State>, + Path(id): Path, +) -> Result, AppError> { + let db = db::get_db(&env)?; + + let res = query!( + &db, + "DELETE FROM ciphers WHERE id = ?1 AND user_id = ?2", + id, + claims.sub + ) + .map_err(|_| AppError::Database)? + .run() + .await?; + + Ok(Json(())) +} diff --git a/src/router.rs b/src/router.rs index 896b3c5..fab218a 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,5 +1,5 @@ use axum::{ - routing::{get, post}, + routing::{get, post, put}, Router, }; use std::sync::Arc; @@ -26,6 +26,8 @@ pub fn api_router(env: Env) -> Router { .route("/api/sync", get(sync::get_sync_data)) // Ciphers CRUD .route("/api/ciphers/create", post(ciphers::create_cipher)) + .route("/api/ciphers/{id}", put(ciphers::update_cipher)) + .route("/api/ciphers/{id}/delete", put(ciphers::delete_cipher)) .route("/api/config", get(config::config)) .with_state(app_state) }