fix permissions loop for charts route

This commit is contained in:
Francis Cao committed 2026-07-14 15:23:32 -07:00
1 parent 712b32c7bf
commit 8a75208d5b
2 files changed
+73 -8

No files matched your search

+2 -8
View File
@@ -1,10 +1,10 @@
import { z } from 'zod';
import { fromZonedTime } from 'date-fns-tz';
import { parseDateRange } from '@/lib/date';
import { canViewBatchWebsites } from '@/permissions/website';
import { parseRequest } from '@/lib/request';
import { json } from '@/lib/response';
import { timezoneParam } from '@/lib/schema';
import { canViewWebsite } from '@/permissions';
import { getWebsiteListCharts } from '@/queries/sql';
const schema = z.object({
@@ -32,13 +32,7 @@ export async function GET(request: Request) {
: fromZonedTime(defaultRange.startDate, timezone);
const endDate = hasDateRange ? new Date(query.endAt) : fromZonedTime(defaultRange.endDate, timezone);
const websiteIds = (
await Promise.all(
query.ids.map(async (websiteId: string) =>
(await canViewWebsite(auth, websiteId)) ? websiteId : null,
),
)
).filter(Boolean);
const websiteIds = await canViewBatchWebsites(auth, query.ids);
const data = await getWebsiteListCharts(websiteIds, {
startDate,
+71
View File
@@ -1,6 +1,7 @@
import { hasPermission } from '@/lib/auth';
import { PERMISSIONS } from '@/lib/constants';
import { getEntity } from '@/lib/entity';
import prisma from '@/lib/prisma';
import type { Auth } from '@/lib/types';
import { getTeamUser, getWebsite } from '@/queries/prisma';
@@ -39,6 +40,76 @@ export async function canViewWebsite({ user, shareToken }: Auth, websiteId: stri
return false;
}
export async function canViewBatchWebsites({ user, shareToken }: Auth, websiteIds: string[]) {
if (!websiteIds.length) {
return [];
}
const requestedIds = Array.from(new Set(websiteIds));
if (user?.isAdmin) {
return requestedIds;
}
const shareAllowedIds = new Set(
[
shareToken?.websiteId,
shareToken?.pixelId,
shareToken?.linkId,
...(shareToken?.websiteIds ?? []),
...(shareToken?.pixelIds ?? []),
...(shareToken?.linkIds ?? []),
].filter((id): id is string => Boolean(id)),
);
if (!user) {
return requestedIds.filter(id => shareAllowedIds.has(id));
}
const websites = await prisma.client.website.findMany({
where: {
id: {
in: requestedIds,
},
},
select: {
id: true,
userId: true,
teamId: true,
},
});
const ownedIds = new Set(
websites.filter(website => website.userId === user.id).map(website => website.id),
);
const teamIds = Array.from(
new Set(websites.map(website => website.teamId).filter((teamId): teamId is string => Boolean(teamId))),
);
const teamUsers = teamIds.length
? await prisma.client.teamUser.findMany({
where: {
userId: user.id,
teamId: {
in: teamIds,
},
},
select: {
teamId: true,
},
})
: [];
const allowedTeamIds = new Set(teamUsers.map(teamUser => teamUser.teamId));
const teamOwnedIds = new Set(
websites
.filter(website => website.teamId && allowedTeamIds.has(website.teamId))
.map(website => website.id),
);
return requestedIds.filter(
id => shareAllowedIds.has(id) || ownedIds.has(id) || teamOwnedIds.has(id),
);
}
export async function canViewAllWebsites({ user }: Auth) {
return user?.isAdmin ?? false;
}