You are viewing the preview version of this book
Click here for the full version.

Downloads

Now that the infrastructure is ready, let's turn our focus to the implementation of the file downloads. This is only needed for the deliverable files, as the promo images are accessible publicly via the CloudFront distribution. That means the only operation we'll implement is what happens when the user clicks on the "Download" button.

The file download is an API operation that returns a URL in the response:

/product/{id}/download:
  get:
    # ...
    security:
      - cognito: []
    summary: Download a product
    responses:
      '200':
        description: return the download url
        content:
          application/json:
            schema:
              type: object 
              properties:
                url:
                  type: string
                  format: url
                  example: https://bucket.com/key2
      '403':
        description: If the current user did not buy the product

Notice that the operation is authenticated (security: - cognito: []) and it can return two different responses. The one with the 200 status code is when the user is allowed to download the product in which case the resulting URL grants access to the file. Then the 403 status code means the download is denied.

This distinction is important as access control happens at this point of the download. When the result URL is used, S3 only checks if the signature is not forged and that the Lambda execution role has read access.

Downloads using a signed URL

Backend implementation

In the API handler the first thing is to decide whether the download is allowed or not:

const productToDownload = await (async () => {
  // fetch product
  const product = await ddbClient.send(new GetItemCommand({
    // ...
  }));
  // fetch order
  const order = await ddbClient.send(new GetItemCommand({
    // ...
  }));
  if (order.Item) {
    // user bought the product, allow download
    return unmarshall(product.Item);
  }else {
    if (product.Item.author.S === c.security.cognito.sub) {
      // user is the author, allow download
      return unmarshall(product.Item);
    }
  }
  // deny download
  return null;
})();
if (!productToDownload) {
  return {
    statusCode: 403,
  };
}else {
  // ... sign URL
}

There is more, but you've reached the end of this preview
Read this and all other chapters in full and get lifetime access to:
  • all future updates
  • full web-based access
  • PDF and Epub versions