feat: added back identity service

This commit is contained in:
=
2025-10-23 19:21:12 +05:30
parent acc357e7e3
commit e4be6b2f28
7 changed files with 720 additions and 1 deletions

View File

@@ -0,0 +1,21 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
const hasProjectIdCol = await knex.schema.hasColumn(TableName.Identity, "projectId");
if (!hasProjectIdCol) {
await knex.schema.alterTable(TableName.Identity, (t) => {
t.string("projectId");
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
});
}
}
export async function down(knex: Knex): Promise<void> {
const hasProjectIdCol = await knex.schema.hasColumn(TableName.Identity, "projectId");
if (hasProjectIdCol) {
await knex.schema.alterTable(TableName.Identity, (t) => {
t.dropColumn("projectId");
});
}
}

View File

@@ -14,7 +14,8 @@ export const IdentitiesSchema = z.object({
createdAt: z.date(),
updatedAt: z.date(),
hasDeleteProtection: z.boolean().default(false),
orgId: z.string().uuid()
orgId: z.string().uuid(),
projectId: z.string().nullable().optional()
});
export type TIdentities = z.infer<typeof IdentitiesSchema>;

View File

@@ -0,0 +1,185 @@
import { TDbClient } from "@app/db";
import { AccessScope, AccessScopeData, IdentitiesSchema, TableName } from "@app/db/schemas";
import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
import { buildAuthMethods } from "../identity/identity-fns";
export type TIdentityDALFactory = ReturnType<typeof identityDALFactory>;
export const identityDALFactory = (db: TDbClient) => {
const orm = ormify(db, TableName.Identity);
const getIdentityById = async (scopeData: AccessScopeData, identityId: string) => {
const doc = await db
.replicaNode()(TableName.Identity)
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
void queryBuilder
.on(`${TableName.Identity}.id`, `${TableName.IdentityMetadata}.identityId`)
.andOn(`${TableName.Identity}.orgId`, `${TableName.IdentityMetadata}.orgId`);
})
.leftJoin(
TableName.IdentityUniversalAuth,
`${TableName.Identity}.id`,
`${TableName.IdentityUniversalAuth}.identityId`
)
.leftJoin(TableName.IdentityGcpAuth, `${TableName.Identity}.id`, `${TableName.IdentityGcpAuth}.identityId`)
.leftJoin(
TableName.IdentityAliCloudAuth,
`${TableName.Identity}.id`,
`${TableName.IdentityAliCloudAuth}.identityId`
)
.leftJoin(TableName.IdentityAwsAuth, `${TableName.Identity}.id`, `${TableName.IdentityAwsAuth}.identityId`)
.leftJoin(
TableName.IdentityKubernetesAuth,
`${TableName.Identity}.id`,
`${TableName.IdentityKubernetesAuth}.identityId`
)
.leftJoin(TableName.IdentityOciAuth, `${TableName.Identity}.id`, `${TableName.IdentityOciAuth}.identityId`)
.leftJoin(TableName.IdentityOidcAuth, `${TableName.Identity}.id`, `${TableName.IdentityOidcAuth}.identityId`)
.leftJoin(TableName.IdentityAzureAuth, `${TableName.Identity}.id`, `${TableName.IdentityAzureAuth}.identityId`)
.leftJoin(TableName.IdentityTokenAuth, `${TableName.Identity}.id`, `${TableName.IdentityTokenAuth}.identityId`)
.leftJoin(
TableName.IdentityTlsCertAuth,
`${TableName.Identity}.id`,
`${TableName.IdentityTlsCertAuth}.identityId`
)
.leftJoin(TableName.IdentityLdapAuth, `${TableName.Identity}.id`, `${TableName.IdentityLdapAuth}.identityId`)
.leftJoin(TableName.IdentityJwtAuth, `${TableName.Identity}.id`, `${TableName.IdentityJwtAuth}.identityId`)
.where(`${TableName.Identity}.id`, identityId)
.where(`${TableName.Identity}.orgId`, scopeData.orgId)
.where((qb) => {
if (scopeData.scope === AccessScope.Project) {
void qb.where(`${TableName.Identity}.projectId`, scopeData.projectId);
} else {
void qb.whereNull(`${TableName.Identity}.projectId`);
}
})
.select(
selectAllTableCols(TableName.Identity),
db.ref("id").withSchema(TableName.IdentityMetadata).as("metadataId"),
db.ref("key").withSchema(TableName.IdentityMetadata).as("metadataKey"),
db.ref("value").withSchema(TableName.IdentityMetadata).as("metadataValue"),
db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth),
db.ref("id").as("gcpId").withSchema(TableName.IdentityGcpAuth),
db.ref("id").as("alicloudId").withSchema(TableName.IdentityAliCloudAuth),
db.ref("id").as("awsId").withSchema(TableName.IdentityAwsAuth),
db.ref("id").as("kubernetesId").withSchema(TableName.IdentityKubernetesAuth),
db.ref("id").as("ociId").withSchema(TableName.IdentityOciAuth),
db.ref("id").as("oidcId").withSchema(TableName.IdentityOidcAuth),
db.ref("id").as("azureId").withSchema(TableName.IdentityAzureAuth),
db.ref("id").as("tokenId").withSchema(TableName.IdentityTokenAuth),
db.ref("id").as("jwtId").withSchema(TableName.IdentityJwtAuth),
db.ref("id").as("ldapId").withSchema(TableName.IdentityLdapAuth),
db.ref("id").as("tlsCertId").withSchema(TableName.IdentityTlsCertAuth)
);
if (!doc) return doc;
const formattedDoc = sqlNestRelationships({
data: doc,
key: "id",
parentMapper: (el) => {
const {
uaId,
awsId,
gcpId,
kubernetesId,
oidcId,
azureId,
alicloudId,
tokenId,
jwtId,
ociId,
ldapId,
tlsCertId
} = el;
return {
...IdentitiesSchema.parse(el),
authMethods: buildAuthMethods({
uaId,
awsId,
gcpId,
kubernetesId,
oidcId,
azureId,
tokenId,
alicloudId,
jwtId,
ldapId,
ociId,
tlsCertId
})
};
},
childrenMapper: [
{
key: "metadataId",
label: "metadata" as const,
mapper: ({ metadataKey, metadataValue, metadataId }) => ({
id: metadataId,
key: metadataKey,
value: metadataValue
})
}
]
});
return formattedDoc?.[0];
};
const listIdentities = async (
scopeData: AccessScopeData,
filter: { limit?: number; offset?: number; search?: string } = {}
) => {
const query = db
.replicaNode()(TableName.Identity)
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
void queryBuilder
.on(`${TableName.Identity}.id`, `${TableName.IdentityMetadata}.identityId`)
.andOn(`${TableName.Identity}.orgId`, `${TableName.IdentityMetadata}.orgId`);
})
.where(`${TableName.Identity}.orgId`, scopeData.orgId)
.where((qb) => {
if (scopeData.scope === AccessScope.Project) {
void qb.where(`${TableName.Identity}.projectId`, scopeData.projectId);
} else {
void qb.whereNull(`${TableName.Identity}.projectId`);
}
})
.select(
selectAllTableCols(TableName.Identity),
db.ref("id").withSchema(TableName.IdentityMetadata).as("metadataId"),
db.ref("key").withSchema(TableName.IdentityMetadata).as("metadataKey"),
db.ref("value").withSchema(TableName.IdentityMetadata).as("metadataValue")
)
.select(db.raw(`count(distinct ??) over () as ??`, [`${TableName.Identity}.id`, "count"]));
if (filter.limit) void query.limit(filter.limit);
if (filter.offset) void query.offset(filter.offset || 0);
if (filter.search) void query.whereILike(`${TableName.Identity}.name`, `%${filter.search}%`);
const docs = await query;
const formattedDoc = sqlNestRelationships({
data: docs,
key: "id",
parentMapper: (el) => IdentitiesSchema.parse(el),
childrenMapper: [
{
key: "metadataId",
label: "metadata" as const,
mapper: ({ metadataKey, metadataValue, metadataId }) => ({
id: metadataId,
key: metadataKey,
value: metadataValue
})
}
]
});
return { docs: formattedDoc, count: Number((docs?.[0] as unknown as { count: number })?.count) };
};
return { ...orm, listIdentities, getIdentityById };
};

View File

@@ -0,0 +1,245 @@
import { AccessScope, OrgMembershipRole } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { TIdentityMetadataDALFactory } from "../identity/identity-metadata-dal";
import { TMembershipRoleDALFactory } from "../membership/membership-role-dal";
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
import { TIdentityDALFactory } from "./identity-dal";
import {
TCreateIdentityDTO,
TDeleteIdentityDTO,
TGetIdentityByIdDTO,
TListIdentityDTO,
TUpdateIdentityDTO
} from "./identity-types";
import { newOrgIdentityFactory } from "./org/org-identity-factory";
import { newProjectIdentityFactory } from "./project/project-identity-factory";
type TScopedIdentityServiceFactoryDep = {
identityDAL: TIdentityDALFactory;
permissionService: TPermissionServiceFactory;
licenseService: Pick<TLicenseServiceFactory, "getPlan" | "updateSubscriptionOrgMemberCount">;
membershipIdentityDAL: TMembershipIdentityDALFactory;
membershipRoleDAL: TMembershipRoleDALFactory;
identityMetadataDAL: TIdentityMetadataDALFactory;
};
export type TScopedIdentityServiceFactory = ReturnType<typeof identityServiceFactory>;
export const identityServiceFactory = ({
identityDAL,
permissionService,
licenseService,
membershipIdentityDAL,
membershipRoleDAL,
identityMetadataDAL
}: TScopedIdentityServiceFactoryDep) => {
const orgFactory = newOrgIdentityFactory({
permissionService
});
const projectFactory = newProjectIdentityFactory({
permissionService
});
const scopeFactory = {
[AccessScope.Organization]: orgFactory,
[AccessScope.Project]: projectFactory,
// namespace will get stripped off
[AccessScope.Namespace]: orgFactory
};
const createIdentity = async (dto: TCreateIdentityDTO) => {
const { scopeData, data } = dto;
const factory = scopeFactory[scopeData.scope];
await factory.onCreateIdentityGuard(dto);
const plan = await licenseService.getPlan(dto.permission.orgId);
if (plan?.slug !== "enterprise" && plan?.identityLimit && plan.identitiesUsed >= plan.identityLimit) {
// limit imposed on number of identities allowed / number of identities used exceeds the number of identities allowed
throw new BadRequestError({
message: "Failed to create identity due to identity limit reached. Upgrade plan to create more identities."
});
}
const identity = await identityDAL.transaction(async (tx) => {
const newIdentity = await identityDAL.create(
{
name: data.name,
hasDeleteProtection: data.hasDeleteProtection,
orgId: dto.permission.orgId,
projectId: scopeData.scope === AccessScope.Project ? scopeData.projectId : null
},
tx
);
const orgMembership = await membershipIdentityDAL.create(
{
scope: AccessScope.Organization,
actorIdentityId: newIdentity.id,
scopeOrgId: dto.permission.orgId
},
tx
);
const newMembershipIds = [orgMembership.id];
if (scopeData.scope === AccessScope.Project) {
const projectMembership = await membershipIdentityDAL.create(
{
scope: AccessScope.Project,
actorIdentityId: newIdentity.id,
scopeOrgId: dto.permission.orgId,
scopeProjectId: scopeData.projectId
},
tx
);
newMembershipIds.push(projectMembership.id);
}
await membershipRoleDAL.insertMany(
newMembershipIds.map((membershipId) => ({
membershipId,
role: OrgMembershipRole.NoAccess
})),
tx
);
let insertedMetadata: Array<{
id: string;
key: string;
value: string;
}> = [];
if (data.metadata && data.metadata.length) {
const rowsToInsert = data.metadata.map(({ key, value }) => ({
identityId: newIdentity.id,
orgId: dto.permission.orgId,
key,
value
}));
insertedMetadata = await identityMetadataDAL.insertMany(rowsToInsert, tx);
}
return {
...newIdentity,
authMethods: [],
metadata: insertedMetadata
};
});
await licenseService.updateSubscriptionOrgMemberCount(dto.permission.orgId);
return { identity };
};
const updateIdentity = async (dto: TUpdateIdentityDTO) => {
const { scopeData, data } = dto;
const factory = scopeFactory[scopeData.scope];
await factory.onUpdateIdentityGuard(dto);
const existingIdentity = await identityDAL.findOne({
id: dto.selector.identityId,
orgId: dto.permission.orgId,
projectId: dto.scopeData.scope === AccessScope.Project ? dto.scopeData.projectId : null
});
if (!existingIdentity)
throw new NotFoundError({ message: `Identity with id ${dto.selector.identityId} not found` });
const identity = await identityDAL.transaction(async (tx) => {
const newIdentity =
data?.name || data?.hasDeleteProtection
? await identityDAL.updateById(
dto.selector.identityId,
{ name: data.name, hasDeleteProtection: data.hasDeleteProtection },
tx
)
: existingIdentity;
let insertedMetadata: Array<{
id: string;
key: string;
value: string;
}> = [];
if (data.metadata) {
await identityMetadataDAL.delete({ orgId: dto.permission.orgId, identityId: dto.selector.identityId }, tx);
if (data.metadata.length) {
const rowsToInsert = data.metadata.map(({ key, value }) => ({
identityId: newIdentity.id,
orgId: dto.permission.orgId,
key,
value
}));
insertedMetadata = await identityMetadataDAL.insertMany(rowsToInsert, tx);
}
}
return {
...newIdentity,
metadata: insertedMetadata
};
});
return { identity };
};
const deleteIdentity = async (dto: TDeleteIdentityDTO) => {
const { scopeData } = dto;
const factory = scopeFactory[scopeData.scope];
await factory.onDeleteIdentityGuard(dto);
const existingIdentity = await identityDAL.findOne({
id: dto.selector.identityId,
orgId: dto.permission.orgId,
projectId: dto.scopeData.scope === AccessScope.Project ? dto.scopeData.projectId : null
});
if (!existingIdentity)
throw new NotFoundError({ message: `Identity with id ${dto.selector.identityId} not found` });
const deletedIdentity = await identityDAL.deleteById(dto.selector.identityId);
await licenseService.updateSubscriptionOrgMemberCount(scopeData.orgId);
return { identity: deletedIdentity };
};
const getIdentityById = async (dto: TGetIdentityByIdDTO) => {
const { scopeData } = dto;
const factory = scopeFactory[scopeData.scope];
await factory.onGetIdentityByIdGuard(dto);
const identity = await identityDAL.getIdentityById(dto.scopeData, dto.selector.identityId);
if (!identity) throw new NotFoundError({ message: `Identity with id ${dto.selector.identityId} not found` });
return { identity };
};
const listIdentities = async (dto: TListIdentityDTO) => {
const { scopeData } = dto;
const factory = scopeFactory[scopeData.scope];
await factory.onListIdentityGuard(dto);
const identities = await identityDAL.listIdentities(dto.scopeData, {
search: dto.data.search,
offset: dto.data.offset,
limit: dto.data.limit
});
return { identities };
};
return {
createIdentity,
updateIdentity,
deleteIdentity,
getIdentityById,
listIdentities
};
};

View File

@@ -0,0 +1,67 @@
import { AccessScopeData } from "@app/db/schemas";
import { OrderByDirection, OrgServiceActor } from "@app/lib/types";
export interface TIdentityFactory {
onCreateIdentityGuard: (arg: TCreateIdentityDTO) => Promise<void>;
onUpdateIdentityGuard: (arg: TUpdateIdentityDTO) => Promise<void>;
onDeleteIdentityGuard: (arg: TDeleteIdentityDTO) => Promise<void>;
onListIdentityGuard: (arg: TListIdentityDTO) => Promise<void>;
onGetIdentityByIdGuard: (arg: TGetIdentityByIdDTO) => Promise<void>;
getScopeField: (scope: AccessScopeData) => { key: "orgId" | "namespaceId" | "projectId"; value: string };
}
export enum IdentityOrderBy {
Name = "name",
Role = "role"
}
export type TCreateIdentityDTO = {
permission: OrgServiceActor;
scopeData: AccessScopeData;
data: {
name: string;
hasDeleteProtection: boolean;
metadata?: { key: string; value: string }[];
};
};
export type TUpdateIdentityDTO = {
permission: OrgServiceActor;
scopeData: AccessScopeData;
selector: {
identityId: string;
};
data: Partial<{
name: string;
hasDeleteProtection: boolean;
metadata?: { key: string; value: string }[];
}>;
};
export type TDeleteIdentityDTO = {
permission: OrgServiceActor;
scopeData: AccessScopeData;
selector: {
identityId: string;
};
};
export type TGetIdentityByIdDTO = {
permission: OrgServiceActor;
scopeData: AccessScopeData;
selector: {
identityId: string;
};
};
export type TListIdentityDTO = {
permission: OrgServiceActor;
scopeData: AccessScopeData;
data: Partial<{
limit: number;
offset: number;
orderBy: IdentityOrderBy;
orderDirection: OrderByDirection;
search: string;
}>;
};

View File

@@ -0,0 +1,90 @@
import { ForbiddenError } from "@casl/ability";
import { AccessScope, OrganizationActionScope } from "@app/db/schemas";
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { InternalServerError } from "@app/lib/errors";
import { TIdentityFactory } from "../identity-types";
type TOrgIdentityFactoryDep = {
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
};
export const newOrgIdentityFactory = ({ permissionService }: TOrgIdentityFactoryDep): TIdentityFactory => {
const getScopeField: TIdentityFactory["getScopeField"] = (scopeData) => {
if (scopeData.scope === AccessScope.Organization) {
return { key: "orgId" as const, value: scopeData.orgId };
}
throw new InternalServerError({ message: "Invalid scope provided for the org factory" });
};
const onCreateIdentityGuard: TIdentityFactory["onCreateIdentityGuard"] = async (dto) => {
const { permission } = await permissionService.getOrgPermission({
actor: dto.permission.type,
actorId: dto.permission.id,
orgId: dto.permission.orgId,
actorAuthMethod: dto.permission.authMethod,
actorOrgId: dto.permission.orgId,
scope: OrganizationActionScope.Any
});
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
};
const onUpdateIdentityGuard: TIdentityFactory["onUpdateIdentityGuard"] = async (dto) => {
const { permission } = await permissionService.getOrgPermission({
actor: dto.permission.type,
actorId: dto.permission.id,
orgId: dto.permission.orgId,
actorAuthMethod: dto.permission.authMethod,
actorOrgId: dto.permission.orgId,
scope: OrganizationActionScope.Any
});
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
};
const onDeleteIdentityGuard: TIdentityFactory["onDeleteIdentityGuard"] = async (dto) => {
const { permission } = await permissionService.getOrgPermission({
actor: dto.permission.type,
actorId: dto.permission.id,
orgId: dto.permission.orgId,
actorAuthMethod: dto.permission.authMethod,
actorOrgId: dto.permission.orgId,
scope: OrganizationActionScope.Any
});
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Delete, OrgPermissionSubjects.Identity);
};
const onListIdentityGuard: TIdentityFactory["onListIdentityGuard"] = async (dto) => {
const { permission } = await permissionService.getOrgPermission({
actor: dto.permission.type,
actorId: dto.permission.id,
orgId: dto.permission.orgId,
actorAuthMethod: dto.permission.authMethod,
actorOrgId: dto.permission.orgId,
scope: OrganizationActionScope.Any
});
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
};
const onGetIdentityByIdGuard: TIdentityFactory["onGetIdentityByIdGuard"] = async (dto) => {
const { permission } = await permissionService.getOrgPermission({
actor: dto.permission.type,
actorId: dto.permission.id,
orgId: dto.permission.orgId,
actorAuthMethod: dto.permission.authMethod,
actorOrgId: dto.permission.orgId,
scope: OrganizationActionScope.Any
});
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
};
return {
onCreateIdentityGuard,
onUpdateIdentityGuard,
onDeleteIdentityGuard,
onListIdentityGuard,
onGetIdentityByIdGuard,
getScopeField
};
};

View File

@@ -0,0 +1,110 @@
import { ForbiddenError } from "@casl/ability";
import { AccessScope, ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionIdentityActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { InternalServerError } from "@app/lib/errors";
import { TIdentityFactory } from "../identity-types";
type TProjectIdentityFactoryDep = {
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
};
export const newProjectIdentityFactory = ({ permissionService }: TProjectIdentityFactoryDep): TIdentityFactory => {
const getScopeField: TIdentityFactory["getScopeField"] = (scopeData) => {
if (scopeData.scope === AccessScope.Project) {
return { key: "projectId" as const, value: scopeData.projectId };
}
throw new InternalServerError({ message: "Invalid scope provided for the project factory" });
};
const onCreateIdentityGuard: TIdentityFactory["onCreateIdentityGuard"] = async (dto) => {
const scope = getScopeField(dto.scopeData);
const { permission } = await permissionService.getProjectPermission({
actor: dto.permission.type,
actorId: dto.permission.id,
actionProjectType: ActionProjectType.Any,
actorAuthMethod: dto.permission.authMethod,
projectId: scope.value,
actorOrgId: dto.permission.orgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Create,
ProjectPermissionSub.Identity
);
};
const onUpdateIdentityGuard: TIdentityFactory["onUpdateIdentityGuard"] = async (dto) => {
const scope = getScopeField(dto.scopeData);
const { permission } = await permissionService.getProjectPermission({
actor: dto.permission.type,
actorId: dto.permission.id,
actionProjectType: ActionProjectType.Any,
actorAuthMethod: dto.permission.authMethod,
projectId: scope.value,
actorOrgId: dto.permission.orgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Edit,
ProjectPermissionSub.Identity
);
};
const onDeleteIdentityGuard: TIdentityFactory["onDeleteIdentityGuard"] = async (dto) => {
const scope = getScopeField(dto.scopeData);
const { permission } = await permissionService.getProjectPermission({
actor: dto.permission.type,
actorId: dto.permission.id,
actionProjectType: ActionProjectType.Any,
actorAuthMethod: dto.permission.authMethod,
projectId: scope.value,
actorOrgId: dto.permission.orgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Delete,
ProjectPermissionSub.Identity
);
};
const onListIdentityGuard: TIdentityFactory["onListIdentityGuard"] = async (dto) => {
const scope = getScopeField(dto.scopeData);
const { permission } = await permissionService.getProjectPermission({
actor: dto.permission.type,
actorId: dto.permission.id,
actionProjectType: ActionProjectType.Any,
actorAuthMethod: dto.permission.authMethod,
projectId: scope.value,
actorOrgId: dto.permission.orgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Read,
ProjectPermissionSub.Identity
);
};
const onGetIdentityByIdGuard: TIdentityFactory["onGetIdentityByIdGuard"] = async (dto) => {
const scope = getScopeField(dto.scopeData);
const { permission } = await permissionService.getProjectPermission({
actor: dto.permission.type,
actorId: dto.permission.id,
actionProjectType: ActionProjectType.Any,
actorAuthMethod: dto.permission.authMethod,
projectId: scope.value,
actorOrgId: dto.permission.orgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Read,
ProjectPermissionSub.Identity
);
};
return {
onCreateIdentityGuard,
onUpdateIdentityGuard,
onDeleteIdentityGuard,
onListIdentityGuard,
onGetIdentityByIdGuard,
getScopeField
};
};