Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions backend/apps/cloud/src/analytics/analytics.controller.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ApiKeyAccess } from '../../../api-key/api-key-access.decorator'
import {
Controller,
Get,
Expand Down Expand Up @@ -47,6 +48,7 @@ export class CaptchaV2Controller {

@Get('summary')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Captcha summary',
Expand All @@ -72,6 +74,7 @@ export class CaptchaV2Controller {

@Get('timeseries')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Captcha timeseries',
Expand All @@ -97,6 +100,7 @@ export class CaptchaV2Controller {

@Get('breakdown')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Captcha breakdown',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ApiKeyAccess } from '../../../api-key/api-key-access.decorator'
import {
Controller,
Get,
Expand Down Expand Up @@ -52,6 +53,7 @@ export class ErrorsV2Controller {

@Get()
@Auth(true, true)
@ApiKeyAccess('errors:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Error groups',
Expand All @@ -77,6 +79,7 @@ export class ErrorsV2Controller {

@Get('overview')
@Auth(true, true)
@ApiKeyAccess('errors:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Errors overview',
Expand All @@ -102,6 +105,7 @@ export class ErrorsV2Controller {

@Get('timeseries')
@Auth(true, true)
@ApiKeyAccess('errors:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Errors timeseries',
Expand All @@ -126,6 +130,7 @@ export class ErrorsV2Controller {

@Get('breakdown')
@Auth(true, true)
@ApiKeyAccess('errors:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Errors breakdown',
Expand Down Expand Up @@ -154,6 +159,7 @@ export class ErrorsV2Controller {

@Get(':eid')
@Auth(true, true)
@ApiKeyAccess('errors:read', 'params', 'pid')
@ApiOperation({
summary: 'Error details',
description:
Expand Down Expand Up @@ -181,6 +187,7 @@ export class ErrorsV2Controller {

@Get(':eid/sessions')
@Auth(true, true)
@ApiKeyAccess('errors:read', 'params', 'pid', ['analytics:read'])
@ApiOperation({
summary: 'Error sessions',
description: 'Paginated sessions affected by a specific error group.',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ApiKeyAccess } from '../../../api-key/api-key-access.decorator'
import {
Controller,
Get,
Expand Down Expand Up @@ -48,6 +49,7 @@ export class PerformanceV2Controller {

@Get('summary')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Performance summary',
Expand All @@ -73,6 +75,7 @@ export class PerformanceV2Controller {

@Get('timeseries')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Performance timeseries',
Expand Down Expand Up @@ -101,6 +104,7 @@ export class PerformanceV2Controller {

@Get('breakdown')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Performance breakdown',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ApiKeyAccess } from '../../../api-key/api-key-access.decorator'
import {
Controller,
Get,
Expand Down Expand Up @@ -47,6 +48,10 @@ export class ProfilesV2Controller {

@Get()
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid', [
'events:read',
'errors:read',
])
@CacheableAnalytics()
@ApiOperation({
summary: 'Profiles',
Expand All @@ -72,6 +77,11 @@ export class ProfilesV2Controller {

@Get(':profileId')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid', [
'events:read',
'errors:read',
'revenue:read',
])
@ApiOperation({
summary: 'Profile details',
description:
Expand Down Expand Up @@ -103,6 +113,10 @@ export class ProfilesV2Controller {

@Get(':profileId/sessions')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid', [
'events:read',
'errors:read',
])
@ApiOperation({
summary: 'Profile sessions',
description: 'Paginated sessions recorded for a specific profile.',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ApiKeyAccess } from '../../../api-key/api-key-access.decorator'
import {
Controller,
Get,
Expand Down Expand Up @@ -51,6 +52,7 @@ export class ProjectV2Controller {

@Get('funnel')
@Auth(true, true)
@ApiKeyAccess('funnels:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Funnel analysis',
Expand All @@ -76,6 +78,11 @@ export class ProjectV2Controller {

@Get('funnel/sessions')
@Auth(true, true)
@ApiKeyAccess('funnels:read', 'params', 'pid', [
'analytics:read',
'events:read',
'errors:read',
])
@CacheableAnalytics()
@ApiOperation({
summary: 'Funnel sessions',
Expand Down Expand Up @@ -104,6 +111,7 @@ export class ProjectV2Controller {

@Get('live-visitors')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@ApiOperation({
summary: 'Live visitors',
description:
Expand All @@ -127,6 +135,7 @@ export class ProjectV2Controller {

@Get('dimensions')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@ApiOperation({
summary: 'Dimension & metric discovery',
description:
Expand Down Expand Up @@ -157,6 +166,7 @@ export class ProjectV2Controller {

@Get('dimensions/:dimension/values')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@ApiOperation({
summary: 'Dimension values',
description:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ApiKeyAccess } from '../../../api-key/api-key-access.decorator'
import {
Controller,
Get,
Expand Down Expand Up @@ -50,6 +51,7 @@ export class SeoV2Controller {

@Get('status')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Search Console connection status',
Expand All @@ -74,6 +76,7 @@ export class SeoV2Controller {

@Get('summary')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'SEO summary',
Expand All @@ -99,6 +102,7 @@ export class SeoV2Controller {

@Get('timeseries')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'SEO timeseries',
Expand All @@ -124,6 +128,7 @@ export class SeoV2Controller {

@Get('breakdown')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'SEO breakdown',
Expand Down Expand Up @@ -152,6 +157,7 @@ export class SeoV2Controller {

@Get('branded-traffic')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Branded vs non-branded traffic',
Expand All @@ -177,6 +183,7 @@ export class SeoV2Controller {

@Get('positions')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Search position analytics',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ApiKeyAccess } from '../../../api-key/api-key-access.decorator'
import {
Controller,
Get,
Expand Down Expand Up @@ -47,6 +48,12 @@ export class SessionsV2Controller {

@Get()
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid', [
'events:read',
'errors:read',
'replays:read',
'revenue:read',
])
@CacheableAnalytics()
@ApiOperation({
summary: 'Sessions',
Expand All @@ -72,6 +79,12 @@ export class SessionsV2Controller {

@Get(':psid')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid', [
'events:read',
'errors:read',
'replays:read',
'revenue:read',
])
@ApiOperation({
summary: 'Session details',
description:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ApiKeyAccess } from '../../../api-key/api-key-access.decorator'
import {
Controller,
Get,
Expand Down Expand Up @@ -54,6 +55,7 @@ export class TrafficV2Controller {

@Get('summary')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Traffic summary',
Expand All @@ -79,6 +81,7 @@ export class TrafficV2Controller {

@Get('timeseries')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Traffic timeseries',
Expand All @@ -104,6 +107,7 @@ export class TrafficV2Controller {

@Get('breakdown')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Traffic breakdown',
Expand Down Expand Up @@ -132,6 +136,7 @@ export class TrafficV2Controller {

@Get('custom-events')
@Auth(true, true)
@ApiKeyAccess('events:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Custom events',
Expand Down Expand Up @@ -160,6 +165,7 @@ export class TrafficV2Controller {

@Get('custom-metrics')
@Auth(true, true)
@ApiKeyAccess('events:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Custom metrics',
Expand Down Expand Up @@ -188,6 +194,7 @@ export class TrafficV2Controller {

@Get('custom-events/timeseries')
@Auth(true, true)
@ApiKeyAccess('events:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Custom events timeseries',
Expand Down Expand Up @@ -216,6 +223,7 @@ export class TrafficV2Controller {

@Get('custom-events/metadata')
@Auth(true, true)
@ApiKeyAccess('events:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Custom event metadata',
Expand Down Expand Up @@ -244,6 +252,7 @@ export class TrafficV2Controller {

@Get('page-properties/metadata')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Page property values',
Expand Down Expand Up @@ -271,6 +280,7 @@ export class TrafficV2Controller {

@Get('page-properties')
@Auth(true, true)
@ApiKeyAccess('analytics:read', 'params', 'pid')
@CacheableAnalytics()
@ApiOperation({
summary: 'Page properties',
Expand Down
15 changes: 15 additions & 0 deletions backend/apps/cloud/src/api-key/api-key-access.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { SetMetadata } from '@nestjs/common'
import { API_KEY_ACCESS, ApiKeyPolicy, ApiKeyScope } from './api-key.types'

export const ApiKeyAccess = (
scope: ApiKeyScope,
source: ApiKeyPolicy['source'],
field = 'pid',
requires: ApiKeyScope[] = [],
) =>
SetMetadata(API_KEY_ACCESS, {
scope,
source,
field,
requires,
} satisfies ApiKeyPolicy)
20 changes: 20 additions & 0 deletions backend/apps/cloud/src/api-key/api-key-collection.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
CanActivate,
ExecutionContext,
Injectable,
UseGuards,
} from '@nestjs/common'
import { AuthGuard } from '@nestjs/passport'
import { ApiKeyGuard } from './api-key.guard'
import { ApiKeyRateLimitGuard } from '../auth/guards/api-key-rate-limit.guard'

@Injectable()
class CollectionKeyGuard extends AuthGuard('api-key') implements CanActivate {
canActivate(context: ExecutionContext) {
if (!context.switchToHttp().getRequest().headers?.['x-api-key']) return true
return super.canActivate(context)
}
}

export const ApiKeyCollection = () =>
UseGuards(CollectionKeyGuard, ApiKeyGuard, ApiKeyRateLimitGuard)
Loading
Loading