diff --git a/README.md b/README.md
index 4215a9fa8..1b2d43c5f 100644
--- a/README.md
+++ b/README.md
@@ -48,11 +48,11 @@
And more.
-## Get started
+## 🚀 Get started
To quickly get started, visit our [get started guide](https://infisical.com/docs/getting-started/introduction).
-## What's cool about this?
+## 🔥 What's cool about this?
Infisical makes secret management simple and end-to-end encrypted by default. We're on a mission to make it more accessible to all developers, not just security teams .
@@ -62,20 +62,20 @@ If you care about efficiency and security, then Infisical is right for you.
We are currently working hard to make Infisical more extensive. Need any integrations or want a new feature? Feel free to [create an issue](https://github.com/Infisical/infisical/issues) or [contribute](https://infisical.com/docs/contributing/overview) directly to the repository.
-## Contributing
+## 🌱 Contributing
Whether it's big or small, we love contributions ❤️ Check out our guide to see how to [get started](https://infisical.com/docs/contributing/overview).
Not sure where to get started? [Book a free, non-pressure pairing sessions with one of our teammates](mailto:tony@infisical.com?subject=Pairing%20session&body=I'd%20like%20to%20do%20a%20pairing%20session!)!
-## Community & Support
+## 💚 Community & Support
- [Slack](https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g) (For live discussion with the community and the Infisical team)
- [GitHub Discussions](https://github.com/Infisical/infisical/discussions) (For help with building and deeper conversations about features)
- [GitHub Issues](https://github.com/Infisical/infisical-cli/issues) (For any bugs and errors you encounter using Infisical)
- [Twitter](https://twitter.com/infisical) (Get news fast)
-## Status
+## 🐥 Status
- [x] Public Alpha: Anyone can sign up over at [infisical.com](https://infisical.com) but go easy on us, there are kinks and we're just getting started.
- [ ] Public Beta: Stable enough for most non-enterprise use-cases.
@@ -83,13 +83,13 @@ Not sure where to get started? [Book a free, non-pressure pairing sessions with
We're currently in Public Alpha.
-## Stay Up-to-Date
+## 🚨 Stay Up-to-Date
Infisical officially launched as v.1.0 on November 21st, 2022. However, a lot of new features are coming very quickly. Watch **releases** of this repository to be notified about future updates:

-## Integrations
+## 🔌 Integrations
We're currently setting the foundation and building [integrations](https://infisical.com/docs/integrations/overview) so secrets can be synced everywhere. Any help is welcome! :)
@@ -261,15 +261,15 @@ We're currently setting the foundation and building [integrations](https://infis
-## Open-source vs. paid
+## 🏘 Open-source vs. paid
This repo is entirely MIT licensed, with the exception of the `ee` directory which will contain premium enterprise features requiring a Infisical license in the future. We're currently focused on developing non-enterprise offerings first that should suit most use-cases.
-## Security
+## 🛡 Security
Looking to report a security vulnerability? Please don't post about it in GitHub issue. Instead, refer to our [SECURITY.md](./SECURITY.md) file.
-## Contributors 🦸
+## 🦸 Contributors
[//]: contributor-faces
@@ -277,4 +277,4 @@ Looking to report a security vulnerability? Please don't post about it in GitHub
-
+
diff --git a/frontend/components/context/Notifications/Notification.tsx b/frontend/components/context/Notifications/Notification.tsx
new file mode 100644
index 000000000..974843cf6
--- /dev/null
+++ b/frontend/components/context/Notifications/Notification.tsx
@@ -0,0 +1,38 @@
+import { faXmarkCircle } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import classnames from "classnames";
+
+import { Notification as NotificationType } from "./NotificationProvider";
+
+interface NotificationProps {
+ notification: NotificationType;
+ clearNotification: (text?: string) => void;
+}
+
+const Notification = ({
+ notification,
+ clearNotification,
+}: NotificationProps) => {
+ return (
+
+
{notification.text}
+
clearNotification(notification.text)}
+ >
+
+
+
+ );
+};
+
+export default Notification;
diff --git a/frontend/components/context/Notifications/NotificationProvider.tsx b/frontend/components/context/Notifications/NotificationProvider.tsx
new file mode 100644
index 000000000..723319615
--- /dev/null
+++ b/frontend/components/context/Notifications/NotificationProvider.tsx
@@ -0,0 +1,64 @@
+import { createContext, ReactNode, useContext, useState } from "react";
+
+import Notifications from "./Notifications";
+
+type NotificationType = "success" | "error";
+
+export type Notification = {
+ text: string;
+ type: NotificationType;
+};
+
+type NotificationContextState = {
+ createNotification: ({ text, type }: Notification) => void;
+};
+
+const NotificationContext = createContext({
+ createNotification: () => console.log("createNotification not set!"),
+});
+
+export const useNotificationContext = () => useContext(NotificationContext);
+
+interface NotificationProviderProps {
+ children: ReactNode;
+}
+
+const NotificationProvider = ({ children }: NotificationProviderProps) => {
+ const [notifications, setNotifications] = useState([]);
+
+ const clearNotification = (text?: string) => {
+ if (text) {
+ return setNotifications((state) =>
+ state.filter((notif) => notif.text !== text)
+ );
+ }
+
+ return setNotifications([]);
+ };
+
+ const createNotification = ({ text, type = "success" }: Notification) => {
+ const doesNotifExist = notifications.some((notif) => notif.text === text);
+
+ if (doesNotifExist) {
+ return;
+ }
+
+ return setNotifications((state) => [...state, { text, type }]);
+ };
+
+ return (
+
+
+ {children}
+
+ );
+};
+
+export default NotificationProvider;
diff --git a/frontend/components/context/Notifications/Notifications.tsx b/frontend/components/context/Notifications/Notifications.tsx
new file mode 100644
index 000000000..856331e24
--- /dev/null
+++ b/frontend/components/context/Notifications/Notifications.tsx
@@ -0,0 +1,28 @@
+import Notification from "./Notification";
+import { Notification as NotificationType } from "./NotificationProvider";
+
+interface NoticationsProps {
+ notifications: NotificationType[];
+ clearNotification: (text?: string) => void;
+}
+
+const Notifications = ({
+ notifications,
+ clearNotification,
+}: NoticationsProps) => {
+ return (
+
+
+ {notifications.map((notif) => (
+
+ ))}
+
+
+ );
+};
+
+export default Notifications;
diff --git a/frontend/components/utilities/attemptLogin.js b/frontend/components/utilities/attemptLogin.js
index 7f14b20de..33c08b698 100644
--- a/frontend/components/utilities/attemptLogin.js
+++ b/frontend/components/utilities/attemptLogin.js
@@ -5,6 +5,7 @@ import getOrganizations from "~/pages/api/organization/getOrgs";
import getOrganizationUserProjects from "~/pages/api/organization/GetOrgUserProjects";
import pushKeys from "./secrets/pushKeys";
+import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage";
import SecurityClient from "./SecurityClient";
import Telemetry from "./telemetry/Telemetry";
@@ -41,66 +42,38 @@ const attemptLogin = async (
async () => {
const clientPublicKey = client.getPublicKey();
- let serverPublicKey, salt;
- try {
- let res = await login1(email, clientPublicKey);
- res = await res.json();
- serverPublicKey = res.serverPublicKey;
- salt = res.salt;
- } catch (err) {
- setErrorLogin(true);
- console.log("Wrong password", err);
- }
+ const { serverPublicKey, salt } = await login1(email, clientPublicKey);
- let response;
try {
client.setSalt(salt);
client.setServerPublicKey(serverPublicKey);
const clientProof = client.getProof(); // called M1
- response = await login2(email, clientProof);
- } catch (err) {
- setErrorLogin(true);
- console.log("Password verification failed");
- }
- // if everything works, go the main dashboard page.
- try {
- if (response.status == "200") {
- response = await response.json();
- SecurityClient.setToken(response["token"]);
- const publicKey = response["publicKey"];
- const encryptedPrivateKey = response["encryptedPrivateKey"];
- const iv = response["iv"];
- const tag = response["tag"];
+ // if everything works, go the main dashboard page.
+ const { token, publicKey, encryptedPrivateKey, iv, tag } =
+ await login2(email, clientProof);
+ SecurityClient.setToken(token);
- const PRIVATE_KEY = Aes256Gcm.decrypt(
- encryptedPrivateKey,
- iv,
- tag,
- password
- .slice(0, 32)
- .padStart(
- 32 +
- (password.slice(0, 32).length - new Blob([password]).size),
- "0"
- )
- );
+ const privateKey = Aes256Gcm.decrypt(
+ encryptedPrivateKey,
+ iv,
+ tag,
+ password
+ .slice(0, 32)
+ .padStart(
+ 32 + (password.slice(0, 32).length - new Blob([password]).size),
+ "0"
+ )
+ );
- try {
- localStorage.setItem("publicKey", publicKey);
- localStorage.setItem("encryptedPrivateKey", encryptedPrivateKey);
- localStorage.setItem("iv", iv);
- localStorage.setItem("tag", tag);
- localStorage.setItem("PRIVATE_KEY", PRIVATE_KEY);
- } catch (err) {
- setErrorLogin(true);
- console.error(
- "Unable to send the tokens in local storage:" + err.message
- );
- }
- } else {
- setErrorLogin(true);
- }
+ saveTokenToLocalStorage({
+ token,
+ publicKey,
+ encryptedPrivateKey,
+ iv,
+ tag,
+ privateKey,
+ });
const userOrgs = await getOrganizations();
const userOrgsData = userOrgs.map((org) => org._id);
@@ -150,7 +123,7 @@ const attemptLogin = async (
STRIPE_SECRET_KEY: ["sk_test_7348oyho4hfq398HIUOH78", "shared"],
},
workspaceId: projectToLogin,
- env: "Development"
+ env: "Development",
});
}
if (email) {
diff --git a/frontend/components/utilities/saveTokenToLocalStorage.ts b/frontend/components/utilities/saveTokenToLocalStorage.ts
new file mode 100644
index 000000000..13e50b2c4
--- /dev/null
+++ b/frontend/components/utilities/saveTokenToLocalStorage.ts
@@ -0,0 +1,29 @@
+interface Props {
+ publicKey: string;
+ encryptedPrivateKey: string;
+ iv: string;
+ tag: string;
+ privateTag: string;
+}
+
+export const saveTokenToLocalStorage = ({
+ publicKey,
+ encryptedPrivateKey,
+ iv,
+ tag,
+ privateTag,
+}: Props) => {
+ try {
+ localStorage.setItem("publicKey", publicKey);
+ localStorage.setItem("encryptedPrivateKey", encryptedPrivateKey);
+ localStorage.setItem("iv", iv);
+ localStorage.setItem("tag", tag);
+ localStorage.setItem("PRIVATE_KEY", privateTag);
+ } catch (err) {
+ if (err instanceof Error) {
+ throw new Error(
+ "Unable to send the tokens in local storage:" + err.message
+ );
+ }
+ }
+};
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 7a560ad3f..7a8ed6702 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -50,13 +50,13 @@
"devDependencies": {
"@tailwindcss/typography": "^0.5.4",
"@types/node": "18.11.9",
+ "@types/react": "^18.0.26",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"autoprefixer": "^10.4.7",
"eslint": "^8.29.0",
"eslint-config-next": "^13.0.5",
"eslint-import-resolver-typescript": "^3.5.2",
- "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-simple-import-sort": "^8.0.0",
"postcss": "^8.4.14",
"prettier": "2.7.1",
@@ -1143,9 +1143,9 @@
"optional": true
},
"node_modules/@types/react": {
- "version": "18.0.15",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz",
- "integrity": "sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==",
+ "version": "18.0.26",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz",
+ "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==",
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -2901,27 +2901,6 @@
"semver": "bin/semver.js"
}
},
- "node_modules/eslint-plugin-prettier": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
- "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
- "dev": true,
- "dependencies": {
- "prettier-linter-helpers": "^1.0.0"
- },
- "engines": {
- "node": ">=12.0.0"
- },
- "peerDependencies": {
- "eslint": ">=7.28.0",
- "prettier": ">=2.0.0"
- },
- "peerDependenciesMeta": {
- "eslint-config-prettier": {
- "optional": true
- }
- }
- },
"node_modules/eslint-plugin-react": {
"version": "7.31.11",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz",
@@ -3289,12 +3268,6 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
- "node_modules/fast-diff": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
- "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
- "dev": true
- },
"node_modules/fast-glob": {
"version": "3.2.11",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
@@ -5624,18 +5597,6 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
- "node_modules/prettier-linter-helpers": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
- "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
- "dev": true,
- "dependencies": {
- "fast-diff": "^1.1.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -7666,7 +7627,8 @@
"@headlessui/react": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.6.6.tgz",
- "integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q=="
+ "integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q==",
+ "requires": {}
},
"@humanwhocodes/config-array": {
"version": "0.11.7",
@@ -8007,9 +7969,9 @@
"optional": true
},
"@types/react": {
- "version": "18.0.15",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz",
- "integrity": "sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==",
+ "version": "18.0.26",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz",
+ "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==",
"requires": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -8247,7 +8209,8 @@
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"acorn-node": {
"version": "1.8.2",
@@ -8450,7 +8413,8 @@
"axios-auth-refresh": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/axios-auth-refresh/-/axios-auth-refresh-3.3.3.tgz",
- "integrity": "sha512-2IbDhJ/h6ddNBBnnzn1VFK/qx17pE9aVqiafB8rx5LVHsJ1HtFpUGkbXY7PzTG+8P9HJWcyA3fNZl9BikSuilg=="
+ "integrity": "sha512-2IbDhJ/h6ddNBBnnzn1VFK/qx17pE9aVqiafB8rx5LVHsJ1HtFpUGkbXY7PzTG+8P9HJWcyA3fNZl9BikSuilg==",
+ "requires": {}
},
"axobject-query": {
"version": "2.2.0",
@@ -9400,15 +9364,6 @@
}
}
},
- "eslint-plugin-prettier": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
- "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
- "dev": true,
- "requires": {
- "prettier-linter-helpers": "^1.0.0"
- }
- },
"eslint-plugin-react": {
"version": "7.31.11",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz",
@@ -9464,13 +9419,15 @@
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
"integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"eslint-plugin-simple-import-sort": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-8.0.0.tgz",
"integrity": "sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"eslint-scope": {
"version": "7.1.1",
@@ -9583,12 +9540,6 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
- "fast-diff": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
- "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
- "dev": true
- },
"fast-glob": {
"version": "3.2.11",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
@@ -11161,15 +11112,6 @@
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true
},
- "prettier-linter-helpers": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
- "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
- "dev": true,
- "requires": {
- "fast-diff": "^1.1.2"
- }
- },
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -11441,7 +11383,8 @@
"react-table": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz",
- "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA=="
+ "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==",
+ "requires": {}
},
"read-cache": {
"version": "1.0.0",
@@ -11482,7 +11425,8 @@
"redux-thunk": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
- "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q=="
+ "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==",
+ "requires": {}
},
"regenerator-runtime": {
"version": "0.13.11",
@@ -11834,7 +11778,8 @@
"styled-jsx": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz",
- "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA=="
+ "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==",
+ "requires": {}
},
"stylis": {
"version": "4.0.13",
@@ -12197,12 +12142,14 @@
"use-memo-one": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz",
- "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ=="
+ "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==",
+ "requires": {}
},
"use-sync-external-store": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
- "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA=="
+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+ "requires": {}
},
"util-deprecate": {
"version": "1.0.2",
diff --git a/frontend/package.json b/frontend/package.json
index ebfdbfe3c..ab71c81bf 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -53,6 +53,7 @@
"devDependencies": {
"@tailwindcss/typography": "^0.5.4",
"@types/node": "18.11.9",
+ "@types/react": "^18.0.26",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"autoprefixer": "^10.4.7",
diff --git a/frontend/pages/_app.js b/frontend/pages/_app.js
index 04d868899..f9f7b3215 100644
--- a/frontend/pages/_app.js
+++ b/frontend/pages/_app.js
@@ -2,7 +2,8 @@ import { useEffect } from "react";
import { useRouter } from "next/router";
import { config } from "@fortawesome/fontawesome-svg-core";
-import Layout from "~/components/basic/Layout";
+import Layout from "~/components/basic/layout";
+import NotificationProvider from "~/components/context/Notifications/NotificationProvider";
import RouteGuard from "~/components/RouteGuard";
import { publicPaths } from "~/const";
import Telemetry from "~/utilities/telemetry/Telemetry";
@@ -42,9 +43,11 @@ const App = ({ Component, pageProps, ...appProps }) => {
return (
-
-
-
+
+
+
+
+
);
};
diff --git a/frontend/pages/api/auth/Login1.js b/frontend/pages/api/auth/Login1.js
deleted file mode 100644
index 3f3493f77..000000000
--- a/frontend/pages/api/auth/Login1.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * This is the first step of the login process (pake)
- * @param {*} email
- * @param {*} clientPublicKey
- * @returns
- */
-const login1 = (email, clientPublicKey) => {
- return fetch("/api/v1/auth/login1", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- email: email,
- clientPublicKey,
- }),
- });
-};
-
-export default login1;
diff --git a/frontend/pages/api/auth/Login1.ts b/frontend/pages/api/auth/Login1.ts
new file mode 100644
index 000000000..818a2d157
--- /dev/null
+++ b/frontend/pages/api/auth/Login1.ts
@@ -0,0 +1,32 @@
+interface Login1 {
+ serverPublicKey: string;
+ salt: string;
+}
+
+/**
+ * This is the first step of the login process (pake)
+ * @param {*} email
+ * @param {*} clientPublicKey
+ * @returns
+ */
+const login1 = async (email: string, clientPublicKey: string) => {
+ const response = await fetch("/api/v1/auth/login1", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ email: email,
+ clientPublicKey,
+ }),
+ });
+ // need precise error handling about the status code
+ if (response?.status === 200) {
+ const data = (await response.json()) as unknown as Login1;
+ return data;
+ }
+
+ throw new Error("Wrong password");
+};
+
+export default login1;
diff --git a/frontend/pages/api/auth/Login2.js b/frontend/pages/api/auth/Login2.js
deleted file mode 100644
index 923e261df..000000000
--- a/frontend/pages/api/auth/Login2.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * This is the second step of the login process
- * @param {*} email
- * @param {*} clientPublicKey
- * @returns
- */
-const login2 = (email, clientProof) => {
- return fetch("/api/v1/auth/login2", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- email: email,
- clientProof,
- }),
- credentials: "include",
- }).then((res) => {
- if (res.status == 200) {
- console.log("User logged in", res);
- return res;
- } else {
- console.log("Failed to log in");
- }
- });
-};
-
-export default login2;
diff --git a/frontend/pages/api/auth/Login2.ts b/frontend/pages/api/auth/Login2.ts
new file mode 100644
index 000000000..3adcb695f
--- /dev/null
+++ b/frontend/pages/api/auth/Login2.ts
@@ -0,0 +1,36 @@
+interface Login2Response {
+ encryptedPrivateKey: string;
+ iv: string;
+ publicKey: string;
+ tag: string;
+ token: string;
+}
+
+/**
+ * This is the second step of the login process
+ * @param {*} email
+ * @param {*} clientPublicKey
+ * @returns
+ */
+const login2 = async (email: string, clientProof: string) => {
+ const response = await fetch("/api/v1/auth/login2", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ email: email,
+ clientProof,
+ }),
+ credentials: "include",
+ });
+ // need precise error handling about the status code
+ if (response.status == 200) {
+ const data = (await response.json()) as unknown as Login2Response;
+ return data;
+ }
+
+ throw new Error("Password verification failed");
+};
+
+export default login2;
diff --git a/frontend/pages/dashboard/[id].js b/frontend/pages/dashboard/[id].js
index b2dfd70f4..bec6849ad 100644
--- a/frontend/pages/dashboard/[id].js
+++ b/frontend/pages/dashboard/[id].js
@@ -26,6 +26,7 @@ import { Menu, Transition } from "@headlessui/react";
import Button from "~/components/basic/buttons/Button";
import ListBox from "~/components/basic/Listbox";
import BottonRightPopup from "~/components/basic/popups/BottomRightPopup";
+import { useNotificationContext } from "~/components/context/Notifications/NotificationProvider";
import DashboardInputField from "~/components/dashboard/DashboardInputField";
import DropZone from "~/components/dashboard/DropZone";
import NavHeader from "~/components/navigation/NavHeader";
@@ -60,7 +61,7 @@ const KeyPair = ({
modifyValue,
modifyVisibility,
isBlurred,
- duplicates
+ duplicates,
}) => {
const [randomStringLength, setRandomStringLength] = useState(32);
@@ -227,6 +228,8 @@ export default function Dashboard() {
const [checkDocsPopUpVisible, setCheckDocsPopUpVisible] = useState(false);
const [hasUserEverPushed, setHasUserEverPushed] = useState(false);
+ const { createNotification } = useNotificationContext();
+
// #TODO: fix save message for changing reroutes
// const beforeRouteHandler = (url) => {
// const warningText =
@@ -370,46 +373,61 @@ export default function Dashboard() {
);
// Checking if any of the secret keys start with a number - if so, don't do anything
- const nameErrors = !Object.keys(obj).map(key => !isNaN(key.charAt(0))).every(v => v === false);
- const duplicatesExist = data?.map(item => item[2]).filter((item, index) => index !== data?.map(item => item[2]).indexOf(item)).length > 0;
+ const nameErrors = !Object.keys(obj)
+ .map((key) => !isNaN(key.charAt(0)))
+ .every((v) => v === false);
+ const duplicatesExist =
+ data
+ ?.map((item) => item[2])
+ .filter(
+ (item, index) => index !== data?.map((item) => item[2]).indexOf(item)
+ ).length > 0;
if (nameErrors) {
- console.log("Solve all name errors first!");
- } else if (duplicatesExist) {
- console.log("Remove the duplicated entries first!");
- } else {
- // Once "Save changes is clicked", disable that button
- setButtonReady(false);
- pushKeys({obj, workspaceId: router.query.id, env});
-
- /**
- * Check which integrations are active for this project and environment
- * If there are any, update environment variables for those integrations
- */
- let integrations = await getWorkspaceIntegrations({
- workspaceId: router.query.id,
- });
- integrations.map(async (integration) => {
- if (
- envMapping[env] == integration.environment &&
- integration.isActive == true
- ) {
- let objIntegration = Object.assign(
- {},
- ...data.map((row) => ({ [row[2]]: row[3] }))
- );
- await pushKeysIntegration({
- obj: objIntegration,
- integrationId: integration._id,
- });
- }
+ return createNotification({
+ text: "Solve all name errors first!",
+ type: "error",
});
+ }
- // If this user has never saved environment variables before, show them a prompt to read docs
- if (!hasUserEverPushed) {
- setCheckDocsPopUpVisible(true);
- await registerUserAction({ action: "first_time_secrets_pushed" });
+ if (duplicatesExist) {
+ return createNotification({
+ text: "Your secrets weren't saved; please fix the conflicts first.",
+ type: "error",
+ });
+ }
+
+ // Once "Save changed is clicked", disable that button
+ setButtonReady(false);
+ pushKeys({ obj, workspaceId: router.query.id, env });
+
+ /**
+ * Check which integrations are active for this project and environment
+ * If there are any, update environment variables for those integrations
+ */
+ let integrations = await getWorkspaceIntegrations({
+ workspaceId: router.query.id,
+ });
+ integrations.map(async (integration) => {
+ if (
+ envMapping[env] == integration.environment &&
+ integration.isActive == true
+ ) {
+ let objIntegration = Object.assign(
+ {},
+ ...data.map((row) => ({ [row[2]]: row[3] }))
+ );
+ await pushKeysIntegration({
+ obj: objIntegration,
+ integrationId: integration._id,
+ });
}
+ });
+
+ // If this user has never saved environment variables before, show them a prompt to read docs
+ if (!hasUserEverPushed) {
+ setCheckDocsPopUpVisible(true);
+ await registerUserAction({ action: "first_time_secrets_pushed" });
}
};
@@ -649,7 +667,13 @@ export default function Dashboard() {
modifyKey={listenChangeKey}
modifyVisibility={listenChangeVisibility}
isBlurred={blurred}
- duplicates={data?.map(item => item[2]).filter((item, index) => index !== data?.map(item => item[2]).indexOf(item))}
+ duplicates={data
+ ?.map((item) => item[2])
+ .filter(
+ (item, index) =>
+ index !==
+ data?.map((item) => item[2]).indexOf(item)
+ )}
/>
))}
@@ -697,7 +721,13 @@ export default function Dashboard() {
modifyKey={listenChangeKey}
modifyVisibility={listenChangeVisibility}
isBlurred={blurred}
- duplicates={data?.map(item => item[2]).filter((item, index) => index !== data?.map(item => item[2]).indexOf(item))}
+ duplicates={data
+ ?.map((item) => item[2])
+ .filter(
+ (item, index) =>
+ index !==
+ data?.map((item) => item[2]).indexOf(item)
+ )}
/>
))}