Index: trunk/phase3/maintenance/fuzz-tester.php |
— | — | @@ -0,0 +1,2770 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Performs fuzz-style testing of MediaWiki's parser and forms. |
| 5 | + * |
| 6 | + * Copyright © 2006 Nick Jenkins |
| 7 | + * |
| 8 | + * This program is free software; you can redistribute it and/or modify |
| 9 | + * it under the terms of the GNU General Public License as published by |
| 10 | + * the Free Software Foundation; either version 2 of the License, or |
| 11 | + * (at your option) any later version. |
| 12 | + * |
| 13 | + * This program is distributed in the hope that it will be useful, |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | + * GNU General Public License for more details. |
| 17 | + * |
| 18 | + * You should have received a copy of the GNU General Public License along |
| 19 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 20 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 21 | + * http://www.gnu.org/copyleft/gpl.html |
| 22 | + * |
| 23 | + * @file |
| 24 | + * @ingroup Maintenance |
| 25 | + * @author Nick Jenkins ( http://nickj.org/ ). |
| 26 | + |
| 27 | + |
| 28 | +Started: 18 May 2006. |
| 29 | + |
| 30 | +Description: |
| 31 | + Performs fuzz-style testing of MediaWiki's parser and forms. |
| 32 | + |
| 33 | +How: |
| 34 | + - Generate lots of nasty wiki text. |
| 35 | + - Ask the Parser to render that wiki text to HTML, or ask MediaWiki's forms |
| 36 | + to deal with that wiki text. |
| 37 | + - Check MediaWiki's output for problems. |
| 38 | + - Repeat. |
| 39 | + |
| 40 | +Why: |
| 41 | + - To help find bugs. |
| 42 | + - To help find security issues, or potential security issues. |
| 43 | + |
| 44 | +What type of problems are being checked for: |
| 45 | + - Unclosed tags. |
| 46 | + - Errors or interesting warnings from Tidy. |
| 47 | + - PHP errors / warnings / notices. |
| 48 | + - MediaWiki internal errors. |
| 49 | + - Very slow responses. |
| 50 | + - No response from apache. |
| 51 | + - Optionally checking for malformed HTML using the W3C validator. |
| 52 | + |
| 53 | +Background: |
| 54 | + Many of the wikiFuzz class methods are a modified PHP port, |
| 55 | + of a "shameless" Python port, of LCAMTUF'S MANGELME: |
| 56 | + - http://www.securiteam.com/tools/6Z00N1PBFK.html |
| 57 | + - http://www.securityfocus.com/archive/1/378632/2004-10-15/2004-10-21/0 |
| 58 | + |
| 59 | +Video: |
| 60 | + There's an XviD video discussing this fuzz tester. You can get it from: |
| 61 | + http://files.nickj.org/MediaWiki/Fuzz-Testing-MediaWiki-xvid.avi |
| 62 | + |
| 63 | +Requirements: |
| 64 | + To run this, you will need: |
| 65 | + - Command-line PHP5, with PHP-curl enabled (not all installations have this |
| 66 | + enabled - try "apt-get install php5-curl" if you're on Debian to install). |
| 67 | + - the Tidy standalone executable. ("apt-get install tidy"). |
| 68 | + |
| 69 | +Optional: |
| 70 | + - If you want to run the curl scripts, you'll need standalone curl installed |
| 71 | + ("apt-get install curl") |
| 72 | + - For viewing the W3C validator output on a command line, the "html2text" |
| 73 | + program may be useful ("apt-get install html2text") |
| 74 | + |
| 75 | +Saving tests and test results: |
| 76 | + Any of the fuzz tests which find problems are saved for later review. |
| 77 | + In order to help track down problems, tests are saved in a number of |
| 78 | + different formats. The default filename extensions and their meanings are: |
| 79 | + - ".test.php" : PHP script that reproduces just that one problem using PHP-Curl. |
| 80 | + - ".curl.sh" : Shell script that reproduces that problem using standalone curl. |
| 81 | + - ".data.bin" : The serialized PHP data so that this script can re-run the test. |
| 82 | + - ".info.txt" : A human-readable text file with details of the field contents. |
| 83 | + |
| 84 | +Wiki configuration for testing: |
| 85 | + You should make some additions to LocalSettings.php in order to catch the most |
| 86 | + errors. Note this configuration is for **TESTING PURPOSES ONLY**, and is IN NO |
| 87 | + WAY, SHAPE, OR FORM suitable for deployment on a hostile network. That said, |
| 88 | + personally I find these additions to be the most helpful for testing purposes: |
| 89 | + |
| 90 | + // --------- Start --------- |
| 91 | + // Everyone can do everything. Very useful for testing, yet useless for deployment. |
| 92 | + $wgGroupPermissions['*']['autoconfirmed'] = true; |
| 93 | + $wgGroupPermissions['*']['block'] = true; |
| 94 | + $wgGroupPermissions['*']['bot'] = true; |
| 95 | + $wgGroupPermissions['*']['delete'] = true; |
| 96 | + $wgGroupPermissions['*']['deletedhistory'] = true; |
| 97 | + $wgGroupPermissions['*']['deleterevision'] = true; |
| 98 | + $wgGroupPermissions['*']['editinterface'] = true; |
| 99 | + $wgGroupPermissions['*']['hiderevision'] = true; |
| 100 | + $wgGroupPermissions['*']['import'] = true; |
| 101 | + $wgGroupPermissions['*']['importupload'] = true; |
| 102 | + $wgGroupPermissions['*']['minoredit'] = true; |
| 103 | + $wgGroupPermissions['*']['move'] = true; |
| 104 | + $wgGroupPermissions['*']['patrol'] = true; |
| 105 | + $wgGroupPermissions['*']['protect'] = true; |
| 106 | + $wgGroupPermissions['*']['proxyunbannable'] = true; |
| 107 | + $wgGroupPermissions['*']['renameuser'] = true; |
| 108 | + $wgGroupPermissions['*']['reupload'] = true; |
| 109 | + $wgGroupPermissions['*']['reupload-shared'] = true; |
| 110 | + $wgGroupPermissions['*']['rollback'] = true; |
| 111 | + $wgGroupPermissions['*']['siteadmin'] = true; |
| 112 | + $wgGroupPermissions['*']['trackback'] = true; |
| 113 | + $wgGroupPermissions['*']['unwatchedpages'] = true; |
| 114 | + $wgGroupPermissions['*']['upload'] = true; |
| 115 | + $wgGroupPermissions['*']['userrights'] = true; |
| 116 | + $wgGroupPermissions['*']['renameuser'] = true; |
| 117 | + $wgGroupPermissions['*']['makebot'] = true; |
| 118 | + $wgGroupPermissions['*']['makesysop'] = true; |
| 119 | + |
| 120 | + // Enable weird and wonderful options: |
| 121 | + // Increase default error reporting level. |
| 122 | + error_reporting (E_ALL); // At a later date could be increased to E_ALL | E_STRICT |
| 123 | + $wgBlockOpenProxies = true; // Some block pages require this to be true in order to test. |
| 124 | + $wgEnableUploads = true; // enable uploads. |
| 125 | + //$wgUseTrackbacks = true; // enable trackbacks; However this breaks the viewPageTest, so currently disabled. |
| 126 | + $wgDBerrorLog = "/root/mediawiki-db-error-log.txt"; // log DB errors, replace with suitable path. |
| 127 | + $wgShowSQLErrors = true; // Show SQL errors (instead of saying the query was hidden). |
| 128 | + $wgShowExceptionDetails = true; // want backtraces. |
| 129 | + $wgEnableAPI = true; // enable API. |
| 130 | + $wgEnableWriteAPI = true; // enable API. |
| 131 | + |
| 132 | + // Install & enable Parser Hook extensions to increase code coverage. E.g.: |
| 133 | + require_once("extensions/ParserFunctions/ParserFunctions.php"); |
| 134 | + require_once("extensions/Cite/Cite.php"); |
| 135 | + require_once("extensions/inputbox/inputbox.php"); |
| 136 | + require_once("extensions/Sort/Sort.php"); |
| 137 | + require_once("extensions/wikihiero/wikihiero.php"); |
| 138 | + require_once("extensions/CharInsert/CharInsert.php"); |
| 139 | + require_once("extensions/FixedImage/FixedImage.php"); |
| 140 | + |
| 141 | + // Install & enable Special Page extensions to increase code coverage. E.g.: |
| 142 | + require_once("extensions/Cite/SpecialCite.php"); |
| 143 | + require_once("extensions/Filepath/SpecialFilepath.php"); |
| 144 | + require_once("extensions/Makebot/Makebot.php"); |
| 145 | + require_once("extensions/Makesysop/SpecialMakesysop.php"); |
| 146 | + require_once("extensions/Renameuser/SpecialRenameuser.php"); |
| 147 | + require_once("extensions/LinkSearch/LinkSearch.php"); |
| 148 | + // --------- End --------- |
| 149 | + |
| 150 | + If you want to try E_STRICT error logging, add this to the above: |
| 151 | + // --------- Start --------- |
| 152 | + error_reporting (E_ALL | E_STRICT); |
| 153 | + set_error_handler( 'error_handler' ); |
| 154 | + function error_handler ($type, $message, $file=__FILE__, $line=__LINE__) { |
| 155 | + if ($message == "var: Deprecated. Please use the public/private/protected modifiers") return; |
| 156 | + print "<br />\n<b>Strict Standards:</b> Type: <b>$type</b>: $message in <b>$file</b> on line <b>$line</b><br />\n"; |
| 157 | + } |
| 158 | + // --------- End --------- |
| 159 | + |
| 160 | + Also add/change this in LocalSettings.php: |
| 161 | + // --------- Start --------- |
| 162 | + $wgEnableProfileInfo = true; |
| 163 | + $wgDBserver = "localhost"; // replace with DB server hostname |
| 164 | + // --------- End --------- |
| 165 | + |
| 166 | +Usage: |
| 167 | + Run with "php fuzz-tester.php". |
| 168 | + To see the various command-line options, run "php fuzz-tester.php --help". |
| 169 | + To stop the script, press Ctrl-C. |
| 170 | + |
| 171 | +Console output: |
| 172 | + - If requested, first any previously failed tests will be rerun. |
| 173 | + - Then new tests will be generated and run. Any tests that fail will be saved, |
| 174 | + and a brief message about why they failed will be printed on the console. |
| 175 | + - The console will show the number of tests run, time run, number of tests |
| 176 | + failed, number of tests being done per minute, and the name of the current test. |
| 177 | + |
| 178 | +TODO: |
| 179 | + Some known things that could improve this script: |
| 180 | + - Logging in with cookie jar storage needed for some tests (as there are some |
| 181 | + pages that cannot be tested without being logged in, and which are currently |
| 182 | + untested - e.g. Special:Emailuser, Special:Preferences, adding to Watchist). |
| 183 | + - Testing of Timeline extension (I cannot test as ploticus has/had issues on |
| 184 | + my architecture). |
| 185 | + |
| 186 | +*/ |
| 187 | + |
| 188 | +// ///////////////////////// COMMAND LINE HELP //////////////////////////////////// |
| 189 | + |
| 190 | +// This is a command line script, load MediaWiki env (gives command line options); |
| 191 | +require_once( dirname( __FILE__ ) . '/commandLine.inc' ); |
| 192 | + |
| 193 | +// if the user asked for an explanation of command line options. |
| 194 | +if ( isset( $options["help"] ) ) { |
| 195 | + print <<<ENDS |
| 196 | +MediaWiki $wgVersion fuzz tester |
| 197 | +Usage: php {$_SERVER["SCRIPT_NAME"]} [--quiet] [--base-url=<url-to-test-wiki>] |
| 198 | + [--directory=<failed-test-path>] [--include-binary] |
| 199 | + [--w3c-validate] [--delete-passed-retests] [--help] |
| 200 | + [--user=<username>] [--password=<password>] |
| 201 | + [--rerun-failed-tests] [--max-errors=<int>] |
| 202 | + [--max-runtime=<num-minutes>] |
| 203 | + [--specific-test=<test-name>] |
| 204 | + |
| 205 | +Options: |
| 206 | + --quiet : Hides passed tests, shows only failed tests. |
| 207 | + --base-url : URL to a wiki on which to run the tests. |
| 208 | + The "http://" is optional and can be omitted. |
| 209 | + --directory : Full path to directory for storing failed tests. |
| 210 | + Will be created if it does not exist. |
| 211 | + --include-binary : Includes non-alphanumeric characters in the tests. |
| 212 | + --w3c-validate : Validates pages using the W3C's web validator. |
| 213 | + Slow. Currently many pages fail validation. |
| 214 | + --user : Login name of a valid user on your test wiki. |
| 215 | + --password : Password for the valid user on your test wiki. |
| 216 | + --delete-passed-retests : Will delete retests that now pass. |
| 217 | + Requires --rerun-failed-tests to be meaningful. |
| 218 | + --rerun-failed-tests : Whether to rerun any previously failed tests. |
| 219 | + --max-errors : Maximum number of errors to report before exiting. |
| 220 | + Does not include errors from --rerun-failed-tests |
| 221 | + --max-runtime : Maximum runtime, in minutes, to run before exiting. |
| 222 | + Only applies to new tests, not --rerun-failed-tests |
| 223 | + --specific-test : Runs only the specified fuzz test. |
| 224 | + Only applies to new tests, not --rerun-failed-tests |
| 225 | + --keep-passed-tests : Saves all test files, even those that pass. |
| 226 | + --help : Show this help message. |
| 227 | + |
| 228 | +Example: |
| 229 | + If you wanted to fuzz test a nightly MediaWiki checkout using cron for 1 hour, |
| 230 | + and only wanted to be informed of errors, and did not want to redo previously |
| 231 | + failed tests, and wanted a maximum of 100 errors, then you could do: |
| 232 | + php {$_SERVER["SCRIPT_NAME"]} --quiet --max-errors=100 --max-runtime=60 |
| 233 | + |
| 234 | + |
| 235 | +ENDS; |
| 236 | + |
| 237 | + exit( 0 ); |
| 238 | +} |
| 239 | + |
| 240 | + |
| 241 | +// if we got command line options, check they look valid. |
| 242 | +$validOptions = array ( "quiet", "base-url", "directory", "include-binary", |
| 243 | + "w3c-validate", "user", "password", "delete-passed-retests", |
| 244 | + "rerun-failed-tests", "max-errors", |
| 245 | + "max-runtime", "specific-test", "keep-passed-tests", "help" ); |
| 246 | +if ( !empty( $options ) ) { |
| 247 | + $unknownArgs = array_diff ( array_keys( $options ), $validOptions ); |
| 248 | + foreach ( $unknownArgs as $invalidArg ) { |
| 249 | + print "Ignoring invalid command-line option: --$invalidArg\n"; |
| 250 | + } |
| 251 | +} |
| 252 | + |
| 253 | + |
| 254 | +// /////////////////////////// CONFIGURATION //////////////////////////////////// |
| 255 | + |
| 256 | +// URL to some wiki on which we can run our tests. |
| 257 | +if ( !empty( $options["base-url"] ) ) { |
| 258 | + define( "WIKI_BASE_URL", $options["base-url"] ); |
| 259 | +} else { |
| 260 | + define( "WIKI_BASE_URL", $wgServer . $wgScriptPath . '/' ); |
| 261 | +} |
| 262 | + |
| 263 | +// The directory name where we store the output. |
| 264 | +// Example for Windows: "c:\\temp\\wiki-fuzz" |
| 265 | +if ( !empty( $options["directory"] ) ) { |
| 266 | + define( "DIRECTORY", $options["directory"] ); |
| 267 | +} else { |
| 268 | + define( "DIRECTORY", "{$wgUploadDirectory}/fuzz-tests" ); |
| 269 | +} |
| 270 | + |
| 271 | +// Should our test fuzz data include binary strings? |
| 272 | +define( "INCLUDE_BINARY", isset( $options["include-binary"] ) ); |
| 273 | + |
| 274 | +// Whether we want to validate HTML output on the web. |
| 275 | +// At the moment very few generated pages will validate, so not recommended. |
| 276 | +define( "VALIDATE_ON_WEB", isset( $options["w3c-validate"] ) ); |
| 277 | +// URL to use to validate our output: |
| 278 | +define( "VALIDATOR_URL", "http://validator.w3.org/check" ); |
| 279 | + |
| 280 | +// Location of Tidy standalone executable. |
| 281 | +define( "PATH_TO_TIDY", "/usr/bin/tidy" ); |
| 282 | + |
| 283 | +// The name of a user who has edited on your wiki. Used |
| 284 | +// when testing the Special:Contributions and Special:Userlogin page. |
| 285 | +if ( !empty( $options["user"] ) ) { |
| 286 | + define( "USER_ON_WIKI", $options["user"] ); |
| 287 | +} else { |
| 288 | + define( "USER_ON_WIKI", "nickj" ); |
| 289 | +} |
| 290 | + |
| 291 | +// The password of the above user. Used when testing the login page, |
| 292 | +// and to do this we sometimes need to login successfully. |
| 293 | +if ( !empty( $options["password"] ) ) { |
| 294 | + define( "USER_PASSWORD", $options["password"] ); |
| 295 | +} else { |
| 296 | + // And no, this is not a valid password on any public wiki. |
| 297 | + define( "USER_PASSWORD", "nickj" ); |
| 298 | +} |
| 299 | + |
| 300 | +// If we have a test that failed, and then we run it again, and it passes, |
| 301 | +// do you want to delete it or keep it? |
| 302 | +define( "DELETE_PASSED_RETESTS", isset( $options["delete-passed-retests"] ) ); |
| 303 | + |
| 304 | +// Do we want to rerun old saved tests at script startup? |
| 305 | +// Set to true to help catch regressions, or false if you only want new stuff. |
| 306 | +define( "RERUN_OLD_TESTS", isset( $options["rerun-failed-tests"] ) ); |
| 307 | + |
| 308 | +// File where the database errors are logged. Should be defined in LocalSettings.php. |
| 309 | +define( "DB_ERROR_LOG_FILE", $wgDBerrorLog ); |
| 310 | + |
| 311 | +// Run in chatty mode (all output, default), or run in quiet mode (only prints out details of failed tests)? |
| 312 | +define( "QUIET", isset( $options["quiet"] ) ); |
| 313 | + |
| 314 | +// Keep all test files, even those that pass. Potentially useful to tracking input that causes something |
| 315 | +// unusual to happen, if you don't know what "unusual" is until later. |
| 316 | +define( "KEEP_PASSED_TESTS", isset( $options["keep-passed-tests"] ) ); |
| 317 | + |
| 318 | +// The maximum runtime, if specified. |
| 319 | +if ( !empty( $options["max-runtime"] ) && intval( $options["max-runtime"] ) > 0 ) { |
| 320 | + define( "MAX_RUNTIME", intval( $options["max-runtime"] ) ); |
| 321 | +} |
| 322 | + |
| 323 | +// The maximum number of problems to find, if specified. Excludes retest errors. |
| 324 | +if ( !empty( $options["max-errors"] ) && intval( $options["max-errors"] ) > 0 ) { |
| 325 | + define( "MAX_ERRORS", intval( $options["max-errors"] ) ); |
| 326 | +} |
| 327 | + |
| 328 | +// if the user has requested a specific test (instead of all tests), and the test they asked for looks valid. |
| 329 | +if ( !empty( $options["specific-test"] ) ) { |
| 330 | + if ( class_exists( $options["specific-test"] ) && get_parent_class( $options["specific-test"] ) == "pageTest" ) { |
| 331 | + define( "SPECIFIC_TEST", $options["specific-test"] ); |
| 332 | + } |
| 333 | + else { |
| 334 | + print "Ignoring invalid --specific-test\n"; |
| 335 | + } |
| 336 | +} |
| 337 | + |
| 338 | +// Define the file extensions we'll use: |
| 339 | +define( "PHP_TEST" , ".test.php" ); |
| 340 | +define( "CURL_TEST", ".curl.sh" ); |
| 341 | +define( "DATA_FILE", ".data.bin" ); |
| 342 | +define( "INFO_FILE", ".info.txt" ); |
| 343 | +define( "HTML_FILE", ".wiki_preview.html" ); |
| 344 | + |
| 345 | +// If it goes wrong, we want to know about it. |
| 346 | +error_reporting( E_ALL | E_STRICT ); |
| 347 | + |
| 348 | +// ////////////// A CLASS THAT GENERATES RANDOM NASTY WIKI & HTML STRINGS ////////////////////// |
| 349 | + |
| 350 | +class wikiFuzz { |
| 351 | + |
| 352 | + // Only some HTML tags are understood with params by MediaWiki, the rest are ignored. |
| 353 | + // List the tags that accept params below, as well as what those params are. |
| 354 | + public static $data = array( |
| 355 | + "B" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 356 | + "CAPTION" => array( "CLASS", "ID", "STYLE", "align", "lang", "dir", "title" ), |
| 357 | + "CENTER" => array( "CLASS", "STYLE", "ID", "lang", "dir", "title" ), |
| 358 | + "DIV" => array( "CLASS", "STYLE", "ID", "align", "lang", "dir", "title" ), |
| 359 | + "FONT" => array( "CLASS", "STYLE", "ID", "lang", "dir", "title", "face", "size", "color" ), |
| 360 | + "H1" => array( "STYLE", "CLASS", "ID", "align", "lang", "dir", "title" ), |
| 361 | + "H2" => array( "STYLE", "CLASS", "ID", "align", "lang", "dir", "title" ), |
| 362 | + "HR" => array( "STYLE", "CLASS", "ID", "WIDTH", "lang", "dir", "title", "size", "noshade" ), |
| 363 | + "LI" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "type", "value" ), |
| 364 | + "TABLE" => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "BORDER", "CELLPADDING", |
| 365 | + "CELLSPACING", "lang", "dir", "title", "summary", "frame", "rules" ), |
| 366 | + "TD" => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "COLSPAN", "ROWSPAN", |
| 367 | + "VALIGN", "abbr", "axis", "headers", "scope", "nowrap", "height", "lang", |
| 368 | + "dir", "title", "char", "charoff" ), |
| 369 | + "TH" => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "COLSPAN", "ROWSPAN", |
| 370 | + "VALIGN", "abbr", "axis", "headers", "scope", "nowrap", "height", "lang", |
| 371 | + "dir", "title", "char", "charoff" ), |
| 372 | + "TR" => array( "CLASS", "STYLE", "ID", "BGCOLOR", "ALIGN", "VALIGN", "lang", "dir", "title", "char", "charoff" ), |
| 373 | + "UL" => array( "CLASS", "STYLE", "ID", "lang", "dir", "title", "type" ), |
| 374 | + "P" => array( "style", "class", "id", "align", "lang", "dir", "title" ), |
| 375 | + "blockquote" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "cite" ), |
| 376 | + "span" => array( "CLASS", "ID", "STYLE", "align", "lang", "dir", "title" ), |
| 377 | + "code" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 378 | + "tt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 379 | + "small" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 380 | + "big" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 381 | + "s" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 382 | + "u" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 383 | + "del" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "datetime", "cite" ), |
| 384 | + "ins" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "datetime", "cite" ), |
| 385 | + "sub" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 386 | + "sup" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 387 | + "ol" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "type", "start" ), |
| 388 | + "br" => array( "CLASS", "ID", "STYLE", "title", "clear" ), |
| 389 | + "cite" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 390 | + "var" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 391 | + "dl" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 392 | + "ruby" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 393 | + "rt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 394 | + "rp" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 395 | + "dt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 396 | + "dl" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 397 | + "em" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 398 | + "strong" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 399 | + "i" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), |
| 400 | + "thead" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign' ), |
| 401 | + "tfoot" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign' ), |
| 402 | + "tbody" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign' ), |
| 403 | + "colgroup" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign', 'span', 'width' ), |
| 404 | + "col" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign', 'span', 'width' ), |
| 405 | + "pre" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "width" ), |
| 406 | + |
| 407 | + // extension tags that accept parameters: |
| 408 | + "sort" => array( "order", "class" ), |
| 409 | + "ref" => array( "name" ), |
| 410 | + "categorytree" => array( "hideroot", "mode", "style" ), |
| 411 | + "chemform" => array( "link", "wikilink", "query" ), |
| 412 | + "section" => array( "begin", "new" ), |
| 413 | + |
| 414 | + // older MW transclusion. |
| 415 | + "transclude" => array( "page" ), |
| 416 | + ); |
| 417 | + |
| 418 | + // The types of the HTML that we will be testing were defined above |
| 419 | + // Note: this needs to be initialized later to be equal to: array_keys(wikiFuzz::$data); |
| 420 | + // as such, it also needs to also be publicly modifiable. |
| 421 | + public static $types; |
| 422 | + |
| 423 | + |
| 424 | + // Some attribute values. |
| 425 | + static private $other = array( "&", "=", ":", "?", "\"", "\n", "%n%n%n%n%n%n%n%n%n%n%n%n", "\\" ); |
| 426 | + static private $ints = array( |
| 427 | + // various numbers |
| 428 | + "0", "-1", "127", "-7897", "89000", "808080", "90928345", |
| 429 | + "0xfffffff", "ffff", |
| 430 | + |
| 431 | + // Different ways of saying: ' |
| 432 | + "'", // Long UTF-8 Unicode encoding |
| 433 | + "'", // dec version. |
| 434 | + "'", // hex version. |
| 435 | + "§", // malformed hex variant, MSB not zero. |
| 436 | + |
| 437 | + // Different ways of saying: " |
| 438 | + """, // Long UTF-8 Unicode encoding |
| 439 | + """, |
| 440 | + """, // hex version. |
| 441 | + "¢", // malformed hex variant, MSB not zero. |
| 442 | + |
| 443 | + // Different ways of saying: < |
| 444 | + "<", |
| 445 | + "<", // Long UTF-8 Unicode encoding without semicolon (Mediawiki wants the colon) |
| 446 | + "<", // Long UTF-8 Unicode encoding with semicolon |
| 447 | + "<", |
| 448 | + "<", // hex version. |
| 449 | + "¼", // malformed hex variant, MSB not zero. |
| 450 | + "<", // mid-length hex version |
| 451 | + "<", // slightly longer hex version, with capital "X" |
| 452 | + |
| 453 | + // Different ways of saying: > |
| 454 | + ">", |
| 455 | + ">", // Long UTF-8 Unicode encoding |
| 456 | + ">", |
| 457 | + ">", // hex version. |
| 458 | + "¾", // malformed variant, MSB not zero. |
| 459 | + |
| 460 | + // Different ways of saying: [ |
| 461 | + "[", // Long UTF-8 Unicode encoding |
| 462 | + "[", |
| 463 | + "[", // hex version. |
| 464 | + |
| 465 | + // Different ways of saying: {{ |
| 466 | + "{{", // Long UTF-8 Unicode encoding |
| 467 | + "{{", |
| 468 | + "{{", // hex version. |
| 469 | + |
| 470 | + // Different ways of saying: | |
| 471 | + "|", // Long UTF-8 Unicode encoding |
| 472 | + "|", |
| 473 | + "|", // hex version. |
| 474 | + "ü", // malformed hex variant, MSB not zero. |
| 475 | + |
| 476 | + // a "lignature" - http://www.robinlionheart.com/stds/html4/spchars#ligature |
| 477 | + // ‌ == ‌ |
| 478 | + "‌" |
| 479 | + ); |
| 480 | + |
| 481 | + // Defines various wiki-related bits of syntax, that can potentially cause |
| 482 | + // MediaWiki to do something other than just print that literal text. |
| 483 | + static private $ext = array( |
| 484 | + // links, templates, parameters. |
| 485 | + "[[", "]]", "{{", "}}", "|", "[", "]", "{{{", "}}}", "|]]", |
| 486 | + |
| 487 | + // wiki tables. |
| 488 | + "\n{|", "\n|}", |
| 489 | + "!", |
| 490 | + "\n!", |
| 491 | + "!!", |
| 492 | + "||", |
| 493 | + "\n|-", "| ", "\n|", |
| 494 | + |
| 495 | + // section headings. |
| 496 | + "=", "==", "===", "====", "=====", "======", |
| 497 | + |
| 498 | + // lists (ordered and unordered) and indentation. |
| 499 | + "\n*", "*", "\n:", ":", |
| 500 | + "\n#", "#", |
| 501 | + |
| 502 | + // definition lists (dl, dt, dd), newline, and newline with pre, and a tab. |
| 503 | + "\n;", ";", "\n ", |
| 504 | + |
| 505 | + // Whitespace: newline, tab, space. |
| 506 | + "\n", "\t", " ", |
| 507 | + |
| 508 | + // Some XSS attack vectors from http://ha.ckers.org/xss.html |
| 509 | + "	", // tab |
| 510 | + "
", // newline |
| 511 | + "
", // carriage return |
| 512 | + "\0", // null character |
| 513 | + "  ", // spaces and meta characters |
| 514 | + "'';!--\"<XSS>=&{()}", // compact injection of XSS & SQL tester |
| 515 | + |
| 516 | + // various NULL fields |
| 517 | + "%00", |
| 518 | + "�", |
| 519 | + "\0", |
| 520 | + |
| 521 | + // horizontal rule. |
| 522 | + "-----", "\n-----", |
| 523 | + |
| 524 | + // signature, redirect, bold, italics. |
| 525 | + "~~~~", "#REDIRECT [[", "'''", "''", |
| 526 | + |
| 527 | + // comments. |
| 528 | + "<!--", "-->", |
| 529 | + |
| 530 | + // quotes. |
| 531 | + "\"", "'", |
| 532 | + |
| 533 | + // tag start and tag end. |
| 534 | + "<", ">", |
| 535 | + |
| 536 | + // implicit link creation on URIs. |
| 537 | + "http://", |
| 538 | + "https://", |
| 539 | + "ftp://", |
| 540 | + "irc://", |
| 541 | + "news:", |
| 542 | + 'gopher://', |
| 543 | + 'telnet://', |
| 544 | + 'nntp://', |
| 545 | + 'worldwind://', |
| 546 | + 'mailto:', |
| 547 | + |
| 548 | + // images. |
| 549 | + "[[image:", |
| 550 | + ".gif", |
| 551 | + ".png", |
| 552 | + ".jpg", |
| 553 | + ".jpeg", |
| 554 | + 'thumbnail=', |
| 555 | + 'thumbnail', |
| 556 | + 'thumb=', |
| 557 | + 'thumb', |
| 558 | + 'right', |
| 559 | + 'none', |
| 560 | + 'left', |
| 561 | + 'framed', |
| 562 | + 'frame', |
| 563 | + 'enframed', |
| 564 | + 'centre', |
| 565 | + 'center', |
| 566 | + "Image:", |
| 567 | + "[[:Image", |
| 568 | + 'px', |
| 569 | + 'upright=', |
| 570 | + 'border', |
| 571 | + |
| 572 | + // misc stuff to throw at the Parser. |
| 573 | + '%08X', |
| 574 | + '/', |
| 575 | + ":x{|", |
| 576 | + "\n|+", |
| 577 | + "<noinclude>", |
| 578 | + "</noinclude>", |
| 579 | + " \302\273", |
| 580 | + " :", |
| 581 | + " !", |
| 582 | + " ;", |
| 583 | + "\302\253", |
| 584 | + "[[category:", |
| 585 | + "?=", |
| 586 | + "(", |
| 587 | + ")", |
| 588 | + "]]]", |
| 589 | + "../", |
| 590 | + "{{{{", |
| 591 | + "}}}}", |
| 592 | + "[[Special:", |
| 593 | + "<includeonly>", |
| 594 | + "</includeonly>", |
| 595 | + "<!--MWTEMPLATESECTION=", |
| 596 | + '<!--MWTOC-->', |
| 597 | + |
| 598 | + // implicit link creation on booknum, RFC, and PubMed ID usage (both with and without IDs) |
| 599 | + "ISBN 2", |
| 600 | + "RFC 000", |
| 601 | + "PMID 000", |
| 602 | + "ISBN ", |
| 603 | + "RFC ", |
| 604 | + "PMID ", |
| 605 | + |
| 606 | + // magic words: |
| 607 | + '__NOTOC__', |
| 608 | + '__FORCETOC__', |
| 609 | + '__NOEDITSECTION__', |
| 610 | + '__START__', |
| 611 | + '__NOTITLECONVERT__', |
| 612 | + '__NOCONTENTCONVERT__', |
| 613 | + '__END__', |
| 614 | + '__TOC__', |
| 615 | + '__NOTC__', |
| 616 | + '__NOCC__', |
| 617 | + "__FORCETOC__", |
| 618 | + "__NEWSECTIONLINK__", |
| 619 | + "__NOGALLERY__", |
| 620 | + |
| 621 | + // more magic words / internal templates. |
| 622 | + '{{PAGENAME}}', |
| 623 | + '{{PAGENAMEE}}', |
| 624 | + '{{NAMESPACE}}', |
| 625 | + "{{MSG:", |
| 626 | + "}}", |
| 627 | + "{{MSGNW:", |
| 628 | + "}}", |
| 629 | + "{{INT:", |
| 630 | + "}}", |
| 631 | + '{{SITENAME}}', |
| 632 | + "{{NS:", |
| 633 | + "}}", |
| 634 | + "{{LOCALURL:", |
| 635 | + "}}", |
| 636 | + "{{LOCALURLE:", |
| 637 | + "}}", |
| 638 | + "{{SCRIPTPATH}}", |
| 639 | + "{{GRAMMAR:gentiv|", |
| 640 | + "}}", |
| 641 | + "{{REVISIONID}}", |
| 642 | + "{{SUBPAGENAME}}", |
| 643 | + "{{SUBPAGENAMEE}}", |
| 644 | + "{{ns:0}}", |
| 645 | + "{{fullurle:", |
| 646 | + "}}", |
| 647 | + "{{subst::", |
| 648 | + "}}", |
| 649 | + "{{UCFIRST:", |
| 650 | + "}}", |
| 651 | + "{{UC:", |
| 652 | + '{{SERVERNAME}}', |
| 653 | + '{{SERVER}}', |
| 654 | + "{{RAW:", |
| 655 | + "}}", |
| 656 | + "{{PLURAL:", |
| 657 | + "}}", |
| 658 | + "{{LCFIRST:", |
| 659 | + "}}", |
| 660 | + "{{LC:", |
| 661 | + "}}", |
| 662 | + '{{CURRENTWEEK}}', |
| 663 | + '{{CURRENTDOW}}', |
| 664 | + "{{INT:{{LC:contribs-showhideminor}}|", |
| 665 | + "}}", |
| 666 | + "{{INT:googlesearch|", |
| 667 | + "}}", |
| 668 | + "{{BASEPAGENAME}}", |
| 669 | + "{{CONTENTLANGUAGE}}", |
| 670 | + "{{PAGESINNAMESPACE:}}", |
| 671 | + "{{#language:", |
| 672 | + "}}", |
| 673 | + "{{#special:", |
| 674 | + "}}", |
| 675 | + "{{#special:emailuser", |
| 676 | + "}}", |
| 677 | + |
| 678 | + // Some raw link for magic words. |
| 679 | + "{{NUMBEROFPAGES:R", |
| 680 | + "}}", |
| 681 | + "{{NUMBEROFUSERS:R", |
| 682 | + "}}", |
| 683 | + "{{NUMBEROFARTICLES:R", |
| 684 | + "}}", |
| 685 | + "{{NUMBEROFFILES:R", |
| 686 | + "}}", |
| 687 | + "{{NUMBEROFADMINS:R", |
| 688 | + "}}", |
| 689 | + "{{padleft:", |
| 690 | + "}}", |
| 691 | + "{{padright:", |
| 692 | + "}}", |
| 693 | + "{{DEFAULTSORT:", |
| 694 | + "}}", |
| 695 | + |
| 696 | + // internal Math "extension": |
| 697 | + "<math>", |
| 698 | + "</math>", |
| 699 | + |
| 700 | + // Parser extension functions: |
| 701 | + "{{#expr:", |
| 702 | + "{{#if:", |
| 703 | + "{{#ifeq:", |
| 704 | + "{{#ifexist:", |
| 705 | + "{{#ifexpr:", |
| 706 | + "{{#switch:", |
| 707 | + "{{#time:", |
| 708 | + "}}", |
| 709 | + |
| 710 | + // references table for the Cite extension. |
| 711 | + "<references/>", |
| 712 | + |
| 713 | + // Internal Parser tokens - try inserting some of these. |
| 714 | + "UNIQ25f46b0524f13e67NOPARSE", |
| 715 | + "UNIQ17197916557e7cd6-HTMLCommentStrip46238afc3bb0cf5f00000002", |
| 716 | + "\x07UNIQ17197916557e7cd6-HTMLCommentStrip46238afc3bb0cf5f00000002-QINU", |
| 717 | + |
| 718 | + // Inputbox extension: |
| 719 | + "<inputbox>\ntype=search\nsearchbuttonlabel=\n", |
| 720 | + "</inputbox>", |
| 721 | + |
| 722 | + // charInsert extension: |
| 723 | + "<charInsert>", |
| 724 | + "</charInsert>", |
| 725 | + |
| 726 | + // wikiHiero extension: |
| 727 | + "<hiero>", |
| 728 | + "</hiero>", |
| 729 | + |
| 730 | + // Image gallery: |
| 731 | + "<gallery>", |
| 732 | + "</gallery>", |
| 733 | + |
| 734 | + // FixedImage extension. |
| 735 | + "<fundraising/>", |
| 736 | + |
| 737 | + // Timeline extension: currently untested. |
| 738 | + |
| 739 | + // Nowiki: |
| 740 | + "<nOwIkI>", |
| 741 | + "</nowiki>", |
| 742 | + |
| 743 | + // an external image to test the external image displaying code |
| 744 | + "http://debian.org/Pics/debian.png", |
| 745 | + |
| 746 | + // LabeledSectionTransclusion extension. |
| 747 | + "{{#lstx:", |
| 748 | + "}}", |
| 749 | + "{{#lst:", |
| 750 | + "}}", |
| 751 | + "{{#lst:Main Page|", |
| 752 | + "}}" |
| 753 | + ); |
| 754 | + |
| 755 | + /** |
| 756 | + ** Randomly returns one element of the input array. |
| 757 | + */ |
| 758 | + static public function chooseInput( array $input ) { |
| 759 | + $randindex = wikiFuzz::randnum( count( $input ) - 1 ); |
| 760 | + return $input[$randindex]; |
| 761 | + } |
| 762 | + |
| 763 | + // Max number of parameters for HTML attributes. |
| 764 | + static private $maxparams = 10; |
| 765 | + |
| 766 | + /** |
| 767 | + ** Returns random number between finish and start. |
| 768 | + */ |
| 769 | + static public function randnum( $finish, $start = 0 ) { |
| 770 | + return mt_rand( $start, $finish ); |
| 771 | + } |
| 772 | + |
| 773 | + /** |
| 774 | + ** Returns a mix of random text and random wiki syntax. |
| 775 | + */ |
| 776 | + static private function randstring() { |
| 777 | + $thestring = ""; |
| 778 | + |
| 779 | + for ( $i = 0; $i < 40; $i++ ) { |
| 780 | + $what = wikiFuzz::randnum( 1 ); |
| 781 | + |
| 782 | + if ( $what == 0 ) { // include some random wiki syntax |
| 783 | + $which = wikiFuzz::randnum( count( wikiFuzz::$ext ) - 1 ); |
| 784 | + $thestring .= wikiFuzz::$ext[$which]; |
| 785 | + } |
| 786 | + else { // include some random text |
| 787 | + $char = INCLUDE_BINARY |
| 788 | + // Decimal version: |
| 789 | + // "&#" . wikiFuzz::randnum(255) . ";" |
| 790 | + // Hex version: |
| 791 | + ? "&#x" . str_pad( dechex( wikiFuzz::randnum( 255 ) ), wikiFuzz::randnum( 2, 7 ), "0", STR_PAD_LEFT ) . ";" |
| 792 | + // A truly binary version: |
| 793 | + // ? chr(wikiFuzz::randnum(0,255)) |
| 794 | + : chr( wikiFuzz::randnum( 126, 32 ) ); |
| 795 | + |
| 796 | + $length = wikiFuzz::randnum( 8 ); |
| 797 | + $thestring .= str_repeat ( $char, $length ); |
| 798 | + } |
| 799 | + } |
| 800 | + return $thestring; |
| 801 | + } |
| 802 | + |
| 803 | + /** |
| 804 | + ** Returns either random text, or random wiki syntax, or random data from "ints", |
| 805 | + ** or random data from "other". |
| 806 | + */ |
| 807 | + static private function makestring() { |
| 808 | + $what = wikiFuzz::randnum( 2 ); |
| 809 | + if ( $what == 0 ) { |
| 810 | + return wikiFuzz::randstring(); |
| 811 | + } |
| 812 | + elseif ( $what == 1 ) { |
| 813 | + return wikiFuzz::$ints[wikiFuzz::randnum( count( wikiFuzz::$ints ) - 1 )]; |
| 814 | + } |
| 815 | + else { |
| 816 | + return wikiFuzz::$other[wikiFuzz::randnum( count( wikiFuzz::$other ) - 1 )]; |
| 817 | + } |
| 818 | + } |
| 819 | + |
| 820 | + /** |
| 821 | + * Returns the matched character slash-escaped as in a C string |
| 822 | + * Helper for makeTitleSafe callback |
| 823 | + */ |
| 824 | + static private function stringEscape( $matches ) { |
| 825 | + return sprintf( "\\x%02x", ord( $matches[1] ) ); |
| 826 | + } |
| 827 | + |
| 828 | + /** |
| 829 | + ** Strips out the stuff that Mediawiki balks at in a page's title. |
| 830 | + ** Implementation copied/pasted from cleanupTable.inc & cleanupImages.php |
| 831 | + */ |
| 832 | + static public function makeTitleSafe( $str ) { |
| 833 | + $legalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF"; |
| 834 | + return preg_replace_callback( |
| 835 | + "/([^$legalTitleChars])/", 'wikiFuzz::stringEscape', |
| 836 | + $str ); |
| 837 | + } |
| 838 | + |
| 839 | + /** |
| 840 | + ** Returns a string of fuzz text. |
| 841 | + */ |
| 842 | + static private function loop() { |
| 843 | + switch ( wikiFuzz::randnum( 3 ) ) { |
| 844 | + case 1: // an opening tag, with parameters. |
| 845 | + $string = ""; |
| 846 | + $i = wikiFuzz::randnum( count( wikiFuzz::$types ) - 1 ); |
| 847 | + $t = wikiFuzz::$types[$i]; |
| 848 | + $arr = wikiFuzz::$data[$t]; |
| 849 | + $string .= "<" . $t . " "; |
| 850 | + $num_params = min( wikiFuzz::$maxparams, count( $arr ) ); |
| 851 | + for ( $z = 0; $z < $num_params; $z++ ) { |
| 852 | + $badparam = $arr[wikiFuzz::randnum( count( $arr ) - 1 )]; |
| 853 | + $badstring = wikiFuzz::makestring(); |
| 854 | + $string .= $badparam . "=" . wikiFuzz::getRandQuote() . $badstring . wikiFuzz::getRandQuote() . " "; |
| 855 | + } |
| 856 | + $string .= ">\n"; |
| 857 | + return $string; |
| 858 | + case 2: // a closing tag. |
| 859 | + $i = wikiFuzz::randnum( count( wikiFuzz::$types ) - 1 ); |
| 860 | + return "</" . wikiFuzz::$types[$i] . ">"; |
| 861 | + case 3: // a random string, between tags. |
| 862 | + return wikiFuzz::makeString(); |
| 863 | + } |
| 864 | + return ""; // catch-all, should never be called. |
| 865 | + } |
| 866 | + |
| 867 | + /** |
| 868 | + ** Returns one of the three styles of random quote: ', ", and nothing. |
| 869 | + */ |
| 870 | + static private function getRandQuote() { |
| 871 | + switch ( wikiFuzz::randnum( 3 ) ) { |
| 872 | + case 1 : return "'"; |
| 873 | + case 2 : return "\""; |
| 874 | + default: return ""; |
| 875 | + } |
| 876 | + } |
| 877 | + |
| 878 | + /** |
| 879 | + ** Returns fuzz text, with the parameter indicating approximately how many lines of text you want. |
| 880 | + */ |
| 881 | + static public function makeFuzz( $maxtypes = 2 ) { |
| 882 | + $page = ""; |
| 883 | + for ( $k = 0; $k < $maxtypes; $k++ ) { |
| 884 | + $page .= wikiFuzz::loop(); |
| 885 | + } |
| 886 | + return $page; |
| 887 | + } |
| 888 | +} |
| 889 | + |
| 890 | + |
| 891 | +// ////// MEDIAWIKI PAGES TO TEST, AND HOW TO TEST THEM /////// |
| 892 | + |
| 893 | +/** |
| 894 | + ** A page test has just these things: |
| 895 | + ** 1) Form parameters. |
| 896 | + ** 2) the URL we are going to test those parameters on. |
| 897 | + ** 3) Any cookies required for the test. |
| 898 | + ** 4) Whether Tidy should validate the page. Defaults to true, but can be turned off. |
| 899 | + ** Declared abstract because it should be extended by a class |
| 900 | + ** that supplies these parameters. |
| 901 | + */ |
| 902 | +abstract class pageTest { |
| 903 | + protected $params; |
| 904 | + protected $pagePath; |
| 905 | + protected $cookie = ""; |
| 906 | + protected $tidyValidate = true; |
| 907 | + |
| 908 | + public function getParams() { |
| 909 | + return $this->params; |
| 910 | + } |
| 911 | + |
| 912 | + public function getPagePath() { |
| 913 | + return $this->pagePath; |
| 914 | + } |
| 915 | + |
| 916 | + public function getCookie() { |
| 917 | + return $this->cookie; |
| 918 | + } |
| 919 | + |
| 920 | + public function tidyValidate() { |
| 921 | + return $this->tidyValidate; |
| 922 | + } |
| 923 | +} |
| 924 | + |
| 925 | + |
| 926 | +/** |
| 927 | + ** a page test for the "Edit" page. Tests Parser.php and Sanitizer.php. |
| 928 | + */ |
| 929 | +class editPageTest extends pageTest { |
| 930 | + function __construct() { |
| 931 | + $this->pagePath = "index.php?title=WIKIFUZZ"; |
| 932 | + |
| 933 | + $this->params = array ( |
| 934 | + "action" => "submit", |
| 935 | + "wpMinoredit" => wikiFuzz::makeFuzz( 2 ), |
| 936 | + "wpPreview" => wikiFuzz::makeFuzz( 2 ), |
| 937 | + "wpSection" => wikiFuzz::makeFuzz( 2 ), |
| 938 | + "wpEdittime" => wikiFuzz::makeFuzz( 2 ), |
| 939 | + "wpSummary" => wikiFuzz::makeFuzz( 2 ), |
| 940 | + "wpScrolltop" => wikiFuzz::makeFuzz( 2 ), |
| 941 | + "wpStarttime" => wikiFuzz::makeFuzz( 2 ), |
| 942 | + "wpAutoSummary" => wikiFuzz::makeFuzz( 2 ), |
| 943 | + "wpTextbox1" => wikiFuzz::makeFuzz( 40 ) // the main wiki text, need lots of this. |
| 944 | + ); |
| 945 | + |
| 946 | + // sometimes we don't want to specify certain parameters. |
| 947 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpSection"] ); |
| 948 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpEdittime"] ); |
| 949 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpSummary"] ); |
| 950 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpScrolltop"] ); |
| 951 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpStarttime"] ); |
| 952 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpAutoSummary"] ); |
| 953 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpTextbox1"] ); |
| 954 | + } |
| 955 | +} |
| 956 | + |
| 957 | + |
| 958 | +/** |
| 959 | + ** a page test for "Special:Listusers". |
| 960 | + */ |
| 961 | +class listusersTest extends pageTest { |
| 962 | + function __construct() { |
| 963 | + $this->pagePath = "index.php?title=Special:Listusers"; |
| 964 | + |
| 965 | + $this->params = array ( |
| 966 | + "title" => wikiFuzz::makeFuzz( 2 ), |
| 967 | + "group" => wikiFuzz::makeFuzz( 2 ), |
| 968 | + "username" => wikiFuzz::makeFuzz( 2 ), |
| 969 | + "Go" => wikiFuzz::makeFuzz( 2 ), |
| 970 | + "limit" => wikiFuzz::chooseInput( array( "0", "-1", "---'----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 971 | + "offset" => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", "81343242346234234", wikiFuzz::makeFuzz( 2 ) ) ) |
| 972 | + ); |
| 973 | + } |
| 974 | +} |
| 975 | + |
| 976 | + |
| 977 | +/** |
| 978 | + ** a page test for "Special:Search". |
| 979 | + */ |
| 980 | +class searchTest extends pageTest { |
| 981 | + function __construct() { |
| 982 | + $this->pagePath = "index.php?title=Special:Search"; |
| 983 | + |
| 984 | + $this->params = array ( |
| 985 | + "action" => "index.php?title=Special:Search", |
| 986 | + "ns0" => wikiFuzz::makeFuzz( 2 ), |
| 987 | + "ns1" => wikiFuzz::makeFuzz( 2 ), |
| 988 | + "ns2" => wikiFuzz::makeFuzz( 2 ), |
| 989 | + "ns3" => wikiFuzz::makeFuzz( 2 ), |
| 990 | + "ns4" => wikiFuzz::makeFuzz( 2 ), |
| 991 | + "ns5" => wikiFuzz::makeFuzz( 2 ), |
| 992 | + "ns6" => wikiFuzz::makeFuzz( 2 ), |
| 993 | + "ns7" => wikiFuzz::makeFuzz( 2 ), |
| 994 | + "ns8" => wikiFuzz::makeFuzz( 2 ), |
| 995 | + "ns9" => wikiFuzz::makeFuzz( 2 ), |
| 996 | + "ns10" => wikiFuzz::makeFuzz( 2 ), |
| 997 | + "ns11" => wikiFuzz::makeFuzz( 2 ), |
| 998 | + "ns12" => wikiFuzz::makeFuzz( 2 ), |
| 999 | + "ns13" => wikiFuzz::makeFuzz( 2 ), |
| 1000 | + "ns14" => wikiFuzz::makeFuzz( 2 ), |
| 1001 | + "ns15" => wikiFuzz::makeFuzz( 2 ), |
| 1002 | + "redirs" => wikiFuzz::makeFuzz( 2 ), |
| 1003 | + "search" => wikiFuzz::makeFuzz( 2 ), |
| 1004 | + "offset" => wikiFuzz::chooseInput( array( "", "0", "-1", "--------'-----0", "+1", "81343242346234234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1005 | + "fulltext" => wikiFuzz::chooseInput( array( "", "0", "1", "--------'-----0", "+1", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1006 | + "searchx" => wikiFuzz::chooseInput( array( "", "0", "1", "--------'-----0", "+1", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1007 | + ); |
| 1008 | + } |
| 1009 | +} |
| 1010 | + |
| 1011 | + |
| 1012 | +/** |
| 1013 | + ** a page test for "Special:Recentchanges". |
| 1014 | + */ |
| 1015 | +class recentchangesTest extends pageTest { |
| 1016 | + function __construct() { |
| 1017 | + $this->pagePath = "index.php?title=Special:Recentchanges"; |
| 1018 | + |
| 1019 | + $this->params = array ( |
| 1020 | + "action" => wikiFuzz::makeFuzz( 2 ), |
| 1021 | + "title" => wikiFuzz::makeFuzz( 2 ), |
| 1022 | + "namespace" => wikiFuzz::chooseInput( range( -1, 15 ) ), |
| 1023 | + "Go" => wikiFuzz::makeFuzz( 2 ), |
| 1024 | + "invert" => wikiFuzz::chooseInput( array( "-1", "---'----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1025 | + "hideanons" => wikiFuzz::chooseInput( array( "-1", "------'-------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1026 | + 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "---------'----0", "+1", "81340909772349234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1027 | + "days" => wikiFuzz::chooseInput( array( "-1", "----------'---0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1028 | + "hideminor" => wikiFuzz::chooseInput( array( "-1", "-----------'--0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1029 | + "hidebots" => wikiFuzz::chooseInput( array( "-1", "---------'----0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1030 | + "hideliu" => wikiFuzz::chooseInput( array( "-1", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1031 | + "hidepatrolled" => wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1032 | + "hidemyself" => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1033 | + 'categories_any' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1034 | + 'categories' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1035 | + 'feed' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1036 | + ); |
| 1037 | + } |
| 1038 | +} |
| 1039 | + |
| 1040 | + |
| 1041 | +/** |
| 1042 | + ** a page test for "Special:Prefixindex". |
| 1043 | + */ |
| 1044 | +class prefixindexTest extends pageTest { |
| 1045 | + function __construct() { |
| 1046 | + $this->pagePath = "index.php?title=Special:Prefixindex"; |
| 1047 | + |
| 1048 | + $this->params = array ( |
| 1049 | + "title" => "Special:Prefixindex", |
| 1050 | + "namespace" => wikiFuzz::randnum( 101, -10 ), |
| 1051 | + "Go" => wikiFuzz::makeFuzz( 2 ) |
| 1052 | + ); |
| 1053 | + |
| 1054 | + // sometimes we want 'prefix', sometimes we want 'from', and sometimes we want nothing. |
| 1055 | + if ( wikiFuzz::randnum( 3 ) == 0 ) { |
| 1056 | + $this->params["prefix"] = wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+++--+1", |
| 1057 | + wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) ); |
| 1058 | + } |
| 1059 | + if ( wikiFuzz::randnum( 3 ) == 0 ) { |
| 1060 | + $this->params["from"] = wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+++--+1", |
| 1061 | + wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) ); |
| 1062 | + } |
| 1063 | + } |
| 1064 | +} |
| 1065 | + |
| 1066 | + |
| 1067 | +/** |
| 1068 | + ** a page test for "Special:MIMEsearch". |
| 1069 | + */ |
| 1070 | +class mimeSearchTest extends pageTest { |
| 1071 | + function __construct() { |
| 1072 | + $this->pagePath = "index.php?title=Special:MIMEsearch"; |
| 1073 | + |
| 1074 | + $this->params = array ( |
| 1075 | + "action" => "index.php?title=Special:MIMEsearch", |
| 1076 | + "mime" => wikiFuzz::makeFuzz( 3 ), |
| 1077 | + 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "-------'------0", "+1", "81342321351235325", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1078 | + 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "-----'--------0", "+1", "81341231235365252234324", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1079 | + ); |
| 1080 | + } |
| 1081 | +} |
| 1082 | + |
| 1083 | + |
| 1084 | +/** |
| 1085 | + ** a page test for "Special:Log". |
| 1086 | + */ |
| 1087 | +class specialLogTest extends pageTest { |
| 1088 | + function __construct() { |
| 1089 | + $this->pagePath = "index.php?title=Special:Log"; |
| 1090 | + |
| 1091 | + $this->params = array ( |
| 1092 | + "type" => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1093 | + "par" => wikiFuzz::makeFuzz( 2 ), |
| 1094 | + "user" => wikiFuzz::makeFuzz( 2 ), |
| 1095 | + "page" => wikiFuzz::makeFuzz( 2 ), |
| 1096 | + "from" => wikiFuzz::makeFuzz( 2 ), |
| 1097 | + "until" => wikiFuzz::makeFuzz( 2 ), |
| 1098 | + "title" => wikiFuzz::makeFuzz( 2 ) |
| 1099 | + ); |
| 1100 | + } |
| 1101 | +} |
| 1102 | + |
| 1103 | + |
| 1104 | +/** |
| 1105 | + ** a page test for "Special:Userlogin", with a successful login. |
| 1106 | + */ |
| 1107 | +class successfulUserLoginTest extends pageTest { |
| 1108 | + function __construct() { |
| 1109 | + $this->pagePath = "index.php?title=Special:Userlogin&action=submitlogin&type=login&returnto=" . wikiFuzz::makeFuzz( 2 ); |
| 1110 | + |
| 1111 | + $this->params = array ( |
| 1112 | + "wpName" => USER_ON_WIKI, |
| 1113 | + // sometimes real password, sometimes not: |
| 1114 | + 'wpPassword' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), USER_PASSWORD ) ), |
| 1115 | + 'wpRemember' => wikiFuzz::makeFuzz( 2 ) |
| 1116 | + ); |
| 1117 | + |
| 1118 | + $this->cookie = "wikidb_session=" . wikiFuzz::chooseInput( array( "1" , wikiFuzz::makeFuzz( 2 ) ) ); |
| 1119 | + } |
| 1120 | +} |
| 1121 | + |
| 1122 | + |
| 1123 | +/** |
| 1124 | + ** a page test for "Special:Userlogin". |
| 1125 | + */ |
| 1126 | +class userLoginTest extends pageTest { |
| 1127 | + function __construct() { |
| 1128 | + |
| 1129 | + $this->pagePath = "index.php?title=Special:Userlogin"; |
| 1130 | + |
| 1131 | + $this->params = array ( |
| 1132 | + 'wpRetype' => wikiFuzz::makeFuzz( 2 ), |
| 1133 | + 'wpRemember' => wikiFuzz::makeFuzz( 2 ), |
| 1134 | + 'wpRealName' => wikiFuzz::makeFuzz( 2 ), |
| 1135 | + 'wpPassword' => wikiFuzz::makeFuzz( 2 ), |
| 1136 | + 'wpName' => wikiFuzz::makeFuzz( 2 ), |
| 1137 | + 'wpMailmypassword' => wikiFuzz::makeFuzz( 2 ), |
| 1138 | + 'wpLoginattempt' => wikiFuzz::makeFuzz( 2 ), |
| 1139 | + 'wpEmail' => wikiFuzz::makeFuzz( 2 ), |
| 1140 | + 'wpDomain' => wikiFuzz::chooseInput( array( "", "local", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1141 | + 'wpCreateaccountMail' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1142 | + 'wpCreateaccount' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1143 | + 'wpCookieCheck' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1144 | + 'type' => wikiFuzz::chooseInput( array( "signup", "login", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1145 | + 'returnto' => wikiFuzz::makeFuzz( 2 ), |
| 1146 | + 'action' => wikiFuzz::chooseInput( array( "", "submitlogin", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1147 | + ); |
| 1148 | + |
| 1149 | + $this->cookie = "wikidb_session=" . wikiFuzz::chooseInput( array( "1" , wikiFuzz::makeFuzz( 2 ) ) ); |
| 1150 | + } |
| 1151 | +} |
| 1152 | + |
| 1153 | + |
| 1154 | +/** |
| 1155 | + ** a page test for "Special:Ipblocklist" (also includes unblocking) |
| 1156 | + */ |
| 1157 | +class ipblocklistTest extends pageTest { |
| 1158 | + function __construct() { |
| 1159 | + $this->pagePath = "index.php?title=Special:Ipblocklist"; |
| 1160 | + |
| 1161 | + $this->params = array ( |
| 1162 | + 'wpUnblockAddress' => wikiFuzz::makeFuzz( 2 ), |
| 1163 | + 'ip' => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ), |
| 1164 | + // something like an IP address, sometimes invalid: |
| 1165 | + ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "." |
| 1166 | + . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ), |
| 1167 | + 'id' => wikiFuzz::makeFuzz( 2 ), |
| 1168 | + 'wpUnblockReason' => wikiFuzz::makeFuzz( 2 ), |
| 1169 | + 'action' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "success", "submit", "unblock" ) ), |
| 1170 | + 'wpEditToken' => wikiFuzz::makeFuzz( 2 ), |
| 1171 | + 'wpBlock' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "" ) ), |
| 1172 | + 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", |
| 1173 | + "09700982312351132098234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1174 | + 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", |
| 1175 | + "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1176 | + ); |
| 1177 | + |
| 1178 | + // sometimes we don't want to specify certain parameters. |
| 1179 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] ); |
| 1180 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["ip"] ); |
| 1181 | + if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["id"] ); |
| 1182 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpUnblockAddress"] ); |
| 1183 | + } |
| 1184 | +} |
| 1185 | + |
| 1186 | + |
| 1187 | +/** |
| 1188 | + ** a page test for "Special:Newimages". |
| 1189 | + */ |
| 1190 | +class newImagesTest extends pageTest { |
| 1191 | + function __construct() { |
| 1192 | + $this->pagePath = "index.php?title=Special:Newimages"; |
| 1193 | + |
| 1194 | + $this->params = array ( |
| 1195 | + 'hidebots' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "1", "", "-1" ) ), |
| 1196 | + 'wpIlMatch' => wikiFuzz::makeFuzz( 2 ), |
| 1197 | + 'until' => wikiFuzz::makeFuzz( 2 ), |
| 1198 | + 'from' => wikiFuzz::makeFuzz( 2 ) |
| 1199 | + ); |
| 1200 | + |
| 1201 | + // sometimes we don't want to specify certain parameters. |
| 1202 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["until"] ); |
| 1203 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["from"] ); |
| 1204 | + } |
| 1205 | +} |
| 1206 | + |
| 1207 | + |
| 1208 | +/** |
| 1209 | + ** a page test for the "Special:Imagelist" page. |
| 1210 | + */ |
| 1211 | +class imagelistTest extends pageTest { |
| 1212 | + function __construct() { |
| 1213 | + $this->pagePath = "index.php?title=Special:Imagelist"; |
| 1214 | + |
| 1215 | + $this->params = array ( |
| 1216 | + 'sort' => wikiFuzz::chooseInput( array( "bysize", "byname" , "bydate", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1217 | + 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", "09700982312351132098234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1218 | + 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1219 | + 'wpIlMatch' => wikiFuzz::makeFuzz( 2 ) |
| 1220 | + ); |
| 1221 | + } |
| 1222 | +} |
| 1223 | + |
| 1224 | + |
| 1225 | +/** |
| 1226 | + ** a page test for "Special:Export". |
| 1227 | + */ |
| 1228 | +class specialExportTest extends pageTest { |
| 1229 | + function __construct() { |
| 1230 | + $this->pagePath = "index.php?title=Special:Export"; |
| 1231 | + |
| 1232 | + $this->params = array ( |
| 1233 | + 'action' => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1234 | + 'pages' => wikiFuzz::makeFuzz( 2 ), |
| 1235 | + 'curonly' => wikiFuzz::chooseInput( array( "", "0", "-1", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1236 | + 'listauthors' => wikiFuzz::chooseInput( array( "", "0", "-1", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1237 | + 'history' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1238 | + |
| 1239 | + ); |
| 1240 | + |
| 1241 | + // For the time being, need to disable "submit" action as Tidy barfs on MediaWiki's XML export. |
| 1242 | + if ( $this->params['action'] == 'submit' ) $this->params['action'] = ''; |
| 1243 | + |
| 1244 | + // Sometimes remove the history field. |
| 1245 | + if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["history"] ); |
| 1246 | + |
| 1247 | + // page does not produce HTML. |
| 1248 | + $this->tidyValidate = false; |
| 1249 | + } |
| 1250 | +} |
| 1251 | + |
| 1252 | + |
| 1253 | +/** |
| 1254 | + ** a page test for "Special:Booksources". |
| 1255 | + */ |
| 1256 | +class specialBooksourcesTest extends pageTest { |
| 1257 | + function __construct() { |
| 1258 | + $this->pagePath = "index.php?title=Special:Booksources"; |
| 1259 | + |
| 1260 | + $this->params = array ( |
| 1261 | + 'go' => wikiFuzz::makeFuzz( 2 ), |
| 1262 | + // ISBN codes have to contain some semi-numeric stuff or will be ignored: |
| 1263 | + 'isbn' => "0X0" . wikiFuzz::makeFuzz( 2 ) |
| 1264 | + ); |
| 1265 | + } |
| 1266 | +} |
| 1267 | + |
| 1268 | + |
| 1269 | +/** |
| 1270 | + ** a page test for "Special:Allpages". |
| 1271 | + */ |
| 1272 | +class specialAllpagesTest extends pageTest { |
| 1273 | + function __construct() { |
| 1274 | + $this->pagePath = "index.php?title=Special%3AAllpages"; |
| 1275 | + |
| 1276 | + $this->params = array ( |
| 1277 | + 'from' => wikiFuzz::makeFuzz( 2 ), |
| 1278 | + 'namespace' => wikiFuzz::chooseInput( range( -1, 15 ) ), |
| 1279 | + 'go' => wikiFuzz::makeFuzz( 2 ) |
| 1280 | + ); |
| 1281 | + } |
| 1282 | +} |
| 1283 | + |
| 1284 | + |
| 1285 | +/** |
| 1286 | + ** a page test for the page History. |
| 1287 | + */ |
| 1288 | +class pageHistoryTest extends pageTest { |
| 1289 | + function __construct() { |
| 1290 | + $this->pagePath = "index.php?title=Main_Page&action=history"; |
| 1291 | + |
| 1292 | + $this->params = array ( |
| 1293 | + 'limit' => wikiFuzz::chooseInput( array( "-1", "0", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1294 | + 'offset' => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1295 | + "go" => wikiFuzz::chooseInput( array( "first", "last", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1296 | + "dir" => wikiFuzz::chooseInput( array( "prev", "next", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1297 | + "diff" => wikiFuzz::chooseInput( array( "-1", "--------'-----0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1298 | + "oldid" => wikiFuzz::chooseInput( array( "prev", "-1", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1299 | + "feed" => wikiFuzz::makeFuzz( 2 ) |
| 1300 | + ); |
| 1301 | + } |
| 1302 | +} |
| 1303 | + |
| 1304 | + |
| 1305 | +/** |
| 1306 | + ** a page test for the Special:Contributions". |
| 1307 | + */ |
| 1308 | +class contributionsTest extends pageTest { |
| 1309 | + function __construct() { |
| 1310 | + $this->pagePath = "index.php?title=Special:Contributions/" . USER_ON_WIKI; |
| 1311 | + |
| 1312 | + $this->params = array ( |
| 1313 | + 'target' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "newbies", USER_ON_WIKI ) ), |
| 1314 | + 'namespace' => wikiFuzz::chooseInput( array( -1, 15, 1, wikiFuzz::makeFuzz( 2 ) ) ), |
| 1315 | + 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "982342131232131231241", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1316 | + 'bot' => wikiFuzz::chooseInput( array( "", "-1", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1317 | + 'go' => wikiFuzz::chooseInput( array( "-1", 'prev', 'next', wikiFuzz::makeFuzz( 2 ) ) ) |
| 1318 | + ); |
| 1319 | + } |
| 1320 | +} |
| 1321 | + |
| 1322 | + |
| 1323 | +/** |
| 1324 | + ** a page test for viewing a normal page, whilst posting various params. |
| 1325 | + */ |
| 1326 | +class viewPageTest extends pageTest { |
| 1327 | + function __construct() { |
| 1328 | + $this->pagePath = "index.php?title=Main_Page"; |
| 1329 | + |
| 1330 | + $this->params = array ( |
| 1331 | + "useskin" => wikiFuzz::chooseInput( array( "chick", "cologneblue", "myskin", |
| 1332 | + "nostalgia", "simple", "standard", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1333 | + "uselang" => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), |
| 1334 | + "ab", "af", "an", "ar", "arc", "as", "ast", "av", "ay", "az", "ba", |
| 1335 | + "bat-smg", "be", "bg", "bm", "bn", "bo", "bpy", "br", "bs", "ca", |
| 1336 | + "ce", "cs", "csb", "cv", "cy", "da", "de", "dv", "dz", "el", "en", |
| 1337 | + "eo", "es", "et", "eu", "fa", "fi", "fo", "fr", "fur", "fy", "ga", |
| 1338 | + "gn", "gsw", "gu", "he", "hi", "hr", "hu", "ia", "id", "ii", "is", |
| 1339 | + "it", "ja", "jv", "ka", "km", "kn", "ko", "ks", "ku", "kv", "la", |
| 1340 | + "li", "lo", "lt", "lv", "mk", "ml", "ms", "nah", "nap", "nds", |
| 1341 | + "nds-nl", "nl", "nn", "no", "non", "nv", "oc", "or", "os", "pa", |
| 1342 | + "pl", "pms", "ps", "pt", "pt-br", "qu", "rmy", "ro", "ru", "sc", |
| 1343 | + "sd", "sk", "sl", "sq", "sr", "sr-ec", "sr-el", |
| 1344 | + "su", "sv", "ta", "te", "th", "tr", "tt", "ty", "tyv", "udm", |
| 1345 | + "ug", "uk", "ur", "utf8", "vec", "vi", "wa", "xal", "yi", "za", |
| 1346 | + "zh", "zh-cn", "zh-hk", "zh-sg", "zh-tw", "zh-tw" ) ), |
| 1347 | + "returnto" => wikiFuzz::makeFuzz( 2 ), |
| 1348 | + "feed" => wikiFuzz::chooseInput( array( "atom", "rss", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1349 | + "rcid" => wikiFuzz::makeFuzz( 2 ), |
| 1350 | + "action" => wikiFuzz::chooseInput( array( "view", "raw", "render", wikiFuzz::makeFuzz( 2 ), "markpatrolled" ) ), |
| 1351 | + "printable" => wikiFuzz::makeFuzz( 2 ), |
| 1352 | + "oldid" => wikiFuzz::makeFuzz( 2 ), |
| 1353 | + "redirect" => wikiFuzz::makeFuzz( 2 ), |
| 1354 | + "diff" => wikiFuzz::makeFuzz( 2 ), |
| 1355 | + "search" => wikiFuzz::makeFuzz( 2 ), |
| 1356 | + "rdfrom" => wikiFuzz::makeFuzz( 2 ), // things from Article.php from here on: |
| 1357 | + "token" => wikiFuzz::makeFuzz( 2 ), |
| 1358 | + "tbid" => wikiFuzz::makeFuzz( 2 ), |
| 1359 | + "action" => wikiFuzz::chooseInput( array( "purge", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1360 | + "wpReason" => wikiFuzz::makeFuzz( 2 ), |
| 1361 | + "wpEditToken" => wikiFuzz::makeFuzz( 2 ), |
| 1362 | + "from" => wikiFuzz::makeFuzz( 2 ), |
| 1363 | + "bot" => wikiFuzz::makeFuzz( 2 ), |
| 1364 | + "summary" => wikiFuzz::makeFuzz( 2 ), |
| 1365 | + "direction" => wikiFuzz::chooseInput( array( "next", "prev", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1366 | + "section" => wikiFuzz::makeFuzz( 2 ), |
| 1367 | + "preload" => wikiFuzz::makeFuzz( 2 ), |
| 1368 | + |
| 1369 | + ); |
| 1370 | + |
| 1371 | + // Tidy does not know how to valid atom or rss, so exclude from testing for the time being. |
| 1372 | + if ( $this->params["feed"] == "atom" ) { unset( $this->params["feed"] ); } |
| 1373 | + else if ( $this->params["feed"] == "rss" ) { unset( $this->params["feed"] ); } |
| 1374 | + |
| 1375 | + // Raw pages cannot really be validated |
| 1376 | + if ( $this->params["action"] == "raw" ) unset( $this->params["action"] ); |
| 1377 | + |
| 1378 | + // sometimes we don't want to specify certain parameters. |
| 1379 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["rcid"] ); |
| 1380 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["diff"] ); |
| 1381 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["rdfrom"] ); |
| 1382 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["oldid"] ); |
| 1383 | + |
| 1384 | + // usually don't want action == purge. |
| 1385 | + if ( wikiFuzz::randnum( 6 ) > 1 ) unset( $this->params["action"] ); |
| 1386 | + } |
| 1387 | +} |
| 1388 | + |
| 1389 | + |
| 1390 | +/** |
| 1391 | + ** a page test for "Special:Allmessages". |
| 1392 | + */ |
| 1393 | +class specialAllmessagesTest extends pageTest { |
| 1394 | + function __construct() { |
| 1395 | + $this->pagePath = "index.php?title=Special:Allmessages"; |
| 1396 | + |
| 1397 | + // only really has one parameter |
| 1398 | + $this->params = array ( |
| 1399 | + "ot" => wikiFuzz::chooseInput( array( "php", "html", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1400 | + ); |
| 1401 | + } |
| 1402 | +} |
| 1403 | + |
| 1404 | +/** |
| 1405 | + ** a page test for "Special:Newpages". |
| 1406 | + */ |
| 1407 | +class specialNewpagesPageTest extends pageTest { |
| 1408 | + function __construct() { |
| 1409 | + $this->pagePath = "index.php?title=Special:Newpages"; |
| 1410 | + |
| 1411 | + $this->params = array ( |
| 1412 | + "namespace" => wikiFuzz::chooseInput( range( -1, 15 ) ), |
| 1413 | + "feed" => wikiFuzz::chooseInput( array( "atom", "rss", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1414 | + 'limit' => wikiFuzz::chooseInput( array( "-1", "0", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1415 | + 'offset' => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1416 | + ); |
| 1417 | + |
| 1418 | + // Tidy does not know how to valid atom or rss, so exclude from testing for the time being. |
| 1419 | + if ( $this->params["feed"] == "atom" ) { unset( $this->params["feed"] ); } |
| 1420 | + else if ( $this->params["feed"] == "rss" ) { unset( $this->params["feed"] ); } |
| 1421 | + } |
| 1422 | +} |
| 1423 | + |
| 1424 | +/** |
| 1425 | + ** a page test for "redirect.php" |
| 1426 | + */ |
| 1427 | +class redirectTest extends pageTest { |
| 1428 | + function __construct() { |
| 1429 | + $this->pagePath = "redirect.php"; |
| 1430 | + |
| 1431 | + $this->params = array ( |
| 1432 | + "wpDropdown" => wikiFuzz::makeFuzz( 2 ) |
| 1433 | + ); |
| 1434 | + |
| 1435 | + // sometimes we don't want to specify certain parameters. |
| 1436 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpDropdown"] ); |
| 1437 | + } |
| 1438 | +} |
| 1439 | + |
| 1440 | + |
| 1441 | +/** |
| 1442 | + ** a page test for "Special:Confirmemail" |
| 1443 | + */ |
| 1444 | +class confirmEmail extends pageTest { |
| 1445 | + function __construct() { |
| 1446 | + // sometimes we send a bogus confirmation code, and sometimes we don't. |
| 1447 | + $this->pagePath = "index.php?title=Special:Confirmemail" . wikiFuzz::chooseInput( array( "", "/" . wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 1 ) ) ) ); |
| 1448 | + |
| 1449 | + $this->params = array ( |
| 1450 | + "token" => wikiFuzz::makeFuzz( 2 ) |
| 1451 | + ); |
| 1452 | + } |
| 1453 | +} |
| 1454 | + |
| 1455 | + |
| 1456 | +/** |
| 1457 | + ** a page test for "Special:Watchlist" |
| 1458 | + ** Note: this test would be better if we were logged in. |
| 1459 | + */ |
| 1460 | +class watchlistTest extends pageTest { |
| 1461 | + function __construct() { |
| 1462 | + $this->pagePath = "index.php?title=Special:Watchlist"; |
| 1463 | + |
| 1464 | + $this->params = array ( |
| 1465 | + "remove" => wikiFuzz::chooseInput( array( "Remove checked items from watchlist", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1466 | + 'days' => wikiFuzz::chooseInput( array( 0, -1, -230, "--", 3, 9, wikiFuzz::makeFuzz( 2 ) ) ), |
| 1467 | + 'hideOwn' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1468 | + 'hideBots' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1469 | + 'namespace' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1470 | + 'action' => wikiFuzz::chooseInput( array( "submit", "clear", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1471 | + 'id[]' => wikiFuzz::makeFuzz( 2 ), |
| 1472 | + 'edit' => wikiFuzz::makeFuzz( 2 ), |
| 1473 | + 'token' => wikiFuzz::chooseInput( array( "", "1243213", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1474 | + ); |
| 1475 | + |
| 1476 | + // sometimes we specifiy "reset", and sometimes we don't. |
| 1477 | + if ( wikiFuzz::randnum( 3 ) == 0 ) $this->params["reset"] = wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ); |
| 1478 | + } |
| 1479 | +} |
| 1480 | + |
| 1481 | + |
| 1482 | +/** |
| 1483 | + ** a page test for "Special:Blockme" |
| 1484 | + */ |
| 1485 | +class specialBlockmeTest extends pageTest { |
| 1486 | + function __construct() { |
| 1487 | + $this->pagePath = "index.php?title=Special:Blockme"; |
| 1488 | + |
| 1489 | + $this->params = array ( ); |
| 1490 | + |
| 1491 | + // sometimes we specify "ip", and sometimes we don't. |
| 1492 | + if ( wikiFuzz::randnum( 1 ) == 0 ) { |
| 1493 | + $this->params["ip"] = wikiFuzz::chooseInput( array( "10.12.41.213", wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) ); |
| 1494 | + } |
| 1495 | + } |
| 1496 | +} |
| 1497 | + |
| 1498 | + |
| 1499 | +/** |
| 1500 | + ** a page test for "Special:Movepage" |
| 1501 | + */ |
| 1502 | +class specialMovePage extends pageTest { |
| 1503 | + function __construct() { |
| 1504 | + $this->pagePath = "index.php?title=Special:Movepage"; |
| 1505 | + |
| 1506 | + $this->params = array ( |
| 1507 | + "action" => wikiFuzz::chooseInput( array( "success", "submit", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1508 | + 'wpEditToken' => wikiFuzz::chooseInput( array( '', 0, 34987987, wikiFuzz::makeFuzz( 2 ) ) ), |
| 1509 | + 'target' => wikiFuzz::chooseInput( array( "x", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ) ) ), |
| 1510 | + 'wpOldTitle' => wikiFuzz::chooseInput( array( "z", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ), wikiFuzz::makeFuzz( 2 ) ) ), |
| 1511 | + 'wpNewTitle' => wikiFuzz::chooseInput( array( "y", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ), wikiFuzz::makeFuzz( 2 ) ) ), |
| 1512 | + 'wpReason' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ) ) ), |
| 1513 | + 'wpMovetalk' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1514 | + 'wpDeleteAndMove' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1515 | + 'wpConfirm' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1516 | + 'talkmoved' => wikiFuzz::chooseInput( array( "1", wikiFuzz::makeFuzz( 2 ), "articleexists", 'notalkpage' ) ), |
| 1517 | + 'oldtitle' => wikiFuzz::makeFuzz( 2 ), |
| 1518 | + 'newtitle' => wikiFuzz::makeFuzz( 2 ), |
| 1519 | + 'wpMovetalk' => wikiFuzz::chooseInput( array( "1", "0", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1520 | + ); |
| 1521 | + |
| 1522 | + // sometimes we don't want to specify certain parameters. |
| 1523 | + if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["wpEditToken"] ); |
| 1524 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["target"] ); |
| 1525 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpNewTitle"] ); |
| 1526 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpReason"] ); |
| 1527 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpOldTitle"] ); |
| 1528 | + } |
| 1529 | +} |
| 1530 | + |
| 1531 | + |
| 1532 | +/** |
| 1533 | + ** a page test for "Special:Undelete" |
| 1534 | + */ |
| 1535 | +class specialUndeletePageTest extends pageTest { |
| 1536 | + function __construct() { |
| 1537 | + $this->pagePath = "index.php?title=Special:Undelete"; |
| 1538 | + |
| 1539 | + $this->params = array ( |
| 1540 | + "action" => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1541 | + 'wpEditToken' => wikiFuzz::chooseInput( array( '', 0, 34987987, wikiFuzz::makeFuzz( 2 ) ) ), |
| 1542 | + 'target' => wikiFuzz::chooseInput( array( "x", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ) ) ), |
| 1543 | + 'timestamp' => wikiFuzz::chooseInput( array( "125223", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1544 | + 'file' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1545 | + 'restore' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1546 | + 'preview' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1547 | + 'wpComment' => wikiFuzz::makeFuzz( 2 ) |
| 1548 | + ); |
| 1549 | + |
| 1550 | + // sometimes we don't want to specify certain parameters. |
| 1551 | + if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["wpEditToken"] ); |
| 1552 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["target"] ); |
| 1553 | + if ( wikiFuzz::randnum( 1 ) == 0 ) unset( $this->params["restore"] ); |
| 1554 | + if ( wikiFuzz::randnum( 1 ) == 0 ) unset( $this->params["preview"] ); |
| 1555 | + } |
| 1556 | +} |
| 1557 | + |
| 1558 | + |
| 1559 | +/** |
| 1560 | + ** a page test for "Special:Unlockdb" |
| 1561 | + */ |
| 1562 | +class specialUnlockdbPageTest extends pageTest { |
| 1563 | + function __construct() { |
| 1564 | + $this->pagePath = "index.php?title=Special:Unlockdb"; |
| 1565 | + |
| 1566 | + $this->params = array ( |
| 1567 | + "action" => wikiFuzz::chooseInput( array( "submit", "success", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1568 | + 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1569 | + 'wpLockConfirm' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1570 | + ); |
| 1571 | + |
| 1572 | + // sometimes we don't want to specify certain parameters. |
| 1573 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpEditToken"] ); |
| 1574 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] ); |
| 1575 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpLockConfirm"] ); |
| 1576 | + } |
| 1577 | +} |
| 1578 | + |
| 1579 | + |
| 1580 | +/** |
| 1581 | + ** a page test for "Special:Lockdb" |
| 1582 | + */ |
| 1583 | +class specialLockdbPageTest extends pageTest { |
| 1584 | + function __construct() { |
| 1585 | + $this->pagePath = "index.php?title=Special:Lockdb"; |
| 1586 | + |
| 1587 | + $this->params = array ( |
| 1588 | + "action" => wikiFuzz::chooseInput( array( "submit", "success", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1589 | + 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1590 | + 'wpLockReason' => wikiFuzz::makeFuzz( 2 ), |
| 1591 | + 'wpLockConfirm' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1592 | + ); |
| 1593 | + |
| 1594 | + // sometimes we don't want to specify certain parameters. |
| 1595 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpEditToken"] ); |
| 1596 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] ); |
| 1597 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpLockConfirm"] ); |
| 1598 | + } |
| 1599 | +} |
| 1600 | + |
| 1601 | + |
| 1602 | +/** |
| 1603 | + ** a page test for "Special:Userrights" |
| 1604 | + */ |
| 1605 | +class specialUserrights extends pageTest { |
| 1606 | + function __construct() { |
| 1607 | + $this->pagePath = "index.php?title=Special:Userrights"; |
| 1608 | + |
| 1609 | + $this->params = array ( |
| 1610 | + 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1611 | + 'user-editname' => wikiFuzz::chooseInput( array( "Nickj2", "Nickj2\n<xyz>", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1612 | + 'ssearchuser' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1613 | + 'saveusergroups' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ), "Save User Groups" ), |
| 1614 | + 'member[]' => wikiFuzz::chooseInput( array( "0", "bot", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1615 | + "available[]" => wikiFuzz::chooseInput( array( "0", "sysop", "bureaucrat", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1616 | + ); |
| 1617 | + |
| 1618 | + // sometimes we don't want to specify certain parameters. |
| 1619 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['ssearchuser'] ); |
| 1620 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['saveusergroups'] ); |
| 1621 | + } |
| 1622 | +} |
| 1623 | + |
| 1624 | + |
| 1625 | +/** |
| 1626 | + ** a test for page protection and unprotection. |
| 1627 | + */ |
| 1628 | +class pageProtectionForm extends pageTest { |
| 1629 | + function __construct() { |
| 1630 | + $this->pagePath = "index.php?title=Main_Page"; |
| 1631 | + |
| 1632 | + $this->params = array ( |
| 1633 | + "action" => "protect", |
| 1634 | + 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1635 | + "mwProtect-level-edit" => wikiFuzz::chooseInput( array( '', 'autoconfirmed', 'sysop', wikiFuzz::makeFuzz( 2 ) ) ), |
| 1636 | + "mwProtect-level-move" => wikiFuzz::chooseInput( array( '', 'autoconfirmed', 'sysop', wikiFuzz::makeFuzz( 2 ) ) ), |
| 1637 | + "mwProtectUnchained" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1638 | + 'mwProtect-reason' => wikiFuzz::chooseInput( array( "because it was there", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1639 | + ); |
| 1640 | + |
| 1641 | + |
| 1642 | + // sometimes we don't want to specify certain parameters. |
| 1643 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["mwProtectUnchained"] ); |
| 1644 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['mwProtect-reason'] ); |
| 1645 | + } |
| 1646 | +} |
| 1647 | + |
| 1648 | + |
| 1649 | +/** |
| 1650 | + ** a page test for "Special:Blockip". |
| 1651 | + */ |
| 1652 | +class specialBlockip extends pageTest { |
| 1653 | + function __construct() { |
| 1654 | + $this->pagePath = "index.php?title=Special:Blockip"; |
| 1655 | + |
| 1656 | + $this->params = array ( |
| 1657 | + "action" => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1658 | + 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1659 | + "wpBlockAddress" => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ), |
| 1660 | + // something like an IP address, sometimes invalid: |
| 1661 | + ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "." |
| 1662 | + . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ), |
| 1663 | + "ip" => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ), |
| 1664 | + // something like an IP address, sometimes invalid: |
| 1665 | + ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "." |
| 1666 | + . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ), |
| 1667 | + "wpBlockOther" => wikiFuzz::chooseInput( array( '', 'Nickj2', wikiFuzz::makeFuzz( 2 ) ) ), |
| 1668 | + "wpBlockExpiry" => wikiFuzz::chooseInput( array( "other", "2 hours", "1 day", "3 days", "1 week", "2 weeks", |
| 1669 | + "1 month", "3 months", "6 months", "1 year", "infinite", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1670 | + "wpBlockReason" => wikiFuzz::chooseInput( array( "because it was there", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1671 | + "wpAnonOnly" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1672 | + "wpCreateAccount" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1673 | + "wpBlock" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ) |
| 1674 | + ); |
| 1675 | + |
| 1676 | + // sometimes we don't want to specify certain parameters. |
| 1677 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockOther"] ); |
| 1678 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockExpiry"] ); |
| 1679 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockReason"] ); |
| 1680 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpAnonOnly"] ); |
| 1681 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpCreateAccount"] ); |
| 1682 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockAddress"] ); |
| 1683 | + if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["ip"] ); |
| 1684 | + } |
| 1685 | +} |
| 1686 | + |
| 1687 | + |
| 1688 | +/** |
| 1689 | + ** a test for the imagepage. |
| 1690 | + */ |
| 1691 | +class imagepageTest extends pageTest { |
| 1692 | + function __construct() { |
| 1693 | + $this->pagePath = "index.php?title=Image:Small-email.png"; |
| 1694 | + |
| 1695 | + $this->params = array ( |
| 1696 | + "image" => wikiFuzz::chooseInput( array( "Small-email.png", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1697 | + "wpReason" => wikiFuzz::makeFuzz( 2 ), |
| 1698 | + "oldimage" => wikiFuzz::chooseInput( array( "Small-email.png", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1699 | + "wpEditToken" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1700 | + ); |
| 1701 | + |
| 1702 | + // sometimes we don't want to specify certain parameters. |
| 1703 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["image"] ); |
| 1704 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpReason"] ); |
| 1705 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldimage"] ); |
| 1706 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpEditToken"] ); |
| 1707 | + } |
| 1708 | +} |
| 1709 | + |
| 1710 | + |
| 1711 | +/** |
| 1712 | + ** a test for page deletion form. |
| 1713 | + */ |
| 1714 | +class pageDeletion extends pageTest { |
| 1715 | + function __construct() { |
| 1716 | + $this->pagePath = "index.php?title=Main_Page&action=delete"; |
| 1717 | + |
| 1718 | + $this->params = array ( |
| 1719 | + "wpEditToken" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1720 | + "wpReason" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1721 | + "wpConfirm" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1722 | + ); |
| 1723 | + |
| 1724 | + // sometimes we don't want to specify certain parameters. |
| 1725 | + if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpReason"] ); |
| 1726 | + if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpEditToken"] ); |
| 1727 | + if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpConfirm"] ); |
| 1728 | + } |
| 1729 | +} |
| 1730 | + |
| 1731 | + |
| 1732 | + |
| 1733 | +/** |
| 1734 | + ** a test for Revision Deletion. |
| 1735 | + */ |
| 1736 | +class specialRevisionDeletePageTest extends pageTest { |
| 1737 | + function __construct() { |
| 1738 | + $this->pagePath = "index.php?title=Special:Revisiondelete"; |
| 1739 | + |
| 1740 | + $this->params = array ( |
| 1741 | + "target" => wikiFuzz::chooseInput( array( "Main Page", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1742 | + "oldid" => wikiFuzz::makeFuzz( 2 ), |
| 1743 | + "oldid[]" => wikiFuzz::makeFuzz( 2 ), |
| 1744 | + "wpReason" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1745 | + "revdelete-hide-text" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1746 | + "revdelete-hide-comment" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1747 | + "revdelete-hide-user" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1748 | + "revdelete-hide-restricted" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1749 | + ); |
| 1750 | + |
| 1751 | + // sometimes we don't want to specify certain parameters. |
| 1752 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["target"] ); |
| 1753 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldid"] ); |
| 1754 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldid[]"] ); |
| 1755 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpReason"] ); |
| 1756 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-text"] ); |
| 1757 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-comment"] ); |
| 1758 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-user"] ); |
| 1759 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-restricted"] ); |
| 1760 | + } |
| 1761 | +} |
| 1762 | + |
| 1763 | + |
| 1764 | +/** |
| 1765 | + ** a test for Special:Import. |
| 1766 | + */ |
| 1767 | +class specialImportPageTest extends pageTest { |
| 1768 | + function __construct() { |
| 1769 | + $this->pagePath = "index.php?title=Special:Import"; |
| 1770 | + |
| 1771 | + $this->params = array ( |
| 1772 | + "action" => "submit", |
| 1773 | + "source" => wikiFuzz::chooseInput( array( "upload", "interwiki", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1774 | + "MAX_FILE_SIZE" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1775 | + "xmlimport" => wikiFuzz::chooseInput( array( "/var/www/hosts/mediawiki/wiki/AdminSettings.php", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1776 | + "namespace" => wikiFuzz::chooseInput( array( wikiFuzz::randnum( 30, -6 ), wikiFuzz::makeFuzz( 2 ) ) ), |
| 1777 | + "interwiki" => wikiFuzz::makeFuzz( 2 ), |
| 1778 | + "interwikiHistory" => wikiFuzz::makeFuzz( 2 ), |
| 1779 | + "frompage" => wikiFuzz::makeFuzz( 2 ), |
| 1780 | + ); |
| 1781 | + |
| 1782 | + // sometimes we don't want to specify certain parameters. |
| 1783 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["action"] ); |
| 1784 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["source"] ); |
| 1785 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["MAX_FILE_SIZE"] ); |
| 1786 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["xmlimport"] ); |
| 1787 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["interwiki"] ); |
| 1788 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["interwikiHistory"] ); |
| 1789 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["frompage"] ); |
| 1790 | + |
| 1791 | + // Note: Need to do a file upload to fully test this Special page. |
| 1792 | + } |
| 1793 | +} |
| 1794 | + |
| 1795 | + |
| 1796 | +/** |
| 1797 | + ** a test for thumb.php |
| 1798 | + */ |
| 1799 | +class thumbTest extends pageTest { |
| 1800 | + function __construct() { |
| 1801 | + $this->pagePath = "thumb.php"; |
| 1802 | + |
| 1803 | + $this->params = array ( |
| 1804 | + "f" => wikiFuzz::chooseInput( array( "..", "\\", "small-email.png", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1805 | + "w" => wikiFuzz::chooseInput( array( "80", wikiFuzz::randnum( 6000, -200 ), wikiFuzz::makeFuzz( 2 ) ) ), |
| 1806 | + "r" => wikiFuzz::chooseInput( array( "0", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1807 | + ); |
| 1808 | + |
| 1809 | + // sometimes we don't want to specify certain parameters. |
| 1810 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["f"] ); |
| 1811 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["w"] ); |
| 1812 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["r"] ); |
| 1813 | + } |
| 1814 | +} |
| 1815 | + |
| 1816 | + |
| 1817 | +/** |
| 1818 | + ** a test for trackback.php |
| 1819 | + */ |
| 1820 | +class trackbackTest extends pageTest { |
| 1821 | + function __construct() { |
| 1822 | + $this->pagePath = "trackback.php"; |
| 1823 | + |
| 1824 | + $this->params = array ( |
| 1825 | + "url" => wikiFuzz::makeFuzz( 2 ), |
| 1826 | + "blog_name" => wikiFuzz::chooseInput( array( "80", wikiFuzz::randnum( 6000, -200 ), wikiFuzz::makeFuzz( 2 ) ) ), |
| 1827 | + "article" => wikiFuzz::chooseInput( array( "Main Page", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1828 | + "title" => wikiFuzz::chooseInput( array( "Main Page", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1829 | + "excerpt" => wikiFuzz::makeFuzz( 2 ), |
| 1830 | + ); |
| 1831 | + |
| 1832 | + // sometimes we don't want to specify certain parameters. |
| 1833 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["title"] ); |
| 1834 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["excerpt"] ); |
| 1835 | + |
| 1836 | + // page does not produce HTML. |
| 1837 | + $this->tidyValidate = false; |
| 1838 | + } |
| 1839 | +} |
| 1840 | + |
| 1841 | + |
| 1842 | +/** |
| 1843 | + ** a test for profileinfo.php |
| 1844 | + */ |
| 1845 | +class profileInfo extends pageTest { |
| 1846 | + function __construct() { |
| 1847 | + $this->pagePath = "profileinfo.php"; |
| 1848 | + |
| 1849 | + $this->params = array ( |
| 1850 | + "expand" => wikiFuzz::makeFuzz( 2 ), |
| 1851 | + "sort" => wikiFuzz::chooseInput( array( "time", "count", "name", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1852 | + "filter" => wikiFuzz::chooseInput( array( "Main Page", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1853 | + ); |
| 1854 | + |
| 1855 | + // sometimes we don't want to specify certain parameters. |
| 1856 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["sort"] ); |
| 1857 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["filter"] ); |
| 1858 | + } |
| 1859 | +} |
| 1860 | + |
| 1861 | + |
| 1862 | +/** |
| 1863 | + ** a test for Special:Cite (extension Special page). |
| 1864 | + */ |
| 1865 | +class specialCitePageTest extends pageTest { |
| 1866 | + function __construct() { |
| 1867 | + $this->pagePath = "index.php?title=Special:Cite"; |
| 1868 | + |
| 1869 | + $this->params = array ( |
| 1870 | + "page" => wikiFuzz::chooseInput( array( "\" onmouseover=\"alert(1);\"", "Main Page", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1871 | + "id" => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "-9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1872 | + ); |
| 1873 | + |
| 1874 | + // sometimes we don't want to specify certain parameters. |
| 1875 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["page"] ); |
| 1876 | + if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["id"] ); |
| 1877 | + } |
| 1878 | +} |
| 1879 | + |
| 1880 | + |
| 1881 | +/** |
| 1882 | + ** a test for Special:Filepath (extension Special page). |
| 1883 | + */ |
| 1884 | +class specialFilepathPageTest extends pageTest { |
| 1885 | + function __construct() { |
| 1886 | + $this->pagePath = "index.php?title=Special:Filepath"; |
| 1887 | + |
| 1888 | + $this->params = array ( |
| 1889 | + "file" => wikiFuzz::chooseInput( array( "Small-email.png", "Small-email.png" . wikiFuzz::makeFuzz( 1 ), wikiFuzz::makeFuzz( 2 ) ) ), |
| 1890 | + ); |
| 1891 | + } |
| 1892 | +} |
| 1893 | + |
| 1894 | + |
| 1895 | +/** |
| 1896 | + ** a test for Special:Makebot (extension Special page). |
| 1897 | + */ |
| 1898 | +class specialMakebot extends pageTest { |
| 1899 | + function __construct() { |
| 1900 | + $this->pagePath = "index.php?title=Special:Makebot"; |
| 1901 | + |
| 1902 | + $this->params = array ( |
| 1903 | + "username" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikiFuzz::makeFuzz( 1 ) ) ), |
| 1904 | + "dosearch" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1905 | + "grant" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1906 | + "comment" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1907 | + "token" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1908 | + ); |
| 1909 | + |
| 1910 | + // sometimes we don't want to specify certain parameters. |
| 1911 | + if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["dosearch"] ); |
| 1912 | + if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["grant"] ); |
| 1913 | + if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["token"] ); |
| 1914 | + } |
| 1915 | +} |
| 1916 | + |
| 1917 | + |
| 1918 | +/** |
| 1919 | + ** a test for Special:Makesysop (extension Special page). |
| 1920 | + */ |
| 1921 | +class specialMakesysop extends pageTest { |
| 1922 | + function __construct() { |
| 1923 | + $this->pagePath = "index.php?title=Special:Makesysop"; |
| 1924 | + |
| 1925 | + $this->params = array ( |
| 1926 | + "wpMakesysopUser" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikiFuzz::makeFuzz( 1 ) ) ), |
| 1927 | + "action" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1928 | + "wpMakesysopSubmit" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1929 | + "wpEditToken" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1930 | + "wpSetBureaucrat" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1931 | + ); |
| 1932 | + |
| 1933 | + // sometimes we don't want to specify certain parameters. |
| 1934 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpMakesysopSubmit"] ); |
| 1935 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpEditToken"] ); |
| 1936 | + if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpSetBureaucrat"] ); |
| 1937 | + } |
| 1938 | +} |
| 1939 | + |
| 1940 | + |
| 1941 | +/** |
| 1942 | + ** a test for Special:Renameuser (extension Special page). |
| 1943 | + */ |
| 1944 | +class specialRenameuserPageTest extends pageTest { |
| 1945 | + function __construct() { |
| 1946 | + $this->pagePath = "index.php?title=Special:Renameuser"; |
| 1947 | + |
| 1948 | + $this->params = array ( |
| 1949 | + "oldusername" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikiFuzz::makeFuzz( 1 ) ) ), |
| 1950 | + "newusername" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikiFuzz::makeFuzz( 1 ) ) ), |
| 1951 | + "token" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1952 | + ); |
| 1953 | + } |
| 1954 | +} |
| 1955 | + |
| 1956 | + |
| 1957 | +/** |
| 1958 | + ** a test for Special:Linksearch (extension Special page). |
| 1959 | + */ |
| 1960 | +class specialLinksearch extends pageTest { |
| 1961 | + function __construct() { |
| 1962 | + $this->pagePath = "index.php?title=Special%3ALinksearch"; |
| 1963 | + |
| 1964 | + $this->params = array ( |
| 1965 | + "target" => wikiFuzz::makeFuzz( 2 ), |
| 1966 | + ); |
| 1967 | + |
| 1968 | + // sometimes we don't want to specify certain parameters. |
| 1969 | + if ( wikiFuzz::randnum( 10 ) == 0 ) unset( $this->params["target"] ); |
| 1970 | + } |
| 1971 | +} |
| 1972 | + |
| 1973 | + |
| 1974 | +/** |
| 1975 | + ** a test for Special:CategoryTree (extension Special page). |
| 1976 | + */ |
| 1977 | +class specialCategoryTree extends pageTest { |
| 1978 | + function __construct() { |
| 1979 | + $this->pagePath = "index.php?title=Special:CategoryTree"; |
| 1980 | + |
| 1981 | + $this->params = array ( |
| 1982 | + "target" => wikiFuzz::makeFuzz( 2 ), |
| 1983 | + "from" => wikiFuzz::makeFuzz( 2 ), |
| 1984 | + "until" => wikiFuzz::makeFuzz( 2 ), |
| 1985 | + "showas" => wikiFuzz::makeFuzz( 2 ), |
| 1986 | + "mode" => wikiFuzz::chooseInput( array( "pages", "categories", "all", wikiFuzz::makeFuzz( 2 ) ) ), |
| 1987 | + ); |
| 1988 | + |
| 1989 | + // sometimes we do want to specify certain parameters. |
| 1990 | + if ( wikiFuzz::randnum( 5 ) == 0 ) $this->params["notree"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) ); |
| 1991 | + } |
| 1992 | +} |
| 1993 | + |
| 1994 | + |
| 1995 | +/** |
| 1996 | + ** a test for "Special:Chemicalsources" (extension Special page). |
| 1997 | + */ |
| 1998 | +class specialChemicalsourcesTest extends pageTest { |
| 1999 | + function __construct() { |
| 2000 | + $this->pagePath = "index.php?title=Special:Chemicalsources"; |
| 2001 | + |
| 2002 | + // choose an input format to use. |
| 2003 | + $format = wikiFuzz::chooseInput( |
| 2004 | + array( 'go', |
| 2005 | + 'CAS', |
| 2006 | + 'EINECS', |
| 2007 | + 'CHEBI', |
| 2008 | + 'PubChem', |
| 2009 | + 'SMILES', |
| 2010 | + 'InChI', |
| 2011 | + 'ATCCode', |
| 2012 | + 'KEGG', |
| 2013 | + 'RTECS', |
| 2014 | + 'ECNumber', |
| 2015 | + 'DrugBank', |
| 2016 | + 'Formula', |
| 2017 | + 'Name' |
| 2018 | + ) |
| 2019 | + ); |
| 2020 | + |
| 2021 | + // values for different formats usually start with either letters or numbers. |
| 2022 | + switch ( $format ) { |
| 2023 | + case 'Name' : $value = "A"; break; |
| 2024 | + case 'InChI' : |
| 2025 | + case 'SMILES' : |
| 2026 | + case 'Formula': $value = "C"; break; |
| 2027 | + default : $value = "0"; break; |
| 2028 | + } |
| 2029 | + |
| 2030 | + // and then we append the fuzz input. |
| 2031 | + $this->params = array ( $format => $value . wikiFuzz::makeFuzz( 2 ) ); |
| 2032 | + } |
| 2033 | +} |
| 2034 | + |
| 2035 | + |
| 2036 | +/** |
| 2037 | + ** A test for api.php (programmatic interface to MediaWiki in XML/JSON/RSS/etc formats). |
| 2038 | + ** Quite involved to test because there are lots of options/parameters, and because |
| 2039 | + ** for a lot of the functionality if all the parameters don't make sense then it just |
| 2040 | + ** returns the help screen - so currently a lot of the tests aren't actually doing much |
| 2041 | + ** because something wasn't right in the query. |
| 2042 | + ** |
| 2043 | + ** @todo: Incomplete / unfinished; Runs too fast (suggests not much testing going on). |
| 2044 | + */ |
| 2045 | +class api extends pageTest { |
| 2046 | + |
| 2047 | + // API login mode. |
| 2048 | + private static function loginMode() { |
| 2049 | + $arr = array ( "lgname" => wikiFuzz::makeFuzz( 2 ), |
| 2050 | + "lgpassword" => wikiFuzz::makeFuzz( 2 ), |
| 2051 | + ); |
| 2052 | + // sometimes we want to specify the extra "lgdomain" parameter. |
| 2053 | + if ( wikiFuzz::randnum( 3 ) == 0 ) { |
| 2054 | + $arr["lgdomain"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) ); |
| 2055 | + } |
| 2056 | + |
| 2057 | + return $arr; |
| 2058 | + } |
| 2059 | + |
| 2060 | + // API OpenSearch mode. |
| 2061 | + private static function opensearchMode() { |
| 2062 | + return array ( "search" => wikiFuzz::makeFuzz( 2 ) ); |
| 2063 | + } |
| 2064 | + |
| 2065 | + // API watchlist feed mode. |
| 2066 | + private static function feedwatchlistMode() { |
| 2067 | + // @todo FIXME: Add "wikiFuzz::makeFuzz(2)" as possible value below? |
| 2068 | + return array ( "feedformat" => wikiFuzz::chooseInput( array( "rss", "atom" ) ) ); |
| 2069 | + } |
| 2070 | + |
| 2071 | + // API query mode. |
| 2072 | + private static function queryMode() { |
| 2073 | + // @todo FIXME: Add "wikiFuzz::makeFuzz(2)" as possible params for the elements below? |
| 2074 | + // Suspect this will stuff up the tests more, but need to check. |
| 2075 | + $params = array ( |
| 2076 | + // @todo FIXME: More titles. |
| 2077 | + "titles" => wikiFuzz::chooseInput( array( "Main Page" ) ), |
| 2078 | + // @todo FIXME: More pageids. |
| 2079 | + "pageids" => 1, |
| 2080 | + "prop" => wikiFuzz::chooseInput( array( "info", "revisions", "watchlist" ) ), |
| 2081 | + "list" => wikiFuzz::chooseInput( array( "allpages", "logevents", "watchlist", "usercontribs", "recentchanges", "backlinks", "embeddedin", "imagelinks" ) ), |
| 2082 | + "meta" => wikiFuzz::chooseInput( array( "siteinfo" ) ), |
| 2083 | + "generator" => wikiFuzz::chooseInput( array( "allpages", "logevents", "watchlist", "info", "revisions" ) ), |
| 2084 | + "siprop" => wikiFuzz::chooseInput( array( "general", "namespaces", "general|namespaces" ) ), |
| 2085 | + ); |
| 2086 | + |
| 2087 | + // Add extra parameters based on what list choice we got. |
| 2088 | + switch ( $params["list"] ) { |
| 2089 | + case "usercontribs" : self::addListParams ( $params, "uc", array( "limit", "start", "end", "user", "dir" ) ); break; |
| 2090 | + case "allpages" : self::addListParams ( $params, "ap", array( "from", "prefix", "namespace", "filterredir", "limit" ) ); break; |
| 2091 | + case "watchlist" : self::addListParams ( $params, "wl", array( "allrev", "start", "end", "namespace", "dir", "limit", "prop" ) ); break; |
| 2092 | + case "logevents" : self::addListParams ( $params, "le", array( "limit", "type", "start", "end", "user", "dir" ) ); break; |
| 2093 | + case "recentchanges": self::addListParams ( $params, "rc", array( "limit", "prop", "show", "namespace", "start", "end", "dir" ) ); break; |
| 2094 | + case "backlinks" : self::addListParams ( $params, "bl", array( "continue", "namespace", "redirect", "limit" ) ); break; |
| 2095 | + case "embeddedin" : self::addListParams ( $params, "ei", array( "continue", "namespace", "redirect", "limit" ) ); break; |
| 2096 | + case "imagelinks" : self::addListParams ( $params, "il", array( "continue", "namespace", "redirect", "limit" ) ); break; |
| 2097 | + } |
| 2098 | + |
| 2099 | + if ( $params["prop"] == "revisions" ) { |
| 2100 | + self::addListParams ( $params, "rv", array( "prop", "limit", "startid", "endid", "end", "dir" ) ); |
| 2101 | + } |
| 2102 | + |
| 2103 | + // Sometimes we want redirects, sometimes we don't. |
| 2104 | + if ( wikiFuzz::randnum( 3 ) == 0 ) { |
| 2105 | + $params["redirects"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) ); |
| 2106 | + } |
| 2107 | + |
| 2108 | + return $params; |
| 2109 | + } |
| 2110 | + |
| 2111 | + // Adds all the elements to the array, using the specified prefix. |
| 2112 | + private static function addListParams( &$array, $prefix, $elements ) { |
| 2113 | + foreach ( $elements as $element ) { |
| 2114 | + $array[$prefix . $element] = self::getParamDetails( $element ); |
| 2115 | + } |
| 2116 | + } |
| 2117 | + |
| 2118 | + // For a given element name, returns the data for that element. |
| 2119 | + private static function getParamDetails( $element ) { |
| 2120 | + switch ( $element ) { |
| 2121 | + case 'startid' : |
| 2122 | + case 'endid' : |
| 2123 | + case 'start' : |
| 2124 | + case 'end' : |
| 2125 | + case 'limit' : return wikiFuzz::chooseInput( array( "0", "-1", "---'----------0", "+1", "8134", "320742734234235", "20060230121212", wikiFuzz::randnum( 9000, -100 ), wikiFuzz::makeFuzz( 2 ) ) ); |
| 2126 | + case 'dir' : return wikiFuzz::chooseInput( array( "newer", "older", wikiFuzz::makeFuzz( 2 ) ) ); |
| 2127 | + case 'user' : return wikiFuzz::chooseInput( array( USER_ON_WIKI, wikiFuzz::makeFuzz( 2 ) ) ); |
| 2128 | + case 'namespace' : return wikiFuzz::chooseInput( array( -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 200000, wikiFuzz::makeFuzz( 2 ) ) ); |
| 2129 | + case 'filterredir': return wikiFuzz::chooseInput( array( "all", "redirects", "nonredirectsallpages", wikiFuzz::makeFuzz( 2 ) ) ); |
| 2130 | + case 'allrev' : return wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) ); |
| 2131 | + case 'prop' : return wikiFuzz::chooseInput( array( "user", "comment", "timestamp", "patrol", "flags", "user|user|comment|flags", wikiFuzz::makeFuzz( 2 ) ) ); |
| 2132 | + case 'type' : return wikiFuzz::chooseInput( array( "block", "protect", "rights", "delete", "upload", "move", "import", "renameuser", "newusers", "makebot", wikiFuzz::makeFuzz( 2 ) ) ); |
| 2133 | + case 'hide' : return wikiFuzz::chooseInput( array( "minor", "bots", "anons", "liu", "liu|bots|", wikiFuzz::makeFuzz( 2 ) ) ); |
| 2134 | + case 'show' : return wikiFuzz::chooseInput( array( 'minor', '!minor', 'bot', '!bot', 'anon', '!anon', wikiFuzz::makeFuzz( 2 ) ) ); |
| 2135 | + default : return wikiFuzz::makeFuzz( 2 ); |
| 2136 | + } |
| 2137 | + } |
| 2138 | + |
| 2139 | + // Entry point. |
| 2140 | + function __construct() { |
| 2141 | + $this->pagePath = "api.php"; |
| 2142 | + |
| 2143 | + $modes = array ( "help", |
| 2144 | + "login", |
| 2145 | + "opensearch", |
| 2146 | + "feedwatchlist", |
| 2147 | + "query" ); |
| 2148 | + $action = wikiFuzz::chooseInput( array_merge ( $modes, array( wikiFuzz::makeFuzz( 2 ) ) ) ); |
| 2149 | + |
| 2150 | + switch ( $action ) { |
| 2151 | + case "login" : $this->params = self::loginMode(); |
| 2152 | + break; |
| 2153 | + case "opensearch" : $this->params = self::opensearchMode(); |
| 2154 | + break; |
| 2155 | + case "feedwatchlist" : $this->params = self::feedwatchlistMode(); |
| 2156 | + break; |
| 2157 | + case "query" : $this->params = self::queryMode(); |
| 2158 | + break; |
| 2159 | + case "help" : |
| 2160 | + default : // Do something random - "Crazy Ivan" mode. |
| 2161 | + $random_mode = wikiFuzz::chooseInput( $modes ) . "Mode"; |
| 2162 | + // There is no "helpMode". |
| 2163 | + if ( $random_mode == "helpMode" ) $random_mode = "queryMode"; |
| 2164 | + $this->params = self::$random_mode(); |
| 2165 | + break; |
| 2166 | + } |
| 2167 | + |
| 2168 | + // Save the selected action. |
| 2169 | + $this->params["action"] = $action; |
| 2170 | + |
| 2171 | + // Set the cookie: |
| 2172 | + // @todo FIXME: Need to get this cookie dynamically set, rather than hard-coded. |
| 2173 | + $this->cookie = "wikidbUserID=10001; wikidbUserName=Test; wikidb_session=178df0fe68c75834643af65dec9ec98a; wikidbToken=1adc6753d62c44aec950c024d7ae0540"; |
| 2174 | + |
| 2175 | + // Output format |
| 2176 | + $this->params["format"] = wikiFuzz::chooseInput( array( "json", "jsonfm", "php", "phpfm", |
| 2177 | + "wddx", "wddxfm", "xml", "xmlfm", |
| 2178 | + "yaml", "yamlfm", "raw", "rawfm", |
| 2179 | + wikiFuzz::makeFuzz( 2 ) ) ); |
| 2180 | + |
| 2181 | + // Page does not produce HTML (sometimes). |
| 2182 | + $this->tidyValidate = false; |
| 2183 | + } |
| 2184 | +} |
| 2185 | + |
| 2186 | + |
| 2187 | +/** |
| 2188 | + ** a page test for the GeSHi extension. |
| 2189 | + */ |
| 2190 | +class GeSHi_Test extends pageTest { |
| 2191 | + |
| 2192 | + private function getGeSHiContent() { |
| 2193 | + return "<source lang=\"" . $this->getLang() . "\" " |
| 2194 | + . ( wikiFuzz::randnum( 2 ) == 0 ? "line " : "" ) |
| 2195 | + . ( wikiFuzz::randnum( 2 ) == 0 ? "strict " : "" ) |
| 2196 | + . "start=" . wikiFuzz::chooseInput( array( wikiFuzz::randnum( 6000, -6000 ), wikiFuzz::makeFuzz( 2 ) ) ) |
| 2197 | + . ">" |
| 2198 | + . wikiFuzz::makeFuzz( 2 ) |
| 2199 | + . "</source>"; |
| 2200 | + } |
| 2201 | + |
| 2202 | + private function getLang() { |
| 2203 | + return wikiFuzz::chooseInput( array( "actionscript", "ada", "apache", "applescript", "asm", "asp", "autoit", "bash", "blitzbasic", "bnf", "c", "c_mac", "caddcl", "cadlisp", |
| 2204 | + "cfdg", "cfm", "cpp", "cpp-qt", "csharp", "css", "d", "delphi", "diff", "div", "dos", "eiffel", "fortran", "freebasic", "gml", "groovy", "html4strict", "idl", |
| 2205 | + "ini", "inno", "io", "java", "java5", "javascript", "latex", "lisp", "lua", "matlab", "mirc", "mpasm", "mysql", "nsis", "objc", "ocaml", "ocaml-brief", "oobas", |
| 2206 | + "oracle8", "pascal", "perl", "php", "php-brief", "plsql", "python", "qbasic", "rails", "reg", "robots", "ruby", "sas", "scheme", "sdlbasic", "smalltalk", "smarty", |
| 2207 | + "sql", "tcl", "text", "thinbasic", "tsql", "vb", "vbnet", "vhdl", "visualfoxpro", "winbatch", "xml", "xpp", "z80", wikiFuzz::makeFuzz( 1 ) ) ); |
| 2208 | + } |
| 2209 | + |
| 2210 | + function __construct() { |
| 2211 | + $this->pagePath = "index.php?title=WIKIFUZZ"; |
| 2212 | + |
| 2213 | + $this->params = array ( |
| 2214 | + "action" => "submit", |
| 2215 | + "wpMinoredit" => "test", |
| 2216 | + "wpPreview" => "test", |
| 2217 | + "wpSection" => "test", |
| 2218 | + "wpEdittime" => "test", |
| 2219 | + "wpSummary" => "test", |
| 2220 | + "wpScrolltop" => "test", |
| 2221 | + "wpStarttime" => "test", |
| 2222 | + "wpAutoSummary" => "test", |
| 2223 | + "wpTextbox1" => $this->getGeSHiContent() // the main wiki text, contains fake GeSHi content. |
| 2224 | + ); |
| 2225 | + } |
| 2226 | +} |
| 2227 | + |
| 2228 | + |
| 2229 | +/** |
| 2230 | + ** selects a page test to run. |
| 2231 | + */ |
| 2232 | +function selectPageTest( $count ) { |
| 2233 | + |
| 2234 | + // if the user only wants a specific test, then only ever give them that. |
| 2235 | + if ( defined( "SPECIFIC_TEST" ) ) { |
| 2236 | + $testType = SPECIFIC_TEST; |
| 2237 | + return new $testType (); |
| 2238 | + } |
| 2239 | + |
| 2240 | + // Some of the time we test Special pages, the remaining |
| 2241 | + // time we test using the standard edit page. |
| 2242 | + switch ( $count % 100 ) { |
| 2243 | + case 0 : return new successfulUserLoginTest(); |
| 2244 | + case 1 : return new listusersTest(); |
| 2245 | + case 2 : return new searchTest(); |
| 2246 | + case 3 : return new recentchangesTest(); |
| 2247 | + case 4 : return new prefixindexTest(); |
| 2248 | + case 5 : return new mimeSearchTest(); |
| 2249 | + case 6 : return new specialLogTest(); |
| 2250 | + case 7 : return new userLoginTest(); |
| 2251 | + case 8 : return new ipblocklistTest(); |
| 2252 | + case 9 : return new newImagesTest(); |
| 2253 | + case 10: return new imagelistTest(); |
| 2254 | + case 11: return new specialExportTest(); |
| 2255 | + case 12: return new specialBooksourcesTest(); |
| 2256 | + case 13: return new specialAllpagesTest(); |
| 2257 | + case 14: return new pageHistoryTest(); |
| 2258 | + case 15: return new contributionsTest(); |
| 2259 | + case 16: return new viewPageTest(); |
| 2260 | + case 17: return new specialAllmessagesTest(); |
| 2261 | + case 18: return new specialNewpagesPageTest(); |
| 2262 | + case 19: return new searchTest(); |
| 2263 | + case 20: return new redirectTest(); |
| 2264 | + case 21: return new confirmEmail(); |
| 2265 | + case 22: return new watchlistTest(); |
| 2266 | + case 23: return new specialBlockmeTest(); |
| 2267 | + case 24: return new specialUndeletePageTest(); |
| 2268 | + case 25: return new specialMovePage(); |
| 2269 | + case 26: return new specialUnlockdbPageTest(); |
| 2270 | + case 27: return new specialLockdbPageTest(); |
| 2271 | + case 28: return new specialUserrights(); |
| 2272 | + case 29: return new pageProtectionForm(); |
| 2273 | + case 30: return new specialBlockip(); |
| 2274 | + case 31: return new imagepageTest(); |
| 2275 | + case 32: return new pageDeletion(); |
| 2276 | + case 33: return new specialRevisionDeletePageTest(); |
| 2277 | + case 34: return new specialImportPageTest(); |
| 2278 | + case 35: return new thumbTest(); |
| 2279 | + case 36: return new trackbackTest(); |
| 2280 | + case 37: return new profileInfo(); |
| 2281 | + case 38: return new specialCitePageTest(); |
| 2282 | + case 39: return new specialFilepathPageTest(); |
| 2283 | + case 40: return new specialMakebot(); |
| 2284 | + case 41: return new specialMakesysop(); |
| 2285 | + case 42: return new specialRenameuserPageTest(); |
| 2286 | + case 43: return new specialLinksearch(); |
| 2287 | + case 44: return new specialCategoryTree(); |
| 2288 | + case 45: return new api(); |
| 2289 | + case 45: return new specialChemicalsourcesTest(); |
| 2290 | + default: return new editPageTest(); |
| 2291 | + } |
| 2292 | +} |
| 2293 | + |
| 2294 | + |
| 2295 | +// ///////////////////// SAVING OUTPUT ///////////////////////// |
| 2296 | + |
| 2297 | +/** |
| 2298 | + ** Utility function for saving a file. Currently has no error checking. |
| 2299 | + */ |
| 2300 | +function saveFile( $data, $name ) { |
| 2301 | + file_put_contents( $name, $data ); |
| 2302 | +} |
| 2303 | + |
| 2304 | + |
| 2305 | +/** |
| 2306 | + ** Returns a test as an experimental GET-to-POST URL. |
| 2307 | + ** This doesn't seem to always work though, and sometimes the output is too long |
| 2308 | + ** to be a valid GET URL, so we also save in other formats. |
| 2309 | + */ |
| 2310 | +function getAsURL( pageTest $test ) { |
| 2311 | + $used_question_mark = ( strpos( $test->getPagePath(), "?" ) !== false ); |
| 2312 | + $retval = "http://get-to-post.nickj.org/?" . WIKI_BASE_URL . $test->getPagePath(); |
| 2313 | + foreach ( $test->getParams() as $param => $value ) { |
| 2314 | + if ( !$used_question_mark ) { |
| 2315 | + $retval .= "?"; |
| 2316 | + $used_question_mark = true; |
| 2317 | + } |
| 2318 | + else { |
| 2319 | + $retval .= "&"; |
| 2320 | + } |
| 2321 | + $retval .= $param . "=" . urlencode( $value ); |
| 2322 | + } |
| 2323 | + return $retval; |
| 2324 | +} |
| 2325 | + |
| 2326 | + |
| 2327 | +/** |
| 2328 | + ** Saves a plain-text human-readable version of a test. |
| 2329 | + */ |
| 2330 | +function saveTestAsText( pageTest $test, $filename ) { |
| 2331 | + $str = "Test: " . $test->getPagePath(); |
| 2332 | + foreach ( $test->getParams() as $param => $value ) { |
| 2333 | + $str .= "\n$param: $value"; |
| 2334 | + } |
| 2335 | + $str .= "\nGet-to-post URL: " . getAsURL( $test ) . "\n"; |
| 2336 | + saveFile( $str, $filename ); |
| 2337 | +} |
| 2338 | + |
| 2339 | + |
| 2340 | +/** |
| 2341 | + ** Saves a test as a standalone basic PHP script that shows this one problem. |
| 2342 | + ** Resulting script requires PHP-Curl be installed in order to work. |
| 2343 | + */ |
| 2344 | +function saveTestAsPHP( pageTest $test, $filename ) { |
| 2345 | + $str = "<?php\n" |
| 2346 | + . "\$params = " . var_export( escapeForCurl( $test->getParams() ), true ) . ";\n" |
| 2347 | + . "\$ch = curl_init();\n" |
| 2348 | + . "curl_setopt(\$ch, CURLOPT_POST, 1);\n" |
| 2349 | + . "curl_setopt(\$ch, CURLOPT_POSTFIELDS, \$params );\n" |
| 2350 | + . "curl_setopt(\$ch, CURLOPT_URL, " . var_export( WIKI_BASE_URL . $test->getPagePath(), true ) . ");\n" |
| 2351 | + . "curl_setopt(\$ch, CURLOPT_RETURNTRANSFER,1);\n" |
| 2352 | + . ( $test->getCookie() ? "curl_setopt(\$ch, CURLOPT_COOKIE, " . var_export( $test->getCookie(), true ) . ");\n" : "" ) |
| 2353 | + . "\$result=curl_exec(\$ch);\n" |
| 2354 | + . "curl_close (\$ch);\n" |
| 2355 | + . "print \$result;\n" |
| 2356 | + . "\n"; |
| 2357 | + saveFile( $str, $filename ); |
| 2358 | +} |
| 2359 | + |
| 2360 | + |
| 2361 | +/** |
| 2362 | + ** Escapes a value so that it can be used on the command line by Curl. |
| 2363 | + ** Specifically, "<" and "@" need to be escaped if they are the first character, |
| 2364 | + ** otherwise curl interprets these as meaning that we want to insert a file. |
| 2365 | + */ |
| 2366 | +function escapeForCurl( array $input_params ) { |
| 2367 | + $output_params = array(); |
| 2368 | + foreach ( $input_params as $param => $value ) { |
| 2369 | + if ( strlen( $value ) > 0 && ( $value[0] == "@" || $value[0] == "<" ) ) { |
| 2370 | + $value = "\\" . $value; |
| 2371 | + } |
| 2372 | + $output_params[$param] = $value; |
| 2373 | + } |
| 2374 | + return $output_params; |
| 2375 | +} |
| 2376 | + |
| 2377 | + |
| 2378 | +/** |
| 2379 | + ** Saves a test as a standalone CURL shell script that shows this one problem. |
| 2380 | + ** Resulting script requires standalone Curl be installed in order to work. |
| 2381 | + */ |
| 2382 | +function saveTestAsCurl( pageTest $test, $filename ) { |
| 2383 | + $str = "#!/bin/bash\n" |
| 2384 | + . "curl --silent --include --globoff \\\n" |
| 2385 | + . ( $test->getCookie() ? " --cookie " . escapeshellarg( $test->getCookie() ) . " \\\n" : "" ); |
| 2386 | + foreach ( escapeForCurl( $test->getParams() ) as $param => $value ) { |
| 2387 | + $str .= " -F " . escapeshellarg( $param ) . "=" . escapeshellarg( $value ) . " \\\n"; |
| 2388 | + } |
| 2389 | + $str .= " " . escapeshellarg( WIKI_BASE_URL . $test->getPagePath() ); // beginning space matters. |
| 2390 | + $str .= "\n"; |
| 2391 | + saveFile( $str, $filename ); |
| 2392 | + chmod( $filename, 0755 ); // make executable |
| 2393 | +} |
| 2394 | + |
| 2395 | + |
| 2396 | +/** |
| 2397 | + ** Saves the internal data structure to file. |
| 2398 | + */ |
| 2399 | +function saveTestData ( pageTest $test, $filename ) { |
| 2400 | + saveFile( serialize( $test ), $filename ); |
| 2401 | +} |
| 2402 | + |
| 2403 | + |
| 2404 | +/** |
| 2405 | + ** saves a test in the various formats. |
| 2406 | + */ |
| 2407 | +function saveTest( pageTest $test, $testname ) { |
| 2408 | + $base_name = DIRECTORY . "/" . $testname; |
| 2409 | + saveTestAsText( $test, $base_name . INFO_FILE ); |
| 2410 | + saveTestAsPHP ( $test, $base_name . PHP_TEST ); |
| 2411 | + saveTestAsCurl( $test, $base_name . CURL_TEST ); |
| 2412 | + saveTestData ( $test, $base_name . DATA_FILE ); |
| 2413 | +} |
| 2414 | + |
| 2415 | + |
| 2416 | +// ////////////////// MEDIAWIKI OUTPUT ///////////////////////// |
| 2417 | + |
| 2418 | +/** |
| 2419 | + ** Asks MediaWiki for the HTML output of a test. |
| 2420 | + */ |
| 2421 | +function wikiTestOutput( pageTest $test ) { |
| 2422 | + |
| 2423 | + $ch = curl_init(); |
| 2424 | + |
| 2425 | + // specify the cookie, if required. |
| 2426 | + if ( $test->getCookie() ) curl_setopt( $ch, CURLOPT_COOKIE, $test->getCookie() ); |
| 2427 | + curl_setopt( $ch, CURLOPT_POST, 1 ); // save form using a POST |
| 2428 | + |
| 2429 | + $params = escapeForCurl( $test->getParams() ); |
| 2430 | + curl_setopt( $ch, CURLOPT_POSTFIELDS, $params ); // load the POST variables |
| 2431 | + |
| 2432 | + curl_setopt( $ch, CURLOPT_URL, WIKI_BASE_URL . $test->getPagePath() ); // set url to post to |
| 2433 | + curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); // return into a variable |
| 2434 | + |
| 2435 | + $result = curl_exec ( $ch ); |
| 2436 | + |
| 2437 | + // if we encountered an error, then say so, and return an empty string. |
| 2438 | + if ( curl_error( $ch ) ) { |
| 2439 | + print "\nCurl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch ); |
| 2440 | + $result = ""; |
| 2441 | + } |
| 2442 | + |
| 2443 | + curl_close ( $ch ); |
| 2444 | + |
| 2445 | + return $result; |
| 2446 | +} |
| 2447 | + |
| 2448 | + |
| 2449 | +// ////////////////// HTML VALIDATION ///////////////////////// |
| 2450 | + |
| 2451 | +/* |
| 2452 | + ** Asks the validator whether this is valid HTML, or not. |
| 2453 | + */ |
| 2454 | +function validateHTML( $text ) { |
| 2455 | + |
| 2456 | + $params = array ( "fragment" => $text ); |
| 2457 | + |
| 2458 | + $ch = curl_init(); |
| 2459 | + |
| 2460 | + curl_setopt( $ch, CURLOPT_POST, 1 ); // save form using a POST |
| 2461 | + curl_setopt( $ch, CURLOPT_POSTFIELDS, $params ); // load the POST variables |
| 2462 | + curl_setopt( $ch, CURLOPT_URL, VALIDATOR_URL ); // set url to post to |
| 2463 | + curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); // return into a variable |
| 2464 | + |
| 2465 | + $result = curl_exec ( $ch ); |
| 2466 | + |
| 2467 | + // if we encountered an error, then log it, and exit. |
| 2468 | + if ( curl_error( $ch ) ) { |
| 2469 | + trigger_error( "Curl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch ) ); |
| 2470 | + print "Curl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch ) . " - exiting.\n"; |
| 2471 | + exit( 1 ); |
| 2472 | + } |
| 2473 | + |
| 2474 | + curl_close ( $ch ); |
| 2475 | + |
| 2476 | + $valid = ( strpos( $result, "Failed validation" ) === false ); |
| 2477 | + |
| 2478 | + return array( $valid, $result ); |
| 2479 | +} |
| 2480 | + |
| 2481 | + |
| 2482 | +/** |
| 2483 | + ** Get tidy to check for no HTML errors in the output file (e.g. unescaped strings). |
| 2484 | + */ |
| 2485 | +function tidyCheckFile( $name ) { |
| 2486 | + $file = DIRECTORY . "/" . $name; |
| 2487 | + $command = PATH_TO_TIDY . " -output /tmp/out.html -quiet $file 2>&1"; |
| 2488 | + $x = `$command`; |
| 2489 | + |
| 2490 | + // Look for the most interesting Tidy errors and warnings. |
| 2491 | + if ( strpos( $x, "end of file while parsing attributes" ) !== false |
| 2492 | + || strpos( $x, "attribute with missing trailing quote mark" ) !== false |
| 2493 | + || strpos( $x, "missing '>' for end of tag" ) !== false |
| 2494 | + || strpos( $x, "Error:" ) !== false ) { |
| 2495 | + print "\nTidy found something - view details with: $command"; |
| 2496 | + return false; |
| 2497 | + } else { |
| 2498 | + return true; |
| 2499 | + } |
| 2500 | +} |
| 2501 | + |
| 2502 | + |
| 2503 | +/** |
| 2504 | + ** Returns whether or not an database error log file has changed in size since |
| 2505 | + ** the last time this was run. This is used to tell if a test caused a DB error. |
| 2506 | + */ |
| 2507 | +function dbErrorLogged() { |
| 2508 | + static $filesize; |
| 2509 | + |
| 2510 | + // first time running this function |
| 2511 | + if ( !isset( $filesize ) ) { |
| 2512 | + // create log if it does not exist |
| 2513 | + if ( DB_ERROR_LOG_FILE && !file_exists( DB_ERROR_LOG_FILE ) ) { |
| 2514 | + saveFile( '', DB_ERROR_LOG_FILE ); |
| 2515 | + } |
| 2516 | + $filesize = filesize( DB_ERROR_LOG_FILE ); |
| 2517 | + return false; |
| 2518 | + } |
| 2519 | + |
| 2520 | + $newsize = filesize( DB_ERROR_LOG_FILE ); |
| 2521 | + // if the log has grown, then assume the current test caused it. |
| 2522 | + if ( $newsize != $filesize ) { |
| 2523 | + $filesize = $newsize; |
| 2524 | + return true; |
| 2525 | + } |
| 2526 | + |
| 2527 | + return false; |
| 2528 | +} |
| 2529 | + |
| 2530 | +// //////////////// TOP-LEVEL PROBLEM-FINDING FUNCTION //////////////////////// |
| 2531 | + |
| 2532 | +/** |
| 2533 | + ** takes a page test, and runs it and tests it for problems in the output. |
| 2534 | + ** Returns: False on finding a problem, or True on no problems being found. |
| 2535 | + */ |
| 2536 | +function runWikiTest( pageTest $test, &$testname, $can_overwrite = false ) { |
| 2537 | + |
| 2538 | + // by default don't overwrite a previous test of the same name. |
| 2539 | + while ( ! $can_overwrite && file_exists( DIRECTORY . "/" . $testname . DATA_FILE ) ) { |
| 2540 | + $testname .= "-" . mt_rand( 0, 9 ); |
| 2541 | + } |
| 2542 | + |
| 2543 | + $filename = DIRECTORY . "/" . $testname . DATA_FILE; |
| 2544 | + |
| 2545 | + // Store the time before and after, to find slow pages. |
| 2546 | + $before = microtime( true ); |
| 2547 | + |
| 2548 | + // Get MediaWiki to give us the output of this test. |
| 2549 | + $wiki_preview = wikiTestOutput( $test ); |
| 2550 | + |
| 2551 | + $after = microtime( true ); |
| 2552 | + |
| 2553 | + // if we received no response, then that's interesting. |
| 2554 | + if ( $wiki_preview == "" ) { |
| 2555 | + print "\nNo response received for: $filename"; |
| 2556 | + return false; |
| 2557 | + } |
| 2558 | + |
| 2559 | + // save output HTML to file. |
| 2560 | + $html_file = DIRECTORY . "/" . $testname . HTML_FILE; |
| 2561 | + saveFile( $wiki_preview, $html_file ); |
| 2562 | + |
| 2563 | + // if there were PHP errors in the output, then that's interesting too. |
| 2564 | + if ( strpos( $wiki_preview, "<b>Warning</b>: " ) !== false |
| 2565 | + || strpos( $wiki_preview, "<b>Fatal error</b>: " ) !== false |
| 2566 | + || strpos( $wiki_preview, "<b>Notice</b>: " ) !== false |
| 2567 | + || strpos( $wiki_preview, "<b>Error</b>: " ) !== false |
| 2568 | + || strpos( $wiki_preview, "<b>Strict Standards:</b>" ) !== false |
| 2569 | + ) { |
| 2570 | + $error = substr( $wiki_preview, strpos( $wiki_preview, "</b>:" ) + 7, 50 ); |
| 2571 | + // Avoid probable PHP bug with bad session ids; http://bugs.php.net/bug.php?id=38224 |
| 2572 | + if ( $error != "Unknown: The session id contains illegal character" ) { |
| 2573 | + print "\nPHP error/warning/notice in HTML output: $html_file ; $error"; |
| 2574 | + return false; |
| 2575 | + } |
| 2576 | + } |
| 2577 | + |
| 2578 | + // if there was a MediaWiki Backtrace message in the output, then that's also interesting. |
| 2579 | + if ( strpos( $wiki_preview, "Backtrace:" ) !== false ) { |
| 2580 | + print "\nInternal MediaWiki error in HTML output: $html_file"; |
| 2581 | + return false; |
| 2582 | + } |
| 2583 | + |
| 2584 | + // if there was a Parser error comment in the output, then that's potentially interesting. |
| 2585 | + if ( strpos( $wiki_preview, "!-- ERR" ) !== false ) { |
| 2586 | + print "\nParser Error comment in HTML output: $html_file"; |
| 2587 | + return false; |
| 2588 | + } |
| 2589 | + |
| 2590 | + // if a database error was logged, then that's definitely interesting. |
| 2591 | + if ( dbErrorLogged() ) { |
| 2592 | + print "\nDatabase Error logged for: $filename"; |
| 2593 | + return false; |
| 2594 | + } |
| 2595 | + |
| 2596 | + // validate result |
| 2597 | + $valid = true; |
| 2598 | + if ( VALIDATE_ON_WEB ) { |
| 2599 | + list ( $valid, $validator_output ) = validateHTML( $wiki_preview ); |
| 2600 | + if ( !$valid ) print "\nW3C web validation failed - view details with: html2text " . DIRECTORY . "/" . $testname . ".validator_output.html"; |
| 2601 | + } |
| 2602 | + |
| 2603 | + // Get tidy to check the page, unless we already know it produces non-XHTML output. |
| 2604 | + if ( $test->tidyValidate() ) { |
| 2605 | + $valid = tidyCheckFile( $testname . HTML_FILE ) && $valid; |
| 2606 | + } |
| 2607 | + |
| 2608 | + // if it took more than 2 seconds to render, then it may be interesting too. (Possible DoS attack?) |
| 2609 | + if ( ( $after - $before ) >= 2 ) { |
| 2610 | + print "\nParticularly slow to render (" . round( $after - $before, 2 ) . " seconds): $filename"; |
| 2611 | + return false; |
| 2612 | + } |
| 2613 | + |
| 2614 | + if ( $valid ) { |
| 2615 | + // Remove temp HTML file if test was valid: |
| 2616 | + unlink( $html_file ); |
| 2617 | + } elseif ( VALIDATE_ON_WEB ) { |
| 2618 | + saveFile( $validator_output, DIRECTORY . "/" . $testname . ".validator_output.html" ); |
| 2619 | + } |
| 2620 | + |
| 2621 | + return $valid; |
| 2622 | +} |
| 2623 | + |
| 2624 | + |
| 2625 | +// ///////////////// RERUNNING OLD TESTS /////////////////// |
| 2626 | + |
| 2627 | +/** |
| 2628 | + ** We keep our failed tests so that they can be rerun. |
| 2629 | + ** This function does that retesting. |
| 2630 | + */ |
| 2631 | +function rerunPreviousTests() { |
| 2632 | + print "Retesting previously found problems.\n"; |
| 2633 | + |
| 2634 | + $dir_contents = scandir ( DIRECTORY ); |
| 2635 | + |
| 2636 | + // sort file into the order a normal person would use. |
| 2637 | + natsort ( $dir_contents ); |
| 2638 | + |
| 2639 | + foreach ( $dir_contents as $file ) { |
| 2640 | + |
| 2641 | + // if file is not a test, then skip it. |
| 2642 | + // Note we need to escape any periods or will be treated as "any character". |
| 2643 | + $matches = array(); |
| 2644 | + if ( !preg_match( "/(.*)" . str_replace( ".", "\.", DATA_FILE ) . "$/", $file, $matches ) ) continue; |
| 2645 | + |
| 2646 | + // reload the test. |
| 2647 | + $full_path = DIRECTORY . "/" . $file; |
| 2648 | + $test = unserialize( file_get_contents( $full_path ) ); |
| 2649 | + |
| 2650 | + // if this is not a valid test, then skip it. |
| 2651 | + if ( ! $test instanceof pageTest ) { |
| 2652 | + print "\nSkipping invalid test - $full_path"; |
| 2653 | + continue; |
| 2654 | + } |
| 2655 | + |
| 2656 | + // The date format is in Apache log format, which makes it easier to locate |
| 2657 | + // which retest caused which error in the Apache logs (only happens usually if |
| 2658 | + // apache segfaults). |
| 2659 | + if ( !QUIET ) print "[" . date ( "D M d H:i:s Y" ) . "] Retesting $file (" . get_class( $test ) . ")"; |
| 2660 | + |
| 2661 | + // run test |
| 2662 | + $testname = $matches[1]; |
| 2663 | + $valid = runWikiTest( $test, $testname, true ); |
| 2664 | + |
| 2665 | + if ( !$valid ) { |
| 2666 | + saveTest( $test, $testname ); |
| 2667 | + if ( QUIET ) { |
| 2668 | + print "\nTest: " . get_class( $test ) . " ; Testname: $testname\n------"; |
| 2669 | + } else { |
| 2670 | + print "\n"; |
| 2671 | + } |
| 2672 | + } |
| 2673 | + else { |
| 2674 | + if ( !QUIET ) print "\r"; |
| 2675 | + if ( DELETE_PASSED_RETESTS ) { |
| 2676 | + $prefix = DIRECTORY . "/" . $testname; |
| 2677 | + if ( is_file( $prefix . DATA_FILE ) ) unlink( $prefix . DATA_FILE ); |
| 2678 | + if ( is_file( $prefix . PHP_TEST ) ) unlink( $prefix . PHP_TEST ); |
| 2679 | + if ( is_file( $prefix . CURL_TEST ) ) unlink( $prefix . CURL_TEST ); |
| 2680 | + if ( is_file( $prefix . INFO_FILE ) ) unlink( $prefix . INFO_FILE ); |
| 2681 | + } |
| 2682 | + } |
| 2683 | + } |
| 2684 | + |
| 2685 | + print "\nDone retesting.\n"; |
| 2686 | +} |
| 2687 | + |
| 2688 | + |
| 2689 | +// //////////////////// MAIN LOOP //////////////////////// |
| 2690 | + |
| 2691 | + |
| 2692 | +// first check whether CURL is installed, because sometimes it's not. |
| 2693 | +if ( ! function_exists( 'curl_init' ) ) { |
| 2694 | + die( "Could not find 'curl_init' function. Is the curl extension compiled into PHP?\n" ); |
| 2695 | +} |
| 2696 | + |
| 2697 | +// Initialization of types. wikiFuzz doesn't have a constructor because we want to |
| 2698 | +// access it staticly and not have any globals. |
| 2699 | +wikiFuzz::$types = array_keys( wikiFuzz::$data ); |
| 2700 | + |
| 2701 | +// Make directory if doesn't exist |
| 2702 | +if ( !is_dir( DIRECTORY ) ) { |
| 2703 | + mkdir ( DIRECTORY, 0700 ); |
| 2704 | +} |
| 2705 | +// otherwise, we first retest the things that we have found in previous runs |
| 2706 | +else if ( RERUN_OLD_TESTS ) { |
| 2707 | + rerunPreviousTests(); |
| 2708 | +} |
| 2709 | + |
| 2710 | +// main loop. |
| 2711 | +$start_time = date( "U" ); |
| 2712 | +$num_errors = 0; |
| 2713 | +if ( !QUIET ) { |
| 2714 | + print "Beginning main loop. Results are stored in the " . DIRECTORY . " directory.\n"; |
| 2715 | + print "Press CTRL+C to stop testing.\n"; |
| 2716 | +} |
| 2717 | + |
| 2718 | +for ( $count = 0; true; $count++ ) { |
| 2719 | + if ( !QUIET ) { |
| 2720 | + // spinning progress indicator. |
| 2721 | + switch( $count % 4 ) { |
| 2722 | + case '0': print "\r/"; break; |
| 2723 | + case '1': print "\r-"; break; |
| 2724 | + case '2': print "\r\\"; break; |
| 2725 | + case '3': print "\r|"; break; |
| 2726 | + } |
| 2727 | + print " $count"; |
| 2728 | + } |
| 2729 | + |
| 2730 | + // generate a page test to run. |
| 2731 | + $test = selectPageTest( $count ); |
| 2732 | + |
| 2733 | + $mins = ( date( "U" ) - $start_time ) / 60; |
| 2734 | + if ( !QUIET && $mins > 0 ) { |
| 2735 | + print ". $num_errors poss errors. " |
| 2736 | + . floor( $mins ) . " mins. " |
| 2737 | + . round ( $count / $mins, 0 ) . " tests/min. " |
| 2738 | + . get_class( $test ); // includes the current test name. |
| 2739 | + } |
| 2740 | + |
| 2741 | + // run this test against MediaWiki, and see if the output was valid. |
| 2742 | + $testname = $count; |
| 2743 | + $valid = runWikiTest( $test, $testname, false ); |
| 2744 | + |
| 2745 | + // save the failed test |
| 2746 | + if ( ! $valid ) { |
| 2747 | + if ( QUIET ) { |
| 2748 | + print "\nTest: " . get_class( $test ) . " ; Testname: $testname\n------"; |
| 2749 | + } else { |
| 2750 | + print "\n"; |
| 2751 | + } |
| 2752 | + saveTest( $test, $testname ); |
| 2753 | + $num_errors += 1; |
| 2754 | + } else if ( KEEP_PASSED_TESTS ) { |
| 2755 | + // print current time, with microseconds (matches "strace" format), and the test name. |
| 2756 | + print " " . date( "H:i:s." ) . substr( current( explode( " ", microtime() ) ), 2 ) . " " . $testname; |
| 2757 | + saveTest( $test, $testname ); |
| 2758 | + } |
| 2759 | + |
| 2760 | + // stop if we have reached max number of errors. |
| 2761 | + if ( defined( "MAX_ERRORS" ) && $num_errors >= MAX_ERRORS ) { |
| 2762 | + break; |
| 2763 | + } |
| 2764 | + |
| 2765 | + // stop if we have reached max number of mins runtime. |
| 2766 | + if ( defined( "MAX_RUNTIME" ) && $mins >= MAX_RUNTIME ) { |
| 2767 | + break; |
| 2768 | + } |
| 2769 | +} |
| 2770 | + |
| 2771 | + |
Property changes on: trunk/phase3/maintenance/fuzz-tester.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 2772 | + native |