jenkins-bot has submitted this change and it was merged. (
https://gerrit.wikimedia.org/r/367632 )
Change subject: [SECURITY] Fix XSS in UserBoard on social profile pages and
CSRF in API modules which do write actions
......................................................................
[SECURITY] Fix XSS in UserBoard on social profile pages and CSRF in API modules
which do write actions
Bug: T171045
Change-Id: I50c1f0837f407489c555c49d3a83437c27a9ddee
---
M .jshintrc
M SocialProfile.php
M UserBoard/ApiDeleteUserBoardMessage.php
M UserBoard/ApiSendUserBoardMessage.php
M UserBoard/SpecialUserBoard.php
M UserBoard/UserBoard.js
M UserBoard/UserBoardClass.php
M UserProfile/ApiUserProfilePrivacy.php
M UserProfile/UpdateProfile.js
M UserProfile/UserProfile.php
M UserProfile/UserProfilePage.js
11 files changed, 97 insertions(+), 82 deletions(-)
Approvals:
Legoktm: Looks good to me, approved
jenkins-bot: Verified
diff --git a/.jshintrc b/.jshintrc
index 8a2a10c..a0ff444 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -18,6 +18,7 @@
"jquery": true,
"globals": {
- "mediaWiki": false
+ "mediaWiki": false,
+ "mw": false
}
}
diff --git a/SocialProfile.php b/SocialProfile.php
index e47e4d5..d9ac323 100644
--- a/SocialProfile.php
+++ b/SocialProfile.php
@@ -150,7 +150,7 @@
'path' => __FILE__,
'name' => 'SocialProfile',
'author' => array( 'Aaron Wright', 'David Pean', 'Jack Phoenix' ),
- 'version' => '1.12',
+ 'version' => '1.13',
'url' => 'https://www.mediawiki.org/wiki/Extension:SocialProfile',
'descriptionmsg' => 'socialprofile-desc',
);
@@ -301,6 +301,7 @@
// UserBoard
$wgResourceModules['ext.socialprofile.userboard.js'] = array(
'scripts' => 'UserBoard.js',
+ 'dependencies' => array( 'mediawiki.api' ),
'messages' => array( 'userboard_confirmdelete' ),
'localBasePath' => __DIR__ . '/UserBoard',
'remoteExtPath' => 'SocialProfile/UserBoard',
diff --git a/UserBoard/ApiDeleteUserBoardMessage.php
b/UserBoard/ApiDeleteUserBoardMessage.php
index b30d79c..85edd33 100644
--- a/UserBoard/ApiDeleteUserBoardMessage.php
+++ b/UserBoard/ApiDeleteUserBoardMessage.php
@@ -27,6 +27,14 @@
return true;
}
+ public function needsToken() {
+ return 'csrf';
+ }
+
+ public function isWriteMode() {
+ return true;
+ }
+
public function getAllowedParams() {
return array_merge( parent::getAllowedParams(), array(
'id' => array(
diff --git a/UserBoard/ApiSendUserBoardMessage.php
b/UserBoard/ApiSendUserBoardMessage.php
index 6c311e6..b8853ec 100644
--- a/UserBoard/ApiSendUserBoardMessage.php
+++ b/UserBoard/ApiSendUserBoardMessage.php
@@ -36,6 +36,14 @@
return true;
}
+ public function needsToken() {
+ return 'csrf';
+ }
+
+ public function isWriteMode() {
+ return true;
+ }
+
public function getAllowedParams() {
return array_merge( parent::getAllowedParams(), array(
'username' => array(
diff --git a/UserBoard/SpecialUserBoard.php b/UserBoard/SpecialUserBoard.php
index d957fa6..438379b 100644
--- a/UserBoard/SpecialUserBoard.php
+++ b/UserBoard/SpecialUserBoard.php
@@ -282,6 +282,9 @@
}
$output .= '<div id="user-page-board">';
+ // @todo FIXME: This if-else loop *massively* duplicates
+ // UserBoard::displayMessages(). We should refactor that and
this into
+ // one sane & sensible method. --ashley, 19 July 2017
if ( $ub_messages ) {
foreach ( $ub_messages as $ub_message ) {
$user = Title::makeTitle( NS_USER,
$ub_message['user_name_from'] );
@@ -325,16 +328,17 @@
$ub_message_text = $ub_message['message_text'];
$userPageURL = htmlspecialchars(
$user->getFullURL() );
+ $senderTitle = htmlspecialchars(
$ub_message['user_name_from'] );
$output .= "<div class=\"user-board-message\">
<div class=\"user-board-message-from\">
- <a
href=\"{$userPageURL}\"
title=\"{$ub_message['user_name_from']}\">{$ub_message['user_name_from']} </a>
{$ub_message_type_label}
+ <a href=\"{$userPageURL}\"
title=\"{$senderTitle}\">{$ub_message['user_name_from']} </a>
{$ub_message_type_label}
</div>
<div class=\"user-board-message-time\">"
. $this->msg(
'userboard_posted_ago', $b->getTimeAgo( $ub_message['timestamp'] ) )->parse() .
"</div>
<div
class=\"user-board-message-content\">
<div
class=\"user-board-message-image\">
- <a
href=\"{$userPageURL}\"
title=\"{$ub_message['user_name_from']}\">{$avatar->getAvatarURL()}</a>
+ <a
href=\"{$userPageURL}\" title=\"{$senderTitle}\">{$avatar->getAvatarURL()}</a>
</div>
<div
class=\"user-board-message-body\">
{$ub_message_text}
diff --git a/UserBoard/UserBoard.js b/UserBoard/UserBoard.js
index f672814..80b2452 100644
--- a/UserBoard/UserBoard.js
+++ b/UserBoard/UserBoard.js
@@ -13,48 +13,42 @@
var encodedName = encodeURIComponent( recipient ),
encodedMsg = encodeURIComponent( message ),
messageType = document.getElementById(
'message_type' ).value;
- jQuery.post(
- mediaWiki.util.wikiScript( 'api' ), {
- action: 'socialprofile-send-message',
- format: 'json',
- username: encodedName,
- message: encodedMsg,
- type: messageType
- },
- function() {
- UserBoard.posted = 0;
- var user_1, user_2;
- if ( sender ) { // it's a board to board
- user_1 = sender;
- user_2 = recipient;
- } else {
- user_1 = recipient;
- user_2 = '';
- }
- var params = ( user_2 ) ? '&conv=' +
user_2 : '';
- var url = mediaWiki.config.get(
'wgScriptPath' ) + '/index.php?title=Special:UserBoard&user=' + user_1 + params;
- window.location = url;
+ ( new mw.Api() ).postWithToken( 'edit', {
+ action: 'socialprofile-send-message',
+ format: 'json',
+ username: encodedName,
+ message: encodedMsg,
+ type: messageType
+ } ).done( function() {
+ UserBoard.posted = 0;
+ var user_1, user_2;
+ if ( sender ) { // it's a board to board
+ user_1 = sender;
+ user_2 = recipient;
+ } else {
+ user_1 = recipient;
+ user_2 = '';
}
- );
+ var params = ( user_2 ) ? '&conv=' + user_2 :
'';
+ var url = mediaWiki.config.get( 'wgScriptPath'
) + '/index.php?title=Special:UserBoard&user=' + user_1 + params;
+ window.location = url;
+ } );
}
},
deleteMessage: function( id ) {
if ( window.confirm( mediaWiki.msg( 'userboard_confirmdelete' )
) ) {
- jQuery.post(
- mediaWiki.util.wikiScript( 'api' ), {
- action: 'socialprofile-delete-message',
- format: 'json',
- 'id': id
- },
- function() {
- //window.location.reload();
- // 1st parent = span.user-board-red
- // 2nd parent =
div.user-board-message-links
- // 3rd parent = div.user-board-message
= the container of a msg
- jQuery( '[data-message-id="' + id +
'"]' ).parent().parent().parent().hide( 100 );
- }
- );
+ ( new mw.Api() ).postWithToken( 'edit', {
+ action: 'socialprofile-delete-message',
+ format: 'json',
+ 'id': id
+ } ).done( function() {
+ //window.location.reload();
+ // 1st parent = span.user-board-red
+ // 2nd parent = div.user-board-message-links
+ // 3rd parent = div.user-board-message = the
container of a msg
+ jQuery( '[data-message-id="' + id + '"]'
).parent().parent().parent().hide( 100 );
+ } );
}
}
};
diff --git a/UserBoard/UserBoardClass.php b/UserBoard/UserBoardClass.php
index 3fa9367..cfd6175 100644
--- a/UserBoard/UserBoardClass.php
+++ b/UserBoard/UserBoardClass.php
@@ -407,16 +407,17 @@
# $message_text = preg_replace_callback(
"/(<a[^>]*>)(.*?)(<\/a>)/i", 'cut_link_text', $message['message_text'] );
$sender = htmlspecialchars( $user->getFullURL()
);
+ $senderTitle = htmlspecialchars(
$message['user_name_from'] );
$output .= "<div class=\"user-board-message\">
<div class=\"user-board-message-from\">
- <a href=\"{$sender}\"
title=\"{$message['user_name_from']}\">{$message['user_name_from']}</a>
{$message_type_label}
+ <a href=\"{$sender}\"
title=\"{$senderTitle}\">{$message['user_name_from']}</a> {$message_type_label}
</div>
<div
class=\"user-board-message-time\">" .
wfMessage(
'userboard_posted_ago', $this->getTimeAgo( $message['timestamp'] ) )->parse() .
"</div>
<div
class=\"user-board-message-content\">
<div
class=\"user-board-message-image\">
- <a href=\"{$sender}\"
title=\"{$message['user_name_from']}\">{$avatar->getAvatarURL()}</a>
+ <a href=\"{$sender}\"
title=\"{$senderTitle}\">{$avatar->getAvatarURL()}</a>
</div>
<div
class=\"user-board-message-body\">
{$message_text}
diff --git a/UserProfile/ApiUserProfilePrivacy.php
b/UserProfile/ApiUserProfilePrivacy.php
index d6be9de..7b7bfc2 100644
--- a/UserProfile/ApiUserProfilePrivacy.php
+++ b/UserProfile/ApiUserProfilePrivacy.php
@@ -60,6 +60,14 @@
$result->addValue( null, $this->getModuleName(), $data );
}
+ public function needsToken() {
+ return 'csrf';
+ }
+
+ public function isWriteMode() {
+ return true;
+ }
+
/**
* @return array
*/
diff --git a/UserProfile/UpdateProfile.js b/UserProfile/UpdateProfile.js
index d9fab41..c99bf05 100644
--- a/UserProfile/UpdateProfile.js
+++ b/UserProfile/UpdateProfile.js
@@ -105,16 +105,12 @@
$( this_element ).find( 'div.title' ).html( '...' );
- $.ajax( {
- type: 'GET',
- url: mediaWiki.util.wikiScript( 'api' ),
- data: {
- action: 'smpuserprivacy',
- format: 'json',
- method: 'set',
- 'field_key': field_key,
- privacy: encodeURIComponent( priv )
- }
+ ( new mw.Api() ).postWithToken( 'edit', {
+ action: 'smpuserprivacy',
+ format: 'json',
+ method: 'set',
+ 'field_key': field_key,
+ privacy: encodeURIComponent( priv )
} ).done( function( data ) {
var offset = $( this_element ).offset();
$( this_element ).remove();
diff --git a/UserProfile/UserProfile.php b/UserProfile/UserProfile.php
index a6dc033..181f86c 100644
--- a/UserProfile/UserProfile.php
+++ b/UserProfile/UserProfile.php
@@ -81,7 +81,7 @@
$wgResourceModules['ext.socialprofile.userprofile.js'] = array(
'scripts' => 'UserProfilePage.js',
'messages' => array( 'user-board-confirm-delete' ),
- 'dependencies' => 'mediawiki.util',
+ 'dependencies' => array( 'mediawiki.api', 'mediawiki.util' ),
'localBasePath' => __DIR__,
'remoteExtPath' => 'SocialProfile/UserProfile',
);
@@ -89,7 +89,7 @@
// Modules for Special:EditProfile/Special:UpdateProfile
$wgResourceModules['ext.userProfile.updateProfile'] = array(
'scripts' => 'UpdateProfile.js',
- 'dependencies' => array( 'mediawiki.util', 'jquery.ui.datepicker' ),
+ 'dependencies' => array( 'mediawiki.api', 'mediawiki.util',
'jquery.ui.datepicker' ),
'localBasePath' => __DIR__,
'remoteExtPath' => 'SocialProfile/UserProfile',
'position' => 'top'
diff --git a/UserProfile/UserProfilePage.js b/UserProfile/UserProfilePage.js
index 6ae9fa5..3452ef3 100644
--- a/UserProfile/UserProfilePage.js
+++ b/UserProfile/UserProfilePage.js
@@ -14,39 +14,33 @@
msgType = document.getElementById( 'message_type'
).value;
if ( document.getElementById( 'message' ).value &&
!UserProfilePage.posted ) {
UserProfilePage.posted = 1;
- jQuery.post(
- mediaWiki.util.wikiScript( 'api' ), {
- action: 'socialprofile-send-message',
- format: 'json',
- username: userTo,
- message: encMsg,
- type: msgType
- },
- function( data ) {
- jQuery( data.result ).prependTo(
'#user-page-board' );
- UserProfilePage.posted = 0;
- jQuery( '#message' ).val( '' );
- }
- );
+ ( new mw.Api() ).postWithToken( 'edit', {
+ action: 'socialprofile-send-message',
+ format: 'json',
+ username: userTo,
+ message: encMsg,
+ type: msgType
+ } ).done( function( data ) {
+ jQuery( data.result ).prependTo(
'#user-page-board' );
+ UserProfilePage.posted = 0;
+ jQuery( '#message' ).val( '' );
+ } );
}
},
deleteMessage: function( id ) {
if ( window.confirm( mediaWiki.msg( 'user-board-confirm-delete'
) ) ) {
- jQuery.post(
- mediaWiki.util.wikiScript( 'api' ), {
- action: 'socialprofile-delete-message',
- format: 'json',
- 'id': id
- },
- function() {
- //window.location.reload();
- // 1st parent = span.user-board-red
- // 2nd parent =
div.user-board-message-links
- // 3rd parent = div.user-board-message
= the container of a msg
- jQuery( '[data-message-id="' + id +
'"]' ).parent().parent().parent().hide( 100 );
- }
- );
+ ( new mw.Api() ).postWithToken( 'edit', {
+ action: 'socialprofile-delete-message',
+ format: 'json',
+ 'id': id
+ } ).done( function() {
+ //window.location.reload();
+ // 1st parent = span.user-board-red
+ // 2nd parent = div.user-board-message-links
+ // 3rd parent = div.user-board-message = the
container of a msg
+ jQuery( '[data-message-id="' + id + '"]'
).parent().parent().parent().hide( 100 );
+ } );
}
},
--
To view, visit https://gerrit.wikimedia.org/r/367632
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I50c1f0837f407489c555c49d3a83437c27a9ddee
Gerrit-PatchSet: 2
Gerrit-Project: mediawiki/extensions/SocialProfile
Gerrit-Branch: master
Gerrit-Owner: Jack Phoenix <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: Lewis Cawte <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits