mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 10:25:52 +02:00
feat: add certificate expiration notifications #387
This commit is contained in:
parent
7a0972495f
commit
1512e1de85
21 changed files with 1616 additions and 1235 deletions
67
internal/cert/check_expired.go
Normal file
67
internal/cert/check_expired.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
package cert
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/internal/notification"
|
||||
"github.com/0xJacky/Nginx-UI/query"
|
||||
"github.com/uozi-tech/cosy/logger"
|
||||
)
|
||||
|
||||
func CertExpiredNotify() {
|
||||
c := query.Cert
|
||||
|
||||
certs, err := c.Find()
|
||||
if err != nil {
|
||||
logger.Errorf("CertExpiredNotify: Err: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, certModel := range certs {
|
||||
if certModel.SSLCertificatePath == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
certInfo, err := GetCertInfo(certModel.SSLCertificatePath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
|
||||
// Calculate days until expiration
|
||||
daysUntilExpiration := int(certInfo.NotAfter.Sub(now).Hours() / 24)
|
||||
|
||||
// ignore expired certificate
|
||||
if daysUntilExpiration < -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
mask := map[string]any{
|
||||
"name": certModel.Name,
|
||||
"days": daysUntilExpiration,
|
||||
}
|
||||
|
||||
// Check if certificate is already expired
|
||||
if now.After(certInfo.NotAfter) {
|
||||
notification.Error("Certificate Expired", "Certificate %{name} has expired", mask)
|
||||
continue
|
||||
}
|
||||
|
||||
// Send notifications based on remaining days
|
||||
switch {
|
||||
case daysUntilExpiration <= 14:
|
||||
notification.Info("Certificate Expiration Notice",
|
||||
"Certificate %{name} will expire in %{days} days", mask)
|
||||
case daysUntilExpiration <= 7:
|
||||
notification.Warning("Certificate Expiring Soon",
|
||||
"Certificate %{name} will expire in %{days} days", mask)
|
||||
case daysUntilExpiration <= 3:
|
||||
notification.Warning("Certificate Expiring Soon",
|
||||
"Certificate %{name} will expire in %{days} days", mask)
|
||||
case daysUntilExpiration <= 1:
|
||||
notification.Error("Certificate Expiring Soon",
|
||||
"Certificate %{name} will expire in 1 day", mask)
|
||||
}
|
||||
}
|
||||
}
|
35
internal/cron/auto_cert.go
Normal file
35
internal/cron/auto_cert.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
package cron
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/internal/cert"
|
||||
"github.com/go-co-op/gocron/v2"
|
||||
"github.com/uozi-tech/cosy/logger"
|
||||
)
|
||||
|
||||
// setupAutoCertJob initializes the automatic certificate renewal job
|
||||
func setupAutoCertJob(scheduler gocron.Scheduler) (gocron.Job, error) {
|
||||
job, err := scheduler.NewJob(gocron.DurationJob(30*time.Minute),
|
||||
gocron.NewTask(cert.AutoCert),
|
||||
gocron.WithSingletonMode(gocron.LimitModeWait),
|
||||
gocron.JobOption(gocron.WithStartImmediately()))
|
||||
if err != nil {
|
||||
logger.Errorf("AutoCert Job: Err: %v\n", err)
|
||||
return nil, err
|
||||
}
|
||||
return job, nil
|
||||
}
|
||||
|
||||
// setupCertExpiredJob initializes the certificate expiration check job
|
||||
func setupCertExpiredJob(scheduler gocron.Scheduler) (gocron.Job, error) {
|
||||
job, err := scheduler.NewJob(gocron.DurationJob(6*time.Hour),
|
||||
gocron.NewTask(cert.CertExpiredNotify),
|
||||
gocron.WithSingletonMode(gocron.LimitModeWait),
|
||||
gocron.JobOption(gocron.WithStartImmediately()))
|
||||
if err != nil {
|
||||
logger.Errorf("CertExpired Job: Err: %v\n", err)
|
||||
return nil, err
|
||||
}
|
||||
return job, nil
|
||||
}
|
29
internal/cron/clear_token.go
Normal file
29
internal/cron/clear_token.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package cron
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/query"
|
||||
"github.com/go-co-op/gocron/v2"
|
||||
"github.com/uozi-tech/cosy/logger"
|
||||
)
|
||||
|
||||
// setupAuthTokenCleanupJob initializes the job to clean expired auth tokens
|
||||
func setupAuthTokenCleanupJob(scheduler gocron.Scheduler) (gocron.Job, error) {
|
||||
job, err := scheduler.NewJob(
|
||||
gocron.DurationJob(5*time.Minute),
|
||||
gocron.NewTask(func() {
|
||||
logger.Debug("clean expired auth tokens")
|
||||
q := query.AuthToken
|
||||
_, _ = q.Where(q.ExpiredAt.Lt(time.Now().Unix())).Delete()
|
||||
}),
|
||||
gocron.WithSingletonMode(gocron.LimitModeWait),
|
||||
gocron.JobOption(gocron.WithStartImmediately()))
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("CleanExpiredAuthToken Err: %v\n", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return job, nil
|
||||
}
|
|
@ -1,16 +1,11 @@
|
|||
package cron
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/internal/cert"
|
||||
"github.com/0xJacky/Nginx-UI/internal/logrotate"
|
||||
"github.com/0xJacky/Nginx-UI/query"
|
||||
"github.com/0xJacky/Nginx-UI/settings"
|
||||
"github.com/go-co-op/gocron/v2"
|
||||
"github.com/uozi-tech/cosy/logger"
|
||||
)
|
||||
|
||||
// Global scheduler instance
|
||||
var s gocron.Scheduler
|
||||
|
||||
func init() {
|
||||
|
@ -21,58 +16,34 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
var logrotateJob gocron.Job
|
||||
|
||||
// InitCronJobs initializes and starts all cron jobs
|
||||
func InitCronJobs() {
|
||||
_, err := s.NewJob(gocron.DurationJob(30*time.Minute),
|
||||
gocron.NewTask(cert.AutoCert),
|
||||
gocron.WithSingletonMode(gocron.LimitModeWait),
|
||||
gocron.JobOption(gocron.WithStartImmediately()))
|
||||
// Initialize auto cert job
|
||||
_, err := setupAutoCertJob(s)
|
||||
if err != nil {
|
||||
logger.Fatalf("AutoCert Err: %v\n", err)
|
||||
}
|
||||
|
||||
startLogrotate()
|
||||
cleanExpiredAuthToken()
|
||||
|
||||
s.Start()
|
||||
}
|
||||
|
||||
func RestartLogrotate() {
|
||||
logger.Debug("Restart Logrotate")
|
||||
if logrotateJob != nil {
|
||||
err := s.RemoveJob(logrotateJob.ID())
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
startLogrotate()
|
||||
}
|
||||
|
||||
func startLogrotate() {
|
||||
if !settings.LogrotateSettings.Enabled {
|
||||
return
|
||||
}
|
||||
var err error
|
||||
logrotateJob, err = s.NewJob(
|
||||
gocron.DurationJob(time.Duration(settings.LogrotateSettings.Interval)*time.Minute),
|
||||
gocron.NewTask(logrotate.Exec),
|
||||
gocron.WithSingletonMode(gocron.LimitModeWait))
|
||||
// Initialize certificate expiration check job
|
||||
_, err = setupCertExpiredJob(s)
|
||||
if err != nil {
|
||||
logger.Fatalf("LogRotate Job: Err: %v\n", err)
|
||||
logger.Fatalf("CertExpired Err: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func cleanExpiredAuthToken() {
|
||||
_, err := s.NewJob(gocron.DurationJob(5*time.Minute), gocron.NewTask(func() {
|
||||
logger.Debug("clean expired auth tokens")
|
||||
q := query.AuthToken
|
||||
_, _ = q.Where(q.ExpiredAt.Lt(time.Now().Unix())).Delete()
|
||||
}), gocron.WithSingletonMode(gocron.LimitModeWait), gocron.JobOption(gocron.WithStartImmediately()))
|
||||
// Start logrotate job
|
||||
setupLogrotateJob(s)
|
||||
|
||||
// Initialize auth token cleanup job
|
||||
_, err = setupAuthTokenCleanupJob(s)
|
||||
if err != nil {
|
||||
logger.Fatalf("CleanExpiredAuthToken Err: %v\n", err)
|
||||
}
|
||||
|
||||
// Start the scheduler
|
||||
s.Start()
|
||||
}
|
||||
|
||||
// RestartLogrotate is a public API to restart the logrotate job
|
||||
func RestartLogrotate() {
|
||||
restartLogrotateJob(s)
|
||||
}
|
||||
|
|
42
internal/cron/logrotate.go
Normal file
42
internal/cron/logrotate.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
package cron
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/internal/logrotate"
|
||||
"github.com/0xJacky/Nginx-UI/settings"
|
||||
"github.com/go-co-op/gocron/v2"
|
||||
"github.com/uozi-tech/cosy/logger"
|
||||
)
|
||||
|
||||
// logrotate job instance
|
||||
var logrotateJobInstance gocron.Job
|
||||
|
||||
// setupLogrotateJob initializes and starts the logrotate job
|
||||
func setupLogrotateJob(scheduler gocron.Scheduler) {
|
||||
if !settings.LogrotateSettings.Enabled {
|
||||
return
|
||||
}
|
||||
var err error
|
||||
logrotateJobInstance, err = scheduler.NewJob(
|
||||
gocron.DurationJob(time.Duration(settings.LogrotateSettings.Interval)*time.Minute),
|
||||
gocron.NewTask(logrotate.Exec),
|
||||
gocron.WithSingletonMode(gocron.LimitModeWait))
|
||||
if err != nil {
|
||||
logger.Fatalf("LogRotate Job: Err: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// restartLogrotateJob stops and restarts the logrotate job
|
||||
func restartLogrotateJob(scheduler gocron.Scheduler) {
|
||||
logger.Debug("Restart Logrotate")
|
||||
if logrotateJobInstance != nil {
|
||||
err := scheduler.RemoveJob(logrotateJobInstance.ID())
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
setupLogrotateJob(scheduler)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue