diff --git a/tests/checks/test-VIPEscapingCheck.php b/tests/checks/test-VIPEscapingCheck.php new file mode 100644 index 0000000..8655198 --- /dev/null +++ b/tests/checks/test-VIPEscapingCheck.php @@ -0,0 +1,101 @@ + 'functions-file', + 'level' => BaseScanner::LEVEL_BLOCKER, + 'description' => sprintf( + esc_html__( 'Printing output of non-escaping localization functions (i.e. %1$s) is potentially dangerous, as they do not escape HTML. An escaping function (e.g. %2$s) should be used rather.', 'vip-scanner' ), + '__( ), _x( ), _n( ), _nx( )', + 'esc_html__( ), esc_attr__( ), esc_html_x( ), esc_attr_x( )' + ), + 'file' => 'VIPEscapingTest.inc', + 'lines' => $lines++, + ); + } + + $lines++; + + + /* + * Now test for non-printing usage of __( ), _x( ), + * _n( ), and _nx( ). + * + * Note: If you find yourself adding 'ifs' within the + * for-loop, stop using a loop and write out each + * expected error individually. + */ + + for ($i = 0; $i < 4; $i++) { + $expected_errors[] = array( + 'slug' => 'functions-file', + 'level' => BaseScanner::LEVEL_WARNING, + 'description' => sprintf( + esc_html__( 'Usage of non-escaping localization functions (i.e. %1$s) is discouraged as they do not escape HTML. An escaping function (e.g. %2$s) should be used rather.', 'vip-scanner' ), + '__( ), _x( ), _n( ), _nx( )', + 'esc_html__( ), esc_attr__( ), esc_html_x( ), esc_attr_x( )' + ), + 'file' => 'VIPEscapingTest.inc', + 'lines' => $lines++, + ); + } + + + /* + * Now test for usage of _e( ), _ex( ). + * + * Note: If you find yourself adding 'ifs' within the + * for-loop, stop using a loop and write out each + * expected error individually. + */ + + for ($i = 0; $i < 2; $i++) { + $expected_errors[] = array( + 'slug' => 'functions-file', + 'level' => BaseScanner::LEVEL_BLOCKER, + 'description' => sprintf( + esc_html__( 'Usage of non-escaping localization functions (i.e. %1$s) is discouraged as they do not escape HTML. An escaping function (e.g. %2$s) should be used rather.', 'vip-scanner' ), + '_e( ), _ex( )', + 'esc_html_e( ), esc_attr_e( ), esc_html_x( ), esc_attr_x( ), esc_attr__( )' + ), + 'file' => 'VIPEscapingTest.inc', + 'lines' => $lines++, + ); + } + + + $actual_errors = $this->checkFile( 'VIPEscapingTest.inc' ); + $this->assertEqualErrors( $expected_errors, $actual_errors ); + } +} diff --git a/tests/data/VIPEscapingTest.inc b/tests/data/VIPEscapingTest.inc new file mode 100644 index 0000000..c7ab068 --- /dev/null +++ b/tests/data/VIPEscapingTest.inc @@ -0,0 +1,30 @@ + '/([\s]|[;]){1,}(echo|vprintf|print)([\s]|[\(])+(__|_x|_n|_nx)[\s]*?\(/', + 'level' => 'blocker', + 'message' => sprintf( + esc_html__( 'Printing output of non-escaping localization functions (i.e. %1$s) is potentially dangerous, as they do not escape HTML. An escaping function (e.g. %2$s) should be used rather.', 'vip-scanner' ), + '__( ), _x( ), _n( ), _nx( )', + 'esc_html__( ), esc_attr__( ), esc_html_x( ), esc_attr_x( )' + ), + ), + array( + /* + * Catch non-printing usage of __( ), etc + * These are warnings, because the results + * are not being immediately printed, and so + * could be escaped at a later point. + */ + 'pattern' => '/([\s]|[;]|[=]){1,}[a-zA-Z]{0}[\s]+(__|_x|_n|_nx)[\s]*?\(/', + 'level' => 'warning', + 'message' => sprintf( + esc_html__( 'Usage of non-escaping localization functions (i.e. %1$s) is discouraged as they do not escape HTML. An escaping function (e.g. %2$s) should be used rather.', 'vip-scanner' ), + '__( ), _x( ), _n( ), _nx( )', + 'esc_html__( ), esc_attr__( ), esc_html_x( ), esc_attr_x( )' + ), + ), + array( + /* + * Catch calls to _e( ), _ex( ) + * These print directly, without HTML-escaping, + * and so are blockers. + */ + 'pattern' => '/([\s]|[;]){1,}[a-zA-Z]{0}[\s]+(_e|_ex)[\s]*?\(/', + 'level' => 'blocker', + 'message' => sprintf( + esc_html__( 'Usage of non-escaping localization functions (i.e. %1$s) is discouraged as they do not escape HTML. An escaping function (e.g. %2$s) should be used rather.', 'vip-scanner' ), + '_e( ), _ex( )', + 'esc_html_e( ), esc_attr_e( ), esc_html_x( ), esc_attr_x( ), esc_attr__( )' + ), + ), + ); + + $result = true; + foreach ( $checks as $check ) { + $this->increment_check_count(); + foreach ( $this->filter_files( $files, 'php' ) as $path => $code ) { + $filename = $this->get_filename( $path ); + $errors = $this->preg_file2( $check['pattern'], $code ); + foreach ( (array) $errors as $line_number => $error ) { + $this->add_error( + 'functions-file', + $check['message'], + $check['level'], + $filename, + array( $line_number => $error ) + ); + $result = false; + } + } + } + return $result; + } +} diff --git a/vip-scanner/config-vip-scanner.php b/vip-scanner/config-vip-scanner.php index e9f688b..1aeb9ed 100644 --- a/vip-scanner/config-vip-scanner.php +++ b/vip-scanner/config-vip-scanner.php @@ -59,6 +59,7 @@ 'DeprecatedFunctionsCheck', 'DeprecatedParametersCheck', 'jQueryCheck', + 'VIPEscapingCheck', 'VIPWhitelistCheck', 'VIPRestrictedClassesCheck', 'VIPRestrictedPatternsCheck',