File Coverage

blib/lib/Template/EmbeddedPerl/SafeString.pm
Criterion Covered Total %
statement 39 63 61.9
branch 6 28 21.4
condition 8 12 66.6
subroutine 15 23 65.2
pod 10 12 83.3
total 78 138 56.5


line stmt bran cond sub pod time code
1             package Template::EmbeddedPerl::SafeString;
2            
3 6     6   40 use warnings;
  6         10  
  6         427  
4 6     6   31 use strict;
  6         12  
  6         161  
5 6     6   26 use Exporter 'import';
  6         10  
  6         179  
6 6     6   3113 use HTML::Escape ();
  6         6385  
  6         195  
7 6     6   41 use Scalar::Util ();
  6         13  
  6         138  
8 6     6   28 use Carp;
  6         10  
  6         1372  
9            
10             use overload
11 0     0   0 bool => sub { shift->to_bool },
12 67     67   134 '""' => sub { shift->to_string },
13             '+' => sub {
14 0     0   0 my ($self, $other, $reverse) = @_;
15 0 0       0 croak "Can only join two safe string objects" unless (ref($other) eq ref($self));
16            
17 0 0       0 return $reverse
18             ? raw("${other}${self}")
19             : raw("${self}${other}");
20             },
21 6     6   43 fallback => 1;
  6         10  
  6         88  
22            
23             our @EXPORT_OK = qw(raw flattened_raw safe flattened_safe is_safe escape_html safe_concat concat);
24             our %EXPORT_TAGS = (all => \@EXPORT_OK, core => ['raw', 'safe', 'escape_html', 'safe_concat']);
25            
26             sub _make_safe {
27 96     96   146 my $string_to_make_safe = shift;
28 96         1903 return bless(\$string_to_make_safe, 'Template::EmbeddedPerl::SafeString');
29             }
30            
31             sub escape_html {
32 28     28 1 41 my $string = shift;
33 28         142 return HTML::Escape::escape_html($string);
34             }
35            
36             sub raw {
37 61 50   61 1 124 if(scalar(@_) == 1) {
38 61 50       123 return is_safe($_[0]) ? $_[0] : _make_safe($_[0])
39             } else {
40 0 0       0 return map { is_safe($_) ? $_ : _make_safe($_) } @_;
  0         0  
41             }
42             }
43            
44             sub flattened_raw {
45 0 0   0 1 0 my $string = join '', map { is_safe($_) ? $_->to_string : $_ } @_;
  0         0  
46 0         0 return _make_safe $string;
47             }
48            
49             sub is_safe {
50 100     100 1 142 my $string_to_test = shift;
51 100 50       186 return 0 unless defined($string_to_test);
52 100 50 100     872 return 0 unless
      50        
      66        
      50        
      66        
53             ((Scalar::Util::blessed($string_to_test)||'') eq 'Template::EmbeddedPerl::SafeString') ||
54             ((Scalar::Util::blessed($string_to_test)||'') eq 'Valiant::HTML::SafeString') ||
55             ((Scalar::Util::blessed($string_to_test)||'') eq 'Mojo::ByteStream');
56 11         35 return 1;
57             }
58            
59             sub safe {
60 0 0   0 1 0 if(scalar(@_) == 1) {
61 0 0       0 return is_safe($_[0]) ? $_[0] : _make_safe(escape_html($_[0]))
62             } else {
63 0 0       0 return map { is_safe($_) ? $_ : _make_safe(escape_html($_)) } @_;
  0         0  
64             }
65             }
66            
67 35     35 0 67 sub safe_concat { return flattened_safe(@_) }
68            
69             sub flattened_safe {
70 35 100   35 1 79 my $string = join '', map { is_safe($_) ? $_->to_string : escape_html($_) } grep { defined($_) } @_;
  39         63  
  39         89  
71 35         89 return _make_safe $string;
72             }
73            
74             sub new {
75 0     0 1 0 my $class = shift;
76 0         0 return flattened_safe(@_);
77             }
78            
79 0     0 1 0 sub concat { return flattened_safe(@_) }
80            
81 78     78 1 96 sub to_string { return ${$_[0]} }
  78         1813  
82            
83 0 0   0 1   sub to_bool { return ${$_[0]} ? 1 : 0 }
  0            
84            
85             sub append {
86 0     0 0   my ($self, @rest) = @_;
87 0 0         my $string = join '', map { is_safe($_) ? $_->to_string : escape_html($_) } grep { defined($_) } @rest;
  0            
  0            
88 0           ${$self} .= $string;
  0            
89             }
90            
91             1;
92              
93             =head1 NAME
94              
95             Template::EmbeddedPerl::SafeString- String rendering safety
96            
97             =head1 SYNOPSIS
98            
99             use Template::EmbeddedPerl::SafeString'safe', 'escape';
100            
101             =head1 DESCRIPTION
102            
103             Protecting your templates from the various types of character injection attacks is
104             a prime concern for anyone working with the HTML user interface. This class provides
105             some methods and exports to make this job easier.
106            
107             =head1 EXPORTABLE FUNCTIONS
108            
109             The following functions can be exported by this library
110            
111             =head2 safe
112            
113             Given a string or array, returns such marked as 'safe' by using C on the string and
114             then encapsulating it inside an instance of L. You can safely pass arguments
115             to this since if the string is already marked safe we just return it unaltered.
116            
117             =head2 flattened_safe
118            
119             Same as C but always returns a string even if you pass an array of strings (they are all
120             joined together).
121            
122             =head2 raw
123            
124             Given a string or array of strings, return each marked as safe (by encapsulating it inside an
125             instance of L. This will just mark strings as safe without doing any
126             escaping first (for that see C) so be careful with this.
127            
128             =head2 flattened_raw
129            
130             Same as C but always returns a string even if you pass an array of strings (they are all
131             joined together).
132            
133             =head2 is_safe
134            
135             Given a string return a boolean indicating if its marked safe or not. Since C and C never
136             double the escapulations / escaping, you probably never need this but saw no reason to not expose it.
137            
138             =head2 escape_html
139            
140             A wrapper on L just to make your life a bit easier
141            
142             =head1 CLASS METHODS
143            
144             This package exposes the folllowing class methods
145            
146             =head2 new
147            
148             my $safe_string = Valiant::HTML::SafeString->new(@strings);
149            
150             Given a string, or array of strings, returns a single string that has been C'd as needed
151             and encapulated in an instance. Its safe to pass arguments to this without testing since if a string
152             is already marked safe we don't do any extra escaping (although you will get a new instance).
153            
154             =head1 INSTANCE METHODS
155            
156             Instances of L expose the following public methods
157            
158             =head2 concat
159            
160             Returns a new safe string which appends a list of strings to the old one, making those new strings
161             'safe' as needed. Basically this will escape any strings not marked safe already and then joins them
162             altogether in a single safe string.
163            
164             =head2 to_string
165            
166             Returns the raw string, suitable for display.
167            
168             =head2 to_bool
169            
170             Returns a boolean indicating if the string is empty or not.
171            
172             =head1 OVERLOADING
173            
174             String context calles C; Boolean context returns true unless the string is empty.
175            
176             =head1 SEE ALSO
177            
178             L
179              
180             =head1 AUTHOR
181            
182             See L
183            
184             =head1 COPYRIGHT & LICENSE
185            
186             See L
187            
188             =cut