summaryrefslogtreecommitdiff
path: root/swiftclient/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'swiftclient/utils.py')
-rw-r--r--swiftclient/utils.py60
1 files changed, 36 insertions, 24 deletions
diff --git a/swiftclient/utils.py b/swiftclient/utils.py
index 656acad..c865d27 100644
--- a/swiftclient/utils.py
+++ b/swiftclient/utils.py
@@ -13,17 +13,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Miscellaneous utility functions for use with Swift."""
+
+import base64
from calendar import timegm
-try:
- from collections.abc import Mapping
-except ImportError:
- from collections import Mapping
+from collections.abc import Mapping
import gzip
import hashlib
import hmac
+import io
import json
import logging
-import six
import time
import traceback
@@ -42,7 +41,7 @@ def config_true_value(value):
This function comes from swift.common.utils.config_true_value()
"""
return value is True or \
- (isinstance(value, six.string_types) and value.lower() in TRUE_VALUES)
+ (isinstance(value, str) and value.lower() in TRUE_VALUES)
def prt_bytes(num_bytes, human_flag):
@@ -72,7 +71,8 @@ def prt_bytes(num_bytes, human_flag):
def generate_temp_url(path, seconds, key, method, absolute=False,
- prefix=False, iso8601=False, ip_range=None):
+ prefix=False, iso8601=False, ip_range=None,
+ digest='sha256'):
"""Generates a temporary URL that gives unauthenticated access to the
Swift object.
@@ -97,7 +97,11 @@ def generate_temp_url(path, seconds, key, method, absolute=False,
instead of a UNIX timestamp will be created.
:param ip_range: if a valid ip range, restricts the temporary URL to the
range of ips.
- :raises ValueError: if timestamp or path is not in valid format.
+ :param digest: digest algorithm to use. Must be one of ``sha1``,
+ ``sha256``, or ``sha512``.
+ :raises ValueError: if timestamp or path is not in valid format,
+ or if digest is not one of ``sha1``, ``sha256``, or
+ ``sha512``.
:return: the path portion of a temporary URL
"""
try:
@@ -134,7 +138,7 @@ def generate_temp_url(path, seconds, key, method, absolute=False,
except ValueError:
raise ValueError(TIME_ERRMSG)
- if isinstance(path, six.binary_type):
+ if isinstance(path, bytes):
try:
path_for_body = path.decode('utf-8')
except UnicodeDecodeError:
@@ -142,6 +146,11 @@ def generate_temp_url(path, seconds, key, method, absolute=False,
else:
path_for_body = path
+ if isinstance(digest, str) and digest in ('sha1', 'sha256', 'sha512'):
+ digest = getattr(hashlib, digest)
+ if digest not in (hashlib.sha1, hashlib.sha256, hashlib.sha512):
+ raise ValueError('digest must be one of sha1, sha256, or sha512')
+
parts = path_for_body.split('/', 4)
if len(parts) != 5 or parts[0] or not all(parts[1:(4 if prefix else 5)]):
if prefix:
@@ -165,7 +174,7 @@ def generate_temp_url(path, seconds, key, method, absolute=False,
('prefix:' if prefix else '') + path_for_body]
if ip_range:
- if isinstance(ip_range, six.binary_type):
+ if isinstance(ip_range, bytes):
try:
ip_range = ip_range.decode('utf-8')
except UnicodeDecodeError:
@@ -174,27 +183,32 @@ def generate_temp_url(path, seconds, key, method, absolute=False,
)
hmac_parts.insert(0, "ip=%s" % ip_range)
- hmac_body = u'\n'.join(hmac_parts)
+ hmac_body = '\n'.join(hmac_parts)
# Encode to UTF-8 for py3 compatibility
- if not isinstance(key, six.binary_type):
+ if not isinstance(key, bytes):
key = key.encode('utf-8')
- sig = hmac.new(key, hmac_body.encode('utf-8'), hashlib.sha1).hexdigest()
+ mac = hmac.new(key, hmac_body.encode('utf-8'), digest)
+ if digest == hashlib.sha512:
+ sig = 'sha512:' + base64.urlsafe_b64encode(
+ mac.digest()).decode('ascii').strip('=')
+ else:
+ sig = mac.hexdigest()
if iso8601:
expiration = time.strftime(
EXPIRES_ISO8601_FORMAT, time.gmtime(expiration))
- temp_url = u'{path}?temp_url_sig={sig}&temp_url_expires={exp}'.format(
+ temp_url = '{path}?temp_url_sig={sig}&temp_url_expires={exp}'.format(
path=path_for_body, sig=sig, exp=expiration)
if ip_range:
- temp_url += u'&temp_url_ip_range={}'.format(ip_range)
+ temp_url += '&temp_url_ip_range={}'.format(ip_range)
if prefix:
- temp_url += u'&temp_url_prefix={}'.format(parts[4])
+ temp_url += '&temp_url_prefix={}'.format(parts[4])
# Have return type match path from caller
- if isinstance(path, six.binary_type):
+ if isinstance(path, bytes):
return temp_url.encode('utf-8')
else:
return temp_url
@@ -202,7 +216,7 @@ def generate_temp_url(path, seconds, key, method, absolute=False,
def get_body(headers, body):
if headers.get('content-encoding') == 'gzip':
- with gzip.GzipFile(fileobj=six.BytesIO(body), mode='r') as gz:
+ with gzip.GzipFile(fileobj=io.BytesIO(body), mode='r') as gz:
nbody = gz.read()
return nbody
return body
@@ -224,7 +238,7 @@ def split_request_headers(options, prefix=''):
if isinstance(options, Mapping):
options = options.items()
for item in options:
- if isinstance(item, six.string_types):
+ if isinstance(item, str):
if ':' not in item:
raise ValueError(
"Metadata parameter %s must contain a ':'.\n"
@@ -256,7 +270,7 @@ def report_traceback():
return None, None
-class NoopMD5(object):
+class NoopMD5:
def __init__(self, *a, **kw):
pass
@@ -267,7 +281,7 @@ class NoopMD5(object):
return ''
-class ReadableToIterable(object):
+class ReadableToIterable:
"""
Wrap a filelike object and act as an iterator.
@@ -316,7 +330,7 @@ class ReadableToIterable(object):
return self
-class LengthWrapper(object):
+class LengthWrapper:
"""
Wrap a filelike object with a maximum length.
@@ -401,8 +415,6 @@ def n_groups(seq, n):
def normalize_manifest_path(path):
- if six.PY2 and isinstance(path, six.text_type):
- path = path.encode('utf-8')
if path.startswith('/'):
return path[1:]
return path