dragonfly 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of dragonfly might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 84cc06b313ddc9f160196e61b36307ea6654d979
4
- data.tar.gz: 181e3671a18a1d2c56cd97134cab2969ccdb4bcd
3
+ metadata.gz: 4918846aff69a7cb7483d21babadf9f74d674d91
4
+ data.tar.gz: e015447812e545b186c422b355de1916fc474201
5
5
  SHA512:
6
- metadata.gz: 6f4d6a4787d47bd693cffa4499ff1160e2632625c1de3d89b565b4144bbbed89ac52d9340f2dd052f9aab75b3d7b505c2495b013df0858eebfffa26d58ad8ed3
7
- data.tar.gz: e66731899aa80963b5cb478a04860680f3a428b1e581b10425da4fe1bda9f4b068d7f15ac2263ffea9609485cf4df11dffff6144124259bf5cbc9863f56e2500
6
+ metadata.gz: 5642ce50bb25ffd86a4960be6d69e011d285c749e54c572a2977399775ce7e30f9634bfe72bae98f5f2d1cb3e24ba860e6e711457a288b02f920a184142123c9
7
+ data.tar.gz: c665ecd2f6c045a668abc45197900ca9a4fd75c3028dcf7085cc6cf1799d82c3c882d97d48eb11f792dfc59947143198ad918b60ee92155a981e5f1d40904dd9
data/History.md CHANGED
@@ -1,3 +1,18 @@
1
+ 1.1.1 (2016-10-26)
2
+ ===================
3
+ Features
4
+ --------
5
+ - Added delegate option for imagemagick (Will Fisher)
6
+
7
+ Fixes
8
+ -----
9
+ - Use `Base64.urlsafe_encode64` (Jan Raasch)
10
+ Note that this changes b64 encodings from '/' to `'_'` and '+' to '-' in URLs, which will change a very
11
+ small number of generated URLs (but shouldn't be enough to cause big recaching problems)
12
+ URLs are encoded now according to the URL safe base64 specification in RFC 4648.
13
+ Old URLs are still recognized so won't break.
14
+
15
+
1
16
  1.1.0 (2016-10-24)
2
17
  ===================
3
18
  Fixes
data/README.md CHANGED
@@ -44,7 +44,7 @@ Installation
44
44
 
45
45
  or in your Gemfile
46
46
  ```ruby
47
- gem 'dragonfly', '~> 1.1.0'
47
+ gem 'dragonfly', '~> 1.1.1'
48
48
  ```
49
49
 
50
50
  Require with
@@ -69,8 +69,7 @@ module Dragonfly
69
69
  end
70
70
 
71
71
  # Extra methods
72
- app.define :identify do |*args|
73
- cli_args = args.first # because ruby 1.8.7 can't deal with default args in blocks
72
+ app.define :identify do |cli_args=nil|
74
73
  shell_eval do |path|
75
74
  "#{app.env[:identify_command]} #{cli_args} #{path}"
76
75
  end
@@ -8,10 +8,11 @@ module Dragonfly
8
8
  format = opts['format']
9
9
 
10
10
  input_args = opts['input_args'] if opts['input_args']
11
+ delegate_string = "#{opts['delegate']}:" if opts['delegate']
11
12
  frame_string = "[#{opts['frame']}]" if opts['frame']
12
13
 
13
14
  content.shell_update :ext => format do |old_path, new_path|
14
- "#{convert_command} #{input_args} #{old_path}#{frame_string} #{args} #{new_path}"
15
+ "#{convert_command} #{input_args} #{delegate_string}#{old_path}#{frame_string} #{args} #{new_path}"
15
16
  end
16
17
 
17
18
  if format
@@ -60,7 +60,7 @@ module Dragonfly
60
60
  Serializer.json_b64_decode(string)
61
61
  rescue Serializer::BadString
62
62
  if app.allow_legacy_urls
63
- Serializer.marshal_b64_decode(string, :check_malicious => true) # legacy strings
63
+ Serializer.marshal_b64_decode(string) # legacy strings
64
64
  else
65
65
  raise
66
66
  end
@@ -13,22 +13,20 @@ module Dragonfly
13
13
  extend self # So we can do Serializer.b64_encode, etc.
14
14
 
15
15
  def b64_encode(string)
16
- Base64.encode64(string).tr("\n=",'')
16
+ Base64.urlsafe_encode64(string).tr('=','')
17
17
  end
18
18
 
19
19
  def b64_decode(string)
20
- padding_length = string.length % 4
21
- string = string.tr('~', '/')
22
- Base64.decode64(string + '=' * padding_length)
20
+ padding_length = (-(string.length % 4)) % 4
21
+ string = string.tr('+','-').tr('~/','_')
22
+ Base64.urlsafe_decode64(string + '=' * padding_length)
23
+ rescue ArgumentError => e
24
+ raise BadString, "couldn't b64_decode string - got #{e}"
23
25
  end
24
26
 
25
- def marshal_b64_encode(object)
26
- b64_encode(Marshal.dump(object))
27
- end
28
-
29
- def marshal_b64_decode(string, opts={})
27
+ def marshal_b64_decode(string)
30
28
  marshal_string = b64_decode(string)
31
- raise MaliciousString, "potentially malicious marshal string #{marshal_string.inspect}" if opts[:check_malicious] && marshal_string[/@[a-z_]/i]
29
+ raise MaliciousString, "potentially malicious marshal string #{marshal_string.inspect}" if marshal_string[/@[a-z_]/i]
32
30
  Marshal.load(marshal_string)
33
31
  rescue TypeError, ArgumentError => e
34
32
  raise BadString, "couldn't marshal decode string - got #{e}"
@@ -37,11 +37,7 @@ module Dragonfly
37
37
 
38
38
  def url_format=(url_format)
39
39
  @url_format = url_format
40
- self.url_mapper = UrlMapper.new(url_format,
41
- :basename => '[^\/]',
42
- :name => '[^\/]',
43
- :format => '[^\.]'
44
- )
40
+ self.url_mapper = UrlMapper.new(url_format)
45
41
  end
46
42
 
47
43
  def before_serve(&block)
@@ -27,10 +27,10 @@ module Dragonfly
27
27
 
28
28
  private
29
29
 
30
- # Annoyingly, Open3 seems buggy on jruby/1.8.7:
30
+ # Annoyingly, Open3 seems buggy on jruby:
31
31
  # Some versions don't yield a wait_thread in the block and
32
32
  # you can't run sub-shells (if explicitly turning shell-escaping off)
33
- if RUBY_PLATFORM == 'java' || RUBY_VERSION < '1.9'
33
+ if RUBY_PLATFORM == 'java'
34
34
 
35
35
  # Unfortunately we have no control over stderr this way
36
36
  def run_command(command)
@@ -2,7 +2,6 @@ require 'stringio'
2
2
  require 'tempfile'
3
3
  require 'pathname'
4
4
  require 'fileutils'
5
- require 'dragonfly/core_ext/tempfile'
6
5
 
7
6
  module Dragonfly
8
7
 
@@ -4,6 +4,15 @@ require 'dragonfly/utils'
4
4
  module Dragonfly
5
5
  class UrlMapper
6
6
 
7
+ PATTERNS = {
8
+ basename: '[^\/]',
9
+ name: '[^\/]',
10
+ ext: '[^\.]',
11
+ format: '[^\.]',
12
+ job: '[^\/\.]'
13
+ }
14
+ DEFAULT_PATTERN = '[^\/\-\.]'
15
+
7
16
  # Exceptions
8
17
  class BadUrlFormat < StandardError; end
9
18
 
@@ -13,10 +22,10 @@ module Dragonfly
13
22
  end
14
23
  end
15
24
 
16
- def initialize(url_format, patterns={})
25
+ def initialize(url_format)
17
26
  @url_format = url_format
18
27
  raise BadUrlFormat, "bad url format #{url_format}" if url_format[/[\w_]:[\w_]/]
19
- init_segments(patterns)
28
+ init_segments
20
29
  init_url_regexp
21
30
  end
22
31
 
@@ -51,13 +60,13 @@ module Dragonfly
51
60
 
52
61
  private
53
62
 
54
- def init_segments(patterns)
63
+ def init_segments
55
64
  @segments = []
56
65
  url_format.scan(/([^\w_]):([\w_]+)/).each do |seperator, param|
57
66
  segments << Segment.new(
58
67
  param,
59
68
  seperator,
60
- patterns[param.to_sym] || '[^\/\-\.]'
69
+ PATTERNS[param.to_sym] || DEFAULT_PATTERN
61
70
  )
62
71
  end
63
72
  end
@@ -1,3 +1,3 @@
1
1
  module Dragonfly
2
- VERSION = '1.1.0'
2
+ VERSION = '1.1.1'
3
3
  end
@@ -11,14 +11,4 @@ class DragonflyGenerator < Rails::Generators::Base
11
11
  SecureRandom.hex(32)
12
12
  end
13
13
 
14
- if RUBY_VERSION > "1.9"
15
- def hash_key(key)
16
- "#{key}:"
17
- end
18
- else
19
- def hash_key(key)
20
- ":#{key} =>"
21
- end
22
- end
23
14
  end
24
-
@@ -9,8 +9,8 @@ Dragonfly.app.configure do
9
9
  url_format "/media/:job/:name"
10
10
 
11
11
  datastore :file,
12
- <%= hash_key(:root_path) %> Rails.root.join('public/system/dragonfly', Rails.env),
13
- <%= hash_key(:server_root) %> Rails.root.join('public')
12
+ root_path: Rails.root.join('public/system/dragonfly', Rails.env),
13
+ server_root: Rails.root.join('public')
14
14
  end
15
15
 
16
16
  # Logger
@@ -62,4 +62,9 @@ describe Dragonfly::ImageMagick::Processors::Convert do
62
62
  pdf.should_not equal_image(pdf2)
63
63
  end
64
64
 
65
+ it "allows converting using specific delegates" do
66
+ expect {
67
+ processor.call(image, '', 'format' => 'jpg', 'delegate' => 'png')
68
+ }.to call_command(app.shell, %r{'convert' 'png:/[^']+?/beach\.png' '/[^']+?\.jpg'})
69
+ end
65
70
  end
@@ -292,7 +292,7 @@ describe Dragonfly::Job do
292
292
  end
293
293
 
294
294
  it "checks for potentially malicious strings" do
295
- string = Dragonfly::Serializer.marshal_b64_encode(Dragonfly::TempObject.new('a'))
295
+ string = Base64.encode64(Marshal.dump(Dragonfly::TempObject.new('a'))).tr("\n=",'')
296
296
  expect{
297
297
  Dragonfly::Job.deserialize(string, @app)
298
298
  }.to raise_error(Dragonfly::Serializer::MaliciousString)
@@ -1136,7 +1136,11 @@ describe "models" do
1136
1136
  }.should raise_error(Dragonfly::Model::Attachment::BadAssignmentKey)
1137
1137
  end
1138
1138
 
1139
- [nil, "", "asdfsad"].each do |value|
1139
+ [
1140
+ nil,
1141
+ "",
1142
+ "asdfsad" # assigning with rubbish shouldn't break it
1143
+ ].each do |value|
1140
1144
  it "should do nothing if assigned with #{value}" do
1141
1145
  @item.retained_preview_image = value
1142
1146
  @item.preview_image_uid.should be_nil
@@ -13,10 +13,11 @@ describe Dragonfly::Serializer do
13
13
  '//..',
14
14
  'whats/up.egg.frog',
15
15
  '£ñçùí;',
16
- '~'
16
+ '~',
17
+ '-umlaut_ö'
17
18
  ].each do |string|
18
- it "should encode #{string.inspect} properly with no padding/line break" do
19
- b64_encode(string).should_not =~ /\n|=/
19
+ it "should encode #{string.inspect} properly with no padding/line break or slash" do
20
+ b64_encode(string).should_not =~ /\n|=|\//
20
21
  end
21
22
  it "should correctly encode and decode #{string.inspect} to the same string" do
22
23
  str = b64_decode(b64_encode(string))
@@ -26,31 +27,21 @@ describe Dragonfly::Serializer do
26
27
  end
27
28
 
28
29
  describe "b64_decode" do
29
- it "converts (deprecated) '~' characters to '/' characters" do
30
- b64_decode('asdf~asdf').should == b64_decode('asdf/asdf')
30
+ if RUBY_PLATFORM != 'java'
31
+ # jruby doesn't seem to throw anything - it just removes non b64 characters
32
+ it "raises an error if the string passed in is not base 64" do
33
+ expect {
34
+ b64_decode("eggs for breakfast")
35
+ }.to raise_error(Dragonfly::Serializer::BadString)
36
+ end
37
+ end
38
+ it "converts (deprecated) '~' and '/' characters to '_' characters" do
39
+ b64_decode('LXVtbGF1dF~Dtg').should == b64_decode('LXVtbGF1dF_Dtg')
40
+ b64_decode('LXVtbGF1dF/Dtg').should == b64_decode('LXVtbGF1dF_Dtg')
41
+ end
42
+ it "converts '+' characters to '-' characters" do
43
+ b64_decode('LXVtbGF1dF+Dtg').should == b64_decode('LXVtbGF1dF-Dtg')
31
44
  end
32
- end
33
-
34
- end
35
-
36
- [
37
- :hello,
38
- nil,
39
- true,
40
- 4,
41
- 2.3,
42
- 'wassup man',
43
- [3,4,5],
44
- {:wo => 'there'},
45
- [{:this => 'should', :work => [3, 5.3, nil, {false => 'egg'}]}, [], true]
46
- ].each do |object|
47
- it "should correctly marshal encode #{object.inspect} properly with no padding/line break" do
48
- encoded = marshal_b64_encode(object)
49
- encoded.should be_a(String)
50
- encoded.should_not =~ /\n|=/
51
- end
52
- it "should correctly marshal encode and decode #{object.inspect} to the same object" do
53
- marshal_b64_decode(marshal_b64_encode(object)).should == object
54
45
  end
55
46
  end
56
47
 
@@ -66,18 +57,14 @@ describe Dragonfly::Serializer do
66
57
  }.should raise_error(Dragonfly::Serializer::BadString)
67
58
  end
68
59
  describe "potentially harmful strings" do
69
- it "doesn't raise if not flagged to check for malicious strings" do
70
- class C; end
71
- marshal_b64_decode('BAhvOgZDBjoOQF9fc2VuZF9faQY').should be_a(C)
72
- end
73
60
  ['_', 'hello', 'h2', '__send__', 'F'].each do |variable_name|
74
- it "raises if flagged to check for malicious strings and finds one" do
61
+ it "raises if it finds a malicious string" do
75
62
  class C; end
76
63
  c = C.new
77
64
  c.instance_eval{ instance_variable_set("@#{variable_name}", 1) }
78
65
  string = Dragonfly::Serializer.b64_encode(Marshal.dump(c))
79
66
  lambda{
80
- marshal_b64_decode(string, :check_malicious => true)
67
+ marshal_b64_decode(string)
81
68
  }.should raise_error(Dragonfly::Serializer::MaliciousString)
82
69
  end
83
70
  end
@@ -24,21 +24,7 @@ describe Dragonfly::UrlMapper do
24
24
  describe "url_regexp" do
25
25
  it "should return a regexp with non-greedy optional groups that include the preceding slash/dot/dash" do
26
26
  url_mapper = Dragonfly::UrlMapper.new('/media/:job/:basename-:size.:format')
27
- url_mapper.url_regexp.should == %r{\A/media(/[^\/\-\.]+?)?(/[^\/\-\.]+?)?(\-[^\/\-\.]+?)?(\.[^\/\-\.]+?)?\z}
28
- end
29
-
30
- it "should allow setting custom patterns in the url" do
31
- url_mapper = Dragonfly::UrlMapper.new('/media/:job-:size.:format',
32
- :job => '\w',
33
- :size => '\d',
34
- :format => '[^\.]'
35
- )
36
- url_mapper.url_regexp.should == %r{\A/media(/\w+?)?(\-\d+?)?(\.[^\.]+?)?\z}
37
- end
38
-
39
- it "should make optional match patterns (ending in ?) apply to the whole group including the preceding seperator" do
40
- url_mapper = Dragonfly::UrlMapper.new('/media/:job', :job => '\w')
41
- url_mapper.url_regexp.should == %r{\A/media(/\w+?)?\z}
27
+ url_mapper.url_regexp.should == %r{\A/media(/[^\/\.]+?)?(/[^\/]+?)?(\-[^\/\-\.]+?)?(\.[^\.]+?)?\z}
42
28
  end
43
29
  end
44
30
 
@@ -98,33 +84,36 @@ describe Dragonfly::UrlMapper do
98
84
  it "should correctly url-unescape funny characters" do
99
85
  @url_mapper.params_for('/media/a%23c').should == {'job' => 'a#c'}
100
86
  end
87
+
88
+ it "should work when the job contains the '-' character" do
89
+ @url_mapper = Dragonfly::UrlMapper.new('/media/:job-:size.:format')
90
+ @url_mapper.params_for('/media/asdf-30x30.jpg').should == {'job' => 'asdf', 'size' => '30x30', 'format' => 'jpg'}
91
+ @url_mapper.params_for('/media/as-df-30x30.jpg').should == {'job' => 'as-df', 'size' => '30x30', 'format' => 'jpg'}
92
+ end
101
93
  end
102
94
 
103
- describe "matching urls with standard format /media/:job/:basename.:format" do
95
+ describe "matching urls with standard format /media/:job/:name" do
104
96
  before(:each) do
105
- @url_mapper = Dragonfly::UrlMapper.new('/media/:job/:basename.:format',
106
- :basename => '[^\/]',
107
- :format => '[^\.]'
108
- )
97
+ @url_mapper = Dragonfly::UrlMapper.new('/media/:job/:name')
109
98
  end
110
99
 
111
100
  {
112
101
  '' => nil,
113
102
  '/' => nil,
114
- '/media' => {'job' => nil, 'basename' => nil, 'format' => nil},
103
+ '/media' => {'job' => nil, 'name' => nil},
115
104
  '/media/' => nil,
116
105
  '/moodia/asdf' => nil,
117
106
  '/media/asdf/' => nil,
118
107
  '/mount/media/asdf' => nil,
119
- '/media/asdf/stuff.egg' => {'job' => 'asdf', 'basename' => 'stuff', 'format' => 'egg'},
120
- '/media/asdf' => {'job' => 'asdf', 'basename' => nil, 'format' => nil},
121
- '/media/asdf/stuff' => {'job' => 'asdf', 'basename' => 'stuff', 'format' => nil},
122
- '/media/asdf.egg' => {'job' => 'asdf', 'basename' => nil, 'format' => 'egg'},
108
+ '/media/asdf/stuff.egg' => {'job' => 'asdf', 'name' => 'stuff.egg'},
109
+ '/media/asdf' => {'job' => 'asdf', 'name' => nil},
110
+ '/media/asdf/stuff' => {'job' => 'asdf', 'name' => 'stuff'},
111
+ '/media/asdf.egg' => {'job' => nil, 'name' => 'asdf.egg'},
123
112
  '/media/asdf/stuff/egg' => nil,
124
- '/media/asdf/stuff.dog.egg' => {'job' => 'asdf', 'basename' => 'stuff.dog', 'format' => 'egg'},
125
- '/media/asdf/s%3D2%2B-.d.e' => {'job' => 'asdf', 'basename' => 's=2+-.d', 'format' => 'e'},
126
- '/media/asdf-40x40/stuff.egg' => nil,
127
- '/media/a%23c' => {'job' => 'a#c', 'basename' => nil, 'format' => nil}
113
+ '/media/asdf/stuff.dog.egg' => {'job' => 'asdf', 'name' => 'stuff.dog.egg'},
114
+ '/media/asdf/s%3D2%2B-.d.e' => {'job' => 'asdf', 'name' => 's=2+-.d.e'},
115
+ '/media/asdf-40x40/stuff.egg' => {'job' => 'asdf-40x40', 'name' => 'stuff.egg'},
116
+ '/media/a%23c' => {'job' => 'a#c', 'name' => nil}
128
117
  }.each do |path, params|
129
118
 
130
119
  it "should turn the url #{path} into params #{params.inspect}" do
@@ -45,7 +45,7 @@ describe "urls" do
45
45
 
46
46
  it "works with potentially tricky url characters for the url" do
47
47
  url = app.fetch('uid []=~/+').url(:name => 'name []=~/+')
48
- url.should =~ %r(^/[\w%]+/name%20%5B%5D%3D%7E%2F%2B$)
48
+ url.should =~ %r(^/[\w-]+/name%20%5B%5D%3D%7E%2F%2B$)
49
49
  job_should_match [["f", "uid []=~/+"]]
50
50
  response = request(app, url)
51
51
  end
@@ -9,7 +9,7 @@ require 'dragonfly'
9
9
  require 'fileutils'
10
10
  require 'tempfile'
11
11
  require 'webmock/rspec'
12
- require 'pry' if RUBY_VERSION >= '1.9'
12
+ require 'pry'
13
13
 
14
14
  # Requires supporting files with custom matchers and macros, etc,
15
15
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
@@ -62,3 +62,16 @@ RSpec::Matchers.define :increase_num_tempfiles do
62
62
  true
63
63
  end
64
64
  end
65
+
66
+ RSpec::Matchers.define :call_command do |shell, command|
67
+ match do |block|
68
+ # run_command is private so this is slightly naughty but it does the job
69
+ allow(shell).to receive(:run_command).and_call_original
70
+ block.call
71
+ expect(shell).to have_received(:run_command).with(command)
72
+ end
73
+
74
+ def supports_block_expectations?
75
+ true
76
+ end
77
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dragonfly
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-24 00:00:00.000000000 Z
11
+ date: 2016-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -126,7 +126,6 @@ files:
126
126
  - lib/dragonfly/core_ext/array.rb
127
127
  - lib/dragonfly/core_ext/hash.rb
128
128
  - lib/dragonfly/core_ext/object.rb
129
- - lib/dragonfly/core_ext/tempfile.rb
130
129
  - lib/dragonfly/file_data_store.rb
131
130
  - lib/dragonfly/has_filename.rb
132
131
  - lib/dragonfly/hash_with_css_style_keys.rb
@@ -259,7 +258,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
259
258
  version: '0'
260
259
  requirements: []
261
260
  rubyforge_project:
262
- rubygems_version: 2.5.1
261
+ rubygems_version: 2.6.7
263
262
  signing_key:
264
263
  specification_version: 4
265
264
  summary: Ideal gem for handling attachments in Rails, Sinatra and Rack applications.
@@ -1,19 +0,0 @@
1
- # Tempfile#size reports size of 0 after the tempfile has been
2
- # closed (without unlinking). This happens because internal
3
- # @tmpfile is set to nil when the Tempfile is closed.
4
- # Alternatively @tmpname is set to nil when file is unlinked.
5
-
6
- if RUBY_VERSION < '1.9'
7
- class Tempfile
8
- def size
9
- if @tmpfile
10
- @tmpfile.flush
11
- @tmpfile.stat.size
12
- elsif @tmpname
13
- File.size(@tmpname)
14
- else
15
- 0
16
- end
17
- end
18
- end
19
- end