@solidxai/core 0.1.12-beta.2 → 0.1.12-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +16 -0
- package/CLAUDE.md +26 -0
- package/dist/constants/media-file-types.d.ts +5 -0
- package/dist/constants/media-file-types.d.ts.map +1 -0
- package/dist/constants/media-file-types.js +27 -0
- package/dist/constants/media-file-types.js.map +1 -0
- package/dist/controllers/media.controller.d.ts +14 -11
- package/dist/controllers/media.controller.d.ts.map +1 -1
- package/dist/controllers/media.controller.js +72 -33
- package/dist/controllers/media.controller.js.map +1 -1
- package/dist/dtos/create-media.dto.d.ts +1 -0
- package/dist/dtos/create-media.dto.d.ts.map +1 -1
- package/dist/dtos/create-media.dto.js +7 -1
- package/dist/dtos/create-media.dto.js.map +1 -1
- package/dist/dtos/update-media.dto.d.ts +1 -0
- package/dist/dtos/update-media.dto.d.ts.map +1 -1
- package/dist/dtos/update-media.dto.js +7 -1
- package/dist/dtos/update-media.dto.js.map +1 -1
- package/dist/entities/media.entity.d.ts +1 -0
- package/dist/entities/media.entity.d.ts.map +1 -1
- package/dist/entities/media.entity.js +9 -1
- package/dist/entities/media.entity.js.map +1 -1
- package/dist/enums/auth-type.enum.d.ts +2 -1
- package/dist/enums/auth-type.enum.d.ts.map +1 -1
- package/dist/enums/auth-type.enum.js +1 -0
- package/dist/enums/auth-type.enum.js.map +1 -1
- package/dist/guards/authentication.guard.d.ts +3 -1
- package/dist/guards/authentication.guard.d.ts.map +1 -1
- package/dist/guards/authentication.guard.js +5 -1
- package/dist/guards/authentication.guard.js.map +1 -1
- package/dist/guards/media-signed-url.guard.d.ts +9 -0
- package/dist/guards/media-signed-url.guard.d.ts.map +1 -0
- package/dist/guards/media-signed-url.guard.js +49 -0
- package/dist/guards/media-signed-url.guard.js.map +1 -0
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js +10 -13
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js.map +1 -1
- package/dist/repository/media.repository.d.ts.map +1 -1
- package/dist/repository/media.repository.js +2 -0
- package/dist/repository/media.repository.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +88 -3
- package/dist/services/media-download-url.service.d.ts +21 -0
- package/dist/services/media-download-url.service.d.ts.map +1 -0
- package/dist/services/media-download-url.service.js +67 -0
- package/dist/services/media-download-url.service.js.map +1 -0
- package/dist/services/media-storage.utils.d.ts +27 -0
- package/dist/services/media-storage.utils.d.ts.map +1 -0
- package/dist/services/media-storage.utils.js +82 -0
- package/dist/services/media-storage.utils.js.map +1 -0
- package/dist/services/media.service.d.ts +20 -4
- package/dist/services/media.service.d.ts.map +1 -1
- package/dist/services/media.service.js +157 -55
- package/dist/services/media.service.js.map +1 -1
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.d.ts +4 -4
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.d.ts.map +1 -1
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.js +37 -63
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
- package/dist/services/mediaStorageProviders/file-storage-provider.d.ts +5 -5
- package/dist/services/mediaStorageProviders/file-storage-provider.d.ts.map +1 -1
- package/dist/services/mediaStorageProviders/file-storage-provider.js +37 -38
- package/dist/services/mediaStorageProviders/file-storage-provider.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +11 -1
- package/dist/solid-core.module.js.map +1 -1
- package/dist/subscribers/audit.subscriber.js +1 -1
- package/dist/subscribers/audit.subscriber.js.map +1 -1
- package/package.json +1 -1
- package/src/constants/media-file-types.ts +44 -0
- package/src/controllers/media.controller.ts +44 -24
- package/src/dtos/create-media.dto.ts +8 -3
- package/src/dtos/update-media.dto.ts +8 -3
- package/src/entities/media.entity.ts +4 -1
- package/src/enums/auth-type.enum.ts +1 -0
- package/src/guards/authentication.guard.ts +3 -0
- package/src/guards/media-signed-url.guard.ts +41 -0
- package/src/helpers/field-crud-managers/MediaFieldCrudManager.ts +12 -24
- package/src/repository/media.repository.ts +2 -0
- package/src/seeders/seed-data/solid-core-metadata.json +88 -3
- package/src/services/1.js +6 -0
- package/src/services/media-download-url.service.ts +67 -0
- package/src/services/media-storage.utils.ts +79 -0
- package/src/services/media.service.ts +189 -59
- package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +52 -76
- package/src/services/mediaStorageProviders/file-storage-provider.ts +44 -48
- package/src/solid-core.module.ts +21 -2
- package/src/subscribers/audit.subscriber.ts +1 -1
- package/dist-tests/api/authenticate.spec.js +0 -119
- package/dist-tests/api/authenticate.spec.js.map +0 -1
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +0 -97
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +0 -1
- package/dist-tests/api/ping.spec.js +0 -21
- package/dist-tests/api/ping.spec.js.map +0 -1
- package/dist-tests/helpers/auth.js +0 -41
- package/dist-tests/helpers/auth.js.map +0 -1
- package/dist-tests/helpers/env.js +0 -11
- package/dist-tests/helpers/env.js.map +0 -1
- package/docs/agent-builder/notebook-lm-prompt-for-agent-builder.md +0 -136
- package/docs/agent-builder/team-ready-note-agent-builder.md +0 -305
- package/docs/agent-hub-grooming.md +0 -301
- package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +0 -438
- package/docs/dashboards/dashboard-curl-smoke-tests.txt +0 -146
- package/docs/dashboards/delete-legacy-dashboard-metadata.sql +0 -172
- package/docs/datasource-introspection-ddl-analysis.md +0 -326
- package/docs/datasource-introspection-implementation-plan.md +0 -306
- package/docs/grouping-enhancements.md +0 -89
- package/docs/java-spring/README.md +0 -3
- package/docs/java-spring/solid-core-module-deep-dive-report.md +0 -1317
- package/docs/module-package-import-handoff.md +0 -691
- package/docs/seed-changes.md +0 -65
- package/docs/test-data-workflow.md +0 -200
- package/docs/type-declaration-import-issue.md +0 -24
- package/docs/workflow/business-automation-example-notes.md +0 -309
- package/docs/workflow/data-engineering-pipeline-example-notes.md +0 -330
- package/docs/workflow/foreach-example-notes.md +0 -187
- package/docs/workflow/hello-world-example-notes.md +0 -271
- package/docs/workflow/kestra-concepts-plugins-blueprints.md +0 -315
- package/docs/workflow/loop-until-example-notes.md +0 -198
- package/docs/workflow/microservices-and-apis-example-notes.md +0 -264
- package/docs/workflow/samples.md +0 -25
- package/docs/workflow/what-is-kestra.md +0 -79
- package/docs/workflow/workflow-core-module-handoff-summary.md +0 -191
- package/docs/workflow/workflow-module-brd.md +0 -185
- package/docs/workflow/workflow-module-domain-model.md +0 -252
- package/docs/workflow/workflow-module-metadata-dsl.md +0 -302
- package/docs/workflow/workflow-module-technical-spec.md +0 -293
- package/docs/workflow/workflow-node-type-contracts.md +0 -635
- package/docs/workflow/workflow-node-ui-metadata-contract.md +0 -1262
- package/docs/workflow/workflow-solidx-model-field-spec.md +0 -284
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-type.enum.js","sourceRoot":"","sources":["../../src/enums/auth-type.enum.ts"],"names":[],"mappings":";;;AAAA,IAAY,
|
|
1
|
+
{"version":3,"file":"auth-type.enum.js","sourceRoot":"","sources":["../../src/enums/auth-type.enum.ts"],"names":[],"mappings":";;;AAAA,IAAY,QAKX;AALD,WAAY,QAAQ;IAChB,2CAAM,CAAA;IACN,2CAAM,CAAA;IACN,uCAAI,CAAA;IACJ,2DAAc,CAAA;AAClB,CAAC,EALW,QAAQ,wBAAR,QAAQ,QAKnB","sourcesContent":["export enum AuthType {\n Bearer,\n ApiKey,\n None,\n MediaSignedUrl,\n}\n"]}
|
|
@@ -2,17 +2,19 @@ import { CanActivate, ExecutionContext } from '@nestjs/common';
|
|
|
2
2
|
import { Reflector } from '@nestjs/core';
|
|
3
3
|
import { AccessTokenGuard } from './access-token.guard';
|
|
4
4
|
import { ApiKeyGuard } from './api-key.guard';
|
|
5
|
+
import { MediaSignedUrlGuard } from './media-signed-url.guard';
|
|
5
6
|
import { PermissionMetadataService } from '../services/permission-metadata.service';
|
|
6
7
|
import { ClsService } from 'nestjs-cls';
|
|
7
8
|
export declare class AuthenticationGuard implements CanActivate {
|
|
8
9
|
private readonly reflector;
|
|
9
10
|
private readonly accessTokenGuard;
|
|
10
11
|
private readonly apiKeyGuard;
|
|
12
|
+
private readonly mediaSignedUrlGuard;
|
|
11
13
|
private readonly permissionService;
|
|
12
14
|
private readonly cls;
|
|
13
15
|
private static readonly defaultAuthTypes;
|
|
14
16
|
private readonly authTypeGuardMap;
|
|
15
|
-
constructor(reflector: Reflector, accessTokenGuard: AccessTokenGuard, apiKeyGuard: ApiKeyGuard, permissionService: PermissionMetadataService, cls: ClsService);
|
|
17
|
+
constructor(reflector: Reflector, accessTokenGuard: AccessTokenGuard, apiKeyGuard: ApiKeyGuard, mediaSignedUrlGuard: MediaSignedUrlGuard, permissionService: PermissionMetadataService, cls: ClsService);
|
|
16
18
|
private isGenericUnauthorizedError;
|
|
17
19
|
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
18
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authentication.guard.d.ts","sourceRoot":"","sources":["../../src/guards/authentication.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,gBAAgB,EAGjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"authentication.guard.d.ts","sourceRoot":"","sources":["../../src/guards/authentication.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,gBAAgB,EAGjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,qBACa,mBAAoB,YAAW,WAAW;IAYnD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG;IAhBtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAsC;IAC9E,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAO7B;gBAGe,SAAS,EAAE,SAAS,EACpB,gBAAgB,EAAE,gBAAgB,EAClC,WAAW,EAAE,WAAW,EACxB,mBAAmB,EAAE,mBAAmB,EACxC,iBAAiB,EAAE,yBAAyB,EAC5C,GAAG,EAAE,UAAU;IAGlC,OAAO,CAAC,0BAA0B;IAgB5B,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;CAsD/D"}
|
|
@@ -17,20 +17,23 @@ const auth_decorator_1 = require("../decorators/auth.decorator");
|
|
|
17
17
|
const auth_type_enum_1 = require("../enums/auth-type.enum");
|
|
18
18
|
const access_token_guard_1 = require("./access-token.guard");
|
|
19
19
|
const api_key_guard_1 = require("./api-key.guard");
|
|
20
|
+
const media_signed_url_guard_1 = require("./media-signed-url.guard");
|
|
20
21
|
const public_decorator_1 = require("../decorators/public.decorator");
|
|
21
22
|
const permission_metadata_service_1 = require("../services/permission-metadata.service");
|
|
22
23
|
const nestjs_cls_1 = require("nestjs-cls");
|
|
23
24
|
let AuthenticationGuard = AuthenticationGuard_1 = class AuthenticationGuard {
|
|
24
|
-
constructor(reflector, accessTokenGuard, apiKeyGuard, permissionService, cls) {
|
|
25
|
+
constructor(reflector, accessTokenGuard, apiKeyGuard, mediaSignedUrlGuard, permissionService, cls) {
|
|
25
26
|
this.reflector = reflector;
|
|
26
27
|
this.accessTokenGuard = accessTokenGuard;
|
|
27
28
|
this.apiKeyGuard = apiKeyGuard;
|
|
29
|
+
this.mediaSignedUrlGuard = mediaSignedUrlGuard;
|
|
28
30
|
this.permissionService = permissionService;
|
|
29
31
|
this.cls = cls;
|
|
30
32
|
this.authTypeGuardMap = {
|
|
31
33
|
[auth_type_enum_1.AuthType.Bearer]: this.accessTokenGuard,
|
|
32
34
|
[auth_type_enum_1.AuthType.ApiKey]: this.apiKeyGuard,
|
|
33
35
|
[auth_type_enum_1.AuthType.None]: { canActivate: () => true },
|
|
36
|
+
[auth_type_enum_1.AuthType.MediaSignedUrl]: this.mediaSignedUrlGuard,
|
|
34
37
|
};
|
|
35
38
|
}
|
|
36
39
|
isGenericUnauthorizedError(error) {
|
|
@@ -89,6 +92,7 @@ exports.AuthenticationGuard = AuthenticationGuard = AuthenticationGuard_1 = __de
|
|
|
89
92
|
__metadata("design:paramtypes", [core_1.Reflector,
|
|
90
93
|
access_token_guard_1.AccessTokenGuard,
|
|
91
94
|
api_key_guard_1.ApiKeyGuard,
|
|
95
|
+
media_signed_url_guard_1.MediaSignedUrlGuard,
|
|
92
96
|
permission_metadata_service_1.PermissionMetadataService,
|
|
93
97
|
nestjs_cls_1.ClsService])
|
|
94
98
|
], AuthenticationGuard);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authentication.guard.js","sourceRoot":"","sources":["../../src/guards/authentication.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAKwB;AACxB,uCAAyC;AACzC,iEAA6D;AAC7D,4DAAmD;AACnD,6DAAwD;AACxD,mDAA8C;AAC9C,qEAA+D;AAC/D,yFAAoF;AACpF,2CAAwC;AAGjC,IAAM,mBAAmB,2BAAzB,MAAM,mBAAmB;
|
|
1
|
+
{"version":3,"file":"authentication.guard.js","sourceRoot":"","sources":["../../src/guards/authentication.guard.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CanActivate,\n ExecutionContext,\n Injectable,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { AUTH_TYPE_KEY } from '../decorators/auth.decorator';\nimport { AuthType } from '../enums/auth-type.enum';\nimport { AccessTokenGuard } from './access-token.guard';\nimport { ApiKeyGuard } from './api-key.guard';\nimport { MediaSignedUrlGuard } from './media-signed-url.guard';\nimport { IS_PUBLIC_KEY } from '../decorators/public.decorator';\nimport { PermissionMetadataService } from '../services/permission-metadata.service';\nimport { ClsService } from 'nestjs-cls';\n\n@Injectable()\nexport class AuthenticationGuard implements CanActivate {\n private static readonly defaultAuthTypes = [AuthType.Bearer, AuthType.ApiKey];\n private readonly authTypeGuardMap: Record<\n AuthType,\n CanActivate | CanActivate[]> = {\n [AuthType.Bearer]: this.accessTokenGuard,\n [AuthType.ApiKey]: this.apiKeyGuard,\n [AuthType.None]: { canActivate: () => true },\n [AuthType.MediaSignedUrl]: this.mediaSignedUrlGuard,\n };\n\n constructor(\n private readonly reflector: Reflector,\n private readonly accessTokenGuard: AccessTokenGuard,\n private readonly apiKeyGuard: ApiKeyGuard,\n private readonly mediaSignedUrlGuard: MediaSignedUrlGuard,\n private readonly permissionService: PermissionMetadataService,\n private readonly cls: ClsService,\n ) { }\n\n private isGenericUnauthorizedError(error: unknown): boolean {\n if (!(error instanceof UnauthorizedException)) {\n return false;\n }\n\n const response = error.getResponse();\n const message =\n typeof response === 'string'\n ? response\n : Array.isArray((response as any)?.message)\n ? (response as any).message[0]\n : (response as any)?.message;\n\n return !message || message === 'Unauthorized';\n }\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n // If method marked as public, then we return with true, else go ahead and apply the access token guard. \n const contextLog = context.getHandler();\n const request = context.switchToHttp().getRequest();\n request['isListedInPublicRole'] = false;\n\n // Set IP and User-Agent into CLS context\n const rawIp = request.headers['x-forwarded-for'] || request.socket?.remoteAddress || request.ip;\n const ip = Array.isArray(rawIp) ? rawIp[0] :\n typeof rawIp === 'string' ? rawIp.split(',')[0].trim() : '';\n const userAgent = request.headers['user-agent'] || '';\n\n this.cls.set('ipAddress', ip);\n this.cls.set('userAgent', userAgent);\n\n const isPublic = this.reflector.get(IS_PUBLIC_KEY, context.getHandler());\n if (isPublic) {\n return true;\n }\n\n // TODO: Check if this permission viz. contextPermission is listed in the Public role.\n const contextPermission = `${context.getClass().name}.${context.getHandler().name}`;\n\n const permissionExistsInRole = await this.permissionService.permissionExistsInRole('Public', contextPermission)\n if (permissionExistsInRole.length > 0) {\n request['isListedInPublicRole'] = true;\n return true\n }\n\n const authTypes = this.reflector.getAllAndOverride<AuthType[]>(\n AUTH_TYPE_KEY,\n [context.getHandler(), context.getClass()],\n ) ?? AuthenticationGuard.defaultAuthTypes;\n const guards = authTypes.map((type) => this.authTypeGuardMap[type]).flat();\n let error = new UnauthorizedException();\n\n for (const instance of guards) {\n const canActivate = await Promise.resolve(\n instance.canActivate(context),\n ).catch((err) => {\n if (\n this.isGenericUnauthorizedError(error) ||\n !this.isGenericUnauthorizedError(err)\n ) {\n error = err;\n }\n });\n\n if (canActivate) {\n return true;\n }\n }\n throw error;\n }\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CanActivate, ExecutionContext } from '@nestjs/common';
|
|
2
|
+
import { MediaDownloadUrlService } from '../services/media-download-url.service';
|
|
3
|
+
export declare class MediaSignedUrlGuard implements CanActivate {
|
|
4
|
+
private readonly mediaDownloadUrlService;
|
|
5
|
+
constructor(mediaDownloadUrlService: MediaDownloadUrlService);
|
|
6
|
+
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
7
|
+
private extractTokenFromQuery;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=media-signed-url.guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-signed-url.guard.d.ts","sourceRoot":"","sources":["../../src/guards/media-signed-url.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAqC,MAAM,gBAAgB,CAAC;AAElG,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAElF,qBACa,mBAAoB,YAAW,WAAW;IACzC,OAAO,CAAC,QAAQ,CAAC,uBAAuB;gBAAvB,uBAAuB,EAAE,uBAAuB;IAEvE,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IA4B9D,OAAO,CAAC,qBAAqB;CAI9B"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MediaSignedUrlGuard = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const media_download_url_service_1 = require("../services/media-download-url.service");
|
|
15
|
+
let MediaSignedUrlGuard = class MediaSignedUrlGuard {
|
|
16
|
+
constructor(mediaDownloadUrlService) {
|
|
17
|
+
this.mediaDownloadUrlService = mediaDownloadUrlService;
|
|
18
|
+
}
|
|
19
|
+
async canActivate(context) {
|
|
20
|
+
const request = context.switchToHttp().getRequest();
|
|
21
|
+
const token = this.extractTokenFromQuery(request);
|
|
22
|
+
if (!token) {
|
|
23
|
+
throw new common_1.UnauthorizedException();
|
|
24
|
+
}
|
|
25
|
+
let payload;
|
|
26
|
+
try {
|
|
27
|
+
payload = await this.mediaDownloadUrlService.verifyDownloadToken(token);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
throw new common_1.UnauthorizedException();
|
|
31
|
+
}
|
|
32
|
+
const routeMediaId = Number(request.params?.id);
|
|
33
|
+
if (!Number.isFinite(routeMediaId) || payload.mediaId !== routeMediaId) {
|
|
34
|
+
throw new common_1.UnauthorizedException();
|
|
35
|
+
}
|
|
36
|
+
request['isListedInPublicRole'] = true;
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
extractTokenFromQuery(request) {
|
|
40
|
+
const token = request.query?.token;
|
|
41
|
+
return typeof token === 'string' ? token : undefined;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
exports.MediaSignedUrlGuard = MediaSignedUrlGuard;
|
|
45
|
+
exports.MediaSignedUrlGuard = MediaSignedUrlGuard = __decorate([
|
|
46
|
+
(0, common_1.Injectable)(),
|
|
47
|
+
__metadata("design:paramtypes", [media_download_url_service_1.MediaDownloadUrlService])
|
|
48
|
+
], MediaSignedUrlGuard);
|
|
49
|
+
//# sourceMappingURL=media-signed-url.guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-signed-url.guard.js","sourceRoot":"","sources":["../../src/guards/media-signed-url.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAkG;AAElG,uFAAkF;AAG3E,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAC9B,YAA6B,uBAAgD;QAAhD,4BAAuB,GAAvB,uBAAuB,CAAyB;IAAI,CAAC;IAElF,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAW,CAAC;QAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,8BAAqB,EAAE,CAAC;QACpC,CAAC;QAED,IAAI,OAA4B,CAAC;QACjC,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAC1E,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,8BAAqB,EAAE,CAAC;QACpC,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,OAAO,KAAK,YAAY,EAAE,CAAC;YACvE,MAAM,IAAI,8BAAqB,EAAE,CAAC;QACpC,CAAC;QAMD,OAAO,CAAC,sBAAsB,CAAC,GAAG,IAAI,CAAC;QAEvC,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,qBAAqB,CAAC,OAAgB;QAC5C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;QACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IACvD,CAAC;CACF,CAAA;AAnCY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;qCAE2C,oDAAuB;GADlE,mBAAmB,CAmC/B","sourcesContent":["import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';\nimport { Request } from 'express';\nimport { MediaDownloadUrlService } from 'src/services/media-download-url.service';\n\n@Injectable()\nexport class MediaSignedUrlGuard implements CanActivate {\n constructor(private readonly mediaDownloadUrlService: MediaDownloadUrlService) { }\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest<Request>();\n const token = this.extractTokenFromQuery(request);\n if (!token) {\n throw new UnauthorizedException();\n }\n\n let payload: { mediaId: number };\n try {\n payload = await this.mediaDownloadUrlService.verifyDownloadToken(token);\n } catch {\n throw new UnauthorizedException();\n }\n\n const routeMediaId = Number(request.params?.id);\n if (!Number.isFinite(routeMediaId) || payload.mediaId !== routeMediaId) {\n throw new UnauthorizedException();\n }\n\n // No REQUEST_USER_KEY is ever set for token auth (only Bearer/ApiKey guards set it), so\n // the sibling global APP_GUARD PermissionsGuard would otherwise reject this request for\n // lack of a per-user permission grant. Flag it the same way AuthenticationGuard flags\n // Public-role-exempt requests - token possession IS the full authorization decision here.\n request['isListedInPublicRole'] = true;\n\n return true;\n }\n\n private extractTokenFromQuery(request: Request): string | undefined {\n const token = request.query?.token;\n return typeof token === 'string' ? token : undefined;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaFieldCrudManager.d.ts","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/MediaFieldCrudManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"MediaFieldCrudManager.d.ts","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/MediaFieldCrudManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGnE,oBAAY,cAAc;IACtB,WAAW,gBAAgB;IAC3B,aAAa,kBAAkB;CAClC;AAED,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IACrC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACrC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IAC1C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;CACxC;AA6DD,qBAAa,qBAAsB,YAAW,gBAAgB;IAE9C,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,iBAAiB;IAGvD,OAAO,CAAC,gBAAgB;IA4BxB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,eAAe,EAAE;IAKxE,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,mBAAmB;IAiD3B,OAAO,CAAC,qBAAqB;IAW7B,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG;CAKpC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MediaFieldCrudManager = exports.SolidMediaType = void 0;
|
|
4
|
+
const media_file_types_1 = require("../../constants/media-file-types");
|
|
4
5
|
var SolidMediaType;
|
|
5
6
|
(function (SolidMediaType) {
|
|
6
7
|
SolidMediaType["mediaSingle"] = "mediaSingle";
|
|
@@ -14,7 +15,6 @@ const MIME_TO_MEDIA_TYPE = {
|
|
|
14
15
|
'image/gif': 'image',
|
|
15
16
|
'image/bmp': 'image',
|
|
16
17
|
'image/tiff': 'image',
|
|
17
|
-
'image/svg+xml': 'image',
|
|
18
18
|
'image/heic': 'image',
|
|
19
19
|
'image/heif': 'image',
|
|
20
20
|
'audio/mpeg': 'audio',
|
|
@@ -51,22 +51,20 @@ const MIME_TO_MEDIA_TYPE = {
|
|
|
51
51
|
'application/x-zip-compressed': 'file',
|
|
52
52
|
'application/x-rar-compressed': 'file',
|
|
53
53
|
'application/x-7z-compressed': 'file',
|
|
54
|
-
'application/octet-stream': 'file',
|
|
55
|
-
};
|
|
56
|
-
const EXT_TO_MEDIA_TYPE = {
|
|
57
|
-
png: 'image', jpg: 'image', jpeg: 'image', webp: 'image', gif: 'image', bmp: 'image', tiff: 'image', svg: 'image', heic: 'image', heif: 'image',
|
|
58
|
-
mp3: 'audio', wav: 'audio', ogg: 'audio', aac: 'audio', m4a: 'audio', flac: 'audio',
|
|
59
|
-
mp4: 'video', mov: 'video', avi: 'video', mkv: 'video', mpeg: 'video', mpg: 'video', '3gp': 'video', '3g2': 'video',
|
|
60
|
-
pdf: 'file', txt: 'file', md: 'file', csv: 'file', json: 'file',
|
|
61
|
-
doc: 'file', docx: 'file', xls: 'file', xlsx: 'file', ppt: 'file', pptx: 'file',
|
|
62
|
-
zip: 'file', rar: 'file', '7z': 'file',
|
|
63
54
|
};
|
|
64
55
|
class MediaFieldCrudManager {
|
|
65
56
|
constructor(options) {
|
|
66
57
|
this.options = options;
|
|
67
58
|
}
|
|
68
59
|
resolveMediaType(mimetype, filename) {
|
|
60
|
+
const ext = (filename || '').split('.').pop()?.toLowerCase();
|
|
61
|
+
if (ext && media_file_types_1.DANGEROUS_EXTENSIONS.has(ext)) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
69
64
|
const mt = (mimetype || '').toLowerCase().trim();
|
|
65
|
+
if (mt === 'image/svg+xml' || mt === 'text/html' || mt === 'application/xhtml+xml') {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
70
68
|
if (mt && MIME_TO_MEDIA_TYPE[mt]) {
|
|
71
69
|
return MIME_TO_MEDIA_TYPE[mt];
|
|
72
70
|
}
|
|
@@ -76,9 +74,8 @@ class MediaFieldCrudManager {
|
|
|
76
74
|
return 'audio';
|
|
77
75
|
if (mt.startsWith('video/'))
|
|
78
76
|
return 'video';
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return EXT_TO_MEDIA_TYPE[ext];
|
|
77
|
+
if (ext && media_file_types_1.EXT_TO_MEDIA_TYPE[ext]) {
|
|
78
|
+
return media_file_types_1.EXT_TO_MEDIA_TYPE[ext];
|
|
82
79
|
}
|
|
83
80
|
return null;
|
|
84
81
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaFieldCrudManager.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/MediaFieldCrudManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { FieldCrudManager, ValidationError } from \"src/interfaces\";\n\nexport enum SolidMediaType {\n mediaSingle = 'mediaSingle',\n mediaMultiple = 'mediaMultiple'\n}\n\nexport interface MediaFieldOptions {\n type: SolidMediaType;\n required: boolean | undefined | null;\n fieldName: string | undefined | null;\n mediaMaxSizeKb: number | undefined | null;\n mediaTypes: string[];\n isUpdate: boolean | undefined | null;\n}\n\ntype MediaType = 'image' | 'audio' | 'video' | 'file' | 'pdf';\n\nconst MIME_TO_MEDIA_TYPE: Record<string, MediaType> = {\n // Images\n 'image/png': 'image',\n 'image/jpeg': 'image',\n 'image/jpg': 'image',\n 'image/webp': 'image',\n 'image/gif': 'image',\n 'image/bmp': 'image',\n 'image/tiff': 'image',\n 'image/svg+xml': 'image',\n 'image/heic': 'image',\n 'image/heif': 'image',\n\n // Audio\n 'audio/mpeg': 'audio', // mp3\n 'audio/mp3': 'audio',\n 'audio/wav': 'audio',\n 'audio/x-wav': 'audio',\n 'audio/webm': 'audio',\n 'audio/ogg': 'audio',\n 'audio/aac': 'audio',\n 'audio/mp4': 'audio', // m4a often shows as audio/mp4\n 'audio/x-m4a': 'audio',\n 'audio/flac': 'audio',\n\n // Video\n 'video/mp4': 'video',\n 'video/mpeg': 'video',\n 'video/webm': 'video',\n 'video/ogg': 'video',\n 'video/quicktime': 'video', // mov\n 'video/x-msvideo': 'video', // avi\n 'video/x-matroska': 'video',// mkv\n 'video/3gpp': 'video',\n 'video/3gpp2': 'video',\n\n // Documents / files (treat as \"file\")\n 'application/pdf': 'pdf',\n 'text/plain': 'file',\n 'text/markdown': 'file',\n 'application/json': 'file',\n 'text/csv': 'file',\n\n // Office\n 'application/msword': 'file', // doc\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'file', // docx\n 'application/vnd.ms-excel': 'file', // xls\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'file', // xlsx\n 'application/vnd.ms-powerpoint': 'file', // ppt\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'file', // pptx,\n\n // Archives (optional)\n 'application/zip': 'file',\n 'application/x-zip-compressed': 'file',\n 'application/x-rar-compressed': 'file',\n 'application/x-7z-compressed': 'file',\n\n // Common binary fallback category\n 'application/octet-stream': 'file',\n};\n\nconst EXT_TO_MEDIA_TYPE: Record<string, MediaType> = {\n // Images\n png: 'image', jpg: 'image', jpeg: 'image', webp: 'image', gif: 'image', bmp: 'image', tiff: 'image', svg: 'image', heic: 'image', heif: 'image',\n\n // Audio\n mp3: 'audio', wav: 'audio', ogg: 'audio', aac: 'audio', m4a: 'audio', flac: 'audio',\n\n // Video\n mp4: 'video', mov: 'video', avi: 'video', mkv: 'video', mpeg: 'video', mpg: 'video', '3gp': 'video', '3g2': 'video',\n\n // Files\n pdf: 'file', txt: 'file', md: 'file', csv: 'file', json: 'file',\n doc: 'file', docx: 'file', xls: 'file', xlsx: 'file', ppt: 'file', pptx: 'file',\n zip: 'file', rar: 'file', '7z': 'file',\n};\n\n\nexport class MediaFieldCrudManager implements FieldCrudManager {\n\n constructor(private readonly options: MediaFieldOptions) {\n }\n\n private resolveMediaType(mimetype?: string, filename?: string): MediaType | null {\n const mt = (mimetype || '').toLowerCase().trim();\n if (mt && MIME_TO_MEDIA_TYPE[mt]) {\n return MIME_TO_MEDIA_TYPE[mt];\n }\n\n // Some libs may send \"image/*\" etc. Treat broad families safely.\n if (mt.startsWith('image/')) return 'image';\n if (mt.startsWith('audio/')) return 'audio';\n if (mt.startsWith('video/')) return 'video';\n\n // Fallback to extension if provided\n const ext = (filename || '').split('.').pop()?.toLowerCase();\n if (ext && EXT_TO_MEDIA_TYPE[ext]) {\n return EXT_TO_MEDIA_TYPE[ext];\n }\n\n return null;\n }\n\n validate(dto: any, files: Array<Express.Multer.File>): ValidationError[] {\n const fieldFiles = files.filter(file => file.fieldname === this.options.fieldName);\n return this.applyValidations(fieldFiles);\n }\n\n private applyValidations(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n switch (this.options.type) {\n case SolidMediaType.mediaSingle:\n return this.validateMediaSingle(fieldFiles);\n case SolidMediaType.mediaMultiple:\n return this.validateMediaMultiple(fieldFiles);\n default:\n return [];\n }\n }\n\n private validateMediaSingle(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} is required`\n });\n }\n if (fieldFiles.length > 1) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} must be a single file`\n });\n }\n // validate size\n if (this.options.mediaMaxSizeKb) {\n for (let i = 0; i < fieldFiles.length; i++) {\n const fieldFile = fieldFiles[i];\n const fieldFileSizeInBytes = Math.ceil(fieldFile.size / 1024);\n if (fieldFileSizeInBytes > this.options.mediaMaxSizeKb) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} with size ${fieldFileSizeInBytes} KB exceeds max size limit of ${this.options.mediaMaxSizeKb} KB`\n });\n }\n }\n }\n // validate type\n if (this.options.mediaTypes && this.options.mediaTypes.length > 0) {\n const allowedFileTypes = this.options.mediaTypes as MediaType[];\n\n for (let i = 0; i < fieldFiles.length; i++) {\n const fieldFile = fieldFiles[i];\n\n const resolvedType = this.resolveMediaType(fieldFile.mimetype, fieldFile.originalname ?? fieldFile.filename ?? '');\n if (!resolvedType || !allowedFileTypes.includes(resolvedType)) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `Allowed: ${allowedFileTypes.join(', ')}. ` +\n `Received mimetype: ${fieldFile.mimetype}${resolvedType ? ` (mapped to ${resolvedType})` : ''}`\n });\n }\n }\n }\n\n return errors;\n }\n\n private validateMediaMultiple(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} is required`\n });\n }\n return errors;\n }\n\n transformForCreate(dto: any): any {\n return dto;\n }\n\n // Validation to be applied\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MediaFieldCrudManager.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/MediaFieldCrudManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { FieldCrudManager, ValidationError } from \"src/interfaces\";\nimport { DANGEROUS_EXTENSIONS, EXT_TO_MEDIA_TYPE, MediaCategory } from \"src/constants/media-file-types\";\n\nexport enum SolidMediaType {\n mediaSingle = 'mediaSingle',\n mediaMultiple = 'mediaMultiple'\n}\n\nexport interface MediaFieldOptions {\n type: SolidMediaType;\n required: boolean | undefined | null;\n fieldName: string | undefined | null;\n mediaMaxSizeKb: number | undefined | null;\n mediaTypes: string[];\n isUpdate: boolean | undefined | null;\n}\n\ntype MediaType = MediaCategory;\n\nconst MIME_TO_MEDIA_TYPE: Record<string, MediaType> = {\n // Images\n 'image/png': 'image',\n 'image/jpeg': 'image',\n 'image/jpg': 'image',\n 'image/webp': 'image',\n 'image/gif': 'image',\n 'image/bmp': 'image',\n 'image/tiff': 'image',\n 'image/heic': 'image',\n 'image/heif': 'image',\n\n // Audio\n 'audio/mpeg': 'audio', // mp3\n 'audio/mp3': 'audio',\n 'audio/wav': 'audio',\n 'audio/x-wav': 'audio',\n 'audio/webm': 'audio',\n 'audio/ogg': 'audio',\n 'audio/aac': 'audio',\n 'audio/mp4': 'audio', // m4a often shows as audio/mp4\n 'audio/x-m4a': 'audio',\n 'audio/flac': 'audio',\n\n // Video\n 'video/mp4': 'video',\n 'video/mpeg': 'video',\n 'video/webm': 'video',\n 'video/ogg': 'video',\n 'video/quicktime': 'video', // mov\n 'video/x-msvideo': 'video', // avi\n 'video/x-matroska': 'video',// mkv\n 'video/3gpp': 'video',\n 'video/3gpp2': 'video',\n\n // Documents / files (treat as \"file\")\n 'application/pdf': 'pdf',\n 'text/plain': 'file',\n 'text/markdown': 'file',\n 'application/json': 'file',\n 'text/csv': 'file',\n\n // Office\n 'application/msword': 'file', // doc\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'file', // docx\n 'application/vnd.ms-excel': 'file', // xls\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'file', // xlsx\n 'application/vnd.ms-powerpoint': 'file', // ppt\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'file', // pptx,\n\n // Archives (optional)\n 'application/zip': 'file',\n 'application/x-zip-compressed': 'file',\n 'application/x-rar-compressed': 'file',\n 'application/x-7z-compressed': 'file',\n};\n\nexport class MediaFieldCrudManager implements FieldCrudManager {\n\n constructor(private readonly options: MediaFieldOptions) {\n }\n\n private resolveMediaType(mimetype?: string, filename?: string): MediaType | null {\n const ext = (filename || '').split('.').pop()?.toLowerCase();\n if (ext && DANGEROUS_EXTENSIONS.has(ext)) {\n return null;\n }\n\n const mt = (mimetype || '').toLowerCase().trim();\n if (mt === 'image/svg+xml' || mt === 'text/html' || mt === 'application/xhtml+xml') {\n return null;\n }\n if (mt && MIME_TO_MEDIA_TYPE[mt]) {\n return MIME_TO_MEDIA_TYPE[mt];\n }\n\n // Some libs may send \"image/*\" etc. Treat broad families safely.\n if (mt.startsWith('image/')) return 'image';\n if (mt.startsWith('audio/')) return 'audio';\n if (mt.startsWith('video/')) return 'video';\n\n // Fallback to extension if provided (also covers generic/unrecognized\n // mimetypes such as application/octet-stream).\n if (ext && EXT_TO_MEDIA_TYPE[ext]) {\n return EXT_TO_MEDIA_TYPE[ext];\n }\n\n return null;\n }\n\n validate(dto: any, files: Array<Express.Multer.File>): ValidationError[] {\n const fieldFiles = files.filter(file => file.fieldname === this.options.fieldName);\n return this.applyValidations(fieldFiles);\n }\n\n private applyValidations(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n switch (this.options.type) {\n case SolidMediaType.mediaSingle:\n return this.validateMediaSingle(fieldFiles);\n case SolidMediaType.mediaMultiple:\n return this.validateMediaMultiple(fieldFiles);\n default:\n return [];\n }\n }\n\n private validateMediaSingle(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} is required`\n });\n }\n if (fieldFiles.length > 1) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} must be a single file`\n });\n }\n // validate size\n if (this.options.mediaMaxSizeKb) {\n for (let i = 0; i < fieldFiles.length; i++) {\n const fieldFile = fieldFiles[i];\n const fieldFileSizeInBytes = Math.ceil(fieldFile.size / 1024);\n if (fieldFileSizeInBytes > this.options.mediaMaxSizeKb) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} with size ${fieldFileSizeInBytes} KB exceeds max size limit of ${this.options.mediaMaxSizeKb} KB`\n });\n }\n }\n }\n // validate type\n if (this.options.mediaTypes && this.options.mediaTypes.length > 0) {\n const allowedFileTypes = this.options.mediaTypes as MediaType[];\n\n for (let i = 0; i < fieldFiles.length; i++) {\n const fieldFile = fieldFiles[i];\n\n const resolvedType = this.resolveMediaType(fieldFile.mimetype, fieldFile.originalname ?? fieldFile.filename ?? '');\n if (!resolvedType || !allowedFileTypes.includes(resolvedType)) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `Allowed: ${allowedFileTypes.join(', ')}. ` +\n `Received mimetype: ${fieldFile.mimetype}${resolvedType ? ` (mapped to ${resolvedType})` : ''}`\n });\n }\n }\n }\n\n return errors;\n }\n\n private validateMediaMultiple(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} is required`\n });\n }\n return errors;\n }\n\n transformForCreate(dto: any): any {\n return dto;\n }\n\n // Validation to be applied\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.repository.d.ts","sourceRoot":"","sources":["../../src/repository/media.repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAM,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,sCAAsC,EAAE,MAAM,8CAA8C,CAAC;AACtG,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"media.repository.d.ts","sourceRoot":"","sources":["../../src/repository/media.repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAM,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,sCAAsC,EAAE,MAAM,8CAA8C,CAAC;AACtG,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAG9D,qBACa,eAAgB,SAAQ,mBAAmB,CAAC,KAAK,CAAC;IAEvD,QAAQ,CAAC,UAAU,EAAE,UAAU;IAC/B,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB;IACrD,QAAQ,CAAC,sBAAsB,EAAE,sBAAsB;IAOvD,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,gCAAgC;gBAZxC,UAAU,EAAE,UAAU,EACtB,qBAAqB,EAAE,qBAAqB,EAC5C,sBAAsB,EAAE,sBAAsB,EAOtC,iBAAiB,EAAE,uBAAuB,EAE1C,iBAAiB,EAAE,uBAAuB,EAC1C,gCAAgC,EAAE,sCAAsC;IAKvF,WAAW,CAAC,SAAS,EAAE,GAAG;IAqB1B,0CAA0C,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,KAAK;IAe7H,4CAA4C,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM;CAexH"}
|
|
@@ -22,6 +22,7 @@ const media_storage_provider_metadata_repository_1 = require("./media-storage-pr
|
|
|
22
22
|
const model_metadata_repository_1 = require("./model-metadata.repository");
|
|
23
23
|
const security_rule_repository_1 = require("./security-rule.repository");
|
|
24
24
|
const solid_base_repository_1 = require("./solid-base.repository");
|
|
25
|
+
const media_storage_utils_1 = require("../services/media-storage.utils");
|
|
25
26
|
let MediaRepository = class MediaRepository extends solid_base_repository_1.SolidBaseRepository {
|
|
26
27
|
constructor(dataSource, requestContextService, securityRuleRepository, fieldMetadataRepo, modelMetadataRepo, mediaStorageProviderMetadataRepo) {
|
|
27
28
|
super(media_entity_1.Media, dataSource, requestContextService, securityRuleRepository);
|
|
@@ -48,6 +49,7 @@ let MediaRepository = class MediaRepository extends solid_base_repository_1.Soli
|
|
|
48
49
|
id: createDto['mediaStorageProviderMetadataId']
|
|
49
50
|
},
|
|
50
51
|
});
|
|
52
|
+
createDto['isPublic'] = (0, media_storage_utils_1.resolveStoredMediaIsPublic)(createDto['isPublic'], createDto['mediaStorageProviderMetadata']);
|
|
51
53
|
const media = this.create(createDto);
|
|
52
54
|
return this.save(media);
|
|
53
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.repository.js","sourceRoot":"","sources":["../../src/repository/media.repository.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAgE;AAChE,2DAAkD;AAClD,iFAA6E;AAC7E,qCAAyC;AACzC,2EAAsE;AACtE,6GAAsG;AACtG,2EAAsE;AACtE,yEAAoE;AACpE,mEAA8D;
|
|
1
|
+
{"version":3,"file":"media.repository.js","sourceRoot":"","sources":["../../src/repository/media.repository.ts"],"names":[],"mappings":"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","sourcesContent":["import { forwardRef, Inject, Injectable } from '@nestjs/common';\nimport { Media } from 'src/entities/media.entity';\nimport { RequestContextService } from 'src/services/request-context.service';\nimport { DataSource, In } from 'typeorm';\nimport { FieldMetadataRepository } from './field-metadata.repository';\nimport { MediaStorageProviderMetadataRepository } from './media-storage-provider-metadata.repository';\nimport { ModelMetadataRepository } from './model-metadata.repository';\nimport { SecurityRuleRepository } from './security-rule.repository';\nimport { SolidBaseRepository } from './solid-base.repository';\nimport { resolveStoredMediaIsPublic } from 'src/services/media-storage.utils';\n\n@Injectable()\nexport class MediaRepository extends SolidBaseRepository<Media> {\n constructor(\n readonly dataSource: DataSource,\n readonly requestContextService: RequestContextService,\n readonly securityRuleRepository: SecurityRuleRepository,\n // @InjectRepository(FieldMetadata)\n // private readonly fieldMetadataRepo: Repository<FieldMetadata>,\n // @InjectRepository(ModelMetadata)\n // private readonly modelMetadataRepo: Repository<ModelMetadata>,\n // @InjectRepository(MediaStorageProviderMetadata)\n // private readonly mediaStorageProviderMetadataRepo: Repository<MediaStorageProviderMetadata>,\n private readonly fieldMetadataRepo: FieldMetadataRepository,\n @Inject(forwardRef(() => ModelMetadataRepository))\n private readonly modelMetadataRepo: ModelMetadataRepository,\n private readonly mediaStorageProviderMetadataRepo: MediaStorageProviderMetadataRepository,\n ) {\n super(Media, dataSource, requestContextService, securityRuleRepository);\n }\n\n async createMedia(createDto: any) {\n createDto['fieldMetadata'] = await this.fieldMetadataRepo.findOne({\n where: {\n id: createDto['fieldMetadataId']\n },\n });\n createDto['modelMetadata'] = await this.modelMetadataRepo.findOne({\n where: {\n id: createDto['modelMetadataId']\n },\n });\n createDto['mediaStorageProviderMetadata'] = await this.mediaStorageProviderMetadataRepo.findOne({\n where: {\n id: createDto['mediaStorageProviderMetadataId']\n },\n });\n createDto['isPublic'] = resolveStoredMediaIsPublic(createDto['isPublic'], createDto['mediaStorageProviderMetadata']);\n const media = this.create(createDto);\n return this.save(media);\n }\n\n async findByEntityIdAndFieldIdAndModelMetadataId(entityId: number, fieldMetadataId: number, modelMetadataId: number, relations = {}) {\n return await this.find({\n where: {\n modelMetadata: {\n id: modelMetadataId\n },\n fieldMetadata: {\n id: fieldMetadataId\n },\n entityId: entityId,\n },\n relations: relations,\n });\n }\n\n async deleteByEntityIdAndFieldIdAndModelMetadataId(entityId: number, fieldMetadataId: number, modelMetadataId: number) {\n const entities = await this.find({\n where: {\n modelMetadata: {\n id: modelMetadataId\n },\n fieldMetadata: {\n id: fieldMetadataId\n },\n entityId: entityId,\n }\n });\n return this.remove(entities);\n }\n\n}\n"]}
|
|
@@ -1704,6 +1704,18 @@
|
|
|
1704
1704
|
"columnName": "original_file_name",
|
|
1705
1705
|
"isSystem": true
|
|
1706
1706
|
},
|
|
1707
|
+
{
|
|
1708
|
+
"name": "isPublic",
|
|
1709
|
+
"displayName": "Is Public",
|
|
1710
|
+
"type": "boolean",
|
|
1711
|
+
"required": false,
|
|
1712
|
+
"unique": false,
|
|
1713
|
+
"index": false,
|
|
1714
|
+
"private": false,
|
|
1715
|
+
"encrypt": false,
|
|
1716
|
+
"columnName": "is_public",
|
|
1717
|
+
"isSystem": true
|
|
1718
|
+
},
|
|
1707
1719
|
{
|
|
1708
1720
|
"name": "modelMetadata",
|
|
1709
1721
|
"displayName": "Model Metadata",
|
|
@@ -5306,6 +5318,9 @@
|
|
|
5306
5318
|
"FieldMetadataController.getSelectionDynamicValues",
|
|
5307
5319
|
"FieldMetadataController.getSelectionDynamicValue",
|
|
5308
5320
|
"FieldMetadataController.findFieldDefaultMetaData",
|
|
5321
|
+
"MediaController.findMany",
|
|
5322
|
+
"MediaController.findOne",
|
|
5323
|
+
"MediaController.download",
|
|
5309
5324
|
"SavedFiltersController.delete",
|
|
5310
5325
|
"SavedFiltersController.deleteMany",
|
|
5311
5326
|
"SavedFiltersController.findOne",
|
|
@@ -8607,9 +8622,9 @@
|
|
|
8607
8622
|
"attrs": {
|
|
8608
8623
|
"name": "roles",
|
|
8609
8624
|
"widget": "checkbox",
|
|
8610
|
-
"inlineCreateAutoSave": "
|
|
8625
|
+
"inlineCreateAutoSave": "false",
|
|
8611
8626
|
"renderModeCheckboxPreprocessor": "MenuItemMetadataRolesFormFieldPreprocessor",
|
|
8612
|
-
"inlineCreate": "
|
|
8627
|
+
"inlineCreate": "false",
|
|
8613
8628
|
"inlineCreateLayout": {
|
|
8614
8629
|
"type": "form",
|
|
8615
8630
|
"attrs": {
|
|
@@ -8758,6 +8773,13 @@
|
|
|
8758
8773
|
"sortable": false
|
|
8759
8774
|
}
|
|
8760
8775
|
},
|
|
8776
|
+
{
|
|
8777
|
+
"type": "field",
|
|
8778
|
+
"attrs": {
|
|
8779
|
+
"name": "isPublic",
|
|
8780
|
+
"sortable": true
|
|
8781
|
+
}
|
|
8782
|
+
},
|
|
8761
8783
|
{
|
|
8762
8784
|
"type": "field",
|
|
8763
8785
|
"attrs": {
|
|
@@ -8853,6 +8875,14 @@
|
|
|
8853
8875
|
"isSearchable": true
|
|
8854
8876
|
}
|
|
8855
8877
|
},
|
|
8878
|
+
{
|
|
8879
|
+
"type": "field",
|
|
8880
|
+
"attrs": {
|
|
8881
|
+
"name": "isPublic",
|
|
8882
|
+
"label": "isPublic",
|
|
8883
|
+
"isSearchable": true
|
|
8884
|
+
}
|
|
8885
|
+
},
|
|
8856
8886
|
{
|
|
8857
8887
|
"type": "field",
|
|
8858
8888
|
"attrs": {
|
|
@@ -8921,6 +8951,12 @@
|
|
|
8921
8951
|
"name": "mediaStorageProviderMetadata"
|
|
8922
8952
|
}
|
|
8923
8953
|
},
|
|
8954
|
+
{
|
|
8955
|
+
"type": "field",
|
|
8956
|
+
"attrs": {
|
|
8957
|
+
"name": "isPublic"
|
|
8958
|
+
}
|
|
8959
|
+
},
|
|
8924
8960
|
{
|
|
8925
8961
|
"type": "field",
|
|
8926
8962
|
"attrs": {
|
|
@@ -14525,7 +14561,15 @@
|
|
|
14525
14561
|
"mediaStorageProviders": [
|
|
14526
14562
|
{
|
|
14527
14563
|
"name": "default-filesystem",
|
|
14528
|
-
"type": "filesystem"
|
|
14564
|
+
"type": "filesystem",
|
|
14565
|
+
"isPublic": true,
|
|
14566
|
+
"localPath": "media-files-storage"
|
|
14567
|
+
},
|
|
14568
|
+
{
|
|
14569
|
+
"name": "private-filesystem",
|
|
14570
|
+
"type": "filesystem",
|
|
14571
|
+
"isPublic": false,
|
|
14572
|
+
"localPath": "media-private-files-storage"
|
|
14529
14573
|
},
|
|
14530
14574
|
{
|
|
14531
14575
|
"name": "default-aws-s3",
|
|
@@ -14561,6 +14605,47 @@
|
|
|
14561
14605
|
}
|
|
14562
14606
|
}
|
|
14563
14607
|
}
|
|
14608
|
+
},
|
|
14609
|
+
{
|
|
14610
|
+
"name": "model:Media-role:Internal User-own",
|
|
14611
|
+
"description": "Show Media records owned by the current user",
|
|
14612
|
+
"roleUserKey": "Internal User",
|
|
14613
|
+
"modelMetadataUserKey": "media",
|
|
14614
|
+
"securityRuleConfig": {
|
|
14615
|
+
"filters": {
|
|
14616
|
+
"createdBy": {
|
|
14617
|
+
"$eq": "$activeUserId"
|
|
14618
|
+
}
|
|
14619
|
+
}
|
|
14620
|
+
}
|
|
14621
|
+
},
|
|
14622
|
+
{
|
|
14623
|
+
"name": "model:Media-role:Internal User-public",
|
|
14624
|
+
"description": "Show public Media records",
|
|
14625
|
+
"roleUserKey": "Internal User",
|
|
14626
|
+
"modelMetadataUserKey": "media",
|
|
14627
|
+
"securityRuleConfig": {
|
|
14628
|
+
"filters": {
|
|
14629
|
+
"mediaStorageProviderMetadata": {
|
|
14630
|
+
"isPublic": {
|
|
14631
|
+
"$eq": true
|
|
14632
|
+
}
|
|
14633
|
+
}
|
|
14634
|
+
}
|
|
14635
|
+
}
|
|
14636
|
+
},
|
|
14637
|
+
{
|
|
14638
|
+
"name": "model:Media-role:Admin",
|
|
14639
|
+
"description": "Show All Media records",
|
|
14640
|
+
"roleUserKey": "Admin",
|
|
14641
|
+
"modelMetadataUserKey": "media",
|
|
14642
|
+
"securityRuleConfig": {
|
|
14643
|
+
"filters": {
|
|
14644
|
+
"id": {
|
|
14645
|
+
"$ne": "0"
|
|
14646
|
+
}
|
|
14647
|
+
}
|
|
14648
|
+
}
|
|
14564
14649
|
}
|
|
14565
14650
|
],
|
|
14566
14651
|
"modelSequences": [],
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ConfigService } from '@nestjs/config';
|
|
2
|
+
import { JwtService } from '@nestjs/jwt';
|
|
3
|
+
import { MediaStorageProviderMetadata } from '../entities/media-storage-provider-metadata.entity';
|
|
4
|
+
import { S3FileService } from '../services/file';
|
|
5
|
+
import { SettingService } from '../services/setting.service';
|
|
6
|
+
export declare const MEDIA_DOWNLOAD_TOKEN_AUDIENCE = "media-download";
|
|
7
|
+
export interface MediaDownloadTokenPayload {
|
|
8
|
+
mediaId: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class MediaDownloadUrlService {
|
|
11
|
+
private readonly jwtService;
|
|
12
|
+
private readonly s3FileService;
|
|
13
|
+
private readonly settingService;
|
|
14
|
+
private readonly configService;
|
|
15
|
+
private readonly logger;
|
|
16
|
+
constructor(jwtService: JwtService, s3FileService: S3FileService, settingService: SettingService, configService: ConfigService);
|
|
17
|
+
resolveDownloadUrl(mediaId: number, relativeUri: string, storageProvider?: MediaStorageProviderMetadata): Promise<string>;
|
|
18
|
+
verifyDownloadToken(token: string): Promise<MediaDownloadTokenPayload>;
|
|
19
|
+
private mintDownloadToken;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=media-download-url.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-download-url.service.d.ts","sourceRoot":"","sources":["../../src/services/media-download-url.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,4BAA4B,EAAE,MAAM,qDAAqD,CAAC;AACnG,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAG9D,eAAO,MAAM,6BAA6B,mBAAmB,CAAC;AAG9D,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBACa,uBAAuB;IAIhC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa;IANhC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4C;gBAGhD,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,aAAa,EAC5B,cAAc,EAAE,cAAc,EAC9B,aAAa,EAAE,aAAa;IAGzC,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,4BAA4B,GAAG,OAAO,CAAC,MAAM,CAAC;IAuBzH,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAO5E,OAAO,CAAC,iBAAiB;CAQ1B"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var MediaDownloadUrlService_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.MediaDownloadUrlService = exports.MEDIA_DOWNLOAD_TOKEN_AUDIENCE = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const config_1 = require("@nestjs/config");
|
|
16
|
+
const jwt_1 = require("@nestjs/jwt");
|
|
17
|
+
const create_media_storage_provider_metadata_dto_1 = require("../dtos/create-media-storage-provider-metadata.dto");
|
|
18
|
+
const file_1 = require("./file");
|
|
19
|
+
const media_storage_utils_1 = require("./media-storage.utils");
|
|
20
|
+
const setting_service_1 = require("./setting.service");
|
|
21
|
+
exports.MEDIA_DOWNLOAD_TOKEN_AUDIENCE = 'media-download';
|
|
22
|
+
const DEFAULT_SIGNED_URL_EXPIRY_MINUTES = 60;
|
|
23
|
+
let MediaDownloadUrlService = MediaDownloadUrlService_1 = class MediaDownloadUrlService {
|
|
24
|
+
constructor(jwtService, s3FileService, settingService, configService) {
|
|
25
|
+
this.jwtService = jwtService;
|
|
26
|
+
this.s3FileService = s3FileService;
|
|
27
|
+
this.settingService = settingService;
|
|
28
|
+
this.configService = configService;
|
|
29
|
+
this.logger = new common_1.Logger(MediaDownloadUrlService_1.name);
|
|
30
|
+
}
|
|
31
|
+
async resolveDownloadUrl(mediaId, relativeUri, storageProvider) {
|
|
32
|
+
const expiryMinutes = storageProvider?.signedUrlExpiry ?? DEFAULT_SIGNED_URL_EXPIRY_MINUTES;
|
|
33
|
+
if (storageProvider?.type === create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.AwsS3) {
|
|
34
|
+
if (storageProvider?.bucketName) {
|
|
35
|
+
return this.s3FileService.getUrl(`${storageProvider.bucketName}:${relativeUri}`, { region: (0, media_storage_utils_1.getEffectiveS3Region)(this.configService, storageProvider.region), expiresIn: expiryMinutes * 60 });
|
|
36
|
+
}
|
|
37
|
+
this.logger.warn(`Media id ${mediaId}: AwsS3 provider missing bucketName; falling back to app-hosted token URL`);
|
|
38
|
+
}
|
|
39
|
+
const token = await this.mintDownloadToken(mediaId, expiryMinutes);
|
|
40
|
+
const downloadPath = `/api/media/${mediaId}/download?token=${token}`;
|
|
41
|
+
const baseUrl = this.settingService.getConfigValue('baseUrl');
|
|
42
|
+
return `${String(baseUrl).replace(/\/+$/, '')}${downloadPath}`;
|
|
43
|
+
}
|
|
44
|
+
async verifyDownloadToken(token) {
|
|
45
|
+
return this.jwtService.verifyAsync(token, {
|
|
46
|
+
secret: this.settingService.getConfigValue('secret'),
|
|
47
|
+
audience: exports.MEDIA_DOWNLOAD_TOKEN_AUDIENCE,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
mintDownloadToken(mediaId, expiryMinutes) {
|
|
51
|
+
const payload = { mediaId };
|
|
52
|
+
return this.jwtService.signAsync(payload, {
|
|
53
|
+
secret: this.settingService.getConfigValue('secret'),
|
|
54
|
+
audience: exports.MEDIA_DOWNLOAD_TOKEN_AUDIENCE,
|
|
55
|
+
expiresIn: expiryMinutes * 60,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
exports.MediaDownloadUrlService = MediaDownloadUrlService;
|
|
60
|
+
exports.MediaDownloadUrlService = MediaDownloadUrlService = MediaDownloadUrlService_1 = __decorate([
|
|
61
|
+
(0, common_1.Injectable)(),
|
|
62
|
+
__metadata("design:paramtypes", [jwt_1.JwtService,
|
|
63
|
+
file_1.S3FileService,
|
|
64
|
+
setting_service_1.SettingService,
|
|
65
|
+
config_1.ConfigService])
|
|
66
|
+
], MediaDownloadUrlService);
|
|
67
|
+
//# sourceMappingURL=media-download-url.service.js.map
|