1 $:.unshift File.join(File.dirname(__FILE__), 'lib')
11 set :upload_password, '0e5f7d398e6f9cd1f6bac5cc823e363aec636495'
13 def password_match?(password)
14 return TRUE if settings.upload_password.nil?
15 (not password.nil?) && Digest::SHA1.hexdigest(password) == settings.upload_password
18 GetText::bindtextdomain('coquelicot')
20 GetText::set_current_locale(params[:lang] || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en')
24 content_type 'text/css', :charset => 'utf-8'
33 "#{Coquelicot.gen_random_pass}"
36 get '/ready/:link' do |link|
37 link, pass = link.split '-' if link.include? '-'
39 file = Coquelicot.depot.get_file(link, nil)
40 rescue Errno::ENOENT => ex
43 @expire_at = file.expire_at
44 @base = request.url.gsub(/\/ready\/[^\/]*$/, '')
50 @url = "#{@base}/#{@name}"
54 post '/authenticate' do
55 pass unless request.xhr?
56 unless password_match? params[:upload_password] then
57 error 403, "Forbidden"
63 unless password_match? params[:upload_password] then
67 tmpfile = params[:file][:tempfile]
68 name = params[:file][:filename]
70 if tmpfile.nil? || name.nil? then
71 @error = "No file selected"
74 if params[:expire].nil? or params[:expire].to_i == 0 then
75 params[:expire] = Coquelicot.settings.default_expire
76 elsif params[:expire].to_i > Coquelicot.settings.maximum_expire then
79 expire_at = Time.now + 60 * params[:expire].to_i
80 one_time_only = params[:one_time] and params[:one_time] == 'true'
81 if params[:file_key].nil? or params[:file_key].empty?then
82 pass = Coquelicot.gen_random_pass
84 pass = params[:file_key]
86 src = params[:file][:tempfile]
87 link = Coquelicot.depot.add_file(
89 { "Expire-at" => expire_at.to_i,
90 "One-time-only" => one_time_only,
91 "Filename" => params[:file][:filename],
92 "Length" => src.stat.size,
93 "Content-Type" => params[:file][:type],
95 redirect "ready/#{link}-#{pass}" if params[:file_key].nil? or params[:file_key].empty?
96 redirect "ready/#{link}"
100 throw :halt, [410, haml(:expired)]
103 def send_stored_file(file)
104 last_modified file.created_at.httpdate
105 attachment file.meta['Filename']
106 response['Content-Length'] = "#{file.meta['Length']}"
107 response['Content-Type'] = file.meta['Content-Type'] || 'application/octet-stream'
108 throw :halt, [200, file]
114 @lockfile ||= Lockfile.new "#{File.expand_path(@path)}.lock", :timeout => 4
119 yield @initial_content
120 @initial_content = nil
121 until (buf = @file.read(BUFFER_LEN)).nil?
122 yield @cipher.update(buf)
135 empty! if @fully_sent
142 def send_link(link, pass)
143 file = Coquelicot.depot.get_file(link, pass)
144 return false if file.nil?
145 return expired if file.expired?
147 if file.one_time_only?
149 # unlocking done in file.close
151 rescue Lockfile::TimeoutLockError
152 error 409, "Download currently in progress"
155 send_stored_file(file)
158 get '/:link-:pass' do |link, pass|
159 link = Coquelicot.remap_base32_extra_characters(link)
160 pass = Coquelicot.remap_base32_extra_characters(pass)
161 not_found unless send_link(link, pass)
164 get '/:link' do |link|
165 link = Coquelicot.remap_base32_extra_characters(link)
166 not_found unless Coquelicot.depot.file_exists? link
171 post '/:link' do |link|
172 pass = params[:file_key]
173 return 403 if pass.nil? or pass.empty?
175 # send Forbidden even if file is not found
176 return 403 unless send_link(link, pass)
177 rescue Coquelicot::BadKey => ex
184 url = request.scheme + "://"
186 if request.scheme == "https" && request.port != 443 ||
187 request.scheme == "http" && request.port != 80
188 url << ":#{request.port}"
190 url << request.script_name