CLI Client: Refactor HTTP request handling with retry logic and improve token refresh mechanism
- commit
- acce5868d6a8918d6c18518438ebff6999946f77
- author
- bamen · · 2024-09-12 09:44 UTC
- parent
- a0bdde0
- signature
- unsigned
5 files · +81 -27
M internal/cli/auth/device_flow.go +9 -9
| @@ -8,14 +8,14 @@ import ( | |||
| 8 | 8 | "net/url" | |
| 9 | 9 | "time" | |
| 10 | 10 | ||
| 11 | - | "github.com/bnema/gordon/internal/common" | |
| 11 | + | "github.com/bnema/gordon/internal/cli" | |
| 12 | 12 | ) | |
| 13 | 13 | ||
| 14 | - | func DeviceFlowAuth(config *common.Config) error { | |
| 14 | + | func DeviceFlowAuth(a *cli.App) error { | |
| 15 | 15 | fmt.Println("Starting device flow authentication...") | |
| 16 | 16 | ||
| 17 | 17 | // Request device code | |
| 18 | - | deviceCode, err := requestDeviceCode(config) | |
| 18 | + | deviceCode, err := requestDeviceCode(a) | |
| 19 | 19 | if err != nil { | |
| 20 | 20 | return fmt.Errorf("error requesting device code: %w", err) | |
| 21 | 21 | } | |
| @@ -28,20 +28,20 @@ func DeviceFlowAuth(config *common.Config) error { | |||
| 28 | 28 | interval = int(i) | |
| 29 | 29 | } | |
| 30 | 30 | ||
| 31 | - | token, err := pollForAccessToken(config, deviceCode["device_code"].(string), interval) | |
| 31 | + | token, err := pollForAccessToken(a, deviceCode["device_code"].(string), interval) | |
| 32 | 32 | if err != nil { | |
| 33 | 33 | return fmt.Errorf("error polling for access token: %w", err) | |
| 34 | 34 | } | |
| 35 | 35 | ||
| 36 | 36 | // Save the token | |
| 37 | - | config.SetToken(token) | |
| 37 | + | a.Config.SetToken(token) | |
| 38 | 38 | ||
| 39 | 39 | fmt.Println("Authentication successful!") | |
| 40 | 40 | return nil | |
| 41 | 41 | } | |
| 42 | 42 | ||
| 43 | - | func requestDeviceCode(config *common.Config) (map[string]interface{}, error) { | |
| 44 | - | resp, err := http.PostForm(config.GetBackendURL()+"/api/device/code", url.Values{}) | |
| 43 | + | func requestDeviceCode(a *cli.App) (map[string]interface{}, error) { | |
| 44 | + | resp, err := http.PostForm(a.Config.GetBackendURL()+"/api/device/code", url.Values{}) | |
| 45 | 45 | if err != nil { | |
| 46 | 46 | return nil, fmt.Errorf("error making request: %w", err) | |
| 47 | 47 | } | |
| @@ -72,12 +72,12 @@ func requestDeviceCode(config *common.Config) (map[string]interface{}, error) { | |||
| 72 | 72 | return deviceCode, nil | |
| 73 | 73 | } | |
| 74 | 74 | ||
| 75 | - | func pollForAccessToken(config *common.Config, deviceCode string, interval int) (string, error) { | |
| 75 | + | func pollForAccessToken(a *cli.App, deviceCode string, interval int) (string, error) { | |
| 76 | 76 | maxAttempts := 60 // Maximum number of attempts (5 minutes with 5-second intervals) | |
| 77 | 77 | for attempt := 0; attempt < maxAttempts; attempt++ { | |
| 78 | 78 | time.Sleep(time.Duration(interval) * time.Second) | |
| 79 | 79 | ||
| 80 | - | resp, err := http.PostForm(config.GetBackendURL()+"/api/device/token", url.Values{ | |
| 80 | + | resp, err := http.PostForm(a.Config.GetBackendURL()+"/api/device/token", url.Values{ | |
| 81 | 81 | "device_code": {deviceCode}, | |
| 82 | 82 | }) | |
| 83 | 83 | if err != nil { | |
| @@ -8,14 +8,14 @@ import ( | |||||
| 8 | "net/url" | 8 | "net/url" | ||
| 9 | "time" | 9 | "time" | ||
| 10 | 10 | ||||
| 11 | - | "github.com/bnema/gordon/internal/common" | 11 | + | "github.com/bnema/gordon/internal/cli" |
| 12 | ) | 12 | ) | ||
| 13 | 13 | ||||
| 14 | - | func DeviceFlowAuth(config *common.Config) error { | 14 | + | func DeviceFlowAuth(a *cli.App) error { |
| 15 | fmt.Println("Starting device flow authentication...") | 15 | fmt.Println("Starting device flow authentication...") | ||
| 16 | 16 | ||||
| 17 | // Request device code | 17 | // Request device code | ||
| 18 | - | deviceCode, err := requestDeviceCode(config) | 18 | + | deviceCode, err := requestDeviceCode(a) |
| 19 | if err != nil { | 19 | if err != nil { | ||
| 20 | return fmt.Errorf("error requesting device code: %w", err) | 20 | return fmt.Errorf("error requesting device code: %w", err) | ||
| 21 | } | 21 | } | ||
| @@ -28,20 +28,20 @@ func DeviceFlowAuth(config *common.Config) error { | |||||
| 28 | interval = int(i) | 28 | interval = int(i) | ||
| 29 | } | 29 | } | ||
| 30 | 30 | ||||
| 31 | - | token, err := pollForAccessToken(config, deviceCode["device_code"].(string), interval) | 31 | + | token, err := pollForAccessToken(a, deviceCode["device_code"].(string), interval) |
| 32 | if err != nil { | 32 | if err != nil { | ||
| 33 | return fmt.Errorf("error polling for access token: %w", err) | 33 | return fmt.Errorf("error polling for access token: %w", err) | ||
| 34 | } | 34 | } | ||
| 35 | 35 | ||||
| 36 | // Save the token | 36 | // Save the token | ||
| 37 | - | config.SetToken(token) | 37 | + | a.Config.SetToken(token) |
| 38 | 38 | ||||
| 39 | fmt.Println("Authentication successful!") | 39 | fmt.Println("Authentication successful!") | ||
| 40 | return nil | 40 | return nil | ||
| 41 | } | 41 | } | ||
| 42 | 42 | ||||
| 43 | - | func requestDeviceCode(config *common.Config) (map[string]interface{}, error) { | 43 | + | func requestDeviceCode(a *cli.App) (map[string]interface{}, error) { |
| 44 | - | resp, err := http.PostForm(config.GetBackendURL()+"/api/device/code", url.Values{}) | 44 | + | resp, err := http.PostForm(a.Config.GetBackendURL()+"/api/device/code", url.Values{}) |
| 45 | if err != nil { | 45 | if err != nil { | ||
| 46 | return nil, fmt.Errorf("error making request: %w", err) | 46 | return nil, fmt.Errorf("error making request: %w", err) | ||
| 47 | } | 47 | } | ||
| @@ -72,12 +72,12 @@ func requestDeviceCode(config *common.Config) (map[string]interface{}, error) { | |||||
| 72 | return deviceCode, nil | 72 | return deviceCode, nil | ||
| 73 | } | 73 | } | ||
| 74 | 74 | ||||
| 75 | - | func pollForAccessToken(config *common.Config, deviceCode string, interval int) (string, error) { | 75 | + | func pollForAccessToken(a *cli.App, deviceCode string, interval int) (string, error) { |
| 76 | maxAttempts := 60 // Maximum number of attempts (5 minutes with 5-second intervals) | 76 | maxAttempts := 60 // Maximum number of attempts (5 minutes with 5-second intervals) | ||
| 77 | for attempt := 0; attempt < maxAttempts; attempt++ { | 77 | for attempt := 0; attempt < maxAttempts; attempt++ { | ||
| 78 | time.Sleep(time.Duration(interval) * time.Second) | 78 | time.Sleep(time.Duration(interval) * time.Second) | ||
| 79 | 79 | ||||
| 80 | - | resp, err := http.PostForm(config.GetBackendURL()+"/api/device/token", url.Values{ | 80 | + | resp, err := http.PostForm(a.Config.GetBackendURL()+"/api/device/token", url.Values{ |
| 81 | "device_code": {deviceCode}, | 81 | "device_code": {deviceCode}, | ||
| 82 | }) | 82 | }) | ||
| 83 | if err != nil { | 83 | if err != nil { | ||
M internal/cli/cmd/update.go +2 -4
| @@ -67,8 +67,6 @@ func NewUpdateCommand(a *cli.App) *cobra.Command { | |||
| 67 | 67 | panic("app instance is nil") | |
| 68 | 68 | } | |
| 69 | 69 | ||
| 70 | - | var withBackup bool | |
| 71 | - | ||
| 72 | 70 | command := &cobra.Command{ | |
| 73 | 71 | Use: "update", | |
| 74 | 72 | Short: "Update the Gordon executable", | |
| @@ -94,13 +92,13 @@ func NewUpdateCommand(a *cli.App) *cobra.Command { | |||
| 94 | 92 | } | |
| 95 | 93 | } | |
| 96 | 94 | ||
| 97 | - | return pluginInstance.update(withBackup) | |
| 95 | + | return pluginInstance.update() | |
| 98 | 96 | }, | |
| 99 | 97 | } | |
| 100 | 98 | return command | |
| 101 | 99 | } | |
| 102 | 100 | ||
| 103 | - | func (p *plugin) update(withBackup bool) error { | |
| 101 | + | func (p *plugin) update() error { | |
| 104 | 102 | color.Yellow("Fetching release information...") | |
| 105 | 103 | ||
| 106 | 104 | latest, err := fetchLatestRelease( | |
| @@ -67,8 +67,6 @@ func NewUpdateCommand(a *cli.App) *cobra.Command { | |||||
| 67 | panic("app instance is nil") | 67 | panic("app instance is nil") | ||
| 68 | } | 68 | } | ||
| 69 | 69 | ||||
| 70 | - | var withBackup bool | |||
| 71 | - | ||||
| 72 | command := &cobra.Command{ | 70 | command := &cobra.Command{ | ||
| 73 | Use: "update", | 71 | Use: "update", | ||
| 74 | Short: "Update the Gordon executable", | 72 | Short: "Update the Gordon executable", | ||
| @@ -94,13 +92,13 @@ func NewUpdateCommand(a *cli.App) *cobra.Command { | |||||
| 94 | } | 92 | } | ||
| 95 | } | 93 | } | ||
| 96 | 94 | ||||
| 97 | - | return pluginInstance.update(withBackup) | 95 | + | return pluginInstance.update() |
| 98 | }, | 96 | }, | ||
| 99 | } | 97 | } | ||
| 100 | return command | 98 | return command | ||
| 101 | } | 99 | } | ||
| 102 | 100 | ||||
| 103 | - | func (p *plugin) update(withBackup bool) error { | 101 | + | func (p *plugin) update() error { |
| 104 | color.Yellow("Fetching release information...") | 102 | color.Yellow("Fetching release information...") | ||
| 105 | 103 | ||||
| 106 | latest, err := fetchLatestRelease( | 104 | latest, err := fetchLatestRelease( | ||
M internal/cli/handler/fieldcheck.go +1 -1
| @@ -34,7 +34,7 @@ func FieldCheck(a *cli.App) error { | |||
| 34 | 34 | ||
| 35 | 35 | if a.Config.General.Token == "" { | |
| 36 | 36 | fmt.Println("Token is not set. Starting OAuth device flow...") | |
| 37 | - | err := auth.DeviceFlowAuth(&a.Config) | |
| 37 | + | err := auth.DeviceFlowAuth(a) | |
| 38 | 38 | if err != nil { | |
| 39 | 39 | fmt.Printf("Device flow authentication error: %v\n", err) | |
| 40 | 40 | return fmt.Errorf("failed to complete device flow authentication: %w", err) | |
| @@ -34,7 +34,7 @@ func FieldCheck(a *cli.App) error { | |||||
| 34 | 34 | ||||
| 35 | if a.Config.General.Token == "" { | 35 | if a.Config.General.Token == "" { | ||
| 36 | fmt.Println("Token is not set. Starting OAuth device flow...") | 36 | fmt.Println("Token is not set. Starting OAuth device flow...") | ||
| 37 | - | err := auth.DeviceFlowAuth(&a.Config) | 37 | + | err := auth.DeviceFlowAuth(a) |
| 38 | if err != nil { | 38 | if err != nil { | ||
| 39 | fmt.Printf("Device flow authentication error: %v\n", err) | 39 | fmt.Printf("Device flow authentication error: %v\n", err) | ||
| 40 | return fmt.Errorf("failed to complete device flow authentication: %w", err) | 40 | return fmt.Errorf("failed to complete device flow authentication: %w", err) | ||
M internal/cli/handler/http.go +69 -12
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | 8 | "net/http" | |
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/gordon/internal/cli" | |
| 11 | + | "github.com/bnema/gordon/internal/cli/auth" | |
| 11 | 12 | "github.com/bnema/gordon/internal/common" | |
| 12 | 13 | ) | |
| 13 | 14 | ||
| @@ -43,8 +44,51 @@ type Response struct { | |||
| 43 | 44 | // SendHTTPRequest sends the HTTP request | |
| 44 | 45 | func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpoint string) (*Response, error) { | |
| 45 | 46 | apiUrl := a.Config.Http.BackendURL + "/api" | |
| 46 | - | token := a.Config.General.Token | |
| 47 | + | client := &http.Client{} | |
| 48 | + | ||
| 49 | + | reauthenticated := false | |
| 50 | + | ||
| 51 | + | for { | |
| 52 | + | req, err := createRequest(apiUrl, endpoint, method, rp, a.Config.General.Token) | |
| 53 | + | if err != nil { | |
| 54 | + | return nil, fmt.Errorf("failed to create request: %w", err) | |
| 55 | + | } | |
| 56 | + | ||
| 57 | + | resp, err := client.Do(req) | |
| 58 | + | if err != nil { | |
| 59 | + | return nil, fmt.Errorf("failed to send request: %w", err) | |
| 60 | + | } | |
| 61 | + | defer resp.Body.Close() | |
| 62 | + | ||
| 63 | + | body, err := io.ReadAll(resp.Body) | |
| 64 | + | if err != nil { | |
| 65 | + | return nil, fmt.Errorf("failed to read response body: %w", err) | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | if resp.StatusCode != http.StatusOK { | |
| 69 | + | var errorResp map[string]interface{} | |
| 70 | + | if err := json.Unmarshal(body, &errorResp); err == nil { | |
| 71 | + | if resp.StatusCode == http.StatusUnauthorized && !reauthenticated { | |
| 72 | + | fmt.Println("Token is invalid or expired. Initiating re-authentication...") | |
| 73 | + | err := ReAuthenticate(a) | |
| 74 | + | if err != nil { | |
| 75 | + | return nil, fmt.Errorf("re-authentication failed: %w", err) | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | reauthenticated = true | |
| 79 | + | continue | |
| 80 | + | } | |
| 81 | + | errorMsg := fmt.Sprintf("Request failed: status=%d, error=%v", resp.StatusCode, errorResp["error"]) | |
| 82 | + | return nil, fmt.Errorf(errorMsg) | |
| 83 | + | } | |
| 84 | + | return nil, fmt.Errorf("request failed with status %d: %s", resp.StatusCode, string(body)) | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | return &Response{Http: resp, Body: body, StatusCode: resp.StatusCode}, nil | |
| 88 | + | } | |
| 89 | + | } | |
| 47 | 90 | ||
| 91 | + | func createRequest(apiUrl, endpoint, method string, rp *common.RequestPayload, token string) (*http.Request, error) { | |
| 48 | 92 | var req *http.Request | |
| 49 | 93 | var err error | |
| 50 | 94 | ||
| @@ -60,7 +104,6 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo | |||
| 60 | 104 | return nil, fmt.Errorf("failed to create new streaming request: %w", err) | |
| 61 | 105 | } | |
| 62 | 106 | ||
| 63 | - | setAuthRequestHeaders(req, token) | |
| 64 | 107 | req.Header.Set("Content-Type", "application/octet-stream") | |
| 65 | 108 | req.Header.Set("X-Ports", deployPayload.Port) | |
| 66 | 109 | req.Header.Set("X-Target-Domain", deployPayload.TargetDomain) | |
| @@ -77,11 +120,10 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo | |||
| 77 | 120 | return nil, fmt.Errorf("failed to create new streaming request: %w", err) | |
| 78 | 121 | } | |
| 79 | 122 | ||
| 80 | - | setAuthRequestHeaders(req, token) | |
| 81 | 123 | req.Header.Set("Content-Type", "application/octet-stream") | |
| 82 | 124 | req.Header.Set("X-Image-Name", pushPayload.ImageName) | |
| 83 | 125 | ||
| 84 | - | default: // This will handle "ping" and any other types | |
| 126 | + | default: | |
| 85 | 127 | jsonPayload, err := json.Marshal(rp) | |
| 86 | 128 | if err != nil { | |
| 87 | 129 | return nil, fmt.Errorf("failed to marshal payload: %w", err) | |
| @@ -92,21 +134,36 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo | |||
| 92 | 134 | return nil, fmt.Errorf("failed to create new JSON request: %w", err) | |
| 93 | 135 | } | |
| 94 | 136 | ||
| 95 | - | setAuthRequestHeaders(req, token) | |
| 96 | 137 | req.Header.Set("Content-Type", "application/json") | |
| 97 | 138 | } | |
| 98 | 139 | ||
| 99 | - | client := &http.Client{} | |
| 100 | - | resp, err := client.Do(req) | |
| 140 | + | // Set the authorization header for all request types | |
| 141 | + | req.Header.Set("Authorization", "Bearer "+token) | |
| 142 | + | ||
| 143 | + | return req, nil | |
| 144 | + | } | |
| 145 | + | ||
| 146 | + | func ReAuthenticate(a *cli.App) error { | |
| 147 | + | fmt.Println("Re-authenticating...") | |
| 148 | + | err := auth.DeviceFlowAuth(a) | |
| 149 | + | if err != nil { | |
| 150 | + | return fmt.Errorf("device flow authentication failed: %w", err) | |
| 151 | + | } | |
| 152 | + | ||
| 153 | + | // After successful re-authentication, get the new token | |
| 154 | + | newToken, err := a.Config.GetToken() | |
| 101 | 155 | if err != nil { | |
| 102 | - | return nil, fmt.Errorf("failed to send request: %w", err) | |
| 156 | + | return fmt.Errorf("failed to get new token: %w", err) | |
| 103 | 157 | } | |
| 104 | - | defer resp.Body.Close() | |
| 158 | + | // Update the token in the app config | |
| 159 | + | a.Config.General.Token = newToken | |
| 105 | 160 | ||
| 106 | - | body, err := io.ReadAll(resp.Body) | |
| 161 | + | // Save the new token to config file | |
| 162 | + | err = a.Config.SaveConfig() | |
| 107 | 163 | if err != nil { | |
| 108 | - | return nil, fmt.Errorf("failed to read response body: %w", err) | |
| 164 | + | return fmt.Errorf("failed to save new token to config: %w", err) | |
| 109 | 165 | } | |
| 110 | 166 | ||
| 111 | - | return &Response{Http: resp, Body: body, StatusCode: resp.StatusCode}, nil | |
| 167 | + | fmt.Println("Re-authentication successful. Your session has been renewed.") | |
| 168 | + | return nil | |
| 112 | 169 | } | |
| @@ -8,6 +8,7 @@ import ( | |||||
| 8 | "net/http" | 8 | "net/http" | ||
| 9 | 9 | ||||
| 10 | "github.com/bnema/gordon/internal/cli" | 10 | "github.com/bnema/gordon/internal/cli" | ||
| 11 | + | "github.com/bnema/gordon/internal/cli/auth" | |||
| 11 | "github.com/bnema/gordon/internal/common" | 12 | "github.com/bnema/gordon/internal/common" | ||
| 12 | ) | 13 | ) | ||
| 13 | 14 | ||||
| @@ -43,8 +44,51 @@ type Response struct { | |||||
| 43 | // SendHTTPRequest sends the HTTP request | 44 | // SendHTTPRequest sends the HTTP request | ||
| 44 | func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpoint string) (*Response, error) { | 45 | func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpoint string) (*Response, error) { | ||
| 45 | apiUrl := a.Config.Http.BackendURL + "/api" | 46 | apiUrl := a.Config.Http.BackendURL + "/api" | ||
| 46 | - | token := a.Config.General.Token | 47 | + | client := &http.Client{} |
| 48 | + | ||||
| 49 | + | reauthenticated := false | |||
| 50 | + | ||||
| 51 | + | for { | |||
| 52 | + | req, err := createRequest(apiUrl, endpoint, method, rp, a.Config.General.Token) | |||
| 53 | + | if err != nil { | |||
| 54 | + | return nil, fmt.Errorf("failed to create request: %w", err) | |||
| 55 | + | } | |||
| 56 | + | ||||
| 57 | + | resp, err := client.Do(req) | |||
| 58 | + | if err != nil { | |||
| 59 | + | return nil, fmt.Errorf("failed to send request: %w", err) | |||
| 60 | + | } | |||
| 61 | + | defer resp.Body.Close() | |||
| 62 | + | ||||
| 63 | + | body, err := io.ReadAll(resp.Body) | |||
| 64 | + | if err != nil { | |||
| 65 | + | return nil, fmt.Errorf("failed to read response body: %w", err) | |||
| 66 | + | } | |||
| 67 | + | ||||
| 68 | + | if resp.StatusCode != http.StatusOK { | |||
| 69 | + | var errorResp map[string]interface{} | |||
| 70 | + | if err := json.Unmarshal(body, &errorResp); err == nil { | |||
| 71 | + | if resp.StatusCode == http.StatusUnauthorized && !reauthenticated { | |||
| 72 | + | fmt.Println("Token is invalid or expired. Initiating re-authentication...") | |||
| 73 | + | err := ReAuthenticate(a) | |||
| 74 | + | if err != nil { | |||
| 75 | + | return nil, fmt.Errorf("re-authentication failed: %w", err) | |||
| 76 | + | } | |||
| 77 | + | ||||
| 78 | + | reauthenticated = true | |||
| 79 | + | continue | |||
| 80 | + | } | |||
| 81 | + | errorMsg := fmt.Sprintf("Request failed: status=%d, error=%v", resp.StatusCode, errorResp["error"]) | |||
| 82 | + | return nil, fmt.Errorf(errorMsg) | |||
| 83 | + | } | |||
| 84 | + | return nil, fmt.Errorf("request failed with status %d: %s", resp.StatusCode, string(body)) | |||
| 85 | + | } | |||
| 86 | + | ||||
| 87 | + | return &Response{Http: resp, Body: body, StatusCode: resp.StatusCode}, nil | |||
| 88 | + | } | |||
| 89 | + | } | |||
| 47 | 90 | ||||
| 91 | + | func createRequest(apiUrl, endpoint, method string, rp *common.RequestPayload, token string) (*http.Request, error) { | |||
| 48 | var req *http.Request | 92 | var req *http.Request | ||
| 49 | var err error | 93 | var err error | ||
| 50 | 94 | ||||
| @@ -60,7 +104,6 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo | |||||
| 60 | return nil, fmt.Errorf("failed to create new streaming request: %w", err) | 104 | return nil, fmt.Errorf("failed to create new streaming request: %w", err) | ||
| 61 | } | 105 | } | ||
| 62 | 106 | ||||
| 63 | - | setAuthRequestHeaders(req, token) | |||
| 64 | req.Header.Set("Content-Type", "application/octet-stream") | 107 | req.Header.Set("Content-Type", "application/octet-stream") | ||
| 65 | req.Header.Set("X-Ports", deployPayload.Port) | 108 | req.Header.Set("X-Ports", deployPayload.Port) | ||
| 66 | req.Header.Set("X-Target-Domain", deployPayload.TargetDomain) | 109 | req.Header.Set("X-Target-Domain", deployPayload.TargetDomain) | ||
| @@ -77,11 +120,10 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo | |||||
| 77 | return nil, fmt.Errorf("failed to create new streaming request: %w", err) | 120 | return nil, fmt.Errorf("failed to create new streaming request: %w", err) | ||
| 78 | } | 121 | } | ||
| 79 | 122 | ||||
| 80 | - | setAuthRequestHeaders(req, token) | |||
| 81 | req.Header.Set("Content-Type", "application/octet-stream") | 123 | req.Header.Set("Content-Type", "application/octet-stream") | ||
| 82 | req.Header.Set("X-Image-Name", pushPayload.ImageName) | 124 | req.Header.Set("X-Image-Name", pushPayload.ImageName) | ||
| 83 | 125 | ||||
| 84 | - | default: // This will handle "ping" and any other types | 126 | + | default: |
| 85 | jsonPayload, err := json.Marshal(rp) | 127 | jsonPayload, err := json.Marshal(rp) | ||
| 86 | if err != nil { | 128 | if err != nil { | ||
| 87 | return nil, fmt.Errorf("failed to marshal payload: %w", err) | 129 | return nil, fmt.Errorf("failed to marshal payload: %w", err) | ||
| @@ -92,21 +134,36 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo | |||||
| 92 | return nil, fmt.Errorf("failed to create new JSON request: %w", err) | 134 | return nil, fmt.Errorf("failed to create new JSON request: %w", err) | ||
| 93 | } | 135 | } | ||
| 94 | 136 | ||||
| 95 | - | setAuthRequestHeaders(req, token) | |||
| 96 | req.Header.Set("Content-Type", "application/json") | 137 | req.Header.Set("Content-Type", "application/json") | ||
| 97 | } | 138 | } | ||
| 98 | 139 | ||||
| 99 | - | client := &http.Client{} | 140 | + | // Set the authorization header for all request types |
| 100 | - | resp, err := client.Do(req) | 141 | + | req.Header.Set("Authorization", "Bearer "+token) |
| 142 | + | ||||
| 143 | + | return req, nil | |||
| 144 | + | } | |||
| 145 | + | ||||
| 146 | + | func ReAuthenticate(a *cli.App) error { | |||
| 147 | + | fmt.Println("Re-authenticating...") | |||
| 148 | + | err := auth.DeviceFlowAuth(a) | |||
| 149 | + | if err != nil { | |||
| 150 | + | return fmt.Errorf("device flow authentication failed: %w", err) | |||
| 151 | + | } | |||
| 152 | + | ||||
| 153 | + | // After successful re-authentication, get the new token | |||
| 154 | + | newToken, err := a.Config.GetToken() | |||
| 101 | if err != nil { | 155 | if err != nil { | ||
| 102 | - | return nil, fmt.Errorf("failed to send request: %w", err) | 156 | + | return fmt.Errorf("failed to get new token: %w", err) |
| 103 | } | 157 | } | ||
| 104 | - | defer resp.Body.Close() | 158 | + | // Update the token in the app config |
| 159 | + | a.Config.General.Token = newToken | |||
| 105 | 160 | ||||
| 106 | - | body, err := io.ReadAll(resp.Body) | 161 | + | // Save the new token to config file |
| 162 | + | err = a.Config.SaveConfig() | |||
| 107 | if err != nil { | 163 | if err != nil { | ||
| 108 | - | return nil, fmt.Errorf("failed to read response body: %w", err) | 164 | + | return fmt.Errorf("failed to save new token to config: %w", err) |
| 109 | } | 165 | } | ||
| 110 | 166 | ||||
| 111 | - | return &Response{Http: resp, Body: body, StatusCode: resp.StatusCode}, nil | 167 | + | fmt.Println("Re-authentication successful. Your session has been renewed.") |
| 168 | + | return nil | |||
| 112 | } | 169 | } | ||
M internal/common/initconfig.go +0 -1
| @@ -166,7 +166,6 @@ func (config *Config) SaveConfig() error { | |||
| 166 | 166 | return fmt.Errorf("error writing configuration file: %w", err) | |
| 167 | 167 | } | |
| 168 | 168 | ||
| 169 | - | fmt.Printf("Configuration saved to %s\n", configFilePath) | |
| 170 | 169 | return nil | |
| 171 | 170 | } | |
| 172 | 171 | ||
| @@ -166,7 +166,6 @@ func (config *Config) SaveConfig() error { | |||||
| 166 | return fmt.Errorf("error writing configuration file: %w", err) | 166 | return fmt.Errorf("error writing configuration file: %w", err) | ||
| 167 | } | 167 | } | ||
| 168 | 168 | ||||
| 169 | - | fmt.Printf("Configuration saved to %s\n", configFilePath) | |||
| 170 | return nil | 169 | return nil | ||
| 171 | } | 170 | } | ||
| 172 | 171 | ||||