Skip to content

Commit

Permalink
Ability to escape validation messages
Browse files Browse the repository at this point in the history
  • Loading branch information
Kieran authored and bytestream committed Nov 5, 2019
1 parent 96960ab commit 021ec23
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 12 deletions.
4 changes: 4 additions & 0 deletions config/jsvalidation.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@
*/
'remote_validation_field' => '_jsvalidation',

/*
* Whether to escape all validation messages with htmlentities.
*/
'escape' => false,
];
13 changes: 11 additions & 2 deletions src/Javascript/MessageParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,23 @@ class MessageParser
{
use UseDelegatedValidatorTrait;

/**
* Whether to escape messages using htmlentities.
*
* @var bool
*/
protected $escape;

/**
* Create a new JsValidation instance.
*
* @param \Proengsoft\JsValidation\Support\DelegatedValidator $validator
* @param bool $escape
*/
public function __construct(DelegatedValidator $validator)
public function __construct(DelegatedValidator $validator, $escape = false)
{
$this->validator = $validator;
$this->escape = $escape;
}

/**
Expand All @@ -37,7 +46,7 @@ public function getMessage($attribute, $rule, $parameters)

$this->validator->setData($data);

return $message;
return $this->escape ? e($message) : $message;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/JsValidatorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ protected function jsValidator(Validator $validator, $selector = null)

$delegated = new DelegatedValidator($validator, new ValidationRuleParserProxy());
$rules = new RuleParser($delegated, $this->getSessionToken());
$messages = new MessageParser($delegated);
$messages = new MessageParser($delegated, isset($this->options['escape']) ? $this->options['escape'] : false);

$jsValidator = new ValidatorHandler($rules, $messages);

Expand Down
13 changes: 11 additions & 2 deletions src/Remote/Resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,24 @@ class Resolver
*/
protected $factory;

/**
* Whether to escape validation messages.
*
* @var bool
*/
protected $escape;

/**
* RemoteValidator constructor.
*
* @param \Illuminate\Contracts\Validation\Factory $factory
* @param bool $escape
*/
public function __construct(ValidationFactory $factory)
public function __construct(ValidationFactory $factory, $escape = false)
{
$this->factory = $factory;
$this->resolver = $this->getProtected($factory, 'resolver');
$this->escape = $escape;
}

/**
Expand Down Expand Up @@ -93,7 +102,7 @@ protected function createValidator($translator, $data, $rules, $messages, $custo
public function validatorClosure()
{
return function ($attribute, $value, $parameters, BaseValidator $validator) {
$remoteValidator = new Validator($validator);
$remoteValidator = new Validator($validator, $this->escape);
$remoteValidator->validate($value, $parameters);

return $attribute;
Expand Down
21 changes: 19 additions & 2 deletions src/Remote/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,23 @@ class Validator
*/
protected $validator;

/**
* Whether to escape validation messages.
*
* @var bool
*/
protected $escape;

/**
* RemoteValidator constructor.
*
* @param \Illuminate\Validation\Validator $validator
* @param bool $escape
*/
public function __construct(BaseValidator $validator)
public function __construct(BaseValidator $validator, $escape = false)
{
$this->validator = $validator;
$this->escape = $escape;
}

/**
Expand Down Expand Up @@ -121,7 +130,15 @@ protected function validateJsRemoteRequest($attribute, $parameters)
return true;
}

return $validator->messages()->get($attribute);
$messages = $validator->messages()->get($attribute);

if ($this->escape) {
foreach ($messages as $key => $value) {
$messages[$key] = e($value);
}
}

return $messages;
}

/**
Expand Down
10 changes: 9 additions & 1 deletion src/RemoteValidationMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ class RemoteValidationMiddleware
*/
protected $field;

/**
* Whether to escape messages or not.
*
* @var bool
*/
protected $escape;

/**
* RemoteValidationMiddleware constructor.
*
Expand All @@ -35,6 +42,7 @@ public function __construct(ValidationFactory $validator, Config $config)
{
$this->factory = $validator;
$this->field = $config->get('jsvalidation.remote_validation_field');
$this->escape = (bool) $config->get('jsvalidation.escape', false);
}

/**
Expand All @@ -60,7 +68,7 @@ public function handle(Request $request, Closure $next)
*/
protected function wrapValidator()
{
$resolver = new Resolver($this->factory);
$resolver = new Resolver($this->factory, $this->escape);
$this->factory->resolver($resolver->resolver($this->field));
$this->factory->extend(RemoteValidator::EXTENSION_NAME, $resolver->validatorClosure());
}
Expand Down
36 changes: 36 additions & 0 deletions tests/Javascript/MessageParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,40 @@ public function testGetMessageFiles()

$this->assertEquals("$attribute $rule", $message);
}

public function testEscape()
{
$attribute = 'field';
$rule = 'Image';
$return = "<html>";

$delegated = $this->getMockBuilder(\Proengsoft\JsValidation\Support\DelegatedValidator::class)
->disableOriginalConstructor()
->getMock();

$delegated->expects($this->once())
->method('getData')
->willReturn([]);

$delegated->expects($this->once())
->method('hasRule')
->with($attribute, ['Mimes', 'Image'])
->willReturn(true);

$delegated->expects($this->once())
->method('getMessage')
->with($attribute, $rule)
->willReturn($return);

$delegated->expects($this->once())
->method('makeReplacements')
->with($return, $attribute, $rule, [])
->willReturn($return);

$parser = new MessageParser($delegated, true);

$message = $parser->getMessage($attribute, $rule, []);

$this->assertEquals("&lt;html&gt;", $message);
}
}
23 changes: 21 additions & 2 deletions tests/Remote/ValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@ public function testValidateRemoteRuleFails()
}
}

public function testEscapeMessage()
{
$rules = ['field' => 'active_url|required'];
$data = ['field' => 'http://nonexistentdomain'];
$params= ['false'];
$validator = $this->getRealValidator($rules, [ 'field.active_url' => '<html>' ], $data, true);

try {
$validator->validate('field',$params);
$this->fail();
} catch (ValidationException $ex) {
$this->assertEquals(200, $ex->getResponse()->getStatusCode());
$this->assertEquals('["&lt;html&gt;"]', $ex->getResponse()->getContent());
} catch (HttpResponseException $ex) {
$this->assertEquals(200, $ex->getResponse()->getStatusCode());
$this->assertEquals('["&lt;html&gt;"]', $ex->getResponse()->getContent());
}
}

public function testValidateRemoteDisabled()
{
$rules = ['field' => 'active_url|required|alpha|no_js_validation'];
Expand Down Expand Up @@ -107,13 +126,13 @@ protected function getRealTranslator()
return $trans;
}

protected function getRealValidator($rules, $messages = [], $data = [])
protected function getRealValidator($rules, $messages = [], $data = [], $escape = false)
{
$trans = $this->getRealTranslator();
$laravelValidator = new LaravelValidator($trans, $data, $rules, $messages);
$laravelValidator->addExtension(ValidatorHandler::JSVALIDATION_DISABLE, function() {
return true;
});
return new Validator($laravelValidator);
return new Validator($laravelValidator, $escape);
}
}
12 changes: 10 additions & 2 deletions tests/RemoteValidationMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@ public function testHandle()
->with(Validator::EXTENSION_NAME, $this->isInstanceOf('Closure'));

$mockedConfig = $this->getMockForAbstractClass(\Illuminate\Contracts\Config\Repository::class, [],'',false);
$mockedConfig->expects($this->once())
$mockedConfig->expects($this->at(0))
->method('get')
->with('jsvalidation.remote_validation_field')
->will($this->returnValue('_jsvalidation'));
$mockedConfig->expects($this->at(1))
->method('get')
->with('jsvalidation.escape', false)
->will($this->returnValue('_jsvalidation'));

$mockedRequest = $this->getMockBuilder(\Illuminate\Http\Request::class)
->disableOriginalConstructor()
Expand Down Expand Up @@ -60,10 +64,14 @@ public function testHandleShouldNotValidate()
->getMock();

$mockedConfig = $this->getMockForAbstractClass(\Illuminate\Contracts\Config\Repository::class,[],'',false);
$mockedConfig->expects($this->once())
$mockedConfig->expects($this->at(0))
->method('get')
->with('jsvalidation.remote_validation_field')
->will($this->returnValue('_jsvalidation'));
$mockedConfig->expects($this->at(1))
->method('get')
->with('jsvalidation.escape', false)
->will($this->returnValue('_jsvalidation'));

$mockedRequest = $this->getMockBuilder(\Illuminate\Http\Request::class)
->disableOriginalConstructor()
Expand Down

0 comments on commit 021ec23

Please sign in to comment.