Continue api-reference docs

This commit is contained in:
Tuan Dang
2023-01-13 15:04:46 +07:00
parent 0f043605d9
commit 9d4ea2dcda
26 changed files with 1466 additions and 122 deletions

View File

@@ -28,6 +28,7 @@
"express-validator": "^6.14.2",
"handlebars": "^4.7.7",
"helmet": "^5.1.1",
"js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.0",
"jsrp": "^0.2.4",
"libsodium-wrappers": "^0.7.10",
@@ -3698,8 +3699,7 @@
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/array-flatten": {
"version": "1.1.1",
@@ -6638,7 +6638,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"dependencies": {
"argparse": "^2.0.1"
},
@@ -14980,8 +14979,7 @@
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"array-flatten": {
"version": "1.1.1",
@@ -17197,7 +17195,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"requires": {
"argparse": "^2.0.1"
}

View File

@@ -5,7 +5,7 @@
"scripts": {
"start": "npm run build && node build/index.js",
"dev": "nodemon",
"swagger-autogen": "node ./swagger.ts",
"swagger-autogen": "node ./swagger/index.ts",
"build": "rimraf ./build && tsc && cp -R ./src/templates ./build",
"lint": "eslint . --ext .ts",
"lint-and-fix": "eslint . --ext .ts --fix",
@@ -94,6 +94,7 @@
"express-validator": "^6.14.2",
"handlebars": "^4.7.7",
"helmet": "^5.1.1",
"js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.0",
"jsrp": "^0.2.4",
"libsodium-wrappers": "^0.7.10",

View File

@@ -5,6 +5,16 @@
"description": "List of all available APIs that can be consumed",
"version": "1.0.0"
},
"servers": [
{
"url": "https://infisical.com",
"description": "Production server"
},
{
"url": "http://localhost:8080",
"description": "Local server"
}
],
"paths": {
"/api/v1/secret/{secretId}/secret-versions": {
"get": {
@@ -43,6 +53,43 @@
}
}
},
"/api/v1/secret/{secretId}/secret-versions/rollback": {
"post": {
"description": "",
"parameters": [
{
"name": "secretId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
},
"400": {
"description": "Bad Request"
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"version": {
"example": "any"
}
}
}
}
}
}
}
},
"/api/v1/secret-snapshot/{secretSnapshotId}": {
"get": {
"description": "",
@@ -126,6 +173,43 @@
}
}
},
"/api/v1/workspace/{workspaceId}/secret-snapshots/rollback": {
"post": {
"description": "",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
},
"400": {
"description": "Bad Request"
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"version": {
"example": "any"
}
}
}
}
}
}
}
},
"/api/v1/workspace/{workspaceId}/logs": {
"get": {
"description": "",
@@ -476,7 +560,11 @@
"post": {
"description": "",
"parameters": [],
"responses": {}
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v1/bot/{workspaceId}": {
@@ -1997,6 +2085,35 @@
}
}
},
"/api/v2/users/me": {
"get": {
"summary": "Retrieve the current user on the request",
"description": "Retrieve the current user on the request",
"parameters": [],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"$ref": "#/components/schemas/CurrentUser",
"description": "Current user on request"
}
}
}
},
"400": {
"description": "Bad Request"
}
},
"security": [
{
"apiKeyAuth": []
}
]
}
},
"/api/v2/workspace/{workspaceId}/secrets": {
"post": {
"description": "",
@@ -2080,7 +2197,8 @@
},
"/api/v2/workspace/{workspaceId}/encrypted-key": {
"get": {
"description": "",
"summary": "Return encrypted project key",
"description": "Return encrypted project key",
"parameters": [
{
"name": "workspaceId",
@@ -2088,17 +2206,34 @@
"required": true,
"schema": {
"type": "string"
}
},
"description": "ID of project"
}
],
"responses": {
"200": {
"description": "OK"
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ProjectKey"
},
"description": "Encrypted project key for the given project"
}
}
}
},
"400": {
"description": "Bad Request"
}
}
},
"security": [
{
"apiKeyAuth": []
}
]
}
},
"/api/v2/workspace/{workspaceId}/service-token-data": {
@@ -2124,7 +2259,7 @@
}
}
},
"/api/v2/secret/batch-create/workspace/{workspaceId}/environment/{environmentName}": {
"/api/v2/secret/batch-create/workspace/{workspaceId}/environment/{environment}": {
"post": {
"description": "",
"parameters": [
@@ -2137,7 +2272,7 @@
}
},
{
"name": "environmentName",
"name": "environment",
"in": "path",
"required": true,
"schema": {
@@ -2166,7 +2301,7 @@
}
}
},
"/api/v2/secret/workspace/{workspaceId}/environment/{environmentName}": {
"/api/v2/secret/workspace/{workspaceId}/environment/{environment}": {
"post": {
"description": "",
"parameters": [
@@ -2179,47 +2314,7 @@
}
},
{
"name": "environmentName",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secret": {
"example": "any"
}
}
}
}
}
}
},
"patch": {
"description": "",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "environmentName",
"name": "environment",
"in": "path",
"required": true,
"schema": {
@@ -2397,6 +2492,230 @@
}
}
},
"/api/v2/secret/workspace/{workspaceId}/environment/{environmentName}": {
"patch": {
"description": "",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "environmentName",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secret": {
"example": "any"
}
}
}
}
}
}
}
},
"/api/v2/secrets/": {
"post": {
"summary": "Create new secret(s)",
"description": "Create one or many secrets for a given project and environment.",
"parameters": [],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of newly-created secrets for the given project and environment"
}
}
}
}
},
"security": [
{
"apiKeyAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"type": "string",
"description": "ID of project"
},
"environment": {
"type": "string",
"description": "Environment within project"
},
"secrets": {
"$ref": "#/components/schemas/CreateSecret",
"description": "Secret(s) to create - object or array of objects"
}
}
}
}
}
}
},
"get": {
"summary": "Read secrets",
"description": "Read secrets from a project and environment",
"parameters": [],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of secrets for the given project and environment"
}
}
}
}
},
"security": [
{
"apiKeyAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"type": "string",
"description": "ID of project"
},
"environment": {
"type": "string",
"description": "Environment within project"
}
}
}
}
}
}
},
"patch": {
"summary": "Update secret(s)",
"description": "Update secret(s)",
"parameters": [],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of newly-updated secrets for the given project and environment"
}
}
}
}
},
"security": [
{
"apiKeyAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secrets": {
"$ref": "#/components/schemas/UpdateSecret",
"description": "Secret(s) to update - object or array of objects"
}
}
}
}
}
}
},
"delete": {
"summary": "Delete secret(s)",
"description": "Delete one or many secrets by their ID(s)",
"parameters": [],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of deleted secrets"
}
}
}
}
},
"security": [
{
"apiKeyAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secretIds": {
"type": "string",
"description": "ID(s) of secrets - string or array of strings"
}
}
}
}
}
}
}
},
"/api/v2/service-token/": {
"get": {
"description": "",
@@ -2557,11 +2876,243 @@
}
},
"components": {
"schemas": {
"CurrentUser": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"example": ""
},
"email": {
"type": "string",
"example": ""
},
"firstName": {
"type": "string",
"example": ""
},
"lastName": {
"type": "string",
"example": ""
},
"publicKey": {
"type": "string",
"example": ""
},
"encryptedPrivateKey": {
"type": "string",
"example": ""
},
"updatedAt": {
"type": "string",
"example": ""
},
"createdAt": {
"type": "string",
"example": ""
}
}
},
"ProjectKey": {
"type": "object",
"properties": {
"encryptedkey": {
"type": "string",
"example": ""
},
"nonce": {
"type": "string",
"example": ""
},
"sender": {
"type": "object",
"properties": {
"publicKey": {
"type": "string",
"example": ""
}
}
},
"receiver": {
"type": "string",
"example": ""
},
"workspace": {
"type": "string",
"example": ""
}
}
},
"CreateSecret": {
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "shared"
},
"secretKeyCiphertext": {
"type": "string",
"example": ""
},
"secretKeyIV": {
"type": "string",
"example": ""
},
"secretKeyTag": {
"type": "string",
"example": ""
},
"secretValueCiphertext": {
"type": "string",
"example": ""
},
"secretValueIV": {
"type": "string",
"example": ""
},
"secretValueTag": {
"type": "string",
"example": ""
},
"secretCommentCiphertext": {
"type": "string",
"example": ""
},
"secretCommentIV": {
"type": "string",
"example": ""
},
"secretCommentTag": {
"type": "string",
"example": ""
}
}
},
"UpdateSecret": {
"type": "object",
"properties": {
"id": {
"type": "string",
"example": ""
},
"secretKeyCiphertext": {
"type": "string",
"example": ""
},
"secretKeyIV": {
"type": "string",
"example": ""
},
"secretKeyTag": {
"type": "string",
"example": ""
},
"secretValueCiphertext": {
"type": "string",
"example": ""
},
"secretValueIV": {
"type": "string",
"example": ""
},
"secretValueTag": {
"type": "string",
"example": ""
},
"secretCommentCiphertext": {
"type": "string",
"example": ""
},
"secretCommentIV": {
"type": "string",
"example": ""
},
"secretCommentTag": {
"type": "string",
"example": ""
}
}
},
"Secret": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"example": ""
},
"version": {
"type": "number",
"example": 1
},
"workspace": {
"type": "string",
"example": ""
},
"type": {
"type": "string",
"example": "shared"
},
"user": {},
"secretKeyCiphertext": {
"type": "string",
"example": ""
},
"secretKeyIV": {
"type": "string",
"example": ""
},
"secretKeyTag": {
"type": "string",
"example": ""
},
"secretValueCiphertext": {
"type": "string",
"example": ""
},
"secretValueIV": {
"type": "string",
"example": ""
},
"secretValueTag": {
"type": "string",
"example": ""
},
"secretCommentCiphertext": {
"type": "string",
"example": ""
},
"secretCommentIV": {
"type": "string",
"example": ""
},
"secretCommentTag": {
"type": "string",
"example": ""
},
"updatedAt": {
"type": "string",
"example": ""
},
"createdAt": {
"type": "string",
"example": ""
}
}
}
},
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
"bearerFormat": "JWT",
"description": "This security definition uses the HTTP 'bearer' scheme, which allows the client to authenticate using a JSON Web Token (JWT) that is passed in the Authorization header of the request."
},
"apiKeyAuth": {
"type": "apiKey",
"in": "header",
"name": "X-API-Key",
"description": "This security definition uses an API key, which is passed in the header of the request as the value of the \"X-API-Key\" header. The client must provide a valid key in order to access the API."
}
}
}

View File

@@ -8,7 +8,7 @@ import cookieParser from 'cookie-parser';
import dotenv from 'dotenv';
import swaggerUi = require('swagger-ui-express');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const swaggerFile = require('../api-documentation.json')
const swaggerFile = require('../spec.json')
dotenv.config();
@@ -41,7 +41,8 @@ import {
integrationAuth as v1IntegrationAuthRouter
} from './routes/v1';
import {
secret as v2SecretRouter,
users as v2UsersRouter,
secret as v2SecretRouter, // begin to phase out
secrets as v2SecretsRouter,
workspace as v2WorkspaceRouter,
serviceTokenData as v2ServiceTokenDataRouter,
@@ -103,6 +104,7 @@ app.use('/api/v1/integration', v1IntegrationRouter);
app.use('/api/v1/integration-auth', v1IntegrationAuthRouter);
// v2 routes
app.use('/api/v2/users', v2UsersRouter);
app.use('/api/v2/workspace', v2WorkspaceRouter); // TODO: turn into plural route
app.use('/api/v2/secret', v2SecretRouter); // stop supporting, TODO: revise
app.use('/api/v2/secrets', v2SecretsRouter);

View File

@@ -170,10 +170,11 @@ export const logout = async (req: Request, res: Response) => {
* @param res
* @returns
*/
export const checkAuth = async (req: Request, res: Response) =>
res.status(200).send({
export const checkAuth = async (req: Request, res: Response) => {
return res.status(200).send({
message: 'Authenticated'
});
}
/**
* Return new token by redeeming refresh token

View File

@@ -1,3 +1,4 @@
import * as usersController from './usersController';
import * as workspaceController from './workspaceController';
import * as serviceTokenDataController from './serviceTokenDataController';
import * as apiKeyDataController from './apiKeyDataController';
@@ -5,6 +6,7 @@ import * as secretController from './secretController';
import * as secretsController from './secretsController';
export {
usersController,
workspaceController,
serviceTokenDataController,
apiKeyDataController,

View File

@@ -21,6 +21,53 @@ import { BadRequestError } from '../../utils/errors';
* @param res
*/
export const createSecrets = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Create new secret(s)'
#swagger.description = 'Create one or many secrets for a given project and environment.'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.requestBody = {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"type": "string",
"description": "ID of project",
},
"environment": {
"type": "string",
"description": "Environment within project"
},
"secrets": {
$ref: "#/components/schemas/CreateSecret",
"description": "Secret(s) to create - object or array of objects"
}
}
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of newly-created secrets for the given project and environment"
}
}
}
}
*/
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
const { workspaceId, environment } = req.body;
@@ -150,6 +197,49 @@ export const createSecrets = async (req: Request, res: Response) => {
* @returns
*/
export const getSecrets = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Read secrets'
#swagger.description = 'Read secrets from a project and environment'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.requestBody = {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"type": "string",
"description": "ID of project"
},
"environment": {
"type": "string",
"description": "Environment within project"
}
}
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of secrets for the given project and environment"
}
}
}
}
*/
const { workspaceId, environment } = req.query;
let userId: Types.ObjectId | undefined = undefined // used for getting personal secrets for user
@@ -217,6 +307,48 @@ export const getSecrets = async (req: Request, res: Response) => {
* @param res
*/
export const updateSecrets = async (req: Request, res: Response) => {
// TODO: fix update secret schema
/*
#swagger.summary = 'Update secret(s)'
#swagger.description = 'Update secret(s)'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.requestBody = {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secrets": {
$ref: "#/components/schemas/UpdateSecret",
"description": "Secret(s) to update - object or array of objects"
}
}
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of newly-updated secrets for the given project and environment"
}
}
}
}
*/
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
// TODO: move type
@@ -384,6 +516,45 @@ export const updateSecrets = async (req: Request, res: Response) => {
* @param res
*/
export const deleteSecrets = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Delete secret(s)'
#swagger.description = 'Delete one or many secrets by their ID(s)'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.requestBody = {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secretIds": {
"type": "string",
"description": "ID(s) of secrets - string or array of strings"
},
}
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
schema: {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of deleted secrets"
}
}
}
}
*/
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
const toDelete = req.secrets.map((s: any) => s._id);

View File

@@ -0,0 +1,44 @@
import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import {
User
} from '../../models';
export const getMe = async (req: Request, res: Response) => {
/*
#swagger.summary = "Retrieve the current user on the request"
#swagger.description = "Retrieve the current user on the request"
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
$ref: "#/components/schemas/CurrentUser",
"description": "Current user on request"
}
}
}
}
*/
let user;
try {
user = await User
.findById(req.user._id)
.select('+publicKey +encryptedPrivateKey');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get user'
});
}
return res.status(200).send({
user
});
}

View File

@@ -169,6 +169,34 @@ export const pullSecrets = async (req: Request, res: Response) => {
};
export const getWorkspaceKey = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Return encrypted project key'
#swagger.description = 'Return encrypted project key'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "array",
"items": {
$ref: "#/components/schemas/ProjectKey"
},
"description": "Encrypted project key for the given project"
}
}
}
}
*/
let key;
try {
const { workspaceId } = req.params;

View File

@@ -1,3 +1,4 @@
import users from './users';
import secret from './secret'; // stop-supporting
import secrets from './secrets';
import workspace from './workspace';
@@ -5,6 +6,7 @@ import serviceTokenData from './serviceTokenData';
import apiKeyData from './apiKeyData';
export {
users,
secret,
secrets,
workspace,

View File

@@ -0,0 +1,16 @@
import express from 'express';
const router = express.Router();
import {
requireAuth
} from '../../middleware';
import { usersController } from '../../controllers/v2';
router.get(
'/me',
requireAuth({
acceptedAuthModes: ['jwt']
}),
usersController.getMe
);
export default router;

View File

@@ -1,22 +0,0 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const swaggerAutogen = require('swagger-autogen')({ openapi: '3.0.0' });
const doc = {
info: {
title: 'Infisical API',
description: 'List of all available APIs that can be consumed',
},
host: ['https://infisical.com'],
securityDefinitions: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT'
}
}
};
const outputFile = './api-documentation.json';
const endpointsFiles = ['./src/app.ts'];
swaggerAutogen(outputFile, endpointsFiles, doc);

116
backend/swagger/index.ts Normal file
View File

@@ -0,0 +1,116 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const swaggerAutogen = require('swagger-autogen')({ openapi: '3.0.0' });
const fs = require('fs').promises;
const yaml = require('js-yaml');
const { secretSchema } = require('./schemas/index.ts');
/**
* Generates OpenAPI specs for all Infisical API endpoints:
* - spec.json in /backend for api-serving
* - spec.yaml in /docs for API reference
*/
const generateOpenAPISpec = async () => {
const doc = {
info: {
title: 'Infisical API',
description: 'List of all available APIs that can be consumed',
},
host: ['https://infisical.com'],
servers: [
{
url: 'https://infisical.com',
description: 'Production server'
},
{
url: 'http://localhost:8080',
description: 'Local server'
}
],
securityDefinitions: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
description: "This security definition uses the HTTP 'bearer' scheme, which allows the client to authenticate using a JSON Web Token (JWT) that is passed in the Authorization header of the request."
},
apiKeyAuth: {
type: 'apiKey',
in: 'header',
name: 'X-API-Key',
description: 'This security definition uses an API key, which is passed in the header of the request as the value of the "X-API-Key" header. The client must provide a valid key in order to access the API.'
}
},
definitions: {
CurrentUser: {
_id: '',
email: '',
firstName: '',
lastName: '',
publicKey: '',
encryptedPrivateKey: '',
updatedAt: '',
createdAt: ''
},
ProjectKey: {
encryptedkey: '',
nonce: '',
sender: {
publicKey: ''
},
receiver: '',
workspace: ''
},
CreateSecret: {
type: 'shared',
secretKeyCiphertext: '',
secretKeyIV: '',
secretKeyTag: '',
secretValueCiphertext: '',
secretValueIV: '',
secretValueTag: '',
secretCommentCiphertext: '',
secretCommentIV: '',
secretCommentTag: ''
},
UpdateSecret: {
id: '',
secretKeyCiphertext: '',
secretKeyIV: '',
secretKeyTag: '',
secretValueCiphertext: '',
secretValueIV: '',
secretValueTag: '',
secretCommentCiphertext: '',
secretCommentIV: '',
secretCommentTag: ''
},
Secret: {
_id: '',
version: 1,
workspace : '',
type: 'shared',
user: null,
secretKeyCiphertext: '',
secretKeyIV: '',
secretKeyTag: '',
secretValueCiphertext: '',
secretValueIV: '',
secretValueTag: '',
secretCommentCiphertext: '',
secretCommentIV: '',
secretCommentTag: '',
updatedAt: '',
createdAt: ''
}
}
};
const outputJSONFile = '../spec.json';
const outputYAMLFile = '../docs/spec.yaml';
const endpointsFiles = ['../src/app.ts'];
const spec = await swaggerAutogen(outputJSONFile, endpointsFiles, doc);
await fs.writeFile(outputYAMLFile, yaml.dump(spec.data));
}
generateOpenAPISpec();

View File

@@ -0,0 +1,6 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const secretSchema = require('./secretSchema.ts');
module.exports = {
secretSchema
}

View File

@@ -0,0 +1,11 @@
const secretSchema = {
_id: {
type: 'string',
format: 'objectId'
},
version: {
type: 'number'
}
}
module.exports = secretSchema;

View File

@@ -1,4 +1,4 @@
---
title: "Read"
title: "Retrieve"
openapi: "GET /api/v2/secrets/"
---

View File

@@ -0,0 +1,4 @@
---
title: "Get Current User"
openapi: "GET /api/v2/users/me"
---

View File

@@ -0,0 +1,4 @@
---
title: "Get Project Key"
openapi: "GET /api/v2/workspace/{workspaceId}/encrypted-key"
---

View File

@@ -1,3 +1,11 @@
---
title: "Authentication"
---
To authenticate requests with Infisical, you must include an API key in the `X-API-KEY` header of HTTP requests made to the platform. You can obtain an API key from your user settings.
<Info>
It's important to keep your API key secure, as it grants access to your
secrets in Infisical. For added security, consider rotating your API key on a
regular basis.
</Info>

View File

@@ -0,0 +1,64 @@
---
title: "Create secrets"
---
In this example, we demonstrate how to add secrets to a project and environment.
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com)
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
## Flow
1. Get your (encrypted) private key.
2. Decrypt your (encrypted) private key with your password.
3. Get the project key for the project.
4. Decrypt the project key with your private key.
5. Encrypt your secrets with the project key.
6. Send (encrypted) secrets to the Infical API
## Example
```js
const axios = require("axios");
const aes = require("aes-256-gcm");
const nacl = require("tweetnacl");
nacl.util = require("tweetnacl-util");
const WORKSPACE_KEY = "3a7a243eb62078c13f09203e75e8cb32";
const secretKey = "SOME_KEY";
const secretValue = "SOME_VALUE";
// encrypt key of secret
const {
ciphertext: secretKeyCiphertext,
iv: secretKeyIV,
tag: secretKeyTag,
} = aes.encrypt(secretKey, WORKSPACE_KEY);
// encrypt value of secret
const {
ciphertext: secretValueCiphertext,
iv: secretValueIV,
tag: secretValueTag,
} = aes.encrypt(secretKey, WORKSPACE_KEY);
// construct request body
const secret = {
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
secretValueCiphertext,
secretValueIV,
secretValueTag,
};
```
<Info>
This example uses [TweetNaCl.js](https://tweetnacl.js.org/#/), a port of
TweetNacl/Nacl, to perform asymmeric decryption of the project key but there
are ports of NaCl in every major language.
</Info>

View File

@@ -0,0 +1,10 @@
---
title: "Retrieve secrets"
---
1. Get your (encrypted) private key.
2. Decrypt your (encrypted) private key with your password.
3. Get the project key for the project.
4. Decrypt the project key with your private key.
5. Get secrets for a project and environment.
6. Decrypt the secrets in your project.

View File

@@ -0,0 +1,10 @@
---
title: "Update secrets"
---
1. Get your (encrypted) private key.
2. Decrypt your (encrypted) private key with your password.
3. Get the project key for the project.
4. Decrypt the project key with your private key.
5. Encrypt your secrets with the project key.
6. Send (encrypted) updated secrets to the Infical API

View File

@@ -1,3 +1,19 @@
---
title: "Introduction"
---
Infisical's REST API provides users an alternative way to programmatically access and manage
secrets via HTTP requests. This can be useful for automating tasks, such as
rotating credentials, or for integrating secret management into a larger system.
With the REST API, users can create, read, update, and delete secrets, as well as manage access control, query audit logs, and more.
## Concepts
Using Infisical's API to manage secrets requires a basic understanding of the system and its underlying cryptography detailed [here](/security/overview).
- Each user has a public/private key pair that is stored with the platform; private keys are encrypted locally by the user's password before being sent off to the server during the account signup process.
- Each (encrypted) secret belongs to a project and environment.
- Each project has an (encrypted) project key used to encrypt the secrets within that project; Infisical stores copies of the project key, for each member of that project, encrypted under each member's public key.
- Secrets are encrypted symmetrically by your copy of the project key belonging to the project containing.
- Infisical uses AES256-GCM and [TweetNaCl.js](https://tweetnacl.js.org/#/) for symmetric and asymmetric encryption/decryption operations.

View File

@@ -0,0 +1,18 @@
---
title: "Usage"
---
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com) or your self-hosted instance.
- Obtain an API Key in your user settings to be included in requests to the Infisical API.
Using Infisical's API to manage secrets requires a basic understanding of the system and its underlying cryptography detailed [here](/security/overview).
## Concepts
- Each user has a public/private key pair that is stored with the platform; private keys are encrypted locally by the user's password before being sent off to the server during the account signup process.
- Each (encrypted) secret belongs to a project and environment.
- Each project has an (encrypted) project key used to encrypt the secrets within that project; Infisical stores copies of the project key, for each member of that project, encrypted under each member's public key.
- Secrets are encrypted symmetrically by your copy of the project key belonging to the project containing.
- Infisical uses AES256-GCM and [TweetNaCl.js](https://tweetnacl.js.org/#/) for symmetric and asymmetric encryption/decryption operations.

View File

@@ -21,6 +21,16 @@
"to": "#F8B7BD"
}
},
"api": {
"baseUrl": [
"https://app.infisical.com",
"http://localhost:8080"
],
"auth": {
"method": "api-key",
"name": "X-API-KEY"
}
},
"topbarLinks": [
{ "name": "Log In", "url": "https://app.infisical.com/login" }
],
@@ -134,12 +144,32 @@
"group": "Overview",
"pages": [
"api-reference/overview/introduction",
"api-reference/overview/authentication"
"api-reference/overview/authentication",
{
"group": "Examples",
"pages": [
"api-reference/overview/examples/create-secrets",
"api-reference/overview/examples/retrieve-secrets",
"api-reference/overview/examples/update-secrets"
]
}
]
},
{
"group": "Endpoints",
"pages": [
{
"group": "Users",
"pages": [
"api-reference/endpoints/users/me"
]
},
{
"group": "Projects",
"pages": [
"api-reference/endpoints/workspaces/workspace-key"
]
},
{
"group": "Secrets",
"pages": [

View File

@@ -4,7 +4,10 @@ info:
description: List of all available APIs that can be consumed
version: 1.0.0
servers:
- url: https://infisical.com
description: Production server
- url: http://localhost:8080
description: Local server
paths:
/api/v1/secret/{secretId}/secret-versions:
get:
@@ -1270,6 +1273,24 @@ paths:
description: OK
'400':
description: Bad Request
/api/v2/users/me:
get:
summary: Retrieve the current user on the request
description: Retrieve the current user on the request
parameters: []
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
$ref: '#/components/schemas/CurrentUser'
description: Current user on request
'400':
description: Bad Request
security:
- apiKeyAuth: []
/api/v2/workspace/{workspaceId}/secrets:
post:
description: ''
@@ -1321,18 +1342,29 @@ paths:
description: Bad Request
/api/v2/workspace/{workspaceId}/encrypted-key:
get:
description: ''
summary: Return encrypted project key
description: Return encrypted project key
parameters:
- name: workspaceId
in: path
required: true
schema:
type: string
description: ID of project
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/ProjectKey'
description: Encrypted project key for the given project
'400':
description: Bad Request
security:
- apiKeyAuth: []
/api/v2/workspace/{workspaceId}/service-token-data:
get:
description: ''
@@ -1513,57 +1545,122 @@ paths:
example: any
/api/v2/secrets/:
post:
description: ''
summary: Create new secret(s)
description: Create one or many secrets for a given project and environment.
parameters: []
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Secret'
description: >-
Array of newly-created secrets for the given project and
environment
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
secrets:
example: any
workspaceId:
example: any
type: string
description: ID of project
environment:
example: any
type: string
description: Environment within project
secrets:
$ref: '#/components/schemas/CreateSecret'
description: Secret(s) to create - object or array of objects
get:
description: ''
parameters:
- name: workspaceId
in: query
schema:
type: string
- name: environment
in: query
schema:
type: string
responses:
'200':
description: OK
patch:
description: ''
summary: Read secrets
description: Read secrets from a project and environment
parameters: []
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Secret'
description: Array of secrets for the given project and environment
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
workspaceId:
type: string
description: ID of project
environment:
type: string
description: Environment within project
patch:
summary: Update secret(s)
description: Update secret(s)
parameters: []
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Secret'
description: >-
Array of newly-updated secrets for the given project and
environment
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
secrets:
example: any
$ref: '#/components/schemas/UpdateSecret'
description: Secret(s) to update - object or array of objects
delete:
description: ''
summary: Delete secret(s)
description: Delete one or many secrets by their ID(s)
parameters: []
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Secret'
description: Array of deleted secrets
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
secretIds:
type: string
description: ID(s) of secrets - string or array of strings
/api/v2/service-token/:
get:
description: ''
@@ -1665,26 +1762,183 @@ paths:
description: OK
components:
schemas:
secret:
CurrentUser:
type: object
properties:
_id:
type: string
example: ''
email:
type: string
example: ''
firstName:
type: string
example: ''
lastName:
type: string
example: ''
publicKey:
type: string
example: ''
encryptedPrivateKey:
type: string
example: ''
updatedAt:
type: string
example: ''
createdAt:
type: string
example: ''
ProjectKey:
type: object
properties:
encryptedkey:
type: string
example: ''
nonce:
type: string
example: ''
sender:
type: object
properties:
publicKey:
type: string
example: ''
receiver:
type: string
example: ''
workspace:
type: string
example: ''
CreateSecret:
type: object
properties:
type:
type: string
example: object
properties:
type: object
properties:
test:
type: object
properties:
type:
type: string
example: integer
description:
type: string
example: '123'
example: shared
secretKeyCiphertext:
type: string
example: ''
secretKeyIV:
type: string
example: ''
secretKeyTag:
type: string
example: ''
secretValueCiphertext:
type: string
example: ''
secretValueIV:
type: string
example: ''
secretValueTag:
type: string
example: ''
secretCommentCiphertext:
type: string
example: ''
secretCommentIV:
type: string
example: ''
secretCommentTag:
type: string
example: ''
UpdateSecret:
type: object
properties:
id:
type: string
example: ''
secretKeyCiphertext:
type: string
example: ''
secretKeyIV:
type: string
example: ''
secretKeyTag:
type: string
example: ''
secretValueCiphertext:
type: string
example: ''
secretValueIV:
type: string
example: ''
secretValueTag:
type: string
example: ''
secretCommentCiphertext:
type: string
example: ''
secretCommentIV:
type: string
example: ''
secretCommentTag:
type: string
example: ''
Secret:
type: object
properties:
_id:
type: string
example: ''
version:
type: number
example: 1
workspace:
type: string
example: ''
type:
type: string
example: shared
user: {}
secretKeyCiphertext:
type: string
example: ''
secretKeyIV:
type: string
example: ''
secretKeyTag:
type: string
example: ''
secretValueCiphertext:
type: string
example: ''
secretValueIV:
type: string
example: ''
secretValueTag:
type: string
example: ''
secretCommentCiphertext:
type: string
example: ''
secretCommentIV:
type: string
example: ''
secretCommentTag:
type: string
example: ''
updatedAt:
type: string
example: ''
createdAt:
type: string
example: ''
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: >-
This security definition uses the HTTP 'bearer' scheme, which allows the
client to authenticate using a JSON Web Token (JWT) that is passed in
the Authorization header of the request.
apiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: >-
This security definition uses an API key, which is passed in the header
of the request as the value of the "X-API-Key" header. The client must
provide a valid key in order to access the API.