65 lines
1.5 KiB
TypeScript
65 lines
1.5 KiB
TypeScript
import { createHash, randomBytes } from "crypto";
|
|
import { prisma } from "./db";
|
|
|
|
const API_KEY_PREFIX = "s2yt_live_";
|
|
|
|
export function hashApiKey(token: string) {
|
|
return createHash("sha256").update(token).digest("hex");
|
|
}
|
|
|
|
export function generateApiKeyMaterial() {
|
|
const secret = randomBytes(24).toString("base64url");
|
|
const token = `${API_KEY_PREFIX}${secret}`;
|
|
return {
|
|
token,
|
|
hash: hashApiKey(token),
|
|
prefix: token.slice(0, 20),
|
|
};
|
|
}
|
|
|
|
export async function createUserApiKey(userId: string) {
|
|
const { token, hash, prefix } = generateApiKeyMaterial();
|
|
|
|
await prisma.user.update({
|
|
where: { id: userId },
|
|
data: {
|
|
apiKeyHash: hash,
|
|
apiKeyPrefix: prefix,
|
|
},
|
|
});
|
|
|
|
return { token, prefix };
|
|
}
|
|
|
|
export async function revokeUserApiKey(userId: string) {
|
|
await prisma.user.update({
|
|
where: { id: userId },
|
|
data: {
|
|
apiKeyHash: null,
|
|
apiKeyPrefix: null,
|
|
},
|
|
});
|
|
}
|
|
|
|
export async function getUserApiKeyStatus(userId: string) {
|
|
const user = await prisma.user.findUniqueOrThrow({
|
|
where: { id: userId },
|
|
select: { apiKeyPrefix: true, apiKeyHash: true },
|
|
});
|
|
|
|
return {
|
|
configured: Boolean(user.apiKeyHash),
|
|
prefix: user.apiKeyPrefix,
|
|
};
|
|
}
|
|
|
|
export async function findUserByApiKey(token: string) {
|
|
if (!token.startsWith(API_KEY_PREFIX)) return null;
|
|
|
|
const hash = hashApiKey(token);
|
|
return prisma.user.findFirst({
|
|
where: { apiKeyHash: hash },
|
|
include: { youtubeConnection: true },
|
|
});
|
|
}
|