94 lines
1.6 KiB
Go
94 lines
1.6 KiB
Go
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
|
|
}
|