From ecf8aac97ea0c9d2075c8ea528e7c82de694f72b Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 15 Nov 2005 00:38:39 +0000 Subject: [PATCH] * Run wikitext-escaping on plaintext sigs (no wiki markup, just name) * Check for unbalanced HTML tags on raw sigs (markup allowed, but show a warning in prefs and use default sig if not balanced) --- RELEASE-NOTES | 3 ++ includes/GlobalFunctions.php | 45 ++++++++++++++++++++ includes/Parser.php | 73 +++++++++++++++++++++++++++------ includes/SpecialPreferences.php | 13 ++++++ languages/Language.php | 1 + 5 files changed, 123 insertions(+), 12 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index ed6cdc214c..377fd56fc9 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -223,6 +223,9 @@ fully support the editing toolbar, but was found to be too confusing. * (bug 2569) Use PATH_SEPARATOR instead of trying to guess based on DIRECTORY_SEPARATOR (was wrong on NetWare) * Require PHP 4.3.2 or higher strictly now. +* Run wikitext-escaping on plaintext sigs (no wiki markup, just name) +* Check for unbalanced HTML tags on raw sigs (markup allowed, but show + a warning in prefs and use default sig if not balanced) === Caveats === diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 0c7e19129a..d459466c1f 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -1527,4 +1527,49 @@ function wfUrlProtocols() { return implode( '|', $x ); } +/** + * Check if a string is well-formed XML. + * Must include the surrounding tag. + * + * @param string $text + * @return bool + * + * @todo Error position reporting return + */ +function wfIsWellFormedXml( $text ) { + $parser = xml_parser_create( "UTF-8" ); + + # case folding violates XML standard, turn it off + xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false ); + + if( !xml_parse( $parser, $text, true ) ) { + $err = xml_error_string( xml_get_error_code( $parser ) ); + $position = xml_get_current_byte_index( $parser ); + //$fragment = $this->extractFragment( $html, $position ); + //$this->mXmlError = "$err at byte $position:\n$fragment"; + xml_parser_free( $parser ); + return false; + } + xml_parser_free( $parser ); + return true; +} + +/** + * Check if a string is a well-formed XML fragment. + * Wraps fragment in an bit and doctype, so it can be a fragment + * and can use HTML named entities. + * + * @param string $text + * @return bool + */ +function wfIsWellFormedXmlFragment( $text ) { + $html = + '' . + '' . + $text . + ''; + return wfIsWellFormedXml( $html ); +} + ?> diff --git a/includes/Parser.php b/includes/Parser.php index 9bf108722a..95183bd20c 100644 --- a/includes/Parser.php +++ b/includes/Parser.php @@ -3097,30 +3097,23 @@ class Parser # Signatures # - $n = $user->getName(); - $k = $user->getOption( 'nickname' ); - if ( '' == $k ) { $k = $n; } - if ( isset( $wgLocaltimezone ) ) { - $oldtz = getenv( 'TZ' ); - putenv( 'TZ='.$wgLocaltimezone ); - } + $sigText = $this->getUserSig( $user ); /* Note: This is the timestamp saved as hardcoded wikitext to * the database, we use $wgContLang here in order to give * everyone the same signiture and use the default one rather * than the one selected in each users preferences. */ + if ( isset( $wgLocaltimezone ) ) { + $oldtz = getenv( 'TZ' ); + putenv( 'TZ='.$wgLocaltimezone ); + } $d = $wgContLang->timeanddate( date( 'YmdHis' ), false, false) . ' (' . date( 'T' ) . ')'; if ( isset( $wgLocaltimezone ) ) { putenv( 'TZ='.$oldtz ); } - if( $user->getOption( 'fancysig' ) ) { - $sigText = $k; - } else { - $sigText = '[[' . $wgContLang->getNsText( NS_USER ) . ":$n|$k]]"; - } $text = preg_replace( '/~~~~~/', $d, $text ); $text = preg_replace( '/~~~~/', "$sigText $d", $text ); $text = preg_replace( '/~~~/', $sigText, $text ); @@ -3160,6 +3153,62 @@ class Parser return $text; } + + /** + * Fetch the user's signature text, if any, and normalize to + * validated, ready-to-insert wikitext. + * + * @param User $user + * @return string + * @access private + */ + function getUserSig( &$user ) { + $name = $user->getName(); + $nick = trim( $user->getOption( 'nickname' ) ); + if ( '' == $nick ) { + $nick = $name; + } + + if( $user->getOption( 'fancysig' ) ) { + // A wikitext signature. + $valid = $this->validateSig( $nick ); + if( $valid === false ) { + // Fall back to default sig + $nick = $name; + wfDebug( "Parser::getUserSig: $name has bad XML tags in signature.\n" ); + } else { + return $nick; + } + } + + // Plain text linking to the user's homepage + global $wgContLang; + $page = $user->getUserPage(); + return '[[' . + $page->getPrefixedText() . + "|" . + wfEscapeWikIText( $nick ) . + "]]"; + } + + /** + * We want to enforce two rules on wikitext sigs here: + * 1) Expand any templates at save time (forced subst:) + * 2) Check for unbalanced XML tags, and reject if so. + * + * @param string $text + * @return mixed An expanded string, or false if invalid. + * + * @todo Run brace substitutions + * @todo ?? Check for unbalanced '' and ''' quotes, etc + */ + function validateSig( $text ) { + if( wfIsWellFormedXmlFragment( $text ) ) { + return $text; + } else { + return false; + } + } /** * Set up some variables which are usually set up in parse() diff --git a/includes/SpecialPreferences.php b/includes/SpecialPreferences.php index 77e7a2b099..fd51c36374 100644 --- a/includes/SpecialPreferences.php +++ b/includes/SpecialPreferences.php @@ -463,6 +463,7 @@ class PreferencesForm { # $this->mUserEmail = htmlspecialchars( $this->mUserEmail ); $this->mRealName = htmlspecialchars( $this->mRealName ); + $rawNick = $this->mNick; $this->mNick = htmlspecialchars( $this->mNick ); if ( !$this->mEmailFlag ) { $emfc = 'checked="checked"'; } else { $emfc = ''; } @@ -539,11 +540,23 @@ class PreferencesForm { ); } + global $wgParser; + if( !empty( $this->mToggles['fancysig'] ) && + false === $wgParser->validateSig( $rawNick ) ) { + $invalidSig = $this->addRow( + ' ', + '' . wfMsgHtml( 'badsig' ) . '' + ); + } else { + $invalidSig = ''; + } + $wgOut->addHTML( $this->addRow( '', "mNick}\" size='25' />" ) . + $invalidSig . # FIXME: The part should be where the   is, getToggle() needs # to be changed to out return its output in two parts. -ævar $this->addRow( diff --git a/languages/Language.php b/languages/Language.php index 8565c2ad35..f710c0e673 100644 --- a/languages/Language.php +++ b/languages/Language.php @@ -622,6 +622,7 @@ Your account has been created. Don't forget to change your {{SITENAME}} preferen 'yourlanguage' => 'Language:', 'yourvariant' => 'Variant', 'yournick' => 'Nickname:', +'badsig' => 'Invalid raw signature; check HTML tags.', 'email' => 'Email', 'emailforlost' => "Fields marked with superscripts are optional. Storing an email address enables people to contact you through the website without you having to reveal your email address to them, and it can be used to send you a new password if you forget it.

Your real name, if you choose to provide it, will be used for giving you attribution for your work.", -- 2.20.1