diff --git a/filter/tex/lib.php b/filter/tex/lib.php index 875c84c380b..9a0fe3c9c58 100644 --- a/filter/tex/lib.php +++ b/filter/tex/lib.php @@ -86,7 +86,35 @@ function filter_tex_sanitize_formula(string $texexp): string { '\noexpand', '\line', '\mathcode', '\item', '\section', '\mbox', '\declarerobustcommand', ]; - return str_ireplace($denylist, 'forbiddenkeyword', $texexp); + $allowlist = ['inputenc']; + + // Prepare the denylist for regular expression. + $denylist = array_map(function($value){ + return '/' . preg_quote($value, '/') . '/i'; + }, $denylist); + + // Prepare the allowlist for regular expression. + $allowlist = array_map(function($value){ + return '/\bforbiddenkeyword_(' . preg_quote($value, '/') . ')\b/i'; + }, $allowlist); + + // First, mangle all denied words. + $texexp = preg_replace_callback($denylist, + function($matches) { + return 'forbiddenkeyword_' . $matches[0]; + }, + $texexp + ); + + // Then, change back the allowed words. + $texexp = preg_replace_callback($allowlist, + function($matches) { + return $matches[1]; + }, + $texexp + ); + + return $texexp; } function filter_tex_get_cmd($pathname, $texexp) { diff --git a/filter/tex/tests/lib_test.php b/filter/tex/tests/lib_test.php new file mode 100644 index 00000000000..cc19e2a2929 --- /dev/null +++ b/filter/tex/tests/lib_test.php @@ -0,0 +1,65 @@ +. + +/** + * Tex filter library functions tests + * + * @package filter_tex + * @category test + * @copyright 2021 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +declare(strict_types=1); + +namespace filter_tex; + +use advanced_testcase; + +global $CFG; +require_once($CFG->dirroot . '/filter/tex/lib.php'); + +/** + * Tex filter library functions tests + * + * @copyright 2021 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class lib_test extends advanced_testcase { + /** + * Data provider for test_filter_tex_sanitize_formula. + * + * @return array + */ + public function filter_tex_sanitize_formula_provider() : array { + return [ + ['x\ =\ \frac{\sqrt{144}}{2}\ \times\ (y\ +\ 12)', 'x\ =\ \frac{\sqrt{144}}{2}\ \times\ (y\ +\ 12)'], + ['\usepackage[latin1]{inputenc}', '\usepackage[latin1]{inputenc}'], + ['\newcommand{\A}{\verbatiminput}', '\newforbiddenkeyword_command{\A}{\verbatimforbiddenkeyword_input}'], + ]; + } + + /** + * Tests for filter_tex_sanitize_formula() function. + * + * @dataProvider filter_tex_sanitize_formula_provider + * @param $formula The formula to test + * @param $expected The sanitized version of the formula we expect to get + */ + public function test_filter_tex_sanitize_formula(string $formula, string $expected) { + $this->assertEquals($expected, filter_tex_sanitize_formula($formula)); + } +}