mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-17 08:35:52 +00:00
feat: completed all role routers
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import { NotFoundError } from "@app/lib/errors";
|
||||
import { TMembershipDALFactory } from "../membership/membership-dal";
|
||||
import { TProjectDALFactory } from "../project/project-dal";
|
||||
import { AccessScope, AccessScopeData } from "@app/db/schemas";
|
||||
|
||||
type TConvertorServiceFactoryDep = {
|
||||
projectDAL: Pick<TProjectDALFactory, "findOne">;
|
||||
membershipDAL: Pick<TMembershipDALFactory, "findOne">;
|
||||
};
|
||||
|
||||
export type TConvertorServiceFactory = ReturnType<typeof convertorServiceFactory>;
|
||||
|
||||
export const convertorServiceFactory = ({ projectDAL, membershipDAL }: TConvertorServiceFactoryDep) => {
|
||||
const $getScopeDatabaseFields = (scopeData: AccessScopeData) => {
|
||||
if (scopeData.scope === AccessScope.Organization) {
|
||||
return { scopeOrgId: scopeData.orgId };
|
||||
}
|
||||
|
||||
if (scopeData.scope === AccessScope.Namespace) {
|
||||
return { scopeNamespaceId: scopeData.namespaceId, scopeOrgId: scopeData.orgId };
|
||||
}
|
||||
|
||||
return { scopeProjectId: scopeData.projectId, scopeOrgId: scopeData.orgId };
|
||||
};
|
||||
|
||||
const projectSlugToId = async (dto: { slug: string; orgId: string }) => {
|
||||
const project = await projectDAL.findOne({
|
||||
orgId: dto.orgId,
|
||||
slug: dto.slug
|
||||
});
|
||||
if (!project) throw new NotFoundError({ message: `Project with slug ${slug} not found` });
|
||||
return project;
|
||||
};
|
||||
|
||||
const userMembershipIdToUserId = async (scopeData: AccessScopeData, membershipId: string) => {
|
||||
const dbFields = $getScopeDatabaseFields(scopeData);
|
||||
|
||||
const membership = await membershipDAL.findOne({
|
||||
scope: scopeData.scope,
|
||||
id: membershipId,
|
||||
...dbFields,
|
||||
scopeOrgId: scopeData.orgId
|
||||
});
|
||||
if (!membership || !membership.actorUserId) {
|
||||
throw new NotFoundError({ message: `Membership with id ${membershipId} not found` });
|
||||
}
|
||||
return membership.actorUserId;
|
||||
};
|
||||
|
||||
const groupMembershipIdToGroupId = async (scopeData: AccessScopeData, membershipId: string) => {
|
||||
const dbFields = $getScopeDatabaseFields(scopeData);
|
||||
|
||||
const membership = await membershipDAL.findOne({
|
||||
scope: scopeData.scope,
|
||||
id: membershipId,
|
||||
...dbFields,
|
||||
scopeOrgId: scopeData.orgId
|
||||
});
|
||||
if (!membership || !membership.actorGroupId) {
|
||||
throw new NotFoundError({ message: `Membership with id ${membershipId} not found` });
|
||||
}
|
||||
|
||||
return membership.actorGroupId;
|
||||
};
|
||||
|
||||
const identityMembershipIdToGroupId = async (scopeData: AccessScopeData, membershipId: string) => {
|
||||
const dbFields = $getScopeDatabaseFields(scopeData);
|
||||
|
||||
const membership = await membershipDAL.findOne({
|
||||
scope: scopeData.scope,
|
||||
id: membershipId,
|
||||
...dbFields,
|
||||
scopeOrgId: scopeData.orgId
|
||||
});
|
||||
if (!membership || !membership.actorIdentityId) {
|
||||
throw new NotFoundError({ message: `Membership with id ${membershipId} not found` });
|
||||
}
|
||||
|
||||
return membership.actorIdentityId;
|
||||
};
|
||||
|
||||
return {
|
||||
projectSlugToId,
|
||||
userMembershipIdToUserId,
|
||||
groupMembershipIdToGroupId,
|
||||
identityMembershipIdToGroupId
|
||||
};
|
||||
};
|
||||
@@ -43,10 +43,7 @@ type TGroupProjectServiceFactoryDep = {
|
||||
projectRoleDAL: Pick<TProjectRoleDALFactory, "find">;
|
||||
projectBotDAL: TProjectBotDALFactory;
|
||||
groupDAL: Pick<TGroupDALFactory, "findOne" | "findAllGroupPossibleMembers">;
|
||||
permissionService: Pick<
|
||||
TPermissionServiceFactory,
|
||||
"getProjectPermission" | "getProjectPermissionByRole" | "invalidateProjectPermissionCache"
|
||||
>;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getProjectPermissionByRoles" | "invalidateProjectPermissionCache">;
|
||||
};
|
||||
|
||||
export type TGroupProjectServiceFactory = ReturnType<typeof groupProjectServiceFactory>;
|
||||
|
||||
+18
-20
@@ -115,29 +115,27 @@ export const newProjectMembershipIdentityFactory = ({
|
||||
|
||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(dto.permission.orgId);
|
||||
const permissionRoles = await permissionService.getProjectPermissionByRoles(
|
||||
dto.data.roles.map((el) => el.role),
|
||||
dto.data.roles.filter((el) => el.role !== ProjectMembershipRole.NoAccess).map((el) => el.role),
|
||||
scope.value
|
||||
);
|
||||
for (const permissionRole of permissionRoles) {
|
||||
if (permissionRole?.role?.name !== ProjectMembershipRole.NoAccess) {
|
||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||
shouldUseNewPrivilegeSystem,
|
||||
ProjectPermissionIdentityActions.GrantPrivileges,
|
||||
ProjectPermissionSub.Identity,
|
||||
permission,
|
||||
permissionRole.permission
|
||||
);
|
||||
if (!permissionBoundary.isValid)
|
||||
throw new PermissionBoundaryError({
|
||||
message: constructPermissionErrorMessage(
|
||||
"Failed to create identity project membership",
|
||||
shouldUseNewPrivilegeSystem,
|
||||
ProjectPermissionIdentityActions.GrantPrivileges,
|
||||
ProjectPermissionSub.Identity
|
||||
),
|
||||
details: { missingPermissions: permissionBoundary.missingPermissions }
|
||||
});
|
||||
}
|
||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||
shouldUseNewPrivilegeSystem,
|
||||
ProjectPermissionIdentityActions.GrantPrivileges,
|
||||
ProjectPermissionSub.Identity,
|
||||
permission,
|
||||
permissionRole.permission
|
||||
);
|
||||
if (!permissionBoundary.isValid)
|
||||
throw new PermissionBoundaryError({
|
||||
message: constructPermissionErrorMessage(
|
||||
"Failed to create identity project membership",
|
||||
shouldUseNewPrivilegeSystem,
|
||||
ProjectPermissionIdentityActions.GrantPrivileges,
|
||||
ProjectPermissionSub.Identity
|
||||
),
|
||||
details: { missingPermissions: permissionBoundary.missingPermissions }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ export const membershipUserDALFactory = (db: TDbClient) => {
|
||||
})
|
||||
.where(`${TableName.Membership}.scopeOrgId`, scopeData.orgId)
|
||||
.where(`${TableName.Membership}.actorUserId`, userId)
|
||||
.where(`${TableName.Users}.isGhost`, false)
|
||||
.where((qb) => {
|
||||
if (scopeData.scope === AccessScope.Organization) {
|
||||
void qb.where(`${TableName.Membership}.scope`, AccessScope.Organization);
|
||||
@@ -60,7 +61,9 @@ export const membershipUserDALFactory = (db: TDbClient) => {
|
||||
})
|
||||
.select(selectAllTableCols(TableName.Membership))
|
||||
.select(
|
||||
db.ref("slug").withSchema(TableName.Role).as("roleSlug"),
|
||||
db.ref("slug").withSchema(TableName.Role).as("customRoleSlug"),
|
||||
db.ref("name").withSchema(TableName.Role).as("customRoleName"),
|
||||
db.ref("id").withSchema(TableName.Role).as("customRoleId"),
|
||||
db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"),
|
||||
db.ref("role").withSchema(TableName.MembershipRole).as("membershipRole"),
|
||||
db.ref("temporaryMode").withSchema(TableName.MembershipRole).as("membershipRoleTemporaryMode"),
|
||||
@@ -78,19 +81,35 @@ export const membershipUserDALFactory = (db: TDbClient) => {
|
||||
db.ref("updatedAt").withSchema(TableName.MembershipRole).as("membershipRoleUpdatedAt"),
|
||||
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("value").withSchema(TableName.IdentityMetadata).as("metadataValue"),
|
||||
db.ref("username").withSchema(TableName.Users).as("userUsername"),
|
||||
db.ref("email").withSchema(TableName.Users).as("userEmail"),
|
||||
db.ref("firstName").withSchema(TableName.Users).as("userFirstName"),
|
||||
db.ref("lastName").withSchema(TableName.Users).as("userLastName"),
|
||||
db.ref("id").withSchema(TableName.Users).as("userId")
|
||||
);
|
||||
|
||||
const data = sqlNestRelationships({
|
||||
data: docs,
|
||||
key: "id",
|
||||
parentMapper: (el) => MembershipsSchema.parse(el),
|
||||
parentMapper: (el) => ({
|
||||
...MembershipsSchema.parse(el),
|
||||
user: {
|
||||
username: el.userUsername,
|
||||
email: el.userEmail,
|
||||
firstName: el.userFirstName,
|
||||
lastName: el.userLastName,
|
||||
id: el.userId
|
||||
}
|
||||
}),
|
||||
childrenMapper: [
|
||||
{
|
||||
key: "membershipRoleId",
|
||||
label: "roles" as const,
|
||||
mapper: ({
|
||||
roleSlug,
|
||||
customRoleSlug,
|
||||
customRoleName,
|
||||
customRoleId,
|
||||
membershipRoleId,
|
||||
membershipRole,
|
||||
membershipRoleIsTemporary,
|
||||
@@ -103,7 +122,9 @@ export const membershipUserDALFactory = (db: TDbClient) => {
|
||||
}) => ({
|
||||
id: membershipRoleId,
|
||||
role: membershipRole,
|
||||
customRoleSlug: roleSlug,
|
||||
customRoleSlug,
|
||||
customRoleName,
|
||||
customRoleId,
|
||||
temporaryRange: membershipRoleTemporaryRange,
|
||||
temporaryMode: membershipRoleTemporaryMode,
|
||||
temporaryAccessStartTime: membershipRoleTemporaryAccessStartTime,
|
||||
@@ -140,6 +161,7 @@ export const membershipUserDALFactory = (db: TDbClient) => {
|
||||
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||
.distinct(`${TableName.Membership}.id`)
|
||||
.where(`${TableName.Membership}.scopeOrgId`, scopeData.orgId)
|
||||
.where(`${TableName.Users}.isGhost`, false)
|
||||
.where((qb) => {
|
||||
if (scopeData.scope === AccessScope.Organization) {
|
||||
void qb.where(`${TableName.Membership}.scope`, AccessScope.Organization);
|
||||
@@ -188,7 +210,9 @@ export const membershipUserDALFactory = (db: TDbClient) => {
|
||||
.whereIn(`${TableName.Membership}.id`, paginatedUsers)
|
||||
.select(selectAllTableCols(TableName.Membership))
|
||||
.select(
|
||||
db.ref("slug").withSchema(TableName.Role).as("roleSlug"),
|
||||
db.ref("slug").withSchema(TableName.Role).as("customRoleSlug"),
|
||||
db.ref("name").withSchema(TableName.Role).as("customRoleName"),
|
||||
db.ref("id").withSchema(TableName.Role).as("customRoleId"),
|
||||
db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"),
|
||||
db.ref("role").withSchema(TableName.MembershipRole).as("membershipRole"),
|
||||
db.ref("temporaryMode").withSchema(TableName.MembershipRole).as("membershipRoleTemporaryMode"),
|
||||
@@ -203,7 +227,12 @@ export const membershipUserDALFactory = (db: TDbClient) => {
|
||||
.withSchema(TableName.MembershipRole)
|
||||
.as("membershipRoleTemporaryAccessEndTime"),
|
||||
db.ref("createdAt").withSchema(TableName.MembershipRole).as("membershipRoleCreatedAt"),
|
||||
db.ref("updatedAt").withSchema(TableName.MembershipRole).as("membershipRoleUpdatedAt")
|
||||
db.ref("updatedAt").withSchema(TableName.MembershipRole).as("membershipRoleUpdatedAt"),
|
||||
db.ref("username").withSchema(TableName.Users).as("userUsername"),
|
||||
db.ref("email").withSchema(TableName.Users).as("userEmail"),
|
||||
db.ref("firstName").withSchema(TableName.Users).as("userFirstName"),
|
||||
db.ref("lastName").withSchema(TableName.Users).as("userLastName"),
|
||||
db.ref("id").withSchema(TableName.Users).as("userId")
|
||||
)
|
||||
.select(
|
||||
db.raw(
|
||||
@@ -214,13 +243,24 @@ export const membershipUserDALFactory = (db: TDbClient) => {
|
||||
const data = sqlNestRelationships({
|
||||
data: docs,
|
||||
key: "id",
|
||||
parentMapper: (el) => MembershipsSchema.parse(el),
|
||||
parentMapper: (el) => ({
|
||||
...MembershipsSchema.parse(el),
|
||||
user: {
|
||||
username: el.userUsername,
|
||||
email: el.userEmail,
|
||||
firstName: el.userFirstName,
|
||||
lastName: el.userLastName,
|
||||
id: el.userId
|
||||
}
|
||||
}),
|
||||
childrenMapper: [
|
||||
{
|
||||
key: "membershipRoleId",
|
||||
label: "roles" as const,
|
||||
mapper: ({
|
||||
roleSlug,
|
||||
customRoleSlug,
|
||||
customRoleName,
|
||||
customRoleId,
|
||||
membershipRoleId,
|
||||
membershipRole,
|
||||
membershipRoleIsTemporary,
|
||||
@@ -233,7 +273,9 @@ export const membershipUserDALFactory = (db: TDbClient) => {
|
||||
}) => ({
|
||||
id: membershipRoleId,
|
||||
role: membershipRole,
|
||||
customRoleSlug: roleSlug,
|
||||
customRoleSlug,
|
||||
customRoleName,
|
||||
customRoleId,
|
||||
temporaryRange: membershipRoleTemporaryRange,
|
||||
temporaryMode: membershipRoleTemporaryMode,
|
||||
temporaryAccessStartTime: membershipRoleTemporaryAccessStartTime,
|
||||
|
||||
@@ -386,7 +386,7 @@ export const membershipUserServiceFactory = ({
|
||||
limit: dto.data.limit,
|
||||
offset: dto.data.offset,
|
||||
username: dto.data.username,
|
||||
role: dto.data.roles.length
|
||||
role: dto.data?.roles?.length
|
||||
? {
|
||||
[SearchResourceOperators.$in]: dto.data.roles
|
||||
}
|
||||
|
||||
@@ -55,14 +55,11 @@ export type TUpdateMembershipUserDTO = {
|
||||
export type TListMembershipUserDTO = {
|
||||
permission: OrgServiceActor;
|
||||
scopeData: AccessScopeData;
|
||||
selector: {
|
||||
actorId: string;
|
||||
};
|
||||
data: {
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
username?: string;
|
||||
roles: string[];
|
||||
roles?: string[];
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -43,10 +43,7 @@ import {
|
||||
import { TProjectUserMembershipRoleDALFactory } from "./project-user-membership-role-dal";
|
||||
|
||||
type TProjectMembershipServiceFactoryDep = {
|
||||
permissionService: Pick<
|
||||
TPermissionServiceFactory,
|
||||
"getProjectPermission" | "getProjectPermissionByRole" | "invalidateProjectPermissionCache"
|
||||
>;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getProjectPermissionByRoles"| "invalidateProjectPermissionCache">;
|
||||
smtpService: TSmtpService;
|
||||
projectBotDAL: TProjectBotDALFactory;
|
||||
projectMembershipDAL: TProjectMembershipDALFactory;
|
||||
@@ -573,6 +570,8 @@ export const projectMembershipServiceFactory = ({
|
||||
tx
|
||||
);
|
||||
|
||||
// TODO(simp): likewise check in all services if i am missing anything
|
||||
// Deletion should handle all cleanups like wise
|
||||
await secretReminderRecipientsDAL.delete(
|
||||
{
|
||||
projectId,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { AccessScope, TableName } from "@app/db/schemas";
|
||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||
import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars";
|
||||
import { unpackPermissions } from "@app/server/routes/sanitizedSchema/permission";
|
||||
|
||||
import { newNamespaceRoleFactory } from "./namespace/namespace-role-factory";
|
||||
import { newOrgRoleFactory } from "./org/org-role-factory";
|
||||
@@ -63,7 +64,7 @@ export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceF
|
||||
[scope.key]: scope.value
|
||||
});
|
||||
|
||||
return { ...role, [scope.key]: scope.value };
|
||||
return { ...role, [scope.key]: scope.value, permissions: unpackPermissions(role.permissions) };
|
||||
};
|
||||
|
||||
const updateRole = async (dto: TUpdateRoleDTO) => {
|
||||
@@ -99,7 +100,7 @@ export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceF
|
||||
permissions: data?.permissions
|
||||
});
|
||||
|
||||
return { ...role, [scope.key]: scope.value };
|
||||
return { ...role, [scope.key]: scope.value, permissions: unpackPermissions(role.permissions) };
|
||||
};
|
||||
|
||||
const deleteRole = async (dto: TDeleteRoleDTO) => {
|
||||
@@ -119,7 +120,7 @@ export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceF
|
||||
[scope.key]: scope.value
|
||||
});
|
||||
|
||||
return { ...role, [scope.key]: scope.value };
|
||||
return { ...role, [scope.key]: scope.value, permissions: unpackPermissions(role.permissions) };
|
||||
};
|
||||
|
||||
const listRoles = async (dto: TListRoleDTO) => {
|
||||
@@ -136,7 +137,7 @@ export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceF
|
||||
{ limit: dto.data.limit, offset: dto.data.offset, sort: [[`${TableName.Role}.slug` as "slug", "asc"]] }
|
||||
);
|
||||
|
||||
return { roles };
|
||||
return { roles: roles.map((el) => ({ ...el, permissions: unpackPermissions(el.permissions) })) };
|
||||
};
|
||||
|
||||
const getRoleById = async (dto: TGetRoleByIdDTO) => {
|
||||
@@ -152,7 +153,7 @@ export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceF
|
||||
});
|
||||
if (!role) throw new NotFoundError({ message: `Role with id ${dto.selector.id} not found` });
|
||||
|
||||
return { ...role, [scope.key]: scope.value };
|
||||
return { ...role, [scope.key]: scope.value, permissions: unpackPermissions(role.permissions) };
|
||||
};
|
||||
|
||||
const getRoleBySlug = async (dto: TGetRoleBySlugDTO) => {
|
||||
@@ -168,7 +169,7 @@ export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceF
|
||||
});
|
||||
if (!role) throw new NotFoundError({ message: `Role with slug ${dto.selector.slug} not found` });
|
||||
|
||||
return { ...role, [scope.key]: scope.value };
|
||||
return { ...role, [scope.key]: scope.value, permissions: unpackPermissions(role.permissions) };
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -16,7 +16,7 @@ export type TCreateRoleDTO = {
|
||||
scopeData: AccessScopeData;
|
||||
data: {
|
||||
name: string;
|
||||
description?: string;
|
||||
description?: string | null;
|
||||
slug: string;
|
||||
permissions: unknown;
|
||||
};
|
||||
@@ -30,7 +30,7 @@ export type TUpdateRoleDTO = {
|
||||
};
|
||||
data: Partial<{
|
||||
name: string;
|
||||
description?: string;
|
||||
description?: string | null;
|
||||
slug: string;
|
||||
permissions: unknown;
|
||||
}>;
|
||||
|
||||
Reference in New Issue
Block a user