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

View File

@@ -4,6 +4,8 @@ import {
Secret
} from '../../models';
import crypto from 'crypto';
import { SecretService } from '../../services';
// TODO: modularize argon2id
import * as argon2 from 'argon2';
@@ -50,30 +52,47 @@ export const createSecret = async (req: Request, res: Response) => {
workspaceId,
environment,
value,
type
type,
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
secretValueCiphertext,
secretValueIV,
secretValueTag
} = req.body;
// use workspace salt
const randomBytes = crypto.randomBytes(16);
const secretBlindIndex = await SecretService.createSecretBlindIndex({
secretName,
workspaceId: new Types.ObjectId(workspaceId)
});
// generate blind index
// TODO 1: abstract away into create blind index function
// TODO 2: create a get blind index function
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');
// // use workspace salt
// const randomBytes = crypto.randomBytes(16);
// // generate blind index
// // TODO 1: abstract away into create blind index function
// // TODO 2: create a get blind index function
// 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');
// const secret = await new Secret({
// workspace: new Types.ObjectId(workspaceId),
// environment,
// type,
// secretBlindIndex
// secretBlindIndex,
// secretKeyCiphertext,
// secretKeyIV,
// secretKeyTag,
// secretValueCiphertext,
// secretValueIV,
// secretValueTag
// }).save();
return res.status(200).send({

View File

@@ -7,7 +7,8 @@ import {
ServiceTokenData,
IServiceTokenData,
Secret,
ISecret
ISecret,
SecretBlindIndexData,
} from '../models';
import {
validateMembership
@@ -34,6 +35,9 @@ import {
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_API_KEY
} from '../variables';
import crypto from 'crypto';
import * as argon2 from 'argon2';
/**
* 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 {
validateClientForSecret,
validateClientForSecrets
validateClientForSecrets,
createSecretBlindIndexHelper,
getSecretBlindIndexHelper
}

View File

@@ -1,8 +1,14 @@
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 {
_id: Types.ObjectId;
name: string;
encryptionMode: string;
organization: Types.ObjectId;
environments: Array<{
name: string;
@@ -16,6 +22,15 @@ const workspaceSchema = new Schema<IWorkspace>({
type: String,
required: true
},
encryptionMode: {
type: String,
default: 'e2ee',
enum: [
WORKSPACE_ENCRYPTION_MODE_E2EE,
WORKSPACE_ENCRYPTION_MODE_BLIND_INDEXED_E2EE,
WORKSPACE_ENCRYPTION_MODE_NOT_E2EE
]
},
autoCapitalization: {
type: Boolean,
default: true,

View File

@@ -1,7 +1,18 @@
// WIP
import { Types } from 'mongoose';
import {
createSecretBlindIndexHelper,
getSecretBlindIndexHelper
} from '../helpers/secrets';
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({
secretName,
workspaceId,
@@ -9,10 +20,19 @@ class SecretService {
secretName: string;
workspaceId: Types.ObjectId;
}) {
// TODO
return;
return await createSecretBlindIndexHelper({
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({
secretName,
workspaceId
@@ -20,7 +40,11 @@ class SecretService {
secretName: string;
workspaceId: Types.ObjectId;
}) {
// TODO
return;
return await getSecretBlindIndexHelper({
secretName,
workspaceId
});
}
}
}
export default SecretService;

View File

@@ -5,14 +5,14 @@ import BotService from './BotService';
import EventService from './EventService';
import IntegrationService from './IntegrationService';
import TokenService from './TokenService';
import SecretService from './SecretService';
export {
TelemetryService,
// logTelemetryMessage,
// getPostHogClient,
DatabaseService,
BotService,
EventService,
IntegrationService,
TokenService
TokenService,
SecretService
}

View File

@@ -77,6 +77,11 @@ import {
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_API_KEY
} from './authentication';
import {
WORKSPACE_ENCRYPTION_MODE_E2EE,
WORKSPACE_ENCRYPTION_MODE_BLIND_INDEXED_E2EE,
WORKSPACE_ENCRYPTION_MODE_NOT_E2EE
} from './workspace';
export {
OWNER,
@@ -148,5 +153,8 @@ export {
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
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
};

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
}

View File

@@ -39,9 +39,9 @@ import {
CreateUpdateEnvFormData,
CreateWsTag,
EnvironmentSection,
ProjectEncryptionModeSection,
ProjectNameChangeSection,
ServiceTokenSection
} from './components';
ServiceTokenSection} from './components';
export const ProjectSettingsPage = () => {
const { t } = useTranslation();
@@ -349,6 +349,7 @@ export const ProjectSettingsPage = () => {
workspaceAutoCapitalization={currentWorkspace?.autoCapitalization}
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">
<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>

View File

@@ -0,0 +1,8 @@
export const ProjectEncryptionModeSection = () => {
return (
<div>
Project encryption mode section
</div>
);
}

View File

@@ -0,0 +1 @@
export { ProjectEncryptionModeSection } from './ProjectEncryptionModeSection';

View File

@@ -1,6 +1,7 @@
export { CopyProjectIDSection } from './CopyProjectIDSection';
export { EnvironmentSection } from './EnvironmentSection';
export type { CreateUpdateEnvFormData } from './EnvironmentSection/EnvironmentSection';
export { ProjectEncryptionModeSection } from './ProjectEncryptionModeSection';
export { ProjectNameChangeSection } from './ProjectNameChangeSection';
export type { CreateWsTag } from './SecretTagsSection/SecretTagsSection';
export { ServiceTokenSection } from './ServiceTokenSection';