UNPKG

@uppy/aws-s3

Version:

Upload to Amazon S3 with Uppy

143 lines (138 loc) 4.33 kB
import assert from 'node:assert' import { PutObjectCommand, S3Client, UploadPartCommand, } from '@aws-sdk/client-s3' import { getSignedUrl } from '@aws-sdk/s3-request-presigner' import { afterEach, beforeEach, describe, it } from 'vitest' import createSignedURL from './createSignedURL.js' const bucketName = 'some-bucket.with.dots' const s3ClientOptions = { region: 'us-bar-1', credentials: { accessKeyId: 'foo', secretAccessKey: 'bar', sessionToken: 'foobar', }, } const { Date: OriginalDate } = globalThis describe('createSignedURL', () => { beforeEach(() => { const now_ms = OriginalDate.now() // @ts-expect-error we're touching globals for test purposes. // biome-ignore lint/suspicious/noShadowRestrictedNames: ... globalThis.Date = function Date() { if (new.target) { return Reflect.construct(OriginalDate, [now_ms]) } return Reflect.apply(OriginalDate, this, [now_ms]) } globalThis.Date.now = function now() { return now_ms } }) afterEach(() => { globalThis.Date = OriginalDate }) it('should be able to sign non-multipart upload', async () => { const client = new S3Client(s3ClientOptions) assert.strictEqual( ( await createSignedURL({ accountKey: s3ClientOptions.credentials.accessKeyId, accountSecret: s3ClientOptions.credentials.secretAccessKey, sessionToken: s3ClientOptions.credentials.sessionToken, bucketName, Key: 'some/key', Region: s3ClientOptions.region, expires: 900, }) ).searchParams.get('X-Amz-Signature'), new URL( await getSignedUrl( client, new PutObjectCommand({ Bucket: bucketName, Key: 'some/key', }), { expiresIn: 900 }, ), ).searchParams.get('X-Amz-Signature'), ) }) it('should be able to sign multipart upload', async () => { const client = new S3Client(s3ClientOptions) const partNumber = 99 const uploadId = 'dummyUploadId' assert.strictEqual( ( await createSignedURL({ accountKey: s3ClientOptions.credentials.accessKeyId, accountSecret: s3ClientOptions.credentials.secretAccessKey, sessionToken: s3ClientOptions.credentials.sessionToken, uploadId, partNumber, bucketName, Key: 'some/key', Region: s3ClientOptions.region, expires: 900, }) ).searchParams.get('X-Amz-Signature'), new URL( await getSignedUrl( client, new UploadPartCommand({ Bucket: bucketName, UploadId: uploadId, PartNumber: partNumber, Key: 'some/key', }), { expiresIn: 900 }, ), ).searchParams.get('X-Amz-Signature'), ) }) it('should escape path and query as restricted to RFC 3986', async () => { const client = new S3Client(s3ClientOptions) const partNumber = 99 const specialChars = ";?:@&=+$,#!'()" const uploadId = `Upload${specialChars}Id` // '.*' chars of path should be encoded const Key = `${specialChars}.*/${specialChars}.*.ext` const implResult = await createSignedURL({ accountKey: s3ClientOptions.credentials.accessKeyId, accountSecret: s3ClientOptions.credentials.secretAccessKey, sessionToken: s3ClientOptions.credentials.sessionToken, uploadId, partNumber, bucketName, Key, Region: s3ClientOptions.region, expires: 900, }) const sdkResult = new URL( await getSignedUrl( client, new UploadPartCommand({ Bucket: bucketName, UploadId: uploadId, PartNumber: partNumber, Key, }), { expiresIn: 900 }, ), ) assert.strictEqual(implResult.pathname, sdkResult.pathname) const extractUploadId = /([?&])uploadId=([^&]+?)(&|$)/ const extractSignature = /([?&])X-Amz-Signature=([^&]+?)(&|$)/ assert.strictEqual( implResult.search.match(extractUploadId)![2], sdkResult.search.match(extractUploadId)![2], ) assert.strictEqual( implResult.search.match(extractSignature)![2], sdkResult.search.match(extractSignature)![2], ) }) })