Convert JS to TS

This commit is contained in:
seunghyunOh
2022-12-06 05:53:34 +09:00
parent 3e2ed62e50
commit a47decd31f
13 changed files with 304 additions and 222 deletions
@@ -1,19 +1,27 @@
import React from "react"; import React, { useState } from "react";
import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { faCircle, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
faCircle,
faCircleExclamation,
faE,
faEye,
faEyeSlash,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import guidGenerator from "../utilities/randomId"; import guidGenerator from "../utilities/randomId";
import Error from "./Error";
const InputField = (props) => { interface InputFieldProps {
static?: boolean;
label: string;
type: string;
value: string;
placeholder?: string;
isRequired: boolean;
disabled?: boolean;
error?: boolean;
text?: string;
name?: string;
blurred?: boolean;
errorText?: string;
onChangeHandler: (value: string) => void;
}
const InputField = (props: InputFieldProps) => {
const [passwordVisible, setPasswordVisible] = useState(false); const [passwordVisible, setPasswordVisible] = useState(false);
const router = useRouter(); const router = useRouter();
@@ -67,7 +75,7 @@ const InputField = (props) => {
> >
<input <input
onChange={(e) => props.onChangeHandler(e.target.value)} onChange={(e) => props.onChangeHandler(e.target.value)}
type={passwordVisible == false ? props.type : "text"} type={passwordVisible === false ? props.type : "text"}
placeholder={props.placeholder} placeholder={props.placeholder}
value={props.value} value={props.value}
required={props.isRequired} required={props.isRequired}
@@ -1,3 +1,4 @@
/* eslint-disable no-unexpected-multiline */
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import Link from "next/link"; import Link from "next/link";
@@ -22,6 +23,7 @@ import getWorkspaces from "~/pages/api/workspace/getWorkspaces";
import uploadKeys from "~/pages/api/workspace/uploadKeys"; import uploadKeys from "~/pages/api/workspace/uploadKeys";
import NavBarDashboard from "../navigation/NavBarDashboard"; import NavBarDashboard from "../navigation/NavBarDashboard";
import { tempLocalStorage } from "../utilities/checks/tempLocalStorage";
import { import {
decryptAssymmetric, decryptAssymmetric,
encryptAssymmetric, encryptAssymmetric,
@@ -30,13 +32,17 @@ import Button from "./buttons/Button";
import AddWorkspaceDialog from "./dialog/AddWorkspaceDialog"; import AddWorkspaceDialog from "./dialog/AddWorkspaceDialog";
import Listbox from "./Listbox"; import Listbox from "./Listbox";
export default function Layout({ children }) { interface LayoutProps {
children: React.ReactNode;
}
export default function Layout({ children }: LayoutProps) {
const router = useRouter(); const router = useRouter();
const [workspaceList, setWorkspaceList] = useState([]); const [workspaceList, setWorkspaceList] = useState([]);
const [workspaceMapping, setWorkspaceMapping] = useState([{ 1: 2 }]); const [workspaceMapping, setWorkspaceMapping] = useState([{ 1: 2 }]);
const [workspaceSelected, setWorkspaceSelected] = useState("∞"); const [workspaceSelected, setWorkspaceSelected] = useState("∞");
let [newWorkspaceName, setNewWorkspaceName] = useState(""); const [newWorkspaceName, setNewWorkspaceName] = useState("");
let [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState(false); const [error, setError] = useState(false);
@@ -44,158 +50,186 @@ export default function Layout({ children }) {
setIsOpen(false); setIsOpen(false);
} }
function openModal() {
setIsOpen(true);
}
// TODO: what to do about the fact that 2ids can have the same name // TODO: what to do about the fact that 2ids can have the same name
/** /**
* When a user creates a new workspace, redirect them to the page of the new workspace. * When a user creates a new workspace, redirect them to the page of the new workspace.
* @param {*} workspaceName * @param {*} workspaceName
*/ */
async function submitModal(workspaceName, addAllUsers) { async function submitModal(workspaceName: string, addAllUsers: boolean) {
setLoading(true); setLoading(true);
// timeout code.
setTimeout(() => setLoading(false), 1500); setTimeout(() => setLoading(false), 1500);
const workspaces = await getWorkspaces();
const currentWorkspaces = workspaces.map((workspace) => workspace.name); try {
if (!currentWorkspaces.includes(workspaceName)) { const workspaces = await getWorkspaces();
const newWorkspace = await createWorkspace({ const currentWorkspaces = workspaces.map((workspace) => workspace.name);
workspaceName, if (!currentWorkspaces.includes(workspaceName)) {
organizationId: localStorage.getItem("orgData.id") const newWorkspace = await createWorkspace({
}); workspaceName,
let newWorkspaceId; organizationId: tempLocalStorage("orgData.id"),
try {
newWorkspaceId = newWorkspace._id;
} catch (error) {
console.log(error);
}
if (addAllUsers) {
let orgUsers = await getOrganizationUsers({
orgId: localStorage.getItem("orgData.id"),
}); });
orgUsers.map(async (user) => { const newWorkspaceId = newWorkspace._id;
if (user.status == "accepted") {
let result = await addUserToWorkspace(
user.user.email,
newWorkspaceId
);
if (result?.invitee && result?.latestKey) {
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY");
// assymmetrically decrypt symmetric key with local private key if (addAllUsers) {
const key = decryptAssymmetric({ const orgUsers = await getOrganizationUsers({
ciphertext: result.latestKey.encryptedKey, orgId: tempLocalStorage("orgData.id"),
nonce: result.latestKey.nonce, });
publicKey: result.latestKey.sender.publicKey, orgUsers.map(async (user: any) => {
privateKey: PRIVATE_KEY, if (user.status == "accepted") {
}); const result = await addUserToWorkspace(
user.user.email,
newWorkspaceId
);
if (result?.invitee && result?.latestKey) {
const PRIVATE_KEY = tempLocalStorage("PRIVATE_KEY");
const { ciphertext, nonce } = encryptAssymmetric({ // assymmetrically decrypt symmetric key with local private key
plaintext: key, const key = decryptAssymmetric({
publicKey: result.invitee.publicKey, ciphertext: result.latestKey.encryptedKey,
privateKey: PRIVATE_KEY, nonce: result.latestKey.nonce,
}); publicKey: result.latestKey.sender.publicKey,
privateKey: PRIVATE_KEY,
});
uploadKeys(newWorkspaceId, result.invitee._id, ciphertext, nonce); const { ciphertext, nonce } = encryptAssymmetric({
plaintext: key,
publicKey: result.invitee.publicKey,
privateKey: PRIVATE_KEY,
}) as { ciphertext: string; nonce: string };
uploadKeys(
newWorkspaceId,
result.invitee._id,
ciphertext,
nonce
);
}
} }
} });
}); }
router.push("/dashboard/" + newWorkspaceId + "?Development");
setIsOpen(false);
setNewWorkspaceName("");
} else {
console.error("A project with this name already exists.");
setError(true);
setLoading(false);
} }
router.push("/dashboard/" + newWorkspaceId + "?Development"); } catch (err) {
setIsOpen(false); console.error(err);
setNewWorkspaceName(""); setError(true);
} else {
setError("A project with this name already exists.");
setLoading(false); setLoading(false);
} }
} }
function openModal() {
setIsOpen(true);
}
const menuItems = [ const menuItems = [
{ {
href: href:
"/dashboard/" + workspaceMapping[workspaceSelected] + "?Development", "/dashboard/" +
workspaceMapping[workspaceSelected as any] +
"?Development",
title: "Secrets", title: "Secrets",
emoji: <FontAwesomeIcon icon={faKey} />, emoji: <FontAwesomeIcon icon={faKey} />,
}, },
{ {
href: "/users/" + workspaceMapping[workspaceSelected], href: "/users/" + workspaceMapping[workspaceSelected as any],
title: "Members", title: "Members",
emoji: <FontAwesomeIcon icon={faUser} />, emoji: <FontAwesomeIcon icon={faUser} />,
}, },
{ {
href: "/integrations/" + workspaceMapping[workspaceSelected], href: "/integrations/" + workspaceMapping[workspaceSelected as any],
title: "Integrations", title: "Integrations",
emoji: <FontAwesomeIcon icon={faPlug} />, emoji: <FontAwesomeIcon icon={faPlug} />,
}, },
{ {
href: "/settings/project/" + workspaceMapping[workspaceSelected], href: "/settings/project/" + workspaceMapping[workspaceSelected as any],
title: "Project Settings", title: "Project Settings",
emoji: <FontAwesomeIcon icon={faGear} />, emoji: <FontAwesomeIcon icon={faGear} />,
}, },
]; ];
useEffect(async () => { useEffect(() => {
// Put a user in a workspace if they're not in one yet // Put a user in a workspace if they're not in one yet
if ( const putUserInWorkSpace = async () => {
localStorage.getItem("orgData.id") == null || if (tempLocalStorage("orgData.id") === "") {
localStorage.getItem("orgData.id") == "" const userOrgs = await getOrganizations();
) { localStorage.setItem("orgData.id", userOrgs[0]._id);
const userOrgs = await getOrganizations();
localStorage.setItem("orgData.id", userOrgs[0]._id);
}
let orgUserProjects = await getOrganizationUserProjects({
orgId: localStorage.getItem("orgData.id"),
});
let userWorkspaces = orgUserProjects;
if (
userWorkspaces.length == 0 &&
router.asPath != "/noprojects" &&
!router.asPath.includes("settings")
) {
router.push("/noprojects");
} else if (router.asPath != "/noprojects") {
const intendedWorkspaceId = router.asPath
.split("/")[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
.map((workspace) => workspace._id)
.includes(intendedWorkspaceId)
) {
router.push("/dashboard/" + userWorkspaces[0]._id + "?Development");
} else {
setWorkspaceList(userWorkspaces.map((workspace) => workspace.name));
setWorkspaceMapping(
Object.fromEntries(
userWorkspaces.map((workspace) => [workspace.name, workspace._id])
)
);
setWorkspaceSelected(
Object.fromEntries(
userWorkspaces.map((workspace) => [workspace._id, workspace.name])
)[
router.asPath
.split("/")[router.asPath.split("/").length - 1].split("?")[0]]
);
} }
}
const orgUserProjects = await getOrganizationUserProjects({
orgId: tempLocalStorage("orgData.id"),
});
const userWorkspaces = orgUserProjects;
if (
userWorkspaces.length == 0 &&
router.asPath != "/noprojects" &&
!router.asPath.includes("settings")
) {
router.push("/noprojects");
} else if (router.asPath != "/noprojects") {
const intendedWorkspaceId = router.asPath
.split("/")
[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
.map((workspace: { _id: string }) => workspace._id)
.includes(intendedWorkspaceId)
) {
router.push("/dashboard/" + userWorkspaces[0]._id + "?Development");
} else {
setWorkspaceList(
userWorkspaces.map((workspace: any) => workspace.name)
);
setWorkspaceMapping(
Object.fromEntries(
userWorkspaces.map((workspace: any) => [
workspace.name,
workspace._id,
])
) as any
);
setWorkspaceSelected(
Object.fromEntries(
userWorkspaces.map((workspace: any) => [
workspace._id,
workspace.name,
])
)[
router.asPath
.split("/")
[router.asPath.split("/").length - 1].split("?")[0]
]
);
}
}
};
putUserInWorkSpace();
}, []); }, []);
useEffect(() => { useEffect(() => {
try { try {
if ( if (
workspaceMapping[workspaceSelected] && workspaceMapping[Number(workspaceSelected)] &&
workspaceMapping[workspaceSelected] !== `${workspaceMapping[Number(workspaceSelected)]}` !==
router.asPath router.asPath
.split("/")[router.asPath.split("/").length - 1].split("?")[0] .split("/")
[router.asPath.split("/").length - 1].split("?")[0]
) { ) {
router.push("/dashboard/" + workspaceMapping[workspaceSelected] + "?Development"); router.push(
"/dashboard/" +
workspaceMapping[Number(workspaceSelected)] +
"?Development"
);
localStorage.setItem( localStorage.setItem(
"projectData.id", "projectData.id",
workspaceMapping[workspaceSelected] `${workspaceMapping[Number(workspaceSelected)]}`
); );
} }
} catch (error) { } catch (error) {
@@ -212,18 +246,18 @@ export default function Layout({ children }) {
<nav className="flex flex-col justify-between items-between h-full"> <nav className="flex flex-col justify-between items-between h-full">
{/* <div className="py-6"></div> */} {/* <div className="py-6"></div> */}
<div> <div>
<div className="flex justify-center w-full mt-[4.5rem] mb-6 bg-bunker-600 w-full h-20 flex flex-col items-center px-4"> <div className="flex justify-center w-full mt-[4.5rem] mb-6 bg-bunker-600 h-20 flex-col items-center px-4">
<div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide"> <div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
PROJECT PROJECT
</div> </div>
{workspaceList.length > 0 ? ( {workspaceList.length > 0 ? (
<Listbox <Listbox
selected={workspaceSelected} selected={workspaceSelected}
onChange={setWorkspaceSelected} onChange={setWorkspaceSelected as any}
data={workspaceList} data={workspaceList}
buttonAction={openModal} buttonAction={openModal}
text="" text=""
workspaceMapping={workspaceMapping} // workspaceMapping={workspaceMapping as any}
/> />
) : ( ) : (
<Button <Button
@@ -249,12 +283,18 @@ export default function Layout({ children }) {
className={`flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10`} className={`flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10`}
> >
<div className="absolute top-0 my-1 ml-1 inset-0 bg-primary w-1 rounded-xl mr-1"></div> <div className="absolute top-0 my-1 ml-1 inset-0 bg-primary w-1 rounded-xl mr-1"></div>
<p className="w-6 ml-4 mr-2 flex items-center justify-center text-lg">{emoji}</p> <p className="w-6 ml-4 mr-2 flex items-center justify-center text-lg">
{emoji}
</p>
{title} {title}
</div> </div>
) : router.asPath == "/noprojects" ? ( ) : router.asPath == "/noprojects" ? (
<div className={`flex p-2.5 text-white text-sm rounded`}> <div
<p className="w-10 flex items-center justify-center text-lg">{emoji}</p> className={`flex p-2.5 text-white text-sm rounded`}
>
<p className="w-10 flex items-center justify-center text-lg">
{emoji}
</p>
{title} {title}
</div> </div>
) : ( ) : (
@@ -262,7 +302,9 @@ export default function Layout({ children }) {
<div <div
className={`flex p-2.5 text-white text-sm rounded cursor-pointer hover:bg-primary-50/5`} className={`flex p-2.5 text-white text-sm rounded cursor-pointer hover:bg-primary-50/5`}
> >
<p className="w-10 flex items-center justify-center text-lg">{emoji}</p> <p className="w-10 flex items-center justify-center text-lg">
{emoji}
</p>
{title} {title}
</div> </div>
</Link> </Link>
@@ -277,15 +319,21 @@ export default function Layout({ children }) {
className={`flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10`} className={`flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10`}
> >
<div className="absolute top-0 my-1 ml-1 inset-0 bg-primary w-1 rounded-xl mr-1"></div> <div className="absolute top-0 my-1 ml-1 inset-0 bg-primary w-1 rounded-xl mr-1"></div>
<p className="w-6 ml-4 mr-2 flex items-center justify-center text-lg"><FontAwesomeIcon icon={faBookOpen}/></p> <p className="w-6 ml-4 mr-2 flex items-center justify-center text-lg">
<FontAwesomeIcon icon={faBookOpen} />
</p>
Infisical Guide Infisical Guide
</div> </div>
) : ( ) : (
<Link href={`/home/` + workspaceMapping[workspaceSelected]}> <Link
href={`/home/` + workspaceMapping[workspaceSelected as any]}
>
<div <div
className={`flex p-2.5 text-white text-sm rounded cursor-pointer hover:bg-primary-50/5 mt-max border border-dashed border-bunker-400`} className={`flex p-2.5 text-white text-sm rounded cursor-pointer hover:bg-primary-50/5 mt-max border border-dashed border-bunker-400`}
> >
<p className="w-10 flex items-center justify-center text-lg"><FontAwesomeIcon icon={faBookOpen}/></p> <p className="w-10 flex items-center justify-center text-lg">
<FontAwesomeIcon icon={faBookOpen} />
</p>
Infisical Guide Infisical Guide
</div> </div>
</Link> </Link>
@@ -305,7 +353,7 @@ export default function Layout({ children }) {
<main className="flex-1 bg-bunker-800">{children}</main> <main className="flex-1 bg-bunker-800">{children}</main>
</div> </div>
</div> </div>
<div className="block md:hidden bg-bunker-800 w-screen h-screen flex flex-col justify-center items-center"> <div className="md:hidden bg-bunker-800 w-screen h-screen flex flex-col justify-center items-center">
<FontAwesomeIcon <FontAwesomeIcon
icon={faMobile} icon={faMobile}
className="text-gray-300 text-7xl mb-8" className="text-gray-300 text-7xl mb-8"
+10 -11
View File
@@ -8,14 +8,13 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Listbox, Transition } from "@headlessui/react"; import { Listbox, Transition } from "@headlessui/react";
interface ListBoxProps {
type ListBoxProps = { selected: string;
selected: string, onChange: () => void;
onChange: () => void, data: string[];
data: string[], text: string;
text: string, buttonAction: () => void;
buttonAction: () => void, isFull?: boolean;
width: string,
} }
/** /**
@@ -35,14 +34,14 @@ export default function ListBox({
data, data,
text, text,
buttonAction, buttonAction,
width, isFull,
} : ListBoxProps): JSX.Element { }: ListBoxProps): JSX.Element {
return ( return (
<Listbox value={selected} onChange={onChange}> <Listbox value={selected} onChange={onChange}>
<div className="relative"> <div className="relative">
<Listbox.Button <Listbox.Button
className={`text-gray-400 relative ${ className={`text-gray-400 relative ${
width == "full" ? "w-full" : "w-52" isFull ? "w-full" : "w-52"
} cursor-default rounded-md bg-white/[0.07] hover:bg-white/[0.11] duration-200 py-2.5 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm`} } cursor-default rounded-md bg-white/[0.07] hover:bg-white/[0.11] duration-200 py-2.5 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm`}
> >
<div className="flex flex-row"> <div className="flex flex-row">
+1 -1
View File
@@ -12,7 +12,7 @@ type ButtonProps = {
text: string; text: string;
onButtonPressed: () => void; onButtonPressed: () => void;
loading?: boolean; loading?: boolean;
color: string; color?: string;
size: string; size: string;
icon?: IconProp; icon?: IconProp;
active?: boolean; active?: boolean;
@@ -3,7 +3,7 @@ import token from "~/pages/api/auth/Token";
export default class SecurityClient { export default class SecurityClient {
static #token = ""; static #token = "";
contructor() {} constructor() {}
static setToken(token) { static setToken(token) {
this.#token = token; this.#token = token;
@@ -32,7 +32,6 @@ const attemptLogin = async (
isLogin isLogin
) => { ) => {
try { try {
let userWorkspace, userOrg;
client.init( client.init(
{ {
username: email, username: email,
@@ -140,14 +139,8 @@ const attemptLogin = async (
"mongodb+srv://${DB_USERNAME}:${DB_PASSWORD}@mongodb.net", "mongodb+srv://${DB_USERNAME}:${DB_PASSWORD}@mongodb.net",
"personal", "personal",
], ],
DB_USERNAME: [ DB_USERNAME: ["user1234", "personal"],
"user1234", DB_PASSWORD: ["ah8jak3hk8dhiu4dw7whxwe1l", "personal"],
"personal",
],
DB_PASSWORD: [
"ah8jak3hk8dhiu4dw7whxwe1l",
"personal",
],
TWILIO_AUTH_TOKEN: [ TWILIO_AUTH_TOKEN: [
"hgSIwDAKvz8PJfkj6xkzYqzGmAP3HLuG", "hgSIwDAKvz8PJfkj6xkzYqzGmAP3HLuG",
"shared", "shared",
@@ -1,18 +1,21 @@
interface PasswordCheckProps {
password: string;
currentErrorCheck: boolean;
setPasswordErrorLength: (value: boolean) => void;
setPasswordErrorNumber: (value: boolean) => void;
setPasswordErrorLowerCase: (value: boolean) => void;
}
/** /**
* This function checks a user password with respect to some criteria. * This function checks a user password with respect to some criteria.
* @param {*} password
* @param {*} setPasswordError
* @param {*} setPasswordErrorMessage
* @param {*} currentErrorCheck
* @returns
*/ */
const passwordCheck = ( const passwordCheck = ({
password, password,
setPasswordErrorLength, setPasswordErrorLength,
setPasswordErrorNumber, setPasswordErrorNumber,
setPasswordErrorLowerCase, setPasswordErrorLowerCase,
currentErrorCheck currentErrorCheck,
) => { }: PasswordCheckProps) => {
let errorCheck = currentErrorCheck; let errorCheck = currentErrorCheck;
if (!password || password.length < 14) { if (!password || password.length < 14) {
setPasswordErrorLength(true); setPasswordErrorLength(true);
@@ -0,0 +1,11 @@
// this function is temporary until. have to create error handling logic for localStorage and delete this.
export const tempLocalStorage = (key: string) => {
const value = localStorage.getItem(key);
if (value === null || value === "") {
console.warn("No value found in localStorage for key");
return "";
}
return value;
};
+1 -1
View File
@@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import { config } from "@fortawesome/fontawesome-svg-core"; import { config } from "@fortawesome/fontawesome-svg-core";
import { initPostHog } from "~/components/analytics/posthog"; import { initPostHog } from "~/components/analytics/posthog";
import Layout from "~/components/basic/layout"; import Layout from "~/components/basic/Layout";
import RouteGuard from "~/components/RouteGuard"; import RouteGuard from "~/components/RouteGuard";
import { publicPaths } from "~/const"; import { publicPaths } from "~/const";
import { ENV } from "~/utilities/config"; import { ENV } from "~/utilities/config";
@@ -6,7 +6,7 @@ import SecurityClient from "~/utilities/SecurityClient";
* @param {*} res * @param {*} res
* @returns * @returns
*/ */
const getOrganizationUserProjects = (req, res) => { const getOrganizationUserProjects = (req) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall(
"/api/v1/organization/" + req.orgId + "/my-workspaces", "/api/v1/organization/" + req.orgId + "/my-workspaces",
{ {
@@ -1,3 +1,5 @@
import { Workspaces } from "types/workspaces";
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from "~/utilities/SecurityClient";
/** /**
@@ -12,10 +14,11 @@ const getWorkspaces = () => {
}, },
}).then(async (res) => { }).then(async (res) => {
if (res?.status == 200) { if (res?.status == 200) {
return (await res.json()).workspaces; const data = (await res.json()) as unknown as { workspaces: Workspaces };
} else { return data.workspaces;
console.log("Failed to get projects");
} }
throw new Error("Failed to get projects");
}); });
}; };
@@ -1,4 +1,5 @@
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import ReactCodeInput from "react-code-input";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import Head from "next/head"; import Head from "next/head";
import Image from "next/image"; import Image from "next/image";
@@ -20,7 +21,7 @@ import completeAccountInformationSignup from "./api/auth/CompleteAccountInformat
import sendVerificationEmail from "./api/auth/SendVerificationEmail"; import sendVerificationEmail from "./api/auth/SendVerificationEmail";
import getWorkspaces from "./api/workspace/getWorkspaces"; import getWorkspaces from "./api/workspace/getWorkspaces";
const ReactCodeInput = dynamic(import("react-code-input")); // const ReactCodeInput = dynamic(import("react-code-input"));
const nacl = require("tweetnacl"); const nacl = require("tweetnacl");
const jsrp = require("jsrp"); const jsrp = require("jsrp");
nacl.util = require("tweetnacl-util"); nacl.util = require("tweetnacl-util");
@@ -42,7 +43,7 @@ const props = {
border: "1px solid gray", border: "1px solid gray",
textAlign: "center", textAlign: "center",
}, },
}; } as const;
const propsPhone = { const propsPhone = {
inputStyle: { inputStyle: {
fontFamily: "monospace", fontFamily: "monospace",
@@ -58,7 +59,7 @@ const propsPhone = {
border: "1px solid gray", border: "1px solid gray",
textAlign: "center", textAlign: "center",
}, },
}; } as const;
export default function SignUp() { export default function SignUp() {
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
@@ -85,15 +86,16 @@ export default function SignUp() {
const [verificationToken, setVerificationToken] = useState(); const [verificationToken, setVerificationToken] = useState();
const [backupKeyIssued, setBackupKeyIssued] = useState(false); const [backupKeyIssued, setBackupKeyIssued] = useState(false);
useEffect(async () => { useEffect(() => {
let userWorkspace; const tryAuth = async () => {
try { try {
const userWorkspaces = await getWorkspaces(); const userWorkspaces = await getWorkspaces();
userWorkspace = userWorkspaces[0]._id; router.push("/dashboard/" + userWorkspaces[0]._id);
router.push("/dashboard/" + userWorkspace); } catch (error) {
} catch (error) { console.log("Error - Not logged in yet");
console.log("Error - Not logged in yet"); }
} };
tryAuth();
}, []); }, []);
/** /**
@@ -108,7 +110,7 @@ export default function SignUp() {
} else if (step == 2) { } else if (step == 2) {
// Checking if the code matches the email. // Checking if the code matches the email.
const response = await checkEmailVerificationCode(email, code); const response = await checkEmailVerificationCode(email, code);
if (response.status == "200" || code == "111222") { if (response.status === 200 || code == "111222") {
setVerificationToken((await response.json()).token); setVerificationToken((await response.json()).token);
setStep(3); setStep(3);
} else { } else {
@@ -123,7 +125,7 @@ export default function SignUp() {
* Verifies if the entered email "looks" correct * Verifies if the entered email "looks" correct
*/ */
const emailCheck = () => { const emailCheck = () => {
var emailCheckBool = false; let emailCheckBool = false;
if (!email) { if (!email) {
setEmailError(true); setEmailError(true);
setEmailErrorMessage("Please enter your email."); setEmailErrorMessage("Please enter your email.");
@@ -150,7 +152,7 @@ export default function SignUp() {
// Verifies if the imformation that the users entered (name, workspace) is there, and if the password matched the criteria. // Verifies if the imformation that the users entered (name, workspace) is there, and if the password matched the criteria.
const signupErrorCheck = async () => { const signupErrorCheck = async () => {
setIsLoading(true); setIsLoading(true);
var errorCheck = false; let errorCheck = false;
if (!firstName) { if (!firstName) {
setFirstNameError(true); setFirstNameError(true);
errorCheck = true; errorCheck = true;
@@ -163,13 +165,13 @@ export default function SignUp() {
} else { } else {
setLastNameError(false); setLastNameError(false);
} }
errorCheck = passwordCheck( errorCheck = passwordCheck({
password, password,
setPasswordErrorLength, setPasswordErrorLength,
setPasswordErrorNumber, setPasswordErrorNumber,
setPasswordErrorLowerCase, setPasswordErrorLowerCase,
errorCheck currentErrorCheck: errorCheck,
); });
if (!errorCheck) { if (!errorCheck) {
// Generate a random pair of a public and a private key // Generate a random pair of a public and a private key
@@ -187,7 +189,8 @@ export default function SignUp() {
32 + (password.slice(0, 32).length - new Blob([password]).size), 32 + (password.slice(0, 32).length - new Blob([password]).size),
"0" "0"
) )
); ) as { ciphertext: string; iv: string; tag: string };
localStorage.setItem("PRIVATE_KEY", PRIVATE_KEY); localStorage.setItem("PRIVATE_KEY", PRIVATE_KEY);
client.init( client.init(
@@ -196,45 +199,47 @@ export default function SignUp() {
password: password, password: password,
}, },
async () => { async () => {
client.createVerifier(async (err, result) => { client.createVerifier(
let response = await completeAccountInformationSignup({ async (err: any, result: { salt: string; verifier: string }) => {
email, const response = await completeAccountInformationSignup({
firstName, email,
lastName, firstName,
organizationName: firstName + "'s organization", lastName,
publicKey: PUBLIC_KEY, organizationName: firstName + "'s organization",
ciphertext, publicKey: PUBLIC_KEY,
iv, ciphertext,
tag, iv,
salt: result.salt, tag,
verifier: result.verifier, salt: result.salt,
token: verificationToken, verifier: result.verifier,
}); token: verificationToken,
});
// if everything works, go the main dashboard page. // if everything works, go the main dashboard page.
if (!errorCheck && response.status == "200") { if (response.status === 200) {
response = await response.json(); // response = await response.json();
localStorage.setItem("publicKey", PUBLIC_KEY); localStorage.setItem("publicKey", PUBLIC_KEY);
localStorage.setItem("encryptedPrivateKey", ciphertext); localStorage.setItem("encryptedPrivateKey", ciphertext);
localStorage.setItem("iv", iv); localStorage.setItem("iv", iv);
localStorage.setItem("tag", tag); localStorage.setItem("tag", tag);
try { try {
await attemptLogin( await attemptLogin(
email, email,
password, password,
setErrorLogin, setErrorLogin,
router, router,
true, true,
false false
); );
incrementStep(); incrementStep();
} catch (error) { } catch (error) {
setIsLoading(false); setIsLoading(false);
}
} }
} }
}); );
} }
); );
} else { } else {
@@ -296,6 +301,8 @@ export default function SignUp() {
</p> </p>
<div className="hidden md:block"> <div className="hidden md:block">
<ReactCodeInput <ReactCodeInput
name=""
inputMode="tel"
type="text" type="text"
fields={6} fields={6}
onChange={setCode} onChange={setCode}
@@ -305,6 +312,8 @@ export default function SignUp() {
</div> </div>
<div className="block md:hidden"> <div className="block md:hidden">
<ReactCodeInput <ReactCodeInput
name=""
inputMode="tel"
type="text" type="text"
fields={6} fields={6}
onChange={setCode} onChange={setCode}
@@ -364,15 +373,15 @@ export default function SignUp() {
<div className="mt-2 flex flex-col items-center justify-center w-full md:p-2 rounded-lg max-h-60"> <div className="mt-2 flex flex-col items-center justify-center w-full md:p-2 rounded-lg max-h-60">
<InputField <InputField
label="Password" label="Password"
onChangeHandler={(password) => { onChangeHandler={(password: string) => {
setPassword(password); setPassword(password);
passwordCheck( passwordCheck({
password, password,
setPasswordErrorLength, setPasswordErrorLength,
setPasswordErrorNumber, setPasswordErrorNumber,
setPasswordErrorLowerCase, setPasswordErrorLowerCase,
false currentErrorCheck: false,
); });
}} }}
type="password" type="password"
value={password} value={password}
@@ -496,7 +505,7 @@ export default function SignUp() {
setBackupKeyIssued, setBackupKeyIssued,
}); });
const userWorkspaces = await getWorkspaces(); const userWorkspaces = await getWorkspaces();
let userWorkspace = userWorkspaces[0]._id; const userWorkspace = userWorkspaces[0]._id;
router.push("/home/" + userWorkspace); router.push("/home/" + userWorkspace);
}} }}
size="lg" size="lg"
+8
View File
@@ -0,0 +1,8 @@
export interface WorkSpace {
__v: number;
_id: string;
name: string;
organization: string;
}
type Workspaces = WorkSpace[];