Shrine - How to prevent Shrine from auto uploading files prior to validation - Ruby Upload Gem

164 Views Asked by At

This question is for anyone who has experience with the Ruby Gem Shrine for File Uploads.

I am trying to scan file uploads for viruses using ClamAV. The scan works well however the file is already auto uploaded to cloud storage by Shrine prior to validation.

  • Is there a hook/callback in Shrine we can use to run the scan prior to file is uploaded?
  • Is there are an alternative approach?

Here is the code at the moment.

Attacher.validate do
    if file
      tmp_file = file.download
      # raise Services::Clamav::Client::FileContainVirus
      errors << "virus file" if Services::Clamav::Client.virus?(tmp_file.path)
    end
 end

Any thoughts/answers will help. Thank you.

1

There are 1 best solutions below

0
Jan Pokorný On

First, note about uploading files through Shrine. All files first get uploaded to a cache/temporary storage (usually on local filesystem), and are persisted in the final storage only after validations pass. Thus, the validations you run are ran on the cached file, and if a virus (or other validation failure) is detected, it won't be promoted to the permanent storage. You can learn more about how this works in the Shrine Getting Started guide.

However, the documentation demonstrates custom validations like this:

require "streamio-ffmpeg"

class VideoUploader < Shrine
  plugin :add_metadata

  add_metadata :duration do |io|
    movie = Shrine.with_file(io) { |file| FFMPEG::Movie.new(file.path) }
    movie.duration
  end

  Attacher.validate do
    if file.duration > 5*60*60
      errors << "duration must not be longer than 5 hours"
    end
  end
end

The add_metadata blocks are passed an io instance that can be used to read the file stream, or it can be promoted to a file object using Shrine.with_file(io). You could achieve your goal by adding metadata :is_virus? and checking that upon validation. (Note that ClamAV actually supports streaming through clamdscan --stream -, so you can directly use the io instance instead of promoting to a file.)