From a37cf9170283dd8bd4c6e2c60bb6db0c8c0287ea Mon Sep 17 00:00:00 2001 From: Adam Rashid Date: Tue, 7 Feb 2023 21:35:13 +0800 Subject: [PATCH 1/8] fix: handle duplicate edge case for sidebar loading This changes the SideBar's data prop to be filtered by id instead of key. fixes issue #308 --- frontend/src/pages/dashboard/[id].tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/dashboard/[id].tsx b/frontend/src/pages/dashboard/[id].tsx index d5b26c2f5a..180fc493f9 100644 --- a/frontend/src/pages/dashboard/[id].tsx +++ b/frontend/src/pages/dashboard/[id].tsx @@ -549,7 +549,7 @@ export default function Dashboard() { toggleSidebar={toggleSidebar} data={data.filter( (row: SecretDataProps) => - row.key === data.filter((r) => r.id === sidebarSecretId)[0]?.key + row.id === sidebarSecretId )} modifyKey={listenChangeKey} modifyValue={listenChangeValue} From b0c541f8dc07d518065e194b0c1478e79c11ddee Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Wed, 8 Feb 2023 13:46:57 -0800 Subject: [PATCH 2/8] generate example .env file command --- cli/packages/api/model.go | 39 +++++--- cli/packages/cmd/secrets.go | 183 ++++++++++++++++++++++++++++++++++- cli/packages/models/cli.go | 11 ++- cli/packages/util/helper.go | 12 +++ cli/packages/util/log.go | 2 +- cli/packages/util/secrets.go | 31 +++++- 6 files changed, 256 insertions(+), 22 deletions(-) diff --git a/cli/packages/api/model.go b/cli/packages/api/model.go index 698d414084..8f929bf697 100644 --- a/cli/packages/api/model.go +++ b/cli/packages/api/model.go @@ -201,21 +201,30 @@ type GetEncryptedSecretsV2Request struct { 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"` - V int `json:"__v"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - User string `json:"user,omitempty"` + 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"` } diff --git a/cli/packages/cmd/secrets.go b/cli/packages/cmd/secrets.go index c5fb11c1eb..a1a8916fd9 100644 --- a/cli/packages/cmd/secrets.go +++ b/cli/packages/cmd/secrets.go @@ -6,6 +6,8 @@ package cmd import ( "encoding/base64" "fmt" + "regexp" + "sort" "strings" "unicode" @@ -22,7 +24,7 @@ import ( ) var secretsCmd = &cobra.Command{ - Example: `infisical secrets"`, + Example: `infisical secrets`, Short: "Used to create, read update and delete secrets", Use: "secrets", DisableFlagsInUseLine: true, @@ -67,6 +69,16 @@ var secretsGetCmd = &cobra.Command{ Run: getSecretsByNames, } +var secretsGenerateExampleEnvCmd = &cobra.Command{ + Example: `secrets generate-example-env > .example-env`, + Short: "Used to generate a example .env file", + Use: "generate-example-env", + DisableFlagsInUseLine: true, + Args: cobra.NoArgs, + PreRun: toggleDebug, + Run: generateExampleEnv, +} + var secretsSetCmd = &cobra.Command{ Example: `secrets set ..."`, Short: "Used set secrets", @@ -357,6 +369,171 @@ func getSecretsByNames(cmd *cobra.Command, args []string) { visualize.PrintAllSecretDetails(requestedSecrets) } +func generateExampleEnv(cmd *cobra.Command, args []string) { + environmentName, err := cmd.Flags().GetString("env") + if err != nil { + util.HandleError(err, "Unable to parse flag") + } + + workspaceFileExists := util.WorkspaceConfigFileExistsInCurrentPath() + if !workspaceFileExists { + util.HandleError(err, "Unable to parse flag") + } + + infisicalToken, err := cmd.Flags().GetString("token") + if err != nil { + util.HandleError(err, "Unable to parse flag") + } + + secrets, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, InfisicalToken: infisicalToken}) + if err != nil { + util.HandleError(err, "To fetch all secrets") + } + + tagsHashToSecretKey := make(map[string]int) + + type TagsAndSecrets struct { + Secrets []models.SingleEnvironmentVariable + Tags []struct { + ID string `json:"_id"` + Name string `json:"name"` + Slug string `json:"slug"` + Workspace string `json:"workspace"` + } + } + + // sort secrets by associated tags (most number of tags to least tags) + sort.Slice(secrets, func(i, j int) bool { + return len(secrets[i].Tags) > len(secrets[j].Tags) + }) + + for _, secret := range secrets { + listOfTagSlugs := []string{} + + for _, tag := range secret.Tags { + listOfTagSlugs = append(listOfTagSlugs, tag.Slug) + } + sort.Strings(listOfTagSlugs) + + tagsHash := util.GetHashFromStringList(listOfTagSlugs) + + tagsHashToSecretKey[tagsHash] += 1 + } + + finalTagHashToSecretKey := make(map[string]TagsAndSecrets) + + for _, secret := range secrets { + listOfTagSlugs := []string{} + for _, tag := range secret.Tags { + listOfTagSlugs = append(listOfTagSlugs, tag.Slug) + } + + // sort the slug so we get the same hash each time + sort.Strings(listOfTagSlugs) + + tagsHash := util.GetHashFromStringList(listOfTagSlugs) + occurrence, exists := tagsHashToSecretKey[tagsHash] + if exists && occurrence > 0 { + + value, exists2 := finalTagHashToSecretKey[tagsHash] + allSecretsForTags := append(value.Secrets, secret) + + // sort the the secrets by keys so that they can later be sorted by the first item in the secrets array + sort.Slice(allSecretsForTags, func(i, j int) bool { + return allSecretsForTags[i].Key < allSecretsForTags[j].Key + }) + + if exists2 { + finalTagHashToSecretKey[tagsHash] = TagsAndSecrets{ + Tags: secret.Tags, + Secrets: allSecretsForTags, + } + } else { + finalTagHashToSecretKey[tagsHash] = TagsAndSecrets{ + Tags: secret.Tags, + Secrets: []models.SingleEnvironmentVariable{secret}, + } + } + + tagsHashToSecretKey[tagsHash] -= 1 + } + } + + // sort the fianl result by secret key fo consistent print order + listOfsecretDetails := make([]TagsAndSecrets, 0, len(finalTagHashToSecretKey)) + for _, secretDetails := range finalTagHashToSecretKey { + listOfsecretDetails = append(listOfsecretDetails, secretDetails) + } + + // sort the order of the headings by the order of the secrets + sort.Slice(listOfsecretDetails, func(i, j int) bool { + return len(listOfsecretDetails[i].Tags) < len(listOfsecretDetails[j].Tags) + }) + + for _, secretDetails := range listOfsecretDetails { + listOfKeyValue := []string{} + + for _, secret := range secretDetails.Secrets { + re := regexp.MustCompile(`(.*)DEFAULT:(.*)`) + match := re.FindStringSubmatch(secret.Comment) + defaultValue := "" + comment := secret.Comment + + // Case: Only has default value + if len(match) == 2 { + defaultValue = strings.TrimSpace(match[1]) + } + + // Case: has a comment and a default value + if len(match) == 3 { + comment = match[1] + defaultValue = match[2] + } + + row := "" + if comment != "" { + comment = addHash(comment) + row = fmt.Sprintf("%s \n%s=%s", strings.TrimSpace(comment), strings.TrimSpace(secret.Key), strings.TrimSpace(defaultValue)) + } else { + row = fmt.Sprintf("%s=%s", strings.TrimSpace(secret.Key), strings.TrimSpace(defaultValue)) + } + + // each secret row to be added to the file + listOfKeyValue = append(listOfKeyValue, row) + } + + listOfTagNames := []string{} + for _, tag := range secretDetails.Tags { + listOfTagNames = append(listOfTagNames, tag.Name) + } + + heading := CenterString(strings.Join(listOfTagNames, " & "), 80) + + if len(listOfTagNames) == 0 { + fmt.Printf("\n%s \n", strings.Join(listOfKeyValue, "\n \n")) + } else { + fmt.Printf("\n\n\n%s\n \n%s \n", heading, strings.Join(listOfKeyValue, "\n \n")) + } + } +} + +func CenterString(s string, numStars int) string { + stars := strings.Repeat("*", numStars) + padding := (numStars - len(s)) / 2 + cenetredTextWithStar := stars[:padding] + " " + strings.ToUpper(s) + " " + stars[padding:] + + hashes := strings.Repeat("#", len(cenetredTextWithStar)+2) + return fmt.Sprintf("%s \n# %s \n%s", hashes, cenetredTextWithStar, hashes) +} + +func addHash(input string) string { + lines := strings.Split(input, "\n") + for i, line := range lines { + lines[i] = "# " + line + } + return strings.Join(lines, "\n") +} + func getSecretsByKeys(secrets []models.SingleEnvironmentVariable) map[string]models.SingleEnvironmentVariable { secretMapByName := make(map[string]models.SingleEnvironmentVariable) @@ -368,6 +545,10 @@ func getSecretsByKeys(secrets []models.SingleEnvironmentVariable) map[string]mod } func init() { + + secretsGenerateExampleEnvCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token") + secretsCmd.AddCommand(secretsGenerateExampleEnvCmd) + secretsGetCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token") secretsCmd.AddCommand(secretsGetCmd) diff --git a/cli/packages/models/cli.go b/cli/packages/models/cli.go index 67b89b27fe..3ffc1cc20f 100644 --- a/cli/packages/models/cli.go +++ b/cli/packages/models/cli.go @@ -1,6 +1,8 @@ package models -import "github.com/99designs/keyring" +import ( + "github.com/99designs/keyring" +) type UserCredentials struct { Email string `json:"email"` @@ -19,6 +21,13 @@ type SingleEnvironmentVariable struct { Value string `json:"value"` Type string `json:"type"` ID string `json:"_id"` + Tags []struct { + ID string `json:"_id"` + Name string `json:"name"` + Slug string `json:"slug"` + Workspace string `json:"workspace"` + } `json:"tags"` + Comment string `json:"comment"` } type Workspace struct { diff --git a/cli/packages/util/helper.go b/cli/packages/util/helper.go index a6e7e35fc1..3fd8853c4a 100644 --- a/cli/packages/util/helper.go +++ b/cli/packages/util/helper.go @@ -1,6 +1,7 @@ package util import ( + "crypto/sha256" "encoding/base64" "fmt" "os" @@ -98,3 +99,14 @@ func RequireLocalWorkspaceFile() { PrintMessageAndExit("Your project id is missing in your local config file. Please add it or run again [infisical init]") } } + +func GetHashFromStringList(list []string) string { + hash := sha256.New() + + for _, item := range list { + hash.Write([]byte(item)) + } + + sum := sha256.Sum256(hash.Sum(nil)) + return fmt.Sprintf("%x", sum) +} diff --git a/cli/packages/util/log.go b/cli/packages/util/log.go index a701987fc2..b191f33c82 100644 --- a/cli/packages/util/log.go +++ b/cli/packages/util/log.go @@ -24,7 +24,7 @@ func PrintErrorAndExit(exitCode int, err error, messages ...string) { } func PrintWarning(message string) { - color.Yellow("Warning: %v", message) + color.New(color.FgYellow).Fprintf(os.Stderr, "Warning: %v \n", message) } func PrintMessageAndExit(messages ...string) { diff --git a/cli/packages/util/secrets.go b/cli/packages/util/secrets.go index 86f4a5e05a..7a4bc09dbc 100644 --- a/cli/packages/util/secrets.go +++ b/cli/packages/util/secrets.go @@ -315,11 +315,34 @@ func GetPlainTextSecrets(key []byte, encryptedSecrets api.GetEncryptedSecretsV2R return nil, fmt.Errorf("unable to symmetrically decrypt secret value") } + // Decrypt comment + comment_iv, err := base64.StdEncoding.DecodeString(secret.SecretCommentIV) + if err != nil { + return nil, fmt.Errorf("unable to decode secret IV for secret value") + } + + comment_tag, err := base64.StdEncoding.DecodeString(secret.SecretCommentTag) + if err != nil { + return nil, fmt.Errorf("unable to decode secret authentication tag for secret value") + } + + comment_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretCommentCiphertext) + if err != nil { + return nil, fmt.Errorf("unable to decode secret cipher text for secret key") + } + + plainTextComment, err := crypto.DecryptSymmetric(key, comment_ciphertext, comment_tag, comment_iv) + if err != nil { + return nil, fmt.Errorf("unable to symmetrically decrypt secret comment") + } + plainTextSecret := models.SingleEnvironmentVariable{ - Key: string(plainTextKey), - Value: string(plainTextValue), - Type: string(secret.Type), - ID: secret.ID, + Key: string(plainTextKey), + Value: string(plainTextValue), + Type: string(secret.Type), + ID: secret.ID, + Tags: secret.Tags, + Comment: string(plainTextComment), } plainTextSecrets = append(plainTextSecrets, plainTextSecret) From 80a3c196aea705fccc5b19d8d3f698b1391c1195 Mon Sep 17 00:00:00 2001 From: Vladyslav Matsiiako Date: Wed, 8 Feb 2023 14:32:57 -0800 Subject: [PATCH 3/8] Fixed errors with undefined tags --- .../src/components/dashboard/AddTagsMenu.tsx | 16 +++++++++------- frontend/src/components/dashboard/KeyPair.tsx | 2 +- frontend/src/pages/dashboard/[id].tsx | 9 ++++----- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/dashboard/AddTagsMenu.tsx b/frontend/src/components/dashboard/AddTagsMenu.tsx index 1b07900791..b0f6b1a228 100644 --- a/frontend/src/components/dashboard/AddTagsMenu.tsx +++ b/frontend/src/components/dashboard/AddTagsMenu.tsx @@ -6,10 +6,12 @@ import { Menu, Transition } from '@headlessui/react'; import { Tag } from 'public/data/frequentInterfaces'; /** - * This is the menu that is used to download secrets as .env ad .yml files (in future we may have more options) + * This is the menu that is used to add more tags to a secret * @param {object} obj - * @param {SecretDataProps[]} obj.data - - * + * @param {Tag[]} obj.allTags - all available tags for a vertain project + * @param {Tag[]} obj.currentTags - currently selected tags for a certain secret + * @param {function} obj.modifyTags - modify tags for a certain secret + * @param {Tag[]} obj.position - currently selected tags for a certain secret */ const AddTagsMenu = ({ allTags, currentTags, modifyTags, position }: { allTags: Tag[]; currentTags: Tag[]; modifyTags: (value: Tag[], position: number) => void; position: number; }) => { const router = useRouter(); @@ -21,7 +23,7 @@ const AddTagsMenu = ({ allTags, currentTags, modifyTags, position }: { allTags: >
- {currentTags.length > 2 && {currentTags.length - 2}} + {currentTags?.length > 2 && {currentTags.length - 2}}
)})} diff --git a/frontend/src/components/dashboard/KeyPair.tsx b/frontend/src/components/dashboard/KeyPair.tsx index 03d22d39c3..f5559046b6 100644 --- a/frontend/src/components/dashboard/KeyPair.tsx +++ b/frontend/src/components/dashboard/KeyPair.tsx @@ -140,7 +140,7 @@ const KeyPair = ({
- {keyPair.tags.map((tag, index) => ( + {keyPair.tags?.map((tag, index) => ( index < 2 &&
tagDp._id === tag._id)[0]?.color} rounded-sm text-sm ${tagData.filter(tagDp => tagDp._id === tag._id)[0]?.colorText} flex items-center`}> {tag.name} modifyTags(keyPair.tags.filter(ttag => ttag._id !== tag._id), keyPair.pos)}/> diff --git a/frontend/src/pages/dashboard/[id].tsx b/frontend/src/pages/dashboard/[id].tsx index a4204a4419..8951004ce5 100644 --- a/frontend/src/pages/dashboard/[id].tsx +++ b/frontend/src/pages/dashboard/[id].tsx @@ -446,8 +446,8 @@ export default function Dashboard() { initDataPoint.key || newData!.filter((dataPoint) => dataPoint.id === initDataPoint.id)[0].comment !== initDataPoint.comment) || - newData!.filter((dataPoint) => dataPoint.id === initDataPoint.id)[0].tags !== - initDataPoint.tags + newData!.filter((dataPoint) => dataPoint.id === initDataPoint.id)[0]?.tags !== + initDataPoint?.tags ) .map((secret) => secret.id) .includes(newDataPoint.id) @@ -498,8 +498,7 @@ export default function Dashboard() { initDataPoint.key || newOverrides!.filter((dataPoint) => dataPoint.id === initDataPoint.id)[0] .comment !== initDataPoint.comment || - newOverrides!.filter((dataPoint) => dataPoint.id === initDataPoint.id)[0] - .tags !== initDataPoint.tags) + newOverrides!.filter((dataPoint) => dataPoint.id === initDataPoint.id)[0]?.tags !== initDataPoint?.tags) ) .map((secret) => secret.id) .includes(newDataPoint.id) @@ -877,7 +876,7 @@ export default function Dashboard() { .map((keyPair) => ( Date: Wed, 8 Feb 2023 14:36:56 -0800 Subject: [PATCH 4/8] Change default secret comments --- frontend/src/components/utilities/attemptLogin.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/utilities/attemptLogin.ts b/frontend/src/components/utilities/attemptLogin.ts index a47b2c1f01..e1a95381ef 100644 --- a/frontend/src/components/utilities/attemptLogin.ts +++ b/frontend/src/components/utilities/attemptLogin.ts @@ -137,7 +137,7 @@ const attemptLogin = async ( // eslint-disable-next-line no-template-curly-in-string value: 'mongodb+srv://${DB_USERNAME}:${DB_PASSWORD}@mongodb.net', valueOverride: undefined, - comment: 'This is an example of secret referencing.', + comment: 'Secret referencing example', id: '', tags: [] }, @@ -147,7 +147,7 @@ const attemptLogin = async ( value: 'OVERRIDE_THIS', valueOverride: undefined, comment: - 'This is an example of secret overriding. Your team can have a shared value of a secret, while you can override it to whatever value you need', + 'Override secrets with personal value', id: '', tags: [] }, @@ -157,7 +157,7 @@ const attemptLogin = async ( value: 'OVERRIDE_THIS', valueOverride: undefined, comment: - 'This is an example of secret overriding. Your team can have a shared value of a secret, while you can override it to whatever value you need', + 'Another secret override', id: '', tags: [] }, From 9a2297573273ff91f85bcfc49ca3194dec2bf29e Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Wed, 8 Feb 2023 17:29:35 -0800 Subject: [PATCH 5/8] When comments are empty, return empty byte --- cli/packages/crypto/crypto.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cli/packages/crypto/crypto.go b/cli/packages/crypto/crypto.go index f9589347a9..2f507ed4c8 100644 --- a/cli/packages/crypto/crypto.go +++ b/cli/packages/crypto/crypto.go @@ -12,6 +12,11 @@ import ( // will decrypt cipher text to plain text using iv and tag func DecryptSymmetric(key []byte, cipherText []byte, tag []byte, iv []byte) ([]byte, error) { + // Case: empty string + if len(cipherText) == 0 && len(tag) == 0 && len(iv) == 0 { + return []byte{}, nil + } + block, err := aes.NewCipher(key) if err != nil { return nil, err From a685ac3e73ecc7be67462627bdc4fe287ff5bef5 Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Wed, 8 Feb 2023 18:48:45 -0800 Subject: [PATCH 6/8] update regex to capature comment --- cli/packages/cmd/secrets.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/packages/cmd/secrets.go b/cli/packages/cmd/secrets.go index a1a8916fd9..a00cacaea5 100644 --- a/cli/packages/cmd/secrets.go +++ b/cli/packages/cmd/secrets.go @@ -474,7 +474,7 @@ func generateExampleEnv(cmd *cobra.Command, args []string) { listOfKeyValue := []string{} for _, secret := range secretDetails.Secrets { - re := regexp.MustCompile(`(.*)DEFAULT:(.*)`) + re := regexp.MustCompile(`(?s)(.*)DEFAULT:(.*)`) match := re.FindStringSubmatch(secret.Comment) defaultValue := "" comment := secret.Comment From 224fa25fdf92659c73ebeae1c07c517129278646 Mon Sep 17 00:00:00 2001 From: Vladyslav Matsiiako Date: Wed, 8 Feb 2023 23:38:00 -0800 Subject: [PATCH 7/8] Minor style fixes --- backend/src/controllers/v2/secretsController.ts | 2 +- .../templates/organizationInvitation.handlebars | 3 +-- .../src/templates/workspaceInvitation.handlebars | 4 ++-- frontend/src/components/basic/Layout.tsx | 8 ++++---- .../components/basic/popups/BottomRightPopup.tsx | 2 +- frontend/src/components/dashboard/CommentField.tsx | 2 +- .../components/dashboard/DashboardInputField.tsx | 6 +++--- frontend/src/components/dashboard/KeyPair.tsx | 14 ++++++++++---- .../src/components/navigation/NavBarDashboard.tsx | 6 +++--- frontend/src/pages/dashboard/[id].tsx | 7 +++++-- frontend/src/pages/home/[id].tsx | 2 +- 11 files changed, 32 insertions(+), 24 deletions(-) diff --git a/backend/src/controllers/v2/secretsController.ts b/backend/src/controllers/v2/secretsController.ts index ff39791ac9..7267ae50cc 100644 --- a/backend/src/controllers/v2/secretsController.ts +++ b/backend/src/controllers/v2/secretsController.ts @@ -452,7 +452,7 @@ export const updateSecrets = async (req: Request, res: Response) => { secretValueTag, tags, ...(( - secretCommentCiphertext && + secretCommentCiphertext !== undefined && secretCommentIV && secretCommentTag ) ? { diff --git a/backend/src/templates/organizationInvitation.handlebars b/backend/src/templates/organizationInvitation.handlebars index 49cc96f38d..c8d0a91163 100644 --- a/backend/src/templates/organizationInvitation.handlebars +++ b/backend/src/templates/organizationInvitation.handlebars @@ -12,7 +12,6 @@

{{inviterFirstName}}({{inviterEmail}}) has invited you to their Infisical organization — {{organizationName}}

Join now

What is Infisical?

-

Infisical is a simple end-to-end encrypted solution that enables teams to sync and manage their environment - variables.

+

Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets and configs.

\ No newline at end of file diff --git a/backend/src/templates/workspaceInvitation.handlebars b/backend/src/templates/workspaceInvitation.handlebars index 252452ce58..501d72c8d9 100644 --- a/backend/src/templates/workspaceInvitation.handlebars +++ b/backend/src/templates/workspaceInvitation.handlebars @@ -8,9 +8,9 @@

Infisical

Join your team on Infisical

-

{{inviterFirstName}}({{inviterEmail}}) has invited you to their Infisical workspace — {{workspaceName}}

+

{{inviterFirstName}}({{inviterEmail}}) has invited you to their Infisical project — {{workspaceName}}

Join now

What is Infisical?

-

Infisical is a simple end-to-end encrypted solution that enables teams to sync and manage their environment variables.

+

Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets and configs.

\ No newline at end of file diff --git a/frontend/src/components/basic/Layout.tsx b/frontend/src/components/basic/Layout.tsx index c6e2340588..a6632b556f 100644 --- a/frontend/src/components/basic/Layout.tsx +++ b/frontend/src/components/basic/Layout.tsx @@ -246,9 +246,9 @@ const Layout = ({ children }: LayoutProps) => { return ( <> -
+
-
+
-
+

{` ${t('common:no-mobile')} `} diff --git a/frontend/src/components/basic/popups/BottomRightPopup.tsx b/frontend/src/components/basic/popups/BottomRightPopup.tsx index 91427a3a8d..58d8a498eb 100644 --- a/frontend/src/components/basic/popups/BottomRightPopup.tsx +++ b/frontend/src/components/basic/popups/BottomRightPopup.tsx @@ -34,7 +34,7 @@ const BottonRightPopup = ({ }: PopupProps): JSX.Element => { return (

diff --git a/frontend/src/components/dashboard/CommentField.tsx b/frontend/src/components/dashboard/CommentField.tsx index bbd77cea05..c6552bb8f5 100644 --- a/frontend/src/components/dashboard/CommentField.tsx +++ b/frontend/src/components/dashboard/CommentField.tsx @@ -18,7 +18,7 @@ const CommentField = ({

{t('dashboard:sidebar.comments')}