Complete preliminary addition of infisical-node to support service tokens

This commit is contained in:
Tuan Dang
2023-03-14 16:38:30 +07:00
parent 1e859c19f4
commit 7fd06e36bc
47 changed files with 691 additions and 691 deletions

View File

@@ -4,7 +4,6 @@ declare global {
namespace NodeJS {
interface ProcessEnv {
PORT: string;
EMAIL_TOKEN_LIFETIME: string;
ENCRYPTION_KEY: string;
SALT_ROUNDS: string;
JWT_AUTH_LIFETIME: string;

View File

@@ -32,6 +32,7 @@
"express-validator": "^6.14.2",
"handlebars": "^4.7.7",
"helmet": "^5.1.1",
"infisical-node": "^1.0.34",
"js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.0",
"jsrp": "^0.2.4",
@@ -5973,6 +5974,16 @@
"node": ">=0.8.19"
}
},
"node_modules/infisical-node": {
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/infisical-node/-/infisical-node-1.0.34.tgz",
"integrity": "sha512-0joSgkNPZ15aZtm8Mrr/vSWizTYZlJivbawCecfllR4bzQ03TT3Ja4hivYyAmRYkrhUTHqb0gpQ3a8lSk7vyug==",
"dependencies": {
"axios": "^1.3.3",
"tweetnacl": "^1.0.3",
"tweetnacl-util": "^0.15.1"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -16758,6 +16769,16 @@
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true
},
"infisical-node": {
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/infisical-node/-/infisical-node-1.0.34.tgz",
"integrity": "sha512-0joSgkNPZ15aZtm8Mrr/vSWizTYZlJivbawCecfllR4bzQ03TT3Ja4hivYyAmRYkrhUTHqb0gpQ3a8lSk7vyug==",
"requires": {
"axios": "^1.3.3",
"tweetnacl": "^1.0.3",
"tweetnacl-util": "^0.15.1"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",

View File

@@ -23,6 +23,7 @@
"express-validator": "^6.14.2",
"handlebars": "^4.7.7",
"helmet": "^5.1.1",
"infisical-node": "^1.0.34",
"js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.0",
"jsrp": "^0.2.4",

View File

@@ -1,144 +0,0 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { patchRouterParam } = require('./utils/patchAsyncRoutes');
import express from 'express';
import helmet from 'helmet';
import cors from 'cors';
import cookieParser from 'cookie-parser';
import dotenv from 'dotenv';
import swaggerUi = require('swagger-ui-express');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const swaggerFile = require('../spec.json');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const requestIp = require('request-ip');
dotenv.config();
import { PORT, NODE_ENV, SITE_URL } from './config';
import { apiLimiter } from './helpers/rateLimiter';
import {
workspace as eeWorkspaceRouter,
secret as eeSecretRouter,
secretSnapshot as eeSecretSnapshotRouter,
action as eeActionRouter
} from './ee/routes/v1';
import {
signup as v1SignupRouter,
auth as v1AuthRouter,
bot as v1BotRouter,
organization as v1OrganizationRouter,
workspace as v1WorkspaceRouter,
membershipOrg as v1MembershipOrgRouter,
membership as v1MembershipRouter,
key as v1KeyRouter,
inviteOrg as v1InviteOrgRouter,
user as v1UserRouter,
userAction as v1UserActionRouter,
secret as v1SecretRouter,
serviceToken as v1ServiceTokenRouter,
password as v1PasswordRouter,
stripe as v1StripeRouter,
integration as v1IntegrationRouter,
integrationAuth as v1IntegrationAuthRouter
} from './routes/v1';
import {
signup as v2SignupRouter,
auth as v2AuthRouter,
users as v2UsersRouter,
organizations as v2OrganizationsRouter,
workspace as v2WorkspaceRouter,
secret as v2SecretRouter, // begin to phase out
secrets as v2SecretsRouter,
serviceTokenData as v2ServiceTokenDataRouter,
apiKeyData as v2APIKeyDataRouter,
environment as v2EnvironmentRouter,
tags as v2TagsRouter,
} from './routes/v2';
import { healthCheck } from './routes/status';
import { getLogger } from './utils/logger';
import { RouteNotFoundError } from './utils/errors';
import { requestErrorHandler } from './middleware/requestErrorHandler';
// patch async route params to handle Promise Rejections
patchRouterParam();
export const app = express();
app.enable('trust proxy');
app.use(express.json());
app.use(cookieParser());
app.use(
cors({
credentials: true,
origin: SITE_URL
})
);
app.use(requestIp.mw())
if (NODE_ENV === 'production') {
// enable app-wide rate-limiting + helmet security
// in production
app.disable('x-powered-by');
app.use(apiLimiter);
app.use(helmet());
}
// (EE) routes
app.use('/api/v1/secret', eeSecretRouter);
app.use('/api/v1/secret-snapshot', eeSecretSnapshotRouter);
app.use('/api/v1/workspace', eeWorkspaceRouter);
app.use('/api/v1/action', eeActionRouter);
// v1 routes
app.use('/api/v1/signup', v1SignupRouter);
app.use('/api/v1/auth', v1AuthRouter);
app.use('/api/v1/bot', v1BotRouter);
app.use('/api/v1/user', v1UserRouter);
app.use('/api/v1/user-action', v1UserActionRouter);
app.use('/api/v1/organization', v1OrganizationRouter);
app.use('/api/v1/workspace', v1WorkspaceRouter);
app.use('/api/v1/membership-org', v1MembershipOrgRouter);
app.use('/api/v1/membership', v1MembershipRouter);
app.use('/api/v1/key', v1KeyRouter);
app.use('/api/v1/invite-org', v1InviteOrgRouter);
app.use('/api/v1/secret', v1SecretRouter);
app.use('/api/v1/service-token', v1ServiceTokenRouter); // deprecated
app.use('/api/v1/password', v1PasswordRouter);
app.use('/api/v1/stripe', v1StripeRouter);
app.use('/api/v1/integration', v1IntegrationRouter);
app.use('/api/v1/integration-auth', v1IntegrationAuthRouter);
// v2 routes
app.use('/api/v2/signup', v2SignupRouter);
app.use('/api/v2/auth', v2AuthRouter);
app.use('/api/v2/users', v2UsersRouter);
app.use('/api/v2/organizations', v2OrganizationsRouter);
app.use('/api/v2/workspace', v2EnvironmentRouter);
app.use('/api/v2/workspace', v2TagsRouter);
app.use('/api/v2/workspace', v2WorkspaceRouter);
app.use('/api/v2/secret', v2SecretRouter); // deprecated
app.use('/api/v2/secrets', v2SecretsRouter);
app.use('/api/v2/service-token', v2ServiceTokenDataRouter); // TODO: turn into plural route
app.use('/api/v2/api-key', v2APIKeyDataRouter);
// api docs
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerFile))
// Server status
app.use('/api', healthCheck)
//* Handle unrouted requests and respond with proper error message as well as status code
app.use((req, res, next) => {
if (res.headersSent) return next();
next(RouteNotFoundError({ message: `The requested source '(${req.method})${req.url}' was not found` }))
})
//* Error Handling Middleware (must be after all routing logic)
app.use(requestErrorHandler)
export const server = app.listen(PORT, () => {
getLogger("backend-main").info(`Server started listening at port ${PORT}`)
});

View File

@@ -1,105 +1,101 @@
const PORT = process.env.PORT || 4000;
const EMAIL_TOKEN_LIFETIME = parseInt(process.env.EMAIL_TOKEN_LIFETIME! || '86400');
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;
const LICENSE_KEY = process.env.LICENSE_KEY!;
// 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,
EMAIL_TOKEN_LIFETIME,
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,
LICENSE_KEY
// 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,
};

View File

@@ -1,8 +1,9 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import * as Sentry from '@sentry/node';
import infisical from 'infisical-node';
import { Request, Response } from 'express';
import jwt from 'jsonwebtoken';
import * as Sentry from '@sentry/node';
import * as bigintConversion from 'bigint-conversion';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const jsrp = require('jsrp');
import { User, LoginSRPDetail } from '../../models';
import { createToken, issueAuthTokens, clearTokens } from '../../helpers/auth';
@@ -11,12 +12,6 @@ import {
ACTION_LOGIN,
ACTION_LOGOUT
} from '../../variables';
import {
NODE_ENV,
JWT_AUTH_LIFETIME,
JWT_AUTH_SECRET,
JWT_REFRESH_SECRET
} from '../../config';
import { BadRequestError } from '../../utils/errors';
import { EELogService } from '../../ee/services';
import { getChannelFromUserAgent } from '../../utils/posthog'; // TODO: move this
@@ -126,7 +121,7 @@ export const login2 = async (req: Request, res: Response) => {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: NODE_ENV === 'production' ? true : false
secure: infisical.get('NODE_ENV')! === 'production' ? true : false
});
const loginAction = await EELogService.createAction({
@@ -182,7 +177,7 @@ export const logout = async (req: Request, res: Response) => {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: NODE_ENV === 'production' ? true : false
secure: infisical.get('NODE_ENV') === 'production' ? true : false
});
const logoutAction = await EELogService.createAction({
@@ -237,7 +232,7 @@ export const getNewToken = async (req: Request, res: Response) => {
}
const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(refreshToken, JWT_REFRESH_SECRET)
jwt.verify(refreshToken, infisical.get('JWT_REFRESH_SECRET')!)
);
const user = await User.findOne({
@@ -252,8 +247,8 @@ export const getNewToken = async (req: Request, res: Response) => {
payload: {
userId: decodedToken.userId
},
expiresIn: JWT_AUTH_LIFETIME,
secret: JWT_AUTH_SECRET
expiresIn: infisical.get('JWT_AUTH_LIFETIME')!,
secret: infisical.get('JWT_AUTH_SECRET')!
});
return res.status(200).send({

View File

@@ -5,7 +5,7 @@ import {
IntegrationAuth,
Bot
} from '../../models';
import { INTEGRATION_SET, INTEGRATION_OPTIONS } from '../../variables';
import { INTEGRATION_SET, getIntegrationOptions as getIntegrationOptionsFunc } from '../../variables';
import { IntegrationService } from '../../services';
import {
getApps,
@@ -39,9 +39,11 @@ export const getIntegrationAuth = async (req: Request, res: Response) => {
}
export const getIntegrationOptions = async (req: Request, res: Response) => {
return res.status(200).send({
integrationOptions: INTEGRATION_OPTIONS,
});
const INTEGRATION_OPTIONS = getIntegrationOptionsFunc();
return res.status(200).send({
integrationOptions: INTEGRATION_OPTIONS,
});
};
/**

View File

@@ -1,12 +1,12 @@
import { Request, Response } from 'express';
import infisical from 'infisical-node';
import * as Sentry from '@sentry/node';
import { Membership, MembershipOrg, User, Key, IMembership, Workspace } from '../../models';
import { Request, Response } from 'express';
import { Membership, MembershipOrg, User, Key } from '../../models';
import {
findMembership,
deleteMembership as deleteMember
} from '../../helpers/membership';
import { sendMail } from '../../helpers/nodemailer';
import { SITE_URL } from '../../config';
import { ADMIN, MEMBER, ACCEPTED } from '../../variables';
/**
@@ -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: SITE_URL + '/login'
callback_url: infisical.get('SITE_URL')! + '/login'
}
});
} catch (err) {

View File

@@ -1,6 +1,6 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { SITE_URL, JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET } from '../../config';
import { MembershipOrg, Organization, User } from '../../models';
import { deleteMembershipOrg as deleteMemberFromOrg } from '../../helpers/membershipOrg';
import { createToken } from '../../helpers/auth';
@@ -178,7 +178,7 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
organizationName: organization.name,
email: inviteeEmail,
token,
callback_url: SITE_URL + '/signupinvite'
callback_url: infisical.get('SITE_URL') + '/signupinvite'
}
});
}
@@ -250,8 +250,8 @@ export const verifyUserToOrganization = async (req: Request, res: Response) => {
payload: {
userId: user._id.toString()
},
expiresIn: JWT_SIGNUP_LIFETIME,
secret: JWT_SIGNUP_SECRET
expiresIn: infisical.get('JWT_SIGNUP_LIFETIME')!,
secret: infisical.get('JWT_SIGNUP_SECRET')!
});
} catch (err) {
Sentry.setUser(null);

View File

@@ -1,21 +1,13 @@
import { Request, Response } from 'express';
import infisical from 'infisical-node';
import * as Sentry from '@sentry/node';
import {
SITE_URL,
STRIPE_SECRET_KEY
} from '../../config';
import { Request, Response } from 'express';
import Stripe from 'stripe';
const stripe = new Stripe(STRIPE_SECRET_KEY, {
apiVersion: '2022-08-01'
});
import {
Membership,
MembershipOrg,
Organization,
Workspace,
IncidentContactOrg,
IMembershipOrg
IncidentContactOrg
} from '../../models';
import { createOrganization as create } from '../../helpers/organization';
import { addMembershipsOrg } from '../../helpers/membershipOrg';
@@ -325,6 +317,10 @@ export const createOrganizationPortalSession = async (
) => {
let session;
try {
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, {
apiVersion: '2022-08-01'
});
// check if there is a payment method on file
const paymentMethods = await stripe.paymentMethods.list({
customer: req.membershipOrg.organization.customerId,
@@ -337,13 +333,13 @@ export const createOrganizationPortalSession = async (
customer: req.membershipOrg.organization.customerId,
mode: 'setup',
payment_method_types: ['card'],
success_url: SITE_URL + '/dashboard',
cancel_url: SITE_URL + '/dashboard'
success_url: infisical.get('SITE_URL')! + '/dashboard',
cancel_url: infisical.get('SITE_URL')! + '/dashboard'
});
} else {
session = await stripe.billingPortal.sessions.create({
customer: req.membershipOrg.organization.customerId,
return_url: SITE_URL + '/dashboard'
return_url: infisical.get('SITE_URL') + '/dashboard'
});
}
@@ -369,6 +365,10 @@ export const getOrganizationSubscriptions = async (
) => {
let subscriptions;
try {
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, {
apiVersion: '2022-08-01'
});
subscriptions = await stripe.subscriptions.list({
customer: req.membershipOrg.organization.customerId
});

View File

@@ -1,3 +1,4 @@
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
@@ -7,7 +8,6 @@ import { User, BackupPrivateKey, LoginSRPDetail } from '../../models';
import { createToken } from '../../helpers/auth';
import { sendMail } from '../../helpers/nodemailer';
import { TokenService } from '../../services';
import { JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET, SITE_URL } from '../../config';
import { TOKEN_EMAIL_PASSWORD_RESET } from '../../variables';
import { BadRequestError } from '../../utils/errors';
@@ -44,7 +44,7 @@ export const emailPasswordReset = async (req: Request, res: Response) => {
substitutions: {
email,
token,
callback_url: SITE_URL + '/password-reset'
callback_url: infisical.get('SITE_URL')! + '/password-reset'
}
});
} catch (err) {
@@ -91,8 +91,8 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => {
payload: {
userId: user._id.toString()
},
expiresIn: JWT_SIGNUP_LIFETIME,
secret: JWT_SIGNUP_SECRET
expiresIn: infisical.get('JWT_SIGNUP_LIFETIME')!,
secret: infisical.get('JWT_SIGNUP_SECRET')!
});
} catch (err) {
Sentry.setUser(null);

View File

@@ -9,7 +9,7 @@ import {
import { pushKeys } from '../../helpers/key';
import { eventPushSecrets } from '../../events';
import { EventService } from '../../services';
import { postHogClient } from '../../services';
import { getPostHogClient } from '../../services';
interface PushSecret {
ciphertextKey: string;
@@ -38,6 +38,7 @@ export const pushSecrets = async (req: Request, res: Response) => {
// upload (encrypted) secrets to workspace with id [workspaceId]
try {
const postHogClient = getPostHogClient();
let { secrets }: { secrets: PushSecret[] } = req.body;
const { keys, environment, channel } = req.body;
const { workspaceId } = req.params;
@@ -111,6 +112,7 @@ export const pullSecrets = async (req: Request, res: Response) => {
let secrets;
let key;
try {
const postHogClient = getPostHogClient();
const environment: string = req.query.environment as string;
const channel: string = req.query.channel as string;
const { workspaceId } = req.params;
@@ -179,6 +181,7 @@ export const pullSecretsServiceToken = async (req: Request, res: Response) => {
let secrets;
let key;
try {
const postHogClient = getPostHogClient();
const environment: string = req.query.environment as string;
const channel: string = req.query.channel as string;
const { workspaceId } = req.params;

View File

@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express';
import { ServiceToken } from '../../models';
import { createToken } from '../../helpers/auth';
import { JWT_SERVICE_SECRET } from '../../config';
/**
* Return service token on request
@@ -61,7 +61,7 @@ export const createServiceToken = async (req: Request, res: Response) => {
workspaceId
},
expiresIn: expiresIn,
secret: JWT_SERVICE_SECRET
secret: infisical.get('JWT_SERVICE_SECRET')!
});
} catch (err) {
return res.status(400).send({

View File

@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { User } from '../../models';
import { JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET, INVITE_ONLY_SIGNUP } from '../../config';
import {
sendEmailVerification,
checkEmailVerification,
@@ -21,7 +21,7 @@ export const beginEmailSignup = async (req: Request, res: Response) => {
try {
email = req.body.email;
if (INVITE_ONLY_SIGNUP) {
if (infisical.get('INVITE_ONLY_SIGNUP') || 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: JWT_SIGNUP_LIFETIME,
secret: JWT_SIGNUP_SECRET
expiresIn: infisical.get('JWT_SIGNUP_LIFETIME')!,
secret: infisical.get('JWT_SIGNUP_SECRET')!
});
} catch (err) {
Sentry.setUser(null);

View File

@@ -1,10 +1,7 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import Stripe from 'stripe';
import { STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET } from '../../config';
const stripe = new Stripe(STRIPE_SECRET_KEY, {
apiVersion: '2022-08-01'
});
/**
* Handle service provisioning/un-provisioning via Stripe
@@ -16,11 +13,15 @@ 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')!, {
apiVersion: '2022-08-01'
});
const sig = req.headers['stripe-signature'] as string;
event = stripe.webhooks.constructEvent(
req.body,
sig,
STRIPE_WEBHOOK_SECRET // ?
infisical.get('STRIPE_WEBHOOK_SECRET')!
);
} catch (err) {
Sentry.setUser({ email: req.user.email });

View File

@@ -1,13 +1,11 @@
import { Request, Response } from 'express';
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 {
SALT_ROUNDS
} from '../../config';
/**
* Return API key data for user with id [req.user_id]
@@ -45,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, SALT_ROUNDS);
const secretHash = await bcrypt.hash(secret, parseInt(infisical.get('SALT_ROUNDS')!) || 10);
const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);

View File

@@ -1,3 +1,4 @@
import infisical from 'infisical-node';
/* eslint-disable @typescript-eslint/no-var-requires */
import { Request, Response } from 'express';
import jwt from 'jsonwebtoken';
@@ -10,11 +11,6 @@ import { checkUserDevice } from '../../helpers/user';
import { sendMail } from '../../helpers/nodemailer';
import { TokenService } from '../../services';
import { EELogService } from '../../ee/services';
import {
NODE_ENV,
JWT_MFA_LIFETIME,
JWT_MFA_SECRET
} from '../../config';
import { BadRequestError, InternalServerError } from '../../utils/errors';
import {
TOKEN_EMAIL_MFA,
@@ -28,8 +24,6 @@ declare module 'jsonwebtoken' {
}
}
const clientPublicKeys: any = {};
/**
* Log in user step 1: Return [salt] and [serverPublicKey] as part of step 1 of SRP protocol
* @param req
@@ -126,8 +120,8 @@ export const login2 = async (req: Request, res: Response) => {
payload: {
userId: user._id.toString()
},
expiresIn: JWT_MFA_LIFETIME,
secret: JWT_MFA_SECRET
expiresIn: infisical.get('JWT_MFA_LIFETIME')!,
secret: infisical.get('JWT_MFA_SECRET')!
});
const code = await TokenService.createToken({
@@ -165,7 +159,7 @@ export const login2 = async (req: Request, res: Response) => {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: NODE_ENV === 'production' ? true : false
secure: infisical.get('NODE_ENV')! === 'production' ? true : false
});
// case: user does not have MFA enablgged
@@ -304,7 +298,7 @@ export const verifyMfaToken = async (req: Request, res: Response) => {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: NODE_ENV === 'production' ? true : false
secure: infisical.get('NODE_ENV')! === 'production' ? true : false
});
interface VerifyMfaTokenRes {

View File

@@ -7,7 +7,7 @@ const { ValidationError } = mongoose.Error;
import { BadRequestError, InternalServerError, UnauthorizedRequestError, ValidationError as RouteValidationError } from '../../utils/errors';
import { AnyBulkWriteOperation } from 'mongodb';
import { SECRET_PERSONAL, SECRET_SHARED } from "../../variables";
import { postHogClient } from '../../services';
import { getPostHogClient } from '../../services';
/**
* Create secret for workspace with id [workspaceId] and environment [environment]
@@ -15,6 +15,7 @@ import { postHogClient } from '../../services';
* @param res
*/
export const createSecret = async (req: Request, res: Response) => {
const postHogClient = getPostHogClient();
const secretToCreate: CreateSecretRequestBody = req.body.secret;
const { workspaceId, environment } = req.params
const sanitizedSecret: SanitizedSecretForCreate = {
@@ -67,6 +68,7 @@ export const createSecret = async (req: Request, res: Response) => {
* @param res
*/
export const createSecrets = async (req: Request, res: Response) => {
const postHogClient = getPostHogClient();
const secretsToCreate: CreateSecretRequestBody[] = req.body.secrets;
const { workspaceId, environment } = req.params
const sanitizedSecretesToCreate: SanitizedSecretForCreate[] = []
@@ -128,6 +130,7 @@ export const createSecrets = async (req: Request, res: Response) => {
* @param res
*/
export const deleteSecrets = async (req: Request, res: Response) => {
const postHogClient = getPostHogClient();
const { workspaceId, environmentName } = req.params
const secretIdsToDelete: string[] = req.body.secretIds
@@ -181,6 +184,7 @@ export const deleteSecrets = async (req: Request, res: Response) => {
* @param res
*/
export const deleteSecret = async (req: Request, res: Response) => {
const postHogClient = getPostHogClient();
await Secret.findByIdAndDelete(req._secret._id)
if (postHogClient) {
@@ -209,6 +213,7 @@ export const deleteSecret = async (req: Request, res: Response) => {
* @returns
*/
export const updateSecrets = async (req: Request, res: Response) => {
const postHogClient = getPostHogClient();
const { workspaceId, environmentName } = req.params
const secretsModificationsRequested: ModifySecretRequestBody[] = req.body.secrets;
const [secretIdsUserCanModifyError, secretIdsUserCanModify] = await to(Secret.find({ workspace: workspaceId, environment: environmentName }, { _id: 1 }).then())
@@ -276,6 +281,7 @@ export const updateSecrets = async (req: Request, res: Response) => {
* @returns
*/
export const updateSecret = async (req: Request, res: Response) => {
const postHogClient = getPostHogClient();
const { workspaceId, environmentName } = req.params
const secretModificationsRequested: ModifySecretRequestBody = req.body.secret;
@@ -329,6 +335,7 @@ export const updateSecret = async (req: Request, res: Response) => {
* @returns
*/
export const getSecrets = async (req: Request, res: Response) => {
const postHogClient = getPostHogClient();
const { environment } = req.query;
const { workspaceId } = req.params;

View File

@@ -15,7 +15,7 @@ import { UnauthorizedRequestError, ValidationError } from '../../utils/errors';
import { EventService } from '../../services';
import { eventPushSecrets } from '../../events';
import { EESecretService, EELogService } from '../../ee/services';
import { postHogClient } from '../../services';
import { getPostHogClient } from '../../services';
import { getChannelFromUserAgent } from '../../utils/posthog';
import { ABILITY_READ, ABILITY_WRITE } from '../../variables/organization';
import { userHasNoAbility, userHasWorkspaceAccess, userHasWriteOnlyAbility } from '../../ee/helpers/checkMembershipPermissions';
@@ -33,6 +33,8 @@ import {
*/
export const batchSecrets = async (req: Request, res: Response) => {
const channel = getChannelFromUserAgent(req.headers['user-agent']);
const postHogClient = getPostHogClient();
const {
workspaceId,
environment,
@@ -326,6 +328,7 @@ export const createSecrets = async (req: Request, res: Response) => {
}
}
*/
const postHogClient = getPostHogClient();
const channel = getChannelFromUserAgent(req.headers['user-agent'])
const { workspaceId, environment }: { workspaceId: string, environment: string } = req.body;
@@ -530,6 +533,7 @@ export const getSecrets = async (req: Request, res: Response) => {
}
*/
const postHogClient = getPostHogClient();
const { workspaceId, environment, tagSlugs } = req.query;
const tagNamesList = typeof tagSlugs === 'string' && tagSlugs !== '' ? tagSlugs.split(',') : [];
@@ -732,6 +736,7 @@ export const updateSecrets = async (req: Request, res: Response) => {
}
}
*/
const postHogClient = getPostHogClient();
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
// TODO: move type
@@ -953,7 +958,7 @@ export const deleteSecrets = async (req: Request, res: Response) => {
}
}
*/
const postHogClient = getPostHogClient();
const channel = getChannelFromUserAgent(req.headers['user-agent'])
const toDelete = req.secrets.map((s: any) => s._id);

View File

@@ -1,13 +1,11 @@
import { Request, Response } from 'express';
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 {
ServiceTokenData
} from '../../models';
import {
SALT_ROUNDS
} from '../../config';
import { userHasWorkspaceAccess } from '../../ee/helpers/checkMembershipPermissions';
import { ABILITY_READ } from '../../variables/organization';
@@ -75,7 +73,7 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
}
const secret = crypto.randomBytes(16).toString('hex');
const secretHash = await bcrypt.hash(secret, SALT_ROUNDS);
const secretHash = await bcrypt.hash(secret, parseInt(infisical.get('SALT_ROUNDS')!) || 10);
const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);

View File

@@ -1,3 +1,4 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { User, MembershipOrg } from '../../models';
@@ -7,7 +8,6 @@ import {
} from '../../helpers/signup';
import { issueAuthTokens } from '../../helpers/auth';
import { INVITED, ACCEPTED } from '../../variables';
import { NODE_ENV } from '../../config';
import request from '../../config/request';
/**
@@ -127,7 +127,7 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: NODE_ENV === 'production' ? true : false
secure: infisical.get('NODE_ENV')! === '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: NODE_ENV === 'production' ? true : false
secure: infisical.get('NODE_ENV')! === 'production' ? true : false
});
} catch (err) {
Sentry.setUser(null);

View File

@@ -19,7 +19,7 @@ import {
reformatPullSecrets
} from '../../helpers/secret';
import { pushKeys } from '../../helpers/key';
import { postHogClient, EventService } from '../../services';
import { getPostHogClient, EventService } from '../../services';
import { eventPushSecrets } from '../../events';
interface V2PushSecret {
@@ -48,6 +48,7 @@ interface V2PushSecret {
export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
// upload (encrypted) secrets to workspace with id [workspaceId]
try {
const postHogClient = getPostHogClient();
let { secrets }: { secrets: V2PushSecret[] } = req.body;
const { keys, environment, channel } = req.body;
const { workspaceId } = req.params;
@@ -121,6 +122,7 @@ export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
export const pullSecrets = async (req: Request, res: Response) => {
let secrets;
try {
const postHogClient = getPostHogClient();
const environment: string = req.query.environment as string;
const channel: string = req.query.channel as string;
const { workspaceId } = req.params;

View File

@@ -1,10 +1,7 @@
import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import infisical from 'infisical-node';
import { Request, Response } from 'express';
import Stripe from 'stripe';
import { STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET } from '../../../config';
const stripe = new Stripe(STRIPE_SECRET_KEY, {
apiVersion: '2022-08-01'
});
/**
* Handle service provisioning/un-provisioning via Stripe
@@ -15,12 +12,16 @@ const stripe = new Stripe(STRIPE_SECRET_KEY, {
export const handleWebhook = async (req: Request, res: Response) => {
let event;
try {
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, {
apiVersion: '2022-08-01'
});
// check request for valid stripe signature
const sig = req.headers['stripe-signature'] as string;
event = stripe.webhooks.constructEvent(
req.body,
sig,
STRIPE_WEBHOOK_SECRET // ?
infisical.get('STRIPE_WEBHOOK_SECRET')!
);
} catch (err) {
Sentry.setUser({ email: req.user.email });

View File

@@ -1,5 +1,3 @@
import { LICENSE_KEY } from '../../config';
/**
* Class to handle Enterprise Edition license actions
*/
@@ -16,4 +14,4 @@ class EELicenseService {
}
}
export default new EELicenseService(LICENSE_KEY);
export default new EELicenseService('N/A');

View File

@@ -1,5 +1,6 @@
import jwt from 'jsonwebtoken';
import * as Sentry from '@sentry/node';
import infisical from 'infisical-node';
import jwt from 'jsonwebtoken';
import bcrypt from 'bcrypt';
import {
IUser,
@@ -7,12 +8,6 @@ import {
ServiceTokenData,
APIKeyData
} from '../models';
import {
JWT_AUTH_LIFETIME,
JWT_AUTH_SECRET,
JWT_REFRESH_LIFETIME,
JWT_REFRESH_SECRET
} from '../config';
import {
AccountNotFoundError,
ServiceTokenDataNotFoundError,
@@ -93,7 +88,7 @@ const getAuthUserPayload = async ({
let user;
try {
const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(authTokenValue, JWT_AUTH_SECRET)
jwt.verify(authTokenValue, infisical.get('JWT_AUTH_SECRET')!)
);
user = await User.findOne({
@@ -224,16 +219,16 @@ const issueAuthTokens = async ({ userId }: { userId: string }) => {
payload: {
userId
},
expiresIn: JWT_AUTH_LIFETIME,
secret: JWT_AUTH_SECRET
expiresIn: infisical.get('JWT_AUTH_LIFETIME')!,
secret: infisical.get('JWT_AUTH_SECRET')!
});
refreshToken = createToken({
payload: {
userId
},
expiresIn: JWT_REFRESH_LIFETIME,
secret: JWT_REFRESH_SECRET
expiresIn: infisical.get('JWT_REFRESH_LIFETIME')!,
secret: infisical.get('JWT_REFRESH_SECRET')!
});
} catch (err) {
Sentry.setUser(null);

View File

@@ -1,4 +1,5 @@
import * as Sentry from '@sentry/node';
import infisical from 'infisical-node';
import {
Bot,
BotKey,
@@ -12,7 +13,6 @@ import {
decryptSymmetric,
decryptAsymmetric
} from '../utils/crypto';
import { ENCRYPTION_KEY } from '../config';
import { SECRET_SHARED } from '../variables';
/**
@@ -33,7 +33,7 @@ const createBot = async ({
const { publicKey, privateKey } = generateKeyPair();
const { ciphertext, iv, tag } = encryptSymmetric({
plaintext: privateKey,
key: ENCRYPTION_KEY
key: infisical.get('ENCRYPTION_KEY')!
});
bot = await new Bot({
@@ -130,7 +130,7 @@ const getKey = async ({ workspaceId }: { workspaceId: string }) => {
ciphertext: bot.encryptedPrivateKey,
iv: bot.iv,
tag: bot.tag,
key: ENCRYPTION_KEY
key: infisical.get('ENCRYPTION_KEY')!
});
key = decryptAsymmetric({

View File

@@ -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 { SMTP_FROM_NAME, SMTP_FROM_ADDRESS } from '../config';
import * as Sentry from '@sentry/node';
let smtpTransporter: nodemailer.Transporter;
@@ -34,7 +34,7 @@ const sendMail = async ({
const htmlToSend = temp(substitutions);
await smtpTransporter.sendMail({
from: `"${SMTP_FROM_NAME}" <${SMTP_FROM_ADDRESS}>`,
from: `"${infisical.get('SMTP_FROM_NAME')!}" <${infisical.get('SMTP_FROM_ADDRESS')!}>`,
to: recipients.join(', '),
subject: subjectLine,
html: htmlToSend

View File

@@ -1,24 +1,10 @@
import infisical from 'infisical-node';
import * as Sentry from '@sentry/node';
import Stripe from 'stripe';
import {
STRIPE_SECRET_KEY,
STRIPE_PRODUCT_STARTER,
STRIPE_PRODUCT_TEAM,
STRIPE_PRODUCT_PRO
} from '../config';
const stripe = new Stripe(STRIPE_SECRET_KEY, {
apiVersion: '2022-08-01'
});
import { Types } from 'mongoose';
import { ACCEPTED } from '../variables';
import { Organization, MembershipOrg } from '../models';
const productToPriceMap = {
starter: STRIPE_PRODUCT_STARTER,
team: STRIPE_PRODUCT_TEAM,
pro: STRIPE_PRODUCT_PRO
};
/**
* Create an organization with name [name]
* @param {Object} obj
@@ -36,8 +22,11 @@ const createOrganization = async ({
let organization;
try {
// register stripe account
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, {
apiVersion: '2022-08-01'
});
if (STRIPE_SECRET_KEY) {
if (infisical.get('STRIPE_SECRET_KEY')) {
const customer = await stripe.customers.create({
email,
description: name
@@ -87,6 +76,16 @@ const initSubscriptionOrg = async ({
if (organization) {
if (organization.customerId) {
// initialize starter subscription with quantity of 0
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, {
apiVersion: '2022-08-01'
});
const productToPriceMap = {
starter: infisical.get('STRIPE_PRODUCT_STARTER')!,
team: infisical.get('STRIPE_PRODUCT_TEAM')!,
pro: infisical.get('STRIPE_PRODUCT_PRO')!
};
stripeSubscription = await stripe.subscriptions.create({
customer: organization.customerId,
items: [
@@ -139,6 +138,10 @@ const updateSubscriptionOrgQuantity = async ({
status: ACCEPTED
});
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, {
apiVersion: '2022-08-01'
});
const subscription = (
await stripe.subscriptions.list({
customer: organization.customerId

View File

@@ -1,4 +1,5 @@
import * as Sentry from '@sentry/node';
import infisical from 'infisical-node';
import { Types } from 'mongoose';
import { TokenData } from '../models';
import crypto from 'crypto';
@@ -9,9 +10,6 @@ import {
TOKEN_EMAIL_ORG_INVITATION,
TOKEN_EMAIL_PASSWORD_RESET
} from '../variables';
import {
SALT_ROUNDS
} from '../config';
import { UnauthorizedRequestError } from '../utils/errors';
/**
@@ -86,7 +84,7 @@ const createTokenHelper = async ({
const query: TokenDataQuery = { type };
const update: TokenDataUpdate = {
type,
tokenHash: await bcrypt.hash(token, SALT_ROUNDS),
tokenHash: await bcrypt.hash(token, parseInt(infisical.get('SALT_ROUNDS')!) || 10),
expiresAt
}

View File

@@ -1,28 +1,168 @@
import dotenv from 'dotenv';
dotenv.config();
import infisical from 'infisical-node';
import express from 'express';
import helmet from 'helmet';
import cors from 'cors';
import * as Sentry from '@sentry/node';
import { SENTRY_DSN, NODE_ENV, MONGO_URL } from './config';
import { server } from './app';
import { DatabaseService } from './services';
import { setUpHealthEndpoint } from './services/health';
import { initSmtp } from './services/smtp';
import { logTelemetryMessage } from './services';
import { setTransporter } from './helpers/nodemailer';
import { createTestUserForDevelopment } from './utils/addDevelopmentUser';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { patchRouterParam } = require('./utils/patchAsyncRoutes');
DatabaseService.initDatabase(MONGO_URL);
import cookieParser from 'cookie-parser';
import swaggerUi = require('swagger-ui-express');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const swaggerFile = require('../spec.json');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const requestIp = require('request-ip');
import { apiLimiter } from './helpers/rateLimiter';
import {
workspace as eeWorkspaceRouter,
secret as eeSecretRouter,
secretSnapshot as eeSecretSnapshotRouter,
action as eeActionRouter
} from './ee/routes/v1';
import {
signup as v1SignupRouter,
auth as v1AuthRouter,
bot as v1BotRouter,
organization as v1OrganizationRouter,
workspace as v1WorkspaceRouter,
membershipOrg as v1MembershipOrgRouter,
membership as v1MembershipRouter,
key as v1KeyRouter,
inviteOrg as v1InviteOrgRouter,
user as v1UserRouter,
userAction as v1UserActionRouter,
secret as v1SecretRouter,
serviceToken as v1ServiceTokenRouter,
password as v1PasswordRouter,
stripe as v1StripeRouter,
integration as v1IntegrationRouter,
integrationAuth as v1IntegrationAuthRouter
} from './routes/v1';
import {
signup as v2SignupRouter,
auth as v2AuthRouter,
users as v2UsersRouter,
organizations as v2OrganizationsRouter,
workspace as v2WorkspaceRouter,
secret as v2SecretRouter, // begin to phase out
secrets as v2SecretsRouter,
serviceTokenData as v2ServiceTokenDataRouter,
apiKeyData as v2APIKeyDataRouter,
environment as v2EnvironmentRouter,
tags as v2TagsRouter,
} from './routes/v2';
import { healthCheck } from './routes/status';
import { getLogger } from './utils/logger';
import { RouteNotFoundError } from './utils/errors';
import { requestErrorHandler } from './middleware/requestErrorHandler';
setUpHealthEndpoint(server);
const main = async () => {
const client = await infisical.connect({
token: process.env.INFISICAL_TOKEN!,
debug: true
});
logTelemetryMessage();
setTransporter(initSmtp());
setTransporter(initSmtp());
await DatabaseService.initDatabase(infisical.get('MONGO_URL')!);
if (infisical.get('NODE_ENV') !== 'test') {
Sentry.init({
dsn: infisical.get('SENTRY_DSN') as string,
tracesSampleRate: 1.0,
debug: infisical.get('NODE_ENV') === 'production' ? false : true,
environment: infisical.get('NODE_ENV') as string
});
}
if (NODE_ENV !== 'test') {
Sentry.init({
dsn: SENTRY_DSN,
tracesSampleRate: 1.0,
debug: NODE_ENV === 'production' ? false : true,
environment: NODE_ENV
});
patchRouterParam();
const app = express();
app.enable('trust proxy');
app.use(express.json());
app.use(cookieParser());
app.use(
cors({
credentials: true,
origin: infisical.get('SITE_URL') as string
})
);
app.use(requestIp.mw());
if (infisical.get('NODE_ENV') === 'production') {
// enable app-wide rate-limiting + helmet security
// in production
app.disable('x-powered-by');
app.use(apiLimiter);
app.use(helmet());
}
// (EE) routes
app.use('/api/v1/secret', eeSecretRouter);
app.use('/api/v1/secret-snapshot', eeSecretSnapshotRouter);
app.use('/api/v1/workspace', eeWorkspaceRouter);
app.use('/api/v1/action', eeActionRouter);
// v1 routes
app.use('/api/v1/signup', v1SignupRouter);
app.use('/api/v1/auth', v1AuthRouter);
app.use('/api/v1/bot', v1BotRouter);
app.use('/api/v1/user', v1UserRouter);
app.use('/api/v1/user-action', v1UserActionRouter);
app.use('/api/v1/organization', v1OrganizationRouter);
app.use('/api/v1/workspace', v1WorkspaceRouter);
app.use('/api/v1/membership-org', v1MembershipOrgRouter);
app.use('/api/v1/membership', v1MembershipRouter);
app.use('/api/v1/key', v1KeyRouter);
app.use('/api/v1/invite-org', v1InviteOrgRouter);
app.use('/api/v1/secret', v1SecretRouter);
app.use('/api/v1/service-token', v1ServiceTokenRouter); // deprecated
app.use('/api/v1/password', v1PasswordRouter);
app.use('/api/v1/stripe', v1StripeRouter);
app.use('/api/v1/integration', v1IntegrationRouter);
app.use('/api/v1/integration-auth', v1IntegrationAuthRouter);
// v2 routes
app.use('/api/v2/signup', v2SignupRouter);
app.use('/api/v2/auth', v2AuthRouter);
app.use('/api/v2/users', v2UsersRouter);
app.use('/api/v2/organizations', v2OrganizationsRouter);
app.use('/api/v2/workspace', v2EnvironmentRouter);
app.use('/api/v2/workspace', v2TagsRouter);
app.use('/api/v2/workspace', v2WorkspaceRouter);
app.use('/api/v2/secret', v2SecretRouter); // deprecated
app.use('/api/v2/secrets', v2SecretsRouter);
app.use('/api/v2/service-token', v2ServiceTokenDataRouter); // TODO: turn into plural route
app.use('/api/v2/api-key', v2APIKeyDataRouter);
// api docs
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerFile))
// Server status
app.use('/api', healthCheck)
//* Handle unrouted requests and respond with proper error message as well as status code
app.use((req, res, next) => {
if (res.headersSent) return next();
next(RouteNotFoundError({ message: `The requested source '(${req.method})${req.url}' was not found` }))
})
app.use(requestErrorHandler)
const server = app.listen(Number(infisical.get('PORT')) || 4000, () => {
createTestUserForDevelopment();
getLogger("backend-main").info(`Server started listening at port ${Number(infisical.get('PORT')) || 4000}`)
});
setUpHealthEndpoint(server);
}
createTestUserForDevelopment()
main();

View File

@@ -1,5 +1,6 @@
import request from '../config/request';
import infisical from 'infisical-node';
import * as Sentry from '@sentry/node';
import request from '../config/request';
import {
INTEGRATION_AZURE_KEY_VAULT,
INTEGRATION_HEROKU,
@@ -14,20 +15,6 @@ import {
INTEGRATION_GITHUB_TOKEN_URL,
INTEGRATION_GITLAB_TOKEN_URL
} from '../variables';
import {
SITE_URL,
CLIENT_ID_AZURE,
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,
} from '../config';
interface ExchangeCodeAzureResponse {
token_type: string;
@@ -159,9 +146,9 @@ const exchangeCodeAzure = async ({
grant_type: 'authorization_code',
code: code,
scope: 'https://vault.azure.net/.default openid offline_access',
client_id: CLIENT_ID_AZURE,
client_secret: CLIENT_SECRET_AZURE,
redirect_uri: `${SITE_URL}/integrations/azure-key-vault/oauth2/callback`
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`
} as any)
)).data;
@@ -204,7 +191,7 @@ const exchangeCodeHeroku = async ({
new URLSearchParams({
grant_type: 'authorization_code',
code: code,
client_secret: CLIENT_SECRET_HEROKU
client_secret: infisical.get('CLIENT_SECRET_HEROKU')!
} as any)
)).data;
@@ -242,9 +229,9 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => {
INTEGRATION_VERCEL_TOKEN_URL,
new URLSearchParams({
code: code,
client_id: CLIENT_ID_VERCEL,
client_secret: CLIENT_SECRET_VERCEL,
redirect_uri: `${SITE_URL}/integrations/vercel/oauth2/callback`
client_id: infisical.get('CLIENT_ID_VERCEL')!,
client_secret: infisical.get('CLIENT_SECRET_VERCEL')!,
redirect_uri: `${infisical.get('SITE_URL')!}/integrations/vercel/oauth2/callback`
} as any)
)
).data;
@@ -282,9 +269,9 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => {
new URLSearchParams({
grant_type: 'authorization_code',
code: code,
client_id: CLIENT_ID_NETLIFY,
client_secret: CLIENT_SECRET_NETLIFY,
redirect_uri: `${SITE_URL}/integrations/netlify/oauth2/callback`
client_id: infisical.get('CLIENT_ID_NETLIFY')!,
client_secret: infisical.get('CLIENT_SECRET_NETLIFY')!,
redirect_uri: `${infisical.get('SITE_URL')!}/integrations/netlify/oauth2/callback`
} as any)
)
).data;
@@ -333,10 +320,10 @@ const exchangeCodeGithub = async ({ code }: { code: string }) => {
res = (
await request.get(INTEGRATION_GITHUB_TOKEN_URL, {
params: {
client_id: CLIENT_ID_GITHUB,
client_secret: CLIENT_SECRET_GITHUB,
client_id: infisical.get('CLIENT_ID_GITHUB')!,
client_secret: infisical.get('CLIENT_SECRET_GITHUB')!,
code: code,
redirect_uri: `${SITE_URL}/integrations/github/oauth2/callback`
redirect_uri: `${infisical.get('SITE_URL')!}/integrations/github/oauth2/callback`
},
headers: {
'Accept': 'application/json',
@@ -379,9 +366,9 @@ const exchangeCodeGitlab = async ({ code }: { code: string }) => {
new URLSearchParams({
grant_type: 'authorization_code',
code: code,
client_id: CLIENT_ID_GITLAB,
client_secret: CLIENT_SECRET_GITLAB,
redirect_uri: `${SITE_URL}/integrations/gitlab/oauth2/callback`
client_id: infisical.get('CLIENT_ID_GITLAB')!,
client_secret: infisical.get('CLIENT_SECRET_GITLAB')!,
redirect_uri: `${infisical.get('SITE_URL')}/integrations/gitlab/oauth2/callback`
} as any),
{
headers: {

View File

@@ -1,5 +1,6 @@
import request from '../config/request';
import infisical from 'infisical-node';
import * as Sentry from '@sentry/node';
import request from '../config/request';
import {
IIntegrationAuth
} from '../models';
@@ -8,14 +9,13 @@ import {
INTEGRATION_HEROKU,
INTEGRATION_GITLAB,
} from '../variables';
import {
SITE_URL,
CLIENT_ID_AZURE,
CLIENT_ID_GITLAB,
CLIENT_SECRET_AZURE,
CLIENT_SECRET_HEROKU,
CLIENT_SECRET_GITLAB
} from '../config';
// 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,
@@ -133,11 +133,11 @@ const exchangeRefreshAzure = async ({
const { data }: { data: RefreshTokenAzureResponse } = await request.post(
INTEGRATION_AZURE_TOKEN_URL,
new URLSearchParams({
client_id: CLIENT_ID_AZURE,
client_id: infisical.get('CLIENT_ID_AZURE')!,
scope: 'openid offline_access',
refresh_token: refreshToken,
grant_type: 'refresh_token',
client_secret: CLIENT_SECRET_AZURE
client_secret: infisical.get('CLIENT_SECRET_AZURE')!
} as any)
);
@@ -180,7 +180,7 @@ const exchangeRefreshHeroku = async ({
new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_secret: CLIENT_SECRET_HEROKU
client_secret: infisical.get('CLIENT_SECRET_HEROKU')!
} as any)
);
@@ -223,9 +223,9 @@ const exchangeRefreshGitLab = async ({
new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: CLIENT_ID_GITLAB,
client_secret: CLIENT_SECRET_GITLAB,
redirect_uri: `${SITE_URL}/integrations/gitlab/oauth2/callback`
client_id: infisical.get('CLIENT_ID_GITLAB')!,
client_secret: infisical.get('CLIENT_SECRET_GITLAB')!,
redirect_uri: `${infisical.get('SITE_URL')!}/integrations/gitlab/oauth2/callback`
} as any),
{
headers: {

View File

@@ -1,16 +1,13 @@
import { ErrorRequestHandler } from "express";
import infisical from 'infisical-node';
import * as Sentry from '@sentry/node';
import { ErrorRequestHandler } from "express";
import { InternalServerError, UnauthorizedRequestError } from "../utils/errors";
import { getLogger } from "../utils/logger";
import RequestError, { LogLevel } from "../utils/requestError";
import { NODE_ENV } from "../config";
import { TokenExpiredError } from 'jsonwebtoken';
export const requestErrorHandler: ErrorRequestHandler = (error: RequestError | Error, req, res, next) => {
if (res.headersSent) return next();
if (NODE_ENV !== "production") {
if (infisical.get('NODE_ENV')! !== "production") {
/* eslint-disable no-console */
console.log(error)
/* eslint-enable no-console */

View File

@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express';
import { User } from '../models';
import { JWT_MFA_SECRET } from '../config';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
declare module 'jsonwebtoken' {
@@ -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.UserIDJwtPayload>(
jwt.verify(AUTH_TOKEN_VALUE, JWT_MFA_SECRET)
jwt.verify(AUTH_TOKEN_VALUE, infisical.get('JWT_MFA_SECRET')!)
);
const user = await User.findOne({

View File

@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express';
import { ServiceToken } from '../models';
import { JWT_SERVICE_SECRET } from '../config';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
// TODO: deprecate
@@ -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.UserIDJwtPayload>(
jwt.verify(AUTH_TOKEN_VALUE, JWT_SERVICE_SECRET)
jwt.verify(AUTH_TOKEN_VALUE, infisical.get('JWT_SERVICE_SECRET')!)
);
const serviceToken = await ServiceToken.findOne({

View File

@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express';
import { User } from '../models';
import { JWT_SIGNUP_SECRET } from '../config';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
declare module 'jsonwebtoken' {
@@ -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.UserIDJwtPayload>(
jwt.verify(AUTH_TOKEN_VALUE, JWT_SIGNUP_SECRET)
jwt.verify(AUTH_TOKEN_VALUE, infisical.get('JWT_SIGNUP_SECRET')!)
);
const user = await User.findOne({

View File

@@ -1,5 +1,4 @@
import { Schema, model } from 'mongoose';
import { EMAIL_TOKEN_LIFETIME } from '../config';
export interface IToken {
email: string;

View File

@@ -1,27 +1,41 @@
import infisical from 'infisical-node';
import { PostHog } from 'posthog-node';
import {
NODE_ENV,
POSTHOG_HOST,
POSTHOG_PROJECT_API_KEY,
TELEMETRY_ENABLED
} from '../config';
import { getLogger } from '../utils/logger';
if(!TELEMETRY_ENABLED){
getLogger("backend-main").info([
"",
"To improve, Infisical collects telemetry data about general usage.",
"This helps us understand how the product is doing and guide our product development to create the best possible platform; it also helps us demonstrate growth as we support Infisical as open-source software.",
"To opt into telemetry, you can set `TELEMETRY_ENABLED=true` within the environment variables.",
].join('\n'))
/**
* Logs telemetry enable/disable notice.
*/
const logTelemetryMessage = () => {
const TELEMETRY_ENABLED = infisical.get('TELEMETRY_ENABLED')! !== 'false' && true;
if(!TELEMETRY_ENABLED){
getLogger("backend-main").info([
"",
"To improve, Infisical collects telemetry data about general usage.",
"This helps us understand how the product is doing and guide our product development to create the best possible platform; it also helps us demonstrate growth as we support Infisical as open-source software.",
"To opt into telemetry, you can set `TELEMETRY_ENABLED=true` within the environment variables.",
].join('\n'))
}
}
let postHogClient: any;
if (NODE_ENV === 'production' && TELEMETRY_ENABLED) {
// case: enable opt-out telemetry in production
postHogClient = new PostHog(POSTHOG_PROJECT_API_KEY, {
host: POSTHOG_HOST
});
/**
* Return an instance of the PostHog client initialized.
* @returns
*/
const getPostHogClient = () => {
let postHogClient: any;
const TELEMETRY_ENABLED = infisical.get('TELEMETRY_ENABLED')! !== 'false' && true;
if (infisical.get('NODE_ENV') === 'production' && TELEMETRY_ENABLED) {
// case: enable opt-out telemetry in production
postHogClient = new PostHog(infisical.get('POSTHOG_PROJECT_API_KEY')! || 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE', {
host: infisical.get('POSTHOG_HOST')!
});
}
return postHogClient;
}
export {
logTelemetryMessage,
getPostHogClient
}
export default postHogClient;

View File

@@ -1,13 +1,14 @@
import DatabaseService from './DatabaseService';
import postHogClient from './PostHogClient';
import { logTelemetryMessage, getPostHogClient } from './PostHogClient';
import BotService from './BotService';
import EventService from './EventService';
import IntegrationService from './IntegrationService';
import TokenService from './TokenService';
export {
logTelemetryMessage,
getPostHogClient,
DatabaseService,
postHogClient,
BotService,
EventService,
IntegrationService,

View File

@@ -1,11 +1,5 @@
import infisical from 'infisical-node';
import nodemailer from 'nodemailer';
import {
SMTP_HOST,
SMTP_PORT,
SMTP_USERNAME,
SMTP_PASSWORD,
SMTP_SECURE
} from '../config';
import {
SMTP_HOST_SENDGRID,
SMTP_HOST_MAILGUN,
@@ -15,54 +9,54 @@ import {
import SMTPConnection from 'nodemailer/lib/smtp-connection';
import * as Sentry from '@sentry/node';
const mailOpts: SMTPConnection.Options = {
host: SMTP_HOST,
port: SMTP_PORT as number
};
if (SMTP_USERNAME && SMTP_PASSWORD) {
mailOpts.auth = {
user: SMTP_USERNAME,
pass: SMTP_PASSWORD
export const initSmtp = () => {
const mailOpts: SMTPConnection.Options = {
host: infisical.get('SMTP_HOST')!,
port: parseInt(infisical.get('SMTP_PORT')!)
};
}
if (SMTP_SECURE) {
switch (SMTP_HOST) {
case SMTP_HOST_SENDGRID:
mailOpts.requireTLS = true;
break;
case SMTP_HOST_MAILGUN:
mailOpts.requireTLS = true;
mailOpts.tls = {
ciphers: 'TLSv1.2'
}
break;
case SMTP_HOST_SOCKETLABS:
mailOpts.requireTLS = true;
mailOpts.tls = {
ciphers: 'TLSv1.2'
}
break;
case SMTP_HOST_ZOHOMAIL:
mailOpts.requireTLS = true;
mailOpts.tls = {
ciphers: 'TLSv1.2'
}
break;
default:
if (SMTP_HOST.includes('amazonaws.com')) {
if (infisical.get('SMTP_USERNAME')! && infisical.get('SMTP_PASSWORD')!) {
mailOpts.auth = {
user: infisical.get('SMTP_USERNAME')!,
pass: infisical.get('SMTP_PASSWORD')!
};
}
if (infisical.get('SMTP_SECURE')! ? infisical.get('SMTP_SECURE')! === 'true' : false) {
switch (infisical.get('SMTP_HOST')!) {
case SMTP_HOST_SENDGRID:
mailOpts.requireTLS = true;
break;
case SMTP_HOST_MAILGUN:
mailOpts.requireTLS = true;
mailOpts.tls = {
ciphers: 'TLSv1.2'
}
} else {
mailOpts.secure = true;
}
break;
break;
case SMTP_HOST_SOCKETLABS:
mailOpts.requireTLS = true;
mailOpts.tls = {
ciphers: 'TLSv1.2'
}
break;
case SMTP_HOST_ZOHOMAIL:
mailOpts.requireTLS = true;
mailOpts.tls = {
ciphers: 'TLSv1.2'
}
break;
default:
if (infisical.get('SMTP_HOST')!.includes('amazonaws.com')) {
mailOpts.tls = {
ciphers: 'TLSv1.2'
}
} else {
mailOpts.secure = true;
}
break;
}
}
}
export const initSmtp = () => {
const transporter = nodemailer.createTransport(mailOpts);
transporter
.verify()
@@ -73,7 +67,7 @@ export const initSmtp = () => {
.catch((err) => {
Sentry.setUser(null);
Sentry.captureException(
`SMTP - Failed to connect to ${SMTP_HOST}:${SMTP_PORT} \n\t${err}`
`SMTP - Failed to connect to ${infisical.get('SMTP_HOST')!}:${infisical.get('SMTP_PORT')!} \n\t${err}`
);
});

View File

@@ -4,12 +4,12 @@
*
************************************************************************************************/
import { NODE_ENV } from "../config"
import infisical from 'infisical-node';
import { Key, Membership, MembershipOrg, Organization, User, Workspace } from "../models";
import { Types } from 'mongoose';
export const createTestUserForDevelopment = async () => {
if (NODE_ENV === "development") {
if (infisical.get('NODE_ENV') === "development") {
const testUserEmail = "test@localhost.local"
const testUserPassword = "testInfisical1"
const testUserId = "63cefa6ec8d3175601cfa980"

View File

@@ -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 { LOKI_HOST, NODE_ENV } 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(LOKI_HOST !== undefined){
if(infisical.get('LOKI_HOST')! !== undefined){
_transports.push(
new LokiTransport({
host: LOKI_HOST,
host: infisical.get('LOKI_HOST')!,
handleExceptions: true,
handleRejections: true,
batching: true,
@@ -37,7 +37,11 @@ const createLoggerWithLabel = (level: string, label: string) => {
format: format.combine(
format.json()
),
labels: {app: process.env.npm_package_name, version: process.env.npm_package_version, environment: NODE_ENV},
labels: {
app: process.env.npm_package_name,
version: process.env.npm_package_version,
environment: infisical.get('NODE_ENV')!
},
onConnectionError: (err: Error)=> console.error('Connection error while connecting to Loki Server.\n', err)
})
)

View File

@@ -1,5 +1,5 @@
import infisical from 'infisical-node';
import { Request } from 'express'
import { VERBOSE_ERROR_OUTPUT } from '../config'
export enum LogLevel {
DEBUG = 100,
@@ -87,6 +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){
_context = this._omit(_context, [
'stacktrace',

View File

@@ -34,7 +34,7 @@ import {
INTEGRATION_FLYIO_API_URL,
INTEGRATION_CIRCLECI_API_URL,
INTEGRATION_TRAVISCI_API_URL,
INTEGRATION_OPTIONS,
getIntegrationOptions
} from "./integration";
import { OWNER, ADMIN, MEMBER, INVITED, ACCEPTED } from "./organization";
import { SECRET_SHARED, SECRET_PERSONAL } from "./secret";
@@ -113,7 +113,7 @@ export {
ACTION_UPDATE_SECRETS,
ACTION_DELETE_SECRETS,
ACTION_READ_SECRETS,
INTEGRATION_OPTIONS,
getIntegrationOptions,
SMTP_HOST_SENDGRID,
SMTP_HOST_MAILGUN,
SMTP_HOST_SOCKETLABS,

View File

@@ -1,13 +1,4 @@
import {
CLIENT_ID_AZURE,
CLIENT_ID_GITLAB
} from '../config';
import {
CLIENT_ID_HEROKU,
CLIENT_ID_NETLIFY,
CLIENT_ID_GITHUB,
CLIENT_SLUG_VERCEL
} from "../config";
import infisical from 'infisical-node';
// integrations
const INTEGRATION_AZURE_KEY_VAULT = 'azure-key-vault';
@@ -48,7 +39,6 @@ const INTEGRATION_GITHUB_TOKEN_URL =
"https://github.com/login/oauth/access_token";
const INTEGRATION_GITLAB_TOKEN_URL = "https://gitlab.com/oauth/token";
// integration apps endpoints
const INTEGRATION_HEROKU_API_URL = "https://api.heroku.com";
const INTEGRATION_GITLAB_API_URL = "https://gitlab.com/api";
@@ -59,156 +49,160 @@ const INTEGRATION_FLYIO_API_URL = "https://api.fly.io/graphql";
const INTEGRATION_CIRCLECI_API_URL = "https://circleci.com/api";
const INTEGRATION_TRAVISCI_API_URL = "https://api.travis-ci.com";
// TODO: deprecate types?
const INTEGRATION_OPTIONS = [
{
name: 'Heroku',
slug: 'heroku',
image: 'Heroku.png',
isAvailable: true,
type: 'oauth',
clientId: CLIENT_ID_HEROKU,
docsLink: ''
},
{
name: 'Vercel',
slug: 'vercel',
image: 'Vercel.png',
isAvailable: true,
type: 'oauth',
clientId: '',
clientSlug: CLIENT_SLUG_VERCEL,
docsLink: ''
},
{
name: 'Netlify',
slug: 'netlify',
image: 'Netlify.png',
isAvailable: true,
type: 'oauth',
clientId: CLIENT_ID_NETLIFY,
docsLink: ''
},
{
name: 'GitHub',
slug: 'github',
image: 'GitHub.png',
isAvailable: true,
type: 'oauth',
clientId: CLIENT_ID_GITHUB,
docsLink: ''
},
{
name: 'Render',
slug: 'render',
image: 'Render.png',
isAvailable: true,
type: 'pat',
clientId: '',
docsLink: ''
},
{
name: 'Fly.io',
slug: 'flyio',
image: 'Flyio.svg',
isAvailable: true,
type: 'pat',
clientId: '',
docsLink: ''
},
{
name: 'AWS Parameter Store',
slug: 'aws-parameter-store',
image: 'Amazon Web Services.png',
isAvailable: true,
type: 'custom',
clientId: '',
docsLink: ''
},
{
name: 'AWS Secret Manager',
slug: 'aws-secret-manager',
image: 'Amazon Web Services.png',
isAvailable: true,
type: 'custom',
clientId: '',
docsLink: ''
},
{
name: 'Azure Key Vault',
slug: 'azure-key-vault',
image: 'Microsoft Azure.png',
isAvailable: true,
type: 'oauth',
clientId: CLIENT_ID_AZURE,
docsLink: ''
},
{
name: 'Circle CI',
slug: 'circleci',
image: 'Circle CI.png',
isAvailable: true,
type: 'pat',
clientId: '',
docsLink: ''
},
{
name: 'GitLab',
slug: 'gitlab',
image: 'GitLab.png',
isAvailable: true,
type: 'custom',
clientId: CLIENT_ID_GITLAB,
docsLink: ''
},
{
name: 'Travis CI',
slug: 'travisci',
image: 'Travis CI.png',
isAvailable: true,
type: 'pat',
clientId: '',
docsLink: ''
},
{
name: 'Google Cloud Platform',
slug: 'gcp',
image: 'Google Cloud Platform.png',
isAvailable: false,
type: '',
clientId: '',
docsLink: ''
}
]
const getIntegrationOptions = () => {
const INTEGRATION_OPTIONS = [
{
name: 'Heroku',
slug: 'heroku',
image: 'Heroku.png',
isAvailable: true,
type: 'oauth',
clientId: infisical.get('CLIENT_ID_HEROKU')!,
docsLink: ''
},
{
name: 'Vercel',
slug: 'vercel',
image: 'Vercel.png',
isAvailable: true,
type: 'oauth',
clientId: '',
clientSlug: infisical.get('CLIENT_SLUG_VERCEL')!,
docsLink: ''
},
{
name: 'Netlify',
slug: 'netlify',
image: 'Netlify.png',
isAvailable: true,
type: 'oauth',
clientId: infisical.get('CLIENT_ID_NETLIFY')!,
docsLink: ''
},
{
name: 'GitHub',
slug: 'github',
image: 'GitHub.png',
isAvailable: true,
type: 'oauth',
clientId: infisical.get('CLIENT_ID_GITHUB')!,
docsLink: ''
},
{
name: 'Render',
slug: 'render',
image: 'Render.png',
isAvailable: true,
type: 'pat',
clientId: '',
docsLink: ''
},
{
name: 'Fly.io',
slug: 'flyio',
image: 'Flyio.svg',
isAvailable: true,
type: 'pat',
clientId: '',
docsLink: ''
},
{
name: 'AWS Parameter Store',
slug: 'aws-parameter-store',
image: 'Amazon Web Services.png',
isAvailable: true,
type: 'custom',
clientId: '',
docsLink: ''
},
{
name: 'AWS Secret Manager',
slug: 'aws-secret-manager',
image: 'Amazon Web Services.png',
isAvailable: true,
type: 'custom',
clientId: '',
docsLink: ''
},
{
name: 'Azure Key Vault',
slug: 'azure-key-vault',
image: 'Microsoft Azure.png',
isAvailable: true,
type: 'oauth',
clientId: infisical.get('CLIENT_ID_AZURE')!,
docsLink: ''
},
{
name: 'Circle CI',
slug: 'circleci',
image: 'Circle CI.png',
isAvailable: true,
type: 'pat',
clientId: '',
docsLink: ''
},
{
name: 'GitLab',
slug: 'gitlab',
image: 'GitLab.png',
isAvailable: true,
type: 'custom',
clientId: infisical.get('CLIENT_ID_GITLAB'),
docsLink: ''
},
{
name: 'Travis CI',
slug: 'travisci',
image: 'Travis CI.png',
isAvailable: true,
type: 'pat',
clientId: '',
docsLink: ''
},
{
name: 'Google Cloud Platform',
slug: 'gcp',
image: 'Google Cloud Platform.png',
isAvailable: false,
type: '',
clientId: '',
docsLink: ''
}
]
return INTEGRATION_OPTIONS;
}
export {
INTEGRATION_AZURE_KEY_VAULT,
INTEGRATION_AWS_PARAMETER_STORE,
INTEGRATION_AWS_SECRET_MANAGER,
INTEGRATION_HEROKU,
INTEGRATION_VERCEL,
INTEGRATION_NETLIFY,
INTEGRATION_GITHUB,
INTEGRATION_GITLAB,
INTEGRATION_RENDER,
INTEGRATION_FLYIO,
INTEGRATION_CIRCLECI,
INTEGRATION_TRAVISCI,
INTEGRATION_SET,
INTEGRATION_OAUTH2,
INTEGRATION_HEROKU,
INTEGRATION_VERCEL,
INTEGRATION_NETLIFY,
INTEGRATION_GITHUB,
INTEGRATION_GITLAB,
INTEGRATION_RENDER,
INTEGRATION_FLYIO,
INTEGRATION_CIRCLECI,
INTEGRATION_TRAVISCI,
INTEGRATION_SET,
INTEGRATION_OAUTH2,
INTEGRATION_AZURE_TOKEN_URL,
INTEGRATION_HEROKU_TOKEN_URL,
INTEGRATION_VERCEL_TOKEN_URL,
INTEGRATION_NETLIFY_TOKEN_URL,
INTEGRATION_GITHUB_TOKEN_URL,
INTEGRATION_GITLAB_API_URL,
INTEGRATION_HEROKU_API_URL,
INTEGRATION_GITLAB_TOKEN_URL,
INTEGRATION_VERCEL_API_URL,
INTEGRATION_NETLIFY_API_URL,
INTEGRATION_RENDER_API_URL,
INTEGRATION_FLYIO_API_URL,
INTEGRATION_CIRCLECI_API_URL,
INTEGRATION_TRAVISCI_API_URL,
INTEGRATION_OPTIONS,
INTEGRATION_HEROKU_TOKEN_URL,
INTEGRATION_VERCEL_TOKEN_URL,
INTEGRATION_NETLIFY_TOKEN_URL,
INTEGRATION_GITHUB_TOKEN_URL,
INTEGRATION_GITLAB_API_URL,
INTEGRATION_HEROKU_API_URL,
INTEGRATION_GITLAB_TOKEN_URL,
INTEGRATION_VERCEL_API_URL,
INTEGRATION_NETLIFY_API_URL,
INTEGRATION_RENDER_API_URL,
INTEGRATION_FLYIO_API_URL,
INTEGRATION_CIRCLECI_API_URL,
INTEGRATION_TRAVISCI_API_URL,
getIntegrationOptions
};