From 8a4f8dd5c5ce8e4eab3b57c3c86165a70e094c24 Mon Sep 17 00:00:00 2001
From: Sohom <sohomdatta1+git@gmail.com>
Date: Fri, 1 Dec 2023 19:32:57 +0100
Subject: [PATCH] Prevent XSS via messages in PageTriage

The following messages are affected:
* rev-deleted-user
* pagetriage-tags-quickfilter-label
* pagetriage-triage
* pagetriage-filter-date-range-format-placeholder
* pagetriage-filter-date-range-to
* pagetriage-filter-date-range-from
* pagetriage-filter-date-range-heading
* pagetriage-filter-set-button
* pagetriage-filter-reset-button

The patch makes sure that these messages are escaped
before being used as part of the raw HTML code.

Bug: T347704
Change-Id: If3091172d3bb74fa3bfd030c9b5e18865c729760
---
 .../models/ext.pageTriage.article.js          |  2 +-
 .../ext.pageTriage.listControlNav.js          | 42 ++++++++++++-------
 .../ext.pageTriage.listView.js                |  2 +-
 .../ext.pageTriage.views.toolbar/ToolView.js  |  4 +-
 .../articleInfo.js                            |  2 +-
 5 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/modules/ext.pageTriage.util/models/ext.pageTriage.article.js b/modules/ext.pageTriage.util/models/ext.pageTriage.article.js
index 578cd4d7..a5416053 100644
--- a/modules/ext.pageTriage.util/models/ext.pageTriage.article.js
+++ b/modules/ext.pageTriage.util/models/ext.pageTriage.article.js
@@ -107,7 +107,7 @@ const Article = Backbone.Model.extend( {
 				)
 			);
 		} else if ( article.get( 'creator_hidden' ) ) {
-			article.set( 'author_byline_html', mw.msg( 'rev-deleted-user' ) );
+			article.set( 'author_byline_html', $( '<span>' ).text( mw.msg( 'rev-deleted-user' ) ).html() );
 		}
 
 		// Are there any PageTriage messages on the talk page?
diff --git a/modules/ext.pageTriage.views.newPagesFeed/ext.pageTriage.listControlNav.js b/modules/ext.pageTriage.views.newPagesFeed/ext.pageTriage.listControlNav.js
index 968a37fe..70e2e12e 100644
--- a/modules/ext.pageTriage.views.newPagesFeed/ext.pageTriage.listControlNav.js
+++ b/modules/ext.pageTriage.views.newPagesFeed/ext.pageTriage.listControlNav.js
@@ -118,7 +118,7 @@ const ListControlNav = Backbone.View.extend( {
 
 		// make a reset button
 		$( '#mwe-pt-filter-reset-button' ).button( {
-			label: mw.msg( 'pagetriage-filter-reset-button' )
+			label: $( '<span>' ).text( mw.msg( 'pagetriage-filter-reset-button' ) ).html()
 		} );
 		$( '#mwe-pt-filter-reset-button' ).on( 'click', function ( e ) {
 			that.model.setParams( that.model.defaultApiParams );
@@ -136,7 +136,7 @@ const ListControlNav = Backbone.View.extend( {
 
 		// make a submit button
 		$( '#mwe-pt-filter-set-button' ).button( {
-			label: mw.msg( 'pagetriage-filter-set-button' )
+			label: $( '<span>' ).text( mw.msg( 'pagetriage-filter-set-button' ) ).html()
 		} );
 		$( '#mwe-pt-filter-set-button' ).on( 'click', function ( e ) {
 			that.filterSync();
@@ -798,14 +798,19 @@ const ListControlNav = Backbone.View.extend( {
 	 * @return {string}
 	 */
 	getDateRangeFilterSectionHtml: function ( context ) {
-		return '<span class="mwe-pt-control-label">' +
-					'<b>' + mw.msg( 'pagetriage-filter-date-range-heading' ) + '</b>' +
-				'</span>' +
-				'<div class="mwe-pt-control-options">' +
+		return $( '<span>' )
+			.attr( 'class', 'mwe-pt-control-label' )
+			.append(
+				$( '<b>' ).text( mw.msg( 'pagetriage-filter-date-range-heading' )
+				)
+			).prop( 'outerHTML' ) +
+			$( '<div>' )
+				.attr( 'class', 'mwe-pt-control-options' )
+				.append(
 					this.getDateRangeFilterFieldsHtml( context, 'from' ) +
 					'</br>' +
-					this.getDateRangeFilterFieldsHtml( context, 'to' ) +
-				'</div>';
+					this.getDateRangeFilterFieldsHtml( context, 'to' )
+				).prop( 'outerHTML' );
 	},
 
 	/**
@@ -816,14 +821,19 @@ const ListControlNav = Backbone.View.extend( {
 	 * @return {string}
 	 */
 	getDateRangeFilterFieldsHtml: function ( context, dateRangeType ) {
-		return '<label for="mwe-pt-filter-' + context + '-date-range-' + dateRangeType + '">' +
-					// eslint-disable-next-line mediawiki/msg-doc
-					mw.msg( 'pagetriage-filter-date-range-' + dateRangeType ) + ' ' +
-				'</label>' +
-				'<input type="date" name="mwe-pt-filter-' + context + '-date-range-' + dateRangeType + '"' +
-					'id="mwe-pt-filter-' + context + '-date-range-' + dateRangeType + '"' +
-					'class="mwe-pt-filter-date-range-' + dateRangeType + '"' +
-					'placeholder="' + mw.msg( 'pagetriage-filter-date-range-format-placeholder' ) + '"/>';
+		// The following messages can be used by this code:
+		// * pagetriage-filter-date-range-to
+		// * pagetriage-filter-date-range-from
+		return $( '<label>' ).attr( 'for', 'mwe-pt-filter-' + context + '-date-range-' + dateRangeType )
+			.text( mw.msg( 'pagetriage-filter-date-range-' + dateRangeType ) + ' ' )
+			.prop( 'outerHTML' ) +
+			$( '<input>' ).attr( {
+				type: 'date',
+				name: 'mwe-pt-filter-' + context + '-date-range-' + dateRangeType,
+				id: 'mwe-pt-filter-' + context + '-date-range-' + dateRangeType,
+				class: 'mwe-pt-filter-date-range-' + dateRangeType,
+				placeholder: mw.msg( 'pagetriage-filter-date-range-format-placeholder' )
+			} ).prop( 'outerHTML' );
 	}
 } );
 
diff --git a/modules/ext.pageTriage.views.newPagesFeed/ext.pageTriage.listView.js b/modules/ext.pageTriage.views.newPagesFeed/ext.pageTriage.listView.js
index 803d29b4..eef7fdd3 100644
--- a/modules/ext.pageTriage.views.newPagesFeed/ext.pageTriage.listView.js
+++ b/modules/ext.pageTriage.views.newPagesFeed/ext.pageTriage.listView.js
@@ -180,7 +180,7 @@ const ListView = Backbone.View.extend( {
 		const pageInfo = view.render().el;
 		$( '#mwe-pt-list-view' ).append( pageInfo );
 		$( pageInfo ).find( '.mwe-pt-list-triage-button' ).show().button( {
-			label: mw.msg( 'pagetriage-triage' ),
+			label: $( '<span>' ).text( mw.msg( 'pagetriage-triage' ) ).html(),
 			icons: { secondary: 'ui-icon-triangle-1-e' }
 		} );
 	},
diff --git a/modules/ext.pageTriage.views.toolbar/ToolView.js b/modules/ext.pageTriage.views.toolbar/ToolView.js
index f2544fec..4514c66c 100644
--- a/modules/ext.pageTriage.views.toolbar/ToolView.js
+++ b/modules/ext.pageTriage.views.toolbar/ToolView.js
@@ -282,7 +282,9 @@ module.exports = Backbone.View.extend( {
 		return $( '<div>' ).attr( 'id', this.id + '-search' )
 			.addClass( 'mwe-pt-tag-quicksearch' )
 			.append(
-				mw.msg( 'pagetriage-tags-quickfilter-label' ) + ' ',
+				$( '<label>' )
+					.text( mw.msg( 'pagetriage-tags-quickfilter-label' ) )
+					.attr( 'for', this.id + '-search-text' ),
 				$( '<input>' )
 					.attr( { id: this.id + '-search-text',
 						type: 'text' } )
diff --git a/modules/ext.pageTriage.views.toolbar/articleInfo.js b/modules/ext.pageTriage.views.toolbar/articleInfo.js
index 28eef292..71cb4327 100644
--- a/modules/ext.pageTriage.views.toolbar/articleInfo.js
+++ b/modules/ext.pageTriage.views.toolbar/articleInfo.js
@@ -157,7 +157,7 @@ module.exports = ToolView.extend( {
 				'YYYYMMDDHHmmss'
 			).utcOffset( offset ).format(
 				mw.msg( 'pagetriage-info-timestamp-date-format' )
-			), mw.msg( 'rev-deleted-user' ) ) );
+			), $( '<span>' ).text( mw.msg( 'rev-deleted-user' ) ) ).html() );
 		}
 
 		const stats = [
-- 
2.42.1

