Skip to content

Commit

Permalink
pythonic way to construct form-data and address review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
balamurugana committed Nov 30, 2020
1 parent d622819 commit edc5751
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 63 deletions.
10 changes: 6 additions & 4 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -1436,11 +1436,13 @@ __Example__

```py
policy = PostPolicy(
"bucket_name", datetime.utcnow() + timedelta(days=10),
"my-bucket", datetime.utcnow() + timedelta(days=10),
)
policy.add_starts_with_condition("key", "objectPrefix/")
form_data = presigned_post_policy(policy)
print(form_data)
policy.add_starts_with_condition("key", "my/object/prefix/")
policy.add_content_length_range_condition(
1*1024*1024, 10*1024*1024,
)
form_data = client.presigned_post_policy(policy)
```

## 5. Explore Further
Expand Down
10 changes: 3 additions & 7 deletions examples/presigned_post_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# Note: my-bucketname, my-objectname, YOUR-ACCESSKEYID, and
# YOUR-SECRETACCESSKEY are dummy values, please replace them with original
# values.

from datetime import datetime, timedelta

from minio import Minio
Expand All @@ -30,16 +26,16 @@
)

policy = PostPolicy(
"bucket_name", datetime.utcnow() + timedelta(days=10),
"my-bucket", datetime.utcnow() + timedelta(days=10),
)
policy.add_starts_with_condition("key", "objectPrefix/")
policy.add_starts_with_condition("key", "my/object/prefix/")
policy.add_content_length_range_condition(1*1024*1024, 10*1024*1024)

form_data = client.presigned_post_policy(policy)

curl_cmd = (
"curl -X POST "
"https://s3.amazonaws.com/bucket_name "
"https://s3.amazonaws.com/my-bucket "
"{0} -F file=@<FILE>"
).format(
" ".join(["-F {0}={1}".format(k, v) for k, v in form_data.items()]),
Expand Down
10 changes: 6 additions & 4 deletions minio/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1772,11 +1772,13 @@ def presigned_post_policy(self, policy):
Example::
policy = PostPolicy(
"bucket_name", datetime.utcnow() + timedelta(days=10),
"my-bucket", datetime.utcnow() + timedelta(days=10),
)
policy.add_starts_with_condition("key", "objectPrefix/")
form_data = presigned_post_policy(policy)
print(form_data)
policy.add_starts_with_condition("key", "my/object/prefix/")
policy.add_content_length_range_condition(
1*1024*1024, 10*1024*1024,
)
form_data = client.presigned_post_policy(policy)
"""
if not isinstance(policy, PostPolicy):
raise ValueError("policy must be PostPolicy type")
Expand Down
56 changes: 14 additions & 42 deletions minio/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import base64
import datetime
import json
from collections import OrderedDict
from urllib.parse import unquote
from xml.etree import ElementTree as ET
Expand Down Expand Up @@ -574,25 +575,10 @@ def uploads(self):


def _trim_dollar(value):
"""Trime dollar character if present."""
"""Trim dollar character if present."""
return value[1:] if value.startswith("$") else value


def _quote(value):
"""Quote value."""
return '"{0}"'.format(value)


def _get_condition(condition, element, value, is_end=False):
"""Get condition string."""
return " [{0}, {1}, {2}]{3}".format(
_quote(condition),
_quote("$" + element),
_quote(value),
"" if is_end else ",",
)


class PostPolicy:
"""
Post policy information to be used to generate presigned post policy
Expand Down Expand Up @@ -698,42 +684,28 @@ def form_data(self, creds, region):
):
raise ValueError("key condition must be set")

data = ["{"]
data.append(
" {0}: {1},".format(
_quote("expiration"),
_quote(to_iso8601utc(self._expiration)),
),
)
data.append(' "conditions": [')
data.append(_get_condition(_EQ, "bucket", self._bucket_name))
policy = OrderedDict()
policy["expiration"] = to_iso8601utc(self._expiration)
policy["conditions"] = [[_EQ, "$bucket", self._bucket_name]]
for cond_key, conditions in self._conditions.items():
for key, value in conditions.items():
data.append(_get_condition(cond_key, key, value))
policy["conditions"].append([cond_key, "$"+key, value])
if self._lower_limit is not None and self._upper_limit is not None:
data.append(
' ["content-length-range", {0}, {1}],'.format(
self._lower_limit, self._upper_limit,
),
policy["conditions"].append(
["content-length-range", self._lower_limit, self._upper_limit],
)

utcnow = datetime.datetime.utcnow()
credential = get_credential_string(creds.access_key, utcnow, region)
amz_date = to_amz_date(utcnow)

data.append(_get_condition("eq", "x-amz-algorithm", _ALGORITHM))
data.append(_get_condition("eq", "x-amz-credential", credential))
policy["conditions"].append([_EQ, "$x-amz-algorithm", _ALGORITHM])
policy["conditions"].append([_EQ, "$x-amz-credential", credential])
if creds.session_token:
data.append(
_get_condition(
"eq", "x-amz-security-token", creds.session_token,
),
policy["conditions"].append(
[_EQ, "$x-amz-security-token", creds.session_token],
)
data.append(_get_condition("eq", "x-amz-date", amz_date, True))
data.append(" ]")
data.append("}")
policy["conditions"].append([_EQ, "$x-amz-date", amz_date])

policy = base64.b64encode("\n".join(data).encode())
policy = base64.b64encode(json.dumps(policy).encode())
signature = post_presign_v4(
policy.decode(), creds.secret_key, utcnow, region,
)
Expand Down
14 changes: 8 additions & 6 deletions tests/functional/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1550,16 +1550,18 @@ def test_presigned_post_policy(log_entry):
no_of_days = 10
prefix = 'objectPrefix/'

# Post policy.
policy = PostPolicy(
bucket_name, datetime.utcnow() + timedelta(days=no_of_days),
)
policy.add_starts_with_condition("key", prefix)
# post_policy arg is a class. To avoid displaying meaningless value
# for the class, policy settings are made part of the args for
# clarity and debugging purposes.
log_entry["args"]["post_policy"] = {'prefix': prefix,
'expires_in_days': no_of_days}
policy.add_content_length_range_condition(64*KB, 10*MB)
policy.add_starts_with_condition("Content-Type", "image/")
log_entry["args"]["post_policy"] = {
"prefix": prefix,
"expires_in_days": no_of_days,
"content_length_range": "64KiB to 10MiB",
"Content-Type": "image/",
}
_CLIENT.presigned_post_policy(policy)
finally:
_CLIENT.remove_bucket(bucket_name)
Expand Down

0 comments on commit edc5751

Please sign in to comment.