Index: branches/REL1_17/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, |
— | — | @@ -478,6 +482,7 @@ |
479 | 483 | if ( $this->mRcidMarkPatrolled && $this->mTitle->quickUserCan( 'patrol' ) ) { |
480 | 484 | $sk = $wgUser->getSkin(); |
481 | 485 | $token = $wgUser->editToken( $this->mRcidMarkPatrolled ); |
| 486 | + $wgOut->preventClickjacking(); |
482 | 487 | $wgOut->addHTML( |
483 | 488 | "<div class='patrollink'>[" . $sk->link( |
484 | 489 | $this->mTitle, |
Index: branches/REL1_17/phase3/includes/Article.php |
— | — | @@ -893,6 +893,9 @@ |
894 | 894 | return; |
895 | 895 | } |
896 | 896 | |
| 897 | + # Allow frames by default |
| 898 | + $wgOut->allowClickjacking(); |
| 899 | + |
897 | 900 | if ( !$wgUseETag && !$this->mTitle->quickUserCan( 'edit' ) ) { |
898 | 901 | $parserOptions->setEditSection( false ); |
899 | 902 | } |
— | — | @@ -1311,6 +1314,7 @@ |
1312 | 1315 | |
1313 | 1316 | $sk = $wgUser->getSkin(); |
1314 | 1317 | $token = $wgUser->editToken( $rcid ); |
| 1318 | + $wgOut->preventClickjacking(); |
1315 | 1319 | |
1316 | 1320 | $wgOut->addHTML( |
1317 | 1321 | "<div class='patrollink'>" . |
— | — | @@ -1591,6 +1595,8 @@ |
1592 | 1596 | return; |
1593 | 1597 | } |
1594 | 1598 | |
| 1599 | + $wgOut->preventClickjacking(); |
| 1600 | + |
1595 | 1601 | $tbtext = ""; |
1596 | 1602 | foreach ( $tbs as $o ) { |
1597 | 1603 | $rmvtxt = ""; |
Property changes on: branches/REL1_17/phase3/includes/Article.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
1598 | 1604 | Merged /trunk/phase3/includes/Article.php:r79561 |
Index: branches/REL1_17/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: branches/REL1_17/phase3/includes/HTMLForm.php |
— | — | @@ -327,6 +327,9 @@ |
328 | 328 | function displayForm( $submitResult ) { |
329 | 329 | global $wgOut; |
330 | 330 | |
| 331 | + # For good measure (it is the default) |
| 332 | + $wgOut->preventClickjacking(); |
| 333 | + |
331 | 334 | $html = '' |
332 | 335 | . $this->getErrors( $submitResult ) |
333 | 336 | . $this->mHeader |
Index: branches/REL1_17/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() { |
— | — | @@ -1666,6 +1702,12 @@ |
1667 | 1703 | $wgRequest->response()->header( "Content-type: $wgMimeType; charset={$wgOutputEncoding}" ); |
1668 | 1704 | $wgRequest->response()->header( 'Content-language: ' . $wgLanguageCode ); |
1669 | 1705 | |
| 1706 | + // Prevent framing, if requested |
| 1707 | + $frameOptions = $this->getFrameOptions(); |
| 1708 | + if ( $frameOptions ) { |
| 1709 | + $wgRequest->response()->header( "X-Frame-Options: $frameOptions" ); |
| 1710 | + } |
| 1711 | + |
1670 | 1712 | if ( $this->mArticleBodyOnly ) { |
1671 | 1713 | $this->out( $this->mBodytext ); |
1672 | 1714 | } else { |
Property changes on: branches/REL1_17/phase3/includes/OutputPage.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
1673 | 1715 | Merged /trunk/phase3/includes/OutputPage.php:r79561 |
Index: branches/REL1_17/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 | /** |
Property changes on: branches/REL1_17/phase3/includes/HistoryPage.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
761 | 781 | Merged /trunk/phase3/includes/HistoryPage.php:r79561 |
Index: branches/REL1_17/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: branches/REL1_17/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: branches/REL1_17/phase3/includes/DefaultSettings.php |
— | — | @@ -2260,12 +2260,33 @@ |
2261 | 2261 | $wgEnableTooltipsAndAccesskeys = true; |
2262 | 2262 | |
2263 | 2263 | /** |
2264 | | - * Break out of framesets. This can be used to prevent external sites from |
2265 | | - * framing your site with ads. |
| 2264 | + * Break out of framesets. This can be used to prevent clickjacking attacks, |
| 2265 | + * or to prevent external sites from framing your site with ads. |
2266 | 2266 | */ |
2267 | 2267 | $wgBreakFrames = false; |
2268 | 2268 | |
2269 | 2269 | /** |
| 2270 | + * The X-Frame-Options header to send on pages sensitive to clickjacking |
| 2271 | + * attacks, such as edit pages. This prevents those pages from being displayed |
| 2272 | + * in a frame or iframe. The options are: |
| 2273 | + * |
| 2274 | + * - 'DENY': Do not allow framing. This is recommended for most wikis. |
| 2275 | + * |
| 2276 | + * - 'SAMEORIGIN': Allow framing by pages on the same domain. This can be used |
| 2277 | + * to allow framing within a trusted domain. This is insecure if there |
| 2278 | + * is a page on the same domain which allows framing of arbitrary URLs. |
| 2279 | + * |
| 2280 | + * - false: Allow all framing. This opens up the wiki to XSS attacks and thus |
| 2281 | + * full compromise of local user accounts. Private wikis behind a |
| 2282 | + * corporate firewall are especially vulnerable. This is not |
| 2283 | + * recommended. |
| 2284 | + * |
| 2285 | + * For extra safety, set $wgBreakFrames = true, to prevent framing on all pages, |
| 2286 | + * not just edit pages. |
| 2287 | + */ |
| 2288 | +$wgEditPageFrameOptions = 'DENY'; |
| 2289 | + |
| 2290 | +/** |
2270 | 2291 | * Disable output compression (enabled by default if zlib is available) |
2271 | 2292 | */ |
2272 | 2293 | $wgDisableOutputCompression = false; |
Index: branches/REL1_17/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: branches/REL1_17/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: branches/REL1_17/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: branches/REL1_17/phase3/includes/specials/SpecialContributions.php |
— | — | @@ -139,6 +139,7 @@ |
140 | 140 | '<p>' . $pager->getNavigationBar() . '</p>' |
141 | 141 | ); |
142 | 142 | } |
| 143 | + $wgOut->preventClickjacking( $pager->getPreventClickjacking() ); |
143 | 144 | |
144 | 145 | |
145 | 146 | # Show the appropriate "footer" message - WHOIS tools, etc. |
— | — | @@ -481,6 +482,7 @@ |
482 | 483 | public $mDefaultDirection = true; |
483 | 484 | var $messages, $target; |
484 | 485 | var $namespace = '', $mDb; |
| 486 | + var $preventClickjacking = false; |
485 | 487 | |
486 | 488 | function __construct( $options ) { |
487 | 489 | parent::__construct(); |
— | — | @@ -629,6 +631,7 @@ |
630 | 632 | if( !$row->page_is_new && $page->quickUserCan( 'rollback' ) |
631 | 633 | && $page->quickUserCan( 'edit' ) ) |
632 | 634 | { |
| 635 | + $this->preventClickjacking(); |
633 | 636 | $topmarktext .= ' '.$sk->generateRollback( $rev ); |
634 | 637 | } |
635 | 638 | } |
— | — | @@ -749,4 +752,11 @@ |
750 | 753 | } |
751 | 754 | } |
752 | 755 | |
| 756 | + protected function preventClickjacking() { |
| 757 | + $this->preventClickjacking = true; |
| 758 | + } |
| 759 | + |
| 760 | + public function getPreventClickjacking() { |
| 761 | + return $this->preventClickjacking; |
| 762 | + } |
753 | 763 | } |
Index: branches/REL1_17/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() ) ) ); |
Property changes on: branches/REL1_17/phase3/includes/specials/SpecialVersion.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
60 | 61 | Merged /trunk/phase3/includes/specials/SpecialVersion.php:r79561 |
Index: branches/REL1_17/phase3/includes/specials/SpecialSearch.php |
— | — | @@ -29,7 +29,9 @@ |
30 | 30 | * @param $par String: (default '') |
31 | 31 | */ |
32 | 32 | function wfSpecialSearch( $par = '' ) { |
33 | | - global $wgRequest, $wgUser; |
| 33 | + global $wgRequest, $wgUser, $wgOut; |
| 34 | + $wgOut->allowClickjacking(); |
| 35 | + |
34 | 36 | // Strip underscores from title parameter; most of the time we'll want |
35 | 37 | // text form here. But don't strip underscores from actual text params! |
36 | 38 | $titleParam = str_replace( '_', ' ', $par ); |
Property changes on: branches/REL1_17/phase3/includes/specials/SpecialSearch.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
37 | 39 | Merged /trunk/phase3/includes/specials/SpecialSearch.php:r79561 |
Index: branches/REL1_17/phase3/includes/specials/SpecialLinkSearch.php |
— | — | @@ -62,6 +62,7 @@ |
63 | 63 | |
64 | 64 | $self = Title::makeTitle( NS_SPECIAL, 'Linksearch' ); |
65 | 65 | |
| 66 | + $wgOut->allowClickjacking(); |
66 | 67 | $wgOut->addWikiMsg( 'linksearch-text', '<nowiki>' . $wgLang->commaList( $wgUrlProtocols ) . '</nowiki>' ); |
67 | 68 | $s = Xml::openElement( 'form', array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => $GLOBALS['wgScript'] ) ) . |
68 | 69 | Html::hidden( 'title', $self->getPrefixedDbKey() ) . |
Index: branches/REL1_17/phase3/includes/Skin.php |
— | — | @@ -440,6 +440,7 @@ |
441 | 441 | 'wgUserGroups' => $wgUser->getEffectiveGroups(), |
442 | 442 | 'wgCurRevisionId' => isset( $wgArticle ) ? $wgArticle->getLatest() : 0, |
443 | 443 | 'wgCategories' => $wgOut->getCategories(), |
| 444 | + 'wgBreakFrames' => $wgOut->getFrameOptions() == 'DENY', |
444 | 445 | ); |
445 | 446 | foreach ( $wgTitle->getRestrictionTypes() as $type ) { |
446 | 447 | $vars['wgRestriction' . ucfirst( $type )] = $wgTitle->getRestrictions( $type ); |