diff --git a/mailpoet/lib/API/JSON/v1/CustomFields.php b/mailpoet/lib/API/JSON/v1/CustomFields.php index fb036fe561..b06c3ee63c 100644 --- a/mailpoet/lib/API/JSON/v1/CustomFields.php +++ b/mailpoet/lib/API/JSON/v1/CustomFields.php @@ -9,6 +9,7 @@ use MailPoet\API\JSON\ResponseBuilders\CustomFieldsResponseBuilder; use MailPoet\Config\AccessControl; use MailPoet\CustomFields\CustomFieldsRepository; use MailPoet\Entities\CustomFieldEntity; +use MailPoet\Form\ApiDataSanitizer; class CustomFields extends APIEndpoint { public $permissions = [ @@ -21,12 +22,17 @@ class CustomFields extends APIEndpoint { /** @var CustomFieldsResponseBuilder */ private $customFieldsResponseBuilder; + /** @var ApiDataSanitizer */ + private $dataSanitizer; + public function __construct( CustomFieldsRepository $customFieldsRepository, - CustomFieldsResponseBuilder $customFieldsResponseBuilder + CustomFieldsResponseBuilder $customFieldsResponseBuilder, + ApiDataSanitizer $dataSanitizer ) { $this->customFieldsRepository = $customFieldsRepository; $this->customFieldsResponseBuilder = $customFieldsResponseBuilder; + $this->dataSanitizer = $dataSanitizer; } public function getAll() { @@ -51,6 +57,7 @@ class CustomFields extends APIEndpoint { public function save($data = []) { try { + $data = $this->dataSanitizer->sanitizeBlock($data); $customField = $this->customFieldsRepository->createOrUpdate($data); $customField = $this->customFieldsRepository->findOneById($customField->getId()); if(!$customField instanceof CustomFieldEntity) return $this->errorResponse(); diff --git a/mailpoet/lib/Form/ApiDataSanitizer.php b/mailpoet/lib/Form/ApiDataSanitizer.php index 3b76a4a4ec..d3c1f83943 100644 --- a/mailpoet/lib/Form/ApiDataSanitizer.php +++ b/mailpoet/lib/Form/ApiDataSanitizer.php @@ -42,7 +42,7 @@ class ApiDataSanitizer { return $body; } - private function sanitizeBlock(array $block): array { + public function sanitizeBlock(array $block): array { if (!isset($this->htmlSanitizeConfig[$block['type']])) { return $block; } diff --git a/mailpoet/tests/integration/API/JSON/v1/CustomFieldsTest.php b/mailpoet/tests/integration/API/JSON/v1/CustomFieldsTest.php index ce7ccf5ab7..0a94c59af9 100644 --- a/mailpoet/tests/integration/API/JSON/v1/CustomFieldsTest.php +++ b/mailpoet/tests/integration/API/JSON/v1/CustomFieldsTest.php @@ -3,10 +3,8 @@ namespace MailPoet\Test\API\JSON\v1; use MailPoet\API\JSON\Response as APIResponse; -use MailPoet\API\JSON\ResponseBuilders\CustomFieldsResponseBuilder; use MailPoet\API\JSON\v1\CustomFields; use MailPoet\CustomFields\CustomFieldsRepository; -use MailPoet\DI\ContainerWrapper; use MailPoet\Entities\CustomFieldEntity; class CustomFieldsTest extends \MailPoetTest { @@ -14,6 +12,9 @@ class CustomFieldsTest extends \MailPoetTest { /** @var CustomFieldsRepository */ private $repository; + /** @var CustomFields */ + private $endpoint; + private $customFields = [ [ 'name' => 'CF: text', @@ -61,15 +62,15 @@ class CustomFieldsTest extends \MailPoetTest { public function _before() { parent::_before(); - $this->repository = ContainerWrapper::getInstance(WP_DEBUG)->get(CustomFieldsRepository::class); + $this->repository = $this->diContainer->get(CustomFieldsRepository::class); foreach ($this->customFields as $customField) { $this->repository->createOrUpdate($customField); } + $this->endpoint = $this->diContainer->get(CustomFields::class); } public function testItCanGetAllCustomFields() { - $router = new CustomFields($this->repository, new CustomFieldsResponseBuilder()); - $response = $router->getAll(); + $response = $this->endpoint->getAll(); expect($response->status)->equals(APIResponse::STATUS_OK); expect($response->data)->count(count($this->customFields)); @@ -85,14 +86,13 @@ class CustomFieldsTest extends \MailPoetTest { $this->assertInstanceOf(CustomFieldEntity::class, $customField); $customFieldId = $customField->getId(); - $router = new CustomFields($this->repository, new CustomFieldsResponseBuilder()); - $response = $router->delete(['id' => $customFieldId]); + $response = $this->endpoint->delete(['id' => $customFieldId]); expect($response->status)->equals(APIResponse::STATUS_OK); $customField = $this->repository->findOneBy(['type' => 'date']); expect($customField)->null(); - $response = $router->delete(['id' => $customFieldId]); + $response = $this->endpoint->delete(['id' => $customFieldId]); expect($response->status)->equals(APIResponse::STATUS_NOT_FOUND); } @@ -103,35 +103,54 @@ class CustomFieldsTest extends \MailPoetTest { 'params' => [], ]; - $router = new CustomFields($this->repository, new CustomFieldsResponseBuilder()); - $response = $router->save($newCustomField); + $response = $this->endpoint->save($newCustomField); expect($response->status)->equals(APIResponse::STATUS_OK); // missing type - $response = $router->save(['name' => 'New custom field1']); + $response = $this->endpoint->save(['name' => 'New custom field1']); expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST); // missing name - $response = $router->save(['type' => 'text']); + $response = $this->endpoint->save(['type' => 'text']); expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST); // missing data - $response = $router->save(); + $response = $this->endpoint->save(); expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST); } + public function testItSanitizesCheckboxValueButKeepsAllowedHTML() { + $newCustomField = [ + 'name' => 'New custom field', + 'type' => 'checkbox', + 'params' => [ + 'values' => [ + [ + 'label' => 'label', + 'value' => '">hellolink', + ], + ], + ], + ]; + + $response = $this->endpoint->save($newCustomField); + expect($response->status)->equals(APIResponse::STATUS_OK); + expect($response->data['params']['values'][0]['value']) + ->equals('"><img src=e onerror=alert(1) hellolink'); + } + public function testItCanGetACustomField() { $customField = $this->repository->findOneBy(['name' => 'CF: text']); $this->assertInstanceOf(CustomFieldEntity::class, $customField); - $router = new CustomFields($this->repository, new CustomFieldsResponseBuilder()); - $response = $router->get(['id' => $customField->getId()]); + + $response = $this->endpoint->get(['id' => $customField->getId()]); expect($response->data['name'])->equals('CF: text'); expect($response->data['type'])->equals('text'); expect($response->data['params'])->notEmpty(); - $response = $router->get(['id' => 'not_an_id']); + $response = $this->endpoint->get(['id' => 'not_an_id']); expect($response->status)->equals(APIResponse::STATUS_NOT_FOUND); } }