-
Notifications
You must be signed in to change notification settings - Fork 4
Automatically roll SSL certs #850
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,7 @@ | |
|
|
||
| use Composer\Command\BaseCommand; | ||
| use Composer\Composer; | ||
| use Exception; | ||
| use Symfony\Component\Console\Input\ArrayInput; | ||
| use Symfony\Component\Console\Input\InputArgument; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
|
|
@@ -34,7 +35,7 @@ | |
| * | ||
| * @var array | ||
| */ | ||
| protected array $package_config; | ||
|
Check failure on line 38 in inc/composer/class-command.php
|
||
|
|
||
| /** | ||
| * Command configuration. | ||
|
|
@@ -280,18 +281,29 @@ | |
|
|
||
| // Generate SSL certificate if not found, and the secure flag is turned on. | ||
| $is_secure = $this->is_using_codespaces() ? false : static::get_composer_config()['secure'] ?? true; | ||
| if ( $is_secure && ! file_exists( 'vendor/ssl-cert.pem' ) ) { | ||
| // Create the certificate programmatically. | ||
| $not_generated = $this->getApplication()->find( 'local-server' )->run( new ArrayInput( [ | ||
| 'subcommand' => 'ssl', | ||
| 'options' => [ | ||
| 'generate', | ||
| '*.altis.dev', // default domain, configured names will be automatically added. | ||
| ], | ||
| ] ), $output ); | ||
| if ( $is_secure ) { | ||
| // Do we need to regenerate the certificate? | ||
| $needs_new_cert = false; | ||
| if ( ! file_exists( 'vendor/ssl-cert.pem' ) ) { | ||
| $needs_new_cert = true; | ||
| } elseif ( $this->check_ssl_expiry( 'vendor/ssl-cert.pem' ) < 30 ) { | ||
| $output->writeln( '<info>Certificate is expiring in less than 30 days, regenerating.</>' ); | ||
| $needs_new_cert = true; | ||
| } | ||
|
|
||
| if ( $not_generated ) { | ||
| return $not_generated; | ||
| // Create the certificate programmatically. | ||
| if ( $needs_new_cert ) { | ||
| $not_generated = $this->getApplication()->find( 'local-server' )->run( new ArrayInput( [ | ||
| 'subcommand' => 'ssl', | ||
| 'options' => [ | ||
| 'generate', | ||
| '*.altis.dev', // default domain, configured names will be automatically added. | ||
| ], | ||
| ] ), $output ); | ||
|
|
||
| if ( $not_generated ) { | ||
| return $not_generated; | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -971,15 +983,22 @@ | |
| break; | ||
|
|
||
| case '': | ||
| $cert_exists = file_exists( 'vendor/ssl-cert.pem' ) && file_exists( 'vendor/ssl-key.pem' ); | ||
| $cert_file = 'vendor/ssl-cert.pem'; | ||
| $cert_exists = file_exists( $cert_file ) && file_exists( $cert_file ); | ||
| if ( ! $cert_exists ) { | ||
| $output->writeln( "<error>Certificate file does not exist. Use 'composer server ssl generate' to generate one. </error>" ); | ||
| return 1; | ||
| } else { | ||
| $output->writeln( '<info>Certificate file exists.</info>' ); | ||
| } | ||
|
|
||
| break; | ||
| // Check certificate expiration. | ||
| $validity_remaining = $this->check_ssl_expiry( $cert_file ); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm are we catching this error? Do we want to block being able to start the server if the |
||
| if ( $validity_remaining < 0 ) { | ||
| $output->writeln( "<error>Certificate has expired. Use 'composer server ssl generate' to regenerate it.</error>" ); | ||
| return 1; | ||
| } | ||
|
|
||
| $output->writeln( "<info>Certificate exists and is valid for $validity_remaining more days</info>" ); | ||
| return 0; | ||
|
|
||
| default: | ||
| $output->writeln( "<error>The subcommand $subcommand is not recognized</error>" ); | ||
|
|
@@ -1011,6 +1030,27 @@ | |
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Get the SSL certificate expiration date. | ||
| * | ||
| * @throws Exception If openssl is missing, the certificate is invalid, or it cannot be read. | ||
| * @param string $path Path to the certificate file. | ||
| * @return int Days until expiry. If negative, the certificate has already expired. | ||
| */ | ||
| protected function check_ssl_expiry( string $path ) : int { | ||
| $cert_info = shell_exec( "openssl x509 -in $path -noout -enddate 2>/dev/null" ); | ||
| if ( ! $cert_info ) { | ||
| throw new Exception( 'Unable to retrieve certificate information.' ); | ||
| } | ||
|
|
||
| // Parse the date and check if expired. | ||
| if ( ! preg_match( '/notAfter=(.+)/', $cert_info, $matches ) ) { | ||
| throw new Exception( 'Unable to parse certificate expiration date.' ); | ||
| } | ||
| $expiry_date = strtotime( $matches[1] ); | ||
| return ceil( ( $expiry_date - time() ) / 86400 ); | ||
| } | ||
|
|
||
| /** | ||
| * Check and notify about required /etc/hosts entries. | ||
| * | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this second test be for the key file?