blob: 8b6e086704a707bddf09909037392626ac8c536f [file] [log] [blame]
swissChilif0cbdc32023-01-05 17:21:38 -05001<?php
2/**
3 * Class WC_REST_Stripe_Account_Keys_Controller
4 */
5
6defined( 'ABSPATH' ) || exit;
7
8/**
9 * REST controller for saving Stripe's test/live account keys.
10 *
11 * This includes Live Publishable Key, Live Secret Key, Webhook Secret.
12 *
13 * @since 5.6.0
14 */
15class WC_REST_Stripe_Account_Keys_Controller extends WC_Stripe_REST_Base_Controller {
16 const STRIPE_GATEWAY_SETTINGS_OPTION_NAME = 'woocommerce_stripe_settings';
17
18 /**
19 * Endpoint path.
20 *
21 * @var string
22 */
23 protected $rest_base = 'wc_stripe/account_keys';
24
25 /**
26 * The instance of the Stripe account.
27 *
28 * @var WC_Stripe_Account
29 */
30 private $account;
31
32 /**
33 * Constructor.
34 *
35 * @param WC_Stripe_Account $account The instance of the Stripe account.
36 */
37 public function __construct( WC_Stripe_Account $account ) {
38 $this->account = $account;
39 }
40
41 /**
42 * Configure REST API routes.
43 */
44 public function register_routes() {
45 register_rest_route(
46 $this->namespace,
47 '/' . $this->rest_base,
48 [
49 'methods' => WP_REST_Server::READABLE,
50 'callback' => [ $this, 'get_account_keys' ],
51 'permission_callback' => [ $this, 'check_permission' ],
52 ]
53 );
54 register_rest_route(
55 $this->namespace,
56 '/' . $this->rest_base,
57 [
58 'methods' => WP_REST_Server::EDITABLE,
59 'callback' => [ $this, 'set_account_keys' ],
60 'permission_callback' => [ $this, 'check_permission' ],
61 'args' => [
62 'publishable_key' => [
63 'description' => __( 'Your Stripe API Publishable key, obtained from your Stripe dashboard.', 'woocommerce-gateway-stripe' ),
64 'type' => 'string',
65 'validate_callback' => [ $this, 'validate_publishable_key' ],
66 ],
67 'secret_key' => [
68 'description' => __( 'Your Stripe API Secret, obtained from your Stripe dashboard.', 'woocommerce-gateway-stripe' ),
69 'type' => 'string',
70 'validate_callback' => [ $this, 'validate_secret_key' ],
71 ],
72 'webhook_secret' => [
73 'description' => __( 'Your Stripe webhook endpoint URL, obtained from your Stripe dashboard.', 'woocommerce-gateway-stripe' ),
74 'type' => 'string',
75 'validate_callback' => 'rest_validate_request_arg',
76 ],
77 'test_publishable_key' => [
78 'description' => __( 'Your Stripe testing API Publishable key, obtained from your Stripe dashboard.', 'woocommerce-gateway-stripe' ),
79 'type' => 'string',
80 'validate_callback' => [ $this, 'validate_test_publishable_key' ],
81 ],
82 'test_secret_key' => [
83 'description' => __( 'Your Stripe testing API Secret, obtained from your Stripe dashboard.', 'woocommerce-gateway-stripe' ),
84 'type' => 'string',
85 'validate_callback' => [ $this, 'validate_test_secret_key' ],
86 ],
87 'test_webhook_secret' => [
88 'description' => __( 'Your Stripe testing webhook endpoint URL, obtained from your Stripe dashboard.', 'woocommerce-gateway-stripe' ),
89 'type' => 'string',
90 'validate_callback' => 'rest_validate_request_arg',
91 ],
92 ],
93 ]
94 );
95 }
96
97 /**
98 * Retrieve flag status.
99 *
100 * @return WP_REST_Response
101 */
102 public function get_account_keys() {
103 $allowed_params = [ 'publishable_key', 'secret_key', 'webhook_secret', 'test_publishable_key', 'test_secret_key', 'test_webhook_secret' ];
104 $stripe_settings = get_option( self::STRIPE_GATEWAY_SETTINGS_OPTION_NAME, [] );
105 // Filter only the fields we want to return
106 $account_keys = array_intersect_key( $stripe_settings, array_flip( $allowed_params ) );
107
108 return new WP_REST_Response( $account_keys );
109 }
110
111 /**
112 * Validate stripe publishable keys and secrets. Allow empty string to erase key.
113 * Also validates against explicit key prefixes based on live/test environment.
114 *
115 * @param mixed $value
116 * @param WP_REST_Request $request
117 * @param string $param
118 * @param array $validate_options
119 * @return true|WP_Error
120 */
121 private function validate_stripe_param( $param, $request, $key, $validate_options ) {
122 if ( empty( $param ) ) {
123 return true;
124 }
125 $result = rest_validate_request_arg( $param, $request, $key );
126 if ( ! empty( $result ) && ! preg_match( $validate_options['regex'], $param ) ) {
127 return new WP_Error( 400, $validate_options['error_message'] );
128 }
129 return true;
130 }
131
132 public function validate_publishable_key( $param, $request, $key ) {
133 return $this->validate_stripe_param(
134 $param,
135 $request,
136 $key,
137 [
138 'regex' => '/^pk_live_/',
139 'error_message' => __( 'The "Live Publishable Key" should start with "pk_live", enter the correct key.', 'woocommerce-gateway-stripe' ),
140 ]
141 );
142 }
143
144 public function validate_secret_key( $param, $request, $key ) {
145 return $this->validate_stripe_param(
146 $param,
147 $request,
148 $key,
149 [
150 'regex' => '/^[rs]k_live_/',
151 'error_message' => __( 'The "Live Secret Key" should start with "sk_live" or "rk_live", enter the correct key.', 'woocommerce-gateway-stripe' ),
152 ]
153 );
154 }
155
156 public function validate_test_publishable_key( $param, $request, $key ) {
157 return $this->validate_stripe_param(
158 $param,
159 $request,
160 $key,
161 [
162 'regex' => '/^pk_test_/',
163 'error_message' => __( 'The "Test Publishable Key" should start with "pk_test", enter the correct key.', 'woocommerce-gateway-stripe' ),
164 ]
165 );
166 }
167
168 public function validate_test_secret_key( $param, $request, $key ) {
169 return $this->validate_stripe_param(
170 $param,
171 $request,
172 $key,
173 [
174 'regex' => '/^[rs]k_test_/',
175 'error_message' => __( 'The "Test Secret Key" should start with "sk_test" or "rk_test", enter the correct key.', 'woocommerce-gateway-stripe' ),
176 ]
177 );
178 }
179
180 /**
181 * Update the data.
182 *
183 * @param WP_REST_Request $request Full data about the request.
184 */
185 public function set_account_keys( WP_REST_Request $request ) {
186 $publishable_key = $request->get_param( 'publishable_key' );
187 $secret_key = $request->get_param( 'secret_key' );
188 $webhook_secret = $request->get_param( 'webhook_secret' );
189 $test_publishable_key = $request->get_param( 'test_publishable_key' );
190 $test_secret_key = $request->get_param( 'test_secret_key' );
191 $test_webhook_secret = $request->get_param( 'test_webhook_secret' );
192
193 $settings = get_option( self::STRIPE_GATEWAY_SETTINGS_OPTION_NAME, [] );
194
195 // If all keys were empty, then is a new account; we need to set the test/live mode.
196 $new_account = ! trim( $settings['publishable_key'] )
197 && ! trim( $settings['secret_key'] )
198 && ! trim( $settings['test_publishable_key'] )
199 && ! trim( $settings['test_secret_key'] );
200 // If all new keys are empty, then account is being disconnected. We should disable the payment gateway.
201 $is_deleting_account = ! trim( $publishable_key )
202 && ! trim( $secret_key )
203 && ! trim( $test_publishable_key )
204 && ! trim( $test_secret_key );
205
206 $settings['publishable_key'] = is_null( $publishable_key ) ? $settings['publishable_key'] : $publishable_key;
207 $settings['secret_key'] = is_null( $secret_key ) ? $settings['secret_key'] : $secret_key;
208 $settings['webhook_secret'] = is_null( $webhook_secret ) ? $settings['webhook_secret'] : $webhook_secret;
209 $settings['test_publishable_key'] = is_null( $test_publishable_key ) ? $settings['test_publishable_key'] : $test_publishable_key;
210 $settings['test_secret_key'] = is_null( $test_secret_key ) ? $settings['test_secret_key'] : $test_secret_key;
211 $settings['test_webhook_secret'] = is_null( $test_webhook_secret ) ? $settings['test_webhook_secret'] : $test_webhook_secret;
212
213 if ( $new_account ) {
214 $settings['enabled'] = 'yes';
215 if ( trim( $settings['publishable_key'] ) && trim( $settings['secret_key'] ) ) {
216 $settings['testmode'] = 'no';
217 } elseif ( trim( $settings['test_publishable_key'] ) && trim( $settings['test_secret_key'] ) ) {
218 $settings['testmode'] = 'yes';
219 }
220 } elseif ( $is_deleting_account ) {
221 $settings['enabled'] = 'no';
222 }
223
224 update_option( self::STRIPE_GATEWAY_SETTINGS_OPTION_NAME, $settings );
225 $this->account->clear_cache();
226
227 // Gives an instant reply if the connection was succesful or not + rebuild the cache for the next request
228 $account = $this->account->get_cached_account_data();
229
230 return new WP_REST_Response( $account, 200 );
231 }
232}