X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=includes%2Flibs%2Fobjectcache%2FRESTBagOStuff.php;h=68fe07c23fde7f1c7ea2f1b3ae2bb98783d5c881;hp=82b5ac05bfa623ea695cf7223f25d7e8b416a018;hb=dbac27bd42bdc72272c898c79c7011e2e0ef92c8;hpb=38190f6608f3d2807cb93b1bae7edb770af36ef8 diff --git a/includes/libs/objectcache/RESTBagOStuff.php b/includes/libs/objectcache/RESTBagOStuff.php index 82b5ac05bf..68fe07c23f 100644 --- a/includes/libs/objectcache/RESTBagOStuff.php +++ b/includes/libs/objectcache/RESTBagOStuff.php @@ -39,6 +39,7 @@ use Psr\Log\LoggerInterface; * 'deleteHeaders' => [], * 'writeMethod' => 'POST', * ], + * 'serialization_type' => 'JSON', * 'extendedErrorBodyFields' => [ 'type', 'title', 'detail', 'instance' ] * ); * $wgSessionCacheType = 'sessions'; @@ -73,6 +74,22 @@ class RESTBagOStuff extends MediumSpecificBagOStuff { */ private $httpParams; + /** + * Optional serialization type to use. Allowed values: "PHP", "JSON", or "legacy". + * "legacy" is PHP serialization with no serialization type tagging or hmac protection. + * @var string + * @deprecated since 1.34, the "legacy" value will be removed in 1.35. + * Use either "PHP" or "JSON". + */ + private $serializationType; + + /** + * Optional HMAC Key for protecting the serialized blob. If omitted, or if serializationType + * is "legacy", then no protection is done + * @var string + */ + private $hmacKey; + /** * @var array additional body fields to log on error, if possible */ @@ -105,6 +122,8 @@ class RESTBagOStuff extends MediumSpecificBagOStuff { $this->httpParams['writeHeaders'] = $params['httpParams']['writeHeaders'] ?? []; $this->httpParams['deleteHeaders'] = $params['httpParams']['deleteHeaders'] ?? []; $this->extendedErrorBodyFields = $params['extendedErrorBodyFields'] ?? []; + $this->serializationType = $params['serialization_type'] ?? 'legacy'; + $this->hmacKey = $params['hmac_key'] ?? ''; // The parent constructor calls setLogger() which sets the logger in $this->client parent::__construct( $params ); @@ -211,22 +230,76 @@ class RESTBagOStuff extends MediumSpecificBagOStuff { * @return mixed|bool the processed body, or false on error */ private function decodeBody( $body ) { - $value = json_decode( $body, true ); - return ( json_last_error() === JSON_ERROR_NONE ) ? $value : false; + if ( $this->serializationType === 'legacy' ) { + $serialized = $body; + } else { + $pieces = explode( '.', $body, 3 ); + if ( count( $pieces ) !== 3 || $pieces[0] !== $this->serializationType ) { + return false; + } + list( , $hmac, $serialized ) = $pieces; + if ( $this->hmacKey !== '' ) { + $checkHmac = hash_hmac( 'sha256', $serialized, $this->hmacKey, true ); + if ( !hash_equals( $checkHmac, base64_decode( $hmac ) ) ) { + return false; + } + } + } + + switch ( $this->serializationType ) { + case 'JSON': + $value = json_decode( $serialized, true ); + return ( json_last_error() === JSON_ERROR_NONE ) ? $value : false; + + case 'PHP': + case 'legacy': + return unserialize( $serialized ); + + default: + throw new \DomainException( + "Unknown serialization type: $this->serializationType" + ); + } } /** * Prepares the request body (the "value" portion of our key/value store) for transmission. * * @param string $body request body to prepare - * @return string the prepared body, or an empty string on error + * @return string the prepared body * @throws LogicException */ private function encodeBody( $body ) { - $value = json_encode( $body ); - if ( $value === false ) { - throw new InvalidArgumentException( __METHOD__ . ": body could not be encoded." ); + switch ( $this->serializationType ) { + case 'JSON': + $value = json_encode( $body ); + if ( $value === false ) { + throw new InvalidArgumentException( __METHOD__ . ": body could not be encoded." ); + } + break; + + case 'PHP': + case "legacy": + $value = serialize( $body ); + break; + + default: + throw new \DomainException( + "Unknown serialization type: $this->serializationType" + ); + } + + if ( $this->serializationType !== 'legacy' ) { + if ( $this->hmacKey !== '' ) { + $hmac = base64_encode( + hash_hmac( 'sha256', $value, $this->hmacKey, true ) + ); + } else { + $hmac = ''; + } + $value = $this->serializationType . '.' . $hmac . '.' . $value; } + return $value; }