From 4a14753b8ce8b5d0785dfbd420b17c58fa9fa4f0 Mon Sep 17 00:00:00 2001 From: seunghyunOh Date: Sun, 11 Dec 2022 14:56:07 +0900 Subject: [PATCH 1/4] Convert TS to JS --- frontend/components/analytics/posthog.ts | 18 +++ .../components/billing/{Plan.js => Plan.tsx} | 48 +++++--- .../components/utilities/SecurityClient.js | 24 ---- .../components/utilities/SecurityClient.ts | 27 +++++ .../utilities/cryptography/issueBackupKey.js | 98 --------------- .../utilities/cryptography/issueBackupKey.ts | 112 ++++++++++++++++++ .../components/utilities/{file.js => file.ts} | 14 +-- .../utilities/{randomId.js => randomId.ts} | 10 +- ...sForProject.js => getSecretsForProject.ts} | 60 +++++----- .../utilities/secrets/pushKeysIntegration.js | 74 ------------ .../utilities/secrets/pushKeysIntegration.ts | 79 ++++++++++++ ...{ChangePassword2.js => ChangePassword2.ts} | 29 +++-- .../api/auth/{CheckAuth.js => CheckAuth.ts} | 16 +-- ...nCode.js => CheckEmailVerificationCode.ts} | 17 ++- ...js => CompleteAccountInformationSignup.ts} | 30 +++-- ...CompleteAccountInformationSignupInvite.ts} | 29 +++-- .../pages/api/auth/IssueBackupPrivateKey.js | 40 ------- .../pages/api/auth/IssueBackupPrivateKey.ts | 44 +++++++ frontend/pages/api/auth/SRP1.js | 26 ---- frontend/pages/api/auth/SRP1.ts | 30 +++++ ...ationEmail.js => SendVerificationEmail.ts} | 12 +- frontend/pages/api/auth/Token.js | 17 --- frontend/pages/api/auth/Token.ts | 17 +++ frontend/pages/api/auth/VerifySignupInvite.js | 20 ---- frontend/pages/api/auth/VerifySignupInvite.ts | 25 ++++ frontend/pages/api/auth/publicKeyInfisical.js | 16 --- frontend/pages/api/auth/publicKeyInfisical.ts | 10 ++ .../files/{GetSecrets.js => GetSecrets.ts} | 20 ++-- frontend/pages/api/files/UploadSecrets.js | 30 ----- frontend/pages/api/files/UploadSecrets.ts | 42 +++++++ .../integrations/ChangeHerokuConfigVars.js | 25 ---- .../integrations/ChangeHerokuConfigVars.ts | 31 +++++ .../api/integrations/DeleteIntegration.js | 26 ---- .../api/integrations/DeleteIntegration.ts | 27 +++++ .../api/integrations/DeleteIntegrationAuth.js | 26 ---- .../api/integrations/DeleteIntegrationAuth.ts | 30 +++++ .../api/integrations/GetIntegrationApps.js | 21 ---- .../api/integrations/GetIntegrationApps.ts | 25 ++++ .../pages/api/integrations/GetIntegrations.js | 18 --- .../pages/api/integrations/GetIntegrations.ts | 18 +++ .../api/integrations/StartIntegration.js | 33 ------ .../api/integrations/StartIntegration.ts | 36 ++++++ .../api/integrations/authorizeIntegration.js | 31 ----- .../api/integrations/authorizeIntegration.ts | 33 ++++++ .../getWorkspaceAuthorizations.js | 26 ---- .../getWorkspaceAuthorizations.ts | 30 +++++ .../integrations/getWorkspaceIntegrations.js | 26 ---- .../integrations/getWorkspaceIntegrations.ts | 30 +++++ .../pages/api/organization/GetOrgProjects.js | 27 ----- .../pages/api/organization/GetOrgProjects.ts | 29 +++++ .../api/organization/GetOrgSubscription.js | 27 ----- .../api/organization/GetOrgSubscription.ts | 27 +++++ .../api/organization/GetOrgUserProjects.js | 27 ----- .../api/organization/GetOrgUserProjects.ts | 27 +++++ .../pages/api/organization/StripeRedirect.js | 27 ----- .../pages/api/organization/StripeRedirect.ts | 27 +++++ .../api/organization/addIncidentContact.js | 29 ----- .../api/organization/addIncidentContact.ts | 29 +++++ .../pages/api/organization/addUserToOrg.js | 28 ----- .../pages/api/organization/addUserToOrg.ts | 28 +++++ .../api/organization/deleteIncidentContact.js | 29 ----- .../api/organization/deleteIncidentContact.ts | 29 +++++ .../deleteUserFromOrganization.js | 26 ---- .../deleteUserFromOrganization.ts | 23 ++++ .../api/organization/getIncidentContacts.js | 26 ---- .../api/organization/getIncidentContacts.ts | 26 ++++ frontend/pages/api/organization/renameOrg.js | 30 ----- frontend/pages/api/organization/renameOrg.ts | 27 +++++ ...{addServiceToken.js => addServiceToken.ts} | 30 +++-- .../api/serviceToken/getServiceTokens.js | 26 ---- .../api/serviceToken/getServiceTokens.ts | 26 ++++ ...{checkUserAction.js => checkUserAction.ts} | 20 ++-- .../api/userActions/registerUserAction.js | 26 ---- .../api/userActions/registerUserAction.ts | 26 ++++ .../pages/api/workspace/addUserToWorkspace.js | 30 ----- .../pages/api/workspace/addUserToWorkspace.ts | 30 +++++ .../workspace/changeUserRoleInWorkspace.js | 30 ----- .../workspace/changeUserRoleInWorkspace.ts | 30 +++++ .../api/workspace/deleteUserFromWorkspace.js | 23 ---- .../api/workspace/deleteUserFromWorkspace.ts | 23 ++++ .../pages/api/workspace/deleteWorkspace.js | 23 ---- .../pages/api/workspace/deleteWorkspace.ts | 23 ++++ .../pages/api/workspace/renameWorkspace.js | 30 ----- .../pages/api/workspace/renameWorkspace.ts | 30 +++++ frontend/pages/api/workspace/uploadKeys.js | 33 ------ frontend/pages/api/workspace/uploadKeys.ts | 38 ++++++ 86 files changed, 1366 insertions(+), 1205 deletions(-) create mode 100644 frontend/components/analytics/posthog.ts rename frontend/components/billing/{Plan.js => Plan.tsx} (66%) delete mode 100644 frontend/components/utilities/SecurityClient.js create mode 100644 frontend/components/utilities/SecurityClient.ts delete mode 100644 frontend/components/utilities/cryptography/issueBackupKey.js create mode 100644 frontend/components/utilities/cryptography/issueBackupKey.ts rename frontend/components/utilities/{file.js => file.ts} (74%) rename frontend/components/utilities/{randomId.js => randomId.ts} (82%) rename frontend/components/utilities/secrets/{getSecretsForProject.js => getSecretsForProject.ts} (60%) delete mode 100644 frontend/components/utilities/secrets/pushKeysIntegration.js create mode 100644 frontend/components/utilities/secrets/pushKeysIntegration.ts rename frontend/pages/api/auth/{ChangePassword2.js => ChangePassword2.ts} (50%) rename frontend/pages/api/auth/{CheckAuth.js => CheckAuth.ts} (50%) rename frontend/pages/api/auth/{CheckEmailVerificationCode.js => CheckEmailVerificationCode.ts} (50%) rename frontend/pages/api/auth/{CompleteAccountInformationSignup.js => CompleteAccountInformationSignup.ts} (64%) rename frontend/pages/api/auth/{CompleteAccountInformationSignupInvite.js => CompleteAccountInformationSignupInvite.ts} (64%) delete mode 100644 frontend/pages/api/auth/IssueBackupPrivateKey.js create mode 100644 frontend/pages/api/auth/IssueBackupPrivateKey.ts delete mode 100644 frontend/pages/api/auth/SRP1.js create mode 100644 frontend/pages/api/auth/SRP1.ts rename frontend/pages/api/auth/{SendVerificationEmail.js => SendVerificationEmail.ts} (55%) delete mode 100644 frontend/pages/api/auth/Token.js create mode 100644 frontend/pages/api/auth/Token.ts delete mode 100644 frontend/pages/api/auth/VerifySignupInvite.js create mode 100644 frontend/pages/api/auth/VerifySignupInvite.ts delete mode 100644 frontend/pages/api/auth/publicKeyInfisical.js create mode 100644 frontend/pages/api/auth/publicKeyInfisical.ts rename frontend/pages/api/files/{GetSecrets.js => GetSecrets.ts} (53%) delete mode 100644 frontend/pages/api/files/UploadSecrets.js create mode 100644 frontend/pages/api/files/UploadSecrets.ts delete mode 100644 frontend/pages/api/integrations/ChangeHerokuConfigVars.js create mode 100644 frontend/pages/api/integrations/ChangeHerokuConfigVars.ts delete mode 100644 frontend/pages/api/integrations/DeleteIntegration.js create mode 100644 frontend/pages/api/integrations/DeleteIntegration.ts delete mode 100644 frontend/pages/api/integrations/DeleteIntegrationAuth.js create mode 100644 frontend/pages/api/integrations/DeleteIntegrationAuth.ts delete mode 100644 frontend/pages/api/integrations/GetIntegrationApps.js create mode 100644 frontend/pages/api/integrations/GetIntegrationApps.ts delete mode 100644 frontend/pages/api/integrations/GetIntegrations.js create mode 100644 frontend/pages/api/integrations/GetIntegrations.ts delete mode 100644 frontend/pages/api/integrations/StartIntegration.js create mode 100644 frontend/pages/api/integrations/StartIntegration.ts delete mode 100644 frontend/pages/api/integrations/authorizeIntegration.js create mode 100644 frontend/pages/api/integrations/authorizeIntegration.ts delete mode 100644 frontend/pages/api/integrations/getWorkspaceAuthorizations.js create mode 100644 frontend/pages/api/integrations/getWorkspaceAuthorizations.ts delete mode 100644 frontend/pages/api/integrations/getWorkspaceIntegrations.js create mode 100644 frontend/pages/api/integrations/getWorkspaceIntegrations.ts delete mode 100644 frontend/pages/api/organization/GetOrgProjects.js create mode 100644 frontend/pages/api/organization/GetOrgProjects.ts delete mode 100644 frontend/pages/api/organization/GetOrgSubscription.js create mode 100644 frontend/pages/api/organization/GetOrgSubscription.ts delete mode 100644 frontend/pages/api/organization/GetOrgUserProjects.js create mode 100644 frontend/pages/api/organization/GetOrgUserProjects.ts delete mode 100644 frontend/pages/api/organization/StripeRedirect.js create mode 100644 frontend/pages/api/organization/StripeRedirect.ts delete mode 100644 frontend/pages/api/organization/addIncidentContact.js create mode 100644 frontend/pages/api/organization/addIncidentContact.ts delete mode 100644 frontend/pages/api/organization/addUserToOrg.js create mode 100644 frontend/pages/api/organization/addUserToOrg.ts delete mode 100644 frontend/pages/api/organization/deleteIncidentContact.js create mode 100644 frontend/pages/api/organization/deleteIncidentContact.ts delete mode 100644 frontend/pages/api/organization/deleteUserFromOrganization.js create mode 100644 frontend/pages/api/organization/deleteUserFromOrganization.ts delete mode 100644 frontend/pages/api/organization/getIncidentContacts.js create mode 100644 frontend/pages/api/organization/getIncidentContacts.ts delete mode 100644 frontend/pages/api/organization/renameOrg.js create mode 100644 frontend/pages/api/organization/renameOrg.ts rename frontend/pages/api/serviceToken/{addServiceToken.js => addServiceToken.ts} (51%) delete mode 100644 frontend/pages/api/serviceToken/getServiceTokens.js create mode 100644 frontend/pages/api/serviceToken/getServiceTokens.ts rename frontend/pages/api/userActions/{checkUserAction.js => checkUserAction.ts} (51%) delete mode 100644 frontend/pages/api/userActions/registerUserAction.js create mode 100644 frontend/pages/api/userActions/registerUserAction.ts delete mode 100644 frontend/pages/api/workspace/addUserToWorkspace.js create mode 100644 frontend/pages/api/workspace/addUserToWorkspace.ts delete mode 100644 frontend/pages/api/workspace/changeUserRoleInWorkspace.js create mode 100644 frontend/pages/api/workspace/changeUserRoleInWorkspace.ts delete mode 100644 frontend/pages/api/workspace/deleteUserFromWorkspace.js create mode 100644 frontend/pages/api/workspace/deleteUserFromWorkspace.ts delete mode 100644 frontend/pages/api/workspace/deleteWorkspace.js create mode 100644 frontend/pages/api/workspace/deleteWorkspace.ts delete mode 100644 frontend/pages/api/workspace/renameWorkspace.js create mode 100644 frontend/pages/api/workspace/renameWorkspace.ts delete mode 100644 frontend/pages/api/workspace/uploadKeys.js create mode 100644 frontend/pages/api/workspace/uploadKeys.ts diff --git a/frontend/components/analytics/posthog.ts b/frontend/components/analytics/posthog.ts new file mode 100644 index 000000000..e0d6e7c09 --- /dev/null +++ b/frontend/components/analytics/posthog.ts @@ -0,0 +1,18 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +/* eslint-disable no-undef */ +import posthog from 'posthog-js'; + +import { ENV, POSTHOG_API_KEY, POSTHOG_HOST } from '../utilities/config'; + +export const initPostHog = () => { + if (typeof window !== 'undefined') { + // @ts-ignore + if (ENV == 'production' && TELEMETRY_CAPTURING_ENABLED) { + posthog.init(POSTHOG_API_KEY, { + api_host: POSTHOG_HOST + }); + } + } + + return posthog; +}; diff --git a/frontend/components/billing/Plan.js b/frontend/components/billing/Plan.tsx similarity index 66% rename from frontend/components/billing/Plan.js rename to frontend/components/billing/Plan.tsx index 427469635..b051e7435 100644 --- a/frontend/components/billing/Plan.js +++ b/frontend/components/billing/Plan.tsx @@ -1,14 +1,27 @@ -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 }) { +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 (
@@ -36,7 +49,7 @@ export default function Plan({ plan }) {
{plan.current == false ? ( <> - {plan.buttonTextMain == "Schedule a Demo" ? ( + {plan.buttonTextMain == 'Schedule a Demo' ? (
{plan.buttonTextMain} @@ -45,15 +58,15 @@ export default function Plan({ plan }) { ) : (
)} -
+
{plan.buttonTextSecondary}
@@ -70,9 +86,9 @@ export default function Plan({ plan }) { ) : (

CURRENT PLAN

diff --git a/frontend/components/utilities/SecurityClient.js b/frontend/components/utilities/SecurityClient.js deleted file mode 100644 index 78eebdebe..000000000 --- a/frontend/components/utilities/SecurityClient.js +++ /dev/null @@ -1,24 +0,0 @@ -import token from "~/pages/api/auth/Token"; - -export default class SecurityClient { - static #token = ""; - - constructor() {} - - static setToken(token) { - this.#token = token; - } - - static async fetchCall(resource, options) { - let req = new Request(resource, options); - - if (this.#token == "") { - this.setToken(await token()); - } - - if (this.#token) { - req.headers.set("Authorization", "Bearer " + this.#token); - return fetch(req); - } - } -} diff --git a/frontend/components/utilities/SecurityClient.ts b/frontend/components/utilities/SecurityClient.ts new file mode 100644 index 000000000..ea2664c70 --- /dev/null +++ b/frontend/components/utilities/SecurityClient.ts @@ -0,0 +1,27 @@ +import token from '~/pages/api/auth/Token'; + +export default class SecurityClient { + static #token = ''; + + constructor() {} + + static setToken(token: string) { + this.#token = token; + } + + static async fetchCall( + resource: RequestInfo, + options?: RequestInit | undefined + ) { + const req = new Request(resource, options); + + if (this.#token == '') { + this.setToken(await token()); + } + + if (this.#token) { + req.headers.set('Authorization', 'Bearer ' + this.#token); + return fetch(req); + } + } +} diff --git a/frontend/components/utilities/cryptography/issueBackupKey.js b/frontend/components/utilities/cryptography/issueBackupKey.js deleted file mode 100644 index 19d7ebefa..000000000 --- a/frontend/components/utilities/cryptography/issueBackupKey.js +++ /dev/null @@ -1,98 +0,0 @@ -import issueBackupPrivateKey from "~/pages/api/auth/IssueBackupPrivateKey"; -import SRP1 from "~/pages/api/auth/SRP1"; - -import generateBackupPDF from "../generateBackupPDF"; -import Aes256Gcm from "./aes-256-gcm"; - -const nacl = require("tweetnacl"); -nacl.util = require("tweetnacl-util"); -const jsrp = require("jsrp"); -const clientPassword = new jsrp.client(); -const clientKey = new jsrp.client(); -const crypto = require("crypto"); - -/** - * This function loggs in the user (whether it's right after signup, or a normal login) - * @param {*} email - * @param {*} password - * @param {*} setErrorLogin - * @param {*} router - * @param {*} isSignUp - * @returns - */ -const issueBackupKey = async ({ - email, - password, - personalName, - setBackupKeyError, - setBackupKeyIssued, -}) => { - try { - setBackupKeyError(false); - setBackupKeyIssued(false); - clientPassword.init( - { - username: email, - password: password, - }, - async () => { - const clientPublicKey = clientPassword.getPublicKey(); - - let serverPublicKey, salt; - try { - const res = await SRP1({ - clientPublicKey: clientPublicKey, - }); - serverPublicKey = res.serverPublicKey; - salt = res.salt; - } catch (err) { - setBackupKeyError(true); - console.log("Wrong current password", err, 1); - } - - clientPassword.setSalt(salt); - clientPassword.setServerPublicKey(serverPublicKey); - const clientProof = clientPassword.getProof(); // called M1 - - const generatedKey = crypto.randomBytes(16).toString("hex"); - - clientKey.init( - { - username: email, - password: generatedKey, - }, - async () => { - clientKey.createVerifier(async (err, result) => { - let { ciphertext, iv, tag } = Aes256Gcm.encrypt( - localStorage.getItem("PRIVATE_KEY"), - generatedKey - ); - - const res = await issueBackupPrivateKey({ - encryptedPrivateKey: ciphertext, - iv, - tag, - salt: result.salt, - verifier: result.verifier, - clientProof, - }); - - if (res.status == 400) { - setBackupKeyError(true); - } else if (res.status == 200) { - generateBackupPDF(personalName, email, generatedKey); - setBackupKeyIssued(true); - } - }); - } - ); - } - ); - } catch (error) { - setBackupKeyError(true); - console.log("Failed to issue a backup key"); - } - return true; -}; - -export default issueBackupKey; diff --git a/frontend/components/utilities/cryptography/issueBackupKey.ts b/frontend/components/utilities/cryptography/issueBackupKey.ts new file mode 100644 index 000000000..518186406 --- /dev/null +++ b/frontend/components/utilities/cryptography/issueBackupKey.ts @@ -0,0 +1,112 @@ +import issueBackupPrivateKey from '~/pages/api/auth/IssueBackupPrivateKey'; +import SRP1 from '~/pages/api/auth/SRP1'; + +import { tempLocalStorage } from '../checks/tempLocalStorage'; +import generateBackupPDF from '../generateBackupPDF'; +import Aes256Gcm from './aes-256-gcm'; + +const nacl = require('tweetnacl'); +nacl.util = require('tweetnacl-util'); +const jsrp = require('jsrp'); +const clientPassword = new jsrp.client(); +const clientKey = new jsrp.client(); +const crypto = require('crypto'); + +interface Props { + email: string; + password: string; + personalName: string; + setBackupKeyError: any; + setBackupKeyIssued: any; +} + +/** + * This function loggs in the user (whether it's right after signup, or a normal login) + * @param {*} email + * @param {*} password + * @param {*} setErrorLogin + * @param {*} router + * @param {*} isSignUp + * @returns + */ +const issueBackupKey = async ({ + email, + password, + personalName, + setBackupKeyError, + setBackupKeyIssued +}: Props) => { + try { + setBackupKeyError(false); + setBackupKeyIssued(false); + clientPassword.init( + { + username: email, + password: password + }, + async () => { + const clientPublicKey = clientPassword.getPublicKey(); + + let serverPublicKey, salt; + try { + const res = await SRP1({ + clientPublicKey: clientPublicKey + }); + serverPublicKey = res.serverPublicKey; + salt = res.salt; + } catch (err) { + setBackupKeyError(true); + console.log('Wrong current password', err, 1); + } + + clientPassword.setSalt(salt); + clientPassword.setServerPublicKey(serverPublicKey); + const clientProof = clientPassword.getProof(); // called M1 + + const generatedKey = crypto.randomBytes(16).toString('hex'); + + clientKey.init( + { + username: email, + password: generatedKey + }, + async () => { + clientKey.createVerifier( + async (_: any, result: { salt: string; verifier: string }) => { + // TODO: Fix this + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const { ciphertext, iv, tag } = Aes256Gcm.encrypt( + tempLocalStorage('PRIVATE_KEY'), + generatedKey + ); + + const res = await issueBackupPrivateKey({ + encryptedPrivateKey: ciphertext, + iv, + tag, + salt: result.salt, + verifier: result.verifier, + clientProof + }); + + if (res && res.status == 400) { + setBackupKeyError(true); + } else if (res && res.status == 200) { + generateBackupPDF(personalName, email, generatedKey); + setBackupKeyIssued(true); + } + } + ); + } + ); + } + ); + } catch (error) { + setBackupKeyError(true); + console.log('Failed to issue a backup key'); + } + return true; +}; + +export default issueBackupKey; diff --git a/frontend/components/utilities/file.js b/frontend/components/utilities/file.ts similarity index 74% rename from frontend/components/utilities/file.js rename to frontend/components/utilities/file.ts index 96d1820eb..3784405f9 100644 --- a/frontend/components/utilities/file.js +++ b/frontend/components/utilities/file.ts @@ -6,21 +6,21 @@ const LINE = * @param {Buffer} src - source buffer * @returns {String} text - text of buffer */ -function parse(src) { - const obj = {}; +function parse(src: Buffer) { + const obj: Record = {}; // Convert buffer to string let lines = src.toString(); // Convert line breaks to same format - lines = lines.replace(/\r\n?/gm, "\n"); + lines = lines.replace(/\r\n?/gm, '\n'); let match; while ((match = LINE.exec(lines)) != null) { const key = match[1]; // Default undefined or null to empty string - let value = match[2] || ""; + let value = match[2] || ''; // Remove whitespace value = value.trim(); @@ -29,12 +29,12 @@ function parse(src) { const maybeQuote = value[0]; // Remove surrounding quotes - value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2"); + value = value.replace(/^(['"`])([\s\S]*)\1$/gm, '$2'); // Expand newlines if double quoted if (maybeQuote === '"') { - value = value.replace(/\\n/g, "\n"); - value = value.replace(/\\r/g, "\r"); + value = value.replace(/\\n/g, '\n'); + value = value.replace(/\\r/g, '\r'); } // Add to object diff --git a/frontend/components/utilities/randomId.js b/frontend/components/utilities/randomId.ts similarity index 82% rename from frontend/components/utilities/randomId.js rename to frontend/components/utilities/randomId.ts index 7d1c0859b..8e1c7f972 100644 --- a/frontend/components/utilities/randomId.js +++ b/frontend/components/utilities/randomId.ts @@ -3,19 +3,19 @@ * @returns */ const guidGenerator = () => { - var S4 = function () { + const S4 = function () { return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); }; return ( S4() + S4() + - "-" + + '-' + S4() + - "-" + + '-' + S4() + - "-" + + '-' + S4() + - "-" + + '-' + S4() + S4() + S4() diff --git a/frontend/components/utilities/secrets/getSecretsForProject.js b/frontend/components/utilities/secrets/getSecretsForProject.ts similarity index 60% rename from frontend/components/utilities/secrets/getSecretsForProject.js rename to frontend/components/utilities/secrets/getSecretsForProject.ts index 7bdac922f..284b8bee1 100644 --- a/frontend/components/utilities/secrets/getSecretsForProject.js +++ b/frontend/components/utilities/secrets/getSecretsForProject.ts @@ -1,22 +1,30 @@ -import getSecrets from "~/pages/api/files/GetSecrets"; +import getSecrets from '~/pages/api/files/GetSecrets'; -import { envMapping } from "../../../public/data/frequentConstants"; -import guidGenerator from "../randomId"; +import { envMapping } from '../../../public/data/frequentConstants'; +import guidGenerator from '../randomId'; const { decryptAssymmetric, - decryptSymmetric, -} = require("../cryptography/crypto"); -const nacl = require("tweetnacl"); -nacl.util = require("tweetnacl-util"); + decryptSymmetric +} = require('../cryptography/crypto'); +const nacl = require('tweetnacl'); +nacl.util = require('tweetnacl-util'); + +interface Props { + env: keyof typeof envMapping; + setFileState: any; + setIsKeyAvailable: any; + setData: any; + workspaceId: string; +} const getSecretsForProject = async ({ env, setFileState, setIsKeyAvailable, setData, - workspaceId, -}) => { + workspaceId +}: Props) => { try { let file; try { @@ -24,44 +32,42 @@ const getSecretsForProject = async ({ setFileState(file); } catch (error) { - console.log("ERROR: Not able to access the latest file"); + console.log('ERROR: Not able to access the latest file'); } // This is called isKeyAvilable but what it really means is if a person is able to create new key pairs - setIsKeyAvailable( - !file.key ? (file.secrets.length == 0 ? true : false) : true - ); + setIsKeyAvailable(!file.key ? file.secrets.length == 0 : true); - const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); + const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY'); - let tempFileState = []; + const tempFileState: { key: string; value: string; type: string }[] = []; if (file.key) { // assymmetrically decrypt symmetric key with local private key const key = decryptAssymmetric({ ciphertext: file.key.encryptedKey, nonce: file.key.nonce, publicKey: file.key.sender.publicKey, - privateKey: PRIVATE_KEY, + privateKey: PRIVATE_KEY }); - file.secrets.map((secretPair) => { + file.secrets.map((secretPair: any) => { // decrypt .env file with symmetric key const plainTextKey = decryptSymmetric({ ciphertext: secretPair.secretKey.ciphertext, iv: secretPair.secretKey.iv, tag: secretPair.secretKey.tag, - key, + key }); const plainTextValue = decryptSymmetric({ ciphertext: secretPair.secretValue.ciphertext, iv: secretPair.secretValue.iv, tag: secretPair.secretValue.tag, - key, + key }); tempFileState.push({ key: plainTextKey, value: plainTextValue, - type: secretPair.type, + type: secretPair.type }); }); } @@ -71,9 +77,9 @@ const getSecretsForProject = async ({ tempFileState.map((line, index) => [ guidGenerator(), index, - line["key"], - line["value"], - line["type"], + line['key'], + line['value'], + line['type'] ]) // .sort((a, b) => // sortMethod == "alphabetical" @@ -84,12 +90,12 @@ const getSecretsForProject = async ({ return tempFileState.map((line, index) => [ guidGenerator(), index, - line["key"], - line["value"], - line["type"], + line['key'], + line['value'], + line['type'] ]); } catch (error) { - console.log("Something went wrong during accessing or decripting secrets."); + console.log('Something went wrong during accessing or decripting secrets.'); } return true; }; diff --git a/frontend/components/utilities/secrets/pushKeysIntegration.js b/frontend/components/utilities/secrets/pushKeysIntegration.js deleted file mode 100644 index 5b08748e7..000000000 --- a/frontend/components/utilities/secrets/pushKeysIntegration.js +++ /dev/null @@ -1,74 +0,0 @@ -import publicKeyInfical from "~/pages/api/auth/publicKeyInfisical"; -import changeHerokuConfigVars from "~/pages/api/integrations/ChangeHerokuConfigVars"; - -const crypto = require("crypto"); -const { - encryptSymmetric, - encryptAssymmetric, -} = require("../cryptography/crypto"); -const nacl = require("tweetnacl"); -nacl.util = require("tweetnacl-util"); - -const pushKeysIntegration = async ({ obj, integrationId }) => { - const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); - - let randomBytes = crypto.randomBytes(16).toString("hex"); - - const secrets = Object.keys(obj).map((key) => { - // encrypt key - const { - ciphertext: ciphertextKey, - iv: ivKey, - tag: tagKey, - } = encryptSymmetric({ - plaintext: key, - key: randomBytes, - }); - - // encrypt value - const { - ciphertext: ciphertextValue, - iv: ivValue, - tag: tagValue, - } = encryptSymmetric({ - plaintext: obj[key], - key: randomBytes, - }); - - const visibility = "shared"; - - return { - ciphertextKey, - ivKey, - tagKey, - hashKey: crypto.createHash("sha256").update(key).digest("hex"), - ciphertextValue, - ivValue, - tagValue, - hashValue: crypto.createHash("sha256").update(obj[key]).digest("hex"), - type: visibility, - }; - }); - - // obtain public keys of all receivers (i.e. members in workspace) - let publicKeyInfisical = await publicKeyInfical(); - - publicKeyInfisical = (await publicKeyInfisical.json()).publicKey; - - // assymmetrically encrypt key with each receiver public keys - - const { ciphertext, nonce } = encryptAssymmetric({ - plaintext: randomBytes, - publicKey: publicKeyInfisical, - privateKey: PRIVATE_KEY, - }); - - const key = { - encryptedKey: ciphertext, - nonce, - }; - - changeHerokuConfigVars({ integrationId, key, secrets }); -}; - -export default pushKeysIntegration; diff --git a/frontend/components/utilities/secrets/pushKeysIntegration.ts b/frontend/components/utilities/secrets/pushKeysIntegration.ts new file mode 100644 index 000000000..949778927 --- /dev/null +++ b/frontend/components/utilities/secrets/pushKeysIntegration.ts @@ -0,0 +1,79 @@ +import publicKeyInfical from '~/pages/api/auth/publicKeyInfisical'; +import changeHerokuConfigVars from '~/pages/api/integrations/ChangeHerokuConfigVars'; + +const crypto = require('crypto'); +const { + encryptSymmetric, + encryptAssymmetric +} = require('../cryptography/crypto'); +const nacl = require('tweetnacl'); +nacl.util = require('tweetnacl-util'); + +interface Props { + obj: Record; + integrationId: string; +} + +const pushKeysIntegration = async ({ obj, integrationId }: Props) => { + const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY'); + + const randomBytes = crypto.randomBytes(16).toString('hex'); + + const secrets = Object.keys(obj).map((key) => { + // encrypt key + const { + ciphertext: ciphertextKey, + iv: ivKey, + tag: tagKey + } = encryptSymmetric({ + plaintext: key, + key: randomBytes + }); + + // encrypt value + const { + ciphertext: ciphertextValue, + iv: ivValue, + tag: tagValue + } = encryptSymmetric({ + plaintext: obj[key], + key: randomBytes + }); + + const visibility = 'shared'; + + return { + ciphertextKey, + ivKey, + tagKey, + hashKey: crypto.createHash('sha256').update(key).digest('hex'), + ciphertextValue, + ivValue, + tagValue, + hashValue: crypto.createHash('sha256').update(obj[key]).digest('hex'), + type: visibility + }; + }); + + // obtain public keys of all receivers (i.e. members in workspace) + const publicKeyInfisical = await publicKeyInfical(); + + const publicKey = (await publicKeyInfisical.json()).publicKey; + + // assymmetrically encrypt key with each receiver public keys + + const { ciphertext, nonce } = encryptAssymmetric({ + plaintext: randomBytes, + publicKey, + privateKey: PRIVATE_KEY + }); + + const key = { + encryptedKey: ciphertext, + nonce + }; + + changeHerokuConfigVars({ integrationId, key, secrets }); +}; + +export default pushKeysIntegration; diff --git a/frontend/pages/api/auth/ChangePassword2.js b/frontend/pages/api/auth/ChangePassword2.ts similarity index 50% rename from frontend/pages/api/auth/ChangePassword2.js rename to frontend/pages/api/auth/ChangePassword2.ts index b764e6067..132eeddf4 100644 --- a/frontend/pages/api/auth/ChangePassword2.js +++ b/frontend/pages/api/auth/ChangePassword2.ts @@ -1,4 +1,13 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + encryptedPrivateKey: string; + iv: string; + tag: string; + salt: string; + verifier: string; + clientProof: string; +} /** * This is the second step of the change password process (pake) @@ -11,12 +20,12 @@ const changePassword2 = ({ tag, salt, verifier, - clientProof, -}) => { - return SecurityClient.fetchCall("/api/v1/password/change-password", { - method: "POST", + clientProof +}: Props) => { + return SecurityClient.fetchCall('/api/v1/password/change-password', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, body: JSON.stringify({ clientProof: clientProof, @@ -24,13 +33,13 @@ const changePassword2 = ({ iv: iv, tag: tag, salt: salt, - verifier: verifier, - }), + verifier: verifier + }) }).then(async (res) => { - if (res.status == 200) { + if (res && res.status == 200) { return res; } else { - console.log("Failed to change the password"); + console.log('Failed to change the password'); } }); }; diff --git a/frontend/pages/api/auth/CheckAuth.js b/frontend/pages/api/auth/CheckAuth.ts similarity index 50% rename from frontend/pages/api/auth/CheckAuth.js rename to frontend/pages/api/auth/CheckAuth.ts index edd373614..6d9c92c54 100644 --- a/frontend/pages/api/auth/CheckAuth.js +++ b/frontend/pages/api/auth/CheckAuth.ts @@ -1,4 +1,4 @@ -import SecurityClient from "~/utilities/SecurityClient.js"; +import SecurityClient from '~/utilities/SecurityClient.js'; /** * This function is used to check if the user is authenticated. @@ -7,17 +7,17 @@ import SecurityClient from "~/utilities/SecurityClient.js"; * @param {*} res * @returns */ -const checkAuth = async (req, res) => { - return SecurityClient.fetchCall("/api/v1/auth/checkAuth", { - method: "POST", +const checkAuth = async () => { + return SecurityClient.fetchCall('/api/v1/auth/checkAuth', { + method: 'POST', headers: { - "Content-Type": "application/json", - }, + 'Content-Type': 'application/json' + } }).then((res) => { - if (res.status == 200) { + if (res && res.status == 200) { return res; } else { - console.log("Not authorized"); + console.log('Not authorized'); } }); }; diff --git a/frontend/pages/api/auth/CheckEmailVerificationCode.js b/frontend/pages/api/auth/CheckEmailVerificationCode.ts similarity index 50% rename from frontend/pages/api/auth/CheckEmailVerificationCode.js rename to frontend/pages/api/auth/CheckEmailVerificationCode.ts index 83a64602a..08fb6b391 100644 --- a/frontend/pages/api/auth/CheckEmailVerificationCode.js +++ b/frontend/pages/api/auth/CheckEmailVerificationCode.ts @@ -1,19 +1,24 @@ +interface Props { + email: string; + code: string; +} + /** * This route check the verification code from the email that user just recieved * @param {*} email * @param {*} code * @returns */ -const checkEmailVerificationCode = (email, code) => { - return fetch("/api/v1/signup/email/verify", { - method: "POST", +const checkEmailVerificationCode = ({ email, code }: Props) => { + return fetch('/api/v1/signup/email/verify', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email, - code: code, - }), + code: code + }) }); }; diff --git a/frontend/pages/api/auth/CompleteAccountInformationSignup.js b/frontend/pages/api/auth/CompleteAccountInformationSignup.ts similarity index 64% rename from frontend/pages/api/auth/CompleteAccountInformationSignup.js rename to frontend/pages/api/auth/CompleteAccountInformationSignup.ts index 21406e381..98e78dec9 100644 --- a/frontend/pages/api/auth/CompleteAccountInformationSignup.js +++ b/frontend/pages/api/auth/CompleteAccountInformationSignup.ts @@ -1,3 +1,17 @@ +interface Props { + email: string; + firstName: string; + lastName: string; + publicKey: string; + ciphertext: string; + organizationName: string; + iv: string; + tag: string; + salt: string; + verifier: string; + token: string; +} + /** * This function is called in the end of the signup process. * It sends all the necessary nformation to the server. @@ -24,13 +38,13 @@ const completeAccountInformationSignup = ({ tag, salt, verifier, - token, -}) => { - return fetch("/api/v1/signup/complete-account/signup", { - method: "POST", + token +}: Props) => { + return fetch('/api/v1/signup/complete-account/signup', { + method: 'POST', headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + token }, body: JSON.stringify({ email, @@ -42,8 +56,8 @@ const completeAccountInformationSignup = ({ iv, tag, salt, - verifier, - }), + verifier + }) }); }; diff --git a/frontend/pages/api/auth/CompleteAccountInformationSignupInvite.js b/frontend/pages/api/auth/CompleteAccountInformationSignupInvite.ts similarity index 64% rename from frontend/pages/api/auth/CompleteAccountInformationSignupInvite.js rename to frontend/pages/api/auth/CompleteAccountInformationSignupInvite.ts index a205e6f59..1e5abdc45 100644 --- a/frontend/pages/api/auth/CompleteAccountInformationSignupInvite.js +++ b/frontend/pages/api/auth/CompleteAccountInformationSignupInvite.ts @@ -1,3 +1,16 @@ +interface Props { + email: string; + firstName: string; + lastName: string; + publicKey: string; + ciphertext: string; + iv: string; + tag: string; + salt: string; + verifier: string; + token: string; +} + /** * This function is called in the end of the signup process. * It sends all the necessary nformation to the server. @@ -22,13 +35,13 @@ const completeAccountInformationSignupInvite = ({ tag, salt, verifier, - token, -}) => { - return fetch("/api/v1/signup/complete-account/invite", { - method: "POST", + token +}: Props) => { + return fetch('/api/v1/signup/complete-account/invite', { + method: 'POST', headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + token }, body: JSON.stringify({ email: email, @@ -39,8 +52,8 @@ const completeAccountInformationSignupInvite = ({ iv: iv, tag: tag, salt: salt, - verifier: verifier, - }), + verifier: verifier + }) }); }; diff --git a/frontend/pages/api/auth/IssueBackupPrivateKey.js b/frontend/pages/api/auth/IssueBackupPrivateKey.js deleted file mode 100644 index 9a31f7b00..000000000 --- a/frontend/pages/api/auth/IssueBackupPrivateKey.js +++ /dev/null @@ -1,40 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This is the route that issues a backup private key that will afterwards be added into a pdf - */ -const issueBackupPrivateKey = ({ - encryptedPrivateKey, - iv, - tag, - salt, - verifier, - clientProof, -}) => { - return SecurityClient.fetchCall( - "/api/v1/password/backup-private-key", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - clientProof: clientProof, - encryptedPrivateKey: encryptedPrivateKey, - iv: iv, - tag: tag, - salt: salt, - verifier: verifier, - }), - } - ).then((res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to issue the backup key"); - return res; - } - }); -}; - -export default issueBackupPrivateKey; diff --git a/frontend/pages/api/auth/IssueBackupPrivateKey.ts b/frontend/pages/api/auth/IssueBackupPrivateKey.ts new file mode 100644 index 000000000..9b300f55b --- /dev/null +++ b/frontend/pages/api/auth/IssueBackupPrivateKey.ts @@ -0,0 +1,44 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + encryptedPrivateKey: string; + iv: string; + tag: string; + salt: string; + verifier: string; + clientProof: string; +} + +/** + * This is the route that issues a backup private key that will afterwards be added into a pdf + */ +const issueBackupPrivateKey = ({ + encryptedPrivateKey, + iv, + tag, + salt, + verifier, + clientProof +}: Props) => { + return SecurityClient.fetchCall('/api/v1/password/backup-private-key', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + clientProof: clientProof, + encryptedPrivateKey: encryptedPrivateKey, + iv: iv, + tag: tag, + salt: salt, + verifier: verifier + }) + }).then((res) => { + if (res?.status !== 200) { + console.log('Failed to issue the backup key'); + } + return res; + }); +}; + +export default issueBackupPrivateKey; diff --git a/frontend/pages/api/auth/SRP1.js b/frontend/pages/api/auth/SRP1.js deleted file mode 100644 index b0fefb857..000000000 --- a/frontend/pages/api/auth/SRP1.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This is the first step of the change password process (pake) - * @param {*} clientPublicKey - * @returns - */ -const SRP1 = ({ clientPublicKey }) => { - return SecurityClient.fetchCall("/api/v1/password/srp1", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - clientPublicKey, - }), - }).then(async (res) => { - if (res.status == 200) { - return await res.json(); - } else { - console.log("Failed to do the first step of SRP"); - } - }); -}; - -export default SRP1; diff --git a/frontend/pages/api/auth/SRP1.ts b/frontend/pages/api/auth/SRP1.ts new file mode 100644 index 000000000..292dcbdd1 --- /dev/null +++ b/frontend/pages/api/auth/SRP1.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + clientPublicKey: string; +} + +/** + * This is the first step of the change password process (pake) + * @param {*} clientPublicKey + * @returns + */ +const SRP1 = ({ clientPublicKey }: Props) => { + return SecurityClient.fetchCall('/api/v1/password/srp1', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + clientPublicKey + }) + }).then(async (res) => { + if (res && res.status == 200) { + return await res.json(); + } else { + console.log('Failed to do the first step of SRP'); + } + }); +}; + +export default SRP1; diff --git a/frontend/pages/api/auth/SendVerificationEmail.js b/frontend/pages/api/auth/SendVerificationEmail.ts similarity index 55% rename from frontend/pages/api/auth/SendVerificationEmail.js rename to frontend/pages/api/auth/SendVerificationEmail.ts index ae952852d..4f3b063c6 100644 --- a/frontend/pages/api/auth/SendVerificationEmail.js +++ b/frontend/pages/api/auth/SendVerificationEmail.ts @@ -2,15 +2,15 @@ * This route send the verification email to the user's email (contains a 6-digit verification code) * @param {*} email */ -const sendVerificationEmail = (email) => { - fetch("/api/v1/signup/email/signup", { - method: "POST", +const sendVerificationEmail = (email: string) => { + fetch('/api/v1/signup/email/signup', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, body: JSON.stringify({ - email: email, - }), + email: email + }) }); }; diff --git a/frontend/pages/api/auth/Token.js b/frontend/pages/api/auth/Token.js deleted file mode 100644 index c3e5fd958..000000000 --- a/frontend/pages/api/auth/Token.js +++ /dev/null @@ -1,17 +0,0 @@ -const token = async (req, res) => { - return fetch("/api/v1/auth/token", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - credentials: "include", - }).then(async (res) => { - if (res.status == 200) { - return (await res.json()).token; - } else { - console.log("Getting a new token failed"); - } - }); -}; - -export default token; diff --git a/frontend/pages/api/auth/Token.ts b/frontend/pages/api/auth/Token.ts new file mode 100644 index 000000000..ed347ba4b --- /dev/null +++ b/frontend/pages/api/auth/Token.ts @@ -0,0 +1,17 @@ +const token = async () => { + return fetch('/api/v1/auth/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + credentials: 'include' + }).then(async (res) => { + if (res.status == 200) { + return (await res.json()).token; + } else { + console.log('Getting a new token failed'); + } + }); +}; + +export default token; diff --git a/frontend/pages/api/auth/VerifySignupInvite.js b/frontend/pages/api/auth/VerifySignupInvite.js deleted file mode 100644 index 2a9ba4dcd..000000000 --- a/frontend/pages/api/auth/VerifySignupInvite.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * This route verifies the signup invite link - * @param {*} email - * @param {*} code - * @returns - */ -const verifySignupInvite = ({ email, code }) => { - return fetch("/api/v1/invite-org/verify", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email, - code, - }), - }); -}; - -export default verifySignupInvite; diff --git a/frontend/pages/api/auth/VerifySignupInvite.ts b/frontend/pages/api/auth/VerifySignupInvite.ts new file mode 100644 index 000000000..20e52dfd1 --- /dev/null +++ b/frontend/pages/api/auth/VerifySignupInvite.ts @@ -0,0 +1,25 @@ +interface Props { + email: string; + code: string; +} + +/** + * This route verifies the signup invite link + * @param {*} email + * @param {*} code + * @returns + */ +const verifySignupInvite = ({ email, code }: Props) => { + return fetch('/api/v1/invite-org/verify', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email, + code + }) + }); +}; + +export default verifySignupInvite; diff --git a/frontend/pages/api/auth/publicKeyInfisical.js b/frontend/pages/api/auth/publicKeyInfisical.js deleted file mode 100644 index 76cad1726..000000000 --- a/frontend/pages/api/auth/publicKeyInfisical.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * This route lets us get the public key of infisical. Th euser doesn't have to be authenticated since this is just the public key. - * @param {*} req - * @param {*} res - * @returns - */ -const publicKeyInfisical = (req, res) => { - return fetch("/api/v1/key/publicKey/infisical", { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }); -}; - -export default publicKeyInfisical; diff --git a/frontend/pages/api/auth/publicKeyInfisical.ts b/frontend/pages/api/auth/publicKeyInfisical.ts new file mode 100644 index 000000000..d3e0f646c --- /dev/null +++ b/frontend/pages/api/auth/publicKeyInfisical.ts @@ -0,0 +1,10 @@ +const publicKeyInfisical = () => { + return fetch('/api/v1/key/publicKey/infisical', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }); +}; + +export default publicKeyInfisical; diff --git a/frontend/pages/api/files/GetSecrets.js b/frontend/pages/api/files/GetSecrets.ts similarity index 53% rename from frontend/pages/api/files/GetSecrets.js rename to frontend/pages/api/files/GetSecrets.ts index fa91d0962..4e33e19f2 100644 --- a/frontend/pages/api/files/GetSecrets.js +++ b/frontend/pages/api/files/GetSecrets.ts @@ -1,4 +1,4 @@ -import SecurityClient from "~/utilities/SecurityClient.js"; +import SecurityClient from '~/utilities/SecurityClient.js'; /** * This function fetches the encrypted secrets from the .env file @@ -6,26 +6,26 @@ import SecurityClient from "~/utilities/SecurityClient.js"; * @param {*} env * @returns */ -const getSecrets = async (workspaceId, env) => { +const getSecrets = async (workspaceId: string, env: string) => { return SecurityClient.fetchCall( - "/api/v1/secret/" + + '/api/v1/secret/' + workspaceId + - "?" + + '?' + new URLSearchParams({ environment: env, - channel: "web", + channel: 'web' }), { - method: "GET", + method: 'GET', headers: { - "Content-Type": "application/json", - }, + 'Content-Type': 'application/json' + } } ).then(async (res) => { - if (res.status == 200) { + if (res && res.status == 200) { return await res.json(); } else { - console.log("Failed to get project secrets"); + console.log('Failed to get project secrets'); } }); }; diff --git a/frontend/pages/api/files/UploadSecrets.js b/frontend/pages/api/files/UploadSecrets.js deleted file mode 100644 index c2f94e64d..000000000 --- a/frontend/pages/api/files/UploadSecrets.js +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This function uploads the encrypted .env file - * @param {*} req - * @param {*} res - * @returns - */ -const uploadSecrets = async ({ workspaceId, secrets, keys, environment }) => { - return SecurityClient.fetchCall("/api/v1/secret/" + workspaceId, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - secrets, - keys, - environment, - channel: "web", - }), - }).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to push secrets"); - } - }); -}; - -export default uploadSecrets; diff --git a/frontend/pages/api/files/UploadSecrets.ts b/frontend/pages/api/files/UploadSecrets.ts new file mode 100644 index 000000000..53b87d62f --- /dev/null +++ b/frontend/pages/api/files/UploadSecrets.ts @@ -0,0 +1,42 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + workspaceId: string; + secrets: string; + keys: string; + environment: string; +} + +/** + * This function uploads the encrypted .env file + * @param {*} req + * @param {*} res + * @returns + */ +const uploadSecrets = async ({ + workspaceId, + secrets, + keys, + environment +}: Props) => { + return SecurityClient.fetchCall('/api/v1/secret/' + workspaceId, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + secrets, + keys, + environment, + channel: 'web' + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to push secrets'); + } + }); +}; + +export default uploadSecrets; diff --git a/frontend/pages/api/integrations/ChangeHerokuConfigVars.js b/frontend/pages/api/integrations/ChangeHerokuConfigVars.js deleted file mode 100644 index 118848ae6..000000000 --- a/frontend/pages/api/integrations/ChangeHerokuConfigVars.js +++ /dev/null @@ -1,25 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -const changeHerokuConfigVars = ({ integrationId, key, secrets }) => { - return SecurityClient.fetchCall( - "/api/v1/integration/" + integrationId + "/sync", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - key, - secrets, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to sync secrets to Heroku"); - } - }); -}; - -export default changeHerokuConfigVars; diff --git a/frontend/pages/api/integrations/ChangeHerokuConfigVars.ts b/frontend/pages/api/integrations/ChangeHerokuConfigVars.ts new file mode 100644 index 000000000..854e614e0 --- /dev/null +++ b/frontend/pages/api/integrations/ChangeHerokuConfigVars.ts @@ -0,0 +1,31 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + integrationId: string; + key: string; + secrets: string; +} + +const changeHerokuConfigVars = ({ integrationId, key, secrets }: Props) => { + return SecurityClient.fetchCall( + '/api/v1/integration/' + integrationId + '/sync', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + key, + secrets + }) + } + ).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to sync secrets to Heroku'); + } + }); +}; + +export default changeHerokuConfigVars; diff --git a/frontend/pages/api/integrations/DeleteIntegration.js b/frontend/pages/api/integrations/DeleteIntegration.js deleted file mode 100644 index 7698d7eae..000000000 --- a/frontend/pages/api/integrations/DeleteIntegration.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route deletes an integration from a certain project - * @param {*} integrationId - * @returns - */ -const deleteIntegration = ({ integrationId }) => { - return SecurityClient.fetchCall( - "/api/v1/integration/" + integrationId, - { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).workspace; - } else { - console.log("Failed to delete an integration"); - } - }); -}; - -export default deleteIntegration; diff --git a/frontend/pages/api/integrations/DeleteIntegration.ts b/frontend/pages/api/integrations/DeleteIntegration.ts new file mode 100644 index 000000000..89aa0ab0c --- /dev/null +++ b/frontend/pages/api/integrations/DeleteIntegration.ts @@ -0,0 +1,27 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + integrationId: string; +} + +/** + * This route deletes an integration from a certain project + * @param {*} integrationId + * @returns + */ +const deleteIntegration = ({ integrationId }: Props) => { + return SecurityClient.fetchCall('/api/v1/integration/' + integrationId, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).workspace; + } else { + console.log('Failed to delete an integration'); + } + }); +}; + +export default deleteIntegration; diff --git a/frontend/pages/api/integrations/DeleteIntegrationAuth.js b/frontend/pages/api/integrations/DeleteIntegrationAuth.js deleted file mode 100644 index eb6106e8e..000000000 --- a/frontend/pages/api/integrations/DeleteIntegrationAuth.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route deletes an integration authorization from a certain project - * @param {*} integrationAuthId - * @returns - */ -const deleteIntegrationAuth = ({ integrationAuthId }) => { - return SecurityClient.fetchCall( - "/api/v1/integration-auth/" + integrationAuthId, - { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to delete an integration authorization"); - } - }); -}; - -export default deleteIntegrationAuth; diff --git a/frontend/pages/api/integrations/DeleteIntegrationAuth.ts b/frontend/pages/api/integrations/DeleteIntegrationAuth.ts new file mode 100644 index 000000000..3a2da2cbf --- /dev/null +++ b/frontend/pages/api/integrations/DeleteIntegrationAuth.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + integrationAuthId: string; +} + +/** + * This route deletes an integration authorization from a certain project + * @param {*} integrationAuthId + * @returns + */ +const deleteIntegrationAuth = ({ integrationAuthId }: Props) => { + return SecurityClient.fetchCall( + '/api/v1/integration-auth/' + integrationAuthId, + { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to delete an integration authorization'); + } + }); +}; + +export default deleteIntegrationAuth; diff --git a/frontend/pages/api/integrations/GetIntegrationApps.js b/frontend/pages/api/integrations/GetIntegrationApps.js deleted file mode 100644 index dc0bfb4b6..000000000 --- a/frontend/pages/api/integrations/GetIntegrationApps.js +++ /dev/null @@ -1,21 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -const getIntegrationApps = ({ integrationAuthId }) => { - return SecurityClient.fetchCall( - "/api/v1/integration-auth/" + integrationAuthId + "/apps", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).apps; - } else { - console.log("Failed to get available apps for an integration"); - } - }); -}; - -export default getIntegrationApps; diff --git a/frontend/pages/api/integrations/GetIntegrationApps.ts b/frontend/pages/api/integrations/GetIntegrationApps.ts new file mode 100644 index 000000000..5597c24b1 --- /dev/null +++ b/frontend/pages/api/integrations/GetIntegrationApps.ts @@ -0,0 +1,25 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + integrationAuthId: string; +} + +const getIntegrationApps = ({ integrationAuthId }: Props) => { + return SecurityClient.fetchCall( + '/api/v1/integration-auth/' + integrationAuthId + '/apps', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).apps; + } else { + console.log('Failed to get available apps for an integration'); + } + }); +}; + +export default getIntegrationApps; diff --git a/frontend/pages/api/integrations/GetIntegrations.js b/frontend/pages/api/integrations/GetIntegrations.js deleted file mode 100644 index 401c80d3b..000000000 --- a/frontend/pages/api/integrations/GetIntegrations.js +++ /dev/null @@ -1,18 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -const getIntegrations = () => { - return SecurityClient.fetchCall("/api/v1/integration/integrations", { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }).then(async (res) => { - if (res.status == 200) { - return (await res.json()).integrations; - } else { - console.log("Failed to get project integrations"); - } - }); -}; - -export default getIntegrations; diff --git a/frontend/pages/api/integrations/GetIntegrations.ts b/frontend/pages/api/integrations/GetIntegrations.ts new file mode 100644 index 000000000..c189010a4 --- /dev/null +++ b/frontend/pages/api/integrations/GetIntegrations.ts @@ -0,0 +1,18 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +const getIntegrations = () => { + return SecurityClient.fetchCall('/api/v1/integration/integrations', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).integrations; + } else { + console.log('Failed to get project integrations'); + } + }); +}; + +export default getIntegrations; diff --git a/frontend/pages/api/integrations/StartIntegration.js b/frontend/pages/api/integrations/StartIntegration.js deleted file mode 100644 index a4e8b0b02..000000000 --- a/frontend/pages/api/integrations/StartIntegration.js +++ /dev/null @@ -1,33 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route starts the integration after teh default one if gonna set up. - * @param {*} integrationId - * @returns - */ -const startIntegration = ({ integrationId, appName, environment }) => { - return SecurityClient.fetchCall( - "/api/v1/integration/" + integrationId, - { - method: "PATCH", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - update: { - app: appName, - environment, - isActive: true, - }, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to start an integration"); - } - }); -}; - -export default startIntegration; diff --git a/frontend/pages/api/integrations/StartIntegration.ts b/frontend/pages/api/integrations/StartIntegration.ts new file mode 100644 index 000000000..bef82e7e1 --- /dev/null +++ b/frontend/pages/api/integrations/StartIntegration.ts @@ -0,0 +1,36 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + integrationId: string; + appName: string; + environment: string; +} + +/** + * This route starts the integration after teh default one if gonna set up. + * @param {*} integrationId + * @returns + */ +const startIntegration = ({ integrationId, appName, environment }: Props) => { + return SecurityClient.fetchCall('/api/v1/integration/' + integrationId, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + update: { + app: appName, + environment, + isActive: true + } + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to start an integration'); + } + }); +}; + +export default startIntegration; diff --git a/frontend/pages/api/integrations/authorizeIntegration.js b/frontend/pages/api/integrations/authorizeIntegration.js deleted file mode 100644 index b9a1d3995..000000000 --- a/frontend/pages/api/integrations/authorizeIntegration.js +++ /dev/null @@ -1,31 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This is the first step of the change password process (pake) - * @param {*} clientPublicKey - * @returns - */ -const AuthorizeIntegration = ({ workspaceId, code, integration }) => { - return SecurityClient.fetchCall( - "/api/v1/integration-auth/oauth-token", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - workspaceId, - code, - integration, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to authorize the integration"); - } - }); -}; - -export default AuthorizeIntegration; diff --git a/frontend/pages/api/integrations/authorizeIntegration.ts b/frontend/pages/api/integrations/authorizeIntegration.ts new file mode 100644 index 000000000..83158f594 --- /dev/null +++ b/frontend/pages/api/integrations/authorizeIntegration.ts @@ -0,0 +1,33 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + workspaceId: string; + code: string; + integration: string; +} +/** + * This is the first step of the change password process (pake) + * @param {*} clientPublicKey + * @returns + */ +const AuthorizeIntegration = ({ workspaceId, code, integration }: Props) => { + return SecurityClient.fetchCall('/api/v1/integration-auth/oauth-token', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + workspaceId, + code, + integration + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to authorize the integration'); + } + }); +}; + +export default AuthorizeIntegration; diff --git a/frontend/pages/api/integrations/getWorkspaceAuthorizations.js b/frontend/pages/api/integrations/getWorkspaceAuthorizations.js deleted file mode 100644 index ad8c4732b..000000000 --- a/frontend/pages/api/integrations/getWorkspaceAuthorizations.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route gets authorizations of a certain project (Heroku, etc.) - * @param {*} workspaceId - * @returns - */ -const getWorkspaceAuthorizations = ({ workspaceId }) => { - return SecurityClient.fetchCall( - "/api/v1/workspace/" + workspaceId + "/authorizations", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).authorizations; - } else { - console.log("Failed to get project authorizations"); - } - }); -}; - -export default getWorkspaceAuthorizations; diff --git a/frontend/pages/api/integrations/getWorkspaceAuthorizations.ts b/frontend/pages/api/integrations/getWorkspaceAuthorizations.ts new file mode 100644 index 000000000..f1b406555 --- /dev/null +++ b/frontend/pages/api/integrations/getWorkspaceAuthorizations.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + workspaceId: string; +} + +/** + * This route gets authorizations of a certain project (Heroku, etc.) + * @param {*} workspaceId + * @returns + */ +const getWorkspaceAuthorizations = ({ workspaceId }: Props) => { + return SecurityClient.fetchCall( + '/api/v1/workspace/' + workspaceId + '/authorizations', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).authorizations; + } else { + console.log('Failed to get project authorizations'); + } + }); +}; + +export default getWorkspaceAuthorizations; diff --git a/frontend/pages/api/integrations/getWorkspaceIntegrations.js b/frontend/pages/api/integrations/getWorkspaceIntegrations.js deleted file mode 100644 index 22470e4be..000000000 --- a/frontend/pages/api/integrations/getWorkspaceIntegrations.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route gets integrations of a certain project (Heroku, etc.) - * @param {*} workspaceId - * @returns - */ -const getWorkspaceIntegrations = ({ workspaceId }) => { - return SecurityClient.fetchCall( - "/api/v1/workspace/" + workspaceId + "/integrations", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).integrations; - } else { - console.log("Failed to get the project integrations"); - } - }); -}; - -export default getWorkspaceIntegrations; diff --git a/frontend/pages/api/integrations/getWorkspaceIntegrations.ts b/frontend/pages/api/integrations/getWorkspaceIntegrations.ts new file mode 100644 index 000000000..a33256749 --- /dev/null +++ b/frontend/pages/api/integrations/getWorkspaceIntegrations.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + workspaceId: string; +} + +/** + * This route gets integrations of a certain project (Heroku, etc.) + * @param {*} workspaceId + * @returns + */ +const getWorkspaceIntegrations = ({ workspaceId }: Props) => { + return SecurityClient.fetchCall( + '/api/v1/workspace/' + workspaceId + '/integrations', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).integrations; + } else { + console.log('Failed to get the project integrations'); + } + }); +}; + +export default getWorkspaceIntegrations; diff --git a/frontend/pages/api/organization/GetOrgProjects.js b/frontend/pages/api/organization/GetOrgProjects.js deleted file mode 100644 index 656fea18f..000000000 --- a/frontend/pages/api/organization/GetOrgProjects.js +++ /dev/null @@ -1,27 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route lets us get all the users in an org. - * @param {*} req - * @param {*} res - * @returns - */ -const getOrganizationProjects = (req, res) => { - return SecurityClient.fetchCall( - "/api/organization/" + req.orgId + "/workspaces", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).workspaces; - } else { - console.log("Failed to get projects for an org"); - } - }); -}; - -export default getOrganizationProjects; diff --git a/frontend/pages/api/organization/GetOrgProjects.ts b/frontend/pages/api/organization/GetOrgProjects.ts new file mode 100644 index 000000000..954694486 --- /dev/null +++ b/frontend/pages/api/organization/GetOrgProjects.ts @@ -0,0 +1,29 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route lets us get all the users in an org. + * @param {*} req + * @param {*} res + * @returns + */ + +// TODO: this file is not used anywhere +const getOrganizationProjects = (req: { orgId: string }) => { + return SecurityClient.fetchCall( + '/api/organization/' + req.orgId + '/workspaces', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).workspaces; + } else { + console.log('Failed to get projects for an org'); + } + }); +}; + +export default getOrganizationProjects; diff --git a/frontend/pages/api/organization/GetOrgSubscription.js b/frontend/pages/api/organization/GetOrgSubscription.js deleted file mode 100644 index 97c6f4e5c..000000000 --- a/frontend/pages/api/organization/GetOrgSubscription.js +++ /dev/null @@ -1,27 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route lets us get the current subscription of an org. - * @param {*} req - * @param {*} res - * @returns - */ -const getOrganizationSubscriptions = (req, res) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + req.orgId + "/subscriptions", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).subscriptions; - } else { - console.log("Failed to get org subscriptions"); - } - }); -}; - -export default getOrganizationSubscriptions; diff --git a/frontend/pages/api/organization/GetOrgSubscription.ts b/frontend/pages/api/organization/GetOrgSubscription.ts new file mode 100644 index 000000000..c93679cdc --- /dev/null +++ b/frontend/pages/api/organization/GetOrgSubscription.ts @@ -0,0 +1,27 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route lets us get the current subscription of an org. + * @param {*} req + * @param {*} res + * @returns + */ +const getOrganizationSubscriptions = (req: { orgId: string }) => { + return SecurityClient.fetchCall( + '/api/v1/organization/' + req.orgId + '/subscriptions', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).subscriptions; + } else { + console.log('Failed to get org subscriptions'); + } + }); +}; + +export default getOrganizationSubscriptions; diff --git a/frontend/pages/api/organization/GetOrgUserProjects.js b/frontend/pages/api/organization/GetOrgUserProjects.js deleted file mode 100644 index c2d751f64..000000000 --- a/frontend/pages/api/organization/GetOrgUserProjects.js +++ /dev/null @@ -1,27 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route lets us get all the projects of a certain user in an org. - * @param {*} req - * @param {*} res - * @returns - */ -const getOrganizationUserProjects = (req) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + req.orgId + "/my-workspaces", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).workspaces; - } else { - console.log("Failed to get projects of a user in an org"); - } - }); -}; - -export default getOrganizationUserProjects; diff --git a/frontend/pages/api/organization/GetOrgUserProjects.ts b/frontend/pages/api/organization/GetOrgUserProjects.ts new file mode 100644 index 000000000..872b8d781 --- /dev/null +++ b/frontend/pages/api/organization/GetOrgUserProjects.ts @@ -0,0 +1,27 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route lets us get all the projects of a certain user in an org. + * @param {*} req + * @param {*} res + * @returns + */ +const getOrganizationUserProjects = (req: { orgId: string }) => { + return SecurityClient.fetchCall( + '/api/v1/organization/' + req.orgId + '/my-workspaces', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).workspaces; + } else { + console.log('Failed to get projects of a user in an org'); + } + }); +}; + +export default getOrganizationUserProjects; diff --git a/frontend/pages/api/organization/StripeRedirect.js b/frontend/pages/api/organization/StripeRedirect.js deleted file mode 100644 index e8911cf53..000000000 --- a/frontend/pages/api/organization/StripeRedirect.js +++ /dev/null @@ -1,27 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route redirects the user to the right stripe billing page. - * @param {*} req - * @param {*} res - * @returns - */ -const StripeRedirect = ({ orgId }) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + orgId + "/customer-portal-session", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (window.location.href = (await res.json()).url); - } else { - console.log("Failed to redirect to Stripe"); - } - }); -}; - -export default StripeRedirect; diff --git a/frontend/pages/api/organization/StripeRedirect.ts b/frontend/pages/api/organization/StripeRedirect.ts new file mode 100644 index 000000000..a9fe1f066 --- /dev/null +++ b/frontend/pages/api/organization/StripeRedirect.ts @@ -0,0 +1,27 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route redirects the user to the right stripe billing page. + * @param {*} req + * @param {*} res + * @returns + */ +const StripeRedirect = ({ orgId }: { orgId: string }) => { + return SecurityClient.fetchCall( + '/api/v1/organization/' + orgId + '/customer-portal-session', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (window.location.href = (await res.json()).url); + } else { + console.log('Failed to redirect to Stripe'); + } + }); +}; + +export default StripeRedirect; diff --git a/frontend/pages/api/organization/addIncidentContact.js b/frontend/pages/api/organization/addIncidentContact.js deleted file mode 100644 index 0e6068a1a..000000000 --- a/frontend/pages/api/organization/addIncidentContact.js +++ /dev/null @@ -1,29 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route add an incident contact email to a certain organization - * @param {*} param0 - * @returns - */ -const addIncidentContact = (organizationId, email) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + organizationId + "/incidentContactOrg", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: email, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to add an incident contact"); - } - }); -}; - -export default addIncidentContact; diff --git a/frontend/pages/api/organization/addIncidentContact.ts b/frontend/pages/api/organization/addIncidentContact.ts new file mode 100644 index 000000000..d3676e641 --- /dev/null +++ b/frontend/pages/api/organization/addIncidentContact.ts @@ -0,0 +1,29 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route add an incident contact email to a certain organization + * @param {*} param0 + * @returns + */ +const addIncidentContact = (organizationId: string, email: string) => { + return SecurityClient.fetchCall( + '/api/v1/organization/' + organizationId + '/incidentContactOrg', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email: email + }) + } + ).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to add an incident contact'); + } + }); +}; + +export default addIncidentContact; diff --git a/frontend/pages/api/organization/addUserToOrg.js b/frontend/pages/api/organization/addUserToOrg.js deleted file mode 100644 index 15f22cff9..000000000 --- a/frontend/pages/api/organization/addUserToOrg.js +++ /dev/null @@ -1,28 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This function sends an email invite to a user to join an org - * @param {*} email - * @param {*} orgId - * @returns - */ -const addUserToOrg = (email, orgId) => { - return SecurityClient.fetchCall("/api/v1/invite-org/signup", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - inviteeEmail: email, - organizationId: orgId, - }), - }).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to add a user to an org"); - } - }); -}; - -export default addUserToOrg; diff --git a/frontend/pages/api/organization/addUserToOrg.ts b/frontend/pages/api/organization/addUserToOrg.ts new file mode 100644 index 000000000..70dbad56c --- /dev/null +++ b/frontend/pages/api/organization/addUserToOrg.ts @@ -0,0 +1,28 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This function sends an email invite to a user to join an org + * @param {*} email + * @param {*} orgId + * @returns + */ +const addUserToOrg = (email: string, orgId: string) => { + return SecurityClient.fetchCall('/api/v1/invite-org/signup', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + inviteeEmail: email, + organizationId: orgId + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to add a user to an org'); + } + }); +}; + +export default addUserToOrg; diff --git a/frontend/pages/api/organization/deleteIncidentContact.js b/frontend/pages/api/organization/deleteIncidentContact.js deleted file mode 100644 index f6e57c590..000000000 --- a/frontend/pages/api/organization/deleteIncidentContact.js +++ /dev/null @@ -1,29 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route deletes an incident Contact from a certain organization - * @param {*} param0 - * @returns - */ -const deleteIncidentContact = (organizaionId, email) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + organizaionId + "/incidentContactOrg", - { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: email, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to delete an incident contact"); - } - }); -}; - -export default deleteIncidentContact; diff --git a/frontend/pages/api/organization/deleteIncidentContact.ts b/frontend/pages/api/organization/deleteIncidentContact.ts new file mode 100644 index 000000000..fd6374e9b --- /dev/null +++ b/frontend/pages/api/organization/deleteIncidentContact.ts @@ -0,0 +1,29 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route deletes an incident Contact from a certain organization + * @param {*} param0 + * @returns + */ +const deleteIncidentContact = (organizationId: string, email: string) => { + return SecurityClient.fetchCall( + '/api/v1/organization/' + organizationId + '/incidentContactOrg', + { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email: email + }) + } + ).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to delete an incident contact'); + } + }); +}; + +export default deleteIncidentContact; diff --git a/frontend/pages/api/organization/deleteUserFromOrganization.js b/frontend/pages/api/organization/deleteUserFromOrganization.js deleted file mode 100644 index 66ea84793..000000000 --- a/frontend/pages/api/organization/deleteUserFromOrganization.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This function removes a certain member from a certain organization - * @param {*} membershipId - * @returns - */ -const deleteUserFromOrganization = (membershipId) => { - return SecurityClient.fetchCall( - "/api/v1/membership-org/" + membershipId, - { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to delete a user from an org"); - } - }); -}; - -export default deleteUserFromOrganization; diff --git a/frontend/pages/api/organization/deleteUserFromOrganization.ts b/frontend/pages/api/organization/deleteUserFromOrganization.ts new file mode 100644 index 000000000..988a09485 --- /dev/null +++ b/frontend/pages/api/organization/deleteUserFromOrganization.ts @@ -0,0 +1,23 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This function removes a certain member from a certain organization + * @param {*} membershipId + * @returns + */ +const deleteUserFromOrganization = (membershipId: string) => { + return SecurityClient.fetchCall('/api/v1/membership-org/' + membershipId, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to delete a user from an org'); + } + }); +}; + +export default deleteUserFromOrganization; diff --git a/frontend/pages/api/organization/getIncidentContacts.js b/frontend/pages/api/organization/getIncidentContacts.js deleted file mode 100644 index 4f3f61a48..000000000 --- a/frontend/pages/api/organization/getIncidentContacts.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This routes gets all the incident contacts of a certain organization - * @param {*} workspaceId - * @returns - */ -const getIncidentContacts = (organizationId) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + organizationId + "/incidentContactOrg", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).incidentContactsOrg; - } else { - console.log("Failed to get incident contacts"); - } - }); -}; - -export default getIncidentContacts; diff --git a/frontend/pages/api/organization/getIncidentContacts.ts b/frontend/pages/api/organization/getIncidentContacts.ts new file mode 100644 index 000000000..bb9c3613a --- /dev/null +++ b/frontend/pages/api/organization/getIncidentContacts.ts @@ -0,0 +1,26 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This routes gets all the incident contacts of a certain organization + * @param {*} workspaceId + * @returns + */ +const getIncidentContacts = (organizationId: string) => { + return SecurityClient.fetchCall( + '/api/v1/organization/' + organizationId + '/incidentContactOrg', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).incidentContactsOrg; + } else { + console.log('Failed to get incident contacts'); + } + }); +}; + +export default getIncidentContacts; diff --git a/frontend/pages/api/organization/renameOrg.js b/frontend/pages/api/organization/renameOrg.js deleted file mode 100644 index a9d80a3a5..000000000 --- a/frontend/pages/api/organization/renameOrg.js +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route lets us rename a certain org. - * @param {*} req - * @param {*} res - * @returns - */ -const renameOrg = (orgId, newOrgName) => { - return SecurityClient.fetchCall( - "/api/v1/organization/" + orgId + "/name", - { - method: "PATCH", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - name: newOrgName, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to rename an organization"); - } - }); -}; - -export default renameOrg; diff --git a/frontend/pages/api/organization/renameOrg.ts b/frontend/pages/api/organization/renameOrg.ts new file mode 100644 index 000000000..c5c0b4d65 --- /dev/null +++ b/frontend/pages/api/organization/renameOrg.ts @@ -0,0 +1,27 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route lets us rename a certain org. + * @param {*} req + * @param {*} res + * @returns + */ +const renameOrg = (orgId: string, newOrgName: string) => { + return SecurityClient.fetchCall('/api/v1/organization/' + orgId + '/name', { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + name: newOrgName + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to rename an organization'); + } + }); +}; + +export default renameOrg; diff --git a/frontend/pages/api/serviceToken/addServiceToken.js b/frontend/pages/api/serviceToken/addServiceToken.ts similarity index 51% rename from frontend/pages/api/serviceToken/addServiceToken.js rename to frontend/pages/api/serviceToken/addServiceToken.ts index 4c6031db8..5dad69f69 100644 --- a/frontend/pages/api/serviceToken/addServiceToken.js +++ b/frontend/pages/api/serviceToken/addServiceToken.ts @@ -1,4 +1,14 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; + +interface Props { + name: string; + workspaceId: string; + environment: string; + expiresIn: number; + publicKey: string; + encryptedKey: string; + nonce: string; +} /** * This route gets service tokens for a specific user in a project @@ -12,12 +22,12 @@ const addServiceToken = ({ expiresIn, publicKey, encryptedKey, - nonce, -}) => { - return SecurityClient.fetchCall("/api/v1/service-token/", { - method: "POST", + nonce +}: Props) => { + return SecurityClient.fetchCall('/api/v1/service-token/', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, body: JSON.stringify({ name, @@ -26,13 +36,13 @@ const addServiceToken = ({ expiresIn, publicKey, encryptedKey, - nonce, - }), + nonce + }) }).then(async (res) => { - if (res.status == 200) { + if (res && res.status == 200) { return (await res.json()).token; } else { - console.log("Failed to add service tokens"); + console.log('Failed to add service tokens'); } }); }; diff --git a/frontend/pages/api/serviceToken/getServiceTokens.js b/frontend/pages/api/serviceToken/getServiceTokens.js deleted file mode 100644 index 79c6a7fc0..000000000 --- a/frontend/pages/api/serviceToken/getServiceTokens.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route gets service tokens for a specific user in a project - * @param {*} param0 - * @returns - */ -const getServiceTokens = ({ workspaceId }) => { - return SecurityClient.fetchCall( - "/api/v1/workspace/" + workspaceId + "/service-tokens", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res.status == 200) { - return (await res.json()).serviceTokens; - } else { - console.log("Failed to get service tokens"); - } - }); -}; - -export default getServiceTokens; diff --git a/frontend/pages/api/serviceToken/getServiceTokens.ts b/frontend/pages/api/serviceToken/getServiceTokens.ts new file mode 100644 index 000000000..d2577cc83 --- /dev/null +++ b/frontend/pages/api/serviceToken/getServiceTokens.ts @@ -0,0 +1,26 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route gets service tokens for a specific user in a project + * @param {*} param0 + * @returns + */ +const getServiceTokens = ({ workspaceId }: { workspaceId: string }) => { + return SecurityClient.fetchCall( + '/api/v1/workspace/' + workspaceId + '/service-tokens', + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status == 200) { + return (await res.json()).serviceTokens; + } else { + console.log('Failed to get service tokens'); + } + }); +}; + +export default getServiceTokens; diff --git a/frontend/pages/api/userActions/checkUserAction.js b/frontend/pages/api/userActions/checkUserAction.ts similarity index 51% rename from frontend/pages/api/userActions/checkUserAction.js rename to frontend/pages/api/userActions/checkUserAction.ts index dfe217856..9941ae85a 100644 --- a/frontend/pages/api/userActions/checkUserAction.js +++ b/frontend/pages/api/userActions/checkUserAction.ts @@ -1,4 +1,4 @@ -import SecurityClient from "~/utilities/SecurityClient"; +import SecurityClient from '~/utilities/SecurityClient'; /** * This route registers a certain action for a user @@ -6,24 +6,24 @@ import SecurityClient from "~/utilities/SecurityClient"; * @param {*} workspaceId * @returns */ -const checkUserAction = ({ action }) => { +const checkUserAction = ({ action }: { action: string }) => { return SecurityClient.fetchCall( - "/api/v1/user-action" + - "?" + + '/api/v1/user-action' + + '?' + new URLSearchParams({ - action, + action }), { - method: "GET", + method: 'GET', headers: { - "Content-Type": "application/json", - }, + 'Content-Type': 'application/json' + } } ).then(async (res) => { - if (res.status == 200) { + if (res && res.status == 200) { return (await res.json()).userAction; } else { - console.log("Failed to check a user action"); + console.log('Failed to check a user action'); } }); }; diff --git a/frontend/pages/api/userActions/registerUserAction.js b/frontend/pages/api/userActions/registerUserAction.js deleted file mode 100644 index 619886d89..000000000 --- a/frontend/pages/api/userActions/registerUserAction.js +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route registers a certain action for a user - * @param {*} action - * @returns - */ -const registerUserAction = ({ action }) => { - return SecurityClient.fetchCall("/api/v1/user-action", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - action, - }), - }).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to register a user action"); - } - }); -}; - -export default registerUserAction; diff --git a/frontend/pages/api/userActions/registerUserAction.ts b/frontend/pages/api/userActions/registerUserAction.ts new file mode 100644 index 000000000..d8f4d41e6 --- /dev/null +++ b/frontend/pages/api/userActions/registerUserAction.ts @@ -0,0 +1,26 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route registers a certain action for a user + * @param {*} action + * @returns + */ +const registerUserAction = ({ action }: { action: string }) => { + return SecurityClient.fetchCall('/api/v1/user-action', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + action + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to register a user action'); + } + }); +}; + +export default registerUserAction; diff --git a/frontend/pages/api/workspace/addUserToWorkspace.js b/frontend/pages/api/workspace/addUserToWorkspace.js deleted file mode 100644 index 86e991389..000000000 --- a/frontend/pages/api/workspace/addUserToWorkspace.js +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This function adds a user to a project - * @param {*} email - * @param {*} workspaceId - * @returns - */ -const addUserToWorkspace = (email, workspaceId) => { - return SecurityClient.fetchCall( - "/api/v1/workspace/" + workspaceId + "/invite-signup", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: email, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return await res.json(); - } else { - console.log("Failed to add a user to project"); - } - }); -}; - -export default addUserToWorkspace; diff --git a/frontend/pages/api/workspace/addUserToWorkspace.ts b/frontend/pages/api/workspace/addUserToWorkspace.ts new file mode 100644 index 000000000..e1efa51a1 --- /dev/null +++ b/frontend/pages/api/workspace/addUserToWorkspace.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This function adds a user to a project + * @param {*} email + * @param {*} workspaceId + * @returns + */ +const addUserToWorkspace = (email: string, workspaceId: string) => { + return SecurityClient.fetchCall( + '/api/v1/workspace/' + workspaceId + '/invite-signup', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email: email + }) + } + ).then(async (res) => { + if (res && res.status == 200) { + return await res.json(); + } else { + console.log('Failed to add a user to project'); + } + }); +}; + +export default addUserToWorkspace; diff --git a/frontend/pages/api/workspace/changeUserRoleInWorkspace.js b/frontend/pages/api/workspace/changeUserRoleInWorkspace.js deleted file mode 100644 index a93e22181..000000000 --- a/frontend/pages/api/workspace/changeUserRoleInWorkspace.js +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This function change the access of a user in a certain workspace - * @param {*} membershipId - * @param {*} role - * @returns - */ -const changeUserRoleInWorkspace = (membershipId, role) => { - return SecurityClient.fetchCall( - "/api/v1/membership/" + membershipId + "/change-role", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - role: role, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to change the user role in a project"); - } - }); -}; - -export default changeUserRoleInWorkspace; diff --git a/frontend/pages/api/workspace/changeUserRoleInWorkspace.ts b/frontend/pages/api/workspace/changeUserRoleInWorkspace.ts new file mode 100644 index 000000000..9ac49440a --- /dev/null +++ b/frontend/pages/api/workspace/changeUserRoleInWorkspace.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This function change the access of a user in a certain workspace + * @param {*} membershipId + * @param {*} role + * @returns + */ +const changeUserRoleInWorkspace = (membershipId: string, role: string) => { + return SecurityClient.fetchCall( + '/api/v1/membership/' + membershipId + '/change-role', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + role: role + }) + } + ).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to change the user role in a project'); + } + }); +}; + +export default changeUserRoleInWorkspace; diff --git a/frontend/pages/api/workspace/deleteUserFromWorkspace.js b/frontend/pages/api/workspace/deleteUserFromWorkspace.js deleted file mode 100644 index bad8beced..000000000 --- a/frontend/pages/api/workspace/deleteUserFromWorkspace.js +++ /dev/null @@ -1,23 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This function removes a certain member from a certain workspace - * @param {*} membershipId - * @returns - */ -const deleteUserFromWorkspace = (membershipId) => { - return SecurityClient.fetchCall("/api/v1/membership/" + membershipId, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - }).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to delete a user from a project"); - } - }); -}; - -export default deleteUserFromWorkspace; diff --git a/frontend/pages/api/workspace/deleteUserFromWorkspace.ts b/frontend/pages/api/workspace/deleteUserFromWorkspace.ts new file mode 100644 index 000000000..ea02f96d4 --- /dev/null +++ b/frontend/pages/api/workspace/deleteUserFromWorkspace.ts @@ -0,0 +1,23 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This function removes a certain member from a certain workspace + * @param {*} membershipId + * @returns + */ +const deleteUserFromWorkspace = (membershipId: string) => { + return SecurityClient.fetchCall('/api/v1/membership/' + membershipId, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to delete a user from a project'); + } + }); +}; + +export default deleteUserFromWorkspace; diff --git a/frontend/pages/api/workspace/deleteWorkspace.js b/frontend/pages/api/workspace/deleteWorkspace.js deleted file mode 100644 index 33d34844d..000000000 --- a/frontend/pages/api/workspace/deleteWorkspace.js +++ /dev/null @@ -1,23 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route deletes a specified workspace. - * @param {*} workspaceId - * @returns - */ -const deleteWorkspace = (workspaceId) => { - return SecurityClient.fetchCall("/api/v1/workspace/" + workspaceId, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - }).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to delete a project"); - } - }); -}; - -export default deleteWorkspace; diff --git a/frontend/pages/api/workspace/deleteWorkspace.ts b/frontend/pages/api/workspace/deleteWorkspace.ts new file mode 100644 index 000000000..2bdb64cd3 --- /dev/null +++ b/frontend/pages/api/workspace/deleteWorkspace.ts @@ -0,0 +1,23 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route deletes a specified workspace. + * @param {*} workspaceId + * @returns + */ +const deleteWorkspace = (workspaceId: string) => { + return SecurityClient.fetchCall('/api/v1/workspace/' + workspaceId, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to delete a project'); + } + }); +}; + +export default deleteWorkspace; diff --git a/frontend/pages/api/workspace/renameWorkspace.js b/frontend/pages/api/workspace/renameWorkspace.js deleted file mode 100644 index 6dd297f82..000000000 --- a/frontend/pages/api/workspace/renameWorkspace.js +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route lets us rename a certain workspace. - * @param {*} req - * @param {*} res - * @returns - */ -const renameWorkspace = (workspaceId, newWorkspaceName) => { - return SecurityClient.fetchCall( - "/api/v1/workspace/" + workspaceId + "/name", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - name: newWorkspaceName, - }), - } - ).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to rename a project"); - } - }); -}; - -export default renameWorkspace; diff --git a/frontend/pages/api/workspace/renameWorkspace.ts b/frontend/pages/api/workspace/renameWorkspace.ts new file mode 100644 index 000000000..a25d2068c --- /dev/null +++ b/frontend/pages/api/workspace/renameWorkspace.ts @@ -0,0 +1,30 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route lets us rename a certain workspace. + * @param {*} req + * @param {*} res + * @returns + */ +const renameWorkspace = (workspaceId: string, newWorkspaceName: string) => { + return SecurityClient.fetchCall( + '/api/v1/workspace/' + workspaceId + '/name', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + name: newWorkspaceName + }) + } + ).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to rename a project'); + } + }); +}; + +export default renameWorkspace; diff --git a/frontend/pages/api/workspace/uploadKeys.js b/frontend/pages/api/workspace/uploadKeys.js deleted file mode 100644 index 37b384f30..000000000 --- a/frontend/pages/api/workspace/uploadKeys.js +++ /dev/null @@ -1,33 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route uplods the keys in an encrypted format. - * @param {*} workspaceId - * @param {*} userId - * @param {*} encryptedKey - * @param {*} nonce - * @returns - */ -const uploadKeys = (workspaceId, userId, encryptedKey, nonce) => { - return SecurityClient.fetchCall("/api/v1/key/" + workspaceId, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - key: { - userId: userId, - encryptedKey: encryptedKey, - nonce: nonce, - }, - }), - }).then(async (res) => { - if (res.status == 200) { - return res; - } else { - console.log("Failed to upload keys for a new user"); - } - }); -}; - -export default uploadKeys; diff --git a/frontend/pages/api/workspace/uploadKeys.ts b/frontend/pages/api/workspace/uploadKeys.ts new file mode 100644 index 000000000..2f791735d --- /dev/null +++ b/frontend/pages/api/workspace/uploadKeys.ts @@ -0,0 +1,38 @@ +import SecurityClient from '~/utilities/SecurityClient'; + +/** + * This route uplods the keys in an encrypted format. + * @param {*} workspaceId + * @param {*} userId + * @param {*} encryptedKey + * @param {*} nonce + * @returns + */ +const uploadKeys = ( + workspaceId: string, + userId: string, + encryptedKey: string, + nonce: string +) => { + return SecurityClient.fetchCall('/api/v1/key/' + workspaceId, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + key: { + userId: userId, + encryptedKey: encryptedKey, + nonce: nonce + } + }) + }).then(async (res) => { + if (res && res.status == 200) { + return res; + } else { + console.log('Failed to upload keys for a new user'); + } + }); +}; + +export default uploadKeys; From d503102f75bb87b51d811967c890037020c149cb Mon Sep 17 00:00:00 2001 From: seunghyunOh Date: Sun, 11 Dec 2022 14:56:27 +0900 Subject: [PATCH 2/4] Change tsconfig --- frontend/tsconfig.json | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index ce99bdc6d..e936a69a2 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -2,25 +2,13 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "~/components/*": [ - "components/*" - ], - "~/utilities/*": [ - "components/utilities/*" - ], - "~/*": [ - "const" - ], - "~/pages/*": [ - "pages/*" - ] + "~/components/*": ["components/*"], + "~/utilities/*": ["components/utilities/*"], + "~/*": ["const"], + "~/pages/*": ["pages/*"] }, - "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "target": "ESNext", + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -35,12 +23,6 @@ "jsx": "preserve", "incremental": true }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ], - "exclude": [ - "node_modules" - ] + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] } From c4b482969493c6f5e4c92f1c6720de63007e4183 Mon Sep 17 00:00:00 2001 From: seunghyunOh Date: Sun, 11 Dec 2022 15:07:53 +0900 Subject: [PATCH 3/4] Linting --- backend/src/controllers/authController.ts | 310 +++++++++--------- backend/src/routes/auth.ts | 32 +- frontend/components/RouteGuard.js | 28 +- frontend/components/basic/InputField.tsx | 26 +- .../basic/table/ServiceTokenTable.js | 12 +- frontend/components/basic/table/UserTable.js | 76 ++--- .../dashboard/DashboardInputField.tsx | 34 +- frontend/components/dashboard/DropZone.tsx | 34 +- .../components/navigation/NavBarDashboard.tsx | 77 ++--- frontend/components/utilities/attemptLogin.js | 72 ++-- frontend/pages/api/auth/CheckAuth.ts | 2 +- frontend/pages/api/auth/Logout.ts | 26 +- frontend/pages/api/files/GetSecrets.ts | 2 +- frontend/pages/api/organization/GetOrg.ts | 14 +- .../pages/api/organization/GetOrgUsers.ts | 19 +- frontend/pages/api/organization/getOrgs.ts | 12 +- frontend/pages/api/user/getUser.ts | 12 +- .../pages/api/workspace/createWorkspace.ts | 22 +- .../pages/api/workspace/getLatestFileKey.ts | 19 +- .../pages/api/workspace/getProjectInfo.ts | 19 +- .../pages/api/workspace/getWorkspaceUsers.ts | 14 +- frontend/pages/api/workspace/getWorkspaces.ts | 12 +- frontend/pages/dashboard/[id].js | 144 ++++---- frontend/pages/integrations/[id].js | 143 ++++---- frontend/pages/settings/org/[id].js | 92 +++--- frontend/pages/signup.tsx | 164 ++++----- frontend/pages/users/[id].js | 68 ++-- 27 files changed, 745 insertions(+), 740 deletions(-) diff --git a/backend/src/controllers/authController.ts b/backend/src/controllers/authController.ts index 9fbd58e93..eb537f2b9 100644 --- a/backend/src/controllers/authController.ts +++ b/backend/src/controllers/authController.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ import { Request, Response } from 'express'; import jwt from 'jsonwebtoken'; import * as Sentry from '@sentry/node'; @@ -5,17 +6,17 @@ import * as bigintConversion from 'bigint-conversion'; const jsrp = require('jsrp'); import { User } from '../models'; import { createToken, issueTokens, clearTokens } from '../helpers/auth'; -import { - NODE_ENV, - JWT_AUTH_LIFETIME, - JWT_AUTH_SECRET, - JWT_REFRESH_SECRET +import { + NODE_ENV, + JWT_AUTH_LIFETIME, + JWT_AUTH_SECRET, + JWT_REFRESH_SECRET } from '../config'; declare module 'jsonwebtoken' { - export interface UserIDJwtPayload extends jwt.JwtPayload { - userId: string; - } + export interface UserIDJwtPayload extends jwt.JwtPayload { + userId: string; + } } const clientPublicKeys: any = {}; @@ -27,47 +28,45 @@ const clientPublicKeys: any = {}; * @returns */ export const login1 = async (req: Request, res: Response) => { - try { - const { - email, - clientPublicKey - }: { email: string; clientPublicKey: string } = req.body; - - const user = await User.findOne({ - email - }).select('+salt +verifier'); - + try { + const { + email, + clientPublicKey + }: { email: string; clientPublicKey: string } = req.body; - if (!user) throw new Error('Failed to find user'); + const user = await User.findOne({ + email + }).select('+salt +verifier'); - const server = new jsrp.server(); - server.init( - { - salt: user.salt, - verifier: user.verifier - }, - () => { - // generate server-side public key - const serverPublicKey = server.getPublicKey(); - clientPublicKeys[email] = { - clientPublicKey, - serverBInt: bigintConversion.bigintToBuf(server.bInt) - }; - + if (!user) throw new Error('Failed to find user'); - return res.status(200).send({ - serverPublicKey, - salt: user.salt - }); - } - ); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Failed to start authentication process' - }); - } + const server = new jsrp.server(); + server.init( + { + salt: user.salt, + verifier: user.verifier + }, + () => { + // generate server-side public key + const serverPublicKey = server.getPublicKey(); + clientPublicKeys[email] = { + clientPublicKey, + serverBInt: bigintConversion.bigintToBuf(server.bInt) + }; + + return res.status(200).send({ + serverPublicKey, + salt: user.salt + }); + } + ); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to start authentication process' + }); + } }; /** @@ -78,59 +77,59 @@ export const login1 = async (req: Request, res: Response) => { * @returns */ export const login2 = async (req: Request, res: Response) => { - try { - const { email, clientProof } = req.body; - const user = await User.findOne({ - email - }).select('+salt +verifier +publicKey +encryptedPrivateKey +iv +tag'); + try { + const { email, clientProof } = req.body; + const user = await User.findOne({ + email + }).select('+salt +verifier +publicKey +encryptedPrivateKey +iv +tag'); - if (!user) throw new Error('Failed to find user'); + if (!user) throw new Error('Failed to find user'); - const server = new jsrp.server(); - server.init( - { - salt: user.salt, - verifier: user.verifier, - b: clientPublicKeys[email].serverBInt - }, - async () => { - server.setClientPublicKey(clientPublicKeys[email].clientPublicKey); + const server = new jsrp.server(); + server.init( + { + salt: user.salt, + verifier: user.verifier, + b: clientPublicKeys[email].serverBInt + }, + async () => { + server.setClientPublicKey(clientPublicKeys[email].clientPublicKey); - // compare server and client shared keys - if (server.checkClientProof(clientProof)) { - // issue tokens - const tokens = await issueTokens({ userId: user._id.toString() }); - - // store (refresh) token in httpOnly cookie - res.cookie('jid', tokens.refreshToken, { - httpOnly: true, - path: '/token', - sameSite: "strict", - secure: NODE_ENV === 'production' ? true : false - }); + // compare server and client shared keys + if (server.checkClientProof(clientProof)) { + // issue tokens + const tokens = await issueTokens({ userId: user._id.toString() }); - // return (access) token in response - return res.status(200).send({ - token: tokens.token, - publicKey: user.publicKey, - encryptedPrivateKey: user.encryptedPrivateKey, - iv: user.iv, - tag: user.tag - }); - } + // store (refresh) token in httpOnly cookie + res.cookie('jid', tokens.refreshToken, { + httpOnly: true, + path: '/token', + sameSite: 'strict', + secure: NODE_ENV === 'production' ? true : false + }); - return res.status(400).send({ - message: 'Failed to authenticate. Try again?' - }); - } - ); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Failed to authenticate. Try again?' - }); - } + // return (access) token in response + return res.status(200).send({ + token: tokens.token, + publicKey: user.publicKey, + encryptedPrivateKey: user.encryptedPrivateKey, + iv: user.iv, + tag: user.tag + }); + } + + return res.status(400).send({ + message: 'Failed to authenticate. Try again?' + }); + } + ); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to authenticate. Try again?' + }); + } }; /** @@ -140,29 +139,29 @@ export const login2 = async (req: Request, res: Response) => { * @returns */ export const logout = async (req: Request, res: Response) => { - try { - await clearTokens({ - userId: req.user._id.toString() - }); - - // clear httpOnly cookie - res.cookie('jid', '', { - httpOnly: true, - path: '/token', - sameSite: "strict", - secure: NODE_ENV === 'production' ? true : false - }); - } catch (err) { - Sentry.setUser({ email: req.user.email }); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Failed to logout' - }); - } + try { + await clearTokens({ + userId: req.user._id.toString() + }); - return res.status(200).send({ - message: 'Successfully logged out.' - }); + // clear httpOnly cookie + res.cookie('jid', '', { + httpOnly: true, + path: '/token', + sameSite: 'strict', + secure: NODE_ENV === 'production' ? true : false + }); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to logout' + }); + } + + return res.status(200).send({ + message: 'Successfully logged out.' + }); }; /** @@ -172,9 +171,9 @@ export const logout = async (req: Request, res: Response) => { * @returns */ export const checkAuth = async (req: Request, res: Response) => - res.status(200).send({ - message: 'Authenticated' - }); + res.status(200).send({ + message: 'Authenticated' + }); /** * Return new token by redeeming refresh token @@ -183,42 +182,41 @@ export const checkAuth = async (req: Request, res: Response) => * @returns */ export const getNewToken = async (req: Request, res: Response) => { - try { - const refreshToken = req.cookies.jid; - - if (!refreshToken) { - throw new Error('Failed to find token in request cookies'); - } - - const decodedToken = ( - jwt.verify(refreshToken, JWT_REFRESH_SECRET) - ); - - const user = await User.findOne({ - _id: decodedToken.userId - }).select('+publicKey'); + try { + const refreshToken = req.cookies.jid; - if (!user) throw new Error('Failed to authenticate unfound user'); - if (!user?.publicKey) - throw new Error('Failed to authenticate not fully set up account'); - - const token = createToken({ - payload: { - userId: decodedToken.userId - }, - expiresIn: JWT_AUTH_LIFETIME, - secret: JWT_AUTH_SECRET - }); - - return res.status(200).send({ - token - }); - - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Invalid request' - }); - } + if (!refreshToken) { + throw new Error('Failed to find token in request cookies'); + } + + const decodedToken = ( + jwt.verify(refreshToken, JWT_REFRESH_SECRET) + ); + + const user = await User.findOne({ + _id: decodedToken.userId + }).select('+publicKey'); + + if (!user) throw new Error('Failed to authenticate unfound user'); + if (!user?.publicKey) + throw new Error('Failed to authenticate not fully set up account'); + + const token = createToken({ + payload: { + userId: decodedToken.userId + }, + expiresIn: JWT_AUTH_LIFETIME, + secret: JWT_AUTH_SECRET + }); + + return res.status(200).send({ + token + }); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Invalid request' + }); + } }; diff --git a/backend/src/routes/auth.ts b/backend/src/routes/auth.ts index 43a57fe7e..6be9c09f7 100644 --- a/backend/src/routes/auth.ts +++ b/backend/src/routes/auth.ts @@ -5,28 +5,24 @@ import { requireAuth, validateRequest } from '../middleware'; import { authController } from '../controllers'; import { loginLimiter } from '../helpers/rateLimiter'; +router.post('/token', validateRequest, authController.getNewToken); + router.post( - '/token', - validateRequest, - authController.getNewToken + '/login1', + loginLimiter, + body('email').exists().trim().notEmpty(), + body('clientPublicKey').exists().trim().notEmpty(), + validateRequest, + authController.login1 ); router.post( - '/login1', - loginLimiter, - body('email').exists().trim().notEmpty(), - body('clientPublicKey').exists().trim().notEmpty(), - validateRequest, - authController.login1 -); - -router.post( - '/login2', - loginLimiter, - body('email').exists().trim().notEmpty(), - body('clientProof').exists().trim().notEmpty(), - validateRequest, - authController.login2 + '/login2', + loginLimiter, + body('email').exists().trim().notEmpty(), + body('clientProof').exists().trim().notEmpty(), + validateRequest, + authController.login2 ); router.post('/logout', requireAuth, authController.logout); diff --git a/frontend/components/RouteGuard.js b/frontend/components/RouteGuard.js index a21c0c86a..d08972b99 100644 --- a/frontend/components/RouteGuard.js +++ b/frontend/components/RouteGuard.js @@ -1,9 +1,9 @@ -import { useEffect, useState } from "react"; -import Image from "next/image"; -import { useRouter } from "next/router"; +import { useEffect, useState } from 'react'; +import Image from 'next/image'; +import { useRouter } from 'next/router'; -import { publicPaths } from "~/const"; -import checkAuth from "~/pages/api/auth/CheckAuth"; +import { publicPaths } from '~/const'; +import checkAuth from '~/pages/api/auth/CheckAuth'; // #TODO: finish spinner only when the data loads fully // #TODO: Redirect somewhere if the page does not exist @@ -22,16 +22,16 @@ export default function RouteGuard({ children }) { // #TODO: add the loading page when not yet authorized. const hideContent = () => setAuthorized(false); // const onError = () => setAuthorized(true) - router.events.on("routeChangeStart", hideContent); + router.events.on('routeChangeStart', hideContent); // router.events.on("routeChangeError", onError); // on route change complete - run auth check - router.events.on("routeChangeComplete", authCheck); + router.events.on('routeChangeComplete', authCheck); // unsubscribe from events in useEffect return function return () => { - router.events.off("routeChangeStart", hideContent); - router.events.off("routeChangeComplete", authCheck); + router.events.off('routeChangeStart', hideContent); + router.events.off('routeChangeComplete', authCheck); // router.events.off("routeChangeError", onError); }; // eslint-disable-next-line react-hooks/exhaustive-deps @@ -43,7 +43,7 @@ export default function RouteGuard({ children }) { */ async function authCheck(url) { // Make sure that we don't redirect when the user is on the following pages. - const path = "/" + url.split("?")[0].split("/")[1]; + const path = '/' + url.split('?')[0].split('/')[1]; // Check if the user is authenticated const response = await checkAuth(); @@ -51,16 +51,16 @@ export default function RouteGuard({ children }) { if (!publicPaths.includes(path)) { try { if (response.status !== 200) { - router.push("/login"); - console.log("Unauthorized to access."); + router.push('/login'); + console.log('Unauthorized to access.'); setAuthorized(false); } else { setAuthorized(true); - console.log("Authorized to access."); + console.log('Authorized to access.'); } } catch (error) { console.log( - "Error (probably the authCheck route is stuck again...):", + 'Error (probably the authCheck route is stuck again...):', error ); } diff --git a/frontend/components/basic/InputField.tsx b/frontend/components/basic/InputField.tsx index 139304ea6..141578214 100644 --- a/frontend/components/basic/InputField.tsx +++ b/frontend/components/basic/InputField.tsx @@ -1,9 +1,9 @@ -import React, { useState } from "react"; -import { useRouter } from "next/router"; -import { faCircle, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import React, { useState } from 'react'; +import { useRouter } from 'next/router'; +import { faCircle, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import guidGenerator from "../utilities/randomId"; +import guidGenerator from '../utilities/randomId'; interface InputFieldProps { static?: boolean; @@ -23,7 +23,7 @@ interface InputFieldProps { const InputField = ( props: InputFieldProps & - Pick + Pick ) => { const [passwordVisible, setPasswordVisible] = useState(false); const router = useRouter(); @@ -75,28 +75,28 @@ const InputField = (
props.onChangeHandler(e.target.value)} - type={passwordVisible === false ? props.type : "text"} + type={passwordVisible === false ? props.type : 'text'} placeholder={props.placeholder} value={props.value} required={props.isRequired} className={`${ props.blurred - ? "text-bunker-800 group-hover:text-gray-400 focus:text-gray-400 active:text-gray-400" - : "" + ? 'text-bunker-800 group-hover:text-gray-400 focus:text-gray-400 active:text-gray-400' + : '' } ${ - props.error ? "focus:ring-red/50" : "focus:ring-primary/50" + props.error ? 'focus:ring-red/50' : 'focus:ring-primary/50' } relative peer bg-bunker-800 rounded-md text-gray-400 text-md p-2 w-full min-w-16 outline-none focus:ring-4 duration-200`} name={props.name} spellCheck="false" autoComplete={props.autoComplete} id={props.id} /> - {props.label?.includes("Password") && ( + {props.label?.includes('Password') && (
)} - {row.status == "completed" && myUser !== row.email && ( + {row.status == 'completed' && myUser !== row.email && (
{myUser !== row.email && // row.role != "admin" && - myRole != "member" ? ( + myRole != 'member' ? (
)} - {!["Heroku"].includes(integrations[integration].name) && ( + {!['Heroku'].includes(integrations[integration].name) && (
Coming Soon @@ -351,7 +353,8 @@ export default function Integrations() {

Click on a framework to get the setup instructions.

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

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

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

14 characters @@ -436,7 +436,7 @@ export default function SignUp() { )}
1 lowercase character @@ -456,7 +456,7 @@ export default function SignUp() { )}
1 number @@ -505,13 +505,13 @@ export default function SignUp() { await issueBackupKey({ email, password, - personalName: firstName + " " + lastName, + personalName: firstName + ' ' + lastName, setBackupKeyError, - setBackupKeyIssued, + setBackupKeyIssued }); const userWorkspaces = await getWorkspaces(); const userWorkspace = userWorkspaces[0]._id; - router.push("/home/" + userWorkspace); + router.push('/home/' + userWorkspace); }} size="lg" /> diff --git a/frontend/pages/users/[id].js b/frontend/pages/users/[id].js index de0307786..fe96ded3a 100644 --- a/frontend/pages/users/[id].js +++ b/frontend/pages/users/[id].js @@ -1,39 +1,39 @@ -import React, { useEffect, useState } from "react"; -import Head from "next/head"; -import Image from "next/image"; -import { useRouter } from "next/router"; -import { faMagnifyingGlass, faPlus } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import React, { useEffect, useState } from 'react'; +import Head from 'next/head'; +import Image from 'next/image'; +import { useRouter } from 'next/router'; +import { faMagnifyingGlass, faPlus } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import Button from "~/components/basic/buttons/Button"; -import AddProjectMemberDialog from "~/components/basic/dialog/AddProjectMemberDialog"; -import UserTable from "~/components/basic/table/UserTable"; -import NavHeader from "~/components/navigation/NavHeader"; -import guidGenerator from "~/utilities/randomId"; +import Button from '~/components/basic/buttons/Button'; +import AddProjectMemberDialog from '~/components/basic/dialog/AddProjectMemberDialog'; +import UserTable from '~/components/basic/table/UserTable'; +import NavHeader from '~/components/navigation/NavHeader'; +import guidGenerator from '~/utilities/randomId'; -import getOrganizationUsers from "../api/organization/GetOrgUsers"; -import getUser from "../api/user/getUser"; +import getOrganizationUsers from '../api/organization/GetOrgUsers'; +import getUser from '../api/user/getUser'; // import DeleteUserDialog from '~/components/basic/dialog/DeleteUserDialog'; -import addUserToWorkspace from "../api/workspace/addUserToWorkspace"; -import getWorkspaceUsers from "../api/workspace/getWorkspaceUsers"; -import uploadKeys from "../api/workspace/uploadKeys"; +import addUserToWorkspace from '../api/workspace/addUserToWorkspace'; +import getWorkspaceUsers from '../api/workspace/getWorkspaceUsers'; +import uploadKeys from '../api/workspace/uploadKeys'; // #TODO: Update all the workspaceIds -const crypto = require("crypto"); +const crypto = require('crypto'); const { decryptAssymmetric, - encryptAssymmetric, -} = require("../../components/utilities/cryptography/crypto"); -const nacl = require("tweetnacl"); -nacl.util = require("tweetnacl-util"); + encryptAssymmetric +} = require('../../components/utilities/cryptography/crypto'); +const nacl = require('tweetnacl'); +nacl.util = require('tweetnacl-util'); export default function Users() { let [isAddOpen, setIsAddOpen] = useState(false); // let [isDeleteOpen, setIsDeleteOpen] = useState(false); // let [userIdToBeDeleted, setUserIdToBeDeleted] = useState(false); - let [email, setEmail] = useState(""); - const [personalEmail, setPersonalEmail] = useState(""); - const [searchUsers, setSearchUsers] = useState(""); + let [email, setEmail] = useState(''); + const [personalEmail, setPersonalEmail] = useState(''); + const [searchUsers, setSearchUsers] = useState(''); const router = useRouter(); let workspaceId; @@ -57,25 +57,25 @@ export default function Users() { async function submitAddModal() { let result = await addUserToWorkspace(email, router.query.id); if (result?.invitee && result?.latestKey) { - const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); + const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY'); // assymmetrically decrypt symmetric key with local private key const key = decryptAssymmetric({ ciphertext: result.latestKey.encryptedKey, nonce: result.latestKey.nonce, publicKey: result.latestKey.sender.publicKey, - privateKey: PRIVATE_KEY, + privateKey: PRIVATE_KEY }); const { ciphertext, nonce } = encryptAssymmetric({ plaintext: key, publicKey: result.invitee.publicKey, - privateKey: PRIVATE_KEY, + privateKey: PRIVATE_KEY }); uploadKeys(router.query.id, result.invitee._id, ciphertext, nonce); } - setEmail(""); + setEmail(''); setIsAddOpen(false); router.reload(); } @@ -93,7 +93,7 @@ export default function Users() { workspaceId = router.query.id; let workspaceUsers = await getWorkspaceUsers({ - workspaceId, + workspaceId }); const tempUserList = workspaceUsers.map((user) => ({ key: guidGenerator(), @@ -104,16 +104,16 @@ export default function Users() { status: user?.status, userId: user.user?._id, membershipId: user._id, - publicKey: user.user?.publicKey, + publicKey: user.user?.publicKey })); setUserList(tempUserList); const orgUsers = await getOrganizationUsers({ - orgId: localStorage.getItem("orgData.id"), + orgId: localStorage.getItem('orgData.id') }); setOrgUserList(orgUsers); setEmail( orgUsers - ?.filter((user) => user.status == "accepted") + ?.filter((user) => user.status == 'accepted') .map((user) => user.user.email) .filter( (email) => !tempUserList?.map((user1) => user1.email).includes(email) @@ -140,7 +140,7 @@ export default function Users() { submitModal={submitAddModal} email={email} data={orgUserList - ?.filter((user) => user.status == "accepted") + ?.filter((user) => user.status == 'accepted') .map((user) => user.user.email) .filter( (email) => !userList?.map((user1) => user1.email).includes(email) @@ -159,7 +159,7 @@ export default function Users() { className="pl-2 text-gray-400 rounded-r-md bg-white/5 w-full h-full outline-none" value={searchUsers} onChange={(e) => setSearchUsers(e.target.value)} - placeholder={"Search members..."} + placeholder={'Search members...'} />
From 2b6e69ce1b8c426b80453e25300c4f1bf6bfd512 Mon Sep 17 00:00:00 2001 From: seunghyunOh Date: Sun, 11 Dec 2022 15:51:29 +0900 Subject: [PATCH 4/4] Fix Build Error --- frontend/components/billing/Plan.tsx | 4 +++- frontend/pages/api/files/UploadSecrets.ts | 2 +- .../api/integrations/ChangeHerokuConfigVars.ts | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/frontend/components/billing/Plan.tsx b/frontend/components/billing/Plan.tsx index b051e7435..69b7baaba 100644 --- a/frontend/components/billing/Plan.tsx +++ b/frontend/components/billing/Plan.tsx @@ -2,6 +2,8 @@ import React from 'react'; import StripeRedirect from '~/pages/api/organization/StripeRedirect'; +import { tempLocalStorage } from '../utilities/checks/tempLocalStorage'; + interface Props { plan: { name: string; @@ -66,7 +68,7 @@ export default function Plan({ plan }: Props) {