Refactor me.* procedures with code review fixes
- Fix silent failures: add 404 NOT_FOUND for invalid resources in passkeysRename, revokeSession, trustDevice, untrustDevice - Fix race condition in passkeysDelete using transaction - Extract helper functions: requireDeviceFingerprint, defaultDeviceName - Improve type safety in updateProfile with Kysely's Updateable<Users> - Extract me.* procedures to separate files under procedures/me/ - Standardize naming to verb-first: listPasskeys, renamePasskey, deletePasskey Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
50
apps/api-server/src/procedures/me/delete.ts
Normal file
50
apps/api-server/src/procedures/me/delete.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Delete account procedure - permanently deletes user account
|
||||
*/
|
||||
|
||||
import { ORPCError } from "@orpc/server";
|
||||
import { COOKIE_NAMES, deleteCookie } from "../../utils/cookies.js";
|
||||
import { verifyPassword } from "../../utils/password.js";
|
||||
import { authMiddleware, os } from "../base.js";
|
||||
|
||||
/**
|
||||
* Delete account handler
|
||||
* - Requires authentication
|
||||
* - Requires password confirmation (passkey-only users must set password first)
|
||||
* - Deletes user record (cascades to sessions, devices, passkeys, etc.)
|
||||
* - Clears session cookie
|
||||
*/
|
||||
export const meDelete = os.me.delete
|
||||
.use(authMiddleware)
|
||||
.handler(async ({ input, context }) => {
|
||||
const { password } = input;
|
||||
|
||||
// Fetch user with password hash
|
||||
const user = await context.db
|
||||
.selectFrom("users")
|
||||
.select(["password_hash"])
|
||||
.where("id", "=", context.user.id)
|
||||
.executeTakeFirstOrThrow();
|
||||
|
||||
// Verify password (required for account deletion)
|
||||
if (!user.password_hash) {
|
||||
throw new ORPCError("BAD_REQUEST", {
|
||||
message:
|
||||
"Cannot delete account without a password. Please set a password first.",
|
||||
});
|
||||
}
|
||||
|
||||
const valid = await verifyPassword(password, user.password_hash);
|
||||
if (!valid) {
|
||||
throw new ORPCError("BAD_REQUEST", { message: "Incorrect password" });
|
||||
}
|
||||
|
||||
// Delete user (cascades to sessions, devices, passkeys, etc.)
|
||||
await context.db
|
||||
.deleteFrom("users")
|
||||
.where("id", "=", context.user.id)
|
||||
.execute();
|
||||
|
||||
// Clear session cookie
|
||||
deleteCookie(context.resHeaders, COOKIE_NAMES.SESSION_TOKEN);
|
||||
});
|
||||
Reference in New Issue
Block a user