This commit is contained in:
95
backend/src/api/controllers/ape-key.ts
Normal file
95
backend/src/api/controllers/ape-key.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { randomBytes } from "crypto";
|
||||
import { hash } from "bcrypt";
|
||||
import * as ApeKeysDAL from "../../dal/ape-keys";
|
||||
import MonkeyError from "../../utils/error";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import { base64UrlEncode, omit } from "../../utils/misc";
|
||||
import { ObjectId } from "mongodb";
|
||||
|
||||
import {
|
||||
AddApeKeyRequest,
|
||||
AddApeKeyResponse,
|
||||
ApeKeyParams,
|
||||
EditApeKeyRequest,
|
||||
GetApeKeyResponse,
|
||||
} from "@monkeytype/contracts/ape-keys";
|
||||
import { ApeKey } from "@monkeytype/schemas/ape-keys";
|
||||
import { MonkeyRequest } from "../types";
|
||||
|
||||
function cleanApeKey(apeKey: ApeKeysDAL.DBApeKey): ApeKey {
|
||||
return omit(apeKey, ["hash", "_id", "uid", "useCount"]);
|
||||
}
|
||||
|
||||
export async function getApeKeys(
|
||||
req: MonkeyRequest,
|
||||
): Promise<GetApeKeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const apeKeys = await ApeKeysDAL.getApeKeys(uid);
|
||||
const cleanedKeys: Record<string, ApeKey> = Object.fromEntries(
|
||||
apeKeys.map((item) => [item._id.toHexString(), cleanApeKey(item)]),
|
||||
);
|
||||
|
||||
return new MonkeyResponse("ApeKeys retrieved", cleanedKeys);
|
||||
}
|
||||
|
||||
export async function generateApeKey(
|
||||
req: MonkeyRequest<undefined, AddApeKeyRequest>,
|
||||
): Promise<AddApeKeyResponse> {
|
||||
const { name, enabled } = req.body;
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { maxKeysPerUser, apeKeyBytes, apeKeySaltRounds } =
|
||||
req.ctx.configuration.apeKeys;
|
||||
|
||||
const currentNumberOfApeKeys = await ApeKeysDAL.countApeKeysForUser(uid);
|
||||
|
||||
if (currentNumberOfApeKeys >= maxKeysPerUser) {
|
||||
throw new MonkeyError(409, "Maximum number of ApeKeys have been generated");
|
||||
}
|
||||
|
||||
const apiKey = randomBytes(apeKeyBytes).toString("base64url");
|
||||
const saltyHash = await hash(apiKey, apeKeySaltRounds);
|
||||
|
||||
const apeKey: ApeKeysDAL.DBApeKey = {
|
||||
_id: new ObjectId(),
|
||||
name,
|
||||
enabled,
|
||||
uid,
|
||||
hash: saltyHash,
|
||||
createdOn: Date.now(),
|
||||
modifiedOn: Date.now(),
|
||||
lastUsedOn: -1,
|
||||
useCount: 0,
|
||||
};
|
||||
|
||||
const apeKeyId = await ApeKeysDAL.addApeKey(apeKey);
|
||||
|
||||
return new MonkeyResponse("ApeKey generated", {
|
||||
apeKey: base64UrlEncode(`${apeKeyId}.${apiKey}`),
|
||||
apeKeyId,
|
||||
apeKeyDetails: cleanApeKey(apeKey),
|
||||
});
|
||||
}
|
||||
|
||||
export async function editApeKey(
|
||||
req: MonkeyRequest<undefined, EditApeKeyRequest, ApeKeyParams>,
|
||||
): Promise<MonkeyResponse> {
|
||||
const { apeKeyId } = req.params;
|
||||
const { name, enabled } = req.body;
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
await ApeKeysDAL.editApeKey(uid, apeKeyId, name, enabled);
|
||||
|
||||
return new MonkeyResponse("ApeKey updated", null);
|
||||
}
|
||||
|
||||
export async function deleteApeKey(
|
||||
req: MonkeyRequest<undefined, undefined, ApeKeyParams>,
|
||||
): Promise<MonkeyResponse> {
|
||||
const { apeKeyId } = req.params;
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
await ApeKeysDAL.deleteApeKey(uid, apeKeyId);
|
||||
|
||||
return new MonkeyResponse("ApeKey deleted", null);
|
||||
}
|
||||
Reference in New Issue
Block a user