From 764636cd4709ba9148f98188d63360de96c84831 Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Thu, 5 Jan 2023 01:01:47 -0500 Subject: [PATCH] Add service token v2 api into cli --- cli/packages/cmd/login.go | 8 +- cli/packages/cmd/root.go | 4 +- cli/packages/cmd/run.go | 2 - cli/packages/cmd/secrets.go | 13 +- cli/packages/config/config.go | 3 + cli/packages/{util => crypto}/crypto.go | 2 +- cli/packages/http/api.go | 43 ++-- cli/packages/models/api.go | 80 +++++-- cli/packages/util/common.go | 2 - cli/packages/util/credentials.go | 5 +- cli/packages/util/helper.go | 56 +++++ cli/packages/util/secrets.go | 265 ++++++++++++++++-------- 12 files changed, 344 insertions(+), 139 deletions(-) create mode 100644 cli/packages/config/config.go rename cli/packages/{util => crypto}/crypto.go (99%) create mode 100644 cli/packages/util/helper.go diff --git a/cli/packages/cmd/login.go b/cli/packages/cmd/login.go index 9c0c229309..d591264472 100644 --- a/cli/packages/cmd/login.go +++ b/cli/packages/cmd/login.go @@ -11,6 +11,8 @@ import ( "fmt" "regexp" + "github.com/Infisical/infisical-merge/packages/config" + "github.com/Infisical/infisical-merge/packages/crypto" "github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/srp" "github.com/Infisical/infisical-merge/packages/util" @@ -76,7 +78,7 @@ var loginCmd = &cobra.Command{ paddedPassword := fmt.Sprintf("%032s", password) key := []byte(paddedPassword) - decryptedPrivateKey, err := util.DecryptSymmetric(key, encryptedPrivateKey, tag, IV) + decryptedPrivateKey, err := crypto.DecryptSymmetric(key, encryptedPrivateKey, tag, IV) if err != nil || len(decryptedPrivateKey) == 0 { log.Errorln("There was an issue decrypting your keys") log.Debugln(err) @@ -178,7 +180,7 @@ func getFreshUserCredentials(email string, password string) (*models.LoginTwoRes R(). SetBody(loginOneRequest). SetResult(&loginOneResponseResult). - Post(fmt.Sprintf("%v/v1/auth/login1", util.INFISICAL_URL)) + Post(fmt.Sprintf("%v/v1/auth/login1", config.INFISICAL_URL)) if err != nil { return nil, err @@ -214,7 +216,7 @@ func getFreshUserCredentials(email string, password string) (*models.LoginTwoRes R(). SetBody(LoginTwoRequest). SetResult(&loginTwoResponseResult). - Post(fmt.Sprintf("%v/v1/auth/login2", util.INFISICAL_URL)) + Post(fmt.Sprintf("%v/v1/auth/login2", config.INFISICAL_URL)) if err != nil { return nil, err diff --git a/cli/packages/cmd/root.go b/cli/packages/cmd/root.go index f09f08800b..5ac52c0b78 100644 --- a/cli/packages/cmd/root.go +++ b/cli/packages/cmd/root.go @@ -6,7 +6,7 @@ package cmd import ( "os" - "github.com/Infisical/infisical-merge/packages/util" + "github.com/Infisical/infisical-merge/packages/config" "github.com/spf13/cobra" ) @@ -30,7 +30,7 @@ func Execute() { func init() { rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") rootCmd.PersistentFlags().BoolVarP(&debugLogging, "debug", "d", false, "Enable verbose logging") - rootCmd.PersistentFlags().StringVar(&util.INFISICAL_URL, "domain", "https://app.infisical.com/api", "Point the CLI to your own backend") + rootCmd.PersistentFlags().StringVar(&config.INFISICAL_URL, "domain", "http://localhost:8080/api", "Point the CLI to your own backend") // rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) { // } } diff --git a/cli/packages/cmd/run.go b/cli/packages/cmd/run.go index 6e0133c8e3..106eb7a83d 100644 --- a/cli/packages/cmd/run.go +++ b/cli/packages/cmd/run.go @@ -130,7 +130,6 @@ func executeSingleCommandWithEnvs(args []string, secrets []models.SingleEnvironm numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(secrets)) log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected) log.Debugf("executing command: %s %s \n", command, strings.Join(argsForCommand, " ")) - log.Debugln("Secrets injected:", secrets) cmd := exec.Command(command, argsForCommand...) cmd.Stdin = os.Stdin @@ -158,7 +157,6 @@ func executeMultipleCommandWithEnvs(fullCommand string, secrets []models.SingleE numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(secrets)) log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected) log.Debugf("executing command: %s %s %s \n", shell[0], shell[1], fullCommand) - log.Debugln("Secrets injected:", secrets) return execCmd(cmd) } diff --git a/cli/packages/cmd/secrets.go b/cli/packages/cmd/secrets.go index 5e6c4ca162..e4e826fe88 100644 --- a/cli/packages/cmd/secrets.go +++ b/cli/packages/cmd/secrets.go @@ -11,6 +11,7 @@ import ( "crypto/sha256" + "github.com/Infisical/infisical-merge/packages/crypto" "github.com/Infisical/infisical-merge/packages/http" "github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/util" @@ -147,13 +148,13 @@ var secretsSetCmd = &cobra.Command{ return } - encryptedWorkspaceKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.LatestKey.EncryptedKey) - encryptedWorkspaceKeySenderPublicKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.LatestKey.Sender.PublicKey) - encryptedWorkspaceKeyNonce, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.LatestKey.Nonce) + encryptedWorkspaceKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.EncryptedKey) + encryptedWorkspaceKeySenderPublicKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Sender.PublicKey) + encryptedWorkspaceKeyNonce, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Nonce) currentUsersPrivateKey, _ := base64.StdEncoding.DecodeString(loggedInUserDetails.UserCredentials.PrivateKey) // decrypt workspace key - plainTextEncryptionKey := util.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey) + plainTextEncryptionKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey) // pull current secrets secrets, err := util.GetAllEnvironmentVariables("", environmentName) @@ -191,13 +192,13 @@ var secretsSetCmd = &cobra.Command{ value := splitKeyValueFromArg[1] hashedKey := fmt.Sprintf("%x", sha256.Sum256([]byte(key))) - encryptedKey, err := util.EncryptSymmetric([]byte(key), []byte(plainTextEncryptionKey)) + encryptedKey, err := crypto.EncryptSymmetric([]byte(key), []byte(plainTextEncryptionKey)) if err != nil { log.Errorf("unable to encrypt your secrets [err=%v]", err) } hashedValue := fmt.Sprintf("%x", sha256.Sum256([]byte(value))) - encryptedValue, err := util.EncryptSymmetric([]byte(value), []byte(plainTextEncryptionKey)) + encryptedValue, err := crypto.EncryptSymmetric([]byte(value), []byte(plainTextEncryptionKey)) if err != nil { log.Errorf("unable to encrypt your secrets [err=%v]", err) } diff --git a/cli/packages/config/config.go b/cli/packages/config/config.go new file mode 100644 index 0000000000..5ceb695e68 --- /dev/null +++ b/cli/packages/config/config.go @@ -0,0 +1,3 @@ +package config + +var INFISICAL_URL = "http://localhost:8080/api" diff --git a/cli/packages/util/crypto.go b/cli/packages/crypto/crypto.go similarity index 99% rename from cli/packages/util/crypto.go rename to cli/packages/crypto/crypto.go index 23e117f4b6..f9589347a9 100644 --- a/cli/packages/util/crypto.go +++ b/cli/packages/crypto/crypto.go @@ -1,4 +1,4 @@ -package util +package crypto import ( "crypto/aes" diff --git a/cli/packages/http/api.go b/cli/packages/http/api.go index 01b8a8a40d..9e75e45b31 100644 --- a/cli/packages/http/api.go +++ b/cli/packages/http/api.go @@ -3,13 +3,13 @@ package http import ( "fmt" + "github.com/Infisical/infisical-merge/packages/config" "github.com/Infisical/infisical-merge/packages/models" - "github.com/Infisical/infisical-merge/packages/util" "github.com/go-resty/resty/v2" ) func CallBatchModifySecretsByWorkspaceAndEnv(httpClient *resty.Client, request models.BatchModifySecretsByWorkspaceAndEnvRequest) error { - endpoint := fmt.Sprintf("%v/v2/secret/batch-modify/workspace/%v/environment/%v", util.INFISICAL_URL, request.WorkspaceId, request.EnvironmentName) + endpoint := fmt.Sprintf("%v/v2/secret/batch-modify/workspace/%v/environment/%v", config.INFISICAL_URL, request.WorkspaceId, request.EnvironmentName) response, err := httpClient. R(). SetBody(request). @@ -27,7 +27,7 @@ func CallBatchModifySecretsByWorkspaceAndEnv(httpClient *resty.Client, request m } func CallBatchCreateSecretsByWorkspaceAndEnv(httpClient *resty.Client, request models.BatchCreateSecretsByWorkspaceAndEnvRequest) error { - endpoint := fmt.Sprintf("%v/v2/secret/batch-create/workspace/%v/environment/%v", util.INFISICAL_URL, request.WorkspaceId, request.EnvironmentName) + endpoint := fmt.Sprintf("%v/v2/secret/batch-create/workspace/%v/environment/%v", config.INFISICAL_URL, request.WorkspaceId, request.EnvironmentName) response, err := httpClient. R(). SetBody(request). @@ -45,7 +45,7 @@ func CallBatchCreateSecretsByWorkspaceAndEnv(httpClient *resty.Client, request m } func CallBatchDeleteSecretsByWorkspaceAndEnv(httpClient *resty.Client, request models.BatchDeleteSecretsBySecretIdsRequest) error { - endpoint := fmt.Sprintf("%v/v2/secret/batch/workspace/%v/environment/%v", util.INFISICAL_URL, request.WorkspaceId, request.EnvironmentName) + endpoint := fmt.Sprintf("%v/v2/secret/batch/workspace/%v/environment/%v", config.INFISICAL_URL, request.WorkspaceId, request.EnvironmentName) response, err := httpClient. R(). SetBody(request). @@ -63,7 +63,7 @@ func CallBatchDeleteSecretsByWorkspaceAndEnv(httpClient *resty.Client, request m } func CallGetEncryptedWorkspaceKey(httpClient *resty.Client, request models.GetEncryptedWorkspaceKeyRequest) (models.GetEncryptedWorkspaceKeyResponse, error) { - endpoint := fmt.Sprintf("%v/v1/key/%v/latest", util.INFISICAL_URL, request.WorkspaceId) + endpoint := fmt.Sprintf("%v/v2/workspace/%v/encrypted-key", config.INFISICAL_URL, request.WorkspaceId) var result models.GetEncryptedWorkspaceKeyResponse response, err := httpClient. R(). @@ -81,22 +81,39 @@ func CallGetEncryptedWorkspaceKey(httpClient *resty.Client, request models.GetEn return result, nil } -func CallGetEncryptedSecretsByWorkspaceIdAndEnv(httpClient resty.Client, request models.GetSecretsByWorkspaceIdAndEnvironmentRequest) (models.PullSecretsResponse, error) { - var pullSecretsRequestResponse models.PullSecretsResponse +func CallGetServiceTokenDetailsV2(httpClient *resty.Client) (models.GetServiceTokenDetailsResponse, error) { + var tokenDetailsResponse models.GetServiceTokenDetailsResponse response, err := httpClient. R(). + SetResult(&tokenDetailsResponse). + Get(fmt.Sprintf("%v/v2/service-token", config.INFISICAL_URL)) + + if err != nil { + return models.GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unable to complete api request [err=%s]", err) + } + + if response.StatusCode() > 299 { + return models.GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unsuccessful response: [response=%s]", response) + } + + return tokenDetailsResponse, nil +} + +func CallGetSecretsV2(httpClient *resty.Client, request models.GetEncryptedSecretsV2Request) (models.GetEncryptedSecretsV2Response, error) { + var secretsResponse models.GetEncryptedSecretsV2Response + response, err := httpClient. + R(). + SetResult(&secretsResponse). SetQueryParam("environment", request.EnvironmentName). - SetQueryParam("channel", "cli"). - SetResult(&pullSecretsRequestResponse). - Get(fmt.Sprintf("%v/v1/secret/%v", util.INFISICAL_URL, request.WorkspaceId)) + Get(fmt.Sprintf("%v/v2/secret/workspace/%v", config.INFISICAL_URL, request.WorkspaceId)) if err != nil { - return models.PullSecretsResponse{}, fmt.Errorf("CallGetEncryptedSecretsByWorkspaceIdAndEnv: Unable to complete api request [err=%s]", err) + return models.GetEncryptedSecretsV2Response{}, fmt.Errorf("CallGetSecretsV2: Unable to complete api request [err=%s]", err) } if response.StatusCode() > 299 { - return models.PullSecretsResponse{}, fmt.Errorf("CallGetEncryptedSecretsByWorkspaceIdAndEnv: Unsuccessful response: [response=%s]", response) + return models.GetEncryptedSecretsV2Response{}, fmt.Errorf("CallGetSecretsV2: Unsuccessful response: [response=%s]", response) } - return pullSecretsRequestResponse, nil + return secretsResponse, nil } diff --git a/cli/packages/models/api.go b/cli/packages/models/api.go index d17200b87f..e012a5077c 100644 --- a/cli/packages/models/api.go +++ b/cli/packages/models/api.go @@ -169,30 +169,68 @@ type GetEncryptedWorkspaceKeyRequest struct { } type GetEncryptedWorkspaceKeyResponse struct { - LatestKey struct { - ID string `json:"_id"` - EncryptedKey string `json:"encryptedKey"` - Nonce string `json:"nonce"` - Sender struct { - ID string `json:"_id"` - Email string `json:"email"` - RefreshVersion int `json:"refreshVersion"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - V int `json:"__v"` - FirstName string `json:"firstName"` - LastName string `json:"lastName"` - PublicKey string `json:"publicKey"` - } `json:"sender"` - Receiver string `json:"receiver"` - Workspace string `json:"workspace"` - V int `json:"__v"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - } `json:"latestKey"` + ID string `json:"_id"` + EncryptedKey string `json:"encryptedKey"` + Nonce string `json:"nonce"` + Sender struct { + ID string `json:"_id"` + Email string `json:"email"` + RefreshVersion int `json:"refreshVersion"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + V int `json:"__v"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + PublicKey string `json:"publicKey"` + } `json:"sender"` + Receiver string `json:"receiver"` + Workspace string `json:"workspace"` + V int `json:"__v"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` } type GetSecretsByWorkspaceIdAndEnvironmentRequest struct { EnvironmentName string `json:"environmentName"` WorkspaceId string `json:"workspaceId"` } + +type GetEncryptedSecretsV2Request struct { + EnvironmentName string `json:"environmentName"` + WorkspaceId string `json:"workspaceId"` +} + +type GetEncryptedSecretsV2Response []struct { + ID string `json:"_id"` + Version int `json:"version"` + Workspace string `json:"workspace"` + Type string `json:"type"` + Environment string `json:"environment"` + SecretKeyCiphertext string `json:"secretKeyCiphertext"` + SecretKeyIV string `json:"secretKeyIV"` + SecretKeyTag string `json:"secretKeyTag"` + SecretKeyHash string `json:"secretKeyHash"` + SecretValueCiphertext string `json:"secretValueCiphertext"` + SecretValueIV string `json:"secretValueIV"` + SecretValueTag string `json:"secretValueTag"` + SecretValueHash string `json:"secretValueHash"` + SecretCommentCiphertext string `json:"secretCommentCiphertext"` + SecretCommentIV string `json:"secretCommentIV"` + SecretCommentTag string `json:"secretCommentTag"` + SecretCommentHash string `json:"secretCommentHash"` + V int `json:"__v"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + User string `json:"user,omitempty"` +} + +type GetServiceTokenDetailsResponse struct { + ID string `json:"_id"` + Name string `json:"name"` + Workspace string `json:"workspace"` + Environment string `json:"environment"` + User string `json:"user"` + EncryptedKey string `json:"encryptedKey"` + Iv string `json:"iv"` + Tag string `json:"tag"` +} diff --git a/cli/packages/util/common.go b/cli/packages/util/common.go index 44f14a12b0..4654fc61c2 100644 --- a/cli/packages/util/common.go +++ b/cli/packages/util/common.go @@ -14,8 +14,6 @@ const ( SECRET_TYPE_SHARED = "shared" ) -var INFISICAL_URL = "https://app.infisical.com/api" - func GetHomeDir() (string, error) { directory, err := os.UserHomeDir() return directory, err diff --git a/cli/packages/util/credentials.go b/cli/packages/util/credentials.go index bd0e67debf..7143a4def5 100644 --- a/cli/packages/util/credentials.go +++ b/cli/packages/util/credentials.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/99designs/keyring" + "github.com/Infisical/infisical-merge/packages/config" "github.com/Infisical/infisical-merge/packages/models" "github.com/go-resty/resty/v2" log "github.com/sirupsen/logrus" @@ -92,7 +93,7 @@ func IsUserLoggedIn() (hasUserLoggedIn bool, theUsersEmail string, err error) { response, err := httpClient. R(). - Post(fmt.Sprintf("%v/v1/auth/checkAuth", INFISICAL_URL)) + Post(fmt.Sprintf("%v/v1/auth/checkAuth", config.INFISICAL_URL)) if err != nil { return false, "", err @@ -132,7 +133,7 @@ func GetCurrentLoggedInUserDetails() (LoggedInUserDetails, error) { response, err := httpClient. R(). - Post(fmt.Sprintf("%v/v1/auth/checkAuth", INFISICAL_URL)) + Post(fmt.Sprintf("%v/v1/auth/checkAuth", config.INFISICAL_URL)) if err != nil { return LoggedInUserDetails{}, err diff --git a/cli/packages/util/helper.go b/cli/packages/util/helper.go new file mode 100644 index 0000000000..2a647d79d9 --- /dev/null +++ b/cli/packages/util/helper.go @@ -0,0 +1,56 @@ +package util + +import ( + "encoding/base64" + "fmt" +) + +type DecodedSymmetricEncryptionDetails = struct { + Cipher []byte + IV []byte + Tag []byte + Key []byte +} + +func GetBase64DecodedSymmetricEncryptionDetails(key string, cipher string, IV string, tag string) (DecodedSymmetricEncryptionDetails, error) { + cipherx, err := base64.StdEncoding.DecodeString(cipher) + if err != nil { + return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode cipher text [err=%v]", err) + } + + keyx, err := base64.StdEncoding.DecodeString(key) + if err != nil { + return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode key [err=%v]", err) + } + + IVx, err := base64.StdEncoding.DecodeString(IV) + if err != nil { + return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode IV [err=%v]", err) + } + + tagx, err := base64.StdEncoding.DecodeString(tag) + if err != nil { + return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode tag [err=%v]", err) + } + + return DecodedSymmetricEncryptionDetails{ + Key: keyx, + Cipher: cipherx, + IV: IVx, + Tag: tagx, + }, nil +} + +func IsSecretEnvironmentValid(env string) bool { + if env == "prod" || env == "dev" || env == "test" || env == "staging" { + return true + } + return false +} + +func IsSecretTypeValid(s string) bool { + if s == "personal" || s == "shared" { + return true + } + return false +} diff --git a/cli/packages/util/secrets.go b/cli/packages/util/secrets.go index 66d2b56e37..f79d53a9ce 100644 --- a/cli/packages/util/secrets.go +++ b/cli/packages/util/secrets.go @@ -2,13 +2,16 @@ package util import ( "encoding/base64" - "errors" "fmt" "os" "regexp" "strings" + "github.com/Infisical/infisical-merge/packages/config" + "github.com/Infisical/infisical-merge/packages/crypto" + "github.com/Infisical/infisical-merge/packages/http" "github.com/Infisical/infisical-merge/packages/models" + "github.com/go-resty/resty/v2" log "github.com/sirupsen/logrus" ) @@ -23,7 +26,7 @@ func getSecretsByWorkspaceIdAndEnvName(httpClient resty.Client, envName string, SetQueryParam("environment", envName). SetQueryParam("channel", "cli"). SetResult(&pullSecretsRequestResponse). - Get(fmt.Sprintf("%v/v1/secret/%v", INFISICAL_URL, workspace.WorkspaceId)) // need to change workspace id + Get(fmt.Sprintf("%v/v1/secret/%v", config.INFISICAL_URL, workspace.WorkspaceId)) // need to change workspace id if err != nil { return nil, err @@ -55,7 +58,7 @@ func getSecretsByWorkspaceIdAndEnvName(httpClient resty.Client, envName string, } // log.Debugln("workspaceKey", workspaceKey, "nonce", nonce, "senderPublicKey", senderPublicKey, "currentUsersPrivateKey", currentUsersPrivateKey) - workspaceKeyInBytes := DecryptAsymmetric(workspaceKey, nonce, senderPublicKey, currentUsersPrivateKey) + workspaceKeyInBytes := crypto.DecryptAsymmetric(workspaceKey, nonce, senderPublicKey, currentUsersPrivateKey) var listOfEnv []models.SingleEnvironmentVariable for _, secret := range pullSecretsRequestResponse.Secrets { @@ -63,7 +66,7 @@ func getSecretsByWorkspaceIdAndEnvName(httpClient resty.Client, envName string, key_tag, _ := base64.StdEncoding.DecodeString(secret.SecretKeyTag) key_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretKeyCiphertext) - plainTextKey, err := DecryptSymmetric(workspaceKeyInBytes, key_ciphertext, key_tag, key_iv) + plainTextKey, err := crypto.DecryptSymmetric(workspaceKeyInBytes, key_ciphertext, key_tag, key_iv) if err != nil { return nil, err } @@ -72,7 +75,7 @@ func getSecretsByWorkspaceIdAndEnvName(httpClient resty.Client, envName string, value_tag, _ := base64.StdEncoding.DecodeString(secret.SecretValueTag) value_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretValueCiphertext) - plainTextValue, err := DecryptSymmetric(workspaceKeyInBytes, value_ciphertext, value_tag, value_iv) + plainTextValue, err := crypto.DecryptSymmetric(workspaceKeyInBytes, value_ciphertext, value_tag, value_iv) if err != nil { return nil, err } @@ -116,90 +119,116 @@ func GetSecretsFromAPIUsingCurrentLoggedInUser(envName string, userCreds models. return secrets, nil } -func GetSecretsFromAPIUsingInfisicalToken(infisicalToken string, envName string, projectId string) ([]models.SingleEnvironmentVariable, error) { - if infisicalToken == "" || projectId == "" || envName == "" { - return nil, errors.New("infisical token, project id and or environment name cannot be empty") - } - splitToken := strings.Split(infisicalToken, ",") - JTWToken := splitToken[0] - temPrivateKey := splitToken[1] +// func GetPlainTextSecretsViaJWT(JTWToken string, privateKey string, workspaceId string, environment string) ([]models.SingleEnvironmentVariable, error) { - // create http client - httpClient := resty.New(). - SetAuthToken(JTWToken). - SetHeader("Accept", "application/json") +// // get key first - var pullSecretsByInfisicalTokenResponse models.PullSecretsByInfisicalTokenResponse - response, err := httpClient. - R(). - SetQueryParam("environment", envName). - SetQueryParam("channel", "cli"). - SetResult(&pullSecretsByInfisicalTokenResponse). - Get(fmt.Sprintf("%v/v1/secret/%v/service-token", INFISICAL_URL, projectId)) +// // Get workspace key +// workspaceKey, err := base64.StdEncoding.DecodeString(pullSecretsRequestResponse.Key.EncryptedKey) +// if err != nil { +// return nil, err +// } - if err != nil { - return nil, err - } +// nonce, err := base64.StdEncoding.DecodeString(pullSecretsRequestResponse.Key.Nonce) +// if err != nil { +// return nil, err +// } - if response.StatusCode() > 299 { - return nil, fmt.Errorf(response.Status()) +// senderPublicKey, err := base64.StdEncoding.DecodeString(pullSecretsRequestResponse.Key.Sender.PublicKey) +// if err != nil { +// return nil, err +// } + +// currentUsersPrivateKey, err := base64.StdEncoding.DecodeString(userCreds.PrivateKey) +// if err != nil { +// return nil, err +// } + +// // log.Debugln("workspaceKey", workspaceKey, "nonce", nonce, "senderPublicKey", senderPublicKey, "currentUsersPrivateKey", currentUsersPrivateKey) +// workspaceKeyInBytes := crypto.DecryptAsymmetric(workspaceKey, nonce, senderPublicKey, currentUsersPrivateKey) + +// httpClient := resty.New() +// httpClient.SetAuthToken(JTWToken). +// SetHeader("Accept", "application/json") + +// serviceTokenDetails, err := http.CallGetServiceTokenDetailsV2(httpClient) +// if err != nil { +// return nil, fmt.Errorf("unable to get service token details. [err=%v]", err) +// } + +// encryptedSecrets, err := http.CallGetSecretsV2(httpClient, models.GetEncryptedSecretsV2Request{ +// WorkspaceId: workspaceId, +// EnvironmentName: environment, +// }) + +// if err != nil { +// return nil, err +// } + +// // workspace key + +// decodedSymmetricEncryptionDetails, err := GetBase64DecodedSymmetricEncryptionDetails(serviceTokenParts[3], serviceTokenDetails.EncryptedKey, serviceTokenDetails.Iv, serviceTokenDetails.Tag) +// if err != nil { +// return nil, fmt.Errorf("unable to decode symmetric encryption details [err=%v]", err) +// } + +// plainTextWorkspaceKey, err := crypto.DecryptSymmetric(decodedSymmetricEncryptionDetails.Key, decodedSymmetricEncryptionDetails.Cipher, decodedSymmetricEncryptionDetails.Tag, decodedSymmetricEncryptionDetails.IV) +// if err != nil { +// return nil, fmt.Errorf("unable to decrypt the required workspace key") +// } + +// plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecrets) +// if err != nil { +// return nil, fmt.Errorf("unable to decrypt your secrets [err=%v]", err) +// } + +// return plainTextSecrets, nil +// } + +func GetPlainTextSecretsViaServiceToken(fullServiceToken string) ([]models.SingleEnvironmentVariable, error) { + // encryotion key, http, + + serviceTokenParts := strings.SplitN(fullServiceToken, ".", 4) + if len(serviceTokenParts) < 4 { + return nil, fmt.Errorf("invalid service token entered. Please double check your service token and try again") } - // Get workspace key - workspaceKey, err := base64.StdEncoding.DecodeString(pullSecretsByInfisicalTokenResponse.Key.EncryptedKey) + serviceToken := fmt.Sprintf("%v.%v.%v", serviceTokenParts[0], serviceTokenParts[1], serviceTokenParts[2]) + + httpClient := resty.New() + httpClient.SetAuthToken(serviceToken). + SetHeader("Accept", "application/json") + + serviceTokenDetails, err := http.CallGetServiceTokenDetailsV2(httpClient) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to get service token details. [err=%v]", err) } - nonce, err := base64.StdEncoding.DecodeString(pullSecretsByInfisicalTokenResponse.Key.Nonce) + encryptedSecrets, err := http.CallGetSecretsV2(httpClient, models.GetEncryptedSecretsV2Request{ + WorkspaceId: serviceTokenDetails.Workspace, + EnvironmentName: serviceTokenDetails.Environment, + }) + if err != nil { return nil, err } - senderPublicKey, err := base64.StdEncoding.DecodeString(pullSecretsByInfisicalTokenResponse.Key.Sender.PublicKey) + decodedSymmetricEncryptionDetails, err := GetBase64DecodedSymmetricEncryptionDetails(serviceTokenParts[3], serviceTokenDetails.EncryptedKey, serviceTokenDetails.Iv, serviceTokenDetails.Tag) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to decode symmetric encryption details [err=%v]", err) } - currentUsersPrivateKey, err := base64.StdEncoding.DecodeString(temPrivateKey) + plainTextWorkspaceKey, err := crypto.DecryptSymmetric(decodedSymmetricEncryptionDetails.Key, decodedSymmetricEncryptionDetails.Cipher, decodedSymmetricEncryptionDetails.Tag, decodedSymmetricEncryptionDetails.IV) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to decrypt the required workspace key") } - // workspaceKeyInBytes, _ := box.Open(nil, workspaceKey, (*[24]byte)(nonce), (*[32]byte)(senderPublicKey), (*[32]byte)(currentUsersPrivateKey)) - workspaceKeyInBytes := DecryptAsymmetric(workspaceKey, nonce, senderPublicKey, currentUsersPrivateKey) - var listOfEnv []models.SingleEnvironmentVariable - - for _, secret := range pullSecretsByInfisicalTokenResponse.Secrets { - key_iv, _ := base64.StdEncoding.DecodeString(secret.SecretKey.Iv) - key_tag, _ := base64.StdEncoding.DecodeString(secret.SecretKey.Tag) - key_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretKey.Ciphertext) - - plainTextKey, err := DecryptSymmetric(workspaceKeyInBytes, key_ciphertext, key_tag, key_iv) - if err != nil { - return nil, err - } - - value_iv, _ := base64.StdEncoding.DecodeString(secret.SecretValue.Iv) - value_tag, _ := base64.StdEncoding.DecodeString(secret.SecretValue.Tag) - value_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretValue.Ciphertext) - - plainTextValue, err := DecryptSymmetric(workspaceKeyInBytes, value_ciphertext, value_tag, value_iv) - if err != nil { - return nil, err - } - - env := models.SingleEnvironmentVariable{ - Key: string(plainTextKey), - Value: string(plainTextValue), - Type: string(secret.Type), - ID: secret.ID, - } - - listOfEnv = append(listOfEnv, env) + plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecrets) + if err != nil { + return nil, fmt.Errorf("unable to decrypt your secrets [err=%v]", err) } - return listOfEnv, nil + return plainTextSecrets, nil } func GetAllEnvironmentVariables(projectId string, envName string) ([]models.SingleEnvironmentVariable, error) { @@ -246,14 +275,7 @@ func GetAllEnvironmentVariables(projectId string, envName string) ([]models.Sing return envsFromApi, nil } else { - envsFromApi, err := GetSecretsFromAPIUsingInfisicalToken(infisicalToken, envName, projectId) - if err != nil { - log.Errorln("Something went wrong when pulling secrets using your Infisical token. Double check the token, project id or environment name (dev, prod, ect.)") - log.Debugln(err) - return nil, err - } - - return envsFromApi, nil + return GetPlainTextSecretsViaServiceToken(infisicalToken) } } @@ -267,7 +289,7 @@ func GetWorkSpacesFromAPI(userCreds models.UserCredentials) (workspaces []models response, err := httpClient. R(). SetResult(&getWorkSpacesResponse). - Get(fmt.Sprintf("%v/v1/workspace", INFISICAL_URL)) + Get(fmt.Sprintf("%v/v1/workspace", config.INFISICAL_URL)) if err != nil { return nil, err @@ -389,16 +411,85 @@ func OverrideWithPersonalSecrets(secrets []models.SingleEnvironmentVariable) []m return secretsToReturn } -func IsSecretEnvironmentValid(env string) bool { - if env == "prod" || env == "dev" || env == "test" || env == "staging" { - return true - } - return false -} +func GetPlainTextSecrets(key []byte, encryptedSecrets models.GetEncryptedSecretsV2Response) ([]models.SingleEnvironmentVariable, error) { + plainTextSecrets := []models.SingleEnvironmentVariable{} + for _, secret := range encryptedSecrets { + // Decrypt key + key_iv, err := base64.StdEncoding.DecodeString(secret.SecretKeyIV) + if err != nil { + return nil, fmt.Errorf("unable to decode secret IV for secret key") + } -func IsSecretTypeValid(s string) bool { - if s == "personal" || s == "shared" { - return true + key_tag, err := base64.StdEncoding.DecodeString(secret.SecretKeyTag) + if err != nil { + return nil, fmt.Errorf("unable to decode secret authentication tag for secret key") + } + + key_ciphertext, err := base64.StdEncoding.DecodeString(secret.SecretKeyCiphertext) + if err != nil { + return nil, fmt.Errorf("unable to decode secret cipher text for secret key") + } + + plainTextKey, err := crypto.DecryptSymmetric(key, key_ciphertext, key_tag, key_iv) + if err != nil { + return nil, fmt.Errorf("unable to symmetrically decrypt secret key") + } + + // Decrypt value + value_iv, err := base64.StdEncoding.DecodeString(secret.SecretValueIV) + if err != nil { + return nil, fmt.Errorf("unable to decode secret IV for secret value") + } + + value_tag, err := base64.StdEncoding.DecodeString(secret.SecretValueTag) + if err != nil { + return nil, fmt.Errorf("unable to decode secret authentication tag for secret value") + } + + value_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretValueCiphertext) + if err != nil { + return nil, fmt.Errorf("unable to decode secret cipher text for secret key") + } + + plainTextValue, err := crypto.DecryptSymmetric(key, value_ciphertext, value_tag, value_iv) + if err != nil { + return nil, fmt.Errorf("unable to symmetrically decrypt secret value") + } + + plainTextSecret := models.SingleEnvironmentVariable{ + Key: string(plainTextKey), + Value: string(plainTextValue), + Type: string(secret.Type), + ID: secret.ID, + } + + plainTextSecrets = append(plainTextSecrets, plainTextSecret) } - return false + + return plainTextSecrets, nil } + +// func GetWorkspaceKeyViaEnvelopeEncryption(JTWToken string, workspaceId string, privateKey string) { +// httpClient := resty.New(). +// SetAuthToken(JTWToken). +// SetHeader("Accept", "application/json") + +// request := models.GetEncryptedWorkspaceKeyRequest{ +// WorkspaceId: workspaceId, +// } + +// workspaceKeyResponse, err := http.CallGetEncryptedWorkspaceKey(httpClient, request) +// if err != nil { +// log.Errorf("unable to get your encrypted workspace key. [err=%v]", err) +// return +// } + +// encryptedWorkspaceKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.EncryptedKey) +// encryptedWorkspaceKeySenderPublicKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Sender.PublicKey) +// encryptedWorkspaceKeyNonce, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Nonce) +// currentUsersPrivateKey, _ := base64.StdEncoding.DecodeString(loggedInUserDetails.UserCredentials.PrivateKey) + +// // decrypt workspace key +// plainTextEncryptionKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey) + +// }