chore: switch storage to D1 (test branch)

This commit is contained in:
shuaiplus
2026-02-09 22:00:14 +08:00
parent 5fc2436552
commit d2ce2aea24
17 changed files with 480 additions and 333 deletions
+6 -6
View File
@@ -14,7 +14,7 @@ function jwtSecretUnsafeReason(env: Env): 'missing' | 'default' | 'too_short' |
// POST /api/accounts/register (only used from setup page, not client)
export async function handleRegister(request: Request, env: Env): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
// Enforce safe JWT_SECRET before allowing first registration.
const unsafe = jwtSecretUnsafeReason(env);
@@ -96,7 +96,7 @@ export async function handleRegister(request: Request, env: Env): Promise<Respon
// GET /api/accounts/profile
export async function handleGetProfile(request: Request, env: Env, userId: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const user = await storage.getUserById(userId);
if (!user) {
@@ -132,7 +132,7 @@ export async function handleGetProfile(request: Request, env: Env, userId: strin
// PUT /api/accounts/profile
export async function handleUpdateProfile(request: Request, env: Env, userId: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const user = await storage.getUserById(userId);
if (!user) {
@@ -158,7 +158,7 @@ export async function handleUpdateProfile(request: Request, env: Env, userId: st
// POST /api/accounts/keys
export async function handleSetKeys(request: Request, env: Env, userId: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const user = await storage.getUserById(userId);
if (!user) {
@@ -189,7 +189,7 @@ export async function handleSetKeys(request: Request, env: Env, userId: string):
// GET /api/accounts/revision-date
export async function handleGetRevisionDate(request: Request, env: Env, userId: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const revisionDate = await storage.getRevisionDate(userId);
// Return as milliseconds timestamp (Bitwarden format)
@@ -199,7 +199,7 @@ export async function handleGetRevisionDate(request: Request, env: Env, userId:
// POST /api/accounts/verify-password
export async function handleVerifyPassword(request: Request, env: Env, userId: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const user = await storage.getUserById(userId);
if (!user) {
+7 -6
View File
@@ -25,7 +25,7 @@ export async function handleCreateAttachment(
userId: string,
cipherId: string
): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
// Verify cipher exists and belongs to user
const cipher = await storage.getCipher(cipherId);
@@ -96,7 +96,7 @@ export async function handleUploadAttachment(
cipherId: string,
attachmentId: string
): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
// Verify cipher exists and belongs to user
const cipher = await storage.getCipher(cipherId);
@@ -169,7 +169,7 @@ export async function handleGetAttachment(
cipherId: string,
attachmentId: string
): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
// Verify cipher exists and belongs to user
const cipher = await storage.getCipher(cipherId);
@@ -227,7 +227,8 @@ export async function handlePublicDownloadAttachment(
return errorResponse('Token mismatch', 401);
}
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
// Verify attachment exists
const attachment = await storage.getAttachment(attachmentId);
@@ -262,7 +263,7 @@ export async function handleDeleteAttachment(
cipherId: string,
attachmentId: string
): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
// Verify cipher exists and belongs to user
const cipher = await storage.getCipher(cipherId);
@@ -348,7 +349,7 @@ export async function deleteAllAttachmentsForCipher(
env: Env,
cipherId: string
): Promise<void> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const attachments = await storage.getAttachmentsByCipher(cipherId);
for (const attachment of attachments) {
+9 -9
View File
@@ -57,7 +57,7 @@ function cipherToResponse(cipher: Cipher, attachments: Attachment[] = []): Ciphe
// GET /api/ciphers
export async function handleGetCiphers(request: Request, env: Env, userId: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const ciphers = await storage.getAllCiphers(userId);
// Filter out soft-deleted ciphers unless specifically requested
@@ -84,7 +84,7 @@ export async function handleGetCiphers(request: Request, env: Env, userId: strin
// GET /api/ciphers/:id
export async function handleGetCipher(request: Request, env: Env, userId: string, id: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const cipher = await storage.getCipher(id);
if (!cipher || cipher.userId !== userId) {
@@ -97,7 +97,7 @@ export async function handleGetCipher(request: Request, env: Env, userId: string
// POST /api/ciphers
export async function handleCreateCipher(request: Request, env: Env, userId: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
let body: any;
try {
@@ -141,7 +141,7 @@ export async function handleCreateCipher(request: Request, env: Env, userId: str
// PUT /api/ciphers/:id
export async function handleUpdateCipher(request: Request, env: Env, userId: string, id: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const existingCipher = await storage.getCipher(id);
if (!existingCipher || existingCipher.userId !== userId) {
@@ -186,7 +186,7 @@ export async function handleUpdateCipher(request: Request, env: Env, userId: str
// DELETE /api/ciphers/:id
export async function handleDeleteCipher(request: Request, env: Env, userId: string, id: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const cipher = await storage.getCipher(id);
if (!cipher || cipher.userId !== userId) {
@@ -204,7 +204,7 @@ export async function handleDeleteCipher(request: Request, env: Env, userId: str
// DELETE /api/ciphers/:id (permanent)
export async function handlePermanentDeleteCipher(request: Request, env: Env, userId: string, id: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const cipher = await storage.getCipher(id);
if (!cipher || cipher.userId !== userId) {
@@ -222,7 +222,7 @@ export async function handlePermanentDeleteCipher(request: Request, env: Env, us
// PUT /api/ciphers/:id/restore
export async function handleRestoreCipher(request: Request, env: Env, userId: string, id: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const cipher = await storage.getCipher(id);
if (!cipher || cipher.userId !== userId) {
@@ -239,7 +239,7 @@ export async function handleRestoreCipher(request: Request, env: Env, userId: st
// PUT /api/ciphers/:id/partial - Update only favorite/folderId
export async function handlePartialUpdateCipher(request: Request, env: Env, userId: string, id: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const cipher = await storage.getCipher(id);
if (!cipher || cipher.userId !== userId) {
@@ -269,7 +269,7 @@ export async function handlePartialUpdateCipher(request: Request, env: Env, user
// POST/PUT /api/ciphers/move - Bulk move to folder
export async function handleBulkMoveCiphers(request: Request, env: Env, userId: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
let body: { ids?: string[]; folderId?: string | null };
try {
+5 -5
View File
@@ -15,7 +15,7 @@ function folderToResponse(folder: Folder): FolderResponse {
// GET /api/folders
export async function handleGetFolders(request: Request, env: Env, userId: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const folders = await storage.getAllFolders(userId);
return jsonResponse({
@@ -27,7 +27,7 @@ export async function handleGetFolders(request: Request, env: Env, userId: strin
// GET /api/folders/:id
export async function handleGetFolder(request: Request, env: Env, userId: string, id: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const folder = await storage.getFolder(id);
if (!folder || folder.userId !== userId) {
@@ -39,7 +39,7 @@ export async function handleGetFolder(request: Request, env: Env, userId: string
// POST /api/folders
export async function handleCreateFolder(request: Request, env: Env, userId: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
let body: { name?: string };
try {
@@ -68,7 +68,7 @@ export async function handleCreateFolder(request: Request, env: Env, userId: str
// PUT /api/folders/:id
export async function handleUpdateFolder(request: Request, env: Env, userId: string, id: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const folder = await storage.getFolder(id);
if (!folder || folder.userId !== userId) {
@@ -94,7 +94,7 @@ export async function handleUpdateFolder(request: Request, env: Env, userId: str
// DELETE /api/folders/:id
export async function handleDeleteFolder(request: Request, env: Env, userId: string, id: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const folder = await storage.getFolder(id);
if (!folder || folder.userId !== userId) {
+5 -4
View File
@@ -6,9 +6,9 @@ import { jsonResponse, errorResponse, identityErrorResponse } from '../utils/res
// POST /identity/connect/token
export async function handleToken(request: Request, env: Env): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const auth = new AuthService(env);
const rateLimit = new RateLimitService(env.VAULT);
const rateLimit = new RateLimitService(env.DB);
let body: Record<string, string>;
const contentType = request.headers.get('content-type') || '';
@@ -28,7 +28,8 @@ export async function handleToken(request: Request, env: Env): Promise<Response>
const passwordHash = body.password;
if (!email || !passwordHash) {
return errorResponse('Email and password are required', 400);
// Bitwarden clients expect OAuth-style error fields.
return identityErrorResponse('Email and password are required', 'invalid_request', 400);
}
const user = await storage.getUser(email);
@@ -156,7 +157,7 @@ export async function handleToken(request: Request, env: Env): Promise<Response>
// POST /identity/accounts/prelogin
export async function handlePrelogin(request: Request, env: Env): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
let body: { email?: string };
try {
+1 -1
View File
@@ -68,7 +68,7 @@ interface CiphersImportRequest {
// 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.VAULT);
const storage = new StorageService(env.DB);
let importData: CiphersImportRequest;
try {
+3 -3
View File
@@ -15,7 +15,7 @@ function getJwtSecretState(env: Env): JwtSecretState | null {
// GET / - Setup page
export async function handleSetupPage(request: Request, env: Env): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const disabled = await storage.isSetupDisabled();
if (disabled) {
return new Response(null, { status: 404 });
@@ -33,7 +33,7 @@ export async function handleSetupPage(request: Request, env: Env): Promise<Respo
// GET /setup/status
export async function handleSetupStatus(request: Request, env: Env): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const registered = await storage.isRegistered();
const disabled = await storage.isSetupDisabled();
return jsonResponse({ registered, disabled });
@@ -41,7 +41,7 @@ export async function handleSetupStatus(request: Request, env: Env): Promise<Res
// POST /setup/disable
export async function handleDisableSetup(request: Request, env: Env): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const registered = await storage.isRegistered();
if (!registered) {
return errorResponse('Registration required', 403);
+1 -1
View File
@@ -659,7 +659,7 @@ const registerPageHTML = `<!DOCTYPE html>
</html>`;
export async function handleRegisterPage(request: Request, env: Env): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const disabled = await storage.isSetupDisabled();
if (disabled) {
return new Response(null, { status: 404 });
+1 -1
View File
@@ -18,7 +18,7 @@ function formatAttachments(attachments: Attachment[]): any[] | null {
// GET /api/sync
export async function handleSync(request: Request, env: Env, userId: string): Promise<Response> {
const storage = new StorageService(env.VAULT);
const storage = new StorageService(env.DB);
const user = await storage.getUserById(userId);
if (!user) {