Refactor infisical-node to config file for birds eye view of envars

This commit is contained in:
Tuan Dang
2023-03-15 00:09:40 +07:00
parent 31111fc63b
commit a6c8638345
33 changed files with 264 additions and 262 deletions
+49 -101
View File
@@ -1,101 +1,49 @@
// const PORT = process.env.PORT || 4000; import infisical from 'infisical-node';
// const INVITE_ONLY_SIGNUP = process.env.INVITE_ONLY_SIGNUP == undefined ? false : process.env.INVITE_ONLY_SIGNUP export const getPort = () => infisical.get('PORT')! || 4000;
// const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY!; export const getInviteOnlySignup = () => infisical.get('INVITE_ONLY_SIGNUP')! == undefined ? false : process.env.INVITE_ONLY_SIGNUP;
// const SALT_ROUNDS = parseInt(process.env.SALT_ROUNDS!) || 10; export const getEncryptionKey = () => infisical.get('ENCRYPTION_KEY')!;
// const JWT_AUTH_LIFETIME = process.env.JWT_AUTH_LIFETIME! || '10d'; export const getSaltRounds = () => parseInt(infisical.get('SALT_ROUNDS')!) || 10;
// const JWT_AUTH_SECRET = process.env.JWT_AUTH_SECRET!; export const getJwtAuthLifetime = () => infisical.get('JWT_AUTH_LIFETIME')! || '10d';
// const JWT_MFA_LIFETIME = process.env.JWT_MFA_LIFETIME! || '5m'; export const getJwtAuthSecret = () => infisical.get('JWT_AUTH_SECRET')!;
// const JWT_MFA_SECRET = process.env.JWT_MFA_SECRET!; export const getJwtMfaLifetime = () => infisical.get('JWT_MFA_LIFETIME')!;
// const JWT_REFRESH_LIFETIME = process.env.JWT_REFRESH_LIFETIME! || '90d'; export const getJwtMfaSecret = () => infisical.get('JWT_MFA_LIFETIME')! || '5m';
// const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET!; export const getJwtRefreshLifetime = () => infisical.get('JWT_REFRESH_LIFETIME')! || '90d';
// const JWT_SERVICE_SECRET = process.env.JWT_SERVICE_SECRET!; export const getJwtRefreshSecret = () => infisical.get('JWT_REFRESH_SECRET')!;
// const JWT_SIGNUP_LIFETIME = process.env.JWT_SIGNUP_LIFETIME! || '15m'; export const getJwtServiceSecret = () => infisical.get('JWT_SERVICE_SECRET')!;
// const JWT_SIGNUP_SECRET = process.env.JWT_SIGNUP_SECRET!; export const getJwtSignupLifetime = () => infisical.get('JWT_SIGNUP_LIFETIME')!;
// const MONGO_URL = process.env.MONGO_URL!; export const getJwtSignupSecret = () => infisical.get('JWT_SIGNUP_SECRET')!;
// const NODE_ENV = process.env.NODE_ENV! || 'production'; export const getMongoURL = () => infisical.get('MONGO_URL')!;
// const VERBOSE_ERROR_OUTPUT = process.env.VERBOSE_ERROR_OUTPUT! === 'true' && true; export const getNodeEnv = () => infisical.get('NODE_ENV')!;
// const LOKI_HOST = process.env.LOKI_HOST || undefined; export const getVerboseErrorOutput = () => infisical.get('VERBOSE_ERROR_OUTPUT')! === 'true' && true;
// const CLIENT_ID_AZURE = process.env.CLIENT_ID_AZURE!; export const getLokiHost = () => infisical.get('LOKI_HOST')!;
// const CLIENT_ID_HEROKU = process.env.CLIENT_ID_HEROKU!; export const getClientIdAzure = () => infisical.get('CLIENT_ID_AZURE')!;
// const CLIENT_ID_VERCEL = process.env.CLIENT_ID_VERCEL!; export const getClientIdHeroku = () => infisical.get('CLIENT_ID_HEROKU')!;
// const CLIENT_ID_NETLIFY = process.env.CLIENT_ID_NETLIFY!; export const getClientIdVercel = () => infisical.get('CLIENT_ID_VERCEL')!;
// const CLIENT_ID_GITHUB = process.env.CLIENT_ID_GITHUB!; export const getClientIdNetlify = () => infisical.get('CLIENT_ID_NETLIFY')!;
// const CLIENT_ID_GITLAB = process.env.CLIENT_ID_GITLAB!; export const getClientIdGitHub = () => infisical.get('CLIENT_ID_GITHUB')!;
// const CLIENT_SECRET_AZURE = process.env.CLIENT_SECRET_AZURE!; export const getClientIdGitLab = () => infisical.get('CLIENT_ID_GITLAB')!;
// const CLIENT_SECRET_HEROKU = process.env.CLIENT_SECRET_HEROKU!; export const getClientSecretAzure = () => infisical.get('CLIENT_SECRET_AZURE')!;
// const CLIENT_SECRET_VERCEL = process.env.CLIENT_SECRET_VERCEL!; export const getClientSecretHeroku = () => infisical.get('CLIENT_SECRET_HEROKU')!;
// const CLIENT_SECRET_NETLIFY = process.env.CLIENT_SECRET_NETLIFY!; export const getClientSecretVercel = () => infisical.get('CLIENT_SECRET_VERCEL')!;
// const CLIENT_SECRET_GITHUB = process.env.CLIENT_SECRET_GITHUB!; export const getClientSecretNetlify = () => infisical.get('CLIENT_SECRET_NETLIFY')!;
// const CLIENT_SECRET_GITLAB = process.env.CLIENT_SECRET_GITLAB; export const getClientSecretGitHub = () => infisical.get('CLIENT_SECRET_GITHUB')!;
// const CLIENT_SLUG_VERCEL = process.env.CLIENT_SLUG_VERCEL!; export const getClientSecretGitLab = () => infisical.get('CLIENT_SECRET_GITLAB')!;
// const POSTHOG_HOST = process.env.POSTHOG_HOST! || 'https://app.posthog.com'; export const getClientSlugVercel = () => infisical.get('CLIENT_SLUG_VERCEL')!;
// const POSTHOG_PROJECT_API_KEY = export const getPostHogHost = () => infisical.get('POSTHOG_HOST')! || 'https://app.posthog.com';
// process.env.POSTHOG_PROJECT_API_KEY! || export const getPostHogProjectApiKey = () => infisical.get('POSTHOG_PROJECT_API_KEY')! || 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE';
// 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE'; export const getSentryDSN = () => infisical.get('SENTRY_DSN')!;
// const SENTRY_DSN = process.env.SENTRY_DSN!; export const getSiteURL = () => infisical.get('SITE_URL')!;
// const SITE_URL = process.env.SITE_URL!; export const getSmtpHost = () => infisical.get('SMTP_HOST')!;
// const SMTP_HOST = process.env.SMTP_HOST!; export const getSmtpSecure = () => infisical.get('SMTP_SECURE')! === 'true' || false;
// const SMTP_SECURE = process.env.SMTP_SECURE! === 'true' || false; export const getSmtpPort = () => parseInt(infisical.get('SMTP_PORT')!) || 587;
// const SMTP_PORT = parseInt(process.env.SMTP_PORT!) || 587; export const getSmtpUsername = () => infisical.get('SMTP_USERNAME')!;
// const SMTP_USERNAME = process.env.SMTP_USERNAME!; export const getSmtpPassword = () => infisical.get('SMTP_PASSWORD')!;
// const SMTP_PASSWORD = process.env.SMTP_PASSWORD!; export const getSmtpFromAddress = () => infisical.get('SMTP_FROM_ADDRESS')!;
// const SMTP_FROM_ADDRESS = process.env.SMTP_FROM_ADDRESS!; export const getSmtpFromName = () => infisical.get('SMTP_FROM_NAME')! || 'Infisical';
// const SMTP_FROM_NAME = process.env.SMTP_FROM_NAME! || 'Infisical'; export const getStripeProductStarter = () => infisical.get('STRIPE_PRODUCT_STARTER')!;
// const STRIPE_PRODUCT_STARTER = process.env.STRIPE_PRODUCT_STARTER!; export const getStripeProductPro = () => infisical.get('STRIPE_PRODUCT_PRO')!;
// const STRIPE_PRODUCT_PRO = process.env.STRIPE_PRODUCT_PRO!; export const getStripeProductTeam = () => infisical.get('STRIPE_PRODUCT_TEAM')!;
// const STRIPE_PRODUCT_TEAM = process.env.STRIPE_PRODUCT_TEAM!; export const getStripePublishableKey = () => infisical.get('STRIPE_PUBLISHABLE_KEY')!;
// const STRIPE_PUBLISHABLE_KEY = process.env.STRIPE_PUBLISHABLE_KEY!; export const getStripeSecretKey = () => infisical.get('STRIPE_SECRET_KEY')!;
// const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY!; export const getStripeWebhookSecret = () => infisical.get('STRIPE_WEBHOOK_SECRET')!;
// const STRIPE_WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET!; export const getTelemetryEnabled = () => infisical.get('TELEMETRY_ENABLED')! !== 'false' && true;
// const TELEMETRY_ENABLED = process.env.TELEMETRY_ENABLED! !== 'false' && true;
export {
// PORT,
// INVITE_ONLY_SIGNUP,
// ENCRYPTION_KEY,
// SALT_ROUNDS,
// JWT_AUTH_LIFETIME,
// JWT_AUTH_SECRET,
// JWT_MFA_LIFETIME,
// JWT_MFA_SECRET,
// JWT_REFRESH_LIFETIME,
// JWT_REFRESH_SECRET,
// JWT_SERVICE_SECRET,
// JWT_SIGNUP_LIFETIME,
// JWT_SIGNUP_SECRET,
// MONGO_URL,
// NODE_ENV,
// VERBOSE_ERROR_OUTPUT,
// LOKI_HOST,
// CLIENT_ID_AZURE,
// CLIENT_ID_HEROKU,
// CLIENT_ID_VERCEL,
// CLIENT_ID_NETLIFY,
// CLIENT_ID_GITHUB,
// CLIENT_ID_GITLAB,
// CLIENT_SECRET_AZURE,
// CLIENT_SECRET_HEROKU,
// CLIENT_SECRET_VERCEL,
// CLIENT_SECRET_NETLIFY,
// CLIENT_SECRET_GITHUB,
// CLIENT_SECRET_GITLAB,
// CLIENT_SLUG_VERCEL,
// POSTHOG_HOST,
// POSTHOG_PROJECT_API_KEY,
// SENTRY_DSN,
// SITE_URL,
// SMTP_HOST,
// SMTP_PORT,
// SMTP_SECURE,
// SMTP_USERNAME,
// SMTP_PASSWORD,
// SMTP_FROM_ADDRESS,
// SMTP_FROM_NAME,
// STRIPE_PRODUCT_STARTER,
// STRIPE_PRODUCT_TEAM,
// STRIPE_PRODUCT_PRO,
// STRIPE_PUBLISHABLE_KEY,
// STRIPE_SECRET_KEY,
// STRIPE_WEBHOOK_SECRET,
// TELEMETRY_ENABLED,
};
+11 -6
View File
@@ -1,5 +1,4 @@
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import infisical from 'infisical-node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import * as bigintConversion from 'bigint-conversion'; import * as bigintConversion from 'bigint-conversion';
@@ -15,6 +14,12 @@ import {
import { BadRequestError } from '../../utils/errors'; import { BadRequestError } from '../../utils/errors';
import { EELogService } from '../../ee/services'; import { EELogService } from '../../ee/services';
import { getChannelFromUserAgent } from '../../utils/posthog'; // TODO: move this import { getChannelFromUserAgent } from '../../utils/posthog'; // TODO: move this
import {
getNodeEnv,
getJwtRefreshSecret,
getJwtAuthLifetime,
getJwtAuthSecret
} from '../../config';
declare module 'jsonwebtoken' { declare module 'jsonwebtoken' {
export interface UserIDJwtPayload extends jwt.JwtPayload { export interface UserIDJwtPayload extends jwt.JwtPayload {
@@ -121,7 +126,7 @@ export const login2 = async (req: Request, res: Response) => {
httpOnly: true, httpOnly: true,
path: '/', path: '/',
sameSite: 'strict', sameSite: 'strict',
secure: infisical.get('NODE_ENV')! === 'production' ? true : false secure: getNodeEnv() === 'production' ? true : false
}); });
const loginAction = await EELogService.createAction({ const loginAction = await EELogService.createAction({
@@ -177,7 +182,7 @@ export const logout = async (req: Request, res: Response) => {
httpOnly: true, httpOnly: true,
path: '/', path: '/',
sameSite: 'strict', sameSite: 'strict',
secure: infisical.get('NODE_ENV') === 'production' ? true : false secure: getNodeEnv() === 'production' ? true : false
}); });
const logoutAction = await EELogService.createAction({ const logoutAction = await EELogService.createAction({
@@ -232,7 +237,7 @@ export const getNewToken = async (req: Request, res: Response) => {
} }
const decodedToken = <jwt.UserIDJwtPayload>( const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(refreshToken, infisical.get('JWT_REFRESH_SECRET')!) jwt.verify(refreshToken, getJwtRefreshSecret())
); );
const user = await User.findOne({ const user = await User.findOne({
@@ -247,8 +252,8 @@ export const getNewToken = async (req: Request, res: Response) => {
payload: { payload: {
userId: decodedToken.userId userId: decodedToken.userId
}, },
expiresIn: infisical.get('JWT_AUTH_LIFETIME')!, expiresIn: getJwtAuthLifetime(),
secret: infisical.get('JWT_AUTH_SECRET')! secret: getJwtAuthSecret()
}); });
return res.status(200).send({ return res.status(200).send({
@@ -1,4 +1,3 @@
import infisical from 'infisical-node';
import * as Sentry from '@sentry/node'; 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';
@@ -8,6 +7,7 @@ import {
} from '../../helpers/membership'; } from '../../helpers/membership';
import { sendMail } from '../../helpers/nodemailer'; import { sendMail } from '../../helpers/nodemailer';
import { ADMIN, MEMBER, ACCEPTED } from '../../variables'; import { ADMIN, MEMBER, ACCEPTED } from '../../variables';
import { getSiteURL } from '../../config';
/** /**
* Check that user is a member of workspace with id [workspaceId] * Check that user is a member of workspace with id [workspaceId]
@@ -215,7 +215,7 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => {
inviterFirstName: req.user.firstName, inviterFirstName: req.user.firstName,
inviterEmail: req.user.email, inviterEmail: req.user.email,
workspaceName: req.membership.workspace.name, workspaceName: req.membership.workspace.name,
callback_url: infisical.get('SITE_URL')! + '/login' callback_url: getSiteURL() + '/login'
} }
}); });
} catch (err) { } catch (err) {
@@ -1,4 +1,3 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import { MembershipOrg, Organization, User } from '../../models'; import { MembershipOrg, Organization, User } from '../../models';
@@ -8,6 +7,7 @@ import { updateSubscriptionOrgQuantity } from '../../helpers/organization';
import { sendMail } from '../../helpers/nodemailer'; import { sendMail } from '../../helpers/nodemailer';
import { TokenService } from '../../services'; import { TokenService } from '../../services';
import { OWNER, ADMIN, MEMBER, ACCEPTED, INVITED, TOKEN_EMAIL_ORG_INVITATION } from '../../variables'; import { OWNER, ADMIN, MEMBER, ACCEPTED, INVITED, TOKEN_EMAIL_ORG_INVITATION } from '../../variables';
import { getSiteURL, getJwtSignupLifetime, getJwtSignupSecret } from '../../config';
/** /**
* Delete organization membership with id [membershipOrgId] from organization * Delete organization membership with id [membershipOrgId] from organization
@@ -178,7 +178,7 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
organizationName: organization.name, organizationName: organization.name,
email: inviteeEmail, email: inviteeEmail,
token, token,
callback_url: infisical.get('SITE_URL') + '/signupinvite' callback_url: getSiteURL() + '/signupinvite'
} }
}); });
} }
@@ -250,8 +250,8 @@ export const verifyUserToOrganization = async (req: Request, res: Response) => {
payload: { payload: {
userId: user._id.toString() userId: user._id.toString()
}, },
expiresIn: infisical.get('JWT_SIGNUP_LIFETIME')!, expiresIn: getJwtSignupLifetime(),
secret: infisical.get('JWT_SIGNUP_SECRET')! secret: getJwtSignupSecret()
}); });
} catch (err) { } catch (err) {
Sentry.setUser(null); Sentry.setUser(null);
@@ -1,4 +1,3 @@
import infisical from 'infisical-node';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import Stripe from 'stripe'; import Stripe from 'stripe';
@@ -13,6 +12,7 @@ import { createOrganization as create } from '../../helpers/organization';
import { addMembershipsOrg } from '../../helpers/membershipOrg'; import { addMembershipsOrg } from '../../helpers/membershipOrg';
import { OWNER, ACCEPTED } from '../../variables'; import { OWNER, ACCEPTED } from '../../variables';
import _ from 'lodash'; import _ from 'lodash';
import { getStripeSecretKey, getSiteURL } from '../../config';
export const getOrganizations = async (req: Request, res: Response) => { export const getOrganizations = async (req: Request, res: Response) => {
let organizations; let organizations;
@@ -317,7 +317,7 @@ export const createOrganizationPortalSession = async (
) => { ) => {
let session; let session;
try { try {
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { const stripe = new Stripe(getStripeSecretKey(), {
apiVersion: '2022-08-01' apiVersion: '2022-08-01'
}); });
@@ -333,13 +333,13 @@ export const createOrganizationPortalSession = async (
customer: req.membershipOrg.organization.customerId, customer: req.membershipOrg.organization.customerId,
mode: 'setup', mode: 'setup',
payment_method_types: ['card'], payment_method_types: ['card'],
success_url: infisical.get('SITE_URL')! + '/dashboard', success_url: getSiteURL() + '/dashboard',
cancel_url: infisical.get('SITE_URL')! + '/dashboard' cancel_url: getSiteURL() + '/dashboard'
}); });
} else { } else {
session = await stripe.billingPortal.sessions.create({ session = await stripe.billingPortal.sessions.create({
customer: req.membershipOrg.organization.customerId, customer: req.membershipOrg.organization.customerId,
return_url: infisical.get('SITE_URL') + '/dashboard' return_url: getSiteURL() + '/dashboard'
}); });
} }
@@ -365,7 +365,7 @@ export const getOrganizationSubscriptions = async (
) => { ) => {
let subscriptions; let subscriptions;
try { try {
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { const stripe = new Stripe(getStripeSecretKey(), {
apiVersion: '2022-08-01' apiVersion: '2022-08-01'
}); });
@@ -1,4 +1,3 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
@@ -10,6 +9,7 @@ import { sendMail } from '../../helpers/nodemailer';
import { TokenService } from '../../services'; import { TokenService } from '../../services';
import { TOKEN_EMAIL_PASSWORD_RESET } from '../../variables'; import { TOKEN_EMAIL_PASSWORD_RESET } from '../../variables';
import { BadRequestError } from '../../utils/errors'; import { BadRequestError } from '../../utils/errors';
import { getSiteURL, getJwtSignupLifetime, getJwtSignupSecret } from '../../config';
/** /**
* Password reset step 1: Send email verification link to email [email] * Password reset step 1: Send email verification link to email [email]
@@ -44,7 +44,7 @@ export const emailPasswordReset = async (req: Request, res: Response) => {
substitutions: { substitutions: {
email, email,
token, token,
callback_url: infisical.get('SITE_URL')! + '/password-reset' callback_url: getSiteURL() + '/password-reset'
} }
}); });
} catch (err) { } catch (err) {
@@ -91,8 +91,8 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => {
payload: { payload: {
userId: user._id.toString() userId: user._id.toString()
}, },
expiresIn: infisical.get('JWT_SIGNUP_LIFETIME')!, expiresIn: getJwtSignupLifetime(),
secret: infisical.get('JWT_SIGNUP_SECRET')! secret: getJwtSignupSecret()
}); });
} catch (err) { } catch (err) {
Sentry.setUser(null); Sentry.setUser(null);
@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { ServiceToken } from '../../models'; import { ServiceToken } from '../../models';
import { createToken } from '../../helpers/auth'; import { createToken } from '../../helpers/auth';
import { getJwtServiceSecret } from '../../config';
/** /**
* Return service token on request * Return service token on request
@@ -61,7 +61,7 @@ export const createServiceToken = async (req: Request, res: Response) => {
workspaceId workspaceId
}, },
expiresIn: expiresIn, expiresIn: expiresIn,
secret: infisical.get('JWT_SERVICE_SECRET')! secret: getJwtServiceSecret()
}); });
} catch (err) { } catch (err) {
return res.status(400).send({ return res.status(400).send({
@@ -1,4 +1,3 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import { User } from '../../models'; import { User } from '../../models';
@@ -8,6 +7,7 @@ import {
} from '../../helpers/signup'; } from '../../helpers/signup';
import { createToken } from '../../helpers/auth'; import { createToken } from '../../helpers/auth';
import { BadRequestError } from '../../utils/errors'; import { BadRequestError } from '../../utils/errors';
import { getInviteOnlySignup, getJwtSignupLifetime, getJwtSignupSecret } from '../../config';
/** /**
* Signup step 1: Initialize account for user under email [email] and send a verification code * 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 { try {
email = req.body.email; email = req.body.email;
if (infisical.get('INVITE_ONLY_SIGNUP') || false) { if (getInviteOnlySignup() || false) {
// Only one user can create an account without being invited. The rest need to be invited in order to make an account // 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({}) const userCount = await User.countDocuments({})
if (userCount != 0) { if (userCount != 0) {
@@ -91,8 +91,8 @@ export const verifyEmailSignup = async (req: Request, res: Response) => {
payload: { payload: {
userId: user._id.toString() userId: user._id.toString()
}, },
expiresIn: infisical.get('JWT_SIGNUP_LIFETIME')!, expiresIn: getJwtSignupLifetime(),
secret: infisical.get('JWT_SIGNUP_SECRET')! secret: getJwtSignupSecret()
}); });
} catch (err) { } catch (err) {
Sentry.setUser(null); Sentry.setUser(null);
@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import Stripe from 'stripe'; import Stripe from 'stripe';
import { getStripeSecretKey, getStripeWebhookSecret } from '../../config';
/** /**
* Handle service provisioning/un-provisioning via Stripe * Handle service provisioning/un-provisioning via Stripe
@@ -13,7 +13,7 @@ export const handleWebhook = async (req: Request, res: Response) => {
let event; let event;
try { try {
// check request for valid stripe signature // check request for valid stripe signature
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { const stripe = new Stripe(getStripeSecretKey(), {
apiVersion: '2022-08-01' apiVersion: '2022-08-01'
}); });
@@ -21,7 +21,7 @@ export const handleWebhook = async (req: Request, res: Response) => {
event = stripe.webhooks.constructEvent( event = stripe.webhooks.constructEvent(
req.body, req.body,
sig, sig,
infisical.get('STRIPE_WEBHOOK_SECRET')! getStripeWebhookSecret()
); );
} catch (err) { } catch (err) {
Sentry.setUser({ email: req.user.email }); Sentry.setUser({ email: req.user.email });
@@ -1,11 +1,11 @@
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import infisical from 'infisical-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';
import { import {
APIKeyData APIKeyData
} from '../../models'; } from '../../models';
import { getSaltRounds } from '../../config';
/** /**
* Return API key data for user with id [req.user_id] * Return API key data for user with id [req.user_id]
@@ -43,7 +43,7 @@ export const createAPIKeyData = async (req: Request, res: Response) => {
const { name, expiresIn } = req.body; const { name, expiresIn } = req.body;
const secret = crypto.randomBytes(16).toString('hex'); const secret = crypto.randomBytes(16).toString('hex');
const secretHash = await bcrypt.hash(secret, parseInt(infisical.get('SALT_ROUNDS')!) || 10); const secretHash = await bcrypt.hash(secret, getSaltRounds());
const expiresAt = new Date(); const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn); expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);
+10 -7
View File
@@ -1,4 +1,3 @@
import infisical from 'infisical-node';
/* 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';
@@ -17,6 +16,11 @@ import {
ACTION_LOGIN ACTION_LOGIN
} from '../../variables'; } from '../../variables';
import { getChannelFromUserAgent } from '../../utils/posthog'; // TODO: move this import { getChannelFromUserAgent } from '../../utils/posthog'; // TODO: move this
import {
getNodeEnv,
getJwtMfaLifetime,
getJwtMfaSecret
} from '../../config';
declare module 'jsonwebtoken' { declare module 'jsonwebtoken' {
export interface UserIDJwtPayload extends jwt.JwtPayload { export interface UserIDJwtPayload extends jwt.JwtPayload {
@@ -120,8 +124,8 @@ export const login2 = async (req: Request, res: Response) => {
payload: { payload: {
userId: user._id.toString() userId: user._id.toString()
}, },
expiresIn: infisical.get('JWT_MFA_LIFETIME')!, expiresIn: getJwtMfaLifetime(),
secret: infisical.get('JWT_MFA_SECRET')! secret: getJwtMfaSecret()
}); });
const code = await TokenService.createToken({ const code = await TokenService.createToken({
@@ -159,7 +163,7 @@ export const login2 = async (req: Request, res: Response) => {
httpOnly: true, httpOnly: true,
path: '/', path: '/',
sameSite: 'strict', sameSite: 'strict',
secure: infisical.get('NODE_ENV')! === 'production' ? true : false secure: getNodeEnv() === 'production' ? true : false
}); });
// case: user does not have MFA enablgged // case: user does not have MFA enablgged
@@ -298,7 +302,7 @@ export const verifyMfaToken = async (req: Request, res: Response) => {
httpOnly: true, httpOnly: true,
path: '/', path: '/',
sameSite: 'strict', sameSite: 'strict',
secure: infisical.get('NODE_ENV')! === 'production' ? true : false secure: getNodeEnv() === 'production' ? true : false
}); });
interface VerifyMfaTokenRes { interface VerifyMfaTokenRes {
@@ -341,5 +345,4 @@ export const verifyMfaToken = async (req: Request, res: Response) => {
}); });
return res.status(200).send(resObj); return res.status(200).send(resObj);
} }
@@ -1,5 +1,4 @@
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import infisical from 'infisical-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';
@@ -8,6 +7,7 @@ import {
} from '../../models'; } from '../../models';
import { userHasWorkspaceAccess } from '../../ee/helpers/checkMembershipPermissions'; import { userHasWorkspaceAccess } from '../../ee/helpers/checkMembershipPermissions';
import { ABILITY_READ } from '../../variables/organization'; import { ABILITY_READ } from '../../variables/organization';
import { getSaltRounds } from '../../config';
/** /**
* Return service token data associated with service token on request * Return service token data associated with service token on request
@@ -73,7 +73,7 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
} }
const secret = crypto.randomBytes(16).toString('hex'); const secret = crypto.randomBytes(16).toString('hex');
const secretHash = await bcrypt.hash(secret, parseInt(infisical.get('SALT_ROUNDS')!) || 10); const secretHash = await bcrypt.hash(secret, getSaltRounds());
const expiresAt = new Date(); const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn); expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);
@@ -140,4 +140,4 @@ export const deleteServiceTokenData = async (req: Request, res: Response) => {
function UnauthorizedRequestError(arg0: { message: string; }) { function UnauthorizedRequestError(arg0: { message: string; }) {
throw new Error('Function not implemented.'); throw new Error('Function not implemented.');
} }
@@ -1,4 +1,3 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import { User, MembershipOrg } from '../../models'; import { User, MembershipOrg } from '../../models';
@@ -9,6 +8,7 @@ import {
import { issueAuthTokens } from '../../helpers/auth'; import { issueAuthTokens } from '../../helpers/auth';
import { INVITED, ACCEPTED } from '../../variables'; import { INVITED, ACCEPTED } from '../../variables';
import request from '../../config/request'; import request from '../../config/request';
import { getNodeEnv } from '../../config';
/** /**
* Complete setting up user by adding their personal and auth information as part of the * Complete setting up user by adding their personal and auth information as part of the
@@ -127,7 +127,7 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
httpOnly: true, httpOnly: true,
path: '/', path: '/',
sameSite: 'strict', sameSite: 'strict',
secure: infisical.get('NODE_ENV')! === 'production' ? true : false secure: getNodeEnv() === 'production' ? true : false
}); });
} catch (err) { } catch (err) {
Sentry.setUser(null); Sentry.setUser(null);
@@ -232,7 +232,7 @@ export const completeAccountInvite = async (req: Request, res: Response) => {
httpOnly: true, httpOnly: true,
path: '/', path: '/',
sameSite: 'strict', sameSite: 'strict',
secure: infisical.get('NODE_ENV')! === 'production' ? true : false secure: getNodeEnv() === 'production' ? true : false
}); });
} catch (err) { } catch (err) {
Sentry.setUser(null); Sentry.setUser(null);
@@ -1,7 +1,7 @@
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import infisical from 'infisical-node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import Stripe from 'stripe'; import Stripe from 'stripe';
import { getStripeSecretKey, getStripeWebhookSecret } from '../../../config';
/** /**
* Handle service provisioning/un-provisioning via Stripe * Handle service provisioning/un-provisioning via Stripe
@@ -12,7 +12,7 @@ import Stripe from 'stripe';
export const handleWebhook = async (req: Request, res: Response) => { export const handleWebhook = async (req: Request, res: Response) => {
let event; let event;
try { try {
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { const stripe = new Stripe(getStripeSecretKey(), {
apiVersion: '2022-08-01' apiVersion: '2022-08-01'
}); });
@@ -21,7 +21,7 @@ export const handleWebhook = async (req: Request, res: Response) => {
event = stripe.webhooks.constructEvent( event = stripe.webhooks.constructEvent(
req.body, req.body,
sig, sig,
infisical.get('STRIPE_WEBHOOK_SECRET')! getStripeWebhookSecret()
); );
} catch (err) { } catch (err) {
Sentry.setUser({ email: req.user.email }); Sentry.setUser({ email: req.user.email });
+11 -6
View File
@@ -1,5 +1,4 @@
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import infisical from 'infisical-node';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import bcrypt from 'bcrypt'; import bcrypt from 'bcrypt';
import { import {
@@ -15,6 +14,12 @@ import {
UnauthorizedRequestError, UnauthorizedRequestError,
BadRequestError BadRequestError
} from '../utils/errors'; } from '../utils/errors';
import {
getJwtAuthLifetime,
getJwtAuthSecret,
getJwtRefreshLifetime,
getJwtRefreshSecret
} from '../config';
/** /**
* *
@@ -88,7 +93,7 @@ const getAuthUserPayload = async ({
let user; let user;
try { try {
const decodedToken = <jwt.UserIDJwtPayload>( const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(authTokenValue, infisical.get('JWT_AUTH_SECRET')!) jwt.verify(authTokenValue, getJwtAuthSecret())
); );
user = await User.findOne({ user = await User.findOne({
@@ -219,16 +224,16 @@ const issueAuthTokens = async ({ userId }: { userId: string }) => {
payload: { payload: {
userId userId
}, },
expiresIn: infisical.get('JWT_AUTH_LIFETIME')!, expiresIn: getJwtAuthLifetime(),
secret: infisical.get('JWT_AUTH_SECRET')! secret: getJwtAuthSecret()
}); });
refreshToken = createToken({ refreshToken = createToken({
payload: { payload: {
userId userId
}, },
expiresIn: infisical.get('JWT_REFRESH_LIFETIME')!, expiresIn: getJwtRefreshLifetime(),
secret: infisical.get('JWT_REFRESH_SECRET')! secret: getJwtRefreshSecret()
}); });
} catch (err) { } catch (err) {
Sentry.setUser(null); Sentry.setUser(null);
+3 -3
View File
@@ -1,5 +1,4 @@
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import infisical from 'infisical-node';
import { import {
Bot, Bot,
BotKey, BotKey,
@@ -14,6 +13,7 @@ import {
decryptAsymmetric decryptAsymmetric
} from '../utils/crypto'; } from '../utils/crypto';
import { SECRET_SHARED } from '../variables'; import { SECRET_SHARED } from '../variables';
import { getEncryptionKey } from '../config';
/** /**
* Create an inactive bot with name [name] for workspace with id [workspaceId] * Create an inactive bot with name [name] for workspace with id [workspaceId]
@@ -33,7 +33,7 @@ const createBot = async ({
const { publicKey, privateKey } = generateKeyPair(); const { publicKey, privateKey } = generateKeyPair();
const { ciphertext, iv, tag } = encryptSymmetric({ const { ciphertext, iv, tag } = encryptSymmetric({
plaintext: privateKey, plaintext: privateKey,
key: infisical.get('ENCRYPTION_KEY')! key: getEncryptionKey()
}); });
bot = await new Bot({ bot = await new Bot({
@@ -130,7 +130,7 @@ const getKey = async ({ workspaceId }: { workspaceId: string }) => {
ciphertext: bot.encryptedPrivateKey, ciphertext: bot.encryptedPrivateKey,
iv: bot.iv, iv: bot.iv,
tag: bot.tag, tag: bot.tag,
key: infisical.get('ENCRYPTION_KEY')! key: getEncryptionKey()
}); });
key = decryptAsymmetric({ key = decryptAsymmetric({
+2 -2
View File
@@ -1,9 +1,9 @@
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import infisical from 'infisical-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';
import nodemailer from 'nodemailer'; import nodemailer from 'nodemailer';
import { getSmtpFromName, getSmtpFromAddress } from '../config';
let smtpTransporter: nodemailer.Transporter; let smtpTransporter: nodemailer.Transporter;
@@ -34,7 +34,7 @@ const sendMail = async ({
const htmlToSend = temp(substitutions); const htmlToSend = temp(substitutions);
await smtpTransporter.sendMail({ await smtpTransporter.sendMail({
from: `"${infisical.get('SMTP_FROM_NAME')!}" <${infisical.get('SMTP_FROM_ADDRESS')!}>`, from: `"${getSmtpFromName()}" <${getSmtpFromAddress()}>`,
to: recipients.join(', '), to: recipients.join(', '),
subject: subjectLine, subject: subjectLine,
html: htmlToSend html: htmlToSend
+14 -9
View File
@@ -1,9 +1,14 @@
import infisical from 'infisical-node';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import Stripe from 'stripe'; import Stripe from 'stripe';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import { ACCEPTED } from '../variables'; import { ACCEPTED } from '../variables';
import { Organization, MembershipOrg } from '../models'; import { Organization, MembershipOrg } from '../models';
import {
getStripeSecretKey,
getStripeProductPro,
getStripeProductTeam,
getStripeProductStarter
} from '../config';
/** /**
* Create an organization with name [name] * Create an organization with name [name]
@@ -22,11 +27,11 @@ const createOrganization = async ({
let organization; let organization;
try { try {
// register stripe account // register stripe account
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { const stripe = new Stripe(getStripeSecretKey(), {
apiVersion: '2022-08-01' apiVersion: '2022-08-01'
}); });
if (infisical.get('STRIPE_SECRET_KEY')) { if (getStripeSecretKey()) {
const customer = await stripe.customers.create({ const customer = await stripe.customers.create({
email, email,
description: name description: name
@@ -76,14 +81,14 @@ const initSubscriptionOrg = async ({
if (organization) { if (organization) {
if (organization.customerId) { if (organization.customerId) {
// initialize starter subscription with quantity of 0 // initialize starter subscription with quantity of 0
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { const stripe = new Stripe(getStripeSecretKey(), {
apiVersion: '2022-08-01' apiVersion: '2022-08-01'
}); });
const productToPriceMap = { const productToPriceMap = {
starter: infisical.get('STRIPE_PRODUCT_STARTER')!, starter: getStripeProductStarter(),
team: infisical.get('STRIPE_PRODUCT_TEAM')!, team: getStripeProductTeam(),
pro: infisical.get('STRIPE_PRODUCT_PRO')! pro: getStripeProductPro()
}; };
stripeSubscription = await stripe.subscriptions.create({ stripeSubscription = await stripe.subscriptions.create({
@@ -138,7 +143,7 @@ const updateSubscriptionOrgQuantity = async ({
status: ACCEPTED status: ACCEPTED
}); });
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { const stripe = new Stripe(getStripeSecretKey(), {
apiVersion: '2022-08-01' apiVersion: '2022-08-01'
}); });
@@ -170,4 +175,4 @@ export {
createOrganization, createOrganization,
initSubscriptionOrg, initSubscriptionOrg,
updateSubscriptionOrgQuantity updateSubscriptionOrgQuantity
}; };
+2 -2
View File
@@ -1,5 +1,4 @@
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import infisical from 'infisical-node';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import { TokenData } from '../models'; import { TokenData } from '../models';
import crypto from 'crypto'; import crypto from 'crypto';
@@ -11,6 +10,7 @@ import {
TOKEN_EMAIL_PASSWORD_RESET TOKEN_EMAIL_PASSWORD_RESET
} from '../variables'; } from '../variables';
import { UnauthorizedRequestError } from '../utils/errors'; import { UnauthorizedRequestError } from '../utils/errors';
import { getSaltRounds } from '../config';
/** /**
* Create and store a token in the database for purpose [type] * Create and store a token in the database for purpose [type]
@@ -84,7 +84,7 @@ const createTokenHelper = async ({
const query: TokenDataQuery = { type }; const query: TokenDataQuery = { type };
const update: TokenDataUpdate = { const update: TokenDataUpdate = {
type, type,
tokenHash: await bcrypt.hash(token, parseInt(infisical.get('SALT_ROUNDS')!) || 10), tokenHash: await bcrypt.hash(token, getSaltRounds()),
expiresAt expiresAt
} }
+18 -9
View File
@@ -63,8 +63,17 @@ import { healthCheck } from './routes/status';
import { getLogger } from './utils/logger'; import { getLogger } from './utils/logger';
import { RouteNotFoundError } from './utils/errors'; import { RouteNotFoundError } from './utils/errors';
import { requestErrorHandler } from './middleware/requestErrorHandler'; import { requestErrorHandler } from './middleware/requestErrorHandler';
import {
getMongoURL,
getNodeEnv,
getPort,
getSentryDSN,
getSiteURL
} from './config';
const main = async () => { const main = async () => {
// TODO 1: handle case of empty string token
// TODO 2: handle case of undefined token
const client = await infisical.connect({ const client = await infisical.connect({
token: process.env.INFISICAL_TOKEN!, token: process.env.INFISICAL_TOKEN!,
debug: true debug: true
@@ -73,13 +82,13 @@ const main = async () => {
logTelemetryMessage(); logTelemetryMessage();
setTransporter(initSmtp()); setTransporter(initSmtp());
await DatabaseService.initDatabase(infisical.get('MONGO_URL')!); await DatabaseService.initDatabase(getMongoURL());
if (infisical.get('NODE_ENV') !== 'test') { if (getNodeEnv() !== 'test') {
Sentry.init({ Sentry.init({
dsn: infisical.get('SENTRY_DSN') as string, dsn: getSentryDSN(),
tracesSampleRate: 1.0, tracesSampleRate: 1.0,
debug: infisical.get('NODE_ENV') === 'production' ? false : true, debug: getNodeEnv() === 'production' ? false : true,
environment: infisical.get('NODE_ENV') as string environment: getNodeEnv()
}); });
} }
@@ -91,13 +100,13 @@ const main = async () => {
app.use( app.use(
cors({ cors({
credentials: true, credentials: true,
origin: infisical.get('SITE_URL') as string origin: getSiteURL()
}) })
); );
app.use(requestIp.mw()); app.use(requestIp.mw());
if (infisical.get('NODE_ENV') === 'production') { if (getNodeEnv() === 'production') {
// enable app-wide rate-limiting + helmet security // enable app-wide rate-limiting + helmet security
// in production // in production
app.disable('x-powered-by'); app.disable('x-powered-by');
@@ -157,9 +166,9 @@ const main = async () => {
app.use(requestErrorHandler) app.use(requestErrorHandler)
const server = app.listen(Number(infisical.get('PORT')) || 4000, () => { const server = app.listen(getPort(), () => {
createTestUserForDevelopment(); createTestUserForDevelopment();
getLogger("backend-main").info(`Server started listening at port ${Number(infisical.get('PORT')) || 4000}`) getLogger("backend-main").info(`Server started listening at port ${getPort()}`)
}); });
setUpHealthEndpoint(server); setUpHealthEndpoint(server);
+30 -17
View File
@@ -1,4 +1,3 @@
import infisical from 'infisical-node';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import request from '../config/request'; import request from '../config/request';
import { import {
@@ -15,6 +14,20 @@ import {
INTEGRATION_GITHUB_TOKEN_URL, INTEGRATION_GITHUB_TOKEN_URL,
INTEGRATION_GITLAB_TOKEN_URL INTEGRATION_GITLAB_TOKEN_URL
} from '../variables'; } from '../variables';
import {
getSiteURL,
getClientIdAzure,
getClientSecretAzure,
getClientSecretHeroku,
getClientIdVercel,
getClientSecretVercel,
getClientIdNetlify,
getClientSecretNetlify,
getClientIdGitHub,
getClientSecretGitHub,
getClientIdGitLab,
getClientSecretGitLab
} from '../config';
interface ExchangeCodeAzureResponse { interface ExchangeCodeAzureResponse {
token_type: string; token_type: string;
@@ -146,9 +159,9 @@ const exchangeCodeAzure = async ({
grant_type: 'authorization_code', grant_type: 'authorization_code',
code: code, code: code,
scope: 'https://vault.azure.net/.default openid offline_access', scope: 'https://vault.azure.net/.default openid offline_access',
client_id: infisical.get('CLIENT_ID_AZURE')!, client_id: getClientIdAzure(),
client_secret: infisical.get('CLIENT_SECRET_AZURE')!, client_secret: getClientSecretAzure(),
redirect_uri: `${infisical.get('SITE_URL')!}/integrations/azure-key-vault/oauth2/callback` redirect_uri: `${getSiteURL()}/integrations/azure-key-vault/oauth2/callback`
} as any) } as any)
)).data; )).data;
@@ -191,7 +204,7 @@ const exchangeCodeHeroku = async ({
new URLSearchParams({ new URLSearchParams({
grant_type: 'authorization_code', grant_type: 'authorization_code',
code: code, code: code,
client_secret: infisical.get('CLIENT_SECRET_HEROKU')! client_secret: getClientSecretHeroku()
} as any) } as any)
)).data; )).data;
@@ -229,9 +242,9 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => {
INTEGRATION_VERCEL_TOKEN_URL, INTEGRATION_VERCEL_TOKEN_URL,
new URLSearchParams({ new URLSearchParams({
code: code, code: code,
client_id: infisical.get('CLIENT_ID_VERCEL')!, client_id: getClientIdVercel(),
client_secret: infisical.get('CLIENT_SECRET_VERCEL')!, client_secret: getClientSecretVercel(),
redirect_uri: `${infisical.get('SITE_URL')!}/integrations/vercel/oauth2/callback` redirect_uri: `${getSiteURL()}/integrations/vercel/oauth2/callback`
} as any) } as any)
) )
).data; ).data;
@@ -269,9 +282,9 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => {
new URLSearchParams({ new URLSearchParams({
grant_type: 'authorization_code', grant_type: 'authorization_code',
code: code, code: code,
client_id: infisical.get('CLIENT_ID_NETLIFY')!, client_id: getClientIdNetlify(),
client_secret: infisical.get('CLIENT_SECRET_NETLIFY')!, client_secret: getClientSecretNetlify(),
redirect_uri: `${infisical.get('SITE_URL')!}/integrations/netlify/oauth2/callback` redirect_uri: `${getSiteURL()}/integrations/netlify/oauth2/callback`
} as any) } as any)
) )
).data; ).data;
@@ -320,10 +333,10 @@ const exchangeCodeGithub = async ({ code }: { code: string }) => {
res = ( res = (
await request.get(INTEGRATION_GITHUB_TOKEN_URL, { await request.get(INTEGRATION_GITHUB_TOKEN_URL, {
params: { params: {
client_id: infisical.get('CLIENT_ID_GITHUB')!, client_id: getClientIdGitHub(),
client_secret: infisical.get('CLIENT_SECRET_GITHUB')!, client_secret: getClientSecretGitHub(),
code: code, code: code,
redirect_uri: `${infisical.get('SITE_URL')!}/integrations/github/oauth2/callback` redirect_uri: `${getSiteURL()}/integrations/github/oauth2/callback`
}, },
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
@@ -366,9 +379,9 @@ const exchangeCodeGitlab = async ({ code }: { code: string }) => {
new URLSearchParams({ new URLSearchParams({
grant_type: 'authorization_code', grant_type: 'authorization_code',
code: code, code: code,
client_id: infisical.get('CLIENT_ID_GITLAB')!, client_id: getClientIdGitLab(),
client_secret: infisical.get('CLIENT_SECRET_GITLAB')!, client_secret: getClientSecretGitLab(),
redirect_uri: `${infisical.get('SITE_URL')}/integrations/gitlab/oauth2/callback` redirect_uri: `${getSiteURL()}/integrations/gitlab/oauth2/callback`
} as any), } as any),
{ {
headers: { headers: {
+14 -14
View File
@@ -1,4 +1,3 @@
import infisical from 'infisical-node';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import request from '../config/request'; import request from '../config/request';
import { import {
@@ -9,13 +8,6 @@ import {
INTEGRATION_HEROKU, INTEGRATION_HEROKU,
INTEGRATION_GITLAB, INTEGRATION_GITLAB,
} from '../variables'; } from '../variables';
// import {
// CLIENT_ID_AZURE,
// CLIENT_ID_GITLAB,
// CLIENT_SECRET_AZURE,
// CLIENT_SECRET_HEROKU,
// CLIENT_SECRET_GITLAB
// } from '../config';
import { import {
INTEGRATION_AZURE_TOKEN_URL, INTEGRATION_AZURE_TOKEN_URL,
INTEGRATION_HEROKU_TOKEN_URL, INTEGRATION_HEROKU_TOKEN_URL,
@@ -24,6 +16,14 @@ import {
import { import {
IntegrationService IntegrationService
} from '../services'; } from '../services';
import {
getSiteURL,
getClientIdAzure,
getClientSecretAzure,
getClientSecretHeroku,
getClientIdGitLab,
getClientSecretGitLab
} from '../config';
interface RefreshTokenAzureResponse { interface RefreshTokenAzureResponse {
token_type: string; token_type: string;
@@ -133,11 +133,11 @@ const exchangeRefreshAzure = async ({
const { data }: { data: RefreshTokenAzureResponse } = await request.post( const { data }: { data: RefreshTokenAzureResponse } = await request.post(
INTEGRATION_AZURE_TOKEN_URL, INTEGRATION_AZURE_TOKEN_URL,
new URLSearchParams({ new URLSearchParams({
client_id: infisical.get('CLIENT_ID_AZURE')!, client_id: getClientIdAzure(),
scope: 'openid offline_access', scope: 'openid offline_access',
refresh_token: refreshToken, refresh_token: refreshToken,
grant_type: 'refresh_token', grant_type: 'refresh_token',
client_secret: infisical.get('CLIENT_SECRET_AZURE')! client_secret: getClientSecretAzure()
} as any) } as any)
); );
@@ -180,7 +180,7 @@ const exchangeRefreshHeroku = async ({
new URLSearchParams({ new URLSearchParams({
grant_type: 'refresh_token', grant_type: 'refresh_token',
refresh_token: refreshToken, refresh_token: refreshToken,
client_secret: infisical.get('CLIENT_SECRET_HEROKU')! client_secret: getClientSecretHeroku()
} as any) } as any)
); );
@@ -223,9 +223,9 @@ const exchangeRefreshGitLab = async ({
new URLSearchParams({ new URLSearchParams({
grant_type: 'refresh_token', grant_type: 'refresh_token',
refresh_token: refreshToken, refresh_token: refreshToken,
client_id: infisical.get('CLIENT_ID_GITLAB')!, client_id: getClientIdGitLab,
client_secret: infisical.get('CLIENT_SECRET_GITLAB')!, client_secret: getClientSecretGitLab(),
redirect_uri: `${infisical.get('SITE_URL')!}/integrations/gitlab/oauth2/callback` redirect_uri: `${getSiteURL()}/integrations/gitlab/oauth2/callback`
} as any), } as any),
{ {
headers: { headers: {
@@ -1,13 +1,13 @@
import infisical from 'infisical-node';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import { ErrorRequestHandler } from "express"; import { ErrorRequestHandler } from "express";
import { InternalServerError, UnauthorizedRequestError } from "../utils/errors"; import { InternalServerError } from "../utils/errors";
import { getLogger } from "../utils/logger"; import { getLogger } from "../utils/logger";
import RequestError, { LogLevel } from "../utils/requestError"; import RequestError, { LogLevel } from "../utils/requestError";
import { getNodeEnv } from '../config';
export const requestErrorHandler: ErrorRequestHandler = (error: RequestError | Error, req, res, next) => { export const requestErrorHandler: ErrorRequestHandler = (error: RequestError | Error, req, res, next) => {
if (res.headersSent) return next(); if (res.headersSent) return next();
if (infisical.get('NODE_ENV')! !== "production") { if (getNodeEnv() !== "production") {
/* eslint-disable no-console */ /* eslint-disable no-console */
console.log(error) console.log(error)
/* eslint-enable no-console */ /* eslint-enable no-console */
+2 -2
View File
@@ -1,8 +1,8 @@
import infisical from 'infisical-node';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express'; import { Request, Response, NextFunction } from 'express';
import { User } from '../models'; import { User } from '../models';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors'; import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
import { getJwtMfaSecret } from '../config';
declare module 'jsonwebtoken' { declare module 'jsonwebtoken' {
export interface UserIDJwtPayload extends jwt.JwtPayload { export interface UserIDJwtPayload extends jwt.JwtPayload {
@@ -26,7 +26,7 @@ const requireMfaAuth = async (
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'})) if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
const decodedToken = <jwt.UserIDJwtPayload>( const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(AUTH_TOKEN_VALUE, infisical.get('JWT_MFA_SECRET')!) jwt.verify(AUTH_TOKEN_VALUE, getJwtMfaSecret())
); );
const user = await User.findOne({ const user = await User.findOne({
@@ -1,8 +1,8 @@
import infisical from 'infisical-node';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express'; import { Request, Response, NextFunction } from 'express';
import { ServiceToken } from '../models'; import { ServiceToken } from '../models';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors'; import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
import { getJwtServiceSecret } from '../config';
// TODO: deprecate // TODO: deprecate
declare module 'jsonwebtoken' { declare module 'jsonwebtoken' {
@@ -33,7 +33,7 @@ const requireServiceTokenAuth = async (
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'})) if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
const decodedToken = <jwt.UserIDJwtPayload>( const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(AUTH_TOKEN_VALUE, infisical.get('JWT_SERVICE_SECRET')!) jwt.verify(AUTH_TOKEN_VALUE, getJwtServiceSecret())
); );
const serviceToken = await ServiceToken.findOne({ const serviceToken = await ServiceToken.findOne({
+2 -2
View File
@@ -1,8 +1,8 @@
import infisical from 'infisical-node';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express'; import { Request, Response, NextFunction } from 'express';
import { User } from '../models'; import { User } from '../models';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors'; import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
import { getJwtSignupSecret } from '../config';
declare module 'jsonwebtoken' { declare module 'jsonwebtoken' {
export interface UserIDJwtPayload extends jwt.JwtPayload { export interface UserIDJwtPayload extends jwt.JwtPayload {
@@ -27,7 +27,7 @@ const requireSignupAuth = async (
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'})) if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
const decodedToken = <jwt.UserIDJwtPayload>( const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(AUTH_TOKEN_VALUE, infisical.get('JWT_SIGNUP_SECRET')!) jwt.verify(AUTH_TOKEN_VALUE, getJwtSignupSecret())
); );
const user = await User.findOne({ const user = await User.findOne({
+10 -7
View File
@@ -1,13 +1,17 @@
import infisical from 'infisical-node';
import { PostHog } from 'posthog-node'; import { PostHog } from 'posthog-node';
import { getLogger } from '../utils/logger'; import { getLogger } from '../utils/logger';
import {
getNodeEnv,
getTelemetryEnabled,
getPostHogProjectApiKey,
getPostHogHost
} from '../config';
/** /**
* Logs telemetry enable/disable notice. * Logs telemetry enable/disable notice.
*/ */
const logTelemetryMessage = () => { const logTelemetryMessage = () => {
const TELEMETRY_ENABLED = infisical.get('TELEMETRY_ENABLED')! !== 'false' && true; if(!getTelemetryEnabled()){
if(!TELEMETRY_ENABLED){
getLogger("backend-main").info([ getLogger("backend-main").info([
"", "",
"To improve, Infisical collects telemetry data about general usage.", "To improve, Infisical collects telemetry data about general usage.",
@@ -23,11 +27,10 @@ const logTelemetryMessage = () => {
*/ */
const getPostHogClient = () => { const getPostHogClient = () => {
let postHogClient: any; let postHogClient: any;
const TELEMETRY_ENABLED = infisical.get('TELEMETRY_ENABLED')! !== 'false' && true; if (getNodeEnv() === 'production' && getTelemetryEnabled()) {
if (infisical.get('NODE_ENV') === 'production' && TELEMETRY_ENABLED) {
// case: enable opt-out telemetry in production // case: enable opt-out telemetry in production
postHogClient = new PostHog(infisical.get('POSTHOG_PROJECT_API_KEY')! || 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE', { postHogClient = new PostHog(getPostHogProjectApiKey(), {
host: infisical.get('POSTHOG_HOST')! host: getPostHogHost()
}); });
} }
+16 -10
View File
@@ -1,4 +1,3 @@
import infisical from 'infisical-node';
import nodemailer from 'nodemailer'; import nodemailer from 'nodemailer';
import { import {
SMTP_HOST_SENDGRID, SMTP_HOST_SENDGRID,
@@ -8,22 +7,29 @@ import {
} from '../variables'; } from '../variables';
import SMTPConnection from 'nodemailer/lib/smtp-connection'; import SMTPConnection from 'nodemailer/lib/smtp-connection';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import {
getSmtpHost,
getSmtpUsername,
getSmtpPassword,
getSmtpSecure,
getSmtpPort
} from '../config';
export const initSmtp = () => { export const initSmtp = () => {
const mailOpts: SMTPConnection.Options = { const mailOpts: SMTPConnection.Options = {
host: infisical.get('SMTP_HOST')!, host: getSmtpHost(),
port: parseInt(infisical.get('SMTP_PORT')!) port: getSmtpPort()
}; };
if (infisical.get('SMTP_USERNAME')! && infisical.get('SMTP_PASSWORD')!) { if (getSmtpUsername() && getSmtpPassword()) {
mailOpts.auth = { mailOpts.auth = {
user: infisical.get('SMTP_USERNAME')!, user: getSmtpUsername(),
pass: infisical.get('SMTP_PASSWORD')! pass: getSmtpPassword()
}; };
} }
if (infisical.get('SMTP_SECURE')! ? infisical.get('SMTP_SECURE')! === 'true' : false) { if (getSmtpSecure() ? getSmtpSecure() : false) {
switch (infisical.get('SMTP_HOST')!) { switch (getSmtpHost()) {
case SMTP_HOST_SENDGRID: case SMTP_HOST_SENDGRID:
mailOpts.requireTLS = true; mailOpts.requireTLS = true;
break; break;
@@ -46,7 +52,7 @@ export const initSmtp = () => {
} }
break; break;
default: default:
if (infisical.get('SMTP_HOST')!.includes('amazonaws.com')) { if (getSmtpHost().includes('amazonaws.com')) {
mailOpts.tls = { mailOpts.tls = {
ciphers: 'TLSv1.2' ciphers: 'TLSv1.2'
} }
@@ -67,7 +73,7 @@ export const initSmtp = () => {
.catch((err) => { .catch((err) => {
Sentry.setUser(null); Sentry.setUser(null);
Sentry.captureException( Sentry.captureException(
`SMTP - Failed to connect to ${infisical.get('SMTP_HOST')!}:${infisical.get('SMTP_PORT')!} \n\t${err}` `SMTP - Failed to connect to ${getSmtpHost()}:${getSmtpPort()} \n\t${err}`
); );
}); });
+2 -2
View File
@@ -4,12 +4,12 @@
* *
************************************************************************************************/ ************************************************************************************************/
import infisical from 'infisical-node';
import { Key, Membership, MembershipOrg, Organization, User, Workspace } from "../models"; import { Key, Membership, MembershipOrg, Organization, User, Workspace } from "../models";
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import { getNodeEnv } from '../config';
export const createTestUserForDevelopment = async () => { export const createTestUserForDevelopment = async () => {
if (infisical.get('NODE_ENV') === "development") { if (getNodeEnv() === "development") {
const testUserEmail = "[email protected]" const testUserEmail = "[email protected]"
const testUserPassword = "testInfisical1" const testUserPassword = "testInfisical1"
const testUserId = "63cefa6ec8d3175601cfa980" const testUserId = "63cefa6ec8d3175601cfa980"
+4 -4
View File
@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
/* eslint-disable no-console */ /* eslint-disable no-console */
import { createLogger, format, transports } from 'winston'; import { createLogger, format, transports } from 'winston';
import LokiTransport from 'winston-loki'; import LokiTransport from 'winston-loki';
import { getLokiHost, getNodeEnv } from '../config';
const { combine, colorize, label, printf, splat, timestamp } = format; const { combine, colorize, label, printf, splat, timestamp } = format;
@@ -25,10 +25,10 @@ const createLoggerWithLabel = (level: string, label: string) => {
}) })
] ]
//* Add LokiTransport if it's enabled //* Add LokiTransport if it's enabled
if(infisical.get('LOKI_HOST')! !== undefined){ if(getLokiHost() !== undefined){
_transports.push( _transports.push(
new LokiTransport({ new LokiTransport({
host: infisical.get('LOKI_HOST')!, host: getLokiHost(),
handleExceptions: true, handleExceptions: true,
handleRejections: true, handleRejections: true,
batching: true, batching: true,
@@ -40,7 +40,7 @@ const createLoggerWithLabel = (level: string, label: string) => {
labels: { labels: {
app: process.env.npm_package_name, app: process.env.npm_package_name,
version: process.env.npm_package_version, version: process.env.npm_package_version,
environment: infisical.get('NODE_ENV')! environment: getNodeEnv()
}, },
onConnectionError: (err: Error)=> console.error('Connection error while connecting to Loki Server.\n', err) onConnectionError: (err: Error)=> console.error('Connection error while connecting to Loki Server.\n', err)
}) })
+2 -3
View File
@@ -1,5 +1,5 @@
import infisical from 'infisical-node';
import { Request } from 'express' import { Request } from 'express'
import { getVerboseErrorOutput } from '../config';
export enum LogLevel { export enum LogLevel {
DEBUG = 100, DEBUG = 100,
@@ -87,8 +87,7 @@ export default class RequestError extends Error{
}, this.context) }, this.context)
//* Omit sensitive information from context that can leak internal workings of this program if user is not developer //* Omit sensitive information from context that can leak internal workings of this program if user is not developer
const VERBOSE_ERROR_OUTPUT = infisical.get('VERBOSE_ERROR_OUTPUT')! === 'true' && true; if(!getVerboseErrorOutput()){
if(!VERBOSE_ERROR_OUTPUT){
_context = this._omit(_context, [ _context = this._omit(_context, [
'stacktrace', 'stacktrace',
'exception', 'exception',
+14 -7
View File
@@ -1,4 +1,11 @@
import infisical from 'infisical-node'; import {
getClientIdHeroku,
getClientSlugVercel,
getClientIdNetlify,
getClientIdAzure,
getClientIdGitLab,
getClientIdGitHub
} from '../config';
// integrations // integrations
const INTEGRATION_AZURE_KEY_VAULT = 'azure-key-vault'; const INTEGRATION_AZURE_KEY_VAULT = 'azure-key-vault';
@@ -57,7 +64,7 @@ const getIntegrationOptions = () => {
image: 'Heroku.png', image: 'Heroku.png',
isAvailable: true, isAvailable: true,
type: 'oauth', type: 'oauth',
clientId: infisical.get('CLIENT_ID_HEROKU')!, clientId: getClientIdHeroku(),
docsLink: '' docsLink: ''
}, },
{ {
@@ -67,7 +74,7 @@ const getIntegrationOptions = () => {
isAvailable: true, isAvailable: true,
type: 'oauth', type: 'oauth',
clientId: '', clientId: '',
clientSlug: infisical.get('CLIENT_SLUG_VERCEL')!, clientSlug: getClientSlugVercel(),
docsLink: '' docsLink: ''
}, },
{ {
@@ -76,7 +83,7 @@ const getIntegrationOptions = () => {
image: 'Netlify.png', image: 'Netlify.png',
isAvailable: true, isAvailable: true,
type: 'oauth', type: 'oauth',
clientId: infisical.get('CLIENT_ID_NETLIFY')!, clientId: getClientIdNetlify(),
docsLink: '' docsLink: ''
}, },
{ {
@@ -85,7 +92,7 @@ const getIntegrationOptions = () => {
image: 'GitHub.png', image: 'GitHub.png',
isAvailable: true, isAvailable: true,
type: 'oauth', type: 'oauth',
clientId: infisical.get('CLIENT_ID_GITHUB')!, clientId: getClientIdGitHub(),
docsLink: '' docsLink: ''
}, },
{ {
@@ -130,7 +137,7 @@ const getIntegrationOptions = () => {
image: 'Microsoft Azure.png', image: 'Microsoft Azure.png',
isAvailable: true, isAvailable: true,
type: 'oauth', type: 'oauth',
clientId: infisical.get('CLIENT_ID_AZURE')!, clientId: getClientIdAzure(),
docsLink: '' docsLink: ''
}, },
{ {
@@ -148,7 +155,7 @@ const getIntegrationOptions = () => {
image: 'GitLab.png', image: 'GitLab.png',
isAvailable: true, isAvailable: true,
type: 'custom', type: 'custom',
clientId: infisical.get('CLIENT_ID_GITLAB'), clientId: getClientIdGitLab(),
docsLink: '' docsLink: ''
}, },
{ {
+7 -8
View File
@@ -59,17 +59,16 @@ infisical.connect({
Options: Options:
| Option | Description | Default Value | | Option | Description | Default Value |
| -------------------- | ----------------------------------------------------------- | --------------------------- | | -------------------- | --------------------------------------------------------- | --------------------------- |
| `token` | ❗️ An Infisical Token to be used to fetch secrets | `None` | | `token` | ❗️ An Infisical Token to be used to fetch secrets | `None` |
| `siteURL` | Site URL of Infisical to connect to | `https://app.infisical.com` | | `siteURL` | Site URL of Infisical to connect to | `https://app.infisical.com` |
| `attachToProcessEnv` | Whether or not to attach fetched secrets to `process.env` | `False` | | `attachToProcessEnv` | Whether or not to attach fetched secrets to `process.env` | `false` |
| `defaultValues` | Default values for secrets if they aren't fetched/passed in | `{}` |
## Access a Secret Value ## Access a Secret Value
```js ```js
const dbURL = infisical.getSecretValue("DB_URL"); const dbURL = infisical.get("DB_URL");
``` ```
## Example with Express ## Example with Express
@@ -81,7 +80,7 @@ const infisical = require("infisical-node");
app.get("/", (req, res) => { app.get("/", (req, res) => {
// access value // access value
const name = infisical.getSecret("NAME"); const name = infisical.get("NAME");
res.send(`Hello! My name is: ${name}`); res.send(`Hello! My name is: ${name}`);
}); });