diff --git a/lib/API/JSON/v1/Subscribers.php b/lib/API/JSON/v1/Subscribers.php index fc161d0549..028d62213d 100644 --- a/lib/API/JSON/v1/Subscribers.php +++ b/lib/API/JSON/v1/Subscribers.php @@ -66,6 +66,11 @@ class Subscribers extends APIEndpoint { APIError::BAD_REQUEST => __('Please specify a valid form ID.', 'mailpoet') )); } + if(!empty($data['email'])) { + return $this->badRequest(array( + APIError::BAD_REQUEST => __('Please leave the first field empty.', 'mailpoet') + )); + } $segment_ids = (!empty($data['segments']) ? (array)$data['segments'] @@ -74,6 +79,8 @@ class Subscribers extends APIEndpoint { $segment_ids = $form->filterSegments($segment_ids); unset($data['segments']); + $data = $this->deobfuscateFormPayload($data); + if(empty($segment_ids)) { return $this->badRequest(array( APIError::BAD_REQUEST => __('Please select a list.', 'mailpoet') @@ -115,6 +122,18 @@ class Subscribers extends APIEndpoint { } } + private function deobfuscateFormPayload($data) { + $result = array(); + foreach($data as $key => $value) { + if(strpos($key, 'form_field_') === 0) { + $result[base64_decode(substr($key, 11))] = $value; + } else { + $result[$key] = $value; + } + } + return $result; + } + function save($data = array()) { if(empty($data['segments'])) { $data['segments'] = array(); diff --git a/lib/Form/Block/Base.php b/lib/Form/Block/Base.php index 723433c5ea..39e6c5809d 100644 --- a/lib/Form/Block/Base.php +++ b/lib/Form/Block/Base.php @@ -104,7 +104,7 @@ abstract class Base { if((int)$block['id'] > 0) { return 'cf_'.$block['id']; } else { - return $block['id']; + return 'form_field_'.base64_encode($block['id']);//obfuscate field name for spambots } } diff --git a/lib/Form/Renderer.php b/lib/Form/Renderer.php index 1649520ad4..f301e4f96a 100644 --- a/lib/Form/Renderer.php +++ b/lib/Form/Renderer.php @@ -15,6 +15,7 @@ class Renderer { $styles = new Util\Styles(static::getStyles($form)); $html = ''; @@ -38,7 +39,8 @@ class Renderer { } static function renderBlocks($blocks = array()) { - $html = ''; + // this is a honeypot for spambots + $html = ''; foreach($blocks as $key => $block) { $html .= static::renderBlock($block)."\n"; } diff --git a/tests/unit/API/JSON/v1/SubscribersTest.php b/tests/unit/API/JSON/v1/SubscribersTest.php index d94d345b47..e49061d33e 100644 --- a/tests/unit/API/JSON/v1/SubscribersTest.php +++ b/tests/unit/API/JSON/v1/SubscribersTest.php @@ -390,10 +390,22 @@ class SubscribersTest extends \MailPoetTest { expect($response->errors[0]['message'])->contains('has no method'); } + function testItFailsWithEmailFilled() { + $router = new Subscribers(); + $response = $router->subscribe(array( + 'form_id' => $this->form->id, + 'email' => 'toto@mailpoet.com' + // no form ID specified + )); + + expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST); + expect($response->errors[0]['message'])->equals('Please leave the first field empty.'); + } + function testItCannotSubscribeWithoutFormID() { $router = new Subscribers(); $response = $router->subscribe(array( - 'email' => 'toto@mailpoet.com' + 'form_field_ZW1haWw' => 'toto@mailpoet.com' // no form ID specified )); @@ -404,7 +416,7 @@ class SubscribersTest extends \MailPoetTest { function testItCannotSubscribeWithoutSegmentsIfTheyAreSelectedByUser() { $router = new Subscribers(); $response = $router->subscribe(array( - 'email' => 'toto@mailpoet.com', + 'form_field_ZW1haWw=' => 'toto@mailpoet.com', 'form_id' => $this->form->id // no segments specified )); @@ -416,7 +428,7 @@ class SubscribersTest extends \MailPoetTest { function testItCanSubscribe() { $router = new Subscribers(); $response = $router->subscribe(array( - 'email' => 'toto@mailpoet.com', + 'form_field_ZW1haWw=' => 'toto@mailpoet.com', 'form_id' => $this->form->id, 'segments' => array($this->segment_1->id, $this->segment_2->id) )); @@ -431,7 +443,7 @@ class SubscribersTest extends \MailPoetTest { $router = new Subscribers(); $response = $router->subscribe(array( - 'email' => 'toto@mailpoet.com', + 'form_field_ZW1haWw=' => 'toto@mailpoet.com', 'form_id' => $this->form->id // no segments specified )); @@ -453,7 +465,7 @@ class SubscribersTest extends \MailPoetTest { $router = new Subscribers(); $response = $router->subscribe(array( - 'email' => 'toto@mailpoet.com', + 'form_field_ZW1haWw=' => 'toto@mailpoet.com', 'form_id' => $this->form->id, 'segments' => array($this->segment_1->id, $this->segment_2->id) )); @@ -465,7 +477,7 @@ class SubscribersTest extends \MailPoetTest { function testItCanFilterOutNonFormFieldsWhenSubscribing() { $router = new Subscribers(); $response = $router->subscribe(array( - 'email' => 'toto@mailpoet.com', + 'form_field_ZW1haWw=' => 'toto@mailpoet.com', 'form_id' => $this->form->id, 'segments' => array($this->segment_1->id, $this->segment_2->id), // exists in table and in the form @@ -486,14 +498,14 @@ class SubscribersTest extends \MailPoetTest { $router = new Subscribers(); $response = $router->subscribe(array( - 'email' => 'toto@mailpoet.com', + 'form_field_ZW1haWw=' => 'toto@mailpoet.com', 'form_id' => $this->form->id, 'segments' => array($this->segment_1->id, $this->segment_2->id) )); try { $response = $router->subscribe(array( - 'email' => 'tata@mailpoet.com', + 'form_field_ZW1haWw=' => 'tata@mailpoet.com', 'form_id' => $this->form->id, 'segments' => array($this->segment_1->id, $this->segment_2->id) )); diff --git a/tests/unit/Subscription/FormTest.php b/tests/unit/Subscription/FormTest.php index b115de96be..09d7abca88 100644 --- a/tests/unit/Subscription/FormTest.php +++ b/tests/unit/Subscription/FormTest.php @@ -11,6 +11,7 @@ use MailPoet\Util\Security; class FormTest extends \MailPoetTest { function _before() { + $this->testEmail = 'test@example.com'; $this->segment = SegmentModel::createOrUpdate( array( 'name' => 'Test segment' @@ -34,7 +35,7 @@ class FormTest extends \MailPoetTest { 'action' => 'mailpoet_subscription_form', 'data' => array( 'form_id' => $this->form->id, - 'email' => 'test@example.com' + 'form_field_ZW1haWw=' => $this->testEmail ), 'token' => Security::generateToken(), 'api_version' => 'v1', @@ -58,7 +59,7 @@ class FormTest extends \MailPoetTest { } ]); $result = Form::onSubmit($this->request_data); - expect(SubscriberModel::findOne($this->request_data['data']['email']))->notEmpty(); + expect(SubscriberModel::findOne($this->testEmail))->notEmpty(); $mock->verifyInvoked('redirectBack'); expect($result['mailpoet_success'])->equals($this->form->id); expect($result['mailpoet_error'])->null(); @@ -78,7 +79,7 @@ class FormTest extends \MailPoetTest { } ]); $result = Form::onSubmit($this->request_data); - expect(SubscriberModel::findOne($this->request_data['data']['email']))->notEmpty(); + expect(SubscriberModel::findOne($this->testEmail))->notEmpty(); $mock->verifyInvoked('redirectTo'); expect($result)->regExp('/http.*?sample-post/i'); }