Index: branches/REL1_6/phase3/maintenance/parserTests.txt |
— | — | @@ -265,7 +265,15 @@ |
266 | 266 | </p> |
267 | 267 | !! end |
268 | 268 | |
| 269 | +!! test |
| 270 | +Comment semantics: unclosed comment at end |
| 271 | +!! input |
| 272 | +<!--This comment will run out to the end of the document |
| 273 | +!! result |
269 | 274 | |
| 275 | +!! end |
| 276 | + |
| 277 | + |
270 | 278 | ### |
271 | 279 | ### Preformatted text |
272 | 280 | ### |
— | — | @@ -2337,7 +2345,36 @@ |
2338 | 2346 | This template has <!-- a comment --> in it. |
2339 | 2347 | !! end |
2340 | 2348 | |
| 2349 | +!! test |
| 2350 | +pre-save transform: unclosed tag |
| 2351 | +!! options |
| 2352 | +pst noxml |
| 2353 | +!! input |
| 2354 | +<nowiki>'''not wiki''' |
| 2355 | +!! result |
| 2356 | +<nowiki>'''not wiki''' |
| 2357 | +!! end |
2341 | 2358 | |
| 2359 | +!! test |
| 2360 | +pre-save transform: mixed tag case |
| 2361 | +!! options |
| 2362 | +pst noxml |
| 2363 | +!! input |
| 2364 | +<NOwiki>'''not wiki'''</noWIKI> |
| 2365 | +!! result |
| 2366 | +<NOwiki>'''not wiki'''</noWIKI> |
| 2367 | +!! end |
| 2368 | + |
| 2369 | +!! test |
| 2370 | +pre-save transform: unclosed comment in <nowiki> |
| 2371 | +!! options |
| 2372 | +pst noxml |
| 2373 | +!! input |
| 2374 | +wiki<nowiki>nowiki<!--nowiki</nowiki>wiki |
| 2375 | +!! result |
| 2376 | +wiki<nowiki>nowiki<!--nowiki</nowiki>wiki |
| 2377 | +!!end |
| 2378 | + |
2342 | 2379 | !! article |
2343 | 2380 | Template:dangerous |
2344 | 2381 | !!text |
Index: branches/REL1_6/phase3/includes/Parser.php |
— | — | @@ -9,6 +9,7 @@ |
10 | 10 | /** */ |
11 | 11 | require_once( 'Sanitizer.php' ); |
12 | 12 | require_once( 'HttpFunctions.php' ); |
| 13 | +require_once( 'ImageGallery.php' ); |
13 | 14 | |
14 | 15 | /** |
15 | 16 | * Update this version number when the ParserOutput format |
— | — | @@ -304,100 +305,87 @@ |
305 | 306 | function getOptions() { return $this->mOptions; } |
306 | 307 | |
307 | 308 | /** |
308 | | - * Replaces all occurrences of <$tag>content</$tag> in the text |
309 | | - * with a random marker and returns the new text. the output parameter |
310 | | - * $content will be an associative array filled with data on the form |
311 | | - * $unique_marker => content. |
| 309 | + * Replaces all occurrences of HTML-style comments and the given tags |
| 310 | + * in the text with a random marker and returns teh next text. The output |
| 311 | + * parameter $matches will be an associative array filled with data in |
| 312 | + * the form: |
| 313 | + * 'UNIQ-xxxxx' => array( |
| 314 | + * 'element', |
| 315 | + * 'tag content', |
| 316 | + * array( 'param' => 'x' ), |
| 317 | + * '<element param="x">tag content</element>' ) ) |
312 | 318 | * |
313 | | - * If $content is already set, the additional entries will be appended |
314 | | - * If $tag is set to STRIP_COMMENTS, the function will extract |
315 | | - * <!-- HTML comments --> |
| 319 | + * @param $elements list of element names. Comments are always extracted. |
| 320 | + * @param $text Source text string. |
| 321 | + * @param $uniq_prefix |
316 | 322 | * |
317 | | - * @access private |
| 323 | + * @private |
318 | 324 | * @static |
319 | 325 | */ |
320 | | - function extractTagsAndParams($tag, $text, &$content, &$tags, &$params, $uniq_prefix = ''){ |
321 | | - $rnd = $uniq_prefix . '-' . $tag . Parser::getRandomString(); |
322 | | - if ( !$content ) { |
323 | | - $content = array( ); |
324 | | - } |
| 326 | + function extractTagsAndParams($elements, $text, &$matches, $uniq_prefix = ''){ |
| 327 | + $rand = Parser::getRandomString(); |
325 | 328 | $n = 1; |
326 | 329 | $stripped = ''; |
| 330 | + $matches = array(); |
327 | 331 | |
328 | | - if ( !$tags ) { |
329 | | - $tags = array( ); |
330 | | - } |
| 332 | + $taglist = implode( '|', $elements ); |
| 333 | + $start = "/<($taglist)(\\s+[^>]*?|\\s*?)(\/?>)|<(!--)/i"; |
331 | 334 | |
332 | | - if ( !$params ) { |
333 | | - $params = array( ); |
334 | | - } |
335 | | - |
336 | | - if( $tag == STRIP_COMMENTS ) { |
337 | | - $start = '/<!--()/'; |
338 | | - $end = '/-->/'; |
339 | | - } else { |
340 | | - $start = "/<$tag(\\s+[^>]*|\\s*\/?)>/i"; |
341 | | - $end = "/<\\/$tag\\s*>/i"; |
342 | | - } |
343 | | - |
344 | 335 | while ( '' != $text ) { |
345 | 336 | $p = preg_split( $start, $text, 2, PREG_SPLIT_DELIM_CAPTURE ); |
346 | 337 | $stripped .= $p[0]; |
347 | | - if( count( $p ) < 3 ) { |
| 338 | + if( count( $p ) < 5 ) { |
348 | 339 | break; |
349 | 340 | } |
350 | | - $attributes = $p[1]; |
351 | | - $inside = $p[2]; |
352 | | - |
353 | | - // If $attributes ends with '/', we have an empty element tag, <tag /> |
354 | | - if( $tag != STRIP_COMMENTS && substr( $attributes, -1 ) == '/' ) { |
355 | | - $attributes = substr( $attributes, 0, -1); |
356 | | - $empty = '/'; |
| 341 | + if( count( $p ) > 5 ) { |
| 342 | + // comment |
| 343 | + $element = $p[4]; |
| 344 | + $attributes = ''; |
| 345 | + $close = ''; |
| 346 | + $inside = $p[5]; |
357 | 347 | } else { |
358 | | - $empty = ''; |
| 348 | + // tag |
| 349 | + $element = $p[1]; |
| 350 | + $attributes = $p[2]; |
| 351 | + $close = $p[3]; |
| 352 | + $inside = $p[4]; |
359 | 353 | } |
360 | 354 | |
361 | | - $marker = $rnd . sprintf('%08X', $n++); |
| 355 | + $marker = "$uniq_prefix-$element-$rand" . sprintf('%08X', $n++) . '-QINU'; |
362 | 356 | $stripped .= $marker; |
363 | 357 | |
364 | | - $tags[$marker] = "<$tag$attributes$empty>"; |
365 | | - $params[$marker] = Sanitizer::decodeTagAttributes( $attributes ); |
366 | | - |
367 | | - if ( $empty === '/' ) { |
| 358 | + if ( $close === '/>' ) { |
368 | 359 | // Empty element tag, <tag /> |
369 | | - $content[$marker] = null; |
| 360 | + $content = null; |
370 | 361 | $text = $inside; |
| 362 | + $tail = null; |
371 | 363 | } else { |
372 | | - $q = preg_split( $end, $inside, 2 ); |
373 | | - $content[$marker] = $q[0]; |
374 | | - if( count( $q ) < 2 ) { |
| 364 | + if( $element == '!--' ) { |
| 365 | + $end = '/(-->)/'; |
| 366 | + } else { |
| 367 | + $end = "/(<\\/$element\\s*>)/i"; |
| 368 | + } |
| 369 | + $q = preg_split( $end, $inside, 2, PREG_SPLIT_DELIM_CAPTURE ); |
| 370 | + $content = $q[0]; |
| 371 | + if( count( $q ) < 3 ) { |
375 | 372 | # No end tag -- let it run out to the end of the text. |
376 | | - break; |
| 373 | + $tail = ''; |
| 374 | + $text = ''; |
377 | 375 | } else { |
378 | | - $text = $q[1]; |
| 376 | + $tail = $q[1]; |
| 377 | + $text = $q[2]; |
379 | 378 | } |
380 | 379 | } |
| 380 | + |
| 381 | + $matches[$marker] = array( $element, |
| 382 | + $content, |
| 383 | + Sanitizer::decodeTagAttributes( $attributes ), |
| 384 | + "<$element$attributes$close$content$tail" ); |
381 | 385 | } |
382 | 386 | return $stripped; |
383 | 387 | } |
384 | 388 | |
385 | 389 | /** |
386 | | - * Wrapper function for extractTagsAndParams |
387 | | - * for cases where $tags and $params isn't needed |
388 | | - * i.e. where tags will never have params, like <nowiki> |
389 | | - * |
390 | | - * @access private |
391 | | - * @static |
392 | | - */ |
393 | | - function extractTags( $tag, $text, &$content, $uniq_prefix = '' ) { |
394 | | - $dummy_tags = array(); |
395 | | - $dummy_params = array(); |
396 | | - |
397 | | - return Parser::extractTagsAndParams( $tag, $text, $content, |
398 | | - $dummy_tags, $dummy_params, $uniq_prefix ); |
399 | | - } |
400 | | - |
401 | | - /** |
402 | 390 | * Strips and renders nowiki, pre, math, hiero |
403 | 391 | * If $render is set, performs necessary rendering operations on plugins |
404 | 392 | * Returns the text, and fills an array with data needed in unstrip() |
— | — | @@ -408,145 +396,98 @@ |
409 | 397 | * for section editing, where these comments cause confusion when |
410 | 398 | * counting the sections in the wikisource |
411 | 399 | * |
412 | | - * @access private |
| 400 | + * @private |
413 | 401 | */ |
414 | 402 | function strip( $text, &$state, $stripcomments = false ) { |
415 | 403 | $render = ($this->mOutputType == OT_HTML); |
416 | | - $html_content = array(); |
417 | | - $nowiki_content = array(); |
418 | | - $math_content = array(); |
419 | | - $pre_content = array(); |
420 | | - $comment_content = array(); |
421 | | - $ext_content = array(); |
422 | | - $ext_tags = array(); |
423 | | - $ext_params = array(); |
424 | | - $gallery_content = array(); |
425 | 404 | |
426 | 405 | # Replace any instances of the placeholders |
427 | 406 | $uniq_prefix = $this->mUniqPrefix; |
428 | 407 | #$text = str_replace( $uniq_prefix, wfHtmlEscapeFirst( $uniq_prefix ), $text ); |
429 | | - |
430 | | - # html |
| 408 | + $commentState = array(); |
| 409 | + |
| 410 | + $elements = array_merge( |
| 411 | + array( 'nowiki', 'pre', 'gallery' ), |
| 412 | + array_keys( $this->mTagHooks ) ); |
431 | 413 | global $wgRawHtml; |
432 | 414 | if( $wgRawHtml ) { |
433 | | - $text = Parser::extractTags('html', $text, $html_content, $uniq_prefix); |
434 | | - foreach( $html_content as $marker => $content ) { |
435 | | - if ($render ) { |
436 | | - # Raw and unchecked for validity. |
437 | | - $html_content[$marker] = $content; |
438 | | - } else { |
439 | | - $html_content[$marker] = '<html>'.$content.'</html>'; |
440 | | - } |
441 | | - } |
| 415 | + $elements[] = 'html'; |
442 | 416 | } |
443 | | - |
444 | | - # nowiki |
445 | | - $text = Parser::extractTags('nowiki', $text, $nowiki_content, $uniq_prefix); |
446 | | - foreach( $nowiki_content as $marker => $content ) { |
447 | | - if( $render ){ |
448 | | - $nowiki_content[$marker] = wfEscapeHTMLTagsOnly( $content ); |
449 | | - } else { |
450 | | - $nowiki_content[$marker] = '<nowiki>'.$content.'</nowiki>'; |
451 | | - } |
452 | | - } |
453 | | - |
454 | | - # math |
455 | 417 | if( $this->mOptions->getUseTeX() ) { |
456 | | - $text = Parser::extractTags('math', $text, $math_content, $uniq_prefix); |
457 | | - foreach( $math_content as $marker => $content ){ |
458 | | - if( $render ) { |
459 | | - $math_content[$marker] = renderMath( $content ); |
460 | | - } else { |
461 | | - $math_content[$marker] = '<math>'.$content.'</math>'; |
462 | | - } |
463 | | - } |
| 418 | + $elements[] = 'math'; |
464 | 419 | } |
| 420 | + |
465 | 421 | |
466 | | - # pre |
467 | | - $text = Parser::extractTags('pre', $text, $pre_content, $uniq_prefix); |
468 | | - foreach( $pre_content as $marker => $content ){ |
469 | | - if( $render ){ |
470 | | - $pre_content[$marker] = '<pre>' . wfEscapeHTMLTagsOnly( $content ) . '</pre>'; |
| 422 | + $matches = array(); |
| 423 | + $text = Parser::extractTagsAndParams( $elements, $text, $matches, $uniq_prefix ); |
| 424 | + |
| 425 | + foreach( $matches as $marker => $data ) { |
| 426 | + list( $element, $content, $params, $tag ) = $data; |
| 427 | + if( $render ) { |
| 428 | + $tagName = strtolower( $element ); |
| 429 | + switch( $tagName ) { |
| 430 | + case '!--': |
| 431 | + // Comment |
| 432 | + if( substr( $tag, -3 ) == '-->' ) { |
| 433 | + $output = $tag; |
| 434 | + } else { |
| 435 | + // Unclosed comment in input. |
| 436 | + // Close it so later stripping can remove it |
| 437 | + $output = "$tag-->"; |
| 438 | + } |
| 439 | + break; |
| 440 | + case 'html': |
| 441 | + if( $wgRawHtml ) { |
| 442 | + $output = $content; |
| 443 | + break; |
| 444 | + } |
| 445 | + // Shouldn't happen otherwise. :) |
| 446 | + case 'nowiki': |
| 447 | + $output = wfEscapeHTMLTagsOnly( $content ); |
| 448 | + break; |
| 449 | + case 'math': |
| 450 | + $output = renderMath( $content ); |
| 451 | + break; |
| 452 | + case 'pre': |
| 453 | + // Backwards-compatibility hack |
| 454 | + $content = preg_replace( '!<nowiki>(.*?)</nowiki>!is', '\\1', $content ); |
| 455 | + $output = '<pre>' . wfEscapeHTMLTagsOnly( $content ) . '</pre>'; |
| 456 | + break; |
| 457 | + case 'gallery': |
| 458 | + $output = $this->renderImageGallery( $content ); |
| 459 | + break; |
| 460 | + default: |
| 461 | + if( isset( $this->mTagHooks[$tagName] ) ) { |
| 462 | + $output = call_user_func_array( $this->mTagHooks[$tagName], |
| 463 | + array( $content, $params, &$this ) ); |
| 464 | + } else { |
| 465 | + wfDebugDieBacktrace( "Invalid call hook $element" ); |
| 466 | + } |
| 467 | + } |
471 | 468 | } else { |
472 | | - $pre_content[$marker] = '<pre>'.$content.'</pre>'; |
| 469 | + // Just stripping tags; keep the source |
| 470 | + $output = $tag; |
473 | 471 | } |
474 | | - } |
475 | | - |
476 | | - # gallery |
477 | | - $text = Parser::extractTags('gallery', $text, $gallery_content, $uniq_prefix); |
478 | | - foreach( $gallery_content as $marker => $content ) { |
479 | | - require_once( 'ImageGallery.php' ); |
480 | | - if ( $render ) { |
481 | | - $gallery_content[$marker] = $this->renderImageGallery( $content ); |
| 472 | + if( !$stripcomments && $element == '!--' ) { |
| 473 | + $commentState[$marker] = $output; |
482 | 474 | } else { |
483 | | - $gallery_content[$marker] = '<gallery>'.$content.'</gallery>'; |
| 475 | + $state[$element][$marker] = $output; |
484 | 476 | } |
485 | 477 | } |
486 | 478 | |
487 | | - # Comments |
488 | | - $text = Parser::extractTags(STRIP_COMMENTS, $text, $comment_content, $uniq_prefix); |
489 | | - foreach( $comment_content as $marker => $content ){ |
490 | | - $comment_content[$marker] = '<!--'.$content.'-->'; |
491 | | - } |
492 | | - |
493 | | - # Extensions |
494 | | - foreach ( $this->mTagHooks as $tag => $callback ) { |
495 | | - $ext_content[$tag] = array(); |
496 | | - $text = Parser::extractTagsAndParams( $tag, $text, $ext_content[$tag], |
497 | | - $ext_tags[$tag], $ext_params[$tag], $uniq_prefix ); |
498 | | - foreach( $ext_content[$tag] as $marker => $content ) { |
499 | | - $full_tag = $ext_tags[$tag][$marker]; |
500 | | - $params = $ext_params[$tag][$marker]; |
501 | | - if ( $render ) |
502 | | - $ext_content[$tag][$marker] = call_user_func_array( $callback, array( $content, $params, &$this ) ); |
503 | | - else { |
504 | | - if ( is_null( $content ) ) { |
505 | | - // Empty element tag |
506 | | - $ext_content[$tag][$marker] = $full_tag; |
507 | | - } else { |
508 | | - $ext_content[$tag][$marker] = "$full_tag$content</$tag>"; |
509 | | - } |
510 | | - } |
511 | | - } |
512 | | - } |
513 | | - |
514 | 479 | # Unstrip comments unless explicitly told otherwise. |
515 | 480 | # (The comments are always stripped prior to this point, so as to |
516 | 481 | # not invoke any extension tags / parser hooks contained within |
517 | 482 | # a comment.) |
518 | 483 | if ( !$stripcomments ) { |
519 | | - $tempstate = array( 'comment' => $comment_content ); |
520 | | - $text = $this->unstrip( $text, $tempstate ); |
521 | | - $comment_content = array(); |
| 484 | + // Put them all back and forget them |
| 485 | + $text = strtr( $text, $commentState ); |
522 | 486 | } |
523 | 487 | |
524 | | - # Merge state with the pre-existing state, if there is one |
525 | | - if ( $state ) { |
526 | | - $state['html'] = $state['html'] + $html_content; |
527 | | - $state['nowiki'] = $state['nowiki'] + $nowiki_content; |
528 | | - $state['math'] = $state['math'] + $math_content; |
529 | | - $state['pre'] = $state['pre'] + $pre_content; |
530 | | - $state['gallery'] = $state['gallery'] + $gallery_content; |
531 | | - $state['comment'] = $state['comment'] + $comment_content; |
532 | | - |
533 | | - foreach( $ext_content as $tag => $array ) { |
534 | | - if ( array_key_exists( $tag, $state ) ) { |
535 | | - $state[$tag] = $state[$tag] + $array; |
536 | | - } |
537 | | - } |
538 | | - } else { |
539 | | - $state = array( |
540 | | - 'html' => $html_content, |
541 | | - 'nowiki' => $nowiki_content, |
542 | | - 'math' => $math_content, |
543 | | - 'pre' => $pre_content, |
544 | | - 'gallery' => $gallery_content, |
545 | | - 'comment' => $comment_content, |
546 | | - ) + $ext_content; |
547 | | - } |
548 | 488 | return $text; |
549 | 489 | } |
550 | 490 | |
| 491 | + |
551 | 492 | /** |
552 | 493 | * restores pre, math, and hiero removed by strip() |
553 | 494 | * |
— | — | @@ -558,20 +499,21 @@ |
559 | 500 | return $text; |
560 | 501 | } |
561 | 502 | |
562 | | - # Must expand in reverse order, otherwise nested tags will be corrupted |
563 | | - foreach( array_reverse( $state, true ) as $tag => $contentDict ) { |
| 503 | + $replacements = array(); |
| 504 | + foreach( $state as $tag => $contentDict ) { |
564 | 505 | if( $tag != 'nowiki' && $tag != 'html' ) { |
565 | | - foreach( array_reverse( $contentDict, true ) as $uniq => $content ) { |
566 | | - $text = str_replace( $uniq, $content, $text ); |
| 506 | + foreach( $contentDict as $uniq => $content ) { |
| 507 | + $replacements[$uniq] = $content; |
567 | 508 | } |
568 | 509 | } |
569 | 510 | } |
| 511 | + $text = strtr( $text, $replacements ); |
570 | 512 | |
571 | 513 | return $text; |
572 | 514 | } |
573 | 515 | |
574 | 516 | /** |
575 | | - * always call this after unstrip() to preserve the order |
| 517 | + * Always call this after unstrip() to preserve the order |
576 | 518 | * |
577 | 519 | * @access private |
578 | 520 | */ |
— | — | @@ -580,17 +522,15 @@ |
581 | 523 | return $text; |
582 | 524 | } |
583 | 525 | |
584 | | - # Must expand in reverse order, otherwise nested tags will be corrupted |
585 | | - for ( $content = end($state['nowiki']); $content !== false; $content = prev( $state['nowiki'] ) ) { |
586 | | - $text = str_replace( key( $state['nowiki'] ), $content, $text ); |
587 | | - } |
588 | | - |
589 | | - global $wgRawHtml; |
590 | | - if ($wgRawHtml) { |
591 | | - for ( $content = end($state['html']); $content !== false; $content = prev( $state['html'] ) ) { |
592 | | - $text = str_replace( key( $state['html'] ), $content, $text ); |
| 526 | + $replacements = array(); |
| 527 | + foreach( $state as $tag => $contentDict ) { |
| 528 | + if( $tag == 'nowiki' || $tag == 'html' ) { |
| 529 | + foreach( $contentDict as $uniq => $content ) { |
| 530 | + $replacements[$uniq] = $content; |
| 531 | + } |
593 | 532 | } |
594 | 533 | } |
| 534 | + $text = strtr( $text, $replacements ); |
595 | 535 | |
596 | 536 | return $text; |
597 | 537 | } |
— | — | @@ -605,14 +545,7 @@ |
606 | 546 | function insertStripItem( $text, &$state ) { |
607 | 547 | $rnd = $this->mUniqPrefix . '-item' . Parser::getRandomString(); |
608 | 548 | if ( !$state ) { |
609 | | - $state = array( |
610 | | - 'html' => array(), |
611 | | - 'nowiki' => array(), |
612 | | - 'math' => array(), |
613 | | - 'pre' => array(), |
614 | | - 'comment' => array(), |
615 | | - 'gallery' => array(), |
616 | | - ); |
| 549 | + $state = array(); |
617 | 550 | } |
618 | 551 | $state['item'][$rnd] = $text; |
619 | 552 | return $rnd; |
— | — | @@ -3588,6 +3521,7 @@ |
3589 | 3522 | * @return The old value of the mTagHooks array associated with the hook |
3590 | 3523 | */ |
3591 | 3524 | function setHook( $tag, $callback ) { |
| 3525 | + $tag = strtolower( $tag ); |
3592 | 3526 | $oldVal = @$this->mTagHooks[$tag]; |
3593 | 3527 | $this->mTagHooks[$tag] = $callback; |
3594 | 3528 | |
Index: branches/REL1_6/phase3/includes/EditPage.php |
— | — | @@ -23,7 +23,7 @@ |
24 | 24 | var $formtype; |
25 | 25 | var $firsttime; |
26 | 26 | var $lastDelete; |
27 | | - var $mTokenOk = true; |
| 27 | + var $mTokenOk = false; |
28 | 28 | var $tooBig = false; |
29 | 29 | var $kblength = false; |
30 | 30 | var $missingComment = false; |
— | — | @@ -356,19 +356,17 @@ |
357 | 357 | $this->preview = $request->getCheck( 'wpPreview' ) || $request->getCheck( 'wpLivePreview' ); |
358 | 358 | $this->diff = $request->getCheck( 'wpDiff' ); |
359 | 359 | |
360 | | - if( !$this->preview ) { |
361 | | - if ( $this->tokenOk( $request ) ) { |
362 | | - # Some browsers will not report any submit button |
363 | | - # if the user hits enter in the comment box. |
364 | | - # The unmarked state will be assumed to be a save, |
365 | | - # if the form seems otherwise complete. |
366 | | - wfDebug( "$fname: Passed token check.\n" ); |
367 | | - } else { |
368 | | - # Page might be a hack attempt posted from |
369 | | - # an external site. Preview instead of saving. |
370 | | - wfDebug( "$fname: Failed token check; forcing preview\n" ); |
371 | | - $this->preview = true; |
372 | | - } |
| 360 | + if ( $this->tokenOk( $request ) ) { |
| 361 | + # Some browsers will not report any submit button |
| 362 | + # if the user hits enter in the comment box. |
| 363 | + # The unmarked state will be assumed to be a save, |
| 364 | + # if the form seems otherwise complete. |
| 365 | + wfDebug( "$fname: Passed token check.\n" ); |
| 366 | + } else { |
| 367 | + # Page might be a hack attempt posted from |
| 368 | + # an external site. Preview instead of saving. |
| 369 | + wfDebug( "$fname: Failed token check; forcing preview\n" ); |
| 370 | + $this->preview = true; |
373 | 371 | } |
374 | 372 | } |
375 | 373 | $this->save = ! ( $this->preview OR $this->diff ); |
— | — | @@ -1084,7 +1082,7 @@ |
1085 | 1083 | # For a bit more sophisticated detection of blank summaries, hash the |
1086 | 1084 | # automatic one and pass that in a hidden field. |
1087 | 1085 | $autosumm = $this->autoSumm ? $this->autoSumm : md5( $this->summary ); |
1088 | | - $wgOut->addHTML( "<input type=\"hidden\" name=\"wpAutoSummary\" value=\"$autosumm\" />\n" ); |
| 1086 | + $wgOut->addHtml( wfHidden( 'wpAutoSummary', $autosumm ) ); |
1089 | 1087 | |
1090 | 1088 | if ( $this->isConflict ) { |
1091 | 1089 | require_once( "DifferenceEngine.php" ); |
— | — | @@ -1245,9 +1243,17 @@ |
1246 | 1244 | $parserOptions = ParserOptions::newFromUser( $wgUser ); |
1247 | 1245 | $parserOptions->setEditSection( false ); |
1248 | 1246 | |
| 1247 | + global $wgRawHtml; |
| 1248 | + if( $wgRawHtml && !$this->mTokenOk ) { |
| 1249 | + // Could be an offsite preview attempt. This is very unsafe if |
| 1250 | + // HTML is enabled, as it could be an attack. |
| 1251 | + return $wgOut->parse( "<div class='previewnote'>" . |
| 1252 | + wfMsg( 'session_fail_preview_html' ) . "</div>" ); |
| 1253 | + } |
| 1254 | + |
1249 | 1255 | # don't parse user css/js, show message about preview |
1250 | 1256 | # XXX: stupid php bug won't let us use $wgTitle->isCssJsSubpage() here |
1251 | | - |
| 1257 | + |
1252 | 1258 | if ( $this->isCssJsSubpage ) { |
1253 | 1259 | if(preg_match("/\\.css$/", $wgTitle->getText() ) ) { |
1254 | 1260 | $previewtext = wfMsg('usercsspreview'); |
Index: branches/REL1_6/phase3/includes/Sanitizer.php |
— | — | @@ -391,8 +391,8 @@ |
392 | 392 | if ( $t == 'table' ) { |
393 | 393 | $tagstack = array_pop( $tablestack ); |
394 | 394 | } |
395 | | - $newparams = ''; |
396 | 395 | } |
| 396 | + $newparams = ''; |
397 | 397 | } else { |
398 | 398 | # Keep track for later |
399 | 399 | if ( in_array( $t, $tabletags ) && |
Index: branches/REL1_6/phase3/includes/DefaultSettings.php |
— | — | @@ -32,7 +32,7 @@ |
33 | 33 | $wgConf = new SiteConfiguration; |
34 | 34 | |
35 | 35 | /** MediaWiki version number */ |
36 | | -$wgVersion = '1.6.6'; |
| 36 | +$wgVersion = '1.6.7'; |
37 | 37 | |
38 | 38 | /** Name of the site. It must be changed in LocalSettings.php */ |
39 | 39 | $wgSitename = 'MediaWiki'; |
Index: branches/REL1_6/phase3/RELEASE-NOTES |
— | — | @@ -5,11 +5,41 @@ |
6 | 6 | |
7 | 7 | == Mediawiki 1.6.7 == |
8 | 8 | |
| 9 | +June 6, 2006 |
| 10 | + |
| 11 | +MediaWiki 1.6.7 is a security and bugfix maintenance release of the |
| 12 | +Spring 2006 snapshot: |
| 13 | + |
| 14 | +An HTML/JavaScript-injection vulnerability in the edit form has been closed. |
| 15 | +This vulnerability was new in 1.6.0; MediaWiki versions 1.5.x or earlier are |
| 16 | +not affected. |
| 17 | + |
| 18 | +Extensions, comments, and <nowiki> sections are now handled in a one-pass |
| 19 | +way which is more reliable and safer. Under earlier versions of MediaWiki, |
| 20 | +certain extensions could be abused to inject HTML/JavaScript into the page. |
| 21 | + |
| 22 | +Additional precautions are made against offsite form submissions when |
| 23 | +the restricted raw HTML mode is enabled. |
| 24 | + |
| 25 | +Some small localization and user interface updates are also included. |
| 26 | + |
9 | 27 | * (bug 6051) Improvement to German localisation (de) |
10 | 28 | * (bug 6017) Update bookstore list for German language (de) |
11 | 29 | * (bug 6138) Minor grammar tweak in "loginreqlink" |
12 | 30 | * (bug 5957) Update for Hebrew language (he) |
| 31 | +* Fix oddity with open tag parameters getting stuck on </li> |
| 32 | +* (bug 5384) Fix <!-- comments --> in <ref> extension |
| 33 | +* Nesting of different tag extensions and comments should now work more |
| 34 | + consistently and more safely. A cleaner, one-pass tag strip lets the |
| 35 | + 'outer' tag either take source (<nowiki>-style) or pass it down to |
| 36 | + further parsing (<ref>-style). There should no longer be surprise |
| 37 | + expansion of foreign extensions inside HTML output, or differences |
| 38 | + in behavior based on the order tags are loaded. |
| 39 | +* (bug 885) Pre-save transform no longer silently appends close tags |
| 40 | +* Pre-save transform no longer changes the case of close tags |
| 41 | +* Edit security precautions in raw HTML mode, etc |
13 | 42 | |
| 43 | + |
14 | 44 | == MediaWiki 1.6.6 == |
15 | 45 | |
16 | 46 | May 23, 2006 |
Index: branches/REL1_6/phase3/languages/Messages.php |
— | — | @@ -511,6 +511,13 @@ |
512 | 512 | Please try again. If it still doesn\'t work, try logging out and logging back in.</strong>', |
513 | 513 | 'previewconflict' => 'This preview reflects the text in the upper |
514 | 514 | text editing area as it will appear if you choose to save.', |
| 515 | +'session_fail_preview_html' => '<strong>Sorry! We could not process your edit due to a loss of session data.</strong> |
| 516 | + |
| 517 | +\'\'Because this wiki has raw HTML enabled, the preview is hidden as a precaution against JavaScript attacks.\'\' |
| 518 | + |
| 519 | +<strong>If this is a legitimate edit attempt, please try again. If it still doesn\'t work, try logging out and logging back in.</strong>', |
| 520 | +'previewconflict' => 'This preview reflects the text in the upper |
| 521 | +text editing area as it will appear if you choose to save.', |
515 | 522 | 'importing' => 'Importing $1', |
516 | 523 | 'editing' => 'Editing $1', |
517 | 524 | 'editingsection' => 'Editing $1 (section)', |