mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-02 18:25:45 +00:00
feat:simplified permission service
This commit is contained in:
Vendored
+2
-2
@@ -1334,12 +1334,12 @@ declare module "knex/types/tables" {
|
|||||||
|
|
||||||
[TableName.Namespace]: KnexOriginal.CompositeTableType<TNamespaces, TNamespacesInsert, TNamespacesUpdate>;
|
[TableName.Namespace]: KnexOriginal.CompositeTableType<TNamespaces, TNamespacesInsert, TNamespacesUpdate>;
|
||||||
[TableName.Membership]: KnexOriginal.CompositeTableType<TMemberships, TMembershipsInsert, TMembershipsUpdate>;
|
[TableName.Membership]: KnexOriginal.CompositeTableType<TMemberships, TMembershipsInsert, TMembershipsUpdate>;
|
||||||
[TableName.MembershipRoles]: KnexOriginal.CompositeTableType<
|
[TableName.MembershipRole]: KnexOriginal.CompositeTableType<
|
||||||
TMembershipRoles,
|
TMembershipRoles,
|
||||||
TMembershipRolesInsert,
|
TMembershipRolesInsert,
|
||||||
TMembershipRolesUpdate
|
TMembershipRolesUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.Roles]: KnexOriginal.CompositeTableType<TRoles, TRolesInsert, TRolesUpdate>;
|
[TableName.Role]: KnexOriginal.CompositeTableType<TRoles, TRolesInsert, TRolesUpdate>;
|
||||||
[TableName.AdditionalPrivilege]: KnexOriginal.CompositeTableType<
|
[TableName.AdditionalPrivilege]: KnexOriginal.CompositeTableType<
|
||||||
TAdditionalPrivileges,
|
TAdditionalPrivileges,
|
||||||
TAdditionalPrivilegesInsert,
|
TAdditionalPrivilegesInsert,
|
||||||
|
|||||||
@@ -314,3 +314,25 @@ export enum SortDirection {
|
|||||||
ASC = "asc",
|
ASC = "asc",
|
||||||
DESC = "desc"
|
DESC = "desc"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum AccessScope {
|
||||||
|
Organization = "organization",
|
||||||
|
Namespace = "namespace",
|
||||||
|
Project = "project"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AccessScopeData =
|
||||||
|
| {
|
||||||
|
scope: AccessScope.Organization;
|
||||||
|
orgId: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
scope: AccessScope.Namespace;
|
||||||
|
orgId: string;
|
||||||
|
namespaceId: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
scope: AccessScope.Project;
|
||||||
|
orgId: string;
|
||||||
|
projectId: string;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,181 +1,53 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import {
|
import {
|
||||||
|
AccessScope,
|
||||||
|
AccessScopeData,
|
||||||
IdentityProjectMembershipRoleSchema,
|
IdentityProjectMembershipRoleSchema,
|
||||||
OrgMembershipRole,
|
MembershipsSchema,
|
||||||
OrgMembershipsSchema,
|
|
||||||
TableName,
|
TableName,
|
||||||
TIdentityOrgMemberships,
|
TMemberships,
|
||||||
TProjectRoles,
|
TProjectRoles,
|
||||||
TProjects
|
TProjects
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
import { selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
||||||
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
interface TPermissionDataReturn extends TMemberships {
|
||||||
|
roles: {
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
isTemporary: boolean;
|
||||||
|
role: string;
|
||||||
|
temporaryRange?: string | null | undefined;
|
||||||
|
permissions?: unknown;
|
||||||
|
customRoleId?: string | null | undefined;
|
||||||
|
temporaryMode?: string | null | undefined;
|
||||||
|
temporaryAccessStartTime?: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime?: Date | null | undefined;
|
||||||
|
customRoleSlug?: string | null | undefined;
|
||||||
|
}[];
|
||||||
|
additionalPrivileges: {
|
||||||
|
id: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
metadata: {
|
||||||
|
id: string;
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface TPermissionDALFactory {
|
export interface TPermissionDALFactory {
|
||||||
getOrgPermission: (
|
|
||||||
userId: string,
|
|
||||||
orgId: string
|
|
||||||
) => Promise<
|
|
||||||
{
|
|
||||||
status: string;
|
|
||||||
orgId: string;
|
|
||||||
id: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
role: string;
|
|
||||||
isActive: boolean;
|
|
||||||
shouldUseNewPrivilegeSystem: boolean;
|
|
||||||
bypassOrgAuthEnabled: boolean;
|
|
||||||
permissions?: unknown;
|
|
||||||
userId?: string | null | undefined;
|
|
||||||
roleId?: string | null | undefined;
|
|
||||||
inviteEmail?: string | null | undefined;
|
|
||||||
projectFavorites?: string[] | null | undefined;
|
|
||||||
customRoleSlug?: string | null | undefined;
|
|
||||||
orgAuthEnforced?: boolean | null | undefined;
|
|
||||||
orgGoogleSsoAuthEnforced: boolean;
|
|
||||||
} & {
|
|
||||||
groups: {
|
|
||||||
id: string;
|
|
||||||
updatedAt: Date;
|
|
||||||
createdAt: Date;
|
|
||||||
role: string;
|
|
||||||
roleId: string | null | undefined;
|
|
||||||
customRolePermission: unknown;
|
|
||||||
name: string;
|
|
||||||
slug: string;
|
|
||||||
orgId: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
getOrgIdentityPermission: (
|
|
||||||
identityId: string,
|
|
||||||
orgId: string
|
|
||||||
) => Promise<
|
|
||||||
| (TIdentityOrgMemberships & {
|
|
||||||
orgAuthEnforced: boolean | null | undefined;
|
|
||||||
shouldUseNewPrivilegeSystem: boolean;
|
|
||||||
permissions?: unknown;
|
|
||||||
})
|
|
||||||
| undefined
|
|
||||||
>;
|
|
||||||
getProjectPermission: (
|
|
||||||
userId: string,
|
|
||||||
projectId: string
|
|
||||||
) => Promise<
|
|
||||||
| {
|
|
||||||
roles: {
|
|
||||||
id: string;
|
|
||||||
role: string;
|
|
||||||
customRoleSlug: string;
|
|
||||||
permissions: unknown;
|
|
||||||
temporaryRange: string | null | undefined;
|
|
||||||
temporaryMode: string | null | undefined;
|
|
||||||
temporaryAccessStartTime: Date | null | undefined;
|
|
||||||
temporaryAccessEndTime: Date | null | undefined;
|
|
||||||
isTemporary: boolean;
|
|
||||||
}[];
|
|
||||||
additionalPrivileges: {
|
|
||||||
id: string;
|
|
||||||
permissions: unknown;
|
|
||||||
temporaryRange: string | null | undefined;
|
|
||||||
temporaryMode: string | null | undefined;
|
|
||||||
temporaryAccessStartTime: Date | null | undefined;
|
|
||||||
temporaryAccessEndTime: Date | null | undefined;
|
|
||||||
isTemporary: boolean;
|
|
||||||
}[];
|
|
||||||
orgId: string;
|
|
||||||
orgAuthEnforced: boolean | null | undefined;
|
|
||||||
orgGoogleSsoAuthEnforced: boolean;
|
|
||||||
orgRole: OrgMembershipRole;
|
|
||||||
userId: string;
|
|
||||||
projectId: string;
|
|
||||||
username: string;
|
|
||||||
projectType?: string | null;
|
|
||||||
id: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
shouldUseNewPrivilegeSystem: boolean;
|
|
||||||
bypassOrgAuthEnabled: boolean;
|
|
||||||
metadata: {
|
|
||||||
id: string;
|
|
||||||
key: string;
|
|
||||||
value: string;
|
|
||||||
}[];
|
|
||||||
userGroupRoles: {
|
|
||||||
id: string;
|
|
||||||
role: string;
|
|
||||||
customRoleSlug: string;
|
|
||||||
permissions: unknown;
|
|
||||||
temporaryRange: string | null | undefined;
|
|
||||||
temporaryMode: string | null | undefined;
|
|
||||||
temporaryAccessStartTime: Date | null | undefined;
|
|
||||||
temporaryAccessEndTime: Date | null | undefined;
|
|
||||||
isTemporary: boolean;
|
|
||||||
}[];
|
|
||||||
projecMembershiptRoles: {
|
|
||||||
id: string;
|
|
||||||
role: string;
|
|
||||||
customRoleSlug: string;
|
|
||||||
permissions: unknown;
|
|
||||||
temporaryRange: string | null | undefined;
|
|
||||||
temporaryMode: string | null | undefined;
|
|
||||||
temporaryAccessStartTime: Date | null | undefined;
|
|
||||||
temporaryAccessEndTime: Date | null | undefined;
|
|
||||||
isTemporary: boolean;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
| undefined
|
|
||||||
>;
|
|
||||||
getProjectIdentityPermission: (
|
|
||||||
identityId: string,
|
|
||||||
projectId: string
|
|
||||||
) => Promise<
|
|
||||||
| {
|
|
||||||
roles: {
|
|
||||||
id: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
isTemporary: boolean;
|
|
||||||
role: string;
|
|
||||||
projectMembershipId: string;
|
|
||||||
temporaryRange?: string | null | undefined;
|
|
||||||
permissions?: unknown;
|
|
||||||
customRoleId?: string | null | undefined;
|
|
||||||
temporaryMode?: string | null | undefined;
|
|
||||||
temporaryAccessStartTime?: Date | null | undefined;
|
|
||||||
temporaryAccessEndTime?: Date | null | undefined;
|
|
||||||
customRoleSlug?: string | null | undefined;
|
|
||||||
}[];
|
|
||||||
additionalPrivileges: {
|
|
||||||
id: string;
|
|
||||||
permissions: unknown;
|
|
||||||
temporaryRange: string | null | undefined;
|
|
||||||
temporaryMode: string | null | undefined;
|
|
||||||
temporaryAccessEndTime: Date | null | undefined;
|
|
||||||
temporaryAccessStartTime: Date | null | undefined;
|
|
||||||
isTemporary: boolean;
|
|
||||||
}[];
|
|
||||||
id: string;
|
|
||||||
identityId: string;
|
|
||||||
username: string;
|
|
||||||
projectId: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
orgId: string;
|
|
||||||
projectType?: string | null;
|
|
||||||
shouldUseNewPrivilegeSystem: boolean;
|
|
||||||
orgAuthEnforced: boolean;
|
|
||||||
metadata: {
|
|
||||||
id: string;
|
|
||||||
key: string;
|
|
||||||
value: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
| undefined
|
|
||||||
>;
|
|
||||||
getProjectUserPermissions: (projectId: string) => Promise<
|
getProjectUserPermissions: (projectId: string) => Promise<
|
||||||
{
|
{
|
||||||
roles: {
|
roles: {
|
||||||
@@ -310,128 +182,181 @@ export interface TPermissionDALFactory {
|
|||||||
}[];
|
}[];
|
||||||
}[]
|
}[]
|
||||||
>;
|
>;
|
||||||
|
getPermission: (dto: {
|
||||||
|
scopeData: AccessScopeData;
|
||||||
|
actorId: string;
|
||||||
|
actorType: ActorType.IDENTITY | ActorType.USER;
|
||||||
|
tx?: Knex;
|
||||||
|
}) => Promise<TPermissionDataReturn[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
|
export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
|
||||||
const getOrgPermission: TPermissionDALFactory["getOrgPermission"] = async (userId: string, orgId: string) => {
|
const getPermission: TPermissionDALFactory["getPermission"] = async ({ scopeData, tx, actorId, actorType }) => {
|
||||||
try {
|
try {
|
||||||
const groupSubQuery = db(TableName.Groups)
|
// akhilmhdh: when group has another group like sub group we would need recursively go down
|
||||||
.where(`${TableName.Groups}.orgId`, orgId)
|
const userGroupSubquery = (tx || db)(TableName.Groups)
|
||||||
.join(TableName.UserGroupMembership, (queryBuilder) => {
|
.leftJoin(TableName.UserGroupMembership, `${TableName.UserGroupMembership}.groupId`, `${TableName.Groups}.id`)
|
||||||
queryBuilder
|
.where(`${TableName.Groups}.orgId`, scopeData.orgId)
|
||||||
.on(`${TableName.UserGroupMembership}.groupId`, `${TableName.Groups}.id`)
|
.where(`${TableName.UserGroupMembership}.userId`, actorId)
|
||||||
.andOn(`${TableName.UserGroupMembership}.userId`, db.raw("?", [userId]));
|
.select(db.ref("id").withSchema(TableName.Groups));
|
||||||
})
|
|
||||||
.leftJoin(TableName.OrgRoles, `${TableName.Groups}.roleId`, `${TableName.OrgRoles}.id`)
|
|
||||||
.select(
|
|
||||||
db.ref("id").withSchema(TableName.Groups).as("groupId"),
|
|
||||||
db.ref("orgId").withSchema(TableName.Groups).as("groupOrgId"),
|
|
||||||
db.ref("name").withSchema(TableName.Groups).as("groupName"),
|
|
||||||
db.ref("slug").withSchema(TableName.Groups).as("groupSlug"),
|
|
||||||
db.ref("role").withSchema(TableName.Groups).as("groupRole"),
|
|
||||||
db.ref("roleId").withSchema(TableName.Groups).as("groupRoleId"),
|
|
||||||
db.ref("createdAt").withSchema(TableName.Groups).as("groupCreatedAt"),
|
|
||||||
db.ref("updatedAt").withSchema(TableName.Groups).as("groupUpdatedAt"),
|
|
||||||
db.ref("permissions").withSchema(TableName.OrgRoles).as("groupCustomRolePermission")
|
|
||||||
);
|
|
||||||
|
|
||||||
const membership = await db
|
const docs = await (tx || db)
|
||||||
.replicaNode()(TableName.OrgMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where(`${TableName.OrgMembership}.orgId`, orgId)
|
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
||||||
.where(`${TableName.OrgMembership}.userId`, userId)
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
.leftJoin(TableName.OrgRoles, `${TableName.OrgRoles}.id`, `${TableName.OrgMembership}.roleId`)
|
.leftJoin(
|
||||||
.leftJoin<Awaited<typeof groupSubQuery>[0]>(
|
TableName.AdditionalPrivilege,
|
||||||
groupSubQuery.as("userGroups"),
|
`${TableName.Membership}.id`,
|
||||||
"userGroups.groupOrgId",
|
`${TableName.AdditionalPrivilege}.membershipId`
|
||||||
db.raw("?", [orgId])
|
|
||||||
)
|
)
|
||||||
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.OrgMembership}.orgId`)
|
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
||||||
|
if (actorType === ActorType.USER) {
|
||||||
|
void queryBuilder
|
||||||
|
.on(`${TableName.Membership}.actorUserId`, `${TableName.IdentityMetadata}.userId`)
|
||||||
|
.andOn(`${TableName.Membership}.scopeOrgId`, `${TableName.IdentityMetadata}.orgId`);
|
||||||
|
} else if (actorType === ActorType.IDENTITY) {
|
||||||
|
void queryBuilder
|
||||||
|
.on(`${TableName.Membership}.actorIdentityId`, `${TableName.IdentityMetadata}.identityId`)
|
||||||
|
.andOn(`${TableName.Membership}.scopeOrgId`, `${TableName.IdentityMetadata}.orgId`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.where(`${TableName.Membership}.scopeOrgId`, scopeData.orgId)
|
||||||
|
.where((qb) => {
|
||||||
|
if (actorType === ActorType.USER) {
|
||||||
|
void qb
|
||||||
|
.where(`${TableName.Membership}.actorUserId`, actorId)
|
||||||
|
.orWhereIn(`${TableName.Membership}.actorGroupId`, userGroupSubquery);
|
||||||
|
} else if (actorType === ActorType.IDENTITY) {
|
||||||
|
void qb.where(`${TableName.Membership}.actorIdentityId`, actorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scopeData.scope === AccessScope.Organization) {
|
||||||
|
void qb.where(`${TableName.Membership}.scope`, AccessScope.Organization);
|
||||||
|
} else if (scopeData.scope === AccessScope.Namespace) {
|
||||||
|
void qb
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Namespace)
|
||||||
|
.where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId)
|
||||||
|
.whereNull(`${TableName.Membership}.scopeNamespaceId`);
|
||||||
|
} else if (scopeData.scope === AccessScope.Project) {
|
||||||
|
void qb
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
|
.where(`${TableName.Membership}.scopeProjectId`, scopeData.projectId);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.select(selectAllTableCols(TableName.Membership))
|
||||||
.select(
|
.select(
|
||||||
selectAllTableCols(TableName.OrgMembership),
|
db.ref("slug").withSchema(TableName.Role).as("roleSlug"),
|
||||||
db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization),
|
db.ref("permissions").withSchema(TableName.Role).as("customRolePermission"),
|
||||||
db.ref("slug").withSchema(TableName.OrgRoles).withSchema(TableName.OrgRoles).as("customRoleSlug"),
|
db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"),
|
||||||
db.ref("permissions").withSchema(TableName.OrgRoles),
|
db.ref("role").withSchema(TableName.MembershipRole).as("membershipRole"),
|
||||||
db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"),
|
db.ref("temporaryMode").withSchema(TableName.MembershipRole).as("membershipRoleTemporaryMode"),
|
||||||
db.ref("googleSsoAuthEnforced").withSchema(TableName.Organization).as("orgGoogleSsoAuthEnforced"),
|
db.ref("isTemporary").withSchema(TableName.MembershipRole).as("membershipRoleIsTemporary"),
|
||||||
db.ref("bypassOrgAuthEnabled").withSchema(TableName.Organization).as("bypassOrgAuthEnabled"),
|
db.ref("temporaryRange").withSchema(TableName.MembershipRole).as("membershipRoleTemporaryRange"),
|
||||||
db.ref("groupId").withSchema("userGroups"),
|
db
|
||||||
db.ref("groupOrgId").withSchema("userGroups"),
|
.ref("temporaryAccessStartTime")
|
||||||
db.ref("groupName").withSchema("userGroups"),
|
.withSchema(TableName.MembershipRole)
|
||||||
db.ref("groupSlug").withSchema("userGroups"),
|
.as("membershipRoleTemporaryAccessStartTime"),
|
||||||
db.ref("groupRole").withSchema("userGroups"),
|
db
|
||||||
db.ref("groupRoleId").withSchema("userGroups"),
|
.ref("temporaryAccessEndTime")
|
||||||
db.ref("groupCreatedAt").withSchema("userGroups"),
|
.withSchema(TableName.MembershipRole)
|
||||||
db.ref("groupUpdatedAt").withSchema("userGroups"),
|
.as("membershipRoleTemporaryAccessEndTime"),
|
||||||
db.ref("groupCustomRolePermission").withSchema("userGroups")
|
db.ref("createdAt").withSchema(TableName.MembershipRole).as("membershipRoleCreatedAt"),
|
||||||
|
db.ref("updatedAt").withSchema(TableName.MembershipRole).as("membershipRoleUpdatedAt"),
|
||||||
|
db.ref("id").withSchema(TableName.AdditionalPrivilege).as("additionalPrivilegeId"),
|
||||||
|
db.ref("name").withSchema(TableName.AdditionalPrivilege).as("additionalPrivilegeName"),
|
||||||
|
db.ref("permissions").withSchema(TableName.AdditionalPrivilege).as("additionalPrivilegePermissions"),
|
||||||
|
db.ref("id").withSchema(TableName.AdditionalPrivilege).as("additionalPrivilegeId"),
|
||||||
|
db.ref("temporaryMode").withSchema(TableName.AdditionalPrivilege).as("additionalPrivilegeTemporaryMode"),
|
||||||
|
db.ref("isTemporary").withSchema(TableName.AdditionalPrivilege).as("additionalPrivilegeIsTemporary"),
|
||||||
|
db.ref("temporaryRange").withSchema(TableName.AdditionalPrivilege).as("additionalPrivilegeTemporaryRange"),
|
||||||
|
db
|
||||||
|
.ref("temporaryAccessStartTime")
|
||||||
|
.withSchema(TableName.AdditionalPrivilege)
|
||||||
|
.as("additionalPrivilegeTemporaryAccessStartTime"),
|
||||||
|
db
|
||||||
|
.ref("temporaryAccessEndTime")
|
||||||
|
.withSchema(TableName.AdditionalPrivilege)
|
||||||
|
.as("additionalPrivilegeTemporaryAccessEndTime"),
|
||||||
|
db.ref("createdAt").withSchema(TableName.AdditionalPrivilege).as("additionalPrivilegeCreatedAt"),
|
||||||
|
db.ref("updatedAt").withSchema(TableName.AdditionalPrivilege).as("additionalPrivilegeUpdatedAt"),
|
||||||
|
db.ref("id").withSchema(TableName.IdentityMetadata).as("metadataId"),
|
||||||
|
db.ref("key").withSchema(TableName.IdentityMetadata).as("metadataKey"),
|
||||||
|
db.ref("value").withSchema(TableName.IdentityMetadata).as("metadataValue")
|
||||||
);
|
);
|
||||||
|
|
||||||
const [formatedDoc] = sqlNestRelationships({
|
const data = sqlNestRelationships({
|
||||||
data: membership,
|
data: docs,
|
||||||
key: "id",
|
key: "id",
|
||||||
parentMapper: (el) =>
|
parentMapper: (el) => MembershipsSchema.parse(el),
|
||||||
OrgMembershipsSchema.extend({
|
|
||||||
permissions: z.unknown(),
|
|
||||||
orgAuthEnforced: z.boolean().optional().nullable(),
|
|
||||||
orgGoogleSsoAuthEnforced: z.boolean(),
|
|
||||||
bypassOrgAuthEnabled: z.boolean(),
|
|
||||||
customRoleSlug: z.string().optional().nullable(),
|
|
||||||
shouldUseNewPrivilegeSystem: z.boolean()
|
|
||||||
}).parse(el),
|
|
||||||
childrenMapper: [
|
childrenMapper: [
|
||||||
{
|
{
|
||||||
key: "groupId",
|
key: "additionalPrivilegeId",
|
||||||
label: "groups" as const,
|
label: "additionalPrivileges" as const,
|
||||||
mapper: ({
|
mapper: ({
|
||||||
groupId,
|
additionalPrivilegeId,
|
||||||
groupUpdatedAt,
|
additionalPrivilegePermissions,
|
||||||
groupCreatedAt,
|
additionalPrivilegeIsTemporary,
|
||||||
groupRole,
|
additionalPrivilegeTemporaryMode,
|
||||||
groupRoleId,
|
additionalPrivilegeTemporaryRange,
|
||||||
groupCustomRolePermission,
|
additionalPrivilegeTemporaryAccessEndTime,
|
||||||
groupName,
|
additionalPrivilegeTemporaryAccessStartTime,
|
||||||
groupSlug,
|
additionalPrivilegeCreatedAt,
|
||||||
groupOrgId
|
additionalPrivilegeUpdatedAt
|
||||||
}) => ({
|
}) => ({
|
||||||
id: groupId,
|
id: additionalPrivilegeId,
|
||||||
updatedAt: groupUpdatedAt,
|
permissions: additionalPrivilegePermissions,
|
||||||
createdAt: groupCreatedAt,
|
temporaryRange: additionalPrivilegeTemporaryRange,
|
||||||
role: groupRole,
|
temporaryMode: additionalPrivilegeTemporaryMode,
|
||||||
roleId: groupRoleId,
|
temporaryAccessStartTime: additionalPrivilegeTemporaryAccessStartTime,
|
||||||
customRolePermission: groupCustomRolePermission,
|
temporaryAccessEndTime: additionalPrivilegeTemporaryAccessEndTime,
|
||||||
name: groupName,
|
isTemporary: additionalPrivilegeIsTemporary,
|
||||||
slug: groupSlug,
|
createdAt: additionalPrivilegeCreatedAt,
|
||||||
orgId: groupOrgId
|
updatedAt: additionalPrivilegeUpdatedAt
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "membershipRoleId",
|
||||||
|
label: "roles" as const,
|
||||||
|
mapper: ({
|
||||||
|
roleSlug,
|
||||||
|
customRolePermission,
|
||||||
|
membershipRoleId,
|
||||||
|
membershipRole,
|
||||||
|
membershipRoleIsTemporary,
|
||||||
|
membershipRoleTemporaryMode,
|
||||||
|
membershipRoleTemporaryRange,
|
||||||
|
membershipRoleTemporaryAccessEndTime,
|
||||||
|
membershipRoleTemporaryAccessStartTime,
|
||||||
|
membershipRoleCreatedAt,
|
||||||
|
membershipRoleUpdatedAt
|
||||||
|
}) => ({
|
||||||
|
id: membershipRoleId,
|
||||||
|
role: membershipRole,
|
||||||
|
permissions: customRolePermission,
|
||||||
|
customRoleSlug: roleSlug,
|
||||||
|
temporaryRange: membershipRoleTemporaryRange,
|
||||||
|
temporaryMode: membershipRoleTemporaryMode,
|
||||||
|
temporaryAccessStartTime: membershipRoleTemporaryAccessStartTime,
|
||||||
|
temporaryAccessEndTime: membershipRoleTemporaryAccessEndTime,
|
||||||
|
isTemporary: membershipRoleIsTemporary,
|
||||||
|
createdAt: membershipRoleCreatedAt,
|
||||||
|
updatedAt: membershipRoleUpdatedAt
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "metadataId",
|
||||||
|
label: "metadata" as const,
|
||||||
|
mapper: ({ metadataKey, metadataValue, metadataId }) => ({
|
||||||
|
id: metadataId,
|
||||||
|
key: metadataKey,
|
||||||
|
value: metadataValue
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
return data;
|
||||||
return formatedDoc;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "GetOrgPermission" });
|
throw new DatabaseError({ error, name: "Get Permission" });
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getOrgIdentityPermission: TPermissionDALFactory["getOrgIdentityPermission"] = async (
|
|
||||||
identityId: string,
|
|
||||||
orgId: string
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
const membership = await db
|
|
||||||
.replicaNode()(TableName.IdentityOrgMembership)
|
|
||||||
.leftJoin(TableName.OrgRoles, `${TableName.IdentityOrgMembership}.roleId`, `${TableName.OrgRoles}.id`)
|
|
||||||
.join(TableName.Organization, `${TableName.IdentityOrgMembership}.orgId`, `${TableName.Organization}.id`)
|
|
||||||
.where("identityId", identityId)
|
|
||||||
.where(`${TableName.IdentityOrgMembership}.orgId`, orgId)
|
|
||||||
.select(selectAllTableCols(TableName.IdentityOrgMembership))
|
|
||||||
.select(db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"))
|
|
||||||
.select("permissions")
|
|
||||||
.select(db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization))
|
|
||||||
.first();
|
|
||||||
|
|
||||||
return membership;
|
|
||||||
} catch (error) {
|
|
||||||
throw new DatabaseError({ error, name: "GetOrgIdentityPermission" });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -841,315 +766,6 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectPermission: TPermissionDALFactory["getProjectPermission"] = async (
|
|
||||||
userId: string,
|
|
||||||
projectId: string
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
const subQueryUserGroups = db(TableName.UserGroupMembership).where("userId", userId).select("groupId");
|
|
||||||
const docs = await db
|
|
||||||
.replicaNode()(TableName.Users)
|
|
||||||
.where(`${TableName.Users}.id`, userId)
|
|
||||||
.leftJoin(TableName.GroupProjectMembership, (queryBuilder) => {
|
|
||||||
void queryBuilder
|
|
||||||
.on(`${TableName.GroupProjectMembership}.projectId`, db.raw("?", [projectId]))
|
|
||||||
// @ts-expect-error akhilmhdh: this is valid knexjs query. Its just ts type argument is missing it
|
|
||||||
.andOnIn(`${TableName.GroupProjectMembership}.groupId`, subQueryUserGroups);
|
|
||||||
})
|
|
||||||
.leftJoin(
|
|
||||||
TableName.GroupProjectMembershipRole,
|
|
||||||
`${TableName.GroupProjectMembershipRole}.projectMembershipId`,
|
|
||||||
`${TableName.GroupProjectMembership}.id`
|
|
||||||
)
|
|
||||||
.leftJoin<TProjectRoles>(
|
|
||||||
{ groupCustomRoles: TableName.ProjectRoles },
|
|
||||||
`${TableName.GroupProjectMembershipRole}.customRoleId`,
|
|
||||||
`groupCustomRoles.id`
|
|
||||||
)
|
|
||||||
.leftJoin(TableName.ProjectMembership, (queryBuilder) => {
|
|
||||||
void queryBuilder
|
|
||||||
.on(`${TableName.ProjectMembership}.projectId`, db.raw("?", [projectId]))
|
|
||||||
.andOn(`${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`);
|
|
||||||
})
|
|
||||||
.leftJoin(
|
|
||||||
TableName.ProjectUserMembershipRole,
|
|
||||||
`${TableName.ProjectUserMembershipRole}.projectMembershipId`,
|
|
||||||
`${TableName.ProjectMembership}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.ProjectRoles,
|
|
||||||
`${TableName.ProjectUserMembershipRole}.customRoleId`,
|
|
||||||
`${TableName.ProjectRoles}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(TableName.ProjectUserAdditionalPrivilege, (queryBuilder) => {
|
|
||||||
void queryBuilder
|
|
||||||
.on(`${TableName.ProjectUserAdditionalPrivilege}.projectId`, db.raw("?", [projectId]))
|
|
||||||
.andOn(`${TableName.ProjectUserAdditionalPrivilege}.userId`, `${TableName.Users}.id`);
|
|
||||||
})
|
|
||||||
.join<TProjects>(TableName.Project, `${TableName.Project}.id`, db.raw("?", [projectId]))
|
|
||||||
.join(TableName.Organization, `${TableName.Project}.orgId`, `${TableName.Organization}.id`)
|
|
||||||
.join(TableName.OrgMembership, (qb) => {
|
|
||||||
void qb
|
|
||||||
.on(`${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
|
||||||
.andOn(`${TableName.OrgMembership}.orgId`, `${TableName.Organization}.id`);
|
|
||||||
})
|
|
||||||
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
|
||||||
void queryBuilder
|
|
||||||
.on(`${TableName.Users}.id`, `${TableName.IdentityMetadata}.userId`)
|
|
||||||
.andOn(`${TableName.Organization}.id`, `${TableName.IdentityMetadata}.orgId`);
|
|
||||||
})
|
|
||||||
.select(
|
|
||||||
db.ref("id").withSchema(TableName.Users).as("userId"),
|
|
||||||
db.ref("username").withSchema(TableName.Users).as("username"),
|
|
||||||
// groups specific
|
|
||||||
db.ref("id").withSchema(TableName.GroupProjectMembership).as("groupMembershipId"),
|
|
||||||
db.ref("createdAt").withSchema(TableName.GroupProjectMembership).as("groupMembershipCreatedAt"),
|
|
||||||
db.ref("updatedAt").withSchema(TableName.GroupProjectMembership).as("groupMembershipUpdatedAt"),
|
|
||||||
db.ref("slug").withSchema("groupCustomRoles").as("userGroupProjectMembershipRoleCustomRoleSlug"),
|
|
||||||
db.ref("permissions").withSchema("groupCustomRoles").as("userGroupProjectMembershipRolePermission"),
|
|
||||||
db.ref("id").withSchema(TableName.GroupProjectMembershipRole).as("userGroupProjectMembershipRoleId"),
|
|
||||||
db.ref("role").withSchema(TableName.GroupProjectMembershipRole).as("userGroupProjectMembershipRole"),
|
|
||||||
db
|
|
||||||
.ref("customRoleId")
|
|
||||||
.withSchema(TableName.GroupProjectMembershipRole)
|
|
||||||
.as("userGroupProjectMembershipRoleCustomRoleId"),
|
|
||||||
db
|
|
||||||
.ref("isTemporary")
|
|
||||||
.withSchema(TableName.GroupProjectMembershipRole)
|
|
||||||
.as("userGroupProjectMembershipRoleIsTemporary"),
|
|
||||||
db
|
|
||||||
.ref("temporaryMode")
|
|
||||||
.withSchema(TableName.GroupProjectMembershipRole)
|
|
||||||
.as("userGroupProjectMembershipRoleTemporaryMode"),
|
|
||||||
db
|
|
||||||
.ref("temporaryRange")
|
|
||||||
.withSchema(TableName.GroupProjectMembershipRole)
|
|
||||||
.as("userGroupProjectMembershipRoleTemporaryRange"),
|
|
||||||
db
|
|
||||||
.ref("temporaryAccessStartTime")
|
|
||||||
.withSchema(TableName.GroupProjectMembershipRole)
|
|
||||||
.as("userGroupProjectMembershipRoleTemporaryAccessStartTime"),
|
|
||||||
db
|
|
||||||
.ref("temporaryAccessEndTime")
|
|
||||||
.withSchema(TableName.GroupProjectMembershipRole)
|
|
||||||
.as("userGroupProjectMembershipRoleTemporaryAccessEndTime"),
|
|
||||||
// user specific
|
|
||||||
db.ref("id").withSchema(TableName.ProjectMembership).as("membershipId"),
|
|
||||||
db.ref("createdAt").withSchema(TableName.ProjectMembership).as("membershipCreatedAt"),
|
|
||||||
db.ref("updatedAt").withSchema(TableName.ProjectMembership).as("membershipUpdatedAt"),
|
|
||||||
db.ref("slug").withSchema(TableName.ProjectRoles).as("userProjectMembershipRoleCustomRoleSlug"),
|
|
||||||
db.ref("permissions").withSchema(TableName.ProjectRoles).as("userProjectCustomRolePermission"),
|
|
||||||
db.ref("id").withSchema(TableName.ProjectUserMembershipRole).as("userProjectMembershipRoleId"),
|
|
||||||
db.ref("role").withSchema(TableName.ProjectUserMembershipRole).as("userProjectMembershipRole"),
|
|
||||||
db
|
|
||||||
.ref("temporaryMode")
|
|
||||||
.withSchema(TableName.ProjectUserMembershipRole)
|
|
||||||
.as("userProjectMembershipRoleTemporaryMode"),
|
|
||||||
db
|
|
||||||
.ref("isTemporary")
|
|
||||||
.withSchema(TableName.ProjectUserMembershipRole)
|
|
||||||
.as("userProjectMembershipRoleIsTemporary"),
|
|
||||||
db
|
|
||||||
.ref("temporaryRange")
|
|
||||||
.withSchema(TableName.ProjectUserMembershipRole)
|
|
||||||
.as("userProjectMembershipRoleTemporaryRange"),
|
|
||||||
db
|
|
||||||
.ref("temporaryAccessStartTime")
|
|
||||||
.withSchema(TableName.ProjectUserMembershipRole)
|
|
||||||
.as("userProjectMembershipRoleTemporaryAccessStartTime"),
|
|
||||||
db
|
|
||||||
.ref("temporaryAccessEndTime")
|
|
||||||
.withSchema(TableName.ProjectUserMembershipRole)
|
|
||||||
.as("userProjectMembershipRoleTemporaryAccessEndTime"),
|
|
||||||
db.ref("id").withSchema(TableName.ProjectUserAdditionalPrivilege).as("userAdditionalPrivilegesId"),
|
|
||||||
db
|
|
||||||
.ref("permissions")
|
|
||||||
.withSchema(TableName.ProjectUserAdditionalPrivilege)
|
|
||||||
.as("userAdditionalPrivilegesPermissions"),
|
|
||||||
db
|
|
||||||
.ref("temporaryMode")
|
|
||||||
.withSchema(TableName.ProjectUserAdditionalPrivilege)
|
|
||||||
.as("userAdditionalPrivilegesTemporaryMode"),
|
|
||||||
db
|
|
||||||
.ref("isTemporary")
|
|
||||||
.withSchema(TableName.ProjectUserAdditionalPrivilege)
|
|
||||||
.as("userAdditionalPrivilegesIsTemporary"),
|
|
||||||
db
|
|
||||||
.ref("temporaryRange")
|
|
||||||
.withSchema(TableName.ProjectUserAdditionalPrivilege)
|
|
||||||
.as("userAdditionalPrivilegesTemporaryRange"),
|
|
||||||
db.ref("userId").withSchema(TableName.ProjectUserAdditionalPrivilege).as("userAdditionalPrivilegesUserId"),
|
|
||||||
db
|
|
||||||
.ref("temporaryAccessStartTime")
|
|
||||||
.withSchema(TableName.ProjectUserAdditionalPrivilege)
|
|
||||||
.as("userAdditionalPrivilegesTemporaryAccessStartTime"),
|
|
||||||
db
|
|
||||||
.ref("temporaryAccessEndTime")
|
|
||||||
.withSchema(TableName.ProjectUserAdditionalPrivilege)
|
|
||||||
.as("userAdditionalPrivilegesTemporaryAccessEndTime"),
|
|
||||||
// general
|
|
||||||
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("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"),
|
|
||||||
db.ref("googleSsoAuthEnforced").withSchema(TableName.Organization).as("orgGoogleSsoAuthEnforced"),
|
|
||||||
db.ref("bypassOrgAuthEnabled").withSchema(TableName.Organization).as("bypassOrgAuthEnabled"),
|
|
||||||
db.ref("role").withSchema(TableName.OrgMembership).as("orgRole"),
|
|
||||||
db.ref("orgId").withSchema(TableName.Project),
|
|
||||||
db.ref("type").withSchema(TableName.Project).as("projectType"),
|
|
||||||
db.ref("id").withSchema(TableName.Project).as("projectId"),
|
|
||||||
db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization)
|
|
||||||
);
|
|
||||||
|
|
||||||
const [userPermission] = sqlNestRelationships({
|
|
||||||
data: docs,
|
|
||||||
key: "projectId",
|
|
||||||
parentMapper: ({
|
|
||||||
orgId,
|
|
||||||
username,
|
|
||||||
orgAuthEnforced,
|
|
||||||
orgGoogleSsoAuthEnforced,
|
|
||||||
orgRole,
|
|
||||||
membershipId,
|
|
||||||
groupMembershipId,
|
|
||||||
membershipCreatedAt,
|
|
||||||
groupMembershipCreatedAt,
|
|
||||||
groupMembershipUpdatedAt,
|
|
||||||
membershipUpdatedAt,
|
|
||||||
projectType,
|
|
||||||
shouldUseNewPrivilegeSystem,
|
|
||||||
bypassOrgAuthEnabled
|
|
||||||
}) => ({
|
|
||||||
orgId,
|
|
||||||
orgAuthEnforced,
|
|
||||||
orgGoogleSsoAuthEnforced,
|
|
||||||
orgRole: orgRole as OrgMembershipRole,
|
|
||||||
userId,
|
|
||||||
projectId,
|
|
||||||
username,
|
|
||||||
projectType,
|
|
||||||
id: membershipId || groupMembershipId,
|
|
||||||
createdAt: membershipCreatedAt || groupMembershipCreatedAt,
|
|
||||||
updatedAt: membershipUpdatedAt || groupMembershipUpdatedAt,
|
|
||||||
shouldUseNewPrivilegeSystem,
|
|
||||||
bypassOrgAuthEnabled
|
|
||||||
}),
|
|
||||||
childrenMapper: [
|
|
||||||
{
|
|
||||||
key: "userGroupProjectMembershipRoleId",
|
|
||||||
label: "userGroupRoles" as const,
|
|
||||||
mapper: ({
|
|
||||||
userGroupProjectMembershipRoleId,
|
|
||||||
userGroupProjectMembershipRole,
|
|
||||||
userGroupProjectMembershipRolePermission,
|
|
||||||
userGroupProjectMembershipRoleCustomRoleSlug,
|
|
||||||
userGroupProjectMembershipRoleIsTemporary,
|
|
||||||
userGroupProjectMembershipRoleTemporaryMode,
|
|
||||||
userGroupProjectMembershipRoleTemporaryAccessEndTime,
|
|
||||||
userGroupProjectMembershipRoleTemporaryAccessStartTime,
|
|
||||||
userGroupProjectMembershipRoleTemporaryRange
|
|
||||||
}) => ({
|
|
||||||
id: userGroupProjectMembershipRoleId,
|
|
||||||
role: userGroupProjectMembershipRole,
|
|
||||||
customRoleSlug: userGroupProjectMembershipRoleCustomRoleSlug,
|
|
||||||
permissions: userGroupProjectMembershipRolePermission,
|
|
||||||
temporaryRange: userGroupProjectMembershipRoleTemporaryRange,
|
|
||||||
temporaryMode: userGroupProjectMembershipRoleTemporaryMode,
|
|
||||||
temporaryAccessStartTime: userGroupProjectMembershipRoleTemporaryAccessStartTime,
|
|
||||||
temporaryAccessEndTime: userGroupProjectMembershipRoleTemporaryAccessEndTime,
|
|
||||||
isTemporary: userGroupProjectMembershipRoleIsTemporary
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "userProjectMembershipRoleId",
|
|
||||||
label: "projecMembershiptRoles" as const,
|
|
||||||
mapper: ({
|
|
||||||
userProjectMembershipRoleId,
|
|
||||||
userProjectMembershipRole,
|
|
||||||
userProjectCustomRolePermission,
|
|
||||||
userProjectMembershipRoleIsTemporary,
|
|
||||||
userProjectMembershipRoleTemporaryMode,
|
|
||||||
userProjectMembershipRoleTemporaryRange,
|
|
||||||
userProjectMembershipRoleTemporaryAccessEndTime,
|
|
||||||
userProjectMembershipRoleTemporaryAccessStartTime,
|
|
||||||
userProjectMembershipRoleCustomRoleSlug
|
|
||||||
}) => ({
|
|
||||||
id: userProjectMembershipRoleId,
|
|
||||||
role: userProjectMembershipRole,
|
|
||||||
customRoleSlug: userProjectMembershipRoleCustomRoleSlug,
|
|
||||||
permissions: userProjectCustomRolePermission,
|
|
||||||
temporaryRange: userProjectMembershipRoleTemporaryRange,
|
|
||||||
temporaryMode: userProjectMembershipRoleTemporaryMode,
|
|
||||||
temporaryAccessStartTime: userProjectMembershipRoleTemporaryAccessStartTime,
|
|
||||||
temporaryAccessEndTime: userProjectMembershipRoleTemporaryAccessEndTime,
|
|
||||||
isTemporary: userProjectMembershipRoleIsTemporary
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "userAdditionalPrivilegesId",
|
|
||||||
label: "additionalPrivileges" as const,
|
|
||||||
mapper: ({
|
|
||||||
userAdditionalPrivilegesId,
|
|
||||||
userAdditionalPrivilegesPermissions,
|
|
||||||
userAdditionalPrivilegesIsTemporary,
|
|
||||||
userAdditionalPrivilegesTemporaryMode,
|
|
||||||
userAdditionalPrivilegesTemporaryRange,
|
|
||||||
userAdditionalPrivilegesTemporaryAccessEndTime,
|
|
||||||
userAdditionalPrivilegesTemporaryAccessStartTime
|
|
||||||
}) => ({
|
|
||||||
id: userAdditionalPrivilegesId,
|
|
||||||
permissions: userAdditionalPrivilegesPermissions,
|
|
||||||
temporaryRange: userAdditionalPrivilegesTemporaryRange,
|
|
||||||
temporaryMode: userAdditionalPrivilegesTemporaryMode,
|
|
||||||
temporaryAccessStartTime: userAdditionalPrivilegesTemporaryAccessStartTime,
|
|
||||||
temporaryAccessEndTime: userAdditionalPrivilegesTemporaryAccessEndTime,
|
|
||||||
isTemporary: userAdditionalPrivilegesIsTemporary
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "metadataId",
|
|
||||||
label: "metadata" as const,
|
|
||||||
mapper: ({ metadataKey, metadataValue, metadataId }) => ({
|
|
||||||
id: metadataId,
|
|
||||||
key: metadataKey,
|
|
||||||
value: metadataValue
|
|
||||||
})
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!userPermission) return undefined;
|
|
||||||
if (!userPermission?.userGroupRoles?.[0] && !userPermission?.projecMembershiptRoles?.[0]) return undefined;
|
|
||||||
|
|
||||||
// when introducting cron mode change it here
|
|
||||||
const activeRoles =
|
|
||||||
userPermission?.projecMembershiptRoles?.filter(
|
|
||||||
({ isTemporary, temporaryAccessEndTime }) =>
|
|
||||||
!isTemporary || (isTemporary && temporaryAccessEndTime && new Date() < temporaryAccessEndTime)
|
|
||||||
) ?? [];
|
|
||||||
|
|
||||||
const activeGroupRoles =
|
|
||||||
userPermission?.userGroupRoles?.filter(
|
|
||||||
({ isTemporary, temporaryAccessEndTime }) =>
|
|
||||||
!isTemporary || (isTemporary && temporaryAccessEndTime && new Date() < temporaryAccessEndTime)
|
|
||||||
) ?? [];
|
|
||||||
|
|
||||||
const activeAdditionalPrivileges =
|
|
||||||
userPermission?.additionalPrivileges?.filter(
|
|
||||||
({ isTemporary, temporaryAccessEndTime }) =>
|
|
||||||
!isTemporary || (isTemporary && temporaryAccessEndTime && new Date() < temporaryAccessEndTime)
|
|
||||||
) ?? [];
|
|
||||||
|
|
||||||
return {
|
|
||||||
...userPermission,
|
|
||||||
roles: [...activeRoles, ...activeGroupRoles],
|
|
||||||
additionalPrivileges: activeAdditionalPrivileges
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new DatabaseError({ error, name: "GetProjectPermission" });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getProjectIdentityPermissions: TPermissionDALFactory["getProjectIdentityPermissions"] = async (
|
const getProjectIdentityPermissions: TPermissionDALFactory["getProjectIdentityPermissions"] = async (
|
||||||
projectId: string
|
projectId: string
|
||||||
) => {
|
) => {
|
||||||
@@ -1309,170 +925,10 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectIdentityPermission: TPermissionDALFactory["getProjectIdentityPermission"] = async (
|
|
||||||
identityId,
|
|
||||||
projectId
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
const docs = await db
|
|
||||||
.replicaNode()(TableName.IdentityProjectMembership)
|
|
||||||
.join(
|
|
||||||
TableName.IdentityProjectMembershipRole,
|
|
||||||
`${TableName.IdentityProjectMembershipRole}.projectMembershipId`,
|
|
||||||
`${TableName.IdentityProjectMembership}.id`
|
|
||||||
)
|
|
||||||
.join(TableName.Identity, `${TableName.Identity}.id`, `${TableName.IdentityProjectMembership}.identityId`)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.ProjectRoles,
|
|
||||||
`${TableName.IdentityProjectMembershipRole}.customRoleId`,
|
|
||||||
`${TableName.ProjectRoles}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.IdentityProjectAdditionalPrivilege,
|
|
||||||
`${TableName.IdentityProjectAdditionalPrivilege}.projectMembershipId`,
|
|
||||||
`${TableName.IdentityProjectMembership}.id`
|
|
||||||
)
|
|
||||||
.join(
|
|
||||||
// Join the Project table to later select orgId
|
|
||||||
TableName.Project,
|
|
||||||
`${TableName.IdentityProjectMembership}.projectId`,
|
|
||||||
`${TableName.Project}.id`
|
|
||||||
)
|
|
||||||
.join(TableName.Organization, `${TableName.Project}.orgId`, `${TableName.Organization}.id`)
|
|
||||||
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
|
||||||
void queryBuilder
|
|
||||||
.on(`${TableName.Identity}.id`, `${TableName.IdentityMetadata}.identityId`)
|
|
||||||
.andOn(`${TableName.Project}.orgId`, `${TableName.IdentityMetadata}.orgId`);
|
|
||||||
})
|
|
||||||
.where(`${TableName.IdentityProjectMembership}.identityId`, identityId)
|
|
||||||
.where(`${TableName.IdentityProjectMembership}.projectId`, projectId)
|
|
||||||
.select(selectAllTableCols(TableName.IdentityProjectMembershipRole))
|
|
||||||
.select(
|
|
||||||
db.ref("id").withSchema(TableName.IdentityProjectMembership).as("membershipId"),
|
|
||||||
db.ref("name").withSchema(TableName.Identity).as("identityName"),
|
|
||||||
db.ref("orgId").withSchema(TableName.Project).as("orgId"), // Now you can select orgId from Project
|
|
||||||
db.ref("type").withSchema(TableName.Project).as("projectType"),
|
|
||||||
db.ref("createdAt").withSchema(TableName.IdentityProjectMembership).as("membershipCreatedAt"),
|
|
||||||
db.ref("updatedAt").withSchema(TableName.IdentityProjectMembership).as("membershipUpdatedAt"),
|
|
||||||
db.ref("slug").withSchema(TableName.ProjectRoles).as("customRoleSlug"),
|
|
||||||
db.ref("permissions").withSchema(TableName.ProjectRoles),
|
|
||||||
db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization),
|
|
||||||
db.ref("id").withSchema(TableName.IdentityProjectAdditionalPrivilege).as("identityApId"),
|
|
||||||
db.ref("permissions").withSchema(TableName.IdentityProjectAdditionalPrivilege).as("identityApPermissions"),
|
|
||||||
db
|
|
||||||
.ref("temporaryMode")
|
|
||||||
.withSchema(TableName.IdentityProjectAdditionalPrivilege)
|
|
||||||
.as("identityApTemporaryMode"),
|
|
||||||
db.ref("isTemporary").withSchema(TableName.IdentityProjectAdditionalPrivilege).as("identityApIsTemporary"),
|
|
||||||
db
|
|
||||||
.ref("temporaryRange")
|
|
||||||
.withSchema(TableName.IdentityProjectAdditionalPrivilege)
|
|
||||||
.as("identityApTemporaryRange"),
|
|
||||||
db
|
|
||||||
.ref("temporaryAccessStartTime")
|
|
||||||
.withSchema(TableName.IdentityProjectAdditionalPrivilege)
|
|
||||||
.as("identityApTemporaryAccessStartTime"),
|
|
||||||
db
|
|
||||||
.ref("temporaryAccessEndTime")
|
|
||||||
.withSchema(TableName.IdentityProjectAdditionalPrivilege)
|
|
||||||
.as("identityApTemporaryAccessEndTime"),
|
|
||||||
db.ref("id").withSchema(TableName.IdentityMetadata).as("metadataId"),
|
|
||||||
db.ref("key").withSchema(TableName.IdentityMetadata).as("metadataKey"),
|
|
||||||
db.ref("value").withSchema(TableName.IdentityMetadata).as("metadataValue")
|
|
||||||
);
|
|
||||||
|
|
||||||
const permission = sqlNestRelationships({
|
|
||||||
data: docs,
|
|
||||||
key: "membershipId",
|
|
||||||
parentMapper: ({
|
|
||||||
membershipId,
|
|
||||||
membershipCreatedAt,
|
|
||||||
membershipUpdatedAt,
|
|
||||||
orgId,
|
|
||||||
identityName,
|
|
||||||
projectType,
|
|
||||||
shouldUseNewPrivilegeSystem
|
|
||||||
}) => ({
|
|
||||||
id: membershipId,
|
|
||||||
identityId,
|
|
||||||
username: identityName,
|
|
||||||
projectId,
|
|
||||||
createdAt: membershipCreatedAt,
|
|
||||||
updatedAt: membershipUpdatedAt,
|
|
||||||
orgId,
|
|
||||||
projectType,
|
|
||||||
shouldUseNewPrivilegeSystem,
|
|
||||||
// just a prefilled value
|
|
||||||
orgAuthEnforced: false
|
|
||||||
}),
|
|
||||||
childrenMapper: [
|
|
||||||
{
|
|
||||||
key: "id",
|
|
||||||
label: "roles" as const,
|
|
||||||
mapper: (data) =>
|
|
||||||
IdentityProjectMembershipRoleSchema.extend({
|
|
||||||
permissions: z.unknown(),
|
|
||||||
customRoleSlug: z.string().optional().nullable()
|
|
||||||
}).parse(data)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "identityApId",
|
|
||||||
label: "additionalPrivileges" as const,
|
|
||||||
mapper: ({
|
|
||||||
identityApId,
|
|
||||||
identityApPermissions,
|
|
||||||
identityApIsTemporary,
|
|
||||||
identityApTemporaryMode,
|
|
||||||
identityApTemporaryRange,
|
|
||||||
identityApTemporaryAccessEndTime,
|
|
||||||
identityApTemporaryAccessStartTime
|
|
||||||
}) => ({
|
|
||||||
id: identityApId,
|
|
||||||
permissions: identityApPermissions,
|
|
||||||
temporaryRange: identityApTemporaryRange,
|
|
||||||
temporaryMode: identityApTemporaryMode,
|
|
||||||
temporaryAccessEndTime: identityApTemporaryAccessEndTime,
|
|
||||||
temporaryAccessStartTime: identityApTemporaryAccessStartTime,
|
|
||||||
isTemporary: identityApIsTemporary
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "metadataId",
|
|
||||||
label: "metadata" as const,
|
|
||||||
mapper: ({ metadataKey, metadataValue, metadataId }) => ({
|
|
||||||
id: metadataId,
|
|
||||||
key: metadataKey,
|
|
||||||
value: metadataValue
|
|
||||||
})
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!permission?.[0]) return undefined;
|
|
||||||
|
|
||||||
// when introducting cron mode change it here
|
|
||||||
const activeRoles = permission?.[0]?.roles.filter(
|
|
||||||
({ isTemporary, temporaryAccessEndTime }) =>
|
|
||||||
!isTemporary || (isTemporary && temporaryAccessEndTime && new Date() < temporaryAccessEndTime)
|
|
||||||
);
|
|
||||||
const activeAdditionalPrivileges = permission?.[0]?.additionalPrivileges?.filter(
|
|
||||||
({ isTemporary, temporaryAccessEndTime }) =>
|
|
||||||
!isTemporary || (isTemporary && temporaryAccessEndTime && new Date() < temporaryAccessEndTime)
|
|
||||||
);
|
|
||||||
|
|
||||||
return { ...permission[0], roles: activeRoles, additionalPrivileges: activeAdditionalPrivileges };
|
|
||||||
} catch (error) {
|
|
||||||
throw new DatabaseError({ error, name: "GetProjectIdentityPermission" });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getOrgPermission,
|
|
||||||
getOrgIdentityPermission,
|
|
||||||
getProjectPermission,
|
|
||||||
getProjectIdentityPermission,
|
|
||||||
getProjectUserPermissions,
|
getProjectUserPermissions,
|
||||||
getProjectIdentityPermissions,
|
getProjectIdentityPermissions,
|
||||||
getProjectGroupPermissions
|
getProjectGroupPermissions,
|
||||||
|
getPermission
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { MongoAbility, RawRuleOf } from "@casl/ability";
|
import { MongoAbility } from "@casl/ability";
|
||||||
import { MongoQuery } from "@ucast/mongo2js";
|
import { MongoQuery } from "@ucast/mongo2js";
|
||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType, TMemberships } from "@app/db/schemas";
|
||||||
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
|
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
import { OrgPermissionSet } from "./org-permission";
|
import { OrgPermissionSet } from "./org-permission";
|
||||||
@@ -50,162 +50,22 @@ export type TGetProjectPermissionArg = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type TPermissionServiceFactory = {
|
export type TPermissionServiceFactory = {
|
||||||
getUserOrgPermission: (
|
|
||||||
userId: string,
|
|
||||||
orgId: string,
|
|
||||||
authMethod: ActorAuthMethod,
|
|
||||||
userOrgId?: string
|
|
||||||
) => Promise<{
|
|
||||||
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
|
||||||
membership: {
|
|
||||||
status: string;
|
|
||||||
orgId: string;
|
|
||||||
id: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
role: string;
|
|
||||||
isActive: boolean;
|
|
||||||
shouldUseNewPrivilegeSystem: boolean;
|
|
||||||
bypassOrgAuthEnabled: boolean;
|
|
||||||
permissions?: unknown;
|
|
||||||
userId?: string | null | undefined;
|
|
||||||
roleId?: string | null | undefined;
|
|
||||||
inviteEmail?: string | null | undefined;
|
|
||||||
projectFavorites?: string[] | null | undefined;
|
|
||||||
customRoleSlug?: string | null | undefined;
|
|
||||||
orgAuthEnforced?: boolean | null | undefined;
|
|
||||||
} & {
|
|
||||||
groups: {
|
|
||||||
id: string;
|
|
||||||
updatedAt: Date;
|
|
||||||
createdAt: Date;
|
|
||||||
role: string;
|
|
||||||
roleId: string | null | undefined;
|
|
||||||
customRolePermission: unknown;
|
|
||||||
name: string;
|
|
||||||
slug: string;
|
|
||||||
orgId: string;
|
|
||||||
}[];
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
getOrgPermission: (
|
getOrgPermission: (
|
||||||
type: ActorType,
|
type: ActorType,
|
||||||
id: string,
|
id: string,
|
||||||
orgId: string,
|
orgId: string,
|
||||||
authMethod: ActorAuthMethod,
|
authMethod: ActorAuthMethod,
|
||||||
actorOrgId: string | undefined
|
actorOrgId: string | undefined
|
||||||
) => Promise<
|
) => Promise<{
|
||||||
| {
|
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
||||||
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
memberships: TMemberships[];
|
||||||
membership: {
|
}>;
|
||||||
status: string;
|
getProjectPermission: (arg: TGetProjectPermissionArg) => Promise<{
|
||||||
orgId: string;
|
|
||||||
id: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
role: string;
|
|
||||||
isActive: boolean;
|
|
||||||
shouldUseNewPrivilegeSystem: boolean;
|
|
||||||
bypassOrgAuthEnabled: boolean;
|
|
||||||
permissions?: unknown;
|
|
||||||
userId?: string | null | undefined;
|
|
||||||
roleId?: string | null | undefined;
|
|
||||||
inviteEmail?: string | null | undefined;
|
|
||||||
projectFavorites?: string[] | null | undefined;
|
|
||||||
customRoleSlug?: string | null | undefined;
|
|
||||||
orgAuthEnforced?: boolean | null | undefined;
|
|
||||||
} & {
|
|
||||||
groups: {
|
|
||||||
id: string;
|
|
||||||
updatedAt: Date;
|
|
||||||
createdAt: Date;
|
|
||||||
role: string;
|
|
||||||
roleId: string | null | undefined;
|
|
||||||
customRolePermission: unknown;
|
|
||||||
name: string;
|
|
||||||
slug: string;
|
|
||||||
orgId: string;
|
|
||||||
}[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
|
||||||
membership: {
|
|
||||||
id: string;
|
|
||||||
role: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
orgId: string;
|
|
||||||
roleId?: string | null | undefined;
|
|
||||||
permissions?: unknown;
|
|
||||||
identityId: string;
|
|
||||||
orgAuthEnforced: boolean | null | undefined;
|
|
||||||
shouldUseNewPrivilegeSystem: boolean;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
getUserProjectPermission: ({
|
|
||||||
userId,
|
|
||||||
projectId,
|
|
||||||
authMethod,
|
|
||||||
userOrgId,
|
|
||||||
actionProjectType
|
|
||||||
}: TGetUserProjectPermissionArg) => Promise<{
|
|
||||||
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
||||||
membership: {
|
memberships: TMemberships[];
|
||||||
id: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
userId: string;
|
|
||||||
projectId: string;
|
|
||||||
} & {
|
|
||||||
orgAuthEnforced: boolean | null | undefined;
|
|
||||||
orgId: string;
|
|
||||||
roles: Array<{
|
|
||||||
role: string;
|
|
||||||
}>;
|
|
||||||
shouldUseNewPrivilegeSystem: boolean;
|
|
||||||
};
|
|
||||||
hasRole: (role: string) => boolean;
|
hasRole: (role: string) => boolean;
|
||||||
}>;
|
}>;
|
||||||
getProjectPermission: <T extends ActorType>(
|
// TODO(simp): check what is this doing
|
||||||
arg: TGetProjectPermissionArg
|
|
||||||
) => Promise<
|
|
||||||
T extends ActorType.SERVICE
|
|
||||||
? {
|
|
||||||
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
|
||||||
membership: {
|
|
||||||
shouldUseNewPrivilegeSystem: boolean;
|
|
||||||
};
|
|
||||||
hasRole: (arg: string) => boolean;
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
|
||||||
membership: (T extends ActorType.USER
|
|
||||||
? {
|
|
||||||
id: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
userId: string;
|
|
||||||
projectId: string;
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
id: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
projectId: string;
|
|
||||||
identityId: string;
|
|
||||||
}) & {
|
|
||||||
orgAuthEnforced: boolean | null | undefined;
|
|
||||||
orgId: string;
|
|
||||||
roles: Array<{
|
|
||||||
role: string;
|
|
||||||
}>;
|
|
||||||
shouldUseNewPrivilegeSystem: boolean;
|
|
||||||
};
|
|
||||||
hasRole: (role: string) => boolean;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
getProjectPermissions: (projectId: string) => Promise<{
|
getProjectPermissions: (projectId: string) => Promise<{
|
||||||
userPermissions: {
|
userPermissions: {
|
||||||
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
||||||
@@ -226,55 +86,40 @@ export type TPermissionServiceFactory = {
|
|||||||
membershipId: string;
|
membershipId: string;
|
||||||
}[];
|
}[];
|
||||||
}>;
|
}>;
|
||||||
|
// TODO(simp): switch to role dal later
|
||||||
getOrgPermissionByRole: (
|
getOrgPermissionByRole: (
|
||||||
role: string,
|
role: string,
|
||||||
orgId: string
|
orgId: string
|
||||||
) => Promise<
|
) => Promise<{
|
||||||
| {
|
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
||||||
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
role?: {
|
||||||
role: {
|
name: string;
|
||||||
name: string;
|
orgId: string;
|
||||||
orgId: string;
|
id: string;
|
||||||
id: string;
|
createdAt: Date;
|
||||||
createdAt: Date;
|
updatedAt: Date;
|
||||||
updatedAt: Date;
|
slug: string;
|
||||||
slug: string;
|
permissions?: unknown;
|
||||||
permissions?: unknown;
|
description?: string | null | undefined;
|
||||||
description?: string | null | undefined;
|
};
|
||||||
};
|
}>;
|
||||||
}
|
|
||||||
| {
|
|
||||||
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
|
||||||
role?: undefined;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
getProjectPermissionByRole: (
|
getProjectPermissionByRole: (
|
||||||
role: string,
|
role: string,
|
||||||
projectId: string
|
projectId: string
|
||||||
) => Promise<
|
) => Promise<{
|
||||||
| {
|
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
||||||
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
role?: {
|
||||||
role: {
|
name: string;
|
||||||
name: string;
|
version: number;
|
||||||
version: number;
|
id: string;
|
||||||
id: string;
|
createdAt: Date;
|
||||||
createdAt: Date;
|
updatedAt: Date;
|
||||||
updatedAt: Date;
|
projectId: string;
|
||||||
projectId: string;
|
slug: string;
|
||||||
slug: string;
|
permissions?: unknown;
|
||||||
permissions?: unknown;
|
description?: string | null | undefined;
|
||||||
description?: string | null | undefined;
|
};
|
||||||
};
|
}>;
|
||||||
}
|
|
||||||
| {
|
|
||||||
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
|
||||||
role?: undefined;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
buildOrgPermission: (orgUserRoles: TBuildOrgPermissionDTO) => MongoAbility<OrgPermissionSet, MongoQuery>;
|
|
||||||
buildProjectPermissionRules: (
|
|
||||||
projectUserRoles: TBuildProjectPermissionDTO
|
|
||||||
) => RawRuleOf<MongoAbility<ProjectPermissionSet>>[];
|
|
||||||
checkGroupProjectPermission: ({
|
checkGroupProjectPermission: ({
|
||||||
groupId,
|
groupId,
|
||||||
projectId,
|
projectId,
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
import { createMongoAbility, MongoAbility, RawRuleOf } from "@casl/ability";
|
import { createMongoAbility, MongoAbility, RawRuleOf } from "@casl/ability";
|
||||||
import { PackRule, unpackRules } from "@casl/ability/extra";
|
import { PackRule, unpackRules } from "@casl/ability/extra";
|
||||||
import { requestContext } from "@fastify/request-context";
|
import { requestContext } from "@fastify/request-context";
|
||||||
import { MongoQuery } from "@ucast/mongo2js";
|
|
||||||
import handlebars from "handlebars";
|
import handlebars from "handlebars";
|
||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AccessScope,
|
||||||
ActionProjectType,
|
ActionProjectType,
|
||||||
OrgMembershipRole,
|
OrgMembershipRole,
|
||||||
ProjectMembershipRole,
|
ProjectMembershipRole,
|
||||||
ServiceTokenScopes,
|
ServiceTokenScopes
|
||||||
TIdentityProjectMemberships,
|
|
||||||
TProjectMemberships
|
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import {
|
import {
|
||||||
cryptographicOperatorPermissions,
|
cryptographicOperatorPermissions,
|
||||||
@@ -25,27 +23,81 @@ import { KeyStorePrefixes, KeyStoreTtls, TKeyStoreFactory } from "@app/keystore/
|
|||||||
import { conditionsMatcher } from "@app/lib/casl";
|
import { conditionsMatcher } from "@app/lib/casl";
|
||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { objectify } from "@app/lib/fn";
|
import { objectify } from "@app/lib/fn";
|
||||||
import { logger } from "@app/lib/logger";
|
|
||||||
import { ActorType } from "@app/services/auth/auth-type";
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "@app/services/identity/identity-dal";
|
||||||
import { TOrgRoleDALFactory } from "@app/services/org/org-role-dal";
|
import { TOrgRoleDALFactory } from "@app/services/org/org-role-dal";
|
||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
import { TProjectRoleDALFactory } from "@app/services/project-role/project-role-dal";
|
import { TProjectRoleDALFactory } from "@app/services/project-role/project-role-dal";
|
||||||
import { TServiceTokenDALFactory } from "@app/services/service-token/service-token-dal";
|
import { TServiceTokenDALFactory } from "@app/services/service-token/service-token-dal";
|
||||||
|
import { TUserDALFactory } from "@app/services/user/user-dal";
|
||||||
|
|
||||||
import { orgAdminPermissions, orgMemberPermissions, orgNoAccessPermissions, OrgPermissionSet } from "./org-permission";
|
import { orgAdminPermissions, orgMemberPermissions, orgNoAccessPermissions, OrgPermissionSet } from "./org-permission";
|
||||||
import { TPermissionDALFactory } from "./permission-dal";
|
import { TPermissionDALFactory } from "./permission-dal";
|
||||||
import { escapeHandlebarsMissingDict, validateOrgSSO } from "./permission-fns";
|
import { escapeHandlebarsMissingDict } from "./permission-fns";
|
||||||
import {
|
import {
|
||||||
TBuildOrgPermissionDTO,
|
TBuildOrgPermissionDTO,
|
||||||
TBuildProjectPermissionDTO,
|
TBuildProjectPermissionDTO,
|
||||||
TGetIdentityProjectPermissionArg,
|
|
||||||
TGetProjectPermissionArg,
|
|
||||||
TGetServiceTokenProjectPermissionArg,
|
TGetServiceTokenProjectPermissionArg,
|
||||||
TGetUserProjectPermissionArg,
|
|
||||||
TPermissionServiceFactory
|
TPermissionServiceFactory
|
||||||
} from "./permission-service-types";
|
} from "./permission-service-types";
|
||||||
import { buildServiceTokenProjectPermission, ProjectPermissionSet } from "./project-permission";
|
import { buildServiceTokenProjectPermission, ProjectPermissionSet } from "./project-permission";
|
||||||
|
|
||||||
|
const buildOrgPermissionRules = (orgUserRoles: TBuildOrgPermissionDTO) => {
|
||||||
|
const rules = orgUserRoles
|
||||||
|
.map(({ role, permissions }) => {
|
||||||
|
switch (role) {
|
||||||
|
case OrgMembershipRole.Admin:
|
||||||
|
return orgAdminPermissions;
|
||||||
|
case OrgMembershipRole.Member:
|
||||||
|
return orgMemberPermissions;
|
||||||
|
case OrgMembershipRole.NoAccess:
|
||||||
|
return orgNoAccessPermissions;
|
||||||
|
case OrgMembershipRole.Custom:
|
||||||
|
return unpackRules<RawRuleOf<MongoAbility<OrgPermissionSet>>>(
|
||||||
|
permissions as PackRule<RawRuleOf<MongoAbility<OrgPermissionSet>>>[]
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw new NotFoundError({ name: "OrgRoleInvalid", message: `Organization role '${role}' not found` });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.reduce((prev, curr) => prev.concat(curr), []);
|
||||||
|
|
||||||
|
return rules;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildProjectPermissionRules = (projectUserRoles: TBuildProjectPermissionDTO) => {
|
||||||
|
const rules = projectUserRoles
|
||||||
|
.map(({ role, permissions }) => {
|
||||||
|
switch (role) {
|
||||||
|
case ProjectMembershipRole.Admin:
|
||||||
|
return projectAdminPermissions;
|
||||||
|
case ProjectMembershipRole.Member:
|
||||||
|
return projectMemberPermissions;
|
||||||
|
case ProjectMembershipRole.Viewer:
|
||||||
|
return projectViewerPermission;
|
||||||
|
case ProjectMembershipRole.NoAccess:
|
||||||
|
return projectNoAccessPermissions;
|
||||||
|
case ProjectMembershipRole.SshHostBootstrapper:
|
||||||
|
return sshHostBootstrapPermissions;
|
||||||
|
case ProjectMembershipRole.KmsCryptographicOperator:
|
||||||
|
return cryptographicOperatorPermissions;
|
||||||
|
case ProjectMembershipRole.Custom: {
|
||||||
|
return unpackRules<RawRuleOf<MongoAbility<ProjectPermissionSet>>>(
|
||||||
|
permissions as PackRule<RawRuleOf<MongoAbility<ProjectPermissionSet>>>[]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new NotFoundError({
|
||||||
|
name: "ProjectRoleInvalid",
|
||||||
|
message: `Project role '${role}' not found`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.reduce((prev, curr) => prev.concat(curr), []);
|
||||||
|
|
||||||
|
return rules;
|
||||||
|
};
|
||||||
|
|
||||||
type TPermissionServiceFactoryDep = {
|
type TPermissionServiceFactoryDep = {
|
||||||
orgRoleDAL: Pick<TOrgRoleDALFactory, "findOne">;
|
orgRoleDAL: Pick<TOrgRoleDALFactory, "findOne">;
|
||||||
projectRoleDAL: Pick<TProjectRoleDALFactory, "findOne">;
|
projectRoleDAL: Pick<TProjectRoleDALFactory, "findOne">;
|
||||||
@@ -53,6 +105,8 @@ type TPermissionServiceFactoryDep = {
|
|||||||
projectDAL: Pick<TProjectDALFactory, "findById">;
|
projectDAL: Pick<TProjectDALFactory, "findById">;
|
||||||
permissionDAL: TPermissionDALFactory;
|
permissionDAL: TPermissionDALFactory;
|
||||||
keyStore: TKeyStoreFactory;
|
keyStore: TKeyStoreFactory;
|
||||||
|
userDAL: Pick<TUserDALFactory, "findById">;
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const permissionServiceFactory = ({
|
export const permissionServiceFactory = ({
|
||||||
@@ -61,33 +115,10 @@ export const permissionServiceFactory = ({
|
|||||||
projectRoleDAL,
|
projectRoleDAL,
|
||||||
serviceTokenDAL,
|
serviceTokenDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
|
userDAL,
|
||||||
|
identityDAL,
|
||||||
keyStore
|
keyStore
|
||||||
}: TPermissionServiceFactoryDep): TPermissionServiceFactory => {
|
}: TPermissionServiceFactoryDep): TPermissionServiceFactory => {
|
||||||
const buildOrgPermission = (orgUserRoles: TBuildOrgPermissionDTO) => {
|
|
||||||
const rules = orgUserRoles
|
|
||||||
.map(({ role, permissions }) => {
|
|
||||||
switch (role) {
|
|
||||||
case OrgMembershipRole.Admin:
|
|
||||||
return orgAdminPermissions;
|
|
||||||
case OrgMembershipRole.Member:
|
|
||||||
return orgMemberPermissions;
|
|
||||||
case OrgMembershipRole.NoAccess:
|
|
||||||
return orgNoAccessPermissions;
|
|
||||||
case OrgMembershipRole.Custom:
|
|
||||||
return unpackRules<RawRuleOf<MongoAbility<OrgPermissionSet>>>(
|
|
||||||
permissions as PackRule<RawRuleOf<MongoAbility<OrgPermissionSet>>>[]
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
throw new NotFoundError({ name: "OrgRoleInvalid", message: `Organization role '${role}' not found` });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.reduce((prev, curr) => prev.concat(curr), []);
|
|
||||||
|
|
||||||
return createMongoAbility<OrgPermissionSet>(rules, {
|
|
||||||
conditionsMatcher
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const invalidateProjectPermissionCache = async (projectId: string, tx?: Knex) => {
|
const invalidateProjectPermissionCache = async (projectId: string, tx?: Knex) => {
|
||||||
const projectPermissionDalVersionKey = KeyStorePrefixes.ProjectPermissionDalVersion(projectId);
|
const projectPermissionDalVersionKey = KeyStorePrefixes.ProjectPermissionDalVersion(projectId);
|
||||||
await keyStore.pgIncrementBy(projectPermissionDalVersionKey, {
|
await keyStore.pgIncrementBy(projectPermissionDalVersionKey, {
|
||||||
@@ -97,147 +128,59 @@ export const permissionServiceFactory = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const calculateProjectPermissionTtl = (membership: unknown): number => {
|
// akhilmdhh: will bring this up later
|
||||||
const now = new Date();
|
// const calculateProjectPermissionTtl = (membership: unknown): number => {
|
||||||
let minTtl = KeyStoreTtls.ProjectPermissionCacheInSeconds;
|
// const now = new Date();
|
||||||
|
// let minTtl = KeyStoreTtls.ProjectPermissionCacheInSeconds;
|
||||||
const getMinEndTime = (items: Array<{ temporaryAccessEndTime?: Date | null; isTemporary?: boolean }>) => {
|
//
|
||||||
return items
|
// const getMinEndTime = (items: Array<{ temporaryAccessEndTime?: Date | null; isTemporary?: boolean }>) => {
|
||||||
.filter((item) => item.isTemporary && item.temporaryAccessEndTime)
|
// return items
|
||||||
.map((item) => item.temporaryAccessEndTime!)
|
// .filter((item) => item.isTemporary && item.temporaryAccessEndTime)
|
||||||
.filter((endTime) => endTime > now)
|
// .map((item) => item.temporaryAccessEndTime!)
|
||||||
.reduce((min, endTime) => (!min || endTime < min ? endTime : min), null as Date | null);
|
// .filter((endTime) => endTime > now)
|
||||||
};
|
// .reduce((min, endTime) => (!min || endTime < min ? endTime : min), null as Date | null);
|
||||||
|
// };
|
||||||
const roleTimes: Date[] = [];
|
//
|
||||||
const additionalPrivilegeTimes: Date[] = [];
|
// const roleTimes: Date[] = [];
|
||||||
|
// const additionalPrivilegeTimes: Date[] = [];
|
||||||
if (
|
//
|
||||||
membership &&
|
// if (
|
||||||
typeof membership === "object" &&
|
// membership &&
|
||||||
"roles" in membership &&
|
// typeof membership === "object" &&
|
||||||
Array.isArray((membership as Record<string, unknown>).roles)
|
// "roles" in membership &&
|
||||||
) {
|
// Array.isArray((membership as Record<string, unknown>).roles)
|
||||||
const roles = (membership as Record<string, unknown>).roles as Array<{
|
// ) {
|
||||||
temporaryAccessEndTime?: Date | null;
|
// const roles = (membership as Record<string, unknown>).roles as Array<{
|
||||||
isTemporary?: boolean;
|
// temporaryAccessEndTime?: Date | null;
|
||||||
}>;
|
// isTemporary?: boolean;
|
||||||
const minRoleEndTime = getMinEndTime(roles);
|
// }>;
|
||||||
if (minRoleEndTime) roleTimes.push(minRoleEndTime);
|
// const minRoleEndTime = getMinEndTime(roles);
|
||||||
}
|
// if (minRoleEndTime) roleTimes.push(minRoleEndTime);
|
||||||
|
// }
|
||||||
if (
|
//
|
||||||
membership &&
|
// if (
|
||||||
typeof membership === "object" &&
|
// membership &&
|
||||||
"additionalPrivileges" in membership &&
|
// typeof membership === "object" &&
|
||||||
Array.isArray((membership as Record<string, unknown>).additionalPrivileges)
|
// "additionalPrivileges" in membership &&
|
||||||
) {
|
// Array.isArray((membership as Record<string, unknown>).additionalPrivileges)
|
||||||
const additionalPrivileges = (membership as Record<string, unknown>).additionalPrivileges as Array<{
|
// ) {
|
||||||
temporaryAccessEndTime?: Date | null;
|
// const additionalPrivileges = (membership as Record<string, unknown>).additionalPrivileges as Array<{
|
||||||
isTemporary?: boolean;
|
// temporaryAccessEndTime?: Date | null;
|
||||||
}>;
|
// isTemporary?: boolean;
|
||||||
const minAdditionalEndTime = getMinEndTime(additionalPrivileges);
|
// }>;
|
||||||
if (minAdditionalEndTime) additionalPrivilegeTimes.push(minAdditionalEndTime);
|
// const minAdditionalEndTime = getMinEndTime(additionalPrivileges);
|
||||||
}
|
// if (minAdditionalEndTime) additionalPrivilegeTimes.push(minAdditionalEndTime);
|
||||||
|
// }
|
||||||
const allEndTimes = [...roleTimes, ...additionalPrivilegeTimes];
|
//
|
||||||
if (allEndTimes.length > 0) {
|
// const allEndTimes = [...roleTimes, ...additionalPrivilegeTimes];
|
||||||
const nearestEndTime = allEndTimes.reduce((min, endTime) => (!min || endTime < min ? endTime : min));
|
// if (allEndTimes.length > 0) {
|
||||||
const timeUntilExpiry = Math.floor((nearestEndTime.getTime() - now.getTime()) / 1000);
|
// const nearestEndTime = allEndTimes.reduce((min, endTime) => (!min || endTime < min ? endTime : min));
|
||||||
minTtl = Math.min(minTtl, Math.max(1, timeUntilExpiry));
|
// const timeUntilExpiry = Math.floor((nearestEndTime.getTime() - now.getTime()) / 1000);
|
||||||
}
|
// minTtl = Math.min(minTtl, Math.max(1, timeUntilExpiry));
|
||||||
|
// }
|
||||||
return minTtl;
|
//
|
||||||
};
|
// return minTtl;
|
||||||
|
// };
|
||||||
const buildProjectPermissionRules = (projectUserRoles: TBuildProjectPermissionDTO) => {
|
|
||||||
const rules = projectUserRoles
|
|
||||||
.map(({ role, permissions }) => {
|
|
||||||
switch (role) {
|
|
||||||
case ProjectMembershipRole.Admin:
|
|
||||||
return projectAdminPermissions;
|
|
||||||
case ProjectMembershipRole.Member:
|
|
||||||
return projectMemberPermissions;
|
|
||||||
case ProjectMembershipRole.Viewer:
|
|
||||||
return projectViewerPermission;
|
|
||||||
case ProjectMembershipRole.NoAccess:
|
|
||||||
return projectNoAccessPermissions;
|
|
||||||
case ProjectMembershipRole.SshHostBootstrapper:
|
|
||||||
return sshHostBootstrapPermissions;
|
|
||||||
case ProjectMembershipRole.KmsCryptographicOperator:
|
|
||||||
return cryptographicOperatorPermissions;
|
|
||||||
case ProjectMembershipRole.Custom: {
|
|
||||||
return unpackRules<RawRuleOf<MongoAbility<ProjectPermissionSet>>>(
|
|
||||||
permissions as PackRule<RawRuleOf<MongoAbility<ProjectPermissionSet>>>[]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new NotFoundError({
|
|
||||||
name: "ProjectRoleInvalid",
|
|
||||||
message: `Project role '${role}' not found`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.reduce((prev, curr) => prev.concat(curr), []);
|
|
||||||
|
|
||||||
return rules;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get user permission in an organization
|
|
||||||
*/
|
|
||||||
const getUserOrgPermission: TPermissionServiceFactory["getUserOrgPermission"] = async (
|
|
||||||
userId,
|
|
||||||
orgId,
|
|
||||||
authMethod,
|
|
||||||
userOrgId
|
|
||||||
) => {
|
|
||||||
// when token is scoped, ensure the passed org id is same as user org id
|
|
||||||
if (userOrgId && userOrgId !== orgId)
|
|
||||||
throw new ForbiddenRequestError({ message: "Invalid user token. Scoped to different organization." });
|
|
||||||
const membership = await permissionDAL.getOrgPermission(userId, orgId);
|
|
||||||
if (!membership) throw new ForbiddenRequestError({ name: "You are not apart of this organization" });
|
|
||||||
if (membership.role === OrgMembershipRole.Custom && !membership.permissions) {
|
|
||||||
throw new BadRequestError({ name: "Custom organization permission not found" });
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the org ID is API_KEY, the request is being made with an API Key.
|
|
||||||
// Since we can't scope API keys to an organization, we'll need to do an arbitrary check to see if the user is a member of the organization.
|
|
||||||
|
|
||||||
// Extra: This means that when users are using API keys to make requests, they can't use slug-based routes.
|
|
||||||
// Slug-based routes depend on the organization ID being present on the request, since project slugs aren't globally unique, and we need a way to filter by organization.
|
|
||||||
if (userOrgId !== "API_KEY" && membership.orgId !== userOrgId) {
|
|
||||||
throw new ForbiddenRequestError({ name: "You are not logged into this organization" });
|
|
||||||
}
|
|
||||||
|
|
||||||
validateOrgSSO(
|
|
||||||
authMethod,
|
|
||||||
membership.orgAuthEnforced,
|
|
||||||
membership.orgGoogleSsoAuthEnforced,
|
|
||||||
membership.bypassOrgAuthEnabled,
|
|
||||||
membership.role as OrgMembershipRole
|
|
||||||
);
|
|
||||||
|
|
||||||
const finalPolicyRoles = [{ role: membership.role, permissions: membership.permissions }].concat(
|
|
||||||
membership?.groups?.map(({ role, customRolePermission }) => ({
|
|
||||||
role,
|
|
||||||
permissions: customRolePermission
|
|
||||||
})) || []
|
|
||||||
);
|
|
||||||
return { permission: buildOrgPermission(finalPolicyRoles), membership };
|
|
||||||
};
|
|
||||||
|
|
||||||
const getIdentityOrgPermission = async (identityId: string, orgId: string) => {
|
|
||||||
const membership = await permissionDAL.getOrgIdentityPermission(identityId, orgId);
|
|
||||||
if (!membership) throw new ForbiddenRequestError({ name: "Identity is not apart of this organization" });
|
|
||||||
if (membership.role === OrgMembershipRole.Custom && !membership.permissions) {
|
|
||||||
throw new NotFoundError({ name: `Custom organization permission not found for identity ${identityId}` });
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
permission: buildOrgPermission([{ role: membership.role, permissions: membership.permissions }]),
|
|
||||||
membership
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const getOrgPermission: TPermissionServiceFactory["getOrgPermission"] = async (
|
const getOrgPermission: TPermissionServiceFactory["getOrgPermission"] = async (
|
||||||
type,
|
type,
|
||||||
@@ -246,17 +189,60 @@ export const permissionServiceFactory = ({
|
|||||||
authMethod,
|
authMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
) => {
|
) => {
|
||||||
switch (type) {
|
if (type !== ActorType.USER && type !== ActorType.IDENTITY) {
|
||||||
case ActorType.USER:
|
throw new BadRequestError({
|
||||||
return getUserOrgPermission(id, orgId, authMethod, actorOrgId);
|
message: "Invalid actor provided",
|
||||||
case ActorType.IDENTITY:
|
name: "Get org permission"
|
||||||
return getIdentityOrgPermission(id, orgId);
|
});
|
||||||
default:
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: "Invalid actor provided",
|
|
||||||
name: "Get org permission"
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (orgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ name: "You are not logged into this organization" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const permissionData = await permissionDAL.getPermission({
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Organization,
|
||||||
|
orgId
|
||||||
|
},
|
||||||
|
actorId: id,
|
||||||
|
actorType: type
|
||||||
|
});
|
||||||
|
if (!permissionData?.length) throw new ForbiddenRequestError({ name: "You are not member of this organization" });
|
||||||
|
|
||||||
|
const permissionFromRoles = permissionData.flatMap((membership) => {
|
||||||
|
const activeRoles = membership?.roles
|
||||||
|
.filter(
|
||||||
|
({ isTemporary, temporaryAccessEndTime }) =>
|
||||||
|
!isTemporary || (isTemporary && temporaryAccessEndTime && new Date() < temporaryAccessEndTime)
|
||||||
|
)
|
||||||
|
.map(({ role, permissions }) => ({ role, permissions }));
|
||||||
|
const activeAdditionalPrivileges = membership?.additionalPrivileges
|
||||||
|
.filter(
|
||||||
|
({ isTemporary, temporaryAccessEndTime }) =>
|
||||||
|
!isTemporary || (isTemporary && temporaryAccessEndTime && new Date() < temporaryAccessEndTime)
|
||||||
|
)
|
||||||
|
.map(({ permissions }) => ({ role: OrgMembershipRole.Custom, permissions }));
|
||||||
|
return activeRoles.concat(activeAdditionalPrivileges);
|
||||||
|
});
|
||||||
|
|
||||||
|
const permission = createMongoAbility<OrgPermissionSet>(buildOrgPermissionRules(permissionFromRoles), {
|
||||||
|
conditionsMatcher
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO(simp): validate this
|
||||||
|
// validateOrgSSO(
|
||||||
|
// authMethod,
|
||||||
|
// membership.orgAuthEnforced,
|
||||||
|
// membership.orgGoogleSsoAuthEnforced,
|
||||||
|
// membership.bypassOrgAuthEnabled,
|
||||||
|
// membership.role as OrgMembershipRole
|
||||||
|
// );
|
||||||
|
|
||||||
|
return {
|
||||||
|
permission,
|
||||||
|
memberships: permissionData
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// instead of actor type this will fetch by role slug. meaning it can be the pre defined slugs like
|
// instead of actor type this will fetch by role slug. meaning it can be the pre defined slugs like
|
||||||
@@ -270,175 +256,19 @@ export const permissionServiceFactory = ({
|
|||||||
message: `Specified role '${role}' was not found in the organization with ID '${orgId}'`
|
message: `Specified role '${role}' was not found in the organization with ID '${orgId}'`
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
permission: buildOrgPermission([{ role: OrgMembershipRole.Custom, permissions: orgRole.permissions }]),
|
permission: createMongoAbility<OrgPermissionSet>(
|
||||||
|
buildOrgPermissionRules([{ role: OrgMembershipRole.Custom, permissions: orgRole.permissions }]),
|
||||||
|
{
|
||||||
|
conditionsMatcher
|
||||||
|
}
|
||||||
|
),
|
||||||
role: orgRole
|
role: orgRole
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return { permission: buildOrgPermission([{ role, permissions: [] }]) };
|
|
||||||
};
|
|
||||||
|
|
||||||
// user permission for a project in an organization
|
|
||||||
const getUserProjectPermission = async ({
|
|
||||||
userId,
|
|
||||||
projectId,
|
|
||||||
authMethod,
|
|
||||||
userOrgId,
|
|
||||||
actionProjectType
|
|
||||||
}: TGetUserProjectPermissionArg): Promise<TProjectPermissionRT<ActorType.USER>> => {
|
|
||||||
const userProjectPermission = await permissionDAL.getProjectPermission(userId, projectId);
|
|
||||||
if (!userProjectPermission) throw new ForbiddenRequestError({ name: "User not a part of the specified project" });
|
|
||||||
|
|
||||||
if (
|
|
||||||
userProjectPermission.roles.some(({ role, permissions }) => role === ProjectMembershipRole.Custom && !permissions)
|
|
||||||
) {
|
|
||||||
throw new NotFoundError({ name: "The permission was not found" });
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the org ID is API_KEY, the request is being made with an API Key.
|
|
||||||
// Since we can't scope API keys to an organization, we'll need to do an arbitrary check to see if the user is a member of the organization.
|
|
||||||
|
|
||||||
// Extra: This means that when users are using API keys to make requests, they can't use slug-based routes.
|
|
||||||
// Slug-based routes depend on the organization ID being present on the request, since project slugs aren't globally unique, and we need a way to filter by organization.
|
|
||||||
if (userOrgId !== "API_KEY" && userProjectPermission.orgId !== userOrgId) {
|
|
||||||
throw new ForbiddenRequestError({ name: "You are not logged into this organization" });
|
|
||||||
}
|
|
||||||
|
|
||||||
validateOrgSSO(
|
|
||||||
authMethod,
|
|
||||||
userProjectPermission.orgAuthEnforced,
|
|
||||||
userProjectPermission.orgGoogleSsoAuthEnforced,
|
|
||||||
userProjectPermission.bypassOrgAuthEnabled,
|
|
||||||
userProjectPermission.orgRole
|
|
||||||
);
|
|
||||||
|
|
||||||
if (actionProjectType !== ActionProjectType.Any && actionProjectType !== userProjectPermission.projectType) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `The project is of type ${userProjectPermission.projectType}. Operations of type ${actionProjectType} are not allowed.`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// join two permissions and pass to build the final permission set
|
|
||||||
const rolePermissions = userProjectPermission.roles?.map(({ role, permissions }) => ({ role, permissions })) || [];
|
|
||||||
const additionalPrivileges =
|
|
||||||
userProjectPermission.additionalPrivileges?.map(({ permissions }) => ({
|
|
||||||
role: ProjectMembershipRole.Custom,
|
|
||||||
permissions
|
|
||||||
})) || [];
|
|
||||||
|
|
||||||
const rules = buildProjectPermissionRules(rolePermissions.concat(additionalPrivileges));
|
|
||||||
const templatedRules = handlebars.compile(JSON.stringify(rules), { data: false });
|
|
||||||
const unescapedMetadata = objectify(
|
|
||||||
userProjectPermission.metadata,
|
|
||||||
(i) => i.key,
|
|
||||||
(i) => i.value
|
|
||||||
);
|
|
||||||
const metadataKeyValuePair = escapeHandlebarsMissingDict(unescapedMetadata, "identity.metadata");
|
|
||||||
requestContext.set("identityPermissionMetadata", { metadata: unescapedMetadata });
|
|
||||||
const interpolateRules = templatedRules(
|
|
||||||
{
|
|
||||||
identity: {
|
|
||||||
id: userProjectPermission.userId,
|
|
||||||
username: userProjectPermission.username,
|
|
||||||
metadata: metadataKeyValuePair
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ data: false }
|
|
||||||
);
|
|
||||||
const permission = createMongoAbility<ProjectPermissionSet>(
|
|
||||||
JSON.parse(interpolateRules) as RawRuleOf<MongoAbility<ProjectPermissionSet>>[],
|
|
||||||
{
|
|
||||||
conditionsMatcher
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
permission,
|
permission: createMongoAbility<OrgPermissionSet>(buildOrgPermissionRules([{ role, permissions: [] }]), {
|
||||||
membership: userProjectPermission,
|
|
||||||
hasRole: (role: string) =>
|
|
||||||
userProjectPermission.roles.findIndex(
|
|
||||||
({ role: slug, customRoleSlug }) => role === slug || slug === customRoleSlug
|
|
||||||
) !== -1
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const getIdentityProjectPermission = async ({
|
|
||||||
identityId,
|
|
||||||
projectId,
|
|
||||||
identityOrgId,
|
|
||||||
actionProjectType
|
|
||||||
}: TGetIdentityProjectPermissionArg): Promise<TProjectPermissionRT<ActorType.IDENTITY>> => {
|
|
||||||
const identityProjectPermission = await permissionDAL.getProjectIdentityPermission(identityId, projectId);
|
|
||||||
if (!identityProjectPermission)
|
|
||||||
throw new ForbiddenRequestError({
|
|
||||||
name: `Identity is not a member of the specified project with ID '${projectId}'`
|
|
||||||
});
|
|
||||||
|
|
||||||
if (
|
|
||||||
identityProjectPermission.roles.some(
|
|
||||||
({ role, permissions }) => role === ProjectMembershipRole.Custom && !permissions
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
throw new NotFoundError({ name: "Custom permission not found" });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (identityProjectPermission.orgId !== identityOrgId) {
|
|
||||||
throw new ForbiddenRequestError({ name: "Identity is not a member of the specified organization" });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actionProjectType !== ActionProjectType.Any && actionProjectType !== identityProjectPermission.projectType) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `The project is of type ${identityProjectPermission.projectType}. Operations of type ${actionProjectType} are not allowed.`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const rolePermissions =
|
|
||||||
identityProjectPermission.roles?.map(({ role, permissions }) => ({ role, permissions })) || [];
|
|
||||||
const additionalPrivileges =
|
|
||||||
identityProjectPermission.additionalPrivileges?.map(({ permissions }) => ({
|
|
||||||
role: ProjectMembershipRole.Custom,
|
|
||||||
permissions
|
|
||||||
})) || [];
|
|
||||||
|
|
||||||
const rules = buildProjectPermissionRules(rolePermissions.concat(additionalPrivileges));
|
|
||||||
const templatedRules = handlebars.compile(JSON.stringify(rules), { data: false });
|
|
||||||
const unescapedIdentityAuthInfo = requestContext.get("identityAuthInfo");
|
|
||||||
const unescapedMetadata = objectify(
|
|
||||||
identityProjectPermission.metadata,
|
|
||||||
(i) => i.key,
|
|
||||||
(i) => i.value
|
|
||||||
);
|
|
||||||
const identityAuthInfo =
|
|
||||||
unescapedIdentityAuthInfo?.identityId === identityId && unescapedIdentityAuthInfo
|
|
||||||
? escapeHandlebarsMissingDict(unescapedIdentityAuthInfo as never, "identity.auth")
|
|
||||||
: {};
|
|
||||||
const metadataKeyValuePair = escapeHandlebarsMissingDict(unescapedMetadata, "identity.metadata");
|
|
||||||
|
|
||||||
requestContext.set("identityPermissionMetadata", { metadata: unescapedMetadata, auth: unescapedIdentityAuthInfo });
|
|
||||||
const interpolateRules = templatedRules(
|
|
||||||
{
|
|
||||||
identity: {
|
|
||||||
id: identityProjectPermission.identityId,
|
|
||||||
username: identityProjectPermission.username,
|
|
||||||
metadata: metadataKeyValuePair,
|
|
||||||
auth: identityAuthInfo
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ data: false }
|
|
||||||
);
|
|
||||||
const permission = createMongoAbility<ProjectPermissionSet>(
|
|
||||||
JSON.parse(interpolateRules) as RawRuleOf<MongoAbility<ProjectPermissionSet>>[],
|
|
||||||
{
|
|
||||||
conditionsMatcher
|
conditionsMatcher
|
||||||
}
|
})
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
permission,
|
|
||||||
membership: identityProjectPermission,
|
|
||||||
hasRole: (role: string) =>
|
|
||||||
identityProjectPermission.roles.findIndex(
|
|
||||||
({ role: slug, customRoleSlug }) => role === slug || slug === customRoleSlug
|
|
||||||
) !== -1
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -480,30 +310,149 @@ export const permissionServiceFactory = ({
|
|||||||
const scopes = ServiceTokenScopes.parse(serviceToken.scopes || []);
|
const scopes = ServiceTokenScopes.parse(serviceToken.scopes || []);
|
||||||
return {
|
return {
|
||||||
permission: buildServiceTokenProjectPermission(scopes, serviceToken.permissions),
|
permission: buildServiceTokenProjectPermission(scopes, serviceToken.permissions),
|
||||||
membership: {
|
memberships: [],
|
||||||
shouldUseNewPrivilegeSystem: true
|
hasRole: () => false
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type TProjectPermissionRT<T extends ActorType> = T extends ActorType.SERVICE
|
const getProjectPermission: TPermissionServiceFactory["getProjectPermission"] = async ({
|
||||||
? {
|
actor: inputActor,
|
||||||
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
actorId: inputActorId,
|
||||||
membership: {
|
projectId,
|
||||||
shouldUseNewPrivilegeSystem: boolean;
|
actorAuthMethod,
|
||||||
};
|
actorOrgId,
|
||||||
hasRole: (arg: string) => boolean;
|
actionProjectType
|
||||||
} // service token doesn't have both membership and roles
|
}) => {
|
||||||
: {
|
let actor = inputActor;
|
||||||
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
let actorId = inputActorId;
|
||||||
membership: (T extends ActorType.USER ? TProjectMemberships : TIdentityProjectMemberships) & {
|
|
||||||
orgAuthEnforced: boolean | null | undefined;
|
if (actor === ActorType.SERVICE) {
|
||||||
orgId: string;
|
return getServiceTokenProjectPermission({
|
||||||
roles: Array<{ role: string }>;
|
serviceTokenId: actorId,
|
||||||
shouldUseNewPrivilegeSystem: boolean;
|
projectId,
|
||||||
};
|
actorOrgId,
|
||||||
hasRole: (role: string) => boolean;
|
actionProjectType
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const assumedPrivilegeDetailsCtx = requestContext.get("assumedPrivilegeDetails");
|
||||||
|
if (
|
||||||
|
assumedPrivilegeDetailsCtx &&
|
||||||
|
actor === ActorType.USER &&
|
||||||
|
actorId === assumedPrivilegeDetailsCtx.requesterId &&
|
||||||
|
projectId === assumedPrivilegeDetailsCtx.projectId
|
||||||
|
) {
|
||||||
|
actor = assumedPrivilegeDetailsCtx.actorType;
|
||||||
|
actorId = assumedPrivilegeDetailsCtx.actorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ActorType.USER !== actor && ActorType.IDENTITY !== actor) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Invalid actor provided",
|
||||||
|
name: "Get org permission"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const projectDetails = await projectDAL.findById(projectId);
|
||||||
|
if (!projectDetails) {
|
||||||
|
throw new NotFoundError({ message: `Project with ${projectId} not found` });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectDetails.orgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ name: "You are not logged into this organization" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionProjectType !== ActionProjectType.Any && actionProjectType !== projectDetails.type) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `The project is of type ${projectDetails.type}. Operations of type ${actionProjectType} are not allowed.`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const permissionData = await permissionDAL.getPermission({
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
orgId: projectDetails.orgId,
|
||||||
|
projectId
|
||||||
|
},
|
||||||
|
actorId,
|
||||||
|
actorType: actor
|
||||||
|
});
|
||||||
|
if (!permissionData?.length) throw new ForbiddenRequestError({ name: "You are not member of this organization" });
|
||||||
|
const permissionFromRoles = permissionData.flatMap((membership) => {
|
||||||
|
const activeRoles = membership?.roles
|
||||||
|
.filter(
|
||||||
|
({ isTemporary, temporaryAccessEndTime }) =>
|
||||||
|
!isTemporary || (isTemporary && temporaryAccessEndTime && new Date() < temporaryAccessEndTime)
|
||||||
|
)
|
||||||
|
.map(({ role, permissions }) => ({ role, permissions }));
|
||||||
|
const activeAdditionalPrivileges = membership?.additionalPrivileges
|
||||||
|
.filter(
|
||||||
|
({ isTemporary, temporaryAccessEndTime }) =>
|
||||||
|
!isTemporary || (isTemporary && temporaryAccessEndTime && new Date() < temporaryAccessEndTime)
|
||||||
|
)
|
||||||
|
.map(({ permissions }) => ({ role: ProjectMembershipRole.Custom, permissions }));
|
||||||
|
return activeRoles.concat(activeAdditionalPrivileges);
|
||||||
|
});
|
||||||
|
|
||||||
|
// validateOrgSSO(
|
||||||
|
// authMethod,
|
||||||
|
// userProjectPermission.orgAuthEnforced,
|
||||||
|
// userProjectPermission.orgGoogleSsoAuthEnforced,
|
||||||
|
// userProjectPermission.bypassOrgAuthEnabled,
|
||||||
|
// userProjectPermission.orgRole
|
||||||
|
// );
|
||||||
|
|
||||||
|
const rules = buildProjectPermissionRules(permissionFromRoles);
|
||||||
|
const templatedRules = handlebars.compile(JSON.stringify(rules), { data: false });
|
||||||
|
const unescapedMetadata = objectify(
|
||||||
|
permissionData?.[0]?.metadata,
|
||||||
|
(i) => i.key,
|
||||||
|
(i) => i.value
|
||||||
|
);
|
||||||
|
const metadataKeyValuePair = escapeHandlebarsMissingDict(unescapedMetadata, "identity.metadata");
|
||||||
|
requestContext.set("identityPermissionMetadata", { metadata: unescapedMetadata });
|
||||||
|
|
||||||
|
let username = "";
|
||||||
|
if (actor === ActorType.USER) {
|
||||||
|
const userDetails = await userDAL.findById(actorId);
|
||||||
|
username = userDetails?.username;
|
||||||
|
} else {
|
||||||
|
const identityDetails = await identityDAL.findById(actorId);
|
||||||
|
username = identityDetails?.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unescapedIdentityAuthInfo = requestContext.get("identityAuthInfo");
|
||||||
|
const identityAuthInfo =
|
||||||
|
unescapedIdentityAuthInfo?.identityId === actorId && unescapedIdentityAuthInfo
|
||||||
|
? escapeHandlebarsMissingDict(unescapedIdentityAuthInfo as never, "identity.auth")
|
||||||
|
: {};
|
||||||
|
|
||||||
|
const interpolateRules = templatedRules(
|
||||||
|
{
|
||||||
|
identity: {
|
||||||
|
id: actorId,
|
||||||
|
username,
|
||||||
|
metadata: metadataKeyValuePair,
|
||||||
|
auth: identityAuthInfo
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ data: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
const permission = createMongoAbility<ProjectPermissionSet>(
|
||||||
|
JSON.parse(interpolateRules) as RawRuleOf<MongoAbility<ProjectPermissionSet>>[],
|
||||||
|
{
|
||||||
|
conditionsMatcher
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
permission,
|
||||||
|
memberships: permissionData,
|
||||||
|
hasRole: (role: string) =>
|
||||||
|
permissionData.some((memberships) => memberships.roles.some((el) => role === (el.customRoleSlug || el.role)))
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const getProjectPermissions: TPermissionServiceFactory["getProjectPermissions"] = async (projectId) => {
|
const getProjectPermissions: TPermissionServiceFactory["getProjectPermissions"] = async (projectId) => {
|
||||||
// fetch user permissions
|
// fetch user permissions
|
||||||
@@ -623,117 +572,6 @@ export const permissionServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectPermission = async <T extends ActorType>({
|
|
||||||
actor: inputActor,
|
|
||||||
actorId: inputActorId,
|
|
||||||
projectId,
|
|
||||||
actorAuthMethod,
|
|
||||||
actorOrgId,
|
|
||||||
actionProjectType
|
|
||||||
}: TGetProjectPermissionArg): Promise<TProjectPermissionRT<T>> => {
|
|
||||||
let actor = inputActor;
|
|
||||||
let actorId = inputActorId;
|
|
||||||
const assumedPrivilegeDetailsCtx = requestContext.get("assumedPrivilegeDetails");
|
|
||||||
if (
|
|
||||||
assumedPrivilegeDetailsCtx &&
|
|
||||||
actor === ActorType.USER &&
|
|
||||||
actorId === assumedPrivilegeDetailsCtx.requesterId &&
|
|
||||||
projectId === assumedPrivilegeDetailsCtx.projectId
|
|
||||||
) {
|
|
||||||
actor = assumedPrivilegeDetailsCtx.actorType;
|
|
||||||
actorId = assumedPrivilegeDetailsCtx.actorId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actor === ActorType.SERVICE) {
|
|
||||||
return getServiceTokenProjectPermission({
|
|
||||||
serviceTokenId: actorId,
|
|
||||||
projectId,
|
|
||||||
actorOrgId,
|
|
||||||
actionProjectType
|
|
||||||
}) as Promise<TProjectPermissionRT<T>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cachedProjectPermissionVersion = await keyStore.pgGetIntItem(
|
|
||||||
KeyStorePrefixes.ProjectPermissionDalVersion(projectId)
|
|
||||||
);
|
|
||||||
const projectPermissionVersion = Number(cachedProjectPermissionVersion || 0);
|
|
||||||
const cacheKey = KeyStorePrefixes.ProjectPermission(
|
|
||||||
projectId,
|
|
||||||
projectPermissionVersion,
|
|
||||||
actor,
|
|
||||||
actorId,
|
|
||||||
actionProjectType || ActionProjectType.Any
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const cachedData = await keyStore.getItem(cacheKey);
|
|
||||||
if (cachedData) {
|
|
||||||
const parsed = JSON.parse(cachedData) as {
|
|
||||||
rules: RawRuleOf<MongoAbility<ProjectPermissionSet>>[];
|
|
||||||
membership: {
|
|
||||||
roles?: Array<{ role: string; customRoleSlug?: string }>;
|
|
||||||
[key: string]: unknown;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
const permission = createMongoAbility<ProjectPermissionSet>(parsed.rules, {
|
|
||||||
conditionsMatcher
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
permission,
|
|
||||||
membership: parsed.membership,
|
|
||||||
hasRole: (role: string) =>
|
|
||||||
parsed.membership.roles?.findIndex(
|
|
||||||
({ role: slug, customRoleSlug }) => role === slug || slug === customRoleSlug
|
|
||||||
) !== -1
|
|
||||||
} as TProjectPermissionRT<T>;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(error, "Failed to get project permission");
|
|
||||||
}
|
|
||||||
|
|
||||||
let result: TProjectPermissionRT<T>;
|
|
||||||
|
|
||||||
switch (actor) {
|
|
||||||
case ActorType.USER:
|
|
||||||
result = (await getUserProjectPermission({
|
|
||||||
userId: actorId,
|
|
||||||
projectId,
|
|
||||||
authMethod: actorAuthMethod,
|
|
||||||
userOrgId: actorOrgId,
|
|
||||||
actionProjectType
|
|
||||||
})) as TProjectPermissionRT<T>;
|
|
||||||
break;
|
|
||||||
case ActorType.IDENTITY:
|
|
||||||
result = (await getIdentityProjectPermission({
|
|
||||||
identityId: actorId,
|
|
||||||
projectId,
|
|
||||||
identityOrgId: actorOrgId,
|
|
||||||
actionProjectType
|
|
||||||
})) as TProjectPermissionRT<T>;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: "Invalid actor provided",
|
|
||||||
name: "Get project permission"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const cacheData = {
|
|
||||||
rules: result.permission.rules,
|
|
||||||
membership: result.membership
|
|
||||||
};
|
|
||||||
|
|
||||||
const ttl = calculateProjectPermissionTtl(result.membership);
|
|
||||||
await keyStore.setItemWithExpiry(cacheKey, ttl, JSON.stringify(cacheData));
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(error, "Failed to cache project permission");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getProjectPermissionByRole: TPermissionServiceFactory["getProjectPermissionByRole"] = async (
|
const getProjectPermissionByRole: TPermissionServiceFactory["getProjectPermissionByRole"] = async (
|
||||||
role,
|
role,
|
||||||
projectId
|
projectId
|
||||||
@@ -785,15 +623,11 @@ export const permissionServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getUserOrgPermission,
|
|
||||||
getOrgPermission,
|
getOrgPermission,
|
||||||
getUserProjectPermission,
|
|
||||||
getProjectPermission,
|
getProjectPermission,
|
||||||
getProjectPermissions,
|
getProjectPermissions,
|
||||||
getOrgPermissionByRole,
|
getOrgPermissionByRole,
|
||||||
getProjectPermissionByRole,
|
getProjectPermissionByRole,
|
||||||
buildOrgPermission,
|
|
||||||
buildProjectPermissionRules,
|
|
||||||
checkGroupProjectPermission,
|
checkGroupProjectPermission,
|
||||||
invalidateProjectPermissionCache
|
invalidateProjectPermissionCache
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user