Newer
Older
Andrew Rudenets
committed
<?php
/**
* Personal info
* @property $LastName string
* @property $FirstName string
* @property $SecondName string
* @property $FacultyID int
* @property $FacultyName string
* @property $FacultyAbbr string
*
* Account info
* @property $ID int
* @property $Login string
* @property $EMail string
* @property $Type string teacher / student
* @property $Role string description
* @property $RoleMark int
* @property $IsEnabled bool
* @property $Code
* @property $UserAgent
*
* Session
* @property-read $SemesterID int
* @property-read $last_active int
* @property-read $LoggedIn bool
* @property-read $UserHash string
* @property-read $PasswordHash string
* @property-read $start_time int
class User implements ArrayAccess
Andrew Rudenets
committed
protected static $_instance;
protected $_session;
protected $_config;
protected $_userInfo;
Andrew Rudenets
committed
/**
* todo: mark deprecated as singleton is an anti-pattern!
public static function instance($state = false) {
self::$_flag = $state;
Andrew Rudenets
committed
$config = Kohana::$config->load('account');
self::$_instance = new self($config);
}
return self::$_instance;
}
Andrew Rudenets
committed
private function __construct($config = array()) {
$this->_config = $config;
$this->_session = Session::instance();
$this->_userInfo['RoleMark'] = (int)1;
$this->_config['hash_key'] = Model_Account::getHashKey();
Andrew Rudenets
committed
$this->_config['hash_method'] = 'sha256';
$this->_userInfo = $this->_session->get('UserInfo');
if (self::$_flag != true) {
$this->_session->regenerate();
$this->_session->set('start_time', time());
}
Andrew Rudenets
committed
}
}
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
const RIGHTS_ANYBODY = 1;
const RIGHTS_STUDENT = 2;
const RIGHTS_TEACHER = 4;
const RIGHTS_ADMIN = 8;
const RIGHTS_DEAN = 16;
/**
* @param $mask
* @throws LogicException
*/
public function checkAccess($mask) {
$goodBoy = $this->RoleMark & $mask;
if (!$goodBoy) throw new LogicException(Error::ACCESS_DENIED);
}
public function isDean() {
return (bool) ($this->RoleMark & self::RIGHTS_DEAN);
}
public function isAdmin() {
return (bool) ($this->RoleMark & self::RIGHTS_ADMIN);
}
public function isTeacher() {
return (bool) ($this->RoleMark & self::RIGHTS_TEACHER);
}
public function isStudent() {
return (bool) ($this->RoleMark & self::RIGHTS_DEAN);
}
public function isAuthorized() {
return (bool) ($this->RoleMark & ~self::RIGHTS_ANYBODY);
}
Andrew Rudenets
committed
/**
* Регистрирует нового пользователя и осуществляет вход.
* Проверяет корректность кода активации и существование
* аккаунтов с такими же авторизационными данными.
Andrew Rudenets
committed
*
* @param string $email E-Mail адрес
* @param string $login
* @param string $password
* @return array Пару вида <tt>(is_ok, err_msg)</tt>
*/
public function signUp($code, $email, $login, $password) {
$isValid = Model_Account::isActivationCodeValid($code);
Andrew Rudenets
committed
return array(false, 'invalid_code');
}
$isLogin = $account->doesLoginExist($login);
$isMail = $account->isMailValid($email);
if ($isLogin) {
return array(false, 'login_exists');
} else {
if ($isMail) {
return array(false, 'mail_exists');
}
$id = Model_Account::activateAccount($login, $password, $email, $code);
$this->completeSignIn($id, $this->hash($password));
return array(true, 'ok');
Andrew Rudenets
committed
}
/**
Andrew Rudenets
committed
*
* @param string $login
* @param string $password
* @return bool true, если авторизация прошла успешно,
* и false, если данные являются некорректными.
*/
Andrew Rudenets
committed
public function signIn($login, $password) {
$id = (int)Model_Account::checkAuth($login, $password);
Andrew Rudenets
committed
return false;
Andrew Rudenets
committed
}
protected function completeSignIn($id, $passHash) {
$source = $id . Request::$user_agent . Request::$client_ip;
$userHash = $this->hash($source) . $this->_config['hash_key'];
$passwordHash = $this->hash($passHash . $this->_config['hash_key']);
$userInfo = Model_Account::getUserInfo($id);
$this->_session->set('UserInfo', $userInfo);
Andrew Rudenets
committed
$this->_session->regenerate();
$this->_session->set('ID', $id);
$this->_session->set('LoggedIn', true);
$this->_session->set('UserHash', $this->hash($userHash));
$this->_session->set('SemesterID', $userInfo['SemesterID']);
Andrew Rudenets
committed
/**
* Проверяет авторизационный статус пользователя и, если
* пользователь имеет UserAgent и IP, отличные от хранимых
* в сессии, осуществляет выход из текущего сеанса.
Andrew Rudenets
committed
*
* @return bool true, если пользователь авторизован
*/
public function isSignedIn() {
Andrew Rudenets
committed
}
return $this->_session->get('LoggedIn');
}
Andrew Rudenets
committed
$id = $this->_session->get('ID');
$source = $id . Request::$user_agent . Request::$client_ip;
$userHash = $this->hash($source) . $this->_config['hash_key'];
Andrew Rudenets
committed
$userCheck = $this->_session->get('UserHash') == $this->hash($userHash);
$passCheck = Cookie::get('userhash') == $this->_session->get('PasswordHash');
return $userCheck AND $passCheck;
Andrew Rudenets
committed
/**
* Завершает текущий сеанс пользователя.
* @return bool
*/
public function signOut() {
if ($this->isSignedIn()) {
Andrew Rudenets
committed
return $this->completeSignOut();
}
Andrew Rudenets
committed
}
protected function completeSignOut() {
$this->_session
->set('ID', false)
->set('LoggedIn', false)
->set('UserHash', false);
Andrew Rudenets
committed
Cookie::delete('userhash');
unset($this->_userInfo);
$this->_session->restart();
Andrew Rudenets
committed
}
/**
* Проверяет корректность данного пароля для текущего пользователя.
*
Andrew Rudenets
committed
public function checkPassword($password) {
if (!$this->isSignedIn())
return false;
$passHash = $this->hash($password);
$computed = $this->hash($passHash . $this->_config['hash_key']);
return $computed === $this->_session->get('PasswordHash');
Andrew Rudenets
committed
}
public function changePassword($old, $new) {
if (!$this->checkPassword($old))
return false;
Model_Account::changeAccountData($this->ID, $new, 'password');
$passhash = $this->hash($this->hash($new) . $this->_config['hash_key']);
Andrew Rudenets
committed
$this->_session->set('PasswordHash', $passhash);
Andrew Rudenets
committed
}
if (!$this->isSignedIn() || Account::instance()->doesLoginExist($login))
Model_Account::changeAccountData($this->ID, $login, 'login');
return true;
}
public function changeMail($email) {
if (!$this->isSignedIn() || Account::instance()->isMailValid($email))
$token = md5(time() . $this->EMail . $email);
Andrew Rudenets
committed
$this->_session->set('NewMail_Token', $token);
$this->_session->set('NewMail_Adress', $email);
return $token;
Andrew Rudenets
committed
$email = $this->_session->get('NewMail_Adress');
if ($token == $this->_session->get('NewMail_Token') AND !Account::instance()->isMailValid($email)) {
Model_Account::changeAccountData($this->ID, $email, 'email');
Andrew Rudenets
committed
return true;
Andrew Rudenets
committed
return false;
Model_Account::changeTeacherInfo($this['TeacherID'], $data['lastName'], $data['firstName'], $data['secondName'], $data['jobPositionID'], $data['departmentID']);
Andrew Rudenets
committed
/**
* Возвращает массив, содержащий пользовательские данные.
*
* @return array
*/
return $this->_userInfo + $this->_session->as_array();
// fixme: nobody knows what _session contains!
Andrew Rudenets
committed
}
Andrew Rudenets
committed
/* Fields access */
function __set($name, $value) {
$this->offsetSet($name, $value);
}
function __get($name) {
return $this->offsetGet($name);
}
Andrew Rudenets
committed
public function offsetSet($offset, $value) {
if ($this->_userInfo && array_key_exists($offset, $this->_userInfo)) {
$this->_userInfo[$offset] = $value;
} elseif (isset($offset, $this->_session)) {
$this->_session[$offset] = $value;
Andrew Rudenets
committed
}
}
public function offsetGet($offset) {
if ($this->_userInfo && array_key_exists($offset, $this->_userInfo))
Andrew Rudenets
committed
return $this->_userInfo[$offset];
return $this->_session[$offset];
throw new ErrorException('No such field');
Andrew Rudenets
committed
}
Andrew Rudenets
committed
public function offsetUnset($offset) {
if (array_key_exists($offset, $this->_userInfo))
Andrew Rudenets
committed
unset($this->_userInfo[$offset]);
Andrew Rudenets
committed
}
Andrew Rudenets
committed
public function offsetExists($offset) {
return array_key_exists($offset, $this->_userInfo) ||
isset($this->_session[$offset]);
Andrew Rudenets
committed
}
Andrew Rudenets
committed
/**
* Perform a hmac hash, using the configured method.
*
Andrew Rudenets
committed
* @return string
*/
protected function hash($str) {
if (!$this->_config['hash_key']) {
$this->_config['hash_key'] = $key = md5(time() . Request::$client_ip);
Andrew Rudenets
committed
}
return hash_hmac($this->_config['hash_method'], $str, $this->_config['hash_key']);