Просмотр исходного кода

Update to using a default list and a smaller override settings list

arvid-e 8 месяцев назад
Родитель
Сommit
80754e272b

+ 5 - 5
apps/app/src/server/routes/apiv3/content-disposition-settings.ts

@@ -21,7 +21,7 @@ const validator = {
       .bail()
       .matches(/^.+\/.+$/)
       .custom((value) => {
-        const mimeTypeDefaults = configManager.getConfig('attachments:contentDisposition:mimeTypeDefaults');
+        const mimeTypeDefaults = configManager.getConfig('attachments:contentDisposition:mimeTypeOverrides');
         return Object.keys(mimeTypeDefaults).includes(value);
       })
       .withMessage('Invalid or unconfigurable MIME type specified.'),
@@ -73,7 +73,7 @@ module.exports = (crowi) => {
   router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
     try {
 
-      const mimeTypeDefaults = configManager.getConfig('attachments:contentDisposition:mimeTypeDefaults');
+      const mimeTypeDefaults = configManager.getConfig('attachments:contentDisposition:mimeTypeOverrides');
       const contentDispositionSettings: Record<string, 'inline' | 'attachment'> = mimeTypeDefaults;
 
       return res.apiv3({ contentDispositionSettings });
@@ -135,7 +135,7 @@ module.exports = (crowi) => {
       const { disposition } = req.body;
 
       try {
-        const currentMimeTypeDefaults = configManager.getConfig('attachments:contentDisposition:mimeTypeDefaults');
+        const currentMimeTypeDefaults = configManager.getConfig('attachments:contentDisposition:mimeTypeOverrides');
 
         const newDisposition: 'inline' | 'attachment' = disposition;
 
@@ -144,8 +144,8 @@ module.exports = (crowi) => {
           [mimeType]: newDisposition,
         };
 
-        await configManager.updateConfigs({ 'attachments:contentDisposition:mimeTypeDefaults': updatedMimeTypeDefaults });
-        const updatedDispositionFromDb = configManager.getConfig('attachments:contentDisposition:mimeTypeDefaults')[mimeType];
+        await configManager.updateConfigs({ 'attachments:contentDisposition:mimeTypeOverrides': updatedMimeTypeDefaults });
+        const updatedDispositionFromDb = configManager.getConfig('attachments:contentDisposition:mimeTypeOverrides')[mimeType];
 
         const parameters = {
           action: SupportedAction.ACTION_ADMIN_ATTACHMENT_DISPOSITION_UPDATE,

+ 4 - 38
apps/app/src/server/service/config-manager/config-definition.ts

@@ -79,7 +79,7 @@ export const CONFIG_KEYS = [
   'app:openaiVectorStoreFileDeletionCronMaxMinutesUntilRequest',
 
   // Content-Disposition settings for MIME types
-  'attachments:contentDisposition:mimeTypeDefaults',
+  'attachments:contentDisposition:mimeTypeOverrides',
 
   // Security Settings
   'security:wikiMode',
@@ -542,48 +542,14 @@ export const CONFIG_DEFINITIONS = {
   }),
 
   // Attachment Content-Disposition settings
-  'attachments:contentDisposition:mimeTypeDefaults': defineConfig<Record<string, 'inline' | 'attachment'>>({
+  'attachments:contentDisposition:mimeTypeOverrides': defineConfig<Record<string, 'inline' | 'attachment'>>({
     defaultValue: {
-      // Image Types
-      'image/jpeg': 'inline',
-      'image/png': 'inline',
-      'image/gif': 'inline',
-      'image/webp': 'inline',
-      'image/bmp': 'inline',
-      'image/tiff': 'inline',
-      'image/x-icon': 'inline',
-
-      // Document & Media Types
-      'application/pdf': 'inline',
-      'text/plain': 'inline',
-      'video/mp4': 'inline',
-      'video/webm': 'inline',
-      'video/ogg': 'inline',
-      'audio/mpeg': 'inline',
-      'audio/ogg': 'inline',
-      'audio/wav': 'inline',
-
-      // Potentially Dangerous / Executable / Scriptable Types
       'text/html': 'attachment',
-      'text/javascript': 'attachment',
-      'application/javascript': 'attachment',
       'image/svg+xml': 'attachment',
-      'application/xml': 'attachment',
+      'application/pdf': 'attachment',
       'application/json': 'attachment',
-      'application/x-sh': 'attachment',
-      'application/x-msdownload': 'attachment',
-      'application/octet-stream': 'attachment',
-
-      // Other Common Document Formats
-      'application/msword': 'attachment',
-      'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'attachment',
-      'application/vnd.ms-excel': 'attachment',
-      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'attachment',
-      'application/vnd.ms-powerpoint': 'attachment',
-      'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'attachment',
-      'application/zip': 'attachment',
-      'application/x-rar-compressed': 'attachment',
       'text/csv': 'attachment',
+      'font/*': 'attachment',
     },
   }),
 

+ 19 - 11
apps/app/src/server/service/file-uploader/utils/headers.ts

@@ -5,6 +5,8 @@ import type { IAttachmentDocument } from '~/server/models/attachment';
 
 import { configManager } from '../../config-manager';
 
+import { defaultContentDispositionSettings } from './security';
+
 
 export class ContentHeaders implements IContentHeaders {
 
@@ -27,28 +29,34 @@ export class ContentHeaders implements IContentHeaders {
     const attachmentContentType = attachment.fileFormat;
     const filename = attachment.originalName;
 
-    const actualContentTypeString: string = attachmentContentType || 'application/octet-stream';
+    const mimeType: string = attachmentContentType || 'application/octet-stream';
 
     this.contentType = {
       field: 'Content-Type',
-      value: actualContentTypeString,
+      value: mimeType,
     };
 
-    const requestedInline = opts?.inline ?? false;
-    const mimeTypeDefaults = configManager.getConfig('attachments:contentDisposition:mimeTypeDefaults') as Record<string, 'inline' | 'attachment'>;
+    let finalDispositionValue: string;
 
-    let systemAllowsInline: boolean;
-    const defaultDispositionForType = mimeTypeDefaults[actualContentTypeString];
+    const requestedInline = opts?.inline ?? false;
+    const mimeTypeOverrides = configManager.getConfig('attachments:contentDisposition:mimeTypeOverrides');
+    const overrideSetting = mimeTypeOverrides[mimeType];
 
-    if (defaultDispositionForType === 'inline') {
-      systemAllowsInline = true;
+    if (overrideSetting) {
+      finalDispositionValue = overrideSetting;
     }
+
     else {
-      systemAllowsInline = false;
+      const defaultSetting = defaultContentDispositionSettings[mimeType];
+
+      if (defaultSetting === 'inline' && requestedInline) {
+        finalDispositionValue = 'inline';
+      }
+      else {
+        finalDispositionValue = 'attachment';
+      }
     }
 
-    // Determine the final disposition based on user request and system allowance
-    const finalDispositionValue: 'inline' | 'attachment' = (requestedInline && systemAllowsInline) ? 'inline' : 'attachment';
 
     this.contentDisposition = {
       field: 'Content-Disposition',

+ 42 - 0
apps/app/src/server/service/file-uploader/utils/security.ts

@@ -0,0 +1,42 @@
+export const defaultContentDispositionSettings = {
+  // Image Types
+  'image/jpeg': 'inline',
+  'image/png': 'inline',
+  'image/gif': 'inline',
+  'image/webp': 'inline',
+  'image/bmp': 'inline',
+  'image/tiff': 'inline',
+  'image/x-icon': 'inline',
+
+  // Document & Media Types
+  'application/pdf': 'inline',
+  'text/plain': 'inline',
+  'video/mp4': 'inline',
+  'video/webm': 'inline',
+  'video/ogg': 'inline',
+  'audio/mpeg': 'inline',
+  'audio/ogg': 'inline',
+  'audio/wav': 'inline',
+
+  // Potentially Dangerous / Executable / Scriptable Types
+  'text/html': 'attachment',
+  'text/javascript': 'attachment',
+  'application/javascript': 'attachment',
+  'image/svg+xml': 'attachment',
+  'application/xml': 'attachment',
+  'application/json': 'attachment',
+  'application/x-sh': 'attachment',
+  'application/x-msdownload': 'attachment',
+  'application/octet-stream': 'attachment',
+
+  // Other Common Document Formats
+  'application/msword': 'attachment',
+  'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'attachment',
+  'application/vnd.ms-excel': 'attachment',
+  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'attachment',
+  'application/vnd.ms-powerpoint': 'attachment',
+  'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'attachment',
+  'application/zip': 'attachment',
+  'application/x-rar-compressed': 'attachment',
+  'text/csv': 'attachment',
+};

+ 33 - 0
apps/app/src/services/renderer/rehype-plugins/add-inline-code-property.ts

@@ -0,0 +1,33 @@
+import type { Element, Root } from 'hast';
+import type { Plugin } from 'unified';
+import { is } from 'unist-util-is';
+import { visitParents } from 'unist-util-visit-parents';
+
+const isInlineCodeTag = (node: Element, parent: Element | Root | null): boolean => {
+  if (node.tagName !== 'code') {
+    return false;
+  }
+
+  if (parent && is(parent, { type: 'element', tagName: 'pre' })) {
+    return false;
+  }
+
+  return true;
+};
+
+export const rehypePlugin: Plugin = () => {
+  return (tree) => {
+    visitParents(tree, 'element', (node: Element, ancestors) => {
+      // The immediate parent is the last item in the ancestors array
+      const parent = ancestors[ancestors.length - 1] || null;
+
+      // Check if the current element is an inline <code> tag
+      if (isInlineCodeTag(node, parent)) {
+        node.properties = {
+          ...node.properties,
+          inline: true,
+        };
+      }
+    });
+  };
+};