From 3f07d79de6454b666a856364d90176e82052e5ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Ib=C3=A1=C3=B1ez?= Date: Mon, 17 Oct 2022 21:43:00 +0200 Subject: [PATCH] Add example for Uppy with S3 and a Node.js server (#4129) Co-authored-by: Merlijn Vos Co-authored-by: Antoine du Hamel --- .eslintrc.js | 2 +- .gitignore | 2 +- CHANGELOG.md | 4 +- examples/aws-nodejs/README.md | 102 ++++++++++++++++++ examples/aws-nodejs/index.js | 53 +++++++++ examples/aws-nodejs/package.json | 17 +++ examples/aws-nodejs/public/drag.html | 85 +++++++++++++++ examples/aws-nodejs/public/index.html | 58 ++++++++++ .../{aws-presigned-url => aws-php}/.gitignore | 0 .../composer.json | 0 .../composer.lock | 0 .../{aws-presigned-url => aws-php}/index.html | 0 .../{aws-presigned-url => aws-php}/main.js | 0 .../package.json | 2 +- .../{aws-presigned-url => aws-php}/readme.md | 6 +- .../s3-sign.php | 0 .../{aws-presigned-url => aws-php}/serve.php | 0 website/src/docs/aws-s3.md | 2 +- yarn.lock | 48 +++++++-- 19 files changed, 366 insertions(+), 15 deletions(-) create mode 100644 examples/aws-nodejs/README.md create mode 100644 examples/aws-nodejs/index.js create mode 100644 examples/aws-nodejs/package.json create mode 100644 examples/aws-nodejs/public/drag.html create mode 100644 examples/aws-nodejs/public/index.html rename examples/{aws-presigned-url => aws-php}/.gitignore (100%) rename examples/{aws-presigned-url => aws-php}/composer.json (100%) rename examples/{aws-presigned-url => aws-php}/composer.lock (100%) rename examples/{aws-presigned-url => aws-php}/index.html (100%) rename examples/{aws-presigned-url => aws-php}/main.js (100%) rename examples/{aws-presigned-url => aws-php}/package.json (90%) rename examples/{aws-presigned-url => aws-php}/readme.md (87%) rename examples/{aws-presigned-url => aws-php}/s3-sign.php (100%) rename examples/{aws-presigned-url => aws-php}/serve.php (100%) diff --git a/.eslintrc.js b/.eslintrc.js index 904d95c17..9d6571198 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -192,7 +192,7 @@ module.exports = { '*.mjs', 'e2e/clients/**/*.js', 'examples/aws-companion/*.js', - 'examples/aws-presigned-url/*.js', + 'examples/aws-php/*.js', 'examples/bundled/*.js', 'examples/custom-provider/client/*.js', 'examples/digitalocean-spaces/*.js', diff --git a/.gitignore b/.gitignore index 9a6c3b85f..4746176b4 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ dist/ lib/ coverage/ examples/dev/bundle.js -examples/aws-presigned-url/vendor/* +examples/aws-php/vendor/* test/endtoend/create-react-app/build/ test/endtoend/create-react-app/coverage/ uppy-*.tgz diff --git a/CHANGELOG.md b/CHANGELOG.md index e4144f8f7..ab44e8d31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -312,7 +312,7 @@ Released: 2022-08-02 - @uppy/transloadit: send `assembly-cancelled` only once (Antoine du Hamel / #3937) - meta: `keepNames` in bundle (Antoine du Hamel / #3926) - meta: e2e: fix Transloadit test suite with Cypress 10 (Antoine du Hamel / #3936) -- meta: Bump guzzlehttp/guzzle from 7.4.1 to 7.4.5 in /examples/aws-presigned-url (dependabot[bot] / #3842) +- meta: Bump guzzlehttp/guzzle from 7.4.1 to 7.4.5 in /examples/aws-php (dependabot[bot] / #3842) - @uppy/tus: fix dependencies (Antoine du Hamel / #3923) - meta: doc: fix linter failure in `image-editor.md` (Antoine du Hamel / #3924) - meta: doc: Fix typo in image-editor.md (Ikko Ashimine / #3921) @@ -841,7 +841,7 @@ Released: 2022-01-10 - @uppy/tus: pause all requests in response to server rate limiting (Antoine du Hamel / #3394) - @uppy/transloadit: better defaults for rate limiting (Antoine du Hamel / #3414) - @uppy/companion: Fix Companion deploys (kiloreux / #3388) -- meta: update aws-presigned-url example to use esm (Antoine du Hamel / #3413) +- meta: update aws-php example to use esm (Antoine du Hamel / #3413) - @uppy/image-editor: namespace input range css (Merlijn Vos / #3406) - @uppy/screen-capture: Add missing option to the screen capture types (Mustafa Navruz / #3400) - @uppy/drag-drop: fix `undefined is not a function` TypeError (Antoine du Hamel / #3397) diff --git a/examples/aws-nodejs/README.md b/examples/aws-nodejs/README.md new file mode 100644 index 000000000..91382f093 --- /dev/null +++ b/examples/aws-nodejs/README.md @@ -0,0 +1,102 @@ +# Uppy + AWS S3 with Node.JS + +A simple and fully working example of Uppy and AWS S3 storage with Node.js (and Express.js) It uses presigned URL at the backend level. + +This README file starts with AWS as this one need to be resolved first. + +# AWS Configuration + +It's assumed that you are familiar with AWS, at least, with the storage service (S3) and users & policies (IAM). + +These instructions are not fit for production but tightening the security is out of the scope here. + +## S3 Setup + +- Create new S3 bucket in AWS (e.g. `aws-nodejs`). +- Add a bucket policy. +```{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "PublicAccess", + "Effect": "Allow", + "Principal": "*", + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::aws-nodejs/*" + } + ] +} +``` + +- Make the S3 bucket public. +- Add CORS configuration. +```[ + { + "AllowedHeaders": [ + "*" + ], + "AllowedMethods": [ + "GET", + "PUT", + "HEAD", + "POST", + "DELETE" + ], + "AllowedOrigins": [ + "*" + ], + "ExposeHeaders": [] + } +] +``` + +## AWS Credentials + +You may use existing AWS credentials or create a new user in the IAM page. + +- Make sure you setup the AWS credentials properly and write down the Access Key ID and Secret Access Key. +- You may configure AWS S3 credentials using [environment variables](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-environment.html) or a [credentials file in `~/.aws/credentials`](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html). +- You will need at least `PutObject` and `PutObjectAcl` permissions. +```{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "VisualEditor0", + "Effect": "Allow", + "Action": [ + "s3:PutObject", + "s3:PutObjectAcl" + ], + "Resource": "arn:aws:s3:::aws-nodejs/*" + } + ] +} +``` +# Install + +Download this code or clone repository into a folder and install dependencies: + +```bash +corepack yarn install +``` + +Add a `.env` file to the root directory and define the S3 bucket name and port variables like the example below: + +``` +S3_BUCKET=aws-nodejs +PORT=8080 +``` + +# Enjoy it + +Start the application: + +```bash +corepack yarn workspace @uppy-example/aws-nodejs start +``` + +Dashboard demo should now be available at http://localhost:8080. + +You have also a Drag & Drop demo on http://localhost:8080/drag. + +*Feel free to check how the demo works and feel free to open an issue.* diff --git a/examples/aws-nodejs/index.js b/examples/aws-nodejs/index.js new file mode 100644 index 000000000..f276492bf --- /dev/null +++ b/examples/aws-nodejs/index.js @@ -0,0 +1,53 @@ +require('dotenv').config({ path: path.join(__dirname, '..', '..', '.env') }) + +const express = require('express') + +const app = express() +const path = require('node:path') + +const port = process.env.PORT +const bodyParser = require('body-parser') + +const aws = require('aws-sdk') + +app.use(bodyParser.json()) + +app.get('/', (req, res) => { + const htmlPath = path.join(__dirname, 'public', 'index.html') + res.sendFile(htmlPath) +}) + +app.get('/drag', (req, res) => { + const htmlPath = path.join(__dirname, 'public', 'drag.html') + res.sendFile(htmlPath) +}) + +app.post('/sign-s3', (req, res) => { + const s3 = new aws.S3() + const fileName = req.body.filename + const { contentType } = req.body + const s3Params = { + Bucket: process.env.S3_BUCKET, + Key: fileName, + Expires: 60, + ContentType: contentType, + ACL: 'public-read', + } + + s3.getSignedUrl('putObject', s3Params, (err, data) => { + if (err) { + console.log(err) + return res.end() + } + const returnData = { + url: data, + method: 'PUT', + } + res.write(JSON.stringify(returnData)) + res.end() + }) +}) + +app.listen(port, () => { + console.log(`Example app listening on port ${port}`) +}) diff --git a/examples/aws-nodejs/package.json b/examples/aws-nodejs/package.json new file mode 100644 index 000000000..e6cbdf957 --- /dev/null +++ b/examples/aws-nodejs/package.json @@ -0,0 +1,17 @@ +{ + "name": "@uppy-example/aws-nodejs", + "version": "1.0.0", + "description": "Uppy for AWS S3 with a custom Node.js backend for signing URLs", + "main": "index.js", + "scripts": { + "start": "node index.js" + }, + "author": "", + "license": "MIT", + "dependencies": { + "aws-sdk": "^2.1038.0", + "body-parser": "^1.20.0", + "dotenv": "^16.0.0", + "express": "^4.18.1" + } +} diff --git a/examples/aws-nodejs/public/drag.html b/examples/aws-nodejs/public/drag.html new file mode 100644 index 000000000..5c0f60d1c --- /dev/null +++ b/examples/aws-nodejs/public/drag.html @@ -0,0 +1,85 @@ + + + + + Uppy + + + +
+
+
+
+
Uploaded files:
+
    +
    + +
    + + diff --git a/examples/aws-nodejs/public/index.html b/examples/aws-nodejs/public/index.html new file mode 100644 index 000000000..fca4263db --- /dev/null +++ b/examples/aws-nodejs/public/index.html @@ -0,0 +1,58 @@ + + + + + Uppy + + + +
    + + + diff --git a/examples/aws-presigned-url/.gitignore b/examples/aws-php/.gitignore similarity index 100% rename from examples/aws-presigned-url/.gitignore rename to examples/aws-php/.gitignore diff --git a/examples/aws-presigned-url/composer.json b/examples/aws-php/composer.json similarity index 100% rename from examples/aws-presigned-url/composer.json rename to examples/aws-php/composer.json diff --git a/examples/aws-presigned-url/composer.lock b/examples/aws-php/composer.lock similarity index 100% rename from examples/aws-presigned-url/composer.lock rename to examples/aws-php/composer.lock diff --git a/examples/aws-presigned-url/index.html b/examples/aws-php/index.html similarity index 100% rename from examples/aws-presigned-url/index.html rename to examples/aws-php/index.html diff --git a/examples/aws-presigned-url/main.js b/examples/aws-php/main.js similarity index 100% rename from examples/aws-presigned-url/main.js rename to examples/aws-php/main.js diff --git a/examples/aws-presigned-url/package.json b/examples/aws-php/package.json similarity index 90% rename from examples/aws-presigned-url/package.json rename to examples/aws-php/package.json index dc8566996..4012a36e5 100644 --- a/examples/aws-presigned-url/package.json +++ b/examples/aws-php/package.json @@ -1,5 +1,5 @@ { - "name": "@uppy-example/aws-presigned-url", + "name": "@uppy-example/aws-php", "version": "0.0.0", "dependencies": { "@uppy/aws-s3": "workspace:*", diff --git a/examples/aws-presigned-url/readme.md b/examples/aws-php/readme.md similarity index 87% rename from examples/aws-presigned-url/readme.md rename to examples/aws-php/readme.md index 990f9fbab..f396b0c54 100644 --- a/examples/aws-presigned-url/readme.md +++ b/examples/aws-php/readme.md @@ -17,7 +17,7 @@ This example also uses the AWS PHP SDK. To install it, [get composer](https://getcomposer.org) and run `composer update` in this folder. ```bash -corepack yarn workspace @uppy-example/aws-presigned-url exec "composer update" +corepack yarn workspace @uppy-example/aws-php exec "composer update" ``` Configure AWS S3 credentials using [environment variables](https://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/credentials.html#environment-credentials) or a [credentials file in `~/.aws/credentials`](https://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/credentials.html#credential-profiles). @@ -26,7 +26,7 @@ Configure a bucket name and region in the `s3-sign.php` file. Then, again in the **repository root**, start this example by doing: ```bash -corepack yarn workspace @uppy-example/aws-presigned-url start +corepack yarn workspace @uppy-example/aws-php start ``` The demo should now be available at http://localhost:8080. @@ -37,5 +37,5 @@ You can use a different S3-compatible service like GCS by configuring that servi AWS_PROFILE="gcs" \ COMPANION_AWS_ENDPOINT="https://storage.googleapis.com" \ COMPANION_AWS_BUCKET="test-bucket-name" \ - corepack yarn run example aws-presigned-url + corepack yarn run example aws-php ``` diff --git a/examples/aws-presigned-url/s3-sign.php b/examples/aws-php/s3-sign.php similarity index 100% rename from examples/aws-presigned-url/s3-sign.php rename to examples/aws-php/s3-sign.php diff --git a/examples/aws-presigned-url/serve.php b/examples/aws-php/serve.php similarity index 100% rename from examples/aws-presigned-url/serve.php rename to examples/aws-php/serve.php diff --git a/website/src/docs/aws-s3.md b/website/src/docs/aws-s3.md index e0bd82c09..abf3c747c 100644 --- a/website/src/docs/aws-s3.md +++ b/website/src/docs/aws-s3.md @@ -347,7 +347,7 @@ uppy.use(AwsS3, { }) ``` -See the [aws-presigned-url example in the uppy repository](https://github.com/transloadit/uppy/tree/main/examples/aws-presigned-url) for a small example that implements both the server-side and the client-side. +See the [aws-php example in the uppy repository](https://github.com/transloadit/uppy/tree/main/examples/aws-php) for a small example that implements both the server-side and the client-side. ### Retrieving presign parameters of the uploaded file diff --git a/yarn.lock b/yarn.lock index 9be7fe01b..9fa8fb830 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6993,8 +6993,8 @@ __metadata: "@types/jasmine@file:./private/@types/jasmine::locator=%40uppy-dev%2Fbuild%40workspace%3A.": version: 0.0.0 - resolution: "@types/jasmine@file:./private/@types/jasmine#./private/@types/jasmine::hash=917119&locator=%40uppy-dev%2Fbuild%40workspace%3A." - checksum: cc86c9a338a6943da64fb636e13bdc8f2e41922ae62c3cfd95525b0a0965a28ecd7545173773f2b61a3c30ae70c8eeb9a725eb71fd9006a07a8733ecbac849b9 + resolution: "@types/jasmine@file:./private/@types/jasmine#./private/@types/jasmine::hash=cf2699&locator=%40uppy-dev%2Fbuild%40workspace%3A." + checksum: f8900f2d42d5c061a69cebc73bc83950095b354964834ab459dbd144a006f4afa0ffc436cfd5c0e74522f5752a7e30d60e1c6c2f69a184f59a749df405a54cdc languageName: node linkType: hard @@ -7007,8 +7007,8 @@ __metadata: "@types/jasminewd2@file:./private/@types/jasmine::locator=%40uppy-dev%2Fbuild%40workspace%3A.": version: 0.0.0 - resolution: "@types/jasminewd2@file:./private/@types/jasmine#./private/@types/jasmine::hash=fe65e0&locator=%40uppy-dev%2Fbuild%40workspace%3A." - checksum: 028a3a54e144661b64d14b439c585db2ade1a22ba4b21de85cb469afd2f1bf5e78079ab3f3e5c058ed4146e7cef5300e27c8d176d9f168222d88576671608135 + resolution: "@types/jasminewd2@file:./private/@types/jasmine#./private/@types/jasmine::hash=17481a&locator=%40uppy-dev%2Fbuild%40workspace%3A." + checksum: ccc420c3ba7580cc562cb093705871265a961bce06bc366365fb32f9f73b276900d07ceb08591e4974bd40f766acc442145e78a70a0cf41a6dc1621999965073 languageName: node linkType: hard @@ -7959,9 +7959,9 @@ __metadata: languageName: unknown linkType: soft -"@uppy-example/aws-presigned-url@workspace:examples/aws-presigned-url": +"@uppy-example/aws-php@workspace:examples/aws-php": version: 0.0.0-use.local - resolution: "@uppy-example/aws-presigned-url@workspace:examples/aws-presigned-url" + resolution: "@uppy-example/aws-php@workspace:examples/aws-php" dependencies: "@uppy/aws-s3": "workspace:*" "@uppy/core": "workspace:*" @@ -8202,6 +8202,17 @@ __metadata: languageName: unknown linkType: soft +"@uppy-example/uppy-s3-example@workspace:examples/uppy-s3-example": + version: 0.0.0-use.local + resolution: "@uppy-example/uppy-s3-example@workspace:examples/uppy-s3-example" + dependencies: + aws-sdk: ^2.1225.0 + body-parser: ^1.20.0 + dotenv: ^16.0.2 + express: ^4.18.1 + languageName: unknown + linkType: soft + "@uppy-example/uppy-with-companion@workspace:examples/uppy-with-companion": version: 0.0.0-use.local resolution: "@uppy-example/uppy-with-companion@workspace:examples/uppy-with-companion" @@ -10774,6 +10785,24 @@ __metadata: languageName: node linkType: hard +"aws-sdk@npm:^2.1225.0": + version: 2.1225.0 + resolution: "aws-sdk@npm:2.1225.0" + dependencies: + buffer: 4.9.2 + events: 1.1.1 + ieee754: 1.1.13 + jmespath: 0.16.0 + querystring: 0.2.0 + sax: 1.2.1 + url: 0.10.3 + util: ^0.12.4 + uuid: 8.0.0 + xml2js: 0.4.19 + checksum: 4483fad82f3cf27540b6beeedbb0c3dd8d8e00751cbd1c7f996bc28822d052879db24b2a646ae1add561112051e0f68705ad77eaa16e13f12d51feb67d8094b1 + languageName: node + linkType: hard + "aws-sign2@npm:~0.7.0": version: 0.7.0 resolution: "aws-sign2@npm:0.7.0" @@ -15033,6 +15062,13 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:^16.0.2": + version: 16.0.3 + resolution: "dotenv@npm:16.0.3" + checksum: afcf03f373d7a6d62c7e9afea6328e62851d627a4e73f2e12d0a8deae1cd375892004f3021883f8aec85932cd2834b091f568ced92b4774625b321db83b827f8 + languageName: node + linkType: hard + "dotenv@npm:^7.0.0": version: 7.0.0 resolution: "dotenv@npm:7.0.0"