ctyun-cli 0.1.0a1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ctyun_cli-0.1.0a1/PKG-INFO +31 -0
- ctyun_cli-0.1.0a1/README.md +62 -0
- ctyun_cli-0.1.0a1/ctyun_cli.egg-info/PKG-INFO +31 -0
- ctyun_cli-0.1.0a1/ctyun_cli.egg-info/SOURCES.txt +30 -0
- ctyun_cli-0.1.0a1/ctyun_cli.egg-info/dependency_links.txt +1 -0
- ctyun_cli-0.1.0a1/ctyun_cli.egg-info/entry_points.txt +2 -0
- ctyun_cli-0.1.0a1/ctyun_cli.egg-info/requires.txt +10 -0
- ctyun_cli-0.1.0a1/ctyun_cli.egg-info/top_level.txt +1 -0
- ctyun_cli-0.1.0a1/setup.cfg +4 -0
- ctyun_cli-0.1.0a1/setup.py +41 -0
- ctyun_cli-0.1.0a1/src/__init__.py +22 -0
- ctyun_cli-0.1.0a1/src/auth/__init__.py +5 -0
- ctyun_cli-0.1.0a1/src/auth/eop_signature.py +235 -0
- ctyun_cli-0.1.0a1/src/auth/signature.py +225 -0
- ctyun_cli-0.1.0a1/src/billing/__init__.py +8 -0
- ctyun_cli-0.1.0a1/src/billing/client.py +1204 -0
- ctyun_cli-0.1.0a1/src/billing/commands.py +701 -0
- ctyun_cli-0.1.0a1/src/cli/__init__.py +5 -0
- ctyun_cli-0.1.0a1/src/cli/main.py +1483 -0
- ctyun_cli-0.1.0a1/src/client.py +391 -0
- ctyun_cli-0.1.0a1/src/config/__init__.py +5 -0
- ctyun_cli-0.1.0a1/src/config/settings.py +159 -0
- ctyun_cli-0.1.0a1/src/ecs/__init__.py +6 -0
- ctyun_cli-0.1.0a1/src/ecs/client.py +475 -0
- ctyun_cli-0.1.0a1/src/ecs/commands.py +587 -0
- ctyun_cli-0.1.0a1/src/security/__init__.py +6 -0
- ctyun_cli-0.1.0a1/src/security/client.py +1188 -0
- ctyun_cli-0.1.0a1/src/security/commands.py +245 -0
- ctyun_cli-0.1.0a1/src/utils/__init__.py +11 -0
- ctyun_cli-0.1.0a1/src/utils/cache.py +176 -0
- ctyun_cli-0.1.0a1/src/utils/helpers.py +322 -0
- ctyun_cli-0.1.0a1/tests/test_basic.py +313 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ctyun-cli
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: 天翼云CLI工具 - 基于终端的云资源管理平台
|
|
5
|
+
Author: Your Name
|
|
6
|
+
Author-email: your.email@example.com
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Requires-Python: >=3.8
|
|
16
|
+
Requires-Dist: requests>=2.31.0
|
|
17
|
+
Requires-Dist: click>=8.1.0
|
|
18
|
+
Requires-Dist: cryptography>=41.0.0
|
|
19
|
+
Requires-Dist: colorama>=0.4.6
|
|
20
|
+
Requires-Dist: tabulate>=0.9.0
|
|
21
|
+
Requires-Dist: pyyaml>=6.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: provides-extra
|
|
29
|
+
Dynamic: requires-dist
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
Dynamic: summary
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# 天翼云CLI工具
|
|
2
|
+
|
|
3
|
+
基于终端的天翼云API操作平台,提供完整的云资源管理功能。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- 🔐 **安全认证**: 基于AK/SK的签名认证机制
|
|
8
|
+
- 🖥️ **ECS管理**: 云服务器生命周期管理
|
|
9
|
+
- 💾 **存储管理**: 对象存储、云硬盘管理
|
|
10
|
+
- 🌐 **网络管理**: VPC、弹性IP、安全组配置
|
|
11
|
+
- 📊 **监控查询**: 资源监控和日志查询
|
|
12
|
+
- ⚡ **批量操作**: 支持批量资源管理
|
|
13
|
+
- 📝 **配置管理**: 灵活的配置文件支持
|
|
14
|
+
|
|
15
|
+
## 项目结构
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
ctyun-cli/
|
|
19
|
+
├── src/
|
|
20
|
+
│ ├── auth/ # 认证模块
|
|
21
|
+
│ ├── ecs/ # 云服务器管理
|
|
22
|
+
│ ├── storage/ # 存储管理
|
|
23
|
+
│ ├── network/ # 网络管理
|
|
24
|
+
│ ├── monitor/ # 监控查询
|
|
25
|
+
│ ├── cli/ # 命令行界面
|
|
26
|
+
│ ├── config/ # 配置管理
|
|
27
|
+
│ └── utils/ # 工具函数
|
|
28
|
+
├── tests/ # 测试文件
|
|
29
|
+
├── docs/ # 文档
|
|
30
|
+
├── examples/ # 示例代码
|
|
31
|
+
├── requirements.txt # Python依赖
|
|
32
|
+
├── setup.py # 安装脚本
|
|
33
|
+
└── README.md # 项目说明
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 快速开始
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# 安装依赖
|
|
40
|
+
pip install -r requirements.txt
|
|
41
|
+
|
|
42
|
+
# 配置认证信息
|
|
43
|
+
python setup_config.py
|
|
44
|
+
|
|
45
|
+
# 查看帮助
|
|
46
|
+
python -m ctyun-cli --help
|
|
47
|
+
|
|
48
|
+
# 列出所有云服务器
|
|
49
|
+
python -m ctyun-cli ecs list
|
|
50
|
+
|
|
51
|
+
# 创建云服务器
|
|
52
|
+
python -m ctyun-cli ecs create --instance-type "s6.small" --image "img-ubuntu20"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 技术栈
|
|
56
|
+
|
|
57
|
+
- **语言**: Python 3.8+
|
|
58
|
+
- **HTTP客户端**: requests
|
|
59
|
+
- **CLI框架**: click
|
|
60
|
+
- **配置管理**: configparser
|
|
61
|
+
- **日志**: logging
|
|
62
|
+
- **测试**: pytest
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ctyun-cli
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: 天翼云CLI工具 - 基于终端的云资源管理平台
|
|
5
|
+
Author: Your Name
|
|
6
|
+
Author-email: your.email@example.com
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Requires-Python: >=3.8
|
|
16
|
+
Requires-Dist: requests>=2.31.0
|
|
17
|
+
Requires-Dist: click>=8.1.0
|
|
18
|
+
Requires-Dist: cryptography>=41.0.0
|
|
19
|
+
Requires-Dist: colorama>=0.4.6
|
|
20
|
+
Requires-Dist: tabulate>=0.9.0
|
|
21
|
+
Requires-Dist: pyyaml>=6.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: provides-extra
|
|
29
|
+
Dynamic: requires-dist
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
Dynamic: summary
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
ctyun_cli.egg-info/PKG-INFO
|
|
4
|
+
ctyun_cli.egg-info/SOURCES.txt
|
|
5
|
+
ctyun_cli.egg-info/dependency_links.txt
|
|
6
|
+
ctyun_cli.egg-info/entry_points.txt
|
|
7
|
+
ctyun_cli.egg-info/requires.txt
|
|
8
|
+
ctyun_cli.egg-info/top_level.txt
|
|
9
|
+
src/__init__.py
|
|
10
|
+
src/client.py
|
|
11
|
+
src/auth/__init__.py
|
|
12
|
+
src/auth/eop_signature.py
|
|
13
|
+
src/auth/signature.py
|
|
14
|
+
src/billing/__init__.py
|
|
15
|
+
src/billing/client.py
|
|
16
|
+
src/billing/commands.py
|
|
17
|
+
src/cli/__init__.py
|
|
18
|
+
src/cli/main.py
|
|
19
|
+
src/config/__init__.py
|
|
20
|
+
src/config/settings.py
|
|
21
|
+
src/ecs/__init__.py
|
|
22
|
+
src/ecs/client.py
|
|
23
|
+
src/ecs/commands.py
|
|
24
|
+
src/security/__init__.py
|
|
25
|
+
src/security/client.py
|
|
26
|
+
src/security/commands.py
|
|
27
|
+
src/utils/__init__.py
|
|
28
|
+
src/utils/cache.py
|
|
29
|
+
src/utils/helpers.py
|
|
30
|
+
tests/test_basic.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ctyun_cli
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="ctyun-cli",
|
|
5
|
+
version="0.1.0a1",
|
|
6
|
+
description="天翼云CLI工具 - 基于终端的云资源管理平台",
|
|
7
|
+
author="Your Name",
|
|
8
|
+
author_email="your.email@example.com",
|
|
9
|
+
packages=["ctyun_cli"] + ["ctyun_cli." + p for p in find_packages(where="src")],
|
|
10
|
+
package_dir={"ctyun_cli": "src"},
|
|
11
|
+
install_requires=[
|
|
12
|
+
"requests>=2.31.0",
|
|
13
|
+
"click>=8.1.0",
|
|
14
|
+
"cryptography>=41.0.0",
|
|
15
|
+
"colorama>=0.4.6",
|
|
16
|
+
"tabulate>=0.9.0",
|
|
17
|
+
"pyyaml>=6.0",
|
|
18
|
+
],
|
|
19
|
+
extras_require={
|
|
20
|
+
"dev": [
|
|
21
|
+
"pytest>=7.4.0",
|
|
22
|
+
"pytest-cov>=4.1.0",
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
entry_points={
|
|
26
|
+
"console_scripts": [
|
|
27
|
+
"ctyun-cli=ctyun_cli:main",
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
python_requires=">=3.8",
|
|
31
|
+
classifiers=[
|
|
32
|
+
"Development Status :: 4 - Beta",
|
|
33
|
+
"Intended Audience :: Developers",
|
|
34
|
+
"License :: OSI Approved :: MIT License",
|
|
35
|
+
"Programming Language :: Python :: 3",
|
|
36
|
+
"Programming Language :: Python :: 3.8",
|
|
37
|
+
"Programming Language :: Python :: 3.9",
|
|
38
|
+
"Programming Language :: Python :: 3.10",
|
|
39
|
+
"Programming Language :: Python :: 3.11",
|
|
40
|
+
],
|
|
41
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
天翼云CLI工具
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
__version__ = "1.0.0"
|
|
6
|
+
__author__ = "Your Name"
|
|
7
|
+
__email__ = "your.email@example.com"
|
|
8
|
+
|
|
9
|
+
from .client import CTYUNClient, CTYUNAPIError
|
|
10
|
+
from .config.settings import ConfigManager, config
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
'CTYUNClient',
|
|
14
|
+
'CTYUNAPIError',
|
|
15
|
+
'ConfigManager',
|
|
16
|
+
'config'
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
def main():
|
|
20
|
+
"""CLI主入口函数"""
|
|
21
|
+
from .cli.main import cli
|
|
22
|
+
cli()
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""
|
|
2
|
+
天翼云EOP签名认证模块
|
|
3
|
+
实现基于EOP规范的AK/SK签名认证机制
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import hashlib
|
|
7
|
+
import hmac
|
|
8
|
+
import base64
|
|
9
|
+
import uuid
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from urllib.parse import quote
|
|
12
|
+
from typing import Dict, Any, Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CTYUNEOPAuth:
|
|
16
|
+
"""天翼云EOP签名认证类"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, access_key: str, secret_key: str):
|
|
19
|
+
"""
|
|
20
|
+
初始化认证器
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
access_key: 访问密钥(AK)
|
|
24
|
+
secret_key: 密钥(SK)
|
|
25
|
+
"""
|
|
26
|
+
self.access_key = access_key
|
|
27
|
+
self.secret_key = secret_key
|
|
28
|
+
|
|
29
|
+
def sign_request(self, method: str, url: str, query_params: Optional[Dict[str, Any]] = None,
|
|
30
|
+
body: Optional[str] = None, extra_headers: Optional[Dict[str, str]] = None) -> Dict[str, str]:
|
|
31
|
+
"""
|
|
32
|
+
对请求进行签名,返回完整的请求头
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
method: HTTP方法
|
|
36
|
+
url: 请求URL
|
|
37
|
+
query_params: 查询参数
|
|
38
|
+
body: 请求体
|
|
39
|
+
extra_headers: 额外的请求头
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
包含签名的请求头字典
|
|
43
|
+
"""
|
|
44
|
+
# 生成必需的请求头
|
|
45
|
+
request_id = str(uuid.uuid4())
|
|
46
|
+
eop_date = self._get_eop_date()
|
|
47
|
+
|
|
48
|
+
# 构建基础请求头
|
|
49
|
+
headers = {
|
|
50
|
+
'Content-Type': 'application/json',
|
|
51
|
+
'ctyun-eop-request-id': request_id,
|
|
52
|
+
'Eop-date': eop_date
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# 添加额外的请求头
|
|
56
|
+
if extra_headers:
|
|
57
|
+
headers.update(extra_headers)
|
|
58
|
+
|
|
59
|
+
# 步骤一:构造待签名字符串 signature
|
|
60
|
+
signature_string = self._build_signature_string(
|
|
61
|
+
headers, query_params, body
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# 步骤二:构造动态密钥 kdate
|
|
65
|
+
kdate = self._build_kdate(eop_date)
|
|
66
|
+
|
|
67
|
+
# 步骤三:构造 signature
|
|
68
|
+
signature = self._build_signature(signature_string, kdate)
|
|
69
|
+
|
|
70
|
+
# 步骤四:构造 Eop-Authorization
|
|
71
|
+
eop_authorization = self._build_eop_authorization(signature, headers)
|
|
72
|
+
|
|
73
|
+
# 添加认证头
|
|
74
|
+
headers['Eop-Authorization'] = eop_authorization
|
|
75
|
+
|
|
76
|
+
return headers
|
|
77
|
+
|
|
78
|
+
def _get_eop_date(self) -> str:
|
|
79
|
+
"""
|
|
80
|
+
获取EOP格式的日期时间
|
|
81
|
+
格式:yyyyMMdd'T'HHmmss'Z'
|
|
82
|
+
注意:实际传时间为北京东八区UTC+8时间,TZ仅为格式,非UTC时间
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
EOP格式的日期时间字符串
|
|
86
|
+
"""
|
|
87
|
+
# 获取当前北京时间(UTC+8)
|
|
88
|
+
now = datetime.now()
|
|
89
|
+
return now.strftime('%Y%m%dT%H%M%SZ')
|
|
90
|
+
|
|
91
|
+
def _build_signature_string(self, headers: Dict[str, str],
|
|
92
|
+
query_params: Optional[Dict[str, Any]] = None,
|
|
93
|
+
body: Optional[str] = None) -> str:
|
|
94
|
+
"""
|
|
95
|
+
构造待签名字符串
|
|
96
|
+
sigture = 需要进行签名的Header排序后的组合列表 + "\n" + encode的query + "\n" + toHex(sha256(原封的body))
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
headers: 请求头字典
|
|
100
|
+
query_params: 查询参数
|
|
101
|
+
body: 请求体
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
待签名字符串
|
|
105
|
+
"""
|
|
106
|
+
# 1. 构造需要签名的Header排序后的组合列表
|
|
107
|
+
# EOP强制要求 ctyun-eop-request-id、eop-date 必须进行签名
|
|
108
|
+
signed_header_names = ['ctyun-eop-request-id', 'eop-date']
|
|
109
|
+
|
|
110
|
+
# 按字母顺序排序
|
|
111
|
+
signed_header_names.sort()
|
|
112
|
+
|
|
113
|
+
# 构造 header_name:header_value\n 格式
|
|
114
|
+
header_list = []
|
|
115
|
+
for header_name in signed_header_names:
|
|
116
|
+
# 注意:查找header时不区分大小写,但构造签名字符串时必须用小写
|
|
117
|
+
header_value = None
|
|
118
|
+
for k, v in headers.items():
|
|
119
|
+
if k.lower() == header_name.lower():
|
|
120
|
+
header_value = v
|
|
121
|
+
break
|
|
122
|
+
|
|
123
|
+
if header_value:
|
|
124
|
+
header_list.append(f"{header_name.lower()}:{header_value}\n")
|
|
125
|
+
|
|
126
|
+
header_string = ''.join(header_list)
|
|
127
|
+
|
|
128
|
+
# 2. 构造编码后的query字符串
|
|
129
|
+
query_string = ''
|
|
130
|
+
if query_params:
|
|
131
|
+
# 对参数按key排序
|
|
132
|
+
sorted_params = sorted(query_params.items())
|
|
133
|
+
encoded_params = []
|
|
134
|
+
for key, value in sorted_params:
|
|
135
|
+
# 值需要进行URL编码
|
|
136
|
+
encoded_value = quote(str(value), safe='')
|
|
137
|
+
encoded_params.append(f"{key}={encoded_value}")
|
|
138
|
+
query_string = '&'.join(encoded_params)
|
|
139
|
+
|
|
140
|
+
# 3. 对body进行SHA256摘要并转十六进制
|
|
141
|
+
if body is None or body == '':
|
|
142
|
+
body = ''
|
|
143
|
+
body_hash = hashlib.sha256(body.encode('utf-8')).hexdigest()
|
|
144
|
+
|
|
145
|
+
# 拼接最终的待签名字符串
|
|
146
|
+
# 格式:header_string + "\n" + query_string + "\n" + body_hash
|
|
147
|
+
signature_string = f"{header_string}\n{query_string}\n{body_hash}"
|
|
148
|
+
|
|
149
|
+
return signature_string
|
|
150
|
+
|
|
151
|
+
def _build_kdate(self, eop_date: str) -> bytes:
|
|
152
|
+
"""
|
|
153
|
+
构造动态密钥 kdate
|
|
154
|
+
|
|
155
|
+
步骤:
|
|
156
|
+
1. ktime = hmacSHA256(eop_date, sk)
|
|
157
|
+
2. kAk = hmacSHA256(ak, ktime)
|
|
158
|
+
3. kdate = hmacSHA256(eop_date的年月日值, kAk)
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
eop_date: EOP格式的日期时间
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
动态密钥 kdate
|
|
165
|
+
"""
|
|
166
|
+
# 1. 使用eop_date作为数据,sk作为密钥,算出ktime
|
|
167
|
+
ktime = hmac.new(
|
|
168
|
+
self.secret_key.encode('utf-8'),
|
|
169
|
+
eop_date.encode('utf-8'),
|
|
170
|
+
hashlib.sha256
|
|
171
|
+
).digest()
|
|
172
|
+
|
|
173
|
+
# 2. 使用ak作为数据,ktime作为密钥,算出kAk
|
|
174
|
+
kAk = hmac.new(
|
|
175
|
+
ktime,
|
|
176
|
+
self.access_key.encode('utf-8'),
|
|
177
|
+
hashlib.sha256
|
|
178
|
+
).digest()
|
|
179
|
+
|
|
180
|
+
# 3. 使用eop_date的年月日值作为数据,kAk作为密钥,算出kdate
|
|
181
|
+
# eop_date格式:20221107T093029Z,提取年月日:20221107
|
|
182
|
+
date_part = eop_date.split('T')[0]
|
|
183
|
+
kdate = hmac.new(
|
|
184
|
+
kAk,
|
|
185
|
+
date_part.encode('utf-8'),
|
|
186
|
+
hashlib.sha256
|
|
187
|
+
).digest()
|
|
188
|
+
|
|
189
|
+
return kdate
|
|
190
|
+
|
|
191
|
+
def _build_signature(self, signature_string: str, kdate: bytes) -> str:
|
|
192
|
+
"""
|
|
193
|
+
构造 signature
|
|
194
|
+
使用kdate作为密钥、signature_string作为数据,进行HMAC-SHA256,然后Base64编码
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
signature_string: 待签名字符串
|
|
198
|
+
kdate: 动态密钥
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
Base64编码的签名
|
|
202
|
+
"""
|
|
203
|
+
signature_bytes = hmac.new(
|
|
204
|
+
kdate,
|
|
205
|
+
signature_string.encode('utf-8'),
|
|
206
|
+
hashlib.sha256
|
|
207
|
+
).digest()
|
|
208
|
+
|
|
209
|
+
# Base64编码
|
|
210
|
+
signature = base64.b64encode(signature_bytes).decode('utf-8')
|
|
211
|
+
|
|
212
|
+
return signature
|
|
213
|
+
|
|
214
|
+
def _build_eop_authorization(self, signature: str, headers: Dict[str, str]) -> str:
|
|
215
|
+
"""
|
|
216
|
+
构造 Eop-Authorization 请求头
|
|
217
|
+
格式:ak Headers=header1;header2 Signature=xxx
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
signature: 签名
|
|
221
|
+
headers: 请求头字典
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
Eop-Authorization 字符串
|
|
225
|
+
"""
|
|
226
|
+
# 构造 Headers 部分(需要签名的header,按字母排序,用分号分隔)
|
|
227
|
+
signed_header_names = ['ctyun-eop-request-id', 'eop-date']
|
|
228
|
+
signed_header_names.sort()
|
|
229
|
+
headers_part = ';'.join(signed_header_names)
|
|
230
|
+
|
|
231
|
+
# 构造完整的 Eop-Authorization
|
|
232
|
+
# 格式:ak Headers=xxx Signature=xxx
|
|
233
|
+
eop_authorization = f"{self.access_key} Headers={headers_part} Signature={signature}"
|
|
234
|
+
|
|
235
|
+
return eop_authorization
|