Failed Conditions
Push — develop ( d770ee...37124d )
by Remco
05:08
created

NotificationController::is_legacy_request()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 1
b 0
f 0
nc 3
nop 0
dl 0
loc 23
ccs 0
cts 8
cp 0
crap 12
rs 10
1
<?php
2
/**
3
 * Notification controller
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2021 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Pay\Gateways\IDealBasic
9
 */
10
11
namespace Pronamic\WordPress\Pay\Gateways\IDealBasic;
12
13
use Pronamic\WordPress\Pay\Plugin;
14
use Pronamic\WordPress\Pay\Core\Util as Core_Util;
15
use Pronamic\WordPress\Pay\Gateways\IDealBasic\XML\NotificationParser;
16
17
/**
18
 * Notification controller
19
 *
20
 * @author  Remco Tolsma
21
 * @version 1.0.0
22
 * @since   1.0.0
23
 */
24
class NotificationController {
25
	/**
26
	 * Setup.
27
	 *
28
	 * @return void
29
	 */
30
	public function setup() {
31
		\add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
32
33
		\add_action( 'wp_loaded', array( $this, 'wp_loaded' ) );
34
	}
35
36
	/**
37
	 * REST API init.
38
	 *
39
	 * @link https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/
40
	 * @link https://developer.wordpress.org/reference/hooks/rest_api_init/
41
	 * @return void
42
	 */
43
	public function rest_api_init() {
44
		\register_rest_route(
45
			Integration::REST_ROUTE_NAMESPACE,
46
			'/notification',
47
			array(
48
				'methods'             => 'POST',
49
				'callback'            => array( $this, 'rest_api_notification' ),
50
				'permission_callback' => '__return_true',
51
			)
52
		);
53
	}
54
55
	/**
56
	 * REST API iDEAL XML notification handler.
57
	 *
58
	 * @param \WP_REST_Request $request Request.
59
	 * @return object
60
	 * @throws \Exception Throws exception when something unexpected happens ;-).
61
	 */
62
	public function rest_api_notification( \WP_REST_Request $request ) {
63
		$body = $request->get_body();
64
65
		if ( empty( $body ) ) {
66
			return new \WP_Error(
67
				'ideal_basic_empty_notification',
68
				__( 'The iDEAL Basic notification is empty.', 'pronamic_ideal' ),
69
				array( 'status' => 400 )
70
			);
71
		}
72
73
		$xml = Core_Util::simplexml_load_string( $body );
74
75
		if ( \is_wp_error( $xml ) ) {
76
			return $xml;
77
		}
78
79
		$notification = NotificationParser::parse( $xml );
80
81
		// Get payment for purchase ID.
82
		$purchase_id = $notification->get_purchase_id();
83
84
		$payment = get_pronamic_payment_by_purchase_id( $purchase_id );
85
86
		if ( null === $payment ) {
87
			return new \WP_Error(
88
				'ideal_basic_no_payment',
89
				\sprintf(
90
					/* translators: %s: Purchase ID. */
91
					__( 'Could not find iDEAL Basic payment by purchase ID: %s.', 'pronamic_ideal' ),
92
					$purchase_id
93
				),
94
				array( 'status' => 404 )
95
			);
96
		}
97
98
		// Add note.
99
		$note = sprintf(
100
			/* translators: %s: payment provider name */
101
			__( 'Webhook requested by %s.', 'pronamic_ideal' ),
102
			__( 'iDEAL Basic', 'pronamic_ideal' )
103
		);
104
105
		$payment->add_note( $note );
106
107
		// Update payment with notification data.
108
		$payment->set_status( $notification->get_status() );
109
		$payment->set_transaction_id( $notification->get_transaction_id() );
110
111
		// Log webhook request.
112
		\do_action( 'pronamic_pay_webhook_log_payment', $payment );
113
114
		// Update payment.
115
		Plugin::update_payment( $payment );
116
	}
117
118
	/**
119
	 * Check if legacy notification URL requests.
120
	 * 
121
	 * @return bool True if legacy notification request, false otherwise.
122
	 */
123
	private function is_legacy_request() {
124
		/**
125
		 * In version <= `2.1.3` we used: `?gateway=IDealBasic&xml_notification=true`.
126
		 * 
127
		 * @link https://github.com/wp-pay-gateways/ideal-basic/blob/2.1.3/src/Integration.php#L85-L91
128
		 * @link https://github.com/wp-pay-gateways/ideal-basic/blob/2.1.3/src/Listener.php#L24-L27
129
		 */
130
		if ( \filter_has_var( INPUT_GET, 'xml_notification' ) ) {
131
			return true;
132
		}
133
134
		/**
135
		 * In version <= `1.1.3` we used a typo: `?gateway=ideal_basic&xml_notification=true`.
136
		 * 
137
		 * @link https://github.com/wp-pay-gateways/ideal-basic/blob/1.1.3/src/Settings.php#L51
138
		 * @link https://github.com/wp-pay-gateways/ideal-basic/commit/94bf9d8e011fb77700bb86fbcacd7a3f359fd496
139
		 * @link https://github.com/wp-pay-gateways/ideal-basic/commit/e4c0653015b16cb8c3e5a0a4099cee2d2c19ff8d#diff-eb1710f64250974d6d1550d421a31054e6079592ae3a8428cd9530bc086bdd94L51
140
		 */
141
		if ( \filter_has_var( INPUT_GET, 'xml_notifaction' ) ) {
142
			return true;
143
		}
144
145
		return false;
146
	}
147
148
	/**
149
	 * WordPress loaded, check for deprecated webhook call.
150
	 *
151
	 * @link https://github.com/WordPress/WordPress/blob/5.3/wp-includes/rest-api.php#L277-L309
152
	 * @return void
153
	 */
154
	public function wp_loaded() {
155
		// Also check for typo 'xml_notifaction', as this has been used in the past.
156
		if ( ! $this->is_legacy_request() ) {
157
			return;
158
		}
159
160
		\rest_get_server()->serve_request( '/pronamic-pay/ideal-basic/v1/notification' );
161
162
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
163
	}
164
}
165