Resolve merge conflicts

This commit is contained in:
Tuan Dang
2023-03-28 14:43:56 +07:00
43 changed files with 1088 additions and 325 deletions
+9
View File
@@ -0,0 +1,9 @@
export default {
preset: 'ts-jest',
testEnvironment: 'node',
collectCoverageFrom: ['src/*.{js,ts}', '!**/node_modules/**'],
modulePaths: ['<rootDir>/src'],
testMatch: ['<rootDir>/tests/**/*.test.ts'],
setupFiles: ['<rootDir>/test-resources/env-vars.js'],
setupFilesAfterEnv: ['<rootDir>/tests/setupTests.ts']
};
+84 -27
View File
@@ -12,7 +12,7 @@
"@aws-sdk/client-secrets-manager": "^3.267.0",
"@godaddy/terminus": "^4.11.2",
"@octokit/rest": "^19.0.5",
"@sentry/node": "^7.14.0",
"@sentry/node": "^7.39.0",
"@sentry/tracing": "^7.19.0",
"@types/crypto-js": "^4.1.1",
"@types/libsodium-wrappers": "^0.7.10",
@@ -40,13 +40,13 @@
"lodash": "^4.17.21",
"mongoose": "^6.7.2",
"nodemailer": "^6.8.0",
"posthog-node": "^2.2.2",
"posthog-node": "^2.5.4",
"query-string": "^7.1.3",
"request-ip": "^3.3.0",
"rimraf": "^3.0.2",
"stripe": "^10.7.0",
"swagger-autogen": "^2.22.0",
"swagger-ui-express": "^4.6.0",
"swagger-ui-express": "^4.6.2",
"tweetnacl": "^1.0.3",
"tweetnacl-util": "^0.15.1",
"typescript": "^4.9.3",
@@ -2800,13 +2800,13 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/@sentry/node": {
"version": "7.38.0",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.38.0.tgz",
"integrity": "sha512-jNIN6NZvgzn/oms8RQzffjX8Z0LQDTN6N28nnhzqGCvnfmS1QtTt0FlU+pTuFXZNNSjfGy4XMXMYvLlbvhm2bg==",
"version": "7.39.0",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.39.0.tgz",
"integrity": "sha512-oe1OBxgs6t/FizjxkSPtuvJv5wJMO+mLENZkiE0PpBD56JyZrWK48kYIt2ccWAfk6Vh235/oIpmqET150xB4lQ==",
"dependencies": {
"@sentry/core": "7.38.0",
"@sentry/types": "7.38.0",
"@sentry/utils": "7.38.0",
"@sentry/core": "7.39.0",
"@sentry/types": "7.39.0",
"@sentry/utils": "7.39.0",
"cookie": "^0.4.1",
"https-proxy-agent": "^5.0.0",
"lru_map": "^0.3.3",
@@ -2816,6 +2816,39 @@
"node": ">=8"
}
},
"node_modules/@sentry/node/node_modules/@sentry/core": {
"version": "7.39.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.39.0.tgz",
"integrity": "sha512-45WJIcWWCQnZ8zhHtcrkJjQ4YydmzMWY4pmRuBG7Qp+zrCT6ISoyODcjY+SCHFdvXkiYFi8+bFZa1qG3YQnnYw==",
"dependencies": {
"@sentry/types": "7.39.0",
"@sentry/utils": "7.39.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/node/node_modules/@sentry/types": {
"version": "7.39.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.39.0.tgz",
"integrity": "sha512-5Y83Y8O3dT5zT2jTKEIPMcpn5lUm05KRMaCXuw0sRsv4r9TbBUKeqiSU1LjowT8rB/XNy8m7DHav8+NmogPaJw==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/node/node_modules/@sentry/utils": {
"version": "7.39.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.39.0.tgz",
"integrity": "sha512-/ZxlPgm1mGgmuMckCTc9iyqDuFTEYNEoMB53IjVFz8ann+37OiWB7Py/QV1rEEsv3xKrGbA8thhRhV9E1sjTlQ==",
"dependencies": {
"@sentry/types": "7.39.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/node/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@@ -10500,9 +10533,9 @@
}
},
"node_modules/posthog-node": {
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-2.5.3.tgz",
"integrity": "sha512-kDmBjQHguPrh/rUTKmB0+Hj7C3fq2t+/fcfQkDBGz0f0fEF2WxV5yyxRmd2IF/hFmHxMrGLDkEVjKr78B+judg==",
"version": "2.5.4",
"resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-2.5.4.tgz",
"integrity": "sha512-CdywlVh0CZU05/3MrBc0qY/zsLdU2X9XSz/yL1qMRhbyZhD8lrnuGlI69G2cpzZtli6S/nu64wcmULz/mFFA5w==",
"dependencies": {
"axios": "^0.27.0"
},
@@ -11483,9 +11516,9 @@
"integrity": "sha512-4J4XekQG0ol4/TyUzMfksrWsMTbw/7JYlT+SFaX7H0xamd1OeuVlUSb/Cbq4qdDx1lc+uLZQW7u2mlImcE8c+w=="
},
"node_modules/swagger-ui-express": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.1.tgz",
"integrity": "sha512-Pss7YNFKNdq66XKNjRe4IRXKKYNx/LvOSml9TdrZ8/78UpxUHIp9JoXpXWA5Z4L+SCmX63DZ9IPlQ8nnRuncvA==",
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.2.tgz",
"integrity": "sha512-MHIOaq9JrTTB3ygUJD+08PbjM5Tt/q7x80yz9VTFIatw8j5uIWKcr90S0h5NLMzFEDC6+eVprtoeA5MDZXCUKQ==",
"dependencies": {
"swagger-ui-dist": ">=4.11.0"
},
@@ -14361,19 +14394,43 @@
}
},
"@sentry/node": {
"version": "7.38.0",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.38.0.tgz",
"integrity": "sha512-jNIN6NZvgzn/oms8RQzffjX8Z0LQDTN6N28nnhzqGCvnfmS1QtTt0FlU+pTuFXZNNSjfGy4XMXMYvLlbvhm2bg==",
"version": "7.39.0",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.39.0.tgz",
"integrity": "sha512-oe1OBxgs6t/FizjxkSPtuvJv5wJMO+mLENZkiE0PpBD56JyZrWK48kYIt2ccWAfk6Vh235/oIpmqET150xB4lQ==",
"requires": {
"@sentry/core": "7.38.0",
"@sentry/types": "7.38.0",
"@sentry/utils": "7.38.0",
"@sentry/core": "7.39.0",
"@sentry/types": "7.39.0",
"@sentry/utils": "7.39.0",
"cookie": "^0.4.1",
"https-proxy-agent": "^5.0.0",
"lru_map": "^0.3.3",
"tslib": "^1.9.3"
},
"dependencies": {
"@sentry/core": {
"version": "7.39.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.39.0.tgz",
"integrity": "sha512-45WJIcWWCQnZ8zhHtcrkJjQ4YydmzMWY4pmRuBG7Qp+zrCT6ISoyODcjY+SCHFdvXkiYFi8+bFZa1qG3YQnnYw==",
"requires": {
"@sentry/types": "7.39.0",
"@sentry/utils": "7.39.0",
"tslib": "^1.9.3"
}
},
"@sentry/types": {
"version": "7.39.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.39.0.tgz",
"integrity": "sha512-5Y83Y8O3dT5zT2jTKEIPMcpn5lUm05KRMaCXuw0sRsv4r9TbBUKeqiSU1LjowT8rB/XNy8m7DHav8+NmogPaJw=="
},
"@sentry/utils": {
"version": "7.39.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.39.0.tgz",
"integrity": "sha512-/ZxlPgm1mGgmuMckCTc9iyqDuFTEYNEoMB53IjVFz8ann+37OiWB7Py/QV1rEEsv3xKrGbA8thhRhV9E1sjTlQ==",
"requires": {
"@sentry/types": "7.39.0",
"tslib": "^1.9.3"
}
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@@ -20049,9 +20106,9 @@
}
},
"posthog-node": {
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-2.5.3.tgz",
"integrity": "sha512-kDmBjQHguPrh/rUTKmB0+Hj7C3fq2t+/fcfQkDBGz0f0fEF2WxV5yyxRmd2IF/hFmHxMrGLDkEVjKr78B+judg==",
"version": "2.5.4",
"resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-2.5.4.tgz",
"integrity": "sha512-CdywlVh0CZU05/3MrBc0qY/zsLdU2X9XSz/yL1qMRhbyZhD8lrnuGlI69G2cpzZtli6S/nu64wcmULz/mFFA5w==",
"requires": {
"axios": "^0.27.0"
},
@@ -20779,9 +20836,9 @@
"integrity": "sha512-4J4XekQG0ol4/TyUzMfksrWsMTbw/7JYlT+SFaX7H0xamd1OeuVlUSb/Cbq4qdDx1lc+uLZQW7u2mlImcE8c+w=="
},
"swagger-ui-express": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.1.tgz",
"integrity": "sha512-Pss7YNFKNdq66XKNjRe4IRXKKYNx/LvOSml9TdrZ8/78UpxUHIp9JoXpXWA5Z4L+SCmX63DZ9IPlQ8nnRuncvA==",
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.2.tgz",
"integrity": "sha512-MHIOaq9JrTTB3ygUJD+08PbjM5Tt/q7x80yz9VTFIatw8j5uIWKcr90S0h5NLMzFEDC6+eVprtoeA5MDZXCUKQ==",
"requires": {
"swagger-ui-dist": ">=4.11.0"
}
+3 -14
View File
@@ -3,7 +3,7 @@
"@aws-sdk/client-secrets-manager": "^3.267.0",
"@godaddy/terminus": "^4.11.2",
"@octokit/rest": "^19.0.5",
"@sentry/node": "^7.14.0",
"@sentry/node": "^7.39.0",
"@sentry/tracing": "^7.19.0",
"@types/crypto-js": "^4.1.1",
"@types/libsodium-wrappers": "^0.7.10",
@@ -31,13 +31,13 @@
"lodash": "^4.17.21",
"mongoose": "^6.7.2",
"nodemailer": "^6.8.0",
"posthog-node": "^2.2.2",
"posthog-node": "^2.5.4",
"query-string": "^7.1.3",
"request-ip": "^3.3.0",
"rimraf": "^3.0.2",
"stripe": "^10.7.0",
"swagger-autogen": "^2.22.0",
"swagger-ui-express": "^4.6.0",
"swagger-ui-express": "^4.6.2",
"tweetnacl": "^1.0.3",
"tweetnacl-util": "^0.15.1",
"typescript": "^4.9.3",
@@ -101,17 +101,6 @@
"ts-jest": "^29.0.3",
"ts-node": "^10.9.1"
},
"jest": {
"preset": "ts-jest",
"testEnvironment": "node",
"collectCoverageFrom": [
"src/*.{js,ts}",
"!**/node_modules/**"
],
"setupFiles": [
"<rootDir>/test-resources/env-vars.js"
]
},
"jest-junit": {
"outputDirectory": "reports",
"outputName": "jest-junit.xml",
+6 -5
View File
@@ -5,12 +5,12 @@ export const getEncryptionKey = () => infisical.get('ENCRYPTION_KEY')!;
export const getSaltRounds = () => parseInt(infisical.get('SALT_ROUNDS')!) || 10;
export const getJwtAuthLifetime = () => infisical.get('JWT_AUTH_LIFETIME')! || '10d';
export const getJwtAuthSecret = () => infisical.get('JWT_AUTH_SECRET')!;
export const getJwtMfaLifetime = () => infisical.get('JWT_MFA_LIFETIME')!;
export const getJwtMfaLifetime = () => infisical.get('JWT_MFA_LIFETIME')! || '5m';
export const getJwtMfaSecret = () => infisical.get('JWT_MFA_LIFETIME')! || '5m';
export const getJwtRefreshLifetime = () => infisical.get('JWT_REFRESH_LIFETIME')! || '90d';
export const getJwtRefreshSecret = () => infisical.get('JWT_REFRESH_SECRET')!;
export const getJwtServiceSecret = () => infisical.get('JWT_SERVICE_SECRET')!;
export const getJwtSignupLifetime = () => infisical.get('JWT_SIGNUP_LIFETIME')!;
export const getJwtSignupLifetime = () => infisical.get('JWT_SIGNUP_LIFETIME')! || '15m';
export const getJwtSignupSecret = () => infisical.get('JWT_SIGNUP_SECRET')!;
export const getMongoURL = () => infisical.get('MONGO_URL')!;
export const getNodeEnv = () => infisical.get('NODE_ENV')!;
@@ -34,12 +34,12 @@ export const getPostHogProjectApiKey = () => infisical.get('POSTHOG_PROJECT_API_
export const getSentryDSN = () => infisical.get('SENTRY_DSN')!;
export const getSiteURL = () => infisical.get('SITE_URL')!;
export const getSmtpHost = () => infisical.get('SMTP_HOST')!;
export const getSmtpSecure = () => infisical.get('SMTP_SECURE')! === 'true' || false;
export const getSmtpSecure = () => infisical.get('SMTP_SECURE')! === 'true' || false;
export const getSmtpPort = () => parseInt(infisical.get('SMTP_PORT')!) || 587;
export const getSmtpUsername = () => infisical.get('SMTP_USERNAME')!;
export const getSmtpPassword = () => infisical.get('SMTP_PASSWORD')!;
export const getSmtpFromAddress = () => infisical.get('SMTP_FROM_ADDRESS')!;
export const getSmtpFromName = () => infisical.get('SMTP_FROM_NAME')! || 'Infisical';
export const getSmtpFromName = () => infisical.get('SMTP_FROM_NAME')! || 'Infisical';
export const getStripeProductStarter = () => infisical.get('STRIPE_PRODUCT_STARTER')!;
export const getStripeProductPro = () => infisical.get('STRIPE_PRODUCT_PRO')!;
export const getStripeProductTeam = () => infisical.get('STRIPE_PRODUCT_TEAM')!;
@@ -47,4 +47,5 @@ export const getStripePublishableKey = () => infisical.get('STRIPE_PUBLISHABLE_K
export const getStripeSecretKey = () => infisical.get('STRIPE_SECRET_KEY')!;
export const getStripeWebhookSecret = () => infisical.get('STRIPE_WEBHOOK_SECRET')!;
export const getTelemetryEnabled = () => infisical.get('TELEMETRY_ENABLED')! !== 'false' && true;
export const getLoopsApiKey = () => infisical.get('LOOPS_API_KEY')!;
export const getLoopsApiKey = () => infisical.get('LOOPS_API_KEY')!;
export const getSmtpConfigured = () => infisical.get('SMTP_HOST') == '' || infisical.get('SMTP_HOST') == undefined ? false : true
@@ -7,7 +7,7 @@ import { updateSubscriptionOrgQuantity } from '../../helpers/organization';
import { sendMail } from '../../helpers/nodemailer';
import { TokenService } from '../../services';
import { OWNER, ADMIN, MEMBER, ACCEPTED, INVITED, TOKEN_EMAIL_ORG_INVITATION } from '../../variables';
import { getSiteURL, getJwtSignupLifetime, getJwtSignupSecret } from '../../config';
import { getSiteURL, getJwtSignupLifetime, getJwtSignupSecret, getSmtpConfigured } from '../../config';
/**
* Delete organization membership with id [membershipOrgId] from organization
@@ -99,9 +99,11 @@ export const changeMembershipOrgRole = async (req: Request, res: Response) => {
* @returns
*/
export const inviteUserToOrganization = async (req: Request, res: Response) => {
let invitee, inviteeMembershipOrg;
let invitee, inviteeMembershipOrg, completeInviteLink;
try {
const { organizationId, inviteeEmail } = req.body;
const host = req.headers.host;
const siteUrl = `${req.protocol}://${host}`;
// validate membership
const membershipOrg = await MembershipOrg.findOne({
@@ -181,6 +183,10 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
callback_url: getSiteURL() + '/signupinvite'
}
});
if (!getSmtpConfigured()) {
completeInviteLink = `${siteUrl + '/signupinvite'}?token=${token}&to=${inviteeEmail}`
}
}
await updateSubscriptionOrgQuantity({ organizationId });
@@ -193,7 +199,8 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
}
return res.status(200).send({
message: `Sent an invite link to ${req.body.inviteeEmail}`
message: `Sent an invite link to ${req.body.inviteeEmail}`,
completeInviteLink
});
};
@@ -218,7 +225,7 @@ export const verifyUserToOrganization = async (req: Request, res: Response) => {
if (!membershipOrg)
throw new Error('Failed to find any invitations for email');
await TokenService.validateToken({
type: TOKEN_EMAIL_ORG_INVITATION,
email,
@@ -7,7 +7,7 @@ import {
} from '../../helpers/signup';
import { createToken } from '../../helpers/auth';
import { BadRequestError } from '../../utils/errors';
import { getInviteOnlySignup, getJwtSignupLifetime, getJwtSignupSecret } from '../../config';
import { getInviteOnlySignup, getJwtSignupLifetime, getJwtSignupSecret, getSmtpConfigured } from '../../config';
/**
* Signup step 1: Initialize account for user under email [email] and send a verification code
@@ -21,7 +21,7 @@ export const beginEmailSignup = async (req: Request, res: Response) => {
try {
email = req.body.email;
if (getInviteOnlySignup() || false) {
if (getInviteOnlySignup()) {
// Only one user can create an account without being invited. The rest need to be invited in order to make an account
const userCount = await User.countDocuments({})
if (userCount != 0) {
@@ -66,7 +66,7 @@ export const verifyEmailSignup = async (req: Request, res: Response) => {
const { email, code } = req.body;
// initialize user account
user = await User.findOne({ email });
user = await User.findOne({ email }).select('+publicKey');
if (user && user?.publicKey) {
// case: user has already completed account
return res.status(403).send({
@@ -75,10 +75,12 @@ export const verifyEmailSignup = async (req: Request, res: Response) => {
}
// verify email
await checkEmailVerification({
email,
code
});
if (getSmtpConfigured()) {
await checkEmailVerification({
email,
code
});
}
if (!user) {
user = await new User({
+87 -75
View File
@@ -87,7 +87,7 @@ export const login1 = 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' });
const { email, clientProof } = req.body;
@@ -127,12 +127,12 @@ export const login2 = async (req: Request, res: Response) => {
expiresIn: getJwtMfaLifetime(),
secret: getJwtMfaSecret()
});
const code = await TokenService.createToken({
type: TOKEN_EMAIL_MFA,
email
});
// send MFA code [code] to [email]
await sendMail({
template: 'emailMfa.handlebars',
@@ -142,13 +142,13 @@ export const login2 = async (req: Request, res: Response) => {
code
}
});
return res.status(200).send({
mfaEnabled: true,
token
});
}
await checkUserDevice({
user,
ip: req.ip,
@@ -181,7 +181,7 @@ export const login2 = async (req: Request, res: Response) => {
iv?: string;
tag?: string;
}
const response: ResponseData = {
mfaEnabled: false,
encryptionVersion: user.encryptionVersion,
@@ -191,7 +191,7 @@ export const login2 = async (req: Request, res: Response) => {
iv: user.iv,
tag: user.tag
}
if (
user?.protectedKey &&
user?.protectedKeyIV &&
@@ -206,14 +206,14 @@ export const login2 = async (req: Request, res: Response) => {
name: ACTION_LOGIN,
userId: user._id
});
loginAction && await EELogService.createLog({
userId: user._id,
actions: [loginAction],
channel: getChannelFromUserAgent(req.headers['user-agent']),
ipAddress: req.ip
});
return res.status(200).send(response);
}
@@ -244,7 +244,7 @@ export const sendMfaToken = async (req: Request, res: Response) => {
type: TOKEN_EMAIL_MFA,
email
});
// send MFA code [code] to [email]
await sendMail({
template: 'emailMfa.handlebars',
@@ -259,9 +259,9 @@ export const sendMfaToken = async (req: Request, res: Response) => {
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to send MFA code'
});
});
}
return res.status(200).send({
message: 'Successfully sent new MFA code'
});
@@ -274,75 +274,87 @@ export const sendMfaToken = async (req: Request, res: Response) => {
* @param res
*/
export const verifyMfaToken = async (req: Request, res: Response) => {
const { email, mfaToken } = req.body;
const { email, mfaToken } = req.body;
await TokenService.validateToken({
type: TOKEN_EMAIL_MFA,
email,
token: mfaToken
});
await TokenService.validateToken({
type: TOKEN_EMAIL_MFA,
email,
token: mfaToken
});
const user = await User.findOne({
email
}).select('+salt +verifier +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag +publicKey +encryptedPrivateKey +iv +tag');
const user = await User.findOne({
email
}).select('+salt +verifier +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag +publicKey +encryptedPrivateKey +iv +tag');
if (!user) throw new Error('Failed to find user');
if (!user) throw new Error('Failed to find user');
await checkUserDevice({
user,
ip: req.ip,
userAgent: req.headers['user-agent'] ?? ''
});
await checkUserDevice({
user,
ip: req.ip,
userAgent: req.headers['user-agent'] ?? ''
});
// issue tokens
const tokens = await issueAuthTokens({ userId: user._id.toString() });
// issue tokens
const tokens = await issueAuthTokens({ userId: user._id.toString() });
// store (refresh) token in httpOnly cookie
res.cookie('jid', tokens.refreshToken, {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: getNodeEnv() === 'production' ? true : false
});
interface VerifyMfaTokenRes {
encryptionVersion: number;
protectedKey?: string;
protectedKeyIV?: string;
protectedKeyTag?: string;
token: string;
publicKey: string;
encryptedPrivateKey: string;
iv: string;
tag: string;
}
// store (refresh) token in httpOnly cookie
res.cookie('jid', tokens.refreshToken, {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: getNodeEnv() === 'production' ? true : false
});
const resObj: VerifyMfaTokenRes = {
encryptionVersion: user.encryptionVersion,
token: tokens.token,
publicKey: user.publicKey as string,
encryptedPrivateKey: user.encryptedPrivateKey as string,
iv: user.iv as string,
tag: user.tag as string
}
if (user?.protectedKey && user?.protectedKeyIV && user?.protectedKeyTag) {
resObj.protectedKey = user.protectedKey;
resObj.protectedKeyIV = user.protectedKeyIV;
resObj.protectedKeyTag = user.protectedKeyTag;
}
interface VerifyMfaTokenRes {
encryptionVersion: number;
protectedKey?: string;
protectedKeyIV?: string;
protectedKeyTag?: string;
token: string;
publicKey: string;
encryptedPrivateKey: string;
iv: string;
tag: string;
}
const loginAction = await EELogService.createAction({
name: ACTION_LOGIN,
userId: user._id
});
loginAction && await EELogService.createLog({
userId: user._id,
actions: [loginAction],
channel: getChannelFromUserAgent(req.headers['user-agent']),
ipAddress: req.ip
});
interface VerifyMfaTokenRes {
encryptionVersion: number;
protectedKey?: string;
protectedKeyIV?: string;
protectedKeyTag?: string;
token: string;
publicKey: string;
encryptedPrivateKey: string;
iv: string;
tag: string;
}
return res.status(200).send(resObj);
}
const resObj: VerifyMfaTokenRes = {
encryptionVersion: user.encryptionVersion,
token: tokens.token,
publicKey: user.publicKey as string,
encryptedPrivateKey: user.encryptedPrivateKey as string,
iv: user.iv as string,
tag: user.tag as string
}
if (user?.protectedKey && user?.protectedKeyIV && user?.protectedKeyTag) {
resObj.protectedKey = user.protectedKey;
resObj.protectedKeyIV = user.protectedKeyIV;
resObj.protectedKeyTag = user.protectedKeyTag;
}
const loginAction = await EELogService.createAction({
name: ACTION_LOGIN,
userId: user._id
});
loginAction && await EELogService.createLog({
userId: user._id,
actions: [loginAction],
channel: getChannelFromUserAgent(req.headers['user-agent']),
ipAddress: req.ip
});
return res.status(200).send(resObj);
}
+19 -17
View File
@@ -3,7 +3,7 @@ import fs from 'fs';
import path from 'path';
import handlebars from 'handlebars';
import nodemailer from 'nodemailer';
import { getSmtpFromName, getSmtpFromAddress } from '../config';
import { getSmtpFromName, getSmtpFromAddress, getSmtpConfigured } from '../config';
let smtpTransporter: nodemailer.Transporter;
@@ -25,23 +25,25 @@ const sendMail = async ({
recipients: string[];
substitutions: any;
}) => {
try {
const html = fs.readFileSync(
path.resolve(__dirname, '../templates/' + template),
'utf8'
);
const temp = handlebars.compile(html);
const htmlToSend = temp(substitutions);
if (getSmtpConfigured()) {
try {
const html = fs.readFileSync(
path.resolve(__dirname, '../templates/' + template),
'utf8'
);
const temp = handlebars.compile(html);
const htmlToSend = temp(substitutions);
await smtpTransporter.sendMail({
from: `"${getSmtpFromName()}" <${getSmtpFromAddress()}>`,
to: recipients.join(', '),
subject: subjectLine,
html: htmlToSend
});
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
await smtpTransporter.sendMail({
from: `"${getSmtpFromName()}" <${getSmtpFromAddress()}>`,
to: recipients.join(', '),
subject: subjectLine,
html: htmlToSend
});
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
}
}
};
+30 -28
View File
@@ -23,29 +23,29 @@ const swaggerFile = require('../spec.json');
const requestIp = require('request-ip');
import { apiLimiter } from './helpers/rateLimiter';
import {
workspace as eeWorkspaceRouter,
secret as eeSecretRouter,
secretSnapshot as eeSecretSnapshotRouter,
action as eeActionRouter
workspace as eeWorkspaceRouter,
secret as eeSecretRouter,
secretSnapshot as eeSecretSnapshotRouter,
action as eeActionRouter
} from './ee/routes/v1';
import {
signup as v1SignupRouter,
auth as v1AuthRouter,
bot as v1BotRouter,
organization as v1OrganizationRouter,
workspace as v1WorkspaceRouter,
membershipOrg as v1MembershipOrgRouter,
membership as v1MembershipRouter,
key as v1KeyRouter,
inviteOrg as v1InviteOrgRouter,
user as v1UserRouter,
userAction as v1UserActionRouter,
secret as v1SecretRouter,
serviceToken as v1ServiceTokenRouter,
password as v1PasswordRouter,
stripe as v1StripeRouter,
integration as v1IntegrationRouter,
integrationAuth as v1IntegrationAuthRouter
signup as v1SignupRouter,
auth as v1AuthRouter,
bot as v1BotRouter,
organization as v1OrganizationRouter,
workspace as v1WorkspaceRouter,
membershipOrg as v1MembershipOrgRouter,
membership as v1MembershipRouter,
key as v1KeyRouter,
inviteOrg as v1InviteOrgRouter,
user as v1UserRouter,
userAction as v1UserActionRouter,
secret as v1SecretRouter,
serviceToken as v1ServiceTokenRouter,
password as v1PasswordRouter,
stripe as v1StripeRouter,
integration as v1IntegrationRouter,
integrationAuth as v1IntegrationAuthRouter
} from './routes/v1';
import {
signup as v2SignupRouter,
@@ -66,7 +66,7 @@ import { getLogger } from './utils/logger';
import { RouteNotFoundError } from './utils/errors';
import { requestErrorHandler } from './middleware/requestErrorHandler';
import {
getMongoURL,
getMongoURL,
getNodeEnv,
getPort,
getSentryDSN,
@@ -74,10 +74,12 @@ import {
} from './config';
const main = async () => {
await infisical.connect({
token: process.env.INFISICAL_TOKEN!
});
if (process.env.INFISICAL_TOKEN != "" || process.env.INFISICAL_TOKEN != undefined) {
await infisical.connect({
token: process.env.INFISICAL_TOKEN!
});
}
logTelemetryMessage();
setTransporter(initSmtp());
@@ -160,7 +162,7 @@ const main = async () => {
//* Handle unrouted requests and respond with proper error message as well as status code
app.use((req, res, next) => {
if (res.headersSent) return next();
if (res.headersSent) return next();
next(RouteNotFoundError({ message: `The requested source '(${req.method})${req.url}' was not found` }))
})
@@ -172,7 +174,7 @@ const main = async () => {
createTestUserForDevelopment();
setUpHealthEndpoint(server);
server.on('close', async () => {
await DatabaseService.closeDatabase();
})
+2
View File
@@ -1,4 +1,5 @@
import express, { Request, Response } from 'express';
import { getSmtpConfigured } from '../../config';
const router = express.Router();
@@ -8,6 +9,7 @@ router.get(
res.status(200).json({
date: new Date(),
message: 'Ok',
emailConfigured: getSmtpConfigured()
})
}
);
+5
View File
@@ -0,0 +1,5 @@
import { it, expect } from '@jest/globals';
it('should return true', () => {
expect(true).toBeTruthy();
});
@@ -18,4 +18,4 @@ describe('Healthcheck endpoint', () => {
const res = await request(server).get('/healthcheck');
expect(res.status).toEqual(200);
});
});
});