diff --git a/projects/packages/videopress/changelog/update-videopress-decode-title-and-description b/projects/packages/videopress/changelog/update-videopress-decode-title-and-description new file mode 100644 index 000000000000..bfac9b582804 --- /dev/null +++ b/projects/packages/videopress/changelog/update-videopress-decode-title-and-description @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +VideoPress: Render properly title and description inputs of the video block diff --git a/projects/packages/videopress/src/client/block-editor/hooks/use-video-data/index.ts b/projects/packages/videopress/src/client/block-editor/hooks/use-video-data/index.ts index 6923298deac3..1e5d159c68ae 100644 --- a/projects/packages/videopress/src/client/block-editor/hooks/use-video-data/index.ts +++ b/projects/packages/videopress/src/client/block-editor/hooks/use-video-data/index.ts @@ -3,7 +3,11 @@ */ import apiFetch from '@wordpress/api-fetch'; import { useEffect, useState } from '@wordpress/element'; +/** + * Internal dependencies + */ import getMediaToken from '../../../lib/get-media-token'; +import { decodeEntities } from '../../../lib/url'; /** * Types */ @@ -49,8 +53,8 @@ export default function useVideoData( { allow_download: response.allow_download, post_id: response.post_id, guid: response.guid, - title: response.title, - description: response.description, + title: decodeEntities( response.title ), + description: decodeEntities( response.description ), display_embed: response.display_embed, privacy_setting: response.privacy_setting, rating: response.rating, diff --git a/projects/packages/videopress/src/client/lib/url/index.ts b/projects/packages/videopress/src/client/lib/url/index.ts index 63d0e422bc0e..b0e83d35ced9 100644 --- a/projects/packages/videopress/src/client/lib/url/index.ts +++ b/projects/packages/videopress/src/client/lib/url/index.ts @@ -129,3 +129,41 @@ export function buildVideoPressURL( export const removeFileNameExtension = ( name: string ) => { return name.replace( /\.[^/.]+$/, '' ); }; + +/** + * Helper function to create and return textarea element. + * Based on https://github.com/Automattic/wp-calypso/blob/1ea156fe734d57fdf13cd332e82ac688eacd3bee/client/lib/formatting/decode/browser.js#L9 + * + * > Moreover, using textContent can prevent XSS attacks. + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent#differences_from_innerhtml + * + * It will be used to decode HTML entities, + * As long as element doesn’t get inserted in the DOM, + * we’re good in terms of security, + * since textContent will return the content without evaluating it. + * @returns {HTMLTextAreaElement} - Textarea element + */ +const createTextareaElement = (): HTMLTextAreaElement => { + if ( document.implementation && document.implementation.createHTMLDocument ) { + return document.implementation.createHTMLDocument( '' ).createElement( 'textarea' ); + } + + return document.createElement( 'textarea' ); +}; + +/** + * Decode the given text, replacing HTML entities + * with their corresponding characters. + * + * @param {string} text - Text to decode + * @returns {string} Decoded text + */ +export function decodeEntities( text: string ): string { + // Create temporary element to decode entities + const element = createTextareaElement(); + element.innerHTML = text; + const decoded = element.textContent; + element.innerHTML = ''; + return decoded; +}