Test Failed
Push — master ( 44b23a...ab385e )
by Remco
04:58 queued 16s
created

src/Integration.php (15 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-2019 Pronamic
11
 * Company: Pronamic
12
 *
13
 * @author  Remco Tolsma
14
 * @version 2.0.4
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
				'dashboard_url'    => null,
30
				'provider'         => null,
31
				'aquirer_url'      => null,
32
				'aquirer_test_url' => null,
33
			)
34
		);
35
36
		$this->id            = $args['id'];
37
		$this->name          = $args['name'];
38
		$this->url           = $args['url'];
39
		$this->product_url   = $args['product_url'];
40
		$this->dashboard_url = $args['dashboard_url'];
41
		$this->provider      = $args['provider'];
42
43
		$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...
44
		$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...
45
46
		// Supported features.
47
		$this->supports = array(
48
			'payment_status_request',
49
		);
50
51
		// Actions.
52
		add_action( 'current_screen', array( $this, 'maybe_download_private_certificate' ) );
53
		add_action( 'current_screen', array( $this, 'maybe_download_private_key' ) );
54
	}
55
56
	public function get_settings_fields() {
57
		$fields = parent::get_settings_fields();
58
59
		/*
60
		 * Private Key and Certificate
61
		 */
62
63
		// Private key and certificate information.
64
		$fields[] = array(
65
			'section'  => 'general',
66
			'title'    => __( 'Private key and certificate', 'pronamic_ideal' ),
67
			'type'     => 'description',
68
			'callback' => array( $this, 'field_security' ),
69
		);
70
71
		// Organization.
72
		$fields[] = array(
73
			'section'  => 'general',
74
			'filter'   => FILTER_SANITIZE_STRING,
75
			'group'    => 'pk-cert',
76
			'meta_key' => '_pronamic_gateway_organization',
77
			'title'    => __( 'Organization', 'pronamic_ideal' ),
78
			'type'     => 'text',
79
			'tooltip'  => __( 'Organization name, e.g. Pronamic', 'pronamic_ideal' ),
80
		);
81
82
		// Organization Unit.
83
		$fields[] = array(
84
			'section'  => 'general',
85
			'filter'   => FILTER_SANITIZE_STRING,
86
			'group'    => 'pk-cert',
87
			'meta_key' => '_pronamic_gateway_organization_unit',
88
			'title'    => __( 'Organization Unit', 'pronamic_ideal' ),
89
			'type'     => 'text',
90
			'tooltip'  => __( 'Organization unit, e.g. Administration', 'pronamic_ideal' ),
91
		);
92
93
		// Locality.
94
		$fields[] = array(
95
			'section'  => 'general',
96
			'filter'   => FILTER_SANITIZE_STRING,
97
			'group'    => 'pk-cert',
98
			'meta_key' => '_pronamic_gateway_locality',
99
			'title'    => __( 'City', 'pronamic_ideal' ),
100
			'type'     => 'text',
101
			'tooltip'  => __( 'City, e.g. Amsterdam', 'pronamic_ideal' ),
102
		);
103
104
		// State or Province.
105
		$fields[] = array(
106
			'section'  => 'general',
107
			'filter'   => FILTER_SANITIZE_STRING,
108
			'group'    => 'pk-cert',
109
			'meta_key' => '_pronamic_gateway_state_or_province',
110
			'title'    => __( 'State / province', 'pronamic_ideal' ),
111
			'type'     => 'text',
112
			'tooltip'  => __( 'State or province, e.g. Friesland', 'pronamic_ideal' ),
113
		);
114
115
		// Country.
116
		$locale = explode( '_', get_locale() );
117
118
		$locale = array_pop( $locale );
119
120
		$fields[] = array(
121
			'section'     => 'general',
122
			'filter'      => FILTER_SANITIZE_STRING,
123
			'group'       => 'pk-cert',
124
			'meta_key'    => '_pronamic_gateway_country',
125
			'title'       => __( 'Country', 'pronamic_ideal' ),
126
			'type'        => 'text',
127
			'tooltip'     => sprintf(
128
				'%s %s (ISO-3166-1 alpha-2)',
129
				__( '2 letter country code, e.g.', 'pronamic_ideal' ),
130
				strtoupper( $locale )
131
			),
132
			'size'        => 2,
133
			'description' => sprintf(
134
				'%s %s',
135
				__( '2 letter country code, e.g.', 'pronamic_ideal' ),
136
				strtoupper( $locale )
137
			),
138
		);
139
140
		// Email Address.
141
		$fields[] = array(
142
			'section'  => 'general',
143
			'filter'   => FILTER_SANITIZE_STRING,
144
			'group'    => 'pk-cert',
145
			'meta_key' => '_pronamic_gateway_email',
146
			'title'    => __( 'E-mail address', 'pronamic_ideal' ),
147
			'tooltip'  => sprintf(
148
				/* translators: %s: admin email */
149
				__( 'E-mail address, e.g. %s', 'pronamic_ideal' ),
150
				get_option( 'admin_email' )
0 ignored issues
show
It seems like get_option('admin_email') can also be of type false; however, parameter $args of sprintf() 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

150
				/** @scrutinizer ignore-type */ get_option( 'admin_email' )
Loading history...
151
			),
152
			'type'     => 'text',
153
		);
154
155
		// Number Days Valid.
156
		$fields[] = array(
157
			'section'  => 'general',
158
			'filter'   => FILTER_SANITIZE_NUMBER_INT,
159
			'group'    => 'pk-cert',
160
			'meta_key' => '_pronamic_gateway_number_days_valid',
161
			'title'    => __( 'Number Days Valid', 'pronamic_ideal' ),
162
			'type'     => 'text',
163
			'default'  => 1825,
164
			'tooltip'  => __( 'Number of days the generated certificate will be valid for, e.g. 1825 days for the maximum duration of 5 years.', 'pronamic_ideal' ),
165
		);
166
167
		// Private Key Password.
168
		$fields[] = array(
169
			'section'  => 'general',
170
			'filter'   => FILTER_SANITIZE_STRING,
171
			'group'    => 'pk-cert',
172
			'meta_key' => '_pronamic_gateway_ideal_private_key_password',
173
			'title'    => __( 'Private Key Password', 'pronamic_ideal' ),
174
			'type'     => 'text',
175
			'classes'  => array( 'regular-text', 'code' ),
176
			'default'  => wp_generate_password(),
177
			'tooltip'  => __( 'A random password which will be used for the generation of the private key and certificate.', 'pronamic_ideal' ),
178
		);
179
180
		// Private Key.
181
		$fields[] = array(
182
			'section'  => 'general',
183
			'filter'   => FILTER_SANITIZE_STRING,
184
			'group'    => 'pk-cert',
185
			'meta_key' => '_pronamic_gateway_ideal_private_key',
186
			'title'    => __( 'Private Key', 'pronamic_ideal' ),
187
			'type'     => 'textarea',
188
			'callback' => array( $this, 'field_private_key' ),
189
			'classes'  => array( 'code' ),
190
			'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' ),
191
		);
192
193
		// Private Certificate.
194
		$fields[] = array(
195
			'section'  => 'general',
196
			'filter'   => FILTER_SANITIZE_STRING,
197
			'group'    => 'pk-cert',
198
			'meta_key' => '_pronamic_gateway_ideal_private_certificate',
199
			'title'    => __( 'Private Certificate', 'pronamic_ideal' ),
200
			'type'     => 'textarea',
201
			'callback' => array( $this, 'field_private_certificate' ),
202
			'classes'  => array( 'code' ),
203
			'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' ),
204
		);
205
206
		// Return.
207
		return $fields;
208
	}
209
210
	/**
211
	 * Field security
212
	 *
213
	 * @param array $field Field.
214
	 */
215
	public function field_security( $field ) {
216
		$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

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

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

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

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

435
			header( 'Content-Type: application/x-x509-ca-cert; charset=' . /** @scrutinizer ignore-type */ get_option( 'blog_charset' ), true );
Loading history...
436
437
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
438
			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

438
			echo /** @scrutinizer ignore-type */ get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true );
Loading history...
439
440
			exit;
441
		}
442
	}
443
444
	/**
445
	 * Download private key
446
	 */
447
	public function maybe_download_private_key() {
448
		if ( filter_has_var( INPUT_POST, 'download_private_key' ) ) {
449
			$post_id = filter_input( INPUT_POST, 'post_ID', FILTER_SANITIZE_STRING );
450
451
			$filename = sprintf( 'ideal-private-key-%s.key', $post_id );
452
453
			header( 'Content-Description: File Transfer' );
454
			header( 'Content-Disposition: attachment; filename=' . $filename );
455
			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

455
			header( 'Content-Type: application/pgp-keys; charset=' . /** @scrutinizer ignore-type */ get_option( 'blog_charset' ), true );
Loading history...
456
457
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
458
			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

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

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

579
				$cert = openssl_csr_sign( $csr, null, $pkey, /** @scrutinizer ignore-type */ $number_days_valid, $args, time() );
Loading history...
580
581
				openssl_x509_export( $cert, $certificate );
582
583
				update_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', $certificate );
584
			}
585
		}
586
	}
587
588
	public function get_config( $post_id ) {
589
		$mode = get_post_meta( $post_id, '_pronamic_gateway_mode', true );
590
591
		$config = new Config();
592
593
		$config->payment_server_url = $this->aquirer_url;
594
595
		if ( 'test' === $mode && null !== $this->aquirer_test_url ) {
596
			$config->payment_server_url = $this->aquirer_test_url;
597
		}
598
599
		$config->merchant_id = get_post_meta( $post_id, '_pronamic_gateway_ideal_merchant_id', true );
600
		$config->sub_id      = get_post_meta( $post_id, '_pronamic_gateway_ideal_sub_id', true );
601
		$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...
602
603
		$config->private_key          = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', true );
604
		$config->private_key_password = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key_password', true );
605
		$config->private_certificate  = get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true );
606
607
		return $config;
608
	}
609
610
	/**
611
	 * Get gateway.
612
	 *
613
	 * @param int $post_id Post ID.
614
	 * @return Gateway
615
	 */
616
	public function get_gateway( $post_id ) {
617
		return new Gateway( $this->get_config( $post_id ) );
618
	}
619
}
620