065d4a6f792d7fe212c7ad70916780f3e0301384
[yaffs-website] / web / core / modules / filter / tests / src / Functional / FilterHtmlImageSecureTest.php
1 <?php
2
3 namespace Drupal\Tests\filter\Functional;
4
5 use Drupal\comment\Tests\CommentTestTrait;
6 use Drupal\Core\StreamWrapper\PublicStream;
7 use Drupal\filter\Entity\FilterFormat;
8 use Drupal\Tests\BrowserTestBase;
9 use Drupal\Tests\TestFileCreationTrait;
10
11 /**
12  * Tests restriction of IMG tags in HTML input.
13  *
14  * @group filter
15  */
16 class FilterHtmlImageSecureTest extends BrowserTestBase {
17
18   use CommentTestTrait;
19   use TestFileCreationTrait;
20
21   /**
22    * Modules to enable.
23    *
24    * @var array
25    */
26   public static $modules = ['filter', 'node', 'comment'];
27
28   /**
29    * An authenticated user.
30    *
31    * @var \Drupal\user\UserInterface
32    */
33   protected $webUser;
34
35   protected function setUp() {
36     parent::setUp();
37
38     // Setup Filtered HTML text format.
39     $filtered_html_format = FilterFormat::create([
40       'format' => 'filtered_html',
41       'name' => 'Filtered HTML',
42       'filters' => [
43         'filter_html' => [
44           'status' => 1,
45           'settings' => [
46             'allowed_html' => '<img src testattribute> <a>',
47           ],
48         ],
49         'filter_autop' => [
50           'status' => 1,
51         ],
52         'filter_html_image_secure' => [
53           'status' => 1,
54         ],
55       ],
56     ]);
57     $filtered_html_format->save();
58
59     // Setup users.
60     $this->webUser = $this->drupalCreateUser([
61       'access content',
62       'access comments',
63       'post comments',
64       'skip comment approval',
65       $filtered_html_format->getPermissionName(),
66     ]);
67     $this->drupalLogin($this->webUser);
68
69     // Setup a node to comment and test on.
70     $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
71     // Add a comment field.
72     $this->addDefaultCommentField('node', 'page');
73     $this->node = $this->drupalCreateNode();
74   }
75
76   /**
77    * Tests removal of images having a non-local source.
78    */
79   public function testImageSource() {
80     global $base_url;
81
82     $public_files_path = PublicStream::basePath();
83
84     $http_base_url = preg_replace('/^https?/', 'http', $base_url);
85     $https_base_url = preg_replace('/^https?/', 'https', $base_url);
86     $files_path = base_path() . $public_files_path;
87     $csrf_path = $public_files_path . '/' . implode('/', array_fill(0, substr_count($public_files_path, '/') + 1, '..'));
88
89     $druplicon = 'core/misc/druplicon.png';
90     $red_x_image = base_path() . 'core/misc/icons/e32700/error.svg';
91     $alt_text = t('Image removed.');
92     $title_text = t('This image has been removed. For security reasons, only images from the local domain are allowed.');
93
94     // Put a test image in the files directory.
95     $test_images = $this->getTestFiles('image');
96     $test_image = $test_images[0]->filename;
97
98     // Put a test image in the files directory with special filename.
99     $special_filename = 'tést fïle nàme.png';
100     $special_image = rawurlencode($special_filename);
101     $special_uri = str_replace($test_images[0]->filename, $special_filename, $test_images[0]->uri);
102     file_unmanaged_copy($test_images[0]->uri, $special_uri);
103
104     // Create a list of test image sources.
105     // The keys become the value of the IMG 'src' attribute, the values are the
106     // expected filter conversions.
107     $host = \Drupal::request()->getHost();
108     $host_pattern = '|^http\://' . $host . '(\:[0-9]{0,5})|';
109     $images = [
110       $http_base_url . '/' . $druplicon => base_path() . $druplicon,
111       $https_base_url . '/' . $druplicon => base_path() . $druplicon,
112       // Test a url that includes a port.
113       preg_replace($host_pattern, 'http://' . $host . ':', $http_base_url . '/' . $druplicon) => base_path() . $druplicon,
114       preg_replace($host_pattern, 'http://' . $host . ':80', $http_base_url . '/' . $druplicon) => base_path() . $druplicon,
115       preg_replace($host_pattern, 'http://' . $host . ':443', $http_base_url . '/' . $druplicon) => base_path() . $druplicon,
116       preg_replace($host_pattern, 'http://' . $host . ':8080', $http_base_url . '/' . $druplicon) => base_path() . $druplicon,
117       base_path() . $druplicon => base_path() . $druplicon,
118       $files_path . '/' . $test_image => $files_path . '/' . $test_image,
119       $http_base_url . '/' . $public_files_path . '/' . $test_image => $files_path . '/' . $test_image,
120       $https_base_url . '/' . $public_files_path . '/' . $test_image => $files_path . '/' . $test_image,
121       $http_base_url . '/' . $public_files_path . '/' . $special_image => $files_path . '/' . $special_image,
122       $https_base_url . '/' . $public_files_path . '/' . $special_image => $files_path . '/' . $special_image,
123       $files_path . '/example.png' => $red_x_image,
124       'http://example.com/' . $druplicon => $red_x_image,
125       'https://example.com/' . $druplicon => $red_x_image,
126       'javascript:druplicon.png' => $red_x_image,
127       $csrf_path . '/logout' => $red_x_image,
128     ];
129     $comment = [];
130     foreach ($images as $image => $converted) {
131       // Output the image source as plain text for debugging.
132       $comment[] = $image . ':';
133       // Hash the image source in a custom test attribute, because it might
134       // contain characters that confuse XPath.
135       $comment[] = '<img src="' . $image . '" testattribute="' . hash('sha256', $image) . '" />';
136     }
137     $edit = [
138       'comment_body[0][value]' => implode("\n", $comment),
139     ];
140     $this->drupalPostForm('node/' . $this->node->id(), $edit, t('Save'));
141     foreach ($images as $image => $converted) {
142       $found = FALSE;
143       foreach ($this->xpath('//img[@testattribute="' . hash('sha256', $image) . '"]') as $element) {
144         $found = TRUE;
145         if ($converted == $red_x_image) {
146           $this->assertEqual($element->getAttribute('src'), $red_x_image);
147           $this->assertEqual($element->getAttribute('alt'), $alt_text);
148           $this->assertEqual($element->getAttribute('title'), $title_text);
149           $this->assertEqual($element->getAttribute('height'), '16');
150           $this->assertEqual($element->getAttribute('width'), '16');
151         }
152         else {
153           $this->assertEqual($element->getAttribute('src'), $converted);
154         }
155       }
156       $this->assertTrue($found, format_string('@image was found.', ['@image' => $image]));
157     }
158   }
159
160 }