first commit
This commit is contained in:
108
backend/src/routes/account/api-keys.ts
Normal file
108
backend/src/routes/account/api-keys.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { COOKIENAME } from "../..";
|
||||
import { db, fileRouter } from "../../";
|
||||
import { authCheck } from "../../lib/Auth";
|
||||
import crypto from "crypto";
|
||||
|
||||
export = new fileRouter.Path("/")
|
||||
.http("GET", "/api/account/api-keys", (http) =>
|
||||
http.onRequest(async (ctr) => {
|
||||
const cookie = ctr.cookies.get(COOKIENAME) || null;
|
||||
const apiHeader = (ctr.headers && ctr.headers.get)
|
||||
? ctr.headers.get("api-authentication") || null
|
||||
: null;
|
||||
const auth = await authCheck(cookie, apiHeader);
|
||||
if (!auth.state) {
|
||||
return ctr.status(ctr.$status.UNAUTHORIZED).print({ error: auth.message });
|
||||
}
|
||||
|
||||
const user = await db.collection("users").findOne({ id: auth.userId });
|
||||
if (!user) {
|
||||
return ctr.status(ctr.$status.NOT_FOUND).print({ error: "User not found" });
|
||||
}
|
||||
|
||||
const keys = (user.apiKeys || []).map((k: any) => ({
|
||||
id: k.id,
|
||||
description: k.description,
|
||||
createdAt: k.createdAt,
|
||||
}));
|
||||
|
||||
return ctr.print({ success: true, apiKeys: keys });
|
||||
})
|
||||
)
|
||||
.http("POST", "/api/account/api-keys/create", (http) =>
|
||||
http.onRequest(async (ctr) => {
|
||||
const cookie = ctr.cookies.get(COOKIENAME) || null;
|
||||
const apiHeader = (ctr.headers && ctr.headers.get)
|
||||
? ctr.headers.get("api-authentication") || null
|
||||
: null;
|
||||
const auth = await authCheck(cookie, apiHeader);
|
||||
if (!auth.state) {
|
||||
return ctr.status(ctr.$status.UNAUTHORIZED).print({ error: auth.message });
|
||||
}
|
||||
|
||||
const [data, error] = await ctr.bindBody((z) =>
|
||||
z.object({ description: z.string().min(1).max(200) })
|
||||
);
|
||||
|
||||
if (!data) return ctr.status(ctr.$status.BAD_REQUEST).print({ error: error.toString() });
|
||||
|
||||
const user = await db.collection("users").findOne({ id: auth.userId });
|
||||
if (!user) return ctr.status(ctr.$status.NOT_FOUND).print({ error: "User not found" });
|
||||
|
||||
const existing = user.apiKeys || [];
|
||||
if (existing.length >= 4) {
|
||||
return ctr.status(ctr.$status.BAD_REQUEST).print({ error: "API key limit reached (max 4)" });
|
||||
}
|
||||
|
||||
const raw = crypto.randomBytes(32).toString("hex");
|
||||
const keyHash = crypto.createHash("sha256").update(raw).digest("hex");
|
||||
const keyId = crypto.randomUUID();
|
||||
|
||||
const newKey = {
|
||||
id: keyId,
|
||||
description: data.description,
|
||||
keyHash,
|
||||
createdAt: new Date(),
|
||||
};
|
||||
|
||||
const res = await db.collection("users").updateOne(
|
||||
{ id: auth.userId },
|
||||
{ $push: { apiKeys: newKey } } as any,
|
||||
{ upsert: false }
|
||||
);
|
||||
|
||||
if (!res.acknowledged) {
|
||||
return ctr.status(ctr.$status.INTERNAL_SERVER_ERROR).print({ error: "Failed to create API key" });
|
||||
}
|
||||
|
||||
return ctr.print({ success: true, apiKey: { id: keyId, description: data.description, createdAt: newKey.createdAt, token: raw } });
|
||||
})
|
||||
)
|
||||
.http("DELETE", "/api/account/api-keys/{id}", (http) =>
|
||||
http.onRequest(async (ctr) => {
|
||||
const cookie = ctr.cookies.get(COOKIENAME) || null;
|
||||
const apiHeader = (ctr.headers && ctr.headers.get)
|
||||
? ctr.headers.get("api-authentication") || null
|
||||
: null;
|
||||
const auth = await authCheck(cookie, apiHeader);
|
||||
if (!auth.state) {
|
||||
return ctr.status(ctr.$status.UNAUTHORIZED).print({ error: auth.message });
|
||||
}
|
||||
|
||||
const keyId = ctr.params.get("id");
|
||||
if (!keyId) return ctr.status(ctr.$status.BAD_REQUEST).print({ error: "Key id required" });
|
||||
|
||||
const res = await db.collection("users").updateOne(
|
||||
{ id: auth.userId },
|
||||
{ $pull: { apiKeys: { id: keyId } } } as any
|
||||
);
|
||||
|
||||
if (!res.acknowledged) {
|
||||
return ctr.status(ctr.$status.INTERNAL_SERVER_ERROR).print({ error: "Failed to delete API key" });
|
||||
}
|
||||
|
||||
return ctr.print({ success: true });
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user