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

@@ -16,9 +16,6 @@ JWT_AUTH_LIFETIME=
JWT_REFRESH_LIFETIME= JWT_REFRESH_LIFETIME=
JWT_SIGNUP_LIFETIME= JWT_SIGNUP_LIFETIME=
# Optional lifetimes for OTP expressed in seconds
EMAIL_TOKEN_LIFETIME=
# MongoDB # MongoDB
# Backend will connect to the MongoDB instance at connection string MONGO_URL which can either be a ref # Backend will connect to the MongoDB instance at connection string MONGO_URL which can either be a ref
# to the MongoDB container instance or Mongo Cloud # to the MongoDB container instance or Mongo Cloud

View File

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

View File

@@ -32,6 +32,7 @@
"express-validator": "^6.14.2", "express-validator": "^6.14.2",
"handlebars": "^4.7.7", "handlebars": "^4.7.7",
"helmet": "^5.1.1", "helmet": "^5.1.1",
"infisical-node": "^1.0.34",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"jsrp": "^0.2.4", "jsrp": "^0.2.4",
@@ -5973,6 +5974,16 @@
"node": ">=0.8.19" "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": { "node_modules/inflight": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -16758,6 +16769,16 @@
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true "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": { "inflight": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",

View File

@@ -23,6 +23,7 @@
"express-validator": "^6.14.2", "express-validator": "^6.14.2",
"handlebars": "^4.7.7", "handlebars": "^4.7.7",
"helmet": "^5.1.1", "helmet": "^5.1.1",
"infisical-node": "^1.0.34",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"jsrp": "^0.2.4", "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 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 INVITE_ONLY_SIGNUP = process.env.INVITE_ONLY_SIGNUP == undefined ? false : process.env.INVITE_ONLY_SIGNUP // const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY!;
const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY!; // const SALT_ROUNDS = parseInt(process.env.SALT_ROUNDS!) || 10;
const SALT_ROUNDS = parseInt(process.env.SALT_ROUNDS!) || 10; // const JWT_AUTH_LIFETIME = process.env.JWT_AUTH_LIFETIME! || '10d';
const JWT_AUTH_LIFETIME = process.env.JWT_AUTH_LIFETIME! || '10d'; // const JWT_AUTH_SECRET = process.env.JWT_AUTH_SECRET!;
const JWT_AUTH_SECRET = process.env.JWT_AUTH_SECRET!; // const JWT_MFA_LIFETIME = process.env.JWT_MFA_LIFETIME! || '5m';
const JWT_MFA_LIFETIME = process.env.JWT_MFA_LIFETIME! || '5m'; // const JWT_MFA_SECRET = process.env.JWT_MFA_SECRET!;
const JWT_MFA_SECRET = process.env.JWT_MFA_SECRET!; // const JWT_REFRESH_LIFETIME = process.env.JWT_REFRESH_LIFETIME! || '90d';
const JWT_REFRESH_LIFETIME = process.env.JWT_REFRESH_LIFETIME! || '90d'; // const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET!;
const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET!; // const JWT_SERVICE_SECRET = process.env.JWT_SERVICE_SECRET!;
const JWT_SERVICE_SECRET = process.env.JWT_SERVICE_SECRET!; // const JWT_SIGNUP_LIFETIME = process.env.JWT_SIGNUP_LIFETIME! || '15m';
const JWT_SIGNUP_LIFETIME = process.env.JWT_SIGNUP_LIFETIME! || '15m'; // const JWT_SIGNUP_SECRET = process.env.JWT_SIGNUP_SECRET!;
const JWT_SIGNUP_SECRET = process.env.JWT_SIGNUP_SECRET!; // const MONGO_URL = process.env.MONGO_URL!;
const MONGO_URL = process.env.MONGO_URL!; // const NODE_ENV = process.env.NODE_ENV! || 'production';
const NODE_ENV = process.env.NODE_ENV! || 'production'; // const VERBOSE_ERROR_OUTPUT = process.env.VERBOSE_ERROR_OUTPUT! === 'true' && true;
const VERBOSE_ERROR_OUTPUT = process.env.VERBOSE_ERROR_OUTPUT! === 'true' && true; // const LOKI_HOST = process.env.LOKI_HOST || undefined;
const LOKI_HOST = process.env.LOKI_HOST || undefined; // const CLIENT_ID_AZURE = process.env.CLIENT_ID_AZURE!;
const CLIENT_ID_AZURE = process.env.CLIENT_ID_AZURE!; // const CLIENT_ID_HEROKU = process.env.CLIENT_ID_HEROKU!;
const CLIENT_ID_HEROKU = process.env.CLIENT_ID_HEROKU!; // const CLIENT_ID_VERCEL = process.env.CLIENT_ID_VERCEL!;
const CLIENT_ID_VERCEL = process.env.CLIENT_ID_VERCEL!; // const CLIENT_ID_NETLIFY = process.env.CLIENT_ID_NETLIFY!;
const CLIENT_ID_NETLIFY = process.env.CLIENT_ID_NETLIFY!; // const CLIENT_ID_GITHUB = process.env.CLIENT_ID_GITHUB!;
const CLIENT_ID_GITHUB = process.env.CLIENT_ID_GITHUB!; // const CLIENT_ID_GITLAB = process.env.CLIENT_ID_GITLAB!;
const CLIENT_ID_GITLAB = process.env.CLIENT_ID_GITLAB!; // const CLIENT_SECRET_AZURE = process.env.CLIENT_SECRET_AZURE!;
const CLIENT_SECRET_AZURE = process.env.CLIENT_SECRET_AZURE!; // const CLIENT_SECRET_HEROKU = process.env.CLIENT_SECRET_HEROKU!;
const CLIENT_SECRET_HEROKU = process.env.CLIENT_SECRET_HEROKU!; // const CLIENT_SECRET_VERCEL = process.env.CLIENT_SECRET_VERCEL!;
const CLIENT_SECRET_VERCEL = process.env.CLIENT_SECRET_VERCEL!; // const CLIENT_SECRET_NETLIFY = process.env.CLIENT_SECRET_NETLIFY!;
const CLIENT_SECRET_NETLIFY = process.env.CLIENT_SECRET_NETLIFY!; // const CLIENT_SECRET_GITHUB = process.env.CLIENT_SECRET_GITHUB!;
const CLIENT_SECRET_GITHUB = process.env.CLIENT_SECRET_GITHUB!; // const CLIENT_SECRET_GITLAB = process.env.CLIENT_SECRET_GITLAB;
const CLIENT_SECRET_GITLAB = process.env.CLIENT_SECRET_GITLAB; // const CLIENT_SLUG_VERCEL = process.env.CLIENT_SLUG_VERCEL!;
const CLIENT_SLUG_VERCEL = process.env.CLIENT_SLUG_VERCEL!; // const POSTHOG_HOST = process.env.POSTHOG_HOST! || 'https://app.posthog.com';
const POSTHOG_HOST = process.env.POSTHOG_HOST! || 'https://app.posthog.com'; // const POSTHOG_PROJECT_API_KEY =
const POSTHOG_PROJECT_API_KEY = // process.env.POSTHOG_PROJECT_API_KEY! ||
process.env.POSTHOG_PROJECT_API_KEY! || // 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE';
'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE'; // const SENTRY_DSN = process.env.SENTRY_DSN!;
const SENTRY_DSN = process.env.SENTRY_DSN!; // const SITE_URL = process.env.SITE_URL!;
const SITE_URL = process.env.SITE_URL!; // const SMTP_HOST = process.env.SMTP_HOST!;
const SMTP_HOST = process.env.SMTP_HOST!; // const SMTP_SECURE = process.env.SMTP_SECURE! === 'true' || false;
const SMTP_SECURE = process.env.SMTP_SECURE! === 'true' || false; // const SMTP_PORT = parseInt(process.env.SMTP_PORT!) || 587;
const SMTP_PORT = parseInt(process.env.SMTP_PORT!) || 587; // const SMTP_USERNAME = process.env.SMTP_USERNAME!;
const SMTP_USERNAME = process.env.SMTP_USERNAME!; // const SMTP_PASSWORD = process.env.SMTP_PASSWORD!;
const SMTP_PASSWORD = process.env.SMTP_PASSWORD!; // const SMTP_FROM_ADDRESS = process.env.SMTP_FROM_ADDRESS!;
const SMTP_FROM_ADDRESS = process.env.SMTP_FROM_ADDRESS!; // const SMTP_FROM_NAME = process.env.SMTP_FROM_NAME! || 'Infisical';
const SMTP_FROM_NAME = process.env.SMTP_FROM_NAME! || 'Infisical'; // const STRIPE_PRODUCT_STARTER = process.env.STRIPE_PRODUCT_STARTER!;
const STRIPE_PRODUCT_STARTER = process.env.STRIPE_PRODUCT_STARTER!; // const STRIPE_PRODUCT_PRO = process.env.STRIPE_PRODUCT_PRO!;
const STRIPE_PRODUCT_PRO = process.env.STRIPE_PRODUCT_PRO!; // const STRIPE_PRODUCT_TEAM = process.env.STRIPE_PRODUCT_TEAM!;
const STRIPE_PRODUCT_TEAM = process.env.STRIPE_PRODUCT_TEAM!; // const STRIPE_PUBLISHABLE_KEY = process.env.STRIPE_PUBLISHABLE_KEY!;
const STRIPE_PUBLISHABLE_KEY = process.env.STRIPE_PUBLISHABLE_KEY!; // const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY!;
const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY!; // const STRIPE_WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET!;
const STRIPE_WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET!; // const TELEMETRY_ENABLED = process.env.TELEMETRY_ENABLED! !== 'false' && true;
const TELEMETRY_ENABLED = process.env.TELEMETRY_ENABLED! !== 'false' && true;
const LICENSE_KEY = process.env.LICENSE_KEY!;
export { export {
PORT, // PORT,
EMAIL_TOKEN_LIFETIME, // INVITE_ONLY_SIGNUP,
INVITE_ONLY_SIGNUP, // ENCRYPTION_KEY,
ENCRYPTION_KEY, // SALT_ROUNDS,
SALT_ROUNDS, // JWT_AUTH_LIFETIME,
JWT_AUTH_LIFETIME, // JWT_AUTH_SECRET,
JWT_AUTH_SECRET, // JWT_MFA_LIFETIME,
JWT_MFA_LIFETIME, // JWT_MFA_SECRET,
JWT_MFA_SECRET, // JWT_REFRESH_LIFETIME,
JWT_REFRESH_LIFETIME, // JWT_REFRESH_SECRET,
JWT_REFRESH_SECRET, // JWT_SERVICE_SECRET,
JWT_SERVICE_SECRET, // JWT_SIGNUP_LIFETIME,
JWT_SIGNUP_LIFETIME, // JWT_SIGNUP_SECRET,
JWT_SIGNUP_SECRET, // MONGO_URL,
MONGO_URL, // NODE_ENV,
NODE_ENV, // VERBOSE_ERROR_OUTPUT,
VERBOSE_ERROR_OUTPUT, // LOKI_HOST,
LOKI_HOST, // CLIENT_ID_AZURE,
CLIENT_ID_AZURE, // CLIENT_ID_HEROKU,
CLIENT_ID_HEROKU, // CLIENT_ID_VERCEL,
CLIENT_ID_VERCEL, // CLIENT_ID_NETLIFY,
CLIENT_ID_NETLIFY, // CLIENT_ID_GITHUB,
CLIENT_ID_GITHUB, // CLIENT_ID_GITLAB,
CLIENT_ID_GITLAB, // CLIENT_SECRET_AZURE,
CLIENT_SECRET_AZURE, // CLIENT_SECRET_HEROKU,
CLIENT_SECRET_HEROKU, // CLIENT_SECRET_VERCEL,
CLIENT_SECRET_VERCEL, // CLIENT_SECRET_NETLIFY,
CLIENT_SECRET_NETLIFY, // CLIENT_SECRET_GITHUB,
CLIENT_SECRET_GITHUB, // CLIENT_SECRET_GITLAB,
CLIENT_SECRET_GITLAB, // CLIENT_SLUG_VERCEL,
CLIENT_SLUG_VERCEL, // POSTHOG_HOST,
POSTHOG_HOST, // POSTHOG_PROJECT_API_KEY,
POSTHOG_PROJECT_API_KEY, // SENTRY_DSN,
SENTRY_DSN, // SITE_URL,
SITE_URL, // SMTP_HOST,
SMTP_HOST, // SMTP_PORT,
SMTP_PORT, // SMTP_SECURE,
SMTP_SECURE, // SMTP_USERNAME,
SMTP_USERNAME, // SMTP_PASSWORD,
SMTP_PASSWORD, // SMTP_FROM_ADDRESS,
SMTP_FROM_ADDRESS, // SMTP_FROM_NAME,
SMTP_FROM_NAME, // STRIPE_PRODUCT_STARTER,
STRIPE_PRODUCT_STARTER, // STRIPE_PRODUCT_TEAM,
STRIPE_PRODUCT_TEAM, // STRIPE_PRODUCT_PRO,
STRIPE_PRODUCT_PRO, // STRIPE_PUBLISHABLE_KEY,
STRIPE_PUBLISHABLE_KEY, // STRIPE_SECRET_KEY,
STRIPE_SECRET_KEY, // STRIPE_WEBHOOK_SECRET,
STRIPE_WEBHOOK_SECRET, // TELEMETRY_ENABLED,
TELEMETRY_ENABLED,
LICENSE_KEY
}; };

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

View File

@@ -5,7 +5,7 @@ import {
IntegrationAuth, IntegrationAuth,
Bot Bot
} from '../../models'; } from '../../models';
import { INTEGRATION_SET, INTEGRATION_OPTIONS } from '../../variables'; import { INTEGRATION_SET, getIntegrationOptions as getIntegrationOptionsFunc } from '../../variables';
import { IntegrationService } from '../../services'; import { IntegrationService } from '../../services';
import { import {
getApps, getApps,
@@ -39,9 +39,11 @@ export const getIntegrationAuth = async (req: Request, res: Response) => {
} }
export const getIntegrationOptions = async (req: Request, res: Response) => { export const getIntegrationOptions = async (req: Request, res: Response) => {
return res.status(200).send({ const INTEGRATION_OPTIONS = getIntegrationOptionsFunc();
integrationOptions: INTEGRATION_OPTIONS,
}); 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 * 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 { import {
findMembership, findMembership,
deleteMembership as deleteMember deleteMembership as deleteMember
} from '../../helpers/membership'; } from '../../helpers/membership';
import { sendMail } from '../../helpers/nodemailer'; import { sendMail } from '../../helpers/nodemailer';
import { SITE_URL } from '../../config';
import { ADMIN, MEMBER, ACCEPTED } from '../../variables'; import { ADMIN, MEMBER, ACCEPTED } from '../../variables';
/** /**
@@ -215,7 +215,7 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => {
inviterFirstName: req.user.firstName, inviterFirstName: req.user.firstName,
inviterEmail: req.user.email, inviterEmail: req.user.email,
workspaceName: req.membership.workspace.name, workspaceName: req.membership.workspace.name,
callback_url: SITE_URL + '/login' callback_url: infisical.get('SITE_URL')! + '/login'
} }
}); });
} catch (err) { } catch (err) {

View File

@@ -1,6 +1,6 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import { SITE_URL, JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET } from '../../config';
import { MembershipOrg, Organization, User } from '../../models'; import { MembershipOrg, Organization, User } from '../../models';
import { deleteMembershipOrg as deleteMemberFromOrg } from '../../helpers/membershipOrg'; import { deleteMembershipOrg as deleteMemberFromOrg } from '../../helpers/membershipOrg';
import { createToken } from '../../helpers/auth'; import { createToken } from '../../helpers/auth';
@@ -178,7 +178,7 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
organizationName: organization.name, organizationName: organization.name,
email: inviteeEmail, email: inviteeEmail,
token, token,
callback_url: SITE_URL + '/signupinvite' callback_url: infisical.get('SITE_URL') + '/signupinvite'
} }
}); });
} }
@@ -250,8 +250,8 @@ export const verifyUserToOrganization = async (req: Request, res: Response) => {
payload: { payload: {
userId: user._id.toString() userId: user._id.toString()
}, },
expiresIn: JWT_SIGNUP_LIFETIME, expiresIn: infisical.get('JWT_SIGNUP_LIFETIME')!,
secret: JWT_SIGNUP_SECRET secret: infisical.get('JWT_SIGNUP_SECRET')!
}); });
} catch (err) { } catch (err) {
Sentry.setUser(null); 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 * as Sentry from '@sentry/node';
import { import { Request, Response } from 'express';
SITE_URL,
STRIPE_SECRET_KEY
} from '../../config';
import Stripe from 'stripe'; import Stripe from 'stripe';
const stripe = new Stripe(STRIPE_SECRET_KEY, {
apiVersion: '2022-08-01'
});
import { import {
Membership, Membership,
MembershipOrg, MembershipOrg,
Organization, Organization,
Workspace, Workspace,
IncidentContactOrg, IncidentContactOrg
IMembershipOrg
} from '../../models'; } from '../../models';
import { createOrganization as create } from '../../helpers/organization'; import { createOrganization as create } from '../../helpers/organization';
import { addMembershipsOrg } from '../../helpers/membershipOrg'; import { addMembershipsOrg } from '../../helpers/membershipOrg';
@@ -325,6 +317,10 @@ export const createOrganizationPortalSession = async (
) => { ) => {
let session; let session;
try { try {
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, {
apiVersion: '2022-08-01'
});
// check if there is a payment method on file // check if there is a payment method on file
const paymentMethods = await stripe.paymentMethods.list({ const paymentMethods = await stripe.paymentMethods.list({
customer: req.membershipOrg.organization.customerId, customer: req.membershipOrg.organization.customerId,
@@ -337,13 +333,13 @@ export const createOrganizationPortalSession = async (
customer: req.membershipOrg.organization.customerId, customer: req.membershipOrg.organization.customerId,
mode: 'setup', mode: 'setup',
payment_method_types: ['card'], payment_method_types: ['card'],
success_url: SITE_URL + '/dashboard', success_url: infisical.get('SITE_URL')! + '/dashboard',
cancel_url: SITE_URL + '/dashboard' cancel_url: infisical.get('SITE_URL')! + '/dashboard'
}); });
} else { } else {
session = await stripe.billingPortal.sessions.create({ session = await stripe.billingPortal.sessions.create({
customer: req.membershipOrg.organization.customerId, customer: req.membershipOrg.organization.customerId,
return_url: SITE_URL + '/dashboard' return_url: infisical.get('SITE_URL') + '/dashboard'
}); });
} }
@@ -369,6 +365,10 @@ export const getOrganizationSubscriptions = async (
) => { ) => {
let subscriptions; let subscriptions;
try { try {
const stripe = new Stripe(infisical.get('STRIPE_SECRET_KEY')!, {
apiVersion: '2022-08-01'
});
subscriptions = await stripe.subscriptions.list({ subscriptions = await stripe.subscriptions.list({
customer: req.membershipOrg.organization.customerId customer: req.membershipOrg.organization.customerId
}); });

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import { User } from '../../models'; import { User } from '../../models';
import { JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET, INVITE_ONLY_SIGNUP } from '../../config';
import { import {
sendEmailVerification, sendEmailVerification,
checkEmailVerification, checkEmailVerification,
@@ -21,7 +21,7 @@ export const beginEmailSignup = async (req: Request, res: Response) => {
try { try {
email = req.body.email; 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 // Only one user can create an account without being invited. The rest need to be invited in order to make an account
const userCount = await User.countDocuments({}) const userCount = await User.countDocuments({})
if (userCount != 0) { if (userCount != 0) {
@@ -91,8 +91,8 @@ export const verifyEmailSignup = async (req: Request, res: Response) => {
payload: { payload: {
userId: user._id.toString() userId: user._id.toString()
}, },
expiresIn: JWT_SIGNUP_LIFETIME, expiresIn: infisical.get('JWT_SIGNUP_LIFETIME')!,
secret: JWT_SIGNUP_SECRET secret: infisical.get('JWT_SIGNUP_SECRET')!
}); });
} catch (err) { } catch (err) {
Sentry.setUser(null); Sentry.setUser(null);

View File

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

View File

@@ -1,13 +1,11 @@
import { Request, Response } from 'express';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import infisical from 'infisical-node';
import { Request, Response } from 'express';
import crypto from 'crypto'; import crypto from 'crypto';
import bcrypt from 'bcrypt'; import bcrypt from 'bcrypt';
import { import {
APIKeyData APIKeyData
} from '../../models'; } from '../../models';
import {
SALT_ROUNDS
} from '../../config';
/** /**
* Return API key data for user with id [req.user_id] * 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 { name, expiresIn } = req.body;
const secret = crypto.randomBytes(16).toString('hex'); 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(); const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn); expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);

View File

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

View File

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

View File

@@ -15,7 +15,7 @@ import { UnauthorizedRequestError, ValidationError } from '../../utils/errors';
import { EventService } from '../../services'; import { EventService } from '../../services';
import { eventPushSecrets } from '../../events'; import { eventPushSecrets } from '../../events';
import { EESecretService, EELogService } from '../../ee/services'; import { EESecretService, EELogService } from '../../ee/services';
import { postHogClient } from '../../services'; import { getPostHogClient } from '../../services';
import { getChannelFromUserAgent } from '../../utils/posthog'; import { getChannelFromUserAgent } from '../../utils/posthog';
import { ABILITY_READ, ABILITY_WRITE } from '../../variables/organization'; import { ABILITY_READ, ABILITY_WRITE } from '../../variables/organization';
import { userHasNoAbility, userHasWorkspaceAccess, userHasWriteOnlyAbility } from '../../ee/helpers/checkMembershipPermissions'; import { userHasNoAbility, userHasWorkspaceAccess, userHasWriteOnlyAbility } from '../../ee/helpers/checkMembershipPermissions';
@@ -33,6 +33,8 @@ import {
*/ */
export const batchSecrets = async (req: Request, res: Response) => { export const batchSecrets = async (req: Request, res: Response) => {
const channel = getChannelFromUserAgent(req.headers['user-agent']); const channel = getChannelFromUserAgent(req.headers['user-agent']);
const postHogClient = getPostHogClient();
const { const {
workspaceId, workspaceId,
environment, environment,
@@ -326,6 +328,7 @@ export const createSecrets = async (req: Request, res: Response) => {
} }
} }
*/ */
const postHogClient = getPostHogClient();
const channel = getChannelFromUserAgent(req.headers['user-agent']) const channel = getChannelFromUserAgent(req.headers['user-agent'])
const { workspaceId, environment }: { workspaceId: string, environment: string } = req.body; 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 { workspaceId, environment, tagSlugs } = req.query;
const tagNamesList = typeof tagSlugs === 'string' && tagSlugs !== '' ? tagSlugs.split(',') : []; 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'; const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
// TODO: move type // 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 channel = getChannelFromUserAgent(req.headers['user-agent'])
const toDelete = req.secrets.map((s: any) => s._id); 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 * as Sentry from '@sentry/node';
import infisical from 'infisical-node';
import { Request, Response } from 'express';
import crypto from 'crypto'; import crypto from 'crypto';
import bcrypt from 'bcrypt'; import bcrypt from 'bcrypt';
import { import {
ServiceTokenData ServiceTokenData
} from '../../models'; } from '../../models';
import {
SALT_ROUNDS
} from '../../config';
import { userHasWorkspaceAccess } from '../../ee/helpers/checkMembershipPermissions'; import { userHasWorkspaceAccess } from '../../ee/helpers/checkMembershipPermissions';
import { ABILITY_READ } from '../../variables/organization'; 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 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(); const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn); expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,28 +1,168 @@
import dotenv from 'dotenv'; import dotenv from 'dotenv';
dotenv.config(); 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 * as Sentry from '@sentry/node';
import { SENTRY_DSN, NODE_ENV, MONGO_URL } from './config';
import { server } from './app';
import { DatabaseService } from './services'; import { DatabaseService } from './services';
import { setUpHealthEndpoint } from './services/health'; import { setUpHealthEndpoint } from './services/health';
import { initSmtp } from './services/smtp'; import { initSmtp } from './services/smtp';
import { logTelemetryMessage } from './services';
import { setTransporter } from './helpers/nodemailer'; import { setTransporter } from './helpers/nodemailer';
import { createTestUserForDevelopment } from './utils/addDevelopmentUser'; 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') { patchRouterParam();
Sentry.init({ const app = express();
dsn: SENTRY_DSN, app.enable('trust proxy');
tracesSampleRate: 1.0, app.use(express.json());
debug: NODE_ENV === 'production' ? false : true, app.use(cookieParser());
environment: NODE_ENV 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 * as Sentry from '@sentry/node';
import request from '../config/request';
import { import {
INTEGRATION_AZURE_KEY_VAULT, INTEGRATION_AZURE_KEY_VAULT,
INTEGRATION_HEROKU, INTEGRATION_HEROKU,
@@ -14,20 +15,6 @@ import {
INTEGRATION_GITHUB_TOKEN_URL, INTEGRATION_GITHUB_TOKEN_URL,
INTEGRATION_GITLAB_TOKEN_URL INTEGRATION_GITLAB_TOKEN_URL
} from '../variables'; } 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 { interface ExchangeCodeAzureResponse {
token_type: string; token_type: string;
@@ -159,9 +146,9 @@ const exchangeCodeAzure = async ({
grant_type: 'authorization_code', grant_type: 'authorization_code',
code: code, code: code,
scope: 'https://vault.azure.net/.default openid offline_access', scope: 'https://vault.azure.net/.default openid offline_access',
client_id: CLIENT_ID_AZURE, client_id: infisical.get('CLIENT_ID_AZURE')!,
client_secret: CLIENT_SECRET_AZURE, client_secret: infisical.get('CLIENT_SECRET_AZURE')!,
redirect_uri: `${SITE_URL}/integrations/azure-key-vault/oauth2/callback` redirect_uri: `${infisical.get('SITE_URL')!}/integrations/azure-key-vault/oauth2/callback`
} as any) } as any)
)).data; )).data;
@@ -204,7 +191,7 @@ const exchangeCodeHeroku = async ({
new URLSearchParams({ new URLSearchParams({
grant_type: 'authorization_code', grant_type: 'authorization_code',
code: code, code: code,
client_secret: CLIENT_SECRET_HEROKU client_secret: infisical.get('CLIENT_SECRET_HEROKU')!
} as any) } as any)
)).data; )).data;
@@ -242,9 +229,9 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => {
INTEGRATION_VERCEL_TOKEN_URL, INTEGRATION_VERCEL_TOKEN_URL,
new URLSearchParams({ new URLSearchParams({
code: code, code: code,
client_id: CLIENT_ID_VERCEL, client_id: infisical.get('CLIENT_ID_VERCEL')!,
client_secret: CLIENT_SECRET_VERCEL, client_secret: infisical.get('CLIENT_SECRET_VERCEL')!,
redirect_uri: `${SITE_URL}/integrations/vercel/oauth2/callback` redirect_uri: `${infisical.get('SITE_URL')!}/integrations/vercel/oauth2/callback`
} as any) } as any)
) )
).data; ).data;
@@ -282,9 +269,9 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => {
new URLSearchParams({ new URLSearchParams({
grant_type: 'authorization_code', grant_type: 'authorization_code',
code: code, code: code,
client_id: CLIENT_ID_NETLIFY, client_id: infisical.get('CLIENT_ID_NETLIFY')!,
client_secret: CLIENT_SECRET_NETLIFY, client_secret: infisical.get('CLIENT_SECRET_NETLIFY')!,
redirect_uri: `${SITE_URL}/integrations/netlify/oauth2/callback` redirect_uri: `${infisical.get('SITE_URL')!}/integrations/netlify/oauth2/callback`
} as any) } as any)
) )
).data; ).data;
@@ -333,10 +320,10 @@ const exchangeCodeGithub = async ({ code }: { code: string }) => {
res = ( res = (
await request.get(INTEGRATION_GITHUB_TOKEN_URL, { await request.get(INTEGRATION_GITHUB_TOKEN_URL, {
params: { params: {
client_id: CLIENT_ID_GITHUB, client_id: infisical.get('CLIENT_ID_GITHUB')!,
client_secret: CLIENT_SECRET_GITHUB, client_secret: infisical.get('CLIENT_SECRET_GITHUB')!,
code: code, code: code,
redirect_uri: `${SITE_URL}/integrations/github/oauth2/callback` redirect_uri: `${infisical.get('SITE_URL')!}/integrations/github/oauth2/callback`
}, },
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
@@ -379,9 +366,9 @@ const exchangeCodeGitlab = async ({ code }: { code: string }) => {
new URLSearchParams({ new URLSearchParams({
grant_type: 'authorization_code', grant_type: 'authorization_code',
code: code, code: code,
client_id: CLIENT_ID_GITLAB, client_id: infisical.get('CLIENT_ID_GITLAB')!,
client_secret: CLIENT_SECRET_GITLAB, client_secret: infisical.get('CLIENT_SECRET_GITLAB')!,
redirect_uri: `${SITE_URL}/integrations/gitlab/oauth2/callback` redirect_uri: `${infisical.get('SITE_URL')}/integrations/gitlab/oauth2/callback`
} as any), } as any),
{ {
headers: { headers: {

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express'; import { Request, Response, NextFunction } from 'express';
import { User } from '../models'; import { User } from '../models';
import { JWT_MFA_SECRET } from '../config';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors'; import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
declare module 'jsonwebtoken' { 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'})) if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
const decodedToken = <jwt.UserIDJwtPayload>( const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(AUTH_TOKEN_VALUE, JWT_MFA_SECRET) jwt.verify(AUTH_TOKEN_VALUE, infisical.get('JWT_MFA_SECRET')!)
); );
const user = await User.findOne({ const user = await User.findOne({

View File

@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express'; import { Request, Response, NextFunction } from 'express';
import { ServiceToken } from '../models'; import { ServiceToken } from '../models';
import { JWT_SERVICE_SECRET } from '../config';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors'; import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
// TODO: deprecate // 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'})) if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
const decodedToken = <jwt.UserIDJwtPayload>( const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(AUTH_TOKEN_VALUE, JWT_SERVICE_SECRET) jwt.verify(AUTH_TOKEN_VALUE, infisical.get('JWT_SERVICE_SECRET')!)
); );
const serviceToken = await ServiceToken.findOne({ const serviceToken = await ServiceToken.findOne({

View File

@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express'; import { Request, Response, NextFunction } from 'express';
import { User } from '../models'; import { User } from '../models';
import { JWT_SIGNUP_SECRET } from '../config';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors'; import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
declare module 'jsonwebtoken' { 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'})) if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
const decodedToken = <jwt.UserIDJwtPayload>( const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(AUTH_TOKEN_VALUE, JWT_SIGNUP_SECRET) jwt.verify(AUTH_TOKEN_VALUE, infisical.get('JWT_SIGNUP_SECRET')!)
); );
const user = await User.findOne({ const user = await User.findOne({

View File

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

View File

@@ -1,27 +1,41 @@
import infisical from 'infisical-node';
import { PostHog } from 'posthog-node'; import { PostHog } from 'posthog-node';
import {
NODE_ENV,
POSTHOG_HOST,
POSTHOG_PROJECT_API_KEY,
TELEMETRY_ENABLED
} from '../config';
import { getLogger } from '../utils/logger'; import { getLogger } from '../utils/logger';
if(!TELEMETRY_ENABLED){ /**
getLogger("backend-main").info([ * Logs telemetry enable/disable notice.
"", */
"To improve, Infisical collects telemetry data about general usage.", const logTelemetryMessage = () => {
"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.", const TELEMETRY_ENABLED = infisical.get('TELEMETRY_ENABLED')! !== 'false' && true;
"To opt into telemetry, you can set `TELEMETRY_ENABLED=true` within the environment variables.", if(!TELEMETRY_ENABLED){
].join('\n')) 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) { * Return an instance of the PostHog client initialized.
// case: enable opt-out telemetry in production * @returns
postHogClient = new PostHog(POSTHOG_PROJECT_API_KEY, { */
host: POSTHOG_HOST 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 DatabaseService from './DatabaseService';
import postHogClient from './PostHogClient'; import { logTelemetryMessage, getPostHogClient } from './PostHogClient';
import BotService from './BotService'; import BotService from './BotService';
import EventService from './EventService'; import EventService from './EventService';
import IntegrationService from './IntegrationService'; import IntegrationService from './IntegrationService';
import TokenService from './TokenService'; import TokenService from './TokenService';
export { export {
logTelemetryMessage,
getPostHogClient,
DatabaseService, DatabaseService,
postHogClient,
BotService, BotService,
EventService, EventService,
IntegrationService, IntegrationService,

View File

@@ -1,11 +1,5 @@
import infisical from 'infisical-node';
import nodemailer from 'nodemailer'; import nodemailer from 'nodemailer';
import {
SMTP_HOST,
SMTP_PORT,
SMTP_USERNAME,
SMTP_PASSWORD,
SMTP_SECURE
} from '../config';
import { import {
SMTP_HOST_SENDGRID, SMTP_HOST_SENDGRID,
SMTP_HOST_MAILGUN, SMTP_HOST_MAILGUN,
@@ -15,54 +9,54 @@ import {
import SMTPConnection from 'nodemailer/lib/smtp-connection'; import SMTPConnection from 'nodemailer/lib/smtp-connection';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
const mailOpts: SMTPConnection.Options = { export const initSmtp = () => {
host: SMTP_HOST, const mailOpts: SMTPConnection.Options = {
port: SMTP_PORT as number host: infisical.get('SMTP_HOST')!,
}; port: parseInt(infisical.get('SMTP_PORT')!)
if (SMTP_USERNAME && SMTP_PASSWORD) {
mailOpts.auth = {
user: SMTP_USERNAME,
pass: SMTP_PASSWORD
}; };
}
if (SMTP_SECURE) { if (infisical.get('SMTP_USERNAME')! && infisical.get('SMTP_PASSWORD')!) {
switch (SMTP_HOST) { mailOpts.auth = {
case SMTP_HOST_SENDGRID: user: infisical.get('SMTP_USERNAME')!,
mailOpts.requireTLS = true; pass: infisical.get('SMTP_PASSWORD')!
break; };
case SMTP_HOST_MAILGUN: }
mailOpts.requireTLS = true;
mailOpts.tls = { if (infisical.get('SMTP_SECURE')! ? infisical.get('SMTP_SECURE')! === 'true' : false) {
ciphers: 'TLSv1.2' switch (infisical.get('SMTP_HOST')!) {
} case SMTP_HOST_SENDGRID:
break; mailOpts.requireTLS = true;
case SMTP_HOST_SOCKETLABS: break;
mailOpts.requireTLS = true; case SMTP_HOST_MAILGUN:
mailOpts.tls = { mailOpts.requireTLS = true;
ciphers: 'TLSv1.2'
}
break;
case SMTP_HOST_ZOHOMAIL:
mailOpts.requireTLS = true;
mailOpts.tls = {
ciphers: 'TLSv1.2'
}
break;
default:
if (SMTP_HOST.includes('amazonaws.com')) {
mailOpts.tls = { mailOpts.tls = {
ciphers: 'TLSv1.2' ciphers: 'TLSv1.2'
} }
} else { break;
mailOpts.secure = true; case SMTP_HOST_SOCKETLABS:
} mailOpts.requireTLS = true;
break; 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); const transporter = nodemailer.createTransport(mailOpts);
transporter transporter
.verify() .verify()
@@ -73,7 +67,7 @@ export const initSmtp = () => {
.catch((err) => { .catch((err) => {
Sentry.setUser(null); Sentry.setUser(null);
Sentry.captureException( 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 { Key, Membership, MembershipOrg, Organization, User, Workspace } from "../models";
import { Types } from 'mongoose'; import { Types } from 'mongoose';
export const createTestUserForDevelopment = async () => { export const createTestUserForDevelopment = async () => {
if (NODE_ENV === "development") { if (infisical.get('NODE_ENV') === "development") {
const testUserEmail = "test@localhost.local" const testUserEmail = "test@localhost.local"
const testUserPassword = "testInfisical1" const testUserPassword = "testInfisical1"
const testUserId = "63cefa6ec8d3175601cfa980" const testUserId = "63cefa6ec8d3175601cfa980"

View File

@@ -1,7 +1,7 @@
import infisical from 'infisical-node';
/* eslint-disable no-console */ /* eslint-disable no-console */
import { createLogger, format, transports } from 'winston'; import { createLogger, format, transports } from 'winston';
import LokiTransport from 'winston-loki'; import LokiTransport from 'winston-loki';
import { LOKI_HOST, NODE_ENV } from '../config';
const { combine, colorize, label, printf, splat, timestamp } = format; const { combine, colorize, label, printf, splat, timestamp } = format;
@@ -25,10 +25,10 @@ const createLoggerWithLabel = (level: string, label: string) => {
}) })
] ]
//* Add LokiTransport if it's enabled //* Add LokiTransport if it's enabled
if(LOKI_HOST !== undefined){ if(infisical.get('LOKI_HOST')! !== undefined){
_transports.push( _transports.push(
new LokiTransport({ new LokiTransport({
host: LOKI_HOST, host: infisical.get('LOKI_HOST')!,
handleExceptions: true, handleExceptions: true,
handleRejections: true, handleRejections: true,
batching: true, batching: true,
@@ -37,7 +37,11 @@ const createLoggerWithLabel = (level: string, label: string) => {
format: format.combine( format: format.combine(
format.json() 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) 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 { Request } from 'express'
import { VERBOSE_ERROR_OUTPUT } from '../config'
export enum LogLevel { export enum LogLevel {
DEBUG = 100, DEBUG = 100,
@@ -87,6 +87,7 @@ export default class RequestError extends Error{
}, this.context) }, this.context)
//* Omit sensitive information from context that can leak internal workings of this program if user is not developer //* Omit sensitive information from context that can leak internal workings of this program if user is not developer
const VERBOSE_ERROR_OUTPUT = infisical.get('VERBOSE_ERROR_OUTPUT')! === 'true' && true;
if(!VERBOSE_ERROR_OUTPUT){ if(!VERBOSE_ERROR_OUTPUT){
_context = this._omit(_context, [ _context = this._omit(_context, [
'stacktrace', 'stacktrace',

View File

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

View File

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

View File

@@ -17,7 +17,6 @@ Configuring Infisical requires setting some environment variables. There is a fi
| `JWT_REFRESH_LIFETIME` | JWT token lifetime expressed in seconds or a string describing a time span (e.g. 60, "2 days", "10h", "7d") | `90d` | | `JWT_REFRESH_LIFETIME` | JWT token lifetime expressed in seconds or a string describing a time span (e.g. 60, "2 days", "10h", "7d") | `90d` |
| `JWT_AUTH_LIFETIME` | JWT token lifetime expressed in seconds or a string describing a time span (e.g. 60, "2 days", "10h", "7d") | `10d` | | `JWT_AUTH_LIFETIME` | JWT token lifetime expressed in seconds or a string describing a time span (e.g. 60, "2 days", "10h", "7d") | `10d` |
| `JWT_MFA_LIFETIME` | JWT token lifetime expressed in seconds or a string describing a time span (e.g. 60, "2 days", "10h", "7d") | `5m` | | `JWT_MFA_LIFETIME` | JWT token lifetime expressed in seconds or a string describing a time span (e.g. 60, "2 days", "10h", "7d") | `5m` |
| `EMAIL_TOKEN_LIFETIME` | Email OTP/magic-link lifetime expressed in seconds | `86400` |
| `MONGO_URL` | ❗️ MongoDB instance connection string either to container instance or MongoDB Cloud | `None` | | `MONGO_URL` | ❗️ MongoDB instance connection string either to container instance or MongoDB Cloud | `None` |
| `MONGO_USERNAME` | MongoDB username if using container | `None` | | `MONGO_USERNAME` | MongoDB username if using container | `None` |
| `MONGO_PASSWORD` | MongoDB password if using container | `None` | | `MONGO_PASSWORD` | MongoDB password if using container | `None` |