input, Forge] // Require: ->validate() or access::verify_csrf\( if ($function && $open_braces >= 2) { if ($token[0] == T_STRING) { if ($token[1] == "access" && self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && self::_token_matches(array(T_STRING, "require"), $tokens, $token_number + 2) && self::_token_matches("(", $tokens, $token_number + 3)) { $token_number += 3; $function->checks_authorization(true); } else if ($token[1] == "access" && self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && self::_token_matches(array(T_STRING, "verify_csrf"), $tokens, $token_number + 2) && self::_token_matches("(", $tokens, $token_number + 3)) { $token_number += 3; $function->checks_csrf(true); } else if (in_array($token[1], array("Input", "Forge")) && self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1)) { $token_number++; $function->uses_input(true); } } else if ($token == T_VARIABLE) { if ($token[1] == '$this' && self::_token_matches(array(T_OBJECT_OPERATOR), $tokens, $token_number + 1) && self::_token_matches(array(T_STRING, "input"), $tokens, $token_number + 2)) { $token_number += 2; $function->uses_input(true); } } else if ($token[0] == T_OBJECT_OPERATOR) { if (self::_token_matches(array(T_STRING), "validate", $token_number + 1) && self::_token_matches("(", $tokens, $token_number + 2)) { $token_number += 2; $function->checks_csrf(true); } } } } } } // Generate the report $new = TMPPATH . "controller_auth_data.txt"; $fd = fopen($new, "wb"); ksort($found); foreach ($found as $controller => $frames) { foreach ($functions as $function) { $flags = array(); if ($function->uses_input() && !$function->checks_csrf()) { $flags[] = "DIRTY_CSRF"; } if ($function->checks_authorization()) { $flags[] = "DIRTY_AUTH"; } if (!$flags) { // Don't print CLEAN instances continue; } fprintf($fd, "%-60s %-20s %-21s\n", $controller, $function->name, implode("|", $flags)); } } fclose($fd); // Compare with the expected report from our golden file. $canonical = MODPATH . "gallery/tests/controller_auth_data.txt"; exec("diff $canonical $new", $output, $return_value); $this->assert_false( $return_value, "Controller auth golden file mismatch. Output:\n" . implode("\n", $output) ); } private static function _token_matches($expected_token, &$tokens, $token_number) { if (!isset($tokens[$token_number])) { return false; } $token = $tokens[$token_number]; if (is_array($expected_token)) { for ($i = 0; $i < count($expected_token); $i++) { if ($expected_token[$i] != $token[$i]) { return false; } } return true; } else { return $expected_token == $token; } } static function _function($name, $line) { return new Controller_Auth_Test_Function($name, $line); } } class Controller_Auth_Test_Function { public $name; public $line; private $_uses_input = false; private $_checks_authorization = false; private $_checks_csrf = false; function __construct($name, $line) { $this->name = $name; $this->line = $line; } function uses_input($val=null) { if ($val !== null) { $this->_uses_input = $val; } return $this->_uses_input; } function checks_authorization($val) { if ($val !== null) { $this->_checks_authorization = $val; } return $this->_checks_authorization; } function checks_csrf($val) { if ($val !== null) { $this->_checks_csrf = $val; } return $this->_checks_csrf; } }