1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119 | from django import forms
import datetime
import base64
import hmac, sha, simplejson
"""
http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1434
<input type="hidden" name="key" value="uploads/${filename}">
<input type="hidden" name="AWSAccessKeyId" value="YOUR_AWS_ACCESS_KEY">
<input type="hidden" name="acl" value="private">
<input type="hidden" name="success_action_redirect" value="http://localhost/">
<input type="hidden" name="policy" value="YOUR_POLICY_DOCUMENT_BASE64_ENCODED">
<input type="hidden" name="signature" value="YOUR_CALCULATED_SIGNATURE">
<input type="hidden" name="Content-Type" value="image/jpeg">
"""
class S3UploadForm(forms.Form):
key = forms.CharField(widget = forms.HiddenInput)
AWSAccessKeyId = forms.CharField(widget = forms.HiddenInput)
acl = forms.CharField(widget = forms.HiddenInput)
success_action_redirect = forms.CharField(widget = forms.HiddenInput)
policy = forms.CharField(widget = forms.HiddenInput)
signature = forms.CharField(widget = forms.HiddenInput)
Content_Type = forms.CharField(widget = forms.HiddenInput)
file = forms.FileField()
def __init__(self, aws_access_key, aws_secret_key, bucket, key,
expires_after = datetime.timedelta(days = 30),
acl = 'public-read',
success_action_redirect = None,
content_type = '',
min_size = 0,
max_size = None
):
self.aws_access_key = aws_access_key
self.aws_secret_key = aws_secret_key
self.bucket = bucket
self.key = key
self.expires_after = expires_after
self.acl = acl
self.success_action_redirect = success_action_redirect
self.content_type = content_type
self.min_size = min_size
self.max_size = max_size
policy = base64.b64encode(self.calculate_policy())
signature = self.sign_policy(policy)
initial = {
'key': self.key,
'AWSAccessKeyId': self.aws_access_key,
'acl': self.acl,
'policy': policy,
'signature': signature,
'Content-Type': self.content_type,
}
if self.success_action_redirect:
initial['success_action_redirect'] = self.success_action_redirect
super(S3UploadForm, self).__init__(initial = initial)
# We need to manually rename the Content_Type field to Content-Type
self.fields['Content-Type'] = self.fields['Content_Type']
del self.fields['Content_Type']
# Don't show success_action_redirect if it's not being used
if not self.success_action_redirect:
del self.fields['success_action_redirect']
def as_html(self):
"""
Use this instead of as_table etc, because S3 requires the file field
come AFTER the hidden fields, but Django's normal form display methods
position the visible fields BEFORE the hidden fields.
"""
html = ''.join(map(unicode, self.hidden_fields()))
html += unicode(self['file'])
return html
def as_form_html(self, prefix='', suffix=''):
html = """
<form action="%s" method="post" enctype="multipart/form-data">
<p>%s <input type="submit" value="Upload"></p>
</form>
""".strip() % (self.action(), self.as_html())
return html
def is_multipart(self):
return True
def action(self):
return 'https://%s.s3.amazonaws.com/' % self.bucket
def calculate_policy(self):
conditions = [
{'bucket': self.bucket},
{'acl': self.acl},
['starts-with', '$key', self.key.replace('${filename}', '')],
["starts-with", "$Content-Type", self.content_type],
]
if self.success_action_redirect:
conditions.append(
{'success_action_redirect': self.success_action_redirect},
)
policy_document = {
"expiration": (
datetime.datetime.now() + self.expires_after
).isoformat().split('.')[0] + 'Z',
"conditions": conditions,
}
return simplejson.dumps(policy_document, indent=2)
def sign_policy(self, policy):
return base64.b64encode(
hmac.new(self.aws_secret_key, policy, sha).digest()
)
|
Comments