From 466dadc611242b9113ba9d324e3112b656bd6ff7 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Wed, 2 Aug 2023 16:07:56 +0530 Subject: [PATCH 01/12] feat: added pull secret feature in dashboard with env json parsing and multiline parsing --- frontend/src/hooks/api/secrets/queries.tsx | 7 +- frontend/src/hooks/index.ts | 1 + frontend/src/hooks/useDebounce.tsx | 26 ++ .../src/views/DashboardPage/DashboardPage.tsx | 11 +- .../DashboardPage/DashboardPage.utils.ts | 11 +- .../SecretDropzone/SecretDropzone.tsx | 276 +++++++++++++++--- 6 files changed, 287 insertions(+), 45 deletions(-) create mode 100644 frontend/src/hooks/useDebounce.tsx diff --git a/frontend/src/hooks/api/secrets/queries.tsx b/frontend/src/hooks/api/secrets/queries.tsx index 34ecd7ec4..6f65a8edd 100644 --- a/frontend/src/hooks/api/secrets/queries.tsx +++ b/frontend/src/hooks/api/secrets/queries.tsx @@ -54,13 +54,14 @@ export const useGetProjectSecrets = ({ env, decryptFileKey, isPaused, - folderId + folderId, + secretPath }: GetProjectSecretsDTO) => useQuery({ // wait for all values to be available enabled: Boolean(decryptFileKey && workspaceId && env) && !isPaused, - queryKey: secretKeys.getProjectSecret(workspaceId, env, folderId), - queryFn: () => fetchProjectEncryptedSecrets(workspaceId, env, folderId), + queryKey: secretKeys.getProjectSecret(workspaceId, env, folderId || secretPath), + queryFn: () => fetchProjectEncryptedSecrets(workspaceId, env, folderId, secretPath), select: useCallback( (data: EncryptedSecret[]) => { const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string; diff --git a/frontend/src/hooks/index.ts b/frontend/src/hooks/index.ts index a3ded034c..98fbe2413 100644 --- a/frontend/src/hooks/index.ts +++ b/frontend/src/hooks/index.ts @@ -1,3 +1,4 @@ +export { useDebounce } from "./useDebounce"; export { useLeaveConfirm } from "./useLeaveConfirm"; export { usePersistentState } from "./usePersistentState"; export { usePopUp } from "./usePopUp"; diff --git a/frontend/src/hooks/useDebounce.tsx b/frontend/src/hooks/useDebounce.tsx new file mode 100644 index 000000000..318763210 --- /dev/null +++ b/frontend/src/hooks/useDebounce.tsx @@ -0,0 +1,26 @@ +import { useEffect, useState } from "react"; + +// Ref: https://usehooks.com/useDebounce/ +export const useDebounce = (value: T, delay = 500): T => { + // State and setters for debounced value + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect( + () => { + // Update debounced value after delay + const handler = setTimeout(() => { + setDebouncedValue(value); + }, delay); + + // Cancel the timeout if value changes (also on delay change or unmount) + // This is how we prevent debounced value from updating if value is changed ... + // .. within the delay period. Timeout gets cleared and restarted. + return () => { + clearTimeout(handler); + }; + }, + [value, delay] // Only re-call effect if value or delay changes + ); + + return debouncedValue; +}; diff --git a/frontend/src/views/DashboardPage/DashboardPage.tsx b/frontend/src/views/DashboardPage/DashboardPage.tsx index 6d794cbec..e809a08a0 100644 --- a/frontend/src/views/DashboardPage/DashboardPage.tsx +++ b/frontend/src/views/DashboardPage/DashboardPage.tsx @@ -740,7 +740,7 @@ export const DashboardPage = () => { return (
-
+ {/* breadcrumb row */}
{
{!isEmptyPage && ( @@ -935,7 +935,7 @@ export const DashboardPage = () => { collisionDetection={closestCenter} modifiers={[restrictToVerticalAxis]} > - + @@ -1016,9 +1016,12 @@ export const DashboardPage = () => { {/* secrets table and drawers, modals */} diff --git a/frontend/src/views/DashboardPage/DashboardPage.utils.ts b/frontend/src/views/DashboardPage/DashboardPage.utils.ts index a46e97a84..375a05489 100644 --- a/frontend/src/views/DashboardPage/DashboardPage.utils.ts +++ b/frontend/src/views/DashboardPage/DashboardPage.utils.ts @@ -75,6 +75,13 @@ export type FormData = yup.InferType; export type TSecretDetailsOpen = { index: number; id: string }; export type TSecOverwriteOpt = { secrets: Record }; +// to convert multi line into single line ones by quoting them and changing to string \n +const formatMultiValueEnv = (val?: string) => { + if (!val) return ""; + if (!val.match("\n")) return val; + return `"${val.replace(/\n/g, "\\n")}"`; +}; + export const downloadSecret = ( secrets: FormData["secrets"] = [], importedSecrets: { key: string; value?: string; comment?: string }[] = [], @@ -86,9 +93,11 @@ export const downloadSecret = ( }); const finalSecret = [...importedSecrets]; secrets.forEach(({ key, value, valueOverride, overrideAction, comment }) => { + const finalVal = + overrideAction && overrideAction !== SecretActionType.Deleted ? valueOverride : value; const newValue = { key, - value: overrideAction && overrideAction !== SecretActionType.Deleted ? valueOverride : value, + value: formatMultiValueEnv(finalVal), comment }; // can also be zero thus failing diff --git a/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx b/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx index 7b8671583..cac722368 100644 --- a/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx +++ b/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx @@ -1,26 +1,109 @@ -import { ChangeEvent, DragEvent } from "react"; +import { ChangeEvent, DragEvent, useEffect, useState } from "react"; +import { Controller, useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; -import { faUpload } from "@fortawesome/free-solid-svg-icons"; +import { faClone, faSearch, faUpload } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { yupResolver } from "@hookform/resolvers/yup"; import { twMerge } from "tailwind-merge"; +import * as yup from "yup"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; -// TODO:(akhilmhdh) convert all the util functions like this into a lib folder grouped by functionalityj +// TODO:(akhilmhdh) convert all the util functions like this into a lib folder grouped by functionality import { parseDotEnv } from "@app/components/utilities/parseDotEnv"; -import { Button } from "@app/components/v2"; -import { useToggle } from "@app/hooks/useToggle"; +import { + Button, + Checkbox, + FormControl, + Input, + Modal, + ModalContent, + ModalTrigger, + Select, + SelectItem, + Skeleton +} from "@app/components/v2"; +import { useDebounce, usePopUp, useToggle } from "@app/hooks"; +import { useGetProjectSecrets } from "@app/hooks/api"; +import { UserWsKeyPair } from "@app/hooks/api/types"; + +const formSchema = yup.object({ + environment: yup.string().required().label("Environment").trim(), + secretPath: yup + .string() + .required() + .label("Secret Path") + .trim() + .transform((val) => + typeof val === "string" && val.at(-1) === "/" && val.length > 1 ? val.slice(0, -1) : val + ), + secrets: yup.lazy((val) => { + const valSchema: Record = {}; + Object.keys(val).forEach((key) => { + valSchema[key] = yup.string().trim(); + }); + return yup.object(valSchema); + }) +}); + +type TFormSchema = yup.InferType; + +const parseJson = (src: ArrayBuffer) => { + const file = src.toString(); + const formatedData: Record = JSON.parse(file); + const env: Record = {}; + Object.keys(formatedData).forEach((key) => { + if (typeof formatedData[key] === "string") { + env[key] = { value: formatedData[key], comments: [] }; + } + }); + return env; +}; type Props = { isSmaller: boolean; onParsedEnv: (env: Record) => void; onAddNewSecret?: () => void; + environments?: { name: string; slug: string }[]; + workspaceId: string; + decryptFileKey: UserWsKeyPair; }; -export const SecretDropzone = ({ isSmaller, onParsedEnv, onAddNewSecret }: Props): JSX.Element => { +export const SecretDropzone = ({ + isSmaller, + onParsedEnv, + onAddNewSecret, + environments = [], + workspaceId, + decryptFileKey +}: Props): JSX.Element => { const { t } = useTranslation(); const [isDragActive, setDragActive] = useToggle(); const [isLoading, setIsLoading] = useToggle(); const { createNotification } = useNotificationContext(); + const { popUp, handlePopUpClose, handlePopUpToggle } = usePopUp(["importSecEnv"] as const); + const [searchFilter, setSearchFilter] = useState(""); + + const { handleSubmit, control, watch, register, reset, setValue } = useForm({ + resolver: yupResolver(formSchema), + defaultValues: { secretPath: "/", environment: environments?.[0]?.slug } + }); + + const secretPath = watch("secretPath"); + const selectedEnvSlug = watch("environment"); + const debouncedSecretPath = useDebounce(secretPath); + + const { data: secrets, isLoading: isSecretsLoading } = useGetProjectSecrets({ + workspaceId, + env: selectedEnvSlug, + secretPath: debouncedSecretPath, + isPaused: !(Boolean(workspaceId) && Boolean(selectedEnvSlug) && Boolean(debouncedSecretPath)), + decryptFileKey + }); + + useEffect(() => { + setValue("secrets", {}); + setSearchFilter(""); + }, [debouncedSecretPath]); const handleDrag = (e: DragEvent) => { e.preventDefault(); @@ -32,7 +115,7 @@ export const SecretDropzone = ({ isSmaller, onParsedEnv, onAddNewSecret }: Props } }; - const parseFile = (file?: File) => { + const parseFile = (file?: File, isJson?: boolean) => { const reader = new FileReader(); if (!file) { createNotification({ @@ -47,7 +130,9 @@ export const SecretDropzone = ({ isSmaller, onParsedEnv, onAddNewSecret }: Props reader.onload = (event) => { if (!event?.target?.result) return; // parse function's argument looks like to be ArrayBuffer - const env = parseDotEnv(event.target.result as ArrayBuffer); + const env = isJson + ? parseJson(event.target.result as ArrayBuffer) + : parseDotEnv(event.target.result as ArrayBuffer); setIsLoading.off(); onParsedEnv(env); }; @@ -74,7 +159,19 @@ export const SecretDropzone = ({ isSmaller, onParsedEnv, onAddNewSecret }: Props const handleFileUpload = (e: ChangeEvent) => { e.preventDefault(); - parseFile(e.target?.files?.[0]); + parseFile(e.target?.files?.[0], e.target?.files?.[0]?.type === "application/json"); + }; + + const handleFormSubmit = (data: TFormSchema) => { + const secretsToBePulled: Record = {}; + Object.keys(data.secrets || {}).forEach((key) => { + if (data.secrets[key]) { + secretsToBePulled[key] = { value: data.secrets[key] || "", comments: [""] }; + } + }); + onParsedEnv(secretsToBePulled); + handlePopUpClose("importSecEnv"); + reset(); }; return ( @@ -84,9 +181,9 @@ export const SecretDropzone = ({ isSmaller, onParsedEnv, onAddNewSecret }: Props onDragOver={handleDrag} onDrop={handleDrop} className={twMerge( - "relative mx-0.5 mb-4 mt-4 flex w-full max-w-[calc(100vw-292px)] cursor-pointer items-center justify-center space-x-2 rounded-md bg-mineshaft-900 py-8 px-2 text-mineshaft-200 opacity-60 outline-dashed outline-2 outline-chicago-600 duration-200 hover:opacity-100", + "relative mx-0.5 mb-4 mt-4 flex cursor-pointer items-center justify-center rounded-md bg-mineshaft-900 py-4 text-sm px-2 text-mineshaft-200 opacity-60 outline-dashed outline-2 outline-chicago-600 duration-200 hover:opacity-100", isDragActive && "opacity-100", - !isSmaller && "max-w-3xl flex-col space-y-4 py-20", + !isSmaller && "w-full max-w-3xl flex-col space-y-4 py-20", isLoading && "bg-bunker-800" )} > @@ -95,35 +192,140 @@ export const SecretDropzone = ({ isSmaller, onParsedEnv, onAddNewSecret }: Props loading animation ) : ( - <> -
- -
-
-

{t(isSmaller ? "common.drop-zone-keys" : "common.drop-zone")}

-
- - {!isSmaller && ( - <> -
-
-

OR

-
-
-
+ +
+
+ +
+
+

{t(isSmaller ? "common.drop-zone-keys" : "common.drop-zone")}

+
+ +
+
+

OR

+
+
+
+ { + handlePopUpToggle("importSecEnv", isOpen); + reset(); + setSearchFilter(""); + }} + > + + + + + +
+ ( + + + + )} + /> + + + +
+
+
+
Secrets
+
+ } + onChange={(evt) => setSearchFilter(evt.target.value)} + /> +
+
+
+ {isSecretsLoading && + Array.apply(0, Array(4)).map((_x, i) => ( + + ))} + {secrets?.secrets + ?.filter(({ key }) => + key.toLowerCase().includes(searchFilter.toLowerCase()) + ) + ?.map(({ _id, key, value: secVal }) => ( + ( + onChange(isChecked ? secVal : "")} + > + {key} + + )} + /> + ))} +
+
+ + +
+
+ +
+
+ {!isSmaller && ( -
- - )}{" "} - + )} +
+
+ )}
); From 817a783ec2ca13a0358178c83c67d7ca6b44112d Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Thu, 3 Aug 2023 13:07:51 +0530 Subject: [PATCH 02/12] feat: updated text and added select all in copy secrets for dashboard --- frontend/src/components/v2/Button/Button.tsx | 48 ++++++++++--------- .../SecretDropzone/SecretDropzone.tsx | 42 ++++++++++++++-- 2 files changed, 62 insertions(+), 28 deletions(-) diff --git a/frontend/src/components/v2/Button/Button.tsx b/frontend/src/components/v2/Button/Button.tsx index b69545766..7c2a5fd6d 100644 --- a/frontend/src/components/v2/Button/Button.tsx +++ b/frontend/src/components/v2/Button/Button.tsx @@ -51,10 +51,10 @@ const buttonVariants = cva( false: "" }, size: { - xs: ["text-xs", "py-1", "px-1"], - sm: ["text-sm", "py-2", "px-2"], - md: ["text-md", "py-2", "px-4"], - lg: ["text-lg", "py-2", "px-8"] + xs: ["text-xs", "py-1", "px-2"], + sm: ["text-sm", "py-2", "px-4"], + md: ["text-md", "py-2", "px-5"], + lg: ["text-lg", "py-2", "px-6"] } }, compoundVariants: [ @@ -186,16 +186,17 @@ export const Button = forwardRef( className="absolute rounded-xl opacity-80" /> )} -
- {leftIcon} -
+ {leftIcon && ( +
+ {leftIcon} +
+ )} ( > {children} -
- {rightIcon} -
+ {rightIcon && ( +
+ {rightIcon} +
+ )} ); } diff --git a/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx b/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx index cac722368..699edea84 100644 --- a/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx +++ b/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx @@ -1,7 +1,8 @@ import { ChangeEvent, DragEvent, useEffect, useState } from "react"; import { Controller, useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; -import { faClone, faSearch, faUpload } from "@fortawesome/free-solid-svg-icons"; +import { faSquareCheck } from "@fortawesome/free-regular-svg-icons"; +import { faClone, faSearch, faSquareXmark, faUpload } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { yupResolver } from "@hookform/resolvers/yup"; import { twMerge } from "tailwind-merge"; @@ -14,13 +15,15 @@ import { Button, Checkbox, FormControl, + IconButton, Input, Modal, ModalContent, ModalTrigger, Select, SelectItem, - Skeleton + Skeleton, + Tooltip } from "@app/components/v2"; import { useDebounce, usePopUp, useToggle } from "@app/hooks"; import { useGetProjectSecrets } from "@app/hooks/api"; @@ -174,6 +177,15 @@ export const SecretDropzone = ({ reset(); }; + const handleSecSelectAll = () => { + if (secrets?.secrets) { + setValue( + "secrets", + secrets?.secrets?.reduce((prev, curr) => ({ ...prev, [curr.key]: curr.value }), {}) + ); + } + }; + return (
@@ -267,7 +279,7 @@ export const SecretDropzone = ({
Secrets
-
+
} onChange={(evt) => setSearchFilter(evt.target.value)} /> + + + + + + + reset()} + > + + +
@@ -308,7 +340,7 @@ export const SecretDropzone = ({
@@ -309,14 +333,18 @@ export const SecretDropzone = ({
+ {!isSecretsLoading && !secrets?.secrets?.length && ( + + )}
{isSecretsLoading && - Array.apply(0, Array(4)).map((_x, i) => ( + Array.apply(0, Array(2)).map((_x, i) => ( ))} + {secrets?.secrets ?.filter(({ key }) => key.toLowerCase().includes(searchFilter.toLowerCase()) @@ -338,8 +366,23 @@ export const SecretDropzone = ({ /> ))}
-
- @@ -40,7 +41,7 @@ export default function InitialSignupStep({ window.close(); }} leftIcon={} - className="h-14 w-full mx-0" + className="h-12 w-full mx-0" > Continue with GitHub @@ -53,7 +54,7 @@ export default function InitialSignupStep({ setIsSignupWithEmail(true); }} leftIcon={} - className="h-14 w-full mx-0" + className="h-12 w-full mx-0" > Continue with Email @@ -63,10 +64,10 @@ export default function InitialSignupStep({ colorSchema="primary" variant="outline_bg" onClick={() => router.push("/saml-sso")} - isFullWidth - className="h-14 w-full mx-0" + leftIcon={} + className="h-12 w-full mx-0" > - Continue with SAML SSO + Continue with SSO
diff --git a/frontend/src/components/v2/Input/Input.tsx b/frontend/src/components/v2/Input/Input.tsx index 17573e527..7ec540232 100644 --- a/frontend/src/components/v2/Input/Input.tsx +++ b/frontend/src/components/v2/Input/Input.tsx @@ -87,7 +87,6 @@ export const Input = forwardRef( ref ): JSX.Element => { const handleInput = (event: ChangeEvent) => { - console.log(123, props, autoCapitalization) if (autoCapitalization) { // eslint-disable-next-line no-param-reassign event.target.value = event.target.value.toUpperCase(); diff --git a/frontend/src/views/DashboardPage/components/SecretInputRow/SecretInputRow.tsx b/frontend/src/views/DashboardPage/components/SecretInputRow/SecretInputRow.tsx index a2f95e4a4..aba283b27 100644 --- a/frontend/src/views/DashboardPage/components/SecretInputRow/SecretInputRow.tsx +++ b/frontend/src/views/DashboardPage/components/SecretInputRow/SecretInputRow.tsx @@ -281,7 +281,6 @@ export const SecretInputRow = memo( value={editorRef} isVisible={!isSecretValueHidden} onChange={(val, html) => { - console.log(val); onChange(val); setEditorRef(html); }} diff --git a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx index c814cd510..2bee45669 100644 --- a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx +++ b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx @@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next"; import Link from "next/link"; import { useRouter } from "next/router"; import { faGithub,faGoogle } from "@fortawesome/free-brands-svg-icons"; +import { faLock } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import axios from "axios" @@ -116,47 +117,6 @@ export const InitialStep = ({ return (

Login to Infisical

-
-
-
-
- setEmail(e.target.value)} - type="email" - placeholder="Enter your email..." - isRequired - autoComplete="username" - className="h-12" - /> -
-
- setPassword(e.target.value)} - type="password" - placeholder="Enter your password..." - isRequired - autoComplete="current-password" - id="current-password" - className="h-12 select:-webkit-autofill:focus" - /> -
-
- -
- {!isLoading && loginError && } -
-
-
@@ -185,7 +145,7 @@ export const InitialStep = ({ window.close(); }} leftIcon={} - className="h-12 w-full mx-0" + className="h-11 w-full mx-0" > Continue with GitHub @@ -197,12 +157,52 @@ export const InitialStep = ({ onClick={() => { setStep(2); }} - isFullWidth - className="h-12 w-full mx-0" + leftIcon={} + className="h-11 w-full mx-0" > - Continue with SAML SSO + Continue with SSO
+
+
+ or +
+
+
+ setEmail(e.target.value)} + type="email" + placeholder="Enter your email..." + isRequired + autoComplete="username" + className="h-11" + /> +
+
+ setPassword(e.target.value)} + type="password" + placeholder="Enter your password..." + isRequired + autoComplete="current-password" + id="current-password" + className="h-11 select:-webkit-autofill:focus" + /> +
+
+ +
+ {!isLoading && loginError && } { !serverDetails?.inviteOnlySignup ?
diff --git a/frontend/src/views/Signup/components/UserInfoSSOStep/UserInfoSSOStep.tsx b/frontend/src/views/Signup/components/UserInfoSSOStep/UserInfoSSOStep.tsx index fed039467..032552958 100644 --- a/frontend/src/views/Signup/components/UserInfoSSOStep/UserInfoSSOStep.tsx +++ b/frontend/src/views/Signup/components/UserInfoSSOStep/UserInfoSSOStep.tsx @@ -3,7 +3,7 @@ import crypto from "crypto"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { faXmark } from "@fortawesome/free-solid-svg-icons"; +import { faInfoCircle, faXmark } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import jsrp from "jsrp"; import nacl from "tweetnacl"; @@ -198,7 +198,7 @@ export const UserInfoSSOStep = ({ localStorage.setItem("orgData.id", orgId); localStorage.setItem("projectData.id", project._id); - setStep(1); + setStep(1); } catch (error) { setIsLoading(false); console.error(error); @@ -256,7 +256,7 @@ export const UserInfoSSOStep = ({ )}
{ setPassword(pass); checkPassword({ @@ -272,6 +272,7 @@ export const UserInfoSSOStep = ({ autoComplete="new-password" id="new-password" /> +
Infisical Password is used as part of the encryption mechanism so that even the authentication provider is not able to access your secrets.
{Object.keys(errors).length > 0 && (
{t("section.password.validate-base")}
@@ -307,7 +308,7 @@ export const UserInfoSSOStep = ({ onClick={signupErrorCheck} size="sm" isFullWidth - className='h-14' + className='h-12' colorSchema="primary" variant="outline_bg" isLoading={isLoading} From b03c34698517536597a37b520512eff1233968e6 Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Thu, 3 Aug 2023 18:03:35 -0400 Subject: [PATCH 05/12] nit: text update --- .../DashboardPage/components/SecretDropzone/SecretDropzone.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx b/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx index 6bb747a20..4e632e517 100644 --- a/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx +++ b/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx @@ -265,7 +265,7 @@ export const SecretDropzone = ({
From 9d57b1db875757d95554bf6996d103ee66ff9aad Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Fri, 4 Aug 2023 11:46:23 +0530 Subject: [PATCH 06/12] fix: added dirty flag to set fn in dropzone paste secret --- .../DashboardPage/components/SecretDropzone/SecretDropzone.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx b/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx index 4e632e517..315eaf63a 100644 --- a/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx +++ b/frontend/src/views/DashboardPage/components/SecretDropzone/SecretDropzone.tsx @@ -200,7 +200,8 @@ export const SecretDropzone = ({ if (secrets?.secrets) { setValue( "secrets", - secrets?.secrets?.reduce((prev, curr) => ({ ...prev, [curr.key]: curr.value }), {}) + secrets?.secrets?.reduce((prev, curr) => ({ ...prev, [curr.key]: curr.value }), {}), + { shouldDirty: true } ); } }; From 5af1eb508c57c02ec6a3826fadfbb4a48e7e1536 Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Fri, 4 Aug 2023 10:49:05 -0400 Subject: [PATCH 07/12] disable trust IP --- backend/src/routes/v3/secrets.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/backend/src/routes/v3/secrets.ts b/backend/src/routes/v3/secrets.ts index 6d3b4911d..5a33e30ff 100644 --- a/backend/src/routes/v3/secrets.ts +++ b/backend/src/routes/v3/secrets.ts @@ -57,7 +57,7 @@ router.get( requiredPermissions: [PERMISSION_READ_SECRETS], requireBlindIndicesEnabled: true, requireE2EEOff: true, - checkIPAllowlist: true + checkIPAllowlist: false }), secretsController.getSecretByNameRaw ); @@ -86,7 +86,7 @@ router.post( requiredPermissions: [PERMISSION_WRITE_SECRETS], requireBlindIndicesEnabled: true, requireE2EEOff: true, - checkIPAllowlist: true + checkIPAllowlist: false }), secretsController.createSecretRaw ); @@ -115,7 +115,7 @@ router.patch( requiredPermissions: [PERMISSION_WRITE_SECRETS], requireBlindIndicesEnabled: true, requireE2EEOff: true, - checkIPAllowlist: true + checkIPAllowlist: false }), secretsController.updateSecretByNameRaw ); @@ -143,7 +143,7 @@ router.delete( requiredPermissions: [PERMISSION_WRITE_SECRETS], requireBlindIndicesEnabled: true, requireE2EEOff: true, - checkIPAllowlist: true + checkIPAllowlist: false }), secretsController.deleteSecretByNameRaw ); @@ -169,7 +169,7 @@ router.get( requiredPermissions: [PERMISSION_READ_SECRETS], requireBlindIndicesEnabled: true, requireE2EEOff: false, - checkIPAllowlist: true + checkIPAllowlist: false }), secretsController.getSecrets ); @@ -205,7 +205,7 @@ router.post( requiredPermissions: [PERMISSION_WRITE_SECRETS], requireBlindIndicesEnabled: true, requireE2EEOff: false, - checkIPAllowlist: true + checkIPAllowlist: false }), secretsController.createSecret ); @@ -232,7 +232,7 @@ router.get( locationEnvironment: "query", requiredPermissions: [PERMISSION_READ_SECRETS], requireBlindIndicesEnabled: true, - checkIPAllowlist: true + checkIPAllowlist: false }), secretsController.getSecretByName ); @@ -263,7 +263,7 @@ router.patch( requiredPermissions: [PERMISSION_WRITE_SECRETS], requireBlindIndicesEnabled: true, requireE2EEOff: false, - checkIPAllowlist: true + checkIPAllowlist: false }), secretsController.updateSecretByName ); @@ -291,7 +291,7 @@ router.delete( requiredPermissions: [PERMISSION_WRITE_SECRETS], requireBlindIndicesEnabled: true, requireE2EEOff: false, - checkIPAllowlist: true + checkIPAllowlist: false }), secretsController.deleteSecretByName ); From 8b50150ec82c97f82e96ea0f1a85a85ac2813ccc Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Fri, 4 Aug 2023 11:11:17 -0400 Subject: [PATCH 08/12] Update usage.mdx --- docs/cli/usage.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/cli/usage.mdx b/docs/cli/usage.mdx index 36f6a4165..166c2804a 100644 --- a/docs/cli/usage.mdx +++ b/docs/cli/usage.mdx @@ -61,16 +61,16 @@ The distinguishing factor, however, is the authentication method used. ```bash - infisical run -- [your application start command] + infisical run --env=dev --path=/apps/firefly -- [your application start command] # example with node (nodemon) - infisical run --env=dev --path=/apps/firefly -- nodemon index.js + infisical run --env=staging --path=/apps/spotify -- nodemon index.js # example with flask - infisical run -- flask run + infisical run --env=prod --path=/apps/backend -- flask run # example with spring boot - maven - infisical run -- ./mvnw spring-boot:run --quiet + infisical run --env=dev --path=/apps/ -- ./mvnw spring-boot:run --quiet ``` @@ -86,7 +86,7 @@ The distinguishing factor, however, is the authentication method used. To make the secrets available from Infisical to `yd`, you can run the following command: ```bash - infisical run --command="source custom.sh && yd" + infisical run --env=prod --path=/apps/reddit --command="source custom.sh && yd" ``` From 3fe592686a4c72c0e473cd5002e5cc3ade2612de Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Fri, 4 Aug 2023 12:01:34 -0400 Subject: [PATCH 09/12] add clarity to CLI docs --- docs/cli/overview.mdx | 5 +++++ docs/cli/usage.mdx | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/cli/overview.mdx b/docs/cli/overview.mdx index 434a39c51..ab913ec1a 100644 --- a/docs/cli/overview.mdx +++ b/docs/cli/overview.mdx @@ -111,3 +111,8 @@ You can use it across various environments, whether it's local development, CI/C + +## Quick Usage Guide + + Now that you have the CLI installed on your system, follow this guide to make the best use of it + \ No newline at end of file diff --git a/docs/cli/usage.mdx b/docs/cli/usage.mdx index 166c2804a..2ea7b6425 100644 --- a/docs/cli/usage.mdx +++ b/docs/cli/usage.mdx @@ -7,7 +7,7 @@ The CLI is designed for a variety of applications, ranging from local secret man The distinguishing factor, however, is the authentication method used. - + To use the Infisical CLI in your local development environment, simply run the command below and follow the interactive guide. ```bash @@ -32,7 +32,7 @@ The distinguishing factor, however, is the authentication method used. - + To use Infisical for non local development scenarios, please create a [service token](../documentation/platform/token). The service token will allow you to authenticate and interact with Infisical. Once you have created a service token with the required permissions, you'll need to feed the token to the CLI. From 24d23e89d07b60e27407cd37d9076fe51d4b779a Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Fri, 4 Aug 2023 12:10:46 -0400 Subject: [PATCH 10/12] add exit code to run command --- cli/packages/cmd/run.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/packages/cmd/run.go b/cli/packages/cmd/run.go index 906723df8..ef83bc10c 100644 --- a/cli/packages/cmd/run.go +++ b/cli/packages/cmd/run.go @@ -144,12 +144,14 @@ var runCmd = &cobra.Command{ err = executeMultipleCommandWithEnvs(command, len(secretsByKey), env) if err != nil { fmt.Println(err) + os.Exit(1) } } else { err = executeSingleCommandWithEnvs(args, len(secretsByKey), env) if err != nil { fmt.Println(err) + os.Exit(1) } } }, From 00030f223103c3247c7c5e36923e6e9e80eddc51 Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Fri, 4 Aug 2023 17:42:29 -0400 Subject: [PATCH 11/12] move secret scanning to ee --- .../src/controllers/v1/secretScanningController.ts | 6 +++--- .../{ => ee}/models/gitAppInstallationSession.ts | 0 .../models/gitAppOrganizationInstallation.ts | 0 backend/src/{ => ee}/models/gitRisks.ts | 0 backend/src/ee/models/index.ts | 5 ++++- backend/src/ee/routes/v1/index.ts | 2 ++ backend/src/{ => ee}/routes/v1/secretScanning.ts | 6 +++--- backend/src/index.ts | 2 +- backend/src/models/index.ts | 5 +---- backend/src/routes/v1/index.ts | 2 -- .../GithubSecretScanningService.ts | 14 +++++++------- backend/src/services/index.ts | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) rename backend/src/{ => ee}/models/gitAppInstallationSession.ts (100%) rename backend/src/{ => ee}/models/gitAppOrganizationInstallation.ts (100%) rename backend/src/{ => ee}/models/gitRisks.ts (100%) rename backend/src/{ => ee}/routes/v1/secretScanning.ts (91%) rename backend/src/services/{ => GithubSecretScanning}/GithubSecretScanningService.ts (95%) diff --git a/backend/src/controllers/v1/secretScanningController.ts b/backend/src/controllers/v1/secretScanningController.ts index e84e5994c..3acd7e293 100644 --- a/backend/src/controllers/v1/secretScanningController.ts +++ b/backend/src/controllers/v1/secretScanningController.ts @@ -1,11 +1,11 @@ import { Request, Response } from "express"; -import GitAppInstallationSession from "../../models/gitAppInstallationSession"; +import GitAppInstallationSession from "../../ee/models/gitAppInstallationSession"; import crypto from "crypto"; import { Types } from "mongoose"; import { UnauthorizedRequestError } from "../../utils/errors"; -import GitAppOrganizationInstallation from "../../models/gitAppOrganizationInstallation"; +import GitAppOrganizationInstallation from "../../ee/models/gitAppOrganizationInstallation"; import { MembershipOrg } from "../../models"; -import GitRisks, { STATUS_RESOLVED_FALSE_POSITIVE, STATUS_RESOLVED_NOT_REVOKED, STATUS_RESOLVED_REVOKED } from "../../models/gitRisks"; +import GitRisks, { STATUS_RESOLVED_FALSE_POSITIVE, STATUS_RESOLVED_NOT_REVOKED, STATUS_RESOLVED_REVOKED } from "../../ee/models/gitRisks"; export const createInstallationSession = async (req: Request, res: Response) => { const sessionId = crypto.randomBytes(16).toString("hex"); diff --git a/backend/src/models/gitAppInstallationSession.ts b/backend/src/ee/models/gitAppInstallationSession.ts similarity index 100% rename from backend/src/models/gitAppInstallationSession.ts rename to backend/src/ee/models/gitAppInstallationSession.ts diff --git a/backend/src/models/gitAppOrganizationInstallation.ts b/backend/src/ee/models/gitAppOrganizationInstallation.ts similarity index 100% rename from backend/src/models/gitAppOrganizationInstallation.ts rename to backend/src/ee/models/gitAppOrganizationInstallation.ts diff --git a/backend/src/models/gitRisks.ts b/backend/src/ee/models/gitRisks.ts similarity index 100% rename from backend/src/models/gitRisks.ts rename to backend/src/ee/models/gitRisks.ts diff --git a/backend/src/ee/models/index.ts b/backend/src/ee/models/index.ts index 1def9073d..c364e3c51 100644 --- a/backend/src/ee/models/index.ts +++ b/backend/src/ee/models/index.ts @@ -4,4 +4,7 @@ export * from "./folderVersion"; export * from "./log"; export * from "./action"; export * from "./ssoConfig"; -export * from "./trustedIp"; \ No newline at end of file +export * from "./trustedIp"; +export * from "./gitRisks"; +export * from "./gitAppOrganizationInstallation"; +export * from "./gitAppInstallationSession"; diff --git a/backend/src/ee/routes/v1/index.ts b/backend/src/ee/routes/v1/index.ts index cf92bfc6c..be4847cef 100644 --- a/backend/src/ee/routes/v1/index.ts +++ b/backend/src/ee/routes/v1/index.ts @@ -6,6 +6,7 @@ import users from "./users"; import workspace from "./workspace"; import action from "./action"; import cloudProducts from "./cloudProducts"; +import secretScanning from "./secretScanning"; export { secret, @@ -16,4 +17,5 @@ export { workspace, action, cloudProducts, + secretScanning } \ No newline at end of file diff --git a/backend/src/routes/v1/secretScanning.ts b/backend/src/ee/routes/v1/secretScanning.ts similarity index 91% rename from backend/src/routes/v1/secretScanning.ts rename to backend/src/ee/routes/v1/secretScanning.ts index fa162ce68..0f6490d8d 100644 --- a/backend/src/routes/v1/secretScanning.ts +++ b/backend/src/ee/routes/v1/secretScanning.ts @@ -4,10 +4,10 @@ import { requireAuth, requireOrganizationAuth, validateRequest, -} from "../../middleware"; +} from "../../../middleware"; import { body, param } from "express-validator"; -import { createInstallationSession, getCurrentOrganizationInstallationStatus, getRisksForOrganization, linkInstallationToOrganization, updateRisksStatus } from "../../controllers/v1/secretScanningController"; -import { ACCEPTED, ADMIN, MEMBER, OWNER } from "../../variables"; +import { createInstallationSession, getCurrentOrganizationInstallationStatus, getRisksForOrganization, linkInstallationToOrganization, updateRisksStatus } from "../../../controllers/v1/secretScanningController"; +import { ACCEPTED, ADMIN, MEMBER, OWNER } from "../../../variables"; router.post( "/create-installation-session/organization/:organizationId", diff --git a/backend/src/index.ts b/backend/src/index.ts index 098e7fc27..e5c384f2a 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -24,6 +24,7 @@ import { secretSnapshot as eeSecretSnapshotRouter, users as eeUsersRouter, workspace as eeWorkspaceRouter, + secretScanning as v1SecretScanningRouter, } from "./ee/routes/v1"; import { auth as v1AuthRouter, @@ -38,7 +39,6 @@ import { password as v1PasswordRouter, secretImport as v1SecretImportRouter, secret as v1SecretRouter, - secretScanning as v1SecretScanningRouter, secretsFolder as v1SecretsFolder, serviceToken as v1ServiceTokenRouter, signup as v1SignupRouter, diff --git a/backend/src/models/index.ts b/backend/src/models/index.ts index d94d2b917..b852b3245 100644 --- a/backend/src/models/index.ts +++ b/backend/src/models/index.ts @@ -24,7 +24,6 @@ import ServiceTokenData, { IServiceTokenData } from "./serviceTokenData"; import APIKeyData, { IAPIKeyData } from "./apiKeyData"; import LoginSRPDetail, { ILoginSRPDetail } from "./loginSRPDetail"; import TokenVersion, { ITokenVersion } from "./tokenVersion"; -import GitRisks, { STATUS_RESOLVED_FALSE_POSITIVE } from "./gitRisks"; export { AuthProvider, @@ -79,7 +78,5 @@ export { LoginSRPDetail, ILoginSRPDetail, TokenVersion, - ITokenVersion, - GitRisks, - STATUS_RESOLVED_FALSE_POSITIVE + ITokenVersion }; diff --git a/backend/src/routes/v1/index.ts b/backend/src/routes/v1/index.ts index ce5b5dd58..08298a1c6 100644 --- a/backend/src/routes/v1/index.ts +++ b/backend/src/routes/v1/index.ts @@ -15,7 +15,6 @@ import password from "./password"; import integration from "./integration"; import integrationAuth from "./integrationAuth"; import secretsFolder from "./secretsFolder"; -import secretScanning from "./secretScanning"; import webhooks from "./webhook"; import secretImport from "./secretImport"; @@ -37,7 +36,6 @@ export { integration, integrationAuth, secretsFolder, - secretScanning, webhooks, secretImport }; diff --git a/backend/src/services/GithubSecretScanningService.ts b/backend/src/services/GithubSecretScanning/GithubSecretScanningService.ts similarity index 95% rename from backend/src/services/GithubSecretScanningService.ts rename to backend/src/services/GithubSecretScanning/GithubSecretScanningService.ts index 295be13b9..7d7a0c03d 100644 --- a/backend/src/services/GithubSecretScanningService.ts +++ b/backend/src/services/GithubSecretScanning/GithubSecretScanningService.ts @@ -3,13 +3,13 @@ import { exec } from "child_process"; import { mkdir, readFile, rm, writeFile } from "fs"; import { tmpdir } from "os"; import { join } from "path" -import GitRisks from "../models/gitRisks"; -import GitAppOrganizationInstallation from "../models/gitAppOrganizationInstallation"; -import MembershipOrg from "../models/membershipOrg"; -import { ADMIN, OWNER } from "../variables"; -import User from "../models/user"; -import { sendMail } from "../helpers"; -import TelemetryService from "./TelemetryService"; +import GitRisks from "../../ee/models/gitRisks"; +import GitAppOrganizationInstallation from "../../ee/models/gitAppOrganizationInstallation"; +import MembershipOrg from "../../models/membershipOrg"; +import { ADMIN, OWNER } from "../../variables"; +import User from "../../models/user"; +import { sendMail } from "../../helpers"; +import TelemetryService from "../TelemetryService"; type SecretMatch = { Description: string; diff --git a/backend/src/services/index.ts b/backend/src/services/index.ts index 5b6d42f26..537de95b1 100644 --- a/backend/src/services/index.ts +++ b/backend/src/services/index.ts @@ -7,7 +7,7 @@ import EventService from "./EventService"; import IntegrationService from "./IntegrationService"; import TokenService from "./TokenService"; import SecretService from "./SecretService"; -import GithubSecretScanningService from "./GithubSecretScanningService" +import GithubSecretScanningService from "./GithubSecretScanning/GithubSecretScanningService" export { TelemetryService, From 49bcd8839f0baad0791aaaf8aeaea38c254d0c23 Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Fri, 4 Aug 2023 18:15:07 -0400 Subject: [PATCH 12/12] move github scanning service to ee --- .../GithubSecretScanningService.ts | 14 +++++++------- backend/src/ee/services/index.ts | 2 ++ backend/src/index.ts | 4 ++-- backend/src/services/index.ts | 2 -- 4 files changed, 11 insertions(+), 11 deletions(-) rename backend/src/{ => ee}/services/GithubSecretScanning/GithubSecretScanningService.ts (94%) diff --git a/backend/src/services/GithubSecretScanning/GithubSecretScanningService.ts b/backend/src/ee/services/GithubSecretScanning/GithubSecretScanningService.ts similarity index 94% rename from backend/src/services/GithubSecretScanning/GithubSecretScanningService.ts rename to backend/src/ee/services/GithubSecretScanning/GithubSecretScanningService.ts index 7d7a0c03d..a8e374ba5 100644 --- a/backend/src/services/GithubSecretScanning/GithubSecretScanningService.ts +++ b/backend/src/ee/services/GithubSecretScanning/GithubSecretScanningService.ts @@ -3,13 +3,13 @@ import { exec } from "child_process"; import { mkdir, readFile, rm, writeFile } from "fs"; import { tmpdir } from "os"; import { join } from "path" -import GitRisks from "../../ee/models/gitRisks"; -import GitAppOrganizationInstallation from "../../ee/models/gitAppOrganizationInstallation"; -import MembershipOrg from "../../models/membershipOrg"; -import { ADMIN, OWNER } from "../../variables"; -import User from "../../models/user"; -import { sendMail } from "../../helpers"; -import TelemetryService from "../TelemetryService"; +import GitRisks from "../../models/gitRisks"; +import GitAppOrganizationInstallation from "../../models/gitAppOrganizationInstallation"; +import MembershipOrg from "../../../models/membershipOrg"; +import { ADMIN, OWNER } from "../../../variables"; +import User from "../../../models/user"; +import { sendMail } from "../../../helpers"; +import TelemetryService from "../../../services/TelemetryService"; type SecretMatch = { Description: string; diff --git a/backend/src/ee/services/index.ts b/backend/src/ee/services/index.ts index afc3fb80e..4cc27a383 100644 --- a/backend/src/ee/services/index.ts +++ b/backend/src/ee/services/index.ts @@ -1,9 +1,11 @@ import EELicenseService from "./EELicenseService"; import EESecretService from "./EESecretService"; import EELogService from "./EELogService"; +import GithubSecretScanningService from "./GithubSecretScanning/GithubSecretScanningService" export { EELicenseService, EESecretService, EELogService, + GithubSecretScanningService } \ No newline at end of file diff --git a/backend/src/index.ts b/backend/src/index.ts index e5c384f2a..3c6e82180 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -5,8 +5,8 @@ import express from "express"; require("express-async-errors"); import helmet from "helmet"; import cors from "cors"; -import { DatabaseService, GithubSecretScanningService } from "./services"; -import { EELicenseService } from "./ee/services"; +import { DatabaseService } from "./services"; +import { EELicenseService, GithubSecretScanningService} from "./ee/services"; import { setUpHealthEndpoint } from "./services/health"; import cookieParser from "cookie-parser"; import swaggerUi = require("swagger-ui-express"); diff --git a/backend/src/services/index.ts b/backend/src/services/index.ts index 537de95b1..781fb435c 100644 --- a/backend/src/services/index.ts +++ b/backend/src/services/index.ts @@ -7,7 +7,6 @@ import EventService from "./EventService"; import IntegrationService from "./IntegrationService"; import TokenService from "./TokenService"; import SecretService from "./SecretService"; -import GithubSecretScanningService from "./GithubSecretScanning/GithubSecretScanningService" export { TelemetryService, @@ -18,5 +17,4 @@ export { IntegrationService, TokenService, SecretService, - GithubSecretScanningService }