mirror of https://github.com/allinssl/allinssl
feat(siteMonitor): add support for custom ports
parent
29a7579743
commit
497b45de83
|
@ -8,6 +8,7 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// SSLInfo 定义结果结构体
|
||||
|
@ -188,18 +189,48 @@ func UpdInfo(id, domain string, s *public.Sqlite, reportType string) error {
|
|||
return errCheck
|
||||
}
|
||||
|
||||
// ExtractHostPort 从 target 中提取 host 和 port 并校验,若无 port 则使用默认值
|
||||
func ExtractAndValidateHostPort(target, defaultPort string) (host string, port string, err error) {
|
||||
host = target
|
||||
port = defaultPort
|
||||
|
||||
// 处理带端口情况
|
||||
if strings.Contains(target, ":") {
|
||||
h, p, splitErr := net.SplitHostPort(target)
|
||||
if splitErr == nil {
|
||||
host, port = h, p
|
||||
} else if !(strings.Count(target, ":") >= 2) || strings.Contains(target, "]") {
|
||||
return "", "", fmt.Errorf("地址格式错误:%v", splitErr)
|
||||
}
|
||||
}
|
||||
|
||||
// 验证端口是数字且在有效范围内
|
||||
portNum, convErr := strconv.Atoi(port)
|
||||
if convErr != nil || portNum < 1 || portNum > 65535 {
|
||||
return "", "", fmt.Errorf("端口号非法:%s", port)
|
||||
}
|
||||
|
||||
return host, port, nil
|
||||
}
|
||||
|
||||
// CheckWebsite 实际检测函数
|
||||
func CheckWebsite(target string) (*SSLInfo, error) {
|
||||
result := &SSLInfo{Target: target}
|
||||
|
||||
host, port, err := ExtractAndValidateHostPort(target, "443")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 验证格式是否是 IP 或域名
|
||||
if net.ParseIP(target) == nil {
|
||||
if _, err := net.LookupHost(target); err != nil {
|
||||
if net.ParseIP(host) == nil {
|
||||
if _, err := net.LookupHost(host); err != nil {
|
||||
return result, fmt.Errorf("无效域名或 IP:%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
hostPort := net.JoinHostPort(target, "443")
|
||||
hostPort := net.JoinHostPort(host, port)
|
||||
|
||||
// result := &SSLInfo{Target: target}
|
||||
|
||||
|
@ -213,7 +244,7 @@ func CheckWebsite(target string) (*SSLInfo, error) {
|
|||
defer conn.Close()
|
||||
|
||||
// 发送 HTTPS 请求检测状态
|
||||
resp, err := http.Get("https://" + target)
|
||||
resp, err := http.Get("https://" + hostPort)
|
||||
if err != nil {
|
||||
result.HTTPStatus = 0
|
||||
result.HTTPStatusText = "异常"
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
site := "bt.cn" // 只传域名或 IP,不要 http://
|
||||
site := "bt.cn:443" // 只传域名或 IP,不要 http://
|
||||
result, err := CheckWebsite(site)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 检测失败: %v\n", err)
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
useLoadingMask,
|
||||
} from '@baota/naive-ui/hooks'
|
||||
import { useError } from '@baota/hooks/error'
|
||||
import { isDomain } from '@baota/utils/business'
|
||||
import { isDomain, isIp, isPort } from '@baota/utils/business'
|
||||
import { $t } from '@locales/index'
|
||||
|
||||
// Store和组件
|
||||
|
@ -335,6 +335,61 @@ export const useMonitorFormController = (data: UpdateSiteMonitorParams | null =
|
|||
}),
|
||||
])
|
||||
|
||||
/**
|
||||
* 验证输入是否合法域名或 IP 地址
|
||||
*/
|
||||
function isValidHost(host: string): boolean {
|
||||
if (!host?.trim()) return false;
|
||||
|
||||
const trimmedHost = host.trim();
|
||||
let hostPart: string;
|
||||
let portPart: string | undefined;
|
||||
|
||||
// 分离主机和端口部分
|
||||
if (trimmedHost.startsWith('[')) {
|
||||
// IPv6 地址(可能带端口)
|
||||
const closingBracketIndex = trimmedHost.indexOf(']');
|
||||
// 缺少闭合括号
|
||||
if (closingBracketIndex === -1) {
|
||||
return false;
|
||||
}
|
||||
// 去掉 []
|
||||
hostPart = trimmedHost.slice(1, closingBracketIndex);
|
||||
const rest = trimmedHost.slice(closingBracketIndex + 1);
|
||||
|
||||
// 检查剩余部分(只能是 :端口 或空)
|
||||
if (rest) {
|
||||
// 非端口部分
|
||||
if (!rest.startsWith(':')) {
|
||||
return false;
|
||||
}
|
||||
portPart = rest.slice(1);
|
||||
}
|
||||
} else {
|
||||
// IPv4 或域名(可能带端口)
|
||||
const lastColonIndex = trimmedHost.lastIndexOf(':');
|
||||
if (lastColonIndex !== -1) {
|
||||
hostPart = trimmedHost.slice(0, lastColonIndex);
|
||||
portPart = trimmedHost.slice(lastColonIndex + 1);
|
||||
} else {
|
||||
hostPart = trimmedHost;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查主机部分(IPv4/IPv6/域名)
|
||||
const isHostValid = isIp(hostPart) || isDomain(hostPart);
|
||||
if (!isHostValid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查端口部分
|
||||
if (portPart !== undefined) {
|
||||
return isPort(portPart);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单验证规则
|
||||
*/
|
||||
|
@ -345,7 +400,7 @@ export const useMonitorFormController = (data: UpdateSiteMonitorParams | null =
|
|||
message: '请输入正确的域名',
|
||||
trigger: 'input',
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (!isDomain(value)) {
|
||||
if (!isValidHost(value)) {
|
||||
callback(new Error('请输入正确的域名'))
|
||||
} else {
|
||||
callback()
|
||||
|
|
Loading…
Reference in New Issue