This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | if ( ! defined( 'ABSPATH' ) ) { |
||
3 | exit; |
||
4 | } |
||
5 | |||
6 | /** |
||
7 | * WC_Stripe_API class. |
||
8 | * |
||
9 | * Communicates with Stripe API. |
||
10 | */ |
||
11 | class WC_Stripe_API { |
||
12 | |||
13 | /** |
||
14 | * Stripe API Endpoint |
||
15 | */ |
||
16 | const ENDPOINT = 'https://api.stripe.com/v1/'; |
||
17 | const STRIPE_API_VERSION = '2019-09-09'; |
||
18 | |||
19 | /** |
||
20 | * Secret API Key. |
||
21 | * @var string |
||
22 | */ |
||
23 | private static $secret_key = ''; |
||
24 | |||
25 | /** |
||
26 | * Set secret API Key. |
||
27 | * @param string $key |
||
0 ignored issues
–
show
|
|||
28 | */ |
||
29 | public static function set_secret_key( $secret_key ) { |
||
30 | self::$secret_key = $secret_key; |
||
31 | } |
||
32 | |||
33 | /** |
||
34 | * Get secret key. |
||
35 | * @return string |
||
36 | */ |
||
37 | public static function get_secret_key() { |
||
38 | if ( ! self::$secret_key ) { |
||
39 | $options = get_option( 'woocommerce_stripe_settings' ); |
||
40 | |||
41 | if ( isset( $options['testmode'], $options['secret_key'], $options['test_secret_key'] ) ) { |
||
42 | self::set_secret_key( 'yes' === $options['testmode'] ? $options['test_secret_key'] : $options['secret_key'] ); |
||
43 | } |
||
44 | } |
||
45 | return self::$secret_key; |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * Generates the user agent we use to pass to API request so |
||
50 | * Stripe can identify our application. |
||
51 | * |
||
52 | * @since 4.0.0 |
||
53 | * @version 4.0.0 |
||
54 | */ |
||
55 | public static function get_user_agent() { |
||
56 | $app_info = array( |
||
57 | 'name' => 'WooCommerce Stripe Gateway', |
||
58 | 'version' => WC_STRIPE_VERSION, |
||
59 | 'url' => 'https://woocommerce.com/products/stripe/', |
||
60 | ); |
||
61 | |||
62 | return array( |
||
63 | 'lang' => 'php', |
||
64 | 'lang_version' => phpversion(), |
||
65 | 'publisher' => 'woocommerce', |
||
66 | 'uname' => php_uname(), |
||
67 | 'application' => $app_info, |
||
68 | ); |
||
69 | } |
||
70 | |||
71 | /** |
||
72 | * Generates the headers to pass to API request. |
||
73 | * |
||
74 | * @since 4.0.0 |
||
75 | * @version 4.0.0 |
||
76 | */ |
||
77 | public static function get_headers() { |
||
78 | $user_agent = self::get_user_agent(); |
||
79 | $app_info = $user_agent['application']; |
||
80 | |||
81 | return apply_filters( |
||
82 | 'woocommerce_stripe_request_headers', |
||
83 | array( |
||
84 | 'Authorization' => 'Basic ' . base64_encode( self::get_secret_key() . ':' ), |
||
85 | 'Stripe-Version' => self::STRIPE_API_VERSION, |
||
86 | 'User-Agent' => $app_info['name'] . '/' . $app_info['version'] . ' (' . $app_info['url'] . ')', |
||
87 | 'X-Stripe-Client-User-Agent' => json_encode( $user_agent ), |
||
88 | ) |
||
89 | ); |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * Send the request to Stripe's API |
||
94 | * |
||
95 | * @since 3.1.0 |
||
96 | * @version 4.0.6 |
||
97 | * @param array $request |
||
98 | * @param string $api |
||
99 | * @param string $method |
||
100 | * @param bool $with_headers To get the response with headers. |
||
101 | * @return stdClass|array |
||
102 | * @throws WC_Stripe_Exception |
||
103 | */ |
||
104 | public static function request( $request, $api = 'charges', $method = 'POST', $with_headers = false ) { |
||
105 | WC_Stripe_Logger::log( "{$api} request: " . print_r( $request, true ) ); |
||
106 | |||
107 | $headers = self::get_headers(); |
||
108 | $idempotency_key = ''; |
||
109 | |||
110 | if ( 'charges' === $api && 'POST' === $method ) { |
||
111 | $customer = ! empty( $request['customer'] ) ? $request['customer'] : ''; |
||
112 | $source = ! empty( $request['source'] ) ? $request['source'] : $customer; |
||
113 | $idempotency_key = apply_filters( 'wc_stripe_idempotency_key', $request['metadata']['order_id'] . '-' . $source, $request ); |
||
114 | |||
115 | $headers['Idempotency-Key'] = $idempotency_key; |
||
116 | } |
||
117 | |||
118 | $response = wp_safe_remote_post( |
||
119 | self::ENDPOINT . $api, |
||
120 | array( |
||
121 | 'method' => $method, |
||
122 | 'headers' => $headers, |
||
123 | 'body' => apply_filters( 'woocommerce_stripe_request_body', $request, $api ), |
||
124 | 'timeout' => 70, |
||
125 | ) |
||
126 | ); |
||
127 | |||
128 | if ( is_wp_error( $response ) || empty( $response['body'] ) ) { |
||
129 | WC_Stripe_Logger::log( |
||
130 | 'Error Response: ' . print_r( $response, true ) . PHP_EOL . PHP_EOL . 'Failed request: ' . print_r( |
||
131 | array( |
||
132 | 'api' => $api, |
||
133 | 'request' => $request, |
||
134 | 'idempotency_key' => $idempotency_key, |
||
135 | ), |
||
136 | true |
||
137 | ) |
||
138 | ); |
||
139 | |||
140 | throw new WC_Stripe_Exception( print_r( $response, true ), __( 'There was a problem connecting to the Stripe API endpoint.', 'woocommerce-gateway-stripe' ) ); |
||
141 | } |
||
142 | |||
143 | if ( $with_headers ) { |
||
144 | return array( |
||
145 | 'headers' => wp_remote_retrieve_headers( $response ), |
||
146 | 'body' => json_decode( $response['body'] ), |
||
147 | ); |
||
148 | } |
||
149 | |||
150 | return json_decode( $response['body'] ); |
||
151 | } |
||
152 | |||
153 | /** |
||
154 | * Retrieve API endpoint. |
||
155 | * |
||
156 | * @since 4.0.0 |
||
157 | * @version 4.0.0 |
||
158 | * @param string $api |
||
159 | */ |
||
160 | public static function retrieve( $api ) { |
||
161 | WC_Stripe_Logger::log( "{$api}" ); |
||
162 | |||
163 | $response = wp_safe_remote_get( |
||
164 | self::ENDPOINT . $api, |
||
165 | array( |
||
166 | 'method' => 'GET', |
||
167 | 'headers' => self::get_headers(), |
||
168 | 'timeout' => 70, |
||
169 | ) |
||
170 | ); |
||
171 | |||
172 | if ( is_wp_error( $response ) || empty( $response['body'] ) ) { |
||
173 | WC_Stripe_Logger::log( 'Error Response: ' . print_r( $response, true ) ); |
||
174 | return new WP_Error( 'stripe_error', __( 'There was a problem connecting to the Stripe API endpoint.', 'woocommerce-gateway-stripe' ) ); |
||
175 | } |
||
176 | |||
177 | return json_decode( $response['body'] ); |
||
178 | } |
||
179 | |||
180 | /** |
||
181 | * Send the request to Stripe's API with level 3 data generated |
||
182 | * from the order. If the request fails due to an error related |
||
183 | * to level3 data, make the request again without it to allow |
||
184 | * the payment to go through. |
||
185 | * |
||
186 | * @since 4.3.2 |
||
187 | * @version 4.3.2 |
||
188 | * |
||
189 | * @param array $request Array with request parameters. |
||
190 | * @param string $api The API path for the request. |
||
191 | * @param array $level3_data The level 3 data for this request. |
||
192 | * @param WC_Order $order The order associated with the payment. |
||
193 | * |
||
194 | * @return stdClass|array The response |
||
195 | */ |
||
196 | public static function request_with_level3_data( $request, $api, $level3_data, $order ) { |
||
197 | // Do not add level3 data it's the array is empty. |
||
198 | if ( empty( $level3_data ) ) { |
||
199 | return self::request( |
||
200 | $request, |
||
201 | $api |
||
202 | ); |
||
203 | } |
||
204 | |||
205 | // If there's a transient indicating that level3 data was not accepted by |
||
206 | // Stripe in the past for this account, do not try to add level3 data. |
||
207 | if ( get_transient( 'wc_stripe_level3_not_allowed' ) ) { |
||
208 | return self::request( |
||
209 | $request, |
||
210 | $api |
||
211 | ); |
||
212 | } |
||
213 | |||
214 | // Add level 3 data to the request. |
||
215 | $request['level3'] = $level3_data; |
||
216 | |||
217 | $result = self::request( |
||
218 | $request, |
||
219 | $api |
||
220 | ); |
||
221 | |||
222 | $is_level3_param_not_allowed = ( |
||
223 | isset( $result->error ) |
||
224 | && isset( $result->error->code ) |
||
225 | && 'parameter_unknown' === $result->error->code |
||
226 | && isset( $result->error->param ) |
||
227 | && 'level3' === $result->error->param |
||
228 | ); |
||
229 | |||
230 | $is_level_3data_incorrect = ( |
||
231 | isset( $result->error ) |
||
232 | && isset( $result->error->type ) |
||
233 | && 'invalid_request_error' === $result->error->type |
||
234 | ); |
||
235 | |||
236 | if ( $is_level3_param_not_allowed ) { |
||
237 | // Set a transient so that future requests do not add level 3 data. |
||
238 | // Transient is set to expire in 3 months, can be manually removed if needed. |
||
239 | set_transient( 'wc_stripe_level3_not_allowed', true, 3 * MONTH_IN_SECONDS ); |
||
240 | } else if ( $is_level_3data_incorrect ) { |
||
241 | // Log the issue so we could debug it. |
||
242 | WC_Stripe_Logger::log( |
||
243 | 'Level3 data sum incorrect: ' . PHP_EOL |
||
244 | . print_r( $result->error->message, true ) . PHP_EOL |
||
245 | . print_r( 'Order line items: ', true ) . PHP_EOL |
||
246 | . print_r( $order->get_items(), true ) . PHP_EOL |
||
247 | . print_r( 'Order shipping amount: ', true ) . PHP_EOL |
||
248 | . print_r( $order->get_shipping_total(), true ) . PHP_EOL |
||
249 | . print_r( 'Order currency: ', true ) . PHP_EOL |
||
250 | . print_r( $order->get_currency(), true ) |
||
251 | ); |
||
252 | } |
||
253 | |||
254 | // Make the request again without level 3 data. |
||
255 | if ( $is_level3_param_not_allowed || $is_level_3data_incorrect ) { |
||
256 | unset( $request['level3'] ); |
||
257 | return WC_Stripe_API::request( |
||
258 | $request, |
||
259 | $api |
||
260 | ); |
||
261 | } |
||
262 | |||
263 | return $result; |
||
264 | } |
||
265 | } |
||
266 |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.
Consider the following example. The parameter
$italy
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was removed, but the annotation was not.