Merge remote-tracking branch 'upstream/main' into feat/39

This commit is contained in:
이강준
2022-12-26 22:11:09 +09:00
432 changed files with 20869 additions and 5690 deletions
+28
View File
@@ -0,0 +1,28 @@
import React from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
export default function Custom404() {
return (
<div className="bg-bunker-800 md:h-screen flex flex-col justify-between">
<Head>
<title>Infisical | Page Not Found</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<div className="flex flex-col items-center justify-center text-gray-200 h-screen w-screen">
<p className="text-4xl mt-32">Oops, something went wrong</p>
<p className="mt-2 mb-1 text-lg">Think this is a mistake? Email <a className="text-primary underline underline-offset-4" href="mailto:[email protected]">team@infisical.com</a> and we`ll fix it! </p>
<Link href="/dashboard" className="bg-mineshaft-500 mt-8 py-2 px-4 rounded-md hover:bg-primary diration-200 hover:text-black cursor-pointer font-semibold">
Go to Dashboard
</Link>
<Image
src="/images/dragon-404.svg"
height={554}
width={942}
alt="google logo"
></Image>
</div>
</div>
);
}
+4 -8
View File
@@ -3,12 +3,11 @@ import { useRouter } from "next/router";
import { appWithTranslation } from "next-i18next";
import { config } from "@fortawesome/fontawesome-svg-core";
import { initPostHog } from "~/components/analytics/posthog";
import Layout from "~/components/basic/layout";
import Layout from "~/components/basic/Layout";
import NotificationProvider from "~/components/context/Notifications/NotificationProvider";
import RouteGuard from "~/components/RouteGuard";
import { publicPaths } from "~/const";
import { ENV } from "~/utilities/config";
import Telemetry from "~/utilities/telemetry/Telemetry";
import "@fortawesome/fontawesome-svg-core/styles.css";
import "../styles/globals.css";
@@ -17,7 +16,6 @@ config.autoAddCss = false;
const App = ({ Component, pageProps, ...appProps }) => {
const router = useRouter();
const posthog = initPostHog();
// useEffect(() => {
// const storedLang = localStorage.getItem("lang");
@@ -32,13 +30,11 @@ const App = ({ Component, pageProps, ...appProps }) => {
useEffect(() => {
// Init for auto capturing
const posthog = initPostHog();
const telemetry = new Telemetry().getInstance();
const handleRouteChange = () => {
if (typeof window !== "undefined") {
if (ENV == "production") {
posthog.capture("$pageview");
}
telemetry.capture("$pageview");
}
};
@@ -1,4 +1,13 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
encryptedPrivateKey: string;
iv: string;
tag: string;
salt: string;
verifier: string;
clientProof: string;
}
/**
* This is the second step of the change password process (pake)
@@ -11,12 +20,12 @@ const changePassword2 = ({
tag,
salt,
verifier,
clientProof,
}) => {
return SecurityClient.fetchCall("/api/v1/password/change-password", {
method: "POST",
clientProof
}: Props) => {
return SecurityClient.fetchCall('/api/v1/password/change-password', {
method: 'POST',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json'
},
body: JSON.stringify({
clientProof: clientProof,
@@ -24,13 +33,13 @@ const changePassword2 = ({
iv: iv,
tag: tag,
salt: salt,
verifier: verifier,
}),
verifier: verifier
})
}).then(async (res) => {
if (res.status == 200) {
if (res && res.status == 200) {
return res;
} else {
console.log("Failed to change the password");
console.log('Failed to change the password');
}
});
};
-25
View File
@@ -1,25 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient.js";
/**
* This function is used to check if the user is authenticated.
* To do that, we get their tokens from cookies, and verify if they are good.
* @param {*} req
* @param {*} res
* @returns
*/
const checkAuth = async (req, res) => {
return SecurityClient.fetchCall("/api/v1/auth/checkAuth", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
}).then((res) => {
if (res.status == 200) {
return res;
} else {
console.log("Not authorized");
}
});
};
export default checkAuth;
+22
View File
@@ -0,0 +1,22 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This function is used to check if the user is authenticated.
* To do that, we get their tokens from cookies, and verify if they are good.
*/
const checkAuth = async () => {
return SecurityClient.fetchCall('/api/v1/auth/checkAuth', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
}).then((res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Not authorized');
}
});
};
export default checkAuth;
@@ -1,20 +0,0 @@
/**
* This route check the verification code from the email that user just recieved
* @param {*} email
* @param {*} code
* @returns
*/
const checkEmailVerificationCode = (email, code) => {
return fetch("/api/v1/signup/email/verify", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
code: code,
}),
});
};
export default checkEmailVerificationCode;
@@ -0,0 +1,26 @@
interface Props {
email: string;
code: string;
}
/**
* This route check the verification code from the email that user just recieved
* @param {object} obj
* @param {string} obj.email
* @param {string} obj.code
* @returns
*/
const checkEmailVerificationCode = ({ email, code }: Props) => {
return fetch('/api/v1/signup/email/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email,
code: code
})
});
};
export default checkEmailVerificationCode;
@@ -1,50 +0,0 @@
/**
* This function is called in the end of the signup process.
* It sends all the necessary nformation to the server.
* @param {*} email
* @param {*} firstName
* @param {*} lastName
* @param {*} workspace
* @param {*} publicKey
* @param {*} ciphertext
* @param {*} iv
* @param {*} tag
* @param {*} salt
* @param {*} verifier
* @returns
*/
const completeAccountInformationSignup = ({
email,
firstName,
lastName,
organizationName,
publicKey,
ciphertext,
iv,
tag,
salt,
verifier,
token,
}) => {
return fetch("/api/v1/signup/complete-account/signup", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + token,
},
body: JSON.stringify({
email,
firstName,
lastName,
publicKey,
encryptedPrivateKey: ciphertext,
organizationName,
iv,
tag,
salt,
verifier,
}),
});
};
export default completeAccountInformationSignup;
@@ -0,0 +1,66 @@
interface Props {
email: string;
firstName: string;
lastName: string;
publicKey: string;
ciphertext: string;
organizationName: string;
iv: string;
tag: string;
salt: string;
verifier: string;
token: string;
}
/**
* This function is called in the end of the signup process.
* It sends all the necessary nformation to the server.
* @param {object} obj
* @param {string} obj.email - email of the user completing signup
* @param {string} obj.firstName - first name of the user completing signup
* @param {string} obj.lastName - last name of the user completing sign up
* @param {string} obj.organizationName - organization name for this user (usually, [FIRST_NAME]'s organization)
* @param {string} obj.publicKey - public key of the user completing signup
* @param {string} obj.ciphertext
* @param {string} obj.iv
* @param {string} obj.tag
* @param {string} obj.salt
* @param {string} obj.verifier
* @param {string} obj.token - token that confirms a user's identity
* @returns
*/
const completeAccountInformationSignup = ({
email,
firstName,
lastName,
organizationName,
publicKey,
ciphertext,
iv,
tag,
salt,
verifier,
token
}: Props) => {
return fetch('/api/v1/signup/complete-account/signup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token
},
body: JSON.stringify({
email,
firstName,
lastName,
publicKey,
encryptedPrivateKey: ciphertext,
organizationName,
iv,
tag,
salt,
verifier
})
});
};
export default completeAccountInformationSignup;
@@ -1,47 +0,0 @@
/**
* This function is called in the end of the signup process.
* It sends all the necessary nformation to the server.
* @param {*} email
* @param {*} firstName
* @param {*} lastName
* @param {*} publicKey
* @param {*} ciphertext
* @param {*} iv
* @param {*} tag
* @param {*} salt
* @param {*} verifier
* @returns
*/
const completeAccountInformationSignupInvite = ({
email,
firstName,
lastName,
publicKey,
ciphertext,
iv,
tag,
salt,
verifier,
token,
}) => {
return fetch("/api/v1/signup/complete-account/invite", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + token,
},
body: JSON.stringify({
email: email,
firstName: firstName,
lastName: lastName,
publicKey: publicKey,
encryptedPrivateKey: ciphertext,
iv: iv,
tag: tag,
salt: salt,
verifier: verifier,
}),
});
};
export default completeAccountInformationSignupInvite;
@@ -0,0 +1,62 @@
interface Props {
email: string;
firstName: string;
lastName: string;
publicKey: string;
ciphertext: string;
iv: string;
tag: string;
salt: string;
verifier: string;
token: string;
}
/**
* This function is called in the end of the signup process.
* It sends all the necessary nformation to the server.
* @param {object} obj
* @param {string} obj.email - email of the user completing signupinvite flow
* @param {string} obj.firstName - first name of the user completing signupinvite flow
* @param {string} obj.lastName - last name of the user completing signupinvite flow
* @param {string} obj.publicKey - public key of the user completing signupinvite flow
* @param {string} obj.ciphertext
* @param {string} obj.iv
* @param {string} obj.tag
* @param {string} obj.salt
* @param {string} obj.verifier
* @param {string} obj.token - token that confirms a user's identity
* @returns
*/
const completeAccountInformationSignupInvite = ({
email,
firstName,
lastName,
publicKey,
ciphertext,
iv,
tag,
salt,
verifier,
token
}: Props) => {
return fetch('/api/v1/signup/complete-account/invite', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token
},
body: JSON.stringify({
email: email,
firstName: firstName,
lastName: lastName,
publicKey: publicKey,
encryptedPrivateKey: ciphertext,
iv: iv,
tag: tag,
salt: salt,
verifier: verifier
})
});
};
export default completeAccountInformationSignupInvite;
@@ -0,0 +1,34 @@
interface Props {
email: string;
code: string;
}
/**
* This is the second part of the account recovery step (a user needs to verify their email).
* A user need to click on a button in a magic link page
* @param {object} obj
* @param {object} obj.email - email of a user that is trying to recover access to their account
* @param {object} obj.code - token that a use received via the magic link
* @returns
*/
const EmailVerifyOnPasswordReset = async ({ email, code }: Props) => {
const response = await fetch('/api/v1/password/email/password-reset-verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email,
code: code
})
});
if (response?.status === 200) {
return response;
}
throw new Error(
'Something went wrong during email verification on password reset.'
);
};
export default EmailVerifyOnPasswordReset;
@@ -1,40 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This is the route that issues a backup private key that will afterwards be added into a pdf
*/
const issueBackupPrivateKey = ({
encryptedPrivateKey,
iv,
tag,
salt,
verifier,
clientProof,
}) => {
return SecurityClient.fetchCall(
"/api/v1/password/backup-private-key",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
clientProof: clientProof,
encryptedPrivateKey: encryptedPrivateKey,
iv: iv,
tag: tag,
salt: salt,
verifier: verifier,
}),
}
).then((res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to issue the backup key");
return res;
}
});
};
export default issueBackupPrivateKey;
@@ -0,0 +1,52 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
encryptedPrivateKey: string;
iv: string;
tag: string;
salt: string;
verifier: string;
clientProof: string;
}
/**
* This is the route that issues a backup private key that will afterwards be added into a pdf
* @param {object} obj
* @param {string} obj.encryptedPrivateKey
* @param {string} obj.iv
* @param {string} obj.tag
* @param {string} obj.salt
* @param {string} obj.verifier
* @param {string} obj.clientProof
* @returns
*/
const issueBackupPrivateKey = ({
encryptedPrivateKey,
iv,
tag,
salt,
verifier,
clientProof
}: Props) => {
return SecurityClient.fetchCall('/api/v1/password/backup-private-key', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
clientProof: clientProof,
encryptedPrivateKey: encryptedPrivateKey,
iv: iv,
tag: tag,
salt: salt,
verifier: verifier
})
}).then((res) => {
if (res?.status !== 200) {
console.log('Failed to issue the backup key');
}
return res;
});
};
export default issueBackupPrivateKey;
+13 -13
View File
@@ -1,29 +1,29 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route logs the user out. Note: the user should authorized to do this.
* We first try to log out - if the authorization fails (response.status = 401), we refetch the new token, and then retry
*/
const logout = async () => {
return SecurityClient.fetchCall("/api/v1/auth/logout", {
method: "POST",
return SecurityClient.fetchCall('/api/v1/auth/logout', {
method: 'POST',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json'
},
credentials: "include",
credentials: 'include'
}).then((res) => {
if (res?.status == 200) {
SecurityClient.setToken("");
SecurityClient.setToken('');
// Delete the cookie by not setting a value; Alternatively clear the local storage
localStorage.setItem("publicKey", "");
localStorage.setItem("encryptedPrivateKey", "");
localStorage.setItem("iv", "");
localStorage.setItem("tag", "");
localStorage.setItem("PRIVATE_KEY", "");
console.log("User logged out", res);
localStorage.setItem('publicKey', '');
localStorage.setItem('encryptedPrivateKey', '');
localStorage.setItem('iv', '');
localStorage.setItem('tag', '');
localStorage.setItem('PRIVATE_KEY', '');
console.log('User logged out', res);
return res;
} else {
console.log("Failed to log out");
console.log('Failed to log out');
}
});
};
-26
View File
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This is the first step of the change password process (pake)
* @param {*} clientPublicKey
* @returns
*/
const SRP1 = ({ clientPublicKey }) => {
return SecurityClient.fetchCall("/api/v1/password/srp1", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
clientPublicKey,
}),
}).then(async (res) => {
if (res.status == 200) {
return await res.json();
} else {
console.log("Failed to do the first step of SRP");
}
});
};
export default SRP1;
+30
View File
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
clientPublicKey: string;
}
/**
* This is the first step of the change password process (pake)
* @param {string} clientPublicKey
* @returns
*/
const SRP1 = ({ clientPublicKey }: Props) => {
return SecurityClient.fetchCall('/api/v1/password/srp1', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
clientPublicKey
})
}).then(async (res) => {
if (res && res.status == 200) {
return await res.json();
} else {
console.log('Failed to do the first step of SRP');
}
});
};
export default SRP1;
@@ -0,0 +1,33 @@
interface Props {
email: string;
}
/**
* This is the first of the account recovery step (a user needs to verify their email).
* It will send an email containing a magic link to start the account recovery flow.
* @param {object} obj
* @param {object} obj.email - email of a user that is trying to recover access to their account
* @returns
*/
const SendEmailOnPasswordReset = async ({ email }: Props) => {
const response = await fetch('/api/v1/password/email/password-reset', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email
})
});
// need precise error handling about the status code
if (response?.status === 200) {
const data = await response.json();
return data;
}
throw new Error(
'Something went wrong while sending the email verification for password reset.'
);
};
export default SendEmailOnPasswordReset;
@@ -2,15 +2,15 @@
* This route send the verification email to the user's email (contains a 6-digit verification code)
* @param {*} email
*/
const sendVerificationEmail = (email) => {
fetch("/api/v1/signup/email/signup", {
method: "POST",
const sendVerificationEmail = (email: string) => {
fetch('/api/v1/signup/email/signup', {
method: 'POST',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email,
}),
email: email
})
});
};
-17
View File
@@ -1,17 +0,0 @@
const token = async (req, res) => {
return fetch("/api/v1/auth/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
}).then(async (res) => {
if (res.status == 200) {
return (await res.json()).token;
} else {
console.log("Getting a new token failed");
}
});
};
export default token;
+17
View File
@@ -0,0 +1,17 @@
const token = async () => {
return fetch('/api/v1/auth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include'
}).then(async (res) => {
if (res.status == 200) {
return (await res.json()).token;
} else {
console.log('Getting a new token failed');
}
});
};
export default token;
@@ -1,20 +0,0 @@
/**
* This route verifies the signup invite link
* @param {*} email
* @param {*} code
* @returns
*/
const verifySignupInvite = ({ email, code }) => {
return fetch("/api/v1/invite-org/verify", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
code,
}),
});
};
export default verifySignupInvite;
@@ -0,0 +1,26 @@
interface Props {
email: string;
code: string;
}
/**
* This route verifies the signup invite link
* @param {object} obj
* @param {string} obj.email - email that a user is trying to verify
* @param {string} obj.code - code that a user received to the abovementioned email
* @returns
*/
const verifySignupInvite = ({ email, code }: Props) => {
return fetch('/api/v1/invite-org/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email,
code
})
});
};
export default verifySignupInvite;
@@ -0,0 +1,26 @@
/**
* This is the route that get an encrypted private key (will be decrypted with a backup key)
* @param {object} obj
* @param {object} obj.verificationToken - this is the token that confirms that a user is the right one
* @returns
*/
const getBackupEncryptedPrivateKey = ({
verificationToken
}: {
verificationToken: string;
}) => {
return fetch('/api/v1/password/backup-private-key', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + verificationToken
}
}).then(async (res) => {
if (res?.status !== 200) {
console.log('Failed to get the backup key');
}
return (await res?.json())?.backupPrivateKey;
});
};
export default getBackupEncryptedPrivateKey;
@@ -1,16 +0,0 @@
/**
* This route lets us get the public key of infisical. Th euser doesn't have to be authenticated since this is just the public key.
* @param {*} req
* @param {*} res
* @returns
*/
const publicKeyInfisical = (req, res) => {
return fetch("/api/v1/key/publicKey/infisical", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
};
export default publicKeyInfisical;
@@ -0,0 +1,10 @@
const publicKeyInfisical = () => {
return fetch('/api/v1/key/publicKey/infisical', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
};
export default publicKeyInfisical;
@@ -0,0 +1,50 @@
interface Props {
verificationToken: string;
encryptedPrivateKey: string;
iv: string;
tag: string;
salt: string;
verifier: string;
}
/**
* This is the route that resets the account password if all the previus steps were passed
* @param {object} obj
* @param {object} obj.verificationToken - this is the token that confirms that a user is the right one
* @param {object} obj.encryptedPrivateKey - the new encrypted private key (encrypted using the new password)
* @param {object} obj.iv
* @param {object} obj.tag
* @param {object} obj.salt
* @param {object} obj.verifier
* @returns
*/
const resetPasswordOnAccountRecovery = ({
verificationToken,
encryptedPrivateKey,
iv,
tag,
salt,
verifier
}: Props) => {
return fetch('/api/v1/password/password-reset', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + verificationToken
},
body: JSON.stringify({
encryptedPrivateKey: encryptedPrivateKey,
iv: iv,
tag: tag,
salt: salt,
verifier: verifier
})
}).then(async (res) => {
if (res?.status !== 200) {
console.log('Failed to get the backup key');
}
return res;
});
};
export default resetPasswordOnAccountRecovery;
+31
View File
@@ -0,0 +1,31 @@
import SecurityClient from "~/utilities/SecurityClient";
interface Props {
workspaceId: string;
}
/**
* This function fetches the bot for a project
* @param {Object} obj
* @param {String} obj.workspaceId
* @returns
*/
const getBot = async ({ workspaceId }: Props) => {
return SecurityClient.fetchCall(
"/api/v1/bot/" + workspaceId,
{
method: "GET",
headers: {
"Content-Type": "application/json",
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).bot;
} else {
console.log("Failed to get bot for project");
}
});
};
export default getBot;
@@ -0,0 +1,46 @@
import SecurityClient from "~/utilities/SecurityClient";
interface BotKey {
encryptedKey: string;
nonce: string;
}
interface Props {
botId: string;
isActive: boolean;
botKey: BotKey;
}
/**
* This function sets the active status of a bot and shares a copy of
* the project key (encrypted under the bot's public key) with the
* project's bot
* @param {Object} obj
* @param {String} obj.botId
* @param {String} obj.isActive
* @param {Object} obj.botKey
* @returns
*/
const setBotActiveStatus = async ({ botId, isActive, botKey }: Props) => {
return SecurityClient.fetchCall(
"/api/v1/bot/" + botId + "/active",
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
isActive,
botKey
})
}
).then(async (res) => {
if (res && res.status == 200) {
return await res.json();
} else {
console.log("Failed to get bot for project");
}
});
};
export default setBotActiveStatus;
-33
View File
@@ -1,33 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient.js";
/**
* This function fetches the encrypted secrets from the .env file
* @param {*} workspaceId
* @param {*} env
* @returns
*/
const getSecrets = async (workspaceId, env) => {
return SecurityClient.fetchCall(
"/api/v1/secret/" +
workspaceId +
"?" +
new URLSearchParams({
environment: env,
channel: "web",
}),
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return await res.json();
} else {
console.log("Failed to get project secrets");
}
});
};
export default getSecrets;
+33
View File
@@ -0,0 +1,33 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This function fetches the encrypted secrets from the .env file
* @param {string} workspaceId - project is for which a user is trying to get secrets
* @param {string} env - environment of a project for which a user is trying ot get secrets
* @returns
*/
const getSecrets = async (workspaceId: string, env: string) => {
return SecurityClient.fetchCall(
'/api/v1/secret/' +
workspaceId +
'?' +
new URLSearchParams({
environment: env,
channel: 'web'
}),
{
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 getSecrets;
-30
View File
@@ -1,30 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This function uploads the encrypted .env file
* @param {*} req
* @param {*} res
* @returns
*/
const uploadSecrets = async ({ workspaceId, secrets, keys, environment }) => {
return SecurityClient.fetchCall("/api/v1/secret/" + workspaceId, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
secrets,
keys,
environment,
channel: "web",
}),
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to push secrets");
}
});
};
export default uploadSecrets;
+45
View File
@@ -0,0 +1,45 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
workspaceId: string;
secrets: any;
keys: string;
environment: string;
}
/**
* This function uploads the encrypted .env file
* @param {object} obj
* @param {string} obj.workspaceId
* @param {} obj.secrets
* @param {} obj.keys
* @param {string} obj.environment
* @returns
*/
const uploadSecrets = async ({
workspaceId,
secrets,
keys,
environment
}: Props) => {
return SecurityClient.fetchCall('/api/v1/secret/' + workspaceId, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
secrets,
keys,
environment,
channel: 'web'
})
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to push secrets');
}
});
};
export default uploadSecrets;
@@ -1,25 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
const changeHerokuConfigVars = ({ integrationId, key, secrets }) => {
return SecurityClient.fetchCall(
"/api/v1/integration/" + integrationId + "/sync",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
key,
secrets,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to sync secrets to Heroku");
}
});
};
export default changeHerokuConfigVars;
@@ -0,0 +1,41 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
integrationId: string;
key: { encryptedKey: any; nonce: any };
secrets: {
ciphertextKey: any;
ivKey: any;
tagKey: any;
hashKey: any;
ciphertextValue: any;
ivValue: any;
tagValue: any;
hashValue: any;
type: string;
}[];
}
const changeHerokuConfigVars = ({ integrationId, key, secrets }: Props) => {
return SecurityClient.fetchCall(
'/api/v1/integration/' + integrationId + '/sync',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
key,
secrets
})
}
).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to sync secrets to Heroku');
}
});
};
export default changeHerokuConfigVars;
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route deletes an integration from a certain project
* @param {*} integrationId
* @returns
*/
const deleteIntegration = ({ integrationId }) => {
return SecurityClient.fetchCall(
"/api/v1/integration/" + integrationId,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).workspace;
} else {
console.log("Failed to delete an integration");
}
});
};
export default deleteIntegration;
@@ -0,0 +1,27 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
integrationId: string;
}
/**
* This route deletes an integration from a certain project
* @param {*} integrationId
* @returns
*/
const deleteIntegration = ({ integrationId }: Props) => {
return SecurityClient.fetchCall('/api/v1/integration/' + integrationId, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).workspace;
} else {
console.log('Failed to delete an integration');
}
});
};
export default deleteIntegration;
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route deletes an integration authorization from a certain project
* @param {*} integrationAuthId
* @returns
*/
const deleteIntegrationAuth = ({ integrationAuthId }) => {
return SecurityClient.fetchCall(
"/api/v1/integration-auth/" + integrationAuthId,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to delete an integration authorization");
}
});
};
export default deleteIntegrationAuth;
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
integrationAuthId: string;
}
/**
* This route deletes an integration authorization from a certain project
* @param {*} integrationAuthId
* @returns
*/
const deleteIntegrationAuth = ({ integrationAuthId }: Props) => {
return SecurityClient.fetchCall(
'/api/v1/integration-auth/' + integrationAuthId,
{
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to delete an integration authorization');
}
});
};
export default deleteIntegrationAuth;
@@ -1,21 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
const getIntegrationApps = ({ integrationAuthId }) => {
return SecurityClient.fetchCall(
"/api/v1/integration-auth/" + integrationAuthId + "/apps",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).apps;
} else {
console.log("Failed to get available apps for an integration");
}
});
};
export default getIntegrationApps;
@@ -0,0 +1,25 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
integrationAuthId: string;
}
const getIntegrationApps = ({ integrationAuthId }: Props) => {
return SecurityClient.fetchCall(
'/api/v1/integration-auth/' + integrationAuthId + '/apps',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).apps;
} else {
console.log('Failed to get available apps for an integration');
}
});
};
export default getIntegrationApps;
@@ -0,0 +1,21 @@
import SecurityClient from '~/utilities/SecurityClient';
const getIntegrationOptions = () => {
return SecurityClient.fetchCall(
'/api/v1/integration-auth/integration-options',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).integrationOptions;
} else {
console.log('Failed to get (cloud) integration options');
}
});
};
export default getIntegrationOptions;
@@ -1,18 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
const getIntegrations = () => {
return SecurityClient.fetchCall("/api/v1/integration/integrations", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
}).then(async (res) => {
if (res.status == 200) {
return (await res.json()).integrations;
} else {
console.log("Failed to get project integrations");
}
});
};
export default getIntegrations;
@@ -1,33 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route starts the integration after teh default one if gonna set up.
* @param {*} integrationId
* @returns
*/
const startIntegration = ({ integrationId, appName, environment }) => {
return SecurityClient.fetchCall(
"/api/v1/integration/" + integrationId,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
update: {
app: appName,
environment,
isActive: true,
},
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to start an integration");
}
});
};
export default startIntegration;
@@ -0,0 +1,36 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
integrationId: string;
appName: string;
environment: string;
}
/**
* This route starts the integration after teh default one if gonna set up.
* @param {*} integrationId
* @returns
*/
const startIntegration = ({ integrationId, appName, environment }: Props) => {
return SecurityClient.fetchCall('/api/v1/integration/' + integrationId, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
update: {
app: appName,
environment,
isActive: true
}
})
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to start an integration');
}
});
};
export default startIntegration;
@@ -1,31 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This is the first step of the change password process (pake)
* @param {*} clientPublicKey
* @returns
*/
const AuthorizeIntegration = ({ workspaceId, code, integration }) => {
return SecurityClient.fetchCall(
"/api/v1/integration-auth/oauth-token",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
workspaceId,
code,
integration,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to authorize the integration");
}
});
};
export default AuthorizeIntegration;
@@ -0,0 +1,36 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
workspaceId: string;
code: string;
integration: string;
}
/**
* This is the first step of the change password process (pake)
* @param {object} obj
* @param {object} obj.workspaceId - project id for which we want to authorize the integration
* @param {object} obj.code
* @param {object} obj.integration - integration which a user is trying to turn on
* @returns
*/
const AuthorizeIntegration = ({ workspaceId, code, integration }: Props) => {
return SecurityClient.fetchCall('/api/v1/integration-auth/oauth-token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
workspaceId,
code,
integration
})
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to authorize the integration');
}
});
};
export default AuthorizeIntegration;
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route gets authorizations of a certain project (Heroku, etc.)
* @param {*} workspaceId
* @returns
*/
const getWorkspaceAuthorizations = ({ workspaceId }) => {
return SecurityClient.fetchCall(
"/api/v1/workspace/" + workspaceId + "/authorizations",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).authorizations;
} else {
console.log("Failed to get project authorizations");
}
});
};
export default getWorkspaceAuthorizations;
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
workspaceId: string;
}
/**
* This route gets authorizations of a certain project (Heroku, etc.)
* @param {*} workspaceId
* @returns
*/
const getWorkspaceAuthorizations = ({ workspaceId }: Props) => {
return SecurityClient.fetchCall(
'/api/v1/workspace/' + workspaceId + '/authorizations',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).authorizations;
} else {
console.log('Failed to get project authorizations');
}
});
};
export default getWorkspaceAuthorizations;
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route gets integrations of a certain project (Heroku, etc.)
* @param {*} workspaceId
* @returns
*/
const getWorkspaceIntegrations = ({ workspaceId }) => {
return SecurityClient.fetchCall(
"/api/v1/workspace/" + workspaceId + "/integrations",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).integrations;
} else {
console.log("Failed to get the project integrations");
}
});
};
export default getWorkspaceIntegrations;
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
workspaceId: string;
}
/**
* This route gets integrations of a certain project (Heroku, etc.)
* @param {*} workspaceId
* @returns
*/
const getWorkspaceIntegrations = ({ workspaceId }: Props) => {
return SecurityClient.fetchCall(
'/api/v1/workspace/' + workspaceId + '/integrations',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).integrations;
} else {
console.log('Failed to get the project integrations');
}
});
};
export default getWorkspaceIntegrations;
@@ -0,0 +1,60 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route starts the integration after teh default one if gonna set up.
* Update integration with id [integrationId] to sync envars from the project's
* [environment] to the integration [app] with active state [isActive]
* @param {Object} obj
* @param {String} obj.integrationId - id of integration
* @param {String} obj.app - name of app
* @param {String} obj.environment - project environment to push secrets from
* @param {Boolean} obj.isActive - active state
* @param {String} obj.target - (optional) target (environment) for Vercel integration
* @param {String} obj.context - (optional) context (environment) for Netlify integration
* @param {String} obj.siteId - (optional) app (site_id) for Netlify integration
* @returns
*/
const updateIntegration = ({
integrationId,
app,
environment,
isActive,
target,
context,
siteId
}: {
integrationId: string,
app: string,
environment: string,
isActive: boolean,
target: string | null,
context: string | null,
siteId: string | null
}) => {
return SecurityClient.fetchCall(
"/api/v1/integration/" + integrationId,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
app,
environment,
isActive,
target,
context,
siteId
}),
}
).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log("Failed to start an integration");
}
});
};
export default updateIntegration;
+7 -7
View File
@@ -1,21 +1,21 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us get info about a certain org
* @param {string} orgId - the organization ID
* @returns
*/
const getOrganization = ({ orgId }: { orgId: string; }) => {
return SecurityClient.fetchCall("/api/v1/organization/" + orgId, {
method: "GET",
const getOrganization = ({ orgId }: { orgId: string }) => {
return SecurityClient.fetchCall('/api/v1/organization/' + orgId, {
method: 'GET',
headers: {
"Content-Type": "application/json",
},
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res?.status == 200) {
return (await res.json()).organization;
} else {
console.log("Failed to get org info");
console.log('Failed to get org info');
}
});
};
@@ -1,27 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route lets us get all the users in an org.
* @param {*} req
* @param {*} res
* @returns
*/
const getOrganizationProjects = (req, res) => {
return SecurityClient.fetchCall(
"/api/organization/" + req.orgId + "/workspaces",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).workspaces;
} else {
console.log("Failed to get projects for an org");
}
});
};
export default getOrganizationProjects;
@@ -0,0 +1,29 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us get all the users in an org.
* @param {*} req
* @param {*} res
* @returns
*/
// TODO: this file is not used anywhere
const getOrganizationProjects = (req: { orgId: string }) => {
return SecurityClient.fetchCall(
'/api/organization/' + req.orgId + '/workspaces',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).workspaces;
} else {
console.log('Failed to get projects for an org');
}
});
};
export default getOrganizationProjects;
@@ -1,27 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route lets us get the current subscription of an org.
* @param {*} req
* @param {*} res
* @returns
*/
const getOrganizationSubscriptions = (req, res) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + req.orgId + "/subscriptions",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).subscriptions;
} else {
console.log("Failed to get org subscriptions");
}
});
};
export default getOrganizationSubscriptions;
@@ -0,0 +1,27 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us get the current subscription of an org.
* @param {*} req
* @param {*} res
* @returns
*/
const getOrganizationSubscriptions = (req: { orgId: string }) => {
return SecurityClient.fetchCall(
'/api/v1/organization/' + req.orgId + '/subscriptions',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).subscriptions;
} else {
console.log('Failed to get org subscriptions');
}
});
};
export default getOrganizationSubscriptions;
@@ -1,27 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route lets us get all the projects of a certain user in an org.
* @param {*} req
* @param {*} res
* @returns
*/
const getOrganizationUserProjects = (req) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + req.orgId + "/my-workspaces",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).workspaces;
} else {
console.log("Failed to get projects of a user in an org");
}
});
};
export default getOrganizationUserProjects;
@@ -0,0 +1,27 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us get all the projects of a certain user in an org.
* @param {*} req
* @param {*} res
* @returns
*/
const getOrganizationUserProjects = (req: { orgId: string }) => {
return SecurityClient.fetchCall(
'/api/v1/organization/' + req.orgId + '/my-workspaces',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).workspaces;
} else {
console.log('Failed to get projects of a user in an org');
}
});
};
export default getOrganizationUserProjects;
+8 -11
View File
@@ -1,4 +1,4 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us get all the users in an org.
@@ -6,20 +6,17 @@ import SecurityClient from "~/utilities/SecurityClient";
* @param {string} obj.orgId - organization Id
* @returns
*/
const getOrganizationUsers = ({ orgId }: { orgId: string; }) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + orgId + "/users",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
const getOrganizationUsers = ({ orgId }: { orgId: string }) => {
return SecurityClient.fetchCall('/api/v1/organization/' + orgId + '/users', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
).then(async (res) => {
}).then(async (res) => {
if (res?.status == 200) {
return (await res.json()).users;
} else {
console.log("Failed to get org users");
console.log('Failed to get org users');
}
});
};
@@ -1,27 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route redirects the user to the right stripe billing page.
* @param {*} req
* @param {*} res
* @returns
*/
const StripeRedirect = ({ orgId }) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + orgId + "/customer-portal-session",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (window.location.href = (await res.json()).url);
} else {
console.log("Failed to redirect to Stripe");
}
});
};
export default StripeRedirect;
@@ -0,0 +1,27 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route redirects the user to the right stripe billing page.
* @param {*} req
* @param {*} res
* @returns
*/
const StripeRedirect = ({ orgId }: { orgId: string }) => {
return SecurityClient.fetchCall(
'/api/v1/organization/' + orgId + '/customer-portal-session',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (window.location.href = (await res.json()).url);
} else {
console.log('Failed to redirect to Stripe');
}
});
};
export default StripeRedirect;
@@ -1,29 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route add an incident contact email to a certain organization
* @param {*} param0
* @returns
*/
const addIncidentContact = (organizationId, email) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + organizationId + "/incidentContactOrg",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to add an incident contact");
}
});
};
export default addIncidentContact;
@@ -0,0 +1,29 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route add an incident contact email to a certain organization
* @param {*} param0
* @returns
*/
const addIncidentContact = (organizationId: string, email: string) => {
return SecurityClient.fetchCall(
'/api/v1/organization/' + organizationId + '/incidentContactOrg',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email
})
}
).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to add an incident contact');
}
});
};
export default addIncidentContact;
@@ -1,28 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This function sends an email invite to a user to join an org
* @param {*} email
* @param {*} orgId
* @returns
*/
const addUserToOrg = (email, orgId) => {
return SecurityClient.fetchCall("/api/v1/invite-org/signup", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
inviteeEmail: email,
organizationId: orgId,
}),
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to add a user to an org");
}
});
};
export default addUserToOrg;
@@ -0,0 +1,28 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This function sends an email invite to a user to join an org
* @param {*} email
* @param {*} orgId
* @returns
*/
const addUserToOrg = (email: string, orgId: string) => {
return SecurityClient.fetchCall('/api/v1/invite-org/signup', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
inviteeEmail: email,
organizationId: orgId
})
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to add a user to an org');
}
});
};
export default addUserToOrg;
@@ -1,29 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route deletes an incident Contact from a certain organization
* @param {*} param0
* @returns
*/
const deleteIncidentContact = (organizaionId, email) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + organizaionId + "/incidentContactOrg",
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to delete an incident contact");
}
});
};
export default deleteIncidentContact;
@@ -0,0 +1,29 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route deletes an incident Contact from a certain organization
* @param {*} param0
* @returns
*/
const deleteIncidentContact = (organizationId: string, email: string) => {
return SecurityClient.fetchCall(
'/api/v1/organization/' + organizationId + '/incidentContactOrg',
{
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email
})
}
).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to delete an incident contact');
}
});
};
export default deleteIncidentContact;
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This function removes a certain member from a certain organization
* @param {*} membershipId
* @returns
*/
const deleteUserFromOrganization = (membershipId) => {
return SecurityClient.fetchCall(
"/api/v1/membership-org/" + membershipId,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to delete a user from an org");
}
});
};
export default deleteUserFromOrganization;
@@ -0,0 +1,23 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This function removes a certain member from a certain organization
* @param {*} membershipId
* @returns
*/
const deleteUserFromOrganization = (membershipId: string) => {
return SecurityClient.fetchCall('/api/v1/membership-org/' + membershipId, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to delete a user from an org');
}
});
};
export default deleteUserFromOrganization;
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This routes gets all the incident contacts of a certain organization
* @param {*} workspaceId
* @returns
*/
const getIncidentContacts = (organizationId) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + organizationId + "/incidentContactOrg",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).incidentContactsOrg;
} else {
console.log("Failed to get incident contacts");
}
});
};
export default getIncidentContacts;
@@ -0,0 +1,26 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This routes gets all the incident contacts of a certain organization
* @param {*} workspaceId
* @returns
*/
const getIncidentContacts = (organizationId: string) => {
return SecurityClient.fetchCall(
'/api/v1/organization/' + organizationId + '/incidentContactOrg',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).incidentContactsOrg;
} else {
console.log('Failed to get incident contacts');
}
});
};
export default getIncidentContacts;
+6 -6
View File
@@ -1,20 +1,20 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us get the all the orgs of a certain user.
* @returns
*/
const getOrganizations = () => {
return SecurityClient.fetchCall("/api/v1/organization", {
method: "GET",
return SecurityClient.fetchCall('/api/v1/organization', {
method: 'GET',
headers: {
"Content-Type": "application/json",
},
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res?.status == 200) {
return (await res.json()).organizations;
} else {
console.log("Failed to get orgs of a user");
console.log('Failed to get orgs of a user');
}
});
};
@@ -1,30 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route lets us rename a certain org.
* @param {*} req
* @param {*} res
* @returns
*/
const renameOrg = (orgId, newOrgName) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + orgId + "/name",
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: newOrgName,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to rename an organization");
}
});
};
export default renameOrg;
@@ -0,0 +1,27 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us rename a certain org.
* @param {*} req
* @param {*} res
* @returns
*/
const renameOrg = (orgId: string, newOrgName: string) => {
return SecurityClient.fetchCall('/api/v1/organization/' + orgId + '/name', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: newOrgName
})
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to rename an organization');
}
});
};
export default renameOrg;
@@ -1,4 +1,14 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
name: string;
workspaceId: string;
environment: string;
expiresIn: number;
publicKey: string;
encryptedKey: string;
nonce: string;
}
/**
* This route gets service tokens for a specific user in a project
@@ -12,12 +22,12 @@ const addServiceToken = ({
expiresIn,
publicKey,
encryptedKey,
nonce,
}) => {
return SecurityClient.fetchCall("/api/v1/service-token/", {
method: "POST",
nonce
}: Props) => {
return SecurityClient.fetchCall('/api/v1/service-token/', {
method: 'POST',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json'
},
body: JSON.stringify({
name,
@@ -26,13 +36,13 @@ const addServiceToken = ({
expiresIn,
publicKey,
encryptedKey,
nonce,
}),
nonce
})
}).then(async (res) => {
if (res.status == 200) {
if (res && res.status == 200) {
return (await res.json()).token;
} else {
console.log("Failed to add service tokens");
console.log('Failed to add service tokens');
}
});
};
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route gets service tokens for a specific user in a project
* @param {*} param0
* @returns
*/
const getServiceTokens = ({ workspaceId }) => {
return SecurityClient.fetchCall(
"/api/v1/workspace/" + workspaceId + "/service-tokens",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).serviceTokens;
} else {
console.log("Failed to get service tokens");
}
});
};
export default getServiceTokens;
@@ -0,0 +1,26 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route gets service tokens for a specific user in a project
* @param {*} param0
* @returns
*/
const getServiceTokens = ({ workspaceId }: { workspaceId: string }) => {
return SecurityClient.fetchCall(
'/api/v1/workspace/' + workspaceId + '/service-tokens',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).serviceTokens;
} else {
console.log('Failed to get service tokens');
}
});
};
export default getServiceTokens;
+6 -6
View File
@@ -1,19 +1,19 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route gets the information about a specific user.
*/
const getUser = () => {
return SecurityClient.fetchCall("/api/v1/user", {
method: "GET",
return SecurityClient.fetchCall('/api/v1/user', {
method: 'GET',
headers: {
"Content-Type": "application/json",
},
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res?.status == 200) {
return (await res.json()).user;
} else {
console.log("Failed to get user info");
console.log('Failed to get user info');
}
});
};
@@ -1,4 +1,4 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route registers a certain action for a user
@@ -6,24 +6,24 @@ import SecurityClient from "~/utilities/SecurityClient";
* @param {*} workspaceId
* @returns
*/
const checkUserAction = ({ action }) => {
const checkUserAction = ({ action }: { action: string }) => {
return SecurityClient.fetchCall(
"/api/v1/user-action" +
"?" +
'/api/v1/user-action' +
'?' +
new URLSearchParams({
action,
action
}),
{
method: "GET",
method: 'GET',
headers: {
"Content-Type": "application/json",
},
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res.status == 200) {
if (res && res.status == 200) {
return (await res.json()).userAction;
} else {
console.log("Failed to check a user action");
console.log('Failed to check a user action');
}
});
};
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route registers a certain action for a user
* @param {*} action
* @returns
*/
const registerUserAction = ({ action }) => {
return SecurityClient.fetchCall("/api/v1/user-action", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
action,
}),
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to register a user action");
}
});
};
export default registerUserAction;
@@ -0,0 +1,26 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route registers a certain action for a user
* @param {*} action
* @returns
*/
const registerUserAction = ({ action }: { action: string }) => {
return SecurityClient.fetchCall('/api/v1/user-action', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
action
})
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to register a user action');
}
});
};
export default registerUserAction;
@@ -1,30 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This function adds a user to a project
* @param {*} email
* @param {*} workspaceId
* @returns
*/
const addUserToWorkspace = (email, workspaceId) => {
return SecurityClient.fetchCall(
"/api/v1/workspace/" + workspaceId + "/invite-signup",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
}),
}
).then(async (res) => {
if (res.status == 200) {
return await res.json();
} else {
console.log("Failed to add a user to project");
}
});
};
export default addUserToWorkspace;
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This function adds a user to a project
* @param {*} email
* @param {*} workspaceId
* @returns
*/
const addUserToWorkspace = (email: string, workspaceId: string) => {
return SecurityClient.fetchCall(
'/api/v1/workspace/' + workspaceId + '/invite-signup',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email
})
}
).then(async (res) => {
if (res && res.status == 200) {
return await res.json();
} else {
console.log('Failed to add a user to project');
}
});
};
export default addUserToWorkspace;
@@ -1,30 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This function change the access of a user in a certain workspace
* @param {*} membershipId
* @param {*} role
* @returns
*/
const changeUserRoleInWorkspace = (membershipId, role) => {
return SecurityClient.fetchCall(
"/api/v1/membership/" + membershipId + "/change-role",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
role: role,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to change the user role in a project");
}
});
};
export default changeUserRoleInWorkspace;
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This function change the access of a user in a certain workspace
* @param {*} membershipId
* @param {*} role
* @returns
*/
const changeUserRoleInWorkspace = (membershipId: string, role: string) => {
return SecurityClient.fetchCall(
'/api/v1/membership/' + membershipId + '/change-role',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
role: role
})
}
).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to change the user role in a project');
}
});
};
export default changeUserRoleInWorkspace;
@@ -1,4 +1,4 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route creates a new workspace for a user within a certain organization.
@@ -6,21 +6,27 @@ import SecurityClient from "~/utilities/SecurityClient";
* @param {string} organizationId - org ID
* @returns
*/
const createWorkspace = ( { workspaceName, organizationId }: { workspaceName: string; organizationId: string; }) => {
return SecurityClient.fetchCall("/api/v1/workspace", {
method: "POST",
const createWorkspace = ({
workspaceName,
organizationId
}: {
workspaceName: string;
organizationId: string;
}) => {
return SecurityClient.fetchCall('/api/v1/workspace', {
method: 'POST',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json'
},
body: JSON.stringify({
workspaceName: workspaceName,
organizationId: organizationId,
}),
organizationId: organizationId
})
}).then(async (res) => {
if (res?.status == 200) {
return (await res.json()).workspace;
} else {
console.log("Failed to create a project");
console.log('Failed to create a project');
}
});
};
@@ -1,23 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This function removes a certain member from a certain workspace
* @param {*} membershipId
* @returns
*/
const deleteUserFromWorkspace = (membershipId) => {
return SecurityClient.fetchCall("/api/v1/membership/" + membershipId, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to delete a user from a project");
}
});
};
export default deleteUserFromWorkspace;
@@ -0,0 +1,23 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This function removes a certain member from a certain workspace
* @param {*} membershipId
* @returns
*/
const deleteUserFromWorkspace = (membershipId: string) => {
return SecurityClient.fetchCall('/api/v1/membership/' + membershipId, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to delete a user from a project');
}
});
};
export default deleteUserFromWorkspace;
@@ -1,23 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route deletes a specified workspace.
* @param {*} workspaceId
* @returns
*/
const deleteWorkspace = (workspaceId) => {
return SecurityClient.fetchCall("/api/v1/workspace/" + workspaceId, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to delete a project");
}
});
};
export default deleteWorkspace;
@@ -0,0 +1,23 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route deletes a specified workspace.
* @param {*} workspaceId
* @returns
*/
const deleteWorkspace = (workspaceId: string) => {
return SecurityClient.fetchCall('/api/v1/workspace/' + workspaceId, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to delete a project');
}
});
};
export default deleteWorkspace;
@@ -1,24 +1,21 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
/**
* Get the latest key pairs from a certain workspace
* @param {string} workspaceId
* @returns
*/
const getLatestFileKey = ({ workspaceId } : { workspaceId: string; }) => {
return SecurityClient.fetchCall(
"/api/v1/key/" + workspaceId + "/latest",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
const getLatestFileKey = ({ workspaceId }: { workspaceId: string }) => {
return SecurityClient.fetchCall('/api/v1/key/' + workspaceId + '/latest', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
).then(async (res) => {
}).then(async (res) => {
if (res?.status == 200) {
return await res.json();
} else {
console.log("Failed to get the latest key pairs for a certain project");
console.log('Failed to get the latest key pairs for a certain project');
}
});
};
+8 -11
View File
@@ -1,24 +1,21 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us get the information of a certain project.
* @param {*} projectId - project ID (we renamed workspaces to projects in the app)
* @returns
*/
const getProjectInfo = ({ projectId }: { projectId: string; }) => {
return SecurityClient.fetchCall(
"/api/v1/workspace/" + projectId,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
const getProjectInfo = ({ projectId }: { projectId: string }) => {
return SecurityClient.fetchCall('/api/v1/workspace/' + projectId, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
).then(async (res) => {
}).then(async (res) => {
if (res?.status == 200) {
return (await res.json()).workspace;
} else {
console.log("Failed to get project info");
console.log('Failed to get project info');
}
});
};
@@ -1,24 +1,24 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us get all the users in the workspace.
* @param {string} workspaceId - workspace ID
* @returns
*/
const getWorkspaceUsers = ({ workspaceId }: { workspaceId: string; }) => {
const getWorkspaceUsers = ({ workspaceId }: { workspaceId: string }) => {
return SecurityClient.fetchCall(
"/api/v1/workspace/" + workspaceId + "/users",
'/api/v1/workspace/' + workspaceId + '/users',
{
method: "GET",
method: 'GET',
headers: {
"Content-Type": "application/json",
},
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res?.status == 200) {
return (await res.json()).users;
} else {
console.log("Failed to get Project Users");
console.log('Failed to get Project Users');
}
});
};
@@ -1,30 +1,29 @@
import SecurityClient from "~/utilities/SecurityClient";
import SecurityClient from '~/utilities/SecurityClient';
interface Workspaces {
interface Workspace {
__v: number;
_id: string;
name: string;
organization: string;
}
[];
/**
* This route lets us get the workspaces of a certain user
* @returns
*/
const getWorkspaces = () => {
return SecurityClient.fetchCall("/api/v1/workspace", {
method: "GET",
return SecurityClient.fetchCall('/api/v1/workspace', {
method: 'GET',
headers: {
"Content-Type": "application/json",
},
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res?.status == 200) {
const data = (await res.json()) as unknown as { workspaces: Workspaces };
const data = (await res.json()) as unknown as { workspaces: Workspace[] };
return data.workspaces;
}
throw new Error("Failed to get projects");
throw new Error('Failed to get projects');
});
};
@@ -1,30 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route lets us rename a certain workspace.
* @param {*} req
* @param {*} res
* @returns
*/
const renameWorkspace = (workspaceId, newWorkspaceName) => {
return SecurityClient.fetchCall(
"/api/v1/workspace/" + workspaceId + "/name",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: newWorkspaceName,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to rename a project");
}
});
};
export default renameWorkspace;
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us rename a certain workspace.
* @param {*} req
* @param {*} res
* @returns
*/
const renameWorkspace = (workspaceId: string, newWorkspaceName: string) => {
return SecurityClient.fetchCall(
'/api/v1/workspace/' + workspaceId + '/name',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: newWorkspaceName
})
}
).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to rename a project');
}
});
};
export default renameWorkspace;
@@ -1,33 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route uplods the keys in an encrypted format.
* @param {*} workspaceId
* @param {*} userId
* @param {*} encryptedKey
* @param {*} nonce
* @returns
*/
const uploadKeys = (workspaceId, userId, encryptedKey, nonce) => {
return SecurityClient.fetchCall("/api/v1/key/" + workspaceId, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
key: {
userId: userId,
encryptedKey: encryptedKey,
nonce: nonce,
},
}),
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to upload keys for a new user");
}
});
};
export default uploadKeys;
@@ -0,0 +1,38 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route uplods the keys in an encrypted format.
* @param {*} workspaceId
* @param {*} userId
* @param {*} encryptedKey
* @param {*} nonce
* @returns
*/
const uploadKeys = (
workspaceId: string,
userId: string,
encryptedKey: string,
nonce: string
) => {
return SecurityClient.fetchCall('/api/v1/key/' + workspaceId, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
key: {
userId: userId,
encryptedKey: encryptedKey,
nonce: nonce
}
})
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to upload keys for a new user');
}
});
};
export default uploadKeys;
+132 -134
View File
@@ -19,35 +19,35 @@ import {
faPerson,
faPlus,
faShuffle,
faX,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Menu, Transition } from "@headlessui/react";
faX
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Menu, Transition } from '@headlessui/react';
import Button from "~/components/basic/buttons/Button";
import ListBox from "~/components/basic/Listbox";
import BottonRightPopup from "~/components/basic/popups/BottomRightPopup";
import { useNotificationContext } from "~/components/context/Notifications/NotificationProvider";
import DashboardInputField from "~/components/dashboard/DashboardInputField";
import DropZone from "~/components/dashboard/DropZone";
import NavHeader from "~/components/navigation/NavHeader";
import getSecretsForProject from "~/components/utilities/secrets/getSecretsForProject";
import pushKeys from "~/components/utilities/secrets/pushKeys";
import pushKeysIntegration from "~/components/utilities/secrets/pushKeysIntegration";
import guidGenerator from "~/utilities/randomId";
import Button from '~/components/basic/buttons/Button';
import ListBox from '~/components/basic/Listbox';
import BottonRightPopup from '~/components/basic/popups/BottomRightPopup';
import { useNotificationContext } from '~/components/context/Notifications/NotificationProvider';
import DashboardInputField from '~/components/dashboard/DashboardInputField';
import DropZone from '~/components/dashboard/DropZone';
import NavHeader from '~/components/navigation/NavHeader';
import getSecretsForProject from '~/components/utilities/secrets/getSecretsForProject';
import pushKeys from '~/components/utilities/secrets/pushKeys';
import pushKeysIntegration from '~/components/utilities/secrets/pushKeysIntegration';
import guidGenerator from '~/utilities/randomId';
import { getTranslatedServerSideProps } from "~/utilities/withTranslateProps";
import { envMapping } from "../../public/data/frequentConstants";
import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations";
import getUser from "../api/user/getUser";
import checkUserAction from "../api/userActions/checkUserAction";
import registerUserAction from "../api/userActions/registerUserAction";
import getWorkspaces from "../api/workspace/getWorkspaces";
import { envMapping } from '../../public/data/frequentConstants';
import getUser from '../api/user/getUser';
import checkUserAction from '../api/userActions/checkUserAction';
import registerUserAction from '../api/userActions/registerUserAction';
import getWorkspaces from '../api/workspace/getWorkspaces';
/**
* 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 (index, key, value, public/private)
* @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
@@ -63,7 +63,7 @@ const KeyPair = ({
modifyValue,
modifyVisibility,
isBlurred,
duplicates,
duplicates
}) => {
const [randomStringLength, setRandomStringLength] = useState(32);
const { t } = useTranslation();
@@ -76,8 +76,8 @@ const KeyPair = ({
<DashboardInputField
onChangeHandler={modifyKey}
type="varName"
index={keyPair[1]}
value={keyPair[2]}
position={keyPair.pos}
value={keyPair.key}
duplicates={duplicates}
/>
</div>
@@ -87,8 +87,8 @@ const KeyPair = ({
<DashboardInputField
onChangeHandler={modifyValue}
type="value"
index={keyPair[1]}
value={keyPair[3]}
position={keyPair.pos}
value={keyPair.value}
blurred={isBlurred}
/>
</div>
@@ -117,15 +117,15 @@ const KeyPair = ({
<div
onClick={() =>
modifyVisibility(
keyPair[4] == "personal" ? "shared" : "personal",
keyPair[1]
keyPair.type == 'personal' ? 'shared' : 'personal',
keyPair.pos
)
}
className="relative flex justify-start items-center cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/10 duration-200 hover:text-gray-200 w-full"
>
<FontAwesomeIcon
className="text-lg pl-1.5 pr-3"
icon={keyPair[4] == "personal" ? faPeopleGroup : faPerson}
icon={keyPair.type == 'personal' ? faPeopleGroup : faPerson}
/>
<div className="text-sm">
{keyPair[4] == "personal"
@@ -143,8 +143,8 @@ const KeyPair = ({
modifyValue(
[...Array(randomStringLength)]
.map(() => Math.floor(Math.random() * 16).toString(16))
.join(""),
keyPair[1]
.join(''),
keyPair.pos
);
}
}}
@@ -152,7 +152,7 @@ const KeyPair = ({
>
<FontAwesomeIcon
className="text-lg pl-1.5 pr-3"
icon={keyPair[3] == "" ? faPlus : faShuffle}
icon={keyPair.value == '' ? faPlus : faShuffle}
/>
<div className="text-sm justify-between flex flex-row w-full">
<p>Generate Random Hex</p>
@@ -195,7 +195,7 @@ const KeyPair = ({
<div className="w-2"></div>
<div className="opacity-50 hover:opacity-100 duration-200">
<Button
onButtonPressed={() => deleteRow(keyPair[0])}
onButtonPressed={() => deleteRow(keyPair.id)}
color="red"
size="icon-sm"
icon={faX}
@@ -215,21 +215,21 @@ export default function Dashboard() {
const [fileState, setFileState] = useState([]);
const [buttonReady, setButtonReady] = useState(false);
const router = useRouter();
const [workspaceId, setWorkspaceId] = useState("");
const [workspaceId, setWorkspaceId] = useState('');
const [blurred, setBlurred] = useState(true);
const [isKeyAvailable, setIsKeyAvailable] = useState(true);
const [env, setEnv] = useState(
router.asPath.split("?").length == 1
? "Development"
: Object.keys(envMapping).includes(router.asPath.split("?")[1])
? router.asPath.split("?")[1]
: "Development"
router.asPath.split('?').length == 1
? 'Development'
: Object.keys(envMapping).includes(router.asPath.split('?')[1])
? router.asPath.split('?')[1]
: 'Development'
);
const [isNew, setIsNew] = useState(false);
const [searchKeys, setSearchKeys] = useState("");
const [searchKeys, setSearchKeys] = useState('');
const [errorDragAndDrop, setErrorDragAndDrop] = useState(false);
const [projectIdCopied, setProjectIdCopied] = useState(false);
const [sortMethod, setSortMethod] = useState("alphabetical");
const [sortMethod, setSortMethod] = useState('alphabetical');
const [checkDocsPopUpVisible, setCheckDocsPopUpVisible] = useState(false);
const [hasUserEverPushed, setHasUserEverPushed] = useState(false);
@@ -255,16 +255,16 @@ export default function Dashboard() {
// prompt the user if they try and leave with unsaved changes
useEffect(() => {
const warningText =
"Do you want to save your results before leaving this page?";
'Do you want to save your results before leaving this page?';
const handleWindowClose = (e) => {
if (!buttonReady) return;
e.preventDefault();
return (e.returnValue = warningText);
};
window.addEventListener("beforeunload", handleWindowClose);
window.addEventListener('beforeunload', handleWindowClose);
// router.events.on('routeChangeStart', beforeRouteHandler);
return () => {
window.removeEventListener("beforeunload", handleWindowClose);
window.removeEventListener('beforeunload', handleWindowClose);
// router.events.off('routeChangeStart', beforeRouteHandler);
};
}, [buttonReady]);
@@ -272,10 +272,12 @@ export default function Dashboard() {
/**
* Reorder rows alphabetically or in the opprosite order
*/
const reorderRows = () => {
setSortMethod(
sortMethod == "alphabetical" ? "-alphabetical" : "alphabetical"
const reorderRows = (dataToReorder) => {
setSortMethod((prevSort) =>
prevSort == 'alphabetical' ? '-alphabetical' : 'alphabetical'
);
sortValuesHandler(dataToReorder);
};
useEffect(() => {
@@ -284,24 +286,25 @@ export default function Dashboard() {
let userWorkspaces = await getWorkspaces();
const listWorkspaces = userWorkspaces.map((workspace) => workspace._id);
if (
!listWorkspaces.includes(router.asPath.split("/")[2].split("?")[0])
!listWorkspaces.includes(router.asPath.split('/')[2].split('?')[0])
) {
router.push("/dashboard/" + listWorkspaces[0]);
router.push('/dashboard/' + listWorkspaces[0]);
}
if (env != router.asPath.split("?")[1]) {
router.push(router.asPath.split("?")[0] + "?" + env);
if (env != router.asPath.split('?')[1]) {
router.push(router.asPath.split('?')[0] + '?' + env);
}
setBlurred(true);
setWorkspaceId(router.query.id);
await getSecretsForProject({
const dataToSort = await getSecretsForProject({
env,
setFileState,
setIsKeyAvailable,
setData,
workspaceId: router.query.id,
workspaceId: router.query.id
});
reorderRows(dataToSort);
const user = await getUser();
setIsNew(
@@ -311,11 +314,11 @@ export default function Dashboard() {
);
let userAction = await checkUserAction({
action: "first_time_secrets_pushed",
action: 'first_time_secrets_pushed'
});
setHasUserEverPushed(userAction ? true : false);
} catch (error) {
console.log("Error", error);
console.log('Error', error);
setData([]);
}
})();
@@ -324,49 +327,58 @@ export default function Dashboard() {
const addRow = () => {
setIsNew(false);
setData([...data, [guidGenerator(), data.length, "", "", "shared"]]);
setData([
...data,
{
id: guidGenerator(),
pos: data.length,
key: '',
value: '',
type: 'shared'
}
]);
};
const deleteRow = (id) => {
setButtonReady(true);
setData(data.filter((row) => row[0] !== id));
setData(data.filter((row) => row.id !== id));
};
const modifyValue = (value, id) => {
const modifyValue = (value, pos) => {
setData((oldData) => {
oldData[id][3] = value;
oldData[pos].value = value;
return [...oldData];
});
setButtonReady(true);
};
const modifyKey = (value, id) => {
const modifyKey = (value, pos) => {
setData((oldData) => {
oldData[id][2] = value;
oldData[pos].key = value;
return [...oldData];
});
setButtonReady(true);
};
const modifyVisibility = (value, id) => {
const modifyVisibility = (value, pos) => {
setData((oldData) => {
oldData[id][4] = value;
oldData[pos].type = value;
return [...oldData];
});
setButtonReady(true);
};
// For speed purposes and better perforamance, we are using useCallback
const listenChangeValue = useCallback((value, id) => {
modifyValue(value, id);
const listenChangeValue = useCallback((value, pos) => {
modifyValue(value, pos);
}, []);
const listenChangeKey = useCallback((value, id) => {
modifyKey(value, id);
const listenChangeKey = useCallback((value, pos) => {
modifyKey(value, pos);
}, []);
const listenChangeVisibility = useCallback((value, id) => {
modifyVisibility(value, id);
const listenChangeVisibility = useCallback((value, pos) => {
modifyVisibility(value, pos);
}, []);
/**
@@ -376,7 +388,7 @@ export default function Dashboard() {
// Format the new object with environment variables
let obj = Object.assign(
{},
...data.map((row) => ({ [row[2]]: [row[3], row[4]] }))
...data.map((row) => ({ [row.key]: [row.value, row.type] }))
);
// Checking if any of the secret keys start with a number - if so, don't do anything
@@ -385,22 +397,22 @@ export default function Dashboard() {
.every((v) => v === false);
const duplicatesExist =
data
?.map((item) => item[2])
?.map((item) => item.key)
.filter(
(item, index) => index !== data?.map((item) => item[2]).indexOf(item)
(item, index) => index !== data?.map((item) => item.key).indexOf(item)
).length > 0;
if (nameErrors) {
return createNotification({
text: "Solve all name errors first!",
type: "error",
text: 'Solve all name errors before saving secrets.',
type: 'error'
});
}
if (duplicatesExist) {
return createNotification({
text: "Your secrets weren't saved; please fix the conflicts first.",
type: "error",
text: 'Remove duplicated secret names before saving.',
type: 'error'
});
}
@@ -408,33 +420,10 @@ export default function Dashboard() {
setButtonReady(false);
pushKeys({ obj, workspaceId: router.query.id, env });
/**
* Check which integrations are active for this project and environment
* If there are any, update environment variables for those integrations
*/
let integrations = await getWorkspaceIntegrations({
workspaceId: router.query.id,
});
integrations.map(async (integration) => {
if (
envMapping[env] == integration.environment &&
integration.isActive == true
) {
let objIntegration = Object.assign(
{},
...data.map((row) => ({ [row[2]]: row[3] }))
);
await pushKeysIntegration({
obj: objIntegration,
integrationId: integration._id,
});
}
});
// If this user has never saved environment variables before, show them a prompt to read docs
if (!hasUserEverPushed) {
setCheckDocsPopUpVisible(true);
await registerUserAction({ action: "first_time_secrets_pushed" });
await registerUserAction({ action: 'first_time_secrets_pushed' });
}
};
@@ -447,14 +436,33 @@ export default function Dashboard() {
setBlurred(!blurred);
};
const sortValuesHandler = (dataToSort) => {
const sortedData = (dataToSort != 1 ? dataToSort : data)
.sort((a, b) =>
sortMethod == 'alphabetical'
? a.key.localeCompare(b.key)
: b.key.localeCompare(a.key)
)
.map((item, index) => {
return {
...item,
pos: index
};
});
setData(sortedData);
};
// This function downloads the secrets as a .env file
const download = () => {
const file = data.map((item) => [item[2], item[3]].join("=")).join("\n");
const file = data
.map((item) => [item.key, item.value].join('='))
.join('\n');
const blob = new Blob([file]);
const fileDownloadUrl = URL.createObjectURL(blob);
let alink = document.createElement("a");
let alink = document.createElement('a');
alink.href = fileDownloadUrl;
alink.download = envMapping[env] + ".env";
alink.download = envMapping[env] + '.env';
alink.click();
};
@@ -466,7 +474,7 @@ export default function Dashboard() {
* This function copies the project id to the clipboard
*/
function copyToClipboard() {
var copyText = document.getElementById("myInput");
var copyText = document.getElementById('myInput');
copyText.select();
copyText.setSelectionRange(0, 99999); // For mobile devices
@@ -506,7 +514,7 @@ export default function Dashboard() {
{data?.length == 0 && (
<ListBox
selected={env}
data={["Development", "Staging", "Production", "Testing"]}
data={['Development', 'Staging', 'Production', 'Testing']}
// ref={useRef(123)}
onChange={setEnv}
className="z-40"
@@ -563,7 +571,7 @@ export default function Dashboard() {
<>
<ListBox
selected={env}
data={["Development", "Staging", "Production", "Testing"]}
data={['Development', 'Staging', 'Production', 'Testing']}
// ref={useRef(123)}
onChange={setEnv}
className="z-40"
@@ -582,11 +590,11 @@ export default function Dashboard() {
</div>
<div className="ml-2 min-w-max flex flex-row items-start justify-start">
<Button
onButtonPressed={reorderRows}
onButtonPressed={() => reorderRows(1)}
color="mineshaft"
size="icon-md"
icon={
sortMethod == "alphabetical"
sortMethod == 'alphabetical'
? faArrowDownAZ
: faArrowDownZA
}
@@ -654,19 +662,14 @@ export default function Dashboard() {
{data
.filter(
(keyPair) =>
keyPair[2]
keyPair.key
.toLowerCase()
.includes(searchKeys.toLowerCase()) &&
keyPair[4] == "personal"
keyPair.type == 'personal'
)
.sort((a, b) =>
sortMethod == "alphabetical"
? a[2].localeCompare(b[2])
: b[2].localeCompare(a[2])
)
?.map((keyPair, index) => (
?.map((keyPair) => (
<KeyPair
key={keyPair[0]}
key={keyPair.id}
keyPair={keyPair}
deleteRow={deleteCertainRow}
modifyValue={listenChangeValue}
@@ -674,11 +677,11 @@ export default function Dashboard() {
modifyVisibility={listenChangeVisibility}
isBlurred={blurred}
duplicates={data
?.map((item) => item[2])
?.map((item) => item.key)
.filter(
(item, index) =>
index !==
data?.map((item) => item[2]).indexOf(item)
data?.map((item) => item.key).indexOf(item)
)}
/>
))}
@@ -686,7 +689,7 @@ export default function Dashboard() {
</div>
<div
className={`bg-white/5 mt-1 mb-2 rounded-md p-1 pb-2 max-w-5xl ${
data?.length > 8 ? "h-3/4" : "h-min"
data?.length > 8 ? 'h-3/4' : 'h-min'
}`}
>
<div className="sticky top-0 z-10 bg-bunker flex flex-row pl-4 pr-5 pt-4 pb-2 items-center justify-between text-gray-300 font-bold">
@@ -708,19 +711,14 @@ export default function Dashboard() {
{data
.filter(
(keyPair) =>
keyPair[2]
keyPair.key
.toLowerCase()
.includes(searchKeys.toLowerCase()) &&
keyPair[4] == "shared"
keyPair.type == 'shared'
)
.sort((a, b) =>
sortMethod == "alphabetical"
? a[2].localeCompare(b[2])
: b[2].localeCompare(a[2])
)
?.map((keyPair, index) => (
?.map((keyPair) => (
<KeyPair
key={keyPair[0]}
key={keyPair.id}
keyPair={keyPair}
deleteRow={deleteCertainRow}
modifyValue={listenChangeValue}
@@ -728,11 +726,11 @@ export default function Dashboard() {
modifyVisibility={listenChangeVisibility}
isBlurred={blurred}
duplicates={data
?.map((item) => item[2])
?.map((item) => item.key)
.filter(
(item, index) =>
index !==
data?.map((item) => item[2]).indexOf(item)
data?.map((item) => item.key).indexOf(item)
)}
/>
))}
@@ -772,10 +770,10 @@ export default function Dashboard() {
/>
)}
{fileState.message ==
"Failed membership validation for workspace" && (
'Failed membership validation for workspace' && (
<p>You are not authorized to view this project.</p>
)}
{fileState.message == "Access needed to pull the latest file" ||
{fileState.message == 'Access needed to pull the latest file' ||
(!isKeyAvailable && (
<>
<FontAwesomeIcon

Some files were not shown because too many files have changed in this diff Show More