| Index: trunk/phase3/includes/diff/DifferenceEngine.php |
| — | — | @@ -115,6 +115,8 @@ |
| 116 | 116 | global $wgUser, $wgOut, $wgUseExternalEditor, $wgUseRCPatrol; |
| 117 | 117 | wfProfileIn( __METHOD__ ); |
| 118 | 118 | |
| | 119 | + # Allow frames except in certain special cases |
| | 120 | + $wgOut->allowClickjacking(); |
| 119 | 121 | |
| 120 | 122 | # If external diffs are enabled both globally and for the user, |
| 121 | 123 | # we'll use the application/x-external-editor interface to call |
| — | — | @@ -206,6 +208,7 @@ |
| 207 | 209 | // Check if page is editable |
| 208 | 210 | $editable = $this->mNewRev->getTitle()->userCan( 'edit' ); |
| 209 | 211 | if ( $editable && $this->mNewRev->isCurrent() && $wgUser->isAllowed( 'rollback' ) ) { |
| | 212 | + $wgOut->preventClickjacking(); |
| 210 | 213 | $rollback = '   ' . $sk->generateRollback( $this->mNewRev ); |
| 211 | 214 | } else { |
| 212 | 215 | $rollback = ''; |
| — | — | @@ -243,6 +246,7 @@ |
| 244 | 247 | } |
| 245 | 248 | // Build the link |
| 246 | 249 | if ( $rcid ) { |
| | 250 | + $wgOut->preventClickjacking(); |
| 247 | 251 | $token = $wgUser->editToken( $rcid ); |
| 248 | 252 | $patrol = ' <span class="patrollink">[' . $sk->link( |
| 249 | 253 | $this->mTitle, |
| — | — | @@ -471,6 +475,7 @@ |
| 472 | 476 | if ( $this->mRcidMarkPatrolled && $this->mTitle->quickUserCan( 'patrol' ) ) { |
| 473 | 477 | $sk = $wgUser->getSkin(); |
| 474 | 478 | $token = $wgUser->editToken( $this->mRcidMarkPatrolled ); |
| | 479 | + $wgOut->preventClickjacking(); |
| 475 | 480 | $wgOut->addHTML( |
| 476 | 481 | "<div class='patrollink'>[" . $sk->link( |
| 477 | 482 | $this->mTitle, |
| Index: trunk/phase3/includes/Article.php |
| — | — | @@ -886,6 +886,9 @@ |
| 887 | 887 | return; |
| 888 | 888 | } |
| 889 | 889 | |
| | 890 | + # Allow frames by default |
| | 891 | + $wgOut->allowClickjacking(); |
| | 892 | + |
| 890 | 893 | if ( !$wgUseETag && !$this->mTitle->quickUserCan( 'edit' ) ) { |
| 891 | 894 | $parserOptions->setEditSection( false ); |
| 892 | 895 | } |
| — | — | @@ -1304,6 +1307,7 @@ |
| 1305 | 1308 | |
| 1306 | 1309 | $sk = $wgUser->getSkin(); |
| 1307 | 1310 | $token = $wgUser->editToken( $rcid ); |
| | 1311 | + $wgOut->preventClickjacking(); |
| 1308 | 1312 | |
| 1309 | 1313 | $wgOut->addHTML( |
| 1310 | 1314 | "<div class='patrollink'>" . |
| — | — | @@ -1584,6 +1588,8 @@ |
| 1585 | 1589 | return; |
| 1586 | 1590 | } |
| 1587 | 1591 | |
| | 1592 | + $wgOut->preventClickjacking(); |
| | 1593 | + |
| 1588 | 1594 | $tbtext = ""; |
| 1589 | 1595 | foreach ( $tbs as $o ) { |
| 1590 | 1596 | $rmvtxt = ""; |
| Index: trunk/phase3/includes/ImagePage.php |
| — | — | @@ -601,6 +601,7 @@ |
| 602 | 602 | $this->loadFile(); |
| 603 | 603 | $pager = new ImageHistoryPseudoPager( $this ); |
| 604 | 604 | $wgOut->addHTML( $pager->getBody() ); |
| | 605 | + $wgOut->preventClickjacking( $pager->getPreventClickjacking() ); |
| 605 | 606 | |
| 606 | 607 | $this->img->resetHistory(); // free db resources |
| 607 | 608 | |
| — | — | @@ -828,6 +829,7 @@ |
| 829 | 830 | class ImageHistoryList { |
| 830 | 831 | |
| 831 | 832 | protected $imagePage, $img, $skin, $title, $repo, $showThumb; |
| | 833 | + protected $preventClickjacking = false; |
| 832 | 834 | |
| 833 | 835 | public function __construct( $imagePage ) { |
| 834 | 836 | global $wgUser, $wgShowArchiveThumbnails; |
| — | — | @@ -954,6 +956,7 @@ |
| 955 | 957 | # Don't link to unviewable files |
| 956 | 958 | $row .= '<span class="history-deleted">' . $wgLang->timeAndDate( $timestamp, true ) . '</span>'; |
| 957 | 959 | } elseif ( $file->isDeleted( File::DELETED_FILE ) ) { |
| | 960 | + $this->preventClickjacking(); |
| 958 | 961 | $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); |
| 959 | 962 | # Make a link to review the image |
| 960 | 963 | $url = $this->skin->link( |
| — | — | @@ -1041,9 +1044,19 @@ |
| 1042 | 1045 | return wfMsgHtml( 'filehist-nothumb' ); |
| 1043 | 1046 | } |
| 1044 | 1047 | } |
| | 1048 | + |
| | 1049 | + protected function preventClickjacking( $enable = true ) { |
| | 1050 | + $this->preventClickjacking = $enable; |
| | 1051 | + } |
| | 1052 | + |
| | 1053 | + public function getPreventClickjacking() { |
| | 1054 | + return $this->preventClickjacking; |
| | 1055 | + } |
| 1045 | 1056 | } |
| 1046 | 1057 | |
| 1047 | 1058 | class ImageHistoryPseudoPager extends ReverseChronologicalPager { |
| | 1059 | + protected $preventClickjacking = false; |
| | 1060 | + |
| 1048 | 1061 | function __construct( $imagePage ) { |
| 1049 | 1062 | parent::__construct(); |
| 1050 | 1063 | $this->mImagePage = $imagePage; |
| — | — | @@ -1084,6 +1097,10 @@ |
| 1085 | 1098 | $s .= $list->imageHistoryLine( !$file->isOld(), $file ); |
| 1086 | 1099 | } |
| 1087 | 1100 | $s .= $list->endImageHistoryList( $navLink ); |
| | 1101 | + |
| | 1102 | + if ( $list->getPreventClickjacking() ) { |
| | 1103 | + $this->preventClickjacking(); |
| | 1104 | + } |
| 1088 | 1105 | } |
| 1089 | 1106 | return $s; |
| 1090 | 1107 | } |
| — | — | @@ -1166,4 +1183,13 @@ |
| 1167 | 1184 | } |
| 1168 | 1185 | $this->mQueryDone = true; |
| 1169 | 1186 | } |
| | 1187 | + |
| | 1188 | + protected function preventClickjacking( $enable = true ) { |
| | 1189 | + $this->preventClickjacking = $enable; |
| | 1190 | + } |
| | 1191 | + |
| | 1192 | + public function getPreventClickjacking() { |
| | 1193 | + return $this->preventClickjacking; |
| | 1194 | + } |
| | 1195 | + |
| 1170 | 1196 | } |
| Index: trunk/phase3/includes/HTMLForm.php |
| — | — | @@ -342,6 +342,9 @@ |
| 343 | 343 | function displayForm( $submitResult ) { |
| 344 | 344 | global $wgOut; |
| 345 | 345 | |
| | 346 | + # For good measure (it is the default) |
| | 347 | + $wgOut->preventClickjacking(); |
| | 348 | + |
| 346 | 349 | $html = '' |
| 347 | 350 | . $this->getErrors( $submitResult ) |
| 348 | 351 | . $this->mHeader |
| Index: trunk/phase3/includes/OutputPage.php |
| — | — | @@ -48,6 +48,7 @@ |
| 49 | 49 | var $mPageTitleActionText = ''; |
| 50 | 50 | var $mParseWarnings = array(); |
| 51 | 51 | var $mSquidMaxage = 0; |
| | 52 | + var $mPreventClickjacking = true; |
| 52 | 53 | var $mRevisionId = null; |
| 53 | 54 | protected $mTitle = null; |
| 54 | 55 | |
| — | — | @@ -1443,6 +1444,41 @@ |
| 1444 | 1445 | } |
| 1445 | 1446 | |
| 1446 | 1447 | /** |
| | 1448 | + * Set a flag which will cause an X-Frame-Options header appropriate for |
| | 1449 | + * edit pages to be sent. The header value is controlled by |
| | 1450 | + * $wgEditPageFrameOptions. |
| | 1451 | + * |
| | 1452 | + * This is the default for special pages. If you display a CSRF-protected |
| | 1453 | + * form on an ordinary view page, then you need to call this function. |
| | 1454 | + */ |
| | 1455 | + public function preventClickjacking( $enable = true ) { |
| | 1456 | + $this->mPreventClickjacking = $enable; |
| | 1457 | + } |
| | 1458 | + |
| | 1459 | + /** |
| | 1460 | + * Turn off frame-breaking. Alias for $this->preventClickjacking(false). |
| | 1461 | + * This can be called from pages which do not contain any CSRF-protected |
| | 1462 | + * HTML form. |
| | 1463 | + */ |
| | 1464 | + public function allowClickjacking() { |
| | 1465 | + $this->mPreventClickjacking = false; |
| | 1466 | + } |
| | 1467 | + |
| | 1468 | + /** |
| | 1469 | + * Get the X-Frame-Options header value (without the name part), or false |
| | 1470 | + * if there isn't one. This is used by Skin to determine whether to enable |
| | 1471 | + * JavaScript frame-breaking, for clients that don't support X-Frame-Options. |
| | 1472 | + */ |
| | 1473 | + public function getFrameOptions() { |
| | 1474 | + global $wgBreakFrames, $wgEditPageFrameOptions; |
| | 1475 | + if ( $wgBreakFrames ) { |
| | 1476 | + return 'DENY'; |
| | 1477 | + } elseif ( $this->mPreventClickjacking && $wgEditPageFrameOptions ) { |
| | 1478 | + return $wgEditPageFrameOptions; |
| | 1479 | + } |
| | 1480 | + } |
| | 1481 | + |
| | 1482 | + /** |
| 1447 | 1483 | * Send cache control HTTP headers |
| 1448 | 1484 | */ |
| 1449 | 1485 | public function sendCacheControl() { |
| — | — | @@ -1665,6 +1701,12 @@ |
| 1666 | 1702 | $wgRequest->response()->header( "Content-type: $wgMimeType; charset={$wgOutputEncoding}" ); |
| 1667 | 1703 | $wgRequest->response()->header( 'Content-language: ' . $wgLanguageCode ); |
| 1668 | 1704 | |
| | 1705 | + // Prevent framing, if requested |
| | 1706 | + $frameOptions = $this->getFrameOptions(); |
| | 1707 | + if ( $frameOptions ) { |
| | 1708 | + $wgRequest->response()->header( "X-Frame-Options: $frameOptions" ); |
| | 1709 | + } |
| | 1710 | + |
| 1669 | 1711 | if ( $this->mArticleBodyOnly ) { |
| 1670 | 1712 | $this->out( $this->mBodytext ); |
| 1671 | 1713 | } else { |
| Index: trunk/phase3/includes/HistoryPage.php |
| — | — | @@ -171,6 +171,7 @@ |
| 172 | 172 | $pager->getBody() . |
| 173 | 173 | $pager->getNavigationBar() |
| 174 | 174 | ); |
| | 175 | + $wgOut->preventClickjacking( $pager->getPreventClickjacking() ); |
| 175 | 176 | |
| 176 | 177 | wfProfileOut( __METHOD__ ); |
| 177 | 178 | } |
| — | — | @@ -309,6 +310,7 @@ |
| 310 | 311 | class HistoryPager extends ReverseChronologicalPager { |
| 311 | 312 | public $lastRow = false, $counter, $historyPage, $title, $buttons, $conds; |
| 312 | 313 | protected $oldIdChecked; |
| | 314 | + protected $preventClickjacking = false; |
| 313 | 315 | |
| 314 | 316 | function __construct( $historyPage, $year = '', $month = '', $tagFilter = '', $conds = array() ) { |
| 315 | 317 | parent::__construct(); |
| — | — | @@ -399,6 +401,7 @@ |
| 400 | 402 | ) . "\n"; |
| 401 | 403 | |
| 402 | 404 | if ( $wgUser->isAllowed( 'deleterevision' ) ) { |
| | 405 | + $this->preventClickjacking(); |
| 403 | 406 | $float = $wgContLang->alignEnd(); |
| 404 | 407 | # Note bug #20966, <button> is non-standard in IE<8 |
| 405 | 408 | $element = Html::element( 'button', |
| — | — | @@ -415,6 +418,7 @@ |
| 416 | 419 | $this->buttons .= $element; |
| 417 | 420 | } |
| 418 | 421 | if ( $wgUser->isAllowed( 'revisionmove' ) ) { |
| | 422 | + $this->preventClickjacking(); |
| 419 | 423 | $float = $wgContLang->alignEnd(); |
| 420 | 424 | # Note bug #20966, <button> is non-standard in IE<8 |
| 421 | 425 | $element = Html::element( 'button', |
| — | — | @@ -516,6 +520,7 @@ |
| 517 | 521 | $del = ''; |
| 518 | 522 | // Show checkboxes for each revision |
| 519 | 523 | if ( $wgUser->isAllowed( 'deleterevision' ) || $wgUser->isAllowed( 'revisionmove' ) ) { |
| | 524 | + $this->preventClickjacking(); |
| 520 | 525 | // If revision was hidden from sysops, disable the checkbox |
| 521 | 526 | // However, if the user has revisionmove rights, we cannot disable the checkbox |
| 522 | 527 | if ( !$rev->userCan( Revision::DELETED_RESTRICTED ) && !$wgUser->isAllowed( 'revisionmove' ) ) { |
| — | — | @@ -565,6 +570,7 @@ |
| 566 | 571 | # Rollback and undo links |
| 567 | 572 | if ( !is_null( $next ) && is_object( $next ) ) { |
| 568 | 573 | if ( $latest && $this->title->userCan( 'rollback' ) && $this->title->userCan( 'edit' ) ) { |
| | 574 | + $this->preventClickjacking(); |
| 569 | 575 | $tools[] = '<span class="mw-rollback-link">' . |
| 570 | 576 | $this->getSkin()->buildRollbackLink( $rev ) . '</span>'; |
| 571 | 577 | } |
| — | — | @@ -754,6 +760,20 @@ |
| 755 | 761 | return ''; |
| 756 | 762 | } |
| 757 | 763 | } |
| | 764 | + |
| | 765 | + /** |
| | 766 | + * This is called if a write operation is possible from the generated HTML |
| | 767 | + */ |
| | 768 | + function preventClickjacking( $enable = true ) { |
| | 769 | + $this->preventClickjacking = $enable; |
| | 770 | + } |
| | 771 | + |
| | 772 | + /** |
| | 773 | + * Get the "prevent clickjacking" flag |
| | 774 | + */ |
| | 775 | + function getPreventClickjacking() { |
| | 776 | + return $this->preventClickjacking; |
| | 777 | + } |
| 758 | 778 | } |
| 759 | 779 | |
| 760 | 780 | /** |
| Index: trunk/phase3/includes/installer/WebInstallerOutput.php |
| — | — | @@ -162,7 +162,8 @@ |
| 163 | 163 | $this->headerDone = true; |
| 164 | 164 | $dbTypes = $this->parent->getDBTypes(); |
| 165 | 165 | |
| 166 | | - $this->parent->request->response()->header("Content-Type: text/html; charset=utf-8"); |
| | 166 | + $this->parent->request->response()->header( 'Content-Type: text/html; charset=utf-8' ); |
| | 167 | + $this->parent->request->response()->header( 'X-Frame-Options: DENY' ); |
| 167 | 168 | if ( $this->redirectTarget ) { |
| 168 | 169 | $this->parent->request->response()->header( 'Location: '.$this->redirectTarget ); |
| 169 | 170 | return; |
| Index: trunk/phase3/includes/resourceloader/ResourceLoaderStartUpModule.php |
| — | — | @@ -30,7 +30,7 @@ |
| 31 | 31 | |
| 32 | 32 | protected function getConfig( $context ) { |
| 33 | 33 | global $wgLoadScript, $wgScript, $wgStylePath, $wgScriptExtension, |
| 34 | | - $wgArticlePath, $wgScriptPath, $wgServer, $wgContLang, $wgBreakFrames, |
| | 34 | + $wgArticlePath, $wgScriptPath, $wgServer, $wgContLang, |
| 35 | 35 | $wgVariantArticlePath, $wgActionPaths, $wgUseAjax, $wgVersion, |
| 36 | 36 | $wgEnableAPI, $wgEnableWriteAPI, $wgDBname, $wgEnableMWSuggest, |
| 37 | 37 | $wgSitename, $wgFileExtensions; |
| — | — | @@ -66,7 +66,6 @@ |
| 67 | 67 | 'wgServer' => $wgServer, |
| 68 | 68 | 'wgUserLanguage' => $context->getLanguage(), |
| 69 | 69 | 'wgContentLanguage' => $wgContLang->getCode(), |
| 70 | | - 'wgBreakFrames' => $wgBreakFrames, |
| 71 | 70 | 'wgVersion' => $wgVersion, |
| 72 | 71 | 'wgEnableAPI' => $wgEnableAPI, |
| 73 | 72 | 'wgEnableWriteAPI' => $wgEnableWriteAPI, |
| Index: trunk/phase3/includes/DefaultSettings.php |
| — | — | @@ -2261,12 +2261,33 @@ |
| 2262 | 2262 | $wgEnableTooltipsAndAccesskeys = true; |
| 2263 | 2263 | |
| 2264 | 2264 | /** |
| 2265 | | - * Break out of framesets. This can be used to prevent external sites from |
| 2266 | | - * framing your site with ads. |
| | 2265 | + * Break out of framesets. This can be used to prevent clickjacking attacks, |
| | 2266 | + * or to prevent external sites from framing your site with ads. |
| 2267 | 2267 | */ |
| 2268 | 2268 | $wgBreakFrames = false; |
| 2269 | 2269 | |
| 2270 | 2270 | /** |
| | 2271 | + * The X-Frame-Options header to send on pages sensitive to clickjacking |
| | 2272 | + * attacks, such as edit pages. This prevents those pages from being displayed |
| | 2273 | + * in a frame or iframe. The options are: |
| | 2274 | + * |
| | 2275 | + * - 'DENY': Do not allow framing. This is recommended for most wikis. |
| | 2276 | + * |
| | 2277 | + * - 'SAMEORIGIN': Allow framing by pages on the same domain. This can be used |
| | 2278 | + * to allow framing within a trusted domain. This is insecure if there |
| | 2279 | + * is a page on the same domain which allows framing of arbitrary URLs. |
| | 2280 | + * |
| | 2281 | + * - false: Allow all framing. This opens up the wiki to XSS attacks and thus |
| | 2282 | + * full compromise of local user accounts. Private wikis behind a |
| | 2283 | + * corporate firewall are especially vulnerable. This is not |
| | 2284 | + * recommended. |
| | 2285 | + * |
| | 2286 | + * For extra safety, set $wgBreakFrames = true, to prevent framing on all pages, |
| | 2287 | + * not just edit pages. |
| | 2288 | + */ |
| | 2289 | +$wgEditPageFrameOptions = 'DENY'; |
| | 2290 | + |
| | 2291 | +/** |
| 2271 | 2292 | * Disable output compression (enabled by default if zlib is available) |
| 2272 | 2293 | */ |
| 2273 | 2294 | $wgDisableOutputCompression = false; |
| Index: trunk/phase3/includes/specials/SpecialAllpages.php |
| — | — | @@ -62,6 +62,7 @@ |
| 63 | 63 | |
| 64 | 64 | $this->setHeaders(); |
| 65 | 65 | $this->outputHeader(); |
| | 66 | + $wgOut->allowClickjacking(); |
| 66 | 67 | |
| 67 | 68 | # GET values |
| 68 | 69 | $from = $wgRequest->getVal( 'from', null ); |
| Index: trunk/phase3/includes/specials/SpecialCategories.php |
| — | — | @@ -35,6 +35,7 @@ |
| 36 | 36 | |
| 37 | 37 | $this->setHeaders(); |
| 38 | 38 | $this->outputHeader(); |
| | 39 | + $wgOut->allowClickjacking(); |
| 39 | 40 | |
| 40 | 41 | $from = $wgRequest->getText( 'from', $par ); |
| 41 | 42 | |
| Index: trunk/phase3/includes/specials/SpecialSpecialpages.php |
| — | — | @@ -33,8 +33,10 @@ |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | 36 | function execute( $par ) { |
| | 37 | + global $wgOut; |
| 37 | 38 | $this->setHeaders(); |
| 38 | 39 | $this->outputHeader(); |
| | 40 | + $wgOut->allowClickjacking(); |
| 39 | 41 | |
| 40 | 42 | $groups = $this->getPageGroups(); |
| 41 | 43 | |
| Index: trunk/phase3/includes/specials/SpecialContributions.php |
| — | — | @@ -143,6 +143,7 @@ |
| 144 | 144 | '<p>' . $pager->getNavigationBar() . '</p>' |
| 145 | 145 | ); |
| 146 | 146 | } |
| | 147 | + $wgOut->preventClickjacking( $pager->getPreventClickjacking() ); |
| 147 | 148 | |
| 148 | 149 | |
| 149 | 150 | # Show the appropriate "footer" message - WHOIS tools, etc. |
| — | — | @@ -485,6 +486,7 @@ |
| 486 | 487 | public $mDefaultDirection = true; |
| 487 | 488 | var $messages, $target; |
| 488 | 489 | var $namespace = '', $mDb; |
| | 490 | + var $preventClickjacking = false; |
| 489 | 491 | |
| 490 | 492 | function __construct( $options ) { |
| 491 | 493 | parent::__construct(); |
| — | — | @@ -633,6 +635,7 @@ |
| 634 | 636 | if( !$row->page_is_new && $page->quickUserCan( 'rollback' ) |
| 635 | 637 | && $page->quickUserCan( 'edit' ) ) |
| 636 | 638 | { |
| | 639 | + $this->preventClickjacking(); |
| 637 | 640 | $topmarktext .= ' '.$sk->generateRollback( $rev ); |
| 638 | 641 | } |
| 639 | 642 | } |
| — | — | @@ -753,4 +756,11 @@ |
| 754 | 757 | } |
| 755 | 758 | } |
| 756 | 759 | |
| | 760 | + protected function preventClickjacking() { |
| | 761 | + $this->preventClickjacking = true; |
| | 762 | + } |
| | 763 | + |
| | 764 | + public function getPreventClickjacking() { |
| | 765 | + return $this->preventClickjacking; |
| | 766 | + } |
| 757 | 767 | } |
| Index: trunk/phase3/includes/specials/SpecialVersion.php |
| — | — | @@ -53,6 +53,7 @@ |
| 54 | 54 | |
| 55 | 55 | $this->setHeaders(); |
| 56 | 56 | $this->outputHeader(); |
| | 57 | + $wgOut->allowClickjacking(); |
| 57 | 58 | |
| 58 | 59 | $wgOut->addHTML( Xml::openElement( 'div', |
| 59 | 60 | array( 'dir' => $wgContLang->getDir() ) ) ); |
| Index: trunk/phase3/includes/specials/SpecialSearch.php |
| — | — | @@ -39,10 +39,11 @@ |
| 40 | 40 | * @param $par String or null |
| 41 | 41 | */ |
| 42 | 42 | public function execute( $par ) { |
| 43 | | - global $wgRequest, $wgUser; |
| | 43 | + global $wgRequest, $wgUser, $wgOut; |
| 44 | 44 | |
| 45 | 45 | $this->setHeaders(); |
| 46 | 46 | $this->outputHeader(); |
| | 47 | + $wgOut->allowClickjacking(); |
| 47 | 48 | |
| 48 | 49 | // Strip underscores from title parameter; most of the time we'll want |
| 49 | 50 | // text form here. But don't strip underscores from actual text params! |
| Index: trunk/phase3/includes/specials/SpecialLinkSearch.php |
| — | — | @@ -45,6 +45,7 @@ |
| 46 | 46 | function execute( $par ) { |
| 47 | 47 | global $wgOut, $wgRequest, $wgUrlProtocols, $wgMiserMode, $wgLang; |
| 48 | 48 | $this->setHeaders(); |
| | 49 | + $wgOut->allowClickjacking(); |
| 49 | 50 | |
| 50 | 51 | $target = $wgRequest->getVal( 'target', $par ); |
| 51 | 52 | $namespace = $wgRequest->getIntorNull( 'namespace', null ); |
| Index: trunk/phase3/includes/Skin.php |
| — | — | @@ -502,6 +502,7 @@ |
| 503 | 503 | 'wgUserGroups' => $wgUser->getEffectiveGroups(), |
| 504 | 504 | 'wgCurRevisionId' => isset( $wgArticle ) ? $wgArticle->getLatest() : 0, |
| 505 | 505 | 'wgCategories' => $wgOut->getCategories(), |
| | 506 | + 'wgBreakFrames' => $wgOut->getFrameOptions() == 'DENY', |
| 506 | 507 | ); |
| 507 | 508 | foreach ( $wgRestrictionTypes as $type ) { |
| 508 | 509 | $vars['wgRestriction' . ucfirst( $type )] = $wgTitle->getRestrictions( $type ); |