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
|
|||
192 | } |
||
193 | } |
||
194 |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.