WC_Stripe_Apple_Pay_Registration   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 307
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 0
loc 307
rs 9.76
c 0
b 0
f 0
wmc 33
lcom 1
cbo 2

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 1
A get_option() 0 11 3
A is_enabled() 0 6 2
A get_secret_key() 0 4 2
A add_domain_association_rewrite_rule() 0 6 1
A whitelist_domain_association_query_param() 0 4 1
A parse_domain_association_request() 0 13 3
A make_domain_registration_request() 0 38 4
A register_domain_with_apple() 0 25 2
A verify_domain_if_configured() 0 16 3
A verify_domain_on_new_settings() 0 3 1
A verify_domain_on_updated_settings() 0 12 3
B admin_notices() 0 46 7
1
<?php
2
/**
3
 * Stripe Apple Pay Registration Class.
4
 *
5
 * @since 4.0.6
6
 */
7
8
if ( ! defined( 'ABSPATH' ) ) {
9
	exit;
10
}
11
12
class WC_Stripe_Apple_Pay_Registration {
13
	/**
14
	 * Enabled.
15
	 *
16
	 * @var
17
	 */
18
	public $stripe_settings;
19
20
	/**
21
	 * Apple Pay Domain Set.
22
	 *
23
	 * @var bool
24
	 */
25
	public $apple_pay_domain_set;
26
27
	/**
28
	 * Stores Apple Pay domain verification issues.
29
	 *
30
	 * @var string
31
	 */
32
	public $apple_pay_verify_notice;
33
34
	public function __construct() {
35
		add_action( 'init', array( $this, 'add_domain_association_rewrite_rule' ) );
36
		add_filter( 'query_vars', array( $this, 'whitelist_domain_association_query_param' ), 10, 1 );
37
		add_action( 'parse_request', array( $this, 'parse_domain_association_request' ), 10, 1 );
38
39
		add_action( 'woocommerce_stripe_updated', array( $this, 'verify_domain_if_configured' ) );
40
		add_action( 'add_option_woocommerce_stripe_settings', array( $this, 'verify_domain_on_new_settings' ), 10, 2 );
41
		add_action( 'update_option_woocommerce_stripe_settings', array( $this, 'verify_domain_on_updated_settings' ), 10, 2 );
42
		add_action( 'admin_notices', array( $this, 'admin_notices' ) );
43
44
		$this->stripe_settings         = get_option( 'woocommerce_stripe_settings', array() );
45
		$this->apple_pay_domain_set    = 'yes' === $this->get_option( 'apple_pay_domain_set', 'no' );
46
		$this->apple_pay_verify_notice = '';
47
	}
48
49
	/**
50
	 * Gets the Stripe settings.
51
	 *
52
	 * @since 4.0.6
53
	 * @param string $setting
54
	 * @param string default
55
	 * @return string $setting_value
56
	 */
57
	public function get_option( $setting = '', $default = '' ) {
58
		if ( empty( $this->stripe_settings ) ) {
59
			return $default;
60
		}
61
62
		if ( ! empty( $this->stripe_settings[ $setting ] ) ) {
63
			return $this->stripe_settings[ $setting ];
64
		}
65
66
		return $default;
67
	}
68
69
	/**
70
	 * Whether the gateway and Payment Request Button (prerequisites for Apple Pay) are enabled.
71
	 *
72
	 * @since 4.5.4
73
	 * @return string Whether Apple Pay required settings are enabled.
74
	 */
75
	private function is_enabled() {
76
		$stripe_enabled                 = 'yes' === $this->get_option( 'enabled', 'no' );
77
		$payment_request_button_enabled = 'yes' === $this->get_option( 'payment_request', 'yes' );
78
79
		return $stripe_enabled && $payment_request_button_enabled;
80
	}
81
82
	/**
83
	 * Gets the Stripe secret key for the current mode.
84
	 *
85
	 * @since 4.5.3
86
	 * @return string Secret key.
87
	 */
88
	private function get_secret_key() {
89
		$testmode = 'yes' === $this->get_option( 'testmode', 'no' );
90
		return $testmode ? $this->get_option( 'test_secret_key' ) : $this->get_option( 'secret_key' );
91
	}
92
93
	/**
94
	 * Adds a rewrite rule for serving the domain association file from the proper location.
95
	 */
96
	public function add_domain_association_rewrite_rule() {
97
		$regex    = '^\.well-known\/apple-developer-merchantid-domain-association$';
98
		$redirect = 'index.php?apple-developer-merchantid-domain-association=1';
99
100
		add_rewrite_rule( $regex, $redirect, 'top' );
101
	}
102
103
	/**
104
	 * Add to the list of publicly allowed query variables.
105
	 *
106
	 * @param  array $query_vars - provided public query vars.
107
	 * @return array Updated public query vars.
108
	 */
109
	public function whitelist_domain_association_query_param( $query_vars ) {
110
		$query_vars[] = 'apple-developer-merchantid-domain-association';
111
		return $query_vars;
112
	}
113
114
	/**
115
	 * Serve domain association file when proper query param is provided.
116
	 *
117
	 * @param WP WordPress environment object.
118
	 */
119
	public function parse_domain_association_request( $wp ) {
120
		if (
121
			! isset( $wp->query_vars['apple-developer-merchantid-domain-association'] ) ||
122
			'1' !== $wp->query_vars['apple-developer-merchantid-domain-association']
123
		) {
124
			return;
125
		}
126
127
		$path = WC_STRIPE_PLUGIN_PATH . '/apple-developer-merchantid-domain-association';
128
		header( 'Content-Type: application/octet-stream' );
129
		echo esc_html( file_get_contents( $path ) );
130
		exit;
131
	}
132
133
	/**
134
	 * Makes request to register the domain with Stripe/Apple Pay.
135
	 *
136
	 * @since 3.1.0
137
	 * @version 4.5.4
138
	 * @param string $secret_key
139
	 */
140
	private function make_domain_registration_request( $secret_key ) {
141
		if ( empty( $secret_key ) ) {
142
			throw new Exception( __( 'Unable to verify domain - missing secret key.', 'woocommerce-gateway-stripe' ) );
143
		}
144
145
		$endpoint = 'https://api.stripe.com/v1/apple_pay/domains';
146
147
		$data = array(
148
			'domain_name' => $_SERVER['HTTP_HOST'],
149
		);
150
151
		$headers = array(
152
			'User-Agent'    => 'WooCommerce Stripe Apple Pay',
153
			'Authorization' => 'Bearer ' . $secret_key,
154
		);
155
156
		$response = wp_remote_post(
157
			$endpoint,
158
			array(
159
				'headers' => $headers,
160
				'body'    => http_build_query( $data ),
161
			)
162
		);
163
164
		if ( is_wp_error( $response ) ) {
165
			/* translators: error message */
166
			throw new Exception( sprintf( __( 'Unable to verify domain - %s', 'woocommerce-gateway-stripe' ), $response->get_error_message() ) );
167
		}
168
169
		if ( 200 !== $response['response']['code'] ) {
170
			$parsed_response = json_decode( $response['body'] );
171
172
			$this->apple_pay_verify_notice = $parsed_response->error->message;
173
174
			/* translators: error message */
175
			throw new Exception( sprintf( __( 'Unable to verify domain - %s', 'woocommerce-gateway-stripe' ), $parsed_response->error->message ) );
176
		}
177
	}
178
179
	/**
180
	 * Processes the Apple Pay domain verification.
181
	 *
182
	 * @since 3.1.0
183
	 * @version 4.5.4
184
	 *
185
	 * @param string $secret_key
186
	 *
187
	 * @return bool Whether domain verification succeeded.
188
	 */
189
	public function register_domain_with_apple( $secret_key ) {
190
		try {
191
			$this->make_domain_registration_request( $secret_key );
192
193
			// No errors to this point, verification success!
194
			$this->stripe_settings['apple_pay_domain_set'] = 'yes';
195
			$this->apple_pay_domain_set                    = true;
196
197
			update_option( 'woocommerce_stripe_settings', $this->stripe_settings );
198
199
			WC_Stripe_Logger::log( 'Your domain has been verified with Apple Pay!' );
200
201
			return true;
202
203
		} catch ( Exception $e ) {
204
			$this->stripe_settings['apple_pay_domain_set'] = 'no';
205
			$this->apple_pay_domain_set                    = false;
206
207
			update_option( 'woocommerce_stripe_settings', $this->stripe_settings );
208
209
			WC_Stripe_Logger::log( 'Error: ' . $e->getMessage() );
210
211
			return false;
212
		}
213
	}
214
215
	/**
216
	 * Process the Apple Pay domain verification if proper settings are configured.
217
	 *
218
	 * @since 4.5.4
219
	 * @version 4.5.4
220
	 */
221
	public function verify_domain_if_configured() {
222
		$secret_key = $this->get_secret_key();
223
224
		if ( ! $this->is_enabled() || empty( $secret_key ) ) {
225
			return;
226
		}
227
228
		// Ensure that domain association file will be served.
229
		flush_rewrite_rules();
230
231
		// Register the domain with Apple Pay.
232
		$verification_complete = $this->register_domain_with_apple( $secret_key );
233
234
		// Show/hide notes if necessary.
235
		WC_Stripe_Inbox_Notes::notify_on_apple_pay_domain_verification( $verification_complete );
236
	}
237
238
	/**
239
	 * Conditionally process the Apple Pay domain verification after settings are initially set.
240
	 *
241
	 * @since 4.5.4
242
	 * @version 4.5.4
243
	 */
244
	public function verify_domain_on_new_settings( $option, $settings ) {
245
		$this->verify_domain_on_updated_settings( array(), $settings );
246
	}
247
248
	/**
249
	 * Conditionally process the Apple Pay domain verification after settings are updated.
250
	 *
251
	 * @since 4.5.3
252
	 * @version 4.5.4
253
	 */
254
	public function verify_domain_on_updated_settings( $prev_settings, $settings ) {
255
		// Grab previous state and then update cached settings.
256
		$this->stripe_settings = $prev_settings;
257
		$prev_secret_key       = $this->get_secret_key();
258
		$prev_is_enabled       = $this->is_enabled();
259
		$this->stripe_settings = $settings;
260
261
		// If Stripe or Payment Request Button wasn't enabled (or secret key was different) then might need to verify now.
262
		if ( ! $prev_is_enabled || ( $this->get_secret_key() !== $prev_secret_key ) ) {
263
			$this->verify_domain_if_configured();
264
		}
265
	}
266
267
	/**
268
	 * Display any admin notices to the user.
269
	 *
270
	 * @since 4.0.6
271
	 */
272
	public function admin_notices() {
273
		if ( ! $this->is_enabled() ) {
274
			return;
275
		}
276
277
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
278
			return;
279
		}
280
281
		$empty_notice = empty( $this->apple_pay_verify_notice );
282
		if ( $empty_notice && ( $this->apple_pay_domain_set || empty( $this->secret_key ) ) ) {
0 ignored issues
show
Bug introduced by
The property secret_key does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
283
			return;
284
		}
285
286
		/**
287
		 * Apple pay is enabled by default and domain verification initializes
288
		 * when setting screen is displayed. So if domain verification is not set,
289
		 * something went wrong so lets notify user.
290
		 */
291
		$allowed_html                      = array(
292
			'a' => array(
293
				'href'  => array(),
294
				'title' => array(),
295
			),
296
		);
297
		$verification_failed_without_error = __( 'Apple Pay domain verification failed.', 'woocommerce-gateway-stripe' );
298
		$verification_failed_with_error    = __( 'Apple Pay domain verification failed with the following error:', 'woocommerce-gateway-stripe' );
299
		$check_log_text                    = sprintf(
300
			/* translators: 1) HTML anchor open tag 2) HTML anchor closing tag */
301
			esc_html__( 'Please check the %1$slogs%2$s for more details on this issue. Logging must be enabled to see recorded logs.', 'woocommerce-gateway-stripe' ),
302
			'<a href="' . admin_url( 'admin.php?page=wc-status&tab=logs' ) . '">',
303
			'</a>'
304
		);
305
306
		?>
307
		<div class="error stripe-apple-pay-message">
308
			<?php if ( $empty_notice ) : ?>
309
				<p><?php echo esc_html( $verification_failed_without_error ); ?></p>
310
			<?php else : ?>
311
				<p><?php echo esc_html( $verification_failed_with_error ); ?></p>
312
				<p><i><?php echo wp_kses( make_clickable( esc_html( $this->apple_pay_verify_notice ) ), $allowed_html ); ?></i></p>
313
			<?php endif; ?>
314
			<p><?php echo $check_log_text; ?></p>
315
		</div>
316
		<?php
317
	}
318
}
319
320
new WC_Stripe_Apple_Pay_Registration();
321