feat: changed backend-pg to backend

This commit is contained in:
Akhil Mohan
2024-01-27 19:14:33 +05:30
parent d13eafcef7
commit 66d258f02b
792 changed files with 40298 additions and 40607 deletions
@@ -0,0 +1,10 @@
import { TDbClient } from "@app/db";
import { TableName } from "@app/db/schemas";
import { ormify } from "@app/lib/knex";
export type TServiceTokenDALFactory = ReturnType<typeof serviceTokenDALFactory>;
export const serviceTokenDALFactory = (db: TDbClient) => {
const stOrm = ormify(db, TableName.ServiceToken);
return stOrm;
};
@@ -0,0 +1,165 @@
import crypto from "node:crypto";
import { ForbiddenError, subject } from "@casl/ability";
import bcrypt from "bcrypt";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import {
ProjectPermissionActions,
ProjectPermissionSub
} from "@app/ee/services/permission/project-permission";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
import { ActorType } from "../auth/auth-type";
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
import { TServiceTokenDALFactory } from "./service-token-dal";
import {
TCreateServiceTokenDTO,
TDeleteServiceTokenDTO,
TGetServiceTokenInfoDTO,
TProjectServiceTokensDTO
} from "./service-token-types";
type TServiceTokenServiceFactoryDep = {
serviceTokenDAL: TServiceTokenDALFactory;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
projectEnvDAL: Pick<TProjectEnvDALFactory, "findBySlugs">;
};
export type TServiceTokenServiceFactory = ReturnType<typeof serviceTokenServiceFactory>;
export const serviceTokenServiceFactory = ({
serviceTokenDAL,
permissionService,
projectEnvDAL
}: TServiceTokenServiceFactoryDep) => {
const createServiceToken = async ({
iv,
tag,
name,
actor,
scopes,
actorId,
projectId,
expiresIn,
permissions,
encryptedKey
}: TCreateServiceTokenDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
ProjectPermissionSub.ServiceTokens
);
scopes.forEach(({ environment, secretPath }) => {
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
);
})
const appCfg = getConfig();
// validates env
const scopeEnvs = [...new Set(scopes.map(({ environment }) => environment))];
const inputEnvs = await projectEnvDAL.findBySlugs(projectId, scopeEnvs);
if (inputEnvs.length !== scopeEnvs.length)
throw new BadRequestError({ message: "Environment not found" });
const secret = crypto.randomBytes(16).toString("hex");
const secretHash = await bcrypt.hash(secret, appCfg.SALT_ROUNDS);
let expiresAt: Date | null = null;
if (expiresIn) {
expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);
}
const createdBy = actorId;
const serviceToken = await serviceTokenDAL.create({
name,
createdBy,
encryptedKey,
iv,
tag,
expiresAt,
secretHash,
permissions,
scopes: JSON.stringify(scopes),
projectId
});
const token = `st.${serviceToken.id.toString()}.${secret}`;
return { token, serviceToken };
};
const deleteServiceToken = async ({ actorId, actor, id }: TDeleteServiceTokenDTO) => {
const serviceToken = await serviceTokenDAL.findById(id);
if (!serviceToken) throw new BadRequestError({ message: "Token not found" });
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
serviceToken.projectId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
ProjectPermissionSub.ServiceTokens
);
const deletedServiceToken = await serviceTokenDAL.deleteById(id);
return deletedServiceToken;
};
const getServiceToken = async ({ actor, actorId }: TGetServiceTokenInfoDTO) => {
if (actor !== ActorType.SERVICE)
throw new BadRequestError({ message: "Service token not found" });
const serviceToken = await serviceTokenDAL.findById(actorId);
if (!serviceToken) throw new BadRequestError({ message: "Token not found" });
return serviceToken;
};
const getProjectServiceTokens = async ({
actorId,
actor,
projectId
}: TProjectServiceTokensDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
ProjectPermissionSub.ServiceTokens
);
const tokens = await serviceTokenDAL.find({ projectId });
return tokens;
};
const fnValidateServiceToken = async (token: string) => {
const [, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>token.split(".", 3);
const serviceToken = await serviceTokenDAL.findById(TOKEN_IDENTIFIER);
if (!serviceToken) throw new UnauthorizedError();
if (serviceToken.expiresAt && new Date(serviceToken.expiresAt) < new Date()) {
await serviceTokenDAL.deleteById(serviceToken.id);
throw new UnauthorizedError({ message: "failed to authenticate expired service token" });
}
const isMatch = await bcrypt.compare(TOKEN_SECRET, serviceToken.secretHash);
if (!isMatch) throw new UnauthorizedError();
const updatedToken = await serviceTokenDAL.updateById(serviceToken.id, {
lastUsed: new Date()
});
return updatedToken;
};
return {
createServiceToken,
deleteServiceToken,
getServiceToken,
getProjectServiceTokens,
fnValidateServiceToken
};
};
@@ -0,0 +1,19 @@
import { TProjectPermission } from "@app/lib/types";
export type TCreateServiceTokenDTO = {
name: string;
scopes: Array<{ environment: string; secretPath: string }>;
encryptedKey: string;
iv: string;
tag: string;
expiresIn?: number | null;
permissions: ("read" | "write")[];
} & TProjectPermission;
export type TGetServiceTokenInfoDTO = Omit<TProjectPermission, "projectId">;
export type TDeleteServiceTokenDTO = {
id: string;
} & Omit<TProjectPermission, "projectId">;
export type TProjectServiceTokensDTO = TProjectPermission;