From a6c8638345ea84f519954225b9ea7815ba9e660c Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Wed, 15 Mar 2023 00:09:40 +0700 Subject: [PATCH] Refactor infisical-node to config file for birds eye view of envars --- backend/src/config/index.ts | 150 ++++++------------ backend/src/controllers/v1/authController.ts | 17 +- .../controllers/v1/membershipController.ts | 4 +- .../controllers/v1/membershipOrgController.ts | 8 +- .../controllers/v1/organizationController.ts | 12 +- .../src/controllers/v1/passwordController.ts | 8 +- .../controllers/v1/serviceTokenController.ts | 4 +- .../src/controllers/v1/signupController.ts | 8 +- .../src/controllers/v1/stripeController.ts | 6 +- .../controllers/v2/apiKeyDataController.ts | 4 +- backend/src/controllers/v2/authController.ts | 17 +- .../v2/serviceTokenDataController.ts | 6 +- .../src/controllers/v2/signupController.ts | 6 +- .../src/ee/controllers/v1/stripeController.ts | 6 +- backend/src/helpers/auth.ts | 17 +- backend/src/helpers/bot.ts | 6 +- backend/src/helpers/nodemailer.ts | 4 +- backend/src/helpers/organization.ts | 23 +-- backend/src/helpers/token.ts | 4 +- backend/src/index.ts | 27 ++-- backend/src/integrations/exchange.ts | 47 ++++-- backend/src/integrations/refresh.ts | 28 ++-- backend/src/middleware/requestErrorHandler.ts | 6 +- backend/src/middleware/requireMfaAuth.ts | 4 +- .../src/middleware/requireServiceTokenAuth.ts | 4 +- backend/src/middleware/requireSignupAuth.ts | 4 +- backend/src/services/PostHogClient.ts | 17 +- backend/src/services/smtp.ts | 26 +-- backend/src/utils/addDevelopmentUser.ts | 4 +- backend/src/utils/logger.ts | 8 +- backend/src/utils/requestError.ts | 5 +- backend/src/variables/integration.ts | 21 ++- docs/sdk/overview/usage.mdx | 15 +- 33 files changed, 264 insertions(+), 262 deletions(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 06ad3a631..c4e072259 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -1,101 +1,49 @@ -// const PORT = process.env.PORT || 4000; -// const INVITE_ONLY_SIGNUP = process.env.INVITE_ONLY_SIGNUP == undefined ? false : process.env.INVITE_ONLY_SIGNUP -// const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY!; -// const SALT_ROUNDS = parseInt(process.env.SALT_ROUNDS!) || 10; -// const JWT_AUTH_LIFETIME = process.env.JWT_AUTH_LIFETIME! || '10d'; -// const JWT_AUTH_SECRET = process.env.JWT_AUTH_SECRET!; -// const JWT_MFA_LIFETIME = process.env.JWT_MFA_LIFETIME! || '5m'; -// const JWT_MFA_SECRET = process.env.JWT_MFA_SECRET!; -// const JWT_REFRESH_LIFETIME = process.env.JWT_REFRESH_LIFETIME! || '90d'; -// const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET!; -// const JWT_SERVICE_SECRET = process.env.JWT_SERVICE_SECRET!; -// const JWT_SIGNUP_LIFETIME = process.env.JWT_SIGNUP_LIFETIME! || '15m'; -// const JWT_SIGNUP_SECRET = process.env.JWT_SIGNUP_SECRET!; -// const MONGO_URL = process.env.MONGO_URL!; -// const NODE_ENV = process.env.NODE_ENV! || 'production'; -// const VERBOSE_ERROR_OUTPUT = process.env.VERBOSE_ERROR_OUTPUT! === 'true' && true; -// const LOKI_HOST = process.env.LOKI_HOST || undefined; -// const CLIENT_ID_AZURE = process.env.CLIENT_ID_AZURE!; -// const CLIENT_ID_HEROKU = process.env.CLIENT_ID_HEROKU!; -// const CLIENT_ID_VERCEL = process.env.CLIENT_ID_VERCEL!; -// const CLIENT_ID_NETLIFY = process.env.CLIENT_ID_NETLIFY!; -// const CLIENT_ID_GITHUB = process.env.CLIENT_ID_GITHUB!; -// const CLIENT_ID_GITLAB = process.env.CLIENT_ID_GITLAB!; -// const CLIENT_SECRET_AZURE = process.env.CLIENT_SECRET_AZURE!; -// const CLIENT_SECRET_HEROKU = process.env.CLIENT_SECRET_HEROKU!; -// const CLIENT_SECRET_VERCEL = process.env.CLIENT_SECRET_VERCEL!; -// const CLIENT_SECRET_NETLIFY = process.env.CLIENT_SECRET_NETLIFY!; -// const CLIENT_SECRET_GITHUB = process.env.CLIENT_SECRET_GITHUB!; -// const CLIENT_SECRET_GITLAB = process.env.CLIENT_SECRET_GITLAB; -// const CLIENT_SLUG_VERCEL = process.env.CLIENT_SLUG_VERCEL!; -// const POSTHOG_HOST = process.env.POSTHOG_HOST! || 'https://app.posthog.com'; -// const POSTHOG_PROJECT_API_KEY = - // process.env.POSTHOG_PROJECT_API_KEY! || - // 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE'; -// const SENTRY_DSN = process.env.SENTRY_DSN!; -// const SITE_URL = process.env.SITE_URL!; -// const SMTP_HOST = process.env.SMTP_HOST!; -// const SMTP_SECURE = process.env.SMTP_SECURE! === 'true' || false; -// const SMTP_PORT = parseInt(process.env.SMTP_PORT!) || 587; -// const SMTP_USERNAME = process.env.SMTP_USERNAME!; -// const SMTP_PASSWORD = process.env.SMTP_PASSWORD!; -// const SMTP_FROM_ADDRESS = process.env.SMTP_FROM_ADDRESS!; -// const SMTP_FROM_NAME = process.env.SMTP_FROM_NAME! || 'Infisical'; -// const STRIPE_PRODUCT_STARTER = process.env.STRIPE_PRODUCT_STARTER!; -// const STRIPE_PRODUCT_PRO = process.env.STRIPE_PRODUCT_PRO!; -// const STRIPE_PRODUCT_TEAM = process.env.STRIPE_PRODUCT_TEAM!; -// const STRIPE_PUBLISHABLE_KEY = process.env.STRIPE_PUBLISHABLE_KEY!; -// const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY!; -// const STRIPE_WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET!; -// 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, -}; +import infisical from 'infisical-node'; +export const getPort = () => infisical.get('PORT')! || 4000; +export const getInviteOnlySignup = () => infisical.get('INVITE_ONLY_SIGNUP')! == undefined ? false : process.env.INVITE_ONLY_SIGNUP; +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 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 getJwtSignupSecret = () => infisical.get('JWT_SIGNUP_SECRET')!; +export const getMongoURL = () => infisical.get('MONGO_URL')!; +export const getNodeEnv = () => infisical.get('NODE_ENV')!; +export const getVerboseErrorOutput = () => infisical.get('VERBOSE_ERROR_OUTPUT')! === 'true' && true; +export const getLokiHost = () => infisical.get('LOKI_HOST')!; +export const getClientIdAzure = () => infisical.get('CLIENT_ID_AZURE')!; +export const getClientIdHeroku = () => infisical.get('CLIENT_ID_HEROKU')!; +export const getClientIdVercel = () => infisical.get('CLIENT_ID_VERCEL')!; +export const getClientIdNetlify = () => infisical.get('CLIENT_ID_NETLIFY')!; +export const getClientIdGitHub = () => infisical.get('CLIENT_ID_GITHUB')!; +export const getClientIdGitLab = () => infisical.get('CLIENT_ID_GITLAB')!; +export const getClientSecretAzure = () => infisical.get('CLIENT_SECRET_AZURE')!; +export const getClientSecretHeroku = () => infisical.get('CLIENT_SECRET_HEROKU')!; +export const getClientSecretVercel = () => infisical.get('CLIENT_SECRET_VERCEL')!; +export const getClientSecretNetlify = () => infisical.get('CLIENT_SECRET_NETLIFY')!; +export const getClientSecretGitHub = () => infisical.get('CLIENT_SECRET_GITHUB')!; +export const getClientSecretGitLab = () => infisical.get('CLIENT_SECRET_GITLAB')!; +export const getClientSlugVercel = () => infisical.get('CLIENT_SLUG_VERCEL')!; +export const getPostHogHost = () => infisical.get('POSTHOG_HOST')! || 'https://app.posthog.com'; +export const getPostHogProjectApiKey = () => infisical.get('POSTHOG_PROJECT_API_KEY')! || 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE'; +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 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 getStripeProductStarter = () => infisical.get('STRIPE_PRODUCT_STARTER')!; +export const getStripeProductPro = () => infisical.get('STRIPE_PRODUCT_PRO')!; +export const getStripeProductTeam = () => infisical.get('STRIPE_PRODUCT_TEAM')!; +export const getStripePublishableKey = () => infisical.get('STRIPE_PUBLISHABLE_KEY')!; +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; \ No newline at end of file diff --git a/backend/src/controllers/v1/authController.ts b/backend/src/controllers/v1/authController.ts index 732715967..3c6ec523a 100644 --- a/backend/src/controllers/v1/authController.ts +++ b/backend/src/controllers/v1/authController.ts @@ -1,5 +1,4 @@ import * as Sentry from '@sentry/node'; -import infisical from 'infisical-node'; import { Request, Response } from 'express'; import jwt from 'jsonwebtoken'; import * as bigintConversion from 'bigint-conversion'; @@ -15,6 +14,12 @@ import { import { BadRequestError } from '../../utils/errors'; import { EELogService } from '../../ee/services'; import { getChannelFromUserAgent } from '../../utils/posthog'; // TODO: move this +import { + getNodeEnv, + getJwtRefreshSecret, + getJwtAuthLifetime, + getJwtAuthSecret +} from '../../config'; declare module 'jsonwebtoken' { export interface UserIDJwtPayload extends jwt.JwtPayload { @@ -121,7 +126,7 @@ export const login2 = async (req: Request, res: Response) => { httpOnly: true, path: '/', sameSite: 'strict', - secure: infisical.get('NODE_ENV')! === 'production' ? true : false + secure: getNodeEnv() === 'production' ? true : false }); const loginAction = await EELogService.createAction({ @@ -177,7 +182,7 @@ export const logout = async (req: Request, res: Response) => { httpOnly: true, path: '/', sameSite: 'strict', - secure: infisical.get('NODE_ENV') === 'production' ? true : false + secure: getNodeEnv() === 'production' ? true : false }); const logoutAction = await EELogService.createAction({ @@ -232,7 +237,7 @@ export const getNewToken = async (req: Request, res: Response) => { } const decodedToken = ( - jwt.verify(refreshToken, infisical.get('JWT_REFRESH_SECRET')!) + jwt.verify(refreshToken, getJwtRefreshSecret()) ); const user = await User.findOne({ @@ -247,8 +252,8 @@ export const getNewToken = async (req: Request, res: Response) => { payload: { userId: decodedToken.userId }, - expiresIn: infisical.get('JWT_AUTH_LIFETIME')!, - secret: infisical.get('JWT_AUTH_SECRET')! + expiresIn: getJwtAuthLifetime(), + secret: getJwtAuthSecret() }); return res.status(200).send({ diff --git a/backend/src/controllers/v1/membershipController.ts b/backend/src/controllers/v1/membershipController.ts index 11fc465c2..436be9dc4 100644 --- a/backend/src/controllers/v1/membershipController.ts +++ b/backend/src/controllers/v1/membershipController.ts @@ -1,4 +1,3 @@ -import infisical from 'infisical-node'; import * as Sentry from '@sentry/node'; import { Request, Response } from 'express'; import { Membership, MembershipOrg, User, Key } from '../../models'; @@ -8,6 +7,7 @@ import { } from '../../helpers/membership'; import { sendMail } from '../../helpers/nodemailer'; import { ADMIN, MEMBER, ACCEPTED } from '../../variables'; +import { getSiteURL } from '../../config'; /** * 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, inviterEmail: req.user.email, workspaceName: req.membership.workspace.name, - callback_url: infisical.get('SITE_URL')! + '/login' + callback_url: getSiteURL() + '/login' } }); } catch (err) { diff --git a/backend/src/controllers/v1/membershipOrgController.ts b/backend/src/controllers/v1/membershipOrgController.ts index 0efe00dac..105be0503 100644 --- a/backend/src/controllers/v1/membershipOrgController.ts +++ b/backend/src/controllers/v1/membershipOrgController.ts @@ -1,4 +1,3 @@ -import infisical from 'infisical-node'; import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; import { MembershipOrg, Organization, User } from '../../models'; @@ -8,6 +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'; /** * Delete organization membership with id [membershipOrgId] from organization @@ -178,7 +178,7 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => { organizationName: organization.name, email: inviteeEmail, 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: { userId: user._id.toString() }, - expiresIn: infisical.get('JWT_SIGNUP_LIFETIME')!, - secret: infisical.get('JWT_SIGNUP_SECRET')! + expiresIn: getJwtSignupLifetime(), + secret: getJwtSignupSecret() }); } catch (err) { Sentry.setUser(null); diff --git a/backend/src/controllers/v1/organizationController.ts b/backend/src/controllers/v1/organizationController.ts index 44403db86..00ad87b82 100644 --- a/backend/src/controllers/v1/organizationController.ts +++ b/backend/src/controllers/v1/organizationController.ts @@ -1,4 +1,3 @@ -import infisical from 'infisical-node'; import * as Sentry from '@sentry/node'; import { Request, Response } from 'express'; import Stripe from 'stripe'; @@ -13,6 +12,7 @@ import { createOrganization as create } from '../../helpers/organization'; import { addMembershipsOrg } from '../../helpers/membershipOrg'; import { OWNER, ACCEPTED } from '../../variables'; import _ from 'lodash'; +import { getStripeSecretKey, getSiteURL } from '../../config'; export const getOrganizations = async (req: Request, res: Response) => { let organizations; @@ -317,7 +317,7 @@ export const createOrganizationPortalSession = async ( ) => { let session; try { - const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { + const stripe = new Stripe(getStripeSecretKey(), { apiVersion: '2022-08-01' }); @@ -333,13 +333,13 @@ export const createOrganizationPortalSession = async ( customer: req.membershipOrg.organization.customerId, mode: 'setup', payment_method_types: ['card'], - success_url: infisical.get('SITE_URL')! + '/dashboard', - cancel_url: infisical.get('SITE_URL')! + '/dashboard' + success_url: getSiteURL() + '/dashboard', + cancel_url: getSiteURL() + '/dashboard' }); } else { session = await stripe.billingPortal.sessions.create({ 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; try { - const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { + const stripe = new Stripe(getStripeSecretKey(), { apiVersion: '2022-08-01' }); diff --git a/backend/src/controllers/v1/passwordController.ts b/backend/src/controllers/v1/passwordController.ts index 72a649bb1..fed24419c 100644 --- a/backend/src/controllers/v1/passwordController.ts +++ b/backend/src/controllers/v1/passwordController.ts @@ -1,4 +1,3 @@ -import infisical from 'infisical-node'; import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -10,6 +9,7 @@ import { sendMail } from '../../helpers/nodemailer'; import { TokenService } from '../../services'; import { TOKEN_EMAIL_PASSWORD_RESET } from '../../variables'; import { BadRequestError } from '../../utils/errors'; +import { getSiteURL, getJwtSignupLifetime, getJwtSignupSecret } from '../../config'; /** * Password reset step 1: Send email verification link to email [email] @@ -44,7 +44,7 @@ export const emailPasswordReset = async (req: Request, res: Response) => { substitutions: { email, token, - callback_url: infisical.get('SITE_URL')! + '/password-reset' + callback_url: getSiteURL() + '/password-reset' } }); } catch (err) { @@ -91,8 +91,8 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => { payload: { userId: user._id.toString() }, - expiresIn: infisical.get('JWT_SIGNUP_LIFETIME')!, - secret: infisical.get('JWT_SIGNUP_SECRET')! + expiresIn: getJwtSignupLifetime(), + secret: getJwtSignupSecret() }); } catch (err) { Sentry.setUser(null); diff --git a/backend/src/controllers/v1/serviceTokenController.ts b/backend/src/controllers/v1/serviceTokenController.ts index 76899a1a7..9f241349a 100644 --- a/backend/src/controllers/v1/serviceTokenController.ts +++ b/backend/src/controllers/v1/serviceTokenController.ts @@ -1,7 +1,7 @@ -import infisical from 'infisical-node'; import { Request, Response } from 'express'; import { ServiceToken } from '../../models'; import { createToken } from '../../helpers/auth'; +import { getJwtServiceSecret } from '../../config'; /** * Return service token on request @@ -61,7 +61,7 @@ export const createServiceToken = async (req: Request, res: Response) => { workspaceId }, expiresIn: expiresIn, - secret: infisical.get('JWT_SERVICE_SECRET')! + secret: getJwtServiceSecret() }); } catch (err) { return res.status(400).send({ diff --git a/backend/src/controllers/v1/signupController.ts b/backend/src/controllers/v1/signupController.ts index dbf5bd5a4..cb411a29e 100644 --- a/backend/src/controllers/v1/signupController.ts +++ b/backend/src/controllers/v1/signupController.ts @@ -1,4 +1,3 @@ -import infisical from 'infisical-node'; import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; import { User } from '../../models'; @@ -8,6 +7,7 @@ import { } from '../../helpers/signup'; import { createToken } from '../../helpers/auth'; 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 @@ -21,7 +21,7 @@ export const beginEmailSignup = async (req: Request, res: Response) => { try { 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 const userCount = await User.countDocuments({}) if (userCount != 0) { @@ -91,8 +91,8 @@ export const verifyEmailSignup = async (req: Request, res: Response) => { payload: { userId: user._id.toString() }, - expiresIn: infisical.get('JWT_SIGNUP_LIFETIME')!, - secret: infisical.get('JWT_SIGNUP_SECRET')! + expiresIn: getJwtSignupLifetime(), + secret: getJwtSignupSecret() }); } catch (err) { Sentry.setUser(null); diff --git a/backend/src/controllers/v1/stripeController.ts b/backend/src/controllers/v1/stripeController.ts index 1d3ee0bf2..1a981c088 100644 --- a/backend/src/controllers/v1/stripeController.ts +++ b/backend/src/controllers/v1/stripeController.ts @@ -1,7 +1,7 @@ -import infisical from 'infisical-node'; import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; import Stripe from 'stripe'; +import { getStripeSecretKey, getStripeWebhookSecret } from '../../config'; /** * Handle service provisioning/un-provisioning via Stripe @@ -13,7 +13,7 @@ export const handleWebhook = async (req: Request, res: Response) => { let event; try { // check request for valid stripe signature - const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { + const stripe = new Stripe(getStripeSecretKey(), { apiVersion: '2022-08-01' }); @@ -21,7 +21,7 @@ export const handleWebhook = async (req: Request, res: Response) => { event = stripe.webhooks.constructEvent( req.body, sig, - infisical.get('STRIPE_WEBHOOK_SECRET')! + getStripeWebhookSecret() ); } catch (err) { Sentry.setUser({ email: req.user.email }); diff --git a/backend/src/controllers/v2/apiKeyDataController.ts b/backend/src/controllers/v2/apiKeyDataController.ts index b6819928a..fd87f7306 100644 --- a/backend/src/controllers/v2/apiKeyDataController.ts +++ b/backend/src/controllers/v2/apiKeyDataController.ts @@ -1,11 +1,11 @@ import * as Sentry from '@sentry/node'; -import infisical from 'infisical-node'; import { Request, Response } from 'express'; import crypto from 'crypto'; import bcrypt from 'bcrypt'; import { APIKeyData } from '../../models'; +import { getSaltRounds } from '../../config'; /** * 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 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(); expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn); diff --git a/backend/src/controllers/v2/authController.ts b/backend/src/controllers/v2/authController.ts index 4401e2498..b0204e1b9 100644 --- a/backend/src/controllers/v2/authController.ts +++ b/backend/src/controllers/v2/authController.ts @@ -1,4 +1,3 @@ -import infisical from 'infisical-node'; /* eslint-disable @typescript-eslint/no-var-requires */ import { Request, Response } from 'express'; import jwt from 'jsonwebtoken'; @@ -17,6 +16,11 @@ import { ACTION_LOGIN } from '../../variables'; import { getChannelFromUserAgent } from '../../utils/posthog'; // TODO: move this +import { + getNodeEnv, + getJwtMfaLifetime, + getJwtMfaSecret +} from '../../config'; declare module 'jsonwebtoken' { export interface UserIDJwtPayload extends jwt.JwtPayload { @@ -120,8 +124,8 @@ export const login2 = async (req: Request, res: Response) => { payload: { userId: user._id.toString() }, - expiresIn: infisical.get('JWT_MFA_LIFETIME')!, - secret: infisical.get('JWT_MFA_SECRET')! + expiresIn: getJwtMfaLifetime(), + secret: getJwtMfaSecret() }); const code = await TokenService.createToken({ @@ -159,7 +163,7 @@ export const login2 = async (req: Request, res: Response) => { httpOnly: true, path: '/', sameSite: 'strict', - secure: infisical.get('NODE_ENV')! === 'production' ? true : false + secure: getNodeEnv() === 'production' ? true : false }); // case: user does not have MFA enablgged @@ -298,7 +302,7 @@ export const verifyMfaToken = async (req: Request, res: Response) => { httpOnly: true, path: '/', sameSite: 'strict', - secure: infisical.get('NODE_ENV')! === 'production' ? true : false + secure: getNodeEnv() === 'production' ? true : false }); interface VerifyMfaTokenRes { @@ -341,5 +345,4 @@ export const verifyMfaToken = async (req: Request, res: Response) => { }); return res.status(200).send(resObj); -} - +} \ No newline at end of file diff --git a/backend/src/controllers/v2/serviceTokenDataController.ts b/backend/src/controllers/v2/serviceTokenDataController.ts index 295664cf9..a4e06f8e4 100644 --- a/backend/src/controllers/v2/serviceTokenDataController.ts +++ b/backend/src/controllers/v2/serviceTokenDataController.ts @@ -1,5 +1,4 @@ import * as Sentry from '@sentry/node'; -import infisical from 'infisical-node'; import { Request, Response } from 'express'; import crypto from 'crypto'; import bcrypt from 'bcrypt'; @@ -8,6 +7,7 @@ import { } from '../../models'; import { userHasWorkspaceAccess } from '../../ee/helpers/checkMembershipPermissions'; import { ABILITY_READ } from '../../variables/organization'; +import { getSaltRounds } from '../../config'; /** * 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 secretHash = await bcrypt.hash(secret, parseInt(infisical.get('SALT_ROUNDS')!) || 10); + const secretHash = await bcrypt.hash(secret, getSaltRounds()); const expiresAt = new Date(); expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn); @@ -140,4 +140,4 @@ export const deleteServiceTokenData = async (req: Request, res: Response) => { function UnauthorizedRequestError(arg0: { message: string; }) { throw new Error('Function not implemented.'); -} +} \ No newline at end of file diff --git a/backend/src/controllers/v2/signupController.ts b/backend/src/controllers/v2/signupController.ts index 0eb148e37..3e4b1f44a 100644 --- a/backend/src/controllers/v2/signupController.ts +++ b/backend/src/controllers/v2/signupController.ts @@ -1,4 +1,3 @@ -import infisical from 'infisical-node'; import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; import { User, MembershipOrg } from '../../models'; @@ -9,6 +8,7 @@ import { import { issueAuthTokens } from '../../helpers/auth'; import { INVITED, ACCEPTED } from '../../variables'; import request from '../../config/request'; +import { getNodeEnv } from '../../config'; /** * 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, path: '/', sameSite: 'strict', - secure: infisical.get('NODE_ENV')! === 'production' ? true : false + secure: getNodeEnv() === 'production' ? true : false }); } catch (err) { Sentry.setUser(null); @@ -232,7 +232,7 @@ export const completeAccountInvite = async (req: Request, res: Response) => { httpOnly: true, path: '/', sameSite: 'strict', - secure: infisical.get('NODE_ENV')! === 'production' ? true : false + secure: getNodeEnv() === 'production' ? true : false }); } catch (err) { Sentry.setUser(null); diff --git a/backend/src/ee/controllers/v1/stripeController.ts b/backend/src/ee/controllers/v1/stripeController.ts index 7c816550e..3caa0f395 100644 --- a/backend/src/ee/controllers/v1/stripeController.ts +++ b/backend/src/ee/controllers/v1/stripeController.ts @@ -1,7 +1,7 @@ import * as Sentry from '@sentry/node'; -import infisical from 'infisical-node'; import { Request, Response } from 'express'; import Stripe from 'stripe'; +import { getStripeSecretKey, getStripeWebhookSecret } from '../../../config'; /** * Handle service provisioning/un-provisioning via Stripe @@ -12,7 +12,7 @@ import Stripe from 'stripe'; export const handleWebhook = async (req: Request, res: Response) => { let event; try { - const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { + const stripe = new Stripe(getStripeSecretKey(), { apiVersion: '2022-08-01' }); @@ -21,7 +21,7 @@ export const handleWebhook = async (req: Request, res: Response) => { event = stripe.webhooks.constructEvent( req.body, sig, - infisical.get('STRIPE_WEBHOOK_SECRET')! + getStripeWebhookSecret() ); } catch (err) { Sentry.setUser({ email: req.user.email }); diff --git a/backend/src/helpers/auth.ts b/backend/src/helpers/auth.ts index 680120395..a08dcf2cc 100644 --- a/backend/src/helpers/auth.ts +++ b/backend/src/helpers/auth.ts @@ -1,5 +1,4 @@ import * as Sentry from '@sentry/node'; -import infisical from 'infisical-node'; import jwt from 'jsonwebtoken'; import bcrypt from 'bcrypt'; import { @@ -15,6 +14,12 @@ import { UnauthorizedRequestError, BadRequestError } from '../utils/errors'; +import { + getJwtAuthLifetime, + getJwtAuthSecret, + getJwtRefreshLifetime, + getJwtRefreshSecret +} from '../config'; /** * @@ -88,7 +93,7 @@ const getAuthUserPayload = async ({ let user; try { const decodedToken = ( - jwt.verify(authTokenValue, infisical.get('JWT_AUTH_SECRET')!) + jwt.verify(authTokenValue, getJwtAuthSecret()) ); user = await User.findOne({ @@ -219,16 +224,16 @@ const issueAuthTokens = async ({ userId }: { userId: string }) => { payload: { userId }, - expiresIn: infisical.get('JWT_AUTH_LIFETIME')!, - secret: infisical.get('JWT_AUTH_SECRET')! + expiresIn: getJwtAuthLifetime(), + secret: getJwtAuthSecret() }); refreshToken = createToken({ payload: { userId }, - expiresIn: infisical.get('JWT_REFRESH_LIFETIME')!, - secret: infisical.get('JWT_REFRESH_SECRET')! + expiresIn: getJwtRefreshLifetime(), + secret: getJwtRefreshSecret() }); } catch (err) { Sentry.setUser(null); diff --git a/backend/src/helpers/bot.ts b/backend/src/helpers/bot.ts index 8912befd1..5cfbeebf5 100644 --- a/backend/src/helpers/bot.ts +++ b/backend/src/helpers/bot.ts @@ -1,5 +1,4 @@ import * as Sentry from '@sentry/node'; -import infisical from 'infisical-node'; import { Bot, BotKey, @@ -14,6 +13,7 @@ import { decryptAsymmetric } from '../utils/crypto'; import { SECRET_SHARED } from '../variables'; +import { getEncryptionKey } from '../config'; /** * Create an inactive bot with name [name] for workspace with id [workspaceId] @@ -33,7 +33,7 @@ const createBot = async ({ const { publicKey, privateKey } = generateKeyPair(); const { ciphertext, iv, tag } = encryptSymmetric({ plaintext: privateKey, - key: infisical.get('ENCRYPTION_KEY')! + key: getEncryptionKey() }); bot = await new Bot({ @@ -130,7 +130,7 @@ const getKey = async ({ workspaceId }: { workspaceId: string }) => { ciphertext: bot.encryptedPrivateKey, iv: bot.iv, tag: bot.tag, - key: infisical.get('ENCRYPTION_KEY')! + key: getEncryptionKey() }); key = decryptAsymmetric({ diff --git a/backend/src/helpers/nodemailer.ts b/backend/src/helpers/nodemailer.ts index 45fce5d1d..d765f3200 100644 --- a/backend/src/helpers/nodemailer.ts +++ b/backend/src/helpers/nodemailer.ts @@ -1,9 +1,9 @@ import * as Sentry from '@sentry/node'; -import infisical from 'infisical-node'; import fs from 'fs'; import path from 'path'; import handlebars from 'handlebars'; import nodemailer from 'nodemailer'; +import { getSmtpFromName, getSmtpFromAddress } from '../config'; let smtpTransporter: nodemailer.Transporter; @@ -34,7 +34,7 @@ const sendMail = async ({ const htmlToSend = temp(substitutions); await smtpTransporter.sendMail({ - from: `"${infisical.get('SMTP_FROM_NAME')!}" <${infisical.get('SMTP_FROM_ADDRESS')!}>`, + from: `"${getSmtpFromName()}" <${getSmtpFromAddress()}>`, to: recipients.join(', '), subject: subjectLine, html: htmlToSend diff --git a/backend/src/helpers/organization.ts b/backend/src/helpers/organization.ts index 87711da92..fb559df1b 100644 --- a/backend/src/helpers/organization.ts +++ b/backend/src/helpers/organization.ts @@ -1,9 +1,14 @@ -import infisical from 'infisical-node'; import * as Sentry from '@sentry/node'; import Stripe from 'stripe'; import { Types } from 'mongoose'; import { ACCEPTED } from '../variables'; import { Organization, MembershipOrg } from '../models'; +import { + getStripeSecretKey, + getStripeProductPro, + getStripeProductTeam, + getStripeProductStarter +} from '../config'; /** * Create an organization with name [name] @@ -22,11 +27,11 @@ const createOrganization = async ({ let organization; try { // register stripe account - const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { + const stripe = new Stripe(getStripeSecretKey(), { apiVersion: '2022-08-01' }); - if (infisical.get('STRIPE_SECRET_KEY')) { + if (getStripeSecretKey()) { const customer = await stripe.customers.create({ email, description: name @@ -76,14 +81,14 @@ const initSubscriptionOrg = async ({ if (organization) { if (organization.customerId) { // 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' }); const productToPriceMap = { - starter: infisical.get('STRIPE_PRODUCT_STARTER')!, - team: infisical.get('STRIPE_PRODUCT_TEAM')!, - pro: infisical.get('STRIPE_PRODUCT_PRO')! + starter: getStripeProductStarter(), + team: getStripeProductTeam(), + pro: getStripeProductPro() }; stripeSubscription = await stripe.subscriptions.create({ @@ -138,7 +143,7 @@ const updateSubscriptionOrgQuantity = async ({ status: ACCEPTED }); - const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, { + const stripe = new Stripe(getStripeSecretKey(), { apiVersion: '2022-08-01' }); @@ -170,4 +175,4 @@ export { createOrganization, initSubscriptionOrg, updateSubscriptionOrgQuantity -}; +}; \ No newline at end of file diff --git a/backend/src/helpers/token.ts b/backend/src/helpers/token.ts index b2365cb2c..0f6a88cc9 100644 --- a/backend/src/helpers/token.ts +++ b/backend/src/helpers/token.ts @@ -1,5 +1,4 @@ import * as Sentry from '@sentry/node'; -import infisical from 'infisical-node'; import { Types } from 'mongoose'; import { TokenData } from '../models'; import crypto from 'crypto'; @@ -11,6 +10,7 @@ import { TOKEN_EMAIL_PASSWORD_RESET } from '../variables'; import { UnauthorizedRequestError } from '../utils/errors'; +import { getSaltRounds } from '../config'; /** * Create and store a token in the database for purpose [type] @@ -84,7 +84,7 @@ const createTokenHelper = async ({ const query: TokenDataQuery = { type }; const update: TokenDataUpdate = { type, - tokenHash: await bcrypt.hash(token, parseInt(infisical.get('SALT_ROUNDS')!) || 10), + tokenHash: await bcrypt.hash(token, getSaltRounds()), expiresAt } diff --git a/backend/src/index.ts b/backend/src/index.ts index 24172fc89..5647ad870 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -63,8 +63,17 @@ import { healthCheck } from './routes/status'; import { getLogger } from './utils/logger'; import { RouteNotFoundError } from './utils/errors'; import { requestErrorHandler } from './middleware/requestErrorHandler'; +import { + getMongoURL, + getNodeEnv, + getPort, + getSentryDSN, + getSiteURL +} from './config'; const main = async () => { + // TODO 1: handle case of empty string token + // TODO 2: handle case of undefined token const client = await infisical.connect({ token: process.env.INFISICAL_TOKEN!, debug: true @@ -73,13 +82,13 @@ const main = async () => { logTelemetryMessage(); setTransporter(initSmtp()); - await DatabaseService.initDatabase(infisical.get('MONGO_URL')!); - if (infisical.get('NODE_ENV') !== 'test') { + await DatabaseService.initDatabase(getMongoURL()); + if (getNodeEnv() !== 'test') { Sentry.init({ - dsn: infisical.get('SENTRY_DSN') as string, + dsn: getSentryDSN(), tracesSampleRate: 1.0, - debug: infisical.get('NODE_ENV') === 'production' ? false : true, - environment: infisical.get('NODE_ENV') as string + debug: getNodeEnv() === 'production' ? false : true, + environment: getNodeEnv() }); } @@ -91,13 +100,13 @@ const main = async () => { app.use( cors({ credentials: true, - origin: infisical.get('SITE_URL') as string + origin: getSiteURL() }) ); app.use(requestIp.mw()); - if (infisical.get('NODE_ENV') === 'production') { + if (getNodeEnv() === 'production') { // enable app-wide rate-limiting + helmet security // in production app.disable('x-powered-by'); @@ -157,9 +166,9 @@ const main = async () => { app.use(requestErrorHandler) - const server = app.listen(Number(infisical.get('PORT')) || 4000, () => { + const server = app.listen(getPort(), () => { 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); diff --git a/backend/src/integrations/exchange.ts b/backend/src/integrations/exchange.ts index 4e89e3aa9..1dccb03d0 100644 --- a/backend/src/integrations/exchange.ts +++ b/backend/src/integrations/exchange.ts @@ -1,4 +1,3 @@ -import infisical from 'infisical-node'; import * as Sentry from '@sentry/node'; import request from '../config/request'; import { @@ -15,6 +14,20 @@ import { INTEGRATION_GITHUB_TOKEN_URL, INTEGRATION_GITLAB_TOKEN_URL } from '../variables'; +import { + getSiteURL, + getClientIdAzure, + getClientSecretAzure, + getClientSecretHeroku, + getClientIdVercel, + getClientSecretVercel, + getClientIdNetlify, + getClientSecretNetlify, + getClientIdGitHub, + getClientSecretGitHub, + getClientIdGitLab, + getClientSecretGitLab +} from '../config'; interface ExchangeCodeAzureResponse { token_type: string; @@ -146,9 +159,9 @@ const exchangeCodeAzure = async ({ grant_type: 'authorization_code', code: code, scope: 'https://vault.azure.net/.default openid offline_access', - client_id: infisical.get('CLIENT_ID_AZURE')!, - client_secret: infisical.get('CLIENT_SECRET_AZURE')!, - redirect_uri: `${infisical.get('SITE_URL')!}/integrations/azure-key-vault/oauth2/callback` + client_id: getClientIdAzure(), + client_secret: getClientSecretAzure(), + redirect_uri: `${getSiteURL()}/integrations/azure-key-vault/oauth2/callback` } as any) )).data; @@ -191,7 +204,7 @@ const exchangeCodeHeroku = async ({ new URLSearchParams({ grant_type: 'authorization_code', code: code, - client_secret: infisical.get('CLIENT_SECRET_HEROKU')! + client_secret: getClientSecretHeroku() } as any) )).data; @@ -229,9 +242,9 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => { INTEGRATION_VERCEL_TOKEN_URL, new URLSearchParams({ code: code, - client_id: infisical.get('CLIENT_ID_VERCEL')!, - client_secret: infisical.get('CLIENT_SECRET_VERCEL')!, - redirect_uri: `${infisical.get('SITE_URL')!}/integrations/vercel/oauth2/callback` + client_id: getClientIdVercel(), + client_secret: getClientSecretVercel(), + redirect_uri: `${getSiteURL()}/integrations/vercel/oauth2/callback` } as any) ) ).data; @@ -269,9 +282,9 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => { new URLSearchParams({ grant_type: 'authorization_code', code: code, - client_id: infisical.get('CLIENT_ID_NETLIFY')!, - client_secret: infisical.get('CLIENT_SECRET_NETLIFY')!, - redirect_uri: `${infisical.get('SITE_URL')!}/integrations/netlify/oauth2/callback` + client_id: getClientIdNetlify(), + client_secret: getClientSecretNetlify(), + redirect_uri: `${getSiteURL()}/integrations/netlify/oauth2/callback` } as any) ) ).data; @@ -320,10 +333,10 @@ const exchangeCodeGithub = async ({ code }: { code: string }) => { res = ( await request.get(INTEGRATION_GITHUB_TOKEN_URL, { params: { - client_id: infisical.get('CLIENT_ID_GITHUB')!, - client_secret: infisical.get('CLIENT_SECRET_GITHUB')!, + client_id: getClientIdGitHub(), + client_secret: getClientSecretGitHub(), code: code, - redirect_uri: `${infisical.get('SITE_URL')!}/integrations/github/oauth2/callback` + redirect_uri: `${getSiteURL()}/integrations/github/oauth2/callback` }, headers: { 'Accept': 'application/json', @@ -366,9 +379,9 @@ const exchangeCodeGitlab = async ({ code }: { code: string }) => { new URLSearchParams({ grant_type: 'authorization_code', code: code, - client_id: infisical.get('CLIENT_ID_GITLAB')!, - client_secret: infisical.get('CLIENT_SECRET_GITLAB')!, - redirect_uri: `${infisical.get('SITE_URL')}/integrations/gitlab/oauth2/callback` + client_id: getClientIdGitLab(), + client_secret: getClientSecretGitLab(), + redirect_uri: `${getSiteURL()}/integrations/gitlab/oauth2/callback` } as any), { headers: { diff --git a/backend/src/integrations/refresh.ts b/backend/src/integrations/refresh.ts index 67cd382c1..a0aea080e 100644 --- a/backend/src/integrations/refresh.ts +++ b/backend/src/integrations/refresh.ts @@ -1,4 +1,3 @@ -import infisical from 'infisical-node'; import * as Sentry from '@sentry/node'; import request from '../config/request'; import { @@ -9,13 +8,6 @@ import { INTEGRATION_HEROKU, INTEGRATION_GITLAB, } from '../variables'; -// import { -// CLIENT_ID_AZURE, -// CLIENT_ID_GITLAB, -// CLIENT_SECRET_AZURE, -// CLIENT_SECRET_HEROKU, -// CLIENT_SECRET_GITLAB -// } from '../config'; import { INTEGRATION_AZURE_TOKEN_URL, INTEGRATION_HEROKU_TOKEN_URL, @@ -24,6 +16,14 @@ import { import { IntegrationService } from '../services'; +import { + getSiteURL, + getClientIdAzure, + getClientSecretAzure, + getClientSecretHeroku, + getClientIdGitLab, + getClientSecretGitLab +} from '../config'; interface RefreshTokenAzureResponse { token_type: string; @@ -133,11 +133,11 @@ const exchangeRefreshAzure = async ({ const { data }: { data: RefreshTokenAzureResponse } = await request.post( INTEGRATION_AZURE_TOKEN_URL, new URLSearchParams({ - client_id: infisical.get('CLIENT_ID_AZURE')!, + client_id: getClientIdAzure(), scope: 'openid offline_access', refresh_token: refreshToken, grant_type: 'refresh_token', - client_secret: infisical.get('CLIENT_SECRET_AZURE')! + client_secret: getClientSecretAzure() } as any) ); @@ -180,7 +180,7 @@ const exchangeRefreshHeroku = async ({ new URLSearchParams({ grant_type: 'refresh_token', refresh_token: refreshToken, - client_secret: infisical.get('CLIENT_SECRET_HEROKU')! + client_secret: getClientSecretHeroku() } as any) ); @@ -223,9 +223,9 @@ const exchangeRefreshGitLab = async ({ new URLSearchParams({ grant_type: 'refresh_token', refresh_token: refreshToken, - client_id: infisical.get('CLIENT_ID_GITLAB')!, - client_secret: infisical.get('CLIENT_SECRET_GITLAB')!, - redirect_uri: `${infisical.get('SITE_URL')!}/integrations/gitlab/oauth2/callback` + client_id: getClientIdGitLab, + client_secret: getClientSecretGitLab(), + redirect_uri: `${getSiteURL()}/integrations/gitlab/oauth2/callback` } as any), { headers: { diff --git a/backend/src/middleware/requestErrorHandler.ts b/backend/src/middleware/requestErrorHandler.ts index 2a881e814..202a38e83 100644 --- a/backend/src/middleware/requestErrorHandler.ts +++ b/backend/src/middleware/requestErrorHandler.ts @@ -1,13 +1,13 @@ -import infisical from 'infisical-node'; import * as Sentry from '@sentry/node'; import { ErrorRequestHandler } from "express"; -import { InternalServerError, UnauthorizedRequestError } from "../utils/errors"; +import { InternalServerError } from "../utils/errors"; import { getLogger } from "../utils/logger"; import RequestError, { LogLevel } from "../utils/requestError"; +import { getNodeEnv } from '../config'; export const requestErrorHandler: ErrorRequestHandler = (error: RequestError | Error, req, res, next) => { if (res.headersSent) return next(); - if (infisical.get('NODE_ENV')! !== "production") { + if (getNodeEnv() !== "production") { /* eslint-disable no-console */ console.log(error) /* eslint-enable no-console */ diff --git a/backend/src/middleware/requireMfaAuth.ts b/backend/src/middleware/requireMfaAuth.ts index 21b4763c2..7fb38ca25 100644 --- a/backend/src/middleware/requireMfaAuth.ts +++ b/backend/src/middleware/requireMfaAuth.ts @@ -1,8 +1,8 @@ -import infisical from 'infisical-node'; import jwt from 'jsonwebtoken'; import { Request, Response, NextFunction } from 'express'; import { User } from '../models'; import { BadRequestError, UnauthorizedRequestError } from '../utils/errors'; +import { getJwtMfaSecret } from '../config'; declare module 'jsonwebtoken' { 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'})) const decodedToken = ( - jwt.verify(AUTH_TOKEN_VALUE, infisical.get('JWT_MFA_SECRET')!) + jwt.verify(AUTH_TOKEN_VALUE, getJwtMfaSecret()) ); const user = await User.findOne({ diff --git a/backend/src/middleware/requireServiceTokenAuth.ts b/backend/src/middleware/requireServiceTokenAuth.ts index ff6bb7c59..106ca9bbb 100644 --- a/backend/src/middleware/requireServiceTokenAuth.ts +++ b/backend/src/middleware/requireServiceTokenAuth.ts @@ -1,8 +1,8 @@ -import infisical from 'infisical-node'; import jwt from 'jsonwebtoken'; import { Request, Response, NextFunction } from 'express'; import { ServiceToken } from '../models'; import { BadRequestError, UnauthorizedRequestError } from '../utils/errors'; +import { getJwtServiceSecret } from '../config'; // TODO: deprecate 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'})) const decodedToken = ( - jwt.verify(AUTH_TOKEN_VALUE, infisical.get('JWT_SERVICE_SECRET')!) + jwt.verify(AUTH_TOKEN_VALUE, getJwtServiceSecret()) ); const serviceToken = await ServiceToken.findOne({ diff --git a/backend/src/middleware/requireSignupAuth.ts b/backend/src/middleware/requireSignupAuth.ts index deb08d9ae..19e6b3146 100644 --- a/backend/src/middleware/requireSignupAuth.ts +++ b/backend/src/middleware/requireSignupAuth.ts @@ -1,8 +1,8 @@ -import infisical from 'infisical-node'; import jwt from 'jsonwebtoken'; import { Request, Response, NextFunction } from 'express'; import { User } from '../models'; import { BadRequestError, UnauthorizedRequestError } from '../utils/errors'; +import { getJwtSignupSecret } from '../config'; declare module 'jsonwebtoken' { 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'})) const decodedToken = ( - jwt.verify(AUTH_TOKEN_VALUE, infisical.get('JWT_SIGNUP_SECRET')!) + jwt.verify(AUTH_TOKEN_VALUE, getJwtSignupSecret()) ); const user = await User.findOne({ diff --git a/backend/src/services/PostHogClient.ts b/backend/src/services/PostHogClient.ts index 2d1bb8391..15ccf0919 100644 --- a/backend/src/services/PostHogClient.ts +++ b/backend/src/services/PostHogClient.ts @@ -1,13 +1,17 @@ -import infisical from 'infisical-node'; import { PostHog } from 'posthog-node'; import { getLogger } from '../utils/logger'; +import { + getNodeEnv, + getTelemetryEnabled, + getPostHogProjectApiKey, + getPostHogHost +} from '../config'; /** * Logs telemetry enable/disable notice. */ const logTelemetryMessage = () => { - const TELEMETRY_ENABLED = infisical.get('TELEMETRY_ENABLED')! !== 'false' && true; - if(!TELEMETRY_ENABLED){ + if(!getTelemetryEnabled()){ getLogger("backend-main").info([ "", "To improve, Infisical collects telemetry data about general usage.", @@ -23,11 +27,10 @@ const logTelemetryMessage = () => { */ const getPostHogClient = () => { let postHogClient: any; - const TELEMETRY_ENABLED = infisical.get('TELEMETRY_ENABLED')! !== 'false' && true; - if (infisical.get('NODE_ENV') === 'production' && TELEMETRY_ENABLED) { + if (getNodeEnv() === 'production' && getTelemetryEnabled()) { // case: enable opt-out telemetry in production - postHogClient = new PostHog(infisical.get('POSTHOG_PROJECT_API_KEY')! || 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE', { - host: infisical.get('POSTHOG_HOST')! + postHogClient = new PostHog(getPostHogProjectApiKey(), { + host: getPostHogHost() }); } diff --git a/backend/src/services/smtp.ts b/backend/src/services/smtp.ts index a9c056071..7a4ebf00b 100644 --- a/backend/src/services/smtp.ts +++ b/backend/src/services/smtp.ts @@ -1,4 +1,3 @@ -import infisical from 'infisical-node'; import nodemailer from 'nodemailer'; import { SMTP_HOST_SENDGRID, @@ -8,22 +7,29 @@ import { } from '../variables'; import SMTPConnection from 'nodemailer/lib/smtp-connection'; import * as Sentry from '@sentry/node'; +import { + getSmtpHost, + getSmtpUsername, + getSmtpPassword, + getSmtpSecure, + getSmtpPort +} from '../config'; export const initSmtp = () => { const mailOpts: SMTPConnection.Options = { - host: infisical.get('SMTP_HOST')!, - port: parseInt(infisical.get('SMTP_PORT')!) + host: getSmtpHost(), + port: getSmtpPort() }; - if (infisical.get('SMTP_USERNAME')! && infisical.get('SMTP_PASSWORD')!) { + if (getSmtpUsername() && getSmtpPassword()) { mailOpts.auth = { - user: infisical.get('SMTP_USERNAME')!, - pass: infisical.get('SMTP_PASSWORD')! + user: getSmtpUsername(), + pass: getSmtpPassword() }; } - if (infisical.get('SMTP_SECURE')! ? infisical.get('SMTP_SECURE')! === 'true' : false) { - switch (infisical.get('SMTP_HOST')!) { + if (getSmtpSecure() ? getSmtpSecure() : false) { + switch (getSmtpHost()) { case SMTP_HOST_SENDGRID: mailOpts.requireTLS = true; break; @@ -46,7 +52,7 @@ export const initSmtp = () => { } break; default: - if (infisical.get('SMTP_HOST')!.includes('amazonaws.com')) { + if (getSmtpHost().includes('amazonaws.com')) { mailOpts.tls = { ciphers: 'TLSv1.2' } @@ -67,7 +73,7 @@ export const initSmtp = () => { .catch((err) => { Sentry.setUser(null); 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}` ); }); diff --git a/backend/src/utils/addDevelopmentUser.ts b/backend/src/utils/addDevelopmentUser.ts index ed886fd62..585740a6b 100644 --- a/backend/src/utils/addDevelopmentUser.ts +++ b/backend/src/utils/addDevelopmentUser.ts @@ -4,12 +4,12 @@ * ************************************************************************************************/ -import infisical from 'infisical-node'; import { Key, Membership, MembershipOrg, Organization, User, Workspace } from "../models"; import { Types } from 'mongoose'; +import { getNodeEnv } from '../config'; export const createTestUserForDevelopment = async () => { - if (infisical.get('NODE_ENV') === "development") { + if (getNodeEnv() === "development") { const testUserEmail = "test@localhost.local" const testUserPassword = "testInfisical1" const testUserId = "63cefa6ec8d3175601cfa980" diff --git a/backend/src/utils/logger.ts b/backend/src/utils/logger.ts index 590a9d950..ed29c97ca 100644 --- a/backend/src/utils/logger.ts +++ b/backend/src/utils/logger.ts @@ -1,7 +1,7 @@ -import infisical from 'infisical-node'; /* eslint-disable no-console */ import { createLogger, format, transports } from 'winston'; import LokiTransport from 'winston-loki'; +import { getLokiHost, getNodeEnv } from '../config'; const { combine, colorize, label, printf, splat, timestamp } = format; @@ -25,10 +25,10 @@ const createLoggerWithLabel = (level: string, label: string) => { }) ] //* Add LokiTransport if it's enabled - if(infisical.get('LOKI_HOST')! !== undefined){ + if(getLokiHost() !== undefined){ _transports.push( new LokiTransport({ - host: infisical.get('LOKI_HOST')!, + host: getLokiHost(), handleExceptions: true, handleRejections: true, batching: true, @@ -40,7 +40,7 @@ const createLoggerWithLabel = (level: string, label: string) => { labels: { app: process.env.npm_package_name, 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) }) diff --git a/backend/src/utils/requestError.ts b/backend/src/utils/requestError.ts index 7e7fd6070..4b5635bac 100644 --- a/backend/src/utils/requestError.ts +++ b/backend/src/utils/requestError.ts @@ -1,5 +1,5 @@ -import infisical from 'infisical-node'; import { Request } from 'express' +import { getVerboseErrorOutput } from '../config'; export enum LogLevel { DEBUG = 100, @@ -87,8 +87,7 @@ export default class RequestError extends Error{ }, this.context) //* 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(!VERBOSE_ERROR_OUTPUT){ + if(!getVerboseErrorOutput()){ _context = this._omit(_context, [ 'stacktrace', 'exception', diff --git a/backend/src/variables/integration.ts b/backend/src/variables/integration.ts index db8adf105..52bfcc614 100644 --- a/backend/src/variables/integration.ts +++ b/backend/src/variables/integration.ts @@ -1,4 +1,11 @@ -import infisical from 'infisical-node'; +import { + getClientIdHeroku, + getClientSlugVercel, + getClientIdNetlify, + getClientIdAzure, + getClientIdGitLab, + getClientIdGitHub +} from '../config'; // integrations const INTEGRATION_AZURE_KEY_VAULT = 'azure-key-vault'; @@ -57,7 +64,7 @@ const getIntegrationOptions = () => { image: 'Heroku.png', isAvailable: true, type: 'oauth', - clientId: infisical.get('CLIENT_ID_HEROKU')!, + clientId: getClientIdHeroku(), docsLink: '' }, { @@ -67,7 +74,7 @@ const getIntegrationOptions = () => { isAvailable: true, type: 'oauth', clientId: '', - clientSlug: infisical.get('CLIENT_SLUG_VERCEL')!, + clientSlug: getClientSlugVercel(), docsLink: '' }, { @@ -76,7 +83,7 @@ const getIntegrationOptions = () => { image: 'Netlify.png', isAvailable: true, type: 'oauth', - clientId: infisical.get('CLIENT_ID_NETLIFY')!, + clientId: getClientIdNetlify(), docsLink: '' }, { @@ -85,7 +92,7 @@ const getIntegrationOptions = () => { image: 'GitHub.png', isAvailable: true, type: 'oauth', - clientId: infisical.get('CLIENT_ID_GITHUB')!, + clientId: getClientIdGitHub(), docsLink: '' }, { @@ -130,7 +137,7 @@ const getIntegrationOptions = () => { image: 'Microsoft Azure.png', isAvailable: true, type: 'oauth', - clientId: infisical.get('CLIENT_ID_AZURE')!, + clientId: getClientIdAzure(), docsLink: '' }, { @@ -148,7 +155,7 @@ const getIntegrationOptions = () => { image: 'GitLab.png', isAvailable: true, type: 'custom', - clientId: infisical.get('CLIENT_ID_GITLAB'), + clientId: getClientIdGitLab(), docsLink: '' }, { diff --git a/docs/sdk/overview/usage.mdx b/docs/sdk/overview/usage.mdx index 2708f9a2b..84d963fff 100644 --- a/docs/sdk/overview/usage.mdx +++ b/docs/sdk/overview/usage.mdx @@ -59,17 +59,16 @@ infisical.connect({ Options: -| Option | Description | Default Value | -| -------------------- | ----------------------------------------------------------- | --------------------------- | -| `token` | ❗️ An Infisical Token to be used to fetch secrets | `None` | -| `siteURL` | Site URL of Infisical to connect to | `https://app.infisical.com` | -| `attachToProcessEnv` | Whether or not to attach fetched secrets to `process.env` | `False` | -| `defaultValues` | Default values for secrets if they aren't fetched/passed in | `{}` | +| Option | Description | Default Value | +| -------------------- | --------------------------------------------------------- | --------------------------- | +| `token` | ❗️ An Infisical Token to be used to fetch secrets | `None` | +| `siteURL` | Site URL of Infisical to connect to | `https://app.infisical.com` | +| `attachToProcessEnv` | Whether or not to attach fetched secrets to `process.env` | `false` | ## Access a Secret Value ```js -const dbURL = infisical.getSecretValue("DB_URL"); +const dbURL = infisical.get("DB_URL"); ``` ## Example with Express @@ -81,7 +80,7 @@ const infisical = require("infisical-node"); app.get("/", (req, res) => { // access value - const name = infisical.getSecret("NAME"); + const name = infisical.get("NAME"); res.send(`Hello! My name is: ${name}`); });