File Coverage

blib/lib/Dancer/Plugin/EscapeHTML.pm
Criterion Covered Total %
statement 30 31 96.7
branch 12 12 100.0
condition 15 21 71.4
subroutine 8 9 88.8
pod n/a
total 65 73 89.0


line stmt bran cond sub pod time code
1             package Dancer::Plugin::EscapeHTML;
2              
3 2     2   386303 use warnings;
  2         6  
  2         78  
4 2     2   13 use strict;
  2         3  
  2         70  
5              
6 2     2   1831 use Dancer::Plugin;
  2         97577  
  2         212  
7 2     2   1067 use Dancer qw(:syntax);
  2         228892  
  2         14  
8              
9 2     2   3514 use HTML::Entities;
  2         17942  
  2         229  
10 2     2   25 use Scalar::Util qw(blessed reftype);
  2         5  
  2         1190  
11              
12             our $VERSION = '0.22';
13              
14             =head1 NAME
15              
16             Dancer::Plugin::EscapeHTML - Escape HTML entities to avoid XSS vulnerabilities
17              
18              
19             =head1 SYNOPSIS
20              
21             This plugin provides convenience keywords C and
22             C which are simply quick shortcuts to C
23             and C from L.
24              
25              
26             use Dancer::Plugin::EscapeHTML;
27              
28             my $encoded = escape_html($some_html);
29              
30              
31             It also provides optional automatic escaping of all HTML (see below.)
32              
33              
34             =head1 DESCRIPTION
35              
36             This plugin is intended to provide a quick and simple way to ensure that
37             HTML passed in the tokens hashref to the template is safely escaped (encoded),
38             thereby helping to avoid
39             L.
40              
41             You can encode specific bits of data yourself using the C and
42             C keywords, or you can enable automatic escaping of all values
43             passed to the template.
44              
45              
46             =head1 KEYWORDS
47              
48             When the plugin is loaded, the following keywords are exported to your app:
49              
50             =head2 escape_html
51              
52             Encodes HTML entities; shortcut to C from L
53              
54             =cut
55              
56             register 'escape_html' => sub {
57 1     1   4895 return HTML::Entities::encode_entities(@_);
58             };
59              
60              
61             =head2 unescape_html
62              
63             Decodes HTML entities; shortcut to C from L
64              
65             =cut
66              
67             register 'unescape_html' => sub {
68 0     0   0 return HTML::Entities::decode_entities(@_);
69             };
70              
71             =head1 Automatic HTML encoding
72              
73             If desired, you can also enable automatic HTML encoding of all params passed to
74             templates.
75              
76             If you're using Template Toolkit, you may wish to look instead at
77             L which takes care of this reliably at the template
78             engine level, and is more widely-used and tested than this module.
79              
80             To arrange for this plugin to automatically encode HTML entities, enable the
81             automatic_encoding option in your app's config - for instance, add the
82             following to your C:
83              
84             plugins:
85             EscapeHTML:
86             automatic_escaping: 1
87              
88             Now, all values passed to the template will be automatically encoded, so you
89             should be protected from potential XSS vulnerabilities.
90              
91             Of course, this has the drawback that you cannot provide pre-prepared HTML in
92             template params to be used "as is". You can get round this by using the
93             C option to provide a pattern to match token names which should
94             be exempted from automatic escaping - for example:
95              
96             plugins:
97             EscapeHTML:
98             automatic_escaping: 1
99             exclude_pattern: '_html$'
100              
101             The above would exclude token names ending in C<_html> from being escaped.
102              
103             By default, blessed objects being passed to the template will be left
104             unmolested, as digging around in the internals of the object is probably not
105             wise or desirable. However, if you do want this to be done, set the
106             C setting to a true value, and objects will be treated just
107             like any other hashref/arrayref.
108              
109             =cut
110              
111             my $exclude_pattern;
112             my $traverse_objects;
113             my %seen;
114              
115             hook before_template_render => sub {
116             my $tokens = shift;
117             my $config = plugin_setting;
118             return unless $config->{automatic_escaping};
119              
120             # compile $exclude_pattern once per template call
121             $exclude_pattern = exists $config->{exclude_pattern}
122             ? qr/$config->{exclude_pattern}/
123             : undef;
124              
125             $traverse_objects = $config->{traverse_objects};
126              
127             # flush seen cache
128             %seen = ();
129              
130             $tokens = _encode($tokens);
131             };
132              
133             # Encode values, recursing down into hash/arrayrefs.
134             sub _encode {
135 226     226   308 my $in = shift;
136              
137 226 100       426 return unless defined $in; # avoid interpolation warnings
138              
139 215 100       594 return HTML::Entities::encode_entities($in)
140             unless ref $in;
141              
142 53 100       131 return $in
143             if exists $seen{scalar $in}; # avoid reference loops
144              
145 51         118 $seen{scalar $in} = 1;
146              
147 51 100 100     421 if (ref $in eq 'ARRAY'
    100 66        
      66        
      66        
      66        
      66        
148             or ($traverse_objects && blessed($in) && reftype($in) eq 'ARRAY'))
149             {
150 1         5 $in->[$_] = _encode($in->[$_]) for (0..$#$in);
151             } elsif (ref $in eq 'HASH'
152             or ($traverse_objects && blessed($in) && reftype($in) eq 'HASH'))
153             {
154 43         131 while (my($k,$v) = each %$in) {
155 223 100 66     3957 next if defined $exclude_pattern
156             && $k =~ $exclude_pattern;
157 222         387 $in->{$k} = _encode($v);
158             }
159             }
160              
161 51         444 return $in;
162             }
163              
164              
165             =head1 SEE ALSO
166              
167             L
168              
169             L
170              
171             L
172              
173              
174              
175             =head1 AUTHOR
176              
177             David Precious, C<< >>
178              
179             =head1 ACKNOWLEDGEMENTS
180              
181             Tom Rathborne C<< >>
182              
183              
184             =head1 LICENSE AND COPYRIGHT
185              
186             Copyright 2011 David Precious.
187              
188             This program is free software; you can redistribute it and/or modify it
189             under the terms of either: the GNU General Public License as published
190             by the Free Software Foundation; or the Artistic License.
191              
192             See http://dev.perl.org/licenses/ for more information.
193              
194              
195             =cut
196              
197             register_plugin;
198             1; # End of Dancer::Plugin::EscapeHTML