*/
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";
}
/**
}
/**
- * Add one or more modules recognized by ResourceLoader. Modules added
- * through this function will be loaded by ResourceLoader when the
- * page loads.
+ * Load one or more ResourceLoader modules on this page.
*
* @param string|array $modules Module name (string) or array of module names
*/
}
/**
- * Get the list of module JS to include on this page
+ * Get the list of script-only modules to load on this page.
*
* @param bool $filter
* @param string|null $position Unused
}
/**
- * Add only JS of one or more modules recognized by ResourceLoader. Module
- * scripts added through this function will be loaded by ResourceLoader when
- * the page loads.
+ * Load the scripts of one or more ResourceLoader modules, on this page.
+ *
+ * This method exists purely to provide the legacy behaviour of loading
+ * a module's scripts in the global scope, and without dependency resolution.
+ * See <https://phabricator.wikimedia.org/T188689>.
*
+ * @deprecated since 1.31 Use addModules() instead.
* @param string|array $modules Module name (string) or array of module names
*/
public function addModuleScripts( $modules ) {
}
/**
- * Get the list of module CSS to include on this page
+ * Get the list of style-only modules to load on this page.
*
* @param bool $filter
* @param string|null $position Unused
}
/**
- * Add only CSS of one or more modules recognized by ResourceLoader.
+ * Load the styles of one or more ResourceLoader modules on this page.
*
- * Module styles added through this function will be added using standard link CSS
- * tags, rather than as a combined Javascript and CSS package. Thus, they will
- * load when JavaScript is disabled (unless CSS also happens to be disabled).
+ * Module styles added through this function will be loaded as a stylesheet,
+ * using a standard `<link rel=stylesheet>` HTML tag, rather than as a combined
+ * Javascript and CSS package. Thus, they will even load when JavaScript is disabled.
*
* @param string|array $modules Module name (string) or array of module names
*/
$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;
+ }
}