diff --git a/README.md b/README.md index b48b67c1..6e443d31 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,8 @@ Arguments: * `successActionStatus` - HTTP response status if successful, defaults to 201 * `awsUrl` - [AWS S3 url](http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region). Defaults to `s3.amazonaws.com` * `timeDelta` - Devices time offset from world clock in milliseconds, defaults to 0 + * `sessionToken` - When working w/ Cognito (info below) + * `successActionStatus` - HTTP response status if successful, defaults to 201. Returns an object that wraps an `XMLHttpRequest` instance and behaves like a promise, with the following additional methods: @@ -115,6 +117,10 @@ RNS3.put(file, option) .abort(); ``` +## Cognito + +[Cognito](http://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html) is a service that enables you to create unique identities for your users. If you are using Cognito, you'll need to pass in the session token you received from AWS Security Token Service as the `sessionToken` key in the `options` hash. See the [Cognito](http://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html) and [temporary security credentials](http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html#RequestWithSTS) documentation for more information. + ## TODO - [ ] Support `DeleteObject` and (authenticated) `GetObject` operations. diff --git a/src/S3Policy.js b/src/S3Policy.js index 8132885d..9797f6fe 100644 --- a/src/S3Policy.js +++ b/src/S3Policy.js @@ -62,8 +62,53 @@ export class S3Policy { } } +const getDate = () => { + let date = new Date(); + let yymmdd = date.toISOString().slice(0, 10).replace(/-/g, ""); + let amzDate = yymmdd + "T000000Z"; + return { yymmdd: yymmdd, amzDate: amzDate } +} + +/** + * Expires in 5 minutes. Amazon will reject request + * if it arrives after the expiration date. + * + * returns string in ISO8601 GMT format, i.e. + * + * 2016-03-24T20:43:47.314Z + */ +const getExpirationDate = () => { + return new Date( + (new Date).getTime() + FIVE_MINUTES + ).toISOString(); +} + +const getPolicyParams = (options) => { + let date = getDate(); + let expiration = getExpirationDate(); + let policyParams = { + acl: options.acl || AWS_ACL, + algorithm: AWS_ALGORITHM, + bucket: options.bucket, + contentType: options.contentType, + credential: options.accessKey + "/" + date.yymmdd + "/" + options.region + "/" + AWS_SERVICE_NAME + "/" + AWS_REQUEST_POLICY_VERSION, + date: date, + expiration: expiration, + key: options.key, + region: options.region, + secretKey: options.secretKey, + successActionStatus: '' + (options.successActionStatus || DEFAULT_SUCCESS_ACTION_STATUS) + }; + + if(options.sessionToken) { + policyParams.sessionToken = options.sessionToken; + } + + return policyParams; +} + const formatPolicyForRequestBody = (base64EncodedPolicy, signature, options) => { - return { + let policyForRequestBody = { "key": options.key, "acl": options.acl, "success_action_status": options.successActionStatus, @@ -74,10 +119,16 @@ const formatPolicyForRequestBody = (base64EncodedPolicy, signature, options) => "Policy": base64EncodedPolicy, "X-Amz-Signature": signature, } + + if(options.sessionToken) { + policyForRequestBody['X-Amz-Security-Token'] = options.sessionToken; + } + + return policyForRequestBody; } const formatPolicyForEncoding = (policy) => { - return { + let formattedPolicy = { "expiration": policy.expirationDate, "conditions": [ {"bucket": policy.bucket}, @@ -89,7 +140,13 @@ const formatPolicyForEncoding = (policy) => { {"x-amz-algorithm": policy.algorithm}, {"x-amz-date": policy.amzDate} ] + }; + + if(policy.sessionToken) { + formattedPolicy.conditions.push({'x-amz-security-token': policy.sessionToken}); } + + return formattedPolicy; } const getEncodedPolicy = (policy) => {