paperclip-nginx-upload 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +16 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +125 -0
- data/Rakefile +1 -0
- data/examples/nginx.conf +23 -0
- data/lib/paperclip/nginx/upload.rb +9 -0
- data/lib/paperclip/nginx/upload/io_adapter.rb +75 -0
- data/lib/paperclip/nginx/upload/version.rb +7 -0
- data/paperclip-nginx-upload.gemspec +25 -0
- data/spec/fixtures/5k.png +0 -0
- data/spec/paperclip/nginx/upload/io_adapter_spec.rb +93 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/support/fixture_file.rb +10 -0
- metadata +135 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Tim Fischbach
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
# Paperclip Nginx Upload
|
2
|
+
|
3
|
+
[](https://travis-ci.org/tf/paperclip-nginx-upload)
|
4
|
+
|
5
|
+
A Paperclip IOAdapter to handle file upload requests which have been
|
6
|
+
rewritten by the
|
7
|
+
[nginx upload module](https://github.com/vkholodkov/nginx-upload-module).
|
8
|
+
|
9
|
+
The gem evolved out of the discussion in the following paperclip
|
10
|
+
issue:
|
11
|
+
|
12
|
+
https://github.com/thoughtbot/paperclip/issues/1396
|
13
|
+
|
14
|
+
## Motivation
|
15
|
+
|
16
|
+
Nginx is must faster when it comes to parsing file uploads from the
|
17
|
+
body of HTTP requests. We do not want to occupy our Rails processes
|
18
|
+
with this tasks. Using the
|
19
|
+
[nginx upload module](https://github.com/vkholodkov/nginx-upload-module),
|
20
|
+
upload request can be rewritten to contain the path of a temp file
|
21
|
+
parsed from the request body before they are passed to our Rails app.
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
Add this line to your application's Gemfile:
|
26
|
+
|
27
|
+
gem 'paperclip-nginx-upload'
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
Configure nginx to parse your upload requests. There is an example
|
32
|
+
nginx configuration snippet in `examples/nginx.conf`.
|
33
|
+
|
34
|
+
Add an initializer to configure the gem:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
# config/intializers/paperclip_nginx_upload.rb
|
38
|
+
require 'paperclip/nginx/upload'
|
39
|
+
|
40
|
+
Paperclip::Nginx::Upload::IOAdapter.default_options.merge!(
|
41
|
+
# location where nginx places file uploads
|
42
|
+
tmp_file_whitelist: ['/tmp/nginx_uploads/**'],
|
43
|
+
|
44
|
+
# Change this option to true to move temp files created
|
45
|
+
# by nginx to the paperclip tmp file location. By default
|
46
|
+
# files are copied.
|
47
|
+
move_tempfile: false
|
48
|
+
)
|
49
|
+
```
|
50
|
+
|
51
|
+
The adapter is a drop in replacement. When using strong parameters,
|
52
|
+
you only have to make sure the param containing the upload can also be
|
53
|
+
a hash of values:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
class User
|
57
|
+
has_attached_file :avatar
|
58
|
+
end
|
59
|
+
|
60
|
+
class UsersController < ApplicationController
|
61
|
+
def update
|
62
|
+
@user.update_attributes(user_params)
|
63
|
+
end
|
64
|
+
|
65
|
+
def user_params
|
66
|
+
params.require(:user)
|
67
|
+
# in production avatar will be a hash generated by nginx
|
68
|
+
.permit(avatar: [:tmp_path, :original_name, :content_type])
|
69
|
+
|
70
|
+
# in development we want to permit the uploaded file itself
|
71
|
+
.merge(params.require(:user).permit(:avatar))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
## Security Considerations
|
77
|
+
|
78
|
+
Assume an upload request contains a form field named
|
79
|
+
`user[avatar]`. Given the nginx configuration from
|
80
|
+
`examples/nginx.conf`, the request is rewritten to contain the
|
81
|
+
following three form fields instead:
|
82
|
+
|
83
|
+
* `user[avatar][original_name]`
|
84
|
+
* `user[avatar][conten_type]`
|
85
|
+
* `user[avatar][upload_tmp_path]`
|
86
|
+
|
87
|
+
By using this gem, you basically tell your app to accept paths to
|
88
|
+
local files in the `upload_tmp_path` param and move them around the
|
89
|
+
file system. Nginx ensures that these parameters can not be passed in
|
90
|
+
from the outside, preventing an attacker from passing `/etc/passwd` as
|
91
|
+
`upload_tmp_path` and having it delivered to him as his own upload
|
92
|
+
later on.
|
93
|
+
|
94
|
+
Still, if you forget to configure the nginx-upload-module correctly
|
95
|
+
for one of your upload end points, this could become a threat. This is
|
96
|
+
especially dangerous when not using strong parameters. While, as seen
|
97
|
+
above, the nested hash has to be permitted explicitly, methods
|
98
|
+
assigning attachments directly might be open to attacks:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
@user.avatar = params[:avatar]
|
102
|
+
```
|
103
|
+
|
104
|
+
Therefore the paperclip-nginx-upload adapter only accepts tmp files
|
105
|
+
from locations matching an entry in the `tmp_file_whitelist`. That way
|
106
|
+
an attacker will only be able to access running uploads of other
|
107
|
+
visitors of the site. He still would have to guess the random file
|
108
|
+
names chosen by nginx, which seems rather unfeasable.
|
109
|
+
|
110
|
+
## Move vs Copy
|
111
|
+
|
112
|
+
By default, temp files created by ngninx are copied before passing
|
113
|
+
them to Paperclip. This ensures proper file ownership. When your nginx
|
114
|
+
runs as the same user as your rails processes, it might be sufficient
|
115
|
+
to simply move the file. Depending on your file system, this might be
|
116
|
+
a significant performance gain. In that case set `move_tempfile` to
|
117
|
+
`true`.
|
118
|
+
|
119
|
+
## Contributing
|
120
|
+
|
121
|
+
1. Fork it
|
122
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
123
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
124
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
125
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/examples/nginx.conf
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
location ~ ^/entries/[0-9]+/files$ {
|
2
|
+
upload_pass @app;
|
3
|
+
|
4
|
+
upload_store /tmp/nginx_uploads 1;
|
5
|
+
upload_store_access user:rw group:rw all:r;
|
6
|
+
|
7
|
+
upload_set_form_field $upload_field_name[original_name] "$upload_file_name";
|
8
|
+
upload_set_form_field $upload_field_name[content_type] "$upload_content_type";
|
9
|
+
upload_set_form_field $upload_field_name[tmp_path] "$upload_tmp_path";
|
10
|
+
|
11
|
+
upload_pass_form_field "^authenticity_token$|^format$";
|
12
|
+
upload_cleanup 400 404 500-505;
|
13
|
+
|
14
|
+
# Catch "Method not allowed" raised for non-POST requests and
|
15
|
+
# delegate to app
|
16
|
+
error_page 405 = @app;
|
17
|
+
}
|
18
|
+
|
19
|
+
location @app {
|
20
|
+
passenger_enabled on;
|
21
|
+
|
22
|
+
...
|
23
|
+
}
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'paperclip'
|
3
|
+
|
4
|
+
module Paperclip
|
5
|
+
module Nginx
|
6
|
+
module Upload
|
7
|
+
class TmpPathNotInWhitelistError < StandardError
|
8
|
+
def initialize(tmp_path, whitelist)
|
9
|
+
super("Paperclip nginx upload adapter received non whitelisted tmp file '#{tmp_path}'. " +
|
10
|
+
"Whitelist: #{whitelist.inspect}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class IOAdapter < Paperclip::AbstractAdapter
|
15
|
+
def initialize(target, options = {})
|
16
|
+
@target = target
|
17
|
+
@options = self.class.default_options.merge(options)
|
18
|
+
|
19
|
+
require_whitelist_match!(@target[:tmp_path])
|
20
|
+
cache_current_values
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.default_options
|
24
|
+
@default_options ||= {
|
25
|
+
:tmp_path_whitelist => [],
|
26
|
+
:move_tempfile => false
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def require_whitelist_match!(path)
|
33
|
+
unless matches_whitelist?(File.expand_path(path))
|
34
|
+
raise TmpPathNotInWhitelistError.new(path, tmp_path_whitelist)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def matches_whitelist?(path)
|
39
|
+
tmp_path_whitelist.any? do |glob|
|
40
|
+
File.fnmatch(glob, path)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def tmp_path_whitelist
|
45
|
+
@options[:tmp_path_whitelist]
|
46
|
+
end
|
47
|
+
|
48
|
+
def cache_current_values
|
49
|
+
self.original_filename = @target[:original_name]
|
50
|
+
@content_type = @target[:content_type].to_s.strip
|
51
|
+
@size = File.size(@target[:tmp_path])
|
52
|
+
|
53
|
+
copy_or_move(@target[:tmp_path], destination.path)
|
54
|
+
@tempfile = destination
|
55
|
+
|
56
|
+
# Required to reopen the tempfile that we have overwritten
|
57
|
+
@tempfile.open
|
58
|
+
@tempfile.binmode
|
59
|
+
end
|
60
|
+
|
61
|
+
def copy_or_move(source_path, destination_path)
|
62
|
+
if @options[:move_tempfile]
|
63
|
+
FileUtils.mv(@target[:tmp_path], destination.path)
|
64
|
+
else
|
65
|
+
FileUtils.cp(@target[:tmp_path], destination.path)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
Paperclip.io_adapters.register Paperclip::Nginx::Upload::IOAdapter do |target|
|
74
|
+
Hash === target && [:original_name, :content_type, :tmp_path].all? { |key| target.key?(key) }
|
75
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'paperclip/nginx/upload/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "paperclip-nginx-upload"
|
8
|
+
spec.version = Paperclip::Nginx::Upload::VERSION
|
9
|
+
spec.authors = ["Tim Fischbach"]
|
10
|
+
spec.email = ["tfischbach@codevise.de"]
|
11
|
+
spec.summary = "Paperclip IOAdapter for integration with nginx upload module"
|
12
|
+
spec.homepage = "https://github.com/tf/paperclip-nignx-upload"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_runtime_dependency "paperclip"
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
end
|
Binary file
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Paperclip::Nginx::Upload::IOAdapter do
|
4
|
+
context 'for tmp file in whitelist' do
|
5
|
+
let :tempfile do
|
6
|
+
fixture_file('5k.png').binmode
|
7
|
+
end
|
8
|
+
|
9
|
+
subject do
|
10
|
+
nginx_upload_hash = {
|
11
|
+
:original_name => '5k.png',
|
12
|
+
:tmp_path => tempfile.path,
|
13
|
+
:content_type => "image/x-png-by-browser\r"
|
14
|
+
}
|
15
|
+
|
16
|
+
options = {
|
17
|
+
:tmp_path_whitelist => [File.join(PROJECT_ROOT, 'spec', 'tmp', '**')]
|
18
|
+
}
|
19
|
+
|
20
|
+
Paperclip::Nginx::Upload::IOAdapter.new(nginx_upload_hash, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'gets the right filename' do
|
24
|
+
expect(subject.original_filename).to eq('5k.png')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'gets content type' do
|
28
|
+
expect(subject.content_type).to eq('image/x-png-by-browser')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'gets the file\'s size' do
|
32
|
+
expect(subject.size).to eq(4456)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns false for a call to nil?' do
|
36
|
+
expect(subject.nil?).to be(false)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'generates a MD5 hash of the contents' do
|
40
|
+
hash = Digest::MD5.file(tempfile.path).to_s
|
41
|
+
expect(subject.fingerprint).to eq(hash)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'reads the contents of the file' do
|
45
|
+
content = tempfile.read
|
46
|
+
expect(content.length).to be > 0
|
47
|
+
expect(subject.read).to eq(content)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'copies the tempfile by default' do
|
51
|
+
subject
|
52
|
+
expect(File.exist?(tempfile.path)).to eq(true)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'for tmp file not in whitelist' do
|
57
|
+
let :tempfile do
|
58
|
+
fixture_file('5k.png').binmode
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'raises an exception' do
|
62
|
+
nginx_upload_hash = {
|
63
|
+
:original_name => '5k.png',
|
64
|
+
:tmp_path => tempfile.path,
|
65
|
+
:content_type => "image/x-png-by-browser\r"
|
66
|
+
}
|
67
|
+
|
68
|
+
expect {
|
69
|
+
Paperclip::Nginx::Upload::IOAdapter.new(nginx_upload_hash, :tmp_path_whitelist => [])
|
70
|
+
}.to raise_error(Paperclip::Nginx::Upload::TmpPathNotInWhitelistError)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'with move_tempfile option set to true' do
|
75
|
+
let :tempfile do
|
76
|
+
fixture_file('5k.png').binmode
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'moves the tempfile to the new location' do
|
80
|
+
nginx_upload_hash = {
|
81
|
+
:original_name => '5k.png',
|
82
|
+
:tmp_path => tempfile.path,
|
83
|
+
:content_type => "image/x-png-by-browser\r"
|
84
|
+
}
|
85
|
+
|
86
|
+
Paperclip::Nginx::Upload::IOAdapter.new(nginx_upload_hash,
|
87
|
+
:tmp_path_whitelist => [File.join(PROJECT_ROOT, 'spec', 'tmp', '**')],
|
88
|
+
:move_tempfile => true)
|
89
|
+
|
90
|
+
expect(File.exist?(tempfile.path)).to eq(false)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
|
3
|
+
PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..')).freeze
|
4
|
+
$LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
|
5
|
+
|
6
|
+
require 'paperclip/nginx/upload'
|
7
|
+
|
8
|
+
Dir[File.join(PROJECT_ROOT, 'spec', 'support', '**', '*.rb')].each { |file| require(file) }
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
FIXTURE_DIR = File.join(File.dirname(__FILE__), '..', 'fixtures')
|
4
|
+
TMP_DIR = File.join(File.dirname(__FILE__), '..', 'tmp')
|
5
|
+
|
6
|
+
def fixture_file(filename)
|
7
|
+
FileUtils.mkdir_p(TMP_DIR)
|
8
|
+
FileUtils.cp(File.join(FIXTURE_DIR, filename), File.join(TMP_DIR, filename))
|
9
|
+
File.new(File.join(TMP_DIR, filename))
|
10
|
+
end
|
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: paperclip-nginx-upload
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tim Fischbach
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-02-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: paperclip
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.3'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.3'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description:
|
79
|
+
email:
|
80
|
+
- tfischbach@codevise.de
|
81
|
+
executables: []
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- .gitignore
|
86
|
+
- .travis.yml
|
87
|
+
- Gemfile
|
88
|
+
- LICENSE.txt
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
91
|
+
- examples/nginx.conf
|
92
|
+
- lib/paperclip/nginx/upload.rb
|
93
|
+
- lib/paperclip/nginx/upload/io_adapter.rb
|
94
|
+
- lib/paperclip/nginx/upload/version.rb
|
95
|
+
- paperclip-nginx-upload.gemspec
|
96
|
+
- spec/fixtures/5k.png
|
97
|
+
- spec/paperclip/nginx/upload/io_adapter_spec.rb
|
98
|
+
- spec/spec_helper.rb
|
99
|
+
- spec/support/fixture_file.rb
|
100
|
+
homepage: https://github.com/tf/paperclip-nignx-upload
|
101
|
+
licenses:
|
102
|
+
- MIT
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ! '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
segments:
|
114
|
+
- 0
|
115
|
+
hash: 1774978758898476396
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
segments:
|
123
|
+
- 0
|
124
|
+
hash: 1774978758898476396
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 1.8.25
|
128
|
+
signing_key:
|
129
|
+
specification_version: 3
|
130
|
+
summary: Paperclip IOAdapter for integration with nginx upload module
|
131
|
+
test_files:
|
132
|
+
- spec/fixtures/5k.png
|
133
|
+
- spec/paperclip/nginx/upload/io_adapter_spec.rb
|
134
|
+
- spec/spec_helper.rb
|
135
|
+
- spec/support/fixture_file.rb
|