Completed
Pull Request — master (#1357)
by
unknown
02:00
created

WC_Stripe_Apple_Pay_Registration::verify_domain()   A

Complexity

Conditions 3
Paths 6

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

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