/** * Returns true if and only if $value meets the validation requirements * * If $value fails validation, then this method returns false, and * getMessages() will return an array of messages that explain why the * validation failed. * * @param mixed $value * @return boolean * @throws \Zend_Valid_Exception If validation of $value is impossible */ public function isValid($value) { if ($throttleSettings = $this->project->getAskThrottleSettings()) { // Prune the database for (very) old attempts $where = $this->db->quoteInto('gta_datetime < DATE_SUB(NOW(), INTERVAL ? second)', $throttleSettings['period'] * 20); $this->db->delete('gems__token_attempts', $where); // Retrieve the number of failed attempts that occurred within the specified window $select = $this->db->select(); $select->from('gems__token_attempts', array(new \Zend_Db_Expr('COUNT(*) AS attempts'), new \Zend_Db_Expr('UNIX_TIMESTAMP(MAX(gta_datetime)) - UNIX_TIMESTAMP() AS last')))->where('gta_datetime > DATE_SUB(NOW(), INTERVAL ? second)', $throttleSettings['period']); $attemptData = $this->db->fetchRow($select); $remainingDelay = $attemptData['last'] + $throttleSettings['delay']; // \MUtil_Echo::track($throttleSettings, $attemptData, $remainingDelay); if ($attemptData['attempts'] > $throttleSettings['threshold'] && $remainingDelay > 0) { $this->logger->log("Possible token brute force attack, throttling for {$remainingDelay} seconds", \Zend_Log::ERR); $this->_messages = $this->translate->_('The server is currently busy, please wait a while and try again.'); return false; } } // The pure token check if ($this->isValidToken($value)) { return true; } $max_length = $this->tracker->getTokenLibrary()->getLength(); $this->db->insert('gems__token_attempts', array('gta_id_token' => substr($value, 0, $max_length), 'gta_ip_address' => $this->getRequest()->getClientIp())); return false; }
/** * Survey dependent calculations / answer changes that must occur after a survey is completed * * @param type $tokenId The tokend the answers are for * @param array $tokenAnswers Array with answers. May be changed in process * @return array The changed values */ public function handleBeforeAnswering() { $survey = $this->getSurvey(); $event = $survey->getSurveyBeforeAnsweringEvent(); if ($event) { try { $changed = $event->processTokenInsertion($this); if ($changed && is_array($changed)) { $this->setRawAnswers($changed); if (\Gems_Tracker::$verbose) { \MUtil_Echo::r($changed, 'Source values for ' . $this->_tokenId . ' changed by event.'); } return $changed; } } catch (\Exception $e) { $this->logger->log(sprintf("Before answering event error for token %s on survey '%s' using event '%s': %s", $this->_tokenId, $this->getSurveyName(), $event->getEventName(), $e->getMessage()), \Zend_Log::ERR); } } }