From 5404ebe034364ada8055e04aa8ba70628aae85ea Mon Sep 17 00:00:00 2001 From: Mees Frensel Date: Thu, 22 Jan 2026 16:38:22 +0100 Subject: [PATCH] fix(server): scoped permissions for more endpoints --- mobile/openapi/lib/model/permission.dart | 3 +++ open-api/immich-openapi-specs.json | 5 +++++ open-api/typescript-sdk/src/fetch-client.ts | 1 + server/src/controllers/asset-media.controller.ts | 2 +- server/src/controllers/asset.controller.ts | 2 +- server/src/controllers/view.controller.ts | 6 +++--- server/src/enum.ts | 2 ++ 7 files changed, 16 insertions(+), 5 deletions(-) diff --git a/mobile/openapi/lib/model/permission.dart b/mobile/openapi/lib/model/permission.dart index 37aecc8b9c..4ae42fb968 100644 --- a/mobile/openapi/lib/model/permission.dart +++ b/mobile/openapi/lib/model/permission.dart @@ -168,6 +168,7 @@ class Permission { static const queueJobPeriodRead = Permission._(r'queueJob.read'); static const queueJobPeriodUpdate = Permission._(r'queueJob.update'); static const queueJobPeriodDelete = Permission._(r'queueJob.delete'); + static const viewPeriodFolder = Permission._(r'view.folder'); static const workflowPeriodCreate = Permission._(r'workflow.create'); static const workflowPeriodRead = Permission._(r'workflow.read'); static const workflowPeriodUpdate = Permission._(r'workflow.update'); @@ -326,6 +327,7 @@ class Permission { queueJobPeriodRead, queueJobPeriodUpdate, queueJobPeriodDelete, + viewPeriodFolder, workflowPeriodCreate, workflowPeriodRead, workflowPeriodUpdate, @@ -519,6 +521,7 @@ class PermissionTypeTransformer { case r'queueJob.read': return Permission.queueJobPeriodRead; case r'queueJob.update': return Permission.queueJobPeriodUpdate; case r'queueJob.delete': return Permission.queueJobPeriodDelete; + case r'view.folder': return Permission.viewPeriodFolder; case r'workflow.create': return Permission.workflowPeriodCreate; case r'workflow.read': return Permission.workflowPeriodRead; case r'workflow.update': return Permission.workflowPeriodUpdate; diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index cb0c8f8a67..ce6a5db995 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -3173,6 +3173,7 @@ "state": "Stable" } ], + "x-immich-permission": "asset.upload", "x-immich-state": "Stable" } }, @@ -3225,6 +3226,7 @@ "state": "Stable" } ], + "x-immich-permission": "job.create", "x-immich-state": "Stable" } }, @@ -14618,6 +14620,7 @@ "state": "Stable" } ], + "x-immich-permission": "view.folder", "x-immich-state": "Stable" } }, @@ -14670,6 +14673,7 @@ "state": "Stable" } ], + "x-immich-permission": "view.folder", "x-immich-state": "Stable" } }, @@ -19054,6 +19058,7 @@ "queueJob.read", "queueJob.update", "queueJob.delete", + "view.folder", "workflow.create", "workflow.read", "workflow.update", diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index 09a0860539..0a6240f8c3 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -5620,6 +5620,7 @@ export enum Permission { QueueJobRead = "queueJob.read", QueueJobUpdate = "queueJob.update", QueueJobDelete = "queueJob.delete", + ViewFolder = "view.folder", WorkflowCreate = "workflow.create", WorkflowRead = "workflow.read", WorkflowUpdate = "workflow.update", diff --git a/server/src/controllers/asset-media.controller.ts b/server/src/controllers/asset-media.controller.ts index 788ee0c0ed..3ef63ff7f9 100644 --- a/server/src/controllers/asset-media.controller.ts +++ b/server/src/controllers/asset-media.controller.ts @@ -202,7 +202,7 @@ export class AssetMediaController { } @Post('exist') - @Authenticated() + @Authenticated({ permission: Permission.AssetUpload }) @Endpoint({ summary: 'Check existing assets', description: 'Checks if multiple assets exist on the server and returns all existing - used by background backup', diff --git a/server/src/controllers/asset.controller.ts b/server/src/controllers/asset.controller.ts index 988623360b..8eb3a5ce44 100644 --- a/server/src/controllers/asset.controller.ts +++ b/server/src/controllers/asset.controller.ts @@ -66,7 +66,7 @@ export class AssetController { } @Post('jobs') - @Authenticated() + @Authenticated({ permission: Permission.JobCreate }) @HttpCode(HttpStatus.NO_CONTENT) @Endpoint({ summary: 'Run an asset job', diff --git a/server/src/controllers/view.controller.ts b/server/src/controllers/view.controller.ts index 8a977e15bc..13b6d67470 100644 --- a/server/src/controllers/view.controller.ts +++ b/server/src/controllers/view.controller.ts @@ -3,7 +3,7 @@ import { ApiTags } from '@nestjs/swagger'; import { Endpoint, HistoryBuilder } from 'src/decorators'; import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; -import { ApiTag } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { ViewService } from 'src/services/view.service'; @@ -13,7 +13,7 @@ export class ViewController { constructor(private service: ViewService) {} @Get('folder/unique-paths') - @Authenticated() + @Authenticated({ permission: Permission.ViewFolder }) @Endpoint({ summary: 'Retrieve unique paths', description: 'Retrieve a list of unique folder paths from asset original paths.', @@ -24,7 +24,7 @@ export class ViewController { } @Get('folder') - @Authenticated() + @Authenticated({ permission: Permission.ViewFolder }) @Endpoint({ summary: 'Retrieve assets by original path', description: 'Retrieve assets that are children of a specific folder.', diff --git a/server/src/enum.ts b/server/src/enum.ts index 5a0f6bdbe0..ba8caaf4e3 100644 --- a/server/src/enum.ts +++ b/server/src/enum.ts @@ -270,6 +270,8 @@ export enum Permission { QueueJobUpdate = 'queueJob.update', QueueJobDelete = 'queueJob.delete', + ViewFolder = 'view.folder', + WorkflowCreate = 'workflow.create', WorkflowRead = 'workflow.read', WorkflowUpdate = 'workflow.update',