mirror of
https://github.com/Infisical/infisical.git
synced 2025-03-29 22:02:57 +00:00
Compare commits
25 Commits
bring-back
...
infisical/
Author | SHA1 | Date | |
---|---|---|---|
37d52432d0 | |||
04b7e04d98 | |||
57a3384f32 | |||
c813c91aec | |||
91947df5f6 | |||
8330890087 | |||
221e601173 | |||
28c24fc8c1 | |||
a9389643b8 | |||
58854e6b81 | |||
7ae859e9ae | |||
ff6e07bdcf | |||
fc9393b77f | |||
0cad823267 | |||
97a0728f02 | |||
6cb8cf53f8 | |||
1ac607b42e | |||
ec21e35f8c | |||
2591161272 | |||
be86e4176c | |||
2067c021ed | |||
648968c453 | |||
373dfff8e0 | |||
b9ce448bed | |||
142fcf0a01 |
@ -28,4 +28,4 @@ HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \
|
||||
|
||||
EXPOSE 4000
|
||||
|
||||
CMD ["npm", "run", "start"]
|
||||
CMD ["npm", "run", "start"]
|
||||
|
@ -15,20 +15,20 @@ import { checkUserDevice } from "../../helpers/user";
|
||||
import {
|
||||
ACTION_LOGIN,
|
||||
ACTION_LOGOUT,
|
||||
AUTH_MODE_JWT,
|
||||
} from "../../variables";
|
||||
import {
|
||||
BadRequestError,
|
||||
UnauthorizedRequestError,
|
||||
} from "../../utils/errors";
|
||||
import { EELogService } from "../../ee/services";
|
||||
import { getChannelFromUserAgent } from "../../utils/posthog";
|
||||
import { getUserAgentType } from "../../utils/posthog";
|
||||
import {
|
||||
getHttpsEnabled,
|
||||
getJwtAuthLifetime,
|
||||
getJwtAuthSecret,
|
||||
getJwtRefreshSecret,
|
||||
} from "../../config";
|
||||
import { ActorType } from "../../ee/models";
|
||||
|
||||
declare module "jsonwebtoken" {
|
||||
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
||||
@ -142,7 +142,7 @@ export const login2 = async (req: Request, res: Response) => {
|
||||
loginAction && await EELogService.createLog({
|
||||
userId: user._id,
|
||||
actions: [loginAction],
|
||||
channel: getChannelFromUserAgent(req.headers["user-agent"]),
|
||||
channel: getUserAgentType(req.headers["user-agent"]),
|
||||
ipAddress: req.realIP,
|
||||
});
|
||||
|
||||
@ -170,7 +170,7 @@ export const login2 = async (req: Request, res: Response) => {
|
||||
* @returns
|
||||
*/
|
||||
export const logout = async (req: Request, res: Response) => {
|
||||
if (req.authData.authMode === AUTH_MODE_JWT && req.authData.authPayload instanceof User && req.authData.tokenVersionId) {
|
||||
if (req.authData.actor.type === ActorType.USER && req.authData.tokenVersionId) {
|
||||
await clearTokens(req.authData.tokenVersionId)
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ export const logout = async (req: Request, res: Response) => {
|
||||
logoutAction && await EELogService.createLog({
|
||||
userId: req.user._id,
|
||||
actions: [logoutAction],
|
||||
channel: getChannelFromUserAgent(req.headers["user-agent"]),
|
||||
channel: getUserAgentType(req.headers["user-agent"]),
|
||||
ipAddress: req.realIP,
|
||||
});
|
||||
|
||||
|
@ -3,7 +3,9 @@ import { Types } from "mongoose";
|
||||
import { standardRequest } from "../../config/request";
|
||||
import { getApps, getTeams, revokeAccess } from "../../integrations";
|
||||
import { Bot, IntegrationAuth } from "../../models";
|
||||
import { EventType } from "../../ee/models";
|
||||
import { IntegrationService } from "../../services";
|
||||
import { EEAuditLogService } from "../../ee/services";
|
||||
import {
|
||||
ALGORITHM_AES_256_GCM,
|
||||
ENCODING_SCHEME_UTF8,
|
||||
@ -62,6 +64,19 @@ export const oAuthExchange = async (req: Request, res: Response) => {
|
||||
environment: environments[0].slug
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.AUTHORIZE_INTEGRATION,
|
||||
metadata: {
|
||||
integration: integrationAuth.integration
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: integrationAuth.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
integrationAuth
|
||||
});
|
||||
@ -129,6 +144,19 @@ export const saveIntegrationAccessToken = async (req: Request, res: Response) =>
|
||||
});
|
||||
|
||||
if (!integrationAuth) throw new Error("Failed to save integration access token");
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.AUTHORIZE_INTEGRATION,
|
||||
metadata: {
|
||||
integration: integrationAuth.integration
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: integrationAuth.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
integrationAuth
|
||||
@ -530,6 +558,23 @@ export const deleteIntegrationAuth = async (req: Request, res: Response) => {
|
||||
integrationAuth: req.integrationAuth,
|
||||
accessToken: req.accessToken
|
||||
});
|
||||
|
||||
if (!integrationAuth) return res.status(400).send({
|
||||
message: "Failed to find integration authorization"
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.UNAUTHORIZE_INTEGRATION,
|
||||
metadata: {
|
||||
integration: integrationAuth.integration
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: integrationAuth.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
integrationAuth
|
||||
|
@ -6,6 +6,8 @@ import { eventStartIntegration } from "../../events";
|
||||
import Folder from "../../models/folder";
|
||||
import { getFolderByPath } from "../../services/FolderService";
|
||||
import { BadRequestError } from "../../utils/errors";
|
||||
import { EEAuditLogService } from "../../ee/services";
|
||||
import { EventType } from "../../ee/models";
|
||||
|
||||
/**
|
||||
* Create/initialize an (empty) integration for integration authorization
|
||||
@ -74,6 +76,31 @@ export const createIntegration = async (req: Request, res: Response) => {
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.CREATE_INTEGRATION,
|
||||
metadata: {
|
||||
integrationId: integration._id.toString(),
|
||||
integration: integration.integration,
|
||||
environment: integration.environment,
|
||||
secretPath,
|
||||
url: integration.url,
|
||||
app: integration.app,
|
||||
appId: integration.appId,
|
||||
targetEnvironment: integration.targetEnvironment,
|
||||
targetEnvironmentId: integration.targetEnvironmentId,
|
||||
targetService: integration.targetService,
|
||||
targetServiceId: integration.targetServiceId,
|
||||
path: integration.path,
|
||||
region: integration.region
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: integration.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
integration
|
||||
@ -148,8 +175,7 @@ export const updateIntegration = async (req: Request, res: Response) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete integration with id [integrationId] and deactivate bot if there are
|
||||
* no integrations left
|
||||
* Delete integration with id [integrationId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
@ -163,6 +189,31 @@ export const deleteIntegration = async (req: Request, res: Response) => {
|
||||
|
||||
if (!integration) throw new Error("Failed to find integration");
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.DELETE_INTEGRATION,
|
||||
metadata: {
|
||||
integrationId: integration._id.toString(),
|
||||
integration: integration.integration,
|
||||
environment: integration.environment,
|
||||
secretPath: integration.secretPath,
|
||||
url: integration.url,
|
||||
app: integration.app,
|
||||
appId: integration.appId,
|
||||
targetEnvironment: integration.targetEnvironment,
|
||||
targetEnvironmentId: integration.targetEnvironmentId,
|
||||
targetService: integration.targetService,
|
||||
targetServiceId: integration.targetServiceId,
|
||||
path: integration.path,
|
||||
region: integration.region
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: integration.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
integration
|
||||
});
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { Types } from "mongoose";
|
||||
import { Request, Response } from "express";
|
||||
import { Key } from "../../models";
|
||||
import { findMembership } from "../../helpers/membership";
|
||||
import { EventType } from "../../ee/models";
|
||||
import { EEAuditLogService } from "../../ee/services";
|
||||
|
||||
/**
|
||||
* Add (encrypted) copy of workspace key for workspace with id [workspaceId] for user with
|
||||
@ -44,7 +47,7 @@ export const uploadKey = async (req: Request, res: Response) => {
|
||||
*/
|
||||
export const getLatestKey = async (req: Request, res: Response) => {
|
||||
const { workspaceId } = req.params;
|
||||
|
||||
|
||||
// get latest key
|
||||
const latestKey = await Key.find({
|
||||
workspace: workspaceId,
|
||||
@ -58,6 +61,18 @@ export const getLatestKey = async (req: Request, res: Response) => {
|
||||
|
||||
if (latestKey.length > 0) {
|
||||
resObj["latestKey"] = latestKey[0];
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.GET_WORKSPACE_KEY,
|
||||
metadata: {
|
||||
keyId: latestKey[0]._id.toString()
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return res.status(200).send(resObj);
|
||||
|
@ -1,9 +1,12 @@
|
||||
import { Request, Response } from "express";
|
||||
import { Key, Membership, MembershipOrg, User } from "../../models";
|
||||
import { Types } from "mongoose";
|
||||
import { IUser, Key, Membership, MembershipOrg, User } from "../../models";
|
||||
import { EventType } from "../../ee/models";
|
||||
import { deleteMembership as deleteMember, findMembership } from "../../helpers/membership";
|
||||
import { sendMail } from "../../helpers/nodemailer";
|
||||
import { ACCEPTED, ADMIN, MEMBER } from "../../variables";
|
||||
import { getSiteURL } from "../../config";
|
||||
import { EEAuditLogService } from "../../ee/services";
|
||||
|
||||
/**
|
||||
* Check that user is a member of workspace with id [workspaceId]
|
||||
@ -36,11 +39,11 @@ export const validateMembership = async (req: Request, res: Response) => {
|
||||
*/
|
||||
export const deleteMembership = async (req: Request, res: Response) => {
|
||||
const { membershipId } = req.params;
|
||||
|
||||
|
||||
// check if membership to delete exists
|
||||
const membershipToDelete = await Membership.findOne({
|
||||
_id: membershipId
|
||||
}).populate("user");
|
||||
}).populate<{ user: IUser }>("user");
|
||||
|
||||
if (!membershipToDelete) {
|
||||
throw new Error("Failed to delete workspace membership that doesn't exist");
|
||||
@ -66,6 +69,20 @@ export const deleteMembership = async (req: Request, res: Response) => {
|
||||
const deletedMembership = await deleteMember({
|
||||
membershipId: membershipToDelete._id.toString()
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.REMOVE_WORKSPACE_MEMBER,
|
||||
metadata: {
|
||||
userId: membershipToDelete.user._id.toString(),
|
||||
email: membershipToDelete.user.email
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: membership.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
deletedMembership
|
||||
@ -140,7 +157,7 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => {
|
||||
const inviteeMembership = await Membership.findOne({
|
||||
user: invitee._id,
|
||||
workspace: workspaceId
|
||||
});
|
||||
}).populate<{ user: IUser }>("user");
|
||||
|
||||
if (inviteeMembership) throw new Error("Failed to add existing member of workspace");
|
||||
|
||||
@ -181,6 +198,20 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => {
|
||||
}
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.ADD_WORKSPACE_MEMBER,
|
||||
metadata: {
|
||||
userId: invitee._id.toString(),
|
||||
email: invitee.email
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
invitee,
|
||||
latestKey
|
||||
|
@ -103,14 +103,14 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
|
||||
// validate membership
|
||||
const membershipOrg = await MembershipOrg.findOne({
|
||||
user: req.user._id,
|
||||
organization: organizationId
|
||||
organization: new Types.ObjectId(organizationId)
|
||||
});
|
||||
|
||||
if (!membershipOrg) {
|
||||
throw new Error("Failed to validate organization membership");
|
||||
}
|
||||
|
||||
const plan = await EELicenseService.getPlan(organizationId);
|
||||
const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId));
|
||||
|
||||
const ssoConfig = await SSOConfig.findOne({
|
||||
organization: new Types.ObjectId(organizationId)
|
||||
|
@ -5,7 +5,7 @@ import * as bigintConversion from "bigint-conversion";
|
||||
import { BackupPrivateKey, LoginSRPDetail, User } from "../../models";
|
||||
import { clearTokens, createToken, sendMail } from "../../helpers";
|
||||
import { TokenService } from "../../services";
|
||||
import { AUTH_MODE_JWT, TOKEN_EMAIL_PASSWORD_RESET } from "../../variables";
|
||||
import { TOKEN_EMAIL_PASSWORD_RESET } from "../../variables";
|
||||
import { BadRequestError } from "../../utils/errors";
|
||||
import {
|
||||
getHttpsEnabled,
|
||||
@ -13,6 +13,7 @@ import {
|
||||
getJwtSignupSecret,
|
||||
getSiteURL
|
||||
} from "../../config";
|
||||
import { ActorType } from "../../ee/models";
|
||||
|
||||
/**
|
||||
* Password reset step 1: Send email verification link to email [email]
|
||||
@ -208,8 +209,7 @@ export const changePassword = async (req: Request, res: Response) => {
|
||||
);
|
||||
|
||||
if (
|
||||
req.authData.authMode === AUTH_MODE_JWT &&
|
||||
req.authData.authPayload instanceof User &&
|
||||
req.authData.actor.type === ActorType.USER &&
|
||||
req.authData.tokenVersionId
|
||||
) {
|
||||
await clearTokens(req.authData.tokenVersionId);
|
||||
|
@ -1,17 +1,49 @@
|
||||
import { Request, Response } from "express";
|
||||
import { validateMembership } from "../../helpers";
|
||||
import { isValidScope, validateMembership } from "../../helpers";
|
||||
import { ServiceTokenData } from "../../models";
|
||||
import Folder from "../../models/folder";
|
||||
import SecretImport from "../../models/secretImports";
|
||||
import { getAllImportedSecrets } from "../../services/SecretImportService";
|
||||
import { BadRequestError } from "../../utils/errors";
|
||||
import { getFolderWithPathFromId } from "../../services/FolderService";
|
||||
import { BadRequestError, ResourceNotFoundError,UnauthorizedRequestError } from "../../utils/errors";
|
||||
import { ADMIN, MEMBER } from "../../variables";
|
||||
import { EEAuditLogService } from "../../ee/services";
|
||||
import { EventType } from "../../ee/models";
|
||||
|
||||
export const createSecretImport = async (req: Request, res: Response) => {
|
||||
const { workspaceId, environment, folderId, secretImport } = req.body;
|
||||
|
||||
const folders = await Folder.findOne({
|
||||
workspace: workspaceId,
|
||||
environment
|
||||
}).lean();
|
||||
|
||||
if (!folders && folderId !== "root") {
|
||||
throw ResourceNotFoundError({
|
||||
message: "Failed to find folder"
|
||||
});
|
||||
}
|
||||
|
||||
let secretPath = "/";
|
||||
if (folders) {
|
||||
const { folderPath } = getFolderWithPathFromId(folders.nodes, folderId);
|
||||
secretPath = folderPath;
|
||||
}
|
||||
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||
// root check
|
||||
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, secretPath);
|
||||
if (!isValidScopeAccess) {
|
||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||
}
|
||||
}
|
||||
|
||||
const importSecDoc = await SecretImport.findOne({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
folderId
|
||||
});
|
||||
|
||||
const importToSecretPath = folders?getFolderWithPathFromId(folders.nodes, folderId).folderPath:"/";
|
||||
|
||||
if (!importSecDoc) {
|
||||
const doc = new SecretImport({
|
||||
@ -20,7 +52,25 @@ export const createSecretImport = async (req: Request, res: Response) => {
|
||||
folderId,
|
||||
imports: [{ environment: secretImport.environment, secretPath: secretImport.secretPath }]
|
||||
});
|
||||
|
||||
await doc.save();
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.CREATE_SECRET_IMPORT,
|
||||
metadata: {
|
||||
secretImportId: doc._id.toString(),
|
||||
folderId: doc.folderId.toString(),
|
||||
importFromEnvironment: secretImport.environment,
|
||||
importFromSecretPath: secretImport.secretPath,
|
||||
importToEnvironment: environment,
|
||||
importToSecretPath
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: doc.workspace
|
||||
}
|
||||
);
|
||||
return res.status(200).json({ message: "successfully created secret import" });
|
||||
}
|
||||
|
||||
@ -30,11 +80,30 @@ export const createSecretImport = async (req: Request, res: Response) => {
|
||||
if (doesImportExist) {
|
||||
throw BadRequestError({ message: "Secret import already exist" });
|
||||
}
|
||||
|
||||
importSecDoc.imports.push({
|
||||
environment: secretImport.environment,
|
||||
secretPath: secretImport.secretPath
|
||||
});
|
||||
await importSecDoc.save();
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.CREATE_SECRET_IMPORT,
|
||||
metadata: {
|
||||
secretImportId: importSecDoc._id.toString(),
|
||||
folderId: importSecDoc.folderId.toString(),
|
||||
importFromEnvironment: secretImport.environment,
|
||||
importFromSecretPath: secretImport.secretPath,
|
||||
importToEnvironment: environment,
|
||||
importToSecretPath
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: importSecDoc.workspace
|
||||
}
|
||||
);
|
||||
return res.status(200).json({ message: "successfully created secret import" });
|
||||
};
|
||||
|
||||
@ -48,14 +117,68 @@ export const updateSecretImport = async (req: Request, res: Response) => {
|
||||
throw BadRequestError({ message: "Import not found" });
|
||||
}
|
||||
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: importSecDoc.workspace,
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
});
|
||||
if (!(req.authData.authPayload instanceof ServiceTokenData)) {
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: importSecDoc.workspace,
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
});
|
||||
} else {
|
||||
// check for service token validity
|
||||
const folders = await Folder.findOne({
|
||||
workspace: importSecDoc.workspace,
|
||||
environment: importSecDoc.environment
|
||||
}).lean();
|
||||
|
||||
let secretPath = "/";
|
||||
if (folders) {
|
||||
const { folderPath } = getFolderWithPathFromId(folders.nodes, importSecDoc.folderId);
|
||||
secretPath = folderPath;
|
||||
}
|
||||
|
||||
const isValidScopeAccess = isValidScope(
|
||||
req.authData.authPayload,
|
||||
importSecDoc.environment,
|
||||
secretPath
|
||||
);
|
||||
if (!isValidScopeAccess) {
|
||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||
}
|
||||
}
|
||||
|
||||
const orderBefore = importSecDoc.imports;
|
||||
importSecDoc.imports = secretImports;
|
||||
|
||||
await importSecDoc.save();
|
||||
|
||||
const folders = await Folder.findOne({
|
||||
workspace: importSecDoc.workspace,
|
||||
environment: importSecDoc.environment,
|
||||
}).lean();
|
||||
|
||||
if (!folders) throw ResourceNotFoundError({
|
||||
message: "Failed to find folder"
|
||||
});
|
||||
|
||||
const importToSecretPath = folders?getFolderWithPathFromId(folders.nodes, importSecDoc.folderId).folderPath:"/";
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.UPDATE_SECRET_IMPORT,
|
||||
metadata: {
|
||||
importToEnvironment: importSecDoc.environment,
|
||||
importToSecretPath,
|
||||
secretImportId: importSecDoc._id.toString(),
|
||||
folderId: importSecDoc.folderId.toString(),
|
||||
orderBefore,
|
||||
orderAfter: secretImports
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: importSecDoc.workspace
|
||||
}
|
||||
);
|
||||
return res.status(200).json({ message: "successfully updated secret import" });
|
||||
};
|
||||
|
||||
@ -67,16 +190,69 @@ export const deleteSecretImport = async (req: Request, res: Response) => {
|
||||
throw BadRequestError({ message: "Import not found" });
|
||||
}
|
||||
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: importSecDoc.workspace,
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
});
|
||||
if (!(req.authData.authPayload instanceof ServiceTokenData)) {
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: importSecDoc.workspace,
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
});
|
||||
} else {
|
||||
// check for service token validity
|
||||
const folders = await Folder.findOne({
|
||||
workspace: importSecDoc.workspace,
|
||||
environment: importSecDoc.environment
|
||||
}).lean();
|
||||
|
||||
let secretPath = "/";
|
||||
if (folders) {
|
||||
const { folderPath } = getFolderWithPathFromId(folders.nodes, importSecDoc.folderId);
|
||||
secretPath = folderPath;
|
||||
}
|
||||
|
||||
const isValidScopeAccess = isValidScope(
|
||||
req.authData.authPayload,
|
||||
importSecDoc.environment,
|
||||
secretPath
|
||||
);
|
||||
if (!isValidScopeAccess) {
|
||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||
}
|
||||
}
|
||||
importSecDoc.imports = importSecDoc.imports.filter(
|
||||
({ environment, secretPath }) =>
|
||||
!(environment === secretImportEnv && secretPath === secretImportPath)
|
||||
);
|
||||
await importSecDoc.save();
|
||||
|
||||
const folders = await Folder.findOne({
|
||||
workspace: importSecDoc.workspace,
|
||||
environment: importSecDoc.environment,
|
||||
}).lean();
|
||||
|
||||
if (!folders) throw ResourceNotFoundError({
|
||||
message: "Failed to find folder"
|
||||
});
|
||||
|
||||
const importToSecretPath = folders?getFolderWithPathFromId(folders.nodes, importSecDoc.folderId).folderPath:"/";
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.DELETE_SECRET_IMPORT,
|
||||
metadata: {
|
||||
secretImportId: importSecDoc._id.toString(),
|
||||
folderId: importSecDoc.folderId.toString(),
|
||||
importFromEnvironment: secretImportEnv,
|
||||
importFromSecretPath: secretImportPath,
|
||||
importToEnvironment: importSecDoc.environment,
|
||||
importToSecretPath
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: importSecDoc.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).json({ message: "successfully delete secret import" });
|
||||
};
|
||||
|
||||
@ -92,6 +268,29 @@ export const getSecretImports = async (req: Request, res: Response) => {
|
||||
return res.status(200).json({ secretImport: {} });
|
||||
}
|
||||
|
||||
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||
// check for service token validity
|
||||
const folders = await Folder.findOne({
|
||||
workspace: importSecDoc.workspace,
|
||||
environment: importSecDoc.environment
|
||||
}).lean();
|
||||
|
||||
let secretPath = "/";
|
||||
if (folders) {
|
||||
const { folderPath } = getFolderWithPathFromId(folders.nodes, importSecDoc.folderId);
|
||||
secretPath = folderPath;
|
||||
}
|
||||
|
||||
const isValidScopeAccess = isValidScope(
|
||||
req.authData.authPayload,
|
||||
importSecDoc.environment,
|
||||
secretPath
|
||||
);
|
||||
if (!isValidScopeAccess) {
|
||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(200).json({ secretImport: importSecDoc });
|
||||
};
|
||||
|
||||
@ -111,6 +310,45 @@ export const getAllSecretsFromImport = async (req: Request, res: Response) => {
|
||||
return res.status(200).json({ secrets: [] });
|
||||
}
|
||||
|
||||
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||
// check for service token validity
|
||||
const folders = await Folder.findOne({
|
||||
workspace: importSecDoc.workspace,
|
||||
environment: importSecDoc.environment
|
||||
}).lean();
|
||||
|
||||
let secretPath = "/";
|
||||
if (folders) {
|
||||
const { folderPath } = getFolderWithPathFromId(folders.nodes, importSecDoc.folderId);
|
||||
secretPath = folderPath;
|
||||
}
|
||||
|
||||
const isValidScopeAccess = isValidScope(
|
||||
req.authData.authPayload,
|
||||
importSecDoc.environment,
|
||||
secretPath
|
||||
);
|
||||
if (!isValidScopeAccess) {
|
||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||
}
|
||||
}
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.GET_SECRET_IMPORTS,
|
||||
metadata: {
|
||||
environment,
|
||||
secretImportId: importSecDoc._id.toString(),
|
||||
folderId,
|
||||
numberOfImports: importSecDoc.imports.length
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: importSecDoc.workspace
|
||||
}
|
||||
);
|
||||
|
||||
const secrets = await getAllImportedSecrets(workspaceId, environment, folderId);
|
||||
return res.status(200).json({ secrets });
|
||||
};
|
||||
|
@ -1,39 +1,49 @@
|
||||
import { Request, Response } from "express";
|
||||
import { Secret } from "../../models";
|
||||
import { Types } from "mongoose";
|
||||
import { EventType, FolderVersion } from "../../ee/models";
|
||||
import { EEAuditLogService, EESecretService } from "../../ee/services";
|
||||
import { validateMembership } from "../../helpers/membership";
|
||||
import { isValidScope } from "../../helpers/secrets";
|
||||
import { Secret, ServiceTokenData } from "../../models";
|
||||
import Folder from "../../models/folder";
|
||||
import { BadRequestError } from "../../utils/errors";
|
||||
import {
|
||||
appendFolder,
|
||||
deleteFolderById,
|
||||
generateFolderId,
|
||||
getAllFolderIds,
|
||||
getFolderByPath,
|
||||
getFolderWithPathFromId,
|
||||
getParentFromFolderId,
|
||||
searchByFolderId,
|
||||
searchByFolderIdWithDir,
|
||||
validateFolderName,
|
||||
validateFolderName
|
||||
} from "../../services/FolderService";
|
||||
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
||||
import { ADMIN, MEMBER } from "../../variables";
|
||||
import { validateMembership } from "../../helpers/membership";
|
||||
import { FolderVersion } from "../../ee/models";
|
||||
import { EESecretService } from "../../ee/services";
|
||||
|
||||
// TODO
|
||||
// verify workspace id/environment
|
||||
export const createFolder = async (req: Request, res: Response) => {
|
||||
const { workspaceId, environment, folderName, parentFolderId } = req.body;
|
||||
if (!validateFolderName(folderName)) {
|
||||
throw BadRequestError({
|
||||
message: "Folder name cannot contain spaces. Only underscore and dashes",
|
||||
message: "Folder name cannot contain spaces. Only underscore and dashes"
|
||||
});
|
||||
}
|
||||
|
||||
const folders = await Folder.findOne({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
environment
|
||||
}).lean();
|
||||
|
||||
// space has no folders initialized
|
||||
|
||||
if (!folders) {
|
||||
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||
// root check
|
||||
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, "/");
|
||||
if (!isValidScopeAccess) {
|
||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||
}
|
||||
}
|
||||
|
||||
const id = generateFolderId();
|
||||
const folder = new Folder({
|
||||
workspace: workspaceId,
|
||||
@ -42,39 +52,93 @@ export const createFolder = async (req: Request, res: Response) => {
|
||||
id: "root",
|
||||
name: "root",
|
||||
version: 1,
|
||||
children: [{ id, name: folderName, children: [], version: 1 }],
|
||||
},
|
||||
children: [{ id, name: folderName, children: [], version: 1 }]
|
||||
}
|
||||
});
|
||||
await folder.save();
|
||||
const folderVersion = new FolderVersion({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
nodes: folder.nodes,
|
||||
nodes: folder.nodes
|
||||
});
|
||||
await folderVersion.save();
|
||||
await EESecretService.takeSecretSnapshot({
|
||||
workspaceId,
|
||||
environment,
|
||||
environment
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.CREATE_FOLDER,
|
||||
metadata: {
|
||||
environment,
|
||||
folderId: id,
|
||||
folderName,
|
||||
folderPath: `root/${folderName}`
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
}
|
||||
);
|
||||
|
||||
return res.json({ folder: { id, name: folderName } });
|
||||
}
|
||||
|
||||
const folder = appendFolder(folders.nodes, { folderName, parentFolderId });
|
||||
|
||||
await Folder.findByIdAndUpdate(folders._id, folders);
|
||||
|
||||
const { folder: parentFolder, folderPath: parentFolderPath } = getFolderWithPathFromId(
|
||||
folders.nodes,
|
||||
parentFolderId || "root"
|
||||
);
|
||||
|
||||
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||
// root check
|
||||
const isValidScopeAccess = isValidScope(
|
||||
req.authData.authPayload,
|
||||
environment,
|
||||
parentFolderPath
|
||||
);
|
||||
if (!isValidScopeAccess) {
|
||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||
}
|
||||
}
|
||||
|
||||
await Folder.findByIdAndUpdate(folders._id, folders);
|
||||
|
||||
const parentFolder = searchByFolderId(folders.nodes, parentFolderId);
|
||||
const folderVersion = new FolderVersion({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
nodes: parentFolder,
|
||||
nodes: parentFolder
|
||||
});
|
||||
await folderVersion.save();
|
||||
|
||||
await EESecretService.takeSecretSnapshot({
|
||||
workspaceId,
|
||||
environment,
|
||||
folderId: parentFolderId,
|
||||
folderId: parentFolderId
|
||||
});
|
||||
|
||||
const {folderPath} = getFolderWithPathFromId(folders.nodes, folder.id);
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.CREATE_FOLDER,
|
||||
metadata: {
|
||||
environment,
|
||||
folderId: folder.id,
|
||||
folderName,
|
||||
folderPath
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
}
|
||||
);
|
||||
|
||||
return res.json({ folder });
|
||||
};
|
||||
@ -82,28 +146,46 @@ export const createFolder = async (req: Request, res: Response) => {
|
||||
export const updateFolderById = async (req: Request, res: Response) => {
|
||||
const { folderId } = req.params;
|
||||
const { name, workspaceId, environment } = req.body;
|
||||
if (!validateFolderName(name)) {
|
||||
throw BadRequestError({
|
||||
message: "Folder name cannot contain spaces. Only underscore and dashes"
|
||||
});
|
||||
}
|
||||
|
||||
const folders = await Folder.findOne({ workspace: workspaceId, environment });
|
||||
if (!folders) {
|
||||
throw BadRequestError({ message: "The folder doesn't exist" });
|
||||
}
|
||||
|
||||
// check that user is a member of the workspace
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId,
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
});
|
||||
if (!(req.authData.authPayload instanceof ServiceTokenData)) {
|
||||
// check that user is a member of the workspace
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId,
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
});
|
||||
}
|
||||
|
||||
const parentFolder = getParentFromFolderId(folders.nodes, folderId);
|
||||
if (!parentFolder) {
|
||||
throw BadRequestError({ message: "The folder doesn't exist" });
|
||||
}
|
||||
const folder = parentFolder.children.find(({ id }) => id === folderId);
|
||||
|
||||
if (!folder) {
|
||||
throw BadRequestError({ message: "The folder doesn't exist" });
|
||||
}
|
||||
|
||||
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||
const { folderPath: secretPath } = getFolderWithPathFromId(folders.nodes, parentFolder.id);
|
||||
// root check
|
||||
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, secretPath);
|
||||
if (!isValidScopeAccess) {
|
||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||
}
|
||||
}
|
||||
|
||||
const oldFolderName = folder.name;
|
||||
parentFolder.version += 1;
|
||||
folder.name = name;
|
||||
|
||||
@ -111,19 +193,38 @@ export const updateFolderById = async (req: Request, res: Response) => {
|
||||
const folderVersion = new FolderVersion({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
nodes: parentFolder,
|
||||
nodes: parentFolder
|
||||
});
|
||||
await folderVersion.save();
|
||||
|
||||
await EESecretService.takeSecretSnapshot({
|
||||
workspaceId,
|
||||
environment,
|
||||
folderId: parentFolder.id,
|
||||
folderId: parentFolder.id
|
||||
});
|
||||
|
||||
const {folderPath} = getFolderWithPathFromId(folders.nodes, folder.id);
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.UPDATE_FOLDER,
|
||||
metadata: {
|
||||
environment,
|
||||
folderId: folder.id,
|
||||
oldFolderName,
|
||||
newFolderName: name,
|
||||
folderPath
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
}
|
||||
);
|
||||
|
||||
return res.json({
|
||||
message: "Successfully updated folder",
|
||||
folder: { name: folder.name, id: folder.id },
|
||||
folder: { name: folder.name, id: folder.id }
|
||||
});
|
||||
};
|
||||
|
||||
@ -136,12 +237,16 @@ export const deleteFolder = async (req: Request, res: Response) => {
|
||||
throw BadRequestError({ message: "The folder doesn't exist" });
|
||||
}
|
||||
|
||||
// check that user is a member of the workspace
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId,
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
});
|
||||
if (!(req.authData.authPayload instanceof ServiceTokenData)) {
|
||||
// check that user is a member of the workspace
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId,
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
});
|
||||
}
|
||||
|
||||
const {folderPath} = getFolderWithPathFromId(folders.nodes, folderId);
|
||||
|
||||
const delOp = deleteFolderById(folders.nodes, folderId);
|
||||
if (!delOp) {
|
||||
@ -149,6 +254,14 @@ export const deleteFolder = async (req: Request, res: Response) => {
|
||||
}
|
||||
const { deletedNode: delFolder, parent: parentFolder } = delOp;
|
||||
|
||||
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||
const { folderPath: secretPath } = getFolderWithPathFromId(folders.nodes, parentFolder.id);
|
||||
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, secretPath);
|
||||
if (!isValidScopeAccess) {
|
||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||
}
|
||||
}
|
||||
|
||||
parentFolder.version += 1;
|
||||
const delFolderIds = getAllFolderIds(delFolder);
|
||||
|
||||
@ -156,35 +269,50 @@ export const deleteFolder = async (req: Request, res: Response) => {
|
||||
const folderVersion = new FolderVersion({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
nodes: parentFolder,
|
||||
nodes: parentFolder
|
||||
});
|
||||
await folderVersion.save();
|
||||
if (delFolderIds.length) {
|
||||
await Secret.deleteMany({
|
||||
folder: { $in: delFolderIds.map(({ id }) => id) },
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
environment
|
||||
});
|
||||
}
|
||||
|
||||
await EESecretService.takeSecretSnapshot({
|
||||
workspaceId,
|
||||
environment,
|
||||
folderId: parentFolder.id,
|
||||
folderId: parentFolder.id
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.DELETE_FOLDER ,
|
||||
metadata: {
|
||||
environment,
|
||||
folderId,
|
||||
folderName: delFolder.name,
|
||||
folderPath
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
}
|
||||
);
|
||||
|
||||
res.send({ message: "successfully deleted folders", folders: delFolderIds });
|
||||
};
|
||||
|
||||
// TODO: validate workspace
|
||||
export const getFolders = async (req: Request, res: Response) => {
|
||||
const { workspaceId, environment, parentFolderId, parentFolderPath } =
|
||||
req.query as {
|
||||
workspaceId: string;
|
||||
environment: string;
|
||||
parentFolderId?: string;
|
||||
parentFolderPath?: string;
|
||||
};
|
||||
const { workspaceId, environment, parentFolderId, parentFolderPath } = req.query as {
|
||||
workspaceId: string;
|
||||
environment: string;
|
||||
parentFolderId?: string;
|
||||
parentFolderPath?: string;
|
||||
};
|
||||
|
||||
const folders = await Folder.findOne({ workspace: workspaceId, environment });
|
||||
if (!folders) {
|
||||
@ -192,16 +320,29 @@ export const getFolders = async (req: Request, res: Response) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// check that user is a member of the workspace
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId,
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
});
|
||||
if (!(req.authData.authPayload instanceof ServiceTokenData)) {
|
||||
// check that user is a member of the workspace
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId,
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
});
|
||||
}
|
||||
|
||||
// if instead of parentFolderId given a path like /folder1/folder2
|
||||
if (parentFolderPath) {
|
||||
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||
const isValidScopeAccess = isValidScope(
|
||||
req.authData.authPayload,
|
||||
environment,
|
||||
parentFolderPath
|
||||
);
|
||||
if (!isValidScopeAccess) {
|
||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||
}
|
||||
}
|
||||
const folder = getFolderByPath(folders.nodes, parentFolderPath);
|
||||
|
||||
if (!folder) {
|
||||
res.send({ folders: [], dir: [] });
|
||||
return;
|
||||
@ -209,27 +350,36 @@ export const getFolders = async (req: Request, res: Response) => {
|
||||
// dir is not needed at present as this is only used in overview section of secrets
|
||||
res.send({
|
||||
folders: folder.children.map(({ id, name }) => ({ id, name })),
|
||||
dir: [{ name: folder.name, id: folder.id }],
|
||||
dir: [{ name: folder.name, id: folder.id }]
|
||||
});
|
||||
}
|
||||
|
||||
if (!parentFolderId) {
|
||||
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, "/");
|
||||
if (!isValidScopeAccess) {
|
||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||
}
|
||||
}
|
||||
|
||||
const rootFolders = folders.nodes.children.map(({ id, name }) => ({
|
||||
id,
|
||||
name,
|
||||
name
|
||||
}));
|
||||
res.send({ folders: rootFolders });
|
||||
return;
|
||||
}
|
||||
|
||||
const folderBySearch = searchByFolderIdWithDir(folders.nodes, parentFolderId);
|
||||
if (!folderBySearch) {
|
||||
throw BadRequestError({ message: "The folder doesn't exist" });
|
||||
const { folder, folderPath, dir } = getFolderWithPathFromId(folders.nodes, parentFolderId);
|
||||
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||
const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, folderPath);
|
||||
if (!isValidScopeAccess) {
|
||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||
}
|
||||
}
|
||||
const { folder, dir } = folderBySearch;
|
||||
|
||||
res.send({
|
||||
folders: folder.children.map(({ id, name }) => ({ id, name })),
|
||||
dir,
|
||||
dir
|
||||
});
|
||||
};
|
||||
|
@ -4,7 +4,9 @@ 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 { BadRequestError, ResourceNotFoundError } from "../../utils/errors";
|
||||
import { EEAuditLogService } from "../../ee/services";
|
||||
import { EventType } from "../../ee/models";
|
||||
import { ADMIN, ALGORITHM_AES_256_GCM, ENCODING_SCHEME_BASE64, MEMBER } from "../../variables";
|
||||
|
||||
export const createWebhook = async (req: Request, res: Response) => {
|
||||
@ -27,6 +29,23 @@ export const createWebhook = async (req: Request, res: Response) => {
|
||||
}
|
||||
|
||||
await webhook.save();
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.CREATE_WEBHOOK,
|
||||
metadata: {
|
||||
webhookId: webhook._id.toString(),
|
||||
environment,
|
||||
secretPath,
|
||||
webhookUrl,
|
||||
isDisabled: false
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
webhook,
|
||||
@ -54,6 +73,23 @@ export const updateWebhook = async (req: Request, res: Response) => {
|
||||
}
|
||||
await webhook.save();
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.UPDATE_WEBHOOK_STATUS,
|
||||
metadata: {
|
||||
webhookId: webhook._id.toString(),
|
||||
environment: webhook.environment,
|
||||
secretPath: webhook.secretPath,
|
||||
webhookUrl: webhook.url,
|
||||
isDisabled
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: webhook.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
webhook,
|
||||
message: "successfully updated webhook"
|
||||
@ -62,9 +98,10 @@ export const updateWebhook = async (req: Request, res: Response) => {
|
||||
|
||||
export const deleteWebhook = async (req: Request, res: Response) => {
|
||||
const { webhookId } = req.params;
|
||||
const webhook = await Webhook.findById(webhookId);
|
||||
let webhook = await Webhook.findById(webhookId);
|
||||
|
||||
if (!webhook) {
|
||||
throw BadRequestError({ message: "Webhook not found!!" });
|
||||
throw ResourceNotFoundError({ message: "Webhook not found!!" });
|
||||
}
|
||||
|
||||
await validateMembership({
|
||||
@ -72,8 +109,29 @@ export const deleteWebhook = async (req: Request, res: Response) => {
|
||||
workspaceId: webhook.workspace,
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
});
|
||||
|
||||
webhook = await Webhook.findByIdAndDelete(webhookId);
|
||||
|
||||
await webhook.deleteOne();
|
||||
if (!webhook) {
|
||||
throw ResourceNotFoundError({ message: "Webhook not found!!" });
|
||||
}
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.DELETE_WEBHOOK,
|
||||
metadata: {
|
||||
webhookId: webhook._id.toString(),
|
||||
environment: webhook.environment,
|
||||
secretPath: webhook.secretPath,
|
||||
webhookUrl: webhook.url,
|
||||
isDisabled: webhook.isDisabled
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: webhook.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
message: "successfully removed webhook"
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Types } from "mongoose";
|
||||
import { Request, Response } from "express";
|
||||
import {
|
||||
IUser,
|
||||
@ -108,14 +109,14 @@ export const createWorkspace = async (req: Request, res: Response) => {
|
||||
// validate organization membership
|
||||
const membershipOrg = await MembershipOrg.findOne({
|
||||
user: req.user._id,
|
||||
organization: organizationId,
|
||||
organization: new Types.ObjectId(organizationId),
|
||||
});
|
||||
|
||||
if (!membershipOrg) {
|
||||
throw new Error("Failed to validate organization membership");
|
||||
}
|
||||
|
||||
const plan = await EELicenseService.getPlan(organizationId);
|
||||
const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId));
|
||||
|
||||
if (plan.workspaceLimit !== null) {
|
||||
// case: limit imposed on number of workspaces allowed
|
||||
@ -134,7 +135,7 @@ export const createWorkspace = async (req: Request, res: Response) => {
|
||||
// create workspace and add user as member
|
||||
const workspace = await create({
|
||||
name: workspaceName,
|
||||
organizationId,
|
||||
organizationId: new Types.ObjectId(organizationId),
|
||||
});
|
||||
|
||||
await addMemberships({
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
ACTION_LOGIN,
|
||||
TOKEN_EMAIL_MFA,
|
||||
} from "../../variables";
|
||||
import { getChannelFromUserAgent } from "../../utils/posthog"; // TODO: move this
|
||||
import { getUserAgentType } from "../../utils/posthog"; // TODO: move this
|
||||
import {
|
||||
getHttpsEnabled,
|
||||
getJwtMfaLifetime,
|
||||
@ -203,7 +203,7 @@ export const login2 = async (req: Request, res: Response) => {
|
||||
loginAction && await EELogService.createLog({
|
||||
userId: user._id,
|
||||
actions: [loginAction],
|
||||
channel: getChannelFromUserAgent(req.headers["user-agent"]),
|
||||
channel: getUserAgentType(req.headers["user-agent"]),
|
||||
ipAddress: req.ip,
|
||||
});
|
||||
|
||||
@ -336,7 +336,7 @@ export const verifyMfaToken = async (req: Request, res: Response) => {
|
||||
loginAction && await EELogService.createLog({
|
||||
userId: user._id,
|
||||
actions: [loginAction],
|
||||
channel: getChannelFromUserAgent(req.headers["user-agent"]),
|
||||
channel: getUserAgentType(req.headers["user-agent"]),
|
||||
ipAddress: req.realIP,
|
||||
});
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Request, Response } from "express";
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
Integration,
|
||||
Membership,
|
||||
@ -7,8 +8,8 @@ import {
|
||||
ServiceTokenData,
|
||||
Workspace,
|
||||
} from "../../models";
|
||||
import { SecretVersion } from "../../ee/models";
|
||||
import { EELicenseService } from "../../ee/services";
|
||||
import { EventType, SecretVersion } from "../../ee/models";
|
||||
import { EEAuditLogService, EELicenseService } from "../../ee/services";
|
||||
import { BadRequestError, WorkspaceNotFoundError } from "../../utils/errors";
|
||||
import _ from "lodash";
|
||||
import { PERMISSION_READ_SECRETS, PERMISSION_WRITE_SECRETS } from "../../variables";
|
||||
@ -30,7 +31,7 @@ export const createWorkspaceEnvironment = async (
|
||||
|
||||
if (!workspace) throw WorkspaceNotFoundError();
|
||||
|
||||
const plan = await EELicenseService.getPlan(workspace.organization.toString());
|
||||
const plan = await EELicenseService.getPlan(workspace.organization);
|
||||
|
||||
if (plan.environmentLimit !== null) {
|
||||
// case: limit imposed on number of environments allowed
|
||||
@ -58,7 +59,21 @@ export const createWorkspaceEnvironment = async (
|
||||
});
|
||||
await workspace.save();
|
||||
|
||||
await EELicenseService.refreshPlan(workspace.organization.toString(), workspaceId);
|
||||
await EELicenseService.refreshPlan(workspace.organization, new Types.ObjectId(workspaceId));
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.CREATE_ENVIRONMENT,
|
||||
metadata: {
|
||||
name: environmentName,
|
||||
slug: environmentSlug
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: workspace._id
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
message: "Successfully created new environment",
|
||||
@ -109,6 +124,8 @@ export const renameWorkspaceEnvironment = async (
|
||||
if (envIndex === -1) {
|
||||
throw new Error("Invalid environment given");
|
||||
}
|
||||
|
||||
const oldEnvironment = workspace.environments[envIndex];
|
||||
|
||||
workspace.environments[envIndex].name = environmentName;
|
||||
workspace.environments[envIndex].slug = environmentSlug.toLowerCase();
|
||||
@ -141,8 +158,23 @@ export const renameWorkspaceEnvironment = async (
|
||||
},
|
||||
{ $set: { "deniedPermissions.$[element].environmentSlug": environmentSlug } },
|
||||
{ arrayFilters: [{ "element.environmentSlug": oldEnvironmentSlug }] }
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.UPDATE_ENVIRONMENT,
|
||||
metadata: {
|
||||
oldName: oldEnvironment.name,
|
||||
newName: environmentName,
|
||||
oldSlug: oldEnvironment.slug,
|
||||
newSlug: environmentSlug.toLowerCase()
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: workspace._id
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
message: "Successfully update environment",
|
||||
@ -178,6 +210,8 @@ export const deleteWorkspaceEnvironment = async (
|
||||
if (envIndex === -1) {
|
||||
throw new Error("Invalid environment given");
|
||||
}
|
||||
|
||||
const oldEnvironment = workspace.environments[envIndex];
|
||||
|
||||
workspace.environments.splice(envIndex, 1);
|
||||
await workspace.save();
|
||||
@ -215,7 +249,21 @@ export const deleteWorkspaceEnvironment = async (
|
||||
{ $pull: { deniedPermissions: { environmentSlug: environmentSlug } } }
|
||||
);
|
||||
|
||||
await EELicenseService.refreshPlan(workspace.organization.toString(), workspaceId);
|
||||
await EELicenseService.refreshPlan(workspace.organization, new Types.ObjectId(workspaceId));
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.DELETE_ENVIRONMENT,
|
||||
metadata: {
|
||||
name: oldEnvironment.name,
|
||||
slug: oldEnvironment.slug
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: workspace._id
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
message: "Successfully deleted environment",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Types } from "mongoose";
|
||||
import { Request, Response } from "express";
|
||||
import { ISecret, Secret, ServiceTokenData } from "../../models";
|
||||
import { IAction, SecretVersion } from "../../ee/models";
|
||||
import { IAction, SecretVersion, EventType, AuditLog } from "../../ee/models";
|
||||
import {
|
||||
ACTION_ADD_SECRETS,
|
||||
ACTION_DELETE_SECRETS,
|
||||
@ -14,9 +14,9 @@ import {
|
||||
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
||||
import { EventService } from "../../services";
|
||||
import { eventPushSecrets } from "../../events";
|
||||
import { EELogService, EESecretService } from "../../ee/services";
|
||||
import { EELogService, EESecretService, EEAuditLogService } from "../../ee/services";
|
||||
import { SecretService, TelemetryService } from "../../services";
|
||||
import { getChannelFromUserAgent } from "../../utils/posthog";
|
||||
import { getUserAgentType } from "../../utils/posthog";
|
||||
import { PERMISSION_WRITE_SECRETS } from "../../variables";
|
||||
import {
|
||||
userHasNoAbility,
|
||||
@ -44,7 +44,7 @@ import { getAllImportedSecrets } from "../../services/SecretImportService";
|
||||
* @param res
|
||||
*/
|
||||
export const batchSecrets = async (req: Request, res: Response) => {
|
||||
const channel = getChannelFromUserAgent(req.headers["user-agent"]);
|
||||
const channel = getUserAgentType(req.headers["user-agent"]);
|
||||
const postHogClient = await TelemetryService.getPostHogClient();
|
||||
|
||||
const {
|
||||
@ -56,12 +56,13 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
||||
environment: string;
|
||||
requests: BatchSecretRequest[];
|
||||
} = req.body;
|
||||
|
||||
let secretPath = req.body.secretPath as string;
|
||||
let folderId = req.body.folderId as string;
|
||||
|
||||
|
||||
const createSecrets: BatchSecret[] = [];
|
||||
const updateSecrets: BatchSecret[] = [];
|
||||
const deleteSecrets: Types.ObjectId[] = [];
|
||||
const deleteSecrets: { _id: Types.ObjectId, secretName: string; }[] = [];
|
||||
const actions: IAction[] = [];
|
||||
|
||||
// get secret blind index salt
|
||||
@ -133,7 +134,7 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
||||
});
|
||||
break;
|
||||
case "DELETE":
|
||||
deleteSecrets.push(new Types.ObjectId(request.secret._id));
|
||||
deleteSecrets.push({ _id: new Types.ObjectId(request.secret._id), secretName: request.secret.secretName });
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -153,7 +154,31 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
||||
};
|
||||
})
|
||||
});
|
||||
|
||||
const auditLogs = await Promise.all(
|
||||
createdSecrets.map((secret, index) => {
|
||||
return EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.CREATE_SECRET,
|
||||
metadata: {
|
||||
environment: secret.environment,
|
||||
secretPath: secretPath ?? "/",
|
||||
secretId: secret._id.toString(),
|
||||
secretKey: createSecrets[index].secretName,
|
||||
secretVersion: secret.version
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: secret.workspace
|
||||
},
|
||||
false
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
await AuditLog.insertMany(auditLogs);
|
||||
|
||||
const addAction = (await EELogService.createAction({
|
||||
name: ACTION_ADD_SECRETS,
|
||||
userId: req.user?._id,
|
||||
@ -252,6 +277,30 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
||||
$in: updateSecrets.map((u) => new Types.ObjectId(u._id))
|
||||
}
|
||||
});
|
||||
|
||||
const auditLogs = await Promise.all(
|
||||
updateSecrets.map((secret) => {
|
||||
return EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.UPDATE_SECRET,
|
||||
metadata: {
|
||||
environment,
|
||||
secretPath: secretPath ?? "/",
|
||||
secretId: secret._id.toString(),
|
||||
secretKey: secret.secretName,
|
||||
secretVersion: listedSecretsObj[secret._id.toString()].version
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
},
|
||||
false
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
await AuditLog.insertMany(auditLogs);
|
||||
|
||||
const updateAction = (await EELogService.createAction({
|
||||
name: ACTION_UPDATE_SECRETS,
|
||||
@ -279,21 +328,60 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
||||
|
||||
// handle delete secrets
|
||||
if (deleteSecrets.length > 0) {
|
||||
const deleteSecretIds: Types.ObjectId[] = deleteSecrets.map((s) => s._id);
|
||||
|
||||
const deletedSecretsObj = (await Secret.find({
|
||||
_id: {
|
||||
$in: deleteSecretIds
|
||||
}
|
||||
}))
|
||||
.reduce(
|
||||
(obj: any, secret: ISecret) => ({
|
||||
...obj,
|
||||
[secret._id.toString()]: secret
|
||||
}),
|
||||
{}
|
||||
);
|
||||
|
||||
await Secret.deleteMany({
|
||||
_id: {
|
||||
$in: deleteSecrets
|
||||
$in: deleteSecretIds
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
await EESecretService.markDeletedSecretVersions({
|
||||
secretIds: deleteSecrets
|
||||
secretIds: deleteSecretIds
|
||||
});
|
||||
|
||||
const auditLogs = await Promise.all(
|
||||
deleteSecrets.map((secret) => {
|
||||
return EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.DELETE_SECRET,
|
||||
metadata: {
|
||||
environment,
|
||||
secretPath: secretPath ?? "/",
|
||||
secretId: secret._id.toString(),
|
||||
secretKey: secret.secretName,
|
||||
secretVersion: deletedSecretsObj[secret._id.toString()].version
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
},
|
||||
false
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
await AuditLog.insertMany(auditLogs);
|
||||
|
||||
const deleteAction = (await EELogService.createAction({
|
||||
name: ACTION_DELETE_SECRETS,
|
||||
userId: req.user._id,
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
secretIds: deleteSecrets
|
||||
secretIds: deleteSecretIds
|
||||
})) as IAction;
|
||||
actions.push(deleteAction);
|
||||
|
||||
@ -351,7 +439,7 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
||||
}
|
||||
|
||||
if (deleteSecrets.length > 0) {
|
||||
resObj["deletedSecrets"] = deleteSecrets.map((d) => d.toString());
|
||||
resObj["deletedSecrets"] = deleteSecrets.map((d) => d._id.toString());
|
||||
}
|
||||
|
||||
return res.status(200).send(resObj);
|
||||
@ -416,7 +504,7 @@ export const createSecrets = async (req: Request, res: Response) => {
|
||||
}
|
||||
*/
|
||||
|
||||
const channel = getChannelFromUserAgent(req.headers["user-agent"]);
|
||||
const channel = getUserAgentType(req.headers["user-agent"]);
|
||||
const {
|
||||
workspaceId,
|
||||
environment,
|
||||
@ -697,10 +785,16 @@ export const getSecrets = async (req: Request, res: Response) => {
|
||||
const environment = req.query.environment as string;
|
||||
|
||||
const folders = await Folder.findOne({ workspace: workspaceId, environment });
|
||||
if ((!folders && folderId && folderId !== "root") || (!folders && secretPath)) {
|
||||
|
||||
if (
|
||||
// if no folders and asking for a non root folder id or non root secret path
|
||||
(!folders && folderId && folderId !== "root") ||
|
||||
(!folders && secretPath && secretPath !== "/")
|
||||
) {
|
||||
res.send({ secrets: [] });
|
||||
return;
|
||||
}
|
||||
|
||||
if (folders && folderId !== "root") {
|
||||
const folder = searchByFolderId(folders.nodes, folderId as string);
|
||||
if (!folder) {
|
||||
@ -834,7 +928,7 @@ export const getSecrets = async (req: Request, res: Response) => {
|
||||
importedSecrets = await getAllImportedSecrets(workspaceId, environment, folderId as string);
|
||||
}
|
||||
|
||||
const channel = getChannelFromUserAgent(req.headers["user-agent"]);
|
||||
const channel = getUserAgentType(req.headers["user-agent"]);
|
||||
|
||||
const readAction = await EELogService.createAction({
|
||||
name: ACTION_READ_SECRETS,
|
||||
@ -855,6 +949,21 @@ export const getSecrets = async (req: Request, res: Response) => {
|
||||
channel,
|
||||
ipAddress: req.realIP
|
||||
}));
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.GET_SECRETS,
|
||||
metadata: {
|
||||
environment,
|
||||
secretPath: secretPath as string,
|
||||
numberOfSecrets: secrets.length
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: new Types.ObjectId(workspaceId as string)
|
||||
}
|
||||
);
|
||||
|
||||
const postHogClient = await TelemetryService.getPostHogClient();
|
||||
if (postHogClient) {
|
||||
@ -1170,7 +1279,7 @@ export const deleteSecrets = async (req: Request, res: Response) => {
|
||||
}
|
||||
*/
|
||||
|
||||
const channel = getChannelFromUserAgent(req.headers["user-agent"]);
|
||||
const channel = getUserAgentType(req.headers["user-agent"]);
|
||||
const toDelete = req.secrets.map((s: any) => s._id);
|
||||
|
||||
await Secret.deleteMany({
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { Request, Response } from "express";
|
||||
import crypto from "crypto";
|
||||
import bcrypt from "bcrypt";
|
||||
import { ServiceAccount, ServiceTokenData, User } from "../../models";
|
||||
import { AUTH_MODE_JWT, AUTH_MODE_SERVICE_ACCOUNT } from "../../variables";
|
||||
import { ServiceTokenData } from "../../models";
|
||||
import { getSaltRounds } from "../../config";
|
||||
import { BadRequestError } from "../../utils/errors";
|
||||
import { ActorType, EventType } from "../../ee/models";
|
||||
import { EEAuditLogService } from "../../ee/services";
|
||||
|
||||
/**
|
||||
* Return service token data associated with service token on request
|
||||
@ -73,24 +74,16 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
|
||||
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);
|
||||
}
|
||||
|
||||
let user, serviceAccount;
|
||||
|
||||
if (req.authData.authMode === AUTH_MODE_JWT && req.authData.authPayload instanceof User) {
|
||||
let user;
|
||||
|
||||
if (req.authData.actor.type === ActorType.USER) {
|
||||
user = req.authData.authPayload._id;
|
||||
}
|
||||
|
||||
if (
|
||||
req.authData.authMode === AUTH_MODE_SERVICE_ACCOUNT &&
|
||||
req.authData.authPayload instanceof ServiceAccount
|
||||
) {
|
||||
serviceAccount = req.authData.authPayload._id;
|
||||
}
|
||||
|
||||
serviceTokenData = await new ServiceTokenData({
|
||||
name,
|
||||
workspace: workspaceId,
|
||||
user,
|
||||
serviceAccount,
|
||||
scopes,
|
||||
lastUsed: new Date(),
|
||||
expiresAt,
|
||||
@ -107,6 +100,20 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
|
||||
if (!serviceTokenData) throw new Error("Failed to find service token data");
|
||||
|
||||
const serviceToken = `st.${serviceTokenData._id.toString()}.${secret}`;
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.CREATE_SERVICE_TOKEN,
|
||||
metadata: {
|
||||
name,
|
||||
scopes
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
serviceToken,
|
||||
@ -124,6 +131,24 @@ export const deleteServiceTokenData = async (req: Request, res: Response) => {
|
||||
const { serviceTokenDataId } = req.params;
|
||||
|
||||
const serviceTokenData = await ServiceTokenData.findByIdAndDelete(serviceTokenDataId);
|
||||
|
||||
if (!serviceTokenData) return res.status(200).send({
|
||||
message: "Failed to delete service token"
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.DELETE_SERVICE_TOKEN,
|
||||
metadata: {
|
||||
name: serviceTokenData.name,
|
||||
scopes: serviceTokenData?.scopes
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: serviceTokenData.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
serviceTokenData
|
||||
|
@ -9,6 +9,8 @@ import {
|
||||
import { pushKeys } from "../../helpers/key";
|
||||
import { EventService, TelemetryService } from "../../services";
|
||||
import { eventPushSecrets } from "../../events";
|
||||
import { EEAuditLogService } from "../../ee/services";
|
||||
import { EventType } from "../../ee/models";
|
||||
|
||||
interface V2PushSecret {
|
||||
type: string; // personal or shared
|
||||
@ -180,16 +182,30 @@ export const getWorkspaceKey = async (req: Request, res: Response) => {
|
||||
}
|
||||
*/
|
||||
const { workspaceId } = req.params;
|
||||
|
||||
|
||||
const key = await Key.findOne({
|
||||
workspace: workspaceId,
|
||||
receiver: req.user._id
|
||||
}).populate("sender", "+publicKey");
|
||||
|
||||
if (!key) throw new Error("Failed to find workspace key");
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.GET_WORKSPACE_KEY,
|
||||
metadata: {
|
||||
keyId: key._id.toString()
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).json(key);
|
||||
};
|
||||
|
||||
export const getWorkspaceServiceTokenData = async (req: Request, res: Response) => {
|
||||
const { workspaceId } = req.params;
|
||||
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
ACTION_LOGIN,
|
||||
TOKEN_EMAIL_MFA,
|
||||
} from "../../variables";
|
||||
import { getChannelFromUserAgent } from "../../utils/posthog"; // TODO: move this
|
||||
import { getUserAgentType } from "../../utils/posthog"; // TODO: move this
|
||||
import {
|
||||
getHttpsEnabled,
|
||||
getJwtMfaLifetime,
|
||||
@ -241,7 +241,7 @@ export const login2 = async (req: Request, res: Response) => {
|
||||
loginAction && await EELogService.createLog({
|
||||
userId: user._id,
|
||||
actions: [loginAction],
|
||||
channel: getChannelFromUserAgent(req.headers["user-agent"]),
|
||||
channel: getUserAgentType(req.headers["user-agent"]),
|
||||
ipAddress: req.realIP,
|
||||
});
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Types } from "mongoose";
|
||||
import { Request, Response } from "express";
|
||||
import { getLicenseServerUrl } from "../../../config";
|
||||
import { licenseServerKeyRequest } from "../../../config/request";
|
||||
@ -20,7 +21,7 @@ export const getOrganizationPlan = async (req: Request, res: Response) => {
|
||||
const { organizationId } = req.params;
|
||||
const workspaceId = req.query.workspaceId as string;
|
||||
|
||||
const plan = await EELicenseService.getPlan(organizationId, workspaceId);
|
||||
const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId), new Types.ObjectId(workspaceId));
|
||||
|
||||
return res.status(200).send({
|
||||
plan,
|
||||
@ -44,7 +45,7 @@ export const startOrganizationTrial = async (req: Request, res: Response) => {
|
||||
}
|
||||
);
|
||||
|
||||
EELicenseService.delPlan(organizationId);
|
||||
EELicenseService.delPlan(new Types.ObjectId(organizationId));
|
||||
|
||||
return res.status(200).send({
|
||||
url
|
||||
|
@ -59,7 +59,7 @@ export const updateSSOConfig = async (req: Request, res: Response) => {
|
||||
cert,
|
||||
} = req.body;
|
||||
|
||||
const plan = await EELicenseService.getPlan(organizationId);
|
||||
const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId));
|
||||
|
||||
if (!plan.samlSSO) return res.status(400).send({
|
||||
message: "Failed to update SAML SSO configuration due to plan restriction. Upgrade plan to update SSO configuration."
|
||||
@ -194,7 +194,7 @@ export const createSSOConfig = async (req: Request, res: Response) => {
|
||||
cert
|
||||
} = req.body;
|
||||
|
||||
const plan = await EELicenseService.getPlan(organizationId);
|
||||
const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId));
|
||||
|
||||
if (!plan.samlSSO) return res.status(400).send({
|
||||
message: "Failed to create SAML SSO configuration due to plan restriction. Upgrade plan to add SSO configuration."
|
||||
|
@ -8,6 +8,6 @@ import { Request, Response } from "express";
|
||||
*/
|
||||
export const getMyIp = (req: Request, res: Response) => {
|
||||
return res.status(200).send({
|
||||
ip: req.authData.authIP
|
||||
ip: req.authData.ipAddress
|
||||
});
|
||||
}
|
@ -1,21 +1,26 @@
|
||||
import { Request, Response } from "express";
|
||||
import { PipelineStage, Types } from "mongoose";
|
||||
import { Secret } from "../../../models";
|
||||
import { Membership, Secret, ServiceTokenData, User } from "../../../models";
|
||||
import {
|
||||
ActorType,
|
||||
AuditLog,
|
||||
EventType,
|
||||
FolderVersion,
|
||||
IPType,
|
||||
ISecretVersion,
|
||||
Log,
|
||||
SecretSnapshot,
|
||||
SecretVersion,
|
||||
ServiceActor,
|
||||
TFolderRootVersionSchema,
|
||||
TrustedIP
|
||||
TrustedIP,
|
||||
UserActor
|
||||
} from "../../models";
|
||||
import { EESecretService } from "../../services";
|
||||
import { getLatestSecretVersionIds } from "../../helpers/secretVersion";
|
||||
import Folder, { TFolderSchema } from "../../../models/folder";
|
||||
import { searchByFolderId } from "../../../services/FolderService";
|
||||
import { EELicenseService } from "../../services";
|
||||
import { EEAuditLogService, EELicenseService } from "../../services";
|
||||
import { extractIPDetails, isValidIpOrCidr } from "../../../utils/ip";
|
||||
|
||||
/**
|
||||
@ -593,6 +598,101 @@ export const getWorkspaceLogs = async (req: Request, res: Response) => {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Return audit logs for workspace with id [workspaceId]
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
export const getWorkspaceAuditLogs = async (req: Request, res: Response) => {
|
||||
const { workspaceId } = req.params;
|
||||
const eventType = req.query.eventType;
|
||||
const userAgentType = req.query.userAgentType;
|
||||
const actor = req.query.actor as string | undefined;
|
||||
const offset: number = parseInt(req.query.offset as string);
|
||||
const limit: number = parseInt(req.query.limit as string);
|
||||
|
||||
const startDate = req.query.startDate as string;
|
||||
const endDate = req.query.endDate as string;
|
||||
|
||||
const query = {
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
...(eventType ? {
|
||||
"event.type": eventType
|
||||
} : {}),
|
||||
...(userAgentType ? {
|
||||
userAgentType
|
||||
} : {}),
|
||||
...(actor ? {
|
||||
"actor.type": actor.split("-", 2)[0],
|
||||
...(actor.split("-", 2)[0] === ActorType.USER ? {
|
||||
"actor.metadata.userId": actor.split("-", 2)[1]
|
||||
} : {
|
||||
"actor.metadata.serviceId": actor.split("-", 2)[1]
|
||||
})
|
||||
} : {}),
|
||||
...(startDate || endDate ? {
|
||||
createdAt: {
|
||||
...(startDate && { $gte: new Date(startDate) }),
|
||||
...(endDate && { $lte: new Date(endDate) })
|
||||
}
|
||||
} : {})
|
||||
}
|
||||
|
||||
const auditLogs = await AuditLog.find(query)
|
||||
.sort({ createdAt: -1 })
|
||||
.skip(offset)
|
||||
.limit(limit);
|
||||
|
||||
const totalCount = await AuditLog.countDocuments(query);
|
||||
|
||||
return res.status(200).send({
|
||||
auditLogs,
|
||||
totalCount
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return audit log actor filter options for workspace with id [workspaceId]
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
export const getWorkspaceAuditLogActorFilterOpts = async (req: Request, res: Response) => {
|
||||
const { workspaceId } = req.params;
|
||||
|
||||
const userIds = await Membership.distinct("user", {
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
const userActors: UserActor[] = (await User.find({
|
||||
_id: {
|
||||
$in: userIds
|
||||
}
|
||||
})
|
||||
.select("email"))
|
||||
.map((user) => ({
|
||||
type: ActorType.USER,
|
||||
metadata: {
|
||||
userId: user._id.toString(),
|
||||
email: user.email
|
||||
}
|
||||
}));
|
||||
|
||||
const serviceActors: ServiceActor[] = (await ServiceTokenData.find({
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
})
|
||||
.select("name"))
|
||||
.map((serviceTokenData) => ({
|
||||
type: ActorType.SERVICE,
|
||||
metadata: {
|
||||
serviceId: serviceTokenData._id.toString(),
|
||||
name: serviceTokenData.name
|
||||
}
|
||||
}));
|
||||
|
||||
return res.status(200).send({
|
||||
actors: [...userActors, ...serviceActors]
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return trusted ips for workspace with id [workspaceId]
|
||||
* @param req
|
||||
@ -623,7 +723,7 @@ export const addWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
isActive
|
||||
} = req.body;
|
||||
|
||||
const plan = await EELicenseService.getPlan(req.workspace.organization.toString());
|
||||
const plan = await EELicenseService.getPlan(req.workspace.organization);
|
||||
|
||||
if (!plan.ipAllowlisting) return res.status(400).send({
|
||||
message: "Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range."
|
||||
@ -645,6 +745,21 @@ export const addWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
isActive,
|
||||
comment,
|
||||
}).save();
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.ADD_TRUSTED_IP,
|
||||
metadata: {
|
||||
trustedIpId: trustedIp._id.toString(),
|
||||
ipAddress: trustedIp.ipAddress,
|
||||
prefix: trustedIp.prefix
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: trustedIp.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
trustedIp
|
||||
@ -663,7 +778,7 @@ export const updateWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
comment
|
||||
} = req.body;
|
||||
|
||||
const plan = await EELicenseService.getPlan(req.workspace.organization.toString());
|
||||
const plan = await EELicenseService.getPlan(req.workspace.organization);
|
||||
|
||||
if (!plan.ipAllowlisting) return res.status(400).send({
|
||||
message: "Failed to update IP access range due to plan restriction. Upgrade plan to update IP access range."
|
||||
@ -708,6 +823,25 @@ export const updateWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
}
|
||||
);
|
||||
|
||||
if (!trustedIp) return res.status(400).send({
|
||||
message: "Failed to update trusted IP"
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.UPDATE_TRUSTED_IP,
|
||||
metadata: {
|
||||
trustedIpId: trustedIp._id.toString(),
|
||||
ipAddress: trustedIp.ipAddress,
|
||||
prefix: trustedIp.prefix
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: trustedIp.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
trustedIp
|
||||
});
|
||||
@ -721,7 +855,7 @@ export const updateWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
export const deleteWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
const { workspaceId, trustedIpId } = req.params;
|
||||
|
||||
const plan = await EELicenseService.getPlan(req.workspace.organization.toString());
|
||||
const plan = await EELicenseService.getPlan(req.workspace.organization);
|
||||
|
||||
if (!plan.ipAllowlisting) return res.status(400).send({
|
||||
message: "Failed to delete IP access range due to plan restriction. Upgrade plan to delete IP access range."
|
||||
@ -731,6 +865,25 @@ export const deleteWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
||||
_id: new Types.ObjectId(trustedIpId),
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
});
|
||||
|
||||
if (!trustedIp) return res.status(400).send({
|
||||
message: "Failed to delete trusted IP"
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.DELETE_TRUSTED_IP,
|
||||
metadata: {
|
||||
trustedIpId: trustedIp._id.toString(),
|
||||
ipAddress: trustedIp.ipAddress,
|
||||
prefix: trustedIp.prefix
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: trustedIp.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
trustedIp
|
||||
|
76
backend/src/ee/models/auditLog/auditLog.ts
Normal file
76
backend/src/ee/models/auditLog/auditLog.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import { Schema, Types, model } from "mongoose";
|
||||
import {
|
||||
ActorType,
|
||||
EventType,
|
||||
UserAgentType
|
||||
} from "./enums";
|
||||
import {
|
||||
Actor,
|
||||
Event
|
||||
} from "./types";
|
||||
|
||||
export interface IAuditLog {
|
||||
actor: Actor;
|
||||
organization: Types.ObjectId;
|
||||
workspace: Types.ObjectId;
|
||||
ipAddress: string;
|
||||
event: Event;
|
||||
userAgent: string;
|
||||
userAgentType: UserAgentType;
|
||||
expiresAt: Date;
|
||||
}
|
||||
|
||||
const auditLogSchema = new Schema<IAuditLog>(
|
||||
{
|
||||
actor: {
|
||||
type: {
|
||||
type: String,
|
||||
enum: ActorType,
|
||||
required: true
|
||||
},
|
||||
metadata: {
|
||||
type: Schema.Types.Mixed
|
||||
}
|
||||
},
|
||||
organization: {
|
||||
type: Schema.Types.ObjectId,
|
||||
required: false
|
||||
},
|
||||
workspace: {
|
||||
type: Schema.Types.ObjectId,
|
||||
required: false
|
||||
},
|
||||
ipAddress: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
event: {
|
||||
type: {
|
||||
type: String,
|
||||
enum: EventType,
|
||||
required: true
|
||||
},
|
||||
metadata: {
|
||||
type: Schema.Types.Mixed
|
||||
}
|
||||
},
|
||||
userAgent: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
userAgentType: {
|
||||
type: String,
|
||||
enum: UserAgentType,
|
||||
required: true
|
||||
},
|
||||
expiresAt: {
|
||||
type: Date,
|
||||
expires: 0
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: true
|
||||
}
|
||||
);
|
||||
|
||||
export const AuditLog = model<IAuditLog>("AuditLog", auditLogSchema);
|
45
backend/src/ee/models/auditLog/enums.ts
Normal file
45
backend/src/ee/models/auditLog/enums.ts
Normal file
@ -0,0 +1,45 @@
|
||||
export enum ActorType {
|
||||
USER = "user",
|
||||
SERVICE = "service"
|
||||
}
|
||||
|
||||
export enum UserAgentType {
|
||||
WEB = "web",
|
||||
CLI = "cli",
|
||||
K8_OPERATOR = "k8-operator",
|
||||
OTHER = "other"
|
||||
}
|
||||
|
||||
export enum EventType {
|
||||
GET_SECRETS = "get-secrets",
|
||||
GET_SECRET = "get-secret",
|
||||
REVEAL_SECRET = "reveal-secret",
|
||||
CREATE_SECRET = "create-secret",
|
||||
UPDATE_SECRET = "update-secret",
|
||||
DELETE_SECRET = "delete-secret",
|
||||
GET_WORKSPACE_KEY = "get-workspace-key",
|
||||
AUTHORIZE_INTEGRATION = "authorize-integration",
|
||||
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
|
||||
CREATE_INTEGRATION = "create-integration",
|
||||
DELETE_INTEGRATION = "delete-integration",
|
||||
ADD_TRUSTED_IP = "add-trusted-ip",
|
||||
UPDATE_TRUSTED_IP = "update-trusted-ip",
|
||||
DELETE_TRUSTED_IP = "delete-trusted-ip",
|
||||
CREATE_SERVICE_TOKEN = "create-service-token",
|
||||
DELETE_SERVICE_TOKEN = "delete-service-token",
|
||||
CREATE_ENVIRONMENT = "create-environment",
|
||||
UPDATE_ENVIRONMENT = "update-environment",
|
||||
DELETE_ENVIRONMENT = "delete-environment",
|
||||
ADD_WORKSPACE_MEMBER = "add-workspace-member",
|
||||
REMOVE_WORKSPACE_MEMBER = "remove-workspace-member",
|
||||
CREATE_FOLDER = "create-folder",
|
||||
UPDATE_FOLDER = "update-folder",
|
||||
DELETE_FOLDER = "delete-folder",
|
||||
CREATE_WEBHOOK = "create-webhook",
|
||||
UPDATE_WEBHOOK_STATUS = "update-webhook-status",
|
||||
DELETE_WEBHOOK = "delete-webhook",
|
||||
GET_SECRET_IMPORTS = "get-secret-imports",
|
||||
CREATE_SECRET_IMPORT = "create-secret-import",
|
||||
UPDATE_SECRET_IMPORT = "update-secret-import",
|
||||
DELETE_SECRET_IMPORT = "delete-secret-import",
|
||||
}
|
3
backend/src/ee/models/auditLog/index.ts
Normal file
3
backend/src/ee/models/auditLog/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from "./auditLog";
|
||||
export * from "./enums";
|
||||
export * from "./types";
|
379
backend/src/ee/models/auditLog/types.ts
Normal file
379
backend/src/ee/models/auditLog/types.ts
Normal file
@ -0,0 +1,379 @@
|
||||
import {
|
||||
ActorType,
|
||||
EventType
|
||||
} from "./enums";
|
||||
|
||||
interface UserActorMetadata {
|
||||
userId: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
interface ServiceActorMetadata {
|
||||
serviceId: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface UserActor {
|
||||
type: ActorType.USER;
|
||||
metadata: UserActorMetadata;
|
||||
}
|
||||
|
||||
export interface ServiceActor {
|
||||
type: ActorType.SERVICE;
|
||||
metadata: ServiceActorMetadata;
|
||||
}
|
||||
|
||||
export type Actor =
|
||||
| UserActor
|
||||
| ServiceActor;
|
||||
|
||||
interface GetSecretsEvent {
|
||||
type: EventType.GET_SECRETS;
|
||||
metadata: {
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
numberOfSecrets: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface GetSecretEvent {
|
||||
type: EventType.GET_SECRET;
|
||||
metadata: {
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
secretId: string;
|
||||
secretKey: string;
|
||||
secretVersion: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface CreateSecretEvent {
|
||||
type: EventType.CREATE_SECRET;
|
||||
metadata: {
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
secretId: string;
|
||||
secretKey: string;
|
||||
secretVersion: number;
|
||||
}
|
||||
}
|
||||
|
||||
interface UpdateSecretEvent {
|
||||
type: EventType.UPDATE_SECRET;
|
||||
metadata: {
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
secretId: string;
|
||||
secretKey: string;
|
||||
secretVersion: number;
|
||||
}
|
||||
}
|
||||
|
||||
interface DeleteSecretEvent {
|
||||
type: EventType.DELETE_SECRET;
|
||||
metadata: {
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
secretId: string;
|
||||
secretKey: string;
|
||||
secretVersion: number;
|
||||
}
|
||||
}
|
||||
|
||||
interface GetWorkspaceKeyEvent {
|
||||
type: EventType.GET_WORKSPACE_KEY,
|
||||
metadata: {
|
||||
keyId: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface AuthorizeIntegrationEvent {
|
||||
type: EventType.AUTHORIZE_INTEGRATION;
|
||||
metadata: {
|
||||
integration: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface UnauthorizeIntegrationEvent {
|
||||
type: EventType.UNAUTHORIZE_INTEGRATION;
|
||||
metadata: {
|
||||
integration: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface CreateIntegrationEvent {
|
||||
type: EventType.CREATE_INTEGRATION;
|
||||
metadata: {
|
||||
integrationId: string;
|
||||
integration: string; // TODO: fix type
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
url?: string;
|
||||
app?: string;
|
||||
appId?: string;
|
||||
targetEnvironment?: string;
|
||||
targetEnvironmentId?: string;
|
||||
targetService?: string;
|
||||
targetServiceId?: string;
|
||||
path?: string;
|
||||
region?: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface DeleteIntegrationEvent {
|
||||
type: EventType.DELETE_INTEGRATION;
|
||||
metadata: {
|
||||
integrationId: string;
|
||||
integration: string; // TODO: fix type
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
url?: string;
|
||||
app?: string;
|
||||
appId?: string;
|
||||
targetEnvironment?: string;
|
||||
targetEnvironmentId?: string;
|
||||
targetService?: string;
|
||||
targetServiceId?: string;
|
||||
path?: string;
|
||||
region?: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface AddTrustedIPEvent {
|
||||
type: EventType.ADD_TRUSTED_IP;
|
||||
metadata: {
|
||||
trustedIpId: string;
|
||||
ipAddress: string;
|
||||
prefix?: number;
|
||||
}
|
||||
}
|
||||
|
||||
interface UpdateTrustedIPEvent {
|
||||
type: EventType.UPDATE_TRUSTED_IP;
|
||||
metadata: {
|
||||
trustedIpId: string;
|
||||
ipAddress: string;
|
||||
prefix?: number;
|
||||
}
|
||||
}
|
||||
|
||||
interface DeleteTrustedIPEvent {
|
||||
type: EventType.DELETE_TRUSTED_IP;
|
||||
metadata: {
|
||||
trustedIpId: string;
|
||||
ipAddress: string;
|
||||
prefix?: number;
|
||||
}
|
||||
}
|
||||
|
||||
interface CreateServiceTokenEvent {
|
||||
type: EventType.CREATE_SERVICE_TOKEN;
|
||||
metadata: {
|
||||
name: string;
|
||||
scopes: Array<{
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
}>;
|
||||
}
|
||||
}
|
||||
|
||||
interface DeleteServiceTokenEvent {
|
||||
type: EventType.DELETE_SERVICE_TOKEN;
|
||||
metadata: {
|
||||
name: string;
|
||||
scopes: Array<{
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
}>;
|
||||
}
|
||||
}
|
||||
|
||||
interface CreateEnvironmentEvent {
|
||||
type: EventType.CREATE_ENVIRONMENT;
|
||||
metadata: {
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface UpdateEnvironmentEvent {
|
||||
type: EventType.UPDATE_ENVIRONMENT;
|
||||
metadata: {
|
||||
oldName: string;
|
||||
newName: string;
|
||||
oldSlug: string;
|
||||
newSlug: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface DeleteEnvironmentEvent {
|
||||
type: EventType.DELETE_ENVIRONMENT;
|
||||
metadata: {
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface AddWorkspaceMemberEvent {
|
||||
type: EventType.ADD_WORKSPACE_MEMBER;
|
||||
metadata: {
|
||||
userId: string;
|
||||
email: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface RemoveWorkspaceMemberEvent {
|
||||
type: EventType.REMOVE_WORKSPACE_MEMBER;
|
||||
metadata: {
|
||||
userId: string;
|
||||
email: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface CreateFolderEvent {
|
||||
type: EventType.CREATE_FOLDER;
|
||||
metadata: {
|
||||
environment: string;
|
||||
folderId: string;
|
||||
folderName: string;
|
||||
folderPath: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface UpdateFolderEvent {
|
||||
type: EventType.UPDATE_FOLDER;
|
||||
metadata: {
|
||||
environment: string;
|
||||
folderId: string;
|
||||
oldFolderName: string;
|
||||
newFolderName: string;
|
||||
folderPath: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface DeleteFolderEvent {
|
||||
type: EventType.DELETE_FOLDER;
|
||||
metadata: {
|
||||
environment: string;
|
||||
folderId: string;
|
||||
folderName: string;
|
||||
folderPath: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface CreateWebhookEvent {
|
||||
type: EventType.CREATE_WEBHOOK,
|
||||
metadata: {
|
||||
webhookId: string;
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
webhookUrl: string;
|
||||
isDisabled: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
interface UpdateWebhookStatusEvent {
|
||||
type: EventType.UPDATE_WEBHOOK_STATUS,
|
||||
metadata: {
|
||||
webhookId: string;
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
webhookUrl: string;
|
||||
isDisabled: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
interface DeleteWebhookEvent {
|
||||
type: EventType.DELETE_WEBHOOK,
|
||||
metadata: {
|
||||
webhookId: string;
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
webhookUrl: string;
|
||||
isDisabled: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
interface GetSecretImportsEvent {
|
||||
type: EventType.GET_SECRET_IMPORTS,
|
||||
metadata: {
|
||||
environment: string;
|
||||
secretImportId: string;
|
||||
folderId: string;
|
||||
numberOfImports: number;
|
||||
}
|
||||
}
|
||||
|
||||
interface CreateSecretImportEvent {
|
||||
type: EventType.CREATE_SECRET_IMPORT,
|
||||
metadata: {
|
||||
secretImportId: string;
|
||||
folderId: string;
|
||||
importFromEnvironment: string;
|
||||
importFromSecretPath: string;
|
||||
importToEnvironment: string;
|
||||
importToSecretPath: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface UpdateSecretImportEvent {
|
||||
type: EventType.UPDATE_SECRET_IMPORT,
|
||||
metadata: {
|
||||
secretImportId: string;
|
||||
folderId: string;
|
||||
importToEnvironment: string;
|
||||
importToSecretPath: string;
|
||||
orderBefore: {
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
}[],
|
||||
orderAfter: {
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
}[]
|
||||
}
|
||||
}
|
||||
|
||||
interface DeleteSecretImportEvent {
|
||||
type: EventType.DELETE_SECRET_IMPORT,
|
||||
metadata: {
|
||||
secretImportId: string;
|
||||
folderId: string;
|
||||
importFromEnvironment: string;
|
||||
importFromSecretPath: string;
|
||||
importToEnvironment: string;
|
||||
importToSecretPath: string;
|
||||
}
|
||||
}
|
||||
|
||||
export type Event =
|
||||
| GetSecretsEvent
|
||||
| GetSecretEvent
|
||||
| CreateSecretEvent
|
||||
| UpdateSecretEvent
|
||||
| DeleteSecretEvent
|
||||
| GetWorkspaceKeyEvent
|
||||
| AuthorizeIntegrationEvent
|
||||
| UnauthorizeIntegrationEvent
|
||||
| CreateIntegrationEvent
|
||||
| DeleteIntegrationEvent
|
||||
| AddTrustedIPEvent
|
||||
| UpdateTrustedIPEvent
|
||||
| DeleteTrustedIPEvent
|
||||
| CreateServiceTokenEvent
|
||||
| DeleteServiceTokenEvent
|
||||
| CreateEnvironmentEvent
|
||||
| UpdateEnvironmentEvent
|
||||
| DeleteEnvironmentEvent
|
||||
| AddWorkspaceMemberEvent
|
||||
| RemoveWorkspaceMemberEvent
|
||||
| CreateFolderEvent
|
||||
| UpdateFolderEvent
|
||||
| DeleteFolderEvent
|
||||
| CreateWebhookEvent
|
||||
| UpdateWebhookStatusEvent
|
||||
| DeleteWebhookEvent
|
||||
| GetSecretImportsEvent
|
||||
| CreateSecretImportEvent
|
||||
| UpdateSecretImportEvent
|
||||
| DeleteSecretImportEvent;
|
@ -5,6 +5,7 @@ export * from "./log";
|
||||
export * from "./action";
|
||||
export * from "./ssoConfig";
|
||||
export * from "./trustedIp";
|
||||
export * from "./auditLog";
|
||||
export * from "./gitRisks";
|
||||
export * from "./gitAppOrganizationInstallation";
|
||||
export * from "./gitAppInstallationSession";
|
||||
|
@ -6,11 +6,12 @@ import {
|
||||
} from "../../../middleware";
|
||||
import { query } from "express-validator";
|
||||
import { cloudProductsController } from "../../controllers/v1";
|
||||
import { AuthMode } from "../../../variables";
|
||||
|
||||
router.get(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt", "apiKey"],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
query("billing-cycle").exists().isIn(["monthly", "yearly"]),
|
||||
validateRequest,
|
||||
|
@ -8,13 +8,13 @@ import {
|
||||
import { body, param, query } from "express-validator";
|
||||
import { organizationsController } from "../../controllers/v1";
|
||||
import {
|
||||
ACCEPTED, ADMIN, MEMBER, OWNER,
|
||||
ACCEPTED, ADMIN, AuthMode, MEMBER, OWNER
|
||||
} from "../../../variables";
|
||||
|
||||
router.get(
|
||||
"/:organizationId/plans/table",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -29,7 +29,7 @@ router.get(
|
||||
router.get(
|
||||
"/:organizationId/plan",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -44,7 +44,7 @@ router.get(
|
||||
router.post(
|
||||
"/:organizationId/session/trial",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -59,7 +59,7 @@ router.post(
|
||||
router.get(
|
||||
"/:organizationId/plan/billing",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -74,7 +74,7 @@ router.get(
|
||||
router.get(
|
||||
"/:organizationId/plan/table",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -89,7 +89,7 @@ router.get(
|
||||
router.get(
|
||||
"/:organizationId/billing-details",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -103,7 +103,7 @@ router.get(
|
||||
router.patch(
|
||||
"/:organizationId/billing-details",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -119,7 +119,7 @@ router.patch(
|
||||
router.get(
|
||||
"/:organizationId/billing-details/payment-methods",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -133,7 +133,7 @@ router.get(
|
||||
router.post(
|
||||
"/:organizationId/billing-details/payment-methods",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -149,7 +149,7 @@ router.post(
|
||||
router.delete(
|
||||
"/:organizationId/billing-details/payment-methods/:pmtMethodId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -164,7 +164,7 @@ router.delete(
|
||||
router.get(
|
||||
"/:organizationId/billing-details/tax-ids",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -178,7 +178,7 @@ router.get(
|
||||
router.post(
|
||||
"/:organizationId/billing-details/tax-ids",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -194,7 +194,7 @@ router.post(
|
||||
router.delete(
|
||||
"/:organizationId/billing-details/tax-ids/:taxId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -209,7 +209,7 @@ router.delete(
|
||||
router.get(
|
||||
"/:organizationId/invoices",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -223,7 +223,7 @@ router.get(
|
||||
router.get(
|
||||
"/:organizationId/licenses",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
|
@ -9,15 +9,16 @@ import { body, param, query } from "express-validator";
|
||||
import { secretController } from "../../controllers/v1";
|
||||
import {
|
||||
ADMIN,
|
||||
AuthMode,
|
||||
MEMBER,
|
||||
PERMISSION_READ_SECRETS,
|
||||
PERMISSION_WRITE_SECRETS,
|
||||
PERMISSION_WRITE_SECRETS
|
||||
} from "../../../variables";
|
||||
|
||||
router.get(
|
||||
"/:secretId/secret-versions",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt", "apiKey"],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireSecretAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -33,7 +34,7 @@ router.get(
|
||||
router.post(
|
||||
"/:secretId/secret-versions/rollback",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt", "apiKey"],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireSecretAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -7,12 +7,12 @@ import {
|
||||
} from "../../../middleware";
|
||||
import { body, param } from "express-validator";
|
||||
import { createInstallationSession, getCurrentOrganizationInstallationStatus, getRisksForOrganization, linkInstallationToOrganization, updateRisksStatus } from "../../../controllers/v1/secretScanningController";
|
||||
import { ACCEPTED, ADMIN, MEMBER, OWNER } from "../../../variables";
|
||||
import { ACCEPTED, ADMIN, AuthMode, MEMBER, OWNER } from "../../../variables";
|
||||
|
||||
router.post(
|
||||
"/create-installation-session/organization/:organizationId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("organizationId").exists().trim(),
|
||||
requireOrganizationAuth({
|
||||
@ -26,7 +26,7 @@ router.post(
|
||||
router.post(
|
||||
"/link-installation",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
body("installationId").exists().trim(),
|
||||
body("sessionId").exists().trim(),
|
||||
@ -37,7 +37,7 @@ router.post(
|
||||
router.get(
|
||||
"/installation-status/organization/:organizationId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("organizationId").exists().trim(),
|
||||
requireOrganizationAuth({
|
||||
@ -51,7 +51,7 @@ router.get(
|
||||
router.get(
|
||||
"/organization/:organizationId/risks",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("organizationId").exists().trim(),
|
||||
requireOrganizationAuth({
|
||||
@ -65,7 +65,7 @@ router.get(
|
||||
router.post(
|
||||
"/organization/:organizationId/risks/:riskId/status",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("organizationId").exists().trim(),
|
||||
param("riskId").exists().trim(),
|
||||
|
@ -8,13 +8,13 @@ import {
|
||||
validateRequest,
|
||||
} from "../../../middleware";
|
||||
import { param } from "express-validator";
|
||||
import { ADMIN, MEMBER } from "../../../variables";
|
||||
import { ADMIN, AuthMode, MEMBER } from "../../../variables";
|
||||
import { secretSnapshotController } from "../../controllers/v1";
|
||||
|
||||
router.get(
|
||||
"/:secretSnapshotId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireSecretSnapshotAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -15,6 +15,7 @@ import { authLimiter } from "../../../helpers/rateLimiter";
|
||||
import {
|
||||
ACCEPTED,
|
||||
ADMIN,
|
||||
AuthMode,
|
||||
OWNER
|
||||
} from "../../../variables";
|
||||
|
||||
@ -90,7 +91,7 @@ router.post("/saml2/:ssoIdentifier",
|
||||
router.get(
|
||||
"/config",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
@ -105,7 +106,7 @@ router.get(
|
||||
router.post(
|
||||
"/config",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
@ -125,7 +126,7 @@ router.post(
|
||||
router.patch(
|
||||
"/config",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
|
@ -3,13 +3,13 @@ const router = express.Router();
|
||||
import {
|
||||
requireAuth
|
||||
} from "../../../middleware";
|
||||
import { AUTH_MODE_API_KEY, AUTH_MODE_JWT } from "../../../variables";
|
||||
import { AuthMode } from "../../../variables";
|
||||
import { usersController } from "../../controllers/v1";
|
||||
|
||||
router.get(
|
||||
"/me/ip",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
usersController.getMyIp
|
||||
);
|
||||
|
@ -8,16 +8,16 @@ import {
|
||||
import { body, param, query } from "express-validator";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AuthMode,
|
||||
MEMBER
|
||||
} from "../../../variables";
|
||||
import { workspaceController } from "../../controllers/v1";
|
||||
import { EventType, UserAgentType } from "../../models";
|
||||
|
||||
router.get(
|
||||
"/:workspaceId/secret-snapshots",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -35,7 +35,7 @@ router.get(
|
||||
router.get(
|
||||
"/:workspaceId/secret-snapshots/count",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -51,7 +51,7 @@ router.get(
|
||||
router.post(
|
||||
"/:workspaceId/secret-snapshots/rollback",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -68,7 +68,7 @@ router.post(
|
||||
router.get(
|
||||
"/:workspaceId/logs",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -84,11 +84,46 @@ router.get(
|
||||
workspaceController.getWorkspaceLogs
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:workspaceId/audit-logs",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: "params",
|
||||
}),
|
||||
param("workspaceId").exists().trim(),
|
||||
query("eventType").isString().isIn(Object.values(EventType)).optional({ nullable: true }),
|
||||
query("userAgentType").isString().isIn(Object.values(UserAgentType)).optional({ nullable: true }),
|
||||
query("actor").optional({ nullable: true }),
|
||||
query("startDate").isISO8601().withMessage("Invalid start date format").optional({ nullable: true }),
|
||||
query("endDate").isISO8601().withMessage("Invalid end date format").optional({ nullable: true }),
|
||||
query("offset"),
|
||||
query("limit"),
|
||||
validateRequest,
|
||||
workspaceController.getWorkspaceAuditLogs
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:workspaceId/audit-logs/filters/actors",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: "params",
|
||||
}),
|
||||
param("workspaceId").exists().trim(),
|
||||
validateRequest,
|
||||
workspaceController.getWorkspaceAuditLogActorFilterOpts
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:workspaceId/trusted-ips",
|
||||
param("workspaceId").exists().isString().trim(),
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -105,7 +140,7 @@ router.post(
|
||||
body("isActive").exists().isBoolean(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
@ -122,7 +157,7 @@ router.patch(
|
||||
body("comment").default("").isString().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
@ -137,7 +172,7 @@ router.delete(
|
||||
param("trustedIpId").exists().isString().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
|
50
backend/src/ee/services/EEAuditLogService.ts
Normal file
50
backend/src/ee/services/EEAuditLogService.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { Types } from "mongoose";
|
||||
import { AuditLog, Event } from "../models";
|
||||
import { AuthData } from "../../interfaces/middleware";
|
||||
import EELicenseService from "./EELicenseService";
|
||||
import { Workspace } from "../../models";
|
||||
import { OrganizationNotFoundError } from "../../utils/errors";
|
||||
|
||||
interface EventScope {
|
||||
workspaceId?: Types.ObjectId;
|
||||
organizationId?: Types.ObjectId;
|
||||
}
|
||||
|
||||
type ValidEventScope =
|
||||
| Required<Pick<EventScope, "workspaceId">>
|
||||
| Required<Pick<EventScope, "organizationId">>
|
||||
| Required<EventScope>
|
||||
|
||||
export default class EEAuditLogService {
|
||||
static async createAuditLog(authData: AuthData, event: Event, eventScope: ValidEventScope, shouldSave: boolean = true) {
|
||||
|
||||
const MS_IN_DAY = 24 * 60 * 60 * 1000;
|
||||
|
||||
const organizationId = ("organizationId" in eventScope)
|
||||
? eventScope.organizationId
|
||||
: (await Workspace.findById(eventScope.workspaceId).select("organization").lean())?.organization;
|
||||
|
||||
if (!organizationId) throw OrganizationNotFoundError({
|
||||
message: "createAuditLog: Failed to create audit log due to missing organizationId"
|
||||
});
|
||||
|
||||
const ttl = (await EELicenseService.getPlan(organizationId)).auditLogsRetentionDays * MS_IN_DAY;
|
||||
|
||||
const auditLog = await new AuditLog({
|
||||
actor: authData.actor,
|
||||
organization: organizationId,
|
||||
workspace: ("workspaceId" in eventScope) ? eventScope.workspaceId : undefined,
|
||||
ipAddress: authData.ipAddress,
|
||||
event,
|
||||
userAgent: authData.userAgent,
|
||||
userAgentType: authData.userAgentType,
|
||||
expiresAt: new Date(Date.now() + ttl)
|
||||
});
|
||||
|
||||
if (shouldSave) {
|
||||
await auditLog.save();
|
||||
}
|
||||
|
||||
return auditLog;
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
import { Types } from "mongoose";
|
||||
import * as Sentry from "@sentry/node";
|
||||
import NodeCache from "node-cache";
|
||||
import {
|
||||
@ -31,6 +32,7 @@ interface FeatureSet {
|
||||
customRateLimits: boolean;
|
||||
customAlerts: boolean;
|
||||
auditLogs: boolean;
|
||||
auditLogsRetentionDays: number;
|
||||
samlSSO: boolean;
|
||||
status: "incomplete" | "incomplete_expired" | "trialing" | "active" | "past_due" | "canceled" | "unpaid" | null;
|
||||
trial_end: number | null;
|
||||
@ -63,9 +65,10 @@ class EELicenseService {
|
||||
pitRecovery: false,
|
||||
ipAllowlisting: false,
|
||||
rbac: true,
|
||||
customRateLimits: true,
|
||||
customAlerts: true,
|
||||
customRateLimits: false,
|
||||
customAlerts: false,
|
||||
auditLogs: false,
|
||||
auditLogsRetentionDays: 0,
|
||||
samlSSO: false,
|
||||
status: null,
|
||||
trial_end: null,
|
||||
@ -81,10 +84,10 @@ class EELicenseService {
|
||||
});
|
||||
}
|
||||
|
||||
public async getPlan(organizationId: string, workspaceId?: string): Promise<FeatureSet> {
|
||||
public async getPlan(organizationId: Types.ObjectId, workspaceId?: Types.ObjectId): Promise<FeatureSet> {
|
||||
try {
|
||||
if (this.instanceType === "cloud") {
|
||||
const cachedPlan = this.localFeatureSet.get<FeatureSet>(`${organizationId}-${workspaceId ?? ""}`);
|
||||
const cachedPlan = this.localFeatureSet.get<FeatureSet>(`${organizationId.toString()}-${workspaceId?.toString() ?? ""}`);
|
||||
if (cachedPlan) {
|
||||
return cachedPlan;
|
||||
}
|
||||
@ -101,7 +104,7 @@ class EELicenseService {
|
||||
const { data: { currentPlan } } = await licenseServerKeyRequest.get(url);
|
||||
|
||||
// cache fetched plan for organization
|
||||
this.localFeatureSet.set(`${organizationId}-${workspaceId ?? ""}`, currentPlan);
|
||||
this.localFeatureSet.set(`${organizationId.toString()}-${workspaceId?.toString() ?? ""}`, currentPlan);
|
||||
|
||||
return currentPlan;
|
||||
}
|
||||
@ -112,16 +115,16 @@ class EELicenseService {
|
||||
return this.globalFeatureSet;
|
||||
}
|
||||
|
||||
public async refreshPlan(organizationId: string, workspaceId?: string) {
|
||||
public async refreshPlan(organizationId: Types.ObjectId, workspaceId?: Types.ObjectId) {
|
||||
if (this.instanceType === "cloud") {
|
||||
this.localFeatureSet.del(`${organizationId}-${workspaceId ?? ""}`);
|
||||
this.localFeatureSet.del(`${organizationId.toString()}-${workspaceId?.toString() ?? ""}`);
|
||||
await this.getPlan(organizationId, workspaceId);
|
||||
}
|
||||
}
|
||||
|
||||
public async delPlan(organizationId: string) {
|
||||
public async delPlan(organizationId: Types.ObjectId) {
|
||||
if (this.instanceType === "cloud") {
|
||||
this.localFeatureSet.del(`${organizationId}-`);
|
||||
this.localFeatureSet.del(`${organizationId.toString()}-`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import EELicenseService from "./EELicenseService";
|
||||
/**
|
||||
* Class to handle Enterprise Edition secret actions
|
||||
*/
|
||||
class EESecretService {
|
||||
export default class EESecretService {
|
||||
/**
|
||||
* Save a secret snapshot that is a copy of the current state of secrets in workspace with id
|
||||
* [workspaceId] under a new snapshot with incremented version under the
|
||||
@ -71,5 +71,3 @@ class EESecretService {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default EESecretService;
|
||||
|
@ -1,11 +1,13 @@
|
||||
import EELicenseService from "./EELicenseService";
|
||||
import EESecretService from "./EESecretService";
|
||||
import EELogService from "./EELogService";
|
||||
import EEAuditLogService from "./EEAuditLogService";
|
||||
import GithubSecretScanningService from "./GithubSecretScanning/GithubSecretScanningService"
|
||||
|
||||
export {
|
||||
EELicenseService,
|
||||
EESecretService,
|
||||
EELogService,
|
||||
EEAuditLogService,
|
||||
GithubSecretScanningService
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
import { Request } from "express";
|
||||
import { Types } from "mongoose";
|
||||
import jwt from "jsonwebtoken";
|
||||
import bcrypt from "bcrypt";
|
||||
@ -5,7 +6,6 @@ import {
|
||||
APIKeyData,
|
||||
ITokenVersion,
|
||||
IUser,
|
||||
ServiceAccount,
|
||||
ServiceTokenData,
|
||||
TokenVersion,
|
||||
User,
|
||||
@ -14,7 +14,6 @@ import {
|
||||
APIKeyDataNotFoundError,
|
||||
AccountNotFoundError,
|
||||
BadRequestError,
|
||||
ServiceAccountNotFoundError,
|
||||
ServiceTokenDataNotFoundError,
|
||||
UnauthorizedRequestError,
|
||||
} from "../utils/errors";
|
||||
@ -26,11 +25,15 @@ import {
|
||||
getJwtRefreshSecret,
|
||||
} from "../config";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AuthMode
|
||||
} from "../variables";
|
||||
import {
|
||||
ServiceTokenAuthData,
|
||||
UserAuthData
|
||||
} from "../interfaces/middleware";
|
||||
|
||||
import { ActorType } from "../ee/models";
|
||||
import { getUserAgentType } from "../utils/posthog";
|
||||
|
||||
/**
|
||||
*
|
||||
@ -42,7 +45,7 @@ export const validateAuthMode = ({
|
||||
acceptedAuthModes,
|
||||
}: {
|
||||
headers: { [key: string]: string | string[] | undefined },
|
||||
acceptedAuthModes: string[]
|
||||
acceptedAuthModes: AuthMode[]
|
||||
}) => {
|
||||
const apiKey = headers["x-api-key"];
|
||||
const authHeader = headers["authorization"];
|
||||
@ -55,7 +58,7 @@ export const validateAuthMode = ({
|
||||
|
||||
if (typeof apiKey === "string") {
|
||||
// case: treat request authentication type as via X-API-KEY (i.e. API Key)
|
||||
authMode = AUTH_MODE_API_KEY;
|
||||
authMode = AuthMode.API_KEY;
|
||||
authTokenValue = apiKey;
|
||||
}
|
||||
|
||||
@ -71,13 +74,10 @@ export const validateAuthMode = ({
|
||||
|
||||
switch (tokenValue.split(".", 1)[0]) {
|
||||
case "st":
|
||||
authMode = AUTH_MODE_SERVICE_TOKEN;
|
||||
break;
|
||||
case "sa":
|
||||
authMode = AUTH_MODE_SERVICE_ACCOUNT;
|
||||
authMode = AuthMode.SERVICE_TOKEN;
|
||||
break;
|
||||
default:
|
||||
authMode = AUTH_MODE_JWT;
|
||||
authMode = AuthMode.JWT;
|
||||
}
|
||||
|
||||
authTokenValue = tokenValue;
|
||||
@ -100,10 +100,12 @@ export const validateAuthMode = ({
|
||||
* @returns {User} user - user corresponding to JWT token
|
||||
*/
|
||||
export const getAuthUserPayload = async ({
|
||||
req,
|
||||
authTokenValue,
|
||||
}: {
|
||||
req: Request,
|
||||
authTokenValue: string;
|
||||
}) => {
|
||||
}): Promise<UserAuthData> => {
|
||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||
jwt.verify(authTokenValue, await getJwtAuthSecret())
|
||||
);
|
||||
@ -130,11 +132,25 @@ export const getAuthUserPayload = async ({
|
||||
if (decodedToken.accessVersion !== tokenVersion.accessVersion) throw UnauthorizedRequestError({
|
||||
message: "Failed to validate access token",
|
||||
});
|
||||
|
||||
return ({
|
||||
user,
|
||||
tokenVersionId: tokenVersion._id,
|
||||
});
|
||||
|
||||
return {
|
||||
actor: {
|
||||
type: ActorType.USER,
|
||||
metadata: {
|
||||
userId: user._id.toString(),
|
||||
email: user.email
|
||||
}
|
||||
},
|
||||
authPayload: user,
|
||||
ipAddress: req.realIP,
|
||||
userAgent: req.headers["user-agent"] ?? "",
|
||||
userAgentType: getUserAgentType(req.headers["user-agent"])
|
||||
}
|
||||
|
||||
// return ({
|
||||
// user,
|
||||
// tokenVersionId: tokenVersion._id, // what to do with this? // move this out
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,10 +160,12 @@ export const getAuthUserPayload = async ({
|
||||
* @returns {ServiceTokenData} serviceTokenData - service token data
|
||||
*/
|
||||
export const getAuthSTDPayload = async ({
|
||||
req,
|
||||
authTokenValue,
|
||||
}: {
|
||||
req: Request,
|
||||
authTokenValue: string;
|
||||
}) => {
|
||||
}): Promise<ServiceTokenAuthData> => {
|
||||
const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split(".", 3);
|
||||
|
||||
const serviceTokenData = await ServiceTokenData
|
||||
@ -180,36 +198,21 @@ export const getAuthSTDPayload = async ({
|
||||
|
||||
if (!serviceTokenDataToReturn) throw ServiceTokenDataNotFoundError({ message: "Failed to find service token data" });
|
||||
|
||||
return serviceTokenDataToReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return service account access key payload
|
||||
* @param {Object} obj
|
||||
* @param {String} obj.authTokenValue - service account access token value
|
||||
* @returns {ServiceAccount} serviceAccount
|
||||
*/
|
||||
export const getAuthSAAKPayload = async ({
|
||||
authTokenValue,
|
||||
}: {
|
||||
authTokenValue: string;
|
||||
}) => {
|
||||
const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split(".", 3);
|
||||
|
||||
const serviceAccount = await ServiceAccount.findById(
|
||||
Buffer.from(TOKEN_IDENTIFIER, "base64").toString("hex")
|
||||
).select("+secretHash");
|
||||
|
||||
if (!serviceAccount) {
|
||||
throw ServiceAccountNotFoundError({ message: "Failed to find service account" });
|
||||
return {
|
||||
actor: {
|
||||
type: ActorType.SERVICE,
|
||||
metadata: {
|
||||
serviceId: serviceTokenDataToReturn._id.toString(),
|
||||
name: serviceTokenDataToReturn.name
|
||||
}
|
||||
},
|
||||
authPayload: serviceTokenDataToReturn,
|
||||
ipAddress: req.realIP,
|
||||
userAgent: req.headers["user-agent"] ?? "",
|
||||
userAgentType: getUserAgentType(req.headers["user-agent"])
|
||||
}
|
||||
|
||||
const result = await bcrypt.compare(TOKEN_SECRET, serviceAccount.secretHash);
|
||||
if (!result) throw UnauthorizedRequestError({
|
||||
message: "Failed to authenticate service account access key",
|
||||
});
|
||||
|
||||
return serviceAccount;
|
||||
// return serviceTokenDataToReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,10 +222,12 @@ export const getAuthSAAKPayload = async ({
|
||||
* @returns {APIKeyData} apiKeyData - API key data
|
||||
*/
|
||||
export const getAuthAPIKeyPayload = async ({
|
||||
req,
|
||||
authTokenValue,
|
||||
}: {
|
||||
req: Request,
|
||||
authTokenValue: string;
|
||||
}) => {
|
||||
}): Promise<UserAuthData> => {
|
||||
const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split(".", 3);
|
||||
|
||||
let apiKeyData = await APIKeyData
|
||||
@ -264,7 +269,19 @@ export const getAuthAPIKeyPayload = async ({
|
||||
});
|
||||
}
|
||||
|
||||
return user;
|
||||
return {
|
||||
actor: {
|
||||
type: ActorType.USER,
|
||||
metadata: {
|
||||
userId: user._id.toString(),
|
||||
email: user.email
|
||||
}
|
||||
},
|
||||
authPayload: user,
|
||||
ipAddress: req.realIP,
|
||||
userAgent: req.headers["user-agent"] ?? "",
|
||||
userAgentType: getUserAgentType(req.headers["user-agent"])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,5 +115,5 @@ export const updateSubscriptionOrgQuantity = async ({
|
||||
);
|
||||
}
|
||||
|
||||
await EELicenseService.refreshPlan(organizationId);
|
||||
await EELicenseService.refreshPlan(new Types.ObjectId(organizationId));
|
||||
};
|
@ -11,9 +11,9 @@ import {
|
||||
IServiceTokenData,
|
||||
Secret,
|
||||
SecretBlindIndexData,
|
||||
ServiceTokenData
|
||||
ServiceTokenData,
|
||||
} from "../models";
|
||||
import { SecretVersion } from "../ee/models";
|
||||
import { EventType, SecretVersion } from "../ee/models";
|
||||
import {
|
||||
BadRequestError,
|
||||
InternalServerError,
|
||||
@ -40,7 +40,7 @@ import {
|
||||
} from "../utils/crypto";
|
||||
import { TelemetryService } from "../services";
|
||||
import { client, getEncryptionKey, getRootEncryptionKey } from "../config";
|
||||
import { EELogService, EESecretService } from "../ee/services";
|
||||
import { EEAuditLogService, EELogService, EESecretService } from "../ee/services";
|
||||
import { getAuthDataPayloadIdObj, getAuthDataPayloadUserObj } from "../utils/auth";
|
||||
import { getFolderByPath, getFolderIdFromServiceToken } from "../services/FolderService";
|
||||
import picomatch from "picomatch";
|
||||
@ -433,10 +433,27 @@ export const createSecretHelper = async ({
|
||||
...getAuthDataPayloadIdObj(authData),
|
||||
workspaceId,
|
||||
actions: [action],
|
||||
channel: authData.authChannel,
|
||||
ipAddress: authData.authIP
|
||||
channel: authData.userAgentType,
|
||||
ipAddress: authData.ipAddress
|
||||
}));
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
authData,
|
||||
{
|
||||
type: EventType.CREATE_SECRET,
|
||||
metadata: {
|
||||
environment,
|
||||
secretPath,
|
||||
secretId: secret._id.toString(),
|
||||
secretKey: secretName,
|
||||
secretVersion: secret.version
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId
|
||||
}
|
||||
);
|
||||
|
||||
// (EE) take a secret snapshot
|
||||
await EESecretService.takeSecretSnapshot({
|
||||
workspaceId,
|
||||
@ -457,8 +474,8 @@ export const createSecretHelper = async ({
|
||||
environment,
|
||||
workspaceId,
|
||||
folderId,
|
||||
channel: authData.authChannel,
|
||||
userAgent: authData.authUserAgent
|
||||
channel: authData.userAgentType,
|
||||
userAgent: authData.userAgent
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -528,9 +545,24 @@ export const getSecretsHelper = async ({
|
||||
...getAuthDataPayloadIdObj(authData),
|
||||
workspaceId,
|
||||
actions: [action],
|
||||
channel: authData.authChannel,
|
||||
ipAddress: authData.authIP
|
||||
channel: authData.userAgentType,
|
||||
ipAddress: authData.ipAddress
|
||||
}));
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
authData,
|
||||
{
|
||||
type: EventType.GET_SECRETS,
|
||||
metadata: {
|
||||
environment,
|
||||
secretPath,
|
||||
numberOfSecrets: secrets.length
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId
|
||||
}
|
||||
);
|
||||
|
||||
const postHogClient = await TelemetryService.getPostHogClient();
|
||||
|
||||
@ -545,8 +577,8 @@ export const getSecretsHelper = async ({
|
||||
environment,
|
||||
workspaceId,
|
||||
folderId,
|
||||
channel: authData.authChannel,
|
||||
userAgent: authData.authUserAgent
|
||||
channel: authData.userAgentType,
|
||||
userAgent: authData.userAgent
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -622,10 +654,27 @@ export const getSecretHelper = async ({
|
||||
...getAuthDataPayloadIdObj(authData),
|
||||
workspaceId,
|
||||
actions: [action],
|
||||
channel: authData.authChannel,
|
||||
ipAddress: authData.authIP
|
||||
channel: authData.userAgentType,
|
||||
ipAddress: authData.ipAddress
|
||||
}));
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
authData,
|
||||
{
|
||||
type: EventType.GET_SECRET,
|
||||
metadata: {
|
||||
environment,
|
||||
secretPath,
|
||||
secretId: secret._id.toString(),
|
||||
secretKey: secretName,
|
||||
secretVersion: secret.version
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId
|
||||
}
|
||||
);
|
||||
|
||||
const postHogClient = await TelemetryService.getPostHogClient();
|
||||
|
||||
if (postHogClient) {
|
||||
@ -639,8 +688,8 @@ export const getSecretHelper = async ({
|
||||
environment,
|
||||
workspaceId,
|
||||
folderId,
|
||||
channel: authData.authChannel,
|
||||
userAgent: authData.authUserAgent
|
||||
channel: authData.userAgentType,
|
||||
userAgent: authData.userAgent
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -771,9 +820,26 @@ export const updateSecretHelper = async ({
|
||||
...getAuthDataPayloadIdObj(authData),
|
||||
workspaceId,
|
||||
actions: [action],
|
||||
channel: authData.authChannel,
|
||||
ipAddress: authData.authIP
|
||||
channel: authData.userAgentType,
|
||||
ipAddress: authData.ipAddress
|
||||
}));
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
authData,
|
||||
{
|
||||
type: EventType.UPDATE_SECRET,
|
||||
metadata: {
|
||||
environment,
|
||||
secretPath,
|
||||
secretId: secret._id.toString(),
|
||||
secretKey: secretName,
|
||||
secretVersion: secret.version
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId
|
||||
}
|
||||
);
|
||||
|
||||
// (EE) take a secret snapshot
|
||||
await EESecretService.takeSecretSnapshot({
|
||||
@ -795,8 +861,8 @@ export const updateSecretHelper = async ({
|
||||
environment,
|
||||
workspaceId,
|
||||
folderId,
|
||||
channel: authData.authChannel,
|
||||
userAgent: authData.authUserAgent
|
||||
channel: authData.userAgentType,
|
||||
userAgent: authData.userAgent
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -894,10 +960,27 @@ export const deleteSecretHelper = async ({
|
||||
...getAuthDataPayloadIdObj(authData),
|
||||
workspaceId,
|
||||
actions: [action],
|
||||
channel: authData.authChannel,
|
||||
ipAddress: authData.authIP
|
||||
channel: authData.userAgentType,
|
||||
ipAddress: authData.ipAddress
|
||||
}));
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
authData,
|
||||
{
|
||||
type: EventType.DELETE_SECRET,
|
||||
metadata: {
|
||||
environment,
|
||||
secretPath,
|
||||
secretId: secret._id.toString(),
|
||||
secretKey: secretName,
|
||||
secretVersion: secret.version
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId
|
||||
}
|
||||
);
|
||||
|
||||
// (EE) take a secret snapshot
|
||||
await EESecretService.takeSecretSnapshot({
|
||||
workspaceId,
|
||||
@ -918,8 +1001,8 @@ export const deleteSecretHelper = async ({
|
||||
environment,
|
||||
workspaceId,
|
||||
folderId,
|
||||
channel: authData.authChannel,
|
||||
userAgent: authData.authUserAgent
|
||||
channel: authData.userAgentType,
|
||||
userAgent: authData.userAgent
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
Bot,
|
||||
Key,
|
||||
@ -25,7 +26,7 @@ export const createWorkspace = async ({
|
||||
organizationId,
|
||||
}: {
|
||||
name: string;
|
||||
organizationId: string;
|
||||
organizationId: Types.ObjectId;
|
||||
}) => {
|
||||
// create workspace
|
||||
const workspace = await new Workspace({
|
||||
|
@ -1,15 +1,31 @@
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
IServiceAccount,
|
||||
IServiceTokenData,
|
||||
IUser,
|
||||
} from "../../models";
|
||||
import {
|
||||
ServiceActor,
|
||||
UserActor,
|
||||
UserAgentType
|
||||
} from "../../ee/models";
|
||||
|
||||
export interface AuthData {
|
||||
authMode: string;
|
||||
authPayload: IUser | IServiceAccount | IServiceTokenData;
|
||||
authChannel: string;
|
||||
authIP: string;
|
||||
authUserAgent: string;
|
||||
interface BaseAuthData {
|
||||
ipAddress: string;
|
||||
userAgent: string;
|
||||
userAgentType: UserAgentType;
|
||||
tokenVersionId?: Types.ObjectId;
|
||||
}
|
||||
}
|
||||
|
||||
export interface UserAuthData extends BaseAuthData {
|
||||
actor: UserActor;
|
||||
authPayload: IUser;
|
||||
}
|
||||
|
||||
export interface ServiceTokenAuthData extends BaseAuthData {
|
||||
actor: ServiceActor;
|
||||
authPayload: IServiceTokenData;
|
||||
}
|
||||
|
||||
export type AuthData =
|
||||
| UserAuthData
|
||||
| ServiceTokenAuthData;
|
@ -1,25 +1,13 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
import { Types } from "mongoose";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import {
|
||||
getAuthAPIKeyPayload,
|
||||
getAuthSAAKPayload,
|
||||
getAuthSTDPayload,
|
||||
getAuthUserPayload,
|
||||
validateAuthMode,
|
||||
} from "../helpers/auth";
|
||||
import {
|
||||
IServiceAccount,
|
||||
IServiceTokenData,
|
||||
IUser,
|
||||
} from "../models";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
} from "../variables";
|
||||
import { getChannelFromUserAgent } from "../utils/posthog";
|
||||
import { AuthMode } from "../variables";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
|
||||
declare module "jsonwebtoken" {
|
||||
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
||||
@ -38,9 +26,9 @@ declare module "jsonwebtoken" {
|
||||
* @returns
|
||||
*/
|
||||
const requireAuth = ({
|
||||
acceptedAuthModes = [AUTH_MODE_JWT],
|
||||
acceptedAuthModes = [AuthMode.JWT],
|
||||
}: {
|
||||
acceptedAuthModes: string[];
|
||||
acceptedAuthModes: AuthMode[];
|
||||
}) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
|
||||
@ -50,55 +38,36 @@ const requireAuth = ({
|
||||
headers: req.headers,
|
||||
acceptedAuthModes,
|
||||
});
|
||||
|
||||
let authPayload: IUser | IServiceAccount | IServiceTokenData;
|
||||
let authUserPayload: {
|
||||
user: IUser;
|
||||
tokenVersionId: Types.ObjectId;
|
||||
};
|
||||
|
||||
let authData: AuthData;
|
||||
|
||||
switch (authMode) {
|
||||
case AUTH_MODE_SERVICE_ACCOUNT:
|
||||
authPayload = await getAuthSAAKPayload({
|
||||
case AuthMode.SERVICE_TOKEN:
|
||||
authData = await getAuthSTDPayload({
|
||||
req,
|
||||
authTokenValue,
|
||||
});
|
||||
req.serviceAccount = authPayload;
|
||||
req.serviceTokenData = authData.authPayload;
|
||||
break;
|
||||
case AUTH_MODE_SERVICE_TOKEN:
|
||||
authPayload = await getAuthSTDPayload({
|
||||
authTokenValue,
|
||||
case AuthMode.API_KEY:
|
||||
authData = await getAuthAPIKeyPayload({
|
||||
req,
|
||||
authTokenValue
|
||||
});
|
||||
req.serviceTokenData = authPayload;
|
||||
req.user = authData.authPayload;
|
||||
break;
|
||||
case AUTH_MODE_API_KEY:
|
||||
authPayload = await getAuthAPIKeyPayload({
|
||||
authTokenValue,
|
||||
case AuthMode.JWT:
|
||||
authData = await getAuthUserPayload({
|
||||
req,
|
||||
authTokenValue
|
||||
});
|
||||
req.user = authPayload;
|
||||
break;
|
||||
default:
|
||||
authUserPayload = await getAuthUserPayload({
|
||||
authTokenValue,
|
||||
});
|
||||
authPayload = authUserPayload.user;
|
||||
req.user = authUserPayload.user;
|
||||
req.tokenVersionId = authUserPayload.tokenVersionId;
|
||||
// authPayload = authUserPayload.user;
|
||||
req.user = authData.authPayload;
|
||||
// req.tokenVersionId = authUserPayload.tokenVersionId; // TODO
|
||||
break;
|
||||
}
|
||||
|
||||
req.requestData = {
|
||||
...req.params,
|
||||
...req.query,
|
||||
...req.body,
|
||||
}
|
||||
|
||||
req.authData = {
|
||||
authMode,
|
||||
authPayload, // User, ServiceAccount, ServiceTokenData
|
||||
authChannel: getChannelFromUserAgent(req.headers["user-agent"]),
|
||||
authIP: req.realIP,
|
||||
authUserAgent: req.headers["user-agent"] ?? "other",
|
||||
tokenVersionId: req.tokenVersionId,
|
||||
}
|
||||
|
||||
req.authData = authData;
|
||||
|
||||
return next();
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import Membership, { IMembership } from "./membership";
|
||||
import MembershipOrg, { IMembershipOrg } from "./membershipOrg";
|
||||
import Organization, { IOrganization } from "./organization";
|
||||
import Secret, { ISecret } from "./secret";
|
||||
import Folder, { TFolderRootSchema, TFolderSchema } from "./folder";
|
||||
import SecretImport, { ISecretImports } from "./secretImports";
|
||||
import SecretBlindIndexData, { ISecretBlindIndexData } from "./secretBlindIndexData";
|
||||
import ServiceToken, { IServiceToken } from "./serviceToken";
|
||||
import ServiceAccount, { IServiceAccount } from "./serviceAccount"; // new
|
||||
@ -51,6 +53,11 @@ export {
|
||||
IOrganization,
|
||||
Secret,
|
||||
ISecret,
|
||||
Folder,
|
||||
TFolderRootSchema,
|
||||
TFolderSchema,
|
||||
SecretImport,
|
||||
ISecretImports,
|
||||
SecretBlindIndexData,
|
||||
ISecretBlindIndexData,
|
||||
ServiceToken,
|
||||
|
@ -4,7 +4,7 @@ import { body } from "express-validator";
|
||||
import { requireAuth, validateRequest } from "../../middleware";
|
||||
import { authController } from "../../controllers/v1";
|
||||
import { authLimiter } from "../../helpers/rateLimiter";
|
||||
import { AUTH_MODE_JWT } from "../../variables";
|
||||
import { AuthMode } from "../../variables";
|
||||
|
||||
router.post("/token", validateRequest, authController.getNewToken);
|
||||
|
||||
@ -30,7 +30,7 @@ router.post(
|
||||
"/logout",
|
||||
authLimiter,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
authController.logout
|
||||
);
|
||||
@ -38,7 +38,7 @@ router.post(
|
||||
router.post(
|
||||
"/checkAuth",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
authController.checkAuth
|
||||
);
|
||||
@ -53,9 +53,9 @@ router.delete(
|
||||
"/sessions",
|
||||
authLimiter,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
authController.revokeAllSessions
|
||||
);
|
||||
|
||||
export default router;
|
||||
export default router;
|
@ -8,12 +8,12 @@ import {
|
||||
validateRequest,
|
||||
} from "../../middleware";
|
||||
import { botController } from "../../controllers/v1";
|
||||
import { ADMIN, AUTH_MODE_JWT, MEMBER } from "../../variables";
|
||||
import { ADMIN, AuthMode, MEMBER } from "../../variables";
|
||||
|
||||
router.get(
|
||||
"/:workspaceId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -27,7 +27,7 @@ router.get(
|
||||
router.patch(
|
||||
"/:botId/active",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireBotAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -8,9 +8,8 @@ import {
|
||||
} from "../../middleware";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
MEMBER,
|
||||
AuthMode,
|
||||
MEMBER
|
||||
} from "../../variables";
|
||||
import { body, param } from "express-validator";
|
||||
import { integrationController } from "../../controllers/v1";
|
||||
@ -18,7 +17,7 @@ import { integrationController } from "../../controllers/v1";
|
||||
router.post(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireIntegrationAuthorizationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -44,7 +43,7 @@ router.post(
|
||||
router.patch(
|
||||
"/:integrationId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
requireIntegrationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -64,7 +63,7 @@ router.patch(
|
||||
router.delete(
|
||||
"/:integrationId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
requireIntegrationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -9,16 +9,15 @@ import {
|
||||
} from "../../middleware";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
MEMBER,
|
||||
AuthMode,
|
||||
MEMBER
|
||||
} from "../../variables";
|
||||
import { integrationAuthController } from "../../controllers/v1";
|
||||
|
||||
router.get(
|
||||
"/integration-options",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
integrationAuthController.getIntegrationOptions
|
||||
);
|
||||
@ -26,7 +25,7 @@ router.get(
|
||||
router.get(
|
||||
"/:integrationAuthId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireIntegrationAuthorizationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -39,7 +38,7 @@ router.get(
|
||||
router.post(
|
||||
"/oauth-token",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -62,7 +61,7 @@ router.post(
|
||||
body("integration").exists().trim().notEmpty(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -74,7 +73,7 @@ router.post(
|
||||
router.get(
|
||||
"/:integrationAuthId/apps",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireIntegrationAuthorizationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -89,7 +88,7 @@ router.get(
|
||||
router.get(
|
||||
"/:integrationAuthId/teams",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireIntegrationAuthorizationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -102,7 +101,7 @@ router.get(
|
||||
router.get(
|
||||
"/:integrationAuthId/vercel/branches",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireIntegrationAuthorizationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -117,7 +116,7 @@ router.get(
|
||||
router.get(
|
||||
"/:integrationAuthId/railway/environments",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireIntegrationAuthorizationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -131,7 +130,7 @@ router.get(
|
||||
router.get(
|
||||
"/:integrationAuthId/railway/services",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireIntegrationAuthorizationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -145,7 +144,7 @@ router.get(
|
||||
router.get(
|
||||
"/:integrationAuthId/bitbucket/workspaces",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireIntegrationAuthorizationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -158,7 +157,7 @@ router.get(
|
||||
router.get(
|
||||
"/:integrationAuthId/northflank/secret-groups",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireIntegrationAuthorizationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -172,7 +171,7 @@ router.get(
|
||||
router.delete(
|
||||
"/:integrationAuthId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireIntegrationAuthorizationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -3,12 +3,12 @@ const router = express.Router();
|
||||
import { body } from "express-validator";
|
||||
import { requireAuth, validateRequest } from "../../middleware";
|
||||
import { membershipOrgController } from "../../controllers/v1";
|
||||
import { AUTH_MODE_JWT } from "../../variables";
|
||||
import { AuthMode } from "../../variables";
|
||||
|
||||
router.post(
|
||||
"/signup",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
body("inviteeEmail").exists().trim().notEmpty().isEmail(),
|
||||
body("organizationId").exists().trim().notEmpty(),
|
||||
|
@ -6,13 +6,13 @@ import {
|
||||
validateRequest,
|
||||
} from "../../middleware";
|
||||
import { body, param } from "express-validator";
|
||||
import { ADMIN, AUTH_MODE_JWT, MEMBER } from "../../variables";
|
||||
import { ADMIN, AuthMode, MEMBER } from "../../variables";
|
||||
import { keyController } from "../../controllers/v1";
|
||||
|
||||
router.post(
|
||||
"/:workspaceId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -27,7 +27,7 @@ router.post(
|
||||
router.get(
|
||||
"/:workspaceId/latest",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -4,14 +4,14 @@ import { body, param } from "express-validator";
|
||||
import { requireAuth, validateRequest } from "../../middleware";
|
||||
import { membershipController } from "../../controllers/v1";
|
||||
import { membershipController as EEMembershipControllers } from "../../ee/controllers/v1";
|
||||
import { AUTH_MODE_JWT } from "../../variables";
|
||||
import { AuthMode } from "../../variables";
|
||||
|
||||
// note: ALL DEPRECIATED (moved to api/v2/workspace/:workspaceId/memberships/:membershipId)
|
||||
|
||||
router.get( // used for old CLI (deprecate)
|
||||
"/:workspaceId/connect",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("workspaceId").exists().trim(),
|
||||
validateRequest,
|
||||
@ -21,7 +21,7 @@ router.get( // used for old CLI (deprecate)
|
||||
router.delete(
|
||||
"/:membershipId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("membershipId").exists().trim(),
|
||||
validateRequest,
|
||||
@ -31,7 +31,7 @@ router.delete(
|
||||
router.post(
|
||||
"/:membershipId/change-role",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
body("role").exists().trim(),
|
||||
validateRequest,
|
||||
@ -41,7 +41,7 @@ router.post(
|
||||
router.post(
|
||||
"/:membershipId/deny-permissions",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("membershipId").isMongoId().exists().trim(),
|
||||
body("permissions").isArray().exists(),
|
||||
|
@ -3,13 +3,13 @@ const router = express.Router();
|
||||
import { param } from "express-validator";
|
||||
import { requireAuth, validateRequest } from "../../middleware";
|
||||
import { membershipOrgController } from "../../controllers/v1";
|
||||
import { AUTH_MODE_JWT } from "../../variables";
|
||||
import { AuthMode } from "../../variables";
|
||||
|
||||
router.post(
|
||||
// TODO
|
||||
"/membershipOrg/:membershipOrgId/change-role",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("membershipOrgId"),
|
||||
validateRequest,
|
||||
@ -19,7 +19,7 @@ router.post(
|
||||
router.delete(
|
||||
"/:membershipOrgId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("membershipOrgId").exists().trim(),
|
||||
validateRequest,
|
||||
|
@ -9,16 +9,16 @@ import {
|
||||
import {
|
||||
ACCEPTED,
|
||||
ADMIN,
|
||||
AUTH_MODE_JWT,
|
||||
AuthMode,
|
||||
MEMBER,
|
||||
OWNER,
|
||||
OWNER
|
||||
} from "../../variables";
|
||||
import { organizationController } from "../../controllers/v1";
|
||||
|
||||
router.get( // deprecated (moved to api/v2/users/me/organizations)
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
organizationController.getOrganizations
|
||||
);
|
||||
@ -26,7 +26,7 @@ router.get( // deprecated (moved to api/v2/users/me/organizations)
|
||||
router.post( // not used on frontend
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
body("organizationName").exists().trim().notEmpty(),
|
||||
validateRequest,
|
||||
@ -36,7 +36,7 @@ router.post( // not used on frontend
|
||||
router.get(
|
||||
"/:organizationId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -50,7 +50,7 @@ router.get(
|
||||
router.get( // deprecated (moved to api/v2/organizations/:organizationId/memberships)
|
||||
"/:organizationId/users",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -64,7 +64,7 @@ router.get( // deprecated (moved to api/v2/organizations/:organizationId/members
|
||||
router.get(
|
||||
"/:organizationId/my-workspaces", // deprecated (moved to api/v2/organizations/:organizationId/workspaces)
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -78,7 +78,7 @@ router.get(
|
||||
router.patch(
|
||||
"/:organizationId/name",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -93,7 +93,7 @@ router.patch(
|
||||
router.get(
|
||||
"/:organizationId/incidentContactOrg",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -107,7 +107,7 @@ router.get(
|
||||
router.post(
|
||||
"/:organizationId/incidentContactOrg",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -122,7 +122,7 @@ router.post(
|
||||
router.delete(
|
||||
"/:organizationId/incidentContactOrg",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -137,7 +137,7 @@ router.delete(
|
||||
router.post(
|
||||
"/:organizationId/customer-portal-session",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -151,7 +151,7 @@ router.post(
|
||||
router.get(
|
||||
"/:organizationId/subscriptions",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -165,7 +165,7 @@ router.get(
|
||||
router.get(
|
||||
"/:organizationId/workspace-memberships",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
|
@ -4,14 +4,12 @@ import { body } from "express-validator";
|
||||
import { requireAuth, requireSignupAuth, validateRequest } from "../../middleware";
|
||||
import { passwordController } from "../../controllers/v1";
|
||||
import { passwordLimiter } from "../../helpers/rateLimiter";
|
||||
import {
|
||||
AUTH_MODE_JWT,
|
||||
} from "../../variables";
|
||||
import { AuthMode } from "../../variables";
|
||||
|
||||
router.post(
|
||||
"/srp1",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
body("clientPublicKey").exists().isString().trim().notEmpty(),
|
||||
validateRequest,
|
||||
@ -22,7 +20,7 @@ router.post(
|
||||
"/change-password",
|
||||
passwordLimiter,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
body("clientProof").exists().trim().notEmpty(),
|
||||
body("protectedKey").exists().isString().trim().notEmpty(),
|
||||
@ -65,7 +63,7 @@ router.post(
|
||||
"/backup-private-key",
|
||||
passwordLimiter,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
body("clientProof").exists().isString().trim().notEmpty(),
|
||||
body("encryptedPrivateKey").exists().isString().trim().notEmpty(), // (backup) private key encrypted under a strong key
|
||||
|
@ -10,8 +10,8 @@ import { body, param, query } from "express-validator";
|
||||
import { secretController } from "../../controllers/v1";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_JWT,
|
||||
MEMBER,
|
||||
AuthMode,
|
||||
MEMBER
|
||||
} from "../../variables";
|
||||
|
||||
// note to devs: these endpoints will be deprecated in favor of v2
|
||||
@ -19,7 +19,7 @@ import {
|
||||
router.post(
|
||||
"/:workspaceId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -37,7 +37,7 @@ router.post(
|
||||
router.get(
|
||||
"/:workspaceId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -1,14 +1,14 @@
|
||||
import express from "express";
|
||||
const router = express.Router();
|
||||
import { body, param, query } from "express-validator";
|
||||
import { secretImportController } from "../../controllers/v1";
|
||||
import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware";
|
||||
import { ADMIN, AUTH_MODE_JWT, MEMBER } from "../../variables";
|
||||
import { ADMIN, AuthMode, MEMBER } from "../../variables";
|
||||
const router = express.Router();
|
||||
|
||||
router.post(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT]
|
||||
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -27,7 +27,7 @@ router.post(
|
||||
router.put(
|
||||
"/:id",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT]
|
||||
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
param("id").exists().isString().trim(),
|
||||
body("secretImports").exists().isArray(),
|
||||
@ -40,7 +40,7 @@ router.put(
|
||||
router.delete(
|
||||
"/:id",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT]
|
||||
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
param("id").exists().isString().trim(),
|
||||
body("secretImportPath").isString().exists().trim(),
|
||||
@ -52,7 +52,7 @@ router.delete(
|
||||
router.get(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT]
|
||||
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -68,7 +68,7 @@ router.get(
|
||||
router.get(
|
||||
"/secrets",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT]
|
||||
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -1,27 +1,23 @@
|
||||
import express from "express";
|
||||
const router = express.Router();
|
||||
import {
|
||||
requireAuth,
|
||||
requireWorkspaceAuth,
|
||||
validateRequest,
|
||||
} from "../../middleware";
|
||||
import { body, param, query } from "express-validator";
|
||||
import {
|
||||
createFolder,
|
||||
deleteFolder,
|
||||
getFolders,
|
||||
updateFolderById,
|
||||
updateFolderById
|
||||
} from "../../controllers/v1/secretsFolderController";
|
||||
import { ADMIN, MEMBER } from "../../variables";
|
||||
import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware";
|
||||
import { ADMIN, AuthMode, MEMBER } from "../../variables";
|
||||
const router = express.Router();
|
||||
|
||||
router.post(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: "body",
|
||||
locationWorkspaceId: "body"
|
||||
}),
|
||||
body("workspaceId").exists(),
|
||||
body("environment").exists(),
|
||||
@ -34,7 +30,7 @@ router.post(
|
||||
router.patch(
|
||||
"/:folderId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
body("workspaceId").exists(),
|
||||
body("environment").exists(),
|
||||
@ -46,7 +42,7 @@ router.patch(
|
||||
router.delete(
|
||||
"/:folderId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
body("workspaceId").exists(),
|
||||
body("environment").exists(),
|
||||
@ -58,7 +54,7 @@ router.delete(
|
||||
router.get(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: ["jwt"],
|
||||
acceptedAuthModes: [AuthMode.JWT,AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
query("workspaceId").exists().isString().trim(),
|
||||
query("environment").exists().isString().trim(),
|
||||
|
@ -9,8 +9,8 @@ import {
|
||||
import { body } from "express-validator";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_JWT,
|
||||
MEMBER,
|
||||
AuthMode,
|
||||
MEMBER
|
||||
} from "../../variables";
|
||||
import { serviceTokenController } from "../../controllers/v1";
|
||||
|
||||
@ -25,7 +25,7 @@ router.get(
|
||||
router.post(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -2,14 +2,12 @@ import express from "express";
|
||||
const router = express.Router();
|
||||
import { requireAuth } from "../../middleware";
|
||||
import { userController } from "../../controllers/v1";
|
||||
import {
|
||||
AUTH_MODE_JWT,
|
||||
} from "../../variables";
|
||||
import { AuthMode } from "../../variables";
|
||||
|
||||
router.get(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
userController.getUser
|
||||
);
|
||||
|
@ -3,13 +3,13 @@ const router = express.Router();
|
||||
import { requireAuth, validateRequest } from "../../middleware";
|
||||
import { body, query } from "express-validator";
|
||||
import { userActionController } from "../../controllers/v1";
|
||||
import { AUTH_MODE_JWT } from "../../variables";
|
||||
import { AuthMode } from "../../variables";
|
||||
|
||||
// note: [userAction] will be deprecated in /v2 in favor of [action]
|
||||
router.post(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
body("action"),
|
||||
validateRequest,
|
||||
@ -19,7 +19,7 @@ router.post(
|
||||
router.get(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
query("action"),
|
||||
validateRequest,
|
||||
|
@ -2,13 +2,13 @@ import express from "express";
|
||||
const router = express.Router();
|
||||
import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware";
|
||||
import { body, param, query } from "express-validator";
|
||||
import { ADMIN, AUTH_MODE_JWT, MEMBER } from "../../variables";
|
||||
import { ADMIN, AuthMode, MEMBER } from "../../variables";
|
||||
import { webhookController } from "../../controllers/v1";
|
||||
|
||||
router.post(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT]
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -27,7 +27,7 @@ router.post(
|
||||
router.patch(
|
||||
"/:webhookId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT]
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("webhookId").exists().isString().trim(),
|
||||
body("isDisabled").default(false).isBoolean(),
|
||||
@ -38,7 +38,7 @@ router.patch(
|
||||
router.post(
|
||||
"/:webhookId/test",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT]
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("webhookId").exists().isString().trim(),
|
||||
validateRequest,
|
||||
@ -48,7 +48,7 @@ router.post(
|
||||
router.delete(
|
||||
"/:webhookId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT]
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("webhookId").exists().isString().trim(),
|
||||
validateRequest,
|
||||
@ -58,7 +58,7 @@ router.delete(
|
||||
router.get(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT]
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -8,16 +8,15 @@ import {
|
||||
} from "../../middleware";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
MEMBER,
|
||||
AuthMode,
|
||||
MEMBER
|
||||
} from "../../variables";
|
||||
import { membershipController, workspaceController } from "../../controllers/v1";
|
||||
|
||||
router.get(
|
||||
"/:workspaceId/keys",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -31,7 +30,7 @@ router.get(
|
||||
router.get(
|
||||
"/:workspaceId/users",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -45,7 +44,7 @@ router.get(
|
||||
router.get(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
workspaceController.getWorkspaces
|
||||
);
|
||||
@ -53,7 +52,7 @@ router.get(
|
||||
router.get(
|
||||
"/:workspaceId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -67,7 +66,7 @@ router.get(
|
||||
router.post(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
body("workspaceName").exists().trim().notEmpty(),
|
||||
body("organizationId").exists().trim().notEmpty(),
|
||||
@ -78,7 +77,7 @@ router.post(
|
||||
router.delete(
|
||||
"/:workspaceId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
@ -92,7 +91,7 @@ router.delete(
|
||||
router.post(
|
||||
"/:workspaceId/name",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -107,7 +106,7 @@ router.post(
|
||||
router.post(
|
||||
"/:workspaceId/invite-signup",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -122,7 +121,7 @@ router.post(
|
||||
router.get(
|
||||
"/:workspaceId/integrations",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -136,7 +135,7 @@ router.get(
|
||||
router.get(
|
||||
"/:workspaceId/authorizations",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -150,7 +149,7 @@ router.get(
|
||||
router.get(
|
||||
"/:workspaceId/service-tokens", // deprecate
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -9,14 +9,14 @@ import {
|
||||
} from "../../middleware";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_JWT,
|
||||
MEMBER,
|
||||
AuthMode,
|
||||
MEMBER
|
||||
} from "../../variables";
|
||||
|
||||
router.post(
|
||||
"/:workspaceId/environments",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -32,7 +32,7 @@ router.post(
|
||||
router.put(
|
||||
"/:workspaceId/environments",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -49,7 +49,7 @@ router.put(
|
||||
router.delete(
|
||||
"/:workspaceId/environments",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
@ -64,7 +64,7 @@ router.delete(
|
||||
router.get(
|
||||
"/:workspaceId/environments",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [MEMBER, ADMIN],
|
||||
|
@ -10,10 +10,9 @@ import { body, param } from "express-validator";
|
||||
import {
|
||||
ACCEPTED,
|
||||
ADMIN,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AuthMode,
|
||||
MEMBER,
|
||||
OWNER,
|
||||
OWNER
|
||||
} from "../../variables";
|
||||
import { organizationsController } from "../../controllers/v2";
|
||||
|
||||
@ -24,7 +23,7 @@ router.get(
|
||||
param("organizationId").exists().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
@ -40,7 +39,7 @@ router.patch(
|
||||
body("role").exists().isString().trim().isIn([OWNER, ADMIN, MEMBER]),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
@ -59,7 +58,7 @@ router.delete(
|
||||
param("membershipId").exists().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
@ -77,7 +76,7 @@ router.get(
|
||||
param("organizationId").exists().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
@ -91,7 +90,7 @@ router.get(
|
||||
param("organizationId").exists().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
|
@ -8,8 +8,7 @@ import {
|
||||
import { body, param, query } from "express-validator";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AuthMode,
|
||||
MEMBER,
|
||||
PERMISSION_READ_SECRETS,
|
||||
PERMISSION_WRITE_SECRETS,
|
||||
@ -24,7 +23,7 @@ const router = express.Router();
|
||||
router.post(
|
||||
"/batch-create/workspace/:workspaceId/environment/:environment",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -41,7 +40,7 @@ router.post(
|
||||
router.post(
|
||||
"/workspace/:workspaceId/environment/:environment",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -60,7 +59,7 @@ router.get(
|
||||
param("workspaceId").exists().trim(),
|
||||
query("environment").exists(),
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_TOKEN],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -74,7 +73,7 @@ router.get(
|
||||
router.get(
|
||||
"/:secretId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_TOKEN],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN],
|
||||
}),
|
||||
requireSecretAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -87,7 +86,7 @@ router.get(
|
||||
router.delete(
|
||||
"/batch/workspace/:workspaceId/environment/:environmentName",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("workspaceId").exists().isMongoId().trim(),
|
||||
param("environmentName").exists().trim(),
|
||||
@ -103,7 +102,7 @@ router.delete(
|
||||
router.delete(
|
||||
"/:secretId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireSecretAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -117,7 +116,7 @@ router.delete(
|
||||
router.patch(
|
||||
"/batch-modify/workspace/:workspaceId/environment/:environmentName",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
body("secrets").exists().isArray().custom((secrets: ModifySecretRequestBody[]) => secrets.length > 0),
|
||||
param("workspaceId").exists().isMongoId().trim(),
|
||||
@ -133,7 +132,7 @@ router.patch(
|
||||
router.patch(
|
||||
"/workspace/:workspaceId/environment/:environmentName",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
body("secret").isObject(),
|
||||
param("workspaceId").exists().isMongoId().trim(),
|
||||
|
@ -12,10 +12,7 @@ import { body, query } from "express-validator";
|
||||
import { secretsController } from "../../controllers/v2";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AuthMode,
|
||||
MEMBER,
|
||||
PERMISSION_READ_SECRETS,
|
||||
PERMISSION_WRITE_SECRETS,
|
||||
@ -27,7 +24,7 @@ import { BatchSecretRequest } from "../../types/secret";
|
||||
router.post(
|
||||
"/batch",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN]
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -109,7 +106,7 @@ router.post(
|
||||
}),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN]
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -130,12 +127,7 @@ router.get(
|
||||
query("include_imports").optional().default(false).isBoolean(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_SERVICE_ACCOUNT
|
||||
]
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -172,7 +164,7 @@ router.patch(
|
||||
}),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN]
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
requireSecretsAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -201,7 +193,7 @@ router.delete(
|
||||
.isEmpty(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY, AUTH_MODE_SERVICE_TOKEN]
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
requireSecretsAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -1,159 +1,158 @@
|
||||
import express from "express";
|
||||
const router = express.Router();
|
||||
import {
|
||||
requireAuth,
|
||||
requireOrganizationAuth,
|
||||
requireServiceAccountAuth,
|
||||
requireServiceAccountWorkspacePermissionAuth,
|
||||
requireWorkspaceAuth,
|
||||
validateRequest,
|
||||
} from "../../middleware";
|
||||
import { body, param, query } from "express-validator";
|
||||
import {
|
||||
ACCEPTED,
|
||||
ADMIN,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
MEMBER,
|
||||
OWNER,
|
||||
} from "../../variables";
|
||||
import { serviceAccountsController } from "../../controllers/v2";
|
||||
// import {
|
||||
// requireAuth,
|
||||
// requireOrganizationAuth,
|
||||
// requireServiceAccountAuth,
|
||||
// requireServiceAccountWorkspacePermissionAuth,
|
||||
// requireWorkspaceAuth,
|
||||
// validateRequest,
|
||||
// } from "../../middleware";
|
||||
// import { body, param, query } from "express-validator";
|
||||
// import {
|
||||
// ACCEPTED,
|
||||
// ADMIN,
|
||||
// MEMBER,
|
||||
// OWNER,
|
||||
// AuthMode
|
||||
// } from "../../variables";
|
||||
// import { serviceAccountsController } from "../../controllers/v2";
|
||||
|
||||
router.get( // TODO: check
|
||||
"/me",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_SERVICE_ACCOUNT],
|
||||
}),
|
||||
serviceAccountsController.getCurrentServiceAccount
|
||||
);
|
||||
// router.get( // TODO: check
|
||||
// "/me",
|
||||
// requireAuth({
|
||||
// acceptedAuthModes: [AUTH_MODE_SERVICE_ACCOUNT],
|
||||
// }),
|
||||
// serviceAccountsController.getCurrentServiceAccount
|
||||
// );
|
||||
|
||||
router.get(
|
||||
"/:serviceAccountId",
|
||||
param("serviceAccountId").exists().isString().trim(),
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
}),
|
||||
requireServiceAccountAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
acceptedStatuses: [ACCEPTED],
|
||||
}),
|
||||
serviceAccountsController.getServiceAccountById
|
||||
);
|
||||
// router.get(
|
||||
// "/:serviceAccountId",
|
||||
// param("serviceAccountId").exists().isString().trim(),
|
||||
// requireAuth({
|
||||
// acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
// }),
|
||||
// requireServiceAccountAuth({
|
||||
// acceptedRoles: [OWNER, ADMIN],
|
||||
// acceptedStatuses: [ACCEPTED],
|
||||
// }),
|
||||
// serviceAccountsController.getServiceAccountById
|
||||
// );
|
||||
|
||||
router.post(
|
||||
"/",
|
||||
body("organizationId").exists().isString().trim(),
|
||||
body("name").exists().isString().trim(),
|
||||
body("publicKey").exists().isString().trim(),
|
||||
body("expiresIn").isNumeric(), // measured in ms
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
acceptedStatuses: [ACCEPTED],
|
||||
locationOrganizationId: "body",
|
||||
}),
|
||||
serviceAccountsController.createServiceAccount
|
||||
);
|
||||
// router.post(
|
||||
// "/",
|
||||
// body("organizationId").exists().isString().trim(),
|
||||
// body("name").exists().isString().trim(),
|
||||
// body("publicKey").exists().isString().trim(),
|
||||
// body("expiresIn").isNumeric(), // measured in ms
|
||||
// validateRequest,
|
||||
// requireAuth({
|
||||
// acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
// }),
|
||||
// requireOrganizationAuth({
|
||||
// acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
// acceptedStatuses: [ACCEPTED],
|
||||
// locationOrganizationId: "body",
|
||||
// }),
|
||||
// serviceAccountsController.createServiceAccount
|
||||
// );
|
||||
|
||||
router.patch(
|
||||
"/:serviceAccountId/name",
|
||||
param("serviceAccountId").exists().isString().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
}),
|
||||
requireServiceAccountAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
acceptedStatuses: [ACCEPTED],
|
||||
}),
|
||||
serviceAccountsController.changeServiceAccountName
|
||||
);
|
||||
// router.patch(
|
||||
// "/:serviceAccountId/name",
|
||||
// param("serviceAccountId").exists().isString().trim(),
|
||||
// validateRequest,
|
||||
// requireAuth({
|
||||
// acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
// }),
|
||||
// requireServiceAccountAuth({
|
||||
// acceptedRoles: [OWNER, ADMIN],
|
||||
// acceptedStatuses: [ACCEPTED],
|
||||
// }),
|
||||
// serviceAccountsController.changeServiceAccountName
|
||||
// );
|
||||
|
||||
router.delete(
|
||||
"/:serviceAccountId",
|
||||
param("serviceAccountId").exists().isString().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
}),
|
||||
requireServiceAccountAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
acceptedStatuses: [ACCEPTED],
|
||||
}),
|
||||
serviceAccountsController.deleteServiceAccount
|
||||
);
|
||||
// router.delete(
|
||||
// "/:serviceAccountId",
|
||||
// param("serviceAccountId").exists().isString().trim(),
|
||||
// validateRequest,
|
||||
// requireAuth({
|
||||
// acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
// }),
|
||||
// requireServiceAccountAuth({
|
||||
// acceptedRoles: [OWNER, ADMIN],
|
||||
// acceptedStatuses: [ACCEPTED],
|
||||
// }),
|
||||
// serviceAccountsController.deleteServiceAccount
|
||||
// );
|
||||
|
||||
router.get(
|
||||
"/:serviceAccountId/permissions/workspace",
|
||||
param("serviceAccountId").exists().isString().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
}),
|
||||
requireServiceAccountAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
acceptedStatuses: [ACCEPTED],
|
||||
}),
|
||||
serviceAccountsController.getServiceAccountWorkspacePermissions
|
||||
);
|
||||
// router.get(
|
||||
// "/:serviceAccountId/permissions/workspace",
|
||||
// param("serviceAccountId").exists().isString().trim(),
|
||||
// validateRequest,
|
||||
// requireAuth({
|
||||
// acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
// }),
|
||||
// requireServiceAccountAuth({
|
||||
// acceptedRoles: [OWNER, ADMIN],
|
||||
// acceptedStatuses: [ACCEPTED],
|
||||
// }),
|
||||
// serviceAccountsController.getServiceAccountWorkspacePermissions
|
||||
// );
|
||||
|
||||
router.post(
|
||||
"/:serviceAccountId/permissions/workspace",
|
||||
param("serviceAccountId").exists().isString().trim(),
|
||||
body("workspaceId").exists().isString().notEmpty(),
|
||||
body("environment").exists().isString().notEmpty(),
|
||||
body("read").isBoolean().optional(),
|
||||
body("write").isBoolean().optional(),
|
||||
body("encryptedKey").exists().isString().notEmpty(),
|
||||
body("nonce").exists().isString().notEmpty(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
}),
|
||||
requireServiceAccountAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
acceptedStatuses: [ACCEPTED],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
locationWorkspaceId: "body",
|
||||
}),
|
||||
serviceAccountsController.addServiceAccountWorkspacePermission
|
||||
);
|
||||
// router.post(
|
||||
// "/:serviceAccountId/permissions/workspace",
|
||||
// param("serviceAccountId").exists().isString().trim(),
|
||||
// body("workspaceId").exists().isString().notEmpty(),
|
||||
// body("environment").exists().isString().notEmpty(),
|
||||
// body("read").isBoolean().optional(),
|
||||
// body("write").isBoolean().optional(),
|
||||
// body("encryptedKey").exists().isString().notEmpty(),
|
||||
// body("nonce").exists().isString().notEmpty(),
|
||||
// validateRequest,
|
||||
// requireAuth({
|
||||
// acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
// }),
|
||||
// requireServiceAccountAuth({
|
||||
// acceptedRoles: [OWNER, ADMIN],
|
||||
// acceptedStatuses: [ACCEPTED],
|
||||
// }),
|
||||
// requireWorkspaceAuth({
|
||||
// acceptedRoles: [ADMIN, MEMBER],
|
||||
// locationWorkspaceId: "body",
|
||||
// }),
|
||||
// serviceAccountsController.addServiceAccountWorkspacePermission
|
||||
// );
|
||||
|
||||
router.delete(
|
||||
"/:serviceAccountId/permissions/workspace/:serviceAccountWorkspacePermissionId",
|
||||
param("serviceAccountId").exists().isString().trim(),
|
||||
param("serviceAccountWorkspacePermissionId").exists().isString().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
}),
|
||||
requireServiceAccountAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
acceptedStatuses: [ACCEPTED],
|
||||
}),
|
||||
requireServiceAccountWorkspacePermissionAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
acceptedStatuses: [ACCEPTED],
|
||||
}),
|
||||
serviceAccountsController.deleteServiceAccountWorkspacePermission
|
||||
);
|
||||
// router.delete(
|
||||
// "/:serviceAccountId/permissions/workspace/:serviceAccountWorkspacePermissionId",
|
||||
// param("serviceAccountId").exists().isString().trim(),
|
||||
// param("serviceAccountWorkspacePermissionId").exists().isString().trim(),
|
||||
// validateRequest,
|
||||
// requireAuth({
|
||||
// acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
// }),
|
||||
// requireServiceAccountAuth({
|
||||
// acceptedRoles: [OWNER, ADMIN],
|
||||
// acceptedStatuses: [ACCEPTED],
|
||||
// }),
|
||||
// requireServiceAccountWorkspacePermissionAuth({
|
||||
// acceptedRoles: [OWNER, ADMIN],
|
||||
// acceptedStatuses: [ACCEPTED],
|
||||
// }),
|
||||
// serviceAccountsController.deleteServiceAccountWorkspacePermission
|
||||
// );
|
||||
|
||||
router.get(
|
||||
"/:serviceAccountId/keys",
|
||||
query("workspaceId").optional().isString(),
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_ACCOUNT],
|
||||
}),
|
||||
requireServiceAccountAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
acceptedStatuses: [ACCEPTED],
|
||||
}),
|
||||
serviceAccountsController.getServiceAccountKeys
|
||||
);
|
||||
// router.get(
|
||||
// "/:serviceAccountId/keys",
|
||||
// query("workspaceId").optional().isString(),
|
||||
// requireAuth({
|
||||
// acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_ACCOUNT],
|
||||
// }),
|
||||
// requireServiceAccountAuth({
|
||||
// acceptedRoles: [OWNER, ADMIN],
|
||||
// acceptedStatuses: [ACCEPTED],
|
||||
// }),
|
||||
// serviceAccountsController.getServiceAccountKeys
|
||||
// );
|
||||
|
||||
export default router;
|
@ -9,9 +9,7 @@ import {
|
||||
import { body, param } from "express-validator";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AuthMode,
|
||||
MEMBER,
|
||||
PERMISSION_WRITE_SECRETS
|
||||
} from "../../variables";
|
||||
@ -20,7 +18,7 @@ import { serviceTokenDataController } from "../../controllers/v2";
|
||||
router.get(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_SERVICE_TOKEN]
|
||||
acceptedAuthModes: [AuthMode.SERVICE_TOKEN]
|
||||
}),
|
||||
serviceTokenDataController.getServiceTokenData
|
||||
);
|
||||
@ -28,7 +26,7 @@ router.get(
|
||||
router.post(
|
||||
"/",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_ACCOUNT]
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -63,7 +61,7 @@ router.post(
|
||||
router.delete(
|
||||
"/:serviceTokenDataId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT]
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
requireServiceTokenDataAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
|
@ -9,14 +9,14 @@ import {
|
||||
} from "../../middleware";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_JWT,
|
||||
MEMBER,
|
||||
AuthMode,
|
||||
MEMBER
|
||||
} from "../../variables";
|
||||
|
||||
router.get(
|
||||
"/:workspaceId/tags",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [MEMBER, ADMIN],
|
||||
@ -30,7 +30,7 @@ router.get(
|
||||
router.delete(
|
||||
"/tags/:tagId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
param("tagId").exists().trim(),
|
||||
validateRequest,
|
||||
@ -40,7 +40,7 @@ router.delete(
|
||||
router.post(
|
||||
"/:workspaceId/tags",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [MEMBER, ADMIN],
|
||||
|
@ -6,10 +6,7 @@ import {
|
||||
} from "../../middleware";
|
||||
import { body, param } from "express-validator";
|
||||
import { usersController } from "../../controllers/v2";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
} from "../../variables";
|
||||
import { AuthMode } from "../../variables";
|
||||
import {
|
||||
AuthProvider
|
||||
} from "../../models";
|
||||
@ -17,7 +14,7 @@ import {
|
||||
router.get(
|
||||
"/me",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
usersController.getMe
|
||||
);
|
||||
@ -25,7 +22,7 @@ router.get(
|
||||
router.patch(
|
||||
"/me/mfa",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
body("isMfaEnabled").exists().isBoolean(),
|
||||
validateRequest,
|
||||
@ -35,7 +32,7 @@ router.patch(
|
||||
router.patch(
|
||||
"/me/name",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
body("firstName").exists().isString(),
|
||||
body("lastName").isString(),
|
||||
@ -46,7 +43,7 @@ router.patch(
|
||||
router.patch(
|
||||
"/me/auth-provider",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
body("authProvider").exists().isString().isIn([
|
||||
AuthProvider.EMAIL,
|
||||
@ -60,7 +57,7 @@ router.patch(
|
||||
router.get(
|
||||
"/me/organizations",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
usersController.getMyOrganizations
|
||||
);
|
||||
@ -68,7 +65,7 @@ router.get(
|
||||
router.get(
|
||||
"/me/api-keys",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
usersController.getMyAPIKeys
|
||||
);
|
||||
@ -76,7 +73,7 @@ router.get(
|
||||
router.post(
|
||||
"/me/api-keys",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
body("name").exists().isString().trim(),
|
||||
body("expiresIn").isNumeric(),
|
||||
@ -87,7 +84,7 @@ router.post(
|
||||
router.delete(
|
||||
"/me/api-keys/:apiKeyDataId",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
param("apiKeyDataId").exists().trim(),
|
||||
validateRequest,
|
||||
@ -97,7 +94,7 @@ router.delete(
|
||||
router.get(
|
||||
"/me/sessions",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
usersController.getMySessions
|
||||
);
|
||||
@ -105,7 +102,7 @@ router.get(
|
||||
router.delete(
|
||||
"/me/sessions",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
usersController.deleteMySessions
|
||||
);
|
||||
|
@ -9,17 +9,15 @@ import {
|
||||
} from "../../middleware";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
MEMBER,
|
||||
AuthMode,
|
||||
MEMBER
|
||||
} from "../../variables";
|
||||
import { workspaceController } from "../../controllers/v2";
|
||||
|
||||
router.post(
|
||||
"/:workspaceId/secrets",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -37,7 +35,7 @@ router.post(
|
||||
router.get(
|
||||
"/:workspaceId/secrets",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_SERVICE_TOKEN],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -53,7 +51,7 @@ router.get(
|
||||
router.get(
|
||||
"/:workspaceId/encrypted-key",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -67,7 +65,7 @@ router.get(
|
||||
router.get(
|
||||
"/:workspaceId/service-token-data",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -83,7 +81,7 @@ router.get( // new - TODO: rewire dashboard to this route
|
||||
param("workspaceId").exists().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
@ -99,7 +97,7 @@ router.patch( // TODO - rewire dashboard to this route
|
||||
body("role").exists().isString().trim().isIn([ADMIN, MEMBER]),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
@ -118,7 +116,7 @@ router.delete( // TODO - rewire dashboard to this route
|
||||
param("membershipId").exists().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
@ -134,7 +132,7 @@ router.delete( // TODO - rewire dashboard to this route
|
||||
router.patch(
|
||||
"/:workspaceId/auto-capitalization",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
|
@ -5,10 +5,7 @@ import { body, param, query } from "express-validator";
|
||||
import { secretsController } from "../../controllers/v3";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AuthMode,
|
||||
MEMBER,
|
||||
PERMISSION_READ_SECRETS,
|
||||
PERMISSION_WRITE_SECRETS,
|
||||
@ -25,10 +22,9 @@ router.get(
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_SERVICE_ACCOUNT
|
||||
AuthMode.JWT,
|
||||
AuthMode.API_KEY,
|
||||
AuthMode.SERVICE_TOKEN
|
||||
]
|
||||
}),
|
||||
secretsController.getSecretsRaw
|
||||
@ -44,10 +40,9 @@ router.get(
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_SERVICE_ACCOUNT
|
||||
AuthMode.JWT,
|
||||
AuthMode.API_KEY,
|
||||
AuthMode.SERVICE_TOKEN
|
||||
]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
@ -73,10 +68,9 @@ router.post(
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_SERVICE_ACCOUNT
|
||||
AuthMode.JWT,
|
||||
AuthMode.API_KEY,
|
||||
AuthMode.SERVICE_TOKEN
|
||||
]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
@ -102,10 +96,9 @@ router.patch(
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_SERVICE_ACCOUNT
|
||||
AuthMode.JWT,
|
||||
AuthMode.API_KEY,
|
||||
AuthMode.SERVICE_TOKEN
|
||||
]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
@ -130,10 +123,9 @@ router.delete(
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_SERVICE_ACCOUNT
|
||||
AuthMode.JWT,
|
||||
AuthMode.API_KEY,
|
||||
AuthMode.SERVICE_TOKEN
|
||||
]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
@ -156,10 +148,9 @@ router.get(
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_SERVICE_ACCOUNT
|
||||
AuthMode.JWT,
|
||||
AuthMode.API_KEY,
|
||||
AuthMode.SERVICE_TOKEN
|
||||
]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
@ -192,10 +183,9 @@ router.post(
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_SERVICE_ACCOUNT
|
||||
AuthMode.JWT,
|
||||
AuthMode.API_KEY,
|
||||
AuthMode.SERVICE_TOKEN
|
||||
]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
@ -220,10 +210,9 @@ router.get(
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_SERVICE_ACCOUNT
|
||||
AuthMode.JWT,
|
||||
AuthMode.API_KEY,
|
||||
AuthMode.SERVICE_TOKEN
|
||||
]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
@ -250,10 +239,9 @@ router.patch(
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_SERVICE_ACCOUNT
|
||||
AuthMode.JWT,
|
||||
AuthMode.API_KEY,
|
||||
AuthMode.SERVICE_TOKEN
|
||||
]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
@ -278,10 +266,9 @@ router.delete(
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
AUTH_MODE_SERVICE_ACCOUNT
|
||||
AuthMode.JWT,
|
||||
AuthMode.API_KEY,
|
||||
AuthMode.SERVICE_TOKEN
|
||||
]
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
import { workspacesController } from "../../controllers/v3";
|
||||
import {
|
||||
ADMIN,
|
||||
AUTH_MODE_JWT,
|
||||
AuthMode
|
||||
} from "../../variables";
|
||||
import { body, param } from "express-validator";
|
||||
|
||||
@ -19,7 +19,7 @@ router.get(
|
||||
param("workspaceId").exists().isString().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
@ -33,7 +33,7 @@ router.get( // allow admins to get all workspace secrets (part of blind indices
|
||||
param("workspaceId").exists().isString().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
@ -65,7 +65,7 @@ router.post( // allow admins to name all workspace secrets (part of blind indice
|
||||
.withMessage("secretId must be a string"),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AUTH_MODE_JWT],
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireWorkspaceAuth({
|
||||
acceptedRoles: [ADMIN],
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { Types } from "mongoose";
|
||||
import Folder, { TFolderSchema } from "../models/folder";
|
||||
import path from "path";
|
||||
|
||||
type TAppendFolderDTO = {
|
||||
folderName: string;
|
||||
@ -58,7 +59,7 @@ const appendChild = (folders: TFolderSchema, folderName: string) => {
|
||||
id,
|
||||
name: folderName,
|
||||
children: [],
|
||||
version: 1,
|
||||
version: 1
|
||||
});
|
||||
return { id, name: folderName };
|
||||
};
|
||||
@ -108,10 +109,7 @@ export const deleteFolderById = (folders: TFolderSchema, folderId: string) => {
|
||||
};
|
||||
|
||||
// bfs but return parent of the folderID
|
||||
export const getParentFromFolderId = (
|
||||
folders: TFolderSchema,
|
||||
folderId: string
|
||||
) => {
|
||||
export const getParentFromFolderId = (folders: TFolderSchema, folderId: string) => {
|
||||
const queue = [folders];
|
||||
while (queue.length) {
|
||||
const folder = queue.pop() as TFolderSchema;
|
||||
@ -140,10 +138,7 @@ export const getAllFolderIds = (folders: TFolderSchema) => {
|
||||
// We then record the number of childs of each root node
|
||||
// When we reach leaf node or when all childs of a root node are visited
|
||||
// We remove it from path recorded by using the total child record
|
||||
export const searchByFolderIdWithDir = (
|
||||
folders: TFolderSchema,
|
||||
folderId: string
|
||||
) => {
|
||||
export const searchByFolderIdWithDir = (folders: TFolderSchema, folderId: string) => {
|
||||
const stack = [folders];
|
||||
const dir: Array<{ id: string; name: string }> = [];
|
||||
const hits: Record<string, number> = {};
|
||||
@ -172,6 +167,20 @@ export const searchByFolderIdWithDir = (
|
||||
return;
|
||||
};
|
||||
|
||||
// used for get folder path from id
|
||||
export const getFolderWithPathFromId = (folders: TFolderSchema, parentFolderId: string) => {
|
||||
const search = searchByFolderIdWithDir(folders, parentFolderId);
|
||||
if (!search) {
|
||||
throw { message: "Folder permission denied" };
|
||||
}
|
||||
const { folder, dir } = search;
|
||||
const folderPath = path.join(
|
||||
"/",
|
||||
...dir.filter(({ name }) => name !== "root").map(({ name }) => name)
|
||||
);
|
||||
return { folder, folderPath, dir };
|
||||
};
|
||||
|
||||
// to get folder of a path given
|
||||
// Like /frontend/folder#1
|
||||
export const getFolderByPath = (folders: TFolderSchema, searchPath: string) => {
|
||||
@ -201,7 +210,7 @@ export const getFolderIdFromServiceToken = async (
|
||||
) => {
|
||||
const folders = await Folder.findOne({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
environment
|
||||
});
|
||||
|
||||
if (!folders) {
|
||||
|
4
backend/src/types/express/index.d.ts
vendored
4
backend/src/types/express/index.d.ts
vendored
@ -1,8 +1,6 @@
|
||||
import { Types } from "mongoose";
|
||||
|
||||
|
||||
import {
|
||||
AuthData,
|
||||
AuthData
|
||||
} from "../../interfaces/middleware";
|
||||
|
||||
declare module "express" {
|
||||
|
1
backend/src/types/secret/index.d.ts
vendored
1
backend/src/types/secret/index.d.ts
vendored
@ -30,6 +30,7 @@ export interface BatchSecretRequest {
|
||||
export interface BatchSecret {
|
||||
_id: string;
|
||||
type: "shared" | "personal";
|
||||
secretName: string;
|
||||
secretBlindIndex: string;
|
||||
secretKeyCiphertext: string;
|
||||
secretKeyIV: string;
|
||||
|
@ -1,15 +1,15 @@
|
||||
const CLI_USER_AGENT_NAME = "cli"
|
||||
const K8_OPERATOR_AGENT_NAME = "k8-operator"
|
||||
export const getChannelFromUserAgent = function (userAgent: string | undefined) {
|
||||
import { UserAgentType } from "../ee/models"
|
||||
|
||||
export const getUserAgentType = function (userAgent: string | undefined) {
|
||||
if (userAgent == undefined) {
|
||||
return "other"
|
||||
} else if (userAgent == CLI_USER_AGENT_NAME) {
|
||||
return "cli"
|
||||
} else if (userAgent == K8_OPERATOR_AGENT_NAME) {
|
||||
return "k8-operator"
|
||||
return UserAgentType.OTHER;
|
||||
} else if (userAgent == UserAgentType.CLI) {
|
||||
return UserAgentType.CLI;
|
||||
} else if (userAgent == UserAgentType.K8_OPERATOR) {
|
||||
return UserAgentType.K8_OPERATOR;
|
||||
} else if (userAgent.toLowerCase().includes("mozilla")) {
|
||||
return "web"
|
||||
return UserAgentType.WEB;
|
||||
} else {
|
||||
return "other"
|
||||
return UserAgentType.OTHER;
|
||||
}
|
||||
}
|
@ -1,25 +1,15 @@
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
Bot,
|
||||
IServiceAccount,
|
||||
IServiceTokenData,
|
||||
IUser,
|
||||
ServiceAccount,
|
||||
ServiceTokenData,
|
||||
User,
|
||||
} from "../models";
|
||||
import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
|
||||
import { validateUserClientForWorkspace } from "./user";
|
||||
import {
|
||||
BotNotFoundError,
|
||||
UnauthorizedRequestError,
|
||||
} from "../utils/errors";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
} from "../variables";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
import { ActorType } from "../ee/models";
|
||||
|
||||
/**
|
||||
* Validate authenticated clients for bot with id [botId] based
|
||||
@ -34,65 +24,24 @@ export const validateClientForBot = async ({
|
||||
botId,
|
||||
acceptedRoles,
|
||||
}: {
|
||||
authData: {
|
||||
authMode: string;
|
||||
authPayload: IUser | IServiceAccount | IServiceTokenData;
|
||||
};
|
||||
authData: AuthData;
|
||||
botId: Types.ObjectId;
|
||||
acceptedRoles: Array<"admin" | "member">;
|
||||
}) => {
|
||||
const bot = await Bot.findById(botId);
|
||||
|
||||
if (!bot) throw BotNotFoundError();
|
||||
|
||||
if (
|
||||
authData.authMode === AUTH_MODE_JWT &&
|
||||
authData.authPayload instanceof User
|
||||
) {
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload,
|
||||
workspaceId: bot.workspace,
|
||||
acceptedRoles,
|
||||
});
|
||||
|
||||
return bot;
|
||||
|
||||
switch (authData.actor.type) {
|
||||
case ActorType.USER:
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload as IUser,
|
||||
workspaceId: bot.workspace,
|
||||
acceptedRoles,
|
||||
});
|
||||
return bot;
|
||||
case ActorType.SERVICE:
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for bot",
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
authData.authMode === AUTH_MODE_SERVICE_ACCOUNT &&
|
||||
authData.authPayload instanceof ServiceAccount
|
||||
) {
|
||||
await validateServiceAccountClientForWorkspace({
|
||||
serviceAccount: authData.authPayload,
|
||||
workspaceId: bot.workspace,
|
||||
});
|
||||
|
||||
return bot;
|
||||
}
|
||||
|
||||
if (
|
||||
authData.authMode === AUTH_MODE_SERVICE_TOKEN &&
|
||||
authData.authPayload instanceof ServiceTokenData
|
||||
) {
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for bot",
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
authData.authMode === AUTH_MODE_API_KEY &&
|
||||
authData.authPayload instanceof User
|
||||
) {
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload,
|
||||
workspaceId: bot.workspace,
|
||||
acceptedRoles,
|
||||
});
|
||||
|
||||
return bot;
|
||||
}
|
||||
|
||||
throw BotNotFoundError({
|
||||
message: "Failed client authorization for bot",
|
||||
});
|
||||
};
|
@ -1,15 +1,9 @@
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
IServiceAccount,
|
||||
IServiceTokenData,
|
||||
IUser,
|
||||
Integration,
|
||||
IntegrationAuth,
|
||||
ServiceAccount,
|
||||
ServiceTokenData,
|
||||
User,
|
||||
} from "../models";
|
||||
import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
|
||||
import { validateUserClientForWorkspace } from "./user";
|
||||
import { IntegrationService } from "../services";
|
||||
import {
|
||||
@ -17,12 +11,8 @@ import {
|
||||
IntegrationNotFoundError,
|
||||
UnauthorizedRequestError,
|
||||
} from "../utils/errors";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
} from "../variables";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
import { ActorType } from "../ee/models";
|
||||
|
||||
/**
|
||||
* Validate authenticated clients for integration with id [integrationId] based
|
||||
@ -39,10 +29,7 @@ export const validateClientForIntegration = async ({
|
||||
integrationId,
|
||||
acceptedRoles,
|
||||
}: {
|
||||
authData: {
|
||||
authMode: string;
|
||||
authPayload: IUser | IServiceAccount | IServiceTokenData;
|
||||
};
|
||||
authData: AuthData;
|
||||
integrationId: Types.ObjectId;
|
||||
acceptedRoles: Array<"admin" | "member">;
|
||||
}) => {
|
||||
@ -61,43 +48,19 @@ export const validateClientForIntegration = async ({
|
||||
const accessToken = (await IntegrationService.getIntegrationAuthAccess({
|
||||
integrationAuthId: integrationAuth._id,
|
||||
})).accessToken;
|
||||
|
||||
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload,
|
||||
workspaceId: integration.workspace,
|
||||
acceptedRoles,
|
||||
});
|
||||
|
||||
return ({ integration, accessToken });
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) {
|
||||
await validateServiceAccountClientForWorkspace({
|
||||
serviceAccount: authData.authPayload,
|
||||
workspaceId: integration.workspace,
|
||||
});
|
||||
switch (authData.actor.type) {
|
||||
case ActorType.USER:
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload as IUser,
|
||||
workspaceId: integration.workspace,
|
||||
acceptedRoles,
|
||||
});
|
||||
|
||||
return ({ integration, accessToken });
|
||||
return ({ integration, accessToken });
|
||||
case ActorType.SERVICE:
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for integration",
|
||||
});
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for integration",
|
||||
});
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload,
|
||||
workspaceId: integration.workspace,
|
||||
acceptedRoles,
|
||||
});
|
||||
|
||||
return ({ integration, accessToken });
|
||||
}
|
||||
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed client authorization for integration",
|
||||
});
|
||||
}
|
@ -1,27 +1,17 @@
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
IServiceAccount,
|
||||
IServiceTokenData,
|
||||
IUser,
|
||||
IWorkspace,
|
||||
IntegrationAuth,
|
||||
ServiceAccount,
|
||||
ServiceTokenData,
|
||||
User,
|
||||
} from "../models";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
} from "../variables";
|
||||
import {
|
||||
IntegrationAuthNotFoundError,
|
||||
UnauthorizedRequestError,
|
||||
} from "../utils/errors";
|
||||
import { IntegrationService } from "../services";
|
||||
import { validateUserClientForWorkspace } from "./user";
|
||||
import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
import { ActorType } from "../ee/models";
|
||||
|
||||
/**
|
||||
* Validate authenticated clients for integration authorization with id [integrationAuthId] based
|
||||
@ -38,10 +28,7 @@ import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
|
||||
acceptedRoles,
|
||||
attachAccessToken,
|
||||
}: {
|
||||
authData: {
|
||||
authMode: string;
|
||||
authPayload: IUser | IServiceAccount | IServiceTokenData;
|
||||
};
|
||||
authData: AuthData;
|
||||
integrationAuthId: Types.ObjectId;
|
||||
acceptedRoles: Array<"admin" | "member">;
|
||||
attachAccessToken?: boolean;
|
||||
@ -66,44 +53,20 @@ import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
|
||||
accessId = access.accessId;
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload,
|
||||
workspaceId: integrationAuth.workspace._id,
|
||||
acceptedRoles,
|
||||
});
|
||||
switch (authData.actor.type) {
|
||||
case ActorType.USER:
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload as IUser,
|
||||
workspaceId: integrationAuth.workspace._id,
|
||||
acceptedRoles,
|
||||
});
|
||||
|
||||
return ({ integrationAuth, accessToken, accessId });
|
||||
return ({ integrationAuth, accessToken, accessId });
|
||||
case ActorType.SERVICE:
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for integration authorization",
|
||||
});
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) {
|
||||
await validateServiceAccountClientForWorkspace({
|
||||
serviceAccount: authData.authPayload,
|
||||
workspaceId: integrationAuth.workspace._id,
|
||||
});
|
||||
|
||||
return ({ integrationAuth, accessToken, accessId });
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for integration authorization",
|
||||
});
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload,
|
||||
workspaceId: integrationAuth.workspace._id,
|
||||
acceptedRoles,
|
||||
});
|
||||
|
||||
return ({ integrationAuth, accessToken, accessId });
|
||||
}
|
||||
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed client authorization for integration authorization",
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
|
@ -1,26 +1,16 @@
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
IServiceAccount,
|
||||
IServiceTokenData,
|
||||
IUser,
|
||||
Membership,
|
||||
ServiceAccount,
|
||||
ServiceTokenData,
|
||||
User,
|
||||
} from "../models";
|
||||
import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
|
||||
import { validateUserClientForWorkspace } from "./user";
|
||||
import { validateServiceTokenDataClientForWorkspace } from "./serviceTokenData";
|
||||
import {
|
||||
MembershipNotFoundError,
|
||||
UnauthorizedRequestError,
|
||||
} from "../utils/errors";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
} from "../variables";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
import { ActorType } from "../ee/models";
|
||||
|
||||
/**
|
||||
* Validate authenticated clients for membership with id [membershipId] based
|
||||
@ -36,10 +26,7 @@ export const validateClientForMembership = async ({
|
||||
membershipId,
|
||||
acceptedRoles,
|
||||
}: {
|
||||
authData: {
|
||||
authMode: string;
|
||||
authPayload: IUser | IServiceAccount | IServiceTokenData;
|
||||
};
|
||||
authData: AuthData;
|
||||
membershipId: Types.ObjectId;
|
||||
acceptedRoles: Array<"admin" | "member">;
|
||||
}) => {
|
||||
@ -49,46 +36,22 @@ export const validateClientForMembership = async ({
|
||||
if (!membership) throw MembershipNotFoundError({
|
||||
message: "Failed to find membership",
|
||||
});
|
||||
|
||||
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload,
|
||||
workspaceId: membership.workspace,
|
||||
acceptedRoles,
|
||||
});
|
||||
|
||||
return membership;
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) {
|
||||
await validateServiceAccountClientForWorkspace({
|
||||
serviceAccount: authData.authPayload,
|
||||
workspaceId: membership.workspace,
|
||||
});
|
||||
|
||||
return membership;
|
||||
switch (authData.actor.type) {
|
||||
case ActorType.USER:
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload as IUser,
|
||||
workspaceId: membership.workspace,
|
||||
acceptedRoles,
|
||||
});
|
||||
|
||||
return membership;
|
||||
case ActorType.SERVICE:
|
||||
await validateServiceTokenDataClientForWorkspace({
|
||||
serviceTokenData: authData.authPayload as IServiceTokenData,
|
||||
workspaceId: new Types.ObjectId(membership.workspace),
|
||||
});
|
||||
|
||||
return membership;
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
|
||||
await validateServiceTokenDataClientForWorkspace({
|
||||
serviceTokenData: authData.authPayload,
|
||||
workspaceId: new Types.ObjectId(membership.workspace),
|
||||
});
|
||||
|
||||
return membership;
|
||||
}
|
||||
|
||||
if (authData.authMode == AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload,
|
||||
workspaceId: membership.workspace,
|
||||
acceptedRoles,
|
||||
});
|
||||
|
||||
return membership;
|
||||
}
|
||||
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed client authorization for membership",
|
||||
});
|
||||
}
|
@ -1,12 +1,6 @@
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
IServiceAccount,
|
||||
IServiceTokenData,
|
||||
IUser,
|
||||
MembershipOrg,
|
||||
ServiceAccount,
|
||||
ServiceTokenData,
|
||||
User,
|
||||
} from "../models";
|
||||
import {
|
||||
validateMembershipOrg,
|
||||
@ -15,12 +9,8 @@ import {
|
||||
MembershipOrgNotFoundError,
|
||||
UnauthorizedRequestError,
|
||||
} from "../utils/errors";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
} from "../variables";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
import { ActorType } from "../ee/models";
|
||||
|
||||
/**
|
||||
* Validate authenticated clients for organization membership with id [membershipOrgId] based
|
||||
@ -37,10 +27,7 @@ export const validateClientForMembershipOrg = async ({
|
||||
acceptedRoles,
|
||||
acceptedStatuses,
|
||||
}: {
|
||||
authData: {
|
||||
authMode: string;
|
||||
authPayload: IUser | IServiceAccount | IServiceTokenData;
|
||||
};
|
||||
authData: AuthData;
|
||||
membershipOrgId: Types.ObjectId;
|
||||
acceptedRoles: Array<"owner" | "admin" | "member">;
|
||||
acceptedStatuses: Array<"invited" | "accepted">;
|
||||
@ -50,44 +37,20 @@ export const validateClientForMembershipOrg = async ({
|
||||
if (!membershipOrg) throw MembershipOrgNotFoundError({
|
||||
message: "Failed to find organization membership ",
|
||||
});
|
||||
|
||||
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
|
||||
await validateMembershipOrg({
|
||||
userId: authData.authPayload._id,
|
||||
organizationId: membershipOrg.organization,
|
||||
acceptedRoles,
|
||||
acceptedStatuses,
|
||||
});
|
||||
|
||||
return membershipOrg;
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) {
|
||||
if (!authData.authPayload.organization.equals(membershipOrg.organization)) throw UnauthorizedRequestError({
|
||||
message: "Failed service account client authorization for organization membership",
|
||||
});
|
||||
|
||||
return membershipOrg;
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service account client authorization for organization membership",
|
||||
});
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
|
||||
await validateMembershipOrg({
|
||||
userId: authData.authPayload._id,
|
||||
organizationId: membershipOrg.organization,
|
||||
acceptedRoles,
|
||||
acceptedStatuses,
|
||||
});
|
||||
|
||||
return membershipOrg;
|
||||
switch (authData.actor.type) {
|
||||
case ActorType.USER:
|
||||
await validateMembershipOrg({
|
||||
userId: authData.authPayload._id,
|
||||
organizationId: membershipOrg.organization,
|
||||
acceptedRoles,
|
||||
acceptedStatuses,
|
||||
});
|
||||
|
||||
return membershipOrg;
|
||||
case ActorType.SERVICE:
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service account client authorization for organization membership",
|
||||
});
|
||||
}
|
||||
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed client authorization for organization membership",
|
||||
});
|
||||
}
|
@ -1,25 +1,15 @@
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
IServiceAccount,
|
||||
IServiceTokenData,
|
||||
IUser,
|
||||
Organization,
|
||||
ServiceAccount,
|
||||
ServiceTokenData,
|
||||
User,
|
||||
} from "../models";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
} from "../variables";
|
||||
import {
|
||||
OrganizationNotFoundError,
|
||||
UnauthorizedRequestError,
|
||||
} from "../utils/errors";
|
||||
import { validateUserClientForOrganization } from "./user";
|
||||
import { validateServiceAccountClientForOrganization } from "./serviceAccount";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
import { ActorType } from "../ee/models";
|
||||
|
||||
/**
|
||||
* Validate accepted clients for organization with id [organizationId]
|
||||
@ -33,10 +23,7 @@ export const validateClientForOrganization = async ({
|
||||
acceptedRoles,
|
||||
acceptedStatuses,
|
||||
}: {
|
||||
authData: {
|
||||
authMode: string;
|
||||
authPayload: IUser | IServiceAccount | IServiceTokenData;
|
||||
};
|
||||
authData: AuthData;
|
||||
organizationId: Types.ObjectId;
|
||||
acceptedRoles: Array<"owner" | "admin" | "member">;
|
||||
acceptedStatuses: Array<"invited" | "accepted">;
|
||||
@ -48,57 +35,21 @@ export const validateClientForOrganization = async ({
|
||||
message: "Failed to find organization",
|
||||
});
|
||||
}
|
||||
|
||||
let membershipOrg;
|
||||
switch (authData.actor.type) {
|
||||
case ActorType.USER:
|
||||
membershipOrg = await validateUserClientForOrganization({
|
||||
user: authData.authPayload as IUser,
|
||||
organization,
|
||||
acceptedRoles,
|
||||
acceptedStatuses,
|
||||
});
|
||||
|
||||
if (
|
||||
authData.authMode === AUTH_MODE_JWT &&
|
||||
authData.authPayload instanceof User
|
||||
) {
|
||||
const membershipOrg = await validateUserClientForOrganization({
|
||||
user: authData.authPayload,
|
||||
organization,
|
||||
acceptedRoles,
|
||||
acceptedStatuses,
|
||||
});
|
||||
|
||||
return { organization, membershipOrg };
|
||||
return { organization, membershipOrg };
|
||||
case ActorType.SERVICE:
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for organization",
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
authData.authMode === AUTH_MODE_SERVICE_ACCOUNT &&
|
||||
authData.authPayload instanceof ServiceAccount
|
||||
) {
|
||||
await validateServiceAccountClientForOrganization({
|
||||
serviceAccount: authData.authPayload,
|
||||
organization,
|
||||
});
|
||||
|
||||
return { organization };
|
||||
}
|
||||
|
||||
if (
|
||||
authData.authMode === AUTH_MODE_SERVICE_TOKEN &&
|
||||
authData.authPayload instanceof ServiceTokenData
|
||||
) {
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for organization",
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
authData.authMode === AUTH_MODE_API_KEY &&
|
||||
authData.authPayload instanceof User
|
||||
) {
|
||||
const membershipOrg = await validateUserClientForOrganization({
|
||||
user: authData.authPayload,
|
||||
organization,
|
||||
acceptedRoles,
|
||||
acceptedStatuses,
|
||||
});
|
||||
|
||||
return { organization, membershipOrg };
|
||||
}
|
||||
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed client authorization for organization",
|
||||
});
|
||||
};
|
@ -1,26 +1,18 @@
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
ISecret,
|
||||
IServiceTokenData,
|
||||
IUser,
|
||||
Secret,
|
||||
ServiceAccount,
|
||||
ServiceTokenData,
|
||||
User,
|
||||
} from "../models";
|
||||
import { validateServiceAccountClientForSecrets, validateServiceAccountClientForWorkspace } from "./serviceAccount";
|
||||
import { validateUserClientForSecret, validateUserClientForSecrets } from "./user";
|
||||
import { validateServiceTokenDataClientForSecrets, validateServiceTokenDataClientForWorkspace } from "./serviceTokenData";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
import {
|
||||
BadRequestError,
|
||||
SecretNotFoundError,
|
||||
UnauthorizedRequestError,
|
||||
} from "../utils/errors";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
} from "../variables";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
import { ActorType } from "../ee/models";
|
||||
|
||||
/**
|
||||
* Validate authenticated clients for secrets with id [secretId] based
|
||||
@ -47,53 +39,26 @@ export const validateClientForSecret = async ({
|
||||
if (!secret) throw SecretNotFoundError({
|
||||
message: "Failed to find secret",
|
||||
});
|
||||
|
||||
switch (authData.actor.type) {
|
||||
case ActorType.USER:
|
||||
await validateUserClientForSecret({
|
||||
user: authData.authPayload as IUser,
|
||||
secret,
|
||||
acceptedRoles,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
|
||||
await validateUserClientForSecret({
|
||||
user: authData.authPayload,
|
||||
secret,
|
||||
acceptedRoles,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return secret;
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) {
|
||||
await validateServiceAccountClientForWorkspace({
|
||||
serviceAccount: authData.authPayload,
|
||||
workspaceId: secret.workspace,
|
||||
environment: secret.environment,
|
||||
requiredPermissions,
|
||||
});
|
||||
return secret;
|
||||
case ActorType.SERVICE:
|
||||
await validateServiceTokenDataClientForWorkspace({
|
||||
serviceTokenData: authData.authPayload as IServiceTokenData,
|
||||
workspaceId: secret.workspace,
|
||||
environment: secret.environment,
|
||||
});
|
||||
|
||||
return secret;
|
||||
return secret;
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
|
||||
await validateServiceTokenDataClientForWorkspace({
|
||||
serviceTokenData: authData.authPayload,
|
||||
workspaceId: secret.workspace,
|
||||
environment: secret.environment,
|
||||
});
|
||||
|
||||
return secret;
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
|
||||
await validateUserClientForSecret({
|
||||
user: authData.authPayload,
|
||||
secret,
|
||||
acceptedRoles,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return secret;
|
||||
}
|
||||
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed client authorization for secret",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,48 +92,23 @@ export const validateClientForSecrets = async ({
|
||||
if (secrets.length != secretIds.length) {
|
||||
throw BadRequestError({ message: "Failed to validate non-existent secrets" })
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
|
||||
await validateUserClientForSecrets({
|
||||
user: authData.authPayload,
|
||||
secrets,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return secrets;
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) {
|
||||
await validateServiceAccountClientForSecrets({
|
||||
serviceAccount: authData.authPayload,
|
||||
secrets,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return secrets;
|
||||
switch (authData.actor.type) {
|
||||
case ActorType.USER:
|
||||
await validateUserClientForSecrets({
|
||||
user: authData.authPayload as IUser,
|
||||
secrets,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return secrets;
|
||||
case ActorType.SERVICE:
|
||||
await validateServiceTokenDataClientForSecrets({
|
||||
serviceTokenData: authData.authPayload as IServiceTokenData,
|
||||
secrets,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return secrets;
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
|
||||
await validateServiceTokenDataClientForSecrets({
|
||||
serviceTokenData: authData.authPayload,
|
||||
secrets,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return secrets;
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
|
||||
await validateUserClientForSecrets({
|
||||
user: authData.authPayload,
|
||||
secrets,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return secrets;
|
||||
}
|
||||
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed client authorization for secrets resource",
|
||||
});
|
||||
}
|
@ -4,12 +4,9 @@ import {
|
||||
IOrganization,
|
||||
ISecret,
|
||||
IServiceAccount,
|
||||
IServiceTokenData,
|
||||
IUser,
|
||||
ServiceAccount,
|
||||
ServiceAccountWorkspacePermission,
|
||||
ServiceTokenData,
|
||||
User,
|
||||
} from "../models";
|
||||
import { validateUserClientForServiceAccount } from "./user";
|
||||
import {
|
||||
@ -18,23 +15,18 @@ import {
|
||||
UnauthorizedRequestError,
|
||||
} from "../utils/errors";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
PERMISSION_READ_SECRETS,
|
||||
PERMISSION_WRITE_SECRETS,
|
||||
} from "../variables";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
import { ActorType } from "../ee/models";
|
||||
|
||||
export const validateClientForServiceAccount = async ({
|
||||
authData,
|
||||
serviceAccountId,
|
||||
requiredPermissions,
|
||||
}: {
|
||||
authData: {
|
||||
authMode: string;
|
||||
authPayload: IUser | IServiceAccount | IServiceTokenData;
|
||||
},
|
||||
authData: AuthData;
|
||||
serviceAccountId: Types.ObjectId;
|
||||
requiredPermissions?: string[];
|
||||
}) => {
|
||||
@ -46,45 +38,20 @@ export const validateClientForServiceAccount = async ({
|
||||
});
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
|
||||
await validateUserClientForServiceAccount({
|
||||
user: authData.authPayload,
|
||||
serviceAccount,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return serviceAccount;
|
||||
switch (authData.actor.type) {
|
||||
case ActorType.USER:
|
||||
await validateUserClientForServiceAccount({
|
||||
user: authData.authPayload as IUser,
|
||||
serviceAccount,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return serviceAccount;
|
||||
case ActorType.SERVICE:
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for service account resource",
|
||||
});
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) {
|
||||
await validateServiceAccountClientForServiceAccount({
|
||||
serviceAccount: authData.authPayload,
|
||||
targetServiceAccount: serviceAccount,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return serviceAccount;
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for service account resource",
|
||||
});
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
|
||||
await validateUserClientForServiceAccount({
|
||||
user: authData.authPayload,
|
||||
serviceAccount,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return serviceAccount;
|
||||
}
|
||||
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed client authorization for service account resource",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,22 +1,14 @@
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
ISecret,
|
||||
IServiceAccount,
|
||||
IServiceTokenData,
|
||||
IUser,
|
||||
ServiceAccount,
|
||||
ServiceTokenData,
|
||||
User
|
||||
} from "../models";
|
||||
import { ServiceTokenDataNotFoundError, UnauthorizedRequestError } from "../utils/errors";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN
|
||||
} from "../variables";
|
||||
import { validateUserClientForWorkspace } from "./user";
|
||||
import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
|
||||
import { ActorType } from "../ee/models";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
|
||||
/**
|
||||
* Validate authenticated clients for service token with id [serviceTokenId] based
|
||||
@ -31,10 +23,7 @@ export const validateClientForServiceTokenData = async ({
|
||||
serviceTokenDataId,
|
||||
acceptedRoles
|
||||
}: {
|
||||
authData: {
|
||||
authMode: string;
|
||||
authPayload: IUser | IServiceAccount | IServiceTokenData;
|
||||
};
|
||||
authData: AuthData;
|
||||
serviceTokenDataId: Types.ObjectId;
|
||||
acceptedRoles: Array<"admin" | "member">;
|
||||
}) => {
|
||||
@ -42,55 +31,24 @@ export const validateClientForServiceTokenData = async ({
|
||||
.select("+encryptedKey +iv +tag")
|
||||
.populate<{ user: IUser }>("user");
|
||||
|
||||
if (!serviceTokenData)
|
||||
throw ServiceTokenDataNotFoundError({
|
||||
message: "Failed to find service token data"
|
||||
});
|
||||
|
||||
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload,
|
||||
workspaceId: serviceTokenData.workspace,
|
||||
acceptedRoles
|
||||
});
|
||||
|
||||
return serviceTokenData;
|
||||
}
|
||||
|
||||
if (
|
||||
authData.authMode === AUTH_MODE_SERVICE_ACCOUNT &&
|
||||
authData.authPayload instanceof ServiceAccount
|
||||
) {
|
||||
await validateServiceAccountClientForWorkspace({
|
||||
serviceAccount: authData.authPayload,
|
||||
workspaceId: serviceTokenData.workspace
|
||||
});
|
||||
|
||||
return serviceTokenData;
|
||||
}
|
||||
|
||||
if (
|
||||
authData.authMode === AUTH_MODE_SERVICE_TOKEN &&
|
||||
authData.authPayload instanceof ServiceTokenData
|
||||
) {
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for service token data"
|
||||
});
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload,
|
||||
workspaceId: serviceTokenData.workspace,
|
||||
acceptedRoles
|
||||
});
|
||||
|
||||
return serviceTokenData;
|
||||
}
|
||||
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed client authorization for service token data"
|
||||
if (!serviceTokenData) throw ServiceTokenDataNotFoundError({
|
||||
message: "Failed to find service token data"
|
||||
});
|
||||
|
||||
switch (authData.actor.type) {
|
||||
case ActorType.USER:
|
||||
await validateUserClientForWorkspace({
|
||||
user: authData.authPayload as IUser,
|
||||
workspaceId: serviceTokenData.workspace,
|
||||
acceptedRoles
|
||||
});
|
||||
|
||||
return serviceTokenData;
|
||||
case ActorType.SERVICE:
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for service token data"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,16 +1,15 @@
|
||||
import net from "net";
|
||||
import { Types } from "mongoose";
|
||||
import {
|
||||
SecretBlindIndexData,
|
||||
ServiceAccount,
|
||||
ServiceTokenData,
|
||||
User,
|
||||
IServiceTokenData,
|
||||
IUser,
|
||||
SecretBlindIndexData,
|
||||
Workspace,
|
||||
} from "../models";
|
||||
import {
|
||||
ActorType,
|
||||
TrustedIP
|
||||
} from "../ee/models";
|
||||
import { validateServiceAccountClientForWorkspace } from "./serviceAccount";
|
||||
import { validateUserClientForWorkspace } from "./user";
|
||||
import { validateServiceTokenDataClientForWorkspace } from "./serviceTokenData";
|
||||
import {
|
||||
@ -18,12 +17,6 @@ import {
|
||||
UnauthorizedRequestError,
|
||||
WorkspaceNotFoundError,
|
||||
} from "../utils/errors";
|
||||
import {
|
||||
AUTH_MODE_API_KEY,
|
||||
AUTH_MODE_JWT,
|
||||
AUTH_MODE_SERVICE_ACCOUNT,
|
||||
AUTH_MODE_SERVICE_TOKEN,
|
||||
} from "../variables";
|
||||
import { BotService } from "../services";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
import { extractIPDetails } from "../utils/ip";
|
||||
@ -85,89 +78,60 @@ export const validateClientForWorkspace = async ({
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
let membership;
|
||||
switch (authData.actor.type) {
|
||||
case ActorType.USER:
|
||||
membership = await validateUserClientForWorkspace({
|
||||
user: authData.authPayload as IUser,
|
||||
workspaceId,
|
||||
environment,
|
||||
acceptedRoles,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return ({ membership, workspace });
|
||||
case ActorType.SERVICE:
|
||||
if (checkIPAllowlist) {
|
||||
const trustedIps = await TrustedIP.find({
|
||||
workspace: workspaceId
|
||||
});
|
||||
|
||||
if (trustedIps.length > 0) {
|
||||
// case: check the IP address of the inbound request against trusted IPs
|
||||
|
||||
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
|
||||
const membership = await validateUserClientForWorkspace({
|
||||
user: authData.authPayload,
|
||||
workspaceId,
|
||||
environment,
|
||||
acceptedRoles,
|
||||
requiredPermissions,
|
||||
});
|
||||
const blockList = new net.BlockList();
|
||||
|
||||
return ({ membership, workspace });
|
||||
}
|
||||
for (const trustedIp of trustedIps) {
|
||||
if (trustedIp.prefix !== undefined) {
|
||||
blockList.addSubnet(
|
||||
trustedIp.ipAddress,
|
||||
trustedIp.prefix,
|
||||
trustedIp.type
|
||||
);
|
||||
} else {
|
||||
blockList.addAddress(
|
||||
trustedIp.ipAddress,
|
||||
trustedIp.type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const { type } = extractIPDetails(authData.ipAddress);
|
||||
const check = blockList.check(authData.ipAddress, type);
|
||||
|
||||
if (!check) throw UnauthorizedRequestError({
|
||||
message: "Failed workspace authorization"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) {
|
||||
await validateServiceAccountClientForWorkspace({
|
||||
serviceAccount: authData.authPayload,
|
||||
workspaceId,
|
||||
environment,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_SERVICE_TOKEN && authData.authPayload instanceof ServiceTokenData) {
|
||||
if (checkIPAllowlist) {
|
||||
const trustedIps = await TrustedIP.find({
|
||||
workspace: workspaceId
|
||||
await validateServiceTokenDataClientForWorkspace({
|
||||
serviceTokenData: authData.authPayload as IServiceTokenData,
|
||||
workspaceId,
|
||||
environment,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
if (trustedIps.length > 0) {
|
||||
// case: check the IP address of the inbound request against trusted IPs
|
||||
|
||||
const blockList = new net.BlockList();
|
||||
|
||||
for (const trustedIp of trustedIps) {
|
||||
if (trustedIp.prefix !== undefined) {
|
||||
blockList.addSubnet(
|
||||
trustedIp.ipAddress,
|
||||
trustedIp.prefix,
|
||||
trustedIp.type
|
||||
);
|
||||
} else {
|
||||
blockList.addAddress(
|
||||
trustedIp.ipAddress,
|
||||
trustedIp.type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const { type } = extractIPDetails(authData.authIP);
|
||||
const check = blockList.check(authData.authIP, type);
|
||||
|
||||
if (!check) throw UnauthorizedRequestError({
|
||||
message: "Failed workspace authorization"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await validateServiceTokenDataClientForWorkspace({
|
||||
serviceTokenData: authData.authPayload,
|
||||
workspaceId,
|
||||
environment,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return {};
|
||||
return {};
|
||||
}
|
||||
|
||||
if (authData.authMode === AUTH_MODE_API_KEY && authData.authPayload instanceof User) {
|
||||
const membership = await validateUserClientForWorkspace({
|
||||
user: authData.authPayload,
|
||||
workspaceId,
|
||||
environment,
|
||||
acceptedRoles,
|
||||
requiredPermissions,
|
||||
});
|
||||
|
||||
return ({ membership, workspace });
|
||||
}
|
||||
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed client authorization for workspace",
|
||||
});
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
export const AUTH_MODE_JWT = "jwt";
|
||||
export const AUTH_MODE_SERVICE_ACCOUNT = "serviceAccount";
|
||||
export const AUTH_MODE_SERVICE_TOKEN = "serviceToken";
|
||||
export const AUTH_MODE_API_KEY = "apiKey"; // TODO: deprecate
|
||||
export enum AuthMode {
|
||||
JWT = "jwt",
|
||||
SERVICE_TOKEN = "serviceToken",
|
||||
API_KEY = "apiKey"
|
||||
}
|
@ -1,29 +1,29 @@
|
||||
import { describe, expect, test } from "@jest/globals";
|
||||
import { getChannelFromUserAgent } from "../../../src/utils/posthog";
|
||||
import { getUserAgentType } from "../../../src/utils/posthog";
|
||||
|
||||
describe("posthog getChannelFromUserAgent", () => {
|
||||
test("should return 'web' when userAgent includes 'mozilla'", () => {
|
||||
const userAgent =
|
||||
"Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.5563.115 Mobile Safari/537.36";
|
||||
const channel = getChannelFromUserAgent(userAgent);
|
||||
const channel = getUserAgentType(userAgent);
|
||||
expect(channel).toBe("web");
|
||||
});
|
||||
|
||||
test("should return 'cli'", () => {
|
||||
const userAgent = "cli";
|
||||
const channel = getChannelFromUserAgent(userAgent);
|
||||
const channel = getUserAgentType(userAgent);
|
||||
expect(channel).toBe("cli");
|
||||
});
|
||||
|
||||
test("should return 'k8-operator'", () => {
|
||||
const userAgent = "k8-operator";
|
||||
const channel = getChannelFromUserAgent(userAgent);
|
||||
const channel = getUserAgentType(userAgent);
|
||||
expect(channel).toBe("k8-operator");
|
||||
});
|
||||
|
||||
test("should return undefined if no userAgent", () => {
|
||||
const userAgent = undefined;
|
||||
const channel = getChannelFromUserAgent(userAgent);
|
||||
const channel = getUserAgentType(userAgent);
|
||||
expect(channel).toBe("other");
|
||||
});
|
||||
});
|
||||
|
@ -1,8 +1,22 @@
|
||||
import { themes } from '@storybook/theming';
|
||||
import '../src/styles/globals.css';
|
||||
import { themes } from "@storybook/theming";
|
||||
import "react-day-picker/dist/style.css";
|
||||
import "../src/styles/globals.css";
|
||||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: '^on[A-Z].*' },
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
backgrounds: {
|
||||
default: "dark",
|
||||
values: [
|
||||
{
|
||||
name: "dark",
|
||||
value: "rgb(14, 16, 20)"
|
||||
},
|
||||
{
|
||||
name: "paper",
|
||||
value: "rgb(30, 31, 34)"
|
||||
}
|
||||
]
|
||||
},
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
@ -10,6 +24,6 @@ export const parameters = {
|
||||
}
|
||||
},
|
||||
darkMode: {
|
||||
dark: { ...themes.dark, appContentBg: 'rgb(14,16,20)', appBg: 'rgb(14,16,20)' }
|
||||
dark: { ...themes.dark, appContentBg: "rgb(14,16,20)", appBg: "rgb(14,16,20)" }
|
||||
}
|
||||
};
|
||||
|
244
frontend/package-lock.json
generated
244
frontend/package-lock.json
generated
@ -47,7 +47,7 @@
|
||||
"classnames": "^2.3.1",
|
||||
"cookies": "^0.8.0",
|
||||
"cva": "npm:class-variance-authority@^0.4.0",
|
||||
"dayjs": "^1.11.9",
|
||||
"date-fns": "^2.30.0",
|
||||
"framer-motion": "^6.2.3",
|
||||
"fs": "^0.0.2",
|
||||
"gray-matter": "^4.0.3",
|
||||
@ -69,6 +69,7 @@
|
||||
"react-beautiful-dnd": "^13.1.1",
|
||||
"react-code-input": "^3.10.1",
|
||||
"react-contenteditable": "^3.3.7",
|
||||
"react-day-picker": "^8.8.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
"react-hook-form": "^7.43.0",
|
||||
@ -95,6 +96,7 @@
|
||||
"@storybook/addon-links": "^7.0.23",
|
||||
"@storybook/addon-styling": "^1.3.0",
|
||||
"@storybook/blocks": "^7.0.23",
|
||||
"@storybook/client-api": "^7.2.1",
|
||||
"@storybook/nextjs": "^7.0.23",
|
||||
"@storybook/react": "^7.0.23",
|
||||
"@storybook/testing-library": "^0.2.0",
|
||||
@ -5781,6 +5783,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/builder-webpack5/node_modules/@storybook/client-api": {
|
||||
"version": "7.0.23",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-7.0.23.tgz",
|
||||
"integrity": "sha512-Z2ubbWJXORuhb1Faur3DL5zV8OObanQY7ow506CmEwNKRgy2LVzkBwpm4woEJHgw95sOyGuz3f3xfDP2DC6M7A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@storybook/client-logger": "7.0.23",
|
||||
"@storybook/preview-api": "7.0.23"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/storybook"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/builder-webpack5/node_modules/@types/node": {
|
||||
"version": "16.18.36",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.36.tgz",
|
||||
@ -6126,13 +6142,96 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@storybook/client-api": {
|
||||
"version": "7.0.23",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-7.0.23.tgz",
|
||||
"integrity": "sha512-Z2ubbWJXORuhb1Faur3DL5zV8OObanQY7ow506CmEwNKRgy2LVzkBwpm4woEJHgw95sOyGuz3f3xfDP2DC6M7A==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-7.2.1.tgz",
|
||||
"integrity": "sha512-VeRUxc4ufSaGAQPe/LM4aucpEx2UHHw9c+tzolV3hzGIp6pmIAS8XI6thL2IccYmsNMS2zz9oDESYP9cNlTsyA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@storybook/client-logger": "7.0.23",
|
||||
"@storybook/preview-api": "7.0.23"
|
||||
"@storybook/client-logger": "7.2.1",
|
||||
"@storybook/preview-api": "7.2.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/storybook"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/client-api/node_modules/@storybook/channels": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.2.1.tgz",
|
||||
"integrity": "sha512-3ZogzjwlFG+oarwnI7TTvWvHVOUtJbjrgZkM5QuLMlxNzIR1XuBY8f01yf4K8+VpdNy9DY+7Q/j6tBThfwYvpA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@storybook/client-logger": "7.2.1",
|
||||
"@storybook/core-events": "7.2.1",
|
||||
"@storybook/global": "^5.0.0",
|
||||
"qs": "^6.10.0",
|
||||
"telejson": "^7.0.3",
|
||||
"tiny-invariant": "^1.3.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/storybook"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/client-api/node_modules/@storybook/client-logger": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.2.1.tgz",
|
||||
"integrity": "sha512-Lyht/lJg2S65CXRy9rXAZXP/Mgye7jbi/aqQL8z9VRMGChbL+k/3pSZnXTTrD1OVSpCEr4UWA+9bStzT4VjtYA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@storybook/global": "^5.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/storybook"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/client-api/node_modules/@storybook/core-events": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.2.1.tgz",
|
||||
"integrity": "sha512-EUXYb3gyQ2EzpDAWkgfoDl1EPabj3OE6+zntsD/gwvzQU85BTocs10ksnRyS55bfrQpYbf+Z+gw2CZboyagLgg==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/storybook"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/client-api/node_modules/@storybook/preview-api": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.2.1.tgz",
|
||||
"integrity": "sha512-WKecuOdeh9+og6bPR9KoQf/JCeSRPCcfZv9uNfJzAp3IiTnS3UpfCz+HBZzZJQrisgbd7OulNY400HQUmxY2Ag==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@storybook/channels": "7.2.1",
|
||||
"@storybook/client-logger": "7.2.1",
|
||||
"@storybook/core-events": "7.2.1",
|
||||
"@storybook/csf": "^0.1.0",
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/types": "7.2.1",
|
||||
"@types/qs": "^6.9.5",
|
||||
"dequal": "^2.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"memoizerific": "^1.11.3",
|
||||
"qs": "^6.10.0",
|
||||
"synchronous-promise": "^2.0.15",
|
||||
"ts-dedent": "^2.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/storybook"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/client-api/node_modules/@storybook/types": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.2.1.tgz",
|
||||
"integrity": "sha512-YwlIY1uyxfJjijbB5x1d1QOKaUUDJnMX8BSb8oGqU4cyT76X/Is4CbGs+vccFsJo0tZu1GfuahYXl0EDT0nnSQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@storybook/channels": "7.2.1",
|
||||
"@types/babel__core": "^7.0.0",
|
||||
"@types/express": "^4.7.0",
|
||||
"file-system-cache": "2.3.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@ -10724,10 +10823,20 @@
|
||||
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.9",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz",
|
||||
"integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA=="
|
||||
"node_modules/date-fns": {
|
||||
"version": "2.30.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
|
||||
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.11"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/date-fns"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
@ -19041,6 +19150,19 @@
|
||||
"react": ">=16.3"
|
||||
}
|
||||
},
|
||||
"node_modules/react-day-picker": {
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.8.0.tgz",
|
||||
"integrity": "sha512-QIC3uOuyGGbtypbd5QEggsCSqVaPNu8kzUWquZ7JjW9fuWB9yv7WyixKmnaFelTLXFdq7h7zU6n/aBleBqe/dA==",
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/gpbl"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"date-fns": "^2.28.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-docgen": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz",
|
||||
@ -26972,6 +27094,16 @@
|
||||
"webpack-virtual-modules": "^0.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/client-api": {
|
||||
"version": "7.0.23",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-7.0.23.tgz",
|
||||
"integrity": "sha512-Z2ubbWJXORuhb1Faur3DL5zV8OObanQY7ow506CmEwNKRgy2LVzkBwpm4woEJHgw95sOyGuz3f3xfDP2DC6M7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@storybook/client-logger": "7.0.23",
|
||||
"@storybook/preview-api": "7.0.23"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "16.18.36",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.36.tgz",
|
||||
@ -27215,13 +27347,78 @@
|
||||
}
|
||||
},
|
||||
"@storybook/client-api": {
|
||||
"version": "7.0.23",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-7.0.23.tgz",
|
||||
"integrity": "sha512-Z2ubbWJXORuhb1Faur3DL5zV8OObanQY7ow506CmEwNKRgy2LVzkBwpm4woEJHgw95sOyGuz3f3xfDP2DC6M7A==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-7.2.1.tgz",
|
||||
"integrity": "sha512-VeRUxc4ufSaGAQPe/LM4aucpEx2UHHw9c+tzolV3hzGIp6pmIAS8XI6thL2IccYmsNMS2zz9oDESYP9cNlTsyA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@storybook/client-logger": "7.0.23",
|
||||
"@storybook/preview-api": "7.0.23"
|
||||
"@storybook/client-logger": "7.2.1",
|
||||
"@storybook/preview-api": "7.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/channels": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.2.1.tgz",
|
||||
"integrity": "sha512-3ZogzjwlFG+oarwnI7TTvWvHVOUtJbjrgZkM5QuLMlxNzIR1XuBY8f01yf4K8+VpdNy9DY+7Q/j6tBThfwYvpA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@storybook/client-logger": "7.2.1",
|
||||
"@storybook/core-events": "7.2.1",
|
||||
"@storybook/global": "^5.0.0",
|
||||
"qs": "^6.10.0",
|
||||
"telejson": "^7.0.3",
|
||||
"tiny-invariant": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"@storybook/client-logger": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.2.1.tgz",
|
||||
"integrity": "sha512-Lyht/lJg2S65CXRy9rXAZXP/Mgye7jbi/aqQL8z9VRMGChbL+k/3pSZnXTTrD1OVSpCEr4UWA+9bStzT4VjtYA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@storybook/global": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"@storybook/core-events": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.2.1.tgz",
|
||||
"integrity": "sha512-EUXYb3gyQ2EzpDAWkgfoDl1EPabj3OE6+zntsD/gwvzQU85BTocs10ksnRyS55bfrQpYbf+Z+gw2CZboyagLgg==",
|
||||
"dev": true
|
||||
},
|
||||
"@storybook/preview-api": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.2.1.tgz",
|
||||
"integrity": "sha512-WKecuOdeh9+og6bPR9KoQf/JCeSRPCcfZv9uNfJzAp3IiTnS3UpfCz+HBZzZJQrisgbd7OulNY400HQUmxY2Ag==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@storybook/channels": "7.2.1",
|
||||
"@storybook/client-logger": "7.2.1",
|
||||
"@storybook/core-events": "7.2.1",
|
||||
"@storybook/csf": "^0.1.0",
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/types": "7.2.1",
|
||||
"@types/qs": "^6.9.5",
|
||||
"dequal": "^2.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"memoizerific": "^1.11.3",
|
||||
"qs": "^6.10.0",
|
||||
"synchronous-promise": "^2.0.15",
|
||||
"ts-dedent": "^2.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"@storybook/types": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.2.1.tgz",
|
||||
"integrity": "sha512-YwlIY1uyxfJjijbB5x1d1QOKaUUDJnMX8BSb8oGqU4cyT76X/Is4CbGs+vccFsJo0tZu1GfuahYXl0EDT0nnSQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@storybook/channels": "7.2.1",
|
||||
"@types/babel__core": "^7.0.0",
|
||||
"@types/express": "^4.7.0",
|
||||
"file-system-cache": "2.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@storybook/client-logger": {
|
||||
@ -30800,10 +30997,13 @@
|
||||
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
|
||||
"dev": true
|
||||
},
|
||||
"dayjs": {
|
||||
"version": "1.11.9",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz",
|
||||
"integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA=="
|
||||
"date-fns": {
|
||||
"version": "2.30.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
|
||||
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
@ -36915,6 +37115,12 @@
|
||||
"prop-types": "^15.7.1"
|
||||
}
|
||||
},
|
||||
"react-day-picker": {
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.8.0.tgz",
|
||||
"integrity": "sha512-QIC3uOuyGGbtypbd5QEggsCSqVaPNu8kzUWquZ7JjW9fuWB9yv7WyixKmnaFelTLXFdq7h7zU6n/aBleBqe/dA==",
|
||||
"requires": {}
|
||||
},
|
||||
"react-docgen": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz",
|
||||
|
@ -55,7 +55,7 @@
|
||||
"classnames": "^2.3.1",
|
||||
"cookies": "^0.8.0",
|
||||
"cva": "npm:class-variance-authority@^0.4.0",
|
||||
"dayjs": "^1.11.9",
|
||||
"date-fns": "^2.30.0",
|
||||
"framer-motion": "^6.2.3",
|
||||
"fs": "^0.0.2",
|
||||
"gray-matter": "^4.0.3",
|
||||
@ -77,6 +77,7 @@
|
||||
"react-beautiful-dnd": "^13.1.1",
|
||||
"react-code-input": "^3.10.1",
|
||||
"react-contenteditable": "^3.3.7",
|
||||
"react-day-picker": "^8.8.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
"react-hook-form": "^7.43.0",
|
||||
@ -103,6 +104,7 @@
|
||||
"@storybook/addon-links": "^7.0.23",
|
||||
"@storybook/addon-styling": "^1.3.0",
|
||||
"@storybook/blocks": "^7.0.23",
|
||||
"@storybook/client-api": "^7.2.1",
|
||||
"@storybook/nextjs": "^7.0.23",
|
||||
"@storybook/react": "^7.0.23",
|
||||
"@storybook/testing-library": "^0.2.0",
|
||||
|
18
frontend/src/components/v2/DatePicker/DatePicker.stories.tsx
Normal file
18
frontend/src/components/v2/DatePicker/DatePicker.stories.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
import { DatePicker } from "./DatePicker";
|
||||
|
||||
const meta: Meta<typeof DatePicker> = {
|
||||
title: "Components/DatePicker",
|
||||
component: DatePicker,
|
||||
tags: ["v2"],
|
||||
argTypes: {}
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof DatePicker>;
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
|
||||
export const Primary: Story = {
|
||||
args: {}
|
||||
};
|
37
frontend/src/components/v2/DatePicker/DatePicker.tsx
Normal file
37
frontend/src/components/v2/DatePicker/DatePicker.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
import { DayPicker, DayPickerProps } from "react-day-picker";
|
||||
import { faCalendar } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { PopoverContentProps, PopoverProps } from "@radix-ui/react-popover";
|
||||
import { format } from "date-fns";
|
||||
|
||||
import { Button } from "../Button";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "../Popoverv2";
|
||||
|
||||
export type DatePickerProps = Omit<DayPickerProps, "selected"> & {
|
||||
value?: Date;
|
||||
onChange: (date?: Date) => void;
|
||||
popUpProps: PopoverProps;
|
||||
popUpContentProps: PopoverContentProps;
|
||||
};
|
||||
|
||||
// Doc: https://react-day-picker.js.org/
|
||||
export const DatePicker = ({
|
||||
value,
|
||||
onChange,
|
||||
popUpProps,
|
||||
popUpContentProps,
|
||||
...props
|
||||
}: DatePickerProps) => {
|
||||
return (
|
||||
<Popover {...popUpProps}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline_bg" leftIcon={<FontAwesomeIcon icon={faCalendar} />}>
|
||||
{value ? format(value, "PPP") : "Pick a date"}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-fit p-2" {...popUpContentProps}>
|
||||
<DayPicker {...props} mode="single" selected={value} onSelect={onChange} />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
};
|
2
frontend/src/components/v2/DatePicker/index.tsx
Normal file
2
frontend/src/components/v2/DatePicker/index.tsx
Normal file
@ -0,0 +1,2 @@
|
||||
export type { DatePickerProps } from "./DatePicker";
|
||||
export { DatePicker } from "./DatePicker";
|
@ -49,6 +49,7 @@ export type DropdownMenuItemProps<T extends ElementType> =
|
||||
icon?: ReactNode;
|
||||
as?: T;
|
||||
inputRef?: Ref<T>;
|
||||
iconPos?: "left" | "right";
|
||||
};
|
||||
|
||||
export const DropdownMenuItem = <T extends ElementType = "button">({
|
||||
@ -57,6 +58,7 @@ export const DropdownMenuItem = <T extends ElementType = "button">({
|
||||
className,
|
||||
icon,
|
||||
as: Item = "button",
|
||||
iconPos = "left",
|
||||
...props
|
||||
}: DropdownMenuItemProps<T> & ComponentPropsWithRef<T>) => (
|
||||
<DropdownMenuPrimitive.Item
|
||||
@ -67,8 +69,9 @@ export const DropdownMenuItem = <T extends ElementType = "button">({
|
||||
)}
|
||||
>
|
||||
<Item type="button" role="menuitem" className="flex w-full items-center" ref={inputRef}>
|
||||
{icon && <span className="flex items-center mr-2">{icon}</span>}
|
||||
{icon && iconPos === "left" && <span className="flex items-center mr-2">{icon}</span>}
|
||||
<span className="flex-grow text-left">{children}</span>
|
||||
{icon && iconPos === "right" && <span className="flex items-center ml-2">{icon}</span>}
|
||||
</Item>
|
||||
</DropdownMenuPrimitive.Item>
|
||||
);
|
||||
|
29
frontend/src/components/v2/Pagination/Pagination.stories.tsx
Normal file
29
frontend/src/components/v2/Pagination/Pagination.stories.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
// eslint-disable-next-line
|
||||
import { useArgs } from "@storybook/client-api";
|
||||
import type { Meta } from "@storybook/react";
|
||||
|
||||
import { Pagination, PaginationProps } from "./Pagination";
|
||||
|
||||
const meta: Meta<typeof Pagination> = {
|
||||
title: "Components/Pagination",
|
||||
component: Pagination,
|
||||
tags: ["v2"],
|
||||
args: {
|
||||
count: 50
|
||||
}
|
||||
};
|
||||
|
||||
export default meta;
|
||||
// type Story = StoryObj<typeof Pagination>;
|
||||
|
||||
export const Primary = (args: PaginationProps) => {
|
||||
const [, updateArgs] = useArgs();
|
||||
|
||||
return (
|
||||
<Pagination
|
||||
{...args}
|
||||
onChangePage={(page) => updateArgs({ page })}
|
||||
onChangePerPage={(perPage) => updateArgs({ perPage, page: 1 })}
|
||||
/>
|
||||
);
|
||||
};
|
95
frontend/src/components/v2/Pagination/Pagination.tsx
Normal file
95
frontend/src/components/v2/Pagination/Pagination.tsx
Normal file
@ -0,0 +1,95 @@
|
||||
import {
|
||||
faCaretDown,
|
||||
faCheck,
|
||||
faChevronLeft,
|
||||
faChevronRight
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger
|
||||
} from "../Dropdown";
|
||||
import { IconButton } from "../IconButton";
|
||||
|
||||
export type PaginationProps = {
|
||||
count: number;
|
||||
page: number;
|
||||
perPage?: number;
|
||||
onChangePage: (pageNumber: number) => void;
|
||||
onChangePerPage: (newRows: number) => void;
|
||||
className?: string;
|
||||
perPageList?: number[];
|
||||
};
|
||||
|
||||
export const Pagination = ({
|
||||
count,
|
||||
page = 1,
|
||||
perPage = 20,
|
||||
onChangePage,
|
||||
onChangePerPage,
|
||||
perPageList = [10, 20, 50, 100],
|
||||
className
|
||||
}: PaginationProps) => {
|
||||
const prevPageNumber = Math.max(1, page - 1);
|
||||
const canGoPrev = page > 1;
|
||||
|
||||
const upperLimit = Math.ceil(count / perPage);
|
||||
const nextPageNumber = Math.min(upperLimit, page + 1);
|
||||
const canGoNext = page + 1 <= upperLimit;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={twMerge(
|
||||
"flex items-center justify-end text-white w-full py-3 px-4 bg-mineshaft-800",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="mr-6 flex items-center space-x-2">
|
||||
<div className="text-xs">
|
||||
{(page - 1) * perPage} - {(page - 1) * perPage + perPage} of {count}
|
||||
</div>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<IconButton ariaLabel="per-page-list" variant="plain">
|
||||
<FontAwesomeIcon className="text-xs" icon={faCaretDown} />
|
||||
</IconButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="min-w-fit">
|
||||
{perPageList.map((perPageOption) => (
|
||||
<DropdownMenuItem
|
||||
key={`pagination-per-page-options-${perPageOption}`}
|
||||
icon={perPage === perPageOption && <FontAwesomeIcon size="sm" icon={faCheck} />}
|
||||
iconPos="right"
|
||||
onClick={() => onChangePerPage(perPageOption)}
|
||||
>
|
||||
{perPageOption} rows per page
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
<div className="flex items-center space-x-4">
|
||||
<IconButton
|
||||
variant="plain"
|
||||
ariaLabel="pagination-prev"
|
||||
onClick={() => onChangePage(prevPageNumber)}
|
||||
isDisabled={!canGoPrev}
|
||||
>
|
||||
<FontAwesomeIcon className="text-xs" icon={faChevronLeft} />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
variant="plain"
|
||||
ariaLabel="pagination-next"
|
||||
onClick={() => onChangePage(nextPageNumber)}
|
||||
isDisabled={!canGoNext}
|
||||
>
|
||||
<FontAwesomeIcon className="text-xs" icon={faChevronRight} />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user