implement 'should map extra base32 characters to filenames'
[coquelicot.git] / test_coquelicot.rb
1 $:.unshift File.join(File.dirname(__FILE__), '../rack-test/lib')
2 $:.unshift File.join(File.dirname(__FILE__), '../timecop/lib')
3
4 require 'sinatra'
5 require 'coquelicot'
6 require 'spec'
7 require 'rack/test'
8 require 'timecop'
9 require 'hpricot'
10 require 'tmpdir'
11
12 UPLOAD_PASSWORD = 'secret'
13
14 set :environment, :test
15 set :upload_password, Digest::SHA1.hexdigest(UPLOAD_PASSWORD)
16
17 describe 'Coquelicot' do
18   include Rack::Test::Methods
19
20   def app
21     Sinatra::Application
22   end
23
24   before do
25     Depot.instance.path = Dir.mktmpdir('coquelicot') #"#{Time.now.to_f}"
26   end
27
28   after do
29     FileUtils.remove_entry_secure Depot.instance.path
30   end
31
32   it "should offer an upload form" do
33     get '/'
34     last_response.should be_ok
35     doc = Hpricot(last_response.body)
36     (doc/"form#upload").should have(1).items
37   end
38
39   it "should accept an uploaded file" do
40     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
41                     'upload_password' => UPLOAD_PASSWORD
42     last_response.redirect?.should be_true
43     last_response['Location'].start_with?('ready/').should be_true
44   end
45
46   it "should allow retrieval of an uploaded file" do
47     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
48                     'upload_password' => UPLOAD_PASSWORD
49     follow_redirect!
50     last_response.should be_ok
51     doc = Hpricot(last_response.body)
52     url = (doc/'a').collect { |a| a.attributes['href'] }.
53       select { |h| h.start_with? "http://#{last_request.host}/" }[0]
54     get url
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)
58   end
59
60   it "should prevent upload without a password" do
61     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby')
62     last_response.status.should eql(403)
63   end
64
65   it "should prevent upload with a wrong password" do
66     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
67                     'upload_password' => "bad"
68     last_response.status.should eql(403)
69   end
70
71   it "should not store an uploaded file in cleartext" do
72     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
73                     'upload_password' => UPLOAD_PASSWORD
74     last_response.redirect?.should be_true
75     files = Dir.glob("#{Depot.instance.path}/*")
76     files.should have(1).items
77     File.new(files[0]).read().should_not include('should not store an uploaded file')
78   end
79
80   it "should generate a random URL to retrieve a file" do
81     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
82                     'upload_password' => UPLOAD_PASSWORD
83     last_response.redirect?.should be_true
84     last_response['Location'].should_not include(File.basename(__FILE__))
85   end
86
87   it "should store files with a different name than then one in URL" do
88     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
89                     'upload_password' => UPLOAD_PASSWORD
90     last_response.redirect?.should be_true
91     url_name = last_response['Location'].split('/')[-1]
92     files = Dir.glob("#{Depot.instance.path}/*")
93     files.should have(1).items
94     url_name.should_not eql(File.basename(files[0]))
95   end
96
97   it "should encode the encryption key in URL when no password has been specified" do
98     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
99                     'upload_password' => UPLOAD_PASSWORD
100     last_response.redirect?.should be_true
101     url_name = last_response['Location'].split('/')[-1]
102     url_name.split('-').should have(2).items
103   end
104
105   it "should not encode the encryption key in URL when a password has been specified" do
106     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
107                     'file_key' => 'somethingSecret',
108                     'upload_password' => UPLOAD_PASSWORD
109     last_response.redirect?.should be_true
110     url_name = last_response['Location'].split('/')[-1]
111     url_name.split('-').should have(1).items
112   end
113
114   it "should give a random password when asked"
115
116   it "should allow retrieval of a password protected file" do
117     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
118                     'file_key' => 'somethingSecret',
119                     'upload_password' => UPLOAD_PASSWORD
120     last_response.redirect?.should be_true
121     follow_redirect!
122     last_response.should be_ok
123     doc = Hpricot(last_response.body)
124     url = (doc/'a').collect { |a| a.attributes['href'] }.
125       select { |h| h.start_with? "http://#{last_request.host}/" }[0]
126     get url
127     last_response.should be_ok
128     doc = Hpricot(last_response.body)
129     (doc/'input#file_key').should have(1).items
130     url = (doc/'form')[0].attributes['action']
131     post url, 'file_key' => 'somethingSecret'
132     last_response.should be_ok
133     last_response['Content-Type'].should eql('text/x-script.ruby')
134     last_response.body.should eql(File.new(__FILE__).read)
135   end
136
137   it "should not allow retrieval of a password protected file without the password" do
138     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
139                     'file_key' => 'somethingSecret',
140                     'upload_password' => UPLOAD_PASSWORD
141     last_response.redirect?.should be_true
142     follow_redirect!
143     last_response.should be_ok
144     doc = Hpricot(last_response.body)
145     url = (doc/'a').collect { |a| a.attributes['href'] }.
146       select { |h| h.start_with? "http://#{last_request.host}/" }[0]
147     get url
148     last_response.should be_ok
149     last_response['Content-Type'].should_not eql('text/x-script.ruby')
150     post url
151     last_response.status.should eql(403)
152   end
153
154   it "should not allow retrieval of a password protected file with a wrong password" do
155     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
156                     'file_key' => 'somethingSecret',
157                     'upload_password' => UPLOAD_PASSWORD
158     last_response.redirect?.should be_true
159     follow_redirect!
160     last_response.should be_ok
161     doc = Hpricot(last_response.body)
162     url = (doc/'a').collect { |a| a.attributes['href'] }.
163       select { |h| h.start_with? "http://#{last_request.host}/" }[0]
164     post url, 'file_key' => 'BAD'
165     last_response.status.should eql(403)
166   end
167
168   it "should not allow retrieval after the time limit has expired" do
169     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
170                     'expire' => 60,  # 1 hour
171                     'upload_password' => UPLOAD_PASSWORD
172     last_response.redirect?.should be_true
173     follow_redirect!
174     last_response.should be_ok
175     doc = Hpricot(last_response.body)
176     url = (doc/'a').collect { |a| a.attributes['href'] }.
177       select { |h| h.start_with? "http://#{last_request.host}/" }[0]
178     # let's be tomorrow
179     Timecop.travel(Date.today + 1) do
180       get url
181       last_response.status.should eql(410)
182     end
183   end
184
185   it "should cleanup expired files" do
186     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
187                     'expire' => 60,  # 1 hour
188                     'upload_password' => UPLOAD_PASSWORD
189     last_response.redirect?.should be_true
190     follow_redirect!
191     last_response.should be_ok
192     Dir.glob("#{Depot.instance.path}/*").should have(1).items
193     # let's be tomorrow
194     Timecop.travel(Date.today + 1) do
195       Depot.instance.gc!
196       Dir.glob("#{Depot.instance.path}/*").should have(0).items
197     end
198   end
199
200   it "should map extra base32 characters to filenames" do
201     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
202                     'expire' => 60,  # 1 hour
203                     'upload_password' => UPLOAD_PASSWORD
204     last_response.redirect?.should be_true
205     follow_redirect!
206     last_response.should be_ok
207     doc = Hpricot(last_response.body)
208     url = (doc/'a').collect { |a| a.attributes['href'] }.
209       select { |h| h.start_with? "http://#{last_request.host}/" }[0]
210     splitted = url.split('/')
211     name = splitted[-1].upcase.gsub(/O/, '0').gsub(/L/, '1')
212     get "#{splitted[0..-2].join '/'}/#{name}"
213     last_response.should be_ok
214     last_response['Content-Type'].should eql('text/x-script.ruby')
215   end
216 end