|
@@ -2,12 +2,12 @@ package watcher
|
|
|
|
|
|
import (
|
|
|
"crypto/tls"
|
|
|
- "errors"
|
|
|
"fmt"
|
|
|
"github.com/SongZihuan/https-watcher/src/config"
|
|
|
"github.com/SongZihuan/https-watcher/src/logger"
|
|
|
"github.com/SongZihuan/https-watcher/src/notify"
|
|
|
"net/http"
|
|
|
+ "strings"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
@@ -20,38 +20,30 @@ func Run() error {
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
-MainCycle:
|
|
|
for _, url := range config.GetConfig().Watcher.URLs {
|
|
|
logger.Infof("开始请求 %s", url.Name)
|
|
|
|
|
|
- tlsState, err := getCertificate(url.URL)
|
|
|
+ tlsState, err := getCertificateRetry(url.URL, url.Name)
|
|
|
if err != nil {
|
|
|
- if errors.Is(err, errNotTLS) {
|
|
|
- logger.Errorf("请求 %s 出现异常:未返回TLS证书", url.Name)
|
|
|
- continue MainCycle
|
|
|
- }
|
|
|
-
|
|
|
logger.Errorf("请求 %s 出现异常:%s", url.Name, err.Error())
|
|
|
- continue MainCycle
|
|
|
- }
|
|
|
-
|
|
|
- if len(tlsState.PeerCertificates) == 0 {
|
|
|
+ notify.NewErrorRecord(url.Name, url.URL, err.Error())
|
|
|
+ } else if len(tlsState.PeerCertificates) == 0 {
|
|
|
logger.Errorf("请求 %s 出现异常:证书链为空", url.Name)
|
|
|
- continue MainCycle
|
|
|
- }
|
|
|
-
|
|
|
- logger.Infof("开始处理 %s", url.Name)
|
|
|
-
|
|
|
- if now.After(tlsState.PeerCertificates[0].NotAfter) {
|
|
|
- // 证书已过期
|
|
|
- logger.Infof("%s 已过期", url.Name)
|
|
|
- notify.NewRecord(url.Name, url.URL, 0)
|
|
|
- } else if deadline := tlsState.PeerCertificates[0].NotAfter.Sub(now); deadline <= url.DeadlineDuration {
|
|
|
- // 证书即将过期
|
|
|
- logger.Infof("%s 即将过期", url.Name)
|
|
|
- notify.NewRecord(url.Name, url.URL, deadline)
|
|
|
+ notify.NewErrorRecord(url.Name, url.URL, "证书链为空")
|
|
|
} else {
|
|
|
- logger.Infof("%s 正常", url.Name)
|
|
|
+ logger.Infof("开始处理 %s 证书", url.Name)
|
|
|
+
|
|
|
+ if now.After(tlsState.PeerCertificates[0].NotAfter) {
|
|
|
+ // 证书已过期
|
|
|
+ logger.Infof("%s 已过期", url.Name)
|
|
|
+ notify.NewOutOfDateRecord(url.Name, url.URL, 0)
|
|
|
+ } else if deadline := tlsState.PeerCertificates[0].NotAfter.Sub(now); deadline <= url.DeadlineDuration {
|
|
|
+ // 证书即将过期
|
|
|
+ logger.Infof("%s 即将过期", url.Name)
|
|
|
+ notify.NewOutOfDateRecord(url.Name, url.URL, deadline)
|
|
|
+ } else {
|
|
|
+ logger.Infof("%s 正常", url.Name)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
logger.Infof("处理 %s 完成", url.Name)
|
|
@@ -62,10 +54,46 @@ MainCycle:
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
+func getCertificateRetry(url string, name string) (*tls.ConnectionState, error) {
|
|
|
+ var err1, err2, err3 error
|
|
|
+ var tlsStats *tls.ConnectionState
|
|
|
+
|
|
|
+ tlsStats, err1 = getCertificate(url)
|
|
|
+ if err1 == nil {
|
|
|
+ return tlsStats, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ tlsStats, err2 = getCertificate(url)
|
|
|
+ if err2 == nil {
|
|
|
+ return tlsStats, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ tlsStats, err3 = getCertificate(url)
|
|
|
+ if err3 == nil {
|
|
|
+ return tlsStats, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // 去除重复
|
|
|
+ var errMap = make(map[string]bool, 3)
|
|
|
+ errMap[err1.Error()] = true
|
|
|
+ errMap[err2.Error()] = true
|
|
|
+ errMap[err3.Error()] = true
|
|
|
+
|
|
|
+ var errStrBuilder strings.Builder
|
|
|
+ var n = 0
|
|
|
+ for err, _ := range errMap {
|
|
|
+ n += 1
|
|
|
+ errStrBuilder.WriteString(fmt.Sprintf("检查 %s 错误[%d]: %s; ", name, n, err))
|
|
|
+ }
|
|
|
+
|
|
|
+ err := fmt.Errorf("%s", strings.TrimSpace(errStrBuilder.String()))
|
|
|
+ return nil, err
|
|
|
+}
|
|
|
+
|
|
|
func getCertificate(url string) (*tls.ConnectionState, error) {
|
|
|
// 创建一个自定义的Transport,这样我们可以访问TLS连接状态
|
|
|
tr := &http.Transport{
|
|
|
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // 忽略服务器证书验证
|
|
|
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // 忽略服务器证书验证(因为我的目的只是检查获取到的证书是否到期)
|
|
|
}
|
|
|
|
|
|
// 使用自定义的Transport创建一个HTTP客户端
|