mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 01:52:22 +00:00
feat(rbac): added new validation to all routes and permission check to most
This commit is contained in:
@@ -1,30 +1,32 @@
|
||||
import { Request, Response } from "express";
|
||||
import { Action } from "../../models";
|
||||
import { ActionNotFoundError } from "../../../utils/errors";
|
||||
import { validateRequest } from "../../../helpers/validation";
|
||||
import * as reqValidator from "../../../validation/action";
|
||||
|
||||
export const getAction = async (req: Request, res: Response) => {
|
||||
let action;
|
||||
try {
|
||||
const { actionId } = req.params;
|
||||
|
||||
action = await Action
|
||||
.findById(actionId)
|
||||
.populate([
|
||||
"payload.secretVersions.oldSecretVersion",
|
||||
"payload.secretVersions.newSecretVersion",
|
||||
]);
|
||||
|
||||
if (!action) throw ActionNotFoundError({
|
||||
message: "Failed to find action",
|
||||
});
|
||||
let action;
|
||||
try {
|
||||
const {
|
||||
params: { actionId }
|
||||
} = await validateRequest(reqValidator.GetActionV1, req);
|
||||
|
||||
} catch (err) {
|
||||
throw ActionNotFoundError({
|
||||
message: "Failed to find action",
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
action,
|
||||
action = await Action.findById(actionId).populate([
|
||||
"payload.secretVersions.oldSecretVersion",
|
||||
"payload.secretVersions.newSecretVersion"
|
||||
]);
|
||||
|
||||
if (!action)
|
||||
throw ActionNotFoundError({
|
||||
message: "Failed to find action"
|
||||
});
|
||||
} catch (err) {
|
||||
throw ActionNotFoundError({
|
||||
message: "Failed to find action"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
action
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,27 +2,31 @@ import { Request, Response } from "express";
|
||||
import { EELicenseService } from "../../services";
|
||||
import { getLicenseServerUrl } from "../../../config";
|
||||
import { licenseServerKeyRequest } from "../../../config/request";
|
||||
import { validateRequest } from "../../../helpers/validation";
|
||||
import * as reqValidator from "../../../validation/cloudProducts";
|
||||
|
||||
/**
|
||||
* Return available cloud product information.
|
||||
* Note: Nicely formatted to easily construct a table from
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
export const getCloudProducts = async (req: Request, res: Response) => {
|
||||
const billingCycle = req.query["billing-cycle"] as string;
|
||||
const {
|
||||
query: { "billing-cycle": billingCycle }
|
||||
} = await validateRequest(reqValidator.GetCloudProductsV1, req);
|
||||
|
||||
if (EELicenseService.instanceType === "cloud") {
|
||||
const { data } = await licenseServerKeyRequest.get(
|
||||
`${await getLicenseServerUrl()}/api/license-server/v1/cloud-products?billing-cycle=${billingCycle}`
|
||||
);
|
||||
if (EELicenseService.instanceType === "cloud") {
|
||||
const { data } = await licenseServerKeyRequest.get(
|
||||
`${await getLicenseServerUrl()}/api/license-server/v1/cloud-products?billing-cycle=${billingCycle}`
|
||||
);
|
||||
|
||||
return res.status(200).send(data);
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
head: [],
|
||||
rows: [],
|
||||
});
|
||||
}
|
||||
return res.status(200).send(data);
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
head: [],
|
||||
rows: []
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import { ForbiddenError, subject } from "@casl/ability";
|
||||
import { Request, Response } from "express";
|
||||
import { validateRequest } from "../../../helpers/validation";
|
||||
import { Secret } from "../../../models";
|
||||
import {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionSub,
|
||||
getUserProjectPermissions
|
||||
} from "../../../services/ProjectRoleService";
|
||||
import { BadRequestError } from "../../../utils/errors";
|
||||
import * as reqValidator from "../../../validation";
|
||||
import { SecretVersion } from "../../models";
|
||||
import { EESecretService } from "../../services";
|
||||
|
||||
@@ -54,10 +63,21 @@ export const getSecretVersions = async (req: Request, res: Response) => {
|
||||
}
|
||||
}
|
||||
*/
|
||||
const { secretId } = req.params;
|
||||
const {
|
||||
params: { secretId },
|
||||
query: { offset, limit }
|
||||
} = await validateRequest(reqValidator.GetSecretVersionsV1, req);
|
||||
|
||||
const offset: number = parseInt(req.query.offset as string);
|
||||
const limit: number = parseInt(req.query.limit as string);
|
||||
const secret = await Secret.findById(secretId);
|
||||
if (!secret) {
|
||||
throw BadRequestError({ message: "Failed to find secret" });
|
||||
}
|
||||
|
||||
const { permission } = await getUserProjectPermissions(req.user._id, secret.workspace.toString());
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.SecretRollback
|
||||
);
|
||||
|
||||
const secretVersions = await SecretVersion.find({
|
||||
secret: secretId
|
||||
@@ -126,8 +146,28 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
|
||||
}
|
||||
}
|
||||
*/
|
||||
const { secretId } = req.params;
|
||||
const { version } = req.body;
|
||||
|
||||
const {
|
||||
params: { secretId },
|
||||
body: { version }
|
||||
} = await validateRequest(reqValidator.RollbackSecretVersionV1, req);
|
||||
|
||||
const toBeUpdatedSec = await Secret.findById(secretId);
|
||||
if (!toBeUpdatedSec) {
|
||||
throw BadRequestError({ message: "Failed to find secret" });
|
||||
}
|
||||
const { permission } = await getUserProjectPermissions(
|
||||
req.user._id,
|
||||
toBeUpdatedSec.workspace.toString()
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Create,
|
||||
ProjectPermissionSub.SecretRollback
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Edit,
|
||||
subject(ProjectPermissionSub.Secrets, { environment: toBeUpdatedSec.environment })
|
||||
);
|
||||
|
||||
// validate secret version
|
||||
const oldSecretVersion = await SecretVersion.findOne({
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
import { Request, Response } from "express";
|
||||
import { validateRequest } from "../../../helpers/validation";
|
||||
import {
|
||||
ISecretVersion,
|
||||
SecretSnapshot,
|
||||
TFolderRootVersionSchema,
|
||||
} from "../../models";
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionSub,
|
||||
getUserProjectPermissions
|
||||
} from "../../../services/ProjectRoleService";
|
||||
import * as reqValidator from "../../../validation/secretSnapshot";
|
||||
import { ISecretVersion, SecretSnapshot, TFolderRootVersionSchema } from "../../models";
|
||||
|
||||
/**
|
||||
* Return secret snapshot with id [secretSnapshotId]
|
||||
@@ -12,7 +16,9 @@ import {
|
||||
* @returns
|
||||
*/
|
||||
export const getSecretSnapshot = async (req: Request, res: Response) => {
|
||||
const { secretSnapshotId } = req.params;
|
||||
const {
|
||||
params: { secretSnapshotId }
|
||||
} = await validateRequest(reqValidator.GetSecretSnapshotV1, req);
|
||||
|
||||
const secretSnapshot = await SecretSnapshot.findById(secretSnapshotId)
|
||||
.lean()
|
||||
@@ -20,26 +26,36 @@ export const getSecretSnapshot = async (req: Request, res: Response) => {
|
||||
path: "secretVersions",
|
||||
populate: {
|
||||
path: "tags",
|
||||
model: "Tag",
|
||||
},
|
||||
model: "Tag"
|
||||
}
|
||||
})
|
||||
.populate<{ folderVersion: TFolderRootVersionSchema }>("folderVersion");
|
||||
|
||||
|
||||
if (!secretSnapshot) throw new Error("Failed to find secret snapshot");
|
||||
|
||||
|
||||
const { permission } = await getUserProjectPermissions(
|
||||
req.user._id,
|
||||
secretSnapshot.workspace.toString()
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.SecretRollback
|
||||
);
|
||||
|
||||
const folderId = secretSnapshot.folderId;
|
||||
// to show only the folder required secrets
|
||||
secretSnapshot.secretVersions = secretSnapshot.secretVersions.filter(
|
||||
({ folder }) => folder === folderId
|
||||
);
|
||||
|
||||
secretSnapshot.folderVersion =
|
||||
secretSnapshot?.folderVersion?.nodes?.children?.map(({ id, name }) => ({
|
||||
secretSnapshot.folderVersion = secretSnapshot?.folderVersion?.nodes?.children?.map(
|
||||
({ id, name }) => ({
|
||||
id,
|
||||
name,
|
||||
})) as any;
|
||||
name
|
||||
})
|
||||
) as any;
|
||||
|
||||
return res.status(200).send({
|
||||
secretSnapshot,
|
||||
secretSnapshot
|
||||
});
|
||||
};
|
||||
|
||||
@@ -22,16 +22,32 @@ import { getLatestSecretVersionIds } from "../../helpers/secretVersion";
|
||||
import { searchByFolderId } from "../../../services/FolderService";
|
||||
import { EEAuditLogService, EELicenseService } from "../../services";
|
||||
import { extractIPDetails, isValidIpOrCidr } from "../../../utils/ip";
|
||||
import { validateRequest } from "../../../helpers/validation";
|
||||
import {
|
||||
AddWorkspaceTrustedIpV1,
|
||||
DeleteWorkspaceTrustedIpV1,
|
||||
GetWorkspaceAuditLogActorFilterOptsV1,
|
||||
GetWorkspaceAuditLogsV1,
|
||||
GetWorkspaceLogsV1,
|
||||
GetWorkspaceSecretSnapshotsCountV1,
|
||||
GetWorkspaceSecretSnapshotsV1,
|
||||
GetWorkspaceTrustedIpsV1,
|
||||
RollbackWorkspaceSecretSnapshotV1,
|
||||
UpdateWorkspaceTrustedIpV1
|
||||
} from "../../../validation";
|
||||
import {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionSub,
|
||||
getUserProjectPermissions
|
||||
} from "../../../services/ProjectRoleService";
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
|
||||
/**
|
||||
* Return secret snapshots for workspace with id [workspaceId]
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
export const getWorkspaceSecretSnapshots = async (
|
||||
req: Request,
|
||||
res: Response
|
||||
) => {
|
||||
export const getWorkspaceSecretSnapshots = async (req: Request, res: Response) => {
|
||||
/*
|
||||
#swagger.summary = 'Return project secret snapshot ids'
|
||||
#swagger.description = 'Return project secret snapshots ids'
|
||||
@@ -77,23 +93,28 @@ export const getWorkspaceSecretSnapshots = async (
|
||||
}
|
||||
}
|
||||
*/
|
||||
const { workspaceId } = req.params;
|
||||
const { environment, folderId } = req.query;
|
||||
const {
|
||||
params: { workspaceId },
|
||||
query: { environment, folderId, offset, limit }
|
||||
} = await validateRequest(GetWorkspaceSecretSnapshotsV1, req);
|
||||
|
||||
const offset: number = parseInt(req.query.offset as string);
|
||||
const limit: number = parseInt(req.query.limit as string);
|
||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.SecretRollback
|
||||
);
|
||||
|
||||
const secretSnapshots = await SecretSnapshot.find({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
folderId: folderId || "root",
|
||||
folderId: folderId || "root"
|
||||
})
|
||||
.sort({ createdAt: -1 })
|
||||
.skip(offset)
|
||||
.limit(limit);
|
||||
|
||||
return res.status(200).send({
|
||||
secretSnapshots,
|
||||
secretSnapshots
|
||||
});
|
||||
};
|
||||
|
||||
@@ -102,21 +123,26 @@ export const getWorkspaceSecretSnapshots = async (
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
export const getWorkspaceSecretSnapshotsCount = async (
|
||||
req: Request,
|
||||
res: Response
|
||||
) => {
|
||||
const { workspaceId } = req.params;
|
||||
const { environment, folderId } = req.query;
|
||||
export const getWorkspaceSecretSnapshotsCount = async (req: Request, res: Response) => {
|
||||
const {
|
||||
params: { workspaceId },
|
||||
query: { environment, folderId }
|
||||
} = await validateRequest(GetWorkspaceSecretSnapshotsCountV1, req);
|
||||
|
||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.SecretRollback
|
||||
);
|
||||
|
||||
const count = await SecretSnapshot.countDocuments({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
folderId: folderId || "root",
|
||||
folderId: folderId || "root"
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
count,
|
||||
count
|
||||
});
|
||||
};
|
||||
|
||||
@@ -126,10 +152,7 @@ export const getWorkspaceSecretSnapshotsCount = async (
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
export const rollbackWorkspaceSecretSnapshot = async (
|
||||
req: Request,
|
||||
res: Response
|
||||
) => {
|
||||
export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Response) => {
|
||||
/*
|
||||
#swagger.summary = 'Roll back project secrets to those captured in a secret snapshot version.'
|
||||
#swagger.description = 'Roll back project secrets to those captured in a secret snapshot version.'
|
||||
@@ -181,19 +204,27 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
}
|
||||
*/
|
||||
|
||||
const { workspaceId } = req.params;
|
||||
const { version, environment, folderId = "root" } = req.body;
|
||||
const {
|
||||
params: { workspaceId },
|
||||
body: { folderId, environment, version }
|
||||
} = await validateRequest(RollbackWorkspaceSecretSnapshotV1, req);
|
||||
|
||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Create,
|
||||
ProjectPermissionSub.SecretRollback
|
||||
);
|
||||
|
||||
// validate secret snapshot
|
||||
const secretSnapshot = await SecretSnapshot.findOne({
|
||||
workspace: workspaceId,
|
||||
version,
|
||||
environment,
|
||||
folderId: folderId,
|
||||
folderId: folderId
|
||||
})
|
||||
.populate<{ secretVersions: ISecretVersion[] }>({
|
||||
path: "secretVersions",
|
||||
select: "+secretBlindIndex",
|
||||
select: "+secretBlindIndex"
|
||||
})
|
||||
.populate<{ folderVersion: TFolderRootVersionSchema }>("folderVersion");
|
||||
|
||||
@@ -202,13 +233,13 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
const snapshotFolderTree = secretSnapshot.folderVersion;
|
||||
const latestFolderTree = await Folder.findOne({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
environment
|
||||
});
|
||||
|
||||
const latestFolderVersion = await FolderVersion.findOne({
|
||||
environment,
|
||||
workspace: workspaceId,
|
||||
"nodes.id": folderId,
|
||||
"nodes.id": folderId
|
||||
}).sort({ "nodes.version": -1 });
|
||||
|
||||
const oldSecretVersionsObj: Record<string, ISecretVersion> = {};
|
||||
@@ -222,8 +253,7 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
|
||||
// the parent node from current latest one
|
||||
// this will be modified according to the snapshot and latest snapshots
|
||||
const newFolderTree =
|
||||
latestFolderTree && searchByFolderId(latestFolderTree.nodes, folderId);
|
||||
const newFolderTree = latestFolderTree && searchByFolderId(latestFolderTree.nodes, folderId);
|
||||
|
||||
if (newFolderTree) {
|
||||
newFolderTree.children = snapshotFolderTree?.nodes?.children || [];
|
||||
@@ -252,43 +282,43 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
folderId: {
|
||||
$in: Object.keys(groupByFolderId),
|
||||
},
|
||||
},
|
||||
$in: Object.keys(groupByFolderId)
|
||||
}
|
||||
}
|
||||
};
|
||||
const sortByFolderIdAndVersion: PipelineStage = {
|
||||
$sort: { folderId: 1, version: -1 },
|
||||
$sort: { folderId: 1, version: -1 }
|
||||
};
|
||||
const pickLatestVersionOfEachFolder = {
|
||||
$group: {
|
||||
_id: "$folderId",
|
||||
latestVersion: { $first: "$version" },
|
||||
doc: {
|
||||
$first: "$$ROOT",
|
||||
},
|
||||
},
|
||||
$first: "$$ROOT"
|
||||
}
|
||||
}
|
||||
};
|
||||
const populateSecVersion = {
|
||||
$lookup: {
|
||||
from: SecretVersion.collection.name,
|
||||
localField: "doc.secretVersions",
|
||||
foreignField: "_id",
|
||||
as: "doc.secretVersions",
|
||||
},
|
||||
as: "doc.secretVersions"
|
||||
}
|
||||
};
|
||||
const populateFolderVersion = {
|
||||
$lookup: {
|
||||
from: FolderVersion.collection.name,
|
||||
localField: "doc.folderVersion",
|
||||
foreignField: "_id",
|
||||
as: "doc.folderVersion",
|
||||
},
|
||||
as: "doc.folderVersion"
|
||||
}
|
||||
};
|
||||
const unwindFolderVerField = {
|
||||
$unwind: {
|
||||
path: "$doc.folderVersion",
|
||||
preserveNullAndEmptyArrays: true,
|
||||
},
|
||||
preserveNullAndEmptyArrays: true
|
||||
}
|
||||
};
|
||||
const latestSnapshotsByFolders: Array<{ doc: typeof secretSnapshot }> =
|
||||
await SecretSnapshot.aggregate([
|
||||
@@ -297,7 +327,7 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
pickLatestVersionOfEachFolder,
|
||||
populateSecVersion,
|
||||
populateFolderVersion,
|
||||
unwindFolderVerField,
|
||||
unwindFolderVerField
|
||||
]);
|
||||
|
||||
// recursive snapshotting each level
|
||||
@@ -327,7 +357,7 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
|
||||
// TODO: fix any
|
||||
const latestSecretVersionIds = await getLatestSecretVersionIds({
|
||||
secretIds,
|
||||
secretIds
|
||||
});
|
||||
|
||||
// TODO: fix any
|
||||
@@ -335,32 +365,31 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
await SecretVersion.find(
|
||||
{
|
||||
_id: {
|
||||
$in: latestSecretVersionIds.map((s) => s.versionId),
|
||||
},
|
||||
$in: latestSecretVersionIds.map((s) => s.versionId)
|
||||
}
|
||||
},
|
||||
"secret version"
|
||||
)
|
||||
).reduce(
|
||||
(accumulator, s) => ({
|
||||
...accumulator,
|
||||
[`${s.secret.toString()}`]: s,
|
||||
[`${s.secret.toString()}`]: s
|
||||
}),
|
||||
{}
|
||||
);
|
||||
|
||||
const secDelQuery: Record<string, unknown> = {
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
environment
|
||||
// undefined means root thus collect all secrets
|
||||
};
|
||||
if (folderId !== "root" && folderIds.length)
|
||||
secDelQuery.folder = { $in: folderIds };
|
||||
if (folderId !== "root" && folderIds.length) secDelQuery.folder = { $in: folderIds };
|
||||
|
||||
// delete existing secrets
|
||||
await Secret.deleteMany(secDelQuery);
|
||||
await Folder.deleteOne({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
environment
|
||||
});
|
||||
|
||||
// add secrets
|
||||
@@ -382,7 +411,7 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
createdAt,
|
||||
algorithm,
|
||||
keyEncoding,
|
||||
folder: secFolderId,
|
||||
folder: secFolderId
|
||||
} = oldSecretVersionsObj[sv];
|
||||
|
||||
return {
|
||||
@@ -405,7 +434,7 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
createdAt,
|
||||
algorithm,
|
||||
keyEncoding,
|
||||
folder: secFolderId,
|
||||
folder: secFolderId
|
||||
};
|
||||
})
|
||||
);
|
||||
@@ -429,7 +458,7 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
secretValueTag,
|
||||
algorithm,
|
||||
keyEncoding,
|
||||
folder: secFolderId,
|
||||
folder: secFolderId
|
||||
}) => ({
|
||||
_id: new Types.ObjectId(),
|
||||
secret: _id,
|
||||
@@ -448,7 +477,7 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
secretValueTag,
|
||||
algorithm,
|
||||
keyEncoding,
|
||||
folder: secFolderId,
|
||||
folder: secFolderId
|
||||
})
|
||||
)
|
||||
);
|
||||
@@ -464,7 +493,7 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
const newFolderVersion = new FolderVersion({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
nodes: newFolderTree,
|
||||
nodes: newFolderTree
|
||||
});
|
||||
await newFolderVersion.save();
|
||||
}
|
||||
@@ -473,13 +502,11 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
await SecretVersion.updateMany(
|
||||
{
|
||||
secret: {
|
||||
$in: Object.keys(oldSecretVersionsObj).map(
|
||||
(sv) => oldSecretVersionsObj[sv].secret
|
||||
),
|
||||
},
|
||||
$in: Object.keys(oldSecretVersionsObj).map((sv) => oldSecretVersionsObj[sv].secret)
|
||||
}
|
||||
},
|
||||
{
|
||||
isDeleted: false,
|
||||
isDeleted: false
|
||||
}
|
||||
);
|
||||
|
||||
@@ -487,11 +514,11 @@ export const rollbackWorkspaceSecretSnapshot = async (
|
||||
await EESecretService.takeSecretSnapshot({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
folderId,
|
||||
folderId
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
secrets,
|
||||
secrets
|
||||
});
|
||||
};
|
||||
|
||||
@@ -568,13 +595,16 @@ export const getWorkspaceLogs = async (req: Request, res: Response) => {
|
||||
}
|
||||
}
|
||||
*/
|
||||
const { workspaceId } = req.params;
|
||||
const {
|
||||
query: { limit, offset, userId, sortBy, actionNames },
|
||||
params: { workspaceId }
|
||||
} = await validateRequest(GetWorkspaceLogsV1, req);
|
||||
|
||||
const offset: number = parseInt(req.query.offset as string);
|
||||
const limit: number = parseInt(req.query.limit as string);
|
||||
const sortBy: string = req.query.sortBy as string;
|
||||
const userId: string = req.query.userId as string;
|
||||
const actionNames: string = req.query.actionNames as string;
|
||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.AuditLogs
|
||||
);
|
||||
|
||||
const logs = await Log.find({
|
||||
workspace: workspaceId,
|
||||
@@ -582,10 +612,10 @@ export const getWorkspaceLogs = async (req: Request, res: Response) => {
|
||||
...(actionNames
|
||||
? {
|
||||
actionNames: {
|
||||
$in: actionNames.split(","),
|
||||
},
|
||||
$in: actionNames.split(",")
|
||||
}
|
||||
}
|
||||
: {}),
|
||||
: {})
|
||||
})
|
||||
.sort({ createdAt: sortBy === "recent" ? -1 : 1 })
|
||||
.skip(offset)
|
||||
@@ -594,93 +624,109 @@ export const getWorkspaceLogs = async (req: Request, res: Response) => {
|
||||
.populate("user serviceAccount serviceTokenData");
|
||||
|
||||
return res.status(200).send({
|
||||
logs,
|
||||
logs
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Return audit logs for workspace with id [workspaceId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @param res
|
||||
*/
|
||||
export const getWorkspaceAuditLogs = async (req: Request, res: Response) => {
|
||||
const { workspaceId } = req.params;
|
||||
const eventType = req.query.eventType;
|
||||
const userAgentType = req.query.userAgentType;
|
||||
const actor = req.query.actor as string | undefined;
|
||||
const offset: number = parseInt(req.query.offset as string);
|
||||
const limit: number = parseInt(req.query.limit as string);
|
||||
|
||||
const startDate = req.query.startDate as string;
|
||||
const endDate = req.query.endDate as string;
|
||||
|
||||
const {
|
||||
query: { limit, offset, endDate, eventType, startDate, userAgentType, actor },
|
||||
params: { workspaceId }
|
||||
} = await validateRequest(GetWorkspaceAuditLogsV1, req);
|
||||
|
||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.AuditLogs
|
||||
);
|
||||
|
||||
const query = {
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
...(eventType ? {
|
||||
"event.type": eventType
|
||||
} : {}),
|
||||
...(userAgentType ? {
|
||||
userAgentType
|
||||
} : {}),
|
||||
...(actor ? {
|
||||
"actor.type": actor.split("-", 2)[0],
|
||||
...(actor.split("-", 2)[0] === ActorType.USER ? {
|
||||
"actor.metadata.userId": actor.split("-", 2)[1]
|
||||
} : {
|
||||
"actor.metadata.serviceId": actor.split("-", 2)[1]
|
||||
})
|
||||
} : {}),
|
||||
...(startDate || endDate ? {
|
||||
createdAt: {
|
||||
...(startDate && { $gte: new Date(startDate) }),
|
||||
...(endDate && { $lte: new Date(endDate) })
|
||||
}
|
||||
} : {})
|
||||
}
|
||||
|
||||
const auditLogs = await AuditLog.find(query)
|
||||
.sort({ createdAt: -1 })
|
||||
.skip(offset)
|
||||
.limit(limit);
|
||||
...(eventType
|
||||
? {
|
||||
"event.type": eventType
|
||||
}
|
||||
: {}),
|
||||
...(userAgentType
|
||||
? {
|
||||
userAgentType
|
||||
}
|
||||
: {}),
|
||||
...(actor
|
||||
? {
|
||||
"actor.type": actor.split("-", 2)[0],
|
||||
...(actor.split("-", 2)[0] === ActorType.USER
|
||||
? {
|
||||
"actor.metadata.userId": actor.split("-", 2)[1]
|
||||
}
|
||||
: {
|
||||
"actor.metadata.serviceId": actor.split("-", 2)[1]
|
||||
})
|
||||
}
|
||||
: {}),
|
||||
...(startDate || endDate
|
||||
? {
|
||||
createdAt: {
|
||||
...(startDate && { $gte: new Date(startDate) }),
|
||||
...(endDate && { $lte: new Date(endDate) })
|
||||
}
|
||||
}
|
||||
: {})
|
||||
};
|
||||
|
||||
const auditLogs = await AuditLog.find(query).sort({ createdAt: -1 }).skip(offset).limit(limit);
|
||||
|
||||
const totalCount = await AuditLog.countDocuments(query);
|
||||
|
||||
|
||||
return res.status(200).send({
|
||||
auditLogs,
|
||||
totalCount
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return audit log actor filter options for workspace with id [workspaceId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @param res
|
||||
*/
|
||||
export const getWorkspaceAuditLogActorFilterOpts = async (req: Request, res: Response) => {
|
||||
const { workspaceId } = req.params;
|
||||
|
||||
const {
|
||||
params: { workspaceId }
|
||||
} = await validateRequest(GetWorkspaceAuditLogActorFilterOptsV1, req);
|
||||
|
||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.AuditLogs
|
||||
);
|
||||
|
||||
const userIds = await Membership.distinct("user", {
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
const userActors: UserActor[] = (await User.find({
|
||||
_id: {
|
||||
$in: userIds
|
||||
}
|
||||
})
|
||||
.select("email"))
|
||||
.map((user) => ({
|
||||
const userActors: UserActor[] = (
|
||||
await User.find({
|
||||
_id: {
|
||||
$in: userIds
|
||||
}
|
||||
}).select("email")
|
||||
).map((user) => ({
|
||||
type: ActorType.USER,
|
||||
metadata: {
|
||||
userId: user._id.toString(),
|
||||
email: user.email
|
||||
}
|
||||
}));
|
||||
|
||||
const serviceActors: ServiceActor[] = (await ServiceTokenData.find({
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
})
|
||||
.select("name"))
|
||||
.map((serviceTokenData) => ({
|
||||
|
||||
const serviceActors: ServiceActor[] = (
|
||||
await ServiceTokenData.find({
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
}).select("name")
|
||||
).map((serviceTokenData) => ({
|
||||
type: ActorType.SERVICE,
|
||||
metadata: {
|
||||
serviceId: serviceTokenData._id.toString(),
|
||||
@@ -691,50 +737,65 @@ export const getWorkspaceAuditLogActorFilterOpts = async (req: Request, res: Res
|
||||
return res.status(200).send({
|
||||
actors: [...userActors, ...serviceActors]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return trusted ips for workspace with id [workspaceId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @param res
|
||||
*/
|
||||
export const getWorkspaceTrustedIps = async (req: Request, res: Response) => {
|
||||
const { workspaceId } = req.params;
|
||||
const {
|
||||
params: { workspaceId }
|
||||
} = await validateRequest(GetWorkspaceTrustedIpsV1, req);
|
||||
|
||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.IpAllowList
|
||||
);
|
||||
|
||||
const trustedIps = await TrustedIP.find({
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
|
||||
return res.status(200).send({
|
||||
trustedIps
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a trusted ip to workspace with id [workspaceId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
export const addWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
const { workspaceId } = req.params;
|
||||
const {
|
||||
ipAddress: ip,
|
||||
comment,
|
||||
isActive
|
||||
} = req.body;
|
||||
|
||||
params: { workspaceId },
|
||||
body: { comment, isActive, ipAddress: ip }
|
||||
} = await validateRequest(AddWorkspaceTrustedIpV1, req);
|
||||
|
||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Create,
|
||||
ProjectPermissionSub.IpAllowList
|
||||
);
|
||||
|
||||
const plan = await EELicenseService.getPlan(req.workspace.organization);
|
||||
|
||||
if (!plan.ipAllowlisting) return res.status(400).send({
|
||||
message: "Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range."
|
||||
});
|
||||
|
||||
|
||||
if (!plan.ipAllowlisting)
|
||||
return res.status(400).send({
|
||||
message:
|
||||
"Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range."
|
||||
});
|
||||
|
||||
const isValidIPOrCidr = isValidIpOrCidr(ip);
|
||||
|
||||
if (!isValidIPOrCidr) return res.status(400).send({
|
||||
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
||||
});
|
||||
|
||||
|
||||
if (!isValidIPOrCidr)
|
||||
return res.status(400).send({
|
||||
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
||||
});
|
||||
|
||||
const { ipAddress, type, prefix } = extractIPDetails(ip);
|
||||
|
||||
const trustedIp = await new TrustedIP({
|
||||
@@ -743,9 +804,9 @@ export const addWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
type,
|
||||
prefix,
|
||||
isActive,
|
||||
comment,
|
||||
comment
|
||||
}).save();
|
||||
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
@@ -764,32 +825,40 @@ export const addWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
return res.status(200).send({
|
||||
trustedIp
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update trusted ip with id [trustedIpId] workspace with id [workspaceId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
export const updateWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
const { workspaceId, trustedIpId } = req.params;
|
||||
const {
|
||||
ipAddress: ip,
|
||||
comment
|
||||
} = req.body;
|
||||
params: { workspaceId, trustedIpId },
|
||||
body: { ipAddress: ip, comment }
|
||||
} = await validateRequest(UpdateWorkspaceTrustedIpV1, req);
|
||||
|
||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Edit,
|
||||
ProjectPermissionSub.IpAllowList
|
||||
);
|
||||
|
||||
const plan = await EELicenseService.getPlan(req.workspace.organization);
|
||||
|
||||
if (!plan.ipAllowlisting) return res.status(400).send({
|
||||
message: "Failed to update IP access range due to plan restriction. Upgrade plan to update IP access range."
|
||||
});
|
||||
if (!plan.ipAllowlisting)
|
||||
return res.status(400).send({
|
||||
message:
|
||||
"Failed to update IP access range due to plan restriction. Upgrade plan to update IP access range."
|
||||
});
|
||||
|
||||
const isValidIPOrCidr = isValidIpOrCidr(ip);
|
||||
|
||||
if (!isValidIPOrCidr) return res.status(400).send({
|
||||
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
||||
});
|
||||
|
||||
|
||||
if (!isValidIPOrCidr)
|
||||
return res.status(400).send({
|
||||
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
||||
});
|
||||
|
||||
const { ipAddress, type, prefix } = extractIPDetails(ip);
|
||||
|
||||
const updateObject: {
|
||||
@@ -799,33 +868,34 @@ export const updateWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
prefix?: number;
|
||||
$unset?: {
|
||||
prefix: number;
|
||||
}
|
||||
};
|
||||
} = {
|
||||
ipAddress,
|
||||
type,
|
||||
comment
|
||||
};
|
||||
|
||||
|
||||
if (prefix !== undefined) {
|
||||
updateObject.prefix = prefix;
|
||||
} else {
|
||||
updateObject.$unset = { prefix: 1 };
|
||||
}
|
||||
|
||||
|
||||
const trustedIp = await TrustedIP.findOneAndUpdate(
|
||||
{
|
||||
_id: new Types.ObjectId(trustedIpId),
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
},
|
||||
updateObject,
|
||||
{
|
||||
new: true
|
||||
}
|
||||
);
|
||||
|
||||
if (!trustedIp) return res.status(400).send({
|
||||
message: "Failed to update trusted IP"
|
||||
});
|
||||
|
||||
if (!trustedIp)
|
||||
return res.status(400).send({
|
||||
message: "Failed to update trusted IP"
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
@@ -841,34 +911,45 @@ export const updateWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
workspaceId: trustedIp.workspace
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
return res.status(200).send({
|
||||
trustedIp
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete IP access range from workspace with id [workspaceId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
export const deleteWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
const { workspaceId, trustedIpId } = req.params;
|
||||
const {
|
||||
params: { workspaceId, trustedIpId }
|
||||
} = await validateRequest(DeleteWorkspaceTrustedIpV1, req);
|
||||
|
||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Delete,
|
||||
ProjectPermissionSub.IpAllowList
|
||||
);
|
||||
|
||||
const plan = await EELicenseService.getPlan(req.workspace.organization);
|
||||
|
||||
if (!plan.ipAllowlisting) return res.status(400).send({
|
||||
message: "Failed to delete IP access range due to plan restriction. Upgrade plan to delete IP access range."
|
||||
});
|
||||
|
||||
|
||||
if (!plan.ipAllowlisting)
|
||||
return res.status(400).send({
|
||||
message:
|
||||
"Failed to delete IP access range due to plan restriction. Upgrade plan to delete IP access range."
|
||||
});
|
||||
|
||||
const trustedIp = await TrustedIP.findOneAndDelete({
|
||||
_id: new Types.ObjectId(trustedIpId),
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
if (!trustedIp) return res.status(400).send({
|
||||
message: "Failed to delete trusted IP"
|
||||
});
|
||||
|
||||
if (!trustedIp)
|
||||
return res.status(400).send({
|
||||
message: "Failed to delete trusted IP"
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
@@ -888,4 +969,4 @@ export const deleteWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
return res.status(200).send({
|
||||
trustedIp
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
import express from "express";
|
||||
const router = express.Router();
|
||||
import {
|
||||
validateRequest,
|
||||
} from "../../../middleware";
|
||||
import { param } from "express-validator";
|
||||
import { actionController } from "../../controllers/v1";
|
||||
|
||||
// TODO: put into action controller
|
||||
router.get(
|
||||
"/:actionId",
|
||||
param("actionId").exists().trim(),
|
||||
validateRequest,
|
||||
actionController.getAction
|
||||
);
|
||||
router.get("/:actionId", actionController.getAction);
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
import express from "express";
|
||||
const router = express.Router();
|
||||
import {
|
||||
requireAuth,
|
||||
validateRequest,
|
||||
} from "../../../middleware";
|
||||
import { query } from "express-validator";
|
||||
import { requireAuth, validateRequest } from "../../../middleware";
|
||||
import { cloudProductsController } from "../../controllers/v1";
|
||||
import { AuthMode } from "../../../variables";
|
||||
|
||||
router.get(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
query("billing-cycle").exists().isIn(["monthly", "yearly"]),
|
||||
validateRequest,
|
||||
cloudProductsController.getCloudProducts
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
|
||||
}),
|
||||
validateRequest,
|
||||
cloudProductsController.getCloudProducts
|
||||
);
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
||||
@@ -1,48 +1,25 @@
|
||||
import express from "express";
|
||||
const router = express.Router();
|
||||
import {
|
||||
requireAuth,
|
||||
requireSecretAuth,
|
||||
validateRequest,
|
||||
} from "../../../middleware";
|
||||
import { body, param, query } from "express-validator";
|
||||
import { requireAuth } from "../../../middleware";
|
||||
import { secretController } from "../../controllers/v1";
|
||||
import {
|
||||
ADMIN,
|
||||
AuthMode,
|
||||
MEMBER,
|
||||
PERMISSION_READ_SECRETS,
|
||||
PERMISSION_WRITE_SECRETS
|
||||
AuthMode
|
||||
} from "../../../variables";
|
||||
|
||||
router.get(
|
||||
"/:secretId/secret-versions",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireSecretAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
requiredPermissions: [PERMISSION_READ_SECRETS],
|
||||
}),
|
||||
param("secretId").exists().trim(),
|
||||
query("offset").exists().isInt(),
|
||||
query("limit").exists().isInt(),
|
||||
validateRequest,
|
||||
secretController.getSecretVersions
|
||||
"/:secretId/secret-versions",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
|
||||
}),
|
||||
secretController.getSecretVersions
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/:secretId/secret-versions/rollback",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireSecretAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
requiredPermissions: [PERMISSION_READ_SECRETS, PERMISSION_WRITE_SECRETS],
|
||||
}),
|
||||
param("secretId").exists().trim(),
|
||||
body("version").exists().isInt(),
|
||||
secretController.rollbackSecretVersion
|
||||
"/:secretId/secret-versions/rollback",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
|
||||
}),
|
||||
secretController.rollbackSecretVersion
|
||||
);
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
||||
@@ -1,182 +1,85 @@
|
||||
import express from "express";
|
||||
const router = express.Router();
|
||||
import {
|
||||
requireAuth,
|
||||
requireWorkspaceAuth,
|
||||
validateRequest,
|
||||
} from "../../../middleware";
|
||||
import { body, param, query } from "express-validator";
|
||||
import {
|
||||
ADMIN,
|
||||
AuthMode,
|
||||
MEMBER
|
||||
} from "../../../variables";
|
||||
import { requireAuth } from "../../../middleware";
|
||||
import { AuthMode } from "../../../variables";
|
||||
import { workspaceController } from "../../controllers/v1";
|
||||
import { EventType, UserAgentType } from "../../models";
|
||||
|
||||
router.get(
|
||||
"/:workspaceId/secret-snapshots",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: "params",
|
||||
}),
|
||||
param("workspaceId").exists().trim(),
|
||||
query("environment").isString().exists().trim(),
|
||||
query("folderId").default("root").isString().trim(),
|
||||
query("offset").exists().isInt(),
|
||||
query("limit").exists().isInt(),
|
||||
validateRequest,
|
||||
workspaceController.getWorkspaceSecretSnapshots
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:workspaceId/secret-snapshots/count",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: "params",
|
||||
}),
|
||||
param("workspaceId").exists().trim(),
|
||||
query("environment").isString().exists().trim(),
|
||||
query("folderId").default("root").isString().trim(),
|
||||
validateRequest,
|
||||
workspaceController.getWorkspaceSecretSnapshotsCount
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/:workspaceId/secret-snapshots/rollback",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: "params",
|
||||
}),
|
||||
param("workspaceId").exists().trim(),
|
||||
body("environment").isString().exists().trim(),
|
||||
query("folderId").default("root").isString().exists().trim(),
|
||||
body("version").exists().isInt(),
|
||||
validateRequest,
|
||||
workspaceController.rollbackWorkspaceSecretSnapshot
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:workspaceId/logs",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: "params",
|
||||
}),
|
||||
param("workspaceId").exists().trim(),
|
||||
query("offset").exists().isInt(),
|
||||
query("limit").exists().isInt(),
|
||||
query("sortBy"),
|
||||
query("userId"),
|
||||
query("actionNames"),
|
||||
validateRequest,
|
||||
workspaceController.getWorkspaceLogs
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:workspaceId/audit-logs",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: "params",
|
||||
}),
|
||||
param("workspaceId").exists().trim(),
|
||||
query("eventType").isString().isIn(Object.values(EventType)).optional({ nullable: true }),
|
||||
query("userAgentType").isString().isIn(Object.values(UserAgentType)).optional({ nullable: true }),
|
||||
query("actor").optional({ nullable: true }),
|
||||
query("startDate").isISO8601().withMessage("Invalid start date format").optional({ nullable: true }),
|
||||
query("endDate").isISO8601().withMessage("Invalid end date format").optional({ nullable: true }),
|
||||
query("offset"),
|
||||
query("limit"),
|
||||
validateRequest,
|
||||
workspaceController.getWorkspaceAuditLogs
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:workspaceId/audit-logs/filters/actors",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: "params",
|
||||
}),
|
||||
param("workspaceId").exists().trim(),
|
||||
validateRequest,
|
||||
workspaceController.getWorkspaceAuditLogActorFilterOpts
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:workspaceId/trusted-ips",
|
||||
param("workspaceId").exists().isString().trim(),
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: "params",
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
workspaceController.getWorkspaceTrustedIps
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/:workspaceId/trusted-ips",
|
||||
param("workspaceId").exists().isString().trim(),
|
||||
body("ipAddress").exists().isString().trim(),
|
||||
body("comment").default("").isString().trim(),
|
||||
body("isActive").exists().isBoolean(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
locationWorkspaceId: "params",
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
workspaceController.addWorkspaceTrustedIp
|
||||
);
|
||||
|
||||
router.patch(
|
||||
"/:workspaceId/trusted-ips/:trustedIpId",
|
||||
param("workspaceId").exists().isString().trim(),
|
||||
param("trustedIpId").exists().isString().trim(),
|
||||
body("ipAddress").isString().trim().default(""),
|
||||
body("comment").default("").isString().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
locationWorkspaceId: "params",
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
workspaceController.updateWorkspaceTrustedIp
|
||||
);
|
||||
|
||||
router.delete(
|
||||
"/:workspaceId/trusted-ips/:trustedIpId",
|
||||
param("workspaceId").exists().isString().trim(),
|
||||
param("trustedIpId").exists().isString().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
locationWorkspaceId: "params",
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
workspaceController.deleteWorkspaceTrustedIp
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user