Skip to content

Instantly share code, notes, and snippets.

@mtigas
Created August 24, 2012 20:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mtigas/3455067 to your computer and use it in GitHub Desktop.
Save mtigas/3455067 to your computer and use it in GitHub Desktop.
Uploader and "signed" url generator for semi-secure private/encrypted S3 uploads.
#!/usr/bin/env python
# coding=utf-8
#
# s3up-private.py
# (c)2012, Mike Tigas
# http://mike.tig.as/
#
# Uploads files into S3 with a "private" ACL and with "encrypt_key" enabled.
# Generates a time-limited URL that can access the given uploaded file.
#
# Usage:
# s3up-private filename [expiration_time]
# Uploads the given file to DEFAULT_BUCKET (media.miketigas.com)
# at the following path:
#
# files/YYYYMMDD/(filename)
#
# ...where (filename) is a hashed representation of the original filename.
#
# [expiration_time] sets the time that the generated link is valid,
# in seconds. (Defaults to 3600 seconds). If set to 0, does not generate
# an access URL.
#
#
# Please set the following options below before using:
# AWS_ACCESS_KEY_ID
# AWS_SECRET_ACCESS_KEY
# DEFAULT_BUCKET
# DEFAULT_EXPIRES
# FILENAME_HASHER
from __future__ import print_function
import hashlib
import sys
import traceback
from mimetypes import guess_type
from datetime import datetime
from boto.s3.connection import S3Connection
import os
from boto.s3.connection import OrdinaryCallingFormat
AWS_ACCESS_KEY_ID = ''
AWS_SECRET_ACCESS_KEY = ''
DEFAULT_BUCKET = ''
DEFAULT_EXPIRES = 3600
FILENAME_HASHER = hashlib.sha224
# ========== Uploader methods ==========
def key_to_secure_url(key, bucket, link_expires):
s3 = S3Connection(
aws_access_key_id=AWS_ACCESS_KEY_ID,
aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
calling_format=OrdinaryCallingFormat()
)
bucket = s3.get_bucket(bucket)
k = bucket.get_key(key)
return k.generate_url(expires_in=link_expires)
def hashed_filename(remote_path):
filebase, fileext = os.path.splitext(os.path.basename(remote_path))
return "%s/%s" % (
os.path.dirname(remote_path),
FILENAME_HASHER(filebase+datetime.now().isoformat()).hexdigest() + fileext
)
def easy_up(local_file, link_expires=DEFAULT_EXPIRES):
if os.path.isfile(local_file):
rpath = "files/"+datetime.now().strftime("%Y%m%d")
remote_path = rpath+"/"+os.path.basename(local_file)
remote_path = hashed_filename(remote_path)
upload_file(os.path.abspath(local_file), DEFAULT_BUCKET, remote_path)
if not link_expires:
# Expiration time is set to zero.
print(file=sys.stderr)
print("Upload successful. To generate an access link:", file=sys.stderr)
else:
# Have a time
print(file=sys.stderr)
print(key_to_secure_url(remote_path, DEFAULT_BUCKET, link_expires))
print(file=sys.stderr)
print("To generate a new link:", file=sys.stderr)
print("s3-genlink.py %s [expiration_time]" % remote_path, file=sys.stderr)
print(file=sys.stderr)
else:
print("Path given is not a file.", file=sys.stderr)
def upload_file(local_file, bucket, remote_path):
s3 = S3Connection(
aws_access_key_id=AWS_ACCESS_KEY_ID,
aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
calling_format=OrdinaryCallingFormat()
)
bucket = s3.get_bucket(bucket)
key = bucket.new_key(remote_path)
key.content_type = guess_type(local_file, False)[0] or "application/octet-stream"
key.set_contents_from_filename(local_file, policy="private", encrypt_key=True)
# ===== / chunked upload =====
key.set_metadata('Cache-Control','no-cache, no-store')
key.set_canned_acl("private")
def main(args):
if len(args) == 2:
easy_up(args[0], int(args[1]))
elif len(args) == 1:
easy_up(args[0])
else:
print("s3up-private filename [expiration_time]", file=sys.stderr)
print(" Uploads the given file to DEFAULT_BUCKET (%s)" % DEFAULT_BUCKET, file=sys.stderr)
print(" at the following path:" , file=sys.stderr)
print(file=sys.stderr)
print(" files/YYYYMMDD/(filename)", file=sys.stderr)
print(file=sys.stderr)
print(" ...where (filename) is a hashed representation of the original filename.", file=sys.stderr)
print(file=sys.stderr)
print(" [expiration_time] sets the time that the generated link is valid,", file=sys.stderr)
print(" in seconds. (Defaults to %s seconds)." % DEFAULT_EXPIRES, file=sys.stderr)
if __name__ == '__main__':
try:
main(sys.argv[1:])
except Exception, e:
sys.stderr.write('\n')
traceback.print_exc(file=sys.stderr)
sys.stderr.write('\n')
sys.exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment