Skip to content

Commit

Permalink
Merge branch 'main' into fix/undefined-url
Browse files Browse the repository at this point in the history
  • Loading branch information
vmatsiiako authored Feb 21, 2023
2 parents 54e2b66 + f8c4ccd commit c65ce14
Show file tree
Hide file tree
Showing 170 changed files with 6,557 additions and 2,841 deletions.
86 changes: 32 additions & 54 deletions .github/values.yaml
Original file line number Diff line number Diff line change
@@ -1,93 +1,71 @@
#####
# INFISICAL K8 DEFAULT VALUES FILE
# PLEASE REPLACE VALUES/EDIT AS REQUIRED
#####

nameOverride: ""

frontend:
enabled: true
name: frontend
podAnnotations: {}
deploymentAnnotations:
secrets.infisical.com/auto-reload: "true"
replicaCount: 2
image:
repository: infisical/frontend
pullPolicy: Always
tag: "latest"
pullPolicy: Always
kubeSecretRef: managed-secret-frontend
service:
# type of the frontend service
type: ClusterIP
# define the nodePort if service type is NodePort
# nodePort:
annotations: {}
type: ClusterIP
nodePort: ""

frontendEnvironmentVariables: null

backend:
enabled: true
name: backend
podAnnotations: {}
deploymentAnnotations:
secrets.infisical.com/auto-reload: "true"
replicaCount: 2
image:
repository: infisical/backend
pullPolicy: Always
tag: "latest"
pullPolicy: Always
kubeSecretRef: managed-backend-secret
service:
annotations: {}
type: ClusterIP
nodePort: ""

backendEnvironmentVariables: null

## Mongo DB persistence
mongodb:
name: mongodb
podAnnotations: {}
image:
repository: mongo
pullPolicy: IfNotPresent
tag: "latest"
service:
annotations: {}
enabled: true
persistence:
enabled: false

# By default the backend will be connected to a Mongo instance in the cluster.
# However, it is recommended to add a managed document DB connection string because the DB instance in the cluster does not have persistence yet ( data will be deleted on next deploy).
# Learn about connection string type here https://www.mongodb.com/docs/manual/reference/connection-string/
mongodbConnection: {}
# externalMongoDBConnectionString: <>
## By default the backend will be connected to a Mongo instance within the cluster
## However, it is recommended to add a managed document DB connection string for production-use (DBaaS)
## Learn about connection string type here https://www.mongodb.com/docs/manual/reference/connection-string/
## e.g. "mongodb://<user>:<pass>@<host>:<port>/<database-name>"
mongodbConnection:
externalMongoDBConnectionString: ""

ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: "nginx"
hostName: gamma.infisical.com # replace with your domain
frontend:
# cert-manager.io/issuer: letsencrypt-nginx
hostName: gamma.infisical.com ## <- Replace with your own domain
frontend:
path: /
pathType: Prefix
backend:
path: /api
pathType: Prefix
tls: []


## Complete Ingress example
# ingress:
# enabled: true
# annotations:
# kubernetes.io/ingress.class: "nginx"
# cert-manager.io/issuer: letsencrypt-nginx
# hostName: k8.infisical.com
# frontend:
# path: /
# pathType: Prefix
# backend:
# path: /api
# pathType: Prefix
# tls:
# - secretName: letsencrypt-nginx
# hosts:
# - k8.infisical.com

###
### YOU MUST FILL IN ALL SECRETS BELOW
###
backendEnvironmentVariables: {}
tls:
[]
# - secretName: letsencrypt-nginx
# hosts:
# - infisical.local

frontendEnvironmentVariables: {}
mailhog:
enabled: false
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
- **[Activity Logs](https://infisical.com/docs/getting-started/dashboard/audit-logs)** to record every action taken in a project
- **[Point-in-time Secrets Recovery](https://infisical.com/docs/getting-started/dashboard/pit-recovery)** for rolling back to any snapshot of your secrets
- **Role-based Access Controls** per environment
- 🔜 **2FA** (next week)
- **2FA** (more options coming soon)
- 🔜 **1-Click Deploy** to AWS
- 🔜 **Automatic Secret Rotation**
- 🔜 **Smart Security Alerts**
Expand Down
6 changes: 5 additions & 1 deletion backend/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { patchRouterParam } = require('./utils/patchAsyncRoutes');

import express, { Request, Response } from 'express';
import express from 'express';
import helmet from 'helmet';
import cors from 'cors';
import cookieParser from 'cookie-parser';
Expand Down Expand Up @@ -42,6 +42,8 @@ import {
integrationAuth as v1IntegrationAuthRouter
} from './routes/v1';
import {
signup as v2SignupRouter,
auth as v2AuthRouter,
users as v2UsersRouter,
organizations as v2OrganizationsRouter,
workspace as v2WorkspaceRouter,
Expand Down Expand Up @@ -110,6 +112,8 @@ 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);
Expand Down
4 changes: 4 additions & 0 deletions backend/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY!;
const SALT_ROUNDS = parseInt(process.env.SALT_ROUNDS!) || 10;
const JWT_AUTH_LIFETIME = process.env.JWT_AUTH_LIFETIME! || '10d';
const JWT_AUTH_SECRET = process.env.JWT_AUTH_SECRET!;
const JWT_MFA_LIFETIME = process.env.JWT_MFA_LIFETIME! || '5m';
const JWT_MFA_SECRET = process.env.JWT_MFA_SECRET!;
const JWT_REFRESH_LIFETIME = process.env.JWT_REFRESH_LIFETIME! || '90d';
const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET!;
const JWT_SERVICE_SECRET = process.env.JWT_SERVICE_SECRET!;
Expand Down Expand Up @@ -56,6 +58,8 @@ export {
SALT_ROUNDS,
JWT_AUTH_LIFETIME,
JWT_AUTH_SECRET,
JWT_MFA_LIFETIME,
JWT_MFA_SECRET,
JWT_REFRESH_LIFETIME,
JWT_REFRESH_SECRET,
JWT_SERVICE_SECRET,
Expand Down
4 changes: 2 additions & 2 deletions backend/src/controllers/v1/authController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as Sentry from '@sentry/node';
import * as bigintConversion from 'bigint-conversion';
const jsrp = require('jsrp');
import { User, LoginSRPDetail } from '../../models';
import { createToken, issueTokens, clearTokens } from '../../helpers/auth';
import { createToken, issueAuthTokens, clearTokens } from '../../helpers/auth';
import {
ACTION_LOGIN,
ACTION_LOGOUT
Expand Down Expand Up @@ -111,7 +111,7 @@ export const login2 = async (req: Request, res: Response) => {
// compare server and client shared keys
if (server.checkClientProof(clientProof)) {
// issue tokens
const tokens = await issueTokens({ userId: user._id.toString() });
const tokens = await issueAuthTokens({ userId: user._id.toString() });

// store (refresh) token in httpOnly cookie
res.cookie('jid', tokens.refreshToken, {
Expand Down
34 changes: 14 additions & 20 deletions backend/src/controllers/v1/membershipOrgController.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import crypto from 'crypto';
import { SITE_URL, JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET, EMAIL_TOKEN_LIFETIME } from '../../config';
import { MembershipOrg, Organization, User, Token } from '../../models';
import { SITE_URL, JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET } from '../../config';
import { MembershipOrg, Organization, User } from '../../models';
import { deleteMembershipOrg as deleteMemberFromOrg } from '../../helpers/membershipOrg';
import { checkEmailVerification } from '../../helpers/signup';
import { createToken } from '../../helpers/auth';
import { updateSubscriptionOrgQuantity } from '../../helpers/organization';
import { sendMail } from '../../helpers/nodemailer';
import { OWNER, ADMIN, MEMBER, ACCEPTED, INVITED } from '../../variables';
import { TokenService } from '../../services';
import { OWNER, ADMIN, MEMBER, ACCEPTED, INVITED, TOKEN_EMAIL_ORG_INVITATION } from '../../variables';

/**
* Delete organization membership with id [membershipOrgId] from organization
Expand Down Expand Up @@ -163,18 +162,11 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
const organization = await Organization.findOne({ _id: organizationId });

if (organization) {
const token = crypto.randomBytes(16).toString('hex');

await Token.findOneAndUpdate(
{ email: inviteeEmail },
{
email: inviteeEmail,
token,
createdAt: new Date(),
ttl: Math.floor(+new Date() / 1000) + EMAIL_TOKEN_LIFETIME // time in seconds, i.e unix
},
{ upsert: true, new: true }
);
const token = await TokenService.createToken({
type: TOKEN_EMAIL_ORG_INVITATION,
email: inviteeEmail,
organizationId: organization._id
});

await sendMail({
template: 'organizationInvitation.handlebars',
Expand Down Expand Up @@ -226,10 +218,12 @@ export const verifyUserToOrganization = async (req: Request, res: Response) => {

if (!membershipOrg)
throw new Error('Failed to find any invitations for email');

await checkEmailVerification({

await TokenService.validateToken({
type: TOKEN_EMAIL_ORG_INVITATION,
email,
code
organizationId: membershipOrg.organization,
token: code
});

if (user && user?.publicKey) {
Expand Down
73 changes: 43 additions & 30 deletions backend/src/controllers/v1/passwordController.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import crypto from 'crypto';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const jsrp = require('jsrp');
import * as bigintConversion from 'bigint-conversion';
import { User, Token, BackupPrivateKey, LoginSRPDetail } from '../../models';
import { checkEmailVerification } from '../../helpers/signup';
import { User, BackupPrivateKey, LoginSRPDetail } from '../../models';
import { createToken } from '../../helpers/auth';
import { sendMail } from '../../helpers/nodemailer';
import { EMAIL_TOKEN_LIFETIME, JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET, SITE_URL } from '../../config';
import { TokenService } from '../../services';
import { JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET, SITE_URL } from '../../config';
import { TOKEN_EMAIL_PASSWORD_RESET } from '../../variables';
import { BadRequestError } from '../../utils/errors';

/**
Expand All @@ -31,20 +31,12 @@ export const emailPasswordReset = async (req: Request, res: Response) => {
error: 'Failed to send email verification for password reset'
});
}

const token = crypto.randomBytes(16).toString('hex');

await Token.findOneAndUpdate(
{ email },
{
email,
token,
createdAt: new Date(),
ttl: Math.floor(+new Date() / 1000) + EMAIL_TOKEN_LIFETIME // time in seconds, i.e unix
},
{ upsert: true, new: true }
);


const token = await TokenService.createToken({
type: TOKEN_EMAIL_PASSWORD_RESET,
email
});

await sendMail({
template: 'passwordReset.handlebars',
subjectLine: 'Infisical password reset',
Expand All @@ -55,7 +47,6 @@ export const emailPasswordReset = async (req: Request, res: Response) => {
callback_url: SITE_URL + '/password-reset'
}
});

} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
Expand Down Expand Up @@ -88,10 +79,11 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => {
error: 'Failed email verification for password reset'
});
}

await checkEmailVerification({

await TokenService.validateToken({
type: TOKEN_EMAIL_PASSWORD_RESET,
email,
code
token: code
});

// generate temporary password-reset token
Expand Down Expand Up @@ -174,8 +166,18 @@ export const srp1 = async (req: Request, res: Response) => {
*/
export const changePassword = async (req: Request, res: Response) => {
try {
const { clientProof, encryptedPrivateKey, iv, tag, salt, verifier } =
req.body;
const {
clientProof,
protectedKey,
protectedKeyIV,
protectedKeyTag,
encryptedPrivateKey,
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt,
verifier
} = req.body;

const user = await User.findOne({
email: req.user.email
}).select('+salt +verifier');
Expand Down Expand Up @@ -205,9 +207,13 @@ export const changePassword = async (req: Request, res: Response) => {
await User.findByIdAndUpdate(
req.user._id.toString(),
{
encryptionVersion: 2,
protectedKey,
protectedKeyIV,
protectedKeyTag,
encryptedPrivateKey,
iv,
tag,
iv: encryptedPrivateKeyIV,
tag: encryptedPrivateKeyTag,
salt,
verifier
},
Expand Down Expand Up @@ -341,19 +347,26 @@ export const getBackupPrivateKey = async (req: Request, res: Response) => {
export const resetPassword = async (req: Request, res: Response) => {
try {
const {
protectedKey,
protectedKeyIV,
protectedKeyTag,
encryptedPrivateKey,
iv,
tag,
encryptedPrivateKeyIV,
encryptedPrivateKeyTag,
salt,
verifier,
} = req.body;

await User.findByIdAndUpdate(
req.user._id.toString(),
{
encryptionVersion: 2,
protectedKey,
protectedKeyIV,
protectedKeyTag,
encryptedPrivateKey,
iv,
tag,
iv: encryptedPrivateKeyIV,
tag: encryptedPrivateKeyTag,
salt,
verifier
},
Expand Down
Loading

0 comments on commit c65ce14

Please sign in to comment.