diff --git a/app/Auth/Access/Mfa/TotpService.php b/app/Auth/Access/Mfa/TotpService.php index 0d9bd37ce..e73c549fe 100644 --- a/app/Auth/Access/Mfa/TotpService.php +++ b/app/Auth/Access/Mfa/TotpService.php @@ -8,6 +8,7 @@ use BaconQrCode\Renderer\ImageRenderer; use BaconQrCode\Renderer\RendererStyle\Fill; use BaconQrCode\Renderer\RendererStyle\RendererStyle; use BaconQrCode\Writer; +use BookStack\Auth\User; use PragmaRX\Google2FA\Google2FA; use PragmaRX\Google2FA\Support\Constants; @@ -36,11 +37,11 @@ class TotpService /** * Generate a TOTP URL from secret key. */ - public function generateUrl(string $secret): string + public function generateUrl(string $secret, User $user): string { return $this->google2fa->getQRCodeUrl( setting('app-name'), - user()->email, + $user->email, $secret ); } diff --git a/app/Config/auth.php b/app/Config/auth.php index 404b5352d..23b9039b9 100644 --- a/app/Config/auth.php +++ b/app/Config/auth.php @@ -70,6 +70,7 @@ return [ 'email' => 'emails.password', 'table' => 'password_resets', 'expire' => 60, + 'throttle' => 60, ], ], diff --git a/app/Config/dompdf.php b/app/Config/dompdf.php index cf07312e8..a5490294c 100644 --- a/app/Config/dompdf.php +++ b/app/Config/dompdf.php @@ -70,7 +70,7 @@ return [ * direct class use like: * $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output(); */ - 'chroot' => realpath(base_path()), + 'chroot' => realpath(public_path()), /** * Whether to use Unicode fonts or not. diff --git a/app/Exceptions/WhoopsBookStackPrettyHandler.php b/app/Exceptions/WhoopsBookStackPrettyHandler.php new file mode 100644 index 000000000..dcf50fa8e --- /dev/null +++ b/app/Exceptions/WhoopsBookStackPrettyHandler.php @@ -0,0 +1,49 @@ +getException(); + + echo view('errors.debug', [ + 'error' => $exception->getMessage(), + 'errorClass' => get_class($exception), + 'trace' => $exception->getTraceAsString(), + 'environment' => $this->getEnvironment(), + ])->render(); + + return Handler::QUIT; + } + + protected function safeReturn(callable $callback, $default = null) + { + try { + return $callback(); + } catch (\Exception $e) { + return $default; + } + } + + protected function getEnvironment(): array + { + return [ + 'PHP Version' => phpversion(), + 'BookStack Version' => $this->safeReturn(function () { + $versionFile = base_path('version'); + + return trim(file_get_contents($versionFile)); + }, 'unknown'), + 'Theme Configured' => $this->safeReturn(function () { + return config('view.theme'); + }) ?? 'None', + ]; + } +} diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index 3df0608f8..8eaee08a2 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -56,7 +56,7 @@ class ForgotPasswordController extends Controller $this->logActivity(ActivityType::AUTH_PASSWORD_RESET, $request->get('email')); } - if ($response === Password::RESET_LINK_SENT || $response === Password::INVALID_USER) { + if (in_array($response, [Password::RESET_LINK_SENT, Password::INVALID_USER, Password::RESET_THROTTLED])) { $message = trans('auth.reset_password_sent', ['email' => $request->get('email')]); $this->showSuccessNotification($message); diff --git a/app/Http/Controllers/Auth/MfaTotpController.php b/app/Http/Controllers/Auth/MfaTotpController.php index 694d69d76..5644f0268 100644 --- a/app/Http/Controllers/Auth/MfaTotpController.php +++ b/app/Http/Controllers/Auth/MfaTotpController.php @@ -31,7 +31,7 @@ class MfaTotpController extends Controller session()->put(static::SETUP_SECRET_SESSION_KEY, encrypt($totpSecret)); } - $qrCodeUrl = $totp->generateUrl($totpSecret); + $qrCodeUrl = $totp->generateUrl($totpSecret, $this->currentOrLastAttemptedUser()); $svg = $totp->generateQrCodeSvg($qrCodeUrl); return view('mfa.totp-generate', [ diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 8334bb179..4446c2a0a 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -9,6 +9,7 @@ use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Bookshelf; use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Page; +use BookStack\Exceptions\WhoopsBookStackPrettyHandler; use BookStack\Settings\Setting; use BookStack\Settings\SettingService; use BookStack\Util\CspService; @@ -20,6 +21,7 @@ use Illuminate\Support\Facades\URL; use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; use Laravel\Socialite\Contracts\Factory as SocialiteFactory; +use Whoops\Handler\HandlerInterface; class AppServiceProvider extends ServiceProvider { @@ -65,6 +67,10 @@ class AppServiceProvider extends ServiceProvider */ public function register() { + $this->app->bind(HandlerInterface::class, function ($app) { + return $app->make(WhoopsBookStackPrettyHandler::class); + }); + $this->app->singleton(SettingService::class, function ($app) { return new SettingService($app->make(Setting::class), $app->make(Repository::class)); }); diff --git a/composer.json b/composer.json index 31ecbef84..e59b0d1f0 100644 --- a/composer.json +++ b/composer.json @@ -17,8 +17,8 @@ "barryvdh/laravel-dompdf": "^0.9.0", "barryvdh/laravel-snappy": "^0.4.8", "doctrine/dbal": "^2.12.1", - "facade/ignition": "^1.16.4", "fideloper/proxy": "^4.4.1", + "filp/whoops": "^2.14", "intervention/image": "^2.5.1", "laravel/framework": "^6.20.33", "laravel/socialite": "^5.1", diff --git a/composer.lock b/composer.lock index fe779d071..dee5aff4c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "10825887b8f66d1d412b92bcc0ca864f", + "content-hash": "d59a665fcd692fc0ddf12e7e4f96d4f1", "packages": [ { "name": "aws/aws-crt-php", @@ -58,16 +58,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.194.1", + "version": "3.198.5", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "67bdee05acef9e8ad60098090996690b49babd09" + "reference": "ec63e1ad1b30689e530089e4c9cb18f2ef5c290b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/67bdee05acef9e8ad60098090996690b49babd09", - "reference": "67bdee05acef9e8ad60098090996690b49babd09", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/ec63e1ad1b30689e530089e4c9cb18f2ef5c290b", + "reference": "ec63e1ad1b30689e530089e4c9cb18f2ef5c290b", "shasum": "" }, "require": { @@ -143,9 +143,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.194.1" + "source": "https://github.com/aws/aws-sdk-php/tree/3.198.5" }, - "time": "2021-09-17T18:15:42+00:00" + "time": "2021-10-14T18:15:37+00:00" }, { "name": "bacon/bacon-qr-code", @@ -479,16 +479,16 @@ }, { "name": "doctrine/dbal", - "version": "2.13.3", + "version": "2.13.4", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "0d7adf4cadfee6f70850e5b163e6cdd706417838" + "reference": "2411a55a2a628e6d8dd598388ab13474802c7b6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/0d7adf4cadfee6f70850e5b163e6cdd706417838", - "reference": "0d7adf4cadfee6f70850e5b163e6cdd706417838", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/2411a55a2a628e6d8dd598388ab13474802c7b6e", + "reference": "2411a55a2a628e6d8dd598388ab13474802c7b6e", "shasum": "" }, "require": { @@ -501,8 +501,8 @@ "require-dev": { "doctrine/coding-standard": "9.0.0", "jetbrains/phpstorm-stubs": "2021.1", - "phpstan/phpstan": "0.12.96", - "phpunit/phpunit": "^7.5.20|^8.5|9.5.5", + "phpstan/phpstan": "0.12.99", + "phpunit/phpunit": "^7.5.20|^8.5|9.5.10", "psalm/plugin-phpunit": "0.16.1", "squizlabs/php_codesniffer": "3.6.0", "symfony/cache": "^4.4", @@ -568,7 +568,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/2.13.3" + "source": "https://github.com/doctrine/dbal/tree/2.13.4" }, "funding": [ { @@ -584,7 +584,7 @@ "type": "tidelift" } ], - "time": "2021-09-12T19:11:48+00:00" + "time": "2021-10-02T15:59:26+00:00" }, { "name": "doctrine/deprecations", @@ -1102,200 +1102,6 @@ ], "time": "2020-12-29T14:50:06+00:00" }, - { - "name": "facade/flare-client-php", - "version": "1.9.1", - "source": { - "type": "git", - "url": "https://github.com/facade/flare-client-php.git", - "reference": "b2adf1512755637d0cef4f7d1b54301325ac78ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facade/flare-client-php/zipball/b2adf1512755637d0cef4f7d1b54301325ac78ed", - "reference": "b2adf1512755637d0cef4f7d1b54301325ac78ed", - "shasum": "" - }, - "require": { - "facade/ignition-contracts": "~1.0", - "illuminate/pipeline": "^5.5|^6.0|^7.0|^8.0", - "php": "^7.1|^8.0", - "symfony/http-foundation": "^3.3|^4.1|^5.0", - "symfony/mime": "^3.4|^4.0|^5.1", - "symfony/var-dumper": "^3.4|^4.0|^5.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.14", - "phpunit/phpunit": "^7.5.16", - "spatie/phpunit-snapshot-assertions": "^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "Facade\\FlareClient\\": "src" - }, - "files": [ - "src/helpers.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Send PHP errors to Flare", - "homepage": "https://github.com/facade/flare-client-php", - "keywords": [ - "exception", - "facade", - "flare", - "reporting" - ], - "support": { - "issues": "https://github.com/facade/flare-client-php/issues", - "source": "https://github.com/facade/flare-client-php/tree/1.9.1" - }, - "funding": [ - { - "url": "https://github.com/spatie", - "type": "github" - } - ], - "time": "2021-09-13T12:16:46+00:00" - }, - { - "name": "facade/ignition", - "version": "1.18.0", - "source": { - "type": "git", - "url": "https://github.com/facade/ignition.git", - "reference": "fca0cbe5f900f94773d821b481c16d4ea3503491" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/fca0cbe5f900f94773d821b481c16d4ea3503491", - "reference": "fca0cbe5f900f94773d821b481c16d4ea3503491", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-mbstring": "*", - "facade/flare-client-php": "^1.3", - "facade/ignition-contracts": "^1.0", - "filp/whoops": "^2.4", - "illuminate/support": "~5.5.0 || ~5.6.0 || ~5.7.0 || ~5.8.0 || ^6.0", - "monolog/monolog": "^1.12 || ^2.0", - "php": "^7.1|^8.0", - "scrivo/highlight.php": "^9.15", - "symfony/console": "^3.4 || ^4.0", - "symfony/var-dumper": "^3.4 || ^4.0" - }, - "require-dev": { - "mockery/mockery": "~1.3.3|^1.4.2", - "orchestra/testbench": "^3.5 || ^3.6 || ^3.7 || ^3.8 || ^4.0" - }, - "suggest": { - "laravel/telescope": "^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - }, - "laravel": { - "providers": [ - "Facade\\Ignition\\IgnitionServiceProvider" - ], - "aliases": { - "Flare": "Facade\\Ignition\\Facades\\Flare" - } - } - }, - "autoload": { - "psr-4": { - "Facade\\Ignition\\": "src" - }, - "files": [ - "src/helpers.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A beautiful error page for Laravel applications.", - "homepage": "https://github.com/facade/ignition", - "keywords": [ - "error", - "flare", - "laravel", - "page" - ], - "support": { - "docs": "https://flareapp.io/docs/ignition-for-laravel/introduction", - "forum": "https://twitter.com/flareappio", - "issues": "https://github.com/facade/ignition/issues", - "source": "https://github.com/facade/ignition" - }, - "time": "2021-08-02T07:45:03+00:00" - }, - { - "name": "facade/ignition-contracts", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/facade/ignition-contracts.git", - "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/3c921a1cdba35b68a7f0ccffc6dffc1995b18267", - "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267", - "shasum": "" - }, - "require": { - "php": "^7.3|^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^v2.15.8", - "phpunit/phpunit": "^9.3.11", - "vimeo/psalm": "^3.17.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Facade\\IgnitionContracts\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://flareapp.io", - "role": "Developer" - } - ], - "description": "Solution contracts for Ignition", - "homepage": "https://github.com/facade/ignition-contracts", - "keywords": [ - "contracts", - "flare", - "ignition" - ], - "support": { - "issues": "https://github.com/facade/ignition-contracts/issues", - "source": "https://github.com/facade/ignition-contracts/tree/1.0.2" - }, - "time": "2020-10-16T08:27:54+00:00" - }, { "name": "fideloper/proxy", "version": "4.4.1", @@ -1356,21 +1162,21 @@ }, { "name": "filp/whoops", - "version": "2.14.1", + "version": "2.14.4", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "15ead64e9828f0fc90932114429c4f7923570cb1" + "reference": "f056f1fe935d9ed86e698905a957334029899895" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/15ead64e9828f0fc90932114429c4f7923570cb1", - "reference": "15ead64e9828f0fc90932114429c4f7923570cb1", + "url": "https://api.github.com/repos/filp/whoops/zipball/f056f1fe935d9ed86e698905a957334029899895", + "reference": "f056f1fe935d9ed86e698905a957334029899895", "shasum": "" }, "require": { "php": "^5.5.9 || ^7.0 || ^8.0", - "psr/log": "^1.0.1" + "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "require-dev": { "mockery/mockery": "^0.9 || ^1.0", @@ -1415,7 +1221,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.14.1" + "source": "https://github.com/filp/whoops/tree/2.14.4" }, "funding": [ { @@ -1423,7 +1229,7 @@ "type": "github" } ], - "time": "2021-08-29T12:00:00+00:00" + "time": "2021-10-03T12:00:00+00:00" }, { "name": "guzzlehttp/guzzle", @@ -1530,16 +1336,16 @@ }, { "name": "guzzlehttp/promises", - "version": "1.4.1", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d" + "reference": "136a635e2b4a49b9d79e9c8fee267ffb257fdba0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d", - "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "url": "https://api.github.com/repos/guzzle/promises/zipball/136a635e2b4a49b9d79e9c8fee267ffb257fdba0", + "reference": "136a635e2b4a49b9d79e9c8fee267ffb257fdba0", "shasum": "" }, "require": { @@ -1551,7 +1357,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.5-dev" } }, "autoload": { @@ -1567,10 +1373,25 @@ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], "description": "Guzzle promises library", @@ -1579,22 +1400,36 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.4.1" + "source": "https://github.com/guzzle/promises/tree/1.5.0" }, - "time": "2021-03-07T09:25:29+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2021-10-07T13:05:22+00:00" }, { "name": "guzzlehttp/psr7", - "version": "1.8.2", + "version": "1.8.3", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91" + "reference": "1afdd860a2566ed3c2b0b4a3de6e23434a79ec85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/1afdd860a2566ed3c2b0b4a3de6e23434a79ec85", + "reference": "1afdd860a2566ed3c2b0b4a3de6e23434a79ec85", "shasum": "" }, "require": { @@ -1631,13 +1466,34 @@ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, { "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", "homepage": "https://github.com/Tobion" } ], @@ -1654,22 +1510,36 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.8.2" + "source": "https://github.com/guzzle/psr7/tree/1.8.3" }, - "time": "2021-04-26T09:17:50+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2021-10-05T13:56:00+00:00" }, { "name": "intervention/image", - "version": "2.6.1", + "version": "2.7.0", "source": { "type": "git", "url": "https://github.com/Intervention/image.git", - "reference": "0925f10b259679b5d8ca58f3a2add9255ffcda45" + "reference": "9a8cc99d30415ec0b3f7649e1647d03a55698545" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Intervention/image/zipball/0925f10b259679b5d8ca58f3a2add9255ffcda45", - "reference": "0925f10b259679b5d8ca58f3a2add9255ffcda45", + "url": "https://api.github.com/repos/Intervention/image/zipball/9a8cc99d30415ec0b3f7649e1647d03a55698545", + "reference": "9a8cc99d30415ec0b3f7649e1647d03a55698545", "shasum": "" }, "require": { @@ -1728,7 +1598,7 @@ ], "support": { "issues": "https://github.com/Intervention/image/issues", - "source": "https://github.com/Intervention/image/tree/2.6.1" + "source": "https://github.com/Intervention/image/tree/2.7.0" }, "funding": [ { @@ -1740,7 +1610,7 @@ "type": "github" } ], - "time": "2021-07-22T14:31:53+00:00" + "time": "2021-10-03T14:17:12+00:00" }, { "name": "knplabs/knp-snappy", @@ -1814,16 +1684,16 @@ }, { "name": "laravel/framework", - "version": "v6.20.34", + "version": "v6.20.35", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "72a6da88c90cee793513b3fe49cf0fcb368eefa0" + "reference": "5e55aa4063b9f7cf3249bfebcc37a6fbad4f159a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/72a6da88c90cee793513b3fe49cf0fcb368eefa0", - "reference": "72a6da88c90cee793513b3fe49cf0fcb368eefa0", + "url": "https://api.github.com/repos/laravel/framework/zipball/5e55aa4063b9f7cf3249bfebcc37a6fbad4f159a", + "reference": "5e55aa4063b9f7cf3249bfebcc37a6fbad4f159a", "shasum": "" }, "require": { @@ -1963,7 +1833,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-09-07T13:28:55+00:00" + "time": "2021-10-05T14:05:19+00:00" }, { "name": "laravel/socialite", @@ -2371,16 +2241,16 @@ }, { "name": "league/mime-type-detection", - "version": "1.7.0", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3" + "reference": "b38b25d7b372e9fddb00335400467b223349fd7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", - "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/b38b25d7b372e9fddb00335400467b223349fd7e", + "reference": "b38b25d7b372e9fddb00335400467b223349fd7e", "shasum": "" }, "require": { @@ -2411,7 +2281,7 @@ "description": "Mime-type detection for Flysystem", "support": { "issues": "https://github.com/thephpleague/mime-type-detection/issues", - "source": "https://github.com/thephpleague/mime-type-detection/tree/1.7.0" + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.8.0" }, "funding": [ { @@ -2423,7 +2293,7 @@ "type": "tidelift" } ], - "time": "2021-01-18T20:58:21+00:00" + "time": "2021-09-25T08:23:19+00:00" }, { "name": "league/oauth1-client", @@ -2503,16 +2373,16 @@ }, { "name": "monolog/monolog", - "version": "2.3.4", + "version": "2.3.5", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "437e7a1c50044b92773b361af77620efb76fff59" + "reference": "fd4380d6fc37626e2f799f29d91195040137eba9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/437e7a1c50044b92773b361af77620efb76fff59", - "reference": "437e7a1c50044b92773b361af77620efb76fff59", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd4380d6fc37626e2f799f29d91195040137eba9", + "reference": "fd4380d6fc37626e2f799f29d91195040137eba9", "shasum": "" }, "require": { @@ -2528,7 +2398,7 @@ "elasticsearch/elasticsearch": "^7", "graylog2/gelf-php": "^1.4.2", "mongodb/mongodb": "^1.8", - "php-amqplib/php-amqplib": "~2.4", + "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.6.1", "phpstan/phpstan": "^0.12.91", @@ -2586,7 +2456,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.3.4" + "source": "https://github.com/Seldaek/monolog/tree/2.3.5" }, "funding": [ { @@ -2598,7 +2468,7 @@ "type": "tidelift" } ], - "time": "2021-09-15T11:27:21+00:00" + "time": "2021-10-01T21:08:31+00:00" }, { "name": "mtdowling/jmespath.php", @@ -3383,16 +3253,16 @@ }, { "name": "predis/predis", - "version": "v1.1.7", + "version": "v1.1.9", "source": { "type": "git", "url": "https://github.com/predis/predis.git", - "reference": "b240daa106d4e02f0c5b7079b41e31ddf66fddf8" + "reference": "c50c3393bb9f47fa012d0cdfb727a266b0818259" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/predis/predis/zipball/b240daa106d4e02f0c5b7079b41e31ddf66fddf8", - "reference": "b240daa106d4e02f0c5b7079b41e31ddf66fddf8", + "url": "https://api.github.com/repos/predis/predis/zipball/c50c3393bb9f47fa012d0cdfb727a266b0818259", + "reference": "c50c3393bb9f47fa012d0cdfb727a266b0818259", "shasum": "" }, "require": { @@ -3437,7 +3307,7 @@ ], "support": { "issues": "https://github.com/predis/predis/issues", - "source": "https://github.com/predis/predis/tree/v1.1.7" + "source": "https://github.com/predis/predis/tree/v1.1.9" }, "funding": [ { @@ -3445,7 +3315,7 @@ "type": "github" } ], - "time": "2021-04-04T19:34:46+00:00" + "time": "2021-10-05T19:02:38+00:00" }, { "name": "psr/container", @@ -3747,22 +3617,22 @@ }, { "name": "ramsey/uuid", - "version": "3.9.4", + "version": "3.9.6", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "be2451bef8147b7352a28fb4cddb08adc497ada3" + "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/be2451bef8147b7352a28fb4cddb08adc497ada3", - "reference": "be2451bef8147b7352a28fb4cddb08adc497ada3", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/ffa80ab953edd85d5b6c004f96181a538aad35a3", + "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3", "shasum": "" }, "require": { "ext-json": "*", "paragonie/random_compat": "^1 | ^2 | ^9.99.99", - "php": "^5.4 | ^7 | ^8", + "php": "^5.4 | ^7.0 | ^8.0", "symfony/polyfill-ctype": "^1.8" }, "replace": { @@ -3771,14 +3641,16 @@ "require-dev": { "codeception/aspect-mock": "^1 | ^2", "doctrine/annotations": "^1.2", - "goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1", - "jakub-onderka/php-parallel-lint": "^1", + "goaop/framework": "1.0.0-alpha.2 | ^1 | >=2.1.0 <=2.3.2", "mockery/mockery": "^0.9.11 | ^1", "moontoast/math": "^1.1", + "nikic/php-parser": "<=4.5.0", "paragonie/random-lib": "^2", - "php-mock/php-mock-phpunit": "^0.3 | ^1.1", - "phpunit/phpunit": "^4.8 | ^5.4 | ^6.5", - "squizlabs/php_codesniffer": "^3.5" + "php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpunit/phpunit": ">=4.8.36 <9.0.0 | >=9.3.0", + "squizlabs/php_codesniffer": "^3.5", + "yoast/phpunit-polyfills": "^1.0" }, "suggest": { "ext-ctype": "Provides support for PHP Ctype functions", @@ -3846,7 +3718,7 @@ "type": "tidelift" } ], - "time": "2021-08-06T20:32:15+00:00" + "time": "2021-09-25T23:07:42+00:00" }, { "name": "robrichards/xmlseclibs", @@ -3939,82 +3811,6 @@ }, "time": "2020-06-01T09:10:00+00:00" }, - { - "name": "scrivo/highlight.php", - "version": "v9.18.1.7", - "source": { - "type": "git", - "url": "https://github.com/scrivo/highlight.php.git", - "reference": "05996fcc61e97978d76ca7d1ac14b65e7cd26f91" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/05996fcc61e97978d76ca7d1ac14b65e7cd26f91", - "reference": "05996fcc61e97978d76ca7d1ac14b65e7cd26f91", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-mbstring": "*", - "php": ">=5.4" - }, - "require-dev": { - "phpunit/phpunit": "^4.8|^5.7", - "sabberworm/php-css-parser": "^8.3", - "symfony/finder": "^2.8|^3.4", - "symfony/var-dumper": "^2.8|^3.4" - }, - "type": "library", - "autoload": { - "psr-0": { - "Highlight\\": "", - "HighlightUtilities\\": "" - }, - "files": [ - "HighlightUtilities/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Geert Bergman", - "homepage": "http://www.scrivo.org/", - "role": "Project Author" - }, - { - "name": "Vladimir Jimenez", - "homepage": "https://allejo.io", - "role": "Maintainer" - }, - { - "name": "Martin Folkers", - "homepage": "https://twobrain.io", - "role": "Contributor" - } - ], - "description": "Server side syntax highlighter that supports 185 languages. It's a PHP port of highlight.js", - "keywords": [ - "code", - "highlight", - "highlight.js", - "highlight.php", - "syntax" - ], - "support": { - "issues": "https://github.com/scrivo/highlight.php/issues", - "source": "https://github.com/scrivo/highlight.php" - }, - "funding": [ - { - "url": "https://github.com/allejo", - "type": "github" - } - ], - "time": "2021-07-09T00:30:39+00:00" - }, { "name": "socialiteproviders/discord", "version": "4.1.1", @@ -5187,16 +4983,16 @@ }, { "name": "symfony/http-kernel", - "version": "v4.4.30", + "version": "v4.4.32", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "87f7ea4a8a7a30c967e26001de99f12943bf57ae" + "reference": "f7bda3ea8f05ae90627400e58af5179b25ce0f38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/87f7ea4a8a7a30c967e26001de99f12943bf57ae", - "reference": "87f7ea4a8a7a30c967e26001de99f12943bf57ae", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f7bda3ea8f05ae90627400e58af5179b25ce0f38", + "reference": "f7bda3ea8f05ae90627400e58af5179b25ce0f38", "shasum": "" }, "require": { @@ -5271,7 +5067,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v4.4.30" + "source": "https://github.com/symfony/http-kernel/tree/v4.4.32" }, "funding": [ { @@ -5287,20 +5083,20 @@ "type": "tidelift" } ], - "time": "2021-08-30T12:27:20+00:00" + "time": "2021-09-28T10:20:04+00:00" }, { "name": "symfony/mime", - "version": "v5.3.7", + "version": "v5.3.8", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "ae887cb3b044658676129f5e97aeb7e9eb69c2d8" + "reference": "a756033d0a7e53db389618653ae991eba5a19a11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/ae887cb3b044658676129f5e97aeb7e9eb69c2d8", - "reference": "ae887cb3b044658676129f5e97aeb7e9eb69c2d8", + "url": "https://api.github.com/repos/symfony/mime/zipball/a756033d0a7e53db389618653ae991eba5a19a11", + "reference": "a756033d0a7e53db389618653ae991eba5a19a11", "shasum": "" }, "require": { @@ -5354,7 +5150,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.3.7" + "source": "https://github.com/symfony/mime/tree/v5.3.8" }, "funding": [ { @@ -5370,7 +5166,7 @@ "type": "tidelift" } ], - "time": "2021-08-20T11:40:01+00:00" + "time": "2021-09-10T12:30:38+00:00" }, { "name": "symfony/polyfill-ctype", @@ -6252,7 +6048,7 @@ }, { "name": "symfony/translation", - "version": "v4.4.30", + "version": "v4.4.32", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", @@ -6321,7 +6117,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v4.4.30" + "source": "https://github.com/symfony/translation/tree/v4.4.32" }, "funding": [ { @@ -6419,16 +6215,16 @@ }, { "name": "symfony/var-dumper", - "version": "v4.4.30", + "version": "v4.4.31", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "7f65c44c2ce80d3a0fcdb6385ee0ad535e45660c" + "reference": "1f12cc0c2e880a5f39575c19af81438464717839" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/7f65c44c2ce80d3a0fcdb6385ee0ad535e45660c", - "reference": "7f65c44c2ce80d3a0fcdb6385ee0ad535e45660c", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1f12cc0c2e880a5f39575c19af81438464717839", + "reference": "1f12cc0c2e880a5f39575c19af81438464717839", "shasum": "" }, "require": { @@ -6488,7 +6284,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v4.4.30" + "source": "https://github.com/symfony/var-dumper/tree/v4.4.31" }, "funding": [ { @@ -6504,7 +6300,7 @@ "type": "tidelift" } ], - "time": "2021-08-04T20:31:23+00:00" + "time": "2021-09-24T15:30:11+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -6561,16 +6357,16 @@ }, { "name": "vlucas/phpdotenv", - "version": "v3.6.8", + "version": "v3.6.9", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "5e679f7616db829358341e2d5cccbd18773bdab8" + "reference": "a1bf4c9853d90ade427b4efe35355fc41b3d6988" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/5e679f7616db829358341e2d5cccbd18773bdab8", - "reference": "5e679f7616db829358341e2d5cccbd18773bdab8", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a1bf4c9853d90ade427b4efe35355fc41b3d6988", + "reference": "a1bf4c9853d90ade427b4efe35355fc41b3d6988", "shasum": "" }, "require": { @@ -6581,7 +6377,7 @@ "require-dev": { "ext-filter": "*", "ext-pcre": "*", - "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20" + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.21" }, "suggest": { "ext-filter": "Required to use the boolean validator.", @@ -6605,13 +6401,11 @@ "authors": [ { "name": "Graham Campbell", - "email": "graham@alt-three.com", - "homepage": "https://gjcampbell.co.uk/" + "email": "hello@gjcampbell.co.uk" }, { "name": "Vance Lucas", - "email": "vance@vancelucas.com", - "homepage": "https://vancelucas.com/" + "email": "vance@vancelucas.com" } ], "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", @@ -6622,7 +6416,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v3.6.8" + "source": "https://github.com/vlucas/phpdotenv/tree/v3.6.9" }, "funding": [ { @@ -6634,7 +6428,7 @@ "type": "tidelift" } ], - "time": "2021-01-20T14:39:46+00:00" + "time": "2021-10-02T19:07:56+00:00" } ], "packages-dev": [ @@ -7780,16 +7574,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.12.0", + "version": "v4.13.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6608f01670c3cc5079e18c1dab1104e002579143" + "reference": "50953a2691a922aa1769461637869a0a2faa3f53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143", - "reference": "6608f01670c3cc5079e18c1dab1104e002579143", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53", + "reference": "50953a2691a922aa1769461637869a0a2faa3f53", "shasum": "" }, "require": { @@ -7830,9 +7624,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0" }, - "time": "2021-07-21T10:44:31+00:00" + "time": "2021-09-20T12:20:58+00:00" }, { "name": "phar-io/manifest", @@ -8056,16 +7850,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f" + "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/30f38bffc6f24293dadd1823936372dfa9e86e2f", - "reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae", + "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae", "shasum": "" }, "require": { @@ -8100,9 +7894,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1" }, - "time": "2021-09-17T15:28:14+00:00" + "time": "2021-10-02T14:08:47+00:00" }, { "name": "phpspec/prophecy", @@ -8491,16 +8285,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.9", + "version": "9.5.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b" + "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b", - "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a", + "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a", "shasum": "" }, "require": { @@ -8516,7 +8310,7 @@ "phar-io/version": "^3.0.2", "php": ">=7.3", "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.3", + "phpunit/php-code-coverage": "^9.2.7", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -8578,7 +8372,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.9" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10" }, "funding": [ { @@ -8590,7 +8384,7 @@ "type": "github" } ], - "time": "2021-08-31T06:47:40+00:00" + "time": "2021-09-25T07:38:51+00:00" }, { "name": "react/promise", diff --git a/readme.md b/readme.md index cb17a1aae..45b40cdb7 100644 --- a/readme.md +++ b/readme.md @@ -14,17 +14,18 @@ A platform for storing and organising information and documentation. Details for * [Documentation](https://www.bookstackapp.com/docs) * [Demo Instance](https://demo.bookstackapp.com) * [Admin Login](https://demo.bookstackapp.com/login?email=admin@example.com&password=password) +* [Screenshots](https://www.bookstackapp.com/#screenshots) * [BookStack Blog](https://www.bookstackapp.com/blog) * [Issue List](https://github.com/BookStackApp/BookStack/issues) * [Discord Chat](https://discord.gg/ztkBqR2) ## 📚 Project Definition -BookStack is an opinionated wiki system that provides a pleasant and simple out of the box experience. New users to an instance should find the experience intuitive and only basic word-processing skills should be required to get involved in creating content on BookStack. The platform should provide advanced power features to those that desire it but they should not interfere with the core simple user experience. +BookStack is an opinionated wiki system that provides a pleasant and simple out-of-the-box experience. New users to an instance should find the experience intuitive and only basic word-processing skills should be required to get involved in creating content on BookStack. The platform should provide advanced power features to those that desire it but they should not interfere with the core simple user experience. BookStack is not designed as an extensible platform to be used for purposes that differ to the statement above. -In regards to development philosophy, BookStack has a relaxed, open & positive approach. At the end of the day this is free software developed and maintained by people donating their own free time. +In regard to development philosophy, BookStack has a relaxed, open & positive approach. At the end of the day this is free software developed and maintained by people donating their own free time. ## 🛣️ Road Map @@ -41,17 +42,23 @@ Below is a high-level road map view for BookStack to provide a sense of directio ## 🚀 Release Versioning & Process -BookStack releases are each assigned a version number, such as "v0.25.2", in the format `v..`. A change only in the `patch` number indicates a fairly minor release that mainly contains fixes and therefore is very unlikely to cause breakages upon update. A change in the `feature` number indicates a release which will generally bring new features in addition to fixes and enhancements. These releases have a small chance of introducing breaking changes upon update so it's worth checking for any notes in the [update guide](https://www.bookstackapp.com/docs/admin/updates/). A change in the `phase` indicates a much large change in BookStack that will likely incur breakages requiring manual intervention. +BookStack releases are each assigned a date-based version number in the format `v.[.]`. For example: + +- `v20.12` - New feature released launched during December 2020. +- `v21.06.2` - Second patch release upon the June 2021 feature release. + +Patch releases are generally fairly minor, primarily intended for fixes and therefore is fairly unlikely to cause breakages upon update. +Feature releases are generally larger, bringing new features in addition to fixes and enhancements. These releases have a greater chance of introducing breaking changes upon update, so it's worth checking for any notes in the [update guide](https://www.bookstackapp.com/docs/admin/updates/). Each BookStack release will have a [milestone](https://github.com/BookStackApp/BookStack/milestones) created with issues & pull requests assigned to it to define what will be in that release. Milestones are built up then worked through until complete at which point, after some testing and documentation updates, the release will be deployed. -For feature releases, and some patch releases, the release will be accompanied by a post on the [BookStack blog](https://www.bookstackapp.com/blog/) which will provide additional detail on features, changes & updates otherwise the [GitHub release page](https://github.com/BookStackApp/BookStack/releases) will show a list of changes. You can sign up to be alerted to new BookStack blogs posts (once per week maximum) [at this link](https://updates.bookstackapp.com/signup/bookstack-news-and-updates). +Feature releases, and some patch releases, will be accompanied by a post on the [BookStack blog](https://www.bookstackapp.com/blog/) which will provide additional detail on features, changes & updates otherwise the [GitHub release page](https://github.com/BookStackApp/BookStack/releases) will show a list of changes. You can sign up to be alerted to new BookStack blogs posts (once per week maximum) [at this link](https://updates.bookstackapp.com/signup/bookstack-news-and-updates). ## 🛠️ Development & Testing All development on BookStack is currently done on the master branch. When it's time for a release the master branch is merged into release with built & minified CSS & JS then tagged at its version. Here are the current development requirements: -* [Node.js](https://nodejs.org/en/) v12.0+ +* [Node.js](https://nodejs.org/en/) v14.0+ This project uses SASS for CSS development and this is built, along with the JavaScript, using a range of npm scripts. The below npm commands can be used to install the dependencies & run the build tasks: diff --git a/resources/lang/es_AR/activities.php b/resources/lang/es_AR/activities.php index 861115fc5..540bd4b82 100644 --- a/resources/lang/es_AR/activities.php +++ b/resources/lang/es_AR/activities.php @@ -48,8 +48,8 @@ return [ 'favourite_remove_notification' => '".name" se eliminó de sus favoritos', // MFA - 'mfa_setup_method_notification' => 'Método de Autenticación en Dos Pasos configurado correctamente', - 'mfa_remove_method_notification' => 'Método de Autenticación en Dos Pasos eliminado correctamente', + 'mfa_setup_method_notification' => 'Método de autenticación de múltiples factores configurado satisfactoriamente', + 'mfa_remove_method_notification' => 'Método de autenticación de múltiples factores eliminado satisfactoriamente', // Other 'commented_on' => 'comentado', diff --git a/resources/lang/es_AR/auth.php b/resources/lang/es_AR/auth.php index c57b26746..cb18a9405 100644 --- a/resources/lang/es_AR/auth.php +++ b/resources/lang/es_AR/auth.php @@ -76,37 +76,37 @@ return [ 'user_invite_success' => 'Contraseña establecida, ahora tiene acceso a :appName!', // Multi-factor Authentication - 'mfa_setup' => 'Configurar Autenticación en Dos Pasos', - 'mfa_setup_desc' => 'La autenticación en dos pasos añade una capa de seguridad adicional a tu cuenta de usuario.', + 'mfa_setup' => 'Configurar autenticación de múltiples factores', + 'mfa_setup_desc' => 'Configure la autenticación de múltiples factores como una capa extra de seguridad para su cuenta de usuario.', 'mfa_setup_configured' => 'Ya está configurado', 'mfa_setup_reconfigure' => 'Reconfigurar', - 'mfa_setup_remove_confirmation' => '¿Está seguro de que desea eliminar este método de autenticación de dos pasos?', + 'mfa_setup_remove_confirmation' => '¿Está seguro que desea eliminar este método de autenticación de múltiples factores?', 'mfa_setup_action' => 'Configuración', - 'mfa_backup_codes_usage_limit_warning' => 'Quedan menos de 5 códigos de respaldo, Por favor, genera y almacena un nuevo conjunto antes de que te quedes sin códigos para evitar que te bloquees fuera de tu cuenta.', - 'mfa_option_totp_title' => 'Aplicación para móviles', - 'mfa_option_totp_desc' => 'Para utilizar la autenticación de dos pasos necesitarás una aplicación móvil que soporte TOTP como Google Authenticator, Authy o Microsoft Authenticator.', + 'mfa_backup_codes_usage_limit_warning' => 'Quedan menos de 5 códigos de respaldo, Por favor, genere y guarde un nuevo conjunto antes de que se quede sin códigos para evitar que se bloquee su cuenta.', + 'mfa_option_totp_title' => 'Aplicación móvil', + 'mfa_option_totp_desc' => 'Para utilizar la autenticación en dos pasos necesitará una aplicación móvil que soporte TOTP como Google Authenticator, Authy o Microsoft Authenticator.', 'mfa_option_backup_codes_title' => 'Códigos de Respaldo', - 'mfa_option_backup_codes_desc' => 'Almacena de forma segura un conjunto de códigos de respaldo de un solo uso que puedes introducir para verificar tu identidad.', + 'mfa_option_backup_codes_desc' => 'Almacene de forma segura un conjunto de códigos de respaldo de un solo uso que pueda introducir para verificar su identidad.', 'mfa_gen_confirm_and_enable' => 'Confirmar y Activar', 'mfa_gen_backup_codes_title' => 'Configuración de Códigos de Respaldo', - 'mfa_gen_backup_codes_desc' => 'Guarda la siguiente lista de códigos en un lugar seguro. Al acceder al sistema podrás usar uno de los códigos como un segundo mecanismo de autenticación.', + 'mfa_gen_backup_codes_desc' => 'Guarde la siguiente lista de códigos en un lugar seguro. Al acceder al sistema podrá usar uno de los códigos como un segundo mecanismo de autenticación.', 'mfa_gen_backup_codes_download' => 'Descargar Códigos', - 'mfa_gen_backup_codes_usage_warning' => 'Cada código sólo puede utilizarse una vez', + 'mfa_gen_backup_codes_usage_warning' => 'Cada código puede utilizarse sólo una vez', 'mfa_gen_totp_title' => 'Configuración de Aplicación móvil', - 'mfa_gen_totp_desc' => 'Para utilizar la autenticación de dos pasos necesitarás una aplicación móvil que soporte TOTP como Google Authenticator, Authy o Microsoft Authenticator.', + 'mfa_gen_totp_desc' => 'Para utilizar la autenticación en dos pasos necesitará una aplicación móvil que soporte TOTP como Google Authenticator, Authy o Microsoft Authenticator.', 'mfa_gen_totp_scan' => 'Escanea el código QR mostrado a continuación usando tu aplicación de autenticación preferida para empezar.', 'mfa_gen_totp_verify_setup' => 'Verificar Configuración', 'mfa_gen_totp_verify_setup_desc' => 'Verifica que todo está funcionando introduciendo un código, generado en tu aplicación de autenticación, en el campo de texto a continuación:', 'mfa_gen_totp_provide_code_here' => 'Introduce aquí tu código generado por la aplicación', 'mfa_verify_access' => 'Verificar Acceso', - 'mfa_verify_access_desc' => 'Tu cuenta de usuario requiere que confirmes tu identidad a través de un nivel adicional de verificación antes de que te conceda el acceso. Verifica tu identidad usando uno de los métodos configurados para continuar.', + 'mfa_verify_access_desc' => 'Su cuenta de usuario requiere que confirme su identidad a través de un nivel adicional de verificación antes de que se le conceda el acceso. Verifique su identidad usando uno de los métodos configurados para continuar.', 'mfa_verify_no_methods' => 'No hay Métodos Configurados', - 'mfa_verify_no_methods_desc' => 'No se han encontrado métodos de autenticación de dos pasos para tu cuenta. Tendrás que configurar al menos un método antes de obtener acceso.', + 'mfa_verify_no_methods_desc' => 'No se han encontrado métodos de autenticación de múltiples factores para su cuenta. Tendrá que configurar al menos un método antes de obtener acceso.', 'mfa_verify_use_totp' => 'Verificar usando una aplicación móvil', 'mfa_verify_use_backup_codes' => 'Verificar usando un código de respaldo', - 'mfa_verify_backup_code' => 'Códigos de Respaldo', + 'mfa_verify_backup_code' => 'Código de Respaldo', 'mfa_verify_backup_code_desc' => 'Introduzca uno de sus códigos de respaldo restantes a continuación:', - 'mfa_verify_backup_code_enter_here' => 'Introduce el código de respaldo aquí', - 'mfa_verify_totp_desc' => 'Introduzca el código, generado con tu aplicación móvil, a continuación:', - 'mfa_setup_login_notification' => 'Método de dos factores configurado. Por favor, inicia sesión de nuevo utilizando el método configurado.', + 'mfa_verify_backup_code_enter_here' => 'Introduzca el código de respaldo aquí', + 'mfa_verify_totp_desc' => 'A continuación, introduzca el código generado con su aplicación móvil:', + 'mfa_setup_login_notification' => 'Método de dos factores configurado. Por favor, inicie sesión nuevamente utilizando el método configurado.', ]; \ No newline at end of file diff --git a/resources/lang/es_AR/entities.php b/resources/lang/es_AR/entities.php index 854680e02..bf08bdb51 100644 --- a/resources/lang/es_AR/entities.php +++ b/resources/lang/es_AR/entities.php @@ -234,7 +234,7 @@ return [ 'pages_initial_name' => 'Página nueva', 'pages_editing_draft_notification' => 'Usted está actualmente editando un borrador que fue guardado por última vez el :timeDiff.', 'pages_draft_edited_notification' => 'Esta página ha sido actualizada desde aquel momento. Se recomienda que cancele este borrador.', - 'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.', + 'pages_draft_page_changed_since_creation' => 'Esta página fue actualizada desde que se creó este borrador. Se recomienda descartar este borrador o tener cuidado de no sobrescribir ningún cambio en la página.', 'pages_draft_edit_active' => [ 'start_a' => ':count usuarios han comenzado a editar esta página', 'start_b' => ':userName ha comenzado a editar esta página', diff --git a/resources/lang/es_AR/settings.php b/resources/lang/es_AR/settings.php index 99ec4c219..027f22421 100644 --- a/resources/lang/es_AR/settings.php +++ b/resources/lang/es_AR/settings.php @@ -92,7 +92,7 @@ return [ 'recycle_bin' => 'Papelera de Reciclaje', 'recycle_bin_desc' => 'Aquí puede restaurar elementos que hayan sido eliminados o elegir eliminarlos permanentemente del sistema. Esta lista no está filtrada a diferencia de las listas de actividad similares en el sistema donde se aplican los filtros de permisos.', 'recycle_bin_deleted_item' => 'Elemento Eliminado', - 'recycle_bin_deleted_parent' => 'Superior', + 'recycle_bin_deleted_parent' => 'Padre', 'recycle_bin_deleted_by' => 'Eliminado por', 'recycle_bin_deleted_at' => 'Fecha de eliminación', 'recycle_bin_permanently_delete' => 'Eliminar permanentemente', @@ -105,7 +105,7 @@ return [ 'recycle_bin_restore_list' => 'Elementos a restaurar', 'recycle_bin_restore_confirm' => 'Esta acción restaurará el elemento eliminado, incluyendo cualquier elemento secundario, a su ubicación original. Si la ubicación original ha sido eliminada, y ahora está en la papelera de reciclaje, el elemento padre también tendrá que ser restaurado.', 'recycle_bin_restore_deleted_parent' => 'El padre de este elemento también ha sido eliminado. Estos permanecerán eliminados hasta que el padre también sea restaurado.', - 'recycle_bin_restore_parent' => 'Restaurar Superior', + 'recycle_bin_restore_parent' => 'Restaurar Padre', 'recycle_bin_destroy_notification' => 'Eliminados :count elementos de la papelera de reciclaje.', 'recycle_bin_restore_notification' => 'Restaurados :count elementos desde la papelera de reciclaje.', @@ -119,7 +119,7 @@ return [ 'audit_table_user' => 'Usuario', 'audit_table_event' => 'Evento', 'audit_table_related' => 'Elemento o detalle relacionados', - 'audit_table_ip' => 'IP Address', + 'audit_table_ip' => 'Dirección IP', 'audit_table_date' => 'Fecha de la Actividad', 'audit_date_from' => 'Inicio del Rango de Fecha', 'audit_date_to' => 'Final del Rango de Fecha', @@ -139,7 +139,7 @@ return [ 'role_details' => 'Detalles de rol', 'role_name' => 'Nombre de rol', 'role_desc' => 'Descripción corta de rol', - 'role_mfa_enforced' => 'Requiere Autenticación en Dos Pasos', + 'role_mfa_enforced' => 'Requiere autenticación de múltiples factores', 'role_external_auth_id' => 'IDs de Autenticación Externa', 'role_system' => 'Permisos de sistema', 'role_manage_users' => 'Gestionar usuarios', @@ -208,8 +208,8 @@ return [ 'users_api_tokens_create' => 'Crear token', 'users_api_tokens_expires' => 'Expira', 'users_api_tokens_docs' => 'Documentación API', - 'users_mfa' => 'Autenticación en Dos Pasos', - 'users_mfa_desc' => 'La autenticación en dos pasos añade una capa de seguridad adicional a tu cuenta.', + 'users_mfa' => 'Autenticación de múltiples factores', + 'users_mfa_desc' => 'Configure la autenticación de múltiples factores como una capa extra de seguridad para su cuenta de usuario.', 'users_mfa_x_methods' => ':count método configurado|:count métodos configurados', 'users_mfa_configure' => 'Configurar Métodos', diff --git a/resources/lang/es_AR/validation.php b/resources/lang/es_AR/validation.php index 2cc8ed9bf..6b72a6549 100644 --- a/resources/lang/es_AR/validation.php +++ b/resources/lang/es_AR/validation.php @@ -15,7 +15,7 @@ return [ 'alpha_dash' => 'El :attribute solo puede contener letras, números y guiones.', 'alpha_num' => 'El :attribute solo puede contener letras y número.', 'array' => 'El :attribute debe de ser un array.', - 'backup_codes' => 'El código suministrado no es válido o ya ha sido utilizado.', + 'backup_codes' => 'El código suministrado no es válido o ya fue utilizado.', 'before' => 'El :attribute debe ser una fecha anterior a :date.', 'between' => [ 'numeric' => 'El :attribute debe estar entre :min y :max.', @@ -99,7 +99,7 @@ return [ ], 'string' => 'El atributo :attribute debe ser una cadena.', 'timezone' => 'El atributo :attribute debe ser una zona válida.', - 'totp' => 'El código suministrado no es válido o ya ha expirado.', + 'totp' => 'El código suministrado no es válido o ya expiró.', 'unique' => 'El atributo :attribute ya ha sido tomado.', 'url' => 'El atributo :attribute tiene un formato inválido.', 'uploaded' => 'El archivo no se pudo subir. Puede ser que el servidor no acepte archivos de este tamaño.', diff --git a/resources/views/errors/debug.blade.php b/resources/views/errors/debug.blade.php new file mode 100644 index 000000000..e7155431c --- /dev/null +++ b/resources/views/errors/debug.blade.php @@ -0,0 +1,146 @@ + + + + + + Error: {{ $error }} + + + + +
+ +

+ WARNING: Application is in debug mode. This mode has the potential to leak confidential + information and therefore should not be used in production or publicly + accessible environments. +

+ +
+

Error

+

{{ $errorClass }}

+

{{ $error }}

+
+ + + +
+

Environment

+
    + @foreach($environment as $label => $text) +
  • {{ $label }}: {{ $text }}
  • + @endforeach +
+
+ +
+

Stack Trace

+
{{ $trace }}
+
+ +
+ + \ No newline at end of file diff --git a/tests/Auth/AuthTest.php b/tests/Auth/AuthTest.php index d037b5701..f19011c46 100644 --- a/tests/Auth/AuthTest.php +++ b/tests/Auth/AuthTest.php @@ -282,6 +282,22 @@ class AuthTest extends TestCase ->assertElementContains('a', 'Sign up'); } + public function test_reset_password_request_is_throttled() + { + $editor = $this->getEditor(); + Notification::fake(); + $this->get('/password/email'); + $this->followingRedirects()->post('/password/email', [ + 'email' => $editor->email, + ]); + + $resp = $this->followingRedirects()->post('/password/email', [ + 'email' => $editor->email, + ]); + Notification::assertTimesSent(1, ResetPassword::class); + $resp->assertSee('A password reset link will be sent to ' . $editor->email . ' if that email address is found in the system.'); + } + public function test_login_redirects_to_initially_requested_url_correctly() { config()->set('app.url', 'http://localhost'); diff --git a/tests/Auth/MfaConfigurationTest.php b/tests/Auth/MfaConfigurationTest.php index 685aad83a..59a2a41b5 100644 --- a/tests/Auth/MfaConfigurationTest.php +++ b/tests/Auth/MfaConfigurationTest.php @@ -4,6 +4,7 @@ namespace Tests\Auth; use BookStack\Actions\ActivityType; use BookStack\Auth\Access\Mfa\MfaValue; +use BookStack\Auth\Role; use BookStack\Auth\User; use PragmaRX\Google2FA\Google2FA; use Tests\TestCase; @@ -164,4 +165,22 @@ class MfaConfigurationTest extends TestCase $this->assertActivityExists(ActivityType::MFA_REMOVE_METHOD); $this->assertEquals(0, $admin->mfaValues()->count()); } + + public function test_totp_setup_url_shows_correct_user_when_setup_forced_upon_login() + { + $admin = $this->getAdmin(); + /** @var Role $role */ + $role = $admin->roles()->first(); + $role->mfa_enforced = true; + $role->save(); + + $resp = $this->post('/login', ['email' => $admin->email, 'password' => 'password']); + $this->assertFalse(auth()->check()); + $resp->assertRedirect('/mfa/verify'); + + $resp = $this->get('/mfa/totp/generate'); + $resp->assertSeeText('Mobile App Setup'); + $resp->assertDontSee('otpauth://totp/BookStack:guest%40example.com'); + $resp->assertSee('otpauth://totp/BookStack:admin%40admin.com'); + } } diff --git a/tests/DebugViewTest.php b/tests/DebugViewTest.php new file mode 100644 index 000000000..63d6472b9 --- /dev/null +++ b/tests/DebugViewTest.php @@ -0,0 +1,53 @@ +set('app.debug', true); + $resp = $this->getDebugViewForException(new \InvalidArgumentException('An error occurred during testing')); + + // Error message + $resp->assertSeeText('An error occurred during testing'); + // Exception Class + $resp->assertSeeText('InvalidArgumentException'); + // Stack trace + $resp->assertSeeText('#0'); + $resp->assertSeeText('#1'); + // Warning message + $resp->assertSeeText('WARNING: Application is in debug mode. This mode has the potential to leak'); + // PHP version + $resp->assertSeeText('PHP Version: ' . phpversion()); + // BookStack version + $resp->assertSeeText('BookStack Version: ' . trim(file_get_contents(base_path('version')))); + // Dynamic help links + $resp->assertElementExists('a[href*="q=' . urlencode('BookStack An error occurred during testing') . '"]'); + $resp->assertElementExists('a[href*="?q=is%3Aissue+' . urlencode('An error occurred during testing') . '"]'); + } + + public function test_debug_view_only_shows_when_debug_mode_is_enabled() + { + config()->set('app.debug', true); + $resp = $this->getDebugViewForException(new \InvalidArgumentException('An error occurred during testing')); + $resp->assertSeeText('Stack Trace'); + $resp->assertDontSeeText('An unknown error occurred'); + + config()->set('app.debug', false); + $resp = $this->getDebugViewForException(new \InvalidArgumentException('An error occurred during testing')); + $resp->assertDontSeeText('Stack Trace'); + $resp->assertSeeText('An unknown error occurred'); + } + + protected function getDebugViewForException(\Exception $exception): TestResponse + { + // Fake an error via social auth service used on login page + $mockService = $this->mock(SocialAuthService::class); + $mockService->shouldReceive('getActiveDrivers')->andThrow($exception); + + return $this->get('/login'); + } +}