include gem 's3-directupload-helper', :git => "git://gist.github.com/5202809.git", :require => "s3_directupload_helper" in your Gemfile
S3DirectuploadHelper::Uploader.new({}).fields contains the signature.
| Gem::Specification.new do |s| | |
| s.name = 's3-directupload-helper' | |
| s.version = '0.0.1' | |
| s.platform = Gem::Platform::RUBY | |
| s.author = 'Raykin' | |
| s.email = '[email protected]' | |
| s.summary = 'easy create s3 directupload form in rails' | |
| s.description = 'clear and easy' | |
| s.files = ['s3_directupload_helper.rb'] | |
| s.require_path = '.' | |
| end |
| module S3DirectuploadHelper | |
| class AccessConfig < Struct.new(:access_key_id, :secret_access_key, :bucket, :region) | |
| include Singleton | |
| end | |
| # setup s3 config in config/initializers/an_override_file.rb works | |
| def self.access_config | |
| if block_given? | |
| yield AccessConfig.instance | |
| end | |
| AccessConfig.instance | |
| end | |
| def self.access_config_blank? | |
| access_config.access_key_id.nil? | |
| end | |
| # setup s3 config by ENV works too | |
| def self.init_access_config | |
| access_config do |config| | |
| config.access_key_id = ENV['s3_access_key_id'] || ENV['S3_ACCESS_KEY_ID'] | |
| config.secret_access_key = ENV['s3_secret_access_key'] || ENV['S3_SECRET_ACCESS_KEY'] | |
| config.bucket = ENV['s3_bucket'] || ENV['S3_BUCKET'] | |
| end | |
| end | |
| class Uploader | |
| def initialize(options) | |
| S3DirectuploadHelper.init_access_config if S3DirectuploadHelper.access_config_blank? | |
| @options = options.reverse_merge( | |
| aws_access_key_id: S3DirectuploadHelper.access_config.access_key_id, | |
| aws_secret_access_key: S3DirectuploadHelper.access_config.secret_access_key, | |
| bucket: S3DirectuploadHelper.access_config.bucket, | |
| region: S3DirectuploadHelper.access_config.region || "s3", | |
| acl: "public-read", | |
| expiration: 10.hours.from_now.utc.iso8601, | |
| max_file_size: 500.megabytes, | |
| as: "file", | |
| key: default_key | |
| ) | |
| end | |
| def form_options | |
| { | |
| id: @options[:id], | |
| class: @options[:class], | |
| method: "post", | |
| authenticity_token: false, | |
| multipart: true, | |
| data: { | |
| post: @options[:post], | |
| as: @options[:as] | |
| }.reverse_merge(@options[:data] || {}) | |
| } | |
| end | |
| def fields | |
| { | |
| :key => @options[:key] || default_key, | |
| :acl => @options[:acl], | |
| "AWSAccessKeyId" => @options[:aws_access_key_id], | |
| :policy => policy, | |
| :signature => signature, | |
| :success_action_status => "201", | |
| 'X-Requested-With' => 'xhr', | |
| :utf8 => true, | |
| 'Content-Type' => '' | |
| } | |
| end | |
| def default_key | |
| @key ||= "uploads/#{DateTime.now.utc.strftime("%Y%m%dT%H%MZ")}_#{SecureRandom.hex}/${filename}" | |
| end | |
| def url | |
| "https://#{@options[:region]}.amazonaws.com/#{@options[:bucket]}/" | |
| end | |
| def policy | |
| Base64.encode64(policy_data.to_json).gsub("\n", "") | |
| end | |
| def policy_data | |
| @policy_data ||= { | |
| expiration: @options[:expiration], | |
| conditions: [ | |
| ["starts-with", "$utf8", ""], | |
| ["starts-with", "$key", ""], | |
| ["starts-with", "$x-requested-with", ""], | |
| ["content-length-range", 0, @options[:max_file_size]], | |
| ["starts-with","$Content-Type",""], | |
| {bucket: @options[:bucket]}, | |
| {acl: @options[:acl]}, | |
| {success_action_status: "201"} | |
| ] | |
| } | |
| end | |
| def add_success_action_redirect(url) | |
| policy_data[:conditions] << { success_action_redirect: url } | |
| end | |
| def signature | |
| Base64.encode64( | |
| OpenSSL::HMAC.digest( | |
| OpenSSL::Digest.new('sha1'), | |
| @options[:aws_secret_access_key], policy | |
| ) | |
| ).gsub("\n", "") | |
| end | |
| end | |
| end |