How to make Carrierwave add random string to the file path? - ruby-on-rails

I have this kind of hot fix:
= image_tag "#{current_candidate.profile.photo_url}?stamp=#{SecureRandom.hex}"
The reason for this is that I made a "crop" feature, and when users recrop their photo - old version gets displayed from browser cache.
Anyway.
This photo_url is called in many places, and rather than making a helper & call it everywhere I thought it would be nice to configure uploader to do that.
Is that possible?
Note: filename can't be random. For other reasons.
I would imagine it has something to do with overriding photo_url method.

Related

Safely filter Active Storage file names?

The Securing Rails Applications rails guide (file uploads section) gives 4 great paragraphs on the dangers of blindly accepting files from users. Some highlights:
If you store file uploads at /var/www/uploads, and the user enters a file name like "../../../etc/passwd", it may overwrite an important file.
It is best to use a permitted list approach, which checks for the validity of a file name with a set of accepted characters. This is opposed to a restricted list approach which attempts to remove not allowed characters.
Suppose the developer has set up Active Storage in a minimal way to work with their application, how would they go about ensuring file names are correctly escaped/sanitized/rejected (open to recommendation on best policy here)
What I know so far
The rails guide shows this code, but gives it only as an example, without much commentary around whether it's best practice or not
def sanitize_filename(filename)
filename.strip.tap do |name|
# NOTE: File.basename doesn't work right with Windows paths on Unix
# get only the filename, not the whole path
name.sub! /\A.*(\\|\/)/, ''
# Finally, replace all non alphanumeric, underscore
# or periods with underscore
name.gsub! /[^\w\.\-]/, '_'
end
end
Is that code sufficient to protect against known file name exploits? Or is there a better way?
Example usage
I don't know exactly how to use the above method.
Suppose we have the following form to submit an image:
<%= f.label "Select one or more images" %>
<%= f.file_field :teacher_images, multiple: true %>
I am not sure exactly how sanitize_filename fits in to this
Its safe to say that it can be expected to be safe against that particular exploit which relies on .. being used to save the file in another directory. However there is no exclusive list of known exploits and it might not protect against potential vulnerabilities which can be specific to whatever backend is actually storing the file.
Like for example a malicious user could overwrite other users uploads if the are all stored in the same directory.
The only way to actually be 100% safe against known and future exploits is to not accept file names from the user and generate them on the server which is done by ActiveStorage.

how to force long URL/text to wrap in table cell when generating PDF in rails?

I am using princely(https://github.com/mbleigh/princely) to generate PDF in rails. I have long url in one table cell. It will extend the margin when I generate the PDF. In html,"word-break: break-all;" works well. But this rule "word-break: break-all;" doesn't work in PDF. Any body have any idea to wrap the long text when generating PDF?
Since princely is converting the ERB to PDF i believe we can use the truncate helper function of rails to make the link shorter.
= link_to truncate("The anchor you want to place", :length => 5), 'http://yoururl'
I was confronted with a similar issues when printing. Aside from the technical problem, you need to ask yourself some design questions: If you were generating a web page, a user would click the link. But if you're generating a PDF, I assume the goal is to print it. In which case, someone needs to type in this long URL.
How likely are the users going to be to type in a long url? If it only makes sense in the context of a live webpage, maybe you want to eliminate that content from the PDF.
If they do need to visit the destination, but they don't need to see the exact URL, then it may make more sense to shorten the URL.
If you want to shorten the URL, you can implement a URL redirection service on your Rails app. I like the following bit of code to generate the short URL code because they are all keyboard-friendly (they don't contain confusing characters, and don't require lots of shifting or switching of keyboards):
def generate_short_murl
a = [('a'..'k'),('m'..'z')].map{|i| i.to_a}.flatten
n = [('2'..'9')].map{|i| i.to_a}.flatten
(0...4).map{ a[rand(a.length)] }.join + (0...3).map{ n[rand(n.length)] }.join
end

How to download image from url and display in view

I am trying to download an image and displaying it in a view in rails.
The reason why I want to download it is because the url contains some api-keys which I am not very fond of giving away.
The solution I have tried thus far is the following:
#Model.rb file
def getUrlMethod
someUrlToAPNGfile = "whatever.png"
file = Tempfile.new(['imageprependname', '.png'], :encoding => "ascii-8bit")
file.write(open(data).read)
return "#{Rails.application.config.action_mailer.default_url_options[:host]}#{file.path}"
end
#This seems to be downloading the image just fine. However the url that is returned does not point to a legal place
Under development I get this URL for the picture: localhost:3000/var/folders/18/94qgts592sq_yq45fnthpzxh0000gn/T/imageprependname20130827-97433-10esqxh.png
That image link does not point anywhere useful.
My theories to what might be wrong is:
The tempfile is deleted before the user can request it
The url points to the wrong place
The url is not a legal route in the routes file
A am currently not aware of any way to fix either of these. Any help?
By the way: I do not need to store the picture after I have displayed it, as it will be changing constantly from the source.
I can think of two options:
First, embed the image directly in the HTML documents, see
http://www.techerator.com/2011/12/how-to-embed-images-directly-into-your-html/
http://webcodertools.com/imagetobase64converter
Second, in the HTML documents, write the image tag as usual:
<img src="/remote_images/show/whatever.png" alt="whatever" />
Then you create a RemoteImages controller to process the requests for images. In the action show, the images will be downloaded and returned with send_data.
You don't have to manage temporary files with both of these options.
You can save the file anywhere in the public folder of the rails application. The right path would be something like this #{Rails.root}/public/myimages/<image_name>.png and then you can refer to it with a URL like this http://localhost:3000/myimages/<image_name>.png. Hope this will help.

How do I replace an attachment in an email with the Rails mail gem?

My program is dealing with emails which arrive as files (something.eml). In some circumstances I need to amend an attachment and then resave the file. I've been using the instructions here as a basis for my code, but there's no suggestion for trying to do exactly what I'd like. The code I have below successfully removes the original attachment and then tries to add in a new one.
#email.without_attachments!
#email.add_file(amended_version)
Unfortunately it goes wrong in two places. Firstly it seems to remove all mime parts, not just attachments. Any text/plain sections are also ditched. Secondly, if I test by reloading my amended .eml file, the attachment is no longer recognised, despite being in the file.
I've included a gist which includes the original and amended files from my current method.
Is there a better way to do this? Perhaps a way of replacing the attachment directly rather than get rid of it and adding again?
I don't know enough about mail formatting to know why this works, but it does.
I extracted just the line I was interested in from the without_attachments! method and it now seems to work fine. The non-attachment parts of the message are kept intact and the message re-reads fine. Code now reads....
#email.parts.delete_if { |p| p.attachment? }
#email.add_file(amended_version)

Using dragonfly with globalize

I'm trying to i18n the image_uid attribute in my model so I can have different images with different languages. I'm using globalize3 and dragonfly.
The problem is that is not working at all. It usually uploads the spanish image (which is the default locale in my app), but it doesn't work with other locales. I don't get any error or trace, it just doesn't work.
The model is quite simple:
image_accessor :image
translates :image_uid
Any idea?
:image_uid is the uniqe id to identify the image and therefore not suitable for translation. But if a :image_name attribute is present Dragonfly uses that as filename.
If you want to have a different image for every language because you e.g insert text, you have to watch out that the name or more precisely the url is always different, e.g. you could append the locale to the url: ?locale=en, or name your files translation.en.jpg. To assign the name you can use the helper methods #model.image.name, .basename, and .ext.
If you want only the filename to change and always have the same image served you need a url rewrite engine and remove the filename before your cache. Otherwise unneeded copies of the same image would be created and waste your disk space and processing power.
Using the rack-rewrite and rack-cache gems it would look something like that:
require 'dragonfly/rails/images'
Rails.application.middleware.insert_before(Rack::Cache, Rack::Rewrite) do
rewrite %r{/media/([^/]+)/[^?]*(.*)}, '/media/$1$2'
end

Resources