/** * Modifies the text editor XSS filter that will used for the given text format. * * Is only called when an EditorXssFilter will effectively be used; this hook * does not allow one to alter that decision. * * @param string &$editor_xss_filter_class * The text editor XSS filter class that will be used. * @param \Drupal\filter\FilterFormatInterface $format * The text format configuration entity. Provides context based upon which * one may want to adjust the filtering. * @param \Drupal\filter\FilterFormatInterface $original_format|null * (optional) The original text format configuration entity (when switching * text formats/editors). Also provides context based upon which one may want * to adjust the filtering. * * @see \Drupal\editor\EditorXssFilterInterface */ function hook_editor_xss_filter_alter(&$editor_xss_filter_class, FilterFormatInterface $format, FilterFormatInterface $original_format = NULL) { $filters = $format->filters()->getAll(); if (isset($filters['filter_wysiwyg']) && $filters['filter_wysiwyg']->status) { $editor_xss_filter_class = '\\Drupal\\filter_wysiwyg\\EditorXssFilter\\WysiwygFilter'; } }
/** * Returns an Ajax response to generate preview of embedded items. * * Expects the the HTML element as GET parameter. * * @param \Symfony\Component\HttpFoundation\Request $request * The request object. * @param \Drupal\filter\FilterFormatInterface $filter_format * The filter format. * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException * Throws an exception if 'value' parameter is not found in the request. * * @return \Symfony\Component\HttpFoundation\Response * The preview of the embedded item specified by the data attributes. */ public function preview(Request $request, FilterFormatInterface $filter_format) { $text = $request->get('value'); if ($text == '') { throw new NotFoundHttpException(); } $output = check_markup($text, $filter_format->id()); $response = new AjaxResponse(); $response->addCommand(new EmbedInsertCommand($output)); return $response; }
/** * Sets up the test. */ protected function setUp() { parent::setUp(); $this->installEntitySchema('file'); $this->installSchema('system', ['key_value_expire']); $this->installSchema('node', array('node_access')); $this->installSchema('file', array('file_usage')); $this->installConfig(['node']); // Add text formats. $this->format = FilterFormat::create(['format' => 'filtered_html', 'name' => 'Filtered HTML', 'weight' => 0, 'filters' => ['filter_align' => ['status' => TRUE], 'filter_caption' => ['status' => TRUE]]]); $this->format->save(); // Set up text editor. $editor = Editor::create(['format' => 'filtered_html', 'editor' => 'unicorn', 'image_upload' => ['max_size' => 100, 'scheme' => 'public', 'directory' => '', 'status' => TRUE]]); $editor->save(); // Create a node type for testing. $type = NodeType::create(['type' => 'page', 'name' => 'page']); $type->save(); node_add_body_field($type); $this->installEntitySchema('user'); \Drupal::service('router.builder')->rebuild(); }
/** * Test tokens for multilingual fields and entities. */ public function testMultilingualFields() { // Create an english term and add a german translation for it. $term = $this->createTerm($this->vocabulary, ['name' => 'english-test-term', 'langcode' => 'en', 'term_field' => ['value' => 'english-term-field-value', 'format' => $this->testFormat->id()]]); $term->addTranslation('de', ['name' => 'german-test-term', 'term_field' => ['value' => 'german-term-field-value', 'format' => $this->testFormat->id()]])->save(); $german_term = $term->getTranslation('de'); // Create an english node, add a german translation for it and add the // english term to the english node's entity reference field and the // german term to the german's entity reference field. $node = Node::create(['title' => 'english-node-title', 'type' => 'article', 'test_term_reference' => ['target_id' => $term->id()], 'test_field' => ['value' => 'test-english-field', 'format' => $this->testFormat->id()]]); $node->addTranslation('de', ['title' => 'german-node-title', 'test_term_reference' => ['target_id' => $german_term->id()], 'test_field' => ['value' => 'test-german-field', 'format' => $this->testFormat->id()]])->save(); // Verify the :title token of the english node and the :name token of the // english term it refers to. Also verify the value of the term's field. $this->assertTokens('node', ['node' => $node], ['title' => 'english-node-title', 'test_term_reference:entity:name' => 'english-test-term', 'test_term_reference:entity:term_field:value' => 'english-term-field-value', 'test_term_reference:entity:term_field' => 'english-term-field-value', 'test_field' => 'test-english-field', 'test_field:value' => 'test-english-field']); // Same test for the german node and its german term. $german_node = $node->getTranslation('de'); $this->assertTokens('node', ['node' => $german_node], ['title' => 'german-node-title', 'test_term_reference:entity:name' => 'german-test-term', 'test_term_reference:entity:term_field:value' => 'german-term-field-value', 'test_term_reference:entity:term_field' => 'german-term-field-value', 'test_field' => 'test-german-field', 'test_field:value' => 'test-german-field']); // If the langcode is specified, it should have priority over the node's // active language. $tokens = ['test_field' => 'test-german-field', 'test_field:value' => 'test-german-field', 'test_term_reference:entity:term_field' => 'german-term-field-value', 'test_term_reference:entity:term_field:value' => 'german-term-field-value']; $this->assertTokens('node', ['node' => $node], $tokens, ['langcode' => 'de']); }
/** * Test tokens on node with the token view mode overriding default formatters. */ public function testTokenViewMode() { $value = 'A really long string that should be trimmed by the special formatter on token view we are going to have.'; // The formatter we are going to use will eventually call Unicode::strlen. // This expects that the Unicode has already been explicitly checked, which // happens in DrupalKernel. But since that doesn't run in kernel tests, we // explicitly call this here. Unicode::check(); // Create a node with a value in the text field and test its token. $entity = Node::create(['title' => 'Test node title', 'type' => 'article', 'test_field' => ['value' => $value, 'format' => $this->testFormat->id()]]); $entity->save(); $this->assertTokens('node', ['node' => $entity], ['test_field' => Markup::create($value)]); // Now, create a token view mode which sets a different format for // test_field. When replacing tokens, this formatter should be picked over // the default formatter for the field type. // @see field_tokens(). $view_mode = EntityViewMode::create(['id' => 'node.token', 'targetEntityType' => 'node']); $view_mode->save(); $entity_display = entity_get_display('node', 'article', 'token'); $entity_display->setComponent('test_field', ['type' => 'text_trimmed', 'settings' => ['trim_length' => 50]]); $entity_display->save(); $this->assertTokens('node', ['node' => $entity], ['test_field' => Markup::create(substr($value, 0, 50))]); }
/** * Gets the label of a filter format. * * @param \Drupal\filter\FilterFormatInterface $filter_format * The filter format. * * @return string * The label of the filter format. */ public function getLabel(FilterFormatInterface $filter_format) { return $filter_format->label(); }
/** * {@inheritdoc} */ public static function filterXss($html, FilterFormatInterface $format, FilterFormatInterface $original_format = NULL) { // Apply XSS filtering, but blacklist the <script>, <style>, <link>, <embed> // and <object> tags. // The <script> and <style> tags are blacklisted because their contents // can be malicious (and therefor they are inherently unsafe), whereas for // all other tags, only their attributes can make them malicious. Since // \Drupal\Component\Utility\Xss::filter() protects against malicious // attributes, we take no blacklisting action. // The exceptions to the above rule are <link>, <embed> and <object>: // - <link> because the href attribute allows the attacker to import CSS // using the HTTP(S) protocols which Xss::filter() considers safe by // default. The imported remote CSS is applied to the main document, thus // allowing for the same XSS attacks as a regular <style> tag. // - <embed> and <object> because these tags allow non-HTML applications or // content to be embedded using the src or data attributes, respectively. // This is safe in the case of HTML documents, but not in the case of // Flash objects for example, that may access/modify the main document // directly. // <iframe> is considered safe because it only allows HTML content to be // embedded, hence ensuring the same origin policy always applies. $dangerous_tags = array('script', 'style', 'link', 'embed', 'object'); // Simply blacklisting these five dangerious tags would bring safety, but // also user frustration: what if a text format is configured to allow // <embed>, for example? Then we would strip that tag, even though it is // allowed, thereby causing data loss! // Therefor, we want to be smarter still. We want to take into account which // HTML tags are allowed and forbidden by the text format we're filtering // for, and if we're switching from another text format, we want to take // that format's allowed and forbidden tags into account as well. // In other words: we only expect markup allowed in both the original and // the new format to continue to exist. $format_restrictions = $format->getHtmlRestrictions(); if ($original_format !== NULL) { $original_format_restrictions = $original_format->getHtmlRestrictions(); } // Any tags that are explicitly blacklisted by the text format must be // appended to the list of default dangerous tags: if they're explicitly // forbidden, then we must respect that configuration. // When switching from another text format, we must use the union of // forbidden tags: if either text format is more restrictive, then the // safety expectations of *both* text formats apply. $forbidden_tags = self::getForbiddenTags($format_restrictions); if ($original_format !== NULL) { $forbidden_tags = array_merge($forbidden_tags, self::getForbiddenTags($original_format_restrictions)); } // Any tags that are explicitly whitelisted by the text format must be // removed from the list of default dangerous tags: if they're explicitly // allowed, then we must respect that configuration. // When switching from another format, we must use the intersection of // allowed tags: if either format is more restrictive, then the safety // expectations of *both* formats apply. $allowed_tags = self::getAllowedTags($format_restrictions); if ($original_format !== NULL) { $allowed_tags = array_intersect($allowed_tags, self::getAllowedTags($original_format_restrictions)); } // Don't blacklist dangerous tags that are explicitly allowed in both text // formats. $blacklisted_tags = array_diff($dangerous_tags, $allowed_tags); // Also blacklist tags that are explicitly forbidden in either text format. $blacklisted_tags = array_merge($blacklisted_tags, $forbidden_tags); return static::filter($html, $blacklisted_tags); }