修改监控为证书监控支持文件导入和smtp监控
监控支持多渠道通知 将静态文件打包到二进制文件
232
backend/app/api/monitor/monitor.go
Normal file
@@ -0,0 +1,232 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/internal/monitor"
|
||||
"ALLinSSL/backend/public"
|
||||
"ALLinSSL/static"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetMonitorList(c *gin.Context) {
|
||||
var form struct {
|
||||
Search string `form:"search"`
|
||||
Page int64 `form:"p"`
|
||||
Limit int64 `form:"limit"`
|
||||
}
|
||||
err := c.Bind(&form)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
data, count, err := monitor.GetList(form.Search, form.Page, form.Limit)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
public.SuccessData(c, data, count)
|
||||
return
|
||||
}
|
||||
|
||||
func AddMonitor(c *gin.Context) {
|
||||
var form struct {
|
||||
Name string `form:"name"`
|
||||
Target string `form:"target"`
|
||||
MonitorType string `form:"monitor_type"`
|
||||
ReportTypes string `form:"report_types"`
|
||||
Cycle string `form:"cycle"`
|
||||
RepeatSendGap string `form:"repeat_send_gap"`
|
||||
Active string `form:"active"`
|
||||
AdvanceDay string `form:"advance_day"`
|
||||
}
|
||||
err := c.Bind(&form)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
form.Name = strings.TrimSpace(form.Name)
|
||||
form.Target = strings.TrimSpace(form.Target)
|
||||
|
||||
err = monitor.AddMonitor(form.Name, form.Target, form.MonitorType, form.ReportTypes, form.Cycle, form.RepeatSendGap, form.Active, form.AdvanceDay)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
public.SuccessMsg(c, "添加成功")
|
||||
return
|
||||
}
|
||||
|
||||
func UpdMonitor(c *gin.Context) {
|
||||
var form struct {
|
||||
ID string `form:"id"`
|
||||
Target string `form:"target"`
|
||||
Name string `form:"name"`
|
||||
Cycle string `form:"cycle"`
|
||||
ReportTypes string `form:"report_types"`
|
||||
RepeatSendGap string `form:"repeat_send_gap"`
|
||||
Active string `form:"active"`
|
||||
AdvanceDay string `form:"advance_day"`
|
||||
}
|
||||
err := c.Bind(&form)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
form.ID = strings.TrimSpace(form.ID)
|
||||
form.Target = strings.TrimSpace(form.Target)
|
||||
form.Name = strings.TrimSpace(form.Name)
|
||||
form.ReportTypes = strings.TrimSpace(form.ReportTypes)
|
||||
|
||||
err = monitor.UpdMonitor(form.ID, form.Name, form.Target, form.ReportTypes, form.Cycle, form.RepeatSendGap, form.Active, form.AdvanceDay)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
public.SuccessMsg(c, "修改成功")
|
||||
return
|
||||
}
|
||||
|
||||
func DelMonitor(c *gin.Context) {
|
||||
var form struct {
|
||||
ID string `form:"id"`
|
||||
}
|
||||
err := c.Bind(&form)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
err = monitor.DelMonitor(form.ID)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
public.SuccessMsg(c, "删除成功")
|
||||
return
|
||||
}
|
||||
|
||||
func SetMonitor(c *gin.Context) {
|
||||
var form struct {
|
||||
ID string `form:"id"`
|
||||
Active int `form:"active"`
|
||||
}
|
||||
err := c.Bind(&form)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
err = monitor.SetMonitor(form.ID, form.Active)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
public.SuccessMsg(c, "操作成功")
|
||||
return
|
||||
}
|
||||
|
||||
func GetMonitorInfo(c *gin.Context) {
|
||||
var form struct {
|
||||
ID string `form:"id"`
|
||||
}
|
||||
err := c.Bind(&form)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
form.ID = strings.TrimSpace(form.ID)
|
||||
data, err := monitor.GetInfo(form.ID)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
public.SuccessData(c, data, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func GetErrRecord(c *gin.Context) {
|
||||
var form struct {
|
||||
ID int64 `form:"id"`
|
||||
Page int64 `form:"p"`
|
||||
Limit int64 `form:"limit"`
|
||||
}
|
||||
err := c.Bind(&form)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
data, count, err := monitor.GetErrRecord(form.ID, form.Page, form.Limit)
|
||||
if err != nil {
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
public.SuccessData(c, data, count)
|
||||
return
|
||||
}
|
||||
|
||||
func FileAddMonitor(c *gin.Context) {
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
public.FailMsg(c, "上传文件失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
if file.Size > 10*1024*1024 { // 限制文件大小为10MB
|
||||
public.FailMsg(c, "上传文件过大,最大限制10MB")
|
||||
return
|
||||
}
|
||||
data, err := monitor.ParseMonitorFile(file)
|
||||
if err != nil {
|
||||
public.FailMsg(c, "文件解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
if len(data) == 0 {
|
||||
public.FailMsg(c, "文件中没有有效的监控数据")
|
||||
return
|
||||
}
|
||||
|
||||
err = monitor.MultiAddMonitor(data)
|
||||
if err != nil {
|
||||
public.FailMsg(c, "文件导入失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
public.SuccessMsg(c, "文件导入成功")
|
||||
return
|
||||
}
|
||||
|
||||
func GetTemplate(c *gin.Context) {
|
||||
t := c.Query("type")
|
||||
if t == "" {
|
||||
c.String(http.StatusBadRequest, "参数 type 不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
fileMap := map[string]string{
|
||||
"txt": "monitor_templates/template.txt",
|
||||
"csv": "monitor_templates/template.csv",
|
||||
"json": "monitor_templates/template.json",
|
||||
"xlsx": "monitor_templates/template.xlsx",
|
||||
}
|
||||
|
||||
filePath, ok := fileMap[strings.ToLower(t)]
|
||||
if !ok {
|
||||
c.String(http.StatusBadRequest, "不支持的类型")
|
||||
return
|
||||
}
|
||||
|
||||
data, err := static.MonitorTemplatesFS.ReadFile(filePath)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "模板文件读取失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 设置 Content-Type
|
||||
contentTypes := map[string]string{
|
||||
"txt": "text/plain",
|
||||
"csv": "text/csv",
|
||||
"json": "application/json",
|
||||
"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"xls": "application/vnd.ms-excel",
|
||||
}
|
||||
c.Header("Content-Type", contentTypes[t])
|
||||
c.Header("Content-Disposition", "attachment; filename=template."+t)
|
||||
c.Data(http.StatusOK, contentTypes[t], data)
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/internal/siteMonitor"
|
||||
"ALLinSSL/backend/public"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetMonitorList(c *gin.Context) {
|
||||
var form struct {
|
||||
Search string `form:"search"`
|
||||
Page int64 `form:"p"`
|
||||
Limit int64 `form:"limit"`
|
||||
}
|
||||
err := c.Bind(&form)
|
||||
if err != nil {
|
||||
// c.JSON(http.StatusBadRequest, public.ResERR(err.Error()))
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
data, count, err := siteMonitor.GetList(form.Search, form.Page, form.Limit)
|
||||
if err != nil {
|
||||
// c.JSON(http.StatusBadRequest, public.ResERR(err.Error()))
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
// c.JSON(http.StatusOK, public.ResOK(len(data), data, ""))
|
||||
public.SuccessData(c, data, count)
|
||||
return
|
||||
}
|
||||
|
||||
func AddMonitor(c *gin.Context) {
|
||||
var form struct {
|
||||
Name string `form:"name"`
|
||||
Domain string `form:"domain"`
|
||||
Cycle int `form:"cycle"`
|
||||
ReportType string `form:"report_type"`
|
||||
}
|
||||
err := c.Bind(&form)
|
||||
if err != nil {
|
||||
// c.JSON(http.StatusBadRequest, public.ResERR(err.Error()))
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
form.Name = strings.TrimSpace(form.Name)
|
||||
form.Domain = strings.TrimSpace(form.Domain)
|
||||
|
||||
err = siteMonitor.AddMonitor(form.Name, form.Domain, form.ReportType, form.Cycle)
|
||||
if err != nil {
|
||||
// c.JSON(http.StatusBadRequest, public.ResERR(err.Error()))
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
// c.JSON(http.StatusOK, public.ResOK(0, nil, "添加成功"))
|
||||
public.SuccessMsg(c, "添加成功")
|
||||
return
|
||||
}
|
||||
|
||||
func UpdMonitor(c *gin.Context) {
|
||||
var form struct {
|
||||
ID string `form:"id"`
|
||||
Name string `form:"name"`
|
||||
Domain string `form:"domain"`
|
||||
Cycle int `form:"cycle"`
|
||||
ReportType string `form:"report_type"`
|
||||
}
|
||||
err := c.Bind(&form)
|
||||
if err != nil {
|
||||
// c.JSON(http.StatusBadRequest, public.ResERR(err.Error()))
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
form.ID = strings.TrimSpace(form.ID)
|
||||
form.Name = strings.TrimSpace(form.Name)
|
||||
form.Domain = strings.TrimSpace(form.Domain)
|
||||
form.ReportType = strings.TrimSpace(form.ReportType)
|
||||
|
||||
err = siteMonitor.UpdMonitor(form.ID, form.Name, form.Domain, form.ReportType, form.Cycle)
|
||||
if err != nil {
|
||||
// c.JSON(http.StatusBadRequest, public.ResERR(err.Error()))
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
// c.JSON(http.StatusOK, public.ResOK(0, nil, "修改成功"))
|
||||
public.SuccessMsg(c, "修改成功")
|
||||
return
|
||||
}
|
||||
|
||||
func DelMonitor(c *gin.Context) {
|
||||
var form struct {
|
||||
ID string `form:"id"`
|
||||
}
|
||||
err := c.Bind(&form)
|
||||
if err != nil {
|
||||
// c.JSON(http.StatusBadRequest, public.ResERR(err.Error()))
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
err = siteMonitor.DelMonitor(form.ID)
|
||||
if err != nil {
|
||||
// c.JSON(http.StatusBadRequest, public.ResERR(err.Error()))
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
// c.JSON(http.StatusOK, public.ResOK(0, nil, "删除成功"))
|
||||
public.SuccessMsg(c, "删除成功")
|
||||
return
|
||||
}
|
||||
|
||||
func SetMonitor(c *gin.Context) {
|
||||
var form struct {
|
||||
ID string `form:"id"`
|
||||
Active int `form:"active"`
|
||||
}
|
||||
err := c.Bind(&form)
|
||||
if err != nil {
|
||||
// c.JSON(http.StatusBadRequest, public.ResERR(err.Error()))
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
err = siteMonitor.SetMonitor(form.ID, form.Active)
|
||||
if err != nil {
|
||||
// c.JSON(http.StatusBadRequest, public.ResERR(err.Error()))
|
||||
public.FailMsg(c, err.Error())
|
||||
return
|
||||
}
|
||||
// c.JSON(http.StatusOK, public.ResOK(0, nil, "操作成功"))
|
||||
public.SuccessMsg(c, "操作成功")
|
||||
return
|
||||
}
|
||||
212
backend/internal/monitor/check.go
Normal file
@@ -0,0 +1,212 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/smtp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// buildCertChainRecursive 构建证书链树结构
|
||||
func buildCertChainRecursive(certs []*x509.Certificate, index int) *CertNode {
|
||||
if index >= len(certs) {
|
||||
return nil
|
||||
}
|
||||
node := &CertNode{
|
||||
CommonName: certs[index].Subject.CommonName,
|
||||
Subject: certs[index].Subject.String(),
|
||||
Issuer: certs[index].Issuer.String(),
|
||||
}
|
||||
if index+1 < len(certs) {
|
||||
child := buildCertChainRecursive(certs, index+1)
|
||||
if child != nil {
|
||||
node.Children = append(node.Children, child)
|
||||
}
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// checkChainRecursive 递归检查链条完整性
|
||||
func checkChainRecursive(node *CertNode, level int) error {
|
||||
if node == nil || len(node.Children) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, child := range node.Children {
|
||||
if node.Issuer != child.Subject {
|
||||
return fmt.Errorf("证书链第 %d 层 [CN=%s] 的 Issuer 与第 %d 层 [CN=%s] 的 Subject 不匹配,链条断裂",
|
||||
level, node.CommonName,
|
||||
level+1, child.CommonName,
|
||||
)
|
||||
}
|
||||
if err := checkChainRecursive(child, level+1); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check 检查证书链的完整性和有效性
|
||||
func Check(certs []*x509.Certificate, host string, advanceDay int) (result *CertInfo, err error) {
|
||||
result = &CertInfo{}
|
||||
if len(certs) == 0 {
|
||||
return nil, fmt.Errorf("未获取到服务端证书")
|
||||
}
|
||||
|
||||
leafCert := certs[0]
|
||||
|
||||
// 提取 CA 名称(Issuer 的组织名)
|
||||
result.CA = "UNKNOWN"
|
||||
if len(leafCert.Issuer.Organization) > 0 {
|
||||
result.CA = leafCert.Issuer.Organization[0]
|
||||
} else if leafCert.Issuer.CommonName != "" {
|
||||
result.CA = leafCert.Issuer.CommonName
|
||||
}
|
||||
|
||||
result.CommonName = leafCert.Subject.CommonName
|
||||
result.NotBefore = leafCert.NotBefore.Format("2006-01-02 15:04:05")
|
||||
result.NotAfter = leafCert.NotAfter.Format("2006-01-02 15:04:05")
|
||||
result.DaysLeft = int(leafCert.NotAfter.Sub(time.Now()).Hours() / 24)
|
||||
result.SANs = strings.Join(leafCert.DNSNames, ",")
|
||||
result.SignatureAlgo = leafCert.SignatureAlgorithm.String()
|
||||
sha256Sum := sha256.Sum256(leafCert.Raw)
|
||||
result.Sha256 = hex.EncodeToString(sha256Sum[:])
|
||||
|
||||
// 构建证书链树结构
|
||||
result.CertChain = buildCertChainRecursive(certs, 0)
|
||||
|
||||
// 用系统根证书池校验是否受信任
|
||||
roots, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加载系统根证书失败:%v", err)
|
||||
}
|
||||
if roots == nil {
|
||||
roots = x509.NewCertPool()
|
||||
}
|
||||
intermediates := x509.NewCertPool()
|
||||
for _, intermediate := range certs[1:] {
|
||||
intermediates.AddCert(intermediate)
|
||||
}
|
||||
opts := x509.VerifyOptions{
|
||||
DNSName: host,
|
||||
Roots: roots,
|
||||
Intermediates: intermediates,
|
||||
}
|
||||
if _, err := leafCert.Verify(opts); err != nil {
|
||||
result.Valid = false
|
||||
result.VerifyError = fmt.Sprintf("证书验证失败:%v", err)
|
||||
return result, nil
|
||||
} else if result.DaysLeft <= advanceDay {
|
||||
result.VerifyError = fmt.Sprintf("证书即将过期,剩余 %d 天,请及时更新", result.DaysLeft)
|
||||
} else if err := checkChainRecursive(result.CertChain, 1); err != nil {
|
||||
result.VerifyError = fmt.Sprintf("证书验证成功,但在检查真实获取到的证书链时出现问题:\n%v\n(可忽略,仅作提醒,如遇到ssl证书问题,可作为排查方向)", err)
|
||||
}
|
||||
|
||||
result.Valid = true
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CheckHttps 严格检查 HTTPS 证书链,基于 CertChain 结构检查链完整性
|
||||
func CheckHttps(target string, advanceDay int) (result *CertInfo, err error) {
|
||||
// 解析 host 和 port
|
||||
host, port, err := net.SplitHostPort(target)
|
||||
if err != nil {
|
||||
host = target
|
||||
port = "443"
|
||||
}
|
||||
|
||||
// 校验 host
|
||||
if net.ParseIP(host) == nil {
|
||||
if _, err := net.LookupHost(host); err != nil {
|
||||
return nil, fmt.Errorf("无效的域名或 IP:%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 拼接 HTTPS URL
|
||||
url := fmt.Sprintf("https://%s", net.JoinHostPort(host, port))
|
||||
|
||||
// 构建 HTTP 客户端
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
},
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("无法建立 HTTPS 连接:%v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 获取证书链
|
||||
certs := resp.TLS.PeerCertificates
|
||||
return Check(certs, host, advanceDay)
|
||||
}
|
||||
|
||||
// CheckSmtp 检查smtp
|
||||
func CheckSmtp(target string, advanceDay int) (result *CertInfo, err error) {
|
||||
// 解析 host 和 port
|
||||
host, port, err := net.SplitHostPort(target)
|
||||
if err != nil {
|
||||
host = target
|
||||
port = "465" // 默认端口
|
||||
}
|
||||
|
||||
// 校验 host
|
||||
if net.ParseIP(host) == nil {
|
||||
if _, err := net.LookupHost(host); err != nil {
|
||||
return nil, fmt.Errorf("无效的域名或 IP:%v", err)
|
||||
}
|
||||
}
|
||||
// 如果端口是 465,使用 TCP
|
||||
if port == "465" {
|
||||
return CheckTCP(host, port, advanceDay)
|
||||
}
|
||||
|
||||
// 建立smtp连接
|
||||
conn, err := smtp.Dial(host + ":" + port)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("无法建立 SMTP 连接:%v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
// 升级到 TLS
|
||||
if err := conn.StartTLS(&tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: host,
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("无法升级到 TLS:%v", err)
|
||||
}
|
||||
// 获取证书
|
||||
state, ok := conn.TLSConnectionState()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("无法获取 TLS 连接状态")
|
||||
}
|
||||
certs := state.PeerCertificates
|
||||
return Check(certs, host, advanceDay)
|
||||
}
|
||||
|
||||
// CheckTCP 通过 tcp 连接检查证书
|
||||
func CheckTCP(host, port string, advanceDay int) (result *CertInfo, err error) {
|
||||
// 建立 tcp 连接
|
||||
url := fmt.Sprintf("%s:%s", host, port)
|
||||
conn, err := tls.Dial("tcp", url, &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: host,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("无法建立tcp连接:%v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
// 获取证书链
|
||||
certs := conn.ConnectionState().PeerCertificates
|
||||
return Check(certs, host, advanceDay)
|
||||
}
|
||||
124
backend/internal/monitor/file_handle.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/tealeg/xlsx"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ParseMonitorFile(fileHeader *multipart.FileHeader) ([]*Monitor, error) {
|
||||
ext := strings.ToLower(filepath.Ext(fileHeader.Filename))
|
||||
|
||||
file, err := fileHeader.Open()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("无法打开文件: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
switch ext {
|
||||
case ".csv", ".txt":
|
||||
return parseCSV(file)
|
||||
case ".json":
|
||||
return parseJSON(file)
|
||||
case ".xlsx":
|
||||
return parseXLSX(file)
|
||||
default:
|
||||
return nil, fmt.Errorf("不支持的文件类型: %s", ext)
|
||||
}
|
||||
}
|
||||
|
||||
func parseCSV(reader io.Reader) ([]*Monitor, error) {
|
||||
csvReader := csv.NewReader(reader)
|
||||
var monitors []*Monitor
|
||||
isHeader := true
|
||||
|
||||
for {
|
||||
record, err := csvReader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CSV 解析失败: %v", err)
|
||||
}
|
||||
|
||||
if isHeader {
|
||||
isHeader = false
|
||||
continue
|
||||
}
|
||||
|
||||
if len(record) < 8 {
|
||||
continue
|
||||
}
|
||||
|
||||
monitor := &Monitor{
|
||||
Name: record[0],
|
||||
Target: record[1],
|
||||
MonitorType: record[2],
|
||||
ReportTypes: record[3],
|
||||
Cycle: record[4],
|
||||
RepeatSendGap: record[5],
|
||||
Active: record[6],
|
||||
AdvanceDay: record[7],
|
||||
}
|
||||
monitors = append(monitors, monitor)
|
||||
}
|
||||
|
||||
return monitors, nil
|
||||
}
|
||||
|
||||
func parseJSON(reader io.Reader) ([]*Monitor, error) {
|
||||
var monitors []*Monitor
|
||||
err := json.NewDecoder(reader).Decode(&monitors)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("JSON 解析失败: %v", err)
|
||||
}
|
||||
return monitors, nil
|
||||
}
|
||||
|
||||
func parseXLSX(file multipart.File) ([]*Monitor, error) {
|
||||
var monitors []*Monitor
|
||||
|
||||
// 读取文件内容到内存
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 解析 XLSX 内容
|
||||
xlFile, err := xlsx.OpenBinary(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解析 xlsx 失败: %v", err)
|
||||
}
|
||||
|
||||
if len(xlFile.Sheets) == 0 {
|
||||
return nil, fmt.Errorf("未找到工作表")
|
||||
}
|
||||
|
||||
sheet := xlFile.Sheets[0]
|
||||
for i, row := range sheet.Rows {
|
||||
if i == 0 {
|
||||
continue // 跳过表头
|
||||
}
|
||||
if len(row.Cells) < 8 {
|
||||
continue
|
||||
}
|
||||
monitor := &Monitor{
|
||||
Name: row.Cells[0].String(),
|
||||
Target: row.Cells[1].String(),
|
||||
MonitorType: row.Cells[2].String(),
|
||||
ReportTypes: row.Cells[3].String(),
|
||||
Cycle: row.Cells[4].String(),
|
||||
RepeatSendGap: row.Cells[5].String(),
|
||||
Active: row.Cells[6].String(),
|
||||
AdvanceDay: row.Cells[7].String(),
|
||||
}
|
||||
monitors = append(monitors, monitor)
|
||||
}
|
||||
|
||||
return monitors, nil
|
||||
}
|
||||
35
backend/internal/monitor/model.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package monitor
|
||||
|
||||
// CertInfo 用于返回证书检查的详细信息
|
||||
type CertInfo struct {
|
||||
CommonName string `json:"common_name"` // 证书主体 CN
|
||||
CA string `json:"ca"` // 颁发机构 CN
|
||||
NotBefore string `json:"not_before"` // 生效时间
|
||||
NotAfter string `json:"not_after"` // 失效时间
|
||||
DaysLeft int `json:"days_left"` // 证书剩余天数
|
||||
SANs string `json:"sans"` // 证书 SAN 列表
|
||||
SignatureAlgo string `json:"signature_algo"` // 签名算法
|
||||
Sha256 string `json:"sha256"` // 证书 SHA256 指纹
|
||||
Valid bool `json:"valid"` // 是否校验通过
|
||||
VerifyError string `json:"verify_error"` // 校验失败原因
|
||||
CertChain *CertNode `json:"cert_chain"` // 证书链结构树
|
||||
}
|
||||
|
||||
// CertNode 代表证书链中的节点
|
||||
type CertNode struct {
|
||||
CommonName string `json:"common_name"` // 当前节点证书 CN
|
||||
Subject string `json:"subject"` // 证书 Subject 字符串
|
||||
Issuer string `json:"issuer"` // 证书 Issuer 字符串
|
||||
Children []*CertNode `json:"children"` // 下级节点
|
||||
}
|
||||
|
||||
type Monitor struct {
|
||||
Name string `json:"name"`
|
||||
Target string `json:"target"`
|
||||
MonitorType string `json:"monitor_type"` // 监控类型
|
||||
ReportTypes string `json:"report_types"` // 报告类型
|
||||
Cycle string `json:"cycle"` // 监控周期
|
||||
RepeatSendGap string `json:"repeat_send_gap"` // 重复发送间隔
|
||||
Active string `json:"active"` // 是否启用
|
||||
AdvanceDay string `json:"advance_day"` // 提前多少天提醒
|
||||
}
|
||||
263
backend/internal/monitor/monitor.go
Normal file
@@ -0,0 +1,263 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/public"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetSqlite() (*public.Sqlite, error) {
|
||||
s, err := public.NewSqlite("data/monitor.db", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.TableName = "monitor"
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func GetList(search string, p, limit int64) ([]map[string]any, int, error) {
|
||||
var data []map[string]any
|
||||
var count int64
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return data, 0, err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
var limits []int64
|
||||
if p >= 0 && limit >= 0 {
|
||||
limits = []int64{0, limit}
|
||||
if p > 1 {
|
||||
limits[0] = (p - 1) * limit
|
||||
limits[1] = limit
|
||||
}
|
||||
}
|
||||
|
||||
if search != "" {
|
||||
count, err = s.Where("name like ? or target like ?", []interface{}{"%" + search + "%", "%" + search + "%"}).Count()
|
||||
data, err = s.Where("name like ? or target like ?", []interface{}{"%" + search + "%", "%" + search + "%"}).Order("update_time", "desc").Limit(limits).Select()
|
||||
} else {
|
||||
count, err = s.Count()
|
||||
data, err = s.Order("update_time", "desc").Limit(limits).Select()
|
||||
}
|
||||
if err != nil {
|
||||
return data, 0, err
|
||||
}
|
||||
for _, v := range data {
|
||||
info, ok := v["info"].(string)
|
||||
if !ok || info == "" {
|
||||
continue
|
||||
}
|
||||
var certInfo CertInfo
|
||||
err := json.Unmarshal([]byte(info), &certInfo)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
v["common_name"] = certInfo.CommonName
|
||||
v["ca"] = certInfo.CA
|
||||
v["not_before"] = certInfo.NotBefore
|
||||
v["not_after"] = certInfo.NotAfter
|
||||
v["days_left"] = certInfo.DaysLeft
|
||||
v["sans"] = certInfo.SANs
|
||||
//v["valid"] = certInfo.Valid
|
||||
delete(v, "info")
|
||||
}
|
||||
return data, int(count), nil
|
||||
}
|
||||
|
||||
func GetInfo(id string) (map[string]any, error) {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer s.Close()
|
||||
data, err := s.Where("id=?", []interface{}{id}).Select()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(data) == 0 || data[0] == nil {
|
||||
return nil, fmt.Errorf("未找到对应的监控记录")
|
||||
}
|
||||
dataMap := data[0]
|
||||
|
||||
monitorInfo := map[string]any{
|
||||
"id": dataMap["id"],
|
||||
"name": dataMap["name"],
|
||||
"target": dataMap["target"],
|
||||
"monitor_type": dataMap["monitor_type"],
|
||||
"valid": dataMap["valid"],
|
||||
}
|
||||
|
||||
info, ok := dataMap["info"].(string)
|
||||
if !ok || info == "" {
|
||||
return monitorInfo, nil
|
||||
}
|
||||
var certInfo CertInfo
|
||||
err = json.Unmarshal([]byte(info), &certInfo)
|
||||
if err != nil {
|
||||
return monitorInfo, fmt.Errorf("解析证书信息失败: %v", err)
|
||||
}
|
||||
monitorInfo["common_name"] = certInfo.CommonName
|
||||
monitorInfo["ca"] = certInfo.CA
|
||||
monitorInfo["not_before"] = certInfo.NotBefore
|
||||
monitorInfo["not_after"] = certInfo.NotAfter
|
||||
monitorInfo["days_left"] = certInfo.DaysLeft
|
||||
monitorInfo["sans"] = certInfo.SANs
|
||||
//monitorInfo["valid"] = certInfo.Valid
|
||||
monitorInfo["verify_error"] = certInfo.VerifyError
|
||||
monitorInfo["cert_chain"] = certInfo.CertChain
|
||||
|
||||
// 查询异常次数
|
||||
// 计算7天前的时间
|
||||
sevenDaysAgo := time.Now().AddDate(0, 0, -7).Format("2006-01-02 15:04:05")
|
||||
s.TableName = "err_record"
|
||||
errCount, err := s.Where("monitor_id=? and create_time >= ?", []interface{}{id, sevenDaysAgo}).Count()
|
||||
if err != nil {
|
||||
errCount = 0
|
||||
}
|
||||
monitorInfo["err_count"] = errCount
|
||||
|
||||
return monitorInfo, nil
|
||||
}
|
||||
|
||||
// AddMonitor 添加新的监控记录
|
||||
func AddMonitor(name, target, monitorType, reportTypes, cycle, repeatSendGap, active, advanceDay string) error {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
data := map[string]any{
|
||||
"name": name,
|
||||
"target": target,
|
||||
"monitor_type": monitorType,
|
||||
"report_types": reportTypes,
|
||||
"cycle": cycle,
|
||||
"repeat_send_gap": repeatSendGap,
|
||||
"active": active,
|
||||
"advance_day": advanceDay,
|
||||
"create_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||
"update_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
if _, err := s.Insert(data); err != nil {
|
||||
return fmt.Errorf("添加监控记录失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdMonitor 更新监控记录
|
||||
func UpdMonitor(id, name, target, reportTypes, cycle, repeatSendGap, active, advanceDay string) error {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
data := map[string]any{
|
||||
"name": name,
|
||||
"target": target,
|
||||
"report_types": reportTypes,
|
||||
"cycle": cycle,
|
||||
"repeat_send_gap": repeatSendGap,
|
||||
"active": active,
|
||||
"advance_day": advanceDay,
|
||||
"update_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||
"info": "", // 清空 info 字段
|
||||
}
|
||||
_, err = s.Where("id=?", []interface{}{id}).Update(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("更新监控记录失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DelMonitor(id string) error {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
_, err = s.Where("id=?", []interface{}{id}).Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.TableName = "err_record"
|
||||
_, err = s.Where("monitor_id=?", []interface{}{id}).Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetMonitor(id string, active int) error {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
_, err = s.Where("id=?", []interface{}{id}).Update(map[string]any{
|
||||
"active": active,
|
||||
"update_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetErrRecord(id, p, limit int64) ([]map[string]any, int, error) {
|
||||
var data []map[string]any
|
||||
var count int64
|
||||
s, err := public.NewSqlite("data/monitor.db", "")
|
||||
if err != nil {
|
||||
return data, 0, err
|
||||
}
|
||||
defer s.Close()
|
||||
s.TableName = "err_record"
|
||||
|
||||
var limits []int64
|
||||
if p >= 0 && limit >= 0 {
|
||||
limits = []int64{0, limit}
|
||||
if p > 1 {
|
||||
limits[0] = (p - 1) * limit
|
||||
limits[1] = limit
|
||||
}
|
||||
}
|
||||
|
||||
count, err = s.Where("monitor_id=?", []any{id}).Count()
|
||||
if err != nil {
|
||||
return data, 0, err
|
||||
}
|
||||
data, err = s.Where("monitor_id=?", []any{id}).Order("create_time", "desc").Limit(limits).Select()
|
||||
if err != nil {
|
||||
return data, 0, err
|
||||
}
|
||||
return data, int(count), nil
|
||||
}
|
||||
|
||||
func MultiAddMonitor(monitors []*Monitor) error {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
for _, monitor := range monitors {
|
||||
data := map[string]any{
|
||||
"name": monitor.Name,
|
||||
"target": monitor.Target,
|
||||
"monitor_type": monitor.MonitorType,
|
||||
"report_types": monitor.ReportTypes,
|
||||
"cycle": monitor.Cycle,
|
||||
"repeat_send_gap": monitor.RepeatSendGap,
|
||||
"active": monitor.Active,
|
||||
"advance_day": monitor.AdvanceDay,
|
||||
"create_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||
"update_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
if _, err := s.Insert(data); err != nil {
|
||||
return fmt.Errorf("添加监控记录失败: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -65,15 +65,15 @@ func GetCertCount() (map[string]int, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func GetSiteMonitorCount() (map[string]any, error) {
|
||||
s, err := public.NewSqlite("data/site_monitor.db", "")
|
||||
func GetMonitorCount() (map[string]any, error) {
|
||||
s, err := public.NewSqlite("data/monitor.db", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer s.Close()
|
||||
cert, err := s.Query(`select count(*) as count,
|
||||
count(case when state='异常' then 1 end ) as exception
|
||||
from site_monitor`)
|
||||
count(case when valid=-1 then 1 end ) as exception
|
||||
from monitor`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -144,18 +144,18 @@ func GetOverviewData() (map[string]any, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
siteMonitorCount, err := GetSiteMonitorCount()
|
||||
workflowHistory, err := GetWorkflowHistory()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workflowHistory, err := GetWorkflowHistory()
|
||||
monitorCount, err := GetMonitorCount()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make(map[string]any)
|
||||
result["workflow"] = workflowCount
|
||||
result["cert"] = certCount
|
||||
result["site_monitor"] = siteMonitorCount
|
||||
result["monitor"] = monitorCount
|
||||
result["workflow_history"] = workflowHistory
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -1,255 +0,0 @@
|
||||
package siteMonitor
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/public"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SSLInfo 定义结果结构体
|
||||
type SSLInfo struct {
|
||||
Target string
|
||||
HTTPStatus int
|
||||
HTTPStatusText string
|
||||
Domains []string
|
||||
Issuer string
|
||||
NotBefore string
|
||||
NotAfter string
|
||||
DaysRemaining int
|
||||
CertificateOK bool
|
||||
CertificateNote string
|
||||
}
|
||||
|
||||
func GetSqlite() (*public.Sqlite, error) {
|
||||
s, err := public.NewSqlite("data/site_monitor.db", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.TableName = "site_monitor"
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func GetList(search string, p, limit int64) ([]map[string]any, int, error) {
|
||||
var data []map[string]any
|
||||
var count int64
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return data, 0, err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
var limits []int64
|
||||
if p >= 0 && limit >= 0 {
|
||||
limits = []int64{0, limit}
|
||||
if p > 1 {
|
||||
limits[0] = (p - 1) * limit
|
||||
limits[1] = limit
|
||||
}
|
||||
}
|
||||
|
||||
if search != "" {
|
||||
count, err = s.Where("name like ? or site_domain like ?", []interface{}{"%" + search + "%", "%" + search + "%"}).Count()
|
||||
data, err = s.Where("name like ? or site_domain like ?", []interface{}{"%" + search + "%", "%" + search + "%"}).Order("update_time", "desc").Limit(limits).Select()
|
||||
} else {
|
||||
count, err = s.Count()
|
||||
data, err = s.Order("update_time", "desc").Limit(limits).Select()
|
||||
}
|
||||
if err != nil {
|
||||
return data, 0, err
|
||||
}
|
||||
for _, v := range data {
|
||||
v["domain"] = v["site_domain"]
|
||||
}
|
||||
|
||||
return data, int(count), nil
|
||||
}
|
||||
|
||||
func AddMonitor(name, domain, reportType string, cycle int) error {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
info, err := CheckWebsite(domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.Insert(map[string]any{
|
||||
"name": name,
|
||||
"site_domain": domain,
|
||||
"report_type": reportType,
|
||||
"cycle": cycle,
|
||||
"state": info.HTTPStatusText,
|
||||
"ca": info.Issuer,
|
||||
"cert_domain": strings.Join(info.Domains, ","),
|
||||
"end_time": info.NotAfter,
|
||||
"end_day": info.DaysRemaining,
|
||||
"create_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||
"update_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||
"last_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||
"active": 1,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdMonitor(id, name, domain, reportType string, cycle int) error {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
info, err := CheckWebsite(domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.Where("id=?", []interface{}{id}).Update(map[string]any{
|
||||
"name": name,
|
||||
"site_domain": domain,
|
||||
"report_type": reportType,
|
||||
"cycle": cycle,
|
||||
"state": info.HTTPStatusText,
|
||||
"ca": info.Issuer,
|
||||
"cert_domain": strings.Join(info.Domains, ","),
|
||||
"end_time": info.NotAfter,
|
||||
"end_day": info.DaysRemaining,
|
||||
"update_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||
"last_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||
"active": 1,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DelMonitor(id string) error {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
_, err = s.Where("id=?", []interface{}{id}).Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetMonitor(id string, active int) error {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
_, err = s.Where("id=?", []interface{}{id}).Update(map[string]any{
|
||||
"active": active,
|
||||
"update_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdInfo(id, domain string, s *public.Sqlite, reportType string) error {
|
||||
info, errCheck := CheckWebsite(domain)
|
||||
now := time.Now()
|
||||
updateData := map[string]any{
|
||||
"state": info.HTTPStatusText,
|
||||
"ca": info.Issuer,
|
||||
"cert_domain": strings.Join(info.Domains, ","),
|
||||
"end_time": info.NotAfter,
|
||||
"end_day": info.DaysRemaining,
|
||||
"last_time": now.Format("2006-01-02 15:04:05"),
|
||||
"except_end_time": now.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
if errCheck != nil {
|
||||
updateData["state"] = "异常"
|
||||
// return err
|
||||
} else {
|
||||
if info.HTTPStatus != 0 && info.CertificateOK != false {
|
||||
delete(updateData, "except_end_time")
|
||||
} else {
|
||||
errCheck = fmt.Errorf("证书异常")
|
||||
}
|
||||
}
|
||||
_, err := s.Where("id=?", []interface{}{id}).Update(updateData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return errCheck
|
||||
}
|
||||
|
||||
// CheckWebsite 实际检测函数
|
||||
func CheckWebsite(target string) (*SSLInfo, error) {
|
||||
result := &SSLInfo{Target: target}
|
||||
|
||||
// 拆分 host 和 port
|
||||
host, port, err := net.SplitHostPort(target)
|
||||
if err != nil {
|
||||
// 没有显式端口,默认 443
|
||||
host = target
|
||||
port = "443"
|
||||
}
|
||||
|
||||
// 验证格式是否是 IP 或域名
|
||||
if net.ParseIP(host) == nil {
|
||||
if _, err := net.LookupHost(host); err != nil {
|
||||
return result, fmt.Errorf("无效域名或 IP:%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TLS 连接(支持所有 TLS 版本)
|
||||
conn, err := tls.Dial("tcp", net.JoinHostPort(host, port), &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
MinVersion: tls.VersionTLS10, // 显式支持所有版本
|
||||
MaxVersion: tls.VersionTLS13,
|
||||
})
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("目标不支持 HTTPS:%v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// HTTP 状态检测(构造 URL,保留端口)
|
||||
url := fmt.Sprintf("https://%s", net.JoinHostPort(host, port))
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
result.HTTPStatus = 0
|
||||
result.HTTPStatusText = "异常"
|
||||
} else {
|
||||
result.HTTPStatus = resp.StatusCode
|
||||
result.HTTPStatusText = "正常"
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
// 获取证书
|
||||
cert := conn.ConnectionState().PeerCertificates[0]
|
||||
result.Domains = cert.DNSNames
|
||||
result.Issuer = cert.Issuer.CommonName
|
||||
result.NotBefore = cert.NotBefore.Format("2006-01-02 15:04:05")
|
||||
result.NotAfter = cert.NotAfter.Format("2006-01-02 15:04:05")
|
||||
result.DaysRemaining = int(cert.NotAfter.Sub(time.Now()).Hours() / 24)
|
||||
|
||||
now := time.Now()
|
||||
switch {
|
||||
case now.Before(cert.NotBefore):
|
||||
result.CertificateOK = false
|
||||
result.CertificateNote = "尚未生效"
|
||||
case now.After(cert.NotAfter):
|
||||
result.CertificateOK = false
|
||||
result.CertificateNote = "已过期"
|
||||
default:
|
||||
result.CertificateOK = true
|
||||
result.CertificateNote = "有效"
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package siteMonitor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
site := "bt.cn" // 只传域名或 IP,不要 http://
|
||||
result, err := CheckWebsite(site)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 检测失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(result.HTTPStatusText)
|
||||
fmt.Println(result.Domains)
|
||||
fmt.Println(result.Issuer)
|
||||
fmt.Println(result.NotAfter)
|
||||
// fmt.Println(result.Domains)
|
||||
// fmt.Println(result.Domains)
|
||||
}
|
||||
@@ -33,6 +33,10 @@ func SessionAuthMiddleware() gin.HandlerFunc {
|
||||
session := sessions.Default(c)
|
||||
now := time.Now()
|
||||
gob.Register(time.Time{})
|
||||
if public.Secure == "/" || public.Secure == "/login" {
|
||||
// 如果安全入口是根目录或登录页,则不需要特殊处理
|
||||
public.Secure = ""
|
||||
}
|
||||
if public.Secure == "" && session.Get("secure") == nil {
|
||||
session.Set("secure", true)
|
||||
session.Set("lastRequestTime", now)
|
||||
|
||||
@@ -192,47 +192,6 @@ func init() {
|
||||
fmt.Println("错误:", err)
|
||||
}
|
||||
|
||||
db1, err := sql.Open("sqlite", "data/site_monitor.db")
|
||||
if err != nil {
|
||||
// fmt.Println("创建数据库失败:", err)
|
||||
return
|
||||
}
|
||||
defer db1.Close()
|
||||
// 创建表
|
||||
_, err = db1.Exec(`
|
||||
PRAGMA journal_mode=WAL;
|
||||
|
||||
create table IF NOT EXISTS site_monitor
|
||||
(
|
||||
id integer not null
|
||||
constraint site_monitor_pk
|
||||
primary key autoincrement,
|
||||
name TEXT not null,
|
||||
site_domain TEXT not null,
|
||||
cycle integer not null,
|
||||
report_type TEXT not null,
|
||||
cert_domain TEXT,
|
||||
ca TEXT,
|
||||
active integer,
|
||||
end_time TEXT,
|
||||
end_day TEXT,
|
||||
last_time TEXT,
|
||||
except_end_time TEXT,
|
||||
create_time TEXT,
|
||||
state TEXT,
|
||||
update_time TEXT,
|
||||
repeat_send_gap INTEGER
|
||||
);
|
||||
`)
|
||||
|
||||
err = sqlite_migrate.EnsureDatabaseWithTables(
|
||||
"data/settings.db",
|
||||
"data/data.db",
|
||||
[]string{"settings", "users"}, // 你要迁移的表
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println("错误:", err)
|
||||
}
|
||||
dbSetting, err := sql.Open("sqlite", "data/settings.db")
|
||||
if err != nil {
|
||||
//fmt.Println("创建 settings 数据库失败:", err)
|
||||
@@ -331,6 +290,82 @@ INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES
|
||||
on a.email = b.mail and a.type like b.ca||'%';
|
||||
`
|
||||
insertDefaultData(dbAcc, "accounts", insertSql)
|
||||
|
||||
sourceDBPath := "data/site_monitor.db"
|
||||
if _, err := os.Stat(sourceDBPath); err != nil {
|
||||
sourceDBPath = "data/data.db"
|
||||
}
|
||||
|
||||
columnMapping := map[string]string{
|
||||
"name": "name",
|
||||
"site_domain": "target",
|
||||
"report_type": "report_types",
|
||||
"active": "active",
|
||||
"last_time": "last_time",
|
||||
"except_end_time": "except_end_time",
|
||||
"update_time": "update_time",
|
||||
"create_time": "create_time",
|
||||
"cycle": "cycle",
|
||||
"repeat_send_gap": "repeat_send_gap",
|
||||
}
|
||||
|
||||
createTableSQL := `
|
||||
create table monitor
|
||||
(
|
||||
id integer not null
|
||||
constraint monitor_pk
|
||||
primary key autoincrement,
|
||||
name TEXT not null,
|
||||
target TEXT not null,
|
||||
monitor_type TEXT default 'https' not null,
|
||||
report_types TEXT not null,
|
||||
active integer default 1,
|
||||
info TEXT,
|
||||
last_time TEXT,
|
||||
except_end_time TEXT,
|
||||
update_time TEXT,
|
||||
create_time TEXT,
|
||||
cycle integer,
|
||||
repeat_send_gap integer default 10,
|
||||
advance_day integer default 30,
|
||||
valid INTEGER default 0 not null
|
||||
);`
|
||||
|
||||
err = sqlite_migrate.MigrateSQLiteTable(
|
||||
sourceDBPath,
|
||||
"site_monitor",
|
||||
"data/monitor.db",
|
||||
"monitor",
|
||||
columnMapping,
|
||||
createTableSQL,
|
||||
1000,
|
||||
)
|
||||
if err != nil {
|
||||
//fmt.Println("迁移失败:", err)
|
||||
return
|
||||
}
|
||||
|
||||
dbMonitor, err := sql.Open("sqlite", "data/monitor.db")
|
||||
if err != nil {
|
||||
// fmt.Println("创建 monitor 数据库失败:", err)
|
||||
return
|
||||
}
|
||||
defer dbMonitor.Close()
|
||||
// 创建表
|
||||
_, err = dbMonitor.Exec(`
|
||||
PRAGMA journal_mode=WAL;
|
||||
create table if not exists err_record
|
||||
(
|
||||
id TEXT not null
|
||||
constraint err_record_pk
|
||||
primary key,
|
||||
monitor_id INTEGER not null,
|
||||
create_time TEXT not null,
|
||||
info TEXT not null,
|
||||
msg TEXT not null
|
||||
);
|
||||
`)
|
||||
|
||||
}
|
||||
|
||||
func insertDefaultData(db *sql.DB, table, insertSQL string) {
|
||||
|
||||
@@ -58,11 +58,6 @@ func NewSqlite(DbFile string, PreFix string) (*Sqlite, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = s.Conn.Exec("PRAGMA busy_timeout = 5000;")
|
||||
if err != nil {
|
||||
s.Close()
|
||||
return nil, fmt.Errorf("设置PRAGMA busy_timeout失败: %w", err)
|
||||
}
|
||||
|
||||
return &s, nil
|
||||
}
|
||||
@@ -80,7 +75,8 @@ func FileExists(file string) bool {
|
||||
* @return error 错误信息
|
||||
*/
|
||||
func (s *Sqlite) Connect() error {
|
||||
conn, err := sql.Open("sqlite", s.DbFile)
|
||||
dsn := fmt.Sprintf("file:%s?_pragma=busy_timeout(60000)", s.DbFile)
|
||||
conn, err := sql.Open("sqlite", dsn)
|
||||
if err == nil {
|
||||
s.Conn = conn
|
||||
s.closed = false
|
||||
|
||||
@@ -21,3 +21,58 @@ func Test(t *testing.T) {
|
||||
fmt.Println("错误:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test1(t *testing.T) {
|
||||
err := os.Chdir("D:/code/ALLinSSL")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "切换目录失败: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
columnMapping := map[string]string{
|
||||
"name": "name",
|
||||
"site_domain": "target",
|
||||
"report_type": "report_types",
|
||||
"active": "active",
|
||||
"last_time": "last_time",
|
||||
"except_end_time": "except_end_time",
|
||||
"update_time": "update_time",
|
||||
"create_time": "create_time",
|
||||
"cycle": "cycle",
|
||||
"repeat_send_gap": "repeat_send_gap",
|
||||
}
|
||||
|
||||
createTableSQL := `
|
||||
create table monitor
|
||||
(
|
||||
id integer not null
|
||||
constraint monitor_pk
|
||||
primary key autoincrement,
|
||||
name TEXT not null,
|
||||
target TEXT not null,
|
||||
monitor_type TEXT default 'https' not null,
|
||||
report_types TEXT not null,
|
||||
active integer default 1,
|
||||
info TEXT,
|
||||
last_time TEXT,
|
||||
except_end_time TEXT,
|
||||
update_time TEXT,
|
||||
create_time TEXT,
|
||||
cycle integer,
|
||||
repeat_send_gap integer default 10,
|
||||
advance_day integer default 30,
|
||||
valid INTEGER default 0 not null
|
||||
);`
|
||||
|
||||
err = MigrateSQLiteTable(
|
||||
"data/site_monitor.db",
|
||||
"site_monitor",
|
||||
"data/monitor.db",
|
||||
"monitor",
|
||||
columnMapping,
|
||||
createTableSQL,
|
||||
1000,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println("迁移失败:", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,150 @@ func joinStrings(strs []string, sep string) string {
|
||||
return result
|
||||
}
|
||||
|
||||
// MigrateSQLiteTable 迁移方法
|
||||
func MigrateSQLiteTable(sourceDBPath, sourceTable, targetDBPath, targetTable string, columnMapping map[string]string, createTableSQL string, batchSize int) error {
|
||||
// 打开目标数据库
|
||||
targetDB, err := sql.Open("sqlite", targetDBPath)
|
||||
if err != nil {
|
||||
//return fmt.Errorf("打开目标数据库失败: %v", err)
|
||||
}
|
||||
defer targetDB.Close()
|
||||
|
||||
// 检查目标表
|
||||
exists, err := tableExists(targetDB, targetTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
//fmt.Printf("目标表 %s 已存在,跳过迁移。\n", targetTable)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 创建目标表
|
||||
//fmt.Printf("目标表 %s 不存在,正在创建...\n", targetTable)
|
||||
if _, err := targetDB.Exec(createTableSQL); err != nil {
|
||||
//return fmt.Errorf("创建目标表失败: %v", err)
|
||||
}
|
||||
fmt.Printf("目标表 %s 创建成功。\n", targetTable)
|
||||
|
||||
// 打开源数据库
|
||||
sourceDB, err := sql.Open("sqlite", sourceDBPath)
|
||||
if err != nil {
|
||||
//return fmt.Errorf("打开源数据库失败: %v", err)
|
||||
}
|
||||
defer sourceDB.Close()
|
||||
|
||||
// 检查源表
|
||||
exists, err = tableExists(sourceDB, sourceTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
//return fmt.Errorf("源表 %s 不存在,迁移终止", sourceTable)
|
||||
}
|
||||
|
||||
// 构建列映射
|
||||
sourceCols, targetCols, placeholders := buildColumnMappings(columnMapping)
|
||||
|
||||
selectSQL := fmt.Sprintf("SELECT %s FROM %s", sourceCols, sourceTable)
|
||||
insertSQL := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", targetTable, targetCols, placeholders)
|
||||
|
||||
rows, err := sourceDB.Query(selectSQL)
|
||||
if err != nil {
|
||||
//return fmt.Errorf("查询源数据失败: %v", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
stmt, err := targetDB.Prepare(insertSQL)
|
||||
if err != nil {
|
||||
//return fmt.Errorf("准备插入语句失败: %v", err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
colCount := len(columnMapping)
|
||||
batch := make([][]interface{}, 0, batchSize)
|
||||
total := 0
|
||||
|
||||
for rows.Next() {
|
||||
values := make([]interface{}, colCount)
|
||||
ptrs := make([]interface{}, colCount)
|
||||
for i := range ptrs {
|
||||
ptrs[i] = &values[i]
|
||||
}
|
||||
|
||||
if err := rows.Scan(ptrs...); err != nil {
|
||||
//return fmt.Errorf("读取行数据失败: %v", err)
|
||||
}
|
||||
|
||||
batch = append(batch, values)
|
||||
total++
|
||||
|
||||
if len(batch) >= batchSize {
|
||||
if err := insertBatch(targetDB, stmt, batch); err != nil {
|
||||
return err
|
||||
}
|
||||
batch = batch[:0]
|
||||
}
|
||||
}
|
||||
|
||||
if len(batch) > 0 {
|
||||
if err := insertBatch(targetDB, stmt, batch); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
//fmt.Printf("数据迁移完成,共迁移 %d 条记录。\n", total)
|
||||
return nil
|
||||
}
|
||||
|
||||
// tableExists 检查表是否存在
|
||||
func tableExists(db *sql.DB, tableName string) (bool, error) {
|
||||
query := `SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name=?`
|
||||
var count int
|
||||
if err := db.QueryRow(query, tableName).Scan(&count); err != nil {
|
||||
return false, fmt.Errorf("检查表是否存在失败: %v", err)
|
||||
}
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
// buildColumnMappings 构建列映射 SQL 片段
|
||||
func buildColumnMappings(mapping map[string]string) (string, string, string) {
|
||||
srcCols := ""
|
||||
tgtCols := ""
|
||||
placeholders := ""
|
||||
i := 0
|
||||
for src, tgt := range mapping {
|
||||
if i > 0 {
|
||||
srcCols += ", "
|
||||
tgtCols += ", "
|
||||
placeholders += ", "
|
||||
}
|
||||
srcCols += src
|
||||
tgtCols += tgt
|
||||
placeholders += "?"
|
||||
i++
|
||||
}
|
||||
return srcCols, tgtCols, placeholders
|
||||
}
|
||||
|
||||
// insertBatch 批量插入数据
|
||||
func insertBatch(db *sql.DB, stmt *sql.Stmt, batch [][]interface{}) error {
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
return fmt.Errorf("开启事务失败: %v", err)
|
||||
}
|
||||
for _, vals := range batch {
|
||||
if _, err := tx.Stmt(stmt).Exec(vals...); err != nil {
|
||||
tx.Rollback()
|
||||
return fmt.Errorf("插入数据失败: %v", err)
|
||||
}
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf("提交事务失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 示例用法
|
||||
func main() {
|
||||
err := EnsureDatabaseWithTables(
|
||||
|
||||
@@ -2,7 +2,10 @@ package route
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/app/api"
|
||||
"ALLinSSL/backend/app/api/monitor"
|
||||
"ALLinSSL/static"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -15,14 +18,20 @@ func Register(r *gin.Engine) {
|
||||
login.POST("/sign-out", api.SignOut)
|
||||
login.GET("/get_code", api.GetCode)
|
||||
}
|
||||
siteMonitor := v1.Group("/siteMonitor")
|
||||
|
||||
_monitor := v1.Group("/monitor")
|
||||
{
|
||||
siteMonitor.POST("/get_list", api.GetMonitorList)
|
||||
siteMonitor.POST("/add_site_monitor", api.AddMonitor)
|
||||
siteMonitor.POST("/upd_site_monitor", api.UpdMonitor)
|
||||
siteMonitor.POST("/del_site_monitor", api.DelMonitor)
|
||||
siteMonitor.POST("/set_site_monitor", api.SetMonitor)
|
||||
_monitor.POST("/get_list", monitor.GetMonitorList)
|
||||
_monitor.POST("/add_monitor", monitor.AddMonitor)
|
||||
_monitor.POST("/upd_monitor", monitor.UpdMonitor)
|
||||
_monitor.POST("/del_monitor", monitor.DelMonitor)
|
||||
_monitor.POST("/set_monitor", monitor.SetMonitor)
|
||||
_monitor.POST("/get_monitor_info", monitor.GetMonitorInfo)
|
||||
_monitor.POST("/get_err_record", monitor.GetErrRecord)
|
||||
_monitor.POST("/file_add_monitor", monitor.FileAddMonitor)
|
||||
_monitor.GET("/template", monitor.GetTemplate)
|
||||
}
|
||||
|
||||
workflow := v1.Group("/workflow")
|
||||
{
|
||||
workflow.POST("/get_list", api.GetWorkflowList)
|
||||
@@ -93,20 +102,28 @@ func Register(r *gin.Engine) {
|
||||
overview.POST("/get_overviews", api.GetOverview)
|
||||
}
|
||||
|
||||
// 1. 提供静态文件服务
|
||||
r.StaticFS("/static", http.Dir("./frontend/static")) // 静态资源路径
|
||||
r.StaticFS("/auto-deploy/static", http.Dir("./frontend/static")) // 静态资源路径
|
||||
// 返回 favicon.ico
|
||||
// 静态资源:/static -> build/static
|
||||
staticFS, _ := fs.Sub(static.BuildFS, "build/static")
|
||||
r.StaticFS("/static", http.FS(staticFS))
|
||||
r.StaticFS("/auto-deploy/static", http.FS(staticFS))
|
||||
|
||||
// favicon.ico
|
||||
r.GET("/favicon.ico", func(c *gin.Context) {
|
||||
c.File("./frontend/favicon.ico")
|
||||
data, err := static.BuildFS.ReadFile("build/favicon.ico")
|
||||
if err != nil {
|
||||
c.Status(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
c.Data(http.StatusOK, "image/x-icon", data)
|
||||
})
|
||||
|
||||
// 3. 前端路由托管:匹配所有其他路由并返回 index.html
|
||||
// 其他路由:返回 index.html
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.File("./frontend/index.html")
|
||||
})
|
||||
// v2 := r.Group("/v2")
|
||||
// {
|
||||
// v2.POST("/submit")
|
||||
// }
|
||||
data, err := static.BuildFS.ReadFile("build/index.html")
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "页面加载失败")
|
||||
return
|
||||
}
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", data)
|
||||
})
|
||||
}
|
||||
|
||||
185
backend/scheduler/monitor.go
Normal file
@@ -0,0 +1,185 @@
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/internal/monitor"
|
||||
"ALLinSSL/backend/internal/report"
|
||||
"ALLinSSL/backend/public"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
MonitorErrCount = make(map[int64]int)
|
||||
monitorErrCountMu sync.Mutex
|
||||
)
|
||||
|
||||
// 通知模板,先写死,后续做成配置
|
||||
var MonitorErrTemplate = "监控名称:%v\n类型:%v\n域名:%v\n错误信息:%v\n请及时处理!\n检测时间:%v"
|
||||
|
||||
func Monitor() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Printf("Monitor 主流程捕获 panic: %v\n", r)
|
||||
}
|
||||
}()
|
||||
|
||||
s, err := monitor.GetSqlite()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
defer s.Close()
|
||||
s1, err := report.GetSqlite()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer s1.Close()
|
||||
s1.TableName = "report"
|
||||
|
||||
data, err := s.Select()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
now := time.Now()
|
||||
loc := now.Location()
|
||||
var wg sync.WaitGroup
|
||||
for _, v := range data {
|
||||
if v["active"].(int64) == 1 {
|
||||
lastTimeStr, ok := v["last_time"].(string)
|
||||
if !ok || lastTimeStr == "" {
|
||||
lastTimeStr = "1970-01-01 00:00:00"
|
||||
}
|
||||
lastTime, err := time.ParseInLocation("2006-01-02 15:04:05", lastTimeStr, loc)
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
monitorType, ok := v["monitor_type"].(string)
|
||||
if !ok {
|
||||
fmt.Println("监控类型错误")
|
||||
return
|
||||
}
|
||||
target, ok := v["target"].(string)
|
||||
if !ok {
|
||||
fmt.Println("监控目标错误")
|
||||
return
|
||||
}
|
||||
advanceDay, ok := v["advance_day"].(int64)
|
||||
if !ok {
|
||||
advanceDay = 30 // 默认提前30天
|
||||
}
|
||||
if now.Sub(lastTime).Minutes() >= float64(v["cycle"].(int64)) {
|
||||
wg.Add(1)
|
||||
go func(v map[string]any) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Printf("监控任务发生错误: %v\n", r)
|
||||
}
|
||||
}()
|
||||
defer wg.Done()
|
||||
gs := *s
|
||||
var (
|
||||
certInfo *monitor.CertInfo
|
||||
certJson string
|
||||
Err error
|
||||
checkErr string
|
||||
)
|
||||
switch monitorType {
|
||||
case "https":
|
||||
certInfo, Err = monitor.CheckHttps(target, int(advanceDay))
|
||||
case "smtp":
|
||||
certInfo, Err = monitor.CheckSmtp(target, int(advanceDay))
|
||||
default:
|
||||
Err = fmt.Errorf("不支持的监控类型:%s", monitorType)
|
||||
}
|
||||
|
||||
if Err != nil {
|
||||
checkErr = strings.Split(Err.Error(), ":")[0] // 只取错误信息的第一部分
|
||||
} else {
|
||||
if certInfo.VerifyError != "" && (!certInfo.Valid || certInfo.DaysLeft <= int(advanceDay)) {
|
||||
checkErr = certInfo.VerifyError
|
||||
}
|
||||
certBytes, err := json.Marshal(certInfo)
|
||||
if err == nil {
|
||||
certJson = string(certBytes)
|
||||
}
|
||||
}
|
||||
id := v["id"].(int64)
|
||||
|
||||
// 此处应该发送错误邮件
|
||||
if checkErr != "" {
|
||||
// 更新监控记录
|
||||
gs.Where("id=?", []interface{}{id}).Update(map[string]any{
|
||||
"last_time": now.Format("2006-01-02 15:04:05"),
|
||||
"except_end_time": now.Format("2006-01-02 15:04:05"),
|
||||
"info": certJson,
|
||||
"valid": -1, // 状态为异常
|
||||
})
|
||||
// 新增错误记录
|
||||
if certInfo == nil || !certInfo.Valid {
|
||||
gs.TableName = "err_record"
|
||||
gs.Insert(map[string]any{
|
||||
"id": public.GenerateUUID(),
|
||||
"monitor_id": id,
|
||||
"create_time": now.Format("2006-01-02 15:04:05"),
|
||||
"msg": checkErr,
|
||||
"info": certJson,
|
||||
})
|
||||
}
|
||||
monitorErrCountMu.Lock()
|
||||
MonitorErrCount[id] += 1
|
||||
errCount := MonitorErrCount[id]
|
||||
monitorErrCountMu.Unlock()
|
||||
|
||||
repeatSendGap, ok := v["repeat_send_gap"].(int64)
|
||||
if !ok {
|
||||
repeatSendGap = 10
|
||||
}
|
||||
reportTypes, ok := v["report_types"].(string)
|
||||
if ok && errCount == 1 {
|
||||
reportTypeArr := strings.Split(reportTypes, ",")
|
||||
for _, reportType := range reportTypeArr {
|
||||
if reportType == "" {
|
||||
continue
|
||||
}
|
||||
rdata, err := s1.Where("type=?", []interface{}{reportType}).Select()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(rdata) <= 0 {
|
||||
return
|
||||
}
|
||||
report.Notify(map[string]any{
|
||||
"provider": reportType,
|
||||
"provider_id": strconv.FormatInt(rdata[0]["id"].(int64), 10),
|
||||
"subject": "ALLinSSL 监控通知",
|
||||
"body": fmt.Sprintf(MonitorErrTemplate, v["name"], monitorType, v["target"], checkErr, now.Format("2006-01-02 15:04:05")),
|
||||
})
|
||||
}
|
||||
}
|
||||
monitorErrCountMu.Lock()
|
||||
if MonitorErrCount[id] >= int(repeatSendGap) {
|
||||
MonitorErrCount[id] = 0
|
||||
}
|
||||
monitorErrCountMu.Unlock()
|
||||
} else {
|
||||
// 更新监控记录
|
||||
gs.Where("id=?", []interface{}{id}).Update(map[string]any{
|
||||
"last_time": now.Format("2006-01-02 15:04:05"),
|
||||
"info": certJson,
|
||||
"valid": 1, // 状态为正常
|
||||
})
|
||||
monitorErrCountMu.Lock()
|
||||
MonitorErrCount[id] = 0
|
||||
monitorErrCountMu.Unlock()
|
||||
}
|
||||
}(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
// 你的任务列表
|
||||
var funcs = []func(){
|
||||
SiteMonitor,
|
||||
Monitor,
|
||||
RunWorkflows,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/internal/report"
|
||||
"ALLinSSL/backend/internal/siteMonitor"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func SiteMonitor() {
|
||||
s, err := siteMonitor.GetSqlite()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
defer s.Close()
|
||||
s1, err := report.GetSqlite()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer s1.Close()
|
||||
data, err := s.Select()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
now := time.Now()
|
||||
loc := now.Location()
|
||||
var wg sync.WaitGroup
|
||||
for _, v := range data {
|
||||
if v["active"].(int64) == 1 {
|
||||
lastTimeStr := v["last_time"].(string)
|
||||
lastTime, err := time.ParseInLocation("2006-01-02 15:04:05", lastTimeStr, loc)
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
if now.Sub(lastTime).Minutes() >= float64(v["cycle"].(int64)) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
Err := siteMonitor.UpdInfo(fmt.Sprintf("%d", v["id"].(int64)), v["site_domain"].(string), s, v["report_type"].(string))
|
||||
|
||||
path := fmt.Sprintf("data/site_monitor/%d", v["id"].(int64))
|
||||
dir := filepath.Dir(path)
|
||||
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||
return
|
||||
}
|
||||
errCount := 0
|
||||
file, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
errCount = 0
|
||||
}
|
||||
errCount, err = strconv.Atoi(string(file))
|
||||
if err != nil {
|
||||
errCount = 0
|
||||
}
|
||||
|
||||
// 此处应该发送错误邮件
|
||||
if Err != nil {
|
||||
errCount += 1
|
||||
os.WriteFile(path, []byte(strconv.Itoa(errCount)), os.ModePerm)
|
||||
repeatSendGap, ok := v["repeat_send_gap"].(int64)
|
||||
if !ok {
|
||||
repeatSendGap = 10
|
||||
}
|
||||
reportType, ok := v["report_type"].(string)
|
||||
if ok && errCount >= int(repeatSendGap) {
|
||||
s1.TableName = "report"
|
||||
rdata, err := s1.Where("type=?", []interface{}{reportType}).Select()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(rdata) <= 0 {
|
||||
return
|
||||
}
|
||||
_ = report.Notify(map[string]any{
|
||||
"provider": reportType,
|
||||
"provider_id": strconv.FormatInt(rdata[0]["id"].(int64), 10),
|
||||
"body": fmt.Sprintf("检测到域名为%s的网站出现异常,请保持关注!\n检测时间:%s", v["site_domain"].(string), now.Format("2006-01-02 15:04:05")),
|
||||
"subject": "ALLinSSL网站监控通知",
|
||||
})
|
||||
os.Remove(path)
|
||||
}
|
||||
} else {
|
||||
os.Remove(path)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
10
cmd/main.go
@@ -120,17 +120,9 @@ start - 启动 ALLinSSL
|
||||
fmt.Print("请输入安全入口: ")
|
||||
fmt.Scanln(&secure)
|
||||
}
|
||||
if len(secure) < 5 {
|
||||
fmt.Println("安全入口至少需要5位")
|
||||
return
|
||||
}
|
||||
if secure[0] != '/' {
|
||||
if secure != "" && secure[0] != '/' {
|
||||
secure = "/" + secure
|
||||
}
|
||||
if secure == "/login" {
|
||||
fmt.Println("安全入口不能是/login")
|
||||
return
|
||||
}
|
||||
err := public.UpdateSetting("secure", secure)
|
||||
if err != nil {
|
||||
fmt.Println("Error updating setting:", err)
|
||||
|
||||
3
go.mod
@@ -28,7 +28,9 @@ require (
|
||||
github.com/mitchellh/go-ps v1.0.0
|
||||
github.com/mojocn/base64Captcha v1.3.8
|
||||
github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0
|
||||
github.com/pkg/sftp v1.13.9
|
||||
github.com/qiniu/go-sdk/v7 v7.25.3
|
||||
github.com/tealeg/xlsx v1.0.5
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1128
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124
|
||||
github.com/volcengine/volcengine-go-sdk v1.1.11
|
||||
@@ -94,6 +96,7 @@ require (
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
|
||||
9
go.sum
@@ -503,6 +503,8 @@ github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQe
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
@@ -610,6 +612,8 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
|
||||
github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -689,6 +693,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=
|
||||
github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1124/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1128 h1:NGnqDc8FQL0YdiCHgTO4Wkso6ToD8rE3JW9VOzoPBNA=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1128/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
@@ -778,6 +784,7 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -981,6 +988,7 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
@@ -996,6 +1004,7 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
9
static/assets.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package static
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed monitor_templates/*
|
||||
var MonitorTemplatesFS embed.FS
|
||||
|
||||
//go:embed build/*
|
||||
var BuildFS embed.FS
|
||||
BIN
static/build/favicon.ico
Normal file
|
After Width: | Height: | Size: 66 KiB |
14
static/build/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="./favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>AllinSSL</title>
|
||||
<script type="module" crossorigin src="./static/js/main-DzwaUoFb.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./static/css/style-DbV1_Tij.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
1
static/build/static/css/style-B3U-cEKB.css
Normal file
1
static/build/static/css/style-B6lQcYLm.css
Normal file
1
static/build/static/css/style-Bl7CD6Rg.css
Normal file
1
static/build/static/css/style-DbV1_Tij.css
Normal file
1
static/build/static/css/style-DiZIyFa4.css
Normal file
3
static/build/static/icons/btssl.svg
Normal file
|
After Width: | Height: | Size: 47 KiB |
1
static/build/static/icons/letsencrypt-icon.svg
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
static/build/static/icons/positive-ico.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
static/build/static/icons/sectigo-ico.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
static/build/static/icons/ssltrus-ico.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
1
static/build/static/images/login-bg-dark.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="1440.855" height="900.46" viewBox="0 0 1440.85 900.46" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient x1="0" y1="724" x2="442.31" y2="898.26" id="a" gradientUnits="userSpaceOnUse"><stop stop-color="#121212"/><stop offset=".969" stop-color="#333" stop-opacity=".969"/><stop offset="1" stop-color="#E3E4E8" stop-opacity="0"/></linearGradient><linearGradient x1="995.427" y1="642.73" x2="466.927" y2="898.31" id="b" gradientUnits="userSpaceOnUse"><stop stop-color="#121212"/><stop offset="1" stop-color="#333"/></linearGradient><linearGradient x1="0" y1="653.04" x2="1120.19" y2="653.04" id="c" gradientUnits="userSpaceOnUse"><stop stop-color="#121212"/><stop offset="1" stop-color="#333"/></linearGradient><linearGradient x1=".7" y1="58.87" x2="382.18" y2="58.87" id="d" gradientUnits="userSpaceOnUse"><stop stop-color="#121212"/><stop offset="1" stop-color="#333"/></linearGradient><linearGradient x1="1440.355" y1="665.73" x2="1152.355" y2="900.23" id="e" gradientUnits="userSpaceOnUse"><stop stop-color="#333"/><stop offset="1" stop-color="#121212"/></linearGradient><linearGradient x1="1206.355" y1="1.73" x2="1460.355" y2="314.73" id="f" gradientUnits="userSpaceOnUse"><stop stop-color="#121212"/><stop offset=".995" stop-color="#333" stop-opacity=".792"/></linearGradient></defs><path fill="#121212" d="M.7.46h1440v900H.7z"/><path d="M3.09 755.27 0 724.46l442.31 174.26h-79.56L3.09 755.27z" fill="url(#a)"/><path d="M532.78 898.72h83.62l526.16-259.19-22.38-27.13-587.4 286.32z" fill="url(#b)"/><path d="m3.09 585.09 470.03-177.73 647.06 205.04-587.4 286.32h-90.47L0 724.46l3.09-139.37z" fill="url(#c)"/><path d="m.7 79.92 88.22 37.37L382.18.45H.7v79.47z" fill="url(#d)"/><path d="M1440.35 665.73v234.5h-288l288-234.5z" fill="url(#e)" fill-opacity=".9" fill-rule="evenodd"/><path d="M1206.35 1.72h234.5v288.01L1206.35 1.72z" fill="url(#f)" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
1
static/build/static/images/login-bg.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="1440.855" height="900.46" viewBox="0 0 1440.85 900.46" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient x1="0" y1="653.04" x2="1120.19" y2="653.04" id="a" gradientUnits="userSpaceOnUse"><stop stop-color="#F0F0F2"/><stop offset="1" stop-color="#F3F4F6"/></linearGradient><linearGradient x1=".7" y1="58.87" x2="382.18" y2="58.87" id="b" gradientUnits="userSpaceOnUse"><stop stop-color="#EBEBED"/><stop offset="1" stop-color="#F3F4F6"/></linearGradient><linearGradient x1="1506.855" y1="665.73" x2="1152.355" y2="900.23" id="c" gradientUnits="userSpaceOnUse"><stop stop-color="#EBECEE"/><stop offset="1" stop-color="#F2F3F5"/></linearGradient><linearGradient x1="1206.355" y1="1.73" x2="1460.355" y2="314.73" id="d" gradientUnits="userSpaceOnUse"><stop offset=".282" stop-color="#F1F2F3"/><stop offset="1" stop-color="#EBECEE" stop-opacity=".792"/></linearGradient></defs><path fill="#F3F4F6" d="M.7.46h1440v900H.7z"/><path d="M3.09 755.27 0 724.46l442.31 174.26h-79.56L3.09 755.27z" fill="#E3E4E8"/><path d="M532.78 898.72h83.62l526.16-259.19-22.38-27.13-587.4 286.32z" fill="#FBFBFC"/><path d="m3.09 585.09 470.03-177.73 647.06 205.04-587.4 286.32h-90.47L0 724.46l3.09-139.37z" fill="url(#a)"/><path d="m.7 79.92 88.22 37.37L382.18.45H.7v79.47z" fill="url(#b)"/><path d="M1440.35 665.73v234.5h-288l288-234.5z" fill="url(#c)" fill-opacity=".9" fill-rule="evenodd"/><path d="M1206.35 1.72h234.5v288.01L1206.35 1.72z" fill="url(#d)" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
1
static/build/static/images/login-display.svg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
static/build/static/images/logo.png
Normal file
|
After Width: | Height: | Size: 364 KiB |
1
static/build/static/js/Badge-8NYqLBAN.js
Normal file
1
static/build/static/js/Badge-BfzridVU.js
Normal file
1
static/build/static/js/Badge-Bvze6Zdy.js
Normal file
1
static/build/static/js/Badge-C33p422y.js
Normal file
1
static/build/static/js/Badge-C7LWMkVb.js
Normal file
1
static/build/static/js/Badge-CfRwiWTi.js
Normal file
1
static/build/static/js/Badge-VdIKCoSK.js
Normal file
1
static/build/static/js/Badge-bjWN4Nwi.js
Normal file
1
static/build/static/js/Badge-f3Jhuj3w.js
Normal file
1
static/build/static/js/CAManageForm-2r0-4wM2.js
Normal file
@@ -0,0 +1 @@
|
||||
import{u as s}from"./index-DJVuZNft.js";import{d as t,c as o}from"./main-l9ONqWM3.js";import"./useStore-B_YQVTNZ.js";import"./index-CROykHUI.js";import"./access-DAUICydO.js";import"./index-DoEhNl1p.js";import"./throttle-CqQDPWAC.js";import"./index-Boi7lFs7.js";import"./data-DuVKJAVf.js";import"./index-DBGpolyE.js";import"./business-BHURL4si.js";import"./index-DDUoCc5m.js";const r=t({name:"CAManageForm",setup(){const{CAForm:t}=s();return()=>o(t,{labelPlacement:"top"},null)}});export{r as default};
|
||||
1
static/build/static/js/CAManageForm-B2Li0mu9.js
Normal file
@@ -0,0 +1 @@
|
||||
import{u as s}from"./index-CZGsWLu5.js";import{d as t,c as o}from"./main-DPHcWoLq.js";import"./useStore-Rp34S9LW.js";import"./index-B19cVdYt.js";import"./access-CRBQqgF7.js";import"./index-DtIETYgH.js";import"./throttle-JmbW0v_s.js";import"./index-G81Br7zM.js";import"./data-DlilpN2t.js";import"./index-CKj4hF6A.js";import"./business-DHKRFoyP.js";import"./index-CHVS5zLT.js";const r=t({name:"CAManageForm",setup(){const{CAForm:t}=s();return()=>o(t,{labelPlacement:"top"},null)}});export{r as default};
|
||||
1
static/build/static/js/CAManageForm-BW-hYz3i.js
Normal file
@@ -0,0 +1 @@
|
||||
import{u as s}from"./index-Bkq98n1o.js";import{d as t,c as o}from"./main-D37kYvfP.js";import"./useStore-BfxXiqmz.js";import"./index-DuE5FJUK.js";import"./access-D5PuzSlL.js";import"./index-CkZPJuYU.js";import"./throttle-DUJLBKRu.js";import"./index-atRq13wP.js";import"./data-C6c8domP.js";import"./index-CfX9d1jr.js";import"./business-3db_PQBB.js";import"./index-D8XFZQMn.js";const r=t({name:"CAManageForm",setup(){const{CAForm:t}=s();return()=>o(t,{labelPlacement:"top"},null)}});export{r as default};
|
||||
1
static/build/static/js/CAManageForm-Bdzad6ta.js
Normal file
@@ -0,0 +1 @@
|
||||
import{u as s}from"./index-DRzBjIiL.js";import{d as t,c as o}from"./main-BLIIbSTQ.js";import"./useStore-fVNzUh3F.js";import"./index-BpNpm-gE.js";import"./access-D0TDoR2F.js";import"./index-Cst_8GwD.js";import"./throttle-BeYFKTpy.js";import"./index-P8bDWxur.js";import"./data-bWxE0nrC.js";import"./index-nSsq-Cp3.js";import"./business-iC8kVSsk.js";import"./index-T_6gqO98.js";const r=t({name:"CAManageForm",setup(){const{CAForm:t}=s();return()=>o(t,{labelPlacement:"top"},null)}});export{r as default};
|
||||
1
static/build/static/js/CAManageForm-C5gl_ovf.js
Normal file
@@ -0,0 +1 @@
|
||||
import{u as t}from"./index-DO8we_Ld.js";import{d as s,c as e}from"./main-DzwaUoFb.js";import"./useStore-Bzsn7zfX.js";import"./index-BNb4DSrN.js";import"./access-D1d2FuYi.js";import"./index-CgB92oEK.js";import"./index-B9Dyybyi.js";import"./throttle-cf_E8cS3.js";import"./data-BqkycWmp.js";import"./index-Dhf2Wig3.js";import"./business-Ckv_hx4t.js";import"./index-sgsDdEi4.js";const o=s({name:"CAManageForm",props:{isEdit:{type:Boolean,default:!1},editId:{type:String,default:""}},setup(s){const{CAForm:o}=t(s);return()=>e(o,{labelPlacement:"top"},null)}});export{o as default};
|
||||
1
static/build/static/js/CAManageForm-CzIztuwl.js
Normal file
@@ -0,0 +1 @@
|
||||
import{u as s}from"./index-poTMapw9.js";import{d as t,c as o}from"./main-TC3Bu45J.js";import"./useStore-B7wwrEXS.js";import"./index-jviZh_iP.js";import"./access-CVoV-9UZ.js";import"./index-D0djR_cB.js";import"./throttle-CQkMUevy.js";import"./index-DXyQC-X-.js";import"./data-CXwlriQE.js";import"./index-OvFH652L.js";import"./business-CSi1hkxo.js";import"./index-Cdsjg_sg.js";const e=t({name:"CAManageForm",setup(){const{CAForm:t}=s();return()=>o(t,{labelPlacement:"top"},null)}});export{e as default};
|
||||
1
static/build/static/js/CAManageForm-DfZMazsP.js
Normal file
@@ -0,0 +1 @@
|
||||
import{u as s}from"./index-BfcToXUg.js";import{d as t,c as o}from"./main-BjWWkfgM.js";import"./useStore-D1h1SxQb.js";import"./index-CyQKn_q4.js";import"./access-C8j2cGON.js";import"./index-D_NskAyf.js";import"./throttle-Bs65PtnC.js";import"./index-DaAFB231.js";import"./data-DGp-Iau0.js";import"./index-BocM-74J.js";import"./business-CjXdXSjQ.js";import"./index-CEm6GyyI.js";const r=t({name:"CAManageForm",setup(){const{CAForm:t}=s();return()=>o(t,{labelPlacement:"top"},null)}});export{r as default};
|
||||
1
static/build/static/js/CAManageForm-Dyz_sMbm.js
Normal file
@@ -0,0 +1 @@
|
||||
import{u as s}from"./index-BZGW-6lh.js";import{d as t,c as o}from"./main-JC8aq1By.js";import"./useStore-CN6rAXJa.js";import"./index-CCRs72lf.js";import"./access-CGnP5Z8L.js";import"./index-DEff3yds.js";import"./throttle-D-tgB-x9.js";import"./index-CmlwJ1kX.js";import"./data-7FrDFtiI.js";import"./index-0z5TG9kl.js";import"./business-0Klrz1zP.js";import"./index-Cfd72zNl.js";const r=t({name:"CAManageForm",setup(){const{CAForm:t}=s();return()=>o(t,{labelPlacement:"top"},null)}});export{r as default};
|
||||
1
static/build/static/js/CAManageForm-lGDfYKxA.js
Normal file
@@ -0,0 +1 @@
|
||||
import{u as s}from"./index-DdlylIcx.js";import{d as t,c as o}from"./main-Cd9NCLQB.js";import"./useStore-Vx4sk6zd.js";import"./index-DaWzl1ur.js";import"./access-INphxj4G.js";import"./index-yUaAtD-K.js";import"./throttle-D99ELLRH.js";import"./index-DyzEpAdl.js";import"./data-DMTi6uCf.js";import"./index-X52VisOU.js";import"./business-CPrm7sa6.js";import"./index-YNVPcluS.js";const r=t({name:"CAManageForm",setup(){const{CAForm:t}=s();return()=>o(t,{labelPlacement:"top"},null)}});export{r as default};
|
||||
1
static/build/static/js/Flow-B49uR8na.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as a,Y as l,Z as n,_ as r}from"./main-JC8aq1By.js";const t={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 20 20"},o=a({name:"Certificate20Regular",render:function(a,o){return n(),l("svg",t,o[0]||(o[0]=[r("g",{fill:"none"},[r("path",{d:"M2 5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3.146a4.508 4.508 0 0 0-1-.678V5a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h7.258c.076.113.157.223.242.329V15H4a2 2 0 0 1-2-2V5zm16.5 6.5c0 .954-.381 1.818-1 2.45V18a.5.5 0 0 1-.8.4l-1.4-1.05a.5.5 0 0 0-.6 0l-1.4 1.05a.5.5 0 0 1-.8-.4v-4.05a3.5 3.5 0 1 1 6-2.45zM15 15c-.537 0-1.045-.12-1.5-.337v2.087l1.243-.746a.5.5 0 0 1 .514 0l1.243.746v-2.087A3.486 3.486 0 0 1 15 15zm0-1a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5zM5 6.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm.5 4.5a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1h-4z",fill:"currentColor"})],-1)]))}}),h={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},w=a({name:"CloudMonitoring",render:function(a,t){return n(),l("svg",h,t[0]||(t[0]=[r("path",{d:"M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6zM18 28h-4v-4h4z",fill:"currentColor"},null,-1),r("path",{d:"M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76l3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04l-3.082 10.018A1 1 0 0 1 18 18z",fill:"currentColor"},null,-1)]))}}),v={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},e=a({name:"Flow",render:function(a,t){return n(),l("svg",v,t[0]||(t[0]=[r("path",{d:"M27 22.14V17a2 2 0 0 0-2-2h-8V9.86a4 4 0 1 0-2 0V15H7a2 2 0 0 0-2 2v5.14a4 4 0 1 0 2 0V17h18v5.14a4 4 0 1 0 2 0zM8 26a2 2 0 1 1-2-2a2 2 0 0 1 2 2zm6-20a2 2 0 1 1 2 2a2 2 0 0 1-2-2zm12 22a2 2 0 1 1 2-2a2 2 0 0 1-2 2z",fill:"currentColor"},null,-1)]))}});export{o as C,e as F,w as a};
|
||||
1
static/build/static/js/Flow-B8gtP3Rr.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as a,U as l,W as n,X as r}from"./main-TC3Bu45J.js";const t={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 20 20"},o=a({name:"Certificate20Regular",render:function(a,o){return n(),l("svg",t,o[0]||(o[0]=[r("g",{fill:"none"},[r("path",{d:"M2 5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3.146a4.508 4.508 0 0 0-1-.678V5a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h7.258c.076.113.157.223.242.329V15H4a2 2 0 0 1-2-2V5zm16.5 6.5c0 .954-.381 1.818-1 2.45V18a.5.5 0 0 1-.8.4l-1.4-1.05a.5.5 0 0 0-.6 0l-1.4 1.05a.5.5 0 0 1-.8-.4v-4.05a3.5 3.5 0 1 1 6-2.45zM15 15c-.537 0-1.045-.12-1.5-.337v2.087l1.243-.746a.5.5 0 0 1 .514 0l1.243.746v-2.087A3.486 3.486 0 0 1 15 15zm0-1a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5zM5 6.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm.5 4.5a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1h-4z",fill:"currentColor"})],-1)]))}}),h={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},w=a({name:"CloudMonitoring",render:function(a,t){return n(),l("svg",h,t[0]||(t[0]=[r("path",{d:"M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6zM18 28h-4v-4h4z",fill:"currentColor"},null,-1),r("path",{d:"M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76l3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04l-3.082 10.018A1 1 0 0 1 18 18z",fill:"currentColor"},null,-1)]))}}),v={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},e=a({name:"Flow",render:function(a,t){return n(),l("svg",v,t[0]||(t[0]=[r("path",{d:"M27 22.14V17a2 2 0 0 0-2-2h-8V9.86a4 4 0 1 0-2 0V15H7a2 2 0 0 0-2 2v5.14a4 4 0 1 0 2 0V17h18v5.14a4 4 0 1 0 2 0zM8 26a2 2 0 1 1-2-2a2 2 0 0 1 2 2zm6-20a2 2 0 1 1 2 2a2 2 0 0 1-2-2zm12 22a2 2 0 1 1 2-2a2 2 0 0 1-2 2z",fill:"currentColor"},null,-1)]))}});export{w as C,e as F,o as a};
|
||||
1
static/build/static/js/Flow-BEylpcHn.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as a,Y as l,Z as n,_ as r}from"./main-BjWWkfgM.js";const t={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 20 20"},o=a({name:"Certificate20Regular",render:function(a,o){return n(),l("svg",t,o[0]||(o[0]=[r("g",{fill:"none"},[r("path",{d:"M2 5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3.146a4.508 4.508 0 0 0-1-.678V5a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h7.258c.076.113.157.223.242.329V15H4a2 2 0 0 1-2-2V5zm16.5 6.5c0 .954-.381 1.818-1 2.45V18a.5.5 0 0 1-.8.4l-1.4-1.05a.5.5 0 0 0-.6 0l-1.4 1.05a.5.5 0 0 1-.8-.4v-4.05a3.5 3.5 0 1 1 6-2.45zM15 15c-.537 0-1.045-.12-1.5-.337v2.087l1.243-.746a.5.5 0 0 1 .514 0l1.243.746v-2.087A3.486 3.486 0 0 1 15 15zm0-1a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5zM5 6.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm.5 4.5a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1h-4z",fill:"currentColor"})],-1)]))}}),h={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},w=a({name:"CloudMonitoring",render:function(a,t){return n(),l("svg",h,t[0]||(t[0]=[r("path",{d:"M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6zM18 28h-4v-4h4z",fill:"currentColor"},null,-1),r("path",{d:"M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76l3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04l-3.082 10.018A1 1 0 0 1 18 18z",fill:"currentColor"},null,-1)]))}}),v={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},e=a({name:"Flow",render:function(a,t){return n(),l("svg",v,t[0]||(t[0]=[r("path",{d:"M27 22.14V17a2 2 0 0 0-2-2h-8V9.86a4 4 0 1 0-2 0V15H7a2 2 0 0 0-2 2v5.14a4 4 0 1 0 2 0V17h18v5.14a4 4 0 1 0 2 0zM8 26a2 2 0 1 1-2-2a2 2 0 0 1 2 2zm6-20a2 2 0 1 1 2 2a2 2 0 0 1-2-2zm12 22a2 2 0 1 1 2-2a2 2 0 0 1-2 2z",fill:"currentColor"},null,-1)]))}});export{o as C,e as F,w as a};
|
||||
1
static/build/static/js/Flow-BuHvmPI8.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as a,Y as l,Z as n,_ as r}from"./main-BLIIbSTQ.js";const t={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 20 20"},o=a({name:"Certificate20Regular",render:function(a,o){return n(),l("svg",t,o[0]||(o[0]=[r("g",{fill:"none"},[r("path",{d:"M2 5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3.146a4.508 4.508 0 0 0-1-.678V5a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h7.258c.076.113.157.223.242.329V15H4a2 2 0 0 1-2-2V5zm16.5 6.5c0 .954-.381 1.818-1 2.45V18a.5.5 0 0 1-.8.4l-1.4-1.05a.5.5 0 0 0-.6 0l-1.4 1.05a.5.5 0 0 1-.8-.4v-4.05a3.5 3.5 0 1 1 6-2.45zM15 15c-.537 0-1.045-.12-1.5-.337v2.087l1.243-.746a.5.5 0 0 1 .514 0l1.243.746v-2.087A3.486 3.486 0 0 1 15 15zm0-1a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5zM5 6.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm.5 4.5a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1h-4z",fill:"currentColor"})],-1)]))}}),h={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},w=a({name:"CloudMonitoring",render:function(a,t){return n(),l("svg",h,t[0]||(t[0]=[r("path",{d:"M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6zM18 28h-4v-4h4z",fill:"currentColor"},null,-1),r("path",{d:"M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76l3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04l-3.082 10.018A1 1 0 0 1 18 18z",fill:"currentColor"},null,-1)]))}}),v={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},e=a({name:"Flow",render:function(a,t){return n(),l("svg",v,t[0]||(t[0]=[r("path",{d:"M27 22.14V17a2 2 0 0 0-2-2h-8V9.86a4 4 0 1 0-2 0V15H7a2 2 0 0 0-2 2v5.14a4 4 0 1 0 2 0V17h18v5.14a4 4 0 1 0 2 0zM8 26a2 2 0 1 1-2-2a2 2 0 0 1 2 2zm6-20a2 2 0 1 1 2 2a2 2 0 0 1-2-2zm12 22a2 2 0 1 1 2-2a2 2 0 0 1-2 2z",fill:"currentColor"},null,-1)]))}});export{o as C,e as F,w as a};
|
||||
1
static/build/static/js/Flow-Cxd2mc38.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as a,Y as l,Z as n,_ as r}from"./main-DzwaUoFb.js";const t={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 20 20"},o=a({name:"Certificate20Regular",render:function(a,o){return n(),l("svg",t,o[0]||(o[0]=[r("g",{fill:"none"},[r("path",{d:"M2 5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3.146a4.508 4.508 0 0 0-1-.678V5a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h7.258c.076.113.157.223.242.329V15H4a2 2 0 0 1-2-2V5zm16.5 6.5c0 .954-.381 1.818-1 2.45V18a.5.5 0 0 1-.8.4l-1.4-1.05a.5.5 0 0 0-.6 0l-1.4 1.05a.5.5 0 0 1-.8-.4v-4.05a3.5 3.5 0 1 1 6-2.45zM15 15c-.537 0-1.045-.12-1.5-.337v2.087l1.243-.746a.5.5 0 0 1 .514 0l1.243.746v-2.087A3.486 3.486 0 0 1 15 15zm0-1a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5zM5 6.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm.5 4.5a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1h-4z",fill:"currentColor"})],-1)]))}}),h={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},w=a({name:"CloudMonitoring",render:function(a,t){return n(),l("svg",h,t[0]||(t[0]=[r("path",{d:"M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6zM18 28h-4v-4h4z",fill:"currentColor"},null,-1),r("path",{d:"M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76l3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04l-3.082 10.018A1 1 0 0 1 18 18z",fill:"currentColor"},null,-1)]))}}),v={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},e=a({name:"Flow",render:function(a,t){return n(),l("svg",v,t[0]||(t[0]=[r("path",{d:"M27 22.14V17a2 2 0 0 0-2-2h-8V9.86a4 4 0 1 0-2 0V15H7a2 2 0 0 0-2 2v5.14a4 4 0 1 0 2 0V17h18v5.14a4 4 0 1 0 2 0zM8 26a2 2 0 1 1-2-2a2 2 0 0 1 2 2zm6-20a2 2 0 1 1 2 2a2 2 0 0 1-2-2zm12 22a2 2 0 1 1 2-2a2 2 0 0 1-2 2z",fill:"currentColor"},null,-1)]))}});export{o as C,e as F,w as a};
|
||||
1
static/build/static/js/Flow-D8fET77H.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as a,Y as l,Z as n,_ as r}from"./main-D37kYvfP.js";const t={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 20 20"},o=a({name:"Certificate20Regular",render:function(a,o){return n(),l("svg",t,o[0]||(o[0]=[r("g",{fill:"none"},[r("path",{d:"M2 5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3.146a4.508 4.508 0 0 0-1-.678V5a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h7.258c.076.113.157.223.242.329V15H4a2 2 0 0 1-2-2V5zm16.5 6.5c0 .954-.381 1.818-1 2.45V18a.5.5 0 0 1-.8.4l-1.4-1.05a.5.5 0 0 0-.6 0l-1.4 1.05a.5.5 0 0 1-.8-.4v-4.05a3.5 3.5 0 1 1 6-2.45zM15 15c-.537 0-1.045-.12-1.5-.337v2.087l1.243-.746a.5.5 0 0 1 .514 0l1.243.746v-2.087A3.486 3.486 0 0 1 15 15zm0-1a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5zM5 6.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm.5 4.5a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1h-4z",fill:"currentColor"})],-1)]))}}),h={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},w=a({name:"CloudMonitoring",render:function(a,t){return n(),l("svg",h,t[0]||(t[0]=[r("path",{d:"M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6zM18 28h-4v-4h4z",fill:"currentColor"},null,-1),r("path",{d:"M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76l3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04l-3.082 10.018A1 1 0 0 1 18 18z",fill:"currentColor"},null,-1)]))}}),v={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},e=a({name:"Flow",render:function(a,t){return n(),l("svg",v,t[0]||(t[0]=[r("path",{d:"M27 22.14V17a2 2 0 0 0-2-2h-8V9.86a4 4 0 1 0-2 0V15H7a2 2 0 0 0-2 2v5.14a4 4 0 1 0 2 0V17h18v5.14a4 4 0 1 0 2 0zM8 26a2 2 0 1 1-2-2a2 2 0 0 1 2 2zm6-20a2 2 0 1 1 2 2a2 2 0 0 1-2-2zm12 22a2 2 0 1 1 2-2a2 2 0 0 1-2 2z",fill:"currentColor"},null,-1)]))}});export{o as C,e as F,w as a};
|
||||
1
static/build/static/js/Flow-DMLSdK7P.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as a,Y as l,Z as n,_ as r}from"./main-DPHcWoLq.js";const t={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 20 20"},o=a({name:"Certificate20Regular",render:function(a,o){return n(),l("svg",t,o[0]||(o[0]=[r("g",{fill:"none"},[r("path",{d:"M2 5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3.146a4.508 4.508 0 0 0-1-.678V5a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h7.258c.076.113.157.223.242.329V15H4a2 2 0 0 1-2-2V5zm16.5 6.5c0 .954-.381 1.818-1 2.45V18a.5.5 0 0 1-.8.4l-1.4-1.05a.5.5 0 0 0-.6 0l-1.4 1.05a.5.5 0 0 1-.8-.4v-4.05a3.5 3.5 0 1 1 6-2.45zM15 15c-.537 0-1.045-.12-1.5-.337v2.087l1.243-.746a.5.5 0 0 1 .514 0l1.243.746v-2.087A3.486 3.486 0 0 1 15 15zm0-1a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5zM5 6.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm.5 4.5a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1h-4z",fill:"currentColor"})],-1)]))}}),h={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},w=a({name:"CloudMonitoring",render:function(a,t){return n(),l("svg",h,t[0]||(t[0]=[r("path",{d:"M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6zM18 28h-4v-4h4z",fill:"currentColor"},null,-1),r("path",{d:"M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76l3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04l-3.082 10.018A1 1 0 0 1 18 18z",fill:"currentColor"},null,-1)]))}}),v={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},e=a({name:"Flow",render:function(a,t){return n(),l("svg",v,t[0]||(t[0]=[r("path",{d:"M27 22.14V17a2 2 0 0 0-2-2h-8V9.86a4 4 0 1 0-2 0V15H7a2 2 0 0 0-2 2v5.14a4 4 0 1 0 2 0V17h18v5.14a4 4 0 1 0 2 0zM8 26a2 2 0 1 1-2-2a2 2 0 0 1 2 2zm6-20a2 2 0 1 1 2 2a2 2 0 0 1-2-2zm12 22a2 2 0 1 1 2-2a2 2 0 0 1-2 2z",fill:"currentColor"},null,-1)]))}});export{o as C,e as F,w as a};
|
||||
1
static/build/static/js/Flow-DtMlLaAY.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as a,Y as l,Z as n,_ as r}from"./main-Cd9NCLQB.js";const t={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 20 20"},o=a({name:"Certificate20Regular",render:function(a,o){return n(),l("svg",t,o[0]||(o[0]=[r("g",{fill:"none"},[r("path",{d:"M2 5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3.146a4.508 4.508 0 0 0-1-.678V5a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h7.258c.076.113.157.223.242.329V15H4a2 2 0 0 1-2-2V5zm16.5 6.5c0 .954-.381 1.818-1 2.45V18a.5.5 0 0 1-.8.4l-1.4-1.05a.5.5 0 0 0-.6 0l-1.4 1.05a.5.5 0 0 1-.8-.4v-4.05a3.5 3.5 0 1 1 6-2.45zM15 15c-.537 0-1.045-.12-1.5-.337v2.087l1.243-.746a.5.5 0 0 1 .514 0l1.243.746v-2.087A3.486 3.486 0 0 1 15 15zm0-1a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5zM5 6.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm.5 4.5a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1h-4z",fill:"currentColor"})],-1)]))}}),h={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},w=a({name:"CloudMonitoring",render:function(a,t){return n(),l("svg",h,t[0]||(t[0]=[r("path",{d:"M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6zM18 28h-4v-4h4z",fill:"currentColor"},null,-1),r("path",{d:"M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76l3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04l-3.082 10.018A1 1 0 0 1 18 18z",fill:"currentColor"},null,-1)]))}}),v={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},e=a({name:"Flow",render:function(a,t){return n(),l("svg",v,t[0]||(t[0]=[r("path",{d:"M27 22.14V17a2 2 0 0 0-2-2h-8V9.86a4 4 0 1 0-2 0V15H7a2 2 0 0 0-2 2v5.14a4 4 0 1 0 2 0V17h18v5.14a4 4 0 1 0 2 0zM8 26a2 2 0 1 1-2-2a2 2 0 0 1 2 2zm6-20a2 2 0 1 1 2 2a2 2 0 0 1-2-2zm12 22a2 2 0 1 1 2-2a2 2 0 0 1-2 2z",fill:"currentColor"},null,-1)]))}});export{o as C,e as F,w as a};
|
||||
1
static/build/static/js/Flow-ZB5TVrD3.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as a,Y as l,Z as n,_ as r}from"./main-l9ONqWM3.js";const t={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 20 20"},o=a({name:"Certificate20Regular",render:function(a,o){return n(),l("svg",t,o[0]||(o[0]=[r("g",{fill:"none"},[r("path",{d:"M2 5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3.146a4.508 4.508 0 0 0-1-.678V5a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h7.258c.076.113.157.223.242.329V15H4a2 2 0 0 1-2-2V5zm16.5 6.5c0 .954-.381 1.818-1 2.45V18a.5.5 0 0 1-.8.4l-1.4-1.05a.5.5 0 0 0-.6 0l-1.4 1.05a.5.5 0 0 1-.8-.4v-4.05a3.5 3.5 0 1 1 6-2.45zM15 15c-.537 0-1.045-.12-1.5-.337v2.087l1.243-.746a.5.5 0 0 1 .514 0l1.243.746v-2.087A3.486 3.486 0 0 1 15 15zm0-1a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5zM5 6.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm.5 4.5a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1h-4z",fill:"currentColor"})],-1)]))}}),h={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},w=a({name:"CloudMonitoring",render:function(a,t){return n(),l("svg",h,t[0]||(t[0]=[r("path",{d:"M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6zM18 28h-4v-4h4z",fill:"currentColor"},null,-1),r("path",{d:"M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76l3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04l-3.082 10.018A1 1 0 0 1 18 18z",fill:"currentColor"},null,-1)]))}}),v={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 32 32"},e=a({name:"Flow",render:function(a,t){return n(),l("svg",v,t[0]||(t[0]=[r("path",{d:"M27 22.14V17a2 2 0 0 0-2-2h-8V9.86a4 4 0 1 0-2 0V15H7a2 2 0 0 0-2 2v5.14a4 4 0 1 0 2 0V17h18v5.14a4 4 0 1 0 2 0zM8 26a2 2 0 1 1-2-2a2 2 0 0 1 2 2zm6-20a2 2 0 1 1 2 2a2 2 0 0 1-2-2zm12 22a2 2 0 1 1 2-2a2 2 0 0 1-2 2z",fill:"currentColor"},null,-1)]))}});export{o as C,e as F,w as a};
|
||||
1
static/build/static/js/LockOutlined-B5ZtmhXj.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as n,Z as r,_ as t}from"./main-JC8aq1By.js";const o={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 1024 1024"},s=c({name:"LockOutlined",render:function(c,s){return r(),n("svg",o,s[0]||(s[0]=[t("path",{d:"M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 1 0-56 0z",fill:"currentColor"},null,-1)]))}});export{s as L};
|
||||
1
static/build/static/js/LockOutlined-B7NOVmKZ.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as n,Z as r,_ as t}from"./main-DPHcWoLq.js";const o={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 1024 1024"},s=c({name:"LockOutlined",render:function(c,s){return r(),n("svg",o,s[0]||(s[0]=[t("path",{d:"M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 1 0-56 0z",fill:"currentColor"},null,-1)]))}});export{s as L};
|
||||
1
static/build/static/js/LockOutlined-BU6vHF85.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as n,Z as r,_ as t}from"./main-BLIIbSTQ.js";const o={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 1024 1024"},s=c({name:"LockOutlined",render:function(c,s){return r(),n("svg",o,s[0]||(s[0]=[t("path",{d:"M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 1 0-56 0z",fill:"currentColor"},null,-1)]))}});export{s as L};
|
||||
1
static/build/static/js/LockOutlined-BkPrBf4U.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as n,Z as r,_ as t}from"./main-l9ONqWM3.js";const o={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 1024 1024"},s=c({name:"LockOutlined",render:function(c,s){return r(),n("svg",o,s[0]||(s[0]=[t("path",{d:"M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 1 0-56 0z",fill:"currentColor"},null,-1)]))}});export{s as L};
|
||||
1
static/build/static/js/LockOutlined-BxdBYrGQ.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as n,Z as r,_ as t}from"./main-Cd9NCLQB.js";const o={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 1024 1024"},s=c({name:"LockOutlined",render:function(c,s){return r(),n("svg",o,s[0]||(s[0]=[t("path",{d:"M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 1 0-56 0z",fill:"currentColor"},null,-1)]))}});export{s as L};
|
||||
1
static/build/static/js/LockOutlined-CTVc4DOh.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as n,Z as r,_ as t}from"./main-DzwaUoFb.js";const o={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 1024 1024"},s=c({name:"LockOutlined",render:function(c,s){return r(),n("svg",o,s[0]||(s[0]=[t("path",{d:"M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 1 0-56 0z",fill:"currentColor"},null,-1)]))}});export{s as L};
|
||||
1
static/build/static/js/LockOutlined-CcPqjOST.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as n,Z as r,_ as t}from"./main-D37kYvfP.js";const o={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 1024 1024"},s=c({name:"LockOutlined",render:function(c,s){return r(),n("svg",o,s[0]||(s[0]=[t("path",{d:"M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 1 0-56 0z",fill:"currentColor"},null,-1)]))}});export{s as L};
|
||||
1
static/build/static/js/LockOutlined-Ybbhb7F_.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,U as n,W as r,X as t}from"./main-TC3Bu45J.js";const o={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 1024 1024"},s=c({name:"LockOutlined",render:function(c,s){return r(),n("svg",o,s[0]||(s[0]=[t("path",{d:"M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 1 0-56 0z",fill:"currentColor"},null,-1)]))}});export{s as L};
|
||||
1
static/build/static/js/LockOutlined-m3miyQNr.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as n,Z as r,_ as t}from"./main-BjWWkfgM.js";const o={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 1024 1024"},s=c({name:"LockOutlined",render:function(c,s){return r(),n("svg",o,s[0]||(s[0]=[t("path",{d:"M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 1 0-56 0z",fill:"currentColor"},null,-1)]))}});export{s as L};
|
||||
1
static/build/static/js/LogoGithub-BKQxx7-N.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as a,Z as n,_ as o}from"./main-DzwaUoFb.js";const r={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 512 512"},t=c({name:"LogoGithub",render:function(c,t){return n(),a("svg",r,t[0]||(t[0]=[o("path",{d:"M256 32C132.3 32 32 134.9 32 261.7c0 101.5 64.2 187.5 153.2 217.9a17.56 17.56 0 0 0 3.8.4c8.3 0 11.5-6.1 11.5-11.4c0-5.5-.2-19.9-.3-39.1a102.4 102.4 0 0 1-22.6 2.7c-43.1 0-52.9-33.5-52.9-33.5c-10.2-26.5-24.9-33.6-24.9-33.6c-19.5-13.7-.1-14.1 1.4-14.1h.1c22.5 2 34.3 23.8 34.3 23.8c11.2 19.6 26.2 25.1 39.6 25.1a63 63 0 0 0 25.6-6c2-14.8 7.8-24.9 14.2-30.7c-49.7-5.8-102-25.5-102-113.5c0-25.1 8.7-45.6 23-61.6c-2.3-5.8-10-29.2 2.2-60.8a18.64 18.64 0 0 1 5-.5c8.1 0 26.4 3.1 56.6 24.1a208.21 208.21 0 0 1 112.2 0c30.2-21 48.5-24.1 56.6-24.1a18.64 18.64 0 0 1 5 .5c12.2 31.6 4.5 55 2.2 60.8c14.3 16.1 23 36.6 23 61.6c0 88.2-52.4 107.6-102.3 113.3c8 7.1 15.2 21.1 15.2 42.5c0 30.7-.3 55.5-.3 63c0 5.4 3.1 11.5 11.4 11.5a19.35 19.35 0 0 0 4-.4C415.9 449.2 480 363.1 480 261.7C480 134.9 379.7 32 256 32z",fill:"currentColor"},null,-1)]))}});export{t as L};
|
||||
1
static/build/static/js/LogoGithub-BLxoVA__.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as a,Z as n,_ as o}from"./main-JC8aq1By.js";const r={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 512 512"},t=c({name:"LogoGithub",render:function(c,t){return n(),a("svg",r,t[0]||(t[0]=[o("path",{d:"M256 32C132.3 32 32 134.9 32 261.7c0 101.5 64.2 187.5 153.2 217.9a17.56 17.56 0 0 0 3.8.4c8.3 0 11.5-6.1 11.5-11.4c0-5.5-.2-19.9-.3-39.1a102.4 102.4 0 0 1-22.6 2.7c-43.1 0-52.9-33.5-52.9-33.5c-10.2-26.5-24.9-33.6-24.9-33.6c-19.5-13.7-.1-14.1 1.4-14.1h.1c22.5 2 34.3 23.8 34.3 23.8c11.2 19.6 26.2 25.1 39.6 25.1a63 63 0 0 0 25.6-6c2-14.8 7.8-24.9 14.2-30.7c-49.7-5.8-102-25.5-102-113.5c0-25.1 8.7-45.6 23-61.6c-2.3-5.8-10-29.2 2.2-60.8a18.64 18.64 0 0 1 5-.5c8.1 0 26.4 3.1 56.6 24.1a208.21 208.21 0 0 1 112.2 0c30.2-21 48.5-24.1 56.6-24.1a18.64 18.64 0 0 1 5 .5c12.2 31.6 4.5 55 2.2 60.8c14.3 16.1 23 36.6 23 61.6c0 88.2-52.4 107.6-102.3 113.3c8 7.1 15.2 21.1 15.2 42.5c0 30.7-.3 55.5-.3 63c0 5.4 3.1 11.5 11.4 11.5a19.35 19.35 0 0 0 4-.4C415.9 449.2 480 363.1 480 261.7C480 134.9 379.7 32 256 32z",fill:"currentColor"},null,-1)]))}});export{t as L};
|
||||
1
static/build/static/js/LogoGithub-Bdy4bvc1.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as a,Z as n,_ as o}from"./main-D37kYvfP.js";const r={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 512 512"},t=c({name:"LogoGithub",render:function(c,t){return n(),a("svg",r,t[0]||(t[0]=[o("path",{d:"M256 32C132.3 32 32 134.9 32 261.7c0 101.5 64.2 187.5 153.2 217.9a17.56 17.56 0 0 0 3.8.4c8.3 0 11.5-6.1 11.5-11.4c0-5.5-.2-19.9-.3-39.1a102.4 102.4 0 0 1-22.6 2.7c-43.1 0-52.9-33.5-52.9-33.5c-10.2-26.5-24.9-33.6-24.9-33.6c-19.5-13.7-.1-14.1 1.4-14.1h.1c22.5 2 34.3 23.8 34.3 23.8c11.2 19.6 26.2 25.1 39.6 25.1a63 63 0 0 0 25.6-6c2-14.8 7.8-24.9 14.2-30.7c-49.7-5.8-102-25.5-102-113.5c0-25.1 8.7-45.6 23-61.6c-2.3-5.8-10-29.2 2.2-60.8a18.64 18.64 0 0 1 5-.5c8.1 0 26.4 3.1 56.6 24.1a208.21 208.21 0 0 1 112.2 0c30.2-21 48.5-24.1 56.6-24.1a18.64 18.64 0 0 1 5 .5c12.2 31.6 4.5 55 2.2 60.8c14.3 16.1 23 36.6 23 61.6c0 88.2-52.4 107.6-102.3 113.3c8 7.1 15.2 21.1 15.2 42.5c0 30.7-.3 55.5-.3 63c0 5.4 3.1 11.5 11.4 11.5a19.35 19.35 0 0 0 4-.4C415.9 449.2 480 363.1 480 261.7C480 134.9 379.7 32 256 32z",fill:"currentColor"},null,-1)]))}});export{t as L};
|
||||
1
static/build/static/js/LogoGithub-D0SyK6Li.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as a,Z as n,_ as o}from"./main-BjWWkfgM.js";const r={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 512 512"},t=c({name:"LogoGithub",render:function(c,t){return n(),a("svg",r,t[0]||(t[0]=[o("path",{d:"M256 32C132.3 32 32 134.9 32 261.7c0 101.5 64.2 187.5 153.2 217.9a17.56 17.56 0 0 0 3.8.4c8.3 0 11.5-6.1 11.5-11.4c0-5.5-.2-19.9-.3-39.1a102.4 102.4 0 0 1-22.6 2.7c-43.1 0-52.9-33.5-52.9-33.5c-10.2-26.5-24.9-33.6-24.9-33.6c-19.5-13.7-.1-14.1 1.4-14.1h.1c22.5 2 34.3 23.8 34.3 23.8c11.2 19.6 26.2 25.1 39.6 25.1a63 63 0 0 0 25.6-6c2-14.8 7.8-24.9 14.2-30.7c-49.7-5.8-102-25.5-102-113.5c0-25.1 8.7-45.6 23-61.6c-2.3-5.8-10-29.2 2.2-60.8a18.64 18.64 0 0 1 5-.5c8.1 0 26.4 3.1 56.6 24.1a208.21 208.21 0 0 1 112.2 0c30.2-21 48.5-24.1 56.6-24.1a18.64 18.64 0 0 1 5 .5c12.2 31.6 4.5 55 2.2 60.8c14.3 16.1 23 36.6 23 61.6c0 88.2-52.4 107.6-102.3 113.3c8 7.1 15.2 21.1 15.2 42.5c0 30.7-.3 55.5-.3 63c0 5.4 3.1 11.5 11.4 11.5a19.35 19.35 0 0 0 4-.4C415.9 449.2 480 363.1 480 261.7C480 134.9 379.7 32 256 32z",fill:"currentColor"},null,-1)]))}});export{t as L};
|
||||
1
static/build/static/js/LogoGithub-LYMF6yE0.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as c,Y as a,Z as n,_ as o}from"./main-BLIIbSTQ.js";const r={xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",viewBox:"0 0 512 512"},t=c({name:"LogoGithub",render:function(c,t){return n(),a("svg",r,t[0]||(t[0]=[o("path",{d:"M256 32C132.3 32 32 134.9 32 261.7c0 101.5 64.2 187.5 153.2 217.9a17.56 17.56 0 0 0 3.8.4c8.3 0 11.5-6.1 11.5-11.4c0-5.5-.2-19.9-.3-39.1a102.4 102.4 0 0 1-22.6 2.7c-43.1 0-52.9-33.5-52.9-33.5c-10.2-26.5-24.9-33.6-24.9-33.6c-19.5-13.7-.1-14.1 1.4-14.1h.1c22.5 2 34.3 23.8 34.3 23.8c11.2 19.6 26.2 25.1 39.6 25.1a63 63 0 0 0 25.6-6c2-14.8 7.8-24.9 14.2-30.7c-49.7-5.8-102-25.5-102-113.5c0-25.1 8.7-45.6 23-61.6c-2.3-5.8-10-29.2 2.2-60.8a18.64 18.64 0 0 1 5-.5c8.1 0 26.4 3.1 56.6 24.1a208.21 208.21 0 0 1 112.2 0c30.2-21 48.5-24.1 56.6-24.1a18.64 18.64 0 0 1 5 .5c12.2 31.6 4.5 55 2.2 60.8c14.3 16.1 23 36.6 23 61.6c0 88.2-52.4 107.6-102.3 113.3c8 7.1 15.2 21.1 15.2 42.5c0 30.7-.3 55.5-.3 63c0 5.4 3.1 11.5 11.4 11.5a19.35 19.35 0 0 0 4-.4C415.9 449.2 480 363.1 480 261.7C480 134.9 379.7 32 256 32z",fill:"currentColor"},null,-1)]))}});export{t as L};
|
||||
1
static/build/static/js/Tabs-BYmnlfgu.js
Normal file
1
static/build/static/js/Tabs-BxwSXwhd.js
Normal file
1
static/build/static/js/Tabs-C08wQZzg.js
Normal file
1
static/build/static/js/Tabs-CNL_If9W.js
Normal file
1
static/build/static/js/Tabs-CP4vdC9u.js
Normal file
1
static/build/static/js/Tabs-CrM1xrfx.js
Normal file
1
static/build/static/js/Tabs-D-Dw3z1S.js
Normal file
1
static/build/static/js/Tabs-uVUkqwn-.js
Normal file
1
static/build/static/js/Tabs-yRmIMARl.js
Normal file
1
static/build/static/js/access-C8j2cGON.js
Normal file
@@ -0,0 +1 @@
|
||||
import{c as s}from"./index-CyQKn_q4.js";const a=a=>s("/v1/access/get_list",a),c=a=>s("/v1/access/add_access",a),e=a=>s("/v1/access/upd_access",a),t=a=>s("/v1/access/del_access",a),_=a=>s("/v1/access/get_all",a),v=a=>s("/v1/access/get_eab_list",a),d=a=>s("/v1/access/add_eab",a),l=a=>s("/v1/access/del_eab",a),g=a=>s("/v1/access/get_all_eab",a),i=a=>s("/v1/access/test_access",a),b=a=>s("/v1/access/get_sites",a);export{c as a,v as b,d as c,t as d,l as e,g as f,a as g,b as h,_ as i,i as t,e as u};
|
||||
1
static/build/static/js/access-CGnP5Z8L.js
Normal file
@@ -0,0 +1 @@
|
||||
import{c as s}from"./index-CCRs72lf.js";const a=a=>s("/v1/access/get_list",a),c=a=>s("/v1/access/add_access",a),e=a=>s("/v1/access/upd_access",a),t=a=>s("/v1/access/del_access",a),_=a=>s("/v1/access/get_all",a),v=a=>s("/v1/access/get_eab_list",a),d=a=>s("/v1/access/add_eab",a),l=a=>s("/v1/access/del_eab",a),g=a=>s("/v1/access/get_all_eab",a),i=a=>s("/v1/access/test_access",a),b=a=>s("/v1/access/get_sites",a);export{c as a,v as b,d as c,t as d,l as e,g as f,a as g,b as h,_ as i,i as t,e as u};
|
||||
1
static/build/static/js/access-CRBQqgF7.js
Normal file
@@ -0,0 +1 @@
|
||||
import{c as s}from"./index-B19cVdYt.js";const a=a=>s("/v1/access/get_list",a),c=a=>s("/v1/access/add_access",a),e=a=>s("/v1/access/upd_access",a),t=a=>s("/v1/access/del_access",a),_=a=>s("/v1/access/get_all",a),v=a=>s("/v1/access/get_eab_list",a),d=a=>s("/v1/access/add_eab",a),l=a=>s("/v1/access/del_eab",a),g=a=>s("/v1/access/get_all_eab",a),i=a=>s("/v1/access/test_access",a),b=a=>s("/v1/access/get_sites",a);export{c as a,v as b,d as c,t as d,l as e,g as f,a as g,b as h,_ as i,i as t,e as u};
|
||||
1
static/build/static/js/access-CVoV-9UZ.js
Normal file
@@ -0,0 +1 @@
|
||||
import{c as s}from"./index-jviZh_iP.js";const a=a=>s("/v1/access/get_list",a),c=a=>s("/v1/access/add_access",a),e=a=>s("/v1/access/upd_access",a),t=a=>s("/v1/access/del_access",a),_=a=>s("/v1/access/get_all",a),v=a=>s("/v1/access/get_eab_list",a),d=a=>s("/v1/access/add_eab",a),l=a=>s("/v1/access/del_eab",a),g=a=>s("/v1/access/get_all_eab",a),i=a=>s("/v1/access/test_access",a),b=a=>s("/v1/access/get_sites",a);export{c as a,v as b,d as c,t as d,l as e,g as f,a as g,b as h,_ as i,i as t,e as u};
|
||||
1
static/build/static/js/access-D0TDoR2F.js
Normal file
@@ -0,0 +1 @@
|
||||
import{c as s}from"./index-BpNpm-gE.js";const a=a=>s("/v1/access/get_list",a),c=a=>s("/v1/access/add_access",a),e=a=>s("/v1/access/upd_access",a),t=a=>s("/v1/access/del_access",a),_=a=>s("/v1/access/get_all",a),v=a=>s("/v1/access/get_eab_list",a),d=a=>s("/v1/access/add_eab",a),l=a=>s("/v1/access/del_eab",a),g=a=>s("/v1/access/get_all_eab",a),i=a=>s("/v1/access/test_access",a),b=a=>s("/v1/access/get_sites",a);export{c as a,v as b,d as c,t as d,l as e,g as f,a as g,b as h,_ as i,i as t,e as u};
|
||||
1
static/build/static/js/access-D1d2FuYi.js
Normal file
@@ -0,0 +1 @@
|
||||
import{c}from"./index-BNb4DSrN.js";const s=s=>c("/v1/access/get_list",s),a=s=>c("/v1/access/add_access",s),e=s=>c("/v1/access/upd_access",s),t=s=>c("/v1/access/del_access",s),_=s=>c("/v1/access/get_all",s),v=s=>c("/v1/acme_account/get_list",s),o=s=>c("/v1/acme_account/add_account",s),u=s=>c("/v1/acme_account/upd_account",s),d=s=>c("/v1/acme_account/del_account",s),n=s=>c("/v1/access/test_access",s),g=s=>c("/v1/access/get_sites",s),i=()=>c("/v1/access/get_plugins");export{a,i as b,v as c,t as d,o as e,u as f,s as g,d as h,g as i,_ as j,n as t,e as u};
|
||||
1
static/build/static/js/access-D5PuzSlL.js
Normal file
@@ -0,0 +1 @@
|
||||
import{c as s}from"./index-DuE5FJUK.js";const a=a=>s("/v1/access/get_list",a),c=a=>s("/v1/access/add_access",a),e=a=>s("/v1/access/upd_access",a),t=a=>s("/v1/access/del_access",a),_=a=>s("/v1/access/get_all",a),v=a=>s("/v1/access/get_eab_list",a),d=a=>s("/v1/access/add_eab",a),l=a=>s("/v1/access/del_eab",a),g=a=>s("/v1/access/get_all_eab",a),i=a=>s("/v1/access/test_access",a),b=a=>s("/v1/access/get_sites",a);export{c as a,v as b,d as c,t as d,l as e,g as f,a as g,b as h,_ as i,i as t,e as u};
|
||||
1
static/build/static/js/access-DAUICydO.js
Normal file
@@ -0,0 +1 @@
|
||||
import{c as s}from"./index-CROykHUI.js";const a=a=>s("/v1/access/get_list",a),c=a=>s("/v1/access/add_access",a),e=a=>s("/v1/access/upd_access",a),t=a=>s("/v1/access/del_access",a),_=a=>s("/v1/access/get_all",a),v=a=>s("/v1/access/get_eab_list",a),d=a=>s("/v1/access/add_eab",a),l=a=>s("/v1/access/del_eab",a),g=a=>s("/v1/access/get_all_eab",a),i=a=>s("/v1/access/test_access",a),b=a=>s("/v1/access/get_sites",a);export{c as a,v as b,d as c,t as d,l as e,g as f,a as g,b as h,_ as i,i as t,e as u};
|
||||
1
static/build/static/js/access-INphxj4G.js
Normal file
@@ -0,0 +1 @@
|
||||
import{c as s}from"./index-DaWzl1ur.js";const a=a=>s("/v1/access/get_list",a),c=a=>s("/v1/access/add_access",a),e=a=>s("/v1/access/upd_access",a),t=a=>s("/v1/access/del_access",a),_=a=>s("/v1/access/get_all",a),v=a=>s("/v1/access/get_eab_list",a),d=a=>s("/v1/access/add_eab",a),l=a=>s("/v1/access/del_eab",a),g=a=>s("/v1/access/get_all_eab",a),i=a=>s("/v1/access/test_access",a),b=a=>s("/v1/access/get_sites",a);export{c as a,v as b,d as c,t as d,l as e,g as f,a as g,b as h,_ as i,i as t,e as u};
|
||||