Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F34695003
0002-ve.ui.MWMediaDialog-Clean-up-image-metadata-display.patch
matmarex (Bartosz Dziewoński)
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Authored By
matmarex
Oct 18 2021, 8:31 PM
2021-10-18 20:31:37 (UTC+0)
Size
10 KB
Referenced Files
None
Subscribers
None
0002-ve.ui.MWMediaDialog-Clean-up-image-metadata-display.patch
View Options
From 0e56dd92ea74d82e478a31a8356447babc2ad723 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bartosz=20Dziewo=C5=84ski?= <matma.rex@gmail.com>
Date: Mon, 18 Oct 2021 16:29:07 +0200
Subject: [PATCH 2/2] ve.ui.MWMediaDialog: Clean up image metadata display
* Fix incorrect use of .append() instead of .text() (which was causing
some l10n messages to be treated as raw HTML)
* Avoid escaping and parsing HTML several times when plain text was
intended
* Remove some unused options and variables
Follow-up to I3a7175fab40ee98106ee3ff174dbc4762b29db7f.
Bug: T293589
Change-Id: I124257c73fe09713afefccdec8e90200e6ae433d
---
.../ve-mw/ui/dialogs/ve.ui.MWMediaDialog.js | 80 +++++++++----------
.../widgets/ve.ui.MWMediaInfoFieldWidget.js | 60 +++++++-------
2 files changed, 69 insertions(+), 71 deletions(-)
diff --git a/modules/ve-mw/ui/dialogs/ve.ui.MWMediaDialog.js b/modules/ve-mw/ui/dialogs/ve.ui.MWMediaDialog.js
index c160f5365..21eda7819 100644
--- a/modules/ve-mw/ui/dialogs/ve.ui.MWMediaDialog.js
+++ b/modules/ve-mw/ui/dialogs/ve.ui.MWMediaDialog.js
@@ -508,9 +508,7 @@ ve.ui.MWMediaDialog.prototype.buildMediaInfoPanel = function ( imageinfo ) {
{
name: 'ImageDescription',
value: ve.getProp( metadata, 'ImageDescription', 'value' ),
- data: {
- keepOriginal: true
- },
+ format: 'html',
view: {
type: 'description',
primary: true,
@@ -519,13 +517,15 @@ ve.ui.MWMediaDialog.prototype.buildMediaInfoPanel = function ( imageinfo ) {
},
{
name: '$fileDetails',
- data: { skipProcessing: true },
+ // Real value is set later
+ value: '',
+ format: 'html',
view: { icon: 'image' }
},
{
name: 'LicenseShortName',
value: ve.getProp( metadata, 'LicenseShortName', 'value' ),
- data: {},
+ format: 'html-remove-formatting',
view: {
href: ve.getProp( metadata, 'LicenseUrl', 'value' ),
icon: this.getLicenseIcon( ve.getProp( metadata, 'LicenseShortName', 'value' ) )
@@ -534,54 +534,52 @@ ve.ui.MWMediaDialog.prototype.buildMediaInfoPanel = function ( imageinfo ) {
{
name: 'Artist',
value: ve.getProp( metadata, 'Artist', 'value' ),
- data: {},
+ format: 'html-remove-formatting',
view: {
// "Artist" label
- label: 'visualeditor-dialog-media-info-meta-artist',
+ labelMsg: 'visualeditor-dialog-media-info-meta-artist',
icon: 'userAvatar'
}
},
{
name: 'Credit',
value: ve.getProp( metadata, 'Credit', 'value' ),
- data: {},
+ format: 'html-remove-formatting',
view: { icon: 'userAvatar' }
},
{
name: 'user',
value: imageinfo.user,
- data: { skipProcessing: true },
+ format: 'plaintext',
view: {
icon: 'userAvatar',
// This is 'uploaded by'
- label: 'visualeditor-dialog-media-info-artist'
+ labelMsg: 'visualeditor-dialog-media-info-artist'
}
},
{
name: 'timestamp',
value: imageinfo.timestamp,
- data: {
- ignoreCharLimit: true
- },
+ format: 'plaintext',
view: {
icon: 'clock',
- label: 'visualeditor-dialog-media-info-uploaded',
+ labelMsg: 'visualeditor-dialog-media-info-uploaded',
isDate: true
}
},
{
name: 'DateTimeOriginal',
value: ve.getProp( metadata, 'DateTimeOriginal', 'value' ),
- data: {},
+ format: 'html-remove-formatting',
view: {
icon: 'clock',
- label: 'visualeditor-dialog-media-info-created'
+ labelMsg: 'visualeditor-dialog-media-info-created'
}
},
{
name: 'moreinfo',
value: ve.msg( 'visualeditor-dialog-media-info-moreinfo' ),
- data: {},
+ format: 'plaintext',
view: {
icon: 'info',
href: imageinfo.descriptionurl
@@ -609,14 +607,17 @@ ve.ui.MWMediaDialog.prototype.buildMediaInfoPanel = function ( imageinfo ) {
// Clean data from the API responses
for ( i = 0; i < apiDataKeysConfig.length; i++ ) {
field = apiDataKeysConfig[ i ].name;
- // Skip empty fields and those that are specifically configured to be skipped
- if ( apiDataKeysConfig[ i ].data.skipProcessing ) {
+ if ( apiDataKeysConfig[ i ].format === 'html' ) {
+ apiData[ field ] = new OO.ui.HtmlSnippet( apiDataKeysConfig[ i ].value );
+
+ } else if ( apiDataKeysConfig[ i ].format === 'html-remove-formatting' ) {
+ apiData[ field ] = this.cleanAPIresponse( apiDataKeysConfig[ i ].value );
+
+ } else if ( apiDataKeysConfig[ i ].format === 'plaintext' ) {
apiData[ field ] = apiDataKeysConfig[ i ].value;
+
} else {
- // Store a clean information from the API.
- if ( apiDataKeysConfig[ i ].value ) {
- apiData[ field ] = this.cleanAPIresponse( apiDataKeysConfig[ i ].value, apiDataKeysConfig[ i ].data );
- }
+ throw new Error( 'Unexpected metadata field format' );
}
}
@@ -624,7 +625,7 @@ ve.ui.MWMediaDialog.prototype.buildMediaInfoPanel = function ( imageinfo ) {
if ( imageinfo.mediatype === 'AUDIO' ) {
// Label this file as an audio
apiData.$fileDetails = $( '<span>' )
- .append( ve.msg( 'visualeditor-dialog-media-info-audiofile' ) );
+ .text( ve.msg( 'visualeditor-dialog-media-info-audiofile' ) );
} else {
// Build the display for image size and type
apiData.$fileDetails = $( '<div>' )
@@ -639,7 +640,7 @@ ve.ui.MWMediaDialog.prototype.buildMediaInfoPanel = function ( imageinfo ) {
),
$( '<span>' )
.addClass( 've-ui-mwMediaDialog-panel-imageinfo-separator' )
- .text( mw.msg( 'visualeditor-dialog-media-info-separator' ) ),
+ .text( ve.msg( 'visualeditor-dialog-media-info-separator' ) ),
$( '<span>' ).text( fileType )
);
}
@@ -768,29 +769,20 @@ ve.ui.MWMediaDialog.prototype.fetchThumbnail = function ( imageName, dimensions
/**
* Clean the API responses and return it in plaintext. If needed, truncate.
*
- * @param {string} rawResponse Raw response from the API
- * @param {Object} config Configuration options
+ * @param {string} html Raw response from the API
* @return {string} Plaintext clean response
*/
-ve.ui.MWMediaDialog.prototype.cleanAPIresponse = function ( rawResponse, config ) {
- var isTruncated, charLimit,
- html = $.parseHTML( rawResponse ),
- ellipsis = ve.msg( 'visualeditor-dialog-media-info-ellipsis' ),
- originalText = $( '<div>' ).append( html ).text();
-
- config = config || {};
-
- charLimit = config.charLimit || 50;
- isTruncated = originalText.length > charLimit;
-
- if ( config.keepOriginal ) {
- return html;
- }
+ve.ui.MWMediaDialog.prototype.cleanAPIresponse = function ( html ) {
+ var text = $( $.parseHTML( html ) ).text();
// Check if the string should be truncated
- return mw.html.escape( isTruncated && !config.ignoreCharLimit ?
- originalText.substring( 0, charLimit ) + ellipsis :
- originalText );
+ var charLimit = 50;
+ if ( text.length > charLimit ) {
+ var ellipsis = ve.msg( 'visualeditor-dialog-media-info-ellipsis' );
+ text = text.substring( 0, charLimit ) + ellipsis;
+ }
+
+ return text;
};
/**
diff --git a/modules/ve-mw/ui/widgets/ve.ui.MWMediaInfoFieldWidget.js b/modules/ve-mw/ui/widgets/ve.ui.MWMediaInfoFieldWidget.js
index 212634dd1..b9b80344a 100644
--- a/modules/ve-mw/ui/widgets/ve.ui.MWMediaInfoFieldWidget.js
+++ b/modules/ve-mw/ui/widgets/ve.ui.MWMediaInfoFieldWidget.js
@@ -16,10 +16,10 @@
* @mixins OO.ui.mixin.TitledElement
*
* @constructor
- * @param {Object} content API response data from which to build the display
+ * @param {jQuery|string|OO.ui.HtmlSnippet} content API response data from which to build the display
* @param {Object} [config] Configuration options
* @cfg {string} [href] A url encapsulating the field text. If a label is attached it will include the label.
- * @cfg {string} [label] A ve.msg() label string for the field.
+ * @cfg {string} [labelMsg] A ve.msg() label string for the field.
* @cfg {boolean} [isDate=false] Field text is a date that will be converted to 'fromNow' string.
* @cfg {string} [type='attribute'] Field type, either 'description' or 'attribute'
* @cfg {string} [descriptionHeight='4em'] Height limit for description fields
@@ -39,38 +39,44 @@ ve.ui.MWMediaInfoFieldWidget = function VeUiMWMediaInfoFieldWidget( content, con
this.$text = $( '<div>' )
.addClass( 've-ui-mwMediaInfoFieldWidget-text' );
- this.$overlay = null;
this.type = config.type || 'attribute';
// Initialization
- if ( config.isDate && ( datetime = moment( content ) ).isValid() ) {
- content = datetime.fromNow();
- }
+ if ( typeof content === 'string' ) {
+ if ( config.isDate && ( datetime = moment( content ) ).isValid() ) {
+ content = datetime.fromNow();
+ }
+
+ if ( config.labelMsg ) {
+ // Messages defined in ve.ui.MWMediaDialog#buildMediaInfoPanel
+ // eslint-disable-next-line mediawiki/msg-doc
+ content = ve.msg( config.labelMsg, content );
+ }
- if ( config.label ) {
- // Messages defined in ve.ui.MWMediaDialog#buildMediaInfoPanel
- // eslint-disable-next-line mediawiki/msg-doc
- content = ve.msg( config.label, content );
+ if ( config.href ) {
+ // This variable may contain either jQuery objects or strings
+ // eslint-disable-next-line no-jquery/variable-pattern
+ content = $( '<a>' )
+ .attr( 'href',
+ // For the cases where we get urls that are "local"
+ // without http(s) prefix, we will add that prefix
+ // ourselves
+ !config.href.match( /^(https?:)?\/\// ) ?
+ '//' + config.href :
+ config.href
+ )
+ .text( content );
+ }
}
- if ( config.href ) {
- this.$text
- .append(
- $( '<a>' )
- .attr( 'target', '_blank' )
- .attr( 'rel', 'mw:ExtLink' )
- .attr( 'href',
- // For the cases where we get urls that are "local"
- // without http(s) prefix, we will add that prefix
- // ourselves
- !config.href.match( /^(https?:)?\/\// ) ?
- '//' + config.href :
- config.href
- )
- .append( content )
- );
- } else {
+ if ( typeof content === 'string' ) {
+ this.$text.text( content );
+ } else if ( content instanceof OO.ui.HtmlSnippet ) {
+ this.$text.html( content.toString() );
+ } else if ( content instanceof $ ) {
this.$text.append( content );
+ } else {
+ throw new Error( 'Unexpected metadata field content' );
}
this.$element
--
2.28.0.windows.1
File Metadata
Details
Attached
Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
9209683
Default Alt Text
0002-ve.ui.MWMediaDialog-Clean-up-image-metadata-display.patch (10 KB)
Attached To
Mode
T293589: CVE-2021-44855: Blind Stored XSS via Upload Image via URL
Attached
Detach File
Event Timeline
Log In to Comment