From 172421948753f5adfff259aebdb4dc62ae814170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Fournier?= Date: Fri, 5 Jan 2024 14:21:20 +0100 Subject: [PATCH] feat: encrypt emails at rest for demo login (#5759) ## About the changes This allows us to encrypt emails at signup for demo users to further secure our demo instance. Currently, emails are anonymized before displaying events performed by demo users. But this means that emails are stored at rest in our DB. By encrypting the emails at login, we're adding another layer of protection. This can be enabled with a flag and requires the encryption key and the initialization vector (IV for short) to be present as environment variables. --- .../__snapshots__/create-config.test.ts.snap | 1 + src/lib/middleware/demo-authentication.ts | 11 ++++++++-- src/lib/types/experimental.ts | 5 +++++ src/lib/util/anonymise.ts | 20 ++++++++++++++++++- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index abab5a6964..e8e30c828a 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -85,6 +85,7 @@ exports[`should create default config 1`] = ` "embedProxy": true, "embedProxyFrontend": true, "enableLicense": false, + "encryptEmails": false, "featureSearchAPI": false, "featureSearchFeedback": false, "featureSearchFeedbackPosting": false, diff --git a/src/lib/middleware/demo-authentication.ts b/src/lib/middleware/demo-authentication.ts index 5a8a68dc9f..d637232f8c 100644 --- a/src/lib/middleware/demo-authentication.ts +++ b/src/lib/middleware/demo-authentication.ts @@ -6,15 +6,22 @@ import ApiUser from '../types/api-user'; import { ApiTokenType } from '../types/models/api-token'; import { IAuthRequest } from 'lib/server-impl'; import { IApiRequest } from 'lib/routes/unleash-types'; +import { encrypt } from '../util'; function demoAuthentication( app: Application, basePath: string, { userService }: Pick, - { authentication }: Pick, + { + authentication, + flagResolver, + }: Pick, ): void { app.post(`${basePath}/auth/demo/login`, async (req: IAuthRequest, res) => { - const { email } = req.body; + let { email } = req.body; + email = flagResolver.isEnabled('encryptEmails', { email }) + ? encrypt(email) + : email; try { const user = await userService.loginUserWithoutPassword( email, diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index 7c0822f06a..63fba69aba 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -5,6 +5,7 @@ import { getDefaultVariant } from 'unleash-client/lib/variant'; export type IFlagKey = | 'accessLogs' | 'anonymiseEventLog' + | 'encryptEmails' | 'enableLicense' | 'embedProxy' | 'embedProxyFrontend' @@ -169,6 +170,10 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_NEW_STRATEGY_CONFIGURATION_FEEDBACK, false, ), + encryptEmails: parseEnvVarBoolean( + process.env.UNLEASH_EXPERIMENTAL_ENCRYPT_EMAILS, + false, + ), edgeBulkMetricsKillSwitch: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_EDGE_BULK_METRICS_KILL_SWITCH, false, diff --git a/src/lib/util/anonymise.ts b/src/lib/util/anonymise.ts index bd185d30ef..7f208e837f 100644 --- a/src/lib/util/anonymise.ts +++ b/src/lib/util/anonymise.ts @@ -1,4 +1,22 @@ -import { createHash } from 'crypto'; +import { createCipheriv, createHash } from 'crypto'; + +export function encrypt(s?: string): string { + const key = process.env.UNLEASH_ENCRYPTION_KEY; + const iv = process.env.UNLEASH_ENCRYPTION_IV; + if (!s || !key || !iv) { + return s ?? ''; + } + + const algorithm = 'aes-256-cbc'; + + const cipher = createCipheriv( + algorithm, + Buffer.from(key, 'hex'), + Buffer.from(iv, 'hex'), + ); + const encrypted = cipher.update(s, 'utf8', 'hex') + cipher.final('hex'); + return `${encrypted}@unleash.run`; +} export function anonymise(s?: string): string { if (!s) {