Failed Conditions
Push — develop ( e144d7...9a75d9 )
by Remco
07:40
created

src/Integration.php (14 issues)

1
<?php
2
3
namespace Pronamic\WordPress\Pay\Gateways\IDealAdvancedV3;
4
5
use Pronamic\WordPress\Pay\Gateways\IDeal\AbstractIntegration;
6
7
/**
8
 * Title: iDEAL Advanced v3 integration
9
 * Description:
10
 * Copyright: 2005-2020 Pronamic
11
 * Company: Pronamic
12
 *
13
 * @author  Remco Tolsma
14
 * @version 2.0.5
15
 * @since   2.0.0
16
 */
17
class Integration extends AbstractIntegration {
18
	/**
19
	 * Settings constructor.
20
	 */
21
	public function __construct( $args = array() ) {
22
		$args = wp_parse_args(
23
			$args,
24
			array(
25
				'id'               => 'ideal-advanced-v3',
26
				'name'             => 'iDEAL Advanced v3',
27
				'url'              => __( 'https://www.ideal.nl/en/', 'pronamic_ideal' ),
28
				'product_url'      => __( 'https://www.ideal.nl/en/', 'pronamic_ideal' ),
29
				'manual_url'       => null,
30
				'dashboard_url'    => null,
31
				'provider'         => null,
32
				'aquirer_url'      => null,
33
				'aquirer_test_url' => null,
34
			)
35
		);
36
37
		parent::__construct( $args );
38
39
		$this->id            = $args['id'];
40
		$this->name          = $args['name'];
41
		$this->url           = $args['url'];
42
		$this->product_url   = $args['product_url'];
43
		$this->dashboard_url = $args['dashboard_url'];
44
		$this->provider      = $args['provider'];
45
46
		$this->aquirer_url      = $args['aquirer_url'];
0 ignored issues
show
Bug Best Practice introduced by
The property aquirer_url does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
47
		$this->aquirer_test_url = $args['aquirer_test_url'];
0 ignored issues
show
Bug Best Practice introduced by
The property aquirer_test_url does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
48
49
		$this->set_manual_url( $args['manual_url'] );
50
51
		// Supported features.
52
		$this->supports = array(
53
			'payment_status_request',
54
		);
55
56
		// Actions.
57
		add_action( 'current_screen', array( $this, 'maybe_download_private_certificate' ) );
58
		add_action( 'current_screen', array( $this, 'maybe_download_private_key' ) );
59
	}
60
61
	public function get_settings_fields() {
62
		$fields = parent::get_settings_fields();
63
64
		/*
65
		 * Private Key and Certificate
66
		 */
67
68
		// Private key and certificate information.
69
		$fields[] = array(
70
			'section'  => 'general',
71
			'title'    => __( 'Private key and certificate', 'pronamic_ideal' ),
72
			'type'     => 'description',
73
			'callback' => array( $this, 'field_security' ),
74
		);
75
76
		// Organization.
77
		$fields[] = array(
78
			'section'  => 'general',
79
			'filter'   => FILTER_SANITIZE_STRING,
80
			'group'    => 'pk-cert',
81
			'meta_key' => '_pronamic_gateway_organization',
82
			'title'    => __( 'Organization', 'pronamic_ideal' ),
83
			'type'     => 'text',
84
			'tooltip'  => __( 'Organization name, e.g. Pronamic', 'pronamic_ideal' ),
85
		);
86
87
		// Organization Unit.
88
		$fields[] = array(
89
			'section'  => 'general',
90
			'filter'   => FILTER_SANITIZE_STRING,
91
			'group'    => 'pk-cert',
92
			'meta_key' => '_pronamic_gateway_organization_unit',
93
			'title'    => __( 'Organization Unit', 'pronamic_ideal' ),
94
			'type'     => 'text',
95
			'tooltip'  => __( 'Organization unit, e.g. Administration', 'pronamic_ideal' ),
96
		);
97
98
		// Locality.
99
		$fields[] = array(
100
			'section'  => 'general',
101
			'filter'   => FILTER_SANITIZE_STRING,
102
			'group'    => 'pk-cert',
103
			'meta_key' => '_pronamic_gateway_locality',
104
			'title'    => __( 'City', 'pronamic_ideal' ),
105
			'type'     => 'text',
106
			'tooltip'  => __( 'City, e.g. Amsterdam', 'pronamic_ideal' ),
107
		);
108
109
		// State or Province.
110
		$fields[] = array(
111
			'section'  => 'general',
112
			'filter'   => FILTER_SANITIZE_STRING,
113
			'group'    => 'pk-cert',
114
			'meta_key' => '_pronamic_gateway_state_or_province',
115
			'title'    => __( 'State / province', 'pronamic_ideal' ),
116
			'type'     => 'text',
117
			'tooltip'  => __( 'State or province, e.g. Friesland', 'pronamic_ideal' ),
118
		);
119
120
		// Country.
121
		$locale = explode( '_', get_locale() );
122
123
		$locale = array_pop( $locale );
124
125
		$fields[] = array(
126
			'section'     => 'general',
127
			'filter'      => FILTER_SANITIZE_STRING,
128
			'group'       => 'pk-cert',
129
			'meta_key'    => '_pronamic_gateway_country',
130
			'title'       => __( 'Country', 'pronamic_ideal' ),
131
			'type'        => 'text',
132
			'tooltip'     => sprintf(
133
				'%s %s (ISO-3166-1 alpha-2)',
134
				__( '2 letter country code, e.g.', 'pronamic_ideal' ),
135
				strtoupper( $locale )
136
			),
137
			'size'        => 2,
138
			'description' => sprintf(
139
				'%s %s',
140
				__( '2 letter country code, e.g.', 'pronamic_ideal' ),
141
				strtoupper( $locale )
142
			),
143
		);
144
145
		// Email Address.
146
		$fields[] = array(
147
			'section'  => 'general',
148
			'filter'   => FILTER_SANITIZE_STRING,
149
			'group'    => 'pk-cert',
150
			'meta_key' => '_pronamic_gateway_email',
151
			'title'    => __( 'E-mail address', 'pronamic_ideal' ),
152
			'tooltip'  => sprintf(
153
				/* translators: %s: admin email */
154
				__( 'E-mail address, e.g. %s', 'pronamic_ideal' ),
155
				(string) get_option( 'admin_email' )
156
			),
157
			'type'     => 'text',
158
		);
159
160
		// Number Days Valid.
161
		$fields[] = array(
162
			'section'  => 'general',
163
			'filter'   => FILTER_SANITIZE_NUMBER_INT,
164
			'group'    => 'pk-cert',
165
			'meta_key' => '_pronamic_gateway_number_days_valid',
166
			'title'    => __( 'Number Days Valid', 'pronamic_ideal' ),
167
			'type'     => 'text',
168
			'default'  => 1825,
169
			'tooltip'  => __( 'Number of days the generated certificate will be valid for, e.g. 1825 days for the maximum duration of 5 years.', 'pronamic_ideal' ),
170
		);
171
172
		// Private Key Password.
173
		$fields[] = array(
174
			'section'  => 'general',
175
			'filter'   => FILTER_SANITIZE_STRING,
176
			'group'    => 'pk-cert',
177
			'meta_key' => '_pronamic_gateway_ideal_private_key_password',
178
			'title'    => __( 'Private Key Password', 'pronamic_ideal' ),
179
			'type'     => 'text',
180
			'classes'  => array( 'regular-text', 'code' ),
181
			'default'  => wp_generate_password(),
182
			'tooltip'  => __( 'A random password which will be used for the generation of the private key and certificate.', 'pronamic_ideal' ),
183
		);
184
185
		// Private Key.
186
		$fields[] = array(
187
			'section'  => 'general',
188
			'filter'   => FILTER_SANITIZE_STRING,
189
			'group'    => 'pk-cert',
190
			'meta_key' => '_pronamic_gateway_ideal_private_key',
191
			'title'    => __( 'Private Key', 'pronamic_ideal' ),
192
			'type'     => 'textarea',
193
			'callback' => array( $this, 'field_private_key' ),
194
			'classes'  => array( 'code' ),
195
			'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' ),
196
		);
197
198
		// Private Certificate.
199
		$fields[] = array(
200
			'section'  => 'general',
201
			'filter'   => FILTER_SANITIZE_STRING,
202
			'group'    => 'pk-cert',
203
			'meta_key' => '_pronamic_gateway_ideal_private_certificate',
204
			'title'    => __( 'Private Certificate', 'pronamic_ideal' ),
205
			'type'     => 'textarea',
206
			'callback' => array( $this, 'field_private_certificate' ),
207
			'classes'  => array( 'code' ),
208
			'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' ),
209
		);
210
211
		// Return.
212
		return $fields;
213
	}
214
215
	/**
216
	 * Field security
217
	 *
218
	 * @param array $field Field.
219
	 */
220
	public function field_security( $field ) {
221
		$certificate = get_post_meta( get_the_ID(), '_pronamic_gateway_ideal_private_certificate', true );
0 ignored issues
show
It seems like get_the_ID() can also be of type false; however, parameter $post_id of get_post_meta() 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

221
		$certificate = get_post_meta( /** @scrutinizer ignore-type */ get_the_ID(), '_pronamic_gateway_ideal_private_certificate', true );
Loading history...
222
223
		?>
224
		<p>
225
			<?php if ( empty( $certificate ) ) : ?>
226
227
				<span
228
					class="dashicons dashicons-no"></span> <?php esc_html_e( 'The private key and certificate have not yet been configured.', 'pronamic_ideal' ); ?>
229
				<br/>
230
231
				<br/>
232
233
				<?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' ); ?>
234
235
			<?php else : ?>
236
237
				<span
238
					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' ); ?>
239
				<br/>
240
241
				<br/>
242
243
				<?php
244
245
				submit_button(
246
					__( 'Download certificate', 'pronamic_ideal' ),
247
					'secondary',
248
					'download_private_certificate',
249
					false
250
				);
251
252
				?>
253
254
			<?php endif; ?>
255
		</p>
256
		<?php
257
	}
258
259
	/**
260
	 * Field private key.
261
	 *
262
	 * @param array $field Field.
263
	 */
264
	public function field_private_key( $field ) {
265
		$private_key          = get_post_meta( get_the_ID(), '_pronamic_gateway_ideal_private_key', true );
0 ignored issues
show
It seems like get_the_ID() can also be of type false; however, parameter $post_id of get_post_meta() 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

265
		$private_key          = get_post_meta( /** @scrutinizer ignore-type */ get_the_ID(), '_pronamic_gateway_ideal_private_key', true );
Loading history...
266
		$private_key_password = get_post_meta( get_the_ID(), '_pronamic_gateway_ideal_private_key_password', true );
267
		$number_days_valid    = get_post_meta( get_the_ID(), '_pronamic_gateway_number_days_valid', true );
268
269
		$filename = __( 'ideal.key', 'pronamic_ideal' );
270
271
		if ( ! empty( $private_key_password ) && ! empty( $number_days_valid ) ) {
272
			$command = sprintf(
273
				'openssl genrsa -aes128 -out %s -passout pass:%s 2048',
274
				escapeshellarg( $filename ),
275
				escapeshellarg( $private_key_password )
276
			);
277
278
			?>
279
280
			<p><?php esc_html_e( 'OpenSSL command', 'pronamic_ideal' ); ?></p>
281
			<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"/>
282
283
			<?php
284
		} else {
285
			printf(
286
				'<p class="pronamic-pay-description description">%s</p>',
287
				esc_html__( 'Leave empty and save the configuration to generate the private key or view the OpenSSL command.', 'pronamic_ideal' )
288
			);
289
		}
290
291
		?>
292
		<p>
293
			<?php
294
295
			if ( ! empty( $private_key ) ) {
296
				submit_button(
297
					__( 'Download', 'pronamic_ideal' ),
298
					'secondary',
299
					'download_private_key',
300
					false
301
				);
302
303
				echo ' ';
304
			}
305
306
			printf(
307
				'<label class="pronamic-pay-form-control-file-button button">%s <input type="file" name="%s" /></label>',
308
				esc_html__( 'Upload', 'pronamic_ideal' ),
309
				'_pronamic_gateway_ideal_private_key_file'
310
			);
311
312
			?>
313
		</p>
314
		<?php
315
	}
316
317
	/**
318
	 * Field private certificate.
319
	 *
320
	 * @param array $field Field.
321
	 */
322
	public function field_private_certificate( $field ) {
323
		$certificate = get_post_meta( get_the_ID(), '_pronamic_gateway_ideal_private_certificate', true );
0 ignored issues
show
It seems like get_the_ID() can also be of type false; however, parameter $post_id of get_post_meta() 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

323
		$certificate = get_post_meta( /** @scrutinizer ignore-type */ get_the_ID(), '_pronamic_gateway_ideal_private_certificate', true );
Loading history...
324
325
		$private_key_password = get_post_meta( get_the_ID(), '_pronamic_gateway_ideal_private_key_password', true );
326
		$number_days_valid    = get_post_meta( get_the_ID(), '_pronamic_gateway_number_days_valid', true );
327
328
		$filename_key = __( 'ideal.key', 'pronamic_ideal' );
329
		$filename_cer = __( 'ideal.cer', 'pronamic_ideal' );
330
331
		// @link http://www.openssl.org/docs/apps/req.html
332
		$subj_args = array(
333
			'C'            => get_post_meta( get_the_ID(), '_pronamic_gateway_country', true ),
334
			'ST'           => get_post_meta( get_the_ID(), '_pronamic_gateway_state_or_province', true ),
335
			'L'            => get_post_meta( get_the_ID(), '_pronamic_gateway_locality', true ),
336
			'O'            => get_post_meta( get_the_ID(), '_pronamic_gateway_organization', true ),
337
			'OU'           => get_post_meta( get_the_ID(), '_pronamic_gateway_organization_unit', true ),
338
			'CN'           => get_post_meta( get_the_ID(), '_pronamic_gateway_organization', true ),
339
			'emailAddress' => get_post_meta( get_the_ID(), '_pronamic_gateway_email', true ),
340
		);
341
342
		$subj_args = array_filter( $subj_args );
343
344
		$subj = '';
345
		foreach ( $subj_args as $type => $value ) {
346
			$subj .= '/' . $type . '=' . addslashes( $value );
347
		}
348
349
		if ( ! empty( $subj ) ) {
350
			$command = trim(
351
				sprintf(
352
					'openssl req -x509 -sha256 -new -key %s -passin pass:%s -days %s -out %s %s',
353
					escapeshellarg( $filename_key ),
354
					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

354
					escapeshellarg( /** @scrutinizer ignore-type */ $private_key_password ),
Loading history...
355
					escapeshellarg( $number_days_valid ),
356
					escapeshellarg( $filename_cer ),
357
					empty( $subj ) ? '' : sprintf( '-subj %s', escapeshellarg( $subj ) )
358
				)
359
			);
360
361
			?>
362
363
			<p><?php esc_html_e( 'OpenSSL command', 'pronamic_ideal' ); ?></p>
364
			<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"/>
365
366
			<?php
367
		} else {
368
			printf(
369
				'<p class="pronamic-pay-description description">%s</p>',
370
				esc_html__( 'Leave empty and save the configuration to generate the certificate or view the OpenSSL command.', 'pronamic_ideal' )
371
			);
372
		}
373
374
		if ( ! empty( $certificate ) ) {
375
			$fingerprint = Security::get_sha_fingerprint( $certificate );
376
			$fingerprint = str_split( $fingerprint, 2 );
377
			$fingerprint = implode( ':', $fingerprint );
378
379
			echo '<dl>';
380
381
			echo '<dt>', esc_html__( 'SHA Fingerprint', 'pronamic_ideal' ), '</dt>';
382
			echo '<dd>', esc_html( $fingerprint ), '</dd>';
383
384
			$info = openssl_x509_parse( $certificate );
385
386
			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...
387
				$date_format = __( 'M j, Y @ G:i', 'pronamic_ideal' );
388
389
				if ( isset( $info['validFrom_time_t'] ) ) {
390
					echo '<dt>', esc_html__( 'Valid From', 'pronamic_ideal' ), '</dt>';
391
					echo '<dd>', esc_html( date_i18n( $date_format, $info['validFrom_time_t'] ) ), '</dd>';
392
				}
393
394
				if ( isset( $info['validTo_time_t'] ) ) {
395
					echo '<dt>', esc_html__( 'Valid To', 'pronamic_ideal' ), '</dt>';
396
					echo '<dd>', esc_html( date_i18n( $date_format, $info['validTo_time_t'] ) ), '</dd>';
397
				}
398
			}
399
400
			echo '</dl>';
401
		}
402
403
		?>
404
		<p>
405
			<?php
406
407
			if ( ! empty( $certificate ) ) {
408
				submit_button(
409
					__( 'Download', 'pronamic_ideal' ),
410
					'secondary',
411
					'download_private_certificate',
412
					false
413
				);
414
415
				echo ' ';
416
			}
417
418
			printf(
419
				'<label class="pronamic-pay-form-control-file-button button">%s <input type="file" name="%s" /></label>',
420
				esc_html__( 'Upload', 'pronamic_ideal' ),
421
				'_pronamic_gateway_ideal_private_certificate_file'
422
			);
423
424
			?>
425
		</p>
426
		<?php
427
	}
428
429
	/**
430
	 * Download private certificate
431
	 */
432
	public function maybe_download_private_certificate() {
433
		if ( filter_has_var( INPUT_POST, 'download_private_certificate' ) ) {
434
			$post_id = filter_input( INPUT_POST, 'post_ID', FILTER_SANITIZE_STRING );
435
436
			$filename = sprintf( 'ideal-private-certificate-%s.cer', $post_id );
437
438
			header( 'Content-Description: File Transfer' );
439
			header( 'Content-Disposition: attachment; filename=' . $filename );
440
			header( 'Content-Type: application/x-x509-ca-cert; charset=' . get_option( 'blog_charset' ), true );
0 ignored issues
show
Are you sure get_option('blog_charset') of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

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

440
			header( 'Content-Type: application/x-x509-ca-cert; charset=' . /** @scrutinizer ignore-type */ get_option( 'blog_charset' ), true );
Loading history...
441
442
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
443
			echo get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true );
0 ignored issues
show
Are you sure get_post_meta($post_id, ...ate_certificate', true) of type false|mixed|string can be used in echo? ( Ignorable by Annotation )

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

443
			echo /** @scrutinizer ignore-type */ get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true );
Loading history...
444
445
			exit;
446
		}
447
	}
448
449
	/**
450
	 * Download private key
451
	 */
452
	public function maybe_download_private_key() {
453
		if ( filter_has_var( INPUT_POST, 'download_private_key' ) ) {
454
			$post_id = filter_input( INPUT_POST, 'post_ID', FILTER_SANITIZE_STRING );
455
456
			$filename = sprintf( 'ideal-private-key-%s.key', $post_id );
457
458
			header( 'Content-Description: File Transfer' );
459
			header( 'Content-Disposition: attachment; filename=' . $filename );
460
			header( 'Content-Type: application/pgp-keys; charset=' . get_option( 'blog_charset' ), true );
0 ignored issues
show
Are you sure get_option('blog_charset') of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

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

460
			header( 'Content-Type: application/pgp-keys; charset=' . /** @scrutinizer ignore-type */ get_option( 'blog_charset' ), true );
Loading history...
461
462
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
463
			echo get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', true );
0 ignored issues
show
Are you sure get_post_meta($post_id, ...eal_private_key', true) of type false|mixed|string can be used in echo? ( Ignorable by Annotation )

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

463
			echo /** @scrutinizer ignore-type */ get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', true );
Loading history...
464
465
			exit;
466
		}
467
	}
468
469
	/**
470
	 * Save post.
471
	 *
472
	 * @param int $post_id Post ID.
473
	 */
474
	public function save_post( $post_id ) {
475
		// Files.
476
		$files = array(
477
			'_pronamic_gateway_ideal_private_key_file' => '_pronamic_gateway_ideal_private_key',
478
			'_pronamic_gateway_ideal_private_certificate_file' => '_pronamic_gateway_ideal_private_certificate',
479
		);
480
481
		foreach ( $files as $name => $meta_key ) {
482
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
483
			if ( isset( $_FILES[ $name ] ) && UPLOAD_ERR_OK === $_FILES[ $name ]['error'] ) {
484
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
485
				$value = file_get_contents( $_FILES[ $name ]['tmp_name'] );
486
487
				update_post_meta( $post_id, $meta_key, $value );
488
			}
489
		}
490
491
		// Generate private key and certificate.
492
		$private_key          = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', true );
493
		$private_key_password = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key_password', true );
494
495
		if ( empty( $private_key_password ) ) {
496
			// Without private key password we can't create private key and certifiate.
497
			return;
498
		}
499
500
		if ( ! in_array( 'aes-128-cbc', openssl_get_cipher_methods(), true ) ) {
501
			// Without AES-128-CBC ciphter method we can't create private key and certificate.
502
			return;
503
		}
504
505
		// Private key.
506
		$pkey = openssl_pkey_get_private( $private_key, $private_key_password );
507
508
		if ( false === $pkey ) {
509
			// If we can't open the private key we will create a new private key and certificate.
510
			if ( defined( 'OPENSSL_CIPHER_AES_128_CBC' ) ) {
511
				$cipher = OPENSSL_CIPHER_AES_128_CBC;
512
			} elseif ( defined( 'OPENSSL_CIPHER_3DES' ) ) {
513
				// @link https://www.pronamic.nl/wp-content/uploads/2011/12/iDEAL_Advanced_PHP_EN_V2.2.pdf
514
				$cipher = OPENSSL_CIPHER_3DES;
515
			} else {
516
				// Unable to create private key without cipher.
517
				return;
518
			}
519
520
			$args = array(
521
				'digest_alg'             => 'SHA256',
522
				'private_key_bits'       => 2048,
523
				'private_key_type'       => OPENSSL_KEYTYPE_RSA,
524
				'encrypt_key'            => true,
525
				'encrypt_key_cipher'     => $cipher,
526
				'subjectKeyIdentifier'   => 'hash',
527
				'authorityKeyIdentifier' => 'keyid:always,issuer:always',
528
				'basicConstraints'       => 'CA:true',
529
			);
530
531
			$pkey = openssl_pkey_new( $args );
532
533
			if ( false === $pkey ) {
534
				return;
535
			}
536
537
			// Export key.
538
			$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

538
			$result = openssl_pkey_export( $pkey, /** @scrutinizer ignore-type */ $private_key, $private_key_password, $args );
Loading history...
539
540
			if ( false === $result ) {
541
				return;
542
			}
543
544
			update_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', $private_key );
545
546
			// Delete private certificate since this is no longer valid.
547
			delete_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate' );
548
		}
549
550
		// Certificate.
551
		$private_certificate = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true );
552
		$number_days_valid   = get_post_meta( $post_id, '_pronamic_gateway_number_days_valid', true );
553
554
		if ( empty( $private_certificate ) ) {
555
			$required_keys = array(
556
				'countryName',
557
				'stateOrProvinceName',
558
				'localityName',
559
				'organizationName',
560
				'commonName',
561
				'emailAddress',
562
			);
563
564
			$distinguished_name = array(
565
				'countryName'            => get_post_meta( $post_id, '_pronamic_gateway_country', true ),
566
				'stateOrProvinceName'    => get_post_meta( $post_id, '_pronamic_gateway_state_or_province', true ),
567
				'localityName'           => get_post_meta( $post_id, '_pronamic_gateway_locality', true ),
568
				'organizationName'       => get_post_meta( $post_id, '_pronamic_gateway_organization', true ),
569
				'organizationalUnitName' => get_post_meta( $post_id, '_pronamic_gateway_organization_unit', true ),
570
				'commonName'             => get_post_meta( $post_id, '_pronamic_gateway_organization', true ),
571
				'emailAddress'           => get_post_meta( $post_id, '_pronamic_gateway_email', true ),
572
			);
573
574
			$distinguished_name = array_filter( $distinguished_name );
575
576
			/*
577
			 * Create certificate only if distinguished name contains all required elements
578
			 *
579
			 * @link http://stackoverflow.com/questions/13169588/how-to-check-if-multiple-array-keys-exists
580
			 */
581
			if ( count( array_intersect_key( array_flip( $required_keys ), $distinguished_name ) ) === count( $required_keys ) ) {
582
				$csr = openssl_csr_new( $distinguished_name, $pkey );
583
584
				$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

584
				$cert = openssl_csr_sign( $csr, null, $pkey, /** @scrutinizer ignore-type */ $number_days_valid, $args, time() );
Loading history...
585
586
				openssl_x509_export( $cert, $certificate );
587
588
				update_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', $certificate );
589
			}
590
		}
591
	}
592
593
	public function get_config( $post_id ) {
594
		$mode = get_post_meta( $post_id, '_pronamic_gateway_mode', true );
595
596
		$config = new Config();
597
598
		$config->payment_server_url = $this->aquirer_url;
599
600
		if ( 'test' === $mode && null !== $this->aquirer_test_url ) {
601
			$config->payment_server_url = $this->aquirer_test_url;
602
		}
603
604
		$config->merchant_id = get_post_meta( $post_id, '_pronamic_gateway_ideal_merchant_id', true );
605
		$config->sub_id      = get_post_meta( $post_id, '_pronamic_gateway_ideal_sub_id', true );
606
		$config->purchase_id = get_post_meta( $post_id, '_pronamic_gateway_ideal_purchase_id', true );
0 ignored issues
show
The property purchase_id does not seem to exist on Pronamic\WordPress\Pay\G...\IDealAdvancedV3\Config.
Loading history...
607
608
		$config->private_key          = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', true );
609
		$config->private_key_password = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key_password', true );
610
		$config->private_certificate  = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true );
611
612
		return $config;
613
	}
614
615
	/**
616
	 * Get gateway.
617
	 *
618
	 * @param int $post_id Post ID.
619
	 * @return Gateway
620
	 */
621
	public function get_gateway( $post_id ) {
622
		return new Gateway( $this->get_config( $post_id ) );
623
	}
624
}
625