Begin frontend for blinded indices

This commit is contained in:
Tuan Dang
2023-04-15 17:39:30 +03:00
parent fcb677d990
commit d9afe90885
11 changed files with 186 additions and 29 deletions
+35 -16
View File
@@ -4,6 +4,8 @@ import {
Secret Secret
} from '../../models'; } from '../../models';
import crypto from 'crypto'; import crypto from 'crypto';
import { SecretService } from '../../services';
// TODO: modularize argon2id // TODO: modularize argon2id
import * as argon2 from 'argon2'; import * as argon2 from 'argon2';
@@ -50,30 +52,47 @@ export const createSecret = async (req: Request, res: Response) => {
workspaceId, workspaceId,
environment, environment,
value, value,
type type,
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
secretValueCiphertext,
secretValueIV,
secretValueTag
} = req.body; } = req.body;
// use workspace salt const secretBlindIndex = await SecretService.createSecretBlindIndex({
const randomBytes = crypto.randomBytes(16); secretName,
workspaceId: new Types.ObjectId(workspaceId)
});
// generate blind index // // use workspace salt
// TODO 1: abstract away into create blind index function // const randomBytes = crypto.randomBytes(16);
// TODO 2: create a get blind index function
const secretBlindIndex = (await argon2.hash(secretName, { // // generate blind index
type: argon2.argon2id, // // TODO 1: abstract away into create blind index function
salt: randomBytes, // // TODO 2: create a get blind index function
saltLength: 16, // default 16 bytes // const secretBlindIndex = (await argon2.hash(secretName, {
memoryCost: 65536, // default pool of 64 MiB per thread. // type: argon2.argon2id,
hashLength: 32, // salt: randomBytes,
parallelism: 1, // saltLength: 16, // default 16 bytes
raw: true // memoryCost: 65536, // default pool of 64 MiB per thread.
})).toString('base64'); // hashLength: 32,
// parallelism: 1,
// raw: true
// })).toString('base64');
// const secret = await new Secret({ // const secret = await new Secret({
// workspace: new Types.ObjectId(workspaceId), // workspace: new Types.ObjectId(workspaceId),
// environment, // environment,
// type, // type,
// secretBlindIndex // secretBlindIndex,
// secretKeyCiphertext,
// secretKeyIV,
// secretKeyTag,
// secretValueCiphertext,
// secretValueIV,
// secretValueTag
// }).save(); // }).save();
return res.status(200).send({ return res.status(200).send({
+73 -2
View File
@@ -7,7 +7,8 @@ import {
ServiceTokenData, ServiceTokenData,
IServiceTokenData, IServiceTokenData,
Secret, Secret,
ISecret ISecret,
SecretBlindIndexData,
} from '../models'; } from '../models';
import { import {
validateMembership validateMembership
@@ -34,6 +35,9 @@ import {
AUTH_MODE_SERVICE_TOKEN, AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_API_KEY AUTH_MODE_API_KEY
} from '../variables'; } from '../variables';
import crypto from 'crypto';
import * as argon2 from 'argon2';
/** /**
* Validate authenticated clients for secrets with id [secretId] based * Validate authenticated clients for secrets with id [secretId] based
@@ -192,7 +196,74 @@ const validateClientForSecrets = async ({
}); });
} }
/**
* Create and return blind index for secret with
* name [name] part of workspace with id [workspaceId]
* @param {Object} obj
* @param {Object} obj.secretName - name of secret to generate blind index for
* @param {Object} obj.workspaceId - id of workspace that secret belongs to
*/
const createSecretBlindIndexHelper = async ({
secretName,
workspaceId
}: {
secretName: string;
workspaceId: Types.ObjectId;
}) => {
// check if workspace blind index data exists
// const secretBlindIndexData = await SecretBlindIndexData.findOne({
// workspace: workspaceId
// });
// if (!secretBlindIndexData) {
// // case: workspace blind index data has not been enabled
// }
// TODO: randomBytes should come from the decrypted secretBlindIndexData
const randomBytes = crypto.randomBytes(16);
const secretBlindIndex = (await argon2.hash(secretName, {
type: argon2.argon2id,
salt: randomBytes,
saltLength: 16, // default 16 bytes
memoryCost: 65536, // default pool of 64 MiB per thread.
hashLength: 32,
parallelism: 1,
raw: true
})).toString('base64');
return secretBlindIndex;
}
/**
* Return the blind index for the secret with
* name [name] part of workspace with id [workspaceId]
* @param {Object} obj
* @param {Object} obj.secretName - name of secret to generate blind index for
* @param {Object} obj.workspaceId - id of workspace that secret belongs to
*/
const getSecretBlindIndexHelper = async ({
secretName,
workspaceId
}: {
secretName: string;
workspaceId: Types.ObjectId;
}) => {
// check if workspace blind index data exists
const secretBlindIndexData = await SecretBlindIndexData.findOne({
workspace: workspaceId
});
if (!secretBlindIndexData) {
// case: workspace blind index data has not been enabled
}
}
export { export {
validateClientForSecret, validateClientForSecret,
validateClientForSecrets validateClientForSecrets,
createSecretBlindIndexHelper,
getSecretBlindIndexHelper
} }
+15
View File
@@ -1,8 +1,14 @@
import { Schema, model, Types } from 'mongoose'; import { Schema, model, Types } from 'mongoose';
import {
WORKSPACE_ENCRYPTION_MODE_E2EE,
WORKSPACE_ENCRYPTION_MODE_BLIND_INDEXED_E2EE,
WORKSPACE_ENCRYPTION_MODE_NOT_E2EE
} from '../variables';
export interface IWorkspace { export interface IWorkspace {
_id: Types.ObjectId; _id: Types.ObjectId;
name: string; name: string;
encryptionMode: string;
organization: Types.ObjectId; organization: Types.ObjectId;
environments: Array<{ environments: Array<{
name: string; name: string;
@@ -16,6 +22,15 @@ const workspaceSchema = new Schema<IWorkspace>({
type: String, type: String,
required: true required: true
}, },
encryptionMode: {
type: String,
default: 'e2ee',
enum: [
WORKSPACE_ENCRYPTION_MODE_E2EE,
WORKSPACE_ENCRYPTION_MODE_BLIND_INDEXED_E2EE,
WORKSPACE_ENCRYPTION_MODE_NOT_E2EE
]
},
autoCapitalization: { autoCapitalization: {
type: Boolean, type: Boolean,
default: true, default: true,
+29 -5
View File
@@ -1,7 +1,18 @@
// WIP // WIP
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import {
createSecretBlindIndexHelper,
getSecretBlindIndexHelper
} from '../helpers/secrets';
class SecretService { class SecretService {
/**
* Create and return blind index for secret with
* name [name] part of workspace with id [workspaceId]
* @param {Object} obj
* @param {Object} obj.secretName - name of secret to generate blind index for
* @param {Object} obj.workspaceId - id of workspace that secret belongs to
*/
static async createSecretBlindIndex({ static async createSecretBlindIndex({
secretName, secretName,
workspaceId, workspaceId,
@@ -9,10 +20,19 @@ class SecretService {
secretName: string; secretName: string;
workspaceId: Types.ObjectId; workspaceId: Types.ObjectId;
}) { }) {
// TODO return await createSecretBlindIndexHelper({
return; secretName,
workspaceId
});
} }
/**
* Return the blind index for the secret with
* name [name] part of workspace with id [workspaceId]
* @param {Object} obj
* @param {Object} obj.secretName - name of secret to generate blind index for
* @param {Object} obj.workspaceId - id of workspace that secret belongs to
*/
static async getSecretBlindIndex({ static async getSecretBlindIndex({
secretName, secretName,
workspaceId workspaceId
@@ -20,7 +40,11 @@ class SecretService {
secretName: string; secretName: string;
workspaceId: Types.ObjectId; workspaceId: Types.ObjectId;
}) { }) {
// TODO return await getSecretBlindIndexHelper({
return; secretName,
workspaceId
});
} }
} }
export default SecretService;
+3 -3
View File
@@ -5,14 +5,14 @@ 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';
import SecretService from './SecretService';
export { export {
TelemetryService, TelemetryService,
// logTelemetryMessage,
// getPostHogClient,
DatabaseService, DatabaseService,
BotService, BotService,
EventService, EventService,
IntegrationService, IntegrationService,
TokenService TokenService,
SecretService
} }
+9 -1
View File
@@ -77,6 +77,11 @@ import {
AUTH_MODE_SERVICE_TOKEN, AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_API_KEY AUTH_MODE_API_KEY
} from './authentication'; } from './authentication';
import {
WORKSPACE_ENCRYPTION_MODE_E2EE,
WORKSPACE_ENCRYPTION_MODE_BLIND_INDEXED_E2EE,
WORKSPACE_ENCRYPTION_MODE_NOT_E2EE
} from './workspace';
export { export {
OWNER, OWNER,
@@ -148,5 +153,8 @@ export {
AUTH_MODE_JWT, AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT, AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN, AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_API_KEY AUTH_MODE_API_KEY,
WORKSPACE_ENCRYPTION_MODE_E2EE,
WORKSPACE_ENCRYPTION_MODE_BLIND_INDEXED_E2EE,
WORKSPACE_ENCRYPTION_MODE_NOT_E2EE
}; };
+9
View File
@@ -0,0 +1,9 @@
const WORKSPACE_ENCRYPTION_MODE_E2EE = 'e2ee';
const WORKSPACE_ENCRYPTION_MODE_BLIND_INDEXED_E2EE = 'blind-indexed-e2ee';
const WORKSPACE_ENCRYPTION_MODE_NOT_E2EE = 'not-e2ee';
export {
WORKSPACE_ENCRYPTION_MODE_E2EE,
WORKSPACE_ENCRYPTION_MODE_BLIND_INDEXED_E2EE,
WORKSPACE_ENCRYPTION_MODE_NOT_E2EE
}
@@ -39,9 +39,9 @@ import {
CreateUpdateEnvFormData, CreateUpdateEnvFormData,
CreateWsTag, CreateWsTag,
EnvironmentSection, EnvironmentSection,
ProjectEncryptionModeSection,
ProjectNameChangeSection, ProjectNameChangeSection,
ServiceTokenSection ServiceTokenSection} from './components';
} from './components';
export const ProjectSettingsPage = () => { export const ProjectSettingsPage = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -349,6 +349,7 @@ export const ProjectSettingsPage = () => {
workspaceAutoCapitalization={currentWorkspace?.autoCapitalization} workspaceAutoCapitalization={currentWorkspace?.autoCapitalization}
onAutoCapitalizationChange={onAutoCapitalizationToggle} onAutoCapitalizationChange={onAutoCapitalizationToggle}
/> />
<ProjectEncryptionModeSection />
<div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md border-l border-red bg-white/5 px-6 pl-6 pb-4 pt-4"> <div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md border-l border-red bg-white/5 px-6 pl-6 pb-4 pt-4">
<p className="text-xl font-bold text-red">{t('settings-project:danger-zone')}</p> <p className="text-xl font-bold text-red">{t('settings-project:danger-zone')}</p>
<p className="text-md mt-2 text-gray-400">{t('settings-project:danger-zone-note')}</p> <p className="text-md mt-2 text-gray-400">{t('settings-project:danger-zone-note')}</p>
@@ -0,0 +1,8 @@
export const ProjectEncryptionModeSection = () => {
return (
<div>
Project encryption mode section
</div>
);
}
@@ -0,0 +1 @@
export { ProjectEncryptionModeSection } from './ProjectEncryptionModeSection';
@@ -1,6 +1,7 @@
export { CopyProjectIDSection } from './CopyProjectIDSection'; export { CopyProjectIDSection } from './CopyProjectIDSection';
export { EnvironmentSection } from './EnvironmentSection'; export { EnvironmentSection } from './EnvironmentSection';
export type { CreateUpdateEnvFormData } from './EnvironmentSection/EnvironmentSection'; export type { CreateUpdateEnvFormData } from './EnvironmentSection/EnvironmentSection';
export { ProjectEncryptionModeSection } from './ProjectEncryptionModeSection';
export { ProjectNameChangeSection } from './ProjectNameChangeSection'; export { ProjectNameChangeSection } from './ProjectNameChangeSection';
export type { CreateWsTag } from './SecretTagsSection/SecretTagsSection'; export type { CreateWsTag } from './SecretTagsSection/SecretTagsSection';
export { ServiceTokenSection } from './ServiceTokenSection'; export { ServiceTokenSection } from './ServiceTokenSection';