1 | <?php |
||
2 | /** |
||
3 | * Integration |
||
4 | * |
||
5 | * @author Pronamic <[email protected]> |
||
6 | * @copyright 2005-2020 Pronamic |
||
7 | * @license GPL-3.0-or-later |
||
8 | * @package Pronamic\WordPress\Pay\Gateways\Adyen |
||
9 | */ |
||
10 | |||
11 | namespace Pronamic\WordPress\Pay\Gateways\Adyen; |
||
12 | |||
13 | use Pronamic\WordPress\Pay\Dependencies\PhpExtensionDependency; |
||
14 | use Pronamic\WordPress\Pay\AbstractGatewayIntegration; |
||
15 | use Pronamic\WordPress\Pay\Util as Pay_Util; |
||
16 | |||
17 | /** |
||
18 | * Integration |
||
19 | * |
||
20 | * @author Remco Tolsma |
||
21 | * @version 1.1.2 |
||
22 | * @since 1.0.0 |
||
23 | */ |
||
24 | class Integration extends AbstractGatewayIntegration { |
||
25 | /** |
||
26 | * REST route namespace. |
||
27 | * |
||
28 | * @var string |
||
29 | */ |
||
30 | const REST_ROUTE_NAMESPACE = 'pronamic-pay/adyen/v1'; |
||
31 | |||
32 | /** |
||
33 | * Construct Adyen integration. |
||
34 | * |
||
35 | * @param array<string, array<string>> $args Arguments. |
||
36 | */ |
||
37 | 5 | public function __construct( $args = array() ) { |
|
38 | 5 | $args = wp_parse_args( |
|
39 | 5 | $args, |
|
40 | array( |
||
41 | 5 | 'id' => 'adyen', |
|
42 | 5 | 'name' => 'Adyen', |
|
43 | 5 | 'provider' => 'adyen', |
|
44 | 5 | 'url' => \__( 'https://www.adyen.com/', 'pronamic_ideal' ), |
|
45 | 5 | 'product_url' => \__( 'https://www.adyen.com/pricing', 'pronamic_ideal' ), |
|
46 | 'dashboard_url' => array( |
||
47 | 5 | \__( 'test', 'pronamic_ideal' ) => 'https://ca-test.adyen.com/ca/ca/login.shtml', |
|
48 | 5 | \__( 'live', 'pronamic_ideal' ) => 'https://ca-live.adyen.com/ca/ca/login.shtml', |
|
49 | ), |
||
50 | 5 | 'manual_url' => \__( 'https://www.pronamic.eu/manuals/using-adyen-pronamic-pay/', 'pronamic_ideal' ), |
|
51 | 'supports' => array( |
||
52 | 'webhook', |
||
53 | 'webhook_log', |
||
54 | ), |
||
55 | ) |
||
56 | ); |
||
57 | |||
58 | 5 | parent::__construct( $args ); |
|
59 | |||
60 | // Dependencies. |
||
61 | 5 | $dependencies = $this->get_dependencies(); |
|
62 | |||
63 | 5 | $dependencies->add( new PhpExtensionDependency( 'intl' ) ); |
|
64 | 5 | } |
|
65 | |||
66 | /** |
||
67 | * Setup gateway integration. |
||
68 | * |
||
69 | * @return void |
||
70 | */ |
||
71 | 1 | public function setup() { |
|
72 | // Check if dependencies are met and integration is active. |
||
73 | 1 | if ( ! $this->is_active() ) { |
|
74 | return; |
||
75 | } |
||
76 | |||
77 | // Notifications controller. |
||
78 | 1 | $notifications_controller = new NotificationsController(); |
|
79 | |||
80 | 1 | $notifications_controller->setup(); |
|
81 | |||
82 | // Payments controller. |
||
83 | 1 | $payments_controller = new PaymentsController(); |
|
84 | |||
85 | 1 | $payments_controller->setup(); |
|
86 | |||
87 | // Payments result controller. |
||
88 | 1 | $payments_result_controller = new PaymentsResultController(); |
|
89 | |||
90 | 1 | $payments_result_controller->setup(); |
|
91 | |||
92 | // Site Health controller. |
||
93 | 1 | $site_healht_controller = new SiteHealthController(); |
|
94 | |||
95 | 1 | $site_healht_controller->setup(); |
|
96 | |||
97 | // Settings. |
||
98 | 1 | add_action( 'init', array( $this, 'init' ) ); |
|
99 | 1 | add_action( 'admin_init', array( $this, 'admin_init' ), 15 ); |
|
100 | |||
101 | // Actions. |
||
102 | 1 | add_action( 'current_screen', array( $this, 'maybe_download_certificate_or_key' ) ); |
|
103 | |||
104 | 1 | \add_filter( 'pronamic_gateway_configuration_display_value_' . $this->get_id(), array( $this, 'gateway_configuration_display_value' ), 10, 2 ); |
|
105 | 1 | } |
|
106 | |||
107 | /** |
||
108 | * Initialize. |
||
109 | * |
||
110 | * @return void |
||
111 | */ |
||
112 | 1 | public function init() { |
|
113 | /* |
||
114 | * Authentication - User Name |
||
115 | */ |
||
116 | 1 | register_setting( |
|
117 | 1 | 'pronamic_pay', |
|
118 | 1 | 'pronamic_pay_adyen_notification_authentication_username', |
|
119 | array( |
||
120 | 1 | 'type' => 'string', |
|
121 | 'sanitize_callback' => 'sanitize_text_field', |
||
122 | ) |
||
123 | ); |
||
124 | |||
125 | /* |
||
126 | * Authentication - Password |
||
127 | */ |
||
128 | 1 | register_setting( |
|
129 | 1 | 'pronamic_pay', |
|
130 | 1 | 'pronamic_pay_adyen_notification_authentication_password', |
|
131 | array( |
||
132 | 1 | 'type' => 'string', |
|
133 | 'sanitize_callback' => 'sanitize_text_field', |
||
134 | ) |
||
135 | ); |
||
136 | 1 | } |
|
137 | |||
138 | /** |
||
139 | * Admin initialize. |
||
140 | * |
||
141 | * @return void |
||
142 | */ |
||
143 | 1 | public function admin_init() { |
|
144 | 1 | add_settings_section( |
|
145 | 1 | 'pronamic_pay_adyen_notification_authentication', |
|
146 | /* translators: Translate 'notification' the same as in the Adyen dashboard. */ |
||
147 | 1 | _x( 'Adyen Notification Authentication', 'Adyen', 'pronamic_ideal' ), |
|
148 | 1 | array( $this, 'settings_section_notification_authentication' ), |
|
149 | 1 | 'pronamic_pay' |
|
150 | ); |
||
151 | |||
152 | 1 | add_settings_field( |
|
153 | 1 | 'pronamic_pay_adyen_notification_authentication_username', |
|
154 | 1 | __( 'User Name', 'pronamic_ideal' ), |
|
155 | 1 | array( __CLASS__, 'input_element' ), |
|
156 | 1 | 'pronamic_pay', |
|
157 | 1 | 'pronamic_pay_adyen_notification_authentication', |
|
158 | array( |
||
159 | 1 | 'label_for' => 'pronamic_pay_adyen_notification_authentication_username', |
|
160 | ) |
||
161 | ); |
||
162 | |||
163 | 1 | add_settings_field( |
|
164 | 1 | 'pronamic_pay_adyen_notification_authentication_password', |
|
165 | 1 | __( 'Password', 'pronamic_ideal' ), |
|
166 | 1 | array( __CLASS__, 'input_element' ), |
|
167 | 1 | 'pronamic_pay', |
|
168 | 1 | 'pronamic_pay_adyen_notification_authentication', |
|
169 | array( |
||
170 | 1 | 'label_for' => 'pronamic_pay_adyen_notification_authentication_password', |
|
171 | ) |
||
172 | ); |
||
173 | 1 | } |
|
174 | |||
175 | /** |
||
176 | * Settings section notification authentication. |
||
177 | * |
||
178 | * @return void |
||
179 | */ |
||
180 | 1 | public function settings_section_notification_authentication() { |
|
181 | 1 | printf( |
|
182 | 1 | '<p>%s</p>', |
|
183 | 1 | esc_html__( |
|
184 | 1 | 'Set the user name and password below and in the webhook authentication settings in the Adyen dashboard for increased security (recommended).', |
|
185 | 1 | 'pronamic_ideal' |
|
186 | ) |
||
187 | ); |
||
188 | 1 | } |
|
189 | |||
190 | /** |
||
191 | * Input text. |
||
192 | * |
||
193 | * @param array<string,string> $args Arguments. |
||
194 | * @return void |
||
195 | */ |
||
196 | 1 | public static function input_element( $args ) { |
|
197 | 1 | $name = $args['label_for']; |
|
198 | |||
199 | 1 | $value = get_option( $name ); |
|
200 | 1 | $value = strval( $value ); |
|
201 | |||
202 | 1 | printf( |
|
203 | 1 | '<input name="%s" id="%s" value="%s" type="text" class="regular-text" />', |
|
204 | 1 | esc_attr( $name ), |
|
205 | 1 | esc_attr( $name ), |
|
206 | 1 | esc_attr( $value ) |
|
207 | ); |
||
208 | 1 | } |
|
209 | |||
210 | /** |
||
211 | * Get settings fields. |
||
212 | * |
||
213 | * @return array<int, array<string, callable|int|string|bool|array<int|string,int|string>>> |
||
214 | */ |
||
215 | 1 | public function get_settings_fields() { |
|
216 | 1 | $fields = array(); |
|
217 | |||
218 | // Merchant Account. |
||
219 | 1 | $fields[] = array( |
|
220 | 1 | 'section' => 'general', |
|
221 | 1 | 'filter' => FILTER_SANITIZE_STRING, |
|
222 | 1 | 'meta_key' => '_pronamic_gateway_adyen_merchant_account', |
|
223 | 1 | 'title' => _x( 'Merchant Account', 'adyen', 'pronamic_ideal' ), |
|
224 | 1 | 'type' => 'text', |
|
225 | 'classes' => array( 'regular-text', 'code' ), |
||
226 | 1 | 'tooltip' => __( 'The merchant account identifier, with which you want to process the transaction.', 'pronamic_ideal' ), |
|
227 | ); |
||
228 | |||
229 | // API Key. |
||
230 | 1 | $fields[] = array( |
|
231 | 1 | 'section' => 'general', |
|
232 | 1 | 'filter' => FILTER_SANITIZE_STRING, |
|
233 | 1 | 'meta_key' => '_pronamic_gateway_adyen_api_key', |
|
234 | 1 | 'title' => _x( 'API Key', 'adyen', 'pronamic_ideal' ), |
|
235 | 1 | 'type' => 'textarea', |
|
236 | 'classes' => array( 'code' ), |
||
237 | 1 | 'tooltip' => __( 'API key as mentioned in the payment provider dashboard.', 'pronamic_ideal' ), |
|
238 | 1 | 'description' => sprintf( |
|
239 | 1 | '<a href="%s" target="_blank">%s</a>', |
|
240 | 1 | esc_url( 'https://docs.adyen.com/developers/user-management/how-to-get-the-api-key' ), |
|
241 | 1 | esc_html__( 'Adyen documentation: "How to get the API key".', 'pronamic_ideal' ) |
|
242 | ), |
||
243 | ); |
||
244 | |||
245 | // Live API URL prefix. |
||
246 | 1 | $fields[] = array( |
|
247 | 1 | 'section' => 'general', |
|
248 | 1 | 'filter' => FILTER_SANITIZE_STRING, |
|
249 | 1 | 'meta_key' => '_pronamic_gateway_adyen_api_live_url_prefix', |
|
250 | 1 | 'title' => _x( 'API Live URL Prefix', 'adyen', 'pronamic_ideal' ), |
|
251 | 1 | 'type' => 'text', |
|
252 | 'classes' => array( 'regular-text', 'code' ), |
||
253 | 1 | 'tooltip' => __( 'The unique prefix for the live API URL, as mentioned at <strong>Account » API URLs</strong> in the Adyen dashboard.', 'pronamic_ideal' ), |
|
254 | 1 | 'description' => sprintf( |
|
255 | 1 | '<a href="%s" target="_blank">%s</a>', |
|
256 | 1 | esc_url( 'https://docs.adyen.com/developers/development-resources/live-endpoints#liveurlprefix' ), |
|
257 | 1 | esc_html__( 'Adyen documentation: "Live URL prefix".', 'pronamic_ideal' ) |
|
258 | ), |
||
259 | ); |
||
260 | |||
261 | // Origin Key. |
||
262 | 1 | $fields[] = array( |
|
263 | 1 | 'section' => 'general', |
|
264 | 1 | 'filter' => FILTER_SANITIZE_STRING, |
|
265 | 1 | 'meta_key' => '_pronamic_gateway_adyen_origin_key', |
|
266 | 1 | 'title' => _x( 'Origin Key', 'adyen', 'pronamic_ideal' ), |
|
267 | 1 | 'type' => 'text', |
|
268 | 'classes' => array( |
||
269 | 'regular-text', |
||
270 | 'code', |
||
271 | 'pronamic-pay-form-control-lg', |
||
272 | ), |
||
273 | 1 | 'tooltip' => __( 'An origin key is a client-side key that is used to validate Adyen\'s JavaScript component library. It is required for the Drop-in and Component integrations.', 'pronamic_ideal' ), |
|
274 | 1 | 'description' => sprintf( |
|
275 | 1 | '<a href="%s" target="_blank">%s</a>', |
|
276 | 1 | esc_url( 'https://docs.adyen.com/user-management/how-to-get-an-origin-key' ), |
|
277 | 1 | esc_html__( 'Adyen documentation: "How to get an origin key".', 'pronamic_ideal' ) |
|
278 | ), |
||
279 | ); |
||
280 | |||
281 | // Merchant Order Reference. |
||
282 | 1 | $fields[] = array( |
|
283 | 1 | 'section' => 'advanced', |
|
284 | 'filter' => array( |
||
285 | 'filter' => \FILTER_SANITIZE_STRING, |
||
286 | 'flags' => \FILTER_FLAG_NO_ENCODE_QUOTES, |
||
287 | ), |
||
288 | 1 | 'meta_key' => '_pronamic_gateway_adyen_merchant_order_reference', |
|
289 | 1 | 'title' => __( 'Merchant Order Reference', 'pronamic_ideal' ), |
|
290 | 1 | 'type' => 'text', |
|
291 | 'classes' => array( 'regular-text', 'code' ), |
||
292 | 1 | 'tooltip' => \sprintf( |
|
293 | /* translators: %s: <code>parameterName</code> */ |
||
294 | 1 | \__( 'The Adyen %s parameter.', 'pronamic_ideal' ), |
|
295 | 1 | \sprintf( '<code>%s</code>', 'merchantOrderReference' ) |
|
296 | ), |
||
297 | 1 | 'description' => \sprintf( |
|
298 | 1 | '%s %s<br />%s', |
|
299 | 1 | \__( 'Available tags:', 'pronamic_ideal' ), |
|
300 | 1 | \sprintf( |
|
301 | 1 | '<code>%s</code> <code>%s</code>', |
|
302 | 1 | '{order_id}', |
|
303 | 1 | '{payment_id}' |
|
304 | ), |
||
305 | 1 | \sprintf( |
|
306 | /* translators: %s: default code */ |
||
307 | 1 | \__( 'Default: <code>%s</code>', 'pronamic_ideal' ), |
|
308 | 1 | '{payment_id}' |
|
309 | ) |
||
310 | ), |
||
311 | ); |
||
312 | |||
313 | // Apple Pay - Merchant identifier. |
||
314 | 1 | $fields[] = array( |
|
315 | 1 | 'section' => 'advanced', |
|
316 | 'filter' => \FILTER_SANITIZE_STRING, |
||
317 | 1 | 'meta_key' => '_pronamic_gateway_adyen_apple_pay_merchant_id', |
|
318 | 1 | 'title' => _x( 'Apple Pay Merchant ID', 'adyen', 'pronamic_ideal' ), |
|
319 | 1 | 'type' => 'text', |
|
320 | 'classes' => array( 'regular-text', 'code' ), |
||
321 | 1 | 'tooltip' => __( 'Your Apple Pay Merchant ID. Required for accepting live payments.', 'pronamic_ideal' ), |
|
322 | 1 | 'description' => sprintf( |
|
323 | 1 | '<a href="%s" target="_blank">%s</a><br /><a href="%s" target="_blank">%s</a>', |
|
324 | 1 | esc_url( 'https://docs.adyen.com/payment-methods/apple-pay/web-drop-in#before-you-begin' ), |
|
325 | 1 | esc_html__( 'Adyen documentation: "Apple Pay Drop-in - Before you begin".', 'pronamic_ideal' ), |
|
326 | 1 | esc_url( 'https://developer.apple.com/documentation/apple_pay_on_the_web/configuring_your_environment' ), |
|
327 | 1 | esc_html__( 'Apple documentation: "Configuring your environment".', 'pronamic_ideal' ) |
|
328 | ), |
||
329 | ); |
||
330 | |||
331 | // Apple Pay - Merchant Identity PKCS#12. |
||
332 | 1 | $fields[] = array( |
|
333 | 1 | 'section' => 'advanced', |
|
334 | 'filter' => \FILTER_SANITIZE_STRING, |
||
335 | 1 | 'meta_key' => '_pronamic_gateway_adyen_apple_pay_merchant_id_certificate', |
|
336 | 1 | 'title' => __( 'Apple Pay Merchant Identity Certificate', 'pronamic_ideal' ), |
|
337 | 1 | 'type' => 'textarea', |
|
338 | 1 | 'callback' => array( $this, 'field_certificate' ), |
|
339 | 'classes' => array( 'code' ), |
||
340 | 1 | 'tooltip' => __( 'The Apple Pay Merchant Identity certificate required for secure communication with Apple.', 'pronamic_ideal' ), |
|
341 | 1 | 'description' => sprintf( |
|
342 | 1 | '<a href="%s" target="_blank">%s</a>', |
|
343 | 1 | esc_url( 'https://docs.adyen.com/payment-methods/apple-pay/enable-apple-pay#create-merchant-identity-certificate' ), |
|
344 | 1 | esc_html__( 'Adyen documentation: "Enable Apple Pay - Create a merchant identity certificate".', 'pronamic_ideal' ) |
|
345 | ), |
||
346 | ); |
||
347 | |||
348 | // Apple Pay - Merchant Identity private key. |
||
349 | 1 | $fields[] = array( |
|
350 | 1 | 'section' => 'advanced', |
|
351 | 'filter' => \FILTER_SANITIZE_STRING, |
||
352 | 1 | 'meta_key' => '_pronamic_gateway_adyen_apple_pay_merchant_id_private_key', |
|
353 | 1 | 'title' => __( 'Apple Pay Merchant Identity Private Key', 'pronamic_ideal' ), |
|
354 | 1 | 'type' => 'textarea', |
|
355 | 1 | 'callback' => array( $this, 'field_private_key' ), |
|
356 | 'classes' => array( 'code' ), |
||
357 | 1 | 'tooltip' => __( 'The private key of the Apple Pay Merchant Identity certificate for secure communication with Apple.', 'pronamic_ideal' ), |
|
358 | ); |
||
359 | |||
360 | // Apple Pay - Merchant Identity certificate private key password. |
||
361 | 1 | $fields[] = array( |
|
362 | 1 | 'section' => 'advanced', |
|
363 | 'filter' => \FILTER_SANITIZE_STRING, |
||
364 | 1 | 'meta_key' => '_pronamic_gateway_adyen_apple_pay_merchant_id_private_key_password', |
|
365 | 1 | 'title' => _x( 'Apple Pay Merchant Identity Private Key Password', 'adyen', 'pronamic_ideal' ), |
|
366 | 1 | 'type' => 'text', |
|
367 | 'classes' => array( 'regular-text', 'code' ), |
||
368 | 1 | 'tooltip' => __( 'Your Apple Pay Merchant Identity Certificate private key password.', 'pronamic_ideal' ), |
|
369 | ); |
||
370 | |||
371 | // Google Pay - Merchant identifier. |
||
372 | 1 | $fields[] = array( |
|
373 | 1 | 'section' => 'advanced', |
|
374 | 'filter' => \FILTER_SANITIZE_STRING, |
||
375 | 1 | 'meta_key' => '_pronamic_gateway_adyen_google_pay_merchant_identifier', |
|
376 | 1 | 'title' => _x( 'Google Pay Merchant ID', 'adyen', 'pronamic_ideal' ), |
|
377 | 1 | 'type' => 'text', |
|
378 | 'classes' => array( 'regular-text', 'code' ), |
||
379 | 1 | 'tooltip' => __( 'Your Google Merchant ID. Required for accepting live payments.', 'pronamic_ideal' ), |
|
380 | 1 | 'description' => sprintf( |
|
381 | 1 | '<a href="%s" target="_blank">%s</a><br /><a href="%s" target="_blank">%s</a>', |
|
382 | 1 | esc_url( 'https://docs.adyen.com/payment-methods/google-pay/web-drop-in#test-and-go-live' ), |
|
383 | 1 | esc_html__( 'Adyen documentation: "Google Pay Drop-in - Test and go live".', 'pronamic_ideal' ), |
|
384 | 1 | esc_url( 'https://developers.google.com/pay/api/web/guides/test-and-deploy/deploy-production-environment' ), |
|
385 | 1 | esc_html__( 'Google documentation: "Deploy production environment".', 'pronamic_ideal' ) |
|
386 | ), |
||
387 | ); |
||
388 | |||
389 | // Webhook URL. |
||
390 | 1 | $fields[] = array( |
|
391 | 1 | 'section' => 'feedback', |
|
392 | 1 | 'title' => __( 'Webhook URL', 'pronamic_ideal' ), |
|
393 | 1 | 'type' => 'text', |
|
394 | 'classes' => array( 'large-text', 'code' ), |
||
395 | 1 | 'value' => rest_url( self::REST_ROUTE_NAMESPACE . '/notifications' ), |
|
396 | 'readonly' => true, |
||
397 | 1 | 'tooltip' => sprintf( |
|
398 | /* translators: %s: payment provider name */ |
||
399 | 1 | __( 'Copy the Webhook URL to the %s dashboard to receive automatic transaction status updates.', 'pronamic_ideal' ), |
|
400 | 1 | __( 'Adyen', 'pronamic_ideal' ) |
|
401 | ), |
||
402 | ); |
||
403 | |||
404 | /** |
||
405 | * SSL Version. |
||
406 | * |
||
407 | * @link https://docs.adyen.com/developers/development-resources/notifications/set-up-notifications#step3configurenotificationsinthecustomerarea |
||
408 | * @link https://www.howsmyssl.com/a/check |
||
409 | */ |
||
410 | 1 | $fields[] = array( |
|
411 | 1 | 'section' => 'feedback', |
|
412 | 1 | 'title' => __( 'SSL Version', 'pronamic_ideal' ), |
|
413 | 1 | 'type' => 'description', |
|
414 | 1 | 'html' => __( 'Choose the SSL Version of your server on the Adyen Customer Area.', 'pronamic_ideal' ), |
|
415 | ); |
||
416 | |||
417 | /** |
||
418 | * Method. |
||
419 | * |
||
420 | * @link https://docs.adyen.com/developers/development-resources/notifications/set-up-notifications#step3configurenotificationsinthecustomerarea |
||
421 | * @link https://www.howsmyssl.com/a/check |
||
422 | */ |
||
423 | 1 | $fields[] = array( |
|
424 | 1 | 'section' => 'feedback', |
|
425 | 1 | 'title' => _x( 'Method', 'adyen notification', 'pronamic_ideal' ), |
|
426 | 1 | 'type' => 'description', |
|
427 | 1 | 'html' => __( 'JSON', 'pronamic_ideal' ), |
|
428 | ); |
||
429 | |||
430 | // Webhook authentication settings. |
||
431 | 1 | $fields[] = array( |
|
432 | 1 | 'section' => 'feedback', |
|
433 | 1 | 'title' => __( 'Authentication', 'pronamic_ideal' ), |
|
434 | 1 | 'type' => 'description', |
|
435 | 1 | 'html' => \sprintf( |
|
436 | /* translators: %s: Pronamic Pay settings page URL. */ |
||
437 | 1 | __( 'Go to the <a href="%s">Pronamic Pay settings page</a> for webhook authentication settings.', 'pronamic_ideal' ), |
|
438 | 1 | \esc_url( |
|
439 | 1 | \add_query_arg( |
|
440 | array( |
||
441 | 1 | 'page' => 'pronamic_pay_settings', |
|
442 | ), |
||
443 | 1 | \admin_url( 'admin.php' ) |
|
444 | ) |
||
445 | ) |
||
446 | ), |
||
447 | ); |
||
448 | |||
449 | // Return fields. |
||
450 | 1 | return $fields; |
|
451 | } |
||
452 | |||
453 | /** |
||
454 | * Field certificate. |
||
455 | * |
||
456 | * @param array<string> $field Field. |
||
457 | * @return void |
||
458 | */ |
||
459 | public function field_certificate( $field ) { |
||
460 | if ( ! \array_key_exists( 'meta_key', $field ) ) { |
||
461 | return; |
||
462 | } |
||
463 | |||
464 | $post_id = \get_the_ID(); |
||
465 | |||
466 | if ( false === $post_id ) { |
||
467 | return; |
||
468 | } |
||
469 | |||
470 | $certificate = \get_post_meta( $post_id, $field['meta_key'], true ); |
||
471 | |||
472 | if ( ! empty( $certificate ) ) { |
||
473 | $fingerprint = Security::get_sha_fingerprint( $certificate ); |
||
474 | |||
475 | echo '<dl>'; |
||
476 | |||
477 | if ( null !== $fingerprint ) { |
||
478 | $fingerprint = \str_split( $fingerprint, 2 ); |
||
479 | $fingerprint = \implode( ':', $fingerprint ); |
||
480 | |||
481 | echo '<dt>', \esc_html__( 'SHA Fingerprint', 'pronamic_ideal' ), '</dt>'; |
||
482 | echo '<dd>', \esc_html( $fingerprint ), '</dd>'; |
||
483 | } |
||
484 | |||
485 | $info = \openssl_x509_parse( $certificate ); |
||
486 | |||
487 | if ( $info ) { |
||
0 ignored issues
–
show
|
|||
488 | $date_format = __( 'M j, Y @ G:i', 'pronamic_ideal' ); |
||
489 | |||
490 | if ( isset( $info['validFrom_time_t'] ) ) { |
||
491 | echo '<dt>', \esc_html__( 'Valid From', 'pronamic_ideal' ), '</dt>'; |
||
492 | echo '<dd>', \esc_html( \date_i18n( $date_format, $info['validFrom_time_t'] ) ), '</dd>'; |
||
493 | } |
||
494 | |||
495 | if ( isset( $info['validTo_time_t'] ) ) { |
||
496 | echo '<dt>', \esc_html__( 'Valid To', 'pronamic_ideal' ), '</dt>'; |
||
497 | echo '<dd>', \esc_html( \date_i18n( $date_format, $info['validTo_time_t'] ) ), '</dd>'; |
||
498 | } |
||
499 | } |
||
500 | |||
501 | echo '</dl>'; |
||
502 | } elseif ( false !== \strpos( $field['meta_key'], 'apple_pay' ) ) { |
||
503 | \printf( |
||
504 | '<p class="pronamic-pay-description description">%s</p><p> </p>', |
||
505 | \esc_html__( 'Upload an Apple Pay Merchant Identity certificate, which can be exported from Keychain Access on Mac as a PKCS#12 (*.p12) file.', 'pronamic_ideal' ) |
||
506 | ); |
||
507 | } |
||
508 | |||
509 | ?> |
||
510 | <p> |
||
511 | <?php |
||
512 | |||
513 | if ( ! empty( $certificate ) ) { |
||
514 | \submit_button( |
||
515 | __( 'Download', 'pronamic_ideal' ), |
||
516 | 'secondary', |
||
517 | 'download' . $field['meta_key'], |
||
518 | false |
||
519 | ); |
||
520 | |||
521 | echo ' '; |
||
522 | } |
||
523 | |||
524 | \printf( |
||
525 | '<label class="pronamic-pay-form-control-file-button button">%s <input type="file" name="%s" /></label>', |
||
526 | \esc_html__( 'Upload', 'pronamic_ideal' ), |
||
527 | \esc_attr( $field['meta_key'] . '_file' ) |
||
528 | ); |
||
529 | |||
530 | ?> |
||
531 | </p> |
||
532 | <?php |
||
533 | } |
||
534 | |||
535 | /** |
||
536 | * Field private key. |
||
537 | * |
||
538 | * @param array<string> $field Field. |
||
539 | * @return void |
||
540 | */ |
||
541 | public function field_private_key( $field ) { |
||
542 | if ( ! \array_key_exists( 'meta_key', $field ) ) { |
||
543 | return; |
||
544 | } |
||
545 | |||
546 | $post_id = \get_the_ID(); |
||
547 | |||
548 | if ( false === $post_id ) { |
||
549 | return; |
||
550 | } |
||
551 | |||
552 | $private_key = \get_post_meta( $post_id, $field['meta_key'], true ); |
||
553 | |||
554 | ?> |
||
555 | <p> |
||
556 | <?php |
||
557 | |||
558 | if ( ! empty( $private_key ) ) { |
||
559 | \submit_button( |
||
560 | __( 'Download', 'pronamic_ideal' ), |
||
561 | 'secondary', |
||
562 | 'download' . $field['meta_key'], |
||
563 | false |
||
564 | ); |
||
565 | |||
566 | echo ' '; |
||
567 | } |
||
568 | |||
569 | if ( empty( $private_key ) && false !== \strpos( $field['meta_key'], 'apple_pay' ) ) { |
||
570 | \printf( |
||
571 | '<p class="pronamic-pay-description description">%s</p><p> </p>', |
||
572 | \esc_html__( 'Leave empty to auto fill when uploading an Apple Pay Merchant Identity PKCS#12 certificate file.', 'pronamic_ideal' ) |
||
573 | ); |
||
574 | } |
||
575 | |||
576 | \printf( |
||
577 | '<label class="pronamic-pay-form-control-file-button button">%s <input type="file" name="%s" /></label>', |
||
578 | \esc_html__( 'Upload', 'pronamic_ideal' ), |
||
579 | \esc_attr( $field['meta_key'] . '_file' ) |
||
580 | ); |
||
581 | |||
582 | ?> |
||
583 | </p> |
||
584 | <?php |
||
585 | } |
||
586 | |||
587 | /** |
||
588 | * Download certificate or key in Privacy Enhanced Mail (PEM) format. |
||
589 | * |
||
590 | * @return void |
||
591 | */ |
||
592 | public function maybe_download_certificate_or_key() { |
||
593 | // Certificate fields and download filename. |
||
594 | $fields = array( |
||
595 | '_pronamic_gateway_adyen_apple_pay_merchant_id_certificate' => 'apple-pay-merchant-identity-certificate-%s.pem', |
||
596 | '_pronamic_gateway_adyen_apple_pay_merchant_id_private_key' => 'apple-pay-merchant-identity-private-key-%s.pem', |
||
597 | ); |
||
598 | |||
599 | // Check download actions. |
||
600 | $is_download_action = false; |
||
601 | |||
602 | foreach ( $fields as $meta_key => $filename ) { |
||
603 | if ( \filter_has_var( \INPUT_POST, 'download' . $meta_key ) ) { |
||
604 | $is_download_action = true; |
||
605 | |||
606 | break; |
||
607 | } |
||
608 | } |
||
609 | |||
610 | // No valid download action found. |
||
611 | if ( false === $is_download_action ) { |
||
612 | return; |
||
613 | } |
||
614 | |||
615 | $post_id = filter_input( \INPUT_POST, 'post_ID', \FILTER_SANITIZE_STRING ); |
||
616 | |||
617 | $filename = sprintf( $filename, $post_id ); |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
618 | |||
619 | header( 'Content-Description: File Transfer' ); |
||
620 | header( 'Content-Disposition: attachment; filename=' . $filename ); |
||
621 | header( 'Content-Type: application/x-pem-file; charset=' . get_option( 'blog_charset' ), true ); |
||
622 | |||
623 | // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
||
624 | echo get_post_meta( $post_id, $meta_key, true ); |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
625 | |||
626 | exit; |
||
0 ignored issues
–
show
|
|||
627 | } |
||
628 | |||
629 | /** |
||
630 | * Gateway configuration display value. |
||
631 | * |
||
632 | * @param string $display_value Display value. |
||
633 | * @param int $post_id Gateway configuration post ID. |
||
634 | * @return string |
||
635 | */ |
||
636 | public function gateway_configuration_display_value( $display_value, $post_id ) { |
||
637 | $config = $this->get_config( $post_id ); |
||
638 | |||
639 | return $config->get_merchant_account(); |
||
640 | } |
||
641 | |||
642 | /** |
||
643 | * Save post. |
||
644 | * |
||
645 | * @param int $post_id Post ID. |
||
646 | * @return void |
||
647 | */ |
||
648 | public function save_post( $post_id ) { |
||
649 | // Files. |
||
650 | $files = array( |
||
651 | '_pronamic_gateway_adyen_apple_pay_merchant_id_certificate_file' => '_pronamic_gateway_adyen_apple_pay_merchant_id_certificate', |
||
652 | '_pronamic_gateway_adyen_apple_pay_merchant_id_private_key_file' => '_pronamic_gateway_adyen_apple_pay_merchant_id_private_key', |
||
653 | ); |
||
654 | |||
655 | foreach ( $files as $name => $meta_key ) { |
||
656 | // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated |
||
657 | if ( isset( $_FILES[ $name ] ) && \UPLOAD_ERR_OK === $_FILES[ $name ]['error'] ) { |
||
658 | // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized |
||
659 | $value = file_get_contents( $_FILES[ $name ]['tmp_name'], true ); |
||
660 | |||
661 | update_post_meta( $post_id, $meta_key, $value ); |
||
662 | } |
||
663 | } |
||
664 | |||
665 | // Update Apple Pay Merchant Identity certificate and private key from uploaded PKCS#12 file. |
||
666 | $apple_pay_merchant_id_pkcs12 = get_post_meta( $post_id, '_pronamic_gateway_adyen_apple_pay_merchant_id_certificate', true ); |
||
667 | |||
668 | if ( ! empty( $apple_pay_merchant_id_pkcs12 ) ) { |
||
669 | // Try to read file without using password. |
||
670 | $pkcs12_read = \openssl_pkcs12_read( $apple_pay_merchant_id_pkcs12, $certs, '' ); |
||
671 | |||
672 | $password = \get_post_meta( $post_id, '_pronamic_gateway_adyen_apple_pay_merchant_id_private_key_password', true ); |
||
673 | |||
674 | // Try to read file with private key password. |
||
675 | if ( false === $pkcs12_read ) { |
||
676 | $pkcs12_read = \openssl_pkcs12_read( $apple_pay_merchant_id_pkcs12, $certs, $password ); |
||
677 | } |
||
678 | |||
679 | if ( true === $pkcs12_read ) { |
||
680 | if ( isset( $certs['cert'] ) ) { |
||
681 | \update_post_meta( $post_id, '_pronamic_gateway_adyen_apple_pay_merchant_id_certificate', $certs['cert'] ); |
||
682 | } |
||
683 | |||
684 | if ( isset( $certs['pkey'] ) ) { |
||
685 | $private_key = $certs['pkey']; |
||
686 | |||
687 | $cipher = null; |
||
688 | |||
689 | // Try to export the private key encrypted. |
||
690 | if ( defined( 'OPENSSL_CIPHER_AES_128_CBC' ) ) { |
||
691 | $cipher = \OPENSSL_CIPHER_AES_128_CBC; |
||
692 | } elseif ( defined( 'OPENSSL_CIPHER_3DES' ) ) { |
||
693 | $cipher = \OPENSSL_CIPHER_3DES; |
||
694 | } |
||
695 | |||
696 | if ( null !== $cipher && '' !== $password ) { |
||
697 | $args = array( |
||
698 | 'digest_alg' => 'SHA256', |
||
699 | 'private_key_bits' => 2048, |
||
700 | 'private_key_type' => \OPENSSL_KEYTYPE_RSA, |
||
701 | 'encrypt_key' => true, |
||
702 | 'encrypt_key_cipher' => $cipher, |
||
703 | 'subjectKeyIdentifier' => 'hash', |
||
704 | 'authorityKeyIdentifier' => 'keyid:always,issuer:always', |
||
705 | 'basicConstraints' => 'CA:true', |
||
706 | ); |
||
707 | |||
708 | \openssl_pkey_export( $certs['pkey'], $private_key, $password, $args ); |
||
709 | } |
||
710 | |||
711 | \update_post_meta( $post_id, '_pronamic_gateway_adyen_apple_pay_merchant_id_private_key', $private_key ); |
||
712 | } |
||
713 | } |
||
714 | } |
||
715 | } |
||
716 | |||
717 | /** |
||
718 | * Get configuration by post ID. |
||
719 | * |
||
720 | * @param int $post_id Post ID. |
||
721 | * @return Config |
||
722 | */ |
||
723 | 1 | public function get_config( $post_id ) { |
|
724 | 1 | $config = new Config(); |
|
725 | |||
726 | 1 | $config->mode = $this->get_meta( $post_id, 'mode' ); |
|
727 | 1 | $config->api_key = $this->get_meta( $post_id, 'adyen_api_key' ); |
|
728 | 1 | $config->api_live_url_prefix = $this->get_meta( $post_id, 'adyen_api_live_url_prefix' ); |
|
729 | 1 | $config->merchant_account = $this->get_meta( $post_id, 'adyen_merchant_account' ); |
|
730 | 1 | $config->origin_key = $this->get_meta( $post_id, 'adyen_origin_key' ); |
|
731 | 1 | $config->merchant_order_reference = $this->get_meta( $post_id, 'adyen_merchant_order_reference' ); |
|
732 | 1 | $config->apple_pay_merchant_id = $this->get_meta( $post_id, 'adyen_apple_pay_merchant_id' ); |
|
733 | 1 | $config->apple_pay_merchant_id_certificate = $this->get_meta( $post_id, 'adyen_apple_pay_merchant_id_certificate' ); |
|
734 | 1 | $config->apple_pay_merchant_id_private_key = $this->get_meta( $post_id, 'adyen_apple_pay_merchant_id_private_key' ); |
|
735 | 1 | $config->apple_pay_merchant_id_private_key_password = $this->get_meta( $post_id, 'adyen_apple_pay_merchant_id_private_key_password' ); |
|
736 | 1 | $config->google_pay_merchant_identifier = $this->get_meta( $post_id, 'adyen_google_pay_merchant_identifier' ); |
|
737 | |||
738 | 1 | return $config; |
|
739 | } |
||
740 | |||
741 | /** |
||
742 | * Get gateway. |
||
743 | * |
||
744 | * @param int $post_id Post ID. |
||
745 | * @return AbstractGateway |
||
746 | */ |
||
747 | 1 | public function get_gateway( $post_id ) { |
|
748 | 1 | $config = $this->get_config( $post_id ); |
|
749 | |||
750 | 1 | if ( empty( $config->origin_key ) ) { |
|
751 | 1 | return new WebSdkGateway( $config ); |
|
752 | } |
||
753 | |||
754 | return new DropInGateway( $config ); |
||
755 | } |
||
756 | } |
||
757 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.