From dde68ce753e6fda6e67b42c7e7a4e06c3b8ef732 Mon Sep 17 00:00:00 2001 From: Favour Ohanekwu Date: Sat, 8 Jan 2022 23:15:09 -0800 Subject: [PATCH] prevent corruption of downloaded file when base64 string is used in download action (#10254) --- .../sagas/ActionExecution/DownloadActionSaga.ts | 14 ++++++++++++-- .../sagas/ActionExecution/downloadActionUtils.ts | 11 +++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 app/client/src/sagas/ActionExecution/downloadActionUtils.ts diff --git a/app/client/src/sagas/ActionExecution/DownloadActionSaga.ts b/app/client/src/sagas/ActionExecution/DownloadActionSaga.ts index a9a87e0f74..7142b9f69e 100644 --- a/app/client/src/sagas/ActionExecution/DownloadActionSaga.ts +++ b/app/client/src/sagas/ActionExecution/DownloadActionSaga.ts @@ -1,4 +1,4 @@ -import { getType, isURL, Types } from "utils/TypeHelpers"; +import { getType, Types } from "utils/TypeHelpers"; import downloadjs from "downloadjs"; import AppsmithConsole from "utils/AppsmithConsole"; import Axios from "axios"; @@ -7,6 +7,7 @@ import { DownloadActionDescription, } from "entities/DataTree/actionTriggers"; import { ActionValidationError } from "sagas/ActionExecution/errorUtils"; +import { isBase64String, isUrlString } from "./downloadActionUtils"; export default async function downloadSaga( action: DownloadActionDescription["payload"], @@ -27,7 +28,7 @@ export default async function downloadSaga( AppsmithConsole.info({ text: `download('${jsonString}', '${name}', '${type}') was triggered`, }); - } else if (dataType === Types.STRING && isURL(data)) { + } else if (isUrlString(data)) { // In the event that a url string is supplied, we need to fetch the image with the response type arraybuffer. // This also covers the case where the file to be downloaded is Binary. Axios.get(data, { responseType: "arraybuffer" }).then((res) => { @@ -36,6 +37,15 @@ export default async function downloadSaga( text: `download('${data}', '${name}', '${type}') was triggered`, }); }); + } else if (isBase64String(data)) { + Axios.get(`data:${type};base64,${data}`, { + responseType: "arraybuffer", + }).then((res) => { + downloadjs(res.data, name, type); + AppsmithConsole.info({ + text: `download('${data}', '${name}', '${type}') was triggered`, + }); + }); } else { downloadjs(data, name, type); AppsmithConsole.info({ diff --git a/app/client/src/sagas/ActionExecution/downloadActionUtils.ts b/app/client/src/sagas/ActionExecution/downloadActionUtils.ts new file mode 100644 index 0000000000..e1cb23e780 --- /dev/null +++ b/app/client/src/sagas/ActionExecution/downloadActionUtils.ts @@ -0,0 +1,11 @@ +import { getType, isURL, Types } from "utils/TypeHelpers"; + +const BASE64_STRING_REGEX = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$/; + +export const isBase64String = (data: any) => { + return getType(data) === Types.STRING && BASE64_STRING_REGEX.test(data); +}; + +export const isUrlString = (data: any) => { + return getType(data) === Types.STRING && isURL(data); +};