Index: trunk/phase3/includes/parser/Parser.php |
— | — | @@ -129,7 +129,7 @@ |
130 | 130 | $this->mFunctionHooks = array(); |
131 | 131 | $this->mFunctionTagHooks = array(); |
132 | 132 | $this->mFunctionSynonyms = array( 0 => array(), 1 => array() ); |
133 | | - $this->mDefaultStripList = $this->mStripList = array( 'nowiki', 'gallery' ); |
| 133 | + $this->mDefaultStripList = $this->mStripList = array( 'nowiki', 'gallery', 'a' ); |
134 | 134 | $this->mUrlProtocols = wfUrlProtocols(); |
135 | 135 | $this->mExtLinkBracketedRegex = '/\[(\b(' . wfUrlProtocols() . ')'. |
136 | 136 | '[^][<>"\\x00-\\x20\\x7F]+) *([^\]\\x0a\\x0d]*?)\]/S'; |
— | — | @@ -3284,6 +3284,9 @@ |
3285 | 3285 | case 'gallery': |
3286 | 3286 | $output = $this->renderImageGallery( $content, $attributes ); |
3287 | 3287 | break; |
| 3288 | + case 'a': |
| 3289 | + $output = $this->renderHyperlink( $content, $attributes, $frame ); |
| 3290 | + break; |
3288 | 3291 | case 'math': |
3289 | 3292 | if ( $this->mOptions->getUseTeX() ) { |
3290 | 3293 | $output = $wgContLang->armourMath( |
— | — | @@ -4333,6 +4336,35 @@ |
4334 | 4337 | } |
4335 | 4338 | |
4336 | 4339 | /** |
| 4340 | + * Tag hook handler for 'a'. Renders a HTML <a> tag, allowing most attributes, filtering href against |
| 4341 | + * allowed protocols and spam blacklist. |
| 4342 | + **/ |
| 4343 | + function renderHyperlink( $text, $params, $frame = false ) { |
| 4344 | + foreach ( $params as $name => $value ) { |
| 4345 | + $params[ $name ] = $this->replaceVariables( $value, $frame ); |
| 4346 | + } |
| 4347 | + |
| 4348 | + $whitelist = Sanitizer::attributeWhitelist( 'a' ); |
| 4349 | + $params = Sanitizer::validateAttributes( $params, $whitelist ); |
| 4350 | + |
| 4351 | + $content = $this->recursiveTagParse( trim( $text ), $frame ); |
| 4352 | + |
| 4353 | + if ( isset( $params[ 'href' ] ) ) { |
| 4354 | + $href = $params[ 'href' ]; |
| 4355 | + $this->mOutput->addExternalLink( $href ); |
| 4356 | + unset( $params[ 'href' ] ); |
| 4357 | + } else { |
| 4358 | + # Non-link <a> tag |
| 4359 | + return Xml::openElement( 'a', $params ) . $content . Xml::closeElement( 'a' ); |
| 4360 | + } |
| 4361 | + |
| 4362 | + $sk = $this->mOptions->getSkin(); |
| 4363 | + $html = $sk->makeExternalLink( $href, $content, false, '', $params ); |
| 4364 | + |
| 4365 | + return $html; |
| 4366 | + } |
| 4367 | + |
| 4368 | + /** |
4337 | 4369 | * Renders an image gallery from a text with one line per image. |
4338 | 4370 | * text labels may be given by using |-style alternative text. E.g. |
4339 | 4371 | * Image:one.jpg|The number "1" |
Index: trunk/phase3/includes/Linker.php |
— | — | @@ -760,7 +760,10 @@ |
761 | 761 | * hook play with them, *then* expand it all at once. |
762 | 762 | */ |
763 | 763 | function makeExternalLink( $url, $text, $escape = true, $linktype = '', $attribs = array() ) { |
764 | | - $attribsText = $this->getExternalLinkAttributes( 'external ' . $linktype ); |
| 764 | + if ( isset( $attribs[ 'class' ] ) ) $class = $attribs[ 'class' ]; # yet another hack :( |
| 765 | + else $class = 'external ' . $linktype; |
| 766 | + |
| 767 | + $attribsText = $this->getExternalLinkAttributes( $class ); |
765 | 768 | $url = htmlspecialchars( $url ); |
766 | 769 | if( $escape ) { |
767 | 770 | $text = htmlspecialchars( $text ); |
Index: trunk/phase3/includes/Sanitizer.php |
— | — | @@ -610,6 +610,8 @@ |
611 | 611 | */ |
612 | 612 | static function validateAttributes( $attribs, $whitelist ) { |
613 | 613 | $whitelist = array_flip( $whitelist ); |
| 614 | + $hrefExp = '/^(' . wfUrlProtocols() . ')[^\s]+$/'; |
| 615 | + |
614 | 616 | $out = array(); |
615 | 617 | foreach( $attribs as $attribute => $value ) { |
616 | 618 | if( !isset( $whitelist[$attribute] ) ) { |
— | — | @@ -641,6 +643,15 @@ |
642 | 644 | } |
643 | 645 | } |
644 | 646 | |
| 647 | + # NOTE: even though elements using href/src are not allowed directly, supply |
| 648 | + # validation code that can be used by tag hook handlers, etc |
| 649 | + if ( $attribute === 'href' || $attribute === 'src' ) { |
| 650 | + if ( !preg_match( $hrefExp, $value ) ) { |
| 651 | + continue; //drop any href or src attributes not using an allowed protocol. |
| 652 | + //NOTE: this also drops all relative URLs |
| 653 | + } |
| 654 | + } |
| 655 | + |
645 | 656 | // If this attribute was previously set, override it. |
646 | 657 | // Output should only have one attribute of each name. |
647 | 658 | $out[$attribute] = $value; |
— | — | @@ -1279,6 +1290,9 @@ |
1280 | 1291 | 'td' => array_merge( $common, $tablecell, $tablealign ), |
1281 | 1292 | 'th' => array_merge( $common, $tablecell, $tablealign ), |
1282 | 1293 | |
| 1294 | + # 12.2 # NOTE: <a> is not allowed directly, but the attrib whitelist is used from the Parser object |
| 1295 | + 'a' => array_merge( $common, array( 'href', 'rel', 'rev' ) ), # rel/rev esp. for RDFa |
| 1296 | + |
1283 | 1297 | # 13.2 |
1284 | 1298 | # Not usually allowed, but may be used for extension-style hooks |
1285 | 1299 | # such as <math> when it is rasterized |