aws.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. const logger = require('@alias/logger')('growi:service:fileUploaderAws');
  2. const axios = require('axios');
  3. const urljoin = require('url-join');
  4. const aws = require('aws-sdk');
  5. module.exports = function(crowi) {
  6. const Uploader = require('./uploader');
  7. const { configManager } = crowi;
  8. const lib = new Uploader(configManager);
  9. function getAwsConfig() {
  10. return {
  11. accessKeyId: configManager.getConfig('crowi', 'aws:accessKeyId'),
  12. secretAccessKey: configManager.getConfig('crowi', 'aws:secretAccessKey'),
  13. region: configManager.getConfig('crowi', 'aws:region'),
  14. bucket: configManager.getConfig('crowi', 'aws:bucket'),
  15. customEndpoint: configManager.getConfig('crowi', 'aws:customEndpoint'),
  16. };
  17. }
  18. function S3Factory(isUploadable) {
  19. const awsConfig = getAwsConfig();
  20. if (!isUploadable) {
  21. throw new Error('AWS is not configured.');
  22. }
  23. aws.config.update({
  24. accessKeyId: awsConfig.accessKeyId,
  25. secretAccessKey: awsConfig.secretAccessKey,
  26. region: awsConfig.region,
  27. s3ForcePathStyle: awsConfig.customEndpoint ? true : undefined,
  28. });
  29. // undefined & null & '' => default endpoint (genuine S3)
  30. return new aws.S3({ endpoint: awsConfig.customEndpoint || undefined });
  31. }
  32. function getFilePathOnStorage(attachment) {
  33. if (attachment.filePath != null) { // backward compatibility for v3.3.x or below
  34. return attachment.filePath;
  35. }
  36. const dirName = (attachment.page != null)
  37. ? 'attachment'
  38. : 'user';
  39. const filePath = urljoin(dirName, attachment.fileName);
  40. return filePath;
  41. }
  42. lib.deleteFile = async function(attachment) {
  43. const filePath = getFilePathOnStorage(attachment);
  44. return lib.deleteFileByFilePath(filePath);
  45. };
  46. lib.deleteFileByFilePath = async function(filePath) {
  47. const s3 = S3Factory(this.getIsUploadable());
  48. const awsConfig = getAwsConfig();
  49. const params = {
  50. Bucket: awsConfig.bucket,
  51. Key: filePath,
  52. };
  53. return s3.deleteObject(params).promise();
  54. };
  55. lib.uploadFile = function(fileStream, attachment) {
  56. logger.debug(`File uploading: fileName=${attachment.fileName}`);
  57. const s3 = S3Factory(this.getIsUploadable());
  58. const awsConfig = getAwsConfig();
  59. const filePath = getFilePathOnStorage(attachment);
  60. const params = {
  61. Bucket: awsConfig.bucket,
  62. ContentType: attachment.fileFormat,
  63. Key: filePath,
  64. Body: fileStream,
  65. ACL: 'public-read',
  66. };
  67. return s3.upload(params).promise();
  68. };
  69. /**
  70. * Find data substance
  71. *
  72. * @param {Attachment} attachment
  73. * @return {stream.Readable} readable stream
  74. */
  75. lib.findDeliveryFile = async function(attachment) {
  76. // construct url
  77. const awsConfig = getAwsConfig();
  78. const baseUrl = awsConfig.customEndpoint || `https://${awsConfig.bucket}.s3.amazonaws.com`;
  79. const url = urljoin(baseUrl, getFilePathOnStorage(attachment));
  80. let response;
  81. try {
  82. response = await axios.get(url, { responseType: 'stream' });
  83. }
  84. catch (err) {
  85. logger.error(err);
  86. throw new Error(`Coudn't get file from AWS for the Attachment (${attachment._id.toString()})`);
  87. }
  88. // return stream.Readable
  89. return response.data;
  90. };
  91. /**
  92. * check the file size limit
  93. *
  94. * In detail, the followings are checked.
  95. * - per-file size limit (specified by MAX_FILE_SIZE)
  96. */
  97. lib.checkLimit = async(uploadFileSize) => {
  98. const maxFileSize = crowi.configManager.getConfig('crowi', 'app:maxFileSize');
  99. return { isUploadable: uploadFileSize <= maxFileSize, errorMessage: 'File size exceeds the size limit per file' };
  100. };
  101. return lib;
  102. };