Merge branch 'main' into feat-error-notifs

This commit is contained in:
asharonbaltazar
2022-12-06 13:10:31 -05:00
committed by GitHub
48 changed files with 692 additions and 394 deletions
+22
View File
@@ -0,0 +1,22 @@
name: Release Helm Charts
on: [workflow_dispatch]
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install Helm
uses: azure/setup-helm@v3
with:
version: v3.10.0
- name: Install python
uses: actions/setup-python@v4
- name: Install Cloudsmith CLI
run: pip install --upgrade cloudsmith-cli
- name: Build and push helm package to Cloudsmith
run: cd helm-charts && sh upload-to-cloudsmith.sh
env:
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}
+1 -1
View File
@@ -1,4 +1,4 @@
name: goreleaser name: Go releaser
on: on:
push: push:
+1 -1
View File
@@ -106,7 +106,7 @@ const initializeDefaultOrg = async ({
// initialize a default workspace inside the new organization // initialize a default workspace inside the new organization
const workspace = await createWorkspace({ const workspace = await createWorkspace({
name: `${user.firstName}'s Project`, name: `Example Project`,
organizationId: organization._id.toString() organizationId: organization._id.toString()
}); });
+1 -1
View File
@@ -15,7 +15,7 @@ var rootCmd = &cobra.Command{
Short: "Infisical CLI is used to inject environment variables into any process", Short: "Infisical CLI is used to inject environment variables into any process",
Long: `Infisical is a simple, end-to-end encrypted service that enables teams to sync and manage their environment variables across their development life cycle.`, Long: `Infisical is a simple, end-to-end encrypted service that enables teams to sync and manage their environment variables across their development life cycle.`,
CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true}, CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true},
Version: "0.1.5", Version: "0.1.6",
} }
// Execute adds all child commands to the root command and sets flags appropriately. // Execute adds all child commands to the root command and sets flags appropriately.
+16
View File
@@ -0,0 +1,16 @@
---
title: "Frequently Asked Questions"
description: "Have any questions? [Join our Slack community](https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g)."
---
## Problem with SMTP
You can normally populate `SMTP_USERNAME` and `SMTP_PASSWORD` with your usual login and password (you could also create a 'burner' email). Sometimes, there still are problems.
You can go to your Gmail account settings > security and enable “less secure apps”. This would allow Infisical to use your Gmail to send emails.
If it still doesn't work, [this](https://stackoverflow.com/questions/72547853/unable-to-send-email-in-c-sharp-less-secure-app-access-not-longer-available/72553362#72553362) should help.
## `MONGO_URL` issues
Your `MONGO_URL` should be something like `mongodb://root:example@mongo:27017/?authSource=admin`. If you want to change it (not recommended), you should make sure that you keep this URL in line with `MONGO_USERNAME=root` and `MONGO_PASSWORD=example`.
+7 -3
View File
@@ -102,8 +102,11 @@
"pages": [ "pages": [
"self-hosting/overview", "self-hosting/overview",
{ {
"group": "Deployments", "group": "Deployments options",
"pages": ["self-hosting/deployments/linux"] "pages": [
"self-hosting/deployments/linux",
"self-hosting/deployments/kubernetes"
]
}, },
{ {
"group": "Configuration", "group": "Configuration",
@@ -162,7 +165,8 @@
"pages": [ "pages": [
"contributing/overview", "contributing/overview",
"contributing/code-of-conduct", "contributing/code-of-conduct",
"contributing/developing" "contributing/developing",
"contributing/FAQ"
] ]
} }
], ],
@@ -0,0 +1,54 @@
---
title: "Kubernetes"
description: "Deploy with Kubernetes"
---
<Info>
Self-host vs. Infisical Cloud
Self-hosting Infisical means managing the service yourself, taking care of upgrades, scaling, security, etc.
If you're less technical and looking for a hands-free experience with minimal overhead then we recommend Infisical Cloud.
</Info>
**Prerequisites**
- You have understanding of [Kubernetes](https://kubernetes.io/)
- You have understanding of [Helm package manager](https://helm.sh/)
- You have [kubectl](https://kubernetes.io/docs/reference/kubectl/kubectl/) installed and connected to your kubernetes cluster
#### 1. Fill our environment variables
Before you can deploy the Helm chart, you must fill out the required environment variables. To do so, please either download or copy the
contents of [this file](https://raw.githubusercontent.com/Infisical/infisical/main/helm-charts/infisical/values.yaml) to a `.yaml` file.
_Refer to the available [environment variables](../../self-hosting/configuration/envars)_
Once you have a local copy of the values file, fill our the required environment variables and save the file.
#### 2. Install Infisical Helm repository
```bash
helm repo add infisical-helm-charts 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/'
helm repo update
```
#### 3. Install the Helm chart
By default, the helm chart will be installed on your default namespace. If you wish to install the Chart on a different namespace, you may specify
that by adding the `--namespace <namespace-to-install-to>` to your `helm install` command.
```bash
## Installs to default namespace
helm install infisical-helm-charts/infisical --values <path to the values.yaml you downloaded/created in step 2>
```
<Note>
If you have not filled out all of the required environment variables, you will see an error message prompting you to
do so.
</Note>
4. Your Infisical installation is complete and should be running on the host name you specified in Ingress in `values.yaml`.
Note: Please allow an additional time (2 minutes) for the frontend pods to be fully ready.
+10 -5
View File
@@ -9,17 +9,22 @@ Self-hosting Infisical means managing the service yourself, taking care of upgra
If you're less technical and looking for a hands-free experience with minimal overhead then we recommend Infisical Cloud. If you're less technical and looking for a hands-free experience with minimal overhead then we recommend Infisical Cloud.
Infisical Cloud also comes with some extra features unavailabe in the self-hosted edition. You can find more information about Infisical Cloud's offering on the pricing page. Infisical Cloud also comes with some extra features unavailable in the self-hosted edition. You can find more information about Infisical Cloud's offering on the pricing page.
</Info> </Info>
## Deployment options ## Deployment options
Infisical can be deployed on a Linux VM with docker-compose. We're rolling out more specific deployment options for DigitalOcean, AWS, GCP, and Azure soon. Infisical can be deployed on a Linux VM with docker-compose and Kubernetes. We're rolling out more specific deployment options for DigitalOcean, AWS, GCP, and Azure soon.
Options: <CardGroup cols={2}>
<Card title="Any Linux" icon="square-1" color="#ea5a0c" href="/self-hosting/deployments/linux">
- [Linux VM](/self-hosting/deployments/linux) Deploy to any Linux with Docker
</Card>
<Card title="Kubernetes" icon="square-2" color="#0285c7" href="/self-hosting/deployments/kubernetes">
Deploy to your Kubernetes cluster
</Card>
</CardGroup>
## Telemetry ## Telemetry
+6 -1
View File
@@ -10,7 +10,12 @@
"rules": { "rules": {
"react-hooks/exhaustive-deps": "off", "react-hooks/exhaustive-deps": "off",
"no-unused-vars": "off", "no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "error", "@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"simple-import-sort/exports": "warn", "simple-import-sort/exports": "warn",
"simple-import-sort/imports": [ "simple-import-sort/imports": [
"warn", "warn",
@@ -1,19 +1,27 @@
import React from "react"; import React, { useState } from "react";
import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { faCircle, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
faCircle,
faCircleExclamation,
faE,
faEye,
faEyeSlash,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import guidGenerator from "../utilities/randomId"; import guidGenerator from "../utilities/randomId";
import Error from "./Error";
const InputField = (props) => { interface InputFieldProps {
static?: boolean;
label: string;
type: string;
value: string;
placeholder?: string;
isRequired: boolean;
disabled?: boolean;
error?: boolean;
text?: string;
name?: string;
blurred?: boolean;
errorText?: string;
onChangeHandler: (value: string) => void;
}
const InputField = (props: InputFieldProps) => {
const [passwordVisible, setPasswordVisible] = useState(false); const [passwordVisible, setPasswordVisible] = useState(false);
const router = useRouter(); const router = useRouter();
@@ -67,7 +75,7 @@ const InputField = (props) => {
> >
<input <input
onChange={(e) => props.onChangeHandler(e.target.value)} onChange={(e) => props.onChangeHandler(e.target.value)}
type={passwordVisible == false ? props.type : "text"} type={passwordVisible === false ? props.type : "text"}
placeholder={props.placeholder} placeholder={props.placeholder}
value={props.value} value={props.value}
required={props.isRequired} required={props.isRequired}
@@ -1,3 +1,4 @@
/* eslint-disable no-unexpected-multiline */
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import Link from "next/link"; import Link from "next/link";
@@ -19,8 +20,10 @@ import getOrganizationUsers from "~/pages/api/organization/GetOrgUsers";
import addUserToWorkspace from "~/pages/api/workspace/addUserToWorkspace"; import addUserToWorkspace from "~/pages/api/workspace/addUserToWorkspace";
import createWorkspace from "~/pages/api/workspace/createWorkspace"; import createWorkspace from "~/pages/api/workspace/createWorkspace";
import getWorkspaces from "~/pages/api/workspace/getWorkspaces"; import getWorkspaces from "~/pages/api/workspace/getWorkspaces";
import uploadKeys from "~/pages/api/workspace/uploadKeys";
import NavBarDashboard from "../navigation/NavBarDashboard"; import NavBarDashboard from "../navigation/NavBarDashboard";
import { tempLocalStorage } from "../utilities/checks/tempLocalStorage";
import { import {
decryptAssymmetric, decryptAssymmetric,
encryptAssymmetric, encryptAssymmetric,
@@ -29,13 +32,17 @@ import Button from "./buttons/Button";
import AddWorkspaceDialog from "./dialog/AddWorkspaceDialog"; import AddWorkspaceDialog from "./dialog/AddWorkspaceDialog";
import Listbox from "./Listbox"; import Listbox from "./Listbox";
export default function Layout({ children }) { interface LayoutProps {
children: React.ReactNode;
}
export default function Layout({ children }: LayoutProps) {
const router = useRouter(); const router = useRouter();
const [workspaceList, setWorkspaceList] = useState([]); const [workspaceList, setWorkspaceList] = useState([]);
const [workspaceMapping, setWorkspaceMapping] = useState([{ 1: 2 }]); const [workspaceMapping, setWorkspaceMapping] = useState([{ 1: 2 }]);
const [workspaceSelected, setWorkspaceSelected] = useState("∞"); const [workspaceSelected, setWorkspaceSelected] = useState("∞");
let [newWorkspaceName, setNewWorkspaceName] = useState(""); const [newWorkspaceName, setNewWorkspaceName] = useState("");
let [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState(false); const [error, setError] = useState(false);
@@ -43,165 +50,186 @@ export default function Layout({ children }) {
setIsOpen(false); setIsOpen(false);
} }
function openModal() {
setIsOpen(true);
}
// TODO: what to do about the fact that 2ids can have the same name // TODO: what to do about the fact that 2ids can have the same name
/** /**
* When a user creates a new workspace, redirect them to the page of the new workspace. * When a user creates a new workspace, redirect them to the page of the new workspace.
* @param {*} workspaceName * @param {*} workspaceName
*/ */
async function submitModal(workspaceName, addAllUsers) { async function submitModal(workspaceName: string, addAllUsers: boolean) {
setLoading(true); setLoading(true);
// timeout code.
setTimeout(() => setLoading(false), 1500); setTimeout(() => setLoading(false), 1500);
const workspaces = await getWorkspaces();
const currentWorkspaces = workspaces.map((workspace) => workspace.name); try {
if (!currentWorkspaces.includes(workspaceName)) { const workspaces = await getWorkspaces();
const newWorkspace = await createWorkspace( const currentWorkspaces = workspaces.map((workspace) => workspace.name);
workspaceName, if (!currentWorkspaces.includes(workspaceName)) {
localStorage.getItem("orgData.id") const newWorkspace = await createWorkspace({
); workspaceName,
let newWorkspaceId; organizationId: tempLocalStorage("orgData.id"),
try {
newWorkspaceId = newWorkspace._id;
} catch (error) {
console.log(error);
}
if (addAllUsers) {
let orgUsers = await getOrganizationUsers({
orgId: localStorage.getItem("orgData.id"),
}); });
orgUsers.map(async (user) => { const newWorkspaceId = newWorkspace._id;
if (user.status == "accepted") {
let result = await addUserToWorkspace(
user.user.email,
newWorkspaceId
);
if (result?.invitee && result?.latestKey) {
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY");
// assymmetrically decrypt symmetric key with local private key if (addAllUsers) {
const key = decryptAssymmetric({ const orgUsers = await getOrganizationUsers({
ciphertext: result.latestKey.encryptedKey, orgId: tempLocalStorage("orgData.id"),
nonce: result.latestKey.nonce, });
publicKey: result.latestKey.sender.publicKey, orgUsers.map(async (user: any) => {
privateKey: PRIVATE_KEY, if (user.status == "accepted") {
}); const result = await addUserToWorkspace(
user.user.email,
newWorkspaceId
);
if (result?.invitee && result?.latestKey) {
const PRIVATE_KEY = tempLocalStorage("PRIVATE_KEY");
const { ciphertext, nonce } = encryptAssymmetric({ // assymmetrically decrypt symmetric key with local private key
plaintext: key, const key = decryptAssymmetric({
publicKey: result.invitee.publicKey, ciphertext: result.latestKey.encryptedKey,
privateKey: PRIVATE_KEY, nonce: result.latestKey.nonce,
}); publicKey: result.latestKey.sender.publicKey,
privateKey: PRIVATE_KEY,
});
uploadKeys(newWorkspaceId, result.invitee._id, ciphertext, nonce); const { ciphertext, nonce } = encryptAssymmetric({
plaintext: key,
publicKey: result.invitee.publicKey,
privateKey: PRIVATE_KEY,
}) as { ciphertext: string; nonce: string };
uploadKeys(
newWorkspaceId,
result.invitee._id,
ciphertext,
nonce
);
}
} }
} });
}); }
router.push("/dashboard/" + newWorkspaceId + "?Development");
setIsOpen(false);
setNewWorkspaceName("");
} else {
console.error("A project with this name already exists.");
setError(true);
setLoading(false);
} }
router.push("/dashboard/" + newWorkspaceId + "?Development"); } catch (err) {
setIsOpen(false); console.error(err);
setNewWorkspaceName(""); setError(true);
} else {
setError("A project with this name already exists.");
setLoading(false); setLoading(false);
} }
} }
function openModal() {
setIsOpen(true);
}
const menuItems = [ const menuItems = [
{ {
href: href:
"/dashboard/" + workspaceMapping[workspaceSelected] + "?Development", "/dashboard/" +
workspaceMapping[workspaceSelected as any] +
"?Development",
title: "Secrets", title: "Secrets",
emoji: <FontAwesomeIcon icon={faKey} />, emoji: <FontAwesomeIcon icon={faKey} />,
}, },
{ {
href: "/users/" + workspaceMapping[workspaceSelected], href: "/users/" + workspaceMapping[workspaceSelected as any],
title: "Members", title: "Members",
emoji: <FontAwesomeIcon icon={faUser} />, emoji: <FontAwesomeIcon icon={faUser} />,
}, },
{ {
href: "/integrations/" + workspaceMapping[workspaceSelected], href: "/integrations/" + workspaceMapping[workspaceSelected as any],
title: "Integrations", title: "Integrations",
emoji: <FontAwesomeIcon icon={faPlug} />, emoji: <FontAwesomeIcon icon={faPlug} />,
}, },
{ {
href: "/settings/project/" + workspaceMapping[workspaceSelected], href: "/settings/project/" + workspaceMapping[workspaceSelected as any],
title: "Project Settings", title: "Project Settings",
emoji: <FontAwesomeIcon icon={faGear} />, emoji: <FontAwesomeIcon icon={faGear} />,
}, },
]; ];
useEffect(async () => { useEffect(() => {
// Put a user in a workspace if they're not in one yet // Put a user in a workspace if they're not in one yet
if ( const putUserInWorkSpace = async () => {
localStorage.getItem("orgData.id") == null || if (tempLocalStorage("orgData.id") === "") {
localStorage.getItem("orgData.id") == "" const userOrgs = await getOrganizations();
) { localStorage.setItem("orgData.id", userOrgs[0]._id);
const userOrgs = await getOrganizations();
localStorage.setItem("orgData.id", userOrgs[0]._id);
}
let orgUserProjects = await getOrganizationUserProjects({
orgId: localStorage.getItem("orgData.id"),
});
let userWorkspaces = orgUserProjects;
if (
userWorkspaces.length == 0 &&
router.asPath != "/noprojects" &&
!router.asPath.includes("settings")
) {
router.push("/noprojects");
} else if (router.asPath != "/noprojects") {
const intendedWorkspaceId = router.asPath
.split("/")
[router.asPath.split("/").length - 1].split("?")[0];
// If a user is not a member of a workspace they are trying to access, just push them to one of theirs
if (
intendedWorkspaceId != "heroku" &&
!userWorkspaces
.map((workspace) => workspace._id)
.includes(intendedWorkspaceId)
) {
router.push("/dashboard/" + userWorkspaces[0]._id + "?Development");
} else {
setWorkspaceList(userWorkspaces.map((workspace) => workspace.name));
setWorkspaceMapping(
Object.fromEntries(
userWorkspaces.map((workspace) => [workspace.name, workspace._id])
)
);
setWorkspaceSelected(
Object.fromEntries(
userWorkspaces.map((workspace) => [workspace._id, workspace.name])
)[
router.asPath
.split("/")
[router.asPath.split("/").length - 1].split("?")[0]
]
);
} }
}
const orgUserProjects = await getOrganizationUserProjects({
orgId: tempLocalStorage("orgData.id"),
});
const userWorkspaces = orgUserProjects;
if (
userWorkspaces.length == 0 &&
router.asPath != "/noprojects" &&
!router.asPath.includes("settings")
) {
router.push("/noprojects");
} else if (router.asPath != "/noprojects") {
const intendedWorkspaceId = router.asPath
.split("/")
[router.asPath.split("/").length - 1].split("?")[0];
// If a user is not a member of a workspace they are trying to access, just push them to one of theirs
if (
intendedWorkspaceId != "heroku" &&
!userWorkspaces
.map((workspace: { _id: string }) => workspace._id)
.includes(intendedWorkspaceId)
) {
router.push("/dashboard/" + userWorkspaces[0]._id + "?Development");
} else {
setWorkspaceList(
userWorkspaces.map((workspace: any) => workspace.name)
);
setWorkspaceMapping(
Object.fromEntries(
userWorkspaces.map((workspace: any) => [
workspace.name,
workspace._id,
])
) as any
);
setWorkspaceSelected(
Object.fromEntries(
userWorkspaces.map((workspace: any) => [
workspace._id,
workspace.name,
])
)[
router.asPath
.split("/")
[router.asPath.split("/").length - 1].split("?")[0]
]
);
}
}
};
putUserInWorkSpace();
}, []); }, []);
useEffect(() => { useEffect(() => {
try { try {
if ( if (
workspaceMapping[workspaceSelected] && workspaceMapping[Number(workspaceSelected)] &&
workspaceMapping[workspaceSelected] !== `${workspaceMapping[Number(workspaceSelected)]}` !==
router.asPath router.asPath
.split("/") .split("/")
[router.asPath.split("/").length - 1].split("?")[0] [router.asPath.split("/").length - 1].split("?")[0]
) { ) {
router.push( router.push(
"/dashboard/" + workspaceMapping[workspaceSelected] + "?Development" "/dashboard/" +
workspaceMapping[Number(workspaceSelected)] +
"?Development"
); );
localStorage.setItem( localStorage.setItem(
"projectData.id", "projectData.id",
workspaceMapping[workspaceSelected] `${workspaceMapping[Number(workspaceSelected)]}`
); );
} }
} catch (error) { } catch (error) {
@@ -218,18 +246,18 @@ export default function Layout({ children }) {
<nav className="flex flex-col justify-between items-between h-full"> <nav className="flex flex-col justify-between items-between h-full">
{/* <div className="py-6"></div> */} {/* <div className="py-6"></div> */}
<div> <div>
<div className="flex justify-center w-full mt-[4.5rem] mb-6 bg-bunker-600 w-full h-20 flex flex-col items-center px-4"> <div className="flex justify-center w-full mt-[4.5rem] mb-6 bg-bunker-600 h-20 flex-col items-center px-4">
<div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide"> <div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
PROJECT PROJECT
</div> </div>
{workspaceList.length > 0 ? ( {workspaceList.length > 0 ? (
<Listbox <Listbox
selected={workspaceSelected} selected={workspaceSelected}
onChange={setWorkspaceSelected} onChange={setWorkspaceSelected as any}
data={workspaceList} data={workspaceList}
buttonAction={openModal} buttonAction={openModal}
text="" text=""
workspaceMapping={workspaceMapping} // workspaceMapping={workspaceMapping as any}
/> />
) : ( ) : (
<Button <Button
@@ -255,12 +283,18 @@ export default function Layout({ children }) {
className={`flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10`} className={`flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10`}
> >
<div className="absolute top-0 my-1 ml-1 inset-0 bg-primary w-1 rounded-xl mr-1"></div> <div className="absolute top-0 my-1 ml-1 inset-0 bg-primary w-1 rounded-xl mr-1"></div>
<p className="w-6 ml-4 mr-2 flex items-center justify-center text-lg">{emoji}</p> <p className="w-6 ml-4 mr-2 flex items-center justify-center text-lg">
{emoji}
</p>
{title} {title}
</div> </div>
) : router.asPath == "/noprojects" ? ( ) : router.asPath == "/noprojects" ? (
<div className={`flex p-2.5 text-white text-sm rounded`}> <div
<p className="w-10 flex items-center justify-center text-lg">{emoji}</p> className={`flex p-2.5 text-white text-sm rounded`}
>
<p className="w-10 flex items-center justify-center text-lg">
{emoji}
</p>
{title} {title}
</div> </div>
) : ( ) : (
@@ -268,7 +302,9 @@ export default function Layout({ children }) {
<div <div
className={`flex p-2.5 text-white text-sm rounded cursor-pointer hover:bg-primary-50/5`} className={`flex p-2.5 text-white text-sm rounded cursor-pointer hover:bg-primary-50/5`}
> >
<p className="w-10 flex items-center justify-center text-lg">{emoji}</p> <p className="w-10 flex items-center justify-center text-lg">
{emoji}
</p>
{title} {title}
</div> </div>
</Link> </Link>
@@ -283,15 +319,21 @@ export default function Layout({ children }) {
className={`flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10`} className={`flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10`}
> >
<div className="absolute top-0 my-1 ml-1 inset-0 bg-primary w-1 rounded-xl mr-1"></div> <div className="absolute top-0 my-1 ml-1 inset-0 bg-primary w-1 rounded-xl mr-1"></div>
<p className="w-6 ml-4 mr-2 flex items-center justify-center text-lg"><FontAwesomeIcon icon={faBookOpen}/></p> <p className="w-6 ml-4 mr-2 flex items-center justify-center text-lg">
<FontAwesomeIcon icon={faBookOpen} />
</p>
Infisical Guide Infisical Guide
</div> </div>
) : ( ) : (
<Link href={`/home/` + workspaceMapping[workspaceSelected]}> <Link
href={`/home/` + workspaceMapping[workspaceSelected as any]}
>
<div <div
className={`flex p-2.5 text-white text-sm rounded cursor-pointer hover:bg-primary-50/5 mt-max border border-dashed border-bunker-400`} className={`flex p-2.5 text-white text-sm rounded cursor-pointer hover:bg-primary-50/5 mt-max border border-dashed border-bunker-400`}
> >
<p className="w-10 flex items-center justify-center text-lg"><FontAwesomeIcon icon={faBookOpen}/></p> <p className="w-10 flex items-center justify-center text-lg">
<FontAwesomeIcon icon={faBookOpen} />
</p>
Infisical Guide Infisical Guide
</div> </div>
</Link> </Link>
@@ -311,7 +353,7 @@ export default function Layout({ children }) {
<main className="flex-1 bg-bunker-800">{children}</main> <main className="flex-1 bg-bunker-800">{children}</main>
</div> </div>
</div> </div>
<div className="block md:hidden bg-bunker-800 w-screen h-screen flex flex-col justify-center items-center"> <div className="md:hidden bg-bunker-800 w-screen h-screen flex flex-col justify-center items-center">
<FontAwesomeIcon <FontAwesomeIcon
icon={faMobile} icon={faMobile}
className="text-gray-300 text-7xl mb-8" className="text-gray-300 text-7xl mb-8"
+10 -11
View File
@@ -8,14 +8,13 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Listbox, Transition } from "@headlessui/react"; import { Listbox, Transition } from "@headlessui/react";
interface ListBoxProps {
type ListBoxProps = { selected: string;
selected: string, onChange: () => void;
onChange: () => void, data: string[];
data: string[], text: string;
text: string, buttonAction: () => void;
buttonAction: () => void, isFull?: boolean;
width: string,
} }
/** /**
@@ -35,14 +34,14 @@ export default function ListBox({
data, data,
text, text,
buttonAction, buttonAction,
width, isFull,
} : ListBoxProps): JSX.Element { }: ListBoxProps): JSX.Element {
return ( return (
<Listbox value={selected} onChange={onChange}> <Listbox value={selected} onChange={onChange}>
<div className="relative"> <div className="relative">
<Listbox.Button <Listbox.Button
className={`text-gray-400 relative ${ className={`text-gray-400 relative ${
width == "full" ? "w-full" : "w-52" isFull ? "w-full" : "w-52"
} cursor-default rounded-md bg-white/[0.07] hover:bg-white/[0.11] duration-200 py-2.5 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm`} } cursor-default rounded-md bg-white/[0.07] hover:bg-white/[0.11] duration-200 py-2.5 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm`}
> >
<div className="flex flex-row"> <div className="flex flex-row">
+6 -6
View File
@@ -6,13 +6,13 @@ import {
FontAwesomeIconProps, FontAwesomeIconProps,
} from "@fortawesome/react-fontawesome"; } from "@fortawesome/react-fontawesome";
var classNames = require("classnames"); const classNames = require("classnames");
type ButtonProps = { type ButtonProps = {
text: string; text: string;
onButtonPressed: () => void; onButtonPressed: () => void;
loading?: boolean; loading?: boolean;
color: string; color?: string;
size: string; size: string;
icon?: IconProp; icon?: IconProp;
active?: boolean; active?: boolean;
@@ -40,7 +40,7 @@ export default function Button(props: ButtonProps): JSX.Element {
const activityStatus = const activityStatus =
props.active || (props.text != "" && props.textDisabled == undefined); props.active || (props.text != "" && props.textDisabled == undefined);
let styleButton = classNames( const styleButton = classNames(
"group m-auto md:m-0 inline-block rounded-md duration-200", "group m-auto md:m-0 inline-block rounded-md duration-200",
// Setting background colors and hover modes // Setting background colors and hover modes
@@ -67,7 +67,7 @@ export default function Button(props: ButtonProps): JSX.Element {
props.size == "icon-sm" && "h-9 w-9 flex items-center justify-center" props.size == "icon-sm" && "h-9 w-9 flex items-center justify-center"
); );
let styleMainDiv = classNames( const styleMainDiv = classNames(
"relative font-medium flex items-center", "relative font-medium flex items-center",
// Setting the text color for the text and icon // Setting the text color for the text and icon
@@ -79,11 +79,11 @@ export default function Button(props: ButtonProps): JSX.Element {
props.size == "icon" && "flex items-center justify-center" props.size == "icon" && "flex items-center justify-center"
); );
let textStyle = classNames( const textStyle = classNames(
"relative duration-200", "relative duration-200",
// Show the loading sign if the loading indicator is on // Show the loading sign if the loading indicator is on
Boolean(props.loading) ? "opacity-0" : "opacity-100", props.loading ? "opacity-0" : "opacity-100",
props.size == "md" && "text-sm", props.size == "md" && "text-sm",
props.size == "lg" && "text-lg" props.size == "lg" && "text-lg"
); );
@@ -37,7 +37,7 @@ const AddServiceTokenDialog = ({
const [serviceTokenCopied, setServiceTokenCopied] = useState(false); const [serviceTokenCopied, setServiceTokenCopied] = useState(false);
const generateServiceToken = async () => { const generateServiceToken = async () => {
const latestFileKey = await getLatestFileKey(workspaceId); const latestFileKey = await getLatestFileKey({ workspaceId });
const key = decryptAssymmetric({ const key = decryptAssymmetric({
ciphertext: latestFileKey.latestKey.encryptedKey, ciphertext: latestFileKey.latestKey.encryptedKey,
+1 -1
View File
@@ -88,7 +88,7 @@ const UserTable = ({
}, [userData, myUser]); }, [userData, myUser]);
const grantAccess = async (id, publicKey) => { const grantAccess = async (id, publicKey) => {
let result = await getLatestFileKey(router.query.id); let result = await getLatestFileKey({workspaceId: router.query.id});
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY");
@@ -47,27 +47,44 @@ const supportOptions = [
], ],
]; ];
export default function Navbar({ onButtonPressed }) { export interface ICurrentOrg {
const router = useRouter(); name: string;
const [user, setUser] = useState({}); }
const [orgs, setOrgs] = useState([]);
const [currentOrg, setCurrentOrg] = useState([]);
useEffect(async () => { export interface IUser {
const userData = await getUser(); firstName: string;
setUser(userData); lastName: string;
const orgsData = await getOrganizations(); email: string;
setOrgs(orgsData); }
const currentOrg = await getOrganization({
orgId: localStorage.getItem("orgData.id"), /**
}); * This is the navigation bar in the main app.
setCurrentOrg(currentOrg); * It has two main components: support options and user menu (inlcudes billing, logout, org/user settings)
* @returns NavBar
*/
export default function Navbar() {
const router = useRouter();
const [user, setUser] = useState<IUser | undefined>();
const [orgs, setOrgs] = useState([]);
const [currentOrg, setCurrentOrg] = useState<ICurrentOrg | undefined>();
useEffect(() => {
(async () => {
const userData = await getUser();
setUser(userData);
const orgsData = await getOrganizations();
setOrgs(orgsData);
const currentOrg = await getOrganization({
orgId: String(localStorage.getItem("orgData.id")),
});
setCurrentOrg(currentOrg);
})();
}, []); }, []);
const closeApp = async () => { const closeApp = async () => {
console.log("Logging out..."); console.log("Logging out...");
await logout(); await logout();
router.push("/"); router.push("/login");
}; };
return ( return (
@@ -108,7 +125,7 @@ export default function Navbar({ onButtonPressed }) {
key={guidGenerator()} key={guidGenerator()}
target="_blank" target="_blank"
rel="noopener" rel="noopener"
href={option[2]} href={String(option[2])}
className="font-normal text-gray-300 duration-200 rounded-md w-full flex items-center py-0.5" className="font-normal text-gray-300 duration-200 rounded-md w-full flex items-center py-0.5"
> >
<div className="relative flex justify-start items-center cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/10 duration-200 hover:text-gray-200 w-full"> <div className="relative flex justify-start items-center cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/10 duration-200 hover:text-gray-200 w-full">
@@ -238,9 +255,9 @@ export default function Navbar({ onButtonPressed }) {
<div className="flex flex-col items-start px-1 mt-3 mb-2"> <div className="flex flex-col items-start px-1 mt-3 mb-2">
{orgs {orgs
.filter( .filter(
(org) => org._id != localStorage.getItem("orgData.id") (org : { _id: string }) => org._id != localStorage.getItem("orgData.id")
) )
.map((org) => ( .map((org : { _id: string; name: string; }) => (
<div <div
key={guidGenerator()} key={guidGenerator()}
onClick={() => { onClick={() => {
@@ -1,29 +1,37 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { faCcMastercard, faCcVisa } from "@fortawesome/free-brands-svg-icons";
import { import {
faAngleRight, faAngleRight,
faQuestionCircle,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { faCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import getOrganization from "~/pages/api/organization/GetOrg"; import getOrganization from "~/pages/api/organization/GetOrg";
import getWorkspaceInfo from "~/pages/api/workspace/getWorkspaceInfo"; import getProjectInfo from "~/pages/api/workspace/getProjectInfo";
export default function NavHeader({ pageName, isProjectRelated }) { /**
* This is the component at the top of almost every page.
* It shows how to navigate to a certain page.
* It future these links should also be clickable and hoverable
* @param obj
* @param obj.pageName - Name of the page
* @param obj.isProjectRelated - whether this page is related to project or now (determine if it's 2 or 3 navigation steps)
* @returns
*/
export default function NavHeader({ pageName, isProjectRelated } : { pageName: string; isProjectRelated: boolean; }): JSX.Element {
const [orgName, setOrgName] = useState(""); const [orgName, setOrgName] = useState("");
const [workspaceName, setWorkspaceName] = useState(""); const [workspaceName, setWorkspaceName] = useState("");
const router = useRouter(); const router = useRouter();
useEffect(() => { useEffect(() => {
(async () => { (async () => {
let org = await getOrganization({ const orgId = localStorage.getItem("orgData.id")
orgId: localStorage.getItem("orgData.id"), const org = await getOrganization({
orgId: orgId ? orgId : "",
}); });
setOrgName(org.name); setOrgName(org.name);
let workspace = await getWorkspaceInfo({
workspaceId: router.query.id, const workspace = await getProjectInfo({
projectId: String(router.query.id),
}); });
setWorkspaceName(workspace.name); setWorkspaceName(workspace.name);
})(); })();
@@ -3,7 +3,7 @@ import token from "~/pages/api/auth/Token";
export default class SecurityClient { export default class SecurityClient {
static #token = ""; static #token = "";
contructor() {} constructor() {}
static setToken(token) { static setToken(token) {
this.#token = token; this.#token = token;
+8 -15
View File
@@ -32,7 +32,6 @@ const attemptLogin = async (
isLogin isLogin
) => { ) => {
try { try {
let userWorkspace, userOrg;
client.init( client.init(
{ {
username: email, username: email,
@@ -43,7 +42,7 @@ const attemptLogin = async (
let serverPublicKey, salt; let serverPublicKey, salt;
try { try {
const res = await login1(email, clientPublicKey); let res = await login1(email, clientPublicKey);
res = await res.json(); res = await res.json();
serverPublicKey = res.serverPublicKey; serverPublicKey = res.serverPublicKey;
salt = res.salt; salt = res.salt;
@@ -134,20 +133,14 @@ const attemptLogin = async (
// If user is logging in for the first time, add the example keys // If user is logging in for the first time, add the example keys
if (isSignUp) { if (isSignUp) {
await pushKeys( await pushKeys({
{ obj: {
DATABASE_URL: [ DATABASE_URL: [
"mongodb+srv://${DB_USERNAME}:${DB_PASSWORD}@mongodb.net", "mongodb+srv://${DB_USERNAME}:${DB_PASSWORD}@mongodb.net",
"personal", "personal",
], ],
DB_USERNAME: [ DB_USERNAME: ["user1234", "personal"],
"user1234", DB_PASSWORD: ["ah8jak3hk8dhiu4dw7whxwe1l", "personal"],
"personal",
],
DB_PASSWORD: [
"ah8jak3hk8dhiu4dw7whxwe1l",
"personal",
],
TWILIO_AUTH_TOKEN: [ TWILIO_AUTH_TOKEN: [
"hgSIwDAKvz8PJfkj6xkzYqzGmAP3HLuG", "hgSIwDAKvz8PJfkj6xkzYqzGmAP3HLuG",
"shared", "shared",
@@ -155,9 +148,9 @@ const attemptLogin = async (
WEBSITE_URL: ["http://localhost:3000", "shared"], WEBSITE_URL: ["http://localhost:3000", "shared"],
STRIPE_SECRET_KEY: ["sk_test_7348oyho4hfq398HIUOH78", "shared"], STRIPE_SECRET_KEY: ["sk_test_7348oyho4hfq398HIUOH78", "shared"],
}, },
projectToLogin, workspaceId: projectToLogin,
"Development" env: "Development"
); });
} }
try { try {
if (email) { if (email) {
@@ -1,18 +1,21 @@
interface PasswordCheckProps {
password: string;
currentErrorCheck: boolean;
setPasswordErrorLength: (value: boolean) => void;
setPasswordErrorNumber: (value: boolean) => void;
setPasswordErrorLowerCase: (value: boolean) => void;
}
/** /**
* This function checks a user password with respect to some criteria. * This function checks a user password with respect to some criteria.
* @param {*} password
* @param {*} setPasswordError
* @param {*} setPasswordErrorMessage
* @param {*} currentErrorCheck
* @returns
*/ */
const passwordCheck = ( const passwordCheck = ({
password, password,
setPasswordErrorLength, setPasswordErrorLength,
setPasswordErrorNumber, setPasswordErrorNumber,
setPasswordErrorLowerCase, setPasswordErrorLowerCase,
currentErrorCheck currentErrorCheck,
) => { }: PasswordCheckProps) => {
let errorCheck = currentErrorCheck; let errorCheck = currentErrorCheck;
if (!password || password.length < 14) { if (!password || password.length < 14) {
setPasswordErrorLength(true); setPasswordErrorLength(true);
@@ -0,0 +1,11 @@
// this is temporary util function. create error handling logic for localStorage and delete this.
export const tempLocalStorage = (key: string) => {
const value = localStorage.getItem(key);
if (value === null || value === "") {
console.warn("No value found in localStorage for key");
return "";
}
return value;
};
@@ -108,11 +108,7 @@ const changePassword = async (
} }
); );
} catch (error) { } catch (error) {
console.log( console.log("Something went wrong during changing the password");
"Something went wrong during changing the password",
slat,
serverPublicKey
);
} }
return true; return true;
}; };
@@ -7,20 +7,30 @@ import { envMapping } from "../../../public/data/frequentConstants";
const crypto = require("crypto"); const crypto = require("crypto");
const { const {
decryptAssymmetric, decryptAssymmetric,
decryptSymmetric,
encryptSymmetric, encryptSymmetric,
encryptAssymmetric, encryptAssymmetric,
} = require("../cryptography/crypto"); } = require("../cryptography/crypto");
const nacl = require("tweetnacl"); const nacl = require("tweetnacl");
nacl.util = require("tweetnacl-util"); nacl.util = require("tweetnacl-util");
export interface IK {
publicKey: string;
userId: string;
}
const pushKeys = async (obj, workspaceId, env) => { /**
let sharedKey = await getLatestFileKey(workspaceId); * This function pushes the keys to the database after decrypting them end-to-end
* @param {object} obj
* @param {object} obj.obj - object with all the key pairs
* @param {object} obj.workspaceId - the id of a project to which a user is pushing
* @param {object} obj.env - which environment a user is pushing to
*/
const pushKeys = async({ obj, workspaceId, env }: { obj: object; workspaceId: string; env: string; }) => {
const sharedKey = await getLatestFileKey({ workspaceId });
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY");
let randomBytes; let randomBytes: string;
if (Object.keys(sharedKey).length > 0) { if (Object.keys(sharedKey).length > 0) {
// case: a (shared) key exists for the workspace // case: a (shared) key exists for the workspace
randomBytes = decryptAssymmetric({ randomBytes = decryptAssymmetric({
@@ -51,11 +61,11 @@ const pushKeys = async (obj, workspaceId, env) => {
iv: ivValue, iv: ivValue,
tag: tagValue, tag: tagValue,
} = encryptSymmetric({ } = encryptSymmetric({
plaintext: obj[key][0], plaintext: obj[key as keyof typeof obj][0],
key: randomBytes, key: randomBytes,
}); });
const visibility = obj[key][1] != null ? obj[key][1] : "personal"; const visibility = obj[key as keyof typeof obj][1] != null ? obj[key as keyof typeof obj][1] : "personal";
return { return {
ciphertextKey, ciphertextKey,
@@ -65,7 +75,7 @@ const pushKeys = async (obj, workspaceId, env) => {
ciphertextValue, ciphertextValue,
ivValue, ivValue,
tagValue, tagValue,
hashValue: crypto.createHash("sha256").update(obj[key][0]).digest("hex"), hashValue: crypto.createHash("sha256").update(obj[key as keyof typeof obj][0]).digest("hex"),
type: visibility, type: visibility,
}; };
}); });
@@ -76,7 +86,7 @@ const pushKeys = async (obj, workspaceId, env) => {
}); });
// assymmetrically encrypt key with each receiver public keys // assymmetrically encrypt key with each receiver public keys
const keys = publicKeys.map((k) => { const keys = publicKeys.map((k: IK) => {
const { ciphertext, nonce } = encryptAssymmetric({ const { ciphertext, nonce } = encryptAssymmetric({
plaintext: randomBytes, plaintext: randomBytes,
publicKey: k.publicKey, publicKey: k.publicKey,
@@ -95,7 +105,7 @@ const pushKeys = async (obj, workspaceId, env) => {
workspaceId, workspaceId,
secrets, secrets,
keys, keys,
environment: envMapping[env], environment: envMapping[env as keyof typeof envMapping],
}); });
}; };
@@ -31,8 +31,8 @@ const issueBackupPrivateKey = ({
if (res.status == 200) { if (res.status == 200) {
return res; return res;
} else { } else {
return res;
console.log("Failed to issue the backup key"); console.log("Failed to issue the backup key");
return res;
} }
}); });
}; };
@@ -3,11 +3,8 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route logs the user out. Note: the user should authorized to do this. * This route logs the user out. Note: the user should authorized to do this.
* We first try to log out - if the authorization fails (response.status = 401), we refetch the new token, and then retry * We first try to log out - if the authorization fails (response.status = 401), we refetch the new token, and then retry
* @param {*} req
* @param {*} res
* @returns
*/ */
const logout = async (req, res) => { const logout = async () => {
return SecurityClient.fetchCall("/api/v1/auth/logout", { return SecurityClient.fetchCall("/api/v1/auth/logout", {
method: "POST", method: "POST",
headers: { headers: {
@@ -15,7 +12,7 @@ const logout = async (req, res) => {
}, },
credentials: "include", credentials: "include",
}).then((res) => { }).then((res) => {
if (res.status == 200) { if (res?.status == 200) {
SecurityClient.setToken(""); SecurityClient.setToken("");
// Delete the cookie by not setting a value; Alternatively clear the local storage // Delete the cookie by not setting a value; Alternatively clear the local storage
localStorage.setItem("publicKey", ""); localStorage.setItem("publicKey", "");
@@ -2,18 +2,17 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route lets us get info about a certain org * This route lets us get info about a certain org
* @param {*} req * @param {string} orgId - the organization ID
* @param {*} res
* @returns * @returns
*/ */
const getOrganization = (req, res) => { const getOrganization = ({ orgId }: { orgId: string; }) => {
return SecurityClient.fetchCall("/api/v1/organization/" + req.orgId, { return SecurityClient.fetchCall("/api/v1/organization/" + orgId, {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
}).then(async (res) => { }).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return (await res.json()).organization; return (await res.json()).organization;
} else { } else {
console.log("Failed to get org info"); console.log("Failed to get org info");
@@ -6,7 +6,7 @@ import SecurityClient from "~/utilities/SecurityClient";
* @param {*} res * @param {*} res
* @returns * @returns
*/ */
const getOrganizationUserProjects = (req, res) => { const getOrganizationUserProjects = (req) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall(
"/api/v1/organization/" + req.orgId + "/my-workspaces", "/api/v1/organization/" + req.orgId + "/my-workspaces",
{ {
@@ -6,7 +6,7 @@ import SecurityClient from "~/utilities/SecurityClient";
* @param {string} obj.orgId - organization Id * @param {string} obj.orgId - organization Id
* @returns * @returns
*/ */
const getOrganizationUsers = ({ orgId }) => { const getOrganizationUsers = ({ orgId }: { orgId: string; }) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall(
"/api/v1/organization/" + orgId + "/users", "/api/v1/organization/" + orgId + "/users",
{ {
@@ -16,7 +16,7 @@ const getOrganizationUsers = ({ orgId }) => {
}, },
} }
).then(async (res) => { ).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return (await res.json()).users; return (await res.json()).users;
} else { } else {
console.log("Failed to get org users"); console.log("Failed to get org users");
@@ -2,18 +2,16 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route lets us get the all the orgs of a certain user. * This route lets us get the all the orgs of a certain user.
* @param {*} req
* @param {*} res
* @returns * @returns
*/ */
const getOrganizations = (req, res) => { const getOrganizations = () => {
return SecurityClient.fetchCall("/api/v1/organization", { return SecurityClient.fetchCall("/api/v1/organization", {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
}).then(async (res) => { }).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return (await res.json()).organizations; return (await res.json()).organizations;
} else { } else {
console.log("Failed to get orgs of a user"); console.log("Failed to get orgs of a user");
@@ -2,18 +2,15 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route gets the information about a specific user. * This route gets the information about a specific user.
* @param {*} req
* @param {*} res
* @returns
*/ */
const getUser = (req, res) => { const getUser = () => {
return SecurityClient.fetchCall("/api/v1/user", { return SecurityClient.fetchCall("/api/v1/user", {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
}).then(async (res) => { }).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return (await res.json()).user; return (await res.json()).user;
} else { } else {
console.log("Failed to get user info"); console.log("Failed to get user info");
@@ -1,11 +1,12 @@
import SecurityClient from "~/utilities/SecurityClient"; import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route creates a new workspace for a user. * This route creates a new workspace for a user within a certain organization.
* @param {*} workspaceName * @param {string} workspaceName - project Name
* @param {string} organizationId - org ID
* @returns * @returns
*/ */
const createWorkspace = (workspaceName, organizationId) => { const createWorkspace = ( { workspaceName, organizationId }: { workspaceName: string; organizationId: string; }) => {
return SecurityClient.fetchCall("/api/v1/workspace", { return SecurityClient.fetchCall("/api/v1/workspace", {
method: "POST", method: "POST",
headers: { headers: {
@@ -16,7 +17,7 @@ const createWorkspace = (workspaceName, organizationId) => {
organizationId: organizationId, organizationId: organizationId,
}), }),
}).then(async (res) => { }).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return (await res.json()).workspace; return (await res.json()).workspace;
} else { } else {
console.log("Failed to create a project"); console.log("Failed to create a project");
@@ -2,10 +2,10 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* Get the latest key pairs from a certain workspace * Get the latest key pairs from a certain workspace
* @param {*} workspaceId * @param {string} workspaceId
* @returns * @returns
*/ */
const getLatestFileKey = (workspaceId) => { const getLatestFileKey = ({ workspaceId } : { workspaceId: string; }) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall(
"/api/v1/key/" + workspaceId + "/latest", "/api/v1/key/" + workspaceId + "/latest",
{ {
@@ -15,7 +15,7 @@ const getLatestFileKey = (workspaceId) => {
}, },
} }
).then(async (res) => { ).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return await res.json(); return await res.json();
} else { } else {
console.log("Failed to get the latest key pairs for a certain project"); console.log("Failed to get the latest key pairs for a certain project");
@@ -2,13 +2,12 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route lets us get the information of a certain project. * This route lets us get the information of a certain project.
* @param {*} req * @param {*} projectId - project ID (we renamed workspaces to projects in the app)
* @param {*} res
* @returns * @returns
*/ */
const getWorkspaceInfo = (req, res) => { const getProjectInfo = ({ projectId }: { projectId: string; }) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall(
"/api/v1/workspace/" + req.workspaceId, "/api/v1/workspace/" + projectId,
{ {
method: "GET", method: "GET",
headers: { headers: {
@@ -16,7 +15,7 @@ const getWorkspaceInfo = (req, res) => {
}, },
} }
).then(async (res) => { ).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return (await res.json()).workspace; return (await res.json()).workspace;
} else { } else {
console.log("Failed to get project info"); console.log("Failed to get project info");
@@ -24,4 +23,4 @@ const getWorkspaceInfo = (req, res) => {
}); });
}; };
export default getWorkspaceInfo; export default getProjectInfo;
@@ -2,13 +2,12 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route lets us get the public keys of everyone in your workspace. * This route lets us get the public keys of everyone in your workspace.
* @param {*} req * @param {string} workspaceId
* @param {*} res
* @returns * @returns
*/ */
const getWorkspaceKeys = (req, res) => { const getWorkspaceKeys = ({ workspaceId }: { workspaceId: string; }) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall(
"/api/v1/workspace/" + req.workspaceId + "/keys", "/api/v1/workspace/" + workspaceId + "/keys",
{ {
method: "GET", method: "GET",
headers: { headers: {
@@ -16,7 +15,7 @@ const getWorkspaceKeys = (req, res) => {
}, },
} }
).then(async (res) => { ).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return (await res.json()).publicKeys; return (await res.json()).publicKeys;
} else { } else {
console.log("Failed to get the public keys of everyone in the workspace"); console.log("Failed to get the public keys of everyone in the workspace");
@@ -2,13 +2,12 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route lets us get all the users in the workspace. * This route lets us get all the users in the workspace.
* @param {*} req * @param {string} workspaceId - workspace ID
* @param {*} res
* @returns * @returns
*/ */
const getWorkspaceUsers = (req, res) => { const getWorkspaceUsers = ({ workspaceId }: { workspaceId: string; }) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall(
"/api/v1/workspace/" + req.workspaceId + "/users", "/api/v1/workspace/" + workspaceId + "/users",
{ {
method: "GET", method: "GET",
headers: { headers: {
@@ -16,7 +15,7 @@ const getWorkspaceUsers = (req, res) => {
}, },
} }
).then(async (res) => { ).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return (await res.json()).users; return (await res.json()).users;
} else { } else {
console.log("Failed to get Project Users"); console.log("Failed to get Project Users");
@@ -1,24 +0,0 @@
import SecurityClient from "~/utilities/SecurityClient";
/**
* This route lets us get the public keys of everyone in your workspace.
* @param {*} req
* @param {*} res
* @returns
*/
const getWorkspaces = (req, res) => {
return SecurityClient.fetchCall("/api/v1/workspace", {
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");
}
});
};
export default getWorkspaces;
@@ -0,0 +1,31 @@
import SecurityClient from "~/utilities/SecurityClient";
interface Workspaces {
__v: number;
_id: string;
name: string;
organization: string;
}
[];
/**
* This route lets us get the workspaces of a certain user
* @returns
*/
const getWorkspaces = () => {
return SecurityClient.fetchCall("/api/v1/workspace", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
}).then(async (res) => {
if (res?.status == 200) {
const data = (await res.json()) as unknown as { workspaces: Workspaces };
return data.workspaces;
}
throw new Error("Failed to get projects");
});
};
export default getWorkspaces;
+7 -7
View File
@@ -98,22 +98,22 @@ export default function Home() {
useEffect(() => { useEffect(() => {
const checkUserActionsFunction = async () => { const checkUserActionsFunction = async () => {
let userActionSlack = await checkUserAction({ const userActionSlack = await checkUserAction({
action: "slack_cta_clicked", action: "slack_cta_clicked",
}); });
setHasUserClickedSlack(userActionSlack ? true : false); setHasUserClickedSlack(userActionSlack ? true : false);
let userActionIntro = await checkUserAction({ const userActionIntro = await checkUserAction({
action: "intro_cta_clicked", action: "intro_cta_clicked",
}); });
setHasUserClickedIntro(userActionIntro ? true : false); setHasUserClickedIntro(userActionIntro ? true : false);
let userActionStar = await checkUserAction({ const userActionStar = await checkUserAction({
action: "star_cta_clicked", action: "star_cta_clicked",
}); });
setHasUserStarred(userActionStar ? true : false); setHasUserStarred(userActionStar ? true : false);
let orgId = localStorage.getItem("orgData.id"); const orgId = localStorage.getItem("orgData.id");
const orgUsers = await getOrganizationUsers({ const orgUsers = await getOrganizationUsers({
orgId: orgId ? orgId : "", orgId: orgId ? orgId : "",
}); });
@@ -123,9 +123,9 @@ export default function Home() {
}, []); }, []);
return ( return (
<div className="mx-6 lg:mx-0 w-full overflow-y-scroll pt-28 h-screen"> <div className="mx-6 lg:mx-0 w-full overflow-y-scroll pt-20 h-screen">
<div className="flex flex-col items-center text-gray-300 text-lg mx-auto max-w-2xl lg:max-w-3xl xl:max-w-4xl"> <div className="flex flex-col items-center text-gray-300 text-lg mx-auto max-w-2xl lg:max-w-3xl xl:max-w-4xl py-6">
<div className="text-3xl font-bold text-left w-full pt-6">Your quick start guide</div> <div className="text-3xl font-bold text-left w-full">Your quick start guide</div>
<div className="text-md text-left w-full pt-2 pb-4 text-bunker-300">Click on the items below and follow the instructions.</div> <div className="text-md text-left w-full pt-2 pb-4 text-bunker-300">Click on the items below and follow the instructions.</div>
{learningItem({ text: "Get to know Infisical", subText: "", complete: hasUserClickedIntro, icon: faHandPeace, time: "3 min", userAction: "intro_cta_clicked", link: "https://www.youtube.com/watch?v=JS3OKYU2078" })} {learningItem({ text: "Get to know Infisical", subText: "", complete: hasUserClickedIntro, icon: faHandPeace, time: "3 min", userAction: "intro_cta_clicked", link: "https://www.youtube.com/watch?v=JS3OKYU2078" })}
{learningItem({ text: "Add your secrets", subText: "Click to see example secrets, and add your own.", complete: false, icon: faPlus, time: "2 min", userAction: "first_time_secrets_pushed", link: "/dashboard/" + router.query.id })} {learningItem({ text: "Add your secrets", subText: "Click to see example secrets, and add your own.", complete: false, icon: faPlus, time: "2 min", userAction: "first_time_secrets_pushed", link: "/dashboard/" + router.query.id })}
@@ -1,4 +1,5 @@
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import ReactCodeInput from "react-code-input";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import Head from "next/head"; import Head from "next/head";
import Image from "next/image"; import Image from "next/image";
@@ -20,7 +21,7 @@ import completeAccountInformationSignup from "./api/auth/CompleteAccountInformat
import sendVerificationEmail from "./api/auth/SendVerificationEmail"; import sendVerificationEmail from "./api/auth/SendVerificationEmail";
import getWorkspaces from "./api/workspace/getWorkspaces"; import getWorkspaces from "./api/workspace/getWorkspaces";
const ReactCodeInput = dynamic(import("react-code-input")); // const ReactCodeInput = dynamic(import("react-code-input"));
const nacl = require("tweetnacl"); const nacl = require("tweetnacl");
const jsrp = require("jsrp"); const jsrp = require("jsrp");
nacl.util = require("tweetnacl-util"); nacl.util = require("tweetnacl-util");
@@ -42,7 +43,7 @@ const props = {
border: "1px solid gray", border: "1px solid gray",
textAlign: "center", textAlign: "center",
}, },
}; } as const;
const propsPhone = { const propsPhone = {
inputStyle: { inputStyle: {
fontFamily: "monospace", fontFamily: "monospace",
@@ -58,7 +59,7 @@ const propsPhone = {
border: "1px solid gray", border: "1px solid gray",
textAlign: "center", textAlign: "center",
}, },
}; } as const;
export default function SignUp() { export default function SignUp() {
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
@@ -85,15 +86,16 @@ export default function SignUp() {
const [verificationToken, setVerificationToken] = useState(); const [verificationToken, setVerificationToken] = useState();
const [backupKeyIssued, setBackupKeyIssued] = useState(false); const [backupKeyIssued, setBackupKeyIssued] = useState(false);
useEffect(async () => { useEffect(() => {
let userWorkspace; const tryAuth = async () => {
try { try {
const userWorkspaces = await getWorkspaces(); const userWorkspaces = await getWorkspaces();
userWorkspace = userWorkspaces[0]._id; router.push("/dashboard/" + userWorkspaces[0]._id);
router.push("/dashboard/" + userWorkspace); } catch (error) {
} catch (error) { console.log("Error - Not logged in yet");
console.log("Error - Not logged in yet"); }
} };
tryAuth();
}, []); }, []);
/** /**
@@ -108,7 +110,7 @@ export default function SignUp() {
} else if (step == 2) { } else if (step == 2) {
// Checking if the code matches the email. // Checking if the code matches the email.
const response = await checkEmailVerificationCode(email, code); const response = await checkEmailVerificationCode(email, code);
if (response.status == "200" || code == "111222") { if (response.status === 200 || code == "111222") {
setVerificationToken((await response.json()).token); setVerificationToken((await response.json()).token);
setStep(3); setStep(3);
} else { } else {
@@ -123,7 +125,7 @@ export default function SignUp() {
* Verifies if the entered email "looks" correct * Verifies if the entered email "looks" correct
*/ */
const emailCheck = () => { const emailCheck = () => {
var emailCheckBool = false; let emailCheckBool = false;
if (!email) { if (!email) {
setEmailError(true); setEmailError(true);
setEmailErrorMessage("Please enter your email."); setEmailErrorMessage("Please enter your email.");
@@ -150,7 +152,7 @@ export default function SignUp() {
// Verifies if the imformation that the users entered (name, workspace) is there, and if the password matched the criteria. // Verifies if the imformation that the users entered (name, workspace) is there, and if the password matched the criteria.
const signupErrorCheck = async () => { const signupErrorCheck = async () => {
setIsLoading(true); setIsLoading(true);
var errorCheck = false; let errorCheck = false;
if (!firstName) { if (!firstName) {
setFirstNameError(true); setFirstNameError(true);
errorCheck = true; errorCheck = true;
@@ -163,13 +165,13 @@ export default function SignUp() {
} else { } else {
setLastNameError(false); setLastNameError(false);
} }
errorCheck = passwordCheck( errorCheck = passwordCheck({
password, password,
setPasswordErrorLength, setPasswordErrorLength,
setPasswordErrorNumber, setPasswordErrorNumber,
setPasswordErrorLowerCase, setPasswordErrorLowerCase,
errorCheck currentErrorCheck: errorCheck,
); });
if (!errorCheck) { if (!errorCheck) {
// Generate a random pair of a public and a private key // Generate a random pair of a public and a private key
@@ -187,7 +189,8 @@ export default function SignUp() {
32 + (password.slice(0, 32).length - new Blob([password]).size), 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( client.init(
@@ -196,45 +199,47 @@ export default function SignUp() {
password: password, password: password,
}, },
async () => { async () => {
client.createVerifier(async (err, result) => { client.createVerifier(
const response = await completeAccountInformationSignup({ async (err: any, result: { salt: string; verifier: string }) => {
email, const response = await completeAccountInformationSignup({
firstName, email,
lastName, firstName,
organizationName: firstName + "'s organization", lastName,
publicKey: PUBLIC_KEY, organizationName: firstName + "'s organization",
ciphertext, publicKey: PUBLIC_KEY,
iv, ciphertext,
tag, iv,
salt: result.salt, tag,
verifier: result.verifier, salt: result.salt,
token: verificationToken, verifier: result.verifier,
}); token: verificationToken,
});
// if everything works, go the main dashboard page. // if everything works, go the main dashboard page.
if (!errorCheck && response.status == "200") { if (response.status === 200) {
response = await response.json(); // response = await response.json();
localStorage.setItem("publicKey", PUBLIC_KEY); localStorage.setItem("publicKey", PUBLIC_KEY);
localStorage.setItem("encryptedPrivateKey", ciphertext); localStorage.setItem("encryptedPrivateKey", ciphertext);
localStorage.setItem("iv", iv); localStorage.setItem("iv", iv);
localStorage.setItem("tag", tag); localStorage.setItem("tag", tag);
try { try {
await attemptLogin( await attemptLogin(
email, email,
password, password,
setErrorLogin, setErrorLogin,
router, router,
true, true,
false false
); );
incrementStep(); incrementStep();
} catch (error) { } catch (error) {
setIsLoading(false); setIsLoading(false);
}
} }
} }
}); );
} }
); );
} else { } else {
@@ -296,6 +301,8 @@ export default function SignUp() {
</p> </p>
<div className="hidden md:block"> <div className="hidden md:block">
<ReactCodeInput <ReactCodeInput
name=""
inputMode="tel"
type="text" type="text"
fields={6} fields={6}
onChange={setCode} onChange={setCode}
@@ -305,6 +312,8 @@ export default function SignUp() {
</div> </div>
<div className="block md:hidden"> <div className="block md:hidden">
<ReactCodeInput <ReactCodeInput
name=""
inputMode="tel"
type="text" type="text"
fields={6} fields={6}
onChange={setCode} onChange={setCode}
@@ -364,15 +373,15 @@ export default function SignUp() {
<div className="mt-2 flex flex-col items-center justify-center w-full md:p-2 rounded-lg max-h-60"> <div className="mt-2 flex flex-col items-center justify-center w-full md:p-2 rounded-lg max-h-60">
<InputField <InputField
label="Password" label="Password"
onChangeHandler={(password) => { onChangeHandler={(password: string) => {
setPassword(password); setPassword(password);
passwordCheck( passwordCheck({
password, password,
setPasswordErrorLength, setPasswordErrorLength,
setPasswordErrorNumber, setPasswordErrorNumber,
setPasswordErrorLowerCase, setPasswordErrorLowerCase,
false currentErrorCheck: false,
); });
}} }}
type="password" type="password"
value={password} value={password}
@@ -496,7 +505,7 @@ export default function SignUp() {
setBackupKeyIssued, setBackupKeyIssued,
}); });
const userWorkspaces = await getWorkspaces(); const userWorkspaces = await getWorkspaces();
let userWorkspace = userWorkspaces[0]._id; const userWorkspace = userWorkspaces[0]._id;
router.push("/home/" + userWorkspace); router.push("/home/" + userWorkspace);
}} }}
size="lg" size="lg"
+2 -2
View File
@@ -92,7 +92,7 @@ export default function SignupInvite() {
}, },
async () => { async () => {
client.createVerifier(async (err, result) => { client.createVerifier(async (err, result) => {
const response = await completeAccountInformationSignupInvite({ let response = await completeAccountInformationSignupInvite({
email, email,
firstName, firstName,
lastName, lastName,
@@ -291,7 +291,7 @@ export default function SignupInvite() {
<div className="py-2"></div> <div className="py-2"></div>
)} )}
</div> </div>
<div className="flex flex-col items-center justify-center w-full md:px-4 md:py-5 mt-2 px-2 py-3 max-h-24 max-w-md mx-auto text-lg"> <div className="flex flex-col items-center justify-center md:px-4 md:py-5 mt-2 px-2 py-3 max-h-24 max-w-max mx-auto text-lg">
<Button <Button
text="Sign Up" text="Sign Up"
onButtonPressed={() => { onButtonPressed={() => {
+16
View File
@@ -0,0 +1,16 @@
### helm repository Setup
Assuming you have helm already installed, it is straight-forward to add a Cloudsmith-based chart repository:
```
helm repo add infisical-helm-charts 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/'
helm repo update
```
### Installing a Helm Chart
```
helm install infisical-helm-charts/<name-of-helm-chart>
```
#### Available chart names
- infisical
@@ -4,7 +4,6 @@ metadata:
name: {{ .Release.Name }}-backend-deployment name: {{ .Release.Name }}-backend-deployment
labels: labels:
app: backend app: backend
namespace: {{ .Values.namespace }}
spec: spec:
replicas: {{ .Values.backend.replicaCount }} replicas: {{ .Values.backend.replicaCount }}
selector: selector:
@@ -23,6 +22,9 @@ spec:
- containerPort: 4000 - containerPort: 4000
env: env:
{{- range $key, $value := .Values.secrets }} {{- range $key, $value := .Values.secrets }}
{{- if eq $value "MUST_REPLACE" }}
{{ fail "Environment variables are not set. Please set all environment variables to continue." }}
{{ end }}
- name: {{ $key }} - name: {{ $key }}
value: {{ $value }} value: {{ $value }}
{{- end }} {{- end }}
@@ -32,7 +34,6 @@ apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: infisical-backend-service name: infisical-backend-service
namespace: {{ .Values.namespace }}
spec: spec:
selector: selector:
app: backend app: backend
@@ -4,7 +4,6 @@ metadata:
name: {{ .Release.Name }}-frontend-deployment name: {{ .Release.Name }}-frontend-deployment
labels: labels:
app: frontend app: frontend
namespace: {{ .Values.namespace }}
spec: spec:
replicas: {{ .Values.frontend.replicaCount }} replicas: {{ .Values.frontend.replicaCount }}
selector: selector:
@@ -26,7 +25,6 @@ apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: infisical-frontend-service name: infisical-frontend-service
namespace: {{ .Values.namespace }}
spec: spec:
selector: selector:
app: frontend app: frontend
+7 -6
View File
@@ -1,8 +1,8 @@
{{ if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1 apiVersion: networking.k8s.io/v1
kind: Ingress kind: Ingress
metadata: metadata:
name: infisical-ingress name: infisical-ingress
namespace: {{ .Values.namespace }}
{{- with .Values.ingress.annotations }} {{- with .Values.ingress.annotations }}
annotations: annotations:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
@@ -22,17 +22,18 @@ spec:
- host: {{ .Values.ingress.hostName}} - host: {{ .Values.ingress.hostName}}
http: http:
paths: paths:
- path: / - path: {{ .Values.ingress.frontend.path }}
pathType: Prefix pathType: {{ .Values.ingress.frontend.pathType }}
backend: backend:
service: service:
name: infisical-frontend-service name: infisical-frontend-service
port: port:
number: 3000 number: 3000
- path: /api - path: {{ .Values.ingress.backend.path }}
pathType: Prefix pathType: {{ .Values.ingress.backend.pathType }}
backend: backend:
service: service:
name: infisical-backend-service name: infisical-backend-service
port: port:
number: 4000 number: 4000
{{ end }}
@@ -0,0 +1,38 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: mongodb-deployment
labels:
app: mongodb
spec:
replicas: 1 # Cannot be scaled. To scale, you must set up Stateful Set
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongodb
image: mongo
ports:
- containerPort: 27017
env:
- name: MONGO_INITDB_ROOT_USERNAME
value: root
- name: MONGO_INITDB_ROOT_PASSWORD
value: root
---
apiVersion: v1
kind: Service
metadata:
name: mongodb-service
spec:
selector:
app: mongodb
ports:
- protocol: TCP
port: 27017
targetPort: 27017 # container port
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: infisical
+55 -15
View File
@@ -1,3 +1,8 @@
#####
# INFISICAL K8 DEFAULT VALUES FIL
# PLEASE REPLACE VALUES/EDIT AS REQUIRED
#####
namespace: infisical namespace: infisical
frontend: frontend:
@@ -15,22 +20,57 @@ backend:
tag: "latest" tag: "latest"
ingress: ingress:
enabled: false enabled: true
annotations: [] annotations: {}
hostName: example.com hostName: example.com
tls: {} frontend:
path: /
pathType: Prefix
backend:
path: /api
pathType: Prefix
tls: []
## Complete Ingress example
# ingress:
# enabled: true
# annotations:
# kubernetes.io/ingress.class: "nginx"
# cert-manager.io/issuer: letsencrypt-nginx
# hostName: example.com
# frontend:
# path: /
# pathType: Prefix
# backend:
# path: /api
# pathType: Prefix
# tls:
# hosts:
# - k8.infisical.com
# secretName: letsencrypt-nginx
###
### YOU MUST FILL IN ALL SECRETS BELOW
###
secrets: secrets:
PRIVATE_KEY: REQUIRED # Required keys for platform encryption/decryption ops. Replace with nacl sk keys
PUBLIC_KEY: REQUIRED PRIVATE_KEY: MUST_REPLACE
ENCRYPTION_KEY: REQUIRED PUBLIC_KEY: MUST_REPLACE
JWT_SIGNUP_SECRET: REQUIRED ENCRYPTION_KEY: MUST_REPLACE
JWT_REFRESH_SECRET: REQUIRED
JWT_AUTH_SECRET: REQUIRED # JWT
NODE_ENV: development # Required secrets to sign JWT tokens
SMTP_HOST: REQUIRED JWT_SIGNUP_SECRET: MUST_REPLACE
SMTP_NAME: REQUIRED JWT_REFRESH_SECRET: MUST_REPLACE
SMTP_USERNAME: REQUIRED JWT_AUTH_SECRET: MUST_REPLACE
SMTP_PASSWORD: REQUIRED
MONGO_URL: REQUIRED # Mail/SMTP
# Required to send emails
SMTP_HOST: MUST_REPLACE
SMTP_NAME: MUST_REPLACE
SMTP_USERNAME: MUST_REPLACE
SMTP_PASSWORD: MUST_REPLACE
# You may replace with Mongo Cloud URI
MONGO_URL: mongodb://root:root@mongodb-service:27017/
+10
View File
@@ -0,0 +1,10 @@
## Loop through each helm chart directoy and build each into helm package
for d in */ ; do
helm package $d
done
## Upload each packaged helm chart
for i in *.tgz; do
[ -f "$i" ] || break
cloudsmith push helm --republish infisical/helm-charts $i
done