Compare commits
4 Commits
cf77dd5cf2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| da24af38e3 | |||
| 6670e81640 | |||
| 3459e91645 | |||
| 9bd98b4fb9 |
@@ -288,8 +288,8 @@ sub parse_inline {
|
|||||||
push @bold_parts, { type => 'bold', content => $1 };
|
push @bold_parts, { type => 'bold', content => $1 };
|
||||||
return "\x01B$idx\x02";
|
return "\x01B$idx\x02";
|
||||||
}->()/ge;
|
}->()/ge;
|
||||||
$text =~ s/___((?:[^_]|_(?!_))+?)___/<strong>$1<\/strong>/g;
|
$text =~ s/(?<!\w)___((?:[^_]|_(?!_))+?)___(?!\w)/<strong>$1<\/strong>/g;
|
||||||
$text =~ s/__((?:[^_]|_(?!_))+?)__/<strong>$1<\/strong>/g;
|
$text =~ s/(?<!\w)__((?:[^_]|_(?!_))+?)__(?!\w)/<strong>$1<\/strong>/g;
|
||||||
|
|
||||||
my @italic_parts;
|
my @italic_parts;
|
||||||
my $italic_idx = 0;
|
my $italic_idx = 0;
|
||||||
@@ -298,7 +298,7 @@ sub parse_inline {
|
|||||||
push @italic_parts, { type => 'italic', content => $1 };
|
push @italic_parts, { type => 'italic', content => $1 };
|
||||||
return "\x01I$idx\x02";
|
return "\x01I$idx\x02";
|
||||||
}->()/ge;
|
}->()/ge;
|
||||||
$text =~ s/_([^_]+)_/sub {
|
$text =~ s/(?<!\w)_((?:[^_]|_(?!_))+?)_(?!\w)/sub {
|
||||||
my $idx = $italic_idx++;
|
my $idx = $italic_idx++;
|
||||||
push @italic_parts, { type => 'italic', content => $1 };
|
push @italic_parts, { type => 'italic', content => $1 };
|
||||||
return "\x01I$idx\x02";
|
return "\x01I$idx\x02";
|
||||||
@@ -312,7 +312,7 @@ sub parse_inline {
|
|||||||
push @italic_parts, { type => 'italic', content => $1 };
|
push @italic_parts, { type => 'italic', content => $1 };
|
||||||
return "\x01I$idx\x02";
|
return "\x01I$idx\x02";
|
||||||
}->()/ge;
|
}->()/ge;
|
||||||
$content =~ s/_([^_]+)_/sub {
|
$content =~ s/(?<!\w)_((?:[^_]|_(?!_))+?)_(?!\w)/sub {
|
||||||
my $idx = $italic_idx++;
|
my $idx = $italic_idx++;
|
||||||
push @italic_parts, { type => 'italic', content => $1 };
|
push @italic_parts, { type => 'italic', content => $1 };
|
||||||
return "\x01I$idx\x02";
|
return "\x01I$idx\x02";
|
||||||
@@ -379,10 +379,22 @@ s/\x01F$i\x02/<$part->{tag}>@{[escape_html($part->{content})]}<\/$part->{tag}>/;
|
|||||||
|
|
||||||
sub is_safe_url {
|
sub is_safe_url {
|
||||||
my ($url) = @_;
|
my ($url) = @_;
|
||||||
return 0 if $url =~ /^\s*javascript:/i;
|
my $normalized = $url // '';
|
||||||
return 0 if $url =~ /^\s*data:/i;
|
|
||||||
return 0 if $url =~ /^\s*vbscript:/i;
|
$normalized =~ s/^\s+//;
|
||||||
return 0 if $url =~ /^\s*file:/i;
|
$normalized =~ s/\s+$//;
|
||||||
|
$normalized =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg
|
||||||
|
while $normalized =~ /%[0-9A-Fa-f]{2}/;
|
||||||
|
$normalized =~ s/&#x([0-9A-Fa-f]+);?/chr(hex($1))/eg;
|
||||||
|
$normalized =~ s/&#(\d+);?/chr($1)/eg;
|
||||||
|
|
||||||
|
if ( $normalized =~ /^([a-z][a-z0-9+\-.]*):/i ) {
|
||||||
|
my $scheme = lc $1;
|
||||||
|
return 1
|
||||||
|
if $scheme eq 'http' || $scheme eq 'https' || $scheme eq 'mailto';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,4 +409,3 @@ sub escape_html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Test::More tests => 11;
|
use Test::More tests => 13;
|
||||||
use MarkdownParser;
|
use MarkdownParser;
|
||||||
|
|
||||||
my $parser = MarkdownParser->new();
|
my $parser = MarkdownParser->new();
|
||||||
@@ -62,4 +62,7 @@ is(
|
|||||||
"<p><strong>bold text</strong></p>\n",
|
"<p><strong>bold text</strong></p>\n",
|
||||||
"Bold with ___"
|
"Bold with ___"
|
||||||
);
|
);
|
||||||
|
is( $parser->parse("my_variable"),
|
||||||
|
"<p>my_variable</p>\n", "Underscore inside word unchanged" );
|
||||||
|
is( $parser->parse("CONST__VALUE"),
|
||||||
|
"<p>CONST__VALUE</p>\n", "Double underscores inside word unchanged" );
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Test::More tests => 8;
|
use Test::More tests => 10;
|
||||||
use MarkdownParser;
|
use MarkdownParser;
|
||||||
|
|
||||||
my $parser = MarkdownParser->new();
|
my $parser = MarkdownParser->new();
|
||||||
@@ -37,8 +37,14 @@ is(
|
|||||||
"<p>Click me</p>\n",
|
"<p>Click me</p>\n",
|
||||||
"Data protocol blocked in links"
|
"Data protocol blocked in links"
|
||||||
);
|
);
|
||||||
|
is(
|
||||||
|
$parser->parse("[Click me](javascript:alert('XSS'))"),
|
||||||
|
"<p>Click me</p>\n",
|
||||||
|
"Encoded JavaScript protocol blocked in links"
|
||||||
|
);
|
||||||
is( $parser->parse(")"),
|
is( $parser->parse(")"),
|
||||||
"<p>Image</p>\n", "JavaScript protocol blocked in images" );
|
"<p>Image</p>\n", "JavaScript protocol blocked in images" );
|
||||||
is( $parser->parse(""),
|
is( $parser->parse(""),
|
||||||
"<p>Image</p>\n", "File protocol blocked in images" );
|
"<p>Image</p>\n", "File protocol blocked in images" );
|
||||||
|
is( $parser->parse(")"),
|
||||||
|
"<p>Image</p>\n", "Encoded JavaScript protocol blocked in images" );
|
||||||
|
|||||||
Reference in New Issue
Block a user