Completed
Pull Request — master (#1357)
by
unknown
01:55
created

WC_Stripe_Apple_Pay_Registration   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 290
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 290
rs 9.84
c 0
b 0
f 0
wmc 32
lcom 1
cbo 1

12 Methods

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