require "cognac/version" require 'active_support/core_ext/numeric/time' require "erb" module Cognac class CloudFile def self.generate(file_name) "#{SecureRandom.hex(4).to_s}_#{file_name}" end def self.resource_end_point(bucket, file_name) "http://#{bucket}.s3.amazonaws.com/#{file_name}" end end # AWS Signature Version 2 : http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html class Signature NEW_LINE = "\n" def self.build_string_to_sign(options = {}) options = { http_verb: "PUT", content_md5: nil, content_type: nil, date: an_hour_from_now, amz_headers: [], resource: "" }.merge(options) add_new_line(options[:http_verb]) + add_new_line(options[:content_md5]) + add_new_line(options[:content_type]) + add_new_line(options[:date]) + (options[:amz_headers].any? ? (options[:amz_headers].join(NEW_LINE) + NEW_LINE) : "") + options[:resource] end def self.build_s3_rest_signature(secret_access_key, options = {}) s = build_string_to_sign(options).force_encoding("UTF-8") Base64.encode64(OpenSSL::HMAC.digest("sha1", secret_access_key, s)).strip end def self.build_s3_upload_url(end_point, aws_access_key, secret_access_key, signature_options = {}) signature = encoded_signature(secret_access_key, signature_options) expires = expiration(signature_options) "#{end_point}?AWSAccessKeyId=#{aws_access_key}&Expires=#{expires}&Signature=#{signature}" end def self.generate_options_for_build_s3_upload_url(bucket, file_name, content_type) { http_verb: "PUT", date: 1.hours.from_now.to_i, resource: "/#{bucket}/#{file_name}", content_type: content_type } end private def self.add_new_line(option) option.to_s + NEW_LINE end def self.an_hour_from_now 1.hours.from_now.rfc822 end def self.encoded_signature(secret_access_key, signature_options) ERB::Util.url_encode(build_s3_rest_signature(secret_access_key, signature_options)) end def self.expiration(signature_options) signature_options[:date] || an_hour_from_now end end end