class Aws::S3::PresignedPost
“‘
})
}
’original-filename’: ‘${filename}’
metadata: {
key: ‘/fixed/key’,
post = Aws::S3::PresignedPost.new(creds, region, bucket, {
“‘ruby
filename in the `x-amz-meta-` hash with the uploaded object.
In the following example, we use `${filename}` to store the original
replaced with an empty string.
as “file.txt”). If no file or file name is provided, the variable is
(e.g., “C:Program Filesdirectory1file.txt” will be interpreted
only the text following the last slash (/) or backslash () will be used
If the browser or client provides a full or partial path to the file,
not supported with `starts_with` conditions.
file provided by the user and is recognized by all form fields. It is
The string `${filename}` is automatically replaced with the name of the
### The `${filename}` Variable
“`
#=> ’bar’
post.fields[‘x-amz-meta-foo’]
metadata(foo: ‘bar’)
key(‘/fixed/key’).
post = Aws::S3::PresignedPost.new(creds, region, bucket).
“‘ruby
form fields, you pass a hash value to these options/methods:
`:metadata_starts_with` and {#metadata_starts_with}. Unlike other
You can add rules for metadata fields using `:metadata`, {#metadata},
### Metadata
“`
})
# …
allow_any: [’Filename’],
key: ‘object-key’,
post = Aws::S3::PresignedPost.new(creds, region, bucket, {
“‘ruby
field with `:allow_any` or {#allow_any}.
To white-list a form field to send any value, you can name that
### Any Field Value
a value for these fields.
user can specify the value. The {PresignedPost} will not add
When using starts with, the form must contain a field where the
“`
})
# …
content_type_starts_with: ’image/‘,
key_starts_with: ’/images/‘,
post = Aws::S3::PresignedPost.new(creds, region, bucket, {
“`ruby
option or call the associated `#<field_name>_starts_with` method.
To specify a required prefix, use the `:<fieldname>_starts_with`
You can specify prefix values for many of the POST form fields.
### Field Starts With
Amazon S3 will reject the POST request.
If any of the given values are changed by the user in the form, then
“`
post.content_type(’text/plain’)
post = Aws::S3::PresignedPost.new(creds, region, bucket)
“‘ruby
or call the associated method.
Simply pass an option like `:content_type` to the constructor,
You can specify that a form field must be a certain value.
### Field Equals
* Specify the field may have any value.
* Specify what value the field starts with.
* Specify exactly what the value must be.
You can specify accepted form field values three ways:
field sent by the browser, Amazon S3 will reject the request.
field name that will be posted by the browser. If you omit a form
When you construct a {PresignedPost}, you must specify every form
## Post Policy
“`
<input type=“file” name=“file”/>
“`erb
Lastly, the form must have a file field with the name `file`.
“`
<% end %>
<input type=“hidden” name=“<%= name %>” value=“<%= value %>”/>
<% @post.fields.each do |name, value| %>
“`erb
the form. Typically these are rendered as hidden input fields.
The {#fields} method returns a hash of form fields to render inside
### Form Fields
* `enctype` - This must be `multipart/form-data`.
* `method` - This must be `post`.
* `action` - This must be the {#url}.
The follow attributes must be set on the form:
“`
</form>
…
<form action=“<%= @post.url %>” method=“post” enctype=“multipart/form-data”>
“`erb
as the form action.
a post form. The {#url} method returns the value you should use
To upload a file to Amazon S3 using a browser, you need to create
### Form Tag
tags that properly escapes values.
recommended to use some helper to build the form tag and input
You can use a {PresignedPost} object to build an HTML form. It is
## HTML Forms
“`
#=> { … }
fields
metadata(’original-filename’ => ‘${filename}’).
acl(‘public-read’).
content_length_range(0..1024).
key(‘/uploaded/object/key’).
post = Aws::S3::PresignedPost.new(creds, region, bucket).
#=> { … }
post.fields
})
}
‘original-filename’ => ‘${filename}’
metadata: {
acl: ‘public-read’,
content_length_range: 0..1024,
key: ‘/uploaded/object/key’,
post = Aws::S3::PresignedPost.new(creds, region, bucket, {
“‘ruby
The following two examples are equivalent.
methods such as {#key} and {#content_length_range}.
to the post object as options to {#initialize} or by calling
your bucket is in, and the name of your bucket. You can apply constraints
To generate a presigned post, you need AWS credentials, the region
## Basic Usage
See {Bucket#presigned_post} and {Object#presigned_post}.
@note Normally you do not need to construct a {PresignedPost} yourself.
def self.define_field(field, *args, &block)
- Api: - private
def self.define_field(field, *args, &block) @@allowed_fields << field options = args.last.is_a?(Hash) ? args.pop : {} field_name = args.last || field.to_s if block_given? define_method("#{field}", block) else define_method("#{field}") do |value| with(field_name, value) end if options[:starts_with] @@allowed_fields << "#{field}_starts_with".to_sym define_method("#{field}_starts_with") do |value| starts_with(field_name, value) end end end end
def allow_any(*field_names)
-
(self)
-
Parameters:
-
field_names
(Sting, Array
) --
def allow_any(*field_names) field_names.flatten.each do |field_name| @key_set = true if field_name.to_s == 'key' starts_with(field_name, '') end self end
def base64(str)
def base64(str) Base64.strict_encode64(str) end
def bucket_url
def bucket_url # Taken from Aws::S3::Endpoints module params = Aws::S3::EndpointParameters.new( bucket: @bucket_name, region: @bucket_region, accelerate: @accelerate, use_global_endpoint: true ) endpoint = Aws::S3::EndpointProvider.new.resolve_endpoint(params) endpoint.url end
def check_required_values!
def check_required_values! unless @key_set msg = 'key required; you must provide a key via :key, '\ ":key_starts_with, or :allow_any => ['key']" raise msg end end
def credential_scope(datetime)
def credential_scope(datetime) parts = [] parts << @credentials.access_key_id parts << datetime[0,8] parts << @bucket_region parts << 's3' parts << 'aws4_request' parts.join('/') end
def fields
-
(Hash)
- A hash of fields to render in an HTML form
def fields check_required_values! datetime = Time.now.utc.strftime('%Y%m%dT%H%M%SZ') fields = @fields.dup fields.update('policy' => policy(datetime)) fields.update(signature_fields(datetime)) fields.update('x-amz-signature' => signature(datetime, fields['policy'])) end
def hexhmac(key, value)
def hexhmac(key, value) OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), key, value) end
def hmac(key, value)
def hmac(key, value) OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), key, value) end
def initialize(credentials, bucket_region, bucket_name, options = {})
(**options)
-
:server_side_encryption_customer_key_starts_with
(String
) -- -
:server_side_encryption_customer_key
(String
) -- -
:server_side_encryption_customer_algorithm
(String
) -- -
:server_side_encryption_aws_kms_key_id
(String
) -- -
:server_side_encryption
(String
) -- -
:metadata_starts_with
(Hash
) -- -
:metadata
(Hash
) -- -
:website_redirect_location
(String
) -- -
:storage_class
(String
) -- -
:success_action_status
(String
) -- -
:success_action_redirect_starts_with
(String
) -- -
:success_action_redirect
(String
) -- -
:content_length_range
(Range
) -- -
:expires_starts_with
(String
) -- -
:expires
(Time
) -- See {PresignedPost#expires}. -
:content_encoding_starts_with
(String
) -- -
:content_encoding
(String
) -- -
:content_disposition_starts_with
(String
) -- -
:content_disposition
(String
) -- -
:content_type_starts_with
(String
) -- -
:content_type
(String
) -- See {PresignedPost#content_type}. -
:cache_control_starts_with
(String
) -- -
:cache_control
(String
) -- -
:acl_starts_with
(String
) -- -
:acl
(String
) -- See {PresignedPost#acl}. -
:key_starts_with
(String
) -- -
:key
(String
) -- See {PresignedPost#key}. -
:signature_expiration
(Time
) -- Specify when the signature on -
:allow_any
(Sting, Array
) -- -
:url
(String
) -- See {PresignedPost#url}. -
:use_accelerate_endpoint
(Boolean
) -- When `true`,
Parameters:
-
bucket_name
(String
) -- Name of the target bucket. -
bucket_region
(String
) -- Region of the target bucket. -
credentials
(Credentials
) -- Security credentials for signing
def initialize(credentials, bucket_region, bucket_name, options = {}) @credentials = credentials.credentials @bucket_region = bucket_region @bucket_name = bucket_name @accelerate = !!options.delete(:use_accelerate_endpoint) options.delete(:url) if @accelerate # resource methods pass url @url = options.delete(:url) || bucket_url @fields = {} @key_set = false @signature_expiration = Time.now + 3600 @conditions = [{ 'bucket' => @bucket_name }] options.each do |option_name, option_value| case option_name when :allow_any then allow_any(option_value) when :signature_expiration then @signature_expiration = option_value else if @@allowed_fields.include?(option_name) send("#{option_name}", option_value) else raise ArgumentError, "Unsupported option: #{option_name}" end end end end
def policy(datetime)
-
(Hash)
-
def policy(datetime) check_required_values! policy = {} policy['expiration'] = @signature_expiration.utc.iso8601 policy['conditions'] = @conditions.dup signature_fields(datetime).each do |name, value| policy['conditions'] << { name => value } end base64(Json.dump(policy)) end
def signature(datetime, string_to_sign)
def signature(datetime, string_to_sign) k_secret = @credentials.secret_access_key k_date = hmac('AWS4' + k_secret, datetime[0,8]) k_region = hmac(k_date, @bucket_region) k_service = hmac(k_region, 's3') k_credentials = hmac(k_service, 'aws4_request') hexhmac(k_credentials, string_to_sign) end
def signature_fields(datetime)
def signature_fields(datetime) fields = {} fields['x-amz-credential'] = credential_scope(datetime) fields['x-amz-algorithm'] = 'AWS4-HMAC-SHA256' fields['x-amz-date'] = datetime if session_token = @credentials.session_token fields['x-amz-security-token'] = session_token end fields end
def starts_with(field_name, value, &block)
def starts_with(field_name, value, &block) @conditions << ['starts-with', "$#{field_name}", value.to_s] self end
def with(field_name, value)
def with(field_name, value) fvar = '${filename}' if index = value.rindex(fvar) if index + fvar.size == value.size @fields[field_name] = value starts_with(field_name, value[0,index]) else msg = "${filename} only supported at the end of #{field_name}" raise ArgumentError, msg end else @fields[field_name] = value.to_s @conditions << { field_name => value.to_s } end self end