diff --git a/backend/src/controllers/v1/authController.ts b/backend/src/controllers/v1/authController.ts index 374c4652c..428c1bda0 100644 --- a/backend/src/controllers/v1/authController.ts +++ b/backend/src/controllers/v1/authController.ts @@ -6,14 +6,8 @@ const jsrp = require("jsrp"); import { LoginSRPDetail, TokenVersion, User } from "../../models"; import { clearTokens, createToken, issueAuthTokens } from "../../helpers/auth"; import { checkUserDevice } from "../../helpers/user"; -import { - ACTION_LOGIN, - ACTION_LOGOUT, - AuthTokenType -} from "../../variables"; +import { AuthTokenType } from "../../variables"; import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors"; -import { EELogService } from "../../ee/services"; -import { getUserAgentType } from "../../utils/posthog"; import { getAuthSecret, getHttpsEnabled, @@ -145,19 +139,6 @@ export const login2 = async (req: Request, res: Response) => { secure: await getHttpsEnabled() }); - const loginAction = await EELogService.createAction({ - name: ACTION_LOGIN, - userId: user._id - }); - - loginAction && - (await EELogService.createLog({ - userId: user._id, - actions: [loginAction], - channel: getUserAgentType(req.headers["user-agent"]), - ipAddress: req.realIP - })); - // return (access) token in response return res.status(200).send({ token: tokens.token, @@ -194,19 +175,6 @@ export const logout = async (req: Request, res: Response) => { secure: (await getHttpsEnabled()) as boolean }); - const logoutAction = await EELogService.createAction({ - name: ACTION_LOGOUT, - userId: req.user._id - }); - - logoutAction && - (await EELogService.createLog({ - userId: req.user._id, - actions: [logoutAction], - channel: getUserAgentType(req.headers["user-agent"]), - ipAddress: req.realIP - })); - return res.status(200).send({ message: "Successfully logged out." }); diff --git a/backend/src/controllers/v2/authController.ts b/backend/src/controllers/v2/authController.ts index 46c288ea0..01ebcdfa0 100644 --- a/backend/src/controllers/v2/authController.ts +++ b/backend/src/controllers/v2/authController.ts @@ -8,10 +8,8 @@ import { createToken, issueAuthTokens } from "../../helpers/auth"; import { checkUserDevice } from "../../helpers/user"; import { sendMail } from "../../helpers/nodemailer"; import { TokenService } from "../../services"; -import { EELogService } from "../../ee/services"; import { BadRequestError, InternalServerError } from "../../utils/errors"; -import { ACTION_LOGIN, AuthTokenType, TOKEN_EMAIL_MFA } from "../../variables"; -import { getUserAgentType } from "../../utils/posthog"; // TODO: move this +import { AuthTokenType, TOKEN_EMAIL_MFA } from "../../variables"; import { getAuthSecret, getHttpsEnabled, getJwtMfaLifetime } from "../../config"; import { validateRequest } from "../../helpers/validation"; import * as reqValidator from "../../validation/auth"; @@ -190,19 +188,6 @@ export const login2 = async (req: Request, res: Response) => { response.protectedKeyTag = user.protectedKeyTag; } - const loginAction = await EELogService.createAction({ - name: ACTION_LOGIN, - userId: user._id - }); - - loginAction && - (await EELogService.createLog({ - userId: user._id, - actions: [loginAction], - channel: getUserAgentType(req.headers["user-agent"]), - ipAddress: req.ip - })); - return res.status(200).send(response); } @@ -330,18 +315,5 @@ export const verifyMfaToken = async (req: Request, res: Response) => { resObj.protectedKeyTag = user.protectedKeyTag; } - const loginAction = await EELogService.createAction({ - name: ACTION_LOGIN, - userId: user._id - }); - - loginAction && - (await EELogService.createLog({ - userId: user._id, - actions: [loginAction], - channel: getUserAgentType(req.headers["user-agent"]), - ipAddress: req.realIP - })); - return res.status(200).send(resObj); }; diff --git a/backend/src/controllers/v2/environmentController.ts b/backend/src/controllers/v2/environmentController.ts index 9441734f9..a56429dfa 100644 --- a/backend/src/controllers/v2/environmentController.ts +++ b/backend/src/controllers/v2/environmentController.ts @@ -23,7 +23,6 @@ import { } from "../../ee/services/ProjectRoleService"; import { ForbiddenError } from "@casl/ability"; import { SecretImport } from "../../models"; -import { ServiceAccountWorkspacePermission } from "../../models"; import { Webhook } from "../../models"; /** @@ -400,11 +399,6 @@ export const renameWorkspaceEnvironment = async (req: Request, res: Response) => { arrayFilters: [{ "element.environment": oldEnvironmentSlug }] }, ); - await ServiceAccountWorkspacePermission.updateMany( - { workspace: workspaceId, environment: oldEnvironmentSlug }, - { environment: environmentSlug } - ); - await Webhook.updateMany( { workspace: workspaceId, environment: oldEnvironmentSlug }, { environment: environmentSlug } diff --git a/backend/src/controllers/v2/index.ts b/backend/src/controllers/v2/index.ts index 6ec40f8ce..e06efe46c 100644 --- a/backend/src/controllers/v2/index.ts +++ b/backend/src/controllers/v2/index.ts @@ -6,7 +6,6 @@ import * as workspaceController from "./workspaceController"; import * as serviceTokenDataController from "./serviceTokenDataController"; import * as secretController from "./secretController"; import * as secretsController from "./secretsController"; -import * as serviceAccountsController from "./serviceAccountsController"; import * as environmentController from "./environmentController"; import * as tagController from "./tagController"; import * as membershipController from "./membershipController"; @@ -20,7 +19,6 @@ export { serviceTokenDataController, secretController, secretsController, - serviceAccountsController, environmentController, tagController, membershipController diff --git a/backend/src/controllers/v2/organizationsController.ts b/backend/src/controllers/v2/organizationsController.ts index 384765f68..9d08cce3d 100644 --- a/backend/src/controllers/v2/organizationsController.ts +++ b/backend/src/controllers/v2/organizationsController.ts @@ -3,7 +3,6 @@ import { Types } from "mongoose"; import { Membership, MembershipOrg, - ServiceAccount, Workspace } from "../../models"; import { Role } from "../../ee/models"; @@ -330,23 +329,6 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) => }); }; -/** - * Return service accounts for organization with id [organizationId] - * @param req - * @param res - */ -export const getOrganizationServiceAccounts = async (req: Request, res: Response) => { - const { organizationId } = req.params; - - const serviceAccounts = await ServiceAccount.find({ - organization: new Types.ObjectId(organizationId) - }); - - return res.status(200).send({ - serviceAccounts - }); -}; - /** * Create new organization named [organizationName] * and add user as owner diff --git a/backend/src/controllers/v2/secretsController.ts b/backend/src/controllers/v2/secretsController.ts index 91319de05..b0362f6a4 100644 --- a/backend/src/controllers/v2/secretsController.ts +++ b/backend/src/controllers/v2/secretsController.ts @@ -1,12 +1,8 @@ import { Types } from "mongoose"; import { Request, Response } from "express"; import { Folder, ISecret, Secret, ServiceTokenData, Tag } from "../../models"; -import { AuditLog, EventType, IAction, SecretVersion } from "../../ee/models"; +import { AuditLog, EventType, SecretVersion } from "../../ee/models"; import { - ACTION_ADD_SECRETS, - ACTION_DELETE_SECRETS, - ACTION_READ_SECRETS, - ACTION_UPDATE_SECRETS, ALGORITHM_AES_256_GCM, ENCODING_SCHEME_UTF8, K8_USER_AGENT_NAME, @@ -15,7 +11,7 @@ import { import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors"; import { EventService } from "../../services"; import { eventPushSecrets } from "../../events"; -import { EEAuditLogService, EELogService, EESecretService } from "../../ee/services"; +import { EEAuditLogService, EESecretService } from "../../ee/services"; import { SecretService, TelemetryService } from "../../services"; import { getUserAgentType } from "../../utils/posthog"; import { PERMISSION_WRITE_SECRETS } from "../../variables"; @@ -82,7 +78,6 @@ export const batchSecrets = async (req: Request, res: Response) => { const createSecrets: any[] = []; const updateSecrets: any[] = []; const deleteSecrets: { _id: Types.ObjectId; secretName: string }[] = []; - const actions: IAction[] = []; // get secret blind index salt const salt = await SecretService.getSecretBlindIndexSalt({ @@ -224,16 +219,6 @@ export const batchSecrets = async (req: Request, res: Response) => { await AuditLog.insertMany(auditLogs); - const addAction = (await EELogService.createAction({ - name: ACTION_ADD_SECRETS, - userId: req.user?._id, - serviceAccountId: req.serviceAccount?._id, - serviceTokenDataId: req.serviceTokenData?._id, - workspaceId: new Types.ObjectId(workspaceId), - secretIds: createdSecrets.map((n) => n._id) - })) as IAction; - actions.push(addAction); - if (postHogClient) { postHogClient.capture({ event: "secrets added", @@ -350,14 +335,6 @@ export const batchSecrets = async (req: Request, res: Response) => { await AuditLog.insertMany(auditLogs); - const updateAction = (await EELogService.createAction({ - name: ACTION_UPDATE_SECRETS, - userId: req.user._id, - workspaceId: new Types.ObjectId(workspaceId), - secretIds: updatedSecrets.map((u) => u._id) - })) as IAction; - actions.push(updateAction); - if (postHogClient) { postHogClient.capture({ event: "secrets modified", @@ -428,14 +405,6 @@ export const batchSecrets = async (req: Request, res: Response) => { await AuditLog.insertMany(auditLogs); - const deleteAction = (await EELogService.createAction({ - name: ACTION_DELETE_SECRETS, - userId: req.user._id, - workspaceId: new Types.ObjectId(workspaceId), - secretIds: deleteSecretIds - })) as IAction; - actions.push(deleteAction); - if (postHogClient) { postHogClient.capture({ event: "secrets deleted", @@ -451,17 +420,6 @@ export const batchSecrets = async (req: Request, res: Response) => { } } - if (actions.length > 0) { - // (EE) create (audit) log - await EELogService.createLog({ - userId: req.user._id.toString(), - workspaceId: new Types.ObjectId(workspaceId), - actions, - channel, - ipAddress: req.realIP - }); - } - // // trigger event - push secrets await EventService.handleEvent({ event: eventPushSecrets({ @@ -731,27 +689,6 @@ export const createSecrets = async (req: Request, res: Response) => { ) }); - const addAction = await EELogService.createAction({ - name: ACTION_ADD_SECRETS, - userId: req.user?._id, - serviceAccountId: req.serviceAccount?._id, - serviceTokenDataId: req.serviceTokenData?._id, - workspaceId: new Types.ObjectId(workspaceId), - secretIds: newlyCreatedSecrets.map((n) => n._id) - }); - - // (EE) create (audit) log - addAction && - (await EELogService.createLog({ - userId: req.user?._id, - serviceAccountId: req.serviceAccount?._id, - serviceTokenDataId: req.serviceTokenData?._id, - workspaceId: new Types.ObjectId(workspaceId), - actions: [addAction], - channel, - ipAddress: req.realIP - })); - // (EE) take a secret snapshot await EESecretService.takeSecretSnapshot({ workspaceId: new Types.ObjectId(workspaceId), @@ -960,22 +897,6 @@ export const getSecrets = async (req: Request, res: Response) => { secrets = await Secret.find(secretQuery).populate("tags"); } - // case: client authorization is via service account - if (req.serviceAccount) { - const secretQuery: any = { - workspace: workspaceId, - environment, - folder: folderId, - user: { $exists: false } // shared secrets only from workspace - }; - - if (tagIds.length > 0) { - secretQuery.tags = { $in: tagIds }; - } - - secrets = await Secret.find(secretQuery).populate("tags"); - } - // TODO(akhilmhdh) - secret-imp change this to org type let importedSecrets: any[] = []; if (include_imports) { @@ -988,28 +909,6 @@ export const getSecrets = async (req: Request, res: Response) => { ); } - const channel = getUserAgentType(req.headers["user-agent"]); - - const readAction = await EELogService.createAction({ - name: ACTION_READ_SECRETS, - userId: req.user?._id, - serviceAccountId: req.serviceAccount?._id, - serviceTokenDataId: req.serviceTokenData?._id, - workspaceId: new Types.ObjectId(workspaceId as string), - secretIds: secrets.map((n: any) => n._id) - }); - - readAction && - (await EELogService.createLog({ - userId: req.user?._id, - serviceAccountId: req.serviceAccount?._id, - serviceTokenDataId: req.serviceTokenData?._id, - workspaceId: new Types.ObjectId(workspaceId as string), - actions: [readAction], - channel, - ipAddress: req.realIP - })); - await EEAuditLogService.createAuditLog( req.authData, { @@ -1247,27 +1146,6 @@ export const updateSecrets = async (req: Request, res: Response) => { // }); // }, 10000); - const updateAction = await EELogService.createAction({ - name: ACTION_UPDATE_SECRETS, - userId: req.user?._id, - serviceAccountId: req.serviceAccount?._id, - serviceTokenDataId: req.serviceTokenData?._id, - workspaceId: new Types.ObjectId(key), - secretIds: workspaceSecretObj[key].map((secret: ISecret) => secret._id) - }); - - // (EE) create (audit) log - updateAction && - (await EELogService.createLog({ - userId: req.user?._id, - serviceAccountId: req.serviceAccount?._id, - serviceTokenDataId: req.serviceTokenData?._id, - workspaceId: new Types.ObjectId(key), - actions: [updateAction], - channel, - ipAddress: req.realIP - })); - // (EE) take a secret snapshot // IMP(akhilmhdh): commented out due to unknown where the environment is // await EESecretService.takeSecretSnapshot({ @@ -1387,26 +1265,6 @@ export const deleteSecrets = async (req: Request, res: Response) => { // workspaceId: new Types.ObjectId(key) // }) // }); - const deleteAction = await EELogService.createAction({ - name: ACTION_DELETE_SECRETS, - userId: req.user?._id, - serviceAccountId: req.serviceAccount?._id, - serviceTokenDataId: req.serviceTokenData?._id, - workspaceId: new Types.ObjectId(key), - secretIds: workspaceSecretObj[key].map((secret: ISecret) => secret._id) - }); - - // (EE) create (audit) log - deleteAction && - (await EELogService.createLog({ - userId: req.user?._id, - serviceAccountId: req.serviceAccount?._id, - serviceTokenDataId: req.serviceTokenData?._id, - workspaceId: new Types.ObjectId(key), - actions: [deleteAction], - channel, - ipAddress: req.realIP - })); // (EE) take a secret snapshot // IMP(akhilmhdh): Not sure how to take secretSnapshot diff --git a/backend/src/controllers/v2/serviceAccountsController.ts b/backend/src/controllers/v2/serviceAccountsController.ts deleted file mode 100644 index d802a9e99..000000000 --- a/backend/src/controllers/v2/serviceAccountsController.ts +++ /dev/null @@ -1,306 +0,0 @@ -import { Request, Response } from "express"; -import { Types } from "mongoose"; -import crypto from "crypto"; -import bcrypt from "bcrypt"; -import { - ServiceAccount, - ServiceAccountKey, - ServiceAccountOrganizationPermission, - ServiceAccountWorkspacePermission, -} from "../../models"; -import { - CreateServiceAccountDto, -} from "../../interfaces/serviceAccounts/dto"; -import { BadRequestError, ServiceAccountNotFoundError } from "../../utils/errors"; -import { getSaltRounds } from "../../config"; - -/** - * Return service account tied to the request (service account) client - * @param req - * @param res - */ -export const getCurrentServiceAccount = async (req: Request, res: Response) => { - const serviceAccount = await ServiceAccount.findById(req.serviceAccount._id); - - if (!serviceAccount) { - throw ServiceAccountNotFoundError({ message: "Failed to find service account" }); - } - - return res.status(200).send({ - serviceAccount, - }); -} - -/** - * Return service account with id [serviceAccountId] - * @param req - * @param res - */ -export const getServiceAccountById = async (req: Request, res: Response) => { - const { serviceAccountId } = req.params; - - const serviceAccount = await ServiceAccount.findById(serviceAccountId); - - if (!serviceAccount) { - throw ServiceAccountNotFoundError({ message: "Failed to find service account" }); - } - - return res.status(200).send({ - serviceAccount, - }); -} - -/** - * Create a new service account under organization with id [organizationId] - * that has access to workspaces [workspaces] - * @param req - * @param res - * @returns - */ -export const createServiceAccount = async (req: Request, res: Response) => { - const { - name, - organizationId, - publicKey, - expiresIn, - }: CreateServiceAccountDto = req.body; - - let expiresAt; - if (expiresIn) { - expiresAt = new Date(); - expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn); - } - - const secret = crypto.randomBytes(16).toString("base64"); - const secretHash = await bcrypt.hash(secret, await getSaltRounds()); - - // create service account - const serviceAccount = await new ServiceAccount({ - name, - organization: new Types.ObjectId(organizationId), - user: req.user, - publicKey, - lastUsed: new Date(), - expiresAt, - secretHash, - }).save() - - const serviceAccountObj = serviceAccount.toObject(); - - delete (serviceAccountObj as any).secretHash; - - // provision default org-level permission for service account - await new ServiceAccountOrganizationPermission({ - serviceAccount: serviceAccount._id, - }).save(); - - const secretId = Buffer.from(serviceAccount._id.toString(), "hex").toString("base64"); - - return res.status(200).send({ - serviceAccountAccessKey: `sa.${secretId}.${secret}`, - serviceAccount: serviceAccountObj, - }); -} - -/** - * Change name of service account with id [serviceAccountId] to [name] - * @param req - * @param res - * @returns - */ -export const changeServiceAccountName = async (req: Request, res: Response) => { - const { serviceAccountId } = req.params; - const { name } = req.body; - - const serviceAccount = await ServiceAccount.findOneAndUpdate( - { - _id: new Types.ObjectId(serviceAccountId), - }, - { - name, - }, - { - new: true, - } - ); - - return res.status(200).send({ - serviceAccount, - }); -} - -/** - * Add a service account key to service account with id [serviceAccountId] - * for workspace with id [workspaceId] - * @param req - * @param res - * @returns - */ -export const addServiceAccountKey = async (req: Request, res: Response) => { - const { - workspaceId, - encryptedKey, - nonce, - } = req.body; - - const serviceAccountKey = await new ServiceAccountKey({ - encryptedKey, - nonce, - sender: req.user._id, - serviceAccount: req.serviceAccount._d, - workspace: new Types.ObjectId(workspaceId), - }).save(); - - return serviceAccountKey; -} - -/** - * Return workspace-level permission for service account with id [serviceAccountId] - * @param req - * @param res - */ -export const getServiceAccountWorkspacePermissions = async (req: Request, res: Response) => { - const serviceAccountWorkspacePermissions = await ServiceAccountWorkspacePermission.find({ - serviceAccount: req.serviceAccount._id, - }).populate("workspace"); - - return res.status(200).send({ - serviceAccountWorkspacePermissions, - }); -} - -/** - * Add a workspace permission to service account with id [serviceAccountId] - * @param req - * @param res - */ -export const addServiceAccountWorkspacePermission = async (req: Request, res: Response) => { - const { serviceAccountId } = req.params; - const { - environment, - workspaceId, - read = false, - write = false, - encryptedKey, - nonce, - } = req.body; - - if (!req.membership.workspace.environments.some((e: { name: string; slug: string }) => e.slug === environment)) { - return res.status(400).send({ - message: "Failed to validate workspace environment", - }); - } - - const existingPermission = await ServiceAccountWorkspacePermission.findOne({ - serviceAccount: new Types.ObjectId(serviceAccountId), - workspace: new Types.ObjectId(workspaceId), - environment, - }); - - if (existingPermission) throw BadRequestError({ message: "Failed to add workspace permission to service account due to already-existing " }); - - const serviceAccountWorkspacePermission = await new ServiceAccountWorkspacePermission({ - serviceAccount: new Types.ObjectId(serviceAccountId), - workspace: new Types.ObjectId(workspaceId), - environment, - read, - write, - }).save(); - - const existingServiceAccountKey = await ServiceAccountKey.findOne({ - serviceAccount: new Types.ObjectId(serviceAccountId), - workspace: new Types.ObjectId(workspaceId), - }); - - if (!existingServiceAccountKey) { - await new ServiceAccountKey({ - encryptedKey, - nonce, - sender: req.user._id, - serviceAccount: new Types.ObjectId(serviceAccountId), - workspace: new Types.ObjectId(workspaceId), - }).save(); - } - - return res.status(200).send({ - serviceAccountWorkspacePermission, - }); -} - -/** - * Delete workspace permission from service account with id [serviceAccountId] - * @param req - * @param res - */ -export const deleteServiceAccountWorkspacePermission = async (req: Request, res: Response) => { - const { serviceAccountWorkspacePermissionId } = req.params; - const serviceAccountWorkspacePermission = await ServiceAccountWorkspacePermission.findByIdAndDelete(serviceAccountWorkspacePermissionId); - - if (serviceAccountWorkspacePermission) { - const { serviceAccount, workspace } = serviceAccountWorkspacePermission; - const count = await ServiceAccountWorkspacePermission.countDocuments({ - serviceAccount, - workspace, - }); - - if (count === 0) { - await ServiceAccountKey.findOneAndDelete({ - serviceAccount, - workspace, - }); - } - } - - return res.status(200).send({ - serviceAccountWorkspacePermission, - }); -} - -/** - * Delete service account with id [serviceAccountId] - * @param req - * @param res - * @returns - */ -export const deleteServiceAccount = async (req: Request, res: Response) => { - const { serviceAccountId } = req.params; - - const serviceAccount = await ServiceAccount.findByIdAndDelete(serviceAccountId); - - if (serviceAccount) { - await ServiceAccountKey.deleteMany({ - serviceAccount: serviceAccount._id, - }); - - await ServiceAccountOrganizationPermission.deleteMany({ - serviceAccount: new Types.ObjectId(serviceAccountId), - }); - - await ServiceAccountWorkspacePermission.deleteMany({ - serviceAccount: new Types.ObjectId(serviceAccountId), - }); - } - - return res.status(200).send({ - serviceAccount, - }); -} - -/** - * Return service account keys for service account with id [serviceAccountId] - * @param req - * @param res - * @returns - */ -export const getServiceAccountKeys = async (req: Request, res: Response) => { - const workspaceId = req.query.workspaceId as string; - - const serviceAccountKeys = await ServiceAccountKey.find({ - serviceAccount: req.serviceAccount._id, - ...(workspaceId ? { workspace: new Types.ObjectId(workspaceId) } : {}), - }); - - return res.status(200).send({ - serviceAccountKeys, - }); -} \ No newline at end of file diff --git a/backend/src/controllers/v3/authController.ts b/backend/src/controllers/v3/authController.ts index 9cd23cf87..4e3576c3b 100644 --- a/backend/src/controllers/v3/authController.ts +++ b/backend/src/controllers/v3/authController.ts @@ -8,10 +8,8 @@ import { createToken, issueAuthTokens, validateProviderAuthToken } from "../../h import { checkUserDevice } from "../../helpers/user"; import { sendMail } from "../../helpers/nodemailer"; import { TokenService } from "../../services"; -import { EELogService } from "../../ee/services"; import { BadRequestError, InternalServerError } from "../../utils/errors"; -import { ACTION_LOGIN, AuthTokenType, TOKEN_EMAIL_MFA } from "../../variables"; -import { getUserAgentType } from "../../utils/posthog"; // TODO: move this +import { AuthTokenType, TOKEN_EMAIL_MFA } from "../../variables"; import { getAuthSecret, getHttpsEnabled, getJwtMfaLifetime } from "../../config"; import { AuthMethod } from "../../models/user"; import { validateRequest } from "../../helpers/validation"; @@ -215,19 +213,6 @@ export const login2 = async (req: Request, res: Response) => { response.protectedKeyTag = user.protectedKeyTag; } - const loginAction = await EELogService.createAction({ - name: ACTION_LOGIN, - userId: user._id - }); - - loginAction && - (await EELogService.createLog({ - userId: user._id, - actions: [loginAction], - channel: getUserAgentType(req.headers["user-agent"]), - ipAddress: req.realIP - })); - return res.status(200).send(response); } diff --git a/backend/src/ee/controllers/v1/actionController.ts b/backend/src/ee/controllers/v1/actionController.ts deleted file mode 100644 index 56b076026..000000000 --- a/backend/src/ee/controllers/v1/actionController.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Request, Response } from "express"; -import { Action } from "../../models"; -import { ActionNotFoundError } from "../../../utils/errors"; -import { validateRequest } from "../../../helpers/validation"; -import * as reqValidator from "../../../validation/action"; - -export const getAction = async (req: Request, res: Response) => { - let action; - try { - const { - params: { actionId } - } = await validateRequest(reqValidator.GetActionV1, req); - - action = await Action.findById(actionId).populate([ - "payload.secretVersions.oldSecretVersion", - "payload.secretVersions.newSecretVersion" - ]); - - if (!action) - throw ActionNotFoundError({ - message: "Failed to find action" - }); - } catch (err) { - throw ActionNotFoundError({ - message: "Failed to find action" - }); - } - - return res.status(200).send({ - action - }); -}; diff --git a/backend/src/ee/controllers/v1/index.ts b/backend/src/ee/controllers/v1/index.ts index dc161c271..a80916733 100644 --- a/backend/src/ee/controllers/v1/index.ts +++ b/backend/src/ee/controllers/v1/index.ts @@ -4,7 +4,6 @@ import * as organizationsController from "./organizationsController"; import * as ssoController from "./ssoController"; import * as usersController from "./usersController"; import * as workspaceController from "./workspaceController"; -import * as actionController from "./actionController"; import * as membershipController from "./membershipController"; import * as cloudProductsController from "./cloudProductsController"; import * as roleController from "./roleController"; @@ -20,7 +19,6 @@ export { ssoController, usersController, workspaceController, - actionController, membershipController, cloudProductsController, roleController, diff --git a/backend/src/ee/controllers/v1/workspaceController.ts b/backend/src/ee/controllers/v1/workspaceController.ts index 3ee7a3229..b26882d74 100644 --- a/backend/src/ee/controllers/v1/workspaceController.ts +++ b/backend/src/ee/controllers/v1/workspaceController.ts @@ -17,7 +17,6 @@ import { FolderVersion, IPType, ISecretVersion, - Log, SecretSnapshot, SecretVersion, ServiceActor, @@ -38,7 +37,6 @@ import { DeleteWorkspaceTrustedIpV1, GetWorkspaceAuditLogActorFilterOptsV1, GetWorkspaceAuditLogsV1, - GetWorkspaceLogsV1, GetWorkspaceSecretSnapshotsCountV1, GetWorkspaceSecretSnapshotsV1, GetWorkspaceTrustedIpsV1, @@ -563,112 +561,6 @@ export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Respons }); }; -/** - * Return (audit) logs for workspace with id [workspaceId] - * @param req - * @param res - * @returns - */ -export const getWorkspaceLogs = async (req: Request, res: Response) => { - /* - #swagger.summary = 'Return project (audit) logs' - #swagger.description = 'Return project (audit) logs' - - #swagger.security = [{ - "apiKeyAuth": [] - }] - - #swagger.parameters['workspaceId'] = { - "description": "ID of project", - "required": true, - "type": "string" - } - - #swagger.parameters['userId'] = { - "description": "ID of project member", - "required": false, - "type": "string" - } - - #swagger.parameters['offset'] = { - "description": "Number of logs to skip", - "required": false, - "type": "string" - } - - #swagger.parameters['limit'] = { - "description": "Maximum number of logs to return", - "required": false, - "type": "string" - } - - #swagger.parameters['sortBy'] = { - "description": "Order to sort the logs by", - "schema": { - "type": "string", - "@enum": ["oldest", "recent"] - }, - "required": false - } - - #swagger.parameters['actionNames'] = { - "description": "Names of log actions (comma-separated)", - "required": false, - "type": "string" - } - - #swagger.responses[200] = { - content: { - "application/json": { - schema: { - "type": "object", - "properties": { - "logs": { - "type": "array", - "items": { - $ref: "#/components/schemas/Log" - }, - "description": "Project logs" - } - } - } - } - } - } - */ - const { - query: { limit, offset, userId, sortBy, actionNames }, - params: { workspaceId } - } = await validateRequest(GetWorkspaceLogsV1, req); - - const { permission } = await getUserProjectPermissions(req.user._id, workspaceId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Read, - ProjectPermissionSub.AuditLogs - ); - - const logs = await Log.find({ - workspace: workspaceId, - ...(userId ? { user: userId } : {}), - ...(actionNames - ? { - actionNames: { - $in: actionNames.split(",") - } - } - : {}) - }) - .sort({ createdAt: sortBy === "recent" ? -1 : 1 }) - .skip(offset) - .limit(limit) - .populate("actions") - .populate("user serviceAccount serviceTokenData"); - - return res.status(200).send({ - logs - }); -}; - /** * Return audit logs for workspace with id [workspaceId] * @param req diff --git a/backend/src/ee/helpers/action.ts b/backend/src/ee/helpers/action.ts deleted file mode 100644 index 3279e86ca..000000000 --- a/backend/src/ee/helpers/action.ts +++ /dev/null @@ -1,195 +0,0 @@ -import { Types } from "mongoose"; -import { Action } from "../models"; -import { - getLatestNSecretSecretVersionIds, - getLatestSecretVersionIds, -} from "../helpers/secretVersion"; -import { - ACTION_ADD_SECRETS, - ACTION_DELETE_SECRETS, - ACTION_LOGIN, - ACTION_LOGOUT, - ACTION_READ_SECRETS, - ACTION_UPDATE_SECRETS, -} from "../../variables"; - -/** - * Create an (audit) action for updating secrets - * @param {Object} obj - * @param {String} obj.name - name of action - * @param {Types.ObjectId} obj.secretIds - ids of relevant secrets - * @returns {Action} action - new action - */ -const createActionUpdateSecret = async ({ - name, - userId, - serviceAccountId, - serviceTokenDataId, - workspaceId, - secretIds, -}: { - name: string; - userId?: Types.ObjectId; - serviceAccountId?: Types.ObjectId; - serviceTokenDataId?: Types.ObjectId; - workspaceId: Types.ObjectId; - secretIds: Types.ObjectId[]; -}) => { - const latestSecretVersions = (await getLatestNSecretSecretVersionIds({ - secretIds, - n: 2, - })) - .map((s) => ({ - oldSecretVersion: s.versions[0]._id, - newSecretVersion: s.versions[1]._id, - })); - - const action = await new Action({ - name, - user: userId, - serviceAccount: serviceAccountId, - serviceTokenData: serviceTokenDataId, - workspace: workspaceId, - payload: { - secretVersions: latestSecretVersions, - }, - }).save(); - - return action; -} - -/** - * Create an (audit) action for creating, reading, and deleting - * secrets - * @param {Object} obj - * @param {String} obj.name - name of action - * @param {Types.ObjectId} obj.secretIds - ids of relevant secrets - * @returns {Action} action - new action - */ -const createActionSecret = async ({ - name, - userId, - serviceAccountId, - serviceTokenDataId, - workspaceId, - secretIds, -}: { - name: string; - userId?: Types.ObjectId; - serviceAccountId?: Types.ObjectId; - serviceTokenDataId?: Types.ObjectId; - workspaceId: Types.ObjectId; - secretIds: Types.ObjectId[]; -}) => { - // case: action is adding, deleting, or reading secrets - // -> add new secret versions - const latestSecretVersions = (await getLatestSecretVersionIds({ - secretIds, - })) - .map((s) => ({ - newSecretVersion: s.versionId, - })); - - const action = await new Action({ - name, - user: userId, - serviceAccount: serviceAccountId, - serviceTokenData: serviceTokenDataId, - workspace: workspaceId, - payload: { - secretVersions: latestSecretVersions, - }, - }).save(); - - return action; -} - -/** - * Create an (audit) action for client with id [userId], - * [serviceAccountId], or [serviceTokenDataId] - * @param {Object} obj - * @param {String} obj.name - name of action - * @param {String} obj.userId - id of user associated with action - * @returns - */ -const createActionClient = ({ - name, - userId, - serviceAccountId, - serviceTokenDataId, -}: { - name: string; - userId?: Types.ObjectId; - serviceAccountId?: Types.ObjectId; - serviceTokenDataId?: Types.ObjectId; -}) => { - const action = new Action({ - name, - user: userId, - serviceAccount: serviceAccountId, - serviceTokenData: serviceTokenDataId, - }).save(); - - return action; -} - -/** - * Create an (audit) action. - * @param {Object} obj - * @param {Object} obj.name - name of action - * @param {Types.ObjectId} obj.userId - id of user associated with action - * @param {Types.ObjectId} obj.workspaceId - id of workspace associated with action - * @param {Types.ObjectId[]} obj.secretIds - ids of secrets associated with action -*/ -const createActionHelper = async ({ - name, - userId, - serviceAccountId, - serviceTokenDataId, - workspaceId, - secretIds, -}: { - name: string; - userId?: Types.ObjectId; - serviceAccountId?: Types.ObjectId; - serviceTokenDataId?: Types.ObjectId; - workspaceId?: Types.ObjectId; - secretIds?: Types.ObjectId[]; -}) => { - let action; - switch (name) { - case ACTION_LOGIN: - case ACTION_LOGOUT: - action = await createActionClient({ - name, - userId, - }); - break; - case ACTION_ADD_SECRETS: - case ACTION_READ_SECRETS: - case ACTION_DELETE_SECRETS: - if (!workspaceId || !secretIds) throw new Error("Missing required params workspace id or secret ids to create action secret"); - action = await createActionSecret({ - name, - userId, - workspaceId, - secretIds, - }); - break; - case ACTION_UPDATE_SECRETS: - if (!workspaceId || !secretIds) throw new Error("Missing required params workspace id or secret ids to create action secret"); - action = await createActionUpdateSecret({ - name, - userId, - workspaceId, - secretIds, - }); - break; - } - - return action; -} - -export { - createActionHelper, -}; diff --git a/backend/src/ee/helpers/log.ts b/backend/src/ee/helpers/log.ts deleted file mode 100644 index feb52d151..000000000 --- a/backend/src/ee/helpers/log.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Types } from "mongoose"; -import { - IAction, - Log, -} from "../models"; - -/** - * Create an (audit) log - * @param {Object} obj - * @param {Types.ObjectId} obj.userId - id of user associated with the log - * @param {Types.ObjectId} obj.workspaceId - id of workspace associated with the log - * @param {IAction[]} obj.actions - actions to include in log - * @param {String} obj.channel - channel (web/cli/auto) associated with the log - * @param {String} obj.ipAddress - ip address associated with the log - * @returns {Log} log - new audit log - */ -const createLogHelper = async ({ - userId, - serviceAccountId, - serviceTokenDataId, - workspaceId, - actions, - channel, - ipAddress, -}: { - userId?: Types.ObjectId; - serviceAccountId?: Types.ObjectId; - serviceTokenDataId?: Types.ObjectId; - workspaceId?: Types.ObjectId; - actions: IAction[]; - channel: string; - ipAddress: string; -}) => { - const log = await new Log({ - user: userId, - serviceAccount: serviceAccountId, - serviceTokenData: serviceTokenDataId, - workspace: workspaceId ?? undefined, - actionNames: actions.map((a) => a.name), - actions, - channel, - ipAddress, - }).save(); - - return log; -} - -export { - createLogHelper, -} diff --git a/backend/src/ee/models/action.ts b/backend/src/ee/models/action.ts deleted file mode 100644 index c763915ee..000000000 --- a/backend/src/ee/models/action.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Schema, Types, model } from "mongoose"; -import { - ACTION_ADD_SECRETS, - ACTION_DELETE_SECRETS, - ACTION_LOGIN, - ACTION_LOGOUT, - ACTION_READ_SECRETS, - ACTION_UPDATE_SECRETS, -} from "../../variables"; - -export interface IAction { - name: string; - user?: Types.ObjectId, - serviceAccount?: Types.ObjectId, - serviceTokenData?: Types.ObjectId, - workspace?: Types.ObjectId, - payload?: { - secretVersions?: Types.ObjectId[] - } -} - -const actionSchema = new Schema( - { - name: { - type: String, - required: true, - enum: [ - ACTION_LOGIN, - ACTION_LOGOUT, - ACTION_ADD_SECRETS, - ACTION_UPDATE_SECRETS, - ACTION_READ_SECRETS, - ACTION_DELETE_SECRETS, - ], - }, - user: { - type: Schema.Types.ObjectId, - ref: "User", - }, - serviceAccount: { - type: Schema.Types.ObjectId, - ref: "ServiceAccount", - }, - serviceTokenData: { - type: Schema.Types.ObjectId, - ref: "ServiceTokenData", - }, - workspace: { - type: Schema.Types.ObjectId, - ref: "Workspace", - }, - payload: { - secretVersions: [{ - oldSecretVersion: { - type: Schema.Types.ObjectId, - ref: "SecretVersion", - }, - newSecretVersion: { - type: Schema.Types.ObjectId, - ref: "SecretVersion", - }, - }], - }, - }, { - timestamps: true, - } -); - -export const Action = model("Action", actionSchema); \ No newline at end of file diff --git a/backend/src/ee/models/index.ts b/backend/src/ee/models/index.ts index 74abad3e4..b2a9556ac 100644 --- a/backend/src/ee/models/index.ts +++ b/backend/src/ee/models/index.ts @@ -1,9 +1,7 @@ export * from "./secretSnapshot"; export * from "./secretVersion"; export * from "./folderVersion"; -export * from "./log"; export * from "./role"; -export * from "./action"; export * from "./ssoConfig"; export * from "./trustedIp"; export * from "./auditLog"; diff --git a/backend/src/ee/models/log.ts b/backend/src/ee/models/log.ts deleted file mode 100644 index ed8ff17f7..000000000 --- a/backend/src/ee/models/log.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Schema, Types, model } from "mongoose"; -import { - ACTION_ADD_SECRETS, - ACTION_DELETE_SECRETS, - ACTION_LOGIN, - ACTION_LOGOUT, - ACTION_READ_SECRETS, - ACTION_UPDATE_SECRETS, -} from "../../variables"; - -export interface ILog { - _id: Types.ObjectId; - user?: Types.ObjectId; - serviceAccount?: Types.ObjectId; - serviceTokenData?: Types.ObjectId; - workspace?: Types.ObjectId; - actionNames: string[]; - actions: Types.ObjectId[]; - channel: string; - ipAddress?: string; -} - -const logSchema = new Schema( - { - user: { - type: Schema.Types.ObjectId, - ref: "User", - }, - serviceAccount: { - type: Schema.Types.ObjectId, - ref: "ServiceAccount", - }, - serviceTokenData: { - type: Schema.Types.ObjectId, - ref: "ServiceTokenData", - }, - workspace: { - type: Schema.Types.ObjectId, - ref: "Workspace", - }, - actionNames: { - type: [String], - enum: [ - ACTION_LOGIN, - ACTION_LOGOUT, - ACTION_ADD_SECRETS, - ACTION_UPDATE_SECRETS, - ACTION_READ_SECRETS, - ACTION_DELETE_SECRETS, - ], - required: true, - }, - actions: [{ - type: Schema.Types.ObjectId, - ref: "Action", - required: true, - }], - channel: { - type: String, - enum: ["web", "cli", "auto", "k8-operator", "other"], - required: true, - }, - ipAddress: { - type: String, - }, - }, - { - timestamps: true, - } -); - -export const Log = model("Log", logSchema); \ No newline at end of file diff --git a/backend/src/ee/routes/v1/action.ts b/backend/src/ee/routes/v1/action.ts deleted file mode 100644 index 4700c5a59..000000000 --- a/backend/src/ee/routes/v1/action.ts +++ /dev/null @@ -1,8 +0,0 @@ -import express from "express"; -const router = express.Router(); -import { actionController } from "../../controllers/v1"; - -// TODO: put into action controller -router.get("/:actionId", actionController.getAction); - -export default router; diff --git a/backend/src/ee/routes/v1/index.ts b/backend/src/ee/routes/v1/index.ts index 40145e81f..d5168e402 100644 --- a/backend/src/ee/routes/v1/index.ts +++ b/backend/src/ee/routes/v1/index.ts @@ -4,7 +4,6 @@ import organizations from "./organizations"; import sso from "./sso"; import users from "./users"; import workspace from "./workspace"; -import action from "./action"; import cloudProducts from "./cloudProducts"; import secretScanning from "./secretScanning"; import roles from "./role"; @@ -20,7 +19,6 @@ export { sso, users, workspace, - action, cloudProducts, secretScanning, roles, diff --git a/backend/src/ee/routes/v1/workspace.ts b/backend/src/ee/routes/v1/workspace.ts index 9a7054ce6..f9be77e78 100644 --- a/backend/src/ee/routes/v1/workspace.ts +++ b/backend/src/ee/routes/v1/workspace.ts @@ -28,14 +28,6 @@ router.post( workspaceController.rollbackWorkspaceSecretSnapshot ); -router.get( - "/:workspaceId/logs", - requireAuth({ - acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY] - }), - workspaceController.getWorkspaceLogs -); - router.get( "/:workspaceId/audit-logs", requireAuth({ diff --git a/backend/src/ee/services/EELogService.ts b/backend/src/ee/services/EELogService.ts deleted file mode 100644 index 70f702953..000000000 --- a/backend/src/ee/services/EELogService.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Types } from "mongoose"; -import { - IAction, -} from "../models"; -import { - createLogHelper, -} from "../helpers/log"; -import { - createActionHelper, -} from "../helpers/action"; -import EELicenseService from "./EELicenseService"; - -/** - * Class to handle Enterprise Edition log actions - */ -class EELogService { - /** - * Create an (audit) log - * @param {Object} obj - * @param {String} obj.userId - id of user associated with the log - * @param {String} obj.workspaceId - id of workspace associated with the log - * @param {Action} obj.actions - actions to include in log - * @param {String} obj.channel - channel (web/cli/auto) associated with the log - * @param {String} obj.ipAddress - ip address associated with the log - * @returns {Log} log - new audit log - */ - static async createLog({ - userId, - serviceAccountId, - serviceTokenDataId, - workspaceId, - actions, - channel, - ipAddress, - }: { - userId?: Types.ObjectId; - serviceAccountId?: Types.ObjectId; - serviceTokenDataId?: Types.ObjectId; - workspaceId?: Types.ObjectId; - actions: IAction[]; - channel: string; - ipAddress: string; - }) { - if (!EELicenseService.isLicenseValid) return null; - return await createLogHelper({ - userId, - serviceAccountId, - serviceTokenDataId, - workspaceId, - actions, - channel, - ipAddress, - }) - } - - /** - * Create an (audit) action - * @param {Object} obj - * @param {String} obj.name - name of action - * @param {Types.ObjectId} obj.userId - id of user associated with the action - * @param {Types.ObjectId} obj.workspaceId - id of workspace associated with the action - * @param {ObjectId[]} obj.secretIds - ids of secrets associated with the action - * @returns {Action} action - new action - */ - static async createAction({ - name, - userId, - serviceAccountId, - serviceTokenDataId, - workspaceId, - secretIds, - }: { - name: string; - userId?: Types.ObjectId; - serviceAccountId?: Types.ObjectId; - serviceTokenDataId?: Types.ObjectId; - workspaceId?: Types.ObjectId; - secretIds?: Types.ObjectId[]; - }) { - return await createActionHelper({ - name, - userId, - serviceAccountId, - serviceTokenDataId, - workspaceId, - secretIds, - }); - } -} - -export default EELogService; \ No newline at end of file diff --git a/backend/src/ee/services/index.ts b/backend/src/ee/services/index.ts index 20571d5bb..4ec55e725 100644 --- a/backend/src/ee/services/index.ts +++ b/backend/src/ee/services/index.ts @@ -1,13 +1,11 @@ import EELicenseService from "./EELicenseService"; import EESecretService from "./EESecretService"; -import EELogService from "./EELogService"; import EEAuditLogService from "./EEAuditLogService"; import GithubSecretScanningService from "./GithubSecretScanning/GithubSecretScanningService" export { EELicenseService, EESecretService, - EELogService, EEAuditLogService, GithubSecretScanningService } \ No newline at end of file diff --git a/backend/src/helpers/organization.ts b/backend/src/helpers/organization.ts index a527c2c21..4b2ac369b 100644 --- a/backend/src/helpers/organization.ts +++ b/backend/src/helpers/organization.ts @@ -23,13 +23,11 @@ import { Workspace } from "../models"; import { - Action, AuditLog, FolderVersion, GitAppInstallationSession, GitAppOrganizationInstallation, GitRisks, - Log, Role, SSOConfig, SecretApprovalPolicy, @@ -288,18 +286,6 @@ export const deleteOrganization = async ({ } }); - await Log.deleteMany({ - workspace: { - $in: workspaceIds - } - }); - - await Action.deleteMany({ - workspace: { - $in: workspaceIds - } - }); - await SecretApprovalPolicy.deleteMany({ workspace: { $in: workspaceIds diff --git a/backend/src/helpers/secret.ts b/backend/src/helpers/secret.ts index 88ff66092..6bdc21e99 100644 --- a/backend/src/helpers/secret.ts +++ b/backend/src/helpers/secret.ts @@ -1,12 +1,8 @@ import { Types } from "mongoose"; import { ISecret, Secret } from "../models"; -import { EELogService, EESecretService } from "../ee/services"; -import { IAction, SecretVersion } from "../ee/models"; +import { EESecretService } from "../ee/services"; +import { SecretVersion } from "../ee/models"; import { - ACTION_ADD_SECRETS, - ACTION_DELETE_SECRETS, - ACTION_READ_SECRETS, - ACTION_UPDATE_SECRETS, ALGORITHM_AES_256_GCM, ENCODING_SCHEME_UTF8, SECRET_PERSONAL, @@ -320,7 +316,6 @@ export const v2PushSecrets = async ({ ipAddress: string; }): Promise => { // TODO: clean up function and fix up types - const actions: IAction[] = []; // construct useful data structures const oldSecrets = await getSecrets({ @@ -356,15 +351,6 @@ export const v2PushSecrets = async ({ await EESecretService.markDeletedSecretVersions({ secretIds: toDelete, }); - - const deleteAction = await EELogService.createAction({ - name: ACTION_DELETE_SECRETS, - userId: new Types.ObjectId(userId), - workspaceId: new Types.ObjectId(userId), - secretIds: toDelete, - }); - - deleteAction && actions.push(deleteAction); } const toUpdate = oldSecrets.filter((s) => { @@ -451,15 +437,6 @@ export const v2PushSecrets = async ({ }; }), }); - - const updateAction = await EELogService.createAction({ - name: ACTION_UPDATE_SECRETS, - userId: new Types.ObjectId(userId), - workspaceId: new Types.ObjectId(workspaceId), - secretIds: toUpdate.map((u) => u._id), - }); - - updateAction && actions.push(updateAction); } // handle adding new secrets @@ -494,14 +471,6 @@ export const v2PushSecrets = async ({ }); }), }); - - const addAction = await EELogService.createAction({ - name: ACTION_ADD_SECRETS, - userId: new Types.ObjectId(userId), - workspaceId: new Types.ObjectId(workspaceId), - secretIds: newSecrets.map((n) => n._id), - }); - addAction && actions.push(addAction); } // (EE) take a secret snapshot @@ -509,17 +478,6 @@ export const v2PushSecrets = async ({ workspaceId: new Types.ObjectId(workspaceId), environment, }); - - // (EE) create (audit) log - if (actions.length > 0) { - await EELogService.createLog({ - userId: new Types.ObjectId(userId), - workspaceId: new Types.ObjectId(workspaceId), - actions, - channel, - ipAddress, - }); - } }; /** @@ -589,22 +547,6 @@ export const pullSecrets = async ({ environment, }); - const readAction = await EELogService.createAction({ - name: ACTION_READ_SECRETS, - userId: new Types.ObjectId(userId), - workspaceId: new Types.ObjectId(workspaceId), - secretIds: secrets.map((n: any) => n._id), - }); - - readAction && - (await EELogService.createLog({ - userId: new Types.ObjectId(userId), - workspaceId: new Types.ObjectId(workspaceId), - actions: [readAction], - channel, - ipAddress, - })); - return secrets; }; diff --git a/backend/src/helpers/secrets.ts b/backend/src/helpers/secrets.ts index f6252d5c6..6bd2db1cd 100644 --- a/backend/src/helpers/secrets.ts +++ b/backend/src/helpers/secrets.ts @@ -29,10 +29,6 @@ import { UnauthorizedRequestError } from "../utils/errors"; import { - ACTION_ADD_SECRETS, - ACTION_DELETE_SECRETS, - ACTION_READ_SECRETS, - ACTION_UPDATE_SECRETS, ALGORITHM_AES_256_GCM, ENCODING_SCHEME_BASE64, ENCODING_SCHEME_UTF8, @@ -48,8 +44,8 @@ import { } from "../utils/crypto"; import { TelemetryService } from "../services"; import { client, getEncryptionKey, getRootEncryptionKey } from "../config"; -import { EEAuditLogService, EELogService, EESecretService } from "../ee/services"; -import { getAuthDataPayloadIdObj, getAuthDataPayloadUserObj } from "../utils/authn/helpers"; +import { EEAuditLogService, EESecretService } from "../ee/services"; +import { getAuthDataPayloadUserObj } from "../utils/authn/helpers"; import { getFolderByPath, getFolderIdFromServiceToken } from "../services/FolderService"; import picomatch from "picomatch"; import path from "path"; @@ -478,23 +474,6 @@ export const createSecretHelper = async ({ secretVersions: [secretVersion] }); - // (EE) create (audit) log - const action = await EELogService.createAction({ - name: ACTION_ADD_SECRETS, - ...getAuthDataPayloadIdObj(authData), - workspaceId, - secretIds: [secret._id] - }); - - action && - (await EELogService.createLog({ - ...getAuthDataPayloadIdObj(authData), - workspaceId, - actions: [action], - channel: authData.userAgentType, - ipAddress: authData.ipAddress - })); - await EEAuditLogService.createAuditLog( authData, { @@ -597,23 +576,6 @@ export const getSecretsHelper = async ({ .lean() ); - // (EE) create (audit) log - const action = await EELogService.createAction({ - name: ACTION_READ_SECRETS, - ...getAuthDataPayloadIdObj(authData), - workspaceId, - secretIds: secrets.map((secret) => secret._id) - }); - - action && - (await EELogService.createLog({ - ...getAuthDataPayloadIdObj(authData), - workspaceId, - actions: [action], - channel: authData.userAgentType, - ipAddress: authData.ipAddress - })); - await EEAuditLogService.createAuditLog( authData, { @@ -725,23 +687,6 @@ export const getSecretHelper = async ({ if (!secret) throw SecretNotFoundError(); - // (EE) create (audit) log - const action = await EELogService.createAction({ - name: ACTION_READ_SECRETS, - ...getAuthDataPayloadIdObj(authData), - workspaceId, - secretIds: [secret._id] - }); - - action && - (await EELogService.createLog({ - ...getAuthDataPayloadIdObj(authData), - workspaceId, - actions: [action], - channel: authData.userAgentType, - ipAddress: authData.ipAddress - })); - await EEAuditLogService.createAuditLog( authData, { @@ -945,23 +890,6 @@ export const updateSecretHelper = async ({ secretVersions: [secretVersion] }); - // (EE) create (audit) log - const action = await EELogService.createAction({ - name: ACTION_UPDATE_SECRETS, - ...getAuthDataPayloadIdObj(authData), - workspaceId, - secretIds: [secret._id] - }); - - action && - (await EELogService.createLog({ - ...getAuthDataPayloadIdObj(authData), - workspaceId, - actions: [action], - channel: authData.userAgentType, - ipAddress: authData.ipAddress - })); - await EEAuditLogService.createAuditLog( authData, { @@ -1089,23 +1017,6 @@ export const deleteSecretHelper = async ({ secretIds: secrets.map((secret) => secret._id) }); - // (EE) create (audit) log - const action = await EELogService.createAction({ - name: ACTION_DELETE_SECRETS, - ...getAuthDataPayloadIdObj(authData), - workspaceId, - secretIds: secrets.map((secret) => secret._id) - }); - - action && - (await EELogService.createLog({ - ...getAuthDataPayloadIdObj(authData), - workspaceId, - actions: [action], - channel: authData.userAgentType, - ipAddress: authData.ipAddress - })); - await EEAuditLogService.createAuditLog( authData, { @@ -1769,22 +1680,6 @@ export const deleteSecretBatchHelper = async ({ secretIds: deletedSecrets.map((secret) => secret._id) }); - const action = await EELogService.createAction({ - name: ACTION_DELETE_SECRETS, - ...getAuthDataPayloadIdObj(authData), - workspaceId, - secretIds: deletedSecrets.map((secret) => secret._id) - }); - - action && - (await EELogService.createLog({ - ...getAuthDataPayloadIdObj(authData), - workspaceId, - actions: [action], - channel: authData.userAgentType, - ipAddress: authData.ipAddress - })); - await EEAuditLogService.createAuditLog( authData, { diff --git a/backend/src/helpers/user.ts b/backend/src/helpers/user.ts index 5c840e906..8085dd599 100644 --- a/backend/src/helpers/user.ts +++ b/backend/src/helpers/user.ts @@ -10,10 +10,6 @@ import { User, UserAction } from "../models"; -import { - Action, - Log -} from "../ee/models"; import { sendMail } from "./nodemailer"; import { InternalServerError, @@ -247,14 +243,6 @@ export const deleteUser = async ({ user: user._id }); - await Action.deleteMany({ - user: user._id - }); - - await Log.deleteMany({ - user: user._id - }); - await TokenVersion.deleteMany({ user: user._id }); diff --git a/backend/src/helpers/workspace.ts b/backend/src/helpers/workspace.ts index 413b187d1..60e4955b5 100644 --- a/backend/src/helpers/workspace.ts +++ b/backend/src/helpers/workspace.ts @@ -19,11 +19,9 @@ import { Workspace } from "../models"; import { - Action, AuditLog, FolderVersion, IPType, - Log, SecretApprovalPolicy, SecretApprovalRequest, SecretSnapshot, @@ -193,14 +191,6 @@ export const deleteWorkspace = async ({ workspace: workspace._id }); - await Log.deleteMany({ - workspace: workspace._id - }); - - await Action.deleteMany({ - workspace: workspace._id - }); - await SecretApprovalPolicy.deleteMany({ workspace: workspace._id }); diff --git a/backend/src/index.ts b/backend/src/index.ts index d7fb17178..df3abb0e3 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -18,7 +18,6 @@ const swaggerFile = require("../spec.json"); // eslint-disable-next-line @typescript-eslint/no-var-requires import { apiLimiter } from "./helpers/rateLimiter"; import { - action as eeActionRouter, cloudProducts as eeCloudProductsRouter, organizations as eeOrganizationsRouter, sso as eeSSORouter, @@ -193,7 +192,6 @@ const main = async () => { app.use("/api/v1/secret-snapshot", eeSecretSnapshotRouter); app.use("/api/v1/users", eeUsersRouter); app.use("/api/v1/workspace", eeWorkspaceRouter); - app.use("/api/v1/action", eeActionRouter); app.use("/api/v1/organizations", eeOrganizationsRouter); app.use("/api/v1/sso", eeSSORouter); app.use("/api/v1/cloud-products", eeCloudProductsRouter); @@ -240,14 +238,13 @@ const main = async () => { app.use("/api/v2/secret", v2SecretRouter); // deprecate app.use("/api/v2/secrets", v2SecretsRouter); // note: in the process of moving to v3/secrets app.use("/api/v2/service-token", v2ServiceTokenDataRouter); - // app.use("/api/v2/service-accounts", v2ServiceAccountsRouter); // new // v3 routes (experimental) app.use("/api/v3/auth", v3AuthRouter); app.use("/api/v3/secrets", v3SecretsRouter); app.use("/api/v3/workspaces", v3WorkspacesRouter); app.use("/api/v3/signup", v3SignupRouter); - app.use("/api/v3/users", v3UsersRouter); + app.use("/api/v3/us", v3UsersRouter); // api docs app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerFile)); diff --git a/backend/src/interfaces/serviceAccounts/dto/AddServiceAccountPermissionDto.ts b/backend/src/interfaces/serviceAccounts/dto/AddServiceAccountPermissionDto.ts deleted file mode 100644 index 6d0954c00..000000000 --- a/backend/src/interfaces/serviceAccounts/dto/AddServiceAccountPermissionDto.ts +++ /dev/null @@ -1,7 +0,0 @@ -interface AddServiceAccountPermissionDto { - name: string; - workspaceId?: string; - environment?: string; -} - -export default AddServiceAccountPermissionDto; \ No newline at end of file diff --git a/backend/src/interfaces/serviceAccounts/dto/CreateServiceAccountDto.ts b/backend/src/interfaces/serviceAccounts/dto/CreateServiceAccountDto.ts deleted file mode 100644 index dcab0f302..000000000 --- a/backend/src/interfaces/serviceAccounts/dto/CreateServiceAccountDto.ts +++ /dev/null @@ -1,8 +0,0 @@ -interface CreateServiceAccountDto { - organizationId: string; - name: string; - publicKey: string; - expiresIn: number; -} - -export default CreateServiceAccountDto; \ No newline at end of file diff --git a/backend/src/interfaces/serviceAccounts/dto/index.ts b/backend/src/interfaces/serviceAccounts/dto/index.ts deleted file mode 100644 index f69778144..000000000 --- a/backend/src/interfaces/serviceAccounts/dto/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import CreateServiceAccountDto from "./CreateServiceAccountDto"; -import AddServiceAccountPermissionDto from "./AddServiceAccountPermissionDto"; - -export { - CreateServiceAccountDto, - AddServiceAccountPermissionDto, -} \ No newline at end of file diff --git a/backend/src/middleware/index.ts b/backend/src/middleware/index.ts index b8c88bd26..bd1d1a48e 100644 --- a/backend/src/middleware/index.ts +++ b/backend/src/middleware/index.ts @@ -10,8 +10,6 @@ import requireIntegrationAuth from "./requireIntegrationAuth"; import requireIntegrationAuthorizationAuth from "./requireIntegrationAuthorizationAuth"; import requireServiceTokenAuth from "./requireServiceTokenAuth"; import requireServiceTokenDataAuth from "./requireServiceTokenDataAuth"; -import requireServiceAccountAuth from "./requireServiceAccountAuth"; -import requireServiceAccountWorkspacePermissionAuth from "./requireServiceAccountWorkspacePermissionAuth"; import requireSecretAuth from "./requireSecretAuth"; import requireSecretsAuth from "./requireSecretsAuth"; import requireBlindIndicesEnabled from "./requireBlindIndicesEnabled"; @@ -32,8 +30,6 @@ export { requireIntegrationAuthorizationAuth, requireServiceTokenAuth, requireServiceTokenDataAuth, - requireServiceAccountAuth, - requireServiceAccountWorkspacePermissionAuth, requireSecretAuth, requireSecretsAuth, requireBlindIndicesEnabled, diff --git a/backend/src/middleware/requireServiceAccountAuth.ts b/backend/src/middleware/requireServiceAccountAuth.ts deleted file mode 100644 index f7e423b79..000000000 --- a/backend/src/middleware/requireServiceAccountAuth.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { NextFunction, Request, Response } from "express"; -import { Types } from "mongoose"; -import { validateClientForServiceAccount } from "../validation"; - -type req = "params" | "body" | "query"; - -const requireServiceAccountAuth = ({ - acceptedRoles, - acceptedStatuses, - locationServiceAccountId = "params", - requiredPermissions = [], -}: { - acceptedRoles: string[]; - acceptedStatuses: string[]; - locationServiceAccountId?: req; - requiredPermissions?: string[]; -}) => { - return async (req: Request, res: Response, next: NextFunction) => { - const serviceAccountId = req[locationServiceAccountId].serviceAccountId; - - req.serviceAccount = await validateClientForServiceAccount({ - authData: req.authData, - serviceAccountId: new Types.ObjectId(serviceAccountId), - requiredPermissions, - }); - - next(); - } -} - -export default requireServiceAccountAuth; \ No newline at end of file diff --git a/backend/src/middleware/requireServiceAccountWorkspacePermissionAuth.ts b/backend/src/middleware/requireServiceAccountWorkspacePermissionAuth.ts deleted file mode 100644 index 535cd2068..000000000 --- a/backend/src/middleware/requireServiceAccountWorkspacePermissionAuth.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { NextFunction, Request, Response } from "express"; -import { ServiceAccount, ServiceAccountWorkspacePermission } from "../models"; -import { - ServiceAccountNotFoundError, -} from "../utils/errors"; -import { - validateMembershipOrg, -} from "../helpers/membershipOrg"; - -type req = "params" | "body" | "query"; - -const requireServiceAccountWorkspacePermissionAuth = ({ - acceptedRoles, - acceptedStatuses, - location = "params", -}: { - acceptedRoles: Array<"owner" | "admin" | "member">; - acceptedStatuses: Array<"invited" | "accepted">; - location?: req; -}) => { - return async (req: Request, res: Response, next: NextFunction) => { - const serviceAccountWorkspacePermissionId = req[location].serviceAccountWorkspacePermissionId; - const serviceAccountWorkspacePermission = await ServiceAccountWorkspacePermission.findById(serviceAccountWorkspacePermissionId); - - if (!serviceAccountWorkspacePermission) { - return next(ServiceAccountNotFoundError({ message: "Failed to locate Service Account workspace permission" })); - } - - const serviceAccount = await ServiceAccount.findById(serviceAccountWorkspacePermission.serviceAccount); - - if (!serviceAccount) { - return next(ServiceAccountNotFoundError({ message: "Failed to locate Service Account" })); - } - - if (serviceAccount.user.toString() !== req.user.id.toString()) { - // case: creator of the service account is different from - // the user on the request -> apply middleware role/status validation - await validateMembershipOrg({ - userId: req.user._id, - organizationId: serviceAccount.organization, - acceptedRoles, - acceptedStatuses, - }); - } - - req.serviceAccount = serviceAccount; - - next(); - } -} - -export default requireServiceAccountWorkspacePermissionAuth; \ No newline at end of file diff --git a/backend/src/models/index.ts b/backend/src/models/index.ts index 6bd1ebef6..a437541b1 100644 --- a/backend/src/models/index.ts +++ b/backend/src/models/index.ts @@ -15,10 +15,6 @@ export * from "./folder"; export * from "./secretImports"; export * from "./secretBlindIndexData"; export * from "./serviceToken"; // TODO: deprecate -export * from "./serviceAccount"; // TODO: deprecate -export * from "./serviceAccountKey"; // TODO: deprecate -export * from "./serviceAccountOrganizationPermission"; // TODO: deprecate -export * from "./serviceAccountWorkspacePermission"; // TODO: deprecate export * from "./tokenData"; export * from "./user"; export * from "./userAction"; diff --git a/backend/src/models/serviceAccount.ts b/backend/src/models/serviceAccount.ts deleted file mode 100644 index 75ae157c6..000000000 --- a/backend/src/models/serviceAccount.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Document, Schema, Types, model } from "mongoose"; - -export interface IServiceAccount extends Document { - _id: Types.ObjectId; - name: string; - organization: Types.ObjectId; - user: Types.ObjectId; - publicKey: string; - lastUsed: Date; - expiresAt: Date; - secretHash: string; -} - -const serviceAccountSchema = new Schema( - { - name: { - type: String, - required: true, - }, - organization: { - type: Schema.Types.ObjectId, - ref: "Organization", - required: true, - }, - user: { // user who created the service account - type: Schema.Types.ObjectId, - ref: "User", - required: true, - }, - publicKey: { - type: String, - required: true, - }, - lastUsed: { - type: Date, - }, - expiresAt: { - type: Date, - }, - secretHash: { - type: String, - required: true, - select: false, - }, - }, - { - timestamps: true, - } -); - -export const ServiceAccount = model("ServiceAccount", serviceAccountSchema); \ No newline at end of file diff --git a/backend/src/models/serviceAccountKey.ts b/backend/src/models/serviceAccountKey.ts deleted file mode 100644 index 538e39103..000000000 --- a/backend/src/models/serviceAccountKey.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Schema, Types, model } from "mongoose"; - -export interface IServiceAccountKey { - _id: Types.ObjectId; - encryptedKey: string; - nonce: string; - sender: Types.ObjectId; - serviceAccount: Types.ObjectId; - workspace: Types.ObjectId; -} - -const serviceAccountKeySchema = new Schema( - { - encryptedKey: { - type: String, - required: true, - }, - nonce: { - type: String, - required: true, - }, - sender: { - type: Schema.Types.ObjectId, - required: true, - }, - serviceAccount: { - type: Schema.Types.ObjectId, - ref: "ServiceAccount", - required: true, - }, - workspace: { - type: Schema.Types.ObjectId, - ref: "Workspace", - required: true, - }, - }, - { - timestamps: true, - } -); - -export const ServiceAccountKey = model("ServiceAccountKey", serviceAccountKeySchema); \ No newline at end of file diff --git a/backend/src/models/serviceAccountOrganizationPermission.ts b/backend/src/models/serviceAccountOrganizationPermission.ts deleted file mode 100644 index 970ec7461..000000000 --- a/backend/src/models/serviceAccountOrganizationPermission.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Document, Schema, Types, model } from "mongoose"; - -export interface IServiceAccountOrganizationPermission extends Document { - _id: Types.ObjectId; - serviceAccount: Types.ObjectId; -} - -const serviceAccountOrganizationPermissionSchema = new Schema( - { - serviceAccount: { - type: Schema.Types.ObjectId, - ref: "ServiceAccount", - required: true, - }, - }, - { - timestamps: true, - } -); - -export const ServiceAccountOrganizationPermission = model("ServiceAccountOrganizationPermission", serviceAccountOrganizationPermissionSchema); \ No newline at end of file diff --git a/backend/src/models/serviceAccountWorkspacePermission.ts b/backend/src/models/serviceAccountWorkspacePermission.ts deleted file mode 100644 index 1d3523766..000000000 --- a/backend/src/models/serviceAccountWorkspacePermission.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Document, Schema, Types, model } from "mongoose"; - -export interface IServiceAccountWorkspacePermission extends Document { - _id: Types.ObjectId; - serviceAccount: Types.ObjectId; - workspace: Types.ObjectId; - environment: string; - read: boolean; - write: boolean; -} - -const serviceAccountWorkspacePermissionSchema = new Schema( - { - serviceAccount: { - type: Schema.Types.ObjectId, - ref: "ServiceAccount", - required: true, - }, - workspace:{ - type: Schema.Types.ObjectId, - ref: "Workspace", - required: true, - }, - environment: { - type: String, - required: true, - }, - read: { - type: Boolean, - default: false, - }, - write: { - type: Boolean, - default: false, - }, - }, - { - timestamps: true, - } -); - -export const ServiceAccountWorkspacePermission = model("ServiceAccountWorkspacePermission", serviceAccountWorkspacePermissionSchema); \ No newline at end of file diff --git a/backend/src/routes/v2/index.ts b/backend/src/routes/v2/index.ts index 597dbafa4..99ad9c01a 100644 --- a/backend/src/routes/v2/index.ts +++ b/backend/src/routes/v2/index.ts @@ -4,7 +4,6 @@ import membership from "./membership"; import organizations from "./organizations"; import secret from "./secret"; // deprecated import secrets from "./secrets"; -import serviceAccounts from "./serviceAccounts"; import serviceTokenData from "./serviceTokenData"; import signup from "./signup"; import tags from "./tags"; @@ -20,7 +19,6 @@ export { secret, secrets, serviceTokenData, - serviceAccounts, environment, tags, membership diff --git a/backend/src/routes/v2/organizations.ts b/backend/src/routes/v2/organizations.ts index 537449273..6eea6fc5a 100644 --- a/backend/src/routes/v2/organizations.ts +++ b/backend/src/routes/v2/organizations.ts @@ -1,10 +1,7 @@ import express from "express"; const router = express.Router(); -import { - requireAuth, - requireOrganizationAuth -} from "../../middleware"; -import { ACCEPTED, ADMIN, AuthMode } from "../../variables"; +import { requireAuth } from "../../middleware"; +import { AuthMode } from "../../variables"; import { organizationsController } from "../../controllers/v2"; // TODO: /POST to create membership @@ -41,19 +38,6 @@ router.get( organizationsController.getOrganizationWorkspaces ); -router.get( - // TODO endpoint: deprecate service accounts - "/:organizationId/service-accounts", - requireAuth({ - acceptedAuthModes: [AuthMode.JWT] - }), - requireOrganizationAuth({ - acceptedRoles: [ADMIN], - acceptedStatuses: [ACCEPTED] - }), - organizationsController.getOrganizationServiceAccounts -); - router.post( "/", requireAuth({ diff --git a/backend/src/routes/v2/serviceAccounts.ts b/backend/src/routes/v2/serviceAccounts.ts deleted file mode 100644 index 85b7c9350..000000000 --- a/backend/src/routes/v2/serviceAccounts.ts +++ /dev/null @@ -1,161 +0,0 @@ -import express from "express"; -const router = express.Router(); - -// TODO endpoint: deprecate all - -// import { -// requireAuth, -// requireOrganizationAuth, -// requireServiceAccountAuth, -// requireServiceAccountWorkspacePermissionAuth, -// requireWorkspaceAuth, -// validateRequest, -// } from "../../middleware"; -// import { body, param, query } from "express-validator"; -// import { -// ACCEPTED, -// ADMIN, -// MEMBER, -// OWNER, -// AuthMode -// } from "../../variables"; -// import { serviceAccountsController } from "../../controllers/v2"; - -// router.get( // TODO: check -// "/me", -// requireAuth({ -// acceptedAuthModes: [AUTH_MODE_SERVICE_ACCOUNT], -// }), -// serviceAccountsController.getCurrentServiceAccount -// ); - -// router.get( -// "/:serviceAccountId", -// param("serviceAccountId").exists().isString().trim(), -// requireAuth({ -// acceptedAuthModes: [AUTH_MODE_JWT], -// }), -// requireServiceAccountAuth({ -// acceptedRoles: [OWNER, ADMIN], -// acceptedStatuses: [ACCEPTED], -// }), -// serviceAccountsController.getServiceAccountById -// ); - -// router.post( -// "/", -// body("organizationId").exists().isString().trim(), -// body("name").exists().isString().trim(), -// body("publicKey").exists().isString().trim(), -// body("expiresIn").isNumeric(), // measured in ms -// validateRequest, -// requireAuth({ -// acceptedAuthModes: [AUTH_MODE_JWT], -// }), -// requireOrganizationAuth({ -// acceptedRoles: [OWNER, ADMIN, MEMBER], -// acceptedStatuses: [ACCEPTED], -// locationOrganizationId: "body", -// }), -// serviceAccountsController.createServiceAccount -// ); - -// router.patch( -// "/:serviceAccountId/name", -// param("serviceAccountId").exists().isString().trim(), -// validateRequest, -// requireAuth({ -// acceptedAuthModes: [AUTH_MODE_JWT], -// }), -// requireServiceAccountAuth({ -// acceptedRoles: [OWNER, ADMIN], -// acceptedStatuses: [ACCEPTED], -// }), -// serviceAccountsController.changeServiceAccountName -// ); - -// router.delete( -// "/:serviceAccountId", -// param("serviceAccountId").exists().isString().trim(), -// validateRequest, -// requireAuth({ -// acceptedAuthModes: [AUTH_MODE_JWT], -// }), -// requireServiceAccountAuth({ -// acceptedRoles: [OWNER, ADMIN], -// acceptedStatuses: [ACCEPTED], -// }), -// serviceAccountsController.deleteServiceAccount -// ); - -// router.get( -// "/:serviceAccountId/permissions/workspace", -// param("serviceAccountId").exists().isString().trim(), -// validateRequest, -// requireAuth({ -// acceptedAuthModes: [AUTH_MODE_JWT], -// }), -// requireServiceAccountAuth({ -// acceptedRoles: [OWNER, ADMIN], -// acceptedStatuses: [ACCEPTED], -// }), -// serviceAccountsController.getServiceAccountWorkspacePermissions -// ); - -// router.post( -// "/:serviceAccountId/permissions/workspace", -// param("serviceAccountId").exists().isString().trim(), -// body("workspaceId").exists().isString().notEmpty(), -// body("environment").exists().isString().notEmpty(), -// body("read").isBoolean().optional(), -// body("write").isBoolean().optional(), -// body("encryptedKey").exists().isString().notEmpty(), -// body("nonce").exists().isString().notEmpty(), -// validateRequest, -// requireAuth({ -// acceptedAuthModes: [AUTH_MODE_JWT], -// }), -// requireServiceAccountAuth({ -// acceptedRoles: [OWNER, ADMIN], -// acceptedStatuses: [ACCEPTED], -// }), -// requireWorkspaceAuth({ -// acceptedRoles: [ADMIN, MEMBER], -// locationWorkspaceId: "body", -// }), -// serviceAccountsController.addServiceAccountWorkspacePermission -// ); - -// router.delete( -// "/:serviceAccountId/permissions/workspace/:serviceAccountWorkspacePermissionId", -// param("serviceAccountId").exists().isString().trim(), -// param("serviceAccountWorkspacePermissionId").exists().isString().trim(), -// validateRequest, -// requireAuth({ -// acceptedAuthModes: [AUTH_MODE_JWT], -// }), -// requireServiceAccountAuth({ -// acceptedRoles: [OWNER, ADMIN], -// acceptedStatuses: [ACCEPTED], -// }), -// requireServiceAccountWorkspacePermissionAuth({ -// acceptedRoles: [OWNER, ADMIN], -// acceptedStatuses: [ACCEPTED], -// }), -// serviceAccountsController.deleteServiceAccountWorkspacePermission -// ); - -// router.get( -// "/:serviceAccountId/keys", -// query("workspaceId").optional().isString(), -// requireAuth({ -// acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_ACCOUNT], -// }), -// requireServiceAccountAuth({ -// acceptedRoles: [OWNER, ADMIN], -// acceptedStatuses: [ACCEPTED], -// }), -// serviceAccountsController.getServiceAccountKeys -// ); - -export default router; \ No newline at end of file diff --git a/backend/src/services/TelemetryService.ts b/backend/src/services/TelemetryService.ts index 63e4f0c12..c24c36bac 100644 --- a/backend/src/services/TelemetryService.ts +++ b/backend/src/services/TelemetryService.ts @@ -8,7 +8,6 @@ import { getTelemetryEnabled, } from "../config"; import { - ServiceAccount, ServiceTokenData, User, } from "../models"; @@ -56,16 +55,11 @@ class Telemetry { let distinctId = ""; if (authData.authPayload instanceof User) { distinctId = authData.authPayload.email; - } else if (authData.authPayload instanceof ServiceAccount) { - distinctId = `sa.${authData.authPayload._id.toString()}`; } else if (authData.authPayload instanceof ServiceTokenData) { - if (authData.authPayload.user) { const user = await User.findById(authData.authPayload.user, "email"); if (!user) throw AccountNotFoundError(); distinctId = user.email; - } else if (authData.authPayload.serviceAccount) { - distinctId = distinctId = `sa.${authData.authPayload.serviceAccount.toString()}`; } } diff --git a/backend/src/types/express/index.d.ts b/backend/src/types/express/index.d.ts index d3a5fbc23..654a24f1d 100644 --- a/backend/src/types/express/index.d.ts +++ b/backend/src/types/express/index.d.ts @@ -29,7 +29,6 @@ declare global { secrets: any; secretSnapshot: any; serviceToken: any; - serviceAccount: any; accessToken: any; accessId: any; serviceTokenData: any; diff --git a/backend/src/utils/authn/helpers/authDataExtractors.ts b/backend/src/utils/authn/helpers/authDataExtractors.ts index 60639739e..d35163e03 100644 --- a/backend/src/utils/authn/helpers/authDataExtractors.ts +++ b/backend/src/utils/authn/helpers/authDataExtractors.ts @@ -1,6 +1,5 @@ import { AuthData } from "../../../interfaces/middleware"; import { - ServiceAccount, ServiceTokenData, ServiceTokenDataV3, User @@ -16,10 +15,6 @@ import { return { userId: authData.authPayload._id }; } - if (authData.authPayload instanceof ServiceAccount) { - return { serviceAccountId: authData.authPayload._id }; - } - if (authData.authPayload instanceof ServiceTokenData) { return { serviceTokenDataId: authData.authPayload._id }; } @@ -39,10 +34,6 @@ export const getAuthDataPayloadUserObj = (authData: AuthData) => { return { user: authData.authPayload._id }; } - if (authData.authPayload instanceof ServiceAccount) { - return { user: authData.authPayload.user }; - } - if (authData.authPayload instanceof ServiceTokenData) { return { user: authData.authPayload.user }; } diff --git a/backend/src/utils/errors.ts b/backend/src/utils/errors.ts index 1751dcd92..105069c2a 100644 --- a/backend/src/utils/errors.ts +++ b/backend/src/utils/errors.ts @@ -182,16 +182,6 @@ export const SecretSnapshotNotFoundError = (error?: Partial stack: error?.stack, }); -//* ----->[ACTION ERRORS]<----- -export const ActionNotFoundError = (error?: Partial) => new RequestError({ - logLevel: error?.logLevel ?? LogLevel.ERROR, - statusCode: error?.statusCode ?? 404, - type: error?.type ?? "action_not_found_error", - message: error?.message ?? "The requested action was not found", - context: error?.context, - stack: error?.stack, -}); - //* ----->[SERVICE TOKEN DATA ERRORS]<----- export const ServiceTokenDataNotFoundError = (error?: Partial) => new RequestError({ logLevel: error?.logLevel ?? LogLevel.ERROR, @@ -212,25 +202,6 @@ export const APIKeyDataNotFoundError = (error?: Partial) => stack: error?.stack, }); -//* ----->[SERVICE_ACCOUNT ERRORS]<----- -export const ServiceAccountNotFoundError = (error?: Partial) => new RequestError({ - logLevel: error?.logLevel ?? LogLevel.ERROR, - statusCode: error?.statusCode ?? 404, - type: error?.type ?? "service_account_not_found_error", - message: error?.message ?? "The requested service account was not found", - context: error?.context, - stack: error?.stack, -}); - -export const ServiceAccountKeyNotFoundError = (error?: Partial) => new RequestError({ - logLevel: error?.logLevel ?? LogLevel.ERROR, - statusCode: error?.statusCode ?? 404, - type: error?.type ?? "service_account_key_not_found_error", - message: error?.message ?? "The requested service account key was not found", - context: error?.context, - stack: error?.stack, -}) - export const BotNotFoundError = (error?: Partial) => new RequestError({ logLevel: error?.logLevel ?? LogLevel.ERROR, statusCode: error?.statusCode ?? 404, diff --git a/backend/src/validation/index.ts b/backend/src/validation/index.ts index 447948c5a..002eda34d 100644 --- a/backend/src/validation/index.ts +++ b/backend/src/validation/index.ts @@ -7,7 +7,6 @@ export * from "./membership"; export * from "./membershipOrg"; export * from "./organization"; export * from "./secrets"; -export * from "./serviceAccount"; export * from "./serviceTokenData"; export * from "./serviceTokenDataV3"; export * from "./apiKeyDataV3"; diff --git a/backend/src/validation/serviceAccount.ts b/backend/src/validation/serviceAccount.ts deleted file mode 100644 index b4cb562c4..000000000 --- a/backend/src/validation/serviceAccount.ts +++ /dev/null @@ -1,227 +0,0 @@ -import _ from "lodash"; -import { Types } from "mongoose"; -import { - IOrganization, - ISecret, - IServiceAccount, - IUser, - ServiceAccount, - ServiceAccountWorkspacePermission, -} from "../models"; -import { validateUserClientForServiceAccount } from "./user"; -import { - BadRequestError, - ServiceAccountNotFoundError, - UnauthorizedRequestError, -} from "../utils/errors"; -import { - PERMISSION_READ_SECRETS, - PERMISSION_WRITE_SECRETS, -} from "../variables"; -import { AuthData } from "../interfaces/middleware"; -import { ActorType } from "../ee/models"; - -export const validateClientForServiceAccount = async ({ - authData, - serviceAccountId, - requiredPermissions, -}: { - authData: AuthData; - serviceAccountId: Types.ObjectId; - requiredPermissions?: string[]; -}) => { - const serviceAccount = await ServiceAccount.findById(serviceAccountId); - - if (!serviceAccount) { - throw ServiceAccountNotFoundError({ - message: "Failed to find service account", - }); - } - - switch (authData.actor.type) { - case ActorType.USER: - await validateUserClientForServiceAccount({ - user: authData.authPayload as IUser, - serviceAccount, - requiredPermissions, - }); - - return serviceAccount; - case ActorType.SERVICE: - throw UnauthorizedRequestError({ - message: "Failed service token authorization for service account resource", - }); - } -} - -/** - * Validate that service account (client) can access workspace - * with id [workspaceId] and its environment [environment] with required permissions - * [requiredPermissions] - * @param {Object} obj - * @param {ServiceAccount} obj.serviceAccount - service account client - * @param {Types.ObjectId} obj.workspaceId - id of workspace to validate against - * @param {String} environment - (optional) environment in workspace to validate against - * @param {String[]} requiredPermissions - required permissions as part of the endpoint - */ -export const validateServiceAccountClientForWorkspace = async ({ - serviceAccount, - workspaceId, - environment, - requiredPermissions, -}: { - serviceAccount: IServiceAccount; - workspaceId: Types.ObjectId; - environment?: string; - requiredPermissions?: string[]; -}) => { - if (environment) { - // case: environment specified -> - // evaluate service account authorization for workspace - // in the context of a specific environment [environment] - const permission = await ServiceAccountWorkspacePermission.findOne({ - serviceAccount, - workspace: new Types.ObjectId(workspaceId), - environment, - }); - - if (!permission) throw UnauthorizedRequestError({ - message: "Failed service account authorization for the given workspace environment", - }); - - let runningIsDisallowed = false; - requiredPermissions?.forEach((requiredPermission: string) => { - switch (requiredPermission) { - case PERMISSION_READ_SECRETS: - if (!permission.read) runningIsDisallowed = true; - break; - case PERMISSION_WRITE_SECRETS: - if (!permission.write) runningIsDisallowed = true; - break; - default: - break; - } - - if (runningIsDisallowed) { - throw UnauthorizedRequestError({ - message: `Failed permissions authorization for workspace environment action : ${requiredPermission}`, - }); - } - }); - - } else { - // case: no environment specified -> - // evaluate service account authorization for workspace - // without need of environment [environment] - - const permission = await ServiceAccountWorkspacePermission.findOne({ - serviceAccount, - workspace: new Types.ObjectId(workspaceId), - }); - - if (!permission) throw UnauthorizedRequestError({ - message: "Failed service account authorization for the given workspace", - }); - } -} - -/** - * Validate that service account (client) can access secrets - * with required permissions [requiredPermissions] - * @param {Object} obj - * @param {ServiceAccount} obj.serviceAccount - service account client - * @param {Secret[]} secrets - secrets to validate against - * @param {string[]} requiredPermissions - required permissions as part of the endpoint - */ -export const validateServiceAccountClientForSecrets = async ({ - serviceAccount, - secrets, - requiredPermissions, -}: { - serviceAccount: IServiceAccount; - secrets: ISecret[]; - requiredPermissions?: string[]; -}) => { - - const permissions = await ServiceAccountWorkspacePermission.find({ - serviceAccount: serviceAccount._id, - }); - - const permissionsObj = _.keyBy(permissions, (p) => { - return `${p.workspace.toString()}-${p.environment}` - }); - - secrets.forEach((secret: ISecret) => { - const permission = permissionsObj[`${secret.workspace.toString()}-${secret.environment}`]; - - if (!permission) throw BadRequestError({ - message: "Failed to find any permission for the secret workspace and environment", - }); - - requiredPermissions?.forEach((requiredPermission: string) => { - let runningIsDisallowed = false; - requiredPermissions?.forEach((requiredPermission: string) => { - switch (requiredPermission) { - case PERMISSION_READ_SECRETS: - if (!permission.read) runningIsDisallowed = true; - break; - case PERMISSION_WRITE_SECRETS: - if (!permission.write) runningIsDisallowed = true; - break; - default: - break; - } - - if (runningIsDisallowed) { - throw UnauthorizedRequestError({ - message: `Failed permissions authorization for workspace environment action : ${requiredPermission}`, - }); - } - }); - }); - }); -} - -/** - * Validate that service account (client) can access target service - * account [serviceAccount] with required permissions [requiredPermissions] - * @param {Object} obj - * @param {SerivceAccount} obj.serviceAccount - service account client - * @param {ServiceAccount} targetServiceAccount - target service account to validate against - * @param {string[]} requiredPermissions - required permissions as part of the endpoint - */ -export const validateServiceAccountClientForServiceAccount = ({ - serviceAccount, - targetServiceAccount, - requiredPermissions, -}: { - serviceAccount: IServiceAccount; - targetServiceAccount: IServiceAccount; - requiredPermissions?: string[]; -}) => { - if (!serviceAccount.organization.equals(targetServiceAccount.organization)) { - throw UnauthorizedRequestError({ - message: "Failed service account authorization for the given service account", - }); - } -} - -/** - * Validate that service account (client) can access organization [organization] - * @param {Object} obj - * @param {User} obj.user - service account client - * @param {Organization} obj.organization - organization to validate against - */ -export const validateServiceAccountClientForOrganization = async ({ - serviceAccount, - organization, -}: { - serviceAccount: IServiceAccount; - organization: IOrganization; -}) => { - if (!serviceAccount.organization.equals(organization._id)) { - throw UnauthorizedRequestError({ - message: "Failed service account authorization for the given organization", - }); - } -} \ No newline at end of file diff --git a/backend/src/validation/user.ts b/backend/src/validation/user.ts index 9f1176f96..1f356ec11 100644 --- a/backend/src/validation/user.ts +++ b/backend/src/validation/user.ts @@ -1,7 +1,7 @@ import fs from "fs"; import path from "path"; import { Types } from "mongoose"; -import { IOrganization, ISecret, IServiceAccount, IUser, Membership } from "../models"; +import { IOrganization, ISecret, IUser, Membership } from "../models"; import { validateMembership } from "../helpers/membership"; import _ from "lodash"; import { BadRequestError, UnauthorizedRequestError, ValidationError } from "../utils/errors"; @@ -172,35 +172,6 @@ export const validateUserClientForSecrets = async ({ }); }; -/** - * Validate that user (client) can access service account [serviceAccount] - * with required permissions [requiredPermissions] - * @param {Object} obj - * @param {User} obj.user - user client - * @param {ServiceAccount} obj.serviceAccount - service account to validate against - * @param {String[]} requiredPermissions - required permissions as part of the endpoint - */ -export const validateUserClientForServiceAccount = async ({ - user, - serviceAccount, - requiredPermissions -}: { - user: IUser; - serviceAccount: IServiceAccount; - requiredPermissions?: string[]; -}) => { - if (!serviceAccount.user.equals(user._id)) { - // case: user who created service account is not the - // same user that is on the request - await validateMembershipOrg({ - userId: user._id, - organizationId: serviceAccount.organization, - acceptedRoles: [], - acceptedStatuses: [] - }); - } -}; - /** * Validate that user (client) can access organization [organization] * @param {Object} obj diff --git a/frontend/src/components/basic/EventFilter.tsx b/frontend/src/components/basic/EventFilter.tsx deleted file mode 100644 index 46b2200f6..000000000 --- a/frontend/src/components/basic/EventFilter.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import React, { Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { - faAngleDown, - faEye, - faPlus, - faShuffle, - faTrash, - faX -} from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Listbox, Transition } from "@headlessui/react"; - -interface ListBoxProps { - selected: string; - select: (event: string) => void; -} - -const eventOptions = [ - { - name: "addSecrets", - icon: faPlus - }, - { - name: "readSecrets", - icon: faEye - }, - { - name: "updateSecrets", - icon: faShuffle - }, - { - name: "deleteSecrets", - icon: faTrash - } -]; - -/** - * This is the component that we use for the event picker in the activity logs tab. - * @param {object} obj - * @param {string} obj.selected - the event that is currently selected - * @param {function} obj.select - an action that happens when an item is selected - */ -const EventFilter = ({ selected, select }: ListBoxProps): JSX.Element => { - const { t } = useTranslation(); - - return ( - -
- - {selected !== "" ? ( -

{t(`activity.event.${selected}`)}

- ) : ( -

{String(t("common.select-event"))}

- )} - {selected !== "" ? ( - select("")} /> - ) : ( - - )} -
- - - {eventOptions.map((event, id) => ( - - {({ selected: isSelected }) => ( - - {" "} - {t(`activity.event.${event.name}`)} - - )} - - ))} - - -
-
- ); -}; - -export default EventFilter; diff --git a/frontend/src/ee/api/secrets/GetProjectLogs.ts b/frontend/src/ee/api/secrets/GetProjectLogs.ts deleted file mode 100644 index bc1d84f7d..000000000 --- a/frontend/src/ee/api/secrets/GetProjectLogs.ts +++ /dev/null @@ -1,76 +0,0 @@ -import SecurityClient from "@app/components/utilities/SecurityClient"; - -interface WorkspaceProps { - workspaceId: string; - offset: number; - limit: number; - userId: string; - actionNames: string; -} - -/** - * This function fetches the activity logs for a certain project - * @param {object} obj - * @param {string} obj.workspaceId - workspace id for which we are trying to get project log - * @param {object} obj.offset - teh starting point of logs that we want to pull - * @param {object} obj.limit - how many logs will we output - * @param {object} obj.userId - optional userId filter - will only query logs for that user - * @param {string} obj.actionNames - optional actionNames filter - will only query logs for those actions - * @returns - */ -const getProjectLogs = async ({ - workspaceId, - offset, - limit, - userId, - actionNames -}: WorkspaceProps) => { - let payload; - if (userId !== "" && actionNames !== "") { - payload = { - offset: String(offset), - limit: String(limit), - sortBy: "recent", - userId: JSON.stringify(userId), - actionNames - }; - } else if (userId !== "") { - payload = { - offset: String(offset), - limit: String(limit), - sortBy: "recent", - userId: JSON.stringify(userId) - }; - } else if (actionNames !== "") { - payload = { - offset: String(offset), - limit: String(limit), - sortBy: "recent", - actionNames - }; - } else { - payload = { - offset: String(offset), - limit: String(limit), - sortBy: "recent" - }; - } - - return SecurityClient.fetchCall( - `/api/v1/workspace/${workspaceId}/logs?${new URLSearchParams(payload)}`, - { - method: "GET", - headers: { - "Content-Type": "application/json" - } - } - ).then(async (res) => { - if (res && res.status === 200) { - return (await res.json()).logs; - } - console.log("Failed to get project logs"); - return undefined; - }); -}; - -export default getProjectLogs; diff --git a/frontend/src/ee/components/ActivitySideBar.tsx b/frontend/src/ee/components/ActivitySideBar.tsx deleted file mode 100644 index d1e068177..000000000 --- a/frontend/src/ee/components/ActivitySideBar.tsx +++ /dev/null @@ -1,237 +0,0 @@ -// TODO: deprecate in favor of new audit logs -import { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import Image from "next/image"; -import { useRouter } from "next/router"; -import { faXmark } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -import getActionData from "@app/ee/api/secrets/GetActionData"; -import patienceDiff from "@app/ee/utilities/findTextDifferences"; -import { - useGetUserWsKey -} from "@app/hooks/api"; - -import { - decryptAssymmetric, - decryptSymmetric -} from "../../components/utilities/cryptography/crypto"; - -interface SideBarProps { - toggleSidebar: (value: string) => void; - currentAction: string; -} - -interface SecretProps { - secret: string; - secretKeyCiphertext: string; - secretKeyHash: string; - secretKeyIV: string; - secretKeyTag: string; - secretValueCiphertext: string; - secretValueHash: string; - secretValueIV: string; - secretValueTag: string; -} - -interface DecryptedSecretProps { - newSecretVersion: { - key: string; - value: string; - }; - oldSecretVersion: { - key: string; - value: string; - }; -} - -interface ActionProps { - name: string; -} - -/** - * @param {object} obj - * @param {function} obj.toggleSidebar - function that opens or closes the sidebar - * @param {string} obj.currentAction - the action id for which a sidebar is being displayed - * @returns the sidebar with the payload of user activity logs - */ -const ActivitySideBar = ({ toggleSidebar, currentAction }: SideBarProps) => { - const { t } = useTranslation(); - const router = useRouter(); - const [actionData, setActionData] = useState(); - const [actionMetaData, setActionMetaData] = useState(); - const [isLoading, setIsLoading] = useState(false); - const { data: wsKey } = useGetUserWsKey(String(router.query.id)); - - useEffect(() => { - const getLogData = async () => { - setIsLoading(true); - const tempActionData = await getActionData({ actionId: currentAction }); - const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); - - // #TODO: make this a separate function and reuse across the app - let decryptedLatestKey: string; - if (wsKey) { - // assymmetrically decrypt symmetric key with local private key - decryptedLatestKey = decryptAssymmetric({ - ciphertext: wsKey.encryptedKey, - nonce: wsKey.nonce, - publicKey: wsKey.sender.publicKey, - privateKey: String(PRIVATE_KEY) - }); - - const decryptedSecretVersions = tempActionData.payload.secretVersions.map( - (encryptedSecretVersion: { - newSecretVersion?: SecretProps; - oldSecretVersion?: SecretProps; - }) => ({ - newSecretVersion: { - key: decryptSymmetric({ - ciphertext: encryptedSecretVersion.newSecretVersion!.secretKeyCiphertext, - iv: encryptedSecretVersion.newSecretVersion!.secretKeyIV, - tag: encryptedSecretVersion.newSecretVersion!.secretKeyTag, - key: decryptedLatestKey - }), - value: decryptSymmetric({ - ciphertext: encryptedSecretVersion.newSecretVersion!.secretValueCiphertext, - iv: encryptedSecretVersion.newSecretVersion!.secretValueIV, - tag: encryptedSecretVersion.newSecretVersion!.secretValueTag, - key: decryptedLatestKey - }) - }, - oldSecretVersion: { - key: encryptedSecretVersion.oldSecretVersion?.secretKeyCiphertext - ? decryptSymmetric({ - ciphertext: encryptedSecretVersion.oldSecretVersion?.secretKeyCiphertext, - iv: encryptedSecretVersion.oldSecretVersion?.secretKeyIV, - tag: encryptedSecretVersion.oldSecretVersion?.secretKeyTag, - key: decryptedLatestKey - }) - : undefined, - value: encryptedSecretVersion.oldSecretVersion?.secretValueCiphertext - ? decryptSymmetric({ - ciphertext: encryptedSecretVersion.oldSecretVersion?.secretValueCiphertext, - iv: encryptedSecretVersion.oldSecretVersion?.secretValueIV, - tag: encryptedSecretVersion.oldSecretVersion?.secretValueTag, - key: decryptedLatestKey - }) - : undefined - } - }) - ); - - setActionData(decryptedSecretVersions); - setActionMetaData({ name: tempActionData.name }); - setIsLoading(false); - } - }; - getLogData(); - }, [currentAction, wsKey]); - - return ( -
- {isLoading ? ( -
- infisical loading indicator -
- ) : ( -
-
-

- {t(`activity.event.${actionMetaData?.name}`)} -

-
null} - role="button" - tabIndex={0} - onClick={() => toggleSidebar("")} - > - -
-
-
- {(actionMetaData?.name === "readSecrets" || - actionMetaData?.name === "addSecrets" || - actionMetaData?.name === "deleteSecrets") && - actionData?.map((item, id) => ( -
-
- {item.newSecretVersion.key} -
-
- {item.newSecretVersion.value ? ( - {item.newSecretVersion.value} - ) : ( - EMPTY - )} -
-
- ))} - {actionMetaData?.name === "updateSecrets" && - actionData?.map((item, id) => ( - <> -
- {item.newSecretVersion.key} -
-
-
- -{" "} - {patienceDiff( - item.oldSecretVersion.value.split(""), - item.newSecretVersion.value.split(""), - false - ).lines.map( - (character, lineId) => - character.bIndex !== -1 && ( - - {character.line} - - ) - )} -
-
- +{" "} - {patienceDiff( - item.oldSecretVersion.value.split(""), - item.newSecretVersion.value.split(""), - false - ).lines.map( - (character, lineId) => - character.aIndex !== -1 && ( - - {character.line} - - ) - )} -
-
- - ))} -
-
- )} -
- ); -}; - -export default ActivitySideBar; diff --git a/frontend/src/ee/components/ActivityTable.tsx b/frontend/src/ee/components/ActivityTable.tsx deleted file mode 100644 index 63640e15a..000000000 --- a/frontend/src/ee/components/ActivityTable.tsx +++ /dev/null @@ -1,205 +0,0 @@ -// TODO: deprecate in favor of new audit logs - -/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ -import React, { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { faAngleDown, faAngleRight, faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -import timeSince from "@app/ee/utilities/timeSince"; - -import guidGenerator from "../../components/utilities/randomId"; - -interface PayloadProps { - _id: string; - name: string; - secretVersions: string[]; -} - -interface LogData { - _id: string; - channel: string; - createdAt: string; - ipAddress: string; - user: string; - serviceAccount: { - name: string; - }; - serviceTokenData: { - name: string; - }; - payload: PayloadProps[]; -} - -/** - * This is a single row of the activity table - * @param obj - * @param {LogData} obj.row - data for a certain event - * @param {function} obj.toggleSidebar - open and close sidebar that displays data for a specific event - * @returns - */ -const ActivityLogsRow = ({ - row, - toggleSidebar -}: { - row: LogData; - toggleSidebar: (value: string) => void; -}) => { - const [payloadOpened, setPayloadOpened] = useState(false); - const { t } = useTranslation(); - - const renderUser = () => { - - if (row?.user) return `${row.user}`; - if (row?.serviceAccount) return `Service Account: ${row.serviceAccount.name}`; - if (row?.serviceTokenData?.name) return `Service Token: ${row.serviceTokenData.name}`; - - return ""; - }; - return ( - <> -
- -
- {row.payload - ?.map( - (action) => - `${String(action.secretVersions.length)} ${t(`activity.event.${action.name}`)}` - ) - .join(" and ")} -
-
{renderUser()}
-
{row.channel}
-
- {timeSince(new Date(row.createdAt))} -
-
- {payloadOpened && ( -
-
-
-
{String(t("common.timestamp"))}
-
{row.createdAt}
-
-
- )} - {payloadOpened && - row.payload?.map( - (action) => - action.secretVersions.length > 0 && ( -
-
-
-
{t(`activity.event.${action.name}`)}
- -
-
- ) - )} - {payloadOpened && ( -
-
-
-
{String(t("activity.ip-address"))}
-
{row.ipAddress}
-
-
- )} - - ); -}; - -/** - * This is the table for activity logs (one of the tabs) - * @param {object} obj - * @param {logData} obj.data - data for user activity logs - * @param {function} obj.toggleSidebar - function that opens or closes the sidebar - * @param {boolean} obj.isLoading - whether the log data has been loaded yet or not - * @returns - */ -const ActivityTable = ({ - data, - toggleSidebar, - isLoading -}: { - data: LogData[]; - toggleSidebar: (value: string) => void; - isLoading: boolean; -}) => { - const { t } = useTranslation(); - - return ( -
-
- {/*
*/} -
-
-
- -
-
- {String(t("common.event")).toUpperCase()} -
-
- {String(t("common.user")).toUpperCase()} -
-
- {String(t("common.source")).toUpperCase()} -
-
- {String(t("common.time")).toUpperCase()} -
-
-
-
- {data?.map((row, index) => ( - - ))} -
-
- {isLoading && ( -
- )} -
- ); -}; - -export default ActivityTable; diff --git a/frontend/src/hooks/api/index.tsx b/frontend/src/hooks/api/index.tsx index c707fe33f..ea5bb658d 100644 --- a/frontend/src/hooks/api/index.tsx +++ b/frontend/src/hooks/api/index.tsx @@ -15,7 +15,6 @@ export * from "./secretImports"; export * from "./secretRotation"; export * from "./secrets"; export * from "./secretSnapshots"; -export * from "./serviceAccounts"; export * from "./serviceTokens"; export * from "./ssoConfig"; export * from "./subscriptions"; diff --git a/frontend/src/hooks/api/serviceAccounts/index.tsx b/frontend/src/hooks/api/serviceAccounts/index.tsx deleted file mode 100644 index bd4f0bbee..000000000 --- a/frontend/src/hooks/api/serviceAccounts/index.tsx +++ /dev/null @@ -1,10 +0,0 @@ -export { - useCreateServiceAccount, - useCreateServiceAccountProjectLevelPermission, - useDeleteServiceAccount, - useDeleteServiceAccountProjectLevelPermission, - useGetServiceAccountById, - useGetServiceAccountProjectLevelPermissions, - useGetServiceAccounts, - useRenameServiceAccount -} from "./queries"; \ No newline at end of file diff --git a/frontend/src/hooks/api/serviceAccounts/queries.tsx b/frontend/src/hooks/api/serviceAccounts/queries.tsx deleted file mode 100644 index fa89def1c..000000000 --- a/frontend/src/hooks/api/serviceAccounts/queries.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; - -import { apiRequest } from "@app/config/request"; - -import { - CreateServiceAccountDTO, - CreateServiceAccountRes, - CreateServiceAccountWorkspacePermissionDTO, - DeleteServiceAccountWorkspacePermissionDTO, - RenameServiceAccountDTO, - ServiceAccount, - ServiceAccountWorkspacePermission -} from "./types"; - -const serviceAccountKeys = { - getServiceAccountById: (serviceAccountId: string) => [{ serviceAccountId }, "service-account"] as const, - getServiceAccounts: (organizationID: string) => [{ organizationID }, "service-accounts"] as const, - getServiceAccountProjectLevelPermissions: (serviceAccountId: string) => [{ serviceAccountId }, "service-account-project-level-permissions"] as const -} - -const fetchServiceAccounts = async (organizationID: string) => { - const { data } = await apiRequest.get<{ serviceAccounts: ServiceAccount[] }>( - `/api/v2/organizations/${organizationID}/service-accounts` - ); - - return data.serviceAccounts; -} - -const fetchServiceAccountById = async (serviceAccountId: string) => { - const { data } = await apiRequest.get<{ serviceAccount: ServiceAccount }>( - `/api/v2/service-accounts/${serviceAccountId}` - ); - - return data.serviceAccount; -} - -export const useGetServiceAccounts = (organizationID: string) => - useQuery({ - queryKey: serviceAccountKeys.getServiceAccounts(organizationID), - queryFn: () => fetchServiceAccounts(organizationID), - enabled: Boolean(organizationID) - }); - -export const useGetServiceAccountById = (serviceAccountId: string) => { - return useQuery({ - queryKey: serviceAccountKeys.getServiceAccountById(serviceAccountId), - queryFn: () => fetchServiceAccountById(serviceAccountId), - enabled: true - }); -} - -export const useCreateServiceAccount = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async (body) => { - const { data } = await apiRequest.post("/api/v2/service-accounts/", body); - return data; - }, - onSuccess: ({ serviceAccount }) => { - queryClient.invalidateQueries(serviceAccountKeys.getServiceAccounts(serviceAccount.organization)); - } - }); -} - -export const useRenameServiceAccount = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async ({ serviceAccountId, name }) => { - const { data: { serviceAccount } } = await apiRequest.patch(`/api/v2/service-accounts/${serviceAccountId}/name`, { name }); - return serviceAccount; - }, - onSuccess: (serviceAccount) => { - queryClient.invalidateQueries(serviceAccountKeys.getServiceAccountById(serviceAccount._id)); - queryClient.invalidateQueries(serviceAccountKeys.getServiceAccounts(serviceAccount.organization)); - } - }); -} - -export const useDeleteServiceAccount = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async (serviceAccountId) => { - const { data: { serviceAccount } } = await apiRequest.delete(`/api/v2/service-accounts/${serviceAccountId}`); - return serviceAccount; - }, - onSuccess: ({ organization }) => { - queryClient.invalidateQueries(serviceAccountKeys.getServiceAccounts(organization)); - } - }); -} - -const fetchServiceAccountProjectLevelPermissions = async (serviceAccountId: string) => { - const { data: { serviceAccountWorkspacePermissions } } = await apiRequest.get<{ serviceAccountWorkspacePermissions: ServiceAccountWorkspacePermission[] }>( - `/api/v2/service-accounts/${serviceAccountId}/permissions/workspace` - ); - - return serviceAccountWorkspacePermissions; -} - -export const useGetServiceAccountProjectLevelPermissions = (serviceAccountId: string) => { - return useQuery({ - queryKey: serviceAccountKeys.getServiceAccountProjectLevelPermissions(serviceAccountId), - queryFn: () => fetchServiceAccountProjectLevelPermissions(serviceAccountId), - enabled: true - }); -} - -export const useCreateServiceAccountProjectLevelPermission = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async (body) => { - const { data: { serviceAccountWorkspacePermission } } = await apiRequest.post(`/api/v2/service-accounts/${body.serviceAccountId}/permissions/workspace`, body); - return serviceAccountWorkspacePermission; - }, - onSuccess: ({ serviceAccount }) => { - queryClient.invalidateQueries(serviceAccountKeys.getServiceAccountProjectLevelPermissions(serviceAccount)); - } - }); -} - -export const useDeleteServiceAccountProjectLevelPermission = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async ({ serviceAccountId, serviceAccountWorkspacePermissionId }) => { - const { data: { serviceAccountWorkspacePermission} } = await apiRequest.delete(`/api/v2/service-accounts/${serviceAccountId}/permissions/workspace/${serviceAccountWorkspacePermissionId}`); - return serviceAccountWorkspacePermission; - }, - onSuccess: (serviceAccountWorkspacePermission) => { - queryClient.invalidateQueries(serviceAccountKeys.getServiceAccountProjectLevelPermissions(serviceAccountWorkspacePermission.serviceAccount)); - } - }); -} \ No newline at end of file diff --git a/frontend/src/hooks/api/serviceAccounts/types.ts b/frontend/src/hooks/api/serviceAccounts/types.ts deleted file mode 100644 index cf6f8832f..000000000 --- a/frontend/src/hooks/api/serviceAccounts/types.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Workspace } from "../workspace/types"; - -export type ServiceAccount = { - _id: string; - name: string; - organization: string; - user: string; - publicKey: string; - expiresAt: string; -} - -export type CreateServiceAccountDTO = { - name: string; - organizationId: string; - publicKey: string; - expiresIn: number; -} - -export type CreateServiceAccountRes = { - serviceAccount: ServiceAccount; - serviceAccountAccessKey: string; -} - -export type RenameServiceAccountDTO = { - serviceAccountId: string; - name: string; -} - -export type ServiceAccountWorkspacePermission = { - _id: string; - serviceAccount: string; - workspace: Workspace; - environment: string; - read: boolean; - write: boolean; -} - -export type CreateServiceAccountWorkspacePermissionDTO = { - serviceAccountId: string; - workspaceId: string; - environment: string; - read: boolean; - write: boolean; - encryptedKey: string; - nonce: string; -} - -export type DeleteServiceAccountWorkspacePermissionDTO = { - serviceAccountId: string; - serviceAccountWorkspacePermissionId: string; -} \ No newline at end of file diff --git a/frontend/src/pages/project/[id]/logs/index.tsx b/frontend/src/pages/project/[id]/logs/index.tsx deleted file mode 100644 index cc6f79457..000000000 --- a/frontend/src/pages/project/[id]/logs/index.tsx +++ /dev/null @@ -1,204 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import Head from "next/head"; -import { useRouter } from "next/router"; - -import Button from "@app/components/basic/buttons/Button"; -import EventFilter from "@app/components/basic/EventFilter"; -import { UpgradePlanModal } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useSubscription } from "@app/context"; -import ActivitySideBar from "@app/ee/components/ActivitySideBar"; -import { withProjectPermission } from "@app/hoc"; -import { usePopUp } from "@app/hooks/usePopUp"; - -import getProjectLogs from "../../../../ee/api/secrets/GetProjectLogs"; -import ActivityTable from "../../../../ee/components/ActivityTable"; - -interface LogData { - _id: string; - channel: string; - createdAt: string; - ipAddress: string; - user: { - email: string; - }; - serviceAccount?: { - string: string; - }; - serviceTokenData?: { - name: string; - }; - actions: { - _id: string; - name: string; - payload: { - secretVersions: string[]; - }; - }[]; -} - -interface PayloadProps { - _id: string; - name: string; - secretVersions: string[]; -} - -interface LogDataPoint { - _id: string; - channel: string; - createdAt: string; - ipAddress: string; - user: string; - serviceAccount: { - name: string; - }; - serviceTokenData: { - name: string; - }; - payload: PayloadProps[]; -} - -/** - * This is the tab that includes all of the user activity logs - */ -const Activity = withProjectPermission( - () => { - const router = useRouter(); - const [eventChosen, setEventChosen] = useState(""); - const [logsData, setLogsData] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [currentOffset, setCurrentOffset] = useState(0); - const currentLimit = 10; - const [currentSidebarAction, toggleSidebar] = useState(); - const { t } = useTranslation(); - const { subscription } = useSubscription(); - const { popUp, handlePopUpOpen, handlePopUpClose } = usePopUp(["upgradePlan"] as const); - - // this use effect updates the data in case of a new filter being added - useEffect(() => { - setCurrentOffset(0); - const getLogData = async () => { - setIsLoading(true); - const tempLogsData = await getProjectLogs({ - workspaceId: String(router.query.id), - offset: 0, - limit: currentLimit, - userId: "", - actionNames: eventChosen - }); - - setLogsData( - tempLogsData.map((log: LogData) => ({ - _id: log._id, - channel: log.channel, - createdAt: log.createdAt, - ipAddress: log.ipAddress, - user: log?.user?.email, - serviceAccount: log?.serviceAccount, - serviceTokenData: log?.serviceTokenData, - payload: log.actions.map((action) => ({ - _id: action._id, - name: action.name, - secretVersions: action.payload.secretVersions - })) - })) - ); - setIsLoading(false); - }; - getLogData(); - }, [eventChosen]); - - // this use effect adds more data in case 'View More' button is clicked - useEffect(() => { - const getLogData = async () => { - setIsLoading(true); - const tempLogsData = await getProjectLogs({ - workspaceId: String(router.query.id), - offset: currentOffset, - limit: currentLimit, - userId: "", - actionNames: eventChosen - }); - setLogsData( - logsData.concat( - tempLogsData.map((log: LogData) => ({ - _id: log._id, - channel: log.channel, - createdAt: log.createdAt, - ipAddress: log.ipAddress, - user: log?.user?.email, - serviceAccount: log?.serviceAccount, - serviceTokenData: log?.serviceTokenData, - payload: log.actions.map((action) => ({ - _id: action._id, - name: action.name, - secretVersions: action.payload.secretVersions - })) - })) - ) - ); - setIsLoading(false); - }; - getLogData(); - }, [currentLimit, currentOffset]); - - const loadMoreLogs = () => { - if (subscription?.auditLogs === false) { - handlePopUpOpen("upgradePlan"); - } else { - setCurrentOffset(currentOffset + currentLimit); - } - }; - - return ( -
- - Audit Logs - - - - {currentSidebarAction && ( - - )} -
-
-

{t("activity.title")}

-
-

{t("activity.subtitle")}

-
-
- -
- -
-
-
-
- {subscription && ( - handlePopUpClose("upgradePlan")} - text={ - subscription.slug === null - ? "You can see more logs under an Enterprise license" - : "You can see more logs if you switch to Infisical's Business/Professional Plan." - } - /> - )} -
- ); - }, - { action: ProjectPermissionActions.Read, subject: ProjectPermissionSub.AuditLogs } -); - -Object.assign(Activity, { requireAuth: true }); - -export default Activity; diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgServiceAccountsTable/OrgServiceAccountsTable.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgServiceAccountsTable/OrgServiceAccountsTable.tsx deleted file mode 100644 index 4d43d9299..000000000 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgServiceAccountsTable/OrgServiceAccountsTable.tsx +++ /dev/null @@ -1,389 +0,0 @@ -import { useEffect, useMemo, useState } from "react"; -import { useRouter } from "next/router"; -import { - faCheck, - faCopy, - faMagnifyingGlass, - faPencil, - faPlus, - faServer, - faTrash -} from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -// import { yupResolver } from "@hookform/resolvers/yup"; -// import * as yup from "yup"; -// import { generateKeyPair } from "@app/components/utilities/cryptography/crypto"; -import { - Button, - DeleteActionModal, - EmptyState, - // FormControl, - IconButton, - Input, - Modal, - ModalContent, - // Select, - // SelectItem, - Table, - TableContainer, - TableSkeleton, - TBody, - Td, - Th, - THead, - Tr -} from "@app/components/v2"; -import { - OrgPermissionActions, - OrgPermissionSubjects, - useOrganization, - useWorkspace -} from "@app/context"; -import { withPermission } from "@app/hoc"; -import { usePopUp, useToggle } from "@app/hooks"; -import { - // useCreateServiceAccount, - useDeleteServiceAccount, - useGetServiceAccounts -} from "@app/hooks/api"; - -import // Controller, -// useForm -"react-hook-form"; - -// const serviceAccountExpiration = [ -// { label: "1 Day", value: 86400 }, -// { label: "7 Days", value: 604800 }, -// { label: "1 Month", value: 2592000 }, -// { label: "6 months", value: 15552000 }, -// { label: "12 months", value: 31104000 }, -// { label: "Never", value: -1 } -// ]; - -// const addServiceAccountFormSchema = yup.object({ -// name: yup.string().required().label("Name").trim(), -// expiresIn: yup.string().required().label("Service Account Expiration") -// }); - -// type TAddServiceAccountForm = yup.InferType; - -export const OrgServiceAccountsTable = withPermission( - () => { - const router = useRouter(); - const { currentOrg } = useOrganization(); - const { currentWorkspace } = useWorkspace(); - - const orgId = currentOrg?._id || ""; - const [step, setStep] = useState(0); - const [isAccessKeyCopied, setIsAccessKeyCopied] = useToggle(false); - const [isPublicKeyCopied, setIsPublicKeyCopied] = useToggle(false); - const [isPrivateKeyCopied, setIsPrivateKeyCopied] = useToggle(false); - const [accessKey] = useState(""); - const [publicKey] = useState(""); - const [privateKey] = useState(""); - const [searchServiceAccountFilter, setSearchServiceAccountFilter] = useState(""); - const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([ - "addServiceAccount", - "removeServiceAccount" - ] as const); - - const { data: serviceAccounts = [], isLoading: isServiceAccountsLoading } = - useGetServiceAccounts(orgId); - - // const createServiceAccount = useCreateServiceAccount(); - const removeServiceAccount = useDeleteServiceAccount(); - - useEffect(() => { - let timer: NodeJS.Timeout; - if (isAccessKeyCopied) { - timer = setTimeout(() => setIsAccessKeyCopied.off(), 2000); - } - - if (isPublicKeyCopied) { - timer = setTimeout(() => setIsPublicKeyCopied.off(), 2000); - } - - if (isPrivateKeyCopied) { - timer = setTimeout(() => setIsPrivateKeyCopied.off(), 2000); - } - - return () => clearTimeout(timer); - }, [isAccessKeyCopied, isPublicKeyCopied, isPrivateKeyCopied]); - - // const { - // control, - // handleSubmit, - // reset, - // formState: { isSubmitting } - // } = useForm({ resolver: yupResolver(addServiceAccountFormSchema) }); - - // const onAddServiceAccount = async ({ name, expiresIn }: TAddServiceAccountForm) => { - // if (!currentOrg?._id) return; - - // const keyPair = generateKeyPair(); - // setPublicKey(keyPair.publicKey); - // setPrivateKey(keyPair.privateKey); - - // const serviceAccountDetails = await createServiceAccount.mutateAsync({ - // name, - // organizationId: currentOrg?._id, - // publicKey: keyPair.publicKey, - // expiresIn: Number(expiresIn) - // }); - - // setAccessKey(serviceAccountDetails.serviceAccountAccessKey); - - // setStep(1); - // reset(); - // } - - const onRemoveServiceAccount = async () => { - const serviceAccountId = (popUp?.removeServiceAccount?.data as { _id: string })?._id; - await removeServiceAccount.mutateAsync(serviceAccountId); - handlePopUpClose("removeServiceAccount"); - }; - - const filteredServiceAccounts = useMemo( - () => - serviceAccounts.filter(({ name }) => - name.toLowerCase().includes(searchServiceAccountFilter) - ), - [serviceAccounts, searchServiceAccountFilter] - ); - - const renderStep = (stepToRender: number) => { - switch (stepToRender) { - case 0: - return ( -
- We are currently revising the service account mechanism. In the meantime, please use - service tokens or API key to fetch secrets via API request. -
- //
- // ( - // - // - // - // )} - // /> - // { - // return ( - // - // - // - // ); - // }} - // /> - //
- // - // - //
- // - ); - case 1: - return ( - <> -

Access Key

-
-

{accessKey}

- { - navigator.clipboard.writeText(accessKey); - setIsAccessKeyCopied.on(); - }} - > - - - Copy - - -
-

Public Key

-
-

{publicKey}

- { - navigator.clipboard.writeText(publicKey); - setIsPublicKeyCopied.on(); - }} - > - - - Copy - - -
-

Private Key

-
-

{privateKey}

- { - navigator.clipboard.writeText(privateKey); - setIsPrivateKeyCopied.on(); - }} - > - - - Copy - - -
- - ); - default: - return
; - } - }; - - return ( -
-
-

Service Accounts

- -
- setSearchServiceAccountFilter(e.target.value)} - leftIcon={} - placeholder="Search service accounts..." - /> - - - - - - - - {isServiceAccountsLoading && ( - - )} - {!isServiceAccountsLoading && - filteredServiceAccounts.map(({ name, expiresAt, _id: serviceAccountId }) => { - return ( - - - - - - ); - })} - -
NameValid Until -
{name}{new Date(expiresAt).toUTCString()} -
- { - if (currentWorkspace?._id) { - router.push( - `/settings/org/${currentWorkspace._id}/service-accounts/${serviceAccountId}` - ); - } - }} - className="mr-2" - > - - - - handlePopUpOpen("removeServiceAccount", { _id: serviceAccountId }) - } - > - - -
-
- {!isServiceAccountsLoading && filteredServiceAccounts?.length === 0 && ( - - )} -
- { - handlePopUpToggle("addServiceAccount", isOpen); - // reset(); - }} - > - - {renderStep(step)} - - - handlePopUpToggle("removeServiceAccount", isOpen)} - onDeleteApproved={onRemoveServiceAccount} - /> -
- ); - }, - { - action: OrgPermissionActions.Read, - subject: OrgPermissionSubjects.Settings, - containerClassName: "mb-4" - } -); diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgServiceAccountsTable/index.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgServiceAccountsTable/index.tsx deleted file mode 100644 index 8e900f6fa..000000000 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgServiceAccountsTable/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { OrgServiceAccountsTable } from "./OrgServiceAccountsTable"; \ No newline at end of file