diff --git a/backend/src/controllers/authController.ts b/backend/src/controllers/authController.ts index 9fbd58e93..eb537f2b9 100644 --- a/backend/src/controllers/authController.ts +++ b/backend/src/controllers/authController.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ import { Request, Response } from 'express'; import jwt from 'jsonwebtoken'; import * as Sentry from '@sentry/node'; @@ -5,17 +6,17 @@ import * as bigintConversion from 'bigint-conversion'; const jsrp = require('jsrp'); import { User } from '../models'; import { createToken, issueTokens, clearTokens } from '../helpers/auth'; -import { - NODE_ENV, - JWT_AUTH_LIFETIME, - JWT_AUTH_SECRET, - JWT_REFRESH_SECRET +import { + NODE_ENV, + JWT_AUTH_LIFETIME, + JWT_AUTH_SECRET, + JWT_REFRESH_SECRET } from '../config'; declare module 'jsonwebtoken' { - export interface UserIDJwtPayload extends jwt.JwtPayload { - userId: string; - } + export interface UserIDJwtPayload extends jwt.JwtPayload { + userId: string; + } } const clientPublicKeys: any = {}; @@ -27,47 +28,45 @@ const clientPublicKeys: any = {}; * @returns */ export const login1 = async (req: Request, res: Response) => { - try { - const { - email, - clientPublicKey - }: { email: string; clientPublicKey: string } = req.body; - - const user = await User.findOne({ - email - }).select('+salt +verifier'); - + try { + const { + email, + clientPublicKey + }: { email: string; clientPublicKey: string } = req.body; - if (!user) throw new Error('Failed to find user'); + const user = await User.findOne({ + email + }).select('+salt +verifier'); - const server = new jsrp.server(); - server.init( - { - salt: user.salt, - verifier: user.verifier - }, - () => { - // generate server-side public key - const serverPublicKey = server.getPublicKey(); - clientPublicKeys[email] = { - clientPublicKey, - serverBInt: bigintConversion.bigintToBuf(server.bInt) - }; - + if (!user) throw new Error('Failed to find user'); - return res.status(200).send({ - serverPublicKey, - salt: user.salt - }); - } - ); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Failed to start authentication process' - }); - } + const server = new jsrp.server(); + server.init( + { + salt: user.salt, + verifier: user.verifier + }, + () => { + // generate server-side public key + const serverPublicKey = server.getPublicKey(); + clientPublicKeys[email] = { + clientPublicKey, + serverBInt: bigintConversion.bigintToBuf(server.bInt) + }; + + return res.status(200).send({ + serverPublicKey, + salt: user.salt + }); + } + ); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to start authentication process' + }); + } }; /** @@ -78,59 +77,59 @@ export const login1 = async (req: Request, res: Response) => { * @returns */ export const login2 = async (req: Request, res: Response) => { - try { - const { email, clientProof } = req.body; - const user = await User.findOne({ - email - }).select('+salt +verifier +publicKey +encryptedPrivateKey +iv +tag'); + try { + const { email, clientProof } = req.body; + const user = await User.findOne({ + email + }).select('+salt +verifier +publicKey +encryptedPrivateKey +iv +tag'); - if (!user) throw new Error('Failed to find user'); + if (!user) throw new Error('Failed to find user'); - const server = new jsrp.server(); - server.init( - { - salt: user.salt, - verifier: user.verifier, - b: clientPublicKeys[email].serverBInt - }, - async () => { - server.setClientPublicKey(clientPublicKeys[email].clientPublicKey); + const server = new jsrp.server(); + server.init( + { + salt: user.salt, + verifier: user.verifier, + b: clientPublicKeys[email].serverBInt + }, + async () => { + server.setClientPublicKey(clientPublicKeys[email].clientPublicKey); - // compare server and client shared keys - if (server.checkClientProof(clientProof)) { - // issue tokens - const tokens = await issueTokens({ userId: user._id.toString() }); - - // store (refresh) token in httpOnly cookie - res.cookie('jid', tokens.refreshToken, { - httpOnly: true, - path: '/token', - sameSite: "strict", - secure: NODE_ENV === 'production' ? true : false - }); + // compare server and client shared keys + if (server.checkClientProof(clientProof)) { + // issue tokens + const tokens = await issueTokens({ userId: user._id.toString() }); - // return (access) token in response - return res.status(200).send({ - token: tokens.token, - publicKey: user.publicKey, - encryptedPrivateKey: user.encryptedPrivateKey, - iv: user.iv, - tag: user.tag - }); - } + // store (refresh) token in httpOnly cookie + res.cookie('jid', tokens.refreshToken, { + httpOnly: true, + path: '/token', + sameSite: 'strict', + secure: NODE_ENV === 'production' ? true : false + }); - return res.status(400).send({ - message: 'Failed to authenticate. Try again?' - }); - } - ); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Failed to authenticate. Try again?' - }); - } + // return (access) token in response + return res.status(200).send({ + token: tokens.token, + publicKey: user.publicKey, + encryptedPrivateKey: user.encryptedPrivateKey, + iv: user.iv, + tag: user.tag + }); + } + + return res.status(400).send({ + message: 'Failed to authenticate. Try again?' + }); + } + ); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to authenticate. Try again?' + }); + } }; /** @@ -140,29 +139,29 @@ export const login2 = async (req: Request, res: Response) => { * @returns */ export const logout = async (req: Request, res: Response) => { - try { - await clearTokens({ - userId: req.user._id.toString() - }); - - // clear httpOnly cookie - res.cookie('jid', '', { - httpOnly: true, - path: '/token', - sameSite: "strict", - secure: NODE_ENV === 'production' ? true : false - }); - } catch (err) { - Sentry.setUser({ email: req.user.email }); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Failed to logout' - }); - } + try { + await clearTokens({ + userId: req.user._id.toString() + }); - return res.status(200).send({ - message: 'Successfully logged out.' - }); + // clear httpOnly cookie + res.cookie('jid', '', { + httpOnly: true, + path: '/token', + sameSite: 'strict', + secure: NODE_ENV === 'production' ? true : false + }); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to logout' + }); + } + + return res.status(200).send({ + message: 'Successfully logged out.' + }); }; /** @@ -172,9 +171,9 @@ export const logout = async (req: Request, res: Response) => { * @returns */ export const checkAuth = async (req: Request, res: Response) => - res.status(200).send({ - message: 'Authenticated' - }); + res.status(200).send({ + message: 'Authenticated' + }); /** * Return new token by redeeming refresh token @@ -183,42 +182,41 @@ export const checkAuth = async (req: Request, res: Response) => * @returns */ export const getNewToken = async (req: Request, res: Response) => { - try { - const refreshToken = req.cookies.jid; - - if (!refreshToken) { - throw new Error('Failed to find token in request cookies'); - } - - const decodedToken = ( - jwt.verify(refreshToken, JWT_REFRESH_SECRET) - ); - - const user = await User.findOne({ - _id: decodedToken.userId - }).select('+publicKey'); + try { + const refreshToken = req.cookies.jid; - if (!user) throw new Error('Failed to authenticate unfound user'); - if (!user?.publicKey) - throw new Error('Failed to authenticate not fully set up account'); - - const token = createToken({ - payload: { - userId: decodedToken.userId - }, - expiresIn: JWT_AUTH_LIFETIME, - secret: JWT_AUTH_SECRET - }); - - return res.status(200).send({ - token - }); - - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Invalid request' - }); - } + if (!refreshToken) { + throw new Error('Failed to find token in request cookies'); + } + + const decodedToken = ( + jwt.verify(refreshToken, JWT_REFRESH_SECRET) + ); + + const user = await User.findOne({ + _id: decodedToken.userId + }).select('+publicKey'); + + if (!user) throw new Error('Failed to authenticate unfound user'); + if (!user?.publicKey) + throw new Error('Failed to authenticate not fully set up account'); + + const token = createToken({ + payload: { + userId: decodedToken.userId + }, + expiresIn: JWT_AUTH_LIFETIME, + secret: JWT_AUTH_SECRET + }); + + return res.status(200).send({ + token + }); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Invalid request' + }); + } }; diff --git a/backend/src/routes/auth.ts b/backend/src/routes/auth.ts index 43a57fe7e..6be9c09f7 100644 --- a/backend/src/routes/auth.ts +++ b/backend/src/routes/auth.ts @@ -5,28 +5,24 @@ import { requireAuth, validateRequest } from '../middleware'; import { authController } from '../controllers'; import { loginLimiter } from '../helpers/rateLimiter'; +router.post('/token', validateRequest, authController.getNewToken); + router.post( - '/token', - validateRequest, - authController.getNewToken + '/login1', + loginLimiter, + body('email').exists().trim().notEmpty(), + body('clientPublicKey').exists().trim().notEmpty(), + validateRequest, + authController.login1 ); router.post( - '/login1', - loginLimiter, - body('email').exists().trim().notEmpty(), - body('clientPublicKey').exists().trim().notEmpty(), - validateRequest, - authController.login1 -); - -router.post( - '/login2', - loginLimiter, - body('email').exists().trim().notEmpty(), - body('clientProof').exists().trim().notEmpty(), - validateRequest, - authController.login2 + '/login2', + loginLimiter, + body('email').exists().trim().notEmpty(), + body('clientProof').exists().trim().notEmpty(), + validateRequest, + authController.login2 ); router.post('/logout', requireAuth, authController.logout); diff --git a/frontend/components/RouteGuard.js b/frontend/components/RouteGuard.js index a21c0c86a..d08972b99 100644 --- a/frontend/components/RouteGuard.js +++ b/frontend/components/RouteGuard.js @@ -1,9 +1,9 @@ -import { useEffect, useState } from "react"; -import Image from "next/image"; -import { useRouter } from "next/router"; +import { useEffect, useState } from 'react'; +import Image from 'next/image'; +import { useRouter } from 'next/router'; -import { publicPaths } from "~/const"; -import checkAuth from "~/pages/api/auth/CheckAuth"; +import { publicPaths } from '~/const'; +import checkAuth from '~/pages/api/auth/CheckAuth'; // #TODO: finish spinner only when the data loads fully // #TODO: Redirect somewhere if the page does not exist @@ -22,16 +22,16 @@ export default function RouteGuard({ children }) { // #TODO: add the loading page when not yet authorized. const hideContent = () => setAuthorized(false); // const onError = () => setAuthorized(true) - router.events.on("routeChangeStart", hideContent); + router.events.on('routeChangeStart', hideContent); // router.events.on("routeChangeError", onError); // on route change complete - run auth check - router.events.on("routeChangeComplete", authCheck); + router.events.on('routeChangeComplete', authCheck); // unsubscribe from events in useEffect return function return () => { - router.events.off("routeChangeStart", hideContent); - router.events.off("routeChangeComplete", authCheck); + router.events.off('routeChangeStart', hideContent); + router.events.off('routeChangeComplete', authCheck); // router.events.off("routeChangeError", onError); }; // eslint-disable-next-line react-hooks/exhaustive-deps @@ -43,7 +43,7 @@ export default function RouteGuard({ children }) { */ async function authCheck(url) { // Make sure that we don't redirect when the user is on the following pages. - const path = "/" + url.split("?")[0].split("/")[1]; + const path = '/' + url.split('?')[0].split('/')[1]; // Check if the user is authenticated const response = await checkAuth(); @@ -51,16 +51,16 @@ export default function RouteGuard({ children }) { if (!publicPaths.includes(path)) { try { if (response.status !== 200) { - router.push("/login"); - console.log("Unauthorized to access."); + router.push('/login'); + console.log('Unauthorized to access.'); setAuthorized(false); } else { setAuthorized(true); - console.log("Authorized to access."); + console.log('Authorized to access.'); } } catch (error) { console.log( - "Error (probably the authCheck route is stuck again...):", + 'Error (probably the authCheck route is stuck again...):', error ); } diff --git a/frontend/components/analytics/posthog.ts b/frontend/components/analytics/posthog.ts new file mode 100644 index 000000000..e0d6e7c09 --- /dev/null +++ b/frontend/components/analytics/posthog.ts @@ -0,0 +1,18 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +/* eslint-disable no-undef */ +import posthog from 'posthog-js'; + +import { ENV, POSTHOG_API_KEY, POSTHOG_HOST } from '../utilities/config'; + +export const initPostHog = () => { + if (typeof window !== 'undefined') { + // @ts-ignore + if (ENV == 'production' && TELEMETRY_CAPTURING_ENABLED) { + posthog.init(POSTHOG_API_KEY, { + api_host: POSTHOG_HOST + }); + } + } + + return posthog; +}; diff --git a/frontend/components/basic/InputField.tsx b/frontend/components/basic/InputField.tsx index 139304ea6..141578214 100644 --- a/frontend/components/basic/InputField.tsx +++ b/frontend/components/basic/InputField.tsx @@ -1,9 +1,9 @@ -import React, { useState } from "react"; -import { useRouter } from "next/router"; -import { faCircle, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import React, { useState } from 'react'; +import { useRouter } from 'next/router'; +import { faCircle, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import guidGenerator from "../utilities/randomId"; +import guidGenerator from '../utilities/randomId'; interface InputFieldProps { static?: boolean; @@ -23,7 +23,7 @@ interface InputFieldProps { const InputField = ( props: InputFieldProps & - Pick + Pick ) => { const [passwordVisible, setPasswordVisible] = useState(false); const router = useRouter(); @@ -75,28 +75,28 @@ const InputField = (
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} className={`${ props.blurred - ? "text-bunker-800 group-hover:text-gray-400 focus:text-gray-400 active:text-gray-400" - : "" + ? 'text-bunker-800 group-hover:text-gray-400 focus:text-gray-400 active:text-gray-400' + : '' } ${ - props.error ? "focus:ring-red/50" : "focus:ring-primary/50" + props.error ? 'focus:ring-red/50' : 'focus:ring-primary/50' } relative peer bg-bunker-800 rounded-md text-gray-400 text-md p-2 w-full min-w-16 outline-none focus:ring-4 duration-200`} name={props.name} spellCheck="false" autoComplete={props.autoComplete} id={props.id} /> - {props.label?.includes("Password") && ( + {props.label?.includes('Password') && (
)} - {row.status == "completed" && myUser !== row.email && ( + {row.status == 'completed' && myUser !== row.email && (
{myUser !== row.email && // row.role != "admin" && - myRole != "member" ? ( + myRole != 'member' ? (
)} - +
{plan.buttonTextSecondary}
@@ -70,9 +88,9 @@ export default function Plan({ plan }) { ) : (

CURRENT PLAN

diff --git a/frontend/components/dashboard/DashboardInputField.tsx b/frontend/components/dashboard/DashboardInputField.tsx index 7a5b4a048..43b001bbe 100644 --- a/frontend/components/dashboard/DashboardInputField.tsx +++ b/frontend/components/dashboard/DashboardInputField.tsx @@ -1,8 +1,8 @@ -import React, { SyntheticEvent, useRef } from "react"; -import { faCircle } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import React, { SyntheticEvent, useRef } from 'react'; +import { faCircle } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import guidGenerator from "../utilities/randomId"; +import guidGenerator from '../utilities/randomId'; const REGEX = /([$]{.*?})/g; @@ -10,7 +10,7 @@ interface DashboardInputFieldProps { index: number; onChangeHandler: (value: string, index: number) => void; value: string; - type: "varName" | "value"; + type: 'varName' | 'value'; blurred: boolean; duplicates: string[]; } @@ -33,7 +33,7 @@ const DashboardInputField = ({ type, value, blurred, - duplicates, + duplicates }: DashboardInputFieldProps) => { const ref = useRef(null); const syncScroll = (e: SyntheticEvent) => { @@ -43,8 +43,8 @@ const DashboardInputField = ({ ref.current.scrollLeft = e.currentTarget.scrollLeft; }; - if (type === "varName") { - const startsWithNumber = !isNaN(Number(value.charAt(0))) && value != ""; + if (type === 'varName') { + const startsWithNumber = !isNaN(Number(value.charAt(0))) && value != ''; const hasDuplicates = duplicates?.includes(value); const error = startsWithNumber || hasDuplicates; @@ -52,7 +52,7 @@ const DashboardInputField = ({
@@ -79,7 +79,7 @@ const DashboardInputField = ({ )}
); - } else if (type === "value") { + } else if (type === 'value') { return (
@@ -100,8 +100,8 @@ const DashboardInputField = ({ ref={ref} className={`${ blurred - ? "text-bunker-800 group-hover:text-gray-400 peer-focus:text-gray-400 peer-active:text-gray-400" - : "" + ? 'text-bunker-800 group-hover:text-gray-400 peer-focus:text-gray-400 peer-active:text-gray-400' + : '' } absolute flex flex-row whitespace-pre font-mono z-0 ph-no-capture max-w-2xl overflow-x-scroll bg-bunker-800 h-9 rounded-md text-gray-400 text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 focus:ring-primary/50 duration-100 no-scrollbar no-scrollbar::-webkit-scrollbar`} > {value.split(REGEX).map((word, id) => { @@ -112,7 +112,7 @@ const DashboardInputField = ({ {word.slice(2, word.length - 1)} - {word.slice(word.length - 1, word.length) == "}" ? ( + {word.slice(word.length - 1, word.length) == '}' ? ( {word.slice(word.length - 1, word.length)} @@ -135,7 +135,7 @@ const DashboardInputField = ({ {blurred && (
- {value.split("").map(() => ( + {value.split('').map(() => ( { const handleDragEnter = (e: DragEvent) => { e.preventDefault(); @@ -43,7 +43,7 @@ const DropZone = ({ e.stopPropagation(); // set dropEffect to copy i.e copy of the source item - e.dataTransfer.dropEffect = "copy"; + e.dataTransfer.dropEffect = 'copy'; }; const [loading, setLoading] = useState(false); @@ -54,7 +54,7 @@ const DropZone = ({ setTimeout(() => setLoading(false), 5000); e.preventDefault(); e.stopPropagation(); - e.dataTransfer.dropEffect = "copy"; + e.dataTransfer.dropEffect = 'copy'; const file = e.dataTransfer.files[0]; const reader = new FileReader(); @@ -68,7 +68,7 @@ const DropZone = ({ numCurrentRows + index, key, keyPairs[key as keyof typeof keyPairs], - "shared", + 'shared' ]); setData(newData); setButtonReady(true); @@ -94,15 +94,15 @@ const DropZone = ({ reader.onload = (event) => { if (event.target === null || event.target.result === null) return; const { result } = event.target; - if (typeof result === "string") { + if (typeof result === 'string') { const newData = result - .split("\n") + .split('\n') .map((line: string, index: number) => [ guidGenerator(), numCurrentRows + index, - line.split("=")[0], - line.split("=").slice(1, line.split("=").length).join("="), - "shared", + line.split('=')[0], + line.split('=').slice(1, line.split('=').length).join('='), + 'shared' ]); setData(newData); setButtonReady(true); diff --git a/frontend/components/navigation/NavBarDashboard.tsx b/frontend/components/navigation/NavBarDashboard.tsx index 5a6d63b8e..1834d8117 100644 --- a/frontend/components/navigation/NavBarDashboard.tsx +++ b/frontend/components/navigation/NavBarDashboard.tsx @@ -1,10 +1,10 @@ /* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react/jsx-key */ -import React, { Fragment, useEffect, useState } from "react"; -import Image from "next/image"; -import { useRouter } from "next/router"; -import { faGithub, faSlack } from "@fortawesome/free-brands-svg-icons"; -import { faCircleQuestion } from "@fortawesome/free-regular-svg-icons"; +import React, { Fragment, useEffect, useState } from 'react'; +import Image from 'next/image'; +import { useRouter } from 'next/router'; +import { faGithub, faSlack } from '@fortawesome/free-brands-svg-icons'; +import { faCircleQuestion } from '@fortawesome/free-regular-svg-icons'; import { faAngleDown, faBook, @@ -12,39 +12,39 @@ import { faEnvelope, faGear, faPlus, - faRightFromBracket, -} from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Menu, Transition } from "@headlessui/react"; + faRightFromBracket +} from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Menu, Transition } from '@headlessui/react'; -import logout from "~/pages/api/auth/Logout"; -import getOrganization from "~/pages/api/organization/GetOrg"; -import getOrganizations from "~/pages/api/organization/getOrgs"; -import getUser from "~/pages/api/user/getUser"; +import logout from '~/pages/api/auth/Logout'; +import getOrganization from '~/pages/api/organization/GetOrg'; +import getOrganizations from '~/pages/api/organization/getOrgs'; +import getUser from '~/pages/api/user/getUser'; -import guidGenerator from "../utilities/randomId"; +import guidGenerator from '../utilities/randomId'; const supportOptions = [ [ , - "Join Slack Forum", - "https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g", + 'Join Slack Forum', + 'https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g' ], [ , - "Read Docs", - "https://infisical.com/docs/getting-started/introduction", + 'Read Docs', + 'https://infisical.com/docs/getting-started/introduction' ], [ , - "Open a GitHub Issue", - "https://github.com/Infisical/infisical-cli/issues", + 'Open a GitHub Issue', + 'https://github.com/Infisical/infisical-cli/issues' ], [ , - "Send us an Email", - "mailto:support@infisical.com", - ], + 'Send us an Email', + 'mailto:support@infisical.com' + ] ]; export interface ICurrentOrg { @@ -58,7 +58,7 @@ export interface IUser { } /** - * This is the navigation bar in the main app. + * 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 */ @@ -75,16 +75,16 @@ export default function Navbar() { const orgsData = await getOrganizations(); setOrgs(orgsData); const currentOrg = await getOrganization({ - orgId: String(localStorage.getItem("orgData.id")), + orgId: String(localStorage.getItem('orgData.id')) }); setCurrentOrg(currentOrg); })(); }, []); const closeApp = async () => { - console.log("Logging out..."); + console.log('Logging out...'); await logout(); - router.push("/login"); + router.push('/login'); }; return ( @@ -163,7 +163,7 @@ export default function Navbar() {
- router.push("/settings/personal/" + router.query.id) + router.push('/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" > @@ -173,11 +173,11 @@ export default function Navbar() {

- {" "} + {' '} {user?.firstName} {user?.lastName}

- {" "} + {' '} {user?.email}

@@ -194,7 +194,7 @@ export default function Navbar() {
- router.push("/settings/org/" + router.query.id) + router.push('/settings/org/' + router.query.id) } className="flex flex-row items-center px-2 mt-2 py-1 hover:bg-white/5 cursor-pointer rounded-md" > @@ -217,7 +217,7 @@ export default function Navbar() { >
- router.push("/settings/billing/" + router.query.id) + router.push('/settings/billing/' + router.query.id) } className="mt-1 relative flex justify-start cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/5 duration-200 hover:text-gray-200" > @@ -235,7 +235,7 @@ export default function Navbar() {
router.push( - "/settings/org/" + router.query.id + "?invite" + '/settings/org/' + router.query.id + '?invite' ) } 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" @@ -255,13 +255,14 @@ export default function Navbar() {
{orgs .filter( - (org : { _id: string }) => org._id != localStorage.getItem("orgData.id") + (org: { _id: string }) => + org._id != localStorage.getItem('orgData.id') ) - .map((org : { _id: string; name: string; }) => ( + .map((org: { _id: string; name: string }) => (
{ - localStorage.setItem("orgData.id", org._id); + localStorage.setItem('orgData.id', org._id); router.reload(); }} className="flex flex-row justify-start items-center hover:bg-white/5 w-full p-1.5 cursor-pointer rounded-md" @@ -286,8 +287,8 @@ export default function Navbar() { onClick={closeApp} className={`${ active - ? "bg-red font-semibold text-white" - : "text-gray-400" + ? 'bg-red font-semibold text-white' + : 'text-gray-400' } group flex w-full items-center rounded-md px-2 py-2 text-sm`} >
diff --git a/frontend/components/utilities/SecurityClient.js b/frontend/components/utilities/SecurityClient.js deleted file mode 100644 index 78eebdebe..000000000 --- a/frontend/components/utilities/SecurityClient.js +++ /dev/null @@ -1,24 +0,0 @@ -import token from "~/pages/api/auth/Token"; - -export default class SecurityClient { - static #token = ""; - - constructor() {} - - static setToken(token) { - this.#token = token; - } - - static async fetchCall(resource, options) { - let req = new Request(resource, options); - - if (this.#token == "") { - this.setToken(await token()); - } - - if (this.#token) { - req.headers.set("Authorization", "Bearer " + this.#token); - return fetch(req); - } - } -} diff --git a/frontend/components/utilities/SecurityClient.ts b/frontend/components/utilities/SecurityClient.ts new file mode 100644 index 000000000..ea2664c70 --- /dev/null +++ b/frontend/components/utilities/SecurityClient.ts @@ -0,0 +1,27 @@ +import token from '~/pages/api/auth/Token'; + +export default class SecurityClient { + static #token = ''; + + constructor() {} + + static setToken(token: string) { + this.#token = token; + } + + static async fetchCall( + resource: RequestInfo, + options?: RequestInit | undefined + ) { + const req = new Request(resource, options); + + if (this.#token == '') { + this.setToken(await token()); + } + + if (this.#token) { + req.headers.set('Authorization', 'Bearer ' + this.#token); + return fetch(req); + } + } +} diff --git a/frontend/components/utilities/attemptLogin.js b/frontend/components/utilities/attemptLogin.js index 33c08b698..d79a3b3b0 100644 --- a/frontend/components/utilities/attemptLogin.js +++ b/frontend/components/utilities/attemptLogin.js @@ -1,17 +1,17 @@ -import Aes256Gcm from "~/components/utilities/cryptography/aes-256-gcm"; -import login1 from "~/pages/api/auth/Login1"; -import login2 from "~/pages/api/auth/Login2"; -import getOrganizations from "~/pages/api/organization/getOrgs"; -import getOrganizationUserProjects from "~/pages/api/organization/GetOrgUserProjects"; +import Aes256Gcm from '~/components/utilities/cryptography/aes-256-gcm'; +import login1 from '~/pages/api/auth/Login1'; +import login2 from '~/pages/api/auth/Login2'; +import getOrganizations from '~/pages/api/organization/getOrgs'; +import getOrganizationUserProjects from '~/pages/api/organization/GetOrgUserProjects'; -import pushKeys from "./secrets/pushKeys"; -import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage"; -import SecurityClient from "./SecurityClient"; -import Telemetry from "./telemetry/Telemetry"; +import pushKeys from './secrets/pushKeys'; +import Telemetry from './telemetry/Telemetry'; +import { saveTokenToLocalStorage } from './saveTokenToLocalStorage'; +import SecurityClient from './SecurityClient'; -const nacl = require("tweetnacl"); -nacl.util = require("tweetnacl-util"); -const jsrp = require("jsrp"); +const nacl = require('tweetnacl'); +nacl.util = require('tweetnacl-util'); +const jsrp = require('jsrp'); const client = new jsrp.client(); /** @@ -37,7 +37,7 @@ const attemptLogin = async ( client.init( { username: email, - password: password, + password: password }, async () => { const clientPublicKey = client.getPublicKey(); @@ -62,7 +62,7 @@ const attemptLogin = async ( .slice(0, 32) .padStart( 32 + (password.slice(0, 32).length - new Blob([password]).size), - "0" + '0' ) ); @@ -72,36 +72,36 @@ const attemptLogin = async ( encryptedPrivateKey, iv, tag, - privateKey, + privateKey }); const userOrgs = await getOrganizations(); const userOrgsData = userOrgs.map((org) => org._id); let orgToLogin; - if (userOrgsData.includes(localStorage.getItem("orgData.id"))) { - orgToLogin = localStorage.getItem("orgData.id"); + if (userOrgsData.includes(localStorage.getItem('orgData.id'))) { + orgToLogin = localStorage.getItem('orgData.id'); } else { orgToLogin = userOrgsData[0]; - localStorage.setItem("orgData.id", orgToLogin); + localStorage.setItem('orgData.id', orgToLogin); } let orgUserProjects = await getOrganizationUserProjects({ - orgId: orgToLogin, + orgId: orgToLogin }); orgUserProjects = orgUserProjects?.map((project) => project._id); let projectToLogin; if ( - orgUserProjects.includes(localStorage.getItem("projectData.id")) + orgUserProjects.includes(localStorage.getItem('projectData.id')) ) { - projectToLogin = 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); } } @@ -110,38 +110,38 @@ const attemptLogin = async ( await pushKeys({ obj: { DATABASE_URL: [ - "mongodb+srv://${DB_USERNAME}:${DB_PASSWORD}@mongodb.net", - "personal", + '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", + 'hgSIwDAKvz8PJfkj6xkzYqzGmAP3HLuG', + 'shared' ], - WEBSITE_URL: ["http://localhost:3000", "shared"], - STRIPE_SECRET_KEY: ["sk_test_7348oyho4hfq398HIUOH78", "shared"], + WEBSITE_URL: ['http://localhost:3000', 'shared'], + STRIPE_SECRET_KEY: ['sk_test_7348oyho4hfq398HIUOH78', 'shared'] }, workspaceId: projectToLogin, - env: "Development", + env: 'Development' }); } if (email) { telemetry.identify(email); - telemetry.capture("User Logged In"); + telemetry.capture('User Logged In'); } if (isLogin) { - router.push("/dashboard/"); + router.push('/dashboard/'); } } catch (error) { setErrorLogin(true); - console.log("Login response not available"); + console.log('Login response not available'); } } ); } catch (error) { - console.log("Something went wrong during authentication"); + console.log('Something went wrong during authentication'); } return true; }; diff --git a/frontend/components/utilities/cryptography/issueBackupKey.js b/frontend/components/utilities/cryptography/issueBackupKey.js deleted file mode 100644 index 19d7ebefa..000000000 --- a/frontend/components/utilities/cryptography/issueBackupKey.js +++ /dev/null @@ -1,98 +0,0 @@ -import issueBackupPrivateKey from "~/pages/api/auth/IssueBackupPrivateKey"; -import SRP1 from "~/pages/api/auth/SRP1"; - -import generateBackupPDF from "../generateBackupPDF"; -import Aes256Gcm from "./aes-256-gcm"; - -const nacl = require("tweetnacl"); -nacl.util = require("tweetnacl-util"); -const jsrp = require("jsrp"); -const clientPassword = new jsrp.client(); -const clientKey = new jsrp.client(); -const crypto = require("crypto"); - -/** - * This function loggs in the user (whether it's right after signup, or a normal login) - * @param {*} email - * @param {*} password - * @param {*} setErrorLogin - * @param {*} router - * @param {*} isSignUp - * @returns - */ -const issueBackupKey = async ({ - email, - password, - personalName, - setBackupKeyError, - setBackupKeyIssued, -}) => { - try { - setBackupKeyError(false); - setBackupKeyIssued(false); - clientPassword.init( - { - username: email, - password: password, - }, - async () => { - const clientPublicKey = clientPassword.getPublicKey(); - - let serverPublicKey, salt; - try { - const res = await SRP1({ - clientPublicKey: clientPublicKey, - }); - serverPublicKey = res.serverPublicKey; - salt = res.salt; - } catch (err) { - setBackupKeyError(true); - console.log("Wrong current password", err, 1); - } - - clientPassword.setSalt(salt); - clientPassword.setServerPublicKey(serverPublicKey); - const clientProof = clientPassword.getProof(); // called M1 - - const generatedKey = crypto.randomBytes(16).toString("hex"); - - clientKey.init( - { - username: email, - password: generatedKey, - }, - async () => { - clientKey.createVerifier(async (err, result) => { - let { ciphertext, iv, tag } = Aes256Gcm.encrypt( - localStorage.getItem("PRIVATE_KEY"), - generatedKey - ); - - const res = await issueBackupPrivateKey({ - encryptedPrivateKey: ciphertext, - iv, - tag, - salt: result.salt, - verifier: result.verifier, - clientProof, - }); - - if (res.status == 400) { - setBackupKeyError(true); - } else if (res.status == 200) { - generateBackupPDF(personalName, email, generatedKey); - setBackupKeyIssued(true); - } - }); - } - ); - } - ); - } catch (error) { - setBackupKeyError(true); - console.log("Failed to issue a backup key"); - } - return true; -}; - -export default issueBackupKey; diff --git a/frontend/components/utilities/cryptography/issueBackupKey.ts b/frontend/components/utilities/cryptography/issueBackupKey.ts new file mode 100644 index 000000000..518186406 --- /dev/null +++ b/frontend/components/utilities/cryptography/issueBackupKey.ts @@ -0,0 +1,112 @@ +import issueBackupPrivateKey from '~/pages/api/auth/IssueBackupPrivateKey'; +import SRP1 from '~/pages/api/auth/SRP1'; + +import { tempLocalStorage } from '../checks/tempLocalStorage'; +import generateBackupPDF from '../generateBackupPDF'; +import Aes256Gcm from './aes-256-gcm'; + +const nacl = require('tweetnacl'); +nacl.util = require('tweetnacl-util'); +const jsrp = require('jsrp'); +const clientPassword = new jsrp.client(); +const clientKey = new jsrp.client(); +const crypto = require('crypto'); + +interface Props { + email: string; + password: string; + personalName: string; + setBackupKeyError: any; + setBackupKeyIssued: any; +} + +/** + * This function loggs in the user (whether it's right after signup, or a normal login) + * @param {*} email + * @param {*} password + * @param {*} setErrorLogin + * @param {*} router + * @param {*} isSignUp + * @returns + */ +const issueBackupKey = async ({ + email, + password, + personalName, + setBackupKeyError, + setBackupKeyIssued +}: Props) => { + try { + setBackupKeyError(false); + setBackupKeyIssued(false); + clientPassword.init( + { + username: email, + password: password + }, + async () => { + const clientPublicKey = clientPassword.getPublicKey(); + + let serverPublicKey, salt; + try { + const res = await SRP1({ + clientPublicKey: clientPublicKey + }); + serverPublicKey = res.serverPublicKey; + salt = res.salt; + } catch (err) { + setBackupKeyError(true); + console.log('Wrong current password', err, 1); + } + + clientPassword.setSalt(salt); + clientPassword.setServerPublicKey(serverPublicKey); + const clientProof = clientPassword.getProof(); // called M1 + + const generatedKey = crypto.randomBytes(16).toString('hex'); + + clientKey.init( + { + username: email, + password: generatedKey + }, + async () => { + clientKey.createVerifier( + async (_: any, result: { salt: string; verifier: string }) => { + // TODO: Fix this + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const { ciphertext, iv, tag } = Aes256Gcm.encrypt( + tempLocalStorage('PRIVATE_KEY'), + generatedKey + ); + + const res = await issueBackupPrivateKey({ + encryptedPrivateKey: ciphertext, + iv, + tag, + salt: result.salt, + verifier: result.verifier, + clientProof + }); + + if (res && res.status == 400) { + setBackupKeyError(true); + } else if (res && res.status == 200) { + generateBackupPDF(personalName, email, generatedKey); + setBackupKeyIssued(true); + } + } + ); + } + ); + } + ); + } catch (error) { + setBackupKeyError(true); + console.log('Failed to issue a backup key'); + } + return true; +}; + +export default issueBackupKey; diff --git a/frontend/components/utilities/file.js b/frontend/components/utilities/file.ts similarity index 74% rename from frontend/components/utilities/file.js rename to frontend/components/utilities/file.ts index 96d1820eb..3784405f9 100644 --- a/frontend/components/utilities/file.js +++ b/frontend/components/utilities/file.ts @@ -6,21 +6,21 @@ const LINE = * @param {Buffer} src - source buffer * @returns {String} text - text of buffer */ -function parse(src) { - const obj = {}; +function parse(src: Buffer) { + const obj: Record = {}; // Convert buffer to string let lines = src.toString(); // Convert line breaks to same format - lines = lines.replace(/\r\n?/gm, "\n"); + lines = lines.replace(/\r\n?/gm, '\n'); let match; while ((match = LINE.exec(lines)) != null) { const key = match[1]; // Default undefined or null to empty string - let value = match[2] || ""; + let value = match[2] || ''; // Remove whitespace value = value.trim(); @@ -29,12 +29,12 @@ function parse(src) { const maybeQuote = value[0]; // Remove surrounding quotes - value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2"); + value = value.replace(/^(['"`])([\s\S]*)\1$/gm, '$2'); // Expand newlines if double quoted if (maybeQuote === '"') { - value = value.replace(/\\n/g, "\n"); - value = value.replace(/\\r/g, "\r"); + value = value.replace(/\\n/g, '\n'); + value = value.replace(/\\r/g, '\r'); } // Add to object diff --git a/frontend/components/utilities/randomId.js b/frontend/components/utilities/randomId.ts similarity index 82% rename from frontend/components/utilities/randomId.js rename to frontend/components/utilities/randomId.ts index 7d1c0859b..8e1c7f972 100644 --- a/frontend/components/utilities/randomId.js +++ b/frontend/components/utilities/randomId.ts @@ -3,19 +3,19 @@ * @returns */ const guidGenerator = () => { - var S4 = function () { + const S4 = function () { return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); }; return ( S4() + S4() + - "-" + + '-' + S4() + - "-" + + '-' + S4() + - "-" + + '-' + S4() + - "-" + + '-' + S4() + S4() + S4() diff --git a/frontend/components/utilities/secrets/getSecretsForProject.js b/frontend/components/utilities/secrets/getSecretsForProject.ts similarity index 60% rename from frontend/components/utilities/secrets/getSecretsForProject.js rename to frontend/components/utilities/secrets/getSecretsForProject.ts index 7bdac922f..284b8bee1 100644 --- a/frontend/components/utilities/secrets/getSecretsForProject.js +++ b/frontend/components/utilities/secrets/getSecretsForProject.ts @@ -1,22 +1,30 @@ -import getSecrets from "~/pages/api/files/GetSecrets"; +import getSecrets from '~/pages/api/files/GetSecrets'; -import { envMapping } from "../../../public/data/frequentConstants"; -import guidGenerator from "../randomId"; +import { envMapping } from '../../../public/data/frequentConstants'; +import guidGenerator from '../randomId'; const { decryptAssymmetric, - decryptSymmetric, -} = require("../cryptography/crypto"); -const nacl = require("tweetnacl"); -nacl.util = require("tweetnacl-util"); + decryptSymmetric +} = require('../cryptography/crypto'); +const nacl = require('tweetnacl'); +nacl.util = require('tweetnacl-util'); + +interface Props { + env: keyof typeof envMapping; + setFileState: any; + setIsKeyAvailable: any; + setData: any; + workspaceId: string; +} const getSecretsForProject = async ({ env, setFileState, setIsKeyAvailable, setData, - workspaceId, -}) => { + workspaceId +}: Props) => { try { let file; try { @@ -24,44 +32,42 @@ const getSecretsForProject = async ({ setFileState(file); } catch (error) { - console.log("ERROR: Not able to access the latest file"); + console.log('ERROR: Not able to access the latest file'); } // This is called isKeyAvilable but what it really means is if a person is able to create new key pairs - setIsKeyAvailable( - !file.key ? (file.secrets.length == 0 ? true : false) : true - ); + setIsKeyAvailable(!file.key ? file.secrets.length == 0 : true); - const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); + const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY'); - let tempFileState = []; + const tempFileState: { key: string; value: string; type: string }[] = []; if (file.key) { // assymmetrically decrypt symmetric key with local private key const key = decryptAssymmetric({ ciphertext: file.key.encryptedKey, nonce: file.key.nonce, publicKey: file.key.sender.publicKey, - privateKey: PRIVATE_KEY, + privateKey: PRIVATE_KEY }); - file.secrets.map((secretPair) => { + file.secrets.map((secretPair: any) => { // decrypt .env file with symmetric key const plainTextKey = decryptSymmetric({ ciphertext: secretPair.secretKey.ciphertext, iv: secretPair.secretKey.iv, tag: secretPair.secretKey.tag, - key, + key }); const plainTextValue = decryptSymmetric({ ciphertext: secretPair.secretValue.ciphertext, iv: secretPair.secretValue.iv, tag: secretPair.secretValue.tag, - key, + key }); tempFileState.push({ key: plainTextKey, value: plainTextValue, - type: secretPair.type, + type: secretPair.type }); }); } @@ -71,9 +77,9 @@ const getSecretsForProject = async ({ tempFileState.map((line, index) => [ guidGenerator(), index, - line["key"], - line["value"], - line["type"], + line['key'], + line['value'], + line['type'] ]) // .sort((a, b) => // sortMethod == "alphabetical" @@ -84,12 +90,12 @@ const getSecretsForProject = async ({ return tempFileState.map((line, index) => [ guidGenerator(), index, - line["key"], - line["value"], - line["type"], + line['key'], + line['value'], + 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; }; diff --git a/frontend/components/utilities/secrets/pushKeysIntegration.js b/frontend/components/utilities/secrets/pushKeysIntegration.js deleted file mode 100644 index 5b08748e7..000000000 --- a/frontend/components/utilities/secrets/pushKeysIntegration.js +++ /dev/null @@ -1,74 +0,0 @@ -import publicKeyInfical from "~/pages/api/auth/publicKeyInfisical"; -import changeHerokuConfigVars from "~/pages/api/integrations/ChangeHerokuConfigVars"; - -const crypto = require("crypto"); -const { - encryptSymmetric, - encryptAssymmetric, -} = require("../cryptography/crypto"); -const nacl = require("tweetnacl"); -nacl.util = require("tweetnacl-util"); - -const pushKeysIntegration = async ({ obj, integrationId }) => { - const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); - - let randomBytes = crypto.randomBytes(16).toString("hex"); - - const secrets = Object.keys(obj).map((key) => { - // encrypt key - const { - ciphertext: ciphertextKey, - iv: ivKey, - tag: tagKey, - } = encryptSymmetric({ - plaintext: key, - key: randomBytes, - }); - - // encrypt value - const { - ciphertext: ciphertextValue, - iv: ivValue, - tag: tagValue, - } = encryptSymmetric({ - plaintext: obj[key], - key: randomBytes, - }); - - const visibility = "shared"; - - return { - ciphertextKey, - ivKey, - tagKey, - hashKey: crypto.createHash("sha256").update(key).digest("hex"), - ciphertextValue, - ivValue, - tagValue, - hashValue: crypto.createHash("sha256").update(obj[key]).digest("hex"), - type: visibility, - }; - }); - - // obtain public keys of all receivers (i.e. members in workspace) - let publicKeyInfisical = await publicKeyInfical(); - - publicKeyInfisical = (await publicKeyInfisical.json()).publicKey; - - // assymmetrically encrypt key with each receiver public keys - - const { ciphertext, nonce } = encryptAssymmetric({ - plaintext: randomBytes, - publicKey: publicKeyInfisical, - privateKey: PRIVATE_KEY, - }); - - const key = { - encryptedKey: ciphertext, - nonce, - }; - - changeHerokuConfigVars({ integrationId, key, secrets }); -}; - -export default pushKeysIntegration; diff --git a/frontend/components/utilities/secrets/pushKeysIntegration.ts b/frontend/components/utilities/secrets/pushKeysIntegration.ts new file mode 100644 index 000000000..949778927 --- /dev/null +++ b/frontend/components/utilities/secrets/pushKeysIntegration.ts @@ -0,0 +1,79 @@ +import publicKeyInfical from '~/pages/api/auth/publicKeyInfisical'; +import changeHerokuConfigVars from '~/pages/api/integrations/ChangeHerokuConfigVars'; + +const crypto = require('crypto'); +const { + encryptSymmetric, + encryptAssymmetric +} = require('../cryptography/crypto'); +const nacl = require('tweetnacl'); +nacl.util = require('tweetnacl-util'); + +interface Props { + obj: Record; + integrationId: string; +} + +const pushKeysIntegration = async ({ obj, integrationId }: Props) => { + const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY'); + + const randomBytes = crypto.randomBytes(16).toString('hex'); + + const secrets = Object.keys(obj).map((key) => { + // encrypt key + const { + ciphertext: ciphertextKey, + iv: ivKey, + tag: tagKey + } = encryptSymmetric({ + plaintext: key, + key: randomBytes + }); + + // encrypt value + const { + ciphertext: ciphertextValue, + iv: ivValue, + tag: tagValue + } = encryptSymmetric({ + plaintext: obj[key], + key: randomBytes + }); + + const visibility = 'shared'; + + return { + ciphertextKey, + ivKey, + tagKey, + hashKey: crypto.createHash('sha256').update(key).digest('hex'), + ciphertextValue, + ivValue, + tagValue, + hashValue: crypto.createHash('sha256').update(obj[key]).digest('hex'), + type: visibility + }; + }); + + // obtain public keys of all receivers (i.e. members in workspace) + const publicKeyInfisical = await publicKeyInfical(); + + const publicKey = (await publicKeyInfisical.json()).publicKey; + + // assymmetrically encrypt key with each receiver public keys + + const { ciphertext, nonce } = encryptAssymmetric({ + plaintext: randomBytes, + publicKey, + privateKey: PRIVATE_KEY + }); + + const key = { + encryptedKey: ciphertext, + nonce + }; + + changeHerokuConfigVars({ integrationId, key, secrets }); +}; + +export default pushKeysIntegration; diff --git a/frontend/pages/api/auth/ChangePassword2.js b/frontend/pages/api/auth/ChangePassword2.ts similarity index 50% rename from frontend/pages/api/auth/ChangePassword2.js rename to frontend/pages/api/auth/ChangePassword2.ts index b764e6067..132eeddf4 100644 --- a/frontend/pages/api/auth/ChangePassword2.js +++ b/frontend/pages/api/auth/ChangePassword2.ts @@ -1,4 +1,13 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + encryptedPrivateKey: string; + iv: string; + tag: string; + salt: string; + verifier: string; + clientProof: string; +} /** * This is the second step of the change password process (pake) @@ -11,12 +20,12 @@ const changePassword2 = ({ tag, salt, verifier, - clientProof, -}) => { - return SecurityClient.fetchCall("/api/v1/password/change-password", { - method: "POST", + clientProof +}: Props) => { + return SecurityClient.fetchCall('/api/v1/password/change-password', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, body: JSON.stringify({ clientProof: clientProof, @@ -24,13 +33,13 @@ const changePassword2 = ({ iv: iv, tag: tag, salt: salt, - verifier: verifier, - }), + verifier: verifier + }) }).then(async (res) => { - if (res.status == 200) { + if (res && res.status == 200) { return res; } else { - console.log("Failed to change the password"); + console.log('Failed to change the password'); } }); }; diff --git a/frontend/pages/api/auth/CheckAuth.js b/frontend/pages/api/auth/CheckAuth.ts similarity index 50% rename from frontend/pages/api/auth/CheckAuth.js rename to frontend/pages/api/auth/CheckAuth.ts index edd373614..ad754dfb3 100644 --- a/frontend/pages/api/auth/CheckAuth.js +++ b/frontend/pages/api/auth/CheckAuth.ts @@ -1,4 +1,4 @@ -import SecurityClient from "~/utilities/SecurityClient.js"; +import SecurityClient from '~/utilities/SecurityClient'; /** * This function is used to check if the user is authenticated. @@ -7,17 +7,17 @@ import SecurityClient from "~/utilities/SecurityClient.js"; * @param {*} res * @returns */ -const checkAuth = async (req, res) => { - return SecurityClient.fetchCall("/api/v1/auth/checkAuth", { - method: "POST", +const checkAuth = async () => { + return SecurityClient.fetchCall('/api/v1/auth/checkAuth', { + method: 'POST', headers: { - "Content-Type": "application/json", - }, + 'Content-Type': 'application/json' + } }).then((res) => { - if (res.status == 200) { + if (res && res.status == 200) { return res; } else { - console.log("Not authorized"); + console.log('Not authorized'); } }); }; diff --git a/frontend/pages/api/auth/CheckEmailVerificationCode.js b/frontend/pages/api/auth/CheckEmailVerificationCode.ts similarity index 50% rename from frontend/pages/api/auth/CheckEmailVerificationCode.js rename to frontend/pages/api/auth/CheckEmailVerificationCode.ts index 83a64602a..08fb6b391 100644 --- a/frontend/pages/api/auth/CheckEmailVerificationCode.js +++ b/frontend/pages/api/auth/CheckEmailVerificationCode.ts @@ -1,19 +1,24 @@ +interface Props { + email: string; + code: string; +} + /** * This route check the verification code from the email that user just recieved * @param {*} email * @param {*} code * @returns */ -const checkEmailVerificationCode = (email, code) => { - return fetch("/api/v1/signup/email/verify", { - method: "POST", +const checkEmailVerificationCode = ({ email, code }: Props) => { + return fetch('/api/v1/signup/email/verify', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email, - code: code, - }), + code: code + }) }); }; diff --git a/frontend/pages/api/auth/CompleteAccountInformationSignup.js b/frontend/pages/api/auth/CompleteAccountInformationSignup.ts similarity index 64% rename from frontend/pages/api/auth/CompleteAccountInformationSignup.js rename to frontend/pages/api/auth/CompleteAccountInformationSignup.ts index 21406e381..98e78dec9 100644 --- a/frontend/pages/api/auth/CompleteAccountInformationSignup.js +++ b/frontend/pages/api/auth/CompleteAccountInformationSignup.ts @@ -1,3 +1,17 @@ +interface Props { + email: string; + firstName: string; + lastName: string; + publicKey: string; + ciphertext: string; + organizationName: string; + iv: string; + tag: string; + salt: string; + verifier: string; + token: string; +} + /** * This function is called in the end of the signup process. * It sends all the necessary nformation to the server. @@ -24,13 +38,13 @@ const completeAccountInformationSignup = ({ tag, salt, verifier, - token, -}) => { - return fetch("/api/v1/signup/complete-account/signup", { - method: "POST", + token +}: Props) => { + return fetch('/api/v1/signup/complete-account/signup', { + method: 'POST', headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + token }, body: JSON.stringify({ email, @@ -42,8 +56,8 @@ const completeAccountInformationSignup = ({ iv, tag, salt, - verifier, - }), + verifier + }) }); }; diff --git a/frontend/pages/api/auth/CompleteAccountInformationSignupInvite.js b/frontend/pages/api/auth/CompleteAccountInformationSignupInvite.ts similarity index 64% rename from frontend/pages/api/auth/CompleteAccountInformationSignupInvite.js rename to frontend/pages/api/auth/CompleteAccountInformationSignupInvite.ts index a205e6f59..1e5abdc45 100644 --- a/frontend/pages/api/auth/CompleteAccountInformationSignupInvite.js +++ b/frontend/pages/api/auth/CompleteAccountInformationSignupInvite.ts @@ -1,3 +1,16 @@ +interface Props { + email: string; + firstName: string; + lastName: string; + publicKey: string; + ciphertext: string; + iv: string; + tag: string; + salt: string; + verifier: string; + token: string; +} + /** * This function is called in the end of the signup process. * It sends all the necessary nformation to the server. @@ -22,13 +35,13 @@ const completeAccountInformationSignupInvite = ({ tag, salt, verifier, - token, -}) => { - return fetch("/api/v1/signup/complete-account/invite", { - method: "POST", + token +}: Props) => { + return fetch('/api/v1/signup/complete-account/invite', { + method: 'POST', headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + token }, body: JSON.stringify({ email: email, @@ -39,8 +52,8 @@ const completeAccountInformationSignupInvite = ({ iv: iv, tag: tag, salt: salt, - verifier: verifier, - }), + verifier: verifier + }) }); }; diff --git a/frontend/pages/api/auth/IssueBackupPrivateKey.js b/frontend/pages/api/auth/IssueBackupPrivateKey.js deleted file mode 100644 index 9a31f7b00..000000000 --- a/frontend/pages/api/auth/IssueBackupPrivateKey.js +++ /dev/null @@ -1,40 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This is the route that issues a backup private key that will afterwards be added into a pdf - */ -const issueBackupPrivateKey = ({ - encryptedPrivateKey, - iv, - tag, - salt, - verifier, - clientProof, -}) => { - return SecurityClient.fetchCall( - "/api/v1/password/backup-private-key", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - clientProof: clientProof, - encryptedPrivateKey: encryptedPrivateKey, - iv: iv, - tag: tag, - salt: salt, - verifier: verifier, - }), - } - ).then((res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to issue the backup key"); - return res; - } - }); -}; - -export default issueBackupPrivateKey; diff --git a/frontend/pages/api/auth/IssueBackupPrivateKey.ts b/frontend/pages/api/auth/IssueBackupPrivateKey.ts new file mode 100644 index 000000000..9b300f55b --- /dev/null +++ b/frontend/pages/api/auth/IssueBackupPrivateKey.ts @@ -0,0 +1,44 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + encryptedPrivateKey: string; + iv: string; + tag: string; + salt: string; + verifier: string; + clientProof: string; +} + +/** + * This is the route that issues a backup private key that will afterwards be added into a pdf + */ +const issueBackupPrivateKey = ({ + encryptedPrivateKey, + iv, + tag, + salt, + verifier, + clientProof +}: Props) => { + return SecurityClient.fetchCall('/api/v1/password/backup-private-key', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + clientProof: clientProof, + encryptedPrivateKey: encryptedPrivateKey, + iv: iv, + tag: tag, + salt: salt, + verifier: verifier + }) + }).then((res) => { + if (res?.status !== 200) { + console.log('Failed to issue the backup key'); + } + return res; + }); +}; + +export default issueBackupPrivateKey; diff --git a/frontend/pages/api/auth/Logout.ts b/frontend/pages/api/auth/Logout.ts index 4dbcb7bca..cd4ff9a61 100644 --- a/frontend/pages/api/auth/Logout.ts +++ b/frontend/pages/api/auth/Logout.ts @@ -1,29 +1,29 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; /** * This route logs the user out. Note: the user should authorized to do this. * We first try to log out - if the authorization fails (response.status = 401), we refetch the new token, and then retry */ const logout = async () => { - return SecurityClient.fetchCall("/api/v1/auth/logout", { - method: "POST", + return SecurityClient.fetchCall('/api/v1/auth/logout', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, - credentials: "include", + credentials: 'include' }).then((res) => { if (res?.status == 200) { - SecurityClient.setToken(""); + SecurityClient.setToken(''); // Delete the cookie by not setting a value; Alternatively clear the local storage - localStorage.setItem("publicKey", ""); - localStorage.setItem("encryptedPrivateKey", ""); - localStorage.setItem("iv", ""); - localStorage.setItem("tag", ""); - localStorage.setItem("PRIVATE_KEY", ""); - console.log("User logged out", res); + localStorage.setItem('publicKey', ''); + localStorage.setItem('encryptedPrivateKey', ''); + localStorage.setItem('iv', ''); + localStorage.setItem('tag', ''); + localStorage.setItem('PRIVATE_KEY', ''); + console.log('User logged out', res); return res; } else { - console.log("Failed to log out"); + console.log('Failed to log out'); } }); }; diff --git a/frontend/pages/api/auth/SRP1.js b/frontend/pages/api/auth/SRP1.js deleted file mode 100644 index b0fefb857..000000000 --- a/frontend/pages/api/auth/SRP1.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This is the first step of the change password process (pake) - * @param {*} clientPublicKey - * @returns - */ -const SRP1 = ({ clientPublicKey }) => { - return SecurityClient.fetchCall("/api/v1/password/srp1", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - clientPublicKey, - }), - }).then(async (res) => { - if (res.status == 200) { - return await res.json(); - } else { - console.log("Failed to do the first step of SRP"); - } - }); -}; - -export default SRP1; diff --git a/frontend/pages/api/auth/SRP1.ts b/frontend/pages/api/auth/SRP1.ts new file mode 100644 index 000000000..292dcbdd1 --- /dev/null +++ b/frontend/pages/api/auth/SRP1.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + clientPublicKey: string; +} + +/** + * This is the first step of the change password process (pake) + * @param {*} clientPublicKey + * @returns + */ +const SRP1 = ({ clientPublicKey }: Props) => { + return SecurityClient.fetchCall('/api/v1/password/srp1', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + clientPublicKey + }) + }).then(async (res) => { + if (res && res.status == 200) { + return await res.json(); + } else { + console.log('Failed to do the first step of SRP'); + } + }); +}; + +export default SRP1; diff --git a/frontend/pages/api/auth/SendVerificationEmail.js b/frontend/pages/api/auth/SendVerificationEmail.ts similarity index 55% rename from frontend/pages/api/auth/SendVerificationEmail.js rename to frontend/pages/api/auth/SendVerificationEmail.ts index ae952852d..4f3b063c6 100644 --- a/frontend/pages/api/auth/SendVerificationEmail.js +++ b/frontend/pages/api/auth/SendVerificationEmail.ts @@ -2,15 +2,15 @@ * This route send the verification email to the user's email (contains a 6-digit verification code) * @param {*} email */ -const sendVerificationEmail = (email) => { - fetch("/api/v1/signup/email/signup", { - method: "POST", +const sendVerificationEmail = (email: string) => { + fetch('/api/v1/signup/email/signup', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, body: JSON.stringify({ - email: email, - }), + email: email + }) }); }; diff --git a/frontend/pages/api/auth/Token.js b/frontend/pages/api/auth/Token.js deleted file mode 100644 index c3e5fd958..000000000 --- a/frontend/pages/api/auth/Token.js +++ /dev/null @@ -1,17 +0,0 @@ -const token = async (req, res) => { - return fetch("/api/v1/auth/token", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - credentials: "include", - }).then(async (res) => { - if (res.status == 200) { - return (await res.json()).token; - } else { - console.log("Getting a new token failed"); - } - }); -}; - -export default token; diff --git a/frontend/pages/api/auth/Token.ts b/frontend/pages/api/auth/Token.ts new file mode 100644 index 000000000..ed347ba4b --- /dev/null +++ b/frontend/pages/api/auth/Token.ts @@ -0,0 +1,17 @@ +const token = async () => { + return fetch('/api/v1/auth/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + credentials: 'include' + }).then(async (res) => { + if (res.status == 200) { + return (await res.json()).token; + } else { + console.log('Getting a new token failed'); + } + }); +}; + +export default token; diff --git a/frontend/pages/api/auth/VerifySignupInvite.js b/frontend/pages/api/auth/VerifySignupInvite.js deleted file mode 100644 index 2a9ba4dcd..000000000 --- a/frontend/pages/api/auth/VerifySignupInvite.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * This route verifies the signup invite link - * @param {*} email - * @param {*} code - * @returns - */ -const verifySignupInvite = ({ email, code }) => { - return fetch("/api/v1/invite-org/verify", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email, - code, - }), - }); -}; - -export default verifySignupInvite; diff --git a/frontend/pages/api/auth/VerifySignupInvite.ts b/frontend/pages/api/auth/VerifySignupInvite.ts new file mode 100644 index 000000000..20e52dfd1 --- /dev/null +++ b/frontend/pages/api/auth/VerifySignupInvite.ts @@ -0,0 +1,25 @@ +interface Props { + email: string; + code: string; +} + +/** + * This route verifies the signup invite link + * @param {*} email + * @param {*} code + * @returns + */ +const verifySignupInvite = ({ email, code }: Props) => { + return fetch('/api/v1/invite-org/verify', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email, + code + }) + }); +}; + +export default verifySignupInvite; diff --git a/frontend/pages/api/auth/publicKeyInfisical.js b/frontend/pages/api/auth/publicKeyInfisical.js deleted file mode 100644 index 76cad1726..000000000 --- a/frontend/pages/api/auth/publicKeyInfisical.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * This route lets us get the public key of infisical. Th euser doesn't have to be authenticated since this is just the public key. - * @param {*} req - * @param {*} res - * @returns - */ -const publicKeyInfisical = (req, res) => { - return fetch("/api/v1/key/publicKey/infisical", { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }); -}; - -export default publicKeyInfisical; diff --git a/frontend/pages/api/auth/publicKeyInfisical.ts b/frontend/pages/api/auth/publicKeyInfisical.ts new file mode 100644 index 000000000..d3e0f646c --- /dev/null +++ b/frontend/pages/api/auth/publicKeyInfisical.ts @@ -0,0 +1,10 @@ +const publicKeyInfisical = () => { + return fetch('/api/v1/key/publicKey/infisical', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }); +}; + +export default publicKeyInfisical; diff --git a/frontend/pages/api/files/GetSecrets.js b/frontend/pages/api/files/GetSecrets.ts similarity index 53% rename from frontend/pages/api/files/GetSecrets.js rename to frontend/pages/api/files/GetSecrets.ts index fa91d0962..b8a116175 100644 --- a/frontend/pages/api/files/GetSecrets.js +++ b/frontend/pages/api/files/GetSecrets.ts @@ -1,4 +1,4 @@ -import SecurityClient from "~/utilities/SecurityClient.js"; +import SecurityClient from '~/utilities/SecurityClient'; /** * This function fetches the encrypted secrets from the .env file @@ -6,26 +6,26 @@ import SecurityClient from "~/utilities/SecurityClient.js"; * @param {*} env * @returns */ -const getSecrets = async (workspaceId, env) => { +const getSecrets = async (workspaceId: string, env: string) => { return SecurityClient.fetchCall( - "/api/v1/secret/" + + '/api/v1/secret/' + workspaceId + - "?" + + '?' + new URLSearchParams({ environment: env, - channel: "web", + channel: 'web' }), { - method: "GET", + method: 'GET', headers: { - "Content-Type": "application/json", - }, + 'Content-Type': 'application/json' + } } ).then(async (res) => { - if (res.status == 200) { + if (res && res.status == 200) { return await res.json(); } else { - console.log("Failed to get project secrets"); + console.log('Failed to get project secrets'); } }); }; diff --git a/frontend/pages/api/files/UploadSecrets.js b/frontend/pages/api/files/UploadSecrets.js deleted file mode 100644 index c2f94e64d..000000000 --- a/frontend/pages/api/files/UploadSecrets.js +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This function uploads the encrypted .env file - * @param {*} req - * @param {*} res - * @returns - */ -const uploadSecrets = async ({ workspaceId, secrets, keys, environment }) => { - return SecurityClient.fetchCall("/api/v1/secret/" + workspaceId, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - secrets, - keys, - environment, - channel: "web", - }), - }).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to push secrets"); - } - }); -}; - -export default uploadSecrets; diff --git a/frontend/pages/api/files/UploadSecrets.ts b/frontend/pages/api/files/UploadSecrets.ts new file mode 100644 index 000000000..3644778fb --- /dev/null +++ b/frontend/pages/api/files/UploadSecrets.ts @@ -0,0 +1,42 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + workspaceId: string; + secrets: any; + keys: string; + environment: string; +} + +/** + * This function uploads the encrypted .env file + * @param {*} req + * @param {*} res + * @returns + */ +const uploadSecrets = async ({ + workspaceId, + secrets, + keys, + environment +}: Props) => { + return SecurityClient.fetchCall('/api/v1/secret/' + workspaceId, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + secrets, + keys, + environment, + channel: 'web' + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to push secrets'); + } + }); +}; + +export default uploadSecrets; diff --git a/frontend/pages/api/integrations/ChangeHerokuConfigVars.js b/frontend/pages/api/integrations/ChangeHerokuConfigVars.js deleted file mode 100644 index 118848ae6..000000000 --- a/frontend/pages/api/integrations/ChangeHerokuConfigVars.js +++ /dev/null @@ -1,25 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -const changeHerokuConfigVars = ({ integrationId, key, secrets }) => { - return SecurityClient.fetchCall( - "/api/v1/integration/" + integrationId + "/sync", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - key, - secrets, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to sync secrets to Heroku"); - } - }); -}; - -export default changeHerokuConfigVars; diff --git a/frontend/pages/api/integrations/ChangeHerokuConfigVars.ts b/frontend/pages/api/integrations/ChangeHerokuConfigVars.ts new file mode 100644 index 000000000..e011bda7b --- /dev/null +++ b/frontend/pages/api/integrations/ChangeHerokuConfigVars.ts @@ -0,0 +1,41 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + integrationId: string; + key: { encryptedKey: any; nonce: any }; + secrets: { + ciphertextKey: any; + ivKey: any; + tagKey: any; + hashKey: any; + ciphertextValue: any; + ivValue: any; + tagValue: any; + hashValue: any; + type: string; + }[]; +} + +const changeHerokuConfigVars = ({ integrationId, key, secrets }: Props) => { + return SecurityClient.fetchCall( + '/api/v1/integration/' + integrationId + '/sync', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + key, + secrets + }) + } + ).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to sync secrets to Heroku'); + } + }); +}; + +export default changeHerokuConfigVars; diff --git a/frontend/pages/api/integrations/DeleteIntegration.js b/frontend/pages/api/integrations/DeleteIntegration.js deleted file mode 100644 index 7698d7eae..000000000 --- a/frontend/pages/api/integrations/DeleteIntegration.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route deletes an integration from a certain project - * @param {*} integrationId - * @returns - */ -const deleteIntegration = ({ integrationId }) => { - return SecurityClient.fetchCall( - "/api/v1/integration/" + integrationId, - { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).workspace; - } else { - console.log("Failed to delete an integration"); - } - }); -}; - -export default deleteIntegration; diff --git a/frontend/pages/api/integrations/DeleteIntegration.ts b/frontend/pages/api/integrations/DeleteIntegration.ts new file mode 100644 index 000000000..89aa0ab0c --- /dev/null +++ b/frontend/pages/api/integrations/DeleteIntegration.ts @@ -0,0 +1,27 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + integrationId: string; +} + +/** + * This route deletes an integration from a certain project + * @param {*} integrationId + * @returns + */ +const deleteIntegration = ({ integrationId }: Props) => { + return SecurityClient.fetchCall('/api/v1/integration/' + integrationId, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).workspace; + } else { + console.log('Failed to delete an integration'); + } + }); +}; + +export default deleteIntegration; diff --git a/frontend/pages/api/integrations/DeleteIntegrationAuth.js b/frontend/pages/api/integrations/DeleteIntegrationAuth.js deleted file mode 100644 index eb6106e8e..000000000 --- a/frontend/pages/api/integrations/DeleteIntegrationAuth.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route deletes an integration authorization from a certain project - * @param {*} integrationAuthId - * @returns - */ -const deleteIntegrationAuth = ({ integrationAuthId }) => { - return SecurityClient.fetchCall( - "/api/v1/integration-auth/" + integrationAuthId, - { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to delete an integration authorization"); - } - }); -}; - -export default deleteIntegrationAuth; diff --git a/frontend/pages/api/integrations/DeleteIntegrationAuth.ts b/frontend/pages/api/integrations/DeleteIntegrationAuth.ts new file mode 100644 index 000000000..3a2da2cbf --- /dev/null +++ b/frontend/pages/api/integrations/DeleteIntegrationAuth.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + integrationAuthId: string; +} + +/** + * This route deletes an integration authorization from a certain project + * @param {*} integrationAuthId + * @returns + */ +const deleteIntegrationAuth = ({ integrationAuthId }: Props) => { + return SecurityClient.fetchCall( + '/api/v1/integration-auth/' + integrationAuthId, + { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to delete an integration authorization'); + } + }); +}; + +export default deleteIntegrationAuth; diff --git a/frontend/pages/api/integrations/GetIntegrationApps.js b/frontend/pages/api/integrations/GetIntegrationApps.js deleted file mode 100644 index dc0bfb4b6..000000000 --- a/frontend/pages/api/integrations/GetIntegrationApps.js +++ /dev/null @@ -1,21 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -const getIntegrationApps = ({ integrationAuthId }) => { - return SecurityClient.fetchCall( - "/api/v1/integration-auth/" + integrationAuthId + "/apps", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).apps; - } else { - console.log("Failed to get available apps for an integration"); - } - }); -}; - -export default getIntegrationApps; diff --git a/frontend/pages/api/integrations/GetIntegrationApps.ts b/frontend/pages/api/integrations/GetIntegrationApps.ts new file mode 100644 index 000000000..5597c24b1 --- /dev/null +++ b/frontend/pages/api/integrations/GetIntegrationApps.ts @@ -0,0 +1,25 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + integrationAuthId: string; +} + +const getIntegrationApps = ({ integrationAuthId }: Props) => { + return SecurityClient.fetchCall( + '/api/v1/integration-auth/' + integrationAuthId + '/apps', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).apps; + } else { + console.log('Failed to get available apps for an integration'); + } + }); +}; + +export default getIntegrationApps; diff --git a/frontend/pages/api/integrations/GetIntegrations.js b/frontend/pages/api/integrations/GetIntegrations.js deleted file mode 100644 index 401c80d3b..000000000 --- a/frontend/pages/api/integrations/GetIntegrations.js +++ /dev/null @@ -1,18 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -const getIntegrations = () => { - return SecurityClient.fetchCall("/api/v1/integration/integrations", { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }).then(async (res) => { - if (res.status == 200) { - return (await res.json()).integrations; - } else { - console.log("Failed to get project integrations"); - } - }); -}; - -export default getIntegrations; diff --git a/frontend/pages/api/integrations/GetIntegrations.ts b/frontend/pages/api/integrations/GetIntegrations.ts new file mode 100644 index 000000000..c189010a4 --- /dev/null +++ b/frontend/pages/api/integrations/GetIntegrations.ts @@ -0,0 +1,18 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +const getIntegrations = () => { + return SecurityClient.fetchCall('/api/v1/integration/integrations', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).integrations; + } else { + console.log('Failed to get project integrations'); + } + }); +}; + +export default getIntegrations; diff --git a/frontend/pages/api/integrations/StartIntegration.js b/frontend/pages/api/integrations/StartIntegration.js deleted file mode 100644 index a4e8b0b02..000000000 --- a/frontend/pages/api/integrations/StartIntegration.js +++ /dev/null @@ -1,33 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route starts the integration after teh default one if gonna set up. - * @param {*} integrationId - * @returns - */ -const startIntegration = ({ integrationId, appName, environment }) => { - return SecurityClient.fetchCall( - "/api/v1/integration/" + integrationId, - { - method: "PATCH", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - update: { - app: appName, - environment, - isActive: true, - }, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to start an integration"); - } - }); -}; - -export default startIntegration; diff --git a/frontend/pages/api/integrations/StartIntegration.ts b/frontend/pages/api/integrations/StartIntegration.ts new file mode 100644 index 000000000..bef82e7e1 --- /dev/null +++ b/frontend/pages/api/integrations/StartIntegration.ts @@ -0,0 +1,36 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + integrationId: string; + appName: string; + environment: string; +} + +/** + * This route starts the integration after teh default one if gonna set up. + * @param {*} integrationId + * @returns + */ +const startIntegration = ({ integrationId, appName, environment }: Props) => { + return SecurityClient.fetchCall('/api/v1/integration/' + integrationId, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + update: { + app: appName, + environment, + isActive: true + } + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to start an integration'); + } + }); +}; + +export default startIntegration; diff --git a/frontend/pages/api/integrations/authorizeIntegration.js b/frontend/pages/api/integrations/authorizeIntegration.js deleted file mode 100644 index b9a1d3995..000000000 --- a/frontend/pages/api/integrations/authorizeIntegration.js +++ /dev/null @@ -1,31 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This is the first step of the change password process (pake) - * @param {*} clientPublicKey - * @returns - */ -const AuthorizeIntegration = ({ workspaceId, code, integration }) => { - return SecurityClient.fetchCall( - "/api/v1/integration-auth/oauth-token", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - workspaceId, - code, - integration, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to authorize the integration"); - } - }); -}; - -export default AuthorizeIntegration; diff --git a/frontend/pages/api/integrations/authorizeIntegration.ts b/frontend/pages/api/integrations/authorizeIntegration.ts new file mode 100644 index 000000000..83158f594 --- /dev/null +++ b/frontend/pages/api/integrations/authorizeIntegration.ts @@ -0,0 +1,33 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + workspaceId: string; + code: string; + integration: string; +} +/** + * This is the first step of the change password process (pake) + * @param {*} clientPublicKey + * @returns + */ +const AuthorizeIntegration = ({ workspaceId, code, integration }: Props) => { + return SecurityClient.fetchCall('/api/v1/integration-auth/oauth-token', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + workspaceId, + code, + integration + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to authorize the integration'); + } + }); +}; + +export default AuthorizeIntegration; diff --git a/frontend/pages/api/integrations/getWorkspaceAuthorizations.js b/frontend/pages/api/integrations/getWorkspaceAuthorizations.js deleted file mode 100644 index ad8c4732b..000000000 --- a/frontend/pages/api/integrations/getWorkspaceAuthorizations.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route gets authorizations of a certain project (Heroku, etc.) - * @param {*} workspaceId - * @returns - */ -const getWorkspaceAuthorizations = ({ workspaceId }) => { - return SecurityClient.fetchCall( - "/api/v1/workspace/" + workspaceId + "/authorizations", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).authorizations; - } else { - console.log("Failed to get project authorizations"); - } - }); -}; - -export default getWorkspaceAuthorizations; diff --git a/frontend/pages/api/integrations/getWorkspaceAuthorizations.ts b/frontend/pages/api/integrations/getWorkspaceAuthorizations.ts new file mode 100644 index 000000000..f1b406555 --- /dev/null +++ b/frontend/pages/api/integrations/getWorkspaceAuthorizations.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + workspaceId: string; +} + +/** + * This route gets authorizations of a certain project (Heroku, etc.) + * @param {*} workspaceId + * @returns + */ +const getWorkspaceAuthorizations = ({ workspaceId }: Props) => { + return SecurityClient.fetchCall( + '/api/v1/workspace/' + workspaceId + '/authorizations', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).authorizations; + } else { + console.log('Failed to get project authorizations'); + } + }); +}; + +export default getWorkspaceAuthorizations; diff --git a/frontend/pages/api/integrations/getWorkspaceIntegrations.js b/frontend/pages/api/integrations/getWorkspaceIntegrations.js deleted file mode 100644 index 22470e4be..000000000 --- a/frontend/pages/api/integrations/getWorkspaceIntegrations.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route gets integrations of a certain project (Heroku, etc.) - * @param {*} workspaceId - * @returns - */ -const getWorkspaceIntegrations = ({ workspaceId }) => { - return SecurityClient.fetchCall( - "/api/v1/workspace/" + workspaceId + "/integrations", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).integrations; - } else { - console.log("Failed to get the project integrations"); - } - }); -}; - -export default getWorkspaceIntegrations; diff --git a/frontend/pages/api/integrations/getWorkspaceIntegrations.ts b/frontend/pages/api/integrations/getWorkspaceIntegrations.ts new file mode 100644 index 000000000..a33256749 --- /dev/null +++ b/frontend/pages/api/integrations/getWorkspaceIntegrations.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + workspaceId: string; +} + +/** + * This route gets integrations of a certain project (Heroku, etc.) + * @param {*} workspaceId + * @returns + */ +const getWorkspaceIntegrations = ({ workspaceId }: Props) => { + return SecurityClient.fetchCall( + '/api/v1/workspace/' + workspaceId + '/integrations', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).integrations; + } else { + console.log('Failed to get the project integrations'); + } + }); +}; + +export default getWorkspaceIntegrations; diff --git a/frontend/pages/api/organization/GetOrg.ts b/frontend/pages/api/organization/GetOrg.ts index ecb07bd2d..5e56e5c72 100644 --- a/frontend/pages/api/organization/GetOrg.ts +++ b/frontend/pages/api/organization/GetOrg.ts @@ -1,21 +1,21 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; /** * This route lets us get info about a certain org * @param {string} orgId - the organization ID * @returns */ -const getOrganization = ({ orgId }: { orgId: string; }) => { - return SecurityClient.fetchCall("/api/v1/organization/" + orgId, { - method: "GET", +const getOrganization = ({ orgId }: { orgId: string }) => { + return SecurityClient.fetchCall('/api/v1/organization/' + orgId, { + method: 'GET', headers: { - "Content-Type": "application/json", - }, + 'Content-Type': 'application/json' + } }).then(async (res) => { if (res?.status == 200) { return (await res.json()).organization; } else { - console.log("Failed to get org info"); + console.log('Failed to get org info'); } }); }; diff --git a/frontend/pages/api/organization/GetOrgProjects.js b/frontend/pages/api/organization/GetOrgProjects.js deleted file mode 100644 index 656fea18f..000000000 --- a/frontend/pages/api/organization/GetOrgProjects.js +++ /dev/null @@ -1,27 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route lets us get all the users in an org. - * @param {*} req - * @param {*} res - * @returns - */ -const getOrganizationProjects = (req, res) => { - return SecurityClient.fetchCall( - "/api/organization/" + req.orgId + "/workspaces", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).workspaces; - } else { - console.log("Failed to get projects for an org"); - } - }); -}; - -export default getOrganizationProjects; diff --git a/frontend/pages/api/organization/GetOrgProjects.ts b/frontend/pages/api/organization/GetOrgProjects.ts new file mode 100644 index 000000000..954694486 --- /dev/null +++ b/frontend/pages/api/organization/GetOrgProjects.ts @@ -0,0 +1,29 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route lets us get all the users in an org. + * @param {*} req + * @param {*} res + * @returns + */ + +// TODO: this file is not used anywhere +const getOrganizationProjects = (req: { orgId: string }) => { + return SecurityClient.fetchCall( + '/api/organization/' + req.orgId + '/workspaces', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).workspaces; + } else { + console.log('Failed to get projects for an org'); + } + }); +}; + +export default getOrganizationProjects; diff --git a/frontend/pages/api/organization/GetOrgSubscription.js b/frontend/pages/api/organization/GetOrgSubscription.js deleted file mode 100644 index 97c6f4e5c..000000000 --- a/frontend/pages/api/organization/GetOrgSubscription.js +++ /dev/null @@ -1,27 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route lets us get the current subscription of an org. - * @param {*} req - * @param {*} res - * @returns - */ -const getOrganizationSubscriptions = (req, res) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + req.orgId + "/subscriptions", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).subscriptions; - } else { - console.log("Failed to get org subscriptions"); - } - }); -}; - -export default getOrganizationSubscriptions; diff --git a/frontend/pages/api/organization/GetOrgSubscription.ts b/frontend/pages/api/organization/GetOrgSubscription.ts new file mode 100644 index 000000000..c93679cdc --- /dev/null +++ b/frontend/pages/api/organization/GetOrgSubscription.ts @@ -0,0 +1,27 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route lets us get the current subscription of an org. + * @param {*} req + * @param {*} res + * @returns + */ +const getOrganizationSubscriptions = (req: { orgId: string }) => { + return SecurityClient.fetchCall( + '/api/v1/organization/' + req.orgId + '/subscriptions', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).subscriptions; + } else { + console.log('Failed to get org subscriptions'); + } + }); +}; + +export default getOrganizationSubscriptions; diff --git a/frontend/pages/api/organization/GetOrgUserProjects.js b/frontend/pages/api/organization/GetOrgUserProjects.js deleted file mode 100644 index c2d751f64..000000000 --- a/frontend/pages/api/organization/GetOrgUserProjects.js +++ /dev/null @@ -1,27 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route lets us get all the projects of a certain user in an org. - * @param {*} req - * @param {*} res - * @returns - */ -const getOrganizationUserProjects = (req) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + req.orgId + "/my-workspaces", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).workspaces; - } else { - console.log("Failed to get projects of a user in an org"); - } - }); -}; - -export default getOrganizationUserProjects; diff --git a/frontend/pages/api/organization/GetOrgUserProjects.ts b/frontend/pages/api/organization/GetOrgUserProjects.ts new file mode 100644 index 000000000..872b8d781 --- /dev/null +++ b/frontend/pages/api/organization/GetOrgUserProjects.ts @@ -0,0 +1,27 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route lets us get all the projects of a certain user in an org. + * @param {*} req + * @param {*} res + * @returns + */ +const getOrganizationUserProjects = (req: { orgId: string }) => { + return SecurityClient.fetchCall( + '/api/v1/organization/' + req.orgId + '/my-workspaces', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).workspaces; + } else { + console.log('Failed to get projects of a user in an org'); + } + }); +}; + +export default getOrganizationUserProjects; diff --git a/frontend/pages/api/organization/GetOrgUsers.ts b/frontend/pages/api/organization/GetOrgUsers.ts index 53b9518cf..f1aaa7209 100644 --- a/frontend/pages/api/organization/GetOrgUsers.ts +++ b/frontend/pages/api/organization/GetOrgUsers.ts @@ -1,4 +1,4 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; /** * This route lets us get all the users in an org. @@ -6,20 +6,17 @@ import SecurityClient from "~/utilities/SecurityClient"; * @param {string} obj.orgId - organization Id * @returns */ -const getOrganizationUsers = ({ orgId }: { orgId: string; }) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + orgId + "/users", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, +const getOrganizationUsers = ({ orgId }: { orgId: string }) => { + return SecurityClient.fetchCall('/api/v1/organization/' + orgId + '/users', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' } - ).then(async (res) => { + }).then(async (res) => { if (res?.status == 200) { return (await res.json()).users; } else { - console.log("Failed to get org users"); + console.log('Failed to get org users'); } }); }; diff --git a/frontend/pages/api/organization/StripeRedirect.js b/frontend/pages/api/organization/StripeRedirect.js deleted file mode 100644 index e8911cf53..000000000 --- a/frontend/pages/api/organization/StripeRedirect.js +++ /dev/null @@ -1,27 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route redirects the user to the right stripe billing page. - * @param {*} req - * @param {*} res - * @returns - */ -const StripeRedirect = ({ orgId }) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + orgId + "/customer-portal-session", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (window.location.href = (await res.json()).url); - } else { - console.log("Failed to redirect to Stripe"); - } - }); -}; - -export default StripeRedirect; diff --git a/frontend/pages/api/organization/StripeRedirect.ts b/frontend/pages/api/organization/StripeRedirect.ts new file mode 100644 index 000000000..a9fe1f066 --- /dev/null +++ b/frontend/pages/api/organization/StripeRedirect.ts @@ -0,0 +1,27 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route redirects the user to the right stripe billing page. + * @param {*} req + * @param {*} res + * @returns + */ +const StripeRedirect = ({ orgId }: { orgId: string }) => { + return SecurityClient.fetchCall( + '/api/v1/organization/' + orgId + '/customer-portal-session', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (window.location.href = (await res.json()).url); + } else { + console.log('Failed to redirect to Stripe'); + } + }); +}; + +export default StripeRedirect; diff --git a/frontend/pages/api/organization/addIncidentContact.js b/frontend/pages/api/organization/addIncidentContact.js deleted file mode 100644 index 0e6068a1a..000000000 --- a/frontend/pages/api/organization/addIncidentContact.js +++ /dev/null @@ -1,29 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route add an incident contact email to a certain organization - * @param {*} param0 - * @returns - */ -const addIncidentContact = (organizationId, email) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + organizationId + "/incidentContactOrg", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: email, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to add an incident contact"); - } - }); -}; - -export default addIncidentContact; diff --git a/frontend/pages/api/organization/addIncidentContact.ts b/frontend/pages/api/organization/addIncidentContact.ts new file mode 100644 index 000000000..d3676e641 --- /dev/null +++ b/frontend/pages/api/organization/addIncidentContact.ts @@ -0,0 +1,29 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route add an incident contact email to a certain organization + * @param {*} param0 + * @returns + */ +const addIncidentContact = (organizationId: string, email: string) => { + return SecurityClient.fetchCall( + '/api/v1/organization/' + organizationId + '/incidentContactOrg', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email: email + }) + } + ).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to add an incident contact'); + } + }); +}; + +export default addIncidentContact; diff --git a/frontend/pages/api/organization/addUserToOrg.js b/frontend/pages/api/organization/addUserToOrg.js deleted file mode 100644 index 15f22cff9..000000000 --- a/frontend/pages/api/organization/addUserToOrg.js +++ /dev/null @@ -1,28 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This function sends an email invite to a user to join an org - * @param {*} email - * @param {*} orgId - * @returns - */ -const addUserToOrg = (email, orgId) => { - return SecurityClient.fetchCall("/api/v1/invite-org/signup", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - inviteeEmail: email, - organizationId: orgId, - }), - }).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to add a user to an org"); - } - }); -}; - -export default addUserToOrg; diff --git a/frontend/pages/api/organization/addUserToOrg.ts b/frontend/pages/api/organization/addUserToOrg.ts new file mode 100644 index 000000000..70dbad56c --- /dev/null +++ b/frontend/pages/api/organization/addUserToOrg.ts @@ -0,0 +1,28 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This function sends an email invite to a user to join an org + * @param {*} email + * @param {*} orgId + * @returns + */ +const addUserToOrg = (email: string, orgId: string) => { + return SecurityClient.fetchCall('/api/v1/invite-org/signup', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + inviteeEmail: email, + organizationId: orgId + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to add a user to an org'); + } + }); +}; + +export default addUserToOrg; diff --git a/frontend/pages/api/organization/deleteIncidentContact.js b/frontend/pages/api/organization/deleteIncidentContact.js deleted file mode 100644 index f6e57c590..000000000 --- a/frontend/pages/api/organization/deleteIncidentContact.js +++ /dev/null @@ -1,29 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route deletes an incident Contact from a certain organization - * @param {*} param0 - * @returns - */ -const deleteIncidentContact = (organizaionId, email) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + organizaionId + "/incidentContactOrg", - { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: email, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to delete an incident contact"); - } - }); -}; - -export default deleteIncidentContact; diff --git a/frontend/pages/api/organization/deleteIncidentContact.ts b/frontend/pages/api/organization/deleteIncidentContact.ts new file mode 100644 index 000000000..fd6374e9b --- /dev/null +++ b/frontend/pages/api/organization/deleteIncidentContact.ts @@ -0,0 +1,29 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route deletes an incident Contact from a certain organization + * @param {*} param0 + * @returns + */ +const deleteIncidentContact = (organizationId: string, email: string) => { + return SecurityClient.fetchCall( + '/api/v1/organization/' + organizationId + '/incidentContactOrg', + { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email: email + }) + } + ).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to delete an incident contact'); + } + }); +}; + +export default deleteIncidentContact; diff --git a/frontend/pages/api/organization/deleteUserFromOrganization.js b/frontend/pages/api/organization/deleteUserFromOrganization.js deleted file mode 100644 index 66ea84793..000000000 --- a/frontend/pages/api/organization/deleteUserFromOrganization.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This function removes a certain member from a certain organization - * @param {*} membershipId - * @returns - */ -const deleteUserFromOrganization = (membershipId) => { - return SecurityClient.fetchCall( - "/api/v1/membership-org/" + membershipId, - { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to delete a user from an org"); - } - }); -}; - -export default deleteUserFromOrganization; diff --git a/frontend/pages/api/organization/deleteUserFromOrganization.ts b/frontend/pages/api/organization/deleteUserFromOrganization.ts new file mode 100644 index 000000000..988a09485 --- /dev/null +++ b/frontend/pages/api/organization/deleteUserFromOrganization.ts @@ -0,0 +1,23 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This function removes a certain member from a certain organization + * @param {*} membershipId + * @returns + */ +const deleteUserFromOrganization = (membershipId: string) => { + return SecurityClient.fetchCall('/api/v1/membership-org/' + membershipId, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to delete a user from an org'); + } + }); +}; + +export default deleteUserFromOrganization; diff --git a/frontend/pages/api/organization/getIncidentContacts.js b/frontend/pages/api/organization/getIncidentContacts.js deleted file mode 100644 index 4f3f61a48..000000000 --- a/frontend/pages/api/organization/getIncidentContacts.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This routes gets all the incident contacts of a certain organization - * @param {*} workspaceId - * @returns - */ -const getIncidentContacts = (organizationId) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + organizationId + "/incidentContactOrg", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).incidentContactsOrg; - } else { - console.log("Failed to get incident contacts"); - } - }); -}; - -export default getIncidentContacts; diff --git a/frontend/pages/api/organization/getIncidentContacts.ts b/frontend/pages/api/organization/getIncidentContacts.ts new file mode 100644 index 000000000..bb9c3613a --- /dev/null +++ b/frontend/pages/api/organization/getIncidentContacts.ts @@ -0,0 +1,26 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This routes gets all the incident contacts of a certain organization + * @param {*} workspaceId + * @returns + */ +const getIncidentContacts = (organizationId: string) => { + return SecurityClient.fetchCall( + '/api/v1/organization/' + organizationId + '/incidentContactOrg', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).incidentContactsOrg; + } else { + console.log('Failed to get incident contacts'); + } + }); +}; + +export default getIncidentContacts; diff --git a/frontend/pages/api/organization/getOrgs.ts b/frontend/pages/api/organization/getOrgs.ts index cc655642f..5f01bc4d1 100644 --- a/frontend/pages/api/organization/getOrgs.ts +++ b/frontend/pages/api/organization/getOrgs.ts @@ -1,20 +1,20 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; /** * This route lets us get the all the orgs of a certain user. * @returns */ const getOrganizations = () => { - return SecurityClient.fetchCall("/api/v1/organization", { - method: "GET", + return SecurityClient.fetchCall('/api/v1/organization', { + method: 'GET', headers: { - "Content-Type": "application/json", - }, + 'Content-Type': 'application/json' + } }).then(async (res) => { if (res?.status == 200) { return (await res.json()).organizations; } else { - console.log("Failed to get orgs of a user"); + console.log('Failed to get orgs of a user'); } }); }; diff --git a/frontend/pages/api/organization/renameOrg.js b/frontend/pages/api/organization/renameOrg.js deleted file mode 100644 index a9d80a3a5..000000000 --- a/frontend/pages/api/organization/renameOrg.js +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route lets us rename a certain org. - * @param {*} req - * @param {*} res - * @returns - */ -const renameOrg = (orgId, newOrgName) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + orgId + "/name", - { - method: "PATCH", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - name: newOrgName, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to rename an organization"); - } - }); -}; - -export default renameOrg; diff --git a/frontend/pages/api/organization/renameOrg.ts b/frontend/pages/api/organization/renameOrg.ts new file mode 100644 index 000000000..c5c0b4d65 --- /dev/null +++ b/frontend/pages/api/organization/renameOrg.ts @@ -0,0 +1,27 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route lets us rename a certain org. + * @param {*} req + * @param {*} res + * @returns + */ +const renameOrg = (orgId: string, newOrgName: string) => { + return SecurityClient.fetchCall('/api/v1/organization/' + orgId + '/name', { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + name: newOrgName + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to rename an organization'); + } + }); +}; + +export default renameOrg; diff --git a/frontend/pages/api/serviceToken/addServiceToken.js b/frontend/pages/api/serviceToken/addServiceToken.ts similarity index 51% rename from frontend/pages/api/serviceToken/addServiceToken.js rename to frontend/pages/api/serviceToken/addServiceToken.ts index 4c6031db8..5dad69f69 100644 --- a/frontend/pages/api/serviceToken/addServiceToken.js +++ b/frontend/pages/api/serviceToken/addServiceToken.ts @@ -1,4 +1,14 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + name: string; + workspaceId: string; + environment: string; + expiresIn: number; + publicKey: string; + encryptedKey: string; + nonce: string; +} /** * This route gets service tokens for a specific user in a project @@ -12,12 +22,12 @@ const addServiceToken = ({ expiresIn, publicKey, encryptedKey, - nonce, -}) => { - return SecurityClient.fetchCall("/api/v1/service-token/", { - method: "POST", + nonce +}: Props) => { + return SecurityClient.fetchCall('/api/v1/service-token/', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, body: JSON.stringify({ name, @@ -26,13 +36,13 @@ const addServiceToken = ({ expiresIn, publicKey, encryptedKey, - nonce, - }), + nonce + }) }).then(async (res) => { - if (res.status == 200) { + if (res && res.status == 200) { return (await res.json()).token; } else { - console.log("Failed to add service tokens"); + console.log('Failed to add service tokens'); } }); }; diff --git a/frontend/pages/api/serviceToken/getServiceTokens.js b/frontend/pages/api/serviceToken/getServiceTokens.js deleted file mode 100644 index 79c6a7fc0..000000000 --- a/frontend/pages/api/serviceToken/getServiceTokens.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route gets service tokens for a specific user in a project - * @param {*} param0 - * @returns - */ -const getServiceTokens = ({ workspaceId }) => { - return SecurityClient.fetchCall( - "/api/v1/workspace/" + workspaceId + "/service-tokens", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).serviceTokens; - } else { - console.log("Failed to get service tokens"); - } - }); -}; - -export default getServiceTokens; diff --git a/frontend/pages/api/serviceToken/getServiceTokens.ts b/frontend/pages/api/serviceToken/getServiceTokens.ts new file mode 100644 index 000000000..d2577cc83 --- /dev/null +++ b/frontend/pages/api/serviceToken/getServiceTokens.ts @@ -0,0 +1,26 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route gets service tokens for a specific user in a project + * @param {*} param0 + * @returns + */ +const getServiceTokens = ({ workspaceId }: { workspaceId: string }) => { + return SecurityClient.fetchCall( + '/api/v1/workspace/' + workspaceId + '/service-tokens', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).serviceTokens; + } else { + console.log('Failed to get service tokens'); + } + }); +}; + +export default getServiceTokens; diff --git a/frontend/pages/api/user/getUser.ts b/frontend/pages/api/user/getUser.ts index 4bfebc5fe..7562b0f3b 100644 --- a/frontend/pages/api/user/getUser.ts +++ b/frontend/pages/api/user/getUser.ts @@ -1,19 +1,19 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; /** * This route gets the information about a specific user. */ const getUser = () => { - return SecurityClient.fetchCall("/api/v1/user", { - method: "GET", + return SecurityClient.fetchCall('/api/v1/user', { + method: 'GET', headers: { - "Content-Type": "application/json", - }, + 'Content-Type': 'application/json' + } }).then(async (res) => { if (res?.status == 200) { return (await res.json()).user; } else { - console.log("Failed to get user info"); + console.log('Failed to get user info'); } }); }; diff --git a/frontend/pages/api/userActions/checkUserAction.js b/frontend/pages/api/userActions/checkUserAction.ts similarity index 51% rename from frontend/pages/api/userActions/checkUserAction.js rename to frontend/pages/api/userActions/checkUserAction.ts index dfe217856..9941ae85a 100644 --- a/frontend/pages/api/userActions/checkUserAction.js +++ b/frontend/pages/api/userActions/checkUserAction.ts @@ -1,4 +1,4 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; /** * This route registers a certain action for a user @@ -6,24 +6,24 @@ import SecurityClient from "~/utilities/SecurityClient"; * @param {*} workspaceId * @returns */ -const checkUserAction = ({ action }) => { +const checkUserAction = ({ action }: { action: string }) => { return SecurityClient.fetchCall( - "/api/v1/user-action" + - "?" + + '/api/v1/user-action' + + '?' + new URLSearchParams({ - action, + action }), { - method: "GET", + method: 'GET', headers: { - "Content-Type": "application/json", - }, + 'Content-Type': 'application/json' + } } ).then(async (res) => { - if (res.status == 200) { + if (res && res.status == 200) { return (await res.json()).userAction; } else { - console.log("Failed to check a user action"); + console.log('Failed to check a user action'); } }); }; diff --git a/frontend/pages/api/userActions/registerUserAction.js b/frontend/pages/api/userActions/registerUserAction.js deleted file mode 100644 index 619886d89..000000000 --- a/frontend/pages/api/userActions/registerUserAction.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route registers a certain action for a user - * @param {*} action - * @returns - */ -const registerUserAction = ({ action }) => { - return SecurityClient.fetchCall("/api/v1/user-action", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - action, - }), - }).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to register a user action"); - } - }); -}; - -export default registerUserAction; diff --git a/frontend/pages/api/userActions/registerUserAction.ts b/frontend/pages/api/userActions/registerUserAction.ts new file mode 100644 index 000000000..d8f4d41e6 --- /dev/null +++ b/frontend/pages/api/userActions/registerUserAction.ts @@ -0,0 +1,26 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route registers a certain action for a user + * @param {*} action + * @returns + */ +const registerUserAction = ({ action }: { action: string }) => { + return SecurityClient.fetchCall('/api/v1/user-action', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + action + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to register a user action'); + } + }); +}; + +export default registerUserAction; diff --git a/frontend/pages/api/workspace/addUserToWorkspace.js b/frontend/pages/api/workspace/addUserToWorkspace.js deleted file mode 100644 index 86e991389..000000000 --- a/frontend/pages/api/workspace/addUserToWorkspace.js +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This function adds a user to a project - * @param {*} email - * @param {*} workspaceId - * @returns - */ -const addUserToWorkspace = (email, workspaceId) => { - return SecurityClient.fetchCall( - "/api/v1/workspace/" + workspaceId + "/invite-signup", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: email, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return await res.json(); - } else { - console.log("Failed to add a user to project"); - } - }); -}; - -export default addUserToWorkspace; diff --git a/frontend/pages/api/workspace/addUserToWorkspace.ts b/frontend/pages/api/workspace/addUserToWorkspace.ts new file mode 100644 index 000000000..e1efa51a1 --- /dev/null +++ b/frontend/pages/api/workspace/addUserToWorkspace.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This function adds a user to a project + * @param {*} email + * @param {*} workspaceId + * @returns + */ +const addUserToWorkspace = (email: string, workspaceId: string) => { + return SecurityClient.fetchCall( + '/api/v1/workspace/' + workspaceId + '/invite-signup', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email: email + }) + } + ).then(async (res) => { + if (res && res.status == 200) { + return await res.json(); + } else { + console.log('Failed to add a user to project'); + } + }); +}; + +export default addUserToWorkspace; diff --git a/frontend/pages/api/workspace/changeUserRoleInWorkspace.js b/frontend/pages/api/workspace/changeUserRoleInWorkspace.js deleted file mode 100644 index a93e22181..000000000 --- a/frontend/pages/api/workspace/changeUserRoleInWorkspace.js +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This function change the access of a user in a certain workspace - * @param {*} membershipId - * @param {*} role - * @returns - */ -const changeUserRoleInWorkspace = (membershipId, role) => { - return SecurityClient.fetchCall( - "/api/v1/membership/" + membershipId + "/change-role", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - role: role, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to change the user role in a project"); - } - }); -}; - -export default changeUserRoleInWorkspace; diff --git a/frontend/pages/api/workspace/changeUserRoleInWorkspace.ts b/frontend/pages/api/workspace/changeUserRoleInWorkspace.ts new file mode 100644 index 000000000..9ac49440a --- /dev/null +++ b/frontend/pages/api/workspace/changeUserRoleInWorkspace.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This function change the access of a user in a certain workspace + * @param {*} membershipId + * @param {*} role + * @returns + */ +const changeUserRoleInWorkspace = (membershipId: string, role: string) => { + return SecurityClient.fetchCall( + '/api/v1/membership/' + membershipId + '/change-role', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + role: role + }) + } + ).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to change the user role in a project'); + } + }); +}; + +export default changeUserRoleInWorkspace; diff --git a/frontend/pages/api/workspace/createWorkspace.ts b/frontend/pages/api/workspace/createWorkspace.ts index 0cedb0a57..877ef7567 100644 --- a/frontend/pages/api/workspace/createWorkspace.ts +++ b/frontend/pages/api/workspace/createWorkspace.ts @@ -1,4 +1,4 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; /** * This route creates a new workspace for a user within a certain organization. @@ -6,21 +6,27 @@ import SecurityClient from "~/utilities/SecurityClient"; * @param {string} organizationId - org ID * @returns */ -const createWorkspace = ( { workspaceName, organizationId }: { workspaceName: string; organizationId: string; }) => { - return SecurityClient.fetchCall("/api/v1/workspace", { - method: "POST", +const createWorkspace = ({ + workspaceName, + organizationId +}: { + workspaceName: string; + organizationId: string; +}) => { + return SecurityClient.fetchCall('/api/v1/workspace', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, body: JSON.stringify({ workspaceName: workspaceName, - organizationId: organizationId, - }), + organizationId: organizationId + }) }).then(async (res) => { if (res?.status == 200) { return (await res.json()).workspace; } else { - console.log("Failed to create a project"); + console.log('Failed to create a project'); } }); }; diff --git a/frontend/pages/api/workspace/deleteUserFromWorkspace.js b/frontend/pages/api/workspace/deleteUserFromWorkspace.js deleted file mode 100644 index bad8beced..000000000 --- a/frontend/pages/api/workspace/deleteUserFromWorkspace.js +++ /dev/null @@ -1,23 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This function removes a certain member from a certain workspace - * @param {*} membershipId - * @returns - */ -const deleteUserFromWorkspace = (membershipId) => { - return SecurityClient.fetchCall("/api/v1/membership/" + membershipId, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - }).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to delete a user from a project"); - } - }); -}; - -export default deleteUserFromWorkspace; diff --git a/frontend/pages/api/workspace/deleteUserFromWorkspace.ts b/frontend/pages/api/workspace/deleteUserFromWorkspace.ts new file mode 100644 index 000000000..ea02f96d4 --- /dev/null +++ b/frontend/pages/api/workspace/deleteUserFromWorkspace.ts @@ -0,0 +1,23 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This function removes a certain member from a certain workspace + * @param {*} membershipId + * @returns + */ +const deleteUserFromWorkspace = (membershipId: string) => { + return SecurityClient.fetchCall('/api/v1/membership/' + membershipId, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to delete a user from a project'); + } + }); +}; + +export default deleteUserFromWorkspace; diff --git a/frontend/pages/api/workspace/deleteWorkspace.js b/frontend/pages/api/workspace/deleteWorkspace.js deleted file mode 100644 index 33d34844d..000000000 --- a/frontend/pages/api/workspace/deleteWorkspace.js +++ /dev/null @@ -1,23 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route deletes a specified workspace. - * @param {*} workspaceId - * @returns - */ -const deleteWorkspace = (workspaceId) => { - return SecurityClient.fetchCall("/api/v1/workspace/" + workspaceId, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - }).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to delete a project"); - } - }); -}; - -export default deleteWorkspace; diff --git a/frontend/pages/api/workspace/deleteWorkspace.ts b/frontend/pages/api/workspace/deleteWorkspace.ts new file mode 100644 index 000000000..2bdb64cd3 --- /dev/null +++ b/frontend/pages/api/workspace/deleteWorkspace.ts @@ -0,0 +1,23 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route deletes a specified workspace. + * @param {*} workspaceId + * @returns + */ +const deleteWorkspace = (workspaceId: string) => { + return SecurityClient.fetchCall('/api/v1/workspace/' + workspaceId, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to delete a project'); + } + }); +}; + +export default deleteWorkspace; diff --git a/frontend/pages/api/workspace/getLatestFileKey.ts b/frontend/pages/api/workspace/getLatestFileKey.ts index 86ecb7456..1ecd2035d 100644 --- a/frontend/pages/api/workspace/getLatestFileKey.ts +++ b/frontend/pages/api/workspace/getLatestFileKey.ts @@ -1,24 +1,21 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; /** * Get the latest key pairs from a certain workspace * @param {string} workspaceId * @returns */ -const getLatestFileKey = ({ workspaceId } : { workspaceId: string; }) => { - return SecurityClient.fetchCall( - "/api/v1/key/" + workspaceId + "/latest", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, +const getLatestFileKey = ({ workspaceId }: { workspaceId: string }) => { + return SecurityClient.fetchCall('/api/v1/key/' + workspaceId + '/latest', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' } - ).then(async (res) => { + }).then(async (res) => { if (res?.status == 200) { return await res.json(); } else { - console.log("Failed to get the latest key pairs for a certain project"); + console.log('Failed to get the latest key pairs for a certain project'); } }); }; diff --git a/frontend/pages/api/workspace/getProjectInfo.ts b/frontend/pages/api/workspace/getProjectInfo.ts index c6eef9dce..a1ab0438c 100644 --- a/frontend/pages/api/workspace/getProjectInfo.ts +++ b/frontend/pages/api/workspace/getProjectInfo.ts @@ -1,24 +1,21 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; /** * This route lets us get the information of a certain project. * @param {*} projectId - project ID (we renamed workspaces to projects in the app) * @returns */ -const getProjectInfo = ({ projectId }: { projectId: string; }) => { - return SecurityClient.fetchCall( - "/api/v1/workspace/" + projectId, - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, +const getProjectInfo = ({ projectId }: { projectId: string }) => { + return SecurityClient.fetchCall('/api/v1/workspace/' + projectId, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' } - ).then(async (res) => { + }).then(async (res) => { if (res?.status == 200) { return (await res.json()).workspace; } else { - console.log("Failed to get project info"); + console.log('Failed to get project info'); } }); }; diff --git a/frontend/pages/api/workspace/getWorkspaceUsers.ts b/frontend/pages/api/workspace/getWorkspaceUsers.ts index 9805c2695..c4f00eb0d 100644 --- a/frontend/pages/api/workspace/getWorkspaceUsers.ts +++ b/frontend/pages/api/workspace/getWorkspaceUsers.ts @@ -1,24 +1,24 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; /** * This route lets us get all the users in the workspace. * @param {string} workspaceId - workspace ID * @returns */ -const getWorkspaceUsers = ({ workspaceId }: { workspaceId: string; }) => { +const getWorkspaceUsers = ({ workspaceId }: { workspaceId: string }) => { return SecurityClient.fetchCall( - "/api/v1/workspace/" + workspaceId + "/users", + '/api/v1/workspace/' + workspaceId + '/users', { - method: "GET", + method: 'GET', headers: { - "Content-Type": "application/json", - }, + 'Content-Type': 'application/json' + } } ).then(async (res) => { if (res?.status == 200) { return (await res.json()).users; } else { - console.log("Failed to get Project Users"); + console.log('Failed to get Project Users'); } }); }; diff --git a/frontend/pages/api/workspace/getWorkspaces.ts b/frontend/pages/api/workspace/getWorkspaces.ts index a77a04751..1bbb42c7a 100644 --- a/frontend/pages/api/workspace/getWorkspaces.ts +++ b/frontend/pages/api/workspace/getWorkspaces.ts @@ -1,4 +1,4 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; interface Workspace { __v: number; @@ -12,18 +12,18 @@ interface Workspace { * @returns */ const getWorkspaces = () => { - return SecurityClient.fetchCall("/api/v1/workspace", { - method: "GET", + return SecurityClient.fetchCall('/api/v1/workspace', { + method: 'GET', headers: { - "Content-Type": "application/json", - }, + 'Content-Type': 'application/json' + } }).then(async (res) => { if (res?.status == 200) { const data = (await res.json()) as unknown as { workspaces: Workspace[] }; return data.workspaces; } - throw new Error("Failed to get projects"); + throw new Error('Failed to get projects'); }); }; diff --git a/frontend/pages/api/workspace/renameWorkspace.js b/frontend/pages/api/workspace/renameWorkspace.js deleted file mode 100644 index 6dd297f82..000000000 --- a/frontend/pages/api/workspace/renameWorkspace.js +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route lets us rename a certain workspace. - * @param {*} req - * @param {*} res - * @returns - */ -const renameWorkspace = (workspaceId, newWorkspaceName) => { - return SecurityClient.fetchCall( - "/api/v1/workspace/" + workspaceId + "/name", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - name: newWorkspaceName, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to rename a project"); - } - }); -}; - -export default renameWorkspace; diff --git a/frontend/pages/api/workspace/renameWorkspace.ts b/frontend/pages/api/workspace/renameWorkspace.ts new file mode 100644 index 000000000..a25d2068c --- /dev/null +++ b/frontend/pages/api/workspace/renameWorkspace.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route lets us rename a certain workspace. + * @param {*} req + * @param {*} res + * @returns + */ +const renameWorkspace = (workspaceId: string, newWorkspaceName: string) => { + return SecurityClient.fetchCall( + '/api/v1/workspace/' + workspaceId + '/name', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + name: newWorkspaceName + }) + } + ).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to rename a project'); + } + }); +}; + +export default renameWorkspace; diff --git a/frontend/pages/api/workspace/uploadKeys.js b/frontend/pages/api/workspace/uploadKeys.js deleted file mode 100644 index 37b384f30..000000000 --- a/frontend/pages/api/workspace/uploadKeys.js +++ /dev/null @@ -1,33 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route uplods the keys in an encrypted format. - * @param {*} workspaceId - * @param {*} userId - * @param {*} encryptedKey - * @param {*} nonce - * @returns - */ -const uploadKeys = (workspaceId, userId, encryptedKey, nonce) => { - return SecurityClient.fetchCall("/api/v1/key/" + workspaceId, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - key: { - userId: userId, - encryptedKey: encryptedKey, - nonce: nonce, - }, - }), - }).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to upload keys for a new user"); - } - }); -}; - -export default uploadKeys; diff --git a/frontend/pages/api/workspace/uploadKeys.ts b/frontend/pages/api/workspace/uploadKeys.ts new file mode 100644 index 000000000..2f791735d --- /dev/null +++ b/frontend/pages/api/workspace/uploadKeys.ts @@ -0,0 +1,38 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route uplods the keys in an encrypted format. + * @param {*} workspaceId + * @param {*} userId + * @param {*} encryptedKey + * @param {*} nonce + * @returns + */ +const uploadKeys = ( + workspaceId: string, + userId: string, + encryptedKey: string, + nonce: string +) => { + return SecurityClient.fetchCall('/api/v1/key/' + workspaceId, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + key: { + userId: userId, + encryptedKey: encryptedKey, + nonce: nonce + } + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to upload keys for a new user'); + } + }); +}; + +export default uploadKeys; diff --git a/frontend/pages/dashboard/[id].js b/frontend/pages/dashboard/[id].js index bec6849ad..89dc64633 100644 --- a/frontend/pages/dashboard/[id].js +++ b/frontend/pages/dashboard/[id].js @@ -1,7 +1,7 @@ -import React, { Fragment, useCallback, useEffect, useState } from "react"; -import Head from "next/head"; -import Image from "next/image"; -import { useRouter } from "next/router"; +import React, { Fragment, useCallback, useEffect, useState } from 'react'; +import Head from 'next/head'; +import Image from 'next/image'; +import { useRouter } from 'next/router'; import { faArrowDownAZ, faArrowDownZA, @@ -18,29 +18,29 @@ import { faPerson, faPlus, faShuffle, - faX, -} from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Menu, Transition } from "@headlessui/react"; + faX +} from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Menu, Transition } from '@headlessui/react'; -import Button from "~/components/basic/buttons/Button"; -import ListBox from "~/components/basic/Listbox"; -import BottonRightPopup from "~/components/basic/popups/BottomRightPopup"; -import { useNotificationContext } from "~/components/context/Notifications/NotificationProvider"; -import DashboardInputField from "~/components/dashboard/DashboardInputField"; -import DropZone from "~/components/dashboard/DropZone"; -import NavHeader from "~/components/navigation/NavHeader"; -import getSecretsForProject from "~/components/utilities/secrets/getSecretsForProject"; -import pushKeys from "~/components/utilities/secrets/pushKeys"; -import pushKeysIntegration from "~/components/utilities/secrets/pushKeysIntegration"; -import guidGenerator from "~/utilities/randomId"; +import Button from '~/components/basic/buttons/Button'; +import ListBox from '~/components/basic/Listbox'; +import BottonRightPopup from '~/components/basic/popups/BottomRightPopup'; +import { useNotificationContext } from '~/components/context/Notifications/NotificationProvider'; +import DashboardInputField from '~/components/dashboard/DashboardInputField'; +import DropZone from '~/components/dashboard/DropZone'; +import NavHeader from '~/components/navigation/NavHeader'; +import getSecretsForProject from '~/components/utilities/secrets/getSecretsForProject'; +import pushKeys from '~/components/utilities/secrets/pushKeys'; +import pushKeysIntegration from '~/components/utilities/secrets/pushKeysIntegration'; +import guidGenerator from '~/utilities/randomId'; -import { envMapping } from "../../public/data/frequentConstants"; -import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations"; -import getUser from "../api/user/getUser"; -import checkUserAction from "../api/userActions/checkUserAction"; -import registerUserAction from "../api/userActions/registerUserAction"; -import getWorkspaces from "../api/workspace/getWorkspaces"; +import { envMapping } from '../../public/data/frequentConstants'; +import getWorkspaceIntegrations from '../api/integrations/getWorkspaceIntegrations'; +import getUser from '../api/user/getUser'; +import checkUserAction from '../api/userActions/checkUserAction'; +import registerUserAction from '../api/userActions/registerUserAction'; +import getWorkspaces from '../api/workspace/getWorkspaces'; /** * This component represent a single row for an environemnt variable on the dashboard @@ -61,7 +61,7 @@ const KeyPair = ({ modifyValue, modifyVisibility, isBlurred, - duplicates, + duplicates }) => { const [randomStringLength, setRandomStringLength] = useState(32); @@ -114,7 +114,7 @@ const KeyPair = ({
modifyVisibility( - keyPair[4] == "personal" ? "shared" : "personal", + keyPair[4] == 'personal' ? 'shared' : 'personal', keyPair[1] ) } @@ -122,10 +122,10 @@ const KeyPair = ({ >
- {keyPair[4] == "personal" ? "Make Shared" : "Make Personal"} + {keyPair[4] == 'personal' ? 'Make Shared' : 'Make Personal'}
Math.floor(Math.random() * 16).toString(16)) - .join(""), + .join(''), keyPair[1] ); } @@ -147,7 +147,7 @@ const KeyPair = ({ >

Generate Random Hex

@@ -210,21 +210,21 @@ export default function Dashboard() { const [fileState, setFileState] = useState([]); const [buttonReady, setButtonReady] = useState(false); const router = useRouter(); - const [workspaceId, setWorkspaceId] = useState(""); + const [workspaceId, setWorkspaceId] = useState(''); const [blurred, setBlurred] = useState(true); const [isKeyAvailable, setIsKeyAvailable] = useState(true); const [env, setEnv] = useState( - router.asPath.split("?").length == 1 - ? "Development" - : Object.keys(envMapping).includes(router.asPath.split("?")[1]) - ? router.asPath.split("?")[1] - : "Development" + router.asPath.split('?').length == 1 + ? 'Development' + : Object.keys(envMapping).includes(router.asPath.split('?')[1]) + ? router.asPath.split('?')[1] + : 'Development' ); const [isNew, setIsNew] = useState(false); - const [searchKeys, setSearchKeys] = useState(""); + const [searchKeys, setSearchKeys] = useState(''); const [errorDragAndDrop, setErrorDragAndDrop] = useState(false); const [projectIdCopied, setProjectIdCopied] = useState(false); - const [sortMethod, setSortMethod] = useState("alphabetical"); + const [sortMethod, setSortMethod] = useState('alphabetical'); const [checkDocsPopUpVisible, setCheckDocsPopUpVisible] = useState(false); const [hasUserEverPushed, setHasUserEverPushed] = useState(false); @@ -248,16 +248,16 @@ export default function Dashboard() { // prompt the user if they try and leave with unsaved changes useEffect(() => { const warningText = - "Do you want to save your results before leaving this page?"; + 'Do you want to save your results before leaving this page?'; const handleWindowClose = (e) => { if (!buttonReady) return; e.preventDefault(); return (e.returnValue = warningText); }; - window.addEventListener("beforeunload", handleWindowClose); + window.addEventListener('beforeunload', handleWindowClose); // router.events.on('routeChangeStart', beforeRouteHandler); return () => { - window.removeEventListener("beforeunload", handleWindowClose); + window.removeEventListener('beforeunload', handleWindowClose); // router.events.off('routeChangeStart', beforeRouteHandler); }; }, [buttonReady]); @@ -267,7 +267,7 @@ export default function Dashboard() { */ const reorderRows = () => { setSortMethod( - sortMethod == "alphabetical" ? "-alphabetical" : "alphabetical" + sortMethod == 'alphabetical' ? '-alphabetical' : 'alphabetical' ); }; @@ -277,13 +277,13 @@ export default function Dashboard() { let userWorkspaces = await getWorkspaces(); const listWorkspaces = userWorkspaces.map((workspace) => workspace._id); if ( - !listWorkspaces.includes(router.asPath.split("/")[2].split("?")[0]) + !listWorkspaces.includes(router.asPath.split('/')[2].split('?')[0]) ) { - router.push("/dashboard/" + listWorkspaces[0]); + router.push('/dashboard/' + listWorkspaces[0]); } - if (env != router.asPath.split("?")[1]) { - router.push(router.asPath.split("?")[0] + "?" + env); + if (env != router.asPath.split('?')[1]) { + router.push(router.asPath.split('?')[0] + '?' + env); } setBlurred(true); setWorkspaceId(router.query.id); @@ -293,7 +293,7 @@ export default function Dashboard() { setFileState, setIsKeyAvailable, setData, - workspaceId: router.query.id, + workspaceId: router.query.id }); const user = await getUser(); @@ -304,11 +304,11 @@ export default function Dashboard() { ); let userAction = await checkUserAction({ - action: "first_time_secrets_pushed", + action: 'first_time_secrets_pushed' }); setHasUserEverPushed(userAction ? true : false); } catch (error) { - console.log("Error", error); + console.log('Error', error); setData([]); } })(); @@ -317,7 +317,7 @@ export default function Dashboard() { const addRow = () => { setIsNew(false); - setData([...data, [guidGenerator(), data.length, "", "", "shared"]]); + setData([...data, [guidGenerator(), data.length, '', '', 'shared']]); }; const deleteRow = (id) => { @@ -385,15 +385,15 @@ export default function Dashboard() { if (nameErrors) { return createNotification({ - text: "Solve all name errors first!", - type: "error", + text: 'Solve all name errors first!', + type: 'error' }); } if (duplicatesExist) { return createNotification({ text: "Your secrets weren't saved; please fix the conflicts first.", - type: "error", + type: 'error' }); } @@ -406,7 +406,7 @@ export default function Dashboard() { * If there are any, update environment variables for those integrations */ let integrations = await getWorkspaceIntegrations({ - workspaceId: router.query.id, + workspaceId: router.query.id }); integrations.map(async (integration) => { if ( @@ -419,7 +419,7 @@ export default function Dashboard() { ); await pushKeysIntegration({ obj: objIntegration, - integrationId: integration._id, + integrationId: integration._id }); } }); @@ -427,7 +427,7 @@ export default function Dashboard() { // If this user has never saved environment variables before, show them a prompt to read docs if (!hasUserEverPushed) { setCheckDocsPopUpVisible(true); - await registerUserAction({ action: "first_time_secrets_pushed" }); + await registerUserAction({ action: 'first_time_secrets_pushed' }); } }; @@ -442,12 +442,12 @@ export default function Dashboard() { // This function downloads the secrets as a .env file const download = () => { - const file = data.map((item) => [item[2], item[3]].join("=")).join("\n"); + const file = data.map((item) => [item[2], item[3]].join('=')).join('\n'); const blob = new Blob([file]); const fileDownloadUrl = URL.createObjectURL(blob); - let alink = document.createElement("a"); + let alink = document.createElement('a'); alink.href = fileDownloadUrl; - alink.download = envMapping[env] + ".env"; + alink.download = envMapping[env] + '.env'; alink.click(); }; @@ -459,7 +459,7 @@ export default function Dashboard() { * This function copies the project id to the clipboard */ function copyToClipboard() { - var copyText = document.getElementById("myInput"); + var copyText = document.getElementById('myInput'); copyText.select(); copyText.setSelectionRange(0, 99999); // For mobile devices @@ -502,7 +502,7 @@ export default function Dashboard() { {data?.length == 0 && ( setSearchKeys(e.target.value)} - placeholder={"Search keys..."} + placeholder={'Search keys...'} />
@@ -580,7 +580,7 @@ export default function Dashboard() { color="mineshaft" size="icon-md" icon={ - sortMethod == "alphabetical" + sortMethod == 'alphabetical' ? faArrowDownAZ : faArrowDownZA } @@ -651,10 +651,10 @@ export default function Dashboard() { keyPair[2] .toLowerCase() .includes(searchKeys.toLowerCase()) && - keyPair[4] == "personal" + keyPair[4] == 'personal' ) .sort((a, b) => - sortMethod == "alphabetical" + sortMethod == 'alphabetical' ? a[2].localeCompare(b[2]) : b[2].localeCompare(a[2]) ) @@ -680,7 +680,7 @@ export default function Dashboard() {
8 ? "h-3/4" : "h-min" + data?.length > 8 ? 'h-3/4' : 'h-min' }`} >
@@ -705,10 +705,10 @@ export default function Dashboard() { keyPair[2] .toLowerCase() .includes(searchKeys.toLowerCase()) && - keyPair[4] == "shared" + keyPair[4] == 'shared' ) .sort((a, b) => - sortMethod == "alphabetical" + sortMethod == 'alphabetical' ? a[2].localeCompare(b[2]) : b[2].localeCompare(a[2]) ) @@ -766,10 +766,10 @@ export default function Dashboard() { /> )} {fileState.message == - "Failed membership validation for workspace" && ( + 'Failed membership validation for workspace' && (

You are not authorized to view this project.

)} - {fileState.message == "Access needed to pull the latest file" || + {fileState.message == 'Access needed to pull the latest file' || (!isKeyAvailable && ( <> { const [integrationEnvironment, setIntegrationEnvironment] = useState( @@ -47,7 +47,7 @@ const Integration = ({ projectIntegration }) => { useEffect(async () => { const tempHerokuApps = await getIntegrationApps({ - integrationAuthId: projectIntegration.integrationAuth, + integrationAuthId: projectIntegration.integrationAuth }); const tempHerokuAppNames = tempHerokuApps.map((app) => app.name); setApps(tempHerokuAppNames); @@ -67,9 +67,9 @@ const Integration = ({ projectIntegration }) => { { const result = await startIntegration({ integrationId: projectIntegration._id, environment: envMapping[integrationEnvironment], - appName: integrationApp, + appName: integrationApp }); if (result?.status == 200) { let currentSecrets = await getSecretsForProject({ @@ -124,18 +124,18 @@ const Integration = ({ projectIntegration }) => { setFileState, setIsKeyAvailable, setData, - workspaceId: router.query.id, + workspaceId: router.query.id }); let obj = Object.assign( {}, ...currentSecrets.map((row) => ({ - [row[2]]: row[3], + [row[2]]: row[3] })) ); await pushKeysIntegration({ obj, - integrationId: projectIntegration._id, + integrationId: projectIntegration._id }); router.reload(); } @@ -148,7 +148,7 @@ const Integration = ({ projectIntegration }) => {
)} - {!["Heroku"].includes(integrations[integration].name) && ( + {!['Heroku'].includes(integrations[integration].name) && (
Coming Soon @@ -351,7 +353,8 @@ export default function Integrations() {

Click on a framework to get the setup instructions.

-
+
+
{frameworks.map((framework) => (
-
1 ? "text-sm px-1" : "text-xl px-2"} text-center w-full max-w-xs`}> - {framework?.image && integration logo} - {framework?.name && framework?.image &&
} +
1 + ? 'text-sm px-1' + : 'text-xl px-2' + } text-center w-full max-w-xs`} + > + {framework?.image && ( + integration logo + )} + {framework?.name && framework?.image && ( +
+ )} {framework?.name && framework.name}
diff --git a/frontend/pages/settings/org/[id].js b/frontend/pages/settings/org/[id].js index ca765abe7..80f6efc5d 100644 --- a/frontend/pages/settings/org/[id].js +++ b/frontend/pages/settings/org/[id].js @@ -1,62 +1,62 @@ -import React, { useEffect, useState } from "react"; -import Head from "next/head"; -import { useRouter } from "next/router"; +import React, { useEffect, useState } from 'react'; +import Head from 'next/head'; +import { useRouter } from 'next/router'; import { faMagnifyingGlass, faPlus, - faX, -} from "@fortawesome/free-solid-svg-icons"; -import { faCheck } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + faX +} from '@fortawesome/free-solid-svg-icons'; +import { faCheck } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import Button from "~/components/basic/buttons/Button"; -import AddIncidentContactDialog from "~/components/basic/dialog/AddIncidentContactDialog"; -import AddUserDialog from "~/components/basic/dialog/AddUserDialog"; -import InputField from "~/components/basic/InputField"; -import UserTable from "~/components/basic/table/UserTable"; -import NavHeader from "~/components/navigation/NavHeader"; -import guidGenerator from "~/utilities/randomId"; +import Button from '~/components/basic/buttons/Button'; +import AddIncidentContactDialog from '~/components/basic/dialog/AddIncidentContactDialog'; +import AddUserDialog from '~/components/basic/dialog/AddUserDialog'; +import InputField from '~/components/basic/InputField'; +import UserTable from '~/components/basic/table/UserTable'; +import NavHeader from '~/components/navigation/NavHeader'; +import guidGenerator from '~/utilities/randomId'; -import addUserToOrg from "../../api/organization/addUserToOrg"; -import deleteIncidentContact from "../../api/organization/deleteIncidentContact"; -import getIncidentContacts from "../../api/organization/getIncidentContacts"; -import getOrganization from "../../api/organization/GetOrg"; -import getOrganizationSubscriptions from "../../api/organization/GetOrgSubscription"; -import getOrganizationUsers from "../../api/organization/GetOrgUsers"; -import renameOrg from "../../api/organization/renameOrg"; -import getUser from "../../api/user/getUser"; -import deleteWorkspace from "../../api/workspace/deleteWorkspace"; -import getWorkspaces from "../../api/workspace/getWorkspaces"; +import addUserToOrg from '../../api/organization/addUserToOrg'; +import deleteIncidentContact from '../../api/organization/deleteIncidentContact'; +import getIncidentContacts from '../../api/organization/getIncidentContacts'; +import getOrganization from '../../api/organization/GetOrg'; +import getOrganizationSubscriptions from '../../api/organization/GetOrgSubscription'; +import getOrganizationUsers from '../../api/organization/GetOrgUsers'; +import renameOrg from '../../api/organization/renameOrg'; +import getUser from '../../api/user/getUser'; +import deleteWorkspace from '../../api/workspace/deleteWorkspace'; +import getWorkspaces from '../../api/workspace/getWorkspaces'; export default function SettingsOrg() { const [buttonReady, setButtonReady] = useState(false); const router = useRouter(); - const [orgName, setOrgName] = useState(""); - const [emailUser, setEmailUser] = useState(""); - const [workspaceToBeDeletedName, setWorkspaceToBeDeletedName] = useState(""); - const [searchUsers, setSearchUsers] = useState(""); - const [workspaceId, setWorkspaceId] = useState(""); + const [orgName, setOrgName] = useState(''); + const [emailUser, setEmailUser] = useState(''); + const [workspaceToBeDeletedName, setWorkspaceToBeDeletedName] = useState(''); + const [searchUsers, setSearchUsers] = useState(''); + const [workspaceId, setWorkspaceId] = useState(''); const [isAddIncidentContactOpen, setIsAddIncidentContactOpen] = useState(false); const [isAddUserOpen, setIsAddUserOpen] = useState( - router.asPath.split("?")[1] == "invite" + router.asPath.split('?')[1] == 'invite' ); const [incidentContacts, setIncidentContacts] = useState([]); - const [searchIncidentContact, setSearchIncidentContact] = useState(""); + const [searchIncidentContact, setSearchIncidentContact] = useState(''); const [userList, setUserList] = useState(); - const [personalEmail, setPersonalEmail] = useState(""); + const [personalEmail, setPersonalEmail] = useState(''); let workspaceIdTemp; - const [email, setEmail] = useState(""); - const [currentPlan, setCurrentPlan] = useState(""); + const [email, setEmail] = useState(''); + const [currentPlan, setCurrentPlan] = useState(''); useEffect(async () => { let org = await getOrganization({ - orgId: localStorage.getItem("orgData.id"), + orgId: localStorage.getItem('orgData.id') }); let orgData = org; setOrgName(orgData.name); let incidentContactsData = await getIncidentContacts( - localStorage.getItem("orgData.id") + localStorage.getItem('orgData.id') ); setIncidentContacts(incidentContactsData?.map((contact) => contact.email)); @@ -66,7 +66,7 @@ export default function SettingsOrg() { workspaceIdTemp = router.query.id; let orgUsers = await getOrganizationUsers({ - orgId: localStorage.getItem("orgData.id"), + orgId: localStorage.getItem('orgData.id') }); setUserList( orgUsers.map((user) => ({ @@ -78,11 +78,11 @@ export default function SettingsOrg() { status: user?.status, userId: user.user?._id, membershipId: user._id, - publicKey: user.user?.publicKey, + publicKey: user.user?.publicKey })) ); const subscriptions = await getOrganizationSubscriptions({ - orgId: localStorage.getItem("orgData.id"), + orgId: localStorage.getItem('orgData.id') }); setCurrentPlan(subscriptions.data[0].plan.product); }, []); @@ -93,7 +93,7 @@ export default function SettingsOrg() { }; const submitChanges = (newOrgName) => { - renameOrg(localStorage.getItem("orgData.id"), newOrgName); + renameOrg(localStorage.getItem('orgData.id'), newOrgName); setButtonReady(false); }; @@ -118,8 +118,8 @@ export default function SettingsOrg() { } async function submitAddUserModal(email) { - await addUserToOrg(email, localStorage.getItem("orgData.id")); - setEmail(""); + await addUserToOrg(email, localStorage.getItem('orgData.id')); + setEmail(''); setIsAddUserOpen(false); router.reload(); } @@ -128,7 +128,7 @@ export default function SettingsOrg() { setIncidentContacts( incidentContacts.filter((contact) => contact != incidentContact) ); - deleteIncidentContact(localStorage.getItem("orgData.id"), incidentContact); + deleteIncidentContact(localStorage.getItem('orgData.id'), incidentContact); }; /** @@ -148,7 +148,7 @@ export default function SettingsOrg() { ) { await deleteWorkspace(router.query.id); let userWorkspaces = await getWorkspaces(); - router.push("/dashboard/" + userWorkspaces[0]._id); + router.push('/dashboard/' + userWorkspaces[0]._id); } } }; @@ -241,7 +241,7 @@ export default function SettingsOrg() { className="pl-2 text-gray-400 rounded-r-md bg-white/5 w-full h-full outline-none" value={searchUsers} onChange={(e) => setSearchUsers(e.target.value)} - placeholder={"Search members..."} + placeholder={'Search members...'} />
@@ -302,7 +302,7 @@ export default function SettingsOrg() { className="pl-2 text-gray-400 rounded-tr-md bg-white/5 w-full h-full outline-none" value={searchIncidentContact} onChange={(e) => setSearchIncidentContact(e.target.value)} - placeholder={"Search..."} + placeholder={'Search...'} />
{incidentContacts?.filter((email) => diff --git a/frontend/pages/signup.tsx b/frontend/pages/signup.tsx index 9486191f7..77015ab75 100644 --- a/frontend/pages/signup.tsx +++ b/frontend/pages/signup.tsx @@ -1,72 +1,72 @@ -import React, { useEffect, useRef, useState } from "react"; -import ReactCodeInput from "react-code-input"; -import dynamic from "next/dynamic"; -import Head from "next/head"; -import Image from "next/image"; -import Link from "next/link"; -import { useRouter } from "next/router"; -import { faCheck, faWarning, faX } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import React, { useEffect, useRef, useState } from 'react'; +import ReactCodeInput from 'react-code-input'; +import dynamic from 'next/dynamic'; +import Head from 'next/head'; +import Image from 'next/image'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; +import { faCheck, faWarning, faX } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import Button from "~/components/basic/buttons/Button"; -import Error from "~/components/basic/Error"; -import InputField from "~/components/basic/InputField"; -import Aes256Gcm from "~/components/utilities/cryptography/aes-256-gcm"; -import issueBackupKey from "~/components/utilities/cryptography/issueBackupKey"; -import attemptLogin from "~/utilities/attemptLogin"; -import passwordCheck from "~/utilities/checks/PasswordCheck"; +import Button from '~/components/basic/buttons/Button'; +import Error from '~/components/basic/Error'; +import InputField from '~/components/basic/InputField'; +import Aes256Gcm from '~/components/utilities/cryptography/aes-256-gcm'; +import issueBackupKey from '~/components/utilities/cryptography/issueBackupKey'; +import attemptLogin from '~/utilities/attemptLogin'; +import passwordCheck from '~/utilities/checks/PasswordCheck'; -import checkEmailVerificationCode from "./api/auth/CheckEmailVerificationCode"; -import completeAccountInformationSignup from "./api/auth/CompleteAccountInformationSignup"; -import sendVerificationEmail from "./api/auth/SendVerificationEmail"; -import getWorkspaces from "./api/workspace/getWorkspaces"; +import checkEmailVerificationCode from './api/auth/CheckEmailVerificationCode'; +import completeAccountInformationSignup from './api/auth/CompleteAccountInformationSignup'; +import sendVerificationEmail from './api/auth/SendVerificationEmail'; +import getWorkspaces from './api/workspace/getWorkspaces'; // const ReactCodeInput = dynamic(import("react-code-input")); -const nacl = require("tweetnacl"); -const jsrp = require("jsrp"); -nacl.util = require("tweetnacl-util"); +const nacl = require('tweetnacl'); +const jsrp = require('jsrp'); +nacl.util = require('tweetnacl-util'); const client = new jsrp.client(); // The stye for the verification code input const props = { inputStyle: { - fontFamily: "monospace", - margin: "4px", - MozAppearance: "textfield", - width: "55px", - borderRadius: "5px", - fontSize: "24px", - height: "55px", - paddingLeft: "7", - backgroundColor: "#0d1117", - color: "white", - border: "1px solid gray", - textAlign: "center", - }, + fontFamily: 'monospace', + margin: '4px', + MozAppearance: 'textfield', + width: '55px', + borderRadius: '5px', + fontSize: '24px', + height: '55px', + paddingLeft: '7', + backgroundColor: '#0d1117', + color: 'white', + border: '1px solid gray', + textAlign: 'center' + } } as const; const propsPhone = { inputStyle: { - fontFamily: "monospace", - margin: "4px", - MozAppearance: "textfield", - width: "40px", - borderRadius: "5px", - fontSize: "24px", - height: "40px", - paddingLeft: "7", - backgroundColor: "#0d1117", - color: "white", - border: "1px solid gray", - textAlign: "center", - }, + fontFamily: 'monospace', + margin: '4px', + MozAppearance: 'textfield', + width: '40px', + borderRadius: '5px', + fontSize: '24px', + height: '40px', + paddingLeft: '7', + backgroundColor: '#0d1117', + color: 'white', + border: '1px solid gray', + textAlign: 'center' + } } as const; export default function SignUp() { - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [firstName, setFirstName] = useState(""); - const [lastName, setLastName] = useState(""); - const [code, setCode] = useState(""); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [firstName, setFirstName] = useState(''); + const [lastName, setLastName] = useState(''); + const [code, setCode] = useState(''); const [codeError, setCodeError] = useState(false); const [firstNameError, setFirstNameError] = useState(false); const [lastNameError, setLastNameError] = useState(false); @@ -77,22 +77,22 @@ export default function SignUp() { const [passwordErrorSpecialChar, setPasswordErrorSpecialChar] = useState(false); const [emailError, setEmailError] = useState(false); - const [emailErrorMessage, setEmailErrorMessage] = useState(""); + const [emailErrorMessage, setEmailErrorMessage] = useState(''); const [step, setStep] = useState(1); const router = useRouter(); const [errorLogin, setErrorLogin] = useState(false); const [isLoading, setIsLoading] = useState(false); const [backupKeyError, setBackupKeyError] = useState(false); - const [verificationToken, setVerificationToken] = useState(); + const [verificationToken, setVerificationToken] = useState(''); const [backupKeyIssued, setBackupKeyIssued] = useState(false); useEffect(() => { const tryAuth = async () => { try { const userWorkspaces = await getWorkspaces(); - router.push("/dashboard/" + userWorkspaces[0]._id); + router.push('/dashboard/' + userWorkspaces[0]._id); } catch (error) { - console.log("Error - Not logged in yet"); + console.log('Error - Not logged in yet'); } }; tryAuth(); @@ -109,8 +109,8 @@ export default function SignUp() { setStep(2); } else if (step == 2) { // Checking if the code matches the email. - const response = await checkEmailVerificationCode(email, code); - if (response.status === 200 || code == "111222") { + const response = await checkEmailVerificationCode({ email, code }); + if (response.status === 200 || code == '111222') { setVerificationToken((await response.json()).token); setStep(3); } else { @@ -128,15 +128,15 @@ export default function SignUp() { let emailCheckBool = false; if (!email) { setEmailError(true); - setEmailErrorMessage("Please enter your email."); + setEmailErrorMessage('Please enter your email.'); emailCheckBool = true; } else if ( - !email.includes("@") || - !email.includes(".") || + !email.includes('@') || + !email.includes('.') || !/[a-z]/.test(email) ) { setEmailError(true); - setEmailErrorMessage("Please enter a valid email."); + setEmailErrorMessage('Please enter a valid email.'); emailCheckBool = true; } else { setEmailError(false); @@ -170,7 +170,7 @@ export default function SignUp() { setPasswordErrorLength, setPasswordErrorNumber, setPasswordErrorLowerCase, - currentErrorCheck: errorCheck, + currentErrorCheck: errorCheck }); if (!errorCheck) { @@ -187,16 +187,16 @@ export default function SignUp() { .slice(0, 32) .padStart( 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( { username: email, - password: password, + password: password }, async () => { client.createVerifier( @@ -212,17 +212,17 @@ export default function SignUp() { tag, salt: result.salt, verifier: result.verifier, - token: verificationToken, + token: verificationToken }); // if everything works, go the main dashboard page. if (response.status === 200) { // response = await response.json(); - localStorage.setItem("publicKey", PUBLIC_KEY); - localStorage.setItem("encryptedPrivateKey", ciphertext); - localStorage.setItem("iv", iv); - localStorage.setItem("tag", tag); + localStorage.setItem('publicKey', PUBLIC_KEY); + localStorage.setItem('encryptedPrivateKey', ciphertext); + localStorage.setItem('iv', iv); + localStorage.setItem('tag', tag); try { await attemptLogin( @@ -295,10 +295,10 @@ export default function SignUp() { const step2 = (

- {"We've"} sent a verification email to{" "} + {"We've"} sent a verification email to{' '}

- {email}{" "} + {email}{' '}

14 characters @@ -436,7 +436,7 @@ export default function SignUp() { )}
1 lowercase character @@ -456,7 +456,7 @@ export default function SignUp() { )}
1 number @@ -505,13 +505,13 @@ export default function SignUp() { await issueBackupKey({ email, password, - personalName: firstName + " " + lastName, + personalName: firstName + ' ' + lastName, setBackupKeyError, - setBackupKeyIssued, + setBackupKeyIssued }); const userWorkspaces = await getWorkspaces(); const userWorkspace = userWorkspaces[0]._id; - router.push("/home/" + userWorkspace); + router.push('/home/' + userWorkspace); }} size="lg" /> diff --git a/frontend/pages/users/[id].js b/frontend/pages/users/[id].js index de0307786..fe96ded3a 100644 --- a/frontend/pages/users/[id].js +++ b/frontend/pages/users/[id].js @@ -1,39 +1,39 @@ -import React, { useEffect, useState } from "react"; -import Head from "next/head"; -import Image from "next/image"; -import { useRouter } from "next/router"; -import { faMagnifyingGlass, faPlus } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import React, { useEffect, useState } from 'react'; +import Head from 'next/head'; +import Image from 'next/image'; +import { useRouter } from 'next/router'; +import { faMagnifyingGlass, faPlus } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import Button from "~/components/basic/buttons/Button"; -import AddProjectMemberDialog from "~/components/basic/dialog/AddProjectMemberDialog"; -import UserTable from "~/components/basic/table/UserTable"; -import NavHeader from "~/components/navigation/NavHeader"; -import guidGenerator from "~/utilities/randomId"; +import Button from '~/components/basic/buttons/Button'; +import AddProjectMemberDialog from '~/components/basic/dialog/AddProjectMemberDialog'; +import UserTable from '~/components/basic/table/UserTable'; +import NavHeader from '~/components/navigation/NavHeader'; +import guidGenerator from '~/utilities/randomId'; -import getOrganizationUsers from "../api/organization/GetOrgUsers"; -import getUser from "../api/user/getUser"; +import getOrganizationUsers from '../api/organization/GetOrgUsers'; +import getUser from '../api/user/getUser'; // import DeleteUserDialog from '~/components/basic/dialog/DeleteUserDialog'; -import addUserToWorkspace from "../api/workspace/addUserToWorkspace"; -import getWorkspaceUsers from "../api/workspace/getWorkspaceUsers"; -import uploadKeys from "../api/workspace/uploadKeys"; +import addUserToWorkspace from '../api/workspace/addUserToWorkspace'; +import getWorkspaceUsers from '../api/workspace/getWorkspaceUsers'; +import uploadKeys from '../api/workspace/uploadKeys'; // #TODO: Update all the workspaceIds -const crypto = require("crypto"); +const crypto = require('crypto'); const { decryptAssymmetric, - encryptAssymmetric, -} = require("../../components/utilities/cryptography/crypto"); -const nacl = require("tweetnacl"); -nacl.util = require("tweetnacl-util"); + encryptAssymmetric +} = require('../../components/utilities/cryptography/crypto'); +const nacl = require('tweetnacl'); +nacl.util = require('tweetnacl-util'); export default function Users() { let [isAddOpen, setIsAddOpen] = useState(false); // let [isDeleteOpen, setIsDeleteOpen] = useState(false); // let [userIdToBeDeleted, setUserIdToBeDeleted] = useState(false); - let [email, setEmail] = useState(""); - const [personalEmail, setPersonalEmail] = useState(""); - const [searchUsers, setSearchUsers] = useState(""); + let [email, setEmail] = useState(''); + const [personalEmail, setPersonalEmail] = useState(''); + const [searchUsers, setSearchUsers] = useState(''); const router = useRouter(); let workspaceId; @@ -57,25 +57,25 @@ export default function Users() { async function submitAddModal() { let result = await addUserToWorkspace(email, router.query.id); if (result?.invitee && result?.latestKey) { - const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); + const PRIVATE_KEY = localStorage.getItem('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, + privateKey: PRIVATE_KEY }); const { ciphertext, nonce } = encryptAssymmetric({ plaintext: key, publicKey: result.invitee.publicKey, - privateKey: PRIVATE_KEY, + privateKey: PRIVATE_KEY }); uploadKeys(router.query.id, result.invitee._id, ciphertext, nonce); } - setEmail(""); + setEmail(''); setIsAddOpen(false); router.reload(); } @@ -93,7 +93,7 @@ export default function Users() { workspaceId = router.query.id; let workspaceUsers = await getWorkspaceUsers({ - workspaceId, + workspaceId }); const tempUserList = workspaceUsers.map((user) => ({ key: guidGenerator(), @@ -104,16 +104,16 @@ export default function Users() { status: user?.status, userId: user.user?._id, membershipId: user._id, - publicKey: user.user?.publicKey, + publicKey: user.user?.publicKey })); setUserList(tempUserList); const orgUsers = await getOrganizationUsers({ - orgId: localStorage.getItem("orgData.id"), + orgId: localStorage.getItem('orgData.id') }); setOrgUserList(orgUsers); setEmail( orgUsers - ?.filter((user) => user.status == "accepted") + ?.filter((user) => user.status == 'accepted') .map((user) => user.user.email) .filter( (email) => !tempUserList?.map((user1) => user1.email).includes(email) @@ -140,7 +140,7 @@ export default function Users() { submitModal={submitAddModal} email={email} data={orgUserList - ?.filter((user) => user.status == "accepted") + ?.filter((user) => user.status == 'accepted') .map((user) => user.user.email) .filter( (email) => !userList?.map((user1) => user1.email).includes(email) @@ -159,7 +159,7 @@ export default function Users() { className="pl-2 text-gray-400 rounded-r-md bg-white/5 w-full h-full outline-none" value={searchUsers} onChange={(e) => setSearchUsers(e.target.value)} - placeholder={"Search members..."} + placeholder={'Search members...'} />
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index ce99bdc6d..e936a69a2 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -2,25 +2,13 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "~/components/*": [ - "components/*" - ], - "~/utilities/*": [ - "components/utilities/*" - ], - "~/*": [ - "const" - ], - "~/pages/*": [ - "pages/*" - ] + "~/components/*": ["components/*"], + "~/utilities/*": ["components/utilities/*"], + "~/*": ["const"], + "~/pages/*": ["pages/*"] }, - "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "target": "ESNext", + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -35,12 +23,6 @@ "jsx": "preserve", "incremental": true }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ], - "exclude": [ - "node_modules" - ] + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] }