FilterHtmlImageSecureTest.php 5.87 KB
Newer Older
1 2 3 4 5 6 7 8 9
<?php

/**
 * @file
 * Contains Drupal\filter\Tests\FilterHtmlImageSecureTest.
 */

namespace Drupal\filter\Tests;

10
use Drupal\Core\StreamWrapper\PublicStream;
11 12 13 14
use Drupal\simpletest\WebTestBase;

/**
 * Tests restriction of IMG tags in HTML input.
15 16
 *
 * @group filter
17 18 19 20 21 22 23 24 25 26
 */
class FilterHtmlImageSecureTest extends WebTestBase {

  /**
   * Modules to enable.
   *
   * @var array
   */
  public static $modules = array('filter', 'node', 'comment');

27
  protected function setUp() {
28 29 30
    parent::setUp();

    // Setup Filtered HTML text format.
31
    $filtered_html_format = entity_create('filter_format', array(
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
      'format' => 'filtered_html',
      'name' => 'Filtered HTML',
      'filters' => array(
        'filter_html' => array(
          'status' => 1,
          'settings' => array(
            'allowed_html' => '<img> <a>',
          ),
        ),
        'filter_autop' => array(
          'status' => 1,
        ),
        'filter_html_image_secure' => array(
          'status' => 1,
        ),
      ),
48 49
    ));
    $filtered_html_format->save();
50 51 52 53 54 55 56

    // Setup users.
    $this->web_user = $this->drupalCreateUser(array(
      'access content',
      'access comments',
      'post comments',
      'skip comment approval',
57
      $filtered_html_format->getPermissionName(),
58 59 60 61 62
    ));
    $this->drupalLogin($this->web_user);

    // Setup a node to comment and test on.
    $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
63 64
    // Add a comment field.
    $this->container->get('comment.manager')->addDefaultField('node', 'page');
65 66 67 68 69 70 71 72 73
    $this->node = $this->drupalCreateNode();
  }

  /**
   * Tests removal of images having a non-local source.
   */
  function testImageSource() {
    global $base_url;

74
    $public_files_path = PublicStream::basePath();
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

    $http_base_url = preg_replace('/^https?/', 'http', $base_url);
    $https_base_url = preg_replace('/^https?/', 'https', $base_url);
    $files_path = base_path() . $public_files_path;
    $csrf_path = $public_files_path . '/' . implode('/', array_fill(0, substr_count($public_files_path, '/') + 1, '..'));

    $druplicon = 'core/misc/druplicon.png';
    $red_x_image = base_path() . 'core/misc/message-16-error.png';
    $alt_text = t('Image removed.');
    $title_text = t('This image has been removed. For security reasons, only images from the local domain are allowed.');

    // Put a test image in the files directory.
    $test_images = $this->drupalGetTestFiles('image');
    $test_image = $test_images[0]->filename;

90 91 92 93 94 95
    // Put a test image in the files directory with special filename.
    $special_filename = 'tést fïle nàme.png';
    $special_image = rawurlencode($special_filename);
    $special_uri = str_replace($test_images[0]->filename, $special_filename, $test_images[0]->uri);
    file_unmanaged_copy($test_images[0]->uri, $special_uri);

96 97 98
    // Create a list of test image sources.
    // The keys become the value of the IMG 'src' attribute, the values are the
    // expected filter conversions.
99
    $host = \Drupal::request()->getHost();
100
    $host_pattern = '|^http\://' . $host . '(\:[0-9]{0,5})|';
101 102 103
    $images = array(
      $http_base_url . '/' . $druplicon => base_path() . $druplicon,
      $https_base_url . '/' . $druplicon => base_path() . $druplicon,
104 105 106 107 108
      // Test a url that includes a port.
      preg_replace($host_pattern, 'http://' . $host . ':', $http_base_url . '/' . $druplicon) => base_path() . $druplicon,
      preg_replace($host_pattern, 'http://' . $host . ':80', $http_base_url . '/' . $druplicon) => base_path() . $druplicon,
      preg_replace($host_pattern, 'http://' . $host . ':443', $http_base_url . '/' . $druplicon) => base_path() . $druplicon,
      preg_replace($host_pattern, 'http://' . $host . ':8080', $http_base_url . '/' . $druplicon) => base_path() . $druplicon,
109 110 111 112
      base_path() . $druplicon => base_path() . $druplicon,
      $files_path . '/' . $test_image => $files_path . '/' . $test_image,
      $http_base_url . '/' . $public_files_path . '/' . $test_image => $files_path . '/' . $test_image,
      $https_base_url . '/' . $public_files_path . '/' . $test_image => $files_path . '/' . $test_image,
113 114
      $http_base_url . '/' . $public_files_path . '/' . $special_image => $files_path . '/' . $special_image,
      $https_base_url . '/' . $public_files_path . '/' . $special_image => $files_path . '/' . $special_image,
115 116 117 118 119 120 121 122 123 124 125 126
      $files_path . '/example.png' => $red_x_image,
      'http://example.com/' . $druplicon => $red_x_image,
      'https://example.com/' . $druplicon => $red_x_image,
      'javascript:druplicon.png' => $red_x_image,
      $csrf_path . '/logout' => $red_x_image,
    );
    $comment = array();
    foreach ($images as $image => $converted) {
      // Output the image source as plain text for debugging.
      $comment[] = $image . ':';
      // Hash the image source in a custom test attribute, because it might
      // contain characters that confuse XPath.
127
      $comment[] = '<img src="' . $image . '" testattribute="' . hash('sha256', $image) . '" />';
128 129
    }
    $edit = array(
130
      'comment_body[0][value]' => implode("\n", $comment),
131
    );
132
    $this->drupalPostForm('node/' . $this->node->id(), $edit, t('Save'));
133 134
    foreach ($images as $image => $converted) {
      $found = FALSE;
135
      foreach ($this->xpath('//img[@testattribute="' . hash('sha256', $image) . '"]') as $element) {
136 137 138 139 140
        $found = TRUE;
        if ($converted == $red_x_image) {
          $this->assertEqual((string) $element['src'], $red_x_image);
          $this->assertEqual((string) $element['alt'], $alt_text);
          $this->assertEqual((string) $element['title'], $title_text);
141 142
          $this->assertEqual((string) $element['height'], '16');
          $this->assertEqual((string) $element['width'], '16');
143 144 145 146 147 148 149 150 151
        }
        else {
          $this->assertEqual((string) $element['src'], $converted);
        }
      }
      $this->assertTrue($found, format_string('@image was found.', array('@image' => $image)));
    }
  }
}