/** * 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(); }