349 lines
No EOL
7.4 KiB
PHP
349 lines
No EOL
7.4 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Users
|
|
*
|
|
* @package Kirby CMS
|
|
* @author Bastian Allgeier <bastian@getkirby.com>
|
|
* @link http://getkirby.com
|
|
* @copyright Bastian Allgeier
|
|
* @license http://getkirby.com/license
|
|
*/
|
|
abstract class UserAbstract {
|
|
|
|
protected $username = null;
|
|
protected $cache = array();
|
|
protected $data = null;
|
|
|
|
public function __construct($username) {
|
|
|
|
$this->username = str::slug(basename($username));
|
|
|
|
// check if the account file exists
|
|
if(!file_exists($this->file())) {
|
|
throw new Exception('The user account could not be found');
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns the username
|
|
*
|
|
* @return string
|
|
*/
|
|
public function username() {
|
|
return $this->username;
|
|
}
|
|
|
|
/**
|
|
* get all data for the user
|
|
*/
|
|
public function data() {
|
|
|
|
if(!is_null($this->data)) return $this->data;
|
|
|
|
// get all data from the account file
|
|
$this->data = data::read($this->file(), 'yaml');
|
|
|
|
// make sure all keys are lowercase
|
|
$this->data = array_change_key_case($this->data, CASE_LOWER);
|
|
|
|
// remove garbage
|
|
unset($this->data[0]);
|
|
|
|
// add the username
|
|
$this->data['username'] = $this->username;
|
|
|
|
// return the data array
|
|
return $this->data;
|
|
|
|
}
|
|
|
|
public function __get($key) {
|
|
return a::get($this->data(), strtolower($key));
|
|
}
|
|
|
|
public function __call($key, $arguments = null) {
|
|
return $this->__get($key);
|
|
}
|
|
|
|
public function role() {
|
|
|
|
$roles = kirby::instance()->site()->roles();
|
|
$data = $this->data();
|
|
|
|
if(empty($data['role'])) {
|
|
// apply the default role, if no role is stored for the user
|
|
$data['role'] = $roles->findDefault()->id();
|
|
}
|
|
|
|
// return the role by id
|
|
if($role = $roles->get($data['role'])) {
|
|
return $role;
|
|
} else {
|
|
return $roles->findDefault();
|
|
}
|
|
|
|
}
|
|
|
|
public function hasRole() {
|
|
$roles = func_get_args();
|
|
return in_array($this->role()->id(), $roles);
|
|
}
|
|
|
|
// support for old 'panel' role permission
|
|
public function hasPanelAccess() {
|
|
return $this->role()->hasPermission('panel.access');
|
|
}
|
|
|
|
public function hasPermission($target) {
|
|
return $this->role()->hasPermission($target);
|
|
}
|
|
|
|
public function isAdmin() {
|
|
return $this->role()->id() == 'admin';
|
|
}
|
|
|
|
public function avatar() {
|
|
|
|
if(isset($this->cache['avatar'])) return $this->cache['avatar'];
|
|
|
|
$avatar = new Avatar($this);
|
|
|
|
return $this->cache['avatar'] = $avatar->exists() ? $avatar : false;
|
|
|
|
}
|
|
|
|
public function avatarRoot($extension = 'jpg') {
|
|
return kirby::instance()->roots()->avatars() . DS . $this->username() . '.' . $extension;
|
|
}
|
|
|
|
public function gravatar($size = 256) {
|
|
return gravatar($this->email(), $size);
|
|
}
|
|
|
|
protected function file() {
|
|
return kirby::instance()->roots()->accounts() . DS . $this->username() . '.php';
|
|
}
|
|
|
|
public function textfile() {
|
|
return $this->file();
|
|
}
|
|
|
|
public function exists() {
|
|
return file_exists($this->file());
|
|
}
|
|
|
|
public function generateKey() {
|
|
return str::random(64);
|
|
}
|
|
|
|
public function generateSecret($key) {
|
|
return sha1($this->username() . $key);
|
|
}
|
|
|
|
public function login($password) {
|
|
|
|
static::logout();
|
|
|
|
if(!password::match($password, $this->password)) return false;
|
|
|
|
// create a new session id
|
|
s::regenerateId();
|
|
|
|
$key = $this->generateKey();
|
|
$secret = $this->generateSecret($key);
|
|
|
|
s::set('kirby_auth_secret', $secret);
|
|
s::set('kirby_auth_username', $this->username());
|
|
|
|
cookie::set(
|
|
s::$name . '_auth',
|
|
$key,
|
|
s::$cookie['lifetime'],
|
|
s::$cookie['path'],
|
|
s::$cookie['domain'],
|
|
s::$cookie['secure'],
|
|
s::$cookie['httponly']
|
|
);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
static public function logout() {
|
|
s::destroy();
|
|
cookie::remove(s::$name . '_auth');
|
|
}
|
|
|
|
public function is($user) {
|
|
if(!is_a($user, 'User')) return false;
|
|
return $this->username() === $user->username();
|
|
}
|
|
|
|
public function isCurrent() {
|
|
return $this->is(static::current());
|
|
}
|
|
|
|
static public function validate($data = array(), $mode = 'insert') {
|
|
|
|
if($mode == 'insert') {
|
|
|
|
if(empty($data['username'])) {
|
|
throw new Exception('Invalid username');
|
|
}
|
|
|
|
if(empty($data['password'])) {
|
|
throw new Exception('Invalid password');
|
|
}
|
|
|
|
}
|
|
|
|
if(!empty($data['email']) and !v::email($data['email'])) {
|
|
throw new Exception('Invalid email');
|
|
}
|
|
|
|
}
|
|
|
|
public function update($data = array()) {
|
|
|
|
// sanitize the given data
|
|
$data = $this->sanitize($data, 'update');
|
|
|
|
// validate the updated dataset
|
|
$this->validate($data, 'update');
|
|
|
|
// don't update the username
|
|
unset($data['username']);
|
|
|
|
// create a new hash for the password
|
|
if(!empty($data['password'])) {
|
|
$data['password'] = password::hash($data['password']);
|
|
}
|
|
|
|
// merge with existing fields
|
|
$this->data = array_merge($this->data(), $data);
|
|
|
|
foreach($this->data as $key => $value) {
|
|
if(is_null($value)) unset($this->data[$key]);
|
|
}
|
|
|
|
// save the new user data
|
|
static::save($this->file(), $this->data);
|
|
|
|
// return the updated user project
|
|
return $this;
|
|
|
|
}
|
|
|
|
public function delete() {
|
|
|
|
if($avatar = $this->avatar()) {
|
|
$avatar->delete();
|
|
}
|
|
|
|
if(!f::remove($this->file())) {
|
|
throw new Exception('The account could not be deleted');
|
|
} else {
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
static public function sanitize($data, $mode = 'insert') {
|
|
|
|
// all usernames must be lowercase
|
|
$data['username'] = str::slug(a::get($data, 'username'));
|
|
|
|
// convert all keys to lowercase
|
|
$data = array_change_key_case($data, CASE_LOWER);
|
|
|
|
// return the cleaned up data
|
|
return $data;
|
|
|
|
}
|
|
|
|
/**
|
|
* Creates a new user
|
|
*
|
|
* @param array $user
|
|
* @return User
|
|
*/
|
|
static public function create($data = array()) {
|
|
|
|
// sanitize the given data for the new user
|
|
$data = static::sanitize($data, 'insert');
|
|
|
|
// validate the dataset
|
|
static::validate($data, 'insert');
|
|
|
|
// create the file root
|
|
$file = kirby::instance()->roots()->accounts() . DS . $data['username'] . '.php';
|
|
|
|
// check for an existing username
|
|
if(file_exists($file)) {
|
|
throw new Exception('The username is taken');
|
|
}
|
|
|
|
// create a new hash for the password
|
|
if(!empty($data['password'])) {
|
|
$data['password'] = password::hash($data['password']);
|
|
}
|
|
|
|
static::save($file, $data);
|
|
|
|
// return the created user project
|
|
return new static($data['username']);
|
|
|
|
}
|
|
|
|
static protected function save($file, $data) {
|
|
|
|
$yaml = '<?php if(!defined(\'KIRBY\')) exit ?>' . PHP_EOL . PHP_EOL;
|
|
$yaml .= data::encode($data, 'yaml');
|
|
|
|
if(!f::write($file, $yaml)) {
|
|
throw new Exception('The user account could not be saved');
|
|
} else {
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
static public function unauthorize() {
|
|
s::remove('kirby_auth_secret');
|
|
s::remove('kirby_auth_username');
|
|
cookie::remove('kirby_auth');
|
|
}
|
|
|
|
static public function current() {
|
|
|
|
$cookey = cookie::get(s::$name . '_auth');
|
|
$username = s::get('kirby_auth_username');
|
|
|
|
if(empty($cookey)) {
|
|
static::unauthorize();
|
|
return false;
|
|
}
|
|
|
|
if(s::get('kirby_auth_secret') !== sha1($username . $cookey)) {
|
|
static::unauthorize();
|
|
return false;
|
|
}
|
|
|
|
// find the logged in user by token
|
|
try {
|
|
$user = new static($username);
|
|
return $user;
|
|
} catch(Exception $e) {
|
|
static::unauthorize();
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
public function __toString() {
|
|
return (string)$this->username;
|
|
}
|
|
|
|
} |