AyeCode /
invoicing
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
| 1 | <?php |
||||
| 2 | /** |
||||
| 3 | * Handle data for the current customers session. |
||||
| 4 | * Implements the WPInv_Session abstract class. |
||||
| 5 | * |
||||
| 6 | */ |
||||
| 7 | |||||
| 8 | defined( 'ABSPATH' ) || exit; |
||||
| 9 | |||||
| 10 | /** |
||||
| 11 | * Session handler class. |
||||
| 12 | * |
||||
| 13 | * @deprecated |
||||
| 14 | */ |
||||
| 15 | class WPInv_Session_Handler extends WPInv_Session { |
||||
| 16 | |||||
| 17 | /** |
||||
| 18 | * Cookie name used for the session. |
||||
| 19 | * |
||||
| 20 | * @var string cookie name |
||||
| 21 | */ |
||||
| 22 | protected $_cookie; |
||||
| 23 | |||||
| 24 | /** |
||||
| 25 | * Stores session expiry. |
||||
| 26 | * |
||||
| 27 | * @var int session due to expire timestamp |
||||
| 28 | */ |
||||
| 29 | protected $_session_expiring; |
||||
| 30 | |||||
| 31 | /** |
||||
| 32 | * Stores session due to expire timestamp. |
||||
| 33 | * |
||||
| 34 | * @var string session expiration timestamp |
||||
| 35 | */ |
||||
| 36 | protected $_session_expiration; |
||||
| 37 | |||||
| 38 | /** |
||||
| 39 | * True when the cookie exists. |
||||
| 40 | * |
||||
| 41 | * @var bool Based on whether a cookie exists. |
||||
| 42 | */ |
||||
| 43 | protected $_has_cookie = false; |
||||
| 44 | |||||
| 45 | /** |
||||
| 46 | * Table name for session data. |
||||
| 47 | * |
||||
| 48 | * @var string Custom session table name |
||||
| 49 | */ |
||||
| 50 | protected $_table; |
||||
| 51 | |||||
| 52 | /** |
||||
| 53 | * Constructor for the session class. |
||||
| 54 | */ |
||||
| 55 | public function old__construct() { |
||||
| 56 | |||||
| 57 | $this->_cookie = apply_filters( 'wpinv_cookie', 'wpinv_session_' . COOKIEHASH ); |
||||
| 58 | add_action( 'init', array( $this, 'init' ), -1 ); |
||||
| 59 | add_action( 'wp_logout', array( $this, 'destroy_session' ) ); |
||||
| 60 | add_action( 'wp', array( $this, 'set_customer_session_cookie' ), 10 ); |
||||
| 61 | add_action( 'shutdown', array( $this, 'save_data' ), 20 ); |
||||
| 62 | |||||
| 63 | } |
||||
| 64 | |||||
| 65 | /** |
||||
| 66 | * Init hooks and session data. |
||||
| 67 | * |
||||
| 68 | * @since 3.3.0 |
||||
| 69 | */ |
||||
| 70 | public function init() { |
||||
| 71 | $this->init_session_cookie(); |
||||
| 72 | |||||
| 73 | if ( ! is_user_logged_in() ) { |
||||
| 74 | add_filter( 'nonce_user_logged_out', array( $this, 'nonce_user_logged_out' ), 10, 2 ); |
||||
| 75 | } |
||||
| 76 | } |
||||
| 77 | |||||
| 78 | /** |
||||
| 79 | * Setup cookie and customer ID. |
||||
| 80 | * |
||||
| 81 | * @since 3.6.0 |
||||
| 82 | */ |
||||
| 83 | public function init_session_cookie() { |
||||
| 84 | $cookie = $this->get_session_cookie(); |
||||
| 85 | |||||
| 86 | if ( $cookie ) { |
||||
|
0 ignored issues
–
show
|
|||||
| 87 | $this->_customer_id = $cookie[0]; |
||||
|
0 ignored issues
–
show
The property
$_customer_id was declared of type integer, but $cookie[0] is of type string. Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
Loading history...
|
|||||
| 88 | $this->_session_expiration = $cookie[1]; |
||||
| 89 | $this->_session_expiring = $cookie[2]; |
||||
|
0 ignored issues
–
show
The property
$_session_expiring was declared of type integer, but $cookie[2] is of type string. Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
Loading history...
|
|||||
| 90 | $this->_has_cookie = true; |
||||
| 91 | $this->_data = $this->get_session_data(); |
||||
| 92 | |||||
| 93 | // If the user logs in, update session. |
||||
| 94 | if ( is_user_logged_in() && get_current_user_id() != $this->_customer_id ) { |
||||
| 95 | $this->_customer_id = get_current_user_id(); |
||||
| 96 | $this->_dirty = true; |
||||
| 97 | $this->save_data(); |
||||
| 98 | $this->set_customer_session_cookie( true ); |
||||
| 99 | } |
||||
| 100 | |||||
| 101 | // Update session if its close to expiring. |
||||
| 102 | if ( time() > $this->_session_expiring ) { |
||||
| 103 | $this->set_session_expiration(); |
||||
| 104 | $this->update_session_timestamp( $this->_customer_id, $this->_session_expiration ); |
||||
| 105 | } |
||||
| 106 | } else { |
||||
| 107 | $this->set_session_expiration(); |
||||
| 108 | $this->_customer_id = $this->generate_customer_id(); |
||||
| 109 | $this->_data = $this->get_session_data(); |
||||
| 110 | } |
||||
| 111 | } |
||||
| 112 | |||||
| 113 | /** |
||||
| 114 | * Sets the session cookie on-demand (usually after adding an item to the cart). |
||||
| 115 | * |
||||
| 116 | * Since the cookie name (as of 2.1) is prepended with wp, cache systems like batcache will not cache pages when set. |
||||
| 117 | * |
||||
| 118 | * Warning: Cookies will only be set if this is called before the headers are sent. |
||||
| 119 | * |
||||
| 120 | * @param bool $set Should the session cookie be set. |
||||
| 121 | */ |
||||
| 122 | public function set_customer_session_cookie( $set ) { |
||||
| 123 | if ( $set ) { |
||||
| 124 | $to_hash = $this->_customer_id . '|' . $this->_session_expiration; |
||||
| 125 | $cookie_hash = hash_hmac( 'md5', $to_hash, wp_hash( $to_hash ) ); |
||||
| 126 | $cookie_value = $this->_customer_id . '||' . $this->_session_expiration . '||' . $this->_session_expiring . '||' . $cookie_hash; |
||||
| 127 | $this->_has_cookie = true; |
||||
| 128 | |||||
| 129 | if ( ! isset( $_COOKIE[ $this->_cookie ] ) || $_COOKIE[ $this->_cookie ] !== $cookie_value ) { |
||||
| 130 | $this->setcookie( $this->_cookie, $cookie_value, $this->_session_expiration, $this->use_secure_cookie(), true ); |
||||
| 131 | } |
||||
| 132 | } |
||||
| 133 | } |
||||
| 134 | |||||
| 135 | public function setcookie( $name, $value, $expire = 0, $secure = false, $httponly = false ) { |
||||
| 136 | if ( ! headers_sent() ) { |
||||
| 137 | setcookie( $name, $value, $expire, COOKIEPATH ? COOKIEPATH : '/', COOKIE_DOMAIN, $secure, apply_filters( 'wpinv_cookie_httponly', $httponly, $name, $value, $expire, $secure ) ); |
||||
|
0 ignored issues
–
show
COOKIE_DOMAIN of type false is incompatible with the type string expected by parameter $domain of setcookie().
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 138 | } elseif ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { |
||||
| 139 | headers_sent( $file, $line ); |
||||
| 140 | trigger_error( "{$name} cookie cannot be set - headers already sent by {$file} on line {$line}", E_USER_NOTICE ); // @codingStandardsIgnoreLine |
||||
| 141 | } |
||||
| 142 | } |
||||
| 143 | |||||
| 144 | /** |
||||
| 145 | * Should the session cookie be secure? |
||||
| 146 | * |
||||
| 147 | * @since 3.6.0 |
||||
| 148 | * @return bool |
||||
| 149 | */ |
||||
| 150 | protected function use_secure_cookie() { |
||||
| 151 | $is_https = false !== strstr( get_option( 'home' ), 'https:' ); |
||||
|
0 ignored issues
–
show
It seems like
get_option('home') can also be of type false; however, parameter $haystack of strstr() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 152 | return apply_filters( 'wpinv_session_use_secure_cookie', $is_https && is_ssl() ); |
||||
| 153 | } |
||||
| 154 | |||||
| 155 | /** |
||||
| 156 | * Return true if the current user has an active session, i.e. a cookie to retrieve values. |
||||
| 157 | * |
||||
| 158 | * @return bool |
||||
| 159 | */ |
||||
| 160 | public function has_session() { |
||||
| 161 | return isset( $_COOKIE[ $this->_cookie ] ) || $this->_has_cookie || is_user_logged_in(); // @codingStandardsIgnoreLine. |
||||
| 162 | } |
||||
| 163 | |||||
| 164 | /** |
||||
| 165 | * Set session expiration. |
||||
| 166 | */ |
||||
| 167 | public function set_session_expiration() { |
||||
| 168 | $this->_session_expiring = time() + intval( apply_filters( 'wpinv_session_expiring', 60 * 60 * 47 ) ); // 47 Hours. |
||||
| 169 | $this->_session_expiration = time() + intval( apply_filters( 'wpinv_session_expiration', 60 * 60 * 48 ) ); // 48 Hours. |
||||
| 170 | } |
||||
| 171 | |||||
| 172 | /** |
||||
| 173 | * Generates session ids. |
||||
| 174 | * |
||||
| 175 | * @return string |
||||
| 176 | */ |
||||
| 177 | public function generate_customer_id() { |
||||
| 178 | require_once ABSPATH . 'wp-includes/class-phpass.php'; |
||||
| 179 | $hasher = new PasswordHash( 8, false ); |
||||
| 180 | return md5( $hasher->get_random_bytes( 32 ) ); |
||||
| 181 | } |
||||
| 182 | |||||
| 183 | /** |
||||
| 184 | * Get the session cookie, if set. Otherwise return false. |
||||
| 185 | * |
||||
| 186 | * Session cookies without a customer ID are invalid. |
||||
| 187 | * |
||||
| 188 | * @return bool|array |
||||
| 189 | */ |
||||
| 190 | public function get_session_cookie() { |
||||
| 191 | $cookie_value = isset( $_COOKIE[ $this->_cookie ] ) ? wp_unslash( $_COOKIE[ $this->_cookie ] ) : false; // @codingStandardsIgnoreLine. |
||||
| 192 | |||||
| 193 | if ( empty( $cookie_value ) || ! is_string( $cookie_value ) ) { |
||||
| 194 | return false; |
||||
| 195 | } |
||||
| 196 | |||||
| 197 | list( $customer_id, $session_expiration, $session_expiring, $cookie_hash ) = explode( '||', $cookie_value ); |
||||
| 198 | |||||
| 199 | if ( empty( $customer_id ) ) { |
||||
| 200 | return false; |
||||
| 201 | } |
||||
| 202 | |||||
| 203 | // Validate hash. |
||||
| 204 | $to_hash = $customer_id . '|' . $session_expiration; |
||||
| 205 | $hash = hash_hmac( 'md5', $to_hash, wp_hash( $to_hash ) ); |
||||
| 206 | |||||
| 207 | if ( empty( $cookie_hash ) || ! hash_equals( $hash, $cookie_hash ) ) { |
||||
| 208 | return false; |
||||
| 209 | } |
||||
| 210 | |||||
| 211 | return array( $customer_id, $session_expiration, $session_expiring, $cookie_hash ); |
||||
| 212 | } |
||||
| 213 | |||||
| 214 | /** |
||||
| 215 | * Get session data. |
||||
| 216 | * |
||||
| 217 | * @return array |
||||
| 218 | */ |
||||
| 219 | public function get_session_data() { |
||||
| 220 | return $this->has_session() ? (array) $this->get_session( $this->_customer_id ) : array(); |
||||
| 221 | } |
||||
| 222 | |||||
| 223 | public function generate_key( $customer_id ) { |
||||
| 224 | if ( ! $customer_id ) { |
||||
| 225 | return; |
||||
| 226 | } |
||||
| 227 | |||||
| 228 | return 'wpi_trans_' . $customer_id; |
||||
| 229 | } |
||||
| 230 | |||||
| 231 | /** |
||||
| 232 | * Save data. |
||||
| 233 | */ |
||||
| 234 | public function save_data() { |
||||
| 235 | // Dirty if something changed - prevents saving nothing new. |
||||
| 236 | if ( $this->_dirty && $this->has_session() ) { |
||||
| 237 | |||||
| 238 | set_transient( $this->generate_key( $this->_customer_id ), $this->_data, $this->_session_expiration ); |
||||
|
0 ignored issues
–
show
$this->_session_expiration of type string is incompatible with the type integer expected by parameter $expiration of set_transient().
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 239 | |||||
| 240 | $this->_dirty = false; |
||||
| 241 | } |
||||
| 242 | } |
||||
| 243 | |||||
| 244 | /** |
||||
| 245 | * Destroy all session data. |
||||
| 246 | */ |
||||
| 247 | public function destroy_session() { |
||||
| 248 | $this->delete_session( $this->_customer_id ); |
||||
| 249 | $this->forget_session(); |
||||
| 250 | } |
||||
| 251 | |||||
| 252 | /** |
||||
| 253 | * Forget all session data without destroying it. |
||||
| 254 | */ |
||||
| 255 | public function forget_session() { |
||||
| 256 | $this->setcookie( $this->_cookie, '', time() - YEAR_IN_SECONDS, $this->use_secure_cookie(), true ); |
||||
| 257 | |||||
| 258 | wpinv_empty_cart(); |
||||
|
0 ignored issues
–
show
The function
wpinv_empty_cart() has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 259 | |||||
| 260 | $this->_data = array(); |
||||
| 261 | $this->_dirty = false; |
||||
| 262 | $this->_customer_id = $this->generate_customer_id(); |
||||
|
0 ignored issues
–
show
The property
$_customer_id was declared of type integer, but $this->generate_customer_id() is of type string. Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
Loading history...
|
|||||
| 263 | } |
||||
| 264 | |||||
| 265 | /** |
||||
| 266 | * When a user is logged out, ensure they have a unique nonce by using the customer/session ID. |
||||
| 267 | * |
||||
| 268 | * @param int $uid User ID. |
||||
| 269 | * @return string |
||||
| 270 | */ |
||||
| 271 | public function nonce_user_logged_out( $uid ) { |
||||
| 272 | |||||
| 273 | // Check if one of our nonces. |
||||
| 274 | if ( substr( $uid, 0, 5 ) === 'wpinv' || substr( $uid, 0, 7 ) === 'getpaid' ) { |
||||
| 275 | return $this->has_session() && $this->_customer_id ? $this->_customer_id : $uid; |
||||
| 276 | } |
||||
| 277 | |||||
| 278 | return $uid; |
||||
| 279 | } |
||||
| 280 | |||||
| 281 | /** |
||||
| 282 | * Returns the session. |
||||
| 283 | * |
||||
| 284 | * @param string $customer_id Customer ID. |
||||
| 285 | * @param mixed $default Default session value. |
||||
| 286 | * @return string|array |
||||
| 287 | */ |
||||
| 288 | public function get_session( $customer_id, $default = false ) { |
||||
| 289 | |||||
| 290 | if ( defined( 'WP_SETUP_CONFIG' ) ) { |
||||
| 291 | return array(); |
||||
| 292 | } |
||||
| 293 | |||||
| 294 | $key = $this->generate_key( $customer_id ); |
||||
| 295 | $value = get_transient( $key ); |
||||
| 296 | |||||
| 297 | if ( ! $value ) { |
||||
| 298 | $value = $default; |
||||
| 299 | } |
||||
| 300 | |||||
| 301 | return maybe_unserialize( $value ); |
||||
| 302 | } |
||||
| 303 | |||||
| 304 | /** |
||||
| 305 | * Delete the session from the cache and database. |
||||
| 306 | * |
||||
| 307 | * @param int $customer_id Customer ID. |
||||
| 308 | */ |
||||
| 309 | public function delete_session( $customer_id ) { |
||||
| 310 | |||||
| 311 | $key = $this->generate_key( $customer_id ); |
||||
| 312 | |||||
| 313 | delete_transient( $key ); |
||||
| 314 | } |
||||
| 315 | |||||
| 316 | /** |
||||
| 317 | * Update the session expiry timestamp. |
||||
| 318 | * |
||||
| 319 | * @param string $customer_id Customer ID. |
||||
| 320 | * @param int $timestamp Timestamp to expire the cookie. |
||||
| 321 | */ |
||||
| 322 | public function update_session_timestamp( $customer_id, $timestamp ) { |
||||
| 323 | |||||
| 324 | set_transient( $this->generate_key( $customer_id ), maybe_serialize( $this->_data ), $timestamp ); |
||||
| 325 | |||||
| 326 | } |
||||
| 327 | } |
||||
| 328 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.