Ver Fonte

Change ContentHeaders class constructor to be synchronous and not include configManager

arvid-e há 9 meses atrás
pai
commit
70557279f3

+ 2 - 2
apps/app/src/server/routes/attachment/get.ts

@@ -9,7 +9,7 @@ import mongoose from 'mongoose';
 
 import type { CrowiProperties, CrowiRequest } from '~/interfaces/crowi-request';
 import { ResponseMode, type ExpressHttpHeader, type RespondOptions } from '~/server/interfaces/attachment';
-import type { ConfigManager } from '~/server/service/config-manager';
+import { configManager } from '~/server/service/config-manager';
 import {
   type FileUploader,
   toExpressHttpHeaders, ContentHeaders, applyHeaders,
@@ -112,7 +112,7 @@ const respondForRelayMode = async(crowi: Crowi, res: Response, fileUploadService
     attachment: IAttachmentDocument, opts?: RespondOptions): Promise<void> => {
   // apply content-* headers before response
   const isDownload = opts?.download ?? false;
-  const contentHeaders = await ContentHeaders.create(crowi.configManager as ConfigManager, attachment, { inline: !isDownload });
+  const contentHeaders = new ContentHeaders(attachment, { inline: !isDownload });
   applyHeaders(res, contentHeaders.toExpressHttpHeaders());
 
   try {

+ 2 - 3
apps/app/src/server/service/file-uploader/azure.ts

@@ -24,7 +24,6 @@ import { FilePathOnStoragePrefix, ResponseMode, type RespondOptions } from '~/se
 import type { IAttachmentDocument } from '~/server/models/attachment';
 import loggerFactory from '~/utils/logger';
 
-import type { ConfigManager } from '../config-manager';
 import { configManager } from '../config-manager';
 
 import {
@@ -138,7 +137,7 @@ class AzureFileUploader extends AbstractFileUploader {
     const filePath = getFilePathOnStorage(attachment);
     const containerClient = await getContainerClient();
     const blockBlobClient: BlockBlobClient = containerClient.getBlockBlobClient(filePath);
-    const contentHeaders = await ContentHeaders.create(this.configManager, attachment);
+    const contentHeaders = new ContentHeaders(attachment);
 
     await blockBlobClient.uploadStream(readable, undefined, undefined, {
       blobHTTPHeaders: {
@@ -216,7 +215,7 @@ class AzureFileUploader extends AbstractFileUploader {
       const userDelegationKey = await blobServiceClient.getUserDelegationKey(startsOn, expiresOn);
 
       const isDownload = opts?.download ?? false;
-      const contentHeaders = await ContentHeaders.create(this.configManager, attachment, { inline: !isDownload });
+      const contentHeaders = new ContentHeaders(attachment, { inline: !isDownload });
 
       // https://github.com/Azure/azure-sdk-for-js/blob/d4d55f73/sdk/storage/storage-blob/src/ContainerSASPermissions.ts#L24
       // r:read, a:add, c:create, w:write, d:delete, l:list

+ 0 - 1
apps/app/src/server/service/file-uploader/file-uploader.ts

@@ -9,7 +9,6 @@ import { type RespondOptions, ResponseMode } from '~/server/interfaces/attachmen
 import { Attachment, type IAttachmentDocument } from '~/server/models/attachment';
 import loggerFactory from '~/utils/logger';
 
-import { configManager } from '../config-manager';
 import type { ConfigManager } from '../config-manager';
 
 import type { MultipartUploader } from './multipart-uploader';

+ 3 - 4
apps/app/src/server/service/file-uploader/gcs/index.ts

@@ -4,7 +4,6 @@ import { pipeline } from 'stream/promises';
 import { Storage } from '@google-cloud/storage';
 import { toNonBlankStringOrUndefined } from '@growi/core/dist/interfaces';
 import axios from 'axios';
-import type { Response } from 'express'; // <--- ADD THIS IMPORT for 'Response' type
 import urljoin from 'url-join';
 
 import type Crowi from '~/server/crowi';
@@ -18,7 +17,7 @@ import { configManager } from '../../config-manager';
 import {
   AbstractFileUploader, type TemporaryUrl, type SaveFileParam,
 } from '../file-uploader';
-import { ContentHeaders, applyHeaders } from '../utils';
+import { ContentHeaders } from '../utils';
 
 import { GcsMultipartUploader } from './multipart-uploader';
 
@@ -141,7 +140,7 @@ class GcsFileUploader extends AbstractFileUploader {
     const gcs = getGcsInstance();
     const myBucket = gcs.bucket(getGcsBucket());
     const filePath = getFilePathOnStorage(attachment);
-    const contentHeaders = await ContentHeaders.create(this.configManager, attachment);
+    const contentHeaders = new ContentHeaders(attachment);
     const file = myBucket.file(filePath);
 
     await pipeline(readable, file.createWriteStream({
@@ -202,7 +201,7 @@ class GcsFileUploader extends AbstractFileUploader {
     // issue signed url (default: expires 120 seconds)
     // https://cloud.google.com/storage/docs/access-control/signed-urls
     const isDownload = opts?.download ?? false;
-    const contentHeaders = await ContentHeaders.create(this.configManager, attachment, { inline: !isDownload });
+    const contentHeaders = new ContentHeaders(attachment, { inline: !isDownload });
     const [signedUrl] = await file.getSignedUrl({
       action: 'read',
       expires: Date.now() + lifetimeSecForTemporaryUrl * 1000,

+ 1 - 1
apps/app/src/server/service/file-uploader/gridfs.ts

@@ -65,7 +65,7 @@ class GridfsFileUploader extends AbstractFileUploader {
   override async uploadAttachment(readable: Readable, attachment: IAttachmentDocument): Promise<void> {
     logger.debug(`File uploading: fileName=${attachment.fileName}`);
 
-    const contentHeaders = await ContentHeaders.create(configManager, attachment);
+    const contentHeaders = new ContentHeaders(attachment);
 
     return AttachmentFile.promisifiedWrite(
       {

+ 1 - 1
apps/app/src/server/service/file-uploader/local.ts

@@ -229,7 +229,7 @@ module.exports = function(crowi: Crowi) {
     const internalPath = urljoin(internalPathRoot, relativePath);
 
     const isDownload = opts?.download ?? false;
-    const contentHeaders = await ContentHeaders.create(configManager, attachment, { inline: !isDownload });
+    const contentHeaders = new ContentHeaders(attachment, { inline: !isDownload });
     applyHeaders(res, [
       ...contentHeaders.toExpressHttpHeaders(),
       { field: 'X-Accel-Redirect', value: internalPath },

+ 18 - 31
apps/app/src/server/service/file-uploader/utils/headers.ts

@@ -2,8 +2,8 @@ import type { Response } from 'express';
 
 import type { ExpressHttpHeader, IContentHeaders } from '~/server/interfaces/attachment';
 import type { IAttachmentDocument } from '~/server/models/attachment';
-import type { ConfigManager } from '~/server/service/config-manager';
 
+import { configManager } from '../../config-manager';
 import type { ConfigKey } from '../../config-manager/config-definition';
 
 import { DEFAULT_ALLOWLIST_MIME_TYPES, SAFE_INLINE_CONFIGURABLE_MIME_TYPES } from './security';
@@ -21,37 +21,26 @@ export class ContentHeaders implements IContentHeaders {
 
   xContentTypeOptions?: ExpressHttpHeader<'X-Content-Type-Options'>;
 
-  private configManager: ConfigManager;
-
-  private constructor(configManager: ConfigManager) {
-    this.configManager = configManager;
-  }
-
-  static async create(
-      configManager: ConfigManager,
+  constructor(
       attachment: IAttachmentDocument,
       opts?: {
-      inline?: boolean,
+        inline?: boolean,
     },
-  ): Promise<ContentHeaders> {
-
-    // Create instance, passing the configManager to the private constructor
-    const instance = new ContentHeaders(configManager);
-
+  ) {
     const attachmentContentType = attachment.fileFormat;
     const filename = attachment.originalName;
 
     const actualContentTypeString: string = attachmentContentType || 'application/octet-stream';
 
-    instance.contentType = {
+    this.contentType = {
       field: 'Content-Type',
       value: actualContentTypeString,
     };
 
+    const requestedInline = opts?.inline ?? false;
     const configKey = `attachments:contentDisposition:${actualContentTypeString}:inline` as ConfigKey;
-    const rawConfigValue = await instance.configManager.getConfig(configKey);
 
-    const requestedInline = opts?.inline ?? false;
+    const rawConfigValue = configManager.getConfig(configKey);
 
     let systemAllowsInline: boolean;
 
@@ -72,37 +61,35 @@ export class ContentHeaders implements IContentHeaders {
 
     const shouldBeInline = requestedInline && systemAllowsInline;
 
-    instance.contentDisposition = {
+    this.contentDisposition = {
       field: 'Content-Disposition',
       value: shouldBeInline
         ? 'inline'
         : `attachment;filename*=UTF-8''${encodeURIComponent(filename)}`,
     };
 
-    instance.contentSecurityPolicy = {
+    this.contentSecurityPolicy = {
       field: 'Content-Security-Policy',
-      value: `script-src 'unsafe-hashes';
-          style-src 'self' 'unsafe-inline';
-          object-src 'none';
-          require-trusted-types-for 'script';
-          media-src 'self';
-          default-src 'none';`,
+      value: "script-src 'unsafe-hashes';"
+         + " style-src 'self' 'unsafe-inline';"
+         + " object-src 'none';"
+         + " require-trusted-types-for 'script';"
+         + " media-src 'self';"
+         + " default-src 'none';",
     };
 
-    instance.xContentTypeOptions = {
+    this.xContentTypeOptions = {
       field: 'X-Content-Type-Options',
       value: 'nosniff',
     };
 
     if (attachment.fileSize) {
-      instance.contentLength = {
+      this.contentLength = {
         field: 'Content-Length',
         value: attachment.fileSize.toString(),
       };
     }
-
-    return instance;
-  }
+  } // End of constructor
 
   /**
    * Convert to ExpressHttpHeader[]