mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 12:27:28 +00:00
Requested changes
This commit is contained in:
@@ -3,6 +3,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
|
||||||
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "../permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "../permission/project-permission";
|
||||||
import { TAuditLogDALFactory } from "./audit-log-dal";
|
import { TAuditLogDALFactory } from "./audit-log-dal";
|
||||||
@@ -11,7 +12,7 @@ import { EventType, TCreateAuditLogDTO, TListProjectAuditLogDTO } from "./audit-
|
|||||||
|
|
||||||
type TAuditLogServiceFactoryDep = {
|
type TAuditLogServiceFactoryDep = {
|
||||||
auditLogDAL: TAuditLogDALFactory;
|
auditLogDAL: TAuditLogDALFactory;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getOrgPermission">;
|
||||||
auditLogQueue: TAuditLogQueueServiceFactory;
|
auditLogQueue: TAuditLogQueueServiceFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,6 +46,16 @@ export const auditLogServiceFactory = ({
|
|||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs);
|
||||||
|
} else {
|
||||||
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Member);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If project ID is not provided, then we need to return all the audit logs for the organization itself.
|
// If project ID is not provided, then we need to return all the audit logs for the organization itself.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { PkiItemType } from "@app/services/pki-collection/pki-collection-types";
|
|||||||
|
|
||||||
export type TListProjectAuditLogDTO = {
|
export type TListProjectAuditLogDTO = {
|
||||||
auditLogActor?: string;
|
auditLogActor?: string;
|
||||||
projectId: string | null;
|
projectId?: string;
|
||||||
eventType?: string;
|
eventType?: string;
|
||||||
startDate?: string;
|
startDate?: string;
|
||||||
endDate?: string;
|
endDate?: string;
|
||||||
|
|||||||
@@ -464,6 +464,7 @@ export const registerRoutes = async (
|
|||||||
userAliasDAL,
|
userAliasDAL,
|
||||||
orgMembershipDAL,
|
orgMembershipDAL,
|
||||||
tokenService,
|
tokenService,
|
||||||
|
permissionService,
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
smtpService,
|
smtpService,
|
||||||
projectMembershipDAL
|
projectMembershipDAL
|
||||||
|
|||||||
@@ -121,8 +121,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
endDate: req.query.endDate,
|
endDate: req.query.endDate,
|
||||||
startDate: req.query.startDate || getLastMidnightDateISO(),
|
startDate: req.query.startDate || getLastMidnightDateISO(),
|
||||||
auditLogActor: req.query.actor,
|
auditLogActor: req.query.actor,
|
||||||
actor: req.permission.type,
|
actor: req.permission.type
|
||||||
projectId: null
|
|
||||||
});
|
});
|
||||||
return { auditLogs };
|
return { auditLogs };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ProjectsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
|
import { UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { authRateLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { authRateLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
@@ -151,34 +151,20 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
|
|||||||
id: z.string(),
|
id: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
slug: z.string(),
|
slug: z.string(),
|
||||||
orgId: z.string(),
|
orgId: z.string()
|
||||||
projectMemberships: z.array(
|
|
||||||
z.object({
|
|
||||||
id: z.string(),
|
|
||||||
project: ProjectsSchema.pick({ id: true, name: true, slug: true }),
|
|
||||||
roles: z.array(
|
|
||||||
z.object({
|
|
||||||
id: z.string(),
|
|
||||||
role: z.string(),
|
|
||||||
customRoleId: z.string().nullable(),
|
|
||||||
customRoleName: z.string().nullable(),
|
|
||||||
customRoleSlug: z.string().nullable(),
|
|
||||||
temporaryRange: z.string().nullable(),
|
|
||||||
temporaryMode: z.string().nullable(),
|
|
||||||
temporaryAccessEndTime: z.string().nullable(),
|
|
||||||
temporaryAccessStartTime: z.string().nullable(),
|
|
||||||
isTemporary: z.boolean()
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.array()
|
.array()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const groupMemberships = await server.services.user.listUserGroups(req.params.username, req.permission.orgId);
|
const groupMemberships = await server.services.user.listUserGroups({
|
||||||
|
username: req.params.username,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actor: req.permission.type
|
||||||
|
});
|
||||||
|
|
||||||
return groupMemberships;
|
return groupMemberships;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,100 +106,14 @@ export const groupProjectDALFactory = (db: TDbClient) => {
|
|||||||
db.raw("?", [orgId])
|
db.raw("?", [orgId])
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.leftJoin(
|
|
||||||
TableName.GroupProjectMembership,
|
|
||||||
`${TableName.GroupProjectMembership}.groupId`,
|
|
||||||
`${TableName.Groups}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.GroupProjectMembershipRole,
|
|
||||||
`${TableName.GroupProjectMembershipRole}.projectMembershipId`,
|
|
||||||
`${TableName.GroupProjectMembership}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.ProjectRoles,
|
|
||||||
`${TableName.GroupProjectMembershipRole}.customRoleId`,
|
|
||||||
`${TableName.ProjectRoles}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(TableName.Project, `${TableName.GroupProjectMembership}.projectId`, `${TableName.Project}.id`)
|
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.Groups).as("groupId"),
|
db.ref("id").withSchema(TableName.Groups),
|
||||||
db.ref("name").withSchema(TableName.Groups).as("groupName"),
|
db.ref("name").withSchema(TableName.Groups),
|
||||||
db.ref("slug").withSchema(TableName.Groups).as("groupSlug"),
|
db.ref("slug").withSchema(TableName.Groups),
|
||||||
db.ref("orgId").withSchema(TableName.Groups),
|
db.ref("orgId").withSchema(TableName.Groups)
|
||||||
db.ref("id").withSchema(TableName.GroupProjectMembership).as("projectMembershipId"),
|
|
||||||
db.ref("id").withSchema(TableName.Project).as("projectId"),
|
|
||||||
db.ref("name").withSchema(TableName.Project).as("projectName"),
|
|
||||||
db.ref("slug").withSchema(TableName.Project).as("projectSlug"),
|
|
||||||
db.ref("role").withSchema(TableName.GroupProjectMembershipRole),
|
|
||||||
db.ref("id").withSchema(TableName.GroupProjectMembershipRole).as("membershipRoleId"),
|
|
||||||
db.ref("customRoleId").withSchema(TableName.GroupProjectMembershipRole),
|
|
||||||
db.ref("name").withSchema(TableName.ProjectRoles).as("customRoleName"),
|
|
||||||
db.ref("slug").withSchema(TableName.ProjectRoles).as("customRoleSlug"),
|
|
||||||
db.ref("temporaryMode").withSchema(TableName.GroupProjectMembershipRole),
|
|
||||||
db.ref("isTemporary").withSchema(TableName.GroupProjectMembershipRole),
|
|
||||||
db.ref("temporaryRange").withSchema(TableName.GroupProjectMembershipRole),
|
|
||||||
db.ref("temporaryAccessStartTime").withSchema(TableName.GroupProjectMembershipRole),
|
|
||||||
db.ref("temporaryAccessEndTime").withSchema(TableName.GroupProjectMembershipRole)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const groupsWithProjects = sqlNestRelationships({
|
return docs;
|
||||||
data: docs,
|
|
||||||
parentMapper: ({ groupId, groupName, groupSlug, orgId: organizationId }) => ({
|
|
||||||
id: groupId,
|
|
||||||
name: groupName,
|
|
||||||
slug: groupSlug,
|
|
||||||
orgId: organizationId,
|
|
||||||
projectMemberships: []
|
|
||||||
}),
|
|
||||||
key: "groupId",
|
|
||||||
childrenMapper: [
|
|
||||||
{
|
|
||||||
label: "projectMemberships" as const,
|
|
||||||
key: "projectMembershipId",
|
|
||||||
mapper: ({ projectId, projectName, projectSlug, projectMembershipId }) => ({
|
|
||||||
id: projectMembershipId,
|
|
||||||
project: {
|
|
||||||
id: projectId,
|
|
||||||
name: projectName,
|
|
||||||
slug: projectSlug
|
|
||||||
},
|
|
||||||
roles: []
|
|
||||||
}),
|
|
||||||
childrenMapper: [
|
|
||||||
{
|
|
||||||
label: "roles" as const,
|
|
||||||
key: "membershipRoleId",
|
|
||||||
mapper: ({
|
|
||||||
role,
|
|
||||||
customRoleId,
|
|
||||||
customRoleName,
|
|
||||||
customRoleSlug,
|
|
||||||
membershipRoleId,
|
|
||||||
temporaryRange,
|
|
||||||
temporaryMode,
|
|
||||||
temporaryAccessEndTime,
|
|
||||||
temporaryAccessStartTime,
|
|
||||||
isTemporary
|
|
||||||
}) => ({
|
|
||||||
id: membershipRoleId,
|
|
||||||
role,
|
|
||||||
customRoleId,
|
|
||||||
customRoleName,
|
|
||||||
customRoleSlug,
|
|
||||||
temporaryRange,
|
|
||||||
temporaryMode,
|
|
||||||
temporaryAccessEndTime,
|
|
||||||
temporaryAccessStartTime,
|
|
||||||
isTemporary
|
|
||||||
})
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
return groupsWithProjects;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "FindByUserId" });
|
throw new DatabaseError({ error, name: "FindByUserId" });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { SecretKeyEncoding } from "@app/db/schemas";
|
import { SecretKeyEncoding } from "@app/db/schemas";
|
||||||
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import { infisicalSymmetricDecrypt } from "@app/lib/crypto/encryption";
|
import { infisicalSymmetricDecrypt } from "@app/lib/crypto/encryption";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { TAuthTokenServiceFactory } from "@app/services/auth-token/auth-token-service";
|
import { TAuthTokenServiceFactory } from "@app/services/auth-token/auth-token-service";
|
||||||
@@ -11,6 +15,7 @@ import { AuthMethod } from "../auth/auth-type";
|
|||||||
import { TGroupProjectDALFactory } from "../group-project/group-project-dal";
|
import { TGroupProjectDALFactory } from "../group-project/group-project-dal";
|
||||||
import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal";
|
import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal";
|
||||||
import { TUserDALFactory } from "./user-dal";
|
import { TUserDALFactory } from "./user-dal";
|
||||||
|
import { TListUserGroupsDTO } from "./user-types";
|
||||||
|
|
||||||
type TUserServiceFactoryDep = {
|
type TUserServiceFactoryDep = {
|
||||||
userDAL: Pick<
|
userDAL: Pick<
|
||||||
@@ -33,6 +38,7 @@ type TUserServiceFactoryDep = {
|
|||||||
tokenService: Pick<TAuthTokenServiceFactory, "createTokenForUser" | "validateTokenForUser">;
|
tokenService: Pick<TAuthTokenServiceFactory, "createTokenForUser" | "validateTokenForUser">;
|
||||||
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find">;
|
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find">;
|
||||||
smtpService: Pick<TSmtpService, "sendMail">;
|
smtpService: Pick<TSmtpService, "sendMail">;
|
||||||
|
permissionService: TPermissionServiceFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TUserServiceFactory = ReturnType<typeof userServiceFactory>;
|
export type TUserServiceFactory = ReturnType<typeof userServiceFactory>;
|
||||||
@@ -44,7 +50,8 @@ export const userServiceFactory = ({
|
|||||||
projectMembershipDAL,
|
projectMembershipDAL,
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
tokenService,
|
tokenService,
|
||||||
smtpService
|
smtpService,
|
||||||
|
permissionService
|
||||||
}: TUserServiceFactoryDep) => {
|
}: TUserServiceFactoryDep) => {
|
||||||
const sendEmailVerificationCode = async (username: string) => {
|
const sendEmailVerificationCode = async (username: string) => {
|
||||||
const user = await userDAL.findOne({ username });
|
const user = await userDAL.findOne({ username });
|
||||||
@@ -298,13 +305,24 @@ export const userServiceFactory = ({
|
|||||||
return updatedOrgMembership.projectFavorites;
|
return updatedOrgMembership.projectFavorites;
|
||||||
};
|
};
|
||||||
|
|
||||||
const listUserGroups = async (username: string, orgId: string) => {
|
const listUserGroups = async ({ username, actorOrgId, actor, actorId, actorAuthMethod }: TListUserGroupsDTO) => {
|
||||||
const user = await userDAL.findOne({
|
const user = await userDAL.findOne({
|
||||||
username
|
username
|
||||||
});
|
});
|
||||||
|
|
||||||
const memberships = await groupProjectDAL.findByUserId(user.id, orgId);
|
// This makes it so the user can always read information about themselves, but no one else if they don't have the Members Read permission.
|
||||||
|
if (user.id !== actorId) {
|
||||||
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Member);
|
||||||
|
}
|
||||||
|
|
||||||
|
const memberships = await groupProjectDAL.findByUserId(user.id, actorOrgId);
|
||||||
return memberships;
|
return memberships;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { TOrgPermission } from "@app/lib/types";
|
||||||
|
|
||||||
|
export type TListUserGroupsDTO = {
|
||||||
|
username: string;
|
||||||
|
} & Omit<TOrgPermission, "orgId">;
|
||||||
|
|||||||
@@ -40,24 +40,4 @@ export type TGroupWithProjectMemberships = {
|
|||||||
name: string;
|
name: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
projectMemberships: {
|
|
||||||
id: string;
|
|
||||||
project: {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
slug: string;
|
|
||||||
};
|
|
||||||
roles: {
|
|
||||||
id: string;
|
|
||||||
role: string;
|
|
||||||
customRoleId: string | null;
|
|
||||||
customRoleName: string | null;
|
|
||||||
customRoleSlug: string | null;
|
|
||||||
temporaryRange: string | null;
|
|
||||||
temporaryMode: string | null;
|
|
||||||
temporaryAccessEndTime: string | null;
|
|
||||||
temporaryAccessStartTime: string | null;
|
|
||||||
isTemporary: boolean;
|
|
||||||
}[];
|
|
||||||
}[];
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,26 +20,24 @@ export const UserGroupsRow = ({ group, handlePopUpOpen }: Props) => {
|
|||||||
>
|
>
|
||||||
<Td>{group.name}</Td>
|
<Td>{group.name}</Td>
|
||||||
<Td>
|
<Td>
|
||||||
{true && (
|
<div className="opacity-0 transition-opacity duration-300 group-hover:opacity-100">
|
||||||
<div className="opacity-0 transition-opacity duration-300 group-hover:opacity-100">
|
<Tooltip content="Unassign user from group">
|
||||||
<Tooltip content="Remove user from group">
|
<IconButton
|
||||||
<IconButton
|
colorSchema="danger"
|
||||||
colorSchema="danger"
|
ariaLabel="copy icon"
|
||||||
ariaLabel="copy icon"
|
variant="plain"
|
||||||
variant="plain"
|
className="group relative"
|
||||||
className="group relative"
|
onClick={(e) => {
|
||||||
onClick={(e) => {
|
e.stopPropagation();
|
||||||
e.stopPropagation();
|
handlePopUpOpen("removeUserFromGroup", {
|
||||||
handlePopUpOpen("removeUserFromGroup", {
|
groupSlug: group.slug
|
||||||
groupSlug: group.slug
|
});
|
||||||
});
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<FontAwesomeIcon icon={faTrash} />
|
||||||
<FontAwesomeIcon icon={faTrash} />
|
</IconButton>
|
||||||
</IconButton>
|
</Tooltip>
|
||||||
</Tooltip>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Td>
|
</Td>
|
||||||
</Tr>
|
</Tr>
|
||||||
</>
|
</>
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ export const UserGroupsSection = ({ orgMembership }: Props) => {
|
|||||||
|
|
||||||
<DeleteActionModal
|
<DeleteActionModal
|
||||||
isOpen={popUp.removeUserFromGroup.isOpen}
|
isOpen={popUp.removeUserFromGroup.isOpen}
|
||||||
title="Are you sure want to remove user from group?"
|
title="Are you sure want to unassign user from group?"
|
||||||
onChange={(isOpen) => handlePopUpToggle("removeUserFromGroup", isOpen)}
|
onChange={(isOpen) => handlePopUpToggle("removeUserFromGroup", isOpen)}
|
||||||
deleteKey="confirm"
|
deleteKey="confirm"
|
||||||
onDeleteApproved={() => {
|
onDeleteApproved={() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user