Merge branch 'main' into feat-error-notifs

This commit is contained in:
asharonbaltazar
2022-12-06 13:10:31 -05:00
committed by GitHub
48 changed files with 692 additions and 394 deletions
@@ -1,19 +1,27 @@
import React from "react";
import { useState } from "react";
import React, { useState } from "react";
import { useRouter } from "next/router";
import {
faCircle,
faCircleExclamation,
faE,
faEye,
faEyeSlash,
} from "@fortawesome/free-solid-svg-icons";
import { faCircle, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
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 router = useRouter();
@@ -67,7 +75,7 @@ const InputField = (props) => {
>
<input
onChange={(e) => props.onChangeHandler(e.target.value)}
type={passwordVisible == false ? props.type : "text"}
type={passwordVisible === false ? props.type : "text"}
placeholder={props.placeholder}
value={props.value}
required={props.isRequired}
@@ -1,3 +1,4 @@
/* eslint-disable no-unexpected-multiline */
/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useState } from "react";
import Link from "next/link";
@@ -19,8 +20,10 @@ import getOrganizationUsers from "~/pages/api/organization/GetOrgUsers";
import addUserToWorkspace from "~/pages/api/workspace/addUserToWorkspace";
import createWorkspace from "~/pages/api/workspace/createWorkspace";
import getWorkspaces from "~/pages/api/workspace/getWorkspaces";
import uploadKeys from "~/pages/api/workspace/uploadKeys";
import NavBarDashboard from "../navigation/NavBarDashboard";
import { tempLocalStorage } from "../utilities/checks/tempLocalStorage";
import {
decryptAssymmetric,
encryptAssymmetric,
@@ -29,13 +32,17 @@ import Button from "./buttons/Button";
import AddWorkspaceDialog from "./dialog/AddWorkspaceDialog";
import Listbox from "./Listbox";
export default function Layout({ children }) {
interface LayoutProps {
children: React.ReactNode;
}
export default function Layout({ children }: LayoutProps) {
const router = useRouter();
const [workspaceList, setWorkspaceList] = useState([]);
const [workspaceMapping, setWorkspaceMapping] = useState([{ 1: 2 }]);
const [workspaceSelected, setWorkspaceSelected] = useState("∞");
let [newWorkspaceName, setNewWorkspaceName] = useState("");
let [isOpen, setIsOpen] = useState(false);
const [newWorkspaceName, setNewWorkspaceName] = useState("");
const [isOpen, setIsOpen] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
@@ -43,165 +50,186 @@ export default function Layout({ children }) {
setIsOpen(false);
}
function openModal() {
setIsOpen(true);
}
// 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.
* @param {*} workspaceName
*/
async function submitModal(workspaceName, addAllUsers) {
async function submitModal(workspaceName: string, addAllUsers: boolean) {
setLoading(true);
// timeout code.
setTimeout(() => setLoading(false), 1500);
const workspaces = await getWorkspaces();
const currentWorkspaces = workspaces.map((workspace) => workspace.name);
if (!currentWorkspaces.includes(workspaceName)) {
const newWorkspace = await createWorkspace(
workspaceName,
localStorage.getItem("orgData.id")
);
let newWorkspaceId;
try {
newWorkspaceId = newWorkspace._id;
} catch (error) {
console.log(error);
}
if (addAllUsers) {
let orgUsers = await getOrganizationUsers({
orgId: localStorage.getItem("orgData.id"),
try {
const workspaces = await getWorkspaces();
const currentWorkspaces = workspaces.map((workspace) => workspace.name);
if (!currentWorkspaces.includes(workspaceName)) {
const newWorkspace = await createWorkspace({
workspaceName,
organizationId: tempLocalStorage("orgData.id"),
});
orgUsers.map(async (user) => {
if (user.status == "accepted") {
let result = await addUserToWorkspace(
user.user.email,
newWorkspaceId
);
if (result?.invitee && result?.latestKey) {
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY");
const newWorkspaceId = newWorkspace._id;
// assymmetrically decrypt symmetric key with local private key
const key = decryptAssymmetric({
ciphertext: result.latestKey.encryptedKey,
nonce: result.latestKey.nonce,
publicKey: result.latestKey.sender.publicKey,
privateKey: PRIVATE_KEY,
});
if (addAllUsers) {
const orgUsers = await getOrganizationUsers({
orgId: tempLocalStorage("orgData.id"),
});
orgUsers.map(async (user: any) => {
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({
plaintext: key,
publicKey: result.invitee.publicKey,
privateKey: PRIVATE_KEY,
});
// assymmetrically decrypt symmetric key with local private key
const key = decryptAssymmetric({
ciphertext: result.latestKey.encryptedKey,
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");
setIsOpen(false);
setNewWorkspaceName("");
} else {
setError("A project with this name already exists.");
} catch (err) {
console.error(err);
setError(true);
setLoading(false);
}
}
function openModal() {
setIsOpen(true);
}
const menuItems = [
{
href:
"/dashboard/" + workspaceMapping[workspaceSelected] + "?Development",
"/dashboard/" +
workspaceMapping[workspaceSelected as any] +
"?Development",
title: "Secrets",
emoji: <FontAwesomeIcon icon={faKey} />,
},
{
href: "/users/" + workspaceMapping[workspaceSelected],
href: "/users/" + workspaceMapping[workspaceSelected as any],
title: "Members",
emoji: <FontAwesomeIcon icon={faUser} />,
},
{
href: "/integrations/" + workspaceMapping[workspaceSelected],
href: "/integrations/" + workspaceMapping[workspaceSelected as any],
title: "Integrations",
emoji: <FontAwesomeIcon icon={faPlug} />,
},
{
href: "/settings/project/" + workspaceMapping[workspaceSelected],
href: "/settings/project/" + workspaceMapping[workspaceSelected as any],
title: "Project Settings",
emoji: <FontAwesomeIcon icon={faGear} />,
},
];
useEffect(async () => {
useEffect(() => {
// Put a user in a workspace if they're not in one yet
if (
localStorage.getItem("orgData.id") == null ||
localStorage.getItem("orgData.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 putUserInWorkSpace = async () => {
if (tempLocalStorage("orgData.id") === "") {
const userOrgs = await getOrganizations();
localStorage.setItem("orgData.id", userOrgs[0]._id);
}
}
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(() => {
try {
if (
workspaceMapping[workspaceSelected] &&
workspaceMapping[workspaceSelected] !==
workspaceMapping[Number(workspaceSelected)] &&
`${workspaceMapping[Number(workspaceSelected)]}` !==
router.asPath
.split("/")
[router.asPath.split("/").length - 1].split("?")[0]
) {
router.push(
"/dashboard/" + workspaceMapping[workspaceSelected] + "?Development"
"/dashboard/" +
workspaceMapping[Number(workspaceSelected)] +
"?Development"
);
localStorage.setItem(
"projectData.id",
workspaceMapping[workspaceSelected]
`${workspaceMapping[Number(workspaceSelected)]}`
);
}
} catch (error) {
@@ -218,18 +246,18 @@ export default function Layout({ children }) {
<nav className="flex flex-col justify-between items-between h-full">
{/* <div className="py-6"></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">
PROJECT
</div>
{workspaceList.length > 0 ? (
<Listbox
selected={workspaceSelected}
onChange={setWorkspaceSelected}
onChange={setWorkspaceSelected as any}
data={workspaceList}
buttonAction={openModal}
text=""
workspaceMapping={workspaceMapping}
// workspaceMapping={workspaceMapping as any}
/>
) : (
<Button
@@ -255,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`}
>
<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}
</div>
) : router.asPath == "/noprojects" ? (
<div className={`flex p-2.5 text-white text-sm rounded`}>
<p className="w-10 flex items-center justify-center text-lg">{emoji}</p>
<div
className={`flex p-2.5 text-white text-sm rounded`}
>
<p className="w-10 flex items-center justify-center text-lg">
{emoji}
</p>
{title}
</div>
) : (
@@ -268,7 +302,9 @@ export default function Layout({ children }) {
<div
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}
</div>
</Link>
@@ -283,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`}
>
<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
</div>
) : (
<Link href={`/home/` + workspaceMapping[workspaceSelected]}>
<Link
href={`/home/` + workspaceMapping[workspaceSelected as any]}
>
<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`}
>
<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
</div>
</Link>
@@ -311,7 +353,7 @@ export default function Layout({ children }) {
<main className="flex-1 bg-bunker-800">{children}</main>
</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
icon={faMobile}
className="text-gray-300 text-7xl mb-8"
+10 -11
View File
@@ -8,14 +8,13 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Listbox, Transition } from "@headlessui/react";
type ListBoxProps = {
selected: string,
onChange: () => void,
data: string[],
text: string,
buttonAction: () => void,
width: string,
interface ListBoxProps {
selected: string;
onChange: () => void;
data: string[];
text: string;
buttonAction: () => void;
isFull?: boolean;
}
/**
@@ -35,14 +34,14 @@ export default function ListBox({
data,
text,
buttonAction,
width,
} : ListBoxProps): JSX.Element {
isFull,
}: ListBoxProps): JSX.Element {
return (
<Listbox value={selected} onChange={onChange}>
<div className="relative">
<Listbox.Button
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`}
>
<div className="flex flex-row">
+6 -6
View File
@@ -6,13 +6,13 @@ import {
FontAwesomeIconProps,
} from "@fortawesome/react-fontawesome";
var classNames = require("classnames");
const classNames = require("classnames");
type ButtonProps = {
text: string;
onButtonPressed: () => void;
loading?: boolean;
color: string;
color?: string;
size: string;
icon?: IconProp;
active?: boolean;
@@ -40,7 +40,7 @@ export default function Button(props: ButtonProps): JSX.Element {
const activityStatus =
props.active || (props.text != "" && props.textDisabled == undefined);
let styleButton = classNames(
const styleButton = classNames(
"group m-auto md:m-0 inline-block rounded-md duration-200",
// Setting background colors and hover modes
@@ -67,7 +67,7 @@ export default function Button(props: ButtonProps): JSX.Element {
props.size == "icon-sm" && "h-9 w-9 flex items-center justify-center"
);
let styleMainDiv = classNames(
const styleMainDiv = classNames(
"relative font-medium flex items-center",
// Setting the text color for the text and icon
@@ -79,11 +79,11 @@ export default function Button(props: ButtonProps): JSX.Element {
props.size == "icon" && "flex items-center justify-center"
);
let textStyle = classNames(
const textStyle = classNames(
"relative duration-200",
// Show the loading sign if the loading indicator is on
Boolean(props.loading) ? "opacity-0" : "opacity-100",
props.loading ? "opacity-0" : "opacity-100",
props.size == "md" && "text-sm",
props.size == "lg" && "text-lg"
);
@@ -37,7 +37,7 @@ const AddServiceTokenDialog = ({
const [serviceTokenCopied, setServiceTokenCopied] = useState(false);
const generateServiceToken = async () => {
const latestFileKey = await getLatestFileKey(workspaceId);
const latestFileKey = await getLatestFileKey({ workspaceId });
const key = decryptAssymmetric({
ciphertext: latestFileKey.latestKey.encryptedKey,
+1 -1
View File
@@ -88,7 +88,7 @@ const UserTable = ({
}, [userData, myUser]);
const grantAccess = async (id, publicKey) => {
let result = await getLatestFileKey(router.query.id);
let result = await getLatestFileKey({workspaceId: router.query.id});
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY");
@@ -47,27 +47,44 @@ const supportOptions = [
],
];
export default function Navbar({ onButtonPressed }) {
const router = useRouter();
const [user, setUser] = useState({});
const [orgs, setOrgs] = useState([]);
const [currentOrg, setCurrentOrg] = useState([]);
export interface ICurrentOrg {
name: string;
}
useEffect(async () => {
const userData = await getUser();
setUser(userData);
const orgsData = await getOrganizations();
setOrgs(orgsData);
const currentOrg = await getOrganization({
orgId: localStorage.getItem("orgData.id"),
});
setCurrentOrg(currentOrg);
export interface IUser {
firstName: string;
lastName: string;
email: string;
}
/**
* This is the navigation bar in the main app.
* It has two main components: support options and user menu (inlcudes billing, logout, org/user settings)
* @returns NavBar
*/
export default function Navbar() {
const router = useRouter();
const [user, setUser] = useState<IUser | undefined>();
const [orgs, setOrgs] = useState([]);
const [currentOrg, setCurrentOrg] = useState<ICurrentOrg | undefined>();
useEffect(() => {
(async () => {
const userData = await getUser();
setUser(userData);
const orgsData = await getOrganizations();
setOrgs(orgsData);
const currentOrg = await getOrganization({
orgId: String(localStorage.getItem("orgData.id")),
});
setCurrentOrg(currentOrg);
})();
}, []);
const closeApp = async () => {
console.log("Logging out...");
await logout();
router.push("/");
router.push("/login");
};
return (
@@ -108,7 +125,7 @@ export default function Navbar({ onButtonPressed }) {
key={guidGenerator()}
target="_blank"
rel="noopener"
href={option[2]}
href={String(option[2])}
className="font-normal text-gray-300 duration-200 rounded-md w-full flex items-center py-0.5"
>
<div 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">
@@ -238,9 +255,9 @@ export default function Navbar({ onButtonPressed }) {
<div className="flex flex-col items-start px-1 mt-3 mb-2">
{orgs
.filter(
(org) => org._id != localStorage.getItem("orgData.id")
(org : { _id: string }) => org._id != localStorage.getItem("orgData.id")
)
.map((org) => (
.map((org : { _id: string; name: string; }) => (
<div
key={guidGenerator()}
onClick={() => {
@@ -1,29 +1,37 @@
import React, { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { faCcMastercard, faCcVisa } from "@fortawesome/free-brands-svg-icons";
import {
faAngleRight,
faQuestionCircle,
} from "@fortawesome/free-solid-svg-icons";
import { faCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import getOrganization from "~/pages/api/organization/GetOrg";
import getWorkspaceInfo from "~/pages/api/workspace/getWorkspaceInfo";
import getProjectInfo from "~/pages/api/workspace/getProjectInfo";
export default function NavHeader({ pageName, isProjectRelated }) {
/**
* This is the component at the top of almost every page.
* It shows how to navigate to a certain page.
* It future these links should also be clickable and hoverable
* @param obj
* @param obj.pageName - Name of the page
* @param obj.isProjectRelated - whether this page is related to project or now (determine if it's 2 or 3 navigation steps)
* @returns
*/
export default function NavHeader({ pageName, isProjectRelated } : { pageName: string; isProjectRelated: boolean; }): JSX.Element {
const [orgName, setOrgName] = useState("");
const [workspaceName, setWorkspaceName] = useState("");
const router = useRouter();
useEffect(() => {
(async () => {
let org = await getOrganization({
orgId: localStorage.getItem("orgData.id"),
const orgId = localStorage.getItem("orgData.id")
const org = await getOrganization({
orgId: orgId ? orgId : "",
});
setOrgName(org.name);
let workspace = await getWorkspaceInfo({
workspaceId: router.query.id,
const workspace = await getProjectInfo({
projectId: String(router.query.id),
});
setWorkspaceName(workspace.name);
})();
@@ -3,7 +3,7 @@ import token from "~/pages/api/auth/Token";
export default class SecurityClient {
static #token = "";
contructor() {}
constructor() {}
static setToken(token) {
this.#token = token;
+8 -15
View File
@@ -32,7 +32,6 @@ const attemptLogin = async (
isLogin
) => {
try {
let userWorkspace, userOrg;
client.init(
{
username: email,
@@ -43,7 +42,7 @@ const attemptLogin = async (
let serverPublicKey, salt;
try {
const res = await login1(email, clientPublicKey);
let res = await login1(email, clientPublicKey);
res = await res.json();
serverPublicKey = res.serverPublicKey;
salt = res.salt;
@@ -134,20 +133,14 @@ const attemptLogin = async (
// If user is logging in for the first time, add the example keys
if (isSignUp) {
await pushKeys(
{
await pushKeys({
obj: {
DATABASE_URL: [
"mongodb+srv://${DB_USERNAME}:${DB_PASSWORD}@mongodb.net",
"personal",
],
DB_USERNAME: [
"user1234",
"personal",
],
DB_PASSWORD: [
"ah8jak3hk8dhiu4dw7whxwe1l",
"personal",
],
DB_USERNAME: ["user1234", "personal"],
DB_PASSWORD: ["ah8jak3hk8dhiu4dw7whxwe1l", "personal"],
TWILIO_AUTH_TOKEN: [
"hgSIwDAKvz8PJfkj6xkzYqzGmAP3HLuG",
"shared",
@@ -155,9 +148,9 @@ const attemptLogin = async (
WEBSITE_URL: ["http://localhost:3000", "shared"],
STRIPE_SECRET_KEY: ["sk_test_7348oyho4hfq398HIUOH78", "shared"],
},
projectToLogin,
"Development"
);
workspaceId: projectToLogin,
env: "Development"
});
}
try {
if (email) {
@@ -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.
* @param {*} password
* @param {*} setPasswordError
* @param {*} setPasswordErrorMessage
* @param {*} currentErrorCheck
* @returns
*/
const passwordCheck = (
const passwordCheck = ({
password,
setPasswordErrorLength,
setPasswordErrorNumber,
setPasswordErrorLowerCase,
currentErrorCheck
) => {
currentErrorCheck,
}: PasswordCheckProps) => {
let errorCheck = currentErrorCheck;
if (!password || password.length < 14) {
setPasswordErrorLength(true);
@@ -0,0 +1,11 @@
// this is temporary util function. 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;
};
@@ -108,11 +108,7 @@ const changePassword = async (
}
);
} catch (error) {
console.log(
"Something went wrong during changing the password",
slat,
serverPublicKey
);
console.log("Something went wrong during changing the password");
}
return true;
};
@@ -7,20 +7,30 @@ import { envMapping } from "../../../public/data/frequentConstants";
const crypto = require("crypto");
const {
decryptAssymmetric,
decryptSymmetric,
encryptSymmetric,
encryptAssymmetric,
} = require("../cryptography/crypto");
const nacl = require("tweetnacl");
nacl.util = require("tweetnacl-util");
export interface IK {
publicKey: string;
userId: string;
}
const pushKeys = async (obj, workspaceId, env) => {
let sharedKey = await getLatestFileKey(workspaceId);
/**
* This function pushes the keys to the database after decrypting them end-to-end
* @param {object} obj
* @param {object} obj.obj - object with all the key pairs
* @param {object} obj.workspaceId - the id of a project to which a user is pushing
* @param {object} obj.env - which environment a user is pushing to
*/
const pushKeys = async({ obj, workspaceId, env }: { obj: object; workspaceId: string; env: string; }) => {
const sharedKey = await getLatestFileKey({ workspaceId });
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY");
let randomBytes;
let randomBytes: string;
if (Object.keys(sharedKey).length > 0) {
// case: a (shared) key exists for the workspace
randomBytes = decryptAssymmetric({
@@ -51,11 +61,11 @@ const pushKeys = async (obj, workspaceId, env) => {
iv: ivValue,
tag: tagValue,
} = encryptSymmetric({
plaintext: obj[key][0],
plaintext: obj[key as keyof typeof obj][0],
key: randomBytes,
});
const visibility = obj[key][1] != null ? obj[key][1] : "personal";
const visibility = obj[key as keyof typeof obj][1] != null ? obj[key as keyof typeof obj][1] : "personal";
return {
ciphertextKey,
@@ -65,7 +75,7 @@ const pushKeys = async (obj, workspaceId, env) => {
ciphertextValue,
ivValue,
tagValue,
hashValue: crypto.createHash("sha256").update(obj[key][0]).digest("hex"),
hashValue: crypto.createHash("sha256").update(obj[key as keyof typeof obj][0]).digest("hex"),
type: visibility,
};
});
@@ -76,7 +86,7 @@ const pushKeys = async (obj, workspaceId, env) => {
});
// assymmetrically encrypt key with each receiver public keys
const keys = publicKeys.map((k) => {
const keys = publicKeys.map((k: IK) => {
const { ciphertext, nonce } = encryptAssymmetric({
plaintext: randomBytes,
publicKey: k.publicKey,
@@ -95,7 +105,7 @@ const pushKeys = async (obj, workspaceId, env) => {
workspaceId,
secrets,
keys,
environment: envMapping[env],
environment: envMapping[env as keyof typeof envMapping],
});
};