mirror of
https://github.com/Snawoot/windscribe-proxy.git
synced 2026-04-02 22:38:19 +00:00
19
main.go
19
main.go
@@ -58,6 +58,8 @@ type CLIArgs struct {
|
||||
caFile string
|
||||
clientAuthSecret string
|
||||
stateFile string
|
||||
username string
|
||||
password string
|
||||
}
|
||||
|
||||
func parse_args() CLIArgs {
|
||||
@@ -82,6 +84,8 @@ func parse_args() CLIArgs {
|
||||
flag.StringVar(&args.clientAuthSecret, "auth-secret", DEFAULT_CLIENT_AUTH_SECRET, "client auth secret")
|
||||
flag.StringVar(&args.stateFile, "state-file", "wndstate.json", "file name used to persist "+
|
||||
"Windscribe API client state")
|
||||
flag.StringVar(&args.username, "username", "", "username for login")
|
||||
flag.StringVar(&args.password, "password", "", "password for login")
|
||||
flag.Parse()
|
||||
if args.listLocations && args.listProxies {
|
||||
arg_fail("list-locations and list-proxies flags are mutually exclusive")
|
||||
@@ -187,7 +191,7 @@ func run() int {
|
||||
state, err := loadState(args.stateFile)
|
||||
if err != nil {
|
||||
mainLogger.Warning("Failed to load client state: %v. Performing cold init...", err)
|
||||
err = coldInit(wndc, args.timeout)
|
||||
err = coldInit(wndc, args.username, args.password, args.timeout)
|
||||
if err != nil {
|
||||
mainLogger.Critical("Cold init failed: %v", err)
|
||||
return 9
|
||||
@@ -367,19 +371,12 @@ func saveState(filename string, state *wndclient.WndClientState) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func coldInit(wndc *wndclient.WndClient, timeout time.Duration) error {
|
||||
func coldInit(wndc *wndclient.WndClient, username, password string, timeout time.Duration) error {
|
||||
ctx, cl := context.WithTimeout(context.Background(), timeout)
|
||||
err := wndc.RegisterToken(ctx)
|
||||
err := wndc.Session(ctx, username, password)
|
||||
cl()
|
||||
if err != nil {
|
||||
return fmt.Errorf("RegisterToken call failed: %w", err)
|
||||
}
|
||||
|
||||
ctx, cl = context.WithTimeout(context.Background(), timeout)
|
||||
err = wndc.Users(ctx)
|
||||
cl()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Users call failed: %w", err)
|
||||
return fmt.Errorf("Session call failed: %w", err)
|
||||
}
|
||||
|
||||
ctx, cl = context.WithTimeout(context.Background(), timeout)
|
||||
|
||||
@@ -14,6 +14,24 @@ type RegisterTokenResponse struct {
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type SessionResponse struct {
|
||||
Data *struct {
|
||||
SessionAuthHash string `json:"session_auth_hash"`
|
||||
Username string `json:"username"`
|
||||
UserID string `json:"user_id"`
|
||||
TrafficUsed float64 `json:"traffic_used"`
|
||||
TrafficMax float64 `json:"traffic_max"`
|
||||
Status int `json:"status"`
|
||||
Email *string `json:"email"`
|
||||
EmailStatus int `json:"email_status"`
|
||||
BillingPlanID int64 `json:"billing_plan_id"`
|
||||
IsPremium int `json:"is_premium"`
|
||||
RegDate float64 `json:"reg_date"`
|
||||
LocationRevision int `json:"loc_rev"`
|
||||
LocationHash string `json:"loc_hash"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type UsersRequest struct {
|
||||
ClientAuthHash string `json:"client_auth_hash"`
|
||||
SessionType int `json:"session_type_id"`
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -30,16 +30,14 @@ const (
|
||||
var ErrNoDataInResponse = errors.New("no \"data\" key in response")
|
||||
|
||||
type WndEndpoints struct {
|
||||
RegisterToken string `json:"RegisterToken"`
|
||||
Users string `json:"Users"`
|
||||
Session string `json:"Session"`
|
||||
ServerList string `json:"serverlist"`
|
||||
ServerCredentials string `json:"ServerCredentials"`
|
||||
BestLocation string `json:"BestLocation"`
|
||||
}
|
||||
|
||||
var DefaultWndEndpoints = WndEndpoints{
|
||||
RegisterToken: "https://api.windscribe.com/RegToken",
|
||||
Users: "https://api.windscribe.com/Users",
|
||||
Session: "https://api.windscribe.com/Session",
|
||||
ServerList: "https://assets.windscribe.com/serverlist",
|
||||
ServerCredentials: "https://api.windscribe.com/ServerCredentials",
|
||||
BestLocation: "https://api.windscribe.com/BestLocation",
|
||||
@@ -59,7 +57,7 @@ var DefaultWndSettings = WndSettings{
|
||||
ClientAuthSecret: "952b4412f002315aa50751032fcaab03",
|
||||
Platform: "chrome",
|
||||
Type: "chrome",
|
||||
UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36",
|
||||
UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
|
||||
Origin: "chrome-extension://hnmpcagpplmpfojmgmnngilcnanddlhb",
|
||||
SessionType: SESSION_TYPE_EXT,
|
||||
Endpoints: DefaultWndEndpoints,
|
||||
@@ -104,49 +102,22 @@ func NewWndClient(transport http.RoundTripper) (*WndClient, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *WndClient) RegisterToken(ctx context.Context) error {
|
||||
func (c *WndClient) Session(ctx context.Context, username, password string) error {
|
||||
c.Mux.Lock()
|
||||
defer c.Mux.Unlock()
|
||||
|
||||
clientAuthHash, authTime := MakeAuthHash(c.State.Settings.ClientAuthSecret)
|
||||
input := RegisterTokenRequest{
|
||||
ClientAuthHash: clientAuthHash,
|
||||
Time: authTime,
|
||||
input := url.Values{
|
||||
"client_auth_hash": []string{clientAuthHash},
|
||||
"time": []string{strconv.FormatInt(authTime, 10)},
|
||||
"session_type_id": []string{strconv.FormatInt(SESSION_TYPE_EXT, 10)},
|
||||
"username": []string{username},
|
||||
"password": []string{password},
|
||||
}
|
||||
|
||||
var output RegisterTokenResponse
|
||||
var output SessionResponse
|
||||
|
||||
err := c.postJSON(ctx, c.State.Settings.Endpoints.RegisterToken, input, &output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if output.Data == nil {
|
||||
return ErrNoDataInResponse
|
||||
}
|
||||
|
||||
c.State.TokenID = output.Data.TokenID
|
||||
c.State.Token = output.Data.Token
|
||||
c.State.TokenSignature = output.Data.TokenSignature
|
||||
c.State.TokenSignatureTime = output.Data.TokenTime
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *WndClient) Users(ctx context.Context) error {
|
||||
c.Mux.Lock()
|
||||
defer c.Mux.Unlock()
|
||||
|
||||
clientAuthHash, authTime := MakeAuthHash(c.State.Settings.ClientAuthSecret)
|
||||
input := UsersRequest{
|
||||
ClientAuthHash: clientAuthHash,
|
||||
Time: authTime,
|
||||
SessionType: SESSION_TYPE_EXT,
|
||||
Token: c.State.Token,
|
||||
}
|
||||
|
||||
var output UsersResponse
|
||||
|
||||
err := c.postJSON(ctx, c.State.Settings.Endpoints.Users, input, &output)
|
||||
err := c.postForm(ctx, c.State.Settings.Endpoints.Session, input, &output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -301,6 +272,48 @@ func (c *WndClient) postJSON(ctx context.Context, endpoint string, input, output
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *WndClient) postForm(ctx context.Context, endpoint string, input url.Values, output interface{}) error {
|
||||
req, err := http.NewRequestWithContext(
|
||||
ctx,
|
||||
"POST",
|
||||
endpoint,
|
||||
strings.NewReader(input.Encode()),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.populateRequest(req)
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||
errBodyBytes, _ := ioutil.ReadAll(
|
||||
&io.LimitedReader{
|
||||
R: resp.Body,
|
||||
N: 1024,
|
||||
})
|
||||
defer resp.Body.Close()
|
||||
return fmt.Errorf("bad http status: %s, headers: %#v, body: %q",
|
||||
resp.Status, resp.Header, string(errBodyBytes))
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
err = decoder.Decode(output)
|
||||
cleanupBody(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *WndClient) GetProxyCredentials() (string, string) {
|
||||
c.Mux.Lock()
|
||||
defer c.Mux.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user