From d1f2659caecc368efa5bca1ee9f6389486359533 Mon Sep 17 00:00:00 2001 From: Alexander Lee Date: Tue, 27 Jun 2023 21:47:32 +0800 Subject: [PATCH] fix: change api to send/receive password directly --- src/routes/v2/authenticatedSites/settings.js | 5 ++-- .../configServices/SettingsService.js | 20 ++++++++-------- src/services/identity/DeploymentsService.ts | 18 +++++++++++---- src/utils/crypto-utils.ts | 23 ++++++++++++++++--- src/validators/RequestSchema.js | 3 +-- 5 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/routes/v2/authenticatedSites/settings.js b/src/routes/v2/authenticatedSites/settings.js index 4af65fcb6..665e7c3d8 100644 --- a/src/routes/v2/authenticatedSites/settings.js +++ b/src/routes/v2/authenticatedSites/settings.js @@ -101,12 +101,11 @@ class SettingsRouter { const { error } = UpdateRepoPasswordRequestSchema.validate(req.body) if (error) throw new BadRequestError(error.message) - const { encryptedPassword, iv, enablePassword } = body + const { password, enablePassword } = body const passwordRes = await this.settingsService.updatePassword( userWithSiteSessionData, { - encryptedPassword, - iv, + password, enablePassword, } ) diff --git a/src/services/configServices/SettingsService.js b/src/services/configServices/SettingsService.js index e1094cbfd..c9ab89942 100644 --- a/src/services/configServices/SettingsService.js +++ b/src/services/configServices/SettingsService.js @@ -3,6 +3,8 @@ const Bluebird = require("bluebird") const _ = require("lodash") const { okAsync, errAsync } = require("neverthrow") +const { decryptPassword } = require("@root/utils/crypto-utils") + class SettingsService { constructor({ configYmlService, @@ -56,16 +58,14 @@ class SettingsService { if (siteInfo.isErr()) { // Missing site indicating netlify site - return special result return okAsync({ - encryptedPassword: "", - iv: "", + password: "", isAmplifySite: false, }) } const { id, isPrivate } = siteInfo.value if (!isPrivate) return okAsync({ - encryptedPassword: "", - iv: "", + password: "", isAmplifySite: true, }) @@ -74,9 +74,12 @@ class SettingsService { ) if (deploymentInfo.isErr()) return deploymentInfo + const password = decryptPassword( + deploymentInfo.value.encryptedPassword, + deploymentInfo.value.encryptionIv + ) return okAsync({ - encryptedPassword: deploymentInfo.value.encryptedPassword, - iv: deploymentInfo.value.encryptionIv, + password, isAmplifySite: true, }) } @@ -154,7 +157,7 @@ class SettingsService { } } - async updatePassword(sessionData, { encryptedPassword, iv, enablePassword }) { + async updatePassword(sessionData, { password, enablePassword }) { const { siteName } = sessionData const siteInfo = await this.sitesService.getBySiteName(siteName) if (siteInfo.isErr()) { @@ -179,8 +182,7 @@ class SettingsService { } return this.deploymentsService.updateAmplifyPassword( siteName, - encryptedPassword, - iv, + password, enablePassword ) } diff --git a/src/services/identity/DeploymentsService.ts b/src/services/identity/DeploymentsService.ts index 8c388eb61..a9b9533a4 100644 --- a/src/services/identity/DeploymentsService.ts +++ b/src/services/identity/DeploymentsService.ts @@ -8,7 +8,7 @@ import { Deployment, Repo, Site } from "@database/models" import { NotFoundError } from "@root/errors/NotFoundError" import { AmplifyError, AmplifyInfo } from "@root/types/index" import { Brand } from "@root/types/util" -import { decryptPassword } from "@root/utils/crypto-utils" +import { decryptPassword, encryptPassword } from "@root/utils/crypto-utils" import DeploymentClient from "@services/identity/DeploymentClient" type deploymentsCreateParamsType = Partial & { @@ -132,8 +132,7 @@ class DeploymentsService { updateAmplifyPassword = async ( repoName: string, - encryptedPassword: string, - iv: string, + password: string, enablePassword: boolean ) => { const deploymentInfo = await this.repository.findOne({ @@ -163,10 +162,18 @@ class DeploymentsService { "" ) } else { - const decryptedPassword = decryptPassword(encryptedPassword, iv) + const { + encryptedPassword: oldEncryptedPassword, + encryptionIv: oldIv, + } = deploymentInfo + if ( + !!oldEncryptedPassword && + decryptPassword(oldEncryptedPassword, oldIv) === oldEncryptedPassword + ) + return okAsync("") updateAppInput = this.deploymentClient.generateUpdatePasswordInput( appId, - decryptedPassword + password ) } const updateResp = await this.deploymentClient.sendUpdateApp(updateAppInput) @@ -184,6 +191,7 @@ class DeploymentsService { { where: { id } } ) } else { + const { encryptedPassword, iv } = encryptPassword(password) await this.repository.update( { encryptedPassword, diff --git a/src/utils/crypto-utils.ts b/src/utils/crypto-utils.ts index 3c9d6fe65..1d6d84ef3 100644 --- a/src/utils/crypto-utils.ts +++ b/src/utils/crypto-utils.ts @@ -1,8 +1,25 @@ -import { createDecipheriv } from "crypto" +import { createCipheriv, createDecipheriv, randomBytes } from "crypto" import { config } from "@config/config" -const ALGORITHM = "aes-256-cbc" +const ENCRYPTION_ALGORITHM = "aes-256-cbc" + +export const encryptPassword = ( + password: string +): { + encryptedPassword: string + iv: string +} => { + const SECRET_KEY = Buffer.from( + config.get("aws.amplify.passwordSecretKey"), + "hex" + ) + const iv = randomBytes(16) + const decipher = createCipheriv(ENCRYPTION_ALGORITHM, SECRET_KEY, iv) + let encryptedPassword = decipher.update(password, "utf8", "hex") + encryptedPassword += decipher.final("hex") + return { encryptedPassword, iv: iv.toString("hex") } +} export const decryptPassword = (encryptedPassword: string, iv: string) => { const SECRET_KEY = Buffer.from( @@ -10,7 +27,7 @@ export const decryptPassword = (encryptedPassword: string, iv: string) => { "hex" ) const decipher = createDecipheriv( - ALGORITHM, + ENCRYPTION_ALGORITHM, SECRET_KEY, Buffer.from(iv, "hex") ) diff --git a/src/validators/RequestSchema.js b/src/validators/RequestSchema.js index 729c137ad..024ba06eb 100644 --- a/src/validators/RequestSchema.js +++ b/src/validators/RequestSchema.js @@ -276,8 +276,7 @@ const UpdateSettingsRequestSchema = Joi.object().keys({ }) const UpdateRepoPasswordRequestSchema = Joi.object().keys({ - encryptedPassword: Joi.string(), - iv: Joi.string(), + password: Joi.string(), enablePassword: Joi.boolean(), })