Files
hsa/.venv/lib/python3.10/site-packages/qcloud_cos/cos_auth.py
2025-09-11 13:29:12 +00:00

199 lines
7.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
from six.moves.urllib.parse import quote, unquote, urlparse, urlencode
import hmac
import time
import hashlib
import logging
from requests.auth import AuthBase
from .cos_comm import to_unicode, to_bytes, to_str
logger = logging.getLogger(__name__)
def filter_headers(data):
"""只设置host content-type 还有x开头的头部.
:param data(dict): 所有的头部信息.
:return(dict): 计算进签名的头部.
"""
valid_headers = [
"cache-control",
"content-disposition",
"content-encoding",
"content-type",
"content-md5",
"content-length",
"expect",
"expires",
"host",
"if-match",
"if-modified-since",
"if-none-match",
"if-unmodified-since",
"origin",
"range",
"transfer-encoding",
"pic-operations",
]
headers = {}
for i in data:
if str.lower(i) in valid_headers or str.lower(i).startswith("x-cos-") or str.lower(i).startswith("x-ci-"):
headers[i] = data[i]
return headers
class CosS3Auth(AuthBase):
def __init__(self, conf, key=None, params={}, expire=10000, sign_host=None):
self._secret_id = conf._secret_id if conf._secret_id else \
(conf._credential_inst.secret_id if conf._credential_inst else None)
self._secret_key = conf._secret_key if conf._secret_key else \
(conf._credential_inst.secret_key if conf._credential_inst else None)
self._anonymous = conf._anonymous
self._expire = expire
self._params = params
self._sign_params = conf._sign_params
# 如果API指定了是否签名host则以具体API为准如果未指定则以配置为准
if sign_host is not None:
self._sign_host = bool(sign_host)
else:
self._sign_host = conf._sign_host
if key:
key = to_unicode(key)
if key[0] == u'/':
self._path = key
else:
self._path = u'/' + key
else:
self._path = u'/'
def __call__(self, r):
# 匿名请求直接返回
if self._anonymous:
r.headers['Authorization'] = ""
logger.debug("anonymous reqeust")
return r
path = self._path
uri_params = {}
if self._sign_params:
uri_params = self._params
headers = filter_headers(r.headers)
# 如果headers中不包含host头域则从url中提取host并且加入签名计算
if self._sign_host:
# 判断headers中是否包含host头域
contain_host = False
for i in headers:
if str.lower(i) == "host": # 兼容host/Host/HOST等
contain_host = True
break
# 从url中提取host
if not contain_host:
url_parsed = urlparse(r.url)
if url_parsed.hostname is not None:
headers["host"] = url_parsed.hostname
# reserved keywords in headers urlencode are -_.~, notice that / should be encoded and space should not be encoded to plus sign(+)
headers = dict([(quote(to_bytes(to_str(k)), '-_.~').lower(), quote(to_bytes(to_str(v)), '-_.~')) for k, v in
headers.items()]) # headers中的key转换为小写value进行encode
uri_params = dict([(quote(to_bytes(to_str(k)), '-_.~').lower(), quote(to_bytes(to_str(v)), '-_.~')) for k, v in
uri_params.items()])
format_str = u"{method}\n{host}\n{params}\n{headers}\n".format(
method=r.method.lower(),
host=path,
params='&'.join(map(lambda tupl: "%s=%s" %
(tupl[0], tupl[1]), sorted(uri_params.items()))),
headers='&'.join(map(lambda tupl: "%s=%s" %
(tupl[0], tupl[1]), sorted(headers.items())))
)
logger.debug("format str: " + format_str)
start_sign_time = int(time.time())
sign_time = "{bg_time};{ed_time}".format(
bg_time=start_sign_time - 60, ed_time=start_sign_time + self._expire)
sha1 = hashlib.sha1()
sha1.update(to_bytes(format_str))
str_to_sign = "sha1\n{time}\n{sha1}\n".format(
time=sign_time, sha1=sha1.hexdigest())
logger.debug('str_to_sign: ' + str(str_to_sign))
sign_key = hmac.new(to_bytes(self._secret_key), to_bytes(
sign_time), hashlib.sha1).hexdigest()
sign = hmac.new(to_bytes(sign_key), to_bytes(
str_to_sign), hashlib.sha1).hexdigest()
logger.debug('sign_key: ' + str(sign_key))
logger.debug('sign: ' + str(sign))
sign_tpl = "q-sign-algorithm=sha1&q-ak={ak}&q-sign-time={sign_time}&q-key-time={key_time}&q-header-list={headers}&q-url-param-list={params}&q-signature={sign}"
r.headers['Authorization'] = sign_tpl.format(
ak=self._secret_id,
sign_time=sign_time,
key_time=sign_time,
params=';'.join(sorted(uri_params.keys())),
headers=';'.join(sorted(headers.keys())),
sign=sign
)
logger.debug("sign_key" + str(sign_key))
logger.debug(r.headers['Authorization'])
logger.debug("request headers: " + str(r.headers))
return r
class CosRtmpAuth(AuthBase):
def __init__(self, conf, bucket=None, channel=None, params={}, expire=3600, presign_expire=0):
self._secret_id = conf._secret_id
self._secret_key = conf._secret_key
self._token = conf._token
self._anonymous = conf._anonymous
self._expire = expire
self._presign_expire = presign_expire
self._params = params
if self._token:
self._params['q-token'] = self._token
self._path = u'/' + bucket + u'/' + channel
def get_rtmp_sign(self):
# get rtmp string
canonicalized_param = ''
for k, v in self._params.items():
canonicalized_param += '{key}={value}&'.format(key=k, value=v)
if self._presign_expire >= 60:
canonicalized_param += 'presign={value}'.format(
value=self._presign_expire)
canonicalized_param = canonicalized_param.rstrip('&')
rtmp_str = u"{path}\n{params}\n".format(
path=self._path, params=canonicalized_param)
logger.debug("rtmp str: " + rtmp_str)
sha1 = hashlib.sha1()
sha1.update(to_bytes(rtmp_str))
# get time
sign_time = int(time.time())
sign_time_str = "{start_time};{end_time}".format(
start_time=sign_time - 60, end_time=sign_time + self._expire)
str_to_sign = "sha1\n{time}\n{sha1}\n".format(
time=sign_time_str, sha1=sha1.hexdigest())
logger.debug('str_to_sign: ' + str(str_to_sign))
# get sinature
signature = hmac.new(to_bytes(self._secret_key), to_bytes(
str_to_sign), hashlib.sha1).hexdigest()
logger.debug('signature: ' + str(signature))
rtmp_sign = "q-sign-algorithm=sha1&q-ak={ak}&q-sign-time={sign_time}&q-key-time={key_time}&q-signature={sign}".format(
ak=self._secret_id, sign_time=sign_time_str, key_time=sign_time_str, sign=signature)
if canonicalized_param != '':
return rtmp_sign + "&{params}".format(params=canonicalized_param)
else:
return rtmp_sign
if __name__ == "__main__":
pass