Compare commits

...

88 Commits

Author SHA1 Message Date
efd13e6b19 remove completions 2023-04-30 15:49:12 -04:00
4ac74e6e9a add back completion with dir 2023-04-30 15:36:55 -04:00
1d422fa82c Merge pull request #545 from Infisical/docs-guides
Add Preliminary Guides to Docs, Delete README translations
2023-04-30 22:28:06 +03:00
8ba3f8d1f7 Merge branch 'main' into docs-guides 2023-04-30 22:25:22 +03:00
6b83393952 Add initial Node, Python, Nextjs + Vercel guides to docs, delete README translations 2023-04-30 22:21:34 +03:00
da07d71e15 remove completions 2023-04-30 12:42:21 -04:00
82d3971d9e Update README.md 2023-04-30 09:07:25 -07:00
3dd21374e7 update go releaser distribution 2023-04-30 11:40:19 -04:00
c5fe41ae57 Merge pull request #543 from Infisical/multi-tag-repo
Only trigger CLI builds for tags with prefix infisical-cli/v*.*.*
2023-04-30 11:30:36 -04:00
9f0313f50b strip v from existing tags 2023-04-30 11:28:55 -04:00
a6e670e93a update tag fetch method to filetr for cli tags only 2023-04-30 11:22:28 -04:00
ec97e1a930 add mono repo support for goreleaser 2023-04-30 11:09:29 -04:00
55ca6938db update cli github action to only listen to infisical-cli/{version} tags 2023-04-30 11:08:58 -04:00
1401c7f6bc add go releaser pro 2023-04-30 10:32:39 -04:00
bb6d0fd7c6 Patch .secretValue access in INVITE_ONLY_SIGNUP 2023-04-30 14:56:27 +03:00
689a20dca2 Begin adding guides to docs 2023-04-30 14:54:54 +03:00
e4b4126971 Merge pull request #540 from Infisical/snyk-upgrade-291700b772b89271eb89e390de3aca7f
[Snyk] Upgrade @aws-sdk/client-secrets-manager from 3.306.0 to 3.309.0
2023-04-29 15:14:27 -04:00
04b04cba5c Merge pull request #539 from Infisical/snyk-upgrade-7c8dbe159d6a113e8720970276ee888f
[Snyk] Upgrade sharp from 0.31.3 to 0.32.0
2023-04-29 15:13:58 -04:00
89e5f644a4 Update README.md 2023-04-29 15:13:27 -04:00
c5619d27d7 Merge pull request #542 from Infisical/revise-readme
Updated README
2023-04-29 21:43:17 +03:00
12a1d8e822 Update README 2023-04-29 21:41:33 +03:00
a85a7d1b00 Update README 2023-04-29 21:23:05 +03:00
fc2846534f Update README 2023-04-29 21:06:25 +03:00
2b605856a3 Update README 2023-04-29 20:55:52 +03:00
191582ef26 Merge pull request #541 from Infisical/revise-quickstart
Add quickstarts to documentation
2023-04-29 20:40:34 +03:00
213b5d465b Merge remote-tracking branch 'origin' into revise-quickstart 2023-04-29 20:39:30 +03:00
75f550caf2 Finish documentation quickstarts update 2023-04-29 20:38:58 +03:00
daabf5ab70 add k8 quick start 2023-04-29 12:24:03 -04:00
7b11976a60 Preliminary README change proposal 2023-04-29 18:55:27 +03:00
39be52c6b2 make minor changes to wording for quick start guide 2023-04-29 11:27:04 -04:00
bced5d0151 Complete preliminary new quickstarts 2023-04-29 14:39:22 +03:00
939d7eb433 fix: upgrade @aws-sdk/client-secrets-manager from 3.306.0 to 3.309.0
Snyk has created this PR to upgrade @aws-sdk/client-secrets-manager from 3.306.0 to 3.309.0.

See this package in npm:
https://www.npmjs.com/package/@aws-sdk/client-secrets-manager

See this project in Snyk:
https://app.snyk.io/org/maidul98/project/35057e82-ed7d-4e19-ba4d-719a42135cd6?utm_source=github&utm_medium=referral&page=upgrade-pr
2023-04-29 00:29:10 +00:00
6de25174aa fix: upgrade sharp from 0.31.3 to 0.32.0
Snyk has created this PR to upgrade sharp from 0.31.3 to 0.32.0.

See this package in npm:
https://www.npmjs.com/package/sharp

See this project in Snyk:
https://app.snyk.io/org/maidul98/project/53d4ecb6-6cc1-4918-aa73-bf9cae4ffd13?utm_source=github&utm_medium=referral&page=upgrade-pr
2023-04-28 20:42:03 +00:00
2aa79d4ad6 Merge pull request #518 from seonggwonyoon/main
Add namespace option for using helm
2023-04-28 14:18:38 -04:00
44b4de754a remove test check in workflow 2023-04-28 13:21:38 -04:00
db0f0d0d9c disable secrets integ tests temp 2023-04-28 13:18:25 -04:00
3471e387ae Merge branch 'main' of https://github.com/Infisical/infisical 2023-04-28 10:11:36 -07:00
aadd964409 Fix the deployment issue 2023-04-28 10:11:25 -07:00
102e45891c Update getAppsGitHub to include pagination 2023-04-28 20:10:29 +03:00
b9ae224aef Patch organization invitation emails expiring for existing users and billing logic affected by missing organization populate call 2023-04-28 17:57:50 +03:00
e5cb0cbca3 Add preliminary platform, sdks, and cli quickstarts 2023-04-28 14:30:13 +03:00
330968c7af added gradient to the menu 2023-04-27 19:46:01 -07:00
68e8e727cd Merge branch 'main' of https://github.com/Infisical/infisical 2023-04-27 18:44:46 -07:00
3b94ee42e9 Animated menu icons 2023-04-27 18:44:23 -07:00
09286b4421 Merge pull request #530 from PylotLight/update-k8s-doc
Update k8s doc to add backend service info
2023-04-27 11:24:31 -04:00
04a9604ba9 add advanced use cases for hostAPI 2023-04-27 11:14:47 -04:00
d86f88db92 Merge pull request #526 from Infisical/snyk-upgrade-9829915033f54fef09ffef896e2c5908
[Snyk] Upgrade @sentry/tracing from 7.46.0 to 7.47.0
2023-04-27 09:57:55 -04:00
fc53c094b7 Merge branch 'main' into snyk-upgrade-9829915033f54fef09ffef896e2c5908 2023-04-27 09:57:49 -04:00
6726ca1882 Merge pull request #522 from Infisical/snyk-upgrade-521a72e06b59b78e721ff564679159b3
[Snyk] Upgrade @aws-sdk/client-secrets-manager from 3.303.0 to 3.306.0
2023-04-27 09:57:05 -04:00
ddbe4d7040 Merge pull request #527 from Infisical/snyk-upgrade-714666653eb4091158908b7ca4704cbb
[Snyk] Upgrade @sentry/node from 7.46.0 to 7.47.0
2023-04-27 09:56:53 -04:00
3f6b0a9e66 Merge pull request #528 from Infisical/snyk-upgrade-8b1f2b028bcdff3d60cbaa239abb732d
[Snyk] Upgrade axios from 1.3.4 to 1.3.5
2023-04-27 09:56:43 -04:00
c3a47597b6 fix formatting 2023-04-27 23:31:33 +10:00
a696a99232 add backend service inof to doc 2023-04-27 23:28:19 +10:00
8b1e64f75e Merge pull request #529 from Infisical/python-sdk-docs
Finish Python SDK docs
2023-04-27 15:57:19 +03:00
f137087ef1 Finish Python SDK docs 2023-04-27 15:53:23 +03:00
2157fab181 fix: upgrade axios from 1.3.4 to 1.3.5
Snyk has created this PR to upgrade axios from 1.3.4 to 1.3.5.

See this package in npm:
https://www.npmjs.com/package/axios

See this project in Snyk:
https://app.snyk.io/org/maidul98/project/35057e82-ed7d-4e19-ba4d-719a42135cd6?utm_source=github&utm_medium=referral&page=upgrade-pr
2023-04-27 04:43:44 +00:00
d2acab57e0 fix: upgrade @sentry/node from 7.46.0 to 7.47.0
Snyk has created this PR to upgrade @sentry/node from 7.46.0 to 7.47.0.

See this package in npm:
https://www.npmjs.com/package/@sentry/node

See this project in Snyk:
https://app.snyk.io/org/maidul98/project/35057e82-ed7d-4e19-ba4d-719a42135cd6?utm_source=github&utm_medium=referral&page=upgrade-pr
2023-04-27 04:43:39 +00:00
811929987b fix: upgrade @sentry/tracing from 7.46.0 to 7.47.0
Snyk has created this PR to upgrade @sentry/tracing from 7.46.0 to 7.47.0.

See this package in npm:
https://www.npmjs.com/package/@sentry/tracing

See this project in Snyk:
https://app.snyk.io/org/maidul98/project/35057e82-ed7d-4e19-ba4d-719a42135cd6?utm_source=github&utm_medium=referral&page=upgrade-pr
2023-04-27 04:43:36 +00:00
4ac13f61e0 Update README.md 2023-04-26 12:05:13 -07:00
3d2b0fa3fc Update docker-image.yml 2023-04-26 15:03:31 -04:00
242809ce26 add folders to batch and get secrets api 2023-04-26 12:53:14 -04:00
492bf39243 Clarify getSecret and caching behavior in docs 2023-04-26 12:11:46 +03:00
dbfa4f5277 Merge pull request #524 from Infisical/update-node-sdk
Update Infisical to use new Infisical Node SDK 1.1.3.
2023-04-26 11:58:07 +03:00
3fd2e22cbd Move Express example for Node SDK to top of that docs page 2023-04-26 11:53:46 +03:00
150eb1f5ee Merge remote-tracking branch 'origin' into update-node-sdk 2023-04-26 11:51:21 +03:00
6314a949f8 Update Infisical to use Infisical Node SDK 1.1.3 2023-04-26 11:50:51 +03:00
660c5806e3 Merge pull request #523 from Infisical/revise-node-sdk-docs
Revise docs for Node SDK
2023-04-26 09:31:54 +03:00
c6d2828262 Merge remote-tracking branch 'origin' into revise-node-sdk-docs 2023-04-26 09:30:03 +03:00
8dedfad22d fix: upgrade @aws-sdk/client-secrets-manager from 3.303.0 to 3.306.0
Snyk has created this PR to upgrade @aws-sdk/client-secrets-manager from 3.303.0 to 3.306.0.

See this package in npm:
https://www.npmjs.com/package/@aws-sdk/client-secrets-manager

See this project in Snyk:
https://app.snyk.io/org/maidul98/project/35057e82-ed7d-4e19-ba4d-719a42135cd6?utm_source=github&utm_medium=referral&page=upgrade-pr
2023-04-26 04:29:05 +00:00
7a3456ca1d scrolling fix 2023-04-25 19:25:31 -07:00
a946031d6f fix loading animation 2023-04-25 17:14:39 -07:00
f0075e8d09 add folder controller 2023-04-25 16:15:18 -04:00
3b00df6662 Updated readme 2023-04-25 08:12:12 -07:00
a263d7481b Added truncation for secret names on the comparison screen 2023-04-25 08:11:31 -07:00
6f91331549 Merge pull request #519 from Infisical/snyk-fix-c89a9aceb5e7741daf73a9a657eb1ead
[Snyk] Security upgrade yaml from 2.2.1 to 2.2.2
2023-04-25 10:14:55 -04:00
13ecc22159 fix: frontend/package.json & frontend/package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-YAML-5458867
2023-04-25 06:51:32 +00:00
a5c5ec1f4d Print helm with namespace 2023-04-25 10:55:27 +09:00
cbb28dc373 Merge pull request #517 from satyamgupta1495/patch-3
Added country flag [India]
2023-04-24 15:31:37 +03:00
e00aad4159 Merge pull request #515 from satyamgupta1495/patch-2
Translated README.md in Hindi language
2023-04-24 15:30:57 +03:00
fb8aaa9d9f Added country flag [india] 2023-04-24 17:57:33 +05:30
e5c5e4cca2 Updated readme.hi.md 2023-04-24 17:26:33 +05:30
803a97fdfc Translated README.md in Hindi language 2023-04-23 23:10:47 +05:30
9e42a7a33e Update quickstart example 2023-04-23 15:51:42 +03:00
34c79b08bc Update InfisicalClient initialization 2023-04-23 13:38:36 +03:00
aacdaf4556 Modify Node SDK docs to be inline with new initializer 2023-04-23 12:45:13 +03:00
a7484f8be5 Update node SDK docs, positioning of examples 2023-04-23 09:49:21 +03:00
e1bf31b371 Update envars to new node SDK format 2023-04-22 16:20:33 +03:00
3817831577 Update docs for upcoming Node SDK update 2023-04-22 14:34:05 +03:00
138 changed files with 12780 additions and 15234 deletions

View File

@ -4,7 +4,7 @@ on:
push:
# run only against tags
tags:
- "v*"
- "infisical-cli/v*.*.*"
permissions:
contents: write
@ -41,13 +41,14 @@ jobs:
git clone https://github.com/plentico/osxcross-target.git ../../osxcross/target
- uses: goreleaser/goreleaser-action@v4
with:
distribution: goreleaser
distribution: goreleaser-pro
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GO_RELEASER_GITHUB_TOKEN }}
FURY_TOKEN: ${{ secrets.FURYPUSHTOKEN }}
AUR_KEY: ${{ secrets.AUR_KEY }}
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
- uses: actions/setup-python@v4
- run: pip install --upgrade cloudsmith-cli
- name: Publish to CloudSmith

View File

@ -11,6 +11,10 @@ before:
- ./cli/scripts/completions.sh
- ./cli/scripts/manpages.sh
monorepo:
tag_prefix: infisical-cli/
dir: cli
builds:
- id: darwin-build
binary: infisical
@ -74,14 +78,7 @@ checksum:
name_template: "checksums.txt"
snapshot:
name_template: "{{ incpatch .Version }}-devel"
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
name_template: "{{ .Version }}-devel"
# publishers:
# - name: fury.io
@ -101,12 +98,12 @@ brews:
folder: Formula
homepage: "https://infisical.com"
description: "The official Infisical CLI"
install: |-
bin.install "infisical"
bash_completion.install "completions/infisical.bash" => "infisical"
zsh_completion.install "completions/infisical.zsh" => "_infisical"
fish_completion.install "completions/infisical.fish"
man1.install "manpages/infisical.1.gz"
# install: |-
# bin.install "infisical"
# bash_completion.install "completions/infisical.bash" => "infisical"
# zsh_completion.install "completions/infisical.zsh" => "_infisical"
# fish_completion.install "completions/infisical.fish"
# man1.install "manpages/infisical.1.gz"
nfpms:
- id: infisical
@ -124,15 +121,15 @@ nfpms:
- apk
- archlinux
bindir: /usr/bin
contents:
- src: ./completions/infisical.bash
dst: /etc/bash_completion.d/infisical
- src: ./completions/infisical.fish
dst: /usr/share/fish/vendor_completions.d/infisical.fish
- src: ./completions/infisical.zsh
dst: /usr/share/zsh/site-functions/_infisical
- src: ./manpages/infisical.1.gz
dst: /usr/share/man/man1/infisical.1.gz
# contents:
# - src: ./completions/infisical.bash
# dst: /etc/bash_completion.d/infisical
# - src: ./completions/infisical.fish
# dst: /usr/share/fish/vendor_completions.d/infisical.fish
# - src: ./completions/infisical.zsh
# dst: /usr/share/zsh/site-functions/_infisical
# - src: ./manpages/infisical.1.gz
# dst: /usr/share/man/man1/infisical.1.gz
scoop:
bucket:
@ -159,15 +156,6 @@ aurs:
install -Dm755 "./infisical" "${pkgdir}/usr/bin/infisical"
# license
install -Dm644 "./LICENSE" "${pkgdir}/usr/share/licenses/infisical/LICENSE"
# completions
mkdir -p "${pkgdir}/usr/share/bash-completion/completions/"
mkdir -p "${pkgdir}/usr/share/zsh/site-functions/"
mkdir -p "${pkgdir}/usr/share/fish/vendor_completions.d/"
install -Dm644 "./completions/infisical.bash" "${pkgdir}/usr/share/bash-completion/completions/infisical"
install -Dm644 "./completions/infisical.zsh" "${pkgdir}/usr/share/zsh/site-functions/infisical"
install -Dm644 "./completions/infisical.fish" "${pkgdir}/usr/share/fish/vendor_completions.d/infisical.fish"
# man pages
install -Dm644 "./manpages/infisical.1.gz" "${pkgdir}/usr/share/man/man1/infisical.1.gz"
# dockers:
# - dockerfile: cli/docker/Dockerfile

356
README.md

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,13 @@
# Security Policy
## Supported Versions
## Supported versions
We always recommend using the latest version of Infisical to ensure you get all security updates.
## Reporting a Vulnerability
## Reporting vulnerabilities
Please report security vulnerabilities or concerns to team@infisical.com.
Please do not file GitHub issues or post on our public forum for security vulnerabilities, as they are public!
Infisical takes security issues very seriously. If you have any concerns about Infisical or believe you have uncovered a vulnerability, please get in touch via the e-mail address security@infisical.com. In the message, try to provide a description of the issue and ideally a way of reproducing it. The security team will get back to you as soon as possible.
Note that this security address should be used only for undisclosed vulnerabilities. Please report any security problems to us before disclosing it publicly.

1736
backend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,16 @@
{
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.303.0",
"@aws-sdk/client-secrets-manager": "^3.309.0",
"@godaddy/terminus": "^4.11.2",
"@octokit/rest": "^19.0.5",
"@sentry/node": "^7.45.0",
"@sentry/tracing": "^7.46.0",
"@sentry/node": "^7.41.0",
"@sentry/tracing": "^7.47.0",
"@types/crypto-js": "^4.1.1",
"@types/libsodium-wrappers": "^0.7.10",
"argon2": "^0.30.3",
"await-to-js": "^3.0.0",
"aws-sdk": "^2.1338.0",
"axios": "^1.1.3",
"axios": "^1.3.5",
"axios-retry": "^3.4.0",
"bcrypt": "^5.1.0",
"bigint-conversion": "^2.2.2",
@ -25,7 +24,7 @@
"express-validator": "^6.14.2",
"handlebars": "^4.7.7",
"helmet": "^5.1.1",
"infisical-node": "^1.0.37",
"infisical-node": "^1.1.3",
"js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.0",
"jsrp": "^0.2.4",

View File

@ -1,64 +1,69 @@
import infisical from 'infisical-node';
export const getPort = () => infisical.get('PORT')! || 4000;
export const getInviteOnlySignup = () => infisical.get('INVITE_ONLY_SIGNUP')! == undefined ? false : infisical.get('INVITE_ONLY_SIGNUP');
export const getEncryptionKey = () => infisical.get('ENCRYPTION_KEY')!;
export const getSaltRounds = () => parseInt(infisical.get('SALT_ROUNDS')!) || 10;
export const getJwtAuthLifetime = () => infisical.get('JWT_AUTH_LIFETIME')! || '10d';
export const getJwtAuthSecret = () => infisical.get('JWT_AUTH_SECRET')!;
export const getJwtMfaLifetime = () => infisical.get('JWT_MFA_LIFETIME')! || '5m';
export const getJwtMfaSecret = () => infisical.get('JWT_MFA_LIFETIME')! || '5m';
export const getJwtRefreshLifetime = () => infisical.get('JWT_REFRESH_LIFETIME')! || '90d';
export const getJwtRefreshSecret = () => infisical.get('JWT_REFRESH_SECRET')!;
export const getJwtServiceSecret = () => infisical.get('JWT_SERVICE_SECRET')!;
export const getJwtSignupLifetime = () => infisical.get('JWT_SIGNUP_LIFETIME')! || '15m';
export const getJwtSignupSecret = () => infisical.get('JWT_SIGNUP_SECRET')!;
export const getMongoURL = () => infisical.get('MONGO_URL')!;
export const getNodeEnv = () => infisical.get('NODE_ENV')! || 'production';
export const getVerboseErrorOutput = () => infisical.get('VERBOSE_ERROR_OUTPUT')! === 'true' && true;
export const getLokiHost = () => infisical.get('LOKI_HOST')!;
export const getClientIdAzure = () => infisical.get('CLIENT_ID_AZURE')!;
export const getClientIdHeroku = () => infisical.get('CLIENT_ID_HEROKU')!;
export const getClientIdVercel = () => infisical.get('CLIENT_ID_VERCEL')!;
export const getClientIdNetlify = () => infisical.get('CLIENT_ID_NETLIFY')!;
export const getClientIdGitHub = () => infisical.get('CLIENT_ID_GITHUB')!;
export const getClientIdGitLab = () => infisical.get('CLIENT_ID_GITLAB')!;
export const getClientSecretAzure = () => infisical.get('CLIENT_SECRET_AZURE')!;
export const getClientSecretHeroku = () => infisical.get('CLIENT_SECRET_HEROKU')!;
export const getClientSecretVercel = () => infisical.get('CLIENT_SECRET_VERCEL')!;
export const getClientSecretNetlify = () => infisical.get('CLIENT_SECRET_NETLIFY')!;
export const getClientSecretGitHub = () => infisical.get('CLIENT_SECRET_GITHUB')!;
export const getClientSecretGitLab = () => infisical.get('CLIENT_SECRET_GITLAB')!;
export const getClientSlugVercel = () => infisical.get('CLIENT_SLUG_VERCEL')!;
export const getPostHogHost = () => infisical.get('POSTHOG_HOST')! || 'https://app.posthog.com';
export const getPostHogProjectApiKey = () => infisical.get('POSTHOG_PROJECT_API_KEY')! || 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE';
export const getSentryDSN = () => infisical.get('SENTRY_DSN')!;
export const getSiteURL = () => infisical.get('SITE_URL')!;
export const getSmtpHost = () => infisical.get('SMTP_HOST')!;
export const getSmtpSecure = () => infisical.get('SMTP_SECURE')! === 'true' || false;
export const getSmtpPort = () => parseInt(infisical.get('SMTP_PORT')!) || 587;
export const getSmtpUsername = () => infisical.get('SMTP_USERNAME')!;
export const getSmtpPassword = () => infisical.get('SMTP_PASSWORD')!;
export const getSmtpFromAddress = () => infisical.get('SMTP_FROM_ADDRESS')!;
export const getSmtpFromName = () => infisical.get('SMTP_FROM_NAME')! || 'Infisical';
export const getStripeProductStarter = () => infisical.get('STRIPE_PRODUCT_STARTER')!;
export const getStripeProductPro = () => infisical.get('STRIPE_PRODUCT_PRO')!;
export const getStripeProductTeam = () => infisical.get('STRIPE_PRODUCT_TEAM')!;
export const getStripePublishableKey = () => infisical.get('STRIPE_PUBLISHABLE_KEY')!;
export const getStripeSecretKey = () => infisical.get('STRIPE_SECRET_KEY')!;
export const getStripeWebhookSecret = () => infisical.get('STRIPE_WEBHOOK_SECRET')!;
export const getTelemetryEnabled = () => infisical.get('TELEMETRY_ENABLED')! !== 'false' && true;
export const getLoopsApiKey = () => infisical.get('LOOPS_API_KEY')!;
export const getSmtpConfigured = () => infisical.get('SMTP_HOST') == '' || infisical.get('SMTP_HOST') == undefined ? false : true
export const getHttpsEnabled = () => {
if (getNodeEnv() != "production") {
import InfisicalClient from 'infisical-node';
const client = new InfisicalClient({
token: process.env.INFISICAL_TOKEN!
});
export const getPort = async () => (await client.getSecret('PORT')).secretValue || 4000;
export const getInviteOnlySignup = async () => (await client.getSecret('INVITE_ONLY_SIGNUP')).secretValue == undefined ? false : (await client.getSecret('INVITE_ONLY_SIGNUP')).secretValue;
export const getEncryptionKey = async () => (await client.getSecret('ENCRYPTION_KEY')).secretValue;
export const getSaltRounds = async () => parseInt((await client.getSecret('SALT_ROUNDS')).secretValue) || 10;
export const getJwtAuthLifetime = async () => (await client.getSecret('JWT_AUTH_LIFETIME')).secretValue || '10d';
export const getJwtAuthSecret = async () => (await client.getSecret('JWT_AUTH_SECRET')).secretValue;
export const getJwtMfaLifetime = async () => (await client.getSecret('JWT_MFA_LIFETIME')).secretValue || '5m';
export const getJwtMfaSecret = async () => (await client.getSecret('JWT_MFA_LIFETIME')).secretValue || '5m';
export const getJwtRefreshLifetime = async () => (await client.getSecret('JWT_REFRESH_LIFETIME')).secretValue || '90d';
export const getJwtRefreshSecret = async () => (await client.getSecret('JWT_REFRESH_SECRET')).secretValue;
export const getJwtServiceSecret = async () => (await client.getSecret('JWT_SERVICE_SECRET')).secretValue;
export const getJwtSignupLifetime = async () => (await client.getSecret('JWT_SIGNUP_LIFETIME')).secretValue || '15m';
export const getJwtSignupSecret = async () => (await client.getSecret('JWT_SIGNUP_SECRET')).secretValue;
export const getMongoURL = async () => (await client.getSecret('MONGO_URL')).secretValue;
export const getNodeEnv = async () => (await client.getSecret('NODE_ENV')).secretValue || 'production';
export const getVerboseErrorOutput = async () => (await client.getSecret('VERBOSE_ERROR_OUTPUT')).secretValue === 'true' && true;
export const getLokiHost = async () => (await client.getSecret('LOKI_HOST')).secretValue;
export const getClientIdAzure = async () => (await client.getSecret('CLIENT_ID_AZURE')).secretValue;
export const getClientIdHeroku = async () => (await client.getSecret('CLIENT_ID_HEROKU')).secretValue;
export const getClientIdVercel = async () => (await client.getSecret('CLIENT_ID_VERCEL')).secretValue;
export const getClientIdNetlify = async () => (await client.getSecret('CLIENT_ID_NETLIFY')).secretValue;
export const getClientIdGitHub = async () => (await client.getSecret('CLIENT_ID_GITHUB')).secretValue;
export const getClientIdGitLab = async () => (await client.getSecret('CLIENT_ID_GITLAB')).secretValue;
export const getClientSecretAzure = async () => (await client.getSecret('CLIENT_SECRET_AZURE')).secretValue;
export const getClientSecretHeroku = async () => (await client.getSecret('CLIENT_SECRET_HEROKU')).secretValue;
export const getClientSecretVercel = async () => (await client.getSecret('CLIENT_SECRET_VERCEL')).secretValue;
export const getClientSecretNetlify = async () => (await client.getSecret('CLIENT_SECRET_NETLIFY')).secretValue;
export const getClientSecretGitHub = async () => (await client.getSecret('CLIENT_SECRET_GITHUB')).secretValue;
export const getClientSecretGitLab = async () => (await client.getSecret('CLIENT_SECRET_GITLAB')).secretValue;
export const getClientSlugVercel = async () => (await client.getSecret('CLIENT_SLUG_VERCEL')).secretValue;
export const getPostHogHost = async () => (await client.getSecret('POSTHOG_HOST')).secretValue || 'https://app.posthog.com';
export const getPostHogProjectApiKey = async () => (await client.getSecret('POSTHOG_PROJECT_API_KEY')).secretValue || 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE';
export const getSentryDSN = async () => (await client.getSecret('SENTRY_DSN')).secretValue;
export const getSiteURL = async () => (await client.getSecret('SITE_URL')).secretValue;
export const getSmtpHost = async () => (await client.getSecret('SMTP_HOST')).secretValue;
export const getSmtpSecure = async () => (await client.getSecret('SMTP_SECURE')).secretValue === 'true' || false;
export const getSmtpPort = async () => parseInt((await client.getSecret('SMTP_PORT')).secretValue) || 587;
export const getSmtpUsername = async () => (await client.getSecret('SMTP_USERNAME')).secretValue;
export const getSmtpPassword = async () => (await client.getSecret('SMTP_PASSWORD')).secretValue;
export const getSmtpFromAddress = async () => (await client.getSecret('SMTP_FROM_ADDRESS')).secretValue;
export const getSmtpFromName = async () => (await client.getSecret('SMTP_FROM_NAME')).secretValue || 'Infisical';
export const getStripeProductStarter = async () => (await client.getSecret('STRIPE_PRODUCT_STARTER')).secretValue;
export const getStripeProductPro = async () => (await client.getSecret('STRIPE_PRODUCT_PRO')).secretValue;
export const getStripeProductTeam = async () => (await client.getSecret('STRIPE_PRODUCT_TEAM')).secretValue;
export const getStripePublishableKey = async () => (await client.getSecret('STRIPE_PUBLISHABLE_KEY')).secretValue;
export const getStripeSecretKey = async () => (await client.getSecret('STRIPE_SECRET_KEY')).secretValue;
export const getStripeWebhookSecret = async () => (await client.getSecret('STRIPE_WEBHOOK_SECRET')).secretValue;
export const getTelemetryEnabled = async () => (await client.getSecret('TELEMETRY_ENABLED')).secretValue !== 'false' && true;
export const getLoopsApiKey = async () => (await client.getSecret('LOOPS_API_KEY')).secretValue;
export const getSmtpConfigured = async () => (await client.getSecret('SMTP_HOST')).secretValue == '' || (await client.getSecret('SMTP_HOST')).secretValue == undefined ? false : true
export const getHttpsEnabled = async () => {
if ((await getNodeEnv()) != "production") {
// no https for anything other than prod
return false
}
if (infisical.get('HTTPS_ENABLED') == undefined || infisical.get('HTTPS_ENABLED') == "") {
if ((await client.getSecret('HTTPS_ENABLED')).secretValue == undefined || (await client.getSecret('HTTPS_ENABLED')).secretValue == "") {
// default when no value present
return true
}
return infisical.get('HTTPS_ENABLED') === 'true' && true
return (await client.getSecret('HTTPS_ENABLED')).secretValue === 'true' && true
}

View File

@ -126,7 +126,7 @@ export const login2 = async (req: Request, res: Response) => {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: getHttpsEnabled()
secure: await getHttpsEnabled()
});
const loginAction = await EELogService.createAction({
@ -182,7 +182,7 @@ export const logout = async (req: Request, res: Response) => {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: getHttpsEnabled() as boolean
secure: (await getHttpsEnabled()) as boolean
});
const logoutAction = await EELogService.createAction({
@ -237,7 +237,7 @@ export const getNewToken = async (req: Request, res: Response) => {
}
const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(refreshToken, getJwtRefreshSecret())
jwt.verify(refreshToken, await getJwtRefreshSecret())
);
const user = await User.findOne({
@ -252,8 +252,8 @@ export const getNewToken = async (req: Request, res: Response) => {
payload: {
userId: decodedToken.userId
},
expiresIn: getJwtAuthLifetime(),
secret: getJwtAuthSecret()
expiresIn: await getJwtAuthLifetime(),
secret: await getJwtAuthSecret()
});
return res.status(200).send({

View File

@ -44,7 +44,7 @@ export const getIntegrationAuth = async (req: Request, res: Response) => {
}
export const getIntegrationOptions = async (req: Request, res: Response) => {
const INTEGRATION_OPTIONS = getIntegrationOptionsFunc();
const INTEGRATION_OPTIONS = await getIntegrationOptionsFunc();
return res.status(200).send({
integrationOptions: INTEGRATION_OPTIONS,

View File

@ -215,7 +215,7 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => {
inviterFirstName: req.user.firstName,
inviterEmail: req.user.email,
workspaceName: req.membership.workspace.name,
callback_url: getSiteURL() + '/login'
callback_url: (await getSiteURL()) + '/login'
}
});
} catch (err) {

View File

@ -1,3 +1,4 @@
import { Types } from 'mongoose';
import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { MembershipOrg, Organization, User } from '../../models';
@ -139,7 +140,7 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
inviteEmail: inviteeEmail,
organization: organizationId,
role: MEMBER,
status: invitee?.publicKey ? ACCEPTED : INVITED
status: INVITED
}).save();
}
} else {
@ -164,6 +165,7 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
const organization = await Organization.findOne({ _id: organizationId });
if (organization) {
const token = await TokenService.createToken({
type: TOKEN_EMAIL_ORG_INVITATION,
email: inviteeEmail,
@ -179,12 +181,13 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
inviterEmail: req.user.email,
organizationName: organization.name,
email: inviteeEmail,
organizationId: organization._id.toString(),
token,
callback_url: getSiteURL() + '/signupinvite'
callback_url: (await getSiteURL()) + '/signupinvite'
}
});
if (!getSmtpConfigured()) {
if (!(await getSmtpConfigured())) {
completeInviteLink = `${siteUrl + '/signupinvite'}?token=${token}&to=${inviteeEmail}`
}
}
@ -214,13 +217,18 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
export const verifyUserToOrganization = async (req: Request, res: Response) => {
let user, token;
try {
const { email, code } = req.body;
const {
email,
organizationId,
code
} = req.body;
user = await User.findOne({ email }).select('+publicKey');
const membershipOrg = await MembershipOrg.findOne({
inviteEmail: email,
status: INVITED
status: INVITED,
organization: new Types.ObjectId(organizationId)
});
if (!membershipOrg)
@ -257,8 +265,8 @@ export const verifyUserToOrganization = async (req: Request, res: Response) => {
payload: {
userId: user._id.toString()
},
expiresIn: getJwtSignupLifetime(),
secret: getJwtSignupSecret()
expiresIn: await getJwtSignupLifetime(),
secret: await getJwtSignupSecret()
});
} catch (err) {
Sentry.setUser(null);

View File

@ -85,7 +85,7 @@ export const createOrganization = async (req: Request, res: Response) => {
export const getOrganization = async (req: Request, res: Response) => {
let organization;
try {
organization = req.membershipOrg.organization;
organization = req.organization
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
@ -317,29 +317,29 @@ export const createOrganizationPortalSession = async (
) => {
let session;
try {
const stripe = new Stripe(getStripeSecretKey(), {
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: '2022-08-01'
});
// check if there is a payment method on file
const paymentMethods = await stripe.paymentMethods.list({
customer: req.membershipOrg.organization.customerId,
customer: req.organization.customerId,
type: 'card'
});
if (paymentMethods.data.length < 1) {
// case: no payment method on file
session = await stripe.checkout.sessions.create({
customer: req.membershipOrg.organization.customerId,
customer: req.organization.customerId,
mode: 'setup',
payment_method_types: ['card'],
success_url: getSiteURL() + '/dashboard',
cancel_url: getSiteURL() + '/dashboard'
success_url: (await getSiteURL()) + '/dashboard',
cancel_url: (await getSiteURL()) + '/dashboard'
});
} else {
session = await stripe.billingPortal.sessions.create({
customer: req.membershipOrg.organization.customerId,
return_url: getSiteURL() + '/dashboard'
customer: req.organization.customerId,
return_url: (await getSiteURL()) + '/dashboard'
});
}
@ -365,12 +365,12 @@ export const getOrganizationSubscriptions = async (
) => {
let subscriptions;
try {
const stripe = new Stripe(getStripeSecretKey(), {
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: '2022-08-01'
});
subscriptions = await stripe.subscriptions.list({
customer: req.membershipOrg.organization.customerId
customer: req.organization.customerId
});
} catch (err) {
Sentry.setUser({ email: req.user.email });

View File

@ -44,7 +44,7 @@ export const emailPasswordReset = async (req: Request, res: Response) => {
substitutions: {
email,
token,
callback_url: getSiteURL() + '/password-reset'
callback_url: (await getSiteURL()) + '/password-reset'
}
});
} catch (err) {
@ -91,8 +91,8 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => {
payload: {
userId: user._id.toString()
},
expiresIn: getJwtSignupLifetime(),
secret: getJwtSignupSecret()
expiresIn: await getJwtSignupLifetime(),
secret: await getJwtSignupSecret()
});
} catch (err) {
Sentry.setUser(null);

View File

@ -39,7 +39,7 @@ export const pushSecrets = async (req: Request, res: Response) => {
// upload (encrypted) secrets to workspace with id [workspaceId]
try {
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
let { secrets }: { secrets: PushSecret[] } = req.body;
const { keys, environment, channel } = req.body;
const { workspaceId } = req.params;
@ -114,7 +114,7 @@ export const pullSecrets = async (req: Request, res: Response) => {
let secrets;
let key;
try {
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
const environment: string = req.query.environment as string;
const channel: string = req.query.channel as string;
const { workspaceId } = req.params;
@ -183,7 +183,7 @@ export const pullSecretsServiceToken = async (req: Request, res: Response) => {
let secrets;
let key;
try {
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
const environment: string = req.query.environment as string;
const channel: string = req.query.channel as string;
const { workspaceId } = req.params;

View File

@ -0,0 +1,89 @@
import { Request, Response } from 'express';
import { Secret } from '../../models';
import Folder from '../../models/folder';
import { BadRequestError } from '../../utils/errors';
import { ROOT_FOLDER_PATH, getFolderPath, getParentPath, normalizePath, validateFolderName } from '../../utils/folder';
import { ADMIN, MEMBER } from '../../variables';
import { validateMembership } from '../../helpers/membership';
// TODO
// verify workspace id/environment
export const createFolder = async (req: Request, res: Response) => {
const { workspaceId, environment, folderName, parentFolderId } = req.body
if (!validateFolderName(folderName)) {
throw BadRequestError({ message: "Folder name cannot contain spaces. Only underscore and dashes" })
}
if (parentFolderId) {
const parentFolder = await Folder.find({ environment: environment, workspace: workspaceId, id: parentFolderId });
if (!parentFolder) {
throw BadRequestError({ message: "The parent folder doesn't exist" })
}
}
let completePath = await getFolderPath(parentFolderId)
if (completePath == ROOT_FOLDER_PATH) {
completePath = ""
}
const currentFolderPath = completePath + "/" + folderName // construct new path with current folder to be created
const normalizedCurrentPath = normalizePath(currentFolderPath)
const normalizedParentPath = getParentPath(normalizedCurrentPath)
const existingFolder = await Folder.findOne({
name: folderName,
workspace: workspaceId,
environment: environment,
parent: parentFolderId,
path: normalizedCurrentPath
});
if (existingFolder) {
return res.json(existingFolder)
}
const newFolder = new Folder({
name: folderName,
workspace: workspaceId,
environment: environment,
parent: parentFolderId,
path: normalizedCurrentPath,
parentPath: normalizedParentPath
});
await newFolder.save();
return res.json(newFolder)
}
export const deleteFolder = async (req: Request, res: Response) => {
const { folderId } = req.params
const queue: any[] = [folderId];
const folder = await Folder.findById(folderId);
if (!folder) {
throw BadRequestError({ message: "The folder doesn't exist" })
}
// check that user is a member of the workspace
await validateMembership({
userId: req.user._id.toString(),
workspaceId: folder.workspace as any,
acceptedRoles: [ADMIN, MEMBER]
});
while (queue.length > 0) {
const currentFolderId = queue.shift();
const childFolders = await Folder.find({ parent: currentFolderId });
for (const childFolder of childFolders) {
queue.push(childFolder._id);
}
await Secret.deleteMany({ folder: currentFolderId });
await Folder.deleteOne({ _id: currentFolderId });
}
res.send()
}

View File

@ -61,7 +61,7 @@ export const createServiceToken = async (req: Request, res: Response) => {
workspaceId
},
expiresIn: expiresIn,
secret: getJwtServiceSecret()
secret: await getJwtServiceSecret()
});
} catch (err) {
return res.status(400).send({

View File

@ -21,7 +21,7 @@ export const beginEmailSignup = async (req: Request, res: Response) => {
try {
email = req.body.email;
if (getInviteOnlySignup()) {
if (await getInviteOnlySignup()) {
// Only one user can create an account without being invited. The rest need to be invited in order to make an account
const userCount = await User.countDocuments({})
if (userCount != 0) {
@ -75,7 +75,7 @@ export const verifyEmailSignup = async (req: Request, res: Response) => {
}
// verify email
if (getSmtpConfigured()) {
if (await getSmtpConfigured()) {
await checkEmailVerification({
email,
code
@ -93,8 +93,8 @@ export const verifyEmailSignup = async (req: Request, res: Response) => {
payload: {
userId: user._id.toString()
},
expiresIn: getJwtSignupLifetime(),
secret: getJwtSignupSecret()
expiresIn: await getJwtSignupLifetime(),
secret: await getJwtSignupSecret()
});
} catch (err) {
Sentry.setUser(null);

View File

@ -13,7 +13,7 @@ export const handleWebhook = async (req: Request, res: Response) => {
let event;
try {
// check request for valid stripe signature
const stripe = new Stripe(getStripeSecretKey(), {
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: '2022-08-01'
});
@ -21,7 +21,7 @@ export const handleWebhook = async (req: Request, res: Response) => {
event = stripe.webhooks.constructEvent(
req.body,
sig,
getStripeWebhookSecret()
await getStripeWebhookSecret()
);
} catch (err) {
Sentry.setUser({ email: req.user.email });

View File

@ -43,7 +43,7 @@ export const createAPIKeyData = async (req: Request, res: Response) => {
const { name, expiresIn } = req.body;
const secret = crypto.randomBytes(16).toString('hex');
const secretHash = await bcrypt.hash(secret, getSaltRounds());
const secretHash = await bcrypt.hash(secret, await getSaltRounds());
const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);

View File

@ -124,8 +124,8 @@ export const login2 = async (req: Request, res: Response) => {
payload: {
userId: user._id.toString()
},
expiresIn: getJwtMfaLifetime(),
secret: getJwtMfaSecret()
expiresIn: await getJwtMfaLifetime(),
secret: await getJwtMfaSecret()
});
const code = await TokenService.createToken({
@ -163,7 +163,7 @@ export const login2 = async (req: Request, res: Response) => {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: getHttpsEnabled()
secure: await getHttpsEnabled()
});
// case: user does not have MFA enablgged
@ -302,7 +302,7 @@ export const verifyMfaToken = async (req: Request, res: Response) => {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: getHttpsEnabled()
secure: await getHttpsEnabled()
});
interface VerifyMfaTokenRes {

View File

@ -17,7 +17,7 @@ import { AccountNotFoundError } from '../../utils/errors';
* @param res
*/
export const createSecret = async (req: Request, res: Response) => {
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
const secretToCreate: CreateSecretRequestBody = req.body.secret;
const { workspaceId, environment } = req.params
const sanitizedSecret: SanitizedSecretForCreate = {
@ -70,7 +70,7 @@ export const createSecret = async (req: Request, res: Response) => {
* @param res
*/
export const createSecrets = async (req: Request, res: Response) => {
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
const secretsToCreate: CreateSecretRequestBody[] = req.body.secrets;
const { workspaceId, environment } = req.params
const sanitizedSecretesToCreate: SanitizedSecretForCreate[] = []
@ -132,7 +132,7 @@ export const createSecrets = async (req: Request, res: Response) => {
* @param res
*/
export const deleteSecrets = async (req: Request, res: Response) => {
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
const { workspaceId, environmentName } = req.params
const secretIdsToDelete: string[] = req.body.secretIds
@ -186,7 +186,7 @@ export const deleteSecrets = async (req: Request, res: Response) => {
* @param res
*/
export const deleteSecret = async (req: Request, res: Response) => {
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
await Secret.findByIdAndDelete(req._secret._id)
if (postHogClient) {
@ -215,7 +215,7 @@ export const deleteSecret = async (req: Request, res: Response) => {
* @returns
*/
export const updateSecrets = async (req: Request, res: Response) => {
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
const { workspaceId, environmentName } = req.params
const secretsModificationsRequested: ModifySecretRequestBody[] = req.body.secrets;
const [secretIdsUserCanModifyError, secretIdsUserCanModify] = await to(Secret.find({ workspace: workspaceId, environment: environmentName }, { _id: 1 }).then())
@ -283,7 +283,7 @@ export const updateSecrets = async (req: Request, res: Response) => {
* @returns
*/
export const updateSecret = async (req: Request, res: Response) => {
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
const { workspaceId, environmentName } = req.params
const secretModificationsRequested: ModifySecretRequestBody = req.body.secret;
@ -337,7 +337,7 @@ export const updateSecret = async (req: Request, res: Response) => {
* @returns
*/
export const getSecrets = async (req: Request, res: Response) => {
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
const { environment } = req.query;
const { workspaceId } = req.params;

View File

@ -25,6 +25,8 @@ import {
BatchSecretRequest,
BatchSecret
} from '../../types/secret';
import { getFolderPath, getFoldersInDirectory, normalizePath } from '../../utils/folder';
import { ROOT_FOLDER_PATH } from '../../utils/folder';
/**
* Peform a batch of any specified CUD secret operations
@ -35,7 +37,7 @@ import {
export const batchSecrets = async (req: Request, res: Response) => {
const channel = getChannelFromUserAgent(req.headers['user-agent']);
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
const {
workspaceId,
@ -51,13 +53,18 @@ export const batchSecrets = async (req: Request, res: Response) => {
const updateSecrets: BatchSecret[] = [];
const deleteSecrets: Types.ObjectId[] = [];
const actions: IAction[] = [];
// get secret blind index salt
const salt = await SecretService.getSecretBlindIndexSalt({
workspaceId: new Types.ObjectId(workspaceId)
});
for await (const request of requests) {
const folderId = request.secret.folderId
// TODO: need to auth folder
const fullFolderPath = await getFolderPath(folderId)
let secretBlindIndex = '';
switch (request.method) {
case 'POST':
@ -72,19 +79,23 @@ export const batchSecrets = async (req: Request, res: Response) => {
user: request.secret.type === SECRET_PERSONAL ? req.user : undefined,
environment,
workspace: new Types.ObjectId(workspaceId),
path: fullFolderPath,
folder: folderId,
secretBlindIndex
});
break;
case 'PATCH':
secretBlindIndex = await SecretService.generateSecretBlindIndexWithSalt({
secretName: request.secret.secretName,
salt
salt,
});
updateSecrets.push({
...request.secret,
_id: new Types.ObjectId(request.secret._id),
secretBlindIndex
secretBlindIndex,
folder: folderId,
path: fullFolderPath,
});
break;
case 'DELETE':
@ -437,9 +448,9 @@ export const createSecrets = async (req: Request, res: Response) => {
});
})
);
const newlyCreatedSecrets: ISecret[] = (await Secret.insertMany(secretsToInsert)).map((insertedSecret) => insertedSecret.toObject());
setTimeout(async () => {
// trigger event - push secrets
await EventService.handleEvent({
@ -508,7 +519,7 @@ export const createSecrets = async (req: Request, res: Response) => {
workspaceId: new Types.ObjectId(workspaceId)
});
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) {
postHogClient.capture({
event: 'secrets added',
@ -578,9 +589,11 @@ export const getSecrets = async (req: Request, res: Response) => {
}
*/
const { tagSlugs } = req.query;
const { tagSlugs, secretsPath } = req.query;
const workspaceId = req.query.workspaceId as string;
const environment = req.query.environment as string;
const normalizedPath = normalizePath(secretsPath as string)
const folders = await getFoldersInDirectory(workspaceId as string, environment as string, normalizedPath)
// secrets to return
let secrets: ISecret[] = [];
@ -613,6 +626,12 @@ export const getSecrets = async (req: Request, res: Response) => {
]
}
if (normalizedPath == ROOT_FOLDER_PATH) {
secretQuery.path = { $in: [ROOT_FOLDER_PATH, null, undefined] }
} else if (normalizedPath) {
secretQuery.path = normalizedPath
}
if (tagIds.length > 0) {
secretQuery.tags = { $in: tagIds };
}
@ -638,6 +657,13 @@ export const getSecrets = async (req: Request, res: Response) => {
]
}
// TODO: check if user can query for given path
if (normalizedPath == ROOT_FOLDER_PATH) {
secretQuery.path = { $in: [ROOT_FOLDER_PATH, null, undefined] }
} else if (normalizedPath) {
secretQuery.path = normalizedPath
}
if (tagIds.length > 0) {
secretQuery.tags = { $in: tagIds };
}
@ -655,6 +681,12 @@ export const getSecrets = async (req: Request, res: Response) => {
user: { $exists: false } // shared secrets only from workspace
}
if (normalizedPath == ROOT_FOLDER_PATH) {
secretQuery.path = { $in: [ROOT_FOLDER_PATH, null, undefined] }
} else if (normalizedPath) {
secretQuery.path = normalizedPath
}
if (tagIds.length > 0) {
secretQuery.tags = { $in: tagIds };
}
@ -683,7 +715,7 @@ export const getSecrets = async (req: Request, res: Response) => {
ipAddress: req.ip
});
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) {
postHogClient.capture({
event: 'secrets pulled',
@ -701,7 +733,8 @@ export const getSecrets = async (req: Request, res: Response) => {
}
return res.status(200).send({
secrets
secrets,
folders
});
}
@ -905,7 +938,7 @@ export const updateSecrets = async (req: Request, res: Response) => {
workspaceId: new Types.ObjectId(key)
})
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) {
postHogClient.capture({
event: 'secrets modified',
@ -1039,7 +1072,7 @@ export const deleteSecrets = async (req: Request, res: Response) => {
workspaceId: new Types.ObjectId(key)
});
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) {
postHogClient.capture({
event: 'secrets deleted',

View File

@ -72,7 +72,7 @@ export const createServiceAccount = async (req: Request, res: Response) => {
}
const secret = crypto.randomBytes(16).toString('base64');
const secretHash = await bcrypt.hash(secret, getSaltRounds());
const secretHash = await bcrypt.hash(secret, await getSaltRounds());
// create service account
const serviceAccount = await new ServiceAccount({

View File

@ -84,7 +84,7 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
} = req.body;
const secret = crypto.randomBytes(16).toString('hex');
const secretHash = await bcrypt.hash(secret, getSaltRounds());
const secretHash = await bcrypt.hash(secret, await getSaltRounds());
let expiresAt;
if (expiresIn) {

View File

@ -108,7 +108,7 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
token = tokens.token;
// sending a welcome email to new users
if (getLoopsApiKey()) {
if (await getLoopsApiKey()) {
await request.post("https://app.loops.so/api/v1/events/send", {
"email": email,
"eventName": "Sign Up",
@ -117,7 +117,7 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
}, {
headers: {
"Accept": "application/json",
"Authorization": "Bearer " + getLoopsApiKey()
"Authorization": "Bearer " + (await getLoopsApiKey())
},
});
}
@ -127,7 +127,7 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: getHttpsEnabled()
secure: await getHttpsEnabled()
});
} catch (err) {
Sentry.setUser(null);
@ -232,7 +232,7 @@ export const completeAccountInvite = async (req: Request, res: Response) => {
httpOnly: true,
path: '/',
sameSite: 'strict',
secure: getHttpsEnabled()
secure: await getHttpsEnabled()
});
} catch (err) {
Sentry.setUser(null);

View File

@ -48,7 +48,7 @@ interface V2PushSecret {
export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
// upload (encrypted) secrets to workspace with id [workspaceId]
try {
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
let { secrets }: { secrets: V2PushSecret[] } = req.body;
const { keys, environment, channel } = req.body;
const { workspaceId } = req.params;
@ -123,7 +123,7 @@ export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
export const pullSecrets = async (req: Request, res: Response) => {
let secrets;
try {
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
const environment: string = req.query.environment as string;
const channel: string = req.query.channel as string;
const { workspaceId } = req.params;

View File

@ -12,7 +12,7 @@ import { getStripeSecretKey, getStripeWebhookSecret } from '../../../config';
export const handleWebhook = async (req: Request, res: Response) => {
let event;
try {
const stripe = new Stripe(getStripeSecretKey(), {
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: '2022-08-01'
});
@ -21,7 +21,7 @@ export const handleWebhook = async (req: Request, res: Response) => {
event = stripe.webhooks.constructEvent(
req.body,
sig,
getStripeWebhookSecret()
await getStripeWebhookSecret()
);
} catch (err) {
Sentry.setUser({ email: req.user.email });

View File

@ -104,7 +104,7 @@ const getAuthUserPayload = async ({
authTokenValue: string;
}) => {
const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(authTokenValue, getJwtAuthSecret())
jwt.verify(authTokenValue, await getJwtAuthSecret())
);
const user = await User.findOne({
@ -263,16 +263,16 @@ const issueAuthTokens = async ({ userId }: { userId: string }) => {
payload: {
userId
},
expiresIn: getJwtAuthLifetime(),
secret: getJwtAuthSecret()
expiresIn: await getJwtAuthLifetime(),
secret: await getJwtAuthSecret()
});
const refreshToken = createToken({
payload: {
userId
},
expiresIn: getJwtRefreshLifetime(),
secret: getJwtRefreshSecret()
expiresIn: await getJwtRefreshLifetime(),
secret: await getJwtRefreshSecret()
});
return {

View File

@ -119,7 +119,7 @@ const createBot = async ({
const { publicKey, privateKey } = generateKeyPair();
const { ciphertext, iv, tag } = encryptSymmetric({
plaintext: privateKey,
key: getEncryptionKey()
key: await getEncryptionKey()
});
bot = await new Bot({
@ -216,7 +216,7 @@ const getKey = async ({ workspaceId }: { workspaceId: Types.ObjectId }) => {
ciphertext: bot.encryptedPrivateKey,
iv: bot.iv,
tag: bot.tag,
key: getEncryptionKey()
key: await getEncryptionKey()
});
key = decryptAsymmetric({

View File

@ -20,12 +20,12 @@ const initDatabaseHelper = async ({
// allow empty strings to pass the required validator
mongoose.Schema.Types.String.checkRequired(v => typeof v === 'string');
getLogger("database").info("Database connection established");
(await getLogger("database")).info("Database connection established");
await EESecretService.initSecretVersioning();
await SecretService.initSecretBlindIndexDataHelper();
} catch (err) {
getLogger("database").error(`Unable to establish Database connection due to the error.\n${err}`);
(await getLogger("database")).error(`Unable to establish Database connection due to the error.\n${err}`);
}
return mongoose.connection;

View File

@ -25,7 +25,7 @@ const sendMail = async ({
recipients: string[];
substitutions: any;
}) => {
if (getSmtpConfigured()) {
if (await getSmtpConfigured()) {
try {
const html = fs.readFileSync(
path.resolve(__dirname, '../templates/' + template),
@ -35,7 +35,7 @@ const sendMail = async ({
const htmlToSend = temp(substitutions);
await smtpTransporter.sendMail({
from: `"${getSmtpFromName()}" <${getSmtpFromAddress()}>`,
from: `"${await getSmtpFromName()}" <${await getSmtpFromAddress()}>`,
to: recipients.join(', '),
subject: subjectLine,
html: htmlToSend

View File

@ -123,11 +123,11 @@ const createOrganization = async ({
let organization;
try {
// register stripe account
const stripe = new Stripe(getStripeSecretKey(), {
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: '2022-08-01'
});
if (getStripeSecretKey()) {
if (await getStripeSecretKey()) {
const customer = await stripe.customers.create({
email,
description: name
@ -177,14 +177,14 @@ const initSubscriptionOrg = async ({
if (organization) {
if (organization.customerId) {
// initialize starter subscription with quantity of 0
const stripe = new Stripe(getStripeSecretKey(), {
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: '2022-08-01'
});
const productToPriceMap = {
starter: getStripeProductStarter(),
team: getStripeProductTeam(),
pro: getStripeProductPro()
starter: await getStripeProductStarter(),
team: await getStripeProductTeam(),
pro: await getStripeProductPro()
};
stripeSubscription = await stripe.subscriptions.create({
@ -239,7 +239,7 @@ const updateSubscriptionOrgQuantity = async ({
status: ACCEPTED
});
const stripe = new Stripe(getStripeSecretKey(), {
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: '2022-08-01'
});

View File

@ -233,27 +233,29 @@ const initSecretBlindIndexDataHelper = async () => {
}
});
const secretBlindIndexDataToInsert = workspaceIdsToBlindIndex.map((workspaceToBlindIndex) => {
const salt = crypto.randomBytes(16).toString('base64');
const secretBlindIndexDataToInsert = await Promise.all(
workspaceIdsToBlindIndex.map(async (workspaceToBlindIndex) => {
const salt = crypto.randomBytes(16).toString('base64');
const {
ciphertext: encryptedSaltCiphertext,
iv: saltIV,
tag: saltTag
} = encryptSymmetric({
plaintext: salt,
key: getEncryptionKey()
});
const {
ciphertext: encryptedSaltCiphertext,
iv: saltIV,
tag: saltTag
} = encryptSymmetric({
plaintext: salt,
key: await getEncryptionKey()
});
const secretBlindIndexData = new SecretBlindIndexData({
workspace: workspaceToBlindIndex,
encryptedSaltCiphertext,
saltIV,
saltTag
const secretBlindIndexData = new SecretBlindIndexData({
workspace: workspaceToBlindIndex,
encryptedSaltCiphertext,
saltIV,
saltTag
})
return secretBlindIndexData;
})
return secretBlindIndexData;
});
);
if (secretBlindIndexDataToInsert.length > 0) {
await SecretBlindIndexData.insertMany(secretBlindIndexDataToInsert);
@ -280,7 +282,7 @@ const createSecretBlindIndexDataHelper = async ({
tag: saltTag
} = encryptSymmetric({
plaintext: salt,
key: getEncryptionKey()
key: await getEncryptionKey()
});
const secretBlindIndexData = await new SecretBlindIndexData({
@ -316,7 +318,7 @@ const getSecretBlindIndexSaltHelper = async ({
ciphertext: secretBlindIndexData.encryptedSaltCiphertext,
iv: secretBlindIndexData.saltIV,
tag: secretBlindIndexData.saltTag,
key: getEncryptionKey()
key: await getEncryptionKey()
});
return salt;
@ -378,7 +380,7 @@ const generateSecretBlindIndexHelper = async ({
ciphertext: secretBlindIndexData.encryptedSaltCiphertext,
iv: secretBlindIndexData.saltIV,
tag: secretBlindIndexData.saltTag,
key: getEncryptionKey()
key: await getEncryptionKey()
});
const secretBlindIndex = await generateSecretBlindIndexWithSaltHelper({
@ -508,7 +510,7 @@ const createSecretHelper = async ({
workspaceId
});
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) {
postHogClient.capture({
@ -578,7 +580,7 @@ const getSecretsHelper = async ({
ipAddress: authData.authIP
});
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) {
postHogClient.capture({
@ -660,7 +662,7 @@ const getSecretHelper = async ({
ipAddress: authData.authIP
});
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) {
postHogClient.capture({
@ -798,7 +800,7 @@ const updateSecretHelper = async ({
workspaceId
});
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) {
postHogClient.capture({
@ -905,7 +907,7 @@ const deleteSecretHelper = async ({
workspaceId
});
const postHogClient = TelemetryService.getPostHogClient();
const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) {
postHogClient.capture({

View File

@ -84,7 +84,7 @@ const createTokenHelper = async ({
const query: TokenDataQuery = { type };
const update: TokenDataUpdate = {
type,
tokenHash: await bcrypt.hash(token, getSaltRounds()),
tokenHash: await bcrypt.hash(token, await getSaltRounds()),
expiresAt
}

View File

@ -28,7 +28,6 @@ import {
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_API_KEY
} from '../variables';
import { getEncryptionKey } from '../config';
import { encryptSymmetric } from '../utils/crypto';
import { SecretService } from '../services';

View File

@ -1,7 +1,6 @@
import mongoose from 'mongoose';
import dotenv from 'dotenv';
dotenv.config();
import infisical from 'infisical-node';
import express from 'express';
import helmet from 'helmet';
import cors from 'cors';
@ -45,7 +44,8 @@ import {
password as v1PasswordRouter,
stripe as v1StripeRouter,
integration as v1IntegrationRouter,
integrationAuth as v1IntegrationAuthRouter
integrationAuth as v1IntegrationAuthRouter,
secretsFolder as v1SecretsFolder
} from './routes/v1';
import {
signup as v2SignupRouter,
@ -79,22 +79,16 @@ import {
} from './config';
const main = async () => {
if (process.env.INFISICAL_TOKEN != "" || process.env.INFISICAL_TOKEN != undefined) {
await infisical.connect({
token: process.env.INFISICAL_TOKEN!
});
}
TelemetryService.logTelemetryMessage();
setTransporter(initSmtp());
setTransporter(await initSmtp());
await DatabaseService.initDatabase(getMongoURL());
if (getNodeEnv() !== 'test') {
await DatabaseService.initDatabase(await getMongoURL());
if ((await getNodeEnv()) !== 'test') {
Sentry.init({
dsn: getSentryDSN(),
dsn: await getSentryDSN(),
tracesSampleRate: 1.0,
debug: getNodeEnv() === 'production' ? false : true,
environment: getNodeEnv()
debug: await getNodeEnv() === 'production' ? false : true,
environment: await getNodeEnv()
});
}
@ -106,13 +100,13 @@ const main = async () => {
app.use(
cors({
credentials: true,
origin: getSiteURL()
origin: await getSiteURL()
})
);
app.use(requestIp.mw());
if (getNodeEnv() === 'production') {
if ((await getNodeEnv()) === 'production') {
// enable app-wide rate-limiting + helmet security
// in production
app.disable('x-powered-by');
@ -144,6 +138,7 @@ const main = async () => {
app.use('/api/v1/stripe', v1StripeRouter);
app.use('/api/v1/integration', v1IntegrationRouter);
app.use('/api/v1/integration-auth', v1IntegrationAuthRouter);
app.use('/api/v1/folder', v1SecretsFolder)
// v2 routes (improvements)
app.use('/api/v2/signup', v2SignupRouter);
@ -158,7 +153,7 @@ const main = async () => {
app.use('/api/v2/service-token', v2ServiceTokenDataRouter); // TODO: turn into plural route
app.use('/api/v2/service-accounts', v2ServiceAccountsRouter); // new
app.use('/api/v2/api-key', v2APIKeyDataRouter);
// v3 routes (experimental)
app.use('/api/v3/secrets', v3SecretsRouter);
app.use('/api/v3/workspaces', v3WorkspacesRouter);
@ -177,8 +172,8 @@ const main = async () => {
app.use(requestErrorHandler)
const server = app.listen(getPort(), () => {
getLogger("backend-main").info(`Server started listening at port ${getPort()}`)
const server = app.listen(await getPort(), async () => {
(await getLogger("backend-main")).info(`Server started listening at port ${await getPort()}`)
});
await createTestUserForDevelopment();

View File

@ -270,28 +270,59 @@ const getAppsNetlify = async ({ accessToken }: { accessToken: string }) => {
const getAppsGithub = async ({ accessToken }: { accessToken: string }) => {
let apps;
try {
interface GitHubApp {
id: string;
name: string;
permissions: {
admin: boolean;
};
owner: {
login: string;
}
}
const octokit = new Octokit({
auth: accessToken,
});
const repos = (
await octokit.request(
"GET /user/repos{?visibility,affiliation,type,sort,direction,per_page,page,since,before}",
{
per_page: 100,
const getAllRepos = async () => {
let repos: GitHubApp[] = [];
let page = 1;
const per_page = 100;
let hasMore = true;
while (hasMore) {
const response = await octokit.request(
"GET /user/repos{?visibility,affiliation,type,sort,direction,per_page,page,since,before}",
{
per_page,
page,
}
);
if (response.data.length > 0) {
repos = repos.concat(response.data);
page++;
} else {
hasMore = false;
}
)
).data;
}
return repos;
};
const repos = await getAllRepos();
apps = repos
.filter((a: any) => a.permissions.admin === true)
.map((a: any) => {
return ({
.filter((a: GitHubApp) => a.permissions.admin === true)
.map((a: GitHubApp) => {
return {
appId: a.id,
name: a.name,
owner: a.owner.login,
});
};
});
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);

View File

@ -159,9 +159,9 @@ const exchangeCodeAzure = async ({
grant_type: 'authorization_code',
code: code,
scope: 'https://vault.azure.net/.default openid offline_access',
client_id: getClientIdAzure(),
client_secret: getClientSecretAzure(),
redirect_uri: `${getSiteURL()}/integrations/azure-key-vault/oauth2/callback`
client_id: await getClientIdAzure(),
client_secret: await getClientSecretAzure(),
redirect_uri: `${await getSiteURL()}/integrations/azure-key-vault/oauth2/callback`
} as any)
)).data;
@ -204,7 +204,7 @@ const exchangeCodeHeroku = async ({
new URLSearchParams({
grant_type: 'authorization_code',
code: code,
client_secret: getClientSecretHeroku()
client_secret: await getClientSecretHeroku()
} as any)
)).data;
@ -242,9 +242,9 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => {
INTEGRATION_VERCEL_TOKEN_URL,
new URLSearchParams({
code: code,
client_id: getClientIdVercel(),
client_secret: getClientSecretVercel(),
redirect_uri: `${getSiteURL()}/integrations/vercel/oauth2/callback`
client_id: await getClientIdVercel(),
client_secret: await getClientSecretVercel(),
redirect_uri: `${await getSiteURL()}/integrations/vercel/oauth2/callback`
} as any)
)
).data;
@ -282,9 +282,9 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => {
new URLSearchParams({
grant_type: 'authorization_code',
code: code,
client_id: getClientIdNetlify(),
client_secret: getClientSecretNetlify(),
redirect_uri: `${getSiteURL()}/integrations/netlify/oauth2/callback`
client_id: await getClientIdNetlify(),
client_secret: await getClientSecretNetlify(),
redirect_uri: `${await getSiteURL()}/integrations/netlify/oauth2/callback`
} as any)
)
).data;
@ -333,10 +333,10 @@ const exchangeCodeGithub = async ({ code }: { code: string }) => {
res = (
await request.get(INTEGRATION_GITHUB_TOKEN_URL, {
params: {
client_id: getClientIdGitHub(),
client_secret: getClientSecretGitHub(),
client_id: await getClientIdGitHub(),
client_secret: await getClientSecretGitHub(),
code: code,
redirect_uri: `${getSiteURL()}/integrations/github/oauth2/callback`
redirect_uri: `${await getSiteURL()}/integrations/github/oauth2/callback`
},
headers: {
'Accept': 'application/json',
@ -379,9 +379,9 @@ const exchangeCodeGitlab = async ({ code }: { code: string }) => {
new URLSearchParams({
grant_type: 'authorization_code',
code: code,
client_id: getClientIdGitLab(),
client_secret: getClientSecretGitLab(),
redirect_uri: `${getSiteURL()}/integrations/gitlab/oauth2/callback`
client_id: await getClientIdGitLab(),
client_secret: await getClientSecretGitLab(),
redirect_uri: `${await getSiteURL()}/integrations/gitlab/oauth2/callback`
} as any),
{
headers: {

View File

@ -133,11 +133,11 @@ const exchangeRefreshAzure = async ({
const { data }: { data: RefreshTokenAzureResponse } = await request.post(
INTEGRATION_AZURE_TOKEN_URL,
new URLSearchParams({
client_id: getClientIdAzure(),
client_id: await getClientIdAzure(),
scope: 'openid offline_access',
refresh_token: refreshToken,
grant_type: 'refresh_token',
client_secret: getClientSecretAzure()
client_secret: await getClientSecretAzure()
} as any)
);
@ -180,7 +180,7 @@ const exchangeRefreshHeroku = async ({
new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_secret: getClientSecretHeroku()
client_secret: await getClientSecretHeroku()
} as any)
);
@ -223,9 +223,9 @@ const exchangeRefreshGitLab = async ({
new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: getClientIdGitLab,
client_secret: getClientSecretGitLab(),
redirect_uri: `${getSiteURL()}/integrations/gitlab/oauth2/callback`
client_id: await getClientIdGitLab,
client_secret: await getClientSecretGitLab(),
redirect_uri: `${await getSiteURL()}/integrations/gitlab/oauth2/callback`
} as any),
{
headers: {

View File

@ -5,9 +5,9 @@ import { getLogger } from "../utils/logger";
import RequestError, { LogLevel } from "../utils/requestError";
import { getNodeEnv } from '../config';
export const requestErrorHandler: ErrorRequestHandler = (error: RequestError | Error, req, res, next) => {
export const requestErrorHandler: ErrorRequestHandler = async (error: RequestError | Error, req, res, next) => {
if (res.headersSent) return next();
if (getNodeEnv() !== "production") {
if ((await getNodeEnv()) !== "production") {
/* eslint-disable no-console */
console.log(error)
/* eslint-enable no-console */
@ -15,8 +15,8 @@ export const requestErrorHandler: ErrorRequestHandler = (error: RequestError | E
//TODO: Find better way to type check for error. In current setting you need to cast type to get the functions and variables from RequestError
if (!(error instanceof RequestError)) {
error = InternalServerError({ context: { exception: error.message }, stack: error.stack })
getLogger('backend-main').log((<RequestError>error).levelName.toLowerCase(), (<RequestError>error).message)
error = InternalServerError({ context: { exception: error.message }, stack: error.stack });
(await getLogger('backend-main')).log((<RequestError>error).levelName.toLowerCase(), (<RequestError>error).message)
}
//* Set Sentry user identification if req.user is populated

View File

@ -26,7 +26,7 @@ const requireMfaAuth = async (
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(AUTH_TOKEN_VALUE, getJwtMfaSecret())
jwt.verify(AUTH_TOKEN_VALUE, await getJwtMfaSecret())
);
const user = await User.findOne({

View File

@ -33,7 +33,7 @@ const requireServiceTokenAuth = async (
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(AUTH_TOKEN_VALUE, getJwtServiceSecret())
jwt.verify(AUTH_TOKEN_VALUE, await getJwtServiceSecret())
);
const serviceToken = await ServiceToken.findOne({

View File

@ -27,7 +27,7 @@ const requireSignupAuth = async (
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(AUTH_TOKEN_VALUE, getJwtSignupSecret())
jwt.verify(AUTH_TOKEN_VALUE, await getJwtSignupSecret())
);
const user = await User.findOne({

View File

@ -0,0 +1,36 @@
import { Schema, Types, model } from 'mongoose';
const folderSchema = new Schema({
name: {
type: String,
required: true,
},
workspace: {
type: Schema.Types.ObjectId,
ref: 'Workspace',
required: true,
},
environment: {
type: String,
required: true,
},
parent: {
type: Schema.Types.ObjectId,
ref: 'Folder',
required: false, // optional for root folders
},
path: {
type: String,
required: true
},
parentPath: {
type: String,
required: true,
},
}, {
timestamps: true
});
const Folder = model('Folder', folderSchema);
export default Folder;

View File

@ -3,6 +3,7 @@ import {
SECRET_SHARED,
SECRET_PERSONAL,
} from '../variables';
import { ROOT_FOLDER_PATH } from '../utils/folder';
export interface ISecret {
_id: Types.ObjectId;
@ -25,6 +26,8 @@ export interface ISecret {
secretCommentTag?: string;
secretCommentHash?: string;
tags?: string[];
path?: string;
folder?: Types.ObjectId;
}
const secretSchema = new Schema<ISecret>(
@ -107,7 +110,18 @@ const secretSchema = new Schema<ISecret>(
secretCommentHash: {
type: String,
required: false
}
},
// the full path to the secret in relation to folders
path: {
type: String,
required: false,
default: ROOT_FOLDER_PATH
},
folder: {
type: Schema.Types.ObjectId,
ref: 'Folder',
required: false,
},
},
{
timestamps: true

View File

@ -5,11 +5,11 @@ const router = express.Router();
router.get(
'/status',
(req: Request, res: Response) => {
async (req: Request, res: Response) => {
res.status(200).json({
date: new Date(),
message: 'Ok',
emailConfigured: getSmtpConfigured()
emailConfigured: await getSmtpConfigured()
})
}
);

View File

@ -15,6 +15,7 @@ import password from './password';
import stripe from './stripe';
import integration from './integration';
import integrationAuth from './integrationAuth';
import secretsFolder from './secretsFolder'
export {
signup,
@ -33,5 +34,6 @@ export {
password,
stripe,
integration,
integrationAuth
integrationAuth,
secretsFolder
};

View File

@ -19,6 +19,7 @@ router.post(
router.post(
'/verify',
body('email').exists().trim().notEmpty(),
body('organizationId').exists().trim().notEmpty(),
body('code').exists().trim().notEmpty(),
validateRequest,
membershipOrgController.verifyUserToOrganization

View File

@ -0,0 +1,40 @@
import express, { Request, Response } from 'express';
const router = express.Router();
import {
requireAuth,
requireWorkspaceAuth,
validateRequest
} from '../../middleware';
import { body, param } from 'express-validator';
import { createFolder, deleteFolder } from '../../controllers/v1/secretsFolderController';
import { ADMIN, MEMBER } from '../../variables';
router.post(
'/',
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: 'body'
}),
body('workspaceId').exists(),
body('environment').exists(),
body('folderName').exists(),
body('parentFolderId'),
validateRequest,
createFolder
);
router.delete(
'/:folderId',
requireAuth({
acceptedAuthModes: ['jwt']
}),
param('folderId').exists(),
validateRequest,
deleteFolder
);
export default router;

View File

@ -1,5 +1,3 @@
import mongoose from 'mongoose';
import { getLogger } from '../utils/logger';
import {
initDatabaseHelper,
closeDatabaseHelper

View File

@ -24,9 +24,9 @@ class Telemetry {
/**
* Logs telemetry enable/disable notice.
*/
static logTelemetryMessage = () => {
if(!getTelemetryEnabled()){
getLogger("backend-main").info([
static logTelemetryMessage = async () => {
if(!(await getTelemetryEnabled())){
(await getLogger("backend-main")).info([
"",
"To improve, Infisical collects telemetry data about general usage.",
"This helps us understand how the product is doing and guide our product development to create the best possible platform; it also helps us demonstrate growth as we support Infisical as open-source software.",
@ -39,12 +39,12 @@ class Telemetry {
* Return an instance of the PostHog client initialized.
* @returns
*/
static getPostHogClient = () => {
static getPostHogClient = async () => {
let postHogClient: any;
if (getNodeEnv() === 'production' && getTelemetryEnabled()) {
if ((await getNodeEnv()) === 'production' && (await getTelemetryEnabled())) {
// case: enable opt-out telemetry in production
postHogClient = new PostHog(getPostHogProjectApiKey(), {
host: getPostHogHost()
postHogClient = new PostHog(await getPostHogProjectApiKey(), {
host: await getPostHogHost()
});
}

View File

@ -3,8 +3,8 @@ import { createTerminus } from '@godaddy/terminus';
import { getLogger } from '../utils/logger';
export const setUpHealthEndpoint = <T>(server: T) => {
const onSignal = () => {
getLogger('backend-main').info('Server is starting clean-up');
const onSignal = async () => {
(await getLogger('backend-main')).info('Server is starting clean-up');
return Promise.all([
new Promise((resolve) => {
if (mongoose.connection && mongoose.connection.readyState == 1) {

View File

@ -15,21 +15,21 @@ import {
getSmtpPort
} from '../config';
export const initSmtp = () => {
export const initSmtp = async () => {
const mailOpts: SMTPConnection.Options = {
host: getSmtpHost(),
port: getSmtpPort()
host: await getSmtpHost(),
port: await getSmtpPort()
};
if (getSmtpUsername() && getSmtpPassword()) {
if ((await getSmtpUsername()) && (await getSmtpPassword())) {
mailOpts.auth = {
user: getSmtpUsername(),
pass: getSmtpPassword()
user: await getSmtpUsername(),
pass: await getSmtpPassword()
};
}
if (getSmtpSecure() ? getSmtpSecure() : false) {
switch (getSmtpHost()) {
if ((await getSmtpSecure()) ? (await getSmtpSecure()) : false) {
switch (await getSmtpHost()) {
case SMTP_HOST_SENDGRID:
mailOpts.requireTLS = true;
break;
@ -52,7 +52,7 @@ export const initSmtp = () => {
}
break;
default:
if (getSmtpHost().includes('amazonaws.com')) {
if ((await getSmtpHost()).includes('amazonaws.com')) {
mailOpts.tls = {
ciphers: 'TLSv1.2'
}
@ -70,10 +70,10 @@ export const initSmtp = () => {
Sentry.setUser(null);
Sentry.captureMessage('SMTP - Successfully connected');
})
.catch((err) => {
.catch(async (err) => {
Sentry.setUser(null);
Sentry.captureException(
`SMTP - Failed to connect to ${getSmtpHost()}:${getSmtpPort()} \n\t${err}`
`SMTP - Failed to connect to ${await getSmtpHost()}:${await getSmtpPort()} \n\t${err}`
);
});

View File

@ -9,7 +9,7 @@
<body>
<h2>Join your organization on Infisical</h2>
<p>{{inviterFirstName}} ({{inviterEmail}}) has invited you to their Infisical organization — {{organizationName}}</p>
<a href="{{callback_url}}?token={{token}}&to={{email}}">Join now</a>
<a href="{{callback_url}}?token={{token}}&to={{email}}&organization_id={{organizationId}}">Join now</a>
<h3>What is Infisical?</h3>
<p>Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets and configs.</p>
</body>

View File

@ -19,7 +19,7 @@ export const testWorkspaceKeyId = "63cf48f0225e6955acec5eff"
export const plainTextWorkspaceKey = "543fef8224813a46230b0a50a46c5fb2"
export const createTestUserForDevelopment = async () => {
if (getNodeEnv() === "development" || getNodeEnv() === "test") {
if ((await getNodeEnv()) === "development" || (await getNodeEnv()) === "test") {
const testUser = {
_id: testUserId,
email: testUserEmail,

View File

@ -0,0 +1,87 @@
import Folder from "../models/folder";
export const ROOT_FOLDER_PATH = "/"
export const getFolderPath = async (folderId: string) => {
let currentFolder = await Folder.findById(folderId);
const pathSegments = [];
while (currentFolder) {
pathSegments.unshift(currentFolder.name);
currentFolder = currentFolder.parent ? await Folder.findById(currentFolder.parent) : null;
}
return '/' + pathSegments.join('/');
};
/**
Returns the folder ID associated with the specified secret path in the given workspace and environment.
@param workspaceId - The ID of the workspace to search in.
@param environment - The environment to search in.
@param secretPath - The secret path to search for.
@returns The folder ID associated with the specified secret path, or undefined if the path is at the root folder level.
@throws Error if the specified secret path is not found.
*/
export const getFolderIdFromPath = async (workspaceId: string, environment: string, secretPath: string) => {
const secretPathParts = secretPath.split("/").filter(path => path != "")
if (secretPathParts.length <= 1) {
return undefined // root folder, so no folder id
}
const folderId = await Folder.find({ path: secretPath, workspace: workspaceId, environment: environment })
if (!folderId) {
throw Error("Secret path not found")
}
return folderId
}
/**
* Cleans up a path by removing empty parts, duplicate slashes,
* and ensuring it starts with ROOT_FOLDER_PATH.
* @param path - The input path to clean up.
* @returns The cleaned-up path string.
*/
export const normalizePath = (path: string) => {
if (path == undefined || path == "" || path == ROOT_FOLDER_PATH) {
return ROOT_FOLDER_PATH
}
const pathParts = path.split("/").filter(part => part != "")
const cleanPathString = ROOT_FOLDER_PATH + pathParts.join("/")
return cleanPathString
}
export const getFoldersInDirectory = async (workspaceId: string, environment: string, pathString: string) => {
const normalizedPath = normalizePath(pathString)
const foldersInDirectory = await Folder.find({
workspace: workspaceId,
environment: environment,
parentPath: normalizedPath,
});
return foldersInDirectory;
}
/**
* Returns the parent path of the given path.
* @param path - The input path.
* @returns The parent path string.
*/
export const getParentPath = (path: string) => {
const normalizedPath = normalizePath(path);
const folderParts = normalizedPath.split('/').filter(part => part !== '');
let folderParent = ROOT_FOLDER_PATH;
if (folderParts.length > 1) {
folderParent = ROOT_FOLDER_PATH + folderParts.slice(0, folderParts.length - 1).join('/');
}
return folderParent;
}
export const validateFolderName = (folderName: string) => {
const validNameRegex = /^[a-zA-Z0-9-_]+$/;
return validNameRegex.test(folderName);
}

View File

@ -12,7 +12,7 @@ const logFormat = (prefix: string) => combine(
printf((info) => `${info.timestamp} ${info.label} ${info.level}: ${info.message}`)
);
const createLoggerWithLabel = (level: string, label: string) => {
const createLoggerWithLabel = async (level: string, label: string) => {
const _level = level.toLowerCase() || 'info'
//* Always add Console output to transports
const _transports: any[] = [
@ -25,10 +25,10 @@ const createLoggerWithLabel = (level: string, label: string) => {
})
]
//* Add LokiTransport if it's enabled
if(getLokiHost() !== undefined){
if((await getLokiHost()) !== undefined){
_transports.push(
new LokiTransport({
host: getLokiHost(),
host: await getLokiHost(),
handleExceptions: true,
handleRejections: true,
batching: true,
@ -40,7 +40,7 @@ const createLoggerWithLabel = (level: string, label: string) => {
labels: {
app: process.env.npm_package_name,
version: process.env.npm_package_version,
environment: getNodeEnv()
environment: await getNodeEnv()
},
onConnectionError: (err: Error)=> console.error('Connection error while connecting to Loki Server.\n', err)
})
@ -58,12 +58,10 @@ const createLoggerWithLabel = (level: string, label: string) => {
});
}
const DEFAULT_LOGGERS = {
"backend-main": createLoggerWithLabel('info', '[IFSC:backend-main]'),
"database": createLoggerWithLabel('info', '[IFSC:database]'),
}
type LoggerNames = keyof typeof DEFAULT_LOGGERS
export const getLogger = (loggerName: LoggerNames) => {
return DEFAULT_LOGGERS[loggerName]
export const getLogger = async (loggerName: 'backend-main' | 'database') => {
const logger = {
"backend-main": await createLoggerWithLabel('info', '[IFSC:backend-main]'),
"database": await createLoggerWithLabel('info', '[IFSC:database]'),
}
return logger[loggerName]
}

View File

@ -81,13 +81,13 @@ export default class RequestError extends Error{
return obj
}
public format(req: Request){
public async format(req: Request){
let _context = Object.assign({
stacktrace: this.stacktrace
}, this.context)
//* Omit sensitive information from context that can leak internal workings of this program if user is not developer
if(!getVerboseErrorOutput()){
if(!(await getVerboseErrorOutput())){
_context = this._omit(_context, [
'stacktrace',
'exception',

View File

@ -61,7 +61,7 @@ const INTEGRATION_CIRCLECI_API_URL = "https://circleci.com/api";
const INTEGRATION_TRAVISCI_API_URL = "https://api.travis-ci.com";
const INTEGRATION_SUPABASE_API_URL = 'https://api.supabase.com';
const getIntegrationOptions = () => {
const getIntegrationOptions = async () => {
const INTEGRATION_OPTIONS = [
{
name: 'Heroku',
@ -69,7 +69,7 @@ const getIntegrationOptions = () => {
image: 'Heroku.png',
isAvailable: true,
type: 'oauth',
clientId: getClientIdHeroku(),
clientId: await getClientIdHeroku(),
docsLink: ''
},
{
@ -79,7 +79,7 @@ const getIntegrationOptions = () => {
isAvailable: true,
type: 'oauth',
clientId: '',
clientSlug: getClientSlugVercel(),
clientSlug: await getClientSlugVercel(),
docsLink: ''
},
{
@ -88,7 +88,7 @@ const getIntegrationOptions = () => {
image: 'Netlify.png',
isAvailable: true,
type: 'oauth',
clientId: getClientIdNetlify(),
clientId: await getClientIdNetlify(),
docsLink: ''
},
{
@ -97,7 +97,7 @@ const getIntegrationOptions = () => {
image: 'GitHub.png',
isAvailable: true,
type: 'oauth',
clientId: getClientIdGitHub(),
clientId: await getClientIdGitHub(),
docsLink: ''
},
{
@ -151,7 +151,7 @@ const getIntegrationOptions = () => {
image: 'Microsoft Azure.png',
isAvailable: true,
type: 'oauth',
clientId: getClientIdAzure(),
clientId: await getClientIdAzure(),
docsLink: ''
},
{
@ -169,7 +169,7 @@ const getIntegrationOptions = () => {
image: 'GitLab.png',
isAvailable: true,
type: 'custom',
clientId: getClientIdGitLab(),
clientId: await getClientIdGitLab(),
docsLink: ''
},
{

View File

@ -1,408 +1,408 @@
import request from 'supertest'
import main from '../../../../src/index'
import { testWorkspaceId } from '../../../../src/utils/addDevelopmentUser';
import { deleteAllSecrets, getAllSecrets, getJWTFromTestUser, getServiceTokenFromTestUser } from '../../../helper/helper';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const batchSecretRequestWithNoOverride = require('../../../data/batch-secrets-no-override.json');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const batchSecretRequestWithOverrides = require('../../../data/batch-secrets-with-overrides.json');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const batchSecretRequestWithBadRequest = require('../../../data/batch-create-secrets-with-some-missing-params.json');
let server: any;
beforeAll(async () => {
server = await main;
});
afterAll(async () => {
server.close();
});
describe("GET /api/v2/secrets", () => {
describe("Get secrets via JTW", () => {
test("should create secrets and read secrets via jwt", async () => {
try {
// get login details
const loginResponse = await getJWTFromTestUser()
// create creates
const createSecretsResponse = await request(server)
.post("/api/v2/secrets/batch")
.set('Authorization', `Bearer ${loginResponse.token}`)
.send({
workspaceId: testWorkspaceId,
environment: "dev",
requests: batchSecretRequestWithNoOverride
})
expect(createSecretsResponse.statusCode).toBe(200)
const getSecrets = await request(server)
.get("/api/v2/secrets")
.set('Authorization', `Bearer ${loginResponse.token}`)
.query({
workspaceId: testWorkspaceId,
environment: "dev"
})
expect(getSecrets.statusCode).toBe(200)
expect(getSecrets.body).toHaveProperty("secrets")
expect(getSecrets.body.secrets).toHaveLength(3)
expect(getSecrets.body.secrets).toBeInstanceOf(Array);
getSecrets.body.secrets.forEach((secret: any) => {
expect(secret).toHaveProperty('_id');
expect(secret._id).toBeTruthy();
expect(secret).toHaveProperty('version');
expect(secret.version).toBeTruthy();
expect(secret).toHaveProperty('workspace');
expect(secret.workspace).toBeTruthy();
expect(secret).toHaveProperty('type');
expect(secret.type).toBeTruthy();
expect(secret).toHaveProperty('tags');
expect(secret.tags).toHaveLength(0);
expect(secret).toHaveProperty('environment');
expect(secret.environment).toEqual("dev");
expect(secret).toHaveProperty('secretKeyCiphertext');
expect(secret.secretKeyCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretKeyIV');
expect(secret.secretKeyIV).toBeTruthy();
// import request from 'supertest'
// import main from '../../../../src/index'
// import { testWorkspaceId } from '../../../../src/utils/addDevelopmentUser';
// import { deleteAllSecrets, getAllSecrets, getJWTFromTestUser, getServiceTokenFromTestUser } from '../../../helper/helper';
// // eslint-disable-next-line @typescript-eslint/no-var-requires
// const batchSecretRequestWithNoOverride = require('../../../data/batch-secrets-no-override.json');
// // eslint-disable-next-line @typescript-eslint/no-var-requires
// const batchSecretRequestWithOverrides = require('../../../data/batch-secrets-with-overrides.json');
// // eslint-disable-next-line @typescript-eslint/no-var-requires
// const batchSecretRequestWithBadRequest = require('../../../data/batch-create-secrets-with-some-missing-params.json');
// let server: any;
// beforeAll(async () => {
// server = await main;
// });
// afterAll(async () => {
// server.close();
// });
// describe("GET /api/v2/secrets", () => {
// describe("Get secrets via JTW", () => {
// test("should create secrets and read secrets via jwt", async () => {
// try {
// // get login details
// const loginResponse = await getJWTFromTestUser()
// // create creates
// const createSecretsResponse = await request(server)
// .post("/api/v2/secrets/batch")
// .set('Authorization', `Bearer ${loginResponse.token}`)
// .send({
// workspaceId: testWorkspaceId,
// environment: "dev",
// requests: batchSecretRequestWithNoOverride
// })
// expect(createSecretsResponse.statusCode).toBe(200)
// const getSecrets = await request(server)
// .get("/api/v2/secrets")
// .set('Authorization', `Bearer ${loginResponse.token}`)
// .query({
// workspaceId: testWorkspaceId,
// environment: "dev"
// })
// expect(getSecrets.statusCode).toBe(200)
// expect(getSecrets.body).toHaveProperty("secrets")
// expect(getSecrets.body.secrets).toHaveLength(3)
// expect(getSecrets.body.secrets).toBeInstanceOf(Array);
// getSecrets.body.secrets.forEach((secret: any) => {
// expect(secret).toHaveProperty('_id');
// expect(secret._id).toBeTruthy();
// expect(secret).toHaveProperty('version');
// expect(secret.version).toBeTruthy();
// expect(secret).toHaveProperty('workspace');
// expect(secret.workspace).toBeTruthy();
// expect(secret).toHaveProperty('type');
// expect(secret.type).toBeTruthy();
// expect(secret).toHaveProperty('tags');
// expect(secret.tags).toHaveLength(0);
// expect(secret).toHaveProperty('environment');
// expect(secret.environment).toEqual("dev");
// expect(secret).toHaveProperty('secretKeyCiphertext');
// expect(secret.secretKeyCiphertext).toBeTruthy();
// expect(secret).toHaveProperty('secretKeyIV');
// expect(secret.secretKeyIV).toBeTruthy();
expect(secret).toHaveProperty('secretKeyTag');
expect(secret.secretKeyTag).toBeTruthy();
// expect(secret).toHaveProperty('secretKeyTag');
// expect(secret.secretKeyTag).toBeTruthy();
expect(secret).toHaveProperty('secretValueCiphertext');
expect(secret.secretValueCiphertext).toBeTruthy();
// expect(secret).toHaveProperty('secretValueCiphertext');
// expect(secret.secretValueCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretValueIV');
expect(secret.secretValueIV).toBeTruthy();
// expect(secret).toHaveProperty('secretValueIV');
// expect(secret.secretValueIV).toBeTruthy();
expect(secret).toHaveProperty('secretValueTag');
expect(secret.secretValueTag).toBeTruthy();
// expect(secret).toHaveProperty('secretValueTag');
// expect(secret.secretValueTag).toBeTruthy();
expect(secret).toHaveProperty('secretCommentCiphertext');
expect(secret.secretCommentCiphertext).toBeFalsy();
// expect(secret).toHaveProperty('secretCommentCiphertext');
// expect(secret.secretCommentCiphertext).toBeFalsy();
expect(secret).toHaveProperty('secretCommentIV');
expect(secret.secretCommentIV).toBeTruthy();
expect(secret).toHaveProperty('secretCommentTag');
expect(secret.secretCommentTag).toBeTruthy();
expect(secret).toHaveProperty('createdAt');
expect(secret.createdAt).toBeTruthy();
expect(secret).toHaveProperty('updatedAt');
expect(secret.updatedAt).toBeTruthy();
});
} finally {
// clean up
await deleteAllSecrets()
}
})
test("Get secrets via jwt when personal overrides exist", async () => {
try {
// get login details
const loginResponse = await getJWTFromTestUser()
// create creates
const createSecretsResponse = await request(server)
.post("/api/v2/secrets/batch")
.set('Authorization', `Bearer ${loginResponse.token}`)
.send({
workspaceId: testWorkspaceId,
environment: "dev",
requests: batchSecretRequestWithOverrides
})
expect(createSecretsResponse.statusCode).toBe(200)
const getSecrets = await request(server)
.get("/api/v2/secrets")
.set('Authorization', `Bearer ${loginResponse.token}`)
.query({
workspaceId: testWorkspaceId,
environment: "dev"
})
// expect(secret).toHaveProperty('secretCommentIV');
// expect(secret.secretCommentIV).toBeTruthy();
// expect(secret).toHaveProperty('secretCommentTag');
// expect(secret.secretCommentTag).toBeTruthy();
// expect(secret).toHaveProperty('createdAt');
// expect(secret.createdAt).toBeTruthy();
// expect(secret).toHaveProperty('updatedAt');
// expect(secret.updatedAt).toBeTruthy();
// });
// } finally {
// // clean up
// await deleteAllSecrets()
// }
// })
// test("Get secrets via jwt when personal overrides exist", async () => {
// try {
// // get login details
// const loginResponse = await getJWTFromTestUser()
// // create creates
// const createSecretsResponse = await request(server)
// .post("/api/v2/secrets/batch")
// .set('Authorization', `Bearer ${loginResponse.token}`)
// .send({
// workspaceId: testWorkspaceId,
// environment: "dev",
// requests: batchSecretRequestWithOverrides
// })
// expect(createSecretsResponse.statusCode).toBe(200)
// const getSecrets = await request(server)
// .get("/api/v2/secrets")
// .set('Authorization', `Bearer ${loginResponse.token}`)
// .query({
// workspaceId: testWorkspaceId,
// environment: "dev"
// })
expect(getSecrets.statusCode).toBe(200)
expect(getSecrets.body).toHaveProperty("secrets")
expect(getSecrets.body.secrets).toHaveLength(2)
expect(getSecrets.body.secrets).toBeInstanceOf(Array);
getSecrets.body.secrets.forEach((secret: any) => {
expect(secret).toHaveProperty('_id');
expect(secret._id).toBeTruthy();
// expect(getSecrets.statusCode).toBe(200)
// expect(getSecrets.body).toHaveProperty("secrets")
// expect(getSecrets.body.secrets).toHaveLength(2)
// expect(getSecrets.body.secrets).toBeInstanceOf(Array);
// getSecrets.body.secrets.forEach((secret: any) => {
// expect(secret).toHaveProperty('_id');
// expect(secret._id).toBeTruthy();
expect(secret).toHaveProperty('version');
expect(secret.version).toBeTruthy();
// expect(secret).toHaveProperty('version');
// expect(secret.version).toBeTruthy();
expect(secret).toHaveProperty('workspace');
expect(secret.workspace).toBeTruthy();
// expect(secret).toHaveProperty('workspace');
// expect(secret.workspace).toBeTruthy();
expect(secret).toHaveProperty('type');
expect(secret.type).toBeTruthy();
// expect(secret).toHaveProperty('type');
// expect(secret.type).toBeTruthy();
expect(secret).toHaveProperty('tags');
expect(secret.tags).toHaveLength(0);
// expect(secret).toHaveProperty('tags');
// expect(secret.tags).toHaveLength(0);
expect(secret).toHaveProperty('environment');
expect(secret.environment).toEqual("dev");
// expect(secret).toHaveProperty('environment');
// expect(secret.environment).toEqual("dev");
expect(secret).toHaveProperty('secretKeyCiphertext');
expect(secret.secretKeyCiphertext).toBeTruthy();
// expect(secret).toHaveProperty('secretKeyCiphertext');
// expect(secret.secretKeyCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretKeyIV');
expect(secret.secretKeyIV).toBeTruthy();
// expect(secret).toHaveProperty('secretKeyIV');
// expect(secret.secretKeyIV).toBeTruthy();
expect(secret).toHaveProperty('secretKeyTag');
expect(secret.secretKeyTag).toBeTruthy();
// expect(secret).toHaveProperty('secretKeyTag');
// expect(secret.secretKeyTag).toBeTruthy();
expect(secret).toHaveProperty('secretValueCiphertext');
expect(secret.secretValueCiphertext).toBeTruthy();
// expect(secret).toHaveProperty('secretValueCiphertext');
// expect(secret.secretValueCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretValueIV');
expect(secret.secretValueIV).toBeTruthy();
// expect(secret).toHaveProperty('secretValueIV');
// expect(secret.secretValueIV).toBeTruthy();
expect(secret).toHaveProperty('secretValueTag');
expect(secret.secretValueTag).toBeTruthy();
// expect(secret).toHaveProperty('secretValueTag');
// expect(secret.secretValueTag).toBeTruthy();
expect(secret).toHaveProperty('secretCommentCiphertext');
expect(secret.secretCommentCiphertext).toBeFalsy();
// expect(secret).toHaveProperty('secretCommentCiphertext');
// expect(secret.secretCommentCiphertext).toBeFalsy();
expect(secret).toHaveProperty('secretCommentIV');
expect(secret.secretCommentIV).toBeTruthy();
// expect(secret).toHaveProperty('secretCommentIV');
// expect(secret.secretCommentIV).toBeTruthy();
expect(secret).toHaveProperty('secretCommentTag');
expect(secret.secretCommentTag).toBeTruthy();
// expect(secret).toHaveProperty('secretCommentTag');
// expect(secret.secretCommentTag).toBeTruthy();
expect(secret).toHaveProperty('createdAt');
expect(secret.createdAt).toBeTruthy();
// expect(secret).toHaveProperty('createdAt');
// expect(secret.createdAt).toBeTruthy();
expect(secret).toHaveProperty('updatedAt');
expect(secret.updatedAt).toBeTruthy();
});
} finally {
// clean up
await deleteAllSecrets()
}
})
})
describe("fetch secrets via service token", () => {
test("Get secrets via jwt when personal overrides exist", async () => {
try {
// get login details
const loginResponse = await getJWTFromTestUser()
// create creates
const createSecretsResponse = await request(server)
.post("/api/v2/secrets/batch")
.set('Authorization', `Bearer ${loginResponse.token}`)
.send({
workspaceId: testWorkspaceId,
environment: "dev",
requests: batchSecretRequestWithOverrides
})
// expect(secret).toHaveProperty('updatedAt');
// expect(secret.updatedAt).toBeTruthy();
// });
// } finally {
// // clean up
// await deleteAllSecrets()
// }
// })
// })
// describe("fetch secrets via service token", () => {
// test("Get secrets via jwt when personal overrides exist", async () => {
// try {
// // get login details
// const loginResponse = await getJWTFromTestUser()
// // create creates
// const createSecretsResponse = await request(server)
// .post("/api/v2/secrets/batch")
// .set('Authorization', `Bearer ${loginResponse.token}`)
// .send({
// workspaceId: testWorkspaceId,
// environment: "dev",
// requests: batchSecretRequestWithOverrides
// })
expect(createSecretsResponse.statusCode).toBe(200)
// now use the service token to fetch secrets
const serviceToken = await getServiceTokenFromTestUser()
// expect(createSecretsResponse.statusCode).toBe(200)
// // now use the service token to fetch secrets
// const serviceToken = await getServiceTokenFromTestUser()
const getSecrets = await request(server)
.get("/api/v2/secrets")
.set('Authorization', `Bearer ${serviceToken}`)
.query({
workspaceId: testWorkspaceId,
environment: "dev"
})
expect(getSecrets.statusCode).toBe(200)
expect(getSecrets.body).toHaveProperty("secrets")
expect(getSecrets.body.secrets).toHaveLength(2)
expect(getSecrets.body.secrets).toBeInstanceOf(Array);
// const getSecrets = await request(server)
// .get("/api/v2/secrets")
// .set('Authorization', `Bearer ${serviceToken}`)
// .query({
// workspaceId: testWorkspaceId,
// environment: "dev"
// })
// expect(getSecrets.statusCode).toBe(200)
// expect(getSecrets.body).toHaveProperty("secrets")
// expect(getSecrets.body.secrets).toHaveLength(2)
// expect(getSecrets.body.secrets).toBeInstanceOf(Array);
getSecrets.body.secrets.forEach((secret: any) => {
expect(secret).toHaveProperty('_id');
expect(secret._id).toBeTruthy();
// getSecrets.body.secrets.forEach((secret: any) => {
// expect(secret).toHaveProperty('_id');
// expect(secret._id).toBeTruthy();
expect(secret).toHaveProperty('version');
expect(secret.version).toBeTruthy();
// expect(secret).toHaveProperty('version');
// expect(secret.version).toBeTruthy();
expect(secret).toHaveProperty('workspace');
expect(secret.workspace).toBeTruthy();
// expect(secret).toHaveProperty('workspace');
// expect(secret.workspace).toBeTruthy();
expect(secret).toHaveProperty('type');
expect(secret.type).toBeTruthy();
// expect(secret).toHaveProperty('type');
// expect(secret.type).toBeTruthy();
expect(secret).toHaveProperty('tags');
expect(secret.tags).toHaveLength(0);
// expect(secret).toHaveProperty('tags');
// expect(secret.tags).toHaveLength(0);
expect(secret).toHaveProperty('environment');
expect(secret.environment).toEqual("dev");
// expect(secret).toHaveProperty('environment');
// expect(secret.environment).toEqual("dev");
expect(secret).toHaveProperty('secretKeyCiphertext');
expect(secret.secretKeyCiphertext).toBeTruthy();
// expect(secret).toHaveProperty('secretKeyCiphertext');
// expect(secret.secretKeyCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretKeyIV');
expect(secret.secretKeyIV).toBeTruthy();
// expect(secret).toHaveProperty('secretKeyIV');
// expect(secret.secretKeyIV).toBeTruthy();
expect(secret).toHaveProperty('secretKeyTag');
expect(secret.secretKeyTag).toBeTruthy();
// expect(secret).toHaveProperty('secretKeyTag');
// expect(secret.secretKeyTag).toBeTruthy();
expect(secret).toHaveProperty('secretValueCiphertext');
expect(secret.secretValueCiphertext).toBeTruthy();
// expect(secret).toHaveProperty('secretValueCiphertext');
// expect(secret.secretValueCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretValueIV');
expect(secret.secretValueIV).toBeTruthy();
// expect(secret).toHaveProperty('secretValueIV');
// expect(secret.secretValueIV).toBeTruthy();
expect(secret).toHaveProperty('secretValueTag');
expect(secret.secretValueTag).toBeTruthy();
// expect(secret).toHaveProperty('secretValueTag');
// expect(secret.secretValueTag).toBeTruthy();
expect(secret).toHaveProperty('secretCommentCiphertext');
expect(secret.secretCommentCiphertext).toBeFalsy();
// expect(secret).toHaveProperty('secretCommentCiphertext');
// expect(secret.secretCommentCiphertext).toBeFalsy();
expect(secret).toHaveProperty('secretCommentIV');
expect(secret.secretCommentIV).toBeTruthy();
// expect(secret).toHaveProperty('secretCommentIV');
// expect(secret.secretCommentIV).toBeTruthy();
expect(secret).toHaveProperty('secretCommentTag');
expect(secret.secretCommentTag).toBeTruthy();
// expect(secret).toHaveProperty('secretCommentTag');
// expect(secret.secretCommentTag).toBeTruthy();
expect(secret).toHaveProperty('createdAt');
expect(secret.createdAt).toBeTruthy();
// expect(secret).toHaveProperty('createdAt');
// expect(secret.createdAt).toBeTruthy();
expect(secret).toHaveProperty('updatedAt');
expect(secret.updatedAt).toBeTruthy();
});
} finally {
// clean up
await deleteAllSecrets()
}
})
test("should create secrets and read secrets via service token when no overrides", async () => {
try {
// get login details
const loginResponse = await getJWTFromTestUser()
// create secrets
const createSecretsResponse = await request(server)
.post("/api/v2/secrets/batch")
.set('Authorization', `Bearer ${loginResponse.token}`)
.send({
workspaceId: testWorkspaceId,
environment: "dev",
requests: batchSecretRequestWithNoOverride
})
expect(createSecretsResponse.statusCode).toBe(200)
// expect(secret).toHaveProperty('updatedAt');
// expect(secret.updatedAt).toBeTruthy();
// });
// } finally {
// // clean up
// await deleteAllSecrets()
// }
// })
// test("should create secrets and read secrets via service token when no overrides", async () => {
// try {
// // get login details
// const loginResponse = await getJWTFromTestUser()
// // create secrets
// const createSecretsResponse = await request(server)
// .post("/api/v2/secrets/batch")
// .set('Authorization', `Bearer ${loginResponse.token}`)
// .send({
// workspaceId: testWorkspaceId,
// environment: "dev",
// requests: batchSecretRequestWithNoOverride
// })
// expect(createSecretsResponse.statusCode).toBe(200)
// now use the service token to fetch secrets
const serviceToken = await getServiceTokenFromTestUser()
// // now use the service token to fetch secrets
// const serviceToken = await getServiceTokenFromTestUser()
const getSecrets = await request(server)
.get("/api/v2/secrets")
.set('Authorization', `Bearer ${serviceToken}`)
.query({
workspaceId: testWorkspaceId,
environment: "dev"
})
// const getSecrets = await request(server)
// .get("/api/v2/secrets")
// .set('Authorization', `Bearer ${serviceToken}`)
// .query({
// workspaceId: testWorkspaceId,
// environment: "dev"
// })
expect(getSecrets.statusCode).toBe(200)
expect(getSecrets.body).toHaveProperty("secrets")
expect(getSecrets.body.secrets).toHaveLength(3)
expect(getSecrets.body.secrets).toBeInstanceOf(Array);
// expect(getSecrets.statusCode).toBe(200)
// expect(getSecrets.body).toHaveProperty("secrets")
// expect(getSecrets.body.secrets).toHaveLength(3)
// expect(getSecrets.body.secrets).toBeInstanceOf(Array);
getSecrets.body.secrets.forEach((secret: any) => {
expect(secret).toHaveProperty('_id');
expect(secret._id).toBeTruthy();
// getSecrets.body.secrets.forEach((secret: any) => {
// expect(secret).toHaveProperty('_id');
// expect(secret._id).toBeTruthy();
expect(secret).toHaveProperty('version');
expect(secret.version).toBeTruthy();
// expect(secret).toHaveProperty('version');
// expect(secret.version).toBeTruthy();
expect(secret).toHaveProperty('workspace');
expect(secret.workspace).toBeTruthy();
// expect(secret).toHaveProperty('workspace');
// expect(secret.workspace).toBeTruthy();
expect(secret).toHaveProperty('type');
expect(secret.type).toBeTruthy();
// expect(secret).toHaveProperty('type');
// expect(secret.type).toBeTruthy();
expect(secret).toHaveProperty('tags');
expect(secret.tags).toHaveLength(0);
// expect(secret).toHaveProperty('tags');
// expect(secret.tags).toHaveLength(0);
expect(secret).toHaveProperty('environment');
expect(secret.environment).toEqual("dev");
// expect(secret).toHaveProperty('environment');
// expect(secret.environment).toEqual("dev");
expect(secret).toHaveProperty('secretKeyCiphertext');
expect(secret.secretKeyCiphertext).toBeTruthy();
// expect(secret).toHaveProperty('secretKeyCiphertext');
// expect(secret.secretKeyCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretKeyIV');
expect(secret.secretKeyIV).toBeTruthy();
// expect(secret).toHaveProperty('secretKeyIV');
// expect(secret.secretKeyIV).toBeTruthy();
expect(secret).toHaveProperty('secretKeyTag');
expect(secret.secretKeyTag).toBeTruthy();
// expect(secret).toHaveProperty('secretKeyTag');
// expect(secret.secretKeyTag).toBeTruthy();
expect(secret).toHaveProperty('secretValueCiphertext');
expect(secret.secretValueCiphertext).toBeTruthy();
// expect(secret).toHaveProperty('secretValueCiphertext');
// expect(secret.secretValueCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretValueIV');
expect(secret.secretValueIV).toBeTruthy();
expect(secret).toHaveProperty('secretValueTag');
expect(secret.secretValueTag).toBeTruthy();
expect(secret).toHaveProperty('secretCommentCiphertext');
expect(secret.secretCommentCiphertext).toBeFalsy();
expect(secret).toHaveProperty('secretCommentIV');
expect(secret.secretCommentIV).toBeTruthy();
expect(secret).toHaveProperty('secretCommentTag');
expect(secret.secretCommentTag).toBeTruthy();
expect(secret).toHaveProperty('createdAt');
expect(secret.createdAt).toBeTruthy();
expect(secret).toHaveProperty('updatedAt');
expect(secret.updatedAt).toBeTruthy();
});
} finally {
// clean up
await deleteAllSecrets()
}
})
})
describe("create secrets via JWT", () => {
test("Create secrets via jwt when some requests have missing required parameters", async () => {
// get login details
const loginResponse = await getJWTFromTestUser()
// create creates
const createSecretsResponse = await request(server)
.post("/api/v2/secrets/batch")
.set('Authorization', `Bearer ${loginResponse.token}`)
.send({
workspaceId: testWorkspaceId,
environment: "dev",
requests: batchSecretRequestWithBadRequest
})
const allSecretsInDB = await getAllSecrets()
// expect(secret).toHaveProperty('secretValueIV');
// expect(secret.secretValueIV).toBeTruthy();
// expect(secret).toHaveProperty('secretValueTag');
// expect(secret.secretValueTag).toBeTruthy();
// expect(secret).toHaveProperty('secretCommentCiphertext');
// expect(secret.secretCommentCiphertext).toBeFalsy();
// expect(secret).toHaveProperty('secretCommentIV');
// expect(secret.secretCommentIV).toBeTruthy();
// expect(secret).toHaveProperty('secretCommentTag');
// expect(secret.secretCommentTag).toBeTruthy();
// expect(secret).toHaveProperty('createdAt');
// expect(secret.createdAt).toBeTruthy();
// expect(secret).toHaveProperty('updatedAt');
// expect(secret.updatedAt).toBeTruthy();
// });
// } finally {
// // clean up
// await deleteAllSecrets()
// }
// })
// })
// describe("create secrets via JWT", () => {
// test("Create secrets via jwt when some requests have missing required parameters", async () => {
// // get login details
// const loginResponse = await getJWTFromTestUser()
// // create creates
// const createSecretsResponse = await request(server)
// .post("/api/v2/secrets/batch")
// .set('Authorization', `Bearer ${loginResponse.token}`)
// .send({
// workspaceId: testWorkspaceId,
// environment: "dev",
// requests: batchSecretRequestWithBadRequest
// })
// const allSecretsInDB = await getAllSecrets()
expect(createSecretsResponse.statusCode).toBe(500) // TODO should be set to 400
expect(allSecretsInDB).toHaveLength(0)
})
})
})
// expect(createSecretsResponse.statusCode).toBe(500) // TODO should be set to 400
// expect(allSecretsInDB).toHaveLength(0)
// })
// })
// })

View File

@ -4,12 +4,14 @@ import (
"encoding/json"
"errors"
"fmt"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"os"
"os/exec"
"runtime"
"strings"
log "github.com/sirupsen/logrus"
"github.com/fatih/color"
)
@ -73,7 +75,23 @@ func getLatestTag(repoOwner string, repoName string) (string, error) {
return "", fmt.Errorf("failed to unmarshal github response: %w", err)
}
return tags[0].Name[1:], nil
// Filter tags with prefix "infisical-cli/"
prefix := "infisical-cli/v"
var validTags []string
for _, tag := range tags {
if strings.HasPrefix(tag.Name, prefix) {
validTags = append(validTags, tag.Name)
}
}
if len(validTags) == 0 {
return "", errors.New("no tags for the CLI is found")
}
// Extract the version from the first valid tag
version := strings.TrimPrefix(validTags[0], prefix)
return version, nil
}
func GetUpdateInstructions() string {

View File

@ -5,11 +5,11 @@ description: "How to authenticate with the Infisical Public API"
## Essentials
The Public API accepts multiple modes of authentication being via API Key, Service Account credentials, or [Infisical Token](../../getting-started/dashboard/token).
The Public API accepts multiple modes of authentication being via API Key, Service Account credentials, or [Infisical Token](/documentation/platform/token).
- API Key: Provides full access to all endpoints representing the user.
- [Service Account](): Provides scoped access to an organization and select projects representing a machine such as a VM or application client.
- [Infisical Token](../../getting-started/dashboard/token): Provides short-lived, scoped CRUD access to the secrets of a specific project and environment.
- Service Account: Provides scoped access to an organization and select projects representing a machine such as a VM or application client.
- [Infisical Token](/documentation/platform/token): Provides short-lived, scoped CRUD access to the secrets of a specific project and environment.
<AccordionGroup>
<Accordion title="API Key">

View File

@ -6,7 +6,7 @@ description: "How to add a secret using an Infisical Token scoped to a project a
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com).
- Create an [Infisical Token](../../../getting-started/dashboard/token) for your project and environment with write access enabled.
- Create an [Infisical Token](/documentation/platform/token) for your project and environment with write access enabled.
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
- [Ensure that your project is blind-indexed](../blind-indices).

View File

@ -6,7 +6,7 @@ description: "How to delete a secret using an Infisical Token scoped to a projec
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com).
- Create either an [API Key](/api-reference/overview/authentication) or [Infisical Token](../../../getting-started/dashboard/token) for your project and environment with write access enabled.
- Create either an [API Key](/api-reference/overview/authentication) or [Infisical Token](/documentation/platform/token) for your project and environment with write access enabled.
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
- [Ensure that your project is blind-indexed](../blind-indices).

View File

@ -6,7 +6,7 @@ description: "How to get a secret using an Infisical Token scoped to a project a
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com).
- Create an [Infisical Token](../../../getting-started/dashboard/token) for your project and environment.
- Create an [Infisical Token](/documentation/platform/token) for your project and environment.
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
- [Ensure that your project is blind-indexed](../blind-indices).

View File

@ -6,7 +6,7 @@ description: "How to get all secrets using an Infisical Token scoped to a projec
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com).
- Create an [Infisical Token](../../../getting-started/dashboard/token) for your project and environment.
- Create an [Infisical Token](/documentation/platform/token) for your project and environment.
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
- [Ensure that your project is blind-indexed](../blind-indices).

View File

@ -6,7 +6,7 @@ description: "How to update a secret using an Infisical Token scoped to a projec
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com).
- Create an [Infisical Token](../../../getting-started/dashboard/token) for your project and environment with write access enabled.
- Create an [Infisical Token](/documentation/platform/token) for your project and environment with write access enabled.
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
- [Ensure that your project is blind-indexed](../blind-indices).

View File

@ -37,7 +37,7 @@ Export environment variables from the platform into a file format.
### Environment variables
<Accordion title="INFISICAL_TOKEN">
Used to fetch secrets via a [service token](/getting-started/dashboard/token) apposed to logged in credentials. Simply, export this variable in the terminal before running this command.
Used to fetch secrets via a [service token](/documentation/platform/token) apposed to logged in credentials. Simply, export this variable in the terminal before running this command.
```bash
# Example

View File

@ -42,7 +42,7 @@ Inject secrets from Infisical into your application process.
### Environment variables
<Accordion title="INFISICAL_TOKEN">
Used to fetch secrets via a [service token](/getting-started/dashboard/token) apposed to logged in credentials. Simply, export this variable in the terminal before running this command.
Used to fetch secrets via a [service token](/documentation/platform/token) apposed to logged in credentials. Simply, export this variable in the terminal before running this command.
```bash
# Example
@ -72,7 +72,7 @@ Inject secrets from Infisical into your application process.
</Accordion>
<Accordion title="--token">
If you are using a [service token](../../getting-started/dashboard/token) to authenticate, you can pass the token as a flag
If you are using a [service token](/documentation/platform/token) to authenticate, you can pass the token as a flag
```bash
# Example

View File

@ -20,7 +20,7 @@ This command enables you to perform CRUD (create, read, update, delete) operatio
### Environment variables
<Accordion title="INFISICAL_TOKEN">
Used to fetch secrets via a [service token](/getting-started/dashboard/token) apposed to logged in credentials. Simply, export this variable in the terminal before running this command.
Used to fetch secrets via a [service token](/documentation/platform/token) apposed to logged in credentials. Simply, export this variable in the terminal before running this command.
```bash
# Example

View File

@ -3,7 +3,7 @@ title: "Infisical Token"
description: "How to use Infical service token within the CLI."
---
Prerequisite: [Infisical Token and How to Generate One](../../getting-started/dashboard/token).
Prerequisite: [Infisical Token and How to Generate One](/documentation/platform/token).
It's possible to use the CLI to sync environment varialbes without manually entering login credentials by using a service token in the prerequisite link above.

View File

@ -18,7 +18,7 @@ Prerequisite: [Install the CLI](/cli/overview)
<Tab title="Infisical Token">
To use Infisical CLI in environments where you cannot run the `infisical login` command, you can authenticate via a
Infisical Token instead. Learn more about [Infisical Token](../getting-started/dashboard/token).
Infisical Token instead. Learn more about [Infisical Token](/documentation/platform/token).
</Tab>
</Tabs>

View File

@ -0,0 +1,128 @@
---
title: "CLI"
---
The Infisical CLI can be used to inject secrets into any framework like Next.js, Express, Django and more in local development.
It can also be used to expose secrets from Infisical as environment variables in CI/CD pipelines and [Docker containers](/documentation/getting-started/docker)
Prerequisites:
- Have a project with secrets ready in [Infisical Cloud](https://app.infisical.com).
## Installation
Follow the instructions for your operating system to install the Infisical CLI.
<Tabs>
<Tab title="MacOS">
Use [brew](https://brew.sh/) package manager
```console
$ brew install infisical/get-cli/infisical
```
</Tab>
<Tab title="Windows">
Use [Scoop](https://scoop.sh/) package manager
```console
$ scoop bucket add org https://github.com/Infisical/scoop-infisical.git
```
```console
$ scoop install infisical
```
</Tab>
<Tab title="Alpine">
Install prerequisite
```console
$ apk add --no-cache bash sudo
```
Add Infisical repository
```console
$ curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.alpine.sh' \
| bash
```
Then install CLI
```console
$ apk update && sudo apk add infisical
```
</Tab>
<Tab title="RedHat/CentOs/Amazon">
Add Infisical repository
```console
$ curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.rpm.sh' \
| sudo -E bash
```
Then install CLI
```console
$ sudo yum install infisical
```
</Tab>
<Tab title="Debian/Ubuntu">
Add Infisical repository
```console
$ curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' \
| sudo -E bash
```
Then install CLI
```console
$ sudo apt-get update && sudo apt-get install -y infisical
```
</Tab>
<Tab title="Arch Linux">
Use the `yay` package manager to install from the [Arch User Repository](https://aur.archlinux.org/packages/infisical-bin)
```console
$ yay -S infisical-bin
```
</Tab>
</Tabs>
## Login
Authenticate the CLI with the Infisical platform using your email and password.
```console
$ infisical login
```
## Initialization
Navigate to the root of your project directory and run the `init` command. This step connects your local project to the project on the Infisical platform and creates a `infisical.json` file containing a reference to that latter project.
```console
$ infisical init
```
## Start your app with environment variables injected
```console
$ infisical run -- <your_application_start_command>
```
## Example Start Commands
```console
$ infisical run -- npm run dev
$ infisical run -- flask run
$ infisical run -- ./your_bash_script.sh
```
Your app should now be running with the secrets from Infisical injected as environment variables.
See also:
- [Documentation for the Infisical CLI](/cli/overview)

View File

@ -0,0 +1,185 @@
---
title: "Docker"
---
The [Infisical CLI](/cli/overview) can be added to Dockerfiles to fetch secrets from Infisical and make them available as environment variables within containers at runtime.
Prerequisites:
- Have a project with secrets ready in [Infisical Cloud](https://app.infisical.com).
- Create an [Infisical Token](/documentation/platform/token) scoped to an environment in your project in Infisical.
<Tabs>
<Tab title="Docker">
## Dockerfile Modification
Follow the instruction for your specific Linux distrubtion to add the Infisical CLI to your Dockerfile.
<Tabs>
<Tab title="Alpine">
```dockerfile
RUN apk add --no-cache bash curl && curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.alpine.sh' | bash \
&& apk add infisical
```
</Tab>
<Tab title="RedHat/CentOs/Amazon-linux">
```dockerfile
RUN curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.rpm.sh' | sh \
&& yum install -y infisical
```
</Tab>
<Tab title="Debian/Ubuntu">
```dockerfile
RUN apt-get update && apt-get install -y bash curl && curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' | bash \
&& apt-get update && apt-get install -y infisical
```
</Tab>
</Tabs>
Next, modify the start command of your Dockerfile:
```dockerfile
CMD ["infisical", "run", "--", "[your service start command]"]
```
## Launch
Spin up your container with the `docker run` command and feed in your Infisical Token.
```console
docker run --env INFISICAL_TOKEN=<your_infisical_token> <DOCKER-IMAGE>
```
Your containerized application should now be up and running with secrets from Infisical exposed as environment variables within your application's process.
## Example Dockerfile
```dockerfile
# Select your base image (based on your Linux distribution, e.g., Alpine, Debian, Ubuntu, etc.)
FROM alpine
# Add the Infisical CLI to your Dockerfile (choose the appropriate block based on your base image)
RUN apk add --no-cache bash curl && curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.alpine.sh' | bash \
&& apk add infisical
# Install any additional dependencies or packages your service requires
# RUN <additional commands for your service>
# Copy your service files to the container
COPY . /app
# Set the working directory
WORKDIR /app
# Modify the start command of your Dockerfile
CMD ["infisical", "run", "--", "npm run start"]
```
</Tab>
<Tab title="Docker Compose">
## Dockerfile Modifications
Follow the instruction for your specific Linux distributions to add the Infisical CLI to your Dockerfiles.
<Tabs>
<Tab title="Alpine">
```dockerfile
RUN apk add --no-cache bash curl && curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.alpine.sh' | bash \
&& apk add infisical
```
</Tab>
<Tab title="RedHat/CentOs/Amazon-linux">
```dockerfile
RUN curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.rpm.sh' | sh \
&& yum install -y infisical
```
</Tab>
<Tab title="Debian/Ubuntu">
```dockerfile
RUN apt-get update && apt-get install -y bash curl && curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' | bash \
&& apt-get update && apt-get install -y infisical
```
</Tab>
</Tabs>
Next, modify the start commands of your Dockerfiles:
```dockerfile
CMD ["infisical", "run", "--", "[your service start command]"]
```
## Example Dockerfile
```dockerfile
# Select your base image (based on your Linux distribution, e.g., Alpine, Debian, Ubuntu, etc.)
FROM alpine
# Add the Infisical CLI to your Dockerfile (choose the appropriate block based on your base image)
RUN apk add --no-cache bash curl && curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.alpine.sh' | bash \
&& apk add infisical
# Install any additional dependencies or packages your service requires
# RUN <additional commands for your service>
# Copy your service files to the container
COPY . /app
# Set the working directory
WORKDIR /app
# Modify the start command of your Dockerfile
CMD ["infisical", "run", "--", "[your service start command]"]
```
## Docker Compose File Modification
For each service you want to inject secrets into, set an environment variable called `INFISICAL_TOKEN` equal to a unique identifier variable. For example:
```yaml
services:
api:
build: .
image: example-service-2
environment:
- INFISICAL_TOKEN=${INFISICAL_TOKEN_FOR_API}
...
```
## Export shell variables
Next, set the shell variables you defined in your compose file. Continuing from the previous example:
```console
export INFISICAL_TOKEN_FOR_API=<your_infisical_token>
```
## Launch
Spin up your containers with the `docker-compose up` command.
```console
docker-compose up
```
Your containers should now be running with the secrets from Infisical available inside as environment variables.
</Tab>
</Tabs>
See also:
- [Documentation for Docker](/integrations/platforms/docker)
- [Documentation for Docker Compose](/integrations/platforms/docker-compose)

View File

@ -0,0 +1,90 @@
---
title: "Introduction"
---
Infisical is an [open-source](https://opensource.com/resources/what-open-source), [end-to-end encrypted](https://en.wikipedia.org/wiki/End-to-end_encryption) secret management platform that enables teams to easily manage and sync their environment variables.
Start syncing environment variables with [Infisical Cloud](https://app.infisical.com) or learn how to [host Infisical](/self-hosting/overview) yourself.
## Learn about Infisical
<Card
href="/documentation/getting-started/platform"
title="Platform"
icon="laptop"
color="#dc2626"
>
Store secrets like API keys, database credentials, environment variables with Infisical
</Card>
## Integrate with Infisical
<CardGroup cols={2}>
<Card
title="SDKs"
href="/documentation/getting-started/sdks"
icon="boxes-stacked"
color="#3c8639"
>
Fetch secrets with any programming language on demand
</Card>
<Card href="/documentation/getting-started/sdks" title="Command Line Interface" icon="square-terminal" color="#3775a9">
Inject secrets into any application process/environment
</Card>
<Card href="/documentation/getting-started/docker" title="Docker" icon="docker" color="#0078d3">
Inject secrets into Docker containers
</Card>
<Card
href="/documentation/getting-started/kubernetes"
title="Kubernetes"
icon="server"
color="#3775a9"
>
Fetch and save secrets as native Kubernetes secrets
</Card>
</CardGroup>
## Resources
<CardGroup cols={2}>
<Card
href="/self-hosting/overview"
title="Self-hosting"
icon="server"
color="#0285c7"
>
Learn how to configure and deploy Infisical
</Card>
<Card
href="/documentation/guides/introduction"
title="Guide"
icon="book-open"
color="#dc2626"
>
Explore guides for every language and stack
</Card>
<Card
href="/integrations/overview"
title="Native Integrations"
icon="clouds"
color="#dc2626"
>
Explore integrations for GitHub, Vercel, Netlify, and more
</Card>
<Card
href="/integrations/overview"
title="Frameworks"
icon="plug"
color="#dc2626"
>
Explore integrations for Next.js, Express, Django, and more
</Card>
<Card
href="https://calendly.com/team-infisical/infisical-demo"
title="Contact Us"
icon="user-headset"
color="#0285c7"
>
Questions? Need help setting up? Book a 1x1 meeting with us
</Card>
</CardGroup>

View File

@ -0,0 +1,83 @@
---
title: "Kubernetes"
---
The Infisical Secrets Operator fetches secrets from Infisical and saves them as Kubernetes secrets using the custom `InfisicalSecret` resource to define authentication and storage methods.
The operator updates secrets continuously and can reload dependent deployments automatically on secret changes.
Prerequisites:
- Connected to your cluster via kubectl
- Have a project with secrets ready in [Infisical Cloud](https://app.infisical.com).
- Create an [Infisical Token](/documentation/platform/token) scoped to an environment in your project in Infisical.
## Installation
Follow the instructions for either [Helm](https://helm.sh/) or [kubectl](https://github.com/kubernetes/kubectl) to install the Infisical Secrets Operator.
<Tabs>
<Tab title="Helm">
Install the Infisical Helm repository
```console
helm repo add infisical-helm-charts 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/'
helm repo update
```
Install the Helm chart
```console
helm install --generate-name infisical-helm-charts/secrets-operator
```
</Tab>
<Tab title="Kubectl">
The operator will be installed in `infisical-operator-system` namespace
```
kubectl apply -f https://raw.githubusercontent.com/Infisical/infisical/main/k8-operator/kubectl-install/install-secrets-operator.yaml
```
</Tab>
</Tabs>
## Usage
**Step 1: Create Kubernetes secret containing service token**
Once you have generated the service token, create a Kubernetes secret containing the service token you generated by running the command below.
``` bash
kubectl create secret generic service-token --from-literal=infisicalToken=<your-service-token-here>
```
**Step 2: Fill out the InfisicalSecrets CRD and apply it to your cluster**
```yaml infisical-secrets-config.yaml
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
# Name of of this InfisicalSecret resource
name: infisicalsecret-sample
spec:
# The host that should be used to pull secrets from. If left empty, the value specified in Global configuration will be used
hostAPI: https://app.infisical.com/api
authentication:
serviceToken:
serviceTokenSecretReference: # <-- The secret's namespaced name that holds the project token for authentication in step 1
secretName: service-token
secretNamespace: option
managedSecretReference:
secretName: managed-secret # <-- the name of kubernetes secret that will be created
secretNamespace: default # <-- in what namespace it will be created in
```
```
kubectl apply -f infisical-secrets-config.yaml
```
You should now see a new kubernetes secret automatically created in the namespace you defined in the `managedSecretReference` property above.
See also:
- [Documentation for the Infisical Kubernetes Operator](../../integrations/platforms/kubernetes)

View File

@ -0,0 +1,57 @@
---
title: "Platform"
---
Infisical is an [open-source](https://opensource.com/resources/what-open-source), [end-to-end encrypted](https://en.wikipedia.org/wiki/End-to-end_encryption) secret management platform that enables teams to easily store, manage, and sync secrets like API keys, database credentials, and environment variables across their apps and infrastructure.
This quickstart provides an overview of the functionalities offered by Infisical.
## Projects
Projects hold secrets for applications, which are further organized into environments such as development, testing and production.
### Secrets Overview
The secrets overview provides a bird's-eye view of all the secrets in a project and is particularly useful for identifying missing secrets across environments.
![dashboard secrets overview](../../images/dashboard-secrets-overview.png)
### Secrets Dashboard
The secrets dashboard lets you manage secrets for a specific environment in a project.
Here, developers can [override secrets](//project#personal-overrides), [version secrets](/documentation/platform/secret-versioning), [rollback projects to any point in time](/documentation/platform/pit-recovery), and much more.
![dashboard](../../images/dashboard.png)
### Integrations
The integrations page provides native integrations to sync secrets from a project environment to a [host of ever-expanding integrations](/integrations/overview).
<Tip>
Depending on your infrastructure setup and compliance requirements, you may or may not prefer to use these native integrations since they break end-to-end encryption (E2EE).
You will learn about various ways to integrate with Infisical and maintain E2EE in subsequent quickstart sections.
</Tip>
![integrations](../../images/integrations.png)
### Access Control
The members page lets you add/remove members for a project and provision them access to environments (access levels include `No Access`, `Read Only`, and `Read and Write`).
![project members](../../images/project-members.png)
## Organizations
Organizations house projects and members.
### Organization Settings
At the organization-level, you can add/remove members and manage their access to projects.
![organization name modal open](../../images/dashboard-name-modal-organization.png)
![organization name modal open](../../images/organization.png)
That's it for the platform quickstart! — We encourage you to continue exploring the documentation to gain a deeper understanding of the extensive features and functionalities that Infisical has to offer.
Next, head back to [Getting Started > Introduction](/documentation/getting-started/overview) to explore ways to fetch secrets from Infisical to your apps and infrastructure.

View File

@ -0,0 +1,145 @@
---
title: "SDKs"
---
From local development to production, Infisical's language-specific SDKs provide the easiest way for your app to fetch back secrets on demand.
Prerequisites:
- Have a project with secrets ready in [Infisical Cloud](https://app.infisical.com).
- Create an [Infisical Token](/documentation/platform/token) scoped to an environment in your project in Infisical.
## Installation
Follow the instructions for your language to install the SDK for it.
<Tabs>
<Tab title="Node">
Run `npm` to add [infisical-node](https://github.com/Infisical/infisical-node) to your project.
```console
$ npm install infisical-node --save
```
## Configuration
Import the SDK and create a client instance with your [Infisical Token](/documentation/platform/token).
<Tabs>
<Tab title="ES6">
```js
import InfisicalClient from "infisical-node";
const client = new InfisicalClient({
token: "your_infisical_token"
});
```
</Tab>
<Tab title="ES5">
```js
const InfisicalClient = require("infisical-node");
const client = new InfisicalClient({
token: "your_infisical_token"
});
````
</Tab>
</Tabs>
## Get a Secret
```js
const secret = await client.getSecret("API_KEY");
const value = secret.secretValue; // get its value
```
## Basic Usage
```js
import express from "express";
import InfisicalClient from "infisical-node";
const app = express();
const PORT = 3000;
const client = new InfisicalClient({
token: "YOUR_INFISICAL_TOKEN"
});
app.get("/", async (req, res) => {
// access value
const name = await client.getSecret("NAME");
res.send(`Hello! My name is: ${name.secretValue}`);
});
app.listen(PORT, async () => {
console.log(`App listening on port ${port}`);
});
```
This example demonstrates how to use the Infisical Node SDK with an Express application. The application retrieves a secret named "NAME" and responds to requests with a greeting that includes the secret value.
</Tab>
<Tab title="Python">
## Installation
Run `pip` to add [infisical-python](https://github.com/Astropilot/infisical-python) to your project
```console
$ pip install infisical
```
Note: You need Python 3.7+.
## Configuration
Import the SDK and create a client instance with your [Infisical Token](/documentation/platform/token).
```py
from infisical import InfisicalClient
client = InfisicalClient(token="your_infisical_token")
```
## Get a Secret
```py
secret = client.get_secret("API_KEY")
value = secret.secret_value # get its value
```
## Basic Usage
```py
from flask import Flask
from infisical import InfisicalClient
app = Flask(__name__)
client = InfisicalClient(token="your_infisical_token")
@app.route("/")
def hello_world():
# access value
name = client.get_secret("NAME")
return f"Hello! My name is: {name.secret_value}"
```
This example demonstrates how to use the Infisical Python SDK with a Flask application. The application retrieves a secret named "NAME" and responds to requests with a greeting that includes the secret value.
</Tab>
<Tab title="Other">
We're currently working on SDKs for other languages. Follow the GitHub issue for your needed language below:
- [Java](https://github.com/Infisical/infisical/issues/434)
- [Ruby](https://github.com/Infisical/infisical/issues/435)
- [Go](https://github.com/Infisical/infisical/issues/436)
- [Rust](https://github.com/Infisical/infisical/issues/437)
- [PHP](https://github.com/Infisical/infisical/issues/531)
Missing a language? [Throw in a request](https://github.com/Infisical/infisical/issues).
</Tab>
</Tabs>
See also:
- Explore the [Node SDK](https://github.com/Infisical/infisical-node)
- Explore the [Python SDK](https://github.com/Infisical/infisical-python)

View File

@ -0,0 +1,41 @@
---
title: "Introduction"
---
Whether you're running a Node application on Heroku, Next.js application with Vercel, or Kubernetes on AWS, Infisical has a secret management strategy from local development to production ready for you.
## Guides by Language
<CardGroup cols={2}>
<Card
title="Node"
href="/documentation/guides/node"
icon="node"
color="#3c8639"
>
Manage secrets across your Node stack
</Card>
<Card
href="/documentation/guides/python"
title="Python"
icon="python"
color="#3775a9"
>
Manage secrets across your Python stack
</Card>
</CardGroup>
## Guides by Stack
<CardGroup cols={2}>
<Card
title="Next.js + Vercel"
href="/documentation/guides/nextjs-vercel"
icon="cloud"
color="#3c8639"
>
Manage secrets for your Next.js + Vercel stack
</Card>
</CardGroup>
Want a guide? [Throw in a request](https://github.com/Infisical/infisical/issues).

View File

@ -0,0 +1,254 @@
---
title: "Next.js + Vercel"
---
This guide demonstrates how to use Infisical to manage secrets for your Next.js + Vercel stack from local development to production. It uses:
- Infisical (you can use [Infisical Cloud](https://app.infisical.com) or a [self-hosted instance of Infisical](https://infisical.com/docs/self-hosting/overview)) to store your secrets.
## Project Setup
To begin, we need to set up a project in Infisical and add secrets to an environment in it.
### Create a project
1. Create a new project in [Infisical](https://app.infisical.com/).
2. Add a secret to the development environment of this project so we can pull it back for local development. In the **Secrets Overview** page, press **Explore Development** and add a secret with the key `NEXT_PUBLIC_NAME` and value `YOUR_NAME`.
3. Add a secret to the production environment of this project so we can sync it to Vercel. Switch to the **Production** environment and add a secret with the key `NEXT_PUBLIC_NAME` and value `ANOTHER_NAME`.
## Create a Next.js app
Initialize a new Node.js app.
We can use `create-next-app` to initialize an app called `infisical-nextjs`.
<Tabs>
<Tab title="JavaScript">
```console
npx create-next-app@latest --use-npm infisical-nextjs
cd infisical-nextjs
```
</Tab>
<Tab title="TypeScript">
```console
npx create-next-app@latest --ts --use-npm infisical-nextjs
cd infisical-nextjs
```
</Tab>
</Tabs>
Next, inside `pages/_app.js`, lets add a `console.log()` to print out the environment variable in the browser console.
<Tabs>
<Tab title="JavaScript">
```js
import '@/styles/globals.css'
export default function App({ Component, pageProps }) {
console.log('Hello, ', process.env.NEXT_PUBLIC_NAME);
return <Component {...pageProps} />
}
```
</Tab>
<Tab title="TypeScript">
```tsx
import '@/styles/globals.css'
import type { AppProps } from 'next/app'
export default function App({ Component, pageProps }: AppProps) {
console.log('Hello, ', process.env.NEXT_PUBLIC_NAME);
return <Component {...pageProps} />
}
```
</Tab>
</Tabs>
## Infisical CLI for local development environment variables
We'll now use the Infisical CLI to fetch secrets from Infisical into your Next.js app for local development.
### CLI Installation
Follow the instructions for your operating system to install the Infisical CLI.
<Tabs>
<Tab title="MacOS">
Use [brew](https://brew.sh/) package manager
```console
$ brew install infisical/get-cli/infisical
```
</Tab>
<Tab title="Windows">
Use [Scoop](https://scoop.sh/) package manager
```console
$ scoop bucket add org https://github.com/Infisical/scoop-infisical.git
```
```console
$ scoop install infisical
```
</Tab>
<Tab title="Alpine">
Install prerequisite
```console
$ apk add --no-cache bash sudo
```
Add Infisical repository
```console
$ curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.alpine.sh' \
| bash
```
Then install CLI
```console
$ apk update && sudo apk add infisical
```
</Tab>
<Tab title="RedHat/CentOs/Amazon">
Add Infisical repository
```console
$ curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.rpm.sh' \
| sudo -E bash
```
Then install CLI
```console
$ sudo yum install infisical
```
</Tab>
<Tab title="Debian/Ubuntu">
Add Infisical repository
```console
$ curl -1sLf \
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' \
| sudo -E bash
```
Then install CLI
```console
$ sudo apt-get update && sudo apt-get install -y infisical
```
</Tab>
<Tab title="Arch Linux">
Use the `yay` package manager to install from the [Arch User Repository](https://aur.archlinux.org/packages/infisical-bin)
```console
$ yay -S infisical-bin
```
</Tab>
</Tabs>
### Login
Authenticate the CLI with the Infisical platform using your email and password.
```console
$ infisical login
```
### Initialization
Run the `init` command at the root of the Next.js app. This step connects your local project to the project on the Infisical platform and creates a `infisical.json` file containing a reference to that latter project.
```console
$ infisical init
```
### Start the Next.js app with secrets injected as environment variables
```console
$ infisical run -- npm run dev
```
If you open your browser console, **Hello, YOUR_NAME** should be printed out.
Here, the CLI fetched the secret from Infisical and injected it into the Next.js app upon starting up. By default,
the CLI fetches secrets from the development environment which has the slug `dev`; you can inject secrets from different
environments by modifying the `env` flag as per the [CLI documentation](/cli/usage).
At this stage, you know how to use the Infisical CLI to inject secrets into your Next.js app for local development.
## Infisical-Vercel integration for production environment variables
We'll now use the Infisical-Vercel integration send secrets from Infisical to Vercel as production environment variables.
### Infisical-Vercel integration
To begin we have to import the Next.js app into Vercel as a project. [Follow these instructions](https://nextjs.org/learn/basics/deploying-nextjs-app/deploy) to deploy the Next.js app to Vercel.
Next, navigate to your project's integrations tab in Infisical and press on the Vercel tile to grant Infisical access to your Vercel account.
![integrations](../../images/integrations.png)
![integrations vercel authorization](../../images/integrations-vercel-auth.png)
<Note>
Opting in for the Infisical-Vercel integration will break end-to-end encryption since Infisical will be able to read
your secrets. This is, however, necessary for Infisical to sync the secrets to Vercel.
Your secrets remain encrypted at rest following our [security guide mechanics](/security/mechanics).
</Note>
Now select **Production** for (the source) **Environment** and sync it to the **Production Environment** of the (target) application in Vercel.
Lastly, press create integration to start syncing secrets to Vercel.
![integrations vercel](../../images/integrations-vercel-create.png)
![integrations vercel](../../images/integrations-vercel.png)
You should now see your secret from Infisical appear as production environment variables in your Vercel project.
At this stage, you know how to use the Infisical-Vercel integration to sync production secrets from Infisical to Vercel.
<Warning>
The following environment variable names are reserved by Vercel and cannot be
synced: `AWS_SECRET_KEY`, `AWS_EXECUTION_ENV`, `AWS_LAMBDA_LOG_GROUP_NAME`,
`AWS_LAMBDA_LOG_STREAM_NAME`, `AWS_LAMBDA_FUNCTION_NAME`,
`AWS_LAMBDA_FUNCTION_MEMORY_SIZE`, `AWS_LAMBDA_FUNCTION_VERSION`,
`NOW_REGION`, `TZ`, `LAMBDA_TASK_ROOT`, `LAMBDA_RUNTIME_DIR`,
`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`,
`AWS_REGION`, and `AWS_DEFAULT_REGION`.
</Warning>
## FAQ
<AccordionGroup>
<Accordion title="Why should I use Infisical if I can centralize all my Next.js + Vercel environment variables across all environments directly in Vercel?">
Vercel does not specialize in secret management which means it lacks many useful features for effectively managing environment variables.
Here are some features that teams benefit from by using Infisical together with Vercel:
- Audit logs: See which team members are creating, reading, updating, and deleting environment variables across all environments.
- Versioning and point in time recovery: Rolling back secrets and an entire project state.
- Overriding secrets that should be unique amongst team members.
And much more.
</Accordion>
<Accordion title="Is opting out of end-to-end encryption for the Infisical-Vercel integration safe?">
Yes. Your secrets are still encrypted at rest. To note, most secret managers actually don't support end-to-end encryption.
Check out the [security guide](/security/overview).
</Accordion>
<Accordion title="Is there way to retain end-to-end encryption for syncing production secrets to Vercel?">
Yes. You can also use the Infisical [Node SDK](https://github.com/Infisical/infisical-node) to fetch secrets back to your Next.js app
in both development and production.
Depending on how you use it, however, it may require certain pages to be server-side rendered.
</Accordion>
</AccordionGroup>
See also:
- [Documentation for the Infisical CLI](/cli/overview)
- [Documentation for the Vercel integration](/integrations/cloud/vercel)

View File

@ -0,0 +1,121 @@
---
title: "Node"
---
This guide demonstrates how to use Infisical to manage secrets for your Node stack from local development to production. It uses:
- Infisical (you can use [Infisical Cloud](https://app.infisical.com) or a [self-hosted instance of Infisical](https://infisical.com/docs/self-hosting/overview)) to store your secrets.
- The [infisical-node](https://github.com/Infisical/infisical-node) client SDK to fetch secrets back to your Node application on demand.
## Project Setup
To begin, we need to set up a project in Infisical and add secrets to an environment in it.
### Create a project
1. Create a new project in [Infisical](https://app.infisical.com/).
2. Add a secret to the development environment of this project so we can pull it back for local development. In the **Secrets Overview** page, press **Explore Development** and add a secret with the key `NAME` and value `YOUR_NAME`.
### Create an Infisical Token
Now that we've created a project and added a secret to its development environment, we need to provision an Infisical Token that our Node application can use to access the secret.
1. Head to the **Project Settings > Service Tokens** and press **Add New Token**.
2. Call the token anything like **My App Token** and select **Development** under **Environment**.
3. Copy the token and keep it handy.
## Create a Node app
For this demonstration, we use a minimal Express application. However, the same principles will apply for any Node application such as those built on Koa or Fastify.
### Create an Express app
Initialize a new Node.js project with a default `package.json` file.
```console
npm init -y
```
Install `express` and [infisical-node](https://github.com/Infisical/infisical-node), the client Node SDK for Infisical.
```console
npm install express infisical-node
```
Finally, create an index.js file containing the application code.
```js
const express = require("express");
const app = express();
const PORT = 3000;
const client = new InfisicalClient({
token: "YOUR_INFISICAL_TOKEN"
});
app.get("/", async (req, res) => {
const name = (await client.getSecret("NAME")).secretValue;
res.send(`Hello, ${name}!`);
});
app.listen(PORT, () => {
console.log(`Example app listening on port ${PORT}`);
});
```
Here, we initialized a `client` instance of the Infisical Node SDK with the Infisical Token
that we created earlier, giving access to the secrets in the development environment of the
project in Infisical that we created earlier.
Finally, start the app and head to `http://localhost:3000` to see the message **Hello, Your Name**.
```console
node index.js
```
The client fetched the secret with the key `NAME` from Infisical that we returned in the response of the endpoint.
At this stage, you know how to fetch secrets from Infisical back to your Node application. By using Infisical Tokens scoped to different environments, you can easily manage secrets across various stages of your project in Infisical, from local development to production.
## FAQ
<AccordionGroup>
<Accordion title="Are my secrets exposed in transit every time the SDK fetches them?">
No. Infisical uses end-to-end encryption which ensures that secrets are always encrypted in transit
and decrypted on the client side. In fact, not even the server can decrypt your secrets (unless
that permission is explicitly granted from within the platform).
Check out the [security guide](/security/overview).
</Accordion>
<Accordion title="Isn't it inefficient if my app makes a request every time it needs a secret?">
The client SDK caches every secret and implements a 5-minute waiting period before
re-requesting it. The waiting period can be controlled by setting the `cacheTTL` parameter at
the time of initializing the client.
</Accordion>
<Accordion title="What if a request for a secret fails?">
The SDK caches every secret and falls back to the cached value if a request fails. If no cached
value ever-existed, the SDK falls back to whatever value is on `process.env`.
</Accordion>
<Accordion title="Can I still use process.env with the SDK?">
Yes. If no `token` parameter is passed in at the time of initializing the client or nothing is found when requesting for a secret,
then the SDK falls back to whatever value is on `process.env`.
</Accordion>
<Accordion title="What's the point if I still have to manage a token for the SDK?">
The token enables the SDK to authenticate with Infisical to fetch back your secrets.
Although the SDK requires you to pass in a token, it enables greater efficiency and security
than if you managed dozens of secrets yourself without it. Here're some benefits:
- You always pull in the right secrets because they're fetched on demand from a centralize source that is Infisical.
- You can use the Infisical which comes with tons of benefits like secret versioning, access controls, audit logs, etc.
- You now risk leaking one token that can be revoked instead of dozens of raw secrets.
And much more.
</Accordion>
</AccordionGroup>
See also:
- Explore the [Node SDK](https://github.com/Infisical/infisical-node)

View File

@ -0,0 +1,119 @@
---
title: "Python"
---
This guide demonstrates how to use Infisical to manage secrets for your Python stack from local development to production. It uses:
- Infisical (you can use [Infisical Cloud](https://app.infisical.com) or a [self-hosted instance of Infisical](https://infisical.com/docs/self-hosting/overview)) to store your secrets.
- The [infisical-python](https://github.com/Infisical/infisical-python) client SDK to fetch secrets back to your Python application on demand.
## Project Setup
To begin, we need to set up a project in Infisical and add secrets to an environment in it.
### Create a project
1. Create a new project in [Infisical](https://app.infisical.com/).
2. Add a secret to the development environment of this project so we can pull it back for local development. In the **Secrets Overview** page, press **Explore Development** and add a secret with the key `NAME` and value `YOUR_NAME`.
### Create an Infisical Token
Now that we've created a project and added a secret to its development environment, we need to provision an Infisical Token that our Node application can use to access the secret.
1. Head to the **Project Settings > Service Tokens** and press **Add New Token**.
2. Call the token anything like **My App Token** and select **Development** under **Environment**.
3. Copy the token and keep it handy.
## Create a Python app
For this demonstration, we use a minimal Flask application. However, the same principles will apply for any Python application such as those built with Django.
### Create a Flask app
First, create a virtual environment and activate it.
```console
python3 -m venv env
source env/bin/activate
```
Install Flask and [infisical-python](https://github.com/Infisical/infisical-python), the client Python SDK for Infisical.
```console
pip install Flask infisical
```
Finally, create an `app.py` file containing the application code.
```python
from flask import Flask
from infisical import InfisicalClient
app = Flask(__name__)
client = InfisicalClient(token="your_infisical_token")
@app.route("/")
def hello_world():
# access value
name = client.get_secret("NAME")
return f"Hello, {name.secret_value}!"
```
Here, we initialized a `client` instance of the Infisical Python SDK with the Infisical Token
that we created earlier, giving access to the secrets in the development environment of the
project in Infisical that we created earlier.
Finally, start the app and head to `http://localhost:5000` to see the message **Hello, Your Name**.
```console
flask run
```
The client fetched the secret with the key `NAME` from Infisical that we returned in the response of the endpoint.
At this stage, you know how to fetch secrets from Infisical back to your Python application. By using Infisical Tokens scoped to different environments, you can easily manage secrets across various stages of your project in Infisical, from local development to production.
## FAQ
<AccordionGroup>
<Accordion title="Are my secrets exposed in transit every time the SDK fetches them?">
No. Infisical uses end-to-end encryption which ensures that secrets are always encrypted in transit
and decrypted on the client side. In fact, not even the server can decrypt your secrets (unless
that permission is explicitly granted from within the platform).
Check out the [security guide](/security/overview).
</Accordion>
<Accordion title="Isn't it inefficient if my app makes a request every time it needs a secret?">
The client SDK caches every secret and implements a 5-minute waiting period before
re-requesting it. The waiting period can be controlled by setting the `cacheTTL` parameter at
the time of initializing the client.
</Accordion>
<Accordion title="What if a request for a secret fails?">
The SDK caches every secret and falls back to the cached value if a request fails. If no cached
value ever-existed, the SDK falls back to whatever value is on `process.env`.
</Accordion>
<Accordion title="Can I still use process.env with the SDK?">
Yes. If no `token` parameter is passed in at the time of initializing the client or nothing is found when requesting for a secret,
then the SDK falls back to whatever value is on `process.env`.
</Accordion>
<Accordion title="What's the point if I still have to manage a token for the SDK?">
The token enables the SDK to authenticate with Infisical to fetch back your secrets.
Although the SDK requires you to pass in a token, it enables greater efficiency and security
than if you managed dozens of secrets yourself without it. Here're some benefits:
- You always pull in the right secrets because they're fetched on demand from a centralize source that is Infisical.
- You can use the Infisical which comes with tons of benefits like secret versioning, access controls, audit logs, etc.
- You now risk leaking one token that can be revoked instead of dozens of raw secrets.
And much more.
</Accordion>
</AccordionGroup>
See also:
- Explore the [Python SDK](https://github.com/Infisical/infisical-python)

View File

@ -1,30 +0,0 @@
---
title: "Features"
description: "A non-exhaustive list of features that Infisical has to offer."
---
## Platform
- Provision members access to organizations and projects.
- Manage secrets by adding, deleting, updating them across environments; search, sort, hide/un-hide, export/import them.
- Sync secrets to platforms via integrations to platforms like GitHub, Vercel, and Netlify.
- Rollback secrets to any point in time.
- Rollback each secrets to any version.
- Track actions through audit logs.
## CLI
The [CLI](/cli/overview) is used to inject environment variables into applications and infrastructure.
- Inject environment variables.
- Inject environment variables into containers via service tokens for Docker.
## SDKs
[SDKs](/sdks/overview) enable apps to fetch back secrets using an [Infisical Token](/getting-started/dashboard/token) scoped to a project and environment.
## Roadmap
We're building the future of secret management, one that's comprehensive and accessible to all. Check out our [roadmap](https://www.notion.so/infisical/be2d2585a6694e40889b03aef96ea36b?v=5b19a8127d1a4060b54769567a8785fa).
Interested in contributing? Check out the [guide](/contributing/overview).

View File

@ -1,42 +0,0 @@
---
title: "Introduction"
description: "What is Infisical?"
---
Infisical is an [open-source](https://opensource.com/resources/what-open-source), [end-to-end encrypted](https://en.wikipedia.org/wiki/End-to-end_encryption) secret management platform that enables teams to easily manage and sync their environment variables.
Start syncing environment variables with [Infisical Cloud](https://app.infisical.com) or learn how to [host Infisical](/self-hosting/overview) yourself.
<CardGroup cols={2}>
<Card
title="Quickstart"
href="/getting-started/quickstart"
icon="timer"
color="#ea5a0c"
>
Tour Infisical in a few minutes.
</Card>
<Card href="/cli/overview" title="CLI" icon="square-terminal" color="#16a34a">
Install the CLI to inject secrets into apps and infra.
</Card>
<Card href="/sdks/overview" title="SDKs" icon="puzzle-piece" color="#16a34a">
Install an SDK into your app to fetch secrets.
</Card>
<Card
href="/self-hosting/overview"
title="Self-hosting"
icon="server"
color="#0285c7"
>
Learn how to configure and deploy Infisical.
</Card>
</CardGroup>
<Card
href="/integrations/overview"
title="Integrations"
icon="plug"
color="#dc2626"
>
Explore integrations for Docker, AWS, Heroku, etc.
</Card>

View File

@ -1,112 +0,0 @@
---
title: "Quickstart"
description: "Start managing developer secrets and configs with Infisical in minutes."
---
These examples demonstrate how to store and fetch environment variables from [Infisical Cloud](https://app.infisical.com) into your application.
## Set up Infisical Cloud
1. Login or create an account at `app.infisical.com`.
2. Create a new project.
3. Keep the default environment variables or populate them as in the image below.
![project quickstart](../images/project-quickstart.png)
## Fetch Secrets for Your App
<Tabs>
<Tab title="CLI">
The Infisical CLI is platform-agnostic and enables you to inject environment variables into your app across many tech stacks and frameworks.
### Set up the CLI
1. Follow the instructions to [install our platform-agnostic CLI](/cli/overview).
2. Initialize Infisical for your project.
```bash
# move to your project
cd /path/to/project
# initialize infisical
infisical init
```
### Start your app with environment variables injected
```bash
# inject environment variables into app
infisical run -- [your application start command]
```
Your app should now be running with the environment variables injected.
Check out our [integrations](/integrations/overview) for injecting environment variables into frameworks and platforms like Docker.
</Tab>
<Tab title="SDK">
[Infisical SDKs](/sdks/overview) let your app fetch back secrets using an [Infisical Token](/getting-started/dashboard/token) that is scoped to a project and environment in Infisical. In this example, we demonstrate how to use the [Node SDK](/sdks/languages/node).
### Obtain an [Infisical Token](/getting-started/dashboard/token)
Head to your project settings to create a token scoped to the project and environment you wish to fetch secrets from.
![token add](../images/project-token-add.png)
### Install the SDK
```bash
npm install infisical-node --save
```
### Initialize the Infisical client
```js
await infisical.connect({
token: "your_infisical_token",
});
```
### Get a value
```js
const value = infisical.get("SOME_KEY");
```
### Example with Express
```js
const express = require("express");
const port = 3000;
const infisical = require("infisical-node");
const main = async () => {
await infisical.connect({
token: "st.xxx.xxx",
});
// your application logic
app.get("/", (req, res) => {
res.send(`Howdy, ${infisical.get("NAME")}!`);
});
app.listen(port, async () => {
console.log(`App listening on port ${port}`);
});
};
```
<Warning>
We do not recommend hardcoding your [Infisical
Token](/getting-started/dashboard/token). Setting it as an environment
variable would be best.
</Warning>
Check out our [SDKs](/sdks/overview) for other language SDKs.
</Tab>
</Tabs>

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -37,7 +37,7 @@ Select which Infisical environment secrets you want to sync to which GitLab repo
## Generate service token
Generate an [Infisical Token](../../getting-started/dashboard/token) for the specific project and environment in Infisical.
Generate an [Infisical Token](/documentation/platform/token) for the specific project and environment in Infisical.
## Set the Infisical Token in Gitlab

View File

@ -5,7 +5,7 @@ description: "How to use Infisical to inject secrets and configs into various 3-
Integrations allow environment variables to be synced from Infisical into your local development workflow, CI/CD pipelines, and production infrastructure.
Missing an integration? Throw in a [request](https://github.com/Infisical/infisical/issues).
Missing an integration? [Throw in a request](https://github.com/Infisical/infisical/issues).
| Integration | Type | Status |
| -------------------------------------------------------------- | --------- | ----------- |

View File

@ -13,7 +13,7 @@ Follow this [guide](./docker) to configure the Infisical CLI for each service th
## Generate Infisical Tokens
Generate a unique [Infisical Token](https://infisical.com/docs/getting-started/dashboard/token) for each service.
Generate a unique [Infisical Token](/documentation/platform/token) for each service.
## Add Infisical Tokens to your Docker Compose file

View File

@ -50,7 +50,7 @@ CMD ["infisical", "run", "--command", "npm run start && ..."]
## Generate an Infisical Token
Head to your project settings in Infisical Cloud to generate an [Infisical Token](https://infisical.com/docs/getting-started/dashboard/token).
Head to your project settings in Infisical Cloud to generate an [Infisical Token](/documentation/platform/token).
## Feed Docker your Infisical Token

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