diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js index cef91ba9a9e2..537913b500f5 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js +++ b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js @@ -1,12 +1,12 @@ import React from 'react'; import htmlRendererPropTypes from './htmlRendererPropTypes'; -import Config from '../../../CONFIG'; import AttachmentModal from '../../AttachmentModal'; import styles from '../../../styles/styles'; import ThumbnailImage from '../../ThumbnailImage'; import PressableWithoutFocus from '../../PressableWithoutFocus'; import CONST from '../../../CONST'; import {ShowContextMenuContext, showContextMenuForReport} from '../../ShowContextMenuContext'; +import tryResolveUrlFromApiRoot from '../../../libs/tryResolveUrlFromApiRoot'; const ImageRenderer = (props) => { const htmlAttribs = props.tnode.attributes; @@ -30,20 +30,12 @@ const ImageRenderer = (props) => { // const isAttachment = Boolean(htmlAttribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE]); const originalFileName = htmlAttribs['data-name']; - let previewSource = htmlAttribs.src; - let source = isAttachment - ? htmlAttribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE] - : htmlAttribs.src; - // Update the image URL so the images can be accessed depending on the config environment - previewSource = previewSource.replace( - Config.EXPENSIFY.EXPENSIFY_URL, - Config.EXPENSIFY.URL_API_ROOT, - ); - source = source.replace( - Config.EXPENSIFY.EXPENSIFY_URL, - Config.EXPENSIFY.URL_API_ROOT, - ); + // Files created/uploaded/hosted by App should resolve from API ROOT. Other URLs aren't modified + const previewSource = tryResolveUrlFromApiRoot(htmlAttribs.src); + const source = tryResolveUrlFromApiRoot(isAttachment + ? htmlAttribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE] + : htmlAttribs.src); const imageWidth = htmlAttribs['data-expensify-width'] ? parseInt(htmlAttribs['data-expensify-width'], 10) : undefined; const imageHeight = htmlAttribs['data-expensify-height'] ? parseInt(htmlAttribs['data-expensify-height'], 10) : undefined; diff --git a/src/libs/fileDownload/getAttachmentDetails.js b/src/libs/fileDownload/getAttachmentDetails.js index 8a465403f8a8..8105a78c4799 100644 --- a/src/libs/fileDownload/getAttachmentDetails.js +++ b/src/libs/fileDownload/getAttachmentDetails.js @@ -1,5 +1,5 @@ import CONST from '../../CONST'; -import Config from '../../CONFIG'; +import tryResolveUrlFromApiRoot from '../tryResolveUrlFromApiRoot'; /** * Extract the thumbnail URL, source URL and the original filename from the HTML. @@ -19,14 +19,11 @@ export default function getAttachmentName(html) { originalFileName: null, }; } - const sourceURL = html.match(SOURCE_REGEX)[1].replace( - Config.EXPENSIFY.EXPENSIFY_URL, - Config.EXPENSIFY.URL_API_ROOT, - ); - const previewSourceURL = (IS_IMAGE_TAG ? html.match(PREVIEW_SOURCE_REGEX)[1] : sourceURL).replace( - Config.EXPENSIFY.EXPENSIFY_URL, - Config.EXPENSIFY.URL_API_ROOT, - ); + + // Files created/uploaded/hosted by App should resolve from API ROOT. Other URLs aren't modified + const sourceURL = tryResolveUrlFromApiRoot(html.match(SOURCE_REGEX)[1]); + const imageURL = IS_IMAGE_TAG && tryResolveUrlFromApiRoot(html.match(PREVIEW_SOURCE_REGEX)[1]); + const previewSourceURL = IS_IMAGE_TAG ? imageURL : sourceURL; const originalFileName = html.match(ORIGINAL_FILENAME_REGEX)[1]; // Update the image URL so the images can be accessed depending on the config environment diff --git a/src/libs/tryResolveUrlFromApiRoot.js b/src/libs/tryResolveUrlFromApiRoot.js new file mode 100644 index 000000000000..7797d3446459 --- /dev/null +++ b/src/libs/tryResolveUrlFromApiRoot.js @@ -0,0 +1,24 @@ +import Config from '../CONFIG'; + +// Absolute URLs (`/` or `//`) should be resolved from API ROOT +// Legacy attachments can come from either staging or prod, depending on the env they were uploaded by +// Both should be replaced and loaded from API ROOT of the current environment +const ORIGINS_TO_REPLACE = ['/+', Config.EXPENSIFY.EXPENSIFY_URL, Config.EXPENSIFY.STAGING_EXPENSIFY_URL]; + +// Anything starting with a match from ORIGINS_TO_REPLACE +const ORIGIN_PATTERN = new RegExp(`^(${ORIGINS_TO_REPLACE.join('|')})`); + +/** + * When possible resolve sources relative to API ROOT + * Updates applicable URLs, so they are accessed relative to URL_API_ROOT + * - Absolute URLs like `/{path}`, become: `https://{API_ROOT}/{path}` + * - Similarly for prod or staging URLs we replace the `https://www.expensify` + * or `https://staging.expensify` part, with `https://{API_ROOT}` + * - Unmatched URLs are returned with no modifications + * + * @param {String} url + * @returns {String} + */ +export default function tryResolveUrlFromApiRoot(url) { + return url.replace(ORIGIN_PATTERN, Config.EXPENSIFY.URL_API_ROOT); +}