From 0ad6eba28a52fb24cf8e960d5adea6ae721a13d8 Mon Sep 17 00:00:00 2001 From: Zaahir Moolla Date: Mon, 30 Jan 2017 17:46:21 -0500 Subject: [PATCH] Calculator: Prevent anything but allowed ops in the query (#3903) * prevent anything but allowed ops in the query no negative nums * Uncomment neg catch and move after garbage is removed * Add more tests * The hex check can be simplified since the trigger isn't allowing most of it Allow expressions like 1e9 to pass * Allow = in query decimal/negatives with e * Remove debug * add test for 1e9 query --- lib/DDG/Goodie/Calculator.pm | 24 ++++++++++++------------ t/Calculator.t | 13 +++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/lib/DDG/Goodie/Calculator.pm b/lib/DDG/Goodie/Calculator.pm index e5c0e8b4b14..e64af703db7 100644 --- a/lib/DDG/Goodie/Calculator.pm +++ b/lib/DDG/Goodie/Calculator.pm @@ -15,12 +15,13 @@ use utf8; zci answer_type => 'calc'; zci is_cached => 1; -triggers query_nowhitespace => qr' - (?: [0-9 () x × ∙ ⋅ * % + \- ÷ / \^ \$ \. ,]+ | +triggers query_nowhitespace => qr'^ + (?: [0-9 () x × ∙ ⋅ * % + \- ÷ / \^ \$ \. \, _ =]+ | + what is| calculate | solve | math | times | divided by | plus | minus | fact | factorial | cos | sin | tan | cotan | log | ln | log_?\d{1,3} | exp | tanh | - sec | csc | squared | sqrt | gross | dozen | pi | - score){2,} + sec | csc | squared | sqrt | gross | dozen | pi | e | + score){2,}$ 'xi; my $number_re = number_style_regex(); @@ -82,23 +83,23 @@ $safe->share_from('main', [qw' handle query_nowhitespace => sub { my $query = $_; - # regex source: http://perldoc.perl.org/functions/hex.html - return if ($req->query_lc =~ /\A(?:0?[xX])?(?:_?[0-9a-fA-F])*\z/); # Probably attempt to express a hexadecimal number, query_nowhitespace makes this overreach a bit. + return if $req->query_lc =~ /^0x/i; # hex maybe? return if ($query =~ $network); # Probably want to talk about addresses, not calculations. return if ($query =~ qr/(?:(?\d+)%(?(\+|\-|\*|\/))(?\d+)) | (?:(?\d+)(?(\+|\-|\*|\/))(?\d+)%)/); # Probably want to calculate a percent ( will be used PercentOf ) return if ($query =~ /^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$/); # Probably are searching for a phone number, not making a calculation - return if $query =~ /[":\@]/; return if $query =~ m{[x × ∙ ⋅ * % + \- ÷ / \^ \$ \. ,]{3,}}i; return if $query =~ /\$[^\d\.]/; return if $query =~ /\(\)/; $query =~ s/^(?:whatis|calculate|solve|math)//i; + + return if $query =~ /^(?:minus|-)\d+$/; + $query =~ s/factorial/fact/i; #replace factorial with fact # Grab expression. my $tmp_expr = spacing($query, 1); - - return if $tmp_expr eq $query; # If it didn't get spaced out, there are no operations to be done. + return if ($tmp_expr eq $query) && ($query !~ /\de/i); # If it didn't get spaced out, there are no operations to be done. # First replace named operations with their computable equivalents. while (my ($name, $operation) = each %named_operations) { @@ -107,7 +108,7 @@ handle query_nowhitespace => sub { } $tmp_expr =~ s#log[_]?(\d{1,3})#(1/log($1))*log#xg; # Arbitrary base logs. - $tmp_expr =~ s/ (\d+?)E(-?\d+)([^\d]|\b) /\($1 * 10**$2\)$3/ixg; # E == *10^n + $tmp_expr =~ s/([\d\.\-]+)E([\d\.\-]+)/\($1 * 10**$2\)/ig; # E == *10^n $tmp_expr =~ s/\$//g; # Remove $s. $tmp_expr =~ s/=$//; # Drop =. $tmp_expr =~ s/([0-9])\s*([a-zA-Z])([^0-9])/$1*$2$3/g; # Support 0.5e or 0.5pi; but don't break 1e8 @@ -117,7 +118,6 @@ handle query_nowhitespace => sub { $tmp_expr =~ s#\b$name\b# $constant #ig; $query =~ s#\b$name\b#($name)#ig; } - my @numbers = grep { $_ =~ /^$number_re$/ } (split /\s+/, $tmp_expr); my $style = number_style_for(@numbers); return unless $style; @@ -162,7 +162,7 @@ sub prepare_for_display { $query =~ s/\=$//; $query =~ s/(\d)[ _](\d)/$1$2/g; # Squeeze out spaces and underscores. # Show them how 'E' was interpreted. This should use the number styler, too. - $query =~ s/((?:\d+?|\s))E(-?\d+)/\($1 * 10^$2\)/i; + $query =~ s/([\d\.\-]+)E([\-\d\.]+)/\($1 * 10^$2\)/ig; $query =~ s/\s*\*\*\s*/^/g; # Use prettier exponentiation. $query =~ s/Math::BigInt->new\(([^)]+)\)/fact\($1\)/g; #replace Math::BigInt->new( with fact( $result = $style->for_display($result); diff --git a/t/Calculator.t b/t/Calculator.t index 3316575c721..771090d5770 100644 --- a/t/Calculator.t +++ b/t/Calculator.t @@ -850,6 +850,15 @@ ddg_goodie_test( result => re(qr/>-30 test_zci( + '(1 * 10 ^ 9) = 1,000,000,000', + heading => 'Calculator', + structured_answer => { + input => ['(1 * 10 ^ 9)'], + operation => 'Calculate', + result => re(qr/>1,000,000,000 undef, '83.166.167.160/27' => undef, '9 + 0 x 0xbf7' => undef, @@ -890,6 +899,10 @@ ddg_goodie_test( 'word+word' => undef, 'word + word' => undef, 'mxtoolbox' => undef, + 'fx-es' => undef, + '-2' => undef, + '-0' => undef, + 'm.box.com' => undef, ); done_testing;