GithubHelp home page GithubHelp logo

imgproxy / imgproxy.rb Goto Github PK

View Code? Open in Web Editor NEW
186.0 186.0 27.0 267 KB

Framework-agnostic Ruby Gem for imgproxy with support for Ruby on Rails' most popular image attachment options

Home Page: https://imgproxy.net

License: MIT License

Ruby 100.00%

imgproxy.rb's Introduction

imgproxy logo

GH Test GH Lint Docker Pulls


imgproxy is a fast and secure standalone server for resizing, processing, and converting images. The guiding principles behind imgproxy are security, speed, and simplicity.

imgproxy is able to quickly and easily resize images on the fly, and it's well-equipped to handle a large amount of image resizing. imgproxy is a fast, secure replacement for all the image resizing code inside your web application (such as resizing libraries, or code that calls ImageMagick or GraphicsMagic). It's also an indispensable tool for processing images from a remote source. With imgproxy, you don’t need to repeatedly prepare images to fit your design every time it changes.

To get an even better introduction, and to dive deeper into the nitty gritty details, check out this article: imgproxy: Resize your images instantly and securely

Simplicity

"No code is better than no code."

imgproxy only includes the must-have features for image processing, fine-tuning, and security. Specifically,

  • It would be great to be able to flip images, apply masks, or round corners, but in most cases, it is possible — and is much easier — to do that using CSS.
  • It may be great to have built-in HTTP caching of some kind, but it is way better to use a Content-Delivery Network or a caching proxy server for this, as you will have to do this sooner or later in the production environment.
  • It might be useful to have everything built in — such as HTTPS support — but, again, an easy way to solve that would be just to use a proxying HTTP server, a load balancer, or a CDN.

Speed

imgproxy takes advantage of probably the most efficient image processing library out there – libvips. It’s scary fast and comes with a very low memory footprint. Thanks to libvips, we can readily and extemporaneously process a massive amount of images.

imgproxy uses Go’s raw (no wrappers) native net/http package to omit any overhead while processing requests and provides the best possible HTTP support.

You can take a look at some benchmarking results and compare imgproxy with some well-known alternatives in our benchmark report.

Security

In terms of security, the massive processing of remote images is a potentially dangerous endeavor. There are a number of possible attack vectors, so it’s a good idea to take an approach that considers attack prevention measures as a priority. Here’s how imgproxy does this:

  • imgproxy checks the image type and its “real” dimensions when downloading. The image will not be fully downloaded if it has an unknown format or if the dimensions are too big (you can set the max allowed dimensions). This is how imgproxy protects from so-called "image bombs”, like those described in this doc.

  • imgproxy protects image URLs with a signature, so an attacker cannot enact a denial-of-service attack by requesting multiple image resizes.

  • imgproxy supports authorization by HTTP header. This prevents imgproxy from being used directly by an attacker but allows it to be used via a CDN or a caching server — simply by adding a header to a proxy or CDN config.

Usage

Check out our 📑 Documentation.

Author

Sergey "DarthSim" Alexandrovich

Special thanks

Many thanks to:

License

imgproxy is licensed under the MIT license.

See LICENSE for the full license text.

Security Contact

To report a security vulnerability, please contact us at [email protected]. We will coordinate the fix and disclosure.

imgproxy.rb's People

Contributors

danielwestendorf avatar darthsim avatar dependabot-preview[bot] avatar dependabot[bot] avatar gauravtiwari avatar gazay avatar holamendi avatar jnunemaker avatar marckohlbrugge avatar mrexox avatar palkan avatar ross-hunter avatar viktorzimmermann avatar wilg avatar yaroslav avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

imgproxy.rb's Issues

shrine compatibility?

The docs say this gem is compatible with shrine but I get this error in a rails 6.1.5 app, using ruby 2.7.2 and shrine 3. If I remove imgproxy.rb works as normal. If I downgrade imgproxy works fine. But if I have the latest of imgproxy.rb rails s crashes with the error below.

/Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/anyway_config-2.3.0/lib/anyway/type_casting.rb:111: warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!
/Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/anyway_config-2.3.0/lib/anyway/rbs.rb:40: warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!
Traceback (most recent call last):
	32: from bin/rails:4:in `<main>'
	31: from bin/rails:4:in `require'
	30: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/railties-6.1.5/lib/rails/commands.rb:18:in `<top (required)>'
	29: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/railties-6.1.5/lib/rails/command.rb:48:in `invoke'
	28: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/railties-6.1.5/lib/rails/command/base.rb:69:in `perform'
	27: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch'
	26: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command'
	25: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/thor-1.2.1/lib/thor/command.rb:27:in `run'
	24: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/railties-6.1.5/lib/rails/commands/server/server_command.rb:135:in `perform'
	23: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/railties-6.1.5/lib/rails/commands/server/server_command.rb:135:in `tap'
	22: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/railties-6.1.5/lib/rails/commands/server/server_command.rb:138:in `block in perform'
	21: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/activesupport-6.1.5/lib/active_support/dependencies.rb:332:in `require'
	20: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/activesupport-6.1.5/lib/active_support/dependencies.rb:299:in `load_dependency'
	19: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/activesupport-6.1.5/lib/active_support/dependencies.rb:332:in `block in require'
	18: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/activesupport-6.1.5/lib/active_support/dependencies.rb:332:in `require'
	17: from /Users/pnovess/Projects/designious-api/config/application.rb:20:in `<top (required)>'
	16: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/bundler-2.2.19/lib/bundler.rb:174:in `require'
	15: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/bundler-2.2.19/lib/bundler/runtime.rb:50:in `require'
	14: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/bundler-2.2.19/lib/bundler/runtime.rb:50:in `each'
	13: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/bundler-2.2.19/lib/bundler/runtime.rb:61:in `block in require'
	12: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/bundler-2.2.19/lib/bundler/runtime.rb:61:in `each'
	11: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/bundler-2.2.19/lib/bundler/runtime.rb:66:in `block (2 levels) in require'
	10: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/bundler-2.2.19/lib/bundler/runtime.rb:66:in `require'
	 9: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/imgproxy-2.0.1/lib/imgproxy.rb:149:in `<top (required)>'
	 8: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/imgproxy-2.0.1/lib/imgproxy.rb:143:in `extend_shrine!'
	 7: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/imgproxy-2.0.1/lib/imgproxy.rb:15:in `config'
	 6: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/imgproxy-2.0.1/lib/imgproxy.rb:15:in `new'
	 5: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/anyway_config-2.3.0/lib/.rbnext/3.0/anyway/config.rb:337:in `initialize'
	 4: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/anyway_config-2.3.0/lib/.rbnext/3.0/anyway/config.rb:355:in `load'
	 3: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/anyway_config-2.3.0/lib/.rbnext/3.0/anyway/tracing.rb:133:in `capture'
	 2: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/anyway_config-2.3.0/lib/.rbnext/3.0/anyway/config.rb:358:in `block in load'
	 1: from /Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/anyway_config-2.3.0/lib/.rbnext/3.0/anyway/config.rb:407:in `resolve_config_path'
/Users/pnovess/.rvm/gems/ruby-2.7.2@designious_api/gems/anyway_config-2.3.0/lib/anyway/rails/settings.rb:67:in `block in <class:Settings>': undefined method `join' for nil:NilClass (NoMethodError)

imgproxy_url helper is trying to modify passed options

Hi!
I'm using imgproxy gem with ActiveStorage. And when I pass a frozen hash as a processing options to the imgproxy_url helper, it raises an error:

class Post
  IMAGE_DIMENSIONS = { width: 148, height: 96, resizing_type: :fill }.freeze
  has_one_attached :image
end

Post.find(666).image.imgproxy_url(Post::IMAGE_DIMENSIONS)

=>

FrozenError (can't modify frozen Hash):
imgproxy (1.0.2) lib/imgproxy/builder.rb:23:in `delete'
imgproxy (1.0.2) lib/imgproxy/builder.rb:23:in `initialize'
imgproxy (1.0.2) lib/imgproxy.rb:73:in `new'
imgproxy (1.0.2) lib/imgproxy.rb:73:in `url_for'
imgproxy (1.0.2) lib/imgproxy/extensions/active_storage.rb:13:in `imgproxy_url'

That is caused by this line:
https://github.com/imgproxy/imgproxy.rb/blob/master/lib/imgproxy/builder.rb#L23

This is potentially harmful, as if somebody forgets to freeze the hash, it can lead to hardly catchable bugs.

Gem version release

Hey,
I noticed @DarthSim added support for URL encryption; thank you 🎉 ! Could I ask for a rubygems.org gem release, including the latest changes?

ShrineS3 url needs to be configurable?

In my shrine setup, the S3 urls are in the format "s3://#{image.storage.bucket.name}/store/#{image.id}". I've overridden Imgproxy::UrlAdapters::ShrineS3#url to customize this, but perhaps it would be a good idea to make this configurable?

Invalid Signature

Hi there,

I am running into an issue that is quite strange. I am using this gem as a stand alone gem and it seems that my imgproxy server wont accept the "advanced" url scheme:

I am using the following code (pulled from: https://github.com/imgproxy/imgproxy/blob/master/examples/signature.rb) which is generating a working, basic url

    def self.generate_url(url,
                          width: 250,
                          height: 250,
                          resize: "fit",
                          gravity: "no",
                          enlarge: 1)
      key = [Rails.application.secrets.IMGPROXY_KEY].pack("H*")
      salt = [Rails.application.secrets.IMGPROXY_SALT].pack("H*")

      encoded_url = Base64.urlsafe_encode64(url).tr("=", "").scan(/.{1,16}/).join("/")

      path = "/#{resize}/#{width}/#{height}/#{gravity}/#{enlarge}/#{encoded_url}"

      digest = OpenSSL::Digest.new("sha256")

      hmac = Base64.urlsafe_encode64(
        OpenSSL::HMAC.digest(digest, key, "#{salt}#{path}")
      ).tr("=", "")

      URI.join(Rails.application.secrets.IMGPROXY_HOST, "/#{hmac}#{path}").to_s
    end

If I update this code to the "advanced" url scheme (https://github.com/imgproxy/imgproxy/blob/master/docs/generating_the_url_advanced.md) I get an "Invalid Signature" error.

Interestingly I also am getting the "Invalid Signature" error when generating a URL using this gem

# config/initializers/imgproxy.rb
Imgproxy.configure do |config|
  config.endpoint = Rails.application.secrets.IMGPROXY_HOST
  config.hex_key = Rails.application.secrets.IMGPROXY_KEY
  config.hex_salt = Rails.application.secrets.IMGPROXY_SALT
end

# console
> Imgproxy.url_for("https://i.scdn.co/image/a41a79bccd8165b0a4c3d0de9979d973ca8cb321") 
=> "http://localhost:1337/Ujm6eYWQ8lJIsjBgT6vuSE742OvVvEfmBus7E9cmHYA/plain/https:/i.scdn.co/image/a41a79bccd8165b0a4c3d0de9979d973ca8cb321"

Can anyone confirm they are also getting this error using the advanced url scheme in Ruby and/or using this gem?


Using version 2.3.0 of imgproxy btw

URL escaping

URL escaping is not happening when using s3:// urls:

Imgproxy.url_for("s3://bucket/file") #=> "https://img.proxy.com/<key>/plain/s3://bucket/file"

See also aws/aws-sdk-ruby#2300

Subclass for chained URLs (Imgproxy Pro)

Hi folks,

I needed to create chained URLs, so I came up with a simple subclass of Imgproxy::Builder which I thought might be useful to others. I just stuck it in a Rails initializer.

Instead of Imgproxy::Builder.new({your: :options}) you pass an array of options as the first argument, and any builder options as the second argument:

Imgproxy::ChainedBuilder.new([{width: 512}, {crop: {height: 340, gravity: :obj}}]).url_for('your-image-url-here')

It's a bit rough, and not worthy of a PR, but I thought it might be useful to others.

module Imgproxy
  class ChainedBuilder < Imgproxy::Builder

    def initialize(option_groups = [], options = {})
      option_groups = option_groups.dup

      @option_groups = option_groups.map do |options|
        Imgproxy::Options.new(options)
      end
      extract_builder_options(options)
      @format = options.delete(:format)

    end

    # build a chained builder. Grouped processing options are an array of the groups of processing options, thus:
    # [
    #   ["width: 1024"],
    #   ["crop:h:300"]
    # ]
    # They need to be on the url separated by a /-/
    def url_for(image)
      path_parts = grouped_processing_options.inject([]) do |a, opts|
        a.push(opts)
        a.push("-")
        a
      end
      path = path_parts.push(url(image, ext: @format)).join("/")
      signature = sign_path(path)
      File.join(Imgproxy.config.endpoint.to_s, signature, path)
    end

    # Build an array of processing options, which will need to be separated by a /-/ in the url
    def grouped_processing_options
      @grouped_processing_options ||= @option_groups.map do |group|
        group.map do |key, value|
          [option_alias(key), value].join(":")
        end
      end
    end
  end
end

Using a mirror service with S3 urls

I'm using S3 with a Mirror Service in production (active storage). My storage.yml config looks like this:

production:
  service: Mirror
  primary: wasabi
  mirrors:
    - backblaze

Because of this, even when IMGPROXY_USE_S3_URLS is properly set, the s3 urls are not being created because the image.service is ActiveStorage::Service::MirrorService not ActiveStorage::Service::S3Service.

In url_adapters/active_storage.rb the call to use_s3_url fails because of the check for S3 service.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.