mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-20 21:00:41 +00:00
feat(storage): add method to retrieve attachments by user ID for improved data handling
This commit is contained in:
+58
-2
@@ -2,6 +2,7 @@ import { Env, Cipher, Folder, CipherType } from '../types';
|
||||
import { StorageService } from '../services/storage';
|
||||
import { errorResponse } from '../utils/response';
|
||||
import { generateUUID } from '../utils/uuid';
|
||||
import { LIMITS } from '../config/limits';
|
||||
|
||||
// Bitwarden client import request format
|
||||
interface CiphersImportRequest {
|
||||
@@ -66,6 +67,17 @@ interface CiphersImportRequest {
|
||||
}>;
|
||||
}
|
||||
|
||||
function bindNull(v: any): any {
|
||||
return v === undefined ? null : v;
|
||||
}
|
||||
|
||||
async function runBatchInChunks(db: D1Database, statements: D1PreparedStatement[], chunkSize: number): Promise<void> {
|
||||
for (let i = 0; i < statements.length; i += chunkSize) {
|
||||
const chunk = statements.slice(i, i + chunkSize);
|
||||
await db.batch(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
// POST /api/ciphers/import - Bitwarden client import endpoint
|
||||
export async function handleCiphersImport(request: Request, env: Env, userId: string): Promise<Response> {
|
||||
const storage = new StorageService(env.DB);
|
||||
@@ -82,9 +94,11 @@ export async function handleCiphersImport(request: Request, env: Env, userId: st
|
||||
const folderRelationships = importData.folderRelationships || [];
|
||||
|
||||
const now = new Date().toISOString();
|
||||
const batchChunkSize = LIMITS.performance.bulkMoveChunkSize;
|
||||
|
||||
// Create folders and build index -> id mapping
|
||||
const folderIdMap = new Map<number, string>();
|
||||
const folderRows: Folder[] = [];
|
||||
|
||||
for (let i = 0; i < folders.length; i++) {
|
||||
const folderId = generateUUID();
|
||||
@@ -98,7 +112,19 @@ export async function handleCiphersImport(request: Request, env: Env, userId: st
|
||||
updatedAt: now,
|
||||
};
|
||||
|
||||
await storage.saveFolder(folder);
|
||||
folderRows.push(folder);
|
||||
}
|
||||
|
||||
if (folderRows.length > 0) {
|
||||
const folderStatements = folderRows.map(folder =>
|
||||
env.DB
|
||||
.prepare(
|
||||
'INSERT INTO folders(id, user_id, name, created_at, updated_at) VALUES(?, ?, ?, ?, ?) ' +
|
||||
'ON CONFLICT(id) DO UPDATE SET user_id=excluded.user_id, name=excluded.name, updated_at=excluded.updated_at'
|
||||
)
|
||||
.bind(folder.id, folder.userId, folder.name, folder.createdAt, folder.updatedAt)
|
||||
);
|
||||
await runBatchInChunks(env.DB, folderStatements, batchChunkSize);
|
||||
}
|
||||
|
||||
// Build cipher index -> folder id mapping from relationships
|
||||
@@ -111,6 +137,7 @@ export async function handleCiphersImport(request: Request, env: Env, userId: st
|
||||
}
|
||||
|
||||
// Create ciphers
|
||||
const cipherRows: Cipher[] = [];
|
||||
for (let i = 0; i < ciphers.length; i++) {
|
||||
const c = ciphers[i];
|
||||
const folderId = cipherFolderMap.get(i) || null;
|
||||
@@ -181,7 +208,36 @@ export async function handleCiphersImport(request: Request, env: Env, userId: st
|
||||
deletedAt: null,
|
||||
};
|
||||
|
||||
await storage.saveCipher(cipher);
|
||||
cipherRows.push(cipher);
|
||||
}
|
||||
|
||||
if (cipherRows.length > 0) {
|
||||
const cipherStatements = cipherRows.map(cipher => {
|
||||
const data = JSON.stringify(cipher);
|
||||
return env.DB
|
||||
.prepare(
|
||||
'INSERT INTO ciphers(id, user_id, type, folder_id, name, notes, favorite, data, reprompt, key, created_at, updated_at, deleted_at) ' +
|
||||
'VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ' +
|
||||
'ON CONFLICT(id) DO UPDATE SET ' +
|
||||
'user_id=excluded.user_id, type=excluded.type, folder_id=excluded.folder_id, name=excluded.name, notes=excluded.notes, favorite=excluded.favorite, data=excluded.data, reprompt=excluded.reprompt, key=excluded.key, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at'
|
||||
)
|
||||
.bind(
|
||||
cipher.id,
|
||||
cipher.userId,
|
||||
Number(cipher.type) || 1,
|
||||
bindNull(cipher.folderId),
|
||||
bindNull(cipher.name),
|
||||
bindNull(cipher.notes),
|
||||
cipher.favorite ? 1 : 0,
|
||||
data,
|
||||
bindNull(cipher.reprompt ?? 0),
|
||||
bindNull(cipher.key),
|
||||
cipher.createdAt,
|
||||
cipher.updatedAt,
|
||||
bindNull(cipher.deletedAt)
|
||||
);
|
||||
});
|
||||
await runBatchInChunks(env.DB, cipherStatements, batchChunkSize);
|
||||
}
|
||||
|
||||
// Update revision date
|
||||
|
||||
Reference in New Issue
Block a user