Update Composer packages
This commit is contained in:
parent
9252d9ce90
commit
134266af8a
176 changed files with 7930 additions and 2262 deletions
|
@ -67,10 +67,10 @@ class Api extends BaseApi
|
|||
* Returns the file object for the given
|
||||
* parent path and filename
|
||||
*
|
||||
* @param string|null $path Path to file's parent model
|
||||
* @param string $path Path to file's parent model
|
||||
* @throws \Kirby\Exception\NotFoundException if the file cannot be found
|
||||
*/
|
||||
public function file(string|null $path = null, string $filename): File|null
|
||||
public function file(string $path, string $filename): File|null
|
||||
{
|
||||
return Find::file($path, $filename);
|
||||
}
|
||||
|
|
|
@ -203,7 +203,6 @@ class App
|
|||
/**
|
||||
* Applies a hook to the given value
|
||||
*
|
||||
* @internal
|
||||
* @param string $name Full event name
|
||||
* @param array $args Associative array of named event arguments
|
||||
* @param string $modify Key in $args that is modified by the hooks
|
||||
|
@ -364,25 +363,23 @@ class App
|
|||
* by name. All relevant dependencies are
|
||||
* automatically injected
|
||||
*
|
||||
* @param string $name
|
||||
* @return \Kirby\Cms\Collection|null
|
||||
* @return \Kirby\Toolkit\Collection|null
|
||||
* @todo 5.0 Add return type declaration
|
||||
*/
|
||||
public function collection(string $name)
|
||||
public function collection(string $name, array $options = [])
|
||||
{
|
||||
return $this->collections()->get($name, [
|
||||
return $this->collections()->get($name, array_merge($options, [
|
||||
'kirby' => $this,
|
||||
'site' => $this->site(),
|
||||
'pages' => $this->site()->children(),
|
||||
'site' => $site = $this->site(),
|
||||
'pages' => $site->children(),
|
||||
'users' => $this->users()
|
||||
]);
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all user-defined collections
|
||||
*
|
||||
* @return \Kirby\Cms\Collections
|
||||
*/
|
||||
public function collections()
|
||||
public function collections(): Collections
|
||||
{
|
||||
return $this->collections ??= new Collections();
|
||||
}
|
||||
|
@ -582,7 +579,14 @@ class App
|
|||
$visitor = $this->visitor();
|
||||
|
||||
foreach ($visitor->acceptedLanguages() as $acceptedLang) {
|
||||
$closure = fn ($language) => $language->locale(LC_ALL) === $acceptedLang->locale();
|
||||
$closure = function ($language) use ($acceptedLang) {
|
||||
$languageLocale = $language->locale(LC_ALL);
|
||||
$acceptedLocale = $acceptedLang->locale();
|
||||
|
||||
return $languageLocale === $acceptedLocale ||
|
||||
$acceptedLocale === Str::substr($languageLocale, 0, 2);
|
||||
};
|
||||
|
||||
if ($language = $languages->filter($closure)?->first()) {
|
||||
return $language;
|
||||
}
|
||||
|
@ -1670,7 +1674,6 @@ class App
|
|||
/**
|
||||
* Trigger a hook by name
|
||||
*
|
||||
* @internal
|
||||
* @param string $name Full event name
|
||||
* @param array $args Associative array of named event arguments
|
||||
* @param \Kirby\Cms\Event|null $originalEvent Event object (internal use)
|
||||
|
|
|
@ -73,7 +73,7 @@ trait AppErrors
|
|||
$handler = null;
|
||||
|
||||
if ($this->option('debug') === true) {
|
||||
if ($this->option('whoops', true) === true) {
|
||||
if ($this->option('whoops', true) !== false) {
|
||||
$handler = new PrettyPageHandler();
|
||||
$handler->setPageTitle('Kirby CMS Debugger');
|
||||
$handler->setResourcesPath(dirname(__DIR__, 2) . '/assets');
|
||||
|
@ -82,6 +82,14 @@ trait AppErrors
|
|||
if ($editor = $this->option('editor')) {
|
||||
$handler->setEditor($editor);
|
||||
}
|
||||
|
||||
if ($blocklist = $this->option('whoops.blocklist')) {
|
||||
foreach ($blocklist as $superglobal => $vars) {
|
||||
foreach ($vars as $var) {
|
||||
$handler->blacklist($superglobal, $var);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$handler = new CallbackHandler(function ($exception, $inspector, $run) {
|
||||
|
|
|
@ -66,7 +66,7 @@ trait AppUsers
|
|||
} finally {
|
||||
// ensure that the impersonation is *always* reset
|
||||
// to the original value, even if an error occurred
|
||||
$auth->impersonate($userBefore !== null ? $userBefore->id() : null);
|
||||
$auth->impersonate($userBefore?->id());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -279,18 +279,39 @@ class Auth
|
|||
|
||||
$id = $session->data()->get('kirby.userId');
|
||||
|
||||
// if no user is logged in, return immediately
|
||||
if (is_string($id) !== true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($user = $this->kirby->users()->find($id)) {
|
||||
// in case the session needs to be updated, do it now
|
||||
// for better performance
|
||||
$session->commit();
|
||||
return $user;
|
||||
// a user is logged in, ensure it exists
|
||||
$user = $this->kirby->users()->find($id);
|
||||
if ($user === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
if ($passwordTimestamp = $user->passwordTimestamp()) {
|
||||
$loginTimestamp = $session->data()->get('kirby.loginTimestamp');
|
||||
if (is_int($loginTimestamp) !== true) {
|
||||
// session that was created before Kirby
|
||||
// 3.5.8.3, 3.6.6.3, 3.7.5.2, 3.8.4.1 or 3.9.6
|
||||
// or when the user didn't have a password set
|
||||
$user->logout();
|
||||
return null;
|
||||
}
|
||||
|
||||
// invalidate the session if the password
|
||||
// changed since the login
|
||||
if ($loginTimestamp < $passwordTimestamp) {
|
||||
$user->logout();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// in case the session needs to be updated, do it now
|
||||
// for better performance
|
||||
$session->commit();
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -66,9 +66,11 @@ class Collection extends BaseCollection
|
|||
}
|
||||
|
||||
/**
|
||||
* Internal setter for each object in the Collection.
|
||||
* This takes care of Component validation and of setting
|
||||
* the collection prop on each object correctly.
|
||||
* Internal setter for each object in the Collection;
|
||||
* override from the Toolkit Collection is needed to
|
||||
* make the CMS collections case-sensitive;
|
||||
* child classes can override it again to add validation
|
||||
* and custom behavior depending on the object type
|
||||
*
|
||||
* @param string $id
|
||||
* @param object $object
|
||||
|
@ -79,6 +81,16 @@ class Collection extends BaseCollection
|
|||
$this->data[$id] = $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal remover for each object in the Collection;
|
||||
* override from the Toolkit Collection is needed to
|
||||
* make the CMS collections case-sensitive
|
||||
*/
|
||||
public function __unset($id)
|
||||
{
|
||||
unset($this->data[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a single object or
|
||||
* an entire second collection to the
|
||||
|
@ -168,9 +180,7 @@ class Collection extends BaseCollection
|
|||
}
|
||||
|
||||
// ignore upper/lowercase for group names
|
||||
if ($i) {
|
||||
$value = Str::lower($value);
|
||||
}
|
||||
$value = $i === true ? Str::lower($value) : (string)$value;
|
||||
|
||||
if (isset($groups->data[$value]) === false) {
|
||||
// create a new entry for the group if it does not exist yet
|
||||
|
@ -209,9 +219,9 @@ class Collection extends BaseCollection
|
|||
* or ids and then search accordingly.
|
||||
*
|
||||
* @param string|object $needle
|
||||
* @return int
|
||||
* @return int|false
|
||||
*/
|
||||
public function indexOf($needle): int
|
||||
public function indexOf($needle): int|false
|
||||
{
|
||||
if (is_string($needle) === true) {
|
||||
return array_search($needle, $this->keys());
|
||||
|
|
|
@ -28,25 +28,20 @@ class Collections
|
|||
* has been called, to avoid further
|
||||
* processing on sequential calls to
|
||||
* the same collection.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $cache = [];
|
||||
protected array $cache = [];
|
||||
|
||||
/**
|
||||
* Store of all collections
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $collections = [];
|
||||
protected array $collections = [];
|
||||
|
||||
/**
|
||||
* Magic caller to enable something like
|
||||
* `$collections->myCollection()`
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return \Kirby\Cms\Collection|null
|
||||
* @return \Kirby\Toolkit\Collection|null
|
||||
* @todo 5.0 Add return type declaration
|
||||
*/
|
||||
public function __call(string $name, array $arguments = [])
|
||||
{
|
||||
|
@ -56,9 +51,9 @@ class Collections
|
|||
/**
|
||||
* Loads a collection by name if registered
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
* @return \Kirby\Cms\Collection|null
|
||||
* @return \Kirby\Toolkit\Collection|null
|
||||
* @todo 4.0 Add deprecation warning when anything else than a Collection is returned
|
||||
* @todo 5.0 Add return type declaration
|
||||
*/
|
||||
public function get(string $name, array $data = [])
|
||||
{
|
||||
|
|
|
@ -207,7 +207,7 @@ class FileRules
|
|||
if (
|
||||
Str::contains($extension, 'php') !== false ||
|
||||
Str::contains($extension, 'phar') !== false ||
|
||||
Str::contains($extension, 'phtml') !== false
|
||||
Str::contains($extension, 'pht') !== false
|
||||
) {
|
||||
throw new InvalidArgumentException([
|
||||
'key' => 'file.type.forbidden',
|
||||
|
|
|
@ -23,12 +23,12 @@ class Find
|
|||
* Returns the file object for the given
|
||||
* parent path and filename
|
||||
*
|
||||
* @param string|null $path Path to file's parent model
|
||||
* @param string $path Path to file's parent model
|
||||
* @param string $filename Filename
|
||||
* @return \Kirby\Cms\File|null
|
||||
* @throws \Kirby\Exception\NotFoundException if the file cannot be found
|
||||
*/
|
||||
public static function file(string $path = null, string $filename)
|
||||
public static function file(string $path, string $filename)
|
||||
{
|
||||
$filename = urldecode($filename);
|
||||
$file = static::parent($path)->file($filename);
|
||||
|
@ -121,7 +121,10 @@ class Find
|
|||
'site' => $kirby->site(),
|
||||
'account' => static::user(),
|
||||
'page' => static::page(basename($path)),
|
||||
'file' => static::file(...explode('/files/', $path)),
|
||||
// regular expression to split the path at the last
|
||||
// occurrence of /files/ which separates parent path
|
||||
// and filename
|
||||
'file' => static::file(...preg_split('$.*\K(/files/)$', $path)),
|
||||
'user' => $kirby->user(basename($path)),
|
||||
default => throw new InvalidArgumentException('Invalid model type: ' . $modelType)
|
||||
};
|
||||
|
|
|
@ -95,7 +95,7 @@ trait HasFiles
|
|||
|
||||
// find by global UUID
|
||||
if (Uuid::is($filename, 'file') === true) {
|
||||
return Uuid::for($filename, $this->files())->model();
|
||||
return Uuid::for($filename, $this->$in())->model();
|
||||
}
|
||||
|
||||
if (strpos($filename, '/') !== false) {
|
||||
|
|
|
@ -19,9 +19,9 @@ trait HasSiblings
|
|||
*
|
||||
* @param \Kirby\Cms\Collection|null $collection
|
||||
*
|
||||
* @return int
|
||||
* @return int|false
|
||||
*/
|
||||
public function indexOf($collection = null): int
|
||||
public function indexOf($collection = null): int|false
|
||||
{
|
||||
$collection ??= $this->siblingsCollection();
|
||||
return $collection->indexOf($this);
|
||||
|
@ -29,10 +29,13 @@ trait HasSiblings
|
|||
|
||||
/**
|
||||
* Returns the next item in the collection if available
|
||||
* @todo `static` return type hint is not 100% accurate because of
|
||||
* quirks in the `Form` classes; would break if enforced
|
||||
* (https://github.com/getkirby/kirby/pull/5175)
|
||||
*
|
||||
* @param \Kirby\Cms\Collection|null $collection
|
||||
*
|
||||
* @return \Kirby\Cms\Model|null
|
||||
* @return static|null
|
||||
*/
|
||||
public function next($collection = null)
|
||||
{
|
||||
|
@ -55,10 +58,13 @@ trait HasSiblings
|
|||
|
||||
/**
|
||||
* Returns the previous item in the collection if available
|
||||
* @todo `static` return type hint is not 100% accurate because of
|
||||
* quirks in the `Form` classes; would break if enforced
|
||||
* (https://github.com/getkirby/kirby/pull/5175)
|
||||
*
|
||||
* @param \Kirby\Cms\Collection|null $collection
|
||||
*
|
||||
* @return \Kirby\Cms\Model|null
|
||||
* @return static|null
|
||||
*/
|
||||
public function prev($collection = null)
|
||||
{
|
||||
|
|
|
@ -201,8 +201,17 @@ class Language extends Model
|
|||
*/
|
||||
public static function create(array $props)
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$user = $kirby->user();
|
||||
|
||||
if (
|
||||
$user === null ||
|
||||
$user->role()->permissions()->for('languages', 'create') === false
|
||||
) {
|
||||
throw new PermissionException(['key' => 'language.create.permission']);
|
||||
}
|
||||
|
||||
$props['code'] = Str::slug($props['code'] ?? null);
|
||||
$kirby = App::instance();
|
||||
$languages = $kirby->languages();
|
||||
|
||||
// make the first language the default language
|
||||
|
@ -256,10 +265,18 @@ class Language extends Model
|
|||
public function delete(): bool
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$user = $kirby->user();
|
||||
$languages = $kirby->languages();
|
||||
$code = $this->code();
|
||||
$isLast = $languages->count() === 1;
|
||||
|
||||
if (
|
||||
$user === null ||
|
||||
$user->role()->permissions()->for('languages', 'delete') === false
|
||||
) {
|
||||
throw new PermissionException(['key' => 'language.delete.permission']);
|
||||
}
|
||||
|
||||
// trigger before hook
|
||||
$kirby->trigger('language.delete:before', [
|
||||
'language' => $this
|
||||
|
@ -672,13 +689,22 @@ class Language extends Model
|
|||
*/
|
||||
public function update(array $props = null)
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$user = $kirby->user();
|
||||
|
||||
if (
|
||||
$user === null ||
|
||||
$user->role()->permissions()->for('languages', 'update') === false
|
||||
) {
|
||||
throw new PermissionException(['key' => 'language.update.permission']);
|
||||
}
|
||||
|
||||
// don't change the language code
|
||||
unset($props['code']);
|
||||
|
||||
// make sure the slug is nice and clean
|
||||
$props['slug'] = Str::slug($props['slug'] ?? null);
|
||||
|
||||
$kirby = App::instance();
|
||||
$updated = $this->clone($props);
|
||||
|
||||
// validate the updated language
|
||||
|
|
|
@ -733,7 +733,7 @@ class Page extends ModelWithContent
|
|||
*/
|
||||
public function isListed(): bool
|
||||
{
|
||||
return $this->num() !== null;
|
||||
return $this->isPublished() && $this->num() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -797,7 +797,7 @@ class Page extends ModelWithContent
|
|||
*/
|
||||
public function isUnlisted(): bool
|
||||
{
|
||||
return $this->isListed() === false;
|
||||
return $this->isPublished() && $this->num() === null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -811,7 +811,7 @@ class Page extends ModelWithContent
|
|||
public function isVerified(string $token = null)
|
||||
{
|
||||
if (
|
||||
$this->isDraft() === false &&
|
||||
$this->isPublished() === true &&
|
||||
$this->parents()->findBy('status', 'draft') === null
|
||||
) {
|
||||
return true;
|
||||
|
|
|
@ -270,9 +270,9 @@ class Pages extends Collection
|
|||
$query = $startAt;
|
||||
|
||||
foreach ($path as $key) {
|
||||
$collection = $item ? $item->children() : $this;
|
||||
$query = ltrim($query . '/' . $key, '/');
|
||||
$item = $collection->get($query) ?? null;
|
||||
$collection = $item?->children() ?? $this;
|
||||
$query = ltrim($query . '/' . $key, '/');
|
||||
$item = $collection->get($query) ?? null;
|
||||
|
||||
if ($item === null && $multiLang === true && !App::instance()->language()->isDefault()) {
|
||||
if (count($path) > 1 || $collection->parent()) {
|
||||
|
|
|
@ -44,7 +44,8 @@ class Permissions
|
|||
],
|
||||
'languages' => [
|
||||
'create' => true,
|
||||
'delete' => true
|
||||
'delete' => true,
|
||||
'update' => true
|
||||
],
|
||||
'pages' => [
|
||||
'changeSlug' => true,
|
||||
|
|
|
@ -206,6 +206,20 @@ class UpdateStatus
|
|||
];
|
||||
}
|
||||
|
||||
// add special message for end-of-life PHP versions
|
||||
$phpMajor = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;
|
||||
$phpEol = $this->data['php'][$phpMajor] ?? null;
|
||||
if (is_string($phpEol) === true && $eolTime = strtotime($phpEol)) {
|
||||
// the timestamp is available and valid, now check if it is in the past
|
||||
if ($eolTime < time()) {
|
||||
$messages[] = [
|
||||
'text' => I18n::template('system.issues.eol.php', null, ['release' => $phpMajor]),
|
||||
'link' => 'https://getkirby.com/security/php-end-of-life',
|
||||
'icon' => 'bell'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->messages = $messages;
|
||||
}
|
||||
|
||||
|
|
|
@ -352,7 +352,7 @@ class User extends ModelWithContent
|
|||
*/
|
||||
public function isKirby(): bool
|
||||
{
|
||||
return $this->email() === 'kirby@getkirby.com';
|
||||
return $this->isAdmin() && $this->id() === 'kirby';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -396,7 +396,7 @@ class User extends ModelWithContent
|
|||
*/
|
||||
public function isNobody(): bool
|
||||
{
|
||||
return $this->email() === 'nobody@getkirby.com';
|
||||
return $this->role()->id() === 'nobody' && $this->id() === 'nobody';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -406,7 +406,9 @@ class User extends ModelWithContent
|
|||
*/
|
||||
public function language(): string
|
||||
{
|
||||
return $this->language ??= $this->credentials()['language'] ?? $this->kirby()->panelLanguage();
|
||||
return $this->language ??=
|
||||
$this->credentials()['language'] ??
|
||||
$this->kirby()->panelLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -441,6 +443,9 @@ class User extends ModelWithContent
|
|||
|
||||
$session->regenerateToken(); // privilege change
|
||||
$session->data()->set('kirby.userId', $this->id());
|
||||
if ($this->passwordTimestamp() !== null) {
|
||||
$session->data()->set('kirby.loginTimestamp', time());
|
||||
}
|
||||
$this->kirby()->auth()->setUser($this);
|
||||
|
||||
$kirby->trigger('user.login:after', ['user' => $this, 'session' => $session]);
|
||||
|
@ -461,6 +466,7 @@ class User extends ModelWithContent
|
|||
|
||||
// remove the user from the session for future requests
|
||||
$session->data()->remove('kirby.userId');
|
||||
$session->data()->remove('kirby.loginTimestamp');
|
||||
|
||||
// clear the cached user object from the app state of the current request
|
||||
$this->kirby()->auth()->flush();
|
||||
|
@ -607,6 +613,26 @@ class User extends ModelWithContent
|
|||
return $this->password = $this->readPassword();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp when the password
|
||||
* was last changed
|
||||
*/
|
||||
public function passwordTimestamp(): int|null
|
||||
{
|
||||
$file = $this->passwordFile();
|
||||
|
||||
// ensure we have the latest information
|
||||
// to prevent cache attacks
|
||||
clearstatcache();
|
||||
|
||||
// user does not have a password
|
||||
if (is_file($file) === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return filemtime($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Kirby\Cms\UserPermissions
|
||||
*/
|
||||
|
@ -864,14 +890,29 @@ class User extends ModelWithContent
|
|||
throw new NotFoundException(['key' => 'user.password.undefined']);
|
||||
}
|
||||
|
||||
// `UserRules` enforces a minimum length of 8 characters,
|
||||
// so everything below that is a typo
|
||||
if (Str::length($password) < 8) {
|
||||
throw new InvalidArgumentException(['key' => 'user.password.invalid']);
|
||||
}
|
||||
|
||||
// too long passwords can cause DoS attacks
|
||||
if (Str::length($password) > 1000) {
|
||||
throw new InvalidArgumentException(['key' => 'user.password.excessive']);
|
||||
}
|
||||
|
||||
if (password_verify($password, $this->password()) !== true) {
|
||||
throw new InvalidArgumentException(['key' => 'user.password.wrong', 'httpCode' => 401]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the password file
|
||||
*/
|
||||
protected function passwordFile(): string
|
||||
{
|
||||
return $this->root() . '/.htpasswd';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,6 +118,13 @@ trait UserActions
|
|||
// update the users collection
|
||||
$user->kirby()->users()->set($user->id(), $user);
|
||||
|
||||
// keep the user logged in to the current browser
|
||||
// if they changed their own password
|
||||
// (regenerate the session token, update the login timestamp)
|
||||
if ($user->isLoggedIn() === true) {
|
||||
$user->loginPasswordless();
|
||||
}
|
||||
|
||||
return $user;
|
||||
});
|
||||
}
|
||||
|
@ -323,7 +330,7 @@ trait UserActions
|
|||
*/
|
||||
protected function readPassword()
|
||||
{
|
||||
return F::read($this->root() . '/.htpasswd');
|
||||
return F::read($this->passwordFile());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -384,6 +391,6 @@ trait UserActions
|
|||
#[SensitiveParameter]
|
||||
string $password = null
|
||||
): bool {
|
||||
return F::write($this->root() . '/.htpasswd', $password);
|
||||
return F::write($this->passwordFile(), $password);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -301,8 +301,8 @@ class UserRules
|
|||
*/
|
||||
public static function validId(User $user, string $id): bool
|
||||
{
|
||||
if ($id === 'account') {
|
||||
throw new InvalidArgumentException('"account" is a reserved word and cannot be used as user id');
|
||||
if (in_array($id, ['account', 'kirby', 'nobody']) === true) {
|
||||
throw new InvalidArgumentException('"' . $id . '" is a reserved word and cannot be used as user id');
|
||||
}
|
||||
|
||||
if ($user->kirby()->users()->find($id)) {
|
||||
|
@ -341,12 +341,23 @@ class UserRules
|
|||
#[SensitiveParameter]
|
||||
string $password
|
||||
): bool {
|
||||
// too short passwords are ineffective
|
||||
if (Str::length($password ?? null) < 8) {
|
||||
throw new InvalidArgumentException([
|
||||
'key' => 'user.password.invalid',
|
||||
]);
|
||||
}
|
||||
|
||||
// too long passwords can cause DoS attacks
|
||||
// and are therefore blocked in the auth system
|
||||
// (blocked here as well to avoid passwords
|
||||
// that cannot be used to log in)
|
||||
if (Str::length($password ?? null) > 1000) {
|
||||
throw new InvalidArgumentException([
|
||||
'key' => 'user.password.excessive',
|
||||
]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue