File Coverage

blib/lib/Perl/Critic/Policy/RegularExpressions/RequireDefault.pm
Criterion Covered Total %
statement 41 46 89.1
branch 12 16 75.0
condition 11 17 64.7
subroutine 13 14 92.8
pod 5 5 100.0
total 82 98 83.6


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::RegularExpressions::RequireDefault;
2              
3 2     2   1718 use 5.006;
  2         9  
4 2     2   12 use strict;
  2         4  
  2         41  
5 2     2   10 use warnings;
  2         4  
  2         57  
6 2     2   1145 use Readonly;
  2         8071  
  2         131  
7              
8 2     2   1340 use Perl::Critic::Utils qw{ :booleans :severities };
  2         259677  
  2         41  
9              
10 2     2   1555 use base 'Perl::Critic::Policy';
  2         6  
  2         1246  
11              
12             our $VERSION = '2.02'; # VERSION: generated by DZP::OurPkgVersion
13              
14             #-----------------------------------------------------------------------------
15              
16             Readonly::Scalar my $DESC => q{Regular expression without "/a" or "/aa" flag};
17             Readonly::Scalar my $EXPL => q{Use regular expression "/a" or "/aa" flag};
18              
19             #-----------------------------------------------------------------------------
20              
21 3     3 1 68 sub default_severity { return $SEVERITY_MEDIUM }
22 0     0 1 0 sub default_themes { return qw< security > }
23              
24             sub applies_to {
25 13     13 1 116888 return qw<
26             PPI::Token::Regexp::Match
27             PPI::Token::Regexp::Substitute
28             PPI::Token::QuoteLike::Regexp
29             PPI::Statement::Include
30             >;
31             }
32              
33             #-----------------------------------------------------------------------------
34              
35             sub violates {
36 19     19 1 1112 my ( $self, $elem, $doc ) = @_;
37              
38 19 50       99 if ( $self->_pragma_enabled($elem) ) {
39 0         0 return; # ok!;
40             }
41              
42 19 100       79 my $re = $doc->ppix_regexp_from_element($elem)
43             or return;
44              
45 13 100       61680 if ( not $self->_allowed_modifier($re)) {
46 3         63 return $self->violation( $DESC, $EXPL, $elem );
47             }
48              
49 10         49 return; # ok!;
50             }
51              
52             sub _allowed_modifier {
53 13     13   60 my ( $self, $re ) = @_;
54              
55 13 100 100     77 if ( $re->modifier_asserted('a') and not $self->{_strict} ) {
56 4         115 return $TRUE;
57             }
58              
59 9 100       245 if ( $re->modifier_asserted('aa') ) {
60 6         116 return $TRUE;
61             }
62              
63 3         62 return $FALSE;
64             }
65              
66              
67             sub _correct_modifier {
68 6     6   523 my ( $self, $elem ) = @_;
69              
70 6 50 33     29 if ( $elem->arguments eq 'a' and not $self->{_strict} ) {
71 0         0 return $TRUE;
72             }
73              
74 6 50       294 if ( $elem->arguments eq 'aa' ) {
75 0         0 return $TRUE;
76             }
77              
78 6         192 return $FALSE;
79             }
80              
81             sub _pragma_enabled {
82 19     19   62 my ( $self, $elem ) = @_;
83              
84 19 50 66     188 if ( $elem->can('type')
      66        
      33        
85             and $elem->type() eq 'use'
86             and $elem->pragma() eq 're'
87             and $self->_correct_modifier($elem) )
88             {
89 0         0 return $TRUE;
90             }
91              
92 19         79 return $FALSE;
93             }
94              
95             sub initialize_if_enabled {
96 3     3 1 2618915 my ( $self, $config ) = @_;
97              
98 3   100     24 $self->{_strict} = $config->get('strict') || 0;
99              
100 3         53 return $TRUE;
101             }
102              
103             1;
104              
105             __END__
106              
107             =pod
108              
109             =begin markdown
110              
111             # Perl::Critic::Policy::RegularExpressions::RequireDefault
112              
113             [![CPAN version](https://badge.fury.io/pl/Perl-Critic-Policy-RegularExpressions-RequireDefault.svg)](https://badge.fury.io/pl/Perl-Critic-Policy-RegularExpressions-RequireDefault)
114             ![stability-stable](https://img.shields.io/badge/stability-stable-green.svg)
115             [![Build Status](https://travis-ci.org/jonasbn/perl-critic-policy-module-moduleblacklist.svg?branch=master)](https://travis-ci.org/jonasbn/perl-critic-policy-module-moduleblacklist)
116             [![Coverage Status](https://coveralls.io/repos/github/jonasbn/perl-critic-policy-module-moduleblacklist/badge.svg?branch=master)](https://coveralls.io/github/jonasbn/perl-critic-policy-module-moduleblacklist?branch=master)
117             [![License: Artistic-2.0](https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg)](https://opensource.org/licenses/Artistic-2.0)
118              
119             =end markdown
120              
121             =begin stopwords
122              
123             Posix pragma pragmas Readonly TODO perlre OWASP AppSecDC Pragma jonasbn ACKNOWLEDGEMENTS Joelle Maslak JMASLAK DBOOK
124              
125             =end stopwords
126              
127             =head1 NAME
128              
129             Perl::Critic::Policy::RegularExpressions::RequireDefault - Always use the C</a> or C</aa> modifier with regular expressions.
130              
131             =head1 VERSION
132              
133             This documentation describes version 2.01
134              
135             =head1 AFFILIATION
136              
137             This policy has no affiliation
138              
139             =head1 DESCRIPTION
140              
141             This policy aims to help enforce Perl's protective measures against security vulnerabilities related to Unicode, such as:
142              
143             =over
144              
145             =item * Visual Spoofing
146              
147             =item * Character and String Transformation Vulnerabilities
148              
149             =back
150              
151             The C</a> and C</aa> modifiers standing for ASCII-restrict or ASCII-safe, provides protection for applications that do not need to be exposed to all of Unicode and possible security issues with Unicode.
152              
153             C</a> causes the sequences C<\d>, C<\s>, C<\w>, and the Posix character classes to match only in the ASCII range. Meaning:
154              
155             =over
156              
157             =item * C<\d> means the digits C<0> to C<9>
158              
159             my $ascii_letters =~ m/[A-Z]*/i; # not ok
160             my $ascii_letters =~ m/[A-Z]*/a; # ok
161             my $ascii_letters =~ m/[A-Z]*/aa; # ok
162              
163             =item * C<\s> means the five characters C<[ \f\n\r\t]>, and starting in Perl v5.18, also the vertical tab
164              
165             my $characters =~ m/[ \f\n\r\t]*/; # not ok
166             my $characters =~ m/[ \f\n\r\t]*/a; # ok
167             my $characters =~ m/[ \f\n\r\t]*/aa; # ok
168              
169             =item * C<\w> means the 63 characters C<[A-Za-z0-9_]> and all the Posix classes such as C<[[:print:]]> match only the appropriate ASCII-range characters
170              
171             my $letters =~ m/[A-Za-z0-9_]*/; # not ok
172             my $letters =~ m/[A-Za-z0-9_]*/a; # ok
173             my $letters =~ m/[A-Za-z0-9_]*/aa; # ok
174              
175             =back
176              
177             The policy also supports the pragma:
178              
179             use re '/a';
180              
181             and:
182              
183             use re '/aa';
184              
185             Which mean it will not evaluate the regular expressions any further:
186              
187             use re '/a';
188             my $letters =~ m/[A-Za-z0-9_]*/; # ok
189              
190             Do note that the C</a> and C</aa> modifiers require Perl 5.14, so by using the recommended modifiers you indirectly introduce a requirement for Perl 5.14.
191              
192             This policy is inspired by L<Perl::Critic::Policy::RegularExpressions::RequireExtendedFormatting|https://metacpan.org/pod/Perl::Critic::Policy::RegularExpressions::RequireExtendedFormatting> and many implementation details was lifted from this particular distribution.
193              
194             =head1 CONFIGURATION AND ENVIRONMENT
195              
196             The policy has a single configuration parameter: C<strict>. The default is disabled (C<0>).
197              
198             The policy, if enabled, allow for both C<'a'> and C<'aa'>, if strict however is enabled, C<'a'> will trigger a violation and C<'aa'> will not.
199              
200             Example configuration:
201              
202             [RegularExpressions::RequireDefault]
203             strict = 1
204              
205             Do note that the policy also evaluates if the pragmas are enabled, meaning: C<use re 'a';> will trigger a violation and C<use re 'a';> will not if the policy is configured for strict evaluation.
206              
207             =head1 INCOMPATIBILITIES
208              
209             This distribution holds no known incompatibilities at this time, please see L</DEPENDENCIES AND REQUIREMENTS> for details on version requirements.
210              
211             =head1 BUGS AND LIMITATIONS
212              
213             =over
214              
215             =item * The pragma handling does not take into consideration of a pragma is disabled.
216              
217             =item * The pragma handling does not take lexical scope into consideration properly and only detects the definition once
218              
219             =back
220              
221             This distribution holds no other known limitations or bugs at this time, please refer to the L<the issue listing on GitHub|https://github.com/jonasbn/perl-critic-policy-regularexpressions-requiredefault/issues> for more up to date information.
222              
223             =head1 BUG REPORTING
224              
225             Please report bugs via L<GitHub|https://github.com/jonasbn/perl-critic-policy-regularexpressions-requiredefault/issues>.
226              
227             =head1 TEST AND QUALITY
228              
229             This distribution aims to adhere to the Perl::Critic::Policy standards and Perl best practices and recommendations.
230              
231             =head1 DEPENDENCIES AND REQUIREMENTS
232              
233             This distribution requires:
234              
235             =over
236              
237             =item * Perl 5.6.0 syntactically for the actual implementation
238              
239             =item * L<Perl 5.14|https://metacpan.org/pod/release/JESSE/perl-5.14.0/pod/perl.pod> for developing the distribution, which relies on L<Dist::Zilla|http://dzil.org/>. The features on which this policy relies, where introduced in Perl 5.14, but this does not make for an actual requirement for the policy only the recommendations it imposes.
240              
241             =item * L<Carp|https://metacpan.org/pod/Carp>, in core since Perl 5.
242              
243             =item * L<Readonly|https://metacpan.org/pod/Readonly>
244              
245             =item * L<Perl::Critic::Policy|https://metacpan.org/pod/Perl::Critic::Policy>
246              
247             =item * L<Perl::Critic::Utils|https://metacpan.org/pod/Perl::Critic::Utils>, part of Perl::Critic
248              
249             =back
250              
251             Please see the listing in the file: F<cpanfile>, included with the distribution for a complete listing and description for configuration, test and development.
252              
253             =head1 TODO
254              
255             Ideas and suggestions for improvements and new features are listed in GitHub and are marked as C<enhancement>.
256              
257             =over
258              
259             =item * Please see L<the issue listing on GitHub|https://github.com/jonasbn/perl-critic-policy-regularexpressions-requiredefault/issues>
260              
261             =back
262              
263             =head1 SEE ALSO
264              
265             =over
266              
267             =item * L<Perl regular expression documentation: perlre|https://perldoc.perl.org/perlre.html>
268              
269             =item * L<Perl delta file describing introduction of modifiers in Perl 5.14|https://perldoc.pl/perl5140delta#%2Fd%2C-%2Fl%2C-%2Fu%2C-and-%2Fa-modifiers>
270              
271             =item * L<Unicode Security Issues FAQ|http://www.unicode.org/faq/security.html>
272              
273             =item * L<Unicode Security Guide|http://websec.github.io/unicode-security-guide/>
274              
275             =item * L<Presentation: "Unicode Transformations: Finding Elusive Vulnerabilities" by Chris Weber for OWASP AppSecDC November 2009|https://www.owasp.org/images/5/5a/Unicode_Transformations_Finding_Elusive_Vulnerabilities-Chris_Weber.pdf>
276              
277             =item * L<Perl::Critic|https://metacpan.org/pod/Perl::Critic>
278              
279             =item * L<Perl::Critic::Policy::RegularExpressions::RequireExtendedFormatting|https://metacpan.org/pod/Perl::Critic::Policy::RegularExpressions::RequireExtendedFormatting>
280              
281             =item * L<Perl Pragma Documentation|https://perldoc.perl.org/re.html>
282              
283             =back
284              
285             =head1 MOTIVATION
286              
287             The motivation for this Perl::Critic policy came from a L<tweet|https://twitter.com/jmaslak/status/1008896883169751040> by L<@joel|https://twitter.com/jmaslak>
288              
289             | Perl folk: Looking for a PR challenge task? Check for \d in regexes
290             | that really should be [0-9] or should have the /a regex modifier.
291             | Perl is multinational by default! #TPCiSLC
292              
293             =head1 AUTHOR
294              
295             =over
296              
297             =item * Jonas B. (jonasbn) <jonasbn@cpan.org>
298              
299             =back
300              
301             =head1 ACKNOWLEDGEMENTS
302              
303             =over
304              
305             =item * L<Joelle Maslak (@joel)|https://twitter.com/jmaslak> / L<JMASLAK|https://metacpan.org/author/JMASLAK> for the initial idea, see link to original tweet under L</MOTIVATION>
306              
307             =item * L<Dan Book (@Grinnz)|https://github.com/Grinnz> / L<DBOOK|https://metacpan.org/author/DBOOK> for information on Pragma and requirement for Perl 5.14, when using the modifiers handled and mentioned by this policy
308              
309             =back
310              
311             =head1 LICENSE AND COPYRIGHT
312              
313             Perl::Critic::Policy::RegularExpressions::RequireDefault is (C) by jonasbn 2018-2019
314              
315             Perl::Critic::Policy::RegularExpressions::RequireDefault is released under the Artistic License 2.0
316              
317             Please see the LICENSE file included with the distribution of this module
318              
319             =cut