diff --git a/bskyweb/cmd/bskyweb/main.go b/bskyweb/cmd/bskyweb/main.go index d9235afd..3f46c4b0 100644 --- a/bskyweb/cmd/bskyweb/main.go +++ b/bskyweb/cmd/bskyweb/main.go @@ -60,6 +60,12 @@ func run(args []string) { Value: "", EnvVars: []string{"LINK_HOST"}, }, + &cli.StringFlag{ + Name: "ipcc-host", + Usage: "scheme, hostname, and port of ipcc service", + Value: "https://localhost:8730", + EnvVars: []string{"IPCC_HOST"}, + }, &cli.BoolFlag{ Name: "debug", Usage: "Enable debug mode", diff --git a/bskyweb/cmd/bskyweb/server.go b/bskyweb/cmd/bskyweb/server.go index 203ed62f..afd9247a 100644 --- a/bskyweb/cmd/bskyweb/server.go +++ b/bskyweb/cmd/bskyweb/server.go @@ -1,12 +1,17 @@ package main import ( + "bytes" "context" "crypto/subtle" + "crypto/tls" + "encoding/base64" + "encoding/json" "errors" "fmt" "io/fs" "net/http" + "net/netip" "net/url" "os" "os/signal" @@ -41,6 +46,7 @@ type Config struct { appviewHost string ogcardHost string linkHost string + ipccHost string } func serve(cctx *cli.Context) error { @@ -49,6 +55,7 @@ func serve(cctx *cli.Context) error { appviewHost := cctx.String("appview-host") ogcardHost := cctx.String("ogcard-host") linkHost := cctx.String("link-host") + ipccHost := cctx.String("ipcc-host") basicAuthPassword := cctx.String("basic-auth-password") // Echo @@ -91,6 +98,7 @@ func serve(cctx *cli.Context) error { appviewHost: appviewHost, ogcardHost: ogcardHost, linkHost: linkHost, + ipccHost: ipccHost, }, } @@ -261,6 +269,9 @@ func serve(cctx *cli.Context) error { e.GET("/starter-pack/:handleOrDID/:rkey", server.WebStarterPack) e.GET("/start/:handleOrDID/:rkey", server.WebStarterPack) + // ipcc + e.GET("/ipcc", server.WebIpCC) + if linkHost != "" { linkUrl, err := url.Parse(linkHost) if err != nil { @@ -520,3 +531,61 @@ func (srv *Server) WebProfile(c echo.Context) error { data["requestHost"] = req.Host return c.Render(http.StatusOK, "profile.html", data) } + +type IPCCRequest struct { + IP string `json:"ip"` +} +type IPCCResponse struct { + CC string `json:"countryCode"` +} + +func (srv *Server) WebIpCC(c echo.Context) error { + realIP := c.RealIP() + addr, err := netip.ParseAddr(realIP) + if err != nil { + log.Warnf("could not parse IP %q %s", realIP, err) + return c.JSON(400, IPCCResponse{}) + } + var request []byte + if addr.Is4() { + ip4 := addr.As4() + var dest [8]byte + base64.StdEncoding.Encode(dest[:], ip4[:]) + request, _ = json.Marshal(IPCCRequest{IP: string(dest[:])}) + } else if addr.Is6() { + ip6 := addr.As16() + var dest [24]byte + base64.StdEncoding.Encode(dest[:], ip6[:]) + request, _ = json.Marshal(IPCCRequest{IP: string(dest[:])}) + } + + ipccUrlBuilder, err := url.Parse(srv.cfg.ipccHost) + if err != nil { + log.Errorf("ipcc misconfigured bad url %s", err) + return c.JSON(500, IPCCResponse{}) + } + ipccUrlBuilder.Path = "ipccdata.IpCcService/Lookup" + ipccUrl := ipccUrlBuilder.String() + cl := http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + }, + } + postBodyReader := bytes.NewReader(request) + response, err := cl.Post(ipccUrl, "application/json", postBodyReader) + if err != nil { + log.Warnf("ipcc backend error %s", err) + return c.JSON(500, IPCCResponse{}) + } + defer response.Body.Close() + dec := json.NewDecoder(response.Body) + var outResponse IPCCResponse + err = dec.Decode(&outResponse) + if err != nil { + log.Warnf("ipcc bad response %s", err) + return c.JSON(500, IPCCResponse{}) + } + return c.JSON(200, outResponse) +}