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

Merge pull request #7048 from mizozobu/imprv/refactor-tk

Imprv: refactor tk
Haku Mizuki 3 лет назад
Родитель
Сommit
39d958fa37

+ 1 - 0
packages/app/package.json

@@ -112,6 +112,7 @@
     "express-validator": "^6.14.0",
     "express-validator": "^6.14.0",
     "express-webpack-assets": "^0.1.0",
     "express-webpack-assets": "^0.1.0",
     "extensible-custom-error": "^0.0.7",
     "extensible-custom-error": "^0.0.7",
+    "form-data": "^4.0.0",
     "graceful-fs": "^4.1.11",
     "graceful-fs": "^4.1.11",
     "hast-util-select": "^5.0.2",
     "hast-util-select": "^5.0.2",
     "helmet": "^4.6.0",
     "helmet": "^4.6.0",

+ 0 - 3
packages/app/src/server/models/transfer-key.ts

@@ -2,11 +2,8 @@ import { Model, Schema, HydratedDocument } from 'mongoose';
 
 
 import { ITransferKey } from '~/interfaces/transfer-key';
 import { ITransferKey } from '~/interfaces/transfer-key';
 
 
-import loggerFactory from '../../utils/logger';
 import { getOrCreateModel } from '../util/mongoose-utils';
 import { getOrCreateModel } from '../util/mongoose-utils';
 
 
-const logger = loggerFactory('growi:models:transfer-key');
-
 interface ITransferKeyMethods {
 interface ITransferKeyMethods {
   findOneActiveTransferKey(key: string): Promise<HydratedDocument<ITransferKey, ITransferKeyMethods> | null>;
   findOneActiveTransferKey(key: string): Promise<HydratedDocument<ITransferKey, ITransferKeyMethods> | null>;
 }
 }

+ 10 - 21
packages/app/src/server/routes/apiv3/g2g-transfer.ts

@@ -6,7 +6,6 @@ import express, { NextFunction, Request, Router } from 'express';
 import { body } from 'express-validator';
 import { body } from 'express-validator';
 import multer from 'multer';
 import multer from 'multer';
 
 
-import { SupportedAction } from '~/interfaces/activity';
 import GrowiArchiveImportOption from '~/models/admin/growi-archive-import-option';
 import GrowiArchiveImportOption from '~/models/admin/growi-archive-import-option';
 import TransferKeyModel from '~/server/models/transfer-key';
 import TransferKeyModel from '~/server/models/transfer-key';
 import { isG2GTransferError } from '~/server/models/vo/g2g-transfer-error';
 import { isG2GTransferError } from '~/server/models/vo/g2g-transfer-error';
@@ -110,7 +109,7 @@ module.exports = (crowi: Crowi): Router => {
   };
   };
 
 
   // Local middleware to check if key is valid or not
   // Local middleware to check if key is valid or not
-  const verifyAndExtractTransferKey = async(req: Request & { transferKey: TransferKey }, res: ApiV3Response, next: NextFunction) => {
+  const validateTransferKey = async(req: Request, res: ApiV3Response, next: NextFunction) => {
     const key = req.headers[X_GROWI_TRANSFER_KEY_HEADER_NAME];
     const key = req.headers[X_GROWI_TRANSFER_KEY_HEADER_NAME];
 
 
     if (typeof key !== 'string') {
     if (typeof key !== 'string') {
@@ -130,15 +129,6 @@ module.exports = (crowi: Crowi): Router => {
       return res.apiv3Err(new ErrorV3('Transfer key has expired or not found.', 'transfer_key_expired_or_not_found'), 404);
       return res.apiv3Err(new ErrorV3('Transfer key has expired or not found.', 'transfer_key_expired_or_not_found'), 404);
     }
     }
 
 
-    // Inject transferKey to req
-    try {
-      req.transferKey = TransferKey.parse(transferKey.keyString);
-    }
-    catch (err) {
-      logger.error(err);
-      return res.apiv3Err(new ErrorV3('Transfer key is invalid.', 'invalid_transfer_key'), 500);
-    }
-
     next();
     next();
   };
   };
 
 
@@ -147,14 +137,14 @@ module.exports = (crowi: Crowi): Router => {
   const pushRouter = express.Router();
   const pushRouter = express.Router();
 
 
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  receiveRouter.get('/files', verifyAndExtractTransferKey, async(req: Request & { transferKey: TransferKey, operatorUserId: string }, res: ApiV3Response) => {
+  receiveRouter.get('/files', validateTransferKey, async(req: Request, res: ApiV3Response) => {
     const files = await crowi.fileUploadService.listFiles();
     const files = await crowi.fileUploadService.listFiles();
     return res.apiv3({ files });
     return res.apiv3({ files });
   });
   });
 
 
   // Auto import
   // Auto import
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  receiveRouter.post('/', uploads.single('transferDataZipFile'), verifyAndExtractTransferKey, async(req: Request & { transferKey: TransferKey, operatorUserId: string }, res: ApiV3Response) => {
+  receiveRouter.post('/', uploads.single('transferDataZipFile'), validateTransferKey, async(req: Request, res: ApiV3Response) => {
     const { file } = req;
     const { file } = req;
 
 
     const zipFile = importService.getFile(file.filename);
     const zipFile = importService.getFile(file.filename);
@@ -284,8 +274,8 @@ module.exports = (crowi: Crowi): Router => {
   });
   });
 
 
   // This endpoint uses multer's MemoryStorage since the received data should be persisted directly on attachment storage.
   // This endpoint uses multer's MemoryStorage since the received data should be persisted directly on attachment storage.
-  receiveRouter.post('/attachment', uploadsForAttachment.single('content'), verifyAndExtractTransferKey,
-    async(req: Request & { transferKey: TransferKey }, res: ApiV3Response) => {
+  receiveRouter.post('/attachment', uploadsForAttachment.single('content'), validateTransferKey,
+    async(req: Request, res: ApiV3Response) => {
       const { file } = req;
       const { file } = req;
       const { attachmentMetadata } = req.body;
       const { attachmentMetadata } = req.body;
 
 
@@ -312,7 +302,7 @@ module.exports = (crowi: Crowi): Router => {
       return res.apiv3({ message: 'Successfully imported attached file.' });
       return res.apiv3({ message: 'Successfully imported attached file.' });
     });
     });
 
 
-  receiveRouter.get('/growi-info', verifyAndExtractTransferKey, async(req: Request & { transferKey: TransferKey }, res: ApiV3Response) => {
+  receiveRouter.get('/growi-info', validateTransferKey, async(req: Request, res: ApiV3Response) => {
     let growiInfo: IDataGROWIInfo;
     let growiInfo: IDataGROWIInfo;
     try {
     try {
       growiInfo = await g2gTransferReceiverService.answerGROWIInfo();
       growiInfo = await g2gTransferReceiverService.answerGROWIInfo();
@@ -332,12 +322,11 @@ module.exports = (crowi: Crowi): Router => {
 
 
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
   receiveRouter.post('/generate-key', accessTokenParser, adminRequiredIfInstalled, appSiteUrlRequiredIfNotInstalled, async(req: Request, res: ApiV3Response) => {
   receiveRouter.post('/generate-key', accessTokenParser, adminRequiredIfInstalled, appSiteUrlRequiredIfNotInstalled, async(req: Request, res: ApiV3Response) => {
-    const strAppSiteUrl = req.body.appSiteUrl ?? crowi.configManager?.getConfig('crowi', 'app:siteUrl');
+    const appSiteUrl = req.body.appSiteUrl ?? crowi.configManager?.getConfig('crowi', 'app:siteUrl');
 
 
-    // Generate transfer key string
-    let appSiteUrl: URL;
+    let appSiteUrlOrigin: string;
     try {
     try {
-      appSiteUrl = new URL(strAppSiteUrl);
+      appSiteUrlOrigin = new URL(appSiteUrl).origin;
     }
     }
     catch (err) {
     catch (err) {
       logger.error(err);
       logger.error(err);
@@ -347,7 +336,7 @@ module.exports = (crowi: Crowi): Router => {
     // Save TransferKey document
     // Save TransferKey document
     let transferKeyString: string;
     let transferKeyString: string;
     try {
     try {
-      transferKeyString = await g2gTransferReceiverService.createTransferKey(appSiteUrl);
+      transferKeyString = await g2gTransferReceiverService.createTransferKey(appSiteUrlOrigin);
     }
     }
     catch (err) {
     catch (err) {
       logger.error(err);
       logger.error(err);

+ 7 - 16
packages/app/src/server/service/g2g-transfer.ts

@@ -113,12 +113,12 @@ interface Receiver {
   answerGROWIInfo(): Promise<IDataGROWIInfo>
   answerGROWIInfo(): Promise<IDataGROWIInfo>
   /**
   /**
    * DO NOT USE TransferKeyModel.create() directly, instead, use this method to create a TransferKey document.
    * DO NOT USE TransferKeyModel.create() directly, instead, use this method to create a TransferKey document.
-   * This method receives appSiteUrl to create a TransferKey document and returns generated transfer key string.
+   * This method receives appSiteUrlOrigin to create a TransferKey document and returns generated transfer key string.
    * UUID is the same value as the created document's _id.
    * UUID is the same value as the created document's _id.
-   * @param {URL} appSiteUrl URL type appSiteUrl
+   * @param {string} appSiteUrlOrigin GROWI app site URL origin
    * @returns {string} Transfer key string (e.g. http://localhost:3000__grw_internal_tranferkey__<uuid>)
    * @returns {string} Transfer key string (e.g. http://localhost:3000__grw_internal_tranferkey__<uuid>)
    */
    */
-  createTransferKey(appSiteUrl: URL): Promise<string>
+  createTransferKey(appSiteUrlOrigin: string): Promise<string>
   /**
   /**
    * Receive transfer request and import data.
    * Receive transfer request and import data.
    * @param {Readable} zippedGROWIDataStream
    * @param {Readable} zippedGROWIDataStream
@@ -128,10 +128,10 @@ interface Receiver {
 }
 }
 
 
 const generateAxiosRequestConfigWithTransferKey = (tk: TransferKey, additionalHeaders: {[key: string]: string} = {}) => {
 const generateAxiosRequestConfigWithTransferKey = (tk: TransferKey, additionalHeaders: {[key: string]: string} = {}) => {
-  const { appUrl, key } = tk;
+  const { appSiteUrlOrigin, key } = tk;
 
 
   return {
   return {
-    baseURL: appUrl.origin,
+    baseURL: appSiteUrlOrigin,
     headers: {
     headers: {
       ...additionalHeaders,
       ...additionalHeaders,
       [X_GROWI_TRANSFER_KEY_HEADER_NAME]: key,
       [X_GROWI_TRANSFER_KEY_HEADER_NAME]: key,
@@ -502,18 +502,9 @@ export class G2GTransferReceiverService implements Receiver {
     return generateGROWIInfo(this.crowi);
     return generateGROWIInfo(this.crowi);
   }
   }
 
 
-  public async createTransferKey(appSiteUrl: URL): Promise<string> {
+  public async createTransferKey(appSiteUrlOrigin: string): Promise<string> {
     const uuid = new MongooseTypes.ObjectId().toString();
     const uuid = new MongooseTypes.ObjectId().toString();
-
-    // Generate transfer key string
-    let transferKeyString: string;
-    try {
-      transferKeyString = TransferKey.generateKeyString(uuid, appSiteUrl);
-    }
-    catch (err) {
-      logger.error(err);
-      throw err;
-    }
+    const transferKeyString = TransferKey.generateKeyString(uuid, appSiteUrlOrigin);
 
 
     // Save TransferKey document
     // Save TransferKey document
     let tkd;
     let tkd;

+ 12 - 12
packages/app/src/utils/vo/transfer-key.ts

@@ -1,21 +1,21 @@
 /**
 /**
- * VO for TransferKey which has appUrl and key as its public member
+ * VO for TransferKey which has appSiteUrlOrigin and key as its public member
  */
  */
 export class TransferKey {
 export class TransferKey {
 
 
   private static _internalSeperator = '__grw_internal_tranferkey__';
   private static _internalSeperator = '__grw_internal_tranferkey__';
 
 
-  public appUrl: URL;
+  public appSiteUrlOrigin: string;
 
 
   public key: string;
   public key: string;
 
 
-  constructor(appUrl: URL, key: string) {
-    this.appUrl = appUrl;
+  constructor(appSiteUrlOrigin: string, key: string) {
+    this.appSiteUrlOrigin = appSiteUrlOrigin;
     this.key = key;
     this.key = key;
   }
   }
 
 
   get getKeyString(): string {
   get getKeyString(): string {
-    return TransferKey.generateKeyString(this.key, this.appUrl);
+    return TransferKey.generateKeyString(this.key, this.appSiteUrlOrigin);
   }
   }
 
 
   /**
   /**
@@ -32,27 +32,27 @@ export class TransferKey {
       throw Error(generalErrorPhrase);
       throw Error(generalErrorPhrase);
     }
     }
     const key = splitted[0];
     const key = splitted[0];
-    const appUrlString = splitted[1];
+    const appSiteUrl = splitted[1];
 
 
-    let appUrl: URL | null;
+    let appSiteUrlOrigin: string;
     try {
     try {
-      appUrl = new URL(appUrlString);
+      appSiteUrlOrigin = new URL(appSiteUrl).origin;
     }
     }
     catch (e) {
     catch (e) {
       throw Error(generalErrorPhrase + (e as Error));
       throw Error(generalErrorPhrase + (e as Error));
     }
     }
 
 
-    return new TransferKey(appUrl, key);
+    return new TransferKey(appSiteUrlOrigin, key);
   }
   }
 
 
   /**
   /**
    * Generates transfer key string (e.g. https://example.com:8080__grw_internal_tranferkey__key)
    * Generates transfer key string (e.g. https://example.com:8080__grw_internal_tranferkey__key)
    * @param {string} key Key generated by GROWI
    * @param {string} key Key generated by GROWI
-   * @param {URL} appUrl GROWI app site url
+   * @param {string} appSiteUrlOrigin GROWI app site URL origin
    * @returns {string} Transfer key string
    * @returns {string} Transfer key string
    */
    */
-  static generateKeyString(key: string, appUrl: URL): string {
-    return `${key}${TransferKey._internalSeperator}${appUrl.origin}`;
+  static generateKeyString(key: string, appSiteUrlOrigin: string): string {
+    return `${key}${TransferKey._internalSeperator}${appSiteUrlOrigin}`;
   }
   }
 
 
 }
 }

+ 10 - 1
yarn.lock

@@ -7100,7 +7100,7 @@ columnify@^1.5.4:
     strip-ansi "^3.0.0"
     strip-ansi "^3.0.0"
     wcwidth "^1.0.0"
     wcwidth "^1.0.0"
 
 
-combined-stream@^1.0.6, combined-stream@~1.0.6:
+combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
   version "1.0.8"
   version "1.0.8"
   resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
   resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
   integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
   integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
@@ -10563,6 +10563,15 @@ form-data@^2.5.0:
     combined-stream "^1.0.6"
     combined-stream "^1.0.6"
     mime-types "^2.1.12"
     mime-types "^2.1.12"
 
 
+form-data@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+  integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.8"
+    mime-types "^2.1.12"
+
 form-data@~2.3.2:
 form-data@~2.3.2:
   version "2.3.3"
   version "2.3.3"
   resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
   resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"