Fine grained options for wgMathDisableTeXFilter

Add new option to filter only new input.
Now the complete list of possible settings is:
MW_MATH_CHECK_ALWAYS  backwards compatible to false
MW_MATH_CHECK_NEVER   backwards compatible to true
MW_MATH_CHECK_NEW     new option

Change-Id: I455b41c8b8d918f4c34f6c115194d227a8394e0a
This commit is contained in:
physikerwelt (Moritz Schubotz) 2014-09-05 21:59:13 -04:00 committed by Physikerwelt
parent c3894c2c49
commit ccc4114812
4 changed files with 144 additions and 38 deletions

View File

@ -92,7 +92,7 @@ class MathHooks {
* @return array * @return array
*/ */
static function mathTagHook( $content, $attributes, $parser ) { static function mathTagHook( $content, $attributes, $parser ) {
global $wgUseMathJax, $wgMathDisableTexFilter; global $wgUseMathJax;
if ( trim( $content ) === '' ) { // bug 8372 if ( trim( $content ) === '' ) { // bug 8372
return ''; return '';
@ -111,14 +111,13 @@ class MathHooks {
$renderer = MathRenderer::getRenderer( $content, $attributes, $mode ); $renderer = MathRenderer::getRenderer( $content, $attributes, $mode );
if ( !$wgMathDisableTexFilter ) { $checkResult = $renderer->checkTex();
$checkResult = $renderer->checkTex();
if ( $checkResult !== true ) { if ( $checkResult !== true ) {
// Returns the error message // Returns the error message
return $renderer->getLastError(); return $renderer->getLastError();
}
} }
if ( $renderer->render() ) { if ( $renderer->render() ) {
wfDebugLog( "Math" , "Rendering successful. Writing output" ); wfDebugLog( "Math" , "Rendering successful. Writing output" );
$renderedMath = $renderer->getHtmlOutput(); $renderedMath = $renderer->getHtmlOutput();

View File

@ -188,12 +188,29 @@ $wgMathDefaultLaTeXMLSetting = array(
* The link to the texvccheck executable * The link to the texvccheck executable
*/ */
$wgMathTexvcCheckExecutable = __DIR__ . '/texvccheck/texvccheck'; $wgMathTexvcCheckExecutable = __DIR__ . '/texvccheck/texvccheck';
/**
* Option to disable the tex filter. If set to true any LaTeX espression is parsed /**@{
* this can be a potential security risk. If set to false only a subset of the TeX * Math check constants
* commands is allowed. See the wikipedia page Help:Math for details.
*/ */
$wgMathDisableTexFilter = false; define( 'MW_MATH_CHECK_ALWAYS', 0 ); /// backwards compatible to false
define( 'MW_MATH_CHECK_NEVER' , 1 ); /// backwards compatible to true
define( 'MW_MATH_CHECK_NEW' , 2 );
/**@}*/
/**
* Option to disable the TeX security filter:
* In general every math object, which is rendered by the math extension has its rendering cached in
* a database.
* MW_MATH_CHECK_ALWAYS: If set to MW_MATH_CHECK_ALWAYS only a subset of the TeX commands is allowed.
* See the Wikipedia page Help:Math for details about the allowed commands.
* MW_MATH_CHECK_NONE: If set to MW_MATH_CHECK_NONE any TeX expression is parsed.
* This can be a potential security risk.
* MW_MATH_CHECK_NEW checks only new equations. If the database does not yet contain the given math object,
* then it is passed through texvccheck.
* Please make sure to truncate the database tables (math, mathoid, mathlatexml) when switching from
* MW_MATH_CHECK_NONE to MW_MATH_CHECK_NEW. Otherwise, unchecked content contained in the database
* will be displayed.
*/
$wgMathDisableTexFilter = MW_MATH_CHECK_NEW;
/** Stores debug information in the database and provides more detailed debug output */ /** Stores debug information in the database and provides more detailed debug output */
$wgMathDebug = false; $wgMathDebug = false;

View File

@ -262,7 +262,7 @@ abstract class MathRenderer {
wfProfileIn( __METHOD__ ); wfProfileIn( __METHOD__ );
/** @var DatabaseBase */ /** @var DatabaseBase */
$dbr = wfGetDB( DB_SLAVE ); $dbr = wfGetDB( DB_SLAVE );
/** @var ResultWrapper asdf */ /** @var ResultWrapper */
$rpage = $dbr->selectRow( $this->getMathTableName(), $rpage = $dbr->selectRow( $this->getMathTableName(),
$this->dbInArray(), $this->dbInArray(),
array( 'math_inputhash' => $this->getInputHash() ), array( 'math_inputhash' => $this->getInputHash() ),
@ -600,8 +600,21 @@ abstract class MathRenderer {
return $this->texSecure; return $this->texSecure;
} }
/**
* @global $wgMathDisableTexFilter
* @return bool
*/
public function checkTex() { public function checkTex() {
if ( !$this->texSecure ) { global $wgMathDisableTexFilter;
if ( $this->texSecure || (int) $wgMathDisableTexFilter == MW_MATH_CHECK_NEVER ) {
// equation was already checked or checking is disabled
return true;
} else {
if( (int) $wgMathDisableTexFilter == MW_MATH_CHECK_NEW ){
if( $this->readFromDatabase() ){
return true;
}
}
$checker = new MathInputCheckTexvc( $this->userInputTex ); $checker = new MathInputCheckTexvc( $this->userInputTex );
if ( $checker->isValid() ) { if ( $checker->isValid() ) {
$this->setTex( $checker->getValidTex() ); $this->setTex( $checker->getValidTex() );
@ -611,8 +624,6 @@ abstract class MathRenderer {
$this->lastError = $checker->getError(); $this->lastError = $checker->getError();
return false; return false;
} }
} else {
return true;
} }
} }

View File

@ -6,19 +6,18 @@
*/ */
class MathRendererTest extends MediaWikiTestCase { class MathRendererTest extends MediaWikiTestCase {
const SOME_TEX = "a+b"; const SOME_TEX = "a+b";
const TEXVCCHECK_INPUT = '\forall \epsilon \exist \delta';
const TEXVCCHECK_OUTPUT = '\forall \epsilon \exists \delta '; // be aware of the s at exists
/** /**
* Checks the tex and hash functions * Checks the tex and hash functions
* @covers MathRenderer::getTex() * @covers MathRenderer::getTex()
* @covers MathRenderer::__construct() * @covers MathRenderer::__construct()
*/ */
public function testBasics() { public function testBasics() {
$renderer = $this->getMockForAbstractClass( 'MathRenderer' $renderer = $this->getMockForAbstractClass( 'MathRenderer', array( self::SOME_TEX ) );
, array ( self::SOME_TEX ) );
// check if the TeX input was corretly passed to the class // check if the TeX input was corretly passed to the class
$this->assertEquals( self::SOME_TEX, $renderer->getTex() $this->assertEquals( self::SOME_TEX, $renderer->getTex(), "test getTex" );
, "test getTex" ); $this->assertEquals( $renderer->isChanged(), false, "test if changed is initially false" );
$this->assertEquals( $renderer->isChanged(), false
, "test if changed is initially false" );
} }
/** /**
@ -26,12 +25,14 @@ class MathRendererTest extends MediaWikiTestCase {
* @covers MathRenderer::writeCache() * @covers MathRenderer::writeCache()
*/ */
public function testWriteCacheSkip() { public function testWriteCacheSkip() {
$renderer = $this->getMockBuilder( 'MathRenderer' ) $renderer =
->setMethods( array( 'writeToDatabase' , 'render', 'getMathTableName', 'getHtmlOutput' ) ) $this->getMockBuilder( 'MathRenderer' )->setMethods( array(
->disableOriginalConstructor() 'writeToDatabase',
->getMock(); 'render',
$renderer->expects( $this->never() ) 'getMathTableName',
->method( 'writeToDatabase' ); 'getHtmlOutput'
) )->disableOriginalConstructor()->getMock();
$renderer->expects( $this->never() )->method( 'writeToDatabase' );
$renderer->writeCache(); $renderer->writeCache();
} }
@ -40,22 +41,100 @@ class MathRendererTest extends MediaWikiTestCase {
* @covers MathRenderer::writeCache() * @covers MathRenderer::writeCache()
*/ */
public function testWriteCache() { public function testWriteCache() {
$renderer = $this->getMockBuilder( 'MathRenderer' ) $renderer =
->setMethods( array( 'writeToDatabase' , 'render', 'getMathTableName', 'getHtmlOutput' ) ) $this->getMockBuilder( 'MathRenderer' )->setMethods( array(
->disableOriginalConstructor() 'writeToDatabase',
->getMock(); 'render',
$renderer->expects( $this->never() ) 'getMathTableName',
->method( 'writeToDatabase' ); 'getHtmlOutput'
) )->disableOriginalConstructor()->getMock();
$renderer->expects( $this->never() )->method( 'writeToDatabase' );
$renderer->writeCache(); $renderer->writeCache();
} }
public function testSetPurge() { public function testSetPurge() {
$renderer = $this->getMockBuilder( 'MathRenderer' ) $renderer =
->setMethods( array( 'render', 'getMathTableName', 'getHtmlOutput' ) ) $this->getMockBuilder( 'MathRenderer' )->setMethods( array(
->disableOriginalConstructor() 'render',
->getMock(); 'getMathTableName',
'getHtmlOutput'
) )->disableOriginalConstructor()->getMock();
$renderer->setPurge(); $renderer->setPurge();
$this->assertEquals( $renderer->isPurge(), true, "Test purge." ); $this->assertEquals( $renderer->isPurge(), true, "Test purge." );
} }
public function testCheckingAlways() {
$this->setMwGlobals( "wgMathDisableTexFilter", MW_MATH_CHECK_ALWAYS );
$renderer =
$this->getMockBuilder( 'MathRenderer' )->setMethods( array(
'render',
'getMathTableName',
'getHtmlOutput',
'readFromDatabase',
'setTex'
) )->setConstructorArgs( array( self::TEXVCCHECK_INPUT ) )->getMock();
$renderer->expects( $this->never() )->method( 'readFromDatabase' );
$renderer->expects( $this->once() )->method( 'setTex' )->with( self::TEXVCCHECK_OUTPUT );
$this->assertEquals( $renderer->checkTex(), true );
// now setTex sould not be called again
$this->assertEquals( $renderer->checkTex(), true );
}
public function testCheckingNever() {
$this->setMwGlobals( "wgMathDisableTexFilter", MW_MATH_CHECK_NEVER );
$renderer =
$this->getMockBuilder( 'MathRenderer' )->setMethods( array(
'render',
'getMathTableName',
'getHtmlOutput',
'readFromDatabase',
'setTex'
) )->setConstructorArgs( array( self::TEXVCCHECK_INPUT ) )->getMock();
$renderer->expects( $this->never() )->method( 'readFromDatabase' );
$renderer->expects( $this->never() )->method( 'setTex' );
$this->assertEquals( $renderer->checkTex(), true );
}
public function testCheckingNewUnknown() {
$this->setMwGlobals( "wgMathDisableTexFilter", MW_MATH_CHECK_NEW );
$renderer =
$this->getMockBuilder( 'MathRenderer' )->setMethods( array(
'render',
'getMathTableName',
'getHtmlOutput',
'readFromDatabase',
'setTex'
) )->setConstructorArgs( array( self::TEXVCCHECK_INPUT ) )->getMock();
$renderer->expects( $this->once() )->method( 'readFromDatabase' )
->will( $this->returnValue( false ) );
$renderer->expects( $this->once() )->method( 'setTex' )->with( self::TEXVCCHECK_OUTPUT );
$this->assertEquals( $renderer->checkTex(), true );
// now setTex sould not be called again
$this->assertEquals( $renderer->checkTex(), true );
}
public function testCheckingNewKnown() {
$this->setMwGlobals( "wgMathDisableTexFilter", MW_MATH_CHECK_NEW );
$renderer =
$this->getMockBuilder( 'MathRenderer' )->setMethods( array(
'render',
'getMathTableName',
'getHtmlOutput',
'readFromDatabase',
'setTex'
) )->setConstructorArgs( array( self::TEXVCCHECK_INPUT ) )->getMock();
$renderer->expects( $this->exactly( 2 ) )->method( 'readFromDatabase' )
->will( $this->returnValue( true ) );
$renderer->expects( $this->never() )->method( 'setTex' );
$this->assertEquals( $renderer->checkTex(), true );
// we don't mark a object as checked even though we rely on the database cache
// so readFromDatabase will be called again
$this->assertEquals( $renderer->checkTex(), true );
}
} }