Fix merge conflicts

This commit is contained in:
Tuan Dang
2023-06-07 12:58:24 +01:00
54 changed files with 4011 additions and 4732 deletions
+1 -36
View File
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
@@ -45,7 +44,6 @@ declare module 'jsonwebtoken' {
* @returns * @returns
*/ */
export const login1 = async (req: Request, res: Response) => { export const login1 = async (req: Request, res: Response) => {
try {
const { const {
email, email,
clientPublicKey clientPublicKey
@@ -79,13 +77,6 @@ export const login1 = async (req: Request, res: Response) => {
}); });
} }
); );
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to start authentication process'
});
}
}; };
/** /**
@@ -96,11 +87,10 @@ export const login1 = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const login2 = async (req: Request, res: Response) => { export const login2 = async (req: Request, res: Response) => {
try {
const { email, clientProof } = req.body; const { email, clientProof } = req.body;
const user = await User.findOne({ const user = await User.findOne({
email email
}).select('+salt +verifier +publicKey +encryptedPrivateKey +iv +tag +devices'); }).select('+salt +verifier +publicKey +encryptedPrivateKey +iv +tag');
if (!user) throw new Error('Failed to find user'); if (!user) throw new Error('Failed to find user');
@@ -171,13 +161,6 @@ export const login2 = async (req: Request, res: Response) => {
}); });
} }
); );
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to authenticate. Try again?'
});
}
}; };
/** /**
@@ -187,8 +170,6 @@ export const login2 = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const logout = async (req: Request, res: Response) => { export const logout = async (req: Request, res: Response) => {
try {
if (req.authData.authMode === AUTH_MODE_JWT && req.authData.authPayload instanceof User && req.authData.tokenVersionId) { if (req.authData.authMode === AUTH_MODE_JWT && req.authData.authPayload instanceof User && req.authData.tokenVersionId) {
await clearTokens(req.authData.tokenVersionId) await clearTokens(req.authData.tokenVersionId)
} }
@@ -213,14 +194,6 @@ export const logout = async (req: Request, res: Response) => {
ipAddress: req.realIP ipAddress: req.realIP
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to logout'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully logged out.' message: 'Successfully logged out.'
}); });
@@ -269,7 +242,6 @@ export const checkAuth = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const getNewToken = async (req: Request, res: Response) => { export const getNewToken = async (req: Request, res: Response) => {
try {
const refreshToken = req.cookies.jid; const refreshToken = req.cookies.jid;
if (!refreshToken) { if (!refreshToken) {
@@ -311,13 +283,6 @@ export const getNewToken = async (req: Request, res: Response) => {
return res.status(200).send({ return res.status(200).send({
token token
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
message: 'Invalid request'
});
}
}; };
export const handleAuthProviderCallback = (req: Request, res: Response) => { export const handleAuthProviderCallback = (req: Request, res: Response) => {
+2 -22
View File
@@ -1,6 +1,5 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import * as Sentry from '@sentry/node';
import { Bot, BotKey } from '../../models'; import { Bot, BotKey } from '../../models';
import { createBot } from '../../helpers/bot'; import { createBot } from '../../helpers/bot';
@@ -17,11 +16,9 @@ interface BotKey {
* @returns * @returns
*/ */
export const getBotByWorkspaceId = async (req: Request, res: Response) => { export const getBotByWorkspaceId = async (req: Request, res: Response) => {
let bot;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
bot = await Bot.findOne({ let bot = await Bot.findOne({
workspace: workspaceId workspace: workspaceId
}); });
@@ -33,13 +30,6 @@ export const getBotByWorkspaceId = async (req: Request, res: Response) => {
workspaceId: new Types.ObjectId(workspaceId) workspaceId: new Types.ObjectId(workspaceId)
}); });
} }
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get bot for workspace'
});
}
return res.status(200).send({ return res.status(200).send({
bot bot
@@ -53,8 +43,6 @@ export const getBotByWorkspaceId = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const setBotActiveState = async (req: Request, res: Response) => { export const setBotActiveState = async (req: Request, res: Response) => {
let bot;
try {
const { isActive, botKey }: { isActive: boolean, botKey: BotKey } = req.body; const { isActive, botKey }: { isActive: boolean, botKey: BotKey } = req.body;
if (isActive) { if (isActive) {
@@ -84,7 +72,7 @@ export const setBotActiveState = async (req: Request, res: Response) => {
}); });
} }
bot = await Bot.findOneAndUpdate({ let bot = await Bot.findOneAndUpdate({
_id: req.bot._id _id: req.bot._id
}, { }, {
isActive isActive
@@ -94,14 +82,6 @@ export const setBotActiveState = async (req: Request, res: Response) => {
if (!bot) throw new Error('Failed to update bot active state'); if (!bot) throw new Error('Failed to update bot active state');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to update bot active state'
});
}
return res.status(200).send({ return res.status(200).send({
bot bot
}); });
@@ -1,6 +1,5 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import * as Sentry from '@sentry/node';
import { import {
IntegrationAuth, IntegrationAuth,
Bot Bot
@@ -22,21 +21,12 @@ import { standardRequest } from '../../config/request';
* Return integration authorization with id [integrationAuthId] * Return integration authorization with id [integrationAuthId]
*/ */
export const getIntegrationAuth = async (req: Request, res: Response) => { export const getIntegrationAuth = async (req: Request, res: Response) => {
let integrationAuth;
try {
const { integrationAuthId } = req.params; const { integrationAuthId } = req.params;
integrationAuth = await IntegrationAuth.findById(integrationAuthId); const integrationAuth = await IntegrationAuth.findById(integrationAuthId);
if (!integrationAuth) return res.status(400).send({ if (!integrationAuth) return res.status(400).send({
message: 'Failed to find integration authorization' message: 'Failed to find integration authorization'
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get integration authorization'
});
}
return res.status(200).send({ return res.status(200).send({
integrationAuth integrationAuth
@@ -61,7 +51,6 @@ export const oAuthExchange = async (
req: Request, req: Request,
res: Response res: Response
) => { ) => {
try {
const { workspaceId, code, integration } = req.body; const { workspaceId, code, integration } = req.body;
if (!INTEGRATION_SET.has(integration)) if (!INTEGRATION_SET.has(integration))
throw new Error('Failed to validate integration'); throw new Error('Failed to validate integration');
@@ -81,13 +70,6 @@ export const oAuthExchange = async (
return res.status(200).send({ return res.status(200).send({
integrationAuth integrationAuth
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get OAuth2 code-token exchange'
});
}
}; };
/** /**
@@ -104,7 +86,6 @@ export const saveIntegrationAccessToken = async (
// TODO: check if access token is valid for each integration // TODO: check if access token is valid for each integration
let integrationAuth; let integrationAuth;
try {
const { const {
workspaceId, workspaceId,
accessId, accessId,
@@ -146,13 +127,6 @@ export const saveIntegrationAccessToken = async (
}); });
if (!integrationAuth) throw new Error('Failed to save integration access token'); if (!integrationAuth) throw new Error('Failed to save integration access token');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to save access token for integration'
});
}
return res.status(200).send({ return res.status(200).send({
integrationAuth integrationAuth
@@ -166,22 +140,13 @@ export const saveIntegrationAccessToken = async (
* @returns * @returns
*/ */
export const getIntegrationAuthApps = async (req: Request, res: Response) => { export const getIntegrationAuthApps = async (req: Request, res: Response) => {
let apps;
try {
const teamId = req.query.teamId as string; const teamId = req.query.teamId as string;
apps = await getApps({ const apps = await getApps({
integrationAuth: req.integrationAuth, integrationAuth: req.integrationAuth,
accessToken: req.accessToken, accessToken: req.accessToken,
...teamId && { teamId } ...teamId && { teamId }
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get integration authorization applications",
});
}
return res.status(200).send({ return res.status(200).send({
apps apps
@@ -402,19 +367,10 @@ export const getIntegrationAuthRailwayServices = async (req: Request, res: Respo
* @returns * @returns
*/ */
export const deleteIntegrationAuth = async (req: Request, res: Response) => { export const deleteIntegrationAuth = async (req: Request, res: Response) => {
let integrationAuth; const integrationAuth = await revokeAccess({
try {
integrationAuth = await revokeAccess({
integrationAuth: req.integrationAuth, integrationAuth: req.integrationAuth,
accessToken: req.accessToken, accessToken: req.accessToken,
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to delete integration authorization",
});
}
return res.status(200).send({ return res.status(200).send({
integrationAuth, integrationAuth,
@@ -1,6 +1,5 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import * as Sentry from '@sentry/node';
import { import {
Integration Integration
} from '../../models'; } from '../../models';
@@ -14,9 +13,6 @@ import { eventPushSecrets } from '../../events';
* @returns * @returns
*/ */
export const createIntegration = async (req: Request, res: Response) => { export const createIntegration = async (req: Request, res: Response) => {
let integration;
try {
const { const {
integrationAuthId, integrationAuthId,
app, app,
@@ -35,7 +31,7 @@ export const createIntegration = async (req: Request, res: Response) => {
// TODO: validate [sourceEnvironment] and [targetEnvironment] // TODO: validate [sourceEnvironment] and [targetEnvironment]
// initialize new integration after saving integration access token // initialize new integration after saving integration access token
integration = await new Integration({ const integration = await new Integration({
workspace: req.integrationAuth.workspace._id, workspace: req.integrationAuth.workspace._id,
environment: sourceEnvironment, environment: sourceEnvironment,
isActive, isActive,
@@ -61,15 +57,6 @@ export const createIntegration = async (req: Request, res: Response) => {
}) })
}); });
} }
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to create integration'
});
}
return res.status(200).send({ return res.status(200).send({
integration, integration,
}); });
@@ -82,12 +69,10 @@ export const createIntegration = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const updateIntegration = async (req: Request, res: Response) => { export const updateIntegration = async (req: Request, res: Response) => {
let integration;
// TODO: add integration-specific validation to ensure that each // TODO: add integration-specific validation to ensure that each
// integration has the correct fields populated in [Integration] // integration has the correct fields populated in [Integration]
try {
const { const {
environment, environment,
isActive, isActive,
@@ -97,7 +82,7 @@ export const updateIntegration = async (req: Request, res: Response) => {
owner, // github-specific integration param owner, // github-specific integration param
} = req.body; } = req.body;
integration = await Integration.findOneAndUpdate( const integration = await Integration.findOneAndUpdate(
{ {
_id: req.integration._id, _id: req.integration._id,
}, },
@@ -123,13 +108,6 @@ export const updateIntegration = async (req: Request, res: Response) => {
}), }),
}); });
} }
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to update integration",
});
}
return res.status(200).send({ return res.status(200).send({
integration, integration,
@@ -144,22 +122,13 @@ export const updateIntegration = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const deleteIntegration = async (req: Request, res: Response) => { export const deleteIntegration = async (req: Request, res: Response) => {
let integration;
try {
const { integrationId } = req.params; const { integrationId } = req.params;
integration = await Integration.findOneAndDelete({ const integration = await Integration.findOneAndDelete({
_id: integrationId, _id: integrationId,
}); });
if (!integration) throw new Error("Failed to find integration"); if (!integration) throw new Error("Failed to find integration");
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to delete integration",
});
}
return res.status(200).send({ return res.status(200).send({
integration, integration,
+1 -19
View File
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { Key } from '../../models'; import { Key } from '../../models';
import { findMembership } from '../../helpers/membership'; import { findMembership } from '../../helpers/membership';
@@ -11,7 +10,6 @@ import { findMembership } from '../../helpers/membership';
* @returns * @returns
*/ */
export const uploadKey = async (req: Request, res: Response) => { export const uploadKey = async (req: Request, res: Response) => {
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
const { key } = req.body; const { key } = req.body;
@@ -32,13 +30,6 @@ export const uploadKey = async (req: Request, res: Response) => {
receiver: key.userId, receiver: key.userId,
workspace: workspaceId workspace: workspaceId
}).save(); }).save();
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to upload key to workspace'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully uploaded key to workspace' message: 'Successfully uploaded key to workspace'
@@ -52,25 +43,16 @@ export const uploadKey = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const getLatestKey = async (req: Request, res: Response) => { export const getLatestKey = async (req: Request, res: Response) => {
let latestKey;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
// get latest key // get latest key
latestKey = await Key.find({ const latestKey = await Key.find({
workspace: workspaceId, workspace: workspaceId,
receiver: req.user._id receiver: req.user._id
}) })
.sort({ createdAt: -1 }) .sort({ createdAt: -1 })
.limit(1) .limit(1)
.populate('sender', '+publicKey'); .populate('sender', '+publicKey');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get latest key'
});
}
const resObj: any = {}; const resObj: any = {};
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { Membership, MembershipOrg, User, Key } from '../../models'; import { Membership, MembershipOrg, User, Key } from '../../models';
import { import {
@@ -16,9 +15,7 @@ import { getSiteURL } from '../../config';
* @returns * @returns
*/ */
export const validateMembership = async (req: Request, res: Response) => { export const validateMembership = async (req: Request, res: Response) => {
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
// validate membership // validate membership
const membership = await findMembership({ const membership = await findMembership({
user: req.user._id, user: req.user._id,
@@ -28,13 +25,6 @@ export const validateMembership = async (req: Request, res: Response) => {
if (!membership) { if (!membership) {
throw new Error('Failed to validate membership'); throw new Error('Failed to validate membership');
} }
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed workspace connection check'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Workspace membership confirmed' message: 'Workspace membership confirmed'
@@ -48,8 +38,6 @@ export const validateMembership = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const deleteMembership = async (req: Request, res: Response) => { export const deleteMembership = async (req: Request, res: Response) => {
let deletedMembership;
try {
const { membershipId } = req.params; const { membershipId } = req.params;
// check if membership to delete exists // check if membership to delete exists
@@ -80,16 +68,9 @@ export const deleteMembership = async (req: Request, res: Response) => {
} }
// delete workspace membership // delete workspace membership
deletedMembership = await deleteMember({ const deletedMembership = await deleteMember({
membershipId: membershipToDelete._id.toString() membershipId: membershipToDelete._id.toString()
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to delete membership'
});
}
return res.status(200).send({ return res.status(200).send({
deletedMembership deletedMembership
@@ -103,8 +84,6 @@ export const deleteMembership = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const changeMembershipRole = async (req: Request, res: Response) => { export const changeMembershipRole = async (req: Request, res: Response) => {
let membershipToChangeRole;
try {
const { membershipId } = req.params; const { membershipId } = req.params;
const { role } = req.body; const { role } = req.body;
@@ -113,7 +92,7 @@ export const changeMembershipRole = async (req: Request, res: Response) => {
} }
// validate target membership // validate target membership
membershipToChangeRole = await findMembership({ const membershipToChangeRole = await findMembership({
_id: membershipId _id: membershipId
}); });
@@ -139,13 +118,6 @@ export const changeMembershipRole = async (req: Request, res: Response) => {
membershipToChangeRole.role = role; membershipToChangeRole.role = role;
await membershipToChangeRole.save(); await membershipToChangeRole.save();
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to change membership role'
});
}
return res.status(200).send({ return res.status(200).send({
membership: membershipToChangeRole membership: membershipToChangeRole
@@ -159,12 +131,10 @@ export const changeMembershipRole = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const inviteUserToWorkspace = async (req: Request, res: Response) => { export const inviteUserToWorkspace = async (req: Request, res: Response) => {
let invitee, latestKey;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
const { email }: { email: string } = req.body; const { email }: { email: string } = req.body;
invitee = await User.findOne({ const invitee = await User.findOne({
email email
}).select('+publicKey'); }).select('+publicKey');
@@ -193,7 +163,7 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => {
throw new Error("Failed to validate invitee's organization membership"); throw new Error("Failed to validate invitee's organization membership");
// get latest key // get latest key
latestKey = await Key.findOne({ const latestKey = await Key.findOne({
workspace: workspaceId, workspace: workspaceId,
receiver: req.user._id receiver: req.user._id
}) })
@@ -218,13 +188,6 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => {
callback_url: (await getSiteURL()) + '/login' callback_url: (await getSiteURL()) + '/login'
} }
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to invite user to workspace'
});
}
return res.status(200).send({ return res.status(200).send({
invitee, invitee,
@@ -1,6 +1,5 @@
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { MembershipOrg, Organization, User } from '../../models'; import { MembershipOrg, Organization, User } from '../../models';
import { deleteMembershipOrg as deleteMemberFromOrg } from '../../helpers/membershipOrg'; import { deleteMembershipOrg as deleteMemberFromOrg } from '../../helpers/membershipOrg';
import { createToken } from '../../helpers/auth'; import { createToken } from '../../helpers/auth';
@@ -19,12 +18,10 @@ import { validateUserEmail } from '../../validation';
* @returns * @returns
*/ */
export const deleteMembershipOrg = async (req: Request, res: Response) => { export const deleteMembershipOrg = async (req: Request, res: Response) => {
let membershipOrgToDelete;
try {
const { membershipOrgId } = req.params; const { membershipOrgId } = req.params;
// check if organization membership to delete exists // check if organization membership to delete exists
membershipOrgToDelete = await MembershipOrg.findOne({ const membershipOrgToDelete = await MembershipOrg.findOne({
_id: membershipOrgId _id: membershipOrgId
}).populate('user'); }).populate('user');
@@ -58,13 +55,6 @@ export const deleteMembershipOrg = async (req: Request, res: Response) => {
await updateSubscriptionOrgQuantity({ await updateSubscriptionOrgQuantity({
organizationId: membershipOrg.organization.toString() organizationId: membershipOrg.organization.toString()
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to delete organization membership'
});
}
return membershipOrgToDelete; return membershipOrgToDelete;
}; };
@@ -80,14 +70,6 @@ export const changeMembershipOrgRole = async (req: Request, res: Response) => {
// [membershipOrgId] // [membershipOrgId]
let membershipToChangeRole; let membershipToChangeRole;
// try {
// } catch (err) {
// Sentry.setUser({ email: req.user.email });
// Sentry.captureException(err);
// return res.status(400).send({
// message: 'Failed to change organization membership role'
// });
// }
return res.status(200).send({ return res.status(200).send({
membershipOrg: membershipToChangeRole membershipOrg: membershipToChangeRole
@@ -103,7 +85,6 @@ export const changeMembershipOrgRole = async (req: Request, res: Response) => {
*/ */
export const inviteUserToOrganization = async (req: Request, res: Response) => { export const inviteUserToOrganization = async (req: Request, res: Response) => {
let invitee, inviteeMembershipOrg, completeInviteLink; let invitee, inviteeMembershipOrg, completeInviteLink;
try {
const { organizationId, inviteeEmail } = req.body; const { organizationId, inviteeEmail } = req.body;
const host = req.headers.host; const host = req.headers.host;
const siteUrl = `${req.protocol}://${host}`; const siteUrl = `${req.protocol}://${host}`;
@@ -212,13 +193,6 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
} }
await updateSubscriptionOrgQuantity({ organizationId }); await updateSubscriptionOrgQuantity({ organizationId });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to send organization invite'
});
}
return res.status(200).send({ return res.status(200).send({
message: `Sent an invite link to ${req.body.inviteeEmail}`, message: `Sent an invite link to ${req.body.inviteeEmail}`,
@@ -234,8 +208,7 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const verifyUserToOrganization = async (req: Request, res: Response) => { export const verifyUserToOrganization = async (req: Request, res: Response) => {
let user, token; let user;
try {
const { const {
email, email,
organizationId, organizationId,
@@ -284,20 +257,13 @@ export const verifyUserToOrganization = async (req: Request, res: Response) => {
} }
// generate temporary signup token // generate temporary signup token
token = createToken({ const token = createToken({
payload: { payload: {
userId: user._id.toString() userId: user._id.toString()
}, },
expiresIn: await getJwtSignupLifetime(), expiresIn: await getJwtSignupLifetime(),
secret: await getJwtSignupSecret() secret: await getJwtSignupSecret()
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
error: 'Failed email magic link verification for organization invitation'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully verified email', message: 'Successfully verified email',
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import Stripe from 'stripe'; import Stripe from 'stripe';
import { import {
@@ -15,21 +14,12 @@ import _ from 'lodash';
import { getStripeSecretKey, getSiteURL } from '../../config'; import { getStripeSecretKey, getSiteURL } from '../../config';
export const getOrganizations = async (req: Request, res: Response) => { export const getOrganizations = async (req: Request, res: Response) => {
let organizations; const organizations = (
try {
organizations = (
await MembershipOrg.find({ await MembershipOrg.find({
user: req.user._id, user: req.user._id,
status: ACCEPTED status: ACCEPTED
}).populate('organization') }).populate('organization')
).map((m) => m.organization); ).map((m) => m.organization);
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get organizations'
});
}
return res.status(200).send({ return res.status(200).send({
organizations organizations
@@ -44,8 +34,6 @@ export const getOrganizations = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const createOrganization = async (req: Request, res: Response) => { export const createOrganization = async (req: Request, res: Response) => {
let organization;
try {
const { organizationName } = req.body; const { organizationName } = req.body;
if (organizationName.length < 1) { if (organizationName.length < 1) {
@@ -53,7 +41,7 @@ export const createOrganization = async (req: Request, res: Response) => {
} }
// create organization and add user as member // create organization and add user as member
organization = await create({ const organization = await create({
email: req.user.email, email: req.user.email,
name: organizationName name: organizationName
}); });
@@ -64,13 +52,6 @@ export const createOrganization = async (req: Request, res: Response) => {
roles: [OWNER], roles: [OWNER],
statuses: [ACCEPTED] statuses: [ACCEPTED]
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to create organization'
});
}
return res.status(200).send({ return res.status(200).send({
organization organization
@@ -84,17 +65,7 @@ export const createOrganization = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const getOrganization = async (req: Request, res: Response) => { export const getOrganization = async (req: Request, res: Response) => {
let organization; const organization = req.organization
try {
organization = req.organization
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to find organization'
});
}
return res.status(200).send({ return res.status(200).send({
organization organization
}); });
@@ -107,20 +78,11 @@ export const getOrganization = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const getOrganizationMembers = async (req: Request, res: Response) => { export const getOrganizationMembers = async (req: Request, res: Response) => {
let users;
try {
const { organizationId } = req.params; const { organizationId } = req.params;
users = await MembershipOrg.find({ const users = await MembershipOrg.find({
organization: organizationId organization: organizationId
}).populate('user', '+publicKey'); }).populate('user', '+publicKey');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get organization members'
});
}
return res.status(200).send({ return res.status(200).send({
users users
@@ -137,8 +99,6 @@ export const getOrganizationWorkspaces = async (
req: Request, req: Request,
res: Response res: Response
) => { ) => {
let workspaces;
try {
const { organizationId } = req.params; const { organizationId } = req.params;
const workspacesSet = new Set( const workspacesSet = new Set(
@@ -152,20 +112,13 @@ export const getOrganizationWorkspaces = async (
).map((w) => w._id.toString()) ).map((w) => w._id.toString())
); );
workspaces = ( const workspaces = (
await Membership.find({ await Membership.find({
user: req.user._id user: req.user._id
}).populate('workspace') }).populate('workspace')
) )
.filter((m) => workspacesSet.has(m.workspace._id.toString())) .filter((m) => workspacesSet.has(m.workspace._id.toString()))
.map((m) => m.workspace); .map((m) => m.workspace);
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get my workspaces'
});
}
return res.status(200).send({ return res.status(200).send({
workspaces workspaces
@@ -179,12 +132,10 @@ export const getOrganizationWorkspaces = async (
* @returns * @returns
*/ */
export const changeOrganizationName = async (req: Request, res: Response) => { export const changeOrganizationName = async (req: Request, res: Response) => {
let organization;
try {
const { organizationId } = req.params; const { organizationId } = req.params;
const { name } = req.body; const { name } = req.body;
organization = await Organization.findOneAndUpdate( const organization = await Organization.findOneAndUpdate(
{ {
_id: organizationId _id: organizationId
}, },
@@ -195,13 +146,6 @@ export const changeOrganizationName = async (req: Request, res: Response) => {
new: true new: true
} }
); );
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to change organization name'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully changed organization name', message: 'Successfully changed organization name',
@@ -219,20 +163,11 @@ export const getOrganizationIncidentContacts = async (
req: Request, req: Request,
res: Response res: Response
) => { ) => {
let incidentContactsOrg;
try {
const { organizationId } = req.params; const { organizationId } = req.params;
incidentContactsOrg = await IncidentContactOrg.find({ const incidentContactsOrg = await IncidentContactOrg.find({
organization: organizationId organization: organizationId
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get organization incident contacts'
});
}
return res.status(200).send({ return res.status(200).send({
incidentContactsOrg incidentContactsOrg
@@ -249,23 +184,14 @@ export const addOrganizationIncidentContact = async (
req: Request, req: Request,
res: Response res: Response
) => { ) => {
let incidentContactOrg;
try {
const { organizationId } = req.params; const { organizationId } = req.params;
const { email } = req.body; const { email } = req.body;
incidentContactOrg = await IncidentContactOrg.findOneAndUpdate( const incidentContactOrg = await IncidentContactOrg.findOneAndUpdate(
{ email, organization: organizationId }, { email, organization: organizationId },
{ email, organization: organizationId }, { email, organization: organizationId },
{ upsert: true, new: true } { upsert: true, new: true }
); );
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to add incident contact for organization'
});
}
return res.status(200).send({ return res.status(200).send({
incidentContactOrg incidentContactOrg
@@ -282,22 +208,13 @@ export const deleteOrganizationIncidentContact = async (
req: Request, req: Request,
res: Response res: Response
) => { ) => {
let incidentContactOrg;
try {
const { organizationId } = req.params; const { organizationId } = req.params;
const { email } = req.body; const { email } = req.body;
incidentContactOrg = await IncidentContactOrg.findOneAndDelete({ const incidentContactOrg = await IncidentContactOrg.findOneAndDelete({
email, email,
organization: organizationId organization: organizationId
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to delete organization incident contact'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully deleted organization incident contact', message: 'Successfully deleted organization incident contact',
@@ -317,7 +234,6 @@ export const createOrganizationPortalSession = async (
res: Response res: Response
) => { ) => {
let session; let session;
try {
const stripe = new Stripe(await getStripeSecretKey(), { const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: '2022-08-01' apiVersion: '2022-08-01'
}); });
@@ -345,13 +261,6 @@ export const createOrganizationPortalSession = async (
} }
return res.status(200).send({ url: session.url }); return res.status(200).send({ url: session.url });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to redirect to organization billing portal'
});
}
}; };
/** /**
@@ -364,22 +273,13 @@ export const getOrganizationSubscriptions = async (
req: Request, req: Request,
res: Response res: Response
) => { ) => {
let subscriptions;
try {
const stripe = new Stripe(await getStripeSecretKey(), { const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: '2022-08-01' apiVersion: '2022-08-01'
}); });
subscriptions = await stripe.subscriptions.list({ const subscriptions = await stripe.subscriptions.list({
customer: req.organization.customerId customer: req.organization.customerId
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get organization subscriptions'
});
}
return res.status(200).send({ return res.status(200).send({
subscriptions subscriptions
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const jsrp = require('jsrp'); const jsrp = require('jsrp');
import * as bigintConversion from 'bigint-conversion'; import * as bigintConversion from 'bigint-conversion';
@@ -31,7 +30,6 @@ import {
*/ */
export const emailPasswordReset = async (req: Request, res: Response) => { export const emailPasswordReset = async (req: Request, res: Response) => {
let email: string; let email: string;
try {
email = req.body.email; email = req.body.email;
const user = await User.findOne({ email }).select('+publicKey'); const user = await User.findOne({ email }).select('+publicKey');
@@ -58,13 +56,6 @@ export const emailPasswordReset = async (req: Request, res: Response) => {
callback_url: (await getSiteURL()) + '/password-reset' callback_url: (await getSiteURL()) + '/password-reset'
} }
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to send email for account recovery'
});
}
return res.status(200).send({ return res.status(200).send({
message:"If an account exists with this email, a password reset link has been sent" message:"If an account exists with this email, a password reset link has been sent"
@@ -78,11 +69,9 @@ export const emailPasswordReset = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const emailPasswordResetVerify = async (req: Request, res: Response) => { export const emailPasswordResetVerify = async (req: Request, res: Response) => {
let user, token;
try {
const { email, code } = req.body; const { email, code } = req.body;
user = await User.findOne({ email }).select('+publicKey'); const user = await User.findOne({ email }).select('+publicKey');
if (!user || !user?.publicKey) { if (!user || !user?.publicKey) {
// case: user doesn't exist with email [email] or // case: user doesn't exist with email [email] or
// hasn't even completed their account // hasn't even completed their account
@@ -98,20 +87,13 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => {
}); });
// generate temporary password-reset token // generate temporary password-reset token
token = createToken({ const token = createToken({
payload: { payload: {
userId: user._id.toString() userId: user._id.toString()
}, },
expiresIn: await getJwtSignupLifetime(), expiresIn: await getJwtSignupLifetime(),
secret: await getJwtSignupSecret() secret: await getJwtSignupSecret()
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed email verification for password reset'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully verified email', message: 'Successfully verified email',
@@ -129,7 +111,6 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => {
export const srp1 = async (req: Request, res: Response) => { export const srp1 = async (req: Request, res: Response) => {
// return salt, serverPublicKey as part of first step of SRP protocol // return salt, serverPublicKey as part of first step of SRP protocol
try {
const { clientPublicKey } = req.body; const { clientPublicKey } = req.body;
const user = await User.findOne({ const user = await User.findOne({
email: req.user.email email: req.user.email
@@ -159,14 +140,8 @@ export const srp1 = async (req: Request, res: Response) => {
}); });
} }
); );
} catch (err) { }
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
error: 'Failed to start change password process'
});
}
};
/** /**
* Change account SRP authentication information for user * Change account SRP authentication information for user
@@ -177,7 +152,6 @@ export const srp1 = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const changePassword = async (req: Request, res: Response) => { export const changePassword = async (req: Request, res: Response) => {
try {
const { const {
clientProof, clientProof,
protectedKey, protectedKey,
@@ -257,13 +231,6 @@ export const changePassword = async (req: Request, res: Response) => {
}); });
} }
); );
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
error: 'Failed to change password. Try again?'
});
}
}; };
/** /**
@@ -277,7 +244,6 @@ export const createBackupPrivateKey = async (req: Request, res: Response) => {
// requires verifying [clientProof] as part of second step of SRP protocol // requires verifying [clientProof] as part of second step of SRP protocol
// as initiated in /srp1 // as initiated in /srp1
try {
const { clientProof, encryptedPrivateKey, iv, tag, salt, verifier } = const { clientProof, encryptedPrivateKey, iv, tag, salt, verifier } =
req.body; req.body;
const user = await User.findOne({ const user = await User.findOne({
@@ -333,13 +299,6 @@ export const createBackupPrivateKey = async (req: Request, res: Response) => {
}); });
} }
); );
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to update backup private key'
});
}
}; };
/** /**
@@ -349,20 +308,11 @@ export const createBackupPrivateKey = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const getBackupPrivateKey = async (req: Request, res: Response) => { export const getBackupPrivateKey = async (req: Request, res: Response) => {
let backupPrivateKey; const backupPrivateKey = await BackupPrivateKey.findOne({
try {
backupPrivateKey = await BackupPrivateKey.findOne({
user: req.user._id user: req.user._id
}).select('+encryptedPrivateKey +iv +tag'); }).select('+encryptedPrivateKey +iv +tag');
if (!backupPrivateKey) throw new Error('Failed to find backup private key'); if (!backupPrivateKey) throw new Error('Failed to find backup private key');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get backup private key'
});
}
return res.status(200).send({ return res.status(200).send({
backupPrivateKey backupPrivateKey
@@ -370,7 +320,6 @@ export const getBackupPrivateKey = async (req: Request, res: Response) => {
} }
export const resetPassword = async (req: Request, res: Response) => { export const resetPassword = async (req: Request, res: Response) => {
try {
const { const {
protectedKey, protectedKey,
protectedKeyIV, protectedKeyIV,
@@ -399,13 +348,6 @@ export const resetPassword = async (req: Request, res: Response) => {
new: true new: true
} }
); );
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get backup private key'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully reset password' message: 'Successfully reset password'
+2 -27
View File
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import { Key, Secret } from '../../models'; import { Key, Secret } from '../../models';
import { import {
@@ -37,8 +36,6 @@ interface PushSecret {
*/ */
export const pushSecrets = async (req: Request, res: Response) => { export const pushSecrets = async (req: Request, res: Response) => {
// upload (encrypted) secrets to workspace with id [workspaceId] // upload (encrypted) secrets to workspace with id [workspaceId]
try {
const postHogClient = await TelemetryService.getPostHogClient(); const postHogClient = await TelemetryService.getPostHogClient();
let { secrets }: { secrets: PushSecret[] } = req.body; let { secrets }: { secrets: PushSecret[] } = req.body;
const { keys, environment, channel } = req.body; const { keys, environment, channel } = req.body;
@@ -90,14 +87,6 @@ export const pushSecrets = async (req: Request, res: Response) => {
}) })
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to upload workspace secrets'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully uploaded workspace secrets' message: 'Successfully uploaded workspace secrets'
}); });
@@ -113,7 +102,7 @@ export const pushSecrets = async (req: Request, res: Response) => {
export const pullSecrets = async (req: Request, res: Response) => { export const pullSecrets = async (req: Request, res: Response) => {
let secrets; let secrets;
let key; let key;
try {
const postHogClient = await TelemetryService.getPostHogClient(); const postHogClient = await TelemetryService.getPostHogClient();
const environment: string = req.query.environment as string; const environment: string = req.query.environment as string;
const channel: string = req.query.channel as string; const channel: string = req.query.channel as string;
@@ -157,13 +146,6 @@ export const pullSecrets = async (req: Request, res: Response) => {
} }
}); });
} }
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to pull workspace secrets'
});
}
return res.status(200).send({ return res.status(200).send({
secrets, secrets,
@@ -182,7 +164,7 @@ export const pullSecrets = async (req: Request, res: Response) => {
export const pullSecretsServiceToken = async (req: Request, res: Response) => { export const pullSecretsServiceToken = async (req: Request, res: Response) => {
let secrets; let secrets;
let key; let key;
try {
const postHogClient = await TelemetryService.getPostHogClient(); const postHogClient = await TelemetryService.getPostHogClient();
const environment: string = req.query.environment as string; const environment: string = req.query.environment as string;
const channel: string = req.query.channel as string; const channel: string = req.query.channel as string;
@@ -225,13 +207,6 @@ export const pullSecretsServiceToken = async (req: Request, res: Response) => {
} }
}); });
} }
} catch (err) {
Sentry.setUser({ email: req.serviceToken.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to pull workspace secrets'
});
}
return res.status(200).send({ return res.status(200).send({
secrets: reformatPullSecrets({ secrets }), secrets: reformatPullSecrets({ secrets }),
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { User } from '../../models'; import { User } from '../../models';
import { import {
sendEmailVerification, sendEmailVerification,
@@ -19,7 +18,6 @@ import { validateUserEmail } from '../../validation';
*/ */
export const beginEmailSignup = async (req: Request, res: Response) => { export const beginEmailSignup = async (req: Request, res: Response) => {
let email: string; let email: string;
try {
email = req.body.email; email = req.body.email;
// validate that email is not disposable // validate that email is not disposable
@@ -36,13 +34,6 @@ export const beginEmailSignup = async (req: Request, res: Response) => {
// send send verification email // send send verification email
await sendEmailVerification({ email }); await sendEmailVerification({ email });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
error: 'Failed to send email verification code'
});
}
return res.status(200).send({ return res.status(200).send({
message: `Sent an email verification code to ${email}` message: `Sent an email verification code to ${email}`
@@ -58,7 +49,6 @@ export const beginEmailSignup = async (req: Request, res: Response) => {
*/ */
export const verifyEmailSignup = async (req: Request, res: Response) => { export const verifyEmailSignup = async (req: Request, res: Response) => {
let user, token; let user, token;
try {
const { email, code } = req.body; const { email, code } = req.body;
// initialize user account // initialize user account
@@ -100,13 +90,6 @@ export const verifyEmailSignup = async (req: Request, res: Response) => {
expiresIn: await getJwtSignupLifetime(), expiresIn: await getJwtSignupLifetime(),
secret: await getJwtSignupSecret() secret: await getJwtSignupSecret()
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
error: 'Failed email verification'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfuly verified email', message: 'Successfuly verified email',
+1 -11
View File
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import Stripe from 'stripe'; import Stripe from 'stripe';
import { getStripeSecretKey, getStripeWebhookSecret } from '../../config'; import { getStripeSecretKey, getStripeWebhookSecret } from '../../config';
@@ -10,26 +9,17 @@ import { getStripeSecretKey, getStripeWebhookSecret } from '../../config';
* @returns * @returns
*/ */
export const handleWebhook = async (req: Request, res: Response) => { export const handleWebhook = async (req: Request, res: Response) => {
let event;
try {
// check request for valid stripe signature // check request for valid stripe signature
const stripe = new Stripe(await getStripeSecretKey(), { const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: '2022-08-01' apiVersion: '2022-08-01'
}); });
const sig = req.headers['stripe-signature'] as string; const sig = req.headers['stripe-signature'] as string;
event = stripe.webhooks.constructEvent( const event = stripe.webhooks.constructEvent(
req.body, req.body,
sig, sig,
await getStripeWebhookSecret() await getStripeWebhookSecret()
); );
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
error: 'Failed to process webhook'
});
}
switch (event.type) { switch (event.type) {
case '': case '':
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { UserAction } from '../../models'; import { UserAction } from '../../models';
/** /**
@@ -11,11 +10,9 @@ import { UserAction } from '../../models';
export const addUserAction = async (req: Request, res: Response) => { export const addUserAction = async (req: Request, res: Response) => {
// add/record new action [action] for user with id [req.user._id] // add/record new action [action] for user with id [req.user._id]
let userAction;
try {
const { action } = req.body; const { action } = req.body;
userAction = await UserAction.findOneAndUpdate( const userAction = await UserAction.findOneAndUpdate(
{ {
user: req.user._id, user: req.user._id,
action action
@@ -26,13 +23,6 @@ export const addUserAction = async (req: Request, res: Response) => {
upsert: true upsert: true
} }
); );
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to record user action'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully recorded user action', message: 'Successfully recorded user action',
@@ -48,21 +38,12 @@ export const addUserAction = async (req: Request, res: Response) => {
*/ */
export const getUserAction = async (req: Request, res: Response) => { export const getUserAction = async (req: Request, res: Response) => {
// get user action [action] for user with id [req.user._id] // get user action [action] for user with id [req.user._id]
let userAction;
try {
const action: string = req.query.action as string; const action: string = req.query.action as string;
userAction = await UserAction.findOne({ const userAction = await UserAction.findOne({
user: req.user._id, user: req.user._id,
action action
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get user action'
});
}
return res.status(200).send({ return res.status(200).send({
userAction userAction
@@ -1,5 +1,4 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import * as Sentry from "@sentry/node";
import { import {
Workspace, Workspace,
Membership, Membership,
@@ -25,11 +24,9 @@ import { ADMIN } from "../../variables";
* @returns * @returns
*/ */
export const getWorkspacePublicKeys = async (req: Request, res: Response) => { export const getWorkspacePublicKeys = async (req: Request, res: Response) => {
let publicKeys;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
publicKeys = ( const publicKeys = (
await Membership.find({ await Membership.find({
workspace: workspaceId, workspace: workspaceId,
}).populate<{ user: IUser }>("user", "publicKey") }).populate<{ user: IUser }>("user", "publicKey")
@@ -39,13 +36,6 @@ export const getWorkspacePublicKeys = async (req: Request, res: Response) => {
userId: member.user._id, userId: member.user._id,
}; };
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get workspace member public keys",
});
}
return res.status(200).send({ return res.status(200).send({
publicKeys, publicKeys,
@@ -59,20 +49,11 @@ export const getWorkspacePublicKeys = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const getWorkspaceMemberships = async (req: Request, res: Response) => { export const getWorkspaceMemberships = async (req: Request, res: Response) => {
let users;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
users = await Membership.find({ const users = await Membership.find({
workspace: workspaceId, workspace: workspaceId,
}).populate("user", "+publicKey"); }).populate("user", "+publicKey");
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get workspace members",
});
}
return res.status(200).send({ return res.status(200).send({
users, users,
@@ -86,20 +67,11 @@ export const getWorkspaceMemberships = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const getWorkspaces = async (req: Request, res: Response) => { export const getWorkspaces = async (req: Request, res: Response) => {
let workspaces; const workspaces = (
try {
workspaces = (
await Membership.find({ await Membership.find({
user: req.user._id, user: req.user._id,
}).populate("workspace") }).populate("workspace")
).map((m) => m.workspace); ).map((m) => m.workspace);
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get workspaces",
});
}
return res.status(200).send({ return res.status(200).send({
workspaces, workspaces,
@@ -113,20 +85,11 @@ export const getWorkspaces = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const getWorkspace = async (req: Request, res: Response) => { export const getWorkspace = async (req: Request, res: Response) => {
let workspace;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
workspace = await Workspace.findOne({ const workspace = await Workspace.findOne({
_id: workspaceId, _id: workspaceId,
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get workspace",
});
}
return res.status(200).send({ return res.status(200).send({
workspace, workspace,
@@ -141,9 +104,6 @@ export const getWorkspace = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const createWorkspace = async (req: Request, res: Response) => { export const createWorkspace = async (req: Request, res: Response) => {
let workspace;
try {
const { workspaceName, organizationId } = req.body; const { workspaceName, organizationId } = req.body;
// validate organization membership // validate organization membership
@@ -173,7 +133,7 @@ export const createWorkspace = async (req: Request, res: Response) => {
} }
// create workspace and add user as member // create workspace and add user as member
workspace = await create({ const workspace = await create({
name: workspaceName, name: workspaceName,
organizationId, organizationId,
}); });
@@ -183,13 +143,6 @@ export const createWorkspace = async (req: Request, res: Response) => {
workspaceId: workspace._id.toString(), workspaceId: workspace._id.toString(),
roles: [ADMIN], roles: [ADMIN],
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to create workspace",
});
}
return res.status(200).send({ return res.status(200).send({
workspace, workspace,
@@ -203,20 +156,12 @@ export const createWorkspace = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const deleteWorkspace = async (req: Request, res: Response) => { export const deleteWorkspace = async (req: Request, res: Response) => {
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
// delete workspace // delete workspace
await deleteWork({ await deleteWork({
id: workspaceId, id: workspaceId,
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to delete workspace",
});
}
return res.status(200).send({ return res.status(200).send({
message: "Successfully deleted workspace", message: "Successfully deleted workspace",
@@ -230,12 +175,10 @@ export const deleteWorkspace = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const changeWorkspaceName = async (req: Request, res: Response) => { export const changeWorkspaceName = async (req: Request, res: Response) => {
let workspace;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
const { name } = req.body; const { name } = req.body;
workspace = await Workspace.findOneAndUpdate( const workspace = await Workspace.findOneAndUpdate(
{ {
_id: workspaceId, _id: workspaceId,
}, },
@@ -246,13 +189,6 @@ export const changeWorkspaceName = async (req: Request, res: Response) => {
new: true, new: true,
} }
); );
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to change workspace name",
});
}
return res.status(200).send({ return res.status(200).send({
message: "Successfully changed workspace name", message: "Successfully changed workspace name",
@@ -267,20 +203,11 @@ export const changeWorkspaceName = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const getWorkspaceIntegrations = async (req: Request, res: Response) => { export const getWorkspaceIntegrations = async (req: Request, res: Response) => {
let integrations;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
integrations = await Integration.find({ const integrations = await Integration.find({
workspace: workspaceId, workspace: workspaceId,
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get workspace integrations",
});
}
return res.status(200).send({ return res.status(200).send({
integrations, integrations,
@@ -297,20 +224,11 @@ export const getWorkspaceIntegrationAuthorizations = async (
req: Request, req: Request,
res: Response res: Response
) => { ) => {
let authorizations;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
authorizations = await IntegrationAuth.find({ const authorizations = await IntegrationAuth.find({
workspace: workspaceId, workspace: workspaceId,
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get workspace integration authorizations",
});
}
return res.status(200).send({ return res.status(200).send({
authorizations, authorizations,
@@ -327,21 +245,12 @@ export const getWorkspaceServiceTokens = async (
req: Request, req: Request,
res: Response res: Response
) => { ) => {
let serviceTokens;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
// ?? FIX. // ?? FIX.
serviceTokens = await ServiceToken.find({ const serviceTokens = await ServiceToken.find({
user: req.user._id, user: req.user._id,
workspace: workspaceId, workspace: workspaceId,
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get workspace service tokens",
});
}
return res.status(200).send({ return res.status(200).send({
serviceTokens, serviceTokens,
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import crypto from 'crypto'; import crypto from 'crypto';
import bcrypt from 'bcrypt'; import bcrypt from 'bcrypt';
@@ -14,18 +13,9 @@ import { getSaltRounds } from '../../config';
* @returns * @returns
*/ */
export const getAPIKeyData = async (req: Request, res: Response) => { export const getAPIKeyData = async (req: Request, res: Response) => {
let apiKeyData; const apiKeyData = await APIKeyData.find({
try {
apiKeyData = await APIKeyData.find({
user: req.user._id user: req.user._id
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get API key data'
});
}
return res.status(200).send({ return res.status(200).send({
apiKeyData apiKeyData
@@ -38,8 +28,6 @@ export const getAPIKeyData = async (req: Request, res: Response) => {
* @param res * @param res
*/ */
export const createAPIKeyData = async (req: Request, res: Response) => { export const createAPIKeyData = async (req: Request, res: Response) => {
let apiKey, apiKeyData;
try {
const { name, expiresIn } = req.body; const { name, expiresIn } = req.body;
const secret = crypto.randomBytes(16).toString('hex'); const secret = crypto.randomBytes(16).toString('hex');
@@ -48,7 +36,7 @@ export const createAPIKeyData = async (req: Request, res: Response) => {
const expiresAt = new Date(); const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn); expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);
apiKeyData = await new APIKeyData({ let apiKeyData = await new APIKeyData({
name, name,
lastUsed: new Date(), lastUsed: new Date(),
expiresAt, expiresAt,
@@ -57,19 +45,12 @@ export const createAPIKeyData = async (req: Request, res: Response) => {
}).save(); }).save();
// return api key data without sensitive data // return api key data without sensitive data
apiKeyData = await APIKeyData.findById(apiKeyData._id); // FIX: fix this any
apiKeyData = await APIKeyData.findById(apiKeyData._id) as any
if (!apiKeyData) throw new Error('Failed to find API key data'); if (!apiKeyData) throw new Error('Failed to find API key data');
apiKey = `ak.${apiKeyData._id.toString()}.${secret}`; const apiKey = `ak.${apiKeyData._id.toString()}.${secret}`;
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to API key data'
});
}
return res.status(200).send({ return res.status(200).send({
apiKey, apiKey,
@@ -84,19 +65,8 @@ export const createAPIKeyData = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const deleteAPIKeyData = async (req: Request, res: Response) => { export const deleteAPIKeyData = async (req: Request, res: Response) => {
let apiKeyData;
try {
const { apiKeyDataId } = req.params; const { apiKeyDataId } = req.params;
const apiKeyData = await APIKeyData.findByIdAndDelete(apiKeyDataId);
apiKeyData = await APIKeyData.findByIdAndDelete(apiKeyDataId);
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to delete API key data'
});
}
return res.status(200).send({ return res.status(200).send({
apiKeyData apiKeyData
+82 -26
View File
@@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import * as Sentry from '@sentry/node';
import * as bigintConversion from 'bigint-conversion'; import * as bigintConversion from 'bigint-conversion';
const jsrp = require('jsrp'); const jsrp = require('jsrp');
import { User, LoginSRPDetail } from '../../models'; import { User, LoginSRPDetail } from '../../models';
@@ -35,7 +34,6 @@ declare module 'jsonwebtoken' {
* @returns * @returns
*/ */
export const login1 = async (req: Request, res: Response) => { export const login1 = async (req: Request, res: Response) => {
try {
const { const {
email, email,
clientPublicKey clientPublicKey
@@ -69,13 +67,7 @@ export const login1 = async (req: Request, res: Response) => {
}); });
} }
); );
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to start authentication process'
});
}
}; };
/** /**
@@ -86,14 +78,21 @@ export const login1 = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const login2 = async (req: Request, res: Response) => { export const login2 = async (req: Request, res: Response) => {
try { if (!req.headers['user-agent']) throw InternalServerError({ message: 'User-Agent header is required' });
<<<<<<< HEAD
if (!req.headers['user-agent']) throw InternalServerError({ message: 'User-Agent header is required' }); if (!req.headers['user-agent']) throw InternalServerError({ message: 'User-Agent header is required' });
const { email, clientProof } = req.body; const { email, clientProof } = req.body;
const user = await User.findOne({ const user = await User.findOne({
email email
}).select('+salt +verifier +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag +publicKey +encryptedPrivateKey +iv +tag +devices'); }).select('+salt +verifier +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag +publicKey +encryptedPrivateKey +iv +tag +devices');
=======
const { email, clientProof } = req.body;
const user = await User.findOne({
email
}).select('+salt +verifier +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag +publicKey +encryptedPrivateKey +iv +tag');
>>>>>>> origin/main
if (!user) throw new Error('Failed to find user'); if (!user) throw new Error('Failed to find user');
@@ -103,6 +102,7 @@ export const login2 = async (req: Request, res: Response) => {
return BadRequestError(Error("Failed to find login details for SRP")) return BadRequestError(Error("Failed to find login details for SRP"))
} }
<<<<<<< HEAD
const server = new jsrp.server(); const server = new jsrp.server();
server.init( server.init(
{ {
@@ -162,6 +162,77 @@ export const login2 = async (req: Request, res: Response) => {
userAgent: req.headers['user-agent'] ?? '' userAgent: req.headers['user-agent'] ?? ''
}); });
// store (refresh) token in httpOnly cookie
res.cookie('jid', tokens.refreshToken, {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: await getHttpsEnabled()
=======
const server = new jsrp.server();
server.init(
{
salt: user.salt,
verifier: user.verifier,
b: loginSRPDetail.serverBInt
},
async () => {
server.setClientPublicKey(loginSRPDetail.clientPublicKey);
// compare server and client shared keys
if (server.checkClientProof(clientProof)) {
if (user.isMfaEnabled) {
// case: user has MFA enabled
// generate temporary MFA token
const token = createToken({
payload: {
userId: user._id.toString()
},
expiresIn: await getJwtMfaLifetime(),
secret: await getJwtMfaSecret()
});
const code = await TokenService.createToken({
type: TOKEN_EMAIL_MFA,
email
>>>>>>> origin/main
});
// send MFA code [code] to [email]
await sendMail({
template: 'emailMfa.handlebars',
subjectLine: 'Infisical MFA code',
recipients: [email],
substitutions: {
code
}
});
<<<<<<< HEAD
loginAction && await EELogService.createLog({
userId: user._id,
actions: [loginAction],
channel: getChannelFromUserAgent(req.headers['user-agent']),
ipAddress: req.realIP
=======
return res.status(200).send({
mfaEnabled: true,
token
>>>>>>> origin/main
});
}
await checkUserDevice({
user,
ip: req.ip,
userAgent: req.headers['user-agent'] ?? ''
});
// issue tokens
const tokens = await issueAuthTokens({ userId: user._id.toString() });
// store (refresh) token in httpOnly cookie // store (refresh) token in httpOnly cookie
res.cookie('jid', tokens.refreshToken, { res.cookie('jid', tokens.refreshToken, {
httpOnly: true, httpOnly: true,
@@ -215,7 +286,7 @@ export const login2 = async (req: Request, res: Response) => {
userId: user._id, userId: user._id,
actions: [loginAction], actions: [loginAction],
channel: getChannelFromUserAgent(req.headers['user-agent']), channel: getChannelFromUserAgent(req.headers['user-agent']),
ipAddress: req.realIP ipAddress: req.ip
}); });
return res.status(200).send(response); return res.status(200).send(response);
@@ -226,13 +297,6 @@ export const login2 = async (req: Request, res: Response) => {
}); });
} }
); );
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to authenticate. Try again?'
});
}
}; };
/** /**
@@ -241,7 +305,6 @@ export const login2 = async (req: Request, res: Response) => {
* @param res * @param res
*/ */
export const sendMfaToken = async (req: Request, res: Response) => { export const sendMfaToken = async (req: Request, res: Response) => {
try {
const { email } = req.body; const { email } = req.body;
const code = await TokenService.createToken({ const code = await TokenService.createToken({
@@ -258,13 +321,6 @@ export const sendMfaToken = async (req: Request, res: Response) => {
code code
} }
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to send MFA code'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully sent new MFA code' message: 'Successfully sent new MFA code'
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { import {
Secret, Secret,
ServiceToken, ServiceToken,
@@ -25,7 +24,6 @@ export const createWorkspaceEnvironment = async (
) => { ) => {
const { workspaceId } = req.params; const { workspaceId } = req.params;
const { environmentName, environmentSlug } = req.body; const { environmentName, environmentSlug } = req.body;
try {
const workspace = await Workspace.findById(workspaceId).exec(); const workspace = await Workspace.findById(workspaceId).exec();
if ( if (
!workspace || !workspace ||
@@ -41,13 +39,6 @@ export const createWorkspaceEnvironment = async (
slug: environmentSlug.toLowerCase(), slug: environmentSlug.toLowerCase(),
}); });
await workspace.save(); await workspace.save();
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to create new workspace environment',
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully created new environment', message: 'Successfully created new environment',
@@ -72,7 +63,6 @@ export const renameWorkspaceEnvironment = async (
) => { ) => {
const { workspaceId } = req.params; const { workspaceId } = req.params;
const { environmentName, environmentSlug, oldEnvironmentSlug } = req.body; const { environmentName, environmentSlug, oldEnvironmentSlug } = req.body;
try {
// user should pass both new slug and env name // user should pass both new slug and env name
if (!environmentSlug || !environmentName) { if (!environmentSlug || !environmentName) {
throw new Error('Invalid environment given.'); throw new Error('Invalid environment given.');
@@ -133,13 +123,6 @@ export const renameWorkspaceEnvironment = async (
{ arrayFilters: [{ "element.environmentSlug": oldEnvironmentSlug }] } { arrayFilters: [{ "element.environmentSlug": oldEnvironmentSlug }] }
) )
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to update workspace environment',
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully update environment', message: 'Successfully update environment',
@@ -163,7 +146,6 @@ export const deleteWorkspaceEnvironment = async (
) => { ) => {
const { workspaceId } = req.params; const { workspaceId } = req.params;
const { environmentSlug } = req.body; const { environmentSlug } = req.body;
try {
// atomic update the env to avoid conflict // atomic update the env to avoid conflict
const workspace = await Workspace.findById(workspaceId).exec(); const workspace = await Workspace.findById(workspaceId).exec();
if (!workspace) { if (!workspace) {
@@ -206,14 +188,6 @@ export const deleteWorkspaceEnvironment = async (
{ $pull: { deniedPermissions: { environmentSlug: environmentSlug } } } { $pull: { deniedPermissions: { environmentSlug: environmentSlug } } }
) )
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to delete workspace environment',
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully deleted environment', message: 'Successfully deleted environment',
workspace: workspaceId, workspace: workspaceId,
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import { import {
MembershipOrg, MembershipOrg,
@@ -49,20 +48,11 @@ export const getOrganizationMemberships = async (req: Request, res: Response) =>
} }
} }
*/ */
let memberships;
try {
const { organizationId } = req.params; const { organizationId } = req.params;
memberships = await MembershipOrg.find({ const memberships = await MembershipOrg.find({
organization: organizationId organization: organizationId
}).populate('user', '+publicKey'); }).populate('user', '+publicKey');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get organization memberships'
});
}
return res.status(200).send({ return res.status(200).send({
memberships memberships
@@ -128,12 +118,10 @@ export const updateOrganizationMembership = async (req: Request, res: Response)
} }
} }
*/ */
let membership;
try {
const { membershipId } = req.params; const { membershipId } = req.params;
const { role } = req.body; const { role } = req.body;
membership = await MembershipOrg.findByIdAndUpdate( const membership = await MembershipOrg.findByIdAndUpdate(
membershipId, membershipId,
{ {
role role
@@ -141,13 +129,6 @@ export const updateOrganizationMembership = async (req: Request, res: Response)
new: true new: true
} }
); );
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to update organization membership'
});
}
return res.status(200).send({ return res.status(200).send({
membership membership
@@ -197,25 +178,16 @@ export const deleteOrganizationMembership = async (req: Request, res: Response)
} }
} }
*/ */
let membership;
try {
const { membershipId } = req.params; const { membershipId } = req.params;
// delete organization membership // delete organization membership
membership = await deleteMembershipOrg({ const membership = await deleteMembershipOrg({
membershipOrgId: membershipId membershipOrgId: membershipId
}); });
await updateSubscriptionOrgQuantity({ await updateSubscriptionOrgQuantity({
organizationId: membership.organization.toString() organizationId: membership.organization.toString()
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to delete organization membership'
});
}
return res.status(200).send({ return res.status(200).send({
membership membership
@@ -218,6 +218,7 @@ export const batchSecrets = async (req: Request, res: Response) => {
algorithm: ALGORITHM_AES_256_GCM, algorithm: ALGORITHM_AES_256_GCM,
keyEncoding: ENCODING_SCHEME_UTF8, keyEncoding: ENCODING_SCHEME_UTF8,
tags: u.tags, tags: u.tags,
folder: u.folder
}) })
); );
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import crypto from 'crypto'; import crypto from 'crypto';
import bcrypt from 'bcrypt'; import bcrypt from 'bcrypt';
+14 -17
View File
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { User, MembershipOrg } from '../../models'; import { User, MembershipOrg } from '../../models';
import { completeAccount } from '../../helpers/user'; import { completeAccount } from '../../helpers/user';
import { import {
@@ -20,7 +19,6 @@ import { updateSubscriptionOrgQuantity } from '../../helpers/organization';
*/ */
export const completeAccountSignup = async (req: Request, res: Response) => { export const completeAccountSignup = async (req: Request, res: Response) => {
let user, token, refreshToken; let user, token, refreshToken;
try {
const { const {
email, email,
firstName, firstName,
@@ -114,12 +112,19 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
} }
); );
<<<<<<< HEAD
// issue tokens // issue tokens
const tokens = await issueAuthTokens({ const tokens = await issueAuthTokens({
userId: user._id, userId: user._id,
ip: req.realIP, ip: req.realIP,
userAgent: req.headers['user-agent'] ?? '' userAgent: req.headers['user-agent'] ?? ''
}); });
=======
// issue tokens
const tokens = await issueAuthTokens({
userId: user._id.toString()
});
>>>>>>> origin/main
token = tokens.token; token = tokens.token;
@@ -145,13 +150,6 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
sameSite: 'strict', sameSite: 'strict',
secure: await getHttpsEnabled() secure: await getHttpsEnabled()
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to complete account setup'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully set up account', message: 'Successfully set up account',
@@ -169,7 +167,6 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
*/ */
export const completeAccountInvite = async (req: Request, res: Response) => { export const completeAccountInvite = async (req: Request, res: Response) => {
let user, token, refreshToken; let user, token, refreshToken;
try {
const { const {
email, email,
firstName, firstName,
@@ -247,12 +244,19 @@ export const completeAccountInvite = async (req: Request, res: Response) => {
} }
); );
<<<<<<< HEAD
// issue tokens // issue tokens
const tokens = await issueAuthTokens({ const tokens = await issueAuthTokens({
userId: user._id, userId: user._id,
ip: req.realIP, ip: req.realIP,
userAgent: req.headers['user-agent'] ?? '' userAgent: req.headers['user-agent'] ?? ''
}); });
=======
// issue tokens
const tokens = await issueAuthTokens({
userId: user._id.toString()
});
>>>>>>> origin/main
token = tokens.token; token = tokens.token;
@@ -263,13 +267,6 @@ export const completeAccountInvite = async (req: Request, res: Response) => {
sameSite: 'strict', sameSite: 'strict',
secure: await getHttpsEnabled() secure: await getHttpsEnabled()
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to complete account setup'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully set up account', message: 'Successfully set up account',
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import { import {
Membership, Secret, Membership, Secret,
+3 -31
View File
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { import {
User, User,
MembershipOrg MembershipOrg
@@ -37,18 +36,9 @@ export const getMe = async (req: Request, res: Response) => {
} }
} }
*/ */
let user; const user = await User
try {
user = await User
.findById(req.user._id) .findById(req.user._id)
.select('+salt +publicKey +encryptedPrivateKey +iv +tag +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag'); .select('+salt +publicKey +encryptedPrivateKey +iv +tag +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get current user'
});
}
return res.status(200).send({ return res.status(200).send({
user user
@@ -64,8 +54,6 @@ export const getMe = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const updateMyMfaEnabled = async (req: Request, res: Response) => { export const updateMyMfaEnabled = async (req: Request, res: Response) => {
let user;
try {
const { isMfaEnabled }: { isMfaEnabled: boolean } = req.body; const { isMfaEnabled }: { isMfaEnabled: boolean } = req.body;
req.user.isMfaEnabled = isMfaEnabled; req.user.isMfaEnabled = isMfaEnabled;
@@ -79,14 +67,7 @@ export const updateMyMfaEnabled = async (req: Request, res: Response) => {
await req.user.save(); await req.user.save();
user = req.user; const user = req.user;
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to update current user's MFA status"
});
}
return res.status(200).send({ return res.status(200).send({
user user
@@ -126,20 +107,11 @@ export const getMyOrganizations = async (req: Request, res: Response) => {
} }
} }
*/ */
let organizations; const organizations = (
try {
organizations = (
await MembershipOrg.find({ await MembershipOrg.find({
user: req.user._id user: req.user._id
}).populate('organization') }).populate('organization')
).map((m) => m.organization); ).map((m) => m.organization);
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get current user's organizations"
});
}
return res.status(200).send({ return res.status(200).send({
organizations organizations
+105 -60
View File
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import { import {
Workspace, Workspace,
@@ -47,6 +46,7 @@ interface V2PushSecret {
*/ */
export const pushWorkspaceSecrets = async (req: Request, res: Response) => { export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
// upload (encrypted) secrets to workspace with id [workspaceId] // upload (encrypted) secrets to workspace with id [workspaceId]
<<<<<<< HEAD
try { try {
const postHogClient = await TelemetryService.getPostHogClient(); const postHogClient = await TelemetryService.getPostHogClient();
let { secrets }: { secrets: V2PushSecret[] } = req.body; let { secrets }: { secrets: V2PushSecret[] } = req.body;
@@ -107,6 +107,59 @@ export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
message: 'Failed to upload workspace secrets' message: 'Failed to upload workspace secrets'
}); });
} }
=======
const postHogClient = await TelemetryService.getPostHogClient();
let { secrets }: { secrets: V2PushSecret[] } = req.body;
const { keys, environment, channel } = req.body;
const { workspaceId } = req.params;
// validate environment
const workspaceEnvs = req.membership.workspace.environments;
if (!workspaceEnvs.find(({ slug }: { slug: string }) => slug === environment)) {
throw new Error('Failed to validate environment');
}
// sanitize secrets
secrets = secrets.filter(
(s: V2PushSecret) => s.secretKeyCiphertext !== '' && s.secretValueCiphertext !== ''
);
await push({
userId: req.user._id,
workspaceId,
environment,
secrets,
channel: channel ? channel : 'cli',
ipAddress: req.ip
});
await pushKeys({
userId: req.user._id,
workspaceId,
keys
});
if (postHogClient) {
postHogClient.capture({
event: 'secrets pushed',
distinctId: req.user.email,
properties: {
numberOfSecrets: secrets.length,
environment,
workspaceId,
channel: channel ? channel : 'cli'
}
});
}
// trigger event - push secrets
EventService.handleEvent({
event: eventPushSecrets({
workspaceId: new Types.ObjectId(workspaceId),
environment
})
});
>>>>>>> origin/main
return res.status(200).send({ return res.status(200).send({
message: 'Successfully uploaded workspace secrets' message: 'Successfully uploaded workspace secrets'
@@ -121,6 +174,7 @@ export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const pullSecrets = async (req: Request, res: Response) => { export const pullSecrets = async (req: Request, res: Response) => {
<<<<<<< HEAD
let secrets; let secrets;
try { try {
const postHogClient = await TelemetryService.getPostHogClient(); const postHogClient = await TelemetryService.getPostHogClient();
@@ -172,6 +226,51 @@ export const pullSecrets = async (req: Request, res: Response) => {
message: 'Failed to pull workspace secrets' message: 'Failed to pull workspace secrets'
}); });
} }
=======
const postHogClient = await TelemetryService.getPostHogClient();
const environment: string = req.query.environment as string;
const channel: string = req.query.channel as string;
const { workspaceId } = req.params;
let userId;
if (req.user) {
userId = req.user._id.toString();
} else if (req.serviceTokenData) {
userId = req.serviceTokenData.user.toString();
}
// validate environment
const workspaceEnvs = req.membership.workspace.environments;
if (!workspaceEnvs.find(({ slug }: { slug: string }) => slug === environment)) {
throw new Error('Failed to validate environment');
}
let secrets = await pull({
userId,
workspaceId,
environment,
channel: channel ? channel : 'cli',
ipAddress: req.ip
});
if (channel !== 'cli') {
// FIX: Fix this any
secrets = reformatPullSecrets({ secrets }) as any;
}
if (postHogClient) {
// capture secrets pushed event in production
postHogClient.capture({
distinctId: req.user.email,
event: 'secrets pulled',
properties: {
numberOfSecrets: secrets.length,
environment,
workspaceId,
channel: channel ? channel : 'cli'
}
});
}
>>>>>>> origin/main
return res.status(200).send({ return res.status(200).send({
secrets secrets
@@ -208,7 +307,6 @@ export const getWorkspaceKey = async (req: Request, res: Response) => {
} }
*/ */
let key; let key;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
key = await Key.findOne({ key = await Key.findOne({
@@ -217,13 +315,6 @@ export const getWorkspaceKey = async (req: Request, res: Response) => {
}).populate('sender', '+publicKey'); }).populate('sender', '+publicKey');
if (!key) throw new Error('Failed to find workspace key'); if (!key) throw new Error('Failed to find workspace key');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get workspace key'
});
}
return res.status(200).json(key); return res.status(200).json(key);
} }
@@ -231,24 +322,14 @@ export const getWorkspaceServiceTokenData = async (
req: Request, req: Request,
res: Response res: Response
) => { ) => {
let serviceTokenData;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
serviceTokenData = await ServiceTokenData const serviceTokenData = await ServiceTokenData
.find({ .find({
workspace: workspaceId workspace: workspaceId
}) })
.select('+encryptedKey +iv +tag'); .select('+encryptedKey +iv +tag');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get workspace service token data'
});
}
return res.status(200).send({ return res.status(200).send({
serviceTokenData serviceTokenData
}); });
@@ -294,20 +375,11 @@ export const getWorkspaceMemberships = async (req: Request, res: Response) => {
} }
} }
*/ */
let memberships;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
memberships = await Membership.find({ const memberships = await Membership.find({
workspace: workspaceId workspace: workspaceId
}).populate('user', '+publicKey'); }).populate('user', '+publicKey');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get workspace memberships'
});
}
return res.status(200).send({ return res.status(200).send({
memberships memberships
@@ -374,14 +446,12 @@ export const updateWorkspaceMembership = async (req: Request, res: Response) =>
} }
} }
*/ */
let membership;
try {
const { const {
membershipId membershipId
} = req.params; } = req.params;
const { role } = req.body; const { role } = req.body;
membership = await Membership.findByIdAndUpdate( const membership = await Membership.findByIdAndUpdate(
membershipId, membershipId,
{ {
role role
@@ -389,13 +459,6 @@ export const updateWorkspaceMembership = async (req: Request, res: Response) =>
new: true new: true
} }
); );
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to update workspace membership'
});
}
return res.status(200).send({ return res.status(200).send({
membership membership
@@ -445,13 +508,11 @@ export const deleteWorkspaceMembership = async (req: Request, res: Response) =>
} }
} }
*/ */
let membership;
try {
const { const {
membershipId membershipId
} = req.params; } = req.params;
membership = await Membership.findByIdAndDelete(membershipId); const membership = await Membership.findByIdAndDelete(membershipId);
if (!membership) throw new Error('Failed to delete workspace membership'); if (!membership) throw new Error('Failed to delete workspace membership');
@@ -459,13 +520,6 @@ export const deleteWorkspaceMembership = async (req: Request, res: Response) =>
receiver: membership.user, receiver: membership.user,
workspace: membership.workspace workspace: membership.workspace
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to delete workspace membership'
});
}
return res.status(200).send({ return res.status(200).send({
membership membership
@@ -479,12 +533,10 @@ export const deleteWorkspaceMembership = async (req: Request, res: Response) =>
* @returns * @returns
*/ */
export const toggleAutoCapitalization = async (req: Request, res: Response) => { export const toggleAutoCapitalization = async (req: Request, res: Response) => {
let workspace;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
const { autoCapitalization } = req.body; const { autoCapitalization } = req.body;
workspace = await Workspace.findOneAndUpdate( const workspace = await Workspace.findOneAndUpdate(
{ {
_id: workspaceId _id: workspaceId
}, },
@@ -495,13 +547,6 @@ export const toggleAutoCapitalization = async (req: Request, res: Response) => {
new: true new: true
} }
); );
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to change autoCapitalization setting'
});
}
return res.status(200).send({ return res.status(200).send({
message: 'Successfully changed autoCapitalization setting', message: 'Successfully changed autoCapitalization setting',
@@ -1,5 +1,4 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { Action, SecretVersion } from '../../models'; import { Action, SecretVersion } from '../../models';
import { ActionNotFoundError } from '../../../utils/errors'; import { ActionNotFoundError } from '../../../utils/errors';
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { EELicenseService } from '../../services'; import { EELicenseService } from '../../services';
import { getLicenseServerUrl } from '../../../config'; import { getLicenseServerUrl } from '../../../config';
@@ -12,7 +11,6 @@ import { licenseServerKeyRequest } from '../../../config/request';
* @returns * @returns
*/ */
export const getCloudProducts = async (req: Request, res: Response) => { export const getCloudProducts = async (req: Request, res: Response) => {
try {
const billingCycle = req.query['billing-cycle'] as string; const billingCycle = req.query['billing-cycle'] as string;
if (EELicenseService.instanceType === 'cloud') { if (EELicenseService.instanceType === 'cloud') {
@@ -22,10 +20,6 @@ export const getCloudProducts = async (req: Request, res: Response) => {
return res.status(200).send(data); return res.status(200).send(data);
} }
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
}
return res.status(200).send({ return res.status(200).send({
head: [], head: [],
@@ -1,5 +1,4 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import * as Sentry from "@sentry/node";
import { Secret } from "../../../models"; import { Secret } from "../../../models";
import { SecretVersion } from "../../models"; import { SecretVersion } from "../../models";
import { EESecretService } from "../../services"; import { EESecretService } from "../../services";
@@ -55,14 +54,12 @@ export const getSecretVersions = async (req: Request, res: Response) => {
} }
} }
*/ */
let secretVersions;
try {
const { secretId, workspaceId, environment, folderId } = req.params; const { secretId, workspaceId, environment, folderId } = req.params;
const offset: number = parseInt(req.query.offset as string); const offset: number = parseInt(req.query.offset as string);
const limit: number = parseInt(req.query.limit as string); const limit: number = parseInt(req.query.limit as string);
secretVersions = await SecretVersion.find({ const secretVersions = await SecretVersion.find({
secret: secretId, secret: secretId,
workspace: workspaceId, workspace: workspaceId,
environment, environment,
@@ -71,13 +68,6 @@ export const getSecretVersions = async (req: Request, res: Response) => {
.sort({ createdAt: -1 }) .sort({ createdAt: -1 })
.skip(offset) .skip(offset)
.limit(limit); .limit(limit);
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get secret versions",
});
}
return res.status(200).send({ return res.status(200).send({
secretVersions, secretVersions,
@@ -139,8 +129,6 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
} }
} }
*/ */
let secret;
try {
const { secretId } = req.params; const { secretId } = req.params;
const { version } = req.body; const { version } = req.body;
@@ -164,13 +152,13 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
secretValueCiphertext, secretValueCiphertext,
secretValueIV, secretValueIV,
secretValueTag, secretValueTag,
folder,
algorithm, algorithm,
folder,
keyEncoding, keyEncoding,
} = oldSecretVersion; } = oldSecretVersion;
// update secret // update secret
secret = await Secret.findByIdAndUpdate( const secret = await Secret.findByIdAndUpdate(
secretId, secretId,
{ {
$inc: { $inc: {
@@ -225,13 +213,6 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
environment, environment,
folderId: folder, folderId: folder,
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to roll back secret version",
});
}
return res.status(200).send({ return res.status(200).send({
secret, secret,
@@ -1,5 +1,4 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import * as Sentry from "@sentry/node";
import { import {
ISecretVersion, ISecretVersion,
SecretSnapshot, SecretSnapshot,
@@ -13,23 +12,21 @@ import {
* @returns * @returns
*/ */
export const getSecretSnapshot = async (req: Request, res: Response) => { export const getSecretSnapshot = async (req: Request, res: Response) => {
let secretSnapshot;
try {
const { secretSnapshotId } = req.params; const { secretSnapshotId } = req.params;
secretSnapshot = await SecretSnapshot.findById(secretSnapshotId) const secretSnapshot = await SecretSnapshot.findById(secretSnapshotId)
.lean() .lean()
.populate<{ secretVersions: ISecretVersion[] }>("secretVersions") .populate<{ secretVersions: ISecretVersion[] }>({
path: 'secretVersions',
populate: {
path: 'tags',
model: 'Tag'
}
})
.populate<{ folderVersion: TFolderRootVersionSchema }>("folderVersion"); .populate<{ folderVersion: TFolderRootVersionSchema }>("folderVersion");
if (!secretSnapshot) throw new Error("Failed to find secret snapshot"); if (!secretSnapshot) throw new Error("Failed to find secret snapshot");
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get secret snapshot",
});
}
const folderId = secretSnapshot.folderId; const folderId = secretSnapshot.folderId;
// to show only the folder required secrets // to show only the folder required secrets
secretSnapshot.secretVersions = secretSnapshot.secretVersions.filter( secretSnapshot.secretVersions = secretSnapshot.secretVersions.filter(
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import Stripe from 'stripe'; import Stripe from 'stripe';
import { getStripeSecretKey, getStripeWebhookSecret } from '../../../config'; import { getStripeSecretKey, getStripeWebhookSecret } from '../../../config';
@@ -10,26 +9,17 @@ import { getStripeSecretKey, getStripeWebhookSecret } from '../../../config';
* @returns * @returns
*/ */
export const handleWebhook = async (req: Request, res: Response) => { export const handleWebhook = async (req: Request, res: Response) => {
let event;
try {
const stripe = new Stripe(await getStripeSecretKey(), { const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: '2022-08-01' apiVersion: '2022-08-01'
}); });
// check request for valid stripe signature // check request for valid stripe signature
const sig = req.headers['stripe-signature'] as string; const sig = req.headers['stripe-signature'] as string;
event = stripe.webhooks.constructEvent( const event = stripe.webhooks.constructEvent(
req.body, req.body,
sig, sig,
await getStripeWebhookSecret() await getStripeWebhookSecret()
); );
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
error: 'Failed to process webhook'
});
}
switch (event.type) { switch (event.type) {
case '': case '':
@@ -1,5 +1,4 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import * as Sentry from "@sentry/node";
import { PipelineStage, Types } from "mongoose"; import { PipelineStage, Types } from "mongoose";
import { Secret } from "../../../models"; import { Secret } from "../../../models";
import { import {
@@ -69,15 +68,13 @@ export const getWorkspaceSecretSnapshots = async (
} }
} }
*/ */
let secretSnapshots;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
const { environment, folderId } = req.query; const { environment, folderId } = req.query;
const offset: number = parseInt(req.query.offset as string); const offset: number = parseInt(req.query.offset as string);
const limit: number = parseInt(req.query.limit as string); const limit: number = parseInt(req.query.limit as string);
secretSnapshots = await SecretSnapshot.find({ const secretSnapshots = await SecretSnapshot.find({
workspace: workspaceId, workspace: workspaceId,
environment, environment,
folderId: folderId || "root", folderId: folderId || "root",
@@ -85,13 +82,6 @@ export const getWorkspaceSecretSnapshots = async (
.sort({ createdAt: -1 }) .sort({ createdAt: -1 })
.skip(offset) .skip(offset)
.limit(limit); .limit(limit);
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get secret snapshots",
});
}
return res.status(200).send({ return res.status(200).send({
secretSnapshots, secretSnapshots,
@@ -107,23 +97,14 @@ export const getWorkspaceSecretSnapshotsCount = async (
req: Request, req: Request,
res: Response res: Response
) => { ) => {
let count;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
const { environment, folderId } = req.query; const { environment, folderId } = req.query;
count = await SecretSnapshot.countDocuments({ const count = await SecretSnapshot.countDocuments({
workspace: workspaceId, workspace: workspaceId,
environment, environment,
folderId: folderId || "root", folderId: folderId || "root",
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to count number of secret snapshots",
});
}
return res.status(200).send({ return res.status(200).send({
count, count,
@@ -191,8 +172,6 @@ export const rollbackWorkspaceSecretSnapshot = async (
} }
*/ */
let secrets;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
const { version, environment, folderId = "root" } = req.body; const { version, environment, folderId = "root" } = req.body;
@@ -376,7 +355,7 @@ export const rollbackWorkspaceSecretSnapshot = async (
}); });
// add secrets // add secrets
secrets = await Secret.insertMany( const secrets = await Secret.insertMany(
Object.keys(oldSecretVersionsObj).map((sv) => { Object.keys(oldSecretVersionsObj).map((sv) => {
const { const {
secret: secretId, secret: secretId,
@@ -501,13 +480,6 @@ export const rollbackWorkspaceSecretSnapshot = async (
environment, environment,
folderId, folderId,
}); });
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to roll back secret snapshot",
});
}
return res.status(200).send({ return res.status(200).send({
secrets, secrets,
@@ -587,8 +559,6 @@ export const getWorkspaceLogs = async (req: Request, res: Response) => {
} }
} }
*/ */
let logs;
try {
const { workspaceId } = req.params; const { workspaceId } = req.params;
const offset: number = parseInt(req.query.offset as string); const offset: number = parseInt(req.query.offset as string);
@@ -597,7 +567,7 @@ export const getWorkspaceLogs = async (req: Request, res: Response) => {
const userId: string = req.query.userId as string; const userId: string = req.query.userId as string;
const actionNames: string = req.query.actionNames as string; const actionNames: string = req.query.actionNames as string;
logs = await Log.find({ const logs = await Log.find({
workspace: workspaceId, workspace: workspaceId,
...(userId ? { user: userId } : {}), ...(userId ? { user: userId } : {}),
...(actionNames ...(actionNames
@@ -613,13 +583,6 @@ export const getWorkspaceLogs = async (req: Request, res: Response) => {
.limit(limit) .limit(limit)
.populate("actions") .populate("actions")
.populate("user serviceAccount serviceTokenData"); .populate("user serviceAccount serviceTokenData");
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get workspace logs",
});
}
return res.status(200).send({ return res.status(200).send({
logs, logs,
+6
View File
@@ -27,6 +27,7 @@ export interface ISecretVersion {
keyEncoding: "utf8" | "base64"; keyEncoding: "utf8" | "base64";
createdAt: string; createdAt: string;
folder?: string; folder?: string;
tags?: string[];
} }
const secretVersionSchema = new Schema<ISecretVersion>( const secretVersionSchema = new Schema<ISecretVersion>(
@@ -112,6 +113,11 @@ const secretVersionSchema = new Schema<ISecretVersion>(
type: String, type: String,
required: true, required: true,
}, },
tags: {
ref: 'Tag',
type: [Schema.Types.ObjectId],
default: []
},
}, },
{ {
timestamps: true, timestamps: true,
@@ -1,5 +1,4 @@
import NodeCache from 'node-cache'; import NodeCache from 'node-cache';
import * as Sentry from '@sentry/node';
import { import {
getLicenseKey, getLicenseKey,
getLicenseServerKey, getLicenseServerKey,
@@ -98,7 +97,6 @@ class EELicenseService {
const licenseServerKey = await getLicenseServerKey(); const licenseServerKey = await getLicenseServerKey();
const licenseKey = await getLicenseKey(); const licenseKey = await getLicenseKey();
try {
if (licenseServerKey) { if (licenseServerKey) {
// license server key is present -> validate it // license server key is present -> validate it
const token = await refreshLicenseServerKeyToken() const token = await refreshLicenseServerKeyToken()
@@ -123,11 +121,6 @@ class EELicenseService {
this.instanceType = 'enterprise-self-hosted'; this.instanceType = 'enterprise-self-hosted';
} }
} }
} catch (err) {
// case: self-hosted free
Sentry.setUser(null);
Sentry.captureException(err);
}
} }
public get isLicenseValid(): boolean { public get isLicenseValid(): boolean {
+5 -57
View File
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import { import {
Bot, Bot,
@@ -16,7 +15,6 @@ import {
import { import {
UnauthorizedRequestError, UnauthorizedRequestError,
} from '../utils/errors'; } from '../utils/errors';
import RequestError from '../utils/requestError';
interface Update { interface Update {
workspace: string; workspace: string;
@@ -48,8 +46,6 @@ export const handleOAuthExchangeHelper = async ({
code: string; code: string;
environment: string; environment: string;
}) => { }) => {
let integrationAuth;
try {
const bot = await Bot.findOne({ const bot = await Bot.findOne({
workspace: workspaceId, workspace: workspaceId,
isActive: true isActive: true
@@ -77,7 +73,7 @@ export const handleOAuthExchangeHelper = async ({
break; break;
} }
integrationAuth = await IntegrationAuth.findOneAndUpdate({ const integrationAuth = await IntegrationAuth.findOneAndUpdate({
workspace: workspaceId, workspace: workspaceId,
integration integration
}, update, { }, update, {
@@ -104,11 +100,6 @@ export const handleOAuthExchangeHelper = async ({
accessExpiresAt: res.accessExpiresAt accessExpiresAt: res.accessExpiresAt
}); });
} }
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to handle OAuth2 code-token exchange')
}
return integrationAuth; return integrationAuth;
} }
@@ -125,9 +116,7 @@ export const syncIntegrationsHelper = async ({
workspaceId: Types.ObjectId; workspaceId: Types.ObjectId;
environment?: string; environment?: string;
}) => { }) => {
let integrations; const integrations = await Integration.find({
try {
integrations = await Integration.find({
workspace: workspaceId, workspace: workspaceId,
...(environment ? { ...(environment ? {
environment environment
@@ -162,11 +151,6 @@ export const syncIntegrationsHelper = async ({
accessToken: access.accessToken accessToken: access.accessToken
}); });
} }
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to sync secrets to integrations');
}
} }
/** /**
@@ -178,31 +162,19 @@ export const syncIntegrationsHelper = async ({
* @param {String} refreshToken - decrypted refresh token * @param {String} refreshToken - decrypted refresh token
*/ */
export const getIntegrationAuthRefreshHelper = async ({ integrationAuthId }: { integrationAuthId: Types.ObjectId }) => { export const getIntegrationAuthRefreshHelper = async ({ integrationAuthId }: { integrationAuthId: Types.ObjectId }) => {
let refreshToken;
try {
const integrationAuth = await IntegrationAuth const integrationAuth = await IntegrationAuth
.findById(integrationAuthId) .findById(integrationAuthId)
.select('+refreshCiphertext +refreshIV +refreshTag'); .select('+refreshCiphertext +refreshIV +refreshTag');
if (!integrationAuth) throw UnauthorizedRequestError({message: 'Failed to locate Integration Authentication credentials'}); if (!integrationAuth) throw UnauthorizedRequestError({message: 'Failed to locate Integration Authentication credentials'});
refreshToken = await BotService.decryptSymmetric({ const refreshToken = await BotService.decryptSymmetric({
workspaceId: integrationAuth.workspace, workspaceId: integrationAuth.workspace,
ciphertext: integrationAuth.refreshCiphertext as string, ciphertext: integrationAuth.refreshCiphertext as string,
iv: integrationAuth.refreshIV as string, iv: integrationAuth.refreshIV as string,
tag: integrationAuth.refreshTag as string tag: integrationAuth.refreshTag as string
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
if(err instanceof RequestError)
throw err
else
throw new Error('Failed to get integration refresh token');
}
return refreshToken; return refreshToken;
} }
@@ -217,7 +189,6 @@ export const getIntegrationAuthRefreshHelper = async ({ integrationAuthId }: { i
export const getIntegrationAuthAccessHelper = async ({ integrationAuthId }: { integrationAuthId: Types.ObjectId }) => { export const getIntegrationAuthAccessHelper = async ({ integrationAuthId }: { integrationAuthId: Types.ObjectId }) => {
let accessId; let accessId;
let accessToken; let accessToken;
try {
const integrationAuth = await IntegrationAuth const integrationAuth = await IntegrationAuth
.findById(integrationAuthId) .findById(integrationAuthId)
.select('workspace integration +accessCiphertext +accessIV +accessTag +accessExpiresAt + refreshCiphertext +accessIdCiphertext +accessIdIV +accessIdTag'); .select('workspace integration +accessCiphertext +accessIV +accessTag +accessExpiresAt + refreshCiphertext +accessIdCiphertext +accessIdIV +accessIdTag');
@@ -254,15 +225,6 @@ export const getIntegrationAuthAccessHelper = async ({ integrationAuthId }: { in
}); });
} }
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
if(err instanceof RequestError)
throw err
else
throw new Error('Failed to get integration access token');
}
return ({ return ({
accessId, accessId,
accessToken accessToken
@@ -285,9 +247,7 @@ export const setIntegrationAuthRefreshHelper = async ({
refreshToken: string; refreshToken: string;
}) => { }) => {
let integrationAuth; let integrationAuth = await IntegrationAuth
try {
integrationAuth = await IntegrationAuth
.findById(integrationAuthId); .findById(integrationAuthId);
if (!integrationAuth) throw new Error('Failed to find integration auth'); if (!integrationAuth) throw new Error('Failed to find integration auth');
@@ -308,11 +268,6 @@ export const setIntegrationAuthRefreshHelper = async ({
}, { }, {
new: true new: true
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to set integration auth refresh token');
}
return integrationAuth; return integrationAuth;
} }
@@ -337,9 +292,7 @@ export const setIntegrationAuthAccessHelper = async ({
accessToken: string; accessToken: string;
accessExpiresAt: Date | undefined; accessExpiresAt: Date | undefined;
}) => { }) => {
let integrationAuth; let integrationAuth = await IntegrationAuth.findById(integrationAuthId);
try {
integrationAuth = await IntegrationAuth.findById(integrationAuthId);
if (!integrationAuth) throw new Error('Failed to find integration auth'); if (!integrationAuth) throw new Error('Failed to find integration auth');
@@ -371,11 +324,6 @@ export const setIntegrationAuthAccessHelper = async ({
}, { }, {
new: true new: true
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to save integration auth access token');
}
return integrationAuth; return integrationAuth;
} }
+9 -32
View File
@@ -1,7 +1,6 @@
import * as Sentry from '@sentry/node'; import { Types } from "mongoose";
import { Types } from 'mongoose'; import { Membership, Key } from "../models";
import { Membership, Key } from '../models'; import { MembershipNotFoundError, BadRequestError } from "../utils/errors";
import { MembershipNotFoundError, BadRequestError } from '../utils/errors';
/** /**
* Validate that user with id [userId] is a member of workspace with id [workspaceId] * Validate that user with id [userId] is a member of workspace with id [workspaceId]
@@ -18,23 +17,23 @@ export const validateMembership = async ({
}: { }: {
userId: Types.ObjectId | string; userId: Types.ObjectId | string;
workspaceId: Types.ObjectId | string; workspaceId: Types.ObjectId | string;
acceptedRoles?: Array<'admin' | 'member'>; acceptedRoles?: Array<"admin" | "member">;
}) => { }) => {
const membership = await Membership.findOne({ const membership = await Membership.findOne({
user: userId, user: userId,
workspace: workspaceId, workspace: workspaceId,
}).populate('workspace'); }).populate("workspace");
if (!membership) { if (!membership) {
throw MembershipNotFoundError({ throw MembershipNotFoundError({
message: 'Failed to find workspace membership', message: "Failed to find workspace membership",
}); });
} }
if (acceptedRoles) { if (acceptedRoles) {
if (!acceptedRoles.includes(membership.role)) { if (!acceptedRoles.includes(membership.role)) {
throw BadRequestError({ throw BadRequestError({
message: 'Failed authorization for membership role', message: "Failed authorization for membership role",
}); });
} }
} }
@@ -48,15 +47,7 @@ export const validateMembership = async ({
* @return {Object} membership - membership * @return {Object} membership - membership
*/ */
export const findMembership = async (queryObj: any) => { export const findMembership = async (queryObj: any) => {
let membership; const membership = await Membership.findOne(queryObj);
try {
membership = await Membership.findOne(queryObj);
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to find membership');
}
return membership; return membership;
}; };
@@ -77,7 +68,6 @@ export const addMemberships = async ({
workspaceId: string; workspaceId: string;
roles: string[]; roles: string[];
}): Promise<void> => { }): Promise<void> => {
try {
const operations = userIds.map((userId, idx) => { const operations = userIds.map((userId, idx) => {
return { return {
updateOne: { updateOne: {
@@ -95,13 +85,7 @@ export const addMemberships = async ({
}, },
}; };
}); });
await Membership.bulkWrite(operations as any); await Membership.bulkWrite(operations as any);
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to add users to workspace');
}
}; };
/** /**
@@ -110,9 +94,7 @@ export const addMemberships = async ({
* @param {String} obj.membershipId - id of membership to delete * @param {String} obj.membershipId - id of membership to delete
*/ */
export const deleteMembership = async ({ membershipId }: { membershipId: string }) => { export const deleteMembership = async ({ membershipId }: { membershipId: string }) => {
let deletedMembership; const deletedMembership = await Membership.findOneAndDelete({
try {
deletedMembership = await Membership.findOneAndDelete({
_id: membershipId _id: membershipId
}); });
@@ -123,11 +105,6 @@ export const deleteMembership = async ({ membershipId }: { membershipId: string
receiver: deletedMembership.user, receiver: deletedMembership.user,
workspace: deletedMembership.workspace, workspace: deletedMembership.workspace,
}); });
}
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to delete membership');
} }
return deletedMembership; return deletedMembership;
+1 -8
View File
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import handlebars from 'handlebars'; import handlebars from 'handlebars';
@@ -26,7 +25,6 @@ export const sendMail = async ({
substitutions: any; substitutions: any;
}) => { }) => {
if (await getSmtpConfigured()) { if (await getSmtpConfigured()) {
try {
const html = fs.readFileSync( const html = fs.readFileSync(
path.resolve(__dirname, '../templates/' + template), path.resolve(__dirname, '../templates/' + template),
'utf8' 'utf8'
@@ -34,17 +32,12 @@ export const sendMail = async ({
const temp = handlebars.compile(html); const temp = handlebars.compile(html);
const htmlToSend = temp(substitutions); const htmlToSend = temp(substitutions);
const x = await smtpTransporter.sendMail({ await smtpTransporter.sendMail({
from: `"${await getSmtpFromName()}" <${await getSmtpFromAddress()}>`, from: `"${await getSmtpFromName()}" <${await getSmtpFromAddress()}>`,
to: recipients.join(', '), to: recipients.join(', '),
subject: subjectLine, subject: subjectLine,
html: htmlToSend html: htmlToSend
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
}
} }
}; };
+33 -3
View File
@@ -185,18 +185,43 @@ export const generateSecretBlindIndexHelper = async ({
workspaceId: Types.ObjectId; workspaceId: Types.ObjectId;
}) => { }) => {
// check if workspace blind index data exists // check if workspace blind index data exists
const encryptionKey = await getEncryptionKey();
const rootEncryptionKey = await getRootEncryptionKey();
const secretBlindIndexData = await SecretBlindIndexData.findOne({ const secretBlindIndexData = await SecretBlindIndexData.findOne({
workspace: workspaceId, workspace: workspaceId,
}); }).select('+algorithm +keyEncoding');
if (!secretBlindIndexData) throw SecretBlindIndexDataNotFoundError(); if (!secretBlindIndexData) throw SecretBlindIndexDataNotFoundError();
let salt;
if (
rootEncryptionKey &&
secretBlindIndexData.keyEncoding === ENCODING_SCHEME_BASE64
) {
salt = client.decryptSymmetric(
secretBlindIndexData.encryptedSaltCiphertext,
rootEncryptionKey,
secretBlindIndexData.saltIV,
secretBlindIndexData.saltTag
);
const secretBlindIndex = await generateSecretBlindIndexWithSaltHelper({
secretName,
salt,
});
return secretBlindIndex;
} else if (
encryptionKey &&
secretBlindIndexData.keyEncoding === ENCODING_SCHEME_UTF8
) {
// decrypt workspace salt // decrypt workspace salt
const salt = decryptSymmetric128BitHexKeyUTF8({ salt = decryptSymmetric128BitHexKeyUTF8({
ciphertext: secretBlindIndexData.encryptedSaltCiphertext, ciphertext: secretBlindIndexData.encryptedSaltCiphertext,
iv: secretBlindIndexData.saltIV, iv: secretBlindIndexData.saltIV,
tag: secretBlindIndexData.saltTag, tag: secretBlindIndexData.saltTag,
key: await getEncryptionKey(), key: encryptionKey,
}); });
const secretBlindIndex = await generateSecretBlindIndexWithSaltHelper({ const secretBlindIndex = await generateSecretBlindIndexWithSaltHelper({
@@ -205,6 +230,11 @@ export const generateSecretBlindIndexHelper = async ({
}); });
return secretBlindIndex; return secretBlindIndex;
}
throw InternalServerError({
message: 'Failed to generate secret blind index'
});
}; };
/** /**
-15
View File
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import { IUser } from '../models'; import { IUser } from '../models';
import { createOrganization } from './organization'; import { createOrganization } from './organization';
import { addMembershipsOrg } from './membershipOrg'; import { addMembershipsOrg } from './membershipOrg';
@@ -15,7 +14,6 @@ import { TOKEN_EMAIL_CONFIRMATION } from '../variables';
* @returns {Boolean} success - whether or not operation was successful * @returns {Boolean} success - whether or not operation was successful
*/ */
export const sendEmailVerification = async ({ email }: { email: string }) => { export const sendEmailVerification = async ({ email }: { email: string }) => {
try {
const token = await TokenService.createToken({ const token = await TokenService.createToken({
type: TOKEN_EMAIL_CONFIRMATION, type: TOKEN_EMAIL_CONFIRMATION,
email email
@@ -30,13 +28,6 @@ export const sendEmailVerification = async ({ email }: { email: string }) => {
code: token code: token
} }
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error(
"Ouch. We weren't able to send your email verification code"
);
}
}; };
/** /**
@@ -52,17 +43,11 @@ export const checkEmailVerification = async ({
email: string; email: string;
code: string; code: string;
}) => { }) => {
try {
await TokenService.validateToken({ await TokenService.validateToken({
type: TOKEN_EMAIL_CONFIRMATION, type: TOKEN_EMAIL_CONFIRMATION,
email, email,
token: code token: code
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error("Oops. We weren't able to verify");
}
}; };
/** /**
+1 -15
View File
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import { import {
Workspace, Workspace,
Bot, Bot,
@@ -23,10 +22,8 @@ export const createWorkspace = async ({
name: string; name: string;
organizationId: string; organizationId: string;
}) => { }) => {
let workspace;
try {
// create workspace // create workspace
workspace = await new Workspace({ const workspace = await new Workspace({
name, name,
organization: organizationId, organization: organizationId,
autoCapitalization: true autoCapitalization: true
@@ -43,11 +40,6 @@ export const createWorkspace = async ({
workspaceId: workspace._id workspaceId: workspace._id
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to create workspace');
}
return workspace; return workspace;
}; };
@@ -59,7 +51,6 @@ export const createWorkspace = async ({
* @param {String} obj.id - id of workspace to delete * @param {String} obj.id - id of workspace to delete
*/ */
export const deleteWorkspace = async ({ id }: { id: string }) => { export const deleteWorkspace = async ({ id }: { id: string }) => {
try {
await Workspace.deleteOne({ _id: id }); await Workspace.deleteOne({ _id: id });
await Bot.deleteOne({ await Bot.deleteOne({
workspace: id workspace: id
@@ -73,9 +64,4 @@ export const deleteWorkspace = async ({ id }: { id: string }) => {
await Key.deleteMany({ await Key.deleteMany({
workspace: id workspace: id
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to delete workspace');
}
}; };
-100
View File
@@ -1,4 +1,3 @@
import * as Sentry from "@sentry/node";
import _ from 'lodash'; import _ from 'lodash';
import AWS from 'aws-sdk'; import AWS from 'aws-sdk';
import { import {
@@ -61,7 +60,6 @@ const syncSecrets = async ({
accessId: string | null; accessId: string | null;
accessToken: string; accessToken: string;
}) => { }) => {
try {
switch (integration.integration) { switch (integration.integration) {
case INTEGRATION_AZURE_KEY_VAULT: case INTEGRATION_AZURE_KEY_VAULT:
await syncSecretsAzureKeyVault({ await syncSecretsAzureKeyVault({
@@ -166,11 +164,6 @@ const syncSecrets = async ({
}); });
break; break;
} }
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to sync secrets to integration');
}
}; };
/** /**
@@ -189,7 +182,6 @@ const syncSecretsAzureKeyVault = async ({
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
try {
interface GetAzureKeyVaultSecret { interface GetAzureKeyVaultSecret {
id: string; // secret URI id: string; // secret URI
attributes: { attributes: {
@@ -212,7 +204,6 @@ const syncSecretsAzureKeyVault = async ({
*/ */
const paginateAzureKeyVaultSecrets = async (url: string) => { const paginateAzureKeyVaultSecrets = async (url: string) => {
let result: GetAzureKeyVaultSecret[] = []; let result: GetAzureKeyVaultSecret[] = [];
try {
while (url) { while (url) {
const res = await standardRequest.get(url, { const res = await standardRequest.get(url, {
headers: { headers: {
@@ -225,11 +216,6 @@ const syncSecretsAzureKeyVault = async ({
url = res.data.nextLink; url = res.data.nextLink;
} }
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
}
return result; return result;
} }
@@ -360,11 +346,6 @@ const syncSecretsAzureKeyVault = async ({
} }
}); });
} }
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to sync secrets to Azure Key Vault');
}
}; };
/** /**
@@ -386,7 +367,6 @@ const syncSecretsAWSParameterStore = async ({
accessId: string | null; accessId: string | null;
accessToken: string; accessToken: string;
}) => { }) => {
try {
if (!accessId) return; if (!accessId) return;
AWS.config.update({ AWS.config.update({
@@ -462,11 +442,6 @@ const syncSecretsAWSParameterStore = async ({
accessKeyId: undefined, accessKeyId: undefined,
secretAccessKey: undefined secretAccessKey: undefined
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to sync secrets to AWS Parameter Store');
}
} }
/** /**
@@ -536,10 +511,6 @@ const syncSecretsAWSSecretManager = async ({
Name: integration.app, Name: integration.app,
SecretString: JSON.stringify(secrets) SecretString: JSON.stringify(secrets)
})); }));
} else {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to sync secrets to AWS Secret Manager');
} }
AWS.config.update({ AWS.config.update({
region: undefined, region: undefined,
@@ -565,7 +536,6 @@ const syncSecretsHeroku = async ({
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
try {
const herokuSecrets = ( const herokuSecrets = (
await standardRequest.get( await standardRequest.get(
`${INTEGRATION_HEROKU_API_URL}/apps/${integration.app}/config-vars`, `${INTEGRATION_HEROKU_API_URL}/apps/${integration.app}/config-vars`,
@@ -596,11 +566,6 @@ const syncSecretsHeroku = async ({
}, },
} }
); );
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error("Failed to sync secrets to Heroku");
}
}; };
/** /**
@@ -628,8 +593,6 @@ const syncSecretsVercel = async ({
target: string[]; target: string[];
gitBranch?: string; gitBranch?: string;
} }
try {
// Get all (decrypted) secrets back from Vercel in // Get all (decrypted) secrets back from Vercel in
// decrypted format // decrypted format
const params: { [key: string]: string } = { const params: { [key: string]: string } = {
@@ -788,11 +751,6 @@ const syncSecretsVercel = async ({
} }
); );
} }
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error("Failed to sync secrets to Vercel");
}
}; };
/** /**
@@ -814,7 +772,6 @@ const syncSecretsNetlify = async ({
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
try {
interface NetlifyValue { interface NetlifyValue {
id?: string; id?: string;
context: string; // 'dev' | 'branch-deploy' | 'deploy-preview' | 'production', context: string; // 'dev' | 'branch-deploy' | 'deploy-preview' | 'production',
@@ -1011,11 +968,6 @@ const syncSecretsNetlify = async ({
); );
}); });
} }
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error("Failed to sync secrets to Heroku");
}
}; };
/** /**
@@ -1035,7 +987,6 @@ const syncSecretsGitHub = async ({
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
try {
interface GitHubRepoKey { interface GitHubRepoKey {
key_id: string; key_id: string;
key: string; key: string;
@@ -1126,11 +1077,6 @@ const syncSecretsGitHub = async ({
); );
}); });
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error("Failed to sync secrets to GitHub");
}
}; };
/** /**
@@ -1149,7 +1095,6 @@ const syncSecretsRender = async ({
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
try {
await standardRequest.put( await standardRequest.put(
`${INTEGRATION_RENDER_API_URL}/v1/services/${integration.appId}/env-vars`, `${INTEGRATION_RENDER_API_URL}/v1/services/${integration.appId}/env-vars`,
Object.keys(secrets).map((key) => ({ Object.keys(secrets).map((key) => ({
@@ -1163,11 +1108,6 @@ const syncSecretsRender = async ({
}, },
} }
); );
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error("Failed to sync secrets to Render");
}
}; };
/** /**
@@ -1186,8 +1126,6 @@ const syncSecretsRailway = async ({
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
try {
const query = ` const query = `
mutation UpsertVariables($input: VariableCollectionUpsertInput!) { mutation UpsertVariables($input: VariableCollectionUpsertInput!) {
variableCollectionUpsert(input: $input) variableCollectionUpsert(input: $input)
@@ -1214,12 +1152,6 @@ const syncSecretsRailway = async ({
'Accept-Encoding': 'application/json' 'Accept-Encoding': 'application/json'
}, },
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error("Failed to sync secrets to Railway");
}
} }
/** /**
@@ -1238,7 +1170,6 @@ const syncSecretsFlyio = async ({
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
try {
// set secrets // set secrets
const SetSecrets = ` const SetSecrets = `
mutation($input: SetSecretsInput!) { mutation($input: SetSecretsInput!) {
@@ -1346,12 +1277,6 @@ const syncSecretsFlyio = async ({
'Accept-Encoding': 'application/json', 'Accept-Encoding': 'application/json',
}, },
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error("Failed to sync secrets to Fly.io");
}
}; };
/** /**
@@ -1370,7 +1295,6 @@ const syncSecretsCircleCI = async ({
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
try {
const circleciOrganizationDetail = ( const circleciOrganizationDetail = (
await standardRequest.get(`${INTEGRATION_CIRCLECI_API_URL}/v2/me/collaborations`, { await standardRequest.get(`${INTEGRATION_CIRCLECI_API_URL}/v2/me/collaborations`, {
headers: { headers: {
@@ -1427,11 +1351,6 @@ const syncSecretsCircleCI = async ({
); );
} }
}); });
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error("Failed to sync secrets to CircleCI");
}
}; };
/** /**
@@ -1450,7 +1369,6 @@ const syncSecretsTravisCI = async ({
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
try {
// get secrets from travis-ci // get secrets from travis-ci
const getSecretsRes = ( const getSecretsRes = (
await standardRequest.get( await standardRequest.get(
@@ -1528,11 +1446,6 @@ const syncSecretsTravisCI = async ({
); );
} }
} }
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error("Failed to sync secrets to GitLab");
}
} }
/** /**
@@ -1552,7 +1465,6 @@ const syncSecretsGitLab = async ({
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
try {
interface GitLabSecret { interface GitLabSecret {
key: string; key: string;
value: string; value: string;
@@ -1646,12 +1558,6 @@ const syncSecretsGitLab = async ({
); );
} }
} }
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error("Failed to sync secrets to GitLab");
}
} }
/** /**
@@ -1671,7 +1577,6 @@ const syncSecretsSupabase = async ({
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
try {
const { data: getSecretsRes } = await standardRequest.get( const { data: getSecretsRes } = await standardRequest.get(
`${INTEGRATION_SUPABASE_API_URL}/v1/projects/${integration.appId}/secrets`, `${INTEGRATION_SUPABASE_API_URL}/v1/projects/${integration.appId}/secrets`,
{ {
@@ -1721,11 +1626,6 @@ const syncSecretsSupabase = async ({
data: secretsToDelete data: secretsToDelete
} }
); );
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to sync secrets to Supabase');
}
}; };
+1
View File
@@ -43,4 +43,5 @@ export interface BatchSecret {
secretCommentIV: string; secretCommentIV: string;
secretCommentTag: string; secretCommentTag: string;
tags: string[]; tags: string[];
folder: string
} }
+33 -3
View File
@@ -335,6 +335,33 @@ export const backfillSecretFolders = async () => {
} }
); );
await SecretVersion.updateMany(
{
folder: {
$exists: false,
},
},
{
$set: {
folder: "root",
},
}
);
// Back fill because tags were missing in secret versions
await SecretVersion.updateMany(
{
tags: {
$exists: false,
},
},
{
$set: {
tags: [],
},
}
);
let secretSnapshots = await SecretSnapshot.find({ let secretSnapshots = await SecretSnapshot.find({
environment: { environment: {
$exists: false, $exists: false,
@@ -352,12 +379,15 @@ export const backfillSecretFolders = async () => {
groupSnapByEnv[secVer.environment].push(secVer); groupSnapByEnv[secVer.environment].push(secVer);
}); });
const newSnapshots = Object.keys(groupSnapByEnv).map((snapEnv) => ({ const newSnapshots = Object.keys(groupSnapByEnv).map((snapEnv) => {
const secretIdsOfEnvGroup = groupSnapByEnv[snapEnv] ? groupSnapByEnv[snapEnv].map(secretVersion => secretVersion._id) : []
return {
...secSnapshot.toObject({ virtuals: false }), ...secSnapshot.toObject({ virtuals: false }),
_id: new Types.ObjectId(), _id: new Types.ObjectId(),
environment: snapEnv, environment: snapEnv,
secretVersions: groupSnapByEnv[snapEnv], secretVersions: secretIdsOfEnvGroup,
})); }
});
await SecretSnapshot.insertMany(newSnapshots); await SecretSnapshot.insertMany(newSnapshots);
await secSnapshot.delete(); await secSnapshot.delete();
+11 -11
View File
@@ -29,20 +29,20 @@ export const validateEncryptionKeysConfig = async () => {
message: "Failed to find required root encryption key environment variable. Please make sure that you're passing in a ROOT_ENCRYPTION_KEY environment variable." message: "Failed to find required root encryption key environment variable. Please make sure that you're passing in a ROOT_ENCRYPTION_KEY environment variable."
}); });
if (encryptionKey && encryptionKey !== '') { // if (encryptionKey && encryptionKey !== '') {
// validate [encryptionKey] // // validate [encryptionKey]
const keyBuffer = Buffer.from(encryptionKey, 'hex'); // const keyBuffer = Buffer.from(encryptionKey, 'hex');
const decoded = keyBuffer.toString('hex'); // const decoded = keyBuffer.toString('hex');
if (decoded !== encryptionKey) throw InternalServerError({ // if (decoded !== encryptionKey) throw InternalServerError({
message: 'Failed to validate that the encryption key is correctly encoded in hex.' // message: 'Failed to validate that the encryption key is correctly encoded in hex.'
}); // });
if (keyBuffer.length !== 16) throw InternalServerError({ // if (keyBuffer.length !== 16) throw InternalServerError({
message: 'Failed to validate that the encryption key is a 128-bit hex string.' // message: 'Failed to validate that the encryption key is a 128-bit hex string.'
}); // });
} // }
if (rootEncryptionKey && rootEncryptionKey !== '') { if (rootEncryptionKey && rootEncryptionKey !== '') {
// validate [rootEncryptionKey] // validate [rootEncryptionKey]
-1
View File
@@ -51,7 +51,6 @@ export const validateClientForWorkspace = async ({
requiredPermissions?: string[]; requiredPermissions?: string[];
requireBlindIndicesEnabled: boolean; requireBlindIndicesEnabled: boolean;
}) => { }) => {
const workspace = await Workspace.findById(workspaceId); const workspace = await Workspace.findById(workspaceId);
if (!workspace) throw WorkspaceNotFoundError({ if (!workspace) throw WorkspaceNotFoundError({
-6
View File
@@ -121,12 +121,6 @@
{ {
"group": "Self-host Infisical", "group": "Self-host Infisical",
"pages": [ "pages": [
{
"group": "Authentication",
"pages": [
"self-hosting/authentication/google"
]
},
{ {
"group": "Deployment options", "group": "Deployment options",
"pages": [ "pages": [
+2 -4
View File
@@ -3,17 +3,15 @@ title: "Configure email service"
description: "How to configure your email when self-hosting Infisical." description: "How to configure your email when self-hosting Infisical."
--- ---
Infisical requires you to configure your own SMTP server for certain functionality like: By default, the core functions of Infisical work without any email service configuration. Without email service, the following functionality will be deactivated.
- Sending email confirmation links to sign up. - Sending email confirmation links to sign up.
- Sending invite links for projects. - Sending invite links for projects.
- Sending alerts. - Sending alerts.
We strongly recommend using an email service to act as your email server and provide examples for common providers.
## General configuration ## General configuration
By default, you need to configure the following SMTP [environment variables](https://infisical.com/docs/self-hosting/configuration/envars): If you choose to setup email service, yuu need to configure the following SMTP [environment variables](https://infisical.com/docs/self-hosting/configuration/envars):
- `SMTP_HOST`: Hostname to connect to for establishing SMTP connections. - `SMTP_HOST`: Hostname to connect to for establishing SMTP connections.
- `SMTP_USERNAME`: Credential to connect to host (e.g. [email protected]) - `SMTP_USERNAME`: Credential to connect to host (e.g. [email protected])
@@ -1,19 +1,65 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Link from 'next/link'; import Link from 'next/link';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import attemptLogin from '@app/components/utilities/attemptLogin';
import Error from '../basic/Error';
// import { faGoogle } from '@fortawesome/free-brands-svg-icons'; // import { faGoogle } from '@fortawesome/free-brands-svg-icons';
// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; // import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button } from '../v2'; import { Button, Input } from '../v2';
export default function InitialLoginStep({ export default function InitialLoginStep({
setIsLoginWithEmail, setStep,
email,
setEmail,
password,
setPassword,
}: { }: {
setIsLoginWithEmail: (value: boolean) => void; setStep: (step: number) => void;
email: string;
setEmail: (email: string) => void;
password: string;
setPassword: (password: string) => void;
}) { }) {
const router = useRouter(); const router = useRouter();
const { t } = useTranslation(); const { t } = useTranslation();
const [isLoading, setIsLoading] = useState(false);
const [loginError, setLoginError] = useState(false);
const handleLogin = async () => {
try {
if (!email || !password) {
return;
}
setIsLoading(true);
const isLoginSuccessful = await attemptLogin({
email,
password,
});
if (isLoginSuccessful && isLoginSuccessful.success) {
// case: login was successful
if (isLoginSuccessful.mfaEnabled) {
// case: login requires MFA step
setStep(2);
setIsLoading(false);
return;
}
// case: login does not require MFA step
router.push(`/dashboard/${localStorage.getItem('projectData.id')}`);
}
} catch (err) {
setLoginError(true);
}
setIsLoading(false);
}
return <div className='flex flex-col mx-auto w-full justify-center items-center'> return <div className='flex flex-col mx-auto w-full justify-center items-center'>
<h1 className='text-xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center mb-8' >Login to Infisical</h1> <h1 className='text-xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center mb-8' >Login to Infisical</h1>
@@ -30,18 +76,49 @@ export default function InitialLoginStep({
{t('login.continue-with-google')} {t('login.continue-with-google')}
</Button> </Button>
</div> */} </div> */}
<div className='lg:w-1/6 w-1/4 min-w-[20rem] text-center rounded-md'> <div className="relative md:px-1.5 flex items-center justify-center lg:w-1/6 w-1/4 min-w-[20rem] md:min-w-[22rem] mx-auto w-full rounded-lg max-h-24 md:max-h-28">
<div className="flex items-center justify-center w-full md:px-2 md:py-1 rounded-lg max-h-24 md:max-h-28">
<Input
value={email}
onChange={(e) => setEmail(e.target.value)}
type="email"
placeholder="Enter your email..."
isRequired
autoComplete="username"
className="h-12"
/>
</div>
</div>
<div className="relative pt-2 md:pt-0 md:px-1.5 flex items-center justify-center lg:w-1/6 w-1/4 min-w-[20rem] md:min-w-[22rem] mx-auto w-full rounded-lg max-h-24 md:max-h-28">
<div className="flex items-center justify-center w-full md:p-2 rounded-lg max-h-24 md:max-h-28">
<Input
value={password}
onChange={(e) => setPassword(e.target.value)}
type="password"
placeholder="Enter your password..."
isRequired
autoComplete="current-password"
id="current-password"
className="h-12 select:-webkit-autofill:focus"
/>
</div>
</div>
{!isLoading && loginError && <Error text={t('login.error-login') ?? ''} />}
<div className='lg:w-1/6 w-1/4 min-w-[21.2rem] md:min-w-[20.1rem] text-center rounded-md mt-4'>
<Button <Button
onClick={async () => handleLogin()}
size="sm"
isFullWidth
className='h-12'
colorSchema="primary" colorSchema="primary"
variant="solid" variant="solid"
onClick={() => { isLoading={isLoading}
setIsLoginWithEmail(true); > Login </Button>
}} </div>
isFullWidth <div className='lg:w-1/6 w-1/4 min-w-[20rem] flex flex-row items-center mt-4 py-2'>
className="h-14 w-full mx-0" <div className='w-1/2 border-t border-mineshaft-500'/>
> <span className='px-4 text-sm text-bunker-400'>or</span>
{t('login.continue-with-email')} <div className='w-1/2 border-t border-mineshaft-500'/>
</Button>
</div> </div>
<div className='lg:w-1/6 w-1/4 min-w-[20rem] text-center rounded-md mt-4'> <div className='lg:w-1/6 w-1/4 min-w-[20rem] text-center rounded-md mt-4'>
<Button <Button
@@ -54,7 +131,7 @@ export default function InitialLoginStep({
Continue with SAML SSO Continue with SAML SSO
</Button> </Button>
</div> </div>
<div className="mt-4 text-bunker-400 text-sm flex flex-row"> <div className="mt-6 text-bunker-400 text-sm flex flex-row">
<span className="mr-1">Don&apos;t have an acount yet?</span> <span className="mr-1">Don&apos;t have an acount yet?</span>
<Link href="/signup"> <Link href="/signup">
<span className='hover:underline hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>{t('login.create-account')}</span> <span className='hover:underline hover:underline-offset-4 hover:decoration-primary-700 hover:text-bunker-200 duration-200 cursor-pointer'>{t('login.create-account')}</span>
+3 -3
View File
@@ -16,10 +16,10 @@ const props = {
fontFamily: 'monospace', fontFamily: 'monospace',
margin: '4px', margin: '4px',
MozAppearance: 'textfield', MozAppearance: 'textfield',
width: '55px', width: '48px',
borderRadius: '5px', borderRadius: '5px',
fontSize: '24px', fontSize: '24px',
height: '55px', height: '48px',
paddingLeft: '7', paddingLeft: '7',
backgroundColor: '#0d1117', backgroundColor: '#0d1117',
color: 'white', color: 'white',
@@ -115,7 +115,7 @@ export default function MFAStep({
}; };
return ( return (
<form className="mx-auto w-max px-8 pb-4 pt-4 md:mb-16"> <form className="mx-auto w-max md:px-8 pb-4 pt-4 md:mb-16">
<p className="text-l flex justify-center text-bunker-300">{t('mfa.step2-message')}</p> <p className="text-l flex justify-center text-bunker-300">{t('mfa.step2-message')}</p>
<p className="text-l my-1 flex justify-center font-semibold text-bunker-300">{email} </p> <p className="text-l my-1 flex justify-center font-semibold text-bunker-300">{email} </p>
<div className="hidden md:block w-max min-w-[20rem] mx-auto"> <div className="hidden md:block w-max min-w-[20rem] mx-auto">
@@ -85,7 +85,7 @@ export default function CodeInputStep({
}; };
return ( return (
<div className="mx-auto h-full w-full pb-4 px-8"> <div className="mx-auto h-full w-full pb-4 md:px-8">
<p className="text-md flex justify-center text-bunker-200">{t('signup.step2-message')}</p> <p className="text-md flex justify-center text-bunker-200">{t('signup.step2-message')}</p>
<p className="text-md flex justify-center font-semibold my-1 text-bunker-200">{email} </p> <p className="text-md flex justify-center font-semibold my-1 text-bunker-200">{email} </p>
<div className="hidden md:block w-max min-w-[20rem] mx-auto"> <div className="hidden md:block w-max min-w-[20rem] mx-auto">
@@ -34,7 +34,7 @@ export default function DonwloadBackupPDFStep({
<p className="text-xl text-center font-medium flex justify-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200"> <p className="text-xl text-center font-medium flex justify-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 text-2xl text-bunker-200" />{t('signup.step4-message')} <FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 text-2xl text-bunker-200" />{t('signup.step4-message')}
</p> </p>
<div className="flex flex-col pb-2 bg-mineshaft-900 border border-mineshaft-700 items-center justify-center text-center lg:w-1/6 w-full md:min-w-[24rem] mt-8 max-w-md text-bunker-300 text-md rounded-md"> <div className="flex flex-col pb-2 bg-mineshaft-800 border border-mineshaft-600 items-center justify-center text-center lg:w-1/6 w-full md:min-w-[24rem] mt-8 max-w-md text-bunker-300 text-md rounded-md">
<div className="w-full mt-4 md:mt-8 flex flex-row text-center items-center m-2 text-bunker-300 rounded-md lg:w-1/6 lg:w-1/6 w-full md:min-w-[23rem] px-3 mx-auto"> <div className="w-full mt-4 md:mt-8 flex flex-row text-center items-center m-2 text-bunker-300 rounded-md lg:w-1/6 lg:w-1/6 w-full md:min-w-[23rem] px-3 mx-auto">
<span className='mb-2'>{t('signup.step4-description1')} {t('signup.step4-description3')}</span> <span className='mb-2'>{t('signup.step4-description1')} {t('signup.step4-description3')}</span>
</div> </div>
@@ -39,7 +39,7 @@ export default function InitialSignupStep({
isFullWidth isFullWidth
className="h-14 w-full mx-0" className="h-14 w-full mx-0"
> >
{t('signup.continue-with-email')} Sign Up with email
</Button> </Button>
</div> </div>
<div className='lg:w-1/6 w-1/4 min-w-[20rem] text-center rounded-md mt-4'> <div className='lg:w-1/6 w-1/4 min-w-[20rem] text-center rounded-md mt-4'>
@@ -217,11 +217,11 @@ export default function UserInfoStep({
}; };
return ( return (
<div className="h-full mx-auto mb-36 w-max rounded-xl px-8 md:mb-16"> <div className="h-full mx-auto mb-36 w-max rounded-xl md:px-8 md:mb-16">
<p className="mx-8 mb-6 flex justify-center text-xl font-bold text-medium md:mx-16 text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200"> <p className="mx-8 mb-6 flex justify-center text-xl font-bold text-medium md:mx-16 text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
{t('signup.step3-message')} {t('signup.step3-message')}
</p> </p>
<div className="h-full mx-auto mb-36 w-max rounded-xl py-6 px-8 md:mb-16 border border-mineshaft-600 bg-mineshaft-800"> <div className="h-full mx-auto mb-36 w-max rounded-xl py-6 md:px-8 md:mb-16 md:border md:border-mineshaft-600 md:bg-mineshaft-800">
<div className="relative z-0 lg:w-1/6 w-1/4 min-w-[20rem] flex flex-col items-center justify-end w-full py-2 rounded-lg"> <div className="relative z-0 lg:w-1/6 w-1/4 min-w-[20rem] flex flex-col items-center justify-end w-full py-2 rounded-lg">
<p className='text-left w-full text-sm text-bunker-300 mb-1 ml-1 font-medium'>Your Name</p> <p className='text-left w-full text-sm text-bunker-300 mb-1 ml-1 font-medium'>Your Name</p>
<Input <Input
+4 -12
View File
@@ -7,7 +7,6 @@ import { useRouter } from 'next/router';
// import ListBox from '@app/components/basic/Listbox'; // import ListBox from '@app/components/basic/Listbox';
import InitialLoginStep from '@app/components/login/InitialLoginStep'; import InitialLoginStep from '@app/components/login/InitialLoginStep';
import LoginStep from '@app/components/login/LoginStep';
import MFAStep from '@app/components/login/MFAStep'; import MFAStep from '@app/components/login/MFAStep';
import PasswordInputStep from '@app/components/login/PasswordInputStep'; import PasswordInputStep from '@app/components/login/PasswordInputStep';
import { useProviderAuth } from '@app/hooks/useProviderAuth'; import { useProviderAuth } from '@app/hooks/useProviderAuth';
@@ -22,7 +21,6 @@ export default function Login() {
const [step, setStep] = useState(1); const [step, setStep] = useState(1);
const { t } = useTranslation(); const { t } = useTranslation();
// const lang = router.locale ?? 'en'; // const lang = router.locale ?? 'en';
const [isLoginWithEmail, setIsLoginWithEmail] = useState(false);
const { const {
providerAuthToken, providerAuthToken,
email: providerEmail, email: providerEmail,
@@ -70,20 +68,14 @@ export default function Login() {
); );
} }
if (isLoginWithEmail && loginStep === 1) { if (loginStep === 1) {
return ( return <InitialLoginStep
<LoginStep setStep={setStep}
email={email} email={email}
setEmail={setEmail} setEmail={setEmail}
password={password} password={password}
setPassword={setPassword} setPassword={setPassword}
setStep={setStep} />;
/>
);
}
if (!isLoginWithEmail && loginStep === 1) {
return <InitialLoginStep setIsLoginWithEmail={setIsLoginWithEmail} />;
} }
if (step === 2) { if (step === 2) {
+4 -4
View File
@@ -46,16 +46,16 @@ export default function Login() {
<Image src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical logo" /> <Image src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical logo" />
</div> </div>
</Link> </Link>
<div className="mx-auto w-full max-w-md px-6"> <div className="mx-auto w-full max-w-md md:px-6">
<p className="mx-auto mb-6 flex w-max justify-center text-xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center mb-8"> <p className="mx-auto mb-6 flex w-max justify-center text-xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center mb-8">
What’s your email? What’s your email?
</p> </p>
<div className="relative flex items-center justify-center lg:w-1/6 w-1/4 min-w-[22rem] mx-auto w-full rounded-lg max-h-24 md:max-h-28"> <div className="relative flex items-center justify-center lg:w-1/6 w-1/4 min-w-[20rem] md:min-w-[22rem] mx-auto w-full rounded-lg max-h-24 md:max-h-28">
<div className="flex items-center justify-center w-full rounded-lg max-h-24 md:max-h-28"> <div className="flex items-center justify-center w-full rounded-lg max-h-24 md:max-h-28">
<Input <Input
value={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
type="password" type="email"
placeholder="Enter your email..." placeholder="Enter your email..."
isRequired isRequired
autoComplete="email" autoComplete="email"
@@ -64,7 +64,7 @@ export default function Login() {
/> />
</div> </div>
</div> </div>
<div className='lg:w-1/6 w-1/4 w-full mx-auto flex items-center justify-center min-w-[22rem] text-center rounded-md mt-4'> <div className='lg:w-1/6 w-1/4 w-full mx-auto flex items-center justify-center min-w-[20rem] md:min-w-[22rem] text-center rounded-md mt-4'>
<Button <Button
colorSchema="primary" colorSchema="primary"
variant="outline_bg" variant="outline_bg"
@@ -717,9 +717,9 @@ export const DashboardPage = ({ envFromTop }: { envFromTop: string }) => {
isLoading={isSubmitting} isLoading={isSubmitting}
leftIcon={<FontAwesomeIcon icon={isRollbackMode ? faClockRotateLeft : faCheck} />} leftIcon={<FontAwesomeIcon icon={isRollbackMode ? faClockRotateLeft : faCheck} />}
onClick={handleSubmit(onSaveSecret)} onClick={handleSubmit(onSaveSecret)}
className="h-10" className="h-10 text-black"
color="primary" color="primary"
variant="star" variant="solid"
> >
{isRollbackMode ? 'Rollback' : 'Save Changes'} {isRollbackMode ? 'Rollback' : 'Save Changes'}
</Button> </Button>