Issues (22)

src/WebhookController.php (1 issue)

Severity
1
<?php
2
/**
3
 * Webhook controller
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2022 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Pay\Gateways\Mollie
9
 */
10
11
namespace Pronamic\WordPress\Pay\Gateways\Mollie;
12
13
use Pronamic\WordPress\Pay\Plugin;
14
use WP_REST_Request;
15
use WP_REST_Response;
16
17
/**
18
 * Webhook controller
19
 *
20
 * @link https://docs.mollie.com/guides/webhooks
21
 *
22
 * @author  Remco Tolsma
23
 * @version 2.1.0
24
 * @since   2.1.0
25
 */
26
class WebhookController {
27
	/**
28
	 * Setup.
29
	 *
30
	 * @return void
31
	 */
32
	public function setup() {
33
		add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
34
35
		add_action( 'wp_loaded', array( $this, 'wp_loaded' ) );
36
	}
37
38
	/**
39
	 * REST API init.
40
	 *
41
	 * @link https://docs.mollie.com/overview/webhooks
42
	 * @link https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/
43
	 * @link https://developer.wordpress.org/reference/hooks/rest_api_init/
44
	 *
45
	 * @return void
46
	 */
47
	public function rest_api_init() {
48
		\register_rest_route(
49
			Integration::REST_ROUTE_NAMESPACE,
50
			'/webhook',
51
			array(
52
				'methods'             => 'POST',
53
				'callback'            => array( $this, 'rest_api_mollie_webhook' ),
54
				'args'                => array(
55
					'id' => array(
56
						'description' => \__( 'Mollie transaction ID.', 'pronamic_ideal' ),
57
						'type'        => 'string',
58
						'required'    => true,
59
					),
60
				),
61
				'permission_callback' => '__return_true',
62
			)
63
		);
64
65
		\register_rest_route(
66
			Integration::REST_ROUTE_NAMESPACE,
67
			'/webhook/(?P<payment_id>\d+)',
68
			array(
69
				'methods'             => 'POST',
70
				'callback'            => array( $this, 'rest_api_mollie_webhook_payment' ),
71
				'args'                => array(
72
					'payment_id' => array(
73
						'description' => \__( 'Payment ID.', 'pronamic_ideal' ),
74
						'type'        => 'string',
75
						'required'    => true,
76
					),
77
					'id'         => array(
78
						'description' => \__( 'Mollie transaction ID.', 'pronamic_ideal' ),
79
						'type'        => 'string',
80
						'required'    => true,
81
					),
82
				),
83
				'permission_callback' => '__return_true',
84
			)
85
		);
86
	}
87
88
	/**
89
	 * REST API Mollie webhook handler.
90
	 *
91
	 * @param WP_REST_Request $request Request.
92
	 * @return object
93
	 */
94
	public function rest_api_mollie_webhook( WP_REST_Request $request ) {
95
		$id = $request->get_param( 'id' );
96
97
		if ( empty( $id ) ) {
98
			return $this->rest_api_mollie_webhook_payment( $request );
99
		}
100
101
		$payment = \get_pronamic_payment_by_transaction_id( $id );
102
103
		if ( null !== $payment ) {
104
			$request->set_param( 'payment_id', $payment->get_id() );
105
		}
106
107
		return $this->rest_api_mollie_webhook_payment( $request );
108
	}
109
110
	/**
111
	 * REST API Mollie webhook handler.
112
	 *
113
	 * @param WP_REST_Request $request Request.
114
	 * @return object
115
	 */
116
	public function rest_api_mollie_webhook_payment( WP_REST_Request $request ) {
117
		$id = $request->get_param( 'id' );
118
119
		/**
120
		 * Result.
121
		 *
122
		 * @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
123
		 */
124
		$response = new WP_REST_Response(
125
			array(
126
				'success' => true,
127
				'id'      => $id,
128
			)
129
		);
130
131
		$response->add_link( 'self', rest_url( $request->get_route() ) );
132
133
		/**
134
		 * Payment.
135
		 */
136
		$payment_id = $request->get_param( 'payment_id' );
137
138
		if ( empty( $payment_id ) ) {
139
			return $response;
140
		}
141
142
		$payment = \get_pronamic_payment( $payment_id );
143
144
		if ( null === $payment ) {
145
			/**
146
			 * How to handle unknown IDs?
147
			 *
148
			 * To not leak any information to malicious third parties, it is recommended
149
			 * to return a 200 OK response even if the ID is not known to your system.
150
			 *
151
			 * @link https://docs.mollie.com/guides/webhooks#how-to-handle-unknown-ids
152
			 */
153
			return $response;
154
		}
155
156
		// Add note.
157
		$note = \sprintf(
158
			/* translators: %s: payment provider name */
159
			\__( 'Webhook requested by %s.', 'pronamic_ideal' ),
160
			\__( 'Mollie', 'pronamic_ideal' )
161
		);
162
163
		$payment->add_note( $note );
164
165
		// Log webhook request.
166
		\do_action( 'pronamic_pay_webhook_log_payment', $payment );
167
168
		// Update payment.
169
		Plugin::update_payment( $payment, false );
170
171
		return $response;
172
	}
173
174
	/**
175
	 * WordPress loaded, check for deprecated webhook call.
176
	 *
177
	 * @link https://github.com/WordPress/WordPress/blob/5.3/wp-includes/rest-api.php#L277-L309
178
	 * @return void
179
	 */
180
	public function wp_loaded() {
181
		if ( ! filter_has_var( INPUT_GET, 'mollie_webhook' ) ) {
182
			return;
183
		}
184
185
		if ( ! filter_has_var( INPUT_POST, 'id' ) ) {
186
			return;
187
		}
188
189
		\rest_get_server()->serve_request( '/pronamic-pay/mollie/v1/webhook' );
190
191
		exit;
0 ignored issues
show
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...
192
	}
193
}
194