diff --git a/.github/images/star-infisical.gif b/.github/images/star-infisical.gif
index bb0752cb7..6d0789969 100644
Binary files a/.github/images/star-infisical.gif and b/.github/images/star-infisical.gif differ
diff --git a/.github/workflows/check-be-pull-request.yml b/.github/workflows/check-be-pull-request.yml
new file mode 100644
index 000000000..f17d8c5c8
--- /dev/null
+++ b/.github/workflows/check-be-pull-request.yml
@@ -0,0 +1,41 @@
+name: Check Backend Pull Request
+
+on:
+ pull_request:
+ types: [ opened, synchronize ]
+ paths:
+ - 'backend/**'
+ - '!backend/README.md'
+ - '!backend/.*'
+ - 'backend/.eslintrc.js'
+
+
+jobs:
+
+ check-be-pr:
+ name: Check
+ runs-on: ubuntu-latest
+
+ steps:
+ -
+ name: โ๏ธ Checkout source
+ uses: actions/checkout@v3
+ -
+ name: ๐ง Setup Node 16
+ uses: actions/setup-node@v3
+ with:
+ node-version: '16'
+ cache: 'npm'
+ cache-dependency-path: backend/package-lock.json
+ -
+ name: ๐ฆ Install dependencies
+ run: npm ci --only-production --ignore-scripts
+ working-directory: backend
+ # -
+ # name: ๐งช Run tests
+ # run: npm run test:ci
+ # working-directory: backend
+ -
+ name: ๐๏ธ Run build
+ run: npm run build
+ working-directory: backend
diff --git a/.github/workflows/check-fe-pull-request.yml b/.github/workflows/check-fe-pull-request.yml
new file mode 100644
index 000000000..b91e6f060
--- /dev/null
+++ b/.github/workflows/check-fe-pull-request.yml
@@ -0,0 +1,41 @@
+name: Check Frontend Pull Request
+
+on:
+ pull_request:
+ types: [ opened, synchronize ]
+ paths:
+ - 'frontend/**'
+ - '!frontend/README.md'
+ - '!frontend/.*'
+ - 'frontend/.eslintrc.js'
+
+
+jobs:
+
+ check-fe-pr:
+ name: Check
+ runs-on: ubuntu-latest
+
+ steps:
+ -
+ name: โ๏ธ Checkout source
+ uses: actions/checkout@v3
+ -
+ name: ๐ง Setup Node 16
+ uses: actions/setup-node@v3
+ with:
+ node-version: '16'
+ cache: 'npm'
+ cache-dependency-path: frontend/package-lock.json
+ -
+ name: ๐ฆ Install dependencies
+ run: npm ci --only-production --ignore-scripts
+ working-directory: frontend
+ # -
+ # name: ๐งช Run tests
+ # run: npm run test:ci
+ # working-directory: frontend
+ -
+ name: ๐๏ธ Run build
+ run: npm run build
+ working-directory: frontend
diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
index 770fa7e83..e85ddcfd5 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image.yml
@@ -3,35 +3,88 @@ name: Push to Docker Hub
on: [workflow_dispatch]
jobs:
- docker:
+
+ backend-image:
+ name: Build backend image
runs-on: ubuntu-latest
+
steps:
- - name: Checkout
- uses: actions/checkout@v2
+ -
+ name: โ๏ธ Checkout source
+ uses: actions/checkout@v3
-
- name: Set up QEMU
+ name: ๐ง Set up QEMU
uses: docker/setup-qemu-action@v2
-
- name: Set up Docker Buildx
+ name: ๐ง Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
- name: Login to Docker Hub
+ name: ๐ Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
+ # -
+ # name: ๐ฆ Build backend and export to Docker
+ # uses: docker/build-push-action@v3
+ # with:
+ # load: true
+ # context: backend
+ # tags: infisical/backend:test
+ # -
+ # name: ๐งช Test backend image
+ # run: |
+ # docker run --rm infisical/backend:test
-
- name: Build and push backend
+ name: ๐๏ธ Build backend and push
uses: docker/build-push-action@v3
with:
push: true
context: backend
- tags: infisical/backend:test
+ tags: infisical/backend:latest
+ platforms: linux/amd64,linux/arm64
+
+
+ frontend-image:
+ name: Build frontend image
+ runs-on: ubuntu-latest
+
+ steps:
+ -
+ name: โ๏ธ Checkout source
+ uses: actions/checkout@v3
-
- name: Build and push frontend
+ name: ๐ง Set up QEMU
+ uses: docker/setup-qemu-action@v2
+ -
+ name: ๐ง Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+ -
+ name: ๐ Login to Docker Hub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+ # -
+ # name: ๐ฆ Build frontend and export to Docker
+ # uses: docker/build-push-action@v3
+ # with:
+ # load: true
+ # context: frontend
+ # tags: infisical/frontend:test
+ # build-args: |
+ # POSTHOG_API_KEY=${{ secrets.PUBLIC_POSTHOG_API_KEY }}
+ # -
+ # name: ๐งช Test frontend image
+ # run: |
+ # docker run --rm infisical/frontend:test
+ -
+ name: ๐๏ธ Build frontend and push
uses: docker/build-push-action@v3
with:
push: true
- file: frontend/Dockerfile.dev
context: frontend
- tags: infisical/frontend:test
+ tags: infisical/frontend:latest
+ platforms: linux/amd64,linux/arm64
+ build-args: |
+ POSTHOG_API_KEY=${{ secrets.PUBLIC_POSTHOG_API_KEY }}
diff --git a/README.md b/README.md
index 4215a9fa8..4e0b7a053 100644
--- a/README.md
+++ b/README.md
@@ -48,11 +48,17 @@
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 +68,22 @@ 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!)!
+Not sure where to get started? You can:
+- [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!)!
+- Join our Slack, and ask us any questions there.
-## 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 +91,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 +269,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 +285,4 @@ Looking to report a security vulnerability? Please don't post about it in GitHub
-
+
diff --git a/backend/package-lock.json b/backend/package-lock.json
index 7e42688ef..19a42c3a1 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -10,7 +10,7 @@
"license": "ISC",
"dependencies": {
"@sentry/node": "^7.14.0",
- "@sentry/tracing": "^7.14.0",
+ "@sentry/tracing": "^7.19.0",
"@types/crypto-js": "^4.1.1",
"axios": "^1.1.3",
"bigint-conversion": "^2.2.2",
@@ -19,13 +19,13 @@
"crypto-js": "^4.1.1",
"dotenv": "^16.0.1",
"express": "^4.18.1",
- "express-rate-limit": "^6.5.1",
+ "express-rate-limit": "^6.7.0",
"express-validator": "^6.14.2",
"handlebars": "^4.7.7",
"helmet": "^5.1.1",
"jsonwebtoken": "^8.5.1",
"jsrp": "^0.2.4",
- "mongoose": "^6.7.1",
+ "mongoose": "^6.7.2",
"nodemailer": "^6.8.0",
"posthog-node": "^2.1.0",
"query-string": "^7.1.1",
@@ -33,7 +33,7 @@
"stripe": "^10.7.0",
"tweetnacl": "^1.0.3",
"tweetnacl-util": "^0.15.1",
- "typescript": "^4.8.4"
+ "typescript": "^4.9.3"
},
"devDependencies": {
"@posthog/plugin-scaffold": "^1.3.4",
@@ -2608,13 +2608,13 @@
}
},
"node_modules/@sentry/node": {
- "version": "7.17.4",
- "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.17.4.tgz",
- "integrity": "sha512-cR+Gsir9c/tzFWxvk4zXkMQy6tNRHEYixHrb88XIjZVYDqDS9l2/bKs5nJusdmaUeLtmPp5Et2o7RJyS7gvKTQ==",
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.19.0.tgz",
+ "integrity": "sha512-yG7Tx32WqOkEHVotFLrumCcT9qlaSDTkFNZ+yLSvZXx74ifsE781DzBA9W7K7bBdYO3op+p2YdsOKzf3nPpAyQ==",
"dependencies": {
- "@sentry/core": "7.17.4",
- "@sentry/types": "7.17.4",
- "@sentry/utils": "7.17.4",
+ "@sentry/core": "7.19.0",
+ "@sentry/types": "7.19.0",
+ "@sentry/utils": "7.19.0",
"cookie": "^0.4.1",
"https-proxy-agent": "^5.0.0",
"lru_map": "^0.3.3",
@@ -2624,14 +2624,80 @@
"node": ">=8"
}
},
- "node_modules/@sentry/tracing": {
- "version": "7.17.4",
- "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.17.4.tgz",
- "integrity": "sha512-9Fz6DI16ddnd970mlB5MiCNRSmSXp4SVZ1Yv3L22oS3kQeNxjBTE+htYNwJzSPrQp9aL/LqTYwlnrCy24u9XQA==",
+ "node_modules/@sentry/node/node_modules/@sentry/core": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.19.0.tgz",
+ "integrity": "sha512-YF9cTBcAnO4R44092BJi5Wa2/EO02xn2ziCtmNgAVTN2LD31a/YVGxGBt/FDr4Y6yeuVehaqijVVvtpSmXrGJw==",
"dependencies": {
- "@sentry/core": "7.17.4",
- "@sentry/types": "7.17.4",
- "@sentry/utils": "7.17.4",
+ "@sentry/types": "7.19.0",
+ "@sentry/utils": "7.19.0",
+ "tslib": "^1.9.3"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@sentry/node/node_modules/@sentry/types": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.19.0.tgz",
+ "integrity": "sha512-oGRAT6lfzoKrxO1mvxiSj0XHxWPd6Gd1wpPGuu6iJo03xgWDS+MIlD1h2unqL4N5fAzLjzmbC2D2lUw50Kn2pA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@sentry/node/node_modules/@sentry/utils": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.19.0.tgz",
+ "integrity": "sha512-2L6lq+c9Ol2uiRxQDdcgoapmHJp24MhMN0gIkn2alSfMJ+ls6bGXzQHx6JAIdoOiwFQXRZHKL9ecfAc8O+vItA==",
+ "dependencies": {
+ "@sentry/types": "7.19.0",
+ "tslib": "^1.9.3"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@sentry/tracing": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.19.0.tgz",
+ "integrity": "sha512-SWY17M3TsgBePaGowUcSqBwaT0TJQzuNexVnLojuU0k6F57L9hubvP9zaoosoCfARXQ/3NypAFWnlJyf570rFQ==",
+ "dependencies": {
+ "@sentry/core": "7.19.0",
+ "@sentry/types": "7.19.0",
+ "@sentry/utils": "7.19.0",
+ "tslib": "^1.9.3"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@sentry/tracing/node_modules/@sentry/core": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.19.0.tgz",
+ "integrity": "sha512-YF9cTBcAnO4R44092BJi5Wa2/EO02xn2ziCtmNgAVTN2LD31a/YVGxGBt/FDr4Y6yeuVehaqijVVvtpSmXrGJw==",
+ "dependencies": {
+ "@sentry/types": "7.19.0",
+ "@sentry/utils": "7.19.0",
+ "tslib": "^1.9.3"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@sentry/tracing/node_modules/@sentry/types": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.19.0.tgz",
+ "integrity": "sha512-oGRAT6lfzoKrxO1mvxiSj0XHxWPd6Gd1wpPGuu6iJo03xgWDS+MIlD1h2unqL4N5fAzLjzmbC2D2lUw50Kn2pA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@sentry/tracing/node_modules/@sentry/utils": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.19.0.tgz",
+ "integrity": "sha512-2L6lq+c9Ol2uiRxQDdcgoapmHJp24MhMN0gIkn2alSfMJ+ls6bGXzQHx6JAIdoOiwFQXRZHKL9ecfAc8O+vItA==",
+ "dependencies": {
+ "@sentry/types": "7.19.0",
"tslib": "^1.9.3"
},
"engines": {
@@ -4517,9 +4583,9 @@
}
},
"node_modules/express-rate-limit": {
- "version": "6.6.0",
- "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.6.0.tgz",
- "integrity": "sha512-HFN2+4ZGdkQOS8Qli4z6knmJFnw6lZed67o6b7RGplWeb1Z0s8VXaj3dUgPIdm9hrhZXTRpCTHXA0/2Eqex0vA==",
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.7.0.tgz",
+ "integrity": "sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA==",
"engines": {
"node": ">= 12.9.0"
},
@@ -6452,9 +6518,9 @@
}
},
"node_modules/mongoose": {
- "version": "6.7.1",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.7.1.tgz",
- "integrity": "sha512-qbagtqSyvIhUz4EWzXC00EA0DJHFrQwlzTlNGX5DjiESoJiPKqkEga1k9hviFKRFgBna+OlW54mkdi+0+AqxCw==",
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.7.2.tgz",
+ "integrity": "sha512-lrP2V5U1qhaf+z33fiIn7aYAZZ1fVDly+TkFRjTujNBF/FIHESATj2RbgAOSlWqv32fsZXkXejXzeVfjbv35Ow==",
"dependencies": {
"bson": "^4.7.0",
"kareem": "2.4.1",
@@ -10508,9 +10574,9 @@
}
},
"node_modules/typescript": {
- "version": "4.8.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
- "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
+ "version": "4.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
+ "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -13058,28 +13124,80 @@
}
},
"@sentry/node": {
- "version": "7.17.4",
- "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.17.4.tgz",
- "integrity": "sha512-cR+Gsir9c/tzFWxvk4zXkMQy6tNRHEYixHrb88XIjZVYDqDS9l2/bKs5nJusdmaUeLtmPp5Et2o7RJyS7gvKTQ==",
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.19.0.tgz",
+ "integrity": "sha512-yG7Tx32WqOkEHVotFLrumCcT9qlaSDTkFNZ+yLSvZXx74ifsE781DzBA9W7K7bBdYO3op+p2YdsOKzf3nPpAyQ==",
"requires": {
- "@sentry/core": "7.17.4",
- "@sentry/types": "7.17.4",
- "@sentry/utils": "7.17.4",
+ "@sentry/core": "7.19.0",
+ "@sentry/types": "7.19.0",
+ "@sentry/utils": "7.19.0",
"cookie": "^0.4.1",
"https-proxy-agent": "^5.0.0",
"lru_map": "^0.3.3",
"tslib": "^1.9.3"
+ },
+ "dependencies": {
+ "@sentry/core": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.19.0.tgz",
+ "integrity": "sha512-YF9cTBcAnO4R44092BJi5Wa2/EO02xn2ziCtmNgAVTN2LD31a/YVGxGBt/FDr4Y6yeuVehaqijVVvtpSmXrGJw==",
+ "requires": {
+ "@sentry/types": "7.19.0",
+ "@sentry/utils": "7.19.0",
+ "tslib": "^1.9.3"
+ }
+ },
+ "@sentry/types": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.19.0.tgz",
+ "integrity": "sha512-oGRAT6lfzoKrxO1mvxiSj0XHxWPd6Gd1wpPGuu6iJo03xgWDS+MIlD1h2unqL4N5fAzLjzmbC2D2lUw50Kn2pA=="
+ },
+ "@sentry/utils": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.19.0.tgz",
+ "integrity": "sha512-2L6lq+c9Ol2uiRxQDdcgoapmHJp24MhMN0gIkn2alSfMJ+ls6bGXzQHx6JAIdoOiwFQXRZHKL9ecfAc8O+vItA==",
+ "requires": {
+ "@sentry/types": "7.19.0",
+ "tslib": "^1.9.3"
+ }
+ }
}
},
"@sentry/tracing": {
- "version": "7.17.4",
- "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.17.4.tgz",
- "integrity": "sha512-9Fz6DI16ddnd970mlB5MiCNRSmSXp4SVZ1Yv3L22oS3kQeNxjBTE+htYNwJzSPrQp9aL/LqTYwlnrCy24u9XQA==",
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.19.0.tgz",
+ "integrity": "sha512-SWY17M3TsgBePaGowUcSqBwaT0TJQzuNexVnLojuU0k6F57L9hubvP9zaoosoCfARXQ/3NypAFWnlJyf570rFQ==",
"requires": {
- "@sentry/core": "7.17.4",
- "@sentry/types": "7.17.4",
- "@sentry/utils": "7.17.4",
+ "@sentry/core": "7.19.0",
+ "@sentry/types": "7.19.0",
+ "@sentry/utils": "7.19.0",
"tslib": "^1.9.3"
+ },
+ "dependencies": {
+ "@sentry/core": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.19.0.tgz",
+ "integrity": "sha512-YF9cTBcAnO4R44092BJi5Wa2/EO02xn2ziCtmNgAVTN2LD31a/YVGxGBt/FDr4Y6yeuVehaqijVVvtpSmXrGJw==",
+ "requires": {
+ "@sentry/types": "7.19.0",
+ "@sentry/utils": "7.19.0",
+ "tslib": "^1.9.3"
+ }
+ },
+ "@sentry/types": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.19.0.tgz",
+ "integrity": "sha512-oGRAT6lfzoKrxO1mvxiSj0XHxWPd6Gd1wpPGuu6iJo03xgWDS+MIlD1h2unqL4N5fAzLjzmbC2D2lUw50Kn2pA=="
+ },
+ "@sentry/utils": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.19.0.tgz",
+ "integrity": "sha512-2L6lq+c9Ol2uiRxQDdcgoapmHJp24MhMN0gIkn2alSfMJ+ls6bGXzQHx6JAIdoOiwFQXRZHKL9ecfAc8O+vItA==",
+ "requires": {
+ "@sentry/types": "7.19.0",
+ "tslib": "^1.9.3"
+ }
+ }
}
},
"@sentry/types": {
@@ -14523,9 +14641,9 @@
}
},
"express-rate-limit": {
- "version": "6.6.0",
- "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.6.0.tgz",
- "integrity": "sha512-HFN2+4ZGdkQOS8Qli4z6knmJFnw6lZed67o6b7RGplWeb1Z0s8VXaj3dUgPIdm9hrhZXTRpCTHXA0/2Eqex0vA==",
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.7.0.tgz",
+ "integrity": "sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA==",
"requires": {}
},
"express-validator": {
@@ -15964,9 +16082,9 @@
}
},
"mongoose": {
- "version": "6.7.1",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.7.1.tgz",
- "integrity": "sha512-qbagtqSyvIhUz4EWzXC00EA0DJHFrQwlzTlNGX5DjiESoJiPKqkEga1k9hviFKRFgBna+OlW54mkdi+0+AqxCw==",
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.7.2.tgz",
+ "integrity": "sha512-lrP2V5U1qhaf+z33fiIn7aYAZZ1fVDly+TkFRjTujNBF/FIHESATj2RbgAOSlWqv32fsZXkXejXzeVfjbv35Ow==",
"requires": {
"bson": "^4.7.0",
"kareem": "2.4.1",
@@ -18825,9 +18943,9 @@
}
},
"typescript": {
- "version": "4.8.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
- "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ=="
+ "version": "4.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
+ "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA=="
},
"uglify-js": {
"version": "3.17.4",
diff --git a/backend/package.json b/backend/package.json
index 2bd296d9c..73cf9311f 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,7 +1,7 @@
{
"dependencies": {
"@sentry/node": "^7.14.0",
- "@sentry/tracing": "^7.14.0",
+ "@sentry/tracing": "^7.19.0",
"@types/crypto-js": "^4.1.1",
"axios": "^1.1.3",
"bigint-conversion": "^2.2.2",
@@ -10,13 +10,13 @@
"crypto-js": "^4.1.1",
"dotenv": "^16.0.1",
"express": "^4.18.1",
- "express-rate-limit": "^6.5.1",
+ "express-rate-limit": "^6.7.0",
"express-validator": "^6.14.2",
"handlebars": "^4.7.7",
"helmet": "^5.1.1",
"jsonwebtoken": "^8.5.1",
"jsrp": "^0.2.4",
- "mongoose": "^6.7.1",
+ "mongoose": "^6.7.2",
"nodemailer": "^6.8.0",
"posthog-node": "^2.1.0",
"query-string": "^7.1.1",
@@ -24,7 +24,7 @@
"stripe": "^10.7.0",
"tweetnacl": "^1.0.3",
"tweetnacl-util": "^0.15.1",
- "typescript": "^4.8.4"
+ "typescript": "^4.9.3"
},
"name": "infisical-api",
"version": "1.0.0",
diff --git a/backend/src/helpers/signup.ts b/backend/src/helpers/signup.ts
index 3229910a5..ff92fbf12 100644
--- a/backend/src/helpers/signup.ts
+++ b/backend/src/helpers/signup.ts
@@ -106,7 +106,7 @@ const initializeDefaultOrg = async ({
// initialize a default workspace inside the new organization
const workspace = await createWorkspace({
- name: `${user.firstName}'s Project`,
+ name: `Example Project`,
organizationId: organization._id.toString()
});
diff --git a/cli/packages/cmd/export.go b/cli/packages/cmd/export.go
new file mode 100644
index 000000000..a0d89301f
--- /dev/null
+++ b/cli/packages/cmd/export.go
@@ -0,0 +1,140 @@
+/*
+Copyright ยฉ 2022 NAME HERE
+*/
+package cmd
+
+import (
+ "encoding/csv"
+ "encoding/json"
+ "fmt"
+ "strings"
+
+ "github.com/Infisical/infisical-merge/packages/models"
+ "github.com/Infisical/infisical-merge/packages/util"
+ log "github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
+)
+
+const (
+ FormatDotenv string = "dotenv"
+ FormatJson string = "json"
+ FormatCSV string = "csv"
+)
+
+// exportCmd represents the export command
+var exportCmd = &cobra.Command{
+ Use: "export",
+ Short: "Used to export environment variables to a file",
+ DisableFlagsInUseLine: true,
+ Example: "infisical export --env=prod --format=json > secrets.json",
+ Args: cobra.NoArgs,
+ PreRun: toggleDebug,
+ Run: func(cmd *cobra.Command, args []string) {
+ envName, err := cmd.Flags().GetString("env")
+ if err != nil {
+ log.Errorln("Unable to parse the environment flag")
+ log.Debugln(err)
+ return
+ }
+
+ shouldExpandSecrets, err := cmd.Flags().GetBool("expand")
+ if err != nil {
+ log.Errorln("Unable to parse the substitute flag")
+ log.Debugln(err)
+ return
+ }
+
+ projectId, err := cmd.Flags().GetString("projectId")
+ if err != nil {
+ log.Errorln("Unable to parse the project id flag")
+ log.Debugln(err)
+ return
+ }
+
+ format, err := cmd.Flags().GetString("format")
+ if err != nil {
+ log.Errorln("Unable to parse the format flag")
+ log.Debugln(err)
+ return
+ }
+
+ envsFromApi, err := util.GetAllEnvironmentVariables(projectId, envName)
+ if err != nil {
+ log.Errorln("Something went wrong when pulling secrets using your Infisical token. Double check the token, project id or environment name (dev, prod, ect.)")
+ log.Debugln(err)
+ return
+ }
+
+ var output string
+ if shouldExpandSecrets {
+ substitutions := util.SubstituteSecrets(envsFromApi)
+ output, err = formatEnvs(substitutions, format)
+ if err != nil {
+ log.Errorln(err)
+ return
+ }
+ } else {
+ output, err = formatEnvs(envsFromApi, format)
+ if err != nil {
+ log.Errorln(err)
+ return
+ }
+ }
+ fmt.Print(output)
+ },
+}
+
+func init() {
+ rootCmd.AddCommand(exportCmd)
+ exportCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from")
+ exportCmd.Flags().String("projectId", "", "The project ID from which your secrets should be pulled from")
+ exportCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
+ exportCmd.Flags().StringP("format", "f", "dotenv", "Set the format of the output file (dotenv, json, csv)")
+}
+
+// Format according to the format flag
+func formatEnvs(envs []models.SingleEnvironmentVariable, format string) (string, error) {
+ switch strings.ToLower(format) {
+ case FormatDotenv:
+ return formatAsDotEnv(envs), nil
+ case FormatJson:
+ return formatAsJson(envs), nil
+ case FormatCSV:
+ return formatAsCSV(envs), nil
+ default:
+ return "", fmt.Errorf("invalid format flag: %s", format)
+ }
+}
+
+// Format environment variables as a CSV file
+func formatAsCSV(envs []models.SingleEnvironmentVariable) string {
+ csvString := &strings.Builder{}
+ writer := csv.NewWriter(csvString)
+ writer.Write([]string{"Key", "Value"})
+ for _, env := range envs {
+ writer.Write([]string{env.Key, env.Value})
+ }
+ writer.Flush()
+ return csvString.String()
+}
+
+// Format environment variables as a dotenv file
+func formatAsDotEnv(envs []models.SingleEnvironmentVariable) string {
+ var dotenv string
+ for _, env := range envs {
+ dotenv += fmt.Sprintf("%s='%s'\n", env.Key, env.Value)
+ }
+ return dotenv
+}
+
+// Format environment variables as a JSON file
+func formatAsJson(envs []models.SingleEnvironmentVariable) string {
+ // Dump as a json array
+ json, err := json.Marshal(envs)
+ if err != nil {
+ log.Errorln("Unable to marshal environment variables to JSON")
+ log.Debugln(err)
+ return ""
+ }
+ return string(json)
+}
diff --git a/cli/packages/cmd/init.go b/cli/packages/cmd/init.go
index 55abe6d4f..2789f220d 100644
--- a/cli/packages/cmd/init.go
+++ b/cli/packages/cmd/init.go
@@ -36,7 +36,7 @@ var initCmd = &cobra.Command{
return
}
- if util.WorkspaceConfigFileExists() {
+ if util.WorkspaceConfigFileExistsInCurrentPath() {
shouldOverride, err := shouldOverrideWorkspacePrompt()
if err != nil {
log.Errorln("Unable to parse your answer")
diff --git a/cli/packages/cmd/login.go b/cli/packages/cmd/login.go
index f84fad501..29e2c4935 100644
--- a/cli/packages/cmd/login.go
+++ b/cli/packages/cmd/login.go
@@ -114,7 +114,7 @@ func init() {
func askForLoginCredentials() (email string, password string, err error) {
validateEmail := func(input string) error {
- matched, err := regexp.MatchString("^[\\w!#$%&'*+/=?`{|}~^-]+(?:\\.[\\w!#$%&'*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$", input)
+ matched, err := regexp.MatchString("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$", input)
if err != nil || !matched {
return errors.New("this doesn't look like an email address")
}
diff --git a/cli/packages/cmd/root.go b/cli/packages/cmd/root.go
index 42d85e5b2..12e4351bb 100644
--- a/cli/packages/cmd/root.go
+++ b/cli/packages/cmd/root.go
@@ -15,7 +15,7 @@ var rootCmd = &cobra.Command{
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.`,
CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true},
- Version: "0.1.6",
+ Version: "0.1.8",
}
// Execute adds all child commands to the root command and sets flags appropriately.
diff --git a/cli/packages/cmd/run.go b/cli/packages/cmd/run.go
index 6b44fa548..ec5210b1f 100644
--- a/cli/packages/cmd/run.go
+++ b/cli/packages/cmd/run.go
@@ -47,53 +47,17 @@ var runCmd = &cobra.Command{
return
}
- var envsFromApi []models.SingleEnvironmentVariable
- infisicalToken := os.Getenv(util.INFISICAL_TOKEN_NAME)
- if infisicalToken == "" {
- hasUserLoggedInbefore, loggedInUserEmail, err := util.IsUserLoggedIn()
- if err != nil {
- log.Info("Unexpected issue occurred while checking login status. To see more details, add flag --debug")
- log.Debugln(err)
- return
- }
-
- if !hasUserLoggedInbefore {
- log.Infoln("No logged in user. To login, please run command [infisical login]")
- return
- }
-
- userCreds, err := util.GetUserCredsFromKeyRing(loggedInUserEmail)
- if err != nil {
- log.Infoln("Unable to get user creds from key ring")
- log.Debug(err)
- return
- }
-
- if !util.WorkspaceConfigFileExists() {
- log.Infoln("Your project is not connected to a project yet. Run command [infisical init]")
- return
- }
-
- envsFromApi, err = util.GetSecretsFromAPIUsingCurrentLoggedInUser(envName, userCreds)
- if err != nil {
- log.Errorln("Something went wrong when pulling secrets using your logged in credentials. If the issue persists, double check your project id/try logging in again.")
- log.Debugln(err)
- return
- }
- } else {
- envsFromApi, err = util.GetSecretsFromAPIUsingInfisicalToken(infisicalToken, envName, projectId)
- if err != nil {
- log.Errorln("Something went wrong when pulling secrets using your Infisical token. Double check the token, project id or environment name (dev, prod, ect.)")
- log.Debugln(err)
- return
- }
+ secrets, err := util.GetAllEnvironmentVariables(projectId, envName)
+ if err != nil {
+ log.Debugln(err)
+ return
}
if shouldExpandSecrets {
- substitutions := util.SubstituteSecrets(envsFromApi)
- execCmd(args[0], args[1:], substitutions)
+ secretsWithSubstitutions := util.SubstituteSecrets(secrets)
+ execCmd(args[0], args[1:], secretsWithSubstitutions)
} else {
- execCmd(args[0], args[1:], envsFromApi)
+ execCmd(args[0], args[1:], secrets)
}
},
@@ -108,9 +72,12 @@ func init() {
// Credit: inspired by AWS Valut
func execCmd(command string, args []string, envs []models.SingleEnvironmentVariable) error {
- log.Infof("\x1b[%dm%s\x1b[0m", 32, "\u2713 Injected Infisical secrets into your application process successfully")
- log.Debugln("Secrets to inject:", envs)
+ numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(envs))
+
+ log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected)
log.Debugf("executing command: %s %s \n", command, strings.Join(args, " "))
+ log.Debugln("Secrets injected:", envs)
+
cmd := exec.Command(command, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
diff --git a/cli/packages/models/error.go b/cli/packages/models/error.go
index 28e48d54d..f6d58cb5a 100644
--- a/cli/packages/models/error.go
+++ b/cli/packages/models/error.go
@@ -5,10 +5,13 @@ import log "github.com/sirupsen/logrus"
// Custom error type so that we can give helpful messages in CLI
type Error struct {
Err error
- DebugMessage string
FriendlyMessage string
}
func (e *Error) printFriendlyMessage() {
log.Infoln(e.FriendlyMessage)
}
+
+func (e *Error) printDebuError() {
+ log.Debugln(e.Err)
+}
diff --git a/cli/packages/util/config.go b/cli/packages/util/config.go
index c42f26fb5..0ee04b013 100644
--- a/cli/packages/util/config.go
+++ b/cli/packages/util/config.go
@@ -56,7 +56,7 @@ func ConfigFileExists() bool {
}
}
-func WorkspaceConfigFileExists() bool {
+func WorkspaceConfigFileExistsInCurrentPath() bool {
if _, err := os.Stat(INFISICAL_WORKSPACE_CONFIG_FILE_NAME); err == nil {
return true
} else {
@@ -90,3 +90,65 @@ func GetFullConfigFilePath() (fullPathToFile string, fullPathToDirectory string,
fullDirPath := fmt.Sprintf("%s/%s", homeDir, CONFIG_FOLDER_NAME)
return fullPath, fullDirPath, err
}
+
+// Given a path to a workspace config, unmarshal workspace config
+func GetWorkspaceConfigByPath(path string) (workspaceConfig models.WorkspaceConfigFile, err error) {
+ workspaceConfigFileAsBytes, err := os.ReadFile(path)
+ if err != nil {
+ return models.WorkspaceConfigFile{}, fmt.Errorf("GetWorkspaceConfigByPath: Unable to read workspace config file because [%s]", err)
+ }
+
+ var workspaceConfigFile models.WorkspaceConfigFile
+ err = json.Unmarshal(workspaceConfigFileAsBytes, &workspaceConfigFile)
+ if err != nil {
+ return models.WorkspaceConfigFile{}, fmt.Errorf("GetWorkspaceConfigByPath: Unable to unmarshal workspace config file because [%s]", err)
+ }
+
+ return workspaceConfigFile, nil
+}
+
+// Will get the list of .infisical.json files that are located
+// within the root of each sub folder from where the CLI is ran from
+func GetAllWorkSpaceConfigsStartingFromCurrentPath() (workspaces []models.WorkspaceConfigFile, err error) {
+ currentDir, err := os.Getwd()
+ if err != nil {
+ return nil, fmt.Errorf("GetAllProjectConfigs: unable to get the current directory because [%s]", err)
+ }
+
+ files, err := os.ReadDir(currentDir)
+ if err != nil {
+ return nil, fmt.Errorf("GetAllProjectConfigs: unable to read the contents of the current directory because [%s]", err)
+ }
+
+ listOfWorkSpaceConfigs := []models.WorkspaceConfigFile{}
+ for _, file := range files {
+ if !file.IsDir() && file.Name() == INFISICAL_WORKSPACE_CONFIG_FILE_NAME {
+ pathToWorkspaceConfigFile := currentDir + "/" + INFISICAL_WORKSPACE_CONFIG_FILE_NAME
+
+ workspaceConfig, err := GetWorkspaceConfigByPath(pathToWorkspaceConfigFile)
+ if err != nil {
+ return nil, fmt.Errorf("GetAllProjectConfigs: Unable to get config file because [%s]", err)
+ }
+
+ listOfWorkSpaceConfigs = append(listOfWorkSpaceConfigs, workspaceConfig)
+
+ } else if file.IsDir() {
+ pathToSubFolder := currentDir + "/" + file.Name()
+ pathToMaybeWorkspaceConfigFile := pathToSubFolder + "/" + INFISICAL_WORKSPACE_CONFIG_FILE_NAME
+
+ _, err := os.Stat(pathToMaybeWorkspaceConfigFile)
+ if err != nil {
+ continue // workspace config file doesn't exist
+ }
+
+ workspaceConfig, err := GetWorkspaceConfigByPath(pathToMaybeWorkspaceConfigFile)
+ if err != nil {
+ return nil, fmt.Errorf("GetAllProjectConfigs: Unable to get config file because [%s]", err)
+ }
+
+ listOfWorkSpaceConfigs = append(listOfWorkSpaceConfigs, workspaceConfig)
+ }
+ }
+
+ return listOfWorkSpaceConfigs, nil
+}
diff --git a/cli/packages/util/crypto.go b/cli/packages/util/crypto.go
index b308ea93d..c6eee2d0c 100644
--- a/cli/packages/util/crypto.go
+++ b/cli/packages/util/crypto.go
@@ -3,12 +3,9 @@ package util
import (
"crypto/aes"
"crypto/cipher"
-
- log "github.com/sirupsen/logrus"
)
func DecryptSymmetric(key []byte, encryptedPrivateKey []byte, tag []byte, IV []byte) ([]byte, error) {
- log.Debugln("Key:", key, "encryptedPrivateKey", encryptedPrivateKey, "tag", tag, "IV", IV)
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
diff --git a/cli/packages/util/secrets.go b/cli/packages/util/secrets.go
index 5cf76d48e..d7d4cdc37 100644
--- a/cli/packages/util/secrets.go
+++ b/cli/packages/util/secrets.go
@@ -4,6 +4,7 @@ import (
"encoding/base64"
"errors"
"fmt"
+ "os"
"regexp"
"strings"
@@ -13,19 +14,7 @@ import (
"golang.org/x/crypto/nacl/box"
)
-func GetSecretsFromAPIUsingCurrentLoggedInUser(envName string, userCreds models.UserCredentials) ([]models.SingleEnvironmentVariable, error) {
- log.Debugln("envName", envName, "userCreds", userCreds)
- // check if user has configured a workspace
- workspace, err := GetWorkSpaceFromFile()
- if err != nil {
- return nil, fmt.Errorf("Unable to read workspace file:", err)
- }
-
- // create http client
- httpClient := resty.New().
- SetAuthToken(userCreds.JTWToken).
- SetHeader("Accept", "application/json")
-
+func getSecretsByWorkspaceIdAndEnvName(httpClient resty.Client, envName string, workspace models.WorkspaceConfigFile, userCreds models.UserCredentials) (listOfSecrets []models.SingleEnvironmentVariable, err error) {
var pullSecretsRequestResponse models.PullSecretsResponse
response, err := httpClient.
R().
@@ -34,14 +23,11 @@ func GetSecretsFromAPIUsingCurrentLoggedInUser(envName string, userCreds models.
SetResult(&pullSecretsRequestResponse).
Get(fmt.Sprintf("%v/v1/secret/%v", INFISICAL_URL, workspace.WorkspaceId)) // need to change workspace id
- log.Debugln("Response from get secrets:", response)
-
if err != nil {
return nil, err
}
if response.StatusCode() > 299 {
- log.Debugln(response)
return nil, fmt.Errorf(response.Status())
}
@@ -66,7 +52,7 @@ func GetSecretsFromAPIUsingCurrentLoggedInUser(envName string, userCreds models.
return nil, err
}
- log.Debugln("workspaceKey", workspaceKey, "nonce", nonce, "senderPublicKey", senderPublicKey, "currentUsersPrivateKey", currentUsersPrivateKey)
+ // log.Debugln("workspaceKey", workspaceKey, "nonce", nonce, "senderPublicKey", senderPublicKey, "currentUsersPrivateKey", currentUsersPrivateKey)
workspaceKeyInBytes, _ := box.Open(nil, workspaceKey, (*[24]byte)(nonce), (*[32]byte)(senderPublicKey), (*[32]byte)(currentUsersPrivateKey))
var listOfEnv []models.SingleEnvironmentVariable
@@ -100,6 +86,32 @@ func GetSecretsFromAPIUsingCurrentLoggedInUser(envName string, userCreds models.
return listOfEnv, nil
}
+func GetSecretsFromAPIUsingCurrentLoggedInUser(envName string, userCreds models.UserCredentials) ([]models.SingleEnvironmentVariable, error) {
+ log.Debugln("GetSecretsFromAPIUsingCurrentLoggedInUser", "envName", envName, "userCreds", userCreds)
+ // check if user has configured a workspace
+ workspaces, err := GetAllWorkSpaceConfigsStartingFromCurrentPath()
+ if err != nil {
+ return nil, fmt.Errorf("Unable to read workspace file(s):", err)
+ }
+
+ // create http client
+ httpClient := resty.New().
+ SetAuthToken(userCreds.JTWToken).
+ SetHeader("Accept", "application/json")
+
+ secrets := []models.SingleEnvironmentVariable{}
+ for _, workspace := range workspaces {
+ secretsFromAPI, err := getSecretsByWorkspaceIdAndEnvName(*httpClient, envName, workspace, userCreds)
+ if err != nil {
+ return nil, fmt.Errorf("GetSecretsFromAPIUsingCurrentLoggedInUser: Unable to get secrets by workspace id and env name")
+ }
+
+ secrets = append(secrets, secretsFromAPI...)
+ }
+
+ return secrets, nil
+}
+
func GetSecretsFromAPIUsingInfisicalToken(infisicalToken string, envName string, projectId string) ([]models.SingleEnvironmentVariable, error) {
if infisicalToken == "" || projectId == "" || envName == "" {
return nil, errors.New("infisical token, project id and or environment name cannot be empty")
@@ -126,7 +138,6 @@ func GetSecretsFromAPIUsingInfisicalToken(infisicalToken string, envName string,
}
if response.StatusCode() > 299 {
- log.Debugln(response)
return nil, fmt.Errorf(response.Status())
}
@@ -184,6 +195,58 @@ func GetSecretsFromAPIUsingInfisicalToken(infisicalToken string, envName string,
return listOfEnv, nil
}
+func GetAllEnvironmentVariables(projectId string, envName string) ([]models.SingleEnvironmentVariable, error) {
+ var envsFromApi []models.SingleEnvironmentVariable
+ infisicalToken := os.Getenv(INFISICAL_TOKEN_NAME)
+
+ if infisicalToken == "" {
+ hasUserLoggedInbefore, loggedInUserEmail, err := IsUserLoggedIn()
+ if err != nil {
+ log.Info("Unexpected issue occurred while checking login status. To see more details, add flag --debug")
+ log.Debugln(err)
+ return envsFromApi, err
+ }
+
+ if !hasUserLoggedInbefore {
+ log.Infoln("No logged in user. To login, please run command [infisical login]")
+ return envsFromApi, fmt.Errorf("user not logged in")
+ }
+
+ userCreds, err := GetUserCredsFromKeyRing(loggedInUserEmail)
+ if err != nil {
+ log.Infoln("Unable to get user creds from key ring")
+ log.Debug(err)
+ return envsFromApi, err
+ }
+
+ workspaceConfigs, err := GetAllWorkSpaceConfigsStartingFromCurrentPath()
+ if err != nil {
+ return nil, fmt.Errorf("unable to check if you have a %s file in your current directory", INFISICAL_WORKSPACE_CONFIG_FILE_NAME)
+ }
+
+ if len(workspaceConfigs) == 0 {
+ log.Infoln("Your local project is not connected to a Infisical project yet. Run command [infisical init]")
+ return envsFromApi, fmt.Errorf("project not initialized")
+ }
+
+ envsFromApi, err = GetSecretsFromAPIUsingCurrentLoggedInUser(envName, userCreds)
+ if err != nil {
+ log.Errorln("Something went wrong when pulling secrets using your logged in credentials. If the issue persists, double check your project id/try logging in again.")
+ log.Debugln(err)
+ return envsFromApi, err
+ }
+ } else {
+ envsFromApi, err := GetSecretsFromAPIUsingInfisicalToken(infisicalToken, envName, projectId)
+ if err != nil {
+ log.Errorln("Something went wrong when pulling secrets using your Infisical token. Double check the token, project id or environment name (dev, prod, ect.)")
+ log.Debugln(err)
+ return envsFromApi, err
+ }
+ }
+
+ return envsFromApi, nil
+}
+
func GetWorkSpacesFromAPI(userCreds models.UserCredentials) (workspaces []models.Workspace, err error) {
// create http client
httpClient := resty.New().
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
index 6eabfe4d9..949a96c7d 100644
--- a/docker-compose.dev.yml
+++ b/docker-compose.dev.yml
@@ -23,7 +23,6 @@ services:
build:
context: ./backend
dockerfile: Dockerfile
- image: infisical/backend
volumes:
- ./backend/src:/app/src
- ./backend/nodemon.json:/app/nodemon.json
@@ -43,7 +42,6 @@ services:
build:
context: ./frontend
dockerfile: Dockerfile.dev
- image: infisical/frontend
volumes:
- ./frontend/pages:/app/pages
- ./frontend/public:/app/public
@@ -52,12 +50,8 @@ services:
env_file: .env
environment:
- NEXT_PUBLIC_ENV=development
- - NEXT_PUBLIC_WEBSITE_URL=${SITE_URL}
- - NEXT_PUBLIC_POSTHOG_HOST=${POSTHOG_HOST}
- - NEXT_PUBLIC_POSTHOG_API_KEY=${POSTHOG_PROJECT_API_KEY}
- NEXT_PUBLIC_STRIPE_PRODUCT_PRO=${STRIPE_PRODUCT_PRO}
- NEXT_PUBLIC_STRIPE_PRODUCT_STARTER=${STRIPE_PRODUCT_STARTER}
- - NEXT_PUBLIC_TELEMETRY_ENABLED=${TELEMETRY_ENABLED}
networks:
- infisical-dev
@@ -78,6 +72,8 @@ services:
container_name: infisical-dev-mongo-express
image: mongo-express
restart: always
+ depends_on:
+ - mongo
env_file: .env
environment:
- ME_CONFIG_MONGODB_ADMINUSERNAME=${MONGO_USERNAME}
@@ -93,4 +89,4 @@ volumes:
driver: local
networks:
- infisical-dev:
\ No newline at end of file
+ infisical-dev:
diff --git a/docker-compose.yml b/docker-compose.yml
index 3204f9257..cc92e1406 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -17,14 +17,10 @@ services:
- infisical
backend:
- platform: linux/amd64
container_name: infisical-backend
restart: unless-stopped
depends_on:
- mongo
- build:
- context: ./backend
- dockerfile: Dockerfile
image: infisical/backend
command: npm run start
env_file: .env
@@ -34,24 +30,17 @@ services:
- infisical
frontend:
- platform: linux/amd64
container_name: infisical-frontend
restart: unless-stopped
depends_on:
- backend
- build:
- context: ./frontend
- dockerfile: Dockerfile.prod
image: infisical/frontend
env_file: .env
environment:
- - NEXT_PUBLIC_ENV=production
- - NEXT_PUBLIC_WEBSITE_URL=${SITE_URL}
- - NEXT_PUBLIC_POSTHOG_HOST=${POSTHOG_HOST}
- - NEXT_PUBLIC_POSTHOG_API_KEY=${POSTHOG_PROJECT_API_KEY}
+ # - NEXT_PUBLIC_POSTHOG_API_KEY=${POSTHOG_PROJECT_API_KEY}
+ - INFISICAL_TELEMETRY_ENABLED=${TELEMETRY_ENABLED}
- NEXT_PUBLIC_STRIPE_PRODUCT_PRO=${STRIPE_PRODUCT_PRO}
- NEXT_PUBLIC_STRIPE_PRODUCT_STARTER=${STRIPE_PRODUCT_STARTER}
- - NEXT_PUBLIC_TELEMETRY_ENABLED=${TELEMETRY_ENABLED}
networks:
- infisical
@@ -73,4 +62,4 @@ volumes:
driver: local
networks:
- infisical:
\ No newline at end of file
+ infisical:
diff --git a/docs/cli/reference/commands.mdx b/docs/cli/commands/commands.mdx
similarity index 100%
rename from docs/cli/reference/commands.mdx
rename to docs/cli/commands/commands.mdx
diff --git a/docs/cli/commands/export.mdx b/docs/cli/commands/export.mdx
new file mode 100644
index 000000000..fd58868ff
--- /dev/null
+++ b/docs/cli/commands/export.mdx
@@ -0,0 +1,33 @@
+---
+title: "infisical export"
+---
+
+```bash
+infisical export [options]
+```
+
+## Description
+
+Export environment variables from the platform into a file format.
+
+## Options
+
+| Option | Description | Default value |
+| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
+| `--env` | Used to set the environment that secrets are pulled from. Accepted values: `dev`, `staging`, `test`, `prod` | `dev` |
+| `--projectId` | Only required if injecting via the [service token method](../token). If you are not using service token, the project id will be automatically retrieved from the `.infisical.json` located at the root of your local project. | `None` |
+| `--expand` | Parse shell parameter expansions in your secrets (e.g., `${DOMAIN}`) | `true` |
+| `--format` | Format of the output file. Accepted values: `dotenv`, `csv` and `json` | `dotenv` |
+
+## Examples
+
+```bash
+# Export variables to a .env file
+infisical export > .env
+
+# Export variables to a CSV file
+infisical export --format=csv > secrets.csv
+
+# Export variables to a JSON file
+infisical export --format=json > secrets.json
+```
diff --git a/docs/cli/reference/init.mdx b/docs/cli/commands/init.mdx
similarity index 100%
rename from docs/cli/reference/init.mdx
rename to docs/cli/commands/init.mdx
diff --git a/docs/cli/reference/login.mdx b/docs/cli/commands/login.mdx
similarity index 100%
rename from docs/cli/reference/login.mdx
rename to docs/cli/commands/login.mdx
diff --git a/docs/cli/reference/run.mdx b/docs/cli/commands/run.mdx
similarity index 100%
rename from docs/cli/reference/run.mdx
rename to docs/cli/commands/run.mdx
diff --git a/docs/cli/overview.mdx b/docs/cli/overview.mdx
index 8411b8e75..6267a66f0 100644
--- a/docs/cli/overview.mdx
+++ b/docs/cli/overview.mdx
@@ -1,5 +1,5 @@
---
-title: "Overview"
+title: "Install"
---
Prerequisite: Set up an account with [Infisical Cloud](https://app.infisical.com) or via a [self-hosted installation](/self-hosting/overview).
diff --git a/docs/getting-started/dashboard/token.mdx b/docs/getting-started/dashboard/token.mdx
index 85f46b799..9b3ddf79f 100644
--- a/docs/getting-started/dashboard/token.mdx
+++ b/docs/getting-started/dashboard/token.mdx
@@ -4,13 +4,16 @@ title: "Infisical Token"
An Infisical Token is needed to authenticate the CLI when there isn't an easy way to input your login credentials.
-It's useful for the [Docker](/integrations/platforms/docker) and [Docker Compose](/integrations/platforms/docker-compose) integrations.
+It's useful for your CI/CD environments and integrations such as [Docker](/integrations/platforms/docker) and [Docker Compose](/integrations/platforms/docker-compose).
+
+To generate the the token, head over to your project settings as shown below.
-It's possible to generate the token in the settings of a project.

The token grants read-only access to a particular environment and project for
- a specified amount of time.
+ a specified amount of time. Once the token is expired, the CLI using it will no longer be able to make
+ requests with it.
+
diff --git a/docs/integrations/platforms/docker-compose.mdx b/docs/integrations/platforms/docker-compose.mdx
index 9e0f90e55..f2cdd60c8 100644
--- a/docs/integrations/platforms/docker-compose.mdx
+++ b/docs/integrations/platforms/docker-compose.mdx
@@ -4,14 +4,14 @@ title: "Docker Compose"
The Docker Compose integration enables you to inject environment variables from Infisical into the containers defined in your compose file.
-## Add the CLI to your Dockerfile(s)
+## Add the CLI to your Dockerfile(s) start command
-Follow steps 1 through 3 on our [guide to configure Infisical CLI](../integrations/platforms/docker) in your Dockerfile.
+Follow the [guide to configure Infisical CLI](./docker) in your your Dockerfile first.
## Generate Infisical Token
In order for Infisical CLI to authenticate and retrieve your project's secrets without exposing your login credentials, you must generate a Infisical Token.
-To learn how, visit [Infisical Token](../getting-started/cli/infisical-token). Once you have generated the token, keep it handy.
+To learn how, visit [Infisical Token](../../getting-started/dashboard/token). Once you have generated the token, keep it handy.
If you have multiple services and they do not use the same secrets, you will
diff --git a/docs/mint.json b/docs/mint.json
index 1d5246680..4fa0436d8 100644
--- a/docs/mint.json
+++ b/docs/mint.json
@@ -87,12 +87,12 @@
"cli/overview",
"cli/usage",
{
- "group": "Reference",
+ "group": "Commands",
"pages": [
- "cli/reference/commands",
- "cli/reference/login",
- "cli/reference/init",
- "cli/reference/run"
+ "cli/commands/login",
+ "cli/commands/init",
+ "cli/commands/run",
+ "cli/commands/export"
]
}
]
diff --git a/docs/self-hosting/configuration/envars.mdx b/docs/self-hosting/configuration/envars.mdx
index bea36da32..a55efbebc 100644
--- a/docs/self-hosting/configuration/envars.mdx
+++ b/docs/self-hosting/configuration/envars.mdx
@@ -9,24 +9,24 @@ Configuring Infisical requires setting some environment variables. There is a fi
| Variable | Description | Default Value |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------- |
-| `PRIVATE_KEY` | โ๏ธ NaCl-generated server secret key | `None` |
-| `PUBLIC_KEY` | โ๏ธ NaCl-generated server public key | `None` |
-| `ENCRYPTION_KEY` | โ๏ธ Strong hex encryption key | `None` |
-| `JWT_SIGNUP_SECRET` | โ๏ธJWT token secret | `None` |
-| `JWT_REFRESH_SECRET` | โ๏ธ JWT token secret | `None` |
-| `JWT_AUTH_SECRET` | โ๏ธ JWT token secret | `None` |
+| `PRIVATE_KEY` | โ๏ธ NaCl-generated server secret key | `None` |
+| `PUBLIC_KEY` | โ๏ธ NaCl-generated server public key | `None` |
+| `ENCRYPTION_KEY` | โ๏ธ Strong hex encryption key | `None` |
+| `JWT_SIGNUP_SECRET` | โ๏ธ JWT token secret | `None` |
+| `JWT_REFRESH_SECRET` | โ๏ธ JWT token secret | `None` |
+| `JWT_AUTH_SECRET` | โ๏ธ JWT token secret | `None` |
| `JWT_SIGNUP_LIFETIME` | JWT token lifetime expressed in seconds or a string describing a time span (e.g. 60, "2 days", "10h", "7d") | `15m` |
| `JWT_REFRESH_LIFETIME` | JWT token lifetime expressed in seconds or a string describing a time span (e.g. 60, "2 days", "10h", "7d") | `90d` |
| `JWT_AUTH_LIFETIME` | JWT token lifetime expressed in seconds or a string describing a time span (e.g. 60, "2 days", "10h", "7d") | `10d` |
| `EMAIL_TOKEN_LIFETIME` | Email OTP/magic-link lifetime expressed in seconds | `86400` |
-| `MONGO_URL` | โ๏ธ MongoDB instance connection string either to container instance or MongoDB Cloud | `None` |
+| `MONGO_URL` | โ๏ธ MongoDB instance connection string either to container instance or MongoDB Cloud | `None` |
| `MONGO_USERNAME` | MongoDB username if using container | `None` |
| `MONGO_PASSWORD` | MongoDB password if using container | `None` |
-| `SITE_URL` | โ๏ธ Site URL - should be an absolute URL including the protocol (e.g. `https://app.infisical.com`) | `None` |
-| `SMT_HOST` | Whether the user joined the community | `smtp.gmail.com` |
-| `SMTP_NAME` | Hostname to connect to for establishing SMTP connections (e.g. `Team`) | `None` |
-| `SMTP_USERNAME` | โ๏ธ Credential to connect to host (e.g. `team@infisical.com`) | `None` |
-| `SMTP_PASSWORD` | โ๏ธ Credential to connect to host | `None` |
+| `SITE_URL` | โ๏ธ Site URL - should be an absolute URL including the protocol (e.g. `https://app.infisical.com`) | `None` |
+| `SMTP_HOST` | Hostname to connect to for establishing SMTP connections | `smtp.gmail.com` |
+| `SMTP_NAME` | Name label to be used in From field (e.g. `Team`) | `None` |
+| `SMTP_USERNAME` | โ๏ธ Credential to connect to host (e.g. `team@infisical.com`) | `None` |
+| `SMTP_PASSWORD` | โ๏ธ Credential to connect to host | `None` |
| `TELEMETRY_ENABLED` | `true` or `false`. [More](../overview). | `true` |
| `OAUTH_CLIENT_SECRET_HEROKU` | OAuth client secret for Heroku integration | `None` |
| `OAUTH_TOKEN_URL_HEROKU` | OAuth token URL for Heroku integration | `None` |
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
new file mode 100644
index 000000000..5e59c68aa
--- /dev/null
+++ b/frontend/Dockerfile
@@ -0,0 +1,64 @@
+ARG POSTHOG_HOST=https://app.posthog.com
+ARG POSTHOG_API_KEY=posthog-api-key
+
+FROM node:16-alpine AS deps
+# Install dependencies only when needed. Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
+# RUN apk add --no-cache libc6-compat
+WORKDIR /app
+
+# Copy over dependency files
+COPY package.json package-lock.json next.config.js ./
+
+# Install dependencies
+RUN npm ci --only-production
+
+
+# Rebuild the source code only when needed
+FROM node:16-alpine AS builder
+WORKDIR /app
+
+# Copy dependencies
+COPY --from=deps /app/node_modules ./node_modules
+# Copy all files
+COPY . .
+
+ENV NODE_ENV production
+ENV NEXT_PUBLIC_ENV production
+ARG POSTHOG_HOST
+ENV NEXT_PUBLIC_POSTHOG_HOST $POSTHOG_HOST
+ARG POSTHOG_API_KEY
+ENV NEXT_PUBLIC_POSTHOG_API_KEY $POSTHOG_API_KEY
+
+# Build
+RUN npm run build
+
+
+# Production image
+FROM node:16-alpine AS runner
+WORKDIR /app
+
+RUN addgroup --system --gid 1001 nodejs
+RUN adduser --system --uid 1001 nextjs
+
+RUN mkdir -p /app/.next/cache/images && chown nextjs:nodejs /app/.next/cache/images
+VOLUME /app/.next/cache/images
+
+ARG POSTHOG_API_KEY
+ENV NEXT_PUBLIC_POSTHOG_API_KEY=$POSTHOG_API_KEY \
+ BAKED_NEXT_PUBLIC_POSTHOG_API_KEY=$POSTHOG_API_KEY
+
+COPY --chown=nextjs:nodejs --chmod=555 scripts ./scripts
+COPY --from=builder /app/public ./public
+RUN chown nextjs:nodejs ./public/data
+COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
+COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
+
+USER nextjs
+
+EXPOSE 3000
+
+ENV PORT 3000
+ENV NEXT_TELEMETRY_DISABLED 1
+
+
+CMD ["/app/scripts/start.sh"]
diff --git a/frontend/components/analytics/posthog.js b/frontend/components/analytics/posthog.js
index c8d51ad1b..44ee4fdb3 100644
--- a/frontend/components/analytics/posthog.js
+++ b/frontend/components/analytics/posthog.js
@@ -4,12 +4,11 @@ import {
ENV,
POSTHOG_API_KEY,
POSTHOG_HOST,
- TELEMETRY_ENABLED,
} from "../utilities/config";
export const initPostHog = () => {
if (typeof window !== "undefined") {
- if (ENV == "production" && TELEMETRY_ENABLED) {
+ if (ENV == "production" && TELEMETRY_CAPTURING_ENABLED) { // eslint-disable-line
posthog.init(POSTHOG_API_KEY, {
api_host: POSTHOG_HOST,
});
diff --git a/frontend/components/basic/InputField.js b/frontend/components/basic/InputField.tsx
similarity index 89%
rename from frontend/components/basic/InputField.js
rename to frontend/components/basic/InputField.tsx
index 8368d9797..02bb8a8cc 100644
--- a/frontend/components/basic/InputField.js
+++ b/frontend/components/basic/InputField.tsx
@@ -1,19 +1,27 @@
-import React from "react";
-import { useState } from "react";
+import React, { useState } from "react";
import { useRouter } from "next/router";
-import {
- faCircle,
- faCircleExclamation,
- faE,
- faEye,
- faEyeSlash,
-} from "@fortawesome/free-solid-svg-icons";
+import { faCircle, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import 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 router = useRouter();
@@ -67,7 +75,7 @@ const InputField = (props) => {
>
props.onChangeHandler(e.target.value)}
- type={passwordVisible == false ? props.type : "text"}
+ type={passwordVisible === false ? props.type : "text"}
placeholder={props.placeholder}
value={props.value}
required={props.isRequired}
diff --git a/frontend/components/basic/layout.js b/frontend/components/basic/Layout.tsx
similarity index 55%
rename from frontend/components/basic/layout.js
rename to frontend/components/basic/Layout.tsx
index effe38942..4a40fdef0 100644
--- a/frontend/components/basic/layout.js
+++ b/frontend/components/basic/Layout.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable no-unexpected-multiline */
/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useState } from "react";
import Link from "next/link";
@@ -22,6 +23,7 @@ import getWorkspaces from "~/pages/api/workspace/getWorkspaces";
import uploadKeys from "~/pages/api/workspace/uploadKeys";
import NavBarDashboard from "../navigation/NavBarDashboard";
+import { tempLocalStorage } from "../utilities/checks/tempLocalStorage";
import {
decryptAssymmetric,
encryptAssymmetric,
@@ -30,13 +32,17 @@ import Button from "./buttons/Button";
import AddWorkspaceDialog from "./dialog/AddWorkspaceDialog";
import Listbox from "./Listbox";
-export default function Layout({ children }) {
+interface LayoutProps {
+ children: React.ReactNode;
+}
+
+export default function Layout({ children }: LayoutProps) {
const router = useRouter();
const [workspaceList, setWorkspaceList] = useState([]);
const [workspaceMapping, setWorkspaceMapping] = useState([{ 1: 2 }]);
const [workspaceSelected, setWorkspaceSelected] = useState("โ");
- let [newWorkspaceName, setNewWorkspaceName] = useState("");
- let [isOpen, setIsOpen] = useState(false);
+ const [newWorkspaceName, setNewWorkspaceName] = useState("");
+ const [isOpen, setIsOpen] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
@@ -44,158 +50,186 @@ export default function Layout({ children }) {
setIsOpen(false);
}
+ function openModal() {
+ setIsOpen(true);
+ }
+
// 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.
* @param {*} workspaceName
*/
- async function submitModal(workspaceName, addAllUsers) {
+ async function submitModal(workspaceName: string, addAllUsers: boolean) {
setLoading(true);
+ // timeout code.
setTimeout(() => setLoading(false), 1500);
- const workspaces = await getWorkspaces();
- const currentWorkspaces = workspaces.map((workspace) => workspace.name);
- if (!currentWorkspaces.includes(workspaceName)) {
- const newWorkspace = await createWorkspace({
- workspaceName,
- organizationId: localStorage.getItem("orgData.id")
- });
- let newWorkspaceId;
- try {
- newWorkspaceId = newWorkspace._id;
- } catch (error) {
- console.log(error);
- }
- if (addAllUsers) {
- let orgUsers = await getOrganizationUsers({
- orgId: localStorage.getItem("orgData.id"),
+
+ try {
+ const workspaces = await getWorkspaces();
+ const currentWorkspaces = workspaces.map((workspace) => workspace.name);
+ if (!currentWorkspaces.includes(workspaceName)) {
+ const newWorkspace = await createWorkspace({
+ workspaceName,
+ organizationId: tempLocalStorage("orgData.id"),
});
- orgUsers.map(async (user) => {
- if (user.status == "accepted") {
- let result = await addUserToWorkspace(
- user.user.email,
- newWorkspaceId
- );
- if (result?.invitee && result?.latestKey) {
- const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY");
+ const newWorkspaceId = newWorkspace._id;
- // assymmetrically decrypt symmetric key with local private key
- const key = decryptAssymmetric({
- ciphertext: result.latestKey.encryptedKey,
- nonce: result.latestKey.nonce,
- publicKey: result.latestKey.sender.publicKey,
- privateKey: PRIVATE_KEY,
- });
+ if (addAllUsers) {
+ const orgUsers = await getOrganizationUsers({
+ orgId: tempLocalStorage("orgData.id"),
+ });
+ orgUsers.map(async (user: any) => {
+ 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({
- plaintext: key,
- publicKey: result.invitee.publicKey,
- privateKey: PRIVATE_KEY,
- });
+ // assymmetrically decrypt symmetric key with local private key
+ const key = decryptAssymmetric({
+ ciphertext: result.latestKey.encryptedKey,
+ nonce: result.latestKey.nonce,
+ publicKey: result.latestKey.sender.publicKey,
+ privateKey: PRIVATE_KEY,
+ });
- 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");
- setIsOpen(false);
- setNewWorkspaceName("");
- } else {
- setError("A project with this name already exists.");
+ } catch (err) {
+ console.error(err);
+ setError(true);
setLoading(false);
}
}
- function openModal() {
- setIsOpen(true);
- }
-
const menuItems = [
{
href:
- "/dashboard/" + workspaceMapping[workspaceSelected] + "?Development",
+ "/dashboard/" +
+ workspaceMapping[workspaceSelected as any] +
+ "?Development",
title: "Secrets",
emoji: ,
},
{
- href: "/users/" + workspaceMapping[workspaceSelected],
+ href: "/users/" + workspaceMapping[workspaceSelected as any],
title: "Members",
emoji: ,
},
{
- href: "/integrations/" + workspaceMapping[workspaceSelected],
+ href: "/integrations/" + workspaceMapping[workspaceSelected as any],
title: "Integrations",
emoji: ,
},
{
- href: "/settings/project/" + workspaceMapping[workspaceSelected],
+ href: "/settings/project/" + workspaceMapping[workspaceSelected as any],
title: "Project Settings",
emoji: ,
},
];
- useEffect(async () => {
+ useEffect(() => {
// Put a user in a workspace if they're not in one yet
- if (
- localStorage.getItem("orgData.id") == null ||
- localStorage.getItem("orgData.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 putUserInWorkSpace = async () => {
+ if (tempLocalStorage("orgData.id") === "") {
+ const userOrgs = await getOrganizations();
+ localStorage.setItem("orgData.id", userOrgs[0]._id);
}
- }
+
+ 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(() => {
try {
if (
- workspaceMapping[workspaceSelected] &&
- workspaceMapping[workspaceSelected] !==
+ workspaceMapping[Number(workspaceSelected)] &&
+ `${workspaceMapping[Number(workspaceSelected)]}` !==
router.asPath
- .split("/")[router.asPath.split("/").length - 1].split("?")[0]
+ .split("/")
+ [router.asPath.split("/").length - 1].split("?")[0]
) {
- router.push("/dashboard/" + workspaceMapping[workspaceSelected] + "?Development");
+ router.push(
+ "/dashboard/" +
+ workspaceMapping[Number(workspaceSelected)] +
+ "?Development"
+ );
localStorage.setItem(
"projectData.id",
- workspaceMapping[workspaceSelected]
+ `${workspaceMapping[Number(workspaceSelected)]}`
);
}
} catch (error) {
@@ -212,18 +246,18 @@ export default function Layout({ children }) {