baseDir = $baseDir; $this->salt = $salt; } function get( $userId ) { $path = "{$this->baseDir}/users/{$userId}/data.yaml"; if ( ! file_exists( $path ) || ! $data = file_get_contents( $path ) ){ return FALSE; } return yaml_parse( $data ); } function put( $userId, $data ) { $path = "{$this->baseDir}/users/{$userId}"; if ( ! is_dir( $path ) ){ mkdir( $path, 0750, TRUE ); } $path .= '/data.yaml'; if ( ! file_put_contents( $path, yaml_emit( $data ) ) ){ return FALSE; } chmod( $path, 0640 ); return TRUE; } function create_user( $id, $password, $email, $status = 0 ) { if ( $password ){ $password = password_hash( $password, PASSWORD_DEFAULT ); $token = hash( 'sha1', microtime() ); } else { $password = ''; $token = ''; } $user = $this->get( $id ); if ( $user && ( $user['email'] != $email || $user['status'] != 0 ) ){ return FALSE; } $email = strtolower( $email ); $status = $status ? 1 : 0; $user = compact( 'id', 'password', 'email', 'token', 'status' ); if ( ! $this->put( $id, $user ) ){ return FALSE; } return [ 'id' => $id, 'token' => $token ]; } function update_challenge( $userId, $challenge ) { $user = $this->get( $userId ); if ( ! $user ){ return FALSE; } $user['challenge'] = $challenge; $user['challenge_ts'] = date('Y-m-s H:i:s'); $result = $this->db->query( $sql ); return $this->put( $userId, $user ); } function update_settings( $userId, $settings ) { $user = $this->get( $userId ); if ( ! $user ){ return FALSE; } foreach ( $settings as $key => $value ){ if ( is_null( $value ) ){ unset( $user['settings'][ $key ] ); continue; } $user['settings'][ $key ] = $value; } return $this->put( $userId, $user ); } function activate_user( $userId, $token ) { $user = $this->get( $userId ); if ( ! $user || $user['token'] != $token ){ return FALSE; } unset( $user['token'] ); $user['status'] = 1; return $this->put( $userId, $user ); } function deactivate_user( $username ) { $user = $this->get( $userId ); if ( ! $user ){ return FALSE; } $user['status'] = 0; return $this->put( $userId, $user ); } function change_pw( $userId, $oldPassword, $newPassword ) { $user = $this->check_pw( $userId, $oldPassword ); if ( ! $user ){ return FALSE; } $user['password'] = password_hash( $newPassword, PASSWORD_DEFAULT ); return $this->put( $userId, $user ); } function check_pw( $userId, $password ) { $user = $this->get( $userId ); if ( ! $user || ( empty( $user['password'] ) && ! empty( $password ) ) || ! password_verify( $password, $user['password'] ) ){ return FALSE; } return $user; } function login( $userId, $password, $persistent = FALSE ) { $user = $this->check_pw( $userId, $password ); if ( ! $user ) { return FALSE; } $user['previous_login_ts'] = $user['login_ts']; $user['login_ts'] = date('Y-m-d H:i:s'); $user['login_ip'] = $_SERVER['REMOTE_ADDR']; unset( $user['login_error_ts'], $user['login_error_ip'] ); if ( $persistent ) { $this->make_persistent( $userId ); } if ( ! $this->put( $userId, $user ) ){ return FALSE; } return $user; } function logout( $userId ) { $this->invalidate(); $user = $this->get( $userId ); if ( ! $user || empty( $user['login_ts'] ) ){ return; } $user['previous_login_ts'] = $user['login_ts']; $user['logout_ts'] = date('Y-m-d H:i:s'); unset( $user['login_ts'] ); $this->put( $userId, $user ); } function validate() { if ( empty( $_COOKIE[ $this->cookieName ] ) ) { return FALSE; } $hash = hash( 'sha1', $_COOKIE[ $this->cookieName ] . $this->salt ); $path = "{$this->baseDir}/tokens/auth/{$hash}/data.yaml"; if ( ! file_exists( $path ) ){ return FALSE; } $data = yaml_parse( file_get_contents( $path ) ); if ( empty( $data['user_id'] ) || empty( $data['expires'] ) || $data['expires'] <= date('Y-m-d') ){ return FALSE; } $this->invalidate(); $this->make_persistent( $data['user_id'] ); return $this->get( $data['user_id'] ); } function make_persistent( $userId ) { do { $token = bin2hex( random_bytes( $this->tokenLength ) ); $hash = sha1( $token . $this->salt ); $path = "{$this->baseDir}/tokens/auth/{$hash}"; } while ( ! @mkdir( $path, 0750, TRUE ) ); $expires = strtotime( 'today +' . $this->cookieLifetime . ' days' ); $data['user_id'] = $userId; $data['expires'] = date( 'Y-m-d', $expires ); if ( ! file_put_contents( "{$path}/data.yaml", yaml_emit( $data ) ) ){ return FALSE; } chmod( "{$path}/data.yaml", 0640 ); setcookie( $this->cookieName, $token, $expires, '/', '', TRUE, TRUE ); } function invalidate() { if ( empty( $_COOKIE[ $this->cookieName ] ) ) { return; } $hash = hash( 'sha1', $_COOKIE[ $this->cookieName ] . $this->salt ); $path = "{$this->baseDir}/tokens/auth/{$hash}/data.yaml"; unlink( $path ); rmdir( dirname( $path ) ); setcookie( $this->cookieName, FALSE, time() - 3600, '/', '', TRUE, TRUE ); } function tidy() { $counter = 0; $listing = glob( "{$this->baseDir}/tokens/auth/*" ); foreach ( $listing as $dir ){ $file = "{$dir}/data.yaml"; if ( file_exists( $file ) ){ continue; } $data = yaml_parse( file_get_contents( $file ) ); if ( empty( $data['user_id'] ) || empty( $data['expires'] ) || $data['expires'] > date('Y-m-d') ){ continue; } $counter++; unlink( $file ); rmdir( $dir ); } return $counter; } } // end of file users.class.php