package main import ( "context" "encoding/json" "os" "fmt" "strings" "bufio" "regexp" "io" "log" "net/http" "net/http/cookiejar" "net/url" "strconv" ) const ( READ_LIMIT int64 = 128 * 1024 ) type Auth struct { User string `json:"user"` Password string `json:"password"` Code string `json:"code"` } func main() { a := Auth{} err := json.NewDecoder(os.Stdin).Decode(&a) if err != nil { log.Fatal(err) } var PTransport http.RoundTripper = &http.Transport{Proxy: http.ProxyFromEnvironment} cli := client{ hc: http.DefaultClient, auth: a, } cli.hc.Transport = PTransport cli.hc.Jar, err = cookiejar.New(nil) if err != nil { log.Fatal(err) } err = cli.matchingPort() if err != nil { log.Fatal(err) } } type client struct { hc *http.Client auth Auth } func (c *client) matchingPort() error { ctx := context.Background() req, err := http.NewRequestWithContext(ctx, "GET", "https://windscribe.com/login", nil) if err != nil { return err } fillReq(req) req.Header.Set("Accept", "*/*") _, err = c.hc.Do(req) if err != nil { return err } csrf, err := c.getCSRF(ctx) if err != nil { return err } err = c.doInit(ctx) if err != nil { return err } values := url.Values{ "login": []string{"1"}, "upgrade": []string{"0"}, "csrf_time": []string{fmt.Sprint(csrf.Time)}, "csrf_token": []string{csrf.Token}, "username": []string{c.auth.User}, "password": []string{c.auth.Password}, "code": []string{c.auth.Code}, } req, err = http.NewRequestWithContext(ctx, "POST", "https://windscribe.com/login", strings.NewReader(values.Encode())) if err != nil { return err } fillReq(req) resp, err := c.hc.Do(req) if err != nil { return err } if resp.StatusCode != 302 { return fmt.Errorf("login failed %d", resp.StatusCode) } csrf, err = c.getCSRFfromBody(ctx, resp.Body) if err != nil { return err } cleanupBody(resp.Body) ephVals := url.Values{ "port": []string{""}, "ctime": []string{fmt.Sprint(csrf.Time)}, "ctoken": []string{csrf.Token}, } req, err = http.NewRequestWithContext(ctx, "POST", "https://windscribe.com/staticips/postEphPort", strings.NewReader(ephVals.Encode())) if err != nil { return err } fillReq(req) req.Header.Set("referer", "https://windscribe.com/myaccount") resp, err = c.hc.Do(req) if err != nil { return err } io.Copy(os.Stderr, resp.Body) cleanupBody(resp.Body) return nil } func fillReq(r *http.Request) { r.Header.Set("Connection", "keep-alive") hdr := map[string]string{ "cache-control": `max-age=0`, "sec-ch-ua": `"Not/A)Brand";v="99", "Google Chrome";v="115", "Chromium";v="115"`, "sec-ch-ua-mobile": `?0`, "sec-ch-ua-platform": `"macOS"`, "origin": `https://windscribe.com`, "dnt": `1`, "upgrade-insecure-requests": `1`, "content-type": `application/x-www-form-urlencoded`, "user-agent": `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36`, "accept": `text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7`, "sec-fetch-site": `same-origin`, "sec-fetch-mode": `navigate`, "sec-fetch-user": `?1`, "sec-fetch-dest": `document`, "referer": `https://windscribe.com/login`, "accept-language": `en-US,en;q=0.9,fr;q=0.8`, "sec-gpc": `1`, } for k, v := range hdr { r.Header.Set(k, v) } } type CSRF struct { Token string `json:"csrf_token"` Time int `json:"csrf_time"` } 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 } func (c *client) doInit(ctx context.Context) (error) { req, err := http.NewRequestWithContext(ctx, "POST", "https://res.windscribe.com/res/init", strings.NewReader(url.Values{"wsref":[]string{"https://windscribe.com/"}}.Encode())) if err != nil { return err } req.Header.Set("Accept", "*/*") fillReq(req) resp, err := c.hc.Do(req) if err != nil { return err } cleanupBody(resp.Body) return nil } func cleanupBody(body io.ReadCloser) { io.Copy(io.Discard, &io.LimitedReader{ R: body, N: READ_LIMIT, }) body.Close() }