From 44affae557009cdc5a0ef9eaba294d05d823da60 Mon Sep 17 00:00:00 2001 From: Mark Pashmfouroush Date: Fri, 29 Mar 2024 14:22:48 +0000 Subject: [PATCH] warp: refactor identity creation Signed-off-by: Mark Pashmfouroush --- app/app.go | 66 +---- warp/account.go | 660 ++++++++++++++----------------------------- wiresocks/scanner.go | 2 +- 3 files changed, 233 insertions(+), 495 deletions(-) diff --git a/app/app.go b/app/app.go index d4e0c9fdb..d40f52fe5 100644 --- a/app/app.go +++ b/app/app.go @@ -6,8 +6,6 @@ import ( "fmt" "log/slog" "net/netip" - "os" - "path/filepath" "github.com/bepass-org/warp-plus/psiphon" "github.com/bepass-org/warp-plus/warp" @@ -39,18 +37,6 @@ func RunWarp(ctx context.Context, l *slog.Logger, opts WarpOptions) error { return errors.New("must provide country for psiphon") } - // create necessary file structures - if err := makeDirs(); err != nil { - return err - } - l.Debug("'primary' and 'secondary' directories are ready") - - // Change the current working directory to 'stuff' - if err := os.Chdir("stuff"); err != nil { - return fmt.Errorf("error changing to 'stuff' directory: %w", err) - } - l.Debug("Changed working directory to 'stuff'") - // create identities if err := createPrimaryAndSecondaryIdentities(l.With("subsystem", "warp/account"), opts.License); err != nil { return err @@ -94,7 +80,7 @@ func RunWarp(ctx context.Context, l *slog.Logger, opts WarpOptions) error { } func runWarp(ctx context.Context, l *slog.Logger, bind netip.AddrPort, endpoint string) error { - conf, err := wiresocks.ParseConfig("./primary/wgcf-profile.ini", endpoint) + conf, err := wiresocks.ParseConfig("./stuff/primary/wgcf-profile.ini", endpoint) if err != nil { return err } @@ -122,7 +108,7 @@ func runWarp(ctx context.Context, l *slog.Logger, bind netip.AddrPort, endpoint } func runWarpWithPsiphon(ctx context.Context, l *slog.Logger, bind netip.AddrPort, endpoint string, country string) error { - conf, err := wiresocks.ParseConfig("./primary/wgcf-profile.ini", endpoint) + conf, err := wiresocks.ParseConfig("./stuff/primary/wgcf-profile.ini", endpoint) if err != nil { return err } @@ -157,7 +143,7 @@ func runWarpWithPsiphon(ctx context.Context, l *slog.Logger, bind netip.AddrPort func runWarpInWarp(ctx context.Context, l *slog.Logger, bind netip.AddrPort, endpoints []string) error { // Run outer warp - conf, err := wiresocks.ParseConfig("./primary/wgcf-profile.ini", endpoints[0]) + conf, err := wiresocks.ParseConfig("./stuff/primary/wgcf-profile.ini", endpoints[0]) if err != nil { return err } @@ -181,7 +167,7 @@ func runWarpInWarp(ctx context.Context, l *slog.Logger, bind netip.AddrPort, end } // Run inner warp - conf, err = wiresocks.ParseConfig("./secondary/wgcf-profile.ini", addr.String()) + conf, err = wiresocks.ParseConfig("./stuff/secondary/wgcf-profile.ini", addr.String()) if err != nil { return err } @@ -208,43 +194,17 @@ func runWarpInWarp(ctx context.Context, l *slog.Logger, bind netip.AddrPort, end func createPrimaryAndSecondaryIdentities(l *slog.Logger, license string) error { // make primary identity - warp.UpdatePath("./primary") - if !warp.CheckProfileExists(license) { - err := warp.LoadOrCreateIdentity(l, license) - if err != nil { - return err - } - } - // make secondary - warp.UpdatePath("./secondary") - if !warp.CheckProfileExists(license) { - err := warp.LoadOrCreateIdentity(l, license) - if err != nil { - return err - } - } - return nil -} - -func makeDirs() error { - stuffDir := "stuff" - primaryDir := "primary" - secondaryDir := "secondary" - - // Check if 'stuff' directory exists, if not create it - if _, err := os.Stat(stuffDir); os.IsNotExist(err) { - if err := os.Mkdir(stuffDir, 0o755); err != nil { - return fmt.Errorf("error creating 'stuff' directory: %w", err) - } + err := warp.LoadOrCreateIdentity(l, "./stuff/primary", license) + if err != nil { + l.Error("couldn't load primary warp identity") + return err } - // Create 'primary' and 'secondary' directories if they don't exist - for _, dir := range []string{primaryDir, secondaryDir} { - if _, err := os.Stat(filepath.Join(stuffDir, dir)); os.IsNotExist(err) { - if err := os.Mkdir(filepath.Join(stuffDir, dir), 0o755); err != nil { - return fmt.Errorf("error creating '%s' directory: %w", dir, err) - } - } + // make secondary + err = warp.LoadOrCreateIdentity(l, "./stuff/secondary", license) + if err != nil { + l.Error("couldn't load secondary warp identity") + return err } return nil diff --git a/warp/account.go b/warp/account.go index 5b0b7d35d..16d4a5ce0 100644 --- a/warp/account.go +++ b/warp/account.go @@ -4,22 +4,20 @@ import ( "bytes" "context" "encoding/json" - "errors" "fmt" "io" "log/slog" "net" "net/http" "os" + "path/filepath" "time" ) const ( - apiVersion = "v0a1922" - apiURL = "https://api.cloudflareclient.com" - regURL = apiURL + "/" + apiVersion + "/reg" - _identityFile = "wgcf-identity.json" - _profileFile = "wgcf-profile.ini" + apiVersion = "v0a3596" + apiURL = "https://api.cloudflareclient.com" + regURL = apiURL + "/" + apiVersion + "/reg" ) var ( @@ -32,30 +30,80 @@ var ( client = makeClient() ) -type AccountData struct { - AccountID string `json:"account_id"` - AccessToken string `json:"access_token"` - PrivateKey string `json:"private_key"` - LicenseKey string `json:"license_key"` +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 ConfigurationData struct { - LocalAddressIPv4 string `json:"local_address_ipv4"` - LocalAddressIPv6 string `json:"local_address_ipv6"` - EndpointAddressHost string `json:"endpoint_address_host"` - EndpointAddressIPv4 string `json:"endpoint_address_ipv4"` - EndpointAddressIPv6 string `json:"endpoint_address_ipv6"` - EndpointPublicKey string `json:"endpoint_public_key"` - WarpEnabled bool `json:"warp_enabled"` - AccountType string `json:"account_type"` - WarpPlusEnabled bool `json:"warp_plus_enabled"` - LicenseKeyUpdated bool `json:"license_key_updated"` +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.3-1922", + "CF-Client-Version": "a-6.30-3596", } } @@ -80,120 +128,64 @@ func makeClient() *http.Client { } } -func MergeMaps(maps ...map[string]string) map[string]string { - out := make(map[string]string) - - for _, m := range maps { - for k, v := range m { - out[k] = v - } - } - - return out -} - -func getConfigURL(accountID string) string { - return fmt.Sprintf("%s/%s", regURL, accountID) -} - -func getAccountURL(accountID string) string { - return fmt.Sprintf("%s/account", getConfigURL(accountID)) -} - -func getDevicesURL(accountID string) string { - return fmt.Sprintf("%s/devices", getAccountURL(accountID)) -} - -func getAccountRegURL(accountID, deviceToken string) string { - return fmt.Sprintf("%s/reg/%s", getAccountURL(accountID), deviceToken) -} - -func getTimestamp() string { - timestamp := time.Now().Format(time.RFC3339Nano) - return timestamp -} - -func genKeyPair() (string, string, error) { - // Generate private key - priv, err := GeneratePrivateKey() - if err != nil { - return "", "", err - } - privateKey := priv.String() - publicKey := priv.PublicKey().String() - return privateKey, publicKey, nil -} - -func doRegister() (*AccountData, error) { - timestamp := getTimestamp() - privateKey, publicKey, err := genKeyPair() - if err != nil { - return nil, err - } +func doRegister(publicKey string) (Identity, error) { data := map[string]interface{}{ - "install_id": "", - "fcm_token": "", - "tos": timestamp, - "key": publicKey, - "type": "Android", - "model": "PC", - "locale": "en_US", + "install_id": "", + "fcm_token": "", + "tos": time.Now().Format(time.RFC3339Nano), + "key": publicKey, + "type": "Android", + "model": "PC", + "locale": "en_US", + "warp_enabled": true, } - headers := map[string]string{ - "Content-Type": "application/json; charset=UTF-8", + jsonBody, err := json.Marshal(data) + if err != nil { + return Identity{}, err } - jsonBody, _ := json.Marshal(data) - req, err := http.NewRequest("POST", regURL, bytes.NewBuffer(jsonBody)) if err != nil { - return nil, err + return Identity{}, err } // Set headers - for k, v := range MergeMaps(defaultHeaders, headers) { + for k, v := range defaultHeaders { req.Header.Set(k, v) } // Create HTTP client and execute request - response, err := client.Do(req) + resp, err := client.Do(req) if err != nil { - return nil, err + return Identity{}, err } + defer resp.Body.Close() // convert response to byte array - responseData, err := io.ReadAll(response.Body) + responseData, err := io.ReadAll(resp.Body) if err != nil { - return nil, err + return Identity{}, err } - var rspData interface{} - + var rspData = Identity{} err = json.Unmarshal(responseData, &rspData) if err != nil { - return nil, err + return Identity{}, err } - m := rspData.(map[string]interface{}) - - return &AccountData{ - AccountID: m["id"].(string), - AccessToken: m["token"].(string), - PrivateKey: privateKey, - LicenseKey: m["account"].(map[string]interface{})["license"].(string), - }, nil + return rspData, nil } -func saveIdentity(accountData *AccountData, identityPath string) error { - file, err := os.Create(identityPath) +func saveIdentity(a Identity, path string) error { + file, err := os.Create(filepath.Join(path, identityFile)) if err != nil { return err } encoder := json.NewEncoder(file) - encoder.SetIndent("", " ") - err = encoder.Encode(accountData) + encoder.SetIndent("", " ") + err = encoder.Encode(a) if err != nil { return err } @@ -201,365 +193,134 @@ func saveIdentity(accountData *AccountData, identityPath string) error { return file.Close() } -func loadIdentity(identityPath string) (accountData *AccountData, err error) { - file, err := os.Open(identityPath) +func updateLicenseKey(accountID, accessToken, license string) (IdentityAccount, error) { + jsonData, err := json.Marshal(map[string]string{"license": license}) if err != nil { - return nil, err + return IdentityAccount{}, err } - defer file.Close() - - accountData = &AccountData{} - decoder := json.NewDecoder(file) - err = decoder.Decode(&accountData) - if err != nil { - return nil, err - } - - return accountData, nil -} - -func enableWarp(accountData *AccountData) error { - data := map[string]interface{}{ - "warp_enabled": true, - } - - jsonData, _ := json.Marshal(data) - url := getConfigURL(accountData.AccountID) + url := fmt.Sprintf("%s/%s/account", regURL, accountID) req, err := http.NewRequest("PATCH", url, bytes.NewBuffer(jsonData)) if err != nil { - return err - } - - // Set headers - headers := map[string]string{ - "Authorization": "Bearer " + accountData.AccessToken, - "Content-Type": "application/json; charset=UTF-8", + return IdentityAccount{}, err } - for k, v := range MergeMaps(defaultHeaders, headers) { + 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 err + return IdentityAccount{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return fmt.Errorf("error enabling WARP, status %d", resp.StatusCode) - } - - var response map[string]interface{} - err = json.NewDecoder(resp.Body).Decode(&response) - if err != nil { - return err - } - - if !response["warp_enabled"].(bool) { - return errors.New("warp not enabled") - } - - return nil -} - -func getServerConf(accountData *AccountData) (*ConfigurationData, error) { - req, err := http.NewRequest("GET", getConfigURL(accountData.AccountID), nil) - if err != nil { - return nil, err - } - - // Set headers - headers := map[string]string{ - "Authorization": "Bearer " + accountData.AccessToken, - "Content-Type": "application/json; charset=UTF-8", - } - - for k, v := range MergeMaps(defaultHeaders, headers) { - req.Header.Set(k, v) - } - - resp, err := client.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("error getting config, status %d", resp.StatusCode) - } - - var response map[string]interface{} - err = json.NewDecoder(resp.Body).Decode(&response) - if err != nil { - return nil, err - } - - addresses := response["config"].(map[string]interface{})["interface"].(map[string]interface{})["addresses"] - lv4 := addresses.(map[string]interface{})["v4"].(string) - lv6 := addresses.(map[string]interface{})["v6"].(string) - - peer := response["config"].(map[string]interface{})["peers"].([]interface{})[0].(map[string]interface{}) - publicKey := peer["public_key"].(string) - - endpoint := peer["endpoint"].(map[string]interface{}) - host := endpoint["host"].(string) - v4 := endpoint["v4"].(string) - v6 := endpoint["v6"].(string) - - account, ok := response["account"].(map[string]interface{}) - if !ok { - account = make(map[string]interface{}) - } - - warpEnabled := response["warp_enabled"].(bool) - - return &ConfigurationData{ - LocalAddressIPv4: lv4, - LocalAddressIPv6: lv6, - EndpointAddressHost: host, - EndpointAddressIPv4: v4, - EndpointAddressIPv6: v6, - EndpointPublicKey: publicKey, - WarpEnabled: warpEnabled, - AccountType: account["account_type"].(string), - WarpPlusEnabled: account["warp_plus"].(bool), - LicenseKeyUpdated: false, // omit for brevity - }, nil -} - -func updateLicenseKey(accountData *AccountData, confData *ConfigurationData) (bool, error) { - if confData.AccountType == "free" && accountData.LicenseKey != "" { - - data := map[string]interface{}{ - "license": accountData.LicenseKey, - } - - jsonData, _ := json.Marshal(data) - - url := getAccountURL(accountData.AccountID) - - req, err := http.NewRequest("PUT", url, bytes.NewBuffer(jsonData)) - if err != nil { - return false, err - } - - // Set headers - headers := map[string]string{ - "Authorization": "Bearer " + accountData.AccessToken, - "Content-Type": "application/json; charset=UTF-8", - } - - for k, v := range MergeMaps(defaultHeaders, headers) { - req.Header.Set(k, v) - } - - resp, err := client.Do(req) + s, err := io.ReadAll(resp.Body) if err != nil { - return false, err - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - s, _ := io.ReadAll(resp.Body) - return false, fmt.Errorf("activation error, status %d %s", resp.StatusCode, string(s)) + return IdentityAccount{}, err } - var activationResp map[string]interface{} - err = json.NewDecoder(resp.Body).Decode(&activationResp) - if err != nil { - return false, err - } - - return activationResp["warp_plus"].(bool), nil - - } else if confData.AccountType == "unlimited" { - return true, nil + return IdentityAccount{}, fmt.Errorf("activation error, status %d %s", resp.StatusCode, string(s)) } - return false, nil -} - -func getDeviceActive(accountData *AccountData) (bool, error) { - req, err := http.NewRequest("GET", getDevicesURL(accountData.AccountID), nil) + req, err = http.NewRequest("GET", url, nil) if err != nil { - return false, err + return IdentityAccount{}, err } - // Set headers - headers := map[string]string{ - "Authorization": "Bearer " + accountData.AccessToken, - "Accept": "application/json", - } - - for k, v := range MergeMaps(defaultHeaders, headers) { + for k, v := range headers { req.Header.Set(k, v) } - resp, err := client.Do(req) + resp1, err := client.Do(req) if err != nil { - return false, err + return IdentityAccount{}, err } - defer resp.Body.Close() + defer resp1.Body.Close() - if resp.StatusCode != http.StatusOK { - return false, fmt.Errorf("error getting devices, status %d", resp.StatusCode) - } - - var devices []map[string]interface{} - json.NewDecoder(resp.Body).Decode(&devices) - - for _, d := range devices { - if d["id"] == accountData.AccountID { - active := d["active"].(bool) - return active, nil + if resp1.StatusCode != http.StatusOK { + s, err := io.ReadAll(resp1.Body) + if err != nil { + return IdentityAccount{}, err } - } - - return false, nil -} -func setDeviceActive(accountData *AccountData, status bool) (bool, error) { - data := map[string]interface{}{ - "active": status, - } - - jsonData, _ := json.Marshal(data) - - url := getAccountRegURL(accountData.AccountID, accountData.AccountID) - - req, err := http.NewRequest("PATCH", url, bytes.NewBuffer(jsonData)) - if err != nil { - return false, err - } - - // Set headers - headers := map[string]string{ - "Authorization": "Bearer " + accountData.AccessToken, - "Accept": "application/json", - } - - for k, v := range MergeMaps(defaultHeaders, headers) { - req.Header.Set(k, v) + return IdentityAccount{}, fmt.Errorf("activation error, status %d %s", resp1.StatusCode, string(s)) } - resp, err := client.Do(req) + var activationResp1 = IdentityAccount{} + err = json.NewDecoder(resp1.Body).Decode(&activationResp1) if err != nil { - return false, err + return IdentityAccount{}, err } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return false, fmt.Errorf("error setting active status, status %d", resp.StatusCode) - } - - var devices []map[string]interface{} - json.NewDecoder(resp.Body).Decode(&devices) - - for _, d := range devices { - if d["id"] == accountData.AccountID { - return d["active"].(bool), nil - } - } - - return false, nil + return activationResp1, nil } -func getWireguardConfig(privateKey, address1, address2, publicKey, endpoint string) string { +func createConf(i Identity, path string) error { var buffer bytes.Buffer buffer.WriteString("[Interface]\n") - buffer.WriteString(fmt.Sprintf("PrivateKey = %s\n", privateKey)) - buffer.WriteString("DNS = 1.1.1.1, 1.0.0.1, 2606:4700:4700::1111, 2606:4700:4700::1001, 8.8.8.8, 8.8.4.4, 2001:4860:4860::8888, 2001:4860:4860::8844, 9.9.9.9, 149.112.112.112, 2620:fe::fe, 2620:fe::9\n") - buffer.WriteString(fmt.Sprintf("Address = %s/24\n", address1)) - buffer.WriteString(fmt.Sprintf("Address = %s/128\n", address2)) + buffer.WriteString(fmt.Sprintf("PrivateKey = %s\n", i.PrivateKey)) + buffer.WriteString("DNS = ") + buffer.WriteString("1.1.1.1, ") + buffer.WriteString("1.0.0.1, ") + buffer.WriteString("8.8.8.8, ") + buffer.WriteString("8.8.4.4, ") + buffer.WriteString("9.9.9.9, ") + buffer.WriteString("149.112.112.112, ") + buffer.WriteString("2606:4700:4700::1111, ") + buffer.WriteString("2606:4700:4700::1001, ") + buffer.WriteString("2001:4860:4860::8888, ") + buffer.WriteString("2001:4860:4860::8844, ") + buffer.WriteString("2620:fe::fe, ") + buffer.WriteString("2620:fe::9\n") + buffer.WriteString(fmt.Sprintf("Address = %s/24\n", i.Config.Interface.Addresses.V4)) + buffer.WriteString(fmt.Sprintf("Address = %s/128\n", i.Config.Interface.Addresses.V6)) buffer.WriteString("[Peer]\n") - buffer.WriteString(fmt.Sprintf("PublicKey = %s\n", publicKey)) + buffer.WriteString(fmt.Sprintf("PublicKey = %s\n", i.Config.Peers[0].PublicKey)) buffer.WriteString("AllowedIPs = 0.0.0.0/0\n") buffer.WriteString("AllowedIPs = ::/0\n") - buffer.WriteString(fmt.Sprintf("Endpoint = %s\n", endpoint)) - - return buffer.String() -} - -func createConf(accountData *AccountData, confData *ConfigurationData) error { - config := getWireguardConfig(accountData.PrivateKey, confData.LocalAddressIPv4, - confData.LocalAddressIPv6, confData.EndpointPublicKey, confData.EndpointAddressHost) + buffer.WriteString(fmt.Sprintf("Endpoint = %s\n", i.Config.Peers[0].Endpoint.Host)) - return os.WriteFile(profileFile, []byte(config), 0o600) + return os.WriteFile(filepath.Join(path, profileFile), buffer.Bytes(), 0o600) } -func LoadOrCreateIdentity(l *slog.Logger, license string) error { - var accountData *AccountData - - if _, err := os.Stat(identityFile); os.IsNotExist(err) { - l.Info("creating new identity") - accountData, err = doRegister() - if err != nil { +func LoadOrCreateIdentity(l *slog.Logger, path, license string) error { + i, err := LoadIdentity(path) + if err != nil { + l.Info("failed to load identity", "path", path, "error", err) + if err := os.RemoveAll(path); err != nil { return err } - accountData.LicenseKey = license - saveIdentity(accountData, identityFile) - } else { - l.Info("loading existing identity") - accountData, err = loadIdentity(identityFile) - if err != nil { + if err := os.MkdirAll(path, os.ModePerm); err != nil { return err } - } - - l.Info("getting server configuration") - confData, err := getServerConf(accountData) - if err != nil { - return err - } - - // updating license key - l.Info("updating account license key") - result, err := updateLicenseKey(accountData, confData) - if err != nil { - return err - } - if result { - confData, err = getServerConf(accountData) + i, err = CreateIdentity(l, path, license) if err != nil { return err } } - deviceStatus, err := getDeviceActive(accountData) - if err != nil { - return err - } - if !deviceStatus { - l.Warn("device is not registered to the account") - } - - if confData.WarpPlusEnabled && !deviceStatus { - l.Info("enabling device") - deviceStatus, _ = setDeviceActive(accountData, true) - } - - if !confData.WarpEnabled { - l.Info("enabling Warp") - err := enableWarp(accountData) + if license != "" && i.Account.License != license { + l.Info("license recreating identity with new license") + if err := os.RemoveAll(path); err != nil { + return err + } + if err := os.MkdirAll(path, os.ModePerm); err != nil { + return err + } + i, err = CreateIdentity(l, path, license) if err != nil { return err } - confData.WarpEnabled = true } - l.Info( - "Creating WireGuard configuration", - "device-active", deviceStatus, - "account-type", confData.AccountType, - "warp", confData.WarpEnabled, - "warp+", confData.WarpPlusEnabled, - ) - err = createConf(accountData, confData) + err = createConf(i, path) if err != nil { return fmt.Errorf("unable to enable write config file: %w", err) } @@ -568,74 +329,91 @@ func LoadOrCreateIdentity(l *slog.Logger, license string) error { return nil } -func fileExist(f string) bool { - if _, err := os.Stat(f); os.IsNotExist(err) { - return false +func LoadIdentity(path string) (Identity, error) { + // If either of the identity or profile files doesn't exist. + identityPath := filepath.Join(path, identityFile) + _, err := os.Stat(identityPath) + if err != nil { + return Identity{}, err } - return true -} -func removeFile(f string) { - if fileExist(f) { - _ = os.Remove(f) + profilePath := filepath.Join(path, profileFile) + _, err = os.Stat(profilePath) + if err != nil { + return Identity{}, err } -} -func UpdatePath(path string) { - identityFile = path + "/" + _identityFile - profileFile = path + "/" + _profileFile + i := &Identity{} + + fileBytes, err := os.ReadFile(identityPath) + if err != nil { + return Identity{}, err + } + + err = json.Unmarshal(fileBytes, i) + if err != nil { + return Identity{}, err + } + + return *i, nil } -func CheckProfileExists(license string) bool { - isOk := true - if !fileExist(identityFile) || !fileExist(profileFile) { - isOk = false +func CreateIdentity(l *slog.Logger, path, license string) (Identity, error) { + priv, err := GeneratePrivateKey() + if err != nil { + return Identity{}, err } - ad := &AccountData{} // Read errors caught by unmarshal - if isOk { - fileBytes, _ := os.ReadFile(identityFile) - err := json.Unmarshal(fileBytes, ad) + privateKey, publicKey := priv.String(), priv.PublicKey().String() + + l.Info("creating new identity") + i, err := doRegister(publicKey) + if err != nil { + return Identity{}, err + } + + if license != "" { + l.Info("updating account license key") + ac, err := updateLicenseKey(i.ID, i.Token, license) if err != nil { - isOk = false - } else if license != "notset" && ad.LicenseKey != license { - isOk = false + return Identity{}, err } + i.Account = ac } - if !isOk { - removeFile(profileFile) - removeFile(identityFile) - } - return isOk -} -func RemoveDevice(l *slog.Logger, account AccountData) error { - headers := map[string]string{ - "Content-Type": "application/json", - "User-Agent": "okhttp/3.12.1", - "CF-Client-Version": "a-6.30-3596", - "Authorization": "Bearer " + account.AccessToken, + i.PrivateKey = privateKey + + err = saveIdentity(i, path) + if err != nil { + return Identity{}, err } - req, err := http.NewRequest("DELETE", "https://api.cloudflareclient.com/v0a3596/reg/"+account.AccountID, nil) + 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 } - // Set headers - for k, v := range MergeMaps(defaultHeaders, headers) { + headers := defaultHeaders + headers["Authorization"] = "Bearer " + accessToken + for k, v := range headers { req.Header.Set(k, v) } // Create HTTP client and execute request - response, err := client.Do(req) + resp, err := client.Do(req) if err != nil { l.Info("sending request to remote server", err) return err } + defer resp.Body.Close() - if response.StatusCode != 204 { - return fmt.Errorf("error in deleting account %d %s", response.StatusCode, response.Status) + if resp.StatusCode != 204 { + return fmt.Errorf("error in deleting account %d %s", resp.StatusCode, resp.Status) } return nil diff --git a/wiresocks/scanner.go b/wiresocks/scanner.go index 80e244696..3263b154d 100644 --- a/wiresocks/scanner.go +++ b/wiresocks/scanner.go @@ -19,7 +19,7 @@ type ScanOptions struct { } func RunScan(ctx context.Context, l *slog.Logger, opts ScanOptions) (result []ipscanner.IPInfo, err error) { - cfg, err := ini.Load("./primary/wgcf-profile.ini") + cfg, err := ini.Load("./stuff/primary/wgcf-profile.ini") if err != nil { return nil, fmt.Errorf("failed to read file: %w", err) }