diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0279f10..496ad20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: timeout-minutes: 5 strategy: matrix: - php: ["8.1", "8.2", "8.3"] + php: ["8.1", "8.2", "8.3", "8.4"] env: extensions: mbstring, pcov ini: pcov.directory=., "pcov.exclude=\"~(vendor|tests)~\"" diff --git a/README.md b/README.md index 84483b9..4d992ec 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ This should print the Kirby CLI version and a list of available commands - kirby register - kirby remove:command - kirby roots +- kirby security - kirby unzip - kirby upgrade - kirby uuid:generate @@ -300,7 +301,8 @@ return [ - **[Forum](https://forum.getkirby.com)** – Whenever you get stuck, don't hesitate to reach out for questions and support. - **[Discord](https://chat.getkirby.com)** – Hang out and meet the community. - **[YouTube](https://youtube.com/kirbyCasts)** - Watch the latest video tutorials visually with Bastian. -- **[Mastodon](https://mastodon.social/@getkirby)** – Spread the word. +- **[Mastodon](https://mastodon.social/@getkirby)** – Follow us in the Fediverse. +- **[Bluesky](https://bsky.app/profile/getkirby.com)** – Follow us on Bluesky. - **[Instagram](https://www.instagram.com/getkirby/)** – Share your creations: #madewithkirby. --- diff --git a/bootstrap.php b/bootstrap.php index f456917..910470d 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -12,9 +12,9 @@ function bootstrap(): string|null // avoid any output in the CLI $_ENV['KIRBY_RENDER'] = false; - if (empty($_ENV['KIRBY_HOST']) === false) { - $_SERVER['SERVER_NAME'] = $_ENV['KIRBY_HOST']; - $_SERVER['HTTP_HOST'] = $_ENV['KIRBY_HOST']; + if ($host = getenv('KIRBY_HOST')) { + $_SERVER['SERVER_NAME'] = $host; + $_SERVER['HTTP_HOST'] = $host; } ob_start(); diff --git a/commands/security.php b/commands/security.php new file mode 100644 index 0000000..5155e52 --- /dev/null +++ b/commands/security.php @@ -0,0 +1,57 @@ + 'Performs security checks of the site', + 'command' => static function (CLI $cli): void { + $kirby = $cli->kirby(); + $system = $kirby->system(); + $updateStatus = $system->updateStatus(); + $messages = [ + ...array_column($updateStatus?->messages() ?? [], 'text'), + ...$updateStatus->exceptionMessages() + ]; + + if ($kirby->option('debug', false) === true) { + $messages[] = I18n::translate('system.issues.debug'); + } + + if ($kirby->environment()->https() !== true) { + $messages[] = I18n::translate('system.issues.https'); + } + + // checks exposable urls of the site + // works only site url is absolute since can't get it in CLI mode + // and CURL won't work for relative urls + if (Url::isAbsolute($kirby->url())) { + $urls = [ + 'content' => $system->exposedFileUrl('content'), + 'git' => $system->exposedFileUrl('git'), + 'kirby' => $system->exposedFileUrl('kirby'), + 'site' => $system->exposedFileUrl('site') + ]; + + foreach ($urls as $key => $url) { + if (empty($url) === false && Remote::get($url)->code() < 400) { + $messages[] = I18n::translate('system.issues.' . $key); + } + } + } else { + $messages[] = 'Could not check for exposed folders as the site URL is not absolute'; + } + + if (empty($messages) === false) { + foreach ($messages as $message) { + $cli->error('> ' . $message); + } + } else { + $cli->success('Basic security checks were successful, please review https://getkirby.com/docs/guide/security for additional best practices.'); + } + } +]; diff --git a/composer.json b/composer.json index 9bea508..9aa5782 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "getkirby/cli", "description": "Kirby command line interface", "license": "MIT", - "version": "1.5.0", + "version": "1.6.0", "keywords": [ "kirby", "cms", @@ -24,11 +24,11 @@ "source": "https://github.com/getkirby/cli" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", "ext-zip": "*", "composer-runtime-api": "^2.2", - "guzzlehttp/guzzle": "^7.8", - "league/climate": "^3.8.2" + "guzzlehttp/guzzle": "^7.9.2", + "league/climate": "^3.10.0" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 8dedd95..4b20d8c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,26 +4,26 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "361a47582c9946f984b0dd2654e9cb87", + "content-hash": "0f8fe4de12fd58407112d9344df28512", "packages": [ { "name": "guzzlehttp/guzzle", - "version": "7.8.1", + "version": "7.9.2", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" + "reference": "d281ed313b989f213357e3be1a179f02196ac99b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", - "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.1", - "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -34,9 +34,9 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", - "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "guzzle/client-integration-tests": "3.0.2", "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { @@ -114,7 +114,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.8.1" + "source": "https://github.com/guzzle/guzzle/tree/7.9.2" }, "funding": [ { @@ -130,20 +130,20 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:35:24+00:00" + "time": "2024-07-24T11:22:20+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.0.2", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" + "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", - "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", + "url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455", + "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455", "shasum": "" }, "require": { @@ -151,7 +151,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.36 || ^9.6.15" + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "type": "library", "extra": { @@ -197,7 +197,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.2" + "source": "https://github.com/guzzle/promises/tree/2.0.4" }, "funding": [ { @@ -213,20 +213,20 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:19:20+00:00" + "time": "2024-10-17T10:06:22+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.6.2", + "version": "2.7.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", - "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", "shasum": "" }, "require": { @@ -241,8 +241,8 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.36 || ^9.6.15" + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -313,7 +313,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.6.2" + "source": "https://github.com/guzzle/psr7/tree/2.7.0" }, "funding": [ { @@ -329,20 +329,20 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:05:35+00:00" + "time": "2024-07-18T11:15:46+00:00" }, { "name": "league/climate", - "version": "3.8.2", + "version": "3.10.0", "source": { "type": "git", "url": "https://github.com/thephpleague/climate.git", - "reference": "a785a3ac8f584eed4abd45e4e16fe64c46659a28" + "reference": "237f70e1032b16d32ff3f65dcda68706911e1c74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/climate/zipball/a785a3ac8f584eed4abd45e4e16fe64c46659a28", - "reference": "a785a3ac8f584eed4abd45e4e16fe64c46659a28", + "url": "https://api.github.com/repos/thephpleague/climate/zipball/237f70e1032b16d32ff3f65dcda68706911e1c74", + "reference": "237f70e1032b16d32ff3f65dcda68706911e1c74", "shasum": "" }, "require": { @@ -351,9 +351,10 @@ "seld/cli-prompt": "^1.0" }, "require-dev": { - "mikey179/vfsstream": "^1.6.10", - "mockery/mockery": "^1.4.2", - "phpunit/phpunit": "^9.5.10" + "mikey179/vfsstream": "^1.6.12", + "mockery/mockery": "^1.6.12", + "phpunit/phpunit": "^9.5.10", + "squizlabs/php_codesniffer": "^3.10" }, "suggest": { "ext-mbstring": "If ext-mbstring is not available you MUST install symfony/polyfill-mbstring" @@ -392,9 +393,9 @@ ], "support": { "issues": "https://github.com/thephpleague/climate/issues", - "source": "https://github.com/thephpleague/climate/tree/3.8.2" + "source": "https://github.com/thephpleague/climate/tree/3.10.0" }, - "time": "2022-06-18T14:42:08+00:00" + "time": "2024-11-18T09:09:55+00:00" }, { "name": "psr/http-client", @@ -450,20 +451,20 @@ }, { "name": "psr/http-factory", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "e616d01114759c4c489f93b099585439f795fe35" + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", - "reference": "e616d01114759c4c489f93b099585439f795fe35", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", "shasum": "" }, "require": { - "php": ">=7.0.0", + "php": ">=7.1", "psr/http-message": "^1.0 || ^2.0" }, "type": "library", @@ -487,7 +488,7 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common interfaces for PSR-7 HTTP message factories", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ "factory", "http", @@ -499,9 +500,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2023-04-10T20:10:41+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { "name": "psr/http-message", @@ -558,16 +559,16 @@ }, { "name": "psr/log", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -602,9 +603,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2021-07-14T16:46:02+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "ralouphie/getallheaders", @@ -707,16 +708,16 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.4.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", "shasum": "" }, "require": { @@ -724,12 +725,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -754,7 +755,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" }, "funding": [ { @@ -770,7 +771,7 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-09-25T14:20:29+00:00" } ], "packages-dev": [], @@ -780,7 +781,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", "ext-zip": "*", "composer-runtime-api": "^2.2" },