Files
yovision/Sense/server/app/sense/onvif/policy.go

77 lines
1.8 KiB
Go

package onvif
import (
"context"
"errors"
"net"
"net/url"
"strings"
)
var (
ErrTargetNotAllowed = errors.New("目标地址不在获准网段内")
ErrAddressInvalid = errors.New("设备地址格式不正确")
)
type Policy struct{ Networks []*net.IPNet }
func ParsePolicy(value string) (Policy, error) {
var policy Policy
for _, item := range strings.Split(value, ",") {
item = strings.TrimSpace(item)
if item == "" {
continue
}
_, network, err := net.ParseCIDR(item)
if err != nil {
return Policy{}, ErrTargetNotAllowed
}
policy.Networks = append(policy.Networks, network)
}
if len(policy.Networks) == 0 {
return Policy{}, ErrTargetNotAllowed
}
return policy, nil
}
func (p Policy) ValidateURL(ctx context.Context, raw string, schemes ...string) (*url.URL, net.IP, error) {
u, err := url.Parse(strings.TrimSpace(raw))
if err != nil || u.Hostname() == "" || u.User != nil || u.Fragment != "" {
return nil, nil, ErrAddressInvalid
}
for key := range u.Query() {
lower := strings.ToLower(key)
for _, sensitive := range []string{"user", "password", "passwd", "token", "auth", "credential", "secret", "key"} {
if strings.Contains(lower, sensitive) {
return nil, nil, ErrAddressInvalid
}
}
}
allowedScheme := false
for _, scheme := range schemes {
if strings.EqualFold(u.Scheme, scheme) {
allowedScheme = true
}
}
if !allowedScheme {
return nil, nil, ErrAddressInvalid
}
addresses, err := net.DefaultResolver.LookupIP(ctx, "ip", u.Hostname())
if err != nil || len(addresses) == 0 {
return nil, nil, ErrTargetNotAllowed
}
for _, address := range addresses {
ok := false
for _, network := range p.Networks {
if network.Contains(address) {
ok = true
break
}
}
if !ok {
return nil, nil, ErrTargetNotAllowed
}
}
return u, addresses[0], nil
}