From ade0819be10f7aa09b7c90c5ba87bf1bbbbfaab9 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 2 Jun 2026 15:29:23 -0700 Subject: [PATCH 1/3] Tighten API access checks by website section and share permissions --- src/app/api/realtime/[websiteId]/route.ts | 4 +- src/app/api/reports/attribution/route.ts | 4 +- src/app/api/reports/breakdown/route.ts | 4 +- src/app/api/reports/funnel/route.ts | 4 +- src/app/api/reports/goal/route.ts | 4 +- src/app/api/reports/heatmap/route.ts | 4 +- src/app/api/reports/journey/route.ts | 4 +- src/app/api/reports/performance/route.ts | 4 +- src/app/api/reports/retention/route.ts | 4 +- src/app/api/reports/revenue/route.ts | 45 ++++------- src/app/api/reports/route.ts | 4 +- src/app/api/reports/utm/route.ts | 4 +- .../api/websites/[websiteId]/active/route.ts | 4 +- .../websites/[websiteId]/daterange/route.ts | 4 +- .../event-data-pivot/array-series/route.ts | 12 ++- .../event-data-pivot/date-series/route.ts | 12 ++- .../event-data-pivot/numeric-series/route.ts | 13 +++- .../event-data-pivot/numeric-stats/route.ts | 12 ++- .../event-data-pivot/property-series/route.ts | 12 ++- .../[websiteId]/event-data-pivot/route.ts | 4 +- .../[websiteId]/event-data/[eventId]/route.ts | 4 +- .../[websiteId]/event-data/events/route.ts | 4 +- .../[websiteId]/event-data/fields/route.ts | 4 +- .../event-data/properties/route.ts | 4 +- .../websites/[websiteId]/event-data/route.ts | 6 +- .../[websiteId]/event-data/stats/route.ts | 4 +- .../[websiteId]/event-data/values/route.ts | 4 +- .../api/websites/[websiteId]/events/route.ts | 4 +- .../[websiteId]/events/series/route.ts | 4 +- .../[websiteId]/events/stats/route.ts | 4 +- .../api/websites/[websiteId]/export/route.ts | 4 +- .../heatmaps/snapshots/[snapshotId]/route.ts | 6 +- .../[websiteId]/metrics/expanded/route.ts | 4 +- .../api/websites/[websiteId]/metrics/route.ts | 14 +++- .../websites/[websiteId]/pageviews/route.ts | 4 +- .../[websiteId]/replays/[replayId]/route.ts | 4 +- .../api/websites/[websiteId]/replays/route.ts | 4 +- .../replays/saved/[replayId]/route.ts | 4 +- .../[websiteId]/replays/saved/route.ts | 4 +- .../api/websites/[websiteId]/reports/route.ts | 4 +- .../[websiteId]/revenue/chart/route.ts | 9 +-- .../[websiteId]/revenue/metrics/route.ts | 13 +--- .../[websiteId]/revenue/sessions/route.ts | 4 +- .../[websiteId]/revenue/stats/route.ts | 6 +- src/app/api/websites/[websiteId]/route.ts | 4 +- .../[websiteId]/segments/[segmentId]/route.ts | 4 +- .../websites/[websiteId]/segments/route.ts | 4 +- .../[websiteId]/session-data-pivot/route.ts | 4 +- .../session-data/array-series/route.ts | 4 +- .../session-data/date-series/route.ts | 4 +- .../session-data/numeric-series/route.ts | 12 ++- .../session-data/numeric-stats/route.ts | 4 +- .../session-data/properties/route.ts | 11 +-- .../session-data/property-series/route.ts | 11 ++- .../[websiteId]/session-data/stats/route.ts | 11 ++- .../[websiteId]/session-data/values/route.ts | 4 +- .../sessions/[sessionId]/activity/route.ts | 4 +- .../sessions/[sessionId]/properties/route.ts | 4 +- .../sessions/[sessionId]/replays/route.ts | 4 +- .../[websiteId]/sessions/[sessionId]/route.ts | 4 +- .../websites/[websiteId]/sessions/route.ts | 4 +- .../[websiteId]/sessions/stats/route.ts | 4 +- .../[websiteId]/sessions/weekly/route.ts | 4 +- .../api/websites/[websiteId]/shares/route.ts | 4 +- .../api/websites/[websiteId]/stats/route.ts | 4 +- .../api/websites/[websiteId]/values/route.ts | 14 +++- src/lib/types.ts | 1 + src/permissions/index.ts | 1 + src/permissions/share.ts | 74 +++++++++++++++++++ 69 files changed, 303 insertions(+), 188 deletions(-) create mode 100644 src/permissions/share.ts diff --git a/src/app/api/realtime/[websiteId]/route.ts b/src/app/api/realtime/[websiteId]/route.ts index 32b7a16c1..ad1995fe5 100644 --- a/src/app/api/realtime/[websiteId]/route.ts +++ b/src/app/api/realtime/[websiteId]/route.ts @@ -2,7 +2,7 @@ import { startOfMinute, subMinutes } from 'date-fns'; import { REALTIME_RANGE } from '@/lib/constants'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getRealtimeData } from '@/queries/sql'; export async function GET( @@ -17,7 +17,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'realtime'))) { return unauthorized(); } diff --git a/src/app/api/reports/attribution/route.ts b/src/app/api/reports/attribution/route.ts index bd7d86dc7..4b38d13f0 100644 --- a/src/app/api/reports/attribution/route.ts +++ b/src/app/api/reports/attribution/route.ts @@ -1,7 +1,7 @@ import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { reportResultSchema } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { type AttributionParameters, getAttribution } from '@/queries/sql/reports/getAttribution'; export async function POST(request: Request) { @@ -13,7 +13,7 @@ export async function POST(request: Request) { const { websiteId } = body; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'attribution'))) { return unauthorized(); } diff --git a/src/app/api/reports/breakdown/route.ts b/src/app/api/reports/breakdown/route.ts index 3c5931458..c45c38a94 100644 --- a/src/app/api/reports/breakdown/route.ts +++ b/src/app/api/reports/breakdown/route.ts @@ -1,7 +1,7 @@ import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { reportResultSchema } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { type BreakdownParameters, getBreakdown } from '@/queries/sql'; export async function POST(request: Request) { @@ -13,7 +13,7 @@ export async function POST(request: Request) { const { websiteId } = body; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'breakdown'))) { return unauthorized(); } diff --git a/src/app/api/reports/funnel/route.ts b/src/app/api/reports/funnel/route.ts index c13f6f1c8..7b7869a27 100644 --- a/src/app/api/reports/funnel/route.ts +++ b/src/app/api/reports/funnel/route.ts @@ -1,7 +1,7 @@ import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { reportResultSchema } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { type FunnelParameters, getFunnel } from '@/queries/sql'; export async function POST(request: Request) { @@ -13,7 +13,7 @@ export async function POST(request: Request) { const { websiteId } = body; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'funnels'))) { return unauthorized(); } diff --git a/src/app/api/reports/goal/route.ts b/src/app/api/reports/goal/route.ts index 3bd0415d6..2887a15cd 100644 --- a/src/app/api/reports/goal/route.ts +++ b/src/app/api/reports/goal/route.ts @@ -1,7 +1,7 @@ import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { reportResultSchema } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { type GoalParameters, getGoal } from '@/queries/sql/reports/getGoal'; export async function POST(request: Request) { @@ -13,7 +13,7 @@ export async function POST(request: Request) { const { websiteId } = body; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'goals'))) { return unauthorized(); } diff --git a/src/app/api/reports/heatmap/route.ts b/src/app/api/reports/heatmap/route.ts index 158cc7dd7..b37836375 100644 --- a/src/app/api/reports/heatmap/route.ts +++ b/src/app/api/reports/heatmap/route.ts @@ -1,7 +1,7 @@ import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { reportResultSchema } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getHeatmap, type HeatmapParameters } from '@/queries/sql'; export async function POST(request: Request) { @@ -13,7 +13,7 @@ export async function POST(request: Request) { const { websiteId } = body; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/reports/journey/route.ts b/src/app/api/reports/journey/route.ts index b53d225d4..cd021d7ab 100644 --- a/src/app/api/reports/journey/route.ts +++ b/src/app/api/reports/journey/route.ts @@ -1,7 +1,7 @@ import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { reportResultSchema } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getJourney } from '@/queries/sql'; export async function POST(request: Request) { @@ -14,7 +14,7 @@ export async function POST(request: Request) { const { websiteId, parameters, filters } = body; const { eventType } = parameters; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'journeys'))) { return unauthorized(); } diff --git a/src/app/api/reports/performance/route.ts b/src/app/api/reports/performance/route.ts index d32ffbdb6..449eb33cd 100644 --- a/src/app/api/reports/performance/route.ts +++ b/src/app/api/reports/performance/route.ts @@ -1,7 +1,7 @@ import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { reportResultSchema } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getPerformance, type PerformanceParameters } from '@/queries/sql/reports/getPerformance'; import { getPerformanceMetrics } from '@/queries/sql/reports/getPerformanceMetrics'; @@ -14,7 +14,7 @@ export async function POST(request: Request) { const { websiteId } = body; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'performance'))) { return unauthorized(); } diff --git a/src/app/api/reports/retention/route.ts b/src/app/api/reports/retention/route.ts index d1a7d698b..15bbd87dd 100644 --- a/src/app/api/reports/retention/route.ts +++ b/src/app/api/reports/retention/route.ts @@ -1,7 +1,7 @@ import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { reportResultSchema } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getRetention, type RetentionParameters } from '@/queries/sql'; export async function POST(request: Request) { @@ -13,7 +13,7 @@ export async function POST(request: Request) { const { websiteId } = body; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'retention'))) { return unauthorized(); } diff --git a/src/app/api/reports/revenue/route.ts b/src/app/api/reports/revenue/route.ts index d6acc0fd5..bf8237d55 100644 --- a/src/app/api/reports/revenue/route.ts +++ b/src/app/api/reports/revenue/route.ts @@ -2,11 +2,8 @@ import { getCompareDate } from '@/lib/date'; import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { reportResultSchema } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; -import { - getRevenueChart, - type RevenuParameters, -} from '@/queries/sql/reports/getRevenueChart'; +import { canViewWebsiteSection } from '@/permissions'; +import { getRevenueChart, type RevenuParameters } from '@/queries/sql/reports/getRevenueChart'; import { getRevenueMetrics, type RevenueMetricsResult, @@ -22,7 +19,7 @@ export async function POST(request: Request) { const { websiteId } = body; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'revenue'))) { return unauthorized(); } @@ -36,30 +33,18 @@ export async function POST(request: Request) { getRevenueChart(websiteId, parameters as RevenuParameters, filters), getRevenueStats(websiteId, parameters as RevenuParameters, filters), getRevenueStats(websiteId, comparisonParameters, filters), - getRevenueMetrics( - websiteId, - parameters as RevenuParameters, - filters, - 'country', - ) as Promise, - getRevenueMetrics( - websiteId, - parameters as RevenuParameters, - filters, - 'region', - ) as Promise, - getRevenueMetrics( - websiteId, - parameters as RevenuParameters, - filters, - 'referrer', - ) as Promise, - getRevenueMetrics( - websiteId, - parameters as RevenuParameters, - filters, - 'channel', - ) as Promise, + getRevenueMetrics(websiteId, parameters as RevenuParameters, filters, 'country') as Promise< + RevenueMetricsResult['country'] + >, + getRevenueMetrics(websiteId, parameters as RevenuParameters, filters, 'region') as Promise< + RevenueMetricsResult['region'] + >, + getRevenueMetrics(websiteId, parameters as RevenuParameters, filters, 'referrer') as Promise< + RevenueMetricsResult['referrer'] + >, + getRevenueMetrics(websiteId, parameters as RevenuParameters, filters, 'channel') as Promise< + RevenueMetricsResult['channel'] + >, ]); return json({ chart, total: { ...total, comparison }, country, region, referrer, channel }); diff --git a/src/app/api/reports/route.ts b/src/app/api/reports/route.ts index b0a413543..1742c93dc 100644 --- a/src/app/api/reports/route.ts +++ b/src/app/api/reports/route.ts @@ -3,7 +3,7 @@ import { uuid } from '@/lib/crypto'; import { parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { pagingParams, reportSchema, reportTypeParam } from '@/lib/schema'; -import { canUpdateWebsite, canViewWebsite } from '@/permissions'; +import { canUpdateWebsite, canViewAuthenticatedWebsite } from '@/permissions'; import { createReport, getReports } from '@/queries/prisma'; export async function GET(request: Request) { @@ -26,7 +26,7 @@ export async function GET(request: Request) { search, }; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/reports/utm/route.ts b/src/app/api/reports/utm/route.ts index 577fdab79..b4621032f 100644 --- a/src/app/api/reports/utm/route.ts +++ b/src/app/api/reports/utm/route.ts @@ -2,7 +2,7 @@ import { UTM_PARAMS } from '@/lib/constants'; import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { reportResultSchema } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getUTM, type UTMParameters } from '@/queries/sql'; export async function POST(request: Request) { @@ -14,7 +14,7 @@ export async function POST(request: Request) { const { websiteId } = body; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'utm'))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/active/route.ts b/src/app/api/websites/[websiteId]/active/route.ts index 233b97e50..59dc4158d 100644 --- a/src/app/api/websites/[websiteId]/active/route.ts +++ b/src/app/api/websites/[websiteId]/active/route.ts @@ -1,6 +1,6 @@ import { parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getActiveVisitors } from '@/queries/sql'; export async function GET( @@ -15,7 +15,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, ['overview', 'realtime']))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/daterange/route.ts b/src/app/api/websites/[websiteId]/daterange/route.ts index 14a241fd9..4b0db171f 100644 --- a/src/app/api/websites/[websiteId]/daterange/route.ts +++ b/src/app/api/websites/[websiteId]/daterange/route.ts @@ -1,6 +1,6 @@ import { parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; -import { canViewWebsite } from '@/permissions'; +import { canViewSharedWebsite } from '@/permissions'; import { getWebsiteDateRange } from '@/queries/sql'; export async function GET( @@ -15,7 +15,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewSharedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/event-data-pivot/array-series/route.ts b/src/app/api/websites/[websiteId]/event-data-pivot/array-series/route.ts index 59afc1e72..1451f62e6 100644 --- a/src/app/api/websites/[websiteId]/event-data-pivot/array-series/route.ts +++ b/src/app/api/websites/[websiteId]/event-data-pivot/array-series/route.ts @@ -3,7 +3,7 @@ import { parseEventPropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventDataArraySeries } from '@/queries/sql/events/getEventDataArraySeries'; export async function GET( @@ -28,14 +28,20 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } const { eventName, propertyName, ...rest } = query; const filters = await getQueryFilters(rest, websiteId); const eventFilters = parseEventPropertyFilters(query); - const data = await getEventDataArraySeries(websiteId, eventName, propertyName, filters, eventFilters); + const data = await getEventDataArraySeries( + websiteId, + eventName, + propertyName, + filters, + eventFilters, + ); return json(data); } diff --git a/src/app/api/websites/[websiteId]/event-data-pivot/date-series/route.ts b/src/app/api/websites/[websiteId]/event-data-pivot/date-series/route.ts index af071dcd9..f3f659678 100644 --- a/src/app/api/websites/[websiteId]/event-data-pivot/date-series/route.ts +++ b/src/app/api/websites/[websiteId]/event-data-pivot/date-series/route.ts @@ -3,7 +3,7 @@ import { parseEventPropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, timezoneParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventDataDateSeries } from '@/queries/sql/events/getEventDataDateSeries'; export async function GET( @@ -27,14 +27,20 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } const { eventName, propertyName, ...rest } = query; const filters = await getQueryFilters(rest, websiteId); const eventFilters = parseEventPropertyFilters(query); - const data = await getEventDataDateSeries(websiteId, eventName, propertyName, filters, eventFilters); + const data = await getEventDataDateSeries( + websiteId, + eventName, + propertyName, + filters, + eventFilters, + ); return json(data); } diff --git a/src/app/api/websites/[websiteId]/event-data-pivot/numeric-series/route.ts b/src/app/api/websites/[websiteId]/event-data-pivot/numeric-series/route.ts index ca359251b..9b85f1b5e 100644 --- a/src/app/api/websites/[websiteId]/event-data-pivot/numeric-series/route.ts +++ b/src/app/api/websites/[websiteId]/event-data-pivot/numeric-series/route.ts @@ -3,7 +3,7 @@ import { parseEventPropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventDataNumericSeries } from '@/queries/sql/events/getEventDataNumericSeries'; export async function GET( @@ -29,14 +29,21 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } const { eventName, propertyName, metric, ...rest } = query; const filters = await getQueryFilters(rest, websiteId); const eventFilters = parseEventPropertyFilters(query); - const data = await getEventDataNumericSeries(websiteId, eventName, propertyName, metric, filters, eventFilters); + const data = await getEventDataNumericSeries( + websiteId, + eventName, + propertyName, + metric, + filters, + eventFilters, + ); return json(data); } diff --git a/src/app/api/websites/[websiteId]/event-data-pivot/numeric-stats/route.ts b/src/app/api/websites/[websiteId]/event-data-pivot/numeric-stats/route.ts index 7ff49e3f5..5c8360462 100644 --- a/src/app/api/websites/[websiteId]/event-data-pivot/numeric-stats/route.ts +++ b/src/app/api/websites/[websiteId]/event-data-pivot/numeric-stats/route.ts @@ -3,7 +3,7 @@ import { parseEventPropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventDataNumericStats } from '@/queries/sql/events/getEventDataNumericStats'; export async function GET( @@ -26,14 +26,20 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } const { eventName, propertyName, ...rest } = query; const filters = await getQueryFilters(rest, websiteId); const eventFilters = parseEventPropertyFilters(query); - const data = await getEventDataNumericStats(websiteId, eventName, propertyName, filters, eventFilters); + const data = await getEventDataNumericStats( + websiteId, + eventName, + propertyName, + filters, + eventFilters, + ); return json(data); } diff --git a/src/app/api/websites/[websiteId]/event-data-pivot/property-series/route.ts b/src/app/api/websites/[websiteId]/event-data-pivot/property-series/route.ts index 37c31ad34..3fa27b58b 100644 --- a/src/app/api/websites/[websiteId]/event-data-pivot/property-series/route.ts +++ b/src/app/api/websites/[websiteId]/event-data-pivot/property-series/route.ts @@ -3,7 +3,7 @@ import { parseEventPropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventDataPropertySeries } from '@/queries/sql/events/getEventDataPropertySeries'; export async function GET( @@ -28,14 +28,20 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } const { eventName, propertyName, ...rest } = query; const filters = await getQueryFilters(rest, websiteId); const eventFilters = parseEventPropertyFilters(query); - const data = await getEventDataPropertySeries(websiteId, eventName, propertyName, filters, eventFilters); + const data = await getEventDataPropertySeries( + websiteId, + eventName, + propertyName, + filters, + eventFilters, + ); return json(data); } diff --git a/src/app/api/websites/[websiteId]/event-data-pivot/route.ts b/src/app/api/websites/[websiteId]/event-data-pivot/route.ts index 048f95a6f..c2a533e93 100644 --- a/src/app/api/websites/[websiteId]/event-data-pivot/route.ts +++ b/src/app/api/websites/[websiteId]/event-data-pivot/route.ts @@ -3,7 +3,7 @@ import { parseEventPropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, pagingParams, timezoneParam, unitParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventDataPivot } from '@/queries/sql/events/getEventDataPivot'; export async function GET( @@ -28,7 +28,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/event-data/[eventId]/route.ts b/src/app/api/websites/[websiteId]/event-data/[eventId]/route.ts index e640f1b6f..b5d65868e 100644 --- a/src/app/api/websites/[websiteId]/event-data/[eventId]/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/[eventId]/route.ts @@ -1,6 +1,6 @@ import { parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventDataById } from '@/queries/sql/events/getEventDataById'; export async function GET( @@ -15,7 +15,7 @@ export async function GET( const { websiteId, eventId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/event-data/events/route.ts b/src/app/api/websites/[websiteId]/event-data/events/route.ts index eb6ee6ed8..70ed3750b 100644 --- a/src/app/api/websites/[websiteId]/event-data/events/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/events/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventDataEvents } from '@/queries/sql/events/getEventDataEvents'; export async function GET( @@ -23,7 +23,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/event-data/fields/route.ts b/src/app/api/websites/[websiteId]/event-data/fields/route.ts index bce6a977c..76257a3cc 100644 --- a/src/app/api/websites/[websiteId]/event-data/fields/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/fields/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventDataFields } from '@/queries/sql'; export async function GET( @@ -23,7 +23,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/event-data/properties/route.ts b/src/app/api/websites/[websiteId]/event-data/properties/route.ts index 52d15cfbd..0afc90c0f 100644 --- a/src/app/api/websites/[websiteId]/event-data/properties/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/properties/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventDataProperties } from '@/queries/sql'; export async function GET( @@ -23,7 +23,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/event-data/route.ts b/src/app/api/websites/[websiteId]/event-data/route.ts index 2d0caf65e..b3eae5313 100644 --- a/src/app/api/websites/[websiteId]/event-data/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, pagingParams } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventData } from '@/queries/sql/events/getEventData'; export async function GET( @@ -24,7 +24,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } @@ -47,4 +47,4 @@ export async function GET( } return json({ data: [...eventMap.values()], count, page, pageSize }); -} \ No newline at end of file +} diff --git a/src/app/api/websites/[websiteId]/event-data/stats/route.ts b/src/app/api/websites/[websiteId]/event-data/stats/route.ts index 042e989a4..1a8b54bd5 100644 --- a/src/app/api/websites/[websiteId]/event-data/stats/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/stats/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventDataStats } from '@/queries/sql'; export async function GET( @@ -23,7 +23,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/event-data/values/route.ts b/src/app/api/websites/[websiteId]/event-data/values/route.ts index b0843427b..6734e5344 100644 --- a/src/app/api/websites/[websiteId]/event-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/values/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventDataValues } from '@/queries/sql'; export async function GET( @@ -26,7 +26,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/events/route.ts b/src/app/api/websites/[websiteId]/events/route.ts index 583e4abbf..85be70e1d 100644 --- a/src/app/api/websites/[websiteId]/events/route.ts +++ b/src/app/api/websites/[websiteId]/events/route.ts @@ -1,7 +1,7 @@ import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, pagingParams, searchParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getWebsiteEvents } from '@/queries/sql'; export async function GET( @@ -22,7 +22,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'events'))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/events/series/route.ts b/src/app/api/websites/[websiteId]/events/series/route.ts index 6060105c2..be9f9dc7b 100644 --- a/src/app/api/websites/[websiteId]/events/series/route.ts +++ b/src/app/api/websites/[websiteId]/events/series/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getEventStats } from '@/queries/sql'; export async function GET( @@ -26,7 +26,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'events'))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/events/stats/route.ts b/src/app/api/websites/[websiteId]/events/stats/route.ts index fceb97cbd..a1898bdbb 100644 --- a/src/app/api/websites/[websiteId]/events/stats/route.ts +++ b/src/app/api/websites/[websiteId]/events/stats/route.ts @@ -2,7 +2,7 @@ import { getCompareDate } from '@/lib/date'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getWebsiteEventStats } from '@/queries/sql/events/getWebsiteEventStats'; export async function GET( @@ -21,7 +21,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'events'))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/export/route.ts b/src/app/api/websites/[websiteId]/export/route.ts index 1beb9bcb2..f298bbcf5 100644 --- a/src/app/api/websites/[websiteId]/export/route.ts +++ b/src/app/api/websites/[websiteId]/export/route.ts @@ -3,7 +3,7 @@ import Papa from 'papaparse'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { pagingParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getEventMetrics, getPageviewMetrics, getSessionMetrics } from '@/queries/sql'; export async function GET( @@ -22,7 +22,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/heatmaps/snapshots/[snapshotId]/route.ts b/src/app/api/websites/[websiteId]/heatmaps/snapshots/[snapshotId]/route.ts index 98c8bb870..d8f7eaa3e 100644 --- a/src/app/api/websites/[websiteId]/heatmaps/snapshots/[snapshotId]/route.ts +++ b/src/app/api/websites/[websiteId]/heatmaps/snapshots/[snapshotId]/route.ts @@ -1,6 +1,6 @@ -import { notFound, unauthorized } from '@/lib/response'; -import { canViewWebsite } from '@/permissions'; import { parseRequest } from '@/lib/request'; +import { notFound, unauthorized } from '@/lib/response'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getHeatmapSnapshotImage } from '@/queries/sql/heatmap/ensureHeatmapSnapshot'; export async function GET( @@ -14,7 +14,7 @@ export async function GET( return error(); } - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/metrics/expanded/route.ts b/src/app/api/websites/[websiteId]/metrics/expanded/route.ts index 34ebcd598..06aa2904b 100644 --- a/src/app/api/websites/[websiteId]/metrics/expanded/route.ts +++ b/src/app/api/websites/[websiteId]/metrics/expanded/route.ts @@ -3,7 +3,7 @@ import { EVENT_COLUMNS, EVENT_TYPE, SESSION_COLUMNS } from '@/lib/constants'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { badRequest, json, unauthorized } from '@/lib/response'; import { filterParams, searchParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getChannelExpandedMetrics, getEventExpandedMetrics, @@ -31,7 +31,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, ['overview', 'compare']))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/metrics/route.ts b/src/app/api/websites/[websiteId]/metrics/route.ts index c9649ae9a..21575a868 100644 --- a/src/app/api/websites/[websiteId]/metrics/route.ts +++ b/src/app/api/websites/[websiteId]/metrics/route.ts @@ -3,7 +3,7 @@ import { EVENT_COLUMNS, EVENT_TYPE, SESSION_COLUMNS } from '@/lib/constants'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { badRequest, json, unauthorized } from '@/lib/response'; import { filterParams, searchParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getChannelMetrics, getEventMetrics, @@ -31,7 +31,17 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if ( + !(await canViewWebsiteSection(auth, websiteId, [ + 'overview', + 'events', + 'sessions', + 'compare', + 'breakdown', + 'utm', + 'attribution', + ])) + ) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/pageviews/route.ts b/src/app/api/websites/[websiteId]/pageviews/route.ts index b9945c87b..257f46daf 100644 --- a/src/app/api/websites/[websiteId]/pageviews/route.ts +++ b/src/app/api/websites/[websiteId]/pageviews/route.ts @@ -2,7 +2,7 @@ import { getCompareDate } from '@/lib/date'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getPageviewStats, getSessionStats } from '@/queries/sql'; export async function GET( @@ -21,7 +21,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, ['overview', 'compare']))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/replays/[replayId]/route.ts b/src/app/api/websites/[websiteId]/replays/[replayId]/route.ts index b3b749228..a35afae55 100644 --- a/src/app/api/websites/[websiteId]/replays/[replayId]/route.ts +++ b/src/app/api/websites/[websiteId]/replays/[replayId]/route.ts @@ -1,6 +1,6 @@ import { parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getReplayChunks } from '@/queries/sql'; function getEventTimestamp(event: any): number | null { @@ -86,7 +86,7 @@ export async function GET( const endEventIndex = parseOptionalInteger(searchParams.get('eventIndex')); const endAt = until !== undefined ? new Date(until) : undefined; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/replays/route.ts b/src/app/api/websites/[websiteId]/replays/route.ts index fb38a0178..d464fc42b 100644 --- a/src/app/api/websites/[websiteId]/replays/route.ts +++ b/src/app/api/websites/[websiteId]/replays/route.ts @@ -1,7 +1,7 @@ import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, pagingParams, searchParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionReplays } from '@/queries/sql'; export async function GET( @@ -22,7 +22,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/replays/saved/[replayId]/route.ts b/src/app/api/websites/[websiteId]/replays/saved/[replayId]/route.ts index 2212d9d08..f4b45afee 100644 --- a/src/app/api/websites/[websiteId]/replays/saved/[replayId]/route.ts +++ b/src/app/api/websites/[websiteId]/replays/saved/[replayId]/route.ts @@ -1,7 +1,7 @@ import { z } from 'zod'; import { parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; -import { canUpdateWebsite, canViewWebsite } from '@/permissions'; +import { canUpdateWebsite, canViewAuthenticatedWebsite } from '@/permissions'; import { createReplaySaved, deleteReplaySaved, @@ -20,7 +20,7 @@ export async function GET( const { websiteId, replayId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/replays/saved/route.ts b/src/app/api/websites/[websiteId]/replays/saved/route.ts index aca134d2c..a72e3f25a 100644 --- a/src/app/api/websites/[websiteId]/replays/saved/route.ts +++ b/src/app/api/websites/[websiteId]/replays/saved/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { pagingParams, searchParams } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSavedReplays } from '@/queries/prisma/sessionReplay'; export async function GET( @@ -22,7 +22,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/reports/route.ts b/src/app/api/websites/[websiteId]/reports/route.ts index 0e4e404ec..2a22e3af5 100644 --- a/src/app/api/websites/[websiteId]/reports/route.ts +++ b/src/app/api/websites/[websiteId]/reports/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { pagingParams, reportTypeParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getReports } from '@/queries/prisma'; export async function GET( @@ -23,7 +23,7 @@ export async function GET( const { websiteId } = await params; const { type, page, pageSize, search } = query; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/revenue/chart/route.ts b/src/app/api/websites/[websiteId]/revenue/chart/route.ts index 27e0c00f7..93e171d06 100644 --- a/src/app/api/websites/[websiteId]/revenue/chart/route.ts +++ b/src/app/api/websites/[websiteId]/revenue/chart/route.ts @@ -2,11 +2,8 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; -import { - getRevenueChart, - type RevenuParameters, -} from '@/queries/sql/reports/getRevenueChart'; +import { canViewWebsiteSection } from '@/permissions'; +import { getRevenueChart, type RevenuParameters } from '@/queries/sql/reports/getRevenueChart'; export async function GET( request: Request, @@ -25,7 +22,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'revenue'))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/revenue/metrics/route.ts b/src/app/api/websites/[websiteId]/revenue/metrics/route.ts index 2498e50d5..75ce6e111 100644 --- a/src/app/api/websites/[websiteId]/revenue/metrics/route.ts +++ b/src/app/api/websites/[websiteId]/revenue/metrics/route.ts @@ -2,12 +2,9 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { badRequest, json, unauthorized } from '@/lib/response'; import { filterParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; -import { - getRevenueMetrics, - type RevenueMetricType, -} from '@/queries/sql/reports/getRevenueMetrics'; +import { canViewWebsiteSection } from '@/permissions'; import type { RevenuParameters } from '@/queries/sql/reports/getRevenueChart'; +import { getRevenueMetrics, type RevenueMetricType } from '@/queries/sql/reports/getRevenueMetrics'; const revenueMetricType = z.enum(['country', 'region', 'referrer', 'channel']); @@ -29,7 +26,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'revenue'))) { return unauthorized(); } @@ -42,7 +39,5 @@ export async function GET( const parameters = { ...filters, currency } as RevenuParameters; - return json( - await getRevenueMetrics(websiteId, parameters, filters, type as RevenueMetricType), - ); + return json(await getRevenueMetrics(websiteId, parameters, filters, type as RevenueMetricType)); } diff --git a/src/app/api/websites/[websiteId]/revenue/sessions/route.ts b/src/app/api/websites/[websiteId]/revenue/sessions/route.ts index 78fad488e..c09488054 100644 --- a/src/app/api/websites/[websiteId]/revenue/sessions/route.ts +++ b/src/app/api/websites/[websiteId]/revenue/sessions/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, pagingParams, searchParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getRevenueSessions } from '@/queries/sql/reports/getRevenueSessions'; export async function GET( @@ -24,7 +24,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'revenue'))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/revenue/stats/route.ts b/src/app/api/websites/[websiteId]/revenue/stats/route.ts index f10852f6d..68295515f 100644 --- a/src/app/api/websites/[websiteId]/revenue/stats/route.ts +++ b/src/app/api/websites/[websiteId]/revenue/stats/route.ts @@ -3,8 +3,8 @@ import { getCompareDate } from '@/lib/date'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; -import { type RevenuParameters } from '@/queries/sql/reports/getRevenueChart'; +import { canViewWebsiteSection } from '@/permissions'; +import type { RevenuParameters } from '@/queries/sql/reports/getRevenueChart'; import { getRevenueStats } from '@/queries/sql/reports/getRevenueStats'; export async function GET( @@ -24,7 +24,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'revenue'))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/route.ts b/src/app/api/websites/[websiteId]/route.ts index b0897b254..c56b3ab8b 100644 --- a/src/app/api/websites/[websiteId]/route.ts +++ b/src/app/api/websites/[websiteId]/route.ts @@ -5,7 +5,7 @@ import { uuid } from '@/lib/crypto'; import { getRecorderConfig, getRecorderEnabled } from '@/lib/recorder'; import { parseRequest } from '@/lib/request'; import { badRequest, json, ok, serverError, unauthorized } from '@/lib/response'; -import { canDeleteWebsite, canUpdateWebsite, canViewWebsite } from '@/permissions'; +import { canDeleteWebsite, canUpdateWebsite, canViewSharedWebsite } from '@/permissions'; import { createShare, deleteSharesByEntityId, @@ -27,7 +27,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewSharedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/segments/[segmentId]/route.ts b/src/app/api/websites/[websiteId]/segments/[segmentId]/route.ts index 045125550..1bd3b22ea 100644 --- a/src/app/api/websites/[websiteId]/segments/[segmentId]/route.ts +++ b/src/app/api/websites/[websiteId]/segments/[segmentId]/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { parseRequest } from '@/lib/request'; import { json, notFound, ok, unauthorized } from '@/lib/response'; import { anyObjectParam, segmentTypeParam } from '@/lib/schema'; -import { canDeleteWebsite, canUpdateWebsite, canViewWebsite } from '@/permissions'; +import { canDeleteWebsite, canUpdateWebsite, canViewAuthenticatedWebsite } from '@/permissions'; import { deleteSegment, getWebsiteSegment, updateSegment } from '@/queries/prisma'; export async function GET( @@ -17,7 +17,7 @@ export async function GET( const { websiteId, segmentId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/segments/route.ts b/src/app/api/websites/[websiteId]/segments/route.ts index db34193ed..3b094dc34 100644 --- a/src/app/api/websites/[websiteId]/segments/route.ts +++ b/src/app/api/websites/[websiteId]/segments/route.ts @@ -3,7 +3,7 @@ import { uuid } from '@/lib/crypto'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { searchParams, segmentParamSchema, segmentTypeParam } from '@/lib/schema'; -import { canUpdateWebsite, canViewWebsite } from '@/permissions'; +import { canUpdateWebsite, canViewAuthenticatedWebsite } from '@/permissions'; import { createSegment, getWebsiteSegments } from '@/queries/prisma'; export async function GET( @@ -24,7 +24,7 @@ export async function GET( const { websiteId } = await params; const { type } = query; - if (websiteId && !(await canViewWebsite(auth, websiteId))) { + if (websiteId && !(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/session-data-pivot/route.ts b/src/app/api/websites/[websiteId]/session-data-pivot/route.ts index 6bf0e2b12..01677d305 100644 --- a/src/app/api/websites/[websiteId]/session-data-pivot/route.ts +++ b/src/app/api/websites/[websiteId]/session-data-pivot/route.ts @@ -3,7 +3,7 @@ import { parsePropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, pagingParams, timezoneParam, unitParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionDataPivot } from '@/queries/sql/sessions/getSessionDataPivot'; export async function GET( @@ -28,7 +28,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/session-data/array-series/route.ts b/src/app/api/websites/[websiteId]/session-data/array-series/route.ts index 5dd5b4b4a..05c7619f8 100644 --- a/src/app/api/websites/[websiteId]/session-data/array-series/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/array-series/route.ts @@ -3,7 +3,7 @@ import { parsePropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionDataArraySeries } from '@/queries/sql'; export async function GET( @@ -27,7 +27,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/session-data/date-series/route.ts b/src/app/api/websites/[websiteId]/session-data/date-series/route.ts index a607ff9ac..4b4da4ddc 100644 --- a/src/app/api/websites/[websiteId]/session-data/date-series/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/date-series/route.ts @@ -3,7 +3,7 @@ import { parsePropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, timezoneParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionDataDateSeries } from '@/queries/sql'; export async function GET( @@ -26,7 +26,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/session-data/numeric-series/route.ts b/src/app/api/websites/[websiteId]/session-data/numeric-series/route.ts index 09cf623b6..b1db37c23 100644 --- a/src/app/api/websites/[websiteId]/session-data/numeric-series/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/numeric-series/route.ts @@ -3,7 +3,7 @@ import { parsePropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionDataNumericSeries } from '@/queries/sql'; export async function GET( @@ -28,14 +28,20 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } const { propertyName, metric, ...rest } = query; const filters = await getQueryFilters(rest, websiteId); const propertyFilters = parsePropertyFilters(query); - const data = await getSessionDataNumericSeries(websiteId, propertyName, metric, filters, propertyFilters); + const data = await getSessionDataNumericSeries( + websiteId, + propertyName, + metric, + filters, + propertyFilters, + ); return json(data); } diff --git a/src/app/api/websites/[websiteId]/session-data/numeric-stats/route.ts b/src/app/api/websites/[websiteId]/session-data/numeric-stats/route.ts index a27f1bc73..2b6b8892f 100644 --- a/src/app/api/websites/[websiteId]/session-data/numeric-stats/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/numeric-stats/route.ts @@ -3,7 +3,7 @@ import { parsePropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, timezoneParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionDataNumericStats } from '@/queries/sql'; export async function GET( @@ -26,7 +26,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/session-data/properties/route.ts b/src/app/api/websites/[websiteId]/session-data/properties/route.ts index 8ac17e4b8..a15df8e98 100644 --- a/src/app/api/websites/[websiteId]/session-data/properties/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/properties/route.ts @@ -3,7 +3,7 @@ import { parsePropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionDataProperties } from '@/queries/sql'; export async function GET( @@ -25,7 +25,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } @@ -33,12 +33,7 @@ export async function GET( const filters = await getQueryFilters(rest, websiteId); const propertyFilters = parsePropertyFilters(query); - const data = await getSessionDataProperties( - websiteId, - filters, - propertyFilters, - propertyName, - ); + const data = await getSessionDataProperties(websiteId, filters, propertyFilters, propertyName); return json(data); } diff --git a/src/app/api/websites/[websiteId]/session-data/property-series/route.ts b/src/app/api/websites/[websiteId]/session-data/property-series/route.ts index fc054e6e2..79672479b 100644 --- a/src/app/api/websites/[websiteId]/session-data/property-series/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/property-series/route.ts @@ -3,7 +3,7 @@ import { parsePropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionDataPropertySeries } from '@/queries/sql'; export async function GET( @@ -27,14 +27,19 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } const { propertyName, ...rest } = query; const filters = await getQueryFilters(rest, websiteId); const propertyFilters = parsePropertyFilters(query); - const data = await getSessionDataPropertySeries(websiteId, propertyName, filters, propertyFilters); + const data = await getSessionDataPropertySeries( + websiteId, + propertyName, + filters, + propertyFilters, + ); return json(data); } diff --git a/src/app/api/websites/[websiteId]/session-data/stats/route.ts b/src/app/api/websites/[websiteId]/session-data/stats/route.ts index 3a41047bb..65b7d060d 100644 --- a/src/app/api/websites/[websiteId]/session-data/stats/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/stats/route.ts @@ -3,7 +3,7 @@ import { parsePropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionDataActivityStats } from '@/queries/sql/sessions/getSessionDataActivityStats'; export async function GET( @@ -27,14 +27,19 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } const { propertyName, ...rest } = query; const filters = await getQueryFilters(rest, websiteId); const propertyFilters = parsePropertyFilters(query); - const result = await getSessionDataActivityStats(websiteId, propertyName, filters, propertyFilters); + const result = await getSessionDataActivityStats( + websiteId, + propertyName, + filters, + propertyFilters, + ); return json(result); } diff --git a/src/app/api/websites/[websiteId]/session-data/values/route.ts b/src/app/api/websites/[websiteId]/session-data/values/route.ts index 57b27e300..f7af66134 100644 --- a/src/app/api/websites/[websiteId]/session-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/values/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionDataValues } from '@/queries/sql'; export async function GET( @@ -25,7 +25,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts b/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts index 41b766d03..d6681072f 100644 --- a/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts @@ -1,7 +1,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionActivity } from '@/queries/sql'; export async function GET( @@ -21,7 +21,7 @@ export async function GET( const { websiteId, sessionId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/sessions/[sessionId]/properties/route.ts b/src/app/api/websites/[websiteId]/sessions/[sessionId]/properties/route.ts index 6b5c2418a..1ba60e4c1 100644 --- a/src/app/api/websites/[websiteId]/sessions/[sessionId]/properties/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/[sessionId]/properties/route.ts @@ -1,6 +1,6 @@ import { parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionData } from '@/queries/sql'; export async function GET( @@ -15,7 +15,7 @@ export async function GET( const { websiteId, sessionId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/sessions/[sessionId]/replays/route.ts b/src/app/api/websites/[websiteId]/sessions/[sessionId]/replays/route.ts index b71ff46a9..f57446df3 100644 --- a/src/app/api/websites/[websiteId]/sessions/[sessionId]/replays/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/[sessionId]/replays/route.ts @@ -1,7 +1,7 @@ import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { pagingParams, searchParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getSessionReplays } from '@/queries/sql'; export async function GET( @@ -21,7 +21,7 @@ export async function GET( const { websiteId, sessionId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/sessions/[sessionId]/route.ts b/src/app/api/websites/[websiteId]/sessions/[sessionId]/route.ts index 109166370..21ac130b4 100644 --- a/src/app/api/websites/[websiteId]/sessions/[sessionId]/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/[sessionId]/route.ts @@ -1,6 +1,6 @@ import { parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; -import { canViewWebsite } from '@/permissions'; +import { canViewAuthenticatedWebsite } from '@/permissions'; import { getWebsiteSession } from '@/queries/sql'; export async function GET( @@ -15,7 +15,7 @@ export async function GET( const { websiteId, sessionId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/sessions/route.ts b/src/app/api/websites/[websiteId]/sessions/route.ts index 88199aff9..dd748bc7c 100644 --- a/src/app/api/websites/[websiteId]/sessions/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/route.ts @@ -1,7 +1,7 @@ import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, pagingParams, searchParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getWebsiteSessions } from '@/queries/sql'; export async function GET( @@ -22,7 +22,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'sessions'))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/sessions/stats/route.ts b/src/app/api/websites/[websiteId]/sessions/stats/route.ts index 459830edf..56b2f807e 100644 --- a/src/app/api/websites/[websiteId]/sessions/stats/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/stats/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getWebsiteSessionStats } from '@/queries/sql'; export async function GET( @@ -23,7 +23,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'sessions'))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/sessions/weekly/route.ts b/src/app/api/websites/[websiteId]/sessions/weekly/route.ts index b9ccf3ef0..910f83333 100644 --- a/src/app/api/websites/[websiteId]/sessions/weekly/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/weekly/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, timezoneParam } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getWeeklyTraffic } from '@/queries/sql'; export async function GET( @@ -24,7 +24,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, 'sessions'))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/shares/route.ts b/src/app/api/websites/[websiteId]/shares/route.ts index 65d53771d..6898eaa29 100644 --- a/src/app/api/websites/[websiteId]/shares/route.ts +++ b/src/app/api/websites/[websiteId]/shares/route.ts @@ -5,7 +5,7 @@ import { getRandomChars } from '@/lib/generate'; import { parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { anyObjectParam, filterParams, pagingParams } from '@/lib/schema'; -import { canUpdateWebsite, canViewWebsite } from '@/permissions'; +import { canUpdateWebsite, canViewAuthenticatedWebsite } from '@/permissions'; import { createShare, getSharesByEntityId } from '@/queries/prisma'; export async function GET( @@ -26,7 +26,7 @@ export async function GET( const { websiteId } = await params; const { page, pageSize, search } = query; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewAuthenticatedWebsite(auth, websiteId))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/stats/route.ts b/src/app/api/websites/[websiteId]/stats/route.ts index bb060e41f..5202566f9 100644 --- a/src/app/api/websites/[websiteId]/stats/route.ts +++ b/src/app/api/websites/[websiteId]/stats/route.ts @@ -2,7 +2,7 @@ import { getCompareDate } from '@/lib/date'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getWebsiteStats } from '@/queries/sql'; export async function GET( @@ -21,7 +21,7 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if (!(await canViewWebsiteSection(auth, websiteId, ['overview', 'compare']))) { return unauthorized(); } diff --git a/src/app/api/websites/[websiteId]/values/route.ts b/src/app/api/websites/[websiteId]/values/route.ts index f07e60f3d..d9242c504 100644 --- a/src/app/api/websites/[websiteId]/values/route.ts +++ b/src/app/api/websites/[websiteId]/values/route.ts @@ -2,7 +2,7 @@ import { EVENT_COLUMNS, FILTER_COLUMNS, SEGMENT_TYPES, SESSION_COLUMNS } from '@ import { getQueryFilters, parseRequest } from '@/lib/request'; import { badRequest, json, unauthorized } from '@/lib/response'; import { fieldsParam, searchParams, withDateRange } from '@/lib/schema'; -import { canViewWebsite } from '@/permissions'; +import { canViewWebsiteSection } from '@/permissions'; import { getWebsiteSegments } from '@/queries/prisma'; import { getValues } from '@/queries/sql'; @@ -23,7 +23,17 @@ export async function GET( const { websiteId } = await params; - if (!(await canViewWebsite(auth, websiteId))) { + if ( + !(await canViewWebsiteSection(auth, websiteId, [ + 'overview', + 'events', + 'sessions', + 'compare', + 'breakdown', + 'utm', + 'attribution', + ])) + ) { return unauthorized(); } diff --git a/src/lib/types.ts b/src/lib/types.ts index d2e20712b..94a14fab7 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -20,6 +20,7 @@ export interface Auth { isAdmin: boolean; }; shareToken?: { + shareType?: number; websiteId?: string; websiteIds?: string[]; boardId?: string; diff --git a/src/permissions/index.ts b/src/permissions/index.ts index c566d77c6..f19c55e2c 100644 --- a/src/permissions/index.ts +++ b/src/permissions/index.ts @@ -3,6 +3,7 @@ export * from './entity'; export * from './link'; export * from './pixel'; export * from './report'; +export * from './share'; export * from './team'; export * from './user'; export * from './website'; diff --git a/src/permissions/share.ts b/src/permissions/share.ts new file mode 100644 index 000000000..d75d2b1eb --- /dev/null +++ b/src/permissions/share.ts @@ -0,0 +1,74 @@ +import { ENTITY_TYPE } from '@/lib/constants'; +import type { Auth } from '@/lib/types'; +import { canViewWebsite } from './website'; + +export type ShareSection = + | 'overview' + | 'events' + | 'sessions' + | 'realtime' + | 'performance' + | 'compare' + | 'breakdown' + | 'goals' + | 'funnels' + | 'journeys' + | 'retention' + | 'utm' + | 'revenue' + | 'attribution'; + +type ShareSectionInput = ShareSection | ShareSection[]; + +function shareTokenIncludesWebsite(auth: Auth | null | undefined, websiteId: string) { + const { shareToken } = auth || {}; + + return shareToken?.websiteId === websiteId || shareToken?.websiteIds?.includes(websiteId); +} + +export async function canViewWebsiteSection( + auth: Auth | null | undefined, + websiteId: string, + section: ShareSectionInput, +) { + if (auth?.user) { + return canViewWebsite(auth, websiteId); + } + + const { shareToken } = auth || {}; + + if ( + !shareToken || + shareToken.shareType !== ENTITY_TYPE.website || + !shareTokenIncludesWebsite(auth, websiteId) + ) { + return false; + } + + const sections = Array.isArray(section) ? section : [section]; + + return sections.some(key => shareToken.parameters?.[key] === true); +} + +export async function canViewSharedWebsite(auth: Auth | null | undefined, websiteId: string) { + if (auth?.user) { + return canViewWebsite(auth, websiteId); + } + + const { shareToken } = auth || {}; + + return ( + shareToken?.shareType === ENTITY_TYPE.website && shareTokenIncludesWebsite(auth, websiteId) + ); +} + +export async function canViewAuthenticatedWebsite( + auth: Auth | null | undefined, + websiteId: string, +) { + if (!auth?.user) { + return false; + } + + return canViewWebsite(auth, websiteId); +} From f366d946e85ebd97c3269ccd41c97601101f01db Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 2 Jun 2026 16:28:30 -0700 Subject: [PATCH 2/3] Allow unrestricted access when share token has no section flags --- src/permissions/share.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/permissions/share.ts b/src/permissions/share.ts index d75d2b1eb..1d22e8dda 100644 --- a/src/permissions/share.ts +++ b/src/permissions/share.ts @@ -18,6 +18,23 @@ export type ShareSection = | 'revenue' | 'attribution'; +const SHARE_SECTIONS: ShareSection[] = [ + 'overview', + 'events', + 'sessions', + 'realtime', + 'performance', + 'compare', + 'breakdown', + 'goals', + 'funnels', + 'journeys', + 'retention', + 'utm', + 'revenue', + 'attribution', +]; + type ShareSectionInput = ShareSection | ShareSection[]; function shareTokenIncludesWebsite(auth: Auth | null | undefined, websiteId: string) { @@ -46,6 +63,13 @@ export async function canViewWebsiteSection( } const sections = Array.isArray(section) ? section : [section]; + const hasSectionParameters = SHARE_SECTIONS.some( + key => typeof shareToken.parameters?.[key] === 'boolean', + ); + + if (!hasSectionParameters) { + return true; + } return sections.some(key => shareToken.parameters?.[key] === true); } From 9ba5fb7c1b11c1ea06cc3dd6c332a5703e316e1d Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 2 Jun 2026 16:54:35 -0700 Subject: [PATCH 3/3] Limit batch API payloads to 500 items --- src/app/api/batch/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/batch/route.ts b/src/app/api/batch/route.ts index 46e8b3c33..c7b7115f4 100644 --- a/src/app/api/batch/route.ts +++ b/src/app/api/batch/route.ts @@ -4,7 +4,7 @@ import { parseRequest } from '@/lib/request'; import { json, serverError } from '@/lib/response'; import { anyObjectParam } from '@/lib/schema'; -const schema = z.array(anyObjectParam); +const schema = z.array(anyObjectParam).max(500); export async function POST(request: Request) { try {