Failed Conditions
Push — develop ( d16b7e...a535bd )
by Reüel
07:00 queued 10s
created

src/Integration.php (12 issues)

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
9
 */
10
11
namespace Pronamic\WordPress\Pay\Gateways\IDealAdvancedV3;
12
13
use Pronamic\WordPress\Pay\Gateways\IDeal\AbstractIntegration;
14
15
/**
16
 * Title: iDEAL Advanced v3 integration
17
 * Description:
18
 * Copyright: 2005-2020 Pronamic
19
 * Company: Pronamic
20
 *
21
 * @author  Remco Tolsma
22
 * @version 2.1.1
23
 * @since   2.0.0
24
 */
25
class Integration extends AbstractIntegration {
26
	/**
27
	 * Construct iDEAL Advanced v3 integration.
28
	 *
29
	 * @param array<string, mixed> $args Arguments.
30
	 * @return void
31
	 */
32
	public function __construct( $args = array() ) {
33
		$args = wp_parse_args(
34
			$args,
35
			array(
36
				'id'                => 'ideal-advanced-v3',
37
				'name'              => 'iDEAL Advanced v3',
38
				'url'               => \__( 'https://www.ideal.nl/en/', 'pronamic_ideal' ),
39
				'product_url'       => \__( 'https://www.ideal.nl/en/', 'pronamic_ideal' ),
40
				'manual_url'        => null,
41
				'dashboard_url'     => null,
42
				'provider'          => null,
43
				'acquirer_url'      => null,
44
				'acquirer_test_url' => null,
45
				'supports'          => array(
46
					'payment_status_request',
47
				),
48
			)
49
		);
50
51
		parent::__construct( $args );
52
53
		// Acquirer URL.
54
		$this->acquirer_url      = $args['acquirer_url'];
0 ignored issues
show
Bug Best Practice introduced by
The property acquirer_url does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
55
		$this->acquirer_test_url = $args['acquirer_test_url'];
0 ignored issues
show
Bug Best Practice introduced by
The property acquirer_test_url does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
56
57
		// Actions.
58
		add_action( 'current_screen', array( $this, 'maybe_download_private_certificate' ) );
59
		add_action( 'current_screen', array( $this, 'maybe_download_private_key' ) );
60
	}
61
62
	/**
63
	 * Get settings fields.
64
	 *
65
	 * @return array<int, array<string, callable|int|string|bool|array<int|string,int|string>>>
66
	 */
67
	public function get_settings_fields() {
68
		$fields = parent::get_settings_fields();
69
70
		/*
71
		 * Private Key and Certificate
72
		 */
73
74
		// Private key and certificate information.
75
		$fields[] = array(
76
			'section'  => 'general',
77
			'title'    => __( 'Private key and certificate', 'pronamic_ideal' ),
78
			'type'     => 'description',
79
			'callback' => array( $this, 'field_security' ),
80
		);
81
82
		// Organization.
83
		$fields[] = array(
84
			'section'  => 'general',
85
			'filter'   => FILTER_SANITIZE_STRING,
86
			'group'    => 'pk-cert',
87
			'meta_key' => '_pronamic_gateway_organization',
88
			'title'    => __( 'Organization', 'pronamic_ideal' ),
89
			'type'     => 'text',
90
			'tooltip'  => __( 'Organization name, e.g. Pronamic', 'pronamic_ideal' ),
91
		);
92
93
		// Organization Unit.
94
		$fields[] = array(
95
			'section'  => 'general',
96
			'filter'   => FILTER_SANITIZE_STRING,
97
			'group'    => 'pk-cert',
98
			'meta_key' => '_pronamic_gateway_organization_unit',
99
			'title'    => __( 'Organization Unit', 'pronamic_ideal' ),
100
			'type'     => 'text',
101
			'tooltip'  => __( 'Organization unit, e.g. Administration', 'pronamic_ideal' ),
102
		);
103
104
		// Locality.
105
		$fields[] = array(
106
			'section'  => 'general',
107
			'filter'   => FILTER_SANITIZE_STRING,
108
			'group'    => 'pk-cert',
109
			'meta_key' => '_pronamic_gateway_locality',
110
			'title'    => __( 'City', 'pronamic_ideal' ),
111
			'type'     => 'text',
112
			'tooltip'  => __( 'City, e.g. Amsterdam', 'pronamic_ideal' ),
113
		);
114
115
		// State or Province.
116
		$fields[] = array(
117
			'section'  => 'general',
118
			'filter'   => FILTER_SANITIZE_STRING,
119
			'group'    => 'pk-cert',
120
			'meta_key' => '_pronamic_gateway_state_or_province',
121
			'title'    => __( 'State / province', 'pronamic_ideal' ),
122
			'type'     => 'text',
123
			'tooltip'  => __( 'State or province, e.g. Friesland', 'pronamic_ideal' ),
124
		);
125
126
		// Country.
127
		$locale = \explode( '_', \get_locale() );
128
129
		$locale = count( $locale ) > 1 ? $locale[1] : $locale[0];
130
131
		$fields[] = array(
132
			'section'     => 'general',
133
			'filter'      => FILTER_SANITIZE_STRING,
134
			'group'       => 'pk-cert',
135
			'meta_key'    => '_pronamic_gateway_country',
136
			'title'       => __( 'Country', 'pronamic_ideal' ),
137
			'type'        => 'text',
138
			'tooltip'     => sprintf(
139
				'%s %s (ISO-3166-1 alpha-2)',
140
				__( '2 letter country code, e.g.', 'pronamic_ideal' ),
141
				strtoupper( $locale )
142
			),
143
			'size'        => 2,
144
			'description' => sprintf(
145
				'%s %s',
146
				__( '2 letter country code, e.g.', 'pronamic_ideal' ),
147
				strtoupper( $locale )
148
			),
149
		);
150
151
		// Email Address.
152
		$fields[] = array(
153
			'section'  => 'general',
154
			'filter'   => FILTER_SANITIZE_STRING,
155
			'group'    => 'pk-cert',
156
			'meta_key' => '_pronamic_gateway_email',
157
			'title'    => __( 'E-mail address', 'pronamic_ideal' ),
158
			'tooltip'  => sprintf(
159
				/* translators: %s: admin email */
160
				__( 'E-mail address, e.g. %s', 'pronamic_ideal' ),
161
				(string) get_option( 'admin_email' )
162
			),
163
			'type'     => 'text',
164
		);
165
166
		// Number Days Valid.
167
		$fields[] = array(
168
			'section'  => 'general',
169
			'filter'   => FILTER_SANITIZE_NUMBER_INT,
170
			'group'    => 'pk-cert',
171
			'meta_key' => '_pronamic_gateway_number_days_valid',
172
			'title'    => __( 'Number Days Valid', 'pronamic_ideal' ),
173
			'type'     => 'text',
174
			'default'  => 1825,
175
			'tooltip'  => __( 'Number of days the generated certificate will be valid for, e.g. 1825 days for the maximum duration of 5 years.', 'pronamic_ideal' ),
176
		);
177
178
		// Private Key Password.
179
		$fields[] = array(
180
			'section'  => 'general',
181
			'filter'   => FILTER_SANITIZE_STRING,
182
			'group'    => 'pk-cert',
183
			'meta_key' => '_pronamic_gateway_ideal_private_key_password',
184
			'title'    => __( 'Private Key Password', 'pronamic_ideal' ),
185
			'type'     => 'text',
186
			'classes'  => array( 'regular-text', 'code' ),
187
			'default'  => wp_generate_password(),
188
			'tooltip'  => __( 'A random password which will be used for the generation of the private key and certificate.', 'pronamic_ideal' ),
189
		);
190
191
		// Private Key.
192
		$fields[] = array(
193
			'section'  => 'general',
194
			'filter'   => FILTER_SANITIZE_STRING,
195
			'group'    => 'pk-cert',
196
			'meta_key' => '_pronamic_gateway_ideal_private_key',
197
			'title'    => __( 'Private Key', 'pronamic_ideal' ),
198
			'type'     => 'textarea',
199
			'callback' => array( $this, 'field_private_key' ),
200
			'classes'  => array( 'code' ),
201
			'tooltip'  => __( 'The private key is used for secure communication with the payment provider. If left empty, the private key will be generated using the given private key password.', 'pronamic_ideal' ),
202
		);
203
204
		// Private Certificate.
205
		$fields[] = array(
206
			'section'  => 'general',
207
			'filter'   => FILTER_SANITIZE_STRING,
208
			'group'    => 'pk-cert',
209
			'meta_key' => '_pronamic_gateway_ideal_private_certificate',
210
			'title'    => __( 'Private Certificate', 'pronamic_ideal' ),
211
			'type'     => 'textarea',
212
			'callback' => array( $this, 'field_private_certificate' ),
213
			'classes'  => array( 'code' ),
214
			'tooltip'  => __( 'The certificate is used for secure communication with the payment provider. If left empty, the certificate will be generated using the private key and given organization details.', 'pronamic_ideal' ),
215
		);
216
217
		// Return.
218
		return $fields;
219
	}
220
221
	/**
222
	 * Field security
223
	 *
224
	 * @param array<string, mixed> $field Field.
225
	 * @return void
226
	 */
227
	public function field_security( $field ) {
228
		$post_id = (int) \get_the_ID();
229
230
		$certificate = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true );
231
232
		?>
233
		<p>
234
			<?php if ( empty( $certificate ) ) : ?>
235
236
				<span
237
					class="dashicons dashicons-no"></span> <?php esc_html_e( 'The private key and certificate have not yet been configured.', 'pronamic_ideal' ); ?>
238
				<br/>
239
240
				<br/>
241
242
				<?php esc_html_e( 'A private key and certificate are required for communication with the payment provider. Enter the organization details from the iDEAL account below to generate these required files.', 'pronamic_ideal' ); ?>
243
244
			<?php else : ?>
245
246
				<span
247
					class="dashicons dashicons-yes"></span> <?php esc_html_e( 'A private key and certificate have been configured. The certificate must be uploaded to the payment provider dashboard to complete configuration.', 'pronamic_ideal' ); ?>
248
				<br/>
249
250
				<br/>
251
252
				<?php
253
254
				submit_button(
255
					__( 'Download certificate', 'pronamic_ideal' ),
256
					'secondary',
257
					'download_private_certificate',
258
					false
259
				);
260
261
				?>
262
263
			<?php endif; ?>
264
		</p>
265
		<?php
266
	}
267
268
	/**
269
	 * Field private key.
270
	 *
271
	 * @param array<string, mixed> $field Field.
272
	 * @return void
273
	 */
274
	public function field_private_key( $field ) {
275
		$post_id = (int) \get_the_ID();
276
277
		$private_key          = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', true );
278
		$private_key_password = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key_password', true );
279
		$number_days_valid    = get_post_meta( $post_id, '_pronamic_gateway_number_days_valid', true );
280
281
		$filename = __( 'ideal.key', 'pronamic_ideal' );
282
283
		if ( ! empty( $private_key_password ) && ! empty( $number_days_valid ) ) {
284
			$command = sprintf(
285
				'openssl genrsa -aes128 -out %s -passout pass:%s 2048',
286
				escapeshellarg( $filename ),
287
				escapeshellarg( $private_key_password )
288
			);
289
290
			?>
291
292
			<p><?php esc_html_e( 'OpenSSL command', 'pronamic_ideal' ); ?></p>
293
			<input id="pronamic_ideal_openssl_command_key" name="pronamic_ideal_openssl_command_key" value="<?php echo esc_attr( $command ); ?>" type="text" class="large-text code" readonly="readonly"/>
294
295
			<?php
296
		} else {
297
			printf(
298
				'<p class="pronamic-pay-description description">%s</p>',
299
				esc_html__( 'Leave empty and save the configuration to generate the private key or view the OpenSSL command.', 'pronamic_ideal' )
300
			);
301
		}
302
303
		?>
304
		<p>
305
			<?php
306
307
			if ( ! empty( $private_key ) ) {
308
				submit_button(
309
					__( 'Download', 'pronamic_ideal' ),
310
					'secondary',
311
					'download_private_key',
312
					false
313
				);
314
315
				echo ' ';
316
			}
317
318
			printf(
319
				'<label class="pronamic-pay-form-control-file-button button">%s <input type="file" name="%s" /></label>',
320
				esc_html__( 'Upload', 'pronamic_ideal' ),
321
				'_pronamic_gateway_ideal_private_key_file'
322
			);
323
324
			?>
325
		</p>
326
		<?php
327
	}
328
329
	/**
330
	 * Field private certificate.
331
	 *
332
	 * @param array<string, mixed> $field Field.
333
	 * @return void
334
	 */
335
	public function field_private_certificate( $field ) {
336
		$post_id = (int) \get_the_ID();
337
338
		$certificate = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true );
339
340
		$private_key_password = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key_password', true );
341
		$number_days_valid    = get_post_meta( $post_id, '_pronamic_gateway_number_days_valid', true );
342
343
		$filename_key = __( 'ideal.key', 'pronamic_ideal' );
344
		$filename_cer = __( 'ideal.cer', 'pronamic_ideal' );
345
346
		// @link http://www.openssl.org/docs/apps/req.html
347
		$subj_args = array(
348
			'C'            => get_post_meta( $post_id, '_pronamic_gateway_country', true ),
349
			'ST'           => get_post_meta( $post_id, '_pronamic_gateway_state_or_province', true ),
350
			'L'            => get_post_meta( $post_id, '_pronamic_gateway_locality', true ),
351
			'O'            => get_post_meta( $post_id, '_pronamic_gateway_organization', true ),
352
			'OU'           => get_post_meta( $post_id, '_pronamic_gateway_organization_unit', true ),
353
			'CN'           => get_post_meta( $post_id, '_pronamic_gateway_organization', true ),
354
			'emailAddress' => get_post_meta( $post_id, '_pronamic_gateway_email', true ),
355
		);
356
357
		$subj_args = array_filter( $subj_args );
358
359
		$subj = '';
360
361
		foreach ( $subj_args as $type => $value ) {
362
			$subj .= '/' . $type . '=' . addslashes( $value );
363
		}
364
365
		if ( ! empty( $subj ) ) {
366
			$command = trim(
367
				sprintf(
368
					'openssl req -x509 -sha256 -new -key %s -passin pass:%s -days %s -out %s %s',
369
					escapeshellarg( $filename_key ),
370
					escapeshellarg( $private_key_password ),
0 ignored issues
show
It seems like $private_key_password can also be of type false; however, parameter $arg of escapeshellarg() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

370
					escapeshellarg( /** @scrutinizer ignore-type */ $private_key_password ),
Loading history...
371
					escapeshellarg( $number_days_valid ),
372
					escapeshellarg( $filename_cer ),
373
					sprintf( '-subj %s', escapeshellarg( $subj ) )
374
				)
375
			);
376
377
			?>
378
379
			<p><?php esc_html_e( 'OpenSSL command', 'pronamic_ideal' ); ?></p>
380
			<input id="pronamic_ideal_openssl_command_certificate" name="pronamic_ideal_openssl_command_certificate" value="<?php echo esc_attr( $command ); ?>" type="text" class="large-text code" readonly="readonly"/>
381
382
			<?php
383
		} else {
384
			printf(
385
				'<p class="pronamic-pay-description description">%s</p>',
386
				esc_html__( 'Leave empty and save the configuration to generate the certificate or view the OpenSSL command.', 'pronamic_ideal' )
387
			);
388
		}
389
390
		if ( ! empty( $certificate ) ) {
391
			$fingerprint = (string) Security::get_sha_fingerprint( $certificate );
392
			$fingerprint = str_split( $fingerprint, 2 );
393
			$fingerprint = implode( ':', $fingerprint );
394
395
			echo '<dl>';
396
397
			echo '<dt>', esc_html__( 'SHA Fingerprint', 'pronamic_ideal' ), '</dt>';
398
			echo '<dd>', esc_html( $fingerprint ), '</dd>';
399
400
			$info = openssl_x509_parse( $certificate );
401
402
			if ( $info ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $info of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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.

Loading history...
403
				$date_format = __( 'M j, Y @ G:i', 'pronamic_ideal' );
404
405
				if ( isset( $info['validFrom_time_t'] ) ) {
406
					echo '<dt>', esc_html__( 'Valid From', 'pronamic_ideal' ), '</dt>';
407
					echo '<dd>', esc_html( date_i18n( $date_format, $info['validFrom_time_t'] ) ), '</dd>';
408
				}
409
410
				if ( isset( $info['validTo_time_t'] ) ) {
411
					echo '<dt>', esc_html__( 'Valid To', 'pronamic_ideal' ), '</dt>';
412
					echo '<dd>', esc_html( date_i18n( $date_format, $info['validTo_time_t'] ) ), '</dd>';
413
				}
414
			}
415
416
			echo '</dl>';
417
		}
418
419
		?>
420
		<p>
421
			<?php
422
423
			if ( ! empty( $certificate ) ) {
424
				submit_button(
425
					__( 'Download', 'pronamic_ideal' ),
426
					'secondary',
427
					'download_private_certificate',
428
					false
429
				);
430
431
				echo ' ';
432
			}
433
434
			printf(
435
				'<label class="pronamic-pay-form-control-file-button button">%s <input type="file" name="%s" /></label>',
436
				esc_html__( 'Upload', 'pronamic_ideal' ),
437
				'_pronamic_gateway_ideal_private_certificate_file'
438
			);
439
440
			?>
441
		</p>
442
		<?php
443
	}
444
445
	/**
446
	 * Download private certificate.
447
	 *
448
	 * @return void
449
	 */
450
	public function maybe_download_private_certificate() {
451
		if ( ! filter_has_var( INPUT_POST, 'download_private_certificate' ) ) {
452
			return;
453
		}
454
455
		$post_id = filter_input( INPUT_POST, 'post_ID', FILTER_SANITIZE_STRING );
456
457
		$filename = sprintf( 'ideal-private-certificate-%s.cer', $post_id );
458
459
		header( 'Content-Description: File Transfer' );
460
		header( 'Content-Disposition: attachment; filename=' . $filename );
461
		header( 'Content-Type: application/x-x509-ca-cert; charset=' . get_option( 'blog_charset' ), true );
462
463
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
464
		echo get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true );
465
466
		exit;
467
	}
468
469
	/**
470
	 * Download private key.
471
	 *
472
	 * @return void
473
	 */
474
	public function maybe_download_private_key() {
475
		if ( filter_has_var( INPUT_POST, 'download_private_key' ) ) {
476
			$post_id = filter_input( INPUT_POST, 'post_ID', FILTER_SANITIZE_STRING );
477
478
			$filename = sprintf( 'ideal-private-key-%s.key', $post_id );
479
480
			header( 'Content-Description: File Transfer' );
481
			header( 'Content-Disposition: attachment; filename=' . $filename );
482
			header( 'Content-Type: application/pgp-keys; charset=' . get_option( 'blog_charset' ), true );
483
484
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
485
			echo get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', true );
486
487
			exit;
488
		}
489
	}
490
491
	/**
492
	 * Save post.
493
	 *
494
	 * @param int $post_id Post ID.
495
	 * @return void
496
	 */
497
	public function save_post( $post_id ) {
498
		// Files.
499
		$files = array(
500
			'_pronamic_gateway_ideal_private_key_file' => '_pronamic_gateway_ideal_private_key',
501
			'_pronamic_gateway_ideal_private_certificate_file' => '_pronamic_gateway_ideal_private_certificate',
502
		);
503
504
		foreach ( $files as $name => $meta_key ) {
505
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
506
			if ( isset( $_FILES[ $name ] ) && UPLOAD_ERR_OK === $_FILES[ $name ]['error'] ) {
507
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
508
				$value = file_get_contents( $_FILES[ $name ]['tmp_name'] );
509
510
				update_post_meta( $post_id, $meta_key, $value );
511
			}
512
		}
513
514
		// Generate private key and certificate.
515
		$private_key          = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', true );
516
		$private_key_password = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key_password', true );
517
518
		if ( empty( $private_key_password ) ) {
519
			// Without private key password we can't create private key and certifiate.
520
			return;
521
		}
522
523
		if ( ! in_array( 'aes-128-cbc', openssl_get_cipher_methods(), true ) ) {
524
			// Without AES-128-CBC ciphter method we can't create private key and certificate.
525
			return;
526
		}
527
528
		$args = array(
529
			'digest_alg'             => 'SHA256',
530
			'private_key_bits'       => 2048,
531
			'private_key_type'       => \OPENSSL_KEYTYPE_RSA,
532
			'encrypt_key'            => true,
533
			'subjectKeyIdentifier'   => 'hash',
534
			'authorityKeyIdentifier' => 'keyid:always,issuer:always',
535
			'basicConstraints'       => 'CA:true',
536
		);
537
538
		// Private key.
539
		$pkey = openssl_pkey_get_private( $private_key, $private_key_password );
540
541
		if ( false === $pkey ) {
542
			// If we can't open the private key we will create a new private key and certificate.
543
			if ( defined( 'OPENSSL_CIPHER_AES_128_CBC' ) ) {
544
				$args['encrypt_key_cipher'] = \OPENSSL_CIPHER_AES_128_CBC;
545
			} elseif ( defined( 'OPENSSL_CIPHER_3DES' ) ) {
546
				// @link https://www.pronamic.nl/wp-content/uploads/2011/12/iDEAL_Advanced_PHP_EN_V2.2.pdf
547
				$args['encrypt_key_cipher'] = \OPENSSL_CIPHER_3DES;
548
			} else {
549
				// Unable to create private key without cipher.
550
				return;
551
			}
552
553
			$pkey = openssl_pkey_new( $args );
554
555
			if ( false === $pkey ) {
556
				return;
557
			}
558
559
			// Export key.
560
			$result = openssl_pkey_export( $pkey, $private_key, $private_key_password, $args );
0 ignored issues
show
It seems like $private_key can also be of type false; however, parameter $out of openssl_pkey_export() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

560
			$result = openssl_pkey_export( $pkey, /** @scrutinizer ignore-type */ $private_key, $private_key_password, $args );
Loading history...
561
562
			if ( false === $result ) {
563
				return;
564
			}
565
566
			update_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', $private_key );
567
568
			// Delete private certificate since this is no longer valid.
569
			delete_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate' );
570
		}
571
572
		// Certificate.
573
		$private_certificate = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true );
574
		$number_days_valid   = get_post_meta( $post_id, '_pronamic_gateway_number_days_valid', true );
575
576
		if ( empty( $private_certificate ) ) {
577
			$required_keys = array(
578
				'countryName',
579
				'stateOrProvinceName',
580
				'localityName',
581
				'organizationName',
582
				'commonName',
583
				'emailAddress',
584
			);
585
586
			$distinguished_name = array(
587
				'countryName'            => get_post_meta( $post_id, '_pronamic_gateway_country', true ),
588
				'stateOrProvinceName'    => get_post_meta( $post_id, '_pronamic_gateway_state_or_province', true ),
589
				'localityName'           => get_post_meta( $post_id, '_pronamic_gateway_locality', true ),
590
				'organizationName'       => get_post_meta( $post_id, '_pronamic_gateway_organization', true ),
591
				'organizationalUnitName' => get_post_meta( $post_id, '_pronamic_gateway_organization_unit', true ),
592
				'commonName'             => get_post_meta( $post_id, '_pronamic_gateway_organization', true ),
593
				'emailAddress'           => get_post_meta( $post_id, '_pronamic_gateway_email', true ),
594
			);
595
596
			$distinguished_name = array_filter( $distinguished_name );
597
598
			/*
599
			 * Create certificate only if distinguished name contains all required elements
600
			 *
601
			 * @link http://stackoverflow.com/questions/13169588/how-to-check-if-multiple-array-keys-exists
602
			 */
603
			if ( count( array_intersect_key( array_flip( $required_keys ), $distinguished_name ) ) === count( $required_keys ) ) {
604
				// If we can't open the private key we will create a new private key and certificate.
605
				if ( defined( 'OPENSSL_CIPHER_AES_128_CBC' ) ) {
606
					$args['encrypt_key_cipher'] = \OPENSSL_CIPHER_AES_128_CBC;
607
				} elseif ( defined( 'OPENSSL_CIPHER_3DES' ) ) {
608
					// @link https://www.pronamic.nl/wp-content/uploads/2011/12/iDEAL_Advanced_PHP_EN_V2.2.pdf
609
					$args['encrypt_key_cipher'] = \OPENSSL_CIPHER_3DES;
610
				} else {
611
					// Unable to create private key without cipher.
612
					return;
613
				}
614
615
				$csr = openssl_csr_new( $distinguished_name, $pkey );
616
617
				if ( false !== $csr ) {
618
					$cert = openssl_csr_sign( $csr, null, $pkey, $number_days_valid, $args, time() );
0 ignored issues
show
It seems like $number_days_valid can also be of type false and string; however, parameter $days of openssl_csr_sign() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

618
					$cert = openssl_csr_sign( $csr, null, $pkey, /** @scrutinizer ignore-type */ $number_days_valid, $args, time() );
Loading history...
619
620
					if ( false !== $cert ) {
621
						openssl_x509_export( $cert, $certificate );
622
623
						update_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', $certificate );
624
					}
625
				}
626
			}
627
		}
628
	}
629
630
	/**
631
	 * Get config.
632
	 *
633
	 * @param int $post_id Post ID.
634
	 * @return Config
635
	 */
636
	public function get_config( $post_id ) {
637
		$mode = get_post_meta( $post_id, '_pronamic_gateway_mode', true );
638
639
		$config = new Config();
640
641
		$config->payment_server_url = $this->acquirer_url;
642
643
		if ( 'test' === $mode && null !== $this->acquirer_test_url ) {
644
			$config->payment_server_url = $this->acquirer_test_url;
645
		}
646
647
		$config->set_merchant_id( get_post_meta( $post_id, '_pronamic_gateway_ideal_merchant_id', true ) );
0 ignored issues
show
It seems like get_post_meta($post_id, ...eal_merchant_id', true) can also be of type false; however, parameter $merchant_id of Pronamic\WordPress\Pay\G...nfig::set_merchant_id() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

647
		$config->set_merchant_id( /** @scrutinizer ignore-type */ get_post_meta( $post_id, '_pronamic_gateway_ideal_merchant_id', true ) );
Loading history...
648
		$config->set_sub_id( get_post_meta( $post_id, '_pronamic_gateway_ideal_sub_id', true ) );
0 ignored issues
show
It seems like get_post_meta($post_id, ...ay_ideal_sub_id', true) can also be of type false; however, parameter $sub_id of Pronamic\WordPress\Pay\G...V3\Config::set_sub_id() does only seem to accept integer|null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

648
		$config->set_sub_id( /** @scrutinizer ignore-type */ get_post_meta( $post_id, '_pronamic_gateway_ideal_sub_id', true ) );
Loading history...
649
		$config->set_purchase_id( get_post_meta( $post_id, '_pronamic_gateway_ideal_purchase_id', true ) );
0 ignored issues
show
It seems like get_post_meta($post_id, ...eal_purchase_id', true) can also be of type false; however, parameter $purchase_id of Pronamic\WordPress\Pay\G...nfig::set_purchase_id() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

649
		$config->set_purchase_id( /** @scrutinizer ignore-type */ get_post_meta( $post_id, '_pronamic_gateway_ideal_purchase_id', true ) );
Loading history...
650
651
		$config->set_private_key( get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', true ) );
0 ignored issues
show
It seems like get_post_meta($post_id, ...eal_private_key', true) can also be of type false; however, parameter $private_key of Pronamic\WordPress\Pay\G...nfig::set_private_key() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

651
		$config->set_private_key( /** @scrutinizer ignore-type */ get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', true ) );
Loading history...
652
		$config->set_private_key_password( get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key_password', true ) );
0 ignored issues
show
It seems like get_post_meta($post_id, ...te_key_password', true) can also be of type false; however, parameter $private_key_password of Pronamic\WordPress\Pay\G..._private_key_password() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

652
		$config->set_private_key_password( /** @scrutinizer ignore-type */ get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key_password', true ) );
Loading history...
653
		$config->set_private_certificate( get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true ) );
0 ignored issues
show
It seems like get_post_meta($post_id, ...ate_certificate', true) can also be of type false; however, parameter $private_certificate of Pronamic\WordPress\Pay\G...t_private_certificate() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

653
		$config->set_private_certificate( /** @scrutinizer ignore-type */ get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true ) );
Loading history...
654
655
		return $config;
656
	}
657
658
	/**
659
	 * Get gateway.
660
	 *
661
	 * @param int $post_id Post ID.
662
	 * @return Gateway
663
	 */
664
	public function get_gateway( $post_id ) {
665
		return new Gateway( $this->get_config( $post_id ) );
666
	}
667
}
668