diff --git a/lib/DI/ContainerConfigurator.php b/lib/DI/ContainerConfigurator.php index 427166bbf5..0913eaccb1 100644 --- a/lib/DI/ContainerConfigurator.php +++ b/lib/DI/ContainerConfigurator.php @@ -288,11 +288,13 @@ class ContainerConfigurator implements IContainerConfigurator { $container->autowire(\MailPoet\Subscription\Registration::class)->setPublic(true); $container->autowire(\MailPoet\Subscription\SubscriptionUrlFactory::class)->setPublic(true); // Newsletter + $container->autowire(\MailPoet\Newsletter\ApiDataSanitizer::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\AutomatedLatestContent::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\NewsletterSaveController::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\NewsletterPostsRepository::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\NewslettersRepository::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\AutomaticEmailsRepository::class)->setPublic(true); + $container->autowire(\MailPoet\Newsletter\NewsletterHtmlSanitizer::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\Listing\NewsletterListingRepository::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\Options\NewsletterOptionsRepository::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\Options\NewsletterOptionFieldsRepository::class)->setPublic(true); diff --git a/lib/Newsletter/ApiDataSanitizer.php b/lib/Newsletter/ApiDataSanitizer.php new file mode 100644 index 0000000000..0787d1256a --- /dev/null +++ b/lib/Newsletter/ApiDataSanitizer.php @@ -0,0 +1,32 @@ +htmlSanitizer = $htmlSanitizer; + } + + public function sanitizeBody(array $body): array { + foreach ($body as $blockName => $block) { + $sanitizedBlock = is_array($block) ? $this->sanitizeBlock($block) : $this->htmlSanitizer->sanitize($block); + $body[$blockName] = $sanitizedBlock; + } + + return $body; + } + + private function sanitizeBlock(array $block): array { + foreach ($block as $name => $value) { + if (is_array($value)) { + $block[$name] = $this->sanitizeBlock($value); + } else { + $block[$name] = $value ? $this->htmlSanitizer->sanitize($value) : $value; + } + } + return $block; + } +} diff --git a/lib/Newsletter/NewsletterHtmlSanitizer.php b/lib/Newsletter/NewsletterHtmlSanitizer.php new file mode 100644 index 0000000000..bf632a00f0 --- /dev/null +++ b/lib/Newsletter/NewsletterHtmlSanitizer.php @@ -0,0 +1,100 @@ + [ + 'class' => true, + 'style' => true, + ], + 'span' => [ + 'class' => true, + 'style' => true, + ], + 'a' => [ + 'href' => true, + 'class' => true, + 'title' => true, + 'target' => true, + 'style' => true, + ], + 'h1' => [ + 'class' => true, + 'style' => true, + ], + 'h2' => [ + 'class' => true, + 'style' => true, + ], + 'h3' => [ + 'class' => true, + 'style' => true, + ], + 'ol' => [ + 'class' => true, + 'style' => true, + ], + 'ul' => [ + 'class' => true, + 'style' => true, + ], + 'li' => [ + 'class' => true, + 'style' => true, + ], + 'strong' => [ + 'class' => true, + 'style' => true, + ], + 'em' => [ + 'class' => true, + 'style' => true, + ], + 'strike' => [], + 'br' => [], + 'blockquote' => [ + 'class' => true, + 'style' => true, + ], + 'table' => [ + 'class' => true, + 'style' => true, + ], + 'tr' => [ + 'class' => true, + 'style' => true, + ], + 'th' => [ + 'class' => true, + 'style' => true, + ], + 'td' => [ + 'class' => true, + 'style' => true, + ], + 'del' => [], + ]; + + public function __construct(WPFunctions $wp) { + $this->wp = $wp; + } + + public function sanitize(string $html): string { + // Because wpKses break shortcodes we prefix shortcodes with http protocol + $html = str_replace('href="[', 'href="http://[', $html); + $html = $this->wp->wpKses($html, $this->allowedHtml); + $html = str_replace('href="http://[', 'href="[', $html); + return $html; + } +}