summaryrefslogtreecommitdiff
path: root/includes
diff options
context:
space:
mode:
Diffstat (limited to 'includes')
-rw-r--r--includes/DefaultSettings.php2
-rw-r--r--includes/SkinTemplate.php6
-rw-r--r--includes/db/Database.php1
-rw-r--r--includes/installer/WebInstallerOutput.php40
-rw-r--r--includes/specials/SpecialMovepage.php13
-rw-r--r--includes/upload/UploadBase.php84
6 files changed, 126 insertions, 20 deletions
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index 04450348..1034ea2e 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -33,7 +33,7 @@ $wgConf = new SiteConfiguration;
/** @endcond */
/** MediaWiki version number */
-$wgVersion = '1.19.0';
+$wgVersion = '1.19.1';
/** Name of the site. It must be changed in LocalSettings.php */
$wgSitename = 'MediaWiki';
diff --git a/includes/SkinTemplate.php b/includes/SkinTemplate.php
index e41b5e7d..2dd00980 100644
--- a/includes/SkinTemplate.php
+++ b/includes/SkinTemplate.php
@@ -298,7 +298,11 @@ class SkinTemplate extends Skin {
$tpl->set( 'specialpageattributes', '' ); # obsolete
if ( $userlang !== $wgContLang->getHtmlCode() || $userdir !== $wgContLang->getDir() ) {
- $attrs = " lang='$userlang' dir='$userdir'";
+ $escUserlang = htmlspecialchars( $userlang );
+ $escUserdir = htmlspecialchars( $userdir );
+ // Attributes must be in double quotes because htmlspecialchars() doesn't
+ // escape single quotes
+ $attrs = " lang=\"$escUserlang\" dir=\"$escUserdir\"";
$tpl->set( 'userlangattributes', $attrs );
}
diff --git a/includes/db/Database.php b/includes/db/Database.php
index 9f34f812..9d517e4a 100644
--- a/includes/db/Database.php
+++ b/includes/db/Database.php
@@ -1440,6 +1440,7 @@ abstract class DatabaseBase implements DatabaseType {
function selectRow( $table, $vars, $conds, $fname = 'DatabaseBase::selectRow',
$options = array(), $join_conds = array() )
{
+ $options = (array)$options;
$options['LIMIT'] = 1;
$res = $this->select( $table, $vars, $conds, $fname, $options, $join_conds );
diff --git a/includes/installer/WebInstallerOutput.php b/includes/installer/WebInstallerOutput.php
index ac97b37d..c6c8a4c2 100644
--- a/includes/installer/WebInstallerOutput.php
+++ b/includes/installer/WebInstallerOutput.php
@@ -94,18 +94,42 @@ class WebInstallerOutput {
*/
public function getCSS( $dir ) {
$skinDir = dirname( dirname( dirname( __FILE__ ) ) ) . '/skins';
- $vectorCssFile = "$skinDir/vector/screen.css";
- $configCssFile = "$skinDir/common/config.css";
+
+ // All these files will be concatenated in sequence and loaded
+ // as one file.
+ // The string 'images/' in the files' contents will be replaced
+ // by '../skins/$skinName/images/', where $skinName is what appears
+ // before the last '/' in each of the strings.
+ $cssFileNames = array(
+
+ // Basically the "skins.vector" ResourceLoader module styles
+ 'common/commonElements.css',
+ 'common/commonContent.css',
+ 'common/commonInterface.css',
+ 'vector/screen.css',
+
+ // mw-config specific
+ 'common/config.css',
+ );
+
$css = '';
+
wfSuppressWarnings();
- $vectorCss = file_get_contents( $vectorCssFile );
- $configCss = file_get_contents( $configCssFile );
- wfRestoreWarnings();
- if( !$vectorCss || !$configCss ) {
- $css = "/** Your webserver cannot read $vectorCssFile or $configCssFile, please check file permissions */";
+ foreach ( $cssFileNames as $cssFileName ) {
+ $fullCssFileName = "$skinDir/$cssFileName";
+ $cssFileContents = file_get_contents( $fullCssFileName );
+ if ( $cssFileContents ) {
+ preg_match( "/^(\w+)\//", $cssFileName, $match );
+ $skinName = $match[1];
+ $css .= str_replace( 'images/', "../skins/$skinName/images/", $cssFileContents );
+ } else {
+ $css .= "/** Your webserver cannot read $fullCssFileName. Please check file permissions. */";
+ }
+
+ $css .= "\n";
}
+ wfRestoreWarnings();
- $css .= str_replace( 'images/', '../skins/vector/images/', $vectorCss ) . "\n" . str_replace( 'images/', '../skins/common/images/', $configCss );
if( $dir == 'rtl' ) {
$css = CSSJanus::transform( $css, true );
}
diff --git a/includes/specials/SpecialMovepage.php b/includes/specials/SpecialMovepage.php
index d7ebd310..5536fbc9 100644
--- a/includes/specials/SpecialMovepage.php
+++ b/includes/specials/SpecialMovepage.php
@@ -55,6 +55,13 @@ class MovePageForm extends UnlistedSpecialPage {
$oldTitleText = $request->getVal( 'wpOldTitle', $target );
$this->oldTitle = Title::newFromText( $oldTitleText );
+ if( is_null( $this->oldTitle ) ) {
+ throw new ErrorPageError( 'notargettitle', 'notargettext' );
+ }
+ if( !$this->oldTitle->exists() ) {
+ throw new ErrorPageError( 'nopagetitle', 'nopagetext' );
+ }
+
$newTitleTextMain = $request->getText( 'wpNewTitleMain' );
$newTitleTextNs = $request->getInt( 'wpNewTitleNs', $this->oldTitle->getNamespace() );
// Backwards compatibility for forms submitting here from other sources
@@ -64,12 +71,6 @@ class MovePageForm extends UnlistedSpecialPage {
? Title::newFromText( $newTitleText_bc )
: Title::makeTitleSafe( $newTitleTextNs, $newTitleTextMain );
- if( is_null( $this->oldTitle ) ) {
- throw new ErrorPageError( 'notargettitle', 'notargettext' );
- }
- if( !$this->oldTitle->exists() ) {
- throw new ErrorPageError( 'nopagetitle', 'nopagetext' );
- }
$user = $this->getUser();
diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php
index 32eeeb38..6cc2287a 100644
--- a/includes/upload/UploadBase.php
+++ b/includes/upload/UploadBase.php
@@ -986,24 +986,100 @@ abstract class UploadBase {
* @todo Replace this with a whitelist filter!
*/
public function checkSvgScriptCallback( $element, $attribs ) {
- $stripped = $this->stripXmlNamespace( $element );
+ $strippedElement = $this->stripXmlNamespace( $element );
- if( $stripped == 'script' ) {
+ /*
+ * check for elements that can contain javascript
+ */
+ if( $strippedElement == 'script' ) {
wfDebug( __METHOD__ . ": Found script element '$element' in uploaded file.\n" );
return true;
}
+ # e.g., <svg xmlns="http://www.w3.org/2000/svg"> <handler xmlns:ev="http://www.w3.org/2001/xml-events" ev:event="load">alert(1)</handler> </svg>
+ if( $strippedElement == 'handler' ) {
+ wfDebug( __METHOD__ . ": Found scriptable element '$element' in uploaded file.\n" );
+ return true;
+ }
+
+ # SVG reported in Feb '12 that used xml:stylesheet to generate javascript block
+ if( $strippedElement == 'stylesheet' ) {
+ wfDebug( __METHOD__ . ": Found scriptable element '$element' in uploaded file.\n" );
+ return true;
+ }
+
foreach( $attribs as $attrib => $value ) {
$stripped = $this->stripXmlNamespace( $attrib );
+ $value = strtolower($value);
+
if( substr( $stripped, 0, 2 ) == 'on' ) {
- wfDebug( __METHOD__ . ": Found script attribute '$attrib'='value' in uploaded file.\n" );
+ wfDebug( __METHOD__ . ": Found event-handler attribute '$attrib'='$value' in uploaded file.\n" );
return true;
}
+
+ # href with javascript target
if( $stripped == 'href' && strpos( strtolower( $value ), 'javascript:' ) !== false ) {
- wfDebug( __METHOD__ . ": Found script href attribute '$attrib'='$value' in uploaded file.\n" );
+ wfDebug( __METHOD__ . ": Found script in href attribute '$attrib'='$value' in uploaded file.\n" );
+ return true;
+ }
+
+ # href with embeded svg as target
+ if( $stripped == 'href' && preg_match( '!data:[^,]*image/svg[^,]*,!sim', $value ) ) {
+ wfDebug( __METHOD__ . ": Found href to embedded svg \"<$strippedElement '$attrib'='$value'...\" in uploaded file.\n" );
+ return true;
+ }
+
+ # href with embeded (text/xml) svg as target
+ if( $stripped == 'href' && preg_match( '!data:[^,]*text/xml[^,]*,!sim', $value ) ) {
+ wfDebug( __METHOD__ . ": Found href to embedded svg \"<$strippedElement '$attrib'='$value'...\" in uploaded file.\n" );
+ return true;
+ }
+
+ # use set/animate to add event-handler attribute to parent
+ if( ( $strippedElement == 'set' || $strippedElement == 'animate' ) && $stripped == 'attributename' && substr( $value, 0, 2 ) == 'on' ) {
+ wfDebug( __METHOD__ . ": Found svg setting event-handler attribute with \"<$strippedElement $stripped='$value'...\" in uploaded file.\n" );
return true;
}
+
+ # use set to add href attribute to parent element
+ if( $strippedElement == 'set' && $stripped == 'attributename' && strpos( $value, 'href' ) !== false ) {
+ wfDebug( __METHOD__ . ": Found svg setting href attibute '$value' in uploaded file.\n" );
+ return true;
+ }
+
+ # use set to add a remote / data / script target to an element
+ if( $strippedElement == 'set' && $stripped == 'to' && preg_match( '!(http|https|data|script):!sim', $value ) ) {
+ wfDebug( __METHOD__ . ": Found svg setting attibute to '$value' in uploaded file.\n" );
+ return true;
+ }
+
+
+ # use handler attribute with remote / data / script
+ if( $stripped == 'handler' && preg_match( '!(http|https|data|script):!sim', $value ) ) {
+ wfDebug( __METHOD__ . ": Found svg setting handler with remote/data/script '$attrib'='$value' in uploaded file.\n" );
+ return true;
+ }
+
+ # use CSS styles to bring in remote code
+ # catch url("http:..., url('http:..., url(http:..., but not url("#..., url('#..., url(#....
+ if( $stripped == 'style' && preg_match_all( '!((?:font|clip-path|fill|filter|marker|marker-end|marker-mid|marker-start|mask|stroke)\s*:\s*url\s*\(\s*["\']?\s*[^#]+.*?\))!sim', $value, $matches ) ) {
+ foreach ($matches[1] as $match) {
+ if (!preg_match( '!(?:font|clip-path|fill|filter|marker|marker-end|marker-mid|marker-start|mask|stroke)\s*:\s*url\s*\(\s*(#|\'#|"#)!sim', $match ) ) {
+ wfDebug( __METHOD__ . ": Found svg setting a style with remote url '$attrib'='$value' in uploaded file.\n" );
+ return true;
+ }
+ }
+ }
+
+ # image filters can pull in url, which could be svg that executes scripts
+ if( $strippedElement == 'image' && $stripped == 'filter' && preg_match( '!url\s*\(!sim', $value ) ) {
+ wfDebug( __METHOD__ . ": Found image filter with url: \"<$strippedElement $stripped='$value'...\" in uploaded file.\n" );
+ return true;
+ }
+
}
+
+ return false; //No scripts detected
}
private function stripXmlNamespace( $name ) {