Revert r110321: introduces an XSS vulnerability because FormatJson::encode() does...
authorTim Starling <tstarling@users.mediawiki.org>
Wed, 8 Feb 2012 00:03:16 +0000 (00:03 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Wed, 8 Feb 2012 00:03:16 +0000 (00:03 +0000)
includes/Xml.php

index f866ff0..7e5b3cd 100644 (file)
@@ -607,19 +607,52 @@ class Xml {
        }
 
        /**
-        * Encode a variable of unknown type to JavaScript. If you're not dealing
-        * with potential instances of XmlJsCode (which bypass encoding), then
-        * FormatJson::encode should be used directly.
+        * Encode a variable of unknown type to JavaScript.
+        * Arrays are converted to JS arrays, objects are converted to JS associative
+        * arrays (objects). So cast your PHP associative arrays to objects before
+        * passing them to here.
         *
         * @param $value
         *
         * @return string
         */
        public static function encodeJsVar( $value ) {
-               if ( $value instanceof XmlJsCode ) {
-                       return $value->value;
+               if ( is_bool( $value ) ) {
+                       $s = $value ? 'true' : 'false';
+               } elseif ( is_null( $value ) ) {
+                       $s = 'null';
+               } elseif ( is_int( $value ) || is_float( $value ) ) {
+                       $s = strval($value);
+               } elseif ( is_array( $value ) && // Make sure it's not associative.
+                                       array_keys($value) === range( 0, count($value) - 1 ) ||
+                                       count($value) == 0
+                               ) {
+                       $s = '[';
+                       foreach ( $value as $elt ) {
+                               if ( $s != '[' ) {
+                                       $s .= ',';
+                               }
+                               $s .= self::encodeJsVar( $elt );
+                       }
+                       $s .= ']';
+               } elseif ( $value instanceof XmlJsCode ) {
+                       $s = $value->value;
+               } elseif ( is_object( $value ) || is_array( $value ) ) {
+                       // Objects and associative arrays
+                       $s = '{';
+                       foreach ( (array)$value as $name => $elt ) {
+                               if ( $s != '{' ) {
+                                       $s .= ',';
+                               }
+
+                               $s .= '"' . self::escapeJsString( $name ) . '":' .
+                                       self::encodeJsVar( $elt );
+                       }
+                       $s .= '}';
+               } else {
+                       $s = '"' . self::escapeJsString( $value ) . '"';
                }
-               return FormatJson::encode( $value );
+               return $s;
        }
 
        /**