require 'gem_plugin' require 'mongrel' require 'digest/sha1' require 'active_crypto' class CryptedDownload < GemPlugin::Plugin "/handlers" include Mongrel::HttpHandlerPlugin def process(request, response) query = Mongrel::HttpRequest.query_parse(request.params['QUERY_STRING']) cookies = Mongrel::HttpRequest.query_parse(request.params['HTTP_COOKIE']) secret_string = cookies.keys.first query['path'] = CGI::unescape(query['path']) key=EzCrypto::Key.with_password secret_string, secret_string query['path']=key.decrypt query['path'] if secret_string.nil? or query['timestamp'].nil? or query['path'].nil? response.start(500){} elsif query['timestamp'].to_i < Time.now.to_i response.start(408){} else send_file(File.expand_path("." + query['path'] + query['file-name']), response) end end def self.generate(file_name, path, uri_prefix, request) secret_string = request.cookies.keys.first key=EzCrypto::Key.with_password secret_string, secret_string path=key.encrypt path timestamp = 1.minute.from_now.to_i.to_s path = CGI::escape(path) return "#{uri_prefix}/?path=#{path}&file-name=#{file_name}×tamp=#{timestamp}" end private # Sends the contents of a file back to the user. def send_file(path, response) # first we setup the headers and status then we do a very fast send on the socket directly file_status = File.stat(path) response.status = 200 # Set the last modified times as well and etag for all files response.header[Mongrel::Const::LAST_MODIFIED] = file_status.mtime.httpdate # Calculated the same as apache, not sure how well the works on win32 response.header[Mongrel::Const::ETAG] = Mongrel::Const::ETAG_FORMAT % [file_status.mtime.to_i, file_status.size, file_status.ino] #set the content type to something generic for now response.header[Mongrel::Const::CONTENT_TYPE] = @default_content_type #set the content disposition and filename response.header['Content-Disposition'] = "attachment; filename=\"#{File.basename(path)}\"" # send a status with out content length response.send_status(file_status.size) response.send_header response.send_file(path) end end