public function validate(GatewayType $adapter, $normalized, &$errors) { if (!isset($normalized['amount']) || !isset($normalized['currency_code'])) { // Not enough info to validate return; } if (isset($errors['currency_code'])) { // Already displaying an error return; } $value = $normalized['amount']; if (self::isZeroIsh($value)) { $errors['amount'] = DataValidator::getErrorMessage('amount', 'not_empty', $normalized['language']); return; } $currency = $normalized['currency_code']; $min = self::convert($adapter->getGlobal('PriceFloor'), $currency); $max = self::convert($adapter->getGlobal('PriceCeiling'), $currency); if (!is_numeric($value) || $value < 0) { $errors['amount'] = WmfFramework::formatMessage('donate_interface-error-msg-invalid-amount'); } else { if ($value > $max) { // FIXME: should format the currency values in this message $errors['amount'] = WmfFramework::formatMessage('donate_interface-bigamount-error', $max, $currency, $adapter->getGlobal('MajorGiftsEmail')); } else { if ($value < $min) { $locale = $normalized['language'] . '_' . $normalized['country']; $formattedMin = self::format($min, $currency, $locale); $errors['amount'] = WmfFramework::formatMessage('donate_interface-smallamount-error', $formattedMin); } } } }
function defineTransactions() { $this->transactions = array(); $this->transactions['Donate'] = array('request' => array('amount', 'currency_code', 'country', 'business', 'cancel_return', 'cmd', 'item_name', 'item_number', 'no_note', 'return', 'custom', 'lc'), 'values' => array('business' => $this->account_config['AccountEmail'], 'cancel_return' => ResultPages::getCancelPage($this), 'cmd' => '_donations', 'item_number' => 'DONATE', 'item_name' => WmfFramework::formatMessage('donate_interface-donation-description'), 'no_note' => 0, 'return' => ResultPages::getThankYouPage($this))); $this->transactions['DonateXclick'] = array('request' => array('cmd', 'item_number', 'item_name', 'cancel_return', 'no_note', 'return', 'business', 'no_shipping', 'amount', 'currency_code', 'country', 'custom'), 'values' => array('item_number' => 'DONATE', 'item_name' => WmfFramework::formatMessage('donate_interface-donation-description'), 'cancel_return' => ResultPages::getCancelPage($this), 'no_note' => '1', 'return' => ResultPages::getThankYouPage($this), 'business' => $this->account_config['AccountEmail'], 'cmd' => '_xclick', 'no_shipping' => '1')); $this->transactions['DonateRecurring'] = array('request' => array('a3', 'currency_code', 'country', 'business', 'cancel_return', 'cmd', 'item_name', 'item_number', 'no_note', 'return', 'custom', 't3', 'p3', 'src', 'srt', 'lc'), 'values' => array('business' => $this->account_config['AccountEmail'], 'cancel_return' => ResultPages::getCancelPage($this), 'cmd' => '_xclick-subscriptions', 'item_number' => 'DONATE', 'item_name' => WmfFramework::formatMessage('donate_interface-donation-description'), 'no_note' => 0, 'return' => ResultPages::getThankYouPage($this), 't3' => 'M', 'p3' => '1', 'src' => '1', 'srt' => $this->getGlobal('RecurringLength'))); }
/** * @param bool $rapidFail if true, render a form as a fail page rather than redirect * @param string $failPage either a wiki page title, or a URL to an external wiki * page title. * @param array $data information about the current request. * language, gateway, payment_method, and payment_submethod must be set * @param Psr\Log\LoggerInterface $logger * @return string full URL of the fail page, or just form name in case of rapidFail */ private static function getFailPageFromParams($rapidFail, $failPage, $data, LoggerInterface $logger) { if (isset($data['language'])) { $language = $data['language']; } else { $language = WmfFramework::getLanguageCode(); } // Prefer RapidFail. if ($rapidFail) { // choose which fail page to go for. try { $fail_ffname = GatewayFormChooser::getBestErrorForm($data['gateway'], $data['payment_method'], $data['payment_submethod']); return $fail_ffname; } catch (Exception $e) { $logger->error('Cannot determine best error form. ' . $e->getMessage()); } } if (filter_var($failPage, FILTER_VALIDATE_URL)) { return self::appendLanguageAndMakeURL($failPage, $language); } // FIXME: either add Special:FailPage to avoid depending on wiki content, // or update the content on payments to be consistent with the /lang // format of ThankYou pages so we can use appendLanguageAndMakeURL here. $failTitle = Title::newFromText($failPage); $url = wfAppendQuery($failTitle->getFullURL(), array('uselang' => $language)); return $url; }
public function setUp() { parent::setUp(); $this->queue_name = 'test-' . mt_rand(); $this->setMwGlobals(array('wgDonationInterfaceEnableQueue' => true, 'wgDonationInterfaceDefaultQueueServer' => array('type' => 'TestingQueue'), 'wgDonationInterfaceQueues' => array($this->queue_name => array()))); $this->transaction = array('amount' => '1.24', 'city' => 'Dunburger', 'contribution_tracking_id' => mt_rand(), 'correlation-id' => 'testgateway-' . mt_rand(), 'country' => 'US', 'currency_code' => 'USD', 'date' => time(), 'email' => '*****@*****.**', 'fname' => 'Jen', 'gateway_account' => 'default', 'gateway' => 'testgateway', 'gateway_txn_id' => mt_rand(), 'order_id' => mt_rand(), 'language' => 'en', 'lname' => 'Russ', 'payment_method' => 'cc', 'payment_submethod' => 'visa', 'php-message-class' => 'SmashPig\\CrmLink\\Messages\\DonationInterfaceMessage', 'response' => 'Gateway response something', 'state' => 'AK', 'street' => '1 Fake St.', 'user_ip' => '127.0.0.1', 'utm_source' => 'testing', 'zip' => '12345'); $this->expected_message = array('contribution_tracking_id' => $this->transaction['contribution_tracking_id'], 'utm_source' => 'testing', 'language' => 'en', 'email' => '*****@*****.**', 'first_name' => 'Jen', 'last_name' => 'Russ', 'street_address' => '1 Fake St.', 'city' => 'Dunburger', 'state_province' => 'AK', 'country' => 'US', 'postal_code' => '12345', 'gateway' => 'testgateway', 'gateway_account' => 'default', 'gateway_txn_id' => $this->transaction['gateway_txn_id'], 'order_id' => $this->transaction['order_id'], 'payment_method' => 'cc', 'payment_submethod' => 'visa', 'response' => 'Gateway response something', 'currency' => 'USD', 'fee' => '0', 'gross' => '1.24', 'user_ip' => '127.0.0.1', 'date' => (int) $this->transaction['date'], 'source_host' => WmfFramework::getHostname(), 'source_name' => 'DonationInterface', 'source_run_id' => getmypid(), 'source_type' => 'payments', 'source_version' => DonationQueue::getVersionStamp()); }
public static function getByCountry($country) { if (isset(self::$list[$country])) { $divisions = self::$list[$country]; // Localize subdivisions where possible if (isset(self::$keyBase[$country])) { foreach ($divisions as $abbr => $name) { $key = self::$keyBase[$country] . $abbr; if (WmfFramework::messageExists($key)) { $divisions[$abbr] = WmfFramework::formatMessage($key); } } } return $divisions; } return false; }
/** * Queue a message with the banner history ID sent on the URL, the * contribution tracking ID from DonationData, and some additional data. */ protected function queueAssociationOfIds() { $this->logger->debug('BannerHistoryLogIdProcessor::queueAssociationOfIds(): will ' . 'push to banner-history queue if required info is available.'); $bannerHistoryId = WmfFramework::getRequestValue(self::BANNER_HISTORY_LOG_ID_PARAM, null); // Campaigns may not have banner history enabled. For now, at least, // bow out silently if no banner history ID was sent. if (!$bannerHistoryId) { return; } $contributionTrackingId = $this->gatewayAdapter->getData_Unstaged_Escaped('contribution_tracking_id'); if (!$contributionTrackingId) { $this->logger->info('No contribution tracking ID for ' . 'banner-history queue ' . $bannerHistoryId . '.'); return; } $data = array('freeform' => true, 'banner_history_id' => $bannerHistoryId, 'contribution_tracking_id' => $contributionTrackingId); $this->logger->info('Pushing to banner-history queue.'); DonationQueue::instance()->push($data, 'banner-history'); }
public function stage(GatewayType $adapter, $normalized, &$stagedData) { if (!isset($normalized['language'])) { return; } $language = $normalized['language']; $adapterLanguages = $adapter->getAvailableLanguages(); if (!in_array($language, $adapterLanguages)) { $fallbacks = WmfFramework::getLanguageFallbacks($language); foreach ($fallbacks as $fallback) { if (in_array($fallback, $adapterLanguages)) { $language = $fallback; break; } } } if (!in_array($language, $adapterLanguages)) { $language = 'en'; } $stagedData['language'] = $language; }
/** * Returns a valid mediawiki language code to use for all the DonationInterface translations. * * Will only look at the currently configured language if the 'language' key * doesn't exist in the data set: Users may not have a language preference * set if we're bouncing between mediawiki instances for payments. * @param array $data A normalized DonationInterface data set. * @return string A valid mediawiki language code. */ public static function guessLanguage($data) { if (array_key_exists('language', $data) && WmfFramework::isValidBuiltInLanguageCode($data['language'])) { return $data['language']; } else { return WmfFramework::getLanguageCode(); } }
protected function write(array $record) { WmfFramework::debugLog($this->identifier, $record['message'], $record['level_name']); }
/** * This function limits the possible characters passed as template keys and * values to letters, numbers, hyphens and underscores. The function also * performs standard escaping of the passed values. * * @param string $string The unsafe string to escape and check for invalid characters * @return string Sanitized version of input */ public static function makeSafe($string) { $stripped = preg_replace('/[^-_\\w]/', '', $string); // theoretically this is overkill, but better safe than sorry return WmfFramework::sanitize(htmlspecialchars($stripped)); }
protected function authorizeOnBillingAgreement() { $billingAgreementId = $this->getData_Staged('subscr_id'); $this->logger->info("Authorizing and capturing payment on billing agreement {$billingAgreementId}"); $authResponse = $this->callPwaClient('authorizeOnBillingAgreement', array('amazon_billing_agreement_id' => $billingAgreementId, 'authorization_amount' => $this->getData_Staged('amount'), 'currency_code' => $this->getData_Staged('currency_code'), 'capture_now' => true, 'authorization_reference_id' => $this->getData_Staged('order_id'), 'seller_order_id' => $this->getData_Staged('order_id'), 'seller_note' => WmfFramework::formatMessage('donate_interface-monthly-donation-description'), 'transaction_timeout' => 0)); return $authResponse['AuthorizeOnBillingAgreementResult']['AuthorizationDetails']; }
/** * 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; }
function defineTransactions() { $this->transactions = array(); // https://developer.paypal.com/docs/classic/api/merchant/SetExpressCheckout_API_Operation_NVP/ $this->transactions['SetExpressCheckout'] = array('request' => array('USER', 'PWD', 'VERSION', 'METHOD', 'RETURNURL', 'CANCELURL', 'REQCONFIRMSHIPPING', 'NOSHIPPING', 'LOCALECODE', 'EMAIL', 'L_PAYMENTREQUEST_0_AMT0', 'L_PAYMENTREQUEST_0_DESC0', 'PAYMENTREQUEST_0_AMT', 'PAYMENTREQUEST_0_CURRENCYCODE', 'PAYMENTREQUEST_0_CUSTOM', 'PAYMENTREQUEST_0_DESC', 'PAYMENTREQUEST_0_INVNUM', 'PAYMENTREQUEST_0_ITEMAMT', 'PAYMENTREQUEST_0_PAYMENTACTION', 'PAYMENTREQUEST_0_PAYMENTREASON'), 'values' => array('USER' => $this->account_config['User'], 'PWD' => $this->account_config['Password'], 'VERSION' => self::API_VERSION, 'METHOD' => 'SetExpressCheckout', 'CANCELURL' => ResultPages::getCancelPage($this), 'REQCONFIRMSHIPPING' => 0, 'NOSHIPPING' => 1, 'L_PAYMENTREQUEST_0_DESC0' => WmfFramework::formatMessage('donate_interface-donation-description'), 'PAYMENTREQUEST_0_DESC' => WmfFramework::formatMessage('donate_interface-donation-description'), 'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale', 'PAYMENTREQUEST_0_PAYMENTREASON' => 'None'), 'response' => array('TOKEN')); // https://developer.paypal.com/docs/classic/api/merchant/SetExpressCheckout_API_Operation_NVP/ $this->transactions['SetExpressCheckout_recurring'] = array('request' => array('USER', 'PWD', 'VERSION', 'METHOD', 'RETURNURL', 'CANCELURL', 'REQCONFIRMSHIPPING', 'NOSHIPPING', 'LOCALECODE', 'EMAIL', 'L_BILLINGTYPE0', 'L_BILLINGAGREEMENTDESCRIPTION0', 'L_BILLINGAGREEMENTCUSTOM0', 'L_PAYMENTREQUEST_0_AMT0', 'L_PAYMENTREQUEST_0_NAME0', 'L_PAYMENTREQUEST_0_QTY0', 'MAXAMT', 'PAYMENTREQUEST_0_AMT', 'PAYMENTREQUEST_0_CURRENCYCODE', 'PAYMENTREQUEST_0_ITEMAMT'), 'values' => array('USER' => $this->account_config['User'], 'PWD' => $this->account_config['Password'], 'VERSION' => self::API_VERSION, 'METHOD' => 'SetExpressCheckout', 'CANCELURL' => ResultPages::getCancelPage($this), 'REQCONFIRMSHIPPING' => 0, 'NOSHIPPING' => 1, 'L_BILLINGTYPE0' => 'RecurringPayments', 'L_BILLINGAGREEMENTDESCRIPTION0' => WmfFramework::formatMessage('donate_interface-monthly-donation-description'), 'L_PAYMENTREQUEST_0_DESC0' => WmfFramework::formatMessage('donate_interface-monthly-donation-description'), 'L_PAYMENTREQUEST_0_NAME0' => WmfFramework::formatMessage('donate_interface-monthly-donation-description'), 'L_PAYMENTREQUEST_0_QTY0' => 1, 'PAYMENTREQUEST_0_DESC' => WmfFramework::formatMessage('donate_interface-monthly-donation-description'), 'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale', 'PAYMENTREQUEST_0_PAYMENTREASON' => 'None'), 'response' => array('TOKEN')); // Incoming parameters after returning from the PayPal workflow $this->transactions['ProcessReturn'] = array('request' => array('token', 'PayerID')); // https://developer.paypal.com/docs/classic/api/merchant/GetExpressCheckoutDetails_API_Operation_NVP/ $this->transactions['GetExpressCheckoutDetails'] = array('request' => array('USER', 'PWD', 'VERSION', 'METHOD', 'TOKEN'), 'values' => array('USER' => $this->account_config['User'], 'PWD' => $this->account_config['Password'], 'VERSION' => self::API_VERSION, 'METHOD' => 'GetExpressCheckoutDetails'), 'response' => array('ACK', 'TOKEN', 'CORRELATIONID', 'TIMESTAMP', 'CUSTOM', 'INVNUM', 'BILLINGAGREEMENTACCEPTEDSTATUS', 'REDIRECTREQUIRED', 'CHECKOUTSTATUS', 'EMAIL', 'PAYERID', 'COUNTRYCODE', 'FIRSTNAME', 'MIDDLENAME', 'LASTNAME', 'SUFFIX', 'PAYMENTREQUEST_0_AMT', 'PAYMENTREQUEST_0_CURRENCYCODE', 'PAYMENTREQUEST_0_INVNUM', 'PAYMENTREQUEST_0_TRANSACTIONID')); // https://developer.paypal.com/docs/classic/api/merchant/DoExpressCheckoutPayment_API_Operation_NVP/ $this->transactions['DoExpressCheckoutPayment'] = array('request' => array('USER', 'PWD', 'VERSION', 'METHOD', 'TOKEN', 'PAYERID', 'PAYMENTREQUEST_0_PAYMENTACTION', 'PAYMENTREQUEST_0_AMT', 'PAYMENTREQUEST_0_CURRENCYCODE', 'PAYMENTREQUEST_0_CUSTOM', 'PAYMENTREQUEST_0_DESC', 'PAYMENTREQUEST_0_INVNUM', 'PAYMENTREQUEST_0_ITEMAMT', 'PAYMENTREQUEST_0_PAYMENTACTION', 'PAYMENTREQUEST_0_PAYMENTREASON'), 'values' => array('USER' => $this->account_config['User'], 'PWD' => $this->account_config['Password'], 'VERSION' => self::API_VERSION, 'METHOD' => 'DoExpressCheckoutPayment', 'PAYMENTREQUEST_0_DESC' => WmfFramework::formatMessage('donate_interface-donation-description'), 'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale', 'PAYMENTREQUEST_0_PAYMENTREASON' => 'None')); // https://developer.paypal.com/docs/classic/api/merchant/CreateRecurringPaymentsProfile_API_Operation_NVP/ $this->transactions['CreateRecurringPaymentsProfile'] = array('request' => array('USER', 'PWD', 'VERSION', 'METHOD', 'TOKEN', 'DESC', 'PROFILESTARTDATE', 'PROFILEREFERENCE', 'AUTOBILLOUTAMT', 'BILLINGPERIOD', 'BILLINGFREQUENCY', 'TOTALBILLINGCYCLES', 'MAXFAILEDPAYMENTS', 'AMT', 'CURRENCYCODE', 'EMAIL'), 'values' => array('USER' => $this->account_config['User'], 'PWD' => $this->account_config['Password'], 'VERSION' => self::API_VERSION, 'METHOD' => 'CreateRecurringPaymentsProfile', 'DESC' => WmfFramework::formatMessage('donate_interface-monthly-donation-description'), 'AUTOBILLOUTAMT' => 'NoAutoBill', 'BILLINGPERIOD' => 'Month', 'BILLINGFREQUENCY' => 1, 'TOTALBILLINGCYCLES' => 0, 'MAXFAILEDPAYMENTS' => 3), 'response' => array('PROFILEID', 'PROFILESTATUS', 'TRANSACTIONID')); // Add the Signature field to all API calls, if necessary. // Note that this gives crappy security, vulnerable to replay attacks. // The signature is static, not a checksum of the request. if (!$this->isCertificateAuthentication()) { foreach ($this->transactions as $_name => &$info) { if (isset($info['request'])) { $info['request'][] = 'SIGNATURE'; $info['values']['SIGNATURE'] = $this->account_config['Signature']; } } } }
protected function __construct() { $this->source_fields = array('source_host' => WmfFramework::getHostname(), 'source_name' => 'DonationInterface', 'source_run_id' => getmypid(), 'source_type' => 'payments', 'source_version' => self::getVersionStamp()); }
/** * Sets communication status and errors for responses to NewInvoice * @param array $response */ protected function processNewInvoiceResponse($response) { // Increment sequence number so next NewInvoice call gets a new order ID $this->incrementSequenceNumber(); if (!isset($response['status'])) { $this->transaction_response->setCommunicationStatus(false); $this->logger->error('AstroPay response does not have a status code'); throw new ResponseProcessingException('AstroPay response does not have a status code', ResponseCodes::MISSING_REQUIRED_DATA); } $this->transaction_response->setCommunicationStatus(true); if ($response['status'] === '0') { if (!isset($response['link'])) { $this->logger->error('AstroPay NewInvoice success has no link'); throw new ResponseProcessingException('AstroPay NewInvoice success has no link', ResponseCodes::MISSING_REQUIRED_DATA); } } else { $logme = 'AstroPay response has non-zero status. Full response: ' . print_r($response, true); $this->logger->warning($logme); $code = 'internal-0000'; $message = $this->getErrorMapByCodeAndTranslate($code); $context = null; if (isset($response['desc'])) { // error codes are unreliable, so we have to examine the description if (preg_match('/^invoice already used/i', $response['desc'])) { $this->logger->error('Order ID collision! Starting again.'); throw new ResponseProcessingException('Order ID collision! Starting again.', ResponseCodes::DUPLICATE_ORDER_ID, array('order_id')); } else { if (preg_match('/^could not (register user|make the deposit)/i', $response['desc'])) { // AstroPay is overwhelmed. Tell the donor to try again soon. $message = WmfFramework::formatMessage('donate_interface-try-again'); } else { if (preg_match('/^user (unauthorized|blacklisted)/i', $response['desc'])) { // They are blacklisted by AstroPay for shady doings, // or listed delinquent by their government. // Either way, we can't process 'em through AstroPay $this->finalizeInternalStatus(FinalStatus::FAILED); } else { if (preg_match('/^the user limit has been exceeded/i', $response['desc'])) { // They've spent too much via AstroPay today. // Setting context to 'amount' will tell the form to treat // this like a validation error and make amount editable. $context = 'amount'; $message = WmfFramework::formatMessage('donate_interface-error-msg-limit'); } else { if (preg_match('/param x_cpf$/i', $response['desc'])) { // Something wrong with the fiscal number $context = 'fiscal_number'; $language = $this->dataObj->getVal_Escaped('language'); $country = $this->dataObj->getVal_Escaped('country'); $message = DataValidator::getErrorMessage('fiscal_number', 'calculated', $language, $country); } else { if (preg_match('/invalid control/i', $response['desc'])) { // They think we screwed up the signature. Log what we signed. $signed = AstroPaySignature::getNewInvoiceMessage($this->getData_Staged()); $signature = $this->getData_Staged('control'); $this->logger->error("{$logme} Signed message: '{$signed}' Signature: '{$signature}'"); } else { // Some less common error. Also log message at 'error' level $this->logger->error($logme); } } } } } } } $this->transaction_response->setErrors(array($code => array('message' => $message, 'debugInfo' => $logme, 'logLevel' => LogLevel::WARNING, 'context' => $context))); } }
/** * 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(); }
/** * Builds minfraud query from user input * * Required: * - city * - country * - i: Client IPA * - license_key * - postal * - region * * Optional that we are sending: * - bin: First 6 digits of the card * - domain: send the domain of the email address * - emailMD5: send an MD5 of the email address * - txnID: The internal transaction id of the contribution. * * @param array $data * @return array containing hash for minfraud query */ protected function build_query(array $data) { // mapping of data keys -> minfraud array keys $map = array("city" => "city", "region" => "state", "postal" => "zip", "country" => "country", "domain" => "email", "emailMD5" => "email", "bin" => "card_num", "txnID" => "contribution_tracking_id"); $this->minfraudQuery = array(); // minfraud license key $this->minfraudQuery["license_key"] = $this->minfraudLicenseKey; // user's IP address $this->minfraudQuery["i"] = $this->gateway_adapter->getData_Unstaged_Escaped('user_ip'); // We only have access to these fields when the user's request is still // present, but not when in batch mode. if (!$this->gateway_adapter->isBatchProcessor()) { // user's user agent $this->minfraudQuery['user_agent'] = WmfFramework::getRequestHeader('user-agent'); // user's language $this->minfraudQuery['accept_language'] = WmfFramework::getRequestHeader('accept-language'); } // fetch the array of country codes $country_codes = CountryCodes::getCountryCodes(); // loop through the map and add pertinent values from $data to the hash foreach ($map as $key => $value) { // do some data processing to clean up values for minfraud switch ($key) { case "domain": // get just the domain from the email address $newdata[$value] = substr(strstr($data[$value], '@'), 1); break; case "bin": // get just the first 6 digits from CC#... if we have one. $bin = ''; if (isset($data[$value])) { $bin = substr($data[$value], 0, 6); } $newdata[$value] = $bin; break; case "country": $newdata[$value] = $country_codes[$data[$value]]; break; case "emailMD5": $newdata[$value] = $this->get_ccfd()->filter_field($key, $data[$value]); break; default: $newdata[$value] = $data[$value]; } $this->minfraudQuery[$key] = $newdata[$value]; } return $this->minfraudQuery; }
/** * 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; }
public function testTooLittleBbd() { $this->normalized['currency_code'] = 'BBD'; $this->normalized['amount'] = '2.95'; $this->validate(); $this->assertNotEmpty($this->errors, 'No error for diminutive amount (BBD)'); $formattedMin = Amount::format(3.0, 'BBD', 'en_US'); $expected = WmfFramework::formatMessage('donate_interface-smallamount-error', $formattedMin); $this->assertEquals($expected, $this->errors['amount'], 'Wrong error message for diminutive amount (BBD)'); }
/** * Basically, this is a wrapper for the WebRequest wasPosted function that * won't give us notices if we weren't even a web request. * I realize this is pretty lame. * Notices, however, are more lame. * @staticvar string $posted Keeps track so we don't have to figure it out twice. */ public function wasPosted() { static $posted = null; if ($posted === null) { $posted = array_key_exists('REQUEST_METHOD', $_SERVER) && WmfFramework::isPosted(); } return $posted; }
/** * 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(); }