feat: add compatibility mode for deleting ciphers to support Bitwarden clients

This commit is contained in:
shuaiplus
2026-02-23 19:35:06 +08:00
parent 747cad35f5
commit f7a5966104
2 changed files with 25 additions and 1 deletions
+23
View File
@@ -204,6 +204,29 @@ export async function handleDeleteCipher(request: Request, env: Env, userId: str
return jsonResponse(cipherToResponse(cipher)); return jsonResponse(cipherToResponse(cipher));
} }
// DELETE /api/ciphers/:id (compat mode)
// Bitwarden clients may call DELETE on a trashed item to purge it permanently.
// For compatibility:
// - If item is active -> soft delete.
// - If item is already soft-deleted -> hard delete.
export async function handleDeleteCipherCompat(request: Request, env: Env, userId: string, id: string): Promise<Response> {
const storage = new StorageService(env.DB);
const cipher = await storage.getCipher(id);
if (!cipher || cipher.userId !== userId) {
return errorResponse('Cipher not found', 404);
}
if (cipher.deletedAt) {
await deleteAllAttachmentsForCipher(env, id);
await storage.deleteCipher(id, userId);
await storage.updateRevisionDate(userId);
return new Response(null, { status: 204 });
}
return handleDeleteCipher(request, env, userId, id);
}
// DELETE /api/ciphers/:id (permanent) // DELETE /api/ciphers/:id (permanent)
export async function handlePermanentDeleteCipher(request: Request, env: Env, userId: string, id: string): Promise<Response> { export async function handlePermanentDeleteCipher(request: Request, env: Env, userId: string, id: string): Promise<Response> {
const storage = new StorageService(env.DB); const storage = new StorageService(env.DB);
+2 -1
View File
@@ -17,6 +17,7 @@ import {
handleCreateCipher, handleCreateCipher,
handleUpdateCipher, handleUpdateCipher,
handleDeleteCipher, handleDeleteCipher,
handleDeleteCipherCompat,
handlePermanentDeleteCipher, handlePermanentDeleteCipher,
handleRestoreCipher, handleRestoreCipher,
handlePartialUpdateCipher, handlePartialUpdateCipher,
@@ -419,7 +420,7 @@ export async function handleRequest(request: Request, env: Env): Promise<Respons
if (subPath === '' || subPath === '/') { if (subPath === '' || subPath === '/') {
if (method === 'GET') return handleGetCipher(request, env, userId, cipherId); if (method === 'GET') return handleGetCipher(request, env, userId, cipherId);
if (method === 'PUT' || method === 'POST') return handleUpdateCipher(request, env, userId, cipherId); if (method === 'PUT' || method === 'POST') return handleUpdateCipher(request, env, userId, cipherId);
if (method === 'DELETE') return handleDeleteCipher(request, env, userId, cipherId); if (method === 'DELETE') return handleDeleteCipherCompat(request, env, userId, cipherId);
} }
if (subPath === '/delete' && method === 'PUT') { if (subPath === '/delete' && method === 'PUT') {