class-wp-session-tokens.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. <?php
  2. /**
  3. * Session API: WP_Session_Tokens class
  4. *
  5. * @package WordPress
  6. * @subpackage Session
  7. * @since 4.7.0
  8. */
  9. /**
  10. * Abstract class for managing user session tokens.
  11. *
  12. * @since 4.0.0
  13. */
  14. abstract class WP_Session_Tokens {
  15. /**
  16. * User ID.
  17. *
  18. * @since 4.0.0
  19. * @var int User ID.
  20. */
  21. protected $user_id;
  22. /**
  23. * Protected constructor.
  24. *
  25. * @since 4.0.0
  26. *
  27. * @param int $user_id User whose session to manage.
  28. */
  29. protected function __construct( $user_id ) {
  30. $this->user_id = $user_id;
  31. }
  32. /**
  33. * Retrieves a session token manager instance for a user.
  34. *
  35. * This method contains a {@see 'session_token_manager'} filter, allowing a plugin to swap out
  36. * the session manager for a subclass of `WP_Session_Tokens`.
  37. *
  38. * @since 4.0.0
  39. * @static
  40. *
  41. * @param int $user_id User whose session to manage.
  42. * @return WP_User_Meta_Session_Tokens WP_User_Meta_Session_Tokens class instance by default.
  43. */
  44. final public static function get_instance( $user_id ) {
  45. /**
  46. * Filters the session token manager used.
  47. *
  48. * @since 4.0.0
  49. *
  50. * @param string $session Name of class to use as the manager.
  51. * Default 'WP_User_Meta_Session_Tokens'.
  52. */
  53. $manager = apply_filters( 'session_token_manager', 'WP_User_Meta_Session_Tokens' );
  54. return new $manager( $user_id );
  55. }
  56. /**
  57. * Hashes a session token for storage.
  58. *
  59. * @since 4.0.0
  60. *
  61. * @param string $token Session token to hash.
  62. * @return string A hash of the session token (a verifier).
  63. */
  64. final private function hash_token( $token ) {
  65. // If ext/hash is not present, use sha1() instead.
  66. if ( function_exists( 'hash' ) ) {
  67. return hash( 'sha256', $token );
  68. } else {
  69. return sha1( $token );
  70. }
  71. }
  72. /**
  73. * Get a user's session.
  74. *
  75. * @since 4.0.0
  76. *
  77. * @param string $token Session token
  78. * @return array User session
  79. */
  80. final public function get( $token ) {
  81. $verifier = $this->hash_token( $token );
  82. return $this->get_session( $verifier );
  83. }
  84. /**
  85. * Validate a user's session token as authentic.
  86. *
  87. * Checks that the given token is present and hasn't expired.
  88. *
  89. * @since 4.0.0
  90. *
  91. * @param string $token Token to verify.
  92. * @return bool Whether the token is valid for the user.
  93. */
  94. final public function verify( $token ) {
  95. $verifier = $this->hash_token( $token );
  96. return (bool) $this->get_session( $verifier );
  97. }
  98. /**
  99. * Generate a session token and attach session information to it.
  100. *
  101. * A session token is a long, random string. It is used in a cookie
  102. * link that cookie to an expiration time and to ensure the cookie
  103. * becomes invalidated upon logout.
  104. *
  105. * This function generates a token and stores it with the associated
  106. * expiration time (and potentially other session information via the
  107. * {@see 'attach_session_information'} filter).
  108. *
  109. * @since 4.0.0
  110. *
  111. * @param int $expiration Session expiration timestamp.
  112. * @return string Session token.
  113. */
  114. final public function create( $expiration ) {
  115. /**
  116. * Filters the information attached to the newly created session.
  117. *
  118. * Could be used in the future to attach information such as
  119. * IP address or user agent to a session.
  120. *
  121. * @since 4.0.0
  122. *
  123. * @param array $session Array of extra data.
  124. * @param int $user_id User ID.
  125. */
  126. $session = apply_filters( 'attach_session_information', array(), $this->user_id );
  127. $session['expiration'] = $expiration;
  128. // IP address.
  129. if ( !empty( $_SERVER['REMOTE_ADDR'] ) ) {
  130. $session['ip'] = $_SERVER['REMOTE_ADDR'];
  131. }
  132. // User-agent.
  133. if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
  134. $session['ua'] = wp_unslash( $_SERVER['HTTP_USER_AGENT'] );
  135. }
  136. // Timestamp
  137. $session['login'] = time();
  138. $token = wp_generate_password( 43, false, false );
  139. $this->update( $token, $session );
  140. return $token;
  141. }
  142. /**
  143. * Update a session token.
  144. *
  145. * @since 4.0.0
  146. *
  147. * @param string $token Session token to update.
  148. * @param array $session Session information.
  149. */
  150. final public function update( $token, $session ) {
  151. $verifier = $this->hash_token( $token );
  152. $this->update_session( $verifier, $session );
  153. }
  154. /**
  155. * Destroy a session token.
  156. *
  157. * @since 4.0.0
  158. *
  159. * @param string $token Session token to destroy.
  160. */
  161. final public function destroy( $token ) {
  162. $verifier = $this->hash_token( $token );
  163. $this->update_session( $verifier, null );
  164. }
  165. /**
  166. * Destroy all session tokens for this user,
  167. * except a single token, presumably the one in use.
  168. *
  169. * @since 4.0.0
  170. *
  171. * @param string $token_to_keep Session token to keep.
  172. */
  173. final public function destroy_others( $token_to_keep ) {
  174. $verifier = $this->hash_token( $token_to_keep );
  175. $session = $this->get_session( $verifier );
  176. if ( $session ) {
  177. $this->destroy_other_sessions( $verifier );
  178. } else {
  179. $this->destroy_all_sessions();
  180. }
  181. }
  182. /**
  183. * Determine whether a session token is still valid,
  184. * based on expiration.
  185. *
  186. * @since 4.0.0
  187. *
  188. * @param array $session Session to check.
  189. * @return bool Whether session is valid.
  190. */
  191. final protected function is_still_valid( $session ) {
  192. return $session['expiration'] >= time();
  193. }
  194. /**
  195. * Destroy all session tokens for a user.
  196. *
  197. * @since 4.0.0
  198. */
  199. final public function destroy_all() {
  200. $this->destroy_all_sessions();
  201. }
  202. /**
  203. * Destroy all session tokens for all users.
  204. *
  205. * @since 4.0.0
  206. * @static
  207. */
  208. final public static function destroy_all_for_all_users() {
  209. /** This filter is documented in wp-includes/class-wp-session-tokens.php */
  210. $manager = apply_filters( 'session_token_manager', 'WP_User_Meta_Session_Tokens' );
  211. call_user_func( array( $manager, 'drop_sessions' ) );
  212. }
  213. /**
  214. * Retrieve all sessions of a user.
  215. *
  216. * @since 4.0.0
  217. *
  218. * @return array Sessions of a user.
  219. */
  220. final public function get_all() {
  221. return array_values( $this->get_sessions() );
  222. }
  223. /**
  224. * This method should retrieve all sessions of a user, keyed by verifier.
  225. *
  226. * @since 4.0.0
  227. *
  228. * @return array Sessions of a user, keyed by verifier.
  229. */
  230. abstract protected function get_sessions();
  231. /**
  232. * This method should look up a session by its verifier (token hash).
  233. *
  234. * @since 4.0.0
  235. *
  236. * @param string $verifier Verifier of the session to retrieve.
  237. * @return array|null The session, or null if it does not exist.
  238. */
  239. abstract protected function get_session( $verifier );
  240. /**
  241. * This method should update a session by its verifier.
  242. *
  243. * Omitting the second argument should destroy the session.
  244. *
  245. * @since 4.0.0
  246. *
  247. * @param string $verifier Verifier of the session to update.
  248. * @param array $session Optional. Session. Omitting this argument destroys the session.
  249. */
  250. abstract protected function update_session( $verifier, $session = null );
  251. /**
  252. * This method should destroy all session tokens for this user,
  253. * except a single session passed.
  254. *
  255. * @since 4.0.0
  256. *
  257. * @param string $verifier Verifier of the session to keep.
  258. */
  259. abstract protected function destroy_other_sessions( $verifier );
  260. /**
  261. * This method should destroy all sessions for a user.
  262. *
  263. * @since 4.0.0
  264. */
  265. abstract protected function destroy_all_sessions();
  266. /**
  267. * This static method should destroy all session tokens for all users.
  268. *
  269. * @since 4.0.0
  270. * @static
  271. */
  272. public static function drop_sessions() {}
  273. }