mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-16 15:08:46 +00:00
Refresh Token 구현 변경
This commit is contained in:
@@ -5,8 +5,10 @@ import { client, userClient } from "./schema";
|
||||
export const createClient = async (pubKey: string, userId: number) => {
|
||||
await db.transaction(async (tx) => {
|
||||
const insertRes = await tx.insert(client).values({ pubKey }).returning({ id: client.id });
|
||||
const { id: clientId } = insertRes[0]!;
|
||||
await tx.insert(userClient).values({ userId, clientId });
|
||||
await tx.insert(userClient).values({
|
||||
userId,
|
||||
clientId: insertRes[0]!.id,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from "./client";
|
||||
export * from "./token";
|
||||
export * from "./user";
|
||||
|
||||
18
src/lib/server/db/schema/token.ts
Normal file
18
src/lib/server/db/schema/token.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { sqliteTable, text, integer, unique } from "drizzle-orm/sqlite-core";
|
||||
import { client } from "./client";
|
||||
import { user } from "./user";
|
||||
|
||||
export const refreshToken = sqliteTable(
|
||||
"refresh_token",
|
||||
{
|
||||
id: text("id").primaryKey(),
|
||||
userId: integer("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id),
|
||||
clientId: integer("client_id").references(() => client.id),
|
||||
expiresAt: integer("expires_at").notNull(), // Only used for cleanup
|
||||
},
|
||||
(t) => ({
|
||||
unq: unique().on(t.userId, t.clientId),
|
||||
}),
|
||||
);
|
||||
@@ -5,9 +5,3 @@ export const user = sqliteTable("user", {
|
||||
email: text("email").notNull().unique(),
|
||||
password: text("password").notNull(),
|
||||
});
|
||||
|
||||
export const revokedToken = sqliteTable("revoked_token", {
|
||||
id: integer("id").primaryKey(),
|
||||
token: text("token").notNull().unique(),
|
||||
revokedAt: integer("revoked_at").notNull(),
|
||||
});
|
||||
|
||||
75
src/lib/server/db/token.ts
Normal file
75
src/lib/server/db/token.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { SqliteError } from "better-sqlite3";
|
||||
import { eq, lte } from "drizzle-orm";
|
||||
import ms from "ms";
|
||||
import env from "$lib/server/loadenv";
|
||||
import db from "./drizzle";
|
||||
import { refreshToken } from "./schema";
|
||||
|
||||
const expiresIn = ms(env.jwt.refreshExp);
|
||||
const expiresAt = () => Date.now() + expiresIn;
|
||||
|
||||
export const registerRefreshToken = async (
|
||||
userId: number,
|
||||
clientId: number | null,
|
||||
tokenId: string,
|
||||
) => {
|
||||
try {
|
||||
await db
|
||||
.insert(refreshToken)
|
||||
.values({
|
||||
id: tokenId,
|
||||
userId,
|
||||
clientId,
|
||||
expiresAt: expiresAt(),
|
||||
})
|
||||
.execute();
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e instanceof SqliteError && e.code === "SQLITE_CONSTRAINT_UNIQUE") {
|
||||
return false;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export const getRefreshToken = async (tokenId: string) => {
|
||||
const tokens = await db.select().from(refreshToken).where(eq(refreshToken.id, tokenId)).execute();
|
||||
return tokens[0] ?? null;
|
||||
};
|
||||
|
||||
export const rotateRefreshToken = async (oldTokenId: string, newTokenId: string) => {
|
||||
const res = await db
|
||||
.update(refreshToken)
|
||||
.set({
|
||||
id: newTokenId,
|
||||
expiresAt: expiresAt(),
|
||||
})
|
||||
.where(eq(refreshToken.id, oldTokenId))
|
||||
.execute();
|
||||
return res.changes > 0;
|
||||
};
|
||||
|
||||
export const upgradeRefreshToken = async (
|
||||
oldTokenId: string,
|
||||
newTokenId: string,
|
||||
clientId: number,
|
||||
) => {
|
||||
const res = await db
|
||||
.update(refreshToken)
|
||||
.set({
|
||||
id: newTokenId,
|
||||
clientId,
|
||||
expiresAt: expiresAt(),
|
||||
})
|
||||
.where(eq(refreshToken.id, oldTokenId))
|
||||
.execute();
|
||||
return res.changes > 0;
|
||||
};
|
||||
|
||||
export const revokeRefreshToken = async (tokenId: string) => {
|
||||
await db.delete(refreshToken).where(eq(refreshToken.id, tokenId)).execute();
|
||||
};
|
||||
|
||||
export const cleanupExpiredRefreshTokens = async () => {
|
||||
await db.delete(refreshToken).where(lte(refreshToken.expiresAt, Date.now())).execute();
|
||||
};
|
||||
@@ -1,27 +1,8 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
import db from "./drizzle";
|
||||
import { user, revokedToken } from "./schema";
|
||||
import { user } from "./schema";
|
||||
|
||||
export const getUserByEmail = async (email: string) => {
|
||||
const users = await db.select().from(user).where(eq(user.email, email)).execute();
|
||||
return users[0] ?? null;
|
||||
};
|
||||
|
||||
export const revokeToken = async (token: string) => {
|
||||
await db
|
||||
.insert(revokedToken)
|
||||
.values({
|
||||
token,
|
||||
revokedAt: Date.now(),
|
||||
})
|
||||
.execute();
|
||||
};
|
||||
|
||||
export const isTokenRevoked = async (token: string) => {
|
||||
const tokens = await db
|
||||
.select()
|
||||
.from(revokedToken)
|
||||
.where(eq(revokedToken.token, token))
|
||||
.execute();
|
||||
return tokens.length > 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user