diff --git a/frontend/components/utilities/secrets/getSecretsForProject.ts b/frontend/components/utilities/secrets/getSecretsForProject.ts
index de034323f..57f0e4a16 100644
--- a/frontend/components/utilities/secrets/getSecretsForProject.ts
+++ b/frontend/components/utilities/secrets/getSecretsForProject.ts
@@ -15,6 +15,7 @@ interface SecretProps {
value: string;
type: 'personal' | 'shared';
comment: string;
+ id: string;
}
interface Props {
@@ -85,6 +86,7 @@ const getSecretsForProject = async ({
}
tempFileState.push({
+ id: secretPair._id,
key: plainTextKey,
value: plainTextValue,
type: secretPair.type,
@@ -97,7 +99,7 @@ const getSecretsForProject = async ({
setData(
tempFileState.map((line, index) => {
return {
- id: guidGenerator(),
+ id: line['id'],
pos: index,
key: line['key'],
value: line['value'],
@@ -109,7 +111,7 @@ const getSecretsForProject = async ({
return tempFileState.map((line, index) => {
return {
- id: guidGenerator(),
+ id: line['id'],
pos: index,
key: line['key'],
value: line['value'],
diff --git a/frontend/ee/api/secrets/GetSecretVersions.ts b/frontend/ee/api/secrets/GetSecretVersions.ts
new file mode 100644
index 000000000..8185234e6
--- /dev/null
+++ b/frontend/ee/api/secrets/GetSecretVersions.ts
@@ -0,0 +1,40 @@
+import SecurityClient from '~/utilities/SecurityClient';
+
+
+interface secretVersionProps {
+ secretId: string;
+ offset: number;
+ limit: number;
+}
+
+/**
+ * This function fetches the versions of a specific secret
+ * @param {object} obj
+ * @param {string} obj.secretId - the id of a secret for which we are fetching the version history
+ * @param {number} obj.offset - the start of our query
+ * @param {number} obj.limit - how far our query goes
+ * @returns
+ */
+const getSecretVersions = async ({ secretId, offset, limit }: secretVersionProps) => {
+ return SecurityClient.fetchCall(
+ '/api/v1/secret/' + secretId + '/secret-versions?'+
+ new URLSearchParams({
+ offset: String(offset),
+ limit: String(limit)
+ }),
+ {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ }
+ ).then(async (res) => {
+ if (res && res.status == 200) {
+ return await res.json();
+ } else {
+ console.log('Failed to get project secrets');
+ }
+ });
+};
+
+export default getSecretVersions;
diff --git a/frontend/ee/components/SecretVersionList.tsx b/frontend/ee/components/SecretVersionList.tsx
index a2147c2af..0bc8d6740 100644
--- a/frontend/ee/components/SecretVersionList.tsx
+++ b/frontend/ee/components/SecretVersionList.tsx
@@ -1,38 +1,95 @@
-import { useState } from 'react';
+import { useEffect, useState } from 'react';
+import { useRouter } from 'next/router';
import { faCircle, faDotCircle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import getSecretVersions from 'ee/api/secrets/GetSecretVersions';
-// eslint-disable-next-line @typescript-eslint/no-empty-interface
-interface SecretVersionListProps {}
+import { decryptAssymmetric, decryptSymmetric } from '~/components/utilities/cryptography/crypto';
+import getLatestFileKey from '~/pages/api/workspace/getLatestFileKey';
+
+interface DecryptedSecretVersionListProps {
+ createdAt: string;
+ value: string;
+}
+
+interface EncrypetedSecretVersionListProps {
+ createdAt: string;
+ secretValueCiphertext: string;
+ secretValueIV: string;
+ secretValueTag: string;
+}
-const versionData = [{
- value: "Value1",
- date: "Date1",
- user: "vlad@infisical.com"
-}, {
- value: "Value2",
- date: "Date2",
- user: "tony@infisical.com"
-}]
/**
- * @returns a list of the versions for a specific secret
+ * @returns a list of versions for a specific secret
*/
-const SecretVersionList = () => {
+const SecretVersionList = ({ secretId }: { secretId: string; }) => {
+ const router = useRouter();
+ const [secretVersions, setSecretVersions] = useState
([{createdAt: "123", value: "124"}]);
+
+ useEffect(() => {
+ const getSecretVersionHistory = async () => {
+ try {
+ const encryptedSecretVersions = await getSecretVersions({ secretId, offset: 0, limit: 10});
+ const latestKey = await getLatestFileKey({ workspaceId: String(router.query.id) })
+
+ const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY');
+
+ let decryptedLatestKey: string;
+ if (latestKey) {
+ // assymmetrically decrypt symmetric key with local private key
+ decryptedLatestKey = decryptAssymmetric({
+ ciphertext: latestKey.latestKey.encryptedKey,
+ nonce: latestKey.latestKey.nonce,
+ publicKey: latestKey.latestKey.sender.publicKey,
+ privateKey: String(PRIVATE_KEY)
+ });
+ }
+
+ const decryptedSecretVersions = encryptedSecretVersions.secretVersions.map((encryptedSecretVersion: EncrypetedSecretVersionListProps) => {
+ return {
+ createdAt: encryptedSecretVersion.createdAt,
+ value: decryptSymmetric({
+ ciphertext: encryptedSecretVersion.secretValueCiphertext,
+ iv: encryptedSecretVersion.secretValueIV,
+ tag: encryptedSecretVersion.secretValueTag,
+ key: decryptedLatestKey
+ })
+ }
+ })
+
+ setSecretVersions(decryptedSecretVersions);
+ } catch (error) {
+ console.log(error)
+ }
+ };
+ getSecretVersionHistory();
+ }, []);
+
return
Version History
-
- {versionData.map((version, index) =>
+
+ {secretVersions?.sort((a, b) => b.createdAt.localeCompare(a.createdAt))
+ .map((version: DecryptedSecretVersionListProps, index: number) =>
-
{version.date}
+
+ {(new Date(version.createdAt)).toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit'
+ })}
+
-
Updated by:{version.user}
+ {/*
Updated by:{version.user}
*/}
)}
diff --git a/frontend/public/images/invitation-expired.svg b/frontend/public/images/invitation-expired.svg
new file mode 100644
index 000000000..0daf7eda4
--- /dev/null
+++ b/frontend/public/images/invitation-expired.svg
@@ -0,0 +1,305 @@
+