Skip to content

Commit 3e0923a

Browse files
authored
Merge pull request #456 from mrrobot47/fix/db-entry
Add migration to fix SSL flag in DB for edge cases
2 parents 02de049 + bc132ce commit 3e0923a

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
3+
namespace EE\Migration;
4+
5+
use EE;
6+
use EE\Model\Site;
7+
use EE\Migration\Base;
8+
9+
class FixSslFlagForExistingLeCerts extends Base {
10+
public function __construct() {
11+
parent::__construct();
12+
$this->sites = Site::all();
13+
if ( $this->is_first_execution || ! $this->sites ) {
14+
$this->skip_this_migration = true;
15+
}
16+
}
17+
18+
public function up() {
19+
if ( $this->skip_this_migration ) {
20+
EE::debug( 'Skipping fix_ssl_flag_for_existing_le_certs migration as it is not needed.' );
21+
22+
return;
23+
}
24+
$certs_dir = EE_ROOT_DIR . '/services/nginx-proxy/certs/';
25+
$conf_dir = EE_ROOT_DIR . '/services/nginx-proxy/conf.d/';
26+
$backup_dir = defined( 'EE_BACKUP_DIR' ) ? EE_BACKUP_DIR : EE_ROOT_DIR . '/.backup';
27+
if ( ! is_dir( $backup_dir ) ) {
28+
@mkdir( $backup_dir, 0755, true );
29+
}
30+
$log_file = $backup_dir . '/.ssl-fix.log';
31+
$log_entries = [];
32+
foreach ( $this->sites as $site ) {
33+
$site_url = $site->site_url;
34+
$crt = $certs_dir . $site_url . '.crt';
35+
$key = $certs_dir . $site_url . '.key';
36+
$chain = $certs_dir . $site_url . '.chain.pem';
37+
$redirect_conf = $conf_dir . $site_url . '-redirect.conf';
38+
39+
$crt_exists = file_exists( $crt );
40+
$key_exists = file_exists( $key );
41+
$chain_exists = file_exists( $chain );
42+
$db_ssl = $site->site_ssl;
43+
$actions = [];
44+
45+
// If redirect conf exists but no certs, remove conf and reload nginx proxy
46+
if ( file_exists( $redirect_conf ) && ( ! $crt_exists || ! $key_exists || ! $chain_exists ) ) {
47+
EE::log( "Removing orphan redirect conf for $site_url and reloading nginx proxy." );
48+
@unlink( $redirect_conf );
49+
$actions[] = "Removed redirect conf: $redirect_conf";
50+
\EE\Site\Utils\reload_global_nginx_proxy();
51+
}
52+
53+
if ( $crt_exists && $key_exists && $chain_exists ) {
54+
if ( empty( $db_ssl ) || $db_ssl !== 'le' ) {
55+
// Check if the cert is a valid Let's Encrypt cert using CertificateParser
56+
try {
57+
$crt_pem = file_get_contents( $crt );
58+
if ( ! function_exists( 'openssl_x509_parse' ) ) {
59+
EE::warning( "openssl_x509_parse() not available in PHP. Cannot check issuer for $site_url." );
60+
$actions[] = "openssl_x509_parse() not available, skipping Let's Encrypt detection";
61+
} else {
62+
$cert_data = openssl_x509_parse( $crt_pem );
63+
$issuer_full = isset( $cert_data['issuer'] ) ? $cert_data['issuer'] : [];
64+
$issuer_json = json_encode( $issuer_full );
65+
$subject_cn = isset( $cert_data['subject']['CN'] ) ? $cert_data['subject']['CN'] : '';
66+
$crt_pem_lines = implode( ' | ', array_slice( explode( "\n", $crt_pem ), 0, 2 ) );
67+
$actions[] = "Cert issuer: $issuer_json";
68+
$actions[] = "Cert subject CN: '$subject_cn'";
69+
$actions[] = "Cert PEM first lines: $crt_pem_lines";
70+
71+
// Check all issuer fields for 'Let's Encrypt'
72+
$le_found = false;
73+
foreach ( $issuer_full as $field => $value ) {
74+
if ( stripos( $value, "Let's Encrypt" ) !== false ) {
75+
$le_found = true;
76+
break;
77+
}
78+
}
79+
if ( $le_found ) {
80+
EE::log( "Updating SSL flag for site $site_url: found valid Let's Encrypt cert." );
81+
$site->site_ssl = 'le';
82+
$site->save();
83+
$actions[] = "Updated DB: set site_ssl=le (valid LE cert)";
84+
} else {
85+
$actions[] = "Cert is not from Let's Encrypt, no DB update";
86+
}
87+
}
88+
} catch ( \Exception $e ) {
89+
EE::debug( "Failed to parse certificate for $site_url: " . $e->getMessage() );
90+
$actions[] = "Failed to parse certificate: " . $e->getMessage();
91+
}
92+
}
93+
}
94+
95+
if ( empty( $actions ) ) {
96+
$actions[] = 'No action needed';
97+
}
98+
$log_entries[] = sprintf(
99+
"%s [%s] DB: '%s', crt: %s, key: %s, chain: %s -- %s",
100+
date( 'c' ),
101+
$site_url,
102+
$db_ssl === null ? '' : $db_ssl,
103+
$crt_exists ? 'yes' : 'no',
104+
$key_exists ? 'yes' : 'no',
105+
$chain_exists ? 'yes' : 'no',
106+
implode( '; ', $actions )
107+
);
108+
}
109+
if ( $log_entries ) {
110+
file_put_contents( $log_file, implode( "\n", $log_entries ) . "\n", FILE_APPEND );
111+
}
112+
}
113+
114+
public function down() {
115+
// No-op: This migration is not reversible.
116+
}
117+
}

0 commit comments

Comments
 (0)