Skip to content

Commit

Permalink
feat: signed url support
Browse files Browse the repository at this point in the history
  • Loading branch information
appotter committed Jan 31, 2024
1 parent afc8b07 commit 209141a
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 4 deletions.
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@

This is a simple wrapper of [Aws S3](https://github.com/aws/aws-sdk-js) client library for NestJS.

### Installation
### Installation (AWS-SDK V3)

```bash
npm install --save @appotter/nestjs-s3 @aws-sdk/client-s3 @aws-sdk/lib-storage uuid
npm install --save @appotter/nestjs-s3 @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner uuid multer
```

### Installation (AWS-SDK V2) (Not recommended)

```bash
npm install --save @appotter/[email protected] aws-sdk uuid multer
```

### Usage
Expand Down Expand Up @@ -131,6 +137,15 @@ export class YourService {

// Also available with all S3 instance methods
// this.s3Service.getClient().[all-method-of-S3-instance]();

// Signed Url (support V3 only)
async signedUrl(file: string): Promise<string> {
// expires in 1 hour
const signed = await this.s3Service.signedUrl(file, 60*60);

console.log(signed);
// https://test.s3.ap-southeast-1.amazonaws.com/fake.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=test%2F20240131%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=20240131T110201Z&X-Amz-Expires=60&X-Amz-Signature=25875526097b1f0182b27009005e70f9e92cd67294fb60583de9bd0b5f1cc5a7&X-Amz-SignedHeaders=host&x-id=GetObject
}
}
```

Expand Down
64 changes: 64 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"devDependencies": {
"@aws-sdk/client-s3": "^3.502.0",
"@aws-sdk/lib-storage": "^3.502.0",
"@aws-sdk/s3-request-presigner": "^3.503.1",
"@nestjs/common": "^10.3.1",
"@nestjs/config": "^3.1.1",
"@nestjs/core": "^10.3.1",
Expand Down Expand Up @@ -63,9 +64,10 @@
"uuid": "^9.0.1"
},
"peerDependencies": {
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
"@aws-sdk/client-s3": "^3.502.0",
"@aws-sdk/lib-storage": "^3.502.0",
"@aws-sdk/s3-request-presigner": "^3.503.1",
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
"uuid": "^9.0.1"
},
"jest": {
Expand All @@ -82,4 +84,4 @@
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
}
27 changes: 27 additions & 0 deletions src/s3.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ describe('S3Service', () => {
} catch (error) {
expect(error.message).toBe('cannot put a file');
}

expect(Logger.error).toHaveBeenCalled();
});

it('put a file as unique name', async () => {
Expand Down Expand Up @@ -166,6 +168,8 @@ describe('S3Service', () => {
} catch (error) {
expect(error.message).toBe('cannot list all files');
}

expect(Logger.error).toHaveBeenCalled();
});

it('get a file', async () => {
Expand Down Expand Up @@ -198,6 +202,8 @@ describe('S3Service', () => {
} catch (error) {
expect(error.message).toBe('cannot get a file');
}

expect(Logger.error).toHaveBeenCalled();
});

it('delete a file', async () => {
Expand All @@ -223,5 +229,26 @@ describe('S3Service', () => {
} catch (error) {
expect(error.message).toBe('cannot delete a file');
}

expect(Logger.error).toHaveBeenCalled();
});

it('signed url with 60 second', async () => {
const data = await service.signedUrl('fake.png', 60);

expect(data).toContain('X-Amz-Algorithm');
expect(data).toContain('X-Amz-Signature');
});

it('should throws exception if cannot signed url', async () => {
fakeS3Client.on(GetObjectCommand).rejects(new Error('cannot signed url'));

try {
await service.signedUrl('fake.png', 60);
} catch (error) {
console.log(error);

expect(error.message).toBe('cannot signed url');
}
});
});
20 changes: 20 additions & 0 deletions src/s3.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
} from '@aws-sdk/client-s3';
import { Upload } from '@aws-sdk/lib-storage';
import { Readable } from 'stream';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';

@Injectable()
export class S3Service {
Expand Down Expand Up @@ -188,4 +189,23 @@ export class S3Service {
throw error;
}
}

public async signedUrl(key: string, expiresIn: number): Promise<string> {
const objectParams = {
Bucket: this.bucket,
Key: key,
};

try {
return await getSignedUrl(
this.client,
new GetObjectCommand(objectParams),
{ expiresIn },
);
} catch (error) {
Logger.error(error);

throw error;
}
}
}

0 comments on commit 209141a

Please sign in to comment.