mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-16 15:31:19 +00:00
feat(webhook): implemented api for webhooks
This commit is contained in:
@@ -14,22 +14,24 @@ import * as userActionController from "./userActionController";
|
||||
import * as userController from "./userController";
|
||||
import * as workspaceController from "./workspaceController";
|
||||
import * as secretScanningController from "./secretScanningController";
|
||||
import * as webhookController from "./webhookController";
|
||||
|
||||
export {
|
||||
authController,
|
||||
botController,
|
||||
integrationAuthController,
|
||||
integrationController,
|
||||
keyController,
|
||||
membershipController,
|
||||
membershipOrgController,
|
||||
organizationController,
|
||||
passwordController,
|
||||
secretController,
|
||||
serviceTokenController,
|
||||
signupController,
|
||||
userActionController,
|
||||
userController,
|
||||
workspaceController,
|
||||
secretScanningController
|
||||
authController,
|
||||
botController,
|
||||
integrationAuthController,
|
||||
integrationController,
|
||||
keyController,
|
||||
membershipController,
|
||||
membershipOrgController,
|
||||
organizationController,
|
||||
passwordController,
|
||||
secretController,
|
||||
serviceTokenController,
|
||||
signupController,
|
||||
userActionController,
|
||||
userController,
|
||||
workspaceController,
|
||||
secretScanningController,
|
||||
webhookController
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Request, Response } from "express";
|
||||
import { Types } from "mongoose";
|
||||
import { Integration } from "../../models";
|
||||
import { EventService } from "../../services";
|
||||
import { eventPushSecrets } from "../../events";
|
||||
import { eventPushSecrets, eventStartIntegration } from "../../events";
|
||||
import Folder from "../../models/folder";
|
||||
import { getFolderByPath } from "../../services/FolderService";
|
||||
import { BadRequestError } from "../../utils/errors";
|
||||
@@ -27,19 +27,19 @@ export const createIntegration = async (req: Request, res: Response) => {
|
||||
owner,
|
||||
path,
|
||||
region,
|
||||
secretPath,
|
||||
secretPath
|
||||
} = req.body;
|
||||
|
||||
const folders = await Folder.findOne({
|
||||
workspace: req.integrationAuth.workspace._id,
|
||||
environment: sourceEnvironment,
|
||||
environment: sourceEnvironment
|
||||
});
|
||||
|
||||
if (folders) {
|
||||
const folder = getFolderByPath(folders.nodes, secretPath);
|
||||
if (!folder) {
|
||||
throw BadRequestError({
|
||||
message: "Path for service token does not exist",
|
||||
message: "Path for service token does not exist"
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -62,21 +62,21 @@ export const createIntegration = async (req: Request, res: Response) => {
|
||||
region,
|
||||
secretPath,
|
||||
integration: req.integrationAuth.integration,
|
||||
integrationAuth: new Types.ObjectId(integrationAuthId),
|
||||
integrationAuth: new Types.ObjectId(integrationAuthId)
|
||||
}).save();
|
||||
|
||||
if (integration) {
|
||||
// trigger event - push secrets
|
||||
EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
event: eventStartIntegration({
|
||||
workspaceId: integration.workspace,
|
||||
environment: sourceEnvironment,
|
||||
}),
|
||||
environment: sourceEnvironment
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
integration,
|
||||
integration
|
||||
});
|
||||
};
|
||||
|
||||
@@ -97,26 +97,26 @@ export const updateIntegration = async (req: Request, res: Response) => {
|
||||
appId,
|
||||
targetEnvironment,
|
||||
owner, // github-specific integration param
|
||||
secretPath,
|
||||
secretPath
|
||||
} = req.body;
|
||||
|
||||
const folders = await Folder.findOne({
|
||||
workspace: req.integration.workspace,
|
||||
environment,
|
||||
environment
|
||||
});
|
||||
|
||||
if (folders) {
|
||||
const folder = getFolderByPath(folders.nodes, secretPath);
|
||||
if (!folder) {
|
||||
throw BadRequestError({
|
||||
message: "Path for service token does not exist",
|
||||
message: "Path for service token does not exist"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const integration = await Integration.findOneAndUpdate(
|
||||
{
|
||||
_id: req.integration._id,
|
||||
_id: req.integration._id
|
||||
},
|
||||
{
|
||||
environment,
|
||||
@@ -125,25 +125,25 @@ export const updateIntegration = async (req: Request, res: Response) => {
|
||||
appId,
|
||||
targetEnvironment,
|
||||
owner,
|
||||
secretPath,
|
||||
secretPath
|
||||
},
|
||||
{
|
||||
new: true,
|
||||
new: true
|
||||
}
|
||||
);
|
||||
|
||||
if (integration) {
|
||||
// trigger event - push secrets
|
||||
EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
event: eventStartIntegration({
|
||||
workspaceId: integration.workspace,
|
||||
environment,
|
||||
}),
|
||||
environment
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
integration,
|
||||
integration
|
||||
});
|
||||
};
|
||||
|
||||
@@ -158,12 +158,12 @@ export const deleteIntegration = async (req: Request, res: Response) => {
|
||||
const { integrationId } = req.params;
|
||||
|
||||
const integration = await Integration.findOneAndDelete({
|
||||
_id: integrationId,
|
||||
_id: integrationId
|
||||
});
|
||||
|
||||
if (!integration) throw new Error("Failed to find integration");
|
||||
|
||||
return res.status(200).send({
|
||||
integration,
|
||||
integration
|
||||
});
|
||||
};
|
||||
|
||||
@@ -80,7 +80,8 @@ export const pushSecrets = async (req: Request, res: Response) => {
|
||||
EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment
|
||||
environment,
|
||||
secretPath: "/"
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
import { Request, Response } from "express";
|
||||
import { Types } from "mongoose";
|
||||
import { client, getRootEncryptionKey } from "../../config";
|
||||
import { validateMembership } from "../../helpers";
|
||||
import Webhook from "../../models/webhooks";
|
||||
import { getWebhookPayload, triggerWebhookRequest } from "../../services/WebhookService";
|
||||
import { BadRequestError } from "../../utils/errors";
|
||||
import { ADMIN, ALGORITHM_AES_256_GCM, ENCODING_SCHEME_BASE64, MEMBER } from "../../variables";
|
||||
|
||||
export const createWebhook = async (req: Request, res: Response) => {
|
||||
const { webhookUrl, webhookSecretKey, environment, workspaceId, secretPath } = req.body;
|
||||
const webhook = new Webhook({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
secretPath,
|
||||
url: webhookUrl,
|
||||
algorithm: ALGORITHM_AES_256_GCM,
|
||||
keyEncoding: ENCODING_SCHEME_BASE64
|
||||
});
|
||||
|
||||
if (webhookSecretKey) {
|
||||
const rootEncryptionKey = await getRootEncryptionKey();
|
||||
const { ciphertext, iv, tag } = client.encryptSymmetric(webhookSecretKey, rootEncryptionKey);
|
||||
webhook.iv = iv;
|
||||
webhook.tag = tag;
|
||||
webhook.encryptedSecretKey = ciphertext;
|
||||
}
|
||||
|
||||
await webhook.save();
|
||||
|
||||
return res.status(200).send({
|
||||
webhook,
|
||||
message: "successfully created webhook"
|
||||
});
|
||||
};
|
||||
|
||||
export const updateWebhook = async (req: Request, res: Response) => {
|
||||
const { webhookId } = req.params;
|
||||
const { isDisabled } = req.body;
|
||||
const webhook = await Webhook.findById(webhookId);
|
||||
if (!webhook) {
|
||||
throw BadRequestError({ message: "Webhook not found!!" });
|
||||
}
|
||||
|
||||
// check that user is a member of the workspace
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: webhook.workspace,
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
});
|
||||
|
||||
if (typeof isDisabled !== undefined) {
|
||||
webhook.isDisabled = isDisabled;
|
||||
}
|
||||
await webhook.save();
|
||||
|
||||
return res.status(200).send({
|
||||
webhook,
|
||||
message: "successfully updated webhook"
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteWebhook = async (req: Request, res: Response) => {
|
||||
const { webhookId } = req.params;
|
||||
const webhook = await Webhook.findById(webhookId);
|
||||
if (!webhook) {
|
||||
throw BadRequestError({ message: "Webhook not found!!" });
|
||||
}
|
||||
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: webhook.workspace,
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
});
|
||||
await webhook.remove();
|
||||
|
||||
return res.status(200).send({
|
||||
message: "successfully removed webhook"
|
||||
});
|
||||
};
|
||||
|
||||
export const testWebhook = async (req: Request, res: Response) => {
|
||||
const { webhookId } = req.params;
|
||||
const webhook = await Webhook.findById(webhookId);
|
||||
if (!webhook) {
|
||||
throw BadRequestError({ message: "Webhook not found!!" });
|
||||
}
|
||||
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: webhook.workspace,
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
});
|
||||
|
||||
try {
|
||||
await triggerWebhookRequest(
|
||||
webhook,
|
||||
getWebhookPayload(
|
||||
"test",
|
||||
webhook.workspace.toString(),
|
||||
webhook.environment,
|
||||
webhook.secretPath
|
||||
)
|
||||
);
|
||||
await Webhook.findByIdAndUpdate(webhookId, {
|
||||
lastStatus: "success",
|
||||
lastRunErrorMessage: null
|
||||
});
|
||||
} catch (err) {
|
||||
await Webhook.findByIdAndUpdate(webhookId, {
|
||||
lastStatus: "failed",
|
||||
lastRunErrorMessage: (err as Error).message
|
||||
});
|
||||
return res.status(400).send({
|
||||
message: "Failed to receive response",
|
||||
error: (err as Error).message
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
message: "Successfully received response"
|
||||
});
|
||||
};
|
||||
|
||||
export const listWebhooks = async (req: Request, res: Response) => {
|
||||
const { environment, workspaceId, secretPath } = req.query;
|
||||
|
||||
const optionalFilters: Record<string, string> = {};
|
||||
if (environment) optionalFilters.environment = environment as string;
|
||||
if (secretPath) optionalFilters.secretPath = secretPath as string;
|
||||
|
||||
const webhooks = await Webhook.find({
|
||||
workspace: new Types.ObjectId(workspaceId as string),
|
||||
...optionalFilters
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
webhooks
|
||||
});
|
||||
};
|
||||
@@ -30,9 +30,11 @@ import Folder from "../../models/folder";
|
||||
import {
|
||||
getFolderByPath,
|
||||
getFolderIdFromServiceToken,
|
||||
searchByFolderId
|
||||
searchByFolderId,
|
||||
searchByFolderIdWithDir
|
||||
} from "../../services/FolderService";
|
||||
import { isValidScope } from "../../helpers/secrets";
|
||||
import path from "path";
|
||||
|
||||
/**
|
||||
* Peform a batch of any specified CUD secret operations
|
||||
@@ -47,14 +49,13 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
||||
const {
|
||||
workspaceId,
|
||||
environment,
|
||||
requests,
|
||||
secretPath
|
||||
requests
|
||||
}: {
|
||||
workspaceId: string;
|
||||
environment: string;
|
||||
requests: BatchSecretRequest[];
|
||||
secretPath: string;
|
||||
} = req.body;
|
||||
let secretPath = req.body.secretPath as string;
|
||||
let folderId = req.body.folderId as string;
|
||||
|
||||
const createSecrets: BatchSecret[] = [];
|
||||
@@ -68,10 +69,6 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
||||
});
|
||||
|
||||
const folders = await Folder.findOne({ workspace: workspaceId, environment });
|
||||
if (folders && folderId !== "root") {
|
||||
const folder = searchByFolderId(folders.nodes, folderId as string);
|
||||
if (!folder) throw BadRequestError({ message: "Folder not found" });
|
||||
}
|
||||
|
||||
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, secretPath);
|
||||
@@ -87,6 +84,15 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
||||
folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
|
||||
}
|
||||
|
||||
if (folders && folderId !== "root") {
|
||||
const folder = searchByFolderIdWithDir(folders.nodes, folderId as string);
|
||||
if (!folder?.folder) throw BadRequestError({ message: "Folder not found" });
|
||||
secretPath = path.join(
|
||||
"/",
|
||||
...folder.dir.map(({ name }) => name).filter((name) => name !== "root")
|
||||
);
|
||||
}
|
||||
|
||||
for await (const request of requests) {
|
||||
// do a validation
|
||||
|
||||
@@ -319,7 +325,10 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
||||
// // trigger event - push secrets
|
||||
await EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
// root condition else this will be filled according to the path or folderid
|
||||
secretPath: secretPath || "/"
|
||||
})
|
||||
});
|
||||
|
||||
@@ -535,7 +544,9 @@ export const createSecrets = async (req: Request, res: Response) => {
|
||||
// trigger event - push secrets
|
||||
await EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
secretPath: secretPath || "/"
|
||||
})
|
||||
});
|
||||
}, 5000);
|
||||
@@ -1033,13 +1044,16 @@ export const updateSecrets = async (req: Request, res: Response) => {
|
||||
|
||||
Object.keys(workspaceSecretObj).forEach(async (key) => {
|
||||
// trigger event - push secrets
|
||||
setTimeout(async () => {
|
||||
await EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
workspaceId: new Types.ObjectId(key)
|
||||
})
|
||||
});
|
||||
}, 10000);
|
||||
// This route is not used anymore thus keep it commented out as it does not expose environment
|
||||
// it will end up creating a lot of requests from the server
|
||||
// setTimeout(async () => {
|
||||
// await EventService.handleEvent({
|
||||
// event: eventPushSecrets({
|
||||
// workspaceId: new Types.ObjectId(key),
|
||||
// environment,
|
||||
// })
|
||||
// });
|
||||
// }, 10000);
|
||||
|
||||
const updateAction = await EELogService.createAction({
|
||||
name: ACTION_UPDATE_SECRETS,
|
||||
@@ -1174,11 +1188,13 @@ export const deleteSecrets = async (req: Request, res: Response) => {
|
||||
|
||||
Object.keys(workspaceSecretObj).forEach(async (key) => {
|
||||
// trigger event - push secrets
|
||||
await EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
workspaceId: new Types.ObjectId(key)
|
||||
})
|
||||
});
|
||||
// DEPRECIATED(akhilmhdh): as this would cause server to send so many request
|
||||
// and this route is not used anymore thus like snapshot keeping it commented out
|
||||
// await EventService.handleEvent({
|
||||
// event: eventPushSecrets({
|
||||
// workspaceId: new Types.ObjectId(key)
|
||||
// })
|
||||
// });
|
||||
const deleteAction = await EELogService.createAction({
|
||||
name: ACTION_DELETE_SECRETS,
|
||||
userId: req.user?._id,
|
||||
|
||||
@@ -1,34 +1,29 @@
|
||||
import { Request, Response } from "express";
|
||||
import { Types } from "mongoose";
|
||||
import { Key, Membership, ServiceTokenData, Workspace } from "../../models";
|
||||
import {
|
||||
Key,
|
||||
Membership,
|
||||
ServiceTokenData,
|
||||
Workspace,
|
||||
} from "../../models";
|
||||
import {
|
||||
pullSecrets as pull,
|
||||
v2PushSecrets as push,
|
||||
reformatPullSecrets,
|
||||
pullSecrets as pull,
|
||||
v2PushSecrets as push,
|
||||
reformatPullSecrets
|
||||
} from "../../helpers/secret";
|
||||
import { pushKeys } from "../../helpers/key";
|
||||
import { EventService, TelemetryService } from "../../services";
|
||||
import { eventPushSecrets } from "../../events";
|
||||
|
||||
interface V2PushSecret {
|
||||
type: string; // personal or shared
|
||||
secretKeyCiphertext: string;
|
||||
secretKeyIV: string;
|
||||
secretKeyTag: string;
|
||||
secretKeyHash: string;
|
||||
secretValueCiphertext: string;
|
||||
secretValueIV: string;
|
||||
secretValueTag: string;
|
||||
secretValueHash: string;
|
||||
secretCommentCiphertext?: string;
|
||||
secretCommentIV?: string;
|
||||
secretCommentTag?: string;
|
||||
secretCommentHash?: string;
|
||||
type: string; // personal or shared
|
||||
secretKeyCiphertext: string;
|
||||
secretKeyIV: string;
|
||||
secretKeyTag: string;
|
||||
secretKeyHash: string;
|
||||
secretValueCiphertext: string;
|
||||
secretValueIV: string;
|
||||
secretValueTag: string;
|
||||
secretValueHash: string;
|
||||
secretCommentCiphertext?: string;
|
||||
secretCommentIV?: string;
|
||||
secretCommentTag?: string;
|
||||
secretCommentHash?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,7 +34,7 @@ interface V2PushSecret {
|
||||
* @returns
|
||||
*/
|
||||
export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
|
||||
// upload (encrypted) secrets to workspace with id [workspaceId]
|
||||
// upload (encrypted) secrets to workspace with id [workspaceId]
|
||||
const postHogClient = await TelemetryService.getPostHogClient();
|
||||
let { secrets }: { secrets: V2PushSecret[] } = req.body;
|
||||
const { keys, environment, channel } = req.body;
|
||||
@@ -62,13 +57,13 @@ export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
|
||||
environment,
|
||||
secrets,
|
||||
channel: channel ? channel : "cli",
|
||||
ipAddress: req.realIP,
|
||||
ipAddress: req.realIP
|
||||
});
|
||||
|
||||
await pushKeys({
|
||||
userId: req.user._id,
|
||||
workspaceId,
|
||||
keys,
|
||||
keys
|
||||
});
|
||||
|
||||
if (postHogClient) {
|
||||
@@ -79,8 +74,8 @@ export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
|
||||
numberOfSecrets: secrets.length,
|
||||
environment,
|
||||
workspaceId,
|
||||
channel: channel ? channel : "cli",
|
||||
},
|
||||
channel: channel ? channel : "cli"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -89,12 +84,13 @@ export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
|
||||
event: eventPushSecrets({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
}),
|
||||
secretPath: "/"
|
||||
})
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
message: "Successfully uploaded workspace secrets",
|
||||
});
|
||||
return res.status(200).send({
|
||||
message: "Successfully uploaded workspace secrets"
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -105,7 +101,7 @@ export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
|
||||
* @returns
|
||||
*/
|
||||
export const pullSecrets = async (req: Request, res: Response) => {
|
||||
let secrets;
|
||||
let secrets;
|
||||
const postHogClient = await TelemetryService.getPostHogClient();
|
||||
const environment: string = req.query.environment as string;
|
||||
const channel: string = req.query.channel as string;
|
||||
@@ -128,7 +124,7 @@ export const pullSecrets = async (req: Request, res: Response) => {
|
||||
workspaceId,
|
||||
environment,
|
||||
channel: channel ? channel : "cli",
|
||||
ipAddress: req.realIP,
|
||||
ipAddress: req.realIP
|
||||
});
|
||||
|
||||
if (channel !== "cli") {
|
||||
@@ -144,18 +140,18 @@ export const pullSecrets = async (req: Request, res: Response) => {
|
||||
numberOfSecrets: secrets.length,
|
||||
environment,
|
||||
workspaceId,
|
||||
channel: channel ? channel : "cli",
|
||||
},
|
||||
channel: channel ? channel : "cli"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
secrets,
|
||||
});
|
||||
return res.status(200).send({
|
||||
secrets
|
||||
});
|
||||
};
|
||||
|
||||
export const getWorkspaceKey = async (req: Request, res: Response) => {
|
||||
/*
|
||||
/*
|
||||
#swagger.summary = 'Return encrypted project key'
|
||||
#swagger.description = 'Return encrypted project key'
|
||||
|
||||
@@ -183,43 +179,38 @@ export const getWorkspaceKey = async (req: Request, res: Response) => {
|
||||
}
|
||||
}
|
||||
*/
|
||||
let key;
|
||||
let key;
|
||||
const { workspaceId } = req.params;
|
||||
|
||||
key = await Key.findOne({
|
||||
workspace: workspaceId,
|
||||
receiver: req.user._id,
|
||||
receiver: req.user._id
|
||||
}).populate("sender", "+publicKey");
|
||||
|
||||
if (!key) throw new Error("Failed to find workspace key");
|
||||
|
||||
return res.status(200).json(key);
|
||||
}
|
||||
export const getWorkspaceServiceTokenData = async (
|
||||
req: Request,
|
||||
res: Response
|
||||
) => {
|
||||
return res.status(200).json(key);
|
||||
};
|
||||
export const getWorkspaceServiceTokenData = async (req: Request, res: Response) => {
|
||||
const { workspaceId } = req.params;
|
||||
|
||||
const serviceTokenData = await ServiceTokenData
|
||||
.find({
|
||||
workspace: workspaceId,
|
||||
})
|
||||
.select("+encryptedKey +iv +tag");
|
||||
const serviceTokenData = await ServiceTokenData.find({
|
||||
workspace: workspaceId
|
||||
}).select("+encryptedKey +iv +tag");
|
||||
|
||||
return res.status(200).send({
|
||||
serviceTokenData,
|
||||
});
|
||||
}
|
||||
return res.status(200).send({
|
||||
serviceTokenData
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Return memberships for workspace with id [workspaceId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
export const getWorkspaceMemberships = async (req: Request, res: Response) => {
|
||||
/*
|
||||
/*
|
||||
#swagger.summary = 'Return project memberships'
|
||||
#swagger.description = 'Return project memberships'
|
||||
|
||||
@@ -255,22 +246,22 @@ export const getWorkspaceMemberships = async (req: Request, res: Response) => {
|
||||
const { workspaceId } = req.params;
|
||||
|
||||
const memberships = await Membership.find({
|
||||
workspace: workspaceId,
|
||||
workspace: workspaceId
|
||||
}).populate("user", "+publicKey");
|
||||
|
||||
return res.status(200).send({
|
||||
memberships,
|
||||
});
|
||||
}
|
||||
return res.status(200).send({
|
||||
memberships
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update role of membership with id [membershipId] to role [role]
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
export const updateWorkspaceMembership = async (req: Request, res: Response) => {
|
||||
/*
|
||||
/*
|
||||
#swagger.summary = 'Update project membership'
|
||||
#swagger.description = 'Update project membership'
|
||||
|
||||
@@ -323,33 +314,32 @@ export const updateWorkspaceMembership = async (req: Request, res: Response) =>
|
||||
}
|
||||
}
|
||||
*/
|
||||
const {
|
||||
membershipId,
|
||||
} = req.params;
|
||||
const { membershipId } = req.params;
|
||||
const { role } = req.body;
|
||||
|
||||
|
||||
const membership = await Membership.findByIdAndUpdate(
|
||||
membershipId,
|
||||
{
|
||||
role,
|
||||
}, {
|
||||
new: true,
|
||||
role
|
||||
},
|
||||
{
|
||||
new: true
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
membership,
|
||||
});
|
||||
}
|
||||
return res.status(200).send({
|
||||
membership
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete workspace membership with id [membershipId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
export const deleteWorkspaceMembership = async (req: Request, res: Response) => {
|
||||
/*
|
||||
/*
|
||||
#swagger.summary = 'Delete project membership'
|
||||
#swagger.description = 'Delete project membership'
|
||||
|
||||
@@ -385,23 +375,21 @@ export const deleteWorkspaceMembership = async (req: Request, res: Response) =>
|
||||
}
|
||||
}
|
||||
*/
|
||||
const {
|
||||
membershipId,
|
||||
} = req.params;
|
||||
|
||||
const { membershipId } = req.params;
|
||||
|
||||
const membership = await Membership.findByIdAndDelete(membershipId);
|
||||
|
||||
|
||||
if (!membership) throw new Error("Failed to delete workspace membership");
|
||||
|
||||
|
||||
await Key.deleteMany({
|
||||
receiver: membership.user,
|
||||
workspace: membership.workspace,
|
||||
workspace: membership.workspace
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
membership,
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
membership
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Change autoCapitilzation Rule of workspace
|
||||
@@ -415,18 +403,18 @@ export const toggleAutoCapitalization = async (req: Request, res: Response) => {
|
||||
|
||||
const workspace = await Workspace.findOneAndUpdate(
|
||||
{
|
||||
_id: workspaceId,
|
||||
_id: workspaceId
|
||||
},
|
||||
{
|
||||
autoCapitalization,
|
||||
autoCapitalization
|
||||
},
|
||||
{
|
||||
new: true,
|
||||
new: true
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
message: "Successfully changed autoCapitalization setting",
|
||||
workspace,
|
||||
});
|
||||
return res.status(200).send({
|
||||
message: "Successfully changed autoCapitalization setting",
|
||||
workspace
|
||||
});
|
||||
};
|
||||
|
||||
@@ -21,22 +21,22 @@ export const getSecretsRaw = async (req: Request, res: Response) => {
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
secretPath,
|
||||
authData: req.authData,
|
||||
authData: req.authData
|
||||
});
|
||||
|
||||
const key = await BotService.getWorkspaceKeyWithBot({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
secrets: secrets.map((secret) => {
|
||||
const rep = repackageSecretToRaw({
|
||||
secret,
|
||||
key,
|
||||
key
|
||||
});
|
||||
|
||||
return rep;
|
||||
}),
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
@@ -58,54 +58,47 @@ export const getSecretByNameRaw = async (req: Request, res: Response) => {
|
||||
environment,
|
||||
type,
|
||||
secretPath,
|
||||
authData: req.authData,
|
||||
authData: req.authData
|
||||
});
|
||||
|
||||
const key = await BotService.getWorkspaceKeyWithBot({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
secret: repackageSecretToRaw({
|
||||
secret,
|
||||
key,
|
||||
}),
|
||||
key
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create secret with name [secretName] in plaintext
|
||||
* @param req
|
||||
* @param res
|
||||
* @param res
|
||||
*/
|
||||
export const createSecretRaw = async (req: Request, res: Response) => {
|
||||
const { secretName } = req.params;
|
||||
const {
|
||||
workspaceId,
|
||||
environment,
|
||||
type,
|
||||
secretValue,
|
||||
secretComment,
|
||||
secretPath = "/",
|
||||
} = req.body;
|
||||
const { workspaceId, environment, type, secretValue, secretComment, secretPath = "/" } = req.body;
|
||||
|
||||
const key = await BotService.getWorkspaceKeyWithBot({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8({
|
||||
plaintext: secretName,
|
||||
key,
|
||||
key
|
||||
});
|
||||
|
||||
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8({
|
||||
plaintext: secretValue,
|
||||
key,
|
||||
key
|
||||
});
|
||||
|
||||
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8({
|
||||
plaintext: secretComment,
|
||||
key,
|
||||
key
|
||||
});
|
||||
|
||||
const secret = await SecretService.createSecret({
|
||||
@@ -123,14 +116,15 @@ export const createSecretRaw = async (req: Request, res: Response) => {
|
||||
secretPath,
|
||||
secretCommentCiphertext: secretCommentEncrypted.ciphertext,
|
||||
secretCommentIV: secretCommentEncrypted.iv,
|
||||
secretCommentTag: secretCommentEncrypted.tag,
|
||||
secretCommentTag: secretCommentEncrypted.tag
|
||||
});
|
||||
|
||||
await EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
}),
|
||||
secretPath
|
||||
})
|
||||
});
|
||||
|
||||
const secretWithoutBlindIndex = secret.toObject();
|
||||
@@ -139,10 +133,10 @@ export const createSecretRaw = async (req: Request, res: Response) => {
|
||||
return res.status(200).send({
|
||||
secret: repackageSecretToRaw({
|
||||
secret: secretWithoutBlindIndex,
|
||||
key,
|
||||
}),
|
||||
key
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update secret with name [secretName]
|
||||
@@ -151,21 +145,15 @@ export const createSecretRaw = async (req: Request, res: Response) => {
|
||||
*/
|
||||
export const updateSecretByNameRaw = async (req: Request, res: Response) => {
|
||||
const { secretName } = req.params;
|
||||
const {
|
||||
workspaceId,
|
||||
environment,
|
||||
type,
|
||||
secretValue,
|
||||
secretPath = "/",
|
||||
} = req.body;
|
||||
const { workspaceId, environment, type, secretValue, secretPath = "/" } = req.body;
|
||||
|
||||
const key = await BotService.getWorkspaceKeyWithBot({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8({
|
||||
plaintext: secretValue,
|
||||
key,
|
||||
key
|
||||
});
|
||||
|
||||
const secret = await SecretService.updateSecret({
|
||||
@@ -177,21 +165,22 @@ export const updateSecretByNameRaw = async (req: Request, res: Response) => {
|
||||
secretValueCiphertext: secretValueEncrypted.ciphertext,
|
||||
secretValueIV: secretValueEncrypted.iv,
|
||||
secretValueTag: secretValueEncrypted.tag,
|
||||
secretPath,
|
||||
secretPath
|
||||
});
|
||||
|
||||
await EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
}),
|
||||
secretPath
|
||||
})
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
secret: repackageSecretToRaw({
|
||||
secret,
|
||||
key,
|
||||
}),
|
||||
key
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
@@ -202,12 +191,7 @@ export const updateSecretByNameRaw = async (req: Request, res: Response) => {
|
||||
*/
|
||||
export const deleteSecretByNameRaw = async (req: Request, res: Response) => {
|
||||
const { secretName } = req.params;
|
||||
const {
|
||||
workspaceId,
|
||||
environment,
|
||||
type,
|
||||
secretPath = "/",
|
||||
} = req.body;
|
||||
const { workspaceId, environment, type, secretPath = "/" } = req.body;
|
||||
|
||||
const { secret } = await SecretService.deleteSecret({
|
||||
secretName,
|
||||
@@ -215,25 +199,26 @@ export const deleteSecretByNameRaw = async (req: Request, res: Response) => {
|
||||
environment,
|
||||
type,
|
||||
authData: req.authData,
|
||||
secretPath,
|
||||
secretPath
|
||||
});
|
||||
|
||||
await EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
}),
|
||||
secretPath
|
||||
})
|
||||
});
|
||||
|
||||
const key = await BotService.getWorkspaceKeyWithBot({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
secret: repackageSecretToRaw({
|
||||
secret,
|
||||
key,
|
||||
}),
|
||||
key
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
@@ -252,11 +237,11 @@ export const getSecrets = async (req: Request, res: Response) => {
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
secretPath,
|
||||
authData: req.authData,
|
||||
authData: req.authData
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
secrets,
|
||||
secrets
|
||||
});
|
||||
};
|
||||
|
||||
@@ -278,11 +263,11 @@ export const getSecretByName = async (req: Request, res: Response) => {
|
||||
environment,
|
||||
type,
|
||||
secretPath,
|
||||
authData: req.authData,
|
||||
authData: req.authData
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
secret,
|
||||
secret
|
||||
});
|
||||
};
|
||||
|
||||
@@ -306,7 +291,7 @@ export const createSecret = async (req: Request, res: Response) => {
|
||||
secretCommentCiphertext,
|
||||
secretCommentIV,
|
||||
secretCommentTag,
|
||||
secretPath = "/",
|
||||
secretPath = "/"
|
||||
} = req.body;
|
||||
|
||||
const secret = await SecretService.createSecret({
|
||||
@@ -324,25 +309,25 @@ export const createSecret = async (req: Request, res: Response) => {
|
||||
secretPath,
|
||||
secretCommentCiphertext,
|
||||
secretCommentIV,
|
||||
secretCommentTag,
|
||||
secretCommentTag
|
||||
});
|
||||
|
||||
await EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
}),
|
||||
secretPath
|
||||
})
|
||||
});
|
||||
|
||||
const secretWithoutBlindIndex = secret.toObject();
|
||||
delete secretWithoutBlindIndex.secretBlindIndex;
|
||||
|
||||
return res.status(200).send({
|
||||
secret: secretWithoutBlindIndex,
|
||||
secret: secretWithoutBlindIndex
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Update secret with name [secretName]
|
||||
* @param req
|
||||
@@ -357,7 +342,7 @@ export const updateSecretByName = async (req: Request, res: Response) => {
|
||||
secretValueCiphertext,
|
||||
secretValueIV,
|
||||
secretValueTag,
|
||||
secretPath = "/",
|
||||
secretPath = "/"
|
||||
} = req.body;
|
||||
|
||||
const secret = await SecretService.updateSecret({
|
||||
@@ -369,18 +354,19 @@ export const updateSecretByName = async (req: Request, res: Response) => {
|
||||
secretValueCiphertext,
|
||||
secretValueIV,
|
||||
secretValueTag,
|
||||
secretPath,
|
||||
secretPath
|
||||
});
|
||||
|
||||
await EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
}),
|
||||
secretPath
|
||||
})
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
secret,
|
||||
secret
|
||||
});
|
||||
};
|
||||
|
||||
@@ -391,12 +377,7 @@ export const updateSecretByName = async (req: Request, res: Response) => {
|
||||
*/
|
||||
export const deleteSecretByName = async (req: Request, res: Response) => {
|
||||
const { secretName } = req.params;
|
||||
const {
|
||||
workspaceId,
|
||||
environment,
|
||||
type,
|
||||
secretPath = "/",
|
||||
} = req.body;
|
||||
const { workspaceId, environment, type, secretPath = "/" } = req.body;
|
||||
|
||||
const { secret } = await SecretService.deleteSecret({
|
||||
secretName,
|
||||
@@ -404,17 +385,18 @@ export const deleteSecretByName = async (req: Request, res: Response) => {
|
||||
environment,
|
||||
type,
|
||||
authData: req.authData,
|
||||
secretPath,
|
||||
secretPath
|
||||
});
|
||||
|
||||
await EventService.handleEvent({
|
||||
event: eventPushSecrets({
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
}),
|
||||
secretPath
|
||||
})
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
secret,
|
||||
secret
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user