| 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
|
|
59097
|
use strict; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
26
|
|
|
7
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
23
|
|
|
8
|
1
|
|
|
1
|
|
4
|
use Carp 'croak'; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
36
|
|
|
9
|
1
|
|
|
1
|
|
4
|
use Exporter 'import'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
30
|
|
|
10
|
1
|
|
|
1
|
|
494
|
use Encode 'encode_utf8'; |
|
|
1
|
|
|
|
|
8457
|
|
|
|
1
|
|
|
|
|
57
|
|
|
11
|
1
|
|
|
1
|
|
7
|
use Scalar::Util 'looks_like_number'; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
1580
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our $VERSION = '1.2'; |
|
15
|
|
|
|
|
|
|
our @EXPORT = ('formValidate', 'mail'); |
|
16
|
|
|
|
|
|
|
our @EXPORT_OK = ('uri_escape', 'kv_validate'); |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub uri_escape { |
|
20
|
0
|
|
|
0
|
1
|
0
|
local $_ = encode_utf8 shift; |
|
21
|
0
|
|
|
|
|
0
|
s/([^A-Za-z0-9._~-])/sprintf '%%%02X', ord $1/eg; |
|
|
0
|
|
|
|
|
0
|
|
|
22
|
0
|
|
|
|
|
0
|
return $_; |
|
23
|
|
|
|
|
|
|
} |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub _template_validate_num { |
|
29
|
13
|
|
|
13
|
|
27
|
$_[0] *= 1; # Normalize to perl number |
|
30
|
13
|
100
|
100
|
|
|
49
|
return 0 if defined($_[1]{min}) && $_[0] < $_[1]{min}; |
|
31
|
9
|
100
|
100
|
|
|
38
|
return 0 if defined($_[1]{max}) && $_[0] > $_[1]{max}; |
|
32
|
6
|
|
|
|
|
13
|
return 1; |
|
33
|
|
|
|
|
|
|
} |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
my $re_fqdn = qr/(?:[a-zA-Z0-9][\w-]*\.)+[a-zA-Z][a-zA-Z0-9-]{1,25}\.?/; |
|
36
|
|
|
|
|
|
|
my $re_ip4_digit = qr/(?:0|[1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/; |
|
37
|
|
|
|
|
|
|
my $re_ip4 = qr/($re_ip4_digit\.){3}$re_ip4_digit/; |
|
38
|
|
|
|
|
|
|
# This monstrosity is based on http://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses |
|
39
|
|
|
|
|
|
|
# Doesn't allow IPv4-mapped-IPv6 addresses or other fancy stuff. |
|
40
|
|
|
|
|
|
|
my $re_ip6 = qr/(?:[0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)/; |
|
41
|
|
|
|
|
|
|
my $re_domain = qr/(?:$re_fqdn|$re_ip4|\[$re_ip6\])/; |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
my %default_templates = ( |
|
44
|
|
|
|
|
|
|
# JSON number format, regex from http://stackoverflow.com/questions/13340717/json-numbers-regular-expression |
|
45
|
|
|
|
|
|
|
num => { func => \&_template_validate_num, regex => qr/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/, inherit => ['min','max'] }, |
|
46
|
|
|
|
|
|
|
int => { func => \&_template_validate_num, regex => qr/^-?(?:0|[1-9]\d*)$/, inherit => ['min','max'] }, |
|
47
|
|
|
|
|
|
|
uint => { func => \&_template_validate_num, regex => qr/^(?:0|[1-9]\d*)$/, inherit => ['min','max'] }, |
|
48
|
|
|
|
|
|
|
ascii => { regex => qr/^[\x20-\x7E]*$/ }, |
|
49
|
|
|
|
|
|
|
email => { regex => qr/^[-\+\.#\$=\w]+\@$re_domain$/, maxlength => 254 }, |
|
50
|
|
|
|
|
|
|
weburl => { regex => qr/^https?:\/\/$re_domain(?::[1-9][0-9]{0,5})?\/[^\s<>"]*$/, maxlength => 65536 }, # the maxlength is a bit arbitrary, but better than unlimited |
|
51
|
|
|
|
|
|
|
); |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
sub kv_validate { |
|
55
|
92
|
|
|
92
|
1
|
54336
|
my($sources, $templates, $params) = @_; |
|
56
|
92
|
|
|
|
|
540
|
$templates = { %default_templates, %$templates }; |
|
57
|
|
|
|
|
|
|
|
|
58
|
92
|
|
|
|
|
168
|
my @err; |
|
59
|
|
|
|
|
|
|
my %ret; |
|
60
|
|
|
|
|
|
|
|
|
61
|
92
|
|
|
|
|
154
|
for my $f (@$params) { |
|
62
|
|
|
|
|
|
|
# Inherit some options from templates. |
|
63
|
|
|
|
|
|
|
!exists($f->{$_}) && _val_from_tpl($f, $_, $templates, $f) |
|
64
|
92
|
|
100
|
|
|
278
|
for(qw|required default rmwhitespace multi mincount maxcount|); |
|
65
|
|
|
|
|
|
|
|
|
66
|
92
|
|
|
|
|
283
|
my $src = (grep $f->{$_}, keys %$sources)[0]; |
|
67
|
92
|
|
|
|
|
190
|
my @values = $sources->{$src}->($f->{$src}); |
|
68
|
92
|
100
|
|
|
|
869
|
@values = ($values[0]) if !$f->{multi}; |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# check each value and add it to %ret |
|
71
|
92
|
|
|
|
|
127
|
for (@values) { |
|
72
|
97
|
|
100
|
|
|
128
|
my $errfield = _validate_early($_, $f) || _validate($_, $templates, $f); |
|
73
|
97
|
100
|
100
|
|
|
278
|
next if !$errfield || $errfield eq 'default'; |
|
74
|
45
|
|
|
|
|
102
|
push @err, [ $f->{$src}, $errfield, $f->{$errfield} ]; |
|
75
|
45
|
|
|
|
|
63
|
last; |
|
76
|
|
|
|
|
|
|
} |
|
77
|
92
|
100
|
|
|
|
200
|
$ret{$f->{$src}} = $f->{multi} ? \@values : $values[0]; |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# check mincount/maxcount |
|
80
|
92
|
100
|
100
|
|
|
148
|
push @err, [ $f->{$src}, 'mincount', $f->{mincount} ] if $f->{mincount} && @values < $f->{mincount}; |
|
81
|
92
|
100
|
100
|
|
|
198
|
push @err, [ $f->{$src}, 'maxcount', $f->{maxcount} ] if $f->{maxcount} && @values > $f->{maxcount}; |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
|
|
84
|
92
|
100
|
|
|
|
148
|
$ret{_err} = \@err if @err; |
|
85
|
92
|
|
|
|
|
329
|
return \%ret; |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub _val_from_tpl { |
|
90
|
896
|
|
|
896
|
|
1076
|
my($top_rules, $field, $tpls, $rules) = @_; |
|
91
|
896
|
100
|
|
|
|
1575
|
return if !$rules->{template}; |
|
92
|
379
|
|
|
|
|
435
|
my $tpl = $tpls->{$rules->{template}}; |
|
93
|
379
|
100
|
|
|
|
472
|
if(exists $tpl->{$field}) { |
|
94
|
17
|
|
|
|
|
36
|
$top_rules->{$field} = $tpl->{$field}; |
|
95
|
|
|
|
|
|
|
} else { |
|
96
|
362
|
|
|
|
|
414
|
_val_from_tpl($top_rules, $field, $tpls, $tpl); |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# Initial validation of a value. Same as _validate() below, but this one |
|
102
|
|
|
|
|
|
|
# validates options that need to be checked only once. (The checks in |
|
103
|
|
|
|
|
|
|
# _validate() may run several times when templates are used). |
|
104
|
|
|
|
|
|
|
sub _validate_early { # value, \%rules |
|
105
|
97
|
|
|
97
|
|
134
|
my($v, $r) = @_; |
|
106
|
|
|
|
|
|
|
|
|
107
|
97
|
100
|
|
|
|
181
|
$r->{required}++ if not exists $r->{required}; |
|
108
|
97
|
100
|
|
|
|
163
|
$r->{rmwhitespace}++ if not exists $r->{rmwhitespace}; |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# remove whitespace |
|
111
|
97
|
100
|
100
|
|
|
261
|
if($v && $r->{rmwhitespace}) { |
|
112
|
75
|
|
|
|
|
137
|
$_[0] =~ s/\r//g; |
|
113
|
75
|
|
|
|
|
182
|
$_[0] =~ s/^[\s\n]+//; |
|
114
|
75
|
|
|
|
|
124
|
$_[0] =~ s/[\s\n]+$//; |
|
115
|
75
|
|
|
|
|
95
|
$v = $_[0] |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
# empty |
|
119
|
97
|
100
|
100
|
|
|
278
|
if(!defined($v) || length($v) < 1) { |
|
120
|
9
|
100
|
|
|
|
26
|
return 'required' if $r->{required}; |
|
121
|
3
|
100
|
|
|
|
8
|
$_[0] = $r->{default} if exists $r->{default}; |
|
122
|
3
|
|
|
|
|
7
|
return 'default'; |
|
123
|
|
|
|
|
|
|
} |
|
124
|
88
|
|
|
|
|
200
|
return undef; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# Internal function used by kv_validate, checks one value on the validation |
|
129
|
|
|
|
|
|
|
# rules, the name of the failed rule on error, undef otherwise |
|
130
|
|
|
|
|
|
|
sub _validate { # value, \%templates, \%rules |
|
131
|
155
|
|
|
155
|
|
195
|
my($v, $t, $r) = @_; |
|
132
|
|
|
|
|
|
|
|
|
133
|
155
|
50
|
66
|
|
|
332
|
croak "Template $r->{template} not defined." if $r->{template} && !$t->{$r->{template}}; |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# length |
|
136
|
155
|
100
|
100
|
|
|
235
|
return 'minlength' if $r->{minlength} && length $v < $r->{minlength}; |
|
137
|
153
|
100
|
100
|
|
|
282
|
return 'maxlength' if $r->{maxlength} && length $v > $r->{maxlength}; |
|
138
|
|
|
|
|
|
|
# enum |
|
139
|
150
|
100
|
100
|
|
|
207
|
return 'enum' if $r->{enum} && !grep $_ eq $v, @{$r->{enum}}; |
|
|
3
|
|
|
|
|
23
|
|
|
140
|
|
|
|
|
|
|
# regex |
|
141
|
149
|
100
|
100
|
|
|
611
|
return 'regex' if $r->{regex} && (ref($r->{regex}) eq 'ARRAY' ? ($v !~ m/$r->{regex}[0]/) : ($v !~ m/$r->{regex}/)); |
|
|
|
100
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# template |
|
143
|
126
|
100
|
|
|
|
177
|
if($r->{template}) { |
|
144
|
67
|
|
|
|
|
94
|
my $in = $t->{$r->{template}}{inherit}; |
|
145
|
67
|
100
|
|
|
|
124
|
my %r = (($in ? (map exists($r->{$_}) ? ($_,$r->{$_}) : (), @$in) : ()), %{$t->{$r->{template}}}); |
|
|
67
|
100
|
|
|
|
170
|
|
|
146
|
67
|
100
|
|
|
|
136
|
return 'template' if _validate($_[0], $t, \%r); |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
# function |
|
149
|
96
|
100
|
100
|
|
|
205
|
return 'func' if $r->{func} && (ref($r->{func}) eq 'ARRAY' ? !$r->{func}[0]->($_[0], $r) : !$r->{func}->($_[0], $r)); |
|
|
|
100
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# passed validation |
|
151
|
86
|
|
|
|
|
211
|
return undef; |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub formValidate { |
|
158
|
0
|
|
|
0
|
1
|
|
my($self, @fields) = @_; |
|
159
|
|
|
|
|
|
|
return kv_validate( |
|
160
|
0
|
|
|
0
|
|
|
{ post => sub { $self->reqPosts(shift) }, |
|
161
|
0
|
|
|
0
|
|
|
get => sub { $self->reqGets(shift) }, |
|
162
|
0
|
|
|
0
|
|
|
param => sub { $self->reqParams(shift) }, |
|
163
|
0
|
|
|
0
|
|
|
cookie => sub { $self->reqCookie(shift) }, |
|
164
|
|
|
|
|
|
|
}, $self->{_TUWF}{validate_templates} || {}, |
|
165
|
|
|
|
|
|
|
\@fields |
|
166
|
0
|
|
0
|
|
|
|
); |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# A simple mail function, body and headers as arguments. Usage: |
|
172
|
|
|
|
|
|
|
# $self->mail('body', header1 => 'value of header 1', ..); |
|
173
|
|
|
|
|
|
|
sub mail { |
|
174
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
175
|
0
|
|
|
|
|
|
my $body = shift; |
|
176
|
0
|
|
|
|
|
|
my %hs = @_; |
|
177
|
|
|
|
|
|
|
|
|
178
|
0
|
0
|
|
|
|
|
croak "No To: specified!\n" if !$hs{To}; |
|
179
|
0
|
0
|
|
|
|
|
croak "No Subject: specified!\n" if !$hs{Subject}; |
|
180
|
0
|
|
0
|
|
|
|
$hs{'Content-Type'} ||= 'text/plain; charset=\'UTF-8\''; |
|
181
|
0
|
|
0
|
|
|
|
$hs{From} ||= $self->{_TUWF}{mail_from}; |
|
182
|
0
|
|
|
|
|
|
$body =~ s/\r?\n/\n/g; |
|
183
|
|
|
|
|
|
|
|
|
184
|
0
|
|
|
|
|
|
my $mail = ''; |
|
185
|
0
|
|
|
|
|
|
foreach (keys %hs) { |
|
186
|
0
|
|
|
|
|
|
$hs{$_} =~ s/[\r\n]//g; |
|
187
|
0
|
|
|
|
|
|
$mail .= sprintf "%s: %s\n", $_, $hs{$_}; |
|
188
|
|
|
|
|
|
|
} |
|
189
|
0
|
|
|
|
|
|
$mail .= sprintf "\n%s", $body; |
|
190
|
|
|
|
|
|
|
|
|
191
|
0
|
0
|
|
|
|
|
if(open(my $mailer, '|-:utf8', "$self->{_TUWF}{mail_sendmail} -t -f '$hs{From}'")) { |
|
192
|
0
|
|
|
|
|
|
print $mailer $mail; |
|
193
|
0
|
0
|
|
|
|
|
croak "Error running sendmail ($!)" |
|
194
|
|
|
|
|
|
|
if !close($mailer); |
|
195
|
|
|
|
|
|
|
} else { |
|
196
|
0
|
|
|
|
|
|
croak "Error opening sendail ($!)"; |
|
197
|
|
|
|
|
|
|
} |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
1; |