|
| 1 | +# |
| 2 | +from const import * |
| 3 | +import datetime |
| 4 | +import hashlib |
| 5 | +import hmac |
| 6 | +import requests |
| 7 | +from requests.utils import quote |
| 8 | +import xml.etree.cElementTree as et |
| 9 | +import uuid |
| 10 | + |
| 11 | +def generate_aws_signed_url(region, bucket, object_key, access_key, secret_key, expiration, endpoint=None): |
| 12 | + |
| 13 | + # request elements |
| 14 | + http_method = 'GET' |
| 15 | + endpoint = endpoint if endpoint else 's3.amazonaws.com' |
| 16 | + host = bucket + '.' + endpoint |
| 17 | + endpoint = 'https://' + host |
| 18 | + |
| 19 | + # hashing methods |
| 20 | + def hash(key, msg): |
| 21 | + return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest() |
| 22 | + |
| 23 | + # region is a wildcard value that takes the place of the AWS region value |
| 24 | + # as COS doen't use regions like AWS, this parameter can accept any string |
| 25 | + def createSignatureKey(key, datestamp, region, service): |
| 26 | + keyDate = hash(('AWS4' + key).encode('utf-8'), datestamp) |
| 27 | + keyRegion = hash(keyDate, region) |
| 28 | + keyService = hash(keyRegion, service) |
| 29 | + keySigning = hash(keyService, 'aws4_request') |
| 30 | + return keySigning |
| 31 | + |
| 32 | + # assemble the standardized request |
| 33 | + time = datetime.datetime.utcnow() |
| 34 | + timestamp = time.strftime('%Y%m%dT%H%M%SZ') |
| 35 | + datestamp = time.strftime('%Y%m%d') |
| 36 | + |
| 37 | + standardized_querystring = ('X-Amz-Algorithm=AWS4-HMAC-SHA256' + |
| 38 | + '&X-Amz-Credential=' + access_key + '/' + datestamp + '/' + region + '/s3/aws4_request' + |
| 39 | + '&X-Amz-Date=' + timestamp + |
| 40 | + '&X-Amz-Expires=' + str(expiration) + |
| 41 | + '&X-Amz-SignedHeaders=host') |
| 42 | + standardized_querystring_url_encoded = quote(standardized_querystring, safe='&=') |
| 43 | + |
| 44 | + standardized_resource = '/' + object_key |
| 45 | + standardized_resource_url_encoded = quote(standardized_resource, safe='&') |
| 46 | + |
| 47 | + payload_hash = 'UNSIGNED-PAYLOAD' |
| 48 | + standardized_headers = 'host:' + host |
| 49 | + signed_headers = 'host' |
| 50 | + |
| 51 | + standardized_request = (http_method + '\n' + |
| 52 | + standardized_resource + '\n' + |
| 53 | + standardized_querystring_url_encoded + '\n' + |
| 54 | + standardized_headers + '\n' + |
| 55 | + '\n' + |
| 56 | + signed_headers + '\n' + |
| 57 | + payload_hash).encode('utf-8') |
| 58 | + |
| 59 | + # assemble string-to-sign |
| 60 | + hashing_algorithm = 'AWS4-HMAC-SHA256' |
| 61 | + credential_scope = datestamp + '/' + region + '/' + 's3' + '/' + 'aws4_request' |
| 62 | + sts = (hashing_algorithm + '\n' + |
| 63 | + timestamp + '\n' + |
| 64 | + credential_scope + '\n' + |
| 65 | + hashlib.sha256(standardized_request).hexdigest()) |
| 66 | + |
| 67 | + # generate the signature |
| 68 | + signature_key = createSignatureKey(secret_key, datestamp, region, 's3') |
| 69 | + signature = hmac.new(signature_key, |
| 70 | + (sts).encode('utf-8'), |
| 71 | + hashlib.sha256).hexdigest() |
| 72 | + |
| 73 | + # create and send the request |
| 74 | + # the 'requests' package autmatically adds the required 'host' header |
| 75 | + request_url = (endpoint + '/' + |
| 76 | + object_key + '?' + |
| 77 | + standardized_querystring_url_encoded + |
| 78 | + '&X-Amz-Signature=' + |
| 79 | + signature) |
| 80 | + |
| 81 | + def hex_hash(key, msg): |
| 82 | + return hmac.new(b'key', msg.encode('utf-8'), hashlib.sha256).hexdigest() |
| 83 | + |
| 84 | + def createHexSignatureKey(key, datestamp, region, service): |
| 85 | + keyDate = hex_hash(('AWS4' + key).encode('utf-8'), datestamp) |
| 86 | + keyRegion = hex_hash(keyDate, region) |
| 87 | + keyService = hex_hash(keyRegion, service) |
| 88 | + keySigning = hex_hash(keyService, 'aws4_request') |
| 89 | + return keySigning |
| 90 | + |
| 91 | + signature_key_hex = createHexSignatureKey(secret_key, datestamp, region, 's3') |
| 92 | + |
| 93 | + # print(request_url) |
| 94 | + return request_url |
| 95 | + |
| 96 | + |
| 97 | +def fps_drm(username, password, uid=None): |
| 98 | + asset_id = uid if uid else uuid.uuid4() |
| 99 | + url = FPS_DRM_KEYGENERATOR_URI_TEMPLATE % (asset_id, username, password) |
| 100 | + response = requests.post(url, {}) |
| 101 | + tree = et.ElementTree(et.fromstring(response.content)) |
| 102 | + root = tree.getroot() |
| 103 | + kid = root[0][0].get('kid') |
| 104 | + iv = root[0][0].get('explicitIV') |
| 105 | + key = root[0][0][0][0][0].text |
| 106 | + key_hex = key.decode('base64').encode('hex') |
| 107 | + iv_hex = iv.decode('base64').encode('hex') |
| 108 | + key_url = DRM_KEY_URL_TEMPLATE % kid |
| 109 | + payload = dict(AssetID=asset_id) |
| 110 | + data = dict(key=key_hex, iv=iv_hex, key_url=key_url) |
| 111 | + return data, payload |
| 112 | + |
| 113 | + |
| 114 | +def cenc_drm(username, password, uid=None): |
| 115 | + asset_id = uid if uid else uuid.uuid4() |
| 116 | + url = CENC_DRM_KEYGENERATOR_URI_TEMPLATE % (asset_id, username, password) |
| 117 | + response = requests.post(url, {}) |
| 118 | + tree = et.ElementTree(et.fromstring(response.content)) |
| 119 | + root = tree.getroot() |
| 120 | + key_id = root[0][0].get('kid') |
| 121 | + key = root[0][0][0][0][0].text |
| 122 | + pssh = root[1][0][0].text |
| 123 | + key_id_hex = key_id.replace('-', '') |
| 124 | + key_hex = key.decode('base64').encode('hex') |
| 125 | + key_url = DRM_KEY_URL_TEMPLATE % key_id |
| 126 | + payload = dict(AssetID=asset_id) |
| 127 | + data = dict(key=key_hex, key_id=key_id_hex, pssh=pssh, key_url=key_url) |
| 128 | + return data, payload |
0 commit comments