diff options
Diffstat (limited to 'includes')
-rw-r--r-- | includes/DefaultSettings.php | 2 | ||||
-rw-r--r-- | includes/SkinTemplate.php | 6 | ||||
-rw-r--r-- | includes/db/Database.php | 1 | ||||
-rw-r--r-- | includes/installer/WebInstallerOutput.php | 40 | ||||
-rw-r--r-- | includes/specials/SpecialMovepage.php | 13 | ||||
-rw-r--r-- | includes/upload/UploadBase.php | 84 |
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 ) { |