Cloudbeam- Simple, Secure Sharing

Cloudbeam’s home page

Recently I built this Rails 6 application, Cloudbeam, with my good friends Kyle Ledoux and Jimmy Zheng. The application also leverages AWS S3 and CloudFront. You can visit Cloudbeam on the web or read on to learn more about this project and how it was built!

About Cloudbeam

Our solution leverages low-impact file storage in the cloud, competent and automatic tracking of file activity, and automated distribution of secure download links, all to make the process of rapidly sharing a large file as safe and simple as possible.

Read on to find out more about the inner workings of the application, some of the challenges we faced when building this app, and how we addressed them.

Direct Uploads with Active Storage

Compared to other file upload solutions in this sphere, Active Storage provides the ability to upload files directly from client to storage solution without requiring the intermediate step of sending the upload files through the application server, which drastically reduces server load, and it does so without requiring the modification of existing models with additional columns, making the adoption of such a setup relatively painless. It does this using only the Rails built-in (as of version 6.1.3) Active Storage module and the aws-sdk-s3 gem, with some additional configuration.

Signed URLs

When the download code is generated, it is given two important security features: an expiration time and strict IP address validation. The expiration time ensures that the signed URL is invalidated by CloudFront after just three minutes. Cloudbeam also captures the IP address of the user requesting the download and will utilize that information as a piece of the signed URL. This means that if the signed URL is passed to a user with a different IP address, access to the content of that signed URL will be denied! We’ve enforced these measures to maintain a high level of security for each download so everyone can share with confidence.

Overriding Default Behavior of Downloaded Content

The solution to this was to dictate that the content should be served as an attachment, and as such, downloaded regardless of underlying file type. Cloudbeam includes the query parameter ’response-content-disposition=attachment;’ as part of each signed URL, in order to dictate that the response should be downloaded as an attachment. It was also necessary to add an additional policy to our CloudFront distribution to instruct that the query string response-content-disposition should be white-listed and forwarded to S3.

Live Updates with ActionCable

To broadcast user-specific live notifications, we had to configure WebSocket to only be sent to a particular session. Cloudbeam makes use of a session controller to set the session[:user_id] for each user, but as Rails does not provide the session variable in connection.rb, we had to ensure that it was manually set again in the session controller in cookies.signed, to make the specific broadcast of Websocket possible.

On the client-side, we needed to make sure that the user was displaying the correct file dashboard page, as the server broadcasts data based on a particular file.

Tracking a file’s current download status

Configuring Mailgun Credentials

In the development environment, we stored the credentials in the encrypted credentials.yml.enc file and referenced the variables stored therein under the development.rb file in our SMTP configuration, like so: user_name: Rails.application.credentials[:mailgun][:username]. This kept the credentials secure and easily accessible during development. As we deployed this app through Heroku, we made use of Heroku's configuration variables to set and access these credentials in our production environment.

Sharing a file ‘foobar’ with the intended recipients

Recurring Rake Tasks with Heroku Scheduler

These tasks are defined in Rails as custom Rake tasks, grouped under relevant namespaces, and run on a predetermined schedule using Heroku’s add-on utility Scheduler. These jobs include removing documents that were uploaded over 30 days prior or have expired (because of the completed download of the file by each document recipient). We also periodically scan the database for unattached files to remove from S3 and the database. These automated jobs keep the environment clean and prevent unused files from taking up space.

Related Resources