@solidxai/core 0.1.17-beta.0 → 0.1.17-beta.1

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.md ADDED
@@ -0,0 +1,26 @@
1
+ # This is the SolidX API project.
2
+ This is included as a dependency in consuming projects.
3
+
4
+ # SolidX UI
5
+ # The corresponding UI project is at the below path:
6
+ /Users/oswald/projects/Solid_Starters/solid-core-ui
7
+
8
+ # SolidX Docs
9
+ # The documentation project is at the below path:
10
+ /Users/oswald/projects/solidxai-docs
11
+
12
+ # SolidX Agent
13
+ # The agent project which has the skills for helping users configure, build and use SolidX is at the below path:
14
+ /Users/oswald/projects/Solid_Starters/agent
15
+
16
+ # SolidX Control Plane Commands
17
+ # The control plane commands for managing SolidX instances are in the below path:
18
+ /Users/oswald/projects/Solid_Starters/solidctl
19
+
20
+ # Testing reference project
21
+ # This is the reference library management project that is used for testing and development of SolidX features. It is located at the below path:
22
+ /Users/oswald/projects/Solid_Starters/solid-library-management
23
+
24
+ # Code Builder project
25
+ # This is the project that contains the code builder which generates code based on user input and templates. It is located at the below path:
26
+ /Users/oswald/projects/Solid_Starters/solid-code-builder
@@ -5,6 +5,8 @@ export type MediaFileTypeDefinition = {
5
5
  mimeType: string;
6
6
  extension: string;
7
7
  };
8
+ export declare const DANGEROUS_EXTENSIONS: Set<string>;
9
+ export declare const DANGEROUS_MIME_TYPES: Set<string>;
8
10
  export declare const MEDIA_FILE_TYPES: MediaFileTypeDefinition[];
9
11
  export declare const MEDIA_TYPE_TO_EXTENSIONS: Record<MediaCategory, string[]>;
10
12
  export declare const IMAGE_EXTENSIONS: string[];
@@ -14,8 +16,6 @@ export declare const DOCUMENT_EXTENSIONS: string[];
14
16
  export declare const PDF_EXTENSION = "pdf";
15
17
  export declare const EXTENSION_TO_MIME_TYPE: Record<string, string>;
16
18
  export declare const MIME_TO_MEDIA_TYPE: Record<string, MediaCategory>;
17
- export declare const DANGEROUS_EXTENSIONS: Set<string>;
18
- export declare const DANGEROUS_MIME_TYPES: Set<string>;
19
19
  export declare function normalizeUploadedFileName(fileName?: string | null): string;
20
20
  export declare function getLowercaseFileExtension(fileName?: string | null): string | undefined;
21
21
  export declare function getLowercaseFileExtensionSegments(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;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;AAUD,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CAatB,CAAC;AAE1C,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAE3D,CAAC;AAMF,eAAO,MAAM,sBAAsB,aAKjC,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;AAyBF,eAAO,MAAM,oBAAoB,aAIhC,CAAC;AA0BF,eAAO,MAAM,oBAAoB,aAIhC,CAAC;AAQF,eAAO,MAAM,gBAAgB,EAAE,uBAAuB,EAwDrD,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;AAuCxC,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;AAUD,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CAatB,CAAC;AAE1C,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAE3D,CAAC;AAWF,eAAO,MAAM,sBAAsB,aAKjC,CAAC"}
@@ -1,12 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.INLINE_SAFE_EXTENSIONS = exports.EXT_TO_MEDIA_TYPE = exports.EXT_TO_MEDIA_TYPES = 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;
3
+ exports.INLINE_SAFE_EXTENSIONS = exports.EXT_TO_MEDIA_TYPE = exports.EXT_TO_MEDIA_TYPES = 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.DANGEROUS_MIME_TYPES = exports.DANGEROUS_EXTENSIONS = 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
+ const DEFAULT_DANGEROUS_EXTENSIONS = [
11
+ 'html', 'htm', 'xhtml', 'svg', 'xml',
12
+ 'js', 'mjs', 'php', 'phtml', 'jsp', 'asp', 'aspx',
13
+ 'exe', 'sh', 'bat', 'cmd', 'ps1', 'jar', 'dll',
14
+ 'msi', 'msix', 'msp', 'com', 'scr', 'vbs', 'vbe', 'wsf', 'wsh', 'hta', 'cpl', 'pif', 'reg',
15
+ ];
16
+ const parseExtensionList = (raw) => raw.split(',').map(ext => ext.toLowerCase().trim().replace(/^\./, '')).filter(Boolean);
17
+ const configuredDangerousExtensions = parseExtensionList(process.env.AB_DANGEROUS_EXTENSIONS ?? '');
18
+ exports.DANGEROUS_EXTENSIONS = new Set(configuredDangerousExtensions.length > 0
19
+ ? configuredDangerousExtensions
20
+ : DEFAULT_DANGEROUS_EXTENSIONS);
21
+ const DANGEROUS_MIME_TYPES_BY_EXTENSION = {
22
+ html: ['text/html'],
23
+ htm: ['text/html'],
24
+ xhtml: ['application/xhtml+xml'],
25
+ svg: ['image/svg+xml'],
26
+ };
27
+ exports.DANGEROUS_MIME_TYPES = new Set(Object.entries(DANGEROUS_MIME_TYPES_BY_EXTENSION)
28
+ .filter(([extension]) => exports.DANGEROUS_EXTENSIONS.has(extension))
29
+ .flatMap(([, mimeTypes]) => mimeTypes));
10
30
  exports.MEDIA_FILE_TYPES = [
11
31
  { mediaType: 'image', mimeType: 'image/png', extension: 'png' },
12
32
  { mediaType: 'image', mimeType: 'image/jpeg', extension: 'jpg' },
@@ -18,6 +38,9 @@ exports.MEDIA_FILE_TYPES = [
18
38
  { mediaType: 'image', mimeType: 'image/tiff', extension: 'tiff' },
19
39
  { mediaType: 'image', mimeType: 'image/heic', extension: 'heic' },
20
40
  { mediaType: 'image', mimeType: 'image/heif', extension: 'heif' },
41
+ ...(exports.DANGEROUS_EXTENSIONS.has('svg')
42
+ ? []
43
+ : [{ mediaType: 'image', mimeType: 'image/svg+xml', extension: 'svg' }]),
21
44
  { mediaType: 'audio', mimeType: 'audio/mpeg', extension: 'mp3' },
22
45
  { mediaType: 'audio', mimeType: 'audio/mp3', extension: 'mp3' },
23
46
  { mediaType: 'audio', mimeType: 'audio/wav', extension: 'wav' },
@@ -84,15 +107,6 @@ exports.MIME_TO_MEDIA_TYPE = exports.MEDIA_FILE_TYPES.reduce((acc, fileType) =>
84
107
  }
85
108
  return acc;
86
109
  }, {});
87
- exports.DANGEROUS_EXTENSIONS = new Set([
88
- 'html', 'htm', 'xhtml', 'svg', 'xml',
89
- 'js', 'mjs', 'php', 'phtml', 'jsp', 'asp', 'aspx',
90
- 'exe', 'sh', 'bat', 'cmd', 'ps1', 'jar', 'dll',
91
- 'msi', 'msix', 'msp', 'com', 'scr', 'vbs', 'vbe', 'wsf', 'wsh', 'hta', 'cpl', 'pif', 'reg',
92
- ]);
93
- exports.DANGEROUS_MIME_TYPES = new Set([
94
- 'image/svg+xml', 'text/html', 'application/xhtml+xml',
95
- ]);
96
110
  function decodePercentEncodingSafely(name) {
97
111
  let decoded = name;
98
112
  for (let i = 0; i < 3; i++) {
@@ -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\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 * Some extensions, such as ogg and webm, are valid for more than one category.\n * Keep every matching category instead of allowing a later entry to overwrite an earlier one.\n */\n// Example: { ogg: ['audio', 'video'], mp3: ['audio'], jpg: ['image'] }\nexport const EXT_TO_MEDIA_TYPES: Record<string, MediaCategory[]> = MEDIA_FILE_TYPES.reduce((acc, fileType) => {\n // Create an empty category list the first time we see an extension.\n if (!acc[fileType.extension]) {\n acc[fileType.extension] = [];\n }\n\n // Add the category for this extension, but do not add duplicates.\n if (!acc[fileType.extension].includes(fileType.mediaType)) {\n acc[fileType.extension].push(fileType.mediaType);\n }\n\n // Return the map so the next media definition can be added to it.\n return acc;\n}, {} as Record<string, MediaCategory[]>);\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"]}
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/**\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 *\n * The default list below. A deployment can replace it wholesale via AB_DANGEROUS_EXTENSIONS\n * (comma-separated) - e.g. to accept svg uploads, which some clients legitimately need. This\n * replaces rather than narrows the list: whatever is set there becomes the entire denylist, so\n * anything left out of it becomes an accepted upload type. See default-settings-provider.service.ts\n * for the read-only \"dangerousExtensions\" setting that surfaces the effective list to admins.\n */\nconst DEFAULT_DANGEROUS_EXTENSIONS = [\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\nconst parseExtensionList = (raw: string): string[] =>\n raw.split(',').map(ext => ext.toLowerCase().trim().replace(/^\\./, '')).filter(Boolean);\n\nconst configuredDangerousExtensions = parseExtensionList(process.env.AB_DANGEROUS_EXTENSIONS ?? '');\n\nexport const DANGEROUS_EXTENSIONS = new Set(\n configuredDangerousExtensions.length > 0\n ? configuredDangerousExtensions\n : DEFAULT_DANGEROUS_EXTENSIONS\n);\n\n/**\n * The mimetype gate must track the extension gate: a .svg upload arrives as image/svg+xml, so\n * removing svg from DANGEROUS_EXTENSIONS while image/svg+xml stayed on a separate literal would\n * still reject the upload at isDangerousMediaFile's second check - with a message pointing at\n * nothing the operator changed. Deriving from a single mapping keeps the two in sync.\n *\n * Only browser-rendered types appear here, which is why the resulting set is short (a handful of\n * entries against dozens of dangerous extensions): everything else is dangerous once downloaded\n * and run, and the mimetype sent for those is typically application/octet-stream, which must stay\n * allowed. When adding a browser-renderable extension to the denylist above, add it here too.\n */\nconst DANGEROUS_MIME_TYPES_BY_EXTENSION: Record<string, string[]> = {\n html: ['text/html'],\n htm: ['text/html'],\n xhtml: ['application/xhtml+xml'],\n svg: ['image/svg+xml'],\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 in sync with DANGEROUS_EXTENSIONS via DANGEROUS_MIME_TYPES_BY_EXTENSION\n * above, rather than maintained separately.\n */\nexport const DANGEROUS_MIME_TYPES = new Set(\n Object.entries(DANGEROUS_MIME_TYPES_BY_EXTENSION)\n .filter(([extension]) => DANGEROUS_EXTENSIONS.has(extension))\n .flatMap(([, mimeTypes]) => mimeTypes)\n);\n\n// The set of media extensions the system currently recognises - its canonical MIME type, and the\n// coarse media category used across validation and UI metadata. Membership here means\n// \"resolvable\", not \"safe\": svg is included only when DANGEROUS_EXTENSIONS has been configured to\n// allow it (see below), since accepting it as an upload also makes it eligible for the inline-safe\n// serving path (INLINE_SAFE_EXTENSIONS further down) - safe there only because of the\n// Content-Security-Policy applied when serving it (solid-core.module.ts, media.controller.ts).\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 // Only a media type when explicitly unblocked via AB_DANGEROUS_EXTENSIONS - see the file\n // header comment. Hardcoded to svg specifically: unblocking e.g. html must not make html a\n // media type, since it isn't a format the product supports as an upload.\n ...(DANGEROUS_EXTENSIONS.has('svg')\n ? []\n : [{ mediaType: 'image', mimeType: 'image/svg+xml', extension: 'svg' } as MediaFileTypeDefinition]),\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 * 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 * Some extensions, such as ogg and webm, are valid for more than one category.\n * Keep every matching category instead of allowing a later entry to overwrite an earlier one.\n */\n// Example: { ogg: ['audio', 'video'], mp3: ['audio'], jpg: ['image'] }\nexport const EXT_TO_MEDIA_TYPES: Record<string, MediaCategory[]> = MEDIA_FILE_TYPES.reduce((acc, fileType) => {\n // Create an empty category list the first time we see an extension.\n if (!acc[fileType.extension]) {\n acc[fileType.extension] = [];\n }\n\n // Add the category for this extension, but do not add duplicates.\n if (!acc[fileType.extension].includes(fileType.mediaType)) {\n acc[fileType.extension].push(fileType.mediaType);\n }\n\n // Return the map so the next media definition can be added to it.\n return acc;\n}, {} as Record<string, MediaCategory[]>);\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 *\n * svg is included here only when it's an accepted media type (see MEDIA_FILE_TYPES above) - and\n * even then it's inline-safe only because both serve paths (ServeStaticModule in\n * solid-core.module.ts, and the signed-URL download in media.controller.ts) attach a\n * Content-Security-Policy to svg responses that neutralizes any embedded script.\n */\nexport const INLINE_SAFE_EXTENSIONS = new Set<string>([\n ...IMAGE_EXTENSIONS,\n ...AUDIO_EXTENSIONS,\n ...VIDEO_EXTENSIONS,\n PDF_EXTENSION,\n]);\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"media.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/media.controller.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAMnC,qBAIa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,YAAY;IAKlD,MAAM,CAAS,SAAS,EAAE,cAAc,EAAmB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAkC,mBAAmB,EAAE,sBAAsB;IAOzK,UAAU,CAAS,UAAU,EAAE,cAAc,EAAE,EAAmB,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAO,EAAkC,mBAAmB,EAAE,sBAAsB;IAQvL,MAAM,CAAc,EAAE,EAAE,MAAM,EAAU,SAAS,EAAE,cAAc,EAAmB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAkC,mBAAmB,EAAE,sBAAsB;IAOlM,aAAa,CAAc,EAAE,EAAE,MAAM,EAAU,SAAS,EAAE,cAAc,EAAmB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAkC,mBAAmB,EAAE,sBAAsB;IASzM,MAAM,CAAkB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAU,SAAS,EAAE,cAAc,EAAkC,mBAAmB,EAAE,sBAAsB;IAQnK,WAAW,CAAS,GAAG,EAAE,MAAM,EAAE,EAAkC,mBAAmB,EAAE,sBAAsB;;;;IAM9G,OAAO,CAAc,EAAE,EAAE,MAAM,EAAkC,mBAAmB,EAAE,sBAAsB;;;;IAe5G,QAAQ,CAAU,KAAK,EAAE,GAAG,EAAkC,mBAAmB,EAAE,sBAAsB;IAQzG,QAAQ,CAAc,EAAE,EAAE,MAAM,EAAwB,WAAW,EAAE,MAAM,EAAS,GAAG,EAAE,QAAQ,EAAkC,mBAAmB,EAAE,sBAAsB;IAuB9K,OAAO,CAAc,EAAE,EAAE,MAAM,EAAW,KAAK,EAAE,GAAG,EAAkC,mBAAmB,EAAE,sBAAsB;IAMjI,UAAU,CAAS,GAAG,EAAE,MAAM,EAAE,EAAkC,mBAAmB,EAAE,sBAAsB;IAM7G,MAAM,CAAc,EAAE,EAAE,MAAM,EAAkC,mBAAmB,EAAE,sBAAsB;CAKlH"}
1
+ {"version":3,"file":"media.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/media.controller.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAMnC,qBAIa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,YAAY;IAKlD,MAAM,CAAS,SAAS,EAAE,cAAc,EAAmB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAkC,mBAAmB,EAAE,sBAAsB;IAOzK,UAAU,CAAS,UAAU,EAAE,cAAc,EAAE,EAAmB,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAO,EAAkC,mBAAmB,EAAE,sBAAsB;IAQvL,MAAM,CAAc,EAAE,EAAE,MAAM,EAAU,SAAS,EAAE,cAAc,EAAmB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAkC,mBAAmB,EAAE,sBAAsB;IAOlM,aAAa,CAAc,EAAE,EAAE,MAAM,EAAU,SAAS,EAAE,cAAc,EAAmB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAkC,mBAAmB,EAAE,sBAAsB;IASzM,MAAM,CAAkB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAU,SAAS,EAAE,cAAc,EAAkC,mBAAmB,EAAE,sBAAsB;IAQnK,WAAW,CAAS,GAAG,EAAE,MAAM,EAAE,EAAkC,mBAAmB,EAAE,sBAAsB;;;;IAM9G,OAAO,CAAc,EAAE,EAAE,MAAM,EAAkC,mBAAmB,EAAE,sBAAsB;;;;IAe5G,QAAQ,CAAU,KAAK,EAAE,GAAG,EAAkC,mBAAmB,EAAE,sBAAsB;IAQzG,QAAQ,CAAc,EAAE,EAAE,MAAM,EAAwB,WAAW,EAAE,MAAM,EAAS,GAAG,EAAE,QAAQ,EAAkC,mBAAmB,EAAE,sBAAsB;IAsC9K,OAAO,CAAc,EAAE,EAAE,MAAM,EAAW,KAAK,EAAE,GAAG,EAAkC,mBAAmB,EAAE,sBAAsB;IAMjI,UAAU,CAAS,GAAG,EAAE,MAAM,EAAE,EAAkC,mBAAmB,EAAE,sBAAsB;IAM7G,MAAM,CAAc,EAAE,EAAE,MAAM,EAAkC,mBAAmB,EAAE,sBAAsB;CAKlH"}
@@ -58,14 +58,19 @@ let MediaController = class MediaController {
58
58
  async download(id, disposition, res, solidRequestContext) {
59
59
  const media = await this.service.findOne(+id, {}, solidRequestContext);
60
60
  const { stream, fileName, mimeType } = await this.service.fileDownloadStream(media);
61
- const isInlineSafe = media_file_types_1.INLINE_SAFE_EXTENSIONS.has((0, media_file_types_1.getLowercaseFileExtension)(fileName) ?? '');
61
+ const ext = (0, media_file_types_1.getLowercaseFileExtension)(fileName) ?? '';
62
+ const isInlineSafe = media_file_types_1.INLINE_SAFE_EXTENSIONS.has(ext);
62
63
  const requestedInline = disposition !== 'attachment';
64
+ const effectiveMimeType = isInlineSafe ? (media_file_types_1.EXTENSION_TO_MIME_TYPE[ext] ?? mimeType) : 'application/octet-stream';
63
65
  (0, file_download_helper_1.setFileDownloadHeaders)(res, {
64
66
  fileName,
65
- mimeType: isInlineSafe ? mimeType : 'application/octet-stream',
67
+ mimeType: effectiveMimeType,
66
68
  disposition: requestedInline && isInlineSafe ? 'inline' : 'attachment',
67
69
  crossOriginResourcePolicy: true,
68
70
  });
71
+ if (ext === 'svg') {
72
+ res.setHeader("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; img-src data:; sandbox");
73
+ }
69
74
  stream.pipe(res);
70
75
  }
71
76
  async findOne(id, query, solidRequestContext) {
@@ -1 +1 @@
1
- {"version":3,"file":"media.controller.js","sourceRoot":"","sources":["../../src/controllers/media.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query, Res, UploadedFiles, UseInterceptors } from '@nestjs/common';\nimport { AnyFilesInterceptor } from \"@nestjs/platform-express\";\nimport { ApiBearerAuth, ApiQuery, ApiTags } from '@nestjs/swagger';\nimport { Auth } from 'src/decorators/auth.decorator';\nimport { AuthType } from 'src/enums/auth-type.enum';\nimport { CreateMediaDto } from 'src/dtos/create-media.dto';\nimport { SolidRequestContextDecorator } from 'src/decorators/solid-request-context.decorator';\nimport { SolidRequestContextDto } from 'src/dtos/solid-request-context.dto';\nimport { UpdateMediaDto } from 'src/dtos/update-media.dto';\nimport { MediaService } from 'src/services/media.service';\nimport { Response } from 'express';\nimport { getLowercaseFileExtension, INLINE_SAFE_EXTENSIONS } from 'src/constants/media-file-types';\nimport { setFileDownloadHeaders } from 'src/helpers/file-download.helper';\n\nimport { ShowSoftDeleted } from '../enums/show-soft-deleted.enum';\n\n@ApiTags('Solid Core')\n@Controller('media')\n// @UseGuards(ThrottlerGuard)\n// @SkipThrottle({ short: true, login: true, burst: true, sustained: true }) //Skip all\nexport class MediaController {\n constructor(private readonly service: MediaService) {}\n\n @ApiBearerAuth(\"jwt\")\n @Post()\n @UseInterceptors(AnyFilesInterceptor())\n create(@Body() createDto: CreateMediaDto, @UploadedFiles() files: Array<Express.Multer.File>, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.create(createDto, files, solidRequestContext);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Post('/bulk')\n @UseInterceptors(AnyFilesInterceptor())\n insertMany(@Body() createDtos: CreateMediaDto[], @UploadedFiles() filesArray: Express.Multer.File[][] = [], @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.insertMany(createDtos, filesArray, solidRequestContext);\n }\n\n\n @ApiBearerAuth(\"jwt\")\n @Put(':id')\n @UseInterceptors(AnyFilesInterceptor())\n update(@Param('id') id: number, @Body() updateDto: UpdateMediaDto, @UploadedFiles() files: Array<Express.Multer.File>, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.update(id, updateDto, files, false, solidRequestContext);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Patch(':id')\n @UseInterceptors(AnyFilesInterceptor())\n partialUpdate(@Param('id') id: number, @Body() updateDto: UpdateMediaDto, @UploadedFiles() files: Array<Express.Multer.File>, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.update(id, updateDto, files, true, solidRequestContext);\n }\n\n // @Public()\n // @SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only\n @ApiBearerAuth(\"jwt\")\n @Post('/upload')\n @UseInterceptors(AnyFilesInterceptor())\n upload(@UploadedFiles() files: Array<Express.Multer.File>, @Body() createDto: CreateMediaDto, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n // this.logger.log(`Creating a new model: ${JSON.stringify(createDto)}`);\n return this.service.upload(createDto, files, solidRequestContext);\n }\n\n\n @ApiBearerAuth(\"jwt\")\n @Post('/bulk-recover')\n async recoverMany(@Body() ids: number[], @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.recoverMany(ids, solidRequestContext);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Get('/recover/:id')\n async recover(@Param('id') id: number, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.recover(id, solidRequestContext);\n }\n \n @ApiBearerAuth(\"jwt\")\n @ApiQuery({ name: 'showSoftDeleted', required: false, enum: ShowSoftDeleted })\n @ApiQuery({ name: 'limit', required: false, type: Number })\n @ApiQuery({ name: 'offset', required: false, type: Number })\n @ApiQuery({ name: 'fields', required: false, type: Array })\n @ApiQuery({ name: 'sort', required: false, type: Array }) \n @ApiQuery({ name: 'groupBy', required: false, type: Array })\n @ApiQuery({ name: 'populate', required: false, type: Array })\n @ApiQuery({ name: 'populateMedia', required: false, type: Array })\n @ApiQuery({ name: 'filters', required: false, type: Array })\n @Get()\n async findMany(@Query() query: any, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.find(query, solidRequestContext);\n }\n\n @Auth(AuthType.MediaSignedUrl)\n @ApiQuery({ name: 'token', required: true, type: String, description: \"Short-lived signed token obtained from a private Media record's URL - not entered manually.\" })\n @ApiQuery({ name: 'disposition', required: false, enum: ['inline', 'attachment'], description: \"'inline' (default) renders/previews in the browser, matching public media - it applies only to types safe to render inline (images, audio, video, pdf); anything else is always downloaded. Pass 'attachment' to force a browser download (e.g. from a download button).\" })\n @Get(':id/download')\n async download(@Param('id') id: string, @Query('disposition') disposition: string, @Res() res: Response, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n const media = await this.service.findOne(+id, {}, solidRequestContext);\n const { stream, fileName, mimeType } = await this.service.fileDownloadStream(media);\n\n // Mirror the static-serve hardening in SolidCoreModule: only a small allowlist of media\n // types is ever safe to render inline. Anything else is forced to download rather than be\n // displayed/executed, regardless of the mimetype the record was stored with - nosniff\n // alone would not help here, since it faithfully honours a declared text/html.\n const isInlineSafe = INLINE_SAFE_EXTENSIONS.has(getLowercaseFileExtension(fileName) ?? '');\n const requestedInline = disposition !== 'attachment';\n\n setFileDownloadHeaders(res, {\n fileName,\n mimeType: isInlineSafe ? mimeType : 'application/octet-stream',\n disposition: requestedInline && isInlineSafe ? 'inline' : 'attachment',\n crossOriginResourcePolicy: true,\n });\n\n stream.pipe(res);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Get(':id')\n async findOne(@Param('id') id: string, @Query() query: any, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.findOne(+id, query, solidRequestContext);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Delete('/bulk')\n async deleteMany(@Body() ids: number[], @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.deleteMany(ids, solidRequestContext);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Delete(':id')\n async delete(@Param('id') id: number, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.delete(id, solidRequestContext);\n }\n\n\n}\n"]}
1
+ {"version":3,"file":"media.controller.js","sourceRoot":"","sources":["../../src/controllers/media.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query, Res, UploadedFiles, UseInterceptors } from '@nestjs/common';\nimport { AnyFilesInterceptor } from \"@nestjs/platform-express\";\nimport { ApiBearerAuth, ApiQuery, ApiTags } from '@nestjs/swagger';\nimport { Auth } from 'src/decorators/auth.decorator';\nimport { AuthType } from 'src/enums/auth-type.enum';\nimport { CreateMediaDto } from 'src/dtos/create-media.dto';\nimport { SolidRequestContextDecorator } from 'src/decorators/solid-request-context.decorator';\nimport { SolidRequestContextDto } from 'src/dtos/solid-request-context.dto';\nimport { UpdateMediaDto } from 'src/dtos/update-media.dto';\nimport { MediaService } from 'src/services/media.service';\nimport { Response } from 'express';\nimport { EXTENSION_TO_MIME_TYPE, getLowercaseFileExtension, INLINE_SAFE_EXTENSIONS } from 'src/constants/media-file-types';\nimport { setFileDownloadHeaders } from 'src/helpers/file-download.helper';\n\nimport { ShowSoftDeleted } from '../enums/show-soft-deleted.enum';\n\n@ApiTags('Solid Core')\n@Controller('media')\n// @UseGuards(ThrottlerGuard)\n// @SkipThrottle({ short: true, login: true, burst: true, sustained: true }) //Skip all\nexport class MediaController {\n constructor(private readonly service: MediaService) {}\n\n @ApiBearerAuth(\"jwt\")\n @Post()\n @UseInterceptors(AnyFilesInterceptor())\n create(@Body() createDto: CreateMediaDto, @UploadedFiles() files: Array<Express.Multer.File>, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.create(createDto, files, solidRequestContext);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Post('/bulk')\n @UseInterceptors(AnyFilesInterceptor())\n insertMany(@Body() createDtos: CreateMediaDto[], @UploadedFiles() filesArray: Express.Multer.File[][] = [], @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.insertMany(createDtos, filesArray, solidRequestContext);\n }\n\n\n @ApiBearerAuth(\"jwt\")\n @Put(':id')\n @UseInterceptors(AnyFilesInterceptor())\n update(@Param('id') id: number, @Body() updateDto: UpdateMediaDto, @UploadedFiles() files: Array<Express.Multer.File>, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.update(id, updateDto, files, false, solidRequestContext);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Patch(':id')\n @UseInterceptors(AnyFilesInterceptor())\n partialUpdate(@Param('id') id: number, @Body() updateDto: UpdateMediaDto, @UploadedFiles() files: Array<Express.Multer.File>, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.update(id, updateDto, files, true, solidRequestContext);\n }\n\n // @Public()\n // @SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only\n @ApiBearerAuth(\"jwt\")\n @Post('/upload')\n @UseInterceptors(AnyFilesInterceptor())\n upload(@UploadedFiles() files: Array<Express.Multer.File>, @Body() createDto: CreateMediaDto, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n // this.logger.log(`Creating a new model: ${JSON.stringify(createDto)}`);\n return this.service.upload(createDto, files, solidRequestContext);\n }\n\n\n @ApiBearerAuth(\"jwt\")\n @Post('/bulk-recover')\n async recoverMany(@Body() ids: number[], @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.recoverMany(ids, solidRequestContext);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Get('/recover/:id')\n async recover(@Param('id') id: number, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.recover(id, solidRequestContext);\n }\n \n @ApiBearerAuth(\"jwt\")\n @ApiQuery({ name: 'showSoftDeleted', required: false, enum: ShowSoftDeleted })\n @ApiQuery({ name: 'limit', required: false, type: Number })\n @ApiQuery({ name: 'offset', required: false, type: Number })\n @ApiQuery({ name: 'fields', required: false, type: Array })\n @ApiQuery({ name: 'sort', required: false, type: Array }) \n @ApiQuery({ name: 'groupBy', required: false, type: Array })\n @ApiQuery({ name: 'populate', required: false, type: Array })\n @ApiQuery({ name: 'populateMedia', required: false, type: Array })\n @ApiQuery({ name: 'filters', required: false, type: Array })\n @Get()\n async findMany(@Query() query: any, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.find(query, solidRequestContext);\n }\n\n @Auth(AuthType.MediaSignedUrl)\n @ApiQuery({ name: 'token', required: true, type: String, description: \"Short-lived signed token obtained from a private Media record's URL - not entered manually.\" })\n @ApiQuery({ name: 'disposition', required: false, enum: ['inline', 'attachment'], description: \"'inline' (default) renders/previews in the browser, matching public media - it applies only to types safe to render inline (images, audio, video, pdf); anything else is always downloaded. Pass 'attachment' to force a browser download (e.g. from a download button).\" })\n @Get(':id/download')\n async download(@Param('id') id: string, @Query('disposition') disposition: string, @Res() res: Response, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n const media = await this.service.findOne(+id, {}, solidRequestContext);\n const { stream, fileName, mimeType } = await this.service.fileDownloadStream(media);\n\n // Mirror the static-serve hardening in SolidCoreModule: only a small allowlist of media\n // types is ever safe to render inline. Anything else is forced to download rather than be\n // displayed/executed, regardless of the mimetype the record was stored with - nosniff\n // alone would not help here, since it faithfully honours a declared text/html.\n const ext = getLowercaseFileExtension(fileName) ?? '';\n const isInlineSafe = INLINE_SAFE_EXTENSIONS.has(ext);\n const requestedInline = disposition !== 'attachment';\n\n // The served mimetype is derived from the extension rather than trusting the stored\n // mimeType (which is the client-declared Content-Type at upload time, and so is spoofable):\n // a file named logo.png could otherwise have been uploaded with Content-Type: image/svg+xml\n // and stored that way, which would bypass an extension-only check below.\n const effectiveMimeType = isInlineSafe ? (EXTENSION_TO_MIME_TYPE[ext] ?? mimeType) : 'application/octet-stream';\n\n setFileDownloadHeaders(res, {\n fileName,\n mimeType: effectiveMimeType,\n disposition: requestedInline && isInlineSafe ? 'inline' : 'attachment',\n crossOriginResourcePolicy: true,\n });\n\n // See the matching comment in solid-core.module.ts's setHeaders: <img>/CSS never execute\n // svg script, but a direct navigation to this URL would, so pin it to a locked-down\n // document. Keyed on the extension (which now drives effectiveMimeType above too), not on\n // the stored mimeType, so the spoofed-Content-Type case above is covered as well.\n if (ext === 'svg') {\n res.setHeader(\"Content-Security-Policy\", \"default-src 'none'; style-src 'unsafe-inline'; img-src data:; sandbox\");\n }\n\n stream.pipe(res);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Get(':id')\n async findOne(@Param('id') id: string, @Query() query: any, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.findOne(+id, query, solidRequestContext);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Delete('/bulk')\n async deleteMany(@Body() ids: number[], @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.deleteMany(ids, solidRequestContext);\n }\n\n @ApiBearerAuth(\"jwt\")\n @Delete(':id')\n async delete(@Param('id') id: number, @SolidRequestContextDecorator() solidRequestContext: SolidRequestContextDto) {\n return this.service.delete(id, solidRequestContext);\n }\n\n\n}\n"]}
@@ -473,6 +473,16 @@ declare const getSolidCoreSettings: (isProd: boolean) => [{
473
473
  readonly sortOrder: 45;
474
474
  readonly controlType: "numeric";
475
475
  readonly helpText: "Global upload size limit enforced by Multer under every per-field mediaMaxSizeKb restriction. Read-only here: it's applied once at process start, so changing AB_MEDIA_MAX_FILE_SIZE_MB requires an app restart to take effect - editing this in the admin UI would not do that.";
476
+ }, {
477
+ readonly moduleName: "solid-core";
478
+ readonly key: "dangerousExtensions";
479
+ readonly value: string;
480
+ readonly level: SettingLevel.SystemAdminReadonly;
481
+ readonly label: "Blocked Upload Extensions";
482
+ readonly group: "storage-settings";
483
+ readonly sortOrder: 46;
484
+ readonly controlType: "shortText";
485
+ readonly helpText: "File extensions rejected on every upload path, regardless of field configuration. Read-only here: it's applied once at process start. To change it, copy this value into AB_DANGEROUS_EXTENSIONS, edit it, and restart - note that variable REPLACES this list rather than adding to it, so any extension you leave out becomes an accepted upload type.";
476
486
  }, {
477
487
  readonly moduleName: "solid-core";
478
488
  readonly key: "S3_AWS_ACCESS_KEY";
@@ -1880,6 +1890,16 @@ export declare class SolidCoreDefaultSettingsProvider implements ISettingsProvid
1880
1890
  readonly sortOrder: 45;
1881
1891
  readonly controlType: "numeric";
1882
1892
  readonly helpText: "Global upload size limit enforced by Multer under every per-field mediaMaxSizeKb restriction. Read-only here: it's applied once at process start, so changing AB_MEDIA_MAX_FILE_SIZE_MB requires an app restart to take effect - editing this in the admin UI would not do that.";
1893
+ }, {
1894
+ readonly moduleName: "solid-core";
1895
+ readonly key: "dangerousExtensions";
1896
+ readonly value: string;
1897
+ readonly level: SettingLevel.SystemAdminReadonly;
1898
+ readonly label: "Blocked Upload Extensions";
1899
+ readonly group: "storage-settings";
1900
+ readonly sortOrder: 46;
1901
+ readonly controlType: "shortText";
1902
+ readonly helpText: "File extensions rejected on every upload path, regardless of field configuration. Read-only here: it's applied once at process start. To change it, copy this value into AB_DANGEROUS_EXTENSIONS, edit it, and restart - note that variable REPLACES this list rather than adding to it, so any extension you leave out becomes an accepted upload type.";
1883
1903
  }, {
1884
1904
  readonly moduleName: "solid-core";
1885
1905
  readonly key: "S3_AWS_ACCESS_KEY";
@@ -1 +1 @@
1
- {"version":3,"file":"default-settings-provider.service.d.ts","sourceRoot":"","sources":["../../../src/services/settings/default-settings-provider.service.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,iBAAiB,EAEjB,YAAY,EACb,MAAM,gBAAgB,CAAC;AAGxB,eAAO,MAAM,wBAAwB,kBAAkB,CAAC;AACxD,eAAO,MAAM,8BAA8B,wBAAwB,CAAC;AAUpE,QAAA,MAAM,oBAAoB,GAAI,QAAQ,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+kDH,CAAC;AAG3C,MAAM,MAAM,gBAAgB,GAAG,UAAU,CACvC,OAAO,oBAAoB,CAC5B,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;AAGjB,qBAEa,gCAAiC,YAAW,iBAAiB;IACxE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAIZ"}
1
+ {"version":3,"file":"default-settings-provider.service.d.ts","sourceRoot":"","sources":["../../../src/services/settings/default-settings-provider.service.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAIZ"}
@@ -12,6 +12,7 @@ const disallow_in_production_decorator_1 = require("../../decorators/disallow-in
12
12
  const settings_provider_decorator_1 = require("../../decorators/settings-provider.decorator");
13
13
  const interfaces_1 = require("../../interfaces");
14
14
  const theme_registry_1 = require("../../theme/theme-registry");
15
+ const media_file_types_1 = require("../../constants/media-file-types");
15
16
  exports.DEFAULT_MEDIA_UPLOAD_DIR = "media-uploads";
16
17
  exports.DEFAULT_MEDIA_FILE_STORAGE_DIR = "media-files-storage";
17
18
  const timeoutFromEnv = (value, fallback) => {
@@ -538,6 +539,17 @@ const getSolidCoreSettings = (isProd) => [
538
539
  controlType: "numeric",
539
540
  helpText: "Global upload size limit enforced by Multer under every per-field mediaMaxSizeKb restriction. Read-only here: it's applied once at process start, so changing AB_MEDIA_MAX_FILE_SIZE_MB requires an app restart to take effect - editing this in the admin UI would not do that.",
540
541
  },
542
+ {
543
+ moduleName: "solid-core",
544
+ key: "dangerousExtensions",
545
+ value: [...media_file_types_1.DANGEROUS_EXTENSIONS].join(','),
546
+ level: interfaces_1.SettingLevel.SystemAdminReadonly,
547
+ label: "Blocked Upload Extensions",
548
+ group: "storage-settings",
549
+ sortOrder: 46,
550
+ controlType: "shortText",
551
+ helpText: "File extensions rejected on every upload path, regardless of field configuration. Read-only here: it's applied once at process start. To change it, copy this value into AB_DANGEROUS_EXTENSIONS, edit it, and restart - note that variable REPLACES this list rather than adding to it, so any extension you leave out becomes an accepted upload type.",
552
+ },
541
553
  {
542
554
  moduleName: "solid-core",
543
555
  key: "S3_AWS_ACCESS_KEY",