0817b0c7a5
Co-authored-by: Claude <noreply@anthropic.com>
108 lines
2.3 KiB
TypeScript
108 lines
2.3 KiB
TypeScript
import { ApiPermission } from "@prisma/client";
|
|
import { db } from "../db";
|
|
import { randomBytes } from "crypto";
|
|
import { smallNanoid } from "../nanoid";
|
|
import { createSecureHash, verifySecureHash } from "../crypto";
|
|
import { logger } from "../logger/log";
|
|
|
|
export async function addApiKey({
|
|
name,
|
|
permission,
|
|
teamId,
|
|
domainId,
|
|
}: {
|
|
name: string;
|
|
permission: ApiPermission;
|
|
teamId: number;
|
|
domainId?: number;
|
|
}) {
|
|
try {
|
|
// Validate domain ownership if domainId is provided
|
|
if (domainId !== undefined) {
|
|
const domain = await db.domain.findUnique({
|
|
where: {
|
|
id: domainId,
|
|
teamId: teamId
|
|
},
|
|
select: { id: true },
|
|
});
|
|
|
|
if (!domain) {
|
|
throw new Error("DOMAIN_NOT_FOUND");
|
|
}
|
|
}
|
|
|
|
const clientId = smallNanoid(10);
|
|
const token = randomBytes(16).toString("hex");
|
|
const hashedToken = await createSecureHash(token);
|
|
|
|
const apiKey = `us_${clientId}_${token}`;
|
|
|
|
await db.apiKey.create({
|
|
data: {
|
|
name,
|
|
permission: permission,
|
|
teamId,
|
|
domainId,
|
|
tokenHash: hashedToken,
|
|
partialToken: `${apiKey.slice(0, 6)}...${apiKey.slice(-3)}`,
|
|
clientId,
|
|
},
|
|
});
|
|
return apiKey;
|
|
} catch (error) {
|
|
logger.error({ err: error }, "Error adding API key");
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function getTeamAndApiKey(apiKey: string) {
|
|
const [, clientId, token] = apiKey.split("_") as [string, string, string];
|
|
|
|
const apiKeyRow = await db.apiKey.findUnique({
|
|
where: {
|
|
clientId,
|
|
},
|
|
include: {
|
|
domain: {
|
|
select: { id: true, name: true },
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!apiKeyRow) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
const isValid = await verifySecureHash(token, apiKeyRow.tokenHash);
|
|
if (!isValid) {
|
|
return null;
|
|
}
|
|
|
|
const team = await db.team.findUnique({
|
|
where: {
|
|
id: apiKeyRow.teamId,
|
|
},
|
|
});
|
|
|
|
return { team, apiKey: apiKeyRow };
|
|
} catch (error) {
|
|
logger.error({ err: error }, "Error verifying API key");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function deleteApiKey(id: number) {
|
|
try {
|
|
await db.apiKey.delete({
|
|
where: {
|
|
id,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
logger.error({ err: error }, "Error deleting API key");
|
|
throw error;
|
|
}
|
|
}
|