r106495 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r106494‎ | r106495 | r106496 >
Date:01:34, 17 December 2011
Author:khorn
Status:deferred (Comments)
Tags:fundraising 
Comment:
The beginnings of input validation in DonationData.
Stuff left to do:
*) Move all the other input validation to DonationData (look in GatewayForm)
*) Halt do_transaction in the gateway adapter if DonationData doesn't come back clean
*) Make the validation errors available directly from the gateway adapter
*) Kill off the old $form_errors array(s) in favor of going back to the adapter directly.
*) Turn the thing on.
Modified paths:
  • /trunk/extensions/DonationInterface/gateway_common/DonationData.php (modified) (history)

Diff [purge]

Index: trunk/extensions/DonationInterface/gateway_common/DonationData.php
@@ -17,6 +17,7 @@
1818
1919 protected $normalized = array( );
2020 public $boss;
 21+ protected $validationErrors = false;
2122
2223 /**
2324 * DonationData constructor
@@ -383,6 +384,8 @@
384385 */
385386 protected function normalize() {
386387 if ( !empty( $this->normalized ) ) {
 388+ //TODO: Uncomment the next line when we want to start actually using the input validation.
 389+ //$this->validateAllInput();
387390 $this->setUtmSource();
388391 $this->setNormalizedAmount();
389392 $this->setNormalizedOrderIDs();
@@ -433,8 +436,8 @@
434437 throw new MWException( 'Could not find form ' . $class_name_orig . ', nor default form ' . $class_name );
435438 }
436439 }
437 -
438 - $this->setVal( 'form_class', $class_name );
 440+
 441+ $this->setVal( 'form_class', $class_name );
439442 }
440443
441444 /**
@@ -1287,6 +1290,303 @@
12881291 }
12891292 return $posted;
12901293 }
 1294+
 1295+ /**
 1296+ * validateAllInput
 1297+ * This function will go through all the data we have pulled from wherever
 1298+ * we've pulled it, and make sure it's safe and expected and everything.
 1299+ */
 1300+ protected function validateAllInput(){
 1301+ $rules = $this->buildValidationRules();
 1302+ foreach ( $this->normalized as $key => $val ){
 1303+ if ( $this->isSomething( $key ) ){
 1304+ //make sure there's a rule for it.
 1305+ if ( !isset( $rules[$key] ) ){
 1306+ $this->log( "Validate Error: There is no rule for $key!" );
 1307+ //TODO: i18n
 1308+ $this->validate_setError( 'general', "Validate Error: There is no rule for $key!" );
 1309+ } else {
 1310+ $function = $rules[$key]['validate_function'];
 1311+ if (method_exists( $this, $function )){
 1312+ $this->{$function}( $key, $rules[$key]['error_form_token'] );
 1313+ } else {
 1314+ $this->log( "Validate Error: There is no $function function!" );
 1315+ //TODO: i18n
 1316+ $this->validate_setError( 'general', "Validate Error: There is no $function function!" );
 1317+ }
 1318+ }
 1319+
 1320+ }
 1321+ }
 1322+ }
 1323+
 1324+ /**
 1325+ * Builds the validation rule set for all the keys we're pulling.
 1326+ * TODO: Do some mapping here with i18n messages, too. We can't take this
 1327+ * into prod just throwing the generic at everything.
 1328+ * TODO: In general with this whole thing, the alphanumeric strategy should
 1329+ * be... revised. Clearly we can't have a list of 'good' characters.
 1330+ * Instead, we need to clean stuff that is clearly dangerous.
 1331+ * Also, maybe we just auto-assign the alphanumeric clean function to
 1332+ * anything that doesn't have other assignments, instead of dying nastily
 1333+ * when we have one with no assignment. That's probably more pleasant.
 1334+ * @return array An array of keys, the ways we want to validate them, and
 1335+ * what messages to set if they don't pass.
 1336+ * $array[$key] = array(
 1337+ * 'validate_function' => $function_name,
 1338+ * 'error_form_token' => $error_token
 1339+ * )
 1340+ */
 1341+ protected function buildValidationRules(){
 1342+ $rules = array();
 1343+
 1344+ //you should group these jerks by type or something.
 1345+
 1346+ //initial build based on general functions to run for validation.
 1347+ $numeric = array(
 1348+ 'amount',
 1349+ 'amountGiven',
 1350+ 'amountOther',
 1351+ 'card_num',
 1352+ 'cvv',
 1353+ 'contribution_tracking_id',
 1354+ 'utm_source_id',
 1355+ 'account_number',
 1356+ 'expiration',
 1357+ 'order_id',
 1358+ 'i_order_id',
 1359+ 'numAttempt'
 1360+ );
 1361+
 1362+ foreach ($numeric as $key){
 1363+ $rules[$key]['validate_function'] = 'validate_numeric';
 1364+ }
 1365+
 1366+ $alphanumeric = array(
 1367+ 'fname',
 1368+ 'mname',
 1369+ 'lname',
 1370+ 'street',
 1371+ 'city',
 1372+ 'state',
 1373+ 'zip',
 1374+ 'country',
 1375+ 'fname2',
 1376+ 'lname2',
 1377+ 'street2',
 1378+ 'city2',
 1379+ 'state2',
 1380+ 'zip2',
 1381+ 'country2',
 1382+ 'size',
 1383+ 'premium_language',
 1384+ 'card_type',
 1385+ 'currency',
 1386+ 'currency_code',
 1387+ 'payment_method',
 1388+ 'payment_submethod',
 1389+ 'form_name',
 1390+ 'ffname',
 1391+
 1392+ //for lack of a better idea what to do with these things, I'm just gonna leave these here.
 1393+ //If any of them need to be numeric or boolean or dealt with specially, do that.
 1394+ 'issuer_id',
 1395+ 'referrer',
 1396+ 'utm_source',
 1397+ 'utm_medium',
 1398+ 'utm_campaign',
 1399+ 'language',
 1400+ 'uselang',
 1401+ 'comment',
 1402+ 'token',
 1403+ 'data_hash',
 1404+ 'action',
 1405+ 'gateway',
 1406+ 'owa_session',
 1407+ 'owa_ref',
 1408+ 'descriptor',
 1409+ 'account_name',
 1410+ 'authorization_id',
 1411+ 'bank_check_digit',
 1412+ 'bank_name',
 1413+ 'bank_code',
 1414+ 'branch_code',
 1415+ 'country_code_bank',
 1416+ 'date_collect',
 1417+ 'direct_debit_text',
 1418+ 'iban',
 1419+ 'transaction_type',
 1420+ );
 1421+
 1422+ foreach ($alphanumeric as $key){
 1423+ $rules[$key]['validate_function'] = 'validate_alphanumeric_with_cleaning';
 1424+ }
 1425+
 1426+ $boolean = array(
 1427+ 'comment-option',
 1428+ 'email-opt',
 1429+ '_cache_',
 1430+ 'anonymous',
 1431+ 'optout',
 1432+ );
 1433+
 1434+ foreach ($boolean as $key){
 1435+ $rules[$key]['validate_function'] = 'validate_boolean';
 1436+ }
 1437+
 1438+ $rules['email']['validate_function'] = 'validate_email';
 1439+
 1440+
 1441+ //now, set the error token to use...
 1442+
 1443+ foreach ( $rules as $key => $value ){
 1444+ $error_token = 'general';
 1445+ switch ( $key ) {
 1446+ case 'amountGiven' :
 1447+ case 'amountOther' :
 1448+ $error_token = 'amount';
 1449+ break;
 1450+ case 'email' :
 1451+ $error_token = 'emailAdd';
 1452+ break;
 1453+ case 'amount' :
 1454+ case 'card_num':
 1455+ case 'card_type':
 1456+ case 'cvv':
 1457+ case 'fname':
 1458+ case 'lname':
 1459+ case 'city':
 1460+ case 'country':
 1461+ case 'street':
 1462+ case 'state':
 1463+ case 'zip':
 1464+ $error_token = $key;
 1465+ break;
 1466+ }
 1467+ $rules[$key]['error_form_token'] = $error_token;
 1468+ }
 1469+
 1470+ return $rules;
 1471+ }
 1472+
 1473+ /**
 1474+ * Sets an error found during validation.
 1475+ * @param string $error_token The error token to set for this error.
 1476+ * (See RapidHTML::$error_tokens for possibilities)
 1477+ * @param string $msg The translated message to display at that error token.
 1478+ */
 1479+ protected function validate_setError( $error_token, $msg ){
 1480+ if ( !$this->validationErrors ){
 1481+ $this->validationErrors = array();
 1482+ }
 1483+ $this->validationErrors[$error_token] = $msg;
 1484+
 1485+ }
 1486+
 1487+ /**
 1488+ * validatedOK
 1489+ * Checks to see if the data validated ok (no errors).
 1490+ * @return boolean True if no errors, false if errors exist.
 1491+ */
 1492+ public function validatedOK() {
 1493+ if ( is_array( $this->validationErrors ) ){
 1494+ return false;
 1495+ }
 1496+ return true;
 1497+ }
 1498+
 1499+ /**
 1500+ * getValidationErrors
 1501+ * Returns the errors set on data validation.
 1502+ * @return mixed Array if errors are set, else false.
 1503+ */
 1504+ public function getValidationErrors() {
 1505+ return $this->validationErrors;
 1506+ }
 1507+
 1508+ /**
 1509+ * validate_email
 1510+ * validateAllInput helper function
 1511+ * To validate any input value using this function, add a line to
 1512+ * $this->buildValidationRules() specifying the function name as the field
 1513+ * name's 'validate_function'.
 1514+ * @param string $key The name of the field to validate.
 1515+ * @param string $error_token As in RapidHTML, the pre-defined area of the
 1516+ * form in which to display the error.
 1517+ */
 1518+ protected function validate_email( $key, $error_token ){
 1519+ // is email address valid?
 1520+ $isEmail = User::isValidEmailAddr( $this->getVal($key) );
 1521+
 1522+ // create error message (supercedes empty field message)
 1523+ if ( !$isEmail ) {
 1524+ $this->log( __FUNCTION__ . " $key is not an email address.", LOG_DEBUG );
 1525+ $this->validate_setError( $error_token, wfMsg( 'donate_interface-error-msg-email' ) );
 1526+ }
 1527+ }
 1528+
 1529+ /**
 1530+ * validate_boolean
 1531+ * validateAllInput helper function
 1532+ * To validate any input value using this function, add a line to
 1533+ * $this->buildValidationRules() specifying the function name as the field
 1534+ * name's 'validate_function'.
 1535+ * @param string $key The name of the field to validate.
 1536+ * @param string $error_token As in RapidHTML, the pre-defined area of the
 1537+ * form in which to display the error.
 1538+ */
 1539+ protected function validate_boolean( $key, $error_token ){
 1540+ $val = $this->getVal($key);
 1541+ if ( $val === 0 || $val === 1 ) {
 1542+ $this->log( __FUNCTION__ . " $key is not boolean.", LOG_DEBUG );
 1543+ $this->validate_setError( $error_token, wfMsg( 'donate_interface-error-msg-general' ) );
 1544+ }
 1545+
 1546+ }
 1547+
 1548+ /**
 1549+ * validate_alphanumeric_with_cleaning
 1550+ * validateAllInput helper function
 1551+ * To validate and clean any input value using this function, add a line to
 1552+ * $this->buildValidationRules() specifying the function name as the field
 1553+ * name's 'validate_function'.
 1554+ * TODO: Something even remotely useful here. Like the cleaning promised in
 1555+ * the function name.
 1556+ * @param string $key The name of the field to validate.
 1557+ * @param string $error_token As in RapidHTML, the pre-defined area of the
 1558+ * form in which to display the error.
 1559+ */
 1560+ protected function validate_alphanumeric_with_cleaning( $key, $error_token ){
 1561+ $val = $this->getVal($key);
 1562+
 1563+ //instead of validating here, we should probably be proactively removing badness.
 1564+ if ( preg_match( '/%/', $val ) ) { //this is dumb and bad. Fixit.
 1565+ $this->log( __FUNCTION__ . " $key is not valid alphanumeric. $val", LOG_DEBUG );
 1566+ //oooh. This blows.
 1567+ $this->validate_setError( $error_token, wfMsg( 'donate_interface-error-msg-general' ) );
 1568+ }
 1569+ }
 1570+
 1571+ /**
 1572+ * validate_numeric
 1573+ * validateAllInput helper function
 1574+ * To validate any input value using this function, add a line to
 1575+ * $this->buildValidationRules() specifying the function name as the field
 1576+ * name's 'validate_function'.
 1577+ * @param string $key The name of the field to validate.
 1578+ * @param string $error_token As in RapidHTML, the pre-defined area of the
 1579+ * form in which to display the error.
 1580+ */
 1581+ protected function validate_numeric( $key, $error_token ){
 1582+ $val = $this->getVal($key);
 1583+
 1584+ //instead of validating here, we should probably be doing something else entirely.
 1585+ if ( !is_numeric( $val ) ) {
 1586+ $this->log( __FUNCTION__ . " $key is not valid numeric format. $val", LOG_DEBUG );
 1587+ //oooh. This blows.
 1588+ $this->validate_setError( $error_token, wfMsg( 'donate_interface-error-msg-general' ) );
 1589+ }
 1590+ }
12911591 }
12921592
12931593 ?>

Follow-up revisions

RevisionCommit summaryAuthorDate
r112287MFT r101785, r105938, r105941, r105953, r106109, r106158, r106259, r106366, r...khorn01:29, 24 February 2012

Comments

#Comment by Awjrichards (talk | contribs)   22:41, 22 December 2011

I heard rumors this is all going to change - holding off on review for now.

Status & tagging log