Implementing accessed_at to ActiveStorage Blob / Attachment in Ruby on Rails

Pentest Team @greenhats.com
4 min readSep 9, 2023
Overwriting ActiveStorage::Blobs::RedirectController

Ruby on Rails (RoR) is a powerful web application framework known for its simplicity and productivity. In this technical blog post, we’ll explore how to enhance your RoR application by adding an accessed_at column to ActiveStorage Blobs and customizing the ActiveStorage::Blobs::RedirectController. This will allow you to track when someone accesses a specific blob or file, such as through a download action.

Adding the accessed_at column

Make sure that Active Storage is properly installed and initialized.

To start, we need to add an accessed_at column to the active_storage_attachments table. We can achieve this using a Rails migration:

bin/rails generate migration AddAccessedAtToActiveStorageAttachments accessed_at:datetime

Which results in the following code

class AddAccessedAtToActiveStorageAttachments < ActiveRecord::Migration[7.0]
def change
add_column :active_storage_attachments, :accessed_at, :datetime
end
end

This migration adds the necessary column to store the access timestamps.

Customizing the RedirectController

Next, we’ll customize the ActiveStorage::Blobs::RedirectController to update the accessed_at timestamp whenever someone accesses / downloads a file. We do this by calling the touch method on the corresponding Attachment record. First create a file that overwrites the internal Rails controller:

app/controllers/active_storage/blobs/redirect_controller.rb

Then we have to add our code (some parts are copied from the original source code of this controller)

class ActiveStorage::Blobs::RedirectController < ActiveStorage::BaseController
include ActiveStorage::SetBlob
before_action :authenticate # Optional: Add authentication to any active storage blob

def show
# Begin accessed_at modification
attachment = ActiveStorage::Attachment.find_by(blob_id: @blob.id)
attachment.touch(:accessed_at) if attachment
# End accessed_at modification

expires_in ActiveStorage.service_urls_expire_in
redirect_to @blob.url(disposition: params[:disposition]), allow_other_host: true
end

private

def authenticate
# Implement your authentication logic here (in our example we use rodauth)
rodauth.require_account
end
end

With this code, we ensure that the accessed_at timestamp is updated whenever someone accesses a file. Additionally, we've added an optional authentication step using Rodauth to restrict access to authenticated users. Adjust the authenticate method to your authentication requirements.

Displaying the accessed_at Column

To display the accessed_at metadata in a user-friendly way, we utilized the Avo gem — an absolute must have in your RoR project.

Check out on https://avohq.io/

Lets have a look at the default file list view:

This view contains the filename and the file size. Now we need to add our metadata. Specifically, we ejected the view for the File List component with the following command:

bin/rails g avo:eject --component Avo::Fields::Common::Files::ViewType::ListComponent

This command extracts the view files into your Rails application’s directory under app/components/avo/fields/common/files/view_type/

  • list_component.rb
  • list_component.html.erb

In the list_component.html.erb file, we made a simple modification to display the accessed_at timestamp alongside the file name.

Just replace the <%= file.filename %> part with:

<div class="flex flex-col">
<p><%= file.filename %></p>
<p class="text-xs text-gray-400"><%= file.created_at %><%= " (Last access: #{file.accessed_at})" if file.accessed_at? %></p>
</div>

This modification ensures that the creation date is also displayed along with the last access date (if available) in parentheses.

After clicking on the download button of the first file the result is as expected.

Software used

  • Ruby on Rails: 7.0.7.2
  • Ruby: 3.2.0
  • Rodauth: 2.31.0
  • Avo: 3.0.1.beta8

By implementing these steps, you can enhance your RoR application’s functionality by tracking when users access specific files while maintaining optional authentication control. Additionally, you can provide a more informative user interface by displaying relevant metadata. Taking it a step further, you can use the overridden Rails controller to update only specific files or file types.

So, go ahead, rock your RoR projects, and let your code leave a lasting impression! 🚀💎

Thanks for reading,

FLX

https://github.com/FLX-0x00

--

--

Pentest Team @greenhats.com

evait security GmbH (aka pentest team of greenhats): full time white hacking / pentesting company who always stays on bleeding edge - https://www.greenhats.com