From a59d2d52588018b924dd393f4357f23dcc9fbd98 Mon Sep 17 00:00:00 2001 From: Yorhel Date: Sat, 2 Jul 2016 11:07:41 +0200 Subject: Validate release dates + move validation out of vndb.pl --- lib/VNDB/Handler/Releases.pm | 2 +- lib/VNDB/Util/FormHTML.pm | 1 + lib/VNDB/Util/ValidateTemplates.pm | 102 +++++++++++++++++++++++++++++++++++++ util/vndb.pl | 75 --------------------------- 4 files changed, 104 insertions(+), 76 deletions(-) create mode 100644 lib/VNDB/Util/ValidateTemplates.pm diff --git a/lib/VNDB/Handler/Releases.pm b/lib/VNDB/Handler/Releases.pm index 7271541e..62ba0c5a 100644 --- a/lib/VNDB/Handler/Releases.pm +++ b/lib/VNDB/Handler/Releases.pm @@ -305,7 +305,7 @@ sub edit { { post => 'catalog', required => 0, default => '', maxlength => 50 }, { post => 'languages', multi => 1, enum => [ keys %{$self->{languages}} ] }, { post => 'website', required => 0, default => '', maxlength => 250, template => 'weburl' }, - { post => 'released', required => 0, default => 0, template => 'uint' }, + { post => 'released', required => 0, default => 0, template => 'rdate' }, { post => 'minage' , required => 0, default => -1, enum => $self->{age_ratings} }, { post => 'notes', required => 0, default => '', maxlength => 10240 }, { post => 'platforms', required => 0, default => '', multi => 1, enum => [ keys %{$self->{platforms}} ] }, diff --git a/lib/VNDB/Util/FormHTML.pm b/lib/VNDB/Util/FormHTML.pm index 51d5a4f6..a522599e 100644 --- a/lib/VNDB/Util/FormHTML.pm +++ b/lib/VNDB/Util/FormHTML.pm @@ -52,6 +52,7 @@ sub htmlFormError { li "$field may only contain lowercase alphanumeric characters and a hyphen" if $rule eq 'uname'; li 'Invalid JAN/UPC/EAN' if $rule eq 'gtin'; li "$field: Malformed data or invalid input" if $rule eq 'json'; + li 'Invalid release date' if $rule eq 'rdate'; if($rule eq 'editsum') { li; lit 'Please read the guidelines on how to use the edit summary.'; end; } diff --git a/lib/VNDB/Util/ValidateTemplates.pm b/lib/VNDB/Util/ValidateTemplates.pm new file mode 100644 index 00000000..c92ac12b --- /dev/null +++ b/lib/VNDB/Util/ValidateTemplates.pm @@ -0,0 +1,102 @@ +# This module implements various templates for formValidate() + +package VNDB::Util::ValidateTemplates; + +use strict; +use warnings; +use VNDB::Func 'json_decode'; +use VNDBUtil 'gtintype'; +use Time::Local 'timegm'; + + +TUWF::set( + validate_templates => { + id => { template => 'uint', max => 1<<40 }, + page => { template => 'uint', max => 1000 }, + uname => { regex => qr/^[a-z0-9-]*$/, minlength => 2, maxlength => 15 }, + gtin => { func => \>intype }, + editsum => { maxlength => 5000, minlength => 2 }, + json => { func => \&json_validate, inherit => ['json_fields','json_maxitems','json_unique','json_sort'], default => [] }, + rdate => { template => 'uint', min => 0, max => 99999999, func => \&rdate_validate, default => 0 }, + } +); + + +# Figure out if a field is treated as a number in kv_validate(). +sub json_validate_is_num { + my $opts = shift; + return 0 if !$opts->{template}; + return 1 if $opts->{template} eq 'num' || $opts->{template} eq 'int' || $opts->{template} eq 'uint'; + my $t = TUWF::set('validate_templates')->{$opts->{template}}; + return $t && json_validate_is_num($t); +} + + +sub json_validate_sort { + my($sort, $fields, $data) = @_; + + # Figure out which fields need to use number comparison + my %nums; + for my $k (@$sort) { + my $f = (grep $_->{field} eq $k, @$fields)[0]; + $nums{$k}++ if json_validate_is_num($f); + } + + # Sort + return [sort { + for(@$sort) { + my $r = $nums{$_} ? $a->{$_} <=> $b->{$_} : $a->{$_} cmp $b->{$_}; + return $r if $r; + } + 0 + } @$data]; +} + +# Special validation function for simple JSON structures as form fields. It can +# only validate arrays of key-value objects. The key-value objects are then +# validated using kv_validate. +# TODO: json_unique implies json_sort on the same fields? These options tend to be the same. +sub json_validate { + my($val, $opts) = @_; + my $fields = $opts->{json_fields}; + my $maxitems = $opts->{json_maxitems}; + my $unique = $opts->{json_unique}; + my $sort = $opts->{json_sort}; + $unique = [$unique] if $unique && !ref $unique; + $sort = [$sort] if $sort && !ref $sort; + + my $data = eval { json_decode $val }; + $_[0] = $@ ? [] : $data; + return 0 if $@ || ref $data ne 'ARRAY'; + return 0 if defined($maxitems) && @$data > $maxitems; + + my %known_fields = map +($_->{field},1), @$fields; + my %unique; + + for my $i (0..$#$data) { + return 0 if ref $data->[$i] ne 'HASH'; + # Require that all keys are known and have a scalar value. + return 0 if grep !$known_fields{$_} || ref($data->[$i]{$_}), keys %{$data->[$i]}; + $data->[$i] = kv_validate({ field => sub { $data->[$i]{shift()} } }, $TUWF::OBJ->{_TUWF}{validate_templates}, $fields); + return 0 if $data->[$i]{_err}; + return 0 if $unique && $unique{ join '|||', map $data->[$i]{$_}, @$unique }++; + } + + $_[0] = json_validate_sort($sort, $fields, $data) if $sort; + return 1; +} + + +sub rdate_validate { + return 0 if $_[0] ne 0 && $_[0] !~ /^(\d{4})(\d{2})(\d{2})$/; + my($y, $m, $d) = defined $1 ? ($1, $2, $3) : (0,0,0); + + # Normalization ought to be done in JS, but do it here again because we can't trust browsers + ($m, $d) = (0, 0) if $y == 0; + $m = 99 if $y == 9999; + $d = 99 if $m == 99; + $_[0] = $y*10000 + $m*100 + $d; + + return 0 if $y && $d != 99 && !eval { timegm(0, 0, 0, $d, $m-1, $y) }; + return 1; +} diff --git a/util/vndb.pl b/util/vndb.pl index dfb78afa..51ade736 100755 --- a/util/vndb.pl +++ b/util/vndb.pl @@ -16,8 +16,6 @@ use lib $ROOT.'/lib'; use TUWF ':html', 'kv_validate'; -use VNDB::Func 'json_decode'; -use VNDBUtil 'gtintype'; use SkinFile; @@ -44,14 +42,6 @@ TUWF::set( pre_request_handler => \&reqinit, error_404_handler => \&handle404, log_format => \&logformat, - validate_templates => { - id => { template => 'uint', max => 1<<40 }, - page => { template => 'uint', max => 1000 }, - uname => { regex => qr/^[a-z0-9-]*$/, minlength => 2, maxlength => 15 }, - gtin => { func => \>intype }, - editsum => { maxlength => 5000, minlength => 2 }, - json => { func => \&json_validate, inherit => ['json_fields','json_maxitems','json_unique','json_sort'], default => [] }, - }, ); TUWF::load_recursive('VNDB::Util', 'VNDB::DB', 'VNDB::Handler'); TUWF::run(); @@ -96,68 +86,3 @@ sub logformat { sprintf "[%s] %s %s: %s\n", scalar localtime(), $uri, $self->authInfo->{id} ? 'u'.$self->authInfo->{id} : '-', $msg; } - - -# Figure out if a field is treated as a number in kv_validate(). -sub json_validate_is_num { - my $opts = shift; - return 0 if !$opts->{template}; - return 1 if $opts->{template} eq 'num' || $opts->{template} eq 'int' || $opts->{template} eq 'uint'; - my $t = TUWF::set('validate_templates')->{$opts->{template}}; - return $t && json_validate_is_num($t); -} - - -sub json_validate_sort { - my($sort, $fields, $data) = @_; - - # Figure out which fields need to use number comparison - my %nums; - for my $k (@$sort) { - my $f = (grep $_->{field} eq $k, @$fields)[0]; - $nums{$k}++ if json_validate_is_num($f); - } - - # Sort - return [sort { - for(@$sort) { - my $r = $nums{$_} ? $a->{$_} <=> $b->{$_} : $a->{$_} cmp $b->{$_}; - return $r if $r; - } - 0 - } @$data]; -} - -# Special validation function for simple JSON structures as form fields. It can -# only validate arrays of key-value objects. The key-value objects are then -# validated using kv_validate. -# TODO: json_unique implies json_sort on the same fields? These options tend to be the same. -sub json_validate { - my($val, $opts) = @_; - my $fields = $opts->{json_fields}; - my $maxitems = $opts->{json_maxitems}; - my $unique = $opts->{json_unique}; - my $sort = $opts->{json_sort}; - $unique = [$unique] if $unique && !ref $unique; - $sort = [$sort] if $sort && !ref $sort; - - my $data = eval { json_decode $val }; - $_[0] = $@ ? [] : $data; - return 0 if $@ || ref $data ne 'ARRAY'; - return 0 if defined($maxitems) && @$data > $maxitems; - - my %known_fields = map +($_->{field},1), @$fields; - my %unique; - - for my $i (0..$#$data) { - return 0 if ref $data->[$i] ne 'HASH'; - # Require that all keys are known and have a scalar value. - return 0 if grep !$known_fields{$_} || ref($data->[$i]{$_}), keys %{$data->[$i]}; - $data->[$i] = kv_validate({ field => sub { $data->[$i]{shift()} } }, $TUWF::OBJ->{_TUWF}{validate_templates}, $fields); - return 0 if $data->[$i]{_err}; - return 0 if $unique && $unique{ join '|||', map $data->[$i]{$_}, @$unique }++; - } - - $_[0] = json_validate_sort($sort, $fields, $data) if $sort; - return 1; -} -- cgit v1.2.3