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

implement aws sdk v3

https://youtrack.weseek.co.jp/issue/GW-7631
- Remove aws.js
- Remove Expires options in getSignedUrl function param
- Update getSignedUrl, add expiresIn option
I Komang Mudana 4 лет назад
Родитель
Сommit
8c6b240f9e

+ 0 - 234
packages/app/src/server/service/file-uploader/aws.js

@@ -1,234 +0,0 @@
-import loggerFactory from '~/utils/logger';
-
-const logger = loggerFactory('growi:service:fileUploaderAws');
-
-const urljoin = require('url-join');
-const aws = require('aws-sdk');
-
-module.exports = function(crowi) {
-  const Uploader = require('./uploader');
-  const { configManager } = crowi;
-  const lib = new Uploader(crowi);
-
-  function getAwsConfig() {
-    return {
-      accessKeyId: configManager.getConfig('crowi', 'aws:s3AccessKeyId'),
-      secretAccessKey: configManager.getConfig('crowi', 'aws:s3SecretAccessKey'),
-      region: configManager.getConfig('crowi', 'aws:s3Region'),
-      bucket: configManager.getConfig('crowi', 'aws:s3Bucket'),
-      customEndpoint: configManager.getConfig('crowi', 'aws:s3CustomEndpoint'),
-    };
-  }
-
-  function S3Factory() {
-    const awsConfig = getAwsConfig();
-
-    aws.config.update({
-      accessKeyId: awsConfig.accessKeyId,
-      secretAccessKey: awsConfig.secretAccessKey,
-      region: awsConfig.region,
-      s3ForcePathStyle: awsConfig.customEndpoint ? true : undefined,
-    });
-
-    // undefined & null & '' => default endpoint (genuine S3)
-    return new aws.S3({ endpoint: awsConfig.customEndpoint || undefined });
-  }
-
-  function getFilePathOnStorage(attachment) {
-    if (attachment.filePath != null) { // backward compatibility for v3.3.x or below
-      return attachment.filePath;
-    }
-
-    const dirName = (attachment.page != null)
-      ? 'attachment'
-      : 'user';
-    const filePath = urljoin(dirName, attachment.fileName);
-
-    return filePath;
-  }
-
-  async function isFileExists(s3, params) {
-    // check file exists
-    try {
-      await s3.headObject(params).promise();
-    }
-    catch (err) {
-      if (err != null && err.code === 'NotFound') {
-        return false;
-      }
-
-      // error except for 'NotFound
-      throw err;
-    }
-
-    return true;
-  }
-
-  lib.isValidUploadSettings = function() {
-    return this.configManager.getConfig('crowi', 'aws:s3AccessKeyId') != null
-      && this.configManager.getConfig('crowi', 'aws:s3SecretAccessKey') != null
-      && (
-        this.configManager.getConfig('crowi', 'aws:s3Region') != null
-          || this.configManager.getConfig('crowi', 'aws:s3CustomEndpoint') != null
-      )
-      && this.configManager.getConfig('crowi', 'aws:s3Bucket') != null;
-  };
-
-  lib.canRespond = function() {
-    return !this.configManager.getConfig('crowi', 'aws:referenceFileWithRelayMode');
-  };
-
-  lib.respond = async function(res, attachment) {
-    if (!this.getIsUploadable()) {
-      throw new Error('AWS is not configured.');
-    }
-    const temporaryUrl = attachment.getValidTemporaryUrl();
-    if (temporaryUrl != null) {
-      return res.redirect(temporaryUrl);
-    }
-
-    const s3 = S3Factory();
-    const awsConfig = getAwsConfig();
-    const filePath = getFilePathOnStorage(attachment);
-    const lifetimeSecForTemporaryUrl = this.configManager.getConfig('crowi', 'aws:lifetimeSecForTemporaryUrl');
-
-    // issue signed url (default: expires 120 seconds)
-    // https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property
-    const params = {
-      Bucket: awsConfig.bucket,
-      Key: filePath,
-      Expires: lifetimeSecForTemporaryUrl,
-    };
-    const signedUrl = s3.getSignedUrl('getObject', params);
-
-    res.redirect(signedUrl);
-
-    try {
-      return attachment.cashTemporaryUrlByProvideSec(signedUrl, lifetimeSecForTemporaryUrl);
-    }
-    catch (err) {
-      logger.error(err);
-    }
-
-  };
-
-  lib.deleteFile = async function(attachment) {
-    const filePath = getFilePathOnStorage(attachment);
-    return lib.deleteFileByFilePath(filePath);
-  };
-
-  lib.deleteFiles = async function(attachments) {
-    if (!this.getIsUploadable()) {
-      throw new Error('AWS is not configured.');
-    }
-    const s3 = S3Factory();
-    const awsConfig = getAwsConfig();
-
-    const filePaths = attachments.map((attachment) => {
-      return { Key: getFilePathOnStorage(attachment) };
-    });
-
-    const totalParams = {
-      Bucket: awsConfig.bucket,
-      Delete: { Objects: filePaths },
-    };
-    return s3.deleteObjects(totalParams).promise();
-  };
-
-  lib.deleteFileByFilePath = async function(filePath) {
-    if (!this.getIsUploadable()) {
-      throw new Error('AWS is not configured.');
-    }
-    const s3 = S3Factory();
-    const awsConfig = getAwsConfig();
-
-    const params = {
-      Bucket: awsConfig.bucket,
-      Key: filePath,
-    };
-
-    // check file exists
-    const isExists = await isFileExists(s3, params);
-    if (!isExists) {
-      logger.warn(`Any object that relate to the Attachment (${filePath}) does not exist in AWS S3`);
-      return;
-    }
-
-    return s3.deleteObject(params).promise();
-  };
-
-  lib.uploadFile = function(fileStream, attachment) {
-    if (!this.getIsUploadable()) {
-      throw new Error('AWS is not configured.');
-    }
-
-    logger.debug(`File uploading: fileName=${attachment.fileName}`);
-
-    const s3 = S3Factory();
-    const awsConfig = getAwsConfig();
-
-    const filePath = getFilePathOnStorage(attachment);
-    const params = {
-      Bucket: awsConfig.bucket,
-      ContentType: attachment.fileFormat,
-      Key: filePath,
-      Body: fileStream,
-      ACL: 'public-read',
-    };
-
-    return s3.upload(params).promise();
-  };
-
-  /**
-   * Find data substance
-   *
-   * @param {Attachment} attachment
-   * @return {stream.Readable} readable stream
-   */
-  lib.findDeliveryFile = async function(attachment) {
-    if (!this.getIsReadable()) {
-      throw new Error('AWS is not configured.');
-    }
-
-    const s3 = S3Factory();
-    const awsConfig = getAwsConfig();
-    const filePath = getFilePathOnStorage(attachment);
-
-    const params = {
-      Bucket: awsConfig.bucket,
-      Key: filePath,
-    };
-
-    // check file exists
-    const isExists = await isFileExists(s3, params);
-    if (!isExists) {
-      throw new Error(`Any object that relate to the Attachment (${filePath}) does not exist in AWS S3`);
-    }
-
-    let stream;
-    try {
-      stream = s3.getObject(params).createReadStream();
-    }
-    catch (err) {
-      logger.error(err);
-      throw new Error(`Coudn't get file from AWS for the Attachment (${attachment._id.toString()})`);
-    }
-
-    // return stream.Readable
-    return stream;
-  };
-
-  /**
-   * check the file size limit
-   *
-   * In detail, the followings are checked.
-   * - per-file size limit (specified by MAX_FILE_SIZE)
-   */
-  lib.checkLimit = async(uploadFileSize) => {
-    const maxFileSize = crowi.configManager.getConfig('crowi', 'app:maxFileSize');
-    const totalLimit = crowi.configManager.getConfig('crowi', 'app:fileUploadTotalLimit');
-    return lib.doCheckLimit(uploadFileSize, maxFileSize, totalLimit);
-  };
-
-  return lib;
-};

+ 3 - 4
packages/app/src/server/service/file-uploader/aws.ts

@@ -34,7 +34,7 @@ module.exports = (crowi) => {
       region: configManager.getConfig('crowi', 'aws:s3Region'),
       endpoint: configManager.getConfig('crowi', 'aws:s3CustomEndpoint'),
       bucket: configManager.getConfig('crowi', 'aws:s3Bucket'),
-      forcePathStyle: configManager.getConfig('crowi', 'aws:s3Bucket') != null,
+      forcePathStyle: configManager.getConfig('crowi', 'aws:s3CustomEndpoint') != null, // s3ForcePathStyle renamed to forcePathStyle in v3
     };
   };
 
@@ -56,7 +56,7 @@ module.exports = (crowi) => {
     return filePath;
   };
 
-  const isFileExists = async(s3, params) => {
+  const isFileExists = async(s3: S3Client, params) => {
     try {
       await s3.send(new HeadObjectCommand(params));
     }
@@ -102,9 +102,8 @@ module.exports = (crowi) => {
     const params = {
       Bucket: awsConfig.bucket,
       Key: filePath,
-      Expires: lifetimeSecForTemporaryUrl,
     };
-    const signedUrl = await getSignedUrl(s3, new GetObjectCommand(params));
+    const signedUrl = await getSignedUrl(s3, new GetObjectCommand(params), { expiresIn: lifetimeSecForTemporaryUrl });
 
 
     res.redirect(signedUrl);