| @@ -1,8 +1,9 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | 3 | namespace Yoast\WP\SEO\Config; |
| 4 | 4 | |
| 5 | +use Exception; | |
| 5 | 6 | use UnexpectedValueException; |
| 6 | 7 | use YoastSEO_Vendor\GuzzleHttp\Exception\BadResponseException; |
| 7 | 8 | use YoastSEO_Vendor\League\OAuth2\Client\Provider\Exception\IdentityProviderException; |
| 8 | 9 | use YoastSEO_Vendor\League\OAuth2\Client\Provider\GenericProvider; |
| @@ -15,17 +16,20 @@ | ||
| 15 | 16 | /** |
| 16 | 17 | * Class Wincher_PKCE_Provider |
| 17 | 18 | * |
| 18 | 19 | * @codeCoverageIgnore Ignoring as this class is purely a temporary wrapper until https://github.com/thephpleague/oauth2-client/pull/901 is merged. |
| 19 | - * @codingStandardsIgnoreStart | |
| 20 | + * | |
| 21 | + * @phpcs:disable WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase -- This class extends an external class. | |
| 22 | + * @phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- This class extends an external class. | |
| 20 | 23 | */ |
| 21 | 24 | class Wincher_PKCE_Provider extends GenericProvider { |
| 25 | + | |
| 22 | 26 | use BearerAuthorizationTrait; |
| 23 | 27 | |
| 24 | 28 | /** |
| 25 | 29 | * The method to use. |
| 26 | 30 | * |
| 27 | - * @var string | |
| 31 | + * @var string|null | |
| 28 | 32 | */ |
| 29 | 33 | protected $pkceMethod = null; |
| 30 | 34 | |
| 31 | 35 | /** |
| @@ -39,13 +43,13 @@ | ||
| 39 | 43 | * Set the value of the pkceCode parameter. |
| 40 | 44 | * |
| 41 | 45 | * When using PKCE this should be set before requesting an access token. |
| 42 | 46 | * |
| 43 | - * @param string $pkceCode | |
| 47 | + * @param string $pkce_code The value for the pkceCode. | |
| 44 | 48 | * @return self |
| 45 | 49 | */ |
| 46 | - public function setPkceCode( $pkceCode ) { | |
| 47 | - $this->pkceCode = $pkceCode; | |
| 50 | + public function setPkceCode( $pkce_code ) { | |
| 51 | + $this->pkceCode = $pkce_code; | |
| 48 | 52 | return $this; |
| 49 | 53 | } |
| 50 | 54 | |
| 51 | 55 | /** |
| @@ -67,19 +71,20 @@ | ||
| 67 | 71 | * @param int $length Length of the random string to be generated. |
| 68 | 72 | * |
| 69 | 73 | * @return string |
| 70 | 74 | * |
| 71 | - * @throws \Exception Throws exception if an invalid value is passed to random_bytes. | |
| 75 | + * @throws Exception Throws exception if an invalid value is passed to random_bytes. | |
| 72 | 76 | */ |
| 73 | 77 | protected function getRandomPkceCode( $length = 64 ) { |
| 74 | - return substr( | |
| 75 | - strtr( | |
| 76 | - base64_encode( random_bytes( $length ) ), | |
| 78 | + return \substr( | |
| 79 | + \strtr( | |
| 80 | + // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode | |
| 81 | + \base64_encode( \random_bytes( $length ) ), | |
| 77 | 82 | '+/', |
| 78 | - '-_' | |
| 83 | + '-_', | |
| 79 | 84 | ), |
| 80 | 85 | 0, |
| 81 | - $length | |
| 86 | + $length, | |
| 82 | 87 | ); |
| 83 | 88 | } |
| 84 | 89 | |
| 85 | 90 | /** |
| @@ -93,14 +98,14 @@ | ||
| 93 | 98 | |
| 94 | 99 | /** |
| 95 | 100 | * Returns authorization parameters based on provided options. |
| 96 | 101 | * |
| 97 | - * @param array $options The options to use in the authorization parameters. | |
| 102 | + * @param array $options The options to use in the authorization parameters. | |
| 98 | 103 | * |
| 99 | 104 | * @return array The authorization parameters |
| 100 | 105 | * |
| 101 | 106 | * @throws InvalidArgumentException Throws exception if an invalid PCKE method is passed in the options. |
| 102 | - * @throws \Exception When something goes wrong with generating the PKCE code. | |
| 107 | + * @throws Exception When something goes wrong with generating the PKCE code. | |
| 103 | 108 | */ |
| 104 | 109 | protected function getAuthorizationParameters( array $options ) { |
| 105 | 110 | if ( empty( $options['state'] ) ) { |
| 106 | 111 | $options['state'] = $this->getRandomState(); |
| @@ -113,11 +118,11 @@ | ||
| 113 | 118 | $options += [ |
| 114 | 119 | 'response_type' => 'code', |
| 115 | 120 | ]; |
| 116 | 121 | |
| 117 | - if ( is_array( $options['scope'] ) ) { | |
| 122 | + if ( \is_array( $options['scope'] ) ) { | |
| 118 | 123 | $separator = $this->getScopeSeparator(); |
| 119 | - $options['scope'] = implode( $separator, $options['scope'] ); | |
| 124 | + $options['scope'] = \implode( $separator, $options['scope'] ); | |
| 120 | 125 | } |
| 121 | 126 | |
| 122 | 127 | // Store the state as it may need to be accessed later on. |
| 123 | 128 | $this->state = $options['state']; |
| @@ -125,15 +130,16 @@ | ||
| 125 | 130 | $pkce_method = $this->getPkceMethod(); |
| 126 | 131 | if ( ! empty( $pkce_method ) ) { |
| 127 | 132 | $this->pkceCode = $this->getRandomPkceCode(); |
| 128 | 133 | if ( $pkce_method === 'S256' ) { |
| 129 | - $options['code_challenge'] = trim( | |
| 130 | - strtr( | |
| 131 | - base64_encode( hash( 'sha256', $this->pkceCode, true ) ), | |
| 134 | + $options['code_challenge'] = \trim( | |
| 135 | + \strtr( | |
| 136 | + // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode | |
| 137 | + \base64_encode( \hash( 'sha256', $this->pkceCode, true ) ), | |
| 132 | 138 | '+/', |
| 133 | - '-_' | |
| 139 | + '-_', | |
| 134 | 140 | ), |
| 135 | - '=' | |
| 141 | + '=', | |
| 136 | 142 | ); |
| 137 | 143 | } |
| 138 | 144 | elseif ( $pkce_method === 'plain' ) { |
| 139 | 145 | $options['code_challenge'] = $this->pkceCode; |
| @@ -162,9 +168,9 @@ | ||
| 162 | 168 | * @param array $options The options to use with the current request. |
| 163 | 169 | * |
| 164 | 170 | * @return AccessToken|AccessTokenInterface The access token. |
| 165 | 171 | * |
| 166 | - * @throws IdentityProviderException Exception thrown if the provider response contains errors. | |
| 172 | + * @throws UnexpectedValueException Exception thrown if the provider response contains errors. | |
| 167 | 173 | */ |
| 168 | 174 | public function getAccessToken( $grant, array $options = [] ) { |
| 169 | 175 | $grant = $this->verifyGrant( $grant ); |
| 170 | 176 | |
| @@ -183,9 +189,9 @@ | ||
| 183 | 189 | $response = $this->getParsedResponse( $request ); |
| 184 | 190 | |
| 185 | 191 | if ( \is_array( $response ) === false ) { |
| 186 | 192 | throw new UnexpectedValueException( |
| 187 | - 'Invalid response received from Authorization Server. Expected JSON.' | |
| 193 | + 'Invalid response received from Authorization Server. Expected JSON.', | |
| 188 | 194 | ); |
| 189 | 195 | } |
| 190 | 196 | |
| 191 | 197 | $prepared = $this->prepareAccessTokenResponse( $response ); |
| @@ -199,9 +205,9 @@ | ||
| 199 | 205 | * |
| 200 | 206 | * @return array The configurable options. |
| 201 | 207 | */ |
| 202 | 208 | protected function getConfigurableOptions() { |
| 203 | - return array_merge( | |
| 209 | + return \array_merge( | |
| 204 | 210 | $this->getRequiredOptions(), |
| 205 | 211 | [ |
| 206 | 212 | 'accessTokenMethod', |
| 207 | 213 | 'accessTokenResourceOwnerId', |
| @@ -210,9 +216,9 @@ | ||
| 210 | 216 | 'responseCode', |
| 211 | 217 | 'responseResourceOwnerId', |
| 212 | 218 | 'scopes', |
| 213 | 219 | 'pkceMethod', |
| 214 | - ] | |
| 220 | + ], | |
| 215 | 221 | ); |
| 216 | 222 | } |
| 217 | 223 | |
| 218 | 224 | /** |
| @@ -234,14 +240,16 @@ | ||
| 234 | 240 | $parsed = $this->parseResponse( $response ); |
| 235 | 241 | |
| 236 | 242 | $this->checkResponse( $response, $parsed ); |
| 237 | 243 | |
| 238 | - if ( ! \is_array( $parsed ) && $parsed === '' ) { | |
| 244 | + // We always expect an array from the API except for on DELETE requests. | |
| 245 | + // We convert to an array here to prevent problems with array_key_exists on PHP8. | |
| 246 | + if ( ! \is_array( $parsed ) ) { | |
| 239 | 247 | $parsed = [ 'data' => [] ]; |
| 240 | 248 | } |
| 241 | 249 | |
| 242 | 250 | // Add the response code as this is omitted from Winchers API. |
| 243 | - if ( ! array_key_exists( 'status', $parsed ) ) { | |
| 251 | + if ( ! \array_key_exists( 'status', $parsed ) ) { | |
| 244 | 252 | $parsed['status'] = $response->getStatusCode(); |
| 245 | 253 | } |
| 246 | 254 | |
| 247 | 255 | return $parsed; |