1 | <?php |
---|
2 | |
---|
3 | abstract class WP_Session_Tokens { |
---|
4 | protected $user_id; |
---|
5 | |
---|
6 | protected function __construct( $user_id ) { |
---|
7 | $this->user_id = $user_id; |
---|
8 | } |
---|
9 | |
---|
10 | final public static function get_instance( $user_id ) { |
---|
11 | $manager = apply_filters( 'session_token_manager', 'WP_Session_Tokens' ); |
---|
12 | return new $manager( $user_id ); |
---|
13 | } |
---|
14 | |
---|
15 | final private function hash( $token ) { |
---|
16 | return hash( 'sha256', $token ); |
---|
17 | } |
---|
18 | |
---|
19 | final public function verify_token( $token ) { |
---|
20 | $verifier = $this->hash( $token ); |
---|
21 | return !! $this->get_session( $verifier ); |
---|
22 | } |
---|
23 | |
---|
24 | final public function create_token( $expiration ) { |
---|
25 | $session = apply_filters( 'attach_session_information', array(), $this->user_id ); |
---|
26 | $session['expiration'] = $expiration; |
---|
27 | |
---|
28 | $token = wp_generate_password( 43, false, false ); |
---|
29 | |
---|
30 | $this->update_token( $token, $session ); |
---|
31 | |
---|
32 | return $token; |
---|
33 | } |
---|
34 | |
---|
35 | final public function update_token( $token ) { |
---|
36 | $verifier = $this->hash( $token ); |
---|
37 | $this->update_session( $verifier, $session ); |
---|
38 | } |
---|
39 | |
---|
40 | final public function destroy_token( $token ) { |
---|
41 | $verifier = $this->hash( $token ); |
---|
42 | $this->update_session( $verifier, null ); |
---|
43 | } |
---|
44 | |
---|
45 | final public function destroy_other_tokens( $token_to_keep ) { |
---|
46 | $verifier = $this->hash( $token ); |
---|
47 | $session = $this->get_session( $verifier ); |
---|
48 | if ( $session ) { |
---|
49 | $this->keep_only_this_session( $verifier, $session ); |
---|
50 | } else { |
---|
51 | $this->destroy_all_tokens(); |
---|
52 | } |
---|
53 | } |
---|
54 | |
---|
55 | final protected function is_still_valid( $session ) { |
---|
56 | return $session['expiration'] >= time(); |
---|
57 | } |
---|
58 | |
---|
59 | final public function destroy_all_tokens() { |
---|
60 | $this->destroy_all_sessions(); |
---|
61 | } |
---|
62 | |
---|
63 | final public static function destroy_all_tokens_for_all_users() { |
---|
64 | $manager = apply_filters( 'session_token_manager', 'WP_Session_Tokens' ); |
---|
65 | $manager::drop_sessions(); |
---|
66 | } |
---|
67 | |
---|
68 | abstract public function get_sessions(); |
---|
69 | |
---|
70 | abstract protected function get_session( $verifier ); |
---|
71 | |
---|
72 | abstract protected function update_session( $verifier, $session = null ); |
---|
73 | |
---|
74 | abstract protected function keep_only_this_session( $verifier, $session ); |
---|
75 | |
---|
76 | abstract protected function destroy_all_sessions(); |
---|
77 | |
---|
78 | abstract public static function drop_sessions(); |
---|
79 | } |
---|
80 | |
---|
81 | class WP_User_Meta_Session_Tokens extends WP_Session_Tokens { |
---|
82 | public function get_sessions() { |
---|
83 | $sessions = get_user_meta( $this->user_id, 'session_tokens', true ); |
---|
84 | |
---|
85 | if ( ! is_array( $sessions ) ) { |
---|
86 | return array(); |
---|
87 | } |
---|
88 | |
---|
89 | $sessions = array_map( array( $this, 'prepare_session' ), $sessions ); |
---|
90 | return array_filter( array( $this, 'is_still_valid' ), $sessions ); |
---|
91 | } |
---|
92 | |
---|
93 | protected function prepare_session( $session ) { |
---|
94 | if ( is_int( $session ) ) { |
---|
95 | return array( 'expiration' => $session ); |
---|
96 | } |
---|
97 | |
---|
98 | return $session; |
---|
99 | } |
---|
100 | |
---|
101 | protected function get_session( $verifier ) { |
---|
102 | $sessions = $this->get_sessions(); |
---|
103 | |
---|
104 | if ( isset( $sessions[$verifier] ) ) { |
---|
105 | return $session; |
---|
106 | } |
---|
107 | |
---|
108 | return null; |
---|
109 | } |
---|
110 | |
---|
111 | protected function update_session( $verifier, $session = null ) { |
---|
112 | $sessions = $this->get_sessions(); |
---|
113 | |
---|
114 | if ( $session ) { |
---|
115 | $sessions[$verifier] = $session; |
---|
116 | } else { |
---|
117 | unset( $sessions[$verifier] ); |
---|
118 | } |
---|
119 | |
---|
120 | $this->update_sessions( $sessions ); |
---|
121 | } |
---|
122 | |
---|
123 | protected function update_sessions( $sessions ) { |
---|
124 | if ( ! has_filter( 'attach_session_information' ) ) { |
---|
125 | $sessions = wp_list_pluck( $sessions, 'expiration' ); |
---|
126 | } |
---|
127 | |
---|
128 | if ( $sessions ) { |
---|
129 | update_user_meta( $this->user_id, 'session_tokens', $sessions ); |
---|
130 | } else { |
---|
131 | delete_user_meta( $this->user_id, 'session_tokens' ); |
---|
132 | } |
---|
133 | } |
---|
134 | |
---|
135 | protected function keep_only_this_session( $verifier, $session ) { |
---|
136 | $this->update_sessions( array( $verifier => $session ) ); |
---|
137 | } |
---|
138 | |
---|
139 | protected function destroy_all_sessions() { |
---|
140 | $this->update_sessions( array() ); |
---|
141 | } |
---|
142 | |
---|
143 | public static function drop_sessions() { |
---|
144 | delete_metadata( 'user', false, 'session_tokens', false, true ); |
---|
145 | } |
---|
146 | } |
---|
147 | |
---|
148 | /* |
---|
149 | CREATE TABLE `wp_sessions` ( |
---|
150 | `id` bigint(20 NOT NULL AUTO_INCREMENT, |
---|
151 | `user_id` bigint(20) NOT NULL, |
---|
152 | `verifier` char(64) NOT NULL, |
---|
153 | `expiration` int(10) NOT NULL, |
---|
154 | `ua` varchar(400) NOT NULL, |
---|
155 | `ip` varchar(45) NOT NULL, |
---|
156 | `start` int(10) NOT NULL, |
---|
157 | PRIMARY KEY (`id`), |
---|
158 | UNIQUE KEY `user_id` (`user_id`, `verifier`) |
---|
159 | ) |
---|
160 | */ |
---|
161 | class Global_Table_Session_Tokens extends WP_Session_Tokens { |
---|
162 | public function get_sessions() { |
---|
163 | global $wpdb; |
---|
164 | |
---|
165 | $sessions = $wpdb->get_results( $wpdb->prepare( |
---|
166 | "SELECT * FROM `$wpdb->sessions` WHERE `user_id` = %d AND `expiration` >= %d", |
---|
167 | $this->user_id, |
---|
168 | time() |
---|
169 | ), ARRAY_A ); |
---|
170 | |
---|
171 | if ( ! is_array( $sessions ) ) { |
---|
172 | return array(); |
---|
173 | } |
---|
174 | |
---|
175 | $verifiers = wp_list_pluck( $sessions, 'verifier' ); |
---|
176 | |
---|
177 | return array_combine( $verifiers, array_map( array( $this, 'prepare_session' ), $sessions ) ); |
---|
178 | } |
---|
179 | |
---|
180 | protected function prepare_session( $session ) { |
---|
181 | unset( $session['user_id'], $session['verifier'] ); |
---|
182 | $session['expiration'] = (int) $session['expiration']; |
---|
183 | return $session; |
---|
184 | } |
---|
185 | |
---|
186 | protected function get_session( $verifier ) { |
---|
187 | global $wpdb; |
---|
188 | |
---|
189 | $session = $wpdb->get_results( $wpdb->prepare( |
---|
190 | "SELECT * FROM `$wpdb->sessions` WHERE `user_id` = %d AND `expiration` >= %d AND `verifier` = %s", |
---|
191 | $this->user_id, |
---|
192 | time(), |
---|
193 | $verifier |
---|
194 | ), ARRAY_A ); |
---|
195 | |
---|
196 | if ( ! $session ) { |
---|
197 | return null; |
---|
198 | } |
---|
199 | |
---|
200 | return $this->prepare_session( $session ); |
---|
201 | } |
---|
202 | |
---|
203 | protected function update_session( $verifier, $session = null ) { |
---|
204 | global $wpdb; |
---|
205 | |
---|
206 | if ( $session ) { |
---|
207 | $wpdb->query( $wpdb->prepare( |
---|
208 | "INSERT INTO `$wpdb->sessions` ( `user_id`, `verifier`, `expiration`, `ua`, `ip`, `start` ) VALUES ( %d, %s, %d, %s, %s, %d ) " . |
---|
209 | "ON DUPLICATE KEY UPDATE `ua` = VALUES( `ua` ), `ip` = VALUES( `ip` ), `expiration` = VALUES( `expiration` ), `start` = VALUES( `start` )", |
---|
210 | |
---|
211 | $this->user_id, |
---|
212 | $verifier, |
---|
213 | $session['expiration'], |
---|
214 | $session['ua'], |
---|
215 | $session['ip'], |
---|
216 | $session['start'] |
---|
217 | ) ); |
---|
218 | } else { |
---|
219 | $wpdb->query( $wpdb->prepare( |
---|
220 | "DELETE FROM `$wpdb->sessions` WHERE `user_id` = %d AND `verifier` = %s", |
---|
221 | $this->user_id, |
---|
222 | $verifier |
---|
223 | ) ); |
---|
224 | } |
---|
225 | } |
---|
226 | |
---|
227 | protected function keep_only_this_session( $verifier, $session ) { |
---|
228 | global $wpdb; |
---|
229 | |
---|
230 | $wpdb->query( $wpdb->prepare( |
---|
231 | "DELETE FROM `$wpdb->sessions` WHERE `user_id` = %d AND `verifier` != %s", |
---|
232 | $this->user_id, |
---|
233 | $verifier |
---|
234 | ) ); |
---|
235 | } |
---|
236 | |
---|
237 | protected function destroy_all_sessions() { |
---|
238 | global $wpdb; |
---|
239 | |
---|
240 | $wpdb->query( $wpdb->prepare( |
---|
241 | "DELETE FROM `$wpdb->sessions` WHERE `user_id` = %d", |
---|
242 | $this->user_id |
---|
243 | ) ); |
---|
244 | } |
---|
245 | |
---|
246 | public static function drop_sessions() { |
---|
247 | global $wpdb; |
---|
248 | |
---|
249 | $wpdb->query( "TRUNCATE TABLE `$wpdb->sessions`" ); |
---|
250 | } |
---|
251 | } |
---|