From c3933426b905b4040e1f503a5d57be3b33aea6c7 Mon Sep 17 00:00:00 2001 From: JC Brand Date: Tue, 29 Mar 2022 19:31:36 +0200 Subject: [PATCH] Refactor `checkFileTypes` - Don't check the protocol in `checkFileTypes`, it should be doing one thing only, and that is check whether the URL ends with a particular file extension. - Raise an error when a URI object can't be created from the passed in URL Adds new function `isAllowedProtocolForMedia` which checks whether the URL points to a file on the file system (`file:`), is in a Chrome extension or uses HTTPs. Use that in `shouldRenderMediaFromURL` to filter out URLs that shouldn't be rendered. Re-add utility methods to the `u` object so that 3rd party plugins can use them. --- src/headless/utils/url.js | 50 +++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/src/headless/utils/url.js b/src/headless/utils/url.js index 0f37d83ca..6fadc53e4 100644 --- a/src/headless/utils/url.js +++ b/src/headless/utils/url.js @@ -1,12 +1,24 @@ import URI from 'urijs'; import log from '@converse/headless/log'; -import { api } from '@converse/headless/core'; +import { api, converse } from '@converse/headless/core'; -function checkTLS (uri) { - const uri_protocol = uri.protocol().toLowerCase(); +const { u } = converse.env; + +/** + * Given a url, check whether the protocol being used is allowed for rendering + * the media in the chat (as opposed to just rendering a URL hyperlink). + * @param { String } url + * @returns { Boolean } + */ +function isAllowedProtocolForMedia(url) { + const uri = getURI(url); + const { protocol } = window.location; + if (['chrome-extension:','file:'].includes(protocol)) { + return true; + } return ( - window.location.protocol === 'http:' || - (window.location.protocol === 'https:' && ['https', 'aesgcm'].includes(uri_protocol)) + protocol === 'http:' || + (protocol === 'https:' && ['https', 'aesgcm'].includes(uri.protocol().toLowerCase())) ); } @@ -19,10 +31,19 @@ export function getURI (url) { } } +/** + * Given the an array of file extensions, check whether a URL points to a file + * ending in one of them. + * @param { String[] } types - An array of file extensions + * @param { String } url + * @returns { Boolean } + * @example + * checkFileTypes(['.gif'], 'https://conversejs.org/cat.gif?foo=bar'); + */ function checkFileTypes (types, url) { const uri = getURI(url); - if (uri === null || (!['chrome-extension:','file:'].includes(window.location.protocol) && !checkTLS(uri))) { - return false; + if (uri === null) { + throw new Error(`checkFileTypes: could not parse url ${url}`); } const filename = uri.filename().toLowerCase(); return !!types.filter(ext => filename.endsWith(ext)).length; @@ -37,6 +58,9 @@ export function isDomainWhitelisted (whitelist, url) { } export function shouldRenderMediaFromURL (url_text, type) { + if (!isAllowedProtocolForMedia(url_text)) { + return false; + } const may_render = api.settings.get('render_media'); const is_domain_allowed = isDomainAllowed(url_text, `allowed_${type}_domains`); @@ -103,3 +127,15 @@ export function isImageURL (url) { export function isEncryptedFileURL (url) { return url.startsWith('aesgcm://'); } + +Object.assign(u, { + isAudioURL, + isGIFURL, + isVideoURL, + isImageURL, + isURLWithImageExtension, + checkFileTypes, + getURI, + shouldRenderMediaFromURL, + isAllowedProtocolForMedia, +});