From fcb677d99029571fdaf64444cc9f16812b58ea78 Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Sat, 15 Apr 2023 15:21:44 +0300 Subject: [PATCH] Checkpoint argon2id test to generate blind index --- .../src/controllers/v3/secretsController.ts | 29 ++++++++++++++++--- backend/src/index.ts | 10 +++++-- backend/src/models/index.ts | 3 ++ backend/src/models/secret.ts | 6 +++- backend/src/models/secretBlindIndexData.ts | 25 ++++++++++++++++ backend/src/routes/v3/index.ts | 5 ++++ backend/src/routes/v3/secrets.ts | 14 ++++----- backend/src/services/SecretService.ts | 26 +++++++++++++++++ 8 files changed, 104 insertions(+), 14 deletions(-) create mode 100644 backend/src/models/secretBlindIndexData.ts create mode 100644 backend/src/routes/v3/index.ts create mode 100644 backend/src/services/SecretService.ts diff --git a/backend/src/controllers/v3/secretsController.ts b/backend/src/controllers/v3/secretsController.ts index 14e0a1462..7c390fab3 100644 --- a/backend/src/controllers/v3/secretsController.ts +++ b/backend/src/controllers/v3/secretsController.ts @@ -1,7 +1,9 @@ import { Request, Response } from 'express'; +import { Types } from 'mongoose'; import { Secret } from '../../models'; +import crypto from 'crypto'; // TODO: modularize argon2id import * as argon2 from 'argon2'; @@ -47,13 +49,32 @@ export const createSecret = async (req: Request, res: Response) => { const { workspaceId, environment, - value + value, + type } = req.body; - // - // use bot to encrypt value - // BotService.encryptSymmetric(value) + // 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 + // }).save(); return res.status(200).send({ diff --git a/backend/src/index.ts b/backend/src/index.ts index 912d39177..dcf66ffd6 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -61,6 +61,9 @@ import { environment as v2EnvironmentRouter, tags as v2TagsRouter, } from './routes/v2'; +import { + secrets as v3SecretsRouter +} from './routes/v3'; import { healthCheck } from './routes/status'; import { getLogger } from './utils/logger'; import { RouteNotFoundError } from './utils/errors'; @@ -121,7 +124,7 @@ const main = async () => { app.use('/api/v1/workspace', eeWorkspaceRouter); app.use('/api/v1/action', eeActionRouter); - // v1 routes + // v1 routes (default) app.use('/api/v1/signup', v1SignupRouter); app.use('/api/v1/auth', v1AuthRouter); app.use('/api/v1/bot', v1BotRouter); @@ -140,7 +143,7 @@ const main = async () => { app.use('/api/v1/integration', v1IntegrationRouter); app.use('/api/v1/integration-auth', v1IntegrationAuthRouter); - // v2 routes + // v2 routes (improvements) app.use('/api/v2/signup', v2SignupRouter); app.use('/api/v2/auth', v2AuthRouter); app.use('/api/v2/users', v2UsersRouter); @@ -153,6 +156,9 @@ const main = async () => { app.use('/api/v2/service-token', v2ServiceTokenDataRouter); // TODO: turn into plural route app.use('/api/v2/service-accounts', v2ServiceAccountsRouter); // new app.use('/api/v2/api-key', v2APIKeyDataRouter); + + // v3 routes (experimental) + app.use('/api/v3/secrets', v3SecretsRouter); // api docs app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerFile)) diff --git a/backend/src/models/index.ts b/backend/src/models/index.ts index 886f7fec6..6cd6a01da 100644 --- a/backend/src/models/index.ts +++ b/backend/src/models/index.ts @@ -9,6 +9,7 @@ import Membership, { IMembership } from './membership'; import MembershipOrg, { IMembershipOrg } from './membershipOrg'; import Organization, { IOrganization } from './organization'; import Secret, { ISecret } from './secret'; +import SecretBlindIndexData, { ISecretBlindIndexData } from './secretBlindIndexData'; import ServiceToken, { IServiceToken } from './serviceToken'; import ServiceAccount, { IServiceAccount } from './serviceAccount'; // new import ServiceAccountKey, { IServiceAccountKey } from './serviceAccountKey'; // new @@ -45,6 +46,8 @@ export { IOrganization, Secret, ISecret, + SecretBlindIndexData, + ISecretBlindIndexData, ServiceToken, IServiceToken, ServiceAccount, diff --git a/backend/src/models/secret.ts b/backend/src/models/secret.ts index 463ed50fd..d3184b5e1 100644 --- a/backend/src/models/secret.ts +++ b/backend/src/models/secret.ts @@ -1,4 +1,4 @@ -import { Schema, model, Types } from 'mongoose'; +import { Schema, model, Types, Document } from 'mongoose'; import { SECRET_SHARED, SECRET_PERSONAL, @@ -11,6 +11,7 @@ export interface ISecret { type: string; user: Types.ObjectId; environment: string; + secretBlindIndex?: string; secretKeyCiphertext: string; secretKeyIV: string; secretKeyTag: string; @@ -57,6 +58,9 @@ const secretSchema = new Schema( type: String, required: true }, + secretBlindIndex: { + type: String + }, secretKeyCiphertext: { type: String, required: true diff --git a/backend/src/models/secretBlindIndexData.ts b/backend/src/models/secretBlindIndexData.ts new file mode 100644 index 000000000..9d0842ba4 --- /dev/null +++ b/backend/src/models/secretBlindIndexData.ts @@ -0,0 +1,25 @@ +import { Schema, model, Types, Document } from 'mongoose'; + +export interface ISecretBlindIndexData { + _id: Types.ObjectId; + workspace: Types.ObjectId; + encryptedSalt: string; +} + +const secretBlindIndexDataSchema = new Schema( + { + workspace: { + type: Schema.Types.ObjectId, + ref: 'Workspace', + required: true + }, + encryptedSalt: { + type: String, + required: true + } + } +); + +const SecretBlindIndexData = model('SecretBlindIndexData', secretBlindIndexDataSchema); + +export default SecretBlindIndexData; \ No newline at end of file diff --git a/backend/src/routes/v3/index.ts b/backend/src/routes/v3/index.ts new file mode 100644 index 000000000..fffd60b49 --- /dev/null +++ b/backend/src/routes/v3/index.ts @@ -0,0 +1,5 @@ +import secrets from './secrets'; + +export { + secrets +} \ No newline at end of file diff --git a/backend/src/routes/v3/secrets.ts b/backend/src/routes/v3/secrets.ts index 7ed47365c..92bc2d9a3 100644 --- a/backend/src/routes/v3/secrets.ts +++ b/backend/src/routes/v3/secrets.ts @@ -20,13 +20,13 @@ router.post( '/:secretName', body('workspaceId').exists().isString().trim(), body('environment').exists().isString().trim(), - body('value').exists().isString().trim(), - body('secretKeyCiphertext').optional().isString().trim(), - body('secretKeyIV').optional().isString().trim(), - body('secretKeyTag').optional().isString().trim(), - body('secretValueCiphertext').optional().isString().trim(), - body('secretValueIV').optional().isString().trim(), - body('secretValueTag').optional().isString().trim(), + body('secretKeyCiphertext').exists().isString().trim(), + body('secretKeyIV').exists().isString().trim(), + body('secretKeyTag').exists().isString().trim(), + body('secretValueCiphertext').exists().isString().trim(), + body('secretValueIV').exists().isString().trim(), + body('secretValueTag').exists().isString().trim(), + validateRequest, secretsController.createSecret ); diff --git a/backend/src/services/SecretService.ts b/backend/src/services/SecretService.ts new file mode 100644 index 000000000..21ecf1124 --- /dev/null +++ b/backend/src/services/SecretService.ts @@ -0,0 +1,26 @@ +// WIP +import { Types } from 'mongoose'; + +class SecretService { + static async createSecretBlindIndex({ + secretName, + workspaceId, + }: { + secretName: string; + workspaceId: Types.ObjectId; + }) { + // TODO + return; + } + + static async getSecretBlindIndex({ + secretName, + workspaceId + }: { + secretName: string; + workspaceId: Types.ObjectId; + }) { + // TODO + return; + } +} \ No newline at end of file