mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Begin refactoring backfilling and preparation operations into setup and start adding encryption metadata to models
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import InfisicalClient from 'infisical-node';
|
||||
import { validateEncryptionKey } from '../validation';
|
||||
|
||||
const client = new InfisicalClient({
|
||||
token: process.env.INFISICAL_TOKEN!
|
||||
@@ -6,7 +7,18 @@ const client = new InfisicalClient({
|
||||
|
||||
export const getPort = async () => (await client.getSecret('PORT')).secretValue || 4000;
|
||||
export const getInviteOnlySignup = async () => (await client.getSecret('INVITE_ONLY_SIGNUP')).secretValue == undefined ? false : (await client.getSecret('INVITE_ONLY_SIGNUP')).secretValue;
|
||||
export const getEncryptionKey = async () => (await client.getSecret('ENCRYPTION_KEY')).secretValue;
|
||||
export const getEncryptionKey = async () => (await client.getSecret('ENCRYPTION_KEY')).secretValue; // TODO: deprecate in favor of INFISICAL_ENCRYPTION_KEY
|
||||
export const getRootEncryptionKey = async (): Promise<string | undefined> => {
|
||||
const encryptionKey = (await client.getSecret('ROOT_ENCRYPTION_KEY')).secretValue;
|
||||
|
||||
if (encryptionKey) {
|
||||
// validate [encryptionKey] to make sure it is in base64 format and 256-bit
|
||||
validateEncryptionKey(encryptionKey);
|
||||
return encryptionKey;
|
||||
}
|
||||
|
||||
return encryptionKey;
|
||||
}
|
||||
export const getSaltRounds = async () => parseInt((await client.getSecret('SALT_ROUNDS')).secretValue) || 10;
|
||||
export const getJwtAuthLifetime = async () => (await client.getSecret('JWT_AUTH_LIFETIME')).secretValue || '10d';
|
||||
export const getJwtAuthSecret = async () => (await client.getSecret('JWT_AUTH_SECRET')).secretValue;
|
||||
|
||||
@@ -93,52 +93,8 @@ const markDeletedSecretVersionsHelper = async ({
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize secret versioning by setting previously unversioned
|
||||
* secrets to version 1 and begin populating secret versions.
|
||||
*/
|
||||
const initSecretVersioningHelper = async () => {
|
||||
await Secret.updateMany(
|
||||
{ version: { $exists: false } },
|
||||
{ $set: { version: 1 } }
|
||||
);
|
||||
|
||||
const unversionedSecrets: ISecret[] = await Secret.aggregate([
|
||||
{
|
||||
$lookup: {
|
||||
from: "secretversions",
|
||||
localField: "_id",
|
||||
foreignField: "secret",
|
||||
as: "versions",
|
||||
},
|
||||
},
|
||||
{
|
||||
$match: {
|
||||
versions: { $size: 0 },
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
if (unversionedSecrets.length > 0) {
|
||||
await addSecretVersionsHelper({
|
||||
secretVersions: unversionedSecrets.map(
|
||||
(s, idx) =>
|
||||
new SecretVersion({
|
||||
...s,
|
||||
secret: s._id,
|
||||
version: s.version ? s.version : 1,
|
||||
isDeleted: false,
|
||||
workspace: s.workspace,
|
||||
environment: s.environment,
|
||||
})
|
||||
),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
takeSecretSnapshotHelper,
|
||||
addSecretVersionsHelper,
|
||||
markDeletedSecretVersionsHelper,
|
||||
initSecretVersioningHelper,
|
||||
markDeletedSecretVersionsHelper
|
||||
};
|
||||
|
||||
@@ -3,8 +3,7 @@ import { ISecretVersion } from '../models';
|
||||
import {
|
||||
takeSecretSnapshotHelper,
|
||||
addSecretVersionsHelper,
|
||||
markDeletedSecretVersionsHelper,
|
||||
initSecretVersioningHelper
|
||||
markDeletedSecretVersionsHelper
|
||||
} from '../helpers/secret';
|
||||
import EELicenseService from './EELicenseService';
|
||||
|
||||
@@ -64,15 +63,6 @@ class EESecretService {
|
||||
secretIds
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize secret versioning by setting previously unversioned
|
||||
* secrets to version 1 and begin populating secret versions.
|
||||
*/
|
||||
static async initSecretVersioning() {
|
||||
if (!EELicenseService.isLicenseValid) return;
|
||||
await initSecretVersioningHelper();
|
||||
}
|
||||
}
|
||||
|
||||
export default EESecretService;
|
||||
@@ -13,10 +13,10 @@ import {
|
||||
} from "../models";
|
||||
import {
|
||||
generateKeyPair,
|
||||
encryptSymmetric,
|
||||
decryptSymmetric,
|
||||
decryptAsymmetric,
|
||||
} from "../utils/crypto";
|
||||
encryptSymmetric128BitHexKeyUTF8,
|
||||
decryptSymmetric128BitHexKeyUTF8,
|
||||
decryptAsymmetric
|
||||
} from '../utils/crypto';
|
||||
import {
|
||||
SECRET_SHARED,
|
||||
AUTH_MODE_JWT,
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
} from "../variables";
|
||||
import { getEncryptionKey } from "../config";
|
||||
import { BotNotFoundError, UnauthorizedRequestError } from "../utils/errors";
|
||||
import { validateMembership } from "../helpers/membership";
|
||||
import { validateUserClientForWorkspace } from "../helpers/user";
|
||||
import { validateServiceAccountClientForWorkspace } from "../helpers/serviceAccount";
|
||||
|
||||
@@ -120,7 +119,7 @@ const createBot = async ({
|
||||
workspaceId: Types.ObjectId;
|
||||
}) => {
|
||||
const { publicKey, privateKey } = generateKeyPair();
|
||||
const { ciphertext, iv, tag } = encryptSymmetric({
|
||||
const { ciphertext, iv, tag } = encryptSymmetric128BitHexKeyUTF8({
|
||||
plaintext: privateKey,
|
||||
key: await getEncryptionKey(),
|
||||
});
|
||||
@@ -161,14 +160,14 @@ const getSecretsHelper = async ({
|
||||
});
|
||||
|
||||
secrets.forEach((secret: ISecret) => {
|
||||
const secretKey = decryptSymmetric({
|
||||
const secretKey = decryptSymmetric128BitHexKeyUTF8({
|
||||
ciphertext: secret.secretKeyCiphertext,
|
||||
iv: secret.secretKeyIV,
|
||||
tag: secret.secretKeyTag,
|
||||
key,
|
||||
});
|
||||
|
||||
const secretValue = decryptSymmetric({
|
||||
const secretValue = decryptSymmetric128BitHexKeyUTF8({
|
||||
ciphertext: secret.secretValueCiphertext,
|
||||
iv: secret.secretValueIV,
|
||||
tag: secret.secretValueTag,
|
||||
@@ -202,7 +201,7 @@ const getKey = async ({ workspaceId }: { workspaceId: string }) => {
|
||||
if (!bot) throw new Error("Failed to find bot");
|
||||
if (!bot.isActive) throw new Error("Bot is not active");
|
||||
|
||||
const privateKeyBot = decryptSymmetric({
|
||||
const privateKeyBot = decryptSymmetric128BitHexKeyUTF8({
|
||||
ciphertext: bot.encryptedPrivateKey,
|
||||
iv: bot.iv,
|
||||
tag: bot.tag,
|
||||
@@ -234,7 +233,7 @@ const encryptSymmetricHelper = async ({
|
||||
plaintext: string;
|
||||
}) => {
|
||||
const key = await getKey({ workspaceId: workspaceId.toString() });
|
||||
const { ciphertext, iv, tag } = encryptSymmetric({
|
||||
const { ciphertext, iv, tag } = encryptSymmetric128BitHexKeyUTF8({
|
||||
plaintext,
|
||||
key,
|
||||
});
|
||||
@@ -266,7 +265,7 @@ const decryptSymmetricHelper = async ({
|
||||
tag: string;
|
||||
}) => {
|
||||
const key = await getKey({ workspaceId: workspaceId.toString() });
|
||||
const plaintext = decryptSymmetric({
|
||||
const plaintext = decryptSymmetric128BitHexKeyUTF8({
|
||||
ciphertext,
|
||||
iv,
|
||||
tag,
|
||||
@@ -281,5 +280,5 @@ export {
|
||||
createBot,
|
||||
getSecretsHelper,
|
||||
encryptSymmetricHelper,
|
||||
decryptSymmetricHelper,
|
||||
decryptSymmetricHelper
|
||||
};
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { EESecretService } from '../ee/services';
|
||||
import { SecretService } from '../services';
|
||||
import { getLogger } from '../utils/logger';
|
||||
|
||||
/**
|
||||
@@ -21,9 +19,7 @@ const initDatabaseHelper = async ({
|
||||
mongoose.Schema.Types.String.checkRequired(v => typeof v === 'string');
|
||||
|
||||
(await getLogger("database")).info("Database connection established");
|
||||
|
||||
await EESecretService.initSecretVersioning();
|
||||
await SecretService.initSecretBlindIndexDataHelper();
|
||||
|
||||
} catch (err) {
|
||||
(await getLogger("database")).error(`Unable to establish Database connection due to the error.\n${err}`);
|
||||
}
|
||||
|
||||
@@ -54,9 +54,9 @@ import {
|
||||
} from '../variables';
|
||||
import crypto from 'crypto';
|
||||
import * as argon2 from 'argon2';
|
||||
import {
|
||||
encryptSymmetric,
|
||||
decryptSymmetric
|
||||
import {
|
||||
encryptSymmetric128BitHexKeyUTF8,
|
||||
decryptSymmetric128BitHexKeyUTF8
|
||||
} from '../utils/crypto';
|
||||
import { getEncryptionKey } from '../config';
|
||||
import { TelemetryService } from '../services';
|
||||
@@ -220,48 +220,6 @@ const validateClientForSecrets = async ({
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize secret blind index data by setting previously
|
||||
* un-initialized projects to have secret blind index data
|
||||
* (Ensures that all projects have associated blind index data)
|
||||
*/
|
||||
const initSecretBlindIndexDataHelper = async () => {
|
||||
const workspaceIdsBlindIndexed = await SecretBlindIndexData.distinct('workspace');
|
||||
const workspaceIdsToBlindIndex = await Workspace.distinct('_id', {
|
||||
_id: {
|
||||
$nin: workspaceIdsBlindIndexed
|
||||
}
|
||||
});
|
||||
|
||||
const secretBlindIndexDataToInsert = await Promise.all(
|
||||
workspaceIdsToBlindIndex.map(async (workspaceToBlindIndex) => {
|
||||
const salt = crypto.randomBytes(16).toString('base64');
|
||||
|
||||
const {
|
||||
ciphertext: encryptedSaltCiphertext,
|
||||
iv: saltIV,
|
||||
tag: saltTag
|
||||
} = encryptSymmetric({
|
||||
plaintext: salt,
|
||||
key: await getEncryptionKey()
|
||||
});
|
||||
|
||||
const secretBlindIndexData = new SecretBlindIndexData({
|
||||
workspace: workspaceToBlindIndex,
|
||||
encryptedSaltCiphertext,
|
||||
saltIV,
|
||||
saltTag
|
||||
})
|
||||
|
||||
return secretBlindIndexData;
|
||||
})
|
||||
);
|
||||
|
||||
if (secretBlindIndexDataToInsert.length > 0) {
|
||||
await SecretBlindIndexData.insertMany(secretBlindIndexDataToInsert);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create secret blind index data containing encrypted blind index [salt]
|
||||
* for workspace with id [workspaceId]
|
||||
@@ -280,7 +238,7 @@ const createSecretBlindIndexDataHelper = async ({
|
||||
ciphertext: encryptedSaltCiphertext,
|
||||
iv: saltIV,
|
||||
tag: saltTag
|
||||
} = encryptSymmetric({
|
||||
} = encryptSymmetric128BitHexKeyUTF8({
|
||||
plaintext: salt,
|
||||
key: await getEncryptionKey()
|
||||
});
|
||||
@@ -314,7 +272,7 @@ const getSecretBlindIndexSaltHelper = async ({
|
||||
if (!secretBlindIndexData) throw SecretBlindIndexDataNotFoundError();
|
||||
|
||||
// decrypt workspace salt
|
||||
const salt = decryptSymmetric({
|
||||
const salt = decryptSymmetric128BitHexKeyUTF8({
|
||||
ciphertext: secretBlindIndexData.encryptedSaltCiphertext,
|
||||
iv: secretBlindIndexData.saltIV,
|
||||
tag: secretBlindIndexData.saltTag,
|
||||
@@ -376,7 +334,7 @@ const generateSecretBlindIndexHelper = async ({
|
||||
if (!secretBlindIndexData) throw SecretBlindIndexDataNotFoundError();
|
||||
|
||||
// decrypt workspace salt
|
||||
const salt = decryptSymmetric({
|
||||
const salt = decryptSymmetric128BitHexKeyUTF8({
|
||||
ciphertext: secretBlindIndexData.encryptedSaltCiphertext,
|
||||
iv: secretBlindIndexData.saltIV,
|
||||
tag: secretBlindIndexData.saltTag,
|
||||
@@ -934,7 +892,6 @@ const deleteSecretHelper = async ({
|
||||
export {
|
||||
validateClientForSecret,
|
||||
validateClientForSecrets,
|
||||
initSecretBlindIndexDataHelper,
|
||||
createSecretBlindIndexDataHelper,
|
||||
getSecretBlindIndexSaltHelper,
|
||||
generateSecretBlindIndexWithSaltHelper,
|
||||
|
||||
@@ -28,7 +28,6 @@ import {
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_API_KEY
|
||||
} from '../variables';
|
||||
import { encryptSymmetric } from '../utils/crypto';
|
||||
import { SecretService } from '../services';
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,15 +4,9 @@ dotenv.config();
|
||||
import express from 'express';
|
||||
import helmet from 'helmet';
|
||||
import cors from 'cors';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { DatabaseService } from './services';
|
||||
import { setUpHealthEndpoint } from './services/health';
|
||||
import { initSmtp } from './services/smtp';
|
||||
import { TelemetryService } from './services';
|
||||
import { setTransporter } from './helpers/nodemailer';
|
||||
import { createTestUserForDevelopment } from './utils/addDevelopmentUser';
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { patchRouterParam } = require('./utils/patchAsyncRoutes');
|
||||
|
||||
import cookieParser from 'cookie-parser';
|
||||
import swaggerUi = require('swagger-ui-express');
|
||||
@@ -77,22 +71,13 @@ import {
|
||||
getSiteURL,
|
||||
getSmtpHost
|
||||
} from './config';
|
||||
import { setup } from './utils/setup';
|
||||
|
||||
const main = async () => {
|
||||
TelemetryService.logTelemetryMessage();
|
||||
setTransporter(await initSmtp());
|
||||
|
||||
await DatabaseService.initDatabase(await getMongoURL());
|
||||
if ((await getNodeEnv()) !== 'test') {
|
||||
Sentry.init({
|
||||
dsn: await getSentryDSN(),
|
||||
tracesSampleRate: 1.0,
|
||||
debug: await getNodeEnv() === 'production' ? false : true,
|
||||
environment: await getNodeEnv()
|
||||
});
|
||||
}
|
||||
await setup();
|
||||
|
||||
patchRouterParam();
|
||||
const app = express();
|
||||
app.enable('trust proxy');
|
||||
app.use(express.json());
|
||||
@@ -176,7 +161,7 @@ const main = async () => {
|
||||
(await getLogger("backend-main")).info(`Server started listening at port ${await getPort()}`)
|
||||
});
|
||||
|
||||
await createTestUserForDevelopment();
|
||||
// await createTestUserForDevelopment();
|
||||
setUpHealthEndpoint(server);
|
||||
|
||||
server.on('close', async () => {
|
||||
|
||||
41
backend/src/interfaces/utils/crypto.ts
Normal file
41
backend/src/interfaces/utils/crypto.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
export interface IGenerateKeyPairOutput {
|
||||
publicKey: string;
|
||||
privateKey: string
|
||||
}
|
||||
|
||||
export interface IEncryptAsymmetricInput {
|
||||
plaintext: string;
|
||||
publicKey: string;
|
||||
privateKey: string;
|
||||
}
|
||||
|
||||
export interface IEncryptAsymmetricOutput {
|
||||
ciphertext: string;
|
||||
nonce: string;
|
||||
}
|
||||
|
||||
export interface IDecryptAsymmetricInput {
|
||||
ciphertext: string;
|
||||
nonce: string;
|
||||
publicKey: string;
|
||||
privateKey: string;
|
||||
}
|
||||
|
||||
export interface IEncryptSymmetricInput {
|
||||
plaintext: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
export interface IEncryptSymmetricOutput {
|
||||
ciphertext: string;
|
||||
iv: string;
|
||||
tag: string;
|
||||
}
|
||||
|
||||
export interface IDecryptSymmetricInput {
|
||||
ciphertext: string;
|
||||
iv: string;
|
||||
tag: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
1
backend/src/interfaces/utils/index.ts
Normal file
1
backend/src/interfaces/utils/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './crypto';
|
||||
@@ -1,4 +1,9 @@
|
||||
import { Schema, model, Types } from 'mongoose';
|
||||
import {
|
||||
ALGORITHM_AES_256_GCM,
|
||||
ENCODING_SCHEME_UTF8,
|
||||
ENCODING_SCHEME_BASE64
|
||||
} from '../variables';
|
||||
|
||||
export interface IBackupPrivateKey {
|
||||
_id: Types.ObjectId;
|
||||
@@ -7,6 +12,9 @@ export interface IBackupPrivateKey {
|
||||
iv: string;
|
||||
tag: string;
|
||||
salt: string;
|
||||
algorithm: string;
|
||||
keySize: number;
|
||||
keyEncoding: 'base64' | 'utf8';
|
||||
verifier: string;
|
||||
}
|
||||
|
||||
@@ -32,6 +40,24 @@ const backupPrivateKeySchema = new Schema<IBackupPrivateKey>(
|
||||
select: false,
|
||||
required: true
|
||||
},
|
||||
algorithm: { // the encryption algorithm used
|
||||
type: String,
|
||||
enum: [ALGORITHM_AES_256_GCM],
|
||||
required: true
|
||||
},
|
||||
keySize: { // the size of the key used in the algorithm
|
||||
type: Number,
|
||||
enum: [256],
|
||||
required: true
|
||||
},
|
||||
keyEncoding: {
|
||||
type: String,
|
||||
enum: [
|
||||
ENCODING_SCHEME_UTF8,
|
||||
ENCODING_SCHEME_BASE64
|
||||
],
|
||||
required: true
|
||||
},
|
||||
salt: {
|
||||
type: String,
|
||||
select: false,
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { Schema, model, Types } from 'mongoose';
|
||||
import {
|
||||
ALGORITHM_AES_256_GCM,
|
||||
ENCODING_SCHEME_UTF8,
|
||||
ENCODING_SCHEME_HEX,
|
||||
ENCODING_SCHEME_BASE64
|
||||
} from '../variables';
|
||||
|
||||
export interface IBot {
|
||||
_id: Types.ObjectId;
|
||||
@@ -9,6 +15,9 @@ export interface IBot {
|
||||
encryptedPrivateKey: string;
|
||||
iv: string;
|
||||
tag: string;
|
||||
algorithm: 'aes-256-gcm';
|
||||
keySize: 256;
|
||||
keyEncoding: 'base64' | 'utf8';
|
||||
}
|
||||
|
||||
const botSchema = new Schema<IBot>(
|
||||
@@ -45,6 +54,24 @@ const botSchema = new Schema<IBot>(
|
||||
type: String,
|
||||
required: true,
|
||||
select: false
|
||||
},
|
||||
algorithm: { // the encryption algorithm used
|
||||
type: String,
|
||||
enum: [ALGORITHM_AES_256_GCM],
|
||||
required: true
|
||||
},
|
||||
keySize: { // the size of the key used in the algorithm
|
||||
type: Number,
|
||||
enum: [256],
|
||||
required: true
|
||||
},
|
||||
keyEncoding: {
|
||||
type: String,
|
||||
enum: [
|
||||
ENCODING_SCHEME_UTF8,
|
||||
ENCODING_SCHEME_BASE64
|
||||
],
|
||||
required: true
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -14,6 +14,9 @@ import {
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
INTEGRATION_SUPABASE,
|
||||
ALGORITHM_AES_256_GCM,
|
||||
ENCODING_SCHEME_UTF8,
|
||||
ENCODING_SCHEME_BASE64
|
||||
} from "../variables";
|
||||
|
||||
export interface IIntegrationAuth extends Document {
|
||||
@@ -31,6 +34,9 @@ export interface IIntegrationAuth extends Document {
|
||||
accessCiphertext?: string;
|
||||
accessIV?: string;
|
||||
accessTag?: string;
|
||||
algorithm?: 'aes-256-gcm';
|
||||
keySize?: 256;
|
||||
keyEncoding: 'utf8' | 'base64';
|
||||
accessExpiresAt?: Date;
|
||||
}
|
||||
|
||||
@@ -109,6 +115,24 @@ const integrationAuthSchema = new Schema<IIntegrationAuth>(
|
||||
type: Date,
|
||||
select: false,
|
||||
},
|
||||
algorithm: { // the encryption algorithm used
|
||||
type: String,
|
||||
enum: [ALGORITHM_AES_256_GCM],
|
||||
required: true
|
||||
},
|
||||
keySize: { // the size of the key used in the algorithm
|
||||
type: Number,
|
||||
enum: [256],
|
||||
required: true
|
||||
},
|
||||
keyEncoding: {
|
||||
type: String,
|
||||
enum: [
|
||||
ENCODING_SCHEME_UTF8,
|
||||
ENCODING_SCHEME_BASE64
|
||||
],
|
||||
required: true
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { Schema, model, Types, Document } from 'mongoose';
|
||||
import {
|
||||
ALGORITHM_AES_256_GCM,
|
||||
ENCODING_SCHEME_UTF8,
|
||||
ENCODING_SCHEME_BASE64
|
||||
} from '../variables';
|
||||
|
||||
export interface ISecretBlindIndexData extends Document {
|
||||
_id: Types.ObjectId;
|
||||
@@ -6,6 +11,9 @@ export interface ISecretBlindIndexData extends Document {
|
||||
encryptedSaltCiphertext: string;
|
||||
saltIV: string;
|
||||
saltTag: string;
|
||||
algorithm: 'aes-256-gcm';
|
||||
keySize: 256;
|
||||
keyEncoding: 'base64' | 'utf8'
|
||||
}
|
||||
|
||||
const secretBlindIndexDataSchema = new Schema<ISecretBlindIndexData>(
|
||||
@@ -26,7 +34,26 @@ const secretBlindIndexDataSchema = new Schema<ISecretBlindIndexData>(
|
||||
saltTag: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
algorithm: {
|
||||
type: String,
|
||||
enum: [ALGORITHM_AES_256_GCM],
|
||||
required: true
|
||||
},
|
||||
keySize: {
|
||||
type: Number,
|
||||
enum: [256],
|
||||
required: true
|
||||
},
|
||||
keyEncoding: {
|
||||
type: String,
|
||||
enum: [
|
||||
ENCODING_SCHEME_UTF8,
|
||||
ENCODING_SCHEME_BASE64
|
||||
],
|
||||
required: true
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// WIP
|
||||
import { Types } from 'mongoose';
|
||||
import {
|
||||
ISecret
|
||||
@@ -11,7 +10,6 @@ import {
|
||||
DeleteSecretParams
|
||||
} from '../interfaces/services/SecretService';
|
||||
import {
|
||||
initSecretBlindIndexDataHelper,
|
||||
createSecretBlindIndexDataHelper,
|
||||
getSecretBlindIndexSaltHelper,
|
||||
generateSecretBlindIndexWithSaltHelper,
|
||||
@@ -24,16 +22,6 @@ import {
|
||||
} from '../helpers/secrets';
|
||||
|
||||
class SecretService {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param param0 h
|
||||
* @returns
|
||||
*/
|
||||
|
||||
static async initSecretBlindIndexDataHelper() {
|
||||
return await initSecretBlindIndexDataHelper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create secret blind index data containing encrypted blind index salt
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
import nacl from 'tweetnacl';
|
||||
import util from 'tweetnacl-util';
|
||||
import AesGCM from './aes-gcm';
|
||||
|
||||
/**
|
||||
* Return new base64, NaCl, public-private key pair.
|
||||
* @returns {Object} obj
|
||||
* @returns {String} obj.publicKey - base64, NaCl, public key
|
||||
* @returns {String} obj.privateKey - base64, NaCl, private key
|
||||
*/
|
||||
const generateKeyPair = () => {
|
||||
const pair = nacl.box.keyPair();
|
||||
|
||||
return ({
|
||||
publicKey: util.encodeBase64(pair.publicKey),
|
||||
privateKey: util.encodeBase64(pair.secretKey)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return assymmetrically encrypted [plaintext] using [publicKey] where
|
||||
* [publicKey] likely belongs to the recipient.
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.plaintext - plaintext to encrypt
|
||||
* @param {String} obj.publicKey - public key of the recipient
|
||||
* @param {String} obj.privateKey - private key of the sender (current user)
|
||||
* @returns {Object} obj
|
||||
* @returns {String} ciphertext - base64-encoded ciphertext
|
||||
* @returns {String} nonce - base64-encoded nonce
|
||||
*/
|
||||
const encryptAsymmetric = ({
|
||||
plaintext,
|
||||
publicKey,
|
||||
privateKey
|
||||
}: {
|
||||
plaintext: string;
|
||||
publicKey: string;
|
||||
privateKey: string;
|
||||
}) => {
|
||||
const nonce = nacl.randomBytes(24);
|
||||
const ciphertext = nacl.box(
|
||||
util.decodeUTF8(plaintext),
|
||||
nonce,
|
||||
util.decodeBase64(publicKey),
|
||||
util.decodeBase64(privateKey)
|
||||
);
|
||||
|
||||
return {
|
||||
ciphertext: util.encodeBase64(ciphertext),
|
||||
nonce: util.encodeBase64(nonce)
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Return assymmetrically decrypted [ciphertext] using [privateKey] where
|
||||
* [privateKey] likely belongs to the recipient.
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.ciphertext - ciphertext to decrypt
|
||||
* @param {String} obj.nonce - nonce
|
||||
* @param {String} obj.publicKey - public key of the sender
|
||||
* @param {String} obj.privateKey - private key of the receiver (current user)
|
||||
* @param {String} plaintext - UTF8 plaintext
|
||||
*/
|
||||
const decryptAsymmetric = ({
|
||||
ciphertext,
|
||||
nonce,
|
||||
publicKey,
|
||||
privateKey
|
||||
}: {
|
||||
ciphertext: string;
|
||||
nonce: string;
|
||||
publicKey: string;
|
||||
privateKey: string;
|
||||
}): string => {
|
||||
const plaintext: any = nacl.box.open(
|
||||
util.decodeBase64(ciphertext),
|
||||
util.decodeBase64(nonce),
|
||||
util.decodeBase64(publicKey),
|
||||
util.decodeBase64(privateKey)
|
||||
);
|
||||
|
||||
return util.encodeUTF8(plaintext);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return symmetrically encrypted [plaintext] using [key].
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.plaintext - plaintext to encrypt
|
||||
* @param {String} obj.key - hex key
|
||||
*/
|
||||
const encryptSymmetric = ({
|
||||
plaintext,
|
||||
key
|
||||
}: {
|
||||
plaintext: string;
|
||||
key: string;
|
||||
}) => {
|
||||
const obj = AesGCM.encrypt(plaintext, key);
|
||||
const { ciphertext, iv, tag } = obj;
|
||||
|
||||
return {
|
||||
ciphertext,
|
||||
iv,
|
||||
tag
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Return symmetrically decypted [ciphertext] using [iv], [tag],
|
||||
* and [key].
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.ciphertext - ciphertext to decrypt
|
||||
* @param {String} obj.iv - iv
|
||||
* @param {String} obj.tag - tag
|
||||
* @param {String} obj.key - hex key
|
||||
*
|
||||
*/
|
||||
const decryptSymmetric = ({
|
||||
ciphertext,
|
||||
iv,
|
||||
tag,
|
||||
key
|
||||
}: {
|
||||
ciphertext: string;
|
||||
iv: string;
|
||||
tag: string;
|
||||
key: string;
|
||||
}): string => {
|
||||
const plaintext = AesGCM.decrypt(ciphertext, iv, tag, key);
|
||||
return plaintext;
|
||||
};
|
||||
|
||||
export {
|
||||
generateKeyPair,
|
||||
encryptAsymmetric,
|
||||
decryptAsymmetric,
|
||||
encryptSymmetric,
|
||||
decryptSymmetric
|
||||
};
|
||||
237
backend/src/utils/crypto/index.ts
Normal file
237
backend/src/utils/crypto/index.ts
Normal file
@@ -0,0 +1,237 @@
|
||||
import crypto from 'crypto';
|
||||
import nacl from 'tweetnacl';
|
||||
import util from 'tweetnacl-util';
|
||||
import {
|
||||
IGenerateKeyPairOutput,
|
||||
IEncryptAsymmetricInput,
|
||||
IEncryptAsymmetricOutput,
|
||||
IDecryptAsymmetricInput,
|
||||
IEncryptSymmetricInput,
|
||||
IEncryptSymmetricOutput,
|
||||
IDecryptSymmetricInput
|
||||
} from '../../interfaces/utils';
|
||||
import {
|
||||
BadRequestError,
|
||||
InternalServerError
|
||||
} from '../errors';
|
||||
import {
|
||||
ALGORITHM_AES_256_GCM,
|
||||
BLOCK_SIZE_BYTES_32,
|
||||
BLOCK_SIZE_BYTES_16
|
||||
} from '../../variables';
|
||||
import { validateEncryptionKey } from '../../validation';
|
||||
|
||||
/**
|
||||
* Return new base64, NaCl, public-private key pair.
|
||||
* @returns {Object} obj
|
||||
* @returns {String} obj.publicKey - (base64) NaCl, public key
|
||||
* @returns {String} obj.privateKey - (base64), NaCl, private key
|
||||
*/
|
||||
const generateKeyPair = (): IGenerateKeyPairOutput => {
|
||||
const pair = nacl.box.keyPair();
|
||||
|
||||
return ({
|
||||
publicKey: util.encodeBase64(pair.publicKey),
|
||||
privateKey: util.encodeBase64(pair.secretKey)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return assymmetrically encrypted [plaintext] using [publicKey] where
|
||||
* [publicKey] likely belongs to the recipient.
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.plaintext - plaintext to encrypt
|
||||
* @param {String} obj.publicKey - (base64) Nacl public key of the recipient
|
||||
* @param {String} obj.privateKey - (base64) Nacl private key of the sender (current user)
|
||||
* @returns {Object} obj
|
||||
* @returns {String} obj.ciphertext - (base64) ciphertext
|
||||
* @returns {String} obj.nonce - (base64) nonce
|
||||
*/
|
||||
const encryptAsymmetric = ({
|
||||
plaintext,
|
||||
publicKey,
|
||||
privateKey
|
||||
}: IEncryptAsymmetricInput): IEncryptAsymmetricOutput => {
|
||||
const nonce = nacl.randomBytes(24);
|
||||
const ciphertext = nacl.box(
|
||||
util.decodeUTF8(plaintext),
|
||||
nonce,
|
||||
util.decodeBase64(publicKey),
|
||||
util.decodeBase64(privateKey)
|
||||
);
|
||||
|
||||
return {
|
||||
ciphertext: util.encodeBase64(ciphertext),
|
||||
nonce: util.encodeBase64(nonce)
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Return assymmetrically decrypted [ciphertext] using [privateKey] where
|
||||
* [privateKey] likely belongs to the recipient.
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.ciphertext - ciphertext to decrypt
|
||||
* @param {String} obj.nonce - (base64) nonce
|
||||
* @param {String} obj.publicKey - (base64) public key of the sender
|
||||
* @param {String} obj.privateKey - (base64) private key of the receiver (current user)
|
||||
* @returns {String} plaintext - (utf8) plaintext
|
||||
*/
|
||||
const decryptAsymmetric = ({
|
||||
ciphertext,
|
||||
nonce,
|
||||
publicKey,
|
||||
privateKey
|
||||
}: IDecryptAsymmetricInput): string => {
|
||||
const plaintext: Uint8Array | null = nacl.box.open(
|
||||
util.decodeBase64(ciphertext),
|
||||
util.decodeBase64(nonce),
|
||||
util.decodeBase64(publicKey),
|
||||
util.decodeBase64(privateKey)
|
||||
);
|
||||
|
||||
if (plaintext == null) throw BadRequestError({
|
||||
message: 'Invalid ciphertext or keys'
|
||||
});
|
||||
|
||||
return util.encodeUTF8(plaintext);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return symmetrically encrypted [plaintext] using [key].
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.plaintext - (utf8) plaintext to encrypt
|
||||
* @param {String} obj.key - (base64) 256-bit key
|
||||
* @returns {Object} obj
|
||||
* @returns {String} obj.ciphertext (base64) ciphertext
|
||||
* @returns {String} obj.iv (base64) iv
|
||||
* @returns {String} obj.tag (base64) tag
|
||||
*/
|
||||
const encryptSymmetric = ({
|
||||
plaintext,
|
||||
key
|
||||
}: IEncryptSymmetricInput): IEncryptSymmetricOutput => {
|
||||
validateEncryptionKey(key);
|
||||
|
||||
const iv = crypto.randomBytes(BLOCK_SIZE_BYTES_32);
|
||||
const secretKey = crypto.createSecretKey(key, 'base64');
|
||||
const cipher = crypto.createCipheriv(ALGORITHM_AES_256_GCM, secretKey, iv);
|
||||
|
||||
let ciphertext = cipher.update(plaintext, 'utf8', 'base64');
|
||||
ciphertext += cipher.final('base64');
|
||||
|
||||
return {
|
||||
ciphertext,
|
||||
iv: iv.toString('base64'),
|
||||
tag: cipher.getAuthTag().toString('base64')
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Return symmetrically decrypted [ciphertext] using [iv], [tag],
|
||||
* and [key].
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.ciphertext - ciphertext to decrypt
|
||||
* @param {String} obj.iv - (base64) 256-bit iv
|
||||
* @param {String} obj.tag - (base64) tag
|
||||
* @param {String} obj.key - (base64) 256-bit key
|
||||
* @returns {String} cleartext - the deciphered ciphertext
|
||||
*/
|
||||
const decryptSymmetric = ({
|
||||
ciphertext,
|
||||
iv,
|
||||
tag,
|
||||
key
|
||||
}: IDecryptSymmetricInput): string => {
|
||||
validateEncryptionKey(key);
|
||||
|
||||
const secretKey = crypto.createSecretKey(key, 'base64');
|
||||
|
||||
const decipher = crypto.createDecipheriv(
|
||||
ALGORITHM_AES_256_GCM,
|
||||
secretKey,
|
||||
Buffer.from(iv, 'base64')
|
||||
);
|
||||
|
||||
decipher.setAuthTag(Buffer.from(tag, 'base64'));
|
||||
|
||||
let cleartext = decipher.update(ciphertext, 'base64', 'utf8');
|
||||
cleartext += decipher.final('utf8');
|
||||
|
||||
return cleartext;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return symmetrically encrypted [plaintext] using [key].
|
||||
*
|
||||
* NOTE: THIS FUNCTION SHOULD NOT BE USED FOR ALL FUTURE
|
||||
* ENCRYPTION OPERATIONS UNLESS IT TOUCHES OLD FUNCTIONALITY
|
||||
* THAT USES IT. USE encryptSymmetric() instead
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.plaintext - (utf8) plaintext to encrypt
|
||||
* @param {String} obj.key - (base64) 256-bit key
|
||||
* @returns {Object} obj
|
||||
* @returns {String} obj.ciphertext (base64) ciphertext
|
||||
* @returns {String} obj.iv (base64) iv
|
||||
* @returns {String} obj.tag (base64) tag
|
||||
*/
|
||||
const encryptSymmetric128BitHexKeyUTF8 = ({
|
||||
plaintext,
|
||||
key
|
||||
}: IEncryptSymmetricInput) => {
|
||||
const iv = crypto.randomBytes(BLOCK_SIZE_BYTES_16);
|
||||
const cipher = crypto.createCipheriv(ALGORITHM_AES_256_GCM, key, iv);
|
||||
|
||||
let ciphertext = cipher.update(plaintext, 'utf8', 'base64');
|
||||
ciphertext += cipher.final('base64');
|
||||
|
||||
return {
|
||||
ciphertext,
|
||||
iv: iv.toString('base64'),
|
||||
tag: cipher.getAuthTag().toString('base64')
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Return symmetrically decrypted [ciphertext] using [iv], [tag],
|
||||
* and [key].
|
||||
*
|
||||
* NOTE: THIS FUNCTION SHOULD NOT BE USED FOR ALL FUTURE
|
||||
* DECRYPTION OPERATIONS UNLESS IT TOUCHES OLD FUNCTIONALITY
|
||||
* THAT USES IT. USE decryptSymmetric() instead
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.ciphertext - ciphertext to decrypt
|
||||
* @param {String} obj.iv - (base64) 256-bit iv
|
||||
* @param {String} obj.tag - (base64) tag
|
||||
* @param {String} obj.key - (hex) 128-bit key
|
||||
* @returns {String} cleartext - the deciphered ciphertext
|
||||
*/
|
||||
const decryptSymmetric128BitHexKeyUTF8 = ({
|
||||
ciphertext,
|
||||
iv,
|
||||
tag,
|
||||
key
|
||||
}: IDecryptSymmetricInput) => {
|
||||
const decipher = crypto.createDecipheriv(
|
||||
ALGORITHM_AES_256_GCM,
|
||||
key,
|
||||
Buffer.from(iv, 'base64')
|
||||
);
|
||||
|
||||
decipher.setAuthTag(Buffer.from(tag, 'base64'));
|
||||
|
||||
let cleartext = decipher.update(ciphertext, 'base64', 'utf8');
|
||||
cleartext += decipher.final('utf8');
|
||||
|
||||
return cleartext;
|
||||
}
|
||||
|
||||
export {
|
||||
generateKeyPair,
|
||||
encryptAsymmetric,
|
||||
decryptAsymmetric,
|
||||
encryptSymmetric,
|
||||
decryptSymmetric,
|
||||
encryptSymmetric128BitHexKeyUTF8,
|
||||
decryptSymmetric128BitHexKeyUTF8
|
||||
};
|
||||
210
backend/src/utils/setup/backfill.ts
Normal file
210
backend/src/utils/setup/backfill.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
import crypto from 'crypto';
|
||||
import { encryptSymmetric128BitHexKeyUTF8 } from '../crypto';
|
||||
import { EESecretService } from '../../ee/services';
|
||||
import { SecretVersion } from '../../ee/models';
|
||||
import {
|
||||
Secret,
|
||||
ISecret,
|
||||
SecretBlindIndexData,
|
||||
Workspace,
|
||||
Bot,
|
||||
BackupPrivateKey,
|
||||
IntegrationAuth
|
||||
} from '../../models';
|
||||
import { getEncryptionKey, getRootEncryptionKey } from '../../config';
|
||||
import {
|
||||
ALGORITHM_AES_256_GCM,
|
||||
ENCODING_SCHEME_UTF8
|
||||
} from '../../variables';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const backfillSecretVersions = async () => {
|
||||
await Secret.updateMany(
|
||||
{ version: { $exists: false } },
|
||||
{ $set: { version: 1 } }
|
||||
);
|
||||
|
||||
const unversionedSecrets: ISecret[] = await Secret.aggregate([
|
||||
{
|
||||
$lookup: {
|
||||
from: "secretversions",
|
||||
localField: "_id",
|
||||
foreignField: "secret",
|
||||
as: "versions",
|
||||
},
|
||||
},
|
||||
{
|
||||
$match: {
|
||||
versions: { $size: 0 },
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
if (unversionedSecrets.length > 0) {
|
||||
await EESecretService.addSecretVersions({
|
||||
secretVersions: unversionedSecrets.map(
|
||||
(s, idx) =>
|
||||
new SecretVersion({
|
||||
...s,
|
||||
secret: s._id,
|
||||
version: s.version ? s.version : 1,
|
||||
isDeleted: false,
|
||||
workspace: s.workspace,
|
||||
environment: s.environment,
|
||||
})
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const backfillSecretBlindIndexData = async () => {
|
||||
const workspaceIdsBlindIndexed = await SecretBlindIndexData.distinct('workspace');
|
||||
const workspaceIdsToBlindIndex = await Workspace.distinct('_id', {
|
||||
_id: {
|
||||
$nin: workspaceIdsBlindIndexed
|
||||
}
|
||||
});
|
||||
|
||||
const secretBlindIndexDataToInsert = await Promise.all(
|
||||
workspaceIdsToBlindIndex.map(async (workspaceToBlindIndex) => {
|
||||
const salt = crypto.randomBytes(16).toString('base64');
|
||||
|
||||
const {
|
||||
ciphertext: encryptedSaltCiphertext,
|
||||
iv: saltIV,
|
||||
tag: saltTag
|
||||
} = encryptSymmetric128BitHexKeyUTF8({
|
||||
plaintext: salt,
|
||||
key: await getEncryptionKey()
|
||||
});
|
||||
|
||||
const secretBlindIndexData = new SecretBlindIndexData({
|
||||
workspace: workspaceToBlindIndex,
|
||||
encryptedSaltCiphertext,
|
||||
saltIV,
|
||||
saltTag
|
||||
})
|
||||
|
||||
return secretBlindIndexData;
|
||||
})
|
||||
);
|
||||
|
||||
if (secretBlindIndexDataToInsert.length > 0) {
|
||||
await SecretBlindIndexData.insertMany(secretBlindIndexDataToInsert);
|
||||
}
|
||||
}
|
||||
|
||||
export const backfillEncryptionMetadata = async () => {
|
||||
|
||||
// backfill bot encryption metadata
|
||||
await Bot.updateMany(
|
||||
{
|
||||
algorithm: {
|
||||
$exists: false
|
||||
},
|
||||
keySize: {
|
||||
$exists: false
|
||||
},
|
||||
keyEncoding: {
|
||||
$exists: false
|
||||
}
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
algorithm: ALGORITHM_AES_256_GCM,
|
||||
keySize: 256,
|
||||
keyEncoding: ENCODING_SCHEME_UTF8
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// backfill secret blind index encryption metadata
|
||||
await SecretBlindIndexData.updateMany(
|
||||
{
|
||||
algorithm: {
|
||||
$exists: false
|
||||
},
|
||||
keySize: {
|
||||
$exists: false
|
||||
},
|
||||
keyEncoding: {
|
||||
$exists: false
|
||||
}
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
algorithm: ALGORITHM_AES_256_GCM,
|
||||
keySize: 256,
|
||||
keyEncoding: ENCODING_SCHEME_UTF8
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// backfill backup private key encryption metadata
|
||||
await BackupPrivateKey.updateMany(
|
||||
{
|
||||
algorithm: {
|
||||
$exists: false
|
||||
},
|
||||
keySize: {
|
||||
$exists: false
|
||||
},
|
||||
keyEncoding: {
|
||||
$exists: false
|
||||
}
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
algorithm: ALGORITHM_AES_256_GCM,
|
||||
keySize: 256,
|
||||
keyEncoding: ENCODING_SCHEME_UTF8
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// backfill integration auth encryption metadata
|
||||
await IntegrationAuth.updateMany(
|
||||
{
|
||||
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
algorithm: ALGORITHM_AES_256_GCM,
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// TODO: blind indices
|
||||
// TODO: secret versions and snapshots etc.
|
||||
|
||||
// TODO: re-encrypt keys logic
|
||||
// TODO: how do you handle different parts of the software
|
||||
// encrypting under different schemes?
|
||||
|
||||
// const encryptionKey = await getEncryptionKey();
|
||||
// const rootEncryptionKey = await getRootEncryptionKey();
|
||||
// console.log('rootEncryptionKey: ', rootEncryptionKey);
|
||||
|
||||
// if (encryptionKey && rootEncryptionKey) {
|
||||
// // case: both the old encryption key and new encryption key are present
|
||||
// // -> perform migration if needed
|
||||
// console.log('rootEncryptionKey is defined');
|
||||
|
||||
// const bots = await Bot.find({
|
||||
// algorithm: ALGORITHM_AES_256_GCM,
|
||||
// keySize: 256,
|
||||
// keyEncoding: ENCODING_SCHEME_UTF8
|
||||
// }, 'encryptedPrivateKey iv tag');
|
||||
|
||||
// if (bots.length > 0) {
|
||||
// // TODO: unencrypt and re-encrypt
|
||||
// // TODO: unencrypt and re-encrypt blind-indices
|
||||
// // probably then need to move this function
|
||||
|
||||
// console.log('bots: ', bots);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
51
backend/src/utils/setup/index.ts
Normal file
51
backend/src/utils/setup/index.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { DatabaseService } from '../../services';
|
||||
import { setTransporter } from '../../helpers/nodemailer';
|
||||
import { initSmtp } from '../../services/smtp';
|
||||
import { createTestUserForDevelopment } from '../addDevelopmentUser'
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { patchRouterParam } = require('../patchAsyncRoutes');
|
||||
import {
|
||||
backfillSecretVersions,
|
||||
backfillSecretBlindIndexData,
|
||||
backfillEncryptionMetadata
|
||||
} from './backfill';
|
||||
import {
|
||||
getNodeEnv,
|
||||
getMongoURL,
|
||||
getSentryDSN
|
||||
} from '../../config';
|
||||
|
||||
/**
|
||||
* Prepare Infisical upon startup. This includes tasks like:
|
||||
* - Initializing SMTP configuration
|
||||
* - Initializing the database connection
|
||||
* - Initializing Sentry
|
||||
* - Backfilling data
|
||||
*/
|
||||
export const setup = async () => {
|
||||
// initializing SMTP configuration
|
||||
setTransporter(await initSmtp());
|
||||
|
||||
// initializing the database connection
|
||||
await DatabaseService.initDatabase(await getMongoURL());
|
||||
|
||||
// backfilling data
|
||||
await backfillSecretVersions();
|
||||
await backfillSecretBlindIndexData();
|
||||
await backfillEncryptionMetadata();
|
||||
|
||||
// initializing Sentry
|
||||
if ((await getNodeEnv()) !== 'development') {
|
||||
Sentry.init({
|
||||
dsn: await getSentryDSN(),
|
||||
tracesSampleRate: 1.0,
|
||||
debug: await getNodeEnv() === 'production' ? false : true,
|
||||
environment: await getNodeEnv()
|
||||
});
|
||||
}
|
||||
|
||||
patchRouterParam();
|
||||
await createTestUserForDevelopment();
|
||||
}
|
||||
|
||||
21
backend/src/validation/config.ts
Normal file
21
backend/src/validation/config.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { InternalServerError } from "../utils/errors";
|
||||
|
||||
/**
|
||||
* Validate that the encryption key [encryptionKey] is in base64 format and 256-bit
|
||||
* @param {String} encryptionKey - the encryption key to validate
|
||||
*/
|
||||
export const validateEncryptionKey = (encryptionKey: string): Buffer => {
|
||||
|
||||
const keyBuffer = Buffer.from(encryptionKey, 'base64')
|
||||
const decoded = keyBuffer.toString('base64');
|
||||
|
||||
if (decoded !== encryptionKey) throw InternalServerError({
|
||||
message: 'Failed to validate the format of the encryption key. Please check that it is in base64 format.'
|
||||
});
|
||||
|
||||
if (keyBuffer.length !== 32) throw InternalServerError({
|
||||
message: 'Failed to validate that the encryption key is 256-bit. Please check that it is 256-bit.'
|
||||
});
|
||||
|
||||
return keyBuffer;
|
||||
};
|
||||
1
backend/src/validation/index.ts
Normal file
1
backend/src/validation/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './config';
|
||||
@@ -1,15 +1,6 @@
|
||||
const ACTION_LOGIN = 'login';
|
||||
const ACTION_LOGOUT = 'logout';
|
||||
const ACTION_ADD_SECRETS = 'addSecrets';
|
||||
const ACTION_DELETE_SECRETS = 'deleteSecrets';
|
||||
const ACTION_UPDATE_SECRETS = 'updateSecrets';
|
||||
const ACTION_READ_SECRETS = 'readSecrets';
|
||||
|
||||
export {
|
||||
ACTION_LOGIN,
|
||||
ACTION_LOGOUT,
|
||||
ACTION_ADD_SECRETS,
|
||||
ACTION_DELETE_SECRETS,
|
||||
ACTION_UPDATE_SECRETS,
|
||||
ACTION_READ_SECRETS
|
||||
}
|
||||
export const ACTION_LOGIN = 'login';
|
||||
export const ACTION_LOGOUT = 'logout';
|
||||
export const ACTION_ADD_SECRETS = 'addSecrets';
|
||||
export const ACTION_DELETE_SECRETS = 'deleteSecrets';
|
||||
export const ACTION_UPDATE_SECRETS = 'updateSecrets';
|
||||
export const ACTION_READ_SECRETS = 'readSecrets';
|
||||
@@ -1,11 +1,4 @@
|
||||
const AUTH_MODE_JWT = 'jwt';
|
||||
const AUTH_MODE_SERVICE_ACCOUNT = 'serviceAccount';
|
||||
const AUTH_MODE_SERVICE_TOKEN = 'serviceToken';
|
||||
const AUTH_MODE_API_KEY = 'apiKey'; // TODO: deprecate
|
||||
|
||||
export {
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_API_KEY
|
||||
}
|
||||
export const AUTH_MODE_JWT = 'jwt';
|
||||
export const AUTH_MODE_SERVICE_ACCOUNT = 'serviceAccount';
|
||||
export const AUTH_MODE_SERVICE_TOKEN = 'serviceToken';
|
||||
export const AUTH_MODE_API_KEY = 'apiKey'; // TODO: deprecate
|
||||
7
backend/src/variables/crypto.ts
Normal file
7
backend/src/variables/crypto.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export const ALGORITHM_AES_256_GCM = 'aes-256-gcm';
|
||||
export const BLOCK_SIZE_BYTES_32 = 32;
|
||||
export const BLOCK_SIZE_BYTES_16 = 16;
|
||||
|
||||
export const ENCODING_SCHEME_UTF8 = 'utf8';
|
||||
export const ENCODING_SCHEME_HEX = 'hex';
|
||||
export const ENCODING_SCHEME_BASE64 = 'base64';
|
||||
@@ -1,14 +1,6 @@
|
||||
// environments
|
||||
const ENV_DEV = 'dev';
|
||||
const ENV_TESTING = 'test';
|
||||
const ENV_STAGING = 'staging';
|
||||
const ENV_PROD = 'prod';
|
||||
const ENV_SET = new Set([ENV_DEV, ENV_TESTING, ENV_STAGING, ENV_PROD]);
|
||||
|
||||
export {
|
||||
ENV_DEV,
|
||||
ENV_TESTING,
|
||||
ENV_STAGING,
|
||||
ENV_PROD,
|
||||
ENV_SET
|
||||
}
|
||||
export const ENV_DEV = 'dev';
|
||||
export const ENV_TESTING = 'test';
|
||||
export const ENV_STAGING = 'staging';
|
||||
export const ENV_PROD = 'prod';
|
||||
export const ENV_SET = new Set([ENV_DEV, ENV_TESTING, ENV_STAGING, ENV_PROD]);
|
||||
@@ -1,7 +1,2 @@
|
||||
const EVENT_PUSH_SECRETS = 'pushSecrets';
|
||||
const EVENT_PULL_SECRETS = 'pullSecrets';
|
||||
|
||||
export {
|
||||
EVENT_PUSH_SECRETS,
|
||||
EVENT_PULL_SECRETS
|
||||
}
|
||||
export const EVENT_PUSH_SECRETS = 'pushSecrets';
|
||||
export const EVENT_PULL_SECRETS = 'pullSecrets';
|
||||
@@ -1,152 +1,13 @@
|
||||
import {
|
||||
ENV_DEV,
|
||||
ENV_TESTING,
|
||||
ENV_STAGING,
|
||||
ENV_PROD,
|
||||
ENV_SET,
|
||||
} from "./environment";
|
||||
import {
|
||||
INTEGRATION_AZURE_KEY_VAULT,
|
||||
INTEGRATION_AWS_PARAMETER_STORE,
|
||||
INTEGRATION_AWS_SECRET_MANAGER,
|
||||
INTEGRATION_HEROKU,
|
||||
INTEGRATION_VERCEL,
|
||||
INTEGRATION_NETLIFY,
|
||||
INTEGRATION_GITHUB,
|
||||
INTEGRATION_GITLAB,
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_RAILWAY,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
INTEGRATION_SUPABASE,
|
||||
INTEGRATION_SET,
|
||||
INTEGRATION_OAUTH2,
|
||||
INTEGRATION_AZURE_TOKEN_URL,
|
||||
INTEGRATION_HEROKU_TOKEN_URL,
|
||||
INTEGRATION_VERCEL_TOKEN_URL,
|
||||
INTEGRATION_NETLIFY_TOKEN_URL,
|
||||
INTEGRATION_GITHUB_TOKEN_URL,
|
||||
INTEGRATION_GITLAB_TOKEN_URL,
|
||||
INTEGRATION_HEROKU_API_URL,
|
||||
INTEGRATION_GITLAB_API_URL,
|
||||
INTEGRATION_VERCEL_API_URL,
|
||||
INTEGRATION_NETLIFY_API_URL,
|
||||
INTEGRATION_RENDER_API_URL,
|
||||
INTEGRATION_RAILWAY_API_URL,
|
||||
INTEGRATION_FLYIO_API_URL,
|
||||
INTEGRATION_CIRCLECI_API_URL,
|
||||
INTEGRATION_TRAVISCI_API_URL,
|
||||
INTEGRATION_SUPABASE_API_URL,
|
||||
getIntegrationOptions
|
||||
} from "./integration";
|
||||
import { OWNER, ADMIN, MEMBER, INVITED, ACCEPTED } from "./organization";
|
||||
import { SECRET_SHARED, SECRET_PERSONAL } from "./secret";
|
||||
import { EVENT_PUSH_SECRETS, EVENT_PULL_SECRETS } from "./event";
|
||||
import {
|
||||
ACTION_LOGIN,
|
||||
ACTION_LOGOUT,
|
||||
ACTION_ADD_SECRETS,
|
||||
ACTION_UPDATE_SECRETS,
|
||||
ACTION_DELETE_SECRETS,
|
||||
ACTION_READ_SECRETS
|
||||
} from './action';
|
||||
import {
|
||||
SMTP_HOST_SENDGRID,
|
||||
SMTP_HOST_MAILGUN,
|
||||
SMTP_HOST_SOCKETLABS,
|
||||
SMTP_HOST_ZOHOMAIL
|
||||
} from './smtp';
|
||||
import { PLAN_STARTER, PLAN_PRO } from './stripe';
|
||||
import {
|
||||
MFA_METHOD_EMAIL
|
||||
} from './user';
|
||||
import {
|
||||
TOKEN_EMAIL_CONFIRMATION,
|
||||
TOKEN_EMAIL_MFA,
|
||||
TOKEN_EMAIL_ORG_INVITATION,
|
||||
TOKEN_EMAIL_PASSWORD_RESET
|
||||
} from './token';
|
||||
import {
|
||||
PERMISSION_READ_SECRETS,
|
||||
PERMISSION_WRITE_SECRETS
|
||||
} from './permission';
|
||||
import {
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_API_KEY
|
||||
} from './authentication';
|
||||
|
||||
export {
|
||||
OWNER,
|
||||
ADMIN,
|
||||
MEMBER,
|
||||
INVITED,
|
||||
ACCEPTED,
|
||||
SECRET_SHARED,
|
||||
SECRET_PERSONAL,
|
||||
ENV_DEV,
|
||||
ENV_TESTING,
|
||||
ENV_STAGING,
|
||||
ENV_PROD,
|
||||
ENV_SET,
|
||||
INTEGRATION_AZURE_KEY_VAULT,
|
||||
INTEGRATION_AWS_PARAMETER_STORE,
|
||||
INTEGRATION_AWS_SECRET_MANAGER,
|
||||
INTEGRATION_HEROKU,
|
||||
INTEGRATION_VERCEL,
|
||||
INTEGRATION_NETLIFY,
|
||||
INTEGRATION_GITHUB,
|
||||
INTEGRATION_GITLAB,
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_RAILWAY,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
INTEGRATION_SUPABASE,
|
||||
INTEGRATION_SET,
|
||||
INTEGRATION_OAUTH2,
|
||||
INTEGRATION_AZURE_TOKEN_URL,
|
||||
INTEGRATION_HEROKU_TOKEN_URL,
|
||||
INTEGRATION_VERCEL_TOKEN_URL,
|
||||
INTEGRATION_NETLIFY_TOKEN_URL,
|
||||
INTEGRATION_GITHUB_TOKEN_URL,
|
||||
INTEGRATION_GITLAB_TOKEN_URL,
|
||||
INTEGRATION_HEROKU_API_URL,
|
||||
INTEGRATION_GITLAB_API_URL,
|
||||
INTEGRATION_VERCEL_API_URL,
|
||||
INTEGRATION_NETLIFY_API_URL,
|
||||
INTEGRATION_RENDER_API_URL,
|
||||
INTEGRATION_RAILWAY_API_URL,
|
||||
INTEGRATION_FLYIO_API_URL,
|
||||
INTEGRATION_CIRCLECI_API_URL,
|
||||
INTEGRATION_TRAVISCI_API_URL,
|
||||
INTEGRATION_SUPABASE_API_URL,
|
||||
EVENT_PUSH_SECRETS,
|
||||
EVENT_PULL_SECRETS,
|
||||
ACTION_LOGIN,
|
||||
ACTION_LOGOUT,
|
||||
ACTION_ADD_SECRETS,
|
||||
ACTION_UPDATE_SECRETS,
|
||||
ACTION_DELETE_SECRETS,
|
||||
ACTION_READ_SECRETS,
|
||||
PERMISSION_READ_SECRETS,
|
||||
PERMISSION_WRITE_SECRETS,
|
||||
getIntegrationOptions,
|
||||
SMTP_HOST_SENDGRID,
|
||||
SMTP_HOST_MAILGUN,
|
||||
SMTP_HOST_SOCKETLABS,
|
||||
SMTP_HOST_ZOHOMAIL,
|
||||
PLAN_STARTER,
|
||||
PLAN_PRO,
|
||||
MFA_METHOD_EMAIL,
|
||||
TOKEN_EMAIL_CONFIRMATION,
|
||||
TOKEN_EMAIL_MFA,
|
||||
TOKEN_EMAIL_ORG_INVITATION,
|
||||
TOKEN_EMAIL_PASSWORD_RESET,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_API_KEY
|
||||
};
|
||||
export * from './action';
|
||||
export * from './authentication';
|
||||
export * from './crypto';
|
||||
export * from './environment';
|
||||
export * from './event';
|
||||
export * from './integration';
|
||||
export * from './organization';
|
||||
export * from './permission';
|
||||
export * from './secret';
|
||||
export * from './smtp';
|
||||
export * from './stripe';
|
||||
export * from './token';
|
||||
export * from './user';
|
||||
@@ -8,21 +8,21 @@ import {
|
||||
} from '../config';
|
||||
|
||||
// integrations
|
||||
const INTEGRATION_AZURE_KEY_VAULT = 'azure-key-vault';
|
||||
const INTEGRATION_AWS_PARAMETER_STORE = 'aws-parameter-store';
|
||||
const INTEGRATION_AWS_SECRET_MANAGER = 'aws-secret-manager';
|
||||
const INTEGRATION_HEROKU = "heroku";
|
||||
const INTEGRATION_VERCEL = "vercel";
|
||||
const INTEGRATION_NETLIFY = "netlify";
|
||||
const INTEGRATION_GITHUB = "github";
|
||||
const INTEGRATION_GITLAB = "gitlab";
|
||||
const INTEGRATION_RENDER = "render";
|
||||
const INTEGRATION_RAILWAY = "railway";
|
||||
const INTEGRATION_FLYIO = "flyio";
|
||||
const INTEGRATION_CIRCLECI = "circleci";
|
||||
const INTEGRATION_TRAVISCI = "travisci";
|
||||
const INTEGRATION_SUPABASE = 'supabase';
|
||||
const INTEGRATION_SET = new Set([
|
||||
export const INTEGRATION_AZURE_KEY_VAULT = 'azure-key-vault';
|
||||
export const INTEGRATION_AWS_PARAMETER_STORE = 'aws-parameter-store';
|
||||
export const INTEGRATION_AWS_SECRET_MANAGER = 'aws-secret-manager';
|
||||
export const INTEGRATION_HEROKU = "heroku";
|
||||
export const INTEGRATION_VERCEL = "vercel";
|
||||
export const INTEGRATION_NETLIFY = "netlify";
|
||||
export const INTEGRATION_GITHUB = "github";
|
||||
export const INTEGRATION_GITLAB = "gitlab";
|
||||
export const INTEGRATION_RENDER = "render";
|
||||
export const INTEGRATION_RAILWAY = "railway";
|
||||
export const INTEGRATION_FLYIO = "flyio";
|
||||
export const INTEGRATION_CIRCLECI = "circleci";
|
||||
export const INTEGRATION_TRAVISCI = "travisci";
|
||||
export const INTEGRATION_SUPABASE = 'supabase';
|
||||
export const INTEGRATION_SET = new Set([
|
||||
INTEGRATION_AZURE_KEY_VAULT,
|
||||
INTEGRATION_HEROKU,
|
||||
INTEGRATION_VERCEL,
|
||||
@@ -37,31 +37,31 @@ const INTEGRATION_SET = new Set([
|
||||
]);
|
||||
|
||||
// integration types
|
||||
const INTEGRATION_OAUTH2 = "oauth2";
|
||||
export const INTEGRATION_OAUTH2 = "oauth2";
|
||||
|
||||
// integration oauth endpoints
|
||||
const INTEGRATION_AZURE_TOKEN_URL = `https://login.microsoftonline.com/common/oauth2/v2.0/token`;
|
||||
const INTEGRATION_HEROKU_TOKEN_URL = 'https://id.heroku.com/oauth/token';
|
||||
const INTEGRATION_VERCEL_TOKEN_URL =
|
||||
export const INTEGRATION_AZURE_TOKEN_URL = `https://login.microsoftonline.com/common/oauth2/v2.0/token`;
|
||||
export const INTEGRATION_HEROKU_TOKEN_URL = 'https://id.heroku.com/oauth/token';
|
||||
export const INTEGRATION_VERCEL_TOKEN_URL =
|
||||
"https://api.vercel.com/v2/oauth/access_token";
|
||||
const INTEGRATION_NETLIFY_TOKEN_URL = "https://api.netlify.com/oauth/token";
|
||||
const INTEGRATION_GITHUB_TOKEN_URL =
|
||||
export const INTEGRATION_NETLIFY_TOKEN_URL = "https://api.netlify.com/oauth/token";
|
||||
export const INTEGRATION_GITHUB_TOKEN_URL =
|
||||
"https://github.com/login/oauth/access_token";
|
||||
const INTEGRATION_GITLAB_TOKEN_URL = "https://gitlab.com/oauth/token";
|
||||
export const INTEGRATION_GITLAB_TOKEN_URL = "https://gitlab.com/oauth/token";
|
||||
|
||||
// integration apps endpoints
|
||||
const INTEGRATION_HEROKU_API_URL = "https://api.heroku.com";
|
||||
const INTEGRATION_GITLAB_API_URL = "https://gitlab.com/api";
|
||||
const INTEGRATION_VERCEL_API_URL = "https://api.vercel.com";
|
||||
const INTEGRATION_NETLIFY_API_URL = "https://api.netlify.com";
|
||||
const INTEGRATION_RENDER_API_URL = "https://api.render.com";
|
||||
const INTEGRATION_RAILWAY_API_URL = "https://backboard.railway.app/graphql/v2";
|
||||
const INTEGRATION_FLYIO_API_URL = "https://api.fly.io/graphql";
|
||||
const INTEGRATION_CIRCLECI_API_URL = "https://circleci.com/api";
|
||||
const INTEGRATION_TRAVISCI_API_URL = "https://api.travis-ci.com";
|
||||
const INTEGRATION_SUPABASE_API_URL = 'https://api.supabase.com';
|
||||
export const INTEGRATION_HEROKU_API_URL = "https://api.heroku.com";
|
||||
export const INTEGRATION_GITLAB_API_URL = "https://gitlab.com/api";
|
||||
export const INTEGRATION_VERCEL_API_URL = "https://api.vercel.com";
|
||||
export const INTEGRATION_NETLIFY_API_URL = "https://api.netlify.com";
|
||||
export const INTEGRATION_RENDER_API_URL = "https://api.render.com";
|
||||
export const INTEGRATION_RAILWAY_API_URL = "https://backboard.railway.app/graphql/v2";
|
||||
export const INTEGRATION_FLYIO_API_URL = "https://api.fly.io/graphql";
|
||||
export const INTEGRATION_CIRCLECI_API_URL = "https://circleci.com/api";
|
||||
export const INTEGRATION_TRAVISCI_API_URL = "https://api.travis-ci.com";
|
||||
export const INTEGRATION_SUPABASE_API_URL = 'https://api.supabase.com';
|
||||
|
||||
const getIntegrationOptions = async () => {
|
||||
export const getIntegrationOptions = async () => {
|
||||
const INTEGRATION_OPTIONS = [
|
||||
{
|
||||
name: 'Heroku',
|
||||
@@ -202,41 +202,4 @@ const getIntegrationOptions = async () => {
|
||||
]
|
||||
|
||||
return INTEGRATION_OPTIONS;
|
||||
}
|
||||
|
||||
|
||||
export {
|
||||
INTEGRATION_AZURE_KEY_VAULT,
|
||||
INTEGRATION_AWS_PARAMETER_STORE,
|
||||
INTEGRATION_AWS_SECRET_MANAGER,
|
||||
INTEGRATION_HEROKU,
|
||||
INTEGRATION_VERCEL,
|
||||
INTEGRATION_NETLIFY,
|
||||
INTEGRATION_GITHUB,
|
||||
INTEGRATION_GITLAB,
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_RAILWAY,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
INTEGRATION_SUPABASE,
|
||||
INTEGRATION_SET,
|
||||
INTEGRATION_OAUTH2,
|
||||
INTEGRATION_AZURE_TOKEN_URL,
|
||||
INTEGRATION_HEROKU_TOKEN_URL,
|
||||
INTEGRATION_VERCEL_TOKEN_URL,
|
||||
INTEGRATION_NETLIFY_TOKEN_URL,
|
||||
INTEGRATION_GITHUB_TOKEN_URL,
|
||||
INTEGRATION_GITLAB_API_URL,
|
||||
INTEGRATION_HEROKU_API_URL,
|
||||
INTEGRATION_GITLAB_TOKEN_URL,
|
||||
INTEGRATION_VERCEL_API_URL,
|
||||
INTEGRATION_NETLIFY_API_URL,
|
||||
INTEGRATION_RENDER_API_URL,
|
||||
INTEGRATION_RAILWAY_API_URL,
|
||||
INTEGRATION_FLYIO_API_URL,
|
||||
INTEGRATION_CIRCLECI_API_URL,
|
||||
INTEGRATION_TRAVISCI_API_URL,
|
||||
INTEGRATION_SUPABASE_API_URL,
|
||||
getIntegrationOptions
|
||||
};
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
// membership roles
|
||||
const OWNER = "owner";
|
||||
const ADMIN = "admin";
|
||||
const MEMBER = "member";
|
||||
export const OWNER = "owner";
|
||||
export const ADMIN = "admin";
|
||||
export const MEMBER = "member";
|
||||
|
||||
// membership statuses
|
||||
const INVITED = "invited";
|
||||
export const INVITED = "invited";
|
||||
|
||||
// -- organization
|
||||
const ACCEPTED = "accepted";
|
||||
|
||||
export { OWNER, ADMIN, MEMBER, INVITED, ACCEPTED };
|
||||
export const ACCEPTED = "accepted";
|
||||
@@ -1,7 +1,2 @@
|
||||
const PERMISSION_READ_SECRETS = 'read';
|
||||
const PERMISSION_WRITE_SECRETS = 'write';
|
||||
|
||||
export {
|
||||
PERMISSION_READ_SECRETS,
|
||||
PERMISSION_WRITE_SECRETS
|
||||
}
|
||||
export const PERMISSION_READ_SECRETS = 'read';
|
||||
export const PERMISSION_WRITE_SECRETS = 'write';
|
||||
@@ -1,8 +1,3 @@
|
||||
// secrets
|
||||
const SECRET_SHARED = 'shared';
|
||||
const SECRET_PERSONAL = 'personal';
|
||||
|
||||
export {
|
||||
SECRET_SHARED,
|
||||
SECRET_PERSONAL
|
||||
}
|
||||
export const SECRET_SHARED = 'shared';
|
||||
export const SECRET_PERSONAL = 'personal';
|
||||
@@ -1,11 +1,4 @@
|
||||
const SMTP_HOST_SENDGRID = 'smtp.sendgrid.net';
|
||||
const SMTP_HOST_MAILGUN = 'smtp.mailgun.org';
|
||||
const SMTP_HOST_SOCKETLABS = 'smtp.socketlabs.com';
|
||||
const SMTP_HOST_ZOHOMAIL = 'smtp.zoho.com';
|
||||
|
||||
export {
|
||||
SMTP_HOST_SENDGRID,
|
||||
SMTP_HOST_MAILGUN,
|
||||
SMTP_HOST_SOCKETLABS,
|
||||
SMTP_HOST_ZOHOMAIL
|
||||
}
|
||||
export const SMTP_HOST_SENDGRID = 'smtp.sendgrid.net';
|
||||
export const SMTP_HOST_MAILGUN = 'smtp.mailgun.org';
|
||||
export const SMTP_HOST_SOCKETLABS = 'smtp.socketlabs.com';
|
||||
export const SMTP_HOST_ZOHOMAIL = 'smtp.zoho.com';
|
||||
@@ -1,7 +1,2 @@
|
||||
const PLAN_STARTER = 'starter';
|
||||
const PLAN_PRO = 'pro';
|
||||
|
||||
export {
|
||||
PLAN_STARTER,
|
||||
PLAN_PRO
|
||||
}
|
||||
export const PLAN_STARTER = 'starter';
|
||||
export const PLAN_PRO = 'pro';
|
||||
@@ -1,11 +1,4 @@
|
||||
const TOKEN_EMAIL_CONFIRMATION = 'emailConfirmation';
|
||||
const TOKEN_EMAIL_MFA = 'emailMfa';
|
||||
const TOKEN_EMAIL_ORG_INVITATION = 'organizationInvitation';
|
||||
const TOKEN_EMAIL_PASSWORD_RESET = 'passwordReset';
|
||||
|
||||
export {
|
||||
TOKEN_EMAIL_CONFIRMATION,
|
||||
TOKEN_EMAIL_MFA,
|
||||
TOKEN_EMAIL_ORG_INVITATION,
|
||||
TOKEN_EMAIL_PASSWORD_RESET
|
||||
}
|
||||
export const TOKEN_EMAIL_CONFIRMATION = 'emailConfirmation';
|
||||
export const TOKEN_EMAIL_MFA = 'emailMfa';
|
||||
export const TOKEN_EMAIL_ORG_INVITATION = 'organizationInvitation';
|
||||
export const TOKEN_EMAIL_PASSWORD_RESET = 'passwordReset';
|
||||
@@ -1,5 +1 @@
|
||||
const MFA_METHOD_EMAIL = 'email';
|
||||
|
||||
export {
|
||||
MFA_METHOD_EMAIL
|
||||
}
|
||||
export const MFA_METHOD_EMAIL = 'email';
|
||||
@@ -10,7 +10,9 @@ const jsrp = require('jsrp');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const axios = require('axios');
|
||||
import { plainTextWorkspaceKey, testWorkspaceId } from "../../src/utils/addDevelopmentUser";
|
||||
import { encryptSymmetric } from "../../src/utils/crypto";
|
||||
import {
|
||||
encryptSymmetric128BitHexKeyUTF8
|
||||
} from '../../src/utils/crypto';
|
||||
|
||||
interface TokenData {
|
||||
token: string;
|
||||
@@ -64,7 +66,7 @@ export const getJWTFromTestUser = (): Promise<TokenData> => {
|
||||
export const getServiceTokenFromTestUser = async () => {
|
||||
const loggedInUserDetails = await getJWTFromTestUser()
|
||||
const randomBytes = crypto.randomBytes(16).toString('hex');
|
||||
const { ciphertext, iv, tag } = encryptSymmetric({
|
||||
const { ciphertext, iv, tag } = encryptSymmetric128BitHexKeyUTF8({
|
||||
plaintext: plainTextWorkspaceKey,
|
||||
key: randomBytes,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user