implement random password generation through ajax
[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 allow retrieval of a password protected file" do
115     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
116                     'file_key' => 'somethingSecret',
117                     'upload_password' => UPLOAD_PASSWORD
118     last_response.redirect?.should be_true
119     follow_redirect!
120     last_response.should be_ok
121     doc = Hpricot(last_response.body)
122     url = (doc/'a').collect { |a| a.attributes['href'] }.
123       select { |h| h.start_with? "http://#{last_request.host}/" }[0]
124     get url
125     last_response.should be_ok
126     doc = Hpricot(last_response.body)
127     (doc/'input#file_key').should have(1).items
128     url = (doc/'form')[0].attributes['action']
129     post url, 'file_key' => 'somethingSecret'
130     last_response.should be_ok
131     last_response['Content-Type'].should eql('text/x-script.ruby')
132     last_response.body.should eql(File.new(__FILE__).read)
133   end
134
135   it "should not allow retrieval of a password protected file without the password" do
136     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
137                     'file_key' => 'somethingSecret',
138                     'upload_password' => UPLOAD_PASSWORD
139     last_response.redirect?.should be_true
140     follow_redirect!
141     last_response.should be_ok
142     doc = Hpricot(last_response.body)
143     url = (doc/'a').collect { |a| a.attributes['href'] }.
144       select { |h| h.start_with? "http://#{last_request.host}/" }[0]
145     get url
146     last_response.should be_ok
147     last_response['Content-Type'].should_not eql('text/x-script.ruby')
148     post url
149     last_response.status.should eql(403)
150   end
151
152   it "should not allow retrieval of a password protected file with a wrong password" do
153     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
154                     'file_key' => 'somethingSecret',
155                     'upload_password' => UPLOAD_PASSWORD
156     last_response.redirect?.should be_true
157     follow_redirect!
158     last_response.should be_ok
159     doc = Hpricot(last_response.body)
160     url = (doc/'a').collect { |a| a.attributes['href'] }.
161       select { |h| h.start_with? "http://#{last_request.host}/" }[0]
162     post url, 'file_key' => 'BAD'
163     last_response.status.should eql(403)
164   end
165
166   it "should not allow retrieval after the time limit has expired" do
167     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
168                     'expire' => 60,  # 1 hour
169                     'upload_password' => UPLOAD_PASSWORD
170     last_response.redirect?.should be_true
171     follow_redirect!
172     last_response.should be_ok
173     doc = Hpricot(last_response.body)
174     url = (doc/'a').collect { |a| a.attributes['href'] }.
175       select { |h| h.start_with? "http://#{last_request.host}/" }[0]
176     # let's be tomorrow
177     Timecop.travel(Date.today + 1) do
178       get url
179       last_response.status.should eql(410)
180     end
181   end
182
183   it "should cleanup expired files" do
184     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
185                     'expire' => 60,  # 1 hour
186                     'upload_password' => UPLOAD_PASSWORD
187     last_response.redirect?.should be_true
188     follow_redirect!
189     last_response.should be_ok
190     Dir.glob("#{Depot.instance.path}/*").should have(1).items
191     # let's be tomorrow
192     Timecop.travel(Date.today + 1) do
193       Depot.instance.gc!
194       Dir.glob("#{Depot.instance.path}/*").should have(0).items
195     end
196   end
197
198   it "should map extra base32 characters to filenames" do
199     post '/upload', 'file' => Rack::Test::UploadedFile.new(__FILE__, 'text/x-script.ruby'),
200                     'expire' => 60,  # 1 hour
201                     'upload_password' => UPLOAD_PASSWORD
202     last_response.redirect?.should be_true
203     follow_redirect!
204     last_response.should be_ok
205     doc = Hpricot(last_response.body)
206     url = (doc/'a').collect { |a| a.attributes['href'] }.
207       select { |h| h.start_with? "http://#{last_request.host}/" }[0]
208     splitted = url.split('/')
209     name = splitted[-1].upcase.gsub(/O/, '0').gsub(/L/, '1')
210     get "#{splitted[0..-2].join '/'}/#{name}"
211     last_response.should be_ok
212     last_response['Content-Type'].should eql('text/x-script.ruby')
213   end
214 end