Skip to content

Commit a900932

Browse files
generate AWS signed url
1 parent 4a259cb commit a900932

File tree

4 files changed

+186
-2
lines changed

4 files changed

+186
-2
lines changed

qencode3/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ def x265_video_codec():
2929

3030
from . exeptions import QencodeClientException, QencodeTaskException
3131

32-
__version__ = "0.9.26"
32+
from . tools import generate_aws_signed_url
33+
34+
35+
36+
__version__ = "0.9.27"
3337
__status__ = "Beta"
3438
__author__ = "Qencode"
3539

qencode3/tools.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#
2+
import datetime
3+
import hashlib
4+
import hmac
5+
import requests
6+
from requests.utils import quote
7+
8+
def generate_aws_signed_url(region, bucket, object_key, access_key, secret_key, expiration, endpoint=None):
9+
10+
# request elements
11+
http_method = 'GET'
12+
endpoint = endpoint if endpoint else 's3.amazonaws.com'
13+
host = bucket + '.' + endpoint
14+
endpoint = 'https://' + host
15+
16+
# hashing methods
17+
def hash(key, msg):
18+
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
19+
20+
# region is a wildcard value that takes the place of the AWS region value
21+
# as COS doen't use regions like AWS, this parameter can accept any string
22+
def createSignatureKey(key, datestamp, region, service):
23+
keyDate = hash(('AWS4' + key).encode('utf-8'), datestamp)
24+
keyRegion = hash(keyDate, region)
25+
keyService = hash(keyRegion, service)
26+
keySigning = hash(keyService, 'aws4_request')
27+
return keySigning
28+
29+
# assemble the standardized request
30+
time = datetime.datetime.utcnow()
31+
timestamp = time.strftime('%Y%m%dT%H%M%SZ')
32+
datestamp = time.strftime('%Y%m%d')
33+
34+
standardized_querystring = ('X-Amz-Algorithm=AWS4-HMAC-SHA256' +
35+
'&X-Amz-Credential=' + access_key + '/' + datestamp + '/' + region + '/s3/aws4_request' +
36+
'&X-Amz-Date=' + timestamp +
37+
'&X-Amz-Expires=' + str(expiration) +
38+
'&X-Amz-SignedHeaders=host')
39+
standardized_querystring_url_encoded = quote(standardized_querystring, safe='&=')
40+
41+
standardized_resource = '/' + object_key
42+
standardized_resource_url_encoded = quote(standardized_resource, safe='&')
43+
44+
payload_hash = 'UNSIGNED-PAYLOAD'
45+
standardized_headers = 'host:' + host
46+
signed_headers = 'host'
47+
48+
standardized_request = (http_method + '\n' +
49+
standardized_resource + '\n' +
50+
standardized_querystring_url_encoded + '\n' +
51+
standardized_headers + '\n' +
52+
'\n' +
53+
signed_headers + '\n' +
54+
payload_hash).encode('utf-8')
55+
56+
# assemble string-to-sign
57+
hashing_algorithm = 'AWS4-HMAC-SHA256'
58+
credential_scope = datestamp + '/' + region + '/' + 's3' + '/' + 'aws4_request'
59+
sts = (hashing_algorithm + '\n' +
60+
timestamp + '\n' +
61+
credential_scope + '\n' +
62+
hashlib.sha256(standardized_request).hexdigest())
63+
64+
# generate the signature
65+
signature_key = createSignatureKey(secret_key, datestamp, region, 's3')
66+
signature = hmac.new(signature_key,
67+
(sts).encode('utf-8'),
68+
hashlib.sha256).hexdigest()
69+
70+
# create and send the request
71+
# the 'requests' package autmatically adds the required 'host' header
72+
request_url = (endpoint + '/' +
73+
object_key + '?' +
74+
standardized_querystring_url_encoded +
75+
'&X-Amz-Signature=' +
76+
signature)
77+
78+
def hex_hash(key, msg):
79+
return hmac.new(b'key', msg.encode('utf-8'), hashlib.sha256).hexdigest()
80+
81+
def createHexSignatureKey(key, datestamp, region, service):
82+
keyDate = hex_hash(('AWS4' + key).encode('utf-8'), datestamp)
83+
keyRegion = hex_hash(keyDate, region)
84+
keyService = hex_hash(keyRegion, service)
85+
keySigning = hex_hash(keyService, 'aws4_request')
86+
return keySigning
87+
88+
signature_key_hex = createHexSignatureKey(secret_key, datestamp, region, 's3')
89+
90+
# print(request_url)
91+
return request_url
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
4+
import sys
5+
import os.path
6+
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))
7+
import qencode3
8+
import time
9+
import json
10+
from qencode3 import QencodeClientException, QencodeTaskException
11+
from qencode3 import generate_aws_signed_url
12+
13+
# replace with your API KEY (can be found in your Project settings on Qencode portal)
14+
API_KEY = 'your-api-qencode-key'
15+
16+
# request elements
17+
region = 'us-east-2'
18+
bucket = 'your-bucket-name'
19+
object_key = 'path'
20+
expiration = 86400 # time in seconds
21+
access_key = 'your-AWS-access-key'
22+
secret_key = 'your-AWS-secret-key'
23+
24+
# generate AWS signed url
25+
source_url = generate_aws_signed_url(region, bucket, object_key, access_key, secret_key, expiration)
26+
print(source_url)
27+
28+
format_240 = dict(
29+
output="mp4",
30+
size="320x240",
31+
video_codec="libx264"
32+
)
33+
34+
format_720 = dict(
35+
output="mp4",
36+
size="1280x720",
37+
video_codec="libx264"
38+
)
39+
40+
format = [format_240, format_720]
41+
42+
query = dict(
43+
source=source_url,
44+
format=format
45+
)
46+
47+
params = dict(query=query)
48+
49+
def start_encode():
50+
51+
"""
52+
Create client object
53+
:param api_key: string. required
54+
:param api_url: string. not required
55+
:param api_version: int. not required. default 'v1'
56+
:return: task object
57+
"""
58+
59+
60+
client = qencode3.client(API_KEY)
61+
if client.error:
62+
raise QencodeClientException(client.message)
63+
64+
print('The client created. Expire date: {0}'.format(client.expire))
65+
66+
task = client.create_task()
67+
68+
if task.error:
69+
raise QencodeTaskException(task.message)
70+
71+
task.custom_start(params)
72+
73+
if task.error:
74+
raise QencodeTaskException(task.message)
75+
76+
print('Start encode. Task: {0}'.format(task.task_token))
77+
78+
line = "-"*80
79+
while True:
80+
print(line)
81+
status = task.status()
82+
# print status
83+
print(json.dumps(status, indent=2, sort_keys=True))
84+
if status['error'] or status['status'] == 'completed':
85+
break
86+
time.sleep(5)
87+
88+
if __name__ == '__main__':
89+
start_encode()

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
setup(
1515
name='qencode3',
16-
version='0.9.26',
16+
version='0.9.27',
1717
description="Qencode client library to easily setup a working solution using Python v3.x.",
1818
long_description=long_description,
1919
long_description_content_type='text/markdown',

0 commit comments

Comments
 (0)