Skip to content

Instantly share code, notes, and snippets.

@wizpig64
Created November 27, 2013 04:58
Show Gist options
  • Save wizpig64/7670865 to your computer and use it in GitHub Desktop.
Save wizpig64/7670865 to your computer and use it in GitHub Desktop.

Revisions

  1. wizpig64 created this gist Nov 27, 2013.
    64 changes: 64 additions & 0 deletions secure_storage.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,64 @@
    from base64 import urlsafe_b64encode
    from urlparse import parse_qs, urlsplit, urlunsplit
    from urllib import unquote, urlencode

    from django.conf import settings
    from django.core.files.storage import Storage
    from django.core.files.storage import FileSystemStorage

    from secret_hash import SecretHash


    class SecretHash(SecretHash):
    SECRET_KEY = settings.SECRET_KEY
    SECRET_LIFESPAN = getattr(settings, 'SECRET_URL_LIFESPAN', 86400) #24h


    class SecureStorageMixin(Storage):
    """Append some paramaters to make urls more secure and expire.
    Made to support nginx and its http_secure_link_module:
    http://wiki.nginx.org/HttpSecureLinkModule
    The secure link module is not compiled with nginx by default. If
    you're using Ubuntu like me, apt-get install nginx-extras to get it.
    Here's how NGINX can be set up if your secret is "SECRET$KEY123":
    (NGINX can't natively escape dollar sign literals, so use ${dollar})
    geo $dollar {
    default "$";
    }
    server {
    ...
    location /media {
    secure_link $arg_key,$arg_exp;
    secure_link_md5 SECRET${dollar}KEY123$arg_exp$uri;
    # If the hash is incorrect then $secure_link is a null string.
    if ($secure_link = "") {
    return 403;
    }
    # The current local time is greater than the specified expiration.
    if ($secure_link = "0") {
    return 403;
    }
    ...
    }
    }
    """
    def url(self, name):
    # Take the URL generated by super and break it up
    u = super(SecureStorageMixin, self).url(name)
    scheme, netloc, path, query_string, fragment = urlsplit(u)
    query_params = parse_qs(query_string)

    # Generate the extra parameters and reconstruct the URL.
    hash = SecretHash(unquote(path))
    query_params['key'] = [hash.key]
    query_params['exp'] = [hash.expires]
    new_query_string = urlencode(query_params, doseq=True)
    return urlunsplit((scheme, netloc, path, new_query_string, fragment))


    class SecureFileSystemStorage(SecureStorageMixin, FileSystemStorage): pass