diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 47540d84e..454e7ed34 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b466adcf..3f309fb4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Release Notes -## [Unreleased](https://github.com/laravel/valet/compare/v4.4.1...master) +## [Unreleased](https://github.com/laravel/valet/compare/v4.5.0...master) + +## [v4.5.0](https://github.com/laravel/valet/compare/v4.4.1...v4.5.0) - 2023-10-10 + +- Add support for proxying multiple domains at once by [@RobertBoes](https://github.com/RobertBoes) in https://github.com/laravel/valet/pull/1437 ## [v4.4.1](https://github.com/laravel/valet/compare/v4.4.0...v4.4.1) - 2023-10-03 diff --git a/cli/Valet/Brew.php b/cli/Valet/Brew.php index 121a13935..33d597bc8 100644 --- a/cli/Valet/Brew.php +++ b/cli/Valet/Brew.php @@ -292,7 +292,7 @@ function ($version) use ($resolvedPhpVersion) { * * @param string|null $phpVersion For example, "php@8.1" */ - public function getPhpExecutablePath(string $phpVersion = null): string + public function getPhpExecutablePath(?string $phpVersion = null): string { if (! $phpVersion) { return BREW_PREFIX.'/bin/php'; diff --git a/cli/Valet/CommandLine.php b/cli/Valet/CommandLine.php index 186d093bf..3d1841834 100644 --- a/cli/Valet/CommandLine.php +++ b/cli/Valet/CommandLine.php @@ -33,7 +33,7 @@ public function passthru(string $command): void /** * Run the given command as the non-root user. */ - public function run(string $command, callable $onError = null): string + public function run(string $command, ?callable $onError = null): string { return $this->runCommand($command, $onError); } @@ -41,7 +41,7 @@ public function run(string $command, callable $onError = null): string /** * Run the given command. */ - public function runAsUser(string $command, callable $onError = null): string + public function runAsUser(string $command, ?callable $onError = null): string { return $this->runCommand('sudo -u "'.user().'" '.$command, $onError); } @@ -49,7 +49,7 @@ public function runAsUser(string $command, callable $onError = null): string /** * Run the given command. */ - public function runCommand(string $command, callable $onError = null): string + public function runCommand(string $command, ?callable $onError = null): string { $onError = $onError ?: function () { }; diff --git a/cli/Valet/Expose.php b/cli/Valet/Expose.php index 7f9651c48..abb1428c0 100644 --- a/cli/Valet/Expose.php +++ b/cli/Valet/Expose.php @@ -11,7 +11,7 @@ public function __construct(public Composer $composer, public CommandLine $cli) { } - public function currentTunnelUrl(string $domain = null): ?string + public function currentTunnelUrl(?string $domain = null): ?string { $endpoint = 'http://127.0.0.1:4040/api/tunnels'; diff --git a/cli/Valet/Filesystem.php b/cli/Valet/Filesystem.php index eaeb1232c..3b16d7f94 100644 --- a/cli/Valet/Filesystem.php +++ b/cli/Valet/Filesystem.php @@ -19,7 +19,7 @@ public function isDir(string $path): bool /** * Create a directory. */ - public function mkdir(string $path, string $owner = null, int $mode = 0755): void + public function mkdir(string $path, ?string $owner = null, int $mode = 0755): void { mkdir($path, $mode, true); @@ -31,7 +31,7 @@ public function mkdir(string $path, string $owner = null, int $mode = 0755): voi /** * Ensure that the given directory exists. */ - public function ensureDirExists(string $path, string $owner = null, int $mode = 0755): void + public function ensureDirExists(string $path, ?string $owner = null, int $mode = 0755): void { if (! $this->isDir($path)) { $this->mkdir($path, $owner, $mode); @@ -49,7 +49,7 @@ public function mkdirAsUser(string $path, int $mode = 0755): void /** * Touch the given path. */ - public function touch(string $path, string $owner = null): string + public function touch(string $path, ?string $owner = null): string { touch($path); @@ -87,7 +87,7 @@ public function get(string $path): string /** * Write to the given file. */ - public function put(string $path, string $contents, string $owner = null): void + public function put(string $path, string $contents, ?string $owner = null): void { file_put_contents($path, $contents); @@ -107,7 +107,7 @@ public function putAsUser(string $path, ?string $contents): void /** * Append the contents to the given file. */ - public function append(string $path, string $contents, string $owner = null): void + public function append(string $path, string $contents, ?string $owner = null): void { file_put_contents($path, $contents, FILE_APPEND); diff --git a/cli/Valet/Ngrok.php b/cli/Valet/Ngrok.php index 222806677..245ce5a5b 100644 --- a/cli/Valet/Ngrok.php +++ b/cli/Valet/Ngrok.php @@ -20,7 +20,7 @@ public function __construct(public CommandLine $cli, public Brew $brew) /** * Get the current tunnel URL from the Ngrok API. */ - public function currentTunnelUrl(string $domain = null): string + public function currentTunnelUrl(?string $domain = null): string { // wait a second for ngrok to start before attempting to find available tunnels sleep(1); @@ -51,20 +51,30 @@ public function currentTunnelUrl(string $domain = null): string } /** - * Find the HTTP tunnel URL from the list of tunnels. + * Find the HTTP/HTTPS tunnel URL from the list of tunnels. */ public function findHttpTunnelUrl(array $tunnels, string $domain): ?string { + $httpTunnel = null; + $httpsTunnel = null; + // If there are active tunnels on the Ngrok instance we will spin through them and // find the one responding on HTTP. Each tunnel has an HTTP and a HTTPS address - // but for local dev purposes we just desire the plain HTTP URL endpoint. + // if no HTTP tunnel is found we will return the HTTPS tunnel as a fallback. + + // Iterate through tunnels to find both HTTP and HTTPS tunnels foreach ($tunnels as $tunnel) { - if ($tunnel->proto === 'http' && strpos($tunnel->config->addr, strtolower($domain))) { - return $tunnel->public_url; + if (stripos($tunnel->config->addr, $domain)) { + if ($tunnel->proto === 'http') { + $httpTunnel = $tunnel->public_url; + } elseif ($tunnel->proto === 'https') { + $httpsTunnel = $tunnel->public_url; + } } } - return null; + // Return HTTP tunnel if available; HTTPS tunnel if not; null if neither + return $httpTunnel ?? $httpsTunnel; } /** diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 75c92d896..9c5e86c92 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -102,7 +102,7 @@ public function createConfigurationFiles(string $phpVersion): void /** * Restart the PHP FPM process (if one specified) or processes (if none specified). */ - public function restart(string $phpVersion = null): void + public function restart(?string $phpVersion = null): void { $this->brew->restartService($phpVersion ?: $this->utilizedPhpVersions()); } @@ -122,7 +122,7 @@ public function stop(): void /** * Get the path to the FPM configuration file for the current PHP version. */ - public function fpmConfigPath(string $phpVersion = null): string + public function fpmConfigPath(?string $phpVersion = null): string { if (! $phpVersion) { $phpVersion = $this->brew->linkedPhp(); @@ -152,7 +152,7 @@ public function stopRunning(): void /** * Stop a given PHP version, if that specific version isn't being used globally or by any sites. */ - public function stopIfUnused(string $phpVersion = null): void + public function stopIfUnused(?string $phpVersion = null): void { if (! $phpVersion) { return; @@ -305,7 +305,7 @@ public function validateRequestedVersion(string $version): string /** * Get FPM sock file name for a given PHP version. */ - public static function fpmSockName(string $phpVersion = null): string + public static function fpmSockName(?string $phpVersion = null): string { $versionInteger = preg_replace('~[^\d]~', '', $phpVersion); diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index 122610e48..29814bbed 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -2,6 +2,7 @@ namespace Valet; +use DateTime; use DomainException; use Illuminate\Support\Collection; use PhpFpm; @@ -188,7 +189,7 @@ public function getSiteUrl(string $directory): string /** * Identify whether a site is for a proxy by reading the host name from its config file. */ - public function getProxyHostForSite(string $site, string $configContents = null): ?string + public function getProxyHostForSite(string $site, ?string $configContents = null): ?string { $siteConf = $configContents ?: $this->getSiteConfigFileContents($site); @@ -207,7 +208,7 @@ public function getProxyHostForSite(string $site, string $configContents = null) /** * Get the contents of the configuration for the given site. */ - public function getSiteConfigFileContents(string $site, string $suffix = null): ?string + public function getSiteConfigFileContents(string $site, ?string $suffix = null): ?string { $config = $this->config->read(); $suffix = $suffix ?: '.'.$config['tld']; @@ -219,7 +220,7 @@ public function getSiteConfigFileContents(string $site, string $suffix = null): /** * Get all certificates from config folder. */ - public function getCertificates(string $path = null): Collection + public function getCertificates(?string $path = null): Collection { $path = $path ?: $this->certificatesPath(); @@ -283,7 +284,7 @@ public function getSites(string $path, Collection $certs): Collection /** * Unlink the given symbolic link. */ - public function unlink(string $name = null): string + public function unlink(?string $name = null): string { $name = $this->getSiteLinkName($name); @@ -435,6 +436,25 @@ public function secured(): array })->unique()->values()->all(); } + /** + * Get all of the URLs with expiration dates that are currently secured. + */ + public function securedWithDates(): array + { + return collect($this->secured())->map(function ($site) { + $filePath = $this->certificatesPath().'/'.$site.'.crt'; + + $expiration = $this->cli->run("openssl x509 -enddate -noout -in $filePath"); + + $expiration = str_replace('notAfter=', '', $expiration); + + return [ + 'site' => $site, + 'exp' => new DateTime($expiration), + ]; + })->unique()->values()->all(); + } + public function isSecured(string $site): bool { $tld = $this->config->read()['tld']; @@ -452,7 +472,7 @@ public function isSecured(string $site): bool * * @see https://github.com/cabforum/servercert/blob/main/docs/BR.md */ - public function secure(string $url, string $siteConf = null, int $certificateExpireInDays = 396, int $caExpireInYears = 20): void + public function secure(string $url, ?string $siteConf = null, int $certificateExpireInDays = 396, int $caExpireInYears = 20): void { // Extract in order to later preserve custom PHP version config when securing $phpVersion = $this->customPhpVersion($url); @@ -480,6 +500,20 @@ public function secure(string $url, string $siteConf = null, int $certificateExp $this->files->putAsUser($this->nginxPath($url), $siteConf); } + /** + * Renews all domains with a trusted TLS certificate. + */ + public function renew($expireIn): void + { + collect($this->securedWithDates())->each(function ($row) use ($expireIn) { + $url = $this->domain($row['site']); + + $this->secure($url, null, $expireIn); + + info('The ['.$url.'] site has been secured with a fresh TLS certificate.'); + }); + } + /** * If CA and root certificates are nonexistent, create them and trust the root cert. * @@ -628,11 +662,14 @@ public function buildCertificateConf(string $path, string $url): void /** * Build the TLS secured Nginx server for the given URL. */ - public function buildSecureNginxServer(string $url, string $siteConf = null): string + public function buildSecureNginxServer(string $url, ?string $siteConf = null): string { if ($siteConf === null) { + $nginxVersion = str_replace('nginx version: nginx/', '', exec('nginx -v 2>&1')); + $configFile = version_compare($nginxVersion, '1.25.1', '>=') ? 'secure.valet.conf' : 'secure.valet-legacy.conf'; + $siteConf = $this->replaceOldLoopbackWithNew( - $this->files->getStub('secure.valet.conf'), + $this->files->getStub($configFile), 'VALET_LOOPBACK', $this->valetLoopback() ); @@ -774,8 +811,11 @@ public function proxyCreate(string $url, string $host, bool $secure = false): vo $proxyUrl .= '.'.$tld; } + $nginxVersion = str_replace('nginx version: nginx/', '', exec('nginx -v 2>&1')); + $configFile = version_compare($nginxVersion, '1.25.1', '>=') ? 'secure.proxy.valet.conf' : 'secure.proxy.valet-legacy.conf'; + $siteConf = $this->replaceOldLoopbackWithNew( - $this->files->getStub($secure ? 'secure.proxy.valet.conf' : 'proxy.valet.conf'), + $this->files->getStub($secure ? $configFile : 'proxy.valet.conf'), 'VALET_LOOPBACK', $this->valetLoopback() ); @@ -943,7 +983,7 @@ public function plistPath(): string /** * Get the path to Nginx site configuration files. */ - public function nginxPath(string $additionalPath = null): string + public function nginxPath(?string $additionalPath = null): string { return $this->valetHomePath().'/Nginx'.($additionalPath ? '/'.$additionalPath : ''); } @@ -951,7 +991,7 @@ public function nginxPath(string $additionalPath = null): string /** * Get the path to the linked Valet sites. */ - public function sitesPath(string $link = null): string + public function sitesPath(?string $link = null): string { return $this->valetHomePath().'/Sites'.($link ? '/'.$link : ''); } @@ -959,7 +999,7 @@ public function sitesPath(string $link = null): string /** * Get the path to the Valet CA certificates. */ - public function caPath(string $caFile = null): string + public function caPath(?string $caFile = null): string { return $this->valetHomePath().'/CA'.($caFile ? '/'.$caFile : ''); } @@ -967,7 +1007,7 @@ public function caPath(string $caFile = null): string /** * Get the path to the Valet TLS certificates. */ - public function certificatesPath(string $url = null, string $extension = null): string + public function certificatesPath(?string $url = null, ?string $extension = null): string { $url = $url ? '/'.$url : ''; $extension = $extension ? '.'.$extension : ''; @@ -1051,7 +1091,7 @@ public function replaceSockFile(string $siteConf, string $phpVersion): string /** * Get configuration items defined in .valetrc for a site. */ - public function valetRc(string $siteName, string $cwd = null): array + public function valetRc(string $siteName, ?string $cwd = null): array { if ($cwd) { $path = $cwd.'/.valetrc'; @@ -1077,7 +1117,7 @@ public function valetRc(string $siteName, string $cwd = null): array /** * Get PHP version from .valetrc or .valetphprc for a site. */ - public function phpRcVersion(string $siteName, string $cwd = null): ?string + public function phpRcVersion(string $siteName, ?string $cwd = null): ?string { if ($cwd) { $oldPath = $cwd.'/.valetphprc'; diff --git a/cli/app.php b/cli/app.php index 61eeef510..08ffd4434 100644 --- a/cli/app.php +++ b/cli/app.php @@ -33,7 +33,7 @@ */ Container::setInstance(new Container); -$version = '4.5.0'; +$version = '4.6.0'; $app = new Application('Laravel Valet', $version); @@ -61,6 +61,7 @@ function (ConsoleCommandEvent $event) { output(); DnsMasq::install(Configuration::read()['tld']); output(); + Site::renew(); Nginx::restart(); output(); Valet::symlinkToUsersBin(); @@ -278,13 +279,33 @@ function (ConsoleCommandEvent $event) { /** * Display all of the currently secured sites. */ - $app->command('secured', function (OutputInterface $output) { - $sites = collect(Site::secured())->map(function ($url) { - return ['Site' => $url]; - }); + $app->command('secured [--expiring] [--days=]', function (OutputInterface $output, $expiring = null, $days = 60) { + $now = (new Datetime())->add(new DateInterval('P'.$days.'D')); + $sites = collect(Site::securedWithDates()) + ->when($expiring, fn ($collection) => $collection->filter(fn ($row) => $row['exp'] < $now)) + ->map(function ($row) { + return [ + 'Site' => $row['site'], + 'Valid Until' => $row['exp']->format('Y-m-d H:i:s T'), + ]; + }) + ->when($expiring, fn ($collection) => $collection->sortBy('Valid Until')); + + return table(['Site', 'Valid Until'], $sites->all()); + })->descriptions('Display all of the currently secured sites', [ + '--expiring' => 'Limits the results to only sites expiring within the next 60 days.', + '--days' => 'To be used with --expiring. Limits the results to only sites expiring within the next X days. Default is set to 60.', + ]); - table(['Site'], $sites->all()); - })->descriptions('Display all of the currently secured sites'); + /** + * Renews all domains with a trusted TLS certificate. + */ + $app->command('renew [--expireIn=]', function (OutputInterface $output, $expireIn = 368) { + Site::renew($expireIn); + Nginx::restart(); + })->descriptions('Renews all domains with a trusted TLS certificate.', [ + '--expireIn' => 'The amount of days the self signed certificate is valid for. Default is set to "368"', + ]); /** * Create an Nginx proxy config for the specified domain. diff --git a/cli/includes/helpers.php b/cli/includes/helpers.php index 475594f05..f9d0ce89e 100644 --- a/cli/includes/helpers.php +++ b/cli/includes/helpers.php @@ -32,7 +32,7 @@ /** * Set or get a global console writer. */ -function writer(OutputInterface $writer = null): OutputInterface|\NullWriter|null +function writer(?OutputInterface $writer = null): OutputInterface|\NullWriter|null { $container = Container::getInstance(); diff --git a/cli/stubs/etc-phpfpm-valet.conf b/cli/stubs/etc-phpfpm-valet.conf index 67618bbc2..b4d82d32f 100644 --- a/cli/stubs/etc-phpfpm-valet.conf +++ b/cli/stubs/etc-phpfpm-valet.conf @@ -24,3 +24,9 @@ pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 +;; these are an attempt to mitigate 502 errors caused by segfaults in upstream processes caused by krb5 v1.21 added in June 2023 to php's core build. Ref Issue #1433 +; for gettext +env['LC_ALL'] = C +; for postgres +env['PGGSSENCMODE'] = disable + diff --git a/cli/stubs/secure.proxy.valet-legacy.conf b/cli/stubs/secure.proxy.valet-legacy.conf new file mode 100644 index 000000000..d1a69d176 --- /dev/null +++ b/cli/stubs/secure.proxy.valet-legacy.conf @@ -0,0 +1,57 @@ +# valet stub: secure.proxy.valet.conf + +server { + listen 127.0.0.1:80; + #listen VALET_LOOPBACK:80; # valet loopback + server_name VALET_SITE www.VALET_SITE *.VALET_SITE; + return 301 https://$host$request_uri; +} + +server { + listen 127.0.0.1:443 ssl http2; + #listen VALET_LOOPBACK:443 ssl http2; # valet loopback + server_name VALET_SITE www.VALET_SITE *.VALET_SITE; + root /; + charset utf-8; + client_max_body_size 128M; + http2_push_preload on; + + location /VALET_STATIC_PREFIX/ { + internal; + alias /; + try_files $uri $uri/; + } + + ssl_certificate "VALET_CERT"; + ssl_certificate_key "VALET_KEY"; + + access_log off; + error_log "VALET_HOME_PATH/Log/VALET_SITE-error.log"; + + error_page 404 "VALET_SERVER_PATH"; + + location / { + proxy_pass VALET_PROXY_HOST; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Client-Verify SUCCESS; + proxy_set_header X-Client-DN $ssl_client_s_dn; + proxy_set_header X-SSL-Subject $ssl_client_s_dn; + proxy_set_header X-SSL-Issuer $ssl_client_i_dn; + proxy_set_header X-NginX-Proxy true; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_http_version 1.1; + proxy_read_timeout 1800; + proxy_connect_timeout 1800; + chunked_transfer_encoding on; + proxy_redirect off; + proxy_buffering off; + } + + location ~ /\.ht { + deny all; + } +} diff --git a/cli/stubs/secure.proxy.valet.conf b/cli/stubs/secure.proxy.valet.conf index d1a69d176..68f28f118 100644 --- a/cli/stubs/secure.proxy.valet.conf +++ b/cli/stubs/secure.proxy.valet.conf @@ -8,13 +8,13 @@ server { } server { - listen 127.0.0.1:443 ssl http2; - #listen VALET_LOOPBACK:443 ssl http2; # valet loopback + listen 127.0.0.1:443 ssl; + #listen VALET_LOOPBACK:443 ssl; # valet loopback server_name VALET_SITE www.VALET_SITE *.VALET_SITE; root /; charset utf-8; client_max_body_size 128M; - http2_push_preload on; + http2 on; location /VALET_STATIC_PREFIX/ { internal; diff --git a/cli/stubs/secure.valet-legacy.conf b/cli/stubs/secure.valet-legacy.conf new file mode 100644 index 000000000..a7cd23104 --- /dev/null +++ b/cli/stubs/secure.valet-legacy.conf @@ -0,0 +1,93 @@ +server { + listen 127.0.0.1:80; + #listen VALET_LOOPBACK:80; # valet loopback + server_name VALET_SITE www.VALET_SITE *.VALET_SITE; + return 301 https://$host$request_uri; +} + +server { + listen 127.0.0.1:443 ssl http2; + #listen VALET_LOOPBACK:443 ssl http2; # valet loopback + server_name VALET_SITE www.VALET_SITE *.VALET_SITE; + root /; + charset utf-8; + client_max_body_size 512M; + http2_push_preload on; + + location /VALET_STATIC_PREFIX/ { + internal; + alias /; + try_files $uri $uri/; + } + + ssl_certificate "VALET_CERT"; + ssl_certificate_key "VALET_KEY"; + + location / { + rewrite ^ "VALET_SERVER_PATH" last; + } + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + access_log off; + error_log "VALET_HOME_PATH/Log/nginx-error.log"; + + error_page 404 "VALET_SERVER_PATH"; + + location ~ [^/]\.php(/|$) { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass "unix:VALET_HOME_PATH/valet.sock"; + fastcgi_index "VALET_SERVER_PATH"; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME "VALET_SERVER_PATH"; + fastcgi_param PATH_INFO $fastcgi_path_info; + } + + location ~ /\.ht { + deny all; + } +} + +server { + listen 127.0.0.1:60; + #listen VALET_LOOPBACK:60; # valet loopback + server_name VALET_SITE www.VALET_SITE *.VALET_SITE; + root /; + charset utf-8; + client_max_body_size 128M; + + add_header X-Robots-Tag 'noindex, nofollow, nosnippet, noarchive'; + + location /VALET_STATIC_PREFIX/ { + internal; + alias /; + try_files $uri $uri/; + } + + location / { + rewrite ^ "VALET_SERVER_PATH" last; + } + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + access_log off; + error_log "VALET_HOME_PATH/Log/nginx-error.log"; + + error_page 404 "VALET_SERVER_PATH"; + + location ~ [^/]\.php(/|$) { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass "unix:VALET_HOME_PATH/valet.sock"; + fastcgi_index "VALET_SERVER_PATH"; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME "VALET_SERVER_PATH"; + fastcgi_param PATH_INFO $fastcgi_path_info; + } + + location ~ /\.ht { + deny all; + } +} + diff --git a/cli/stubs/secure.valet.conf b/cli/stubs/secure.valet.conf index a7cd23104..c44db331c 100644 --- a/cli/stubs/secure.valet.conf +++ b/cli/stubs/secure.valet.conf @@ -6,13 +6,13 @@ server { } server { - listen 127.0.0.1:443 ssl http2; - #listen VALET_LOOPBACK:443 ssl http2; # valet loopback + listen 127.0.0.1:443 ssl; + #listen VALET_LOOPBACK:443 ssl; # valet loopback server_name VALET_SITE www.VALET_SITE *.VALET_SITE; root /; charset utf-8; client_max_body_size 512M; - http2_push_preload on; + http2 on; location /VALET_STATIC_PREFIX/ { internal; diff --git a/find-usable-php.php b/find-usable-php.php index 9ff3869d9..7af434ae9 100644 --- a/find-usable-php.php +++ b/find-usable-php.php @@ -52,7 +52,7 @@ * @param string|null $phpFormulaName For example, "php@8.1" * @return string */ -function getPhpExecutablePath(string $phpFormulaName = null) +function getPhpExecutablePath(?string $phpFormulaName = null) { $brewPrefix = exec('printf $(brew --prefix)'); diff --git a/tests/CliTest.php b/tests/CliTest.php index 59ece0715..c73637c22 100644 --- a/tests/CliTest.php +++ b/tests/CliTest.php @@ -436,7 +436,12 @@ public function test_secured_command() [$app, $tester] = $this->appAndTester(); $site = Mockery::mock(RealSite::class); - $site->shouldReceive('secured')->andReturn(['tighten.test']); + $site->shouldReceive('securedWithDates')->andReturn([ + [ + 'site' => 'tighten.test', + 'exp' => new DateTime('Aug 2 13:16:40 2024 GMT'), + ], + ]); swap(RealSite::class, $site); $tester->run(['command' => 'secured']); @@ -445,6 +450,22 @@ public function test_secured_command() $this->assertStringContainsString('tighten.test', $tester->getDisplay()); } + public function test_renew_command() + { + [$app, $tester] = $this->appAndTester(); + + $site = Mockery::mock(RealSite::class); + $site->shouldReceive('renew')->andReturn(); + swap(RealSite::class, $site); + + $nginx = Mockery::mock(Nginx::class); + $nginx->shouldReceive('restart')->once(); + swap(Nginx::class, $nginx); + + $tester->run(['command' => 'renew']); + $tester->assertCommandIsSuccessful(); + } + public function test_proxy_command() { [$app, $tester] = $this->appAndTester(); diff --git a/tests/NgrokTest.php b/tests/NgrokTest.php index 7f37da617..4191db664 100644 --- a/tests/NgrokTest.php +++ b/tests/NgrokTest.php @@ -47,10 +47,18 @@ public function test_it_matches_correct_share_tunnel() ], 'public_url' => 'http://right-one.ngrok.io/', ], + (object) [ + 'proto' => 'https', + 'config' => (object) [ + 'addr' => 'http://mysecuresite.test:80', + ], + 'public_url' => 'http://secure-right-one.ngrok.io/', + ], ]; $ngrok = resolve(Ngrok::class); $this->assertEquals('http://right-one.ngrok.io/', $ngrok->findHttpTunnelUrl($tunnels, 'mysite')); + $this->assertEquals('http://secure-right-one.ngrok.io/', $ngrok->findHttpTunnelUrl($tunnels, 'mysecuresite')); } public function test_it_checks_against_lowercased_domain() diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 9d4e50335..232b45c77 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -449,7 +449,7 @@ public function test_isolate_will_throw_if_site_is_not_parked_or_linked() class StubForUpdatingFpmConfigFiles extends PhpFpm { - public function fpmConfigPath(string $phpVersion = null): string + public function fpmConfigPath(?string $phpVersion = null): string { return __DIR__.'/output/fpm.conf'; } diff --git a/tests/SiteTest.php b/tests/SiteTest.php index d941b258c..d6201678a 100644 --- a/tests/SiteTest.php +++ b/tests/SiteTest.php @@ -1161,7 +1161,7 @@ public function test_it_can_read_php_rc_version() class CommandLineFake extends CommandLine { - public function runCommand(string $command, callable $onError = null): string + public function runCommand(string $command, ?callable $onError = null): string { // noop // @@ -1284,7 +1284,7 @@ public function assertCertificateExistsWithCounterValue($urlWithTld, $counter) class StubForRemovingLinks extends Site { - public function sitesPath(string $additionalPath = null): string + public function sitesPath(?string $additionalPath = null): string { return __DIR__.'/output'.($additionalPath ? '/'.$additionalPath : ''); }