diff --git a/cli/packages/api/api.go b/cli/packages/api/api.go index 5f8bc7aae..4ace4c387 100644 --- a/cli/packages/api/api.go +++ b/cli/packages/api/api.go @@ -2,6 +2,7 @@ package api import ( "fmt" + "net/http" "github.com/Infisical/infisical-merge/packages/config" "github.com/go-resty/resty/v2" @@ -179,6 +180,19 @@ func CallLogin2V2(httpClient *resty.Client, request GetLoginTwoV2Request) (GetLo SetBody(request). Post(fmt.Sprintf("%v/v2/auth/login2", config.INFISICAL_URL)) + cookies := response.Cookies() + // Find a cookie by name + cookieName := "jid" + var refreshToken *http.Cookie + for _, cookie := range cookies { + if cookie.Name == cookieName { + refreshToken = cookie + break + } + } + + loginTwoV2Response.RefreshToken = refreshToken.Value + if err != nil { return GetLoginTwoV2Response{}, fmt.Errorf("CallLogin2V2: Unable to complete api request [err=%s]", err) } @@ -247,3 +261,26 @@ func CallGetAccessibleEnvironments(httpClient *resty.Client, request GetAccessib return accessibleEnvironmentsResponse, nil } + +func CallGetNewAccessTokenWithRefreshToken(httpClient *resty.Client, refreshToken string) (GetNewAccessTokenWithRefreshTokenResponse, error) { + var newAccessToken GetNewAccessTokenWithRefreshTokenResponse + response, err := httpClient. + R(). + SetResult(&newAccessToken). + SetHeader("User-Agent", USER_AGENT). + SetCookie(&http.Cookie{ + Name: "jid", + Value: refreshToken, + }). + Post(fmt.Sprintf("%v/v1/auth/token", config.INFISICAL_URL)) + + if err != nil { + return GetNewAccessTokenWithRefreshTokenResponse{}, err + } + + if response.IsError() { + return GetNewAccessTokenWithRefreshTokenResponse{}, fmt.Errorf("CallGetNewAccessTokenWithRefreshToken: Unsuccessful response: [response=%v]", response) + } + + return newAccessToken, nil +} diff --git a/cli/packages/api/model.go b/cli/packages/api/model.go index 71354c84c..bce2a34d6 100644 --- a/cli/packages/api/model.go +++ b/cli/packages/api/model.go @@ -281,6 +281,7 @@ type GetLoginTwoV2Response struct { ProtectedKey string `json:"protectedKey"` ProtectedKeyIV string `json:"protectedKeyIV"` ProtectedKeyTag string `json:"protectedKeyTag"` + RefreshToken string `json:"RefreshToken"` } type VerifyMfaTokenRequest struct { @@ -314,3 +315,7 @@ type VerifyMfaTokenErrorResponse struct { Application string `json:"application"` Extra []interface{} `json:"extra"` } + +type GetNewAccessTokenWithRefreshTokenResponse struct { + Token string `json:"token"` +} diff --git a/cli/packages/cmd/login.go b/cli/packages/cmd/login.go index f20a17853..ab0f531c2 100644 --- a/cli/packages/cmd/login.go +++ b/cli/packages/cmd/login.go @@ -97,7 +97,7 @@ var loginCmd = &cobra.Command{ loginOneResponse, loginTwoResponse, err := getFreshUserCredentials(email, password) if err != nil { - fmt.Println("Unable to authenticate with the provided credentials, please try again") + log.Warn().Msg("Unable to authenticate with the provided credentials, please ensure your email and password are correct") log.Debug().Err(err) return } @@ -244,9 +244,10 @@ var loginCmd = &cobra.Command{ } userCredentialsToBeStored := &models.UserCredentials{ - Email: email, - PrivateKey: string(decryptedPrivateKey), - JTWToken: loginTwoResponse.Token, + Email: email, + PrivateKey: string(decryptedPrivateKey), + JTWToken: loginTwoResponse.Token, + RefreshToken: loginTwoResponse.RefreshToken, } err = util.StoreUserCredsInKeyRing(userCredentialsToBeStored) @@ -414,7 +415,7 @@ func getFreshUserCredentials(email string, password string) (*api.GetLoginOneV2R }) if err != nil { - util.HandleError(err) + return nil, nil, err } // **** Login 2 diff --git a/cli/packages/models/cli.go b/cli/packages/models/cli.go index b9b0ab7b5..22f72e2da 100644 --- a/cli/packages/models/cli.go +++ b/cli/packages/models/cli.go @@ -5,9 +5,10 @@ import ( ) type UserCredentials struct { - Email string `json:"email"` - PrivateKey string `json:"privateKey"` - JTWToken string `json:"JTWToken"` + Email string `json:"email"` + PrivateKey string `json:"privateKey"` + JTWToken string `json:"JTWToken"` + RefreshToken string `json:"RefreshToken"` } // The file struct for Infisical config file diff --git a/cli/packages/util/credentials.go b/cli/packages/util/credentials.go index 9147a717a..6b203c2e3 100644 --- a/cli/packages/util/credentials.go +++ b/cli/packages/util/credentials.go @@ -9,6 +9,7 @@ import ( "github.com/Infisical/infisical-merge/packages/config" "github.com/Infisical/infisical-merge/packages/models" "github.com/go-resty/resty/v2" + "github.com/rs/zerolog/log" ) type LoggedInUserDetails struct { @@ -96,6 +97,20 @@ func GetCurrentLoggedInUserDetails() (LoggedInUserDetails, error) { } isAuthenticated := api.CallIsAuthenticated(httpClient) + + if !isAuthenticated { + accessTokenResponse, _ := api.CallGetNewAccessTokenWithRefreshToken(httpClient, userCreds.RefreshToken) + if accessTokenResponse.Token != "" { + isAuthenticated = true + userCreds.JTWToken = accessTokenResponse.Token + } + } + + err = StoreUserCredsInKeyRing(&userCreds) + if err != nil { + log.Debug().Msg("unable to store your user credentials with new access token") + } + if !isAuthenticated { return LoggedInUserDetails{ IsUserLoggedIn: true, // was logged in diff --git a/cli/packages/util/helper.go b/cli/packages/util/helper.go index 8527c4059..d96ac3899 100644 --- a/cli/packages/util/helper.go +++ b/cli/packages/util/helper.go @@ -74,23 +74,12 @@ func ConfigContainsEmail(users []models.LoggedInUser, email string) bool { } func RequireLogin() { - currentUserDetails, err := GetCurrentLoggedInUserDetails() + // get the config file that stores the current logged in user email + configFile, _ := GetConfigFile() - if err != nil { - HandleError(err, "unable to retrieve your login details") - } - - if !currentUserDetails.IsUserLoggedIn { + if configFile.LoggedInUserEmail == "" { PrintErrorMessageAndExit("You must be logged in to run this command. To login, run [infisical login]") } - - if currentUserDetails.LoginExpired { - PrintErrorMessageAndExit("Your login expired, please login in again. To login, run [infisical login]") - } - - if currentUserDetails.UserCredentials.Email == "" && currentUserDetails.UserCredentials.JTWToken == "" && currentUserDetails.UserCredentials.PrivateKey == "" { - PrintErrorMessageAndExit("One or more of your login details is empty. Please try logging in again via by running [infisical login]") - } } func RequireServiceToken() {