Files
phishingclub/backend/controller/ipdata.go
T
2026-10-01 20:25:18 +02:00

147 lines
3.3 KiB
Go

package controller
import (
"strconv"
"strings"
"github.com/gin-gonic/gin"
"github.com/phishingclub/phishingclub/ipdata"
"github.com/phishingclub/phishingclub/service"
)
// IPData is a controller for the country and ASN data packages
type IPData struct {
Common
IPDataService *service.IPData
}
// Status returns the state of both data packages
func (c *IPData) Status(g *gin.Context) {
session, _, ok := c.handleSession(g)
if !ok {
return
}
status, err := c.IPDataService.Status(g, session)
if ok := c.handleErrors(g, err); !ok {
return
}
c.Response.OK(g, gin.H{"packages": status})
}
// Download fetches and installs the package named in the path
func (c *IPData) Download(g *gin.Context) {
session, _, ok := c.handleSession(g)
if !ok {
return
}
kind := g.Param("kind")
err := c.IPDataService.Download(g, session, kind)
if ok := c.handleErrors(g, err); !ok {
return
}
c.Response.OK(g, nil)
}
// Remove deletes the installed package named in the path
func (c *IPData) Remove(g *gin.Context) {
session, _, ok := c.handleSession(g)
if !ok {
return
}
kind := g.Param("kind")
err := c.IPDataService.Remove(g, session, kind)
if ok := c.handleErrors(g, err); !ok {
return
}
c.Response.OK(g, nil)
}
// SearchASN returns ASNs matching the query for the filter typeahead
func (c *IPData) SearchASN(g *gin.Context) {
session, _, ok := c.handleSession(g)
if !ok {
return
}
if !c.handleGlobalAuthorization(g, session) {
return
}
q := g.Query("q")
limit := 25
if v := g.Query("limit"); v != "" {
if n, err := strconv.Atoi(v); err == nil {
limit = n
}
}
results := ipdata.Get().SearchASN(q, limit)
c.Response.OK(g, gin.H{"results": results})
}
// LookupASN returns the autonomous systems that announce the given IP address
func (c *IPData) LookupASN(g *gin.Context) {
session, _, ok := c.handleSession(g)
if !ok {
return
}
if !c.handleGlobalAuthorization(g, session) {
return
}
ip := g.Query("ip")
if ip == "" {
c.Response.BadRequest(g)
return
}
store := ipdata.Get()
results := store.LookupASNDetails(ip)
c.Response.OK(g, gin.H{
"ip": ip,
"available": store.ASNLoaded(),
"found": len(results) > 0,
"results": results,
})
}
// ResolveASNRequest is the body for resolving configured ASNs to names.
type ResolveASNRequest struct {
Asns []string `json:"asns"`
}
// ResolveASNs returns the details of the given ASNs that exist in the dataset.
// ASNs that are absent are left out, which lets the UI flag orphaned entries.
func (c *IPData) ResolveASNs(g *gin.Context) {
session, _, ok := c.handleSession(g)
if !ok {
return
}
if !c.handleGlobalAuthorization(g, session) {
return
}
var req ResolveASNRequest
if ok := c.handleParseRequest(g, &req); !ok {
return
}
nums := make([]uint32, 0, len(req.Asns))
for _, s := range req.Asns {
if n, ok := parseASNInput(s); ok {
nums = append(nums, n)
}
}
results := ipdata.Get().ResolveASNs(nums)
c.Response.OK(g, gin.H{"results": results})
}
// parseASNInput parses one ASN string with an optional AS or ASN prefix.
func parseASNInput(s string) (uint32, bool) {
v := strings.ToLower(strings.TrimSpace(s))
v = strings.TrimPrefix(v, "asn")
v = strings.TrimPrefix(v, "as")
v = strings.TrimSpace(v)
if v == "" {
return 0, false
}
n, err := strconv.ParseUint(v, 10, 32)
if err != nil {
return 0, false
}
return uint32(n), true
}