From: <Cra...@nt...> - 2004-12-21 16:25:02
|
Author: CrawfordCurrie Date: 2004-12-21 08:20:14 -0800 (Tue, 21 Dec 2004) New Revision: 3408 Modified: twiki/branches/DEVELOP/data/TestCases/TestCaseAmISane.txt twiki/branches/DEVELOP/data/TestCases/TestCaseAutoFormatting.txt twiki/branches/DEVELOP/data/TestCases/TestCaseAutoIncludes.txt twiki/branches/DEVELOP/data/TestCases/TestCaseAutoTagFromTags.txt twiki/branches/DEVELOP/lib/TWiki.pm twiki/branches/DEVELOP/lib/TWiki/Render.pm twiki/branches/DEVELOP/lib/TWiki/Sandbox.pm twiki/branches/DEVELOP/lib/TWiki/Search.pm twiki/branches/DEVELOP/lib/TWiki/Store.pm twiki/branches/DEVELOP/lib/TWiki/Store/RcsWrap.pm twiki/branches/DEVELOP/lib/TWiki/UI.pm twiki/branches/DEVELOP/lib/TWiki/UI/Manage.pm twiki/branches/DEVELOP/lib/TWiki/UI/Register.pm twiki/branches/DEVELOP/lib/TWiki/User.pm Log: TWikiSecurity: Merged RichardDonkins emailed patch (why didn't you check it in, Richard?) and fixed some tests that were wrong as highlighted by Sven's recent checkins which I guess he didn't run the tests on mutter mutter..... Modified: twiki/branches/DEVELOP/data/TestCases/TestCaseAmISane.txt =================================================================== --- twiki/branches/DEVELOP/data/TestCases/TestCaseAmISane.txt 2004-12-21 11:26:22 UTC (rev 3407) +++ twiki/branches/DEVELOP/data/TestCases/TestCaseAmISane.txt 2004-12-21 16:20:14 UTC (rev 3408) @@ -1,4 +1,4 @@ -%META:TOPICINFO{author="guest" date="1102321544" format="1.0" version="1.9"}% +%META:TOPICINFO{author="guest" date="1102353378" format="1.0" version="1.10"}% Description: Manual trivial fast sanity checks for script functions. | *Script* | *Description* | *Test* | @@ -8,10 +8,10 @@ | =oops= | Tested by quietsave, below | | | =preview= | Should redirect to preview | <a href="%SCRIPTURLPATH%/preview%SCRIPTSUFFIX%/TestCases/WasteOfSpace?text=Cabbages%20And%20Kings&topicparent=TestCaseQuickScriptsChecks">click here</a> | | =rdiff= | Compare WebHome 1.1 and 1.2 | <a href="%SCRIPTURLPATH%/rdiff%SCRIPTSUFFIX%/TestCases/WebHome?rev1=1&rev2=2">click here</a> | -| =rename= | | | | =save= | =action= = =save= Should redirect to view | <a href="%SCRIPTURLPATH%/save%SCRIPTSUFFIX%/TestCases/WasteOfSpace?action=save&text=Save%20PASSED&topicparent=TestCaseQuickScriptsChecks">click here</a> | | =save= | =action= = =checkpoint= (should come back to edit) | <a href="%SCRIPTURLPATH%/save%SCRIPTSUFFIX%/TestCases/WasteOfSpace?action=checkpoint&text=Checkpoint%2-save%20PASSED&topicparent=TestCaseQuickScriptsChecks">click here</a> | | =save= | =action= = =quietsave= (should redirect to view) | <a href="%SCRIPTURLPATH%/save%SCRIPTSUFFIX%/TestCases/WasteOfSpace?action=quietsave&text=Quietsave%20test%20PASSED&topicparent=TestCaseQuickScriptsChecks">click here </a> | +| =rename= | Rename topic WasteOfSpace. Rename it within this web, and take care to clear the checkboxes so this topic doesn't get munged. | <a href="%SCRIPTURLPATH%/rename/TestCases/WasteOfSpace">click here</a> | | =search= | Search for the word "sanity" |<a href="%SCRIPTURLPATH%/search%SCRIPTSUFFIX%/TestCases/WasteOfSpace?search=sanity">click here</a> | | =statistics= | Should redirect to refreshed statistics |<a href="%SCRIPTURLPATH%/statistics%SCRIPTSUFFIX%/TestCases">click here</a> | | =attach=, =upload= | Attach a file to topic WasteOfSpace | <a href="%SCRIPTURLPATH%/attach%SCRIPTSUFFIX%/%WEB%/WasteOfSpace">click here</a> | @@ -25,3 +25,4 @@ %META:FILEATTACHMENT{name="volcano.jpg" attachment="volcano.jpg" attr="" comment="" date="1102080112" path="volcano.jpg" size="2637" tmpFilename="/usr/tmp/CGItemp3319" user="guest" version="1"}% + Modified: twiki/branches/DEVELOP/data/TestCases/TestCaseAutoFormatting.txt =================================================================== --- twiki/branches/DEVELOP/data/TestCases/TestCaseAutoFormatting.txt 2004-12-21 11:26:22 UTC (rev 3407) +++ twiki/branches/DEVELOP/data/TestCases/TestCaseAutoFormatting.txt 2004-12-21 16:20:14 UTC (rev 3408) @@ -1,339 +1,340 @@ -Description: Simple formatting, as described in TWiki.TextFormattingRules - -<table cols=3 border=2> -<tr><th>Feature</th><th>Expected</th><th>Actual</th></tr> -<tr><td> Paragraphs</td><td> -<!-- expected --> -1st paragraph -<p /> -2nd paragraph -<!-- /expected --> -</td><td> -<!-- actual --> -1st paragraph - -2nd paragraph -<!-- /actual --> -</td></tr> -<tr><td> Headings</td><td> -<!-- expected --> -<h2><a name="Sushi"></a>Sushi</h2> -<h3><a name="Maguro"></a>Maguro</h3> -<!-- /expected --> -</td><td> -<!-- actual --> ----++ Sushi ----+++ Maguro -<!-- /actual --> -</td></tr> -<tr><td> Bold Text</td><td> -<!-- expected --> -<strong>Bold</strong> -<!-- /expected --> -</td><td> -<!-- actual --> -*Bold* -<!-- /actual --> -</td></tr> -<tr><td> Italic Text</td><td> -<!-- expected --> -<em>Italic</em> -<!-- /expected --> -</td><td> -<!-- actual --> -_Italic_ -<!-- /actual --> -</td></tr> -<tr><td> Bold Italic</td><td> -<!-- expected --> -<strong><em>Bold italic</em></strong> -<!-- /expected --> -</td><td> -<!-- actual --> -__Bold italic__ -<!-- /actual --> -</td></tr> -<tr><td> Fixed Font</td><td> -<!-- expected --> -<code>Fixed font</code> -<!-- /expected --> -</td><td> -<!-- actual --> -=Fixed font= -<!-- /actual --> -</td></tr> -<tr><td> Bold Fixed Font</td><td> -<!-- expected --> -<code><b>Bold fixed</b></code> -<!-- /expected --> -</td><td> -<!-- actual --> -==Bold fixed== -<!-- /actual --> -</td></tr> -<tr><td> Verbatim Mode</td><td> -<!-- expected --> -%_verbatim0% -<!-- /expected --> -Note: at the point the test handler is called, verbatim has not been put back into the text, so we can't test this properly. -</td><td> -<!-- actual --> -<verbatim> -class CatAnimal { - void purr() { - code here - } -} -</verbatim> -<!-- /actual --> -</td></tr> -<tr><td> Separator</td><td> -<!-- expected --> -<hr> -<hr> --- -<!-- /expected --> -</td><td> -<!-- actual --> ---- -------- --- -<!-- /actual --> -</td></tr> -<tr><td> List Item</td><td> -<!-- expected --> -<ul> -<li>bullet item -</li> -</ul> -<!-- /expected --> -</td><td> -<!-- actual --> - * bullet item -<!-- /actual --> -</td></tr> -<tr><td> Nested List Item</td><td> -<!-- expected --> -<ul> -<li>level 1 -<ul> -<li>level 2 -</li> -</ul> -</li> -</ul> -<!-- /expected --> -</td><td> -<!-- actual --> - * level 1 - * level 2 -<!-- /actual --> -</td></tr> -<tr><td> Ordered List</td><td> -<!-- expected --> -<ol><li> Sushi</li></ol><p /> -<ol><li type="A"> Sushi</li></ol><p /> -<ol><li type="i"> Sushi</li></ol><p /> -<ol><li> Sushi</li> -<li type="A"> Sushi</li> -<li type="i"> Sushi</li></ol> -<!-- /expected --> -</td><td> -<!-- actual --> - 1. Sushi - - A. Sushi - - i. Sushi - - 1. Sushi - A. Sushi - i. Sushi -<!-- /actual --> -</td></tr> -<tr><td> Definition List</td><td> -<!-- expected --> -<dl> -<dt> Sushi </dt><dd> Japan -</dd> -<dt> Dim Sum </dt><dd> S.F. -</dd> - -</dl> -<!-- /expected --> -</td><td> -<!-- actual --> - $ Sushi: Japan - $ Dim Sum: S.F. -<!-- /actual --> -</td></tr> -<tr><td> Table</td><td> -<!-- expected --> -<p /> -<table border="1" cellspacing="0" cellpadding="1"> <tr><th bgcolor="#99CCCC"> <strong>L</strong> </th><th bgcolor="#99CCCC"> <strong>C</strong> </th><th bgcolor="#99CCCC"> <strong>R</strong> </th></tr> -<tr><td> A2 </td><td align="center"> 2 </td><td align="right"> 2 </td></tr> - -<tr><td> A3 </td><td align="center"> 3 </td><td align="right"> 3 </td></tr> -<tr><td colspan="3"> multi span </td></tr> -<tr><td> A4-6 </td><td> four </td><td> four </td></tr> - -<tr><td> ^ </td><td> five </td><td> five </td></tr> -</table> -<p /> -<table border="1" cellspacing="0" cellpadding="1"> <tr><td> ^ </td><td> six </td><td> six </td></tr> - -</table> -<p /> -<!-- /expected --> -</td><td> -<!-- actual --> - -| *L* | *C* | *R* | -| A2 | 2 | 2 | -| A3 | 3 | 3 | -| multi span ||| -| A4-6 | four | four | -|^| five | five | - -|^| six | six | - -<!-- /actual --> -</td></tr> -<tr><td> Prevent a Link</td><td> -<!-- expected --> -<nop>SunOS -<!-- /expected --> -</td><td> -<!-- actual --> -!SunOS -<!-- /actual --> -</td></tr> -<tr><td> Disable Links</td><td> -<!-- expected --> - <noautolink> - RedHat & SuSE - </noautolink> -<!-- /expected --> -Note: noautolink tags will still be there, because they are not removed until immediately before topic display. -</td><td> -<!-- actual --> - <noautolink> - RedHat & SuSE - </noautolink> -<!-- /actual --> -</td></tr> -<tr><td> Mailto: Links</td><td> -<!-- expected --> -<a href="mailto:a@z.com">Mail</a> - -<p /> -<a href="mailto:?subject=Hi">Hi</a> -<!-- /expected --> -</td><td> -<!-- actual --> -[[mailto:a@z.com Mail]] - -[[mailto:?subject=Hi Hi]] -<!-- /actual --> -</td></tr> -<tr><td> Wiki Word Links</td><td> -<!-- expected expand --> -<a class="twikiLink" href="%SCRIPTURLPATH%/view%SCRIPTSUFFIX%/TestCases/WebPreferences">WebPreferences</a> -<p /> -<a class="twikiLink" href="%SCRIPTURLPATH%/view%SCRIPTSUFFIX%/%MAINWEB%/TWikiUsers">TWikiUsers</a> -<p /> -<span class="twikiNewLink" style='background : #FFFFCE;'><font color="#0000FF">CompleteAndUtterNothing</font><a href="%SCRIPTURLPATH%/edit%SCRIPTSUFFIX%/TestCases/CompleteAndUtterNothing?topicparent=TestCases.TestCaseAutoFormatting"><sup>?</sup></a></span> -<!-- /expected --> -</td><td> -<!-- actual --> -WebPreferences - -%MAINWEB%.TWikiUsers - -CompleteAndUtterNothing -<!-- /actual --> -</td></tr> -<tr><td> Square Brackets</td><td> -<!-- expected expand --> -<span class="twikiNewLink" style='background : #FFFFCE;'><font color="#0000FF">wiki syntax</font><a href="%SCRIPTURLPATH%/edit%SCRIPTSUFFIX%/TestCases/WikiSyntax?topicparent=TestCases.TestCaseAutoFormatting"><sup>?</sup></a></span> -<p /> -<a class="twikiLink" href="%SCRIPTURLPATH%/view%SCRIPTSUFFIX%/%MAINWEB%/TWikiUsers">Main.TWiki users</a> -<p /> -escaped: -[<nop>[wiki syntax]] -<!-- /expected --> -</td><td> -<!-- actual --> -[[wiki syntax]] - -[[%MAINWEB%.TWiki users]] - -escaped: -![[wiki syntax]] -<!-- /actual --> -</td></tr> -<tr><td> Specific Links</td><td> -<!-- expected expand --> -<span class="twikiNewLink" style='background : #FFFFCE;'><font color="#0000FF">syntax</font><a href="%SCRIPTURLPATH%/edit%SCRIPTSUFFIX%/TestCases/WikiSyntax?topicparent=TestCases.TestCaseAutoFormatting"><sup>?</sup></a></span> -<p /> -<a href="http://gnu.org" target="_top">GNU</a> -<p /> -<a href="http://xml.org" target="_top">XML</a> -<!-- /expected --> -</td><td> -<!-- actual --> -[[WikiSyntax][syntax]] - -[[http://gnu.org][GNU]] - -[[http://xml.org XML]] -<!-- /actual --> -</td></tr> -<tr><td> Anchors</td><td> -<!-- expected expand --> -<a class="twikiAnchorLink" href="%SCRIPTURLPATH%/view/TestCases/TestCaseAutoFormatting#NotThere">TestCaseAutoFormatting#NotThere</a> -<p /> -<a class="twikiAnchorLink" href="%SCRIPTURLPATH%/view/TestCases/TestCaseAutoFormatting#MyAnchor">Jump</a> -<p /> -<a name="MyAnchor"></a> To here -<!-- /expected --> -</td><td> -<!-- actual --> -[[TestCaseAutoFormatting#NotThere]] - -[[#MyAnchor][Jump]] - -#MyAnchor To here -<!-- /actual --> -</td></tr> -</table> -<!-- expected --> -<p /> -<table border="1" cellspacing="0" cellpadding="1"> <tr><th bgcolor="#99CCCC"> <strong>L</strong> </th><th bgcolor="#99CCCC"> <strong>C</strong> </th><th bgcolor="#99CCCC"> <strong>R</strong> </th></tr> - -<tr><td> A2 </td><td align="center"> 2 </td><td align="right"> 2 </td></tr> -<tr><td> A3 </td><td align="center"> 3 </td><td align="right"> 3 </td></tr> -<tr><td colspan="3"> multi span </td></tr> - -<tr><td> A4-6 </td><td> four </td><td> four </td></tr> -<tr><td> ^ </td><td> five </td><td> five </td></tr> -</table> -<p /> -<table border="1" cellspacing="0" cellpadding="1"> <tr><td> ^ </td><td> six </td><td> six </td></tr> - -</table> -<p /> -<!-- /expected --> -</td><td> -<!-- actual --> - -| *L* | *C* | *R* | -| A2 | 2 | 2 | -| A3 | 3 | 3 | -| multi span ||| -| A4-6 | four | four | -|^| five | five | - -|^| six | six | - -<!-- /actual --> +%META:TOPICINFO{author="guest" date="1102566706" format="1.0" version="1.4"}% +Description: Simple formatting, as described in TWiki.TextFormattingRules + +<table cols=3 border=2> +<tr><th>Feature</th><th>Expected</th><th>Actual</th></tr> +<tr><td> Paragraphs</td><td> +<!-- expected --> +1st paragraph +<p /> +2nd paragraph +<!-- /expected --> +</td><td> +<!-- actual --> +1st paragraph + +2nd paragraph +<!-- /actual --> +</td></tr> +<tr><td> Headings</td><td> +<!-- expected --> +<h2><a name="Sushi"></a>Sushi</h2> +<h3><a name="Maguro"></a>Maguro</h3> +<!-- /expected --> +</td><td> +<!-- actual --> +---++ Sushi +---+++ Maguro +<!-- /actual --> +</td></tr> +<tr><td> Bold Text</td><td> +<!-- expected --> +<strong>Bold</strong> +<!-- /expected --> +</td><td> +<!-- actual --> +*Bold* +<!-- /actual --> +</td></tr> +<tr><td> Italic Text</td><td> +<!-- expected --> +<em>Italic</em> +<!-- /expected --> +</td><td> +<!-- actual --> +_Italic_ +<!-- /actual --> +</td></tr> +<tr><td> Bold Italic</td><td> +<!-- expected --> +<strong><em>Bold italic</em></strong> +<!-- /expected --> +</td><td> +<!-- actual --> +__Bold italic__ +<!-- /actual --> +</td></tr> +<tr><td> Fixed Font</td><td> +<!-- expected --> +<code>Fixed font</code> +<!-- /expected --> +</td><td> +<!-- actual --> +=Fixed font= +<!-- /actual --> +</td></tr> +<tr><td> Bold Fixed Font</td><td> +<!-- expected --> +<code><b>Bold fixed</b></code> +<!-- /expected --> +</td><td> +<!-- actual --> +==Bold fixed== +<!-- /actual --> +</td></tr> +<tr><td> Verbatim Mode</td><td> +<!-- expected --> +%_verbatim0% +<!-- /expected --> +Note: at the point the test handler is called, verbatim has not been put back into the text, so we can't test this properly. +</td><td> +<!-- actual --> +<verbatim> +class CatAnimal { + void purr() { + code here + } +} +</verbatim> +<!-- /actual --> +</td></tr> +<tr><td> Separator</td><td> +<!-- expected --> +<hr> +<hr> +-- +<!-- /expected --> +</td><td> +<!-- actual --> +--- +------- +-- +<!-- /actual --> +</td></tr> +<tr><td> List Item</td><td> +<!-- expected --> +<ul> +<li>bullet item +</li> +</ul> +<!-- /expected --> +</td><td> +<!-- actual --> + * bullet item +<!-- /actual --> +</td></tr> +<tr><td> Nested List Item</td><td> +<!-- expected --> +<ul> +<li>level 1 +<ul> +<li>level 2 +</li> +</ul> +</li> +</ul> +<!-- /expected --> +</td><td> +<!-- actual --> + * level 1 + * level 2 +<!-- /actual --> +</td></tr> +<tr><td> Ordered List</td><td> +<!-- expected --> +<ol><li> Sushi</li></ol><p /> +<ol><li type="A"> Sushi</li></ol><p /> +<ol><li type="i"> Sushi</li></ol><p /> +<ol><li> Sushi</li> +<li type="A"> Sushi</li> +<li type="i"> Sushi</li></ol> +<!-- /expected --> +</td><td> +<!-- actual --> + 1. Sushi + + A. Sushi + + i. Sushi + + 1. Sushi + A. Sushi + i. Sushi +<!-- /actual --> +</td></tr> +<tr><td> Definition List</td><td> +<!-- expected --> +<dl> +<dt> Sushi </dt><dd> Japan +</dd> +<dt> Dim Sum </dt><dd> S.F. +</dd> + +</dl> +<!-- /expected --> +</td><td> +<!-- actual --> + $ Sushi: Japan + $ Dim Sum: S.F. +<!-- /actual --> +</td></tr> +<tr><td> Table</td><td> +<!-- expected --> +<p /> +<table border="1" cellspacing="0" cellpadding="1"> <tr><th bgcolor="#99CCCC"> <strong>L</strong> </th><th bgcolor="#99CCCC"> <strong>C</strong> </th><th bgcolor="#99CCCC"> <strong>R</strong> </th></tr> +<tr><td> A2 </td><td align="center"> 2 </td><td align="right"> 2 </td></tr> + +<tr><td> A3 </td><td align="center"> 3 </td><td align="right"> 3 </td></tr> +<tr><td colspan="3"> multi span </td></tr> +<tr><td> A4-6 </td><td> four </td><td> four </td></tr> + +<tr><td> ^ </td><td> five </td><td> five </td></tr> +</table> +<p /> +<table border="1" cellspacing="0" cellpadding="1"> <tr><td> ^ </td><td> six </td><td> six </td></tr> + +</table> +<p /> +<!-- /expected --> +</td><td> +<!-- actual --> + +| *L* | *C* | *R* | +| A2 | 2 | 2 | +| A3 | 3 | 3 | +| multi span ||| +| A4-6 | four | four | +|^| five | five | + +|^| six | six | + +<!-- /actual --> +</td></tr> +<tr><td> Prevent a Link</td><td> +<!-- expected --> +<nop>SunOS +<!-- /expected --> +</td><td> +<!-- actual --> +!SunOS +<!-- /actual --> +</td></tr> +<tr><td> Disable Links</td><td> +<!-- expected --> + <noautolink> + RedHat & SuSE + </noautolink> +<!-- /expected --> +Note: noautolink tags will still be there, because they are not removed until immediately before topic display. +</td><td> +<!-- actual --> + <noautolink> + RedHat & SuSE + </noautolink> +<!-- /actual --> +</td></tr> +<tr><td> Mailto: Links</td><td> +<!-- expected --> +<a href="mailto:a@z.com">Mail</a> + +<p /> +<a href="mailto:?subject=Hi">Hi</a> +<!-- /expected --> +</td><td> +<!-- actual --> +[[mailto:a@z.com Mail]] + +[[mailto:?subject=Hi Hi]] +<!-- /actual --> +</td></tr> +<tr><td> Wiki Word Links</td><td> +<!-- expected expand --> +<a class="twikiLink" href="%SCRIPTURL%/view%SCRIPTSUFFIX%/TestCases/WebPreferences">WebPreferences</a> +<p /> +<a class="twikiLink" href="%SCRIPTURL%/view%SCRIPTSUFFIX%/%MAINWEB%/TWikiUsers">TWikiUsers</a> +<p /> +<span class="twikiNewLink" style='background : #FFFFCE;'><font color="#0000FF">CompleteAndUtterNothing</font><a href="%SCRIPTURL%/edit%SCRIPTSUFFIX%/TestCases/CompleteAndUtterNothing?topicparent=TestCases.TestCaseAutoFormatting"><sup>?</sup></a></span> +<!-- /expected --> +</td><td> +<!-- actual --> +WebPreferences + +%MAINWEB%.TWikiUsers + +CompleteAndUtterNothing +<!-- /actual --> +</td></tr> +<tr><td> Square Brackets</td><td> +<!-- expected expand --> +<span class="twikiNewLink" style='background : #FFFFCE;'><font color="#0000FF">wiki syntax</font><a href="%SCRIPTURL%/edit%SCRIPTSUFFIX%/TestCases/WikiSyntax?topicparent=TestCases.TestCaseAutoFormatting"><sup>?</sup></a></span> +<p /> +<a class="twikiLink" href="%SCRIPTURL%/view%SCRIPTSUFFIX%/%MAINWEB%/TWikiUsers">Main.TWiki users</a> +<p /> +escaped: +[<nop>[wiki syntax]] +<!-- /expected --> +</td><td> +<!-- actual --> +[[wiki syntax]] + +[[%MAINWEB%.TWiki users]] + +escaped: +![[wiki syntax]] +<!-- /actual --> +</td></tr> +<tr><td> Specific Links</td><td> +<!-- expected expand --> +<span class="twikiNewLink" style='background : #FFFFCE;'><font color="#0000FF">syntax</font><a href="%SCRIPTURL%/edit%SCRIPTSUFFIX%/TestCases/WikiSyntax?topicparent=TestCases.TestCaseAutoFormatting"><sup>?</sup></a></span> +<p /> +<a href="http://gnu.org" target="_top">GNU</a> +<p /> +<a href="http://xml.org" target="_top">XML</a> +<!-- /expected --> +</td><td> +<!-- actual --> +[[WikiSyntax][syntax]] + +[[http://gnu.org][GNU]] + +[[http://xml.org XML]] +<!-- /actual --> +</td></tr> +<tr><td> Anchors</td><td> +<!-- expected expand --> +<a class="twikiAnchorLink" href="%SCRIPTURL%/view/TestCases/TestCaseAutoFormatting#NotThere">TestCaseAutoFormatting#NotThere</a> +<p /> +<a class="twikiAnchorLink" href="%SCRIPTURL%/view/TestCases/TestCaseAutoFormatting#MyAnchor">Jump</a> +<p /> +<a name="MyAnchor"></a> To here +<!-- /expected --> +</td><td> +<!-- actual --> +[[TestCaseAutoFormatting#NotThere]] + +[[#MyAnchor][Jump]] + +#MyAnchor To here +<!-- /actual --> +</td></tr> +</table> +<!-- expected --> +<p /> +<table border="1" cellspacing="0" cellpadding="1"> <tr><th bgcolor="#99CCCC"> <strong>L</strong> </th><th bgcolor="#99CCCC"> <strong>C</strong> </th><th bgcolor="#99CCCC"> <strong>R</strong> </th></tr> + +<tr><td> A2 </td><td align="center"> 2 </td><td align="right"> 2 </td></tr> +<tr><td> A3 </td><td align="center"> 3 </td><td align="right"> 3 </td></tr> +<tr><td colspan="3"> multi span </td></tr> + +<tr><td> A4-6 </td><td> four </td><td> four </td></tr> +<tr><td> ^ </td><td> five </td><td> five </td></tr> +</table> +<p /> +<table border="1" cellspacing="0" cellpadding="1"> <tr><td> ^ </td><td> six </td><td> six </td></tr> + +</table> +<p /> +<!-- /expected --> +</td><td> +<!-- actual --> + +| *L* | *C* | *R* | +| A2 | 2 | 2 | +| A3 | 3 | 3 | +| multi span ||| +| A4-6 | four | four | +|^| five | five | + +|^| six | six | + +<!-- /actual --> Modified: twiki/branches/DEVELOP/data/TestCases/TestCaseAutoIncludes.txt =================================================================== --- twiki/branches/DEVELOP/data/TestCases/TestCaseAutoIncludes.txt 2004-12-21 11:26:22 UTC (rev 3407) +++ twiki/branches/DEVELOP/data/TestCases/TestCaseAutoIncludes.txt 2004-12-21 16:20:14 UTC (rev 3408) @@ -31,7 +31,7 @@ <!-- /actual --> ---+ Expected <!-- expected expand --> -<font color="#ff0000"> <strong><em>Note:</em></strong> </font> Included topic <span class="twikiNewLink" style='background : #FFFFCE;'><font color="#0000FF">FileNotFound</font><a href="%SCRIPTURLPATH%/edit%SCRIPTSUFFIX%/TestCases/FileNotFound?topicparent=TestCases.TestCaseAutoIncludes"><sup>?</sup></a></span> does not exist yet +<font color="#ff0000"> <strong><em>Note:</em></strong> </font> Included topic <span class="twikiNewLink" style='background : #FFFFCE;'><font color="#0000FF">FileNotFound</font><a href="%SCRIPTURL%/edit%SCRIPTSUFFIX%/TestCases/FileNotFound?topicparent=TestCases.TestCaseAutoIncludes"><sup>?</sup></a></span> does not exist yet <!-- /expected --> ---+ Actual <!-- actual --> Modified: twiki/branches/DEVELOP/data/TestCases/TestCaseAutoTagFromTags.txt =================================================================== --- twiki/branches/DEVELOP/data/TestCases/TestCaseAutoTagFromTags.txt 2004-12-21 11:26:22 UTC (rev 3407) +++ twiki/branches/DEVELOP/data/TestCases/TestCaseAutoTagFromTags.txt 2004-12-21 16:20:14 UTC (rev 3408) @@ -48,6 +48,7 @@ Expected: <!-- expected expand --> %EGGSAMPLE% +<p /> <!-- /expected --> saw: <!-- actual --> Modified: twiki/branches/DEVELOP/lib/TWiki/Render.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Render.pm 2004-12-21 11:26:22 UTC (rev 3407) +++ twiki/branches/DEVELOP/lib/TWiki/Render.pm 2004-12-21 16:20:14 UTC (rev 3408) @@ -262,36 +262,35 @@ $theIndent =~ s/ /\t/g; my $depth = length( $theIndent ); - my $top = scalar( @{$this->{LISTTYPES}} ); - if( $top < $depth ) { + my $size = scalar( @{$this->{LIST}} ); + if( $size < $depth ) { my $firstTime = 1; - while( $top < $depth ) { - push( @{$this->{LISTTYPES}}, $theType ); - push( @{$this->{LISTELEMENTS}}, $theElement ); + while( $size < $depth ) { + push( @{$this->{LIST}}, { type=>$theType, element=>$theElement } ); push( @$result, "<$theElement>\n" ) unless( $firstTime ); push( @$result, "<$theType>\n" ); $firstTime = 0; - $top++; + $size++; } - } elsif( $top > $depth ) { - while( $top > $depth ) { - push( @$result, "</".pop( @{$this->{LISTELEMENTS}} ).">\n" ); - push( @$result, "</".pop( @{$this->{LISTTYPES}} ).">\n" ); - $top--; + } else { + while( $size > $depth ) { + my $tags = pop( @{$this->{LIST}} ); + push( @$result, "</$tags->{element}>\n" ); + push( @$result, "</$tags->{type}>\n" ); + $size--; } - $top = @{$this->{LISTELEMENTS}}; - push( @$result, "</".$this->{LISTELEMENTS}->[$top].">\n") if( $top ); - } elsif( scalar( @{$this->{LISTELEMENTS}} )) { - $top = $#{$this->{LISTELEMENTS}}; - push ( @$result, "</".$this->{LISTELEMENTS}->[$top].">\n" ); + if ($size) { + push( @$result, "</$this->{LIST}->[$size-1]->{element}>\n" ); + } } - $top = $#{$this->{LISTTYPES}}; - my $oldt = $this->{LISTTYPES}->[$top] || ""; - if( $top && $oldt ne $theType ) { - push( @$result, "</$oldt>\n<$theType>\n" ); - $this->{LISTTYPES}->[$top] = $theType; - $this->{LISTELEMENTS}->[$#{$this->{LISTELEMENTS}}] = $theElement; + if ( $size ) { + my $oldt = $this->{LIST}->[$size-1]; + if( $oldt->{type} ne $theType ) { + push( @$result, "</$oldt->{type}>\n<$theType>\n" ); + pop( @{$this->{LIST}} ); + push( @{$this->{LIST}}, { type=>$theType, element=>$theElement } ); + } } } @@ -779,8 +778,7 @@ $insideTABLE = 0; $insideNoAutoLink = 0; - @{$this->{LISTTYPES}} = (); - @{$this->{LISTELEMENTS}} = (); + @{$this->{LIST}} = (); # Initial cleanup $text =~ s/\r//g; @@ -833,7 +831,7 @@ # inside <PRE> # close list tags if any - if( @{$this->{LISTTYPES}} ) { + if( @{$this->{LIST}} ) { $this->_addListItem( \@result, "", "", "" ); $isList = 0; } Modified: twiki/branches/DEVELOP/lib/TWiki/Sandbox.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Sandbox.pm 2004-12-21 11:26:22 UTC (rev 3407) +++ twiki/branches/DEVELOP/lib/TWiki/Sandbox.pm 2004-12-21 16:20:14 UTC (rev 3408) @@ -24,36 +24,82 @@ use strict; -=pod +# TODO: Sandbox module should probably use custom 'die' handler so that output goes +# only to web server error log - otherwise it might give useful debugging +# information to someone developing an exploit. ----++ new( $OS ) -Construct a new sandbox suitable for $OS +# TODO: Get rid of $cmdQuote in TWiki.cfg and TWiki.pm +# DEBUG - use confess instead of die for stack trace +# use CGI::Carp qw(confess fatalsToBrowser); + +sub _writeDebug { + my $this = shift; +# $this->{session}->writeDebug($_[0]); +# print STDERR $_[0],"\n"; +} + +=pod +---++ new( $OS, $detailedOS ) + +Construct a new sandbox suitable for $OS, setting +flags for platform features that help. $detailedOS distinguishes +Perl variants on platforms such as Windows. + =cut sub new { - my ( $class, $session, $OS ) = @_; + my ( $class, $session, $OS, $detailedOS ) = @_; my $this = bless( {}, $class ); $this->{session} = $session; - $this->{USE_SAFE_PIPES} = 0; - if ( $OS ne "WINDOWS" ) { - eval 'require 5.008'; - return if $@; - eval 'use POSIX'; - return if $@; - $this->{USE_SAFE_PIPES} = 1; + $this->{REAL_SAFE_PIPE_OPEN} = 0; # supports "open FH, '-|" + $this->{EMULATED_SAFE_PIPE_OPEN} = 0; # emulate open from pipe + + if ( $OS eq "UNIX" or + ($OS eq "WINDOWS" and $detailedOS eq "cygwin" ) ) { + # Real safe pipes on Unix/Linux/Cygwin, for Perl 5.005+ + $this->{REAL_SAFE_PIPE_OPEN} = 1; + + } elsif ( $OS eq "WINDOWS" ) { + # Emulated safe pipes on ActivePerl 5.8 or higher + my $isActivePerl = eval 'Win32::BuildNumber !~ /Win32/'; + if ( $isActivePerl and $] >= 5.008 ) { + $this->{EMULATED_SAFE_PIPE_OPEN} = 1 unless $@; + } + # FIXME - not yet working, disable! + $this->{EMULATED_SAFE_PIPE_OPEN} = 0; } - # Set to 1 to trace all command executrions to STDERR + + $this->_writeDebug("use safe pipes setting = $this->{REAL_SAFE_PIPE_OPEN}"); + $this->_writeDebug("emulated safe pipes setting = $this->{EMULATED_SAFE_PIPE_OPEN}"); + + # 'Safe' means no need to filter in on this platform - check + # sandbox status at time of filtering + $this->{SAFE} = ($this->{REAL_SAFE_PIPE_OPEN} || + $this->{EMULATED_SAFE_PIPE_OPEN}); + + ##$this->_writeDebug("safe setting = $this->{SAFE}"); + + # Shell quoting - shell used only on non-safe platforms + if ($OS eq "UNIX" or ($OS eq "WINDOWS" and $detailedOS eq "cygwin" ) ) { + $this->{CMDQUOTE} = '\''; + } else { + $this->{CMDQUOTE} = '\"'; + } + + # Set to 1 to trace all command executions to STDERR $this->{TRACE} = 0; + #$this->{TRACE} = 1; # DEBUG return $this; }; + =pod ----++ untaintUnchecked ( $string ) ->: $untainted +---++ untaintUnchecked ( $string ) -> $untainted Untaints $string without any checks (dangerous). If $string is undefined, return undef. @@ -96,14 +142,14 @@ if ($dotdot && @result > 0) { pop @result; } else { - die 'directory traversal attempt'; + die "directory traversal attempt in filename '$string'"; } } elsif ($component =~ /^(\S+)$/) { # We need to untaint the string explicitly. # FIXME: This might be a Perl bug. push @result, untaintUnchecked $1; } else { - die 'whitespace in file name component'; + die "whitespace in file name component '$component' of filename '$string'"; } } if (@result) { @@ -115,13 +161,14 @@ return join '/', @result; } else { return '/' if $absolute; - die 'empty file name'; + die "empty filename '$string'"; } } =pod ---++ buildCommandLine ( $template, %params ) -> @arguments + $template is split at whitespace, and '%VAR%' strings contained in it are replaced with $params{VAR}. %params may consist of scalars and array references as values. Array references are dereferenced and the @@ -174,21 +221,21 @@ push @targs, normalizeFileName $param; } elsif ($flag =~ /N/) { # Generalized number. - if ($param =~ /^([0-9A-Fa-f.x+\-]{0,30})$/) { + if ( $param =~ /^([0-9A-Fa-f.x+\-]{0,30})$/ ) { push @targs, $1; } else { die "invalid number argument '$param'"; } } elsif ($flag =~ /S/) { # Harmless string. - if ($param =~ /^([0-9A-Za-z.+_\-]{0,30})$/) { + if ( $param =~ /^([0-9A-Za-z.+_\-]{0,30})$/ ) { push @targs, $1; } else { die "invalid string argument"; } } elsif ($flag =~ /D/) { # RCS date. - if ($param =~ m!^(\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d)$!) { + if ( $param =~ m|^(\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d)$| ) { push @targs, $1; } else { die "invalid date argument"; @@ -234,31 +281,146 @@ =cut +# TODO: get emulated pipes or even backticks working on ActivePerl... +# TODO: make most of this routine common with readFromProcess? + sub readFromProcessArray { my ($this, $path, $template, %params) = @_; + my @data; # Output lines + my $processFileHandle; # Holds filehandle to read from process + + # Build argument list from template my @args = $this->buildCommandLine( $template, %params ); - my @data; - if ( $this->{USE_SAFE_PIPES} ) { - my $process; - open $process, '-|', $path, @args - or die "open failed: $!"; - # remove newline characters. - @data = map { chomp $_; $_ } <$process>; - close $process; + + $this->_writeDebug("path = $path"); + $this->_writeDebug("args = @args"); + + if ( $this->{REAL_SAFE_PIPE_OPEN} ) { + $this->_writeDebug("Got to safe pipes section"); + # Real safe pipes, open from process directly - works + # for most Unix/Linux Perl platforms and on Cygwin. Based on + # perlipc(1). + my $pid = open ($processFileHandle, '-|'); + die "open of pipe failed: $!" unless defined $pid; + + $this->_writeDebug("processFileHandle = $processFileHandle"); + + if ( $pid ) { + # Parent - read data from process filehandle and remove newlines + $this->_writeDebug("pid = $pid"); + @data = map { chomp $_; $_ } <$processFileHandle>; + $this->_writeDebug("data = @data"); + close $processFileHandle; + } else { + # Child - run the command, stdout to pipe + exec $path, @args + or die "exec of $path with args @args failed: $!"; + die "cannot happen"; + exit 127; + } + + } elsif ( $this->{EMULATED_SAFE_PIPE_OPEN} ) { + $this->_writeDebug("Got to emulated pipes section"); + + # FIXME: not working yet for ActivePerl on Windows + # Safe pipe emulation mostly on Windows platforms + my $pid; + ($pid, $processFileHandle) = $this->_openSafePipeFromProcess(); + if ( $pid ) { + # Parent - read data from process filehandle and remove newlines + $this->_writeDebug("pid = $pid"); + # Exec definitely does work, can cause error if wrong pathname + $this->_writeDebug("fileno of processFileHandle= " . fileno($processFileHandle) ); + # FIXME: Doesn't read (or perhaps write in child) any data here... File handle + # issue of some sort... + @data = map { chomp $_; $_ } <$processFileHandle>; + $this->_writeDebug("data = @data "); + close $processFileHandle; + } else { + # Child - run the command, stdout to pipe + exec $path, @args + or die "exec of $path with args @args failed: $!"; + die "should never happen"; + exit 127; + } + } else { - my $cmd = "$path $TWiki::cmdQuote"; - $cmd .= join( "$TWiki::cmdQuote $TWiki::cmdQuote", @args ) . - $TWiki::cmdQuote; + # FIXME: not working yet for ActivePerl on Windows + # No safe pipes available, use the shell as last resort (with + # earlier filtering in unless administrator forced to use filtering out) + my $cmdQuote = $this->{CMDQUOTE}; + + my $cmd = "$path $cmdQuote"; + $cmd .= join( "$cmdQuote $cmdQuote", @args ) . $cmdQuote; + # DEBUG + $cmd .= ' >c:\temp\searchout.log'; @data = split( /\r?\n/, `$cmd` ); } + if( $this->{TRACE} ) { - print STDERR "$path ",join( " ", @args ), " -> ", + my $q = $this->{CMDQUOTE}; + print STDERR "$path $q",join( "$q $q", @args ), "$q -> ", join( "\n", @data ),"\n"; - } + } return @data; } + +# _openSafePipeFromProcess ( $parentFileHandle ) -> $pid +# +# Simulate open(FOO, "-|") for read from piped process on platforms such as +# Windows - see perlfork(1). +# +# NOTE: This routine does a fork and returns in both the parent and child +# processes - check for $pid == 0 to see if you are in the child process. +sub _openSafePipeFromProcess { + my $this = shift; + + # Create pipe + my $parentFileHandle; + my $childFileHandle; + pipe ($parentFileHandle, $childFileHandle) or + die "could not create pipe: $!"; + $this->_writeDebug("filehandles = $parentFileHandle $childFileHandle "); + + my $pid = fork(); + if (not defined $pid) { + die "fork() failed: $!"; + } + + if ($pid) { + $this->_writeDebug("Parent, pid = $pid"); + # Parent + close $childFileHandle or die; + $this->_writeDebug("fileno of parent handle is " . fileno($parentFileHandle)); + return ($pid, $parentFileHandle); + } else { + # Child + $this->_writeDebug("Child, pid = $pid"); + close $parentFileHandle or die; + # FIXME: standard output to pipe disappears - hard to work out + # what's happening + $this->_writeDebug("fileno of stdout handle is " . fileno(STDOUT)); + $this->_writeDebug("fileno of stderr handle is " . fileno(STDERR)); + $this->_writeDebug("fileno of child handle is " . fileno($childFileHandle)); + # Tried this from readFromProcess routine - doesn't work either ... + # use POSIX; + # POSIX::close 2; + # POSIX::dup 1; + + close STDOUT; + open(STDOUT, ">&=" . fileno($childFileHandle)) or die; + $this->_writeDebug("fileno of stdout handle is now " . fileno(STDOUT)); + close STDERR; + open(STDERR, ">&=" . fileno($childFileHandle)) or die; + $this->_writeDebug("fileno of stderr handle is now " . fileno(STDERR)); + #die "test 3\n"; # Never works after dupe of stdout... + return ($pid, $parentFileHandle); + } +} + + =pod ---++ readFromProcess( $template, @params ) -> ($output, $status) @@ -270,14 +432,16 @@ =cut +# FIXME: need to upgrade as per the Array variant sub readFromProcess { my ($this, $template, %params) = @_; my @args = $this->buildCommandLine( $template, %params ); my $data; my $exit; - if ( $this->{USE_SAFE_PIPES} ) { - # The code follows the safe pipe construct found in perlipc(1). + if ( $this->{REAL_SAFE_PIPE_OPEN} ) { + # The code follows the safe pipe construct found in perlipc(1) + # since Perl 5.005 my $pipe; my $pid = open $pipe, '-|'; if ($pid) { # parent @@ -287,6 +451,7 @@ $exit = ( $? >> 8 ); } else { # Redirect standard error to standard output. + # FIXME: do a require since only needed with safe pipe platform use POSIX; POSIX::close 2; POSIX::dup 1; @@ -295,9 +460,12 @@ exit 127; } } else { + # FIXME: Should be able to do similarly safe pipe open in 5.6 or + # earlier, see perlipc(1) + my $cmdQuote = $this->{CMDQUOTE}; + my $cmd = shift( @args ) . " $TWiki::cmdQuote"; - $cmd .= join( "$TWiki::cmdQuote $TWiki::cmdQuote", @args ) . - $TWiki::cmdQuote; + $cmd .= join( "$cmdQuote $cmdQuote", @args ) . $cmdQuote; $cmd .= " 2>&1" if( $TWiki::OS eq "UNIX" ); $data = `$cmd`; $exit = ( $? >> 8 ); Modified: twiki/branches/DEVELOP/lib/TWiki/Search.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Search.pm 2004-12-21 11:26:22 UTC (rev 3407) +++ twiki/branches/DEVELOP/lib/TWiki/Search.pm 2004-12-21 16:20:14 UTC (rev 3408) @@ -54,8 +54,9 @@ =pod ---++ sub new () -Constructor for the signleton Search engine object. +Constructor for the singleton Search engine object. + =cut sub new { @@ -79,45 +80,145 @@ sub templates { my $this = shift; return $this->{session}->{templates}; } sub renderer { my $this = shift; return $this->{session}->{renderer}; } +sub writeDebug { my $this = shift; $this->{session}->writeDebug($_[0]); } + # =========================== -# Normally writes no output, uncomment writeDebug line to get output of all RCS etc command to debug file + =pod ---++ sub _traceExec ( $cmd, $result ) -Not yet documented. +Normally writes no output, uncomment writeDebug line to get output of all external commands and chdirs to debug file =cut sub _traceExec { - my( $cmd, $result ) = @_; + my( $this, $cmd, $result ) = @_; - #$this->{session}->writeDebug( "Search exec: $cmd -> $result" ); + $this->writeDebug( "Search exec: $cmd -> $result" ); } -# =========================== =pod ----++ sub _translateSpace ( $theText ) -Not yet documented. +---++ sub _filterSearchString ( $this, $searchString, $theType ) -> $searchString +Untaints the search value (text string, regex or search expression) by +'filtering in' valid characters only. + =cut -sub _translateSpace +sub _filterSearchString { + my $this = shift; + my $searchString = shift; + my $theType = shift; + + # Use filtering-out of regexes only if (1) on a safe sandbox platform + # OR (2) administrator has explicitly configured $forceUnsafeRegexes == 1. + # + # Only well-secured intranet sites, authenticated for all access + # (view, edit, attach, search, etc), AND forced to use unsafe + # platforms, should use the $forceUnsafeRegexes flag. + my $unsafePlatform = ( not ($this->sandbox()->{SAFE} ) ); + + # FIXME: Use of new global + my $useFilterIn = ($unsafePlatform and not $TWiki::forceUnsafeRegexes); + + $this->writeDebug("unsafePlatform = $unsafePlatform"); + $this->writeDebug("useFilterIn = $useFilterIn"); + + # Non-alphabetic language sites (e.g. Japanese and Chinese) cannot use + # filtering-in and must use safe pipes, since TWiki does not currently + # support Unicode, required for filtering-in. Alphabetic languages such + # as English, French, Russian, Greek and most European languages are + # handled by filtering-in. + if ( not $TWiki::langAlphabetic and $unsafePlatform ) { + # Best option is to upgrade Perl. + die "You are using a non-alphabetic language on a non-safe-pipes platform. This is a serious SECURITY RISK,\nso TWiki cannot be used as it is currently installed - please\nread TWiki:Codev/SafePipes for options to avoid or remove this risk."; + } + + my $mixedAlphaNum = $TWiki::regex{mixedAlphaNum}; + + my $validChars; # String of valid characters or POSIX + # regex elements (e.g. [:alpha:] from + # _setupRegexes) - designed to + # be used within a character class. + + if( $theType eq "regex" ) { + # Regular expression search - example: soap;wsdl;web service;!shampoo;[Ff]red + if ( $useFilterIn ) { + # Filter in + $validChars = "${mixedAlphaNum} " . + '!;' . # TWiki search syntax + '.[]\\*\\+'; # Limited regex syntax + } else { + # Filter out - only for use on safe pipe platform or + # if forced by admin + # FIXME: Review and test since first versions were broken + # SMELL: CC commented out next two lines as they escape escape chars in REs + #$searchString =~ s/(^|[^\\])(['"`\\])/$1\\$2/g; # Escape all types of quotes and backslashes + #$searchString =~ s/([\@\$])\(/$1\\\(/g; # Escape @( ... ) and $( ... ) + } + + } elsif( $theType eq "literal" ) { + # Filter in + # Literal search - search for exactly what was typed in (old style TWiki non-regex search) + $validChars = "${mixedAlphaNum} " . '\.'; # Alphanumeric, spaces, selected punctuation + + } else { + # FIXME: spaces not working - url encoded in search pattern + # Filter in + # Keyword search (new style, Google-like). Example: soap +wsdl +"web service" -shampoo + $validChars = "${mixedAlphaNum} +\"\-"; # Alphanumeric, spaces and search syntax + } + + if ( $useFilterIn ) { + # Clean up - delete all invalid characters + # FIXME: be sure to escape special characters in literal + $searchString =~ s/[^${validChars}]+//go; + } + + # Untaint - same for filtering in and out since already sanitised + $searchString =~ /^(.*)$/; + $searchString = $1; + + # Limit string length + $searchString = substr($searchString, 0, 1500); +} + +=pod + +---++ sub getTextPattern ( $theText, $thePattern ) + +Sanitise search pattern - currently used for FormattedSearch only + +=cut + +sub getTextPattern { - my( $theText ) = @_; - $theText =~ s/\s+/$TWiki::TranslationToken/go; + my( $theText, $thePattern ) = @_; + + $thePattern =~ s/([^\\])([\$\@\%\&\#\'\`\/])/$1\\$2/go; # escape some special chars + $thePattern =~ /(.*)/; # untaint + $thePattern = $1; + my $OK = 0; + eval { + $OK = ( $theText =~ s/$thePattern/$1/is ); + }; + $theText = "" unless( $OK ); + return $theText; } -# =========================== + =pod ---++ sub _tokensFromSearchString ( $this, $theSearchVal, $theType ) -Not yet documented. +Split the search string into tokens depending on type of search. +Search is an 'AND' of all tokens - various syntaxes implemented +by this routine. =cut @@ -127,24 +228,28 @@ my @tokens = (); if( $theType eq "regex" ) { - # regular expression search Example: soap;wsdl;web service;!shampoo + # Regular expression search Example: soap;wsdl;web service;!shampoo @tokens = split( /;/, $theSearchVal ); } elsif( $theType eq "literal" ) { - # literal search + # Literal search (old style) $tokens[0] = $theSearchVal; } else { - # keyword search. Example: soap +wsdl +"web service" -shampoo - $theSearchVal =~ s/(\".*?)\"/&_translateSpace($1)/geo; # hide spaces in "literal text" + # Keyword search (Google-style) - implemented by converting + # to regex format. Example: soap +wsdl +"web service" -shampoo + + # Prevent tokenizing on spaces in "literal string" + $theSearchVal =~ s/(\".*?)\"/&_translateSpace($1)/geo; $theSearchVal =~ s/[\+\-]\s+//go; - # build pattern of stop words + # Build pattern of stop words my $stopWords = $this->prefs()->getPreferencesValue( "SEARCHSTOPWORDS" ) || ""; $stopWords =~ s/[\s\,]+/\|/go; $stopWords =~ s/[\(\)]//go; - # read from bottom to up: + # Tokenize string taking account of literal strings, then remove + # stop words and convert '+' and '-' syntax. @tokens = map { s/^\+//o; s/^\-/\!/o; s/^\"//o; $_ } # remove +, change - to !, remove " grep { ! /^($stopWords)$/i } # remove stopwords @@ -155,13 +260,34 @@ return @tokens; } -# ========================= =pod +---++ sub _translateSpace ( $theText ) + +Convert spaces into translation token characters (typically NULs), +preventing tokenization. + +FIXME: Terminology confusing here! + +=cut + +sub _translateSpace +{ + my( $theText ) = @_; + $theText =~ s/\s+/$TWiki::TranslationToken/go; + return $theText; +} + + +=pod + ---++ sub _searchTopicsInWeb ( $theWeb, $theTopic, $theScope, $theType, $caseSensitive, @theTokens ) -Not yet documented. +Search a single web based on parameters - @theTokens is a list of search terms +to be ANDed together, $theTopic is list of one or more topics. +Executes external command to do the search. + =cut sub _searchTopicsInWeb @@ -193,7 +319,8 @@ my $sDir = "$TWiki::dataDir/$theWeb"; $theScope = "text" unless( $theScope =~ /^(topic|all)$/ ); # default scope is "text" - foreach my $token ( @theTokens ) { # search each token + # AND search - search once for each token, ANDing result together + foreach my $token ( @theTokens ) { # search on each token my $invertSearch = ( $token =~ s/^\!//o ); # flag for AND NOT search my @scopeTextList = (); my @scopeTopicList = (); @@ -217,10 +344,13 @@ # I18N: 'grep' must use locales if needed, # for case-insensitive searching. See TWiki::setupLocale. my $program = ""; + # FIXME: For Cygwin grep, do something about -E and -F switches + # - best to strip off any switches after first space in + # $egrepCmd etc and apply those as argument 1. if( $theType eq "regex" ) { $program = $TWiki::egrepCmd; } else { - $ program= $TWiki::fgrepCmd; + $program = $TWiki::fgrepCmd; } my $template = ''; $template .= ' -i' unless( $caseSensitive ); @@ -228,11 +358,11 @@ if( $sDir ) { chdir( "$sDir" ); - _traceExec( "chdir to $sDir", "" ); + $this->_traceExec( "chdir to $sDir", "" ); $sDir = ""; # chdir only once } - # process topics in sets, fix for Codev.ArgumentListIsTooLongForSearch + # process topics in sets, fix for Codev.ArgumentListIsTooLongForSearch my $maxTopicsInSet = 512; # max number of topics for a grep call my @take = @topicList; my @set = splice( @take, 0, $maxTopicsInSet ); @@ -275,7 +405,6 @@ return @topicList; } -# ========================= =pod ---++ sub _makeTopicPattern ( $theTopic ) @@ -296,7 +425,6 @@ return '^(' . join( "|", @arr ) . ')$'; } -# ========================= =pod ---++ sub revDate2ISO () @@ -311,12 +439,11 @@ return &TWiki::formatTime( $epochSec, "\$iso", "gmtime"); } -# ========================= =pod ---++ sub searchWeb (...) -Search according to the parameters. +Search one or more webs according to the parameters. If =_callback= is set, that means the caller wants results as soon as they are ready. =_callback_ should be set to a reference @@ -366,8 +493,9 @@ my $theSeparator = $params{"separator"} || ""; my $newLine = $params{"newline"} || ""; - ##$this->{session}->writeDebug "Search locale is $TWiki::siteLocale"; + ##$this->writeDebug "Search locale is $TWiki::siteLocale"; + # Limit search results if ($theLimit =~ /(^\d+$)/o) { # only digits, all else is the same as $theLimit = $1; # an empty string. "+10" won't work. } else { @@ -379,9 +507,10 @@ $theType = "regex" if( $theRegex ); - # I18N fix + # Filter the search string for security and untaint it + $theSearchVal = $this->_filterSearchString( $theSearchVal, $theType ); + my $mixedAlpha = $TWiki::regex{mixedAlpha}; - if( $theSeparator ) { $theSeparator =~ s/\$n\(\)/\n/gos; # expand "$n()" to new line $theSeparator =~ s/\$n([^$mixedAlpha]|$)/\n$1/gos; @@ -401,29 +530,34 @@ my $searchAllFlag = ( $theWebName =~ /(^|[\,\s])(all|on)([\,\s]|$)/i ); # Search what webs? "" current web, list gets the list, all gets - # all (unless marked in WebPrefs as NOSEARCHALL) + # all (unless marked in WebPrefs as NOSEARCHALL) - build up list of + # webs to be searched in @webList. if( $theWebName ) { foreach my $web ( split( /[\,\s]+/, $theWebName ) ) { # the web processing loop filters for valid web names, so don't do it here. if( $web =~ /^(all|on)$/i ) { - # get list of all webs by scanning $dataDir + # Get list of all webs - first scan $dataDir opendir DIR, $TWiki::dataDir; my @tmpList = readdir(DIR); closedir(DIR); + + # Now get list of pathnames to web directories @tmpList = sort grep { s#^.+/([^/]+)$#$1# } grep { -d } map { "$TWiki::dataDir/$_" } grep { ! /^[._]/ } @tmpList; - # what that does (looking from the bottom up) is take the file - # list, filter out the dot directories and dot files, turn the - # list into full paths instead of just file names, filter out - # any non-directories, strip the path back off, and sort - # whatever was left after all that (which should be merely a - # list of directory's names.) + # what the above does (looking from the bottom up) is + # take the file list, filter out the dot directories and + # dot files, turn the list into full paths instead of + # just file names, filter out any non-directories, strip + # the path back off, and sort whatever was left after + # all that (which should be merely a list of directory's + # names.) + # Build list of webs, without duplicates foreach my $aweb ( @tmpList ) { push( @webList, $aweb ) unless( grep { /^$aweb$/ } @webList ); } @@ -445,17 +579,13 @@ my $tmpl = ""; my $topicCount = 0; # JohnTalintyre - # See Codev.SecurityAlertExecuteCommandsWithSearch - $theSearchVal =~ s/(^|[^\\])([\'\`])/\\$2/g; # Escape ' and ` - $theSearchVal =~ s/[\@\$]\(/$1\\\(/g; # Defuse @( ... ) and $( ... ) - $theSearchVal = substr($theSearchVal, 0, 1500); # Limit string length - my $originalSearch = $theSearchVal; my $renameTopic; my $renameWeb = ""; my $spacedTopic; - $theTemplate = "searchformat" if( $theFormat ); + $theTemplate = "searchformat" if( $theFormat ); # FormattedSearch + # Handle normal, book view and rename cases if( $theTemplate ) { $tmpl = $this->templates()->readTemplate( "$theTemplate" ); # FIXME replace following with this @@@ @@ -477,9 +607,9 @@ # I18N: match non-alpha before and after topic name in renameview searches # This regex must work under grep, i.e. if using Perl 5.6 or higher # the POSIX character classes will be used in grep as well. - my $alphaNum = $TWiki::regex{mixedAlphaNum}; - $theSearchVal = "(^|[^${alphaNum}_])$theSearchVal" . - "([^${alphaNum}_]" . '|$)|' . + my $mixedAlphaNum = $TWiki::regex{mixedAlphaNum}; + $theSearchVal = "(^|[^${mixedAlphaNum}_])$theSearchVal" . + "([^${mixedAlphaNum}_]" . '|$)|' . '(\[\[' . $spacedTopic . '\]\])'; } else { $tmpl = $this->templates()->readTemplate( "search" ); @@ -487,9 +617,11 @@ $tmpl =~ s/\%META{.*?}\%//go; # remove %META{"parent"}% + # Split template into 5 sections my( $tmplHead, $tmplSearch, $tmplTable, $tmplNumber, $tmplTail ) = split( /%SPLIT%/, $tmpl ); + # Invalid template? if( ! $tmplTail ) { my $mess = "<html><body>" . "<h1>TWiki Installation Error</h1>" . @@ -504,11 +636,12 @@ } } + # Expand tags in template sections $tmplSearch = $this->{session}->handleCommonTags( $tmplSearch, $topic ); $tmplNumber = $this->{session}->handleCommonTags( $tmplNumber, $topic ); + # If not inline search, also expand tags in head and tail sections unless( $inline ) { - # head and tail only required if _not_ inline $tmplHead = $this->{session}->handleCommonTags( $tmplHead, $topic ); if( $callback) { @@ -522,8 +655,8 @@ } } + # Generate "Search:" part showing actual search string used unless( $noSearch ) { - # generate "Search:" part my $searchStr = $theSearchVal; $searchStr = "" if( $theSearchVal eq $emptySearch ); $searchStr =~ s/&/&/go; @@ -541,19 +674,21 @@ } } + # Split the search string into tokens depending on type of search - + # each token is ANDed together by actual search my @tokens = $this->_tokensFromSearchString( $theSearchVal, $theType ); - # write log entry + # Write log entry # FIXME: Move log entry further down to log actual webs searched if( ( $TWiki::doLogTopicSearch ) && ( ! $inline ) ) { $tempVal = join( ' ', @webList ); $this->{session}->writeLog( "search", $tempVal, $theSearchVal ); } - # loop through webs + # Loop through webs foreach my $thisWebName ( @webList ) { $thisWebName =~ s/$TWiki::securityFilter//go; - $thisWebName =~ /(.*)/; + $thisWebName =~ /(.*)/; # FIXME: untaint using webname regex $thisWebName = $1; # untaint variable next unless $this->store()->webExists( $thisWebName ); # can't process what ain't thar @@ -568,7 +703,7 @@ && ( ( $thisWebNoSearchAll =~ /on/i ) || ( $thisWebName =~ /^[\.\_]/ ) ) && ( $thisWebName ne $this->{session}->{webName} ) ); - # search topics in this web + # Run the search on topics in this web my @topicList = $this->_searchTopicsInWeb( $thisWebName, $theTopic, $theScope, $theType, $caseSensitive, @tokens ); # exclude topics, Codev.ExcludeWebTopicsFromSearch @@ -758,13 +893,13 @@ } else { # simple sort, suggested by RaymondLutz in Codev.SchwartzianTransformMisused - ##$this->{session}->writeDebug "Topic list before sort = @topicList"; + ##$this->writeDebug "Topic list before sort = @topicList"; if( $revSort ) { @topicList = sort {$b cmp $a} @topicList; } else { @topicList = sort {$a cmp $b} @topicList; } - ##$this->{session}->writeDebug "Topic list after sort = @topicList"; + ##$this->writeDebug "Topic list after sort = @topicList"; } # header and footer of $thisWebName @@ -966,8 +1101,8 @@ if( ! ( $insidePRE || $insideVERBATIM || $noAutoLink ) ) { # Case insensitive option is required to get [[spaced Word]] to match # I18N: match non-alpha before and after topic name in renameview searches - my $alphaNum = $TWiki::regex{mixedAlphaNum}; - my $match = "(^|[^${alphaNum}_.])($originalSearch)(?=[^${alphaNum}]|\$)"; + my $mixedAlphaNum = $TWiki::regex{mixedAlphaNum}; + my $match = "(^|[^${mixedAlphaNum}_.])($originalSearch)(?=[^${mixedAlphaNum}]|\$)"; # NOTE: Must *not* use /o here, since $match is based on # search string that will vary during lifetime of # compiled code with mod_perl. @@ -1007,6 +1142,7 @@ $tempVal =~ s/\$parent/getMetaParent( $meta )/geos; $tempVal =~ s/\$formfield\(\s*([^\)]*)\s*\)/getMetaFormField( $meta, $1 )/geos; $tempVal =~ s/\$formname/_getMetaFormName( $meta )/geos; + # FIXME: Allow all regex characters but escape them $tempVal =~ s/\$pattern\((.*?\s*\.\*)\)/getTextPattern( $text, $1 )/geos; $tempVal =~ s/\r?\n/$newLine/gos if( $newLine ); if( $theSeparator ) { @@ -1137,7 +1273,6 @@ return $searchResult; } -#========================= =pod ---++ sub _getRev1Info( $theWeb, $theTopic, $theAttr ) @@ -1248,34 +1383,8 @@ return ""; } -#========================= =pod ----++ sub getTextPattern ( $theText, $thePattern ) - -Not yet documented. - -=cut - -sub getTextPattern -{ - my( $theText, $thePattern ) = @_; - - $thePattern =~ s/([^\\])([\$\@\%\&\#\'\`\/])/$1\\$2/go; # escape some special chars - $thePattern =~ /(.*)/; # untaint - $thePattern = $1; - my $OK = 0; - eval { - $OK = ( $theText =~ s/$thePattern/$1/is ); - }; - $theText = "" unless( $OK ); - - return $theText; -} - -#========================= -=pod - ---++ sub wikiName ( $theWikiUserName ) Not yet documented. @@ -1290,7 +1399,6 @@ return $theWikiUserName; } -#========================= =pod ---++ sub breakName ( $theText, $theParams ) @@ -1322,6 +1430,8 @@ return $theText; } + + #========================= 1; Modified: twiki/branches/DEVELOP/lib/TWiki/Store/RcsWrap.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Store/RcsWrap.pm 2004-12-21 11:26:22 UTC (rev 3407) +++ twiki/branches/DEVELOP/lib/TWiki/Store/RcsWrap.pm 2004-12-21 16:20:14 UTC (rev 3408) @@ -258,7 +258,7 @@ ---++ sub numRevisions ( $self ) Find out how many revisions there are. If there is a problem, such -as a nonexistant file, returns the null string. +as a nonexistent file, returns the null string. =cut Modified: twiki/branches/DEVELOP/lib/TWiki/Store.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Store.pm 2004-12-21 11:26:22 UTC (rev 3407) +++ twiki/branches/DEVELOP/lib/TWiki/Store.pm 2004-12-21 16:20:14 UTC (rev 3408) @@ -223,7 +223,7 @@ $theAttachment, $user ) = @_; die "ASSERT $this from ".join(",",caller)."\n" unless $this =~ /TWiki::Store/; - my $wName = TWiki::userToWikiName( $user ); + my $wName = $this->users()->userToWikiName( $user ); # Remove file attachment from old topic my $topicHandler = $this->_getTopicHandler( $oldWeb, $oldTopic, $theAttachment ); my $error = $topicHandler->moveMe( $newWeb, $newTopic ); @@ -444,7 +444,7 @@ my $preTopic = '^|\W'; # Start of line or non-alphanumeric my $postTopic = '$|\W'; # End of line or non-alphanumeric my $spacedTopic = TWiki::searchableTopic( $oldTopic ); - my $wikiUserName = TWiki::userToWikiName( $user ); + my $wikiUserName = $this->users()->userToWikiName( $user ); while ( @refs ) { my $type = shift @refs; @@ -1159,7 +1159,7 @@ } close( IN_FILE ); - my $meta ... [truncated message content] |