Fix merge conflicts frontend integrations

This commit is contained in:
Tuan Dang
2022-12-11 11:45:47 -05:00
110 changed files with 2084 additions and 1847 deletions
+145 -147
View File
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
@@ -6,16 +7,16 @@ const jsrp = require('jsrp');
import { User } from '../models'; import { User } from '../models';
import { createToken, issueTokens, clearTokens } from '../helpers/auth'; import { createToken, issueTokens, clearTokens } from '../helpers/auth';
import { import {
NODE_ENV, NODE_ENV,
JWT_AUTH_LIFETIME, JWT_AUTH_LIFETIME,
JWT_AUTH_SECRET, JWT_AUTH_SECRET,
JWT_REFRESH_SECRET JWT_REFRESH_SECRET
} from '../config'; } from '../config';
declare module 'jsonwebtoken' { declare module 'jsonwebtoken' {
export interface UserIDJwtPayload extends jwt.JwtPayload { export interface UserIDJwtPayload extends jwt.JwtPayload {
userId: string; userId: string;
} }
} }
const clientPublicKeys: any = {}; const clientPublicKeys: any = {};
@@ -27,47 +28,45 @@ const clientPublicKeys: any = {};
* @returns * @returns
*/ */
export const login1 = async (req: Request, res: Response) => { export const login1 = async (req: Request, res: Response) => {
try { try {
const { const {
email, email,
clientPublicKey clientPublicKey
}: { email: string; clientPublicKey: string } = req.body; }: { email: string; clientPublicKey: string } = req.body;
const user = await User.findOne({ const user = await User.findOne({
email email
}).select('+salt +verifier'); }).select('+salt +verifier');
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
},
() => {
// generate server-side public key
const serverPublicKey = server.getPublicKey();
clientPublicKeys[email] = {
clientPublicKey,
serverBInt: bigintConversion.bigintToBuf(server.bInt)
};
const server = new jsrp.server(); return res.status(200).send({
server.init( serverPublicKey,
{ salt: user.salt
salt: user.salt, });
verifier: user.verifier }
}, );
() => { } catch (err) {
// generate server-side public key Sentry.setUser(null);
const serverPublicKey = server.getPublicKey(); Sentry.captureException(err);
clientPublicKeys[email] = { return res.status(400).send({
clientPublicKey, message: 'Failed to start authentication process'
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 * @returns
*/ */
export const login2 = async (req: Request, res: Response) => { export const login2 = async (req: Request, res: Response) => {
try { try {
const { email, clientProof } = req.body; const { email, clientProof } = req.body;
const user = await User.findOne({ const user = await User.findOne({
email email
}).select('+salt +verifier +publicKey +encryptedPrivateKey +iv +tag'); }).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(); const server = new jsrp.server();
server.init( server.init(
{ {
salt: user.salt, salt: user.salt,
verifier: user.verifier, verifier: user.verifier,
b: clientPublicKeys[email].serverBInt b: clientPublicKeys[email].serverBInt
}, },
async () => { async () => {
server.setClientPublicKey(clientPublicKeys[email].clientPublicKey); server.setClientPublicKey(clientPublicKeys[email].clientPublicKey);
// compare server and client shared keys // compare server and client shared keys
if (server.checkClientProof(clientProof)) { if (server.checkClientProof(clientProof)) {
// issue tokens // issue tokens
const tokens = await issueTokens({ userId: user._id.toString() }); const tokens = await issueTokens({ userId: user._id.toString() });
// store (refresh) token in httpOnly cookie // store (refresh) token in httpOnly cookie
res.cookie('jid', tokens.refreshToken, { res.cookie('jid', tokens.refreshToken, {
httpOnly: true, httpOnly: true,
path: '/token', path: '/token',
sameSite: "strict", sameSite: 'strict',
secure: NODE_ENV === 'production' ? true : false secure: NODE_ENV === 'production' ? true : false
}); });
// return (access) token in response // return (access) token in response
return res.status(200).send({ return res.status(200).send({
token: tokens.token, token: tokens.token,
publicKey: user.publicKey, publicKey: user.publicKey,
encryptedPrivateKey: user.encryptedPrivateKey, encryptedPrivateKey: user.encryptedPrivateKey,
iv: user.iv, iv: user.iv,
tag: user.tag tag: user.tag
}); });
} }
return res.status(400).send({ return res.status(400).send({
message: 'Failed to authenticate. Try again?' message: 'Failed to authenticate. Try again?'
}); });
} }
); );
} catch (err) { } catch (err) {
Sentry.setUser(null); Sentry.setUser(null);
Sentry.captureException(err); Sentry.captureException(err);
return res.status(400).send({ return res.status(400).send({
message: 'Failed to authenticate. Try again?' message: 'Failed to authenticate. Try again?'
}); });
} }
}; };
/** /**
@@ -140,29 +139,29 @@ export const login2 = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const logout = async (req: Request, res: Response) => { export const logout = async (req: Request, res: Response) => {
try { try {
await clearTokens({ await clearTokens({
userId: req.user._id.toString() userId: req.user._id.toString()
}); });
// clear httpOnly cookie // clear httpOnly cookie
res.cookie('jid', '', { res.cookie('jid', '', {
httpOnly: true, httpOnly: true,
path: '/token', path: '/token',
sameSite: "strict", sameSite: 'strict',
secure: NODE_ENV === 'production' ? true : false secure: NODE_ENV === 'production' ? true : false
}); });
} catch (err) { } catch (err) {
Sentry.setUser({ email: req.user.email }); Sentry.setUser({ email: req.user.email });
Sentry.captureException(err); Sentry.captureException(err);
return res.status(400).send({ return res.status(400).send({
message: 'Failed to logout' message: 'Failed to logout'
}); });
} }
return res.status(200).send({ return res.status(200).send({
message: 'Successfully logged out.' message: 'Successfully logged out.'
}); });
}; };
/** /**
@@ -172,9 +171,9 @@ export const logout = async (req: Request, res: Response) => {
* @returns * @returns
*/ */
export const checkAuth = async (req: Request, res: Response) => export const checkAuth = async (req: Request, res: Response) =>
res.status(200).send({ res.status(200).send({
message: 'Authenticated' message: 'Authenticated'
}); });
/** /**
* Return new token by redeeming refresh token * Return new token by redeeming refresh token
@@ -183,42 +182,41 @@ export const checkAuth = async (req: Request, res: Response) =>
* @returns * @returns
*/ */
export const getNewToken = async (req: Request, res: Response) => { export const getNewToken = async (req: Request, res: Response) => {
try { try {
const refreshToken = req.cookies.jid; const refreshToken = req.cookies.jid;
if (!refreshToken) { if (!refreshToken) {
throw new Error('Failed to find token in request cookies'); throw new Error('Failed to find token in request cookies');
} }
const decodedToken = <jwt.UserIDJwtPayload>( const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(refreshToken, JWT_REFRESH_SECRET) jwt.verify(refreshToken, JWT_REFRESH_SECRET)
); );
const user = await User.findOne({ const user = await User.findOne({
_id: decodedToken.userId _id: decodedToken.userId
}).select('+publicKey'); }).select('+publicKey');
if (!user) throw new Error('Failed to authenticate unfound user'); if (!user) throw new Error('Failed to authenticate unfound user');
if (!user?.publicKey) if (!user?.publicKey)
throw new Error('Failed to authenticate not fully set up account'); throw new Error('Failed to authenticate not fully set up account');
const token = createToken({ const token = createToken({
payload: { payload: {
userId: decodedToken.userId userId: decodedToken.userId
}, },
expiresIn: JWT_AUTH_LIFETIME, expiresIn: JWT_AUTH_LIFETIME,
secret: JWT_AUTH_SECRET secret: JWT_AUTH_SECRET
}); });
return res.status(200).send({ return res.status(200).send({
token token
}); });
} catch (err) {
} catch (err) { Sentry.setUser(null);
Sentry.setUser(null); Sentry.captureException(err);
Sentry.captureException(err); return res.status(400).send({
return res.status(400).send({ message: 'Invalid request'
message: 'Invalid request' });
}); }
}
}; };
+14 -18
View File
@@ -5,28 +5,24 @@ import { requireAuth, validateRequest } from '../middleware';
import { authController } from '../controllers'; import { authController } from '../controllers';
import { loginLimiter } from '../helpers/rateLimiter'; import { loginLimiter } from '../helpers/rateLimiter';
router.post('/token', validateRequest, authController.getNewToken);
router.post( router.post(
'/token', '/login1',
validateRequest, loginLimiter,
authController.getNewToken body('email').exists().trim().notEmpty(),
body('clientPublicKey').exists().trim().notEmpty(),
validateRequest,
authController.login1
); );
router.post( router.post(
'/login1', '/login2',
loginLimiter, loginLimiter,
body('email').exists().trim().notEmpty(), body('email').exists().trim().notEmpty(),
body('clientPublicKey').exists().trim().notEmpty(), body('clientProof').exists().trim().notEmpty(),
validateRequest, validateRequest,
authController.login1 authController.login2
);
router.post(
'/login2',
loginLimiter,
body('email').exists().trim().notEmpty(),
body('clientProof').exists().trim().notEmpty(),
validateRequest,
authController.login2
); );
router.post('/logout', requireAuth, authController.logout); router.post('/logout', requireAuth, authController.logout);
+14 -14
View File
@@ -1,9 +1,9 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from 'react';
import Image from "next/image"; import Image from 'next/image';
import { useRouter } from "next/router"; import { useRouter } from 'next/router';
import { publicPaths } from "~/const"; import { publicPaths } from '~/const';
import checkAuth from "~/pages/api/auth/CheckAuth"; import checkAuth from '~/pages/api/auth/CheckAuth';
// #TODO: finish spinner only when the data loads fully // #TODO: finish spinner only when the data loads fully
// #TODO: Redirect somewhere if the page does not exist // #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. // #TODO: add the loading page when not yet authorized.
const hideContent = () => setAuthorized(false); const hideContent = () => setAuthorized(false);
// const onError = () => setAuthorized(true) // const onError = () => setAuthorized(true)
router.events.on("routeChangeStart", hideContent); router.events.on('routeChangeStart', hideContent);
// router.events.on("routeChangeError", onError); // router.events.on("routeChangeError", onError);
// on route change complete - run auth check // on route change complete - run auth check
router.events.on("routeChangeComplete", authCheck); router.events.on('routeChangeComplete', authCheck);
// unsubscribe from events in useEffect return function // unsubscribe from events in useEffect return function
return () => { return () => {
router.events.off("routeChangeStart", hideContent); router.events.off('routeChangeStart', hideContent);
router.events.off("routeChangeComplete", authCheck); router.events.off('routeChangeComplete', authCheck);
// router.events.off("routeChangeError", onError); // router.events.off("routeChangeError", onError);
}; };
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -43,7 +43,7 @@ export default function RouteGuard({ children }) {
*/ */
async function authCheck(url) { async function authCheck(url) {
// Make sure that we don't redirect when the user is on the following pages. // 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 // Check if the user is authenticated
const response = await checkAuth(); const response = await checkAuth();
@@ -51,16 +51,16 @@ export default function RouteGuard({ children }) {
if (!publicPaths.includes(path)) { if (!publicPaths.includes(path)) {
try { try {
if (response.status !== 200) { if (response.status !== 200) {
router.push("/login"); router.push('/login');
console.log("Unauthorized to access."); console.log('Unauthorized to access.');
setAuthorized(false); setAuthorized(false);
} else { } else {
setAuthorized(true); setAuthorized(true);
console.log("Authorized to access."); console.log('Authorized to access.');
} }
} catch (error) { } catch (error) {
console.log( console.log(
"Error (probably the authCheck route is stuck again...):", 'Error (probably the authCheck route is stuck again...):',
error error
); );
} }
+18
View File
@@ -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;
};
+13 -13
View File
@@ -1,9 +1,9 @@
import React, { useState } from "react"; import React, { useState } from 'react';
import { useRouter } from "next/router"; import { useRouter } from 'next/router';
import { faCircle, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons"; import { faCircle, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import guidGenerator from "../utilities/randomId"; import guidGenerator from '../utilities/randomId';
interface InputFieldProps { interface InputFieldProps {
static?: boolean; static?: boolean;
@@ -23,7 +23,7 @@ interface InputFieldProps {
const InputField = ( const InputField = (
props: InputFieldProps & props: InputFieldProps &
Pick<JSX.IntrinsicElements["input"], "autoComplete" | "id"> Pick<JSX.IntrinsicElements['input'], 'autoComplete' | 'id'>
) => { ) => {
const [passwordVisible, setPasswordVisible] = useState(false); const [passwordVisible, setPasswordVisible] = useState(false);
const router = useRouter(); const router = useRouter();
@@ -75,28 +75,28 @@ const InputField = (
</div> </div>
<div <div
className={`group relative flex flex-col justify-center w-full max-w-2xl border ${ className={`group relative flex flex-col justify-center w-full max-w-2xl border ${
props.error ? "border-red" : "border-mineshaft-500" props.error ? 'border-red' : 'border-mineshaft-500'
} rounded-md`} } rounded-md`}
> >
<input <input
onChange={(e) => props.onChangeHandler(e.target.value)} onChange={(e) => props.onChangeHandler(e.target.value)}
type={passwordVisible === false ? props.type : "text"} type={passwordVisible === false ? props.type : 'text'}
placeholder={props.placeholder} placeholder={props.placeholder}
value={props.value} value={props.value}
required={props.isRequired} required={props.isRequired}
className={`${ className={`${
props.blurred 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`} } 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} name={props.name}
spellCheck="false" spellCheck="false"
autoComplete={props.autoComplete} autoComplete={props.autoComplete}
id={props.id} id={props.id}
/> />
{props.label?.includes("Password") && ( {props.label?.includes('Password') && (
<button <button
onClick={() => { onClick={() => {
setPasswordVisible(!passwordVisible); setPasswordVisible(!passwordVisible);
@@ -114,7 +114,7 @@ const InputField = (
<div className="peer group-hover:hidden peer-hover:hidden peer-focus:hidden peer-active:invisible absolute h-10 w-fit max-w-xl rounded-md flex items-center text-gray-400/50 text-clip overflow-hidden"> <div className="peer group-hover:hidden peer-hover:hidden peer-focus:hidden peer-active:invisible absolute h-10 w-fit max-w-xl rounded-md flex items-center text-gray-400/50 text-clip overflow-hidden">
<p className="ml-2"></p> <p className="ml-2"></p>
{props.value {props.value
.split("") .split('')
.slice(0, 54) .slice(0, 54)
.map(() => ( .map(() => (
<FontAwesomeIcon <FontAwesomeIcon
@@ -1,10 +1,10 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from 'react';
import { useRouter } from "next/router"; import { useRouter } from 'next/router';
import { faX } from "@fortawesome/free-solid-svg-icons"; import { faX } from '@fortawesome/free-solid-svg-icons';
import { reverseEnvMapping } from "../../../public/data/frequentConstants"; import { reverseEnvMapping } from '../../../public/data/frequentConstants';
import guidGenerator from "../../utilities/randomId"; import guidGenerator from '../../utilities/randomId';
import Button from "../buttons/Button"; import Button from '../buttons/Button';
/** /**
* This is the component that we utilize for the user table - in future, can reuse it for some other purposes too. * This is the component that we utilize for the user table - in future, can reuse it for some other purposes too.
+38 -38
View File
@@ -1,25 +1,25 @@
import React, { useEffect, useMemo, useState } from "react"; import React, { useEffect, useMemo, useState } from 'react';
import { useRouter } from "next/router"; import { useRouter } from 'next/router';
import { faX } from "@fortawesome/free-solid-svg-icons"; import { faX } from '@fortawesome/free-solid-svg-icons';
import deleteUserFromOrganization from "~/pages/api/organization/deleteUserFromOrganization"; import deleteUserFromOrganization from '~/pages/api/organization/deleteUserFromOrganization';
import changeUserRoleInWorkspace from "~/pages/api/workspace/changeUserRoleInWorkspace"; import changeUserRoleInWorkspace from '~/pages/api/workspace/changeUserRoleInWorkspace';
import deleteUserFromWorkspace from "~/pages/api/workspace/deleteUserFromWorkspace"; import deleteUserFromWorkspace from '~/pages/api/workspace/deleteUserFromWorkspace';
import getLatestFileKey from "~/pages/api/workspace/getLatestFileKey"; import getLatestFileKey from '~/pages/api/workspace/getLatestFileKey';
import uploadKeys from "~/pages/api/workspace/uploadKeys"; import uploadKeys from '~/pages/api/workspace/uploadKeys';
import guidGenerator from "../../utilities/randomId"; import guidGenerator from '../../utilities/randomId';
import Button from "../buttons/Button"; import Button from '../buttons/Button';
import Listbox from "../Listbox"; import Listbox from '../Listbox';
const { const {
decryptAssymmetric, decryptAssymmetric,
encryptAssymmetric, encryptAssymmetric
} = require("../../utilities/cryptography/crypto"); } = require('../../utilities/cryptography/crypto');
const nacl = require("tweetnacl"); const nacl = require('tweetnacl');
nacl.util = require("tweetnacl-util"); nacl.util = require('tweetnacl-util');
const roles = ["admin", "user"]; const roles = ['admin', 'user'];
/** /**
* This is the component that we utilize for the user table - in future, can reuse it for some other purposes too. * This is the component that we utilize for the user table - in future, can reuse it for some other purposes too.
@@ -36,13 +36,13 @@ const UserTable = ({
isOrg, isOrg,
onClick, onClick,
deleteUser, deleteUser,
setUserIdToBeDeleted, setUserIdToBeDeleted
}) => { }) => {
const [roleSelected, setRoleSelected] = useState( const [roleSelected, setRoleSelected] = useState(
Array(userData?.length).fill(userData.map((user) => user.role)) Array(userData?.length).fill(userData.map((user) => user.role))
); );
const router = useRouter(); const router = useRouter();
const [myRole, setMyRole] = useState("member"); const [myRole, setMyRole] = useState('member');
// Delete the row in the table (e.g. a user) // Delete the row in the table (e.g. a user)
// #TODO: Add a pop-up that warns you that the user is going to be deleted. // #TODO: Add a pop-up that warns you that the user is going to be deleted.
@@ -57,7 +57,7 @@ const UserTable = ({
changeData(userData.filter((v, i) => i !== index)); changeData(userData.filter((v, i) => i !== index));
setRoleSelected([ setRoleSelected([
...roleSelected.slice(0, index), ...roleSelected.slice(0, index),
...roleSelected.slice(index + 1, userData?.length), ...roleSelected.slice(index + 1, userData?.length)
]); ]);
}; };
@@ -76,10 +76,10 @@ const UserTable = ({
status: userData[index].status, status: userData[index].status,
userId: userData[index].userId, userId: userData[index].userId,
membershipId: userData[index].membershipId, membershipId: userData[index].membershipId,
publicKey: userData[index].publicKey, publicKey: userData[index].publicKey
}, }
], ],
...userData.slice(index + 1, userData?.length), ...userData.slice(index + 1, userData?.length)
]); ]);
}; };
@@ -88,22 +88,22 @@ const UserTable = ({
}, [userData, myUser]); }, [userData, myUser]);
const grantAccess = async (id, publicKey) => { const grantAccess = async (id, publicKey) => {
let result = await getLatestFileKey({workspaceId: router.query.id}); let result = await getLatestFileKey({ workspaceId: router.query.id });
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY');
// assymmetrically decrypt symmetric key with local private key // assymmetrically decrypt symmetric key with local private key
const key = decryptAssymmetric({ const key = decryptAssymmetric({
ciphertext: result.latestKey.encryptedKey, ciphertext: result.latestKey.encryptedKey,
nonce: result.latestKey.nonce, nonce: result.latestKey.nonce,
publicKey: result.latestKey.sender.publicKey, publicKey: result.latestKey.sender.publicKey,
privateKey: PRIVATE_KEY, privateKey: PRIVATE_KEY
}); });
const { ciphertext, nonce } = encryptAssymmetric({ const { ciphertext, nonce } = encryptAssymmetric({
plaintext: key, plaintext: key,
publicKey: publicKey, publicKey: publicKey,
privateKey: PRIVATE_KEY, privateKey: PRIVATE_KEY
}); });
uploadKeys(router.query.id, id, ciphertext, nonce); uploadKeys(router.query.id, id, ciphertext, nonce);
@@ -158,24 +158,24 @@ const UserTable = ({
</td> </td>
<td className="flex flex-row justify-end pr-8 py-2 border-t border-0.5 border-mineshaft-700"> <td className="flex flex-row justify-end pr-8 py-2 border-t border-0.5 border-mineshaft-700">
<div className="flex justify-end mr-6 w-3/4 mx-2 w-full h-full flex flex-row items-center"> <div className="flex justify-end mr-6 w-3/4 mx-2 w-full h-full flex flex-row items-center">
{row.status == "granted" && {row.status == 'granted' &&
((myRole == "admin" && row.role != "owner") || ((myRole == 'admin' && row.role != 'owner') ||
myRole == "owner") && myRole == 'owner') &&
myUser !== row.email ? ( myUser !== row.email ? (
<Listbox <Listbox
selected={row.role} selected={row.role}
onChange={(e) => handleRoleUpdate(index, e)} onChange={(e) => handleRoleUpdate(index, e)}
data={ data={
myRole == "owner" myRole == 'owner'
? ["owner", "admin", "member"] ? ['owner', 'admin', 'member']
: ["admin", "member"] : ['admin', 'member']
} }
text="Role: " text="Role: "
membershipId={row.membershipId} membershipId={row.membershipId}
/> />
) : ( ) : (
row.status != "invited" && row.status != 'invited' &&
row.status != "verified" && ( row.status != 'verified' && (
<Listbox <Listbox
selected={row.role} selected={row.role}
text="Role: " text="Role: "
@@ -183,8 +183,8 @@ const UserTable = ({
/> />
) )
)} )}
{(row.status == "invited" || {(row.status == 'invited' ||
row.status == "verified") && ( row.status == 'verified') && (
<div className="w-full pl-9"> <div className="w-full pl-9">
<Button <Button
onButtonPressed={() => onButtonPressed={() =>
@@ -199,7 +199,7 @@ const UserTable = ({
/> />
</div> </div>
)} )}
{row.status == "completed" && myUser !== row.email && ( {row.status == 'completed' && myUser !== row.email && (
<div className="border border-mineshaft-700 rounded-md bg-white/5 hover:bg-primary text-white hover:text-black duration-200"> <div className="border border-mineshaft-700 rounded-md bg-white/5 hover:bg-primary text-white hover:text-black duration-200">
<Button <Button
onButtonPressed={() => onButtonPressed={() =>
@@ -214,7 +214,7 @@ const UserTable = ({
</div> </div>
{myUser !== row.email && {myUser !== row.email &&
// row.role != "admin" && // row.role != "admin" &&
myRole != "member" ? ( myRole != 'member' ? (
<div className="opacity-50 hover:opacity-100 flex items-center"> <div className="opacity-50 hover:opacity-100 flex items-center">
<Button <Button
onButtonPressed={(e) => onButtonPressed={(e) =>
@@ -1,14 +1,29 @@
import React from "react"; import React from 'react';
import StripeRedirect from "~/pages/api/organization/StripeRedirect"; import StripeRedirect from '~/pages/api/organization/StripeRedirect';
export default function Plan({ plan }) { import { tempLocalStorage } from '../utilities/checks/tempLocalStorage';
interface Props {
plan: {
name: string;
price: string;
priceExplanation: string;
text: string;
subtext: string;
buttonTextMain: string;
buttonTextSecondary: string;
current: boolean;
};
}
export default function Plan({ plan }: Props) {
return ( return (
<div <div
className={`relative flex flex-col justify-between border border-2 min-w-fit w-96 rounded-lg h-68 mr-4 bg-mineshaft-800 ${ className={`relative flex flex-col justify-between border-2 min-w-fit w-96 rounded-lg h-68 mr-4 bg-mineshaft-800 ${
(plan.name != "Starter") & (plan.current == true) plan.name != 'Starter' && plan.current == true
? "border-primary" ? 'border-primary'
: "border-chicago-700" : 'border-chicago-700'
} }
`} `}
> >
@@ -36,7 +51,7 @@ export default function Plan({ plan }) {
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
{plan.current == false ? ( {plan.current == false ? (
<> <>
{plan.buttonTextMain == "Schedule a Demo" ? ( {plan.buttonTextMain == 'Schedule a Demo' ? (
<a href="/scheduledemo" target='_blank rel="noopener"'> <a href="/scheduledemo" target='_blank rel="noopener"'>
<div className="relative z-10 mx-5 mt-3 mb-4 py-2 px-4 border border-1 border-gray-600 hover:text-black hover:border-primary text-gray-400 font-semibold hover:bg-primary bg-bunker duration-200 cursor-pointer rounded-md flex w-max"> <div className="relative z-10 mx-5 mt-3 mb-4 py-2 px-4 border border-1 border-gray-600 hover:text-black hover:border-primary text-gray-400 font-semibold hover:bg-primary bg-bunker duration-200 cursor-pointer rounded-md flex w-max">
{plan.buttonTextMain} {plan.buttonTextMain}
@@ -45,15 +60,15 @@ export default function Plan({ plan }) {
) : ( ) : (
<div <div
className={`relative z-10 mx-5 mt-3 mb-4 py-2 px-4 border border-1 border-gray-600 text-gray-400 font-semibold ${ className={`relative z-10 mx-5 mt-3 mb-4 py-2 px-4 border border-1 border-gray-600 text-gray-400 font-semibold ${
plan.buttonTextMain == "Downgrade" plan.buttonTextMain == 'Downgrade'
? "hover:bg-red hover:text-white hover:border-red" ? 'hover:bg-red hover:text-white hover:border-red'
: "hover:bg-primary hover:text-black hover:border-primary" : 'hover:bg-primary hover:text-black hover:border-primary'
} bg-bunker duration-200 cursor-pointer rounded-md flex w-max`} } bg-bunker duration-200 cursor-pointer rounded-md flex w-max`}
> >
<button <button
onClick={() => onClick={() =>
StripeRedirect({ StripeRedirect({
orgId: localStorage.getItem("orgData.id"), orgId: tempLocalStorage('orgData.id')
}) })
} }
> >
@@ -61,7 +76,10 @@ export default function Plan({ plan }) {
</button> </button>
</div> </div>
)} )}
<a href="https://infisical.com/pricing" target='_blank rel="noopener"'> <a
href="https://infisical.com/pricing"
target='_blank rel="noopener"'
>
<div className="relative z-10 text-gray-400 font-semibold hover:text-primary duration-200 cursor-pointer mb-0.5"> <div className="relative z-10 text-gray-400 font-semibold hover:text-primary duration-200 cursor-pointer mb-0.5">
{plan.buttonTextSecondary} {plan.buttonTextSecondary}
</div> </div>
@@ -70,9 +88,9 @@ export default function Plan({ plan }) {
) : ( ) : (
<div <div
className={`h-8 w-full rounded-b-md flex justify-center items-center z-10 ${ className={`h-8 w-full rounded-b-md flex justify-center items-center z-10 ${
(plan.name != "Starter") & (plan.current == true) plan.name != 'Starter' && plan.current == true
? "bg-primary" ? 'bg-primary'
: "bg-chicago-700" : 'bg-chicago-700'
}`} }`}
> >
<p className="text-xs text-black font-semibold">CURRENT PLAN</p> <p className="text-xs text-black font-semibold">CURRENT PLAN</p>
@@ -1,8 +1,8 @@
import React, { SyntheticEvent, useRef } from "react"; import React, { SyntheticEvent, useRef } from 'react';
import { faCircle } from "@fortawesome/free-solid-svg-icons"; import { faCircle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import guidGenerator from "../utilities/randomId"; import guidGenerator from '../utilities/randomId';
const REGEX = /([$]{.*?})/g; const REGEX = /([$]{.*?})/g;
@@ -10,7 +10,7 @@ interface DashboardInputFieldProps {
index: number; index: number;
onChangeHandler: (value: string, index: number) => void; onChangeHandler: (value: string, index: number) => void;
value: string; value: string;
type: "varName" | "value"; type: 'varName' | 'value';
blurred: boolean; blurred: boolean;
duplicates: string[]; duplicates: string[];
} }
@@ -33,7 +33,7 @@ const DashboardInputField = ({
type, type,
value, value,
blurred, blurred,
duplicates, duplicates
}: DashboardInputFieldProps) => { }: DashboardInputFieldProps) => {
const ref = useRef<HTMLDivElement | null>(null); const ref = useRef<HTMLDivElement | null>(null);
const syncScroll = (e: SyntheticEvent<HTMLDivElement>) => { const syncScroll = (e: SyntheticEvent<HTMLDivElement>) => {
@@ -43,8 +43,8 @@ const DashboardInputField = ({
ref.current.scrollLeft = e.currentTarget.scrollLeft; ref.current.scrollLeft = e.currentTarget.scrollLeft;
}; };
if (type === "varName") { if (type === 'varName') {
const startsWithNumber = !isNaN(Number(value.charAt(0))) && value != ""; const startsWithNumber = !isNaN(Number(value.charAt(0))) && value != '';
const hasDuplicates = duplicates?.includes(value); const hasDuplicates = duplicates?.includes(value);
const error = startsWithNumber || hasDuplicates; const error = startsWithNumber || hasDuplicates;
@@ -52,7 +52,7 @@ const DashboardInputField = ({
<div className="flex-col w-full"> <div className="flex-col w-full">
<div <div
className={`group relative flex flex-col justify-center w-full max-w-2xl border ${ className={`group relative flex flex-col justify-center w-full max-w-2xl border ${
error ? "border-red" : "border-mineshaft-500" error ? 'border-red' : 'border-mineshaft-500'
} rounded-md`} } rounded-md`}
> >
<input <input
@@ -62,7 +62,7 @@ const DashboardInputField = ({
type={type} type={type}
value={value} value={value}
className={`z-10 peer font-mono ph-no-capture bg-bunker-800 rounded-md caret-white text-gray-400 text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 ${ className={`z-10 peer font-mono ph-no-capture bg-bunker-800 rounded-md caret-white text-gray-400 text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 ${
error ? "focus:ring-red/50" : "focus:ring-primary/50" error ? 'focus:ring-red/50' : 'focus:ring-primary/50'
} duration-200`} } duration-200`}
spellCheck="false" spellCheck="false"
/> />
@@ -79,7 +79,7 @@ const DashboardInputField = ({
)} )}
</div> </div>
); );
} else if (type === "value") { } else if (type === 'value') {
return ( return (
<div className="flex-col w-full"> <div className="flex-col w-full">
<div <div
@@ -91,8 +91,8 @@ const DashboardInputField = ({
onScroll={syncScroll} onScroll={syncScroll}
className={`${ className={`${
blurred blurred
? "text-transparent group-hover:text-transparent focus:text-transparent active:text-transparent" ? 'text-transparent group-hover:text-transparent focus:text-transparent active:text-transparent'
: "" : ''
} z-10 peer font-mono ph-no-capture bg-transparent rounded-md caret-white text-transparent text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 focus:ring-primary/50 duration-200 no-scrollbar no-scrollbar::-webkit-scrollbar`} } z-10 peer font-mono ph-no-capture bg-transparent rounded-md caret-white text-transparent text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 focus:ring-primary/50 duration-200 no-scrollbar no-scrollbar::-webkit-scrollbar`}
spellCheck="false" spellCheck="false"
/> />
@@ -100,8 +100,8 @@ const DashboardInputField = ({
ref={ref} ref={ref}
className={`${ className={`${
blurred 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`} } 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) => { {value.split(REGEX).map((word, id) => {
@@ -112,7 +112,7 @@ const DashboardInputField = ({
<span className="ph-no-capture text-yellow-200/80"> <span className="ph-no-capture text-yellow-200/80">
{word.slice(2, word.length - 1)} {word.slice(2, word.length - 1)}
</span> </span>
{word.slice(word.length - 1, word.length) == "}" ? ( {word.slice(word.length - 1, word.length) == '}' ? (
<span className="ph-no-capture text-yellow"> <span className="ph-no-capture text-yellow">
{word.slice(word.length - 1, word.length)} {word.slice(word.length - 1, word.length)}
</span> </span>
@@ -135,7 +135,7 @@ const DashboardInputField = ({
{blurred && ( {blurred && (
<div className="absolute flex flex-row items-center z-20 peer pr-2 bg-bunker-800 group-hover:hidden peer-hover:hidden peer-focus:hidden peer-active:invisible h-9 w-full max-w-2xl rounded-md text-gray-400/50 text-clip"> <div className="absolute flex flex-row items-center z-20 peer pr-2 bg-bunker-800 group-hover:hidden peer-hover:hidden peer-focus:hidden peer-active:invisible h-9 w-full max-w-2xl rounded-md text-gray-400/50 text-clip">
<div className="px-2 flex flex-row items-center overflow-x-scroll no-scrollbar no-scrollbar::-webkit-scrollbar"> <div className="px-2 flex flex-row items-center overflow-x-scroll no-scrollbar no-scrollbar::-webkit-scrollbar">
{value.split("").map(() => ( {value.split('').map(() => (
<FontAwesomeIcon <FontAwesomeIcon
key={guidGenerator()} key={guidGenerator()}
className="text-xxs mx-0.5" className="text-xxs mx-0.5"
+17 -17
View File
@@ -1,12 +1,12 @@
import { type ChangeEvent, type DragEvent, useState } from "react"; import { type ChangeEvent, type DragEvent, useState } from 'react';
import Image from "next/image"; import Image from 'next/image';
import { faUpload } from "@fortawesome/free-solid-svg-icons"; import { faUpload } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Button from "../basic/buttons/Button"; import Button from '../basic/buttons/Button';
import Error from "../basic/Error"; import Error from '../basic/Error';
import parse from "../utilities/file"; import parse from '../utilities/file';
import guidGenerator from "../utilities/randomId"; import guidGenerator from '../utilities/randomId';
interface DropZoneProps { interface DropZoneProps {
// TODO: change Data type from any // TODO: change Data type from any
@@ -26,7 +26,7 @@ const DropZone = ({
errorDragAndDrop, errorDragAndDrop,
setButtonReady, setButtonReady,
keysExist, keysExist,
numCurrentRows, numCurrentRows
}: DropZoneProps) => { }: DropZoneProps) => {
const handleDragEnter = (e: DragEvent) => { const handleDragEnter = (e: DragEvent) => {
e.preventDefault(); e.preventDefault();
@@ -43,7 +43,7 @@ const DropZone = ({
e.stopPropagation(); e.stopPropagation();
// set dropEffect to copy i.e copy of the source item // set dropEffect to copy i.e copy of the source item
e.dataTransfer.dropEffect = "copy"; e.dataTransfer.dropEffect = 'copy';
}; };
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -54,7 +54,7 @@ const DropZone = ({
setTimeout(() => setLoading(false), 5000); setTimeout(() => setLoading(false), 5000);
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
e.dataTransfer.dropEffect = "copy"; e.dataTransfer.dropEffect = 'copy';
const file = e.dataTransfer.files[0]; const file = e.dataTransfer.files[0];
const reader = new FileReader(); const reader = new FileReader();
@@ -68,7 +68,7 @@ const DropZone = ({
numCurrentRows + index, numCurrentRows + index,
key, key,
keyPairs[key as keyof typeof keyPairs], keyPairs[key as keyof typeof keyPairs],
"shared", 'shared'
]); ]);
setData(newData); setData(newData);
setButtonReady(true); setButtonReady(true);
@@ -94,15 +94,15 @@ const DropZone = ({
reader.onload = (event) => { reader.onload = (event) => {
if (event.target === null || event.target.result === null) return; if (event.target === null || event.target.result === null) return;
const { result } = event.target; const { result } = event.target;
if (typeof result === "string") { if (typeof result === 'string') {
const newData = result const newData = result
.split("\n") .split('\n')
.map((line: string, index: number) => [ .map((line: string, index: number) => [
guidGenerator(), guidGenerator(),
numCurrentRows + index, numCurrentRows + index,
line.split("=")[0], line.split('=')[0],
line.split("=").slice(1, line.split("=").length).join("="), line.split('=').slice(1, line.split('=').length).join('='),
"shared", 'shared'
]); ]);
setData(newData); setData(newData);
setButtonReady(true); setButtonReady(true);
@@ -1,10 +1,10 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable react/jsx-key */ /* eslint-disable react/jsx-key */
import React, { Fragment, useEffect, useState } from "react"; import React, { Fragment, useEffect, useState } from 'react';
import Image from "next/image"; import Image from 'next/image';
import { useRouter } from "next/router"; import { useRouter } from 'next/router';
import { faGithub, faSlack } from "@fortawesome/free-brands-svg-icons"; import { faGithub, faSlack } from '@fortawesome/free-brands-svg-icons';
import { faCircleQuestion } from "@fortawesome/free-regular-svg-icons"; import { faCircleQuestion } from '@fortawesome/free-regular-svg-icons';
import { import {
faAngleDown, faAngleDown,
faBook, faBook,
@@ -12,39 +12,39 @@ import {
faEnvelope, faEnvelope,
faGear, faGear,
faPlus, faPlus,
faRightFromBracket, faRightFromBracket
} from "@fortawesome/free-solid-svg-icons"; } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Menu, Transition } from "@headlessui/react"; import { Menu, Transition } from '@headlessui/react';
import logout from "~/pages/api/auth/Logout"; import logout from '~/pages/api/auth/Logout';
import getOrganization from "~/pages/api/organization/GetOrg"; import getOrganization from '~/pages/api/organization/GetOrg';
import getOrganizations from "~/pages/api/organization/getOrgs"; import getOrganizations from '~/pages/api/organization/getOrgs';
import getUser from "~/pages/api/user/getUser"; import getUser from '~/pages/api/user/getUser';
import guidGenerator from "../utilities/randomId"; import guidGenerator from '../utilities/randomId';
const supportOptions = [ const supportOptions = [
[ [
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faSlack} />, <FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faSlack} />,
"Join Slack Forum", 'Join Slack Forum',
"https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g", 'https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g'
], ],
[ [
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faBook} />, <FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faBook} />,
"Read Docs", 'Read Docs',
"https://infisical.com/docs/getting-started/introduction", 'https://infisical.com/docs/getting-started/introduction'
], ],
[ [
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faGithub} />, <FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faGithub} />,
"Open a GitHub Issue", 'Open a GitHub Issue',
"https://github.com/Infisical/infisical-cli/issues", 'https://github.com/Infisical/infisical-cli/issues'
], ],
[ [
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faEnvelope} />, <FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faEnvelope} />,
"Send us an Email", 'Send us an Email',
"mailto:[email protected]", 'mailto:[email protected]'
], ]
]; ];
export interface ICurrentOrg { export interface ICurrentOrg {
@@ -75,16 +75,16 @@ export default function Navbar() {
const orgsData = await getOrganizations(); const orgsData = await getOrganizations();
setOrgs(orgsData); setOrgs(orgsData);
const currentOrg = await getOrganization({ const currentOrg = await getOrganization({
orgId: String(localStorage.getItem("orgData.id")), orgId: String(localStorage.getItem('orgData.id'))
}); });
setCurrentOrg(currentOrg); setCurrentOrg(currentOrg);
})(); })();
}, []); }, []);
const closeApp = async () => { const closeApp = async () => {
console.log("Logging out..."); console.log('Logging out...');
await logout(); await logout();
router.push("/login"); router.push('/login');
}; };
return ( return (
@@ -163,7 +163,7 @@ export default function Navbar() {
</div> </div>
<div <div
onClick={() => onClick={() =>
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" 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() {
<div className="flex items-center justify-between w-full"> <div className="flex items-center justify-between w-full">
<div> <div>
<p className="text-gray-300 px-2 pt-1 text-sm"> <p className="text-gray-300 px-2 pt-1 text-sm">
{" "} {' '}
{user?.firstName} {user?.lastName} {user?.firstName} {user?.lastName}
</p> </p>
<p className="text-gray-400 px-2 pb-1 text-xs"> <p className="text-gray-400 px-2 pb-1 text-xs">
{" "} {' '}
{user?.email} {user?.email}
</p> </p>
</div> </div>
@@ -194,7 +194,7 @@ export default function Navbar() {
</div> </div>
<div <div
onClick={() => onClick={() =>
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" 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() {
> >
<div <div
onClick={() => onClick={() =>
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" 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() {
<div <div
onClick={() => onClick={() =>
router.push( 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" 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() {
<div className="flex flex-col items-start px-1 mt-3 mb-2"> <div className="flex flex-col items-start px-1 mt-3 mb-2">
{orgs {orgs
.filter( .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 }) => (
<div <div
key={guidGenerator()} key={guidGenerator()}
onClick={() => { onClick={() => {
localStorage.setItem("orgData.id", org._id); localStorage.setItem('orgData.id', org._id);
router.reload(); router.reload();
}} }}
className="flex flex-row justify-start items-center hover:bg-white/5 w-full p-1.5 cursor-pointer rounded-md" 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} onClick={closeApp}
className={`${ className={`${
active active
? "bg-red font-semibold text-white" ? 'bg-red font-semibold text-white'
: "text-gray-400" : 'text-gray-400'
} group flex w-full items-center rounded-md px-2 py-2 text-sm`} } group flex w-full items-center rounded-md px-2 py-2 text-sm`}
> >
<div className="relative flex justify-start items-center cursor-pointer select-none"> <div className="relative flex justify-start items-center cursor-pointer select-none">
@@ -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);
}
}
}
@@ -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);
}
}
}
+36 -36
View File
@@ -1,17 +1,17 @@
import Aes256Gcm from "~/components/utilities/cryptography/aes-256-gcm"; import Aes256Gcm from '~/components/utilities/cryptography/aes-256-gcm';
import login1 from "~/pages/api/auth/Login1"; import login1 from '~/pages/api/auth/Login1';
import login2 from "~/pages/api/auth/Login2"; import login2 from '~/pages/api/auth/Login2';
import getOrganizations from "~/pages/api/organization/getOrgs"; import getOrganizations from '~/pages/api/organization/getOrgs';
import getOrganizationUserProjects from "~/pages/api/organization/GetOrgUserProjects"; import getOrganizationUserProjects from '~/pages/api/organization/GetOrgUserProjects';
import pushKeys from "./secrets/pushKeys"; import pushKeys from './secrets/pushKeys';
import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage"; import Telemetry from './telemetry/Telemetry';
import SecurityClient from "./SecurityClient"; import { saveTokenToLocalStorage } from './saveTokenToLocalStorage';
import Telemetry from "./telemetry/Telemetry"; import SecurityClient from './SecurityClient';
const nacl = require("tweetnacl"); const nacl = require('tweetnacl');
nacl.util = require("tweetnacl-util"); nacl.util = require('tweetnacl-util');
const jsrp = require("jsrp"); const jsrp = require('jsrp');
const client = new jsrp.client(); const client = new jsrp.client();
/** /**
@@ -37,7 +37,7 @@ const attemptLogin = async (
client.init( client.init(
{ {
username: email, username: email,
password: password, password: password
}, },
async () => { async () => {
const clientPublicKey = client.getPublicKey(); const clientPublicKey = client.getPublicKey();
@@ -62,7 +62,7 @@ const attemptLogin = async (
.slice(0, 32) .slice(0, 32)
.padStart( .padStart(
32 + (password.slice(0, 32).length - new Blob([password]).size), 32 + (password.slice(0, 32).length - new Blob([password]).size),
"0" '0'
) )
); );
@@ -72,36 +72,36 @@ const attemptLogin = async (
encryptedPrivateKey, encryptedPrivateKey,
iv, iv,
tag, tag,
privateKey, privateKey
}); });
const userOrgs = await getOrganizations(); const userOrgs = await getOrganizations();
const userOrgsData = userOrgs.map((org) => org._id); const userOrgsData = userOrgs.map((org) => org._id);
let orgToLogin; let orgToLogin;
if (userOrgsData.includes(localStorage.getItem("orgData.id"))) { if (userOrgsData.includes(localStorage.getItem('orgData.id'))) {
orgToLogin = localStorage.getItem("orgData.id"); orgToLogin = localStorage.getItem('orgData.id');
} else { } else {
orgToLogin = userOrgsData[0]; orgToLogin = userOrgsData[0];
localStorage.setItem("orgData.id", orgToLogin); localStorage.setItem('orgData.id', orgToLogin);
} }
let orgUserProjects = await getOrganizationUserProjects({ let orgUserProjects = await getOrganizationUserProjects({
orgId: orgToLogin, orgId: orgToLogin
}); });
orgUserProjects = orgUserProjects?.map((project) => project._id); orgUserProjects = orgUserProjects?.map((project) => project._id);
let projectToLogin; let projectToLogin;
if ( if (
orgUserProjects.includes(localStorage.getItem("projectData.id")) orgUserProjects.includes(localStorage.getItem('projectData.id'))
) { ) {
projectToLogin = localStorage.getItem("projectData.id"); projectToLogin = localStorage.getItem('projectData.id');
} else { } else {
try { try {
projectToLogin = orgUserProjects[0]; projectToLogin = orgUserProjects[0];
localStorage.setItem("projectData.id", projectToLogin); localStorage.setItem('projectData.id', projectToLogin);
} catch (error) { } 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({ await pushKeys({
obj: { obj: {
DATABASE_URL: [ DATABASE_URL: [
"mongodb+srv://${DB_USERNAME}:${DB_PASSWORD}@mongodb.net", 'mongodb+srv://${DB_USERNAME}:${DB_PASSWORD}@mongodb.net',
"personal", 'personal'
], ],
DB_USERNAME: ["user1234", "personal"], DB_USERNAME: ['user1234', 'personal'],
DB_PASSWORD: ["ah8jak3hk8dhiu4dw7whxwe1l", "personal"], DB_PASSWORD: ['ah8jak3hk8dhiu4dw7whxwe1l', 'personal'],
TWILIO_AUTH_TOKEN: [ TWILIO_AUTH_TOKEN: [
"hgSIwDAKvz8PJfkj6xkzYqzGmAP3HLuG", 'hgSIwDAKvz8PJfkj6xkzYqzGmAP3HLuG',
"shared", 'shared'
], ],
WEBSITE_URL: ["http://localhost:3000", "shared"], WEBSITE_URL: ['http://localhost:3000', 'shared'],
STRIPE_SECRET_KEY: ["sk_test_7348oyho4hfq398HIUOH78", "shared"], STRIPE_SECRET_KEY: ['sk_test_7348oyho4hfq398HIUOH78', 'shared']
}, },
workspaceId: projectToLogin, workspaceId: projectToLogin,
env: "Development", env: 'Development'
}); });
} }
if (email) { if (email) {
telemetry.identify(email); telemetry.identify(email);
telemetry.capture("User Logged In"); telemetry.capture('User Logged In');
} }
if (isLogin) { if (isLogin) {
router.push("/dashboard/"); router.push('/dashboard/');
} }
} catch (error) { } catch (error) {
setErrorLogin(true); setErrorLogin(true);
console.log("Login response not available"); console.log('Login response not available');
} }
} }
); );
} catch (error) { } catch (error) {
console.log("Something went wrong during authentication"); console.log('Something went wrong during authentication');
} }
return true; return true;
}; };
@@ -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;
@@ -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;
@@ -6,21 +6,21 @@ const LINE =
* @param {Buffer} src - source buffer * @param {Buffer} src - source buffer
* @returns {String} text - text of buffer * @returns {String} text - text of buffer
*/ */
function parse(src) { function parse(src: Buffer) {
const obj = {}; const obj: Record<string, string> = {};
// Convert buffer to string // Convert buffer to string
let lines = src.toString(); let lines = src.toString();
// Convert line breaks to same format // Convert line breaks to same format
lines = lines.replace(/\r\n?/gm, "\n"); lines = lines.replace(/\r\n?/gm, '\n');
let match; let match;
while ((match = LINE.exec(lines)) != null) { while ((match = LINE.exec(lines)) != null) {
const key = match[1]; const key = match[1];
// Default undefined or null to empty string // Default undefined or null to empty string
let value = match[2] || ""; let value = match[2] || '';
// Remove whitespace // Remove whitespace
value = value.trim(); value = value.trim();
@@ -29,12 +29,12 @@ function parse(src) {
const maybeQuote = value[0]; const maybeQuote = value[0];
// Remove surrounding quotes // Remove surrounding quotes
value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2"); value = value.replace(/^(['"`])([\s\S]*)\1$/gm, '$2');
// Expand newlines if double quoted // Expand newlines if double quoted
if (maybeQuote === '"') { if (maybeQuote === '"') {
value = value.replace(/\\n/g, "\n"); value = value.replace(/\\n/g, '\n');
value = value.replace(/\\r/g, "\r"); value = value.replace(/\\r/g, '\r');
} }
// Add to object // Add to object
@@ -3,19 +3,19 @@
* @returns * @returns
*/ */
const guidGenerator = () => { const guidGenerator = () => {
var S4 = function () { const S4 = function () {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}; };
return ( return (
S4() + S4() +
S4() + S4() +
"-" + '-' +
S4() + S4() +
"-" + '-' +
S4() + S4() +
"-" + '-' +
S4() + S4() +
"-" + '-' +
S4() + S4() +
S4() + S4() +
S4() S4()
@@ -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 { envMapping } from '../../../public/data/frequentConstants';
import guidGenerator from "../randomId"; import guidGenerator from '../randomId';
const { const {
decryptAssymmetric, decryptAssymmetric,
decryptSymmetric, decryptSymmetric
} = require("../cryptography/crypto"); } = require('../cryptography/crypto');
const nacl = require("tweetnacl"); const nacl = require('tweetnacl');
nacl.util = require("tweetnacl-util"); nacl.util = require('tweetnacl-util');
interface Props {
env: keyof typeof envMapping;
setFileState: any;
setIsKeyAvailable: any;
setData: any;
workspaceId: string;
}
const getSecretsForProject = async ({ const getSecretsForProject = async ({
env, env,
setFileState, setFileState,
setIsKeyAvailable, setIsKeyAvailable,
setData, setData,
workspaceId, workspaceId
}) => { }: Props) => {
try { try {
let file; let file;
try { try {
@@ -24,44 +32,47 @@ const getSecretsForProject = async ({
setFileState(file); setFileState(file);
} catch (error) { } 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 // This is called isKeyAvilable but what it really means is if a person is able to create new key pairs
setIsKeyAvailable( setIsKeyAvailable(!file.key ? file.secrets.length == 0 : true);
!file.key ? (file.secrets.length == 0 ? true : false) : 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) { if (file.key) {
// assymmetrically decrypt symmetric key with local private key // assymmetrically decrypt symmetric key with local private key
const key = decryptAssymmetric({ const key = decryptAssymmetric({
ciphertext: file.key.encryptedKey, ciphertext: file.key.encryptedKey,
nonce: file.key.nonce, nonce: file.key.nonce,
publicKey: file.key.sender.publicKey, publicKey: file.key.sender.publicKey,
privateKey: PRIVATE_KEY, privateKey: PRIVATE_KEY
}); });
<<<<<<< HEAD:frontend/components/utilities/secrets/getSecretsForProject.js
file.secrets.map((secretPair) => { file.secrets.map((secretPair) => {
=======
file.secrets.map((secretPair: any) => {
>>>>>>> 158c51ff3cbcd9a8eab6c44e728232d79a1cbab9:frontend/components/utilities/secrets/getSecretsForProject.ts
// decrypt .env file with symmetric key // decrypt .env file with symmetric key
const plainTextKey = decryptSymmetric({ const plainTextKey = decryptSymmetric({
ciphertext: secretPair.secretKey.ciphertext, ciphertext: secretPair.secretKey.ciphertext,
iv: secretPair.secretKey.iv, iv: secretPair.secretKey.iv,
tag: secretPair.secretKey.tag, tag: secretPair.secretKey.tag,
key, key
}); });
const plainTextValue = decryptSymmetric({ const plainTextValue = decryptSymmetric({
ciphertext: secretPair.secretValue.ciphertext, ciphertext: secretPair.secretValue.ciphertext,
iv: secretPair.secretValue.iv, iv: secretPair.secretValue.iv,
tag: secretPair.secretValue.tag, tag: secretPair.secretValue.tag,
key, key
}); });
tempFileState.push({ tempFileState.push({
key: plainTextKey, key: plainTextKey,
value: plainTextValue, value: plainTextValue,
type: secretPair.type, type: secretPair.type
}); });
}); });
} }
@@ -71,9 +82,9 @@ const getSecretsForProject = async ({
tempFileState.map((line, index) => [ tempFileState.map((line, index) => [
guidGenerator(), guidGenerator(),
index, index,
line["key"], line['key'],
line["value"], line['value'],
line["type"], line['type']
]) ])
// .sort((a, b) => // .sort((a, b) =>
// sortMethod == "alphabetical" // sortMethod == "alphabetical"
@@ -84,12 +95,12 @@ const getSecretsForProject = async ({
return tempFileState.map((line, index) => [ return tempFileState.map((line, index) => [
guidGenerator(), guidGenerator(),
index, index,
line["key"], line['key'],
line["value"], line['value'],
line["type"], line['type']
]); ]);
} catch (error) { } catch (error) {
console.log("Something went wrong during accessing or decripting secrets."); console.log('Something went wrong during accessing or decripting secrets.');
} }
return true; return true;
}; };
@@ -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;
@@ -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<string, string>;
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;
@@ -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) * This is the second step of the change password process (pake)
@@ -11,12 +20,12 @@ const changePassword2 = ({
tag, tag,
salt, salt,
verifier, verifier,
clientProof, clientProof
}) => { }: Props) => {
return SecurityClient.fetchCall("/api/v1/password/change-password", { return SecurityClient.fetchCall('/api/v1/password/change-password', {
method: "POST", method: 'POST',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ body: JSON.stringify({
clientProof: clientProof, clientProof: clientProof,
@@ -24,13 +33,13 @@ const changePassword2 = ({
iv: iv, iv: iv,
tag: tag, tag: tag,
salt: salt, salt: salt,
verifier: verifier, verifier: verifier
}), })
}).then(async (res) => { }).then(async (res) => {
if (res.status == 200) { if (res && res.status == 200) {
return res; return res;
} else { } else {
console.log("Failed to change the password"); console.log('Failed to change the password');
} }
}); });
}; };
@@ -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. * This function is used to check if the user is authenticated.
@@ -7,17 +7,17 @@ import SecurityClient from "~/utilities/SecurityClient.js";
* @param {*} res * @param {*} res
* @returns * @returns
*/ */
const checkAuth = async (req, res) => { const checkAuth = async () => {
return SecurityClient.fetchCall("/api/v1/auth/checkAuth", { return SecurityClient.fetchCall('/api/v1/auth/checkAuth', {
method: "POST", method: 'POST',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, }
}).then((res) => { }).then((res) => {
if (res.status == 200) { if (res && res.status == 200) {
return res; return res;
} else { } else {
console.log("Not authorized"); console.log('Not authorized');
} }
}); });
}; };
@@ -1,19 +1,24 @@
interface Props {
email: string;
code: string;
}
/** /**
* This route check the verification code from the email that user just recieved * This route check the verification code from the email that user just recieved
* @param {*} email * @param {*} email
* @param {*} code * @param {*} code
* @returns * @returns
*/ */
const checkEmailVerificationCode = (email, code) => { const checkEmailVerificationCode = ({ email, code }: Props) => {
return fetch("/api/v1/signup/email/verify", { return fetch('/api/v1/signup/email/verify', {
method: "POST", method: 'POST',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ body: JSON.stringify({
email: email, email: email,
code: code, code: code
}), })
}); });
}; };
@@ -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. * This function is called in the end of the signup process.
* It sends all the necessary nformation to the server. * It sends all the necessary nformation to the server.
@@ -24,13 +38,13 @@ const completeAccountInformationSignup = ({
tag, tag,
salt, salt,
verifier, verifier,
token, token
}) => { }: Props) => {
return fetch("/api/v1/signup/complete-account/signup", { return fetch('/api/v1/signup/complete-account/signup', {
method: "POST", method: 'POST',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
Authorization: "Bearer " + token, Authorization: 'Bearer ' + token
}, },
body: JSON.stringify({ body: JSON.stringify({
email, email,
@@ -42,8 +56,8 @@ const completeAccountInformationSignup = ({
iv, iv,
tag, tag,
salt, salt,
verifier, verifier
}), })
}); });
}; };
@@ -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. * This function is called in the end of the signup process.
* It sends all the necessary nformation to the server. * It sends all the necessary nformation to the server.
@@ -22,13 +35,13 @@ const completeAccountInformationSignupInvite = ({
tag, tag,
salt, salt,
verifier, verifier,
token, token
}) => { }: Props) => {
return fetch("/api/v1/signup/complete-account/invite", { return fetch('/api/v1/signup/complete-account/invite', {
method: "POST", method: 'POST',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
Authorization: "Bearer " + token, Authorization: 'Bearer ' + token
}, },
body: JSON.stringify({ body: JSON.stringify({
email: email, email: email,
@@ -39,8 +52,8 @@ const completeAccountInformationSignupInvite = ({
iv: iv, iv: iv,
tag: tag, tag: tag,
salt: salt, salt: salt,
verifier: verifier, verifier: verifier
}), })
}); });
}; };
@@ -1,40 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This is the route that issues a backup private key that will afterwards be added into a pdf
*/
const issueBackupPrivateKey = ({
encryptedPrivateKey,
iv,
tag,
salt,
verifier,
clientProof,
}) => {
return SecurityClient.fetchCall(
"/api/v1/password/backup-private-key",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
clientProof: clientProof,
encryptedPrivateKey: encryptedPrivateKey,
iv: iv,
tag: tag,
salt: salt,
verifier: verifier,
}),
}
).then((res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to issue the backup key");
return res;
}
});
};
export default issueBackupPrivateKey;
@@ -0,0 +1,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;
+13 -13
View File
@@ -1,29 +1,29 @@
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from '~/utilities/SecurityClient';
/** /**
* This route logs the user out. Note: the user should authorized to do this. * 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 * We first try to log out - if the authorization fails (response.status = 401), we refetch the new token, and then retry
*/ */
const logout = async () => { const logout = async () => {
return SecurityClient.fetchCall("/api/v1/auth/logout", { return SecurityClient.fetchCall('/api/v1/auth/logout', {
method: "POST", method: 'POST',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, },
credentials: "include", credentials: 'include'
}).then((res) => { }).then((res) => {
if (res?.status == 200) { if (res?.status == 200) {
SecurityClient.setToken(""); SecurityClient.setToken('');
// Delete the cookie by not setting a value; Alternatively clear the local storage // Delete the cookie by not setting a value; Alternatively clear the local storage
localStorage.setItem("publicKey", ""); localStorage.setItem('publicKey', '');
localStorage.setItem("encryptedPrivateKey", ""); localStorage.setItem('encryptedPrivateKey', '');
localStorage.setItem("iv", ""); localStorage.setItem('iv', '');
localStorage.setItem("tag", ""); localStorage.setItem('tag', '');
localStorage.setItem("PRIVATE_KEY", ""); localStorage.setItem('PRIVATE_KEY', '');
console.log("User logged out", res); console.log('User logged out', res);
return res; return res;
} else { } else {
console.log("Failed to log out"); console.log('Failed to log out');
} }
}); });
}; };
-26
View File
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This is the first step of the change password process (pake)
* @param {*} clientPublicKey
* @returns
*/
const SRP1 = ({ clientPublicKey }) => {
return SecurityClient.fetchCall("/api/v1/password/srp1", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
clientPublicKey,
}),
}).then(async (res) => {
if (res.status == 200) {
return await res.json();
} else {
console.log("Failed to do the first step of SRP");
}
});
};
export default SRP1;
+30
View File
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
clientPublicKey: string;
}
/**
* This is the first step of the change password process (pake)
* @param {*} 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;
@@ -2,15 +2,15 @@
* This route send the verification email to the user's email (contains a 6-digit verification code) * This route send the verification email to the user's email (contains a 6-digit verification code)
* @param {*} email * @param {*} email
*/ */
const sendVerificationEmail = (email) => { const sendVerificationEmail = (email: string) => {
fetch("/api/v1/signup/email/signup", { fetch('/api/v1/signup/email/signup', {
method: "POST", method: 'POST',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ body: JSON.stringify({
email: email, email: email
}), })
}); });
}; };
-17
View File
@@ -1,17 +0,0 @@
const token = async (req, res) => {
return fetch("/api/v1/auth/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
}).then(async (res) => {
if (res.status == 200) {
return (await res.json()).token;
} else {
console.log("Getting a new token failed");
}
});
};
export default token;
+17
View File
@@ -0,0 +1,17 @@
const token = async () => {
return fetch('/api/v1/auth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include'
}).then(async (res) => {
if (res.status == 200) {
return (await res.json()).token;
} else {
console.log('Getting a new token failed');
}
});
};
export default token;
@@ -1,20 +0,0 @@
/**
* This route verifies the signup invite link
* @param {*} email
* @param {*} code
* @returns
*/
const verifySignupInvite = ({ email, code }) => {
return fetch("/api/v1/invite-org/verify", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
code,
}),
});
};
export default verifySignupInvite;
@@ -0,0 +1,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;
@@ -1,16 +0,0 @@
/**
* This route lets us get the public key of infisical. Th euser doesn't have to be authenticated since this is just the public key.
* @param {*} req
* @param {*} res
* @returns
*/
const publicKeyInfisical = (req, res) => {
return fetch("/api/v1/key/publicKey/infisical", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
};
export default publicKeyInfisical;
@@ -0,0 +1,10 @@
const publicKeyInfisical = () => {
return fetch('/api/v1/key/publicKey/infisical', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
};
export default publicKeyInfisical;
@@ -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 * This function fetches the encrypted secrets from the .env file
@@ -6,26 +6,26 @@ import SecurityClient from "~/utilities/SecurityClient.js";
* @param {*} env * @param {*} env
* @returns * @returns
*/ */
const getSecrets = async (workspaceId, env) => { const getSecrets = async (workspaceId: string, env: string) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall(
"/api/v1/secret/" + '/api/v1/secret/' +
workspaceId + workspaceId +
"?" + '?' +
new URLSearchParams({ new URLSearchParams({
environment: env, environment: env,
channel: "web", channel: 'web'
}), }),
{ {
method: "GET", method: 'GET',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, }
} }
).then(async (res) => { ).then(async (res) => {
if (res.status == 200) { if (res && res.status == 200) {
return await res.json(); return await res.json();
} else { } else {
console.log("Failed to get project secrets"); console.log('Failed to get project secrets');
} }
}); });
}; };
-30
View File
@@ -1,30 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This function uploads the encrypted .env file
* @param {*} req
* @param {*} res
* @returns
*/
const uploadSecrets = async ({ workspaceId, secrets, keys, environment }) => {
return SecurityClient.fetchCall("/api/v1/secret/" + workspaceId, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
secrets,
keys,
environment,
channel: "web",
}),
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to push secrets");
}
});
};
export default uploadSecrets;
+42
View File
@@ -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;
@@ -1,25 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
const changeHerokuConfigVars = ({ integrationId, key, secrets }) => {
return SecurityClient.fetchCall(
"/api/v1/integration/" + integrationId + "/sync",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
key,
secrets,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to sync secrets to Heroku");
}
});
};
export default changeHerokuConfigVars;
@@ -0,0 +1,41 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
integrationId: string;
key: { encryptedKey: any; nonce: any };
secrets: {
ciphertextKey: any;
ivKey: any;
tagKey: any;
hashKey: any;
ciphertextValue: any;
ivValue: any;
tagValue: any;
hashValue: any;
type: string;
}[];
}
const changeHerokuConfigVars = ({ integrationId, key, secrets }: Props) => {
return SecurityClient.fetchCall(
'/api/v1/integration/' + integrationId + '/sync',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
key,
secrets
})
}
).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to sync secrets to Heroku');
}
});
};
export default changeHerokuConfigVars;
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route deletes an integration from a certain project
* @param {*} integrationId
* @returns
*/
const deleteIntegration = ({ integrationId }) => {
return SecurityClient.fetchCall(
"/api/v1/integration/" + integrationId,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).workspace;
} else {
console.log("Failed to delete an integration");
}
});
};
export default deleteIntegration;
@@ -0,0 +1,27 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
integrationId: string;
}
/**
* This route deletes an integration from a certain project
* @param {*} integrationId
* @returns
*/
const deleteIntegration = ({ integrationId }: Props) => {
return SecurityClient.fetchCall('/api/v1/integration/' + integrationId, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).workspace;
} else {
console.log('Failed to delete an integration');
}
});
};
export default deleteIntegration;
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route deletes an integration authorization from a certain project
* @param {*} integrationAuthId
* @returns
*/
const deleteIntegrationAuth = ({ integrationAuthId }) => {
return SecurityClient.fetchCall(
"/api/v1/integration-auth/" + integrationAuthId,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to delete an integration authorization");
}
});
};
export default deleteIntegrationAuth;
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
integrationAuthId: string;
}
/**
* This route deletes an integration authorization from a certain project
* @param {*} integrationAuthId
* @returns
*/
const deleteIntegrationAuth = ({ integrationAuthId }: Props) => {
return SecurityClient.fetchCall(
'/api/v1/integration-auth/' + integrationAuthId,
{
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to delete an integration authorization');
}
});
};
export default deleteIntegrationAuth;
@@ -1,21 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
const getIntegrationApps = ({ integrationAuthId }) => {
return SecurityClient.fetchCall(
"/api/v1/integration-auth/" + integrationAuthId + "/apps",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).apps;
} else {
console.log("Failed to get available apps for an integration");
}
});
};
export default getIntegrationApps;
@@ -0,0 +1,25 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
integrationAuthId: string;
}
const getIntegrationApps = ({ integrationAuthId }: Props) => {
return SecurityClient.fetchCall(
'/api/v1/integration-auth/' + integrationAuthId + '/apps',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).apps;
} else {
console.log('Failed to get available apps for an integration');
}
});
};
export default getIntegrationApps;
@@ -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;
@@ -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;
@@ -0,0 +1,36 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
integrationId: string;
appName: string;
environment: string;
}
/**
* This route starts the integration after teh default one if gonna set up.
* @param {*} integrationId
* @returns
*/
const startIntegration = ({ integrationId, appName, environment }: Props) => {
return SecurityClient.fetchCall('/api/v1/integration/' + integrationId, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
update: {
app: appName,
environment,
isActive: true
}
})
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to start an integration');
}
});
};
export default startIntegration;
@@ -1,31 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This is the first step of the change password process (pake)
* @param {*} clientPublicKey
* @returns
*/
const AuthorizeIntegration = ({ workspaceId, code, integration }) => {
return SecurityClient.fetchCall(
"/api/v1/integration-auth/oauth-token",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
workspaceId,
code,
integration,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to authorize the integration");
}
});
};
export default AuthorizeIntegration;
@@ -0,0 +1,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;
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route gets authorizations of a certain project (Heroku, etc.)
* @param {*} workspaceId
* @returns
*/
const getWorkspaceAuthorizations = ({ workspaceId }) => {
return SecurityClient.fetchCall(
"/api/v1/workspace/" + workspaceId + "/authorizations",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).authorizations;
} else {
console.log("Failed to get project authorizations");
}
});
};
export default getWorkspaceAuthorizations;
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
workspaceId: string;
}
/**
* This route gets authorizations of a certain project (Heroku, etc.)
* @param {*} workspaceId
* @returns
*/
const getWorkspaceAuthorizations = ({ workspaceId }: Props) => {
return SecurityClient.fetchCall(
'/api/v1/workspace/' + workspaceId + '/authorizations',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).authorizations;
} else {
console.log('Failed to get project authorizations');
}
});
};
export default getWorkspaceAuthorizations;
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route gets integrations of a certain project (Heroku, etc.)
* @param {*} workspaceId
* @returns
*/
const getWorkspaceIntegrations = ({ workspaceId }) => {
return SecurityClient.fetchCall(
"/api/v1/workspace/" + workspaceId + "/integrations",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).integrations;
} else {
console.log("Failed to get the project integrations");
}
});
};
export default getWorkspaceIntegrations;
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
interface Props {
workspaceId: string;
}
/**
* This route gets integrations of a certain project (Heroku, etc.)
* @param {*} workspaceId
* @returns
*/
const getWorkspaceIntegrations = ({ workspaceId }: Props) => {
return SecurityClient.fetchCall(
'/api/v1/workspace/' + workspaceId + '/integrations',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).integrations;
} else {
console.log('Failed to get the project integrations');
}
});
};
export default getWorkspaceIntegrations;
+7 -7
View File
@@ -1,21 +1,21 @@
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from '~/utilities/SecurityClient';
/** /**
* This route lets us get info about a certain org * This route lets us get info about a certain org
* @param {string} orgId - the organization ID * @param {string} orgId - the organization ID
* @returns * @returns
*/ */
const getOrganization = ({ orgId }: { orgId: string; }) => { const getOrganization = ({ orgId }: { orgId: string }) => {
return SecurityClient.fetchCall("/api/v1/organization/" + orgId, { return SecurityClient.fetchCall('/api/v1/organization/' + orgId, {
method: "GET", method: 'GET',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, }
}).then(async (res) => { }).then(async (res) => {
if (res?.status == 200) { if (res?.status == 200) {
return (await res.json()).organization; return (await res.json()).organization;
} else { } else {
console.log("Failed to get org info"); console.log('Failed to get org info');
} }
}); });
}; };
@@ -1,27 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route lets us get all the users in an org.
* @param {*} req
* @param {*} res
* @returns
*/
const getOrganizationProjects = (req, res) => {
return SecurityClient.fetchCall(
"/api/organization/" + req.orgId + "/workspaces",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).workspaces;
} else {
console.log("Failed to get projects for an org");
}
});
};
export default getOrganizationProjects;
@@ -0,0 +1,29 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us get all the users in an org.
* @param {*} req
* @param {*} res
* @returns
*/
// TODO: this file is not used anywhere
const getOrganizationProjects = (req: { orgId: string }) => {
return SecurityClient.fetchCall(
'/api/organization/' + req.orgId + '/workspaces',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).workspaces;
} else {
console.log('Failed to get projects for an org');
}
});
};
export default getOrganizationProjects;
@@ -1,27 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route lets us get the current subscription of an org.
* @param {*} req
* @param {*} res
* @returns
*/
const getOrganizationSubscriptions = (req, res) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + req.orgId + "/subscriptions",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).subscriptions;
} else {
console.log("Failed to get org subscriptions");
}
});
};
export default getOrganizationSubscriptions;
@@ -0,0 +1,27 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us get the current subscription of an org.
* @param {*} req
* @param {*} res
* @returns
*/
const getOrganizationSubscriptions = (req: { orgId: string }) => {
return SecurityClient.fetchCall(
'/api/v1/organization/' + req.orgId + '/subscriptions',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).subscriptions;
} else {
console.log('Failed to get org subscriptions');
}
});
};
export default getOrganizationSubscriptions;
@@ -1,27 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route lets us get all the projects of a certain user in an org.
* @param {*} req
* @param {*} res
* @returns
*/
const getOrganizationUserProjects = (req) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + req.orgId + "/my-workspaces",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).workspaces;
} else {
console.log("Failed to get projects of a user in an org");
}
});
};
export default getOrganizationUserProjects;
@@ -0,0 +1,27 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us get all the projects of a certain user in an org.
* @param {*} req
* @param {*} res
* @returns
*/
const getOrganizationUserProjects = (req: { orgId: string }) => {
return SecurityClient.fetchCall(
'/api/v1/organization/' + req.orgId + '/my-workspaces',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).workspaces;
} else {
console.log('Failed to get projects of a user in an org');
}
});
};
export default getOrganizationUserProjects;
+8 -11
View File
@@ -1,4 +1,4 @@
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from '~/utilities/SecurityClient';
/** /**
* This route lets us get all the users in an org. * 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 * @param {string} obj.orgId - organization Id
* @returns * @returns
*/ */
const getOrganizationUsers = ({ orgId }: { orgId: string; }) => { const getOrganizationUsers = ({ orgId }: { orgId: string }) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall('/api/v1/organization/' + orgId + '/users', {
"/api/v1/organization/" + orgId + "/users", method: 'GET',
{ headers: {
method: "GET", 'Content-Type': 'application/json'
headers: {
"Content-Type": "application/json",
},
} }
).then(async (res) => { }).then(async (res) => {
if (res?.status == 200) { if (res?.status == 200) {
return (await res.json()).users; return (await res.json()).users;
} else { } else {
console.log("Failed to get org users"); console.log('Failed to get org users');
} }
}); });
}; };
@@ -1,27 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route redirects the user to the right stripe billing page.
* @param {*} req
* @param {*} res
* @returns
*/
const StripeRedirect = ({ orgId }) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + orgId + "/customer-portal-session",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (window.location.href = (await res.json()).url);
} else {
console.log("Failed to redirect to Stripe");
}
});
};
export default StripeRedirect;
@@ -0,0 +1,27 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route redirects the user to the right stripe billing page.
* @param {*} req
* @param {*} res
* @returns
*/
const StripeRedirect = ({ orgId }: { orgId: string }) => {
return SecurityClient.fetchCall(
'/api/v1/organization/' + orgId + '/customer-portal-session',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (window.location.href = (await res.json()).url);
} else {
console.log('Failed to redirect to Stripe');
}
});
};
export default StripeRedirect;
@@ -1,29 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route add an incident contact email to a certain organization
* @param {*} param0
* @returns
*/
const addIncidentContact = (organizationId, email) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + organizationId + "/incidentContactOrg",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to add an incident contact");
}
});
};
export default addIncidentContact;
@@ -0,0 +1,29 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route add an incident contact email to a certain organization
* @param {*} param0
* @returns
*/
const addIncidentContact = (organizationId: string, email: string) => {
return SecurityClient.fetchCall(
'/api/v1/organization/' + organizationId + '/incidentContactOrg',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email
})
}
).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to add an incident contact');
}
});
};
export default addIncidentContact;
@@ -1,28 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This function sends an email invite to a user to join an org
* @param {*} email
* @param {*} orgId
* @returns
*/
const addUserToOrg = (email, orgId) => {
return SecurityClient.fetchCall("/api/v1/invite-org/signup", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
inviteeEmail: email,
organizationId: orgId,
}),
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to add a user to an org");
}
});
};
export default addUserToOrg;
@@ -0,0 +1,28 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This function sends an email invite to a user to join an org
* @param {*} email
* @param {*} orgId
* @returns
*/
const addUserToOrg = (email: string, orgId: string) => {
return SecurityClient.fetchCall('/api/v1/invite-org/signup', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
inviteeEmail: email,
organizationId: orgId
})
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to add a user to an org');
}
});
};
export default addUserToOrg;
@@ -1,29 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route deletes an incident Contact from a certain organization
* @param {*} param0
* @returns
*/
const deleteIncidentContact = (organizaionId, email) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + organizaionId + "/incidentContactOrg",
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to delete an incident contact");
}
});
};
export default deleteIncidentContact;
@@ -0,0 +1,29 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route deletes an incident Contact from a certain organization
* @param {*} param0
* @returns
*/
const deleteIncidentContact = (organizationId: string, email: string) => {
return SecurityClient.fetchCall(
'/api/v1/organization/' + organizationId + '/incidentContactOrg',
{
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email
})
}
).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to delete an incident contact');
}
});
};
export default deleteIncidentContact;
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This function removes a certain member from a certain organization
* @param {*} membershipId
* @returns
*/
const deleteUserFromOrganization = (membershipId) => {
return SecurityClient.fetchCall(
"/api/v1/membership-org/" + membershipId,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to delete a user from an org");
}
});
};
export default deleteUserFromOrganization;
@@ -0,0 +1,23 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This function removes a certain member from a certain organization
* @param {*} membershipId
* @returns
*/
const deleteUserFromOrganization = (membershipId: string) => {
return SecurityClient.fetchCall('/api/v1/membership-org/' + membershipId, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to delete a user from an org');
}
});
};
export default deleteUserFromOrganization;
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This routes gets all the incident contacts of a certain organization
* @param {*} workspaceId
* @returns
*/
const getIncidentContacts = (organizationId) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + organizationId + "/incidentContactOrg",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).incidentContactsOrg;
} else {
console.log("Failed to get incident contacts");
}
});
};
export default getIncidentContacts;
@@ -0,0 +1,26 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This routes gets all the incident contacts of a certain organization
* @param {*} workspaceId
* @returns
*/
const getIncidentContacts = (organizationId: string) => {
return SecurityClient.fetchCall(
'/api/v1/organization/' + organizationId + '/incidentContactOrg',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).incidentContactsOrg;
} else {
console.log('Failed to get incident contacts');
}
});
};
export default getIncidentContacts;
+6 -6
View File
@@ -1,20 +1,20 @@
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from '~/utilities/SecurityClient';
/** /**
* This route lets us get the all the orgs of a certain user. * This route lets us get the all the orgs of a certain user.
* @returns * @returns
*/ */
const getOrganizations = () => { const getOrganizations = () => {
return SecurityClient.fetchCall("/api/v1/organization", { return SecurityClient.fetchCall('/api/v1/organization', {
method: "GET", method: 'GET',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, }
}).then(async (res) => { }).then(async (res) => {
if (res?.status == 200) { if (res?.status == 200) {
return (await res.json()).organizations; return (await res.json()).organizations;
} else { } else {
console.log("Failed to get orgs of a user"); console.log('Failed to get orgs of a user');
} }
}); });
}; };
@@ -1,30 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route lets us rename a certain org.
* @param {*} req
* @param {*} res
* @returns
*/
const renameOrg = (orgId, newOrgName) => {
return SecurityClient.fetchCall(
"/api/v1/organization/" + orgId + "/name",
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: newOrgName,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to rename an organization");
}
});
};
export default renameOrg;
@@ -0,0 +1,27 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route lets us rename a certain org.
* @param {*} req
* @param {*} res
* @returns
*/
const renameOrg = (orgId: string, newOrgName: string) => {
return SecurityClient.fetchCall('/api/v1/organization/' + orgId + '/name', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: newOrgName
})
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to rename an organization');
}
});
};
export default renameOrg;
@@ -1,4 +1,14 @@
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from '~/utilities/SecurityClient';
interface Props {
name: string;
workspaceId: string;
environment: string;
expiresIn: number;
publicKey: string;
encryptedKey: string;
nonce: string;
}
/** /**
* This route gets service tokens for a specific user in a project * This route gets service tokens for a specific user in a project
@@ -12,12 +22,12 @@ const addServiceToken = ({
expiresIn, expiresIn,
publicKey, publicKey,
encryptedKey, encryptedKey,
nonce, nonce
}) => { }: Props) => {
return SecurityClient.fetchCall("/api/v1/service-token/", { return SecurityClient.fetchCall('/api/v1/service-token/', {
method: "POST", method: 'POST',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ body: JSON.stringify({
name, name,
@@ -26,13 +36,13 @@ const addServiceToken = ({
expiresIn, expiresIn,
publicKey, publicKey,
encryptedKey, encryptedKey,
nonce, nonce
}), })
}).then(async (res) => { }).then(async (res) => {
if (res.status == 200) { if (res && res.status == 200) {
return (await res.json()).token; return (await res.json()).token;
} else { } else {
console.log("Failed to add service tokens"); console.log('Failed to add service tokens');
} }
}); });
}; };
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route gets service tokens for a specific user in a project
* @param {*} param0
* @returns
*/
const getServiceTokens = ({ workspaceId }) => {
return SecurityClient.fetchCall(
"/api/v1/workspace/" + workspaceId + "/service-tokens",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(async (res) => {
if (res.status == 200) {
return (await res.json()).serviceTokens;
} else {
console.log("Failed to get service tokens");
}
});
};
export default getServiceTokens;
@@ -0,0 +1,26 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route gets service tokens for a specific user in a project
* @param {*} param0
* @returns
*/
const getServiceTokens = ({ workspaceId }: { workspaceId: string }) => {
return SecurityClient.fetchCall(
'/api/v1/workspace/' + workspaceId + '/service-tokens',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(async (res) => {
if (res && res.status == 200) {
return (await res.json()).serviceTokens;
} else {
console.log('Failed to get service tokens');
}
});
};
export default getServiceTokens;
+6 -6
View File
@@ -1,19 +1,19 @@
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from '~/utilities/SecurityClient';
/** /**
* This route gets the information about a specific user. * This route gets the information about a specific user.
*/ */
const getUser = () => { const getUser = () => {
return SecurityClient.fetchCall("/api/v1/user", { return SecurityClient.fetchCall('/api/v1/user', {
method: "GET", method: 'GET',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, }
}).then(async (res) => { }).then(async (res) => {
if (res?.status == 200) { if (res?.status == 200) {
return (await res.json()).user; return (await res.json()).user;
} else { } else {
console.log("Failed to get user info"); console.log('Failed to get user info');
} }
}); });
}; };
@@ -1,4 +1,4 @@
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from '~/utilities/SecurityClient';
/** /**
* This route registers a certain action for a user * This route registers a certain action for a user
@@ -6,24 +6,24 @@ import SecurityClient from "~/utilities/SecurityClient";
* @param {*} workspaceId * @param {*} workspaceId
* @returns * @returns
*/ */
const checkUserAction = ({ action }) => { const checkUserAction = ({ action }: { action: string }) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall(
"/api/v1/user-action" + '/api/v1/user-action' +
"?" + '?' +
new URLSearchParams({ new URLSearchParams({
action, action
}), }),
{ {
method: "GET", method: 'GET',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, }
} }
).then(async (res) => { ).then(async (res) => {
if (res.status == 200) { if (res && res.status == 200) {
return (await res.json()).userAction; return (await res.json()).userAction;
} else { } else {
console.log("Failed to check a user action"); console.log('Failed to check a user action');
} }
}); });
}; };
@@ -1,26 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route registers a certain action for a user
* @param {*} action
* @returns
*/
const registerUserAction = ({ action }) => {
return SecurityClient.fetchCall("/api/v1/user-action", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
action,
}),
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to register a user action");
}
});
};
export default registerUserAction;
@@ -0,0 +1,26 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route registers a certain action for a user
* @param {*} action
* @returns
*/
const registerUserAction = ({ action }: { action: string }) => {
return SecurityClient.fetchCall('/api/v1/user-action', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
action
})
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to register a user action');
}
});
};
export default registerUserAction;
@@ -1,30 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This function adds a user to a project
* @param {*} email
* @param {*} workspaceId
* @returns
*/
const addUserToWorkspace = (email, workspaceId) => {
return SecurityClient.fetchCall(
"/api/v1/workspace/" + workspaceId + "/invite-signup",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
}),
}
).then(async (res) => {
if (res.status == 200) {
return await res.json();
} else {
console.log("Failed to add a user to project");
}
});
};
export default addUserToWorkspace;
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This function adds a user to a project
* @param {*} email
* @param {*} workspaceId
* @returns
*/
const addUserToWorkspace = (email: string, workspaceId: string) => {
return SecurityClient.fetchCall(
'/api/v1/workspace/' + workspaceId + '/invite-signup',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email
})
}
).then(async (res) => {
if (res && res.status == 200) {
return await res.json();
} else {
console.log('Failed to add a user to project');
}
});
};
export default addUserToWorkspace;
@@ -1,30 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This function change the access of a user in a certain workspace
* @param {*} membershipId
* @param {*} role
* @returns
*/
const changeUserRoleInWorkspace = (membershipId, role) => {
return SecurityClient.fetchCall(
"/api/v1/membership/" + membershipId + "/change-role",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
role: role,
}),
}
).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to change the user role in a project");
}
});
};
export default changeUserRoleInWorkspace;
@@ -0,0 +1,30 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This function change the access of a user in a certain workspace
* @param {*} membershipId
* @param {*} role
* @returns
*/
const changeUserRoleInWorkspace = (membershipId: string, role: string) => {
return SecurityClient.fetchCall(
'/api/v1/membership/' + membershipId + '/change-role',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
role: role
})
}
).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to change the user role in a project');
}
});
};
export default changeUserRoleInWorkspace;
@@ -1,4 +1,4 @@
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from '~/utilities/SecurityClient';
/** /**
* This route creates a new workspace for a user within a certain organization. * 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 * @param {string} organizationId - org ID
* @returns * @returns
*/ */
const createWorkspace = ( { workspaceName, organizationId }: { workspaceName: string; organizationId: string; }) => { const createWorkspace = ({
return SecurityClient.fetchCall("/api/v1/workspace", { workspaceName,
method: "POST", organizationId
}: {
workspaceName: string;
organizationId: string;
}) => {
return SecurityClient.fetchCall('/api/v1/workspace', {
method: 'POST',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ body: JSON.stringify({
workspaceName: workspaceName, workspaceName: workspaceName,
organizationId: organizationId, organizationId: organizationId
}), })
}).then(async (res) => { }).then(async (res) => {
if (res?.status == 200) { if (res?.status == 200) {
return (await res.json()).workspace; return (await res.json()).workspace;
} else { } else {
console.log("Failed to create a project"); console.log('Failed to create a project');
} }
}); });
}; };
@@ -1,23 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This function removes a certain member from a certain workspace
* @param {*} membershipId
* @returns
*/
const deleteUserFromWorkspace = (membershipId) => {
return SecurityClient.fetchCall("/api/v1/membership/" + membershipId, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to delete a user from a project");
}
});
};
export default deleteUserFromWorkspace;
@@ -0,0 +1,23 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This function removes a certain member from a certain workspace
* @param {*} membershipId
* @returns
*/
const deleteUserFromWorkspace = (membershipId: string) => {
return SecurityClient.fetchCall('/api/v1/membership/' + membershipId, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to delete a user from a project');
}
});
};
export default deleteUserFromWorkspace;
@@ -1,23 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route deletes a specified workspace.
* @param {*} workspaceId
* @returns
*/
const deleteWorkspace = (workspaceId) => {
return SecurityClient.fetchCall("/api/v1/workspace/" + workspaceId, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
}).then(async (res) => {
if (res.status == 200) {
return res;
} else {
console.log("Failed to delete a project");
}
});
};
export default deleteWorkspace;
@@ -0,0 +1,23 @@
import SecurityClient from '~/utilities/SecurityClient';
/**
* This route deletes a specified workspace.
* @param {*} workspaceId
* @returns
*/
const deleteWorkspace = (workspaceId: string) => {
return SecurityClient.fetchCall('/api/v1/workspace/' + workspaceId, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}).then(async (res) => {
if (res && res.status == 200) {
return res;
} else {
console.log('Failed to delete a project');
}
});
};
export default deleteWorkspace;
@@ -1,24 +1,21 @@
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from '~/utilities/SecurityClient';
/** /**
* Get the latest key pairs from a certain workspace * Get the latest key pairs from a certain workspace
* @param {string} workspaceId * @param {string} workspaceId
* @returns * @returns
*/ */
const getLatestFileKey = ({ workspaceId } : { workspaceId: string; }) => { const getLatestFileKey = ({ workspaceId }: { workspaceId: string }) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall('/api/v1/key/' + workspaceId + '/latest', {
"/api/v1/key/" + workspaceId + "/latest", method: 'GET',
{ headers: {
method: "GET", 'Content-Type': 'application/json'
headers: {
"Content-Type": "application/json",
},
} }
).then(async (res) => { }).then(async (res) => {
if (res?.status == 200) { if (res?.status == 200) {
return await res.json(); return await res.json();
} else { } else {
console.log("Failed to get the latest key pairs for a certain project"); console.log('Failed to get the latest key pairs for a certain project');
} }
}); });
}; };
+8 -11
View File
@@ -1,24 +1,21 @@
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from '~/utilities/SecurityClient';
/** /**
* This route lets us get the information of a certain project. * This route lets us get the information of a certain project.
* @param {*} projectId - project ID (we renamed workspaces to projects in the app) * @param {*} projectId - project ID (we renamed workspaces to projects in the app)
* @returns * @returns
*/ */
const getProjectInfo = ({ projectId }: { projectId: string; }) => { const getProjectInfo = ({ projectId }: { projectId: string }) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall('/api/v1/workspace/' + projectId, {
"/api/v1/workspace/" + projectId, method: 'GET',
{ headers: {
method: "GET", 'Content-Type': 'application/json'
headers: {
"Content-Type": "application/json",
},
} }
).then(async (res) => { }).then(async (res) => {
if (res?.status == 200) { if (res?.status == 200) {
return (await res.json()).workspace; return (await res.json()).workspace;
} else { } else {
console.log("Failed to get project info"); console.log('Failed to get project info');
} }
}); });
}; };
@@ -1,24 +1,24 @@
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from '~/utilities/SecurityClient';
/** /**
* This route lets us get all the users in the workspace. * This route lets us get all the users in the workspace.
* @param {string} workspaceId - workspace ID * @param {string} workspaceId - workspace ID
* @returns * @returns
*/ */
const getWorkspaceUsers = ({ workspaceId }: { workspaceId: string; }) => { const getWorkspaceUsers = ({ workspaceId }: { workspaceId: string }) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall(
"/api/v1/workspace/" + workspaceId + "/users", '/api/v1/workspace/' + workspaceId + '/users',
{ {
method: "GET", method: 'GET',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json'
}, }
} }
).then(async (res) => { ).then(async (res) => {
if (res?.status == 200) { if (res?.status == 200) {
return (await res.json()).users; return (await res.json()).users;
} else { } else {
console.log("Failed to get Project Users"); console.log('Failed to get Project Users');
} }
}); });
}; };

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