This week I had to implement a feature where users would be able to upload files directly to our s3 bucket from their browser.
Among different techniques we decided to upload using POST method with AWS Signature version 4.
The workflow kinda goes like this:
- user goes to our webpage
- select files to upload
- gets a policy and signature for those selected files
- upload directly to s3
We delegated the generation of policy and signature to a serverless function.
Setting Origin
We had setup the policy such a way that after the file upload it’ll redirect to a specific page. We were getting a 403
status since cors
was enabled and the Origin was set to null
!
So, I looked for how to set the Origin to localhost
or something like that. After some digging, I find out you can’t just set the Origin programmatically since it compromises the security.
Turns out we were using webpack-dev-server
for development and we hadn’t set any host name there.
Time drifting
We fixed that Origin issue and next we were getting policy expired error from s3.
s3 requires that the time of the server which is generating the policy syncs with the AWS server.
I was using docker for development environment, and after a little googling I found that the time inside the container might not match the host sometimes. Especially time drifts happen when the host is kept to sleep.
So, I updated the time with ntpdate
from http://pool.ntp.org and turns out it was already in sync with the host machine!
Type inference in JS
So I looked into the policy generating function in our AWS Lambda console. And there was that culprit. I had to set the expiration time, and while doing it I was ‘adding’ integer with a date string! And javascript being a cute language instead of adding as numbers it concatenated as a string.
new Date(Date.now()).toISOString()+EXPIRATION_TIME
-> new Date(Date.now()+EXPIRATION_TIME).toISOString()