mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-16 03:31:27 +00:00
feat(rbac): implemented backend base apis for rbac permission system
This commit is contained in:
@@ -11,29 +11,29 @@ import { BadRequestError, MembershipNotFoundError } from "../utils/errors";
|
||||
* @returns {Membership} membership - membership of user with id [userId] for workspace with id [workspaceId]
|
||||
*/
|
||||
export const validateMembership = async ({
|
||||
userId,
|
||||
workspaceId,
|
||||
acceptedRoles,
|
||||
userId,
|
||||
workspaceId,
|
||||
acceptedRoles
|
||||
}: {
|
||||
userId: Types.ObjectId | string;
|
||||
workspaceId: Types.ObjectId | string;
|
||||
acceptedRoles?: Array<"admin" | "member">;
|
||||
acceptedRoles?: Array<"admin" | "member" | "custom">;
|
||||
}) => {
|
||||
const membership = await Membership.findOne({
|
||||
user: userId,
|
||||
workspace: workspaceId,
|
||||
workspace: workspaceId
|
||||
}).populate("workspace");
|
||||
|
||||
if (!membership) {
|
||||
throw MembershipNotFoundError({
|
||||
message: "Failed to find workspace membership",
|
||||
message: "Failed to find workspace membership"
|
||||
});
|
||||
}
|
||||
|
||||
if (acceptedRoles) {
|
||||
if (!acceptedRoles.includes(membership.role)) {
|
||||
throw BadRequestError({
|
||||
message: "Failed authorization for membership role",
|
||||
message: "Failed authorization for membership role"
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ export const validateMembership = async ({
|
||||
* @return {Object} membership - membership
|
||||
*/
|
||||
export const findMembership = async (queryObj: any) => {
|
||||
const membership = await Membership.findOne(queryObj);
|
||||
const membership = await Membership.findOne(queryObj);
|
||||
return membership;
|
||||
};
|
||||
|
||||
@@ -60,9 +60,9 @@ export const findMembership = async (queryObj: any) => {
|
||||
* @param {String[]} obj.roles - roles of users.
|
||||
*/
|
||||
export const addMemberships = async ({
|
||||
userIds,
|
||||
workspaceId,
|
||||
roles,
|
||||
userIds,
|
||||
workspaceId,
|
||||
roles
|
||||
}: {
|
||||
userIds: string[];
|
||||
workspaceId: string;
|
||||
@@ -74,15 +74,15 @@ export const addMemberships = async ({
|
||||
filter: {
|
||||
user: userId,
|
||||
workspace: workspaceId,
|
||||
role: roles[idx],
|
||||
role: roles[idx]
|
||||
},
|
||||
update: {
|
||||
user: userId,
|
||||
workspace: workspaceId,
|
||||
role: roles[idx],
|
||||
role: roles[idx]
|
||||
},
|
||||
upsert: true,
|
||||
},
|
||||
upsert: true
|
||||
}
|
||||
};
|
||||
});
|
||||
await Membership.bulkWrite(operations as any);
|
||||
@@ -94,8 +94,8 @@ export const addMemberships = async ({
|
||||
* @param {String} obj.membershipId - id of membership to delete
|
||||
*/
|
||||
export const deleteMembership = async ({ membershipId }: { membershipId: string }) => {
|
||||
const deletedMembership = await Membership.findOneAndDelete({
|
||||
_id: membershipId,
|
||||
const deletedMembership = await Membership.findOneAndDelete({
|
||||
_id: membershipId
|
||||
});
|
||||
|
||||
// delete keys associated with the membership
|
||||
@@ -103,9 +103,9 @@ export const deleteMembership = async ({ membershipId }: { membershipId: string
|
||||
// case: membership had a registered user
|
||||
await Key.deleteMany({
|
||||
receiver: deletedMembership.user,
|
||||
workspace: deletedMembership.workspace,
|
||||
workspace: deletedMembership.workspace
|
||||
});
|
||||
}
|
||||
|
||||
return deletedMembership;
|
||||
return deletedMembership;
|
||||
};
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
Key,
|
||||
Membership,
|
||||
MembershipOrg,
|
||||
Workspace,
|
||||
} from "../models";
|
||||
import {
|
||||
MembershipOrgNotFoundError,
|
||||
UnauthorizedRequestError,
|
||||
} from "../utils/errors";
|
||||
import { Key, Membership, MembershipOrg, Workspace } from "../models";
|
||||
import { MembershipOrgNotFoundError, UnauthorizedRequestError } from "../utils/errors";
|
||||
|
||||
/**
|
||||
* Validate that user with id [userId] is a member of organization with id [organizationId]
|
||||
@@ -19,39 +11,43 @@ import {
|
||||
* @param {String[]} obj.acceptedRoles
|
||||
*/
|
||||
export const validateMembershipOrg = async ({
|
||||
userId,
|
||||
organizationId,
|
||||
acceptedRoles,
|
||||
acceptedStatuses,
|
||||
userId,
|
||||
organizationId,
|
||||
acceptedRoles,
|
||||
acceptedStatuses
|
||||
}: {
|
||||
userId: Types.ObjectId;
|
||||
organizationId: Types.ObjectId;
|
||||
acceptedRoles?: Array<"owner" | "admin" | "member">;
|
||||
acceptedStatuses?: Array<"invited" | "accepted">;
|
||||
userId: Types.ObjectId;
|
||||
organizationId: Types.ObjectId;
|
||||
acceptedRoles?: Array<"owner" | "admin" | "member" | "custom">;
|
||||
acceptedStatuses?: Array<"invited" | "accepted">;
|
||||
}) => {
|
||||
const membershipOrg = await MembershipOrg.findOne({
|
||||
user: userId,
|
||||
organization: organizationId,
|
||||
});
|
||||
|
||||
if (!membershipOrg) {
|
||||
throw MembershipOrgNotFoundError({ message: "Failed to find organization membership" });
|
||||
}
|
||||
|
||||
if (acceptedRoles) {
|
||||
if (!acceptedRoles.includes(membershipOrg.role)) {
|
||||
throw UnauthorizedRequestError({ message: "Failed to validate organization membership role" });
|
||||
}
|
||||
}
|
||||
|
||||
if (acceptedStatuses) {
|
||||
if (!acceptedStatuses.includes(membershipOrg.status)) {
|
||||
throw UnauthorizedRequestError({ message: "Failed to validate organization membership status" });
|
||||
}
|
||||
}
|
||||
|
||||
return membershipOrg;
|
||||
}
|
||||
const membershipOrg = await MembershipOrg.findOne({
|
||||
user: userId,
|
||||
organization: organizationId
|
||||
});
|
||||
|
||||
if (!membershipOrg) {
|
||||
throw MembershipOrgNotFoundError({ message: "Failed to find organization membership" });
|
||||
}
|
||||
|
||||
if (acceptedRoles) {
|
||||
if (!acceptedRoles.includes(membershipOrg.role)) {
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed to validate organization membership role"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (acceptedStatuses) {
|
||||
if (!acceptedStatuses.includes(membershipOrg.status)) {
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed to validate organization membership status"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return membershipOrg;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return organization membership matching criteria specified in
|
||||
@@ -60,8 +56,8 @@ export const validateMembershipOrg = async ({
|
||||
* @return {Object} membershipOrg - membership
|
||||
*/
|
||||
export const findMembershipOrg = (queryObj: any) => {
|
||||
const membershipOrg = MembershipOrg.findOne(queryObj);
|
||||
return membershipOrg;
|
||||
const membershipOrg = MembershipOrg.findOne(queryObj);
|
||||
return membershipOrg;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -73,15 +69,15 @@ export const findMembershipOrg = (queryObj: any) => {
|
||||
* @param {String[]} obj.roles - roles of users.
|
||||
*/
|
||||
export const addMembershipsOrg = async ({
|
||||
userIds,
|
||||
organizationId,
|
||||
roles,
|
||||
statuses,
|
||||
userIds,
|
||||
organizationId,
|
||||
roles,
|
||||
statuses
|
||||
}: {
|
||||
userIds: string[];
|
||||
organizationId: string;
|
||||
roles: string[];
|
||||
statuses: string[];
|
||||
userIds: string[];
|
||||
organizationId: string;
|
||||
roles: string[];
|
||||
statuses: string[];
|
||||
}) => {
|
||||
const operations = userIds.map((userId, idx) => {
|
||||
return {
|
||||
@@ -90,16 +86,16 @@ export const addMembershipsOrg = async ({
|
||||
user: userId,
|
||||
organization: organizationId,
|
||||
role: roles[idx],
|
||||
status: statuses[idx],
|
||||
status: statuses[idx]
|
||||
},
|
||||
update: {
|
||||
user: userId,
|
||||
organization: organizationId,
|
||||
role: roles[idx],
|
||||
status: statuses[idx],
|
||||
status: statuses[idx]
|
||||
},
|
||||
upsert: true,
|
||||
},
|
||||
upsert: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -111,13 +107,9 @@ export const addMembershipsOrg = async ({
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.membershipOrgId - id of organization membership to delete
|
||||
*/
|
||||
export const deleteMembershipOrg = async ({
|
||||
membershipOrgId,
|
||||
}: {
|
||||
membershipOrgId: string;
|
||||
}) => {
|
||||
export const deleteMembershipOrg = async ({ membershipOrgId }: { membershipOrgId: string }) => {
|
||||
const deletedMembershipOrg = await MembershipOrg.findOneAndDelete({
|
||||
_id: membershipOrgId,
|
||||
_id: membershipOrgId
|
||||
});
|
||||
|
||||
if (!deletedMembershipOrg) throw new Error("Failed to delete organization membership");
|
||||
@@ -128,24 +120,24 @@ export const deleteMembershipOrg = async ({
|
||||
|
||||
const workspaces = (
|
||||
await Workspace.find({
|
||||
organization: deletedMembershipOrg.organization,
|
||||
organization: deletedMembershipOrg.organization
|
||||
})
|
||||
).map((w) => w._id.toString());
|
||||
|
||||
await Membership.deleteMany({
|
||||
user: deletedMembershipOrg.user,
|
||||
workspace: {
|
||||
$in: workspaces,
|
||||
},
|
||||
$in: workspaces
|
||||
}
|
||||
});
|
||||
|
||||
await Key.deleteMany({
|
||||
receiver: deletedMembershipOrg.user,
|
||||
workspace: {
|
||||
$in: workspaces,
|
||||
},
|
||||
$in: workspaces
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return deletedMembershipOrg;
|
||||
};
|
||||
return deletedMembershipOrg;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { Request } from "express";
|
||||
import { AnyZodObject, ZodError, z } from "zod";
|
||||
import { BadRequestError } from "../utils/errors";
|
||||
|
||||
export async function validateRequest<T extends AnyZodObject>(
|
||||
schema: T,
|
||||
req: Request
|
||||
): Promise<z.infer<T>> {
|
||||
try {
|
||||
return schema.parseAsync(req);
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
throw BadRequestError({ message: error.message });
|
||||
}
|
||||
return BadRequestError({ message: JSON.stringify(error) });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user