diff --git a/README.md b/README.md index 89a44050f..65eaed395 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ Not sure where to get started? You can: - [Slack](https://join.slack.com/t/infisical-users/shared_invite/zt-1wehzfnzn-1aMo5JcGENJiNAC2SD8Jlg) for discussion with the community and Infisical team. - [GitHub](https://github.com/Infisical/infisical) for code, issues, and pull requests - [Twitter](https://twitter.com/infisical) for fast news -- [YouTube](https://www.youtube.com/@infisical5306) for videos on secret management +- [YouTube](https://www.youtube.com/@infisical_od) for videos on secret management - [Blog](https://infisical.com/blog) for secret management insights, articles, tutorials, and updates - [Roadmap](https://www.notion.so/infisical/be2d2585a6694e40889b03aef96ea36b?v=5b19a8127d1a4060b54769567a8785fa) for planned features diff --git a/backend/package-lock.json b/backend/package-lock.json index dd4e7dc6c..524a6017b 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -17,13 +17,11 @@ "@types/crypto-js": "^4.1.1", "@types/libsodium-wrappers": "^0.7.10", "argon2": "^0.30.3", - "await-to-js": "^3.0.0", "aws-sdk": "^2.1364.0", "axios": "^1.3.5", "axios-retry": "^3.4.0", "bcrypt": "^5.1.0", "bigint-conversion": "^2.4.0", - "builder-pattern": "^2.2.0", "cookie-parser": "^1.4.6", "cors": "^2.8.5", "crypto-js": "^4.1.1", @@ -3787,14 +3785,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/await-to-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz", - "integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/aws-sdk": { "version": "2.1386.0", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1386.0.tgz", @@ -4217,11 +4207,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/builder-pattern": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/builder-pattern/-/builder-pattern-2.2.0.tgz", - "integrity": "sha512-cES3qdeBzA4QyJi7rV/l/kAhIFX6AKo3vK66ZPXLNpjcQWCS8sjLKscly8imlfW2YPTo/hquMRMnaWpZ80Kj+g==" - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -15393,11 +15378,6 @@ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" }, - "await-to-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz", - "integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==" - }, "aws-sdk": { "version": "2.1386.0", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1386.0.tgz", @@ -15724,11 +15704,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "builder-pattern": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/builder-pattern/-/builder-pattern-2.2.0.tgz", - "integrity": "sha512-cES3qdeBzA4QyJi7rV/l/kAhIFX6AKo3vK66ZPXLNpjcQWCS8sjLKscly8imlfW2YPTo/hquMRMnaWpZ80Kj+g==" - }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", diff --git a/backend/package.json b/backend/package.json index 84750e6b9..448ccfac2 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,13 +8,11 @@ "@types/crypto-js": "^4.1.1", "@types/libsodium-wrappers": "^0.7.10", "argon2": "^0.30.3", - "await-to-js": "^3.0.0", "aws-sdk": "^2.1364.0", "axios": "^1.3.5", "axios-retry": "^3.4.0", "bcrypt": "^5.1.0", "bigint-conversion": "^2.4.0", - "builder-pattern": "^2.2.0", "cookie-parser": "^1.4.6", "cors": "^2.8.5", "crypto-js": "^4.1.1", diff --git a/backend/src/controllers/v2/secretController.ts b/backend/src/controllers/v2/secretController.ts index 1b6038f0e..c24243f3b 100644 --- a/backend/src/controllers/v2/secretController.ts +++ b/backend/src/controllers/v2/secretController.ts @@ -1,4 +1,3 @@ -import to from "await-to-js"; import { Request, Response } from "express"; import mongoose, { Types } from "mongoose"; import Secret, { ISecret } from "../../models/secret"; @@ -56,10 +55,7 @@ export const createSecret = async (req: Request, res: Response) => { keyEncoding: ENCODING_SCHEME_UTF8 }; - const [error, secret] = await to(Secret.create(sanitizedSecret).then()); - if (error instanceof ValidationError) { - throw RouteValidationError({ message: error.message, stack: error.stack }); - } + const secret = await new Secret(sanitizedSecret).save(); if (postHogClient) { postHogClient.capture({ @@ -81,7 +77,7 @@ export const createSecret = async (req: Request, res: Response) => { }; /** - * Create many secrets for workspace wiht id [workspaceId] and environment [environment] + * Create many secrets for workspace with id [workspaceId] and environment [environment] * @param req * @param res */ @@ -116,20 +112,7 @@ export const createSecrets = async (req: Request, res: Response) => { sanitizedSecretesToCreate.push(safeUpdateFields); }); - const [bulkCreateError, secrets] = await to(Secret.insertMany(sanitizedSecretesToCreate).then()); - if (bulkCreateError) { - if (bulkCreateError instanceof ValidationError) { - throw RouteValidationError({ - message: bulkCreateError.message, - stack: bulkCreateError.stack - }); - } - - throw InternalServerError({ - message: "Unable to process your batch create request. Please try again", - stack: bulkCreateError.stack - }); - } + const secrets = await Secret.insertMany(sanitizedSecretesToCreate); if (postHogClient) { postHogClient.capture({ @@ -160,14 +143,7 @@ export const deleteSecrets = async (req: Request, res: Response) => { const { workspaceId, environmentName } = req.params; const secretIdsToDelete: string[] = req.body.secretIds; - const [secretIdsUserCanDeleteError, secretIdsUserCanDelete] = await to( - Secret.find({ workspace: workspaceId, environment: environmentName }, { _id: 1 }).then() - ); - if (secretIdsUserCanDeleteError) { - throw InternalServerError({ - message: `Unable to fetch secrets you own: [error=${secretIdsUserCanDeleteError.message}]` - }); - } + const secretIdsUserCanDelete = await Secret.find({ workspace: workspaceId, environment: environmentName }, { _id: 1 }); const secretsUserCanDeleteSet: Set = new Set( secretIdsUserCanDelete.map((objectId) => objectId._id.toString()) @@ -189,16 +165,7 @@ export const deleteSecrets = async (req: Request, res: Response) => { } }); - const [bulkDeleteError] = await to(Secret.bulkWrite(deleteOperationsToPerform).then()); - if (bulkDeleteError) { - if (bulkDeleteError instanceof ValidationError) { - throw RouteValidationError({ - message: "Unable to apply modifications, please try again", - stack: bulkDeleteError.stack - }); - } - throw InternalServerError(); - } + await Secret.bulkWrite(deleteOperationsToPerform); if (postHogClient) { postHogClient.capture({ @@ -255,12 +222,7 @@ export const updateSecrets = async (req: Request, res: Response) => { const postHogClient = await TelemetryService.getPostHogClient(); const { workspaceId, environmentName } = req.params; const secretsModificationsRequested: ModifySecretRequestBody[] = req.body.secrets; - const [secretIdsUserCanModifyError, secretIdsUserCanModify] = await to( - Secret.find({ workspace: workspaceId, environment: environmentName }, { _id: 1 }).then() - ); - if (secretIdsUserCanModifyError) { - throw InternalServerError({ message: "Unable to fetch secrets you own" }); - } + const secretIdsUserCanModify = await Secret.find({ workspace: workspaceId, environment: environmentName }, { _id: 1 }); const secretsUserCanModifySet: Set = new Set( secretIdsUserCanModify.map((objectId) => objectId._id.toString()) @@ -298,19 +260,7 @@ export const updateSecrets = async (req: Request, res: Response) => { } }); - const [bulkModificationInfoError, bulkModificationInfo] = await to( - Secret.bulkWrite(updateOperationsToPerform).then() - ); - if (bulkModificationInfoError) { - if (bulkModificationInfoError instanceof ValidationError) { - throw RouteValidationError({ - message: "Unable to apply modifications, please try again", - stack: bulkModificationInfoError.stack - }); - } - - throw InternalServerError(); - } + await Secret.bulkWrite(updateOperationsToPerform); if (postHogClient) { postHogClient.capture({ @@ -340,12 +290,7 @@ export const updateSecret = async (req: Request, res: Response) => { const { workspaceId, environmentName } = req.params; const secretModificationsRequested: ModifySecretRequestBody = req.body.secret; - const [secretIdUserCanModifyError, secretIdUserCanModify] = await to( - Secret.findOne({ workspace: workspaceId, environment: environmentName }, { _id: 1 }).then() - ); - if (secretIdUserCanModifyError && !secretIdUserCanModify) { - throw BadRequestError(); - } + const secretIdUserCanModify = await Secret.findOne({ workspace: workspaceId, environment: environmentName }, { _id: 1 }); const sanitizedSecret: SanitizedSecretModify = { secretKeyCiphertext: secretModificationsRequested.secretKeyCiphertext, @@ -362,18 +307,20 @@ export const updateSecret = async (req: Request, res: Response) => { secretCommentHash: secretModificationsRequested.secretCommentHash }; - const [error, singleModificationUpdate] = await to( - Secret.updateOne( - { _id: secretModificationsRequested._id, workspace: workspaceId }, - { $inc: { version: 1 }, $set: sanitizedSecret } - ).then() - ); - if (error instanceof ValidationError) { - throw RouteValidationError({ - message: "Unable to apply modifications, please try again", - stack: error.stack - }); - } + const singleModificationUpdate = await Secret.updateOne( + { _id: secretModificationsRequested._id, workspace: workspaceId }, + { $inc: { version: 1 }, $set: sanitizedSecret } + ) + .catch((error) => { + if (error instanceof ValidationError) { + throw RouteValidationError({ + message: "Unable to apply modifications, please try again", + stack: error.stack + }); + } + + throw error; + }); if (postHogClient) { postHogClient.capture({ @@ -419,21 +366,18 @@ export const getSecrets = async (req: Request, res: Response) => { userEmail = user.email; } - const [err, secrets] = await to( - Secret.find({ - workspace: workspaceId, - environment, - $or: [{ user: userId }, { user: { $exists: false } }], - type: { $in: [SECRET_SHARED, SECRET_PERSONAL] } - }).then() - ); - - if (err) { + const secrets = await Secret.find({ + workspace: workspaceId, + environment, + $or: [{ user: userId }, { user: { $exists: false } }], + type: { $in: [SECRET_SHARED, SECRET_PERSONAL] } + }) + .catch((err) => { throw RouteValidationError({ message: "Failed to get secrets, please try again", stack: err.stack }); - } + }) if (postHogClient) { postHogClient.capture({ diff --git a/backend/src/controllers/v2/tagController.ts b/backend/src/controllers/v2/tagController.ts index 926df0ca5..f714e4348 100644 --- a/backend/src/controllers/v2/tagController.ts +++ b/backend/src/controllers/v2/tagController.ts @@ -1,32 +1,23 @@ import { Request, Response } from "express"; import { Types } from "mongoose"; import { Membership, Secret } from "../../models"; -import Tag, { ITag } from "../../models/tag"; -import { Builder } from "builder-pattern"; -import to from "await-to-js"; +import Tag from "../../models/tag"; import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors"; import { MongoError } from "mongodb"; export const createWorkspaceTag = async (req: Request, res: Response) => { const { workspaceId } = req.params; const { name, slug } = req.body; - const sanitizedTagToCreate = Builder() - .name(name) - .workspace(new Types.ObjectId(workspaceId)) - .slug(slug) - .user(new Types.ObjectId(req.user._id)) - .build(); - - const [err, createdTag] = await to(Tag.create(sanitizedTagToCreate)); - - if (err) { - if ((err as MongoError).code === 11000) { - throw BadRequestError({ message: "Tags must be unique in a workspace" }); - } - - throw err; - } - + + const tagToCreate = { + name, + workspace: new Types.ObjectId(workspaceId), + slug, + user: new Types.ObjectId(req.user._id), + }; + + const createdTag = await new Tag(tagToCreate); + res.json(createdTag); }; diff --git a/backend/src/ee/controllers/v1/membershipController.ts b/backend/src/ee/controllers/v1/membershipController.ts index 1a03d36d0..f7bebfdc5 100644 --- a/backend/src/ee/controllers/v1/membershipController.ts +++ b/backend/src/ee/controllers/v1/membershipController.ts @@ -4,7 +4,6 @@ import { IMembershipPermission } from "../../../models/membership"; import { BadRequestError, UnauthorizedRequestError } from "../../../utils/errors"; import { ADMIN, MEMBER } from "../../../variables/organization"; import { PERMISSION_READ_SECRETS, PERMISSION_WRITE_SECRETS } from "../../../variables"; -import { Builder } from "builder-pattern" import _ from "lodash"; export const denyMembershipPermissions = async (req: Request, res: Response) => { @@ -15,10 +14,10 @@ export const denyMembershipPermissions = async (req: Request, res: Response) => throw BadRequestError({ message: "One or more required fields are missing from the request or have incorrect type" }) } - return Builder() - .environmentSlug(permission.environmentSlug) - .ability(permission.ability) - .build(); + return { + environmentSlug: permission.environmentSlug, + ability: permission.ability + } }) const sanitizedMembershipPermissionsUnique = _.uniqWith(sanitizedMembershipPermissions, _.isEqual) diff --git a/frontend/Dockerfile b/frontend/Dockerfile index b33d63b4f..1f4a5ce4e 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,5 +1,6 @@ ARG POSTHOG_HOST=https://app.posthog.com ARG POSTHOG_API_KEY=posthog-api-key +ARG INTERCOM_ID=intercom-id FROM node:16-alpine AS deps # Install dependencies only when needed. Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. diff --git a/frontend/src/components/utilities/intercom/intercom.ts b/frontend/src/components/utilities/intercom/intercom.ts index 94079bc2b..cea69edd7 100644 --- a/frontend/src/components/utilities/intercom/intercom.ts +++ b/frontend/src/components/utilities/intercom/intercom.ts @@ -54,6 +54,7 @@ export const load = () => { // Initializes Intercom export const boot = (options = {}) => { + console.log("boot", { app_id: APP_ID, ...options }) window && window.Intercom && window.Intercom("boot", { app_id: APP_ID, ...options }); diff --git a/frontend/src/components/utilities/intercom/intercomProvider.ts b/frontend/src/components/utilities/intercom/intercomProvider.ts index e7944a7b1..455deb299 100644 --- a/frontend/src/components/utilities/intercom/intercomProvider.ts +++ b/frontend/src/components/utilities/intercom/intercomProvider.ts @@ -1,6 +1,8 @@ import { useEffect } from "react"; import { useRouter } from "next/router"; +import { useUser } from "@app/context"; + import { boot as bootIntercom, load as loadIntercom, @@ -9,11 +11,12 @@ import { // eslint-disable-next-line @typescript-eslint/no-unused-vars export const IntercomProvider = ({ children }: { children: any }) => { + const { user } = useUser(); const router = useRouter(); if (typeof window !== "undefined") { loadIntercom(); - bootIntercom(); + bootIntercom({name: `${user?.firstName || ""} ${user?.lastName || ""}`, email: user?.email || "", created_at: Math.floor(((new Date(user?.createdAt))?.getTime() || 0) / 1000)}); } useEffect(() => { diff --git a/frontend/src/pages/home/[id].tsx b/frontend/src/pages/home/[id].tsx index 5e1921ab6..10c6ec125 100644 --- a/frontend/src/pages/home/[id].tsx +++ b/frontend/src/pages/home/[id].tsx @@ -168,7 +168,7 @@ export default function Home() { icon: faHandPeace, time: "3 min", userAction: "intro_cta_clicked", - link: "https://www.youtube.com/watch?v=3F7FNYX94zA" + link: "https://www.youtube.com/watch?v=PK23097-25I" })} {learningItem({ text: "Add your secrets",