/**
  * populateData helper function
  * If donor session data has been set, pull the fields in the session that
  * are populated, and merge that with the data set we already have.
  */
 protected function integrateDataFromSession()
 {
     if ($this->gateway->isBatchProcessor()) {
         return;
     }
     /**
      * if the thing coming in from the session isn't already something,
      * replace it.
      * if it is: assume that the session data was meant to be replaced
      * with better data.
      * ...unless it's an explicit $overwrite
      **/
     $donorData = WmfFramework::getSessionValue('Donor');
     if (is_null($donorData)) {
         return;
     }
     //fields that should always overwrite with their original values
     $overwrite = array('referrer', 'contribution_tracking_id');
     foreach ($donorData as $key => $val) {
         if (!$this->isSomething($key)) {
             $this->setVal($key, $val);
         } else {
             if (in_array($key, $overwrite)) {
                 $this->setVal($key, $val);
             }
         }
     }
 }
 protected function setBillingAgreementDetailsIfUnset($billingAgreementId)
 {
     if ($this->session_getData('billing_agreements', $billingAgreementId)) {
         return;
     }
     $this->logger->info("Setting details for billing agreement {$billingAgreementId}");
     $this->callPwaClient('setBillingAgreementDetails', array('amazon_billing_agreement_id' => $billingAgreementId, 'seller_note' => WmfFramework::formatMessage('donate_interface-monthly-donation-description'), 'seller_billing_agreement_id' => $this->getData_Staged('order_id')));
     $billingAgreements = WmfFramework::getSessionValue('billing_agreements');
     $billingAgreements[$billingAgreementId] = true;
     WmfFramework::setSessionValue('billing_agreements', $billingAgreements);
 }
 /**
  * Run the filter if we haven't for this session, and set a flag
  * @param GatewayType $gateway_adapter
  * @param Gateway_Extras_CustomFilters $custom_filter_object
  * @return bool
  */
 public static function onInitialFilter($gateway_adapter, $custom_filter_object)
 {
     if (!$gateway_adapter->getGlobal('EnableIPVelocityFilter')) {
         return true;
     }
     if (WmfFramework::getSessionValue(self::RAN_INITIAL)) {
         return true;
     }
     WmfFramework::setSessionValue(self::RAN_INITIAL, true);
     $gateway_adapter->debugarray[] = 'IP Velocity onFilter!';
     return self::singleton($gateway_adapter, $custom_filter_object)->filter();
 }
 /**
  * buildOrderIDSources: Uses the 'alt_locations' array in the order id
  * metadata, to build an array of all possible candidates for order_id.
  * This will also weed out candidates that do not meet the
  * gateway-specific data constraints for that field, and are therefore
  * invalid.
  *
  * @TODO: Data Item Class. There should be a class that keeps track of
  * the metadata for every field we use (everything that currently comes
  * back from DonationData), that can be overridden per gateway. Revisit
  * this in a more universal way when that time comes.
  */
 public function buildOrderIDSources()
 {
     static $built = false;
     if ($built && isset($this->order_id_candidates)) {
         //once per request is plenty
         return;
     }
     //pull all order ids and variants from all their usual locations
     $locations = array('request' => 'order_id', 'session' => array('Donor' => 'order_id'));
     $alt_locations = $this->getOrderIDMeta('alt_locations');
     if ($alt_locations && is_array($alt_locations)) {
         foreach ($alt_locations as $var => $key) {
             $locations[$var] = $key;
         }
     }
     if ($this->isBatchProcessor()) {
         // Can't use request or session from here.
         $locations = array_diff_key($locations, array_flip(array('request', 'session')));
     }
     //Now pull all the locations and populate the candidate array.
     $oid_candidates = array();
     foreach ($locations as $var => $key) {
         switch ($var) {
             case "request":
                 $value = WmfFramework::getRequestValue($key, '');
                 if ($value !== '') {
                     $oid_candidates[$var] = $value;
                 }
                 break;
             case "session":
                 if (is_array($key)) {
                     foreach ($key as $subkey => $subvalue) {
                         $parentVal = WmfFramework::getSessionValue($subkey);
                         if (is_array($parentVal) && array_key_exists($subvalue, $parentVal)) {
                             $oid_candidates['session' . $subkey . $subvalue] = $parentVal[$subvalue];
                         }
                     }
                 } else {
                     $val = WmfFramework::getSessionValue($key);
                     if (!is_null($val)) {
                         $oid_candidates[$var] = $val;
                     }
                 }
                 break;
             default:
                 if (!is_array($key) && array_key_exists($key, ${$var})) {
                     //simple case first. This is a direct key in $var.
                     $oid_candidates[$var] = ${$var}[$key];
                 }
                 if (is_array($key)) {
                     foreach ($key as $subkey => $subvalue) {
                         if (array_key_exists($subkey, ${$var}) && array_key_exists($subvalue, ${$var}[$subkey])) {
                             $oid_candidates[$var . $subkey . $subvalue] = ${$var}[$subkey][$subvalue];
                         }
                     }
                 }
                 break;
         }
     }
     //unset every invalid candidate
     foreach ($oid_candidates as $source => $value) {
         if (empty($value) || !$this->validateDataConstraintsMet('order_id', $value)) {
             unset($oid_candidates[$source]);
         }
     }
     $this->order_id_candidates = $oid_candidates;
     $built = true;
 }
 /**
  * Although this function actually does the filtering, as this is a singleton pattern
  * we only want one instance actually using it.
  *
  * @return bool false if we should stop processing
  */
 private function filter()
 {
     $user_ip = $this->gateway_adapter->getData_Unstaged_Escaped('user_ip');
     // Determine IP status before doing anything complex
     $wl = DataValidator::ip_is_listed($user_ip, $this->gateway_adapter->getGlobal('IPWhitelist'));
     $bl = DataValidator::ip_is_listed($user_ip, $this->gateway_adapter->getGlobal('IPBlacklist'));
     if ($wl) {
         $this->gateway_adapter->debugarray[] = "SessionVelocity: IP present in whitelist.";
         return true;
     }
     if ($bl) {
         $this->gateway_adapter->debugarray[] = "SessionVelocity: IP present in blacklist.";
         return false;
     }
     // Open a session if it doesn't already exist
     $this->gateway_adapter->session_ensure();
     // Obtain some useful information
     $gateway = $this->gateway_adapter->getIdentifier();
     $transaction = $this->gateway_adapter->getCurrentTransaction();
     $cRequestTime = $_SERVER['REQUEST_TIME'];
     $decayRate = $this->getVar('DecayRate', $transaction);
     $threshold = $this->getVar('Threshold', $transaction);
     $multiplier = $this->getVar('Multiplier', $transaction);
     // Initialize the filter
     $sessionData = WmfFramework::getSessionValue(self::SESS_ROOT);
     if (!is_array($sessionData)) {
         $sessionData = array();
     }
     if (!array_key_exists($gateway, $sessionData)) {
         $sessionData[$gateway] = array();
     }
     if (!array_key_exists($transaction, $sessionData[$gateway])) {
         $sessionData[$gateway][$transaction] = array($this::SESS_SCORE => 0, $this::SESS_TIME => $cRequestTime, $this::SESS_MULTIPLIER => 1);
     }
     $lastTime = $sessionData[$gateway][$transaction][self::SESS_TIME];
     $score = $sessionData[$gateway][$transaction][self::SESS_SCORE];
     $lastMultiplier = $sessionData[$gateway][$transaction][self::SESS_MULTIPLIER];
     // Update the filter if it's stale
     if ($cRequestTime != $lastTime) {
         $score = max(0, $score - ($cRequestTime - $lastTime) * $decayRate);
         $score += $this->getVar('HitScore', $transaction) * $lastMultiplier;
         $sessionData[$gateway][$transaction][$this::SESS_SCORE] = $score;
         $sessionData[$gateway][$transaction][$this::SESS_TIME] = $cRequestTime;
         $sessionData[$gateway][$transaction][$this::SESS_MULTIPLIER] = $lastMultiplier * $multiplier;
     }
     // Store the results
     WmfFramework::setSessionValue(self::SESS_ROOT, $sessionData);
     // Analyze the filter results
     if ($score >= $threshold) {
         // Ahh!!! Failure!!! Sloooooooow doooowwwwnnnn
         $this->fraud_logger->alert("SessionVelocity: Rejecting request due to score of {$score}");
         $this->sendAntifraudMessage('reject', $score, array('SessionVelocity' => $score));
         $retval = false;
     } else {
         $retval = true;
     }
     $this->fraud_logger->debug("SessionVelocity: ({$gateway}, {$transaction}) Score: {$score}, " . "AllowAction: {$retval}, DecayRate: {$decayRate}, " . "Threshold: {$threshold}, Multiplier: {$lastMultiplier}");
     return $retval;
 }
 /**
  * Gets the action calculated on the last filter run. If there are no
  * risk scores stored in session, throws a RuntimeException. Even if
  * all filters are disabled, we should have stored 'initial' => 0.
  *
  * @param GatewayType $gateway_adapter
  * @return string
  */
 public static function determineStoredAction(GatewayType $gateway_adapter)
 {
     if (!WmfFramework::getSessionValue('risk_scores')) {
         throw new RuntimeException('No stored risk scores');
     }
     return self::singleton($gateway_adapter)->determineAction();
 }