refile 0.5.2 → 0.5.3

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

Potentially problematic release.


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

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d93614e14a47419b97ee9062afbbe4d1df8fbdeb
4
- data.tar.gz: 352d8c297f223caeddd1bc9b2fe0381ae8f2ce80
3
+ metadata.gz: 6797e0c960a77817f75d9f5a6c5b48e7e4f3b363
4
+ data.tar.gz: 430f42e462d044897740dad2fb9dd21db6b707d9
5
5
  SHA512:
6
- metadata.gz: ecbafbc35dc7a1fac5fbd9d0bd92681362bc09f188dd494e7e76d2a2d5a4fb2c2538c19c64bf167c508f1ed62d853e0ad64f6dfbd5cf99a94b1ca236ca7c6eef
7
- data.tar.gz: 7f1e0714723dcabd5d884d3e031664a2153d987d464df0a43547aaba94de10d68fc761de7a87e2075abca911cfce4db5b2d527120ba4323f01bd9a5a0bf72214
6
+ metadata.gz: 7e1560a7e9a3ff8e13e628f1e77c1d135e0828dd1eb451b8702092122bf90575c4f11d77dc6f526787a6d7eeeb6818ae602007a5276acfccc51dc7f88d3e770e
7
+ data.tar.gz: d99149310b57a8a766f448361cb46bf9e7d5d4699ed624422985d418cd3bc8529a86c425e87b8b367f5f5371ce2398241d90cbdac9065d3e504e7a7258429549
data/.rubocop.yml CHANGED
@@ -55,8 +55,14 @@ Style/AccessModifierIndentation:
55
55
  Style/SignalException:
56
56
  Enabled: false
57
57
 
58
+ Style/IndentationWidth:
59
+ Enabled: false
60
+
58
61
  Lint/EndAlignment:
59
62
  AlignWith: variable
60
63
 
64
+ Lint/DefEndAlignment:
65
+ Enabled: false
66
+
61
67
  Lint/HandleExceptions:
62
68
  Enabled: false
data/History.md CHANGED
@@ -1,3 +1,10 @@
1
+ # 0.5.3
2
+
3
+ Release date: 2015-01-18
4
+
5
+ - [FIXED] More stringent checks for ID validity.
6
+ - [CHANGED] `Refile.attachment_url` not uses `Refile.mount_point` as the prefix by default.
7
+
1
8
  # 0.5.2
2
9
 
3
10
  Release date: 2015-01-13
data/lib/refile.rb CHANGED
@@ -8,6 +8,9 @@ module Refile
8
8
  # @api private
9
9
  class Invalid < StandardError; end
10
10
 
11
+ # @api private
12
+ class InvalidID < Invalid; end
13
+
11
14
  # @api private
12
15
  class Confirm < StandardError
13
16
  def message
@@ -166,27 +169,6 @@ module Refile
166
169
  yield self
167
170
  end
168
171
 
169
- # Verify that the given uploadable is indeed a valid uploadable. This
170
- # method is used by backends as a sanity check, you should not have to use
171
- # this method unless you are writing a backend.
172
- #
173
- # @param [IO] uploadable The uploadable object to verify
174
- # @param [Fixnum] max_size The maximum size of the uploadable object
175
- # @raise [ArgumentError] If the uploadable is not an IO-like object
176
- # @raise [Refile::Invalid] If the uploadable's size is too large
177
- # @return [true] Always returns true if it doesn't raise
178
- def verify_uploadable(uploadable, max_size)
179
- [:size, :read, :eof?, :close].each do |m|
180
- unless uploadable.respond_to?(m)
181
- raise ArgumentError, "does not respond to `#{m}`."
182
- end
183
- end
184
- if max_size and uploadable.size > max_size
185
- raise Refile::Invalid, "#{uploadable.inspect} is too large"
186
- end
187
- true
188
- end
189
-
190
172
  # Extract the filename from an uploadable object. If the filename cannot be
191
173
  # determined, this method will return `nil`.
192
174
  #
@@ -254,6 +236,7 @@ module Refile
254
236
  return unless file
255
237
 
256
238
  host ||= Refile.host
239
+ prefix ||= Refile.mount_point
257
240
  filename ||= attacher.basename || name.to_s
258
241
  format ||= attacher.extension
259
242
 
@@ -271,6 +254,7 @@ module Refile
271
254
  require "refile/version"
272
255
  require "refile/signature"
273
256
  require "refile/type"
257
+ require "refile/backend_macros"
274
258
  require "refile/attacher"
275
259
  require "refile/attachment"
276
260
  require "refile/random_hasher"
@@ -7,6 +7,8 @@ module Refile
7
7
  # file = backend.upload(StringIO.new("hello"))
8
8
  # backend.read(file.id) # => "hello"
9
9
  class FileSystem
10
+ extend Refile::BackendMacros
11
+
10
12
  # @return [String] the directory where files are stored
11
13
  attr_reader :directory
12
14
 
@@ -30,9 +32,7 @@ module Refile
30
32
  #
31
33
  # @param [IO] uploadable An uploadable IO-like object.
32
34
  # @return [Refile::File] The uploaded file
33
- def upload(uploadable)
34
- Refile.verify_uploadable(uploadable, @max_size)
35
-
35
+ verify_uploadable def upload(uploadable)
36
36
  id = @hasher.hash(uploadable)
37
37
  IO.copy_stream(uploadable, path(id))
38
38
 
@@ -47,7 +47,7 @@ module Refile
47
47
  #
48
48
  # @param [Sring] id The id of the file
49
49
  # @return [Refile::File] The retrieved file
50
- def get(id)
50
+ verify_id def get(id)
51
51
  Refile::File.new(self, id)
52
52
  end
53
53
 
@@ -55,7 +55,7 @@ module Refile
55
55
  #
56
56
  # @param [Sring] id The id of the file
57
57
  # @return [void]
58
- def delete(id)
58
+ verify_id def delete(id)
59
59
  FileUtils.rm(path(id)) if exists?(id)
60
60
  end
61
61
 
@@ -64,7 +64,7 @@ module Refile
64
64
  #
65
65
  # @param [Sring] id The id of the file
66
66
  # @return [IO] An IO object containing the file contents
67
- def open(id)
67
+ verify_id def open(id)
68
68
  ::File.open(path(id), "rb")
69
69
  end
70
70
 
@@ -72,7 +72,7 @@ module Refile
72
72
  #
73
73
  # @param [Sring] id The id of the file
74
74
  # @return [String] The file's contents
75
- def read(id)
75
+ verify_id def read(id)
76
76
  ::File.read(path(id)) if exists?(id)
77
77
  end
78
78
 
@@ -80,7 +80,7 @@ module Refile
80
80
  #
81
81
  # @param [Sring] id The id of the file
82
82
  # @return [Integer] The file's size
83
- def size(id)
83
+ verify_id def size(id)
84
84
  ::File.size(path(id)) if exists?(id)
85
85
  end
86
86
 
@@ -88,7 +88,7 @@ module Refile
88
88
  #
89
89
  # @param [Sring] id The id of the file
90
90
  # @return [Boolean]
91
- def exists?(id)
91
+ verify_id def exists?(id)
92
92
  ::File.exist?(path(id))
93
93
  end
94
94
 
@@ -110,7 +110,7 @@ module Refile
110
110
  #
111
111
  # @param [Sring] id The id of the file
112
112
  # @return [String]
113
- def path(id)
113
+ verify_id def path(id)
114
114
  ::File.join(@directory, id)
115
115
  end
116
116
  end
@@ -15,6 +15,8 @@ module Refile
15
15
  # file = backend.upload(StringIO.new("hello"))
16
16
  # backend.read(file.id) # => "hello"
17
17
  class S3
18
+ extend Refile::BackendMacros
19
+
18
20
  attr_reader :access_key_id, :max_size
19
21
 
20
22
  # Sets up an S3 backend with the given credentials.
@@ -44,9 +46,7 @@ module Refile
44
46
  #
45
47
  # @param [IO] uploadable An uploadable IO-like object.
46
48
  # @return [Refile::File] The uploaded file
47
- def upload(uploadable)
48
- Refile.verify_uploadable(uploadable, @max_size)
49
-
49
+ verify_uploadable def upload(uploadable)
50
50
  id = @hasher.hash(uploadable)
51
51
 
52
52
  if uploadable.is_a?(Refile::File) and uploadable.backend.is_a?(S3) and uploadable.backend.access_key_id == access_key_id
@@ -66,7 +66,7 @@ module Refile
66
66
  #
67
67
  # @param [Sring] id The id of the file
68
68
  # @return [Refile::File] The retrieved file
69
- def get(id)
69
+ verify_id def get(id)
70
70
  Refile::File.new(self, id)
71
71
  end
72
72
 
@@ -74,7 +74,7 @@ module Refile
74
74
  #
75
75
  # @param [Sring] id The id of the file
76
76
  # @return [void]
77
- def delete(id)
77
+ verify_id def delete(id)
78
78
  object(id).delete
79
79
  end
80
80
 
@@ -83,7 +83,7 @@ module Refile
83
83
  #
84
84
  # @param [Sring] id The id of the file
85
85
  # @return [IO] An IO object containing the file contents
86
- def open(id)
86
+ verify_id def open(id)
87
87
  Kernel.open(object(id).url_for(:read))
88
88
  end
89
89
 
@@ -91,7 +91,7 @@ module Refile
91
91
  #
92
92
  # @param [String] id The id of the file
93
93
  # @return [String] The file's contents
94
- def read(id)
94
+ verify_id def read(id)
95
95
  object(id).read
96
96
  rescue AWS::S3::Errors::NoSuchKey
97
97
  nil
@@ -101,7 +101,7 @@ module Refile
101
101
  #
102
102
  # @param [Sring] id The id of the file
103
103
  # @return [Integer] The file's size
104
- def size(id)
104
+ verify_id def size(id)
105
105
  object(id).content_length
106
106
  rescue AWS::S3::Errors::NoSuchKey
107
107
  nil
@@ -111,7 +111,7 @@ module Refile
111
111
  #
112
112
  # @param [Sring] id The id of the file
113
113
  # @return [Boolean]
114
- def exists?(id)
114
+ verify_id def exists?(id)
115
115
  object(id).exists?
116
116
  end
117
117
 
@@ -139,7 +139,7 @@ module Refile
139
139
  Signature.new(as: "file", id: id, url: signature.url.to_s, fields: signature.fields)
140
140
  end
141
141
 
142
- def object(id)
142
+ verify_id def object(id)
143
143
  @bucket.objects[[*@prefix, id].join("/")]
144
144
  end
145
145
  end
@@ -0,0 +1,37 @@
1
+ module Refile
2
+ # Macros which make it easier to write secure backends.
3
+ #
4
+ # @api private
5
+ module BackendMacros
6
+ def verify_id(method)
7
+ mod = Module.new do
8
+ define_method(method) do |id|
9
+ id = id.to_s
10
+ if id =~ /\A[a-z0-9]+\z/i
11
+ super(id)
12
+ else
13
+ raise Refile::InvalidID
14
+ end
15
+ end
16
+ end
17
+ prepend mod
18
+ end
19
+
20
+ def verify_uploadable(method)
21
+ mod = Module.new do
22
+ define_method(method) do |uploadable|
23
+ [:size, :read, :eof?, :close].each do |m|
24
+ unless uploadable.respond_to?(m)
25
+ raise ArgumentError, "does not respond to `#{m}`."
26
+ end
27
+ end
28
+ if max_size and uploadable.size > max_size
29
+ raise Refile::Invalid, "#{uploadable.inspect} is too large"
30
+ end
31
+ super(uploadable)
32
+ end
33
+ end
34
+ prepend mod
35
+ end
36
+ end
37
+ end
@@ -23,7 +23,7 @@ module Refile
23
23
  # @param [String, nil] host Override the host
24
24
  # @return [String, nil] The generated URL
25
25
  def attachment_url(record, name, *args, **opts)
26
- Refile.attachment_url(record, name, *args, prefix: main_app.refile_app_path, **opts)
26
+ Refile.attachment_url(record, name, *args, **opts)
27
27
  end
28
28
 
29
29
  # Generates an image tag for the given attachment, adding appropriate
@@ -1,3 +1,3 @@
1
1
  module Refile
2
- VERSION = "0.5.2"
2
+ VERSION = "0.5.3"
3
3
  end
@@ -67,6 +67,10 @@ RSpec.shared_examples_for :backend do
67
67
 
68
68
  expect(backend.get(file.id).exists?).to be_falsy
69
69
  end
70
+
71
+ it "raises error when called with invalid ID" do
72
+ expect { backend.delete("/evil") }.to raise_error(Refile::InvalidID)
73
+ end
70
74
  end
71
75
 
72
76
  describe "#read" do
@@ -83,6 +87,10 @@ RSpec.shared_examples_for :backend do
83
87
  file = backend.upload(uploadable)
84
88
  expect(file.read).to eq("hello")
85
89
  end
90
+
91
+ it "raises error when called with invalid ID" do
92
+ expect { backend.read("/evil") }.to raise_error(Refile::InvalidID)
93
+ end
86
94
  end
87
95
 
88
96
  describe "#size" do
@@ -99,6 +107,10 @@ RSpec.shared_examples_for :backend do
99
107
  file = backend.upload(uploadable)
100
108
  expect(file.size).to eq(5)
101
109
  end
110
+
111
+ it "raises error when called with invalid ID" do
112
+ expect { backend.size("/evil") }.to raise_error(Refile::InvalidID)
113
+ end
102
114
  end
103
115
 
104
116
  describe "#exists?" do
@@ -115,6 +127,10 @@ RSpec.shared_examples_for :backend do
115
127
  expect(backend.upload(uploadable).exists?).to eq(true)
116
128
  expect(backend.get("nosuchfile").exists?).to eq(false)
117
129
  end
130
+
131
+ it "raises error when called with invalid ID" do
132
+ expect { backend.exists?("/evil") }.to raise_error(Refile::InvalidID)
133
+ end
118
134
  end
119
135
 
120
136
  describe "#clear!" do
@@ -0,0 +1,62 @@
1
+ RSpec.describe Refile::BackendMacros do
2
+ let(:klass) do
3
+ Class.new do
4
+ extend Refile::BackendMacros
5
+
6
+ attr_accessor :max_size
7
+
8
+ verify_uploadable def upload(uploadable)
9
+ uploadable
10
+ end
11
+
12
+ verify_id def get(id)
13
+ id
14
+ end
15
+ end
16
+ end
17
+ let(:instance) { klass.new }
18
+
19
+ describe "#verify_uploadable" do
20
+ let(:io) { StringIO.new("hello") }
21
+
22
+ it "works if it conforms to required API" do
23
+ expect(instance.upload(double(size: 444, read: io, eof?: true, close: nil))).to be_truthy
24
+ end
25
+
26
+ it "raises ArgumentError if argument does not respond to `size`" do
27
+ expect { instance.upload(double(read: io, eof?: true, close: nil)) }.to raise_error(ArgumentError)
28
+ end
29
+
30
+ it "raises ArgumentError if argument does not respond to `read`" do
31
+ expect { instance.upload(double(size: 444, eof?: true, close: nil)) }.to raise_error(ArgumentError)
32
+ end
33
+
34
+ it "raises ArgumentError if argument does not respond to `eof?`" do
35
+ expect { instance.upload(double(size: 444, read: true, close: nil)) }.to raise_error(ArgumentError)
36
+ end
37
+
38
+ it "raises ArgumentError if argument does not respond to `close`" do
39
+ expect { instance.upload(double(size: 444, read: true, eof?: true)) }.to raise_error(ArgumentError)
40
+ end
41
+
42
+ it "returns true if size is respeced" do
43
+ instance.max_size = 8
44
+ expect(instance.upload(Refile::FileDouble.new("hello"))).to be_truthy
45
+ end
46
+
47
+ it "raises Refile::Invalid if size is exceeded" do
48
+ instance.max_size = 8
49
+ expect { instance.upload(Refile::FileDouble.new("hello world")) }.to raise_error(Refile::Invalid)
50
+ end
51
+ end
52
+
53
+ describe "#verify_id" do
54
+ it "works if it has a valid ID" do
55
+ expect(instance.get("1234aBCde123aee")).to be_truthy
56
+ end
57
+
58
+ it "raises ArgumentError if argument does not respond to `size`" do
59
+ expect { instance.get("ev/il") }.to raise_error(Refile::InvalidID)
60
+ end
61
+ end
62
+ end
data/spec/refile_spec.rb CHANGED
@@ -1,38 +1,6 @@
1
1
  require "refile"
2
2
 
3
3
  RSpec.describe Refile do
4
- let(:io) { StringIO.new("hello") }
5
-
6
- describe ".verify_uploadable" do
7
- it "works if it conforms to required API" do
8
- expect(Refile.verify_uploadable(double(size: 444, read: io, eof?: true, close: nil), nil)).to be_truthy
9
- end
10
-
11
- it "raises ArgumentError if argument does not respond to `size`" do
12
- expect { Refile.verify_uploadable(double(read: io, eof?: true, close: nil), nil) }.to raise_error(ArgumentError)
13
- end
14
-
15
- it "raises ArgumentError if argument does not respond to `read`" do
16
- expect { Refile.verify_uploadable(double(size: 444, eof?: true, close: nil), nil) }.to raise_error(ArgumentError)
17
- end
18
-
19
- it "raises ArgumentError if argument does not respond to `eof?`" do
20
- expect { Refile.verify_uploadable(double(size: 444, read: true, close: nil), nil) }.to raise_error(ArgumentError)
21
- end
22
-
23
- it "raises ArgumentError if argument does not respond to `close`" do
24
- expect { Refile.verify_uploadable(double(size: 444, read: true, eof?: true), nil) }.to raise_error(ArgumentError)
25
- end
26
-
27
- it "returns true if size is respeced" do
28
- expect(Refile.verify_uploadable(Refile::FileDouble.new("hello"), 8)).to be_truthy
29
- end
30
-
31
- it "raises Refile::Invalid if size is exceeded" do
32
- expect { Refile.verify_uploadable(Refile::FileDouble.new("hello world"), 8) }.to raise_error(Refile::Invalid)
33
- end
34
- end
35
-
36
4
  describe ".extract_filename" do
37
5
  it "extracts filename from original_filename" do
38
6
  name = Refile.extract_filename(double(original_filename: "/foo/bar/baz.png"))
@@ -84,6 +52,7 @@ RSpec.describe Refile do
84
52
 
85
53
  before do
86
54
  allow(Refile).to receive(:host).and_return(nil)
55
+ allow(Refile).to receive(:mount_point).and_return(nil)
87
56
  end
88
57
 
89
58
  context "with file" do
@@ -109,6 +78,11 @@ RSpec.describe Refile do
109
78
  expect(Refile.attachment_url(instance, :document, prefix: "moo")).to eq("/moo/cache/#{id}/document")
110
79
  end
111
80
 
81
+ it "takes prefix from Refile.mount_point" do
82
+ allow(Refile).to receive(:mount_point).and_return("attachments")
83
+ expect(Refile.attachment_url(instance, :document)).to eq("/attachments/cache/#{id}/document")
84
+ end
85
+
112
86
  it "adds an escaped filename" do
113
87
  expect(Refile.attachment_url(instance, :document, filename: "test.png")).to eq("/cache/#{id}/test.png")
114
88
  expect(Refile.attachment_url(instance, :document, filename: "tes/t.png")).to eq("/cache/#{id}/tes%2Ft.png")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: refile
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Nicklas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-13 00:00:00.000000000 Z
11
+ date: 2015-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -291,6 +291,7 @@ files:
291
291
  - lib/refile/attachment/active_record.rb
292
292
  - lib/refile/backend/file_system.rb
293
293
  - lib/refile/backend/s3.rb
294
+ - lib/refile/backend_macros.rb
294
295
  - lib/refile/custom_logger.rb
295
296
  - lib/refile/file.rb
296
297
  - lib/refile/image_processing.rb
@@ -308,6 +309,7 @@ files:
308
309
  - spec/refile/backend/file_system_spec.rb
309
310
  - spec/refile/backend/s3_spec.rb
310
311
  - spec/refile/backend_examples.rb
312
+ - spec/refile/backend_macros_spec.rb
311
313
  - spec/refile/custom_logger_spec.rb
312
314
  - spec/refile/features/direct_upload_spec.rb
313
315
  - spec/refile/features/normal_upload_spec.rb
@@ -370,6 +372,7 @@ test_files:
370
372
  - spec/refile/backend/file_system_spec.rb
371
373
  - spec/refile/backend/s3_spec.rb
372
374
  - spec/refile/backend_examples.rb
375
+ - spec/refile/backend_macros_spec.rb
373
376
  - spec/refile/custom_logger_spec.rb
374
377
  - spec/refile/features/direct_upload_spec.rb
375
378
  - spec/refile/features/normal_upload_spec.rb