mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-14 22:08:45 +00:00
암호 키 등록 챌린지 처리 방식을 세션 업그레이드 챌린지 처리 방식과 동일하게 변경
This commit is contained in:
@@ -119,26 +119,21 @@ export const registerUserClientChallenge = async (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getUserClientChallenge = async (answer: string, ip: string) => {
|
export const consumeUserClientChallenge = async (userId: number, answer: string, ip: string) => {
|
||||||
const challenges = await db
|
const challenges = await db
|
||||||
.select()
|
.delete(userClientChallenge)
|
||||||
.from(userClientChallenge)
|
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
|
eq(userClientChallenge.userId, userId),
|
||||||
eq(userClientChallenge.answer, answer),
|
eq(userClientChallenge.answer, answer),
|
||||||
eq(userClientChallenge.allowedIp, ip),
|
eq(userClientChallenge.allowedIp, ip),
|
||||||
gt(userClientChallenge.expiresAt, new Date()),
|
gt(userClientChallenge.expiresAt, new Date()),
|
||||||
eq(userClientChallenge.isUsed, false),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.limit(1);
|
.returning({ clientId: userClientChallenge.clientId });
|
||||||
return challenges[0] ?? null;
|
return challenges[0] ?? null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const markUserClientChallengeAsUsed = async (id: number) => {
|
|
||||||
await db.update(userClientChallenge).set({ isUsed: true }).where(eq(userClientChallenge.id, id));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const cleanupExpiredUserClientChallenges = async () => {
|
export const cleanupExpiredUserClientChallenges = async () => {
|
||||||
await db.delete(userClientChallenge).where(lte(userClientChallenge.expiresAt, new Date()));
|
await db.delete(userClientChallenge).where(lte(userClientChallenge.expiresAt, new Date()));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
import { sqliteTable, text, integer, primaryKey, unique } from "drizzle-orm/sqlite-core";
|
import {
|
||||||
|
sqliteTable,
|
||||||
|
text,
|
||||||
|
integer,
|
||||||
|
primaryKey,
|
||||||
|
foreignKey,
|
||||||
|
unique,
|
||||||
|
} from "drizzle-orm/sqlite-core";
|
||||||
import { user } from "./user";
|
import { user } from "./user";
|
||||||
|
|
||||||
export const client = sqliteTable(
|
export const client = sqliteTable(
|
||||||
@@ -31,16 +38,24 @@ export const userClient = sqliteTable(
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const userClientChallenge = sqliteTable("user_client_challenge", {
|
export const userClientChallenge = sqliteTable(
|
||||||
id: integer("id").primaryKey(),
|
"user_client_challenge",
|
||||||
userId: integer("user_id")
|
{
|
||||||
.notNull()
|
id: integer("id").primaryKey(),
|
||||||
.references(() => user.id),
|
userId: integer("user_id")
|
||||||
clientId: integer("client_id")
|
.notNull()
|
||||||
.notNull()
|
.references(() => user.id),
|
||||||
.references(() => client.id),
|
clientId: integer("client_id")
|
||||||
answer: text("answer").notNull().unique(), // Base64
|
.notNull()
|
||||||
allowedIp: text("allowed_ip").notNull(),
|
.references(() => client.id),
|
||||||
expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(),
|
answer: text("answer").notNull().unique(), // Base64
|
||||||
isUsed: integer("is_used", { mode: "boolean" }).notNull().default(false),
|
allowedIp: text("allowed_ip").notNull(),
|
||||||
});
|
expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(),
|
||||||
|
},
|
||||||
|
(t) => ({
|
||||||
|
ref: foreignKey({
|
||||||
|
columns: [t.userId, t.clientId],
|
||||||
|
foreignColumns: [userClient.userId, userClient.clientId],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ import {
|
|||||||
getUserClient,
|
getUserClient,
|
||||||
setUserClientStateToPending,
|
setUserClientStateToPending,
|
||||||
registerUserClientChallenge,
|
registerUserClientChallenge,
|
||||||
getUserClientChallenge,
|
consumeUserClientChallenge,
|
||||||
markUserClientChallengeAsUsed,
|
|
||||||
} from "$lib/server/db/client";
|
} from "$lib/server/db/client";
|
||||||
import { IntegrityError } from "$lib/server/db/error";
|
import { IntegrityError } from "$lib/server/db/error";
|
||||||
import { verifyPubKey, verifySignature, generateChallenge } from "$lib/server/modules/crypto";
|
import { verifyPubKey, verifySignature, generateChallenge } from "$lib/server/modules/crypto";
|
||||||
@@ -81,15 +80,11 @@ export const verifyUserClient = async (
|
|||||||
answer: string,
|
answer: string,
|
||||||
answerSig: string,
|
answerSig: string,
|
||||||
) => {
|
) => {
|
||||||
const challenge = await getUserClientChallenge(answer, ip);
|
const challenge = await consumeUserClientChallenge(userId, answer, ip);
|
||||||
if (!challenge) {
|
if (!challenge) {
|
||||||
error(403, "Invalid challenge answer");
|
error(403, "Invalid challenge answer");
|
||||||
} else if (challenge.userId !== userId) {
|
|
||||||
error(403, "Forbidden");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await markUserClientChallengeAsUsed(challenge.id);
|
|
||||||
|
|
||||||
const client = await getClient(challenge.clientId);
|
const client = await getClient(challenge.clientId);
|
||||||
if (!client) {
|
if (!client) {
|
||||||
error(500, "Invalid challenge answer");
|
error(500, "Invalid challenge answer");
|
||||||
@@ -97,7 +92,7 @@ export const verifyUserClient = async (
|
|||||||
error(403, "Invalid challenge answer signature");
|
error(403, "Invalid challenge answer signature");
|
||||||
}
|
}
|
||||||
|
|
||||||
await setUserClientStateToPending(userId, challenge.clientId);
|
await setUserClientStateToPending(userId, client.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getUserClientStatus = async (userId: number, clientId: number) => {
|
export const getUserClientStatus = async (userId: number, clientId: number) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user