ref(frontend): update to absolute import

This commit is contained in:
이강준
2022-11-26 18:19:41 +09:00
parent 001df70e26
commit 22c184840c
73 changed files with 2029 additions and 1287 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import checkAuth from "../pages/api/auth/CheckAuth";
import checkAuth from "~/pages/api/auth/CheckAuth";
import Image from "next/image";
import { publicPaths } from "../const";
@@ -1,7 +1,7 @@
import { Dialog, Transition } from "@headlessui/react";
import { Fragment, useState } from "react";
import InputField from "../InputField";
import addIncidentContact from "../../../pages/api/organization/addIncidentContact";
import addIncidentContact from "~/pages/api/organization/addIncidentContact";
import Button from "../buttons/Button";
const AddIncidentContactDialog = ({
@@ -4,9 +4,9 @@ import ListBox from "../Listbox";
import { useRouter } from "next/router";
import Button from "../buttons/Button";
import InputField from "../InputField";
import getLatestFileKey from "../../../pages/api/workspace/getLatestFileKey";
import getLatestFileKey from "~/pages/api/workspace/getLatestFileKey";
import { decryptAssymmetric, encryptAssymmetric } from "../../utilities/crypto";
import addServiceToken from "../../../pages/api/serviceToken/addServiceToken";
import addServiceToken from "~/pages/api/serviceToken/addServiceToken";
import nacl from "tweetnacl";
import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@@ -28,7 +28,7 @@ const AddServiceTokenDialog = ({
isOpen,
closeModal,
workspaceId,
workspaceName
workspaceName,
}) => {
const router = useRouter();
const [serviceToken, setServiceToken] = useState("");
@@ -44,7 +44,7 @@ const AddServiceTokenDialog = ({
ciphertext: latestFileKey.latestKey.encryptedKey,
nonce: latestFileKey.latestKey.nonce,
publicKey: latestFileKey.latestKey.sender.publicKey,
privateKey: localStorage.getItem("PRIVATE_KEY")
privateKey: localStorage.getItem("PRIVATE_KEY"),
});
// generate new public/private key pair
@@ -56,7 +56,7 @@ const AddServiceTokenDialog = ({
const { ciphertext: encryptedKey, nonce } = encryptAssymmetric({
plaintext: key,
publicKey,
privateKey
privateKey,
});
let newServiceToken = await addServiceToken({
@@ -66,12 +66,12 @@ const AddServiceTokenDialog = ({
expiresIn: expiryMapping[serviceTokenExpiresIn],
publicKey,
encryptedKey,
nonce
})
nonce,
});
const serviceToken = newServiceToken + ',' + privateKey;
const serviceToken = newServiceToken + "," + privateKey;
setServiceToken(serviceToken);
}
};
function copyToClipboard() {
// Get the text field
@@ -94,7 +94,7 @@ const AddServiceTokenDialog = ({
closeModal();
setServiceTokenName("");
setServiceToken("");
}
};
return (
<div className="z-50">
@@ -123,18 +123,25 @@ const AddServiceTokenDialog = ({
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
{serviceToken == ""
? <Dialog.Panel className="w-full max-w-md transform rounded-md bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all">
{serviceToken == "" ? (
<Dialog.Panel className="w-full max-w-md transform rounded-md bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-gray-400 z-50"
>
Add a service token for {workspaceName}
Add a service token for{" "}
{workspaceName}
</Dialog.Title>
<div className="mt-2 mb-4">
<div className="flex flex-col">
<p className="text-sm text-gray-500">
Specify the name, environment, and expiry period. When a token is generated, you will only be able to see it once before it disappears. Make sure to save it somewhere.
Specify the name,
environment, and expiry
period. When a token is
generated, you will only be
able to see it once before
it disappears. Make sure to
save it somewhere.
</p>
</div>
</div>
@@ -154,7 +161,12 @@ const AddServiceTokenDialog = ({
<ListBox
selected={serviceTokenEnv}
onChange={setServiceTokenEnv}
data={["Development", "Staging", "Production", "Testing"]}
data={[
"Development",
"Staging",
"Production",
"Testing",
]}
width="full"
text="Environment: "
/>
@@ -162,8 +174,14 @@ const AddServiceTokenDialog = ({
<div className="max-h-28">
<ListBox
selected={serviceTokenExpiresIn}
onChange={setServiceTokenExpiresIn}
data={["1 day", "7 days", "1 month"]}
onChange={
setServiceTokenExpiresIn
}
data={[
"1 day",
"7 days",
"1 month",
]}
width="full"
text="Expires in: "
/>
@@ -171,17 +189,24 @@ const AddServiceTokenDialog = ({
<div className="max-w-max">
<div className="mt-6 flex flex-col justify-start w-max">
<Button
onButtonPressed={() => generateServiceToken()}
onButtonPressed={() =>
generateServiceToken()
}
color="mineshaft"
text="Add Service Token"
textDisabled="Add Service Token"
size="md"
active={serviceTokenName == "" ? false : true}
active={
serviceTokenName == ""
? false
: true
}
/>
</div>
</div>
</Dialog.Panel>
: <Dialog.Panel className="w-full max-w-md transform rounded-md bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all">
) : (
<Dialog.Panel className="w-full max-w-md transform rounded-md bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-gray-400 z-50"
@@ -191,17 +216,40 @@ const AddServiceTokenDialog = ({
<div className="mt-2 mb-4">
<div className="flex flex-col">
<p className="text-sm text-gray-500">
Once you close this popup, you will never see your service token again
Once you close this popup,
you will never see your
service token again
</p>
</div>
</div>
<div className="w-full">
<div className="flex justify-end items-center bg-white/[0.07] text-base mt-2 mr-2 rounded-md text-gray-400 w-full h-36">
<input type="text" value={serviceToken} id="serviceToken" className="invisible bg-white/0 text-gray-400 py-2 w-full px-2 min-w-full outline-none"></input>
<div className="bg-white/0 max-w-md text-sm text-gray-400 py-2 w-full pl-14 pr-2 break-words outline-none">{serviceToken}</div>
<input
type="text"
value={serviceToken}
id="serviceToken"
className="invisible bg-white/0 text-gray-400 py-2 w-full px-2 min-w-full outline-none"
></input>
<div className="bg-white/0 max-w-md text-sm text-gray-400 py-2 w-full pl-14 pr-2 break-words outline-none">
{serviceToken}
</div>
<div className="group font-normal h-full relative inline-block text-gray-400 underline hover:text-primary duration-200">
<button onClick={copyToClipboard} className="h-full pl-3.5 pr-4 border-l border-white/20 py-2 hover:bg-white/[0.12] duration-200">
{serviceTokenCopied ? <FontAwesomeIcon icon={faCheck} className="pr-0.5"/> : <FontAwesomeIcon icon={faCopy} />}
<button
onClick={
copyToClipboard
}
className="h-full pl-3.5 pr-4 border-l border-white/20 py-2 hover:bg-white/[0.12] duration-200"
>
{serviceTokenCopied ? (
<FontAwesomeIcon
icon={faCheck}
className="pr-0.5"
/>
) : (
<FontAwesomeIcon
icon={faCopy}
/>
)}
</button>
<span className="absolute hidden group-hover:flex group-hover:animate-popup duration-300 w-28 -left-8 -top-20 translate-y-full px-3 py-2 bg-chicago-900 rounded-md text-center text-gray-400 text-sm">
Click to Copy
@@ -211,14 +259,16 @@ const AddServiceTokenDialog = ({
</div>
<div className="mt-6 flex flex-col justify-start w-max">
<Button
onButtonPressed={() => closeAddServiceTokenModal()}
onButtonPressed={() =>
closeAddServiceTokenModal()
}
color="mineshaft"
text="Close"
size="md"
/>
</div>
</Dialog.Panel>
}
)}
</Transition.Child>
</div>
</div>
+41 -22
View File
@@ -4,7 +4,7 @@ import { useEffect, useState } from "react";
import NavBarDashboard from "../navigation/NavBarDashboard";
import Listbox from "./Listbox";
import getWorkspaces from "../../pages/api/workspace/getWorkspaces";
import getWorkspaces from "~/pages/api/workspace/getWorkspaces";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faHouse,
@@ -14,11 +14,11 @@ import {
faLink,
} from "@fortawesome/free-solid-svg-icons";
import AddWorkspaceDialog from "./dialog/AddWorkspaceDialog";
import createWorkspace from "../../pages/api/workspace/createWorkspace";
import getOrganizationUserProjects from "../../pages/api/organization/GetOrgUserProjects";
import getOrganizationUsers from "../../pages/api/organization/GetOrgUsers";
import addUserToWorkspace from "../../pages/api/workspace/addUserToWorkspace";
import getOrganizations from "../../pages/api/organization/getOrgs";
import createWorkspace from "~/pages/api/workspace/createWorkspace";
import getOrganizationUserProjects from "~/pages/api/organization/GetOrgUserProjects";
import getOrganizationUsers from "~/pages/api/organization/GetOrgUsers";
import addUserToWorkspace from "~/pages/api/workspace/addUserToWorkspace";
import getOrganizations from "~/pages/api/organization/getOrgs";
import { faPlus } from "@fortawesome/free-solid-svg-icons";
import { decryptAssymmetric, encryptAssymmetric } from "../utilities/crypto";
@@ -48,9 +48,7 @@ export default function Layout({ children }) {
setLoading(true);
setTimeout(() => setLoading(false), 1500);
const workspaces = await getWorkspaces();
const currentWorkspaces = workspaces.map(
(workspace) => workspace.name
);
const currentWorkspaces = workspaces.map((workspace) => workspace.name);
if (!currentWorkspaces.includes(workspaceName)) {
const newWorkspace = await createWorkspace(
workspaceName,
@@ -141,7 +139,10 @@ export default function Layout({ children }) {
useEffect(async () => {
// Put a user in a workspace if they're not in one yet
if (localStorage.getItem("orgData.id") == null || localStorage.getItem("orgData.id") == "") {
if (
localStorage.getItem("orgData.id") == null ||
localStorage.getItem("orgData.id") == ""
) {
const userOrgs = await getOrganizations();
localStorage.setItem("orgData.id", userOrgs[0]._id);
}
@@ -150,7 +151,11 @@ export default function Layout({ children }) {
orgId: localStorage.getItem("orgData.id"),
});
let userWorkspaces = orgUserProjects;
if (userWorkspaces.length == 0 && (router.asPath != "/noprojects" && !router.asPath.includes("settings"))) {
if (
userWorkspaces.length == 0 &&
router.asPath != "/noprojects" &&
!router.asPath.includes("settings")
) {
router.push("/noprojects");
} else if (router.asPath != "/noprojects") {
const intendedWorkspaceId = router.asPath
@@ -158,7 +163,9 @@ export default function Layout({ children }) {
[router.asPath.split("/").length - 1].split("?")[0];
// If a user is not a member of a workspace they are trying to access, just push them to one of theirs
if (intendedWorkspaceId != "heroku" && !userWorkspaces
if (
intendedWorkspaceId != "heroku" &&
!userWorkspaces
.map((workspace) => workspace._id)
.includes(intendedWorkspaceId)
) {
@@ -207,7 +214,10 @@ export default function Layout({ children }) {
workspaceMapping[workspaceSelected] +
"?Development"
);
localStorage.setItem("projectData.id", workspaceMapping[workspaceSelected])
localStorage.setItem(
"projectData.id",
workspaceMapping[workspaceSelected]
);
}
} catch (error) {
console.log(error);
@@ -226,8 +236,8 @@ export default function Layout({ children }) {
<div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
PROJECT
</div>
{workspaceList.length>0
? <Listbox
{workspaceList.length > 0 ? (
<Listbox
selected={workspaceSelected}
onChange={setWorkspaceSelected}
data={workspaceList}
@@ -235,25 +245,33 @@ export default function Layout({ children }) {
text=""
workspaceMapping={workspaceMapping}
/>
: <Button
) : (
<Button
text="Add Project"
onButtonPressed={openModal}
color="mineshaft"
size="md"
icon={faPlus}
/>
}
)}
</div>
<ul>
{workspaceList.length > 0 && menuItems.map(({ href, title, emoji }) => (
{workspaceList.length > 0 &&
menuItems.map(({ href, title, emoji }) => (
<li className="mt-1.5 mx-2" key={title}>
{router.asPath.split("/")[1] ===
href.split("/")[1] &&
(["project", "billing", "org", "personal"].includes(
([
"project",
"billing",
"org",
"personal",
].includes(
router.asPath.split("/")[2]
)
? router.asPath.split("/")[2] ===
href.split("/")[2]
? router.asPath.split(
"/"
)[2] === href.split("/")[2]
: true) ? (
<div
className={`flex p-2 text-white text-sm rounded cursor-pointer bg-mineshaft-50/10`}
@@ -264,7 +282,8 @@ export default function Layout({ children }) {
</p>
{title}
</div>
) : router.asPath == "/noprojects" ? (
) : router.asPath ==
"/noprojects" ? (
<div
className={`flex p-2 text-white text-sm rounded`}
>
+9 -6
View File
@@ -1,11 +1,11 @@
import React, { useEffect, useMemo, useState } from "react";
import { useRouter } from "next/router";
import Listbox from "../Listbox";
import uploadKeys from "../../../pages/api/workspace/uploadKeys";
import getLatestFileKey from "../../../pages/api/workspace/getLatestFileKey";
import deleteUserFromWorkspace from "../../../pages/api/workspace/deleteUserFromWorkspace";
import changeUserRoleInWorkspace from "../../../pages/api/workspace/changeUserRoleInWorkspace";
import deleteUserFromOrganization from "../../../pages/api/organization/deleteUserFromOrganization";
import uploadKeys from "~/pages/api/workspace/uploadKeys";
import getLatestFileKey from "~/pages/api/workspace/getLatestFileKey";
import deleteUserFromWorkspace from "~/pages/api/workspace/deleteUserFromWorkspace";
import changeUserRoleInWorkspace from "~/pages/api/workspace/changeUserRoleInWorkspace";
import deleteUserFromOrganization from "~/pages/api/organization/deleteUserFromOrganization";
import { faX } from "@fortawesome/free-solid-svg-icons";
import Button from "../buttons/Button";
import guidGenerator from "../../utilities/randomId";
@@ -145,7 +145,10 @@ const UserTable = ({
)
.map((row, index) => {
return (
<tr key={guidGenerator()} className="bg-bunker-800 hover:bg-bunker-800/5">
<tr
key={guidGenerator()}
className="bg-bunker-800 hover:bg-bunker-800/5"
>
<td className="pl-6 py-2 border-mineshaft-700 border-t text-gray-300">
{row.firstName}
</td>
+12 -2
View File
@@ -1,5 +1,5 @@
import React from "react";
import StripeRedirect from "../../pages/api/organization/StripeRedirect";
import StripeRedirect from "~/pages/api/organization/StripeRedirect";
export default function Plan({ plan }) {
return (
@@ -54,7 +54,17 @@ export default function Plan({ plan }) {
: "hover:bg-primary hover:text-black hover:border-primary"
} bg-bunker duration-200 cursor-pointer rounded-md flex w-max`}
>
<button onClick={() => StripeRedirect({orgId: localStorage.getItem("orgData.id")})}>{plan.buttonTextMain}</button>
<button
onClick={() =>
StripeRedirect({
orgId: localStorage.getItem(
"orgData.id"
),
})
}
>
{plan.buttonTextMain}
</button>
</div>
)}
<a href="/pricing" target='_blank rel="noopener"'>
@@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import Image from "next/image";
import logout from "../../pages/api/auth/Logout";
import logout from "~/pages/api/auth/Logout";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCircleQuestion } from "@fortawesome/free-regular-svg-icons";
import {
@@ -13,13 +13,13 @@ import {
faRightFromBracket,
faEnvelope,
faPlus,
faAngleDown
faAngleDown,
} from "@fortawesome/free-solid-svg-icons";
import { faSlack, faGithub } from "@fortawesome/free-brands-svg-icons";
import { Menu, Transition } from "@headlessui/react";
import getUser from "../../pages/api/user/getUser";
import getOrganizations from "../../pages/api/organization/getOrgs";
import getOrganization from "../../pages/api/organization/GetOrg";
import getUser from "~/pages/api/user/getUser";
import getOrganizations from "~/pages/api/organization/getOrgs";
import getOrganization from "~/pages/api/organization/GetOrg";
import guidGenerator from "../utilities/randomId";
const supportOptions = [
@@ -128,7 +128,10 @@ export default function Navbar({ onButtonPressed }) {
<div>
<Menu.Button className="inline-flex w-full justify-center rounded-md pr-2 pl-2 py-2 text-sm font-medium text-gray-200 rounded-md hover:bg-white/10 duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75">
{user?.firstName} {user?.lastName}
<FontAwesomeIcon icon={faAngleDown} className="ml-2 mt-1 text-sm text-gray-300 hover:text-lime-100"/>
<FontAwesomeIcon
icon={faAngleDown}
className="ml-2 mt-1 text-sm text-gray-300 hover:text-lime-100"
/>
</Menu.Button>
</div>
<Transition
@@ -148,10 +151,12 @@ export default function Navbar({ onButtonPressed }) {
<div
onClick={() =>
router.push(
"/settings/personal/" + router.query.id
"/settings/personal/" +
router.query.id
)
}
className="flex flex-row items-center px-1 mx-1 my-1 hover:bg-white/5 cursor-pointer rounded-md">
className="flex flex-row items-center px-1 mx-1 my-1 hover:bg-white/5 cursor-pointer rounded-md"
>
<div className="bg-white/10 h-8 w-9 rounded-full flex items-center justify-center text-gray-300">
{user?.firstName?.charAt(0)}
</div>
@@ -159,7 +164,8 @@ export default function Navbar({ onButtonPressed }) {
<div>
<p className="text-gray-300 px-2 pt-1 text-sm">
{" "}
{user?.firstName} {user?.lastName}
{user?.firstName}{" "}
{user?.lastName}
</p>
<p className="text-gray-400 px-2 pb-1 text-xs">
{" "}
@@ -235,7 +241,10 @@ export default function Navbar({ onButtonPressed }) {
className="relative flex justify-start cursor-pointer select-none py-2 pl-10 pr-4 rounded-md text-gray-400 hover:bg-primary/100 duration-200 hover:text-black hover:font-semibold mt-1"
>
<span className="rounded-lg absolute inset-y-0 left-0 flex items-center pl-3 pr-4">
<FontAwesomeIcon icon={faPlus} className="ml-1" />
<FontAwesomeIcon
icon={faPlus}
className="ml-1"
/>
</span>
<div className="text-sm ml-1">
Invite Members
@@ -243,7 +252,8 @@ export default function Navbar({ onButtonPressed }) {
</div>
</button>
</div>
{orgs?.length > 1 && <div className="px-1 pt-1">
{orgs?.length > 1 && (
<div className="px-1 pt-1">
<div className="text-gray-400 self-start ml-2 mt-2 text-xs font-semibold tracking-wide">
OTHER ORGANIZATIONS
</div>
@@ -279,7 +289,8 @@ export default function Navbar({ onButtonPressed }) {
</div>
))}
</div>
</div>}
</div>
)}
<div className="px-1 py-1">
<Menu.Item>
{({ active }) => (
+19 -13
View File
@@ -1,10 +1,13 @@
import React, { useEffect, useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleRight, faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
import {
faAngleRight,
faQuestionCircle,
} from "@fortawesome/free-solid-svg-icons";
import { faCcMastercard, faCcVisa } from "@fortawesome/free-brands-svg-icons";
import { faCircle } from "@fortawesome/free-solid-svg-icons";
import getOrganization from "../../pages/api/organization/GetOrg";
import getWorkspaceInfo from "../../pages/api/workspace/getWorkspaceInfo";
import getOrganization from "~/pages/api/organization/GetOrg";
import getWorkspaceInfo from "~/pages/api/workspace/getWorkspaceInfo";
import { useRouter } from "next/router";
export default function NavHeader({ pageName, isProjectRelated }) {
@@ -28,20 +31,23 @@ export default function NavHeader({ pageName, isProjectRelated}) {
<div className="bg-primary-900 h-6 w-6 rounded-md flex items-center justify-center text-mineshaft-100 mr-2">
{orgName?.charAt(0)}
</div>
<div className="text-primary text-sm font-semibold">
{orgName}
</div>
{isProjectRelated && <>
<FontAwesomeIcon icon={faAngleRight} className="ml-3 text-sm text-gray-400 mr-3" />
<div className="text-primary text-sm font-semibold">{orgName}</div>
{isProjectRelated && (
<>
<FontAwesomeIcon
icon={faAngleRight}
className="ml-3 text-sm text-gray-400 mr-3"
/>
<div className="font-semibold text-primary text-sm">
{workspaceName}
</div>
</>
}
<FontAwesomeIcon icon={faAngleRight} className="ml-3 text-sm text-gray-400 mr-3" />
<div className="text-gray-400 text-sm">
{pageName}
</div>
)}
<FontAwesomeIcon
icon={faAngleRight}
className="ml-3 text-sm text-gray-400 mr-3"
/>
<div className="text-gray-400 text-sm">{pageName}</div>
</div>
);
}
@@ -1,13 +1,11 @@
import token from "../../pages/api/auth/Token"
import { PATH } from '../../const';
import token from "~/pages/api/auth/Token";
import { PATH } from "../../const";
export default class SecurityClient {
static authOrigins = [PATH]
static #token = '';
static authOrigins = [PATH];
static #token = "";
contructor() {
}
contructor() {}
static setToken(token) {
this.#token = token;
@@ -18,11 +16,11 @@ export default class SecurityClient {
const destOrigin = new URL(req.url).origin;
if (this.#token == "") {
this.setToken(await token())
this.setToken(await token());
}
if (this.#token && this.authOrigins.includes(destOrigin)) {
req.headers.set('Authorization', "Bearer " + this.#token);
req.headers.set("Authorization", "Bearer " + this.#token);
return fetch(req);
}
}
+35 -12
View File
@@ -1,10 +1,10 @@
import login1 from "../../pages/api/auth/Login1";
import login2 from "../../pages/api/auth/Login2";
import Aes256Gcm from "../../components/aes-256-gcm";
import login1 from "~/pages/api/auth/Login1";
import login2 from "~/pages/api/auth/Login2";
import Aes256Gcm from "~/components/aes-256-gcm";
import pushKeys from "./pushKeys";
import { initPostHog } from "../analytics/posthog";
import getOrganizations from "../../pages/api/organization/getOrgs";
import getOrganizationUserProjects from "../../pages/api/organization/GetOrgUserProjects";
import getOrganizations from "~/pages/api/organization/getOrgs";
import getOrganizationUserProjects from "~/pages/api/organization/GetOrgUserProjects";
import SecurityClient from "./SecurityClient";
import { ENV } from "./config";
@@ -77,7 +77,14 @@ const attemptLogin = async (
encryptedPrivateKey,
iv,
tag,
password.slice(0, 32).padStart(32 + (password.slice(0, 32).length - new Blob([password]).size), "0")
password
.slice(0, 32)
.padStart(
32 +
(password.slice(0, 32).length -
new Blob([password]).size),
"0"
)
);
try {
@@ -101,10 +108,14 @@ const attemptLogin = async (
}
const userOrgs = await getOrganizations();
const userOrgsData = userOrgs.map(org => org._id);
const userOrgsData = userOrgs.map((org) => org._id);
let orgToLogin;
if (userOrgsData.includes(localStorage.getItem("orgData.id"))) {
if (
userOrgsData.includes(
localStorage.getItem("orgData.id")
)
) {
orgToLogin = localStorage.getItem("orgData.id");
} else {
orgToLogin = userOrgsData[0];
@@ -115,16 +126,28 @@ const attemptLogin = async (
orgId: orgToLogin,
});
orgUserProjects = orgUserProjects?.map(project => project._id);
orgUserProjects = orgUserProjects?.map(
(project) => project._id
);
let projectToLogin;
if (orgUserProjects.includes(localStorage.getItem("projectData.id"))) {
if (
orgUserProjects.includes(
localStorage.getItem("projectData.id")
)
) {
projectToLogin = localStorage.getItem("projectData.id");
} else {
try {
projectToLogin = orgUserProjects[0];
localStorage.setItem("projectData.id", projectToLogin);
localStorage.setItem(
"projectData.id",
projectToLogin
);
} catch (error) {
console.log("ERROR: User likely has no projects. ", error)
console.log(
"ERROR: User likely has no projects. ",
error
);
}
}
+31 -15
View File
@@ -1,6 +1,6 @@
import Aes256Gcm from "../aes-256-gcm";
import SRP1 from "../../pages/api/auth/SRP1";
import changePassword2 from "../../pages/api/auth/ChangePassword2";
import SRP1 from "~/pages/api/auth/SRP1";
import changePassword2 from "~/pages/api/auth/ChangePassword2";
const nacl = require("tweetnacl");
nacl.util = require("tweetnacl-util");
@@ -41,7 +41,7 @@ const changePassword = async (
let serverPublicKey, salt;
try {
const res = await SRP1({
clientPublicKey: clientPublicKey
clientPublicKey: clientPublicKey,
});
serverPublicKey = res.serverPublicKey;
salt = res.salt;
@@ -54,15 +54,26 @@ const changePassword = async (
clientOldPassword.setServerPublicKey(serverPublicKey);
const clientProof = clientOldPassword.getProof(); // called M1
clientNewPassword.init({
clientNewPassword.init(
{
username: email,
password: newPassword
}, async () => {
clientNewPassword.createVerifier(async (err, result) => {
password: newPassword,
},
async () => {
clientNewPassword.createVerifier(
async (err, result) => {
let { ciphertext, iv, tag } = Aes256Gcm.encrypt(
localStorage.getItem("PRIVATE_KEY"),
newPassword.slice(0, 32).padStart(32 + (newPassword.slice(0, 32).length - new Blob([newPassword]).size), "0")
newPassword
.slice(0, 32)
.padStart(
32 +
(newPassword.slice(0, 32)
.length -
new Blob([newPassword])
.size),
"0"
)
);
if (ciphertext) {
@@ -81,7 +92,7 @@ const changePassword = async (
tag,
salt: result.salt,
verifier: result.verifier,
clientProof
clientProof,
});
if (res.status == 400) {
setCurrentPasswordError(true);
@@ -91,17 +102,22 @@ const changePassword = async (
setNewPassword("");
}
} catch (err) {
setCurrentPasswordError(true)
setCurrentPasswordError(true);
console.log(err);
}
}
});
});
}
);
}
);
}
);
} catch (error) {
console.log("Something went wrong during changing the password", slat, serverPublicKey);
console.log(
"Something went wrong during changing the password",
slat,
serverPublicKey
);
}
return true;
};
@@ -1,7 +1,6 @@
import getSecrets from "../../pages/api/files/GetSecrets";
import getSecrets from "~/pages/api/files/GetSecrets";
import guidGenerator from "./randomId";
const {
decryptAssymmetric,
decryptSymmetric,
@@ -21,15 +20,12 @@ const getSecretsForProject = async ({
setFileState,
setIsKeyAvailable,
setData,
workspaceId
workspaceId,
}) => {
try {
let file;
try {
file = await getSecrets(
workspaceId,
envMapping[env]
);
file = await getSecrets(workspaceId, envMapping[env]);
setFileState(file);
} catch (error) {
@@ -98,7 +94,9 @@ const getSecretsForProject = async ({
line["type"],
]);
} catch (error) {
console.log("Something went wrong during accessing or decripting secrets.");
console.log(
"Something went wrong during accessing or decripting secrets."
);
}
return true;
};
+17 -12
View File
@@ -1,6 +1,6 @@
import Aes256Gcm from "../aes-256-gcm";
import SRP1 from "../../pages/api/auth/SRP1";
import issueBackupPrivateKey from "../../pages/api/auth/IssueBackupPrivateKey";
import SRP1 from "~/pages/api/auth/SRP1";
import issueBackupPrivateKey from "~/pages/api/auth/IssueBackupPrivateKey";
import generateBackupPDF from "./generateBackupPDF";
const nacl = require("tweetnacl");
@@ -24,7 +24,7 @@ const issueBackupKey = async ({
password,
personalName,
setBackupKeyError,
setBackupKeyIssued
setBackupKeyIssued,
}) => {
try {
setBackupKeyError(false);
@@ -40,7 +40,7 @@ const issueBackupKey = async ({
let serverPublicKey, salt;
try {
const res = await SRP1({
clientPublicKey: clientPublicKey
clientPublicKey: clientPublicKey,
});
serverPublicKey = res.serverPublicKey;
salt = res.salt;
@@ -55,13 +55,13 @@ const issueBackupKey = async ({
const generatedKey = crypto.randomBytes(16).toString("hex");
clientKey.init({
clientKey.init(
{
username: email,
password: generatedKey
}, async () => {
password: generatedKey,
},
async () => {
clientKey.createVerifier(async (err, result) => {
let { ciphertext, iv, tag } = Aes256Gcm.encrypt(
localStorage.getItem("PRIVATE_KEY"),
generatedKey
@@ -73,17 +73,22 @@ const issueBackupKey = async ({
tag,
salt: result.salt,
verifier: result.verifier,
clientProof
clientProof,
});
if (res.status == 400) {
setBackupKeyError(true);
} else if (res.status == 200) {
generateBackupPDF(personalName, email, generatedKey);
generateBackupPDF(
personalName,
email,
generatedKey
);
setBackupKeyIssued(true);
}
});
})
}
);
}
);
} catch (error) {
+3 -3
View File
@@ -1,6 +1,6 @@
import getLatestFileKey from "../../pages/api/workspace/getLatestFileKey";
import getWorkspaceKeys from "../../pages/api/workspace/getWorkspaceKeys";
import uploadSecrets from "../../pages/api/files/UploadSecrets";
import getLatestFileKey from "~/pages/api/workspace/getLatestFileKey";
import getWorkspaceKeys from "~/pages/api/workspace/getWorkspaceKeys";
import uploadSecrets from "~/pages/api/files/UploadSecrets";
const crypto = require("crypto");
const {
@@ -1,11 +1,8 @@
import publicKeyInfical from "../../pages/api/auth/publicKeyInfisical"
import changeHerokuConfigVars from "../../pages/api/integrations/ChangeHerokuConfigVars";
import publicKeyInfical from "~/pages/api/auth/publicKeyInfisical";
import changeHerokuConfigVars from "~/pages/api/integrations/ChangeHerokuConfigVars";
const crypto = require("crypto");
const {
encryptSymmetric,
encryptAssymmetric,
} = require("./crypto");
const { encryptSymmetric, encryptAssymmetric } = require("./crypto");
const nacl = require("tweetnacl");
nacl.util = require("tweetnacl-util");
@@ -71,7 +68,7 @@ const pushKeysIntegration = async ({ obj, integrationId }) => {
nonce,
};
changeHerokuConfigVars({integrationId, key, secrets})
changeHerokuConfigVars({ integrationId, key, secrets });
};
export default pushKeysIntegration;
+2 -2
View File
@@ -6,10 +6,10 @@
"components/*"
],
"~/utilities/*": [
"components/utilities"
"components/utilities/*"
],
"~/pages/*": [
"components/*"
"pages/*"
],
}
}
+5 -7
View File
@@ -1,13 +1,13 @@
import "../styles/globals.css";
import "@fortawesome/fontawesome-svg-core/styles.css";
import { config } from "@fortawesome/fontawesome-svg-core";
import Layout from "../components/basic/layout";
import RouteGuard from "../components/RouteGuard";
import Layout from "~/components/basic/layout";
import RouteGuard from "~/components/RouteGuard";
import { publicPaths } from "../const.js";
import { useEffect } from "react";
import { useRouter } from "next/router";
import { initPostHog } from "../components/analytics/posthog";
import { ENV } from "../components/utilities/config";
import { initPostHog } from "~/components/analytics/posthog";
import { ENV } from "~/utilities/config";
config.autoAddCss = false;
@@ -39,9 +39,7 @@ const App = ({ Component, pageProps, ...appProps }) => {
publicPaths.includes("/" + appProps.router.pathname.split("/")[1]) ||
!Component.requireAuth
) {
return (
<Component {...pageProps} />
)
return <Component {...pageProps} />;
}
return (
+18 -12
View File
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -6,28 +6,34 @@ import { PATH } from "../../../const";
* @param {*} clientPublicKey
* @returns
*/
const changePassword2 = ({encryptedPrivateKey, iv, tag, salt, verifier, clientProof}) => {
const changePassword2 = ({
encryptedPrivateKey,
iv,
tag,
salt,
verifier,
clientProof,
}) => {
return SecurityClient.fetchCall(PATH + "/api/v1/password/change-password", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"clientProof": clientProof,
"encryptedPrivateKey": encryptedPrivateKey,
"iv": iv,
"tag": tag,
"salt": salt,
"verifier": verifier
clientProof: clientProof,
encryptedPrivateKey: encryptedPrivateKey,
iv: iv,
tag: tag,
salt: salt,
verifier: verifier,
}),
})
.then(async res => {
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to change the password');
console.log("Failed to change the password");
}
})
});
};
export default changePassword2;
+3 -4
View File
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient.js";
import SecurityClient from "~/utilities/SecurityClient.js";
import { PATH } from "../../../const.js";
/**
@@ -14,14 +14,13 @@ const checkAuth = async (req, res) => {
headers: {
"Content-Type": "application/json",
},
})
.then(res => {
}).then((res) => {
if (res.status == 200) {
return res;
} else {
console.log("Not authorized");
}
})
});
};
export default checkAuth;
@@ -1,32 +1,41 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
* 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(PATH + "/api/v1/password/backup-private-key", {
const issueBackupPrivateKey = ({
encryptedPrivateKey,
iv,
tag,
salt,
verifier,
clientProof,
}) => {
return SecurityClient.fetchCall(
PATH + "/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
clientProof: clientProof,
encryptedPrivateKey: encryptedPrivateKey,
iv: iv,
tag: tag,
salt: salt,
verifier: verifier,
}),
})
.then(res => {
}
).then((res) => {
if (res.status == 200) {
return res;
} else {
return res;
console.log("Failed to issue the backup key");
}
})
});
};
export default issueBackupPrivateKey;
+4 -5
View File
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -14,9 +14,8 @@ const logout = async (req, res) => {
headers: {
"Content-Type": "application/json",
},
credentials: "include"
})
.then(res => {
credentials: "include",
}).then((res) => {
if (res.status == 200) {
SecurityClient.setToken("");
// Delete the cookie by not setting a value; Alternatively clear the local storage
@@ -30,7 +29,7 @@ const logout = async (req, res) => {
} else {
console.log("Failed to log out");
}
})
});
};
export default logout;
+5 -6
View File
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -15,14 +15,13 @@ const SRP1 = ({clientPublicKey}) => {
body: JSON.stringify({
clientPublicKey,
}),
})
.then(async res => {
}).then(async (res) => {
if (res.status == 200) {
return (await res.json());
return await res.json();
} else {
console.log('Failed to do the first step of SRP');
console.log("Failed to do the first step of SRP");
}
})
});
};
export default SRP1;
+13 -11
View File
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient.js";
import SecurityClient from "~/utilities/SecurityClient.js";
import { PATH } from "../../../const.js";
/**
@@ -8,26 +8,28 @@ import { PATH } from "../../../const.js";
* @returns
*/
const getSecrets = async (workspaceId, env) => {
return SecurityClient.fetchCall(PATH + "/api/v1/secret/" +
return SecurityClient.fetchCall(
PATH +
"/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');
}
})
).then(async (res) => {
if (res.status == 200) {
return await res.json();
} else {
console.log("Failed to get project secrets");
}
});
};
export default getSecrets;
+4 -5
View File
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -19,14 +19,13 @@ const uploadSecrets = async ({ workspaceId, secrets, keys, environment }) => {
environment,
channel: "web",
}),
})
.then(async res => {
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to push secrets');
console.log("Failed to push secrets");
}
})
});
};
export default uploadSecrets;
@@ -1,8 +1,10 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
const changeHerokuConfigVars = ({ integrationId, key, secrets }) => {
return SecurityClient.fetchCall(PATH + "/api/v1/integration/" + integrationId + "/sync", {
return SecurityClient.fetchCall(
PATH + "/api/v1/integration/" + integrationId + "/sync",
{
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -10,15 +12,15 @@ const changeHerokuConfigVars = ({ integrationId, key, secrets }) => {
body: JSON.stringify({
key,
secrets,
})
})
.then(async res => {
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to sync secrets to Heroku');
console.log("Failed to sync secrets to Heroku");
}
})
});
};
export default changeHerokuConfigVars;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
* @returns
*/
const deleteIntegration = ({ integrationId }) => {
return SecurityClient.fetchCall(PATH + "/api/v1/integration/" + integrationId, {
return SecurityClient.fetchCall(
PATH + "/api/v1/integration/" + integrationId,
{
method: "DELETE",
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 delete an integration');
console.log("Failed to delete an integration");
}
})
});
};
export default deleteIntegration;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
* @returns
*/
const deleteIntegrationAuth = ({ integrationAuthId }) => {
return SecurityClient.fetchCall(PATH + "/api/v1/integration-auth/" + integrationAuthId, {
return SecurityClient.fetchCall(
PATH + "/api/v1/integration-auth/" + integrationAuthId,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to delete an integration authorization');
console.log("Failed to delete an integration authorization");
}
})
});
};
export default deleteIntegrationAuth;
@@ -1,20 +1,22 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
const getIntegrationApps = ({ integrationAuthId }) => {
return SecurityClient.fetchCall(PATH + "/api/v1/integration-auth/" + integrationAuthId + "/apps", {
return SecurityClient.fetchCall(
PATH + "/api/v1/integration-auth/" + integrationAuthId + "/apps",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).apps;
} else {
console.log('Failed to get available apps for an integration');
console.log("Failed to get available apps for an integration");
}
})
});
};
export default getIntegrationApps;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
const getIntegrations = () => {
@@ -7,14 +7,13 @@ const getIntegrations = () => {
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}).then(async (res) => {
if (res.status == 200) {
return (await res.json()).integrations;
} else {
console.log('Failed to get project integrations');
console.log("Failed to get project integrations");
}
})
});
};
export default getIntegrations;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,26 +7,28 @@ import { PATH } from "../../../const";
* @returns
*/
const startIntegration = ({ integrationId, appName, environment }) => {
return SecurityClient.fetchCall(PATH + "/api/v1/integration/" + integrationId, {
return SecurityClient.fetchCall(
PATH + "/api/v1/integration/" + integrationId,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"update": {
update: {
app: appName,
environment,
isActive: true
isActive: true,
},
}),
}
})
})
.then(async res => {
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to start an integration');
console.log("Failed to start an integration");
}
})
});
};
export default startIntegration;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,7 +7,9 @@ import { PATH } from "../../../const";
* @returns
*/
const AuthorizeIntegration = ({ workspaceId, code, integration }) => {
return SecurityClient.fetchCall(PATH + "/api/v1/integration-auth/oauth-token", {
return SecurityClient.fetchCall(
PATH + "/api/v1/integration-auth/oauth-token",
{
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -15,16 +17,16 @@ const AuthorizeIntegration = ({ workspaceId, code, integration }) => {
body: JSON.stringify({
workspaceId,
code,
integration
integration,
}),
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to authorize the integration');
console.log("Failed to authorize the integration");
}
})
});
};
export default AuthorizeIntegration;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
* @returns
*/
const getWorkspaceAuthorizations = ({ workspaceId }) => {
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + workspaceId + "/authorizations", {
return SecurityClient.fetchCall(
PATH + "/api/v1/workspace/" + workspaceId + "/authorizations",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).authorizations;
} else {
console.log('Failed to get project authorizations');
console.log("Failed to get project authorizations");
}
})
});
};
export default getWorkspaceAuthorizations;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
* @returns
*/
const getWorkspaceIntegrations = ({ workspaceId }) => {
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + workspaceId + "/integrations", {
return SecurityClient.fetchCall(
PATH + "/api/v1/workspace/" + workspaceId + "/integrations",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).integrations;
} else {
console.log('Failed to get the project integrations');
console.log("Failed to get the project integrations");
}
})
});
};
export default getWorkspaceIntegrations;
+8 -6
View File
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
* @returns
*/
const getOrganization = (req, res) => {
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + req.orgId, {
return SecurityClient.fetchCall(
PATH + "/api/v1/organization/" + req.orgId,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).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");
}
})
});
};
export default getOrganization;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
* @returns
*/
const getOrganizationProjects = (req, res) => {
return SecurityClient.fetchCall(PATH + "/api/organization/" + req.orgId + "/workspaces", {
return SecurityClient.fetchCall(
PATH + "/api/organization/" + req.orgId + "/workspaces",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).workspaces;
} else {
console.log('Failed to get projects for an org');
console.log("Failed to get projects for an org");
}
})
});
};
export default getOrganizationProjects;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
* @returns
*/
const getOrganizationSubscriptions = (req, res) => {
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + req.orgId + "/subscriptions", {
return SecurityClient.fetchCall(
PATH + "/api/v1/organization/" + req.orgId + "/subscriptions",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).subscriptions;
} else {
console.log('Failed to get org subscriptions');
console.log("Failed to get org subscriptions");
}
})
});
};
export default getOrganizationSubscriptions;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
* @returns
*/
const getOrganizationUserProjects = (req, res) => {
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + req.orgId + "/my-workspaces", {
return SecurityClient.fetchCall(
PATH + "/api/v1/organization/" + req.orgId + "/my-workspaces",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).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');
console.log("Failed to get projects of a user in an org");
}
})
});
};
export default getOrganizationUserProjects;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
* @returns
*/
const getOrganizationUsers = (req, res) => {
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + req.orgId + "/users", {
return SecurityClient.fetchCall(
PATH + "/api/v1/organization/" + req.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");
}
})
});
};
export default getOrganizationUsers;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
* @returns
*/
const StripeRedirect = ({ orgId }) => {
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + orgId + "/customer-portal-session", {
return SecurityClient.fetchCall(
PATH + "/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');
}
})
).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;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,7 +7,9 @@ import { PATH } from "../../../const";
* @returns
*/
const addIncidentContact = (organizationId, email) => {
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + organizationId + "/incidentContactOrg", {
return SecurityClient.fetchCall(
PATH + "/api/v1/organization/" + organizationId + "/incidentContactOrg",
{
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -15,14 +17,14 @@ const addIncidentContact = (organizationId, email) => {
body: JSON.stringify({
email: email,
}),
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to add an incident contact');
console.log("Failed to add an incident contact");
}
})
});
};
export default addIncidentContact;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -17,14 +17,13 @@ const addUserToOrg = (email, orgId) => {
inviteeEmail: email,
organizationId: orgId,
}),
})
.then(async res => {
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to add a user to an org');
console.log("Failed to add a user to an org");
}
})
});
};
export default addUserToOrg;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,7 +7,9 @@ import { PATH } from "../../../const";
* @returns
*/
const deleteIncidentContact = (organizaionId, email) => {
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + organizaionId + "/incidentContactOrg", {
return SecurityClient.fetchCall(
PATH + "/api/v1/organization/" + organizaionId + "/incidentContactOrg",
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
@@ -15,14 +17,14 @@ const deleteIncidentContact = (organizaionId, email) => {
body: JSON.stringify({
email: email,
}),
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to delete an incident contact');
console.log("Failed to delete an incident contact");
}
})
});
};
export default deleteIncidentContact;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
* @returns
*/
const deleteUserFromOrganization = (membershipId) => {
return SecurityClient.fetchCall(PATH + "/api/v1/membership-org/" + membershipId, {
return SecurityClient.fetchCall(
PATH + "/api/v1/membership-org/" + membershipId,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to delete a user from an org');
console.log("Failed to delete a user from an org");
}
})
});
};
export default deleteUserFromOrganization;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
* @returns
*/
const getIncidentContacts = (organizationId) => {
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + organizationId + "/incidentContactOrg", {
return SecurityClient.fetchCall(
PATH + "/api/v1/organization/" + organizationId + "/incidentContactOrg",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).incidentContactsOrg;
} else {
console.log('Failed to get incident contacts');
console.log("Failed to get incident contacts");
}
})
});
};
export default getIncidentContacts;
+4 -5
View File
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -13,14 +13,13 @@ const getOrganizations = (req, res) => {
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}).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");
}
})
});
};
export default getOrganizations;
+8 -6
View File
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,7 +8,9 @@ import { PATH } from "../../../const";
* @returns
*/
const renameOrg = (orgId, newOrgName) => {
return SecurityClient.fetchCall(PATH + "/api/v1/organization/" + orgId + "/name", {
return SecurityClient.fetchCall(
PATH + "/api/v1/organization/" + orgId + "/name",
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
@@ -16,14 +18,14 @@ const renameOrg = (orgId, newOrgName) => {
body: JSON.stringify({
name: newOrgName,
}),
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to rename an organization');
console.log("Failed to rename an organization");
}
})
});
};
export default renameOrg;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -6,7 +6,15 @@ import { PATH } from "../../../const";
* @param {*} param0
* @returns
*/
const addServiceToken = ({name, workspaceId, environment, expiresIn, publicKey, encryptedKey, nonce}) => {
const addServiceToken = ({
name,
workspaceId,
environment,
expiresIn,
publicKey,
encryptedKey,
nonce,
}) => {
return SecurityClient.fetchCall(PATH + "/api/v1/service-token/", {
method: "POST",
headers: {
@@ -19,16 +27,15 @@ const addServiceToken = ({name, workspaceId, environment, expiresIn, publicKey,
expiresIn,
publicKey,
encryptedKey,
nonce
})
})
.then(async res => {
nonce,
}),
}).then(async (res) => {
if (res.status == 200) {
return (await res.json()).token;
} else {
console.log('Failed to add service tokens');
console.log("Failed to add service tokens");
}
})
});
};
export default addServiceToken;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
* @returns
*/
const getServiceTokens = ({ workspaceId }) => {
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + workspaceId + "/service-tokens", {
return SecurityClient.fetchCall(
PATH + "/api/v1/workspace/" + workspaceId + "/service-tokens",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).serviceTokens;
} else {
console.log('Failed to get service tokens');
console.log("Failed to get service tokens");
}
})
});
};
export default getServiceTokens;
+4 -5
View File
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -13,14 +13,13 @@ const getUser = (req, res) => {
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}).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");
}
})
});
};
export default getUser;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,23 +8,26 @@ import { PATH } from "../../../const";
* @returns
*/
const checkUserAction = ({ action }) => {
return SecurityClient.fetchCall(PATH + "/api/v1/user-action" +
return SecurityClient.fetchCall(
PATH +
"/api/v1/user-action" +
"?" +
new URLSearchParams({
action,
}), {
}),
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).then(async (res) => {
if (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");
}
})
});
};
export default checkUserAction;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -15,14 +15,13 @@ const registerUserAction = ({ action }) => {
body: JSON.stringify({
action,
}),
})
.then(async res => {
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to register a user action');
console.log("Failed to register a user action");
}
})
});
};
export default registerUserAction;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,7 +8,9 @@ import { PATH } from "../../../const";
* @returns
*/
const addUserToWorkspace = (email, workspaceId) => {
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + workspaceId + "/invite-signup", {
return SecurityClient.fetchCall(
PATH + "/api/v1/workspace/" + workspaceId + "/invite-signup",
{
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -16,14 +18,14 @@ const addUserToWorkspace = (email, workspaceId) => {
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');
}
})
).then(async (res) => {
if (res.status == 200) {
return await res.json();
} else {
console.log("Failed to add a user to project");
}
});
};
export default addUserToWorkspace;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,7 +8,9 @@ import { PATH } from "../../../const";
* @returns
*/
const changeUserRoleInWorkspace = (membershipId, role) => {
return SecurityClient.fetchCall(PATH + "/api/v1/membership/" + membershipId + "/change-role", {
return SecurityClient.fetchCall(
PATH + "/api/v1/membership/" + membershipId + "/change-role",
{
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -16,14 +18,14 @@ const changeUserRoleInWorkspace = (membershipId, role) => {
body: JSON.stringify({
role: role,
}),
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to change the user role in a project');
console.log("Failed to change the user role in a project");
}
})
});
};
export default changeUserRoleInWorkspace;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -16,14 +16,13 @@ const createWorkspace = (workspaceName, organizationId) => {
workspaceName: workspaceName,
organizationId: organizationId,
}),
})
.then(async res => {
}).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");
}
})
});
};
export default createWorkspace;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,19 +7,21 @@ import { PATH } from "../../../const";
* @returns
*/
const deleteUserFromWorkspace = (membershipId) => {
return SecurityClient.fetchCall(PATH + "/api/v1/membership/" + membershipId, {
return SecurityClient.fetchCall(
PATH + "/api/v1/membership/" + membershipId,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to delete a user from a project');
console.log("Failed to delete a user from a project");
}
})
});
};
export default deleteUserFromWorkspace;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -12,14 +12,13 @@ const deleteWorkspace = (workspaceId) => {
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to delete a project');
console.log("Failed to delete a project");
}
})
});
};
export default deleteWorkspace;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -7,19 +7,23 @@ import { PATH } from "../../../const";
* @returns
*/
const getLatestFileKey = (workspaceId) => {
return SecurityClient.fetchCall(PATH + "/api/v1/key/" + workspaceId + "/latest", {
return SecurityClient.fetchCall(
PATH + "/api/v1/key/" + workspaceId + "/latest",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.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');
}
})
).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"
);
}
});
};
export default getLatestFileKey;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
* @returns
*/
const getWorkspaceInfo = (req, res) => {
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + req.workspaceId, {
return SecurityClient.fetchCall(
PATH + "/api/v1/workspace/" + req.workspaceId,
{
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");
}
})
});
};
export default getWorkspaceInfo;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,19 +8,23 @@ import { PATH } from "../../../const";
* @returns
*/
const getWorkspaceKeys = (req, res) => {
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + req.workspaceId + "/keys", {
return SecurityClient.fetchCall(
PATH + "/api/v1/workspace/" + req.workspaceId + "/keys",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).publicKeys;
} else {
console.log('Failed to get the public keys of everyone in the workspace');
console.log(
"Failed to get the public keys of everyone in the workspace"
);
}
})
});
};
export default getWorkspaceKeys;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,19 +8,21 @@ import { PATH } from "../../../const";
* @returns
*/
const getWorkspaceUsers = (req, res) => {
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + req.workspaceId + "/users", {
return SecurityClient.fetchCall(
PATH + "/api/v1/workspace/" + req.workspaceId + "/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 Project Users');
console.log("Failed to get Project Users");
}
})
});
};
export default getWorkspaceUsers;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -13,14 +13,13 @@ const getWorkspaces = (req, res) => {
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
}).then(async (res) => {
if (res.status == 200) {
return (await res.json()).workspaces;
} else {
console.log('Failed to get projects');
console.log("Failed to get projects");
}
})
});
};
export default getWorkspaces;
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -8,7 +8,9 @@ import { PATH } from "../../../const";
* @returns
*/
const renameWorkspace = (workspaceId, newWorkspaceName) => {
return SecurityClient.fetchCall(PATH + "/api/v1/workspace/" + workspaceId + "/name", {
return SecurityClient.fetchCall(
PATH + "/api/v1/workspace/" + workspaceId + "/name",
{
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -16,14 +18,14 @@ const renameWorkspace = (workspaceId, newWorkspaceName) => {
body: JSON.stringify({
name: newWorkspaceName,
}),
})
.then(async res => {
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to rename a project');
console.log("Failed to rename a project");
}
})
});
};
export default renameWorkspace;
+4 -5
View File
@@ -1,4 +1,4 @@
import SecurityClient from "../../../components/utilities/SecurityClient";
import SecurityClient from "~/utilities/SecurityClient";
import { PATH } from "../../../const";
/**
@@ -22,14 +22,13 @@ const uploadKeys = (workspaceId, userId, encryptedKey, nonce) => {
nonce: nonce,
},
}),
})
.then(async res => {
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log('Failed to upload keys for a new user');
console.log("Failed to upload keys for a new user");
}
})
});
};
export default uploadKeys;
+137 -70
View File
@@ -2,14 +2,14 @@ import React, { useState, useEffect, useCallback, Fragment } from "react";
import { useRouter } from "next/router";
import Head from "next/head";
import Image from "next/image";
import guidGenerator from "../../components/utilities/randomId";
import getSecretsForProject from "../../components/utilities/getSecretsForProject";
import pushKeys from "../../components/utilities/pushKeys";
import guidGenerator from "~/utilities/randomId";
import getSecretsForProject from "~/utilities/getSecretsForProject";
import pushKeys from "~/utilities/pushKeys";
import getWorkspaces from "../api/workspace/getWorkspaces";
import getUser from "../api/user/getUser";
import NavHeader from "../../components/navigation/NavHeader";
import NavHeader from "~/components/navigation/NavHeader";
import DashboardInputField from "../../components/dashboard/DashboardInputField";
import DashboardInputField from "~/components/dashboard/DashboardInputField";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faMagnifyingGlass,
@@ -26,19 +26,26 @@ import {
faCheck,
faCopy,
faCircleInfo,
faX
faX,
} from "@fortawesome/free-solid-svg-icons";
import ListBox from "../../components/basic/Listbox";
import DropZone from "../../components/dashboard/DropZone";
import ListBox from "~/components/basic/Listbox";
import DropZone from "~/components/dashboard/DropZone";
import { Menu, Transition } from "@headlessui/react";
import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations";
import BottonRightPopup from "../../components/basic/popups/BottomRightPopup";
import BottonRightPopup from "~/components/basic/popups/BottomRightPopup";
import checkUserAction from "../api/userActions/checkUserAction";
import registerUserAction from "../api/userActions/registerUserAction";
import pushKeysIntegration from "../../components/utilities/pushKeysIntegration";
import Button from "../../components/basic/buttons/Button";
import pushKeysIntegration from "~/utilities/pushKeysIntegration";
import Button from "~/components/basic/buttons/Button";
const KeyPair = ({ keyPair, deleteRow, modifyKey, modifyValue, modifyVisibility, isBlurred }) => {
const KeyPair = ({
keyPair,
deleteRow,
modifyKey,
modifyValue,
modifyVisibility,
isBlurred,
}) => {
return (
<div className="px-1 flex flex-col items-center ml-1">
<div className="relative flex flex-row justify-between w-full max-w-5xl mr-auto max-h-10 my-1 items-center px-2">
@@ -86,9 +93,12 @@ const KeyPair = ({ keyPair, deleteRow, modifyKey, modifyValue, modifyVisibility,
<Menu.Items className="absolute right-0 mt-0.5 w-44 origin-top-right rounded-md bg-bunker border border-mineshaft-700 shadow-lg ring-1 ring-black z-20 ring-opacity-5 focus:outline-none px-1 py-1">
<div
onClick={() =>
modifyVisibility(keyPair[4] == "personal"
modifyVisibility(
keyPair[4] == "personal"
? "shared"
: "personal", keyPair[1])
: "personal",
keyPair[1]
)
}
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"
>
@@ -123,7 +133,6 @@ const KeyPair = ({ keyPair, deleteRow, modifyKey, modifyValue, modifyVisibility,
);
};
const envMapping = {
Development: "dev",
Staging: "staging",
@@ -186,7 +195,6 @@ export default function Dashboard() {
};
}, [buttonReady]);
const reorderRows = () => {
setSortMethod(
sortMethod == "alphabetical" ? "-alphabetical" : "alphabetical"
@@ -218,21 +226,21 @@ export default function Dashboard() {
setFileState,
setIsKeyAvailable,
setData,
workspaceId: router.query.id
})
workspaceId: router.query.id,
});
const user = await getUser();
setIsNew(
(Date.parse(new Date()) -
Date.parse(user.createdAt)) /
60000 <
(Date.parse(new Date()) - Date.parse(user.createdAt)) / 60000 <
3
? true
: false
);
let userAction = await checkUserAction({action: "first_time_secrets_pushed"});
setHasUserEverPushed(userAction ? true : false)
let userAction = await checkUserAction({
action: "first_time_secrets_pushed",
});
setHasUserEverPushed(userAction ? true : false);
} catch (error) {
console.log("Error", error);
setData([]);
@@ -252,39 +260,38 @@ export default function Dashboard() {
const modifyValue = (value, id) => {
setData((oldData) => {
oldData[id][3] = value;
return [...oldData]
return [...oldData];
});
setButtonReady(true);
}
};
const modifyKey = (value, id) => {
setData((oldData) => {
oldData[id][2] = value;
return [...oldData]
return [...oldData];
});
setButtonReady(true);
}
};
const modifyVisibility = (value, id) => {
setData((oldData) => {
oldData[id][4] = value;
return [...oldData]
return [...oldData];
});
setButtonReady(true);
}
};
const listenChangeValue = useCallback((value, id) => {
modifyValue(value, id)
}, [])
modifyValue(value, id);
}, []);
const listenChangeKey = useCallback((value, id) => {
modifyKey(value, id)
}, [])
modifyKey(value, id);
}, []);
const listenChangeVisibility = useCallback((value, id) => {
modifyVisibility(value, id)
}, [])
modifyVisibility(value, id);
}, []);
const savePush = async () => {
let obj = Object.assign(
@@ -294,18 +301,27 @@ export default function Dashboard() {
setButtonReady(false);
pushKeys(obj, router.query.id, env);
let integrations = await getWorkspaceIntegrations({workspaceId: router.query.id});
let integrations = await getWorkspaceIntegrations({
workspaceId: router.query.id,
});
integrations.map(async (integration) => {
if (envMapping[env] == integration.environment && integration.isActive == true) {
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});}
await pushKeysIntegration({
obj: objIntegration,
integrationId: integration._id,
});
}
});
if (!hasUserEverPushed) {
setCheckDocsPopUpVisible(true)
setCheckDocsPopUpVisible(true);
await registerUserAction({ action: "first_time_secrets_pushed" });
}
};
@@ -353,7 +369,6 @@ export default function Dashboard() {
// alert("Copied the text: " + copyText.value);
}
return data ? (
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
<Head>
@@ -372,7 +387,7 @@ export default function Dashboard() {
<div className="flex flex-row">
<div className="w-full max-h-96 pb-2">
<NavHeader pageName="Secrets" isProjectRelated={true} />
{checkDocsPopUpVisible &&
{checkDocsPopUpVisible && (
<BottonRightPopup
buttonText="Check Docs"
buttonLink="https://infisical.com/docs/getting-started/introduction"
@@ -382,11 +397,12 @@ export default function Dashboard() {
textLine2="Here is how to connect them to your codebase."
setCheckDocsPopUpVisible={setCheckDocsPopUpVisible}
/>
}
)}
<div className="flex flex-row justify-between items-center mx-6 mt-6 mb-3 text-xl max-w-5xl">
<div className="flex flex-row justify-start items-center text-3xl">
<p className="font-semibold mr-4 mt-1">Secrets</p>
{data?.length==0 && <ListBox
{data?.length == 0 && (
<ListBox
selected={env}
data={[
"Development",
@@ -397,15 +413,34 @@ export default function Dashboard() {
// ref={useRef(123)}
onChange={setEnv}
className="z-40"
/>}
/>
)}
</div>
<div className="flex flex-row">
<div className="flex justify-end items-center bg-white/[0.07] text-base mt-2 mr-2 rounded-md text-gray-400">
<p className="mr-2 font-bold pl-4">Project ID:</p>
<input type="text" value={workspaceId} id="myInput" className="bg-white/0 text-gray-400 py-2 w-60 px-2 min-w-md outline-none" disabled></input>
<p className="mr-2 font-bold pl-4">
Project ID:
</p>
<input
type="text"
value={workspaceId}
id="myInput"
className="bg-white/0 text-gray-400 py-2 w-60 px-2 min-w-md outline-none"
disabled
></input>
<div className="group font-normal group relative inline-block text-gray-400 underline hover:text-primary duration-200">
<button onClick={copyToClipboard} className="pl-4 pr-4 border-l border-white/20 py-2 hover:bg-white/[0.12] duration-200">
{projectIdCopied ? <FontAwesomeIcon icon={faCheck} className="pr-0.5"/> : <FontAwesomeIcon icon={faCopy} />}
<button
onClick={copyToClipboard}
className="pl-4 pr-4 border-l border-white/20 py-2 hover:bg-white/[0.12] duration-200"
>
{projectIdCopied ? (
<FontAwesomeIcon
icon={faCheck}
className="pr-0.5"
/>
) : (
<FontAwesomeIcon icon={faCopy} />
)}
</button>
<span className="absolute hidden group-hover:flex group-hover:animate-popup duration-300 w-28 -left-8 -top-20 translate-y-full pl-3 py-2 bg-white/10 rounded-md text-center text-gray-400 text-sm">
Click to Copy
@@ -455,7 +490,9 @@ export default function Dashboard() {
className="pl-2 text-gray-400 rounded-r-md bg-white/5 w-full h-full outline-none"
value={searchKeys}
onChange={(e) =>
setSearchKeys(e.target.value)
setSearchKeys(
e.target.value
)
}
placeholder={"Search keys..."}
/>
@@ -465,7 +502,11 @@ export default function Dashboard() {
onButtonPressed={reorderRows}
color="mineshaft"
size="icon-md"
icon={sortMethod == "alphabetical" ? faArrowDownAZ : faArrowDownZA}
icon={
sortMethod == "alphabetical"
? faArrowDownAZ
: faArrowDownZA
}
/>
</div>
<div className="ml-2 min-w-max flex flex-row items-start justify-start">
@@ -481,7 +522,9 @@ export default function Dashboard() {
onButtonPressed={changeBlurred}
color="mineshaft"
size="icon-md"
icon={blurred ? faEye : faEyeSlash}
icon={
blurred ? faEye : faEyeSlash
}
/>
</div>
<div className="relative ml-2 min-w-max flex flex-row items-start justify-end">
@@ -514,14 +557,17 @@ export default function Dashboard() {
<div className="rounded-t-md sticky top-0 z-20 bg-bunker flex flex-row pl-4 pr-6 pt-4 pb-2 items-center justify-between text-gray-300 font-bold">
{/* <FontAwesomeIcon icon={faAngleDown} /> */}
<div className="flex flex-row items-center">
<p className="pl-2 text-lg">Personal</p>
<p className="pl-2 text-lg">
Personal
</p>
<div className="group font-normal group relative inline-block text-gray-300 underline hover:text-primary duration-200">
<FontAwesomeIcon
className="ml-3 mt-1 text-lg"
icon={faCircleInfo}
/>
<span className="absolute hidden group-hover:flex group-hover:animate-popdown duration-300 w-44 -left-16 -top-7 translate-y-full px-2 py-2 bg-gray-700 rounded-md text-center text-gray-100 text-sm after:content-[''] after:absolute after:left-1/2 after:bottom-[100%] after:-translate-x-1/2 after:border-8 after:border-x-transparent after:border-t-transparent after:border-b-gray-700">
Personal keys are only visible to you
Personal keys are only
visible to you
</span>
</div>
</div>
@@ -534,7 +580,8 @@ export default function Dashboard() {
.toLowerCase()
.includes(
searchKeys.toLowerCase()
) && keyPair[4] == "personal"
) &&
keyPair[4] == "personal"
)
.sort((a, b) =>
sortMethod == "alphabetical"
@@ -546,9 +593,13 @@ export default function Dashboard() {
key={keyPair[0]}
keyPair={keyPair}
deleteRow={deleteCertainRow}
modifyValue={listenChangeValue}
modifyValue={
listenChangeValue
}
modifyKey={listenChangeKey}
modifyVisibility={listenChangeVisibility}
modifyVisibility={
listenChangeVisibility
}
isBlurred={blurred}
/>
))}
@@ -562,15 +613,17 @@ export default function Dashboard() {
<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">
{/* <FontAwesomeIcon icon={faAngleDown} /> */}
<div className="flex flex-row items-center">
<p className="pl-2 text-lg">Shared</p>
<p className="pl-2 text-lg">
Shared
</p>
<div className="group font-normal group relative inline-block text-gray-300 underline hover:text-primary duration-200">
<FontAwesomeIcon
className="ml-3 text-lg mt-1"
icon={faCircleInfo}
/>
<span className="absolute hidden group-hover:flex group-hover:animate-popdown duration-300 w-44 -left-16 -top-7 translate-y-full px-2 py-2 bg-gray-700 rounded-md text-center text-gray-100 text-sm after:content-[''] after:absolute after:left-1/2 after:bottom-[100%] after:-translate-x-1/2 after:border-8 after:border-x-transparent after:border-t-transparent after:border-b-gray-700">
Shared keys are visible to your whole
team
Shared keys are visible to
your whole team
</span>
</div>
</div>
@@ -583,7 +636,8 @@ export default function Dashboard() {
.toLowerCase()
.includes(
searchKeys.toLowerCase()
) && keyPair[4] == "shared"
) &&
keyPair[4] == "shared"
)
.sort((a, b) =>
sortMethod == "alphabetical"
@@ -595,9 +649,13 @@ export default function Dashboard() {
key={keyPair[0]}
keyPair={keyPair}
deleteRow={deleteCertainRow}
modifyValue={listenChangeValue}
modifyValue={
listenChangeValue
}
modifyKey={listenChangeKey}
modifyVisibility={listenChangeVisibility}
modifyVisibility={
listenChangeVisibility
}
isBlurred={blurred}
/>
))}
@@ -606,7 +664,9 @@ export default function Dashboard() {
<div className="w-full max-w-5xl">
<DropZone
setData={addData}
setErrorDragAndDrop={setErrorDragAndDrop}
setErrorDragAndDrop={
setErrorDragAndDrop
}
createNewFile={addRow}
errorDragAndDrop={errorDragAndDrop}
setButtonReady={setButtonReady}
@@ -617,19 +677,23 @@ export default function Dashboard() {
</div>
) : (
<div className="flex flex-col items-center justify-center h-full text-xl text-gray-400 max-w-5xl mt-28">
{fileState.message != "There's nothing to pull" &&
{fileState.message !=
"There's nothing to pull" &&
fileState.message != undefined && (
<FontAwesomeIcon
className="text-7xl mb-8"
icon={faFolderOpen}
/>
)}
{(fileState.message == "There's nothing to pull" ||
{(fileState.message ==
"There's nothing to pull" ||
fileState.message == undefined) &&
isKeyAvailable && (
<DropZone
setData={setData}
setErrorDragAndDrop={setErrorDragAndDrop}
setErrorDragAndDrop={
setErrorDragAndDrop
}
createNewFile={addRow}
errorDragAndDrop={errorDragAndDrop}
setButtonReady={setButtonReady}
@@ -638,7 +702,10 @@ export default function Dashboard() {
)}
{fileState.message ==
"Failed membership validation for workspace" && (
<p>You are not authorized to view this project.</p>
<p>
You are not authorized to view this
project.
</p>
)}
{fileState.message ==
"Access needed to pull the latest file" ||
@@ -653,8 +720,8 @@ export default function Dashboard() {
administrator for permission.
</p>
<p className="mt-1">
They need to grant you access in the team
tab.
They need to grant you access in
the team tab.
</p>
</>
))}
+231 -76
View File
@@ -3,20 +3,25 @@ import { useRouter } from "next/router";
import Head from "next/head";
import Image from "next/image";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCheck, faArrowRight, faRotate, faX } from "@fortawesome/free-solid-svg-icons";
import ListBox from "../../components/basic/Listbox";
import NavHeader from "../../components/navigation/NavHeader";
import {
faCheck,
faArrowRight,
faRotate,
faX,
} from "@fortawesome/free-solid-svg-icons";
import ListBox from "~/components/basic/Listbox";
import NavHeader from "~/components/navigation/NavHeader";
import getIntegrations from "../api/integrations/GetIntegrations";
import getIntegrationApps from "../api/integrations/GetIntegrationApps";
import getWorkspaceAuthorizations from "../api/integrations/getWorkspaceAuthorizations";
import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations";
import startIntegration from "../api/integrations/StartIntegration";
import deleteIntegration from "../api/integrations/DeleteIntegration";
import getSecretsForProject from "../../components/utilities/getSecretsForProject";
import pushKeysIntegration from "../../components/utilities/pushKeysIntegration";
import getSecretsForProject from "~/utilities/getSecretsForProject";
import pushKeysIntegration from "~/utilities/pushKeysIntegration";
import deleteIntegrationAuth from "../api/integrations/DeleteIntegrationAuth";
import Button from "../../components/basic/buttons/Button";
import guidGenerator from "../../components/utilities/randomId";
import Button from "~/components/basic/buttons/Button";
import guidGenerator from "~/utilities/randomId";
const crypto = require("crypto");
@@ -28,30 +33,40 @@ const envMapping = {
};
const reverseEnvMapping = {
"dev": "Development",
"staging": "Staging",
"prod": "Production",
"test": "Testing"
}
dev: "Development",
staging: "Staging",
prod: "Production",
test: "Testing",
};
const Integration = ({ projectIntegration }) => {
const [integrationEnvironment, setIntegrationEnvironment] = useState(reverseEnvMapping[projectIntegration.environment]);
const [integrationEnvironment, setIntegrationEnvironment] = useState(
reverseEnvMapping[projectIntegration.environment]
);
const [fileState, setFileState] = useState([]);
const [data, setData] = useState();
const [isKeyAvailable, setIsKeyAvailable] = useState(true);
const router = useRouter();
const [apps, setApps] = useState([]);
const [integrationApp, setIntegrationApp] = useState(projectIntegration.app ? projectIntegration.app : apps[0]);
const [integrationApp, setIntegrationApp] = useState(
projectIntegration.app ? projectIntegration.app : apps[0]
);
useEffect(async () => {
const tempHerokuApps = await getIntegrationApps({integrationAuthId: projectIntegration.integrationAuth});
const tempHerokuAppNames = tempHerokuApps.map(app => app.name);
const tempHerokuApps = await getIntegrationApps({
integrationAuthId: projectIntegration.integrationAuth,
});
const tempHerokuAppNames = tempHerokuApps.map((app) => app.name);
setApps(tempHerokuAppNames);
setIntegrationApp(projectIntegration.app ? projectIntegration.app : tempHerokuAppNames[0])
setIntegrationApp(
projectIntegration.app
? projectIntegration.app
: tempHerokuAppNames[0]
);
}, []);
return <div className="flex flex-col max-w-5xl justify-center bg-white/5 p-6 rounded-md mx-6 mt-8">
return (
<div className="flex flex-col max-w-5xl justify-center bg-white/5 p-6 rounded-md mx-6 mt-8">
<div className="relative px-4 flex flex-row items-center justify-between mb-4">
<div className="flex flex-row">
<div>
@@ -59,7 +74,13 @@ const Integration = ({projectIntegration}) => {
ENVIRONMENT
</div>
<ListBox
data={!projectIntegration.isActive && ["Development", "Staging", "Production"]}
data={
!projectIntegration.isActive && [
"Development",
"Staging",
"Production",
]
}
selected={integrationEnvironment}
onChange={setIntegrationEnvironment}
/>
@@ -73,7 +94,10 @@ const Integration = ({projectIntegration}) => {
INTEGRATION
</div>
<div className="py-2.5 bg-white/[.07] rounded-md pl-4 pr-20 text-sm font-semibold text-gray-300">
{projectIntegration.integration.charAt(0).toUpperCase() + projectIntegration.integration.slice(1)}
{projectIntegration.integration
.charAt(0)
.toUpperCase() +
projectIntegration.integration.slice(1)}
</div>
</div>
<div>
@@ -88,44 +112,59 @@ const Integration = ({projectIntegration}) => {
</div>
</div>
<div className="flex flex-row mt-6">
{projectIntegration.isActive
? <div className="max-w-5xl flex flex-row items-center bg-white/5 p-2 rounded-md px-4">
<FontAwesomeIcon icon={faRotate} className="text-lg mr-2.5 text-primary animate-spin"/>
<div className="text-gray-300 font-semibold">In Sync</div>
{projectIntegration.isActive ? (
<div className="max-w-5xl flex flex-row items-center bg-white/5 p-2 rounded-md px-4">
<FontAwesomeIcon
icon={faRotate}
className="text-lg mr-2.5 text-primary animate-spin"
/>
<div className="text-gray-300 font-semibold">
In Sync
</div>
: <Button
</div>
) : (
<Button
text="Start Integration"
onButtonPressed={async () => {
const result = await startIntegration({
"integrationId": projectIntegration._id,
"environment": envMapping[integrationEnvironment],
"appName": integrationApp
})
integrationId: projectIntegration._id,
environment:
envMapping[integrationEnvironment],
appName: integrationApp,
});
if (result?.status == 200) {
let currentSecrets = await getSecretsForProject({
let currentSecrets =
await getSecretsForProject({
env: integrationEnvironment,
setFileState,
setIsKeyAvailable,
setData,
workspaceId: router.query.id
})
workspaceId: router.query.id,
});
let obj = Object.assign(
{},
...currentSecrets.map((row) => ({ [row[2]]: row[3] }))
...currentSecrets.map((row) => ({
[row[2]]: row[3],
}))
);
await pushKeysIntegration({obj, integrationId: projectIntegration._id});
await pushKeysIntegration({
obj,
integrationId: projectIntegration._id,
});
router.reload();
}
}}
color="mineshaft"
size="md"
/>
}
)}
<div className="opacity-50 hover:opacity-100 duration-200 ml-2">
<Button
onButtonPressed={async () => {
await deleteIntegration({integrationId: projectIntegration._id});
await deleteIntegration({
integrationId: projectIntegration._id,
});
router.reload();
}}
color="red"
@@ -135,8 +174,9 @@ const Integration = ({projectIntegration}) => {
</div>
</div>
</div>
</div>;
}
</div>
);
};
export default function Integrations() {
const [integrations, setIntegrations] = useState();
@@ -150,10 +190,14 @@ export default function Integrations() {
setCsrfToken(tempCSRFToken);
localStorage.setItem("latestCSRFToken", tempCSRFToken);
let projectAuthorizations = await getWorkspaceAuthorizations({workspaceId: router.query.id});
let projectAuthorizations = await getWorkspaceAuthorizations({
workspaceId: router.query.id,
});
setAuthorizations(projectAuthorizations);
const projectIntegrations = await getWorkspaceIntegrations({workspaceId: router.query.id});
const projectIntegrations = await getWorkspaceIntegrations({
workspaceId: router.query.id,
});
setProjectIntegrations(projectIntegrations);
try {
@@ -181,7 +225,10 @@ export default function Integrations() {
</Head>
<div className="flex flex-row">
<div className="w-full max-h-96 pb-2 h-screen max-h-[calc(100vh-10px)] overflow-y-scroll no-scrollbar no-scrollbar::-webkit-scrollbar">
<NavHeader pageName="Project Integrations" isProjectRelated={true}/>
<NavHeader
pageName="Project Integrations"
isProjectRelated={true}
/>
<div className="flex flex-col justify-between items-start mx-4 mt-6 mb-4 text-xl max-w-5xl px-2">
<div className="flex flex-row justify-start items-center text-3xl">
<p className="font-semibold mr-4">
@@ -189,24 +236,31 @@ export default function Integrations() {
</p>
</div>
<p className="mr-4 text-base text-gray-400">
Manage your integrations of Infisical with third-party services.
Manage your integrations of Infisical with
third-party services.
</p>
</div>
{projectIntegrations.length > 0
? projectIntegrations.map(projectIntegration =>
<Integration key={guidGenerator()} projectIntegration={projectIntegration} />
)
: <div className="flex flex-col max-w-5xl justify-center bg-white/5 p-6 rounded-md mx-6 mt-8">
{projectIntegrations.length > 0 ? (
projectIntegrations.map((projectIntegration) => (
<Integration
key={guidGenerator()}
projectIntegration={projectIntegration}
/>
))
) : (
<div className="flex flex-col max-w-5xl justify-center bg-white/5 p-6 rounded-md mx-6 mt-8">
<div className="relative px-4 flex flex-col text-gray-400 items-center justify-center">
<div className="mb-1">
You don't have any integrations set up yet. When you do, they will appear here.
You don't have any integrations set up yet.
When you do, they will appear here.
</div>
<div className="">
To start, click on any of the options below. It takes 5 clicks to set up.
To start, click on any of the options below.
It takes 5 clicks to set up.
</div>
</div>
</div>
}
)}
<div className="flex flex-col justify-between items-start mx-4 mt-12 mb-4 text-xl max-w-5xl px-2">
<div className="flex flex-row justify-start items-center text-3xl">
<p className="font-semibold mr-4">
@@ -214,50 +268,151 @@ export default function Integrations() {
</p>
</div>
<p className="mr-4 text-base text-gray-400">
Click on the itegration you want to connect. This will let your environment variables flow automatically into selected third-party services.
Click on the itegration you want to connect. This
will let your environment variables flow
automatically into selected third-party services.
</p>
<p className="mr-4 text-xs text-gray-600 mt-1">
Note: during an integration with Heroku, for security reasons, it is impossible to maintain end-to-end encryption. In theory, this lets Infisical decrypt yor environment variables. In practice, we can assure you that this will never be done, and it allows us to protect your secrets from bad actors online. The core Infisical service will always stay end-to-end encrypted. With any questions, reach out support@infisical.com.
Note: during an integration with Heroku, for
security reasons, it is impossible to maintain
end-to-end encryption. In theory, this lets
Infisical decrypt yor environment variables. In
practice, we can assure you that this will never be
done, and it allows us to protect your secrets from
bad actors online. The core Infisical service will
always stay end-to-end encrypted. With any
questions, reach out support@infisical.com.
</p>
</div>
<div className="grid gap-4 grid-cols-3 grid-rows-3 mx-6 mt-4 max-w-5xl">
{Object.keys(integrations).map(integration =>
<div className={`relative ${["Heroku"].includes(integrations[integration].name) ? "" : "opacity-50"}`} key={integrations[integration].name} >
{Object.keys(integrations).map((integration) => (
<div
className={`relative ${
["Heroku"].includes(
integrations[integration].name
)
? ""
: "opacity-50"
}`}
key={integrations[integration].name}
>
<a
href={`${["Heroku"].includes(integrations[integration].name) ? `https://id.heroku.com/oauth/authorize?client_id=bc132901-935a-4590-b010-f1857efc380d&response_type=code&scope=write-protected&state=${csrfToken}` : "#"}`}
href={`${
["Heroku"].includes(
integrations[integration].name
)
? `https://id.heroku.com/oauth/authorize?client_id=bc132901-935a-4590-b010-f1857efc380d&response_type=code&scope=write-protected&state=${csrfToken}`
: "#"
}`}
rel="noopener"
className={`relative flex flex-row bg-white/5 h-32 rounded-md p-4 items-center ${["Heroku"].includes(integrations[integration].name) ? "hover:bg-white/10 duration-200 cursor-pointer" : "cursor-default grayscale"}`}>
className={`relative flex flex-row bg-white/5 h-32 rounded-md p-4 items-center ${
["Heroku"].includes(
integrations[integration].name
)
? "hover:bg-white/10 duration-200 cursor-pointer"
: "cursor-default grayscale"
}`}
>
<Image
src={`/images/integrations/${integrations[integration].name}.png`}
height={100}
width={100}
alt="integration logo"
></Image>
{integrations[integration].name.split(" ").length > 2
? <div className="font-semibold text-gray-300 group-hover:text-gray-200 duration-200 text-3xl ml-8 max-w-xs">
<div>{integrations[integration].name.split(" ")[0]}</div>
<div className="text-base">{integrations[integration].name.split(" ")[1]}{" "}{integrations[integration].name.split(" ")[2]}</div>
</div>
: <div className="font-semibold text-gray-300 group-hover:text-gray-200 duration-200 text-2xl ml-8 max-w-xs">{integrations[integration].name}</div>
{integrations[integration].name.split(" ")
.length > 2 ? (
<div className="font-semibold text-gray-300 group-hover:text-gray-200 duration-200 text-3xl ml-8 max-w-xs">
<div>
{
integrations[
integration
].name.split(" ")[0]
}
</a>
{["Heroku"].includes(integrations[integration].name) && authorizations.map(authorization => authorization.integration).includes(integrations[integration].name.toLowerCase()) &&
<div className="absolute group z-50 top-0 right-0 flex flex-row">
<div onClick={() => {
deleteIntegrationAuth({integrationAuthId: authorizations.filter(authorization => authorization.integration == integrations[integration].name.toLowerCase()).map(authorization => authorization._id)[0]});
router.reload();
}} className="cursor-pointer w-max bg-red py-0.5 px-2 rounded-b-md text-xs flex flex-row items-center opacity-0 group-hover:opacity-100 duration-200"><FontAwesomeIcon icon={faX} className="text-xs mr-2 py-px"/>Revoke</div>
<div className="w-max bg-primary py-0.5 px-2 rounded-bl-md rounded-tr-md text-xs flex flex-row items-center text-black opacity-90 group-hover:opacity-100 duration-200"><FontAwesomeIcon icon={faCheck} className="text-xs mr-2"/>Authorized</div>
</div>
<div className="text-base">
{
integrations[
integration
].name.split(" ")[1]
}{" "}
{
integrations[
integration
].name.split(" ")[2]
}
{!["Heroku"].includes(integrations[integration].name) &&
<div className="absolute group z-50 top-0 right-0 flex flex-row">
<div className="w-max bg-yellow py-0.5 px-2 rounded-bl-md rounded-tr-md text-xs flex flex-row items-center text-black opacity-90">Coming Soon</div>
</div>
}
</div>
) : (
<div className="font-semibold text-gray-300 group-hover:text-gray-200 duration-200 text-2xl ml-8 max-w-xs">
{integrations[integration].name}
</div>
)}
</a>
{["Heroku"].includes(
integrations[integration].name
) &&
authorizations
.map(
(authorization) =>
authorization.integration
)
.includes(
integrations[
integration
].name.toLowerCase()
) && (
<div className="absolute group z-50 top-0 right-0 flex flex-row">
<div
onClick={() => {
deleteIntegrationAuth({
integrationAuthId:
authorizations
.filter(
(
authorization
) =>
authorization.integration ==
integrations[
integration
].name.toLowerCase()
)
.map(
(
authorization
) =>
authorization._id
)[0],
});
router.reload();
}}
className="cursor-pointer w-max bg-red py-0.5 px-2 rounded-b-md text-xs flex flex-row items-center opacity-0 group-hover:opacity-100 duration-200"
>
<FontAwesomeIcon
icon={faX}
className="text-xs mr-2 py-px"
/>
Revoke
</div>
<div className="w-max bg-primary py-0.5 px-2 rounded-bl-md rounded-tr-md text-xs flex flex-row items-center text-black opacity-90 group-hover:opacity-100 duration-200">
<FontAwesomeIcon
icon={faCheck}
className="text-xs mr-2"
/>
Authorized
</div>
</div>
)}
{!["Heroku"].includes(
integrations[integration].name
) && (
<div className="absolute group z-50 top-0 right-0 flex flex-row">
<div className="w-max bg-yellow py-0.5 px-2 rounded-bl-md rounded-tr-md text-xs flex flex-row items-center text-black opacity-90">
Coming Soon
</div>
</div>
)}
</div>
))}
</div>
</div>
</div>
+23 -12
View File
@@ -5,11 +5,11 @@ import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import InputField from "../components/basic/InputField";
import Error from "../components/basic/Error";
import Button from "../components/basic/buttons/Button";
import InputField from "~/components/basic/InputField";
import Error from "~/components/basic/Error";
import Button from "~/components/basic/buttons/Button";
import getWorkspaces from "./api/workspace/getWorkspaces";
import attemptLogin from "../components/utilities/attemptLogin";
import attemptLogin from "~/utilities/attemptLogin";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faWarning } from "@fortawesome/free-solid-svg-icons";
@@ -36,13 +36,18 @@ export default function Login() {
*/
const loginCheck = async () => {
setIsLoading(true);
await attemptLogin(email, password, setErrorLogin, router, false, true).then(
() => {
await attemptLogin(
email,
password,
setErrorLogin,
router,
false,
true
).then(() => {
setTimeout(function () {
setIsLoading(false);
}, 2000);
}
);
});
};
return (
@@ -122,11 +127,17 @@ export default function Login() {
<p className="text-gray-400">I may have <Link href="/login"><u className="text-sky-500 cursor-pointer">forgotten my password.</u></Link></p>
</div> */}
</div>
{false &&
{false && (
<div className="w-full p-2 flex flex-row items-center bg-white/10 text-gray-300 rounded-md max-w-md mx-auto mt-4">
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-6 text-6xl"/>
We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.
</div>}
<FontAwesomeIcon
icon={faWarning}
className="ml-2 mr-6 text-6xl"
/>
We are experiencing minor technical difficulties. We are
working on solving it right now. Please come back in a few
minutes.
</div>
)}
</div>
);
}
+22 -18
View File
@@ -1,11 +1,10 @@
import React, { useState, useEffect } from "react";
import Head from "next/head";
import Plan from "../../../components/billing/Plan";
import getOrganizationSubscriptions from "../../api/organization/GetOrgSubscription"
import getOrganizationUsers from "../../api/organization/GetOrgUsers"
import NavHeader from "../../../components/navigation/NavHeader";
import { STRIPE_PRODUCT_PRO, STRIPE_PRODUCT_STARTER } from "../../../components/utilities/config";
import Plan from "~/components/billing/Plan";
import getOrganizationSubscriptions from "../../api/organization/GetOrgSubscription";
import getOrganizationUsers from "../../api/organization/GetOrgUsers";
import NavHeader from "~/components/navigation/NavHeader";
import { STRIPE_PRODUCT_PRO, STRIPE_PRODUCT_STARTER } from "~/utilities/config";
export default function SettingsBilling() {
let [currentPlan, setCurrentPlan] = useState("");
@@ -46,10 +45,14 @@ export default function SettingsBilling() {
];
useEffect(async () => {
const subscriptions = await getOrganizationSubscriptions({orgId: localStorage.getItem("orgData.id")});
setCurrentPlan(subscriptions.data[0].plan.product)
const orgUsers = await getOrganizationUsers({orgId: localStorage.getItem("orgData.id")})
setNumUsers(orgUsers.length)
const subscriptions = await getOrganizationSubscriptions({
orgId: localStorage.getItem("orgData.id"),
});
setCurrentPlan(subscriptions.data[0].plan.product);
const orgUsers = await getOrganizationUsers({
orgId: localStorage.getItem("orgData.id"),
});
setNumUsers(orgUsers.length);
}, []);
return (
@@ -67,7 +70,8 @@ export default function SettingsBilling() {
Usage & Billing
</p>
<p className="font-normal mr-4 text-gray-400 text-base">
View and manage your organization's subscription here.
View and manage your organization's subscription
here.
</p>
</div>
</div>
@@ -75,24 +79,24 @@ export default function SettingsBilling() {
<p className="text-xl font-semibold">Subscription</p>
<div className="flex flex-row mt-4 overflow-x-auto">
{plans.map((plan) => (
<Plan
key={plan.name}
plan={plan}
/>
<Plan key={plan.name} plan={plan} />
))}
</div>
<p className='text-xl font-bold mt-12'>Current Usage</p>
<p className="text-xl font-bold mt-12">Current Usage</p>
<div className="flex flex-row">
<div className="mr-4 mt-8 text-gray-300 w-60 pt-6 pb-10 rounded-md bg-white/5 flex justify-center items-center flex flex-col">
<p className="text-6xl font-bold">{numUsers}</p>
<p className="text-gray-300">{numUsers > 1 ? "Organization members" : "Organization member"}</p>
<p className="text-gray-300">
{numUsers > 1
? "Organization members"
: "Organization member"}
</p>
</div>
{/* <div className="mr-4 mt-8 text-gray-300 w-60 pt-6 pb-10 rounded-md bg-white/5 flex justify-center items-center flex flex-col">
<p className="text-6xl font-bold">1 </p>
<p className="text-gray-300">Organization projects</p>
</div> */}
</div>
</div>
</div>
</div>
+34 -19
View File
@@ -2,26 +2,29 @@ import React, { useState, useEffect } from "react";
import { useRouter } from "next/router";
import Head from "next/head";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faMagnifyingGlass, faPlus, faX } from "@fortawesome/free-solid-svg-icons";
import {
faMagnifyingGlass,
faPlus,
faX,
} from "@fortawesome/free-solid-svg-icons";
import { faCheck } from "@fortawesome/free-solid-svg-icons";
import InputField from "../../../components/basic/InputField";
import InputField from "~/components/basic/InputField";
import getWorkspaces from "../../api/workspace/getWorkspaces";
import AddIncidentContactDialog from "../../../components/basic/dialog/AddIncidentContactDialog";
import AddIncidentContactDialog from "~/components/basic/dialog/AddIncidentContactDialog";
import getIncidentContacts from "../../api/organization/getIncidentContacts";
import deleteIncidentContact from "../../api/organization/deleteIncidentContact";
import deleteWorkspace from "../../api/workspace/deleteWorkspace";
import AddUserDialog from "../../../components/basic/dialog/AddUserDialog";
import UserTable from "../../../components/basic/table/UserTable";
import AddUserDialog from "~/components/basic/dialog/AddUserDialog";
import UserTable from "~/components/basic/table/UserTable";
import getUser from "../../api/user/getUser";
import guidGenerator from "../../../components/utilities/randomId";
import guidGenerator from "~/utilities/randomId";
import addUserToOrg from "../../api/organization/addUserToOrg";
import getOrganizationUsers from "../../api/organization/GetOrgUsers";
import renameOrg from "../../api/organization/renameOrg";
import getOrganization from "../../api/organization/GetOrg";
import getOrganizationSubscriptions from "../../api/organization/GetOrgSubscription";
import NavHeader from "../../../components/navigation/NavHeader";
import Button from "../../../components/basic/buttons/Button";
import NavHeader from "~/components/navigation/NavHeader";
import Button from "~/components/basic/buttons/Button";
export default function SettingsOrg() {
const [buttonReady, setButtonReady] = useState(false);
@@ -51,12 +54,12 @@ export default function SettingsOrg() {
});
let orgData = org;
setOrgName(orgData.name);
let incidentContactsData = await getIncidentContacts(localStorage.getItem("orgData.id"));
let incidentContactsData = await getIncidentContacts(
localStorage.getItem("orgData.id")
);
setIncidentContacts(
incidentContactsData?.map(
(contact) => contact.email
)
incidentContactsData?.map((contact) => contact.email)
);
const user = await getUser();
@@ -82,8 +85,10 @@ export default function SettingsOrg() {
publicKey: user.user?.publicKey,
}))
);
const subscriptions = await getOrganizationSubscriptions({orgId: localStorage.getItem("orgData.id")});
setCurrentPlan(subscriptions.data[0].plan.product)
const subscriptions = await getOrganizationSubscriptions({
orgId: localStorage.getItem("orgData.id"),
});
setCurrentPlan(subscriptions.data[0].plan.product);
}, []);
const modifyOrgName = (newName) => {
@@ -127,7 +132,10 @@ export default function SettingsOrg() {
setIncidentContacts(
incidentContacts.filter((contact) => contact != incidentContact)
);
deleteIncidentContact(localStorage.getItem("orgData.id"), incidentContact);
deleteIncidentContact(
localStorage.getItem("orgData.id"),
incidentContact
);
};
/**
@@ -201,7 +209,9 @@ export default function SettingsOrg() {
>
<Button
text="Save Changes"
onButtonPressed={() => submitChanges(orgName)}
onButtonPressed={() =>
submitChanges(orgName)
}
color="mineshaft"
size="md"
active={buttonReady}
@@ -289,7 +299,9 @@ export default function SettingsOrg() {
<div className="mt-4 mb-2 min-w-max flex flex-row items-end justify-end justify-center">
<Button
text="Add Contact"
onButtonPressed={openAddIncidentContactModal}
onButtonPressed={
openAddIncidentContactModal
}
color="mineshaft"
size="md"
icon={faPlus}
@@ -318,7 +330,10 @@ export default function SettingsOrg() {
email.includes(searchIncidentContact)
)
.map((contact) => (
<div key={guidGenerator()} className="flex flex-row items-center justify-between max-w-5xl px-4 py-3 hover:bg-white/5 border-t border-gray-600 w-full">
<div
key={guidGenerator()}
className="flex flex-row items-center justify-between max-w-5xl px-4 py-3 hover:bg-white/5 border-t border-gray-600 w-full"
>
<p className="text-gray-300">
{contact}
</p>
+127 -35
View File
@@ -2,14 +2,13 @@ import React, { useState, useEffect } from "react";
import Head from "next/head";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCheck, faX } from "@fortawesome/free-solid-svg-icons";
import InputField from "../../../components/basic/InputField";
import InputField from "~/components/basic/InputField";
import getUser from "../../api/user/getUser";
import NavHeader from "../../../components/navigation/NavHeader";
import passwordCheck from "../../../components/utilities/checks/PasswordCheck";
import changePassword from "../../../components/utilities/changePassword";
import issueBackupKey from "../../../components/utilities/issueBackupKey";
import Button from "../../../components/basic/buttons/Button";
import NavHeader from "~/components/navigation/NavHeader";
import passwordCheck from "~/utilities/checks/PasswordCheck";
import changePassword from "~/utilities/changePassword";
import issueBackupKey from "~/utilities/issueBackupKey";
import Button from "~/components/basic/buttons/Button";
export default function PersonalSettings() {
const [personalEmail, setPersonalEmail] = useState("");
@@ -31,8 +30,6 @@ export default function PersonalSettings() {
setPersonalName(user.firstName + " " + user.lastName);
}, []);
return (
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
<Head>
@@ -41,7 +38,10 @@ export default function PersonalSettings() {
</Head>
<div className="flex flex-row">
<div className="w-full max-h-screen pb-2 overflow-y-auto">
<NavHeader pageName="Personal Settings" isProjectRelated={false}/>
<NavHeader
pageName="Personal Settings"
isProjectRelated={false}
/>
<div className="flex flex-row justify-between items-center ml-6 mt-8 mb-6 text-xl max-w-5xl">
<div className="flex flex-col justify-start items-start text-3xl">
<p className="font-semibold mr-4 text-gray-200">
@@ -137,35 +137,101 @@ export default function PersonalSettings() {
type="password"
value={newPassword}
isRequired
error={passwordErrorLength && passwordErrorLowerCase && passwordErrorNumber}
error={
passwordErrorLength &&
passwordErrorLowerCase &&
passwordErrorNumber
}
/>
</div>
{(passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber) ? <div className="w-full mt-3 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md max-w-xl mb-2">
<div className={`text-gray-400 text-sm mb-1`}>Password should contain at least:</div>
<div className="flex flex-row justify-start items-center ml-1">
{passwordErrorLength
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
<div className={`${passwordErrorLength ? "text-gray-400" : "text-gray-600"} text-sm`}>14 characters</div>
{passwordErrorLength ||
passwordErrorLowerCase ||
passwordErrorNumber ? (
<div className="w-full mt-3 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md max-w-xl mb-2">
<div
className={`text-gray-400 text-sm mb-1`}
>
Password should contain at least:
</div>
<div className="flex flex-row justify-start items-center ml-1">
{passwordErrorLowerCase
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
<div className={`${passwordErrorLowerCase ? "text-gray-400" : "text-gray-600"} text-sm`}>1 lowercase character</div>
{passwordErrorLength ? (
<FontAwesomeIcon
icon={faX}
className="text-md text-red mr-2.5"
/>
) : (
<FontAwesomeIcon
icon={faCheck}
className="text-md text-primary mr-2"
/>
)}
<div
className={`${
passwordErrorLength
? "text-gray-400"
: "text-gray-600"
} text-sm`}
>
14 characters
</div>
</div>
<div className="flex flex-row justify-start items-center ml-1">
{passwordErrorNumber
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
<div className={`${passwordErrorNumber ? "text-gray-400" : "text-gray-600"} text-sm`}>1 number</div>
{passwordErrorLowerCase ? (
<FontAwesomeIcon
icon={faX}
className="text-md text-red mr-2.5"
/>
) : (
<FontAwesomeIcon
icon={faCheck}
className="text-md text-primary mr-2"
/>
)}
<div
className={`${
passwordErrorLowerCase
? "text-gray-400"
: "text-gray-600"
} text-sm`}
>
1 lowercase character
</div>
</div> : <div className="py-2"></div>}
</div>
<div className="flex flex-row justify-start items-center ml-1">
{passwordErrorNumber ? (
<FontAwesomeIcon
icon={faX}
className="text-md text-red mr-2.5"
/>
) : (
<FontAwesomeIcon
icon={faCheck}
className="text-md text-primary mr-2"
/>
)}
<div
className={`${
passwordErrorNumber
? "text-gray-400"
: "text-gray-600"
} text-sm`}
>
1 number
</div>
</div>
</div>
) : (
<div className="py-2"></div>
)}
<div className="flex flex-row items-center mt-3 w-52 pr-3">
<Button
text="Change Password"
onButtonPressed={() => {
if (!passwordErrorLength && !passwordErrorLowerCase && !passwordErrorNumber) {
if (
!passwordErrorLength &&
!passwordErrorLowerCase &&
!passwordErrorNumber
) {
changePassword(
personalEmail,
currentPassword,
@@ -174,15 +240,30 @@ export default function PersonalSettings() {
setPasswordChanged,
setCurrentPassword,
setNewPassword
)
);
}
}}
color="mineshaft"
size="md"
active={(newPassword != "") && (currentPassword != "") && !(passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber)}
active={
newPassword != "" &&
currentPassword != "" &&
!(
passwordErrorLength ||
passwordErrorLowerCase ||
passwordErrorNumber
)
}
textDisabled="Change Password"
/>
<FontAwesomeIcon icon={faCheck} className={`ml-4 text-primary text-3xl ${passwordChanged ? "opacity-100" : "opacity-0"} duration-300`}/>
<FontAwesomeIcon
icon={faCheck}
className={`ml-4 text-primary text-3xl ${
passwordChanged
? "opacity-100"
: "opacity-0"
} duration-300`}
/>
</div>
</div>
@@ -193,10 +274,14 @@ export default function PersonalSettings() {
Emergency Kit
</p>
<p className="text-sm text-mineshaft-300 min-w-max">
Your Emergency Kit contains the information you’ll need to sign in to your Infisical account.
Your Emergency Kit contains the
information you’ll need to sign in to
your Infisical account.
</p>
<p className="text-sm text-mineshaft-300 mb-5 min-w-max">
Only the latest issued Emergency Kit remains valid. To get a new Emergency Kit, verify your password.
Only the latest issued Emergency Kit
remains valid. To get a new Emergency
Kit, verify your password.
</p>
</div>
</div>
@@ -220,7 +305,7 @@ export default function PersonalSettings() {
password: backupPassword,
personalName,
setBackupKeyError,
setBackupKeyIssued
setBackupKeyIssued,
});
}}
color="mineshaft"
@@ -228,7 +313,14 @@ export default function PersonalSettings() {
active={backupPassword != ""}
textDisabled="Download Emergency Kit"
/>
<FontAwesomeIcon icon={faCheck} className={`ml-4 text-primary text-3xl ${backupKeyIssued ? "opacity-100" : "opacity-0"} duration-300`}/>
<FontAwesomeIcon
icon={faCheck}
className={`ml-4 text-primary text-3xl ${
backupKeyIssued
? "opacity-100"
: "opacity-0"
} duration-300`}
/>
</div>
</div>
</div>
+32 -14
View File
@@ -3,15 +3,15 @@ import { useRouter } from "next/router";
import Head from "next/head";
import { faCheck, faPlus } from "@fortawesome/free-solid-svg-icons";
import InputField from "../../../components/basic/InputField";
import InputField from "~/components/basic/InputField";
import getWorkspaces from "../../api/workspace/getWorkspaces";
import renameWorkspace from "../../api/workspace/renameWorkspace";
import deleteWorkspace from "../../api/workspace/deleteWorkspace";
import NavHeader from "../../../components/navigation/NavHeader";
import Button from "../../../components/basic/buttons/Button";
import ServiceTokenTable from "../../../components/basic/table/ServiceTokenTable";
import getServiceTokens from "../../api/serviceToken/getServiceTokens"
import AddServiceTokenDialog from "../../../components/basic/dialog/AddServiceTokenDialog";
import NavHeader from "~/components/navigation/NavHeader";
import Button from "~/components/basic/buttons/Button";
import ServiceTokenTable from "~/components/basic/table/ServiceTokenTable";
import getServiceTokens from "../../api/serviceToken/getServiceTokens";
import AddServiceTokenDialog from "~/components/basic/dialog/AddServiceTokenDialog";
export default function SettingsBasic() {
const [buttonReady, setButtonReady] = useState(false);
@@ -22,7 +22,8 @@ export default function SettingsBasic() {
useState("");
const [workspaceId, setWorkspaceId] = useState("");
const [isAddOpen, setIsAddOpen] = useState(false);
let [isAddServiceTokenDialogOpen, setIsAddServiceTokenDialogOpen] = useState(false);
let [isAddServiceTokenDialogOpen, setIsAddServiceTokenDialogOpen] =
useState(false);
useEffect(async () => {
let userWorkspaces = await getWorkspaces();
@@ -31,7 +32,9 @@ export default function SettingsBasic() {
setWorkspaceName(userWorkspace.name);
}
});
let tempServiceTokens = await getServiceTokens({workspaceId: router.query.id});
let tempServiceTokens = await getServiceTokens({
workspaceId: router.query.id,
});
setServiceTokens(tempServiceTokens);
}, []);
@@ -59,7 +62,7 @@ export default function SettingsBasic() {
const closeAddServiceTokenModal = () => {
setIsAddServiceTokenDialogOpen(false);
}
};
/**
* This function deleted a workspace.
@@ -97,7 +100,10 @@ export default function SettingsBasic() {
/>
<div className="flex flex-row mr-6 max-w-5xl">
<div className="w-full max-h-screen pb-2 overflow-y-auto">
<NavHeader pageName="Project Settings" isProjectRelated={true}/>
<NavHeader
pageName="Project Settings"
isProjectRelated={true}
/>
<div className="flex flex-row justify-between items-center ml-6 my-8 text-xl max-w-5xl">
<div className="flex flex-col justify-start items-start text-3xl">
<p className="font-semibold mr-4 text-gray-200">
@@ -133,7 +139,9 @@ export default function SettingsBasic() {
>
<Button
text="Save Changes"
onButtonPressed={() => submitChanges(workspaceName)}
onButtonPressed={() =>
submitChanges(workspaceName)
}
color="mineshaft"
size="md"
active={buttonReady}
@@ -184,20 +192,30 @@ export default function SettingsBasic() {
Service Tokens
</p>
<p className="text-base text-gray-400 mb-4">
Every service token is specific to you, a certain project and a certain environment within this project.
Every service token is specific
to you, a certain project and a
certain environment within this
project.
</p>
</div>
<div className="w-48">
<Button
text="Add New Token"
onButtonPressed={() => {setIsAddServiceTokenDialogOpen(true)}}
onButtonPressed={() => {
setIsAddServiceTokenDialogOpen(
true
);
}}
color="mineshaft"
icon={faPlus}
size="md"
/>
</div>
</div>
<ServiceTokenTable data={serviceTokens} workspaceName={workspaceName}/>
<ServiceTokenTable
data={serviceTokens}
workspaceName={workspaceName}
/>
</div>
{/* <div className="bg-white/5 rounded-md px-6 flex flex-col items-start flex flex-col items-start w-full mb-6 mt-4 pb-6 pt-6">
+138 -41
View File
@@ -6,19 +6,19 @@ import Image from "next/image";
import Link from "next/link";
import dynamic from "next/dynamic";
import InputField from "../components/basic/InputField";
import Error from "../components/basic/Error";
import Button from "../components/basic/buttons/Button";
import InputField from "~/compoennts/basic/InputField";
import Error from "~/compoennts/basic/Error";
import Button from "~/compoennts/basic/buttons/Button";
import sendVerificationEmail from "./api/auth/SendVerificationEmail";
import checkEmailVerificationCode from "./api/auth/CheckEmailVerificationCode";
import completeAccountInformationSignup from "./api/auth/CompleteAccountInformationSignup";
import Aes256Gcm from "../components/aes-256-gcm";
import passwordCheck from "../components/utilities/checks/PasswordCheck";
import Aes256Gcm from "~/compoennts/aes-256-gcm";
import passwordCheck from "~/compoennts/utilities/checks/PasswordCheck";
import getWorkspaces from "./api/workspace/getWorkspaces";
import attemptLogin from "../components/utilities/attemptLogin";
import attemptLogin from "~/compoennts/utilities/attemptLogin";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCheck, faX, faWarning } from "@fortawesome/free-solid-svg-icons";
import issueBackupKey from "../components/utilities/issueBackupKey";
import issueBackupKey from "~/compoennts/utilities/issueBackupKey";
const ReactCodeInput = dynamic(import("react-code-input"));
const nacl = require("tweetnacl");
@@ -73,7 +73,8 @@ export default function SignUp() {
const [passwordErrorNumber, setPasswordErrorNumber] = useState(false);
const [passwordErrorUpperCase, setPasswordErrorUpperCase] = useState(false);
const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false);
const [passwordErrorSpecialChar, setPasswordErrorSpecialChar] = useState(false);
const [passwordErrorSpecialChar, setPasswordErrorSpecialChar] =
useState(false);
const [emailError, setEmailError] = useState(false);
const [emailErrorMessage, setEmailErrorMessage] = useState("");
const [step, setStep] = useState(1);
@@ -108,7 +109,7 @@ export default function SignUp() {
// Checking if the code matches the email.
const response = await checkEmailVerificationCode(email, code);
if (response.status == "200" || code == "111222") {
setVerificationToken((await response.json()).token)
setVerificationToken((await response.json()).token);
setStep(3);
} else {
setCodeError(true);
@@ -180,7 +181,14 @@ export default function SignUp() {
const { ciphertext, iv, tag } = Aes256Gcm.encrypt(
PRIVATE_KEY,
password.slice(0, 32).padStart(32 + (password.slice(0, 32).length - new Blob([password]).size), "0")
password
.slice(0, 32)
.padStart(
32 +
(password.slice(0, 32).length -
new Blob([password]).size),
"0"
)
);
localStorage.setItem("PRIVATE_KEY", PRIVATE_KEY);
@@ -191,7 +199,8 @@ export default function SignUp() {
},
async () => {
client.createVerifier(async (err, result) => {
const response = await completeAccountInformationSignup({
const response = await completeAccountInformationSignup(
{
email,
firstName,
lastName,
@@ -202,8 +211,9 @@ export default function SignUp() {
tag,
salt: result.salt,
verifier: result.verifier,
token: verificationToken
});
token: verificationToken,
}
);
// if everything works, go the main dashboard page.
if (!errorCheck && response.status == "200") {
@@ -276,7 +286,11 @@ export default function SignUp() {
and acknowledged the Privacy Policy.
</p>
<div className="text-l mt-6 m-2 md:m-8 px-8 py-1 text-lg">
<Button text="Get Started" onButtonPressed={emailCheck} size="lg"/>
<Button
text="Get Started"
onButtonPressed={emailCheck}
size="lg"
/>
</div>
</div>
</div>
@@ -313,7 +327,11 @@ export default function SignUp() {
<Error text="Oops. Your code is wrong. Please try again." />
)}
<div className="flex max-w-min flex-col items-center justify-center md:p-2 max-h-24 max-w-md mx-auto text-lg px-4 mt-4 mb-2">
<Button text="Verify" onButtonPressed={incrementStep} size="lg"/>
<Button
text="Verify"
onButtonPressed={incrementStep}
size="lg"
/>
</div>
<div className="flex flex-col items-center justify-center w-full max-h-24 max-w-md mx-auto pt-2">
{/* <Link href="/login">
@@ -374,37 +392,101 @@ export default function SignUp() {
type="password"
value={password}
isRequired
error={passwordErrorLength && passwordErrorNumber && passwordErrorLowerCase}
error={
passwordErrorLength &&
passwordErrorNumber &&
passwordErrorLowerCase
}
/>
{(passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber) ? <div className="w-full mt-4 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md">
<div className={`text-gray-400 text-sm mb-1`}>Password should contain at least:</div>
<div className="flex flex-row justify-start items-center ml-1">
{passwordErrorLength
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
<div className={`${passwordErrorLength ? "text-gray-400" : "text-gray-600"} text-sm`}>14 characters</div>
{passwordErrorLength ||
passwordErrorLowerCase ||
passwordErrorNumber ? (
<div className="w-full mt-4 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md">
<div className={`text-gray-400 text-sm mb-1`}>
Password should contain at least:
</div>
<div className="flex flex-row justify-start items-center ml-1">
{passwordErrorLowerCase
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
<div className={`${passwordErrorLowerCase ? "text-gray-400" : "text-gray-600"} text-sm`}>1 lowercase character</div>
{passwordErrorLength ? (
<FontAwesomeIcon
icon={faX}
className="text-md text-red mr-2.5"
/>
) : (
<FontAwesomeIcon
icon={faCheck}
className="text-md text-primary mr-2"
/>
)}
<div
className={`${
passwordErrorLength
? "text-gray-400"
: "text-gray-600"
} text-sm`}
>
14 characters
</div>
</div>
<div className="flex flex-row justify-start items-center ml-1">
{passwordErrorNumber
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
<div className={`${passwordErrorNumber ? "text-gray-400" : "text-gray-600"} text-sm`}>1 number</div>
{passwordErrorLowerCase ? (
<FontAwesomeIcon
icon={faX}
className="text-md text-red mr-2.5"
/>
) : (
<FontAwesomeIcon
icon={faCheck}
className="text-md text-primary mr-2"
/>
)}
<div
className={`${
passwordErrorLowerCase
? "text-gray-400"
: "text-gray-600"
} text-sm`}
>
1 lowercase character
</div>
</div> : <div className="py-2"></div>}
</div>
<div className="flex flex-row justify-start items-center ml-1">
{passwordErrorNumber ? (
<FontAwesomeIcon
icon={faX}
className="text-md text-red mr-2.5"
/>
) : (
<FontAwesomeIcon
icon={faCheck}
className="text-md text-primary mr-2"
/>
)}
<div
className={`${
passwordErrorNumber
? "text-gray-400"
: "text-gray-600"
} text-sm`}
>
1 number
</div>
</div>
</div>
) : (
<div className="py-2"></div>
)}
</div>
<div className="flex flex-col items-center justify-center md:p-2 max-h-48 max-w-max mx-auto text-lg px-2 py-3">
<Button text="Sign Up" loading={isLoading} onButtonPressed={signupErrorCheck} size="lg" />
<Button
text="Sign Up"
loading={isLoading}
onButtonPressed={signupErrorCheck}
size="lg"
/>
</div>
</div>
);
// Step 4 of the sign up process (download the emergency kit pdf)
const step4 = (
<div className="bg-bunker flex flex-col items-center w-full max-w-xs md:max-w-lg mx-auto h-7/12 py-8 px-4 md:px-6 mx-1 mb-36 md:mb-16 rounded-xl drop-shadow-xl">
@@ -412,12 +494,21 @@ export default function SignUp() {
Save your Emergency Kit
</p>
<div className="flex flex-col items-center justify-center w-full mt-4 md:mt-8 max-w-md text-gray-400 text-md rounded-md px-2">
<div>If you get locked out of your account, your Emergency Kit is the only way to sign in.</div>
<div className="mt-3">We recommend you download it and keep it somewhere safe.</div>
<div>
If you get locked out of your account, your Emergency Kit is
the only way to sign in.
</div>
<div className="mt-3">
We recommend you download it and keep it somewhere safe.
</div>
</div>
<div className="w-full p-2 flex flex-row items-center bg-white/10 text-gray-400 rounded-md max-w-xs md:max-w-md mx-auto mt-4">
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-4 text-4xl"/>
It contains your Secret Key which we cannot access or recover for you if you lose it.
<FontAwesomeIcon
icon={faWarning}
className="ml-2 mr-4 text-4xl"
/>
It contains your Secret Key which we cannot access or recover
for you if you lose it.
</div>
<div className="flex flex-row items-center justify-center w-3/4 md:w-full md:p-2 max-h-28 max-w-max mx-auto mt-6 py-1 md:mt-4 text-lg text-center md:text-left">
<Button
@@ -426,9 +517,9 @@ export default function SignUp() {
await issueBackupKey({
email,
password,
personalName: (firstName + " " + lastName),
personalName: firstName + " " + lastName,
setBackupKeyError,
setBackupKeyIssued
setBackupKeyIssued,
});
router.push("/dashboard/");
}}
@@ -476,7 +567,13 @@ export default function SignUp() {
/>
</div>
</Link>
{step == 1 ? step1 : step == 2 ? step2 : step == 3 ? step3 : step4}
{step == 1
? step1
: step == 2
? step2
: step == 3
? step3
: step4}
</div>
</div>
);
+113 -36
View File
@@ -5,15 +5,15 @@ import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import InputField from "../components/basic/InputField";
import Button from "../components/basic/buttons/Button";
import InputField from "~/components/basic/InputField";
import Button from "~/components/basic/buttons/Button";
import completeAccountInformationSignupInvite from "./api/auth/CompleteAccountInformationSignupInvite";
import Aes256Gcm from "../components/aes-256-gcm";
import passwordCheck from "../components/utilities/checks/PasswordCheck";
import attemptLogin from "../components/utilities/attemptLogin";
import Aes256Gcm from "~/components/aes-256-gcm";
import passwordCheck from "~/utilities/checks/PasswordCheck";
import attemptLogin from "~/utilities/attemptLogin";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCheck, faX, faWarning } from "@fortawesome/free-solid-svg-icons";
import issueBackupKey from "../components/utilities/issueBackupKey";
import issueBackupKey from "~/utilities/issueBackupKey";
import verifySignupInvite from "./api/auth/VerifySignupInvite";
const nacl = require("tweetnacl");
@@ -76,7 +76,14 @@ export default function SignupInvite() {
const { ciphertext, iv, tag } = Aes256Gcm.encrypt(
PRIVATE_KEY,
password.slice(0, 32).padStart(32 + (password.slice(0, 32).length - new Blob([password]).size), "0")
password
.slice(0, 32)
.padStart(
32 +
(password.slice(0, 32).length -
new Blob([password]).size),
"0"
)
);
localStorage.setItem("PRIVATE_KEY", PRIVATE_KEY);
@@ -87,7 +94,8 @@ export default function SignupInvite() {
},
async () => {
client.createVerifier(async (err, result) => {
const response = await completeAccountInformationSignupInvite({
const response =
await completeAccountInformationSignupInvite({
email,
firstName,
lastName,
@@ -97,7 +105,7 @@ export default function SignupInvite() {
tag,
salt: result.salt,
verifier: result.verifier,
token: verificationToken
token: verificationToken,
});
// if everything works, go the main dashboard page.
@@ -153,14 +161,14 @@ export default function SignupInvite() {
onButtonPressed={async () => {
const response = await verifySignupInvite({
email,
code: token
code: token,
});
if (response.status == 200) {
setVerificationToken((await response.json()).token)
setVerificationToken((await response.json()).token);
setStep(2);
} else {
console.log("ERROR", response)
router.push("/requestnewinvite")
console.log("ERROR", response);
router.push("/requestnewinvite");
}
}}
size="lg"
@@ -213,29 +221,89 @@ export default function SignupInvite() {
type="password"
value={password}
isRequired
error={passwordErrorLength && passwordErrorNumber && passwordErrorLowerCase}
error={
passwordErrorLength &&
passwordErrorNumber &&
passwordErrorLowerCase
}
/>
{(passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber) ? <div className="w-full mt-4 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md">
<div className={`text-gray-400 text-sm mb-1`}>Password should contain at least:</div>
<div className="flex flex-row justify-start items-center ml-1">
{passwordErrorLength
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
<div className={`${passwordErrorLength ? "text-gray-400" : "text-gray-600"} text-sm`}>14 characters</div>
{passwordErrorLength ||
passwordErrorLowerCase ||
passwordErrorNumber ? (
<div className="w-full mt-4 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md">
<div className={`text-gray-400 text-sm mb-1`}>
Password should contain at least:
</div>
<div className="flex flex-row justify-start items-center ml-1">
{passwordErrorLowerCase
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
<div className={`${passwordErrorLowerCase ? "text-gray-400" : "text-gray-600"} text-sm`}>1 lowercase character</div>
{passwordErrorLength ? (
<FontAwesomeIcon
icon={faX}
className="text-md text-red mr-2.5"
/>
) : (
<FontAwesomeIcon
icon={faCheck}
className="text-md text-primary mr-2"
/>
)}
<div
className={`${
passwordErrorLength
? "text-gray-400"
: "text-gray-600"
} text-sm`}
>
14 characters
</div>
</div>
<div className="flex flex-row justify-start items-center ml-1">
{passwordErrorNumber
? <FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5"/>
: <FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2"/>}
<div className={`${passwordErrorNumber ? "text-gray-400" : "text-gray-600"} text-sm`}>1 number</div>
{passwordErrorLowerCase ? (
<FontAwesomeIcon
icon={faX}
className="text-md text-red mr-2.5"
/>
) : (
<FontAwesomeIcon
icon={faCheck}
className="text-md text-primary mr-2"
/>
)}
<div
className={`${
passwordErrorLowerCase
? "text-gray-400"
: "text-gray-600"
} text-sm`}
>
1 lowercase character
</div>
</div> : <div className="py-2"></div>}
</div>
<div className="flex flex-row justify-start items-center ml-1">
{passwordErrorNumber ? (
<FontAwesomeIcon
icon={faX}
className="text-md text-red mr-2.5"
/>
) : (
<FontAwesomeIcon
icon={faCheck}
className="text-md text-primary mr-2"
/>
)}
<div
className={`${
passwordErrorNumber
? "text-gray-400"
: "text-gray-600"
} text-sm`}
>
1 number
</div>
</div>
</div>
) : (
<div className="py-2"></div>
)}
</div>
<div className="flex flex-col items-center justify-center w-full md:px-4 md:py-5 mt-2 px-2 py-3 max-h-24 max-w-md mx-auto text-lg">
<Button
@@ -257,12 +325,21 @@ export default function SignupInvite() {
Save your Emergency Kit
</p>
<div className="flex flex-col items-center justify-center w-full mt-4 md:mt-8 max-w-md text-gray-400 text-md rounded-md px-2">
<div>If you get locked out of your account, your Emergency Kit is the only way to sign in.</div>
<div className="mt-3">We recommend you download it and keep it somewhere safe.</div>
<div>
If you get locked out of your account, your Emergency Kit is
the only way to sign in.
</div>
<div className="mt-3">
We recommend you download it and keep it somewhere safe.
</div>
</div>
<div className="w-full p-2 flex flex-row items-center bg-white/10 text-gray-400 rounded-md max-w-xs md:max-w-md mx-auto mt-4">
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-4 text-4xl"/>
It contains your Secret Key which we cannot access or recover for you if you lose it.
<FontAwesomeIcon
icon={faWarning}
className="ml-2 mr-4 text-4xl"
/>
It contains your Secret Key which we cannot access or recover
for you if you lose it.
</div>
<div className="flex flex-row items-center justify-center w-3/4 md:w-full md:p-2 max-h-28 max-w-xs md:max-w-md mx-auto mt-6 md:mt-8 py-1 text-lg text-center md:text-left">
<Button
@@ -271,9 +348,9 @@ export default function SignupInvite() {
await issueBackupKey({
email,
password,
personalName: (firstName + " " + lastName),
personalName: firstName + " " + lastName,
setBackupKeyError,
setBackupKeyIssued
setBackupKeyIssued,
});
router.push("/dashboard/");
}}
+9 -11
View File
@@ -5,17 +5,17 @@ import Image from "next/image";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faMagnifyingGlass, faPlus } from "@fortawesome/free-solid-svg-icons";
import UserTable from "../../components/basic/table/UserTable";
import UserTable from "~/components/basic/table/UserTable";
import getWorkspaceUsers from "../api/workspace/getWorkspaceUsers";
import guidGenerator from "../../components/utilities/randomId";
import AddProjectMemberDialog from "../../components/basic/dialog/AddProjectMemberDialog";
// import DeleteUserDialog from '../../components/basic/dialog/DeleteUserDialog';
import guidGenerator from "~/utilities/randomId";
import AddProjectMemberDialog from "~/components/basic/dialog/AddProjectMemberDialog";
// import DeleteUserDialog from '~/components/basic/dialog/DeleteUserDialog';
import addUserToWorkspace from "../api/workspace/addUserToWorkspace";
import getUser from "../api/user/getUser";
import uploadKeys from "../api/workspace/uploadKeys";
import getOrganizationUsers from "../api/organization/GetOrgUsers";
import NavHeader from "../../components/navigation/NavHeader";
import Button from "../../components/basic/buttons/Button";
import NavHeader from "~/components/navigation/NavHeader";
import Button from "~/components/basic/buttons/Button";
// #TODO: Update all the workspaceIds
const crypto = require("crypto");
@@ -98,15 +98,13 @@ export default function Users() {
firstName: user.user?.firstName,
lastName: user.user?.lastName,
email:
user.user?.email == null
? user.inviteEmail
: user.user?.email,
user.user?.email == null ? user.inviteEmail : user.user?.email,
role: user?.role,
status: user?.status,
userId: user.user?._id,
membershipId: user._id,
publicKey: user.user?.publicKey,
}))
}));
setUserList(tempUserList);
const orgUsers = await getOrganizationUsers({
orgId: localStorage.getItem("orgData.id"),
@@ -122,7 +120,7 @@ export default function Users() {
?.map((user1) => user1.email)
.includes(email)
)[0]
)
);
}, []);
return userList ? (