mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 16:27:46 +00:00
Merge pull request #1987 from akhilmhdh/feat/ui-permission-check-broken
New API endpoints for Tag update, get by id and get by slug
This commit is contained in:
Generated
+7
-7
@@ -6459,12 +6459,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/braces": {
|
"node_modules/braces": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fill-range": "^7.0.1"
|
"fill-range": "^7.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
@@ -8115,9 +8115,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.0.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
|
|||||||
@@ -508,12 +508,27 @@ export const SECRET_TAGS = {
|
|||||||
LIST: {
|
LIST: {
|
||||||
projectId: "The ID of the project to list tags from."
|
projectId: "The ID of the project to list tags from."
|
||||||
},
|
},
|
||||||
|
GET_TAG_BY_ID: {
|
||||||
|
projectId: "The ID of the project to get tags from.",
|
||||||
|
tagId: "The ID of the tag to get details"
|
||||||
|
},
|
||||||
|
GET_TAG_BY_SLUG: {
|
||||||
|
projectId: "The ID of the project to get tags from.",
|
||||||
|
tagSlug: "The slug of the tag to get details"
|
||||||
|
},
|
||||||
CREATE: {
|
CREATE: {
|
||||||
projectId: "The ID of the project to create the tag in.",
|
projectId: "The ID of the project to create the tag in.",
|
||||||
name: "The name of the tag to create.",
|
name: "The name of the tag to create.",
|
||||||
slug: "The slug of the tag to create.",
|
slug: "The slug of the tag to create.",
|
||||||
color: "The color of the tag to create."
|
color: "The color of the tag to create."
|
||||||
},
|
},
|
||||||
|
UPDATE: {
|
||||||
|
projectId: "The ID of the project to update the tag in.",
|
||||||
|
tagId: "The ID of the tag to get details",
|
||||||
|
name: "The name of the tag to update.",
|
||||||
|
slug: "The slug of the tag to update.",
|
||||||
|
color: "The color of the tag to update."
|
||||||
|
},
|
||||||
DELETE: {
|
DELETE: {
|
||||||
tagId: "The ID of the tag to delete.",
|
tagId: "The ID of the tag to delete.",
|
||||||
projectId: "The ID of the project to delete the tag from."
|
projectId: "The ID of the project to delete the tag from."
|
||||||
|
|||||||
@@ -59,6 +59,18 @@ export class BadRequestError extends Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class NotFoundError extends Error {
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
error: unknown;
|
||||||
|
|
||||||
|
constructor({ name, error, message }: { message?: string; name?: string; error?: unknown }) {
|
||||||
|
super(message ?? "The requested entity is not found");
|
||||||
|
this.name = name || "NotFound";
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class DisableRotationErrors extends Error {
|
export class DisableRotationErrors extends Error {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
BadRequestError,
|
BadRequestError,
|
||||||
DatabaseError,
|
DatabaseError,
|
||||||
InternalServerError,
|
InternalServerError,
|
||||||
|
NotFoundError,
|
||||||
ScimRequestError,
|
ScimRequestError,
|
||||||
UnauthorizedError
|
UnauthorizedError
|
||||||
} from "@app/lib/errors";
|
} from "@app/lib/errors";
|
||||||
@@ -15,6 +16,8 @@ export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider
|
|||||||
req.log.error(error);
|
req.log.error(error);
|
||||||
if (error instanceof BadRequestError) {
|
if (error instanceof BadRequestError) {
|
||||||
void res.status(400).send({ statusCode: 400, message: error.message, error: error.name });
|
void res.status(400).send({ statusCode: 400, message: error.message, error: error.name });
|
||||||
|
} else if (error instanceof NotFoundError) {
|
||||||
|
void res.status(404).send({ statusCode: 404, message: error.message, error: error.name });
|
||||||
} else if (error instanceof UnauthorizedError) {
|
} else if (error instanceof UnauthorizedError) {
|
||||||
void res.status(403).send({ statusCode: 403, message: error.message, error: error.name });
|
void res.status(403).send({ statusCode: 403, message: error.message, error: error.name });
|
||||||
} else if (error instanceof DatabaseError || error instanceof InternalServerError) {
|
} else if (error instanceof DatabaseError || error instanceof InternalServerError) {
|
||||||
|
|||||||
@@ -36,6 +36,67 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:projectId/tags/:tagId",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
projectId: z.string().trim().describe(SECRET_TAGS.GET_TAG_BY_ID.projectId),
|
||||||
|
tagId: z.string().trim().describe(SECRET_TAGS.GET_TAG_BY_ID.tagId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
workspaceTag: SecretTagsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const workspaceTag = await server.services.secretTag.getTagById({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
id: req.params.tagId
|
||||||
|
});
|
||||||
|
return { workspaceTag };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:projectId/tags/slug/:tagSlug",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
projectId: z.string().trim().describe(SECRET_TAGS.GET_TAG_BY_SLUG.projectId),
|
||||||
|
tagSlug: z.string().trim().describe(SECRET_TAGS.GET_TAG_BY_SLUG.tagSlug)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
workspaceTag: SecretTagsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const workspaceTag = await server.services.secretTag.getTagBySlug({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
slug: req.params.tagSlug,
|
||||||
|
projectId: req.params.projectId
|
||||||
|
});
|
||||||
|
return { workspaceTag };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: "/:projectId/tags",
|
url: "/:projectId/tags",
|
||||||
@@ -71,6 +132,42 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "PATCH",
|
||||||
|
url: "/:projectId/tags/:tagId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
projectId: z.string().trim().describe(SECRET_TAGS.UPDATE.projectId),
|
||||||
|
tagId: z.string().trim().describe(SECRET_TAGS.UPDATE.tagId)
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
name: z.string().trim().describe(SECRET_TAGS.UPDATE.name),
|
||||||
|
slug: z.string().trim().describe(SECRET_TAGS.UPDATE.slug),
|
||||||
|
color: z.string().trim().describe(SECRET_TAGS.UPDATE.color)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
workspaceTag: SecretTagsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const workspaceTag = await server.services.secretTag.updateTag({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
...req.body,
|
||||||
|
id: req.params.tagId
|
||||||
|
});
|
||||||
|
return { workspaceTag };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
url: "/:projectId/tags/:tagId",
|
url: "/:projectId/tags/:tagId",
|
||||||
|
|||||||
@@ -2,10 +2,17 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
|
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
|
|
||||||
import { TSecretTagDALFactory } from "./secret-tag-dal";
|
import { TSecretTagDALFactory } from "./secret-tag-dal";
|
||||||
import { TCreateTagDTO, TDeleteTagDTO, TListProjectTagsDTO } from "./secret-tag-types";
|
import {
|
||||||
|
TCreateTagDTO,
|
||||||
|
TDeleteTagDTO,
|
||||||
|
TGetTagByIdDTO,
|
||||||
|
TGetTagBySlugDTO,
|
||||||
|
TListProjectTagsDTO,
|
||||||
|
TUpdateTagDTO
|
||||||
|
} from "./secret-tag-types";
|
||||||
|
|
||||||
type TSecretTagServiceFactoryDep = {
|
type TSecretTagServiceFactoryDep = {
|
||||||
secretTagDAL: TSecretTagDALFactory;
|
secretTagDAL: TSecretTagDALFactory;
|
||||||
@@ -48,6 +55,28 @@ export const secretTagServiceFactory = ({ secretTagDAL, permissionService }: TSe
|
|||||||
return newTag;
|
return newTag;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateTag = async ({ actorId, actor, actorOrgId, actorAuthMethod, id, name, color, slug }: TUpdateTagDTO) => {
|
||||||
|
const tag = await secretTagDAL.findById(id);
|
||||||
|
if (!tag) throw new BadRequestError({ message: "Tag doesn't exist" });
|
||||||
|
|
||||||
|
if (slug) {
|
||||||
|
const existingTag = await secretTagDAL.findOne({ slug, projectId: tag.projectId });
|
||||||
|
if (existingTag && existingTag.id !== tag.id) throw new BadRequestError({ message: "Tag already exist" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
tag.projectId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Tags);
|
||||||
|
|
||||||
|
const updatedTag = await secretTagDAL.updateById(tag.id, { name, color, slug });
|
||||||
|
return updatedTag;
|
||||||
|
};
|
||||||
|
|
||||||
const deleteTag = async ({ actorId, actor, actorOrgId, actorAuthMethod, id }: TDeleteTagDTO) => {
|
const deleteTag = async ({ actorId, actor, actorOrgId, actorAuthMethod, id }: TDeleteTagDTO) => {
|
||||||
const tag = await secretTagDAL.findById(id);
|
const tag = await secretTagDAL.findById(id);
|
||||||
if (!tag) throw new BadRequestError({ message: "Tag doesn't exist" });
|
if (!tag) throw new BadRequestError({ message: "Tag doesn't exist" });
|
||||||
@@ -65,6 +94,38 @@ export const secretTagServiceFactory = ({ secretTagDAL, permissionService }: TSe
|
|||||||
return deletedTag;
|
return deletedTag;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getTagById = async ({ actorId, actor, actorOrgId, actorAuthMethod, id }: TGetTagByIdDTO) => {
|
||||||
|
const tag = await secretTagDAL.findById(id);
|
||||||
|
if (!tag) throw new NotFoundError({ message: "Tag doesn't exist" });
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
tag.projectId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Tags);
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTagBySlug = async ({ actorId, actor, actorOrgId, actorAuthMethod, slug, projectId }: TGetTagBySlugDTO) => {
|
||||||
|
const tag = await secretTagDAL.findOne({ projectId, slug });
|
||||||
|
if (!tag) throw new NotFoundError({ message: "Tag doesn't exist" });
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
tag.projectId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Tags);
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
};
|
||||||
|
|
||||||
const getProjectTags = async ({ actor, actorId, actorOrgId, actorAuthMethod, projectId }: TListProjectTagsDTO) => {
|
const getProjectTags = async ({ actor, actorId, actorOrgId, actorAuthMethod, projectId }: TListProjectTagsDTO) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
actor,
|
actor,
|
||||||
@@ -79,5 +140,5 @@ export const secretTagServiceFactory = ({ secretTagDAL, permissionService }: TSe
|
|||||||
return tags;
|
return tags;
|
||||||
};
|
};
|
||||||
|
|
||||||
return { createTag, deleteTag, getProjectTags };
|
return { createTag, deleteTag, getProjectTags, getTagById, getTagBySlug, updateTag };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,21 @@ export type TCreateTagDTO = {
|
|||||||
slug: string;
|
slug: string;
|
||||||
} & TProjectPermission;
|
} & TProjectPermission;
|
||||||
|
|
||||||
|
export type TUpdateTagDTO = {
|
||||||
|
id: string;
|
||||||
|
name?: string;
|
||||||
|
slug?: string;
|
||||||
|
color?: string;
|
||||||
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
export type TGetTagByIdDTO = {
|
||||||
|
id: string;
|
||||||
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
export type TGetTagBySlugDTO = {
|
||||||
|
slug: string;
|
||||||
|
} & TProjectPermission;
|
||||||
|
|
||||||
export type TDeleteTagDTO = {
|
export type TDeleteTagDTO = {
|
||||||
id: string;
|
id: string;
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "Get By ID"
|
||||||
|
openapi: "GET /api/v1/workspace/{projectId}/tags/{tagId}"
|
||||||
|
---
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "Get By Slug"
|
||||||
|
openapi: "GET /api/v1/workspace/{projectId}/tags/slug/{tagSlug}"
|
||||||
|
---
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "Update"
|
||||||
|
openapi: "PATCH /api/v1/workspace/{projectId}/tags/{tagId}"
|
||||||
|
---
|
||||||
@@ -505,7 +505,10 @@
|
|||||||
"group": "Secret Tags",
|
"group": "Secret Tags",
|
||||||
"pages": [
|
"pages": [
|
||||||
"api-reference/endpoints/secret-tags/list",
|
"api-reference/endpoints/secret-tags/list",
|
||||||
|
"api-reference/endpoints/secret-tags/get-by-id",
|
||||||
|
"api-reference/endpoints/secret-tags/get-by-slug",
|
||||||
"api-reference/endpoints/secret-tags/create",
|
"api-reference/endpoints/secret-tags/create",
|
||||||
|
"api-reference/endpoints/secret-tags/update",
|
||||||
"api-reference/endpoints/secret-tags/delete"
|
"api-reference/endpoints/secret-tags/delete"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user