package windscribe import ( "bufio" "context" "encoding/json" "fmt" "io" "net/http" "regexp" "strconv" "strings" "time" ) const ( csrfExpire time.Duration = time.Second * 4 ) type CSRF struct { Token string `json:"csrf_token"` Time int `json:"csrf_time"` } func (c *client) CSRF(ctx context.Context) *CSRF { if c.csrf == nil || time.Now().Sub(time.Unix(int64(c.csrf.Time), 0)) > csrfExpire { var err error c.csrf, err = c.getCSRF(ctx) if err != nil { panic(err) } } return c.csrf } func (c *client) getCSRF(ctx context.Context) (*CSRF, error) { req, err := http.NewRequestWithContext(ctx, "POST", "https://res.windscribe.com/res/logintoken", strings.NewReader("")) if err != nil { return nil, err } fillReq(req) resp, err := c.hc.Do(req) if err != nil { return nil, err } var csrf CSRF decoder := json.NewDecoder(resp.Body) err = decoder.Decode(&csrf) if err != nil { return nil, err } cleanupBody(resp.Body) return &csrf, nil } var csrfRE = regexp.MustCompile(`^\s*csrf_(time|token) = '?([0-9a-f]+)'?;\s*$`) func (c *client) getCSRFfromBody(ctx context.Context, body io.Reader) (*CSRF, error) { csrf := CSRF{} scan := bufio.NewScanner(body) for scan.Scan() { ln := scan.Text() m := csrfRE.FindStringSubmatch(ln) if len(m) == 3 { var err error switch m[1] { case "time": csrf.Time, err = strconv.Atoi(m[2]) if err != nil { return nil, err } case "token": csrf.Token = m[2] } } } if err := scan.Err(); err != nil { return nil, err } if csrf.Token == "" || csrf.Time == 0 { return nil, fmt.Errorf("getCSRFfromBody: csrf is %+v", csrf) } return &csrf, nil }