getConfigFactory() ->makeConfig( 'templatestyles' ); } return self::$config; } /** * Get our Sanitizer * @param string $class Class to limit selectors to * @return Sanitizer */ public static function getSanitizer( $class ) { if ( !isset( self::$sanitizers[$class] ) ) { $config = self::getConfig(); $matcherFactory = new TemplateStylesMatcherFactory( $config->get( 'TemplateStylesAllowedUrls' ) ); $propertySanitizer = new StylePropertySanitizer( $matcherFactory ); $propertySanitizer->setKnownProperties( array_diff_key( $propertySanitizer->getKnownProperties(), array_flip( $config->get( 'TemplateStylesPropertyBlacklist' ) ) ) ); Hooks::run( 'TemplateStylesPropertySanitizer', [ &$propertySanitizer, $matcherFactory ] ); $atRuleBlacklist = array_flip( $config->get( 'TemplateStylesAtRuleBlacklist' ) ); $ruleSanitizers = [ 'styles' => new StyleRuleSanitizer( $matcherFactory->cssSelectorList(), $propertySanitizer, [ 'prependSelectors' => [ new Token( Token::T_DELIM, '.' ), new Token( Token::T_IDENT, $class ), new Token( Token::T_WHITESPACE ), ], ] ), '@font-face' => new TemplateStylesFontFaceAtRuleSanitizer( $matcherFactory ), '@font-feature-values' => new FontFeatureValuesAtRuleSanitizer( $matcherFactory ), '@keyframes' => new KeyframesAtRuleSanitizer( $matcherFactory, $propertySanitizer ), '@page' => new PageAtRuleSanitizer( $matcherFactory, $propertySanitizer ), '@media' => new MediaAtRuleSanitizer( $matcherFactory->cssMediaQueryList() ), '@supports' => new SupportsAtRuleSanitizer( $matcherFactory, [ 'declarationSanitizer' => $propertySanitizer, ] ), ]; $ruleSanitizers = array_diff_key( $ruleSanitizers, $atRuleBlacklist ); if ( isset( $ruleSanitizers['@media'] ) ) { // In case @media was blacklisted $ruleSanitizers['@media']->setRuleSanitizers( $ruleSanitizers ); } if ( isset( $ruleSanitizers['@supports'] ) ) { // In case @supports was blacklisted $ruleSanitizers['@supports']->setRuleSanitizers( $ruleSanitizers ); } $allRuleSanitizers = $ruleSanitizers + [ // Omit @import, it's not secure. Maybe someday we'll make an "@-mw-import" or something. '@namespace' => new NamespaceAtRuleSanitizer( $matcherFactory ), ]; $allRuleSanitizers = array_diff_key( $allRuleSanitizers, $atRuleBlacklist ); $sanitizer = new StylesheetSanitizer( $allRuleSanitizers ); Hooks::run( 'TemplateStylesStylesheetSanitizer', [ &$sanitizer, $propertySanitizer, $matcherFactory ] ); self::$sanitizers[$class] = $sanitizer; } return self::$sanitizers[$class]; } /** * Update $wgTextModelsToParse */ public static function onRegistration() { // This gets called before ConfigFactory is set up, so I guess we need // to use globals. global $wgTextModelsToParse, $wgTemplateStylesAutoParseContent; if ( in_array( CONTENT_MODEL_CSS, $wgTextModelsToParse, true ) && $wgTemplateStylesAutoParseContent ) { $wgTextModelsToParse[] = 'sanitized-css'; } } /** * Add `` to the parser. * @param Parser &$parser Parser object being cleared * @return bool */ public static function onParserFirstCallInit( &$parser ) { $parser->setHook( 'templatestyles', 'TemplateStylesHooks::handleTag' ); $parser->extTemplateStylesCache = new MapCacheLRU( 100 ); // 100 is arbitrary return true; } /** * Fix Tidy screw-ups * * It seems some versions of Tidy try to wrap the contents of a `