Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Secure paperclip urls only for secure pages

I'm trying to find the best way to make paperclip urls secure, but only for secure pages.

For instance, the homepage, which shows images stored in S3, is http://mydomain.com and the image url is http://s3.amazonaws.com/mydomainphotos/89/thisimage.JPG?1284314856.

I have secure pages like https://mydomain.com/users/my_stuff/49 that has images stored in S3, but the S3 protocol is http and not https, so the user gets a warning from the browser saying that some elements on the page are not secure, blah blah blah.

I know that I can specify :s3_protocol in the model, but this makes everything secure even when it isn't necessary. So, I'm looking for the best way to change the protocol to https on the fly, only for secure pages.

One (probably bad) way would be to create a new url method like:

def custom_url(style = default_style, ssl = false)
  ssl ? self.url(style).gsub('http', 'https') : self.url(style)
end

One thing to note is that I'm using the ssl_requirement plugin, so there might be a way to tie it in with that.

I'm sure there is some simple, standard way to do this that I'm overlooking, but I can't seem to find it.

like image 525
Shagymoe Avatar asked Sep 22 '10 15:09

Shagymoe


2 Answers

If anyone stumbles upon this now: There is a solution in Paperclip since April 2012! Simply write:

Paperclip::Attachment.default_options[:s3_protocol] = ""

in an initializer or use the s3_protocol option inside your model.

Thanks to @Thomas Watson for initiating this.

like image 182
emrass Avatar answered Sep 21 '22 12:09

emrass


If using Rails 2.3.x or newer, you can use Rails middleware to filter the response before sending it back to the user. This way you can detect if the current request is an HTTPS request and modify the calls to s3.amazonaws.com accordingly.

Create a new file called paperclip_s3_url_rewriter.rb and place it inside a directory that's loaded when the server starts. The lib direcotry will work, but many prefer to create an app/middleware directory and add this to the Rails application load path.

Add the following class to the new file:

class PaperclipS3UrlRewriter
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, response = @app.call(env)
    if response.is_a?(ActionController::Response) && response.request.protocol == 'https://' && headers["Content-Type"].include?("text/html")
      body = response.body.gsub('http://s3.amazonaws.com', 'https://s3.amazonaws.com')
      headers["Content-Length"] = body.length.to_s
      [status, headers, body]
    else
      [status, headers, response]
    end
  end
end

Then just register the new middleware:

Rails 2.3.x: Add the line below to environment.rb in the beginning of the Rails::Initializer.run block.
Rails 3.x: Add the line below to application.rb in the beginning of the Application class.

config.middleware.use "PaperclipS3UrlRewriter"

UPDATE:
I just edited my answer and added a check for response.is_a?(ActionController::Response) in the if statement. In some cases (maybe caching related) the response object is an empty array(?) and hence fails when request is called upon it.

UPDATE 2: I edited the Rack/Middleware code example above to also update the Content-Length header. Otherwise the HTML body will be truncated by most browsers.

like image 32
Thomas Watson Avatar answered Sep 20 '22 12:09

Thomas Watson