Merge branch 'main' into import-export-secrets

This commit is contained in:
mv-turtle
2023-01-06 16:07:11 -08:00
committed by GitHub
177 changed files with 9049 additions and 4575 deletions
-16
View File
@@ -1,16 +0,0 @@
import posthog from 'posthog-js';
import { ENV, POSTHOG_API_KEY, POSTHOG_HOST } from '../utilities/config';
export const initPostHog = () => {
if (typeof window !== 'undefined') {
// eslint-disable-next-line
if (ENV == 'production' && TELEMETRY_CAPTURING_ENABLED) {
posthog.init(POSTHOG_API_KEY, {
api_host: POSTHOG_HOST
});
}
}
return posthog;
};
+13 -8
View File
@@ -5,14 +5,19 @@ import posthog from 'posthog-js';
import { ENV, POSTHOG_API_KEY, POSTHOG_HOST } from '../utilities/config';
export const initPostHog = () => {
if (typeof window !== 'undefined') {
// @ts-ignore
if (ENV == 'production' && TELEMETRY_CAPTURING_ENABLED) {
posthog.init(POSTHOG_API_KEY, {
api_host: POSTHOG_HOST
});
try {
if (typeof window !== 'undefined') {
// @ts-ignore
if (ENV == 'production' && TELEMETRY_CAPTURING_ENABLED) {
console.log("Outside of posthog", "POSTHOG_API_KEY", POSTHOG_API_KEY, "POSTHOG_HOST", POSTHOG_HOST)
posthog.init(POSTHOG_API_KEY, {
api_host: POSTHOG_HOST
});
}
}
}
return posthog;
return posthog;
} catch (e) {
console.log("posthog err", e)
}
};
+106
View File
@@ -0,0 +1,106 @@
import React from 'react';
import { Fragment } from 'react';
import { useTranslation } from "next-i18next";
import {
faAngleDown,
faEye,
faPlus,
faShuffle,
faTrash,
faX
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Listbox, Transition } from '@headlessui/react';
interface ListBoxProps {
selected: string;
select: (event: string) => void;
}
const eventOptions = [
{
name: 'addSecrets',
icon: faPlus
},
{
name: 'readSecrets',
icon: faEye
},
{
name: 'updateSecrets',
icon: faShuffle
},
{
name: 'deleteSecrets',
icon: faTrash
}
];
/**
* This is the component that we use for the event picker in the activity logs tab.
* @param {object} obj
* @param {string} obj.selected - the event that is currently selected
* @param {function} obj.select - an action that happens when an item is selected
*/
export default function EventFilter({
selected,
select
}: ListBoxProps): JSX.Element {
const { t } = useTranslation();
return (
<Listbox value={t("activity:event." + selected)} onChange={select}>
<div className="relative">
<Listbox.Button className="bg-mineshaft-800 hover:bg-mineshaft-700 duration-200 cursor-pointer rounded-md h-10 flex items-center justify-between pl-4 pr-2 w-52 text-bunker-200 text-sm">
{selected != '' ? (
<p className="select-none text-bunker-100">{t("activity:event." + selected)}</p>
) : (
<p className="select-none">Select an event</p>
)}
{selected != '' ? (
<FontAwesomeIcon
icon={faX}
className="pl-2 w-2 p-2"
onClick={() => select('')}
/>
) : (
<FontAwesomeIcon icon={faAngleDown} className="pl-4 pr-2" />
)}
</Listbox.Button>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="border border-mineshaft-700 z-50 w-52 p-1 absolute mt-1 max-h-60 overflow-auto rounded-md bg-bunker text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{eventOptions.map((event, id) => {
return (
<Listbox.Option
key={id}
className={`px-4 h-10 flex items-center text-sm cursor-pointer hover:bg-mineshaft-700 text-bunker-200 rounded-md ${
selected == t("activity:event." + event.name) && 'bg-mineshaft-700'
}`}
value={event.name}
>
{({ selected }) => (
<>
<span
className={`block truncate ${
selected ? 'font-semibold' : 'font-normal'
}`}
>
<FontAwesomeIcon icon={event.icon} className="pr-4" />{' '}
{t("activity:event." + event.name)}
</span>
</>
)}
</Listbox.Option>
);
})}
</Listbox.Options>
</Transition>
</div>
</Listbox>
);
}
+11 -6
View File
@@ -6,10 +6,12 @@ import { useRouter } from "next/router";
import { useTranslation } from "next-i18next";
import {
faBookOpen,
faFileLines,
faGear,
faKey,
faMobile,
faPlug,
faTimeline,
faUser,
} from "@fortawesome/free-solid-svg-icons";
import { faPlus } from "@fortawesome/free-solid-svg-icons";
@@ -119,7 +121,7 @@ export default function Layout({ children }: LayoutProps) {
}
});
}
router.push("/dashboard/" + newWorkspaceId + "?Development");
router.push("/dashboard/" + newWorkspaceId);
setIsOpen(false);
setNewWorkspaceName("");
} else {
@@ -139,8 +141,7 @@ export default function Layout({ children }: LayoutProps) {
{
href:
"/dashboard/" +
workspaceMapping[workspaceSelected as any] +
"?Development",
workspaceMapping[workspaceSelected as any],
title: t("nav:menu.secrets"),
emoji: <FontAwesomeIcon icon={faKey} />,
},
@@ -154,6 +155,11 @@ export default function Layout({ children }: LayoutProps) {
title: t("nav:menu.integrations"),
emoji: <FontAwesomeIcon icon={faPlug} />,
},
{
href: '/activity/' + workspaceMapping[workspaceSelected as any],
title: 'Activity Logs',
emoji: <FontAwesomeIcon icon={faFileLines} />
},
{
href: "/settings/project/" + workspaceMapping[workspaceSelected as any],
title: t("nav:menu.project-settings"),
@@ -192,7 +198,7 @@ export default function Layout({ children }: LayoutProps) {
.map((workspace: { _id: string }) => workspace._id)
.includes(intendedWorkspaceId)
) {
router.push("/dashboard/" + userWorkspaces[0]._id + "?Development");
router.push("/dashboard/" + userWorkspaces[0]._id);
} else {
setWorkspaceList(
userWorkspaces.map((workspace: any) => workspace.name)
@@ -235,8 +241,7 @@ export default function Layout({ children }: LayoutProps) {
) {
router.push(
"/dashboard/" +
workspaceMapping[workspaceSelected as any] +
"?Development"
workspaceMapping[workspaceSelected as any]
);
localStorage.setItem(
"projectData.id",
+13 -13
View File
@@ -1,12 +1,12 @@
import React from "react";
import { Fragment } from "react";
import React from 'react';
import { Fragment } from 'react';
import {
faAngleDown,
faCheck,
faPlus,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Listbox, Transition } from "@headlessui/react";
faPlus
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Listbox, Transition } from '@headlessui/react';
interface ListBoxProps {
selected: string;
@@ -34,20 +34,20 @@ export default function ListBox({
data,
text,
buttonAction,
isFull,
isFull
}: ListBoxProps): JSX.Element {
return (
<Listbox value={selected} onChange={onChange}>
<div className="relative">
<Listbox.Button
className={`text-gray-400 relative ${
isFull ? "w-full" : "w-52"
isFull ? 'w-full' : 'w-52'
} cursor-default rounded-md bg-white/[0.07] hover:bg-white/[0.11] duration-200 py-2.5 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm`}
>
<div className="flex flex-row">
{text}
<span className="ml-1 cursor-pointer block truncate font-semibold text-gray-300">
{" "}
{' '}
{selected}
</span>
</div>
@@ -70,11 +70,11 @@ export default function ListBox({
key={personIdx}
className={({ active, selected }) =>
`my-0.5 relative cursor-default select-none py-2 pl-10 pr-4 rounded-md ${
selected ? "bg-white/10 text-gray-400 font-bold" : ""
selected ? 'bg-white/10 text-gray-400 font-bold' : ''
} ${
active && !selected
? "bg-white/5 text-mineshaft-200 cursor-pointer"
: "text-gray-400"
? 'bg-white/5 text-mineshaft-200 cursor-pointer'
: 'text-gray-400'
} `
}
value={person}
@@ -83,7 +83,7 @@ export default function ListBox({
<>
<span
className={`block truncate text-primary${
selected ? "font-medium" : "font-normal"
selected ? 'font-medium' : 'font-normal'
}`}
>
{person}
+1 -1
View File
@@ -115,7 +115,7 @@ export default function Button(props: ButtonProps): JSX.Element {
<FontAwesomeIcon
icon={props.icon}
className={`flex my-auto font-extrabold ${
props.size == "icon-sm" ? "text-sm" : "text-md"
props.size == "icon-sm" ? "text-sm" : "text-sm"
} ${(props.text || props.textDisabled) && "mr-2"}`}
/>
)}
@@ -12,6 +12,7 @@ import { envMapping } from "../../../public/data/frequentConstants";
import {
decryptAssymmetric,
encryptAssymmetric,
encryptSymmetric,
} from "../../utilities/cryptography/crypto";
import Button from "../buttons/Button";
import InputField from "../InputField";
@@ -25,11 +26,15 @@ const expiryMapping = {
"12 months": 31104000,
};
const crypto = require('crypto');
const AddServiceTokenDialog = ({
isOpen,
closeModal,
workspaceId,
workspaceName,
serviceTokens,
setServiceTokens
}) => {
const [serviceToken, setServiceToken] = useState("");
const [serviceTokenName, setServiceTokenName] = useState("");
@@ -48,16 +53,14 @@ const AddServiceTokenDialog = ({
privateKey: localStorage.getItem("PRIVATE_KEY"),
});
// generate new public/private key pair
const pair = nacl.box.keyPair();
const publicKey = nacl.util.encodeBase64(pair.publicKey);
const privateKey = nacl.util.encodeBase64(pair.secretKey);
// encrypt workspace key under newly-generated public key
const { ciphertext: encryptedKey, nonce } = encryptAssymmetric({
const randomBytes = crypto.randomBytes(16).toString('hex');
const {
ciphertext,
iv,
tag,
} = encryptSymmetric({
plaintext: key,
publicKey,
privateKey,
key: randomBytes,
});
let newServiceToken = await addServiceToken({
@@ -65,13 +68,15 @@ const AddServiceTokenDialog = ({
workspaceId,
environment: envMapping[serviceTokenEnv],
expiresIn: expiryMapping[serviceTokenExpiresIn],
publicKey,
encryptedKey,
nonce,
encryptedKey: ciphertext,
iv,
tag
});
console.log('newServiceToken', newServiceToken);
const serviceToken = newServiceToken + "," + privateKey;
setServiceToken(serviceToken);
setServiceTokens(serviceTokens.concat([newServiceToken.serviceTokenData]));
setServiceToken(newServiceToken.serviceToken + "." + randomBytes);
};
function copyToClipboard() {
@@ -161,7 +166,7 @@ const AddServiceTokenDialog = ({
"Production",
"Testing",
]}
width="full"
isFull={true}
text={`${t("common:environment")}: `}
/>
</div>
@@ -176,7 +181,7 @@ const AddServiceTokenDialog = ({
"6 months",
"12 months",
]}
width="full"
isFull={true}
text={`${t("common:expired-in")}: `}
/>
</div>
@@ -211,7 +216,7 @@ const AddServiceTokenDialog = ({
</div>
</div>
<div className="w-full">
<div className="flex justify-end items-center bg-white/[0.07] text-base mt-2 mr-2 rounded-md text-gray-400 w-full h-44">
<div className="flex justify-end items-center bg-white/[0.07] text-base mt-2 mr-2 rounded-md text-gray-400 w-full h-20">
<input
type="text"
value={serviceToken}
@@ -236,7 +241,7 @@ const AddServiceTokenDialog = ({
)}
</button>
<span className="absolute hidden group-hover:flex group-hover:animate-popup duration-300 w-28 -left-8 -top-20 translate-y-full px-3 py-2 bg-chicago-900 rounded-md text-center text-gray-400 text-sm">
{t("common.click-to-copy")}
{t("common:click-to-copy")}
</span>
</div>
</div>
@@ -1,36 +1,53 @@
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import { faX } from '@fortawesome/free-solid-svg-icons';
import { useNotificationContext } from '~/components/context/Notifications/NotificationProvider';
import deleteServiceToken from "../../../pages/api/serviceToken/deleteServiceToken";
import { reverseEnvMapping } from '../../../public/data/frequentConstants';
import guidGenerator from '../../utilities/randomId';
import Button from '../buttons/Button';
interface TokenProps {
_id: string;
name: string;
environment: string;
expiresAt: string;
}
interface ServiceTokensProps {
data: TokenProps[];
workspaceName: string;
setServiceTokens: (value: TokenProps[]) => void;
}
/**
* This is the component that we utilize for the user table - in future, can reuse it for some other purposes too.
* This is the component that we utilize for the service token table
* #TODO: add the possibility of choosing and doing operations on multiple users.
* @param {*} props
* @param {object} obj
* @param {any[]} obj.data - current state of the service token table
* @param {string} obj.workspaceName - name of the current project
* @param {function} obj.setServiceTokens - updating the state of the service token table
* @returns
*/
const ServiceTokenTable = ({ data, workspaceName }) => {
const router = useRouter();
const ServiceTokenTable = ({ data, workspaceName, setServiceTokens }: ServiceTokensProps) => {
const { createNotification } = useNotificationContext();
return (
<div className="table-container w-full bg-bunker rounded-md mb-6 border border-mineshaft-700 relative mt-1">
<div className="absolute rounded-t-md w-full h-12 bg-white/5"></div>
<table className="w-full my-1">
<thead className="text-bunker-300">
<thead className="text-bunker-300 text-sm font-light">
<tr>
<th className="text-left pl-6 pt-2.5 pb-2">Token name</th>
<th className="text-left pl-6 pt-2.5 pb-2">Project</th>
<th className="text-left pl-6 pt-2.5 pb-2">Environment</th>
<th className="text-left pl-6 pt-2.5 pb-2">Valid until</th>
<th className="text-left pl-6 pt-2.5 pb-2">TOKEN NAME</th>
<th className="text-left pl-6 pt-2.5 pb-2">PROJECT</th>
<th className="text-left pl-6 pt-2.5 pb-2">ENVIRONMENT</th>
<th className="text-left pl-6 pt-2.5 pb-2">VAILD UNTIL</th>
<th></th>
</tr>
</thead>
<tbody>
{data?.length > 0 ? (
data.map((row, index) => {
data?.map((row) => {
return (
<tr
key={guidGenerator()}
@@ -51,7 +68,14 @@ const ServiceTokenTable = ({ data, workspaceName }) => {
<td className="py-2 border-mineshaft-700 border-t">
<div className="opacity-50 hover:opacity-100 duration-200 flex items-center">
<Button
onButtonPressed={() => {}}
onButtonPressed={() => {
deleteServiceToken({ serviceTokenId: row._id} );
setServiceTokens(data.filter(token => token._id != row._id));
createNotification({
text: `'${row.name}' token has been revoked.`,
type: 'error'
});
}}
color="red"
size="icon-sm"
icon={faX}
@@ -63,7 +87,7 @@ const ServiceTokenTable = ({ data, workspaceName }) => {
})
) : (
<tr>
<td colSpan="4" className="text-center pt-7 pb-4 text-bunker-400">
<td colSpan={4} className="text-center pt-7 pb-5 text-bunker-300 text-sm">
No service tokens yet
</td>
</tr>
@@ -36,7 +36,7 @@ const Notification = ({
return (
<div
className="relative w-full flex items-center justify-between px-4 py-6 rounded-md border border-bunker-500 pointer-events-auto bg-bunker-500"
className="relative w-full flex items-center justify-between px-4 py-4 rounded-md border border-bunker-500 pointer-events-auto bg-bunker-500"
role="alert"
>
{notification.type === 'error' && (
@@ -56,7 +56,7 @@ const Notification = ({
onClick={() => clearNotification(notification.text)}
>
<FontAwesomeIcon
className="text-white w-4 h-3 hover:text-red"
className="text-white pl-2 w-4 h-3 hover:text-red"
icon={faX}
/>
</button>
@@ -38,7 +38,7 @@ const NotificationProvider = ({ children }: NotificationProviderProps) => {
const createNotification = ({
text,
type = 'success',
timeoutMs = 5000
timeoutMs = 4000
}: Notification) => {
const doesNotifExist = notifications.some((notif) => notif.text === text);
@@ -53,7 +53,7 @@ const DashboardInputField = ({
return (
<div className="flex-col w-full">
<div
className={`group relative flex flex-col justify-center w-full max-w-2xl border ${
className={`group relative flex flex-col justify-center w-full border ${
error ? 'border-red' : 'border-mineshaft-500'
} rounded-md`}
>
@@ -85,7 +85,7 @@ const DashboardInputField = ({
return (
<div className="flex-col w-full">
<div
className={`group relative whitespace-pre flex flex-col justify-center w-full max-w-2xl border border-mineshaft-500 rounded-md`}
className={`group relative whitespace-pre flex flex-col justify-center w-full border border-mineshaft-500 rounded-md`}
>
{override == true && <div className='bg-primary-300 absolute top-[0.1rem] right-[0.1rem] z-10 w-min text-xxs px-1 text-black opacity-80 rounded-md'>Override enabled</div>}
<input
@@ -108,9 +108,9 @@ const DashboardInputField = ({
} ${
override ? 'text-primary-300' : 'text-gray-400'
}
absolute flex flex-row whitespace-pre font-mono z-0 ph-no-capture max-w-2xl overflow-x-scroll bg-bunker-800 h-9 rounded-md text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 focus:ring-primary/50 duration-100 no-scrollbar no-scrollbar::-webkit-scrollbar`}
absolute flex flex-row whitespace-pre font-mono z-0 ph-no-capture overflow-x-scroll bg-bunker-800 h-9 rounded-md text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 focus:ring-primary/50 duration-100 no-scrollbar no-scrollbar::-webkit-scrollbar`}
>
{value.split(REGEX).map((word, id) => {
{value?.split(REGEX).map((word, id) => {
if (word.match(REGEX) !== null) {
return (
<span className="ph-no-capture text-yellow" key={id}>
@@ -139,7 +139,7 @@ const DashboardInputField = ({
})}
</div>
{blurred && (
<div className="absolute flex flex-row items-center z-20 peer pr-2 bg-bunker-800 group-hover:hidden peer-hover:hidden peer-focus:hidden peer-active:invisible h-9 w-full max-w-2xl rounded-md text-gray-400/50 text-clip">
<div className="absolute flex flex-row items-center z-20 peer pr-2 bg-bunker-800 group-hover:hidden peer-hover:hidden peer-focus:hidden peer-active:invisible h-9 w-full rounded-md text-gray-400/50 text-clip">
<div className="px-2 flex flex-row items-center overflow-x-scroll no-scrollbar no-scrollbar::-webkit-scrollbar">
{value.split('').map(() => (
<FontAwesomeIcon
+11 -20
View File
@@ -15,40 +15,40 @@ interface SecretDataProps {
interface KeyPairProps {
keyPair: SecretDataProps;
deleteRow: (id: string) => void;
modifyKey: (value: string, position: number) => void;
modifyValue: (value: string, position: number) => void;
isBlurred: boolean;
isDuplicate: boolean;
toggleSidebar: (id: string) => void;
sidebarSecretId: string;
isSnapshot: boolean;
}
/**
* This component represent a single row for an environemnt variable on the dashboard
* @param {object} obj
* @param {String[]} obj.keyPair - data related to the environment variable (id, pos, key, value, public/private)
* @param {function} obj.deleteRow - a function to delete a certain keyPair
* @param {function} obj.modifyKey - modify the key of a certain environment variable
* @param {function} obj.modifyValue - modify the value of a certain environment variable
* @param {boolean} obj.isBlurred - if the blurring setting is turned on
* @param {boolean} obj.isDuplicate - list of all the duplicates secret names on the dashboard
* @param {function} obj.toggleSidebar - open/close/switch sidebar
* @param {string} obj.sidebarSecretId - the id of a secret for the side bar is displayed
* @param {boolean} obj.isSnapshot - whether this keyPair is in a snapshot. If so, it won't have some features like sidebar
* @returns
*/
const KeyPair = ({
keyPair,
deleteRow,
modifyKey,
modifyValue,
isBlurred,
isDuplicate,
toggleSidebar,
sidebarSecretId
sidebarSecretId,
isSnapshot
}: KeyPairProps) => {
return (
<div className={`mx-1 flex flex-col items-center ml-1 ${keyPair.id == sidebarSecretId && "bg-mineshaft-500 duration-200"} rounded-md`}>
<div className={`mx-1 flex flex-col items-center ml-1 ${isSnapshot && "pointer-events-none"} ${keyPair.id == sidebarSecretId && "bg-mineshaft-500 duration-200"} rounded-md`}>
<div className="relative flex flex-row justify-between w-full max-w-5xl mr-auto max-h-14 my-1 items-start px-1">
{keyPair.type == "personal" && <div className="group font-normal group absolute top-[1rem] left-[0.2rem] z-40 inline-block text-gray-300 underline hover:text-primary duration-200">
<div className='w-1 h-1 rounded-full bg-primary z-40'></div>
@@ -57,7 +57,7 @@ const KeyPair = ({
</span>
</div>}
<div className="min-w-xl w-96">
<div className="flex pr-1 items-center rounded-lg mt-4 md:mt-0 max-h-16">
<div className="flex pr-1.5 items-center rounded-lg mt-4 md:mt-0 max-h-16">
<DashboardInputField
onChangeHandler={modifyKey}
type="varName"
@@ -67,8 +67,8 @@ const KeyPair = ({
/>
</div>
</div>
<div className="w-full min-w-5xl">
<div className="flex min-w-7xl items-center pl-1 pr-1.5 rounded-lg mt-4 md:mt-0 max-h-10 ">
<div className="w-full min-w-xl">
<div className={`flex min-w-xl items-center ${!isSnapshot && "pr-1.5"} rounded-lg mt-4 md:mt-0 max-h-10`}>
<DashboardInputField
onChangeHandler={modifyValue}
type="value"
@@ -79,24 +79,15 @@ const KeyPair = ({
/>
</div>
</div>
<div onClick={() => toggleSidebar(keyPair.id)} className="cursor-pointer w-9 h-9 bg-mineshaft-700 hover:bg-chicago-700 rounded-md flex flex-row justify-center items-center duration-200">
{!isSnapshot && <div onClick={() => toggleSidebar(keyPair.id)} className="cursor-pointer w-[2.35rem] h-[2.35rem] bg-mineshaft-700 hover:bg-chicago-700 rounded-md flex flex-row justify-center items-center duration-200">
<FontAwesomeIcon
className="text-gray-300 px-2.5 text-lg mt-0.5"
icon={faEllipsis}
/>
</div>
<div className="w-2"></div>
<div className="bg-[#9B3535] hover:bg-red rounded-md duration-200">
<Button
onButtonPressed={() => deleteRow(keyPair.id)}
color="none"
size="icon-sm"
icon={faX}
/>
</div>
</div>}
</div>
</div>
);
};
export default React.memo(KeyPair);
export default KeyPair;
+88 -73
View File
@@ -1,4 +1,5 @@
import { useState } from 'react';
import Image from 'next/image';
import { useTranslation } from "next-i18next";
import { faX } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
@@ -40,6 +41,7 @@ interface SideBarProps {
savePush: () => void;
sharedToHide: string[];
setSharedToHide: (values: string[]) => void;
deleteRow: any;
}
/**
@@ -54,6 +56,7 @@ interface SideBarProps {
* @param {function} obj.savePush - save changes andp ush secrets
* @param {string[]} obj.sharedToHide - an array of shared secrets that we want to hide visually because they are overriden.
* @param {function} obj.setSharedToHide - a function that updates the array of secrets that we want to hide visually
* @param {function} obj.deleteRow - a function to delete a certain keyPair
* @returns the sidebar with 'secret's settings'
*/
const SideBar = ({
@@ -67,93 +70,97 @@ const SideBar = ({
buttonReady,
savePush,
sharedToHide,
setSharedToHide
setSharedToHide,
deleteRow
}: SideBarProps) => {
const [isLoading, setIsLoading] = useState(false);
const [overrideEnabled, setOverrideEnabled] = useState(data.map(secret => secret.type).includes("personal"));
const { t } = useTranslation();
return <div className='absolute border-l border-mineshaft-500 bg-bunker fixed h-full w-96 top-14 right-0 z-50 shadow-xl flex flex-col justify-between'>
<div className='h-min overflow-y-auto'>
<div className="flex flex-row px-4 py-3 border-b border-mineshaft-500 justify-between items-center">
<p className="font-semibold text-lg text-bunker-200">{t("dashboard:sidebar.secret")}</p>
<div className='p-1' onClick={() => toggleSidebar("None")}>
<FontAwesomeIcon icon={faX} className='w-4 h-4 text-bunker-300 cursor-pointer'/>
return <div className='absolute border-l border-mineshaft-500 bg-bunker fixed h-full w-96 top-14 right-0 z-40 shadow-xl flex flex-col justify-between'>
{isLoading ? (
<div className="flex items-center justify-center h-full">
<Image
src="/images/loading/loading.gif"
height={60}
width={100}
alt="infisical loading indicator"
></Image>
</div>
) : (
<div className='h-min overflow-y-auto'>
<div className="flex flex-row px-4 py-3 border-b border-mineshaft-500 justify-between items-center">
<p className="font-semibold text-lg text-bunker-200">{t("dashboard:sidebar.secret")}</p>
<div className='p-1' onClick={() => toggleSidebar("None")}>
<FontAwesomeIcon icon={faX} className='w-4 h-4 text-bunker-300 cursor-pointer'/>
</div>
</div>
</div>
<div className='mt-4 px-4 pointer-events-none'>
<p className='text-sm text-bunker-300'>{t("dashboard:sidebar.key")}</p>
<DashboardInputField
onChangeHandler={modifyKey}
type="varName"
position={data[0]?.pos}
value={data[0]?.key}
isDuplicate={false}
blurred={false}
/>
</div>
{data.filter(secret => secret.type == "shared")[0]?.value
? <div className={`relative mt-2 px-4 ${overrideEnabled && "opacity-40 pointer-events-none"} duration-200`}>
<p className='text-sm text-bunker-300'>{t("dashboard:sidebar.value")}</p>
<DashboardInputField
onChangeHandler={modifyValue}
type="value"
position={data.filter(secret => secret.type == "shared")[0]?.pos}
value={data.filter(secret => secret.type == "shared")[0]?.value}
isDuplicate={false}
blurred={true}
/>
<div className='absolute bg-bunker-800 right-[1.07rem] top-[1.6rem] z-50'>
<GenerateSecretMenu modifyValue={modifyValue} position={data.filter(secret => secret.type == "shared")[0]?.pos} />
</div>
</div>
: <div className='px-4 text-sm text-bunker-300 pt-4'>
<span className='py-0.5 px-1 rounded-md bg-primary-200/10 mr-1'>{t("common:note")}:</span>
{t("dashboard:sidebar.personal-explanation")}
</div>}
<div className='mt-4 px-4'>
{data.filter(secret => secret.type == "shared")[0]?.value &&
<div className='flex flex-row items-center justify-between my-2 pl-1 pr-2'>
<p className='text-sm text-bunker-300'>{t("dashboard:sidebar.override")}</p>
<Toggle
enabled={overrideEnabled}
setEnabled={setOverrideEnabled}
addOverride={addOverride}
keyName={data[0]?.key}
value={data[0]?.value}
pos={data[0]?.pos}
id={data[0]?.id}
comment={data[0]?.comment}
deleteOverride={deleteOverride}
sharedToHide={sharedToHide}
setSharedToHide={setSharedToHide}
<div className='mt-4 px-4 pointer-events-none'>
<p className='text-sm text-bunker-300'>{t("dashboard:sidebar.key")}</p>
<DashboardInputField
onChangeHandler={modifyKey}
type="varName"
position={data[0]?.pos}
value={data[0]?.key}
isDuplicate={false}
blurred={false}
/>
</div>}
<div className={`relative ${!overrideEnabled && "opacity-40 pointer-events-none"} duration-200`}>
</div>
{data.filter(secret => secret.type == "shared")[0]?.value
? <div className={`relative mt-2 px-4 ${overrideEnabled && "opacity-40 pointer-events-none"} duration-200`}>
<p className='text-sm text-bunker-300'>{t("dashboard:sidebar.value")}</p>
<DashboardInputField
onChangeHandler={modifyValue}
type="value"
position={overrideEnabled ? data.filter(secret => secret.type == "personal")[0]?.pos : data[0]?.pos}
value={overrideEnabled ? data.filter(secret => secret.type == "personal")[0]?.value : data[0]?.value}
position={data.filter(secret => secret.type == "shared")[0]?.pos}
value={data.filter(secret => secret.type == "shared")[0]?.value}
isDuplicate={false}
blurred={true}
blurred={true}
/>
<div className='absolute right-[0.57rem] top-[0.3rem] z-50'>
<GenerateSecretMenu modifyValue={modifyValue} position={overrideEnabled ? data.filter(secret => secret.type == "personal")[0]?.pos : data[0]?.pos} />
<div className='absolute bg-bunker-800 right-[1.07rem] top-[1.6rem] z-50'>
<GenerateSecretMenu modifyValue={modifyValue} position={data.filter(secret => secret.type == "shared")[0]?.pos} />
</div>
</div>
: <div className='px-4 text-sm text-bunker-300 pt-4'>
<span className='py-0.5 px-1 rounded-md bg-primary-200/10 mr-1'>{t("common:note")}:</span>
{t("dashboard:sidebar.personal-explanation")}
</div>}
<div className='mt-4 px-4'>
{data.filter(secret => secret.type == "shared")[0]?.value &&
<div className='flex flex-row items-center justify-between my-2 pl-1 pr-2'>
<p className='text-sm text-bunker-300'>{t("dashboard:sidebar.override")}</p>
<Toggle
enabled={overrideEnabled}
setEnabled={setOverrideEnabled}
addOverride={addOverride}
keyName={data[0]?.key}
value={data[0]?.value}
pos={data[0]?.pos}
id={data[0]?.id}
comment={data[0]?.comment}
deleteOverride={deleteOverride}
sharedToHide={sharedToHide}
setSharedToHide={setSharedToHide}
/>
</div>}
<div className={`relative ${!overrideEnabled && "opacity-40 pointer-events-none"} duration-200`}>
<DashboardInputField
onChangeHandler={modifyValue}
type="value"
position={overrideEnabled ? data.filter(secret => secret.type == "personal")[0]?.pos : data[0]?.pos}
value={overrideEnabled ? data.filter(secret => secret.type == "personal")[0]?.value : data[0]?.value}
isDuplicate={false}
blurred={true}
/>
<div className='absolute right-[0.57rem] top-[0.3rem] z-50'>
<GenerateSecretMenu modifyValue={modifyValue} position={overrideEnabled ? data.filter(secret => secret.type == "personal")[0]?.pos : data[0]?.pos} />
</div>
</div>
</div>
<SecretVersionList secretId={data[0]?.id} />
<CommentField comment={data.filter(secret => secret.type == "shared")[0]?.comment} modifyComment={modifyComment} position={data[0]?.pos} />
</div>
{/* <div className={`relative mt-4 px-4 opacity-80 duration-200`}>
<p className='text-sm text-bunker-200'>Group</p>
<ListBox
selected={"Database Secrets"}
onChange={() => {}}
data={["Group1"]}
isFull={true}
/>
</div> */}
<SecretVersionList secretId={data[0]?.id} />
<CommentField comment={data.filter(secret => secret.type == "shared")[0]?.comment} modifyComment={modifyComment} position={data[0]?.pos} />
</div>
)}
<div className={`flex justify-start max-w-sm mt-4 px-4 mt-full mb-[4.7rem]`}>
<Button
text={String(t("common:save-changes"))}
@@ -163,6 +170,14 @@ const SideBar = ({
active={buttonReady}
textDisabled="Saved"
/>
<div className="bg-[#9B3535] opacity-70 hover:opacity-100 w-[4.5rem] h-[2.5rem] rounded-md duration-200 ml-2">
<Button
text={String(t("Delete"))}
onButtonPressed={() => deleteRow({ ids: overrideEnabled ? data.map(secret => secret.id) : [data.filter(secret => secret.type == "shared")[0]?.id], secretName: data[0]?.key })}
color="red"
size="md"
/>
</div>
</div>
</div>
};
@@ -52,6 +52,7 @@ const attemptLogin = async (
// if everything works, go the main dashboard page.
const { token, publicKey, encryptedPrivateKey, iv, tag } =
await login2(email, clientProof);
SecurityClient.setToken(token);
const privateKey = Aes256Gcm.decrypt({
@@ -10,7 +10,7 @@ class Capturer {
capture(item) {
if (ENV == "production" && TELEMETRY_CAPTURING_ENABLED) {
try {
api.capture(item);
this.api.capture(item);
} catch (error) {
console.error("PostHog", error);
}
@@ -20,7 +20,7 @@ class Capturer {
identify(id) {
if (ENV == "production" && TELEMETRY_CAPTURING_ENABLED) {
try {
api.identify(id);
this.api.identify(id);
} catch (error) {
console.error("PostHog", error);
}