Merge pull request #828 from Infisical/audit-log-revamp

Audit Log V2
This commit is contained in:
BlackMagiq
2023-08-08 22:45:54 +07:00
committed by GitHub
119 changed files with 3868 additions and 1529 deletions
+5 -5
View File
@@ -15,20 +15,20 @@ import { checkUserDevice } from "../../helpers/user";
import { import {
ACTION_LOGIN, ACTION_LOGIN,
ACTION_LOGOUT, ACTION_LOGOUT,
AUTH_MODE_JWT,
} from "../../variables"; } from "../../variables";
import { import {
BadRequestError, BadRequestError,
UnauthorizedRequestError, UnauthorizedRequestError,
} from "../../utils/errors"; } from "../../utils/errors";
import { EELogService } from "../../ee/services"; import { EELogService } from "../../ee/services";
import { getChannelFromUserAgent } from "../../utils/posthog"; import { getUserAgentType } from "../../utils/posthog";
import { import {
getHttpsEnabled, getHttpsEnabled,
getJwtAuthLifetime, getJwtAuthLifetime,
getJwtAuthSecret, getJwtAuthSecret,
getJwtRefreshSecret, getJwtRefreshSecret,
} from "../../config"; } from "../../config";
import { ActorType } from "../../ee/models";
declare module "jsonwebtoken" { declare module "jsonwebtoken" {
export interface UserIDJwtPayload extends jwt.JwtPayload { export interface UserIDJwtPayload extends jwt.JwtPayload {
@@ -142,7 +142,7 @@ export const login2 = async (req: Request, res: Response) => {
loginAction && await EELogService.createLog({ loginAction && await EELogService.createLog({
userId: user._id, userId: user._id,
actions: [loginAction], actions: [loginAction],
channel: getChannelFromUserAgent(req.headers["user-agent"]), channel: getUserAgentType(req.headers["user-agent"]),
ipAddress: req.realIP, ipAddress: req.realIP,
}); });
@@ -170,7 +170,7 @@ export const login2 = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const logout = async (req: Request, res: Response) => { export const logout = async (req: Request, res: Response) => {
if (req.authData.authMode === AUTH_MODE_JWT && req.authData.authPayload instanceof User && req.authData.tokenVersionId) { if (req.authData.actor.type === ActorType.USER && req.authData.tokenVersionId) {
await clearTokens(req.authData.tokenVersionId) await clearTokens(req.authData.tokenVersionId)
} }
@@ -190,7 +190,7 @@ export const logout = async (req: Request, res: Response) => {
logoutAction && await EELogService.createLog({ logoutAction && await EELogService.createLog({
userId: req.user._id, userId: req.user._id,
actions: [logoutAction], actions: [logoutAction],
channel: getChannelFromUserAgent(req.headers["user-agent"]), channel: getUserAgentType(req.headers["user-agent"]),
ipAddress: req.realIP, ipAddress: req.realIP,
}); });
@@ -3,7 +3,9 @@ import { Types } from "mongoose";
import { standardRequest } from "../../config/request"; import { standardRequest } from "../../config/request";
import { getApps, getTeams, revokeAccess } from "../../integrations"; import { getApps, getTeams, revokeAccess } from "../../integrations";
import { Bot, IntegrationAuth } from "../../models"; import { Bot, IntegrationAuth } from "../../models";
import { EventType } from "../../ee/models";
import { IntegrationService } from "../../services"; import { IntegrationService } from "../../services";
import { EEAuditLogService } from "../../ee/services";
import { import {
ALGORITHM_AES_256_GCM, ALGORITHM_AES_256_GCM,
ENCODING_SCHEME_UTF8, ENCODING_SCHEME_UTF8,
@@ -62,6 +64,19 @@ export const oAuthExchange = async (req: Request, res: Response) => {
environment: environments[0].slug environment: environments[0].slug
}); });
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.AUTHORIZE_INTEGRATION,
metadata: {
integration: integrationAuth.integration
}
},
{
workspaceId: integrationAuth.workspace
}
);
return res.status(200).send({ return res.status(200).send({
integrationAuth integrationAuth
}); });
@@ -129,6 +144,19 @@ export const saveIntegrationAccessToken = async (req: Request, res: Response) =>
}); });
if (!integrationAuth) throw new Error("Failed to save integration access token"); if (!integrationAuth) throw new Error("Failed to save integration access token");
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.AUTHORIZE_INTEGRATION,
metadata: {
integration: integrationAuth.integration
}
},
{
workspaceId: integrationAuth.workspace
}
);
return res.status(200).send({ return res.status(200).send({
integrationAuth integrationAuth
@@ -530,6 +558,23 @@ export const deleteIntegrationAuth = async (req: Request, res: Response) => {
integrationAuth: req.integrationAuth, integrationAuth: req.integrationAuth,
accessToken: req.accessToken accessToken: req.accessToken
}); });
if (!integrationAuth) return res.status(400).send({
message: "Failed to find integration authorization"
});
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UNAUTHORIZE_INTEGRATION,
metadata: {
integration: integrationAuth.integration
}
},
{
workspaceId: integrationAuth.workspace
}
);
return res.status(200).send({ return res.status(200).send({
integrationAuth integrationAuth
@@ -6,6 +6,8 @@ import { eventStartIntegration } from "../../events";
import Folder from "../../models/folder"; import Folder from "../../models/folder";
import { getFolderByPath } from "../../services/FolderService"; import { getFolderByPath } from "../../services/FolderService";
import { BadRequestError } from "../../utils/errors"; import { BadRequestError } from "../../utils/errors";
import { EEAuditLogService } from "../../ee/services";
import { EventType } from "../../ee/models";
/** /**
* Create/initialize an (empty) integration for integration authorization * Create/initialize an (empty) integration for integration authorization
@@ -74,6 +76,31 @@ export const createIntegration = async (req: Request, res: Response) => {
}) })
}); });
} }
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_INTEGRATION,
metadata: {
integrationId: integration._id.toString(),
integration: integration.integration,
environment: integration.environment,
secretPath,
url: integration.url,
app: integration.app,
appId: integration.appId,
targetEnvironment: integration.targetEnvironment,
targetEnvironmentId: integration.targetEnvironmentId,
targetService: integration.targetService,
targetServiceId: integration.targetServiceId,
path: integration.path,
region: integration.region
}
},
{
workspaceId: integration.workspace
}
);
return res.status(200).send({ return res.status(200).send({
integration integration
@@ -148,8 +175,7 @@ export const updateIntegration = async (req: Request, res: Response) => {
}; };
/** /**
* Delete integration with id [integrationId] and deactivate bot if there are * Delete integration with id [integrationId]
* no integrations left
* @param req * @param req
* @param res * @param res
* @returns * @returns
@@ -163,6 +189,31 @@ export const deleteIntegration = async (req: Request, res: Response) => {
if (!integration) throw new Error("Failed to find integration"); if (!integration) throw new Error("Failed to find integration");
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_INTEGRATION,
metadata: {
integrationId: integration._id.toString(),
integration: integration.integration,
environment: integration.environment,
secretPath: integration.secretPath,
url: integration.url,
app: integration.app,
appId: integration.appId,
targetEnvironment: integration.targetEnvironment,
targetEnvironmentId: integration.targetEnvironmentId,
targetService: integration.targetService,
targetServiceId: integration.targetServiceId,
path: integration.path,
region: integration.region
}
},
{
workspaceId: integration.workspace
}
);
return res.status(200).send({ return res.status(200).send({
integration integration
}); });
+16 -1
View File
@@ -1,6 +1,9 @@
import { Types } from "mongoose";
import { Request, Response } from "express"; import { Request, Response } from "express";
import { Key } from "../../models"; import { Key } from "../../models";
import { findMembership } from "../../helpers/membership"; import { findMembership } from "../../helpers/membership";
import { EventType } from "../../ee/models";
import { EEAuditLogService } from "../../ee/services";
/** /**
* Add (encrypted) copy of workspace key for workspace with id [workspaceId] for user with * Add (encrypted) copy of workspace key for workspace with id [workspaceId] for user with
@@ -44,7 +47,7 @@ export const uploadKey = async (req: Request, res: Response) => {
*/ */
export const getLatestKey = async (req: Request, res: Response) => { export const getLatestKey = async (req: Request, res: Response) => {
const { workspaceId } = req.params; const { workspaceId } = req.params;
// get latest key // get latest key
const latestKey = await Key.find({ const latestKey = await Key.find({
workspace: workspaceId, workspace: workspaceId,
@@ -58,6 +61,18 @@ export const getLatestKey = async (req: Request, res: Response) => {
if (latestKey.length > 0) { if (latestKey.length > 0) {
resObj["latestKey"] = latestKey[0]; resObj["latestKey"] = latestKey[0];
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.GET_WORKSPACE_KEY,
metadata: {
keyId: latestKey[0]._id.toString()
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
} }
return res.status(200).send(resObj); return res.status(200).send(resObj);
@@ -1,9 +1,12 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import { Key, Membership, MembershipOrg, User } from "../../models"; import { Types } from "mongoose";
import { IUser, Key, Membership, MembershipOrg, User } from "../../models";
import { EventType } from "../../ee/models";
import { deleteMembership as deleteMember, findMembership } from "../../helpers/membership"; import { deleteMembership as deleteMember, findMembership } from "../../helpers/membership";
import { sendMail } from "../../helpers/nodemailer"; import { sendMail } from "../../helpers/nodemailer";
import { ACCEPTED, ADMIN, MEMBER } from "../../variables"; import { ACCEPTED, ADMIN, MEMBER } from "../../variables";
import { getSiteURL } from "../../config"; import { getSiteURL } from "../../config";
import { EEAuditLogService } from "../../ee/services";
/** /**
* Check that user is a member of workspace with id [workspaceId] * Check that user is a member of workspace with id [workspaceId]
@@ -36,11 +39,11 @@ export const validateMembership = async (req: Request, res: Response) => {
*/ */
export const deleteMembership = async (req: Request, res: Response) => { export const deleteMembership = async (req: Request, res: Response) => {
const { membershipId } = req.params; const { membershipId } = req.params;
// check if membership to delete exists // check if membership to delete exists
const membershipToDelete = await Membership.findOne({ const membershipToDelete = await Membership.findOne({
_id: membershipId _id: membershipId
}).populate("user"); }).populate<{ user: IUser }>("user");
if (!membershipToDelete) { if (!membershipToDelete) {
throw new Error("Failed to delete workspace membership that doesn't exist"); throw new Error("Failed to delete workspace membership that doesn't exist");
@@ -66,6 +69,20 @@ export const deleteMembership = async (req: Request, res: Response) => {
const deletedMembership = await deleteMember({ const deletedMembership = await deleteMember({
membershipId: membershipToDelete._id.toString() membershipId: membershipToDelete._id.toString()
}); });
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.REMOVE_WORKSPACE_MEMBER,
metadata: {
userId: membershipToDelete.user._id.toString(),
email: membershipToDelete.user.email
}
},
{
workspaceId: membership.workspace
}
);
return res.status(200).send({ return res.status(200).send({
deletedMembership deletedMembership
@@ -140,7 +157,7 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => {
const inviteeMembership = await Membership.findOne({ const inviteeMembership = await Membership.findOne({
user: invitee._id, user: invitee._id,
workspace: workspaceId workspace: workspaceId
}); }).populate<{ user: IUser }>("user");
if (inviteeMembership) throw new Error("Failed to add existing member of workspace"); if (inviteeMembership) throw new Error("Failed to add existing member of workspace");
@@ -181,6 +198,20 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => {
} }
}); });
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.ADD_WORKSPACE_MEMBER,
metadata: {
userId: invitee._id.toString(),
email: invitee.email
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
return res.status(200).send({ return res.status(200).send({
invitee, invitee,
latestKey latestKey
@@ -103,14 +103,14 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
// validate membership // validate membership
const membershipOrg = await MembershipOrg.findOne({ const membershipOrg = await MembershipOrg.findOne({
user: req.user._id, user: req.user._id,
organization: organizationId organization: new Types.ObjectId(organizationId)
}); });
if (!membershipOrg) { if (!membershipOrg) {
throw new Error("Failed to validate organization membership"); throw new Error("Failed to validate organization membership");
} }
const plan = await EELicenseService.getPlan(organizationId); const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId));
const ssoConfig = await SSOConfig.findOne({ const ssoConfig = await SSOConfig.findOne({
organization: new Types.ObjectId(organizationId) organization: new Types.ObjectId(organizationId)
@@ -5,7 +5,7 @@ import * as bigintConversion from "bigint-conversion";
import { BackupPrivateKey, LoginSRPDetail, User } from "../../models"; import { BackupPrivateKey, LoginSRPDetail, User } from "../../models";
import { clearTokens, createToken, sendMail } from "../../helpers"; import { clearTokens, createToken, sendMail } from "../../helpers";
import { TokenService } from "../../services"; import { TokenService } from "../../services";
import { AUTH_MODE_JWT, TOKEN_EMAIL_PASSWORD_RESET } from "../../variables"; import { TOKEN_EMAIL_PASSWORD_RESET } from "../../variables";
import { BadRequestError } from "../../utils/errors"; import { BadRequestError } from "../../utils/errors";
import { import {
getHttpsEnabled, getHttpsEnabled,
@@ -13,6 +13,7 @@ import {
getJwtSignupSecret, getJwtSignupSecret,
getSiteURL getSiteURL
} from "../../config"; } from "../../config";
import { ActorType } from "../../ee/models";
/** /**
* Password reset step 1: Send email verification link to email [email] * Password reset step 1: Send email verification link to email [email]
@@ -208,8 +209,7 @@ export const changePassword = async (req: Request, res: Response) => {
); );
if ( if (
req.authData.authMode === AUTH_MODE_JWT && req.authData.actor.type === ActorType.USER &&
req.authData.authPayload instanceof User &&
req.authData.tokenVersionId req.authData.tokenVersionId
) { ) {
await clearTokens(req.authData.tokenVersionId); await clearTokens(req.authData.tokenVersionId);
@@ -1,9 +1,12 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import { validateMembership } from "../../helpers"; import { validateMembership } from "../../helpers";
import SecretImport from "../../models/secretImports"; import { Folder, SecretImport } from "../../models";
import { getAllImportedSecrets } from "../../services/SecretImportService"; import { getAllImportedSecrets } from "../../services/SecretImportService";
import { BadRequestError } from "../../utils/errors"; import { BadRequestError, ResourceNotFoundError } from "../../utils/errors";
import { ADMIN, MEMBER } from "../../variables"; import { ADMIN, MEMBER } from "../../variables";
import { EEAuditLogService } from "../../ee/services";
import { EventType } from "../../ee/models";
import { getFolderPath } from "../../services/FolderService";
export const createSecretImport = async (req: Request, res: Response) => { export const createSecretImport = async (req: Request, res: Response) => {
const { workspaceId, environment, folderId, secretImport } = req.body; const { workspaceId, environment, folderId, secretImport } = req.body;
@@ -12,6 +15,17 @@ export const createSecretImport = async (req: Request, res: Response) => {
environment, environment,
folderId folderId
}); });
const folders = await Folder.findOne({
workspace: workspaceId,
environment,
}).lean();
if (!folders) throw ResourceNotFoundError({
message: "Failed to find folder"
});
const importToSecretPath = await getFolderPath(folders, folderId);
if (!importSecDoc) { if (!importSecDoc) {
const doc = new SecretImport({ const doc = new SecretImport({
@@ -20,7 +34,25 @@ export const createSecretImport = async (req: Request, res: Response) => {
folderId, folderId,
imports: [{ environment: secretImport.environment, secretPath: secretImport.secretPath }] imports: [{ environment: secretImport.environment, secretPath: secretImport.secretPath }]
}); });
await doc.save(); await doc.save();
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_SECRET_IMPORT,
metadata: {
secretImportId: doc._id.toString(),
folderId: doc.folderId.toString(),
importFromEnvironment: secretImport.environment,
importFromSecretPath: secretImport.secretPath,
importToEnvironment: environment,
importToSecretPath
}
},
{
workspaceId: doc.workspace
}
);
return res.status(200).json({ message: "successfully created secret import" }); return res.status(200).json({ message: "successfully created secret import" });
} }
@@ -30,11 +62,30 @@ export const createSecretImport = async (req: Request, res: Response) => {
if (doesImportExist) { if (doesImportExist) {
throw BadRequestError({ message: "Secret import already exist" }); throw BadRequestError({ message: "Secret import already exist" });
} }
importSecDoc.imports.push({ importSecDoc.imports.push({
environment: secretImport.environment, environment: secretImport.environment,
secretPath: secretImport.secretPath secretPath: secretImport.secretPath
}); });
await importSecDoc.save(); await importSecDoc.save();
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_SECRET_IMPORT,
metadata: {
secretImportId: importSecDoc._id.toString(),
folderId: importSecDoc.folderId.toString(),
importFromEnvironment: secretImport.environment,
importFromSecretPath: secretImport.secretPath,
importToEnvironment: environment,
importToSecretPath
}
},
{
workspaceId: importSecDoc.workspace
}
);
return res.status(200).json({ message: "successfully created secret import" }); return res.status(200).json({ message: "successfully created secret import" });
}; };
@@ -54,8 +105,39 @@ export const updateSecretImport = async (req: Request, res: Response) => {
acceptedRoles: [ADMIN, MEMBER] acceptedRoles: [ADMIN, MEMBER]
}); });
const orderBefore = importSecDoc.imports;
importSecDoc.imports = secretImports; importSecDoc.imports = secretImports;
await importSecDoc.save(); await importSecDoc.save();
const folders = await Folder.findOne({
workspace: importSecDoc.workspace,
environment: importSecDoc.environment,
}).lean();
if (!folders) throw ResourceNotFoundError({
message: "Failed to find folder"
});
const importToSecretPath = await getFolderPath(folders, importSecDoc.folderId);
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UPDATE_SECRET_IMPORT,
metadata: {
importToEnvironment: importSecDoc.environment,
importToSecretPath,
secretImportId: importSecDoc._id.toString(),
folderId: importSecDoc.folderId.toString(),
orderBefore,
orderAfter: secretImports
}
},
{
workspaceId: importSecDoc.workspace
}
);
return res.status(200).json({ message: "successfully updated secret import" }); return res.status(200).json({ message: "successfully updated secret import" });
}; };
@@ -77,6 +159,36 @@ export const deleteSecretImport = async (req: Request, res: Response) => {
!(environment === secretImportEnv && secretPath === secretImportPath) !(environment === secretImportEnv && secretPath === secretImportPath)
); );
await importSecDoc.save(); await importSecDoc.save();
const folders = await Folder.findOne({
workspace: importSecDoc.workspace,
environment: importSecDoc.environment,
}).lean();
if (!folders) throw ResourceNotFoundError({
message: "Failed to find folder"
});
const importToSecretPath = await getFolderPath(folders, importSecDoc.folderId);
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_SECRET_IMPORT,
metadata: {
secretImportId: importSecDoc._id.toString(),
folderId: importSecDoc.folderId.toString(),
importFromEnvironment: secretImportEnv,
importFromSecretPath: secretImportPath,
importToEnvironment: importSecDoc.environment,
importToSecretPath
}
},
{
workspaceId: importSecDoc.workspace
}
);
return res.status(200).json({ message: "successfully delete secret import" }); return res.status(200).json({ message: "successfully delete secret import" });
}; };
@@ -111,6 +223,22 @@ export const getAllSecretsFromImport = async (req: Request, res: Response) => {
return res.status(200).json({ secrets: [] }); return res.status(200).json({ secrets: [] });
} }
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.GET_SECRET_IMPORTS,
metadata: {
environment,
secretImportId: importSecDoc._id.toString(),
folderId,
numberOfImports: importSecDoc.imports.length
}
},
{
workspaceId: importSecDoc.workspace
}
);
const secrets = await getAllImportedSecrets(workspaceId, environment, folderId); const secrets = await getAllImportedSecrets(workspaceId, environment, folderId);
return res.status(200).json({ secrets }); return res.status(200).json({ secrets });
}; };
@@ -1,5 +1,6 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import { Secret } from "../../models"; import { Secret } from "../../models";
import { Types } from "mongoose";
import Folder from "../../models/folder"; import Folder from "../../models/folder";
import { BadRequestError } from "../../utils/errors"; import { BadRequestError } from "../../utils/errors";
import { import {
@@ -8,6 +9,7 @@ import {
generateFolderId, generateFolderId,
getAllFolderIds, getAllFolderIds,
getFolderByPath, getFolderByPath,
getFolderPath,
getParentFromFolderId, getParentFromFolderId,
searchByFolderId, searchByFolderId,
searchByFolderIdWithDir, searchByFolderIdWithDir,
@@ -15,10 +17,9 @@ import {
} from "../../services/FolderService"; } from "../../services/FolderService";
import { ADMIN, MEMBER } from "../../variables"; import { ADMIN, MEMBER } from "../../variables";
import { validateMembership } from "../../helpers/membership"; import { validateMembership } from "../../helpers/membership";
import { FolderVersion } from "../../ee/models"; import { EventType, FolderVersion } from "../../ee/models";
import { EESecretService } from "../../ee/services"; import { EEAuditLogService, EESecretService } from "../../ee/services";
// TODO
// verify workspace id/environment // verify workspace id/environment
export const createFolder = async (req: Request, res: Response) => { export const createFolder = async (req: Request, res: Response) => {
const { workspaceId, environment, folderName, parentFolderId } = req.body; const { workspaceId, environment, folderName, parentFolderId } = req.body;
@@ -33,6 +34,7 @@ export const createFolder = async (req: Request, res: Response) => {
environment, environment,
}).lean(); }).lean();
// space has no folders initialized // space has no folders initialized
if (!folders) { if (!folders) {
const id = generateFolderId(); const id = generateFolderId();
const folder = new Folder({ const folder = new Folder({
@@ -56,13 +58,32 @@ export const createFolder = async (req: Request, res: Response) => {
workspaceId, workspaceId,
environment, environment,
}); });
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_FOLDER,
metadata: {
environment,
folderId: id,
folderName,
folderPath: `root/${folderName}`
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
return res.json({ folder: { id, name: folderName } }); return res.json({ folder: { id, name: folderName } });
} }
const folder = appendFolder(folders.nodes, { folderName, parentFolderId }); const folder = appendFolder(folders.nodes, { folderName, parentFolderId });
await Folder.findByIdAndUpdate(folders._id, folders); await Folder.findByIdAndUpdate(folders._id, folders);
const parentFolder = searchByFolderId(folders.nodes, parentFolderId); const parentFolder = searchByFolderId(folders.nodes, parentFolderId);
const folderVersion = new FolderVersion({ const folderVersion = new FolderVersion({
workspace: workspaceId, workspace: workspaceId,
environment, environment,
@@ -75,6 +96,24 @@ export const createFolder = async (req: Request, res: Response) => {
environment, environment,
folderId: parentFolderId, folderId: parentFolderId,
}); });
const folderPath = await getFolderPath(folders, folder.id);
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_FOLDER,
metadata: {
environment,
folderId: folder.id,
folderName,
folderPath
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
return res.json({ folder }); return res.json({ folder });
}; };
@@ -87,7 +126,7 @@ export const updateFolderById = async (req: Request, res: Response) => {
if (!folders) { if (!folders) {
throw BadRequestError({ message: "The folder doesn't exist" }); throw BadRequestError({ message: "The folder doesn't exist" });
} }
// check that user is a member of the workspace // check that user is a member of the workspace
await validateMembership({ await validateMembership({
userId: req.user._id.toString(), userId: req.user._id.toString(),
@@ -100,10 +139,12 @@ export const updateFolderById = async (req: Request, res: Response) => {
throw BadRequestError({ message: "The folder doesn't exist" }); throw BadRequestError({ message: "The folder doesn't exist" });
} }
const folder = parentFolder.children.find(({ id }) => id === folderId); const folder = parentFolder.children.find(({ id }) => id === folderId);
if (!folder) { if (!folder) {
throw BadRequestError({ message: "The folder doesn't exist" }); throw BadRequestError({ message: "The folder doesn't exist" });
} }
const oldFolderName = folder.name;
parentFolder.version += 1; parentFolder.version += 1;
folder.name = name; folder.name = name;
@@ -121,6 +162,25 @@ export const updateFolderById = async (req: Request, res: Response) => {
folderId: parentFolder.id, folderId: parentFolder.id,
}); });
const folderPath = await getFolderPath(folders, folder.id);
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UPDATE_FOLDER,
metadata: {
environment,
folderId: folder.id,
oldFolderName,
newFolderName: name,
folderPath
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
return res.json({ return res.json({
message: "Successfully updated folder", message: "Successfully updated folder",
folder: { name: folder.name, id: folder.id }, folder: { name: folder.name, id: folder.id },
@@ -143,6 +203,8 @@ export const deleteFolder = async (req: Request, res: Response) => {
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
}); });
const folderPath = await getFolderPath(folders, folderId);
const delOp = deleteFolderById(folders.nodes, folderId); const delOp = deleteFolderById(folders.nodes, folderId);
if (!delOp) { if (!delOp) {
throw BadRequestError({ message: "The folder doesn't exist" }); throw BadRequestError({ message: "The folder doesn't exist" });
@@ -173,6 +235,22 @@ export const deleteFolder = async (req: Request, res: Response) => {
folderId: parentFolder.id, folderId: parentFolder.id,
}); });
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_FOLDER ,
metadata: {
environment,
folderId,
folderName: delFolder.name,
folderPath
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
res.send({ message: "successfully deleted folders", folders: delFolderIds }); res.send({ message: "successfully deleted folders", folders: delFolderIds });
}; };
@@ -4,7 +4,9 @@ import { client, getRootEncryptionKey } from "../../config";
import { validateMembership } from "../../helpers"; import { validateMembership } from "../../helpers";
import Webhook from "../../models/webhooks"; import Webhook from "../../models/webhooks";
import { getWebhookPayload, triggerWebhookRequest } from "../../services/WebhookService"; import { getWebhookPayload, triggerWebhookRequest } from "../../services/WebhookService";
import { BadRequestError } from "../../utils/errors"; import { BadRequestError, ResourceNotFoundError } from "../../utils/errors";
import { EEAuditLogService } from "../../ee/services";
import { EventType } from "../../ee/models";
import { ADMIN, ALGORITHM_AES_256_GCM, ENCODING_SCHEME_BASE64, MEMBER } from "../../variables"; import { ADMIN, ALGORITHM_AES_256_GCM, ENCODING_SCHEME_BASE64, MEMBER } from "../../variables";
export const createWebhook = async (req: Request, res: Response) => { export const createWebhook = async (req: Request, res: Response) => {
@@ -27,6 +29,23 @@ export const createWebhook = async (req: Request, res: Response) => {
} }
await webhook.save(); await webhook.save();
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_WEBHOOK,
metadata: {
webhookId: webhook._id.toString(),
environment,
secretPath,
webhookUrl,
isDisabled: false
}
},
{
workspaceId
}
);
return res.status(200).send({ return res.status(200).send({
webhook, webhook,
@@ -54,6 +73,23 @@ export const updateWebhook = async (req: Request, res: Response) => {
} }
await webhook.save(); await webhook.save();
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UPDATE_WEBHOOK_STATUS,
metadata: {
webhookId: webhook._id.toString(),
environment: webhook.environment,
secretPath: webhook.secretPath,
webhookUrl: webhook.url,
isDisabled
}
},
{
workspaceId: webhook.workspace
}
);
return res.status(200).send({ return res.status(200).send({
webhook, webhook,
message: "successfully updated webhook" message: "successfully updated webhook"
@@ -62,9 +98,10 @@ export const updateWebhook = async (req: Request, res: Response) => {
export const deleteWebhook = async (req: Request, res: Response) => { export const deleteWebhook = async (req: Request, res: Response) => {
const { webhookId } = req.params; const { webhookId } = req.params;
const webhook = await Webhook.findById(webhookId); let webhook = await Webhook.findById(webhookId);
if (!webhook) { if (!webhook) {
throw BadRequestError({ message: "Webhook not found!!" }); throw ResourceNotFoundError({ message: "Webhook not found!!" });
} }
await validateMembership({ await validateMembership({
@@ -72,8 +109,29 @@ export const deleteWebhook = async (req: Request, res: Response) => {
workspaceId: webhook.workspace, workspaceId: webhook.workspace,
acceptedRoles: [ADMIN, MEMBER] acceptedRoles: [ADMIN, MEMBER]
}); });
webhook = await Webhook.findByIdAndDelete(webhookId);
await webhook.deleteOne(); if (!webhook) {
throw ResourceNotFoundError({ message: "Webhook not found!!" });
}
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_WEBHOOK,
metadata: {
webhookId: webhook._id.toString(),
environment: webhook.environment,
secretPath: webhook.secretPath,
webhookUrl: webhook.url,
isDisabled: webhook.isDisabled
}
},
{
workspaceId: webhook.workspace
}
);
return res.status(200).send({ return res.status(200).send({
message: "successfully removed webhook" message: "successfully removed webhook"
@@ -1,3 +1,4 @@
import { Types } from "mongoose";
import { Request, Response } from "express"; import { Request, Response } from "express";
import { import {
IUser, IUser,
@@ -108,14 +109,14 @@ export const createWorkspace = async (req: Request, res: Response) => {
// validate organization membership // validate organization membership
const membershipOrg = await MembershipOrg.findOne({ const membershipOrg = await MembershipOrg.findOne({
user: req.user._id, user: req.user._id,
organization: organizationId, organization: new Types.ObjectId(organizationId),
}); });
if (!membershipOrg) { if (!membershipOrg) {
throw new Error("Failed to validate organization membership"); throw new Error("Failed to validate organization membership");
} }
const plan = await EELicenseService.getPlan(organizationId); const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId));
if (plan.workspaceLimit !== null) { if (plan.workspaceLimit !== null) {
// case: limit imposed on number of workspaces allowed // case: limit imposed on number of workspaces allowed
@@ -134,7 +135,7 @@ export const createWorkspace = async (req: Request, res: Response) => {
// create workspace and add user as member // create workspace and add user as member
const workspace = await create({ const workspace = await create({
name: workspaceName, name: workspaceName,
organizationId, organizationId: new Types.ObjectId(organizationId),
}); });
await addMemberships({ await addMemberships({
+3 -3
View File
@@ -14,7 +14,7 @@ import {
ACTION_LOGIN, ACTION_LOGIN,
TOKEN_EMAIL_MFA, TOKEN_EMAIL_MFA,
} from "../../variables"; } from "../../variables";
import { getChannelFromUserAgent } from "../../utils/posthog"; // TODO: move this import { getUserAgentType } from "../../utils/posthog"; // TODO: move this
import { import {
getHttpsEnabled, getHttpsEnabled,
getJwtMfaLifetime, getJwtMfaLifetime,
@@ -203,7 +203,7 @@ export const login2 = async (req: Request, res: Response) => {
loginAction && await EELogService.createLog({ loginAction && await EELogService.createLog({
userId: user._id, userId: user._id,
actions: [loginAction], actions: [loginAction],
channel: getChannelFromUserAgent(req.headers["user-agent"]), channel: getUserAgentType(req.headers["user-agent"]),
ipAddress: req.ip, ipAddress: req.ip,
}); });
@@ -336,7 +336,7 @@ export const verifyMfaToken = async (req: Request, res: Response) => {
loginAction && await EELogService.createLog({ loginAction && await EELogService.createLog({
userId: user._id, userId: user._id,
actions: [loginAction], actions: [loginAction],
channel: getChannelFromUserAgent(req.headers["user-agent"]), channel: getUserAgentType(req.headers["user-agent"]),
ipAddress: req.realIP, ipAddress: req.realIP,
}); });
@@ -1,4 +1,5 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import { Types } from "mongoose";
import { import {
Integration, Integration,
Membership, Membership,
@@ -7,8 +8,8 @@ import {
ServiceTokenData, ServiceTokenData,
Workspace, Workspace,
} from "../../models"; } from "../../models";
import { SecretVersion } from "../../ee/models"; import { EventType, SecretVersion } from "../../ee/models";
import { EELicenseService } from "../../ee/services"; import { EEAuditLogService, EELicenseService } from "../../ee/services";
import { BadRequestError, WorkspaceNotFoundError } from "../../utils/errors"; import { BadRequestError, WorkspaceNotFoundError } from "../../utils/errors";
import _ from "lodash"; import _ from "lodash";
import { PERMISSION_READ_SECRETS, PERMISSION_WRITE_SECRETS } from "../../variables"; import { PERMISSION_READ_SECRETS, PERMISSION_WRITE_SECRETS } from "../../variables";
@@ -30,7 +31,7 @@ export const createWorkspaceEnvironment = async (
if (!workspace) throw WorkspaceNotFoundError(); if (!workspace) throw WorkspaceNotFoundError();
const plan = await EELicenseService.getPlan(workspace.organization.toString()); const plan = await EELicenseService.getPlan(workspace.organization);
if (plan.environmentLimit !== null) { if (plan.environmentLimit !== null) {
// case: limit imposed on number of environments allowed // case: limit imposed on number of environments allowed
@@ -58,7 +59,21 @@ export const createWorkspaceEnvironment = async (
}); });
await workspace.save(); await workspace.save();
await EELicenseService.refreshPlan(workspace.organization.toString(), workspaceId); await EELicenseService.refreshPlan(workspace.organization, new Types.ObjectId(workspaceId));
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_ENVIRONMENT,
metadata: {
name: environmentName,
slug: environmentSlug
}
},
{
workspaceId: workspace._id
}
);
return res.status(200).send({ return res.status(200).send({
message: "Successfully created new environment", message: "Successfully created new environment",
@@ -109,6 +124,8 @@ export const renameWorkspaceEnvironment = async (
if (envIndex === -1) { if (envIndex === -1) {
throw new Error("Invalid environment given"); throw new Error("Invalid environment given");
} }
const oldEnvironment = workspace.environments[envIndex];
workspace.environments[envIndex].name = environmentName; workspace.environments[envIndex].name = environmentName;
workspace.environments[envIndex].slug = environmentSlug.toLowerCase(); workspace.environments[envIndex].slug = environmentSlug.toLowerCase();
@@ -141,8 +158,23 @@ export const renameWorkspaceEnvironment = async (
}, },
{ $set: { "deniedPermissions.$[element].environmentSlug": environmentSlug } }, { $set: { "deniedPermissions.$[element].environmentSlug": environmentSlug } },
{ arrayFilters: [{ "element.environmentSlug": oldEnvironmentSlug }] } { arrayFilters: [{ "element.environmentSlug": oldEnvironmentSlug }] }
) );
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UPDATE_ENVIRONMENT,
metadata: {
oldName: oldEnvironment.name,
newName: environmentName,
oldSlug: oldEnvironment.slug,
newSlug: environmentSlug.toLowerCase()
}
},
{
workspaceId: workspace._id
}
);
return res.status(200).send({ return res.status(200).send({
message: "Successfully update environment", message: "Successfully update environment",
@@ -178,6 +210,8 @@ export const deleteWorkspaceEnvironment = async (
if (envIndex === -1) { if (envIndex === -1) {
throw new Error("Invalid environment given"); throw new Error("Invalid environment given");
} }
const oldEnvironment = workspace.environments[envIndex];
workspace.environments.splice(envIndex, 1); workspace.environments.splice(envIndex, 1);
await workspace.save(); await workspace.save();
@@ -215,7 +249,21 @@ export const deleteWorkspaceEnvironment = async (
{ $pull: { deniedPermissions: { environmentSlug: environmentSlug } } } { $pull: { deniedPermissions: { environmentSlug: environmentSlug } } }
); );
await EELicenseService.refreshPlan(workspace.organization.toString(), workspaceId); await EELicenseService.refreshPlan(workspace.organization, new Types.ObjectId(workspaceId));
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_ENVIRONMENT,
metadata: {
name: oldEnvironment.name,
slug: oldEnvironment.slug
}
},
{
workspaceId: workspace._id
}
);
return res.status(200).send({ return res.status(200).send({
message: "Successfully deleted environment", message: "Successfully deleted environment",
+118 -15
View File
@@ -1,7 +1,7 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { Request, Response } from "express"; import { Request, Response } from "express";
import { ISecret, Secret, ServiceTokenData } from "../../models"; import { ISecret, Secret, ServiceTokenData } from "../../models";
import { IAction, SecretVersion } from "../../ee/models"; import { IAction, SecretVersion, EventType, AuditLog } from "../../ee/models";
import { import {
ACTION_ADD_SECRETS, ACTION_ADD_SECRETS,
ACTION_DELETE_SECRETS, ACTION_DELETE_SECRETS,
@@ -14,9 +14,9 @@ import {
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors"; import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
import { EventService } from "../../services"; import { EventService } from "../../services";
import { eventPushSecrets } from "../../events"; import { eventPushSecrets } from "../../events";
import { EELogService, EESecretService } from "../../ee/services"; import { EELogService, EESecretService, EEAuditLogService } from "../../ee/services";
import { SecretService, TelemetryService } from "../../services"; import { SecretService, TelemetryService } from "../../services";
import { getChannelFromUserAgent } from "../../utils/posthog"; import { getUserAgentType } from "../../utils/posthog";
import { PERMISSION_WRITE_SECRETS } from "../../variables"; import { PERMISSION_WRITE_SECRETS } from "../../variables";
import { import {
userHasNoAbility, userHasNoAbility,
@@ -44,7 +44,7 @@ import { getAllImportedSecrets } from "../../services/SecretImportService";
* @param res * @param res
*/ */
export const batchSecrets = async (req: Request, res: Response) => { export const batchSecrets = async (req: Request, res: Response) => {
const channel = getChannelFromUserAgent(req.headers["user-agent"]); const channel = getUserAgentType(req.headers["user-agent"]);
const postHogClient = await TelemetryService.getPostHogClient(); const postHogClient = await TelemetryService.getPostHogClient();
const { const {
@@ -56,12 +56,13 @@ export const batchSecrets = async (req: Request, res: Response) => {
environment: string; environment: string;
requests: BatchSecretRequest[]; requests: BatchSecretRequest[];
} = req.body; } = req.body;
let secretPath = req.body.secretPath as string; let secretPath = req.body.secretPath as string;
let folderId = req.body.folderId as string; let folderId = req.body.folderId as string;
const createSecrets: BatchSecret[] = []; const createSecrets: BatchSecret[] = [];
const updateSecrets: BatchSecret[] = []; const updateSecrets: BatchSecret[] = [];
const deleteSecrets: Types.ObjectId[] = []; const deleteSecrets: { _id: Types.ObjectId, secretName: string; }[] = [];
const actions: IAction[] = []; const actions: IAction[] = [];
// get secret blind index salt // get secret blind index salt
@@ -133,7 +134,7 @@ export const batchSecrets = async (req: Request, res: Response) => {
}); });
break; break;
case "DELETE": case "DELETE":
deleteSecrets.push(new Types.ObjectId(request.secret._id)); deleteSecrets.push({ _id: new Types.ObjectId(request.secret._id), secretName: request.secret.secretName });
break; break;
} }
} }
@@ -153,7 +154,31 @@ export const batchSecrets = async (req: Request, res: Response) => {
}; };
}) })
}); });
const auditLogs = await Promise.all(
createdSecrets.map((secret, index) => {
return EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_SECRET,
metadata: {
environment: secret.environment,
secretPath: secretPath ?? "/",
secretId: secret._id.toString(),
secretKey: createSecrets[index].secretName,
secretVersion: secret.version
}
},
{
workspaceId: secret.workspace
},
false
);
})
);
await AuditLog.insertMany(auditLogs);
const addAction = (await EELogService.createAction({ const addAction = (await EELogService.createAction({
name: ACTION_ADD_SECRETS, name: ACTION_ADD_SECRETS,
userId: req.user?._id, userId: req.user?._id,
@@ -252,6 +277,30 @@ export const batchSecrets = async (req: Request, res: Response) => {
$in: updateSecrets.map((u) => new Types.ObjectId(u._id)) $in: updateSecrets.map((u) => new Types.ObjectId(u._id))
} }
}); });
const auditLogs = await Promise.all(
updateSecrets.map((secret) => {
return EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UPDATE_SECRET,
metadata: {
environment,
secretPath: secretPath ?? "/",
secretId: secret._id.toString(),
secretKey: secret.secretName,
secretVersion: listedSecretsObj[secret._id.toString()].version
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
},
false
);
})
);
await AuditLog.insertMany(auditLogs);
const updateAction = (await EELogService.createAction({ const updateAction = (await EELogService.createAction({
name: ACTION_UPDATE_SECRETS, name: ACTION_UPDATE_SECRETS,
@@ -279,21 +328,60 @@ export const batchSecrets = async (req: Request, res: Response) => {
// handle delete secrets // handle delete secrets
if (deleteSecrets.length > 0) { if (deleteSecrets.length > 0) {
const deleteSecretIds: Types.ObjectId[] = deleteSecrets.map((s) => s._id);
const deletedSecretsObj = (await Secret.find({
_id: {
$in: deleteSecretIds
}
}))
.reduce(
(obj: any, secret: ISecret) => ({
...obj,
[secret._id.toString()]: secret
}),
{}
);
await Secret.deleteMany({ await Secret.deleteMany({
_id: { _id: {
$in: deleteSecrets $in: deleteSecretIds
} }
}); });
await EESecretService.markDeletedSecretVersions({ await EESecretService.markDeletedSecretVersions({
secretIds: deleteSecrets secretIds: deleteSecretIds
}); });
const auditLogs = await Promise.all(
deleteSecrets.map((secret) => {
return EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_SECRET,
metadata: {
environment,
secretPath: secretPath ?? "/",
secretId: secret._id.toString(),
secretKey: secret.secretName,
secretVersion: deletedSecretsObj[secret._id.toString()].version
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
},
false
);
})
);
await AuditLog.insertMany(auditLogs);
const deleteAction = (await EELogService.createAction({ const deleteAction = (await EELogService.createAction({
name: ACTION_DELETE_SECRETS, name: ACTION_DELETE_SECRETS,
userId: req.user._id, userId: req.user._id,
workspaceId: new Types.ObjectId(workspaceId), workspaceId: new Types.ObjectId(workspaceId),
secretIds: deleteSecrets secretIds: deleteSecretIds
})) as IAction; })) as IAction;
actions.push(deleteAction); actions.push(deleteAction);
@@ -351,7 +439,7 @@ export const batchSecrets = async (req: Request, res: Response) => {
} }
if (deleteSecrets.length > 0) { if (deleteSecrets.length > 0) {
resObj["deletedSecrets"] = deleteSecrets.map((d) => d.toString()); resObj["deletedSecrets"] = deleteSecrets.map((d) => d._id.toString());
} }
return res.status(200).send(resObj); return res.status(200).send(resObj);
@@ -416,7 +504,7 @@ export const createSecrets = async (req: Request, res: Response) => {
} }
*/ */
const channel = getChannelFromUserAgent(req.headers["user-agent"]); const channel = getUserAgentType(req.headers["user-agent"]);
const { const {
workspaceId, workspaceId,
environment, environment,
@@ -834,7 +922,7 @@ export const getSecrets = async (req: Request, res: Response) => {
importedSecrets = await getAllImportedSecrets(workspaceId, environment, folderId as string); importedSecrets = await getAllImportedSecrets(workspaceId, environment, folderId as string);
} }
const channel = getChannelFromUserAgent(req.headers["user-agent"]); const channel = getUserAgentType(req.headers["user-agent"]);
const readAction = await EELogService.createAction({ const readAction = await EELogService.createAction({
name: ACTION_READ_SECRETS, name: ACTION_READ_SECRETS,
@@ -855,6 +943,21 @@ export const getSecrets = async (req: Request, res: Response) => {
channel, channel,
ipAddress: req.realIP ipAddress: req.realIP
})); }));
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.GET_SECRETS,
metadata: {
environment,
secretPath: secretPath as string,
numberOfSecrets: secrets.length
}
},
{
workspaceId: new Types.ObjectId(workspaceId as string)
}
);
const postHogClient = await TelemetryService.getPostHogClient(); const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) { if (postHogClient) {
@@ -1170,7 +1273,7 @@ export const deleteSecrets = async (req: Request, res: Response) => {
} }
*/ */
const channel = getChannelFromUserAgent(req.headers["user-agent"]); const channel = getUserAgentType(req.headers["user-agent"]);
const toDelete = req.secrets.map((s: any) => s._id); const toDelete = req.secrets.map((s: any) => s._id);
await Secret.deleteMany({ await Secret.deleteMany({
@@ -1,10 +1,11 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import crypto from "crypto"; import crypto from "crypto";
import bcrypt from "bcrypt"; import bcrypt from "bcrypt";
import { ServiceAccount, ServiceTokenData, User } from "../../models"; import { ServiceTokenData } from "../../models";
import { AUTH_MODE_JWT, AUTH_MODE_SERVICE_ACCOUNT } from "../../variables";
import { getSaltRounds } from "../../config"; import { getSaltRounds } from "../../config";
import { BadRequestError } from "../../utils/errors"; import { BadRequestError } from "../../utils/errors";
import { ActorType, EventType } from "../../ee/models";
import { EEAuditLogService } from "../../ee/services";
/** /**
* Return service token data associated with service token on request * Return service token data associated with service token on request
@@ -73,24 +74,16 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn); expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);
} }
let user, serviceAccount; let user;
if (req.authData.authMode === AUTH_MODE_JWT && req.authData.authPayload instanceof User) { if (req.authData.actor.type === ActorType.USER) {
user = req.authData.authPayload._id; user = req.authData.authPayload._id;
} }
if (
req.authData.authMode === AUTH_MODE_SERVICE_ACCOUNT &&
req.authData.authPayload instanceof ServiceAccount
) {
serviceAccount = req.authData.authPayload._id;
}
serviceTokenData = await new ServiceTokenData({ serviceTokenData = await new ServiceTokenData({
name, name,
workspace: workspaceId, workspace: workspaceId,
user, user,
serviceAccount,
scopes, scopes,
lastUsed: new Date(), lastUsed: new Date(),
expiresAt, expiresAt,
@@ -107,6 +100,20 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
if (!serviceTokenData) throw new Error("Failed to find service token data"); if (!serviceTokenData) throw new Error("Failed to find service token data");
const serviceToken = `st.${serviceTokenData._id.toString()}.${secret}`; const serviceToken = `st.${serviceTokenData._id.toString()}.${secret}`;
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_SERVICE_TOKEN,
metadata: {
name,
scopes
}
},
{
workspaceId
}
);
return res.status(200).send({ return res.status(200).send({
serviceToken, serviceToken,
@@ -124,6 +131,24 @@ export const deleteServiceTokenData = async (req: Request, res: Response) => {
const { serviceTokenDataId } = req.params; const { serviceTokenDataId } = req.params;
const serviceTokenData = await ServiceTokenData.findByIdAndDelete(serviceTokenDataId); const serviceTokenData = await ServiceTokenData.findByIdAndDelete(serviceTokenDataId);
if (!serviceTokenData) return res.status(200).send({
message: "Failed to delete service token"
});
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_SERVICE_TOKEN,
metadata: {
name: serviceTokenData.name,
scopes: serviceTokenData?.scopes
}
},
{
workspaceId: serviceTokenData.workspace
}
);
return res.status(200).send({ return res.status(200).send({
serviceTokenData serviceTokenData
@@ -9,6 +9,8 @@ import {
import { pushKeys } from "../../helpers/key"; import { pushKeys } from "../../helpers/key";
import { EventService, TelemetryService } from "../../services"; import { EventService, TelemetryService } from "../../services";
import { eventPushSecrets } from "../../events"; import { eventPushSecrets } from "../../events";
import { EEAuditLogService } from "../../ee/services";
import { EventType } from "../../ee/models";
interface V2PushSecret { interface V2PushSecret {
type: string; // personal or shared type: string; // personal or shared
@@ -180,16 +182,30 @@ export const getWorkspaceKey = async (req: Request, res: Response) => {
} }
*/ */
const { workspaceId } = req.params; const { workspaceId } = req.params;
const key = await Key.findOne({ const key = await Key.findOne({
workspace: workspaceId, workspace: workspaceId,
receiver: req.user._id receiver: req.user._id
}).populate("sender", "+publicKey"); }).populate("sender", "+publicKey");
if (!key) throw new Error("Failed to find workspace key"); if (!key) throw new Error("Failed to find workspace key");
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.GET_WORKSPACE_KEY,
metadata: {
keyId: key._id.toString()
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
return res.status(200).json(key); return res.status(200).json(key);
}; };
export const getWorkspaceServiceTokenData = async (req: Request, res: Response) => { export const getWorkspaceServiceTokenData = async (req: Request, res: Response) => {
const { workspaceId } = req.params; const { workspaceId } = req.params;
+2 -2
View File
@@ -15,7 +15,7 @@ import {
ACTION_LOGIN, ACTION_LOGIN,
TOKEN_EMAIL_MFA, TOKEN_EMAIL_MFA,
} from "../../variables"; } from "../../variables";
import { getChannelFromUserAgent } from "../../utils/posthog"; // TODO: move this import { getUserAgentType } from "../../utils/posthog"; // TODO: move this
import { import {
getHttpsEnabled, getHttpsEnabled,
getJwtMfaLifetime, getJwtMfaLifetime,
@@ -241,7 +241,7 @@ export const login2 = async (req: Request, res: Response) => {
loginAction && await EELogService.createLog({ loginAction && await EELogService.createLog({
userId: user._id, userId: user._id,
actions: [loginAction], actions: [loginAction],
channel: getChannelFromUserAgent(req.headers["user-agent"]), channel: getUserAgentType(req.headers["user-agent"]),
ipAddress: req.realIP, ipAddress: req.realIP,
}); });
@@ -1,3 +1,4 @@
import { Types } from "mongoose";
import { Request, Response } from "express"; import { Request, Response } from "express";
import { getLicenseServerUrl } from "../../../config"; import { getLicenseServerUrl } from "../../../config";
import { licenseServerKeyRequest } from "../../../config/request"; import { licenseServerKeyRequest } from "../../../config/request";
@@ -20,7 +21,7 @@ export const getOrganizationPlan = async (req: Request, res: Response) => {
const { organizationId } = req.params; const { organizationId } = req.params;
const workspaceId = req.query.workspaceId as string; const workspaceId = req.query.workspaceId as string;
const plan = await EELicenseService.getPlan(organizationId, workspaceId); const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId), new Types.ObjectId(workspaceId));
return res.status(200).send({ return res.status(200).send({
plan, plan,
@@ -44,7 +45,7 @@ export const startOrganizationTrial = async (req: Request, res: Response) => {
} }
); );
EELicenseService.delPlan(organizationId); EELicenseService.delPlan(new Types.ObjectId(organizationId));
return res.status(200).send({ return res.status(200).send({
url url
@@ -59,7 +59,7 @@ export const updateSSOConfig = async (req: Request, res: Response) => {
cert, cert,
} = req.body; } = req.body;
const plan = await EELicenseService.getPlan(organizationId); const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId));
if (!plan.samlSSO) return res.status(400).send({ if (!plan.samlSSO) return res.status(400).send({
message: "Failed to update SAML SSO configuration due to plan restriction. Upgrade plan to update SSO configuration." message: "Failed to update SAML SSO configuration due to plan restriction. Upgrade plan to update SSO configuration."
@@ -194,7 +194,7 @@ export const createSSOConfig = async (req: Request, res: Response) => {
cert cert
} = req.body; } = req.body;
const plan = await EELicenseService.getPlan(organizationId); const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId));
if (!plan.samlSSO) return res.status(400).send({ if (!plan.samlSSO) return res.status(400).send({
message: "Failed to create SAML SSO configuration due to plan restriction. Upgrade plan to add SSO configuration." message: "Failed to create SAML SSO configuration due to plan restriction. Upgrade plan to add SSO configuration."
@@ -8,6 +8,6 @@ import { Request, Response } from "express";
*/ */
export const getMyIp = (req: Request, res: Response) => { export const getMyIp = (req: Request, res: Response) => {
return res.status(200).send({ return res.status(200).send({
ip: req.authData.authIP ip: req.authData.ipAddress
}); });
} }
@@ -1,21 +1,26 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import { PipelineStage, Types } from "mongoose"; import { PipelineStage, Types } from "mongoose";
import { Secret } from "../../../models"; import { Membership, Secret, ServiceTokenData, User } from "../../../models";
import { import {
ActorType,
AuditLog,
EventType,
FolderVersion, FolderVersion,
IPType, IPType,
ISecretVersion, ISecretVersion,
Log, Log,
SecretSnapshot, SecretSnapshot,
SecretVersion, SecretVersion,
ServiceActor,
TFolderRootVersionSchema, TFolderRootVersionSchema,
TrustedIP TrustedIP,
UserActor
} from "../../models"; } from "../../models";
import { EESecretService } from "../../services"; import { EESecretService } from "../../services";
import { getLatestSecretVersionIds } from "../../helpers/secretVersion"; import { getLatestSecretVersionIds } from "../../helpers/secretVersion";
import Folder, { TFolderSchema } from "../../../models/folder"; import Folder, { TFolderSchema } from "../../../models/folder";
import { searchByFolderId } from "../../../services/FolderService"; import { searchByFolderId } from "../../../services/FolderService";
import { EELicenseService } from "../../services"; import { EEAuditLogService, EELicenseService } from "../../services";
import { extractIPDetails, isValidIpOrCidr } from "../../../utils/ip"; import { extractIPDetails, isValidIpOrCidr } from "../../../utils/ip";
/** /**
@@ -593,6 +598,101 @@ export const getWorkspaceLogs = async (req: Request, res: Response) => {
}); });
}; };
/**
* Return audit logs for workspace with id [workspaceId]
* @param req
* @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 = {
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);
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
*/
export const getWorkspaceAuditLogActorFilterOpts = async (req: Request, res: Response) => {
const { workspaceId } = req.params;
const userIds = await Membership.distinct("user", {
workspace: new Types.ObjectId(workspaceId)
});
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) => ({
type: ActorType.SERVICE,
metadata: {
serviceId: serviceTokenData._id.toString(),
name: serviceTokenData.name
}
}));
return res.status(200).send({
actors: [...userActors, ...serviceActors]
});
}
/** /**
* Return trusted ips for workspace with id [workspaceId] * Return trusted ips for workspace with id [workspaceId]
* @param req * @param req
@@ -623,7 +723,7 @@ export const addWorkspaceTrustedIp = async (req: Request, res: Response) => {
isActive isActive
} = req.body; } = req.body;
const plan = await EELicenseService.getPlan(req.workspace.organization.toString()); const plan = await EELicenseService.getPlan(req.workspace.organization);
if (!plan.ipAllowlisting) return res.status(400).send({ 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." message: "Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range."
@@ -645,6 +745,21 @@ export const addWorkspaceTrustedIp = async (req: Request, res: Response) => {
isActive, isActive,
comment, comment,
}).save(); }).save();
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.ADD_TRUSTED_IP,
metadata: {
trustedIpId: trustedIp._id.toString(),
ipAddress: trustedIp.ipAddress,
prefix: trustedIp.prefix
}
},
{
workspaceId: trustedIp.workspace
}
);
return res.status(200).send({ return res.status(200).send({
trustedIp trustedIp
@@ -663,7 +778,7 @@ export const updateWorkspaceTrustedIp = async (req: Request, res: Response) => {
comment comment
} = req.body; } = req.body;
const plan = await EELicenseService.getPlan(req.workspace.organization.toString()); const plan = await EELicenseService.getPlan(req.workspace.organization);
if (!plan.ipAllowlisting) return res.status(400).send({ 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." message: "Failed to update IP access range due to plan restriction. Upgrade plan to update IP access range."
@@ -708,6 +823,25 @@ export const updateWorkspaceTrustedIp = async (req: Request, res: Response) => {
} }
); );
if (!trustedIp) return res.status(400).send({
message: "Failed to update trusted IP"
});
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UPDATE_TRUSTED_IP,
metadata: {
trustedIpId: trustedIp._id.toString(),
ipAddress: trustedIp.ipAddress,
prefix: trustedIp.prefix
}
},
{
workspaceId: trustedIp.workspace
}
);
return res.status(200).send({ return res.status(200).send({
trustedIp trustedIp
}); });
@@ -721,7 +855,7 @@ export const updateWorkspaceTrustedIp = async (req: Request, res: Response) => {
export const deleteWorkspaceTrustedIp = async (req: Request, res: Response) => { export const deleteWorkspaceTrustedIp = async (req: Request, res: Response) => {
const { workspaceId, trustedIpId } = req.params; const { workspaceId, trustedIpId } = req.params;
const plan = await EELicenseService.getPlan(req.workspace.organization.toString()); const plan = await EELicenseService.getPlan(req.workspace.organization);
if (!plan.ipAllowlisting) return res.status(400).send({ 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." message: "Failed to delete IP access range due to plan restriction. Upgrade plan to delete IP access range."
@@ -731,6 +865,25 @@ export const deleteWorkspaceTrustedIp = async (req: Request, res: Response) => {
_id: new Types.ObjectId(trustedIpId), _id: new Types.ObjectId(trustedIpId),
workspace: new Types.ObjectId(workspaceId) workspace: new Types.ObjectId(workspaceId)
}); });
if (!trustedIp) return res.status(400).send({
message: "Failed to delete trusted IP"
});
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_TRUSTED_IP,
metadata: {
trustedIpId: trustedIp._id.toString(),
ipAddress: trustedIp.ipAddress,
prefix: trustedIp.prefix
}
},
{
workspaceId: trustedIp.workspace
}
);
return res.status(200).send({ return res.status(200).send({
trustedIp trustedIp
@@ -0,0 +1,76 @@
import { Schema, Types, model } from "mongoose";
import {
ActorType,
EventType,
UserAgentType
} from "./enums";
import {
Actor,
Event
} from "./types";
export interface IAuditLog {
actor: Actor;
organization: Types.ObjectId;
workspace: Types.ObjectId;
ipAddress: string;
event: Event;
userAgent: string;
userAgentType: UserAgentType;
expiresAt: Date;
}
const auditLogSchema = new Schema<IAuditLog>(
{
actor: {
type: {
type: String,
enum: ActorType,
required: true
},
metadata: {
type: Schema.Types.Mixed
}
},
organization: {
type: Schema.Types.ObjectId,
required: false
},
workspace: {
type: Schema.Types.ObjectId,
required: false
},
ipAddress: {
type: String,
required: true
},
event: {
type: {
type: String,
enum: EventType,
required: true
},
metadata: {
type: Schema.Types.Mixed
}
},
userAgent: {
type: String,
required: true
},
userAgentType: {
type: String,
enum: UserAgentType,
required: true
},
expiresAt: {
type: Date,
expires: 0
}
},
{
timestamps: true
}
);
export const AuditLog = model<IAuditLog>("AuditLog", auditLogSchema);
+45
View File
@@ -0,0 +1,45 @@
export enum ActorType {
USER = "user",
SERVICE = "service"
}
export enum UserAgentType {
WEB = "web",
CLI = "cli",
K8_OPERATOR = "k8-operator",
OTHER = "other"
}
export enum EventType {
GET_SECRETS = "get-secrets",
GET_SECRET = "get-secret",
REVEAL_SECRET = "reveal-secret",
CREATE_SECRET = "create-secret",
UPDATE_SECRET = "update-secret",
DELETE_SECRET = "delete-secret",
GET_WORKSPACE_KEY = "get-workspace-key",
AUTHORIZE_INTEGRATION = "authorize-integration",
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
CREATE_INTEGRATION = "create-integration",
DELETE_INTEGRATION = "delete-integration",
ADD_TRUSTED_IP = "add-trusted-ip",
UPDATE_TRUSTED_IP = "update-trusted-ip",
DELETE_TRUSTED_IP = "delete-trusted-ip",
CREATE_SERVICE_TOKEN = "create-service-token",
DELETE_SERVICE_TOKEN = "delete-service-token",
CREATE_ENVIRONMENT = "create-environment",
UPDATE_ENVIRONMENT = "update-environment",
DELETE_ENVIRONMENT = "delete-environment",
ADD_WORKSPACE_MEMBER = "add-workspace-member",
REMOVE_WORKSPACE_MEMBER = "remove-workspace-member",
CREATE_FOLDER = "create-folder",
UPDATE_FOLDER = "update-folder",
DELETE_FOLDER = "delete-folder",
CREATE_WEBHOOK = "create-webhook",
UPDATE_WEBHOOK_STATUS = "update-webhook-status",
DELETE_WEBHOOK = "delete-webhook",
GET_SECRET_IMPORTS = "get-secret-imports",
CREATE_SECRET_IMPORT = "create-secret-import",
UPDATE_SECRET_IMPORT = "update-secret-import",
DELETE_SECRET_IMPORT = "delete-secret-import",
}
+3
View File
@@ -0,0 +1,3 @@
export * from "./auditLog";
export * from "./enums";
export * from "./types";
+379
View File
@@ -0,0 +1,379 @@
import {
ActorType,
EventType
} from "./enums";
interface UserActorMetadata {
userId: string;
email: string;
}
interface ServiceActorMetadata {
serviceId: string;
name: string;
}
export interface UserActor {
type: ActorType.USER;
metadata: UserActorMetadata;
}
export interface ServiceActor {
type: ActorType.SERVICE;
metadata: ServiceActorMetadata;
}
export type Actor =
| UserActor
| ServiceActor;
interface GetSecretsEvent {
type: EventType.GET_SECRETS;
metadata: {
environment: string;
secretPath: string;
numberOfSecrets: number;
};
}
interface GetSecretEvent {
type: EventType.GET_SECRET;
metadata: {
environment: string;
secretPath: string;
secretId: string;
secretKey: string;
secretVersion: number;
};
}
interface CreateSecretEvent {
type: EventType.CREATE_SECRET;
metadata: {
environment: string;
secretPath: string;
secretId: string;
secretKey: string;
secretVersion: number;
}
}
interface UpdateSecretEvent {
type: EventType.UPDATE_SECRET;
metadata: {
environment: string;
secretPath: string;
secretId: string;
secretKey: string;
secretVersion: number;
}
}
interface DeleteSecretEvent {
type: EventType.DELETE_SECRET;
metadata: {
environment: string;
secretPath: string;
secretId: string;
secretKey: string;
secretVersion: number;
}
}
interface GetWorkspaceKeyEvent {
type: EventType.GET_WORKSPACE_KEY,
metadata: {
keyId: string;
}
}
interface AuthorizeIntegrationEvent {
type: EventType.AUTHORIZE_INTEGRATION;
metadata: {
integration: string;
}
}
interface UnauthorizeIntegrationEvent {
type: EventType.UNAUTHORIZE_INTEGRATION;
metadata: {
integration: string;
}
}
interface CreateIntegrationEvent {
type: EventType.CREATE_INTEGRATION;
metadata: {
integrationId: string;
integration: string; // TODO: fix type
environment: string;
secretPath: string;
url?: string;
app?: string;
appId?: string;
targetEnvironment?: string;
targetEnvironmentId?: string;
targetService?: string;
targetServiceId?: string;
path?: string;
region?: string;
}
}
interface DeleteIntegrationEvent {
type: EventType.DELETE_INTEGRATION;
metadata: {
integrationId: string;
integration: string; // TODO: fix type
environment: string;
secretPath: string;
url?: string;
app?: string;
appId?: string;
targetEnvironment?: string;
targetEnvironmentId?: string;
targetService?: string;
targetServiceId?: string;
path?: string;
region?: string;
}
}
interface AddTrustedIPEvent {
type: EventType.ADD_TRUSTED_IP;
metadata: {
trustedIpId: string;
ipAddress: string;
prefix?: number;
}
}
interface UpdateTrustedIPEvent {
type: EventType.UPDATE_TRUSTED_IP;
metadata: {
trustedIpId: string;
ipAddress: string;
prefix?: number;
}
}
interface DeleteTrustedIPEvent {
type: EventType.DELETE_TRUSTED_IP;
metadata: {
trustedIpId: string;
ipAddress: string;
prefix?: number;
}
}
interface CreateServiceTokenEvent {
type: EventType.CREATE_SERVICE_TOKEN;
metadata: {
name: string;
scopes: Array<{
environment: string;
secretPath: string;
}>;
}
}
interface DeleteServiceTokenEvent {
type: EventType.DELETE_SERVICE_TOKEN;
metadata: {
name: string;
scopes: Array<{
environment: string;
secretPath: string;
}>;
}
}
interface CreateEnvironmentEvent {
type: EventType.CREATE_ENVIRONMENT;
metadata: {
name: string;
slug: string;
}
}
interface UpdateEnvironmentEvent {
type: EventType.UPDATE_ENVIRONMENT;
metadata: {
oldName: string;
newName: string;
oldSlug: string;
newSlug: string;
}
}
interface DeleteEnvironmentEvent {
type: EventType.DELETE_ENVIRONMENT;
metadata: {
name: string;
slug: string;
}
}
interface AddWorkspaceMemberEvent {
type: EventType.ADD_WORKSPACE_MEMBER;
metadata: {
userId: string;
email: string;
}
}
interface RemoveWorkspaceMemberEvent {
type: EventType.REMOVE_WORKSPACE_MEMBER;
metadata: {
userId: string;
email: string;
}
}
interface CreateFolderEvent {
type: EventType.CREATE_FOLDER;
metadata: {
environment: string;
folderId: string;
folderName: string;
folderPath: string;
}
}
interface UpdateFolderEvent {
type: EventType.UPDATE_FOLDER;
metadata: {
environment: string;
folderId: string;
oldFolderName: string;
newFolderName: string;
folderPath: string;
}
}
interface DeleteFolderEvent {
type: EventType.DELETE_FOLDER;
metadata: {
environment: string;
folderId: string;
folderName: string;
folderPath: string;
}
}
interface CreateWebhookEvent {
type: EventType.CREATE_WEBHOOK,
metadata: {
webhookId: string;
environment: string;
secretPath: string;
webhookUrl: string;
isDisabled: boolean;
}
}
interface UpdateWebhookStatusEvent {
type: EventType.UPDATE_WEBHOOK_STATUS,
metadata: {
webhookId: string;
environment: string;
secretPath: string;
webhookUrl: string;
isDisabled: boolean;
}
}
interface DeleteWebhookEvent {
type: EventType.DELETE_WEBHOOK,
metadata: {
webhookId: string;
environment: string;
secretPath: string;
webhookUrl: string;
isDisabled: boolean;
}
}
interface GetSecretImportsEvent {
type: EventType.GET_SECRET_IMPORTS,
metadata: {
environment: string;
secretImportId: string;
folderId: string;
numberOfImports: number;
}
}
interface CreateSecretImportEvent {
type: EventType.CREATE_SECRET_IMPORT,
metadata: {
secretImportId: string;
folderId: string;
importFromEnvironment: string;
importFromSecretPath: string;
importToEnvironment: string;
importToSecretPath: string;
}
}
interface UpdateSecretImportEvent {
type: EventType.UPDATE_SECRET_IMPORT,
metadata: {
secretImportId: string;
folderId: string;
importToEnvironment: string;
importToSecretPath: string;
orderBefore: {
environment: string;
secretPath: string;
}[],
orderAfter: {
environment: string;
secretPath: string;
}[]
}
}
interface DeleteSecretImportEvent {
type: EventType.DELETE_SECRET_IMPORT,
metadata: {
secretImportId: string;
folderId: string;
importFromEnvironment: string;
importFromSecretPath: string;
importToEnvironment: string;
importToSecretPath: string;
}
}
export type Event =
| GetSecretsEvent
| GetSecretEvent
| CreateSecretEvent
| UpdateSecretEvent
| DeleteSecretEvent
| GetWorkspaceKeyEvent
| AuthorizeIntegrationEvent
| UnauthorizeIntegrationEvent
| CreateIntegrationEvent
| DeleteIntegrationEvent
| AddTrustedIPEvent
| UpdateTrustedIPEvent
| DeleteTrustedIPEvent
| CreateServiceTokenEvent
| DeleteServiceTokenEvent
| CreateEnvironmentEvent
| UpdateEnvironmentEvent
| DeleteEnvironmentEvent
| AddWorkspaceMemberEvent
| RemoveWorkspaceMemberEvent
| CreateFolderEvent
| UpdateFolderEvent
| DeleteFolderEvent
| CreateWebhookEvent
| UpdateWebhookStatusEvent
| DeleteWebhookEvent
| GetSecretImportsEvent
| CreateSecretImportEvent
| UpdateSecretImportEvent
| DeleteSecretImportEvent;
+1
View File
@@ -5,6 +5,7 @@ export * from "./log";
export * from "./action"; export * from "./action";
export * from "./ssoConfig"; export * from "./ssoConfig";
export * from "./trustedIp"; export * from "./trustedIp";
export * from "./auditLog";
export * from "./gitRisks"; export * from "./gitRisks";
export * from "./gitAppOrganizationInstallation"; export * from "./gitAppOrganizationInstallation";
export * from "./gitAppInstallationSession"; export * from "./gitAppInstallationSession";
+2 -1
View File
@@ -6,11 +6,12 @@ import {
} from "../../../middleware"; } from "../../../middleware";
import { query } from "express-validator"; import { query } from "express-validator";
import { cloudProductsController } from "../../controllers/v1"; import { cloudProductsController } from "../../controllers/v1";
import { AuthMode } from "../../../variables";
router.get( router.get(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt", "apiKey"], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
query("billing-cycle").exists().isIn(["monthly", "yearly"]), query("billing-cycle").exists().isIn(["monthly", "yearly"]),
validateRequest, validateRequest,
+16 -16
View File
@@ -8,13 +8,13 @@ import {
import { body, param, query } from "express-validator"; import { body, param, query } from "express-validator";
import { organizationsController } from "../../controllers/v1"; import { organizationsController } from "../../controllers/v1";
import { import {
ACCEPTED, ADMIN, MEMBER, OWNER, ACCEPTED, ADMIN, AuthMode, MEMBER, OWNER
} from "../../../variables"; } from "../../../variables";
router.get( router.get(
"/:organizationId/plans/table", "/:organizationId/plans/table",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -29,7 +29,7 @@ router.get(
router.get( router.get(
"/:organizationId/plan", "/:organizationId/plan",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -44,7 +44,7 @@ router.get(
router.post( router.post(
"/:organizationId/session/trial", "/:organizationId/session/trial",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -59,7 +59,7 @@ router.post(
router.get( router.get(
"/:organizationId/plan/billing", "/:organizationId/plan/billing",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -74,7 +74,7 @@ router.get(
router.get( router.get(
"/:organizationId/plan/table", "/:organizationId/plan/table",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -89,7 +89,7 @@ router.get(
router.get( router.get(
"/:organizationId/billing-details", "/:organizationId/billing-details",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -103,7 +103,7 @@ router.get(
router.patch( router.patch(
"/:organizationId/billing-details", "/:organizationId/billing-details",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -119,7 +119,7 @@ router.patch(
router.get( router.get(
"/:organizationId/billing-details/payment-methods", "/:organizationId/billing-details/payment-methods",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -133,7 +133,7 @@ router.get(
router.post( router.post(
"/:organizationId/billing-details/payment-methods", "/:organizationId/billing-details/payment-methods",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -149,7 +149,7 @@ router.post(
router.delete( router.delete(
"/:organizationId/billing-details/payment-methods/:pmtMethodId", "/:organizationId/billing-details/payment-methods/:pmtMethodId",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -164,7 +164,7 @@ router.delete(
router.get( router.get(
"/:organizationId/billing-details/tax-ids", "/:organizationId/billing-details/tax-ids",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -178,7 +178,7 @@ router.get(
router.post( router.post(
"/:organizationId/billing-details/tax-ids", "/:organizationId/billing-details/tax-ids",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -194,7 +194,7 @@ router.post(
router.delete( router.delete(
"/:organizationId/billing-details/tax-ids/:taxId", "/:organizationId/billing-details/tax-ids/:taxId",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -209,7 +209,7 @@ router.delete(
router.get( router.get(
"/:organizationId/invoices", "/:organizationId/invoices",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -223,7 +223,7 @@ router.get(
router.get( router.get(
"/:organizationId/licenses", "/:organizationId/licenses",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN], acceptedRoles: [OWNER, ADMIN],
+4 -3
View File
@@ -9,15 +9,16 @@ import { body, param, query } from "express-validator";
import { secretController } from "../../controllers/v1"; import { secretController } from "../../controllers/v1";
import { import {
ADMIN, ADMIN,
AuthMode,
MEMBER, MEMBER,
PERMISSION_READ_SECRETS, PERMISSION_READ_SECRETS,
PERMISSION_WRITE_SECRETS, PERMISSION_WRITE_SECRETS
} from "../../../variables"; } from "../../../variables";
router.get( router.get(
"/:secretId/secret-versions", "/:secretId/secret-versions",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt", "apiKey"], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireSecretAuth({ requireSecretAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -33,7 +34,7 @@ router.get(
router.post( router.post(
"/:secretId/secret-versions/rollback", "/:secretId/secret-versions/rollback",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt", "apiKey"], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireSecretAuth({ requireSecretAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+6 -6
View File
@@ -7,12 +7,12 @@ import {
} from "../../../middleware"; } from "../../../middleware";
import { body, param } from "express-validator"; import { body, param } from "express-validator";
import { createInstallationSession, getCurrentOrganizationInstallationStatus, getRisksForOrganization, linkInstallationToOrganization, updateRisksStatus } from "../../../controllers/v1/secretScanningController"; import { createInstallationSession, getCurrentOrganizationInstallationStatus, getRisksForOrganization, linkInstallationToOrganization, updateRisksStatus } from "../../../controllers/v1/secretScanningController";
import { ACCEPTED, ADMIN, MEMBER, OWNER } from "../../../variables"; import { ACCEPTED, ADMIN, AuthMode, MEMBER, OWNER } from "../../../variables";
router.post( router.post(
"/create-installation-session/organization/:organizationId", "/create-installation-session/organization/:organizationId",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
param("organizationId").exists().trim(), param("organizationId").exists().trim(),
requireOrganizationAuth({ requireOrganizationAuth({
@@ -26,7 +26,7 @@ router.post(
router.post( router.post(
"/link-installation", "/link-installation",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("installationId").exists().trim(), body("installationId").exists().trim(),
body("sessionId").exists().trim(), body("sessionId").exists().trim(),
@@ -37,7 +37,7 @@ router.post(
router.get( router.get(
"/installation-status/organization/:organizationId", "/installation-status/organization/:organizationId",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
param("organizationId").exists().trim(), param("organizationId").exists().trim(),
requireOrganizationAuth({ requireOrganizationAuth({
@@ -51,7 +51,7 @@ router.get(
router.get( router.get(
"/organization/:organizationId/risks", "/organization/:organizationId/risks",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
param("organizationId").exists().trim(), param("organizationId").exists().trim(),
requireOrganizationAuth({ requireOrganizationAuth({
@@ -65,7 +65,7 @@ router.get(
router.post( router.post(
"/organization/:organizationId/risks/:riskId/status", "/organization/:organizationId/risks/:riskId/status",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
param("organizationId").exists().trim(), param("organizationId").exists().trim(),
param("riskId").exists().trim(), param("riskId").exists().trim(),
+2 -2
View File
@@ -8,13 +8,13 @@ import {
validateRequest, validateRequest,
} from "../../../middleware"; } from "../../../middleware";
import { param } from "express-validator"; import { param } from "express-validator";
import { ADMIN, MEMBER } from "../../../variables"; import { ADMIN, AuthMode, MEMBER } from "../../../variables";
import { secretSnapshotController } from "../../controllers/v1"; import { secretSnapshotController } from "../../controllers/v1";
router.get( router.get(
"/:secretSnapshotId", "/:secretSnapshotId",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireSecretSnapshotAuth({ requireSecretSnapshotAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+4 -3
View File
@@ -15,6 +15,7 @@ import { authLimiter } from "../../../helpers/rateLimiter";
import { import {
ACCEPTED, ACCEPTED,
ADMIN, ADMIN,
AuthMode,
OWNER OWNER
} from "../../../variables"; } from "../../../variables";
@@ -90,7 +91,7 @@ router.post("/saml2/:ssoIdentifier",
router.get( router.get(
"/config", "/config",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN], acceptedRoles: [OWNER, ADMIN],
@@ -105,7 +106,7 @@ router.get(
router.post( router.post(
"/config", "/config",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN], acceptedRoles: [OWNER, ADMIN],
@@ -125,7 +126,7 @@ router.post(
router.patch( router.patch(
"/config", "/config",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN], acceptedRoles: [OWNER, ADMIN],
+2 -2
View File
@@ -3,13 +3,13 @@ const router = express.Router();
import { import {
requireAuth requireAuth
} from "../../../middleware"; } from "../../../middleware";
import { AUTH_MODE_API_KEY, AUTH_MODE_JWT } from "../../../variables"; import { AuthMode } from "../../../variables";
import { usersController } from "../../controllers/v1"; import { usersController } from "../../controllers/v1";
router.get( router.get(
"/me/ip", "/me/ip",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
usersController.getMyIp usersController.getMyIp
); );
+45 -10
View File
@@ -8,16 +8,16 @@ import {
import { body, param, query } from "express-validator"; import { body, param, query } from "express-validator";
import { import {
ADMIN, ADMIN,
AUTH_MODE_API_KEY, AuthMode,
AUTH_MODE_JWT,
MEMBER MEMBER
} from "../../../variables"; } from "../../../variables";
import { workspaceController } from "../../controllers/v1"; import { workspaceController } from "../../controllers/v1";
import { EventType, UserAgentType } from "../../models";
router.get( router.get(
"/:workspaceId/secret-snapshots", "/:workspaceId/secret-snapshots",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -35,7 +35,7 @@ router.get(
router.get( router.get(
"/:workspaceId/secret-snapshots/count", "/:workspaceId/secret-snapshots/count",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -51,7 +51,7 @@ router.get(
router.post( router.post(
"/:workspaceId/secret-snapshots/rollback", "/:workspaceId/secret-snapshots/rollback",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -68,7 +68,7 @@ router.post(
router.get( router.get(
"/:workspaceId/logs", "/:workspaceId/logs",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -84,11 +84,46 @@ router.get(
workspaceController.getWorkspaceLogs workspaceController.getWorkspaceLogs
); );
router.get(
"/:workspaceId/audit-logs",
requireAuth({
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],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "params",
}),
param("workspaceId").exists().trim(),
validateRequest,
workspaceController.getWorkspaceAuditLogActorFilterOpts
);
router.get( router.get(
"/:workspaceId/trusted-ips", "/:workspaceId/trusted-ips",
param("workspaceId").exists().isString().trim(), param("workspaceId").exists().isString().trim(),
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -105,7 +140,7 @@ router.post(
body("isActive").exists().isBoolean(), body("isActive").exists().isBoolean(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN], acceptedRoles: [ADMIN],
@@ -122,7 +157,7 @@ router.patch(
body("comment").default("").isString().trim(), body("comment").default("").isString().trim(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN], acceptedRoles: [ADMIN],
@@ -137,7 +172,7 @@ router.delete(
param("trustedIpId").exists().isString().trim(), param("trustedIpId").exists().isString().trim(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN], acceptedRoles: [ADMIN],
@@ -0,0 +1,50 @@
import { Types } from "mongoose";
import { AuditLog, Event } from "../models";
import { AuthData } from "../../interfaces/middleware";
import EELicenseService from "./EELicenseService";
import { Workspace } from "../../models";
import { OrganizationNotFoundError } from "../../utils/errors";
interface EventScope {
workspaceId?: Types.ObjectId;
organizationId?: Types.ObjectId;
}
type ValidEventScope =
| Required<Pick<EventScope, "workspaceId">>
| Required<Pick<EventScope, "organizationId">>
| Required<EventScope>
export default class EEAuditLogService {
static async createAuditLog(authData: AuthData, event: Event, eventScope: ValidEventScope, shouldSave: boolean = true) {
const MS_IN_DAY = 24 * 60 * 60 * 1000;
const organizationId = ("organizationId" in eventScope)
? eventScope.organizationId
: (await Workspace.findById(eventScope.workspaceId).select("organization").lean())?.organization;
if (!organizationId) throw OrganizationNotFoundError({
message: "createAuditLog: Failed to create audit log due to missing organizationId"
});
const ttl = (await EELicenseService.getPlan(organizationId)).auditLogsRetentionDays * MS_IN_DAY;
const auditLog = await new AuditLog({
actor: authData.actor,
organization: organizationId,
workspace: ("workspaceId" in eventScope) ? eventScope.workspaceId : undefined,
ipAddress: authData.ipAddress,
event,
userAgent: authData.userAgent,
userAgentType: authData.userAgentType,
expiresAt: new Date(Date.now() + ttl)
});
if (shouldSave) {
await auditLog.save();
}
return auditLog;
}
}
+12 -9
View File
@@ -1,3 +1,4 @@
import { Types } from "mongoose";
import * as Sentry from "@sentry/node"; import * as Sentry from "@sentry/node";
import NodeCache from "node-cache"; import NodeCache from "node-cache";
import { import {
@@ -31,6 +32,7 @@ interface FeatureSet {
customRateLimits: boolean; customRateLimits: boolean;
customAlerts: boolean; customAlerts: boolean;
auditLogs: boolean; auditLogs: boolean;
auditLogsRetentionDays: number;
samlSSO: boolean; samlSSO: boolean;
status: "incomplete" | "incomplete_expired" | "trialing" | "active" | "past_due" | "canceled" | "unpaid" | null; status: "incomplete" | "incomplete_expired" | "trialing" | "active" | "past_due" | "canceled" | "unpaid" | null;
trial_end: number | null; trial_end: number | null;
@@ -63,9 +65,10 @@ class EELicenseService {
pitRecovery: false, pitRecovery: false,
ipAllowlisting: false, ipAllowlisting: false,
rbac: true, rbac: true,
customRateLimits: true, customRateLimits: false,
customAlerts: true, customAlerts: false,
auditLogs: false, auditLogs: false,
auditLogsRetentionDays: 0,
samlSSO: false, samlSSO: false,
status: null, status: null,
trial_end: null, trial_end: null,
@@ -81,10 +84,10 @@ class EELicenseService {
}); });
} }
public async getPlan(organizationId: string, workspaceId?: string): Promise<FeatureSet> { public async getPlan(organizationId: Types.ObjectId, workspaceId?: Types.ObjectId): Promise<FeatureSet> {
try { try {
if (this.instanceType === "cloud") { if (this.instanceType === "cloud") {
const cachedPlan = this.localFeatureSet.get<FeatureSet>(`${organizationId}-${workspaceId ?? ""}`); const cachedPlan = this.localFeatureSet.get<FeatureSet>(`${organizationId.toString()}-${workspaceId?.toString() ?? ""}`);
if (cachedPlan) { if (cachedPlan) {
return cachedPlan; return cachedPlan;
} }
@@ -101,7 +104,7 @@ class EELicenseService {
const { data: { currentPlan } } = await licenseServerKeyRequest.get(url); const { data: { currentPlan } } = await licenseServerKeyRequest.get(url);
// cache fetched plan for organization // cache fetched plan for organization
this.localFeatureSet.set(`${organizationId}-${workspaceId ?? ""}`, currentPlan); this.localFeatureSet.set(`${organizationId.toString()}-${workspaceId?.toString() ?? ""}`, currentPlan);
return currentPlan; return currentPlan;
} }
@@ -112,16 +115,16 @@ class EELicenseService {
return this.globalFeatureSet; return this.globalFeatureSet;
} }
public async refreshPlan(organizationId: string, workspaceId?: string) { public async refreshPlan(organizationId: Types.ObjectId, workspaceId?: Types.ObjectId) {
if (this.instanceType === "cloud") { if (this.instanceType === "cloud") {
this.localFeatureSet.del(`${organizationId}-${workspaceId ?? ""}`); this.localFeatureSet.del(`${organizationId.toString()}-${workspaceId?.toString() ?? ""}`);
await this.getPlan(organizationId, workspaceId); await this.getPlan(organizationId, workspaceId);
} }
} }
public async delPlan(organizationId: string) { public async delPlan(organizationId: Types.ObjectId) {
if (this.instanceType === "cloud") { if (this.instanceType === "cloud") {
this.localFeatureSet.del(`${organizationId}-`); this.localFeatureSet.del(`${organizationId.toString()}-`);
} }
} }
+1 -3
View File
@@ -10,7 +10,7 @@ import EELicenseService from "./EELicenseService";
/** /**
* Class to handle Enterprise Edition secret actions * Class to handle Enterprise Edition secret actions
*/ */
class EESecretService { export default class EESecretService {
/** /**
* Save a secret snapshot that is a copy of the current state of secrets in workspace with id * Save a secret snapshot that is a copy of the current state of secrets in workspace with id
* [workspaceId] under a new snapshot with incremented version under the * [workspaceId] under a new snapshot with incremented version under the
@@ -71,5 +71,3 @@ class EESecretService {
}); });
} }
} }
export default EESecretService;
+2
View File
@@ -1,11 +1,13 @@
import EELicenseService from "./EELicenseService"; import EELicenseService from "./EELicenseService";
import EESecretService from "./EESecretService"; import EESecretService from "./EESecretService";
import EELogService from "./EELogService"; import EELogService from "./EELogService";
import EEAuditLogService from "./EEAuditLogService";
import GithubSecretScanningService from "./GithubSecretScanning/GithubSecretScanningService" import GithubSecretScanningService from "./GithubSecretScanning/GithubSecretScanningService"
export { export {
EELicenseService, EELicenseService,
EESecretService, EESecretService,
EELogService, EELogService,
EEAuditLogService,
GithubSecretScanningService GithubSecretScanningService
} }
+67 -50
View File
@@ -1,3 +1,4 @@
import { Request } from "express";
import { Types } from "mongoose"; import { Types } from "mongoose";
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
import bcrypt from "bcrypt"; import bcrypt from "bcrypt";
@@ -5,7 +6,6 @@ import {
APIKeyData, APIKeyData,
ITokenVersion, ITokenVersion,
IUser, IUser,
ServiceAccount,
ServiceTokenData, ServiceTokenData,
TokenVersion, TokenVersion,
User, User,
@@ -14,7 +14,6 @@ import {
APIKeyDataNotFoundError, APIKeyDataNotFoundError,
AccountNotFoundError, AccountNotFoundError,
BadRequestError, BadRequestError,
ServiceAccountNotFoundError,
ServiceTokenDataNotFoundError, ServiceTokenDataNotFoundError,
UnauthorizedRequestError, UnauthorizedRequestError,
} from "../utils/errors"; } from "../utils/errors";
@@ -26,11 +25,15 @@ import {
getJwtRefreshSecret, getJwtRefreshSecret,
} from "../config"; } from "../config";
import { import {
AUTH_MODE_API_KEY, AuthMode
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
} from "../variables"; } from "../variables";
import {
ServiceTokenAuthData,
UserAuthData
} from "../interfaces/middleware";
import { ActorType } from "../ee/models";
import { getUserAgentType } from "../utils/posthog";
/** /**
* *
@@ -42,7 +45,7 @@ export const validateAuthMode = ({
acceptedAuthModes, acceptedAuthModes,
}: { }: {
headers: { [key: string]: string | string[] | undefined }, headers: { [key: string]: string | string[] | undefined },
acceptedAuthModes: string[] acceptedAuthModes: AuthMode[]
}) => { }) => {
const apiKey = headers["x-api-key"]; const apiKey = headers["x-api-key"];
const authHeader = headers["authorization"]; const authHeader = headers["authorization"];
@@ -55,7 +58,7 @@ export const validateAuthMode = ({
if (typeof apiKey === "string") { if (typeof apiKey === "string") {
// case: treat request authentication type as via X-API-KEY (i.e. API Key) // case: treat request authentication type as via X-API-KEY (i.e. API Key)
authMode = AUTH_MODE_API_KEY; authMode = AuthMode.API_KEY;
authTokenValue = apiKey; authTokenValue = apiKey;
} }
@@ -71,13 +74,10 @@ export const validateAuthMode = ({
switch (tokenValue.split(".", 1)[0]) { switch (tokenValue.split(".", 1)[0]) {
case "st": case "st":
authMode = AUTH_MODE_SERVICE_TOKEN; authMode = AuthMode.SERVICE_TOKEN;
break;
case "sa":
authMode = AUTH_MODE_SERVICE_ACCOUNT;
break; break;
default: default:
authMode = AUTH_MODE_JWT; authMode = AuthMode.JWT;
} }
authTokenValue = tokenValue; authTokenValue = tokenValue;
@@ -100,10 +100,12 @@ export const validateAuthMode = ({
* @returns {User} user - user corresponding to JWT token * @returns {User} user - user corresponding to JWT token
*/ */
export const getAuthUserPayload = async ({ export const getAuthUserPayload = async ({
req,
authTokenValue, authTokenValue,
}: { }: {
req: Request,
authTokenValue: string; authTokenValue: string;
}) => { }): Promise<UserAuthData> => {
const decodedToken = <jwt.UserIDJwtPayload>( const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(authTokenValue, await getJwtAuthSecret()) jwt.verify(authTokenValue, await getJwtAuthSecret())
); );
@@ -130,11 +132,25 @@ export const getAuthUserPayload = async ({
if (decodedToken.accessVersion !== tokenVersion.accessVersion) throw UnauthorizedRequestError({ if (decodedToken.accessVersion !== tokenVersion.accessVersion) throw UnauthorizedRequestError({
message: "Failed to validate access token", message: "Failed to validate access token",
}); });
return ({ return {
user, actor: {
tokenVersionId: tokenVersion._id, type: ActorType.USER,
}); metadata: {
userId: user._id.toString(),
email: user.email
}
},
authPayload: user,
ipAddress: req.realIP,
userAgent: req.headers["user-agent"] ?? "",
userAgentType: getUserAgentType(req.headers["user-agent"])
}
// return ({
// user,
// tokenVersionId: tokenVersion._id, // what to do with this? // move this out
// });
} }
/** /**
@@ -144,10 +160,12 @@ export const getAuthUserPayload = async ({
* @returns {ServiceTokenData} serviceTokenData - service token data * @returns {ServiceTokenData} serviceTokenData - service token data
*/ */
export const getAuthSTDPayload = async ({ export const getAuthSTDPayload = async ({
req,
authTokenValue, authTokenValue,
}: { }: {
req: Request,
authTokenValue: string; authTokenValue: string;
}) => { }): Promise<ServiceTokenAuthData> => {
const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split(".", 3); const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split(".", 3);
const serviceTokenData = await ServiceTokenData const serviceTokenData = await ServiceTokenData
@@ -180,36 +198,21 @@ export const getAuthSTDPayload = async ({
if (!serviceTokenDataToReturn) throw ServiceTokenDataNotFoundError({ message: "Failed to find service token data" }); if (!serviceTokenDataToReturn) throw ServiceTokenDataNotFoundError({ message: "Failed to find service token data" });
return serviceTokenDataToReturn; return {
} actor: {
type: ActorType.SERVICE,
/** metadata: {
* Return service account access key payload serviceId: serviceTokenDataToReturn._id.toString(),
* @param {Object} obj name: serviceTokenDataToReturn.name
* @param {String} obj.authTokenValue - service account access token value }
* @returns {ServiceAccount} serviceAccount },
*/ authPayload: serviceTokenDataToReturn,
export const getAuthSAAKPayload = async ({ ipAddress: req.realIP,
authTokenValue, userAgent: req.headers["user-agent"] ?? "",
}: { userAgentType: getUserAgentType(req.headers["user-agent"])
authTokenValue: string;
}) => {
const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split(".", 3);
const serviceAccount = await ServiceAccount.findById(
Buffer.from(TOKEN_IDENTIFIER, "base64").toString("hex")
).select("+secretHash");
if (!serviceAccount) {
throw ServiceAccountNotFoundError({ message: "Failed to find service account" });
} }
const result = await bcrypt.compare(TOKEN_SECRET, serviceAccount.secretHash); // return serviceTokenDataToReturn;
if (!result) throw UnauthorizedRequestError({
message: "Failed to authenticate service account access key",
});
return serviceAccount;
} }
/** /**
@@ -219,10 +222,12 @@ export const getAuthSAAKPayload = async ({
* @returns {APIKeyData} apiKeyData - API key data * @returns {APIKeyData} apiKeyData - API key data
*/ */
export const getAuthAPIKeyPayload = async ({ export const getAuthAPIKeyPayload = async ({
req,
authTokenValue, authTokenValue,
}: { }: {
req: Request,
authTokenValue: string; authTokenValue: string;
}) => { }): Promise<UserAuthData> => {
const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split(".", 3); const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split(".", 3);
let apiKeyData = await APIKeyData let apiKeyData = await APIKeyData
@@ -264,7 +269,19 @@ export const getAuthAPIKeyPayload = async ({
}); });
} }
return user; return {
actor: {
type: ActorType.USER,
metadata: {
userId: user._id.toString(),
email: user.email
}
},
authPayload: user,
ipAddress: req.realIP,
userAgent: req.headers["user-agent"] ?? "",
userAgentType: getUserAgentType(req.headers["user-agent"])
}
} }
/** /**
+1 -1
View File
@@ -115,5 +115,5 @@ export const updateSubscriptionOrgQuantity = async ({
); );
} }
await EELicenseService.refreshPlan(organizationId); await EELicenseService.refreshPlan(new Types.ObjectId(organizationId));
}; };
+106 -23
View File
@@ -11,9 +11,9 @@ import {
IServiceTokenData, IServiceTokenData,
Secret, Secret,
SecretBlindIndexData, SecretBlindIndexData,
ServiceTokenData ServiceTokenData,
} from "../models"; } from "../models";
import { SecretVersion } from "../ee/models"; import { EventType, SecretVersion } from "../ee/models";
import { import {
BadRequestError, BadRequestError,
InternalServerError, InternalServerError,
@@ -40,7 +40,7 @@ import {
} from "../utils/crypto"; } from "../utils/crypto";
import { TelemetryService } from "../services"; import { TelemetryService } from "../services";
import { client, getEncryptionKey, getRootEncryptionKey } from "../config"; import { client, getEncryptionKey, getRootEncryptionKey } from "../config";
import { EELogService, EESecretService } from "../ee/services"; import { EEAuditLogService, EELogService, EESecretService } from "../ee/services";
import { getAuthDataPayloadIdObj, getAuthDataPayloadUserObj } from "../utils/auth"; import { getAuthDataPayloadIdObj, getAuthDataPayloadUserObj } from "../utils/auth";
import { getFolderByPath, getFolderIdFromServiceToken } from "../services/FolderService"; import { getFolderByPath, getFolderIdFromServiceToken } from "../services/FolderService";
import picomatch from "picomatch"; import picomatch from "picomatch";
@@ -433,10 +433,27 @@ export const createSecretHelper = async ({
...getAuthDataPayloadIdObj(authData), ...getAuthDataPayloadIdObj(authData),
workspaceId, workspaceId,
actions: [action], actions: [action],
channel: authData.authChannel, channel: authData.userAgentType,
ipAddress: authData.authIP ipAddress: authData.ipAddress
})); }));
await EEAuditLogService.createAuditLog(
authData,
{
type: EventType.CREATE_SECRET,
metadata: {
environment,
secretPath,
secretId: secret._id.toString(),
secretKey: secretName,
secretVersion: secret.version
}
},
{
workspaceId
}
);
// (EE) take a secret snapshot // (EE) take a secret snapshot
await EESecretService.takeSecretSnapshot({ await EESecretService.takeSecretSnapshot({
workspaceId, workspaceId,
@@ -457,8 +474,8 @@ export const createSecretHelper = async ({
environment, environment,
workspaceId, workspaceId,
folderId, folderId,
channel: authData.authChannel, channel: authData.userAgentType,
userAgent: authData.authUserAgent userAgent: authData.userAgent
} }
}); });
} }
@@ -528,9 +545,24 @@ export const getSecretsHelper = async ({
...getAuthDataPayloadIdObj(authData), ...getAuthDataPayloadIdObj(authData),
workspaceId, workspaceId,
actions: [action], actions: [action],
channel: authData.authChannel, channel: authData.userAgentType,
ipAddress: authData.authIP ipAddress: authData.ipAddress
})); }));
await EEAuditLogService.createAuditLog(
authData,
{
type: EventType.GET_SECRETS,
metadata: {
environment,
secretPath,
numberOfSecrets: secrets.length
}
},
{
workspaceId
}
);
const postHogClient = await TelemetryService.getPostHogClient(); const postHogClient = await TelemetryService.getPostHogClient();
@@ -545,8 +577,8 @@ export const getSecretsHelper = async ({
environment, environment,
workspaceId, workspaceId,
folderId, folderId,
channel: authData.authChannel, channel: authData.userAgentType,
userAgent: authData.authUserAgent userAgent: authData.userAgent
} }
}); });
} }
@@ -622,10 +654,27 @@ export const getSecretHelper = async ({
...getAuthDataPayloadIdObj(authData), ...getAuthDataPayloadIdObj(authData),
workspaceId, workspaceId,
actions: [action], actions: [action],
channel: authData.authChannel, channel: authData.userAgentType,
ipAddress: authData.authIP ipAddress: authData.ipAddress
})); }));
await EEAuditLogService.createAuditLog(
authData,
{
type: EventType.GET_SECRET,
metadata: {
environment,
secretPath,
secretId: secret._id.toString(),
secretKey: secretName,
secretVersion: secret.version
}
},
{
workspaceId
}
);
const postHogClient = await TelemetryService.getPostHogClient(); const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) { if (postHogClient) {
@@ -639,8 +688,8 @@ export const getSecretHelper = async ({
environment, environment,
workspaceId, workspaceId,
folderId, folderId,
channel: authData.authChannel, channel: authData.userAgentType,
userAgent: authData.authUserAgent userAgent: authData.userAgent
} }
}); });
} }
@@ -771,9 +820,26 @@ export const updateSecretHelper = async ({
...getAuthDataPayloadIdObj(authData), ...getAuthDataPayloadIdObj(authData),
workspaceId, workspaceId,
actions: [action], actions: [action],
channel: authData.authChannel, channel: authData.userAgentType,
ipAddress: authData.authIP ipAddress: authData.ipAddress
})); }));
await EEAuditLogService.createAuditLog(
authData,
{
type: EventType.UPDATE_SECRET,
metadata: {
environment,
secretPath,
secretId: secret._id.toString(),
secretKey: secretName,
secretVersion: secret.version
}
},
{
workspaceId
}
);
// (EE) take a secret snapshot // (EE) take a secret snapshot
await EESecretService.takeSecretSnapshot({ await EESecretService.takeSecretSnapshot({
@@ -795,8 +861,8 @@ export const updateSecretHelper = async ({
environment, environment,
workspaceId, workspaceId,
folderId, folderId,
channel: authData.authChannel, channel: authData.userAgentType,
userAgent: authData.authUserAgent userAgent: authData.userAgent
} }
}); });
} }
@@ -894,10 +960,27 @@ export const deleteSecretHelper = async ({
...getAuthDataPayloadIdObj(authData), ...getAuthDataPayloadIdObj(authData),
workspaceId, workspaceId,
actions: [action], actions: [action],
channel: authData.authChannel, channel: authData.userAgentType,
ipAddress: authData.authIP ipAddress: authData.ipAddress
})); }));
await EEAuditLogService.createAuditLog(
authData,
{
type: EventType.DELETE_SECRET,
metadata: {
environment,
secretPath,
secretId: secret._id.toString(),
secretKey: secretName,
secretVersion: secret.version
}
},
{
workspaceId
}
);
// (EE) take a secret snapshot // (EE) take a secret snapshot
await EESecretService.takeSecretSnapshot({ await EESecretService.takeSecretSnapshot({
workspaceId, workspaceId,
@@ -918,8 +1001,8 @@ export const deleteSecretHelper = async ({
environment, environment,
workspaceId, workspaceId,
folderId, folderId,
channel: authData.authChannel, channel: authData.userAgentType,
userAgent: authData.authUserAgent userAgent: authData.userAgent
} }
}); });
} }
+2 -1
View File
@@ -1,3 +1,4 @@
import { Types } from "mongoose";
import { import {
Bot, Bot,
Key, Key,
@@ -25,7 +26,7 @@ export const createWorkspace = async ({
organizationId, organizationId,
}: { }: {
name: string; name: string;
organizationId: string; organizationId: Types.ObjectId;
}) => { }) => {
// create workspace // create workspace
const workspace = await new Workspace({ const workspace = await new Workspace({
+24 -8
View File
@@ -1,15 +1,31 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { import {
IServiceAccount,
IServiceTokenData, IServiceTokenData,
IUser, IUser,
} from "../../models"; } from "../../models";
import {
ServiceActor,
UserActor,
UserAgentType
} from "../../ee/models";
export interface AuthData { interface BaseAuthData {
authMode: string; ipAddress: string;
authPayload: IUser | IServiceAccount | IServiceTokenData; userAgent: string;
authChannel: string; userAgentType: UserAgentType;
authIP: string;
authUserAgent: string;
tokenVersionId?: Types.ObjectId; tokenVersionId?: Types.ObjectId;
} }
export interface UserAuthData extends BaseAuthData {
actor: UserActor;
authPayload: IUser;
}
export interface ServiceTokenAuthData extends BaseAuthData {
actor: ServiceActor;
authPayload: IServiceTokenData;
}
export type AuthData =
| UserAuthData
| ServiceTokenAuthData;
+25 -56
View File
@@ -1,25 +1,13 @@
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
import { Types } from "mongoose";
import { NextFunction, Request, Response } from "express"; import { NextFunction, Request, Response } from "express";
import { import {
getAuthAPIKeyPayload, getAuthAPIKeyPayload,
getAuthSAAKPayload,
getAuthSTDPayload, getAuthSTDPayload,
getAuthUserPayload, getAuthUserPayload,
validateAuthMode, validateAuthMode,
} from "../helpers/auth"; } from "../helpers/auth";
import { import { AuthMode } from "../variables";
IServiceAccount, import { AuthData } from "../interfaces/middleware";
IServiceTokenData,
IUser,
} from "../models";
import {
AUTH_MODE_API_KEY,
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
} from "../variables";
import { getChannelFromUserAgent } from "../utils/posthog";
declare module "jsonwebtoken" { declare module "jsonwebtoken" {
export interface UserIDJwtPayload extends jwt.JwtPayload { export interface UserIDJwtPayload extends jwt.JwtPayload {
@@ -38,9 +26,9 @@ declare module "jsonwebtoken" {
* @returns * @returns
*/ */
const requireAuth = ({ const requireAuth = ({
acceptedAuthModes = [AUTH_MODE_JWT], acceptedAuthModes = [AuthMode.JWT],
}: { }: {
acceptedAuthModes: string[]; acceptedAuthModes: AuthMode[];
}) => { }) => {
return async (req: Request, res: Response, next: NextFunction) => { return async (req: Request, res: Response, next: NextFunction) => {
@@ -50,55 +38,36 @@ const requireAuth = ({
headers: req.headers, headers: req.headers,
acceptedAuthModes, acceptedAuthModes,
}); });
let authPayload: IUser | IServiceAccount | IServiceTokenData; let authData: AuthData;
let authUserPayload: {
user: IUser;
tokenVersionId: Types.ObjectId;
};
switch (authMode) { switch (authMode) {
case AUTH_MODE_SERVICE_ACCOUNT: case AuthMode.SERVICE_TOKEN:
authPayload = await getAuthSAAKPayload({ authData = await getAuthSTDPayload({
req,
authTokenValue, authTokenValue,
}); });
req.serviceAccount = authPayload; req.serviceTokenData = authData.authPayload;
break; break;
case AUTH_MODE_SERVICE_TOKEN: case AuthMode.API_KEY:
authPayload = await getAuthSTDPayload({ authData = await getAuthAPIKeyPayload({
authTokenValue, req,
authTokenValue
}); });
req.serviceTokenData = authPayload; req.user = authData.authPayload;
break; break;
case AUTH_MODE_API_KEY: case AuthMode.JWT:
authPayload = await getAuthAPIKeyPayload({ authData = await getAuthUserPayload({
authTokenValue, req,
authTokenValue
}); });
req.user = authPayload; // authPayload = authUserPayload.user;
break; req.user = authData.authPayload;
default: // req.tokenVersionId = authUserPayload.tokenVersionId; // TODO
authUserPayload = await getAuthUserPayload({
authTokenValue,
});
authPayload = authUserPayload.user;
req.user = authUserPayload.user;
req.tokenVersionId = authUserPayload.tokenVersionId;
break; break;
} }
req.requestData = { req.authData = authData;
...req.params,
...req.query,
...req.body,
}
req.authData = {
authMode,
authPayload, // User, ServiceAccount, ServiceTokenData
authChannel: getChannelFromUserAgent(req.headers["user-agent"]),
authIP: req.realIP,
authUserAgent: req.headers["user-agent"] ?? "other",
tokenVersionId: req.tokenVersionId,
}
return next(); return next();
} }
+7
View File
@@ -10,6 +10,8 @@ import Membership, { IMembership } from "./membership";
import MembershipOrg, { IMembershipOrg } from "./membershipOrg"; import MembershipOrg, { IMembershipOrg } from "./membershipOrg";
import Organization, { IOrganization } from "./organization"; import Organization, { IOrganization } from "./organization";
import Secret, { ISecret } from "./secret"; import Secret, { ISecret } from "./secret";
import Folder, { TFolderRootSchema, TFolderSchema } from "./folder";
import SecretImport, { ISecretImports } from "./secretImports";
import SecretBlindIndexData, { ISecretBlindIndexData } from "./secretBlindIndexData"; import SecretBlindIndexData, { ISecretBlindIndexData } from "./secretBlindIndexData";
import ServiceToken, { IServiceToken } from "./serviceToken"; import ServiceToken, { IServiceToken } from "./serviceToken";
import ServiceAccount, { IServiceAccount } from "./serviceAccount"; // new import ServiceAccount, { IServiceAccount } from "./serviceAccount"; // new
@@ -51,6 +53,11 @@ export {
IOrganization, IOrganization,
Secret, Secret,
ISecret, ISecret,
Folder,
TFolderRootSchema,
TFolderSchema,
SecretImport,
ISecretImports,
SecretBlindIndexData, SecretBlindIndexData,
ISecretBlindIndexData, ISecretBlindIndexData,
ServiceToken, ServiceToken,
+5 -5
View File
@@ -4,7 +4,7 @@ import { body } from "express-validator";
import { requireAuth, validateRequest } from "../../middleware"; import { requireAuth, validateRequest } from "../../middleware";
import { authController } from "../../controllers/v1"; import { authController } from "../../controllers/v1";
import { authLimiter } from "../../helpers/rateLimiter"; import { authLimiter } from "../../helpers/rateLimiter";
import { AUTH_MODE_JWT } from "../../variables"; import { AuthMode } from "../../variables";
router.post("/token", validateRequest, authController.getNewToken); router.post("/token", validateRequest, authController.getNewToken);
@@ -30,7 +30,7 @@ router.post(
"/logout", "/logout",
authLimiter, authLimiter,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
authController.logout authController.logout
); );
@@ -38,7 +38,7 @@ router.post(
router.post( router.post(
"/checkAuth", "/checkAuth",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
authController.checkAuth authController.checkAuth
); );
@@ -53,9 +53,9 @@ router.delete(
"/sessions", "/sessions",
authLimiter, authLimiter,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
authController.revokeAllSessions authController.revokeAllSessions
); );
export default router; export default router;
+3 -3
View File
@@ -8,12 +8,12 @@ import {
validateRequest, validateRequest,
} from "../../middleware"; } from "../../middleware";
import { botController } from "../../controllers/v1"; import { botController } from "../../controllers/v1";
import { ADMIN, AUTH_MODE_JWT, MEMBER } from "../../variables"; import { ADMIN, AuthMode, MEMBER } from "../../variables";
router.get( router.get(
"/:workspaceId", "/:workspaceId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -27,7 +27,7 @@ router.get(
router.patch( router.patch(
"/:botId/active", "/:botId/active",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireBotAuth({ requireBotAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+5 -6
View File
@@ -8,9 +8,8 @@ import {
} from "../../middleware"; } from "../../middleware";
import { import {
ADMIN, ADMIN,
AUTH_MODE_API_KEY, AuthMode,
AUTH_MODE_JWT, MEMBER
MEMBER,
} from "../../variables"; } from "../../variables";
import { body, param } from "express-validator"; import { body, param } from "express-validator";
import { integrationController } from "../../controllers/v1"; import { integrationController } from "../../controllers/v1";
@@ -18,7 +17,7 @@ import { integrationController } from "../../controllers/v1";
router.post( router.post(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireIntegrationAuthorizationAuth({ requireIntegrationAuthorizationAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -44,7 +43,7 @@ router.post(
router.patch( router.patch(
"/:integrationId", "/:integrationId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT]
}), }),
requireIntegrationAuth({ requireIntegrationAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -64,7 +63,7 @@ router.patch(
router.delete( router.delete(
"/:integrationId", "/:integrationId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT]
}), }),
requireIntegrationAuth({ requireIntegrationAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+14 -15
View File
@@ -9,16 +9,15 @@ import {
} from "../../middleware"; } from "../../middleware";
import { import {
ADMIN, ADMIN,
AUTH_MODE_API_KEY, AuthMode,
AUTH_MODE_JWT, MEMBER
MEMBER,
} from "../../variables"; } from "../../variables";
import { integrationAuthController } from "../../controllers/v1"; import { integrationAuthController } from "../../controllers/v1";
router.get( router.get(
"/integration-options", "/integration-options",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
integrationAuthController.getIntegrationOptions integrationAuthController.getIntegrationOptions
); );
@@ -26,7 +25,7 @@ router.get(
router.get( router.get(
"/:integrationAuthId", "/:integrationAuthId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireIntegrationAuthorizationAuth({ requireIntegrationAuthorizationAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -39,7 +38,7 @@ router.get(
router.post( router.post(
"/oauth-token", "/oauth-token",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -62,7 +61,7 @@ router.post(
body("integration").exists().trim().notEmpty(), body("integration").exists().trim().notEmpty(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -74,7 +73,7 @@ router.post(
router.get( router.get(
"/:integrationAuthId/apps", "/:integrationAuthId/apps",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireIntegrationAuthorizationAuth({ requireIntegrationAuthorizationAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -89,7 +88,7 @@ router.get(
router.get( router.get(
"/:integrationAuthId/teams", "/:integrationAuthId/teams",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireIntegrationAuthorizationAuth({ requireIntegrationAuthorizationAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -102,7 +101,7 @@ router.get(
router.get( router.get(
"/:integrationAuthId/vercel/branches", "/:integrationAuthId/vercel/branches",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireIntegrationAuthorizationAuth({ requireIntegrationAuthorizationAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -117,7 +116,7 @@ router.get(
router.get( router.get(
"/:integrationAuthId/railway/environments", "/:integrationAuthId/railway/environments",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireIntegrationAuthorizationAuth({ requireIntegrationAuthorizationAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -131,7 +130,7 @@ router.get(
router.get( router.get(
"/:integrationAuthId/railway/services", "/:integrationAuthId/railway/services",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireIntegrationAuthorizationAuth({ requireIntegrationAuthorizationAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -145,7 +144,7 @@ router.get(
router.get( router.get(
"/:integrationAuthId/bitbucket/workspaces", "/:integrationAuthId/bitbucket/workspaces",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireIntegrationAuthorizationAuth({ requireIntegrationAuthorizationAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -158,7 +157,7 @@ router.get(
router.get( router.get(
"/:integrationAuthId/northflank/secret-groups", "/:integrationAuthId/northflank/secret-groups",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireIntegrationAuthorizationAuth({ requireIntegrationAuthorizationAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -172,7 +171,7 @@ router.get(
router.delete( router.delete(
"/:integrationAuthId", "/:integrationAuthId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireIntegrationAuthorizationAuth({ requireIntegrationAuthorizationAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+2 -2
View File
@@ -3,12 +3,12 @@ const router = express.Router();
import { body } from "express-validator"; import { body } from "express-validator";
import { requireAuth, validateRequest } from "../../middleware"; import { requireAuth, validateRequest } from "../../middleware";
import { membershipOrgController } from "../../controllers/v1"; import { membershipOrgController } from "../../controllers/v1";
import { AUTH_MODE_JWT } from "../../variables"; import { AuthMode } from "../../variables";
router.post( router.post(
"/signup", "/signup",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("inviteeEmail").exists().trim().notEmpty().isEmail(), body("inviteeEmail").exists().trim().notEmpty().isEmail(),
body("organizationId").exists().trim().notEmpty(), body("organizationId").exists().trim().notEmpty(),
+3 -3
View File
@@ -6,13 +6,13 @@ import {
validateRequest, validateRequest,
} from "../../middleware"; } from "../../middleware";
import { body, param } from "express-validator"; import { body, param } from "express-validator";
import { ADMIN, AUTH_MODE_JWT, MEMBER } from "../../variables"; import { ADMIN, AuthMode, MEMBER } from "../../variables";
import { keyController } from "../../controllers/v1"; import { keyController } from "../../controllers/v1";
router.post( router.post(
"/:workspaceId", "/:workspaceId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -27,7 +27,7 @@ router.post(
router.get( router.get(
"/:workspaceId/latest", "/:workspaceId/latest",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+5 -5
View File
@@ -4,14 +4,14 @@ import { body, param } from "express-validator";
import { requireAuth, validateRequest } from "../../middleware"; import { requireAuth, validateRequest } from "../../middleware";
import { membershipController } from "../../controllers/v1"; import { membershipController } from "../../controllers/v1";
import { membershipController as EEMembershipControllers } from "../../ee/controllers/v1"; import { membershipController as EEMembershipControllers } from "../../ee/controllers/v1";
import { AUTH_MODE_JWT } from "../../variables"; import { AuthMode } from "../../variables";
// note: ALL DEPRECIATED (moved to api/v2/workspace/:workspaceId/memberships/:membershipId) // note: ALL DEPRECIATED (moved to api/v2/workspace/:workspaceId/memberships/:membershipId)
router.get( // used for old CLI (deprecate) router.get( // used for old CLI (deprecate)
"/:workspaceId/connect", "/:workspaceId/connect",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
param("workspaceId").exists().trim(), param("workspaceId").exists().trim(),
validateRequest, validateRequest,
@@ -21,7 +21,7 @@ router.get( // used for old CLI (deprecate)
router.delete( router.delete(
"/:membershipId", "/:membershipId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
param("membershipId").exists().trim(), param("membershipId").exists().trim(),
validateRequest, validateRequest,
@@ -31,7 +31,7 @@ router.delete(
router.post( router.post(
"/:membershipId/change-role", "/:membershipId/change-role",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("role").exists().trim(), body("role").exists().trim(),
validateRequest, validateRequest,
@@ -41,7 +41,7 @@ router.post(
router.post( router.post(
"/:membershipId/deny-permissions", "/:membershipId/deny-permissions",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
param("membershipId").isMongoId().exists().trim(), param("membershipId").isMongoId().exists().trim(),
body("permissions").isArray().exists(), body("permissions").isArray().exists(),
+3 -3
View File
@@ -3,13 +3,13 @@ const router = express.Router();
import { param } from "express-validator"; import { param } from "express-validator";
import { requireAuth, validateRequest } from "../../middleware"; import { requireAuth, validateRequest } from "../../middleware";
import { membershipOrgController } from "../../controllers/v1"; import { membershipOrgController } from "../../controllers/v1";
import { AUTH_MODE_JWT } from "../../variables"; import { AuthMode } from "../../variables";
router.post( router.post(
// TODO // TODO
"/membershipOrg/:membershipOrgId/change-role", "/membershipOrg/:membershipOrgId/change-role",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
param("membershipOrgId"), param("membershipOrgId"),
validateRequest, validateRequest,
@@ -19,7 +19,7 @@ router.post(
router.delete( router.delete(
"/:membershipOrgId", "/:membershipOrgId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
param("membershipOrgId").exists().trim(), param("membershipOrgId").exists().trim(),
validateRequest, validateRequest,
+14 -14
View File
@@ -9,16 +9,16 @@ import {
import { import {
ACCEPTED, ACCEPTED,
ADMIN, ADMIN,
AUTH_MODE_JWT, AuthMode,
MEMBER, MEMBER,
OWNER, OWNER
} from "../../variables"; } from "../../variables";
import { organizationController } from "../../controllers/v1"; import { organizationController } from "../../controllers/v1";
router.get( // deprecated (moved to api/v2/users/me/organizations) router.get( // deprecated (moved to api/v2/users/me/organizations)
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
organizationController.getOrganizations organizationController.getOrganizations
); );
@@ -26,7 +26,7 @@ router.get( // deprecated (moved to api/v2/users/me/organizations)
router.post( // not used on frontend router.post( // not used on frontend
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("organizationName").exists().trim().notEmpty(), body("organizationName").exists().trim().notEmpty(),
validateRequest, validateRequest,
@@ -36,7 +36,7 @@ router.post( // not used on frontend
router.get( router.get(
"/:organizationId", "/:organizationId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -50,7 +50,7 @@ router.get(
router.get( // deprecated (moved to api/v2/organizations/:organizationId/memberships) router.get( // deprecated (moved to api/v2/organizations/:organizationId/memberships)
"/:organizationId/users", "/:organizationId/users",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -64,7 +64,7 @@ router.get( // deprecated (moved to api/v2/organizations/:organizationId/members
router.get( router.get(
"/:organizationId/my-workspaces", // deprecated (moved to api/v2/organizations/:organizationId/workspaces) "/:organizationId/my-workspaces", // deprecated (moved to api/v2/organizations/:organizationId/workspaces)
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -78,7 +78,7 @@ router.get(
router.patch( router.patch(
"/:organizationId/name", "/:organizationId/name",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -93,7 +93,7 @@ router.patch(
router.get( router.get(
"/:organizationId/incidentContactOrg", "/:organizationId/incidentContactOrg",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -107,7 +107,7 @@ router.get(
router.post( router.post(
"/:organizationId/incidentContactOrg", "/:organizationId/incidentContactOrg",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -122,7 +122,7 @@ router.post(
router.delete( router.delete(
"/:organizationId/incidentContactOrg", "/:organizationId/incidentContactOrg",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -137,7 +137,7 @@ router.delete(
router.post( router.post(
"/:organizationId/customer-portal-session", "/:organizationId/customer-portal-session",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -151,7 +151,7 @@ router.post(
router.get( router.get(
"/:organizationId/subscriptions", "/:organizationId/subscriptions",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -165,7 +165,7 @@ router.get(
router.get( router.get(
"/:organizationId/workspace-memberships", "/:organizationId/workspace-memberships",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT]
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
+4 -6
View File
@@ -4,14 +4,12 @@ import { body } from "express-validator";
import { requireAuth, requireSignupAuth, validateRequest } from "../../middleware"; import { requireAuth, requireSignupAuth, validateRequest } from "../../middleware";
import { passwordController } from "../../controllers/v1"; import { passwordController } from "../../controllers/v1";
import { passwordLimiter } from "../../helpers/rateLimiter"; import { passwordLimiter } from "../../helpers/rateLimiter";
import { import { AuthMode } from "../../variables";
AUTH_MODE_JWT,
} from "../../variables";
router.post( router.post(
"/srp1", "/srp1",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("clientPublicKey").exists().isString().trim().notEmpty(), body("clientPublicKey").exists().isString().trim().notEmpty(),
validateRequest, validateRequest,
@@ -22,7 +20,7 @@ router.post(
"/change-password", "/change-password",
passwordLimiter, passwordLimiter,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("clientProof").exists().trim().notEmpty(), body("clientProof").exists().trim().notEmpty(),
body("protectedKey").exists().isString().trim().notEmpty(), body("protectedKey").exists().isString().trim().notEmpty(),
@@ -65,7 +63,7 @@ router.post(
"/backup-private-key", "/backup-private-key",
passwordLimiter, passwordLimiter,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("clientProof").exists().isString().trim().notEmpty(), body("clientProof").exists().isString().trim().notEmpty(),
body("encryptedPrivateKey").exists().isString().trim().notEmpty(), // (backup) private key encrypted under a strong key body("encryptedPrivateKey").exists().isString().trim().notEmpty(), // (backup) private key encrypted under a strong key
+4 -4
View File
@@ -10,8 +10,8 @@ import { body, param, query } from "express-validator";
import { secretController } from "../../controllers/v1"; import { secretController } from "../../controllers/v1";
import { import {
ADMIN, ADMIN,
AUTH_MODE_JWT, AuthMode,
MEMBER, MEMBER
} from "../../variables"; } from "../../variables";
// note to devs: these endpoints will be deprecated in favor of v2 // note to devs: these endpoints will be deprecated in favor of v2
@@ -19,7 +19,7 @@ import {
router.post( router.post(
"/:workspaceId", "/:workspaceId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -37,7 +37,7 @@ router.post(
router.get( router.get(
"/:workspaceId", "/:workspaceId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+6 -6
View File
@@ -3,12 +3,12 @@ const router = express.Router();
import { body, param, query } from "express-validator"; import { body, param, query } from "express-validator";
import { secretImportController } from "../../controllers/v1"; import { secretImportController } from "../../controllers/v1";
import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware"; import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware";
import { ADMIN, AUTH_MODE_JWT, MEMBER } from "../../variables"; import { ADMIN, AuthMode, MEMBER } from "../../variables";
router.post( router.post(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT] acceptedAuthModes: [AuthMode.JWT]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -27,7 +27,7 @@ router.post(
router.put( router.put(
"/:id", "/:id",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT] acceptedAuthModes: [AuthMode.JWT]
}), }),
param("id").exists().isString().trim(), param("id").exists().isString().trim(),
body("secretImports").exists().isArray(), body("secretImports").exists().isArray(),
@@ -40,7 +40,7 @@ router.put(
router.delete( router.delete(
"/:id", "/:id",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT] acceptedAuthModes: [AuthMode.JWT]
}), }),
param("id").exists().isString().trim(), param("id").exists().isString().trim(),
body("secretImportPath").isString().exists().trim(), body("secretImportPath").isString().exists().trim(),
@@ -52,7 +52,7 @@ router.delete(
router.get( router.get(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT] acceptedAuthModes: [AuthMode.JWT]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -68,7 +68,7 @@ router.get(
router.get( router.get(
"/secrets", "/secrets",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT] acceptedAuthModes: [AuthMode.JWT]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+5 -5
View File
@@ -12,12 +12,12 @@ import {
getFolders, getFolders,
updateFolderById, updateFolderById,
} from "../../controllers/v1/secretsFolderController"; } from "../../controllers/v1/secretsFolderController";
import { ADMIN, MEMBER } from "../../variables"; import { ADMIN, AuthMode, MEMBER } from "../../variables";
router.post( router.post(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -34,7 +34,7 @@ router.post(
router.patch( router.patch(
"/:folderId", "/:folderId",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("workspaceId").exists(), body("workspaceId").exists(),
body("environment").exists(), body("environment").exists(),
@@ -46,7 +46,7 @@ router.patch(
router.delete( router.delete(
"/:folderId", "/:folderId",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("workspaceId").exists(), body("workspaceId").exists(),
body("environment").exists(), body("environment").exists(),
@@ -58,7 +58,7 @@ router.delete(
router.get( router.get(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: ["jwt"], acceptedAuthModes: [AuthMode.JWT],
}), }),
query("workspaceId").exists().isString().trim(), query("workspaceId").exists().isString().trim(),
query("environment").exists().isString().trim(), query("environment").exists().isString().trim(),
+3 -3
View File
@@ -9,8 +9,8 @@ import {
import { body } from "express-validator"; import { body } from "express-validator";
import { import {
ADMIN, ADMIN,
AUTH_MODE_JWT, AuthMode,
MEMBER, MEMBER
} from "../../variables"; } from "../../variables";
import { serviceTokenController } from "../../controllers/v1"; import { serviceTokenController } from "../../controllers/v1";
@@ -25,7 +25,7 @@ router.get(
router.post( router.post(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+2 -4
View File
@@ -2,14 +2,12 @@ import express from "express";
const router = express.Router(); const router = express.Router();
import { requireAuth } from "../../middleware"; import { requireAuth } from "../../middleware";
import { userController } from "../../controllers/v1"; import { userController } from "../../controllers/v1";
import { import { AuthMode } from "../../variables";
AUTH_MODE_JWT,
} from "../../variables";
router.get( router.get(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
userController.getUser userController.getUser
); );
+3 -3
View File
@@ -3,13 +3,13 @@ const router = express.Router();
import { requireAuth, validateRequest } from "../../middleware"; import { requireAuth, validateRequest } from "../../middleware";
import { body, query } from "express-validator"; import { body, query } from "express-validator";
import { userActionController } from "../../controllers/v1"; import { userActionController } from "../../controllers/v1";
import { AUTH_MODE_JWT } from "../../variables"; import { AuthMode } from "../../variables";
// note: [userAction] will be deprecated in /v2 in favor of [action] // note: [userAction] will be deprecated in /v2 in favor of [action]
router.post( router.post(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("action"), body("action"),
validateRequest, validateRequest,
@@ -19,7 +19,7 @@ router.post(
router.get( router.get(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
query("action"), query("action"),
validateRequest, validateRequest,
+6 -6
View File
@@ -2,13 +2,13 @@ import express from "express";
const router = express.Router(); const router = express.Router();
import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware"; import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware";
import { body, param, query } from "express-validator"; import { body, param, query } from "express-validator";
import { ADMIN, AUTH_MODE_JWT, MEMBER } from "../../variables"; import { ADMIN, AuthMode, MEMBER } from "../../variables";
import { webhookController } from "../../controllers/v1"; import { webhookController } from "../../controllers/v1";
router.post( router.post(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT] acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -27,7 +27,7 @@ router.post(
router.patch( router.patch(
"/:webhookId", "/:webhookId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT] acceptedAuthModes: [AuthMode.JWT],
}), }),
param("webhookId").exists().isString().trim(), param("webhookId").exists().isString().trim(),
body("isDisabled").default(false).isBoolean(), body("isDisabled").default(false).isBoolean(),
@@ -38,7 +38,7 @@ router.patch(
router.post( router.post(
"/:webhookId/test", "/:webhookId/test",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT] acceptedAuthModes: [AuthMode.JWT],
}), }),
param("webhookId").exists().isString().trim(), param("webhookId").exists().isString().trim(),
validateRequest, validateRequest,
@@ -48,7 +48,7 @@ router.post(
router.delete( router.delete(
"/:webhookId", "/:webhookId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT] acceptedAuthModes: [AuthMode.JWT],
}), }),
param("webhookId").exists().isString().trim(), param("webhookId").exists().isString().trim(),
validateRequest, validateRequest,
@@ -58,7 +58,7 @@ router.delete(
router.get( router.get(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT] acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+13 -14
View File
@@ -8,16 +8,15 @@ import {
} from "../../middleware"; } from "../../middleware";
import { import {
ADMIN, ADMIN,
AUTH_MODE_API_KEY, AuthMode,
AUTH_MODE_JWT, MEMBER
MEMBER,
} from "../../variables"; } from "../../variables";
import { membershipController, workspaceController } from "../../controllers/v1"; import { membershipController, workspaceController } from "../../controllers/v1";
router.get( router.get(
"/:workspaceId/keys", "/:workspaceId/keys",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -31,7 +30,7 @@ router.get(
router.get( router.get(
"/:workspaceId/users", "/:workspaceId/users",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -45,7 +44,7 @@ router.get(
router.get( router.get(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
workspaceController.getWorkspaces workspaceController.getWorkspaces
); );
@@ -53,7 +52,7 @@ router.get(
router.get( router.get(
"/:workspaceId", "/:workspaceId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -67,7 +66,7 @@ router.get(
router.post( router.post(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("workspaceName").exists().trim().notEmpty(), body("workspaceName").exists().trim().notEmpty(),
body("organizationId").exists().trim().notEmpty(), body("organizationId").exists().trim().notEmpty(),
@@ -78,7 +77,7 @@ router.post(
router.delete( router.delete(
"/:workspaceId", "/:workspaceId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN], acceptedRoles: [ADMIN],
@@ -92,7 +91,7 @@ router.delete(
router.post( router.post(
"/:workspaceId/name", "/:workspaceId/name",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -107,7 +106,7 @@ router.post(
router.post( router.post(
"/:workspaceId/invite-signup", "/:workspaceId/invite-signup",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -122,7 +121,7 @@ router.post(
router.get( router.get(
"/:workspaceId/integrations", "/:workspaceId/integrations",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -136,7 +135,7 @@ router.get(
router.get( router.get(
"/:workspaceId/authorizations", "/:workspaceId/authorizations",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -150,7 +149,7 @@ router.get(
router.get( router.get(
"/:workspaceId/service-tokens", // deprecate "/:workspaceId/service-tokens", // deprecate
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+6 -6
View File
@@ -9,14 +9,14 @@ import {
} from "../../middleware"; } from "../../middleware";
import { import {
ADMIN, ADMIN,
AUTH_MODE_JWT, AuthMode,
MEMBER, MEMBER
} from "../../variables"; } from "../../variables";
router.post( router.post(
"/:workspaceId/environments", "/:workspaceId/environments",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -32,7 +32,7 @@ router.post(
router.put( router.put(
"/:workspaceId/environments", "/:workspaceId/environments",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -49,7 +49,7 @@ router.put(
router.delete( router.delete(
"/:workspaceId/environments", "/:workspaceId/environments",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN], acceptedRoles: [ADMIN],
@@ -64,7 +64,7 @@ router.delete(
router.get( router.get(
"/:workspaceId/environments", "/:workspaceId/environments",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [MEMBER, ADMIN], acceptedRoles: [MEMBER, ADMIN],
+7 -8
View File
@@ -10,10 +10,9 @@ import { body, param } from "express-validator";
import { import {
ACCEPTED, ACCEPTED,
ADMIN, ADMIN,
AUTH_MODE_API_KEY, AuthMode,
AUTH_MODE_JWT,
MEMBER, MEMBER,
OWNER, OWNER
} from "../../variables"; } from "../../variables";
import { organizationsController } from "../../controllers/v2"; import { organizationsController } from "../../controllers/v2";
@@ -24,7 +23,7 @@ router.get(
param("organizationId").exists().trim(), param("organizationId").exists().trim(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedRoles: [OWNER, ADMIN, MEMBER],
@@ -40,7 +39,7 @@ router.patch(
body("role").exists().isString().trim().isIn([OWNER, ADMIN, MEMBER]), body("role").exists().isString().trim().isIn([OWNER, ADMIN, MEMBER]),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN], acceptedRoles: [OWNER, ADMIN],
@@ -59,7 +58,7 @@ router.delete(
param("membershipId").exists().trim(), param("membershipId").exists().trim(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN], acceptedRoles: [OWNER, ADMIN],
@@ -77,7 +76,7 @@ router.get(
param("organizationId").exists().trim(), param("organizationId").exists().trim(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN], acceptedRoles: [OWNER, ADMIN],
@@ -91,7 +90,7 @@ router.get(
param("organizationId").exists().trim(), param("organizationId").exists().trim(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT]
}), }),
requireOrganizationAuth({ requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN], acceptedRoles: [OWNER, ADMIN],
+9 -10
View File
@@ -8,8 +8,7 @@ import {
import { body, param, query } from "express-validator"; import { body, param, query } from "express-validator";
import { import {
ADMIN, ADMIN,
AUTH_MODE_JWT, AuthMode,
AUTH_MODE_SERVICE_TOKEN,
MEMBER, MEMBER,
PERMISSION_READ_SECRETS, PERMISSION_READ_SECRETS,
PERMISSION_WRITE_SECRETS, PERMISSION_WRITE_SECRETS,
@@ -24,7 +23,7 @@ const router = express.Router();
router.post( router.post(
"/batch-create/workspace/:workspaceId/environment/:environment", "/batch-create/workspace/:workspaceId/environment/:environment",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -41,7 +40,7 @@ router.post(
router.post( router.post(
"/workspace/:workspaceId/environment/:environment", "/workspace/:workspaceId/environment/:environment",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -60,7 +59,7 @@ router.get(
param("workspaceId").exists().trim(), param("workspaceId").exists().trim(),
query("environment").exists(), query("environment").exists(),
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_TOKEN], acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -74,7 +73,7 @@ router.get(
router.get( router.get(
"/:secretId", "/:secretId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_TOKEN], acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN],
}), }),
requireSecretAuth({ requireSecretAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -87,7 +86,7 @@ router.get(
router.delete( router.delete(
"/batch/workspace/:workspaceId/environment/:environmentName", "/batch/workspace/:workspaceId/environment/:environmentName",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
param("workspaceId").exists().isMongoId().trim(), param("workspaceId").exists().isMongoId().trim(),
param("environmentName").exists().trim(), param("environmentName").exists().trim(),
@@ -103,7 +102,7 @@ router.delete(
router.delete( router.delete(
"/:secretId", "/:secretId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireSecretAuth({ requireSecretAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -117,7 +116,7 @@ router.delete(
router.patch( router.patch(
"/batch-modify/workspace/:workspaceId/environment/:environmentName", "/batch-modify/workspace/:workspaceId/environment/:environmentName",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("secrets").exists().isArray().custom((secrets: ModifySecretRequestBody[]) => secrets.length > 0), body("secrets").exists().isArray().custom((secrets: ModifySecretRequestBody[]) => secrets.length > 0),
param("workspaceId").exists().isMongoId().trim(), param("workspaceId").exists().isMongoId().trim(),
@@ -133,7 +132,7 @@ router.patch(
router.patch( router.patch(
"/workspace/:workspaceId/environment/:environmentName", "/workspace/:workspaceId/environment/:environmentName",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
body("secret").isObject(), body("secret").isObject(),
param("workspaceId").exists().isMongoId().trim(), param("workspaceId").exists().isMongoId().trim(),
+6 -14
View File
@@ -12,10 +12,7 @@ import { body, query } from "express-validator";
import { secretsController } from "../../controllers/v2"; import { secretsController } from "../../controllers/v2";
import { import {
ADMIN, ADMIN,
AUTH_MODE_API_KEY, AuthMode,
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
MEMBER, MEMBER,
PERMISSION_READ_SECRETS, PERMISSION_READ_SECRETS,
PERMISSION_WRITE_SECRETS, PERMISSION_WRITE_SECRETS,
@@ -27,7 +24,7 @@ import { BatchSecretRequest } from "../../types/secret";
router.post( router.post(
"/batch", "/batch",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -109,7 +106,7 @@ router.post(
}), }),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -130,12 +127,7 @@ router.get(
query("include_imports").optional().default(false).isBoolean(), query("include_imports").optional().default(false).isBoolean(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [ acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
AUTH_MODE_JWT,
AUTH_MODE_API_KEY,
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_SERVICE_ACCOUNT
]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -172,7 +164,7 @@ router.patch(
}), }),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireSecretsAuth({ requireSecretsAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -201,7 +193,7 @@ router.delete(
.isEmpty(), .isEmpty(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireSecretsAuth({ requireSecretsAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+145 -146
View File
@@ -1,159 +1,158 @@
import express from "express"; import express from "express";
const router = express.Router(); const router = express.Router();
import { // import {
requireAuth, // requireAuth,
requireOrganizationAuth, // requireOrganizationAuth,
requireServiceAccountAuth, // requireServiceAccountAuth,
requireServiceAccountWorkspacePermissionAuth, // requireServiceAccountWorkspacePermissionAuth,
requireWorkspaceAuth, // requireWorkspaceAuth,
validateRequest, // validateRequest,
} from "../../middleware"; // } from "../../middleware";
import { body, param, query } from "express-validator"; // import { body, param, query } from "express-validator";
import { // import {
ACCEPTED, // ACCEPTED,
ADMIN, // ADMIN,
AUTH_MODE_JWT, // MEMBER,
AUTH_MODE_SERVICE_ACCOUNT, // OWNER,
MEMBER, // AuthMode
OWNER, // } from "../../variables";
} from "../../variables"; // import { serviceAccountsController } from "../../controllers/v2";
import { serviceAccountsController } from "../../controllers/v2";
router.get( // TODO: check // router.get( // TODO: check
"/me", // "/me",
requireAuth({ // requireAuth({
acceptedAuthModes: [AUTH_MODE_SERVICE_ACCOUNT], // acceptedAuthModes: [AUTH_MODE_SERVICE_ACCOUNT],
}), // }),
serviceAccountsController.getCurrentServiceAccount // serviceAccountsController.getCurrentServiceAccount
); // );
router.get( // router.get(
"/:serviceAccountId", // "/:serviceAccountId",
param("serviceAccountId").exists().isString().trim(), // param("serviceAccountId").exists().isString().trim(),
requireAuth({ // requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], // acceptedAuthModes: [AUTH_MODE_JWT],
}), // }),
requireServiceAccountAuth({ // requireServiceAccountAuth({
acceptedRoles: [OWNER, ADMIN], // acceptedRoles: [OWNER, ADMIN],
acceptedStatuses: [ACCEPTED], // acceptedStatuses: [ACCEPTED],
}), // }),
serviceAccountsController.getServiceAccountById // serviceAccountsController.getServiceAccountById
); // );
router.post( // router.post(
"/", // "/",
body("organizationId").exists().isString().trim(), // body("organizationId").exists().isString().trim(),
body("name").exists().isString().trim(), // body("name").exists().isString().trim(),
body("publicKey").exists().isString().trim(), // body("publicKey").exists().isString().trim(),
body("expiresIn").isNumeric(), // measured in ms // body("expiresIn").isNumeric(), // measured in ms
validateRequest, // validateRequest,
requireAuth({ // requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], // acceptedAuthModes: [AUTH_MODE_JWT],
}), // }),
requireOrganizationAuth({ // requireOrganizationAuth({
acceptedRoles: [OWNER, ADMIN, MEMBER], // acceptedRoles: [OWNER, ADMIN, MEMBER],
acceptedStatuses: [ACCEPTED], // acceptedStatuses: [ACCEPTED],
locationOrganizationId: "body", // locationOrganizationId: "body",
}), // }),
serviceAccountsController.createServiceAccount // serviceAccountsController.createServiceAccount
); // );
router.patch( // router.patch(
"/:serviceAccountId/name", // "/:serviceAccountId/name",
param("serviceAccountId").exists().isString().trim(), // param("serviceAccountId").exists().isString().trim(),
validateRequest, // validateRequest,
requireAuth({ // requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], // acceptedAuthModes: [AUTH_MODE_JWT],
}), // }),
requireServiceAccountAuth({ // requireServiceAccountAuth({
acceptedRoles: [OWNER, ADMIN], // acceptedRoles: [OWNER, ADMIN],
acceptedStatuses: [ACCEPTED], // acceptedStatuses: [ACCEPTED],
}), // }),
serviceAccountsController.changeServiceAccountName // serviceAccountsController.changeServiceAccountName
); // );
router.delete( // router.delete(
"/:serviceAccountId", // "/:serviceAccountId",
param("serviceAccountId").exists().isString().trim(), // param("serviceAccountId").exists().isString().trim(),
validateRequest, // validateRequest,
requireAuth({ // requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], // acceptedAuthModes: [AUTH_MODE_JWT],
}), // }),
requireServiceAccountAuth({ // requireServiceAccountAuth({
acceptedRoles: [OWNER, ADMIN], // acceptedRoles: [OWNER, ADMIN],
acceptedStatuses: [ACCEPTED], // acceptedStatuses: [ACCEPTED],
}), // }),
serviceAccountsController.deleteServiceAccount // serviceAccountsController.deleteServiceAccount
); // );
router.get( // router.get(
"/:serviceAccountId/permissions/workspace", // "/:serviceAccountId/permissions/workspace",
param("serviceAccountId").exists().isString().trim(), // param("serviceAccountId").exists().isString().trim(),
validateRequest, // validateRequest,
requireAuth({ // requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], // acceptedAuthModes: [AUTH_MODE_JWT],
}), // }),
requireServiceAccountAuth({ // requireServiceAccountAuth({
acceptedRoles: [OWNER, ADMIN], // acceptedRoles: [OWNER, ADMIN],
acceptedStatuses: [ACCEPTED], // acceptedStatuses: [ACCEPTED],
}), // }),
serviceAccountsController.getServiceAccountWorkspacePermissions // serviceAccountsController.getServiceAccountWorkspacePermissions
); // );
router.post( // router.post(
"/:serviceAccountId/permissions/workspace", // "/:serviceAccountId/permissions/workspace",
param("serviceAccountId").exists().isString().trim(), // param("serviceAccountId").exists().isString().trim(),
body("workspaceId").exists().isString().notEmpty(), // body("workspaceId").exists().isString().notEmpty(),
body("environment").exists().isString().notEmpty(), // body("environment").exists().isString().notEmpty(),
body("read").isBoolean().optional(), // body("read").isBoolean().optional(),
body("write").isBoolean().optional(), // body("write").isBoolean().optional(),
body("encryptedKey").exists().isString().notEmpty(), // body("encryptedKey").exists().isString().notEmpty(),
body("nonce").exists().isString().notEmpty(), // body("nonce").exists().isString().notEmpty(),
validateRequest, // validateRequest,
requireAuth({ // requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], // acceptedAuthModes: [AUTH_MODE_JWT],
}), // }),
requireServiceAccountAuth({ // requireServiceAccountAuth({
acceptedRoles: [OWNER, ADMIN], // acceptedRoles: [OWNER, ADMIN],
acceptedStatuses: [ACCEPTED], // acceptedStatuses: [ACCEPTED],
}), // }),
requireWorkspaceAuth({ // requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], // acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body", // locationWorkspaceId: "body",
}), // }),
serviceAccountsController.addServiceAccountWorkspacePermission // serviceAccountsController.addServiceAccountWorkspacePermission
); // );
router.delete( // router.delete(
"/:serviceAccountId/permissions/workspace/:serviceAccountWorkspacePermissionId", // "/:serviceAccountId/permissions/workspace/:serviceAccountWorkspacePermissionId",
param("serviceAccountId").exists().isString().trim(), // param("serviceAccountId").exists().isString().trim(),
param("serviceAccountWorkspacePermissionId").exists().isString().trim(), // param("serviceAccountWorkspacePermissionId").exists().isString().trim(),
validateRequest, // validateRequest,
requireAuth({ // requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], // acceptedAuthModes: [AUTH_MODE_JWT],
}), // }),
requireServiceAccountAuth({ // requireServiceAccountAuth({
acceptedRoles: [OWNER, ADMIN], // acceptedRoles: [OWNER, ADMIN],
acceptedStatuses: [ACCEPTED], // acceptedStatuses: [ACCEPTED],
}), // }),
requireServiceAccountWorkspacePermissionAuth({ // requireServiceAccountWorkspacePermissionAuth({
acceptedRoles: [OWNER, ADMIN], // acceptedRoles: [OWNER, ADMIN],
acceptedStatuses: [ACCEPTED], // acceptedStatuses: [ACCEPTED],
}), // }),
serviceAccountsController.deleteServiceAccountWorkspacePermission // serviceAccountsController.deleteServiceAccountWorkspacePermission
); // );
router.get( // router.get(
"/:serviceAccountId/keys", // "/:serviceAccountId/keys",
query("workspaceId").optional().isString(), // query("workspaceId").optional().isString(),
requireAuth({ // requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_ACCOUNT], // acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_ACCOUNT],
}), // }),
requireServiceAccountAuth({ // requireServiceAccountAuth({
acceptedRoles: [OWNER, ADMIN], // acceptedRoles: [OWNER, ADMIN],
acceptedStatuses: [ACCEPTED], // acceptedStatuses: [ACCEPTED],
}), // }),
serviceAccountsController.getServiceAccountKeys // serviceAccountsController.getServiceAccountKeys
); // );
export default router; export default router;
+4 -6
View File
@@ -9,9 +9,7 @@ import {
import { body, param } from "express-validator"; import { body, param } from "express-validator";
import { import {
ADMIN, ADMIN,
AUTH_MODE_JWT, AuthMode,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
MEMBER, MEMBER,
PERMISSION_WRITE_SECRETS PERMISSION_WRITE_SECRETS
} from "../../variables"; } from "../../variables";
@@ -20,7 +18,7 @@ import { serviceTokenDataController } from "../../controllers/v2";
router.get( router.get(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_SERVICE_TOKEN] acceptedAuthModes: [AuthMode.SERVICE_TOKEN]
}), }),
serviceTokenDataController.getServiceTokenData serviceTokenDataController.getServiceTokenData
); );
@@ -28,7 +26,7 @@ router.get(
router.post( router.post(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_ACCOUNT] acceptedAuthModes: [AuthMode.JWT]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -63,7 +61,7 @@ router.post(
router.delete( router.delete(
"/:serviceTokenDataId", "/:serviceTokenDataId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT] acceptedAuthModes: [AuthMode.JWT]
}), }),
requireServiceTokenDataAuth({ requireServiceTokenDataAuth({
acceptedRoles: [ADMIN, MEMBER] acceptedRoles: [ADMIN, MEMBER]
+5 -5
View File
@@ -9,14 +9,14 @@ import {
} from "../../middleware"; } from "../../middleware";
import { import {
ADMIN, ADMIN,
AUTH_MODE_JWT, AuthMode,
MEMBER, MEMBER
} from "../../variables"; } from "../../variables";
router.get( router.get(
"/:workspaceId/tags", "/:workspaceId/tags",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [MEMBER, ADMIN], acceptedRoles: [MEMBER, ADMIN],
@@ -30,7 +30,7 @@ router.get(
router.delete( router.delete(
"/tags/:tagId", "/tags/:tagId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
param("tagId").exists().trim(), param("tagId").exists().trim(),
validateRequest, validateRequest,
@@ -40,7 +40,7 @@ router.delete(
router.post( router.post(
"/:workspaceId/tags", "/:workspaceId/tags",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [MEMBER, ADMIN], acceptedRoles: [MEMBER, ADMIN],
+11 -14
View File
@@ -6,10 +6,7 @@ import {
} from "../../middleware"; } from "../../middleware";
import { body, param } from "express-validator"; import { body, param } from "express-validator";
import { usersController } from "../../controllers/v2"; import { usersController } from "../../controllers/v2";
import { import { AuthMode } from "../../variables";
AUTH_MODE_API_KEY,
AUTH_MODE_JWT,
} from "../../variables";
import { import {
AuthProvider AuthProvider
} from "../../models"; } from "../../models";
@@ -17,7 +14,7 @@ import {
router.get( router.get(
"/me", "/me",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
usersController.getMe usersController.getMe
); );
@@ -25,7 +22,7 @@ router.get(
router.patch( router.patch(
"/me/mfa", "/me/mfa",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
body("isMfaEnabled").exists().isBoolean(), body("isMfaEnabled").exists().isBoolean(),
validateRequest, validateRequest,
@@ -35,7 +32,7 @@ router.patch(
router.patch( router.patch(
"/me/name", "/me/name",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
body("firstName").exists().isString(), body("firstName").exists().isString(),
body("lastName").isString(), body("lastName").isString(),
@@ -46,7 +43,7 @@ router.patch(
router.patch( router.patch(
"/me/auth-provider", "/me/auth-provider",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
body("authProvider").exists().isString().isIn([ body("authProvider").exists().isString().isIn([
AuthProvider.EMAIL, AuthProvider.EMAIL,
@@ -60,7 +57,7 @@ router.patch(
router.get( router.get(
"/me/organizations", "/me/organizations",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
usersController.getMyOrganizations usersController.getMyOrganizations
); );
@@ -68,7 +65,7 @@ router.get(
router.get( router.get(
"/me/api-keys", "/me/api-keys",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT]
}), }),
usersController.getMyAPIKeys usersController.getMyAPIKeys
); );
@@ -76,7 +73,7 @@ router.get(
router.post( router.post(
"/me/api-keys", "/me/api-keys",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT]
}), }),
body("name").exists().isString().trim(), body("name").exists().isString().trim(),
body("expiresIn").isNumeric(), body("expiresIn").isNumeric(),
@@ -87,7 +84,7 @@ router.post(
router.delete( router.delete(
"/me/api-keys/:apiKeyDataId", "/me/api-keys/:apiKeyDataId",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT]
}), }),
param("apiKeyDataId").exists().trim(), param("apiKeyDataId").exists().trim(),
validateRequest, validateRequest,
@@ -97,7 +94,7 @@ router.delete(
router.get( router.get(
"/me/sessions", "/me/sessions",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT]
}), }),
usersController.getMySessions usersController.getMySessions
); );
@@ -105,7 +102,7 @@ router.get(
router.delete( router.delete(
"/me/sessions", "/me/sessions",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT]
}), }),
usersController.deleteMySessions usersController.deleteMySessions
); );
+10 -12
View File
@@ -9,17 +9,15 @@ import {
} from "../../middleware"; } from "../../middleware";
import { import {
ADMIN, ADMIN,
AUTH_MODE_API_KEY, AuthMode,
AUTH_MODE_JWT, MEMBER
AUTH_MODE_SERVICE_TOKEN,
MEMBER,
} from "../../variables"; } from "../../variables";
import { workspaceController } from "../../controllers/v2"; import { workspaceController } from "../../controllers/v2";
router.post( router.post(
"/:workspaceId/secrets", "/:workspaceId/secrets",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -37,7 +35,7 @@ router.post(
router.get( router.get(
"/:workspaceId/secrets", "/:workspaceId/secrets",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_TOKEN], acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -53,7 +51,7 @@ router.get(
router.get( router.get(
"/:workspaceId/encrypted-key", "/:workspaceId/encrypted-key",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -67,7 +65,7 @@ router.get(
router.get( router.get(
"/:workspaceId/service-token-data", "/:workspaceId/service-token-data",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -83,7 +81,7 @@ router.get( // new - TODO: rewire dashboard to this route
param("workspaceId").exists().trim(), param("workspaceId").exists().trim(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
@@ -99,7 +97,7 @@ router.patch( // TODO - rewire dashboard to this route
body("role").exists().isString().trim().isIn([ADMIN, MEMBER]), body("role").exists().isString().trim().isIn([ADMIN, MEMBER]),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN], acceptedRoles: [ADMIN],
@@ -118,7 +116,7 @@ router.delete( // TODO - rewire dashboard to this route
param("membershipId").exists().trim(), param("membershipId").exists().trim(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY], acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN], acceptedRoles: [ADMIN],
@@ -134,7 +132,7 @@ router.delete( // TODO - rewire dashboard to this route
router.patch( router.patch(
"/:workspaceId/auto-capitalization", "/:workspaceId/auto-capitalization",
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
+31 -44
View File
@@ -5,10 +5,7 @@ import { body, param, query } from "express-validator";
import { secretsController } from "../../controllers/v3"; import { secretsController } from "../../controllers/v3";
import { import {
ADMIN, ADMIN,
AUTH_MODE_API_KEY, AuthMode,
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
MEMBER, MEMBER,
PERMISSION_READ_SECRETS, PERMISSION_READ_SECRETS,
PERMISSION_WRITE_SECRETS, PERMISSION_WRITE_SECRETS,
@@ -25,10 +22,9 @@ router.get(
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [ acceptedAuthModes: [
AUTH_MODE_JWT, AuthMode.JWT,
AUTH_MODE_API_KEY, AuthMode.API_KEY,
AUTH_MODE_SERVICE_TOKEN, AuthMode.SERVICE_TOKEN
AUTH_MODE_SERVICE_ACCOUNT
] ]
}), }),
secretsController.getSecretsRaw secretsController.getSecretsRaw
@@ -44,10 +40,9 @@ router.get(
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [ acceptedAuthModes: [
AUTH_MODE_JWT, AuthMode.JWT,
AUTH_MODE_API_KEY, AuthMode.API_KEY,
AUTH_MODE_SERVICE_TOKEN, AuthMode.SERVICE_TOKEN
AUTH_MODE_SERVICE_ACCOUNT
] ]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
@@ -73,10 +68,9 @@ router.post(
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [ acceptedAuthModes: [
AUTH_MODE_JWT, AuthMode.JWT,
AUTH_MODE_API_KEY, AuthMode.API_KEY,
AUTH_MODE_SERVICE_TOKEN, AuthMode.SERVICE_TOKEN
AUTH_MODE_SERVICE_ACCOUNT
] ]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
@@ -102,10 +96,9 @@ router.patch(
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [ acceptedAuthModes: [
AUTH_MODE_JWT, AuthMode.JWT,
AUTH_MODE_API_KEY, AuthMode.API_KEY,
AUTH_MODE_SERVICE_TOKEN, AuthMode.SERVICE_TOKEN
AUTH_MODE_SERVICE_ACCOUNT
] ]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
@@ -130,10 +123,9 @@ router.delete(
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [ acceptedAuthModes: [
AUTH_MODE_JWT, AuthMode.JWT,
AUTH_MODE_API_KEY, AuthMode.API_KEY,
AUTH_MODE_SERVICE_TOKEN, AuthMode.SERVICE_TOKEN
AUTH_MODE_SERVICE_ACCOUNT
] ]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
@@ -156,10 +148,9 @@ router.get(
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [ acceptedAuthModes: [
AUTH_MODE_JWT, AuthMode.JWT,
AUTH_MODE_API_KEY, AuthMode.API_KEY,
AUTH_MODE_SERVICE_TOKEN, AuthMode.SERVICE_TOKEN
AUTH_MODE_SERVICE_ACCOUNT
] ]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
@@ -192,10 +183,9 @@ router.post(
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [ acceptedAuthModes: [
AUTH_MODE_JWT, AuthMode.JWT,
AUTH_MODE_API_KEY, AuthMode.API_KEY,
AUTH_MODE_SERVICE_TOKEN, AuthMode.SERVICE_TOKEN
AUTH_MODE_SERVICE_ACCOUNT
] ]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
@@ -220,10 +210,9 @@ router.get(
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [ acceptedAuthModes: [
AUTH_MODE_JWT, AuthMode.JWT,
AUTH_MODE_API_KEY, AuthMode.API_KEY,
AUTH_MODE_SERVICE_TOKEN, AuthMode.SERVICE_TOKEN
AUTH_MODE_SERVICE_ACCOUNT
] ]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
@@ -250,10 +239,9 @@ router.patch(
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [ acceptedAuthModes: [
AUTH_MODE_JWT, AuthMode.JWT,
AUTH_MODE_API_KEY, AuthMode.API_KEY,
AUTH_MODE_SERVICE_TOKEN, AuthMode.SERVICE_TOKEN
AUTH_MODE_SERVICE_ACCOUNT
] ]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
@@ -278,10 +266,9 @@ router.delete(
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [ acceptedAuthModes: [
AUTH_MODE_JWT, AuthMode.JWT,
AUTH_MODE_API_KEY, AuthMode.API_KEY,
AUTH_MODE_SERVICE_TOKEN, AuthMode.SERVICE_TOKEN
AUTH_MODE_SERVICE_ACCOUNT
] ]
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
+4 -4
View File
@@ -8,7 +8,7 @@ import {
import { workspacesController } from "../../controllers/v3"; import { workspacesController } from "../../controllers/v3";
import { import {
ADMIN, ADMIN,
AUTH_MODE_JWT, AuthMode
} from "../../variables"; } from "../../variables";
import { body, param } from "express-validator"; import { body, param } from "express-validator";
@@ -19,7 +19,7 @@ router.get(
param("workspaceId").exists().isString().trim(), param("workspaceId").exists().isString().trim(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN], acceptedRoles: [ADMIN],
@@ -33,7 +33,7 @@ router.get( // allow admins to get all workspace secrets (part of blind indices
param("workspaceId").exists().isString().trim(), param("workspaceId").exists().isString().trim(),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN], acceptedRoles: [ADMIN],
@@ -65,7 +65,7 @@ router.post( // allow admins to name all workspace secrets (part of blind indice
.withMessage("secretId must be a string"), .withMessage("secretId must be a string"),
validateRequest, validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT], acceptedAuthModes: [AuthMode.JWT],
}), }),
requireWorkspaceAuth({ requireWorkspaceAuth({
acceptedRoles: [ADMIN], acceptedRoles: [ADMIN],
+16 -1
View File
@@ -1,6 +1,7 @@
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { Types } from "mongoose"; import { Types } from "mongoose";
import Folder, { TFolderSchema } from "../models/folder"; import Folder, { TFolderRootSchema, TFolderSchema } from "../models/folder";
import { ResourceNotFoundError } from "../utils/errors";
type TAppendFolderDTO = { type TAppendFolderDTO = {
folderName: string; folderName: string;
@@ -172,6 +173,20 @@ export const searchByFolderIdWithDir = (
return; return;
}; };
export const getFolderPath = (
folders: TFolderRootSchema,
folderId: string
) => {
const folderBySearch = searchByFolderIdWithDir(folders.nodes, folderId);
if (!folderBySearch) throw ResourceNotFoundError({
message: "Failed to find folder"
});
const folderPath = folderBySearch.dir.map((folder) => folder.name).join("/");
return folderPath;
}
// to get folder of a path given // to get folder of a path given
// Like /frontend/folder#1 // Like /frontend/folder#1
export const getFolderByPath = (folders: TFolderSchema, searchPath: string) => { export const getFolderByPath = (folders: TFolderSchema, searchPath: string) => {
+1 -3
View File
@@ -1,8 +1,6 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { import {
AuthData, AuthData
} from "../../interfaces/middleware"; } from "../../interfaces/middleware";
declare module "express" { declare module "express" {
+1
View File
@@ -30,6 +30,7 @@ export interface BatchSecretRequest {
export interface BatchSecret { export interface BatchSecret {
_id: string; _id: string;
type: "shared" | "personal"; type: "shared" | "personal";
secretName: string;
secretBlindIndex: string; secretBlindIndex: string;
secretKeyCiphertext: string; secretKeyCiphertext: string;
secretKeyIV: string; secretKeyIV: string;
+10 -10
View File
@@ -1,15 +1,15 @@
const CLI_USER_AGENT_NAME = "cli" import { UserAgentType } from "../ee/models"
const K8_OPERATOR_AGENT_NAME = "k8-operator"
export const getChannelFromUserAgent = function (userAgent: string | undefined) { export const getUserAgentType = function (userAgent: string | undefined) {
if (userAgent == undefined) { if (userAgent == undefined) {
return "other" return UserAgentType.OTHER;
} else if (userAgent == CLI_USER_AGENT_NAME) { } else if (userAgent == UserAgentType.CLI) {
return "cli" return UserAgentType.CLI;
} else if (userAgent == K8_OPERATOR_AGENT_NAME) { } else if (userAgent == UserAgentType.K8_OPERATOR) {
return "k8-operator" return UserAgentType.K8_OPERATOR;
} else if (userAgent.toLowerCase().includes("mozilla")) { } else if (userAgent.toLowerCase().includes("mozilla")) {
return "web" return UserAgentType.WEB;
} else { } else {
return "other" return UserAgentType.OTHER;
} }
} }
+16 -67
View File
@@ -1,25 +1,15 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { import {
Bot, Bot,
IServiceAccount,
IServiceTokenData,
IUser, IUser,
ServiceAccount,
ServiceTokenData,
User,
} from "../models"; } from "../models";
import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
import { validateUserClientForWorkspace } from "./user"; import { validateUserClientForWorkspace } from "./user";
import { import {
BotNotFoundError, BotNotFoundError,
UnauthorizedRequestError, UnauthorizedRequestError,
} from "../utils/errors"; } from "../utils/errors";
import { import { AuthData } from "../interfaces/middleware";
AUTH_MODE_API_KEY, import { ActorType } from "../ee/models";
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
} from "../variables";
/** /**
* Validate authenticated clients for bot with id [botId] based * Validate authenticated clients for bot with id [botId] based
@@ -34,65 +24,24 @@ export const validateClientForBot = async ({
botId, botId,
acceptedRoles, acceptedRoles,
}: { }: {
authData: { authData: AuthData;
authMode: string;
authPayload: IUser | IServiceAccount | IServiceTokenData;
};
botId: Types.ObjectId; botId: Types.ObjectId;
acceptedRoles: Array<"admin" | "member">; acceptedRoles: Array<"admin" | "member">;
}) => { }) => {
const bot = await Bot.findById(botId); const bot = await Bot.findById(botId);
if (!bot) throw BotNotFoundError(); if (!bot) throw BotNotFoundError();
if ( switch (authData.actor.type) {
authData.authMode === AUTH_MODE_JWT && case ActorType.USER:
authData.authPayload instanceof User await validateUserClientForWorkspace({
) { user: authData.authPayload as IUser,
await validateUserClientForWorkspace({ workspaceId: bot.workspace,
user: authData.authPayload, acceptedRoles,
workspaceId: bot.workspace, });
acceptedRoles, return bot;
}); case ActorType.SERVICE:
throw UnauthorizedRequestError({
return bot; message: "Failed service token authorization for bot",
});
} }
if (
authData.authMode === AUTH_MODE_SERVICE_ACCOUNT &&
authData.authPayload instanceof ServiceAccount
) {
await validateServiceAccountClientForWorkspace({
serviceAccount: authData.authPayload,
workspaceId: bot.workspace,
});
return bot;
}
if (
authData.authMode === AUTH_MODE_SERVICE_TOKEN &&
authData.authPayload instanceof ServiceTokenData
) {
throw UnauthorizedRequestError({
message: "Failed service token authorization for bot",
});
}
if (
authData.authMode === AUTH_MODE_API_KEY &&
authData.authPayload instanceof User
) {
await validateUserClientForWorkspace({
user: authData.authPayload,
workspaceId: bot.workspace,
acceptedRoles,
});
return bot;
}
throw BotNotFoundError({
message: "Failed client authorization for bot",
});
}; };
+15 -52
View File
@@ -1,15 +1,9 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { import {
IServiceAccount,
IServiceTokenData,
IUser, IUser,
Integration, Integration,
IntegrationAuth, IntegrationAuth,
ServiceAccount,
ServiceTokenData,
User,
} from "../models"; } from "../models";
import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
import { validateUserClientForWorkspace } from "./user"; import { validateUserClientForWorkspace } from "./user";
import { IntegrationService } from "../services"; import { IntegrationService } from "../services";
import { import {
@@ -17,12 +11,8 @@ import {
IntegrationNotFoundError, IntegrationNotFoundError,
UnauthorizedRequestError, UnauthorizedRequestError,
} from "../utils/errors"; } from "../utils/errors";
import { import { AuthData } from "../interfaces/middleware";
AUTH_MODE_API_KEY, import { ActorType } from "../ee/models";
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
} from "../variables";
/** /**
* Validate authenticated clients for integration with id [integrationId] based * Validate authenticated clients for integration with id [integrationId] based
@@ -39,10 +29,7 @@ export const validateClientForIntegration = async ({
integrationId, integrationId,
acceptedRoles, acceptedRoles,
}: { }: {
authData: { authData: AuthData;
authMode: string;
authPayload: IUser | IServiceAccount | IServiceTokenData;
};
integrationId: Types.ObjectId; integrationId: Types.ObjectId;
acceptedRoles: Array<"admin" | "member">; acceptedRoles: Array<"admin" | "member">;
}) => { }) => {
@@ -61,43 +48,19 @@ export const validateClientForIntegration = async ({
const accessToken = (await IntegrationService.getIntegrationAuthAccess({ const accessToken = (await IntegrationService.getIntegrationAuthAccess({
integrationAuthId: integrationAuth._id, integrationAuthId: integrationAuth._id,
})).accessToken; })).accessToken;
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
await validateUserClientForWorkspace({
user: authData.authPayload,
workspaceId: integration.workspace,
acceptedRoles,
});
return ({ integration, accessToken });
}
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) { switch (authData.actor.type) {
await validateServiceAccountClientForWorkspace({ case ActorType.USER:
serviceAccount: authData.authPayload, await validateUserClientForWorkspace({
workspaceId: integration.workspace, user: authData.authPayload as IUser,
}); workspaceId: integration.workspace,
acceptedRoles,
});
return ({ integration, accessToken }); return ({ integration, accessToken });
case ActorType.SERVICE:
throw UnauthorizedRequestError({
message: "Failed service token authorization for integration",
});
} }
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
throw UnauthorizedRequestError({
message: "Failed service token authorization for integration",
});
}
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
await validateUserClientForWorkspace({
user: authData.authPayload,
workspaceId: integration.workspace,
acceptedRoles,
});
return ({ integration, accessToken });
}
throw UnauthorizedRequestError({
message: "Failed client authorization for integration",
});
} }
+15 -52
View File
@@ -1,27 +1,17 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { import {
IServiceAccount,
IServiceTokenData,
IUser, IUser,
IWorkspace, IWorkspace,
IntegrationAuth, IntegrationAuth,
ServiceAccount,
ServiceTokenData,
User,
} from "../models"; } from "../models";
import {
AUTH_MODE_API_KEY,
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
} from "../variables";
import { import {
IntegrationAuthNotFoundError, IntegrationAuthNotFoundError,
UnauthorizedRequestError, UnauthorizedRequestError,
} from "../utils/errors"; } from "../utils/errors";
import { IntegrationService } from "../services"; import { IntegrationService } from "../services";
import { validateUserClientForWorkspace } from "./user"; import { validateUserClientForWorkspace } from "./user";
import { validateServiceAccountClientForWorkspace } from "./serviceAccount"; import { AuthData } from "../interfaces/middleware";
import { ActorType } from "../ee/models";
/** /**
* Validate authenticated clients for integration authorization with id [integrationAuthId] based * Validate authenticated clients for integration authorization with id [integrationAuthId] based
@@ -38,10 +28,7 @@ import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
acceptedRoles, acceptedRoles,
attachAccessToken, attachAccessToken,
}: { }: {
authData: { authData: AuthData;
authMode: string;
authPayload: IUser | IServiceAccount | IServiceTokenData;
};
integrationAuthId: Types.ObjectId; integrationAuthId: Types.ObjectId;
acceptedRoles: Array<"admin" | "member">; acceptedRoles: Array<"admin" | "member">;
attachAccessToken?: boolean; attachAccessToken?: boolean;
@@ -66,44 +53,20 @@ import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
accessId = access.accessId; accessId = access.accessId;
} }
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) { switch (authData.actor.type) {
await validateUserClientForWorkspace({ case ActorType.USER:
user: authData.authPayload, await validateUserClientForWorkspace({
workspaceId: integrationAuth.workspace._id, user: authData.authPayload as IUser,
acceptedRoles, workspaceId: integrationAuth.workspace._id,
}); acceptedRoles,
});
return ({ integrationAuth, accessToken, accessId }); return ({ integrationAuth, accessToken, accessId });
case ActorType.SERVICE:
throw UnauthorizedRequestError({
message: "Failed service token authorization for integration authorization",
});
} }
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) {
await validateServiceAccountClientForWorkspace({
serviceAccount: authData.authPayload,
workspaceId: integrationAuth.workspace._id,
});
return ({ integrationAuth, accessToken, accessId });
}
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
throw UnauthorizedRequestError({
message: "Failed service token authorization for integration authorization",
});
}
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
await validateUserClientForWorkspace({
user: authData.authPayload,
workspaceId: integrationAuth.workspace._id,
acceptedRoles,
});
return ({ integrationAuth, accessToken, accessId });
}
throw UnauthorizedRequestError({
message: "Failed client authorization for integration authorization",
});
} }
export { export {
+19 -56
View File
@@ -1,26 +1,16 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { import {
IServiceAccount,
IServiceTokenData, IServiceTokenData,
IUser, IUser,
Membership, Membership,
ServiceAccount,
ServiceTokenData,
User,
} from "../models"; } from "../models";
import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
import { validateUserClientForWorkspace } from "./user"; import { validateUserClientForWorkspace } from "./user";
import { validateServiceTokenDataClientForWorkspace } from "./serviceTokenData"; import { validateServiceTokenDataClientForWorkspace } from "./serviceTokenData";
import { import {
MembershipNotFoundError, MembershipNotFoundError,
UnauthorizedRequestError,
} from "../utils/errors"; } from "../utils/errors";
import { import { AuthData } from "../interfaces/middleware";
AUTH_MODE_API_KEY, import { ActorType } from "../ee/models";
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
} from "../variables";
/** /**
* Validate authenticated clients for membership with id [membershipId] based * Validate authenticated clients for membership with id [membershipId] based
@@ -36,10 +26,7 @@ export const validateClientForMembership = async ({
membershipId, membershipId,
acceptedRoles, acceptedRoles,
}: { }: {
authData: { authData: AuthData;
authMode: string;
authPayload: IUser | IServiceAccount | IServiceTokenData;
};
membershipId: Types.ObjectId; membershipId: Types.ObjectId;
acceptedRoles: Array<"admin" | "member">; acceptedRoles: Array<"admin" | "member">;
}) => { }) => {
@@ -49,46 +36,22 @@ export const validateClientForMembership = async ({
if (!membership) throw MembershipNotFoundError({ if (!membership) throw MembershipNotFoundError({
message: "Failed to find membership", message: "Failed to find membership",
}); });
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
await validateUserClientForWorkspace({
user: authData.authPayload,
workspaceId: membership.workspace,
acceptedRoles,
});
return membership;
}
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) { switch (authData.actor.type) {
await validateServiceAccountClientForWorkspace({ case ActorType.USER:
serviceAccount: authData.authPayload, await validateUserClientForWorkspace({
workspaceId: membership.workspace, user: authData.authPayload as IUser,
}); workspaceId: membership.workspace,
acceptedRoles,
return membership; });
return membership;
case ActorType.SERVICE:
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: authData.authPayload as IServiceTokenData,
workspaceId: new Types.ObjectId(membership.workspace),
});
return membership;
} }
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: authData.authPayload,
workspaceId: new Types.ObjectId(membership.workspace),
});
return membership;
}
if (authData.authMode == AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
await validateUserClientForWorkspace({
user: authData.authPayload,
workspaceId: membership.workspace,
acceptedRoles,
});
return membership;
}
throw UnauthorizedRequestError({
message: "Failed client authorization for membership",
});
} }
+17 -54
View File
@@ -1,12 +1,6 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { import {
IServiceAccount,
IServiceTokenData,
IUser,
MembershipOrg, MembershipOrg,
ServiceAccount,
ServiceTokenData,
User,
} from "../models"; } from "../models";
import { import {
validateMembershipOrg, validateMembershipOrg,
@@ -15,12 +9,8 @@ import {
MembershipOrgNotFoundError, MembershipOrgNotFoundError,
UnauthorizedRequestError, UnauthorizedRequestError,
} from "../utils/errors"; } from "../utils/errors";
import { import { AuthData } from "../interfaces/middleware";
AUTH_MODE_API_KEY, import { ActorType } from "../ee/models";
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
} from "../variables";
/** /**
* Validate authenticated clients for organization membership with id [membershipOrgId] based * Validate authenticated clients for organization membership with id [membershipOrgId] based
@@ -37,10 +27,7 @@ export const validateClientForMembershipOrg = async ({
acceptedRoles, acceptedRoles,
acceptedStatuses, acceptedStatuses,
}: { }: {
authData: { authData: AuthData;
authMode: string;
authPayload: IUser | IServiceAccount | IServiceTokenData;
};
membershipOrgId: Types.ObjectId; membershipOrgId: Types.ObjectId;
acceptedRoles: Array<"owner" | "admin" | "member">; acceptedRoles: Array<"owner" | "admin" | "member">;
acceptedStatuses: Array<"invited" | "accepted">; acceptedStatuses: Array<"invited" | "accepted">;
@@ -50,44 +37,20 @@ export const validateClientForMembershipOrg = async ({
if (!membershipOrg) throw MembershipOrgNotFoundError({ if (!membershipOrg) throw MembershipOrgNotFoundError({
message: "Failed to find organization membership ", message: "Failed to find organization membership ",
}); });
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
await validateMembershipOrg({
userId: authData.authPayload._id,
organizationId: membershipOrg.organization,
acceptedRoles,
acceptedStatuses,
});
return membershipOrg;
}
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) {
if (!authData.authPayload.organization.equals(membershipOrg.organization)) throw UnauthorizedRequestError({
message: "Failed service account client authorization for organization membership",
});
return membershipOrg;
}
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
throw UnauthorizedRequestError({
message: "Failed service account client authorization for organization membership",
});
}
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) { switch (authData.actor.type) {
await validateMembershipOrg({ case ActorType.USER:
userId: authData.authPayload._id, await validateMembershipOrg({
organizationId: membershipOrg.organization, userId: authData.authPayload._id,
acceptedRoles, organizationId: membershipOrg.organization,
acceptedStatuses, acceptedRoles,
}); acceptedStatuses,
});
return membershipOrg;
return membershipOrg;
case ActorType.SERVICE:
throw UnauthorizedRequestError({
message: "Failed service account client authorization for organization membership",
});
} }
throw UnauthorizedRequestError({
message: "Failed client authorization for organization membership",
});
} }
+18 -67
View File
@@ -1,25 +1,15 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { import {
IServiceAccount,
IServiceTokenData,
IUser, IUser,
Organization, Organization,
ServiceAccount,
ServiceTokenData,
User,
} from "../models"; } from "../models";
import {
AUTH_MODE_API_KEY,
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
} from "../variables";
import { import {
OrganizationNotFoundError, OrganizationNotFoundError,
UnauthorizedRequestError, UnauthorizedRequestError,
} from "../utils/errors"; } from "../utils/errors";
import { validateUserClientForOrganization } from "./user"; import { validateUserClientForOrganization } from "./user";
import { validateServiceAccountClientForOrganization } from "./serviceAccount"; import { AuthData } from "../interfaces/middleware";
import { ActorType } from "../ee/models";
/** /**
* Validate accepted clients for organization with id [organizationId] * Validate accepted clients for organization with id [organizationId]
@@ -33,10 +23,7 @@ export const validateClientForOrganization = async ({
acceptedRoles, acceptedRoles,
acceptedStatuses, acceptedStatuses,
}: { }: {
authData: { authData: AuthData;
authMode: string;
authPayload: IUser | IServiceAccount | IServiceTokenData;
};
organizationId: Types.ObjectId; organizationId: Types.ObjectId;
acceptedRoles: Array<"owner" | "admin" | "member">; acceptedRoles: Array<"owner" | "admin" | "member">;
acceptedStatuses: Array<"invited" | "accepted">; acceptedStatuses: Array<"invited" | "accepted">;
@@ -48,57 +35,21 @@ export const validateClientForOrganization = async ({
message: "Failed to find organization", message: "Failed to find organization",
}); });
} }
let membershipOrg;
switch (authData.actor.type) {
case ActorType.USER:
membershipOrg = await validateUserClientForOrganization({
user: authData.authPayload as IUser,
organization,
acceptedRoles,
acceptedStatuses,
});
if ( return { organization, membershipOrg };
authData.authMode === AUTH_MODE_JWT && case ActorType.SERVICE:
authData.authPayload instanceof User throw UnauthorizedRequestError({
) { message: "Failed service token authorization for organization",
const membershipOrg = await validateUserClientForOrganization({ });
user: authData.authPayload,
organization,
acceptedRoles,
acceptedStatuses,
});
return { organization, membershipOrg };
} }
if (
authData.authMode === AUTH_MODE_SERVICE_ACCOUNT &&
authData.authPayload instanceof ServiceAccount
) {
await validateServiceAccountClientForOrganization({
serviceAccount: authData.authPayload,
organization,
});
return { organization };
}
if (
authData.authMode === AUTH_MODE_SERVICE_TOKEN &&
authData.authPayload instanceof ServiceTokenData
) {
throw UnauthorizedRequestError({
message: "Failed service token authorization for organization",
});
}
if (
authData.authMode === AUTH_MODE_API_KEY &&
authData.authPayload instanceof User
) {
const membershipOrg = await validateUserClientForOrganization({
user: authData.authPayload,
organization,
acceptedRoles,
acceptedStatuses,
});
return { organization, membershipOrg };
}
throw UnauthorizedRequestError({
message: "Failed client authorization for organization",
});
}; };
+38 -98
View File
@@ -1,26 +1,18 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { import {
ISecret, ISecret,
IServiceTokenData,
IUser,
Secret, Secret,
ServiceAccount,
ServiceTokenData,
User,
} from "../models"; } from "../models";
import { validateServiceAccountClientForSecrets, validateServiceAccountClientForWorkspace } from "./serviceAccount";
import { validateUserClientForSecret, validateUserClientForSecrets } from "./user"; import { validateUserClientForSecret, validateUserClientForSecrets } from "./user";
import { validateServiceTokenDataClientForSecrets, validateServiceTokenDataClientForWorkspace } from "./serviceTokenData"; import { validateServiceTokenDataClientForSecrets, validateServiceTokenDataClientForWorkspace } from "./serviceTokenData";
import { AuthData } from "../interfaces/middleware";
import { import {
BadRequestError, BadRequestError,
SecretNotFoundError, SecretNotFoundError,
UnauthorizedRequestError,
} from "../utils/errors"; } from "../utils/errors";
import { import { AuthData } from "../interfaces/middleware";
AUTH_MODE_API_KEY, import { ActorType } from "../ee/models";
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
} from "../variables";
/** /**
* Validate authenticated clients for secrets with id [secretId] based * Validate authenticated clients for secrets with id [secretId] based
@@ -47,53 +39,26 @@ export const validateClientForSecret = async ({
if (!secret) throw SecretNotFoundError({ if (!secret) throw SecretNotFoundError({
message: "Failed to find secret", message: "Failed to find secret",
}); });
switch (authData.actor.type) {
case ActorType.USER:
await validateUserClientForSecret({
user: authData.authPayload as IUser,
secret,
acceptedRoles,
requiredPermissions,
});
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) { return secret;
await validateUserClientForSecret({ case ActorType.SERVICE:
user: authData.authPayload, await validateServiceTokenDataClientForWorkspace({
secret, serviceTokenData: authData.authPayload as IServiceTokenData,
acceptedRoles, workspaceId: secret.workspace,
requiredPermissions, environment: secret.environment,
}); });
return secret;
}
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) {
await validateServiceAccountClientForWorkspace({
serviceAccount: authData.authPayload,
workspaceId: secret.workspace,
environment: secret.environment,
requiredPermissions,
});
return secret; return secret;
} }
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: authData.authPayload,
workspaceId: secret.workspace,
environment: secret.environment,
});
return secret;
}
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
await validateUserClientForSecret({
user: authData.authPayload,
secret,
acceptedRoles,
requiredPermissions,
});
return secret;
}
throw UnauthorizedRequestError({
message: "Failed client authorization for secret",
});
} }
/** /**
@@ -127,48 +92,23 @@ export const validateClientForSecrets = async ({
if (secrets.length != secretIds.length) { if (secrets.length != secretIds.length) {
throw BadRequestError({ message: "Failed to validate non-existent secrets" }) throw BadRequestError({ message: "Failed to validate non-existent secrets" })
} }
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
await validateUserClientForSecrets({
user: authData.authPayload,
secrets,
requiredPermissions,
});
return secrets;
}
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) { switch (authData.actor.type) {
await validateServiceAccountClientForSecrets({ case ActorType.USER:
serviceAccount: authData.authPayload, await validateUserClientForSecrets({
secrets, user: authData.authPayload as IUser,
requiredPermissions, secrets,
}); requiredPermissions,
});
return secrets;
return secrets;
case ActorType.SERVICE:
await validateServiceTokenDataClientForSecrets({
serviceTokenData: authData.authPayload as IServiceTokenData,
secrets,
requiredPermissions,
});
return secrets;
} }
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
await validateServiceTokenDataClientForSecrets({
serviceTokenData: authData.authPayload,
secrets,
requiredPermissions,
});
return secrets;
}
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
await validateUserClientForSecrets({
user: authData.authPayload,
secrets,
requiredPermissions,
});
return secrets;
}
throw UnauthorizedRequestError({
message: "Failed client authorization for secrets resource",
});
} }
+16 -49
View File
@@ -4,12 +4,9 @@ import {
IOrganization, IOrganization,
ISecret, ISecret,
IServiceAccount, IServiceAccount,
IServiceTokenData,
IUser, IUser,
ServiceAccount, ServiceAccount,
ServiceAccountWorkspacePermission, ServiceAccountWorkspacePermission,
ServiceTokenData,
User,
} from "../models"; } from "../models";
import { validateUserClientForServiceAccount } from "./user"; import { validateUserClientForServiceAccount } from "./user";
import { import {
@@ -18,23 +15,18 @@ import {
UnauthorizedRequestError, UnauthorizedRequestError,
} from "../utils/errors"; } from "../utils/errors";
import { import {
AUTH_MODE_API_KEY,
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
PERMISSION_READ_SECRETS, PERMISSION_READ_SECRETS,
PERMISSION_WRITE_SECRETS, PERMISSION_WRITE_SECRETS,
} from "../variables"; } from "../variables";
import { AuthData } from "../interfaces/middleware";
import { ActorType } from "../ee/models";
export const validateClientForServiceAccount = async ({ export const validateClientForServiceAccount = async ({
authData, authData,
serviceAccountId, serviceAccountId,
requiredPermissions, requiredPermissions,
}: { }: {
authData: { authData: AuthData;
authMode: string;
authPayload: IUser | IServiceAccount | IServiceTokenData;
},
serviceAccountId: Types.ObjectId; serviceAccountId: Types.ObjectId;
requiredPermissions?: string[]; requiredPermissions?: string[];
}) => { }) => {
@@ -46,45 +38,20 @@ export const validateClientForServiceAccount = async ({
}); });
} }
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) { switch (authData.actor.type) {
await validateUserClientForServiceAccount({ case ActorType.USER:
user: authData.authPayload, await validateUserClientForServiceAccount({
serviceAccount, user: authData.authPayload as IUser,
requiredPermissions, serviceAccount,
}); requiredPermissions,
});
return serviceAccount;
return serviceAccount;
case ActorType.SERVICE:
throw UnauthorizedRequestError({
message: "Failed service token authorization for service account resource",
});
} }
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) {
await validateServiceAccountClientForServiceAccount({
serviceAccount: authData.authPayload,
targetServiceAccount: serviceAccount,
requiredPermissions,
});
return serviceAccount;
}
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
throw UnauthorizedRequestError({
message: "Failed service token authorization for service account resource",
});
}
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
await validateUserClientForServiceAccount({
user: authData.authPayload,
serviceAccount,
requiredPermissions,
});
return serviceAccount;
}
throw UnauthorizedRequestError({
message: "Failed client authorization for service account resource",
});
} }
/** /**
+20 -62
View File
@@ -1,22 +1,14 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { import {
ISecret, ISecret,
IServiceAccount,
IServiceTokenData, IServiceTokenData,
IUser, IUser,
ServiceAccount,
ServiceTokenData, ServiceTokenData,
User
} from "../models"; } from "../models";
import { ServiceTokenDataNotFoundError, UnauthorizedRequestError } from "../utils/errors"; import { ServiceTokenDataNotFoundError, UnauthorizedRequestError } from "../utils/errors";
import {
AUTH_MODE_API_KEY,
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN
} from "../variables";
import { validateUserClientForWorkspace } from "./user"; import { validateUserClientForWorkspace } from "./user";
import { validateServiceAccountClientForWorkspace } from "./serviceAccount"; import { ActorType } from "../ee/models";
import { AuthData } from "../interfaces/middleware";
/** /**
* Validate authenticated clients for service token with id [serviceTokenId] based * Validate authenticated clients for service token with id [serviceTokenId] based
@@ -31,10 +23,7 @@ export const validateClientForServiceTokenData = async ({
serviceTokenDataId, serviceTokenDataId,
acceptedRoles acceptedRoles
}: { }: {
authData: { authData: AuthData;
authMode: string;
authPayload: IUser | IServiceAccount | IServiceTokenData;
};
serviceTokenDataId: Types.ObjectId; serviceTokenDataId: Types.ObjectId;
acceptedRoles: Array<"admin" | "member">; acceptedRoles: Array<"admin" | "member">;
}) => { }) => {
@@ -42,55 +31,24 @@ export const validateClientForServiceTokenData = async ({
.select("+encryptedKey +iv +tag") .select("+encryptedKey +iv +tag")
.populate<{ user: IUser }>("user"); .populate<{ user: IUser }>("user");
if (!serviceTokenData) if (!serviceTokenData) throw ServiceTokenDataNotFoundError({
throw ServiceTokenDataNotFoundError({ message: "Failed to find service token data"
message: "Failed to find service token data"
});
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
await validateUserClientForWorkspace({
user: authData.authPayload,
workspaceId: serviceTokenData.workspace,
acceptedRoles
});
return serviceTokenData;
}
if (
authData.authMode === AUTH_MODE_SERVICE_ACCOUNT &&
authData.authPayload instanceof ServiceAccount
) {
await validateServiceAccountClientForWorkspace({
serviceAccount: authData.authPayload,
workspaceId: serviceTokenData.workspace
});
return serviceTokenData;
}
if (
authData.authMode === AUTH_MODE_SERVICE_TOKEN &&
authData.authPayload instanceof ServiceTokenData
) {
throw UnauthorizedRequestError({
message: "Failed service token authorization for service token data"
});
}
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
await validateUserClientForWorkspace({
user: authData.authPayload,
workspaceId: serviceTokenData.workspace,
acceptedRoles
});
return serviceTokenData;
}
throw UnauthorizedRequestError({
message: "Failed client authorization for service token data"
}); });
switch (authData.actor.type) {
case ActorType.USER:
await validateUserClientForWorkspace({
user: authData.authPayload as IUser,
workspaceId: serviceTokenData.workspace,
acceptedRoles
});
return serviceTokenData;
case ActorType.SERVICE:
throw UnauthorizedRequestError({
message: "Failed service token authorization for service token data"
});
}
}; };
/** /**
+54 -90
View File
@@ -1,16 +1,15 @@
import net from "net"; import net from "net";
import { Types } from "mongoose"; import { Types } from "mongoose";
import { import {
SecretBlindIndexData, IServiceTokenData,
ServiceAccount, IUser,
ServiceTokenData, SecretBlindIndexData,
User,
Workspace, Workspace,
} from "../models"; } from "../models";
import { import {
ActorType,
TrustedIP TrustedIP
} from "../ee/models"; } from "../ee/models";
import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
import { validateUserClientForWorkspace } from "./user"; import { validateUserClientForWorkspace } from "./user";
import { validateServiceTokenDataClientForWorkspace } from "./serviceTokenData"; import { validateServiceTokenDataClientForWorkspace } from "./serviceTokenData";
import { import {
@@ -18,12 +17,6 @@ import {
UnauthorizedRequestError, UnauthorizedRequestError,
WorkspaceNotFoundError, WorkspaceNotFoundError,
} from "../utils/errors"; } from "../utils/errors";
import {
AUTH_MODE_API_KEY,
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
} from "../variables";
import { BotService } from "../services"; import { BotService } from "../services";
import { AuthData } from "../interfaces/middleware"; import { AuthData } from "../interfaces/middleware";
import { extractIPDetails } from "../utils/ip"; import { extractIPDetails } from "../utils/ip";
@@ -85,89 +78,60 @@ export const validateClientForWorkspace = async ({
}); });
} }
let membership;
switch (authData.actor.type) {
case ActorType.USER:
membership = await validateUserClientForWorkspace({
user: authData.authPayload as IUser,
workspaceId,
environment,
acceptedRoles,
requiredPermissions,
});
return ({ membership, workspace });
case ActorType.SERVICE:
if (checkIPAllowlist) {
const trustedIps = await TrustedIP.find({
workspace: workspaceId
});
if (trustedIps.length > 0) {
// case: check the IP address of the inbound request against trusted IPs
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) { const blockList = new net.BlockList();
const membership = await validateUserClientForWorkspace({
user: authData.authPayload,
workspaceId,
environment,
acceptedRoles,
requiredPermissions,
});
return ({ membership, workspace }); for (const trustedIp of trustedIps) {
} if (trustedIp.prefix !== undefined) {
blockList.addSubnet(
trustedIp.ipAddress,
trustedIp.prefix,
trustedIp.type
);
} else {
blockList.addAddress(
trustedIp.ipAddress,
trustedIp.type
);
}
}
const { type } = extractIPDetails(authData.ipAddress);
const check = blockList.check(authData.ipAddress, type);
if (!check) throw UnauthorizedRequestError({
message: "Failed workspace authorization"
});
}
}
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) { await validateServiceTokenDataClientForWorkspace({
await validateServiceAccountClientForWorkspace({ serviceTokenData: authData.authPayload as IServiceTokenData,
serviceAccount: authData.authPayload, workspaceId,
workspaceId, environment,
environment, requiredPermissions,
requiredPermissions,
});
return {};
}
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
if (checkIPAllowlist) {
const trustedIps = await TrustedIP.find({
workspace: workspaceId
}); });
if (trustedIps.length > 0) { return {};
// case: check the IP address of the inbound request against trusted IPs
const blockList = new net.BlockList();
for (const trustedIp of trustedIps) {
if (trustedIp.prefix !== undefined) {
blockList.addSubnet(
trustedIp.ipAddress,
trustedIp.prefix,
trustedIp.type
);
} else {
blockList.addAddress(
trustedIp.ipAddress,
trustedIp.type
);
}
}
const { type } = extractIPDetails(authData.authIP);
const check = blockList.check(authData.authIP, type);
if (!check) throw UnauthorizedRequestError({
message: "Failed workspace authorization"
});
}
}
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: authData.authPayload,
workspaceId,
environment,
requiredPermissions,
});
return {};
} }
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
const membership = await validateUserClientForWorkspace({
user: authData.authPayload,
workspaceId,
environment,
acceptedRoles,
requiredPermissions,
});
return ({ membership, workspace });
}
throw UnauthorizedRequestError({
message: "Failed client authorization for workspace",
});
} }
+5 -4
View File
@@ -1,4 +1,5 @@
export const AUTH_MODE_JWT = "jwt"; export enum AuthMode {
export const AUTH_MODE_SERVICE_ACCOUNT = "serviceAccount"; JWT = "jwt",
export const AUTH_MODE_SERVICE_TOKEN = "serviceToken"; SERVICE_TOKEN = "serviceToken",
export const AUTH_MODE_API_KEY = "apiKey"; // TODO: deprecate API_KEY = "apiKey"
}
@@ -21,7 +21,7 @@ export type PaginationProps = {
perPage?: number; perPage?: number;
onChangePage: (pageNumber: number) => void; onChangePage: (pageNumber: number) => void;
onChangePerPage: (newRows: number) => void; onChangePerPage: (newRows: number) => void;
className: string; className?: string;
perPageList?: number[]; perPageList?: number[];
}; };
@@ -44,18 +44,18 @@ export const Pagination = ({
return ( return (
<div <div
className={twMerge( className={twMerge(
"flex items-center justify-end text-white w-full p-4 bg-mineshaft-700", "flex items-center justify-end text-white w-full py-3 px-4 bg-mineshaft-800",
className className
)} )}
> >
<div className="mr-6 flex items-center space-x-2"> <div className="mr-6 flex items-center space-x-2">
<div className="text-sm"> <div className="text-xs">
{(page - 1) * perPage} - {(page - 1) * perPage + perPage} of {count} {(page - 1) * perPage} - {(page - 1) * perPage + perPage} of {count}
</div> </div>
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<IconButton ariaLabel="per-page-list" variant="plain"> <IconButton ariaLabel="per-page-list" variant="plain">
<FontAwesomeIcon icon={faCaretDown} /> <FontAwesomeIcon className="text-xs" icon={faCaretDown} />
</IconButton> </IconButton>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className="min-w-fit"> <DropdownMenuContent className="min-w-fit">
@@ -79,7 +79,7 @@ export const Pagination = ({
onClick={() => onChangePage(prevPageNumber)} onClick={() => onChangePage(prevPageNumber)}
isDisabled={!canGoPrev} isDisabled={!canGoPrev}
> >
<FontAwesomeIcon icon={faChevronLeft} /> <FontAwesomeIcon className="text-xs" icon={faChevronLeft} />
</IconButton> </IconButton>
<IconButton <IconButton
variant="plain" variant="plain"
@@ -87,7 +87,7 @@ export const Pagination = ({
onClick={() => onChangePage(nextPageNumber)} onClick={() => onChangePage(nextPageNumber)}
isDisabled={!canGoNext} isDisabled={!canGoNext}
> >
<FontAwesomeIcon icon={faChevronRight} /> <FontAwesomeIcon className="text-xs" icon={faChevronRight} />
</IconButton> </IconButton>
</div> </div>
</div> </div>
+1 -1
View File
@@ -40,7 +40,7 @@ export const Select = forwardRef<HTMLButtonElement, SelectProps>(
ref={ref} ref={ref}
className={twMerge( className={twMerge(
`inline-flex items-center justify-between rounded-md `inline-flex items-center justify-between rounded-md
bg-mineshaft-900 px-3 py-2 font-inter text-sm font-normal text-bunker-200 outline-none data-[placeholder]:text-gray-500`, bg-mineshaft-900 px-3 py-2 font-inter text-sm font-normal text-bunker-200 outline-none data-[placeholder]:text-mineshaft-200`,
className className
)} )}
> >
@@ -1,3 +1,4 @@
// TODO: deprecate in favor of new audit logs
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Image from "next/image"; import Image from "next/image";
@@ -1,3 +1,5 @@
// TODO: deprecate in favor of new audit logs
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -0,0 +1,42 @@
import { EventType, UserAgentType } from "./enums";
export const eventToNameMap: { [K in EventType]: string } = {
[EventType.GET_SECRETS]: "List secrets",
[EventType.GET_SECRET]: "Read secret",
[EventType.CREATE_SECRET]: "Create secret",
[EventType.UPDATE_SECRET]: "Update secret",
[EventType.DELETE_SECRET]: "Delete secret",
[EventType.GET_WORKSPACE_KEY]: "Read project key",
[EventType.AUTHORIZE_INTEGRATION]: "Authorize integration",
[EventType.UNAUTHORIZE_INTEGRATION]: "Unauthorize integration",
[EventType.CREATE_INTEGRATION]: "Create integration",
[EventType.DELETE_INTEGRATION]: "Delete integration",
[EventType.ADD_TRUSTED_IP]: "Add trusted IP",
[EventType.UPDATE_TRUSTED_IP]: "Update trusted IP",
[EventType.DELETE_TRUSTED_IP]: "Delete trusted IP",
[EventType.CREATE_SERVICE_TOKEN]: "Create service token",
[EventType.DELETE_SERVICE_TOKEN]: "Delete service token",
[EventType.CREATE_ENVIRONMENT]: "Create environment",
[EventType.UPDATE_ENVIRONMENT]: "Update environment",
[EventType.DELETE_ENVIRONMENT]: "Delete environment",
[EventType.ADD_WORKSPACE_MEMBER]: "Add member",
[EventType.REMOVE_WORKSPACE_MEMBER]: "Remove member",
[EventType.CREATE_FOLDER]: "Create folder",
[EventType.UPDATE_FOLDER]: "Update folder",
[EventType.DELETE_FOLDER]: "Delete folder",
[EventType.CREATE_WEBHOOK]: "Create webhook",
[EventType.UPDATE_WEBHOOK_STATUS]: "Update webhook status",
[EventType.DELETE_WEBHOOK]: "Delete webhook",
[EventType.GET_SECRET_IMPORTS]: "List secret imports",
[EventType.CREATE_SECRET_IMPORT]: "Create secret import",
[EventType.UPDATE_SECRET_IMPORT]: "Update secret import",
[EventType.DELETE_SECRET_IMPORT]: "Delete secret import",
};
export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = {
[UserAgentType.WEB]: "Web",
[UserAgentType.CLI]: "CLI",
[UserAgentType.K8_OPERATOR]: "K8s operator",
[UserAgentType.OTHER]: "Other",
};
@@ -0,0 +1,44 @@
export enum ActorType {
USER = "user",
SERVICE = "service"
}
export enum UserAgentType {
WEB = "web",
CLI = "cli",
K8_OPERATOR = "k8-operator",
OTHER = "other"
}
export enum EventType {
GET_SECRETS = "get-secrets",
GET_SECRET = "get-secret",
CREATE_SECRET = "create-secret",
UPDATE_SECRET = "update-secret",
DELETE_SECRET = "delete-secret",
GET_WORKSPACE_KEY = "get-workspace-key",
AUTHORIZE_INTEGRATION = "authorize-integration",
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
CREATE_INTEGRATION = "create-integration",
DELETE_INTEGRATION = "delete-integration",
ADD_TRUSTED_IP = "add-trusted-ip",
UPDATE_TRUSTED_IP = "update-trusted-ip",
DELETE_TRUSTED_IP = "delete-trusted-ip",
CREATE_SERVICE_TOKEN = "create-service-token",
DELETE_SERVICE_TOKEN = "delete-service-token",
CREATE_ENVIRONMENT = "create-environment",
UPDATE_ENVIRONMENT = "update-environment",
DELETE_ENVIRONMENT = "delete-environment",
ADD_WORKSPACE_MEMBER = "add-workspace-member",
REMOVE_WORKSPACE_MEMBER = "remove-workspace-member",
CREATE_FOLDER = "create-folder",
UPDATE_FOLDER = "update-folder",
DELETE_FOLDER = "delete-folder",
CREATE_WEBHOOK = "create-webhook",
UPDATE_WEBHOOK_STATUS = "update-webhook-status",
DELETE_WEBHOOK = "delete-webhook",
GET_SECRET_IMPORTS = "get-secret-imports",
CREATE_SECRET_IMPORT = "create-secret-import",
UPDATE_SECRET_IMPORT = "update-secret-import",
DELETE_SECRET_IMPORT = "delete-secret-import"
}
@@ -0,0 +1 @@
export * from "./queries";
@@ -0,0 +1,59 @@
import { useQuery } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import {
Actor,
AuditLog,
AuditLogFilters
} from "./types";
export const workspaceKeys = {
getAuditLogs: (workspaceId: string, filters: AuditLogFilters) => [{ workspaceId, filters }, "audit-logs"] as const,
getAuditLogActorFilterOpts: (workspaceId: string) => [{ workspaceId }, "audit-log-actor-filters"] as const
}
export const useGetAuditLogs = (workspaceId: string, filters: AuditLogFilters) => {
return useQuery({
queryKey: workspaceKeys.getAuditLogs(workspaceId, filters),
queryFn: async () => {
const params = new URLSearchParams();
if (filters.eventType) {
params.append("eventType", filters.eventType);
}
if (filters.userAgentType) {
params.append("userAgentType", filters.userAgentType);
}
if (filters.actor) {
params.append("actor", filters.actor);
}
if (filters.startDate) {
params.append("startDate", filters.startDate.toISOString());
}
if (filters.endDate) {
params.append("endDate", filters.endDate.toISOString());
}
params.append("offset", String(filters.offset));
params.append("limit", String(filters.limit));
const { data } = await apiRequest.get<{ auditLogs: AuditLog[], totalCount: number }>(`/api/v1/workspace/${workspaceId}/audit-logs`, { params });
return data;
}
});
}
export const useGetAuditLogActorFilterOpts = (workspaceId: string) => {
return useQuery({
queryKey: workspaceKeys.getAuditLogActorFilterOpts(workspaceId),
queryFn: async () => {
const { data } = await apiRequest.get<{ actors: Actor[] }>(`/api/v1/workspace/${workspaceId}/audit-logs/filters/actors`);
return data.actors;
}
});
}
+404
View File
@@ -0,0 +1,404 @@
import {
ActorType,
EventType,
UserAgentType
} from "./enums";
interface UserActorMetadata {
userId: string;
email: string;
}
interface ServiceActorMetadata {
serviceId: string;
name: string;
}
interface UserActor {
type: ActorType.USER;
metadata: UserActorMetadata;
}
export interface ServiceActor {
type: ActorType.SERVICE;
metadata: ServiceActorMetadata;
}
export type Actor =
| UserActor
| ServiceActor;
interface GetSecretsEvent {
type: EventType.GET_SECRETS;
metadata: {
environment: string;
secretPath: string;
numberOfSecrets: number;
};
}
interface GetSecretEvent {
type: EventType.GET_SECRET;
metadata: {
environment: string;
secretPath: string;
secretId: string;
secretKey: string;
secretVersion: number;
};
}
interface CreateSecretEvent {
type: EventType.CREATE_SECRET;
metadata: {
environment: string;
secretPath: string;
secretId: string;
secretKey: string;
secretVersion: number;
}
}
interface UpdateSecretEvent {
type: EventType.UPDATE_SECRET;
metadata: {
environment: string;
secretPath: string;
secretId: string;
secretKey: string;
secretVersion: number;
}
}
interface DeleteSecretEvent {
type: EventType.DELETE_SECRET;
metadata: {
environment: string;
secretPath: string;
secretId: string;
secretKey: string;
secretVersion: number;
}
}
interface GetWorkspaceKeyEvent {
type: EventType.GET_WORKSPACE_KEY,
metadata: {
keyId: string;
}
}
interface AuthorizeIntegrationEvent {
type: EventType.AUTHORIZE_INTEGRATION;
metadata: {
integration: string;
}
}
interface UnauthorizeIntegrationEvent {
type: EventType.UNAUTHORIZE_INTEGRATION;
metadata: {
integration: string;
}
}
interface CreateIntegrationEvent {
type: EventType.CREATE_INTEGRATION;
metadata: {
integrationId: string;
integration: string;
environment: string;
secretPath: string;
url?: string;
app?: string;
appId?: string;
targetEnvironment?: string;
targetEnvironmentId?: string;
targetService?: string;
targetServiceId?: string;
path?: string;
region?: string;
}
}
interface DeleteIntegrationEvent {
type: EventType.DELETE_INTEGRATION;
metadata: {
integrationId: string;
integration: string;
environment: string;
secretPath: string;
url?: string;
app?: string;
appId?: string;
targetEnvironment?: string;
targetEnvironmentId?: string;
targetService?: string;
targetServiceId?: string;
path?: string;
region?: string;
}
}
interface AddTrustedIPEvent {
type: EventType.ADD_TRUSTED_IP;
metadata: {
trustedIpId: string;
ipAddress: string;
prefix?: number;
}
}
interface UpdateTrustedIPEvent {
type: EventType.UPDATE_TRUSTED_IP;
metadata: {
trustedIpId: string;
ipAddress: string;
prefix?: number;
}
}
interface DeleteTrustedIPEvent {
type: EventType.DELETE_TRUSTED_IP;
metadata: {
trustedIpId: string;
ipAddress: string;
prefix?: number;
}
}
interface CreateServiceTokenEvent {
type: EventType.CREATE_SERVICE_TOKEN;
metadata: {
name: string;
scopes: Array<{
environment: string;
secretPath: string;
}>;
}
}
interface DeleteServiceTokenEvent {
type: EventType.DELETE_SERVICE_TOKEN;
metadata: {
name: string;
scopes: Array<{
environment: string;
secretPath: string;
}>;
}
}
interface CreateEnvironmentEvent {
type: EventType.CREATE_ENVIRONMENT;
metadata: {
name: string;
slug: string;
}
}
interface UpdateEnvironmentEvent {
type: EventType.UPDATE_ENVIRONMENT;
metadata: {
oldName: string;
newName: string;
oldSlug: string;
newSlug: string;
}
}
interface DeleteEnvironmentEvent {
type: EventType.DELETE_ENVIRONMENT;
metadata: {
name: string;
slug: string;
}
}
interface AddWorkspaceMemberEvent {
type: EventType.ADD_WORKSPACE_MEMBER;
metadata: {
userId: string;
email: string;
}
}
interface RemoveWorkspaceMemberEvent {
type: EventType.REMOVE_WORKSPACE_MEMBER;
metadata: {
userId: string;
email: string;
}
}
interface CreateFolderEvent {
type: EventType.CREATE_FOLDER;
metadata: {
environment: string;
folderId: string;
folderName: string;
folderPath: string;
}
}
interface UpdateFolderEvent {
type: EventType.UPDATE_FOLDER;
metadata: {
environment: string;
folderId: string;
oldFolderName: string;
newFolderName: string;
folderPath: string;
}
}
interface DeleteFolderEvent {
type: EventType.DELETE_FOLDER;
metadata: {
environment: string;
folderId: string;
folderName: string;
folderPath: string;
}
}
interface CreateWebhookEvent {
type: EventType.CREATE_WEBHOOK,
metadata: {
webhookId: string;
environment: string;
secretPath: string;
webhookUrl: string;
isDisabled: boolean;
}
}
interface UpdateWebhookStatusEvent {
type: EventType.UPDATE_WEBHOOK_STATUS,
metadata: {
webhookId: string;
environment: string;
secretPath: string;
webhookUrl: string;
isDisabled: boolean;
}
}
interface DeleteWebhookEvent {
type: EventType.DELETE_WEBHOOK,
metadata: {
webhookId: string;
environment: string;
secretPath: string;
webhookUrl: string;
isDisabled: boolean;
}
}
interface GetSecretImportsEvent {
type: EventType.GET_SECRET_IMPORTS,
metadata: {
environment: string;
secretImportId: string;
folderId: string;
numberOfImports: number;
}
}
interface CreateSecretImportEvent {
type: EventType.CREATE_SECRET_IMPORT,
metadata: {
secretImportId: string;
folderId: string;
importFromEnvironment: string;
importFromSecretPath: string;
importToEnvironment: string;
importToSecretPath: string;
}
}
interface UpdateSecretImportEvent {
type: EventType.UPDATE_SECRET_IMPORT,
metadata: {
secretImportId: string;
folderId: string;
importToEnvironment: string;
importToSecretPath: string;
orderBefore: {
environment: string;
secretPath: string;
}[],
orderAfter: {
environment: string;
secretPath: string;
}[]
}
}
interface DeleteSecretImportEvent {
type: EventType.DELETE_SECRET_IMPORT,
metadata: {
secretImportId: string;
folderId: string;
importFromEnvironment: string;
importFromSecretPath: string;
importToEnvironment: string;
importToSecretPath: string;
}
}
export type Event =
| GetSecretsEvent
| GetSecretEvent
| CreateSecretEvent
| UpdateSecretEvent
| DeleteSecretEvent
| GetWorkspaceKeyEvent
| AuthorizeIntegrationEvent
| UnauthorizeIntegrationEvent
| CreateIntegrationEvent
| DeleteIntegrationEvent
| AddTrustedIPEvent
| UpdateTrustedIPEvent
| DeleteTrustedIPEvent
| CreateServiceTokenEvent
| DeleteServiceTokenEvent
| CreateEnvironmentEvent
| UpdateEnvironmentEvent
| DeleteEnvironmentEvent
| AddWorkspaceMemberEvent
| RemoveWorkspaceMemberEvent
| CreateFolderEvent
| UpdateFolderEvent
| DeleteFolderEvent
| CreateWebhookEvent
| UpdateWebhookStatusEvent
| DeleteWebhookEvent
| GetSecretImportsEvent
| CreateSecretImportEvent
| UpdateSecretImportEvent
| DeleteSecretImportEvent;
export type AuditLog = {
_id: string;
actor: Actor;
organization: string;
workspace: string;
ipAddress: string;
event: Event;
userAgent: string;
userAgentType: UserAgentType;
createdAt: string;
updatedAt: string;
}
export type AuditLogFilters = {
eventType?: EventType;
userAgentType?: UserAgentType;
actor?: string;
offset: number;
limit: number;
startDate?: Date;
endDate?: Date;
}
+1
View File
@@ -1,3 +1,4 @@
export * from "./auditLogs";
export * from "./auth"; export * from "./auth";
export * from "./bots"; export * from "./bots";
export * from "./incidentContacts"; export * from "./incidentContacts";
+1 -1
View File
@@ -79,7 +79,7 @@ export type UpdateSecretArg = {
export type CreateSecretArg = Omit<UpdateSecretArg, "_id">; export type CreateSecretArg = Omit<UpdateSecretArg, "_id">;
export type DeleteSecretArg = { _id: string }; export type DeleteSecretArg = { _id: string, secretName: string; };
export type BatchSecretDTO = { export type BatchSecretDTO = {
workspaceId: string; workspaceId: string;

Some files were not shown because too many files have changed in this diff Show More