mirror of
				https://github.com/TeaOSLab/EdgeAPI.git
				synced 2025-11-04 16:00:24 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			205 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package tasks
 | 
						||
 | 
						||
import (
 | 
						||
	"github.com/TeaOSLab/EdgeAPI/internal/db/models"
 | 
						||
	"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
 | 
						||
	"github.com/iwind/TeaGo/dbs"
 | 
						||
	"github.com/iwind/TeaGo/logs"
 | 
						||
	"github.com/iwind/TeaGo/maps"
 | 
						||
	timeutil "github.com/iwind/TeaGo/utils/time"
 | 
						||
	"strconv"
 | 
						||
	"time"
 | 
						||
)
 | 
						||
 | 
						||
func init() {
 | 
						||
	dbs.OnReady(func() {
 | 
						||
		go NewSSLCertExpireCheckExecutor().Start()
 | 
						||
	})
 | 
						||
}
 | 
						||
 | 
						||
// 证书检查任务
 | 
						||
type SSLCertExpireCheckExecutor struct {
 | 
						||
}
 | 
						||
 | 
						||
func NewSSLCertExpireCheckExecutor() *SSLCertExpireCheckExecutor {
 | 
						||
	return &SSLCertExpireCheckExecutor{}
 | 
						||
}
 | 
						||
 | 
						||
// 启动任务
 | 
						||
func (this *SSLCertExpireCheckExecutor) Start() {
 | 
						||
	seconds := int64(3600)
 | 
						||
	ticker := time.NewTicker(time.Duration(seconds) * time.Second)
 | 
						||
	for range ticker.C {
 | 
						||
		err := this.loop(seconds)
 | 
						||
		if err != nil {
 | 
						||
			logs.Println("[ERROR][SSLCertExpireCheckExecutor]" + err.Error())
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
// 单次执行
 | 
						||
func (this *SSLCertExpireCheckExecutor) loop(seconds int64) error {
 | 
						||
	// 检查上次运行时间,防止重复运行
 | 
						||
	settingKey := "sslCertExpiringCheck"
 | 
						||
	timestamp := time.Now().Unix()
 | 
						||
	c, err := models.SharedSysSettingDAO.CompareInt64Setting(settingKey, timestamp-seconds)
 | 
						||
	if err != nil {
 | 
						||
		return err
 | 
						||
	}
 | 
						||
	if c > 0 {
 | 
						||
		return nil
 | 
						||
	}
 | 
						||
 | 
						||
	// 记录时间
 | 
						||
	err = models.SharedSysSettingDAO.UpdateSetting(settingKey, []byte(numberutils.FormatInt64(timestamp)))
 | 
						||
	if err != nil {
 | 
						||
		return err
 | 
						||
	}
 | 
						||
 | 
						||
	// 查找需要自动更新的证书
 | 
						||
	// 30, 14 ... 是到期的天数
 | 
						||
	for _, days := range []int{30, 14, 7} {
 | 
						||
		certs, err := models.SharedSSLCertDAO.FindAllExpiringCerts(days)
 | 
						||
		if err != nil {
 | 
						||
			return err
 | 
						||
		}
 | 
						||
		for _, cert := range certs {
 | 
						||
			// 发送消息
 | 
						||
			msg := "SSL证书\"" + cert.Name + "\"(" + cert.DnsNames + ")在" + strconv.Itoa(days) + "天后将到期,"
 | 
						||
 | 
						||
			// 是否有自动更新任务
 | 
						||
			if cert.AcmeTaskId > 0 {
 | 
						||
				task, err := models.SharedACMETaskDAO.FindEnabledACMETask(int64(cert.AcmeTaskId))
 | 
						||
				if err != nil {
 | 
						||
					return err
 | 
						||
				}
 | 
						||
				if task != nil {
 | 
						||
					if task.AutoRenew == 1 {
 | 
						||
						msg += "此证书是免费申请的证书,且已设置了自动续期,将会在到期前三天自动尝试续期。"
 | 
						||
					} else {
 | 
						||
						msg += "此证书是免费申请的证书,没有设置自动续期,请在到期前手动执行续期任务。"
 | 
						||
					}
 | 
						||
				}
 | 
						||
			} else {
 | 
						||
				msg += "请及时更新证书。"
 | 
						||
			}
 | 
						||
 | 
						||
			err = models.SharedMessageDAO.CreateMessage(int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertExpiring, models.MessageLevelWarning, msg, maps.Map{
 | 
						||
				"certId":     cert.Id,
 | 
						||
				"acmeTaskId": cert.AcmeTaskId,
 | 
						||
			}.AsJSON())
 | 
						||
			if err != nil {
 | 
						||
				return err
 | 
						||
			}
 | 
						||
 | 
						||
			// 设置最后通知时间
 | 
						||
			err = models.SharedSSLCertDAO.UpdateCertNotifiedAt(int64(cert.Id))
 | 
						||
			if err != nil {
 | 
						||
				return err
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	// 自动续期
 | 
						||
	for _, days := range []int{3, 2, 1} {
 | 
						||
		certs, err := models.SharedSSLCertDAO.FindAllExpiringCerts(days)
 | 
						||
		if err != nil {
 | 
						||
			return err
 | 
						||
		}
 | 
						||
		for _, cert := range certs {
 | 
						||
			// 发送消息
 | 
						||
			msg := "SSL证书\"" + cert.Name + "\"(" + cert.DnsNames + ")在" + strconv.Itoa(days) + "天后将到期,"
 | 
						||
 | 
						||
			// 是否有自动更新任务
 | 
						||
			if cert.AcmeTaskId > 0 {
 | 
						||
				task, err := models.SharedACMETaskDAO.FindEnabledACMETask(int64(cert.AcmeTaskId))
 | 
						||
				if err != nil {
 | 
						||
					return err
 | 
						||
				}
 | 
						||
				if task != nil {
 | 
						||
					if task.AutoRenew == 1 {
 | 
						||
						isOk, errMsg, _ := models.SharedACMETaskDAO.RunTask(int64(cert.AcmeTaskId))
 | 
						||
						if isOk {
 | 
						||
							// 发送成功通知
 | 
						||
							msg = "系统已成功为你自动更新了证书\"" + cert.Name + "\"(" + cert.DnsNames + ")。"
 | 
						||
							err = models.SharedMessageDAO.CreateMessage(int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertACMETaskSuccess, models.MessageLevelSuccess, msg, maps.Map{
 | 
						||
								"certId":     cert.Id,
 | 
						||
								"acmeTaskId": cert.AcmeTaskId,
 | 
						||
							}.AsJSON())
 | 
						||
 | 
						||
							// 更新通知时间
 | 
						||
							err = models.SharedSSLCertDAO.UpdateCertNotifiedAt(int64(cert.Id))
 | 
						||
							if err != nil {
 | 
						||
								return err
 | 
						||
							}
 | 
						||
						} else {
 | 
						||
							// 发送失败通知
 | 
						||
							msg = "系统在尝试自动更新证书\"" + cert.Name + "\"(" + cert.DnsNames + ")时发生错误:" + errMsg + "。请检查系统设置并修复错误。"
 | 
						||
							err = models.SharedMessageDAO.CreateMessage(int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertACMETaskFailed, models.MessageLevelError, msg, maps.Map{
 | 
						||
								"certId":     cert.Id,
 | 
						||
								"acmeTaskId": cert.AcmeTaskId,
 | 
						||
							}.AsJSON())
 | 
						||
 | 
						||
							// 更新通知时间
 | 
						||
							err = models.SharedSSLCertDAO.UpdateCertNotifiedAt(int64(cert.Id))
 | 
						||
							if err != nil {
 | 
						||
								return err
 | 
						||
							}
 | 
						||
						}
 | 
						||
 | 
						||
						// 中止不发送消息
 | 
						||
						continue
 | 
						||
 | 
						||
					} else {
 | 
						||
						msg += "此证书是免费申请的证书,没有设置自动续期,请在到期前手动执行续期任务。"
 | 
						||
					}
 | 
						||
				}
 | 
						||
			} else {
 | 
						||
				msg += "请及时更新证书。"
 | 
						||
			}
 | 
						||
 | 
						||
			err = models.SharedMessageDAO.CreateMessage(int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertExpiring, models.MessageLevelWarning, msg, maps.Map{
 | 
						||
				"certId":     cert.Id,
 | 
						||
				"acmeTaskId": cert.AcmeTaskId,
 | 
						||
			}.AsJSON())
 | 
						||
			if err != nil {
 | 
						||
				return err
 | 
						||
			}
 | 
						||
 | 
						||
			// 设置最后通知时间
 | 
						||
			err = models.SharedSSLCertDAO.UpdateCertNotifiedAt(int64(cert.Id))
 | 
						||
			if err != nil {
 | 
						||
				return err
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	// 当天过期
 | 
						||
	for _, days := range []int{0} {
 | 
						||
		certs, err := models.SharedSSLCertDAO.FindAllExpiringCerts(days)
 | 
						||
		if err != nil {
 | 
						||
			return err
 | 
						||
		}
 | 
						||
		for _, cert := range certs {
 | 
						||
			// 发送消息
 | 
						||
			today := timeutil.Format("Y-m-d")
 | 
						||
			msg := "SSL证书\"" + cert.Name + "\"(" + cert.DnsNames + ")在今天(" + today + ")过期,请及时更新证书,之后将不再重复提醒。"
 | 
						||
			err = models.SharedMessageDAO.CreateMessage(int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertExpiring, models.MessageLevelWarning, msg, maps.Map{
 | 
						||
				"certId":     cert.Id,
 | 
						||
				"acmeTaskId": cert.AcmeTaskId,
 | 
						||
			}.AsJSON())
 | 
						||
			if err != nil {
 | 
						||
				return err
 | 
						||
			}
 | 
						||
 | 
						||
			// 设置最后通知时间
 | 
						||
			err = models.SharedSSLCertDAO.UpdateCertNotifiedAt(int64(cert.Id))
 | 
						||
			if err != nil {
 | 
						||
				return err
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	return nil
 | 
						||
}
 |