mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-02-04 16:16:55 +00:00
/api/auth 아래의 Endpoint들을 tRPC로 마이그레이션
This commit is contained in:
@@ -3,11 +3,6 @@ import env from "$lib/server/loadenv";
|
||||
import { authenticate, AuthenticationError } from "$lib/server/modules/auth";
|
||||
|
||||
export const authenticateMiddleware: Handle = async ({ event, resolve }) => {
|
||||
const { pathname, search } = event.url;
|
||||
if (pathname === "/api/auth/login") {
|
||||
return await resolve(event);
|
||||
}
|
||||
|
||||
try {
|
||||
const sessionIdSigned = event.cookies.get("sessionId");
|
||||
if (!sessionIdSigned) {
|
||||
@@ -24,6 +19,7 @@ export const authenticateMiddleware: Handle = async ({ event, resolve }) => {
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof AuthenticationError) {
|
||||
const { pathname, search } = event.url;
|
||||
if (pathname === "/auth/login" || pathname.startsWith("/api/trpc")) {
|
||||
return await resolve(event);
|
||||
} else if (pathname.startsWith("/api")) {
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const passwordChangeRequest = z.object({
|
||||
oldPassword: z.string().trim().nonempty(),
|
||||
newPassword: z.string().trim().nonempty(),
|
||||
});
|
||||
export type PasswordChangeRequest = z.input<typeof passwordChangeRequest>;
|
||||
|
||||
export const loginRequest = z.object({
|
||||
email: z.email(),
|
||||
password: z.string().trim().nonempty(),
|
||||
});
|
||||
export type LoginRequest = z.input<typeof loginRequest>;
|
||||
|
||||
export const sessionUpgradeRequest = z.object({
|
||||
encPubKey: z.base64().nonempty(),
|
||||
sigPubKey: z.base64().nonempty(),
|
||||
});
|
||||
export type SessionUpgradeRequest = z.input<typeof sessionUpgradeRequest>;
|
||||
|
||||
export const sessionUpgradeResponse = z.object({
|
||||
id: z.int().positive(),
|
||||
challenge: z.base64().nonempty(),
|
||||
});
|
||||
export type SessionUpgradeResponse = z.output<typeof sessionUpgradeResponse>;
|
||||
|
||||
export const sessionUpgradeVerifyRequest = z.object({
|
||||
id: z.int().positive(),
|
||||
answerSig: z.base64().nonempty(),
|
||||
force: z.boolean().default(false),
|
||||
});
|
||||
export type SessionUpgradeVerifyRequest = z.input<typeof sessionUpgradeVerifyRequest>;
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from "./auth";
|
||||
export * from "./category";
|
||||
export * from "./directory";
|
||||
export * from "./file";
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
import { error } from "@sveltejs/kit";
|
||||
import argon2 from "argon2";
|
||||
import { getClient, getClientByPubKeys, getUserClient } from "$lib/server/db/client";
|
||||
import { IntegrityError } from "$lib/server/db/error";
|
||||
import {
|
||||
upgradeSession,
|
||||
deleteSession,
|
||||
deleteAllOtherSessions,
|
||||
registerSessionUpgradeChallenge,
|
||||
consumeSessionUpgradeChallenge,
|
||||
} from "$lib/server/db/session";
|
||||
import { getUser, getUserByEmail, setUserPassword } from "$lib/server/db/user";
|
||||
import env from "$lib/server/loadenv";
|
||||
import { startSession } from "$lib/server/modules/auth";
|
||||
import { verifySignature, generateChallenge } from "$lib/server/modules/crypto";
|
||||
|
||||
const hashPassword = async (password: string) => {
|
||||
return await argon2.hash(password);
|
||||
};
|
||||
|
||||
const verifyPassword = async (hash: string, password: string) => {
|
||||
return await argon2.verify(hash, password);
|
||||
};
|
||||
|
||||
export const changePassword = async (
|
||||
userId: number,
|
||||
sessionId: string,
|
||||
oldPassword: string,
|
||||
newPassword: string,
|
||||
) => {
|
||||
if (oldPassword === newPassword) {
|
||||
error(400, "Same passwords");
|
||||
} else if (newPassword.length < 8) {
|
||||
error(400, "Too short password");
|
||||
}
|
||||
|
||||
const user = await getUser(userId);
|
||||
if (!user) {
|
||||
error(500, "Invalid session id");
|
||||
} else if (!(await verifyPassword(user.password, oldPassword))) {
|
||||
error(403, "Invalid password");
|
||||
}
|
||||
|
||||
await setUserPassword(userId, await hashPassword(newPassword));
|
||||
await deleteAllOtherSessions(userId, sessionId);
|
||||
};
|
||||
|
||||
export const login = async (email: string, password: string, ip: string, userAgent: string) => {
|
||||
const user = await getUserByEmail(email);
|
||||
if (!user || !(await verifyPassword(user.password, password))) {
|
||||
error(401, "Invalid email or password");
|
||||
}
|
||||
|
||||
return { sessionIdSigned: await startSession(user.id, ip, userAgent) };
|
||||
};
|
||||
|
||||
export const logout = async (sessionId: string) => {
|
||||
await deleteSession(sessionId);
|
||||
};
|
||||
|
||||
export const createSessionUpgradeChallenge = async (
|
||||
sessionId: string,
|
||||
userId: number,
|
||||
ip: string,
|
||||
encPubKey: string,
|
||||
sigPubKey: string,
|
||||
) => {
|
||||
const client = await getClientByPubKeys(encPubKey, sigPubKey);
|
||||
const userClient = client ? await getUserClient(userId, client.id) : undefined;
|
||||
if (!client) {
|
||||
error(401, "Invalid public key(s)");
|
||||
} else if (!userClient || userClient.state === "challenging") {
|
||||
error(403, "Unregistered client");
|
||||
}
|
||||
|
||||
const { answer, challenge } = await generateChallenge(32, encPubKey);
|
||||
const { id } = await registerSessionUpgradeChallenge(
|
||||
sessionId,
|
||||
client.id,
|
||||
answer.toString("base64"),
|
||||
ip,
|
||||
new Date(Date.now() + env.challenge.sessionUpgradeExp),
|
||||
);
|
||||
|
||||
return { id, challenge: challenge.toString("base64") };
|
||||
};
|
||||
|
||||
export const verifySessionUpgradeChallenge = async (
|
||||
sessionId: string,
|
||||
userId: number,
|
||||
ip: string,
|
||||
challengeId: number,
|
||||
answerSig: string,
|
||||
force: boolean,
|
||||
) => {
|
||||
const challenge = await consumeSessionUpgradeChallenge(challengeId, sessionId, ip);
|
||||
if (!challenge) {
|
||||
error(403, "Invalid challenge answer");
|
||||
}
|
||||
|
||||
const client = await getClient(challenge.clientId);
|
||||
if (!client) {
|
||||
error(500, "Invalid challenge answer");
|
||||
} else if (
|
||||
!verifySignature(Buffer.from(challenge.answer, "base64"), answerSig, client.sigPubKey)
|
||||
) {
|
||||
error(403, "Invalid challenge answer signature");
|
||||
}
|
||||
|
||||
try {
|
||||
await upgradeSession(userId, sessionId, client.id, force);
|
||||
} catch (e) {
|
||||
if (e instanceof IntegrityError) {
|
||||
if (e.message === "Session not found") {
|
||||
error(500, "Invalid challenge answer");
|
||||
} else if (!force && e.message === "Session already exists") {
|
||||
error(409, "Already logged in");
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user