diff --git a/src/helper/class-ee-site.php b/src/helper/class-ee-site.php index 08ad268e..cf82bc04 100644 --- a/src/helper/class-ee-site.php +++ b/src/helper/class-ee-site.php @@ -1540,7 +1540,7 @@ protected function init_le( $site_url, $site_fs_path, $wildcard = false, $www_or $this->site_data['site_fs_path'] = $site_fs_path; $this->site_data['site_ssl_wildcard'] = $wildcard; $client = new Site_Letsencrypt(); - $this->le_mail = \EE::get_runner()->config['le-mail'] ?? \EE::input( 'Enter your mail id: ' ); + $this->le_mail = $this->get_validated_le_mail( \EE::get_runner()->config['le-mail'] ?? null ); \EE::get_runner()->ensure_present_in_config( 'le-mail', $this->le_mail ); if ( ! $client->register( $this->le_mail ) ) { $this->site_data['site_ssl'] = null; @@ -1577,6 +1577,30 @@ protected function init_le( $site_url, $site_fs_path, $wildcard = false, $www_or } } + /** + * Resolves and validates the Let's Encrypt account email. + * + * `??` only guards null/unset, so an empty/garbage le-mail (e.g. an empty STDIN + * read during non-interactive cron runs) used to slip through to ACME and fail + * with an opaque error. Validate here so callers always get a real email. + * + * @param string|null $config_mail Email resolved from config by the caller, if any. + * + * @return string A non-empty, valid email address. + */ + private function get_validated_le_mail( $config_mail = null ) { + $mail = $config_mail; + if ( empty( $mail ) || ! filter_var( $mail, FILTER_VALIDATE_EMAIL ) ) { + // One re-prompt for interactive users; on non-interactive runs STDIN is empty and this stays empty. + $mail = \EE::input( 'Enter your mail id: ' ); + } + if ( empty( $mail ) || ! filter_var( $mail, FILTER_VALIDATE_EMAIL ) ) { + \EE::error( 'A valid Let\'s Encrypt email is required. Set it with `ee config set le-mail `.' ); + } + + return $mail; + } + /** * Returns all domains required by cert * @@ -1679,7 +1703,7 @@ public function ssl_verify( $args = [], $assoc_args = [], $www_or_non_www = fals } if ( ! isset( $this->le_mail ) ) { - $this->le_mail = \EE::get_config( 'le-mail' ) ?? \EE::input( 'Enter your mail id: ' ); + $this->le_mail = $this->get_validated_le_mail( \EE::get_config( 'le-mail' ) ); } $force = \EE\Utils\get_flag_value( $assoc_args, 'force' ); @@ -1944,10 +1968,6 @@ public function ssl_renew( $args, $assoc_args ) { EE::log( 'Starting SSL cert renewal' ); - if ( ! isset( $this->le_mail ) ) { - $this->le_mail = EE::get_config( 'le-mail' ) ?? EE::input( 'Enter your mail id: ' ); - } - $force = get_flag_value( $assoc_args, 'force', false ); $all = get_flag_value( $assoc_args, 'all', false ); @@ -1999,6 +2019,11 @@ private function renew_ssl_cert( $args, $force ) { EE::error( 'Only Letsencrypt certificate renewal is supported.' ); } + // Resolve le-mail only after confirming the site is LE, so non-LE sites hit the site-type error first. + if ( ! isset( $this->le_mail ) ) { + $this->le_mail = $this->get_validated_le_mail( EE::get_config( 'le-mail' ) ); + } + $client = new Site_Letsencrypt(); $preferred_challenge = get_preferred_ssl_challenge( get_domains_of_site( $this->site_data['site_url'] ) );