Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

warp: rewrite API functions #110

Merged
merged 1 commit into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 0 additions & 24 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

"github.com/bepass-org/warp-plus/iputils"
"github.com/bepass-org/warp-plus/psiphon"
"github.com/bepass-org/warp-plus/warp"
"github.com/bepass-org/warp-plus/wiresocks"
"github.com/go-ini/ini"
)
Expand Down Expand Up @@ -58,11 +57,6 @@ func RunWarp(ctx context.Context, l *slog.Logger, opts WarpOptions) error {
return errors.New("can't use psiphon and tun at the same time")
}

// create identities
if err := createPrimaryAndSecondaryIdentities(l.With("subsystem", "warp/account"), opts); err != nil {
return err
}

// Decide Working Scenario
endpoints := []string{opts.Endpoint, opts.Endpoint}

Expand Down Expand Up @@ -391,21 +385,3 @@ func runWarpWithPsiphon(ctx context.Context, l *slog.Logger, opts WarpOptions, e
l.Info("serving proxy", "address", opts.Bind)
return nil
}

func createPrimaryAndSecondaryIdentities(l *slog.Logger, opts WarpOptions) error {
// make primary identity
err := warp.LoadOrCreateIdentity(l, path.Join(opts.CacheDir, "primary"), opts.License)
if err != nil {
l.Error("couldn't load primary warp identity")
return err
}

// make secondary
err = warp.LoadOrCreateIdentity(l, path.Join(opts.CacheDir, "secondary"), opts.License)
if err != nil {
l.Error("couldn't load secondary warp identity")
return err
}

return nil
}
23 changes: 23 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@ func main() {
opts.Endpoint = addrPort.String()
}

// create identities
if err := createPrimaryAndSecondaryIdentities(l.With("subsystem", "warp/account"), opts); err != nil {
fatal(l, err)
}

ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
go func() {
if err := app.RunWarp(ctx, l, opts); err != nil {
Expand All @@ -193,6 +198,24 @@ func main() {
<-ctx.Done()
}

func createPrimaryAndSecondaryIdentities(l *slog.Logger, opts app.WarpOptions) error {
// make primary identity
err := warp.LoadOrCreateIdentity(l, path.Join(opts.CacheDir, "primary"), opts.License)
if err != nil {
l.Error("couldn't load primary warp identity")
return err
}

// make secondary
err = warp.LoadOrCreateIdentity(l, path.Join(opts.CacheDir, "secondary"), opts.License)
if err != nil {
l.Error("couldn't load secondary warp identity")
return err
}

return nil
}

func fatal(l *slog.Logger, err error) {
l.Error(err.Error())
os.Exit(1)
Expand Down
262 changes: 2 additions & 260 deletions warp/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,182 +2,19 @@ package warp

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
"net"
"net/http"
"os"
"path/filepath"
"time"
)

const (
apiVersion = "v0a3596"
apiURL = "https://api.cloudflareclient.com"
regURL = apiURL + "/" + apiVersion + "/reg"
)

var (
identityFile = "wgcf-identity.json"
profileFile = "wgcf-profile.ini"
)

var (
defaultHeaders = makeDefaultHeaders()
client = makeClient()
)

type IdentityAccount struct {
Created string `json:"created"`
Updated string `json:"updated"`
License string `json:"license"`
PremiumData int64 `json:"premium_data"`
WarpPlus bool `json:"warp_plus"`
AccountType string `json:"account_type"`
ReferralRenewalCountdown int64 `json:"referral_renewal_countdown"`
Role string `json:"role"`
ID string `json:"id"`
Quota int64 `json:"quota"`
Usage int64 `json:"usage"`
ReferralCount int64 `json:"referral_count"`
TTL string `json:"ttl"`
}

type IdentityConfigPeerEndpoint struct {
V4 string `json:"v4"`
V6 string `json:"v6"`
Host string `json:"host"`
Ports []uint16 `json:"ports"`
}

type IdentityConfigPeer struct {
PublicKey string `json:"public_key"`
Endpoint IdentityConfigPeerEndpoint `json:"endpoint"`
}

type IdentityConfigInterfaceAddresses struct {
V4 string `json:"v4"`
V6 string `json:"v6"`
}

type IdentityConfigInterface struct {
Addresses IdentityConfigInterfaceAddresses `json:"addresses"`
}
type IdentityConfigServices struct {
HTTPProxy string `json:"http_proxy"`
}

type IdentityConfig struct {
Peers []IdentityConfigPeer `json:"peers"`
Interface IdentityConfigInterface `json:"interface"`
Services IdentityConfigServices `json:"services"`
ClientID string `json:"client_id"`
}

type Identity struct {
PrivateKey string `json:"private_key"`
Key string `json:"key"`
Account IdentityAccount `json:"account"`
Place int64 `json:"place"`
FCMToken string `json:"fcm_token"`
Name string `json:"name"`
TOS string `json:"tos"`
Locale string `json:"locale"`
InstallID string `json:"install_id"`
WarpEnabled bool `json:"warp_enabled"`
Type string `json:"type"`
Model string `json:"model"`
Config IdentityConfig `json:"config"`
Token string `json:"token"`
Enabled bool `json:"enabled"`
ID string `json:"id"`
Created string `json:"created"`
Updated string `json:"updated"`
WaitlistEnabled bool `json:"waitlist_enabled"`
}

func makeDefaultHeaders() map[string]string {
return map[string]string{
"Content-Type": "application/json; charset=UTF-8",
"User-Agent": "okhttp/3.12.1",
"CF-Client-Version": "a-6.30-3596",
}
}

func makeClient() *http.Client {
// Create a custom dialer using the TLS config
plainDialer := &net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 5 * time.Second,
}
tlsDialer := Dialer{}
// Create a custom HTTP transport
transport := &http.Transport{
DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return tlsDialer.TLSDial(plainDialer, network, addr)
},
}

// Create a custom HTTP client using the transport
return &http.Client{
Transport: transport,
// Other client configurations can be added here
}
}

func doRegister(publicKey string) (Identity, error) {
data := map[string]interface{}{
"install_id": "",
"fcm_token": "",
"tos": time.Now().Format(time.RFC3339Nano),
"key": publicKey,
"type": "Android",
"model": "PC",
"locale": "en_US",
"warp_enabled": true,
}

jsonBody, err := json.Marshal(data)
if err != nil {
return Identity{}, err
}

req, err := http.NewRequest("POST", regURL, bytes.NewBuffer(jsonBody))
if err != nil {
return Identity{}, err
}

// Set headers
for k, v := range defaultHeaders {
req.Header.Set(k, v)
}

// Create HTTP client and execute request
resp, err := client.Do(req)
if err != nil {
return Identity{}, err
}
defer resp.Body.Close()

// convert response to byte array
responseData, err := io.ReadAll(resp.Body)
if err != nil {
return Identity{}, err
}

var rspData = Identity{}
err = json.Unmarshal(responseData, &rspData)
if err != nil {
return Identity{}, err
}

return rspData, nil
}

func saveIdentity(a Identity, path string) error {
file, err := os.Create(filepath.Join(path, identityFile))
if err != nil {
Expand All @@ -194,73 +31,6 @@ func saveIdentity(a Identity, path string) error {
return file.Close()
}

func updateLicenseKey(accountID, accessToken, license string) (IdentityAccount, error) {
jsonData, err := json.Marshal(map[string]string{"license": license})
if err != nil {
return IdentityAccount{}, err
}

url := fmt.Sprintf("%s/%s/account", regURL, accountID)

req, err := http.NewRequest("PATCH", url, bytes.NewBuffer(jsonData))
if err != nil {
return IdentityAccount{}, err
}

headers := defaultHeaders
headers["Authorization"] = "Bearer " + accessToken
for k, v := range headers {
req.Header.Set(k, v)
}

resp, err := client.Do(req)
if err != nil {
return IdentityAccount{}, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
s, err := io.ReadAll(resp.Body)
if err != nil {
return IdentityAccount{}, err
}

return IdentityAccount{}, fmt.Errorf("activation error, status %d %s", resp.StatusCode, string(s))
}

req, err = http.NewRequest("GET", url, nil)
if err != nil {
return IdentityAccount{}, err
}

for k, v := range headers {
req.Header.Set(k, v)
}

resp1, err := client.Do(req)
if err != nil {
return IdentityAccount{}, err
}
defer resp1.Body.Close()

if resp1.StatusCode != http.StatusOK {
s, err := io.ReadAll(resp1.Body)
if err != nil {
return IdentityAccount{}, err
}

return IdentityAccount{}, fmt.Errorf("activation error, status %d %s", resp1.StatusCode, string(s))
}

var activationResp1 = IdentityAccount{}
err = json.NewDecoder(resp1.Body).Decode(&activationResp1)
if err != nil {
return IdentityAccount{}, err
}

return activationResp1, nil
}

func createConf(i Identity, path string) error {
var buffer bytes.Buffer

Expand Down Expand Up @@ -360,14 +130,14 @@ func CreateIdentity(l *slog.Logger, path, license string) (Identity, error) {
privateKey, publicKey := priv.String(), priv.PublicKey().String()

l.Info("creating new identity")
i, err := doRegister(publicKey)
i, err := Register(publicKey)
if err != nil {
return Identity{}, err
}

if license != "" {
l.Info("updating account license key")
ac, err := updateLicenseKey(i.ID, i.Token, license)
ac, err := UpdateAccount(i.Token, i.ID, license)
if err != nil {
return Identity{}, err
}
Expand All @@ -383,31 +153,3 @@ func CreateIdentity(l *slog.Logger, path, license string) (Identity, error) {

return i, nil
}

func RemoveDevice(l *slog.Logger, accountID, accessToken string) error {
url := fmt.Sprintf("%s/%s", regURL, accountID)
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
return err
}

headers := defaultHeaders
headers["Authorization"] = "Bearer " + accessToken
for k, v := range headers {
req.Header.Set(k, v)
}

// Create HTTP client and execute request
resp, err := client.Do(req)
if err != nil {
l.Info("sending request to remote server", err)
return err
}
defer resp.Body.Close()

if resp.StatusCode != 204 {
return fmt.Errorf("error in deleting account %d %s", resp.StatusCode, resp.Status)
}

return nil
}
Loading