diff options
author | Mike Fulton <mikefultonpersonal@gmail.com> | 2022-01-14 16:23:47 -0800 |
---|---|---|
committer | Karl Williamson <khw@cpan.org> | 2022-01-19 18:15:54 -0700 |
commit | 0b66d70fe7769af01a6bea67bd2ea91b2404eb4b (patch) | |
tree | 786bb10be872bda482b2b8de7b5de699cc40c8bf | |
parent | 7c5e8757892abf1a831f67919b4c01339c8cac7c (diff) | |
download | perl-0b66d70fe7769af01a6bea67bd2ea91b2404eb4b.tar.gz |
Provide inclusive names allowlist and denylist
Updated the following files:
AUTHORS:
- corrected my email address
MANIFEST:
- added new testcases for Locale-Maketext
dist/Locale-Maketext/ChangeLog:
- short summary of changes made
dist/Locale-Maketext/lib/Locale/Maketext.pm:
- updated the version to 1.30
- refactored the code to create a common method _include
called by the allowlist and whitelist methods
(whitelist is now an alias, deprecated method, for allowlist).
The _include method now has an internal list called allowlist
that is updated by calls to _include through whitelist or
allowlist methods.
- refactored the code to create a common method _exclude
called by the denylist and blacklist methods
(blacklist is now an alias, deprecated method, for denylist).
The _exclude method now has an internal list called denylist
that is updated by calls to _exclude through blacklist or
denylist methods.
dist/Locale-Maketext/lib/Locale/Maketext.pod:
- documented allowlist and denylist as new methods
- added a NOTE for allowlist and denylist indicating that
they are now the preferred method names to use instead
of whitelist and blacklist
dist/Locale-Maketext/t/92_blacklist.t
- updated the code to have messages in terms of allowlist
and denylist. Actual code continues to test blacklist
method.
dist/Locale-Maketext/t/93_whitelist.t
- updated the code to have messages in terms of allowlist
and denylist. Actual code continues to test whitelist
method.
Created 2 new testcases:
dist/Locale-Maketext/t/94_denylist.t
- this testcase is analagous to 92_blacklist.t but calls
the denylist method instead of the blacklist method.
dist/Locale-Maketext/t/95_allowlist.t
- this testcase is analagous to 93_whitelist.t but calls
the allowlist method instead of the whitelist method.
-rw-r--r-- | AUTHORS | 2 | ||||
-rw-r--r-- | MANIFEST | 2 | ||||
-rw-r--r-- | dist/Locale-Maketext/ChangeLog | 5 | ||||
-rw-r--r-- | dist/Locale-Maketext/lib/Locale/Maketext.pm | 49 | ||||
-rw-r--r-- | dist/Locale-Maketext/lib/Locale/Maketext.pod | 54 | ||||
-rw-r--r-- | dist/Locale-Maketext/t/92_blacklist.t | 34 | ||||
-rw-r--r-- | dist/Locale-Maketext/t/93_whitelist.t | 42 | ||||
-rw-r--r-- | dist/Locale-Maketext/t/94_denylist.t | 93 | ||||
-rw-r--r-- | dist/Locale-Maketext/t/95_allowlist.t | 96 |
9 files changed, 307 insertions, 70 deletions
@@ -915,7 +915,7 @@ Michiel Beijen <mb@x14.nl> Mik Firestone <fireston@lexmark.com> Mike Doherty <mike@mikedoherty.ca> Mike Fletcher <fletch@phydeaux.org> -Mike Fulton <61100689+mikefultondev@users.noreply.github.com> +Mike Fulton <mikefultonpersonal@gmail.com> Mike Giroux <rmgiroux@acm.org> Mike Guy <mjtg@cam.ac.uk> Mike Heins <mike@bill.iac.net> @@ -3828,6 +3828,8 @@ dist/Locale-Maketext/t/90_utf8.t See if Locale::Maketext works dist/Locale-Maketext/t/91_backslash.t See if Locale::Maketext works dist/Locale-Maketext/t/92_blacklist.t See if Locale::Maketext works dist/Locale-Maketext/t/93_whitelist.t See if Locale::Maketext works +dist/Locale-Maketext/t/94_denylist.t See if Locale::Maketext works +dist/Locale-Maketext/t/95_allowlist.t See if Locale::Maketext works dist/Module-CoreList/Changes Module::CoreList Changes dist/Module-CoreList/corelist The corelist command-line utility dist/Module-CoreList/identify-dependencies A usage example for Module::CoreList diff --git a/dist/Locale-Maketext/ChangeLog b/dist/Locale-Maketext/ChangeLog index d9b524f8ac..2edc0aedd9 100644 --- a/dist/Locale-Maketext/ChangeLog +++ b/dist/Locale-Maketext/ChangeLog @@ -1,5 +1,10 @@ Revision history for Perl suite Locale::Maketext +2022-01-14 + * Release 1.30 to CPAN + * Provide alternate methods allowlist and denylist for + whitelist and blacklist, respectively + 2020-01-19 * Release 1.29 to CPAN * Replace multiple 'use vars' by 'our' diff --git a/dist/Locale-Maketext/lib/Locale/Maketext.pm b/dist/Locale-Maketext/lib/Locale/Maketext.pm index f70438b78d..ca2242664d 100644 --- a/dist/Locale-Maketext/lib/Locale/Maketext.pm +++ b/dist/Locale-Maketext/lib/Locale/Maketext.pm @@ -25,7 +25,7 @@ BEGIN { } -our $VERSION = '1.29'; +our $VERSION = '1.30'; our @ISA = (); our $MATCH_SUPERS = 1; @@ -136,19 +136,20 @@ sub fail_with { # an actual attribute method! #-------------------------------------------------------------------------- -sub blacklist { - my ( $handle, @methods ) = @_; +sub _exclude { + my ( $handle, @methods ) = @_; - unless ( defined $handle->{'blacklist'} ) { + unless ( defined $handle->{'denylist'} ) { no strict 'refs'; # Don't let people call methods they're not supposed to from maketext. # Explicitly exclude all methods in this package that start with an # underscore on principle. - $handle->{'blacklist'} = { + $handle->{'denylist'} = { map { $_ => 1 } ( qw/ blacklist + denylist encoding fail_with failure_handler_auto @@ -160,30 +161,55 @@ sub blacklist { maketext new whitelist + allowlist /, grep { /^_/ } keys %{ __PACKAGE__ . "::" } ), }; } if ( scalar @methods ) { - $handle->{'blacklist'} = { %{ $handle->{'blacklist'} }, map { $_ => 1 } @methods }; + $handle->{'denylist'} = { %{ $handle->{'denylist'} }, map { $_ => 1 } @methods }; } delete $handle->{'_external_lex_cache'}; return; } -sub whitelist { +sub blacklist { + my ( $handle, @methods ) = @_; + _exclude ( $handle, @methods ); + return; +} + +sub denylist { + my ( $handle, @methods ) = @_; + _exclude ( $handle, @methods ); + return; +} + +sub _include { my ( $handle, @methods ) = @_; if ( scalar @methods ) { - $handle->{'whitelist'} = {} unless defined $handle->{'whitelist'}; - $handle->{'whitelist'} = { %{ $handle->{'whitelist'} }, map { $_ => 1 } @methods }; + $handle->{'allowlist'} = {} unless defined $handle->{'allowlist'}; + $handle->{'allowlist'} = { %{ $handle->{'allowlist'} }, map { $_ => 1 } @methods }; } delete $handle->{'_external_lex_cache'}; return; } +sub whitelist { + my ( $handle, @methods ) = @_; + _include ( $handle, @methods ); + return; +} + +sub allowlist { + my ( $handle, @methods ) = @_; + _include ( $handle, @methods ); + return; +} + #-------------------------------------------------------------------------- sub failure_handler_auto { @@ -228,6 +254,7 @@ sub new { my $class = ref($_[0]) || $_[0]; my $handle = bless {}, $class; $handle->blacklist; + $handle->denylist; $handle->init; return $handle; } @@ -679,8 +706,10 @@ sub _compile { } elsif($m =~ /^\w+$/s && !$handle->{'blacklist'}{$m} + && !$handle->{'denylist'}{$m} && ( !defined $handle->{'whitelist'} || $handle->{'whitelist'}{$m} ) - # exclude anything fancy and restrict to the whitelist/blacklist. + && ( !defined $handle->{'allowlist'} || $handle->{'allowlist'}{$m} ) + # exclude anything fancy and restrict to the allowlist/denylist (and historical whitelist/blacklist). ) { push @code, ' $_[0]->' . $m . '('; } diff --git a/dist/Locale-Maketext/lib/Locale/Maketext.pod b/dist/Locale-Maketext/lib/Locale/Maketext.pod index 26be348353..3ea5ea478b 100644 --- a/dist/Locale-Maketext/lib/Locale/Maketext.pod +++ b/dist/Locale-Maketext/lib/Locale/Maketext.pod @@ -307,9 +307,9 @@ interested in hearing about it.) These two methods are discussed in the section "Controlling Lookup Failure". -=item $lh->blacklist(@list) +=item $lh->denylist(@list) <or> $lh->blacklist(@list) -=item $lh->whitelist(@list) +=item $lh->allowlist(@list) <or> $lh->whitelist(@list) These methods are discussed in the section "Bracket Notation Security". @@ -875,17 +875,17 @@ bracket notation methods from normal class or object methods. This design makes it vulnerable to format string attacks whenever it is used to process strings provided by untrusted users. -Locale::Maketext does support blacklist and whitelist functionality +Locale::Maketext does support denylist and allowlist functionality to limit which methods may be called as bracket notation methods. -By default, Locale::Maketext blacklists all methods in the +By default, Locale::Maketext denies all methods in the Locale::Maketext namespace that begin with the '_' character, and all methods which include Perl's namespace separator characters. -The default blacklist for Locale::Maketext also prevents use of the +The default denylist for Locale::Maketext also prevents use of the following methods in bracket notation: - blacklist + denylist encoding fail_with failure_handler_auto @@ -896,44 +896,56 @@ following methods in bracket notation: language_tag maketext new + allowlist whitelist + blacklist -This list can be extended by either blacklisting additional "known bad" -methods, or whitelisting only "known good" methods. +This list can be extended by either deny-listing additional "known bad" +methods, or allow-listing only "known good" methods. To prevent specific methods from being called in bracket notation, use -the blacklist() method: +the denylist() method: my $lh = MyProgram::L10N->get_handle(); - $lh->blacklist(qw{my_internal_method my_other_method}); + $lh->denylist(qw{my_internal_method my_other_method}); $lh->maketext('[my_internal_method]'); # dies To limit the allowed bracked notation methods to a specific list, use the -whitelist() method: +allowlist() method: my $lh = MyProgram::L10N->get_handle(); - $lh->whitelist('numerate', 'numf'); + $lh->allowlist('numerate', 'numf'); $lh->maketext('[_1] [numerate, _1,shoe,shoes]', 12); # works $lh->maketext('[my_internal_method]'); # dies -The blacklist() and whitelist() methods extend their internal lists -whenever they are called. To reset the blacklist or whitelist, create +The denylist() and allowlist() methods extend their internal lists +whenever they are called. To reset the denylist or allowlist, create a new maketext object. my $lh = MyProgram::L10N->get_handle(); - $lh->blacklist('numerate'); - $lh->blacklist('numf'); + $lh->denylist('numerate'); + $lh->denylist('numf'); $lh->maketext('[_1] [numerate,_1,shoe,shoes]', 12); # dies For lexicons that use an internal cache, translations which have already been cached in their compiled form are not affected by subsequent changes -to the whitelist or blacklist settings. Lexicons that use an external -cache will have their cache cleared whenever the whitelist of blacklist -setings change. The difference between the two types of caching is explained +to the allowlist or denylist settings. Lexicons that use an external +cache will have their cache cleared whenever the allowlist or denylist +settings change. The difference between the two types of caching is explained in the "Readonly Lexicons" section. -Methods disallowed by the blacklist cannot be permitted by the -whitelist. +Methods disallowed by the denylist cannot be permitted by the +allowlist. + +NOTE: denylist() is the preferred method name to use instead of the +historical and non-inclusive method blacklist(). blacklist() may be +removed in a future release of this package and so it's use should be +removed from usage. + +NOTE: allowlist() is the preferred method name to use instead of the +historical and non-inclusive method whitelist(). whitelist() may be +removed in a future release of this package and so it's use should be +removed from usage. =head1 AUTO LEXICONS diff --git a/dist/Locale-Maketext/t/92_blacklist.t b/dist/Locale-Maketext/t/92_blacklist.t index 6ed36d1edd..6605d835ce 100644 --- a/dist/Locale-Maketext/t/92_blacklist.t +++ b/dist/Locale-Maketext/t/92_blacklist.t @@ -48,46 +48,46 @@ my $res; # get_handle blocked by default $res = eval { $lh->maketext('[get_handle,en]') }; is( $res, undef, 'no return value from blocked expansion' ); -like( $@, qr/Can't use .* as a method name/, 'get_handle blocked in bracket notation by default blacklist' ); +like( $@, qr/Can't use .* as a method name/, 'get_handle blocked in bracket notation by default denylist' ); # _ambient_langprefs blocked by default $res = eval { $lh->maketext('[_ambient_langprefs]') }; is( $res, undef, 'no return value from blocked expansion' ); -like( $@, qr/Can't use .* as a method name/, '_ambient_langprefs blocked in bracket notation by default blacklist' ); +like( $@, qr/Can't use .* as a method name/, '_ambient_langprefs blocked in bracket notation by default denylist' ); # _internal_method not blocked by default $res = eval { $lh->maketext('[_internal_method]') }; -is( $res, "_internal_method_response", '_internal_method allowed in bracket notation by default blacklist' ); -is( $@, '', 'no exception thrown by use of _internal_method under default blacklist' ); +is( $res, "_internal_method_response", '_internal_method allowed in bracket notation by default denylist' ); +is( $@, '', 'no exception thrown by use of _internal_method under default denylist' ); # sprintf not blocked by default $res = eval { $lh->maketext('[sprintf,%s,hello]') }; -is( $res, "hello", 'sprintf allowed in bracket notation by default blacklist' ); -is( $@, '', 'no exception thrown by use of sprintf under default blacklist' ); +is( $res, "hello", 'sprintf allowed in bracket notation by default denylist' ); +is( $@, '', 'no exception thrown by use of sprintf under default denylist' ); -# blacklisting sprintf and numerate +# denylisting sprintf and numerate $lh->blacklist( 'sprintf', 'numerate' ); -# sprintf blocked by custom blacklist +# sprintf blocked by custom denylist $res = eval { $lh->maketext('[sprintf,%s,hello]') }; is( $res, undef, 'no return value from blocked expansion' ); -like( $@, qr/Can't use .* as a method name/, 'sprintf blocked in bracket notation by custom blacklist' ); +like( $@, qr/Can't use .* as a method name/, 'sprintf blocked in bracket notation by custom denylist' ); -# blacklisting numf and _internal_method +# denylisting numf and _internal_method $lh->blacklist('numf'); $lh->blacklist('_internal_method'); -# sprintf blocked by custom blacklist +# sprintf blocked by custom denylist $res = eval { $lh->maketext('[sprintf,%s,hello]') }; is( $res, undef, 'no return value from blocked expansion' ); -like( $@, qr/Can't use .* as a method name/, 'sprintf blocked in bracket notation by custom blacklist after extension of blacklist' ); +like( $@, qr/Can't use .* as a method name/, 'sprintf blocked in bracket notation by custom denylist after extension of denylist' ); -# _internal_method blocked by custom blacklist +# _internal_method blocked by custom denylist $res = eval { $lh->maketext('[_internal_method]') }; is( $res, undef, 'no return value from blocked expansion' ); -like( $@, qr/Can't use .* as a method name/, 'sprintf blocked in bracket notation by custom blacklist after extension of blacklist' ); +like( $@, qr/Can't use .* as a method name/, 'sprintf blocked in bracket notation by custom denylist after extension of denylist' ); -# custom_handler not in default or custom blacklist +# custom_handler not in default or custom denylist $res = eval { $lh->maketext('[custom_handler]') }; -is( $res, "custom_handler_response", 'custom_handler allowed in bracket notation by default and custom blacklists' ); -is( $@, '', 'no exception thrown by use of custom_handler under default and custom blacklists' ); +is( $res, "custom_handler_response", 'custom_handler allowed in bracket notation by default and custom denylist' ); +is( $@, '', 'no exception thrown by use of custom_handler under default and custom denylist' ); diff --git a/dist/Locale-Maketext/t/93_whitelist.t b/dist/Locale-Maketext/t/93_whitelist.t index 21f2d8574e..15e6678a8f 100644 --- a/dist/Locale-Maketext/t/93_whitelist.t +++ b/dist/Locale-Maketext/t/93_whitelist.t @@ -47,50 +47,50 @@ my $res; # _internal_method not blocked by default $res = eval { $lh->maketext('[_internal_method]') }; -is( $res, "_internal_method_response", '_internal_method allowed when no whitelist defined' ); -is( $@, '', 'no exception thrown by use of _internal_method without whitelist setting' ); +is( $res, "_internal_method_response", '_internal_method allowed when no allowlist defined' ); +is( $@, '', 'no exception thrown by use of _internal_method without allowlist setting' ); -# whitelisting sprintf +# allowlisting sprintf $lh->whitelist('sprintf'); -# _internal_method blocked by whitelist +# _internal_method blocked by allowlist $res = eval { $lh->maketext('[_internal_method]') }; is( $res, undef, 'no return value from blocked expansion' ); -like( $@, qr/Can't use .* as a method name/, '_internal_method blocked in bracket notation by whitelist' ); +like( $@, qr/Can't use .* as a method name/, '_internal_method blocked in bracket notation by allowlist' ); -# sprintf allowed by whitelist +# sprintf allowed by allowlist $res = eval { $lh->maketext('[sprintf,%s,hello]') }; -is( $res, "hello", 'sprintf allowed in bracket notation by whitelist' ); -is( $@, '', 'no exception thrown by use of sprintf with whitelist' ); +is( $res, "hello", 'sprintf allowed in bracket notation by allowlist' ); +is( $@, '', 'no exception thrown by use of sprintf with allowlist' ); -# custom_handler blocked by whitelist +# custom_handler blocked by allowlist $res = eval { $lh->maketext('[custom_handler]') }; is( $res, undef, 'no return value from blocked expansion' ); -like( $@, qr/Can't use .* as a method name/, 'custom_handler blocked in bracket notation by whitelist' ); +like( $@, qr/Can't use .* as a method name/, 'custom_handler blocked in bracket notation by allowlist' ); -# adding custom_handler to whitelist +# adding custom_handler to allowlist $lh->whitelist('custom_handler'); -# sprintf still allowed by whitelist +# sprintf still allowed by allowlist $res = eval { $lh->maketext('[sprintf,%s,hello]') }; -is( $res, "hello", 'sprintf allowed in bracket notation by whitelist' ); -is( $@, '', 'no exception thrown by use of sprintf with whitelist' ); +is( $res, "hello", 'sprintf allowed in bracket notation by allowlist' ); +is( $@, '', 'no exception thrown by use of sprintf with allowlist' ); -# custom_handler allowed by whitelist +# custom_handler allowed by allowlist $res = eval { $lh->maketext('[custom_handler]') }; -is( $res, "custom_handler_response", 'custom_handler allowed in bracket notation by whitelist' ); -is( $@, '', 'no exception thrown by use of custom_handler with whitelist' ); +is( $res, "custom_handler_response", 'custom_handler allowed in bracket notation by allowlist' ); +is( $@, '', 'no exception thrown by use of custom_handler with allowlist' ); -# _internal_method blocked by whitelist +# _internal_method blocked by allowlist $res = eval { $lh->maketext('[_internal_method]') }; is( $res, undef, 'no return value from blocked expansion' ); -like( $@, qr/Can't use .* as a method name/, '_internal_method blocked in bracket notation by whitelist' ); +like( $@, qr/Can't use .* as a method name/, '_internal_method blocked in bracket notation by allowlist' ); -# adding fail_with to whitelist +# adding fail_with to allowlist $lh->whitelist('fail_with'); # fail_with still blocked by blacklist $res = eval { $lh->maketext('[fail_with,xyzzy]') }; is( $res, undef, 'no return value from blocked expansion' ); -like( $@, qr/Can't use .* as a method name/, 'fail_with blocked in bracket notation by blacklist even when whitelisted' ); +like( $@, qr/Can't use .* as a method name/, 'fail_with blocked in bracket notation by blacklist even when allowlisted' ); diff --git a/dist/Locale-Maketext/t/94_denylist.t b/dist/Locale-Maketext/t/94_denylist.t new file mode 100644 index 0000000000..73574e67f8 --- /dev/null +++ b/dist/Locale-Maketext/t/94_denylist.t @@ -0,0 +1,93 @@ +#!/usr/bin/perl -Tw + +use strict; +use warnings; +use Test::More tests => 17; + +BEGIN { + use_ok("Locale::Maketext"); +} + +{ + + package MyTestLocale; + no warnings 'once'; + + @MyTestLocale::ISA = qw(Locale::Maketext); + %MyTestLocale::Lexicon = (); +} + +{ + + package MyTestLocale::en; + no warnings 'once'; + + @MyTestLocale::en::ISA = qw(MyTestLocale); + + %MyTestLocale::en::Lexicon = ( '_AUTO' => 1 ); + + sub custom_handler { + return "custom_handler_response"; + } + + sub _internal_method { + return "_internal_method_response"; + } + + sub new { + my ( $class, @args ) = @_; + my $lh = $class->SUPER::new(@args); + $lh->{use_external_lex_cache} = 1; + return $lh; + } +} + +my $lh = MyTestLocale->get_handle('en'); +my $res; + +# get_handle blocked by default +$res = eval { $lh->maketext('[get_handle,en]') }; +is( $res, undef, 'no return value from blocked expansion' ); +like( $@, qr/Can't use .* as a method name/, 'get_handle blocked in bracket notation by default denylist' ); + +# _ambient_langprefs blocked by default +$res = eval { $lh->maketext('[_ambient_langprefs]') }; +is( $res, undef, 'no return value from blocked expansion' ); +like( $@, qr/Can't use .* as a method name/, '_ambient_langprefs blocked in bracket notation by default denylist' ); + +# _internal_method not blocked by default +$res = eval { $lh->maketext('[_internal_method]') }; +is( $res, "_internal_method_response", '_internal_method allowed in bracket notation by default denylist' ); +is( $@, '', 'no exception thrown by use of _internal_method under default denylist' ); + +# sprintf not blocked by default +$res = eval { $lh->maketext('[sprintf,%s,hello]') }; +is( $res, "hello", 'sprintf allowed in bracket notation by default denylist' ); +is( $@, '', 'no exception thrown by use of sprintf under default denylist' ); + +# denylisting sprintf and numerate +$lh->denylist( 'sprintf', 'numerate' ); + +# sprintf blocked by custom denylist +$res = eval { $lh->maketext('[sprintf,%s,hello]') }; +is( $res, undef, 'no return value from blocked expansion' ); +like( $@, qr/Can't use .* as a method name/, 'sprintf blocked in bracket notation by custom denylist' ); + +# denylisting numf and _internal_method +$lh->denylist('numf'); +$lh->denylist('_internal_method'); + +# sprintf blocked by custom denylist +$res = eval { $lh->maketext('[sprintf,%s,hello]') }; +is( $res, undef, 'no return value from blocked expansion' ); +like( $@, qr/Can't use .* as a method name/, 'sprintf blocked in bracket notation by custom denylist after extension of denylist' ); + +# _internal_method blocked by custom denylist +$res = eval { $lh->maketext('[_internal_method]') }; +is( $res, undef, 'no return value from blocked expansion' ); +like( $@, qr/Can't use .* as a method name/, 'sprintf blocked in bracket notation by custom denylist after extension of denylist' ); + +# custom_handler not in default or custom denylist +$res = eval { $lh->maketext('[custom_handler]') }; +is( $res, "custom_handler_response", 'custom_handler allowed in bracket notation by default and custom denylist' ); +is( $@, '', 'no exception thrown by use of custom_handler under default and custom denylist' ); diff --git a/dist/Locale-Maketext/t/95_allowlist.t b/dist/Locale-Maketext/t/95_allowlist.t new file mode 100644 index 0000000000..eb12e64286 --- /dev/null +++ b/dist/Locale-Maketext/t/95_allowlist.t @@ -0,0 +1,96 @@ +#!/usr/bin/perl -Tw + +use strict; +use warnings; +use Test::More tests => 17; + +BEGIN { + use_ok("Locale::Maketext"); +} + +{ + + package MyTestLocale; + no warnings 'once'; + + @MyTestLocale::ISA = qw(Locale::Maketext); + %MyTestLocale::Lexicon = (); +} + +{ + + package MyTestLocale::en; + no warnings 'once'; + + @MyTestLocale::en::ISA = qw(MyTestLocale); + + %MyTestLocale::en::Lexicon = ( '_AUTO' => 1 ); + + sub custom_handler { + return "custom_handler_response"; + } + + sub _internal_method { + return "_internal_method_response"; + } + + sub new { + my ( $class, @args ) = @_; + my $lh = $class->SUPER::new(@args); + $lh->{use_external_lex_cache} = 1; + return $lh; + } +} + +my $lh = MyTestLocale->get_handle('en'); +my $res; + +# _internal_method not blocked by default +$res = eval { $lh->maketext('[_internal_method]') }; +is( $res, "_internal_method_response", '_internal_method allowed when no allowlist defined' ); +is( $@, '', 'no exception thrown by use of _internal_method without allowlist setting' ); + +# allowlisting sprintf +$lh->allowlist('sprintf'); + +# _internal_method blocked by allowlist +$res = eval { $lh->maketext('[_internal_method]') }; +is( $res, undef, 'no return value from blocked expansion' ); +like( $@, qr/Can't use .* as a method name/, '_internal_method blocked in bracket notation by allowlist' ); + +# sprintf allowed by allowlist +$res = eval { $lh->maketext('[sprintf,%s,hello]') }; +is( $res, "hello", 'sprintf allowed in bracket notation by allowlist' ); +is( $@, '', 'no exception thrown by use of sprintf with allowlist' ); + +# custom_handler blocked by allowlist +$res = eval { $lh->maketext('[custom_handler]') }; +is( $res, undef, 'no return value from blocked expansion' ); +like( $@, qr/Can't use .* as a method name/, 'custom_handler blocked in bracket notation by allowlist' ); + +# adding custom_handler to allowlist +$lh->allowlist('custom_handler'); + +# sprintf still allowed by allowlist +$res = eval { $lh->maketext('[sprintf,%s,hello]') }; +is( $res, "hello", 'sprintf allowed in bracket notation by allowlist' ); +is( $@, '', 'no exception thrown by use of sprintf with allowlist' ); + +# custom_handler allowed by allowlist +$res = eval { $lh->maketext('[custom_handler]') }; +is( $res, "custom_handler_response", 'custom_handler allowed in bracket notation by allowlist' ); +is( $@, '', 'no exception thrown by use of custom_handler with allowlist' ); + +# _internal_method blocked by allowlist +$res = eval { $lh->maketext('[_internal_method]') }; +is( $res, undef, 'no return value from blocked expansion' ); +like( $@, qr/Can't use .* as a method name/, '_internal_method blocked in bracket notation by allowlist' ); + +# adding fail_with to allowlist +$lh->allowlist('fail_with'); + +# fail_with still blocked by denylist +$res = eval { $lh->maketext('[fail_with,xyzzy]') }; +is( $res, undef, 'no return value from blocked expansion' ); +like( $@, qr/Can't use .* as a method name/, 'fail_with blocked in bracket notation by denylist even when allowlisted' ); + |