Complete v1 API reference docs, pre-launch

This commit is contained in:
Tuan Dang
2023-01-14 19:02:12 +07:00
parent b63360813a
commit 315810bd74
28 changed files with 2216 additions and 222 deletions

View File

@@ -18,7 +18,8 @@
"paths": {
"/api/v1/secret/{secretId}/secret-versions": {
"get": {
"description": "",
"summary": "Return secret versions",
"description": "Return secret versions",
"parameters": [
{
"name": "secretId",
@@ -26,10 +27,13 @@
"required": true,
"schema": {
"type": "string"
}
},
"description": "ID of secret"
},
{
"name": "offset",
"description": "Number of versions to skip",
"required": false,
"in": "query",
"schema": {
"type": "string"
@@ -37,6 +41,8 @@
},
{
"name": "limit",
"description": "Maximum number of versions to return",
"required": false,
"in": "query",
"schema": {
"type": "string"
@@ -45,17 +51,39 @@
],
"responses": {
"200": {
"description": "OK"
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secretVersions": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SecretVersion"
},
"description": "Secret versions"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
}
},
"security": [
{
"apiKeyAuth": []
}
]
}
},
"/api/v1/secret/{secretId}/secret-versions/rollback": {
"post": {
"description": "",
"summary": "Roll back secret to a version.",
"description": "Roll back secret to a version.",
"parameters": [
{
"name": "secretId",
@@ -63,25 +91,47 @@
"required": true,
"schema": {
"type": "string"
}
},
"description": "ID of secret"
}
],
"responses": {
"200": {
"description": "OK"
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secret": {
"type": "object",
"$ref": "#/components/schemas/Secret",
"description": "Secret rolled back to"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
},
"security": [
{
"apiKeyAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"version": {
"example": "any"
"type": "integer",
"description": "Version of secret to roll back to"
}
}
}
@@ -115,7 +165,8 @@
},
"/api/v1/workspace/{workspaceId}/secret-snapshots": {
"get": {
"description": "",
"summary": "Return project secret snapshot ids",
"description": "Return project secret snapshots ids",
"parameters": [
{
"name": "workspaceId",
@@ -123,10 +174,13 @@
"required": true,
"schema": {
"type": "string"
}
},
"description": "ID of project"
},
{
"name": "offset",
"description": "Number of secret snapshots to skip",
"required": false,
"in": "query",
"schema": {
"type": "string"
@@ -134,6 +188,8 @@
},
{
"name": "limit",
"description": "Maximum number of secret snapshots to return",
"required": false,
"in": "query",
"schema": {
"type": "string"
@@ -142,12 +198,33 @@
],
"responses": {
"200": {
"description": "OK"
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secretSnapshots": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SecretSnapshot"
},
"description": "Project secret snapshots"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
}
},
"security": [
{
"apiKeyAuth": []
}
]
}
},
"/api/v1/workspace/{workspaceId}/secret-snapshots/count": {
@@ -175,8 +252,8 @@
},
"/api/v1/workspace/{workspaceId}/secret-snapshots/rollback": {
"post": {
"summary": "Roll back project secrets to those captured in a secret snapshot version",
"description": "Roll back project secrets to those captured in a secret snapshot version",
"summary": "Roll back project secrets to those captured in a secret snapshot version.",
"description": "Roll back project secrets to those captured in a secret snapshot version.",
"parameters": [
{
"name": "workspaceId",
@@ -194,11 +271,16 @@
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of secrets captured in the secret snapshot"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Secrets rolled back to"
}
}
}
}
}
@@ -232,18 +314,31 @@
},
"/api/v1/workspace/{workspaceId}/logs": {
"get": {
"description": "",
"summary": "Return project (audit) logs",
"description": "Return project (audit) logs",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "ID of project"
},
{
"name": "userId",
"description": "ID of project member",
"required": false,
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "offset",
"description": "Number of logs to skip",
"required": false,
"in": "query",
"schema": {
"type": "string"
@@ -251,6 +346,8 @@
},
{
"name": "limit",
"description": "Maximum number of logs to return",
"required": false,
"in": "query",
"schema": {
"type": "string"
@@ -258,20 +355,21 @@
},
{
"name": "sortBy",
"in": "query",
"description": "Order to sort the logs by",
"schema": {
"type": "string"
}
},
{
"name": "userId",
"in": "query",
"schema": {
"type": "string"
}
"type": "string",
"enum": [
"oldest",
"recent"
]
},
"required": false,
"in": "query"
},
{
"name": "actionNames",
"description": "Names of log actions (comma-separated)",
"required": false,
"in": "query",
"schema": {
"type": "string"
@@ -280,12 +378,33 @@
],
"responses": {
"200": {
"description": "OK"
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"logs": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Log"
},
"description": "Project logs"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
}
},
"security": [
{
"apiKeyAuth": []
}
]
}
},
"/api/v1/action/{actionId}": {
@@ -2117,8 +2236,13 @@
"application/json": {
"schema": {
"type": "object",
"$ref": "#/components/schemas/CurrentUser",
"description": "Current user on request"
"properties": {
"user": {
"type": "object",
"$ref": "#/components/schemas/CurrentUser",
"description": "Current user on request"
}
}
}
}
}
@@ -2279,6 +2403,170 @@
}
}
},
"/api/v2/workspace/{workspaceId}/memberships": {
"get": {
"summary": "Return project memberships",
"description": "Return project memberships",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "ID of project"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"memberships": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Membership"
},
"description": "Memberships of project"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
},
"security": [
{
"apiKeyAuth": []
}
]
}
},
"/api/v2/workspace/{workspaceId}/memberships/{membershipId}": {
"delete": {
"summary": "Delete project membership",
"description": "Delete project membership",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "ID of project"
},
{
"name": "membershipId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "ID of membership"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"membership": {
"$ref": "#/components/schemas/Membership",
"description": "Deleted membership"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
},
"security": [
{
"apiKeyAuth": []
}
]
},
"patch": {
"summary": "Update project membership",
"description": "Update project membership",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "ID of project"
},
{
"name": "membershipId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "ID of membership"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"membership": {
"$ref": "#/components/schemas/Membership",
"description": "Updated membership"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
},
"security": [
{
"apiKeyAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"role": {
"type": "string",
"description": "Role of membership - either admin or member"
}
}
}
}
}
}
}
},
"/api/v2/secret/batch-create/workspace/{workspaceId}/environment/{environment}": {
"post": {
"description": "",
@@ -2565,11 +2853,16 @@
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of newly-created secrets for the given project and environment"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Newly-created secrets for the given project and environment"
}
}
}
}
}
@@ -2608,18 +2901,49 @@
"get": {
"summary": "Read secrets",
"description": "Read secrets from a project and environment",
"parameters": [],
"parameters": [
{
"name": "workspaceId",
"description": "ID of project",
"required": true,
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "environment",
"description": "Environment within project",
"required": true,
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "content",
"in": "query",
"schema": {
"type": "string"
}
}
],
"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"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Secrets for the given project and environment"
}
}
}
}
}
@@ -2629,27 +2953,7 @@
{
"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)",
@@ -2661,11 +2965,16 @@
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of newly-updated secrets for the given project and environment"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Updated secrets"
}
}
}
}
}
@@ -2703,11 +3012,16 @@
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of deleted secrets"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Deleted secrets"
}
}
}
}
}
@@ -2942,6 +3256,52 @@
}
}
},
"Membership": {
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"example": ""
},
"email": {
"type": "string",
"example": ""
},
"firstName": {
"type": "string",
"example": ""
},
"lastName": {
"type": "string",
"example": ""
},
"publicKey": {
"type": "string",
"example": ""
},
"updatedAt": {
"type": "string",
"example": ""
},
"createdAt": {
"type": "string",
"example": ""
}
}
},
"workspace": {
"type": "string",
"example": ""
},
"role": {
"type": "string",
"example": "admin"
}
}
},
"ProjectKey": {
"type": "object",
"properties": {
@@ -3127,6 +3487,187 @@
"example": ""
}
}
},
"Log": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"example": ""
},
"user": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"example": ""
},
"email": {
"type": "string",
"example": ""
},
"firstName": {
"type": "string",
"example": ""
},
"lastName": {
"type": "string",
"example": ""
}
}
},
"workspace": {
"type": "string",
"example": ""
},
"actionNames": {
"type": "array",
"example": [
"addSecrets"
],
"items": {
"type": "string"
}
},
"actions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"example": "addSecrets"
},
"user": {
"type": "string",
"example": ""
},
"workspace": {
"type": "string",
"example": ""
},
"payload": {
"type": "array",
"items": {
"type": "object",
"properties": {
"oldSecretVersion": {
"type": "string",
"example": ""
},
"newSecretVersion": {
"type": "string",
"example": ""
}
}
}
}
}
}
},
"channel": {
"type": "string",
"example": "cli"
},
"ipAddress": {
"type": "string",
"example": "192.168.0.1"
},
"updatedAt": {
"type": "string",
"example": ""
},
"createdAt": {
"type": "string",
"example": ""
}
}
},
"SecretSnapshot": {
"type": "object",
"properties": {
"workspace": {
"type": "string",
"example": ""
},
"version": {
"type": "number",
"example": 1
},
"secretVersions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"example": ""
}
}
}
}
}
},
"SecretVersion": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"example": ""
},
"secret": {
"type": "string",
"example": ""
},
"version": {
"type": "number",
"example": 1
},
"workspace": {
"type": "string",
"example": ""
},
"type": {
"type": "string",
"example": ""
},
"user": {
"type": "string",
"example": ""
},
"environment": {
"type": "string",
"example": ""
},
"isDeleted": {
"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": ""
}
}
}
},
"securitySchemes": {

View File

@@ -58,11 +58,16 @@ export const createSecrets = async (req: Request, res: Response) => {
content: {
"application/json": {
"schema": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of newly-created secrets for the given project and environment"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Newly-created secrets for the given project and environment"
}
}
}
}
}
@@ -205,36 +210,32 @@ export const getSecrets = async (req: Request, res: Response) => {
"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.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.parameters['environment'] = {
"description": "Environment within project",
"required": true,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of secrets for the given project and environment"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Secrets for the given project and environment"
}
}
}
}
}
@@ -307,9 +308,6 @@ 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)'
@@ -339,15 +337,20 @@ export const updateSecrets = async (req: Request, res: Response) => {
content: {
"application/json": {
"schema": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of newly-updated secrets for the given project and environment"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Updated secrets"
}
}
}
}
}
}
}
*/
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
@@ -544,12 +547,17 @@ export const deleteSecrets = async (req: Request, res: Response) => {
#swagger.responses[200] = {
content: {
"application/json": {
schema: {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of deleted secrets"
"schema": {
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Deleted secrets"
}
}
}
}
}

View File

@@ -18,8 +18,13 @@ export const getMe = async (req: Request, res: Response) => {
"application/json": {
"schema": {
"type": "object",
$ref: "#/components/schemas/CurrentUser",
"description": "Current user on request"
"properties": {
"user": {
"type": "object",
$ref: "#/components/schemas/CurrentUser",
"description": "Current user on request"
}
}
}
}
}

View File

@@ -1,7 +1,9 @@
import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { Types } from 'mongoose';
import {
Workspace,
Secret,
Membership,
MembershipOrg,
Integration,
@@ -242,4 +244,222 @@ export const getWorkspaceServiceTokenData = async (
return res.status(200).send({
serviceTokenData
});
}
/**
* Return memberships for workspace with id [workspaceId]
* @param req
* @param res
* @returns
*/
export const getWorkspaceMemberships = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Return project memberships'
#swagger.description = 'Return project memberships'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"memberships": {
"type": "array",
"items": {
$ref: "#/components/schemas/Membership"
},
"description": "Memberships of project"
}
}
}
}
}
}
*/
let memberships;
try {
const { workspaceId } = req.params;
memberships = await Membership.find({
workspace: workspaceId
}).populate('user', '+publicKey');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get workspace members'
});
}
return res.status(200).send({
memberships
});
}
/**
* Delete workspace membership with id [membershipId]
* @param req
* @param res
* @returns
*/
export const deleteWorkspaceMembership = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Delete project membership'
#swagger.description = 'Delete project membership'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.parameters['membershipId'] = {
"description": "ID of membership",
"required": true,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"membership": {
$ref: "#/components/schemas/Membership",
"description": "Deleted membership"
}
}
}
}
}
}
*/
let membership;
try {
const {
membershipId
} = req.params;
membership = await Membership.findByIdAndDelete(membershipId);
if (!membership) throw new Error('Failed to delete workspace membership');
await Key.deleteMany({
receiver: membership.user,
workspace: membership.workspace
});
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to delete workspace membership'
});
}
return res.status(200).send({
membership
});
}
/**
* Update role of membership with id [membershipId] to role [role]
* @param req
* @param res
* @returns
*/
export const updateWorkspaceMembership = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Update project membership'
#swagger.description = 'Update project membership'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.parameters['membershipId'] = {
"description": "ID of membership",
"required": true,
"type": "string"
}
#swagger.requestBody = {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"role": {
"type": "string",
"description": "Role of membership - either admin or member",
}
}
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"membership": {
$ref: "#/components/schemas/Membership",
"description": "Updated membership"
}
}
}
}
}
}
*/
let membership;
try {
const {
membershipId
} = req.params;
const { role } = req.body;
membership = await Membership.findByIdAndUpdate(
membershipId,
{
role
}, {
new: true
}
);
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to update workspace membership'
});
}
return res.status(200).send({
membership
});
}

View File

@@ -10,6 +10,51 @@ import { EESecretService } from '../../services';
* @param res
*/
export const getSecretVersions = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Return secret versions'
#swagger.description = 'Return secret versions'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['secretId'] = {
"description": "ID of secret",
"required": true,
"type": "string"
}
#swagger.parameters['offset'] = {
"description": "Number of versions to skip",
"required": false,
"type": "string"
}
#swagger.parameters['limit'] = {
"description": "Maximum number of versions to return",
"required": false,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
schema: {
"type": "object",
"properties": {
"secretVersions": {
"type": "array",
"items": {
$ref: "#/components/schemas/SecretVersion"
},
"description": "Secret versions"
}
}
}
}
}
}
*/
let secretVersions;
try {
const { secretId } = req.params;
@@ -44,6 +89,54 @@ import { EESecretService } from '../../services';
* @returns
*/
export const rollbackSecretVersion = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Roll back secret to a version.'
#swagger.description = 'Roll back secret to a version.'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['secretId'] = {
"description": "ID of secret",
"required": true,
"type": "string"
}
#swagger.requestBody = {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"version": {
"type": "integer",
"description": "Version of secret to roll back to"
}
}
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
schema: {
"type": "object",
"properties": {
"secret": {
"type": "object",
$ref: "#/components/schemas/Secret",
"description": "Secret rolled back to"
}
}
}
}
}
}
*/
let secret;
try {
const { secretId } = req.params;

View File

@@ -19,6 +19,51 @@ import { getLatestSecretVersionIds } from '../../helpers/secretVersion';
* @param res
*/
export const getWorkspaceSecretSnapshots = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Return project secret snapshot ids'
#swagger.description = 'Return project secret snapshots ids'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.parameters['offset'] = {
"description": "Number of secret snapshots to skip",
"required": false,
"type": "string"
}
#swagger.parameters['limit'] = {
"description": "Maximum number of secret snapshots to return",
"required": false,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
schema: {
"type": "object",
"properties": {
"secretSnapshots": {
"type": "array",
"items": {
$ref: "#/components/schemas/SecretSnapshot"
},
"description": "Project secret snapshots"
}
}
}
}
}
}
*/
let secretSnapshots;
try {
const { workspaceId } = req.params;
@@ -79,8 +124,8 @@ export const getWorkspaceSecretSnapshotsCount = async (req: Request, res: Respon
*/
export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Roll back project secrets to those captured in a secret snapshot version'
#swagger.description = 'Roll back project secrets to those captured in a secret snapshot version'
#swagger.summary = 'Roll back project secrets to those captured in a secret snapshot version.'
#swagger.description = 'Roll back project secrets to those captured in a secret snapshot version.'
#swagger.security = [{
"apiKeyAuth": []
@@ -113,11 +158,16 @@ export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Respons
content: {
"application/json": {
schema: {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of secrets captured in the secret snapshot"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Secrets rolled back to"
}
}
}
}
}
@@ -276,6 +326,72 @@ export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Respons
* @returns
*/
export const getWorkspaceLogs = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Return project (audit) logs'
#swagger.description = 'Return project (audit) logs'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.parameters['userId'] = {
"description": "ID of project member",
"required": false,
"type": "string"
}
#swagger.parameters['offset'] = {
"description": "Number of logs to skip",
"required": false,
"type": "string"
}
#swagger.parameters['limit'] = {
"description": "Maximum number of logs to return",
"required": false,
"type": "string"
}
#swagger.parameters['sortBy'] = {
"description": "Order to sort the logs by",
"schema": {
"type": "string",
"@enum": ["oldest", "recent"]
},
"required": false
}
#swagger.parameters['actionNames'] = {
"description": "Names of log actions (comma-separated)",
"required": false,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
schema: {
"type": "object",
"properties": {
"logs": {
"type": "array",
"items": {
$ref: "#/components/schemas/Log"
},
"description": "Project logs"
}
}
}
}
}
}
*/
let logs
try {
const { workspaceId } = req.params;

View File

@@ -2,6 +2,7 @@ import requireAuth from './requireAuth';
import requireBotAuth from './requireBotAuth';
import requireSignupAuth from './requireSignupAuth';
import requireWorkspaceAuth from './requireWorkspaceAuth';
import requireMembershipAuth from './requireMembershipAuth';
import requireOrganizationAuth from './requireOrganizationAuth';
import requireIntegrationAuth from './requireIntegrationAuth';
import requireIntegrationAuthorizationAuth from './requireIntegrationAuthorizationAuth';
@@ -16,6 +17,7 @@ export {
requireBotAuth,
requireSignupAuth,
requireWorkspaceAuth,
requireMembershipAuth,
requireOrganizationAuth,
requireIntegrationAuth,
requireIntegrationAuthorizationAuth,

View File

@@ -0,0 +1,57 @@
import { Request, Response, NextFunction } from 'express';
import { UnauthorizedRequestError } from '../utils/errors';
import {
Membership,
} from '../models';
import { validateMembership } from '../helpers/membership';
type req = 'params' | 'body' | 'query';
/**
* Validate membership with id [membershipId] and that user with id
* [req.user._id] can modify that membership.
* @param {Object} obj
* @param {String[]} obj.acceptedRoles - accepted workspace roles for JWT auth
* @param {String[]} obj.location - location of [workspaceId] on request (e.g. params, body) for parsing
*/
const requireMembershipAuth = ({
acceptedRoles,
location = 'params'
}: {
acceptedRoles: string[];
location?: req;
}) => {
return async (
req: Request,
res: Response,
next: NextFunction
) => {
try {
const { membershipId } = req[location];
const membership = await Membership.findById(membershipId);
if (!membership) throw new Error('Failed to find target membership');
const userMembership = await Membership.findOne({
workspace: membership.workspace
});
if (!userMembership) throw new Error('Failed to validate own membership')
const targetMembership = await validateMembership({
userId: req.user._id.toString(),
workspaceId: membership.workspace.toString(),
acceptedRoles
});
req.targetMembership = targetMembership;
} catch (err) {
return next(UnauthorizedRequestError({
message: 'Unable to validate workspace membership'
}));
}
}
}
export default requireMembershipAuth;

View File

@@ -4,7 +4,7 @@ import { body, param } from 'express-validator';
import { requireAuth, validateRequest } from '../../middleware';
import { membershipController } from '../../controllers/v1';
router.get( // used for CLI (deprecate)
router.get( // used for old CLI (deprecate)
'/:workspaceId/connect',
requireAuth({
acceptedAuthModes: ['jwt']

View File

@@ -3,6 +3,7 @@ const router = express.Router();
import { body, param, query } from 'express-validator';
import {
requireAuth,
requireMembershipAuth,
requireWorkspaceAuth,
validateRequest
} from '../../middleware';
@@ -67,4 +68,54 @@ router.get(
workspaceController.getWorkspaceServiceTokenData
);
// TODO: /POST to create membership
router.get( // new - TODO: rewire dashboard to this route
'/:workspaceId/memberships',
param('workspaceId').exists().trim(),
validateRequest,
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
}),
workspaceController.getWorkspaceMemberships
);
router.delete( // TODO - rewire dashboard to this route
'/:workspaceId/memberships/:membershipId',
param('workspaceId').exists().trim(),
param('membershipId').exists().trim(),
validateRequest,
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN],
}),
requireMembershipAuth({
acceptedRoles: [ADMIN]
}),
workspaceController.deleteWorkspaceMembership
);
router.patch( // TODO - rewire dashboard to this route
'/:workspaceId/memberships/:membershipId',
param('workspaceId').exists().trim(),
param('membershipId').exists().trim(),
body('role').exists().isString().trim().isIn([ADMIN, MEMBER]),
validateRequest,
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN],
}),
requireMembershipAuth({
acceptedRoles: [ADMIN]
}),
workspaceController.updateWorkspaceMembership
);
export default router;

View File

@@ -8,6 +8,7 @@ declare global {
user: any;
workspace: any;
membership: any;
targetMembership: any;
organization: any;
membershipOrg: any;
integration: any;

View File

@@ -53,6 +53,19 @@ const generateOpenAPISpec = async () => {
updatedAt: '',
createdAt: ''
},
Membership: {
user: {
_id: '',
email: '',
firstName: '',
lastName: '',
publicKey: '',
updatedAt: '',
createdAt: ''
},
workspace: '',
role: 'admin'
},
ProjectKey: {
encryptedkey: '',
nonce: '',
@@ -103,6 +116,61 @@ const generateOpenAPISpec = async () => {
secretCommentTag: '',
updatedAt: '',
createdAt: ''
},
Log: {
_id: '',
user: {
_id: '',
email: '',
firstName: '',
lastName: ''
},
workspace: '',
actionNames: [
'addSecrets'
],
actions: [
{
name: 'addSecrets',
user: '',
workspace: '',
payload: [
{
oldSecretVersion: '',
newSecretVersion: ''
}
]
}
],
channel: 'cli',
ipAddress: '192.168.0.1',
updatedAt: '',
createdAt: ''
},
SecretSnapshot: {
workspace: '',
version: 1,
secretVersions: [
{
_id: ''
}
]
},
SecretVersion: {
_id: '',
secret: '',
version: 1,
workspace: '',
type: '',
user: '',
environment: '',
isDeleted: '',
secretKeyCiphertext: '',
secretKeyIV: '',
secretKeyTag: '',
secretValueCiphertext: '',
secretValueIV: '',
secretValueTag: '',
}
}
};