| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
package TUWF::Misc; |
|
3
|
|
|
|
|
|
|
# Yeah, just put all miscellaneous functions in one module! |
|
4
|
|
|
|
|
|
|
# Geez, talk about being sloppy... |
|
5
|
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
73642
|
use strict; |
|
|
1
|
|
|
|
|
12
|
|
|
|
1
|
|
|
|
|
34
|
|
|
7
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
32
|
|
|
8
|
1
|
|
|
1
|
|
5
|
use Carp 'croak'; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
52
|
|
|
9
|
1
|
|
|
1
|
|
5
|
use Exporter 'import'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
47
|
|
|
10
|
1
|
|
|
1
|
|
12
|
use Scalar::Util 'looks_like_number'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
54
|
|
|
11
|
1
|
|
|
1
|
|
437
|
use TUWF::Validate; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
2150
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our $VERSION = '1.5'; |
|
15
|
|
|
|
|
|
|
our @EXPORT_OK = ('uri_escape', 'kv_validate'); |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub uri_escape { |
|
19
|
0
|
|
|
0
|
1
|
0
|
utf8::encode(local $_ = shift); |
|
20
|
0
|
|
|
|
|
0
|
s/([^A-Za-z0-9._~-])/sprintf '%%%02X', ord $1/eg; |
|
|
0
|
|
|
|
|
0
|
|
|
21
|
0
|
|
|
|
|
0
|
return $_; |
|
22
|
|
|
|
|
|
|
} |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub _template_validate_num { |
|
28
|
13
|
|
|
13
|
|
32
|
$_[0] *= 1; # Normalize to perl number |
|
29
|
13
|
100
|
100
|
|
|
62
|
return 0 if defined($_[1]{min}) && $_[0] < $_[1]{min}; |
|
30
|
9
|
100
|
100
|
|
|
48
|
return 0 if defined($_[1]{max}) && $_[0] > $_[1]{max}; |
|
31
|
6
|
|
|
|
|
18
|
return 1; |
|
32
|
|
|
|
|
|
|
} |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
my %default_templates = ( |
|
36
|
|
|
|
|
|
|
# JSON number format, regex from http://stackoverflow.com/questions/13340717/json-numbers-regular-expression |
|
37
|
|
|
|
|
|
|
num => { func => \&_template_validate_num, regex => qr/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/, inherit => ['min','max'] }, |
|
38
|
|
|
|
|
|
|
int => { func => \&_template_validate_num, regex => qr/^-?(?:0|[1-9]\d*)$/, inherit => ['min','max'] }, |
|
39
|
|
|
|
|
|
|
uint => { func => \&_template_validate_num, regex => qr/^(?:0|[1-9]\d*)$/, inherit => ['min','max'] }, |
|
40
|
|
|
|
|
|
|
ascii => { regex => qr/^[\x20-\x7E]*$/ }, |
|
41
|
|
|
|
|
|
|
email => { regex => $TUWF::Validate::re_email, maxlength => 254 }, |
|
42
|
|
|
|
|
|
|
weburl => { regex => $TUWF::Validate::re_weburl, maxlength => 65536 }, # the maxlength is a bit arbitrary, but better than unlimited |
|
43
|
|
|
|
|
|
|
); |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub kv_validate { |
|
47
|
92
|
|
|
92
|
1
|
68459
|
my($sources, $templates, $params) = @_; |
|
48
|
92
|
|
|
|
|
614
|
$templates = { %default_templates, %$templates }; |
|
49
|
|
|
|
|
|
|
|
|
50
|
92
|
|
|
|
|
208
|
my @err; |
|
51
|
|
|
|
|
|
|
my %ret; |
|
52
|
|
|
|
|
|
|
|
|
53
|
92
|
|
|
|
|
165
|
for my $f (@$params) { |
|
54
|
|
|
|
|
|
|
# Inherit some options from templates. |
|
55
|
|
|
|
|
|
|
!exists($f->{$_}) && _val_from_tpl($f, $_, $templates, $f) |
|
56
|
92
|
|
100
|
|
|
352
|
for(qw|required default rmwhitespace multi mincount maxcount|); |
|
57
|
|
|
|
|
|
|
|
|
58
|
92
|
|
|
|
|
303
|
my $src = (grep $f->{$_}, keys %$sources)[0]; |
|
59
|
92
|
|
|
|
|
249
|
my @values = $sources->{$src}->($f->{$src}); |
|
60
|
92
|
100
|
|
|
|
1025
|
@values = ($values[0]) if !$f->{multi}; |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# check each value and add it to %ret |
|
63
|
92
|
|
|
|
|
153
|
for (@values) { |
|
64
|
97
|
|
100
|
|
|
154
|
my $errfield = _validate_early($_, $f) || _validate($_, $templates, $f); |
|
65
|
97
|
100
|
100
|
|
|
335
|
next if !$errfield || $errfield eq 'default'; |
|
66
|
47
|
|
|
|
|
131
|
push @err, [ $f->{$src}, $errfield, $f->{$errfield} ]; |
|
67
|
47
|
|
|
|
|
83
|
last; |
|
68
|
|
|
|
|
|
|
} |
|
69
|
92
|
100
|
|
|
|
260
|
$ret{$f->{$src}} = $f->{multi} ? \@values : $values[0]; |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# check mincount/maxcount |
|
72
|
92
|
100
|
100
|
|
|
197
|
push @err, [ $f->{$src}, 'mincount', $f->{mincount} ] if $f->{mincount} && @values < $f->{mincount}; |
|
73
|
92
|
100
|
100
|
|
|
234
|
push @err, [ $f->{$src}, 'maxcount', $f->{maxcount} ] if $f->{maxcount} && @values > $f->{maxcount}; |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
92
|
100
|
|
|
|
195
|
$ret{_err} = \@err if @err; |
|
77
|
92
|
|
|
|
|
398
|
return \%ret; |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub _val_from_tpl { |
|
82
|
896
|
|
|
896
|
|
1283
|
my($top_rules, $field, $tpls, $rules) = @_; |
|
83
|
896
|
100
|
|
|
|
2019
|
return if !$rules->{template}; |
|
84
|
379
|
|
|
|
|
539
|
my $tpl = $tpls->{$rules->{template}}; |
|
85
|
379
|
100
|
|
|
|
571
|
if(exists $tpl->{$field}) { |
|
86
|
17
|
|
|
|
|
62
|
$top_rules->{$field} = $tpl->{$field}; |
|
87
|
|
|
|
|
|
|
} else { |
|
88
|
362
|
|
|
|
|
563
|
_val_from_tpl($top_rules, $field, $tpls, $tpl); |
|
89
|
|
|
|
|
|
|
} |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# Initial validation of a value. Same as _validate() below, but this one |
|
94
|
|
|
|
|
|
|
# validates options that need to be checked only once. (The checks in |
|
95
|
|
|
|
|
|
|
# _validate() may run several times when templates are used). |
|
96
|
|
|
|
|
|
|
sub _validate_early { # value, \%rules |
|
97
|
97
|
|
|
97
|
|
160
|
my($v, $r) = @_; |
|
98
|
|
|
|
|
|
|
|
|
99
|
97
|
100
|
|
|
|
226
|
$r->{required}++ if not exists $r->{required}; |
|
100
|
97
|
100
|
|
|
|
199
|
$r->{rmwhitespace}++ if not exists $r->{rmwhitespace}; |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# remove whitespace |
|
103
|
97
|
100
|
100
|
|
|
340
|
if($v && $r->{rmwhitespace}) { |
|
104
|
75
|
|
|
|
|
170
|
$_[0] =~ s/\r//g; |
|
105
|
75
|
|
|
|
|
234
|
$_[0] =~ s/^[\s\n]+//; |
|
106
|
75
|
|
|
|
|
165
|
$_[0] =~ s/[\s\n]+$//; |
|
107
|
75
|
|
|
|
|
104
|
$v = $_[0] |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# empty |
|
111
|
97
|
100
|
100
|
|
|
374
|
if(!defined($v) || length($v) < 1) { |
|
112
|
9
|
100
|
|
|
|
32
|
return 'required' if $r->{required}; |
|
113
|
3
|
100
|
|
|
|
8
|
$_[0] = $r->{default} if exists $r->{default}; |
|
114
|
3
|
|
|
|
|
9
|
return 'default'; |
|
115
|
|
|
|
|
|
|
} |
|
116
|
88
|
|
|
|
|
235
|
return undef; |
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# Internal function used by kv_validate, checks one value on the validation |
|
121
|
|
|
|
|
|
|
# rules, the name of the failed rule on error, undef otherwise |
|
122
|
|
|
|
|
|
|
sub _validate { # value, \%templates, \%rules |
|
123
|
155
|
|
|
155
|
|
244
|
my($v, $t, $r) = @_; |
|
124
|
|
|
|
|
|
|
|
|
125
|
155
|
50
|
66
|
|
|
443
|
croak "Template $r->{template} not defined." if $r->{template} && !$t->{$r->{template}}; |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# length |
|
128
|
155
|
100
|
100
|
|
|
311
|
return 'minlength' if $r->{minlength} && length $v < $r->{minlength}; |
|
129
|
153
|
100
|
100
|
|
|
338
|
return 'maxlength' if $r->{maxlength} && length $v > $r->{maxlength}; |
|
130
|
|
|
|
|
|
|
# enum |
|
131
|
150
|
100
|
100
|
|
|
297
|
return 'enum' if $r->{enum} && !grep $_ eq $v, @{$r->{enum}}; |
|
|
3
|
|
|
|
|
26
|
|
|
132
|
|
|
|
|
|
|
# regex |
|
133
|
149
|
100
|
100
|
|
|
855
|
return 'regex' if $r->{regex} && (ref($r->{regex}) eq 'ARRAY' ? ($v !~ m/$r->{regex}[0]/) : ($v !~ m/$r->{regex}/)); |
|
|
|
100
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# template |
|
135
|
124
|
100
|
|
|
|
233
|
if($r->{template}) { |
|
136
|
67
|
|
|
|
|
121
|
my $in = $t->{$r->{template}}{inherit}; |
|
137
|
67
|
100
|
|
|
|
152
|
my %r = (($in ? (map exists($r->{$_}) ? ($_,$r->{$_}) : (), @$in) : ()), %{$t->{$r->{template}}}); |
|
|
67
|
100
|
|
|
|
217
|
|
|
138
|
67
|
100
|
|
|
|
153
|
return 'template' if _validate($_[0], $t, \%r); |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
# function |
|
141
|
92
|
100
|
100
|
|
|
251
|
return 'func' if $r->{func} && (ref($r->{func}) eq 'ARRAY' ? !$r->{func}[0]->($_[0], $r) : !$r->{func}->($_[0], $r)); |
|
|
|
100
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# passed validation |
|
143
|
82
|
|
|
|
|
228
|
return undef; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub TUWF::Object::formValidate { |
|
150
|
0
|
|
|
0
|
|
|
my($self, @fields) = @_; |
|
151
|
|
|
|
|
|
|
return kv_validate( |
|
152
|
0
|
|
|
0
|
|
|
{ post => sub { $self->reqPosts(shift) }, |
|
153
|
0
|
|
|
0
|
|
|
get => sub { $self->reqGets(shift) }, |
|
154
|
0
|
|
|
0
|
|
|
param => sub { $self->reqParams(shift) }, |
|
155
|
0
|
|
|
0
|
|
|
cookie => sub { $self->reqCookie(shift) }, |
|
156
|
|
|
|
|
|
|
}, $self->{_TUWF}{validate_templates} || {}, |
|
157
|
|
|
|
|
|
|
\@fields |
|
158
|
0
|
|
0
|
|
|
|
); |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# A simple mail function, body and headers as arguments. Usage: |
|
164
|
|
|
|
|
|
|
# $self->mail('body', header1 => 'value of header 1', ..); |
|
165
|
|
|
|
|
|
|
sub TUWF::Object::mail { |
|
166
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
167
|
0
|
|
|
|
|
|
my $body = shift; |
|
168
|
0
|
|
|
|
|
|
my %hs = @_; |
|
169
|
|
|
|
|
|
|
|
|
170
|
0
|
0
|
|
|
|
|
croak "No To: specified!\n" if !$hs{To}; |
|
171
|
0
|
0
|
|
|
|
|
croak "No Subject: specified!\n" if !$hs{Subject}; |
|
172
|
0
|
|
0
|
|
|
|
$hs{'Content-Type'} ||= 'text/plain; charset=\'UTF-8\''; |
|
173
|
0
|
|
0
|
|
|
|
$hs{From} ||= $self->{_TUWF}{mail_from}; |
|
174
|
0
|
|
|
|
|
|
$body =~ s/\r?\n/\n/g; |
|
175
|
|
|
|
|
|
|
|
|
176
|
0
|
|
|
|
|
|
my $mail = ''; |
|
177
|
0
|
|
|
|
|
|
foreach (keys %hs) { |
|
178
|
0
|
|
|
|
|
|
$hs{$_} =~ s/[\r\n]//g; |
|
179
|
0
|
|
|
|
|
|
$mail .= sprintf "%s: %s\n", $_, $hs{$_}; |
|
180
|
|
|
|
|
|
|
} |
|
181
|
0
|
|
|
|
|
|
$mail .= sprintf "\n%s", $body; |
|
182
|
|
|
|
|
|
|
|
|
183
|
0
|
0
|
|
|
|
|
if($self->{_TUWF}{mail_sendmail} eq 'log') { |
|
|
|
0
|
|
|
|
|
|
|
184
|
0
|
|
|
|
|
|
$self->log("tuwf->mail(): The following mail would have been sent:\n$mail"); |
|
185
|
|
|
|
|
|
|
} elsif(open(my $mailer, '|-:utf8', "$self->{_TUWF}{mail_sendmail} -t -f '$hs{From}'")) { |
|
186
|
0
|
|
|
|
|
|
print $mailer $mail; |
|
187
|
0
|
0
|
|
|
|
|
croak "Error running sendmail ($!)" |
|
188
|
|
|
|
|
|
|
if !close($mailer); |
|
189
|
|
|
|
|
|
|
} else { |
|
190
|
0
|
|
|
|
|
|
croak "Error opening sendail ($!)"; |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub TUWF::Object::compile { |
|
196
|
0
|
|
|
0
|
|
|
TUWF::Validate::compile($_[0]{_TUWF}{custom_validations}, $_[1]); |
|
197
|
|
|
|
|
|
|
} |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub _compile { |
|
201
|
0
|
0
|
|
0
|
|
|
ref $_[0] eq 'TUWF::Validate' ? $_[0] : $TUWF::OBJ->compile($_[0]); |
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
sub TUWF::Object::validate { |
|
206
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
207
|
0
|
|
|
|
|
|
my $what = shift; |
|
208
|
|
|
|
|
|
|
|
|
209
|
0
|
0
|
|
|
|
|
return _compile($_[0])->validate($self->reqJSON) if $what eq 'json'; |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# 'param' is special, and not really encouraged. Create a new hash based on |
|
212
|
|
|
|
|
|
|
# reqParam() and cache the result. |
|
213
|
|
|
|
|
|
|
$self->{_TUWF}{Req}{PARAM} ||= { |
|
214
|
0
|
0
|
0
|
|
|
|
map { my @v = $self->reqParams($_); +($_, @v > 1 ? \@v : $v[0]) } $self->reqParams() |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
} if $what eq 'param'; |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
my $source = |
|
218
|
|
|
|
|
|
|
$what eq 'get' ? $self->{_TUWF}{Req}{GET} : |
|
219
|
|
|
|
|
|
|
$what eq 'post' ? $self->{_TUWF}{Req}{POST} : |
|
220
|
|
|
|
|
|
|
$what eq 'param' ? $self->{_TUWF}{Req}{PARAM} |
|
221
|
0
|
0
|
|
|
|
|
: croak "Invalid source type '$what'"; |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# Multi-value, schema hash or object |
|
224
|
0
|
0
|
|
|
|
|
return _compile($_[0])->validate($source) if @_ == 1; |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# Single value |
|
227
|
0
|
0
|
|
|
|
|
return _compile($_[1])->validate($source->{$_[0]}) if @_ == 2; |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# Multi-value, separate params |
|
230
|
0
|
|
|
|
|
|
_compile({ type => 'hash', keys => { @_ } })->validate($source); |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
# Internal function used by other TUWF modules to find an appropriate JSON |
|
235
|
|
|
|
|
|
|
# module. Kinda like JSON::MaybeXS, but without an extra dependency. |
|
236
|
|
|
|
|
|
|
sub _JSON { |
|
237
|
0
|
0
|
|
0
|
|
|
return 'JSON::XS' if $INC{'JSON/XS.pm'}; |
|
238
|
0
|
0
|
|
|
|
|
return 'Cpanel::JSON::XS' if $INC{'Cpanel/JSON/XS.pm'}; |
|
239
|
0
|
0
|
|
|
|
|
return 'JSON::PP' if $INC{'JSON/PP.pm'}; |
|
240
|
0
|
0
|
|
|
|
|
return 'JSON::XS' if eval { require JSON::XS; 1 }; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
241
|
0
|
0
|
|
|
|
|
return 'Cpanel::JSON::XS' if eval { require Cpanel::JSON::XS; 1 }; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
242
|
0
|
0
|
|
|
|
|
die "Unable to load a suitable JSON module: $@" if !eval { require JSON::PP; 1 }; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
|
'JSON::PP' |
|
244
|
|
|
|
|
|
|
} |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
1; |