forked from GEOLYTIX/xyz
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request GEOLYTIX#1698 from AlexanderGeere/minor
API Sign: Change the S3 Provider into a signer
- Loading branch information
Showing
5 changed files
with
201 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,102 +1,35 @@ | ||
/** | ||
@module /provider/s3 | ||
*/ | ||
|
||
const { | ||
S3Client, | ||
PutObjectCommand, | ||
GetObjectCommand, | ||
DeleteObjectCommand, | ||
ListObjectsCommand | ||
} = require('@aws-sdk/client-s3'); | ||
|
||
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner'); | ||
|
||
module.exports = async (req, res) => { | ||
|
||
const credentials = Object.fromEntries(new URLSearchParams(process.env.AWS_S3_CLIENT)) | ||
|
||
const s3Client = new S3Client({ | ||
credentials, | ||
region: req.params.region | ||
}) | ||
|
||
|
||
const commands = { | ||
get, | ||
put, | ||
trash, | ||
list | ||
} | ||
|
||
if (!Object.hasOwn(commands, req.params.command)) { | ||
return res.status(400).send(`S3 command validation failed.`) | ||
} | ||
|
||
return commands[req.params.command](s3Client, req) | ||
} | ||
|
||
async function trash(s3Client, req) { | ||
|
||
const command = new DeleteObjectCommand({ | ||
Key: req.params.key, | ||
Bucket: req.params.bucket | ||
}) | ||
|
||
return s3Client.send(command); | ||
} | ||
|
||
async function get(s3Client, req) { | ||
|
||
try { | ||
|
||
const command = new GetObjectCommand({ | ||
Key: req.params.key, | ||
Bucket: req.params.bucket | ||
}) | ||
|
||
const signedURL = await getSignedUrl(s3Client, command, { | ||
expiresIn: 3600, | ||
}); | ||
|
||
return JSON.stringify(signedURL); | ||
|
||
} catch (err) { | ||
console.error(err) | ||
} | ||
} | ||
|
||
async function put(s3Client, req) { | ||
|
||
try { | ||
|
||
const command = new PutObjectCommand({ | ||
Key: req.params.key, | ||
Bucket: req.params.bucket, | ||
Region: req.params.region | ||
}); | ||
|
||
const signedURL = await getSignedUrl(s3Client, command, { | ||
expiresIn: 3600, | ||
}); | ||
|
||
return JSON.stringify(signedURL); | ||
|
||
} catch (err) { | ||
console.error(err) | ||
} | ||
} | ||
|
||
async function list(s3Client, req) { | ||
|
||
try { | ||
|
||
const command = new ListObjectsCommand({ Bucket: req.params.bucket }) | ||
const response = await s3Client.send(command); | ||
|
||
return response | ||
|
||
} catch (err) { | ||
console.error(err) | ||
} | ||
} | ||
/** | ||
### /provider/s3 | ||
The S3 provider module requires the [S3 signer]{@link module:/sign/s3} and will return a signed request URL. | ||
@requires /sign/s3 | ||
@module /provider/s3 | ||
*/ | ||
|
||
const s3_signer = require('../sign/s3') | ||
|
||
if (!s3_signer) { | ||
|
||
module.exports = null | ||
} else { | ||
|
||
module.exports = s3_provider | ||
} | ||
|
||
/** | ||
@function s3_provider | ||
@description | ||
The s3_provider method returns the s3_signer method. | ||
@param {Object} req HTTP request. | ||
@param {Object} res HTTP response. | ||
@returns {Function} The s3_signer module method. | ||
**/ | ||
async function s3_provider(req, res) { | ||
|
||
return s3_signer(req, res) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
/** | ||
### /sign/s3 | ||
Signs requests to S3. Provides functions for get, list, delete and put to S3. | ||
> For public buckets you do not need to use the s3 sign in order to get or list from the bucket. | ||
> See bellow for examples of how public interactions | ||
The module requires AWS_S3_CLIENT credentials in the process.env and will export as null if the credentials are not provided. The credentials consist of two parts: an access key ID and a secret access key eg: `AWS_S3_CLIENT="accessKeyId=AKIAIOSFODNN7EXAMPLE&secretAccessKey=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"`. [Both the access key ID and secret access key together are required to authenticate your requests]{@link https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html}. | ||
Sample requests for common S3 SDK commands. Please refer to the S3 SDK documentation for detailed information in regards to the Command methods. | ||
```js | ||
let url; // URL to be signed. | ||
// List S3 Bucket | ||
url = `${host}/api/sign/s3?` + mapp.utils.paramString({ | ||
command: 'ListObjectsV2Command', | ||
Bucket, | ||
Region}) | ||
// Get object from S3 Bucket | ||
url = `${host}/api/sign/s3?` + mapp.utils.paramString({ | ||
command: 'GetObjectCommand', | ||
Key, //file name | ||
Bucket, | ||
Region}) | ||
// Get object from S3 Bucket | ||
url = `${host}/api/sign/s3?` + mapp.utils.paramString({ | ||
command: 'PutObjectCommand', | ||
Key, //file name | ||
Bucket, | ||
Region}) | ||
// Get object from S3 Bucket | ||
url = `${host}/api/sign/s3?` + mapp.utils.paramString({ | ||
command: 'DeleteObjectCommand', | ||
Key, //file name | ||
Bucket, | ||
Region}) | ||
// Sign URL | ||
const signedURL = await mapp.utils.xhr({ | ||
url, | ||
responseType: 'text' | ||
}) | ||
// Public Bucket Operations (No credentials needed) | ||
// List bucket contents | ||
url = `https://${Bucket}.s3.${Region}.amazonaws.com?list-type=2` | ||
// Get object | ||
url = `https://${Bucket}.s3.${Region}.amazonaws.com/${Key}` | ||
``` | ||
Note: Write operations (PUT, DELETE) are not available for public buckets. | ||
The aws-sdk/client-s3 and aws-sdk/s3-request-presigner are optional dependencies. The require will fail and the module will export as null if these optional dependencies are not installed. | ||
@requires aws-sdk/client-s3 | ||
@requires aws-sdk/s3-request-presigner | ||
@module /sign/s3 | ||
*/ | ||
|
||
let clientSDK; | ||
let getSignedUrl; | ||
let credentials; | ||
|
||
if (!process.env.AWS_S3_CLIENT) { | ||
|
||
//Assume the bucket is public if no credentials are supplied | ||
console.log('Sign S3: AWS_S3_CLIENT was not found in the env') | ||
|
||
module.exports = null | ||
} else { | ||
|
||
//Attempt import if credentials are found | ||
try { | ||
|
||
// Create credentials object from AWS_S3_CLIENT | ||
credentials = Object.fromEntries(new URLSearchParams(process.env.AWS_S3_CLIENT)) | ||
|
||
// Require will err if installed without optional dependencies. | ||
clientSDK = require('@aws-sdk/client-s3'); | ||
getSignedUrl = require('@aws-sdk/s3-request-presigner').getSignedUrl; | ||
|
||
module.exports = s3_signer | ||
} | ||
catch (err) { | ||
|
||
module.exports = null | ||
} | ||
} | ||
|
||
/** | ||
@function s3_signer | ||
@async | ||
@description | ||
The S3 signer method checks whether the command string parameter exists in the S3 clientSDK. | ||
The provided request params will be spread into the Command object created from the S3 clientSDK. | ||
@param {Object} req HTTP request. | ||
@param {Object} res HTTP response. | ||
@property {Object} req.params Request parameter. | ||
@property {String} params.command S3Client SDK command. | ||
@returns {Promise<String>} The signed url associated to the request params. | ||
**/ | ||
async function s3_signer(req, res) { | ||
|
||
const S3Client = new clientSDK.S3Client({ | ||
credentials, | ||
region: req.params.Region | ||
}) | ||
|
||
if (!Object.hasOwn(clientSDK, req.params.command)) { | ||
return res.status(400).send(`S3 clientSDK command validation failed.`) | ||
} | ||
|
||
// Spread req.params into the clientSDK Command. | ||
const Command = new clientSDK[req.params.command]({ ...req.params }) | ||
|
||
const signedURL = await getSignedUrl( | ||
S3Client, | ||
Command, | ||
{ | ||
expiresIn: 3600, | ||
}); | ||
|
||
return signedURL; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters