How to validate placeholders? - perl

The Placeholders are available in Mojolicious.
We can access them via $c->param( 'placeholder_name' ) as other input data from user $c->param( 'post_or_query_param' )
But when we access parameters after validation we use:
$c->validation->param( 'post_or_query_param' )
The undef is returned if post_or_query_param did not pass validation.
We can validate placeholders partially via Restrective placeholders but still access them as $c->param( 'placeholder_name' ) (because placeholder is not available to validation object)
This often lead programmer to think that in this place of code not validated data is used because validated data is available as: $v->param( 'xxx' )
The placeholders is same input from user as query or post data.
How to make placeholders available to validation object? and access user's input in same way as other validated data:
$v->param( 'validated parameter name' );

I have found this solution: put placeholder into ->input
# GET /tariffs/:tariff_id
my $v = $c->validation;
# Solution: how to make placeholder available to validation:
my $placeholders = $self->match->stack->[-1];
#{ $v->input }{ keys %$placeholders } = values %$placeholders;
# etc.
$v->required( tariff_id => [ data_exists => $self, '!Tariff' ] );
return ... if $v->has_error;
my $tariff = $v->param( 'tariff_id' );

Usually I use OpenAPI plugin and describe API using this format. Placeholder parameters also will be validated through schema (just like Query/JSON/Form/XML parameters).
OpenAPI validator is based on JSON Schema Validator and is rich. Supports min, max, patterns, enums, deep structures etc.
Read article about Mojolicious and OpenAPI.
Here is example of validation schema and controller.

Related

Trim function before validating form input in Codeigniter 4

With Codeigniter 3 it was possible to use "trim" as a validation rule.
It seems it is no more possible with Codeigniter 4.
Then how can I trim input values before validating, in case the user left whitespaces at the beginning or the end of the input?
$validation->setRule('username', 'Username', 'trim|required|min_length[3]');
I thought using a custom rule but these functions can only return true or false. They can't modify the input. The other solution is using the php trim function but I can't see where to use it.
Thanks for your help!
I'm guessing you're validating the post request directly. For what you need I would validate your modified array instead of the post request directly.
One of the great things in codeigniter 4 validation is that your can actually validate anything. Unlike codeigniter 3 where you could only use it to validate the $_POST data.
Let's say you have two fields, username and password and want to trim the username.
In you controller that would get the post date you would do the following.
$validation = \Config\Services::validation();
$validation->setRules([
'username' => 'required',
'password' => 'required|min_length[10]'
]);
$data = $this->request->getPost();
$data['username'] = trim($data['username']);
if (!$validation->run($data)) {
// handle validation errors
}
If you're doing the validation in the model, I'm not sure if the validation is run before the callbacks but its worth a try. So You would define a function in your beforeInsert callback and handle the trim there.
More about callbacks here:
https://codeigniter.com/user_guide/models/model.html#specifying-callbacks-to-run
If that does not work you can even remove the username from your validation rules in your model and then in a beforeFind and beforeUpdate function validate the username yourself and trim it.
I had the exact same question. For me, it makes sense to trim most POST variables before any validation. Even some of the common validation rules are best executed with already-trimmed values.
As #micthi stated, CodeIgniter 3 offered an easy way to trim just before validation. CodeIgniter 4 makes it much less straightforward. A custom validation rule can't modify data for us, and the model event methods such as beforeInsert and beforeUpdate also don't help us in running callbacks as they all execute after validation.
Below is a CodeIgniter 4 solution that works to allow trimming of POST variables before any validation. In brief, a filter is created and then configured to run before any controller code is executed for any POST method. It loops thru the $request object to trim the POST variables and then allows the newly-trimmed version if the $request to proceed to the controller.
Create: app/Filters/TrimFilter.php
namespace App\Filters;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;
class TrimFilter implements FilterInterface
{
public function before(RequestInterface $request, $arguments = null) {
$trimmed_post = [];
foreach($request->getPost() as $var => $val) {
$trimmed_post[$var] = trim($val);
}
$request->setGlobal('post', $trimmed_post);
}
}
Modify: app/Config/Filters.php
// Add to the use statements
use App\Filters\TrimFilter;
// Add to the $aliases array
public $aliases = [
'trim' => TrimFilter::class
];
// Add to the $methods array
public $methods = [
'post' => ['trim']
];
ANOTHER OPTION: Instead of using the filter approach, you could instead perform the trimming loop within the BaseController.php file. In this case, remember to use $this-> to reference the request while within the BaseController.

Unexpected field in POST data with a multiple choice fieldName

What I have
foreach ($statuses as $key=>$value) {
echo $this->Form->control('Filter.statuses['.$key.']', array(
'type' => 'checkbox',
'value' => $key,
'label' => $value,
));
}
What I'm getting
Unexpected field 'Filter.statuses[1' in POST data
Unexpected field 'Filter.statuses[2' in POST data
Unexpected field 'Filter.statuses[3' in POST data
...
What I have tried
$this->Form->unlockField('Filter.statuses');
$this->Form->unlockField('Filter.statuses[]');
If I remove the Filter. prefix, the errors are gone and I no longer need the unlockField() call.
References
In cakephp 3 I got error Unexpected field in POST data
Unexpected field 'g-recaptcha-response' in POST data on CakePHP 3
https://book.cakephp.org/3.0/en/controllers/components/security.html
You're not supposed to use brackets in the field name, the form helper doesn't support that. If you ever need an unconventional name that the form helper doesn't support, then use the name option to specify it, while passing a compatible field name to the control() method's first argument.
Use the dot syntax all the way:
echo $this->Form->control("Filter.statuses.$key", /* ... */);
That way the form helper will be able to secure the fields, and create proper HTML name attribute values like Filter[statuses][1].

what does Validator::make($request->all() do in Laravel 5.2?

Laravel newbie here.
I am trying to understand the following snippet, and it's not clearly explained on the Laravel docs. I thought maybe other newbies might also find it helpful if it were explained in plain words. From what I understand, the routes file contains this route for new task creation, and so the validator makes a check on all the fields of the incoming Request object, checking along the way if the name field equals 255 chars? Is that correct? Why do we have a $request->all() bit in there?
Route::post('/task', function (Request $request) {
$validator = Validator::make($request->all(), [
'name' => 'required|max:255',
]);
The method Validator::make() takes two arguments: one array of inputs to check, and one array of rules to check against.
If you have a posted form from a webpage, you can retrieve the form data (and/or GET variables) from the $request object. If you want all of them, you simply call $request->all().
So what you're saying in the code is basically "I want to create a new validator. I supply it with the posted form data, and I want to check that form data against these rules. There's only one rule, which says to make sure the name field was supplied, and that it isn't longer than 255 characters."
Hope that makes sense.

How to receive json in Dancer?

I am very new to Perl framework Dancer. As of now I have a get http listener working. I have an Angular framework trying to post a json string to Dancer. How can I retreive the json and perhaps assign it to a scalar variable ($json).
get '/games' => sub {
header 'Access-Control-Allow-Origin' => '*';
&loadgames();
return $games;
};
post '/newgame' => sub {
header 'Access-Control-Allow-Origin' => '*';
#what should i put here to retrieve the json string
#I plan to pass the json string to a sub to convert to XML
};
I am not sure If I chose Dancer as backend framework that will get and post data.
Thanks for the help!
If your HTTP request has a JSON body (Content-type: application/json) rather than being an HTML form post, then you probably want something like this:
post '/url-path' => {
my $post = from_json( request->body );
# do something with the POSTed data structure
# which would typically be a hashref (or an arrayref)
# e.g.: schema->resultset('Widget')->create($post);
}
The from_json routine is one of the DSL Keywords provided by Dancer.
Dancer provides the params keyword for accessing route, body, and query parameters. You want a body parameter. Exactly which body parameter you want will depend on the name of the field you posted it to the route with (look at your form or your ajax request).
my $json_string = params('body')->{$field_name}
You can also use param, if you don't have any conflicting parameter names in the route or query parameters.
Once you have the json, remember it's just a string at the moment. You might want to read it into a perl data structure: Dancer provides from_json for this purpose.
As an aside: I notice in your get route, you call a function loadgames in void context, and then return a variable you haven't declared (or perhaps you have set it as a global - but do you need it to be a global?). I recommend beginning each perl file with use strict; to pick up issues like this. I suspect you probably just want to use the return value of loadgames as your return value.

Perl WebService::Soundcloud - how to pass track parameters while uploading to Soundcloud

I'm trying to upload a sound to soundcloud using WebService::Soundcloud. I've so far been able to make a couple of GET/POST requests following the examples provided by the WebService::Soundcloud documentation.
However, I can't find a decent example anywhere on how to do an upload while passing the required parameters i.e. track, and within it, asset_data, title e.t.c. I'm wondering if I should be sending out a multipart message.
Any examples will be appreciated!
Also, here's what I have tried so far: After authenticating and getting a valid WebService::Soundcloud instance.
GET my $response = $scloud->get( '/me/tracks' );
PUT my $response = $scloud->put( '/me/tracks/91576621', JSON::to_json({track=>{title=>"My test title",description=>"My test description"}}) );
POST my $file = '/home/ski/track1.mp3';
my $asset_data = File::Slurp::read_file( $file, binmode => ':raw' );
my $response = $scloud->post('/me/tracks', '{"track":{"title":"My test title","asset_data":"'.$asset_data.'"}}' );
This fails with "Request entity contains invalid byte sequence. Please transmit valid UTF-8"
The example you provide manually constructs the JSON but doesn't take into account the binary nature of the file content which means it's unlikely to work. It's also vulnerable to abusive content changing your JSON due to lack of escaping/proper encoding.
The documentation you cite has a put example which demonstrate the content needs to be encoded into JSON and then passed to the library. I've not used this api but it's probably a simple case of using encode_json as per the examples. I'll just show an example that's equivalent to your manual encoding:
use JSON qw(encode_json);
my $asset_data = "ascii, quotes (\"'), non-ascii: \000\001\002\003";
my $content = encode_json({ track => { title => "My test title",
asset_data => $asset_data}});
print $content . "\n"; ### inspection of encoding
And this shows that JSON uses a UTF-8 representation to deal with binary data:
{"track":{"asset_data":"ascii, quotes (\"'), non-ascii: \u0000\u0001\u0002\u0003","title":"My test title"}}
The key/values are being re-ordered there but it's equivalent JSON.