@solidxai/core 0.1.13 → 0.1.14-beta.0
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/CHANGELOG.md +1779 -0
- package/dist/constants/media-file-types.d.ts +14 -0
- package/dist/constants/media-file-types.d.ts.map +1 -1
- package/dist/constants/media-file-types.js +83 -15
- package/dist/constants/media-file-types.js.map +1 -1
- package/dist/controllers/field-metadata.controller.d.ts +4 -0
- package/dist/controllers/field-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/view-metadata.controller.d.ts +4 -0
- package/dist/controllers/view-metadata.controller.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/LongTextFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/LongTextFieldCrudManager.js +3 -2
- package/dist/helpers/field-crud-managers/LongTextFieldCrudManager.js.map +1 -1
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts +2 -0
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js +10 -52
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js.map +1 -1
- package/dist/helpers/field-crud-managers/ShortTextFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/ShortTextFieldCrudManager.js +3 -2
- package/dist/helpers/field-crud-managers/ShortTextFieldCrudManager.js.map +1 -1
- package/dist/helpers/field-crud-managers/textFieldCrudManagerUtils.d.ts +3 -0
- package/dist/helpers/field-crud-managers/textFieldCrudManagerUtils.d.ts.map +1 -0
- package/dist/helpers/field-crud-managers/textFieldCrudManagerUtils.js +17 -0
- package/dist/helpers/field-crud-managers/textFieldCrudManagerUtils.js.map +1 -0
- package/dist/services/crud.service.d.ts.map +1 -1
- package/dist/services/crud.service.js +2 -1
- package/dist/services/crud.service.js.map +1 -1
- package/dist/services/field-metadata.service.d.ts +4 -0
- package/dist/services/field-metadata.service.d.ts.map +1 -1
- package/dist/services/field-metadata.service.js +1 -0
- package/dist/services/field-metadata.service.js.map +1 -1
- package/dist/services/view-metadata.service.d.ts +4 -0
- package/dist/services/view-metadata.service.d.ts.map +1 -1
- package/dist/services/view-metadata.service.js +2 -0
- package/dist/services/view-metadata.service.js.map +1 -1
- package/package.json +1 -1
- package/src/constants/media-file-types.ts +95 -10
- package/src/helpers/field-crud-managers/LongTextFieldCrudManager.ts +3 -2
- package/src/helpers/field-crud-managers/MediaFieldCrudManager.ts +12 -64
- package/src/helpers/field-crud-managers/ShortTextFieldCrudManager.ts +3 -2
- package/src/helpers/field-crud-managers/textFieldCrudManagerUtils.ts +14 -0
- package/src/services/crud.service.ts +2 -1
- package/src/services/field-metadata.service.ts +2 -1
- package/src/services/view-metadata.service.ts +4 -0
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
export type MediaCategory = 'image' | 'audio' | 'video' | 'file' | 'pdf';
|
|
2
2
|
export declare const MEDIA_CATEGORIES: readonly ["image", "audio", "video", "file", "pdf"];
|
|
3
|
+
export type MediaFileTypeDefinition = {
|
|
4
|
+
mediaType: MediaCategory;
|
|
5
|
+
mimeType: string;
|
|
6
|
+
extension: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const MEDIA_FILE_TYPES: MediaFileTypeDefinition[];
|
|
9
|
+
export declare const MEDIA_TYPE_TO_EXTENSIONS: Record<MediaCategory, string[]>;
|
|
10
|
+
export declare const IMAGE_EXTENSIONS: string[];
|
|
11
|
+
export declare const AUDIO_EXTENSIONS: string[];
|
|
12
|
+
export declare const VIDEO_EXTENSIONS: string[];
|
|
13
|
+
export declare const DOCUMENT_EXTENSIONS: string[];
|
|
14
|
+
export declare const PDF_EXTENSION = "pdf";
|
|
15
|
+
export declare const EXTENSION_TO_MIME_TYPE: Record<string, string>;
|
|
16
|
+
export declare const MIME_TO_MEDIA_TYPE: Record<string, MediaCategory>;
|
|
3
17
|
export declare const DANGEROUS_EXTENSIONS: Set<string>;
|
|
4
18
|
export declare const DANGEROUS_MIME_TYPES: Set<string>;
|
|
5
19
|
export declare function normalizeUploadedFileName(fileName?: string | null): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-file-types.d.ts","sourceRoot":"","sources":["../../src/constants/media-file-types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAEzE,eAAO,MAAM,gBAAgB,qDAAsD,CAAC;
|
|
1
|
+
{"version":3,"file":"media-file-types.d.ts","sourceRoot":"","sources":["../../src/constants/media-file-types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAEzE,eAAO,MAAM,gBAAgB,qDAAsD,CAAC;AAEpF,MAAM,MAAM,uBAAuB,GAAG;IAClC,SAAS,EAAE,aAAa,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACrB,CAAC;AAIF,eAAO,MAAM,gBAAgB,EAAE,uBAAuB,EAkDrD,CAAC;AAUF,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,EAAE,CAKzC,CAAC;AAE7B,eAAO,MAAM,gBAAgB,UAAiC,CAAC;AAC/D,eAAO,MAAM,gBAAgB,UAAiC,CAAC;AAC/D,eAAO,MAAM,gBAAgB,UAAiC,CAAC;AAC/D,eAAO,MAAM,mBAAmB,UAAgC,CAAC;AACjE,eAAO,MAAM,aAAa,QAAQ,CAAC;AAEnC,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK1B,CAAC;AAEjC,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAKtB,CAAC;AAOxC,eAAO,MAAM,oBAAoB,aAK/B,CAAC;AAQH,eAAO,MAAM,oBAAoB,aAE/B,CAAC;AAuCH,wBAAgB,yBAAyB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAmB1E;AAOD,wBAAgB,yBAAyB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAStF;AAWD,wBAAgB,iCAAiC,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,EAAE,CAGpF;AAGD,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAGD,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,MAAM,CAE1E;AAQD,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAO5E;AASD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAE3D,CAAC;AAMF,eAAO,MAAM,sBAAsB,aAKjC,CAAC"}
|
|
@@ -1,17 +1,89 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.INLINE_SAFE_EXTENSIONS = exports.EXT_TO_MEDIA_TYPE = exports.DANGEROUS_MIME_TYPES = exports.DANGEROUS_EXTENSIONS = exports.MEDIA_CATEGORIES = void 0;
|
|
3
|
+
exports.INLINE_SAFE_EXTENSIONS = exports.EXT_TO_MEDIA_TYPE = exports.DANGEROUS_MIME_TYPES = exports.DANGEROUS_EXTENSIONS = exports.MIME_TO_MEDIA_TYPE = exports.EXTENSION_TO_MIME_TYPE = exports.PDF_EXTENSION = exports.DOCUMENT_EXTENSIONS = exports.VIDEO_EXTENSIONS = exports.AUDIO_EXTENSIONS = exports.IMAGE_EXTENSIONS = exports.MEDIA_TYPE_TO_EXTENSIONS = exports.MEDIA_FILE_TYPES = exports.MEDIA_CATEGORIES = void 0;
|
|
4
4
|
exports.normalizeUploadedFileName = normalizeUploadedFileName;
|
|
5
5
|
exports.getLowercaseFileExtension = getLowercaseFileExtension;
|
|
6
6
|
exports.getLowercaseFileExtensionSegments = getLowercaseFileExtensionSegments;
|
|
7
7
|
exports.getUploadedFileName = getUploadedFileName;
|
|
8
8
|
exports.isDangerousMediaFile = isDangerousMediaFile;
|
|
9
9
|
exports.MEDIA_CATEGORIES = ['image', 'audio', 'video', 'file', 'pdf'];
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
exports.MEDIA_FILE_TYPES = [
|
|
11
|
+
{ mediaType: 'image', mimeType: 'image/png', extension: 'png' },
|
|
12
|
+
{ mediaType: 'image', mimeType: 'image/jpeg', extension: 'jpg' },
|
|
13
|
+
{ mediaType: 'image', mimeType: 'image/jpg', extension: 'jpg' },
|
|
14
|
+
{ mediaType: 'image', mimeType: 'image/jpeg', extension: 'jpeg' },
|
|
15
|
+
{ mediaType: 'image', mimeType: 'image/webp', extension: 'webp' },
|
|
16
|
+
{ mediaType: 'image', mimeType: 'image/gif', extension: 'gif' },
|
|
17
|
+
{ mediaType: 'image', mimeType: 'image/bmp', extension: 'bmp' },
|
|
18
|
+
{ mediaType: 'image', mimeType: 'image/tiff', extension: 'tiff' },
|
|
19
|
+
{ mediaType: 'image', mimeType: 'image/heic', extension: 'heic' },
|
|
20
|
+
{ mediaType: 'image', mimeType: 'image/heif', extension: 'heif' },
|
|
21
|
+
{ mediaType: 'audio', mimeType: 'audio/mpeg', extension: 'mp3' },
|
|
22
|
+
{ mediaType: 'audio', mimeType: 'audio/mp3', extension: 'mp3' },
|
|
23
|
+
{ mediaType: 'audio', mimeType: 'audio/wav', extension: 'wav' },
|
|
24
|
+
{ mediaType: 'audio', mimeType: 'audio/x-wav', extension: 'wav' },
|
|
25
|
+
{ mediaType: 'audio', mimeType: 'audio/ogg', extension: 'ogg' },
|
|
26
|
+
{ mediaType: 'audio', mimeType: 'audio/aac', extension: 'aac' },
|
|
27
|
+
{ mediaType: 'audio', mimeType: 'audio/mp4', extension: 'm4a' },
|
|
28
|
+
{ mediaType: 'audio', mimeType: 'audio/x-m4a', extension: 'm4a' },
|
|
29
|
+
{ mediaType: 'audio', mimeType: 'audio/flac', extension: 'flac' },
|
|
30
|
+
{ mediaType: 'audio', mimeType: 'audio/webm', extension: 'webm' },
|
|
31
|
+
{ mediaType: 'video', mimeType: 'video/mp4', extension: 'mp4' },
|
|
32
|
+
{ mediaType: 'video', mimeType: 'video/quicktime', extension: 'mov' },
|
|
33
|
+
{ mediaType: 'video', mimeType: 'video/x-msvideo', extension: 'avi' },
|
|
34
|
+
{ mediaType: 'video', mimeType: 'video/x-matroska', extension: 'mkv' },
|
|
35
|
+
{ mediaType: 'video', mimeType: 'video/mpeg', extension: 'mpeg' },
|
|
36
|
+
{ mediaType: 'video', mimeType: 'video/mpeg', extension: 'mpg' },
|
|
37
|
+
{ mediaType: 'video', mimeType: 'video/3gpp', extension: '3gp' },
|
|
38
|
+
{ mediaType: 'video', mimeType: 'video/3gpp2', extension: '3g2' },
|
|
39
|
+
{ mediaType: 'video', mimeType: 'video/webm', extension: 'webm' },
|
|
40
|
+
{ mediaType: 'video', mimeType: 'video/ogg', extension: 'ogg' },
|
|
41
|
+
{ mediaType: 'file', mimeType: 'text/plain', extension: 'txt' },
|
|
42
|
+
{ mediaType: 'file', mimeType: 'text/markdown', extension: 'md' },
|
|
43
|
+
{ mediaType: 'file', mimeType: 'text/csv', extension: 'csv' },
|
|
44
|
+
{ mediaType: 'file', mimeType: 'application/json', extension: 'json' },
|
|
45
|
+
{ mediaType: 'file', mimeType: 'application/msword', extension: 'doc' },
|
|
46
|
+
{ mediaType: 'file', mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', extension: 'docx' },
|
|
47
|
+
{ mediaType: 'file', mimeType: 'application/vnd.ms-excel', extension: 'xls' },
|
|
48
|
+
{ mediaType: 'file', mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', extension: 'xlsx' },
|
|
49
|
+
{ mediaType: 'file', mimeType: 'application/vnd.ms-powerpoint', extension: 'ppt' },
|
|
50
|
+
{ mediaType: 'file', mimeType: 'application/vnd.openxmlformats-officedocument.presentationml.presentation', extension: 'pptx' },
|
|
51
|
+
{ mediaType: 'file', mimeType: 'application/zip', extension: 'zip' },
|
|
52
|
+
{ mediaType: 'file', mimeType: 'application/x-zip-compressed', extension: 'zip' },
|
|
53
|
+
{ mediaType: 'file', mimeType: 'application/x-rar-compressed', extension: 'rar' },
|
|
54
|
+
{ mediaType: 'file', mimeType: 'application/x-7z-compressed', extension: '7z' },
|
|
55
|
+
{ mediaType: 'pdf', mimeType: 'application/pdf', extension: 'pdf' },
|
|
56
|
+
];
|
|
57
|
+
const createMediaTypeBuckets = () => ({
|
|
58
|
+
image: [],
|
|
59
|
+
audio: [],
|
|
60
|
+
video: [],
|
|
61
|
+
file: [],
|
|
62
|
+
pdf: [],
|
|
63
|
+
});
|
|
64
|
+
exports.MEDIA_TYPE_TO_EXTENSIONS = exports.MEDIA_FILE_TYPES.reduce((acc, fileType) => {
|
|
65
|
+
if (!acc[fileType.mediaType].includes(fileType.extension)) {
|
|
66
|
+
acc[fileType.mediaType].push(fileType.extension);
|
|
67
|
+
}
|
|
68
|
+
return acc;
|
|
69
|
+
}, createMediaTypeBuckets());
|
|
70
|
+
exports.IMAGE_EXTENSIONS = exports.MEDIA_TYPE_TO_EXTENSIONS.image;
|
|
71
|
+
exports.AUDIO_EXTENSIONS = exports.MEDIA_TYPE_TO_EXTENSIONS.audio;
|
|
72
|
+
exports.VIDEO_EXTENSIONS = exports.MEDIA_TYPE_TO_EXTENSIONS.video;
|
|
73
|
+
exports.DOCUMENT_EXTENSIONS = exports.MEDIA_TYPE_TO_EXTENSIONS.file;
|
|
74
|
+
exports.PDF_EXTENSION = 'pdf';
|
|
75
|
+
exports.EXTENSION_TO_MIME_TYPE = exports.MEDIA_FILE_TYPES.reduce((acc, fileType) => {
|
|
76
|
+
if (!(fileType.extension in acc)) {
|
|
77
|
+
acc[fileType.extension] = fileType.mimeType;
|
|
78
|
+
}
|
|
79
|
+
return acc;
|
|
80
|
+
}, {});
|
|
81
|
+
exports.MIME_TO_MEDIA_TYPE = exports.MEDIA_FILE_TYPES.reduce((acc, fileType) => {
|
|
82
|
+
if (!(fileType.mimeType in acc)) {
|
|
83
|
+
acc[fileType.mimeType] = fileType.mediaType;
|
|
84
|
+
}
|
|
85
|
+
return acc;
|
|
86
|
+
}, {});
|
|
15
87
|
exports.DANGEROUS_EXTENSIONS = new Set([
|
|
16
88
|
'html', 'htm', 'xhtml', 'svg', 'xml',
|
|
17
89
|
'js', 'mjs', 'php', 'phtml', 'jsp', 'asp', 'aspx',
|
|
@@ -77,16 +149,12 @@ function isDangerousMediaFile(file) {
|
|
|
77
149
|
return exports.DANGEROUS_MIME_TYPES.has((file?.mimetype || '').toLowerCase().trim());
|
|
78
150
|
}
|
|
79
151
|
exports.EXT_TO_MEDIA_TYPE = {
|
|
80
|
-
...Object.fromEntries(
|
|
81
|
-
...Object.fromEntries(AUDIO_EXTENSIONS.map((ext) => [ext, 'audio'])),
|
|
82
|
-
...Object.fromEntries(VIDEO_EXTENSIONS.map((ext) => [ext, 'video'])),
|
|
83
|
-
...Object.fromEntries(DOCUMENT_EXTENSIONS.map((ext) => [ext, 'file'])),
|
|
84
|
-
[PDF_EXTENSION]: 'pdf',
|
|
152
|
+
...Object.fromEntries(exports.MEDIA_FILE_TYPES.map((fileType) => [fileType.extension, fileType.mediaType])),
|
|
85
153
|
};
|
|
86
154
|
exports.INLINE_SAFE_EXTENSIONS = new Set([
|
|
87
|
-
...IMAGE_EXTENSIONS,
|
|
88
|
-
...AUDIO_EXTENSIONS,
|
|
89
|
-
...VIDEO_EXTENSIONS,
|
|
90
|
-
PDF_EXTENSION,
|
|
155
|
+
...exports.IMAGE_EXTENSIONS,
|
|
156
|
+
...exports.AUDIO_EXTENSIONS,
|
|
157
|
+
...exports.VIDEO_EXTENSIONS,
|
|
158
|
+
exports.PDF_EXTENSION,
|
|
91
159
|
]);
|
|
92
160
|
//# sourceMappingURL=media-file-types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-file-types.js","sourceRoot":"","sources":["../../src/constants/media-file-types.ts"],"names":[],"mappings":"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","sourcesContent":["export type MediaCategory = 'image' | 'audio' | 'video' | 'file' | 'pdf';\n\nexport const MEDIA_CATEGORIES = ['image', 'audio', 'video', 'file', 'pdf'] as const;\n\nconst IMAGE_EXTENSIONS = ['png', 'jpg', 'jpeg', 'webp', 'gif', 'bmp', 'tiff', 'heic', 'heif'];\nconst AUDIO_EXTENSIONS = ['mp3', 'wav', 'ogg', 'aac', 'm4a', 'flac', 'webm'];\nconst VIDEO_EXTENSIONS = ['mp4', 'mov', 'avi', 'mkv', 'mpeg', 'mpg', '3gp', '3g2', 'webm', 'ogg'];\nconst DOCUMENT_EXTENSIONS = ['txt', 'md', 'csv', 'json', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'rar', '7z'];\nconst PDF_EXTENSION = 'pdf';\n\n/**\n * Extensions that must never be accepted as media uploads, regardless of declared mimetype or\n * admin-configured mediaTypes allowlist. Checked before any other resolution so a spoofed\n * Content-Type (e.g. application/octet-stream on an .html file) can't bypass this.\n */\nexport const DANGEROUS_EXTENSIONS = new Set([\n 'html', 'htm', 'xhtml', 'svg', 'xml',\n 'js', 'mjs', 'php', 'phtml', 'jsp', 'asp', 'aspx',\n 'exe', 'sh', 'bat', 'cmd', 'ps1', 'jar', 'dll',\n 'msi', 'msix', 'msp', 'com', 'scr', 'vbs', 'vbe', 'wsf', 'wsh', 'hta', 'cpl', 'pif', 'reg',\n]);\n\n\n/**\n * Mimetypes that are never safe to accept, regardless of extension. These render as active\n * content in a browser (svg can carry <script>), so they are rejected even when the filename\n * looks harmless. Kept alongside DANGEROUS_EXTENSIONS so upload paths check both.\n */\nexport const DANGEROUS_MIME_TYPES = new Set([\n 'image/svg+xml', 'text/html', 'application/xhtml+xml',\n]);\n\n/**\n * Percent-decodes a filename, repeating a bounded number of times so a double-encoded payload\n * (`%252e` -> `%2e` -> `.`) survives a single pass through a proxy/framework that already\n * decoded once. Malformed escape sequences are left as-is rather than thrown, since this runs\n * on attacker-controlled input and a literal `%` in a filename (`100%done.pdf`) is legal.\n */\nfunction decodePercentEncodingSafely(name: string): string {\n let decoded = name;\n for (let i = 0; i < 3; i++) {\n let next: string;\n try {\n next = decodeURIComponent(decoded);\n } catch {\n return decoded;\n }\n if (next === decoded) {\n return decoded;\n }\n decoded = next;\n }\n return decoded;\n}\n\n/**\n * Reduces a client-supplied name to the name that will actually be resolved on disk, so\n * extension checks can't be dodged by decorating it. Each step defends a known bypass:\n *\n * - `evil.exe%2e` -> percent-encoding a trailing dot (or anything else) hides the real\n * extension from naive string matching; decode before inspecting it.\n * - `../../evil.exe` -> only the final path segment is the file name.\n * - `evil.exe\\0.png` -> a NUL truncates the name at the syscall/filesystem layer, so\n * anything after it is invisible to the OS but visible to naive\n * validation.\n * - `evil.exe::$DATA` -> NTFS alternate data stream suffix; the file on disk is evil.exe.\n * - `evil.exe.` / `.exe ` -> Windows silently strips trailing dots and spaces when resolving\n * a path, so these land on disk as evil.exe.\n */\nexport function normalizeUploadedFileName(fileName?: string | null): string {\n if (!fileName) {\n return '';\n }\n\n let name = decodePercentEncodingSafely(String(fileName));\n name = name.split(/[/\\\\]/).pop() ?? '';\n\n const nulIndex = name.indexOf('\\0');\n if (nulIndex >= 0) {\n name = name.slice(0, nulIndex);\n }\n\n const streamIndex = name.indexOf(':');\n if (streamIndex >= 0) {\n name = name.slice(0, streamIndex);\n }\n\n return name.replace(/[\\s.]+$/, '');\n}\n\n/**\n * The effective extension - what the OS/browser will treat the file as. Used for media\n * category resolution and inline-safety decisions. Always normalizes first, so\n * `evil.exe.` resolves to `exe` rather than to nothing.\n */\nexport function getLowercaseFileExtension(fileName?: string | null): string | undefined {\n const name = normalizeUploadedFileName(fileName);\n\n const lastDotIndex = name.lastIndexOf('.');\n if (lastDotIndex < 0 || lastDotIndex === name.length - 1) {\n return undefined;\n }\n\n return name.slice(lastDotIndex + 1).toLowerCase();\n}\n\n/**\n * Every dot-delimited segment after the stem, lowercased. The danger check uses this rather\n * than only the effective extension so a dangerous type buried in a double extension\n * (`evil.exe.png`, `shell.php.jpg`) is still caught - several servers and browsers resolve\n * such names by an earlier segment than the last one.\n *\n * The stem is skipped so an innocuous file that merely starts with a keyword (`exe.png`)\n * isn't rejected.\n */\nexport function getLowercaseFileExtensionSegments(fileName?: string | null): string[] {\n const segments = normalizeUploadedFileName(fileName).toLowerCase().split('.');\n return segments.slice(1).filter(segment => segment.length > 0);\n}\n\n/** Minimal shape of an uploaded file, so this module stays free of framework imports. */\nexport interface UploadedFileLike {\n mimetype?: string;\n originalname?: string;\n filename?: string;\n}\n\n/** originalname is the client-supplied name; filename is multer's on-disk name. */\nexport function getUploadedFileName(file?: UploadedFileLike | null): string {\n return file?.originalname ?? file?.filename ?? '';\n}\n\n/**\n * Single predicate for \"must never be stored\". Shared by every upload entry point\n * (MediaFieldCrudManager, chatter attachments) so the rules can't drift between them.\n * Extensions are checked before mimetype so a spoofed Content-Type (e.g.\n * application/octet-stream, or image/png, on an .html file) can't bypass it.\n */\nexport function isDangerousMediaFile(file?: UploadedFileLike | null): boolean {\n const segments = getLowercaseFileExtensionSegments(getUploadedFileName(file));\n if (segments.some(segment => DANGEROUS_EXTENSIONS.has(segment))) {\n return true;\n }\n\n return DANGEROUS_MIME_TYPES.has((file?.mimetype || '').toLowerCase().trim());\n}\n\n/**\n * Single source of truth for extension -> coarse media category. Shared by upload-time\n * validation (MediaFieldCrudManager) and serve-time header hardening (ServeStaticModule), so\n * both agree on which extensions belong to which category and neither drifts out of sync.\n * webm/ogg are shared between AUDIO_EXTENSIONS and VIDEO_EXTENSIONS - last one wins here, they\n * default to 'video' since that's the more common upload case.\n */\nexport const EXT_TO_MEDIA_TYPE: Record<string, MediaCategory> = {\n ...Object.fromEntries(IMAGE_EXTENSIONS.map((ext) => [ext, 'image' as const])),\n ...Object.fromEntries(AUDIO_EXTENSIONS.map((ext) => [ext, 'audio' as const])),\n ...Object.fromEntries(VIDEO_EXTENSIONS.map((ext) => [ext, 'video' as const])),\n ...Object.fromEntries(DOCUMENT_EXTENSIONS.map((ext) => [ext, 'file' as const])),\n [PDF_EXTENSION]: 'pdf',\n};\n\n/**\n * Extensions safe to serve inline with their natural Content-Type; everything else served from\n * media-files-storage is forced to application/octet-stream + Content-Disposition: attachment.\n */\nexport const INLINE_SAFE_EXTENSIONS = new Set<string>([\n ...IMAGE_EXTENSIONS,\n ...AUDIO_EXTENSIONS,\n ...VIDEO_EXTENSIONS,\n PDF_EXTENSION,\n]);\n"]}
|
|
1
|
+
{"version":3,"file":"media-file-types.js","sourceRoot":"","sources":["../../src/constants/media-file-types.ts"],"names":[],"mappings":"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","sourcesContent":["export type MediaCategory = 'image' | 'audio' | 'video' | 'file' | 'pdf';\n\nexport const MEDIA_CATEGORIES = ['image', 'audio', 'video', 'file', 'pdf'] as const;\n\nexport type MediaFileTypeDefinition = {\n mediaType: MediaCategory;\n mimeType: string;\n extension: string;\n};\n\n// Single source of truth for every supported media extension, its canonical MIME type,\n// and the coarse media category used across validation and UI metadata.\nexport const MEDIA_FILE_TYPES: MediaFileTypeDefinition[] = [\n { mediaType: 'image', mimeType: 'image/png', extension: 'png' },\n { mediaType: 'image', mimeType: 'image/jpeg', extension: 'jpg' },\n { mediaType: 'image', mimeType: 'image/jpg', extension: 'jpg' },\n { mediaType: 'image', mimeType: 'image/jpeg', extension: 'jpeg' },\n { mediaType: 'image', mimeType: 'image/webp', extension: 'webp' },\n { mediaType: 'image', mimeType: 'image/gif', extension: 'gif' },\n { mediaType: 'image', mimeType: 'image/bmp', extension: 'bmp' },\n { mediaType: 'image', mimeType: 'image/tiff', extension: 'tiff' },\n { mediaType: 'image', mimeType: 'image/heic', extension: 'heic' },\n { mediaType: 'image', mimeType: 'image/heif', extension: 'heif' },\n\n { mediaType: 'audio', mimeType: 'audio/mpeg', extension: 'mp3' },\n { mediaType: 'audio', mimeType: 'audio/mp3', extension: 'mp3' },\n { mediaType: 'audio', mimeType: 'audio/wav', extension: 'wav' },\n { mediaType: 'audio', mimeType: 'audio/x-wav', extension: 'wav' },\n { mediaType: 'audio', mimeType: 'audio/ogg', extension: 'ogg' },\n { mediaType: 'audio', mimeType: 'audio/aac', extension: 'aac' },\n { mediaType: 'audio', mimeType: 'audio/mp4', extension: 'm4a' },\n { mediaType: 'audio', mimeType: 'audio/x-m4a', extension: 'm4a' },\n { mediaType: 'audio', mimeType: 'audio/flac', extension: 'flac' },\n { mediaType: 'audio', mimeType: 'audio/webm', extension: 'webm' },\n\n { mediaType: 'video', mimeType: 'video/mp4', extension: 'mp4' },\n { mediaType: 'video', mimeType: 'video/quicktime', extension: 'mov' },\n { mediaType: 'video', mimeType: 'video/x-msvideo', extension: 'avi' },\n { mediaType: 'video', mimeType: 'video/x-matroska', extension: 'mkv' },\n { mediaType: 'video', mimeType: 'video/mpeg', extension: 'mpeg' },\n { mediaType: 'video', mimeType: 'video/mpeg', extension: 'mpg' },\n { mediaType: 'video', mimeType: 'video/3gpp', extension: '3gp' },\n { mediaType: 'video', mimeType: 'video/3gpp2', extension: '3g2' },\n { mediaType: 'video', mimeType: 'video/webm', extension: 'webm' },\n { mediaType: 'video', mimeType: 'video/ogg', extension: 'ogg' },\n\n { mediaType: 'file', mimeType: 'text/plain', extension: 'txt' },\n { mediaType: 'file', mimeType: 'text/markdown', extension: 'md' },\n { mediaType: 'file', mimeType: 'text/csv', extension: 'csv' },\n { mediaType: 'file', mimeType: 'application/json', extension: 'json' },\n { mediaType: 'file', mimeType: 'application/msword', extension: 'doc' },\n { mediaType: 'file', mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', extension: 'docx' },\n { mediaType: 'file', mimeType: 'application/vnd.ms-excel', extension: 'xls' },\n { mediaType: 'file', mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', extension: 'xlsx' },\n { mediaType: 'file', mimeType: 'application/vnd.ms-powerpoint', extension: 'ppt' },\n { mediaType: 'file', mimeType: 'application/vnd.openxmlformats-officedocument.presentationml.presentation', extension: 'pptx' },\n { mediaType: 'file', mimeType: 'application/zip', extension: 'zip' },\n { mediaType: 'file', mimeType: 'application/x-zip-compressed', extension: 'zip' },\n { mediaType: 'file', mimeType: 'application/x-rar-compressed', extension: 'rar' },\n { mediaType: 'file', mimeType: 'application/x-7z-compressed', extension: '7z' },\n\n { mediaType: 'pdf', mimeType: 'application/pdf', extension: 'pdf' },\n];\n\nconst createMediaTypeBuckets = (): Record<MediaCategory, string[]> => ({\n image: [],\n audio: [],\n video: [],\n file: [],\n pdf: [],\n});\n\nexport const MEDIA_TYPE_TO_EXTENSIONS: Record<MediaCategory, string[]> = MEDIA_FILE_TYPES.reduce((acc, fileType) => {\n if (!acc[fileType.mediaType].includes(fileType.extension)) {\n acc[fileType.mediaType].push(fileType.extension);\n }\n return acc;\n}, createMediaTypeBuckets());\n\nexport const IMAGE_EXTENSIONS = MEDIA_TYPE_TO_EXTENSIONS.image;\nexport const AUDIO_EXTENSIONS = MEDIA_TYPE_TO_EXTENSIONS.audio;\nexport const VIDEO_EXTENSIONS = MEDIA_TYPE_TO_EXTENSIONS.video;\nexport const DOCUMENT_EXTENSIONS = MEDIA_TYPE_TO_EXTENSIONS.file;\nexport const PDF_EXTENSION = 'pdf';\n\nexport const EXTENSION_TO_MIME_TYPE: Record<string, string> = MEDIA_FILE_TYPES.reduce((acc, fileType) => {\n if (!(fileType.extension in acc)) {\n acc[fileType.extension] = fileType.mimeType;\n }\n return acc;\n}, {} as Record<string, string>);\n\nexport const MIME_TO_MEDIA_TYPE: Record<string, MediaCategory> = MEDIA_FILE_TYPES.reduce((acc, fileType) => {\n if (!(fileType.mimeType in acc)) {\n acc[fileType.mimeType] = fileType.mediaType;\n }\n return acc;\n}, {} as Record<string, MediaCategory>);\n\n/**\n * Extensions that must never be accepted as media uploads, regardless of declared mimetype or\n * admin-configured mediaTypes allowlist. Checked before any other resolution so a spoofed\n * Content-Type (e.g. application/octet-stream on an .html file) can't bypass this.\n */\nexport const DANGEROUS_EXTENSIONS = new Set([\n 'html', 'htm', 'xhtml', 'svg', 'xml',\n 'js', 'mjs', 'php', 'phtml', 'jsp', 'asp', 'aspx',\n 'exe', 'sh', 'bat', 'cmd', 'ps1', 'jar', 'dll',\n 'msi', 'msix', 'msp', 'com', 'scr', 'vbs', 'vbe', 'wsf', 'wsh', 'hta', 'cpl', 'pif', 'reg',\n]);\n\n\n/**\n * Mimetypes that are never safe to accept, regardless of extension. These render as active\n * content in a browser (svg can carry <script>), so they are rejected even when the filename\n * looks harmless. Kept alongside DANGEROUS_EXTENSIONS so upload paths check both.\n */\nexport const DANGEROUS_MIME_TYPES = new Set([\n 'image/svg+xml', 'text/html', 'application/xhtml+xml',\n]);\n\n/**\n * Percent-decodes a filename, repeating a bounded number of times so a double-encoded payload\n * (`%252e` -> `%2e` -> `.`) survives a single pass through a proxy/framework that already\n * decoded once. Malformed escape sequences are left as-is rather than thrown, since this runs\n * on attacker-controlled input and a literal `%` in a filename (`100%done.pdf`) is legal.\n */\nfunction decodePercentEncodingSafely(name: string): string {\n let decoded = name;\n for (let i = 0; i < 3; i++) {\n let next: string;\n try {\n next = decodeURIComponent(decoded);\n } catch {\n return decoded;\n }\n if (next === decoded) {\n return decoded;\n }\n decoded = next;\n }\n return decoded;\n}\n\n/**\n * Reduces a client-supplied name to the name that will actually be resolved on disk, so\n * extension checks can't be dodged by decorating it. Each step defends a known bypass:\n *\n * - `evil.exe%2e` -> percent-encoding a trailing dot (or anything else) hides the real\n * extension from naive string matching; decode before inspecting it.\n * - `../../evil.exe` -> only the final path segment is the file name.\n * - `evil.exe\\0.png` -> a NUL truncates the name at the syscall/filesystem layer, so\n * anything after it is invisible to the OS but visible to naive\n * validation.\n * - `evil.exe::$DATA` -> NTFS alternate data stream suffix; the file on disk is evil.exe.\n * - `evil.exe.` / `.exe ` -> Windows silently strips trailing dots and spaces when resolving\n * a path, so these land on disk as evil.exe.\n */\nexport function normalizeUploadedFileName(fileName?: string | null): string {\n if (!fileName) {\n return '';\n }\n\n let name = decodePercentEncodingSafely(String(fileName));\n name = name.split(/[/\\\\]/).pop() ?? '';\n\n const nulIndex = name.indexOf('\\0');\n if (nulIndex >= 0) {\n name = name.slice(0, nulIndex);\n }\n\n const streamIndex = name.indexOf(':');\n if (streamIndex >= 0) {\n name = name.slice(0, streamIndex);\n }\n\n return name.replace(/[\\s.]+$/, '');\n}\n\n/**\n * The effective extension - what the OS/browser will treat the file as. Used for media\n * category resolution and inline-safety decisions. Always normalizes first, so\n * `evil.exe.` resolves to `exe` rather than to nothing.\n */\nexport function getLowercaseFileExtension(fileName?: string | null): string | undefined {\n const name = normalizeUploadedFileName(fileName);\n\n const lastDotIndex = name.lastIndexOf('.');\n if (lastDotIndex < 0 || lastDotIndex === name.length - 1) {\n return undefined;\n }\n\n return name.slice(lastDotIndex + 1).toLowerCase();\n}\n\n/**\n * Every dot-delimited segment after the stem, lowercased. The danger check uses this rather\n * than only the effective extension so a dangerous type buried in a double extension\n * (`evil.exe.png`, `shell.php.jpg`) is still caught - several servers and browsers resolve\n * such names by an earlier segment than the last one.\n *\n * The stem is skipped so an innocuous file that merely starts with a keyword (`exe.png`)\n * isn't rejected.\n */\nexport function getLowercaseFileExtensionSegments(fileName?: string | null): string[] {\n const segments = normalizeUploadedFileName(fileName).toLowerCase().split('.');\n return segments.slice(1).filter(segment => segment.length > 0);\n}\n\n/** Minimal shape of an uploaded file, so this module stays free of framework imports. */\nexport interface UploadedFileLike {\n mimetype?: string;\n originalname?: string;\n filename?: string;\n}\n\n/** originalname is the client-supplied name; filename is multer's on-disk name. */\nexport function getUploadedFileName(file?: UploadedFileLike | null): string {\n return file?.originalname ?? file?.filename ?? '';\n}\n\n/**\n * Single predicate for \"must never be stored\". Shared by every upload entry point\n * (MediaFieldCrudManager, chatter attachments) so the rules can't drift between them.\n * Extensions are checked before mimetype so a spoofed Content-Type (e.g.\n * application/octet-stream, or image/png, on an .html file) can't bypass it.\n */\nexport function isDangerousMediaFile(file?: UploadedFileLike | null): boolean {\n const segments = getLowercaseFileExtensionSegments(getUploadedFileName(file));\n if (segments.some(segment => DANGEROUS_EXTENSIONS.has(segment))) {\n return true;\n }\n\n return DANGEROUS_MIME_TYPES.has((file?.mimetype || '').toLowerCase().trim());\n}\n\n/**\n * Single source of truth for extension -> coarse media category. Shared by upload-time\n * validation (MediaFieldCrudManager) and serve-time header hardening (ServeStaticModule), so\n * both agree on which extensions belong to which category and neither drifts out of sync.\n * webm/ogg are shared between AUDIO_EXTENSIONS and VIDEO_EXTENSIONS - last one wins here, they\n * default to 'video' since that's the more common upload case.\n */\nexport const EXT_TO_MEDIA_TYPE: Record<string, MediaCategory> = {\n ...Object.fromEntries(MEDIA_FILE_TYPES.map((fileType) => [fileType.extension, fileType.mediaType])),\n};\n\n/**\n * Extensions safe to serve inline with their natural Content-Type; everything else served from\n * media-files-storage is forced to application/octet-stream + Content-Disposition: attachment.\n */\nexport const INLINE_SAFE_EXTENSIONS = new Set<string>([\n ...IMAGE_EXTENSIONS,\n ...AUDIO_EXTENSIONS,\n ...VIDEO_EXTENSIONS,\n PDF_EXTENSION,\n]);\n"]}
|
|
@@ -350,6 +350,10 @@ export declare class FieldMetadataController {
|
|
|
350
350
|
label: "file" | "image" | "audio" | "video" | "pdf";
|
|
351
351
|
value: "file" | "image" | "audio" | "video" | "pdf";
|
|
352
352
|
}[];
|
|
353
|
+
mediaFileTypeDefinitions: {
|
|
354
|
+
mediaType: import("../constants/media-file-types").MediaCategory;
|
|
355
|
+
extension: string;
|
|
356
|
+
}[];
|
|
353
357
|
relationTypes: {
|
|
354
358
|
label: unknown;
|
|
355
359
|
value: unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-metadata.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/field-metadata.controller.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAE1E,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,qBAEa,uBAAuB;IAG5B,OAAO,CAAC,QAAQ,CAAC,oBAAoB;gBAApB,oBAAoB,EAAE,oBAAoB;IAazD,QAAQ,CACD,cAAc,EAAE,cAAc;;;;;;;;;;;IAOrC,wBAAwB
|
|
1
|
+
{"version":3,"file":"field-metadata.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/field-metadata.controller.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAE1E,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,qBAEa,uBAAuB;IAG5B,OAAO,CAAC,QAAQ,CAAC,oBAAoB;gBAApB,oBAAoB,EAAE,oBAAoB;IAazD,QAAQ,CACD,cAAc,EAAE,cAAc;;;;;;;;;;;IAOrC,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAMxB,yBAAyB,CAAU,KAAK,EAAE,wBAAwB;IAMlE,wBAAwB,CAAU,KAAK,EAAE,wBAAwB;IAMvE,OAAO,CAA4B,EAAE,EAAE,MAAM,EAAW,KAAK,EAAE,GAAG;IAMlE,MAAM,CAAS,UAAU,EAAE,sBAAsB,EAAE;IAM7C,MAAM,CAAc,EAAE,EAAE,MAAM;IAMpC,YAAY,CAAS,eAAe,EAAE,eAAe;;;CAKxD"}
|
|
@@ -18,6 +18,10 @@ export declare class ViewMetadataController {
|
|
|
18
18
|
solidFieldsMetadata: {
|
|
19
19
|
[k: string]: import("..").FieldMetadata;
|
|
20
20
|
};
|
|
21
|
+
mediaFileTypeDefinitions: {
|
|
22
|
+
mediaType: import("../constants/media-file-types").MediaCategory;
|
|
23
|
+
extension: string;
|
|
24
|
+
}[];
|
|
21
25
|
solidFormViewWorkflowData: readonly import("..").IWorkflowFieldDataProviderValues[];
|
|
22
26
|
applicableLocales: any[];
|
|
23
27
|
viewModes: any[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-metadata.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/view-metadata.controller.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAEzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAE5E,OAAO,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAE3E,qBAEa,sBAAsB;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,mBAAmB;IAKzD,MAAM,CAAS,SAAS,EAAE,qBAAqB,EAAmB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAkC,mBAAmB,EAAE,sBAAsB;IAOhL,UAAU,CAAS,UAAU,EAAE,qBAAqB,EAAE,EAAmB,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAO,EAAkC,mBAAmB,EAAE,sBAAsB;IAQ9L,MAAM,CAAc,EAAE,EAAE,MAAM,EAAU,SAAS,EAAE,qBAAqB,EAAmB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAkC,mBAAmB,EAAE,sBAAsB;IAgBnM,QAAQ,CAAU,KAAK,EAAE,GAAG,EAAkC,mBAAmB,EAAE,sBAAsB;IAMzG,OAAO,CAAc,EAAE,EAAE,MAAM,EAAW,KAAK,EAAE,GAAG,EAAkC,mBAAmB,EAAE,sBAAsB;IAKjI,UAAU,CAAS,GAAG,EAAE,MAAM,EAAE,EAAkC,mBAAmB,EAAE,sBAAsB;IAM7G,MAAM,CAAc,EAAE,EAAE,MAAM,EAAkC,mBAAmB,EAAE,sBAAsB;IAMjH,SAAS,CAAU,KAAK,EAAE,GAAG,EAAgB,UAAU,EAAE,cAAc
|
|
1
|
+
{"version":3,"file":"view-metadata.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/view-metadata.controller.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAEzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAE5E,OAAO,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAE3E,qBAEa,sBAAsB;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,mBAAmB;IAKzD,MAAM,CAAS,SAAS,EAAE,qBAAqB,EAAmB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAkC,mBAAmB,EAAE,sBAAsB;IAOhL,UAAU,CAAS,UAAU,EAAE,qBAAqB,EAAE,EAAmB,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAO,EAAkC,mBAAmB,EAAE,sBAAsB;IAQ9L,MAAM,CAAc,EAAE,EAAE,MAAM,EAAU,SAAS,EAAE,qBAAqB,EAAmB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAkC,mBAAmB,EAAE,sBAAsB;IAgBnM,QAAQ,CAAU,KAAK,EAAE,GAAG,EAAkC,mBAAmB,EAAE,sBAAsB;IAMzG,OAAO,CAAc,EAAE,EAAE,MAAM,EAAW,KAAK,EAAE,GAAG,EAAkC,mBAAmB,EAAE,sBAAsB;IAKjI,UAAU,CAAS,GAAG,EAAE,MAAM,EAAE,EAAkC,mBAAmB,EAAE,sBAAsB;IAM7G,MAAM,CAAc,EAAE,EAAE,MAAM,EAAkC,mBAAmB,EAAE,sBAAsB;IAMjH,SAAS,CAAU,KAAK,EAAE,GAAG,EAAgB,UAAU,EAAE,cAAc;;;;;;;;;;;;;CAIxE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LongTextFieldCrudManager.d.ts","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/LongTextFieldCrudManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"LongTextFieldCrudManager.d.ts","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/LongTextFieldCrudManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGnE,MAAM,WAAW,oBAAoB;IACjC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACxC,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,wBAAyB,YAAW,gBAAgB;IAC7D,OAAO,CAAC,OAAO,CAAuB;gBAE1B,OAAO,EAAE,oBAAoB;IAIzC,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,eAAe,EAAE;IAKrC,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,sBAAsB;IAO9B,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG;IAKjC,OAAO,CAAC,uBAAuB;IAG/B,OAAO,CAAC,sBAAsB;IAG9B,OAAO,CAAC,yBAAyB;CAGpC"}
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LongTextFieldCrudManager = void 0;
|
|
4
4
|
const class_validator_1 = require("class-validator");
|
|
5
|
+
const textFieldCrudManagerUtils_1 = require("./textFieldCrudManagerUtils");
|
|
5
6
|
class LongTextFieldCrudManager {
|
|
6
7
|
constructor(options) {
|
|
7
8
|
this.options = options;
|
|
8
9
|
}
|
|
9
10
|
validate(dto) {
|
|
10
|
-
const fieldValue = dto[this.options.fieldName];
|
|
11
|
+
const fieldValue = (0, textFieldCrudManagerUtils_1.normalizeTextFieldValue)(dto[this.options.fieldName]);
|
|
11
12
|
return this.applyValidations(fieldValue);
|
|
12
13
|
}
|
|
13
14
|
applyValidations(fieldValue) {
|
|
@@ -25,7 +26,7 @@ class LongTextFieldCrudManager {
|
|
|
25
26
|
return errors;
|
|
26
27
|
}
|
|
27
28
|
transformForCreate(dto) {
|
|
28
|
-
return dto;
|
|
29
|
+
return (0, textFieldCrudManagerUtils_1.normalizeTextFieldInDto)(dto, this.options.fieldName);
|
|
29
30
|
}
|
|
30
31
|
isApplyStringValidation() {
|
|
31
32
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LongTextFieldCrudManager.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/LongTextFieldCrudManager.ts"],"names":[],"mappings":";;;AAAA,qDAAyE;
|
|
1
|
+
{"version":3,"file":"LongTextFieldCrudManager.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/LongTextFieldCrudManager.ts"],"names":[],"mappings":";;;AAAA,qDAAyE;AAEzE,2EAA+F;AAQ/F,MAAa,wBAAwB;IAGjC,YAAY,OAA6B;QACrC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED,QAAQ,CAAC,GAAQ;QACb,MAAM,UAAU,GAAQ,IAAA,mDAAuB,EAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;QAC7E,OAAO,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC;IAEO,gBAAgB,CAAC,UAAe;QACpC,MAAM,MAAM,GAAsB,EAAE,CAAC;QACrC,IAAI,CAAC,yBAAyB,EAAE,IAAI,IAAA,yBAAO,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAA,CAAC,CAAC,WAAW,CAAC;QAC7K,IAAI,IAAA,4BAAU,EAAC,UAAU,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,sBAAsB,CAAC,UAAe;QAC1C,MAAM,MAAM,GAAsB,EAAE,CAAC;QACrC,IAAI,CAAC,uBAAuB,EAAE,IAAI,CAAC,IAAA,0BAAQ,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QACvJ,IAAI,CAAC,sBAAsB,EAAE,IAAI,CAAC,IAAA,yBAAO,EAAC,UAAU,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QACrM,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,kBAAkB,CAAC,GAAQ;QACvB,OAAO,IAAA,mDAAuB,EAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC;IAGO,uBAAuB;QAC3B,OAAO,IAAI,CAAC;IAChB,CAAC;IACO,sBAAsB;QAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,KAAK,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IACxI,CAAC;IACO,yBAAyB;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;IACjC,CAAC;CACJ;AA1CD,4DA0CC","sourcesContent":["import { isEmpty, isNotEmpty, isString, matches } from \"class-validator\";\nimport { FieldCrudManager, ValidationError } from \"src/interfaces\";\nimport { normalizeTextFieldInDto, normalizeTextFieldValue } from \"./textFieldCrudManagerUtils\";\n\nexport interface LongTextFieldOptions {\n regexPattern: string | undefined | null;\n required: boolean | undefined | null;\n fieldName: string;\n}\n\nexport class LongTextFieldCrudManager implements FieldCrudManager {\n private options: LongTextFieldOptions;\n\n constructor(options: LongTextFieldOptions) {\n this.options = options;\n }\n\n validate(dto: any): ValidationError[] {\n const fieldValue: any = normalizeTextFieldValue(dto[this.options.fieldName]);\n return this.applyValidations(fieldValue);\n }\n\n private applyValidations(fieldValue: any): ValidationError[] {\n const errors: ValidationError[] = [];\n this.isApplyRequiredValidation() && isEmpty(fieldValue) ? errors.push({ field: this.options.fieldName, error: `Field: ${this.options.fieldName} is required` }): \"no errors\";\n if (isNotEmpty(fieldValue)) {\n errors.push(...this.applyFormatValidations(fieldValue));\n }\n return errors;\n }\n\n private applyFormatValidations(fieldValue: any): ValidationError[] {\n const errors: ValidationError[] = [];\n this.isApplyStringValidation() && !isString(fieldValue) ? errors.push({ field: this.options.fieldName, error: 'Field is not a string' }) : \"no errors\";\n this.isApplyRegexValidation() && !matches(fieldValue, new RegExp(this.options.regexPattern)) ? errors.push({ field: this.options.fieldName, error: 'Field regex pattern is invalid' }) : \"no errors\";\n return errors;\n }\n\n transformForCreate(dto: any): any {\n return normalizeTextFieldInDto(dto, this.options.fieldName);\n }\n\n // Validation to be applied\n private isApplyStringValidation(): boolean {\n return true;\n }\n private isApplyRegexValidation(): boolean {\n return this.options.regexPattern !== null && this.options.regexPattern !== undefined && this.options.regexPattern.trim().length > 0;\n }\n private isApplyRequiredValidation(): boolean {\n return this.options.required;\n }\n}\n"]}
|
|
@@ -7,6 +7,7 @@ export interface MediaFieldOptions {
|
|
|
7
7
|
type: SolidMediaType;
|
|
8
8
|
required: boolean | undefined | null;
|
|
9
9
|
fieldName: string | undefined | null;
|
|
10
|
+
fieldLabel?: string | undefined | null;
|
|
10
11
|
mediaMaxSizeKb: number | undefined | null;
|
|
11
12
|
mediaTypes: string[];
|
|
12
13
|
mediaAllowedExtensions?: string[] | null;
|
|
@@ -15,6 +16,7 @@ export interface MediaFieldOptions {
|
|
|
15
16
|
export declare class MediaFieldCrudManager implements FieldCrudManager {
|
|
16
17
|
private readonly options;
|
|
17
18
|
constructor(options: MediaFieldOptions);
|
|
19
|
+
private getFieldLabel;
|
|
18
20
|
private resolveMediaType;
|
|
19
21
|
validate(dto: any, files: Array<Express.Multer.File>): ValidationError[];
|
|
20
22
|
private applyValidations;
|
|
@@ -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;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,sBAAsB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACzC,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;CACxC;
|
|
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,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACvC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IAC1C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,sBAAsB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACzC,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;CACxC;AAID,qBAAa,qBAAsB,YAAW,gBAAgB;IAE9C,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,iBAAiB;IAGvD,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,gBAAgB;IA+BxB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,eAAe,EAAE;IAKxE,OAAO,CAAC,gBAAgB;IAexB,OAAO,CAAC,sBAAsB;IAY9B,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,YAAY;IAiBpB,OAAO,CAAC,aAAa;IAsBrB,OAAO,CAAC,yBAAyB;IAmBjC,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,qBAAqB;IAI7B,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG;CAKpC"}
|
|
@@ -7,55 +7,13 @@ var SolidMediaType;
|
|
|
7
7
|
SolidMediaType["mediaSingle"] = "mediaSingle";
|
|
8
8
|
SolidMediaType["mediaMultiple"] = "mediaMultiple";
|
|
9
9
|
})(SolidMediaType || (exports.SolidMediaType = SolidMediaType = {}));
|
|
10
|
-
const MIME_TO_MEDIA_TYPE = {
|
|
11
|
-
'image/png': 'image',
|
|
12
|
-
'image/jpeg': 'image',
|
|
13
|
-
'image/jpg': 'image',
|
|
14
|
-
'image/webp': 'image',
|
|
15
|
-
'image/gif': 'image',
|
|
16
|
-
'image/bmp': 'image',
|
|
17
|
-
'image/tiff': 'image',
|
|
18
|
-
'image/heic': 'image',
|
|
19
|
-
'image/heif': 'image',
|
|
20
|
-
'audio/mpeg': 'audio',
|
|
21
|
-
'audio/mp3': 'audio',
|
|
22
|
-
'audio/wav': 'audio',
|
|
23
|
-
'audio/x-wav': 'audio',
|
|
24
|
-
'audio/webm': 'audio',
|
|
25
|
-
'audio/ogg': 'audio',
|
|
26
|
-
'audio/aac': 'audio',
|
|
27
|
-
'audio/mp4': 'audio',
|
|
28
|
-
'audio/x-m4a': 'audio',
|
|
29
|
-
'audio/flac': 'audio',
|
|
30
|
-
'video/mp4': 'video',
|
|
31
|
-
'video/mpeg': 'video',
|
|
32
|
-
'video/webm': 'video',
|
|
33
|
-
'video/ogg': 'video',
|
|
34
|
-
'video/quicktime': 'video',
|
|
35
|
-
'video/x-msvideo': 'video',
|
|
36
|
-
'video/x-matroska': 'video',
|
|
37
|
-
'video/3gpp': 'video',
|
|
38
|
-
'video/3gpp2': 'video',
|
|
39
|
-
'application/pdf': 'pdf',
|
|
40
|
-
'text/plain': 'file',
|
|
41
|
-
'text/markdown': 'file',
|
|
42
|
-
'application/json': 'file',
|
|
43
|
-
'text/csv': 'file',
|
|
44
|
-
'application/msword': 'file',
|
|
45
|
-
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'file',
|
|
46
|
-
'application/vnd.ms-excel': 'file',
|
|
47
|
-
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'file',
|
|
48
|
-
'application/vnd.ms-powerpoint': 'file',
|
|
49
|
-
'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'file',
|
|
50
|
-
'application/zip': 'file',
|
|
51
|
-
'application/x-zip-compressed': 'file',
|
|
52
|
-
'application/x-rar-compressed': 'file',
|
|
53
|
-
'application/x-7z-compressed': 'file',
|
|
54
|
-
};
|
|
55
10
|
class MediaFieldCrudManager {
|
|
56
11
|
constructor(options) {
|
|
57
12
|
this.options = options;
|
|
58
13
|
}
|
|
14
|
+
getFieldLabel() {
|
|
15
|
+
return this.options.fieldLabel || this.options.fieldName || 'File';
|
|
16
|
+
}
|
|
59
17
|
resolveMediaType(file) {
|
|
60
18
|
if ((0, media_file_types_1.isDangerousMediaFile)(file)) {
|
|
61
19
|
return null;
|
|
@@ -66,7 +24,7 @@ class MediaFieldCrudManager {
|
|
|
66
24
|
return null;
|
|
67
25
|
}
|
|
68
26
|
const mt = (file.mimetype || '').toLowerCase().trim();
|
|
69
|
-
const mimeType = MIME_TO_MEDIA_TYPE[mt]
|
|
27
|
+
const mimeType = media_file_types_1.MIME_TO_MEDIA_TYPE[mt]
|
|
70
28
|
?? (mt.startsWith('image/') ? 'image' : mt.startsWith('audio/') ? 'audio' : mt.startsWith('video/') ? 'video' : undefined);
|
|
71
29
|
if (mimeType && mimeType !== extType) {
|
|
72
30
|
return null;
|
|
@@ -93,7 +51,7 @@ class MediaFieldCrudManager {
|
|
|
93
51
|
.filter(fieldFile => (0, media_file_types_1.isDangerousMediaFile)(fieldFile))
|
|
94
52
|
.map(fieldFile => ({
|
|
95
53
|
field: this.options.fieldName,
|
|
96
|
-
error: `${this.
|
|
54
|
+
error: `${this.getFieldLabel()} file type not allowed. ` +
|
|
97
55
|
`${(0, media_file_types_1.getUploadedFileName)(fieldFile) || 'File'} is a potentially dangerous file type.`
|
|
98
56
|
}));
|
|
99
57
|
}
|
|
@@ -110,7 +68,7 @@ class MediaFieldCrudManager {
|
|
|
110
68
|
if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {
|
|
111
69
|
errors.push({
|
|
112
70
|
field: this.options.fieldName,
|
|
113
|
-
error: `${this.
|
|
71
|
+
error: `${this.getFieldLabel()} is required`
|
|
114
72
|
});
|
|
115
73
|
}
|
|
116
74
|
return errors;
|
|
@@ -124,7 +82,7 @@ class MediaFieldCrudManager {
|
|
|
124
82
|
if (fieldFileSizeInBytes > this.options.mediaMaxSizeKb) {
|
|
125
83
|
errors.push({
|
|
126
84
|
field: this.options.fieldName,
|
|
127
|
-
error: `${this.
|
|
85
|
+
error: `${this.getFieldLabel()} with size ${fieldFileSizeInBytes} KB exceeds max size limit of ${this.options.mediaMaxSizeKb} KB`
|
|
128
86
|
});
|
|
129
87
|
}
|
|
130
88
|
}
|
|
@@ -141,7 +99,7 @@ class MediaFieldCrudManager {
|
|
|
141
99
|
if (!resolvedType || !allowedFileTypes.includes(resolvedType)) {
|
|
142
100
|
errors.push({
|
|
143
101
|
field: this.options.fieldName,
|
|
144
|
-
error: `${this.
|
|
102
|
+
error: `${this.getFieldLabel()} file type not allowed. ` +
|
|
145
103
|
`Allowed: ${allowedFileTypes.join(', ')}. ` +
|
|
146
104
|
`Received mimetype: ${fieldFile.mimetype}${resolvedType ? ` (mapped to ${resolvedType})` : ''}`
|
|
147
105
|
});
|
|
@@ -163,7 +121,7 @@ class MediaFieldCrudManager {
|
|
|
163
121
|
})
|
|
164
122
|
.map(fieldFile => ({
|
|
165
123
|
field: this.options.fieldName,
|
|
166
|
-
error: `${this.
|
|
124
|
+
error: `${this.getFieldLabel()} file type not allowed. ` +
|
|
167
125
|
`Allowed extensions: ${[...normalizedAllowed].join(', ')}.`
|
|
168
126
|
}));
|
|
169
127
|
}
|
|
@@ -172,7 +130,7 @@ class MediaFieldCrudManager {
|
|
|
172
130
|
if (fieldFiles.length > 1) {
|
|
173
131
|
errors.push({
|
|
174
132
|
field: this.options.fieldName,
|
|
175
|
-
error: `${this.
|
|
133
|
+
error: `${this.getFieldLabel()} must be a single file`
|
|
176
134
|
});
|
|
177
135
|
}
|
|
178
136
|
return errors;
|
|
@@ -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\";\nimport { EXT_TO_MEDIA_TYPE, getLowercaseFileExtension, getUploadedFileName, isDangerousMediaFile, 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 mediaAllowedExtensions?: string[] | null;\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(file: Express.Multer.File): MediaType | null {\n // Belt-and-braces: dangerous files are already rejected outright by\n // validateDangerousFiles, but never let one resolve to a usable category.\n if (isDangerousMediaFile(file)) {\n return null;\n }\n\n // Extension is authoritative: a declared mimetype is fully attacker-controlled and\n // proved insufficient on its own (a .msi uploaded as image/png previously resolved to\n // 'image', since the mimetype match short-circuited before the extension was ever\n // checked). The extension must independently resolve to a known-safe category before\n // anything is accepted - not merely \"not on the denylist\".\n const ext = getLowercaseFileExtension(getUploadedFileName(file));\n const extType = ext ? EXT_TO_MEDIA_TYPE[ext] : undefined;\n if (!extType) {\n return null;\n }\n\n // The mimetype may only confirm or veto what the extension already established, never\n // grant a category on its own. A mimetype that doesn't resolve to anything (e.g.\n // application/octet-stream) has no opinion and is treated as agreeing.\n const mt = (file.mimetype || '').toLowerCase().trim();\n const mimeType = MIME_TO_MEDIA_TYPE[mt]\n ?? (mt.startsWith('image/') ? 'image' : mt.startsWith('audio/') ? 'audio' : mt.startsWith('video/') ? 'video' : undefined);\n if (mimeType && mimeType !== extType) {\n return null;\n }\n\n return extType;\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 // A dangerous upload is never acceptable, regardless of admin config, so this is the\n // only check that sits outside validateCommon() and can't be skipped either way below.\n const dangerousFileErrors = this.validateDangerousFiles(fieldFiles);\n\n switch (this.options.type) {\n case SolidMediaType.mediaSingle:\n return [...dangerousFileErrors, ...this.validateMediaSingle(fieldFiles)];\n case SolidMediaType.mediaMultiple:\n return [...dangerousFileErrors, ...this.validateMediaMultiple(fieldFiles)];\n default:\n return dangerousFileErrors;\n }\n }\n\n private validateDangerousFiles(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return fieldFiles\n .filter(fieldFile => isDangerousMediaFile(fieldFile))\n .map(fieldFile => ({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `${getUploadedFileName(fieldFile) || 'File'} is a potentially dangerous file type.`\n }));\n }\n\n // Every optional, admin-configured, per-field check - no-ops when its setting is unset -\n // shared between mediaSingle and mediaMultiple so neither can drift out of sync with it.\n private validateCommon(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return [\n ...this.validateRequired(fieldFiles),\n ...this.validateSize(fieldFiles),\n ...this.validateTypes(fieldFiles),\n ...this.validateAllowedExtensions(fieldFiles),\n ];\n }\n\n private validateRequired(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 private validateSize(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\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 return errors;\n }\n\n private validateTypes(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\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);\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 return errors;\n }\n\n private validateAllowedExtensions(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const allowed = this.options.mediaAllowedExtensions;\n if (!allowed || allowed.length === 0) {\n return [];\n }\n\n const normalizedAllowed = new Set(allowed.map(ext => ext.toLowerCase().replace(/^\\./, '')));\n return fieldFiles\n .filter(fieldFile => {\n const ext = getLowercaseFileExtension(getUploadedFileName(fieldFile));\n return !ext || !normalizedAllowed.has(ext);\n })\n .map(fieldFile => ({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `Allowed extensions: ${[...normalizedAllowed].join(', ')}.`\n }));\n }\n\n private validateMediaSingle(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors = this.validateCommon(fieldFiles);\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 return errors;\n }\n\n private validateMediaMultiple(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return this.validateCommon(fieldFiles);\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 { EXT_TO_MEDIA_TYPE, getLowercaseFileExtension, getUploadedFileName, isDangerousMediaFile, MediaCategory, MIME_TO_MEDIA_TYPE } 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 fieldLabel?: string | undefined | null;\n mediaMaxSizeKb: number | undefined | null;\n mediaTypes: string[];\n mediaAllowedExtensions?: string[] | null;\n isUpdate: boolean | undefined | null;\n}\n\ntype MediaType = MediaCategory;\n\nexport class MediaFieldCrudManager implements FieldCrudManager {\n\n constructor(private readonly options: MediaFieldOptions) {\n }\n\n private getFieldLabel(): string {\n return this.options.fieldLabel || this.options.fieldName || 'File';\n }\n\n private resolveMediaType(file: Express.Multer.File): MediaType | null {\n // Belt-and-braces: dangerous files are already rejected outright by\n // validateDangerousFiles, but never let one resolve to a usable category.\n if (isDangerousMediaFile(file)) {\n return null;\n }\n\n // Extension is authoritative: a declared mimetype is fully attacker-controlled and\n // proved insufficient on its own (a .msi uploaded as image/png previously resolved to\n // 'image', since the mimetype match short-circuited before the extension was ever\n // checked). The extension must independently resolve to a known-safe category before\n // anything is accepted - not merely \"not on the denylist\".\n const ext = getLowercaseFileExtension(getUploadedFileName(file));\n const extType = ext ? EXT_TO_MEDIA_TYPE[ext] : undefined;\n if (!extType) {\n return null;\n }\n\n // The mimetype may only confirm or veto what the extension already established, never\n // grant a category on its own. A mimetype that doesn't resolve to anything (e.g.\n // application/octet-stream) has no opinion and is treated as agreeing.\n const mt = (file.mimetype || '').toLowerCase().trim();\n const mimeType = MIME_TO_MEDIA_TYPE[mt]\n ?? (mt.startsWith('image/') ? 'image' : mt.startsWith('audio/') ? 'audio' : mt.startsWith('video/') ? 'video' : undefined);\n if (mimeType && mimeType !== extType) {\n return null;\n }\n\n return extType;\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 // A dangerous upload is never acceptable, regardless of admin config, so this is the\n // only check that sits outside validateCommon() and can't be skipped either way below.\n const dangerousFileErrors = this.validateDangerousFiles(fieldFiles);\n\n switch (this.options.type) {\n case SolidMediaType.mediaSingle:\n return [...dangerousFileErrors, ...this.validateMediaSingle(fieldFiles)];\n case SolidMediaType.mediaMultiple:\n return [...dangerousFileErrors, ...this.validateMediaMultiple(fieldFiles)];\n default:\n return dangerousFileErrors;\n }\n }\n\n private validateDangerousFiles(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return fieldFiles\n .filter(fieldFile => isDangerousMediaFile(fieldFile))\n .map(fieldFile => ({\n field: this.options.fieldName,\n error: `${this.getFieldLabel()} file type not allowed. ` +\n `${getUploadedFileName(fieldFile) || 'File'} is a potentially dangerous file type.`\n }));\n }\n\n // Every optional, admin-configured, per-field check - no-ops when its setting is unset -\n // shared between mediaSingle and mediaMultiple so neither can drift out of sync with it.\n private validateCommon(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return [\n ...this.validateRequired(fieldFiles),\n ...this.validateSize(fieldFiles),\n ...this.validateTypes(fieldFiles),\n ...this.validateAllowedExtensions(fieldFiles),\n ];\n }\n\n private validateRequired(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.getFieldLabel()} is required`\n });\n }\n return errors;\n }\n\n private validateSize(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\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.getFieldLabel()} with size ${fieldFileSizeInBytes} KB exceeds max size limit of ${this.options.mediaMaxSizeKb} KB`\n });\n }\n }\n }\n return errors;\n }\n\n private validateTypes(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\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);\n if (!resolvedType || !allowedFileTypes.includes(resolvedType)) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.getFieldLabel()} file type not allowed. ` +\n `Allowed: ${allowedFileTypes.join(', ')}. ` +\n `Received mimetype: ${fieldFile.mimetype}${resolvedType ? ` (mapped to ${resolvedType})` : ''}`\n });\n }\n }\n }\n return errors;\n }\n\n private validateAllowedExtensions(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const allowed = this.options.mediaAllowedExtensions;\n if (!allowed || allowed.length === 0) {\n return [];\n }\n\n const normalizedAllowed = new Set(allowed.map(ext => ext.toLowerCase().replace(/^\\./, '')));\n return fieldFiles\n .filter(fieldFile => {\n const ext = getLowercaseFileExtension(getUploadedFileName(fieldFile));\n return !ext || !normalizedAllowed.has(ext);\n })\n .map(fieldFile => ({\n field: this.options.fieldName,\n error: `${this.getFieldLabel()} file type not allowed. ` +\n `Allowed extensions: ${[...normalizedAllowed].join(', ')}.`\n }));\n }\n\n private validateMediaSingle(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors = this.validateCommon(fieldFiles);\n if (fieldFiles.length > 1) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.getFieldLabel()} must be a single file`\n });\n }\n return errors;\n }\n\n private validateMediaMultiple(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return this.validateCommon(fieldFiles);\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":"ShortTextFieldCrudManager.d.ts","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/ShortTextFieldCrudManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"ShortTextFieldCrudManager.d.ts","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/ShortTextFieldCrudManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGnE,MAAM,WAAW,qBAAqB;IAClC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACxC,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,yBAA0B,YAAW,gBAAgB;IAC9D,OAAO,CAAC,OAAO,CAAwB;gBAE3B,OAAO,EAAE,qBAAqB;IAI1C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAG,MAAM,EAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,eAAe,EAAE;IAMzE,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,sBAAsB;IAQ9B,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG;IAKjC,OAAO,CAAC,uBAAuB;IAG/B,OAAO,CAAC,uBAAuB;IAG/B,OAAO,CAAC,sBAAsB;IAG9B,OAAO,CAAC,yBAAyB;CAGpC"}
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ShortTextFieldCrudManager = void 0;
|
|
4
4
|
const class_validator_1 = require("class-validator");
|
|
5
|
+
const textFieldCrudManagerUtils_1 = require("./textFieldCrudManagerUtils");
|
|
5
6
|
class ShortTextFieldCrudManager {
|
|
6
7
|
constructor(options) {
|
|
7
8
|
this.options = options;
|
|
8
9
|
}
|
|
9
10
|
validate(dto, _files) {
|
|
10
|
-
const fieldValue = dto[this.options.fieldName];
|
|
11
|
+
const fieldValue = (0, textFieldCrudManagerUtils_1.normalizeTextFieldValue)(dto[this.options.fieldName]);
|
|
11
12
|
return this.applyValidations(fieldValue);
|
|
12
13
|
}
|
|
13
14
|
applyValidations(fieldValue) {
|
|
@@ -26,7 +27,7 @@ class ShortTextFieldCrudManager {
|
|
|
26
27
|
return errors;
|
|
27
28
|
}
|
|
28
29
|
transformForCreate(dto) {
|
|
29
|
-
return dto;
|
|
30
|
+
return (0, textFieldCrudManagerUtils_1.normalizeTextFieldInDto)(dto, this.options.fieldName);
|
|
30
31
|
}
|
|
31
32
|
isApplyStringValidation() {
|
|
32
33
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShortTextFieldCrudManager.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/ShortTextFieldCrudManager.ts"],"names":[],"mappings":";;;AAAA,qDAAiF;
|
|
1
|
+
{"version":3,"file":"ShortTextFieldCrudManager.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/ShortTextFieldCrudManager.ts"],"names":[],"mappings":";;;AAAA,qDAAiF;AAEjF,2EAA+F;AAS/F,MAAa,yBAAyB;IAGlC,YAAY,OAA8B;QACtC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED,QAAQ,CAAC,GAAQ,EAAG,MAAiC;QACjD,MAAM,UAAU,GAAQ,IAAA,mDAAuB,EAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;QAC7E,OAAO,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC;IAGO,gBAAgB,CAAC,UAAe;QACpC,MAAM,MAAM,GAAsB,EAAE,CAAC;QACrC,IAAI,CAAC,yBAAyB,EAAE,IAAI,IAAA,yBAAO,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAA,CAAC,CAAC,WAAW,CAAC;QAC7K,IAAI,IAAA,4BAAU,EAAC,UAAU,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,sBAAsB,CAAC,UAAe;QAC1C,MAAM,MAAM,GAAsB,EAAE,CAAC;QACrC,IAAI,CAAC,uBAAuB,EAAE,IAAI,CAAC,IAAA,0BAAQ,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QACvJ,IAAI,CAAC,uBAAuB,EAAE,IAAI,CAAC,IAAA,wBAAM,EAAC,UAAU,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QAC/K,IAAI,CAAC,sBAAsB,EAAE,IAAI,CAAC,IAAA,yBAAO,EAAC,UAAU,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QACrM,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,kBAAkB,CAAC,GAAQ;QACvB,OAAO,IAAA,mDAAuB,EAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC;IAGO,uBAAuB;QAC3B,OAAO,IAAI,CAAC;IAChB,CAAC;IACO,uBAAuB;QAC3B,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrC,CAAC;IACO,sBAAsB;QAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,KAAK,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IACxI,CAAC;IACO,yBAAyB;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;IACjC,CAAC;CACJ;AA/CD,8DA+CC","sourcesContent":["import { isEmpty, isNotEmpty, isString, length, matches } from \"class-validator\";\nimport { FieldCrudManager, ValidationError } from \"src/interfaces\";\nimport { normalizeTextFieldInDto, normalizeTextFieldValue } from \"./textFieldCrudManagerUtils\";\n\nexport interface ShortTextFieldOptions {\n length: number | undefined | null;\n regexPattern: string | undefined | null;\n required: boolean | undefined | null;\n fieldName: string;\n}\n\nexport class ShortTextFieldCrudManager implements FieldCrudManager {\n private options: ShortTextFieldOptions;\n\n constructor(options: ShortTextFieldOptions) {\n this.options = options;\n }\n\n validate(dto: any, _files:Array<Express.Multer.File>): ValidationError[] {\n const fieldValue: any = normalizeTextFieldValue(dto[this.options.fieldName]);\n return this.applyValidations(fieldValue);\n }\n\n\n private applyValidations(fieldValue: any): ValidationError[] {\n const errors: ValidationError[] = [];\n this.isApplyRequiredValidation() && isEmpty(fieldValue) ? errors.push({ field: this.options.fieldName, error: `Field: ${this.options.fieldName} is required` }): \"no errors\";\n if (isNotEmpty(fieldValue)) {\n errors.push(...this.applyFormatValidations(fieldValue));\n }\n return errors;\n }\n\n private applyFormatValidations(fieldValue: any): ValidationError[] {\n const errors: ValidationError[] = [];\n this.isApplyStringValidation() && !isString(fieldValue) ? errors.push({ field: this.options.fieldName, error: 'Field is not a string' }) : \"no errors\";\n this.isApplyLengthValidation() && !length(fieldValue, 1, this.options.length) ? errors.push({ field: this.options.fieldName, error: 'Field length is invalid' }) : \"no errors\"; //FIXME min length to be handled\n this.isApplyRegexValidation() && !matches(fieldValue, new RegExp(this.options.regexPattern)) ? errors.push({ field: this.options.fieldName, error: 'Field regex pattern is invalid' }) : \"no errors\";\n return errors;\n }\n\n transformForCreate(dto: any): any {\n return normalizeTextFieldInDto(dto, this.options.fieldName);\n }\n\n // Validation to be applied\n private isApplyStringValidation(): boolean {\n return true;\n }\n private isApplyLengthValidation(): boolean {\n return (this.options.length > 0);\n }\n private isApplyRegexValidation(): boolean {\n return this.options.regexPattern !== null && this.options.regexPattern !== undefined && this.options.regexPattern.trim().length > 0;\n }\n private isApplyRequiredValidation(): boolean {\n return this.options.required;\n }\n}"]}
|