UNPKG

cloud-presign

Version:

A unified presigned URL generator for multiple cloud platforms

128 lines (112 loc) 4.14 kB
import { BlobServiceClient, StorageSharedKeyCredential, BlobSASPermissions, generateBlobSASQueryParameters } from '@azure/storage-blob'; import { AzureConfig, HttpMethod, PresignOptions, PresignParams, PresignResponse, Provider, } from '../types'; import { Common } from './common'; export class AzureProvider implements Provider { private blobServiceClient: BlobServiceClient; private containerName: string; private accountName: string; private accountKey: string; private defaultExpiration: number; private common = new Common() constructor(config: AzureConfig, defaultExpiration: number) { this.containerName = config.container; this.accountName = config.accountName; this.accountKey = config.accountKey; this.defaultExpiration = defaultExpiration; // Create the BlobServiceClient if (config.connectionString) { this.blobServiceClient = BlobServiceClient.fromConnectionString(config.connectionString); } else { const credential = new StorageSharedKeyCredential(config.accountName, config.accountKey); const blobServiceUri = `https://${config.accountName}.blob.core.windows.net`; this.blobServiceClient = new BlobServiceClient(blobServiceUri, credential); } } async generatePresignedUrl( params: PresignParams, options?: PresignOptions ): Promise<PresignResponse> { const expiration = options?.expiration || this.defaultExpiration; const method = params.method || HttpMethod.GET; let fileName = params.key; let key = params.key; // Create permissions based on HTTP method const permissions = new BlobSASPermissions(); switch (method) { case HttpMethod.GET: permissions.read = true; break; case HttpMethod.PUT: case HttpMethod.POST: permissions.create = true; permissions.write = true; fileName = await this.common.generateFileUniqueName(params.key); key = params.prefix ? `${params.prefix}/${fileName}` : fileName; break; case HttpMethod.DELETE: permissions.delete = true; break; default: throw new Error(`Unsupported HTTP method: ${method}`); } // Set start and expiry time const startDate = new Date(); const expiryDate = new Date(startDate); expiryDate.setSeconds(startDate.getSeconds() + expiration); // Define SAS parameters const sasOptions = { containerName: this.containerName, blobName: key, permissions, startsOn: startDate, expiresOn: expiryDate, }; // Create the shared key credential const sharedKeyCredential = new StorageSharedKeyCredential( this.accountName, this.accountKey ); // Generate the SAS token const sasToken = generateBlobSASQueryParameters( sasOptions, sharedKeyCredential ).toString(); // Construct the full URL const containerClient = this.blobServiceClient.getContainerClient(this.containerName); const blobClient = containerClient.getBlobClient(key); const presignedUrl = `${blobClient.url}?${sasToken}`; const url = blobClient.url.split('?')[0]; // Calculate expiration date const expiresAt = expiryDate.toISOString(); // Build response const response: PresignResponse = { key, presignedUrl, url: params.isPublic ? url : '', method, expiresAt, headers: {}, }; // Add content type header for upload requests if ((method === HttpMethod.PUT || method === HttpMethod.POST) && params.contentType) { response.headers['Content-Type'] = params.contentType; } return response; } async makeFilePublic(key?: string): Promise<void> { const containerClient = this.blobServiceClient.getContainerClient(this.containerName); // Check current access level const properties = await containerClient.getProperties(); if (properties.blobPublicAccess !== 'blob') { // Set container access level to 'blob' (public read access to blobs) await containerClient.setAccessPolicy('blob'); } } }