UNPKG

nestjs-minio-backend

Version:
178 lines 7.89 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MinioService = void 0; const common_1 = require("@nestjs/common"); const crypto = require("crypto"); const Minio = require("minio"); const constants_1 = require("./constants"); let MinioService = class MinioService { constructor(config) { this.config = config; this.bucketInitialized = false; } async onModuleInit() { this.minioClient = new Minio.Client({ endPoint: this.config.endPoint, port: this.config.port, useSSL: this.config.useSSL, accessKey: this.config.accessKey, secretKey: this.config.secretKey, region: this.config.region, }); await this.initializeBuckets(); } async initializeBuckets() { if (this.bucketInitialized) return; for (const bucket of this.config.buckets.private) { const exists = await this.minioClient.bucketExists(bucket); if (!exists) { await this.minioClient.makeBucket(bucket, this.config.region || 'us-east-1'); await this.minioClient.setBucketPolicy(bucket, JSON.stringify({ Version: '2012-10-17', Statement: [ { Effect: 'Deny', Principal: { AWS: ['*'] }, Action: ['s3:GetObject'], Resource: [`arn:aws:s3:::${bucket}/*`], }, ], })); } } for (const bucket of this.config.buckets.public) { const exists = await this.minioClient.bucketExists(bucket); if (!exists) { await this.minioClient.makeBucket(bucket, this.config.region || 'us-east-1'); await this.minioClient.setBucketPolicy(bucket, JSON.stringify({ Version: '2012-10-17', Statement: [ { Effect: 'Allow', Principal: { AWS: ['*'] }, Action: ['s3:GetObject'], Resource: [`arn:aws:s3:::${bucket}/*`], }, ], })); } } this.bucketInitialized = true; } sha256(data) { return crypto.createHash('sha256').update(data).digest('hex'); } hmacSha256(key, data) { return crypto.createHmac('sha256', key).update(data).digest(); } getSigningKey(secretKey, dateStamp, region, serviceName = 's3') { const kSecret = 'AWS4' + secretKey; const kDate = this.hmacSha256(kSecret, dateStamp); const kRegion = this.hmacSha256(kDate, region); const kService = this.hmacSha256(kRegion, serviceName); const kSigning = this.hmacSha256(kService, 'aws4_request'); return kSigning; } getAmzDate(date) { return date.toISOString().replace(/[:-]|\.\d{3}/g, ''); } getDateStamp(date) { return date.toISOString().slice(0, 10).replace(/-/g, ''); } async calculatePresignedGetUrl(endPoint, bucketName, objectName, expirySeconds) { const accessKey = this.config.accessKey; const secretKey = this.config.secretKey; const region = this.config.region || 'us-east-1'; const externalHost = endPoint; const port = this.config.port; const signingHost = port ? `${externalHost}:${port}` : externalHost; const currentDate = new Date(); const amzDate = this.getAmzDate(currentDate); const dateStamp = this.getDateStamp(currentDate); const credentialScope = `${dateStamp}/${region}/s3/aws4_request`; const canonicalURI = '/' + encodeURIComponent(bucketName) + '/' + objectName .split('/') .map((segment) => encodeURIComponent(segment)) .join('/'); const params = { 'X-Amz-Algorithm': 'AWS4-HMAC-SHA256', 'X-Amz-Credential': `${accessKey}/${credentialScope}`, 'X-Amz-Date': amzDate, 'X-Amz-Expires': expirySeconds.toString(), 'X-Amz-SignedHeaders': 'host', }; const canonicalQueryString = Object.keys(params) .sort() .map((key) => { return `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`; }) .join('&'); const canonicalHeaders = `host:${signingHost.toLowerCase()}\n`; const canonicalRequest = [ 'GET', canonicalURI, canonicalQueryString, canonicalHeaders, 'host', 'UNSIGNED-PAYLOAD', ].join('\n'); const stringToSign = [ 'AWS4-HMAC-SHA256', amzDate, credentialScope, this.sha256(canonicalRequest), ].join('\n'); const signingKey = this.getSigningKey(secretKey, dateStamp, region); const signature = this.hmacSha256(signingKey, stringToSign).toString('hex'); const protocol = (this.config.externalUseSSL ?? this.config.useSSL) ? 'https' : 'http'; const finalUrl = `${protocol}://${signingHost}${canonicalURI}?${canonicalQueryString}&X-Amz-Signature=${signature}`; return finalUrl; } async uploadFile(file, bucketName, objectName) { if (!this.bucketInitialized) { await this.initializeBuckets(); } const fileName = objectName || `${Date.now()}-${file.originalname.replace(/\s/g, '-')}`; await this.minioClient.putObject(bucketName, fileName, file.buffer, file.size, { 'Content-Type': file.mimetype, }); return `${bucketName}/${fileName}`; } async getPresignedUrl(bucketName, objectName) { if (!this.config.buckets.private.includes(bucketName)) { const endpoint = this.config.externalEndPoint || this.config.endPoint; const protocol = (this.config.externalUseSSL ?? this.config.useSSL) ? 'https' : 'http'; return `${protocol}://${endpoint}${this.config.port ? `:${this.config.port}` : ''}/${bucketName}/${objectName}`; } return await this.calculatePresignedGetUrl(this.config.externalEndPoint || this.config.endPoint, bucketName, objectName, (this.config.urlExpiryHours || 1) * 60 * 60); } async deleteFile(bucketName, objectName) { await this.minioClient.removeObject(bucketName, objectName); } getMinioClient() { return this.minioClient; } }; exports.MinioService = MinioService; exports.MinioService = MinioService = __decorate([ (0, common_1.Injectable)(), __param(0, (0, common_1.Inject)(constants_1.MINIO_CONFIG)), __metadata("design:paramtypes", [Object]) ], MinioService); //# sourceMappingURL=minio.service.js.map