Upgrade to 3.2.3
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "getkirby/cms",
|
"name": "getkirby/cms",
|
||||||
"description": "The Kirby 3 core",
|
"description": "The Kirby 3 core",
|
||||||
"version": "3.2.2",
|
"version": "3.2.3",
|
||||||
"license": "proprietary",
|
"license": "proprietary",
|
||||||
"keywords": ["kirby", "cms", "core"],
|
"keywords": ["kirby", "cms", "core"],
|
||||||
"homepage": "https://getkirby.com",
|
"homepage": "https://getkirby.com",
|
||||||
|
@@ -35,7 +35,7 @@ return [
|
|||||||
'requirements' => function (System $system) {
|
'requirements' => function (System $system) {
|
||||||
return $system->toArray();
|
return $system->toArray();
|
||||||
},
|
},
|
||||||
'breadcrumbTitle' => function () {
|
'site' => function () {
|
||||||
try {
|
try {
|
||||||
return $this->site()->blueprint()->title();
|
return $this->site()->blueprint()->title();
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
@@ -90,7 +90,6 @@ return [
|
|||||||
],
|
],
|
||||||
'panel' => [
|
'panel' => [
|
||||||
'ascii',
|
'ascii',
|
||||||
'breadcrumbTitle',
|
|
||||||
'isOk',
|
'isOk',
|
||||||
'isInstalled',
|
'isInstalled',
|
||||||
'isLocal',
|
'isLocal',
|
||||||
@@ -99,6 +98,7 @@ return [
|
|||||||
'license',
|
'license',
|
||||||
'multilang',
|
'multilang',
|
||||||
'requirements',
|
'requirements',
|
||||||
|
'site',
|
||||||
'slugs',
|
'slugs',
|
||||||
'title',
|
'title',
|
||||||
'translation',
|
'translation',
|
||||||
|
@@ -35,25 +35,13 @@ return [
|
|||||||
$long = $this->requestBody('long');
|
$long = $this->requestBody('long');
|
||||||
$password = $this->requestBody('password');
|
$password = $this->requestBody('password');
|
||||||
|
|
||||||
try {
|
$user = $this->kirby()->auth()->login($email, $password, $long);
|
||||||
if ($user = $this->kirby()->auth()->login($email, $password, $long)) {
|
|
||||||
return [
|
|
||||||
'code' => 200,
|
|
||||||
'status' => 'ok',
|
|
||||||
'user' => $this->resolve($user)->view('auth')->toArray()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new NotFoundException(['key' => 'user.undefined']);
|
return [
|
||||||
} catch (Throwable $e) {
|
'code' => 200,
|
||||||
if ($this->kirby()->option('debug') === true) {
|
'status' => 'ok',
|
||||||
throw $e;
|
'user' => $this->resolve($user)->view('auth')->toArray()
|
||||||
} else {
|
];
|
||||||
// catch any kind of login error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new InvalidArgumentException('Invalid email or password');
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@@ -1,37 +1,70 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Kirby\Exception\Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Content Lock Routes
|
* Content Lock Routes
|
||||||
*/
|
*/
|
||||||
return [
|
return [
|
||||||
|
|
||||||
[
|
[
|
||||||
'pattern' => '(:all)/lock',
|
'pattern' => '(:all)/lock',
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
'action' => function (string $path) {
|
'action' => function (string $path) {
|
||||||
return $this->parent($path)->lock()->get();
|
if ($lock = $this->parent($path)->lock()) {
|
||||||
|
return [
|
||||||
|
'supported' => true,
|
||||||
|
'locked' => $lock->get()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'supported' => false,
|
||||||
|
'locked' => null
|
||||||
|
];
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'pattern' => '(:all)/lock',
|
'pattern' => '(:all)/lock',
|
||||||
'method' => 'PATCH',
|
'method' => 'PATCH',
|
||||||
'action' => function (string $path) {
|
'action' => function (string $path) {
|
||||||
return $this->parent($path)->lock()->create();
|
if ($lock = $this->parent($path)->lock()) {
|
||||||
|
return $lock->create();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception([
|
||||||
|
'key' => 'lock.notImplemented',
|
||||||
|
'httpCode' => 501
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'pattern' => '(:all)/lock',
|
'pattern' => '(:all)/lock',
|
||||||
'method' => 'DELETE',
|
'method' => 'DELETE',
|
||||||
'action' => function (string $path) {
|
'action' => function (string $path) {
|
||||||
return $this->parent($path)->lock()->remove();
|
if ($lock = $this->parent($path)->lock()) {
|
||||||
|
return $lock->remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception([
|
||||||
|
'key' => 'lock.notImplemented',
|
||||||
|
'httpCode' => 501
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'pattern' => '(:all)/unlock',
|
'pattern' => '(:all)/unlock',
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
'action' => function (string $path) {
|
'action' => function (string $path) {
|
||||||
|
if ($lock = $this->parent($path)->lock()) {
|
||||||
|
return [
|
||||||
|
'supported' => true,
|
||||||
|
'unlocked' => $lock->isUnlocked()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'isUnlocked' => $this->parent($path)->lock()->isUnlocked()
|
'supported' => false,
|
||||||
|
'unlocked' => null
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -39,14 +72,28 @@ return [
|
|||||||
'pattern' => '(:all)/unlock',
|
'pattern' => '(:all)/unlock',
|
||||||
'method' => 'PATCH',
|
'method' => 'PATCH',
|
||||||
'action' => function (string $path) {
|
'action' => function (string $path) {
|
||||||
return $this->parent($path)->lock()->unlock();
|
if ($lock = $this->parent($path)->lock()) {
|
||||||
|
return $lock->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception([
|
||||||
|
'key' => 'lock.notImplemented',
|
||||||
|
'httpCode' => 501
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'pattern' => '(:all)/unlock',
|
'pattern' => '(:all)/unlock',
|
||||||
'method' => 'DELETE',
|
'method' => 'DELETE',
|
||||||
'action' => function (string $path) {
|
'action' => function (string $path) {
|
||||||
return $this->parent($path)->lock()->resolve();
|
if ($lock = $this->parent($path)->lock()) {
|
||||||
|
return $lock->resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception([
|
||||||
|
'key' => 'lock.notImplemented',
|
||||||
|
'httpCode' => 501
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@@ -82,7 +82,7 @@ return [
|
|||||||
$files = $this->parent->files()->template($this->template);
|
$files = $this->parent->files()->template($this->template);
|
||||||
|
|
||||||
if ($this->sortBy) {
|
if ($this->sortBy) {
|
||||||
$files = $files->sortBy(...Str::split($this->sortBy, ' '));
|
$files = $files->sortBy(...$files::sortArgs($this->sortBy));
|
||||||
} elseif ($this->sortable === true) {
|
} elseif ($this->sortable === true) {
|
||||||
$files = $files->sortBy('sort', 'asc');
|
$files = $files->sortBy('sort', 'asc');
|
||||||
}
|
}
|
||||||
|
@@ -122,7 +122,7 @@ return [
|
|||||||
|
|
||||||
// sort
|
// sort
|
||||||
if ($this->sortBy) {
|
if ($this->sortBy) {
|
||||||
$pages = $pages->sortBy(...Str::split($this->sortBy, ' '));
|
$pages = $pages->sortBy(...$pages::sortArgs($this->sortBy));
|
||||||
}
|
}
|
||||||
|
|
||||||
// pagination
|
// pagination
|
||||||
|
@@ -106,7 +106,7 @@ return [
|
|||||||
if (empty($tag->link) === true) {
|
if (empty($tag->link) === true) {
|
||||||
return $img;
|
return $img;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($link = $tag->file($tag->link)) {
|
if ($link = $tag->file($tag->link)) {
|
||||||
$link = $link->url();
|
$link = $link->url();
|
||||||
} else {
|
} else {
|
||||||
@@ -227,13 +227,15 @@ return [
|
|||||||
'html' => function ($tag) {
|
'html' => function ($tag) {
|
||||||
$video = Html::video(
|
$video = Html::video(
|
||||||
$tag->value,
|
$tag->value,
|
||||||
$tag->kirby()->option('kirbytext.video.options', [])
|
$tag->kirby()->option('kirbytext.video.options', []),
|
||||||
|
[
|
||||||
|
'height' => $tag->height ?? $tag->kirby()->option('kirbytext.video.height'),
|
||||||
|
'width' => $tag->width ?? $tag->kirby()->option('kirbytext.video.width'),
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return Html::figure([$video], $tag->caption, [
|
return Html::figure([$video], $tag->caption, [
|
||||||
'class' => $tag->class ?? $tag->kirby()->option('kirbytext.video.class', 'video'),
|
'class' => $tag->class ?? $tag->kirby()->option('kirbytext.video.class', 'video'),
|
||||||
'height' => $tag->height ?? $tag->kirby()->option('kirbytext.video.height'),
|
|
||||||
'width' => $tag->width ?? $tag->kirby()->option('kirbytext.video.width'),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Отляво надясно",
|
"language.direction.ltr": "Отляво надясно",
|
||||||
"language.direction.rtl": "Отдясно наляво",
|
"language.direction.rtl": "Отдясно наляво",
|
||||||
"language.locale": "PHP locale string",
|
"language.locale": "PHP locale string",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Име",
|
"language.name": "Име",
|
||||||
"language.updated": "Езикът беше обновен",
|
"language.updated": "Езикът беше обновен",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Esquerra a dreta",
|
"language.direction.ltr": "Esquerra a dreta",
|
||||||
"language.direction.rtl": "De dreta a esquerra",
|
"language.direction.rtl": "De dreta a esquerra",
|
||||||
"language.locale": "Cadena local de PHP",
|
"language.locale": "Cadena local de PHP",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Nom",
|
"language.name": "Nom",
|
||||||
"language.updated": "S'ha actualitzat l'idioma",
|
"language.updated": "S'ha actualitzat l'idioma",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Zleva doprava",
|
"language.direction.ltr": "Zleva doprava",
|
||||||
"language.direction.rtl": "Zprava doleva",
|
"language.direction.rtl": "Zprava doleva",
|
||||||
"language.locale": "Řetězec lokalizace PHP",
|
"language.locale": "Řetězec lokalizace PHP",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Jméno",
|
"language.name": "Jméno",
|
||||||
"language.updated": "Jazyk byl aktualizován",
|
"language.updated": "Jazyk byl aktualizován",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Venstre mod højre",
|
"language.direction.ltr": "Venstre mod højre",
|
||||||
"language.direction.rtl": "Højre mod venstre",
|
"language.direction.rtl": "Højre mod venstre",
|
||||||
"language.locale": "PHP locale string",
|
"language.locale": "PHP locale string",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Navn",
|
"language.name": "Navn",
|
||||||
"language.updated": "Sproget er blevet opdateret",
|
"language.updated": "Sproget er blevet opdateret",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Von links nach rechts",
|
"language.direction.ltr": "Von links nach rechts",
|
||||||
"language.direction.rtl": "Von rechts nach links",
|
"language.direction.rtl": "Von rechts nach links",
|
||||||
"language.locale": "PHP locale string",
|
"language.locale": "PHP locale string",
|
||||||
|
"language.locale.warning": "Du nutzt ein angepasstes Setup for PHP Locales. Bitte bearbeite dieses direkt in der entsprechenden Sprachdatei in /site/languages",
|
||||||
"language.name": "Name",
|
"language.name": "Name",
|
||||||
"language.updated": "Die Sprache wurde gespeichert",
|
"language.updated": "Die Sprache wurde gespeichert",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Αριστερά προς τα δεξιά",
|
"language.direction.ltr": "Αριστερά προς τα δεξιά",
|
||||||
"language.direction.rtl": "Δεξιά προς τα αριστερά",
|
"language.direction.rtl": "Δεξιά προς τα αριστερά",
|
||||||
"language.locale": "Συμβολοσειρά τοπικής γλώσσας PHP",
|
"language.locale": "Συμβολοσειρά τοπικής γλώσσας PHP",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Ονομασία",
|
"language.name": "Ονομασία",
|
||||||
"language.updated": "Η γλώσσα έχει ενημερωθεί",
|
"language.updated": "Η γλώσσα έχει ενημερωθεί",
|
||||||
|
|
||||||
|
@@ -169,7 +169,6 @@
|
|||||||
"error.user.password.notSame": "The passwords do not match",
|
"error.user.password.notSame": "The passwords do not match",
|
||||||
"error.user.password.undefined": "The user does not have a password",
|
"error.user.password.undefined": "The user does not have a password",
|
||||||
"error.user.role.invalid": "Please enter a valid role",
|
"error.user.role.invalid": "Please enter a valid role",
|
||||||
"error.user.undefined": "The user cannot be found",
|
|
||||||
"error.user.update.permission":
|
"error.user.update.permission":
|
||||||
"You are not allowed to update the user \"{name}\"",
|
"You are not allowed to update the user \"{name}\"",
|
||||||
|
|
||||||
@@ -265,6 +264,7 @@
|
|||||||
"language.direction.ltr": "Left to right",
|
"language.direction.ltr": "Left to right",
|
||||||
"language.direction.rtl": "Right to left",
|
"language.direction.rtl": "Right to left",
|
||||||
"language.locale": "PHP locale string",
|
"language.locale": "PHP locale string",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Name",
|
"language.name": "Name",
|
||||||
"language.updated": "The language has been updated",
|
"language.updated": "The language has been updated",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "De Izquierda a derecha",
|
"language.direction.ltr": "De Izquierda a derecha",
|
||||||
"language.direction.rtl": "De derecha a izquierda",
|
"language.direction.rtl": "De derecha a izquierda",
|
||||||
"language.locale": "Cadena de localización PHP",
|
"language.locale": "Cadena de localización PHP",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Nombre",
|
"language.name": "Nombre",
|
||||||
"language.updated": "El idioma a sido actualizado",
|
"language.updated": "El idioma a sido actualizado",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "De izquierda a derecha",
|
"language.direction.ltr": "De izquierda a derecha",
|
||||||
"language.direction.rtl": "De derecha a izquierda",
|
"language.direction.rtl": "De derecha a izquierda",
|
||||||
"language.locale": "PHP locale string",
|
"language.locale": "PHP locale string",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Nombre",
|
"language.name": "Nombre",
|
||||||
"language.updated": "El idioma ha sido actualizado",
|
"language.updated": "El idioma ha sido actualizado",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "چپ به راست",
|
"language.direction.ltr": "چپ به راست",
|
||||||
"language.direction.rtl": "راست به چپ",
|
"language.direction.rtl": "راست به چپ",
|
||||||
"language.locale": "PHP locale string",
|
"language.locale": "PHP locale string",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "پارسی",
|
"language.name": "پارسی",
|
||||||
"language.updated": "زبان به روز شد",
|
"language.updated": "زبان به روز شد",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Vasemmalta oikealle",
|
"language.direction.ltr": "Vasemmalta oikealle",
|
||||||
"language.direction.rtl": "Oikealta vasemmalle",
|
"language.direction.rtl": "Oikealta vasemmalle",
|
||||||
"language.locale": "PHP-lokaalin tunniste",
|
"language.locale": "PHP-lokaalin tunniste",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Nimi",
|
"language.name": "Nimi",
|
||||||
"language.updated": "Kieli on päivitetty",
|
"language.updated": "Kieli on päivitetty",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "De gauche à droite",
|
"language.direction.ltr": "De gauche à droite",
|
||||||
"language.direction.rtl": "De droite à gauche",
|
"language.direction.rtl": "De droite à gauche",
|
||||||
"language.locale": "Locales PHP",
|
"language.locale": "Locales PHP",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Nom",
|
"language.name": "Nom",
|
||||||
"language.updated": "La langue a été mise à jour",
|
"language.updated": "La langue a été mise à jour",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Balról jobbra",
|
"language.direction.ltr": "Balról jobbra",
|
||||||
"language.direction.rtl": "Jobbról balra",
|
"language.direction.rtl": "Jobbról balra",
|
||||||
"language.locale": "PHP locale sztring",
|
"language.locale": "PHP locale sztring",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Név",
|
"language.name": "Név",
|
||||||
"language.updated": "A nyelv frissítve lett",
|
"language.updated": "A nyelv frissítve lett",
|
||||||
|
|
||||||
|
@@ -183,9 +183,9 @@
|
|||||||
"error.validation.contains":
|
"error.validation.contains":
|
||||||
"Masukkan nilai yang mengandung \"{needle}\"",
|
"Masukkan nilai yang mengandung \"{needle}\"",
|
||||||
"error.validation.date": "Masukkan tanggal yang valid",
|
"error.validation.date": "Masukkan tanggal yang valid",
|
||||||
"error.validation.date.after": "Please enter a date after {date}",
|
"error.validation.date.after": "Masukkan tanggal setelah {date}",
|
||||||
"error.validation.date.before": "Please enter a date before {date}",
|
"error.validation.date.before": "Masukkan tanggal sebelum {date}",
|
||||||
"error.validation.date.between": "Please enter a date between {min} and {max}",
|
"error.validation.date.between": "Masukkan tanggal antara {min} dan {max}",
|
||||||
"error.validation.denied": "Mohon tolak",
|
"error.validation.denied": "Mohon tolak",
|
||||||
"error.validation.different": "Nilai harus selain \"{other}\"",
|
"error.validation.different": "Nilai harus selain \"{other}\"",
|
||||||
"error.validation.email": "Masukkan surel yang valid",
|
"error.validation.email": "Masukkan surel yang valid",
|
||||||
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Kiri ke kanan",
|
"language.direction.ltr": "Kiri ke kanan",
|
||||||
"language.direction.rtl": "Kanan ke kiri",
|
"language.direction.rtl": "Kanan ke kiri",
|
||||||
"language.locale": "String \"PHP locale\"",
|
"language.locale": "String \"PHP locale\"",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Nama",
|
"language.name": "Nama",
|
||||||
"language.updated": "Bahasa sudah diperbaharui",
|
"language.updated": "Bahasa sudah diperbaharui",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Sinistra a destra",
|
"language.direction.ltr": "Sinistra a destra",
|
||||||
"language.direction.rtl": "Destra a sinistra",
|
"language.direction.rtl": "Destra a sinistra",
|
||||||
"language.locale": "Stringa \"PHP locale\"",
|
"language.locale": "Stringa \"PHP locale\"",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Nome",
|
"language.name": "Nome",
|
||||||
"language.updated": "La lingua è stata aggiornata",
|
"language.updated": "La lingua è stata aggiornata",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "왼쪽에서 오른쪽",
|
"language.direction.ltr": "왼쪽에서 오른쪽",
|
||||||
"language.direction.rtl": "오른쪽에서 왼쪽",
|
"language.direction.rtl": "오른쪽에서 왼쪽",
|
||||||
"language.locale": "PHP 로캘 문자열",
|
"language.locale": "PHP 로캘 문자열",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "이름",
|
"language.name": "이름",
|
||||||
"language.updated": "언어를 변경했습니다.",
|
"language.updated": "언어를 변경했습니다.",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Venstre til høyre",
|
"language.direction.ltr": "Venstre til høyre",
|
||||||
"language.direction.rtl": "Høyre til venstre",
|
"language.direction.rtl": "Høyre til venstre",
|
||||||
"language.locale": "PHP locale streng",
|
"language.locale": "PHP locale streng",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Navn",
|
"language.name": "Navn",
|
||||||
"language.updated": "Språk har blitt oppdatert",
|
"language.updated": "Språk har blitt oppdatert",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Links naar rechts",
|
"language.direction.ltr": "Links naar rechts",
|
||||||
"language.direction.rtl": "Rechts naar links",
|
"language.direction.rtl": "Rechts naar links",
|
||||||
"language.locale": "PHP-locale regel",
|
"language.locale": "PHP-locale regel",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Naam",
|
"language.name": "Naam",
|
||||||
"language.updated": "De taal is geüpdatet",
|
"language.updated": "De taal is geüpdatet",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Od lewej do prawej",
|
"language.direction.ltr": "Od lewej do prawej",
|
||||||
"language.direction.rtl": "Od prawej do lewej",
|
"language.direction.rtl": "Od prawej do lewej",
|
||||||
"language.locale": "PHP locale string",
|
"language.locale": "PHP locale string",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Nazwa",
|
"language.name": "Nazwa",
|
||||||
"language.updated": "Język został zaktualizowany",
|
"language.updated": "Język został zaktualizowany",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Esquerda para direita",
|
"language.direction.ltr": "Esquerda para direita",
|
||||||
"language.direction.rtl": "Direita para esquerda",
|
"language.direction.rtl": "Direita para esquerda",
|
||||||
"language.locale": "String de localização do PHP",
|
"language.locale": "String de localização do PHP",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Nome",
|
"language.name": "Nome",
|
||||||
"language.updated": "Idioma atualizado",
|
"language.updated": "Idioma atualizado",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Esquerda para direita",
|
"language.direction.ltr": "Esquerda para direita",
|
||||||
"language.direction.rtl": "Direita para esquerda",
|
"language.direction.rtl": "Direita para esquerda",
|
||||||
"language.locale": "String de localização do PHP",
|
"language.locale": "String de localização do PHP",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Nome",
|
"language.name": "Nome",
|
||||||
"language.updated": "Idioma atualizado",
|
"language.updated": "Idioma atualizado",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Zľava doprava",
|
"language.direction.ltr": "Zľava doprava",
|
||||||
"language.direction.rtl": "Zprava doľava",
|
"language.direction.rtl": "Zprava doľava",
|
||||||
"language.locale": "PHP locale string",
|
"language.locale": "PHP locale string",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Názov",
|
"language.name": "Názov",
|
||||||
"language.updated": "Jazyk bol aktualizovaný",
|
"language.updated": "Jazyk bol aktualizovaný",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Vänster till höger",
|
"language.direction.ltr": "Vänster till höger",
|
||||||
"language.direction.rtl": "Höger till vänster",
|
"language.direction.rtl": "Höger till vänster",
|
||||||
"language.locale": "PHP locale string",
|
"language.locale": "PHP locale string",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "Namn",
|
"language.name": "Namn",
|
||||||
"language.updated": "Språket har uppdaterats",
|
"language.updated": "Språket har uppdaterats",
|
||||||
|
|
||||||
|
@@ -265,6 +265,7 @@
|
|||||||
"language.direction.ltr": "Soldan sağa",
|
"language.direction.ltr": "Soldan sağa",
|
||||||
"language.direction.rtl": "Sağdan sola",
|
"language.direction.rtl": "Sağdan sola",
|
||||||
"language.locale": "PHP yerel dizesi",
|
"language.locale": "PHP yerel dizesi",
|
||||||
|
"language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages",
|
||||||
"language.name": "İsim",
|
"language.name": "İsim",
|
||||||
"language.updated": "Dil güncellendi",
|
"language.updated": "Dil güncellendi",
|
||||||
|
|
||||||
|
2
kirby/panel/dist/js/app.js
vendored
2
kirby/panel/dist/js/app.js
vendored
File diff suppressed because one or more lines are too long
@@ -543,7 +543,7 @@ class Api
|
|||||||
if (is_a($e, 'Kirby\Exception\Exception') === true) {
|
if (is_a($e, 'Kirby\Exception\Exception') === true) {
|
||||||
$result = [
|
$result = [
|
||||||
'status' => 'error',
|
'status' => 'error',
|
||||||
'route' => $this->route->pattern()
|
'route' => ($this->route)? $this->route->pattern() : null
|
||||||
] + $e->toArray();
|
] + $e->toArray();
|
||||||
} else {
|
} else {
|
||||||
// remove the document root from the file path
|
// remove the document root from the file path
|
||||||
|
@@ -81,7 +81,7 @@ trait AppCaches
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$prefix = str_replace('/', '_', $this->system()->indexUrl()) .
|
$prefix = str_replace(['/', ':'], '_', $this->system()->indexUrl()) .
|
||||||
'/' .
|
'/' .
|
||||||
str_replace('.', '/', $key);
|
str_replace('.', '/', $key);
|
||||||
|
|
||||||
|
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Kirby\Cms;
|
namespace Kirby\Cms;
|
||||||
|
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AppUsers
|
* AppUsers
|
||||||
*
|
*
|
||||||
@@ -88,7 +90,11 @@ trait AppUsers
|
|||||||
if (is_string($this->user) === true) {
|
if (is_string($this->user) === true) {
|
||||||
return $this->auth()->impersonate($this->user);
|
return $this->auth()->impersonate($this->user);
|
||||||
} else {
|
} else {
|
||||||
return $this->auth()->user();
|
try {
|
||||||
|
return $this->auth()->user();
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,6 +7,7 @@ use Kirby\Exception\PermissionException;
|
|||||||
use Kirby\Exception\InvalidArgumentException;
|
use Kirby\Exception\InvalidArgumentException;
|
||||||
use Kirby\Exception\NotFoundException;
|
use Kirby\Exception\NotFoundException;
|
||||||
use Kirby\Http\Request\Auth\BasicAuth;
|
use Kirby\Http\Request\Auth\BasicAuth;
|
||||||
|
use Kirby\Toolkit\F;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,10 +23,12 @@ class Auth
|
|||||||
{
|
{
|
||||||
protected $impersonate;
|
protected $impersonate;
|
||||||
protected $kirby;
|
protected $kirby;
|
||||||
protected $user;
|
protected $user = false;
|
||||||
|
protected $userException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Kirby\Cms\App $kirby
|
* @param Kirby\Cms\App $kirby
|
||||||
|
* @codeCoverageIgnore
|
||||||
*/
|
*/
|
||||||
public function __construct(App $kirby)
|
public function __construct(App $kirby)
|
||||||
{
|
{
|
||||||
@@ -79,13 +82,7 @@ class Auth
|
|||||||
throw new PermissionException('Basic authentication is only allowed over HTTPS');
|
throw new PermissionException('Basic authentication is only allowed over HTTPS');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($user = $this->kirby->users()->find($auth->username())) {
|
return $this->validatePassword($auth->username(), $auth->password());
|
||||||
if ($user->validatePassword($auth->password()) === true) {
|
|
||||||
return $user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -158,24 +155,33 @@ class Auth
|
|||||||
*/
|
*/
|
||||||
public function ipHash(): string
|
public function ipHash(): string
|
||||||
{
|
{
|
||||||
return hash('sha256', $this->kirby->visitor()->ip());
|
$hash = hash('sha256', $this->kirby->visitor()->ip());
|
||||||
|
|
||||||
|
// only use the first 50 chars to ensure privacy
|
||||||
|
return substr($hash, 0, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if logins are blocked for the current ip
|
* Check if logins are blocked for the current ip or email
|
||||||
*
|
*
|
||||||
|
* @param string $email
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function isBlocked(): bool
|
public function isBlocked(string $email): bool
|
||||||
{
|
{
|
||||||
$ip = $this->ipHash();
|
$ip = $this->ipHash();
|
||||||
$log = $this->log();
|
$log = $this->log();
|
||||||
$trials = $this->kirby->option('auth.trials', 10);
|
$trials = $this->kirby->option('auth.trials', 10);
|
||||||
$timeout = $this->kirby->option('auth.timeout', 3600);
|
|
||||||
|
|
||||||
if ($entry = ($log[$ip] ?? null)) {
|
if ($entry = ($log['by-ip'][$ip] ?? null)) {
|
||||||
if ($entry['trials'] > $trials) {
|
if ($entry['trials'] >= $trials) {
|
||||||
if ($entry['time'] > (time() - $timeout)) {
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->kirby->users()->find($email)) {
|
||||||
|
if ($entry = ($log['by-email'][$email] ?? null)) {
|
||||||
|
if ($entry['trials'] >= $trials) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,18 +196,14 @@ class Auth
|
|||||||
* @param string $email
|
* @param string $email
|
||||||
* @param string $password
|
* @param string $password
|
||||||
* @param boolean $long
|
* @param boolean $long
|
||||||
* @return Kirby\Cms\User|false
|
* @return Kirby\Cms\User
|
||||||
|
*
|
||||||
|
* @throws PermissionException If the rate limit was exceeded or if any other error occured with debug mode off
|
||||||
|
* @throws NotFoundException If the email was invalid
|
||||||
|
* @throws InvalidArgumentException If the password is not valid (via `$user->login()`)
|
||||||
*/
|
*/
|
||||||
public function login(string $email, string $password, bool $long = false)
|
public function login(string $email, string $password, bool $long = false)
|
||||||
{
|
{
|
||||||
// check for blocked ips
|
|
||||||
if ($this->isBlocked() === true) {
|
|
||||||
throw new PermissionException('Rate limit exceeded', 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop impersonating
|
|
||||||
$this->impersonate = null;
|
|
||||||
|
|
||||||
// session options
|
// session options
|
||||||
$options = [
|
$options = [
|
||||||
'createMode' => 'cookie',
|
'createMode' => 'cookie',
|
||||||
@@ -209,20 +211,71 @@ class Auth
|
|||||||
];
|
];
|
||||||
|
|
||||||
// validate the user and log in to the session
|
// validate the user and log in to the session
|
||||||
if ($user = $this->kirby->users()->find($email)) {
|
$user = $this->validatePassword($email, $password);
|
||||||
if ($user->login($password, $options) === true) {
|
$user->loginPasswordless($options);
|
||||||
return $this->user = $user;
|
|
||||||
|
// stop impersonating
|
||||||
|
$this->impersonate = null;
|
||||||
|
|
||||||
|
return $this->user = $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the user credentials and returns the user object on success;
|
||||||
|
* otherwise logs the failed attempt
|
||||||
|
*
|
||||||
|
* @param string $email
|
||||||
|
* @param string $password
|
||||||
|
* @return Kirby\Cms\User
|
||||||
|
*
|
||||||
|
* @throws PermissionException If the rate limit was exceeded or if any other error occured with debug mode off
|
||||||
|
* @throws NotFoundException If the email was invalid
|
||||||
|
* @throws InvalidArgumentException If the password is not valid (via `$user->login()`)
|
||||||
|
*/
|
||||||
|
public function validatePassword(string $email, string $password)
|
||||||
|
{
|
||||||
|
// check for blocked ips
|
||||||
|
if ($this->isBlocked($email) === true) {
|
||||||
|
if ($this->kirby->option('debug') === true) {
|
||||||
|
$message = 'Rate limit exceeded';
|
||||||
|
} else {
|
||||||
|
// avoid leaking security-relevant information
|
||||||
|
$message = 'Invalid email or password';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new PermissionException($message, 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
// log invalid login trial
|
// validate the user
|
||||||
$this->track();
|
try {
|
||||||
|
if ($user = $this->kirby->users()->find($email)) {
|
||||||
|
if ($user->validatePassword($password) === true) {
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// sleep for a random amount of milliseconds
|
throw new NotFoundException([
|
||||||
// to make automated attacks harder
|
'key' => 'user.notFound',
|
||||||
usleep(random_int(1000, 2000000));
|
'data' => [
|
||||||
|
'name' => $email
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
// log invalid login trial
|
||||||
|
$this->track($email);
|
||||||
|
|
||||||
return false;
|
// sleep for a random amount of milliseconds
|
||||||
|
// to make automated attacks harder
|
||||||
|
usleep(random_int(1000, 2000000));
|
||||||
|
|
||||||
|
// keep throwing the original error in debug mode,
|
||||||
|
// otherwise hide it to avoid leaking security-relevant information
|
||||||
|
if ($this->kirby->option('debug') === true) {
|
||||||
|
throw $e;
|
||||||
|
} else {
|
||||||
|
throw new PermissionException('Invalid email or password');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -243,10 +296,39 @@ class Auth
|
|||||||
public function log(): array
|
public function log(): array
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return Data::read($this->logfile(), 'json');
|
$log = Data::read($this->logfile(), 'json');
|
||||||
|
$read = true;
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
return [];
|
$log = [];
|
||||||
|
$read = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure that the category arrays are defined
|
||||||
|
$log['by-ip'] = $log['by-ip'] ?? [];
|
||||||
|
$log['by-email'] = $log['by-email'] ?? [];
|
||||||
|
|
||||||
|
// remove entries that are no longer needed
|
||||||
|
$originalLog = $log;
|
||||||
|
$time = time() - $this->kirby->option('auth.timeout', 3600);
|
||||||
|
foreach ($log as $category => $entries) {
|
||||||
|
$log[$category] = array_filter($entries, function ($entry) use ($time) {
|
||||||
|
return $entry['time'] > $time;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove all elements on the top level with different keys (old structure)
|
||||||
|
$log = array_intersect_key($log, array_flip(['by-ip', 'by-email']));
|
||||||
|
|
||||||
|
// write new log to the file system if it changed
|
||||||
|
if ($read === false || $log !== $originalLog) {
|
||||||
|
if (count($log['by-ip']) === 0 && count($log['by-email']) === 0) {
|
||||||
|
F::remove($this->logfile());
|
||||||
|
} else {
|
||||||
|
Data::write($this->logfile(), $log, 'json');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $log;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -271,26 +353,41 @@ class Auth
|
|||||||
/**
|
/**
|
||||||
* Tracks a login
|
* Tracks a login
|
||||||
*
|
*
|
||||||
|
* @param string $email
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function track(): bool
|
public function track(string $email): bool
|
||||||
{
|
{
|
||||||
$ip = $this->ipHash();
|
$ip = $this->ipHash();
|
||||||
$log = $this->log();
|
$log = $this->log();
|
||||||
$time = time();
|
$time = time();
|
||||||
|
|
||||||
if (isset($log[$ip]) === true) {
|
if (isset($log['by-ip'][$ip]) === true) {
|
||||||
$log[$ip] = [
|
$log['by-ip'][$ip] = [
|
||||||
'time' => $time,
|
'time' => $time,
|
||||||
'trials' => ($log[$ip]['trials'] ?? 0) + 1
|
'trials' => ($log['by-ip'][$ip]['trials'] ?? 0) + 1
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
$log[$ip] = [
|
$log['by-ip'][$ip] = [
|
||||||
'time' => $time,
|
'time' => $time,
|
||||||
'trials' => 1
|
'trials' => 1
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->kirby->users()->find($email)) {
|
||||||
|
if (isset($log['by-email'][$email]) === true) {
|
||||||
|
$log['by-email'][$email] = [
|
||||||
|
'time' => $time,
|
||||||
|
'trials' => ($log['by-email'][$email]['trials'] ?? 0) + 1
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$log['by-email'][$email] = [
|
||||||
|
'time' => $time,
|
||||||
|
'trials' => 1
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Data::write($this->logfile(), $log, 'json');
|
return Data::write($this->logfile(), $log, 'json');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,8 +413,9 @@ class Auth
|
|||||||
/**
|
/**
|
||||||
* Validates the currently logged in user
|
* Validates the currently logged in user
|
||||||
*
|
*
|
||||||
* @param Kirby\Session\Sessionarray||null $session
|
* @param Kirby\Session\Session|array|null $session
|
||||||
* @return Kirby\Cms\User|null
|
* @return Kirby\Cms\User
|
||||||
|
* @throws
|
||||||
*/
|
*/
|
||||||
public function user($session = null)
|
public function user($session = null)
|
||||||
{
|
{
|
||||||
@@ -325,6 +423,18 @@ class Auth
|
|||||||
return $this->impersonate;
|
return $this->impersonate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return from cache
|
||||||
|
if ($this->user === null) {
|
||||||
|
// throw the same Exception again if one was captured before
|
||||||
|
if ($this->userException !== null) {
|
||||||
|
throw $this->userException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} elseif ($this->user !== false) {
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($this->type() === 'basic') {
|
if ($this->type() === 'basic') {
|
||||||
return $this->user = $this->currentUserFromBasicAuth();
|
return $this->user = $this->currentUserFromBasicAuth();
|
||||||
@@ -332,7 +442,12 @@ class Auth
|
|||||||
return $this->user = $this->currentUserFromSession($session);
|
return $this->user = $this->currentUserFromSession($session);
|
||||||
}
|
}
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
return $this->user = null;
|
$this->user = null;
|
||||||
|
|
||||||
|
// capture the Exception for future calls
|
||||||
|
$this->userException = $e;
|
||||||
|
|
||||||
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -66,12 +66,12 @@ class ContentLock
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns array with `locked` flag and,
|
* Returns either `false` or array with `user`, `email`,
|
||||||
* if needed, `user`, `email`, `time`, `canUnlock`
|
* `time` and `unlockable` keys
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array|bool
|
||||||
*/
|
*/
|
||||||
public function get(): array
|
public function get()
|
||||||
{
|
{
|
||||||
$data = $this->data['lock'] ?? [];
|
$data = $this->data['lock'] ?? [];
|
||||||
|
|
||||||
@@ -83,17 +83,14 @@ class ContentLock
|
|||||||
$time = intval($data['time']);
|
$time = intval($data['time']);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'locked' => true,
|
'user' => $user->id(),
|
||||||
'user' => $user->id(),
|
'email' => $user->email(),
|
||||||
'email' => $user->email(),
|
'time' => $time,
|
||||||
'time' => $time,
|
'unlockable' => $time + $this->kirby()->option('lock.duration', 60 * 2) <= time()
|
||||||
'canUnlock' => $time + $this->kirby()->option('lock.duration', 60 * 2) <= time()
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return false;
|
||||||
'locked' => false
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,10 +102,7 @@ class ContentLock
|
|||||||
{
|
{
|
||||||
$lock = $this->get();
|
$lock = $this->get();
|
||||||
|
|
||||||
if (
|
if ($lock !== false && $lock['user'] !== $this->user()->id()) {
|
||||||
$lock['locked'] === true &&
|
|
||||||
$lock['user'] !== $this->user()->id()
|
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -260,11 +260,18 @@ abstract class ModelWithContent extends Model
|
|||||||
/**
|
/**
|
||||||
* Returns the lock object for this model
|
* Returns the lock object for this model
|
||||||
*
|
*
|
||||||
* @return Kirby\Cms\ContentLock
|
* Only if a content directory exists,
|
||||||
|
* virtual pages will need to overwrite this method
|
||||||
|
*
|
||||||
|
* @return Kirby\Cms\ContentLock|null
|
||||||
*/
|
*/
|
||||||
public function lock()
|
public function lock()
|
||||||
{
|
{
|
||||||
return new ContentLock($this);
|
$dir = $this->contentFileDirectory();
|
||||||
|
|
||||||
|
if (is_string($dir) === true && file_exists($dir) === true) {
|
||||||
|
return new ContentLock($this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -420,7 +420,7 @@ class User extends ModelWithContent
|
|||||||
/**
|
/**
|
||||||
* Logs the user in without checking the password
|
* Logs the user in without checking the password
|
||||||
*
|
*
|
||||||
* @param SKirby\Session\Session|array $session Session options or session object to set the user in
|
* @param Kirby\Session\Session|array $session Session options or session object to set the user in
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function loginPasswordless($session = null): void
|
public function loginPasswordless($session = null): void
|
||||||
|
@@ -109,8 +109,15 @@ class Users extends Collection
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = new User([
|
// get role information
|
||||||
'id' => $userDirectory,
|
if (file_exists($root . '/' . $userDirectory . '/index.php') === true) {
|
||||||
|
$credentials = require $root . '/' . $userDirectory . '/index.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
// create user model based on role
|
||||||
|
$user = User::factory([
|
||||||
|
'id' => $userDirectory,
|
||||||
|
'model' => $credentials['role'] ?? null
|
||||||
] + $inject);
|
] + $inject);
|
||||||
|
|
||||||
$users->set($user->id(), $user);
|
$users->set($user->id(), $user);
|
||||||
|
@@ -247,7 +247,7 @@ class Uri
|
|||||||
}
|
}
|
||||||
|
|
||||||
$uri = Server::get('REQUEST_URI');
|
$uri = Server::get('REQUEST_URI');
|
||||||
$uri = str_replace(Server::get('HTTP_HOST'), '', $uri);
|
$uri = preg_replace('!^(http|https)\:\/\/' . Server::get('HTTP_HOST') . '!', '', $uri);
|
||||||
$uri = parse_url('http://getkirby.com' . $uri);
|
$uri = parse_url('http://getkirby.com' . $uri);
|
||||||
|
|
||||||
$url = new static(array_merge([
|
$url = new static(array_merge([
|
||||||
|
@@ -88,7 +88,7 @@ class Image extends File
|
|||||||
return $this->dimensions;
|
return $this->dimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array($this->mime(), ['image/jpeg', 'image/jp2', 'image/png', 'image/gif'])) {
|
if (in_array($this->mime(), ['image/jpeg', 'image/jp2', 'image/png', 'image/gif', 'image/webp'])) {
|
||||||
return $this->dimensions = Dimensions::forImage($this->root);
|
return $this->dimensions = Dimensions::forImage($this->root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -469,6 +469,9 @@ class Session
|
|||||||
} else {
|
} else {
|
||||||
$this->needsRetransmission = true;
|
$this->needsRetransmission = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update cache of the Sessions instance with the new token
|
||||||
|
$this->sessions->updateCache($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -242,6 +242,18 @@ class Sessions
|
|||||||
$this->store()->collectGarbage();
|
$this->store()->collectGarbage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the instance cache with a newly created
|
||||||
|
* session or a session with a regenerated token
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
* @param Kirby\Session\Session $session Session instance to push to the cache
|
||||||
|
*/
|
||||||
|
public function updateCache(Session $session)
|
||||||
|
{
|
||||||
|
$this->cache[$session->token()] = $session;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the auth token from the cookie
|
* Returns the auth token from the cookie
|
||||||
*
|
*
|
||||||
|
@@ -843,6 +843,26 @@ class Collection extends Iterator implements Countable
|
|||||||
return $collection;
|
return $collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get sort arguments from a string
|
||||||
|
*
|
||||||
|
* @param string $sortBy
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function sortArgs(string $sortBy): array
|
||||||
|
{
|
||||||
|
$sortArgs = Str::split($sortBy, ' ');
|
||||||
|
|
||||||
|
// fill in PHP constants
|
||||||
|
array_walk($sortArgs, function (string &$value) {
|
||||||
|
if (Str::startsWith($value, 'SORT_') === true && defined($value) === true) {
|
||||||
|
$value = constant($value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $sortArgs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the elements by any number of fields
|
* Sorts the elements by any number of fields
|
||||||
*
|
*
|
||||||
|
@@ -76,6 +76,11 @@ class Query
|
|||||||
*/
|
*/
|
||||||
protected function resolve(string $query)
|
protected function resolve(string $query)
|
||||||
{
|
{
|
||||||
|
// direct key access in arrays
|
||||||
|
if (is_array($this->data) === true && array_key_exists($query, $this->data) === true) {
|
||||||
|
return $this->data[$query];
|
||||||
|
}
|
||||||
|
|
||||||
$parts = $this->parts($query);
|
$parts = $this->parts($query);
|
||||||
$data = $this->data;
|
$data = $this->data;
|
||||||
$value = null;
|
$value = null;
|
||||||
|
@@ -826,7 +826,6 @@ class Str
|
|||||||
return $string;
|
return $string;
|
||||||
}
|
}
|
||||||
|
|
||||||
$string = trim((string)$string, $separator);
|
|
||||||
$parts = explode($separator, $string);
|
$parts = explode($separator, $string);
|
||||||
$out = [];
|
$out = [];
|
||||||
|
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
namespace Kirby\Toolkit;
|
namespace Kirby\Toolkit;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Kirby\Http\Idn;
|
||||||
use Kirby\Toolkit\Str;
|
use Kirby\Toolkit\Str;
|
||||||
use ReflectionFunction;
|
use ReflectionFunction;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
@@ -270,7 +271,20 @@ V::$validators = [
|
|||||||
* Checks for valid email addresses
|
* Checks for valid email addresses
|
||||||
*/
|
*/
|
||||||
'email' => function ($value): bool {
|
'email' => function ($value): bool {
|
||||||
return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
|
if (filter_var($value, FILTER_VALIDATE_EMAIL) === false) {
|
||||||
|
try {
|
||||||
|
$parts = Str::split($value, '@');
|
||||||
|
$address = $parts[0] ?? null;
|
||||||
|
$domain = Idn::encode($parts[1] ?? '');
|
||||||
|
$email = $address . '@' . $domain;
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user