allow to query for folders via path in backend, allow to filter by path in cli

This commit is contained in:
Maidul Islam
2023-04-07 11:27:42 -07:00
parent 75958d4d10
commit b4703c2e67
14 changed files with 297 additions and 79 deletions

View File

@@ -2,21 +2,38 @@ import { Request, Response } from 'express';
import { Secret } from '../../models';
import Folder from '../../models/folder';
import { BadRequestError } from '../../utils/errors';
import { ROOT_FOLDER_PATH, getFolderPath, getParentPath, normalizePath, validateFolderName } from '../../utils/folder';
// TODO
// verify workspace id/environment
export const createFolder = async (req: Request, res: Response) => {
const { workspaceId, environment, folderName, parentFolderId } = req.body
if (!validateFolderName(folderName)) {
throw BadRequestError({ message: "Folder name cannot contain spaces. Only underscore and dashes" })
}
if (parentFolderId) {
const parentFolder = await Folder.findById(parentFolderId);
const parentFolder = await Folder.find({ environment: environment, workspace: workspaceId, id: parentFolderId });
if (!parentFolder) {
throw BadRequestError({ message: "The parent folder doesn't exist" })
}
}
let completePath = await getFolderPath(parentFolderId)
if (completePath == ROOT_FOLDER_PATH) {
completePath = ""
}
const currentFolderPath = completePath + "/" + folderName // construct new path with current folder to be created
const normalizedCurrentPath = normalizePath(currentFolderPath)
const normalizedParentPath = getParentPath(normalizedCurrentPath)
const existingFolder = await Folder.findOne({
name: folderName,
workspace: workspaceId,
environment: environment,
parent: parentFolderId,
path: normalizedCurrentPath
});
if (existingFolder) {
@@ -28,6 +45,8 @@ export const createFolder = async (req: Request, res: Response) => {
workspace: workspaceId,
environment: environment,
parent: parentFolderId,
path: normalizedCurrentPath,
parentPath: normalizedParentPath
});
await newFolder.save();

View File

@@ -25,7 +25,7 @@ import {
BatchSecretRequest,
BatchSecret
} from '../../types/secret';
import { getFolderPath } from '../../utils/folder';
import { getFolderPath, getFoldersInDirectory, normalizePath } from '../../utils/folder';
import Folder from '../../models/folder';
/**
@@ -507,7 +507,7 @@ export const getSecrets = async (req: Request, res: Response) => {
#swagger.security = [{
"apiKeyAuth": []
}]
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
@@ -543,8 +543,9 @@ export const getSecrets = async (req: Request, res: Response) => {
const postHogClient = getPostHogClient();
const { workspaceId, environment, tagSlugs } = req.query;
const { folderId } = req.query
const { workspaceId, environment, tagSlugs, secretsPath } = req.query;
const normalizedPath = normalizePath(secretsPath as string)
const tagNamesList = typeof tagSlugs === 'string' && tagSlugs !== '' ? tagSlugs.split(',') : [];
let userId = "" // used for getting personal secrets for user
let userEmail = "" // used for posthog
@@ -602,10 +603,8 @@ export const getSecrets = async (req: Request, res: Response) => {
}
}
// query for secrets at root folder
if (folderId != undefined) {
secretQuery.folder = folderId == "" ? undefined : folderId
}
// Add path to secrets query
secretQuery.path = normalizedPath
if (hasWriteOnlyAccess) {
secrets = await Secret.find(secretQuery).select("secretKeyCiphertext secretKeyIV secretKeyTag")
@@ -630,14 +629,7 @@ export const getSecrets = async (req: Request, res: Response) => {
ipAddress: req.ip
});
let folders: any[] = []
if (folderId != undefined) {
folders = await Folder.find({
workspace: workspaceId,
environment: environment,
parent: folderId == "" ? undefined : folderId // undefined means root
})
}
const folders = await getFoldersInDirectory(workspaceId as string, environment as string, normalizedPath)
if (postHogClient) {
postHogClient.capture({

View File

@@ -19,6 +19,14 @@ const folderSchema = new Schema({
ref: 'Folder',
required: false, // optional for root folders
},
path: {
type: String,
required: true
},
parentPath: {
type: String,
required: true,
},
}, {
timestamps: true
});

View File

@@ -1,5 +1,7 @@
import Folder from "../models/folder";
export const ROOT_FOLDER_PATH = "/"
export const getFolderPath = async (folderId: string) => {
let currentFolder = await Folder.findById(folderId);
const pathSegments = [];
@@ -10,4 +12,76 @@ export const getFolderPath = async (folderId: string) => {
}
return '/' + pathSegments.join('/');
};
};
/**
Returns the folder ID associated with the specified secret path in the given workspace and environment.
@param workspaceId - The ID of the workspace to search in.
@param environment - The environment to search in.
@param secretPath - The secret path to search for.
@returns The folder ID associated with the specified secret path, or undefined if the path is at the root folder level.
@throws Error if the specified secret path is not found.
*/
export const getFolderIdFromPath = async (workspaceId: string, environment: string, secretPath: string) => {
const secretPathParts = secretPath.split("/").filter(path => path != "")
if (secretPathParts.length <= 1) {
return undefined // root folder, so no folder id
}
const folderId = await Folder.find({ path: secretPath, workspace: workspaceId, environment: environment })
if (!folderId) {
throw Error("Secret path not found")
}
return folderId
}
/**
* Cleans up a path by removing empty parts, duplicate slashes,
* and ensuring it starts with ROOT_FOLDER_PATH.
* @param path - The input path to clean up.
* @returns The cleaned-up path string.
*/
export const normalizePath = (path: string) => {
if (path == undefined || path == "" || path == ROOT_FOLDER_PATH) {
return ROOT_FOLDER_PATH
}
const pathParts = path.split("/").filter(part => part != "")
const cleanPathString = ROOT_FOLDER_PATH + pathParts.join("/")
return cleanPathString
}
export const getFoldersInDirectory = async (workspaceId: string, environment: string, pathString: string) => {
const normalizedPath = normalizePath(pathString)
const foldersInDirectory = await Folder.find({
workspace: workspaceId,
environment: environment,
parentPath: normalizedPath,
});
return foldersInDirectory;
}
/**
* Returns the parent path of the given path.
* @param path - The input path.
* @returns The parent path string.
*/
export const getParentPath = (path: string) => {
const normalizedPath = normalizePath(path);
const folderParts = normalizedPath.split('/').filter(part => part !== '');
let folderParent = ROOT_FOLDER_PATH;
if (folderParts.length > 1) {
folderParent = ROOT_FOLDER_PATH + folderParts.slice(0, folderParts.length - 1).join('/');
}
return folderParent;
}
export const validateFolderName = (folderName: string) => {
const validNameRegex = /^[a-zA-Z0-9-_]+$/;
return validNameRegex.test(folderName);
}

View File

@@ -115,6 +115,7 @@ func CallGetSecretsV2(httpClient *resty.Client, request GetEncryptedSecretsV2Req
SetQueryParam("environment", request.Environment).
SetQueryParam("workspaceId", request.WorkspaceId).
SetQueryParam("tagSlugs", request.TagSlugs).
SetQueryParam("secretsPath", request.SecretPath).
Get(fmt.Sprintf("%v/v2/secrets", config.INFISICAL_URL))
if err != nil {

View File

@@ -198,35 +198,51 @@ type GetEncryptedSecretsV2Request struct {
Environment string `json:"environment"`
WorkspaceId string `json:"workspaceId"`
TagSlugs string `json:"tagSlugs"`
SecretPath string `json:"secretPath"`
FolderId string `json:"folderId"`
}
type Folders struct {
ID string `json:"_id"`
Name string `json:"name"`
Workspace string `json:"workspace"`
Environment string `json:"environment"`
Parent string `json:"parent"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
type Secrets 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"`
SecretValueCiphertext string `json:"secretValueCiphertext"`
SecretValueIV string `json:"secretValueIV"`
SecretValueTag string `json:"secretValueTag"`
SecretCommentCiphertext string `json:"secretCommentCiphertext"`
SecretCommentIV string `json:"secretCommentIV"`
SecretCommentTag string `json:"secretCommentTag"`
V int `json:"__v"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
User string `json:"user,omitempty"`
Tags []struct {
ID string `json:"_id"`
Name string `json:"name"`
Slug string `json:"slug"`
Workspace string `json:"workspace"`
} `json:"tags"`
}
type GetEncryptedSecretsV2Response struct {
Secrets []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"`
SecretValueCiphertext string `json:"secretValueCiphertext"`
SecretValueIV string `json:"secretValueIV"`
SecretValueTag string `json:"secretValueTag"`
SecretCommentCiphertext string `json:"secretCommentCiphertext"`
SecretCommentIV string `json:"secretCommentIV"`
SecretCommentTag string `json:"secretCommentTag"`
V int `json:"__v"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
User string `json:"user,omitempty"`
Tags []struct {
ID string `json:"_id"`
Name string `json:"name"`
Slug string `json:"slug"`
Workspace string `json:"workspace"`
} `json:"tags"`
} `json:"secrets"`
Secrets []Secrets `json:"secrets"`
Folders []Folders `json:"folders"`
}
type GetServiceTokenDetailsResponse struct {

View File

@@ -74,7 +74,12 @@ var exportCmd = &cobra.Command{
util.HandleError(err, "Unable to parse flag")
}
secrets, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, InfisicalToken: infisicalToken, TagSlugs: tagSlugs, WorkspaceId: projectId})
secretsPath, err := cmd.Flags().GetString("path")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
secrets, _, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, InfisicalToken: infisicalToken, TagSlugs: tagSlugs, WorkspaceId: projectId, Path: secretsPath})
if err != nil {
util.HandleError(err, "Unable to fetch secrets")
}
@@ -112,6 +117,7 @@ func init() {
exportCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
exportCmd.Flags().StringP("tags", "t", "", "filter secrets by tag slugs")
exportCmd.Flags().String("projectId", "", "manually set the projectId to fetch secrets from")
exportCmd.Flags().String("path", "/", "The path to the folder where secrets are located. Defaults to root folder")
}
// Format according to the format flag

View File

@@ -82,7 +82,12 @@ var runCmd = &cobra.Command{
util.HandleError(err, "Unable to parse flag")
}
secrets, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, InfisicalToken: infisicalToken, TagSlugs: tagSlugs})
secretsPath, err := cmd.Flags().GetString("path")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
secrets, _, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, InfisicalToken: infisicalToken, TagSlugs: tagSlugs, Path: secretsPath})
if err != nil {
util.HandleError(err, "Could not fetch secrets", "If you are using a service token to fetch secrets, please ensure it is valid")
@@ -182,6 +187,7 @@ func init() {
runCmd.Flags().Bool("secret-overriding", true, "Prioritizes personal secrets, if any, with the same name over shared secrets")
runCmd.Flags().StringP("command", "c", "", "chained commands to execute (e.g. \"npm install && npm run dev; echo ...\")")
runCmd.Flags().StringP("tags", "t", "", "filter secrets by tag slugs ")
runCmd.Flags().String("path", "/", "The path to the folder where secrets are located. Defaults to root folder")
}
// Will execute a single command and pass in the given secrets into the process

View File

@@ -44,6 +44,11 @@ var secretsCmd = &cobra.Command{
util.HandleError(err, "Unable to parse flag")
}
secretsPath, err := cmd.Flags().GetString("path")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
shouldExpandSecrets, err := cmd.Flags().GetBool("expand")
if err != nil {
util.HandleError(err)
@@ -54,7 +59,8 @@ var secretsCmd = &cobra.Command{
util.HandleError(err, "Unable to parse flag")
}
secrets, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, InfisicalToken: infisicalToken, TagSlugs: tagSlugs})
normalizedPath := util.NormalizePath(secretsPath)
secrets, folders, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, InfisicalToken: infisicalToken, TagSlugs: tagSlugs, Path: normalizedPath})
if err != nil {
util.HandleError(err)
}
@@ -63,6 +69,10 @@ var secretsCmd = &cobra.Command{
secrets = util.SubstituteSecrets(secrets)
}
if len(folders) > 0 {
visualize.PrintSecretFolders(folders)
}
visualize.PrintAllSecretDetails(secrets)
},
}
@@ -142,7 +152,7 @@ var secretsSetCmd = &cobra.Command{
plainTextEncryptionKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey)
// pull current secrets
secrets, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName})
secrets, _, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName})
if err != nil {
util.HandleError(err, "unable to retrieve secrets")
}
@@ -263,13 +273,14 @@ var secretsSetCmd = &cobra.Command{
}
// Print secret operations
headers := [...]string{"SECRET NAME", "SECRET VALUE", "STATUS"}
rows := [][3]string{}
secretHeaders := [...]string{"SECRET NAME", "SECRET VALUE", "STATUS"}
secretRows := [][3]string{}
for _, secretOperation := range secretOperations {
rows = append(rows, [...]string{secretOperation.SecretKey, secretOperation.SecretValue, secretOperation.SecretOperation})
secretRows = append(secretRows, [...]string{secretOperation.SecretKey, secretOperation.SecretValue, secretOperation.SecretOperation})
}
visualize.Table(headers, rows)
// visualize.PrintSecretFolders()
visualize.SecretsTable(secretHeaders, secretRows)
},
}
@@ -299,11 +310,13 @@ var secretsDeleteCmd = &cobra.Command{
util.HandleError(err, "Unable to get local project details")
}
secrets, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName})
secrets, folders, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName})
if err != nil {
util.HandleError(err, "Unable to fetch secrets")
}
fmt.Println("folders===>", folders)
secretByKey := getSecretsByKeys(secrets)
validSecretIdsToDelete := []string{}
invalidSecretNamesThatDoNotExist := []string{}
@@ -360,11 +373,13 @@ func getSecretsByNames(cmd *cobra.Command, args []string) {
util.HandleError(err, "Unable to parse flag")
}
secrets, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, InfisicalToken: infisicalToken, TagSlugs: tagSlugs})
secrets, folders, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, InfisicalToken: infisicalToken, TagSlugs: tagSlugs})
if err != nil {
util.HandleError(err, "To fetch all secrets")
}
fmt.Println("folders===>", folders)
requestedSecrets := []models.SingleEnvironmentVariable{}
secretsMap := getSecretsByKeys(secrets)
@@ -403,11 +418,13 @@ func generateExampleEnv(cmd *cobra.Command, args []string) {
util.HandleError(err, "Unable to parse flag")
}
secrets, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, InfisicalToken: infisicalToken, TagSlugs: tagSlugs})
secrets, folders, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, InfisicalToken: infisicalToken, TagSlugs: tagSlugs})
if err != nil {
util.HandleError(err, "To fetch all secrets")
}
fmt.Println("folders===>", folders)
tagsHashToSecretKey := make(map[string]int)
slugsToFilerBy := make(map[string]int)
@@ -602,6 +619,7 @@ func getSecretsByKeys(secrets []models.SingleEnvironmentVariable) map[string]mod
func init() {
secretsGenerateExampleEnvCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
secretsCmd.Flags().String("path", "/", "The path to the folder where secrets are located. Defaults to root folder")
secretsCmd.AddCommand(secretsGenerateExampleEnvCmd)
secretsGetCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")

View File

@@ -56,4 +56,5 @@ type GetAllSecretsParameters struct {
InfisicalToken string
TagSlugs string
WorkspaceId string
Path string
}

View File

@@ -137,3 +137,36 @@ func getCurrentBranch() (string, error) {
}
return path.Base(strings.TrimSpace(out.String())), nil
}
func GetSplitPathByDash(path string) []string {
pathParts := strings.Split(path, "/")
var filteredPathParts []string
for _, s := range pathParts {
if s != "" {
filteredPathParts = append(filteredPathParts, s)
}
}
return filteredPathParts
}
// NormalizePath cleans up a path by removing empty parts, duplicate slashes,
// and ensuring it starts with ROOT_FOLDER_PATH.
func NormalizePath(path string) string {
ROOT_FOLDER_PATH := "/"
if path == "" || path == ROOT_FOLDER_PATH {
return ROOT_FOLDER_PATH
}
pathParts := strings.Split(path, "/")
nonEmptyParts := []string{}
for _, part := range pathParts {
if part != "" {
nonEmptyParts = append(nonEmptyParts, part)
}
}
cleanPathString := ROOT_FOLDER_PATH + strings.Join(nonEmptyParts, "/")
return cleanPathString
}

View File

@@ -17,10 +17,10 @@ import (
"github.com/go-resty/resty/v2"
)
func GetPlainTextSecretsViaServiceToken(fullServiceToken string) ([]models.SingleEnvironmentVariable, error) {
func GetPlainTextSecretsViaServiceToken(fullServiceToken string) ([]models.SingleEnvironmentVariable, []api.Folders, error) {
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")
return nil, nil, fmt.Errorf("invalid service token entered. Please double check your service token and try again")
}
serviceToken := fmt.Sprintf("%v.%v.%v", serviceTokenParts[0], serviceTokenParts[1], serviceTokenParts[2])
@@ -32,7 +32,7 @@ func GetPlainTextSecretsViaServiceToken(fullServiceToken string) ([]models.Singl
serviceTokenDetails, err := api.CallGetServiceTokenDetailsV2(httpClient)
if err != nil {
return nil, fmt.Errorf("unable to get service token details. [err=%v]", err)
return nil, nil, fmt.Errorf("unable to get service token details. [err=%v]", err)
}
encryptedSecrets, err := api.CallGetSecretsV2(httpClient, api.GetEncryptedSecretsV2Request{
@@ -41,28 +41,28 @@ func GetPlainTextSecretsViaServiceToken(fullServiceToken string) ([]models.Singl
})
if err != nil {
return nil, err
return nil, nil, err
}
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)
return nil, nil, fmt.Errorf("unable to decode symmetric encryption details [err=%v]", err)
}
plainTextWorkspaceKey, err := crypto.DecryptSymmetric([]byte(serviceTokenParts[3]), decodedSymmetricEncryptionDetails.Cipher, decodedSymmetricEncryptionDetails.Tag, decodedSymmetricEncryptionDetails.IV)
if err != nil {
return nil, fmt.Errorf("unable to decrypt the required workspace key")
return nil, 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 nil, nil, fmt.Errorf("unable to decrypt your secrets [err=%v]", err)
}
return plainTextSecrets, nil
return plainTextSecrets, encryptedSecrets.Folders, nil
}
func GetPlainTextSecretsViaJTW(JTWToken string, receiversPrivateKey string, workspaceId string, environmentName string, tagSlugs string) ([]models.SingleEnvironmentVariable, error) {
func GetPlainTextSecretsViaJTW(JTWToken string, receiversPrivateKey string, workspaceId string, environmentName string, tagSlugs string, secretPath string) ([]models.SingleEnvironmentVariable, []api.Folders, error) {
httpClient := resty.New()
httpClient.SetAuthToken(JTWToken).
SetHeader("Accept", "application/json")
@@ -73,7 +73,7 @@ func GetPlainTextSecretsViaJTW(JTWToken string, receiversPrivateKey string, work
workspaceKeyResponse, err := api.CallGetEncryptedWorkspaceKey(httpClient, request)
if err != nil {
return nil, fmt.Errorf("unable to get your encrypted workspace key. [err=%v]", err)
return nil, nil, fmt.Errorf("unable to get your encrypted workspace key. [err=%v]", err)
}
encryptedWorkspaceKey, err := base64.StdEncoding.DecodeString(workspaceKeyResponse.EncryptedKey)
@@ -103,25 +103,26 @@ func GetPlainTextSecretsViaJTW(JTWToken string, receiversPrivateKey string, work
plainTextWorkspaceKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey)
encryptedSecrets, err := api.CallGetSecretsV2(httpClient, api.GetEncryptedSecretsV2Request{
encryptedSecretsAndFolders, err := api.CallGetSecretsV2(httpClient, api.GetEncryptedSecretsV2Request{
WorkspaceId: workspaceId,
Environment: environmentName,
TagSlugs: tagSlugs,
SecretPath: secretPath,
})
if err != nil {
return nil, err
return nil, nil, err
}
plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecrets)
plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecretsAndFolders)
if err != nil {
return nil, fmt.Errorf("unable to decrypt your secrets [err=%v]", err)
return nil, nil, fmt.Errorf("unable to decrypt your secrets [err=%v]", err)
}
return plainTextSecrets, nil
return plainTextSecrets, encryptedSecretsAndFolders.Folders, nil
}
func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models.SingleEnvironmentVariable, error) {
func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models.SingleEnvironmentVariable, []api.Folders, error) {
var infisicalToken string
if params.InfisicalToken == "" {
infisicalToken = os.Getenv(INFISICAL_TOKEN_NAME)
@@ -132,6 +133,7 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models
isConnected := CheckIsConnectedToInternet()
var secretsToReturn []models.SingleEnvironmentVariable
var errorToReturn error
var folders []api.Folders
if infisicalToken == "" {
if isConnected {
@@ -144,12 +146,12 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models
loggedInUserDetails, err := GetCurrentLoggedInUserDetails()
if err != nil {
return nil, err
return nil, nil, err
}
workspaceFile, err := GetWorkSpaceFromFile()
if err != nil {
return nil, err
return nil, nil, err
}
if params.WorkspaceId != "" {
@@ -159,10 +161,10 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models
// Verify environment
err = ValidateEnvironmentName(params.Environment, workspaceFile.WorkspaceId, loggedInUserDetails.UserCredentials)
if err != nil {
return nil, fmt.Errorf("unable to validate environment name because [err=%s]", err)
return nil, nil, fmt.Errorf("unable to validate environment name because [err=%s]", err)
}
secretsToReturn, errorToReturn = GetPlainTextSecretsViaJTW(loggedInUserDetails.UserCredentials.JTWToken, loggedInUserDetails.UserCredentials.PrivateKey, workspaceFile.WorkspaceId, params.Environment, params.TagSlugs)
secretsToReturn, folders, errorToReturn = GetPlainTextSecretsViaJTW(loggedInUserDetails.UserCredentials.JTWToken, loggedInUserDetails.UserCredentials.PrivateKey, workspaceFile.WorkspaceId, params.Environment, params.TagSlugs, params.Path)
log.Debugf("GetAllEnvironmentVariables: Trying to fetch secrets JTW token [err=%s]", errorToReturn)
backupSecretsEncryptionKey := []byte(loggedInUserDetails.UserCredentials.PrivateKey)[0:32]
@@ -182,10 +184,10 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models
} else {
log.Debug("Trying to fetch secrets using service token")
secretsToReturn, errorToReturn = GetPlainTextSecretsViaServiceToken(infisicalToken)
secretsToReturn, folders, errorToReturn = GetPlainTextSecretsViaServiceToken(infisicalToken)
}
return secretsToReturn, errorToReturn
return secretsToReturn, folders, errorToReturn
}
func ValidateEnvironmentName(environmentName string, workspaceId string, userLoggedInDetails models.UserCredentials) error {

View File

@@ -1,6 +1,9 @@
package visualize
import "github.com/Infisical/infisical-merge/packages/models"
import (
"github.com/Infisical/infisical-merge/packages/api"
"github.com/Infisical/infisical-merge/packages/models"
)
func PrintAllSecretDetails(secrets []models.SingleEnvironmentVariable) {
rows := [][3]string{}
@@ -10,5 +13,16 @@ func PrintAllSecretDetails(secrets []models.SingleEnvironmentVariable) {
headers := [...]string{"SECRET NAME", "SECRET VALUE", "SECRET TYPE"}
SecretsTable(headers, rows)
}
func PrintSecretFolders(folders []api.Folders) {
rows := [][]string{}
for _, folder := range folders {
rows = append(rows, []string{folder.Name})
}
headers := []string{"FOLDER NAME(S)"}
Table(headers, rows)
}

View File

@@ -29,8 +29,36 @@ const (
ellipsis = "…"
)
// Given any number of headers and rows, this function will print out a table
func Table(headers []string, rows [][]string) {
t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.SetStyle(table.StyleLight)
// t.SetTitle("Title")
t.Style().Options.DrawBorder = true
t.Style().Options.SeparateHeader = true
t.Style().Options.SeparateColumns = true
tableHeaders := table.Row{}
for _, header := range headers {
tableHeaders = append(tableHeaders, header)
}
t.AppendHeader(tableHeaders)
for _, row := range rows {
tableRow := table.Row{}
for _, val := range row {
tableRow = append(tableRow, val)
}
t.AppendRow(tableRow)
}
t.Render()
}
// Given headers and rows, this function will print out a table
func Table(headers [3]string, rows [][3]string) {
func SecretsTable(headers [3]string, rows [][3]string) {
// if we're not in a terminal or cygwin terminal, don't truncate the secret value
shouldTruncate := isatty.IsTerminal(os.Stdout.Fd())