Version 5.0.0 beta 1
This commit is contained in:
1 parent
25ddeb65d6
commit
15c7beabc5
6736 files changed
+627902
-497943
No files matched your search
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief 2Checkout Gateway
|
||||
* @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 Mar 2014
|
||||
*/
|
||||
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
|
||||
try
|
||||
{
|
||||
$transaction = \IPS\nexus\Transaction::load( \IPS\Request::i()->nexustransactionid );
|
||||
|
||||
if ( $transaction->status !== \IPS\nexus\Transaction::STATUS_PENDING )
|
||||
{
|
||||
throw new \OutOfRangeException();
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $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' ) );
|
||||
}
|
||||
|
||||
$settings = json_decode( $transaction->method->settings, TRUE );
|
||||
$hash = mb_strtoupper( md5( $settings['word'] . $settings['sid'] . ( \IPS\NEXUS_TEST_GATEWAYS ? 1 : \IPS\Request::i()->order_number ) . number_format( $transaction->amount->amountAsString(), 2 ) ) );
|
||||
if ( !\IPS\Login::compareHashes( (string) $hash, (string) \IPS\Request::i()->key ) )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $transaction->invoice->checkoutUrl()->setQueryString( array( '_step' => 'checkout_pay', 'err' => $transaction->member->language()->get('gateway_err') ) ) );
|
||||
}
|
||||
if ( \IPS\Request::i()->credit_card_processed !== 'Y' )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $transaction->invoice->checkoutUrl()->setQueryString( array( '_step' => 'checkout_pay', 'err' => $transaction->member->language()->get('card_refused') ) ) );
|
||||
}
|
||||
|
||||
$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 ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request( FALSE );
|
||||
$maxMind->setIpAddress( $transaction->ip );
|
||||
$maxMind->setTransaction( $transaction );
|
||||
}
|
||||
|
||||
$memberJustCreated = $transaction->checkFraudRulesAndCapture( $maxMind );
|
||||
$transaction->sendNotification();
|
||||
|
||||
if ( $memberJustCreated )
|
||||
{
|
||||
\IPS\Session::i()->setMember( $memberJustCreated );
|
||||
\IPS\Member\Device::loadOrCreate( $memberJustCreated, FALSE )->updateAfterAuthentication( NULL );
|
||||
}
|
||||
\IPS\Output::i()->redirect( $transaction->url() );
|
||||
@@ -1,138 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Authorize.Net DPM Gateway
|
||||
* @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 17 Mar 2014
|
||||
*/
|
||||
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
|
||||
\IPS\Output::setCacheTime( false );
|
||||
|
||||
try
|
||||
{
|
||||
$invoice = \IPS\nexus\Invoice::load( \IPS\Request::i()->x_invoice_num );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( '', 404 );
|
||||
exit;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
/* Load Gateway */
|
||||
$gateway = \IPS\nexus\Gateway::load( \IPS\Request::i()->payment_method );
|
||||
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 = 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 = 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 ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request;
|
||||
$maxMind->setTransaction( $transaction );
|
||||
$maxMind->setTransactionType( 'creditcard' );
|
||||
$maxMind->setAVS( \IPS\Request::i()->x_avs_code );
|
||||
}
|
||||
|
||||
/* Check Fraud Rules and capture */
|
||||
$transaction->checkFraudRulesAndCapture( $maxMind );
|
||||
$transaction->sendNotification();
|
||||
|
||||
/* Show thanks screen */
|
||||
$url = $transaction->url();
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$url = $invoice->checkoutUrl()->setQueryString( array( '_step' => 'checkout_pay', 'err' => $e->getMessage() ) );
|
||||
}
|
||||
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<script type='text/javascript' charset='utf-8'>
|
||||
window.location='<?php echo $url; ?>';
|
||||
</script>
|
||||
<noscript>
|
||||
<meta http-equiv='refresh' content='1;url=<?php echo $url; ?>'>
|
||||
</noscript>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
@@ -1,92 +0,0 @@
|
||||
<?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';
|
||||
|
||||
\IPS\Output::setCacheTime( false );
|
||||
|
||||
$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' );
|
||||
@@ -9,11 +9,26 @@
|
||||
* @since 11 Oct 2019
|
||||
*/
|
||||
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Session\Front::i();
|
||||
use IPS\core\AdminNotification;
|
||||
use IPS\Db;
|
||||
use IPS\nexus\extensions\nexus\Item\MiscellaneousCharge;
|
||||
use IPS\nexus\Gateway;
|
||||
use IPS\nexus\Gateway\PayPal;
|
||||
use IPS\nexus\Gateway\PayPal\BillingAgreement;
|
||||
use IPS\nexus\Invoice;
|
||||
use IPS\nexus\Invoice\Item\Renewal;
|
||||
use IPS\nexus\Money;
|
||||
use IPS\nexus\Purchase;
|
||||
use IPS\nexus\Transaction;
|
||||
use IPS\Output;
|
||||
use IPS\Patterns\ActiveRecordIterator;
|
||||
use IPS\Session\Front;
|
||||
|
||||
\IPS\Output::setCacheTime( false );
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
Front::i();
|
||||
|
||||
Output::i()->pageCaching = FALSE;
|
||||
|
||||
/**
|
||||
* PayPal Webhook Handler
|
||||
@@ -23,17 +38,17 @@ class paypalWebhookHandler
|
||||
/**
|
||||
* @brief Raw Webhook Data (as a string)
|
||||
*/
|
||||
private $body;
|
||||
private mixed $body;
|
||||
|
||||
/**
|
||||
* @brief Parsed Webhook Data (as an array)
|
||||
*/
|
||||
private $data;
|
||||
private array $data;
|
||||
|
||||
/**
|
||||
* @brief The payment method
|
||||
*/
|
||||
private $method;
|
||||
private Gateway $method;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -41,7 +56,7 @@ class paypalWebhookHandler
|
||||
* @param string $body The raw body posted to this script
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $body )
|
||||
public function __construct( string $body )
|
||||
{
|
||||
$this->body = $body;
|
||||
$this->data = json_decode( $body, TRUE );
|
||||
@@ -50,9 +65,9 @@ class paypalWebhookHandler
|
||||
/**
|
||||
* Sale completed
|
||||
*
|
||||
* @return void
|
||||
* @return string
|
||||
*/
|
||||
public function saleCompleted()
|
||||
public function saleCompleted() : string
|
||||
{
|
||||
/* 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'] ) )
|
||||
@@ -60,39 +75,36 @@ class paypalWebhookHandler
|
||||
/* Have we seen this transaction before? */
|
||||
try
|
||||
{
|
||||
/* @note SELECT_FROM_WRITE_SERVER transaction race condition */
|
||||
$transaction = \IPS\Db::i()->select( '*', 'nexus_transactions', array( 't_gw_id=? AND t_method=?', $this->data['resource']['id'], $this->method->id ), flags: \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
|
||||
$transaction = Db::i()->select( '*', 'nexus_transactions', array( 't_gw_id=? AND t_method=?', $this->data['resource']['id'], $this->method->id ), flags: Db::SELECT_FROM_WRITE_SERVER )->first();
|
||||
return 'ALREADY_PROCESSED';
|
||||
}
|
||||
catch ( \UnderflowException $e ) {}
|
||||
catch (UnderflowException ) {}
|
||||
|
||||
/* Get the billing agreement */
|
||||
try
|
||||
{
|
||||
/* @note Possible race condition when the webhook is almost instant */
|
||||
$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 ), flags: \IPS\Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
$billingAgreement = BillingAgreement::constructFromData( 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 )
|
||||
catch (UnderflowException )
|
||||
{
|
||||
throw new \DomainException('UNKNOWN_BILLING_AGREEMENT');
|
||||
throw new DomainException('UNKNOWN_BILLING_AGREEMENT');
|
||||
}
|
||||
|
||||
/* Do it */
|
||||
try
|
||||
{
|
||||
/* @note Possible race condition when the webhook is almost instant */
|
||||
$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 ), flags: \IPS\Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
$transaction = Transaction::constructFromData( Db::i()->select( '*', 'nexus_transactions', array( 't_billing_agreement=? AND t_method=? AND t_status=?', $billingAgreement->id, $this->method->id, Transaction::STATUS_GATEWAY_PENDING ) )->first() );
|
||||
$transaction->gw_id = $this->data['resource']['id'];
|
||||
$transaction->save();
|
||||
|
||||
return $this->_processInitialBillingAgreementTransaction( $transaction );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
catch (UnderflowException )
|
||||
{
|
||||
$transaction = new \IPS\nexus\Transaction;
|
||||
$transaction = new 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->amount = new 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'];
|
||||
@@ -110,18 +122,18 @@ class paypalWebhookHandler
|
||||
/**
|
||||
* Process the initial transaction for a billing agreement
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction The transaction
|
||||
* @param Transaction $transaction The transaction
|
||||
* @return string
|
||||
*/
|
||||
protected function _processInitialBillingAgreementTransaction( \IPS\nexus\Transaction $transaction )
|
||||
protected function _processInitialBillingAgreementTransaction( Transaction $transaction ) : string
|
||||
{
|
||||
/* Take any fraud action */
|
||||
$fraudResult = $transaction->fraud_blocked ? $transaction->fraud_blocked->action : NULL;
|
||||
$fraudResult = $transaction->fraud_blocked?->action;
|
||||
if ( $fraudResult )
|
||||
{
|
||||
$transaction->executeFraudAction( $fraudResult, TRUE );
|
||||
}
|
||||
if ( !$fraudResult or $fraudResult === \IPS\nexus\Transaction::STATUS_PAID )
|
||||
if ( !$fraudResult or $fraudResult === Transaction::STATUS_PAID )
|
||||
{
|
||||
$transaction->approve();
|
||||
}
|
||||
@@ -136,16 +148,16 @@ class paypalWebhookHandler
|
||||
/**
|
||||
* Process a reccuring (i.e. not the intitial) transaction for a billing agreement
|
||||
*
|
||||
* @param \IPS\nexus\Transaction $transaction The transaction
|
||||
* @param Transaction $transaction The transaction
|
||||
* @return string
|
||||
*/
|
||||
protected function _processRecurringBillingAgreementTransaction( \IPS\nexus\Transaction $transaction )
|
||||
protected function _processRecurringBillingAgreementTransaction( Transaction $transaction ) : string
|
||||
{
|
||||
/* Get purchases */
|
||||
$purchases = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_purchases', array( 'ps_billing_agreement=?', $transaction->billing_agreement->id ) ), 'IPS\nexus\Purchase' );
|
||||
$purchases = new ActiveRecordIterator( 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 = new Invoice;
|
||||
$invoice->system = TRUE;
|
||||
$invoice->date = $transaction->date;
|
||||
$invoice->currency = $transaction->amount->currency;
|
||||
@@ -153,15 +165,16 @@ class paypalWebhookHandler
|
||||
$invoice->billaddress = $transaction->billing_agreement->member->primaryBillingAddress();
|
||||
foreach ( $purchases as $purchase )
|
||||
{
|
||||
/* @var Purchase $purchase */
|
||||
if( !$purchase->renewals )
|
||||
{
|
||||
// Renewals have been cancelled for this purchase since PayPal tried to bill for it.
|
||||
$amount = new \IPS\nexus\Money( $purchase->renewal_price, $transaction->amount->currency );
|
||||
$invoice->addItem( new \IPS\nexus\extensions\nexus\Item\MiscellaneousCharge( sprintf( $purchase->member->language()->get('renew_payment_no_ba'), $purchase->name ), $amount ) );
|
||||
$amount = new Money( $purchase->renewal_price, $transaction->amount->currency );
|
||||
$invoice->addItem( new MiscellaneousCharge( sprintf( $purchase->member->language()->get('renew_payment_no_ba'), $purchase->name ), $amount ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
$invoice->addItem( \IPS\nexus\Invoice\Item\Renewal::create( $purchase ) );
|
||||
$invoice->addItem( Renewal::create( $purchase ) );
|
||||
}
|
||||
$invoice->save();
|
||||
|
||||
@@ -174,7 +187,7 @@ class paypalWebhookHandler
|
||||
/* Log */
|
||||
$invoice->member->log( 'transaction', array(
|
||||
'type' => 'paid',
|
||||
'status' => \IPS\nexus\Transaction::STATUS_PAID,
|
||||
'status' => Transaction::STATUS_PAID,
|
||||
'id' => $transaction->id,
|
||||
'invoice_id' => $invoice->id,
|
||||
'invoice_title' => $invoice->title,
|
||||
@@ -212,9 +225,9 @@ class paypalWebhookHandler
|
||||
/**
|
||||
* Run
|
||||
*
|
||||
* @return void
|
||||
* @return string
|
||||
*/
|
||||
public function run( $headers )
|
||||
public function run() : string
|
||||
{
|
||||
/* Do it */
|
||||
if ( isset( $this->data['event_type'] ) )
|
||||
@@ -224,9 +237,9 @@ class paypalWebhookHandler
|
||||
/* Sale completed: Used for automatic billing agreement purchases */
|
||||
case 'PAYMENT.SALE.COMPLETED':
|
||||
/* Validate it */
|
||||
foreach ( \IPS\nexus\Gateway::roots() as $method )
|
||||
foreach ( Gateway::roots() as $method )
|
||||
{
|
||||
if ( $method instanceof \IPS\nexus\Gateway\PayPal )
|
||||
if ( $method instanceof PayPal )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -246,12 +259,11 @@ class paypalWebhookHandler
|
||||
$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 )
|
||||
catch (Exception )
|
||||
{
|
||||
\IPS\core\AdminNotification::send( 'nexus', 'ConfigurationError', "pm{$method->id}", FALSE );
|
||||
AdminNotification::send( 'nexus', 'ConfigurationError', "pm{$method->id}", FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,14 +280,14 @@ class paypalWebhookHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception )
|
||||
{
|
||||
// Do nothing - try the next one
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new \Exception('COULD_NOT_VALIDATE');
|
||||
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)
|
||||
|
||||
@@ -286,7 +298,7 @@ class paypalWebhookHandler
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception('INVALID_HOOK_DATA');
|
||||
throw new Exception('INVALID_HOOK_DATA');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,10 +314,10 @@ try
|
||||
$headers[ str_replace( '_', '-', mb_substr( $k, 5 ) ) ] = $v;
|
||||
}
|
||||
}
|
||||
$response = $class->run( $headers );
|
||||
\IPS\Output::i()->sendOutput( $response, 200, 'text/plain' );
|
||||
$response = $class->run();
|
||||
Output::i()->sendOutput( $response, 200, 'text/plain' );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception $e)
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( $e->getMessage(), 500, 'text/plain' );
|
||||
Output::i()->sendOutput( $e->getMessage(), 500, 'text/plain' );
|
||||
}
|
||||
@@ -9,40 +9,52 @@
|
||||
* @since 07 Mar 2014
|
||||
*/
|
||||
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
use IPS\Db;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Log;
|
||||
use IPS\Member\Device;
|
||||
use IPS\nexus\Gateway\PayPal\BillingAgreement;
|
||||
use IPS\nexus\Transaction;
|
||||
use IPS\Output;
|
||||
use IPS\Request;
|
||||
use IPS\Session;
|
||||
use IPS\Session\Front;
|
||||
use IPS\Settings;
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Session\Front::i();
|
||||
Front::i();
|
||||
|
||||
/* Load Transaction */
|
||||
try
|
||||
{
|
||||
$transaction = \IPS\nexus\Transaction::load( \IPS\Request::i()->nexusTransactionId );
|
||||
$transaction = Transaction::load( Request::i()->nexusTransactionId );
|
||||
|
||||
if ( $transaction->status !== \IPS\nexus\Transaction::STATUS_PENDING )
|
||||
if ( $transaction->status !== Transaction::STATUS_PENDING )
|
||||
{
|
||||
throw new \OutofRangeException;
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
catch (OutOfRangeException )
|
||||
{
|
||||
\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' ) );
|
||||
Output::i()->redirect( Url::internal( "app=nexus&module=checkout&controller=checkout&do=transaction&id=&t=" . Request::i()->nexusTransactionId, 'front', 'nexus_checkout' ) );
|
||||
}
|
||||
|
||||
$fraudCheck = function( $transaction, $refuseExecute=TRUE ) {
|
||||
/* 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 ( Settings::i()->maxmind_key and ( !Settings::i()->maxmind_gateways or Settings::i()->maxmind_gateways == '*' or in_array( $transaction->method->id, explode( ',', Settings::i()->maxmind_gateways ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request;
|
||||
$maxMind->setTransaction( $transaction );
|
||||
$maxMind->setTransactionType( 'paypal' );
|
||||
}
|
||||
$fraudResult = $transaction->runFraudCheck( $maxMind );
|
||||
if ( $refuseExecute AND $fraudResult === \IPS\nexus\Transaction::STATUS_REFUSED )
|
||||
if ( $refuseExecute AND $fraudResult === Transaction::STATUS_REFUSED )
|
||||
{
|
||||
$transaction->executeFraudAction( $fraudResult, FALSE );
|
||||
$transaction->sendNotification();
|
||||
\IPS\Output::i()->redirect( $transaction->url() );
|
||||
Output::i()->redirect( $transaction->url() );
|
||||
}
|
||||
|
||||
return $fraudResult;
|
||||
@@ -52,67 +64,45 @@ $fraudCheck = function( $transaction, $refuseExecute=TRUE ) {
|
||||
try
|
||||
{
|
||||
/* Subscription */
|
||||
if ( isset( \IPS\Request::i()->subscription ) )
|
||||
if ( isset( Request::i()->subscription ) )
|
||||
{
|
||||
/* Sometimes PayPal doesn't include the subscription ID, so let's check if we have it in the transaction */
|
||||
$subscriptionId = \IPS\Request::i()->subscription_id ?? $transaction->gw_id;
|
||||
|
||||
/* If we have no subscription ID, but the transaction is already linked to a Billing agreement, use that */
|
||||
if( empty( \IPS\Request::i()->subscription_id ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$billingAgreement = \IPS\nexus\Gateway\PayPal\BillingAgreement::load( \IPS\Db::i()->select( 't_billing_agreement', 'nexus_transactions', [ 't_id=?', $transaction->id ], flags: \IPS\Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
}
|
||||
catch( \OutOfRangeException | \UnderflowException )
|
||||
{
|
||||
/* Log it, along with the whole request, so that we can try to see what's happening */
|
||||
\IPS\Log::log( "Missing subscription_id " . print_r( \IPS\Request::i(), true ), 'paypal' );
|
||||
throw new Exception( \IPS\Member::loggedIn()->language()->get( 'billing_agreement_start_error' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Get details */
|
||||
if( !isset( $billingAgreement ) )
|
||||
$response = $transaction->method->api( "billing/subscriptions/" . Request::i()->subscription_id, NULL, 'get' );
|
||||
|
||||
/* Create Billing Agreement */
|
||||
try
|
||||
{
|
||||
$response = $transaction->method->api( "billing/subscriptions/" . $subscriptionId, NULL, 'get' );
|
||||
|
||||
/* Create Billing Agreement */
|
||||
try
|
||||
{
|
||||
/* @note SELECT_FROM_WRITE_SERVER transaction race condition */
|
||||
$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 ), flags: \IPS\Db::SELECT_FROM_WRITE_SERVER )->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();
|
||||
$billingAgreement = BillingAgreement::constructFromData( Db::i()->select( '*', 'nexus_billing_agreements', array( 'ba_gw_id=? AND ba_method=?', $response['id'], $transaction->method->id ), flags: Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
}
|
||||
catch (UnderflowException )
|
||||
{
|
||||
$billingAgreement = new 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();
|
||||
|
||||
/* Check Fraud */
|
||||
$fraudResult = $fraudCheck( $transaction, FALSE );
|
||||
|
||||
/* Just save that we're waiting for the webhook, but also try again in a few minutes because PayPal is flakey */
|
||||
$transaction->status = \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING;
|
||||
$transaction->status = 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() );
|
||||
Db::i()->update( 'core_tasks', array( 'enabled' => 1 ), "`key`='gatewayPending'" );
|
||||
Output::i()->redirect( $transaction->url() );
|
||||
}
|
||||
|
||||
/* Billing Agreement (DEPRECATED) */
|
||||
elseif ( isset( \IPS\Request::i()->billingAgreement ) )
|
||||
elseif ( isset( Request::i()->billingAgreement ) )
|
||||
{
|
||||
/* Execute */
|
||||
$response = $transaction->method->api( "payments/billing-agreements/" . \IPS\Request::i()->token . "/agreement-execute" );
|
||||
$response = $transaction->method->api( "payments/billing-agreements/" . Request::i()->token . "/agreement-execute" );
|
||||
$agreementId = $response['id'];
|
||||
if ( isset( $response['payer'] ) and isset( $response['payer']['status'] ) )
|
||||
{
|
||||
@@ -122,12 +112,12 @@ try
|
||||
}
|
||||
|
||||
/* Create Billing Agreement */
|
||||
$billingAgreement = new \IPS\nexus\Gateway\PayPal\BillingAgreement;
|
||||
$billingAgreement = new BillingAgreement;
|
||||
$billingAgreement->gw_id = $agreementId;
|
||||
$billingAgreement->method = $transaction->method;
|
||||
$billingAgreement->member = $transaction->member;
|
||||
$billingAgreement->started = \IPS\DateTime::create();
|
||||
$billingAgreement->next_cycle = \IPS\DateTime::create()->add( new \DateInterval( 'P' . $response['plan']['payment_definitions'][0]['frequency_interval'] . mb_substr( $response['plan']['payment_definitions'][0]['frequency'], 0, 1 ) ) );
|
||||
$billingAgreement->next_cycle = \IPS\DateTime::create()->add( new DateInterval( 'P' . $response['plan']['payment_definitions'][0]['frequency_interval'] . mb_substr( $response['plan']['payment_definitions'][0]['frequency'], 0, 1 ) ) );
|
||||
$billingAgreement->save();
|
||||
$transaction->billing_agreement = $billingAgreement;
|
||||
$transaction->save();
|
||||
@@ -144,7 +134,7 @@ try
|
||||
|
||||
/* Check Fraud Actions */
|
||||
$fraudResult = $fraudCheck( $transaction );
|
||||
if ( $fraudResult and $fraudResult !== \IPS\nexus\Transaction::STATUS_PAID )
|
||||
if ( $fraudResult and $fraudResult !== Transaction::STATUS_PAID )
|
||||
{
|
||||
$transaction->executeFraudAction( $fraudResult, TRUE );
|
||||
}
|
||||
@@ -161,30 +151,30 @@ try
|
||||
$memberJustCreated = $transaction->approve();
|
||||
if ( $memberJustCreated )
|
||||
{
|
||||
\IPS\Session::i()->setMember( $memberJustCreated );
|
||||
\IPS\Member\Device::loadOrCreate( $memberJustCreated, FALSE )->updateAfterAuthentication( NULL );
|
||||
Session::i()->setMember( $memberJustCreated );
|
||||
Device::loadOrCreate( $memberJustCreated, FALSE )->updateAfterAuthentication( NULL );
|
||||
}
|
||||
}
|
||||
|
||||
$transaction->sendNotification();
|
||||
\IPS\Output::i()->redirect( $transaction->url() );
|
||||
Output::i()->redirect( $transaction->url() );
|
||||
}
|
||||
}
|
||||
|
||||
/* Just save that we're waiting for the webhook */
|
||||
$transaction->status = \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING;
|
||||
$transaction->status = 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() );
|
||||
Db::i()->update( 'core_tasks', array( 'enabled' => 1 ), "`key`='gatewayPending'" );
|
||||
Output::i()->redirect( $transaction->url() );
|
||||
}
|
||||
|
||||
/* Normal */
|
||||
else
|
||||
{
|
||||
$response = $transaction->method->api( "checkout/orders/{$transaction->gw_id}/authorize", array(
|
||||
'payer_id' => \IPS\Request::i()->PayerID,
|
||||
), 'post', TRUE, NULL, NULL, 2 );
|
||||
'payer_id' => Request::i()->PayerID,
|
||||
), 'post', TRUE, NULL, md5( $transaction->invoice->checkoutUrl() . ';' . $transaction->id . ';' . $transaction->gw_id ), 2 );
|
||||
$transaction->gw_id = $response['purchase_units'][0]['payments']['authorizations'][0]['id']; // Was previously a payment ID. This sets it to the actual transaction ID for the authorization. At capture, it will be updated again to the capture transaction ID
|
||||
$transaction->auth = \IPS\DateTime::ts( strtotime( $response['purchase_units'][0]['payments']['authorizations'][0]['expiration_time'] ) );
|
||||
if ( isset( $response['payer'] ) and isset( $response['payer']['status'] ) )
|
||||
@@ -204,23 +194,22 @@ try
|
||||
{
|
||||
$transaction->executeFraudAction( $fraudResult, TRUE );
|
||||
}
|
||||
if ( !$fraudResult or $fraudResult === \IPS\nexus\Transaction::STATUS_PAID )
|
||||
if ( !$fraudResult or $fraudResult === Transaction::STATUS_PAID )
|
||||
{
|
||||
$memberJustCreated = $transaction->captureAndApprove();
|
||||
if ( $memberJustCreated )
|
||||
{
|
||||
\IPS\Session::i()->setMember( $memberJustCreated );
|
||||
\IPS\Member\Device::loadOrCreate( $memberJustCreated, FALSE )->updateAfterAuthentication( NULL );
|
||||
Session::i()->setMember( $memberJustCreated );
|
||||
Device::loadOrCreate( $memberJustCreated, FALSE )->updateAfterAuthentication( NULL );
|
||||
}
|
||||
}
|
||||
$transaction->sendNotification();
|
||||
|
||||
/* Redirect */
|
||||
\IPS\Output::i()->redirect( $transaction->url() );
|
||||
Output::i()->redirect( $transaction->url() );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception $e )
|
||||
{
|
||||
$transaction->method->processException( $transaction, $e );
|
||||
\IPS\Log::log( $e, 'paypal' );
|
||||
\IPS\Output::i()->redirect( $transaction->invoice->checkoutUrl()->setQueryString( array( '_step' => 'checkout_pay', 'err' => $e->getMessage() ) ) );
|
||||
Log::log( $e, 'paypal' );
|
||||
Output::i()->redirect( $transaction->invoice->checkoutUrl()->setQueryString( array( '_step' => 'checkout_pay', 'err' => $e->getMessage() ) ) );
|
||||
}
|
||||
@@ -9,52 +9,66 @@
|
||||
* @since 20 Jul 2017
|
||||
*/
|
||||
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Session\Front::i();
|
||||
use IPS\Log;
|
||||
use IPS\Member;
|
||||
use IPS\Member\Device;
|
||||
use IPS\nexus\Gateway;
|
||||
use IPS\nexus\Gateway\Stripe;
|
||||
use IPS\nexus\Invoice;
|
||||
use IPS\nexus\Money;
|
||||
use IPS\nexus\Transaction;
|
||||
use IPS\Output;
|
||||
use IPS\Request;
|
||||
use IPS\Session;
|
||||
use IPS\Session\Front;
|
||||
use IPS\Settings;
|
||||
|
||||
\IPS\Output::setCacheTime( false );
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
Front::i();
|
||||
|
||||
Output::i()->pageCaching = FALSE;
|
||||
|
||||
/* Get the invoice */
|
||||
try
|
||||
{
|
||||
$invoice = \IPS\nexus\Invoice::load( \IPS\Request::i()->invoice );
|
||||
$invoice = Invoice::load( Request::i()->invoice );
|
||||
|
||||
if ( !$invoice->canView() )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
catch (OutOfRangeException )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( json_encode( array( 'success' => 0 ) ), 500, 'application/json' );
|
||||
Output::i()->sendOutput( json_encode( array( 'success' => 0 ) ), 500, 'application/json' );
|
||||
}
|
||||
|
||||
/* Get the gateway */
|
||||
try
|
||||
{
|
||||
$gateway = \IPS\nexus\Gateway::load( \IPS\Request::i()->gateway );
|
||||
if ( !( $gateway instanceof \IPS\nexus\Gateway\Stripe ) )
|
||||
$gateway = Gateway::load( Request::i()->gateway );
|
||||
if ( !( $gateway instanceof Stripe ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
catch (OutOfRangeException )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( json_encode( array( 'success' => 0 ) ), 500, 'application/json' );
|
||||
Output::i()->sendOutput( json_encode( array( 'success' => 0 ) ), 500, 'application/json' );
|
||||
}
|
||||
|
||||
/* Create a transaction */
|
||||
$transaction = new \IPS\nexus\Transaction;
|
||||
$transaction->member = \IPS\Member::loggedIn();
|
||||
$transaction = new Transaction;
|
||||
$transaction->member = Member::loggedIn();
|
||||
$transaction->invoice = $invoice;
|
||||
$transaction->amount = new \IPS\nexus\Money( \IPS\Request::i()->amount, mb_strtoupper( \IPS\Request::i()->currency ) );
|
||||
$transaction->ip = \IPS\Request::i()->ipAddress();
|
||||
$transaction->amount = new Money( Request::i()->amount, mb_strtoupper( Request::i()->currency ) );
|
||||
$transaction->ip = Request::i()->ipAddress();
|
||||
$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 ( Settings::i()->maxmind_key and ( !Settings::i()->maxmind_gateways or Settings::i()->maxmind_gateways == '*' or in_array( $transaction->method->id, explode( ',', Settings::i()->maxmind_gateways ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request;
|
||||
$maxMind->setTransaction( $transaction );
|
||||
@@ -64,25 +78,25 @@ if ( \IPS\Settings::i()->maxmind_key and ( !\IPS\Settings::i()->maxmind_gateways
|
||||
try
|
||||
{
|
||||
/* Authorize */
|
||||
$transaction->auth = $gateway->auth( $transaction, array( "{$gateway->id}_card" => \IPS\Request::i()->token ), $maxMind );
|
||||
$transaction->auth = $gateway->auth( $transaction, array( "{$gateway->id}_card" => Request::i()->token ), $maxMind );
|
||||
|
||||
/* Check Fraud Rules and capture */
|
||||
$memberJustCreated = $transaction->checkFraudRulesAndCapture( $maxMind );
|
||||
if ( $memberJustCreated )
|
||||
{
|
||||
\IPS\Session::i()->setMember( $memberJustCreated );
|
||||
\IPS\Member\Device::loadOrCreate( $memberJustCreated, FALSE )->updateAfterAuthentication( NULL );
|
||||
Session::i()->setMember( $memberJustCreated );
|
||||
Device::loadOrCreate( $memberJustCreated, FALSE )->updateAfterAuthentication( NULL );
|
||||
}
|
||||
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'applepay' );
|
||||
\IPS\Output::i()->sendOutput( json_encode( array( 'success' => 0 ) ), 500, 'application/json' );
|
||||
Log::log( $e, 'applepay' );
|
||||
Output::i()->sendOutput( json_encode( array( 'success' => 0 ) ), 500, 'application/json' );
|
||||
}
|
||||
|
||||
/* Send email receipt */
|
||||
$transaction->sendNotification();
|
||||
|
||||
/* Return */
|
||||
\IPS\Output::i()->sendOutput( json_encode( array( 'success' => 1, 'url' => (string) $transaction->url() ) ), 200, 'application/json' );
|
||||
Output::i()->sendOutput( json_encode( array( 'success' => 1, 'url' => (string) $transaction->url() ) ), 200, 'application/json' );
|
||||
@@ -9,16 +9,26 @@
|
||||
* @since 20 Jul 2017
|
||||
*/
|
||||
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Session\Front::i();
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Member\Device;
|
||||
use IPS\nexus\Transaction;
|
||||
use IPS\Output;
|
||||
use IPS\Request;
|
||||
use IPS\Session;
|
||||
use IPS\Session\Front;
|
||||
use IPS\Settings;
|
||||
|
||||
\IPS\Output::setCacheTime( false );
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
Front::i();
|
||||
|
||||
Output::i()->pageCaching = FALSE;
|
||||
|
||||
/* Little IN_DEV helper to prevent firing this until we've triggered the webhooks */
|
||||
if ( \IPS\IN_DEV and !isset( \IPS\Request::i()->indevconfirm ) )
|
||||
if ( \IPS\IN_DEV and !isset( Request::i()->indevconfirm ) )
|
||||
{
|
||||
echo "<a href='" . \IPS\Request::i()->url()->setQueryString( 'indevconfirm', 1 ) . "'>Continue</a>";
|
||||
echo "<a href='" . Request::i()->url()->setQueryString( 'indevconfirm', 1 ) . "'>Continue</a>";
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -28,37 +38,37 @@ sleep( 5 );
|
||||
/* Load Source */
|
||||
try
|
||||
{
|
||||
$transaction = \IPS\nexus\Transaction::load( \IPS\Request::i()->nexusTransactionId );
|
||||
$intent = $transaction->method->api( 'payment_intents/' . \IPS\Request::i()->payment_intent, null, 'GET' );
|
||||
if( $intent['client_secret'] != \IPS\Request::i()->payment_intent_client_secret )
|
||||
$transaction = Transaction::load( Request::i()->nexusTransactionId );
|
||||
$intent = $transaction->method->api( 'payment_intents/' . Request::i()->payment_intent, null, 'GET' );
|
||||
if( $intent['client_secret'] != Request::i()->payment_intent_client_secret )
|
||||
{
|
||||
throw new \Exception;
|
||||
throw new Exception;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception )
|
||||
{
|
||||
\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 ) );
|
||||
Output::i()->redirect( Url::internal( "app=nexus&module=checkout&controller=checkout&do=transaction&id=&t=" . Request::i()->nexusTransactionId, 'front', 'nexus_checkout', Settings::i()->nexus_https ) );
|
||||
}
|
||||
|
||||
/* 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 )
|
||||
if ( !Member::loggedIn()->member_id and $transaction->member->member_id )
|
||||
{
|
||||
\IPS\Session::i()->setMember( $transaction->member );
|
||||
\IPS\Member\Device::loadOrCreate( $transaction->member, FALSE )->updateAfterAuthentication( NULL );
|
||||
Session::i()->setMember( $transaction->member );
|
||||
Device::loadOrCreate( $transaction->member, FALSE )->updateAfterAuthentication( NULL );
|
||||
}
|
||||
|
||||
/* And then send them on */
|
||||
switch( $intent['status'] )
|
||||
{
|
||||
case 'processing':
|
||||
\IPS\Output::i()->redirect( $transaction->url()->setQueryString( 'pending', 1 ) );
|
||||
Output::i()->redirect( $transaction->url()->setQueryString( 'pending', 1 ) );
|
||||
break;
|
||||
|
||||
case 'succeeded':
|
||||
\IPS\Output::i()->redirect( $transaction->url() );
|
||||
Output::i()->redirect( $transaction->url() );
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -67,6 +77,6 @@ switch( $intent['status'] )
|
||||
{
|
||||
$url = $url->setQueryString( 'err', $intent['last_payment_error']['message'] );
|
||||
}
|
||||
\IPS\Output::i()->redirect( $url );
|
||||
Output::i()->redirect( $url );
|
||||
break;
|
||||
}
|
||||
@@ -9,11 +9,27 @@
|
||||
* @since 20 Jul 2017
|
||||
*/
|
||||
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Session\Front::i();
|
||||
use IPS\core\AdminNotification;
|
||||
use IPS\Db;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Math\Number;
|
||||
use IPS\Member;
|
||||
use IPS\nexus\Customer;
|
||||
use IPS\nexus\Fraud\MaxMind\Request;
|
||||
use IPS\nexus\Gateway;
|
||||
use IPS\nexus\Gateway\Stripe;
|
||||
use IPS\nexus\Invoice;
|
||||
use IPS\nexus\Money;
|
||||
use IPS\nexus\Transaction;
|
||||
use IPS\Output;
|
||||
use IPS\Session\Front;
|
||||
use IPS\Settings;
|
||||
|
||||
\IPS\Output::setCacheTime( false );
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
Front::i();
|
||||
|
||||
Output::i()->pageCaching = FALSE;
|
||||
|
||||
/**
|
||||
* Stripe Webhook Handler
|
||||
@@ -23,17 +39,17 @@ class stripeWebhookHandler
|
||||
/**
|
||||
* @brief Raw Webhook Data (as a string)
|
||||
*/
|
||||
private $body;
|
||||
private mixed $body;
|
||||
|
||||
/**
|
||||
* @brief Parsed Webhook Data (as an array)
|
||||
*/
|
||||
private $data;
|
||||
private array $data;
|
||||
|
||||
/**
|
||||
* @brief Transaction
|
||||
*/
|
||||
private $transaction;
|
||||
private Transaction $transaction;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -41,7 +57,7 @@ class stripeWebhookHandler
|
||||
* @param string $body The raw body posted to this script
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $body )
|
||||
public function __construct( string $body )
|
||||
{
|
||||
$this->body = $body;
|
||||
$this->data = json_decode( $body, TRUE );
|
||||
@@ -52,24 +68,24 @@ class stripeWebhookHandler
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function sourceChargeable()
|
||||
private function sourceChargeable() : string
|
||||
{
|
||||
/* Don't need to do anything for cards, since this is only for asynchronous payments */
|
||||
if ( isset( $this->data['data']['object']['type'] ) and \in_array( $this->data['data']['object']['type'], array( 'card' ) ) )
|
||||
if ( isset( $this->data['data']['object']['type'] ) and in_array( $this->data['data']['object']['type'], array( 'card' ) ) )
|
||||
{
|
||||
return 'NO_PROCESSING_REQUIRED';
|
||||
}
|
||||
|
||||
/* Check the status */
|
||||
if ( !\in_array( $this->transaction->status, array( \IPS\nexus\Transaction::STATUS_PENDING, \IPS\nexus\Transaction::STATUS_WAITING ) ) )
|
||||
if ( !in_array( $this->transaction->status, array( Transaction::STATUS_PENDING, Transaction::STATUS_WAITING ) ) )
|
||||
{
|
||||
if ( \in_array( $this->transaction->status, array( \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING, \IPS\nexus\Transaction::STATUS_PAID ) ) )
|
||||
if ( in_array( $this->transaction->status, array( Transaction::STATUS_GATEWAY_PENDING, Transaction::STATUS_PAID ) ) )
|
||||
{
|
||||
return 'ALREADY_PROCESSED';
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception('BAD_STATUS');
|
||||
throw new Exception('BAD_STATUS');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,19 +93,19 @@ class stripeWebhookHandler
|
||||
$source = $this->transaction->method->api( 'sources/' . preg_replace( '/[^A-Z0-9_]/i', '', $this->data['data']['object']['id'] ), null, 'get' );
|
||||
if ( $source['client_secret'] != $this->data['data']['object']['client_secret'] )
|
||||
{
|
||||
throw new \Exception('BAD_SECRET');
|
||||
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( $this->transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
if ( Settings::i()->maxmind_key and ( !Settings::i()->maxmind_gateways or Settings::i()->maxmind_gateways == '*' or in_array( $this->transaction->method->id, explode( ',', Settings::i()->maxmind_gateways ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request( FALSE );
|
||||
$maxMind = new Request( FALSE );
|
||||
$maxMind->setIpAddress( $this->transaction->ip );
|
||||
$maxMind->setTransaction( $this->transaction );
|
||||
}
|
||||
$fraudResult = $this->transaction->runFraudCheck( $maxMind );
|
||||
if ( $fraudResult === \IPS\nexus\Transaction::STATUS_REFUSED )
|
||||
if ( $fraudResult === Transaction::STATUS_REFUSED )
|
||||
{
|
||||
$this->transaction->executeFraudAction( $fraudResult, FALSE );
|
||||
$this->transaction->sendNotification();
|
||||
@@ -99,7 +115,7 @@ class stripeWebhookHandler
|
||||
else
|
||||
{
|
||||
$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->status = Transaction::STATUS_GATEWAY_PENDING;
|
||||
$this->transaction->save();
|
||||
}
|
||||
|
||||
@@ -112,18 +128,18 @@ class stripeWebhookHandler
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function chargeSucceeded()
|
||||
private function chargeSucceeded() : string
|
||||
{
|
||||
/* Check the status */
|
||||
if ( !\in_array( $this->transaction->status, [ \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING, IPS\nexus\Transaction::STATUS_PENDING ] ) )
|
||||
if ( !in_array( $this->transaction->status, [ Transaction::STATUS_GATEWAY_PENDING, IPS\nexus\Transaction::STATUS_PENDING ] ) )
|
||||
{
|
||||
if ( $this->transaction->status === \IPS\nexus\Transaction::STATUS_PAID )
|
||||
if ( $this->transaction->status === Transaction::STATUS_PAID )
|
||||
{
|
||||
return 'ALREADY_PROCESSED';
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception('BAD_STATUS');
|
||||
throw new Exception('BAD_STATUS');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,21 +147,21 @@ class stripeWebhookHandler
|
||||
try
|
||||
{
|
||||
$charge = $this->transaction->method->api( 'charges/' . preg_replace( '/[^A-Z0-9_]/i', '', $this->data['data']['object']['id'] ), null, 'get' );
|
||||
if ( !\in_array( $charge['status'], array( 'succeeded', 'paid' ) ) )
|
||||
if ( !in_array( $charge['status'], array( 'succeeded', 'paid' ) ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
throw new Exception;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception )
|
||||
{
|
||||
throw new \Exception('INVALID_CHARGE');
|
||||
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( $this->transaction->method->id, explode( ',', \IPS\Settings::i()->maxmind_gateways ) ) ) )
|
||||
if ( Settings::i()->maxmind_key and ( !Settings::i()->maxmind_gateways or Settings::i()->maxmind_gateways == '*' or in_array( $this->transaction->method->id, explode( ',', Settings::i()->maxmind_gateways ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request( FALSE );
|
||||
$maxMind = new Request( FALSE );
|
||||
$maxMind->setIpAddress( $this->transaction->ip );
|
||||
$maxMind->setTransaction( $this->transaction );
|
||||
}
|
||||
@@ -158,11 +174,11 @@ class stripeWebhookHandler
|
||||
}
|
||||
|
||||
/* If we're not being fraud blocked, we can approve */
|
||||
if ( $fraudResult === \IPS\nexus\Transaction::STATUS_PAID )
|
||||
if ( $fraudResult === Transaction::STATUS_PAID )
|
||||
{
|
||||
$this->transaction->member->log( 'transaction', array(
|
||||
'type' => 'paid',
|
||||
'status' => \IPS\nexus\Transaction::STATUS_PAID,
|
||||
'status' => Transaction::STATUS_PAID,
|
||||
'id' => $this->transaction->id,
|
||||
'invoice_id' => $this->transaction->invoice->id,
|
||||
'invoice_title' => $this->transaction->invoice->title,
|
||||
@@ -182,39 +198,39 @@ class stripeWebhookHandler
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function chargeSucceededNew()
|
||||
private function chargeSucceededNew() : string
|
||||
{
|
||||
/* Check the status */
|
||||
if ( !\in_array( $this->transaction->status, [ \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING, IPS\nexus\Transaction::STATUS_PENDING ] ) )
|
||||
if ( !in_array( $this->transaction->status, [ Transaction::STATUS_GATEWAY_PENDING, IPS\nexus\Transaction::STATUS_PENDING ] ) )
|
||||
{
|
||||
if ( $this->transaction->status === \IPS\nexus\Transaction::STATUS_PAID )
|
||||
if ( $this->transaction->status === Transaction::STATUS_PAID )
|
||||
{
|
||||
return 'ALREADY_PROCESSED';
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception('BAD_STATUS');
|
||||
throw new Exception('BAD_STATUS');
|
||||
}
|
||||
}
|
||||
|
||||
/* If the invoice this is for is already paid, this may be a duplicate charge, so don't capture */
|
||||
if ( $this->transaction->invoice->status === \IPS\nexus\Invoice::STATUS_PAID )
|
||||
if ( $this->transaction->invoice->status === Invoice::STATUS_PAID )
|
||||
{
|
||||
throw new \Exception('INVOICE_ALREADY_PAID');
|
||||
throw new Exception('INVOICE_ALREADY_PAID');
|
||||
}
|
||||
|
||||
/* Validate the charge with Stripe */
|
||||
try
|
||||
{
|
||||
$charge = $this->transaction->method->api( 'charges/' . preg_replace( '/[^A-Z0-9_]/i', '', $this->data['data']['object']['id'] ), null, 'get' );
|
||||
if ( !\in_array( $charge['status'], array( 'succeeded', 'paid' ) ) )
|
||||
if ( !in_array( $charge['status'], array( 'succeeded', 'paid' ) ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
throw new Exception;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception )
|
||||
{
|
||||
throw new \Exception('INVALID_CHARGE');
|
||||
throw new Exception('INVALID_CHARGE');
|
||||
}
|
||||
|
||||
/* If this was done by an admin, we just capture and approve straight away */
|
||||
@@ -224,11 +240,11 @@ class stripeWebhookHandler
|
||||
$this->transaction->capture();
|
||||
$this->transaction->member->log( 'transaction', array(
|
||||
'type' => 'paid',
|
||||
'status' => \IPS\nexus\Transaction::STATUS_PAID,
|
||||
'status' => 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'] ) );
|
||||
), Member::load( $this->data['data']['object']['metadata']['Admin'] ) );
|
||||
$this->transaction->approve();
|
||||
}
|
||||
|
||||
@@ -237,15 +253,15 @@ class stripeWebhookHandler
|
||||
{
|
||||
/* 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 ) ) ) )
|
||||
if ( Settings::i()->maxmind_key and ( !Settings::i()->maxmind_gateways or Settings::i()->maxmind_gateways == '*' or in_array( $this->transaction->method->id, explode( ',', Settings::i()->maxmind_gateways ) ) ) )
|
||||
{
|
||||
$maxMind = new \IPS\nexus\Fraud\MaxMind\Request( FALSE );
|
||||
$maxMind = new 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' ) );
|
||||
$this->transaction->auth = \IPS\DateTime::ts( $this->data['data']['object']['created'] )->add( new DateInterval( 'P7D' ) );
|
||||
|
||||
/* Check Fraud Rules and capture */
|
||||
$this->transaction->checkFraudRulesAndCapture( $maxMind );
|
||||
@@ -263,18 +279,18 @@ class stripeWebhookHandler
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function chargeFailed()
|
||||
private function chargeFailed() : string
|
||||
{
|
||||
/* Check the status */
|
||||
if ( !\in_array( $this->transaction->status, [ \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING, IPS\nexus\Transaction::STATUS_PENDING ] ) )
|
||||
if ( !in_array( $this->transaction->status, [ Transaction::STATUS_GATEWAY_PENDING, IPS\nexus\Transaction::STATUS_PENDING ] ) )
|
||||
{
|
||||
if ( $this->transaction->status === \IPS\nexus\Transaction::STATUS_REFUSED )
|
||||
if ( $this->transaction->status === Transaction::STATUS_REFUSED )
|
||||
{
|
||||
return 'ALREADY_PROCESSED';
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception('BAD_STATUS');
|
||||
throw new Exception('BAD_STATUS');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,23 +300,23 @@ class stripeWebhookHandler
|
||||
$charge = $this->transaction->method->api( 'charges/' . preg_replace( '/[^A-Z0-9_]/i', '', $this->data['data']['object']['id'] ), null, 'get' );
|
||||
if ( $charge['status'] !== 'failed' )
|
||||
{
|
||||
throw new \Exception;
|
||||
throw new Exception;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception )
|
||||
{
|
||||
throw new \Exception('INVALID_CHARGE');
|
||||
throw new Exception('INVALID_CHARGE');
|
||||
}
|
||||
|
||||
/* Mark it failed */
|
||||
$this->transaction->status = \IPS\nexus\Transaction::STATUS_REFUSED;
|
||||
$this->transaction->status = Transaction::STATUS_REFUSED;
|
||||
$extra = $this->transaction->extra;
|
||||
$extra['history'][] = array( 's' => \IPS\nexus\Transaction::STATUS_REFUSED, 'noteRaw' => $this->data['data']['object']['failure_message'] );
|
||||
$extra['history'][] = array( 's' => 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,
|
||||
'status' => Transaction::STATUS_REFUSED,
|
||||
'id' => $this->transaction->id,
|
||||
'invoice_id' => $this->transaction->invoice->id,
|
||||
'invoice_title' => $this->transaction->title,
|
||||
@@ -321,15 +337,15 @@ class stripeWebhookHandler
|
||||
private function paymentIntentFailed(): string
|
||||
{
|
||||
/* Check the status */
|
||||
if ( !\in_array( $this->transaction->status, [ \IPS\nexus\Transaction::STATUS_GATEWAY_PENDING, IPS\nexus\Transaction::STATUS_PENDING ] ) )
|
||||
if ( !in_array( $this->transaction->status, [ Transaction::STATUS_GATEWAY_PENDING, Transaction::STATUS_PENDING ] ) )
|
||||
{
|
||||
if ( $this->transaction->status === \IPS\nexus\Transaction::STATUS_REFUSED )
|
||||
if ( $this->transaction->status === Transaction::STATUS_REFUSED )
|
||||
{
|
||||
return 'ALREADY_PROCESSED';
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception('BAD_STATUS');
|
||||
throw new Exception('BAD_STATUS');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,23 +355,23 @@ class stripeWebhookHandler
|
||||
$pi = $this->transaction->method->api( 'payment_intents/' . $this->data['data']['object']['id'], null, 'get' );
|
||||
if ( !is_array( $pi['last_payment_error'] ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
throw new Exception;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch ( Exception $e )
|
||||
{
|
||||
throw new \Exception('INVALID_PI');
|
||||
throw new Exception('INVALID_PI');
|
||||
}
|
||||
|
||||
/* Mark it failed */
|
||||
$this->transaction->status = \IPS\nexus\Transaction::STATUS_REFUSED;
|
||||
$this->transaction->status = Transaction::STATUS_REFUSED;
|
||||
$extra = $this->transaction->extra;
|
||||
$extra['history'][] = array( 's' => \IPS\nexus\Transaction::STATUS_REFUSED, 'noteRaw' => $this->data['data']['object']['last_payment_error']['message'] );
|
||||
$extra['history'][] = array( 's' => Transaction::STATUS_REFUSED, 'noteRaw' => $this->data['data']['object']['last_payment_error']['message'] );
|
||||
$this->transaction->extra = $extra;
|
||||
$this->transaction->save();
|
||||
$this->transaction->member->log( 'transaction', array(
|
||||
'type' => 'paid',
|
||||
'status' => \IPS\nexus\Transaction::STATUS_REFUSED,
|
||||
'status' => Transaction::STATUS_REFUSED,
|
||||
'id' => $this->transaction->id,
|
||||
'invoice_id' => $this->transaction->invoice->id,
|
||||
'invoice_title' => $this->transaction->title,
|
||||
@@ -367,24 +383,24 @@ class stripeWebhookHandler
|
||||
/* Return */
|
||||
return 'OK';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A chargeback/dispute has been made against a transaction so we need to mark it as such locally
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function disputeCreated()
|
||||
private function disputeCreated() : string
|
||||
{
|
||||
/* Validate the dispute with Stripe */
|
||||
try
|
||||
{
|
||||
$dispute = $this->transaction->method->api( 'disputes/' . preg_replace( '/[^A-Z0-9_]/i', '', $this->data['data']['object']['id'] ), null, 'get' );
|
||||
if ( !\in_array( $dispute['status'], array( 'needs_response', 'warning_needs_response' ) ) )
|
||||
if ( !in_array( $dispute['status'], array( 'needs_response', 'warning_needs_response' ) ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
throw new Exception;
|
||||
}
|
||||
|
||||
if ( \substr( $this->transaction->gw_id, 0, 3 ) === 'pi_' )
|
||||
if ( substr( $this->transaction->gw_id, 0, 3 ) === 'pi_' )
|
||||
{
|
||||
$paymentIntent = $this->transaction->method->api( 'charges?payment_intent=' . $this->transaction->gw_id, null, 'get' );
|
||||
|
||||
@@ -400,23 +416,23 @@ class stripeWebhookHandler
|
||||
|
||||
if ( !$ok )
|
||||
{
|
||||
throw new \Exception;
|
||||
throw new Exception;
|
||||
}
|
||||
}
|
||||
elseif ( $dispute['charge'] !== $this->transaction->gw_id )
|
||||
{
|
||||
throw new \Exception;
|
||||
throw new Exception;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception )
|
||||
{
|
||||
throw new \Exception('INVALID_DISPUTE');
|
||||
throw new Exception('INVALID_DISPUTE');
|
||||
}
|
||||
|
||||
/* Mark the transaction as disputed */
|
||||
$this->transaction->status = \IPS\nexus\Transaction::STATUS_DISPUTED;
|
||||
$this->transaction->status = 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'] );
|
||||
$extra['history'][] = array( 's' => Transaction::STATUS_DISPUTED, 'on' => $this->data['data']['object']['created'], 'ref' => $this->data['data']['object']['id'] );
|
||||
$this->transaction->extra = $extra;
|
||||
$this->transaction->save();
|
||||
|
||||
@@ -425,16 +441,16 @@ class stripeWebhookHandler
|
||||
{
|
||||
$this->transaction->member->log( 'transaction', array(
|
||||
'type' => 'status',
|
||||
'status' => \IPS\nexus\Transaction::STATUS_DISPUTED,
|
||||
'status' => Transaction::STATUS_DISPUTED,
|
||||
'id' => $this->transaction->id
|
||||
) );
|
||||
}
|
||||
|
||||
/* Mark the invoice as not paid (revoking benefits) */
|
||||
$this->transaction->invoice->markUnpaid( \IPS\nexus\Invoice::STATUS_CANCELED );
|
||||
$this->transaction->invoice->markUnpaid( Invoice::STATUS_CANCELED );
|
||||
|
||||
/* Send admin notification */
|
||||
\IPS\core\AdminNotification::send( 'nexus', 'Transaction', \IPS\nexus\Transaction::STATUS_DISPUTED, TRUE, $this->transaction );
|
||||
AdminNotification::send( 'nexus', 'Transaction', Transaction::STATUS_DISPUTED, TRUE, $this->transaction );
|
||||
|
||||
/* Return */
|
||||
return 'OK';
|
||||
@@ -445,13 +461,13 @@ class stripeWebhookHandler
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function disputeClosed()
|
||||
private function disputeClosed() : string
|
||||
{
|
||||
/* Validate the dispute with Stripe */
|
||||
try
|
||||
{
|
||||
$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_' )
|
||||
if ( substr( $this->transaction->gw_id, 0, 3 ) === 'pi_' )
|
||||
{
|
||||
$paymentIntent = $this->transaction->method->api( 'charges?payment_intent=' . $this->transaction->gw_id, null, 'get' );
|
||||
|
||||
@@ -467,27 +483,27 @@ class stripeWebhookHandler
|
||||
|
||||
if ( !$ok )
|
||||
{
|
||||
throw new \Exception;
|
||||
throw new Exception;
|
||||
}
|
||||
}
|
||||
elseif ( $dispute['charge'] !== $this->transaction->gw_id )
|
||||
{
|
||||
throw new \Exception;
|
||||
throw new Exception;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception )
|
||||
{
|
||||
throw new \Exception('INVALID_DISPUTE');
|
||||
throw new Exception('INVALID_DISPUTE');
|
||||
}
|
||||
|
||||
/* Did we win or lose? */
|
||||
if ( \in_array( $dispute['status'], array( 'won', 'warning_closed' ) ) )
|
||||
if ( in_array( $dispute['status'], array( 'won', 'warning_closed' ) ) )
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
elseif ( \in_array( $dispute['status'], array( 'lost' ) ) )
|
||||
elseif ( in_array( $dispute['status'], array( 'lost' ) ) )
|
||||
{
|
||||
$this->transaction->status = \IPS\nexus\Transaction::STATUS_REFUNDED;
|
||||
$this->transaction->status = Transaction::STATUS_REFUNDED;
|
||||
$this->transaction->save();
|
||||
}
|
||||
|
||||
@@ -499,12 +515,12 @@ class stripeWebhookHandler
|
||||
* Run
|
||||
*
|
||||
* @param string $signature The signature provided by this request
|
||||
* @return void
|
||||
* @return string
|
||||
*/
|
||||
public function run( $signature )
|
||||
public function run( string $signature ) : string
|
||||
{
|
||||
/* 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'/*, 'payment_intent.payment_failed'*/ ) ) )
|
||||
if ( !isset( $this->data['type'] ) or !in_array( $this->data['type'], array( 'source.chargeable', 'charge.succeeded', 'charge.failed', 'charge.dispute.created', 'charge.dispute.closed', 'payment_intent.payment_failed' ) ) )
|
||||
{
|
||||
return 'UNNEEDED_TYPE';
|
||||
}
|
||||
@@ -515,21 +531,19 @@ class stripeWebhookHandler
|
||||
{
|
||||
if ( isset( $this->data['data']['object']['metadata']['Transaction ID'] ) )
|
||||
{
|
||||
/* @note SELECT_FROM_WRITE_SERVER transaction race condition */
|
||||
$this->transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', array( 't_id=?', $this->data['data']['object']['metadata']['Transaction ID'] ), flags: \IPS\Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
$this->transaction = Transaction::constructFromData( Db::i()->select( '*', 'nexus_transactions', array( 't_id=?', $this->data['data']['object']['metadata']['Transaction ID'] ), flags: Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
}
|
||||
elseif ( isset( $this->data['data']['object']['redirect']['return_url'] ) )
|
||||
{
|
||||
$url = new \IPS\Http\Url( $this->data['data']['object']['redirect']['return_url'] );
|
||||
/* @note SELECT_FROM_WRITE_SERVER transaction race condition */
|
||||
$this->transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', array( 't_id=?', $url->queryString['nexusTransactionId'] ), flags: \IPS\Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
$url = new Url( $this->data['data']['object']['redirect']['return_url'] );
|
||||
$this->transaction = Transaction::constructFromData( Db::i()->select( '*', 'nexus_transactions', array( 't_id=?', $url->queryString['nexusTransactionId'] ), flags: Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
}
|
||||
elseif ( isset( $this->data['data']['object']['charge'] ) )
|
||||
{
|
||||
$paymentIntentId = NULL;
|
||||
foreach ( \IPS\nexus\Gateway::roots() as $method )
|
||||
foreach ( Gateway::roots() as $method )
|
||||
{
|
||||
if ( $method instanceof \IPS\nexus\Gateway\Stripe )
|
||||
if ( $method instanceof Stripe )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -540,7 +554,7 @@ class stripeWebhookHandler
|
||||
}
|
||||
break;
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception )
|
||||
{
|
||||
// Do nothing - try the next one
|
||||
}
|
||||
@@ -549,13 +563,11 @@ class stripeWebhookHandler
|
||||
|
||||
if ( $paymentIntentId )
|
||||
{
|
||||
/* @note SELECT_FROM_WRITE_SERVER transaction race condition */
|
||||
$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'] ), flags: \IPS\Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
$this->transaction = Transaction::constructFromData( Db::i()->select( '*', 'nexus_transactions', array( '( t_gw_id=? OR t_gw_id=? )', $paymentIntentId, $this->data['data']['object']['charge'] ), flags: Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* @note SELECT_FROM_WRITE_SERVER transaction race condition */
|
||||
$this->transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', array( 't_gw_id=?', $this->data['data']['object']['charge'] ), flags: \IPS\Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
{
|
||||
$this->transaction = Transaction::constructFromData( Db::i()->select( '*', 'nexus_transactions', array( 't_gw_id=?', $this->data['data']['object']['charge'] ), flags: Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
}
|
||||
}
|
||||
elseif ( isset( $this->data['data']['object']['id'] ) and mb_substr( $this->data['data']['object']['id'], 0, 4 ) !== 'src_' )
|
||||
@@ -576,24 +588,23 @@ class stripeWebhookHandler
|
||||
|
||||
try
|
||||
{
|
||||
/* @note SELECT_FROM_WRITE_SERVER transaction race condition */
|
||||
$this->transaction = \IPS\nexus\Transaction::constructFromData( \IPS\Db::i()->select( '*', 'nexus_transactions', $where, flags: \IPS\Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
$this->transaction = Transaction::constructFromData( Db::i()->select( '*', 'nexus_transactions', $where, flags: Db::SELECT_FROM_WRITE_SERVER )->first() );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
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'] ) );
|
||||
$invoice = 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 = new Transaction;
|
||||
$this->transaction->member = isset( $this->data['data']['object']['metadata']['Customer ID'] ) ? 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->amount = new Money( new 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->gw_id = $this->data['data']['object']['payment_intent'] ?? $this->data['data']['object']['id'];
|
||||
$this->transaction->status = Transaction::STATUS_PENDING;
|
||||
$this->transaction->method = Gateway::load( intval( $this->data['data']['object']['metadata']['Payment Method ID'] ) );
|
||||
$this->transaction->save();
|
||||
|
||||
$new = TRUE;
|
||||
@@ -609,20 +620,20 @@ class stripeWebhookHandler
|
||||
return 'NO_TRANSACTION_INFORMATION';
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception )
|
||||
{
|
||||
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');
|
||||
throw new Exception('COULD_NOT_FIND_TRANSACTION');
|
||||
}
|
||||
|
||||
/* Validate the signature */
|
||||
if ( !( $this->transaction->method instanceof \IPS\nexus\Gateway\Stripe ) )
|
||||
if ( !( $this->transaction->method instanceof Stripe ) )
|
||||
{
|
||||
throw new \Exception('INVALID_GATEWAY');
|
||||
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
|
||||
@@ -630,7 +641,7 @@ class stripeWebhookHandler
|
||||
$sig = array();
|
||||
foreach ( explode( ',', $signature ) as $row )
|
||||
{
|
||||
if ( \strpos( $row, '=' ) !== FALSE )
|
||||
if ( strpos( $row, '=' ) !== FALSE )
|
||||
{
|
||||
list( $k, $v ) = explode( '=', trim( $row ) );
|
||||
$sig[ trim( $k ) ][] = trim( $v );
|
||||
@@ -642,14 +653,14 @@ class stripeWebhookHandler
|
||||
$signedPayload = $sig['t'][0] . '.' . $this->body;
|
||||
$signature = hash_hmac( 'sha256', $signedPayload, $settings['webhook_secret'] );
|
||||
|
||||
if ( !\in_array( $signature, $sig['v1'] ) )
|
||||
if ( !in_array( $signature, $sig['v1'] ) )
|
||||
{
|
||||
throw new \Exception('INVALID_SIGNING_SECRET');
|
||||
throw new Exception('INVALID_SIGNING_SECRET');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception('INVALID_SIGNING_SECRET');
|
||||
throw new Exception('INVALID_SIGNING_SECRET');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,12 +679,14 @@ class stripeWebhookHandler
|
||||
return $this->disputeCreated();
|
||||
case 'charge.dispute.closed':
|
||||
return $this->disputeClosed();
|
||||
/*case 'payment_intent.payment_failed':
|
||||
return $this->paymentIntentFailed();*/
|
||||
case 'payment_intent.payment_failed':
|
||||
return $this->paymentIntentFailed();
|
||||
default:
|
||||
return 'UNNEEDED_TYPE';
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,10 +694,10 @@ $class = new stripeWebhookHandler( trim( @file_get_contents('php://input') ) );
|
||||
try
|
||||
{
|
||||
sleep( 5 ); // Stripe can send web hooks very quickly, we need to delay to ensure we've processed the transaction first.
|
||||
$response = $class->run( isset( $_SERVER['HTTP_STRIPE_SIGNATURE'] ) ? $_SERVER['HTTP_STRIPE_SIGNATURE'] : '' );
|
||||
\IPS\Output::i()->sendOutput( $response, 200, 'text/plain' );
|
||||
$response = $class->run($_SERVER['HTTP_STRIPE_SIGNATURE'] ?? '');
|
||||
Output::i()->sendOutput( $response, 200, 'text/plain' );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch (Exception $e)
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( $e->getMessage(), 500, 'text/plain' );
|
||||
Output::i()->sendOutput( $e->getMessage(), 500, 'text/plain' );
|
||||
}
|
||||
@@ -9,19 +9,29 @@
|
||||
* @since 01 Apr 2015
|
||||
*/
|
||||
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
\IPS\Dispatcher\External::i();
|
||||
use IPS\Dispatcher\External;
|
||||
use IPS\nexus\Customer;
|
||||
use IPS\nexus\Purchase\LicenseKey;
|
||||
use IPS\Output;
|
||||
use IPS\Request;
|
||||
use const IPS\NEXUS_LKEY_API_ALLOW_IP_OVERRIDE;
|
||||
use const IPS\NEXUS_LKEY_API_CHECK_IP;
|
||||
use const IPS\NEXUS_LKEY_API_DISABLE;
|
||||
|
||||
if ( \IPS\NEXUS_LKEY_API_ALLOW_IP_OVERRIDE )
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
require_once '../../../../init.php';
|
||||
External::i();
|
||||
|
||||
if ( NEXUS_LKEY_API_ALLOW_IP_OVERRIDE )
|
||||
{
|
||||
$_SERVER['REMOTE_ADDR'] = isset( \IPS\Request::i()->ip ) ? \IPS\Request::i()->ip : $_SERVER['REMOTE_ADDR'];
|
||||
$_SERVER['REMOTE_ADDR'] = isset( Request::i()->ip ) ? Request::i()->ip : $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
|
||||
/**
|
||||
* API Exception
|
||||
*/
|
||||
class ApiException extends \Exception { }
|
||||
class ApiException extends Exception
|
||||
{ }
|
||||
|
||||
/**
|
||||
* API class to verify license keys
|
||||
@@ -35,30 +45,31 @@ class Api
|
||||
* @param string $message Status message
|
||||
* @return void
|
||||
*/
|
||||
public function error( $code, $message )
|
||||
public function error( int $code, string $message ) : void
|
||||
{
|
||||
\IPS\Output::setCacheTime( false );
|
||||
\IPS\Output::i()->sendOutput( json_encode( array( 'errorCode' => $code, 'errorMessage' => $message ) ), 400, 'application/json' );
|
||||
Output::i()->pageCaching = FALSE;
|
||||
Output::i()->sendOutput( json_encode( array( 'errorCode' => $code, 'errorMessage' => $message ) ), 400, 'application/json' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get key
|
||||
*
|
||||
* @param bool $validateIdentifier Should the identifier be validated?
|
||||
* @return \IPS\nexus\Purchase\LicenseKey
|
||||
* @return LicenseKey
|
||||
* @throws ApiException
|
||||
*/
|
||||
protected function getKey( $validateIdentifier=TRUE )
|
||||
protected function getKey( bool $validateIdentifier=TRUE ) : LicenseKey
|
||||
{
|
||||
try
|
||||
{
|
||||
$key = \IPS\nexus\Purchase\LicenseKey::load( isset( \IPS\Request::i()->key ) ? \IPS\Request::i()->key : NULL );
|
||||
$key = LicenseKey::load( isset( Request::i()->key ) ? Request::i()->key : NULL );
|
||||
|
||||
if ( $key->key !== \IPS\Request::i()->key )
|
||||
if ( $key->key !== 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 ) )
|
||||
if ( $validateIdentifier and $identifier = $this->getIdentifier( $key ) and ( !isset( Request::i()->identifier ) or $identifier != Request::i()->identifier ) )
|
||||
{
|
||||
throw new ApiException( 'BAD_KEY_OR_ID', 101 );
|
||||
}
|
||||
@@ -78,7 +89,7 @@ class Api
|
||||
|
||||
return $key;
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
catch (OutOfRangeException )
|
||||
{
|
||||
throw new ApiException( 'BAD_KEY_OR_ID', 101 );
|
||||
}
|
||||
@@ -87,24 +98,24 @@ class Api
|
||||
/**
|
||||
* Get identifier
|
||||
*
|
||||
* @param \IPS\nexus\Purchase\LicenseKey $key The license key
|
||||
* @param LicenseKey $key The license key
|
||||
* @return string|NULL
|
||||
*/
|
||||
protected function getIdentifier( \IPS\nexus\Purchase\LicenseKey $key )
|
||||
protected function getIdentifier( LicenseKey $key ) : string|null
|
||||
{
|
||||
$identifier = NULL;
|
||||
switch ( $key->identifier )
|
||||
{
|
||||
case 'name':
|
||||
$identifier = \IPS\nexus\Customer::load( $key->member )->cm_name;
|
||||
$identifier = Customer::load( $key->member )->cm_name;
|
||||
break;
|
||||
|
||||
case 'email':
|
||||
$identifier = \IPS\nexus\Customer::load( $key->member )->email;
|
||||
$identifier = Customer::load( $key->member )->email;
|
||||
break;
|
||||
|
||||
case 'username':
|
||||
$identifier = \IPS\nexus\Customer::load( $key->member )->name;
|
||||
$identifier = Customer::load( $key->member )->name;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -122,8 +133,9 @@ class Api
|
||||
* Activate
|
||||
*
|
||||
* @return void
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function activate()
|
||||
public function activate() : void
|
||||
{
|
||||
$key = $this->getKey( FALSE );
|
||||
|
||||
@@ -133,19 +145,19 @@ class Api
|
||||
}
|
||||
|
||||
$identifier = $this->getIdentifier( $key );
|
||||
$providedIdentifier = isset( \IPS\Request::i()->identifier ) ? \IPS\Request::i()->identifier : NULL;
|
||||
if ( isset( \IPS\Request::i()->setIdentifier ) and \IPS\Request::i()->setIdentifier )
|
||||
$providedIdentifier = isset( Request::i()->identifier ) ? Request::i()->identifier : NULL;
|
||||
if ( isset( Request::i()->setIdentifier ) and Request::i()->setIdentifier )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
else
|
||||
{
|
||||
$cfields = $key->purchase->custom_fields;
|
||||
$cfields[ $key->identifier ] = \IPS\Request::i()->setIdentifier;
|
||||
$cfields[ $key->identifier ] = Request::i()->setIdentifier;
|
||||
$key->purchase->custom_fields = $cfields;
|
||||
$key->purchase->save();
|
||||
}
|
||||
@@ -156,9 +168,9 @@ 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'];
|
||||
$ip = $this->params['ip'] ?: $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -172,25 +184,26 @@ class Api
|
||||
'activated' => time(),
|
||||
'ip' => $ip,
|
||||
'last_checked' => 0,
|
||||
'extra' => isset( \IPS\Request::i()->extra ) ? json_decode( \IPS\Request::i()->extra ) : NULL,
|
||||
'extra' => isset( Request::i()->extra ) ? json_decode( Request::i()->extra ) : NULL,
|
||||
);
|
||||
|
||||
$key->activate_data = $activateData;
|
||||
$key->uses++;
|
||||
$key->save();
|
||||
|
||||
\IPS\nexus\Customer::load( $key->member )->log( 'lkey', array( 'type' => 'activated', 'key' => $key->key, 'ps_id' => $key->purchase->id ), FALSE );
|
||||
Customer::load( $key->member )->log( 'lkey', array( 'type' => 'activated', 'key' => $key->key, 'ps_id' => $key->purchase->id ), FALSE );
|
||||
|
||||
\IPS\Output::setCacheTime( false );
|
||||
\IPS\Output::i()->sendOutput( json_encode( array( 'response' => 'OKAY', 'usage_id' => $k ) ), 200, 'application/json' );
|
||||
Output::i()->pageCaching = FALSE;
|
||||
Output::i()->sendOutput( json_encode( array( 'response' => 'OKAY', 'usage_id' => $k ) ), 200, 'application/json' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check
|
||||
*
|
||||
* @return void
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function check()
|
||||
public function check() : void
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -202,9 +215,9 @@ class Api
|
||||
{
|
||||
case 102:
|
||||
case 103:
|
||||
\IPS\Output::i()->sendOutput( json_encode( array( 'status' => 'INACTIVE' ) ), 200, 'application/json', \IPS\Output::getCacheHeaders( time(), 360 ) );
|
||||
Output::i()->sendOutput( json_encode( array( 'status' => 'INACTIVE' ) ), 200, 'application/json', Output::getCacheHeaders( time(), 360 ) );
|
||||
case 104:
|
||||
\IPS\Output::i()->sendOutput( json_encode( array( 'status' => 'EXPIRED' ) ), 200, 'application/json', \IPS\Output::getCacheHeaders( time(), 360 ) );
|
||||
Output::i()->sendOutput( json_encode( array( 'status' => 'EXPIRED' ) ), 200, 'application/json', Output::getCacheHeaders( time(), 360 ) );
|
||||
|
||||
default:
|
||||
throw $e;
|
||||
@@ -212,28 +225,29 @@ class Api
|
||||
}
|
||||
|
||||
$activateData = $key->activate_data;
|
||||
if ( !isset( \IPS\Request::i()->usage_id ) or !isset( $activateData[ \IPS\Request::i()->usage_id ] ) )
|
||||
if ( !isset( Request::i()->usage_id ) or !isset( $activateData[ Request::i()->usage_id ] ) )
|
||||
{
|
||||
throw new ApiException( 'BAD_USAGE_ID', 303 );
|
||||
}
|
||||
if ( \IPS\NEXUS_LKEY_API_CHECK_IP and $activateData[ \IPS\Request::i()->usage_id ]['ip'] != $_SERVER['REMOTE_ADDR'] )
|
||||
if ( NEXUS_LKEY_API_CHECK_IP and $activateData[ Request::i()->usage_id ]['ip'] != $_SERVER['REMOTE_ADDR'] )
|
||||
{
|
||||
throw new ApiException( 'BAD_IP', 304 );
|
||||
}
|
||||
|
||||
$activateData[ \IPS\Request::i()->usage_id ]['last_checked'] = time();
|
||||
$activateData[ Request::i()->usage_id ]['last_checked'] = time();
|
||||
$key->activate_data = $activateData;
|
||||
$key->save();
|
||||
|
||||
\IPS\Output::i()->sendOutput( json_encode( array( 'status' => 'ACTIVE', 'uses' => $key->uses, 'max_uses' => $key->max_uses ) ), 200, 'application/json', \IPS\Output::getCacheHeaders( time(), 360 ) );
|
||||
Output::i()->sendOutput( json_encode( array( 'status' => 'ACTIVE', 'uses' => $key->uses, 'max_uses' => $key->max_uses ) ), 200, 'application/json', Output::getCacheHeaders( time(), 360 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Information
|
||||
*
|
||||
* @return void
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function info()
|
||||
public function info() : void
|
||||
{
|
||||
$key = $this->getKey();
|
||||
|
||||
@@ -253,7 +267,7 @@ class Api
|
||||
);
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sendOutput( json_encode( array(
|
||||
Output::i()->sendOutput( json_encode( array(
|
||||
'key' => $key->key,
|
||||
'identifier' => $this->getIdentifier( $key ),
|
||||
'generated' => $key->generated->getTimestamp(),
|
||||
@@ -266,47 +280,48 @@ class Api
|
||||
'purchase_start' => $key->purchase->start->getTimestamp(),
|
||||
'purchase_expire' => $key->purchase->expire ? $key->purchase->expire->getTimestamp() : NULL,
|
||||
'purchase_children' => $children,
|
||||
'customer_name' => \IPS\nexus\Customer::load( $key->member )->cm_name,
|
||||
'customer_email' => \IPS\nexus\Customer::load( $key->member )->email,
|
||||
'customer_name' => Customer::load( $key->member )->cm_name,
|
||||
'customer_email' => Customer::load( $key->member )->email,
|
||||
'uses' => $key->uses,
|
||||
'max_uses' => $key->max_uses
|
||||
) ), 200, 'application/json', \IPS\Output::getCacheHeaders( time(), 360 ) );
|
||||
) ), 200, 'application/json', Output::getCacheHeaders( time(), 360 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update extra information
|
||||
*
|
||||
* @return void
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function updateExtra()
|
||||
public function updateExtra() : void
|
||||
{
|
||||
$key = $this->getKey();
|
||||
|
||||
$activateData = $key->activate_data;
|
||||
if ( !isset( \IPS\Request::i()->usage_id ) or !isset( $activateData[ \IPS\Request::i()->usage_id ] ) )
|
||||
if ( !isset( Request::i()->usage_id ) or !isset( $activateData[ Request::i()->usage_id ] ) )
|
||||
{
|
||||
throw new ApiException( 'BAD_USAGE_ID', 303 );
|
||||
}
|
||||
if ( \IPS\NEXUS_LKEY_API_CHECK_IP and $activateData[ \IPS\Request::i()->usage_id ]['ip'] != $_SERVER['REMOTE_ADDR'] )
|
||||
if ( NEXUS_LKEY_API_CHECK_IP and $activateData[ Request::i()->usage_id ]['ip'] != $_SERVER['REMOTE_ADDR'] )
|
||||
{
|
||||
throw new ApiException( 'BAD_IP', 304 );
|
||||
}
|
||||
|
||||
$activateData[ \IPS\Request::i()->usage_id ]['extra'] = isset( \IPS\Request::i()->extra ) ? json_decode( \IPS\Request::i()->extra ) : NULL;
|
||||
$activateData[ Request::i()->usage_id ]['extra'] = isset( Request::i()->extra ) ? json_decode( Request::i()->extra ) : NULL;
|
||||
$key->activate_data = $activateData;
|
||||
$key->save();
|
||||
|
||||
\IPS\Output::setCacheTime( false );
|
||||
\IPS\Output::i()->sendOutput( json_encode( array( 'status' => 'OKAY' ) ), 200, 'application/json' );
|
||||
|
||||
Output::i()->pageCaching = FALSE;
|
||||
Output::i()->sendOutput( json_encode( array( 'status' => 'OKAY' ) ), 200, 'application/json' );
|
||||
}
|
||||
}
|
||||
|
||||
$api = new api;
|
||||
if ( !\IPS\NEXUS_LKEY_API_DISABLE )
|
||||
if ( !NEXUS_LKEY_API_DISABLE )
|
||||
{
|
||||
foreach ( array( 'activate', 'check', 'info', 'updateExtra' ) as $k )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->$k ) )
|
||||
if ( isset( Request::i()->$k ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -316,7 +331,7 @@ if ( !\IPS\NEXUS_LKEY_API_DISABLE )
|
||||
{
|
||||
$api->error( $e->getMessage(), $e->getCode() );
|
||||
}
|
||||
catch ( Exception $e )
|
||||
catch ( Exception )
|
||||
{
|
||||
$api->error( 0, 'INTERNAL_ERROR' );
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user