diff --git a/db/task_scope.go b/db/task_scope.go index dee0c61..e3108eb 100644 --- a/db/task_scope.go +++ b/db/task_scope.go @@ -22,6 +22,19 @@ type TaskScope struct { Reason string `json:"reason,omitempty"` } +// stripHostPort drops a trailing :port from a host:port / ip:port / [ipv6]:port +// value, returning the bare host. Bare hosts, bare IPs (v4 or v6, whose colons make +// them ambiguous), and anything not in host:port form are returned unchanged. Scope +// is host/net based, so the port from a target like "10.0.188.136:3000" or +// "api.example.com:8080" is simply discarded rather than baked into the key. +func stripHostPort(v string) string { + v = strings.TrimSpace(v) + if host, _, err := net.SplitHostPort(v); err == nil { + return host + } + return v +} + // ipToHostCIDR turns a bare IP into its single-host CIDR (/32 or /128). "" if invalid. func ipToHostCIDR(ip string) string { ip = strings.TrimSpace(ip) @@ -132,7 +145,7 @@ func (s *AssetStore) AddAgentScope(taskID int64, kind, value, reason string) (Ta } ts.CompanyID = &comp.ID case "root_domain": - d := DomainKey(value) + d := DomainKey(stripHostPort(value)) root, _ := RootDomain(d) if root == "" { root = d @@ -142,7 +155,7 @@ func (s *AssetStore) AddAgentScope(taskID int64, kind, value, reason string) (Ta } ts.Domain = root case "subdomain": - d := DomainKey(value) + d := DomainKey(stripHostPort(value)) if d == "" { return ts, fmt.Errorf("无效子域: %s", value) } @@ -150,7 +163,7 @@ func (s *AssetStore) AddAgentScope(taskID int64, kind, value, reason string) (Ta case "ip", "cidr": v := value if !strings.Contains(v, "/") { - v = ipToHostCIDR(v) + v = ipToHostCIDR(stripHostPort(v)) ts.Kind = "ip" } else { ts.Kind = "cidr" diff --git a/db/task_scope_test.go b/db/task_scope_test.go new file mode 100644 index 0000000..ec74bfe --- /dev/null +++ b/db/task_scope_test.go @@ -0,0 +1,23 @@ +package db + +import "testing" + +// TestStripHostPort covers the ip:port / [ipv6]:port stripping used by the +// ip/cidr scope path so a target like "10.0.188.136:3000" no longer 404s. +func TestStripHostPort(t *testing.T) { + cases := []struct{ in, want string }{ + {"10.0.188.136:3000", "10.0.188.136"}, // the reported IP case + {"10.0.188.136", "10.0.188.136"}, // bare IPv4 unchanged + {"[2001:db8::1]:8080", "2001:db8::1"}, // bracketed IPv6 + port + {"2001:db8::1", "2001:db8::1"}, // bare IPv6 unchanged (has colons) + {" 1.2.3.4:80 ", "1.2.3.4"}, // trims surrounding space + {"example.com:443", "example.com"}, // domain + port → bare host + {"api.example.com:8080", "api.example.com"}, // subdomain + port + {"example.com", "example.com"}, // bare domain unchanged + } + for _, c := range cases { + if got := stripHostPort(c.in); got != c.want { + t.Errorf("stripHostPort(%q) = %q, want %q", c.in, got, c.want) + } + } +}