X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fsession%2FSession.php;h=0fd8fa8a310f4317a7a7ea19bfa5bed3ec1a882b;hb=5b119a0e442306d90198deead25f6a975513e65e;hp=840baa70fed8b61a1c2808f1c10b45c2ba342a91;hpb=23299ca8790bcf1aebcf54e0932b94338e630474;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/session/Session.php b/includes/session/Session.php index 840baa70fe..0fd8fa8a31 100644 --- a/includes/session/Session.php +++ b/includes/session/Session.php @@ -23,6 +23,7 @@ namespace MediaWiki\Session; +use Psr\Log\LoggerInterface; use User; use WebRequest; @@ -41,24 +42,28 @@ use WebRequest; * The Session object also serves as a replacement for PHP's $_SESSION, * managing access to per-session data. * - * @todo Once we drop support for PHP 5.3.3, implementing ArrayAccess would be nice. * @ingroup Session * @since 1.27 */ -final class Session implements \Countable, \Iterator { +final class Session implements \Countable, \Iterator, \ArrayAccess { /** @var SessionBackend Session backend */ private $backend; /** @var int Session index */ private $index; + /** @var LoggerInterface */ + private $logger; + /** * @param SessionBackend $backend * @param int $index + * @param LoggerInterface $logger */ - public function __construct( SessionBackend $backend, $index ) { + public function __construct( SessionBackend $backend, $index, LoggerInterface $logger ) { $this->backend = $backend; $this->index = $index; + $this->logger = $logger; } public function __destruct() { @@ -119,6 +124,13 @@ final class Session implements \Countable, \Iterator { $this->backend->persist(); } + /** + * Make this session not be persisted across requests + */ + public function unpersist() { + $this->backend->unpersist(); + } + /** * Indicate whether the user should be remembered independently of the * session ID. @@ -235,7 +247,7 @@ final class Session implements \Countable, \Iterator { public function clear() { $data = &$this->backend->getData(); if ( $data ) { - $data = array(); + $data = []; $this->backend->dirty(); } if ( $this->backend->canSetUser() ) { @@ -271,7 +283,7 @@ final class Session implements \Countable, \Iterator { /** * Fetch a value from the session * @param string|int $key - * @param mixed $default + * @param mixed $default Returned if $this->exists( $key ) would be false * @return mixed */ public function get( $key, $default = null ) { @@ -281,6 +293,7 @@ final class Session implements \Countable, \Iterator { /** * Test if a value exists in the session + * @note Unlike isset(), null values are considered to exist. * @param string|int $key * @return bool */ @@ -314,6 +327,58 @@ final class Session implements \Countable, \Iterator { } } + /** + * Fetch a CSRF token from the session + * + * Note that this does not persist the session, which you'll probably want + * to do if you want the token to actually be useful. + * + * @param string|string[] $salt Token salt + * @param string $key Token key + * @return MediaWiki\\Session\\SessionToken + */ + public function getToken( $salt = '', $key = 'default' ) { + $new = false; + $secrets = $this->get( 'wsTokenSecrets' ); + if ( !is_array( $secrets ) ) { + $secrets = []; + } + if ( isset( $secrets[$key] ) && is_string( $secrets[$key] ) ) { + $secret = $secrets[$key]; + } else { + $secret = \MWCryptRand::generateHex( 32 ); + $secrets[$key] = $secret; + $this->set( 'wsTokenSecrets', $secrets ); + $new = true; + } + if ( is_array( $salt ) ) { + $salt = implode( '|', $salt ); + } + return new Token( $secret, (string)$salt, $new ); + } + + /** + * Remove a CSRF token from the session + * + * The next call to self::getToken() with $key will generate a new secret. + * + * @param string $key Token key + */ + public function resetToken( $key = 'default' ) { + $secrets = $this->get( 'wsTokenSecrets' ); + if ( is_array( $secrets ) && isset( $secrets[$key] ) ) { + unset( $secrets[$key] ); + $this->set( 'wsTokenSecrets', $secrets ); + } + } + + /** + * Remove all CSRF tokens from the session + */ + public function resetAllTokens() { + $this->remove( 'wsTokenSecrets' ); + } + /** * Delay automatic saving while multiple updates are being made * @@ -367,6 +432,39 @@ final class Session implements \Countable, \Iterator { return key( $data ) !== null; } + /** + * @note Despite the name, this seems to be intended to implement isset() + * rather than array_key_exists(). So do that. + */ + public function offsetExists( $offset ) { + $data = &$this->backend->getData(); + return isset( $data[$offset] ); + } + + /** + * @note This supports indirect modifications but can't mark the session + * dirty when those happen. SessionBackend::save() checks the hash of the + * data to detect such changes. + * @note Accessing a nonexistent key via this mechanism causes that key to + * be created with a null value, and does not raise a PHP warning. + */ + public function &offsetGet( $offset ) { + $data = &$this->backend->getData(); + if ( !array_key_exists( $offset, $data ) ) { + $ex = new \Exception( "Undefined index (auto-adds to session with a null value): $offset" ); + $this->logger->debug( $ex->getMessage(), [ 'exception' => $ex ] ); + } + return $data[$offset]; + } + + public function offsetSet( $offset, $value ) { + $this->set( $offset, $value ); + } + + public function offsetUnset( $offset ) { + $this->remove( $offset ); + } + /**@}*/ }