mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 22:27:48 +00:00
Merge remote-tracking branch 'origin' into update-node-sdk
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
<img src="https://img.shields.io/github/commit-activity/m/infisical/infisical" alt="git commit activity" />
|
<img src="https://img.shields.io/github/commit-activity/m/infisical/infisical" alt="git commit activity" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://cloudsmith.io/~infisical/repos/">
|
<a href="https://cloudsmith.io/~infisical/repos/">
|
||||||
<img src="https://img.shields.io/badge/Downloads-128.2k-orange" alt="Cloudsmith downloads" />
|
<img src="https://img.shields.io/badge/Downloads-150.8k-orange" alt="Cloudsmith downloads" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g">
|
<a href="https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g">
|
||||||
<img src="https://img.shields.io/badge/chat-on%20Slack-blueviolet" alt="Slack community channel" />
|
<img src="https://img.shields.io/badge/chat-on%20Slack-blueviolet" alt="Slack community channel" />
|
||||||
@@ -46,6 +46,7 @@
|
|||||||
<kbd>[<img title="Portuguese - Brazil" alt="Portuguese - Brazil" src="https://cdn.staticaly.com/gh/hjnilsson/country-flags/master/svg/br.svg" width="22">](i18n/README.pt-br.md)</kbd>
|
<kbd>[<img title="Portuguese - Brazil" alt="Portuguese - Brazil" src="https://cdn.staticaly.com/gh/hjnilsson/country-flags/master/svg/br.svg" width="22">](i18n/README.pt-br.md)</kbd>
|
||||||
<kbd>[<img title="Japanese" alt="Japanese language" src="https://cdn.staticaly.com/gh/hjnilsson/country-flags/master/svg/jp.svg" width="22">](i18n/README.ja.md)</kbd>
|
<kbd>[<img title="Japanese" alt="Japanese language" src="https://cdn.staticaly.com/gh/hjnilsson/country-flags/master/svg/jp.svg" width="22">](i18n/README.ja.md)</kbd>
|
||||||
<kbd>[<img title="Italian" alt="Italian language" src="https://cdn.staticaly.com/gh/hjnilsson/country-flags/master/svg/it.svg" width="22">](i18n/README.it.md)</kbd>
|
<kbd>[<img title="Italian" alt="Italian language" src="https://cdn.staticaly.com/gh/hjnilsson/country-flags/master/svg/it.svg" width="22">](i18n/README.it.md)</kbd>
|
||||||
|
<kbd>[<img title="Indian" alt="Hindi language" src="https://cdn.staticaly.com/gh/hjnilsson/country-flags/master/svg/in.svg" width="22">](i18n/README.hi.md)</kbd>
|
||||||
|
|
||||||
**[Infisical](https://infisical.com)** is an open source, end-to-end encrypted secret manager which you can use to centralize your API keys and configs. From Infisical, you can then distribute these secrets across your whole development lifecycle - from development to production . It's designed to be simple and take minutes to get going.
|
**[Infisical](https://infisical.com)** is an open source, end-to-end encrypted secret manager which you can use to centralize your API keys and configs. From Infisical, you can then distribute these secrets across your whole development lifecycle - from development to production . It's designed to be simple and take minutes to get going.
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -131,7 +131,7 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models
|
|||||||
|
|
||||||
isConnected := CheckIsConnectedToInternet()
|
isConnected := CheckIsConnectedToInternet()
|
||||||
var secretsToReturn []models.SingleEnvironmentVariable
|
var secretsToReturn []models.SingleEnvironmentVariable
|
||||||
var serviceTokenDetails api.GetServiceTokenDetailsResponse
|
// var serviceTokenDetails api.GetServiceTokenDetailsResponse
|
||||||
var errorToReturn error
|
var errorToReturn error
|
||||||
|
|
||||||
if infisicalToken == "" {
|
if infisicalToken == "" {
|
||||||
@@ -183,11 +183,11 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
log.Debug("Trying to fetch secrets using service token")
|
log.Debug("Trying to fetch secrets using service token")
|
||||||
secretsToReturn, serviceTokenDetails, errorToReturn = GetPlainTextSecretsViaServiceToken(infisicalToken)
|
secretsToReturn, _, errorToReturn = GetPlainTextSecretsViaServiceToken(infisicalToken)
|
||||||
|
|
||||||
if serviceTokenDetails.Environment != params.Environment {
|
// if serviceTokenDetails.Environment != params.Environment {
|
||||||
PrintErrorMessageAndExit(fmt.Sprintf("Fetch secrets failed: token allows [%s] environment access, not [%s]. Service tokens are environment-specific; no need for --env flag.", params.Environment, serviceTokenDetails.Environment))
|
// PrintErrorMessageAndExit(fmt.Sprintf("Fetch secrets failed: token allows [%s] environment access, not [%s]. Service tokens are environment-specific; no need for --env flag.", params.Environment, serviceTokenDetails.Environment))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
return secretsToReturn, errorToReturn
|
return secretsToReturn, errorToReturn
|
||||||
|
|||||||
@@ -64,7 +64,9 @@ These examples demonstrate how to store and fetch environment variables from [In
|
|||||||
### Initialize the Infisical client
|
### Initialize the Infisical client
|
||||||
|
|
||||||
```js
|
```js
|
||||||
await infisical.connect({
|
import InfisicalClient from "infisical-node";
|
||||||
|
|
||||||
|
const client = new InfisicalClient({
|
||||||
token: "your_infisical_token",
|
token: "your_infisical_token",
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
@@ -72,31 +74,31 @@ These examples demonstrate how to store and fetch environment variables from [In
|
|||||||
### Get a value
|
### Get a value
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const value = infisical.get("SOME_KEY");
|
const value = await client.getSecret("SOME_KEY");
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example with Express
|
### Example with Express
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const express = require("express");
|
import InfisicalClient from "infisical-node";
|
||||||
const port = 3000;
|
import express from "express";
|
||||||
const infisical = require("infisical-node");
|
const app = express();
|
||||||
|
const PORT = 3000;
|
||||||
|
|
||||||
const main = async () => {
|
const client = InfisicalClient({
|
||||||
await infisical.connect({
|
|
||||||
token: "st.xxx.xxx",
|
token: "st.xxx.xxx",
|
||||||
});
|
});
|
||||||
|
|
||||||
// your application logic
|
// your application logic
|
||||||
|
|
||||||
app.get("/", (req, res) => {
|
app.get("/", async (req, res) => {
|
||||||
res.send(`Howdy, ${infisical.get("NAME")}!`);
|
const name = await client.getSecret("NAME");
|
||||||
|
res.send(`Hello! My name is: ${name.secretValue}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(port, async () => {
|
app.listen(PORT, async () => {
|
||||||
console.log(`App listening on port ${port}`);
|
console.log(`App listening on port ${port}`);
|
||||||
});
|
});
|
||||||
};
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<Warning>
|
<Warning>
|
||||||
|
|||||||
+131
-98
@@ -2,7 +2,7 @@
|
|||||||
title: "Node"
|
title: "Node"
|
||||||
---
|
---
|
||||||
|
|
||||||
If you're working with Node.js, the official [infisical-node](https://github.com/Infisical/infisical-node) package is the easiest way to fetch secrets for your application.
|
If you're working with Node.js, the official [infisical-node](https://github.com/Infisical/infisical-node) package is the easiest way to fetch and work with secrets for your application.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -12,141 +12,174 @@ Run `npm` to add `infisical-node` to your project.
|
|||||||
npm install infisical-node --save
|
npm install infisical-node --save
|
||||||
```
|
```
|
||||||
|
|
||||||
## Initialization
|
## Configuration
|
||||||
|
|
||||||
Set up the Infisical client asynchronously as early as possible in your application by importing and initializing the global instance with `infisical.connect(options)`.
|
Import the SDK and create a client instance with your Infisical token.
|
||||||
|
|
||||||
This methods fetches back all the secrets in the project and environment accessible by the token passed in `options`.
|
|
||||||
|
|
||||||
### infisical.connect(options)
|
|
||||||
|
|
||||||
Updates the global instance of the Infisical client with a connection to an Infisical project and fetches back secrets if supplied with an [Infisical Token](/getting-started/dashboard/token).
|
|
||||||
|
|
||||||
<ResponseField name="options" type="object">
|
|
||||||
<Expandable title="properties">
|
|
||||||
<ResponseField name="token" type="string">
|
|
||||||
An [Infisical Token](/getting-started/dashboard/token) scoped to a project
|
|
||||||
and environment
|
|
||||||
</ResponseField>
|
|
||||||
<ResponseField
|
|
||||||
name="siteURL"
|
|
||||||
type="string"
|
|
||||||
default="https://app.infisical.com"
|
|
||||||
>
|
|
||||||
Your self-hosted absolute site URL including the protocol (e.g.
|
|
||||||
`https://app.infisical.com`)
|
|
||||||
</ResponseField>
|
|
||||||
<ResponseField name="debug" type="boolean" default="false">
|
|
||||||
Whether or not debug mode is on
|
|
||||||
</ResponseField>
|
|
||||||
<ResponseField name="attachToProcessEnv" type="boolean" default="false">
|
|
||||||
Whether or not to attach fetched secrets to `process.env`
|
|
||||||
</ResponseField>
|
|
||||||
</Expandable>
|
|
||||||
</ResponseField>
|
|
||||||
|
|
||||||
### infisical.createConnection(options)
|
|
||||||
|
|
||||||
Returns a local instance of the Infisical client with a connection to an Infisical project and fetches back secrets if supplied with an [Infisical Token](/getting-started/dashboard/token).
|
|
||||||
|
|
||||||
This method is useful if you wish to connect to two or more Infisical projects within your app.
|
|
||||||
|
|
||||||
<ResponseField name="options" type="object">
|
|
||||||
<Expandable title="properties">
|
|
||||||
<ResponseField name="token" type="string">
|
|
||||||
An [Infisical Token](/getting-started/dashboard/token) scoped to a project
|
|
||||||
and environment
|
|
||||||
</ResponseField>
|
|
||||||
<ResponseField
|
|
||||||
name="siteURL"
|
|
||||||
type="string"
|
|
||||||
default="https://app.infisical.com"
|
|
||||||
>
|
|
||||||
Your self-hosted absolute site URL including the protocol (e.g.
|
|
||||||
`https://app.infisical.com`)
|
|
||||||
</ResponseField>
|
|
||||||
<ResponseField name="debug" type="boolean" default="false">
|
|
||||||
Whether or not debug mode is on
|
|
||||||
</ResponseField>
|
|
||||||
</Expandable>
|
|
||||||
</ResponseField>
|
|
||||||
|
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<Tab title="ES6">
|
<Tab title="ES6">
|
||||||
```js
|
```js
|
||||||
import infisical from "infisical-node";
|
import InfisicalClient from "infisical-node";
|
||||||
|
|
||||||
const main = async () => {
|
const client = new InfisicalClient({
|
||||||
await infisical.connect({
|
token: "your_infisical_token"
|
||||||
token: "your_infisical_token",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// your app logic
|
// your app logic
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
||||||
```
|
```
|
||||||
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab title="ES5">
|
<Tab title="ES5">
|
||||||
```js
|
```js
|
||||||
const infisical = require("infisical-node");
|
const InfisicalClient = require("infisical-node");
|
||||||
|
|
||||||
infisical.connect({
|
const client = new InfisicalClient({
|
||||||
token: "your_infisical_token"
|
token: "your_infisical_token"
|
||||||
})
|
});
|
||||||
.then(() => {
|
|
||||||
// your application logic
|
// your app logic
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error('Error: ', err);
|
|
||||||
})
|
|
||||||
````
|
````
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
## Usage
|
<ResponseField name="options" type="object">
|
||||||
|
<Expandable title="properties">
|
||||||
To get the value of a secret, use `infisical.get(key)`.
|
<ResponseField name="token" type="string">
|
||||||
|
An [Infisical Token](/getting-started/dashboard/token) scoped to a project
|
||||||
### infisical.get(key)
|
and environment
|
||||||
|
</ResponseField>
|
||||||
Return the value of the secret with the specified `key`. Note that the Infisical client falls back to `process.env` if `token` is `undefined` during the
|
<ResponseField
|
||||||
initialization step or if a value for the secret is not found in the fetched secrets.
|
name="siteURL"
|
||||||
|
type="string"
|
||||||
<ResponseField name="key" type="string" required>
|
default="https://app.infisical.com"
|
||||||
The key of the secret
|
>
|
||||||
|
Your self-hosted absolute site URL including the protocol (e.g.
|
||||||
|
`https://app.infisical.com`)
|
||||||
|
</ResponseField>
|
||||||
|
<ResponseField name="cacheTTL" type="number" default="300">
|
||||||
|
Time-to-live (in seconds) for refreshing cached secrets. Default: `300`.
|
||||||
|
</ResponseField>
|
||||||
|
<ResponseField name="debug" type="boolean" default="false">
|
||||||
|
Whether or not debug mode is on
|
||||||
|
</ResponseField>
|
||||||
|
</Expandable>
|
||||||
</ResponseField>
|
</ResponseField>
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### infisical.getSecret(secretName, options)
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const value = infisical.get("SOME_KEY");
|
const secret = await infisical.getSecret("API_KEY");
|
||||||
|
const value = secret.secretValue; // get its value
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Retrieve a secret from Infisical.
|
||||||
|
|
||||||
|
By default, `getSecret()` returns a personal secret. If not found, it returns a shared secret, or tries to retrieve the value from `process.env`.
|
||||||
|
|
||||||
|
|
||||||
|
<ResponseField name="secretName" type="string" required>
|
||||||
|
The key of the secret to retrieve
|
||||||
|
</ResponseField>
|
||||||
|
<ResponseField name="options" type="object">
|
||||||
|
<Expandable title="properties">
|
||||||
|
<ResponseField name="type" type="string">
|
||||||
|
"personal" (default) or "shared".
|
||||||
|
</ResponseField>
|
||||||
|
</Expandable>
|
||||||
|
</ResponseField>
|
||||||
|
|
||||||
|
### infisical.createSecret(secretName, secretValue, options)
|
||||||
|
|
||||||
|
```js
|
||||||
|
const newApiKey = await infisical.createSecret("API_KEY", "FOO");
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a new secret in Infisical.
|
||||||
|
|
||||||
|
<ResponseField name="secretName" type="string" required>
|
||||||
|
The key of the secret to create
|
||||||
|
</ResponseField>
|
||||||
|
<ResponseField name="secretName" type="string" required>
|
||||||
|
The value of the secret to create
|
||||||
|
</ResponseField>
|
||||||
|
<ResponseField name="options" type="object">
|
||||||
|
<Expandable title="properties">
|
||||||
|
<ResponseField name="type" type="string">
|
||||||
|
"shared" (default) or "personal". A personal secret can only be created if a shared secret with the same name exists.
|
||||||
|
</ResponseField>
|
||||||
|
</Expandable>
|
||||||
|
</ResponseField>
|
||||||
|
|
||||||
|
### infisical.updateSecret(secretName, secretValue, options)
|
||||||
|
|
||||||
|
```js
|
||||||
|
const updatedApiKey = await infisical.updateSecret("API_KEY", "BAR");
|
||||||
|
```
|
||||||
|
|
||||||
|
Update an existing secret in Infisical.
|
||||||
|
|
||||||
|
<ResponseField name="secretName" type="string" required>
|
||||||
|
The key of the secret to update
|
||||||
|
</ResponseField>
|
||||||
|
<ResponseField name="secretName" type="string" required>
|
||||||
|
The new value of the secret
|
||||||
|
</ResponseField>
|
||||||
|
<ResponseField name="options" type="object">
|
||||||
|
<Expandable title="properties">
|
||||||
|
<ResponseField name="type" type="string">
|
||||||
|
"shared" (default) or "personal".
|
||||||
|
</ResponseField>
|
||||||
|
</Expandable>
|
||||||
|
</ResponseField>
|
||||||
|
|
||||||
|
### infisical.deleteSecret(secretName, options)
|
||||||
|
|
||||||
|
```js
|
||||||
|
const deletedSecret = await infisical.deleteSecret("API_KEY");
|
||||||
|
```
|
||||||
|
|
||||||
|
Delete a secret in Infisical.
|
||||||
|
|
||||||
|
<ResponseField name="secretName" type="string" required>
|
||||||
|
The key of the secret to delete
|
||||||
|
</ResponseField>
|
||||||
|
<ResponseField name="options" type="object">
|
||||||
|
<Expandable title="properties">
|
||||||
|
<ResponseField name="type" type="string">
|
||||||
|
"shared" (default) or "personal". Note that deleting a shared secret also deletes all associated personal secrets.
|
||||||
|
</ResponseField>
|
||||||
|
</Expandable>
|
||||||
|
</ResponseField>
|
||||||
|
|
||||||
## Example with Express
|
## Example with Express
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const express = require("express");
|
import InfisicalClient from "infisical-node";
|
||||||
const port = 3000;
|
import express from "express";
|
||||||
const infisical = require("infisical-node");
|
const app = express();
|
||||||
|
const PORT = 3000;
|
||||||
|
|
||||||
const main = async () => {
|
const client = new InfisicalClient({
|
||||||
await infisical.connect({
|
token: "YOUR_INFISICAL_TOKEN"
|
||||||
token: "st.xxx.xxx",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// your application logic
|
app.get("/", async (req, res) => {
|
||||||
|
// access value
|
||||||
app.get("/", (req, res) => {
|
const name = await client.getSecret("NAME");
|
||||||
res.send(`Howdy, ${infisical.get("NAME")}!`);
|
res.send(`Hello! My name is: ${name.secretValue}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(port, async () => {
|
app.listen(PORT, async () => {
|
||||||
|
// initialize client
|
||||||
console.log(`App listening on port ${port}`);
|
console.log(`App listening on port ${port}`);
|
||||||
});
|
});
|
||||||
};
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This example demonstrates how to use the Infisical SDK with an Express application. The application retrieves a secret named "NAME" and responds to requests with a greeting that includes the secret value.
|
||||||
|
|
||||||
<Warning>
|
<Warning>
|
||||||
We do not recommend hardcoding your [Infisical
|
We do not recommend hardcoding your [Infisical
|
||||||
Token](/getting-started/dashboard/token). Setting it as an environment
|
Token](/getting-started/dashboard/token). Setting it as an environment
|
||||||
|
|||||||
Generated
+8
-8
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "npm-proj-1682405486465-0.42385611556033065msLhaJ",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
"tweetnacl-util": "^0.15.1",
|
"tweetnacl-util": "^0.15.1",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"uuidv4": "^6.2.13",
|
"uuidv4": "^6.2.13",
|
||||||
"yaml": "^2.2.0",
|
"yaml": "^2.2.2",
|
||||||
"yup": "^0.32.11"
|
"yup": "^0.32.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -22405,9 +22405,9 @@
|
|||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||||
},
|
},
|
||||||
"node_modules/yaml": {
|
"node_modules/yaml": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
|
||||||
"integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==",
|
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14"
|
"node": ">= 14"
|
||||||
}
|
}
|
||||||
@@ -38856,9 +38856,9 @@
|
|||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||||
},
|
},
|
||||||
"yaml": {
|
"yaml": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
|
||||||
"integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw=="
|
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA=="
|
||||||
},
|
},
|
||||||
"yargs": {
|
"yargs": {
|
||||||
"version": "16.2.0",
|
"version": "16.2.0",
|
||||||
|
|||||||
@@ -82,7 +82,7 @@
|
|||||||
"tweetnacl-util": "^0.15.1",
|
"tweetnacl-util": "^0.15.1",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"uuidv4": "^6.2.13",
|
"uuidv4": "^6.2.13",
|
||||||
"yaml": "^2.2.0",
|
"yaml": "^2.2.2",
|
||||||
"yup": "^0.32.11"
|
"yup": "^0.32.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -803,8 +803,6 @@ export default function Dashboard() {
|
|||||||
isReadDenied: false
|
isReadDenied: false
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(124, envSlug, selectedWorkspaceEnv)
|
|
||||||
|
|
||||||
if (selectedWorkspaceEnv) {
|
if (selectedWorkspaceEnv) {
|
||||||
if (snapshotData) setSelectedSnapshotEnv(selectedWorkspaceEnv);
|
if (snapshotData) setSelectedSnapshotEnv(selectedWorkspaceEnv);
|
||||||
else setSelectedEnv(selectedWorkspaceEnv);
|
else setSelectedEnv(selectedWorkspaceEnv);
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ export const DashboardEnvOverview = ({onEnvChange}: {onEnvChange: any;}) => {
|
|||||||
|
|
||||||
if (isSecretsLoading || isEnvListLoading) {
|
if (isSecretsLoading || isEnvListLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto flex h-full w-full items-center justify-center px-8 text-mineshaft-50 dark:[color-scheme:dark]">
|
<div className="container mx-auto flex h-screen w-full items-center justify-center px-8 text-mineshaft-50 dark:[color-scheme:dark]">
|
||||||
<img src="/images/loading/loading.gif" height={70} width={120} alt="loading animation" />
|
<img src="/images/loading/loading.gif" height={70} width={120} alt="loading animation" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -234,14 +234,14 @@ export const DashboardEnvOverview = ({onEnvChange}: {onEnvChange: any;}) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div> */}
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
<div className="group min-w-full flex flex-row items-center mt-4">
|
<div className="group flex flex-row items-center mt-4 min-w-[60.3rem]">
|
||||||
<div className="w-10 h-10 px-4 flex items-center justify-center border-none"><div className='text-center w-10 text-xs text-transparent'>0</div></div>
|
<div className="w-10 h-10 px-4 flex items-center justify-center border-none"><div className='text-center w-10 text-xs text-transparent'>0</div></div>
|
||||||
<div className="flex flex-row justify-between items-center min-w-[200px] lg:min-w-[220px] xl:min-w-[250px]">
|
<div className="flex flex-row justify-between items-center min-w-[200px] lg:min-w-[220px] xl:min-w-[250px]">
|
||||||
<span className="text-transparent">0</span>
|
<span className="text-transparent">0</span>
|
||||||
<button type="button" className='mr-2 text-transparent'>1</button>
|
<button type="button" className='mr-2 text-transparent'>1</button>
|
||||||
</div>
|
</div>
|
||||||
{userAvailableEnvs?.map(env => {
|
{userAvailableEnvs?.map(env => {
|
||||||
return <div key={`button-${env.slug}`} className="flex flex-row w-full justify-center h-10 items-center border-none mb-1 mx-2 min-w-[10rem]">
|
return <div key={`button-${env.slug}`} className="flex flex-row w-full justify-center h-10 items-center border-none mb-1 mx-2 min-w-[11rem]">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => onEnvChange(env.slug)}
|
onClick={() => onEnvChange(env.slug)}
|
||||||
// router.push(`${router.asPath }?env=${env.slug}`)
|
// router.push(`${router.asPath }?env=${env.slug}`)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const DashboardInput = ({ isOverridden, isSecretValueHidden, isReadOnly, secret,
|
|||||||
ref.current.scrollLeft = e.currentTarget.scrollLeft;
|
ref.current.scrollLeft = e.currentTarget.scrollLeft;
|
||||||
};
|
};
|
||||||
|
|
||||||
return <td key={`row-${secret?.key || ''}--`} className={`flex cursor-default flex-row w-full min-w-[11rem] justify-center h-10 items-center ${!(secret?.value || secret?.value === '') ? "bg-red-400/10" : "bg-mineshaft-900/30"}`}>
|
return <td key={`row-${secret?.key || ''}--`} className={`flex cursor-default flex-row w-full justify-center h-10 items-center ${!(secret?.value || secret?.value === '') ? "bg-red-400/10" : "bg-mineshaft-900/30"}`}>
|
||||||
<div className="group relative whitespace-pre flex flex-col justify-center w-full cursor-default">
|
<div className="group relative whitespace-pre flex flex-col justify-center w-full cursor-default">
|
||||||
<input
|
<input
|
||||||
// {...register(`secrets.${index}.valueOverride`)}
|
// {...register(`secrets.${index}.valueOverride`)}
|
||||||
@@ -118,8 +118,8 @@ export const EnvComparisonRow = ({
|
|||||||
<tr className="group min-w-full flex flex-row items-center hover:bg-bunker-700">
|
<tr className="group min-w-full flex flex-row items-center hover:bg-bunker-700">
|
||||||
<td className="w-10 h-10 px-4 flex items-center justify-center border-none"><div className='text-center w-10 text-xs text-bunker-400'>{index + 1}</div></td>
|
<td className="w-10 h-10 px-4 flex items-center justify-center border-none"><div className='text-center w-10 text-xs text-bunker-400'>{index + 1}</div></td>
|
||||||
<td className="flex flex-row justify-between items-center h-full min-w-[200px] lg:min-w-[220px] xl:min-w-[250px]">
|
<td className="flex flex-row justify-between items-center h-full min-w-[200px] lg:min-w-[220px] xl:min-w-[250px]">
|
||||||
<div className="flex flex-row items-center h-8 cursor-default">{secrets![0].key || ''}</div>
|
<div className="flex truncate flex-row items-center h-8 cursor-default">{secrets![0].key || ''}</div>
|
||||||
<button type="button" className='mr-2 text-bunker-400 hover:text-bunker-300 invisible group-hover:visible' onClick={() => setAreValuesHiddenThisRow(!areValuesHiddenThisRow)}>
|
<button type="button" className='mr-1 ml-2 text-bunker-400 hover:text-bunker-300 invisible group-hover:visible' onClick={() => setAreValuesHiddenThisRow(!areValuesHiddenThisRow)}>
|
||||||
<FontAwesomeIcon icon={areValuesHiddenThisRow ? faEye : faEyeSlash} />
|
<FontAwesomeIcon icon={areValuesHiddenThisRow ? faEye : faEyeSlash} />
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user