1 $:.unshift File.join(File.dirname(__FILE__), '../rack-test/lib')
2 $:.unshift File.join(File.dirname(__FILE__), '../timecop/lib')
5 require 'coquelicot_app'
12 UPLOAD_PASSWORD = 'secret'
14 set :environment, :test
15 set :upload_password, Digest::SHA1.hexdigest(UPLOAD_PASSWORD)
17 describe 'Coquelicot' do
18 include Rack::Test::Methods
25 opts = { :file => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
26 :upload_password => UPLOAD_PASSWORD
29 return nil unless last_response.redirect?
31 last_response.should be_ok
32 doc = Hpricot(last_response.body)
33 return (doc/'a').collect { |a| a.attributes['href'] }.
34 select { |h| h.start_with? "http://#{last_request.host}/" }[0]
38 Coquelicot.setup :depot_path => Dir.mktmpdir('coquelicot') #"#{Time.now.to_f}"
42 FileUtils.remove_entry_secure Coquelicot.depot.path
45 it "should offer an upload form" do
47 last_response.should be_ok
48 doc = Hpricot(last_response.body)
49 (doc/"form#upload").should have(1).items
52 it "should allow retrieval of an uploaded file" do
55 last_response.should be_ok
56 last_response['Content-Type'].should eql('text/x-script.ruby')
57 last_response.body.should eql(File.new(__FILE__).read)
60 it "should correctly set Last-Modified header when downloading" do
63 last_modified = last_response['Last-Modified']
64 last_modified.should_not be_nil
66 last_response['Last-Modified'].should eql(last_modified)
69 it "should prevent upload without a password" do
70 url = upload :upload_password => ''
72 last_response.status.should eql(403)
75 it "should prevent upload with a wrong password" do
76 url = upload :upload_password => "bad"
78 last_response.status.should eql(403)
81 it "should not store an uploaded file in cleartext" do
83 files = Dir.glob("#{Coquelicot.depot.path}/*")
84 files.should have(1).items
85 File.new(files[0]).read().should_not include('should not store an uploaded file')
88 it "should generate a random URL to retrieve a file" do
90 url.should_not include(File.basename(__FILE__))
93 it "should store files with a different name than then one in URL" do
95 url_name = url.split('/')[-1]
96 files = Dir.glob("#{Coquelicot.depot.path}/*")
97 files.should have(1).items
98 url_name.should_not eql(File.basename(files[0]))
101 it "should encode the encryption key in URL when no password has been specified" do
103 url_name = url.split('/')[-1]
104 url_name.split('-').should have(2).items
107 it "should not encode the encryption key in URL when a password has been specified" do
108 url = upload :file_key => 'somethingSecret'
109 url_name = url.split('/')[-1]
110 url_name.split('-').should have(1).items
113 it "should only allow one time download to be retrieved once" do
114 url = upload :one_time => true
116 last_response.should be_ok
117 last_response['Content-Type'].should eql('text/x-script.ruby')
118 last_response.body.should eql(File.new(__FILE__).read)
120 last_response.status.should eql(410)
123 it "should have files zero'ed after 'one time' download" do
124 url = upload :one_time => true
126 files = Dir.glob("#{Coquelicot.depot.path}/*")
127 files.should have(1).items
128 File.lstat(files[0]).size.should eql(0)
131 it "should allow retrieval of a password protected file" do
132 url = upload :file_key => 'somethingSecret'
134 last_response.should be_ok
135 doc = Hpricot(last_response.body)
136 (doc/'input#file_key').should have(1).items
137 url = (doc/'form')[0].attributes['action']
138 post url, :file_key => 'somethingSecret'
139 last_response.should be_ok
140 last_response['Content-Type'].should eql('text/x-script.ruby')
141 last_response.body.should eql(File.new(__FILE__).read)
144 it "should not allow retrieval of a password protected file without the password" do
145 url = upload :file_key => 'somethingSecret'
147 last_response.should be_ok
148 last_response['Content-Type'].should_not eql('text/x-script.ruby')
150 last_response.status.should eql(403)
153 it "should not allow retrieval of a password protected file with a wrong password" do
154 url = upload :file_key => 'somethingSecret'
155 post url, :file_key => 'BAD'
156 last_response.status.should eql(403)
159 it "should not allow retrieval after the time limit has expired" do
160 url = upload :expire => 60 # 1 hour
162 Timecop.travel(Date.today + 1) do
164 last_response.status.should eql(410)
168 it "should not allow an expiration time longer than the maximum" do
169 upload :expire => 60 * 24 * 31 * 12 # 1 year
170 last_response.status.should eql(403)
173 it "should cleanup expired files" do
174 url = upload :expire => 60, :file_key => 'test' # 1 hour
175 url_name = url.split('/')[-1]
176 Dir.glob("#{Coquelicot.depot.path}/*").should have(1).items
178 Timecop.travel(Date.today + 1) do
180 files = Dir.glob("#{Coquelicot.depot.path}/*")
181 files.should have(1).items
182 File.lstat(files[0]).size.should eql(0)
183 Coquelicot.depot.get_file(url_name).expired?.should be_true
185 # let's be after 'gone' period
186 Timecop.travel(Time.now + (Coquelicot.settings.gone_period * 60)) do
188 Dir.glob("#{Coquelicot.depot.path}/*").should have(0).items
189 Coquelicot.depot.get_file(url_name).should be_nil
193 it "should map extra base32 characters to filenames" do
194 url = upload :expire => 60 # 1 hour
195 splitted = url.split('/')
196 name = splitted[-1].upcase.gsub(/O/, '0').gsub(/L/, '1')
197 get "#{splitted[0..-2].join '/'}/#{name}"
198 last_response.should be_ok
199 last_response['Content-Type'].should eql('text/x-script.ruby')