Skip to content

Instantly share code, notes, and snippets.

/xss_escape.diff Secret

Created November 11, 2014 18:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/4b50c57e75785fb2d91f to your computer and use it in GitHub Desktop.
Save anonymous/4b50c57e75785fb2d91f to your computer and use it in GitHub Desktop.
diff --git a/Changes b/Changes
index 5a57ba3..42394eb 100644
--- a/Changes
+++ b/Changes
@@ -1,6 +1,7 @@
5.60 2014-11-11
- Added to_array method to Mojo::Collection.
+ - Added xss_escape function to Mojo::Util.
- Updated Net::DNS::Native requirement to 0.12 for some important bug fixes.
5.59 2014-11-07
diff --git a/lib/Mojo/Template.pm b/lib/Mojo/Template.pm
index e025c25..78d4407 100644
--- a/lib/Mojo/Template.pm
+++ b/lib/Mojo/Template.pm
@@ -14,7 +14,7 @@ has capture_end => 'end';
has capture_start => 'begin';
has comment_mark => '#';
has encoding => 'UTF-8';
-has escape => sub { \&Mojo::Util::xml_escape };
+has escape => sub { \&Mojo::Util::xss_escape };
has [qw(escape_mark expression_mark trim_mark)] => '=';
has [qw(line_start replace_mark)] => '%';
has name => 'template';
@@ -264,11 +264,7 @@ sub _wrap {
my ($self, $code) = @_;
# Escape function
- my $escape = $self->escape;
- monkey_patch $self->namespace, _escape => sub {
- no warnings 'uninitialized';
- ref $_[0] eq 'Mojo::ByteStream' ? $_[0] : $escape->("$_[0]");
- };
+ monkey_patch $self->namespace, '_escape', $self->escape;
# Wrap lines
my $num = () = $code =~ /\n/g;
@@ -493,7 +489,7 @@ Encoding used for template files.
$mt = $mt->escape(sub {...});
A callback used to escape the results of escaped expressions, defaults to
-L<Mojo::Util/"xml_escape">.
+L<Mojo::Util/"xss_escape">.
$mt->escape(sub {
my $str = shift;
diff --git a/lib/Mojo/Util.pm b/lib/Mojo/Util.pm
index c168f38..d6d860c 100644
--- a/lib/Mojo/Util.pm
+++ b/lib/Mojo/Util.pm
@@ -58,7 +58,7 @@ our @EXPORT_OK = (
qw(md5_sum monkey_patch punycode_decode punycode_encode quote),
qw(secure_compare sha1_bytes sha1_sum slurp split_header spurt squish),
qw(steady_time tablify trim unindent unquote url_escape url_unescape),
- qw(xml_escape xor_encode)
+ qw(xml_escape xor_encode xss_escape)
);
sub b64_decode { decode_base64($_[0]) }
@@ -352,6 +352,11 @@ sub xor_encode {
return $output .= $buffer ^ substr($key, 0, length $buffer, '');
}
+sub xss_escape {
+ no warnings 'uninitialized';
+ ref $_[0] eq 'Mojo::ByteStream' ? $_[0] : xml_escape("$_[0]");
+}
+
sub _adapt {
my ($delta, $numpoints, $firsttime) = @_;
use integer;
@@ -719,6 +724,12 @@ Escape unsafe characters C<&>, C<E<lt>>, C<E<gt>>, C<"> and
XOR encode string with variable length key.
+=head2 xss_escape
+
+ my $escaped = xss_escape $str;
+
+Same as L</"xml_escape">, but does not escape L<Mojo::ByteStream> objects.
+
=head1 SEE ALSO
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
diff --git a/lib/Mojolicious/Plugin/TagHelpers.pm b/lib/Mojolicious/Plugin/TagHe
index 6ef43ac..221ac57 100644
--- a/lib/Mojolicious/Plugin/TagHelpers.pm
+++ b/lib/Mojolicious/Plugin/TagHelpers.pm
@@ -2,7 +2,7 @@ package Mojolicious::Plugin::TagHelpers;
use Mojo::Base 'Mojolicious::Plugin';
use Mojo::ByteStream;
-use Mojo::Util 'xml_escape';
+use Mojo::Util 'xss_escape';
use Scalar::Util 'blessed';
sub register {
@@ -140,7 +140,7 @@ sub _option {
$attrs{selected} = 'selected' if exists $values->{$pair->[1]};
%attrs = (%attrs, @$pair[2 .. $#$pair]);
- return _tag('option', %attrs, sub { xml_escape $pair->[0] });
+ return _tag('option', %attrs, $pair->[0]);
}
sub _password_field {
@@ -212,13 +212,13 @@ sub _tag {
}
delete $attrs{data};
}
- $tag .= qq{ $_="} . xml_escape($attrs{$_} // '') . '"' for sort keys %attrs;
+ $tag .= qq{ $_="} . xss_escape($attrs{$_} // '') . '"' for sort keys %attrs;
# Empty element
unless ($cb || defined $content) { $tag .= ' />' }
# End tag
- else { $tag .= '>' . ($cb ? $cb->() : xml_escape($content)) . "</$name>" }
+ else { $tag .= '>' . ($cb ? $cb->() : xss_escape $content) . "</$name>" }
# Prevent escaping
return Mojo::ByteStream->new($tag);
@@ -234,13 +234,11 @@ sub _tag_with_error {
sub _text_area {
my ($c, $name) = (shift, shift);
- # Make sure content is wrapped
- my $cb = ref $_[-1] eq 'CODE' ? pop : sub {''};
+ my $cb = ref $_[-1] eq 'CODE' ? pop : undef;
my $content = @_ % 2 ? shift : undef;
- $cb = sub { xml_escape $content }
- if defined($content = $c->param($name) // $content);
- return _validation($c, $name, 'textarea', @_, name => $name, $cb);
+ $content = $c->param($name) // $content // $cb // '';
+ return _validation($c, $name, 'textarea', @_, name => $name, $content);
}
sub _validation {
diff --git a/t/mojo/util.t b/t/mojo/util.t
index 9f949f1..07e7800 100644
--- a/t/mojo/util.t
+++ b/t/mojo/util.t
@@ -6,6 +6,7 @@ use lib "$FindBin::Bin/lib";
use Test::More;
use File::Spec::Functions qw(catfile splitdir);
use File::Temp 'tempdir';
+use Mojo::ByteStream 'b';
use Mojo::DeprecationTest;
use Mojo::Util
@@ -14,7 +15,7 @@ use Mojo::Util
qw(monkey_patch punycode_decode punycode_encode quote secure_compare),
qw(secure_compare sha1_bytes sha1_sum slurp split_header spurt squish),
qw(steady_time tablify trim unindent unquote url_escape url_unescape),
- qw(xml_escape xor_encode);
+ qw(xml_escape xor_encode xss_escape);
# camelize
is camelize('foo_bar_baz'), 'FooBarBaz', 'right camelized result';
@@ -193,6 +194,10 @@ is xml_escape('привет'), 'привет', 'right XML escaped resul
is xml_escape('привет<foo>'), 'привет&lt;foo&gt;',
'right XML escaped result';
+# xss_escape
+is xss_escape('<p>'), '&lt;p&gt;', 'right XSS escaped result';
+is xss_escape(b('<p>')), '<p>', 'right XSS escaped result';
+
# punycode_encode
is punycode_encode('bücher'), 'bcher-kva', 'right punycode encoded result';
diff --git a/t/mojolicious/tag_helper_lite_app.t b/t/mojolicious/tag_helper_lite
index b2fd857..039e9a6 100644
--- a/t/mojolicious/tag_helper_lite_app.t
+++ b/t/mojolicious/tag_helper_lite_app.t
@@ -68,7 +68,8 @@ EOF
# Shortcut
$t->get_ok('/small_tags')->status_is(200)->content_is(<<EOF);
-<div>test &amp; 123</div>
+<div id="&amp;lt;">test &amp; 123</div>
+<div id="&lt;">test&nbsp;321</div>
<div>
<p id="0">just</p>
<p>0</p>
@@ -494,7 +495,8 @@ __DATA__
%= tag 'bar', class => 'test', ''
@@ small_tags.html.ep
-%=t div => 'test & 123'
+%=t div => (id => '&lt;') => 'test & 123'
+%=t div => (id => b('&lt;')) => b('test&nbsp;321')
%=t div => begin
%=t p => (id => 0) => 'just'
%=t p => 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment