package products import ( "net/url" "regexp" "strings" "git.t5de.dev/t5de/t5de-proxy/internal/proxy" ) // Guard is the last check before a request goes to IMVU: one that still names a community product (a local ID the // proxy gave out, in its query or body, as an integer or a float) is refused, not sent. The interceptors take // community products out of every request known to carry them; Guard stops the ones not known yet, and logs them // so they can be handled. type Guard struct{ Products *Products } var localIDPattern = regexp.MustCompile(`(?:^|[^0-9.])(2[0-9]{9})(?:\.0+)?(?:[^0-9.]|$)`) func (g Guard) Intercept(x *proxy.Exchange) error { if x.Response != nil || !strings.HasSuffix(strings.ToLower(x.URL.Hostname()), ".imvu.com") { return nil } query, _ := url.QueryUnescape(x.URL.RawQuery) for _, text := range []string{query, x.URL.Path, string(x.Body)} { for _, m := range localIDPattern.FindAllStringSubmatch(text, -1) { id, ok := parseID(m[1]) if ok && IsCommunity(id) && g.Products.given(id) { g.Products.logf("products: refused a request to %s%s: it names community product %d", x.URL.Host, x.URL.Path, id) x.Response = localResponse(403, "application/json", []byte(`{"error":"t5de: community products stay off IMVU"}`)) return nil } } } return nil } // given reports whether a local ID was given to a product. func (p *Products) given(local int64) bool { _, ok := p.state.productID(local) return ok }