Skip to content

Instantly share code, notes, and snippets.

@raykin
Last active December 15, 2015 04:39
Show Gist options
  • Save raykin/5202809 to your computer and use it in GitHub Desktop.
Save raykin/5202809 to your computer and use it in GitHub Desktop.
A ruby method to quickly generate s3 direct upload hash
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 = 'raykincoldxiao@gmail.com'
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

Usage:

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment