*/
private $mLinkHeader = [];
+ /**
+ * @var string The nonce for Content-Security-Policy
+ */
+ private $CSPNonce;
+
/**
* Constructor for OutputPage. This should not be called directly.
* Instead a new RequestContext should be created and it will implicitly create
if ( is_null( $version ) ) {
$version = $this->getConfig()->get( 'StyleVersion' );
}
- $this->addScript( Html::linkedScript( wfAppendQuery( $path, $version ) ) );
+ $this->addScript( Html::linkedScript( wfAppendQuery( $path, $version ), $this->getCSPNonce() ) );
}
/**
* @param string $script JavaScript text, no script tags
*/
public function addInlineScript( $script ) {
- $this->mScripts .= Html::inlineScript( $script );
+ $this->mScripts .= Html::inlineScript( "\n$script\n", $this->getCSPNonce() ) . "\n";
}
/**
$response->header( "X-Frame-Options: $frameOptions" );
}
+ ContentSecurityPolicy::sendHeaders( $this );
+
if ( $this->mArticleBodyOnly ) {
echo $this->mBodytext;
} else {
}
$pieces[] = Html::element( 'title', null, $this->getHTMLTitle() );
- $pieces[] = $this->getRlClient()->getHeadHtml();
+ $pieces[] = $this->getRlClient()->getHeadHtml( $this->getCSPNonce() );
$pieces[] = $this->buildExemptModules();
$pieces = array_merge( $pieces, array_values( $this->getHeadLinksArray() ) );
$pieces = array_merge( $pieces, array_values( $this->mHeadItems ) );
ResourceLoaderContext::newDummyContext(),
[ 'html5shiv' ],
ResourceLoaderModule::TYPE_SCRIPTS,
- [ 'sync' => true ]
+ [ 'sync' => true ],
+ $this->getCSPNonce()
) .
'<![endif]-->';
$this->getRlClientContext(),
$modules,
$only,
- $extraQuery
+ $extraQuery,
+ $this->getCSPNonce()
);
}
$chunks[] = ResourceLoader::makeInlineScript(
ResourceLoader::makeConfigSetScript(
[ 'wgPageParseReport' => $this->limitReportJSData ]
- )
+ ),
+ $this->getCSPNonce()
);
}
);
}
}
+
+ /**
+ * Get (and set if not yet set) the CSP nonce.
+ *
+ * This value needs to be included in any <script> tags on the
+ * page.
+ *
+ * @return string|bool Nonce or false to mean don't output nonce
+ * @since 1.32
+ */
+ public function getCSPNonce() {
+ if ( !ContentSecurityPolicy::isEnabled( $this->getConfig() ) ) {
+ return false;
+ }
+ if ( $this->CSPNonce === null ) {
+ // XXX It might be expensive to generate randomness
+ // on every request, on windows.
+ $rand = MWCryptRand::generate( 15 );
+ $this->CSPNonce = base64_encode( $rand );
+ }
+ return $this->CSPNonce;
+ }
}