Add SSL monitoring (Svc, model, cron, UI)

Introduce SSL certificate monitoring: add SslService for fetching/parsing certs and parsing monitor targets, SslCertificate model for storing snapshots and managing monitored targets, and cron/check_ssl.php for scheduled checks. Extend DomainController with many SSL endpoints and helpers (add/refresh/bulk refresh/delete/bulk delete, snapshot handling, formatting, stats, safety checks) and surface SSL data in domain views. Add NotificationService helpers to create/send SSL alerts, update Installer to include new migration, add migration 028 to create ssl_certificates table, bump app version default to 1.1.5, update changelog, and modify routes and templates to include SSL tab and related UI. Logs and basic validation/error handling are included to surface SSL issues and protect default root-target behavior.
This commit is contained in:
Hosteroid
2026-03-08 21:12:09 +02:00
parent 8559e903b9
commit 5916daa293
17 changed files with 2460 additions and 349 deletions

View File

@@ -142,10 +142,14 @@ CREATE TABLE IF NOT EXISTS domains (
abuse_email VARCHAR(255),
last_checked TIMESTAMP NULL,
dns_last_checked TIMESTAMP NULL,
ssl_last_checked TIMESTAMP NULL,
crtsh_last_fetched DATETIME NULL DEFAULT NULL,
status ENUM('active', 'expiring_soon', 'expired', 'error', 'available', 'redemption_period', 'pending_delete') DEFAULT 'active',
whois_data JSON,
notes TEXT,
is_active BOOLEAN DEFAULT TRUE,
dns_monitoring_enabled TINYINT(1) NOT NULL DEFAULT 1,
ssl_monitoring_enabled TINYINT(1) NOT NULL DEFAULT 0,
user_id INT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
@@ -368,6 +372,38 @@ CREATE TABLE IF NOT EXISTS dns_records (
INDEX idx_last_seen (last_seen_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- SSL certificates table for tracking monitored TLS endpoints
CREATE TABLE IF NOT EXISTS ssl_certificates (
id INT AUTO_INCREMENT PRIMARY KEY,
domain_id INT NOT NULL,
hostname VARCHAR(255) NOT NULL,
port INT NOT NULL DEFAULT 443,
status ENUM('valid', 'expiring', 'expired', 'invalid') NOT NULL DEFAULT 'invalid',
is_trusted TINYINT(1) NOT NULL DEFAULT 0,
is_self_signed TINYINT(1) NOT NULL DEFAULT 0,
valid_from DATETIME NULL,
valid_to DATETIME NULL,
days_remaining INT NULL,
issuer_name VARCHAR(255) NULL,
subject_name VARCHAR(255) NULL,
serial_number VARCHAR(255) NULL,
signature_algorithm VARCHAR(100) NULL,
key_bits INT NULL,
key_type VARCHAR(20) NULL,
certificate_version VARCHAR(20) NULL,
san_list JSON NULL,
last_checked DATETIME NULL,
last_error TEXT NULL,
raw_data JSON NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (domain_id) REFERENCES domains(id) ON DELETE CASCADE,
UNIQUE KEY uniq_domain_host_port (domain_id, hostname, port),
INDEX idx_ssl_domain_id (domain_id),
INDEX idx_ssl_status (status),
INDEX idx_ssl_valid_to (valid_to)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- =====================================================
-- SYSTEM SETTINGS
-- =====================================================
@@ -389,7 +425,7 @@ INSERT INTO settings (setting_key, setting_value, `type`, `description`) VALUES
('app_name', 'Domain Monitor', 'string', 'Application name'),
('app_url', 'http://localhost:8000', 'string', 'Application URL'),
('app_timezone', 'UTC', 'string', 'Application timezone'),
('app_version', '1.1.4', 'string', 'Application version number'),
('app_version', '1.1.5', 'string', 'Application version number'),
-- Email settings
('mail_host', 'smtp.mailtrap.io', 'string', 'SMTP server host'),
@@ -431,6 +467,10 @@ INSERT INTO settings (setting_key, setting_value, `type`, `description`) VALUES
('dns_check_interval_hours', '24', 'string', 'DNS record check interval in hours'),
('last_dns_check_run', NULL, 'datetime', 'Last time DNS cron job ran'),
-- SSL monitoring settings
('ssl_check_interval_hours', '12', 'string', 'SSL certificate check interval in hours'),
('last_ssl_check_run', NULL, 'datetime', 'Last time SSL cron job ran'),
-- Update system settings
('update_channel', 'stable', 'string', 'Update channel: stable (releases only) or latest (releases + hotfixes)'),
('update_badge_enabled', '1', 'string', 'Show update available badge in top menu when an update is available (1=yes, 0=no)')

View File

@@ -0,0 +1,68 @@
-- SSL Monitoring - Add ssl_certificates table for tracking monitored TLS endpoints
CREATE TABLE IF NOT EXISTS ssl_certificates (
id INT AUTO_INCREMENT PRIMARY KEY,
domain_id INT NOT NULL,
hostname VARCHAR(255) NOT NULL,
port INT NOT NULL DEFAULT 443,
status ENUM('valid', 'expiring', 'expired', 'invalid') NOT NULL DEFAULT 'invalid',
is_trusted TINYINT(1) NOT NULL DEFAULT 0,
is_self_signed TINYINT(1) NOT NULL DEFAULT 0,
valid_from DATETIME NULL,
valid_to DATETIME NULL,
days_remaining INT NULL,
issuer_name VARCHAR(255) NULL,
subject_name VARCHAR(255) NULL,
serial_number VARCHAR(255) NULL,
signature_algorithm VARCHAR(100) NULL,
key_bits INT NULL,
key_type VARCHAR(20) NULL,
certificate_version VARCHAR(20) NULL,
san_list JSON NULL,
last_checked DATETIME NULL,
last_error TEXT NULL,
raw_data JSON NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (domain_id) REFERENCES domains(id) ON DELETE CASCADE,
UNIQUE KEY uniq_domain_host_port (domain_id, hostname, port),
INDEX idx_ssl_domain_id (domain_id),
INDEX idx_ssl_status (status),
INDEX idx_ssl_valid_to (valid_to)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- SSL Monitoring - Add per-domain toggle, timestamps, and cron settings
ALTER TABLE domains
ADD COLUMN ssl_last_checked TIMESTAMP NULL AFTER dns_last_checked,
ADD COLUMN ssl_monitoring_enabled TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1=SSL monitoring active, 0=disabled' AFTER dns_monitoring_enabled;
-- Preserve existing monitored SSL domains when upgrading
UPDATE domains d
SET d.ssl_monitoring_enabled = 1
WHERE EXISTS (
SELECT 1
FROM ssl_certificates s
WHERE s.domain_id = d.id
);
-- Carry forward the latest stored SSL check time
UPDATE domains d
JOIN (
SELECT domain_id, MAX(last_checked) AS max_checked
FROM ssl_certificates
GROUP BY domain_id
) s ON s.domain_id = d.id
SET d.ssl_last_checked = s.max_checked;
-- Add SSL monitoring cron settings
INSERT INTO settings (setting_key, setting_value, `type`, `description`) VALUES
('ssl_check_interval_hours', '12', 'string', 'SSL certificate check interval in hours'),
('last_ssl_check_run', NULL, 'datetime', 'Last time SSL cron job ran')
ON DUPLICATE KEY UPDATE setting_key=setting_key;
-- Update application version to 1.1.5
UPDATE settings
SET setting_value = '1.1.5'
WHERE setting_key = 'app_version';
INSERT INTO migrations (migration) VALUES ('028_add_ssl_monitoring.sql')
ON DUPLICATE KEY UPDATE migration=migration;

View File

@@ -35,6 +35,11 @@ If upgrading from v1.0.0, these incremental migrations will be applied:
- `021_add_avatar_field.sql` - User avatar field
- `022_add_pushover_channel_type.sql` - Pushover notification channel support
- `023_update_app_version_to_1.1.1.sql` - Update version to 1.1.1
- `024_add_status_notifications_v1.1.2.sql` - Status notification triggers
- `025_add_update_system_v1.1.3.sql` - In-app update system
- `026_update_app_version_v1.1.4.sql` - Update version to 1.1.4
- `027_add_dns_monitoring.sql` - DNS monitoring tables and settings
- `028_add_ssl_monitoring.sql` - SSL certificate monitoring table, per-domain toggles, timestamps, and cron settings
**Upgrade via:** Web updater at `/install/update`