Improved Grav\Common\User class; added $user->update() method

This commit is contained in:
Matias Griese
2019-01-18 12:20:57 +02:00
parent 0afe9d4f93
commit 254fe990ba
2 changed files with 63 additions and 40 deletions

View File

@@ -15,12 +15,14 @@
* Added `arrayDiffMultidimensional`, `arrayIsAssociative`, `arrayCombine` Util functions * Added `arrayDiffMultidimensional`, `arrayIsAssociative`, `arrayCombine` Util functions
1. [](#improved) 1. [](#improved)
* Added method argument `Data::filter($missingValuesAsNull)`, defaulting to `false` * Added method argument `Data::filter($missingValuesAsNull)`, defaulting to `false`
* Improved `Grav\Common\User` class; added `$user->update()` method
1. [](#bugfix) 1. [](#bugfix)
* Fixed environment getting port added [#2284](https://github.com/getgrav/grav/issues/2284) * Fixed environment getting port added [#2284](https://github.com/getgrav/grav/issues/2284)
* Fixed `FlexForm::updateObject()` to update array values when they are empty in the form * Fixed `FlexForm::updateObject()` to update array values when they are empty in the form
* Fixed some issues related to Medium objects losing query string attributes * Fixed some issues related to Medium objects losing query string attributes
* Broke out Medium timestamp so it's not cleared on `reset()s` * Broke out Medium timestamp so it's not cleared on `reset()s`
* Fixed issue with `redirect_trailing_slash` losing query string [#2269](https://github.com/getgrav/grav/issues/2269) * Fixed issue with `redirect_trailing_slash` losing query string [#2269](https://github.com/getgrav/grav/issues/2269)
* Fixed failed login if user attempts to log in with upper case non-english letters
# v1.6.0-beta.7 # v1.6.0-beta.7
## 12/14/2018 ## 12/14/2018

View File

@@ -34,16 +34,17 @@ class User extends Data
$locator = $grav['locator']; $locator = $grav['locator'];
// force lowercase of username // force lowercase of username
$username = strtolower($username); $username = mb_strtolower($username);
$blueprints = new Blueprints; $blueprints = new Blueprints;
$blueprint = $blueprints->get('user/account'); $blueprint = $blueprints->get('user/account');
$file_path = $locator->findResource('account://' . $username . YAML_EXT); $filename = 'account://' . $username . YAML_EXT;
$file = CompiledYamlFile::instance($file_path); $path = $locator->findResource($filename) ?: $locator->findResource($filename, true, true);
$file = CompiledYamlFile::instance($path);
$content = (array)$file->content() + ['username' => $username, 'state' => 'enabled']; $content = (array)$file->content() + ['username' => $username, 'state' => 'enabled'];
$user = new User($content, $blueprint); $user = new static($content, $blueprint);
$user->file($file); $user->file($file);
return $user; return $user;
@@ -63,17 +64,17 @@ class User extends Data
// Try with username first, you never know! // Try with username first, you never know!
if (in_array('username', $fields, true)) { if (in_array('username', $fields, true)) {
$user = User::load($query); $user = static::load($query);
unset($fields[array_search('username', $fields, true)]); unset($fields[array_search('username', $fields, true)]);
} else { } else {
$user = User::load(''); $user = static::load('');
} }
// If not found, try the fields // If not found, try the fields
if (!$user->exists()) { if (!$user->exists()) {
foreach ($files as $file) { foreach ($files as $file) {
if (Utils::endsWith($file, YAML_EXT)) { if (Utils::endsWith($file, YAML_EXT)) {
$find_user = User::load(trim(pathinfo($file, PATHINFO_FILENAME))); $find_user = static::load(trim(pathinfo($file, PATHINFO_FILENAME)));
foreach ($fields as $field) { foreach ($fields as $field) {
if ($find_user[$field] === $query) { if ($find_user[$field] === $query) {
return $find_user; return $find_user;
@@ -146,8 +147,9 @@ class User extends Data
$save = false; $save = false;
// Plain-text is still stored // Plain-text is still stored
if ($this->password) { $storedPassword = $this->get('password');
if ($password !== $this->password) { if ($storedPassword) {
if ($password !== $storedPassword) {
// Plain-text passwords do not match, we know we should fail but execute // Plain-text passwords do not match, we know we should fail but execute
// verify to protect us from timing attacks and return false regardless of // verify to protect us from timing attacks and return false regardless of
// the result // the result
@@ -162,17 +164,16 @@ class User extends Data
// Plain-text does match, we can update the hash and proceed // Plain-text does match, we can update the hash and proceed
$save = true; $save = true;
$this->hashed_password = Authentication::create($this->password); $this->set('hashed_password', Authentication::create($storedPassword));
unset($this->password); $this->undef('password');
} }
$result = Authentication::verify($password, $this->hashed_password); $result = Authentication::verify($password, $this->get('hashed_password'));
// Password needs to be updated, save the file. // Password needs to be updated, save the file.
if ($result === 2) { if ($result === 2) {
$save = true; $save = true;
$this->hashed_password = Authentication::create($password); $this->set('hashed_password', Authentication::create($password));
} }
if ($save) { if ($save) {
@@ -182,28 +183,48 @@ class User extends Data
return (bool)$result; return (bool)$result;
} }
/**
* Replace all data
*
* WARNING: There are no checks! All the data will be replaced.
*
* @param array $data
* @return $this
*/
public function update(array $data)
{
$this->items = $data;
return $this;
}
/** /**
* Save user without the username * Save user without the username
*/ */
public function save() public function save()
{ {
/** @var CompiledYamlFile $file */
$file = $this->file(); $file = $this->file();
if (!$file || !$file->filename()) {
user_error(__CLASS__ . ": calling \$user = new User() is deprecated since Grav 1.6, use User::load(\$username) or User::load('') instead", E_USER_DEPRECATED);
}
if ($file) { if ($file) {
$username = $this->get('username'); $username = $this->get('username');
if (!$file->filename()) { if (!$file->filename()) {
$locator = Grav::instance()['locator']; $locator = Grav::instance()['locator'];
$file->filename($locator->findResource('account://') . DS . strtolower($username) . YAML_EXT); $file->filename($locator->findResource('account://' . mb_strtolower($username) . YAML_EXT, true, true));
} }
// if plain text password, hash it and remove plain text // if plain text password, hash it and remove plain text
if ($this->password) { $password = $this->get('password');
$this->hashed_password = Authentication::create($this->password); if ($password) {
unset($this->password); $this->set('hashed_password', Authentication::create($password));
$this->undef('password');
} }
unset($this->username); $this->undef('username');
$file->save($this->items); $file->save($this->items);
$this->set('username', $username); $this->set('username', $username);
} }
@@ -218,15 +239,11 @@ class User extends Data
*/ */
public function authorize($action) public function authorize($action)
{ {
if (empty($this->items)) { if (!$this->get('authenticated')) {
return false; return false;
} }
if (!$this->authenticated) { if ($this->get('state', 'enabled') !== 'enabled') {
return false;
}
if (isset($this->state) && $this->state !== 'enabled') {
return false; return false;
} }
@@ -245,11 +262,10 @@ class User extends Data
} }
//Check user access level //Check user access level
if ($this->get('access')) { $access = $this->get('access');
if (Utils::getDotNotation($this->get('access'), $action) !== null) { if ($access && Utils::getDotNotation($access, $action) !== null) {
$permission = $this->get("access.{$action}"); $permission = $this->get("access.{$action}");
$return = Utils::isPositive($permission); $return = Utils::isPositive($permission);
}
} }
return $return; return $return;
@@ -278,20 +294,25 @@ class User extends Data
*/ */
public function avatarUrl() public function avatarUrl()
{ {
if ($this->avatar) { $avatar = $this->get('avatar');
$avatar = $this->avatar; if ($avatar) {
$avatar = array_shift($avatar); $avatar = array_shift($avatar);
return Grav::instance()['base_url'] . '/' . $avatar['path'];
} elseif ($this->provider) { $path = $avatar['path'] ?? null;
$provider = $this->provider; if ($path) {
if (isset($this->$provider['avatar_url'])) { return Grav::instance()['base_url'] . '/' . $path;
return $this->$provider['avatar_url'];
} elseif (isset($this->$provider['avatar'])) {
return $this->$provider['avatar'];
} }
} }
return 'https://www.gravatar.com/avatar/' . md5($this->email); $provider = $this->get('provider');
if ($provider) {
$avatar = $this->{$provider}['avatar_url'] ?? $this->{$provider}['avatar'] ?? null;
if ($avatar) {
return $avatar;
}
}
return 'https://www.gravatar.com/avatar/' . md5($this->get('email'));
} }
/** /**