feat: improve account security
Support TOTP 2fa, allow for changing password, add session management and account removal.
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import { sessions } from '~~/drizzle/schema';
|
||||
import { auth } from '~~/lib/auth';
|
||||
import { db } from '~~/server/lib/db';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const sessionData = await auth.api.getSession({ headers: event.headers });
|
||||
|
||||
if (sessionData === null) {
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
statusMessage: 'Unauthorized',
|
||||
});
|
||||
}
|
||||
|
||||
const id = getRouterParam(event, 'id')!;
|
||||
|
||||
// signing out the current device goes through the normal sign out, which
|
||||
// also clears its cookies
|
||||
if (id === sessionData.session.id) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'Cannot revoke the current session',
|
||||
});
|
||||
}
|
||||
|
||||
const deleted = await db.delete(sessions)
|
||||
.where(and(eq(sessions.id, id), eq(sessions.userId, sessionData.user.id)))
|
||||
.returning({ id: sessions.id });
|
||||
|
||||
if (deleted.length === 0) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: 'Not Found',
|
||||
message: 'Session not found',
|
||||
});
|
||||
}
|
||||
|
||||
return { ok: true };
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import { auth } from '~~/lib/auth';
|
||||
import { db } from '~~/server/lib/db';
|
||||
|
||||
/**
|
||||
* Lists the signed in devices for the current user. Session tokens are left
|
||||
* out on purpose: the client only ever needs the id to sign a device out.
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
const sessionData = await auth.api.getSession({ headers: event.headers });
|
||||
|
||||
if (sessionData === null) {
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
statusMessage: 'Unauthorized',
|
||||
});
|
||||
}
|
||||
|
||||
const result = await db.query.sessions.findMany({
|
||||
where: {
|
||||
userId: sessionData.user.id,
|
||||
expiresAt: {
|
||||
gt: new Date(),
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
updatedAt: 'desc',
|
||||
},
|
||||
});
|
||||
|
||||
return result.map(session => ({
|
||||
id: session.id,
|
||||
createdAt: session.createdAt,
|
||||
updatedAt: session.updatedAt,
|
||||
ipAddress: session.ipAddress,
|
||||
userAgent: session.userAgent,
|
||||
current: session.id === sessionData.session.id,
|
||||
}));
|
||||
});
|
||||
Reference in New Issue
Block a user