-
-
Save iHiD/955355 to your computer and use it in GitHub Desktop.
# A simple function to return a signed, expiring url for Amazon Cloudfront. | |
# As it's relatively difficult to figure out exactly what is required, I've posted my working code here. | |
# This will require openssl, digest/sha1, base64 and maybe other libraries. | |
# In my rails app, all of these are already loaded so I'm not sure of the exact dependencies. | |
module CloudFront | |
def get_signed_expiring_url(path, expires_in, private_key_filename, key_pair_id) | |
# AWS works on UTC, so make sure you are not using local time | |
expires = (Time.now.getutc + expires_in).to_i.to_s | |
private_key = OpenSSL::PKey::RSA.new(File.read(private_key_filename)) | |
# path should be your S3 path without a leading slash and without a file extension. | |
# e.g. files/private/52 | |
policy = %Q[{"Statement":[{"Resource":"#{path}","Condition":{"DateLessThan":{"AWS:EpochTime":#{expires}}}}]}] | |
signature = Base64.strict_encode64(private_key.sign(OpenSSL::Digest::SHA1.new, policy)) | |
# I'm not sure exactly why this is required, but it's in Amazon's perl script and seems necessary | |
# Different base64 implementations maybe? | |
signature.tr!("+=/", "-_~") | |
"#{path}?Expires=#{expires}&Signature=#{signature}&Key-Pair-Id=#{key_pair_id}" | |
end | |
end | |
# Sample implementation for returning either a publicly accessibly or a time-limited url | |
class Video | |
def get_url | |
if public? | |
self.path | |
else | |
CloudFront.get_signed_expiring_url(self.path, 45.seconds, "#{Rails.root}/config/cloudfront.pem", "xxxKEYPAIRIDxxx") | |
end | |
end | |
end |
@wweidendorf urlsafe_encode64
complies with RFC 4648
Returns the Base64-encoded version of bin. This method complies with “Base 64 Encoding with URL and Filename Safe Alphabet” in RFC 4648. The alphabet uses ‘-’ instead of ‘+’ and ‘_’ instead of ‘/’.
And actually looks like this in the source ... (see here) ... seems it doesn't replace '=' with '_'. I'll also point out that Amazon's sample PHP code replaces all three as well so I think it's safer to stick with what they do though I must admit I've not tested if it fails.
def urlsafe_encode64(bin)
strict_encode64(bin).tr("+/", "-_")
end
Amazon uses their own version of URL-safe Base64 that also accounts for "=", the spec only accounts for "+" and "/", so you have to do the replacement yourself.
Also, this worked great, but only if I used the entire URL, not just the path - extension. Thanks!
Instead of
why not just use:
As an aside, the reason that Amazon's Perl script does that is due to: http://en.wikipedia.org/wiki/Base64#URL_applications