Files
kefu/wechat_rpa/.venv/Lib/site-packages/qcloud_cos/cos_auth.py
T
2026-09-21 10:34:06 +08:00

199 lines
7.4 KiB
Python

# -*- 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