Added sharing keys with a user while creating a new project

This commit is contained in:
Vladyslav Matsiiako
2023-01-09 19:01:22 -08:00
parent ce7d411f29
commit 556a646dce
6 changed files with 171 additions and 83 deletions
@@ -36,7 +36,7 @@ export default function BottonRightPopup({
}: PopupProps): JSX.Element { }: PopupProps): JSX.Element {
return ( return (
<div <div
className="z-50 drop-shadow-xl border-gray-600/50 border flex flex-col items-start bg-bunker max-w-xl text-gray-200 pt-3 pb-4 rounded-xl absolute bottom-0 right-0 mr-6 mb-6" className="z-50 drop-shadow-xl border-gray-600/50 border flex flex-col items-start bg-bunker max-w-xl text-gray-200 pt-3 pb-4 rounded-md absolute bottom-0 right-0 mr-6 mb-6"
role="alert" role="alert"
> >
<div className="flex flex-row items-center justify-between w-full border-b border-gray-600/70 pb-3 px-6"> <div className="flex flex-row items-center justify-between w-full border-b border-gray-600/70 pb-3 px-6">
@@ -112,9 +112,9 @@ export default function Navbar() {
href="https://infisical.com/docs/getting-started/introduction" href="https://infisical.com/docs/getting-started/introduction"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-gray-200 hover:text-primary duration-200"> className="text-gray-200 hover:bg-white/10 px-3 rounded-md duration-200 text-sm mr-4 py-2 flex items-center">
<FontAwesomeIcon icon={faBook} className="text-xl mr-2" />
Docs Docs
<FontAwesomeIcon icon={faUpRightFromSquare} className="text-xs mb-[0.1rem] mr-5 ml-1.5" />
</a> </a>
<Menu as="div" className="relative inline-block text-left"> <Menu as="div" className="relative inline-block text-left">
<div className="mr-4"> <div className="mr-4">
+78 -1
View File
@@ -4,7 +4,10 @@ import login2 from '~/pages/api/auth/Login2';
import addSecrets from '~/pages/api/files/AddSecrets'; import addSecrets from '~/pages/api/files/AddSecrets';
import getOrganizations from '~/pages/api/organization/getOrgs'; import getOrganizations from '~/pages/api/organization/getOrgs';
import getOrganizationUserProjects from '~/pages/api/organization/GetOrgUserProjects'; import getOrganizationUserProjects from '~/pages/api/organization/GetOrgUserProjects';
import getUser from '~/pages/api/user/getUser';
import uploadKeys from '~/pages/api/workspace/uploadKeys';
import { encryptAssymmetric } from './cryptography/crypto';
import encryptSecrets from './secrets/encryptSecrets'; import encryptSecrets from './secrets/encryptSecrets';
import Telemetry from './telemetry/Telemetry'; import Telemetry from './telemetry/Telemetry';
import { saveTokenToLocalStorage } from './saveTokenToLocalStorage'; import { saveTokenToLocalStorage } from './saveTokenToLocalStorage';
@@ -19,6 +22,7 @@ interface SecretDataProps {
comment: string; comment: string;
} }
const crypto = require("crypto");
const nacl = require('tweetnacl'); const nacl = require('tweetnacl');
nacl.util = require('tweetnacl-util'); nacl.util = require('tweetnacl-util');
const jsrp = require('jsrp'); const jsrp = require('jsrp');
@@ -121,8 +125,81 @@ const attemptLogin = async (
telemetry.capture('User Logged In'); telemetry.capture('User Logged In');
} }
if (isSignUp) {
const randomBytes = crypto.randomBytes(16).toString("hex");
const PRIVATE_KEY = String(localStorage.getItem("PRIVATE_KEY"));
const myUser = await getUser();
const { ciphertext, nonce } = encryptAssymmetric({
plaintext: randomBytes,
publicKey: myUser.publicKey,
privateKey: PRIVATE_KEY,
}) as { ciphertext: string; nonce: string };
await uploadKeys(
projectToLogin,
myUser._id,
ciphertext,
nonce
);
const secretsToBeAdded: SecretDataProps[] = [{
type: "shared",
pos: 0,
key: "DATABASE_URL",
value: "mongodb+srv://${DB_USERNAME}:${DB_PASSWORD}@mongodb.net",
comment: "This is an example of secret referencing.",
id: ''
}, {
type: "shared",
pos: 1,
key: "DB_USERNAME",
value: "OVERRIDE_THIS",
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",
id: ''
}, {
type: "personal",
pos: 2,
key: "DB_USERNAME",
value: "user1234",
comment: "",
id: ''
}, {
type: "shared",
pos: 3,
key: "DB_PASSWORD",
value: "OVERRIDE_THIS",
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",
id: ''
}, {
type: "personal",
pos: 4,
key: "DB_PASSWORD",
value: "example_password",
comment: "",
id: ''
}, {
type: "shared",
pos: 5,
key: "TWILIO_AUTH_TOKEN",
value: "example_twillio_token",
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",
id: ''
}, {
type: "shared",
pos: 6,
key: "WEBSITE_URL",
value: "http://localhost:3000",
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",
id: ''
}]
const secrets = await encryptSecrets({ secretsToEncrypt: secretsToBeAdded, workspaceId: String(localStorage.getItem('projectData.id')), env: 'dev' })
await addSecrets({ secrets: secrets ?? [], env: "dev", workspaceId: String(localStorage.getItem('projectData.id')) });
}
if (isLogin) { if (isLogin) {
router.push('/dashboard/'); router.push('/dashboard/' + localStorage.getItem('projectData.id'));
} }
} catch (error) { } catch (error) {
console.log(error) console.log(error)
@@ -42,6 +42,8 @@ interface EncryptedSecretProps {
* @returns * @returns
*/ */
const encryptSecrets = async ({ secretsToEncrypt, workspaceId, env }: { secretsToEncrypt: SecretDataProps[]; workspaceId: string; env: string; }) => { const encryptSecrets = async ({ secretsToEncrypt, workspaceId, env }: { secretsToEncrypt: SecretDataProps[]; workspaceId: string; env: string; }) => {
let secrets;
try {
const sharedKey = await getLatestFileKey({ workspaceId }); const sharedKey = await getLatestFileKey({ workspaceId });
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY");
@@ -60,7 +62,7 @@ const encryptSecrets = async ({ secretsToEncrypt, workspaceId, env }: { secretsT
randomBytes = crypto.randomBytes(16).toString("hex"); randomBytes = crypto.randomBytes(16).toString("hex");
} }
const secrets = secretsToEncrypt.map((secret) => { secrets = secretsToEncrypt.map((secret) => {
// encrypt key // encrypt key
const { const {
ciphertext: secretKeyCiphertext, ciphertext: secretKeyCiphertext,
@@ -109,8 +111,12 @@ const encryptSecrets = async ({ secretsToEncrypt, workspaceId, env }: { secretsT
return result; return result;
}); });
} catch (error) {
console.log("Error while encrypting secrets");
}
return secrets; return secrets;
} }
export default encryptSecrets; export default encryptSecrets;
+3 -5
View File
@@ -72,10 +72,8 @@ const ActivityLogsRow = ({ row, toggleSidebar }: { row: logData, toggleSidebar:
<td>{String(t("common:timestamp"))}</td> <td>{String(t("common:timestamp"))}</td>
<td>{row.createdAt}</td> <td>{row.createdAt}</td>
</tr>} </tr>}
{payloadOpened && {payloadOpened && row.payload?.map((action, index) => {
row.payload?.map((action, index) => { return action.secretVersions.length > 0 && <tr key={index} className="h-9 text-bunker-200 border-mineshaft-700 border-t text-sm">
action.secretVersions.length > 0 &&
<tr key={index} className="h-9 text-bunker-200 border-mineshaft-700 border-t text-sm">
<td></td> <td></td>
<td className="">{t("activity:event." + action.name)}</td> <td className="">{t("activity:event." + action.name)}</td>
<td className="text-primary-300 cursor-pointer hover:text-primary duration-200" onClick={() => toggleSidebar(action._id)}> <td className="text-primary-300 cursor-pointer hover:text-primary duration-200" onClick={() => toggleSidebar(action._id)}>
@@ -87,7 +85,7 @@ const ActivityLogsRow = ({ row, toggleSidebar }: { row: logData, toggleSidebar:
{payloadOpened && {payloadOpened &&
<tr className='h-9 text-bunker-200 border-mineshaft-700 border-t text-sm'> <tr className='h-9 text-bunker-200 border-mineshaft-700 border-t text-sm'>
<td></td> <td></td>
<td>{String(t("common:ip-address"))}</td> <td>{String(t("activity:ip-address"))}</td>
<td>{row.ipAddress}</td> <td>{row.ipAddress}</td>
</tr>} </tr>}
</> </>
+13 -6
View File
@@ -16,11 +16,9 @@ import {
faPlus, faPlus,
} from '@fortawesome/free-solid-svg-icons'; } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Menu, Transition } from '@headlessui/react';
import getProjectSercetSnapshotsCount from 'ee/api/secrets/GetProjectSercetSnapshotsCount'; import getProjectSercetSnapshotsCount from 'ee/api/secrets/GetProjectSercetSnapshotsCount';
import performSecretRollback from 'ee/api/secrets/PerformSecretRollback'; import performSecretRollback from 'ee/api/secrets/PerformSecretRollback';
import PITRecoverySidebar from 'ee/components/PITRecoverySidebar'; import PITRecoverySidebar from 'ee/components/PITRecoverySidebar';
import { Document, YAMLSeq } from 'yaml';
import Button from '~/components/basic/buttons/Button'; import Button from '~/components/basic/buttons/Button';
import ListBox from '~/components/basic/Listbox'; import ListBox from '~/components/basic/Listbox';
@@ -542,15 +540,24 @@ export default function Dashboard() {
text={String(t("Rollback to this snapshot"))} text={String(t("Rollback to this snapshot"))}
onButtonPressed={async () => { onButtonPressed={async () => {
// Update secrets in the state only for the current environment // Update secrets in the state only for the current environment
setData( const rolledBackSecrets = snapshotData.secretVersions
snapshotData.secretVersions
.filter(row => reverseEnvMapping[row.environment] == env) .filter(row => reverseEnvMapping[row.environment] == env)
.map((sv, position) => { .map((sv, position) => {
return { return {
id: sv.id, pos: position, type: sv.type, key: sv.key, value: sv.value, comment: '' id: sv.id, pos: position, type: sv.type, key: sv.key, value: sv.value, comment: ''
} }
}) });
); setData(rolledBackSecrets);
setSharedToHide(
rolledBackSecrets?.filter(row => (rolledBackSecrets
?.map((item) => item.key)
.filter(
(item, index) =>
index !==
rolledBackSecrets?.map((item) => item.key).indexOf(item)
).includes(row.key) && row.type == 'shared'))?.map((item) => item.id)
)
// Perform the rollback globally // Perform the rollback globally
performSecretRollback({ workspaceId, version: snapshotData.version }) performSecretRollback({ workspaceId, version: snapshotData.version })