feat: assert permission for remaining routes
This commit is contained in:
@@ -8,7 +8,7 @@ import * as workspaceRepo from "@kan/db/repository/workspace.repo";
|
|||||||
import { generateUID } from "@kan/shared/utils";
|
import { generateUID } from "@kan/shared/utils";
|
||||||
|
|
||||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||||
import { assertUserInWorkspace } from "../utils/auth";
|
import { assertPermission } from "../utils/permissions";
|
||||||
import { deleteObject, generateUploadUrl } from "../utils/s3";
|
import { deleteObject, generateUploadUrl } from "../utils/s3";
|
||||||
|
|
||||||
export const attachmentRouter = createTRPCRouter({
|
export const attachmentRouter = createTRPCRouter({
|
||||||
@@ -55,8 +55,7 @@ export const attachmentRouter = createTRPCRouter({
|
|||||||
message: `Card with public ID ${input.cardPublicId} not found`,
|
message: `Card with public ID ${input.cardPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, card.workspaceId, "card:edit");
|
||||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
|
||||||
|
|
||||||
// Get workspace publicId
|
// Get workspace publicId
|
||||||
const workspace = await workspaceRepo.getById(ctx.db, card.workspaceId);
|
const workspace = await workspaceRepo.getById(ctx.db, card.workspaceId);
|
||||||
@@ -131,8 +130,7 @@ export const attachmentRouter = createTRPCRouter({
|
|||||||
message: `Card with public ID ${input.cardPublicId} not found`,
|
message: `Card with public ID ${input.cardPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, card.workspaceId, "card:edit");
|
||||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
|
||||||
|
|
||||||
const attachment = await cardAttachmentRepo.create(ctx.db, {
|
const attachment = await cardAttachmentRepo.create(ctx.db, {
|
||||||
cardId: card.id,
|
cardId: card.id,
|
||||||
@@ -186,8 +184,7 @@ export const attachmentRouter = createTRPCRouter({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const workspaceId = attachment.card.list.board.workspaceId;
|
const workspaceId = attachment.card.list.board.workspaceId;
|
||||||
|
await assertPermission(ctx.db, userId, workspaceId, "card:edit");
|
||||||
await assertUserInWorkspace(ctx.db, userId, workspaceId);
|
|
||||||
|
|
||||||
const bucket = process.env.NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME;
|
const bucket = process.env.NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME;
|
||||||
if (bucket) {
|
if (bucket) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import * as cardActivityRepo from "@kan/db/repository/cardActivity.repo";
|
|||||||
import * as checklistRepo from "@kan/db/repository/checklist.repo";
|
import * as checklistRepo from "@kan/db/repository/checklist.repo";
|
||||||
|
|
||||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||||
import { assertUserInWorkspace } from "../utils/auth";
|
import { assertPermission } from "../utils/permissions";
|
||||||
|
|
||||||
const checklistSchema = z.object({
|
const checklistSchema = z.object({
|
||||||
publicId: z.string().length(12),
|
publicId: z.string().length(12),
|
||||||
@@ -57,8 +57,7 @@ export const checklistRouter = createTRPCRouter({
|
|||||||
message: `Card with public ID ${input.cardPublicId} not found`,
|
message: `Card with public ID ${input.cardPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, card.workspaceId, "card:edit");
|
||||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
|
||||||
|
|
||||||
const newChecklist = await checklistRepo.create(ctx.db, {
|
const newChecklist = await checklistRepo.create(ctx.db, {
|
||||||
name: input.name,
|
name: input.name,
|
||||||
@@ -106,11 +105,11 @@ export const checklistRouter = createTRPCRouter({
|
|||||||
message: `Checklist with public ID ${input.checklistPublicId} not found`,
|
message: `Checklist with public ID ${input.checklistPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(
|
||||||
await assertUserInWorkspace(
|
|
||||||
ctx.db,
|
ctx.db,
|
||||||
userId,
|
userId,
|
||||||
checklist.card.list.board.workspace.id,
|
checklist.card.list.board.workspace.id,
|
||||||
|
"card:edit",
|
||||||
);
|
);
|
||||||
|
|
||||||
const previousName = checklist.name;
|
const previousName = checklist.name;
|
||||||
@@ -166,11 +165,11 @@ export const checklistRouter = createTRPCRouter({
|
|||||||
message: `Checklist with public ID ${input.checklistPublicId} not found`,
|
message: `Checklist with public ID ${input.checklistPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(
|
||||||
await assertUserInWorkspace(
|
|
||||||
ctx.db,
|
ctx.db,
|
||||||
userId,
|
userId,
|
||||||
checklist.card.list.board.workspace.id,
|
checklist.card.list.board.workspace.id,
|
||||||
|
"card:edit",
|
||||||
);
|
);
|
||||||
|
|
||||||
await checklistRepo.softDeleteAllItemsByChecklistId(ctx.db, {
|
await checklistRepo.softDeleteAllItemsByChecklistId(ctx.db, {
|
||||||
@@ -237,11 +236,11 @@ export const checklistRouter = createTRPCRouter({
|
|||||||
message: `Checklist with public ID ${input.checklistPublicId} not found`,
|
message: `Checklist with public ID ${input.checklistPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(
|
||||||
await assertUserInWorkspace(
|
|
||||||
ctx.db,
|
ctx.db,
|
||||||
userId,
|
userId,
|
||||||
checklist.card.list.board.workspace.id,
|
checklist.card.list.board.workspace.id,
|
||||||
|
"card:edit",
|
||||||
);
|
);
|
||||||
|
|
||||||
const newChecklistItem = await checklistRepo.createItem(ctx.db, {
|
const newChecklistItem = await checklistRepo.createItem(ctx.db, {
|
||||||
@@ -304,11 +303,11 @@ export const checklistRouter = createTRPCRouter({
|
|||||||
message: `Checklist item with public ID ${input.checklistItemPublicId} not found`,
|
message: `Checklist item with public ID ${input.checklistItemPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(
|
||||||
await assertUserInWorkspace(
|
|
||||||
ctx.db,
|
ctx.db,
|
||||||
userId,
|
userId,
|
||||||
item.checklist.card.list.board.workspace.id,
|
item.checklist.card.list.board.workspace.id,
|
||||||
|
"card:edit",
|
||||||
);
|
);
|
||||||
|
|
||||||
const previousTitle = item.title;
|
const previousTitle = item.title;
|
||||||
@@ -394,11 +393,11 @@ export const checklistRouter = createTRPCRouter({
|
|||||||
message: `Checklist item with public ID ${input.checklistItemPublicId} not found`,
|
message: `Checklist item with public ID ${input.checklistItemPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(
|
||||||
await assertUserInWorkspace(
|
|
||||||
ctx.db,
|
ctx.db,
|
||||||
userId,
|
userId,
|
||||||
item.checklist.card.list.board.workspace.id,
|
item.checklist.card.list.board.workspace.id,
|
||||||
|
"card:edit",
|
||||||
);
|
);
|
||||||
|
|
||||||
const deleted = await checklistRepo.softDeleteItemById(ctx.db, {
|
const deleted = await checklistRepo.softDeleteItemById(ctx.db, {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { colours } from "@kan/shared/constants";
|
|||||||
import { generateUID } from "@kan/shared/utils";
|
import { generateUID } from "@kan/shared/utils";
|
||||||
|
|
||||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||||
import { assertUserInWorkspace } from "../utils/auth";
|
import { assertPermission } from "../utils/permissions";
|
||||||
import { apiKeys, urls } from "./integration";
|
import { apiKeys, urls } from "./integration";
|
||||||
|
|
||||||
export interface TrelloBoard {
|
export interface TrelloBoard {
|
||||||
@@ -180,8 +180,7 @@ export const importRouter = createTRPCRouter({
|
|||||||
message: `Workspace with public ID ${input.workspacePublicId} not found`,
|
message: `Workspace with public ID ${input.workspacePublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, workspace.id, "board:create");
|
||||||
await assertUserInWorkspace(ctx.db, userId, workspace.id);
|
|
||||||
|
|
||||||
const newImport = await importRepo.create(ctx.db, {
|
const newImport = await importRepo.create(ctx.db, {
|
||||||
source: "trello",
|
source: "trello",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import * as cardRepo from "@kan/db/repository/card.repo";
|
|||||||
import * as labelRepo from "@kan/db/repository/label.repo";
|
import * as labelRepo from "@kan/db/repository/label.repo";
|
||||||
|
|
||||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||||
import { assertUserInWorkspace } from "../utils/auth";
|
import { assertPermission } from "../utils/permissions";
|
||||||
|
|
||||||
const labelSchema = z.object({
|
const labelSchema = z.object({
|
||||||
publicId: z.string(),
|
publicId: z.string(),
|
||||||
@@ -47,8 +47,7 @@ export const labelRouter = createTRPCRouter({
|
|||||||
message: `Label with public ID ${input.labelPublicId} not found`,
|
message: `Label with public ID ${input.labelPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, label.workspaceId, "board:view");
|
||||||
await assertUserInWorkspace(ctx.db, userId, label.workspaceId);
|
|
||||||
|
|
||||||
const result = await labelRepo.getByPublicId(ctx.db, input.labelPublicId);
|
const result = await labelRepo.getByPublicId(ctx.db, input.labelPublicId);
|
||||||
|
|
||||||
@@ -102,8 +101,7 @@ export const labelRouter = createTRPCRouter({
|
|||||||
message: `Board with public ID ${input.boardPublicId} not found`,
|
message: `Board with public ID ${input.boardPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, board.workspaceId, "board:edit");
|
||||||
await assertUserInWorkspace(ctx.db, userId, board.workspaceId);
|
|
||||||
|
|
||||||
const result = await labelRepo.create(ctx.db, {
|
const result = await labelRepo.create(ctx.db, {
|
||||||
name: input.name,
|
name: input.name,
|
||||||
@@ -162,8 +160,7 @@ export const labelRouter = createTRPCRouter({
|
|||||||
message: `Label with public ID ${input.labelPublicId} not found`,
|
message: `Label with public ID ${input.labelPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, label.workspaceId, "board:edit");
|
||||||
await assertUserInWorkspace(ctx.db, userId, label.workspaceId);
|
|
||||||
|
|
||||||
const result = await labelRepo.update(ctx.db, input);
|
const result = await labelRepo.update(ctx.db, input);
|
||||||
|
|
||||||
@@ -211,8 +208,7 @@ export const labelRouter = createTRPCRouter({
|
|||||||
message: `Label with public ID ${input.labelPublicId} not found`,
|
message: `Label with public ID ${input.labelPublicId} not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, label.workspaceId, "board:edit");
|
||||||
await assertUserInWorkspace(ctx.db, userId, label.workspaceId);
|
|
||||||
|
|
||||||
await cardRepo.hardDeleteAllCardLabelRelationships(ctx.db, label.id);
|
await cardRepo.hardDeleteAllCardLabelRelationships(ctx.db, label.id);
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import {
|
|||||||
import { updateSubscriptionSeats } from "@kan/stripe";
|
import { updateSubscriptionSeats } from "@kan/stripe";
|
||||||
|
|
||||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
||||||
import { assertUserInWorkspace } from "../utils/auth";
|
|
||||||
import {
|
import {
|
||||||
assertCanManageMember,
|
assertCanManageMember,
|
||||||
assertCanManageRole,
|
assertCanManageRole,
|
||||||
@@ -62,7 +61,7 @@ export const memberRouter = createTRPCRouter({
|
|||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
|
||||||
await assertUserInWorkspace(ctx.db, userId, workspace.id, "admin");
|
await assertPermission(ctx.db, userId, workspace.id, "member:invite");
|
||||||
|
|
||||||
const isInvitedEmailAlreadyMember = workspace.members.some(
|
const isInvitedEmailAlreadyMember = workspace.members.some(
|
||||||
(member) => member.email === input.email,
|
(member) => member.email === input.email,
|
||||||
@@ -196,7 +195,7 @@ export const memberRouter = createTRPCRouter({
|
|||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
|
||||||
await assertUserInWorkspace(ctx.db, userId, workspace.id, "admin");
|
await assertPermission(ctx.db, userId, workspace.id, "member:remove");
|
||||||
|
|
||||||
const member = await memberRepo.getByPublicId(
|
const member = await memberRepo.getByPublicId(
|
||||||
ctx.db,
|
ctx.db,
|
||||||
@@ -298,8 +297,8 @@ export const memberRouter = createTRPCRouter({
|
|||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check if user is in workspace
|
// Check if user can view members
|
||||||
await assertUserInWorkspace(ctx.db, userId, workspace.id);
|
await assertPermission(ctx.db, userId, workspace.id, "member:view");
|
||||||
|
|
||||||
// Get active invite link for this workspace
|
// Get active invite link for this workspace
|
||||||
const activeInviteLink = await inviteLinkRepo.getActiveForWorkspace(
|
const activeInviteLink = await inviteLinkRepo.getActiveForWorkspace(
|
||||||
@@ -366,8 +365,8 @@ export const memberRouter = createTRPCRouter({
|
|||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check if user is in workspace
|
// Check if user can edit members (admin-equivalent)
|
||||||
await assertUserInWorkspace(ctx.db, userId, workspace.id, "admin");
|
await assertPermission(ctx.db, userId, workspace.id, "member:edit");
|
||||||
|
|
||||||
// Check subscription for cloud environment
|
// Check subscription for cloud environment
|
||||||
if (process.env.NEXT_PUBLIC_KAN_ENV === "cloud") {
|
if (process.env.NEXT_PUBLIC_KAN_ENV === "cloud") {
|
||||||
@@ -467,8 +466,8 @@ export const memberRouter = createTRPCRouter({
|
|||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check if user is in workspace
|
// Check if user can edit members (admin-equivalent)
|
||||||
await assertUserInWorkspace(ctx.db, userId, workspace.id, "admin");
|
await assertPermission(ctx.db, userId, workspace.id, "member:edit");
|
||||||
|
|
||||||
// Deactivate all active invite links
|
// Deactivate all active invite links
|
||||||
await inviteLinkRepo.deactivateAllActiveForWorkspace(ctx.db, {
|
await inviteLinkRepo.deactivateAllActiveForWorkspace(ctx.db, {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import * as workspaceSlugRepo from "@kan/db/repository/workspaceSlug.repo";
|
|||||||
import { generateUID } from "@kan/shared/utils";
|
import { generateUID } from "@kan/shared/utils";
|
||||||
|
|
||||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
||||||
import { assertUserInWorkspace } from "../utils/auth";
|
import { assertPermission } from "../utils/permissions";
|
||||||
|
|
||||||
export const workspaceRouter = createTRPCRouter({
|
export const workspaceRouter = createTRPCRouter({
|
||||||
all: protectedProcedure
|
all: protectedProcedure
|
||||||
@@ -74,8 +74,7 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
message: `Workspace not found`,
|
message: `Workspace not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, result.id, "workspace:view");
|
||||||
await assertUserInWorkspace(ctx.db, userId, result.id);
|
|
||||||
|
|
||||||
// Check if user is an admin
|
// Check if user is an admin
|
||||||
const userMember = result.members.find(
|
const userMember = result.members.find(
|
||||||
@@ -164,8 +163,7 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
message: `Workspace not found`,
|
message: `Workspace not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, result.id, "workspace:view");
|
||||||
await assertUserInWorkspace(ctx.db, userId, result.id);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}),
|
}),
|
||||||
@@ -296,8 +294,7 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
message: `Workspace not found`,
|
message: `Workspace not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, workspace.id, "workspace:edit");
|
||||||
await assertUserInWorkspace(ctx.db, userId, workspace.id, "admin");
|
|
||||||
|
|
||||||
if (input.slug) {
|
if (input.slug) {
|
||||||
const reservedOrPremiumWorkspaceSlug =
|
const reservedOrPremiumWorkspaceSlug =
|
||||||
@@ -379,8 +376,7 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
message: `Workspace not found`,
|
message: `Workspace not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, workspace.id, "workspace:delete");
|
||||||
await assertUserInWorkspace(ctx.db, userId, workspace.id, "admin");
|
|
||||||
|
|
||||||
const result = await workspaceRepo.hardDelete(
|
const result = await workspaceRepo.hardDelete(
|
||||||
ctx.db,
|
ctx.db,
|
||||||
@@ -518,8 +514,7 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
message: `Workspace not found`,
|
message: `Workspace not found`,
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
});
|
});
|
||||||
|
await assertPermission(ctx.db, userId, workspace.id, "workspace:view");
|
||||||
await assertUserInWorkspace(ctx.db, userId, workspace.id);
|
|
||||||
|
|
||||||
const result = await workspaceRepo.searchBoardsAndCards(
|
const result = await workspaceRepo.searchBoardsAndCards(
|
||||||
ctx.db,
|
ctx.db,
|
||||||
|
|||||||
Reference in New Issue
Block a user