Version 4.5.0
This commit is contained in:
1 parent
1a0c7fd3c2
commit
f79dcf067a
3791 files changed
+248032
-76372
No files matched your search
@@ -9,9 +9,9 @@
|
||||
* @since 25 Apr 2014
|
||||
*/
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Dispatcher\Front::i();
|
||||
\IPS\Dispatcher\External::i();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* @since 18 Mar 2014
|
||||
*/
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
|
||||
try
|
||||
@@ -41,7 +41,7 @@ $transaction->gw_id = \IPS\Request::i()->order_number;
|
||||
$transaction->save();
|
||||
|
||||
$maxMind = NULL;
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or in_array( $transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or \in_array( $transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request( FALSE );
|
||||
$maxMind->setIpAddress( $transaction->ip );
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* @since 17 Mar 2014
|
||||
*/
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
|
||||
try
|
||||
@@ -26,37 +26,83 @@ try
|
||||
{
|
||||
/* Load Gateway */
|
||||
$gateway = \IPS\nexus\Gateway::load( \IPS\Request::i()->payment_method );
|
||||
$settings = json_decode( $gateway->settings, TRUE );
|
||||
|
||||
/* Check MD5 hash */
|
||||
if ( !\IPS\Login::compareHashes( mb_strtoupper( md5( $settings['hash'] . $settings['login'] . \IPS\Request::i()->x_trans_id . \IPS\Request::i()->x_amount ) ), \IPS\Request::i()->x_MD5_Hash ) )
|
||||
if ( !( $gateway instanceof \IPS\nexus\Gateway\AuthorizeNet ) )
|
||||
{
|
||||
throw new \Exception( $invoice->member->language()->addToStack('gateway_err') );
|
||||
}
|
||||
$settings = json_decode( $gateway->settings, TRUE );
|
||||
|
||||
/* Check hash */
|
||||
$message = '^' . implode( '^', array(
|
||||
\IPS\Request::i()->x_trans_id,
|
||||
\IPS\Request::i()->x_test_request,
|
||||
\IPS\Request::i()->x_response_code,
|
||||
\IPS\Request::i()->x_auth_code,
|
||||
\IPS\Request::i()->x_cvv2_resp_code,
|
||||
\IPS\Request::i()->x_cavv_response,
|
||||
\IPS\Request::i()->x_avs_code,
|
||||
\IPS\Request::i()->x_method,
|
||||
\IPS\Request::i()->x_account_number,
|
||||
\IPS\Request::i()->x_amount,
|
||||
\IPS\Request::i()->x_company,
|
||||
\IPS\Request::i()->x_first_name,
|
||||
\IPS\Request::i()->x_last_name,
|
||||
\IPS\Request::i()->x_address,
|
||||
\IPS\Request::i()->x_city,
|
||||
\IPS\Request::i()->x_state,
|
||||
\IPS\Request::i()->x_zip,
|
||||
\IPS\Request::i()->x_country,
|
||||
\IPS\Request::i()->x_phone,
|
||||
\IPS\Request::i()->x_fax,
|
||||
\IPS\Request::i()->x_email,
|
||||
\IPS\Request::i()->x_ship_to_company,
|
||||
\IPS\Request::i()->x_ship_to_first_name,
|
||||
\IPS\Request::i()->x_ship_to_last_name,
|
||||
\IPS\Request::i()->x_ship_to_address,
|
||||
\IPS\Request::i()->x_ship_to_city,
|
||||
\IPS\Request::i()->x_ship_to_state,
|
||||
\IPS\Request::i()->x_ship_to_zip,
|
||||
\IPS\Request::i()->x_ship_to_country,
|
||||
\IPS\Request::i()->x_invoice_num,
|
||||
) ) . '^';
|
||||
|
||||
if ( isset( \IPS\Request::i()->x_SHA2_Hash ) and isset( $settings['signature_key'] ) and $settings['signature_key'] and \IPS\Login::compareHashes( mb_strtoupper( hash_hmac( 'sha512', $message, hex2bin( $settings['signature_key'] ) ) ), \IPS\Request::i()->x_SHA2_Hash ) )
|
||||
{
|
||||
// SHA hash is okay
|
||||
}
|
||||
elseif ( isset( \IPS\Request::i()->x_MD5_Hash ) and isset( $settings['hash'] ) and $settings['hash'] and \IPS\Login::compareHashes( mb_strtoupper( md5( $settings['hash'] . $settings['login'] . \IPS\Request::i()->x_trans_id . \IPS\Request::i()->x_amount ) ), \IPS\Request::i()->x_MD5_Hash ) )
|
||||
{
|
||||
// MD5 hash is okay
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception( $invoice->member->language()->addToStack('gateway_err') );
|
||||
}
|
||||
|
||||
/* Was it accepted? */
|
||||
if ( \IPS\Request::i()->x_response_code != 1 )
|
||||
{
|
||||
\IPS\Session\Front::i();
|
||||
throw new \IPS\nexus\Gateway\AuthorizeNet\Exception( \IPS\Request::i()->x_response_reason_code );
|
||||
}
|
||||
|
||||
|
||||
/* Create a transaction */
|
||||
$transaction = new \IPS\nexus\Transaction;
|
||||
$transaction->member = \IPS\Member::load( \IPS\Request::i()->x_cust_id );
|
||||
$transaction->invoice = $invoice;
|
||||
$transaction->method = $gateway;
|
||||
$transaction->amount = \IPS\Request::i()->x_amount;
|
||||
$transaction->amount = new \IPS\nexus\Money( \IPS\Request::i()->x_amount, $invoice->currency );
|
||||
$transaction->currency = $invoice->currency;
|
||||
$transaction->gw_id = \IPS\Request::i()->x_trans_id;
|
||||
$transaction->ip = \IPS\Request::i()->x_customer_ip;
|
||||
$transaction->ip = isset( \IPS\Request::i()->x_customer_ip ) ? \IPS\Request::i()->x_customer_ip : \IPS\Request::i()->ipAddress();
|
||||
$extra = $transaction->extra;
|
||||
$extra['lastFour'] = str_replace( 'X', '', \IPS\Request::i()->x_account_number );
|
||||
$transaction->extra = $extra;
|
||||
$transaction->auth = \IPS\DateTime::create()->add( new \DateInterval( 'P30D' ) );
|
||||
|
||||
|
||||
/* Create a MaxMind request */
|
||||
$maxMind = NULL;
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or in_array( $transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or \in_array( $transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request;
|
||||
$maxMind->setTransaction( $transaction );
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Braintree Webhook Handler
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Nexus
|
||||
* @since 18 Dec 2018
|
||||
*/
|
||||
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
|
||||
$webhookNotification = NULL;
|
||||
$transaction = NULL;
|
||||
foreach ( \IPS\nexus\Gateway::roots() as $method )
|
||||
{
|
||||
if ( $method instanceof \IPS\nexus\Gateway\Braintree )
|
||||
{
|
||||
try
|
||||
{
|
||||
$webhookNotification = $method->gateway()->webhookNotification()->parse( $_POST["bt_signature"], $_POST["bt_payload"] );
|
||||
|
||||
if ( isset( $webhookNotification->subject['dispute'] ) and isset( $webhookNotification->subject['dispute']['transaction'] ) )
|
||||
{
|
||||
$transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', array( 't_gw_id=?', $webhookNotification->subject['dispute']['transaction']['id'] ) )->first() );
|
||||
if ( $transaction->method->id == $method->id )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
}
|
||||
if ( !$webhookNotification or !$transaction )
|
||||
{
|
||||
if( $webhookNotification AND $webhookNotification->kind == 'check' )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'TEST-CORRECT', 200, 'text/plain' );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'INVALID', 500, 'text/plain' );
|
||||
}
|
||||
}
|
||||
|
||||
switch ( $webhookNotification->kind )
|
||||
{
|
||||
case \Braintree_WebhookNotification::DISPUTE_OPENED:
|
||||
|
||||
$transaction->status = $transaction::STATUS_DISPUTED;
|
||||
$extra = $transaction->extra;
|
||||
$extra['history'][] = array( 's' => $transaction::STATUS_DISPUTED, 'on' => $webhookNotification->subject['dispute']['createdAt']->getTimestamp(), 'ref' => $webhookNotification->subject['dispute']['id'] );
|
||||
$transaction->extra = $extra;
|
||||
$transaction->save();
|
||||
|
||||
if ( $transaction->member )
|
||||
{
|
||||
$transaction->member->log( 'transaction', array(
|
||||
'type' => 'status',
|
||||
'status' => $transaction::STATUS_DISPUTED,
|
||||
'id' => $transaction->id
|
||||
) );
|
||||
}
|
||||
|
||||
$transaction->invoice->markUnpaid( \IPS\nexus\Invoice::STATUS_CANCELED );
|
||||
|
||||
\IPS\core\AdminNotification::send( 'nexus', 'Transaction', $transaction::STATUS_DISPUTED, TRUE, $transaction );
|
||||
|
||||
\IPS\Output::i()->sendOutput( 'OK', 200, 'text/plain' );
|
||||
exit;
|
||||
|
||||
case \Braintree_WebhookNotification::DISPUTE_LOST:
|
||||
$transaction->status = $transaction::STATUS_REFUNDED;
|
||||
$transaction->save();
|
||||
exit;
|
||||
|
||||
case \Braintree_WebhookNotification::DISPUTE_WON:
|
||||
$transaction->status = $transaction::STATUS_PAID;
|
||||
$transaction->save();
|
||||
if ( !$transaction->invoice->amountToPay()->amount->isGreaterThanZero() )
|
||||
{
|
||||
$transaction->invoice->markPaid();
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sendOutput( 'UNEXPECTED_WEBHOOK', 500, 'text/plain' );
|
||||
@@ -0,0 +1,298 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief PayPal Webhook Handler
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Nexus
|
||||
* @since 11 Oct 2019
|
||||
*/
|
||||
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Session\Front::i();
|
||||
|
||||
/**
|
||||
* PayPal Webhook Handler
|
||||
*/
|
||||
class paypalWebhookHandler
|
||||
{
|
||||
/**
|
||||
* @brief Raw Webhook Data (as a string)
|
||||
*/
|
||||
private $body;
|
||||
|
||||
/**
|
||||
* @brief Parsed Webhook Data (as an array)
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* @brief The payment method
|
||||
*/
|
||||
private $method;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $body The raw body posted to this script
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $body )
|
||||
{
|
||||
$this->body = $body;
|
||||
$this->data = json_decode( $body, TRUE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sale completed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function saleCompleted()
|
||||
{
|
||||
/* Is this a billing agreement payment? */
|
||||
if ( isset( $this->data['resource'] ) and isset( $this->data['resource']['id'] ) and isset( $this->data['resource']['billing_agreement_id'] ) )
|
||||
{
|
||||
/* Have we seen this transaction before? */
|
||||
try
|
||||
{
|
||||
$transaction = \IPS\Db::i()->select( '*', 'nexus_transactions', array( 't_gw_id=? AND t_method=?', $this->data['resource']['id'], $this->method->id ) )->first();
|
||||
return 'ALREADY_PROCESSED';
|
||||
}
|
||||
catch ( \UnderflowException $e ) {}
|
||||
|
||||
/* Get the billing agreement */
|
||||
try
|
||||
{
|
||||
$billingAgreement = \IPS\nexus\Gateway\PayPal\BillingAgreement::constructFromData( \IPS\Db::i()->select( '*', 'nexus_billing_agreements', array( 'ba_gw_id=? AND ba_method=?', $this->data['resource']['billing_agreement_id'], $this->method->id ) )->first() );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
throw new \DomainException('UNKNOWN_BILLING_AGREEMENT');
|
||||
}
|
||||
|
||||
/* Do it */
|
||||
try
|
||||
{
|
||||
$transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', array( 't_billing_agreement=? AND t_method=? AND t_status=?', $billingAgreement->id, $this->method->id, \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING ) )->first() );
|
||||
$transaction->gw_id = $this->data['resource']['id'];
|
||||
$transaction->save();
|
||||
|
||||
return $this->_processInitialBillingAgreementTransaction( $transaction );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
$transaction = new \IPS\nexus\Transaction;
|
||||
$transaction->member = $billingAgreement->member;
|
||||
$transaction->method = $this->method;
|
||||
$transaction->amount = new \IPS\nexus\Money( $this->data['resource']['amount']['total'], $this->data['resource']['amount']['currency'] );
|
||||
$transaction->date = new \IPS\DateTime( $this->data['resource']['create_time'] );
|
||||
$transaction->extra = array( 'automatic' => TRUE );
|
||||
$transaction->gw_id = $this->data['resource']['id'];
|
||||
$transaction->billing_agreement = $billingAgreement;
|
||||
|
||||
return $this->_processRecurringBillingAgreementTransaction( $transaction );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'NOT_BILLING_AGREEMENT';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the initial transaction for a billing agreement
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction The transaction
|
||||
* @return string
|
||||
*/
|
||||
protected function _processInitialBillingAgreementTransaction( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
/* Take any fraud action */
|
||||
$fraudResult = $transaction->fraud_blocked ? $transaction->fraud_blocked->action : NULL;
|
||||
if ( $fraudResult )
|
||||
{
|
||||
$transaction->executeFraudAction( $fraudResult, TRUE );
|
||||
}
|
||||
if ( !$fraudResult or $fraudResult === \IPS\nexus\Transaction::STATUS_PAID )
|
||||
{
|
||||
$transaction->approve();
|
||||
}
|
||||
|
||||
/* Let the customer know */
|
||||
$transaction->sendNotification();
|
||||
|
||||
/* Return */
|
||||
return 'OK-INITIAL';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a reccuring (i.e. not the intitial) transaction for a billing agreement
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction The transaction
|
||||
* @return string
|
||||
*/
|
||||
protected function _processRecurringBillingAgreementTransaction( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
/* Get purchases */
|
||||
$purchases = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_purchases', array( 'ps_billing_agreement=?', $transaction->billing_agreement->id ) ), 'IPS\nexus\Purchase' );
|
||||
|
||||
/* Generate an invoice */
|
||||
$invoice = new \IPS\nexus\Invoice;
|
||||
$invoice->system = TRUE;
|
||||
$invoice->date = $transaction->date;
|
||||
$invoice->currency = $transaction->amount->currency;
|
||||
$invoice->member = $transaction->billing_agreement->member;
|
||||
$invoice->billaddress = $transaction->billing_agreement->member->primaryBillingAddress();
|
||||
foreach ( $purchases as $purchase )
|
||||
{
|
||||
$invoice->addItem( \IPS\nexus\Invoice\Item\Renewal::create( $purchase ) );
|
||||
}
|
||||
$invoice->save();
|
||||
|
||||
/* Assign the transaction to it */
|
||||
$transaction->invoice = $invoice;
|
||||
$transaction->save();
|
||||
$transaction->approve();
|
||||
$invoice->status = $transaction->invoice->status;
|
||||
|
||||
/* Log */
|
||||
$invoice->member->log( 'transaction', array(
|
||||
'type' => 'paid',
|
||||
'status' => \IPS\nexus\Transaction::STATUS_PAID,
|
||||
'id' => $transaction->id,
|
||||
'invoice_id' => $invoice->id,
|
||||
'invoice_title' => $invoice->title,
|
||||
'automatic' => TRUE,
|
||||
), FALSE );
|
||||
|
||||
/* Update the purchase */
|
||||
if ( $invoice->status !== $invoice::STATUS_PAID )
|
||||
{
|
||||
foreach ( $purchases as $purchase )
|
||||
{
|
||||
$purchase->invoice_pending = $invoice;
|
||||
$purchase->save();
|
||||
}
|
||||
}
|
||||
|
||||
/* Send notification */
|
||||
$invoice->sendNotification();
|
||||
|
||||
/* Update billing agreement */
|
||||
if ( $invoice->status === $invoice::STATUS_PAID )
|
||||
{
|
||||
$transaction->billing_agreement->next_cycle = $transaction->billing_agreement->nextPaymentDate();
|
||||
}
|
||||
else
|
||||
{
|
||||
$transaction->billing_agreement->next_cycle = NULL;
|
||||
}
|
||||
$transaction->billing_agreement->save();
|
||||
|
||||
/* Return */
|
||||
return 'OK-RECURRING';
|
||||
}
|
||||
|
||||
/**
|
||||
* Run
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run( $headers )
|
||||
{
|
||||
/* Do it */
|
||||
if ( isset( $this->data['event_type'] ) )
|
||||
{
|
||||
switch ( $this->data['event_type'] )
|
||||
{
|
||||
/* Sale completed: Used for automatic billing agreement purchases */
|
||||
case 'PAYMENT.SALE.COMPLETED':
|
||||
/* Validate it */
|
||||
foreach ( \IPS\nexus\Gateway::roots() as $method )
|
||||
{
|
||||
if ( $method instanceof \IPS\nexus\Gateway\PayPal )
|
||||
{
|
||||
try
|
||||
{
|
||||
$settings = json_decode( $method->settings, TRUE );
|
||||
|
||||
/* If billing agreements are not enabled, skip. We may have more than one PayPal gateway set up, and the first one may not be using billing agreements but the next one could be. */
|
||||
if ( !isset( $settings['billing_agreements'] ) OR !$settings['billing_agreements'] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* If the webhook ID does not exist... */
|
||||
if( empty( $settings['webhook_id'] ) )
|
||||
{
|
||||
/* First, try to set it automatically if we can */
|
||||
try
|
||||
{
|
||||
$newSettings = $method->testSettings( $settings );
|
||||
$method->settings = json_encode( $newSettings );
|
||||
$method->save();
|
||||
$settings = $newSettings;
|
||||
}
|
||||
/* But if that fails, send an AdminCP notification letting the admin know they need to fix it. */
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\core\AdminNotification::send( 'nexus', 'ConfigurationError', "pm{$method->id}", FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
if( isset( $this->data['event_type'] ) AND $this->data['event_type'] == 'PAYMENT.SALE.COMPLETED' AND
|
||||
isset( $this->data['resource'] ) AND isset( $this->data['resource']['id'] ) )
|
||||
{
|
||||
$response = $method->api( 'payments/sale/' . $this->data['resource']['id'], NULL, 'get' );
|
||||
|
||||
if ( isset( $response['state'] ) and mb_strtoupper( $response['state'] ) === 'COMPLETED' )
|
||||
{
|
||||
$this->method = $method;
|
||||
|
||||
return $this->saleCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
// Do nothing - try the next one
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new \Exception('COULD_NOT_VALIDATE');
|
||||
|
||||
// PAYMENTS.PAYMENT.CREATED, PAYMENT.AUTHORIZATION.CREATED and then PAYMENT.CAPTURE.COMPLETED are actually buying something (not a billing agreement payment)
|
||||
|
||||
/* Everything else: unneeded */
|
||||
default:
|
||||
return 'UNNEEDED_TYPE';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception('INVALID_HOOK_DATA');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$class = new paypalWebhookHandler( trim( @file_get_contents('php://input') ) );
|
||||
try
|
||||
{
|
||||
$headers = array();
|
||||
foreach ( $_SERVER as $k => $v )
|
||||
{
|
||||
if ( mb_substr( $k, 0, 12 ) === 'HTTP_PAYPAL_' )
|
||||
{
|
||||
$headers[ str_replace( '_', '-', mb_substr( $k, 5 ) ) ] = $v;
|
||||
}
|
||||
}
|
||||
$response = $class->run( $headers );
|
||||
\IPS\Output::i()->sendOutput( $response, 200, 'text/plain' );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( $e->getMessage(), 500, 'text/plain' );
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
* @since 07 Mar 2014
|
||||
*/
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Session\Front::i();
|
||||
|
||||
@@ -33,7 +33,7 @@ try
|
||||
{
|
||||
/* Check fraud rules */
|
||||
$maxMind = NULL;
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or in_array( $transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or \in_array( $transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request;
|
||||
$maxMind->setTransaction( $transaction );
|
||||
@@ -47,8 +47,39 @@ try
|
||||
\IPS\Output::i()->redirect( $transaction->url() );
|
||||
}
|
||||
|
||||
/* Billing Agreement */
|
||||
if ( isset( \IPS\Request::i()->billingAgreement ) )
|
||||
/* Subscription */
|
||||
if ( isset( \IPS\Request::i()->subscription ) )
|
||||
{
|
||||
/* Get details */
|
||||
$response = $transaction->method->api( "billing/subscriptions/" . \IPS\Request::i()->subscription_id, NULL, 'get' );
|
||||
|
||||
/* Create Billing Agreement */
|
||||
try
|
||||
{
|
||||
$billingAgreement = \IPS\nexus\Gateway\PayPal\BillingAgreement::constructFromData( \IPS\Db::i()->select( '*', 'nexus_billing_agreements', array( 'ba_gw_id=? AND ba_method=?', $response['id'], $transaction->method->id ) )->first() );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
$billingAgreement = new \IPS\nexus\Gateway\PayPal\BillingAgreement;
|
||||
$billingAgreement->gw_id = $response['id'];
|
||||
$billingAgreement->method = $transaction->method;
|
||||
$billingAgreement->member = $transaction->member;
|
||||
$billingAgreement->started = \IPS\DateTime::create();
|
||||
$billingAgreement->next_cycle = ( new \IPS\DateTime( $response['billing_info']['next_billing_time'] ) );
|
||||
$billingAgreement->save();
|
||||
}
|
||||
$transaction->billing_agreement = $billingAgreement;
|
||||
$transaction->save();
|
||||
|
||||
/* Just save that we're waiting for the webhook */
|
||||
$transaction->status = \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING;
|
||||
$transaction->save();
|
||||
$transaction->sendNotification();
|
||||
\IPS\Output::i()->redirect( $transaction->url() );
|
||||
}
|
||||
|
||||
/* Billing Agreement (DEPRECATED) */
|
||||
elseif ( isset( \IPS\Request::i()->billingAgreement ) )
|
||||
{
|
||||
/* Execute */
|
||||
$response = $transaction->method->api( "payments/billing-agreements/" . \IPS\Request::i()->token . "/agreement-execute" );
|
||||
@@ -70,49 +101,11 @@ try
|
||||
$billingAgreement->save();
|
||||
$transaction->billing_agreement = $billingAgreement;
|
||||
$transaction->save();
|
||||
|
||||
/* Get the initial setup transaction if possible */
|
||||
$haveInitialTransaction = FALSE;
|
||||
$transactions = $transaction->method->api( "payments/billing-agreements/{$agreementId}/transactions?start_date=" . date( 'Y-m-d', time() - 86400 ) . '&end_date=' . date( 'Y-m-d' ), NULL, 'get' );
|
||||
foreach ( $transactions['agreement_transaction_list'] as $t )
|
||||
{
|
||||
if ( $t['status'] == 'Completed' )
|
||||
{
|
||||
$transaction->gw_id = $t['transaction_id'];
|
||||
$transaction->save();
|
||||
|
||||
if ( $fraudResult and $fraudResult !== \IPS\nexus\Transaction::STATUS_PAID )
|
||||
{
|
||||
$transaction->executeFraudAction( $fraudResult, TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
$transaction->member->log( 'transaction', array(
|
||||
'type' => 'paid',
|
||||
'status' => $transaction::STATUS_PAID,
|
||||
'id' => $transaction->id,
|
||||
'invoice_id' => $transaction->invoice->id,
|
||||
'invoice_title' => $transaction->invoice->title,
|
||||
) );
|
||||
|
||||
$memberJustCreated = $transaction->approve();
|
||||
if ( $memberJustCreated )
|
||||
{
|
||||
\IPS\Session::i()->setMember( $memberJustCreated );
|
||||
\IPS\Member\Device::loadOrCreate( $memberJustCreated, FALSE )->updateAfterAuthentication( NULL );
|
||||
}
|
||||
}
|
||||
|
||||
$transaction->sendNotification();
|
||||
\IPS\Output::i()->redirect( $transaction->url() );
|
||||
}
|
||||
}
|
||||
|
||||
/* If it hasn't been processed yet (PayPal is a bit flakey), we need to try again in a few minutes */
|
||||
/* Just save that we're waiting for the webhook */
|
||||
$transaction->status = \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING;
|
||||
$transaction->save();
|
||||
$transaction->sendNotification();
|
||||
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 1 ), "`key`='gatewayPending'" );
|
||||
\IPS\Output::i()->redirect( $transaction->url() );
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* @since 20 Jul 2017
|
||||
*/
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Session\Front::i();
|
||||
|
||||
@@ -52,7 +52,7 @@ $transaction->method = $gateway;
|
||||
|
||||
/* Create a MaxMind request */
|
||||
$maxMind = NULL;
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or in_array( $transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or \in_array( $transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request;
|
||||
$maxMind->setTransaction( $transaction );
|
||||
@@ -61,12 +61,8 @@ if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways
|
||||
/* Authorize and Capture */
|
||||
try
|
||||
{
|
||||
/* Create Card Object */
|
||||
$card = new \IPS\nexus\CreditCard;
|
||||
$card->token = \IPS\Request::i()->token;
|
||||
|
||||
/* Authorize */
|
||||
$transaction->auth = $gateway->auth( $transaction, array( "{$gateway->id}_card" => $card ), $maxMind );
|
||||
$transaction->auth = $gateway->auth( $transaction, array( "{$gateway->id}_card" => \IPS\Request::i()->token ), $maxMind );
|
||||
|
||||
/* Check Fraud Rules and capture */
|
||||
$memberJustCreated = $transaction->checkFraudRulesAndCapture( $maxMind );
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
* @since 20 Jul 2017
|
||||
*/
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Session\Front::i();
|
||||
|
||||
/* Little IN_DEV helper to prevent firing this until we've triggered the webhooks */
|
||||
if ( \IPS\IN_DEV and !isset( \IPS\Request::i()->indevconfirm ) )
|
||||
{
|
||||
echo "<a href='" . \IPS\Request::i()->url()->setQueryString( 'indevconfirm', 1 ) . "'>Continue</a>";
|
||||
exit;
|
||||
}
|
||||
|
||||
/* Wait a few seconds so the webhook has time to come through */
|
||||
sleep( 5 );
|
||||
|
||||
/* Load Source */
|
||||
try
|
||||
{
|
||||
@@ -28,10 +38,14 @@ catch ( \Exception $e )
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=nexus&module=checkout&controller=checkout&do=transaction&id=&t=" . \IPS\Request::i()->nexusTransactionId, 'front', 'nexus_checkout', \IPS\Settings::i()->nexus_https ) );
|
||||
}
|
||||
|
||||
/* If we haven't had the webhook yet, wait a few seconds */
|
||||
if ( !in_array( $source['status'], array( 'failed', 'consumed' ) ) )
|
||||
/* If we're a guest, but the transaction belongs to a member, that's because the webhook has
|
||||
processed the transaction and created an account - so we need to log the newly created
|
||||
member in. This is okay to do because we've checked client_secret is correct, meaning
|
||||
we know this is a genuine redirect back from Stripe after payment of this transaction */
|
||||
if ( !\IPS\Member::loggedIn()->member_id and $transaction->member->member_id )
|
||||
{
|
||||
sleep( 5 );
|
||||
\IPS\Session::i()->setMember( $transaction->member );
|
||||
\IPS\Member\Device::loadOrCreate( $transaction->member, FALSE )->updateAfterAuthentication( NULL );
|
||||
}
|
||||
|
||||
/* And then send them on */
|
||||
|
||||
@@ -9,360 +9,611 @@
|
||||
* @since 20 Jul 2017
|
||||
*/
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
$body = trim( @file_get_contents('php://input') );
|
||||
$data = json_decode( $body, TRUE );
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Session\Front::i();
|
||||
|
||||
function loadTransaction( $returnUrl )
|
||||
/**
|
||||
* Stripe Webhook Handler
|
||||
*/
|
||||
class stripeWebhookHandler
|
||||
{
|
||||
$url = new \IPS\Http\Url( $returnUrl );
|
||||
$transaction = \IPS\nexus\Transaction::load( $url->queryString['nexusTransactionId'] );
|
||||
|
||||
$settings = json_decode( $transaction->method->settings, TRUE );
|
||||
if ( !validate( $settings['webhook_secret'] ) )
|
||||
/**
|
||||
* @brief Raw Webhook Data (as a string)
|
||||
*/
|
||||
private $body;
|
||||
|
||||
/**
|
||||
* @brief Parsed Webhook Data (as an array)
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* @brief Transaction
|
||||
*/
|
||||
private $transaction;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $body The raw body posted to this script
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $body )
|
||||
{
|
||||
throw new \Exception('INVALID_SIGNING_SECRET');
|
||||
$this->body = $body;
|
||||
$this->data = json_decode( $body, TRUE );
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
|
||||
function validate( $correctSigningSecret )
|
||||
{
|
||||
global $body;
|
||||
|
||||
if ( !$correctSigningSecret )
|
||||
/**
|
||||
* A source has become chargeable (for example, 3DSecure was completed) so we're ready to authorize the payment
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function sourceChargeable()
|
||||
{
|
||||
return TRUE; // In case they upgraded and haven't provided one
|
||||
}
|
||||
|
||||
if ( isset( $_SERVER['HTTP_STRIPE_SIGNATURE'] ) )
|
||||
{
|
||||
foreach ( explode( ',', $_SERVER['HTTP_STRIPE_SIGNATURE'] ) as $row )
|
||||
{
|
||||
list( $k, $v ) = explode( '=', trim( $row ) );
|
||||
$sig[ trim( $k ) ][] = trim( $v );
|
||||
}
|
||||
|
||||
$signedPayload = $sig['t'][0] . '.' . $body;
|
||||
$signature = hash_hmac( 'sha256', $signedPayload, $correctSigningSecret );
|
||||
|
||||
return in_array( $signature, $sig['v1'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
/* source.chargeable means we're ready to charge (then we need to wait for charge.succeeded) */
|
||||
if ( isset( $data['type'] ) and $data['type'] === 'source.chargeable' )
|
||||
{
|
||||
/* Is this a validation? */
|
||||
if ( isset( $data['data']['object']['owner']['email'] ) and $data['data']['object']['owner']['email'] === 'webhook-validate@example.com' and isset( $data['data']['object']['metadata']['method'] ) )
|
||||
{
|
||||
$method = \IPS\nexus\Gateway::load( $data['data']['object']['metadata']['method'] );
|
||||
$settings = json_decode( $method->settings, TRUE );
|
||||
if ( !isset( $settings['webhook_verified'] ) )
|
||||
{
|
||||
if ( validate( $settings['webhook_secret'] ) )
|
||||
{
|
||||
$settings['webhook_verified'] = $settings['webhook_secret'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$settings['webhook_verified'] = 'ERR';
|
||||
}
|
||||
$method->settings = json_encode( $settings );
|
||||
$method->save();
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
/* Don't need to do anything for cards, since this is only for asynchronous payments */
|
||||
if ( isset( $data['data']['object']['type'] ) and in_array( $data['data']['object']['type'], array( 'card' ) ) )
|
||||
if ( isset( $this->data['data']['object']['type'] ) and \in_array( $this->data['data']['object']['type'], array( 'card' ) ) )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'NO_PROCESSING_REQUIRED', 200, 'text/plain' );
|
||||
exit;
|
||||
return 'NO_PROCESSING_REQUIRED';
|
||||
}
|
||||
|
||||
/* Load the transaction */
|
||||
if ( isset( $data['data']['object']['metadata']['Transaction ID'] ) )
|
||||
/* Check the status */
|
||||
if ( !\in_array( $this->transaction->status, array( \IPS\nexus\Transaction::STATUS_PENDING, \IPS\nexus\Transaction::STATUS_WAITING ) ) )
|
||||
{
|
||||
$transaction = \IPS\nexus\Transaction::load( $data['data']['object']['metadata']['Transaction ID'] );
|
||||
}
|
||||
elseif ( isset( $data['data']['object']['redirect']['return_url'] ) )
|
||||
{
|
||||
$transaction = loadTransaction( $data['data']['object']['redirect']['return_url'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
if ( \in_array( $this->transaction->status, array( \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING, \IPS\nexus\Transaction::STATUS_PAID ) ) )
|
||||
{
|
||||
$where = array( array( 't_gw_id=?', $data['data']['object']['id'] ) );
|
||||
if ( isset( $data['data']['object']['metadata']['Invoice ID'] ) )
|
||||
{
|
||||
$where[] = array( 't_invoice=?', $data['data']['object']['metadata']['Invoice ID'] );
|
||||
}
|
||||
|
||||
$transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', $where )->first() );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'COULD_NOT_FIND_TRANSACTION', 403, 'text/plain' );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
if ( $transaction->status !== \IPS\nexus\Transaction::STATUS_PENDING and $transaction->status !== \IPS\nexus\Transaction::STATUS_WAITING )
|
||||
{
|
||||
if ( $transaction->status === \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'ALREADY_PROCESSED', 200, 'text/plain' );
|
||||
return 'ALREADY_PROCESSED';
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'BAD_STATUS', 403, 'text/plain' );
|
||||
throw new \Exception('BAD_STATUS');
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
/* Load the source */
|
||||
$source = $transaction->method->api( 'sources/' . preg_replace( '/[^A-Z0-9_]/i', '', $data['data']['object']['id'] ) );
|
||||
if ( $source['client_secret'] != $data['data']['object']['client_secret'] )
|
||||
/* Validate the source with Stripe */
|
||||
$source = $this->transaction->method->api( 'sources/' . preg_replace( '/[^A-Z0-9_]/i', '', $this->data['data']['object']['id'] ) );
|
||||
if ( $source['client_secret'] != $this->data['data']['object']['client_secret'] )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'BAD_SECRET', 403, 'text/plain' );
|
||||
exit;
|
||||
throw new \Exception('BAD_SECRET');
|
||||
}
|
||||
|
||||
/* Check we're not just going to refuse this */
|
||||
$maxMind = NULL;
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or in_array( $transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or \in_array( $this->transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request( FALSE );
|
||||
$maxMind->setIpAddress( $transaction->ip );
|
||||
$maxMind->setTransaction( $transaction );
|
||||
$maxMind->setIpAddress( $this->transaction->ip );
|
||||
$maxMind->setTransaction( $this->transaction );
|
||||
}
|
||||
$fraudResult = $transaction->runFraudCheck( $maxMind );
|
||||
$fraudResult = $this->transaction->runFraudCheck( $maxMind );
|
||||
if ( $fraudResult === \IPS\nexus\Transaction::STATUS_REFUSED )
|
||||
{
|
||||
$transaction->executeFraudAction( $fraudResult, FALSE );
|
||||
$transaction->sendNotification();
|
||||
$this->transaction->executeFraudAction( $fraudResult, FALSE );
|
||||
$this->transaction->sendNotification();
|
||||
}
|
||||
|
||||
/* Authorize */
|
||||
else
|
||||
{
|
||||
$transaction->auth = $transaction->method->auth( $transaction, array( $transaction->method->id . '_card' => $source['id'] ) );
|
||||
$transaction->status = \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING;
|
||||
$transaction->save();
|
||||
$this->transaction->auth = $this->transaction->method->auth( $this->transaction, array( $this->transaction->method->id . '_card' => $source['id'] ) );
|
||||
$this->transaction->status = \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING;
|
||||
$this->transaction->save();
|
||||
}
|
||||
|
||||
/* OK */
|
||||
\IPS\Output::i()->sendOutput( 'OK', 200, 'text/plain' );
|
||||
/* Return */
|
||||
return 'OK';
|
||||
}
|
||||
|
||||
/* charge.succeeded means we got the payment */
|
||||
elseif ( isset( $data['type'] ) and $data['type'] === 'charge.succeeded' )
|
||||
/**
|
||||
* A charge was successful on a RECURRING payment, so we can approve the transaction
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function chargeSucceeded()
|
||||
{
|
||||
/* Load the transaction */
|
||||
if ( isset( $data['data']['object']['metadata']['Transaction ID'] ) )
|
||||
/* Check the status */
|
||||
if ( $this->transaction->status !== \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING )
|
||||
{
|
||||
$transaction = \IPS\nexus\Transaction::load( $data['data']['object']['metadata']['Transaction ID'] );
|
||||
}
|
||||
elseif ( isset( $data['data']['object']['source']['redirect']['return_url'] ) )
|
||||
{
|
||||
$transaction = loadTransaction( $data['data']['object']['source']['redirect']['return_url'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
if ( $this->transaction->status === \IPS\nexus\Transaction::STATUS_PAID )
|
||||
{
|
||||
$where = array( array( 't_gw_id=?', $data['data']['object']['id'] ) );
|
||||
if ( isset( $data['data']['object']['metadata']['Invoice ID'] ) )
|
||||
{
|
||||
$where[] = array( 't_invoice=?', $data['data']['object']['metadata']['Invoice ID'] );
|
||||
}
|
||||
|
||||
$transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', $where )->first() );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'COULD_NOT_FIND_TRANSACTION', 403, 'text/plain' );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
if ( $transaction->status !== \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING )
|
||||
{
|
||||
if ( $transaction->status === \IPS\nexus\Transaction::STATUS_PAID )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'ALREADY_PROCESSED', 200, 'text/plain' );
|
||||
return 'ALREADY_PROCESSED';
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'BAD_STATUS', 403, 'text/plain' );
|
||||
throw new \Exception('BAD_STATUS');
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
/* Validate the charge with Stripe */
|
||||
try
|
||||
{
|
||||
$charge = $this->transaction->method->api( 'charges/' . preg_replace( '/[^A-Z0-9_]/i', '', $this->data['data']['object']['id'] ) );
|
||||
if ( !\in_array( $charge['status'], array( 'succeeded', 'paid' ) ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
throw new \Exception('INVALID_CHARGE');
|
||||
}
|
||||
|
||||
/* Create a MaxMind request */
|
||||
$maxMind = NULL;
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or in_array( $transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or \in_array( $this->transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request( FALSE );
|
||||
$maxMind->setIpAddress( $transaction->ip );
|
||||
$maxMind->setTransaction( $transaction );
|
||||
$maxMind->setIpAddress( $this->transaction->ip );
|
||||
$maxMind->setTransaction( $this->transaction );
|
||||
}
|
||||
|
||||
/* Check fraud rules */
|
||||
$fraudResult = $transaction->runFraudCheck( $maxMind );
|
||||
$fraudResult = $this->transaction->runFraudCheck( $maxMind );
|
||||
if ( $fraudResult )
|
||||
{
|
||||
$transaction->executeFraudAction( $fraudResult, TRUE );
|
||||
$this->transaction->executeFraudAction( $fraudResult, TRUE );
|
||||
}
|
||||
|
||||
/* If we're not being fraud blocked, we can approve */
|
||||
if ( $fraudResult === \IPS\nexus\Transaction::STATUS_PAID )
|
||||
{
|
||||
$transaction->member->log( 'transaction', array(
|
||||
$this->transaction->member->log( 'transaction', array(
|
||||
'type' => 'paid',
|
||||
'status' => \IPS\nexus\Transaction::STATUS_PAID,
|
||||
'id' => $transaction->id,
|
||||
'invoice_id' => $transaction->invoice->id,
|
||||
'invoice_title' => $transaction->invoice->title,
|
||||
'id' => $this->transaction->id,
|
||||
'invoice_id' => $this->transaction->invoice->id,
|
||||
'invoice_title' => $this->transaction->invoice->title,
|
||||
) );
|
||||
$transaction->approve();
|
||||
$this->transaction->approve();
|
||||
}
|
||||
|
||||
/* Either way, let the user know we got their payment */
|
||||
$transaction->sendNotification();
|
||||
|
||||
/* OK */
|
||||
\IPS\Output::i()->sendOutput( 'OK', 200, 'text/plain' );
|
||||
$this->transaction->sendNotification();
|
||||
|
||||
/* Return */
|
||||
return 'OK';
|
||||
}
|
||||
|
||||
/* charge.failed means it failed */
|
||||
elseif ( isset( $data['type'] ) and $data['type'] === 'charge.failed' )
|
||||
/**
|
||||
* A charge was successful on a NEW payment, so we can create, capture, and approve the transaction
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function chargeSucceededNew()
|
||||
{
|
||||
/* Load the transaction */
|
||||
if ( isset( $data['data']['object']['metadata']['Transaction ID'] ) )
|
||||
/* Check the status */
|
||||
if ( $this->transaction->status !== \IPS\nexus\Transaction::STATUS_PENDING )
|
||||
{
|
||||
$transaction = \IPS\nexus\Transaction::load( $data['data']['object']['metadata']['Transaction ID'] );
|
||||
}
|
||||
elseif ( isset( $data['data']['object']['source']['redirect']['return_url'] ) )
|
||||
{
|
||||
$transaction = loadTransaction( $data['data']['object']['source']['redirect']['return_url'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
if ( $this->transaction->status === \IPS\nexus\Transaction::STATUS_PAID )
|
||||
{
|
||||
$where = array( array( 't_gw_id=?', $data['data']['object']['id'] ) );
|
||||
if ( isset( $data['data']['object']['metadata']['Invoice ID'] ) )
|
||||
{
|
||||
$where[] = array( 't_invoice=?', $data['data']['object']['metadata']['Invoice ID'] );
|
||||
}
|
||||
|
||||
$transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', $where )->first() );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'COULD_NOT_FIND_TRANSACTION', 403, 'text/plain' );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
if ( $transaction->status !== \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING )
|
||||
{
|
||||
if ( $transaction->status === \IPS\nexus\Transaction::STATUS_REFUSED )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'ALREADY_PROCESSED', 200, 'text/plain' );
|
||||
return 'ALREADY_PROCESSED';
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( 'BAD_STATUS', 403, 'text/plain' );
|
||||
throw new \Exception('BAD_STATUS');
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
/* Validate the charge with Stripe */
|
||||
try
|
||||
{
|
||||
$charge = $this->transaction->method->api( 'charges/' . preg_replace( '/[^A-Z0-9_]/i', '', $this->data['data']['object']['id'] ) );
|
||||
if ( !\in_array( $charge['status'], array( 'succeeded', 'paid' ) ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
throw new \Exception('INVALID_CHARGE');
|
||||
}
|
||||
|
||||
/* If this was done by an admin, we just capture and approve straight away */
|
||||
if ( isset( $this->data['data']['object']['metadata']['Admin'] ) and $this->data['data']['object']['metadata']['Admin'] )
|
||||
{
|
||||
$this->transaction->auth = NULL;
|
||||
$this->transaction->capture();
|
||||
$this->transaction->member->log( 'transaction', array(
|
||||
'type' => 'paid',
|
||||
'status' => \IPS\nexus\Transaction::STATUS_PAID,
|
||||
'id' => $this->transaction->id,
|
||||
'invoice_id' => $this->transaction->invoice->id,
|
||||
'invoice_title' => $this->transaction->invoice->title,
|
||||
), \IPS\Member::load( $this->data['data']['object']['metadata']['Admin'] ) );
|
||||
$this->transaction->approve();
|
||||
}
|
||||
|
||||
/* Otherwise, check fraud rules and then capture */
|
||||
else
|
||||
{
|
||||
/* Create a MaxMind request */
|
||||
$maxMind = NULL;
|
||||
if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways or \IPS\Settings::i()->maxmind_gateways == '*' or \in_array( $this->transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request( FALSE );
|
||||
$maxMind->setIpAddress( $this->transaction->ip );
|
||||
$maxMind->setTransaction( $this->transaction );
|
||||
}
|
||||
|
||||
/* Set the authorize date (it's already actually been authorized) */
|
||||
$this->transaction->auth = \IPS\DateTime::ts( $this->data['data']['object']['created'] )->add( new \DateInterval( 'P7D' ) );
|
||||
|
||||
/* Check Fraud Rules and capture */
|
||||
$this->transaction->checkFraudRulesAndCapture( $maxMind );
|
||||
}
|
||||
|
||||
/* Send email receipt */
|
||||
$this->transaction->sendNotification();
|
||||
|
||||
/* Return */
|
||||
return 'OK';
|
||||
}
|
||||
|
||||
/**
|
||||
* A charge failed so we need to mark the transaction as failed locally
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function chargeFailed()
|
||||
{
|
||||
/* Check the status */
|
||||
if ( !\in_array( $this->transaction->status, [ \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING, IPS\nexus\Transaction::STATUS_PENDING ] ) )
|
||||
{
|
||||
if ( $this->transaction->status === \IPS\nexus\Transaction::STATUS_REFUSED )
|
||||
{
|
||||
return 'ALREADY_PROCESSED';
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception('BAD_STATUS');
|
||||
}
|
||||
}
|
||||
|
||||
/* Validate the charge with Stripe */
|
||||
try
|
||||
{
|
||||
$charge = $this->transaction->method->api( 'charges/' . preg_replace( '/[^A-Z0-9_]/i', '', $this->data['data']['object']['id'] ) );
|
||||
if ( $charge['status'] !== 'failed' )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
throw new \Exception('INVALID_CHARGE');
|
||||
}
|
||||
|
||||
/* Mark it failed */
|
||||
$transaction->status = \IPS\nexus\Transaction::STATUS_REFUSED;
|
||||
$extra = $transaction->extra;
|
||||
$extra['history'][] = array( 's' => \IPS\nexus\Transaction::STATUS_REFUSED, 'noteRaw' => $data['data']['object']['failure_message'] );
|
||||
$transaction->extra = $extra;
|
||||
$transaction->save();
|
||||
$transaction->member->log( 'transaction', array(
|
||||
$this->transaction->status = \IPS\nexus\Transaction::STATUS_REFUSED;
|
||||
$extra = $this->transaction->extra;
|
||||
$extra['history'][] = array( 's' => \IPS\nexus\Transaction::STATUS_REFUSED, 'noteRaw' => $this->data['data']['object']['failure_message'] );
|
||||
$this->transaction->extra = $extra;
|
||||
$this->transaction->save();
|
||||
$this->transaction->member->log( 'transaction', array(
|
||||
'type' => 'paid',
|
||||
'status' => \IPS\nexus\Transaction::STATUS_REFUSED,
|
||||
'id' => $transaction->id,
|
||||
'invoice_id' => $transaction->invoice->id,
|
||||
'invoice_title' => $transaction->title,
|
||||
'id' => $this->transaction->id,
|
||||
'invoice_id' => $this->transaction->invoice->id,
|
||||
'invoice_title' => $this->transaction->title,
|
||||
), FALSE );
|
||||
|
||||
/* Send notification */
|
||||
$transaction->sendNotification();
|
||||
$this->transaction->sendNotification();
|
||||
|
||||
/* Return */
|
||||
\IPS\Output::i()->sendOutput( 'OK', 200, 'text/plain' );
|
||||
return 'OK';
|
||||
}
|
||||
|
||||
/* charge.dispute.created is a chargeback */
|
||||
elseif ( isset( $data['type'] ) and $data['type'] === 'charge.dispute.created' and isset( $data['data']['object']['charge'] ) )
|
||||
/**
|
||||
* A chargeback/dispute has been made against a transaction so we need to mark it as such locally
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function disputeCreated()
|
||||
{
|
||||
$transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', array( 't_gw_id=?', $data['data']['object']['charge'] ) )->first() );
|
||||
$settings = json_decode( $transaction->method->settings, TRUE );
|
||||
if ( !validate( $settings['webhook_secret'] ) )
|
||||
/* Validate the dispute with Stripe */
|
||||
try
|
||||
{
|
||||
throw new \Exception('INVALID_SIGNING_SECRET');
|
||||
$dispute = $this->transaction->method->api( 'disputes/' . preg_replace( '/[^A-Z0-9_]/i', '', $this->data['data']['object']['id'] ) );
|
||||
if ( !\in_array( $dispute['status'], array( 'needs_response', 'warning_needs_response' ) ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
|
||||
if ( \substr( $this->transaction->gw_id, 0, 3 ) === 'pi_' )
|
||||
{
|
||||
$paymentIntent = $this->transaction->method->api( 'payment_intents/' . $this->transaction->gw_id );
|
||||
|
||||
$ok = FALSE;
|
||||
foreach ( $paymentIntent['charges']['data'] as $charge )
|
||||
{
|
||||
if ( $dispute['charge'] === $charge['id'] )
|
||||
{
|
||||
$ok = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !$ok )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
}
|
||||
elseif ( $dispute['charge'] !== $this->transaction->gw_id )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
throw new \Exception('INVALID_DISPUTE');
|
||||
}
|
||||
|
||||
$transaction->status = $transaction::STATUS_DISPUTED;
|
||||
$extra = $transaction->extra;
|
||||
$extra['history'][] = array( 's' => $transaction::STATUS_DISPUTED, 'on' => $data['data']['object']['created'], 'ref' => $data['data']['object']['id'] );
|
||||
$transaction->extra = $extra;
|
||||
$transaction->save();
|
||||
/* Mark the transaction as disputed */
|
||||
$this->transaction->status = \IPS\nexus\Transaction::STATUS_DISPUTED;
|
||||
$extra = $this->transaction->extra;
|
||||
$extra['history'][] = array( 's' => \IPS\nexus\Transaction::STATUS_DISPUTED, 'on' => $this->data['data']['object']['created'], 'ref' => $this->data['data']['object']['id'] );
|
||||
$this->transaction->extra = $extra;
|
||||
$this->transaction->save();
|
||||
|
||||
if ( $transaction->member )
|
||||
/* Log */
|
||||
if ( $this->transaction->member )
|
||||
{
|
||||
$transaction->member->log( 'transaction', array(
|
||||
$this->transaction->member->log( 'transaction', array(
|
||||
'type' => 'status',
|
||||
'status' => $transaction::STATUS_DISPUTED,
|
||||
'id' => $transaction->id
|
||||
'status' => \IPS\nexus\Transaction::STATUS_DISPUTED,
|
||||
'id' => $this->transaction->id
|
||||
) );
|
||||
}
|
||||
|
||||
$transaction->invoice->markUnpaid( \IPS\nexus\Invoice::STATUS_CANCELED );
|
||||
/* Mark the invoice as not paid (revoking benefits) */
|
||||
$this->transaction->invoice->markUnpaid( \IPS\nexus\Invoice::STATUS_CANCELED );
|
||||
|
||||
/* Send admin notification */
|
||||
\IPS\core\AdminNotification::send( 'nexus', 'Transaction', \IPS\nexus\Transaction::STATUS_DISPUTED, TRUE, $this->transaction );
|
||||
|
||||
/* Return */
|
||||
return 'OK';
|
||||
}
|
||||
|
||||
/* charge.dispute.closed is a chargeback being resolved */
|
||||
elseif ( isset( $data['type'] ) and $data['type'] === 'charge.dispute.closed' and isset( $data['data']['object']['charge'] ) and isset( $data['data']['object']['status'] ) )
|
||||
/**
|
||||
* A chargeback/dispute has been resolved (which may be won or lost)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function disputeClosed()
|
||||
{
|
||||
$transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', array( 't_gw_id=?', $data['data']['object']['charge'] ) )->first() );
|
||||
$settings = json_decode( $transaction->method->settings, TRUE );
|
||||
if ( !validate( $settings['webhook_secret'] ) )
|
||||
/* Validate the dispute with Stripe */
|
||||
try
|
||||
{
|
||||
throw new \Exception('INVALID_SIGNING_SECRET');
|
||||
}
|
||||
|
||||
if ( $data['data']['object']['status'] === 'won' )
|
||||
{
|
||||
$transaction->status = $transaction::STATUS_PAID;
|
||||
$transaction->save();
|
||||
if ( !$transaction->invoice->amountToPay()->amount->isGreaterThanZero() )
|
||||
{
|
||||
$transaction->invoice->markPaid();
|
||||
$dispute = $this->transaction->method->api( 'disputes/' . preg_replace( '/[^A-Z0-9_]/i', '', $this->data['data']['object']['id'] ) );
|
||||
if ( \substr( $this->transaction->gw_id, 0, 3 ) === 'pi_' )
|
||||
{
|
||||
$paymentIntent = $this->transaction->method->api( 'payment_intents/' . $this->transaction->gw_id );
|
||||
|
||||
$ok = FALSE;
|
||||
foreach ( $paymentIntent['charges']['data'] as $charge )
|
||||
{
|
||||
if ( $dispute['charge'] === $charge['id'] )
|
||||
{
|
||||
$ok = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !$ok )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
}
|
||||
elseif ( $dispute['charge'] !== $this->transaction->gw_id )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
}
|
||||
else
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$transaction->status = $transaction::STATUS_REFUNDED;
|
||||
$transaction->save();
|
||||
throw new \Exception('INVALID_DISPUTE');
|
||||
}
|
||||
|
||||
/* Did we win or lose? */
|
||||
if ( \in_array( $dispute['status'], array( 'won', 'warning_closed' ) ) )
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
elseif ( \in_array( $dispute['status'], array( 'lost' ) ) )
|
||||
{
|
||||
$this->transaction->status = \IPS\nexus\Transaction::STATUS_REFUNDED;
|
||||
$this->transaction->save();
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return 'OK';
|
||||
}
|
||||
|
||||
/**
|
||||
* Run
|
||||
*
|
||||
* @param string $signature The signature provided by this request
|
||||
* @return void
|
||||
*/
|
||||
public function run( $signature )
|
||||
{
|
||||
/* Ignore anything we don't care about */
|
||||
if ( !isset( $this->data['type'] ) or !\in_array( $this->data['type'], array( 'source.chargeable', 'charge.succeeded', 'charge.failed', 'charge.dispute.created', 'charge.dispute.closed' ) ) )
|
||||
{
|
||||
return 'UNNEEDED_TYPE';
|
||||
}
|
||||
|
||||
/* Try to find the transaction this is about */
|
||||
$new = FALSE;
|
||||
try
|
||||
{
|
||||
if ( isset( $this->data['data']['object']['metadata']['Transaction ID'] ) )
|
||||
{
|
||||
$this->transaction = \IPS\nexus\Transaction::load( $this->data['data']['object']['metadata']['Transaction ID'] );
|
||||
}
|
||||
elseif ( isset( $this->data['data']['object']['redirect']['return_url'] ) )
|
||||
{
|
||||
$url = new \IPS\Http\Url( $this->data['data']['object']['redirect']['return_url'] );
|
||||
$this->transaction = \IPS\nexus\Transaction::load( $url->queryString['nexusTransactionId'] );
|
||||
}
|
||||
elseif ( isset( $this->data['data']['object']['charge'] ) )
|
||||
{
|
||||
$paymentIntentId = NULL;
|
||||
foreach ( \IPS\nexus\Gateway::roots() as $method )
|
||||
{
|
||||
if ( $method instanceof \IPS\nexus\Gateway\Stripe )
|
||||
{
|
||||
try
|
||||
{
|
||||
$charge = $method->api( 'charges/' . preg_replace( '/[^A-Z0-9_]/i', '', $this->data['data']['object']['charge'] ) );
|
||||
if ( isset( $charge['payment_intent'] ) )
|
||||
{
|
||||
$paymentIntentId = $charge['payment_intent'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
// Do nothing - try the next one
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $paymentIntentId )
|
||||
{
|
||||
$this->transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', array( '( t_gw_id=? OR t_gw_id=? )', $paymentIntentId, $this->data['data']['object']['charge'] ) )->first() );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', array( 't_gw_id=?', $this->data['data']['object']['charge'] ) )->first() );
|
||||
}
|
||||
}
|
||||
elseif ( isset( $this->data['data']['object']['id'] ) and mb_substr( $this->data['data']['object']['id'], 0, 4 ) !== 'src_' )
|
||||
{
|
||||
if ( isset( $this->data['data']['object']['payment_intent'] ) )
|
||||
{
|
||||
$where = array( array( '( t_gw_id=? OR t_gw_id=? )', $this->data['data']['object']['id'], $this->data['data']['object']['payment_intent'] ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$where = array( array( 't_gw_id=?', $this->data['data']['object']['id'] ) );
|
||||
}
|
||||
|
||||
if ( isset( $this->data['data']['object']['metadata']['Invoice ID'] ) )
|
||||
{
|
||||
$where[] = array( 't_invoice=?', $this->data['data']['object']['metadata']['Invoice ID'] );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$this->transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', $where )->first() );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
/* If we can't find a transaction, but there is an "IP Address" in the metadata, this is from the actual checkout process: create a transaction */
|
||||
if ( isset( $this->data['data']['object']['metadata']['Invoice ID'] ) and isset( $this->data['data']['object']['metadata']['IP Address'] ) and isset( $this->data['data']['object']['metadata']['Payment Method ID'] ) )
|
||||
{
|
||||
$invoice = \IPS\nexus\Invoice::load( \intval( $this->data['data']['object']['metadata']['Invoice ID'] ) );
|
||||
|
||||
$this->transaction = new \IPS\nexus\Transaction;
|
||||
$this->transaction->member = isset( $this->data['data']['object']['metadata']['Customer ID'] ) ? \IPS\nexus\Customer::load( \intval( $this->data['data']['object']['metadata']['Customer ID'] ) ) : $invoice->member;
|
||||
$this->transaction->invoice = $invoice;
|
||||
$this->transaction->amount = new \IPS\nexus\Money( new \IPS\Math\Number( mb_substr( $this->data['data']['object']['amount'], 0, -2 ) . '.' . mb_substr( $this->data['data']['object']['amount'], -2 ) ), mb_strtoupper( $this->data['data']['object']['currency'] ) );
|
||||
$this->transaction->ip = $this->data['data']['object']['metadata']['IP Address'];
|
||||
$this->transaction->gw_id = isset( $this->data['data']['object']['payment_intent'] ) ? $this->data['data']['object']['payment_intent'] : $this->data['data']['object']['id'];
|
||||
$this->transaction->status = \IPS\nexus\Transaction::STATUS_PENDING;
|
||||
$this->transaction->method = \IPS\nexus\Gateway::load( \intval( $this->data['data']['object']['metadata']['Payment Method ID'] ) );
|
||||
$this->transaction->save();
|
||||
|
||||
$new = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'NO_TRANSACTION_INFORMATION';
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
if ( $this->data['type'] === 'charge.failed' )
|
||||
{
|
||||
return 'COULD_NOT_FIND_TRANSACTION'; // Sometimes if a transaction fails we don't create a transaction record
|
||||
}
|
||||
|
||||
throw new \Exception('COULD_NOT_FIND_TRANSACTION');
|
||||
}
|
||||
|
||||
/* Validate the signature */
|
||||
if ( !( $this->transaction->method instanceof \IPS\nexus\Gateway\Stripe ) )
|
||||
{
|
||||
throw new \Exception('INVALID_GATEWAY');
|
||||
}
|
||||
$settings = json_decode( $this->transaction->method->settings, TRUE );
|
||||
if ( isset( $settings['webhook_secret'] ) and $settings['webhook_secret'] ) // In case they upgraded and haven't provided one
|
||||
{
|
||||
$sig = array();
|
||||
foreach ( explode( ',', $signature ) as $row )
|
||||
{
|
||||
if ( \strpos( $row, '=' ) !== FALSE )
|
||||
{
|
||||
list( $k, $v ) = explode( '=', trim( $row ) );
|
||||
$sig[ trim( $k ) ][] = trim( $v );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $sig['t'] ) and isset( $sig['t'][0] ) )
|
||||
{
|
||||
$signedPayload = $sig['t'][0] . '.' . $this->body;
|
||||
$signature = hash_hmac( 'sha256', $signedPayload, $settings['webhook_secret'] );
|
||||
|
||||
if ( !\in_array( $signature, $sig['v1'] ) )
|
||||
{
|
||||
throw new \Exception('INVALID_SIGNING_SECRET');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception('INVALID_SIGNING_SECRET');
|
||||
}
|
||||
}
|
||||
|
||||
/* Do it */
|
||||
if ( isset( $this->data['type'] ) )
|
||||
{
|
||||
switch ( $this->data['type'] )
|
||||
{
|
||||
case 'source.chargeable':
|
||||
return $this->sourceChargeable();
|
||||
case 'charge.succeeded':
|
||||
return $new ? $this->chargeSucceededNew() : $this->chargeSucceeded();
|
||||
case 'charge.failed':
|
||||
return $this->chargeFailed();
|
||||
case 'charge.dispute.created':
|
||||
return $this->disputeCreated();
|
||||
case 'charge.dispute.closed':
|
||||
return $this->disputeClosed();
|
||||
default:
|
||||
return 'UNNEEDED_TYPE';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$class = new stripeWebhookHandler( trim( @file_get_contents('php://input') ) );
|
||||
try
|
||||
{
|
||||
$response = $class->run( isset( $_SERVER['HTTP_STRIPE_SIGNATURE'] ) ? $_SERVER['HTTP_STRIPE_SIGNATURE'] : '' );
|
||||
\IPS\Output::i()->sendOutput( $response, 200, 'text/plain' );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( $e->getMessage(), 500, 'text/plain' );
|
||||
}
|
||||
}
|
||||
@@ -9,16 +9,23 @@
|
||||
* @since 01 Apr 2015
|
||||
*/
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Dispatcher\External::i();
|
||||
|
||||
if ( \IPS\NEXUS_LKEY_API_ALLOW_IP_OVERRIDE )
|
||||
{
|
||||
$_SERVER['REMOTE_ADDR'] = isset( \IPS\Request::i()->ip ) ? \IPS\Request::i()->ip : $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
|
||||
/**
|
||||
* API Exception
|
||||
*/
|
||||
class ApiException extends \Exception { }
|
||||
|
||||
/**
|
||||
* API class to verify license keys
|
||||
*/
|
||||
class Api
|
||||
{
|
||||
/**
|
||||
@@ -42,9 +49,14 @@ class Api
|
||||
protected function getKey( $validateIdentifier=TRUE )
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
$key = \IPS\nexus\Purchase\LicenseKey::load( isset( \IPS\Request::i()->key ) ? \IPS\Request::i()->key : NULL );
|
||||
|
||||
if ( $key->key !== \IPS\Request::i()->key )
|
||||
{
|
||||
throw new ApiException( 'BAD_KEY_OR_ID', 105 );
|
||||
}
|
||||
|
||||
if ( $validateIdentifier and $identifier = $this->getIdentifier( $key ) and ( !isset( \IPS\Request::i()->identifier ) or $identifier != \IPS\Request::i()->identifier ) )
|
||||
{
|
||||
throw new ApiException( 'BAD_KEY_OR_ID', 101 );
|
||||
@@ -125,7 +137,7 @@ class Api
|
||||
{
|
||||
if ( $identifier != $providedIdentifier )
|
||||
{
|
||||
if ( $identifier or in_array( $key->identifier, array( 'name', 'email', 'username' ) ) )
|
||||
if ( $identifier or \in_array( $key->identifier, array( 'name', 'email', 'username' ) ) )
|
||||
{
|
||||
throw new ApiException( 'BAD_KEY_OR_ID', 101 );
|
||||
}
|
||||
@@ -143,7 +155,7 @@ class Api
|
||||
throw new ApiException( 'BAD_KEY_OR_ID', 101 );
|
||||
}
|
||||
|
||||
if ( defined( 'NEXUS_LKEY_API_ALLOW_IP_OVERRIDE' ) )
|
||||
if ( \defined( 'NEXUS_LKEY_API_ALLOW_IP_OVERRIDE' ) )
|
||||
{
|
||||
$ip = $this->params['ip'] ? $this->params['ip'] : $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* @since 07 Aug 2014
|
||||
*/
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Dispatcher\External::i();
|
||||
try
|
||||
@@ -38,7 +38,7 @@ if ( \IPS\Request::i()->a === 'a' )
|
||||
$server->save();
|
||||
$server->monitoringAcknowledged( \IPS\Request::i()->by );
|
||||
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->blankTemplate( \IPS\Theme::i()->getTemplate( 'hosting', 'nexus', 'front' )->monitorRespond( 'monitor_respond_acknowleged' ) ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->blankTemplate( \IPS\Theme::i()->getTemplate( 'hosting', 'nexus', 'front' )->monitorRespond( 'monitor_respond_acknowleged' ) ), 200, 'text/html' );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -49,5 +49,5 @@ elseif ( \IPS\Request::i()->a === 'r' )
|
||||
$server->save();
|
||||
$server->monitoringReset( \IPS\Request::i()->by );
|
||||
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->blankTemplate( \IPS\Theme::i()->getTemplate( 'hosting', 'nexus', 'front' )->monitorRespond( 'monitor_respond_reset' ) ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->blankTemplate( \IPS\Theme::i()->getTemplate( 'hosting', 'nexus', 'front' )->monitorRespond( 'monitor_respond_reset' ) ), 200, 'text/html' );
|
||||
}
|
||||
Reference in new issue
Block a user